aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.github/workflows/ci.yml43
-rw-r--r--.github/workflows/commitlint.yml6
-rw-r--r--.gitignore2
-rw-r--r--cmake.deps/cmake/BuildGettext.cmake20
-rw-r--r--cmake.deps/cmake/BuildLibiconv.cmake16
-rw-r--r--cmake.deps/cmake/BuildMsgpack.cmake9
-rw-r--r--cmake.deps/cmake/GettextCMakeLists.txt2
-rw-r--r--cmake.deps/cmake/LibiconvCMakeLists.txt2
-rw-r--r--cmake.deps/cmake/LibvtermCMakeLists.txt2
-rw-r--r--cmake.deps/cmake/TreesitterCMakeLists.txt2
-rw-r--r--cmake.deps/cmake/TreesitterParserCMakeLists.txt2
-rw-r--r--cmake.deps/cmake/UnibiliumCMakeLists.txt2
-rw-r--r--cmake.deps/cmake/libtermkeyCMakeLists.txt2
-rw-r--r--cmake/GenerateVersion.cmake2
-rw-r--r--runtime/autoload/provider/clipboard.vim7
-rw-r--r--runtime/doc/builtin.txt50
-rw-r--r--runtime/doc/editing.txt38
-rw-r--r--runtime/doc/lua.txt3
-rw-r--r--runtime/doc/options.txt22
-rw-r--r--runtime/doc/pattern.txt2
-rw-r--r--runtime/doc/repeat.txt2
-rw-r--r--runtime/doc/testing.txt38
-rw-r--r--runtime/doc/usr_41.txt3
-rw-r--r--runtime/lua/man.lua2
-rw-r--r--scripts/lua2dox.lua4
-rwxr-xr-xscripts/pvscheck.sh2
-rw-r--r--src/nvim/README.md4
-rw-r--r--src/nvim/buffer_defs.h6
-rw-r--r--src/nvim/cmdexpand.c4
-rw-r--r--src/nvim/diff.c431
-rw-r--r--src/nvim/drawline.c11
-rw-r--r--src/nvim/eval.c27
-rw-r--r--src/nvim/eval.lua5
-rw-r--r--src/nvim/eval/funcs.c127
-rw-r--r--src/nvim/eval/typval.c17
-rw-r--r--src/nvim/eval/typval.h5
-rw-r--r--src/nvim/eval/userfunc.c4
-rw-r--r--src/nvim/ex_cmds.c11
-rw-r--r--src/nvim/ex_docmd.c9
-rw-r--r--src/nvim/ex_eval.c7
-rw-r--r--src/nvim/ex_getln.c2
-rw-r--r--src/nvim/fileio.c48
-rw-r--r--src/nvim/globals.h6
-rw-r--r--src/nvim/highlight_group.c2
-rw-r--r--src/nvim/indent.c80
-rw-r--r--src/nvim/linematch.c376
-rw-r--r--src/nvim/linematch.h10
-rw-r--r--src/nvim/lua/xdiff.c138
-rw-r--r--src/nvim/mapping.c2
-rw-r--r--src/nvim/match.c2
-rw-r--r--src/nvim/message.c7
-rw-r--r--src/nvim/mouse.c9
-rw-r--r--src/nvim/ops.c2
-rw-r--r--src/nvim/option.c11
-rw-r--r--src/nvim/options.lua2
-rw-r--r--src/nvim/optionstr.c10
-rw-r--r--src/nvim/path.c2
-rw-r--r--src/nvim/plines.c4
-rw-r--r--src/nvim/quickfix.c6
-rw-r--r--src/nvim/regexp.c57
-rw-r--r--src/nvim/regexp_bt.c11
-rw-r--r--src/nvim/regexp_nfa.c59
-rw-r--r--src/nvim/runtime.c2
-rw-r--r--src/nvim/search.c2
-rw-r--r--src/nvim/shada.c18
-rw-r--r--src/nvim/spell.c4
-rw-r--r--src/nvim/spellfile.c2
-rw-r--r--src/nvim/syntax.c4
-rw-r--r--src/nvim/tag.c4
-rw-r--r--src/nvim/testdir/check.vim3
-rw-r--r--src/nvim/testdir/samples/re.freeze.txt (renamed from test/benchmark/samples/re.freeze.txt)0
-rw-r--r--src/nvim/testdir/shared.vim15
-rw-r--r--src/nvim/testdir/test49.ok44
-rw-r--r--src/nvim/testdir/test49.vim5284
-rw-r--r--src/nvim/testdir/test_arglist.vim5
-rw-r--r--src/nvim/testdir/test_assert.vim60
-rw-r--r--src/nvim/testdir/test_autochdir.vim4
-rw-r--r--src/nvim/testdir/test_autocmd.vim8
-rw-r--r--src/nvim/testdir/test_backup.vim18
-rw-r--r--src/nvim/testdir/test_blob.vim4
-rw-r--r--src/nvim/testdir/test_breakindent.vim157
-rw-r--r--src/nvim/testdir/test_buffer.vim4
-rw-r--r--src/nvim/testdir/test_bufline.vim32
-rw-r--r--src/nvim/testdir/test_cd.vim32
-rw-r--r--src/nvim/testdir/test_charsearch.vim61
-rw-r--r--src/nvim/testdir/test_clientserver.vim7
-rw-r--r--src/nvim/testdir/test_cmdline.vim24
-rw-r--r--src/nvim/testdir/test_cpoptions.vim927
-rw-r--r--src/nvim/testdir/test_display.vim2
-rw-r--r--src/nvim/testdir/test_edit.vim146
-rw-r--r--src/nvim/testdir/test_eval_stuff.vim9
-rw-r--r--src/nvim/testdir/test_ex_mode.vim1
-rw-r--r--src/nvim/testdir/test_excmd.vim4
-rw-r--r--src/nvim/testdir/test_exists.vim6
-rw-r--r--src/nvim/testdir/test_expand.vim18
-rw-r--r--src/nvim/testdir/test_expand_func.vim1
-rw-r--r--src/nvim/testdir/test_expr.vim46
-rw-r--r--src/nvim/testdir/test_fixeol.vim67
-rw-r--r--src/nvim/testdir/test_functions.vim136
-rw-r--r--src/nvim/testdir/test_global.vim2
-rw-r--r--src/nvim/testdir/test_increment.vim35
-rw-r--r--src/nvim/testdir/test_let.vim2
-rw-r--r--src/nvim/testdir/test_listdict.vim16
-rw-r--r--src/nvim/testdir/test_mapping.vim24
-rw-r--r--src/nvim/testdir/test_marks.vim2
-rw-r--r--src/nvim/testdir/test_match.vim16
-rw-r--r--src/nvim/testdir/test_matchfuzzy.vim18
-rw-r--r--src/nvim/testdir/test_menu.vim3
-rw-r--r--src/nvim/testdir/test_method.vim4
-rw-r--r--src/nvim/testdir/test_normal.vim248
-rw-r--r--src/nvim/testdir/test_options.vim2
-rw-r--r--src/nvim/testdir/test_partial.vim5
-rw-r--r--src/nvim/testdir/test_quickfix.vim21
-rw-r--r--src/nvim/testdir/test_random.vim10
-rw-r--r--src/nvim/testdir/test_regexp_latin.vim55
-rw-r--r--src/nvim/testdir/test_registers.vim18
-rw-r--r--src/nvim/testdir/test_reltime.vim4
-rw-r--r--src/nvim/testdir/test_search.vim34
-rw-r--r--src/nvim/testdir/test_selectmode.vim3
-rw-r--r--src/nvim/testdir/test_signals.vim33
-rw-r--r--src/nvim/testdir/test_signs.vim10
-rw-r--r--src/nvim/testdir/test_sort.vim2
-rw-r--r--src/nvim/testdir/test_spell.vim4
-rw-r--r--src/nvim/testdir/test_startup.vim8
-rw-r--r--src/nvim/testdir/test_startup_utf8.vim4
-rw-r--r--src/nvim/testdir/test_substitute.vim88
-rw-r--r--src/nvim/testdir/test_syntax.vim8
-rw-r--r--src/nvim/testdir/test_tabpage.vim15
-rw-r--r--src/nvim/testdir/test_tagfunc.vim2
-rw-r--r--src/nvim/testdir/test_tagjump.vim60
-rw-r--r--src/nvim/testdir/test_taglist.vim6
-rw-r--r--src/nvim/testdir/test_textformat.vim14
-rw-r--r--src/nvim/testdir/test_timers.vim4
-rw-r--r--src/nvim/testdir/test_trycatch.vim23
-rw-r--r--src/nvim/testdir/test_utf8.vim11
-rw-r--r--src/nvim/testdir/test_vartabs.vim2
-rw-r--r--src/nvim/testdir/test_vimscript.vim5003
-rw-r--r--src/nvim/testdir/test_virtualedit.vim56
-rw-r--r--src/nvim/testdir/test_visual.vim9
-rw-r--r--src/nvim/testdir/test_winbuf_close.vim2
-rw-r--r--src/nvim/testdir/test_window_cmd.vim37
-rw-r--r--src/nvim/testdir/test_window_id.vim12
-rw-r--r--src/nvim/testdir/test_writefile.vim187
-rw-r--r--src/nvim/testing.c103
-rw-r--r--src/nvim/usercmd.c4
-rw-r--r--src/nvim/version.c2
-rw-r--r--src/nvim/window.c6
-rw-r--r--test/benchmark/bench_regexp_spec.lua (renamed from test/benchmark/bench_re_freeze_spec.lua)12
-rw-r--r--test/functional/api/keymap_spec.lua2
-rw-r--r--test/functional/core/fileio_spec.lua53
-rw-r--r--test/functional/core/startup_spec.lua2
-rw-r--r--test/functional/ex_cmds/verbose_spec.lua4
-rw-r--r--test/functional/legacy/breakindent_spec.lua44
-rw-r--r--test/functional/legacy/digraph_spec.lua46
-rw-r--r--test/functional/legacy/edit_spec.lua64
-rw-r--r--test/functional/legacy/increment_spec.lua2
-rw-r--r--test/functional/legacy/vimscript_spec.lua90
-rw-r--r--test/functional/plugin/lsp_spec.lua4
-rw-r--r--test/functional/ui/diff_spec.lua176
-rw-r--r--test/functional/ui/linematch_spec.lua981
-rw-r--r--test/functional/ui/sign_spec.lua2
-rw-r--r--test/functional/vimscript/eval_spec.lua74
-rw-r--r--test/functional/vimscript/null_spec.lua2
163 files changed, 10485 insertions, 6270 deletions
diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
index c386930073..732e3bb8c1 100644
--- a/.github/workflows/ci.yml
+++ b/.github/workflows/ci.yml
@@ -95,6 +95,11 @@ jobs:
run: ./ci/before_script.sh
- if: "!cancelled()"
+ name: Determine if run should be aborted
+ id: abort_job
+ run: echo "status=${{ job.status }}" >> $GITHUB_OUTPUT
+
+ - if: success() || failure() && steps.abort_job.outputs.status == 'success'
name: lintstylua
uses: JohnnyMorganz/stylua-action@v1
with:
@@ -102,20 +107,20 @@ jobs:
version: latest
args: --check runtime/
- - if: "!cancelled()"
+ - if: success() || failure() && steps.abort_job.outputs.status == 'success'
name: lintlua
run: make lintlua
- - if: "!cancelled()"
+ - if: success() || failure() && steps.abort_job.outputs.status == 'success'
name: lintsh
run: make lintsh
- - if: "!cancelled()"
+ - if: success() || failure() && steps.abort_job.outputs.status == 'success'
name: uncrustify
run: |
${{ env.CACHE_UNCRUSTIFY }} -c ./src/uncrustify.cfg -q --replace --no-backup $(find ./src/nvim -name "*.[ch]")
- - if: "!cancelled()"
+ - if: success() || failure() && steps.abort_job.outputs.status == 'success'
name: suggester / uncrustify
uses: reviewdog/action-suggester@v1
with:
@@ -123,7 +128,7 @@ jobs:
tool_name: uncrustify
cleanup: false
- - if: "!cancelled()"
+ - if: success() || failure() && steps.abort_job.outputs.status == 'success'
name: check uncrustify
run: |
git diff --color --exit-code
@@ -192,10 +197,15 @@ jobs:
run: ./ci/run_tests.sh build_nvim
- if: "!cancelled()"
+ name: Determine if run should be aborted
+ id: abort_job
+ run: echo "status=${{ job.status }}" >> $GITHUB_OUTPUT
+
+ - if: success() || failure() && steps.abort_job.outputs.status == 'success'
name: lintc
run: make lintc
- - if: "!cancelled()"
+ - if: success() || failure() && steps.abort_job.outputs.status == 'success'
name: check-single-includes
run: make check-single-includes
@@ -292,19 +302,24 @@ jobs:
- name: Build
run: ./ci/run_tests.sh build_nvim
- - if: matrix.flavor != 'tsan' && matrix.flavor != 'functionaltest-lua' && !cancelled()
+ - if: "!cancelled()"
+ name: Determine if run should be aborted
+ id: abort_job
+ run: echo "status=${{ job.status }}" >> $GITHUB_OUTPUT
+
+ - if: matrix.flavor != 'tsan' && matrix.flavor != 'functionaltest-lua' && (success() || failure() && steps.abort_job.outputs.status == 'success')
name: Unittests
run: ./ci/run_tests.sh unittests
- - if: matrix.flavor != 'tsan' && !cancelled()
+ - if: matrix.flavor != 'tsan' && (success() || failure() && steps.abort_job.outputs.status == 'success')
name: Functionaltests
run: ./ci/run_tests.sh functionaltests
- - if: "!cancelled()"
+ - if: success() || failure() && steps.abort_job.outputs.status == 'success'
name: Oldtests
run: ./ci/run_tests.sh oldtests
- - if: "!cancelled()"
+ - if: success() || failure() && steps.abort_job.outputs.status == 'success'
name: Install nvim
run: ./ci/run_tests.sh install_nvim
@@ -336,9 +351,15 @@ jobs:
run: .\ci\build.ps1 -EnsureTestDeps
- if: "!cancelled()"
+ name: Determine if run should be aborted
+ id: abort_job
+ run: |
+ "status=${{ job.status }}" >> $env:GITHUB_OUTPUT
+
+ - if: success() || failure() && steps.abort_job.outputs.status == 'success'
name: Run tests
run: .\ci\build.ps1 -Test
- - if: "!cancelled()"
+ - if: success() || failure() && steps.abort_job.outputs.status == 'success'
name: Run old tests
run: .\ci\build.ps1 -TestOld
diff --git a/.github/workflows/commitlint.yml b/.github/workflows/commitlint.yml
index 68be5436f6..a7a227865d 100644
--- a/.github/workflows/commitlint.yml
+++ b/.github/workflows/commitlint.yml
@@ -1,8 +1,6 @@
name: "Commit Linter"
on:
- # Only pull_request and push honor [skip ci]. Since this workflow must pass
- # to merge a PR, it can't be skipped, so use pull_request_target
- pull_request_target:
+ pull_request:
types: [opened, synchronize, reopened, ready_for_review]
branches:
- 'master'
@@ -10,6 +8,8 @@ jobs:
lint-commits:
runs-on: ubuntu-latest
if: github.event.pull_request.draft == false
+ env:
+ GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
steps:
- uses: actions/checkout@v3
with:
diff --git a/.gitignore b/.gitignore
index be43c5cd90..97fed7b949 100644
--- a/.gitignore
+++ b/.gitignore
@@ -74,4 +74,4 @@ tags
# vim patches
/vim-*.patch
-/CMakeUserPresets.json
+CMakeUserPresets.json
diff --git a/cmake.deps/cmake/BuildGettext.cmake b/cmake.deps/cmake/BuildGettext.cmake
index aecd5da626..4ba1f46d2e 100644
--- a/cmake.deps/cmake/BuildGettext.cmake
+++ b/cmake.deps/cmake/BuildGettext.cmake
@@ -7,18 +7,16 @@ if(MSVC)
URL_HASH SHA256=${GETTEXT_SHA256}
DOWNLOAD_NO_PROGRESS TRUE
DOWNLOAD_DIR ${DEPS_DOWNLOAD_DIR}/gettext
- CONFIGURE_COMMAND ${CMAKE_COMMAND} -E copy
+ PATCH_COMMAND ${CMAKE_COMMAND} -E copy
${CMAKE_CURRENT_SOURCE_DIR}/cmake/GettextCMakeLists.txt
- ${DEPS_BUILD_DIR}/src/gettext/CMakeLists.txt
- COMMAND ${CMAKE_COMMAND} ${DEPS_BUILD_DIR}/src/gettext
- -DCMAKE_INSTALL_PREFIX=${DEPS_INSTALL_DIR}
- ${BUILD_TYPE_STRING}
- -DCMAKE_GENERATOR=${CMAKE_GENERATOR}
- -DCMAKE_GENERATOR_PLATFORM=${CMAKE_GENERATOR_PLATFORM}
- -DLIBICONV_INCLUDE_DIRS=${DEPS_INSTALL_DIR}/include
- -DLIBICONV_LIBRARIES=${DEPS_LIB_DIR}/${CMAKE_STATIC_LIBRARY_PREFIX}libcharset${CMAKE_STATIC_LIBRARY_SUFFIX}$<SEMICOLON>${DEPS_LIB_DIR}/${CMAKE_STATIC_LIBRARY_PREFIX}libiconv${CMAKE_STATIC_LIBRARY_SUFFIX}
- BUILD_COMMAND ${CMAKE_COMMAND} --build . --config $<CONFIG>
- INSTALL_COMMAND ${CMAKE_COMMAND} --build . --target install --config $<CONFIG>)
+ ${DEPS_BUILD_DIR}/src/gettext/CMakeLists.txt
+ CMAKE_ARGS
+ -DCMAKE_INSTALL_PREFIX=${DEPS_INSTALL_DIR}
+ ${BUILD_TYPE_STRING}
+ -DCMAKE_GENERATOR=${CMAKE_GENERATOR}
+ -DCMAKE_GENERATOR_PLATFORM=${CMAKE_GENERATOR_PLATFORM}
+ -DLIBICONV_INCLUDE_DIRS=${DEPS_INSTALL_DIR}/include
+ -DLIBICONV_LIBRARIES=${DEPS_LIB_DIR}/${CMAKE_STATIC_LIBRARY_PREFIX}libcharset${CMAKE_STATIC_LIBRARY_SUFFIX}$<SEMICOLON>${DEPS_LIB_DIR}/${CMAKE_STATIC_LIBRARY_PREFIX}libiconv${CMAKE_STATIC_LIBRARY_SUFFIX})
else()
message(FATAL_ERROR "Trying to build gettext in an unsupported system ${CMAKE_SYSTEM_NAME}/${CMAKE_C_COMPILER_ID}")
endif()
diff --git a/cmake.deps/cmake/BuildLibiconv.cmake b/cmake.deps/cmake/BuildLibiconv.cmake
index 26d9b02e77..382aae3df7 100644
--- a/cmake.deps/cmake/BuildLibiconv.cmake
+++ b/cmake.deps/cmake/BuildLibiconv.cmake
@@ -7,16 +7,14 @@ if(MSVC)
URL_HASH SHA256=${LIBICONV_SHA256}
DOWNLOAD_NO_PROGRESS TRUE
DOWNLOAD_DIR ${DEPS_DOWNLOAD_DIR}/libiconv
- CONFIGURE_COMMAND ${CMAKE_COMMAND} -E copy
+ PATCH_COMMAND ${CMAKE_COMMAND} -E copy
${CMAKE_CURRENT_SOURCE_DIR}/cmake/LibiconvCMakeLists.txt
- ${DEPS_BUILD_DIR}/src/libiconv/CMakeLists.txt
- COMMAND ${CMAKE_COMMAND} ${DEPS_BUILD_DIR}/src/libiconv
- -DCMAKE_INSTALL_PREFIX=${DEPS_INSTALL_DIR}
- ${BUILD_TYPE_STRING}
- -DCMAKE_GENERATOR=${CMAKE_GENERATOR}
- -DCMAKE_GENERATOR_PLATFORM=${CMAKE_GENERATOR_PLATFORM}
- BUILD_COMMAND ${CMAKE_COMMAND} --build . --config $<CONFIG>
- INSTALL_COMMAND ${CMAKE_COMMAND} --build . --target install --config $<CONFIG>)
+ ${DEPS_BUILD_DIR}/src/libiconv/CMakeLists.txt
+ CMAKE_ARGS
+ -DCMAKE_INSTALL_PREFIX=${DEPS_INSTALL_DIR}
+ ${BUILD_TYPE_STRING}
+ -DCMAKE_GENERATOR=${CMAKE_GENERATOR}
+ -DCMAKE_GENERATOR_PLATFORM=${CMAKE_GENERATOR_PLATFORM})
else()
message(FATAL_ERROR "Trying to build libiconv in an unsupported system ${CMAKE_SYSTEM_NAME}/${CMAKE_C_COMPILER_ID}")
endif()
diff --git a/cmake.deps/cmake/BuildMsgpack.cmake b/cmake.deps/cmake/BuildMsgpack.cmake
index b59d98159d..3197ec45a1 100644
--- a/cmake.deps/cmake/BuildMsgpack.cmake
+++ b/cmake.deps/cmake/BuildMsgpack.cmake
@@ -1,4 +1,4 @@
-set(MSGPACK_CONFIGURE_COMMAND ${CMAKE_COMMAND} ${DEPS_BUILD_DIR}/src/msgpack
+set(MSGPACK_CMAKE_ARGS
-DMSGPACK_BUILD_TESTS=OFF
-DMSGPACK_BUILD_EXAMPLES=OFF
-DCMAKE_INSTALL_PREFIX=${DEPS_INSTALL_DIR}
@@ -8,8 +8,7 @@ set(MSGPACK_CONFIGURE_COMMAND ${CMAKE_COMMAND} ${DEPS_BUILD_DIR}/src/msgpack
-DCMAKE_GENERATOR=${CMAKE_GENERATOR})
if(MSVC)
- # Same as Unix without fPIC
- set(MSGPACK_CONFIGURE_COMMAND ${CMAKE_COMMAND} ${DEPS_BUILD_DIR}/src/msgpack
+ set(MSGPACK_CMAKE_ARGS
-DMSGPACK_BUILD_TESTS=OFF
-DMSGPACK_BUILD_EXAMPLES=OFF
-DCMAKE_INSTALL_PREFIX=${DEPS_INSTALL_DIR}
@@ -29,9 +28,7 @@ ExternalProject_Add(msgpack
URL_HASH SHA256=${MSGPACK_SHA256}
DOWNLOAD_NO_PROGRESS TRUE
DOWNLOAD_DIR ${DEPS_DOWNLOAD_DIR}/msgpack
- CONFIGURE_COMMAND "${MSGPACK_CONFIGURE_COMMAND}"
- BUILD_COMMAND ${CMAKE_COMMAND} --build . --config $<CONFIG>
- INSTALL_COMMAND ${CMAKE_COMMAND} --build . --target install --config $<CONFIG>
+ CMAKE_ARGS "${MSGPACK_CMAKE_ARGS}"
LIST_SEPARATOR |)
list(APPEND THIRD_PARTY_DEPS msgpack)
diff --git a/cmake.deps/cmake/GettextCMakeLists.txt b/cmake.deps/cmake/GettextCMakeLists.txt
index d9f251897d..26f060ec08 100644
--- a/cmake.deps/cmake/GettextCMakeLists.txt
+++ b/cmake.deps/cmake/GettextCMakeLists.txt
@@ -327,3 +327,5 @@ install(TARGETS libintl msgmerge msgfmt xgettext
LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
PUBLIC_HEADER DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}
RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR})
+
+# vim: set ft=cmake:
diff --git a/cmake.deps/cmake/LibiconvCMakeLists.txt b/cmake.deps/cmake/LibiconvCMakeLists.txt
index b4ba6b5d7e..f6a23db864 100644
--- a/cmake.deps/cmake/LibiconvCMakeLists.txt
+++ b/cmake.deps/cmake/LibiconvCMakeLists.txt
@@ -95,3 +95,5 @@ install(TARGETS libcharset libiconv iconv
LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
PUBLIC_HEADER DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}
RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR})
+
+# vim: set ft=cmake:
diff --git a/cmake.deps/cmake/LibvtermCMakeLists.txt b/cmake.deps/cmake/LibvtermCMakeLists.txt
index d7ec9eacad..079ad28ba0 100644
--- a/cmake.deps/cmake/LibvtermCMakeLists.txt
+++ b/cmake.deps/cmake/LibvtermCMakeLists.txt
@@ -82,3 +82,5 @@ if(Perl_FOUND)
DEPENDS ${header_path} ${perl_header_path})
endforeach()
endif()
+
+# vim: set ft=cmake:
diff --git a/cmake.deps/cmake/TreesitterCMakeLists.txt b/cmake.deps/cmake/TreesitterCMakeLists.txt
index e20b47dd74..69372bd2b0 100644
--- a/cmake.deps/cmake/TreesitterCMakeLists.txt
+++ b/cmake.deps/cmake/TreesitterCMakeLists.txt
@@ -19,3 +19,5 @@ install(FILES
include(GNUInstallDirs)
install(TARGETS tree-sitter
LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR})
+
+# vim: set ft=cmake:
diff --git a/cmake.deps/cmake/TreesitterParserCMakeLists.txt b/cmake.deps/cmake/TreesitterParserCMakeLists.txt
index be07f00a37..44e4ef160f 100644
--- a/cmake.deps/cmake/TreesitterParserCMakeLists.txt
+++ b/cmake.deps/cmake/TreesitterParserCMakeLists.txt
@@ -19,3 +19,5 @@ set_target_properties(
include_directories(src)
install(TARGETS parser LIBRARY DESTINATION lib/nvim/parser)
+
+# vim: set ft=cmake:
diff --git a/cmake.deps/cmake/UnibiliumCMakeLists.txt b/cmake.deps/cmake/UnibiliumCMakeLists.txt
index 9112b416fa..0a5d8481a7 100644
--- a/cmake.deps/cmake/UnibiliumCMakeLists.txt
+++ b/cmake.deps/cmake/UnibiliumCMakeLists.txt
@@ -23,3 +23,5 @@ install(TARGETS unibilium
PUBLIC_HEADER
ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}
PUBLIC_HEADER DESTINATION ${CMAKE_INSTALL_INCLUDEDIR})
+
+# vim: set ft=cmake:
diff --git a/cmake.deps/cmake/libtermkeyCMakeLists.txt b/cmake.deps/cmake/libtermkeyCMakeLists.txt
index 6c02b7549d..b419d38d7b 100644
--- a/cmake.deps/cmake/libtermkeyCMakeLists.txt
+++ b/cmake.deps/cmake/libtermkeyCMakeLists.txt
@@ -32,3 +32,5 @@ foreach(f ${TESTSOURCES})
target_link_libraries("test_${t}" termkey)
add_test("${t}" "test_${t}")
endforeach()
+
+# vim: set ft=cmake:
diff --git a/cmake/GenerateVersion.cmake b/cmake/GenerateVersion.cmake
index d2a711fdf9..7ce6ee430e 100644
--- a/cmake/GenerateVersion.cmake
+++ b/cmake/GenerateVersion.cmake
@@ -16,7 +16,9 @@ endif()
# `git describe` annotates the most recent tagged release; for pre-release
# builds we append that to the dev version.
if(NVIM_VERSION_PRERELEASE)
+ # Extract pre-release info: "v0.8.0-145-g0f9113907" => "145-g0f9113907"
string(REGEX REPLACE "^v[0-9]+.[0-9]+.[0-9]+-" "" NVIM_VERSION_GIT "${GIT_TAG}")
+ # Replace "-" with "+": "145-g0f9113907" => "145+g0f9113907"
string(REGEX REPLACE "^([0-9]+)-([a-z0-9]+)" "\\1+\\2" NVIM_VERSION_GIT "${NVIM_VERSION_GIT}")
set(NVIM_VERSION "${NVIM_VERSION}-${NVIM_VERSION_GIT}")
endif()
diff --git a/runtime/autoload/provider/clipboard.vim b/runtime/autoload/provider/clipboard.vim
index 991bed6bbd..026c01bce6 100644
--- a/runtime/autoload/provider/clipboard.vim
+++ b/runtime/autoload/provider/clipboard.vim
@@ -139,7 +139,12 @@ function! provider#clipboard#Executable() abort
let s:paste['*'] = s:paste['+']
return 'termux-clipboard'
elseif !empty($TMUX) && executable('tmux')
- let s:copy['+'] = ['tmux', 'load-buffer', '-']
+ let [major, minor] = matchlist(systemlist(['tmux', '-V'])[0], 'tmux \(\d\+\)\.\(\d\+\)')[1:2]
+ if major > 3 || (major == 3 && minor >= 2)
+ let s:copy['+'] = ['tmux', 'load-buffer', '-w', '-']
+ else
+ let s:copy['+'] = ['tmux', 'load-buffer', '-']
+ endif
let s:paste['+'] = ['tmux', 'save-buffer', '-']
let s:copy['*'] = s:copy['+']
let s:paste['*'] = s:paste['+']
diff --git a/runtime/doc/builtin.txt b/runtime/doc/builtin.txt
index 8ffe9d54a4..11352bb0c8 100644
--- a/runtime/doc/builtin.txt
+++ b/runtime/doc/builtin.txt
@@ -134,7 +134,8 @@ exists({expr}) Number |TRUE| if {expr} exists
exp({expr}) Float exponential of {expr}
expand({expr} [, {nosuf} [, {list}]])
any expand special keywords in {expr}
-expandcmd({expr}) String expand {expr} like with `:edit`
+expandcmd({string} [, {options}])
+ String expand {string} like with `:edit`
extend({expr1}, {expr2} [, {expr3}])
List/Dict insert items of {expr2} into {expr1}
feedkeys({string} [, {mode}]) Number add key sequence to typeahead buffer
@@ -466,10 +467,11 @@ str2list({expr} [, {utf8}]) List convert each character of {expr} to
ASCII/UTF-8 value
str2nr({expr} [, {base} [, {quoted}]])
Number convert String to Number
+strcharlen({expr}) Number character length of the String {expr}
strcharpart({str}, {start} [, {len}])
String {len} characters of {str} at
character {start}
-strchars({expr} [, {skipcc}]) Number character length of the String {expr}
+strchars({expr} [, {skipcc}]) Number character count of the String {expr}
strdisplaywidth({expr} [, {col}]) Number display length of the String {expr}
strftime({format} [, {time}]) String format time with a specified format
strgetchar({str}, {index}) Number get char {index} from {str}
@@ -654,9 +656,10 @@ appendbufline({buf}, {lnum}, {text}) *appendbufline()*
For the use of {buf}, see |bufname()|.
- {lnum} is used like with |append()|. Note that using |line()|
- would use the current buffer, not the one appending to.
- Use "$" to append at the end of the buffer.
+ {lnum} is the line number to append below. Note that using
+ |line()| would use the current buffer, not the one appending
+ to. Use "$" to append at the end of the buffer. Other string
+ values are not supported.
On success 0 is returned, on failure 1 is returned.
@@ -2042,18 +2045,27 @@ expand({string} [, {nosuf} [, {list}]]) *expand()*
Can also be used as a |method|: >
Getpattern()->expand()
-expandcmd({string}) *expandcmd()*
+expandcmd({string} [, {options}]) *expandcmd()*
Expand special items in String {string} like what is done for
an Ex command such as `:edit`. This expands special keywords,
like with |expand()|, and environment variables, anywhere in
{string}. "~user" and "~/path" are only expanded at the
start.
+
+ The following items are supported in the {options} Dict
+ argument:
+ errmsg If set to TRUE, error messages are displayed
+ if an error is encountered during expansion.
+ By default, error messages are not displayed.
+
Returns the expanded string. If an error is encountered
during expansion, the unmodified {string} is returned.
+
Example: >
:echo expandcmd('make %<.o')
-< make /path/runtime/doc/builtin.o ~
-
+ make /path/runtime/doc/builtin.o
+ :echo expandcmd('make %<.o', {'errmsg': v:true})
+<
Can also be used as a |method|: >
GetCommand()->expandcmd()
<
@@ -7080,8 +7092,8 @@ setloclist({nr}, {list} [, {action} [, {what}]]) *setloclist()*
GetLoclist()->setloclist(winnr)
setmatches({list} [, {win}]) *setmatches()*
- Restores a list of matches saved by |getmatches() for the
- current window|. Returns 0 if successful, otherwise -1. All
+ Restores a list of matches saved by |getmatches()| for the
+ current window. Returns 0 if successful, otherwise -1. All
current matches are cleared before the list is restored. See
example for |getmatches()|.
If {win} is specified, use the window with this number or
@@ -7261,6 +7273,7 @@ setqflist({list} [, {action} [, {what}]]) *setqflist()*
*setreg()*
setreg({regname}, {value} [, {options}])
Set the register {regname} to {value}.
+ If {regname} is "" or "@", the unnamed register '"' is used.
The {regname} argument is a string.
{value} may be any value returned by |getreg()| or
@@ -7834,6 +7847,21 @@ str2nr({string} [, {base}]) *str2nr()*
Can also be used as a |method|: >
GetText()->str2nr()
+
+strcharlen({string}) *strcharlen()*
+ The result is a Number, which is the number of characters
+ in String {string}. Composing characters are ignored.
+ |strchars()| can count the number of characters, counting
+ composing characters separately.
+
+ Returns 0 if {string} is empty or on error.
+
+ Also see |strlen()|, |strdisplaywidth()| and |strwidth()|.
+
+ Can also be used as a |method|: >
+ GetText()->strcharlen()
+
+
strcharpart({src}, {start} [, {len}]) *strcharpart()*
Like |strpart()| but using character index and length instead
of byte index and length. Composing characters are counted
@@ -7848,12 +7876,14 @@ strcharpart({src}, {start} [, {len}]) *strcharpart()*
Can also be used as a |method|: >
GetText()->strcharpart(5)
+
strchars({string} [, {skipcc}]) *strchars()*
The result is a Number, which is the number of characters
in String {string}.
When {skipcc} is omitted or zero, composing characters are
counted separately.
When {skipcc} set to 1, Composing characters are ignored.
+ |strcharlen()| always does this.
Returns zero on error.
diff --git a/runtime/doc/editing.txt b/runtime/doc/editing.txt
index 21a30ca429..58a5cbc60c 100644
--- a/runtime/doc/editing.txt
+++ b/runtime/doc/editing.txt
@@ -545,6 +545,44 @@ Before editing binary, executable or Vim script files you should set the
option. This will avoid the use of 'fileformat'. Without this you risk that
single <NL> characters are unexpectedly replaced with <CR><NL>.
+END OF LINE AND END OF FILE *eol-and-eof*
+
+Vim has several options to control the file format:
+ 'fileformat' the <EOL> style: Unix, DOS, Mac
+ 'endofline' whether the last line ends with a <EOL>
+ 'endoffile' whether the file ends with a CTRL-Z
+ 'fixendofline' whether to fix eol and eof
+
+The first three values are normally detected automatically when reading the
+file and are used when writing the text to a file. While editing the buffer
+it looks like every line has a line ending and the CTRL-Z isn't there (an
+exception is when 'binary' is set, it works differently then).
+
+The 'fixendofline' option can be used to choose what to write. You can also
+change the option values to write the file differently than how it was read.
+
+Here are some examples how to use them.
+
+If you want files in Unix format (every line NL terminated): >
+ setl ff=unix fixeol
+You should probably do this on any Unix-like system. Also modern MS-Windows
+systems tend to work well with this. It is recommended to always use this
+format for Vim scripts.
+
+If you want to use an old MS-DOS file in a modern environment, fixing line
+endings and dropping CTRL-Z, but keeping the <CR><NL> style <EOL>: >
+ setl ff=dos fixeol
+This is useful for many MS-Windows programs, they regularly expect the
+<CR><NL> line endings.
+
+If you want to drop the final <EOL> and add a final CTRL-Z (e.g. for an old
+system like CP/M): >
+ setl ff=dos nofixeol noeol eof
+
+If you want to preserve the fileformat exactly as-is, including any final
+<EOL> and final CTRL-Z: >
+ setl nofixeol
+
==============================================================================
3. The argument list *argument-list* *arglist*
diff --git a/runtime/doc/lua.txt b/runtime/doc/lua.txt
index 70a28a7519..c4e139bca7 100644
--- a/runtime/doc/lua.txt
+++ b/runtime/doc/lua.txt
@@ -677,6 +677,9 @@ vim.diff({a}, {b}, {opts}) *vim.diff()*
• "unified": (default) String in unified format.
• "indices": Array of hunk locations.
Note: This option is ignored if `on_hunk` is used.
+ • `linematch` (boolean): Run linematch on the resulting hunks
+ from xdiff. Requires `result_type = indices`, ignored
+ otherwise.
• `algorithm` (string):
Diff algorithm to use. Values:
• "myers" the default algorithm
diff --git a/runtime/doc/options.txt b/runtime/doc/options.txt
index 4718876b29..818c6d0115 100644
--- a/runtime/doc/options.txt
+++ b/runtime/doc/options.txt
@@ -1053,19 +1053,26 @@ A jump table for the options with a short description can be found at |Q_op|.
text should normally be narrower. This prevents
text indented almost to the right window border
occupying lot of vertical space when broken.
+ (default: 20)
shift:{n} After applying 'breakindent', the wrapped line's
beginning will be shifted by the given number of
characters. It permits dynamic French paragraph
indentation (negative) or emphasizing the line
continuation (positive).
+ (default: 0)
sbr Display the 'showbreak' value before applying the
additional indent.
+ (default: off)
list:{n} Adds an additional indent for lines that match a
numbered or bulleted list (using the
'formatlistpat' setting).
list:-1 Uses the length of a match with 'formatlistpat'
for indentation.
- The default value for min is 20, shift and list is 0.
+ (default: 0)
+ column:{n} Indent at column {n}. Will overrule the other
+ sub-options. Note: an additional indent may be
+ added for the 'showbreak' setting.
+ (default: off)
*'browsedir'* *'bsdir'*
'browsedir' 'bsdir' string (default: "last")
@@ -2017,6 +2024,16 @@ A jump table for the options with a short description can be found at |Q_op|.
Use the indent heuristic for the internal
diff library.
+ linematch:{n} Enable a second stage diff on each generated
+ hunk in order to align lines. When the total
+ number of lines in a hunk exceeds {n}, the
+ second stage diff will not be performed as
+ very large hunks can cause noticeable lag. A
+ recommended setting is "linematch:60", as this
+ will enable alignment for a 2 buffer diff with
+ hunks of up to 30 lines each, or a 3 buffer
+ diff with hunks of up to 20 lines each.
+
algorithm:{text} Use the specified diff algorithm with the
internal diff engine. Currently supported
algorithms are:
@@ -2143,6 +2160,7 @@ A jump table for the options with a short description can be found at |Q_op|.
When writing a file and this option is off and the 'binary' option
is on, or 'fixeol' option is off, no CTRL-Z will be written at the
end of the file.
+ See |eol-and-eof| for example settings.
*'endofline'* *'eol'* *'noendofline'* *'noeol'*
'endofline' 'eol' boolean (default on)
@@ -2158,6 +2176,7 @@ A jump table for the options with a short description can be found at |Q_op|.
to remember the presence of a <EOL> for the last line in the file, so
that when you write the file the situation from the original file can
be kept. But you can change it if you want to.
+ See |eol-and-eof| for example settings.
*'equalalways'* *'ea'* *'noequalalways'* *'noea'*
'equalalways' 'ea' boolean (default on)
@@ -2504,6 +2523,7 @@ A jump table for the options with a short description can be found at |Q_op|.
When the 'binary' option is set the value of this option doesn't
matter.
See the 'endofline' option.
+ See |eol-and-eof| for example settings.
*'foldclose'* *'fcl'*
'foldclose' 'fcl' string (default "")
diff --git a/runtime/doc/pattern.txt b/runtime/doc/pattern.txt
index 371a210847..5357aaa3f1 100644
--- a/runtime/doc/pattern.txt
+++ b/runtime/doc/pattern.txt
@@ -372,7 +372,7 @@ Vim includes two regexp engines:
1. An old, backtracking engine that supports everything.
2. A new, NFA engine that works much faster on some patterns, possibly slower
on some patterns.
-
+ *E1281*
Vim will automatically select the right engine for you. However, if you run
into a problem or want to specifically select one engine or the other, you can
prepend one of the following to the pattern:
diff --git a/runtime/doc/repeat.txt b/runtime/doc/repeat.txt
index 6a1b8b05a7..1bbd20702b 100644
--- a/runtime/doc/repeat.txt
+++ b/runtime/doc/repeat.txt
@@ -689,7 +689,7 @@ found automatically. Your package would have these files:
< pack/foo/start/lib/autoload/foolib.vim >
func foolib#getit()
-This works, because start packages will be searchd for autoload files, when
+This works, because start packages will be searched for autoload files, when
sourcing the plugins.
==============================================================================
diff --git a/runtime/doc/testing.txt b/runtime/doc/testing.txt
index f4375c3363..56e0dad656 100644
--- a/runtime/doc/testing.txt
+++ b/runtime/doc/testing.txt
@@ -98,18 +98,46 @@ assert_exception({error} [, {msg}]) *assert_exception()*
catch
call assert_exception('E492:')
endtry
-
-assert_fails({cmd} [, {error} [, {msg}]]) *assert_fails()*
+<
+ *assert_fails()*
+assert_fails({cmd} [, {error} [, {msg} [, {lnum} [, {context}]]]])
Run {cmd} and add an error message to |v:errors| if it does
- NOT produce an error. Also see |assert-return|.
- When {error} is given it must match in |v:errmsg|.
+ NOT produce an error or when {error} is not found in the
+ error message. Also see |assert-return|.
+
+ When {error} is a string it must be found literally in the
+ first reported error. Most often this will be the error code,
+ including the colon, e.g. "E123:". >
+ assert_fails('bad cmd', 'E987:')
+<
+ When {error} is a |List| with one or two strings, these are
+ used as patterns. The first pattern is matched against the
+ first reported error: >
+ assert_fails('cmd', ['E987:.*expected bool'])
+< The second pattern, if present, is matched against the last
+ reported error. To only match the last error use an empty
+ string for the first error: >
+ assert_fails('cmd', ['', 'E987:'])
+<
+ If {msg} is empty then it is not used. Do this to get the
+ default message when passing the {lnum} argument.
+
+ When {lnum} is present and not negative, and the {error}
+ argument is present and matches, then this is compared with
+ the line number at which the error was reported. That can be
+ the line number in a function or in a script.
+
+ When {context} is present it is used as a pattern and matched
+ against the context (script name or function name) where
+ {lnum} is located in.
+
Note that beeping is not considered an error, and some failing
commands only beep. Use |assert_beeps()| for those.
Can also be used as a |method|: >
GetCmd()->assert_fails('E99:')
-assert_false({actual} [, {msg}]) *assert_false()*
+assert_false({actual} [, {msg}]) *assert_false()*
When {actual} is not false an error message is added to
|v:errors|, like with |assert_equal()|.
Also see |assert-return|.
diff --git a/runtime/doc/usr_41.txt b/runtime/doc/usr_41.txt
index 8abc5bdf06..067ad6648c 100644
--- a/runtime/doc/usr_41.txt
+++ b/runtime/doc/usr_41.txt
@@ -619,7 +619,8 @@ String manipulation: *string-functions*
stridx() first index of a short string in a long string
strridx() last index of a short string in a long string
strlen() length of a string in bytes
- strchars() length of a string in characters
+ strcharlen() length of a string in characters
+ strchars() number of characters in a string
strwidth() size of string when displayed
strdisplaywidth() size of string when displayed, deals with tabs
setcellwidths() set character cell width overrides
diff --git a/runtime/lua/man.lua b/runtime/lua/man.lua
index 6eebee6376..5951884e07 100644
--- a/runtime/lua/man.lua
+++ b/runtime/lua/man.lua
@@ -457,7 +457,7 @@ local function get_page(path, silent)
end
local function put_page(page)
- vim.bo.modified = true
+ vim.bo.modifiable = true
vim.bo.readonly = false
vim.bo.swapfile = false
diff --git a/scripts/lua2dox.lua b/scripts/lua2dox.lua
index 86afe97a7e..83bf213f40 100644
--- a/scripts/lua2dox.lua
+++ b/scripts/lua2dox.lua
@@ -497,14 +497,14 @@ function TLua2DoX_filter.readfile(this, AppStamp, Filename)
else
this:warning(inStream:getLineNo(), 'something weird here')
end
- fn_magic = nil -- mustn't indavertently use it again
+ fn_magic = nil -- mustn't inadvertently use it again
-- TODO: If we can make this learn how to generate these, that would be helpful.
-- elseif string.find(line, "^M%['.*'%] = function") then
-- state = 'in_function' -- it's a function
-- outStream:writeln("function textDocument/publishDiagnostics(...){}")
- -- fn_magic = nil -- mustn't indavertently use it again
+ -- fn_magic = nil -- mustn't inadvertently use it again
else
state = '' -- unknown
if #line > 0 then -- we don't know what this line means, so just comment it out
diff --git a/scripts/pvscheck.sh b/scripts/pvscheck.sh
index 610c20eb48..97757c0848 100755
--- a/scripts/pvscheck.sh
+++ b/scripts/pvscheck.sh
@@ -328,7 +328,7 @@ realdir() {(
patch_sources() {(
local tgt="$1" ; shift
- local only_bulid="${1}" ; shift
+ local only_build="${1}" ; shift
get_pvs_comment "$tgt"
diff --git a/src/nvim/README.md b/src/nvim/README.md
index 91fb3ca2f6..e710c3ef58 100644
--- a/src/nvim/README.md
+++ b/src/nvim/README.md
@@ -391,8 +391,8 @@ implemented by libuv, the platform layer used by Nvim.
Since Nvim inherited its code from Vim, the states are not prepared to receive
"arbitrary events", so we use a special key to represent those (When a state
-receives an "arbitrary event", it normally doesn't do anything other update the
-screen).
+receives an "arbitrary event", it normally doesn't do anything other than
+update the screen).
Main loop
---------
diff --git a/src/nvim/buffer_defs.h b/src/nvim/buffer_defs.h
index d8edd4b2d0..4e46a1aef2 100644
--- a/src/nvim/buffer_defs.h
+++ b/src/nvim/buffer_defs.h
@@ -894,6 +894,8 @@ struct diffblock_S {
diff_T *df_next;
linenr_T df_lnum[DB_COUNT]; // line number in buffer
linenr_T df_count[DB_COUNT]; // nr of inserted/changed lines
+ bool is_linematched; // has the linematch algorithm ran on this diff hunk to divide it into
+ // smaller diff hunks?
};
#define SNAP_HELP_IDX 0
@@ -961,7 +963,8 @@ struct frame_S {
// for first
// fr_child and fr_win are mutually exclusive
frame_T *fr_child; // first contained frame
- win_T *fr_win; // window that fills this frame
+ win_T *fr_win; // window that fills this frame; for a snapshot
+ // set to the current window
};
#define FR_LEAF 0 // frame is a leaf
@@ -1338,6 +1341,7 @@ struct window_S {
int w_briopt_shift; // additional shift for breakindent
bool w_briopt_sbr; // sbr in 'briopt'
int w_briopt_list; // additional indent for lists
+ int w_briopt_vcol; // indent for specific column
// transform a pointer to a "onebuf" option into a "allbuf" option
#define GLOBAL_WO(p) ((char *)(p) + sizeof(winopt_T))
diff --git a/src/nvim/cmdexpand.c b/src/nvim/cmdexpand.c
index ca95a9a24e..480f3aa18c 100644
--- a/src/nvim/cmdexpand.c
+++ b/src/nvim/cmdexpand.c
@@ -1246,7 +1246,7 @@ static const char *set_context_by_cmdname(const char *cmd, cmdidx_T cmdidx, cons
arg = (const char *)skipwhite(skiptowhite(arg));
if (*arg != NUL) {
xp->xp_context = EXPAND_NOTHING;
- arg = (const char *)skip_regexp((char *)arg + 1, (uint8_t)(*arg), p_magic, NULL);
+ arg = (const char *)skip_regexp((char *)arg + 1, (uint8_t)(*arg), p_magic);
}
}
return (const char *)find_nextcmd(arg);
@@ -1285,7 +1285,7 @@ static const char *set_context_by_cmdname(const char *cmd, cmdidx_T cmdidx, cons
if (delim) {
// Skip "from" part.
arg++;
- arg = (const char *)skip_regexp((char *)arg, delim, p_magic, NULL);
+ arg = (const char *)skip_regexp((char *)arg, delim, p_magic);
}
// Skip "to" part.
while (arg[0] != NUL && (uint8_t)arg[0] != delim) {
diff --git a/src/nvim/diff.c b/src/nvim/diff.c
index 964db599a3..503e546562 100644
--- a/src/nvim/diff.c
+++ b/src/nvim/diff.c
@@ -27,6 +27,7 @@
#include "nvim/fileio.h"
#include "nvim/fold.h"
#include "nvim/garray.h"
+#include "nvim/linematch.h"
#include "nvim/mark.h"
#include "nvim/mbyte.h"
#include "nvim/memline.h"
@@ -62,10 +63,12 @@ static bool diff_need_update = false; // ex_diffupdate needs to be called
#define DIFF_INTERNAL 0x200 // use internal xdiff algorithm
#define DIFF_CLOSE_OFF 0x400 // diffoff when closing window
#define DIFF_FOLLOWWRAP 0x800 // follow the wrap option
+#define DIFF_LINEMATCH 0x1000 // match most similar lines within diff
#define ALL_WHITE_DIFF (DIFF_IWHITE | DIFF_IWHITEALL | DIFF_IWHITEEOL)
static int diff_flags = DIFF_INTERNAL | DIFF_FILLER | DIFF_CLOSE_OFF;
static long diff_algorithm = 0;
+static int linematch_lines = 0;
#define LBUFLEN 50 // length of line in diff file
@@ -362,7 +365,7 @@ static void diff_mark_adjust_tp(tabpage_T *tp, int idx, linenr_T line1, linenr_T
if (last >= line1 - 1) {
// 6. change below line2: only adjust for amount_after; also when
// "deleted" became zero when deleted all lines between two diffs.
- if (dp->df_lnum[idx] - (deleted + inserted != 0) > line2) {
+ if (dp->df_lnum[idx] - (deleted + inserted != 0) > line2 - dp->is_linematched) {
if (amount_after == 0) {
// nothing left to change
break;
@@ -454,7 +457,7 @@ static void diff_mark_adjust_tp(tabpage_T *tp, int idx, linenr_T line1, linenr_T
}
// check if this block touches the previous one, may merge them.
- if ((dprev != NULL)
+ if ((dprev != NULL) && !dp->is_linematched
&& (dprev->df_lnum[idx] + dprev->df_count[idx] == dp->df_lnum[idx])) {
int i;
for (i = 0; i < DB_COUNT; i++) {
@@ -513,6 +516,7 @@ static diff_T *diff_alloc_new(tabpage_T *tp, diff_T *dprev, diff_T *dp)
{
diff_T *dnew = xmalloc(sizeof(*dnew));
+ dnew->is_linematched = false;
dnew->df_next = dp;
if (dprev == NULL) {
tp->tp_first_diff = dnew;
@@ -727,12 +731,16 @@ static void clear_diffout(diffout_T *dout)
/// @param din
///
/// @return FAIL for failure.
-static int diff_write_buffer(buf_T *buf, mmfile_t *m)
+static int diff_write_buffer(buf_T *buf, mmfile_t *m, linenr_T start, linenr_T end)
{
size_t len = 0;
+ if (end < 0) {
+ end = buf->b_ml.ml_line_count;
+ }
+
// xdiff requires one big block of memory with all the text.
- for (linenr_T lnum = 1; lnum <= buf->b_ml.ml_line_count; lnum++) {
+ for (linenr_T lnum = start; lnum <= end; lnum++) {
len += strlen(ml_get_buf(buf, lnum, false)) + 1;
}
char *ptr = try_malloc(len);
@@ -753,7 +761,7 @@ static int diff_write_buffer(buf_T *buf, mmfile_t *m)
m->size = (long)len;
len = 0;
- for (linenr_T lnum = 1; lnum <= buf->b_ml.ml_line_count; lnum++) {
+ for (linenr_T lnum = start; lnum <= end; lnum++) {
char *s = ml_get_buf(buf, lnum, false);
if (diff_flags & DIFF_ICASE) {
while (*s != NUL) {
@@ -792,7 +800,7 @@ static int diff_write_buffer(buf_T *buf, mmfile_t *m)
static int diff_write(buf_T *buf, diffin_T *din)
{
if (din->din_fname == NULL) {
- return diff_write_buffer(buf, &din->din_mmfile);
+ return diff_write_buffer(buf, &din->din_mmfile, 1, -1);
}
// Always use 'fileformat' set to "unix".
@@ -1784,6 +1792,294 @@ void diff_clear(tabpage_T *tp)
tp->tp_first_diff = NULL;
}
+///
+/// return true if the options are set to use diff linematch
+///
+bool diff_linematch(diff_T *dp)
+{
+ if (!(diff_flags & DIFF_LINEMATCH)) {
+ return false;
+ }
+ // are there more than three diff buffers?
+ int tsize = 0;
+ for (int i = 0; i < DB_COUNT; i++) {
+ if (curtab->tp_diffbuf[i] != NULL) {
+ // for the rare case (bug?) that the count of a diff block is negative, do
+ // not run the algorithm because this will try to allocate a negative
+ // amount of space and crash
+ if (dp->df_count[i] < 0) {
+ return false;
+ }
+ tsize += dp->df_count[i];
+ }
+ }
+ // avoid allocating a huge array because it will lag
+ return tsize <= linematch_lines;
+}
+
+static int get_max_diff_length(const diff_T *dp)
+{
+ int maxlength = 0;
+ for (int k = 0; k < DB_COUNT; k++) {
+ if (curtab->tp_diffbuf[k] != NULL) {
+ if (dp->df_count[k] > maxlength) {
+ maxlength = dp->df_count[k];
+ }
+ }
+ }
+ return maxlength;
+}
+
+static void find_top_diff_block(diff_T **thistopdiff, diff_T **nextblockblock, int fromidx,
+ int topline)
+{
+ diff_T *topdiff = NULL;
+ diff_T *localtopdiff = NULL;
+ int topdiffchange = 0;
+
+ for (topdiff = curtab->tp_first_diff; topdiff != NULL; topdiff = topdiff->df_next) {
+ // set the top of the current overlapping diff block set as we
+ // iterate through all of the sets of overlapping diff blocks
+ if (!localtopdiff || topdiffchange) {
+ localtopdiff = topdiff;
+ topdiffchange = 0;
+ }
+
+ // check if the fromwin topline is matched by the current diff. if so, set it to the top of the diff block
+ if (topline >= topdiff->df_lnum[fromidx] && topline <=
+ (topdiff->df_lnum[fromidx] + topdiff->df_count[fromidx])) {
+ // this line is inside the current diff block, so we will save the
+ // top block of the set of blocks to refer to later
+ if ((*thistopdiff) == NULL) {
+ (*thistopdiff) = localtopdiff;
+ }
+ }
+
+ // check if the next set of overlapping diff blocks is next
+ if (!(topdiff->df_next && (topdiff->df_next->df_lnum[fromidx] ==
+ (topdiff->df_lnum[fromidx] + topdiff->df_count[fromidx])))) {
+ // mark that the next diff block is belongs to a different set of
+ // overlapping diff blocks
+ topdiffchange = 1;
+
+ // if we already have found that the line number is inside a diff block,
+ // set the marker of the next block and finish the iteration
+ if (*thistopdiff) {
+ (*nextblockblock) = topdiff->df_next;
+ break;
+ }
+ }
+ }
+}
+
+static void count_filler_lines_and_topline(int *curlinenum_to, int *linesfiller,
+ const diff_T *thistopdiff, const int toidx,
+ int virtual_lines_passed)
+{
+ const diff_T *curdif = thistopdiff;
+ int ch_virtual_lines = 0;
+ int isfiller = 0;
+ while (virtual_lines_passed) {
+ if (ch_virtual_lines) {
+ virtual_lines_passed--;
+ ch_virtual_lines--;
+ if (!isfiller) {
+ (*curlinenum_to)++;
+ } else {
+ (*linesfiller)++;
+ }
+ } else {
+ (*linesfiller) = 0;
+ ch_virtual_lines = get_max_diff_length(curdif);
+ isfiller = (curdif->df_count[toidx] ? 0 : 1);
+ if (isfiller) {
+ while (curdif && curdif->df_next && curdif->df_lnum[toidx] ==
+ curdif->df_next->df_lnum[toidx]
+ && curdif->df_next->df_count[toidx] == 0) {
+ curdif = curdif->df_next;
+ ch_virtual_lines += get_max_diff_length(curdif);
+ }
+ }
+ if (curdif) {
+ curdif = curdif->df_next;
+ }
+ }
+ }
+}
+
+static void calculate_topfill_and_topline(const int fromidx, const int toidx, const
+ int from_topline, const int from_topfill, int *topfill,
+ linenr_T *topline)
+{
+ // 1. find the position from the top of the diff block, and the start
+ // of the next diff block
+ diff_T *thistopdiff = NULL;
+ diff_T *nextblockblock = NULL;
+ int virtual_lines_passed = 0;
+
+ find_top_diff_block(&thistopdiff, &nextblockblock, fromidx, from_topline);
+
+ // count the virtual lines that have been passed
+
+ diff_T *curdif = thistopdiff;
+ while (curdif && (curdif->df_lnum[fromidx] + curdif->df_count[fromidx])
+ <= from_topline) {
+ virtual_lines_passed += get_max_diff_length(curdif);
+
+ curdif = curdif->df_next;
+ }
+
+ if (curdif != nextblockblock) {
+ virtual_lines_passed += from_topline - curdif->df_lnum[fromidx];
+ }
+ virtual_lines_passed -= from_topfill;
+
+ // count the same amount of virtual lines in the toidx buffer
+ curdif = thistopdiff;
+ int curlinenum_to = thistopdiff->df_lnum[toidx];
+ int linesfiller = 0;
+ count_filler_lines_and_topline(&curlinenum_to, &linesfiller,
+ thistopdiff, toidx, virtual_lines_passed);
+
+ // count the number of filler lines that would normally be above this line
+ int maxfiller = 0;
+ for (diff_T *dpfillertest = thistopdiff; dpfillertest != NULL;
+ dpfillertest = dpfillertest->df_next) {
+ if (dpfillertest->df_lnum[toidx] == curlinenum_to) {
+ while (dpfillertest && dpfillertest->df_lnum[toidx] == curlinenum_to) {
+ maxfiller += dpfillertest->df_count[toidx] ? 0 : get_max_diff_length(dpfillertest);
+ dpfillertest = dpfillertest->df_next;
+ }
+ break;
+ }
+ }
+ (*topfill) = maxfiller - linesfiller;
+ (*topline) = curlinenum_to;
+}
+
+static int linematched_filler_lines(diff_T *dp, int idx, linenr_T lnum, int *linestatus)
+{
+ int filler_lines_d1 = 0;
+ while (dp && dp->df_next
+ && lnum == (dp->df_lnum[idx] + dp->df_count[idx])
+ && dp->df_next->df_lnum[idx] == lnum) {
+ if (dp->df_count[idx] == 0) {
+ filler_lines_d1 += get_max_diff_length(dp);
+ }
+ dp = dp->df_next;
+ }
+
+ if (dp->df_count[idx] == 0) {
+ filler_lines_d1 += get_max_diff_length(dp);
+ }
+
+ if (lnum < dp->df_lnum[idx] + dp->df_count[idx]) {
+ int j = 0;
+ for (int i = 0; i < DB_COUNT; i++) {
+ if (curtab->tp_diffbuf[i] != NULL) {
+ if (dp->df_count[i]) {
+ j++;
+ }
+ }
+ // is this an added line or a changed line?
+ if (linestatus) {
+ (*linestatus) = (j == 1) ? -2 : -1;
+ }
+ }
+ }
+ return filler_lines_d1;
+}
+
+// Apply results from the linematch algorithm and apply to 'dp' by splitting it into multiple
+// adjacent diff blocks.
+static void apply_linematch_results(diff_T *dp, size_t decisions_length, const int *decisions)
+{
+ // get the start line number here in each diff buffer, and then increment
+ int line_numbers[DB_COUNT];
+ int outputmap[DB_COUNT];
+ size_t ndiffs = 0;
+ for (int i = 0; i < DB_COUNT; i++) {
+ if (curtab->tp_diffbuf[i] != NULL) {
+ line_numbers[i] = dp->df_lnum[i];
+ dp->df_count[i] = 0;
+
+ // Keep track of the index of the diff buffer we are using here.
+ // We will use this to write the output of the algorithm to
+ // diff_T structs at the correct indexes
+ outputmap[ndiffs] = i;
+ ndiffs++;
+ }
+ }
+
+ // write the diffs starting with the current diff block
+ diff_T *dp_s = dp;
+ for (size_t i = 0; i < decisions_length; i++) {
+ // Don't allocate on first iter since we can reuse the initial diffblock
+ if (i != 0 && (decisions[i - 1] != decisions[i])) {
+ // create new sub diff blocks to segment the original diff block which we
+ // further divided by running the linematch algorithm
+ dp_s = diff_alloc_new(curtab, dp_s, dp_s->df_next);
+ dp_s->is_linematched = true;
+ for (int j = 0; j < DB_COUNT; j++) {
+ if (curtab->tp_diffbuf[j] != NULL) {
+ dp_s->df_lnum[j] = line_numbers[j];
+ dp_s->df_count[j] = 0;
+ }
+ }
+ }
+ for (size_t j = 0; j < ndiffs; j++) {
+ if (decisions[i] & (1 << j)) {
+ // will need to use the map here
+ dp_s->df_count[outputmap[j]]++;
+ line_numbers[outputmap[j]]++;
+ }
+ }
+ }
+ dp->is_linematched = true;
+}
+
+static void run_linematch_algorithm(diff_T *dp)
+{
+ // define buffers for diff algorithm
+ mmfile_t diffbufs_mm[DB_COUNT];
+ const char *diffbufs[DB_COUNT];
+ int diff_length[DB_COUNT];
+ size_t ndiffs = 0;
+ for (int i = 0; i < DB_COUNT; i++) {
+ if (curtab->tp_diffbuf[i] != NULL) {
+ // write the contents of the entire buffer to
+ // diffbufs_mm[diffbuffers_count]
+ diff_write_buffer(curtab->tp_diffbuf[i], &diffbufs_mm[ndiffs],
+ dp->df_lnum[i], dp->df_lnum[i] + dp->df_count[i] - 1);
+
+ // we want to get the char* to the diff buffer that was just written
+ // we add it to the array of char*, diffbufs
+ diffbufs[ndiffs] = diffbufs_mm[ndiffs].ptr;
+
+ // keep track of the length of this diff block to pass it to the linematch
+ // algorithm
+ diff_length[ndiffs] = dp->df_count[i];
+
+ // increment the amount of diff buffers we are passing to the algorithm
+ ndiffs++;
+ }
+ }
+
+ // we will get the output of the linematch algorithm in the format of an array
+ // of integers (*decisions) and the length of that array (decisions_length)
+ int *decisions = NULL;
+ const bool iwhite = (diff_flags & (DIFF_IWHITEALL | DIFF_IWHITE)) > 0;
+ size_t decisions_length = linematch_nbuffers(diffbufs, diff_length, ndiffs, &decisions, iwhite);
+
+ for (size_t i = 0; i < ndiffs; i++) {
+ XFREE_CLEAR(diffbufs_mm[i].ptr);
+ }
+
+ apply_linematch_results(dp, decisions_length, decisions);
+
+ xfree(decisions);
+}
+
/// Check diff status for line "lnum" in buffer "buf":
///
/// Returns 0 for nothing special
@@ -1795,9 +2091,10 @@ void diff_clear(tabpage_T *tp)
///
/// @param wp
/// @param lnum
+/// @param[out] linestatus
///
/// @return diff status.
-int diff_check(win_T *wp, linenr_T lnum)
+int diff_check_with_linestatus(win_T *wp, linenr_T lnum, int *linestatus)
{
buf_T *buf = wp->w_buffer;
@@ -1840,6 +2137,14 @@ int diff_check(win_T *wp, linenr_T lnum)
return 0;
}
+ if (!dp->is_linematched && diff_linematch(dp)) {
+ run_linematch_algorithm(dp);
+ }
+
+ if (dp->is_linematched) {
+ return linematched_filler_lines(dp, idx, lnum, linestatus);
+ }
+
if (lnum < dp->df_lnum[idx] + dp->df_count[idx]) {
int zero = false;
@@ -1894,15 +2199,16 @@ int diff_check(win_T *wp, linenr_T lnum)
// Insert filler lines above the line just below the change. Will return
// 0 when this buf had the max count.
- linenr_T maxcount = 0;
- for (int i = 0; i < DB_COUNT; i++) {
- if ((curtab->tp_diffbuf[i] != NULL) && (dp->df_count[i] > maxcount)) {
- maxcount = dp->df_count[i];
- }
- }
+ int maxcount = get_max_diff_length(dp);
return maxcount - dp->df_count[idx];
}
+/// See diff_check_with_linestatus
+int diff_check(win_T *wp, linenr_T lnum)
+{
+ return diff_check_with_linestatus(wp, lnum, NULL);
+}
+
/// Compare two entries in diff "dp" and return true if they are equal.
///
/// @param dp diff
@@ -2062,46 +2368,51 @@ void diff_set_topline(win_T *fromwin, win_T *towin)
towin->w_topline = lnum + (dp->df_lnum[toidx] - dp->df_lnum[fromidx]);
if (lnum >= dp->df_lnum[fromidx]) {
- // Inside a change: compute filler lines. With three or more
- // buffers we need to know the largest count.
- linenr_T max_count = 0;
-
- for (int i = 0; i < DB_COUNT; i++) {
- if ((curtab->tp_diffbuf[i] != NULL) && (max_count < dp->df_count[i])) {
- max_count = dp->df_count[i];
- }
- }
+ if (diff_flags & DIFF_LINEMATCH) {
+ calculate_topfill_and_topline(fromidx, toidx, fromwin->w_topline,
+ fromwin->w_topfill, &towin->w_topfill, &towin->w_topline);
+ } else {
+ // Inside a change: compute filler lines. With three or more
+ // buffers we need to know the largest count.
+ linenr_T max_count = 0;
- if (dp->df_count[toidx] == dp->df_count[fromidx]) {
- // same number of lines: use same filler count
- towin->w_topfill = fromwin->w_topfill;
- } else if (dp->df_count[toidx] > dp->df_count[fromidx]) {
- if (lnum == dp->df_lnum[fromidx] + dp->df_count[fromidx]) {
- // more lines in towin and fromwin doesn't show diff
- // lines, only filler lines
- if (max_count - fromwin->w_topfill >= dp->df_count[toidx]) {
- // towin also only shows filler lines
- towin->w_topline = dp->df_lnum[toidx] + dp->df_count[toidx];
- towin->w_topfill = fromwin->w_topfill;
- } else {
- // towin still has some diff lines to show
- towin->w_topline = dp->df_lnum[toidx]
- + max_count - fromwin->w_topfill;
+ for (int i = 0; i < DB_COUNT; i++) {
+ if ((curtab->tp_diffbuf[i] != NULL) && (max_count < dp->df_count[i])) {
+ max_count = dp->df_count[i];
}
}
- } else if (towin->w_topline >= dp->df_lnum[toidx]
- + dp->df_count[toidx]) {
- // less lines in towin and no diff lines to show: compute
- // filler lines
- towin->w_topline = dp->df_lnum[toidx] + dp->df_count[toidx];
- if (diff_flags & DIFF_FILLER) {
+ if (dp->df_count[toidx] == dp->df_count[fromidx]) {
+ // same number of lines: use same filler count
+ towin->w_topfill = fromwin->w_topfill;
+ } else if (dp->df_count[toidx] > dp->df_count[fromidx]) {
if (lnum == dp->df_lnum[fromidx] + dp->df_count[fromidx]) {
- // fromwin is also out of diff lines
- towin->w_topfill = fromwin->w_topfill;
- } else {
- // fromwin has some diff lines
- towin->w_topfill = dp->df_lnum[fromidx] + max_count - lnum;
+ // more lines in towin and fromwin doesn't show diff
+ // lines, only filler lines
+ if (max_count - fromwin->w_topfill >= dp->df_count[toidx]) {
+ // towin also only shows filler lines
+ towin->w_topline = dp->df_lnum[toidx] + dp->df_count[toidx];
+ towin->w_topfill = fromwin->w_topfill;
+ } else {
+ // towin still has some diff lines to show
+ towin->w_topline = dp->df_lnum[toidx]
+ + max_count - fromwin->w_topfill;
+ }
+ }
+ } else if (towin->w_topline >= dp->df_lnum[toidx]
+ + dp->df_count[toidx]) {
+ // less lines in towin and no diff lines to show: compute
+ // filler lines
+ towin->w_topline = dp->df_lnum[toidx] + dp->df_count[toidx];
+
+ if (diff_flags & DIFF_FILLER) {
+ if (lnum == dp->df_lnum[fromidx] + dp->df_count[fromidx]) {
+ // fromwin is also out of diff lines
+ towin->w_topfill = fromwin->w_topfill;
+ } else {
+ // fromwin has some diff lines
+ towin->w_topfill = dp->df_lnum[fromidx] + max_count - lnum;
+ }
}
}
}
@@ -2136,6 +2447,7 @@ void diff_set_topline(win_T *fromwin, win_T *towin)
int diffopt_changed(void)
{
int diff_context_new = 6;
+ int linematch_lines_new = 0;
int diff_flags_new = 0;
int diff_foldcolumn_new = 2;
long diff_algorithm_new = 0;
@@ -2205,6 +2517,10 @@ int diffopt_changed(void)
} else {
return FAIL;
}
+ } else if ((STRNCMP(p, "linematch:", 10) == 0) && ascii_isdigit(p[10])) {
+ p += 10;
+ linematch_lines_new = getdigits_int(&p, false, linematch_lines_new);
+ diff_flags_new |= DIFF_LINEMATCH;
}
if ((*p != ',') && (*p != NUL)) {
@@ -2233,6 +2549,7 @@ int diffopt_changed(void)
diff_flags = diff_flags_new;
diff_context = diff_context_new == 0 ? 1 : diff_context_new;
+ linematch_lines = linematch_lines_new;
diff_foldcolumn = diff_foldcolumn_new;
diff_algorithm = diff_algorithm_new;
@@ -2300,6 +2617,13 @@ bool diff_find_change(win_T *wp, linenr_T lnum, int *startp, int *endp)
break;
}
}
+ if (dp->is_linematched) {
+ while (dp && dp->df_next
+ && lnum == dp->df_count[idx] + dp->df_lnum[idx]
+ && dp->df_next->df_lnum[idx] == lnum) {
+ dp = dp->df_next;
+ }
+ }
if ((dp == NULL) || (diff_check_sanity(curtab, dp) == FAIL)) {
xfree(line_org);
@@ -2674,6 +2998,17 @@ static void diffgetput(const int addr_count, const int idx_cur, const int idx_fr
diff_T *dprev = NULL;
for (diff_T *dp = curtab->tp_first_diff; dp != NULL;) {
+ if (!addr_count) {
+ // handle the case with adjacent diff blocks
+ while (dp->is_linematched
+ && dp->df_next
+ && dp->df_next->df_lnum[idx_cur] == dp->df_lnum[idx_cur] + dp->df_count[idx_cur]
+ && dp->df_next->df_lnum[idx_cur] == line1 + off + 1) {
+ dprev = dp;
+ dp = dp->df_next;
+ }
+ }
+
if (dp->df_lnum[idx_cur] > line2 + off) {
// past the range that was specified
break;
diff --git a/src/nvim/drawline.c b/src/nvim/drawline.c
index 08b6fd89af..cb7d85a467 100644
--- a/src/nvim/drawline.c
+++ b/src/nvim/drawline.c
@@ -804,9 +804,10 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool nochange,
int bg_attr = win_bg_attr(wp);
- filler_lines = diff_check(wp, lnum);
- if (filler_lines < 0) {
- if (filler_lines == -1) {
+ int linestatus = 0;
+ filler_lines = diff_check_with_linestatus(wp, lnum, &linestatus);
+ if (filler_lines < 0 || linestatus < 0) {
+ if (filler_lines == -1 || linestatus == -1) {
if (diff_find_change(wp, lnum, &change_start, &change_end)) {
diff_hlf = HLF_ADD; // added line
} else if (change_start == 0) {
@@ -817,7 +818,9 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool nochange,
} else {
diff_hlf = HLF_ADD; // added line
}
- filler_lines = 0;
+ if (linestatus == 0) {
+ filler_lines = 0;
+ }
area_highlighting = true;
}
VirtLines virt_lines = KV_INITIAL_VALUE;
diff --git a/src/nvim/eval.c b/src/nvim/eval.c
index 89ae4a2cd0..1200ba20ba 100644
--- a/src/nvim/eval.c
+++ b/src/nvim/eval.c
@@ -545,7 +545,7 @@ int var_redir_start(char *name, int append)
// check if we can write to the variable: set it to or append an empty
// string
- int save_emsg = did_emsg;
+ const int called_emsg_before = called_emsg;
did_emsg = false;
typval_T tv;
tv.v_type = VAR_STRING;
@@ -556,9 +556,7 @@ int var_redir_start(char *name, int append)
set_var_lval(redir_lval, redir_endp, &tv, true, false, "=");
}
clear_lval(redir_lval);
- int err = did_emsg;
- did_emsg |= save_emsg;
- if (err) {
+ if (called_emsg > called_emsg_before) {
redir_endp = NULL; // don't store a value, only cleanup
var_redir_stop();
return FAIL;
@@ -2185,7 +2183,7 @@ char *get_user_var_name(expand_T *xp, int idx)
/// Does not use 'cpo' and always uses 'magic'.
///
/// @return true if "pat" matches "text".
-int pattern_match(char *pat, char *text, bool ic)
+int pattern_match(const char *pat, const char *text, bool ic)
{
int matches = 0;
regmatch_T regmatch;
@@ -2193,7 +2191,7 @@ int pattern_match(char *pat, char *text, bool ic)
// avoid 'l' flag in 'cpoptions'
char *save_cpo = p_cpo;
p_cpo = empty_option;
- regmatch.regprog = vim_regcomp(pat, RE_MAGIC + RE_STRING);
+ regmatch.regprog = vim_regcomp((char *)pat, RE_MAGIC + RE_STRING);
if (regmatch.regprog != NULL) {
regmatch.rm_ic = ic;
matches = vim_regexec_nl(&regmatch, (char_u *)text, (colnr_T)0);
@@ -3051,7 +3049,7 @@ static int eval7(char **arg, typval_T *rettv, int evaluate, int want_string)
case '#':
if ((*arg)[1] == '{') {
(*arg)++;
- ret = dict_get_tv(arg, rettv, evaluate, true);
+ ret = eval_dict(arg, rettv, evaluate, true);
} else {
ret = NOTDONE;
}
@@ -3062,7 +3060,7 @@ static int eval7(char **arg, typval_T *rettv, int evaluate, int want_string)
case '{':
ret = get_lambda_tv(arg, rettv, evaluate);
if (ret == NOTDONE) {
- ret = dict_get_tv(arg, rettv, evaluate, false);
+ ret = eval_dict(arg, rettv, evaluate, false);
}
break;
@@ -4595,7 +4593,7 @@ static int get_literal_key(char **arg, typval_T *tv)
/// "literal" is true for #{key: val}
///
/// @return OK or FAIL. Returns NOTDONE for {expr}.
-static int dict_get_tv(char **arg, typval_T *rettv, int evaluate, bool literal)
+static int eval_dict(char **arg, typval_T *rettv, int evaluate, bool literal)
{
typval_T tv;
char *key = NULL;
@@ -5202,6 +5200,7 @@ linenr_T tv_get_lnum_buf(const typval_T *const tv, const buf_T *const buf)
if (tv->v_type == VAR_STRING
&& tv->vval.v_string != NULL
&& tv->vval.v_string[0] == '$'
+ && tv->vval.v_string[1] == NUL
&& buf != NULL) {
return buf->b_ml.ml_line_count;
}
@@ -5581,6 +5580,13 @@ void set_buffer_lines(buf_T *buf, linenr_T lnum_arg, bool append, const typval_T
const char *line = NULL;
if (lines->v_type == VAR_LIST) {
l = lines->vval.v_list;
+ if (l == NULL || tv_list_len(l) == 0) {
+ // set proper return code
+ if (lnum > curbuf->b_ml.ml_line_count) {
+ rettv->vval.v_number = 1; // FAIL
+ }
+ goto done;
+ }
li = tv_list_first(l);
} else {
line = tv_get_string_chk(lines);
@@ -5651,6 +5657,7 @@ void set_buffer_lines(buf_T *buf, linenr_T lnum_arg, bool append, const typval_T
update_topline(curwin);
}
+done:
if (!is_curbuf) {
curbuf = curbuf_save;
curwin = curwin_save;
@@ -8873,7 +8880,7 @@ int typval_compare(typval_T *typ1, typval_T *typ2, exprtype_T type, bool ic)
case EXPR_MATCH:
case EXPR_NOMATCH:
- n1 = pattern_match((char *)s2, (char *)s1, ic);
+ n1 = pattern_match(s2, s1, ic);
if (type == EXPR_NOMATCH) {
n1 = !n1;
}
diff --git a/src/nvim/eval.lua b/src/nvim/eval.lua
index ecb411a652..8bfa6797d0 100644
--- a/src/nvim/eval.lua
+++ b/src/nvim/eval.lua
@@ -38,7 +38,7 @@ return {
assert_equal={args={2, 3}, base=2},
assert_equalfile={args={2, 3}, base=1},
assert_exception={args={1, 2}},
- assert_fails={args={1, 3}, base=1},
+ assert_fails={args={1, 5}, base=1},
assert_false={args={1, 2}, base=1},
assert_inrange={args={3, 4}, base=3},
assert_match={args={2, 3}, base=2},
@@ -118,7 +118,7 @@ return {
exists={args=1, base=1},
exp={args=1, base=1, float_func="exp"},
expand={args={1, 3}, base=1},
- expandcmd={args=1, base=1},
+ expandcmd={args={1, 2}, base=1},
extend={args={2, 3}, base=1},
feedkeys={args={1, 2}, base=1},
file_readable={args=1, base=1, func='f_filereadable'}, -- obsolete
@@ -376,6 +376,7 @@ return {
str2float={args=1, base=1},
str2list={args={1, 2}, base=1},
str2nr={args={1, 3}, base=1},
+ strcharlen={args=1, base=1},
strcharpart={args={2, 3}, base=1},
strchars={args={1, 2}, base=1},
strdisplaywidth={args={1, 2}, base=1},
diff --git a/src/nvim/eval/funcs.c b/src/nvim/eval/funcs.c
index 79c93f1917..26a5c133da 100644
--- a/src/nvim/eval/funcs.c
+++ b/src/nvim/eval/funcs.c
@@ -112,6 +112,8 @@ PRAGMA_DIAG_POP
static char *e_listblobarg = N_("E899: Argument of %s must be a List or Blob");
static char *e_invalwindow = N_("E957: Invalid window number");
static char *e_reduceempty = N_("E998: Reduce of an empty %s with no initial value");
+static char e_using_number_as_bool_nr[]
+ = N_("E1023: Using a Number as a Bool: %d");
static char e_cannot_resize_window_in_another_tab_page[]
= N_("E1308: Cannot resize a window in another tab page");
@@ -365,23 +367,34 @@ static void f_api_info(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
/// "append(lnum, string/list)" function
static void f_append(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
{
+ const int did_emsg_before = did_emsg;
const linenr_T lnum = tv_get_lnum(&argvars[0]);
-
- set_buffer_lines(curbuf, lnum, true, &argvars[1], rettv);
+ if (did_emsg == did_emsg_before) {
+ set_buffer_lines(curbuf, lnum, true, &argvars[1], rettv);
+ }
}
-/// "appendbufline(buf, lnum, string/list)" function
-static void f_appendbufline(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
+/// Set or append lines to a buffer.
+static void buf_set_append_line(typval_T *argvars, typval_T *rettv, bool append)
{
+ const int did_emsg_before = did_emsg;
buf_T *const buf = tv_get_buf(&argvars[0], false);
if (buf == NULL) {
rettv->vval.v_number = 1; // FAIL
} else {
const linenr_T lnum = tv_get_lnum_buf(&argvars[1], buf);
- set_buffer_lines(buf, lnum, true, &argvars[2], rettv);
+ if (did_emsg == did_emsg_before) {
+ set_buffer_lines(buf, lnum, append, &argvars[2], rettv);
+ }
}
}
+/// "appendbufline(buf, lnum, string/list)" function
+static void f_appendbufline(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
+{
+ buf_set_append_line(argvars, rettv, true);
+}
+
/// "atan2()" function
static void f_atan2(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
{
@@ -895,7 +908,7 @@ static void f_charidx(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
countcc = (int)tv_get_number(&argvars[2]);
}
if (countcc < 0 || countcc > 1) {
- emsg(_(e_invarg));
+ semsg(_(e_using_number_as_bool_nr), countcc);
return;
}
@@ -1347,10 +1360,10 @@ static void f_deepcopy(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
int noref = 0;
if (argvars[1].v_type != VAR_UNKNOWN) {
- noref = (int)tv_get_number_chk(&argvars[1], NULL);
+ noref = (int)tv_get_bool_chk(&argvars[1], NULL);
}
if (noref < 0 || noref > 1) {
- emsg(_(e_invarg));
+ semsg(_(e_using_number_as_bool_nr), noref);
} else {
var_item_copy(NULL, &argvars[0], rettv, true, (noref == 0
? get_copyID()
@@ -1470,9 +1483,10 @@ static void f_dictwatcherdel(typval_T *argvars, typval_T *rettv, EvalFuncData fp
/// "deletebufline()" function
static void f_deletebufline(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
{
+ const int did_emsg_before = did_emsg;
+ rettv->vval.v_number = 1; // FAIL by default
buf_T *const buf = tv_get_buf(&argvars[0], false);
if (buf == NULL) {
- rettv->vval.v_number = 1; // FAIL
return;
}
const bool is_curbuf = buf == curbuf;
@@ -1480,6 +1494,9 @@ static void f_deletebufline(typval_T *argvars, typval_T *rettv, EvalFuncData fpt
linenr_T last;
const linenr_T first = tv_get_lnum_buf(&argvars[1], buf);
+ if (did_emsg > did_emsg_before) {
+ return;
+ }
if (argvars[2].v_type != VAR_UNKNOWN) {
last = tv_get_lnum_buf(&argvars[2], buf);
} else {
@@ -1488,7 +1505,6 @@ static void f_deletebufline(typval_T *argvars, typval_T *rettv, EvalFuncData fpt
if (buf->b_ml.ml_mfp == NULL || first < 1
|| first > buf->b_ml.ml_line_count || last < first) {
- rettv->vval.v_number = 1; // FAIL
return;
}
@@ -1541,6 +1557,7 @@ static void f_deletebufline(typval_T *argvars, typval_T *rettv, EvalFuncData fpt
curwin = curwin_save;
VIsual_active = save_VIsual_active;
}
+ rettv->vval.v_number = 0; // OK
}
/// "did_filetype()" function
@@ -1573,9 +1590,10 @@ static void f_diff_hlID(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
|| changedtick != buf_get_changedtick(curbuf)
|| fnum != curbuf->b_fnum) {
// New line, buffer, change: need to get the values.
- int filler_lines = diff_check(curwin, lnum);
- if (filler_lines < 0) {
- if (filler_lines == -1) {
+ int linestatus = 0;
+ int filler_lines = diff_check_with_linestatus(curwin, lnum, &linestatus);
+ if (filler_lines < 0 || linestatus < 0) {
+ if (filler_lines == -1 || linestatus == -1) {
change_start = MAXCOL;
change_end = -1;
if (diff_find_change(curwin, lnum, &change_start, &change_end)) {
@@ -2040,6 +2058,12 @@ static void f_menu_get(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
static void f_expandcmd(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
{
char *errormsg = NULL;
+ bool emsgoff = true;
+
+ if (argvars[1].v_type == VAR_DICT
+ && tv_dict_get_bool(argvars[1].vval.v_dict, "errmsg", kBoolVarFalse)) {
+ emsgoff = false;
+ }
rettv->v_type = VAR_STRING;
char *cmdstr = xstrdup(tv_get_string(&argvars[0]));
@@ -2053,9 +2077,17 @@ static void f_expandcmd(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
};
eap.argt |= EX_NOSPC;
- emsg_off++;
- expand_filename(&eap, &cmdstr, &errormsg);
- emsg_off--;
+ if (emsgoff) {
+ emsg_off++;
+ }
+ if (expand_filename(&eap, &cmdstr, &errormsg) == FAIL) {
+ if (!emsgoff && errormsg != NULL && *errormsg != NUL) {
+ emsg(errormsg);
+ }
+ }
+ if (emsgoff) {
+ emsg_off--;
+ }
rettv->vval.v_string = cmdstr;
}
@@ -2574,9 +2606,12 @@ static void get_buffer_lines(buf_T *buf, linenr_T start, linenr_T end, int retli
/// "getbufline()" function
static void f_getbufline(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
{
+ const int did_emsg_before = did_emsg;
buf_T *const buf = tv_get_buf_from_arg(&argvars[0]);
-
const linenr_T lnum = tv_get_lnum_buf(&argvars[1], buf);
+ if (did_emsg > did_emsg_before) {
+ return;
+ }
const linenr_T end = (argvars[2].v_type == VAR_UNKNOWN
? lnum
: tv_get_lnum_buf(&argvars[2], buf));
@@ -7500,16 +7535,7 @@ static void f_serverstop(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
/// "setbufline()" function
static void f_setbufline(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
{
- linenr_T lnum;
- buf_T *buf;
-
- buf = tv_get_buf(&argvars[0], false);
- if (buf == NULL) {
- rettv->vval.v_number = 1; // FAIL
- } else {
- lnum = tv_get_lnum_buf(&argvars[1], buf);
- set_buffer_lines(buf, lnum, false, &argvars[2], rettv);
- }
+ buf_set_append_line(argvars, rettv, false);
}
/// Set the cursor or mark position.
@@ -7638,8 +7664,11 @@ static void f_setfperm(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
/// "setline()" function
static void f_setline(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
{
+ const int did_emsg_before = did_emsg;
linenr_T lnum = tv_get_lnum(&argvars[0]);
- set_buffer_lines(curbuf, lnum, false, &argvars[1], rettv);
+ if (did_emsg == did_emsg_before) {
+ set_buffer_lines(curbuf, lnum, false, &argvars[1], rettv);
+ }
}
/// "setpos()" function
@@ -8147,7 +8176,7 @@ static void f_split(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
typeerr = true;
}
if (argvars[2].v_type != VAR_UNKNOWN) {
- keepempty = (bool)tv_get_number_chk(&argvars[2], &typeerr);
+ keepempty = (bool)tv_get_bool_chk(&argvars[2], &typeerr);
}
}
if (pat == NULL || *pat == NUL) {
@@ -8277,7 +8306,7 @@ static void f_str2nr(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
emsg(_(e_invarg));
return;
}
- if (argvars[2].v_type != VAR_UNKNOWN && tv_get_number(&argvars[2])) {
+ if (argvars[2].v_type != VAR_UNKNOWN && tv_get_bool(&argvars[2])) {
what |= STR2NR_QUOTE;
}
}
@@ -8432,26 +8461,38 @@ static void f_strlen(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
rettv->vval.v_number = (varnumber_T)strlen(tv_get_string(&argvars[0]));
}
-/// "strchars()" function
-static void f_strchars(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
+static void strchar_common(typval_T *argvars, typval_T *rettv, bool skipcc)
{
const char *s = tv_get_string(&argvars[0]);
- int skipcc = 0;
varnumber_T len = 0;
int (*func_mb_ptr2char_adv)(const char_u **pp);
+ func_mb_ptr2char_adv = skipcc ? mb_ptr2char_adv : mb_cptr2char_adv;
+ while (*s != NUL) {
+ func_mb_ptr2char_adv((const char_u **)&s);
+ len++;
+ }
+ rettv->vval.v_number = len;
+}
+
+/// "strcharlen()" function
+static void f_strcharlen(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
+{
+ strchar_common(argvars, rettv, true);
+}
+
+/// "strchars()" function
+static void f_strchars(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
+{
+ int skipcc = false;
+
if (argvars[1].v_type != VAR_UNKNOWN) {
- skipcc = (int)tv_get_number_chk(&argvars[1], NULL);
+ skipcc = (int)tv_get_bool(&argvars[1]);
}
if (skipcc < 0 || skipcc > 1) {
- emsg(_(e_invarg));
+ semsg(_(e_using_number_as_bool_nr), skipcc);
} else {
- func_mb_ptr2char_adv = skipcc ? mb_ptr2char_adv : mb_cptr2char_adv;
- while (*s != NUL) {
- func_mb_ptr2char_adv((const char_u **)&s);
- len++;
- }
- rettv->vval.v_number = len;
+ strchar_common(argvars, rettv, skipcc);
}
}
@@ -9690,6 +9731,10 @@ static void f_win_move_separator(typval_T *argvars, typval_T *rettv, EvalFuncDat
if (wp == NULL || wp->w_floating) {
return;
}
+ if (!win_valid(wp)) {
+ emsg(_(e_cannot_resize_window_in_another_tab_page));
+ return;
+ }
int offset = (int)tv_get_number(&argvars[1]);
win_drag_vsep_line(wp, offset);
diff --git a/src/nvim/eval/typval.c b/src/nvim/eval/typval.c
index 11b2b6e5fd..31b73f8d48 100644
--- a/src/nvim/eval/typval.c
+++ b/src/nvim/eval/typval.c
@@ -2061,9 +2061,24 @@ int tv_dict_get_tv(dict_T *d, const char *const key, typval_T *rettv)
varnumber_T tv_dict_get_number(const dict_T *const d, const char *const key)
FUNC_ATTR_PURE FUNC_ATTR_WARN_UNUSED_RESULT
{
+ return tv_dict_get_number_def(d, key, 0);
+}
+
+/// Get a number item from a dictionary.
+///
+/// Returns "def" if the entry doesn't exist.
+///
+/// @param[in] d Dictionary to get item from.
+/// @param[in] key Key to find in dictionary.
+/// @param[in] def Default value.
+///
+/// @return Dictionary item.
+varnumber_T tv_dict_get_number_def(const dict_T *const d, const char *const key, const int def)
+ FUNC_ATTR_PURE FUNC_ATTR_WARN_UNUSED_RESULT
+{
dictitem_T *const di = tv_dict_find(d, key, -1);
if (di == NULL) {
- return 0;
+ return def;
}
return tv_get_number(&di->di_tv);
}
diff --git a/src/nvim/eval/typval.h b/src/nvim/eval/typval.h
index fcc933c967..6757d058ef 100644
--- a/src/nvim/eval/typval.h
+++ b/src/nvim/eval/typval.h
@@ -559,4 +559,9 @@ EXTERN const size_t kTVTranslate INIT(= TV_TRANSLATE);
#ifdef INCLUDE_GENERATED_DECLARATIONS
# include "eval/typval.h.generated.h"
#endif
+
+#define tv_get_bool tv_get_number
+#define tv_get_bool_chk tv_get_number_chk
+#define tv_dict_get_bool tv_dict_get_number_def
+
#endif // NVIM_EVAL_TYPVAL_H
diff --git a/src/nvim/eval/userfunc.c b/src/nvim/eval/userfunc.c
index c22718c65d..4024410a04 100644
--- a/src/nvim/eval/userfunc.c
+++ b/src/nvim/eval/userfunc.c
@@ -460,7 +460,7 @@ int get_func_tv(const char_u *name, int len, typval_T *rettv, char **arg, funcex
int i = 0;
if (get_vim_var_nr(VV_TESTING)) {
- // Prepare for calling garbagecollect_for_testing(), need to know
+ // Prepare for calling test_garbagecollect_now(), need to know
// what variables are used on the call stack.
if (funcargs.ga_itemsize == 0) {
ga_init(&funcargs, (int)sizeof(typval_T *), 50);
@@ -1964,7 +1964,7 @@ void ex_function(exarg_T *eap)
// ":function /pat": list functions matching pattern.
if (*eap->arg == '/') {
- p = skip_regexp(eap->arg + 1, '/', true, NULL);
+ p = skip_regexp(eap->arg + 1, '/', true);
if (!eap->skip) {
regmatch_T regmatch;
diff --git a/src/nvim/ex_cmds.c b/src/nvim/ex_cmds.c
index 87c4f4e654..89e6d47950 100644
--- a/src/nvim/ex_cmds.c
+++ b/src/nvim/ex_cmds.c
@@ -504,9 +504,8 @@ void ex_sort(exarg_T *eap)
eap->nextcmd = check_nextcmd(p);
break;
} else if (!ASCII_ISALPHA(*p) && regmatch.regprog == NULL) {
- s = skip_regexp(p + 1, *p, true, NULL);
- if (*s != *p) {
- emsg(_(e_invalpat));
+ s = skip_regexp_err(p + 1, *p, true);
+ if (s == NULL) {
goto sortend;
}
*s = NUL;
@@ -3503,7 +3502,7 @@ static int do_sub(exarg_T *eap, proftime_T timeout, long cmdpreview_ns, handle_T
which_pat = RE_LAST; // use last used regexp
delimiter = (char_u)(*cmd++); // remember delimiter character
pat = cmd; // remember start of search pat
- cmd = skip_regexp(cmd, delimiter, p_magic, &eap->arg);
+ cmd = skip_regexp_ex(cmd, delimiter, p_magic, &eap->arg, NULL);
if (cmd[0] == delimiter) { // end delimiter found
*cmd++ = NUL; // replace it with a NUL
has_second_delim = true;
@@ -4536,7 +4535,7 @@ void ex_global(exarg_T *eap)
delim = *cmd; // get the delimiter
cmd++; // skip delimiter if there is one
pat = cmd; // remember start of pattern
- cmd = skip_regexp(cmd, delim, p_magic, &eap->arg);
+ cmd = skip_regexp_ex(cmd, delim, p_magic, &eap->arg, NULL);
if (cmd[0] == delim) { // end delimiter found
*cmd++ = NUL; // replace it with a NUL
}
@@ -4849,7 +4848,7 @@ char *skip_vimgrep_pat(char *p, char **s, int *flags)
*s = p + 1;
}
c = (char_u)(*p);
- p = skip_regexp(p + 1, c, true, NULL);
+ p = skip_regexp(p + 1, c, true);
if (*p != c) {
return NULL;
}
diff --git a/src/nvim/ex_docmd.c b/src/nvim/ex_docmd.c
index e867bd57d4..dc2b7247f1 100644
--- a/src/nvim/ex_docmd.c
+++ b/src/nvim/ex_docmd.c
@@ -726,7 +726,7 @@ int do_cmdline(char *cmdline, LineGetter fgetline, void *cookie, int flags)
if (cstack.cs_idx >= 0) {
// If a sourced file or executed function ran to its end, report the
// unclosed conditional.
- if (!got_int && !did_throw
+ if (!got_int && !did_throw && !aborting()
&& ((getline_equal(fgetline, cookie, getsourceline)
&& !source_finished(fgetline, cookie))
|| (getline_equal(fgetline, cookie, get_func_line)
@@ -807,6 +807,7 @@ int do_cmdline(char *cmdline, LineGetter fgetline, void *cookie, int flags)
next = messages->next;
emsg(messages->msg);
xfree(messages->msg);
+ xfree(messages->sfile);
xfree(messages);
messages = next;
} while (messages != NULL);
@@ -3351,7 +3352,7 @@ static linenr_T get_address(exarg_T *eap, char **ptr, cmd_addr_T addr_type, int
goto error;
}
if (skip) { // skip "/pat/"
- cmd = skip_regexp(cmd, c, p_magic, NULL);
+ cmd = skip_regexp(cmd, c, p_magic);
if (*cmd == c) {
cmd++;
}
@@ -5212,7 +5213,7 @@ void do_exedit(exarg_T *eap, win_T *old_curwin)
old_curwin == NULL ? curwin : NULL);
} else if ((eap->cmdidx != CMD_split && eap->cmdidx != CMD_vsplit)
|| *eap->arg != NUL) {
- // Can't edit another file when "curbuf->b_ro_lockec" is set. Only ":edit"
+ // Can't edit another file when "curbuf->b_ro_locked" is set. Only ":edit"
// can bring us here, others are stopped earlier.
if (*eap->arg != NUL && curbuf_locked()) {
return;
@@ -6494,7 +6495,7 @@ static void ex_findpat(exarg_T *eap)
if (*eap->arg == '/') { // Match regexp, not just whole words
whole = false;
eap->arg++;
- char *p = skip_regexp(eap->arg, '/', p_magic, NULL);
+ char *p = skip_regexp(eap->arg, '/', p_magic);
if (*p) {
*p++ = NUL;
p = skipwhite(p);
diff --git a/src/nvim/ex_eval.c b/src/nvim/ex_eval.c
index 2d6b236007..8c2ac895cb 100644
--- a/src/nvim/ex_eval.c
+++ b/src/nvim/ex_eval.c
@@ -900,12 +900,12 @@ void ex_else(exarg_T *eap)
if (eap->cmdidx == CMD_elseif) {
bool error;
result = eval_to_bool(eap->arg, &error, &eap->nextcmd, skip);
+
// When throwing error exceptions, we want to throw always the first
// of several errors in a row. This is what actually happens when
// a conditional error was detected above and there is another failure
// when parsing the expression. Since the skip flag is set in this
// case, the parsing error will be ignored by emsg().
-
if (!skip && !error) {
if (result) {
cstack->cs_flags[cstack->cs_idx] = CSF_ACTIVE | CSF_TRUE;
@@ -1296,7 +1296,10 @@ void ex_catch(exarg_T *eap)
eap->nextcmd = find_nextcmd(eap->arg);
} else {
pat = eap->arg + 1;
- end = skip_regexp(pat, *eap->arg, true, NULL);
+ end = skip_regexp_err(pat, *eap->arg, true);
+ if (end == NULL) {
+ give_up = true;
+ }
}
if (!give_up) {
diff --git a/src/nvim/ex_getln.c b/src/nvim/ex_getln.c
index a1e4bc96b5..1d242e4ed2 100644
--- a/src/nvim/ex_getln.c
+++ b/src/nvim/ex_getln.c
@@ -314,7 +314,7 @@ static bool do_incsearch_highlighting(int firstc, int *search_delim, incsearch_s
p = skipwhite(p);
delim = (delim_optional && vim_isIDc(*p)) ? ' ' : *p++;
*search_delim = delim;
- end = skip_regexp(p, delim, p_magic, NULL);
+ end = skip_regexp(p, delim, p_magic);
use_last_pat = end == p && *end == delim;
if (end == p && !use_last_pat) {
diff --git a/src/nvim/fileio.c b/src/nvim/fileio.c
index 2ba2f4c9c9..c780f64a7a 100644
--- a/src/nvim/fileio.c
+++ b/src/nvim/fileio.c
@@ -1624,23 +1624,31 @@ failed:
error = false;
}
+ // In Dos format ignore a trailing CTRL-Z, unless 'binary' is set.
+ // In old days the file length was in sector count and the CTRL-Z the
+ // marker where the file really ended. Assuming we write it to a file
+ // system that keeps file length properly the CTRL-Z should be dropped.
+ // Set the 'endoffile' option so the user can decide what to write later.
+ // In Unix format the CTRL-Z is just another character.
+ if (linerest != 0
+ && !curbuf->b_p_bin
+ && fileformat == EOL_DOS
+ && ptr[-1] == Ctrl_Z) {
+ ptr--;
+ linerest--;
+ if (set_options) {
+ curbuf->b_p_eof = true;
+ }
+ }
+
// If we get EOF in the middle of a line, note the fact and
// complete the line ourselves.
- // In Dos format ignore a trailing CTRL-Z, unless 'binary' set.
if (!error
&& !got_int
- && linerest != 0
- // TODO(vim): should we handle CTRL-Z differently here for 'endoffile'?
- && !(!curbuf->b_p_bin
- && fileformat == EOL_DOS
- && *line_start == Ctrl_Z
- && ptr == line_start + 1)) {
+ && linerest != 0) {
// remember for when writing
if (set_options) {
curbuf->b_p_eol = false;
- if (*line_start == Ctrl_Z && ptr == line_start + 1) {
- curbuf->b_p_eof = true;
- }
}
*ptr = NUL;
len = (colnr_T)(ptr - line_start + 1);
@@ -2773,10 +2781,11 @@ int buf_write(buf_T *buf, char *fname, char *sfname, linenr_T start, linenr_T en
#endif
// copy the file
- if (os_copy(fname, backup, UV_FS_COPYFILE_FICLONE)
- != 0) {
- SET_ERRMSG(_("E506: Can't write to backup file "
- "(add ! to override)"));
+ if (os_copy(fname, backup, UV_FS_COPYFILE_FICLONE) != 0) {
+ SET_ERRMSG(_("E509: Cannot create backup file (add ! to override)"));
+ XFREE_CLEAR(backup);
+ backup = NULL;
+ continue;
}
#ifdef UNIX
@@ -2787,6 +2796,7 @@ int buf_write(buf_T *buf, char *fname, char *sfname, linenr_T start, linenr_T en
#ifdef HAVE_ACL
mch_set_acl((char_u *)backup, acl);
#endif
+ SET_ERRMSG(NULL);
break;
}
}
@@ -3197,11 +3207,6 @@ restore_backup:
len = 0;
write_info.bw_start_lnum = lnum;
}
- if (!buf->b_p_fixeol && buf->b_p_eof) {
- // write trailing CTRL-Z
- (void)write_eintr(write_info.bw_fd, "\x1a", 1);
- }
-
// write failed or last line has no EOL: stop here
if (end == 0
|| (lnum == end
@@ -3253,6 +3258,11 @@ restore_backup:
nchars += len;
}
+ if (!buf->b_p_fixeol && buf->b_p_eof) {
+ // write trailing CTRL-Z
+ (void)write_eintr(write_info.bw_fd, "\x1a", 1);
+ }
+
// Stop when writing done or an error was encountered.
if (!checking_conversion || end == 0) {
break;
diff --git a/src/nvim/globals.h b/src/nvim/globals.h
index c556aac1fd..14266fc859 100644
--- a/src/nvim/globals.h
+++ b/src/nvim/globals.h
@@ -194,6 +194,12 @@ EXTERN int emsg_skip INIT(= 0); // don't display errors for
// expression that is skipped
EXTERN bool emsg_severe INIT(= false); // use message of next of several
// emsg() calls for throw
+// used by assert_fails()
+EXTERN bool emsg_assert_fails_used INIT(= false);
+EXTERN char *emsg_assert_fails_msg INIT(= NULL);
+EXTERN long emsg_assert_fails_lnum INIT(= 0);
+EXTERN char *emsg_assert_fails_context INIT(= NULL);
+
EXTERN bool did_endif INIT(= false); // just had ":endif"
EXTERN dict_T vimvardict; // Dictionary with v: variables
EXTERN dict_T globvardict; // Dictionary with g: variables
diff --git a/src/nvim/highlight_group.c b/src/nvim/highlight_group.c
index 4c253480be..9a09118939 100644
--- a/src/nvim/highlight_group.c
+++ b/src/nvim/highlight_group.c
@@ -851,7 +851,7 @@ void do_highlight(const char *line, const bool forceit, const bool init)
bool did_highlight_changed = false;
// If no argument, list current highlighting.
- if (ends_excmd((uint8_t)(*line))) {
+ if (!init && ends_excmd((uint8_t)(*line))) {
for (int i = 1; i <= highlight_ga.ga_len && !got_int; i++) {
// TODO(brammool): only call when the group has attributes set
highlight_list_one(i);
diff --git a/src/nvim/indent.c b/src/nvim/indent.c
index cb5819e946..d372e41459 100644
--- a/src/nvim/indent.c
+++ b/src/nvim/indent.c
@@ -743,6 +743,7 @@ bool briopt_check(win_T *wp)
int bri_min = 20;
bool bri_sbr = false;
int bri_list = 0;
+ int bri_vcol = 0;
char *p = wp->w_p_briopt;
while (*p != NUL) {
@@ -759,6 +760,9 @@ bool briopt_check(win_T *wp)
} else if (STRNCMP(p, "list:", 5) == 0) {
p += 5;
bri_list = (int)getdigits(&p, false, 0);
+ } else if (STRNCMP(p, "column:", 7) == 0) {
+ p += 7;
+ bri_vcol = (int)getdigits(&p, false, 0);
}
if (*p != ',' && *p != NUL) {
return false;
@@ -771,7 +775,8 @@ bool briopt_check(win_T *wp)
wp->w_briopt_shift = bri_shift;
wp->w_briopt_min = bri_min;
wp->w_briopt_sbr = bri_sbr;
- wp->w_briopt_list = bri_list;
+ wp->w_briopt_list = bri_list;
+ wp->w_briopt_vcol = bri_vcol;
return true;
}
@@ -783,51 +788,78 @@ int get_breakindent_win(win_T *wp, char_u *line)
FUNC_ATTR_NONNULL_ALL
{
static int prev_indent = 0; // Cached indent value.
- static long prev_ts = 0; // Cached tabstop value.
+ static long prev_ts = 0L; // Cached tabstop value.
static const char_u *prev_line = NULL; // cached pointer to line.
static varnumber_T prev_tick = 0; // Changedtick of cached value.
- static long *prev_vts = NULL; // Cached vartabs values.
+ static long *prev_vts = NULL; // Cached vartabs values.
+ static int prev_list = 0; // cached list value
+ static int prev_listopt = 0; // cached w_p_briopt_list value
+ static char *prev_flp = NULL; // cached formatlistpat value
int bri = 0;
// window width minus window margin space, i.e. what rests for text
const int eff_wwidth = wp->w_width_inner -
((wp->w_p_nu || wp->w_p_rnu)
&& (vim_strchr(p_cpo, CPO_NUMCOL) == NULL) ? number_width(wp) + 1 : 0);
- // used cached indent, unless pointer or 'tabstop' changed
+ // used cached indent, unless
+ // - line pointer changed
+ // - 'tabstop' changed
+ // - 'briopt_list changed' changed or
+ // - 'formatlistpattern' changed
if (prev_line != line || prev_ts != wp->w_buffer->b_p_ts
|| prev_tick != buf_get_changedtick(wp->w_buffer)
+ || prev_listopt != wp->w_briopt_list
+ || (prev_flp == NULL || (strcmp(prev_flp, get_flp_value(wp->w_buffer)) != 0))
|| prev_vts != wp->w_buffer->b_p_vts_array) {
prev_line = line;
prev_ts = wp->w_buffer->b_p_ts;
prev_tick = buf_get_changedtick(wp->w_buffer);
prev_vts = wp->w_buffer->b_p_vts_array;
- prev_indent = get_indent_str_vtab((char *)line,
- wp->w_buffer->b_p_ts,
- wp->w_buffer->b_p_vts_array,
- wp->w_p_list);
+ if (wp->w_briopt_vcol == 0) {
+ prev_indent = get_indent_str_vtab((char *)line,
+ wp->w_buffer->b_p_ts,
+ wp->w_buffer->b_p_vts_array,
+ wp->w_p_list);
+ }
+ prev_listopt = wp->w_briopt_list;
+ prev_list = 0;
+ xfree(prev_flp);
+ prev_flp = xstrdup(get_flp_value(wp->w_buffer));
+ // add additional indent for numbered lists
+ if (wp->w_briopt_list != 0 && wp->w_briopt_vcol == 0) {
+ regmatch_T regmatch = {
+ .regprog = vim_regcomp(prev_flp, RE_MAGIC + RE_STRING + RE_AUTO + RE_STRICT),
+ };
+ if (regmatch.regprog != NULL) {
+ regmatch.rm_ic = false;
+ if (vim_regexec(&regmatch, (char *)line, 0)) {
+ if (wp->w_briopt_list > 0) {
+ prev_list += wp->w_briopt_list;
+ } else {
+ prev_list = (int)(*regmatch.endp - *regmatch.startp);
+ }
+ }
+ vim_regfree(regmatch.regprog);
+ }
+ }
+ }
+ if (wp->w_briopt_vcol != 0) {
+ // column value has priority
+ bri = wp->w_briopt_vcol;
+ prev_list = 0;
+ } else {
+ bri = prev_indent + wp->w_briopt_shift;
}
- bri = prev_indent + wp->w_briopt_shift;
// Add offset for number column, if 'n' is in 'cpoptions'
bri += win_col_off2(wp);
// add additional indent for numbered lists
if (wp->w_briopt_list != 0) {
- regmatch_T regmatch = {
- .regprog = vim_regcomp(curbuf->b_p_flp,
- RE_MAGIC + RE_STRING + RE_AUTO + RE_STRICT),
- };
-
- if (regmatch.regprog != NULL) {
- regmatch.rm_ic = false;
- if (vim_regexec(&regmatch, (char *)line, 0)) {
- if (wp->w_briopt_list > 0) {
- bri += wp->w_briopt_list;
- } else {
- bri = (int)(*regmatch.endp - *regmatch.startp);
- }
- }
- vim_regfree(regmatch.regprog);
+ if (wp->w_briopt_list > 0) {
+ bri += prev_list;
+ } else {
+ bri = prev_list;
}
}
diff --git a/src/nvim/linematch.c b/src/nvim/linematch.c
new file mode 100644
index 0000000000..04209bb836
--- /dev/null
+++ b/src/nvim/linematch.c
@@ -0,0 +1,376 @@
+#include "nvim/linematch.h"
+#include "nvim/memory.h"
+#include "nvim/vim.h"
+
+// struct for running the diff linematch algorithm
+typedef struct {
+ int *df_decision; // to keep track of this path traveled
+ int df_lev_score; // to keep track of the total score of this path
+ size_t df_path_idx; // current index of this path
+} diffcmppath_T;
+
+#define LN_MAX_BUFS 8
+
+#ifdef INCLUDE_GENERATED_DECLARATIONS
+# include "linematch.c.generated.h"
+#endif
+
+static size_t line_len(const char *s)
+{
+ char *end = strchr(s, '\n');
+ if (end) {
+ return (size_t)(end - s);
+ }
+ return STRLEN(s);
+}
+
+/// Same as matching_chars but ignore whitespace
+///
+/// @param s1
+/// @param s2
+static int matching_chars_iwhite(const char *s1, const char *s2)
+{
+ // the newly processed strings that will be compared
+ // delete the white space characters, and/or replace all upper case with lower
+ char *strsproc[2];
+ const char *strsorig[2] = { s1, s2 };
+ for (int k = 0; k < 2; k++) {
+ size_t d = 0;
+ size_t i = 0;
+ size_t slen = line_len(strsorig[k]);
+ strsproc[k] = xmalloc((slen + 1) * sizeof(char));
+ while (d + i < slen) {
+ char e = strsorig[k][i + d];
+ if (e != ' ' && e != '\t') {
+ strsproc[k][i] = e;
+ i++;
+ } else {
+ d++;
+ }
+ }
+ strsproc[k][i] = '\0';
+ }
+ int matching = matching_chars(strsproc[0], strsproc[1]);
+ xfree(strsproc[0]);
+ xfree(strsproc[1]);
+ return matching;
+}
+
+/// update the path of a point in the diff linematch algorithm
+/// @param diffcmppath
+/// @param score
+/// @param to
+/// @param from
+/// @param choice
+static void update_path_flat(diffcmppath_T *diffcmppath, int score, size_t to, size_t from,
+ const int choice)
+{
+ size_t path_idx = diffcmppath[from].df_path_idx;
+
+ for (size_t k = 0; k < path_idx; k++) {
+ diffcmppath[to].df_decision[k] = diffcmppath[from].df_decision[k];
+ }
+
+ diffcmppath[to].df_decision[path_idx] = choice;
+ diffcmppath[to].df_lev_score = score;
+ diffcmppath[to].df_path_idx = path_idx + 1;
+}
+
+#define MATCH_CHAR_MAX_LEN 500
+
+/// Return matching characters between "s1" and "s2" whilst respecting sequence order.
+/// Consider the case of two strings 'AAACCC' and 'CCCAAA', the
+/// return value from this function will be 3, either to match
+/// the 3 C's, or the 3 A's.
+///
+/// Examples:
+/// matching_chars("aabc", "acba") -> 2 // 'a' and 'b' in common
+/// matching_chars("123hello567", "he123ll567o") -> 8 // '123', 'll' and '567' in common
+/// matching_chars("abcdefg", "gfedcba") -> 1 // all characters in common,
+/// // but only at most 1 in sequence
+///
+/// @param s1
+/// @param s2
+static int matching_chars(const char *s1, const char *s2)
+{
+ size_t s1len = MIN(MATCH_CHAR_MAX_LEN, line_len(s1));
+ size_t s2len = MIN(MATCH_CHAR_MAX_LEN, line_len(s2));
+ int matrix[2][MATCH_CHAR_MAX_LEN] = { 0 };
+ bool icur = 1; // save space by storing only two rows for i axis
+ for (size_t i = 0; i < s1len; i++) {
+ icur = !icur;
+ int *e1 = matrix[icur];
+ int *e2 = matrix[!icur];
+ for (size_t j = 0; j < s2len; j++) {
+ // skip char in s1
+ if (e2[j + 1] > e1[j + 1]) {
+ e1[j + 1] = e2[j + 1];
+ }
+ // skip char in s2
+ if (e1[j] > e1[j + 1]) {
+ e1[j + 1] = e1[j];
+ }
+ // compare char in s1 and s2
+ if ((s1[i] == s2[j]) && (e2[j] + 1) > e1[j + 1]) {
+ e1[j + 1] = e2[j] + 1;
+ }
+ }
+ }
+ return matrix[icur][s2len];
+}
+
+/// count the matching characters between a variable number of strings "sp"
+/// mark the strings that have already been compared to extract them later
+/// without re-running the character match counting.
+/// @param sp
+/// @param fomvals
+/// @param n
+static int count_n_matched_chars(const char **sp, const size_t n, bool iwhite)
+{
+ int matched_chars = 0;
+ int matched = 0;
+ for (size_t i = 0; i < n; i++) {
+ for (size_t j = i + 1; j < n; j++) {
+ if (sp[i] != NULL && sp[j] != NULL) {
+ matched++;
+ // TODO(lewis6991): handle whitespace ignoring higher up in the stack
+ matched_chars += iwhite ? matching_chars_iwhite(sp[i], sp[j])
+ : matching_chars(sp[i], sp[j]);
+ }
+ }
+ }
+
+ // prioritize a match of 3 (or more lines) equally to a match of 2 lines
+ if (matched >= 2) {
+ matched_chars *= 2;
+ matched_chars /= matched;
+ }
+
+ return matched_chars;
+}
+
+void fastforward_buf_to_lnum(const char **s, long lnum)
+{
+ for (long i = 0; i < lnum - 1; i++) {
+ *s = strchr(*s, '\n');
+ (*s)++;
+ }
+}
+
+/// try all the different ways to compare these lines and use the one that
+/// results in the most matching characters
+/// @param df_iters
+/// @param paths
+/// @param npaths
+/// @param path_idx
+/// @param choice
+/// @param diffcmppath
+/// @param diff_len
+/// @param ndiffs
+/// @param diff_blk
+static void try_possible_paths(const int *df_iters, const size_t *paths, const int npaths,
+ const int path_idx, int *choice, diffcmppath_T *diffcmppath,
+ const int *diff_len, const size_t ndiffs, const char **diff_blk,
+ bool iwhite)
+{
+ if (path_idx == npaths) {
+ if ((*choice) > 0) {
+ int from_vals[LN_MAX_BUFS];
+ const int *to_vals = df_iters;
+ const char *current_lines[LN_MAX_BUFS];
+ for (size_t k = 0; k < ndiffs; k++) {
+ from_vals[k] = df_iters[k];
+ // get the index at all of the places
+ if ((*choice) & (1 << k)) {
+ from_vals[k]--;
+ const char *p = diff_blk[k];
+ fastforward_buf_to_lnum(&p, df_iters[k]);
+ current_lines[k] = p;
+ } else {
+ current_lines[k] = NULL;
+ }
+ }
+ size_t unwrapped_idx_from = unwrap_indexes(from_vals, diff_len, ndiffs);
+ size_t unwrapped_idx_to = unwrap_indexes(to_vals, diff_len, ndiffs);
+ int matched_chars = count_n_matched_chars(current_lines, ndiffs, iwhite);
+ int score = diffcmppath[unwrapped_idx_from].df_lev_score + matched_chars;
+ if (score > diffcmppath[unwrapped_idx_to].df_lev_score) {
+ update_path_flat(diffcmppath, score, unwrapped_idx_to, unwrapped_idx_from, *choice);
+ }
+ } else {
+ // initialize the 0, 0, 0 ... choice
+ size_t i = 0;
+ while (i < ndiffs && df_iters[i] == 0) {
+ i++;
+ if (i == ndiffs) {
+ diffcmppath[0].df_lev_score = 0;
+ diffcmppath[0].df_path_idx = 0;
+ }
+ }
+ }
+ return;
+ }
+ size_t bit_place = paths[path_idx];
+ *(choice) |= (1 << bit_place); // set it to 1
+ try_possible_paths(df_iters, paths, npaths, path_idx + 1, choice,
+ diffcmppath, diff_len, ndiffs, diff_blk, iwhite);
+ *(choice) &= ~(1 << bit_place); // set it to 0
+ try_possible_paths(df_iters, paths, npaths, path_idx + 1, choice,
+ diffcmppath, diff_len, ndiffs, diff_blk, iwhite);
+}
+
+/// unwrap indexes to access n dimensional tensor
+/// @param values
+/// @param diff_len
+/// @param ndiffs
+static size_t unwrap_indexes(const int *values, const int *diff_len, const size_t ndiffs)
+{
+ size_t num_unwrap_scalar = 1;
+ for (size_t k = 0; k < ndiffs; k++) {
+ num_unwrap_scalar *= (size_t)diff_len[k] + 1;
+ }
+
+ size_t path_idx = 0;
+ for (size_t k = 0; k < ndiffs; k++) {
+ num_unwrap_scalar /= (size_t)diff_len[k] + 1;
+
+ // (k == 0) space optimization
+ int n = k == 0 ? values[k] % 2 : values[k];
+ path_idx += num_unwrap_scalar * (size_t)n;
+ }
+ return path_idx;
+}
+
+/// populate the values of the linematch algorithm tensor, and find the best
+/// decision for how to compare the relevant lines from each of the buffers at
+/// each point in the tensor
+/// @param df_iters
+/// @param ch_dim
+/// @param diffcmppath
+/// @param diff_len
+/// @param ndiffs
+/// @param diff_blk
+static void populate_tensor(int *df_iters, const size_t ch_dim, diffcmppath_T *diffcmppath,
+ const int *diff_len, const size_t ndiffs, const char **diff_blk,
+ bool iwhite)
+{
+ if (ch_dim == ndiffs) {
+ int npaths = 0;
+ size_t paths[LN_MAX_BUFS];
+
+ for (size_t j = 0; j < ndiffs; j++) {
+ if (df_iters[j] > 0) {
+ paths[npaths] = j;
+ npaths++;
+ }
+ }
+ int choice = 0;
+ size_t unwrapper_idx_to = unwrap_indexes(df_iters, diff_len, ndiffs);
+ diffcmppath[unwrapper_idx_to].df_lev_score = -1;
+ try_possible_paths(df_iters, paths, npaths, 0, &choice, diffcmppath,
+ diff_len, ndiffs, diff_blk, iwhite);
+ return;
+ }
+
+ for (int i = 0; i <= diff_len[ch_dim]; i++) {
+ df_iters[ch_dim] = i;
+ populate_tensor(df_iters, ch_dim + 1, diffcmppath, diff_len,
+ ndiffs, diff_blk, iwhite);
+ }
+}
+
+/// algorithm to find an optimal alignment of lines of a diff block with 2 or
+/// more files. The algorithm is generalized to work for any number of files
+/// which corresponds to another dimmension added to the tensor used in the
+/// algorithm
+///
+/// for questions and information about the linematch algorithm please contact
+/// Jonathon White (jonathonwhite@protonmail.com)
+///
+/// for explanation, a summary of the algorithm in 3 dimmensions (3 files
+/// compared) follows
+///
+/// The 3d case (for 3 buffers) of the algorithm implemented when diffopt
+/// 'linematch' is enabled. The algorithm constructs a 3d tensor to
+/// compare a diff between 3 buffers. The dimmensions of the tensor are
+/// the length of the diff in each buffer plus 1 A path is constructed by
+/// moving from one edge of the cube/3d tensor to the opposite edge.
+/// Motions from one cell of the cube to the next represent decisions. In
+/// a 3d cube, there are a total of 7 decisions that can be made,
+/// represented by the enum df_path3_choice which is defined in
+/// buffer_defs.h a comparison of buffer 0 and 1 represents a motion
+/// toward the opposite edge of the cube with components along the 0 and
+/// 1 axes. a comparison of buffer 0, 1, and 2 represents a motion
+/// toward the opposite edge of the cube with components along the 0, 1,
+/// and 2 axes. A skip of buffer 0 represents a motion along only the 0
+/// axis. For each action, a point value is awarded, and the path is
+/// saved for reference later, if it is found to have been the optimal
+/// path. The optimal path has the highest score. The score is
+/// calculated as the summation of the total characters matching between
+/// all of the lines which were compared. The structure of the algorithm
+/// is that of a dynamic programming problem. We can calculate a point
+/// i,j,k in the cube as a function of i-1, j-1, and k-1. To find the
+/// score and path at point i,j,k, we must determine which path we want
+/// to use, this is done by looking at the possibilities and choosing
+/// the one which results in the local highest score. The total highest
+/// scored path is, then in the end represented by the cell in the
+/// opposite corner from the start location. The entire algorithm
+/// consits of populating the 3d cube with the optimal paths from which
+/// it may have came.
+///
+/// Optimizations:
+/// As the function to calculate the cell of a tensor at point i,j,k is a
+/// function of the cells at i-1, j-1, k-1, the whole tensor doesn't need
+/// to be stored in memory at once. In the case of the 3d cube, only two
+/// slices (along k and j axis) are stored in memory. For the 2d matrix
+/// (for 2 files), only two rows are stored at a time. The next/previous
+/// slice (or row) is always calculated from the other, and they alternate
+/// at each iteration.
+/// In the 3d case, 3 arrays are populated to memorize the score (matched
+/// characters) of the 3 buffers, so a redundant calculation of the
+/// scores does not occur
+/// @param diff_blk
+/// @param diff_len
+/// @param ndiffs
+/// @param [out] [allocated] decisions
+/// @return the length of decisions
+size_t linematch_nbuffers(const char **diff_blk, const int *diff_len, const size_t ndiffs,
+ int **decisions, bool iwhite)
+{
+ assert(ndiffs <= LN_MAX_BUFS);
+
+ size_t memsize = 1;
+ size_t memsize_decisions = 0;
+ for (size_t i = 0; i < ndiffs; i++) {
+ assert(diff_len[i] >= 0);
+ memsize *= i == 0 ? 2 : (size_t)(diff_len[i] + 1);
+ memsize_decisions += (size_t)diff_len[i];
+ }
+
+ // create the flattened path matrix
+ diffcmppath_T *diffcmppath = xmalloc(sizeof(diffcmppath_T) * memsize);
+ // allocate memory here
+ for (size_t i = 0; i < memsize; i++) {
+ diffcmppath[i].df_decision = xmalloc(memsize_decisions * sizeof(int));
+ }
+
+ // memory for avoiding repetitive calculations of score
+ int df_iters[LN_MAX_BUFS];
+ populate_tensor(df_iters, 0, diffcmppath, diff_len, ndiffs, diff_blk, iwhite);
+
+ const size_t u = unwrap_indexes(diff_len, diff_len, ndiffs);
+ const size_t best_path_idx = diffcmppath[u].df_path_idx;
+ const int *best_path_decisions = diffcmppath[u].df_decision;
+
+ *decisions = xmalloc(sizeof(int) * best_path_idx);
+ for (size_t i = 0; i < best_path_idx; i++) {
+ (*decisions)[i] = best_path_decisions[i];
+ }
+
+ for (size_t i = 0; i < memsize; i++) {
+ xfree(diffcmppath[i].df_decision);
+ }
+ xfree(diffcmppath);
+
+ return best_path_idx;
+}
diff --git a/src/nvim/linematch.h b/src/nvim/linematch.h
new file mode 100644
index 0000000000..052d438617
--- /dev/null
+++ b/src/nvim/linematch.h
@@ -0,0 +1,10 @@
+#ifndef NVIM_LINEMATCH_H
+#define NVIM_LINEMATCH_H
+
+#include <stddef.h>
+
+#ifdef INCLUDE_GENERATED_DECLARATIONS
+# include "linematch.h.generated.h"
+#endif
+
+#endif // NVIM_LINEMATCH_H
diff --git a/src/nvim/lua/xdiff.c b/src/nvim/lua/xdiff.c
index b2b5dfedee..cd542b0e00 100644
--- a/src/nvim/lua/xdiff.c
+++ b/src/nvim/lua/xdiff.c
@@ -10,12 +10,16 @@
#include <string.h>
#include "nvim/api/private/helpers.h"
+#include "nvim/linematch.h"
#include "nvim/lua/converter.h"
#include "nvim/lua/executor.h"
#include "nvim/lua/xdiff.h"
#include "nvim/vim.h"
#include "xdiff/xdiff.h"
+#define COMPARED_BUFFER0 (1 << 0)
+#define COMPARED_BUFFER1 (1 << 1)
+
typedef enum {
kNluaXdiffModeUnified = 0,
kNluaXdiffModeOnHunkCB,
@@ -25,12 +29,81 @@ typedef enum {
typedef struct {
lua_State *lstate;
Error *err;
+ mmfile_t *ma;
+ mmfile_t *mb;
+ bool linematch;
+ bool iwhite;
} hunkpriv_t;
#ifdef INCLUDE_GENERATED_DECLARATIONS
# include "lua/xdiff.c.generated.h"
#endif
+static void lua_pushhunk(lua_State *lstate, long start_a, long count_a, long start_b, long count_b)
+{
+ // Mimic extra offsets done by xdiff, see:
+ // src/xdiff/xemit.c:284
+ // src/xdiff/xutils.c:(356,368)
+ if (count_a > 0) {
+ start_a += 1;
+ }
+ if (count_b > 0) {
+ start_b += 1;
+ }
+ lua_createtable(lstate, 0, 0);
+ lua_pushinteger(lstate, start_a);
+ lua_rawseti(lstate, -2, 1);
+ lua_pushinteger(lstate, count_a);
+ lua_rawseti(lstate, -2, 2);
+ lua_pushinteger(lstate, start_b);
+ lua_rawseti(lstate, -2, 3);
+ lua_pushinteger(lstate, count_b);
+ lua_rawseti(lstate, -2, 4);
+ lua_rawseti(lstate, -2, (signed)lua_objlen(lstate, -2) + 1);
+}
+
+static void get_linematch_results(lua_State *lstate, mmfile_t *ma, mmfile_t *mb, long start_a,
+ long count_a, long start_b, long count_b, bool iwhite)
+{
+ // get the pointer to char of the start of the diff to pass it to linematch algorithm
+ const char *diff_begin[2] = { ma->ptr, mb->ptr };
+ int diff_length[2] = { (int)count_a, (int)count_b };
+
+ fastforward_buf_to_lnum(&diff_begin[0], start_a + 1);
+ fastforward_buf_to_lnum(&diff_begin[1], start_b + 1);
+
+ int *decisions = NULL;
+ size_t decisions_length = linematch_nbuffers(diff_begin, diff_length, 2, &decisions, iwhite);
+
+ long lnuma = start_a, lnumb = start_b;
+
+ long hunkstarta = lnuma;
+ long hunkstartb = lnumb;
+ long hunkcounta = 0;
+ long hunkcountb = 0;
+ for (size_t i = 0; i < decisions_length; i++) {
+ if (i && (decisions[i - 1] != decisions[i])) {
+ lua_pushhunk(lstate, hunkstarta, hunkcounta, hunkstartb, hunkcountb);
+
+ hunkstarta = lnuma;
+ hunkstartb = lnumb;
+ hunkcounta = 0;
+ hunkcountb = 0;
+ // create a new hunk
+ }
+ if (decisions[i] & COMPARED_BUFFER0) {
+ lnuma++;
+ hunkcounta++;
+ }
+ if (decisions[i] & COMPARED_BUFFER1) {
+ lnumb++;
+ hunkcountb++;
+ }
+ }
+ lua_pushhunk(lstate, hunkstarta, hunkcounta, hunkstartb, hunkcountb);
+ xfree(decisions);
+}
+
static int write_string(void *priv, mmbuffer_t *mb, int nbuf)
{
luaL_Buffer *buf = (luaL_Buffer *)priv;
@@ -52,30 +125,15 @@ static int write_string(void *priv, mmbuffer_t *mb, int nbuf)
// hunk_func callback used when opts.hunk_lines = true
static int hunk_locations_cb(long start_a, long count_a, long start_b, long count_b, void *cb_data)
{
- // Mimic extra offsets done by xdiff, see:
- // src/xdiff/xemit.c:284
- // src/xdiff/xutils.c:(356,368)
- if (count_a > 0) {
- start_a += 1;
- }
- if (count_b > 0) {
- start_b += 1;
+ hunkpriv_t *priv = (hunkpriv_t *)cb_data;
+ lua_State *lstate = priv->lstate;
+ if (priv->linematch) {
+ get_linematch_results(lstate, priv->ma, priv->mb, start_a, count_a, start_b, count_b,
+ priv->iwhite);
+ } else {
+ lua_pushhunk(lstate, start_a, count_a, start_b, count_b);
}
- lua_State *lstate = (lua_State *)cb_data;
- lua_createtable(lstate, 0, 0);
-
- lua_pushinteger(lstate, start_a);
- lua_rawseti(lstate, -2, 1);
- lua_pushinteger(lstate, count_a);
- lua_rawseti(lstate, -2, 2);
- lua_pushinteger(lstate, start_b);
- lua_rawseti(lstate, -2, 3);
- lua_pushinteger(lstate, count_b);
- lua_rawseti(lstate, -2, 4);
-
- lua_rawseti(lstate, -2, (signed)lua_objlen(lstate, -2) + 1);
-
return 0;
}
@@ -149,7 +207,7 @@ static bool check_xdiff_opt(ObjectType actType, ObjectType expType, const char *
}
static NluaXdiffMode process_xdl_diff_opts(lua_State *lstate, xdemitconf_t *cfg, xpparam_t *params,
- Error *err)
+ bool *linematch, Error *err)
{
const DictionaryOf(LuaRef) opts = nlua_pop_Dictionary(lstate, true, err);
@@ -205,6 +263,11 @@ static NluaXdiffMode process_xdl_diff_opts(lua_State *lstate, xdemitconf_t *cfg,
goto exit_1;
}
cfg->interhunkctxlen = v->data.integer;
+ } else if (strequal("linematch", k.data)) {
+ *linematch = api_object_to_bool(*v, "linematch", false, err);
+ if (ERROR_SET(err)) {
+ goto exit_1;
+ }
} else {
struct {
const char *name;
@@ -244,10 +307,8 @@ static NluaXdiffMode process_xdl_diff_opts(lua_State *lstate, xdemitconf_t *cfg,
if (had_on_hunk) {
mode = kNluaXdiffModeOnHunkCB;
- cfg->hunk_func = call_on_hunk_cb;
} else if (had_result_type_indices) {
mode = kNluaXdiffModeLocations;
- cfg->hunk_func = hunk_locations_cb;
}
exit_1:
@@ -268,6 +329,7 @@ int nlua_xdl_diff(lua_State *lstate)
xdemitconf_t cfg;
xpparam_t params;
xdemitcb_t ecb;
+ bool linematch = false;
CLEAR_FIELD(cfg);
CLEAR_FIELD(params);
@@ -280,7 +342,7 @@ int nlua_xdl_diff(lua_State *lstate)
return luaL_argerror(lstate, 3, "expected table");
}
- mode = process_xdl_diff_opts(lstate, &cfg, &params, &err);
+ mode = process_xdl_diff_opts(lstate, &cfg, &params, &linematch, &err);
if (ERROR_SET(&err)) {
goto exit_0;
@@ -288,7 +350,7 @@ int nlua_xdl_diff(lua_State *lstate)
}
luaL_Buffer buf;
- hunkpriv_t *priv = NULL;
+ hunkpriv_t priv;
switch (mode) {
case kNluaXdiffModeUnified:
luaL_buffinit(lstate, &buf);
@@ -296,14 +358,24 @@ int nlua_xdl_diff(lua_State *lstate)
ecb.out_line = write_string;
break;
case kNluaXdiffModeOnHunkCB:
- priv = xmalloc(sizeof(*priv));
- priv->lstate = lstate;
- priv->err = &err;
- ecb.priv = priv;
+ cfg.hunk_func = call_on_hunk_cb;
+ priv = (hunkpriv_t) {
+ .lstate = lstate,
+ .err = &err,
+ };
+ ecb.priv = &priv;
break;
case kNluaXdiffModeLocations:
+ cfg.hunk_func = hunk_locations_cb;
+ priv = (hunkpriv_t) {
+ .lstate = lstate,
+ .ma = &ma,
+ .mb = &mb,
+ .linematch = linematch,
+ .iwhite = (params.flags & XDF_IGNORE_WHITESPACE) > 0
+ };
+ ecb.priv = &priv;
lua_createtable(lstate, 0, 0);
- ecb.priv = lstate;
break;
}
@@ -314,8 +386,6 @@ int nlua_xdl_diff(lua_State *lstate)
}
}
- XFREE_CLEAR(priv);
-
exit_0:
if (ERROR_SET(&err)) {
luaL_where(lstate, 1);
diff --git a/src/nvim/mapping.c b/src/nvim/mapping.c
index 2b42d7725b..0fff48019b 100644
--- a/src/nvim/mapping.c
+++ b/src/nvim/mapping.c
@@ -176,7 +176,7 @@ static void showmap(mapblock_T *mp, bool local)
// Display the LHS. Get length of what we write.
len = (size_t)msg_outtrans_special((char *)mp->m_keys, true, 0);
do {
- msg_putchar(' '); // padd with blanks
+ msg_putchar(' '); // pad with blanks
len++;
} while (len < 12);
diff --git a/src/nvim/match.c b/src/nvim/match.c
index b422dc0ba8..916bb44d8c 100644
--- a/src/nvim/match.c
+++ b/src/nvim/match.c
@@ -1206,7 +1206,7 @@ void ex_match(exarg_T *eap)
semsg(_(e_invarg2), eap->arg);
return;
}
- end = skip_regexp(p + 1, *p, true, NULL);
+ end = skip_regexp(p + 1, *p, true);
if (!eap->skip) {
if (*end != NUL && !ends_excmd(*skipwhite(end + 1))) {
xfree(g);
diff --git a/src/nvim/message.c b/src/nvim/message.c
index b608b59c9b..fa1c8036e6 100644
--- a/src/nvim/message.c
+++ b/src/nvim/message.c
@@ -663,6 +663,13 @@ static bool emsg_multiline(const char *s, bool multiline)
return true;
}
+ if (emsg_assert_fails_used && emsg_assert_fails_msg == NULL) {
+ emsg_assert_fails_msg = xstrdup(s);
+ emsg_assert_fails_lnum = SOURCING_LNUM;
+ xfree(emsg_assert_fails_context);
+ emsg_assert_fails_context = xstrdup(SOURCING_NAME == NULL ? "" : SOURCING_NAME);
+ }
+
// set "v:errmsg", also when using ":silent! cmd"
set_vim_var_string(VV_ERRMSG, s, -1);
diff --git a/src/nvim/mouse.c b/src/nvim/mouse.c
index 88dd81da8b..53431187af 100644
--- a/src/nvim/mouse.c
+++ b/src/nvim/mouse.c
@@ -969,6 +969,14 @@ static bool mouse_model_popup(void)
return p_mousem[0] == 'p';
}
+static win_T *dragwin = NULL; ///< window being dragged
+
+/// Reset the window being dragged. To be called when switching tab page.
+void reset_dragwin(void)
+{
+ dragwin = NULL;
+}
+
/// Move the cursor to the specified row and column on the screen.
/// Change current window if necessary. Returns an integer with the
/// CURSOR_MOVED bit set if the cursor has moved or unset otherwise.
@@ -1005,7 +1013,6 @@ int jump_to_mouse(int flags, bool *inclusive, int which_button)
static bool on_winbar = false;
static int prev_row = -1;
static int prev_col = -1;
- static win_T *dragwin = NULL; // window being dragged
static int did_drag = false; // drag was noticed
win_T *wp, *old_curwin;
diff --git a/src/nvim/ops.c b/src/nvim/ops.c
index 7f8a5b6f2e..2d53918ded 100644
--- a/src/nvim/ops.c
+++ b/src/nvim/ops.c
@@ -3272,7 +3272,7 @@ void do_put(int regname, yankreg_T *reg, int dir, long count, int flags)
shortline = (vcol < col) || (vcol == col && !*ptr);
- if (vcol < col) { // line too short, padd with spaces
+ if (vcol < col) { // line too short, pad with spaces
bd.startspaces = col - vcol;
} else if (vcol > col) {
bd.endspaces = vcol - col;
diff --git a/src/nvim/option.c b/src/nvim/option.c
index 8de86ce76e..8142be4eb1 100644
--- a/src/nvim/option.c
+++ b/src/nvim/option.c
@@ -5220,6 +5220,17 @@ unsigned int get_bkc_value(buf_T *buf)
return buf->b_bkc_flags ? buf->b_bkc_flags : bkc_flags;
}
+/// Get the local or global value of 'formatlistpat'.
+///
+/// @param buf The buffer.
+char *get_flp_value(buf_T *buf)
+{
+ if (buf->b_p_flp == NULL || *buf->b_p_flp == NUL) {
+ return p_flp;
+ }
+ return buf->b_p_flp;
+}
+
/// Get the local or global value of the 'virtualedit' flags.
unsigned int get_ve_flags(void)
{
diff --git a/src/nvim/options.lua b/src/nvim/options.lua
index 088aa40fda..3a59becb33 100644
--- a/src/nvim/options.lua
+++ b/src/nvim/options.lua
@@ -19,7 +19,7 @@
-- types: bool, number, string
-- lists: (nil), comma, onecomma, flags, flagscomma
-- scopes: global, buffer, window
--- redraw options: statuslines, tabline, current_window, curent_window_only,
+-- redraw options: statuslines, tabline, current_window, current_window_only,
-- current_buffer, all_windows, curswant
-- defaults: {condition=#if condition, if_true=default, if_false=default}
-- #if condition:
diff --git a/src/nvim/optionstr.c b/src/nvim/optionstr.c
index 43628d2842..65bc9f60df 100644
--- a/src/nvim/optionstr.c
+++ b/src/nvim/optionstr.c
@@ -697,6 +697,10 @@ char *did_set_string_option(int opt_idx, char **varp, char *oldval, char *errbuf
if (briopt_check(curwin) == FAIL) {
errmsg = e_invarg;
}
+ // list setting requires a redraw
+ if (curwin->w_briopt_list) {
+ redraw_all_later(UPD_NOT_VALID);
+ }
} else if (varp == &p_isi
|| varp == &(curbuf->b_p_isk)
|| varp == &p_isp
@@ -1601,6 +1605,12 @@ char *did_set_string_option(int opt_idx, char **varp, char *oldval, char *errbuf
setmouse(); // in case 'mouse' changed
}
+ // Changing Formatlistpattern when briopt includes the list setting:
+ // redraw
+ if ((varp == &p_flp || varp == &(curbuf->b_p_flp)) && curwin->w_briopt_list) {
+ redraw_all_later(UPD_NOT_VALID);
+ }
+
if (curwin->w_curswant != MAXCOL
&& (opt->flags & (P_CURSWANT | P_RALL)) != 0) {
curwin->w_set_curswant = true;
diff --git a/src/nvim/path.c b/src/nvim/path.c
index 625a3c7922..f568ba8854 100644
--- a/src/nvim/path.c
+++ b/src/nvim/path.c
@@ -1244,7 +1244,7 @@ int gen_expand_wildcards(int num_pat, char **pat, int *num_file, char ***file, i
add_pat = expand_backtick(&ga, (char *)p, flags);
if (add_pat == -1) {
recursive = false;
- FreeWild(ga.ga_len, ga.ga_data);
+ ga_clear_strings(&ga);
*num_file = 0;
*file = NULL;
return FAIL;
diff --git a/src/nvim/plines.c b/src/nvim/plines.c
index 42218ac847..bed15f9e36 100644
--- a/src/nvim/plines.c
+++ b/src/nvim/plines.c
@@ -444,9 +444,9 @@ int win_lbr_chartabsize(chartabsize_T *cts, int *headp)
// May have to add something for 'breakindent' and/or 'showbreak'
// string at start of line.
// Set *headp to the size of what we add.
+ // Do not use 'showbreak' at the NUL after the text.
added = 0;
-
- char *const sbr = (char *)get_showbreak_value(wp);
+ char *const sbr = c == NUL ? empty_option : (char *)get_showbreak_value(wp);
if ((*sbr != NUL || wp->w_p_bri) && wp->w_p_wrap && vcol != 0) {
colnr_T sbrlen = 0;
int numberwidth = win_col_off(wp);
diff --git a/src/nvim/quickfix.c b/src/nvim/quickfix.c
index acf9b881f8..5d101ee415 100644
--- a/src/nvim/quickfix.c
+++ b/src/nvim/quickfix.c
@@ -5325,10 +5325,8 @@ static int vgr_process_args(exarg_T *eap, vgr_args_T *args)
}
// Parse the list of arguments, wildcards have already been expanded.
- if (get_arglist_exp(p, &args->fcount, &args->fnames, true) == FAIL) {
- return FAIL;
- }
- if (args->fcount == 0) {
+ if (get_arglist_exp(p, &args->fcount, &args->fnames, true) == FAIL
+ || args->fcount == 0) {
emsg(_(e_nomatch));
return FAIL;
}
diff --git a/src/nvim/regexp.c b/src/nvim/regexp.c
index d6f207a248..7a96889f22 100644
--- a/src/nvim/regexp.c
+++ b/src/nvim/regexp.c
@@ -97,20 +97,24 @@ static int toggle_Magic(int x)
#define MAX_LIMIT (32767L << 16L)
-static char_u e_missingbracket[] = N_("E769: Missing ] after %s[");
-static char_u e_reverse_range[] = N_("E944: Reverse range in character class");
-static char_u e_large_class[] = N_("E945: Range too large in character class");
-static char_u e_unmatchedpp[] = N_("E53: Unmatched %s%%(");
-static char_u e_unmatchedp[] = N_("E54: Unmatched %s(");
-static char_u e_unmatchedpar[] = N_("E55: Unmatched %s)");
-static char_u e_z_not_allowed[] = N_("E66: \\z( not allowed here");
-static char_u e_z1_not_allowed[] = N_("E67: \\z1 - \\z9 not allowed here");
-static char_u e_missing_sb[] = N_("E69: Missing ] after %s%%[");
-static char_u e_empty_sb[] = N_("E70: Empty %s%%[]");
-static char_u e_recursive[] = N_("E956: Cannot use pattern recursively");
-static char_u e_regexp_number_after_dot_pos_search[]
+static char e_missingbracket[] = N_("E769: Missing ] after %s[");
+static char e_reverse_range[] = N_("E944: Reverse range in character class");
+static char e_large_class[] = N_("E945: Range too large in character class");
+static char e_unmatchedpp[] = N_("E53: Unmatched %s%%(");
+static char e_unmatchedp[] = N_("E54: Unmatched %s(");
+static char e_unmatchedpar[] = N_("E55: Unmatched %s)");
+static char e_z_not_allowed[] = N_("E66: \\z( not allowed here");
+static char e_z1_not_allowed[] = N_("E67: \\z1 - \\z9 not allowed here");
+static char e_missing_sb[] = N_("E69: Missing ] after %s%%[");
+static char e_empty_sb[] = N_("E70: Empty %s%%[]");
+static char e_recursive[] = N_("E956: Cannot use pattern recursively");
+static char e_regexp_number_after_dot_pos_search_chr[]
= N_("E1204: No Number allowed after .: '\\%%%c'");
-static char_u e_substitute_nesting_too_deep[] = N_("E1290: substitute nesting too deep");
+static char e_nfa_regexp_missing_value_in_chr[]
+ = N_("E1273: (NFA regexp) missing value in '\\%%%c'");
+static char e_atom_engine_must_be_at_start_of_pattern[]
+ = N_("E1281: Atom '\\%%#=%c' must be at the start of the pattern");
+static char e_substitute_nesting_too_deep[] = N_("E1290: substitute nesting too deep");
#define NOT_MULTI 0
#define MULTI_ONE 1
@@ -481,13 +485,33 @@ static char_u *skip_anyof(char *p)
}
/// Skip past regular expression.
-/// Stop at end of "startp" or where "dirc" is found ('/', '?', etc).
+/// Stop at end of "startp" or where "delim" is found ('/', '?', etc).
/// Take care of characters with a backslash in front of it.
/// Skip strings inside [ and ].
+char *skip_regexp(char *startp, int delim, int magic)
+{
+ return skip_regexp_ex(startp, delim, magic, NULL, NULL);
+}
+
+/// Call skip_regexp() and when the delimiter does not match give an error and
+/// return NULL.
+char *skip_regexp_err(char *startp, int delim, int magic)
+{
+ char *p = skip_regexp(startp, delim, magic);
+
+ if (*p != delim) {
+ semsg(_("E654: missing delimiter after search pattern: %s"), startp);
+ return NULL;
+ }
+ return p;
+}
+
+/// skip_regexp() with extra arguments:
/// When "newp" is not NULL and "dirc" is '?', make an allocated copy of the
/// expression and change "\?" to "?". If "*newp" is not NULL the expression
/// is changed in-place.
-char *skip_regexp(char *startp, int dirc, int magic, char **newp)
+/// If a "\?" is changed to "?" then "dropped" is incremented, unless NULL.
+char *skip_regexp_ex(char *startp, int dirc, int magic, char **newp, int *dropped)
{
int mymagic;
char *p = startp;
@@ -516,6 +540,9 @@ char *skip_regexp(char *startp, int dirc, int magic, char **newp)
*newp = xstrdup(startp);
p = *newp + (p - startp);
}
+ if (dropped != NULL) {
+ (*dropped)++;
+ }
STRMOVE(p, p + 1);
} else {
p++; // skip next character
diff --git a/src/nvim/regexp_bt.c b/src/nvim/regexp_bt.c
index ac33fc0f13..6f63b38a90 100644
--- a/src/nvim/regexp_bt.c
+++ b/src/nvim/regexp_bt.c
@@ -1971,6 +1971,11 @@ static char_u *regatom(int *flagp)
break;
case '#':
+ if (regparse[0] == '=' && regparse[1] >= 48 && regparse[1] <= 50) {
+ // misplaced \%#=1
+ semsg(_(e_atom_engine_must_be_at_start_of_pattern), regparse[1]);
+ return FAIL;
+ }
ret = regnode(CURSOR);
break;
@@ -2091,6 +2096,7 @@ static char_u *regatom(int *flagp)
uint32_t n = 0;
int cmp;
bool cur = false;
+ bool got_digit = false;
cmp = c;
if (cmp == '<' || cmp == '>') {
@@ -2101,6 +2107,7 @@ static char_u *regatom(int *flagp)
c = getchr();
}
while (ascii_isdigit(c)) {
+ got_digit = true;
n = n * 10 + (uint32_t)(c - '0');
c = getchr();
}
@@ -2115,9 +2122,9 @@ static char_u *regatom(int *flagp)
*regcode++ = (char_u)cmp;
}
break;
- } else if (c == 'l' || c == 'c' || c == 'v') {
+ } else if ((c == 'l' || c == 'c' || c == 'v') && (cur || got_digit)) {
if (cur && n) {
- semsg(_(e_regexp_number_after_dot_pos_search), no_Magic(c));
+ semsg(_(e_regexp_number_after_dot_pos_search_chr), no_Magic(c));
rc_did_emsg = true;
return NULL;
}
diff --git a/src/nvim/regexp_nfa.c b/src/nvim/regexp_nfa.c
index fbd4e26c75..d4d2ed28cc 100644
--- a/src/nvim/regexp_nfa.c
+++ b/src/nvim/regexp_nfa.c
@@ -2094,6 +2094,12 @@ static int nfa_regatom(void)
break;
case '#':
+ if (regparse[0] == '=' && regparse[1] >= 48
+ && regparse[1] <= 50) {
+ // misplaced \%#=1
+ semsg(_(e_atom_engine_must_be_at_start_of_pattern), regparse[1]);
+ return FAIL;
+ }
EMIT(NFA_CURSOR);
break;
@@ -2141,6 +2147,7 @@ static int nfa_regatom(void)
int64_t n = 0;
const int cmp = c;
bool cur = false;
+ bool got_digit = false;
if (c == '<' || c == '>') {
c = getchr();
@@ -2151,7 +2158,7 @@ static int nfa_regatom(void)
}
while (ascii_isdigit(c)) {
if (cur) {
- semsg(_(e_regexp_number_after_dot_pos_search), no_Magic(c));
+ semsg(_(e_regexp_number_after_dot_pos_search_chr), no_Magic(c));
return FAIL;
}
if (n > (INT32_MAX - (c - '0')) / 10) {
@@ -2161,10 +2168,15 @@ static int nfa_regatom(void)
}
n = n * 10 + (c - '0');
c = getchr();
+ got_digit = true;
}
if (c == 'l' || c == 'c' || c == 'v') {
int32_t limit = INT32_MAX;
+ if (!cur && !got_digit) {
+ semsg(_(e_nfa_regexp_missing_value_in_chr), no_Magic(c));
+ return FAIL;
+ }
if (c == 'l') {
if (cur) {
n = curwin->w_cursor.lnum;
@@ -3358,8 +3370,8 @@ static void nfa_print_state2(FILE *debugf, nfa_state_T *state, garray_T *indent)
int last = indent->ga_len - 3;
char_u save[2];
- STRNCPY(save, &p[last], 2);
- STRNCPY(&p[last], "+-", 2);
+ STRNCPY(save, &p[last], 2); // NOLINT(runtime/printf)
+ memcpy(&p[last], "+-", 2);
fprintf(debugf, " %s", p);
STRNCPY(&p[last], save, 2); // NOLINT(runtime/printf)
} else {
@@ -4623,6 +4635,20 @@ static bool sub_equal(regsub_T *sub1, regsub_T *sub2)
}
#ifdef REGEXP_DEBUG
+static void open_debug_log(TriState result)
+{
+ log_fd = fopen(NFA_REGEXP_RUN_LOG, "a");
+ if (log_fd == NULL) {
+ emsg(_(e_log_open_failed));
+ log_fd = stderr;
+ }
+
+ fprintf(log_fd, "****************************\n");
+ fprintf(log_fd, "FINISHED RUNNING nfa_regmatch() recursively\n");
+ fprintf(log_fd, "MATCH = %s\n", result == kTrue ? "OK" : result == kNone ? "MAYBE" : "FALSE");
+ fprintf(log_fd, "****************************\n");
+}
+
static void report_state(char *action, regsub_T *sub, nfa_state_T *state, int lid, nfa_pim_T *pim)
{
int col;
@@ -4635,6 +4661,9 @@ static void report_state(char *action, regsub_T *sub, nfa_state_T *state, int li
col = (int)(sub->list.line[0].start - rex.line);
}
nfa_set_code(state->c);
+ if (log_fd == NULL) {
+ open_debug_log(kNone);
+ }
fprintf(log_fd, "> %s state %d to list %d. char %d: %s (start col %d)%s\n",
action, abs(state->id), lid, state->c, code, col,
pim_info(pim));
@@ -5656,16 +5685,7 @@ static int recursive_regmatch(nfa_state_T *state, nfa_pim_T *pim, nfa_regprog_T
nfa_endp = save_nfa_endp;
#ifdef REGEXP_DEBUG
- log_fd = fopen(NFA_REGEXP_RUN_LOG, "a");
- if (log_fd != NULL) {
- fprintf(log_fd, "****************************\n");
- fprintf(log_fd, "FINISHED RUNNING nfa_regmatch() recursively\n");
- fprintf(log_fd, "MATCH = %s\n", !result ? "false" : "OK");
- fprintf(log_fd, "****************************\n");
- } else {
- emsg(_(e_log_open_failed));
- log_fd = stderr;
- }
+ open_debug_log(result);
#endif
return result;
@@ -5971,16 +5991,15 @@ static int nfa_regmatch(nfa_regprog_T *prog, nfa_state_T *start, regsubs_T *subm
#ifdef REGEXP_DEBUG
log_fd = fopen(NFA_REGEXP_RUN_LOG, "a");
- if (log_fd != NULL) {
- fprintf(log_fd, "**********************************\n");
- nfa_set_code(start->c);
- fprintf(log_fd, " RUNNING nfa_regmatch() starting with state %d, code %s\n",
- abs(start->id), code);
- fprintf(log_fd, "**********************************\n");
- } else {
+ if (log_fd == NULL) {
emsg(_(e_log_open_failed));
log_fd = stderr;
}
+ fprintf(log_fd, "**********************************\n");
+ nfa_set_code(start->c);
+ fprintf(log_fd, " RUNNING nfa_regmatch() starting with state %d, code %s\n",
+ abs(start->id), code);
+ fprintf(log_fd, "**********************************\n");
#endif
thislist = &list[0];
diff --git a/src/nvim/runtime.c b/src/nvim/runtime.c
index fa7aa35a4d..6becd50910 100644
--- a/src/nvim/runtime.c
+++ b/src/nvim/runtime.c
@@ -1633,7 +1633,7 @@ void ex_options(exarg_T *eap)
bool multi_mods = 0;
buf[0] = NUL;
- (void)add_win_cmd_modifers(buf, &cmdmod, &multi_mods);
+ (void)add_win_cmd_modifiers(buf, &cmdmod, &multi_mods);
os_setenv("OPTWIN_CMD", buf, 1);
cmd_source(SYS_OPTWIN_FILE, NULL);
diff --git a/src/nvim/search.c b/src/nvim/search.c
index 49892a4cc5..2f3e5a2cb6 100644
--- a/src/nvim/search.c
+++ b/src/nvim/search.c
@@ -1080,7 +1080,7 @@ int do_search(oparg_T *oap, int dirc, int search_delim, char_u *pat, long count,
// Find end of regular expression.
// If there is a matching '/' or '?', toss it.
ps = (char_u *)strcopy;
- p = (char_u *)skip_regexp((char *)pat, search_delim, p_magic, &strcopy);
+ p = (char_u *)skip_regexp_ex((char *)pat, search_delim, p_magic, &strcopy, NULL);
if (strcopy != (char *)ps) {
// made a copy of "pat" to change "\?" to "?"
searchcmdlen += (int)(STRLEN(pat) - strlen(strcopy));
diff --git a/src/nvim/shada.c b/src/nvim/shada.c
index 7830dd5206..40b3429de9 100644
--- a/src/nvim/shada.c
+++ b/src/nvim/shada.c
@@ -166,7 +166,7 @@ typedef enum {
/// Possible results of shada_write function.
typedef enum {
- kSDWriteSuccessfull, ///< Writing was successful.
+ kSDWriteSuccessful, ///< Writing was successful.
kSDWriteReadNotShada, ///< Writing was successful, but when reading it
///< attempted to read file that did not look like
///< a ShaDa file.
@@ -1511,7 +1511,7 @@ static char *shada_filename(const char *file)
/// @param[in] max_kbyte Maximum size of an item in KiB. Zero means no
/// restrictions.
///
-/// @return kSDWriteSuccessfull, kSDWriteFailed or kSDWriteIgnError.
+/// @return kSDWriteSuccessful, kSDWriteFailed or kSDWriteIgnError.
static ShaDaWriteResult shada_pack_entry(msgpack_packer *const packer, ShadaEntry entry,
const size_t max_kbyte)
FUNC_ATTR_NONNULL_ALL
@@ -1819,7 +1819,7 @@ static ShaDaWriteResult shada_pack_entry(msgpack_packer *const packer, ShadaEntr
}
msgpack_packer_free(spacker);
msgpack_sbuffer_destroy(&sbuf);
- return kSDWriteSuccessfull;
+ return kSDWriteSuccessful;
shada_pack_entry_error:
msgpack_packer_free(spacker);
msgpack_sbuffer_destroy(&sbuf);
@@ -1839,7 +1839,7 @@ static inline ShaDaWriteResult shada_pack_pfreed_entry(msgpack_packer *const pac
const size_t max_kbyte)
FUNC_ATTR_NONNULL_ALL FUNC_ATTR_ALWAYS_INLINE
{
- ShaDaWriteResult ret = kSDWriteSuccessfull;
+ ShaDaWriteResult ret = kSDWriteSuccessful;
ret = shada_pack_entry(packer, entry.data, max_kbyte);
if (entry.can_free_entry) {
shada_free_shada_entry(&entry.data);
@@ -2053,7 +2053,7 @@ static inline ShaDaWriteResult shada_read_when_writing(ShaDaReadDef *const sd_re
msgpack_packer *const packer)
FUNC_ATTR_NONNULL_ALL FUNC_ATTR_WARN_UNUSED_RESULT
{
- ShaDaWriteResult ret = kSDWriteSuccessfull;
+ ShaDaWriteResult ret = kSDWriteSuccessful;
ShadaEntry entry;
ShaDaReadResult srni_ret;
@@ -2492,7 +2492,7 @@ static int hist_type2char(const int type)
static ShaDaWriteResult shada_write(ShaDaWriteDef *const sd_writer, ShaDaReadDef *const sd_reader)
FUNC_ATTR_NONNULL_ARG(1)
{
- ShaDaWriteResult ret = kSDWriteSuccessfull;
+ ShaDaWriteResult ret = kSDWriteSuccessful;
int max_kbyte_i = get_shada_parameter('s');
if (max_kbyte_i < 0) {
max_kbyte_i = 10;
@@ -2652,7 +2652,7 @@ static ShaDaWriteResult shada_write(ShaDaWriteDef *const sd_writer, ShaDaReadDef
}
tv_clear(&vartv);
tv_clear(&tgttv);
- if (spe_ret == kSDWriteSuccessfull) {
+ if (spe_ret == kSDWriteSuccessful) {
int kh_ret;
(void)kh_put(strset, &wms->dumped_variables, name, &kh_ret);
}
@@ -2817,7 +2817,7 @@ static ShaDaWriteResult shada_write(ShaDaWriteDef *const sd_writer, ShaDaReadDef
if (sd_reader != NULL) {
const ShaDaWriteResult srww_ret = shada_read_when_writing(sd_reader, srni_flags, max_kbyte, wms,
packer);
- if (srww_ret != kSDWriteSuccessfull) {
+ if (srww_ret != kSDWriteSuccessful) {
ret = srww_ret;
}
}
@@ -3078,7 +3078,7 @@ shada_write_file_nomerge: {}
if (!nomerge) {
sd_reader.close(&sd_reader);
bool did_remove = false;
- if (sw_ret == kSDWriteSuccessfull) {
+ if (sw_ret == kSDWriteSuccessful) {
#ifdef UNIX
// For Unix we check the owner of the file. It's not very nice to
// overwrite a user’s viminfo file after a "su root", with a
diff --git a/src/nvim/spell.c b/src/nvim/spell.c
index 1bd0b9c85f..e76ac49b5d 100644
--- a/src/nvim/spell.c
+++ b/src/nvim/spell.c
@@ -50,7 +50,7 @@
// Use SPELL_PRINTTREE for debugging: dump the word tree after adding a word.
// Only use it for small word lists!
-// Use SPELL_COMPRESS_ALLWAYS for debugging: compress the word tree after
+// Use SPELL_COMPRESS_ALWAYS for debugging: compress the word tree after
// adding a word. Only use it for small word lists!
// Use DEBUG_TRIEWALK to print the changes made in suggest_trie_walk() for a
@@ -160,7 +160,7 @@ typedef struct matchinf_S {
win_T *mi_win; // buffer being checked
// for NOBREAK
- int mi_result2; // "mi_resul" without following word
+ int mi_result2; // "mi_result" without following word
char_u *mi_end2; // "mi_end" without following word
} matchinf_T;
diff --git a/src/nvim/spellfile.c b/src/nvim/spellfile.c
index d5fbbaff1f..7837f242b5 100644
--- a/src/nvim/spellfile.c
+++ b/src/nvim/spellfile.c
@@ -4089,7 +4089,7 @@ static int tree_add_word(spellinfo_T *spin, const char_u *word, wordnode_T *root
// 3. When compressed before, added "compress_added" words
// (si_compress_cnt == 1) and the number of free nodes drops below the
// maximum word length.
-#ifndef SPELL_COMPRESS_ALLWAYS
+#ifndef SPELL_COMPRESS_ALWAYS
if (spin->si_compress_cnt == 1 // NOLINT(readability/braces)
? spin->si_free_count < MAXWLEN
: spin->si_blocks_cnt >= compress_start)
diff --git a/src/nvim/syntax.c b/src/nvim/syntax.c
index e5962cd273..fb82df4fe9 100644
--- a/src/nvim/syntax.c
+++ b/src/nvim/syntax.c
@@ -4749,7 +4749,7 @@ static char *get_syn_pattern(char *arg, synpat_T *ci)
return NULL;
}
- end = skip_regexp(arg + 1, *arg, true, NULL);
+ end = skip_regexp(arg + 1, *arg, true);
if (*end != *arg) { // end delimiter not found
semsg(_("E401: Pattern delimiter not found: %s"), arg);
return NULL;
@@ -4902,7 +4902,7 @@ static void syn_cmd_sync(exarg_T *eap, int syncing)
finished = true;
break;
}
- arg_end = skip_regexp(next_arg + 1, *next_arg, true, NULL);
+ arg_end = skip_regexp(next_arg + 1, *next_arg, true);
if (*arg_end != *next_arg) { // end delimiter not found
illegal = true;
break;
diff --git a/src/nvim/tag.c b/src/nvim/tag.c
index 90b21320d2..264f961b43 100644
--- a/src/nvim/tag.c
+++ b/src/nvim/tag.c
@@ -2670,7 +2670,7 @@ static int jumpto_tag(const char_u *lbuf_arg, int forceit, int keep_help)
// anything following.
str = pbuf;
if (pbuf[0] == '/' || pbuf[0] == '?') {
- str = (char_u *)skip_regexp((char *)pbuf + 1, pbuf[0], false, NULL) + 1;
+ str = (char_u *)skip_regexp((char *)pbuf + 1, pbuf[0], false) + 1;
}
if (str > pbuf_end - 1) { // search command with nothing following
save_p_ws = p_ws;
@@ -2883,7 +2883,7 @@ static int find_extra(char_u **pp)
if (ascii_isdigit(*str)) {
str = (char_u *)skipdigits((char *)str + 1);
} else if (*str == '/' || *str == '?') {
- str = (char_u *)skip_regexp((char *)str + 1, *str, false, NULL);
+ str = (char_u *)skip_regexp((char *)str + 1, *str, false);
if (*str != first_char) {
str = NULL;
} else {
diff --git a/src/nvim/testdir/check.vim b/src/nvim/testdir/check.vim
index 92a51d4371..1459b70243 100644
--- a/src/nvim/testdir/check.vim
+++ b/src/nvim/testdir/check.vim
@@ -4,6 +4,9 @@ source term_util.vim
" Command to check for the presence of a feature.
command -nargs=1 CheckFeature call CheckFeature(<f-args>)
func CheckFeature(name)
+ " if !has(a:name, 1)
+ " throw 'Checking for non-existent feature ' .. a:name
+ " endif
if !has(a:name)
throw 'Skipped: ' .. a:name .. ' feature missing'
endif
diff --git a/test/benchmark/samples/re.freeze.txt b/src/nvim/testdir/samples/re.freeze.txt
index d768c23c5e..d768c23c5e 100644
--- a/test/benchmark/samples/re.freeze.txt
+++ b/src/nvim/testdir/samples/re.freeze.txt
diff --git a/src/nvim/testdir/shared.vim b/src/nvim/testdir/shared.vim
index c2809844ac..ef7cc4ac5f 100644
--- a/src/nvim/testdir/shared.vim
+++ b/src/nvim/testdir/shared.vim
@@ -364,4 +364,19 @@ func GetMessages()
return msg_list
endfunc
+" Run the list of commands in 'cmds' and look for 'errstr' in exception.
+" Note that assert_fails() cannot be used in some places and this function
+" can be used.
+func AssertException(cmds, errstr)
+ let save_exception = ''
+ try
+ for cmd in a:cmds
+ exe cmd
+ endfor
+ catch
+ let save_exception = v:exception
+ endtry
+ call assert_match(a:errstr, save_exception)
+endfunc
+
" vim: shiftwidth=2 sts=2 expandtab
diff --git a/src/nvim/testdir/test49.ok b/src/nvim/testdir/test49.ok
index 9f283e808b..d687f5bc77 100644
--- a/src/nvim/testdir/test49.ok
+++ b/src/nvim/testdir/test49.ok
@@ -1,48 +1,4 @@
Results of test49.vim:
-*** Test 18: OK (67224583)
-*** Test 19: OK (69275973)
-*** Test 20: OK (1874575085)
-*** Test 21: OK (147932225)
-*** Test 22: OK (4161)
-*** Test 23: OK (49)
-*** Test 24: OK (41)
-*** Test 27: OK (1996459)
-*** Test 28: OK (1996459)
-*** Test 29: OK (170428555)
-*** Test 30: OK (190905173)
-*** Test 31: OK (190905173)
-*** Test 34: OK (2146584868)
-*** Test 35: OK (2146584868)
-*** Test 36: OK (1071644672)
-*** Test 37: OK (1071644672)
-*** Test 38: OK (357908480)
-*** Test 39: OK (357908480)
-*** Test 40: OK (357908480)
-*** Test 49: OK (179000669)
-*** Test 50: OK (363550045)
-*** Test 52: OK (1247112011)
-*** Test 53: OK (131071)
-*** Test 54: OK (2047)
-*** Test 55: OK (1023)
-*** Test 56: OK (511)
-*** Test 57: OK (2147450880)
-*** Test 58: OK (624945)
-*** Test 59: OK (2038431743)
-*** Test 60: OK (311511339)
-*** Test 61: OK (374889517)
-*** Test 62: OK (286331153)
-*** Test 63: OK (236978127)
-*** Test 64: OK (1499645335)
-*** Test 65: OK (70187)
-*** Test 66: OK (5464)
-*** Test 67: OK (212514423)
-*** Test 68: OK (212514423)
-*** Test 76: OK (1610087935)
-*** Test 77: OK (1388671)
-*** Test 78: OK (134217728)
-*** Test 79: OK (70288929)
-*** Test 80: OK (17895765)
-*** Test 81: OK (387)
*** Test 82: OK (8454401)
*** Test 83: OK (2835)
*** Test 84: OK (934782101)
diff --git a/src/nvim/testdir/test49.vim b/src/nvim/testdir/test49.vim
index 3ee5e9ff7c..d5f8cd3b60 100644
--- a/src/nvim/testdir/test49.vim
+++ b/src/nvim/testdir/test49.vim
@@ -1,6 +1,6 @@
" Vim script language tests
" Author: Servatius Brandt <Servatius.Brandt@fujitsu-siemens.com>
-" Last Change: 2019 Nov 03
+" Last Change: 2020 Jun 07
"-------------------------------------------------------------------------------
" Test environment {{{1
@@ -456,7 +456,7 @@ function ExtraVim(...)
" messing up the user's viminfo file.
let redirect = a:0 ?
\ " -c 'au VimLeave * redir END' -c 'redir\\! >" . a:1 . "'" : ""
- exec "!echo '" . debug_quits . "q' | " .. v:progpath .. " -u NONE -N -es" . redirect .
+ exec "!echo '" . debug_quits . "q' | " .. v:progpath .. " -u NONE -N -Xes" . redirect .
\ " -c 'debuggreedy|set viminfo+=nviminfo'" .
\ " -c 'let ExtraVimBegin = " . extra_begin . "'" .
\ " -c 'let ExtraVimResult = \"" . resultfile . "\"'" . breakpoints .
@@ -607,1660 +607,6 @@ com! -nargs=1 -bar ExecAsScript call ExecAsScript(<f-args>)
" END_OF_TEST_ENVIRONMENT - do not change or remove this line.
-
-" Tests 1 to 17 were moved to test_vimscript.vim
-let Xtest = 18
-
-"-------------------------------------------------------------------------------
-" Test 18: Interrupt (Ctrl-C pressed) {{{1
-"
-" On an interrupt, the script processing is terminated immediately.
-"-------------------------------------------------------------------------------
-
-XpathINIT
-
-if ExtraVim()
- if 1
- Xpath 1 " X: 1
- while 1
- Xpath 2 " X: 2
- if 1
- Xpath 4 " X: 4
- "INTERRUPT
- Xpath 8 " X: 0
- break
- finish
- endif | Xpath 16 " X: 0
- Xpath 32 " X: 0
- endwhile | Xpath 64 " X: 0
- Xpath 128 " X: 0
- endif | Xpath 256 " X: 0
- Xpath 512 " X: 0
-endif
-
-if ExtraVim()
- try
- Xpath 1024 " X: 1024
- "INTERRUPT
- Xpath 2048 " X: 0
- endtry | Xpath 4096 " X: 0
- Xpath 8192 " X: 0
-endif
-
-if ExtraVim()
- function! F()
- if 1
- Xpath 16384 " X: 16384
- while 1
- Xpath 32768 " X: 32768
- if 1
- Xpath 65536 " X: 65536
- "INTERRUPT
- Xpath 131072 " X: 0
- break
- return
- endif | Xpath 262144 " X: 0
- Xpath Xpath 524288 " X: 0
- endwhile | Xpath 1048576 " X: 0
- Xpath Xpath 2097152 " X: 0
- endif | Xpath Xpath 4194304 " X: 0
- Xpath Xpath 8388608 " X: 0
- endfunction
-
- call F() | Xpath 16777216 " X: 0
- Xpath 33554432 " X: 0
-endif
-
-if ExtraVim()
- function! G()
- try
- Xpath 67108864 " X: 67108864
- "INTERRUPT
- Xpath 134217728 " X: 0
- endtry | Xpath 268435456 " X: 0
- Xpath 536870912 " X: 0
- endfunction
-
- call G() | Xpath 1073741824 " X: 0
- " The Xpath command does not accept 2^31 (negative); display explicitly:
- exec "!echo 2147483648 >>" . g:ExtraVimResult
- " X: 0
-endif
-
-Xcheck 67224583
-
-
-"-------------------------------------------------------------------------------
-" Test 19: Aborting on errors inside :try/:endtry {{{1
-"
-" An error in a command dynamically enclosed in a :try/:endtry region
-" aborts script processing immediately. It does not matter whether
-" the failing command is outside or inside a function and whether a
-" function has an "abort" attribute.
-"-------------------------------------------------------------------------------
-
-XpathINIT
-
-if ExtraVim()
- function! F() abort
- Xpath 1 " X: 1
- asdf
- Xpath 2 " X: 0
- endfunction
-
- try
- Xpath 4 " X: 4
- call F()
- Xpath 8 " X: 0
- endtry | Xpath 16 " X: 0
- Xpath 32 " X: 0
-endif
-
-if ExtraVim()
- function! G()
- Xpath 64 " X: 64
- asdf
- Xpath 128 " X: 0
- endfunction
-
- try
- Xpath 256 " X: 256
- call G()
- Xpath 512 " X: 0
- endtry | Xpath 1024 " X: 0
- Xpath 2048 " X: 0
-endif
-
-if ExtraVim()
- try
- Xpath 4096 " X: 4096
- asdf
- Xpath 8192 " X: 0
- endtry | Xpath 16384 " X: 0
- Xpath 32768 " X: 0
-endif
-
-if ExtraVim()
- if 1
- try
- Xpath 65536 " X: 65536
- asdf
- Xpath 131072 " X: 0
- endtry | Xpath 262144 " X: 0
- endif | Xpath 524288 " X: 0
- Xpath 1048576 " X: 0
-endif
-
-if ExtraVim()
- let p = 1
- while p
- let p = 0
- try
- Xpath 2097152 " X: 2097152
- asdf
- Xpath 4194304 " X: 0
- endtry | Xpath 8388608 " X: 0
- endwhile | Xpath 16777216 " X: 0
- Xpath 33554432 " X: 0
-endif
-
-if ExtraVim()
- let p = 1
- while p
- let p = 0
-" try
- Xpath 67108864 " X: 67108864
- endwhile | Xpath 134217728 " X: 0
- Xpath 268435456 " X: 0
-endif
-
-Xcheck 69275973
-"-------------------------------------------------------------------------------
-" Test 20: Aborting on errors after :try/:endtry {{{1
-"
-" When an error occurs after the last active :try/:endtry region has
-" been left, termination behavior is as if no :try/:endtry has been
-" seen.
-"-------------------------------------------------------------------------------
-
-XpathINIT
-
-if ExtraVim()
- let p = 1
- while p
- let p = 0
- try
- Xpath 1 " X: 1
- endtry
- asdf
- endwhile | Xpath 2 " X: 0
- Xpath 4 " X: 4
-endif
-
-if ExtraVim()
- while 1
- try
- Xpath 8 " X: 8
- break
- Xpath 16 " X: 0
- endtry
- endwhile
- Xpath 32 " X: 32
- asdf
- Xpath 64 " X: 64
-endif
-
-if ExtraVim()
- while 1
- try
- Xpath 128 " X: 128
- break
- Xpath 256 " X: 0
- finally
- Xpath 512 " X: 512
- endtry
- endwhile
- Xpath 1024 " X: 1024
- asdf
- Xpath 2048 " X: 2048
-endif
-
-if ExtraVim()
- while 1
- try
- Xpath 4096 " X: 4096
- finally
- Xpath 8192 " X: 8192
- break
- Xpath 16384 " X: 0
- endtry
- endwhile
- Xpath 32768 " X: 32768
- asdf
- Xpath 65536 " X: 65536
-endif
-
-if ExtraVim()
- let p = 1
- while p
- let p = 0
- try
- Xpath 131072 " X: 131072
- continue
- Xpath 262144 " X: 0
- endtry
- endwhile
- Xpath 524288 " X: 524288
- asdf
- Xpath 1048576 " X: 1048576
-endif
-
-if ExtraVim()
- let p = 1
- while p
- let p = 0
- try
- Xpath 2097152 " X: 2097152
- continue
- Xpath 4194304 " X: 0
- finally
- Xpath 8388608 " X: 8388608
- endtry
- endwhile
- Xpath 16777216 " X: 16777216
- asdf
- Xpath 33554432 " X: 33554432
-endif
-
-if ExtraVim()
- let p = 1
- while p
- let p = 0
- try
- Xpath 67108864 " X: 67108864
- finally
- Xpath 134217728 " X: 134217728
- continue
- Xpath 268435456 " X: 0
- endtry
- endwhile
- Xpath 536870912 " X: 536870912
- asdf
- Xpath 1073741824 " X: 1073741824
-endif
-
-Xcheck 1874575085
-
-
-"-------------------------------------------------------------------------------
-" Test 21: :finally for :try after :continue/:break/:return/:finish {{{1
-"
-" If a :try conditional stays inactive due to a preceding :continue,
-" :break, :return, or :finish, its :finally clause should not be
-" executed.
-"-------------------------------------------------------------------------------
-
-XpathINIT
-
-if ExtraVim()
- function F()
- let loops = 2
- XloopINIT! 1 256
- while loops > 0
- XloopNEXT
- let loops = loops - 1
- try
- if loops == 1
- Xloop 1 " X: 1
- continue
- Xloop 2 " X: 0
- elseif loops == 0
- Xloop 4 " X: 4*256
- break
- Xloop 8 " X: 0
- endif
-
- try " inactive
- Xloop 16 " X: 0
- finally
- Xloop 32 " X: 0
- endtry
- finally
- Xloop 64 " X: 64 + 64*256
- endtry
- Xloop 128 " X: 0
- endwhile
-
- try
- Xpath 65536 " X: 65536
- return
- Xpath 131072 " X: 0
- try " inactive
- Xpath 262144 " X: 0
- finally
- Xpath 524288 " X: 0
- endtry
- finally
- Xpath 1048576 " X: 1048576
- endtry
- Xpath 2097152 " X: 0
- endfunction
-
- try
- Xpath 4194304 " X: 4194304
- call F()
- Xpath 8388608 " X: 8388608
- finish
- Xpath 16777216 " X: 0
- try " inactive
- Xpath 33554432 " X: 0
- finally
- Xpath 67108864 " X: 0
- endtry
- finally
- Xpath 134217728 " X: 134217728
- endtry
- Xpath 268435456 " X: 0
-endif
-
-Xcheck 147932225
-
-
-"-------------------------------------------------------------------------------
-" Test 22: :finally for a :try after an error/interrupt/:throw {{{1
-"
-" If a :try conditional stays inactive due to a preceding error or
-" interrupt or :throw, its :finally clause should not be executed.
-"-------------------------------------------------------------------------------
-
-XpathINIT
-
-if ExtraVim()
- function! Error()
- try
- asdf " aborting error, triggering error exception
- endtry
- endfunction
-
- Xpath 1 " X: 1
- call Error()
- Xpath 2 " X: 0
-
- if 1 " not active due to error
- try " not active since :if inactive
- Xpath 4 " X: 0
- finally
- Xpath 8 " X: 0
- endtry
- endif
-
- try " not active due to error
- Xpath 16 " X: 0
- finally
- Xpath 32 " X: 0
- endtry
-endif
-
-if ExtraVim()
- function! Interrupt()
- try
- "INTERRUPT " triggering interrupt exception
- endtry
- endfunction
-
- Xpath 64 " X: 64
- call Interrupt()
- Xpath 128 " X: 0
-
- if 1 " not active due to interrupt
- try " not active since :if inactive
- Xpath 256 " X: 0
- finally
- Xpath 512 " X: 0
- endtry
- endif
-
- try " not active due to interrupt
- Xpath 1024 " X: 0
- finally
- Xpath 2048 " X: 0
- endtry
-endif
-
-if ExtraVim()
- function! Throw()
- throw "xyz"
- endfunction
-
- Xpath 4096 " X: 4096
- call Throw()
- Xpath 8192 " X: 0
-
- if 1 " not active due to :throw
- try " not active since :if inactive
- Xpath 16384 " X: 0
- finally
- Xpath 32768 " X: 0
- endtry
- endif
-
- try " not active due to :throw
- Xpath 65536 " X: 0
- finally
- Xpath 131072 " X: 0
- endtry
-endif
-
-Xcheck 4161
-
-
-"-------------------------------------------------------------------------------
-" Test 23: :catch clauses for a :try after a :throw {{{1
-"
-" If a :try conditional stays inactive due to a preceding :throw,
-" none of its :catch clauses should be executed.
-"-------------------------------------------------------------------------------
-
-XpathINIT
-
-if ExtraVim()
- try
- Xpath 1 " X: 1
- throw "xyz"
- Xpath 2 " X: 0
-
- if 1 " not active due to :throw
- try " not active since :if inactive
- Xpath 4 " X: 0
- catch /xyz/
- Xpath 8 " X: 0
- endtry
- endif
- catch /xyz/
- Xpath 16 " X: 16
- endtry
-
- Xpath 32 " X: 32
- throw "abc"
- Xpath 64 " X: 0
-
- try " not active due to :throw
- Xpath 128 " X: 0
- catch /abc/
- Xpath 256 " X: 0
- endtry
-endif
-
-Xcheck 49
-
-
-"-------------------------------------------------------------------------------
-" Test 24: :endtry for a :try after a :throw {{{1
-"
-" If a :try conditional stays inactive due to a preceding :throw,
-" its :endtry should not rethrow the exception to the next surrounding
-" active :try conditional.
-"-------------------------------------------------------------------------------
-
-XpathINIT
-
-if ExtraVim()
- try " try 1
- try " try 2
- Xpath 1 " X: 1
- throw "xyz" " makes try 2 inactive
- Xpath 2 " X: 0
-
- try " try 3
- Xpath 4 " X: 0
- endtry " no rethrow to try 1
- catch /xyz/ " should catch although try 2 inactive
- Xpath 8 " X: 8
- endtry
- catch /xyz/ " try 1 active, but exception already caught
- Xpath 16 " X: 0
- endtry
- Xpath 32 " X: 32
-endif
-
-Xcheck 41
-
-" Tests 25 and 26 were moved to test_trycatch.vim
-let Xtest = 27
-
-
-"-------------------------------------------------------------------------------
-" Test 27: Executing :finally clauses after :return {{{1
-"
-" For a :return command dynamically enclosed in a :try/:endtry region,
-" :finally clauses are executed and the called function is ended.
-"-------------------------------------------------------------------------------
-
-XpathINIT
-
-function! F()
- try
- Xpath 1 " X: 1
- try
- Xpath 2 " X: 2
- return
- Xpath 4 " X: 0
- finally
- Xpath 8 " X: 8
- endtry
- Xpath 16 " X: 0
- finally
- Xpath 32 " X: 32
- endtry
- Xpath 64 " X: 0
-endfunction
-
-function! G()
- try
- Xpath 128 " X: 128
- return
- Xpath 256 " X: 0
- finally
- Xpath 512 " X: 512
- call F()
- Xpath 1024 " X: 1024
- endtry
- Xpath 2048 " X: 0
-endfunction
-
-function! H()
- try
- Xpath 4096 " X: 4096
- call G()
- Xpath 8192 " X: 8192
- finally
- Xpath 16384 " X: 16384
- return
- Xpath 32768 " X: 0
- endtry
- Xpath 65536 " X: 0
-endfunction
-
-try
- Xpath 131072 " X: 131072
- call H()
- Xpath 262144 " X: 262144
-finally
- Xpath 524288 " X: 524288
-endtry
-Xpath 1048576 " X: 1048576
-
-Xcheck 1996459
-
-" Leave F, G, and H for execution as scripts in the next test.
-
-
-"-------------------------------------------------------------------------------
-" Test 28: Executing :finally clauses after :finish {{{1
-"
-" For a :finish command dynamically enclosed in a :try/:endtry region,
-" :finally clauses are executed and the sourced file is finished.
-"
-" This test executes the bodies of the functions F, G, and H from the
-" previous test as script files (:return replaced by :finish).
-"-------------------------------------------------------------------------------
-
-XpathINIT
-
-let scriptF = MakeScript("F") " X: 1 + 2 + 8 + 32
-let scriptG = MakeScript("G", scriptF) " X: 128 + 512 + 1024
-let scriptH = MakeScript("H", scriptG) " X: 4096 + 8192 + 16384
-
-try
- Xpath 131072 " X: 131072
- exec "source" scriptH
- Xpath 262144 " X: 262144
-finally
- Xpath 524288 " X: 524288
-endtry
-Xpath 1048576 " X: 1048576
-
-call delete(scriptF)
-call delete(scriptG)
-call delete(scriptH)
-unlet scriptF scriptG scriptH
-delfunction F
-delfunction G
-delfunction H
-
-Xcheck 1996459
-
-
-"-------------------------------------------------------------------------------
-" Test 29: Executing :finally clauses on errors {{{1
-"
-" After an error in a command dynamically enclosed in a :try/:endtry
-" region, :finally clauses are executed and the script processing is
-" terminated.
-"-------------------------------------------------------------------------------
-
-XpathINIT
-
-if ExtraVim()
- function! F()
- while 1
- try
- Xpath 1 " X: 1
- while 1
- try
- Xpath 2 " X: 2
- asdf " error
- Xpath 4 " X: 0
- finally
- Xpath 8 " X: 8
- endtry | Xpath 16 " X: 0
- Xpath 32 " X: 0
- break
- endwhile
- Xpath 64 " X: 0
- finally
- Xpath 128 " X: 128
- endtry | Xpath 256 " X: 0
- Xpath 512 " X: 0
- break
- endwhile
- Xpath 1024 " X: 0
- endfunction
-
- while 1
- try
- Xpath 2048 " X: 2048
- while 1
- call F()
- Xpath 4096 " X: 0
- break
- endwhile | Xpath 8192 " X: 0
- Xpath 16384 " X: 0
- finally
- Xpath 32768 " X: 32768
- endtry | Xpath 65536 " X: 0
- endwhile | Xpath 131072 " X: 0
- Xpath 262144 " X: 0
-endif
-
-if ExtraVim()
- function! G() abort
- if 1
- try
- Xpath 524288 " X: 524288
- asdf " error
- Xpath 1048576 " X: 0
- finally
- Xpath 2097152 " X: 2097152
- endtry | Xpath 4194304 " X: 0
- endif | Xpath 8388608 " X: 0
- Xpath 16777216 " X: 0
- endfunction
-
- if 1
- try
- Xpath 33554432 " X: 33554432
- call G()
- Xpath 67108864 " X: 0
- finally
- Xpath 134217728 " X: 134217728
- endtry | Xpath 268435456 " X: 0
- endif | Xpath 536870912 " X: 0
- Xpath 1073741824 " X: 0
-endif
-
-Xcheck 170428555
-
-
-"-------------------------------------------------------------------------------
-" Test 30: Executing :finally clauses on interrupt {{{1
-"
-" After an interrupt in a command dynamically enclosed in
-" a :try/:endtry region, :finally clauses are executed and the
-" script processing is terminated.
-"-------------------------------------------------------------------------------
-
-XpathINIT
-
-if ExtraVim()
- XloopINIT 1 16
-
- function! F()
- try
- Xloop 1 " X: 1 + 1*16
- "INTERRUPT
- Xloop 2 " X: 0
- finally
- Xloop 4 " X: 4 + 4*16
- endtry
- Xloop 8 " X: 0
- endfunction
-
- try
- Xpath 256 " X: 256
- try
- Xpath 512 " X: 512
- "INTERRUPT
- Xpath 1024 " X: 0
- finally
- Xpath 2048 " X: 2048
- try
- Xpath 4096 " X: 4096
- try
- Xpath 8192 " X: 8192
- finally
- Xpath 16384 " X: 16384
- try
- Xpath 32768 " X: 32768
- "INTERRUPT
- Xpath 65536 " X: 0
- endtry
- Xpath 131072 " X: 0
- endtry
- Xpath 262144 " X: 0
- endtry
- Xpath 524288 " X: 0
- endtry
- Xpath 1048576 " X: 0
- finally
- Xpath 2097152 " X: 2097152
- try
- Xpath 4194304 " X: 4194304
- call F()
- Xpath 8388608 " X: 0
- finally
- Xpath 16777216 " X: 16777216
- try
- Xpath 33554432 " X: 33554432
- XloopNEXT
- ExecAsScript F
- Xpath 67108864 " X: 0
- finally
- Xpath 134217728 " X: 134217728
- endtry
- Xpath 268435456 " X: 0
- endtry
- Xpath 536870912 " X: 0
- endtry
- Xpath 1073741824 " X: 0
-endif
-
-Xcheck 190905173
-
-
-"-------------------------------------------------------------------------------
-" Test 31: Executing :finally clauses after :throw {{{1
-"
-" After a :throw dynamically enclosed in a :try/:endtry region,
-" :finally clauses are executed and the script processing is
-" terminated.
-"-------------------------------------------------------------------------------
-
-XpathINIT
-
-if ExtraVim()
- XloopINIT 1 16
-
- function! F()
- try
- Xloop 1 " X: 1 + 1*16
- throw "exception"
- Xloop 2 " X: 0
- finally
- Xloop 4 " X: 4 + 4*16
- endtry
- Xloop 8 " X: 0
- endfunction
-
- try
- Xpath 256 " X: 256
- try
- Xpath 512 " X: 512
- throw "exception"
- Xpath 1024 " X: 0
- finally
- Xpath 2048 " X: 2048
- try
- Xpath 4096 " X: 4096
- try
- Xpath 8192 " X: 8192
- finally
- Xpath 16384 " X: 16384
- try
- Xpath 32768 " X: 32768
- throw "exception"
- Xpath 65536 " X: 0
- endtry
- Xpath 131072 " X: 0
- endtry
- Xpath 262144 " X: 0
- endtry
- Xpath 524288 " X: 0
- endtry
- Xpath 1048576 " X: 0
- finally
- Xpath 2097152 " X: 2097152
- try
- Xpath 4194304 " X: 4194304
- call F()
- Xpath 8388608 " X: 0
- finally
- Xpath 16777216 " X: 16777216
- try
- Xpath 33554432 " X: 33554432
- XloopNEXT
- ExecAsScript F
- Xpath 67108864 " X: 0
- finally
- Xpath 134217728 " X: 134217728
- endtry
- Xpath 268435456 " X: 0
- endtry
- Xpath 536870912 " X: 0
- endtry
- Xpath 1073741824 " X: 0
-endif
-
-Xcheck 190905173
-
-" Tests 32 and 33 were moved to test_trycatch.vim
-let Xtest = 34
-
-
-"-------------------------------------------------------------------------------
-" Test 34: :finally reason discarded by :continue {{{1
-"
-" When a :finally clause is executed due to a :continue, :break,
-" :return, :finish, error, interrupt or :throw, the jump reason is
-" discarded by a :continue in the finally clause.
-"-------------------------------------------------------------------------------
-
-XpathINIT
-
-if ExtraVim()
-
- XloopINIT! 1 8
-
- function! C(jump)
- XloopNEXT
- let loop = 0
- while loop < 2
- let loop = loop + 1
- if loop == 1
- try
- if a:jump == "continue"
- continue
- elseif a:jump == "break"
- break
- elseif a:jump == "return" || a:jump == "finish"
- return
- elseif a:jump == "error"
- asdf
- elseif a:jump == "interrupt"
- "INTERRUPT
- let dummy = 0
- elseif a:jump == "throw"
- throw "abc"
- endif
- finally
- continue " discards jump that caused the :finally
- Xloop 1 " X: 0
- endtry
- Xloop 2 " X: 0
- elseif loop == 2
- Xloop 4 " X: 4*(1+8+64+512+4096+32768+262144)
- endif
- endwhile
- endfunction
-
- call C("continue")
- Xpath 2097152 " X: 2097152
- call C("break")
- Xpath 4194304 " X: 4194304
- call C("return")
- Xpath 8388608 " X: 8388608
- let g:jump = "finish"
- ExecAsScript C
- unlet g:jump
- Xpath 16777216 " X: 16777216
- try
- call C("error")
- Xpath 33554432 " X: 33554432
- finally
- Xpath 67108864 " X: 67108864
- try
- call C("interrupt")
- Xpath 134217728 " X: 134217728
- finally
- Xpath 268435456 " X: 268435456
- call C("throw")
- Xpath 536870912 " X: 536870912
- endtry
- endtry
- Xpath 1073741824 " X: 1073741824
-
- delfunction C
-
-endif
-
-Xcheck 2146584868
-
-
-"-------------------------------------------------------------------------------
-" Test 35: :finally reason discarded by :break {{{1
-"
-" When a :finally clause is executed due to a :continue, :break,
-" :return, :finish, error, interrupt or :throw, the jump reason is
-" discarded by a :break in the finally clause.
-"-------------------------------------------------------------------------------
-
-XpathINIT
-
-if ExtraVim()
-
- XloopINIT! 1 8
-
- function! B(jump)
- XloopNEXT
- let loop = 0
- while loop < 2
- let loop = loop + 1
- if loop == 1
- try
- if a:jump == "continue"
- continue
- elseif a:jump == "break"
- break
- elseif a:jump == "return" || a:jump == "finish"
- return
- elseif a:jump == "error"
- asdf
- elseif a:jump == "interrupt"
- "INTERRUPT
- let dummy = 0
- elseif a:jump == "throw"
- throw "abc"
- endif
- finally
- break " discards jump that caused the :finally
- Xloop 1 " X: 0
- endtry
- elseif loop == 2
- Xloop 2 " X: 0
- endif
- endwhile
- Xloop 4 " X: 4*(1+8+64+512+4096+32768+262144)
- endfunction
-
- call B("continue")
- Xpath 2097152 " X: 2097152
- call B("break")
- Xpath 4194304 " X: 4194304
- call B("return")
- Xpath 8388608 " X: 8388608
- let g:jump = "finish"
- ExecAsScript B
- unlet g:jump
- Xpath 16777216 " X: 16777216
- try
- call B("error")
- Xpath 33554432 " X: 33554432
- finally
- Xpath 67108864 " X: 67108864
- try
- call B("interrupt")
- Xpath 134217728 " X: 134217728
- finally
- Xpath 268435456 " X: 268435456
- call B("throw")
- Xpath 536870912 " X: 536870912
- endtry
- endtry
- Xpath 1073741824 " X: 1073741824
-
- delfunction B
-
-endif
-
-Xcheck 2146584868
-
-
-"-------------------------------------------------------------------------------
-" Test 36: :finally reason discarded by :return {{{1
-"
-" When a :finally clause is executed due to a :continue, :break,
-" :return, :finish, error, interrupt or :throw, the jump reason is
-" discarded by a :return in the finally clause.
-"-------------------------------------------------------------------------------
-
-XpathINIT
-
-if ExtraVim()
-
- XloopINIT! 1 8
-
- function! R(jump, retval) abort
- XloopNEXT
- let loop = 0
- while loop < 2
- let loop = loop + 1
- if loop == 1
- try
- if a:jump == "continue"
- continue
- elseif a:jump == "break"
- break
- elseif a:jump == "return"
- return
- elseif a:jump == "error"
- asdf
- elseif a:jump == "interrupt"
- "INTERRUPT
- let dummy = 0
- elseif a:jump == "throw"
- throw "abc"
- endif
- finally
- return a:retval " discards jump that caused the :finally
- Xloop 1 " X: 0
- endtry
- elseif loop == 2
- Xloop 2 " X: 0
- endif
- endwhile
- Xloop 4 " X: 0
- endfunction
-
- let sum = -R("continue", -8)
- Xpath 2097152 " X: 2097152
- let sum = sum - R("break", -16)
- Xpath 4194304 " X: 4194304
- let sum = sum - R("return", -32)
- Xpath 8388608 " X: 8388608
- try
- let sum = sum - R("error", -64)
- Xpath 16777216 " X: 16777216
- finally
- Xpath 33554432 " X: 33554432
- try
- let sum = sum - R("interrupt", -128)
- Xpath 67108864 " X: 67108864
- finally
- Xpath 134217728 " X: 134217728
- let sum = sum - R("throw", -256)
- Xpath 268435456 " X: 268435456
- endtry
- endtry
- Xpath 536870912 " X: 536870912
-
- let expected = 8 + 16 + 32 + 64 + 128 + 256
- if sum != expected
- Xpath 1073741824 " X: 0
- Xout "sum =" . sum . ", expected: " . expected
- endif
-
- unlet sum expected
- delfunction R
-
-endif
-
-Xcheck 1071644672
-
-
-"-------------------------------------------------------------------------------
-" Test 37: :finally reason discarded by :finish {{{1
-"
-" When a :finally clause is executed due to a :continue, :break,
-" :return, :finish, error, interrupt or :throw, the jump reason is
-" discarded by a :finish in the finally clause.
-"-------------------------------------------------------------------------------
-
-XpathINIT
-
-if ExtraVim()
-
- XloopINIT! 1 8
-
- function! F(jump) " not executed as function, transformed to a script
- XloopNEXT
- let loop = 0
- while loop < 2
- let loop = loop + 1
- if loop == 1
- try
- if a:jump == "continue"
- continue
- elseif a:jump == "break"
- break
- elseif a:jump == "finish"
- finish
- elseif a:jump == "error"
- asdf
- elseif a:jump == "interrupt"
- "INTERRUPT
- let dummy = 0
- elseif a:jump == "throw"
- throw "abc"
- endif
- finally
- finish " discards jump that caused the :finally
- Xloop 1 " X: 0
- endtry
- elseif loop == 2
- Xloop 2 " X: 0
- endif
- endwhile
- Xloop 4 " X: 0
- endfunction
-
- let scriptF = MakeScript("F")
- delfunction F
-
- let g:jump = "continue"
- exec "source" scriptF
- Xpath 2097152 " X: 2097152
- let g:jump = "break"
- exec "source" scriptF
- Xpath 4194304 " X: 4194304
- let g:jump = "finish"
- exec "source" scriptF
- Xpath 8388608 " X: 8388608
- try
- let g:jump = "error"
- exec "source" scriptF
- Xpath 16777216 " X: 16777216
- finally
- Xpath 33554432 " X: 33554432
- try
- let g:jump = "interrupt"
- exec "source" scriptF
- Xpath 67108864 " X: 67108864
- finally
- Xpath 134217728 " X: 134217728
- try
- let g:jump = "throw"
- exec "source" scriptF
- Xpath 268435456 " X: 268435456
- finally
- Xpath 536870912 " X: 536870912
- endtry
- endtry
- endtry
- unlet g:jump
-
- call delete(scriptF)
- unlet scriptF
-
-endif
-
-Xcheck 1071644672
-
-
-"-------------------------------------------------------------------------------
-" Test 38: :finally reason discarded by an error {{{1
-"
-" When a :finally clause is executed due to a :continue, :break,
-" :return, :finish, error, interrupt or :throw, the jump reason is
-" discarded by an error in the finally clause.
-"-------------------------------------------------------------------------------
-
-XpathINIT
-
-if ExtraVim()
-
- XloopINIT! 1 4
-
- function! E(jump)
- XloopNEXT
- let loop = 0
- while loop < 2
- let loop = loop + 1
- if loop == 1
- try
- if a:jump == "continue"
- continue
- elseif a:jump == "break"
- break
- elseif a:jump == "return" || a:jump == "finish"
- return
- elseif a:jump == "error"
- asdf
- elseif a:jump == "interrupt"
- "INTERRUPT
- let dummy = 0
- elseif a:jump == "throw"
- throw "abc"
- endif
- finally
- asdf " error; discards jump that caused the :finally
- endtry
- elseif loop == 2
- Xloop 1 " X: 0
- endif
- endwhile
- Xloop 2 " X: 0
- endfunction
-
- try
- Xpath 16384 " X: 16384
- call E("continue")
- Xpath 32768 " X: 0
- finally
- try
- Xpath 65536 " X: 65536
- call E("break")
- Xpath 131072 " X: 0
- finally
- try
- Xpath 262144 " X: 262144
- call E("return")
- Xpath 524288 " X: 0
- finally
- try
- Xpath 1048576 " X: 1048576
- let g:jump = "finish"
- ExecAsScript E
- Xpath 2097152 " X: 0
- finally
- unlet g:jump
- try
- Xpath 4194304 " X: 4194304
- call E("error")
- Xpath 8388608 " X: 0
- finally
- try
- Xpath 16777216 " X: 16777216
- call E("interrupt")
- Xpath 33554432 " X: 0
- finally
- try
- Xpath 67108864 " X: 67108864
- call E("throw")
- Xpath 134217728 " X: 0
- finally
- Xpath 268435456 " X: 268435456
- delfunction E
- endtry
- endtry
- endtry
- endtry
- endtry
- endtry
- endtry
- Xpath 536870912 " X: 0
-
-endif
-
-Xcheck 357908480
-
-
-"-------------------------------------------------------------------------------
-" Test 39: :finally reason discarded by an interrupt {{{1
-"
-" When a :finally clause is executed due to a :continue, :break,
-" :return, :finish, error, interrupt or :throw, the jump reason is
-" discarded by an interrupt in the finally clause.
-"-------------------------------------------------------------------------------
-
-XpathINIT
-
-if ExtraVim()
-
- XloopINIT! 1 4
-
- function! I(jump)
- XloopNEXT
- let loop = 0
- while loop < 2
- let loop = loop + 1
- if loop == 1
- try
- if a:jump == "continue"
- continue
- elseif a:jump == "break"
- break
- elseif a:jump == "return" || a:jump == "finish"
- return
- elseif a:jump == "error"
- asdf
- elseif a:jump == "interrupt"
- "INTERRUPT
- let dummy = 0
- elseif a:jump == "throw"
- throw "abc"
- endif
- finally
- "INTERRUPT - discards jump that caused the :finally
- let dummy = 0
- endtry
- elseif loop == 2
- Xloop 1 " X: 0
- endif
- endwhile
- Xloop 2 " X: 0
- endfunction
-
- try
- Xpath 16384 " X: 16384
- call I("continue")
- Xpath 32768 " X: 0
- finally
- try
- Xpath 65536 " X: 65536
- call I("break")
- Xpath 131072 " X: 0
- finally
- try
- Xpath 262144 " X: 262144
- call I("return")
- Xpath 524288 " X: 0
- finally
- try
- Xpath 1048576 " X: 1048576
- let g:jump = "finish"
- ExecAsScript I
- Xpath 2097152 " X: 0
- finally
- unlet g:jump
- try
- Xpath 4194304 " X: 4194304
- call I("error")
- Xpath 8388608 " X: 0
- finally
- try
- Xpath 16777216 " X: 16777216
- call I("interrupt")
- Xpath 33554432 " X: 0
- finally
- try
- Xpath 67108864 " X: 67108864
- call I("throw")
- Xpath 134217728 " X: 0
- finally
- Xpath 268435456 " X: 268435456
- delfunction I
- endtry
- endtry
- endtry
- endtry
- endtry
- endtry
- endtry
- Xpath 536870912 " X: 0
-
-endif
-
-Xcheck 357908480
-
-
-"-------------------------------------------------------------------------------
-" Test 40: :finally reason discarded by :throw {{{1
-"
-" When a :finally clause is executed due to a :continue, :break,
-" :return, :finish, error, interrupt or :throw, the jump reason is
-" discarded by a :throw in the finally clause.
-"-------------------------------------------------------------------------------
-
-XpathINIT
-
-if ExtraVim()
-
- XloopINIT! 1 4
-
- function! T(jump)
- XloopNEXT
- let loop = 0
- while loop < 2
- let loop = loop + 1
- if loop == 1
- try
- if a:jump == "continue"
- continue
- elseif a:jump == "break"
- break
- elseif a:jump == "return" || a:jump == "finish"
- return
- elseif a:jump == "error"
- asdf
- elseif a:jump == "interrupt"
- "INTERRUPT
- let dummy = 0
- elseif a:jump == "throw"
- throw "abc"
- endif
- finally
- throw "xyz" " discards jump that caused the :finally
- endtry
- elseif loop == 2
- Xloop 1 " X: 0
- endif
- endwhile
- Xloop 2 " X: 0
- endfunction
-
- try
- Xpath 16384 " X: 16384
- call T("continue")
- Xpath 32768 " X: 0
- finally
- try
- Xpath 65536 " X: 65536
- call T("break")
- Xpath 131072 " X: 0
- finally
- try
- Xpath 262144 " X: 262144
- call T("return")
- Xpath 524288 " X: 0
- finally
- try
- Xpath 1048576 " X: 1048576
- let g:jump = "finish"
- ExecAsScript T
- Xpath 2097152 " X: 0
- finally
- unlet g:jump
- try
- Xpath 4194304 " X: 4194304
- call T("error")
- Xpath 8388608 " X: 0
- finally
- try
- Xpath 16777216 " X: 16777216
- call T("interrupt")
- Xpath 33554432 " X: 0
- finally
- try
- Xpath 67108864 " X: 67108864
- call T("throw")
- Xpath 134217728 " X: 0
- finally
- Xpath 268435456 " X: 268435456
- delfunction T
- endtry
- endtry
- endtry
- endtry
- endtry
- endtry
- endtry
- Xpath 536870912 " X: 0
-
-endif
-
-Xcheck 357908480
-
-" Tests 41 to 48 were moved to test_trycatch.vim
-let Xtest = 49
-
-
-"-------------------------------------------------------------------------------
-" Test 49: Throwing exceptions across functions {{{1
-"
-" When an exception is thrown but not caught inside a function, the
-" caller is checked for a matching :catch clause.
-"-------------------------------------------------------------------------------
-
-XpathINIT
-
-function! C()
- try
- Xpath 1 " X: 1
- throw "arrgh"
- Xpath 2 " X: 0
- catch /arrgh/
- Xpath 4 " X: 4
- endtry
- Xpath 8 " X: 8
-endfunction
-
-XloopINIT! 16 16
-
-function! T1()
- XloopNEXT
- try
- Xloop 1 " X: 16 + 16*16
- throw "arrgh"
- Xloop 2 " X: 0
- finally
- Xloop 4 " X: 64 + 64*16
- endtry
- Xloop 8 " X: 0
-endfunction
-
-function! T2()
- try
- Xpath 4096 " X: 4096
- call T1()
- Xpath 8192 " X: 0
- finally
- Xpath 16384 " X: 16384
- endtry
- Xpath 32768 " X: 0
-endfunction
-
-try
- Xpath 65536 " X: 65536
- call C() " throw and catch
- Xpath 131072 " X: 131072
-catch /.*/
- Xpath 262144 " X: 0
- Xout v:exception "in" v:throwpoint
-endtry
-
-try
- Xpath 524288 " X: 524288
- call T1() " throw, one level
- Xpath 1048576 " X: 0
-catch /arrgh/
- Xpath 2097152 " X: 2097152
-catch /.*/
- Xpath 4194304 " X: 0
- Xout v:exception "in" v:throwpoint
-endtry
-
-try
- Xpath 8388608 " X: 8388608
- call T2() " throw, two levels
- Xpath 16777216 " X: 0
-catch /arrgh/
- Xpath 33554432 " X: 33554432
-catch /.*/
- Xpath 67108864 " X: 0
- Xout v:exception "in" v:throwpoint
-endtry
-Xpath 134217728 " X: 134217728
-
-Xcheck 179000669
-
-" Leave C, T1, and T2 for execution as scripts in the next test.
-
-
-"-------------------------------------------------------------------------------
-" Test 50: Throwing exceptions across script files {{{1
-"
-" When an exception is thrown but not caught inside a script file,
-" the sourcing script or function is checked for a matching :catch
-" clause.
-"
-" This test executes the bodies of the functions C, T1, and T2 from
-" the previous test as script files (:return replaced by :finish).
-"-------------------------------------------------------------------------------
-
-XpathINIT
-
-let scriptC = MakeScript("C") " X: 1 + 4 + 8
-delfunction C
-
-XloopINIT! 16 16
-
-let scriptT1 = MakeScript("T1") " X: 16 + 64 + 16*16 + 64*16
-delfunction T1
-
-let scriptT2 = MakeScript("T2", scriptT1) " X: 4096 + 16384
-delfunction T2
-
-function! F()
- try
- Xpath 65536 " X: 65536
- exec "source" g:scriptC
- Xpath 131072 " X: 131072
- catch /.*/
- Xpath 262144 " X: 0
- Xout v:exception "in" v:throwpoint
- endtry
-
- try
- Xpath 524288 " X: 524288
- exec "source" g:scriptT1
- Xpath 1048576 " X: 0
- catch /arrgh/
- Xpath 2097152 " X: 2097152
- catch /.*/
- Xpath 4194304 " X: 0
- Xout v:exception "in" v:throwpoint
- endtry
-endfunction
-
-try
- Xpath 8388608 " X: 8388608
- call F()
- Xpath 16777216 " X: 16777216
- exec "source" scriptT2
- Xpath 33554432 " X: 0
-catch /arrgh/
- Xpath 67108864 " X: 67108864
-catch /.*/
- Xpath 134217728 " X: 0
- Xout v:exception "in" v:throwpoint
-endtry
-Xpath 268435456 " X: 268435456
-
-call delete(scriptC)
-call delete(scriptT1)
-call delete(scriptT2)
-unlet scriptC scriptT1 scriptT2
-delfunction F
-
-Xcheck 363550045
-
-" Test 51 was moved to test_trycatch.vim
-let Xtest = 52
-
-
-"-------------------------------------------------------------------------------
-" Test 52: Uncaught exceptions {{{1
-"
-" When an exception is thrown but not caught, an error message is
-" displayed when the script is terminated. In case of an interrupt
-" or error exception, the normal interrupt or error message(s) are
-" displayed.
-"-------------------------------------------------------------------------------
-
-XpathINIT
-
-let msgfile = tempname()
-
function! MESSAGES(...)
try
exec "edit" g:msgfile
@@ -2302,3627 +648,11 @@ function! MESSAGES(...)
return match
endfunction
-if ExtraVim(msgfile)
- Xpath 1 " X: 1
- throw "arrgh"
-endif
-
-Xpath 2 " X: 2
-if !MESSAGES('E605', "Exception not caught")
- Xpath 4 " X: 0
-endif
-
-if ExtraVim(msgfile)
- try
- Xpath 8 " X: 8
- throw "oops"
- catch /arrgh/
- Xpath 16 " X: 0
- endtry
- Xpath 32 " X: 0
-endif
-
-Xpath 64 " X: 64
-if !MESSAGES('E605', "Exception not caught")
- Xpath 128 " X: 0
-endif
-
-if ExtraVim(msgfile)
- function! T()
- throw "brrr"
- endfunction
-
- try
- Xpath 256 " X: 256
- throw "arrgh"
- catch /.*/
- Xpath 512 " X: 512
- call T()
- endtry
- Xpath 1024 " X: 0
-endif
-
-Xpath 2048 " X: 2048
-if !MESSAGES('E605', "Exception not caught")
- Xpath 4096 " X: 0
-endif
-
-if ExtraVim(msgfile)
- try
- Xpath 8192 " X: 8192
- throw "arrgh"
- finally
- Xpath 16384 " X: 16384
- throw "brrr"
- endtry
- Xpath 32768 " X: 0
-endif
-
-Xpath 65536 " X: 65536
-if !MESSAGES('E605', "Exception not caught")
- Xpath 131072 " X: 0
-endif
-
-if ExtraVim(msgfile)
- try
- Xpath 262144 " X: 262144
- "INTERRUPT
- endtry
- Xpath 524288 " X: 0
-endif
-
-Xpath 1048576 " X: 1048576
-if !MESSAGES('INT', "Interrupted")
- Xpath 2097152 " X: 0
-endif
-
-if ExtraVim(msgfile)
- try
- Xpath 4194304 " X: 4194304
- let x = novar " error E121/E15; exception: E121
- catch /E15:/ " should not catch
- Xpath 8388608 " X: 0
- endtry
- Xpath 16777216 " X: 0
-endif
-
-Xpath 33554432 " X: 33554432
-if !MESSAGES('E121', "Undefined variable", 'E15', "Invalid expression")
- Xpath 67108864 " X: 0
-endif
-
-if ExtraVim(msgfile)
- try
- Xpath 134217728 " X: 134217728
-" unlet novar # " error E108/E488; exception: E488
- catch /E108:/ " should not catch
- Xpath 268435456 " X: 0
- endtry
- Xpath 536870912 " X: 0
-endif
-
-Xpath 1073741824 " X: 1073741824
-if !MESSAGES('E108', "No such variable", 'E488', "Trailing characters")
- " The Xpath command does not accept 2^31 (negative); add explicitly:
- let Xpath = Xpath + 2147483648 " X: 0
-endif
-
-call delete(msgfile)
-unlet msgfile
-
-Xcheck 1247112011
-
-" Leave MESSAGES() for the next tests.
-
-
-"-------------------------------------------------------------------------------
-" Test 53: Nesting errors: :endif/:else/:elseif {{{1
-"
-" For nesting errors of :if conditionals the correct error messages
-" should be given.
-"
-" This test reuses the function MESSAGES() from the previous test.
-" This functions checks the messages in g:msgfile.
-"-------------------------------------------------------------------------------
-
-XpathINIT
-
-let msgfile = tempname()
-
-if ExtraVim(msgfile)
-" endif
-endif
-if MESSAGES('E580', ":endif without :if")
- Xpath 1 " X: 1
-endif
-
-if ExtraVim(msgfile)
-" while 1
-" endif
-" endwhile
-endif
-if MESSAGES('E580', ":endif without :if")
- Xpath 2 " X: 2
-endif
-
-if ExtraVim(msgfile)
-" try
-" finally
-" endif
-" endtry
-endif
-if MESSAGES('E580', ":endif without :if")
- Xpath 4 " X: 4
-endif
-
-if ExtraVim(msgfile)
-" try
-" endif
-" endtry
-endif
-if MESSAGES('E580', ":endif without :if")
- Xpath 8 " X: 8
-endif
-
-if ExtraVim(msgfile)
-" try
-" throw "a"
-" catch /a/
-" endif
-" endtry
-endif
-if MESSAGES('E580', ":endif without :if")
- Xpath 16 " X: 16
-endif
-
-if ExtraVim(msgfile)
-" else
-endif
-if MESSAGES('E581', ":else without :if")
- Xpath 32 " X: 32
-endif
-
-if ExtraVim(msgfile)
-" while 1
-" else
-" endwhile
-endif
-if MESSAGES('E581', ":else without :if")
- Xpath 64 " X: 64
-endif
-
-if ExtraVim(msgfile)
-" try
-" finally
-" else
-" endtry
-endif
-if MESSAGES('E581', ":else without :if")
- Xpath 128 " X: 128
-endif
-
-if ExtraVim(msgfile)
-" try
-" else
-" endtry
-endif
-if MESSAGES('E581', ":else without :if")
- Xpath 256 " X: 256
-endif
-
-if ExtraVim(msgfile)
-" try
-" throw "a"
-" catch /a/
-" else
-" endtry
-endif
-if MESSAGES('E581', ":else without :if")
- Xpath 512 " X: 512
-endif
-
-if ExtraVim(msgfile)
-" elseif
-endif
-if MESSAGES('E582', ":elseif without :if")
- Xpath 1024 " X: 1024
-endif
-
-if ExtraVim(msgfile)
-" while 1
-" elseif
-" endwhile
-endif
-if MESSAGES('E582', ":elseif without :if")
- Xpath 2048 " X: 2048
-endif
-
-if ExtraVim(msgfile)
-" try
-" finally
-" elseif
-" endtry
-endif
-if MESSAGES('E582', ":elseif without :if")
- Xpath 4096 " X: 4096
-endif
-
-if ExtraVim(msgfile)
-" try
-" elseif
-" endtry
-endif
-if MESSAGES('E582', ":elseif without :if")
- Xpath 8192 " X: 8192
-endif
-
-if ExtraVim(msgfile)
-" try
-" throw "a"
-" catch /a/
-" elseif
-" endtry
-endif
-if MESSAGES('E582', ":elseif without :if")
- Xpath 16384 " X: 16384
-endif
-
-if ExtraVim(msgfile)
-" if 1
-" else
-" else
-" endif
-endif
-if MESSAGES('E583', "multiple :else")
- Xpath 32768 " X: 32768
-endif
-
-if ExtraVim(msgfile)
-" if 1
-" else
-" elseif 1
-" endif
-endif
-if MESSAGES('E584', ":elseif after :else")
- Xpath 65536 " X: 65536
-endif
-
-call delete(msgfile)
-unlet msgfile
-
-Xcheck 131071
-
-" Leave MESSAGES() for the next test.
-
-
-"-------------------------------------------------------------------------------
-" Test 54: Nesting errors: :while/:endwhile {{{1
-"
-" For nesting errors of :while conditionals the correct error messages
-" should be given.
-"
-" This test reuses the function MESSAGES() from the previous test.
-" This functions checks the messages in g:msgfile.
-"-------------------------------------------------------------------------------
-
-XpathINIT
-
-let msgfile = tempname()
-
-if ExtraVim(msgfile)
-" endwhile
-endif
-if MESSAGES('E588', ":endwhile without :while")
- Xpath 1 " X: 1
-endif
-
-if ExtraVim(msgfile)
-" if 1
-" endwhile
-" endif
-endif
-if MESSAGES('E588', ":endwhile without :while")
- Xpath 2 " X: 2
-endif
-
-if ExtraVim(msgfile)
-" while 1
-" if 1
-" endwhile
-endif
-if MESSAGES('E171', "Missing :endif")
- Xpath 4 " X: 4
-endif
-
-if ExtraVim(msgfile)
-" try
-" finally
-" endwhile
-" endtry
-endif
-if MESSAGES('E588', ":endwhile without :while")
- Xpath 8 " X: 8
-endif
-
-if ExtraVim(msgfile)
-" while 1
-" try
-" finally
-" endwhile
-endif
-if MESSAGES('E600', "Missing :endtry")
- Xpath 16 " X: 16
-endif
-
-if ExtraVim(msgfile)
-" while 1
-" if 1
-" try
-" finally
-" endwhile
-endif
-if MESSAGES('E600', "Missing :endtry")
- Xpath 32 " X: 32
-endif
-
-if ExtraVim(msgfile)
-" while 1
-" try
-" finally
-" if 1
-" endwhile
-endif
-if MESSAGES('E171', "Missing :endif")
- Xpath 64 " X: 64
-endif
-
-if ExtraVim(msgfile)
-" try
-" endwhile
-" endtry
-endif
-if MESSAGES('E588', ":endwhile without :while")
- Xpath 128 " X: 128
-endif
-
-if ExtraVim(msgfile)
-" while 1
-" try
-" endwhile
-" endtry
-" endwhile
-endif
-if MESSAGES('E588', ":endwhile without :while")
- Xpath 256 " X: 256
-endif
-
-if ExtraVim(msgfile)
-" try
-" throw "a"
-" catch /a/
-" endwhile
-" endtry
-endif
-if MESSAGES('E588', ":endwhile without :while")
- Xpath 512 " X: 512
-endif
-
-if ExtraVim(msgfile)
-" while 1
-" try
-" throw "a"
-" catch /a/
-" endwhile
-" endtry
-" endwhile
-endif
-if MESSAGES('E588', ":endwhile without :while")
- Xpath 1024 " X: 1024
-endif
-
-
-call delete(msgfile)
-unlet msgfile
-
-Xcheck 2047
-
-" Leave MESSAGES() for the next test.
-
-
-"-------------------------------------------------------------------------------
-" Test 55: Nesting errors: :continue/:break {{{1
-"
-" For nesting errors of :continue and :break commands the correct
-" error messages should be given.
-"
-" This test reuses the function MESSAGES() from the previous test.
-" This functions checks the messages in g:msgfile.
-"-------------------------------------------------------------------------------
-
-XpathINIT
-
-let msgfile = tempname()
-
-if ExtraVim(msgfile)
-" continue
-endif
-if MESSAGES('E586', ":continue without :while")
- Xpath 1 " X: 1
-endif
-
-if ExtraVim(msgfile)
-" if 1
-" continue
-" endif
-endif
-if MESSAGES('E586', ":continue without :while")
- Xpath 2 " X: 2
-endif
-
-if ExtraVim(msgfile)
-" try
-" finally
-" continue
-" endtry
-endif
-if MESSAGES('E586', ":continue without :while")
- Xpath 4 " X: 4
-endif
-
-if ExtraVim(msgfile)
-" try
-" continue
-" endtry
-endif
-if MESSAGES('E586', ":continue without :while")
- Xpath 8 " X: 8
-endif
-
-if ExtraVim(msgfile)
-" try
-" throw "a"
-" catch /a/
-" continue
-" endtry
-endif
-if MESSAGES('E586', ":continue without :while")
- Xpath 16 " X: 16
-endif
-
-if ExtraVim(msgfile)
-" break
-endif
-if MESSAGES('E587', ":break without :while")
- Xpath 32 " X: 32
-endif
-
-if ExtraVim(msgfile)
-" if 1
-" break
-" endif
-endif
-if MESSAGES('E587', ":break without :while")
- Xpath 64 " X: 64
-endif
-
-if ExtraVim(msgfile)
-" try
-" finally
-" break
-" endtry
-endif
-if MESSAGES('E587', ":break without :while")
- Xpath 128 " X: 128
-endif
-
-if ExtraVim(msgfile)
-" try
-" break
-" endtry
-endif
-if MESSAGES('E587', ":break without :while")
- Xpath 256 " X: 256
-endif
-
-if ExtraVim(msgfile)
-" try
-" throw "a"
-" catch /a/
-" break
-" endtry
-endif
-if MESSAGES('E587', ":break without :while")
- Xpath 512 " X: 512
-endif
-
-call delete(msgfile)
-unlet msgfile
-
-Xcheck 1023
-
-" Leave MESSAGES() for the next test.
-
-
-"-------------------------------------------------------------------------------
-" Test 56: Nesting errors: :endtry {{{1
-"
-" For nesting errors of :try conditionals the correct error messages
-" should be given.
-"
-" This test reuses the function MESSAGES() from the previous test.
-" This functions checks the messages in g:msgfile.
-"-------------------------------------------------------------------------------
-
-XpathINIT
-
-let msgfile = tempname()
-
-if ExtraVim(msgfile)
-" endtry
-endif
-if MESSAGES('E602', ":endtry without :try")
- Xpath 1 " X: 1
-endif
-
-if ExtraVim(msgfile)
-" if 1
-" endtry
-" endif
-endif
-if MESSAGES('E602', ":endtry without :try")
- Xpath 2 " X: 2
-endif
-
-if ExtraVim(msgfile)
-" while 1
-" endtry
-" endwhile
-endif
-if MESSAGES('E602', ":endtry without :try")
- Xpath 4 " X: 4
-endif
-
-if ExtraVim(msgfile)
-" try
-" if 1
-" endtry
-endif
-if MESSAGES('E171', "Missing :endif")
- Xpath 8 " X: 8
-endif
-
-if ExtraVim(msgfile)
-" try
-" while 1
-" endtry
-endif
-if MESSAGES('E170', "Missing :endwhile")
- Xpath 16 " X: 16
-endif
-
-if ExtraVim(msgfile)
-" try
-" finally
-" if 1
-" endtry
-endif
-if MESSAGES('E171', "Missing :endif")
- Xpath 32 " X: 32
-endif
-
-if ExtraVim(msgfile)
-" try
-" finally
-" while 1
-" endtry
-endif
-if MESSAGES('E170', "Missing :endwhile")
- Xpath 64 " X: 64
-endif
-
-if ExtraVim(msgfile)
- try
- Xpath 4194304 " X: 4194304
- let x = novar " error E121; exception: E121
- catch /E15:/ " should not catch
- Xpath 8388608 " X: 0
- endtry
- Xpath 16777216 " X: 0
-endif
-
-Xpath 33554432 " X: 33554432
-if !MESSAGES('E121', "Undefined variable")
- Xpath 67108864 " X: 0
-endif
-
-if ExtraVim(msgfile)
-" try
-" throw "a"
-" catch /a/
-" while 1
-" endtry
-endif
-if MESSAGES('E170', "Missing :endwhile")
- Xpath 256 " X: 256
-endif
-
-call delete(msgfile)
-unlet msgfile
-
-delfunction MESSAGES
-
-Xcheck 511
-
-
-"-------------------------------------------------------------------------------
-" Test 57: v:exception and v:throwpoint for user exceptions {{{1
-"
-" v:exception evaluates to the value of the exception that was caught
-" most recently and is not finished. (A caught exception is finished
-" when the next ":catch", ":finally", or ":endtry" is reached.)
-" v:throwpoint evaluates to the script/function name and line number
-" where that exception has been thrown.
-"-------------------------------------------------------------------------------
-
-XpathINIT
-
-function! FuncException()
- let g:exception = v:exception
-endfunction
-
-function! FuncThrowpoint()
- let g:throwpoint = v:throwpoint
-endfunction
-
-let scriptException = MakeScript("FuncException")
-let scriptThrowPoint = MakeScript("FuncThrowpoint")
-
-command! CmdException let g:exception = v:exception
-command! CmdThrowpoint let g:throwpoint = v:throwpoint
-
-XloopINIT! 1 2
-
-function! CHECK(n, exception, throwname, throwline)
- XloopNEXT
- let error = 0
- if v:exception != a:exception
- Xout a:n.": v:exception is" v:exception "instead of" a:exception
- let error = 1
- endif
- if v:throwpoint !~ a:throwname
- let name = escape(a:throwname, '\')
- Xout a:n.": v:throwpoint (".v:throwpoint.") does not match" name
- let error = 1
- endif
- if v:throwpoint !~ a:throwline
- let line = escape(a:throwline, '\')
- Xout a:n.": v:throwpoint (".v:throwpoint.") does not match" line
- let error = 1
- endif
- if error
- Xloop 1 " X: 0
- endif
-endfunction
-
-function! T(arg, line)
- if a:line == 2
- throw a:arg " in line 2
- elseif a:line == 4
- throw a:arg " in line 4
- elseif a:line == 6
- throw a:arg " in line 6
- elseif a:line == 8
- throw a:arg " in line 8
- endif
-endfunction
-
-function! G(arg, line)
- call T(a:arg, a:line)
-endfunction
-
-function! F(arg, line)
- call G(a:arg, a:line)
-endfunction
-
-let scriptT = MakeScript("T")
-let scriptG = MakeScript("G", scriptT)
-let scriptF = MakeScript("F", scriptG)
-
-try
- Xpath 32768 " X: 32768
- call F("oops", 2)
-catch /.*/
- Xpath 65536 " X: 65536
- let exception = v:exception
- let throwpoint = v:throwpoint
- call CHECK(1, "oops", '\<F\[1]\.\.G\[1]\.\.T\>', '\<2\>')
- exec "let exception = v:exception"
- exec "let throwpoint = v:throwpoint"
- call CHECK(2, "oops", '\<F\[1]\.\.G\[1]\.\.T\>', '\<2\>')
- CmdException
- CmdThrowpoint
- call CHECK(3, "oops", '\<F\[1]\.\.G\[1]\.\.T\>', '\<2\>')
- call FuncException()
- call FuncThrowpoint()
- call CHECK(4, "oops", '\<F\[1]\.\.G\[1]\.\.T\>', '\<2\>')
- exec "source" scriptException
- exec "source" scriptThrowPoint
- call CHECK(5, "oops", '\<F\[1]\.\.G\[1]\.\.T\>', '\<2\>')
- try
- Xpath 131072 " X: 131072
- call G("arrgh", 4)
- catch /.*/
- Xpath 262144 " X: 262144
- let exception = v:exception
- let throwpoint = v:throwpoint
- call CHECK(6, "arrgh", '\<G\[1]\.\.T\>', '\<4\>')
- try
- Xpath 524288 " X: 524288
- let g:arg = "autsch"
- let g:line = 6
- exec "source" scriptF
- catch /.*/
- Xpath 1048576 " X: 1048576
- let exception = v:exception
- let throwpoint = v:throwpoint
- " Symbolic links in tempname()s are not resolved, whereas resolving
- " is done for v:throwpoint. Resolve the temporary file name for
- " scriptT, so that it can be matched against v:throwpoint.
- call CHECK(7, "autsch", resolve(scriptT), '\<6\>')
- finally
- Xpath 2097152 " X: 2097152
- let exception = v:exception
- let throwpoint = v:throwpoint
- call CHECK(8, "arrgh", '\<G\[1]\.\.T\>', '\<4\>')
- try
- Xpath 4194304 " X: 4194304
- let g:arg = "brrrr"
- let g:line = 8
- exec "source" scriptG
- catch /.*/
- Xpath 8388608 " X: 8388608
- let exception = v:exception
- let throwpoint = v:throwpoint
- " Resolve scriptT for matching it against v:throwpoint.
- call CHECK(9, "brrrr", resolve(scriptT), '\<8\>')
- finally
- Xpath 16777216 " X: 16777216
- let exception = v:exception
- let throwpoint = v:throwpoint
- call CHECK(10, "arrgh", '\<G\[1]\.\.T\>', '\<4\>')
- endtry
- Xpath 33554432 " X: 33554432
- let exception = v:exception
- let throwpoint = v:throwpoint
- call CHECK(11, "arrgh", '\<G\[1]\.\.T\>', '\<4\>')
- endtry
- Xpath 67108864 " X: 67108864
- let exception = v:exception
- let throwpoint = v:throwpoint
- call CHECK(12, "arrgh", '\<G\[1]\.\.T\>', '\<4\>')
- finally
- Xpath 134217728 " X: 134217728
- let exception = v:exception
- let throwpoint = v:throwpoint
- call CHECK(13, "oops", '\<F\[1]\.\.G\[1]\.\.T\>', '\<2\>')
- endtry
- Xpath 268435456 " X: 268435456
- let exception = v:exception
- let throwpoint = v:throwpoint
- call CHECK(14, "oops", '\<F\[1]\.\.G\[1]\.\.T\>', '\<2\>')
-finally
- Xpath 536870912 " X: 536870912
- let exception = v:exception
- let throwpoint = v:throwpoint
- call CHECK(15, "", '^$', '^$')
-endtry
-
-Xpath 1073741824 " X: 1073741824
-
-unlet exception throwpoint
-delfunction FuncException
-delfunction FuncThrowpoint
-call delete(scriptException)
-call delete(scriptThrowPoint)
-unlet scriptException scriptThrowPoint
-delcommand CmdException
-delcommand CmdThrowpoint
-delfunction T
-delfunction G
-delfunction F
-call delete(scriptT)
-call delete(scriptG)
-call delete(scriptF)
-unlet scriptT scriptG scriptF
-
-Xcheck 2147450880
-
-
-"-------------------------------------------------------------------------------
-"
-" Test 58: v:exception and v:throwpoint for error/interrupt exceptions {{{1
-"
-" v:exception and v:throwpoint work also for error and interrupt
-" exceptions.
-"-------------------------------------------------------------------------------
-
-XpathINIT
-
-if ExtraVim()
-
- function! T(line)
- if a:line == 2
- delfunction T " error (function in use) in line 2
- elseif a:line == 4
- let dummy = 0 " INTERRUPT1 - interrupt in line 4
- endif
- endfunction
-
- while 1
- try
- Xpath 1 " X: 1
- let caught = 0
- call T(2)
- catch /.*/
- let caught = 1
- if v:exception !~ 'Vim(delfunction):'
- Xpath 2 " X: 0
- endif
- if v:throwpoint !~ '\<T\>'
- Xpath 4 " X: 0
- endif
- if v:throwpoint !~ '\<2\>'
- Xpath 8 " X: 0
- endif
- finally
- Xpath 16 " X: 16
- if caught || $VIMNOERRTHROW
- Xpath 32 " X: 32
- endif
- if v:exception != ""
- Xpath 64 " X: 0
- endif
- if v:throwpoint != ""
- Xpath 128 " X: 0
- endif
- break " discard error for $VIMNOERRTHROW
- endtry
- endwhile
-
- Xpath 256 " X: 256
- if v:exception != ""
- Xpath 512 " X: 0
- endif
- if v:throwpoint != ""
- Xpath 1024 " X: 0
- endif
-
- while 1
- try
- Xpath 2048 " X: 2048
- let caught = 0
- call T(4)
- catch /.*/
- let caught = 1
- if v:exception != 'Vim:Interrupt'
- Xpath 4096 " X: 0
- endif
- if v:throwpoint !~ '\<T\>'
- Xpath 8192 " X: 0
- endif
- if v:throwpoint !~ '\<4\>'
- Xpath 16384 " X: 0
- endif
- finally
- Xpath 32768 " X: 32768
- if caught || $VIMNOINTTHROW
- Xpath 65536 " X: 65536
- endif
- if v:exception != ""
- Xpath 131072 " X: 0
- endif
- if v:throwpoint != ""
- Xpath 262144 " X: 0
- endif
- break " discard error for $VIMNOERRTHROW
- endtry
- endwhile
-
- Xpath 524288 " X: 524288
- if v:exception != ""
- Xpath 1048576 " X: 0
- endif
- if v:throwpoint != ""
- Xpath 2097152 " X: 0
- endif
-
-endif
-
-Xcheck 624945
-
-
-"-------------------------------------------------------------------------------
-"
-" Test 59: v:exception and v:throwpoint when discarding exceptions {{{1
-"
-" When a :catch clause is left by a ":break" etc or an error or
-" interrupt exception, v:exception and v:throwpoint are reset. They
-" are not affected by an exception that is discarded before being
-" caught.
-"-------------------------------------------------------------------------------
-
-XpathINIT
-
-if ExtraVim()
-
- XloopINIT! 1 2
-
- let sfile = expand("<sfile>")
-
- function! LineNumber()
- return substitute(substitute(v:throwpoint, g:sfile, '', ""),
- \ '\D*\(\d*\).*', '\1', "")
- endfunction
-
- command! -nargs=1 SetLineNumber
- \ try | throw "line" | catch /.*/ | let <args> = LineNumber() | endtry
-
- " Check v:exception/v:throwpoint against second/fourth parameter if
- " specified, check for being empty else.
- function! CHECK(n, ...)
- XloopNEXT
- let exception = a:0 != 0 ? a:1 : "" " second parameter (optional)
- let emsg = a:0 != 0 ? a:2 : "" " third parameter (optional)
- let line = a:0 != 0 ? a:3 : 0 " fourth parameter (optional)
- let error = 0
- if emsg != ""
- " exception is the error number, emsg the English error message text
- if exception !~ '^E\d\+$'
- Xout "TODO: Add message number for:" emsg
- elseif v:lang == "C" || v:lang =~ '^[Ee]n'
- if exception == "E492" && emsg == "Not an editor command"
- let exception = '^Vim:' . exception . ': ' . emsg
- else
- let exception = '^Vim(\a\+):' . exception . ': ' . emsg
- endif
- else
- if exception == "E492"
- let exception = '^Vim:' . exception
- else
- let exception = '^Vim(\a\+):' . exception
- endif
- endif
- endif
- if exception == "" && v:exception != ""
- Xout a:n.": v:exception is set:" v:exception
- let error = 1
- elseif exception != "" && v:exception !~ exception
- Xout a:n.": v:exception (".v:exception.") does not match" exception
- let error = 1
- endif
- if line == 0 && v:throwpoint != ""
- Xout a:n.": v:throwpoint is set:" v:throwpoint
- let error = 1
- elseif line != 0 && v:throwpoint !~ '\<' . line . '\>'
- Xout a:n.": v:throwpoint (".v:throwpoint.") does not match" line
- let error = 1
- endif
- if !error
- Xloop 1 " X: 2097151
- endif
- endfunction
-
- while 1
- try
- throw "x1"
- catch /.*/
- break
- endtry
- endwhile
- call CHECK(1)
-
- while 1
- try
- throw "x2"
- catch /.*/
- break
- finally
- call CHECK(2)
- endtry
- break
- endwhile
- call CHECK(3)
-
- while 1
- try
- let errcaught = 0
- try
- try
- throw "x3"
- catch /.*/
- SetLineNumber line_before_error
- asdf
- endtry
- catch /.*/
- let errcaught = 1
- call CHECK(4, 'E492', "Not an editor command",
- \ line_before_error + 1)
- endtry
- finally
- if !errcaught && $VIMNOERRTHROW
- call CHECK(4)
- endif
- break " discard error for $VIMNOERRTHROW
- endtry
- endwhile
- call CHECK(5)
-
- Xpath 2097152 " X: 2097152
-
- while 1
- try
- let intcaught = 0
- try
- try
- throw "x4"
- catch /.*/
- SetLineNumber two_lines_before_interrupt
- "INTERRUPT
- let dummy = 0
- endtry
- catch /.*/
- let intcaught = 1
- call CHECK(6, "Vim:Interrupt", '',
- \ two_lines_before_interrupt + 2)
- endtry
- finally
- if !intcaught && $VIMNOINTTHROW
- call CHECK(6)
- endif
- break " discard interrupt for $VIMNOINTTHROW
- endtry
- endwhile
- call CHECK(7)
-
- Xpath 4194304 " X: 4194304
-
- while 1
- try
- let errcaught = 0
- try
- try
-" if 1
- SetLineNumber line_before_throw
- throw "x5"
- " missing endif
- catch /.*/
- Xpath 8388608 " X: 0
- endtry
- catch /.*/
- let errcaught = 1
- call CHECK(8, 'E171', "Missing :endif", line_before_throw + 3)
- endtry
- finally
- if !errcaught && $VIMNOERRTHROW
- call CHECK(8)
- endif
- break " discard error for $VIMNOERRTHROW
- endtry
- endwhile
- call CHECK(9)
-
- Xpath 16777216 " X: 16777216
-
- try
- while 1
- try
- throw "x6"
- finally
- break
- endtry
- break
- endwhile
- catch /.*/
- Xpath 33554432 " X: 0
- endtry
- call CHECK(10)
-
- try
- while 1
- try
- throw "x7"
- finally
- break
- endtry
- break
- endwhile
- catch /.*/
- Xpath 67108864 " X: 0
- finally
- call CHECK(11)
- endtry
- call CHECK(12)
-
- while 1
- try
- let errcaught = 0
- try
- try
- throw "x8"
- finally
- SetLineNumber line_before_error
- asdf
- endtry
- catch /.*/
- let errcaught = 1
- call CHECK(13, 'E492', "Not an editor command",
- \ line_before_error + 1)
- endtry
- finally
- if !errcaught && $VIMNOERRTHROW
- call CHECK(13)
- endif
- break " discard error for $VIMNOERRTHROW
- endtry
- endwhile
- call CHECK(14)
-
- Xpath 134217728 " X: 134217728
-
- while 1
- try
- let intcaught = 0
- try
- try
- throw "x9"
- finally
- SetLineNumber two_lines_before_interrupt
- "INTERRUPT
- endtry
- catch /.*/
- let intcaught = 1
- call CHECK(15, "Vim:Interrupt", '',
- \ two_lines_before_interrupt + 2)
- endtry
- finally
- if !intcaught && $VIMNOINTTHROW
- call CHECK(15)
- endif
- break " discard interrupt for $VIMNOINTTHROW
- endtry
- endwhile
- call CHECK(16)
-
- Xpath 268435456 " X: 268435456
-
- while 1
- try
- let errcaught = 0
- try
- try
-" if 1
- SetLineNumber line_before_throw
- throw "x10"
- " missing endif
- finally
- call CHECK(17)
- endtry
- catch /.*/
- let errcaught = 1
- call CHECK(18, 'E171', "Missing :endif", line_before_throw + 3)
- endtry
- finally
- if !errcaught && $VIMNOERRTHROW
- call CHECK(18)
- endif
- break " discard error for $VIMNOERRTHROW
- endtry
- endwhile
- call CHECK(19)
-
- Xpath 536870912 " X: 536870912
-
- while 1
- try
- let errcaught = 0
- try
- try
-" if 1
- SetLineNumber line_before_throw
- throw "x11"
- " missing endif
- endtry
- catch /.*/
- let errcaught = 1
- call CHECK(20, 'E171', "Missing :endif", line_before_throw + 3)
- endtry
- finally
- if !errcaught && $VIMNOERRTHROW
- call CHECK(20)
- endif
- break " discard error for $VIMNOERRTHROW
- endtry
- endwhile
- call CHECK(21)
-
- Xpath 1073741824 " X: 1073741824
-
-endif
-
-Xcheck 2038431743
-
-
-"-------------------------------------------------------------------------------
-"
-" Test 60: (Re)throwing v:exception; :echoerr. {{{1
-"
-" A user exception can be rethrown after catching by throwing
-" v:exception. An error or interrupt exception cannot be rethrown
-" because Vim exceptions cannot be faked. A Vim exception using the
-" value of v:exception can, however, be triggered by the :echoerr
-" command.
-"-------------------------------------------------------------------------------
-
-XpathINIT
-
-try
- try
- Xpath 1 " X: 1
- throw "oops"
- catch /oops/
- Xpath 2 " X: 2
- throw v:exception " rethrow user exception
- catch /.*/
- Xpath 4 " X: 0
- endtry
-catch /^oops$/ " catches rethrown user exception
- Xpath 8 " X: 8
-catch /.*/
- Xpath 16 " X: 0
-endtry
-
-function! F()
- try
- let caught = 0
- try
- Xpath 32 " X: 32
- write /n/o/n/w/r/i/t/a/b/l/e/_/f/i/l/e
- Xpath 64 " X: 0
- Xout "did_emsg was reset before executing " .
- \ "BufWritePost autocommands."
- catch /^Vim(write):/
- let caught = 1
- throw v:exception " throw error: cannot fake Vim exception
- catch /.*/
- Xpath 128 " X: 0
- finally
- Xpath 256 " X: 256
- if !caught && !$VIMNOERRTHROW
- Xpath 512 " X: 0
- endif
- endtry
- catch /^Vim(throw):/ " catches throw error
- let caught = caught + 1
- catch /.*/
- Xpath 1024 " X: 0
- finally
- Xpath 2048 " X: 2048
- if caught != 2
- if !caught && !$VIMNOERRTHROW
- Xpath 4096 " X: 0
- elseif caught
- Xpath 8192 " X: 0
- endif
- return | " discard error for $VIMNOERRTHROW
- endif
- endtry
-endfunction
-
-call F()
-delfunction F
-
-function! G()
- try
- let caught = 0
- try
- Xpath 16384 " X: 16384
- asdf
- catch /^Vim/ " catch error exception
- let caught = 1
- " Trigger Vim error exception with value specified after :echoerr
- let value = substitute(v:exception, '^Vim\((.*)\)\=:', '', "")
- echoerr value
- catch /.*/
- Xpath 32768 " X: 0
- finally
- Xpath 65536 " X: 65536
- if !caught
- if !$VIMNOERRTHROW
- Xpath 131072 " X: 0
- else
- let value = "Error"
- echoerr value
- endif
- endif
- endtry
- catch /^Vim(echoerr):/
- let caught = caught + 1
- if v:exception !~ value
- Xpath 262144 " X: 0
- endif
- catch /.*/
- Xpath 524288 " X: 0
- finally
- Xpath 1048576 " X: 1048576
- if caught != 2
- if !caught && !$VIMNOERRTHROW
- Xpath 2097152 " X: 0
- elseif caught
- Xpath 4194304 " X: 0
- endif
- return | " discard error for $VIMNOERRTHROW
- endif
- endtry
-endfunction
-
-call G()
-delfunction G
-
-unlet! value caught
-
-if ExtraVim()
- try
- let errcaught = 0
- try
- Xpath 8388608 " X: 8388608
- let intcaught = 0
- "INTERRUPT
- catch /^Vim:/ " catch interrupt exception
- let intcaught = 1
- " Trigger Vim error exception with value specified after :echoerr
- echoerr substitute(v:exception, '^Vim\((.*)\)\=:', '', "")
- catch /.*/
- Xpath 16777216 " X: 0
- finally
- Xpath 33554432 " X: 33554432
- if !intcaught
- if !$VIMNOINTTHROW
- Xpath 67108864 " X: 0
- else
- echoerr "Interrupt"
- endif
- endif
- endtry
- catch /^Vim(echoerr):/
- let errcaught = 1
- if v:exception !~ "Interrupt"
- Xpath 134217728 " X: 0
- endif
- finally
- Xpath 268435456 " X: 268435456
- if !errcaught && !$VIMNOERRTHROW
- Xpath 536870912 " X: 0
- endif
- endtry
-endif
-
-Xcheck 311511339
-
-
-"-------------------------------------------------------------------------------
-" Test 61: Catching interrupt exceptions {{{1
-"
-" When an interrupt occurs inside a :try/:endtry region, an
-" interrupt exception is thrown and can be caught. Its value is
-" "Vim:Interrupt". If the interrupt occurs after an error or a :throw
-" but before a matching :catch is reached, all following :catches of
-" that try block are ignored, but the interrupt exception can be
-" caught by the next surrounding try conditional. An interrupt is
-" ignored when there is a previous interrupt that has not been caught
-" or causes a :finally clause to be executed.
-"-------------------------------------------------------------------------------
-
-XpathINIT
-
-if ExtraVim()
-
- while 1
- try
- try
- Xpath 1 " X: 1
- let caught = 0
- "INTERRUPT
- Xpath 2 " X: 0
- catch /^Vim:Interrupt$/
- let caught = 1
- finally
- Xpath 4 " X: 4
- if caught || $VIMNOINTTHROW
- Xpath 8 " X: 8
- endif
- endtry
- catch /.*/
- Xpath 16 " X: 0
- Xout v:exception "in" v:throwpoint
- finally
- break " discard interrupt for $VIMNOINTTHROW
- endtry
- endwhile
-
- while 1
- try
- try
- let caught = 0
- try
- Xpath 32 " X: 32
- asdf
- Xpath 64 " X: 0
- catch /do_not_catch/
- Xpath 128 " X: 0
- catch /.*/ "INTERRUPT - throw interrupt if !$VIMNOERRTHROW
- Xpath 256 " X: 0
- catch /.*/
- Xpath 512 " X: 0
- finally "INTERRUPT - throw interrupt if $VIMNOERRTHROW
- Xpath 1024 " X: 1024
- endtry
- catch /^Vim:Interrupt$/
- let caught = 1
- finally
- Xpath 2048 " X: 2048
- if caught || $VIMNOINTTHROW
- Xpath 4096 " X: 4096
- endif
- endtry
- catch /.*/
- Xpath 8192 " X: 0
- Xout v:exception "in" v:throwpoint
- finally
- break " discard interrupt for $VIMNOINTTHROW
- endtry
- endwhile
-
- while 1
- try
- try
- let caught = 0
- try
- Xpath 16384 " X: 16384
- throw "x"
- Xpath 32768 " X: 0
- catch /do_not_catch/
- Xpath 65536 " X: 0
- catch /x/ "INTERRUPT
- Xpath 131072 " X: 0
- catch /.*/
- Xpath 262144 " X: 0
- endtry
- catch /^Vim:Interrupt$/
- let caught = 1
- finally
- Xpath 524288 " X: 524288
- if caught || $VIMNOINTTHROW
- Xpath 1048576 " X: 1048576
- endif
- endtry
- catch /.*/
- Xpath 2097152 " X: 0
- Xout v:exception "in" v:throwpoint
- finally
- break " discard interrupt for $VIMNOINTTHROW
- endtry
- endwhile
-
- while 1
- try
- let caught = 0
- try
- Xpath 4194304 " X: 4194304
- "INTERRUPT
- Xpath 8388608 " X: 0
- catch /do_not_catch/ "INTERRUPT
- Xpath 16777216 " X: 0
- catch /^Vim:Interrupt$/
- let caught = 1
- finally
- Xpath 33554432 " X: 33554432
- if caught || $VIMNOINTTHROW
- Xpath 67108864 " X: 67108864
- endif
- endtry
- catch /.*/
- Xpath 134217728 " X: 0
- Xout v:exception "in" v:throwpoint
- finally
- break " discard interrupt for $VIMNOINTTHROW
- endtry
- endwhile
-
- Xpath 268435456 " X: 268435456
-
-endif
-
-Xcheck 374889517
-
-
-"-------------------------------------------------------------------------------
-" Test 62: Catching error exceptions {{{1
-"
-" An error inside a :try/:endtry region is converted to an exception
-" and can be caught. The error exception has a "Vim(cmdname):" prefix
-" where cmdname is the name of the failing command, or a "Vim:" prefix
-" if no command name is known. The "Vim" prefixes cannot be faked.
-"-------------------------------------------------------------------------------
-
-XpathINIT
-
-function! MSG(enr, emsg)
- let english = v:lang == "C" || v:lang =~ '^[Ee]n'
- if a:enr == ""
- Xout "TODO: Add message number for:" a:emsg
- let v:errmsg = ":" . v:errmsg
- endif
- let match = 1
- if v:errmsg !~ '^'.a:enr.':' || (english && v:errmsg !~ a:emsg)
- let match = 0
- if v:errmsg == ""
- Xout "Message missing."
- else
- let v:errmsg = escape(v:errmsg, '"')
- Xout "Unexpected message:" v:errmsg
- endif
- endif
- return match
-endfunction
-
-while 1
- try
- try
- let caught = 0
- unlet novar
- catch /^Vim(unlet):/
- let caught = 1
- let v:errmsg = substitute(v:exception, '^Vim(unlet):', '', "")
- finally
- Xpath 1 " X: 1
- if !caught && !$VIMNOERRTHROW
- Xpath 2 " X: 0
- endif
- if !MSG('E108', "No such variable")
- Xpath 4 " X: 0
- endif
- endtry
- catch /.*/
- Xpath 8 " X: 0
- Xout v:exception "in" v:throwpoint
- finally
- break " discard error for $VIMNOERRTHROW
- endtry
-endwhile
-
-while 1
- try
- try
- let caught = 0
- throw novar " error in :throw
- catch /^Vim(throw):/
- let caught = 1
- let v:errmsg = substitute(v:exception, '^Vim(throw):', '', "")
- finally
- Xpath 16 " X: 16
- if !caught && !$VIMNOERRTHROW
- Xpath 32 " X: 0
- endif
- if caught ? !MSG('E121', "Undefined variable")
- \ : !MSG('E15', "Invalid expression")
- Xpath 64 " X: 0
- endif
- endtry
- catch /.*/
- Xpath 128 " X: 0
- Xout v:exception "in" v:throwpoint
- finally
- break " discard error for $VIMNOERRTHROW
- endtry
-endwhile
-
-while 1
- try
- try
- let caught = 0
- throw "Vim:faked" " error: cannot fake Vim exception
- catch /^Vim(throw):/
- let caught = 1
- let v:errmsg = substitute(v:exception, '^Vim(throw):', '', "")
- finally
- Xpath 256 " X: 256
- if !caught && !$VIMNOERRTHROW
- Xpath 512 " X: 0
- endif
- if !MSG('E608', "Cannot :throw exceptions with 'Vim' prefix")
- Xpath 1024 " X: 0
- endif
- endtry
- catch /.*/
- Xpath 2048 " X: 0
- Xout v:exception "in" v:throwpoint
- finally
- break " discard error for $VIMNOERRTHROW
- endtry
-endwhile
-
-function! F()
- while 1
- " Missing :endwhile
-endfunction
-
-while 1
- try
- try
- let caught = 0
- call F()
- catch /^Vim(endfunction):/
- let caught = 1
- let v:errmsg = substitute(v:exception, '^Vim(endfunction):', '', "")
- finally
- Xpath 4096 " X: 4096
- if !caught && !$VIMNOERRTHROW
- Xpath 8192 " X: 0
- endif
- if !MSG('E170', "Missing :endwhile")
- Xpath 16384 " X: 0
- endif
- endtry
- catch /.*/
- Xpath 32768 " X: 0
- Xout v:exception "in" v:throwpoint
- finally
- break " discard error for $VIMNOERRTHROW
- endtry
-endwhile
-
-while 1
- try
- try
- let caught = 0
- ExecAsScript F
- catch /^Vim:/
- let caught = 1
- let v:errmsg = substitute(v:exception, '^Vim:', '', "")
- finally
- Xpath 65536 " X: 65536
- if !caught && !$VIMNOERRTHROW
- Xpath 131072 " X: 0
- endif
- if !MSG('E170', "Missing :endwhile")
- Xpath 262144 " X: 0
- endif
- endtry
- catch /.*/
- Xpath 524288 " X: 0
- Xout v:exception "in" v:throwpoint
- finally
- break " discard error for $VIMNOERRTHROW
- endtry
-endwhile
-
-function! G()
- call G()
-endfunction
-
-while 1
- try
- let mfd_save = &mfd
- set mfd=3
- try
- let caught = 0
- call G()
- catch /^Vim(call):/
- let caught = 1
- let v:errmsg = substitute(v:exception, '^Vim(call):', '', "")
- finally
- Xpath 1048576 " X: 1048576
- if !caught && !$VIMNOERRTHROW
- Xpath 2097152 " X: 0
- endif
- if !MSG('E132', "Function call depth is higher than 'maxfuncdepth'")
- Xpath 4194304 " X: 0
- endif
- endtry
- catch /.*/
- Xpath 8388608 " X: 0
- Xout v:exception "in" v:throwpoint
- finally
- let &mfd = mfd_save
- break " discard error for $VIMNOERRTHROW
- endtry
-endwhile
-
-function! H()
- return H()
-endfunction
-
-while 1
- try
- let mfd_save = &mfd
- set mfd=3
- try
- let caught = 0
- call H()
- catch /^Vim(return):/
- let caught = 1
- let v:errmsg = substitute(v:exception, '^Vim(return):', '', "")
- finally
- Xpath 16777216 " X: 16777216
- if !caught && !$VIMNOERRTHROW
- Xpath 33554432 " X: 0
- endif
- if !MSG('E132', "Function call depth is higher than 'maxfuncdepth'")
- Xpath 67108864 " X: 0
- endif
- endtry
- catch /.*/
- Xpath 134217728 " X: 0
- Xout v:exception "in" v:throwpoint
- finally
- let &mfd = mfd_save
- break " discard error for $VIMNOERRTHROW
- endtry
-endwhile
-
-unlet! caught mfd_save
-delfunction F
-delfunction G
-delfunction H
-Xpath 268435456 " X: 268435456
-
-Xcheck 286331153
-
-" Leave MSG() for the next test.
-
-
-"-------------------------------------------------------------------------------
-" Test 63: Suppressing error exceptions by :silent!. {{{1
-"
-" A :silent! command inside a :try/:endtry region suppresses the
-" conversion of errors to an exception and the immediate abortion on
-" error. When the commands executed by the :silent! themselves open
-" a new :try/:endtry region, conversion of errors to exception and
-" immediate abortion is switched on again - until the next :silent!
-" etc. The :silent! has the effect of setting v:errmsg to the error
-" message text (without displaying it) and continuing with the next
-" script line.
-"
-" When a command triggering autocommands is executed by :silent!
-" inside a :try/:endtry, the autocommand execution is not suppressed
-" on error.
-"
-" This test reuses the function MSG() from the previous test.
-"-------------------------------------------------------------------------------
-
-XpathINIT
-
-XloopINIT! 1 4
-
-let taken = ""
-
-function! S(n) abort
- XloopNEXT
- let g:taken = g:taken . "E" . a:n
- let v:errmsg = ""
- exec "asdf" . a:n
-
- " Check that ":silent!" continues:
- Xloop 1
-
- " Check that ":silent!" sets "v:errmsg":
- if MSG('E492', "Not an editor command")
- Xloop 2
- endif
-endfunction
-
-function! Foo()
- while 1
- try
- try
- let caught = 0
- " This is not silent:
- call S(3) " X: 0 * 16
- catch /^Vim:/
- let caught = 1
- let errmsg3 = substitute(v:exception, '^Vim:', '', "")
- silent! call S(4) " X: 3 * 64
- finally
- if !caught
- let errmsg3 = v:errmsg
- " Do call S(4) here if not executed in :catch.
- silent! call S(4)
- endif
- Xpath 1048576 " X: 1048576
- if !caught && !$VIMNOERRTHROW
- Xpath 2097152 " X: 0
- endif
- let v:errmsg = errmsg3
- if !MSG('E492', "Not an editor command")
- Xpath 4194304 " X: 0
- endif
- silent! call S(5) " X: 3 * 256
- " Break out of try conditionals that cover ":silent!". This also
- " discards the aborting error when $VIMNOERRTHROW is non-zero.
- break
- endtry
- catch /.*/
- Xpath 8388608 " X: 0
- Xout v:exception "in" v:throwpoint
- endtry
- endwhile
- " This is a double ":silent!" (see caller).
- silent! call S(6) " X: 3 * 1024
-endfunction
-
-function! Bar()
- try
- silent! call S(2) " X: 3 * 4
- " X: 3 * 4096
- silent! execute "call Foo() | call S(7)"
- silent! call S(8) " X: 3 * 16384
- endtry " normal end of try cond that covers ":silent!"
- " This has a ":silent!" from the caller:
- call S(9) " X: 3 * 65536
-endfunction
-
-silent! call S(1) " X: 3 * 1
-silent! call Bar()
-silent! call S(10) " X: 3 * 262144
-
-let expected = "E1E2E3E4E5E6E7E8E9E10"
-if taken != expected
- Xpath 16777216 " X: 0
- Xout "'taken' is" taken "instead of" expected
-endif
-
-augroup TMP
- autocmd BufWritePost * Xpath 33554432 " X: 33554432
-augroup END
-
-Xpath 67108864 " X: 67108864
-write /i/m/p/o/s/s/i/b/l/e
-Xpath 134217728 " X: 134217728
-
-autocmd! TMP
-unlet! caught errmsg3 taken expected
-delfunction S
-delfunction Foo
-delfunction Bar
-delfunction MSG
-
-Xcheck 236978127
-
-
-"-------------------------------------------------------------------------------
-" Test 64: Error exceptions after error, interrupt or :throw {{{1
-"
-" When an error occurs after an interrupt or a :throw but before
-" a matching :catch is reached, all following :catches of that try
-" block are ignored, but the error exception can be caught by the next
-" surrounding try conditional. Any previous error exception is
-" discarded. An error is ignored when there is a previous error that
-" has not been caught.
-"-------------------------------------------------------------------------------
-
-XpathINIT
-
-if ExtraVim()
-
- while 1
- try
- try
- Xpath 1 " X: 1
- let caught = 0
- while 1
-" if 1
- " Missing :endif
- endwhile " throw error exception
- catch /^Vim(/
- let caught = 1
- finally
- Xpath 2 " X: 2
- if caught || $VIMNOERRTHROW
- Xpath 4 " X: 4
- endif
- endtry
- catch /.*/
- Xpath 8 " X: 0
- Xout v:exception "in" v:throwpoint
- finally
- break " discard error for $VIMNOERRTHROW
- endtry
- endwhile
-
- while 1
- try
- try
- Xpath 16 " X: 16
- let caught = 0
- try
-" if 1
- " Missing :endif
- catch /.*/ " throw error exception
- Xpath 32 " X: 0
- catch /.*/
- Xpath 64 " X: 0
- endtry
- catch /^Vim(/
- let caught = 1
- finally
- Xpath 128 " X: 128
- if caught || $VIMNOERRTHROW
- Xpath 256 " X: 256
- endif
- endtry
- catch /.*/
- Xpath 512 " X: 0
- Xout v:exception "in" v:throwpoint
- finally
- break " discard error for $VIMNOERRTHROW
- endtry
- endwhile
-
- while 1
- try
- try
- let caught = 0
- try
- Xpath 1024 " X: 1024
- "INTERRUPT
- catch /do_not_catch/
- Xpath 2048 " X: 0
-" if 1
- " Missing :endif
- catch /.*/ " throw error exception
- Xpath 4096 " X: 0
- catch /.*/
- Xpath 8192 " X: 0
- endtry
- catch /^Vim(/
- let caught = 1
- finally
- Xpath 16384 " X: 16384
- if caught || $VIMNOERRTHROW
- Xpath 32768 " X: 32768
- endif
- endtry
- catch /.*/
- Xpath 65536 " X: 0
- Xout v:exception "in" v:throwpoint
- finally
- break " discard error for $VIMNOERRTHROW
- endtry
- endwhile
-
- while 1
- try
- try
- let caught = 0
- try
- Xpath 131072 " X: 131072
- throw "x"
- catch /do_not_catch/
- Xpath 262144 " X: 0
-" if 1
- " Missing :endif
- catch /x/ " throw error exception
- Xpath 524288 " X: 0
- catch /.*/
- Xpath 1048576 " X: 0
- endtry
- catch /^Vim(/
- let caught = 1
- finally
- Xpath 2097152 " X: 2097152
- if caught || $VIMNOERRTHROW
- Xpath 4194304 " X: 4194304
- endif
- endtry
- catch /.*/
- Xpath 8388608 " X: 0
- Xout v:exception "in" v:throwpoint
- finally
- break " discard error for $VIMNOERRTHROW
- endtry
- endwhile
-
- while 1
- try
- try
- let caught = 0
- Xpath 16777216 " X: 16777216
-" endif " :endif without :if; throw error exception
-" if 1
- " Missing :endif
- catch /do_not_catch/ " ignore new error
- Xpath 33554432 " X: 0
- catch /^Vim(endif):/
- let caught = 1
- catch /^Vim(/
- Xpath 67108864 " X: 0
- finally
- Xpath 134217728 " X: 134217728
- if caught || $VIMNOERRTHROW
- Xpath 268435456 " X: 268435456
- endif
- endtry
- catch /.*/
- Xpath 536870912 " X: 0
- Xout v:exception "in" v:throwpoint
- finally
- break " discard error for $VIMNOERRTHROW
- endtry
- endwhile
-
- Xpath 1073741824 " X: 1073741824
-
-endif
-
-Xcheck 1499645335
-
-
-"-------------------------------------------------------------------------------
-" Test 65: Errors in the /pattern/ argument of a :catch {{{1
-"
-" On an error in the /pattern/ argument of a :catch, the :catch does
-" not match. Any following :catches of the same :try/:endtry don't
-" match either. Finally clauses are executed.
-"-------------------------------------------------------------------------------
-
-XpathINIT
-
-function! MSG(enr, emsg)
- let english = v:lang == "C" || v:lang =~ '^[Ee]n'
- if a:enr == ""
- Xout "TODO: Add message number for:" a:emsg
- let v:errmsg = ":" . v:errmsg
- endif
- let match = 1
- if v:errmsg !~ '^'.a:enr.':' || (english && v:errmsg !~ a:emsg)
- let match = 0
- if v:errmsg == ""
- Xout "Message missing."
- else
- let v:errmsg = escape(v:errmsg, '"')
- Xout "Unexpected message:" v:errmsg
- endif
- endif
- return match
-endfunction
-
-try
- try
- Xpath 1 " X: 1
- throw "oops"
- catch /^oops$/
- Xpath 2 " X: 2
- catch /\)/ " not checked; exception has already been caught
- Xpath 4 " X: 0
- endtry
- Xpath 8 " X: 8
-catch /.*/
- Xpath 16 " X: 0
- Xout v:exception "in" v:throwpoint
-endtry
-
-function! F()
- try
- let caught = 0
- try
- try
- Xpath 32 " X: 32
- throw "ab"
- catch /abc/ " does not catch
- Xpath 64 " X: 0
- catch /\)/ " error; discards exception
- Xpath 128 " X: 0
- catch /.*/ " not checked
- Xpath 256 " X: 0
- finally
- Xpath 512 " X: 512
- endtry
- Xpath 1024 " X: 0
- catch /^ab$/ " checked, but original exception is discarded
- Xpath 2048 " X: 0
- catch /^Vim(catch):/
- let caught = 1
- let v:errmsg = substitute(v:exception, '^Vim(catch):', '', "")
- finally
- Xpath 4096 " X: 4096
- if !caught && !$VIMNOERRTHROW
- Xpath 8192 " X: 0
- endif
- if !MSG('E475', "Invalid argument")
- Xpath 16384 " X: 0
- endif
- if !caught
- return | " discard error
- endif
- endtry
- catch /.*/
- Xpath 32768 " X: 0
- Xout v:exception "in" v:throwpoint
- endtry
-endfunction
-
-call F()
-Xpath 65536 " X: 65536
-
-delfunction MSG
-delfunction F
-unlet! caught
-
-Xcheck 70187
-
-
-"-------------------------------------------------------------------------------
-" Test 66: Stop range :call on error, interrupt, or :throw {{{1
-"
-" When a function which is multiply called for a range since it
-" doesn't handle the range itself has an error in a command
-" dynamically enclosed by :try/:endtry or gets an interrupt or
-" executes a :throw, no more calls for the remaining lines in the
-" range are made. On an error in a command not dynamically enclosed
-" by :try/:endtry, the function is executed again for the remaining
-" lines in the range.
-"-------------------------------------------------------------------------------
-
-XpathINIT
-
-if ExtraVim()
-
- let file = tempname()
- exec "edit" file
-
- insert
-line 1
-line 2
-line 3
-.
-
- XloopINIT! 1 2
-
- let taken = ""
- let expected = "G1EF1E(1)F1E(2)F1E(3)G2EF2E(1)G3IF3I(1)G4TF4T(1)G5AF5A(1)"
-
- function! F(reason, n) abort
- let g:taken = g:taken . "F" . a:n .
- \ substitute(a:reason, '\(\l\).*', '\u\1', "") .
- \ "(" . line(".") . ")"
-
- if a:reason == "error"
- asdf
- elseif a:reason == "interrupt"
- "INTERRUPT
- let dummy = 0
- elseif a:reason == "throw"
- throw "xyz"
- elseif a:reason == "aborting error"
- XloopNEXT
- if g:taken != g:expected
- Xloop 1 " X: 0
- Xout "'taken' is" g:taken "instead of" g:expected
- endif
- try
- bwipeout!
- call delete(file)
- asdf
- endtry
- endif
- endfunction
-
- function! G(reason, n)
- let g:taken = g:taken . "G" . a:n .
- \ substitute(a:reason, '\(\l\).*', '\u\1', "")
- 1,3call F(a:reason, a:n)
- endfunction
-
- Xpath 8 " X: 8
- call G("error", 1)
- try
- Xpath 16 " X: 16
- try
- call G("error", 2)
- Xpath 32 " X: 0
- finally
- Xpath 64 " X: 64
- try
- call G("interrupt", 3)
- Xpath 128 " X: 0
- finally
- Xpath 256 " X: 256
- try
- call G("throw", 4)
- Xpath 512 " X: 0
- endtry
- endtry
- endtry
- catch /xyz/
- Xpath 1024 " X: 1024
- catch /.*/
- Xpath 2048 " X: 0
- Xout v:exception "in" ExtraVimThrowpoint()
- endtry
- Xpath 4096 " X: 4096
- call G("aborting error", 5)
- Xpath 8192 " X: 0
- Xout "'taken' is" taken "instead of" expected
-
-endif
-
-Xcheck 5464
-
-
-"-------------------------------------------------------------------------------
-" Test 67: :throw across :call command {{{1
-"
-" On a call command, an exception might be thrown when evaluating the
-" function name, during evaluation of the arguments, or when the
-" function is being executed. The exception can be caught by the
-" caller.
-"-------------------------------------------------------------------------------
-
-XpathINIT
-
-function! THROW(x, n)
- if a:n == 1
- Xpath 1 " X: 1
- elseif a:n == 2
- Xpath 2 " X: 2
- elseif a:n == 3
- Xpath 4 " X: 4
- endif
- throw a:x
-endfunction
-
-function! NAME(x, n)
- if a:n == 1
- Xpath 8 " X: 0
- elseif a:n == 2
- Xpath 16 " X: 16
- elseif a:n == 3
- Xpath 32 " X: 32
- elseif a:n == 4
- Xpath 64 " X: 64
- endif
- return a:x
-endfunction
-
-function! ARG(x, n)
- if a:n == 1
- Xpath 128 " X: 0
- elseif a:n == 2
- Xpath 256 " X: 0
- elseif a:n == 3
- Xpath 512 " X: 512
- elseif a:n == 4
- Xpath 1024 " X: 1024
- endif
- return a:x
-endfunction
-
-function! F(x, n)
- if a:n == 2
- Xpath 2048 " X: 0
- elseif a:n == 4
- Xpath 4096 " X: 4096
- endif
-endfunction
-
-while 1
- try
- let error = 0
- let v:errmsg = ""
-
- while 1
- try
- Xpath 8192 " X: 8192
- call {NAME(THROW("name", 1), 1)}(ARG(4711, 1), 1)
- Xpath 16384 " X: 0
- catch /^name$/
- Xpath 32768 " X: 32768
- catch /.*/
- let error = 1
- Xout "1:" v:exception "in" v:throwpoint
- finally
- if !error && $VIMNOERRTHROW && v:errmsg != ""
- let error = 1
- Xout "1:" v:errmsg
- endif
- if error
- Xpath 65536 " X: 0
- endif
- let error = 0
- let v:errmsg = ""
- break " discard error for $VIMNOERRTHROW
- endtry
- endwhile
-
- while 1
- try
- Xpath 131072 " X: 131072
- call {NAME("F", 2)}(ARG(THROW("arg", 2), 2), 2)
- Xpath 262144 " X: 0
- catch /^arg$/
- Xpath 524288 " X: 524288
- catch /.*/
- let error = 1
- Xout "2:" v:exception "in" v:throwpoint
- finally
- if !error && $VIMNOERRTHROW && v:errmsg != ""
- let error = 1
- Xout "2:" v:errmsg
- endif
- if error
- Xpath 1048576 " X: 0
- endif
- let error = 0
- let v:errmsg = ""
- break " discard error for $VIMNOERRTHROW
- endtry
- endwhile
-
- while 1
- try
- Xpath 2097152 " X: 2097152
- call {NAME("THROW", 3)}(ARG("call", 3), 3)
- Xpath 4194304 " X: 0
- catch /^call$/
- Xpath 8388608 " X: 8388608
- catch /^0$/ " default return value
- Xpath 16777216 " X: 0
- Xout "3:" v:throwpoint
- catch /.*/
- let error = 1
- Xout "3:" v:exception "in" v:throwpoint
- finally
- if !error && $VIMNOERRTHROW && v:errmsg != ""
- let error = 1
- Xout "3:" v:errmsg
- endif
- if error
- Xpath 33554432 " X: 0
- endif
- let error = 0
- let v:errmsg = ""
- break " discard error for $VIMNOERRTHROW
- endtry
- endwhile
-
- while 1
- try
- Xpath 67108864 " X: 67108864
- call {NAME("F", 4)}(ARG(4711, 4), 4)
- Xpath 134217728 " X: 134217728
- catch /.*/
- let error = 1
- Xout "4:" v:exception "in" v:throwpoint
- finally
- if !error && $VIMNOERRTHROW && v:errmsg != ""
- let error = 1
- Xout "4:" v:errmsg
- endif
- if error
- Xpath 268435456 " X: 0
- endif
- let error = 0
- let v:errmsg = ""
- break " discard error for $VIMNOERRTHROW
- endtry
- endwhile
-
- catch /^0$/ " default return value
- Xpath 536870912 " X: 0
- Xout v:throwpoint
- catch /.*/
- let error = 1
- Xout v:exception "in" v:throwpoint
- finally
- if !error && $VIMNOERRTHROW && v:errmsg != ""
- let error = 1
- Xout v:errmsg
- endif
- if error
- Xpath 1073741824 " X: 0
- endif
- break " discard error for $VIMNOERRTHROW
- endtry
-endwhile
-
-unlet error
-delfunction F
-
-Xcheck 212514423
-
-" Leave THROW(), NAME(), and ARG() for the next test.
-
-
-"-------------------------------------------------------------------------------
-" Test 68: :throw across function calls in expressions {{{1
-"
-" On a function call within an expression, an exception might be
-" thrown when evaluating the function name, during evaluation of the
-" arguments, or when the function is being executed. The exception
-" can be caught by the caller.
-"
-" This test reuses the functions THROW(), NAME(), and ARG() from the
-" previous test.
-"-------------------------------------------------------------------------------
-
-XpathINIT
-
-function! F(x, n)
- if a:n == 2
- Xpath 2048 " X: 0
- elseif a:n == 4
- Xpath 4096 " X: 4096
- endif
- return a:x
-endfunction
-
-unlet! var1 var2 var3 var4
-
-while 1
- try
- let error = 0
- let v:errmsg = ""
-
- while 1
- try
- Xpath 8192 " X: 8192
- let var1 = {NAME(THROW("name", 1), 1)}(ARG(4711, 1), 1)
- Xpath 16384 " X: 0
- catch /^name$/
- Xpath 32768 " X: 32768
- catch /.*/
- let error = 1
- Xout "1:" v:exception "in" v:throwpoint
- finally
- if !error && $VIMNOERRTHROW && v:errmsg != ""
- let error = 1
- Xout "1:" v:errmsg
- endif
- if error
- Xpath 65536 " X: 0
- endif
- let error = 0
- let v:errmsg = ""
- break " discard error for $VIMNOERRTHROW
- endtry
- endwhile
-
- while 1
- try
- Xpath 131072 " X: 131072
- let var2 = {NAME("F", 2)}(ARG(THROW("arg", 2), 2), 2)
- Xpath 262144 " X: 0
- catch /^arg$/
- Xpath 524288 " X: 524288
- catch /.*/
- let error = 1
- Xout "2:" v:exception "in" v:throwpoint
- finally
- if !error && $VIMNOERRTHROW && v:errmsg != ""
- let error = 1
- Xout "2:" v:errmsg
- endif
- if error
- Xpath 1048576 " X: 0
- endif
- let error = 0
- let v:errmsg = ""
- break " discard error for $VIMNOERRTHROW
- endtry
- endwhile
-
- while 1
- try
- Xpath 2097152 " X: 2097152
- let var3 = {NAME("THROW", 3)}(ARG("call", 3), 3)
- Xpath 4194304 " X: 0
- catch /^call$/
- Xpath 8388608 " X: 8388608
- catch /^0$/ " default return value
- Xpath 16777216 " X: 0
- Xout "3:" v:throwpoint
- catch /.*/
- let error = 1
- Xout "3:" v:exception "in" v:throwpoint
- finally
- if !error && $VIMNOERRTHROW && v:errmsg != ""
- let error = 1
- Xout "3:" v:errmsg
- endif
- if error
- Xpath 33554432 " X: 0
- endif
- let error = 0
- let v:errmsg = ""
- break " discard error for $VIMNOERRTHROW
- endtry
- endwhile
-
- while 1
- try
- Xpath 67108864 " X: 67108864
- let var4 = {NAME("F", 4)}(ARG(4711, 4), 4)
- Xpath 134217728 " X: 134217728
- catch /.*/
- let error = 1
- Xout "4:" v:exception "in" v:throwpoint
- finally
- if !error && $VIMNOERRTHROW && v:errmsg != ""
- let error = 1
- Xout "4:" v:errmsg
- endif
- if error
- Xpath 268435456 " X: 0
- endif
- let error = 0
- let v:errmsg = ""
- break " discard error for $VIMNOERRTHROW
- endtry
- endwhile
-
- catch /^0$/ " default return value
- Xpath 536870912 " X: 0
- Xout v:throwpoint
- catch /.*/
- let error = 1
- Xout v:exception "in" v:throwpoint
- finally
- if !error && $VIMNOERRTHROW && v:errmsg != ""
- let error = 1
- Xout v:errmsg
- endif
- if error
- Xpath 1073741824 " X: 0
- endif
- break " discard error for $VIMNOERRTHROW
- endtry
-endwhile
-
-if exists("var1") || exists("var2") || exists("var3") ||
- \ !exists("var4") || var4 != 4711
- " The Xpath command does not accept 2^31 (negative); add explicitly:
- let Xpath = Xpath + 2147483648 " X: 0
- if exists("var1")
- Xout "var1 =" var1
- endif
- if exists("var2")
- Xout "var2 =" var2
- endif
- if exists("var3")
- Xout "var3 =" var3
- endif
- if !exists("var4")
- Xout "var4 unset"
- elseif var4 != 4711
- Xout "var4 =" var4
- endif
-endif
-
-unlet! error var1 var2 var3 var4
-delfunction THROW
-delfunction NAME
-delfunction ARG
-delfunction F
-
-Xcheck 212514423
-
-" Tests 69 to 75 were moved to test_trycatch.vim
-let Xtest = 76
-
-
-"-------------------------------------------------------------------------------
-" Test 76: Errors, interrupts, :throw during expression evaluation {{{1
-"
-" When a function call made during expression evaluation is aborted
-" due to an error inside a :try/:endtry region or due to an interrupt
-" or a :throw, the expression evaluation is aborted as well. No
-" message is displayed for the cancelled expression evaluation. On an
-" error not inside :try/:endtry, the expression evaluation continues.
-"-------------------------------------------------------------------------------
-
-XpathINIT
-
-if ExtraVim()
-
- let taken = ""
-
- function! ERR(n)
- let g:taken = g:taken . "E" . a:n
- asdf
- endfunction
-
- function! ERRabort(n) abort
- let g:taken = g:taken . "A" . a:n
- asdf
- endfunction " returns -1; may cause follow-up msg for illegal var/func name
-
- function! WRAP(n, arg)
- let g:taken = g:taken . "W" . a:n
- let g:saved_errmsg = v:errmsg
- return arg
- endfunction
-
- function! INT(n)
- let g:taken = g:taken . "I" . a:n
- "INTERRUPT9
- let dummy = 0
- endfunction
-
- function! THR(n)
- let g:taken = g:taken . "T" . a:n
- throw "should not be caught"
- endfunction
-
- function! CONT(n)
- let g:taken = g:taken . "C" . a:n
- endfunction
-
- function! MSG(n)
- let g:taken = g:taken . "M" . a:n
- let errmsg = (a:n >= 37 && a:n <= 44) ? g:saved_errmsg : v:errmsg
- let msgptn = (a:n >= 10 && a:n <= 27) ? "^$" : "asdf"
- if errmsg !~ msgptn
- let g:taken = g:taken . "x"
- Xout "Expr" a:n.": Unexpected message:" v:errmsg
- endif
- let v:errmsg = ""
- let g:saved_errmsg = ""
- endfunction
-
- let v:errmsg = ""
-
- try
- let t = 1
- XloopINIT 1 2
- while t <= 9
- Xloop 1 " X: 511
- try
- if t == 1
- let v{ERR(t) + CONT(t)} = 0
- elseif t == 2
- let v{ERR(t) + CONT(t)}
- elseif t == 3
- let var = exists('v{ERR(t) + CONT(t)}')
- elseif t == 4
- unlet v{ERR(t) + CONT(t)}
- elseif t == 5
- function F{ERR(t) + CONT(t)}()
- endfunction
- elseif t == 6
- function F{ERR(t) + CONT(t)}
- elseif t == 7
- let var = exists('*F{ERR(t) + CONT(t)}')
- elseif t == 8
- delfunction F{ERR(t) + CONT(t)}
- elseif t == 9
- let var = ERR(t) + CONT(t)
- endif
- catch /asdf/
- " v:errmsg is not set when the error message is converted to an
- " exception. Set it to the original error message.
- let v:errmsg = substitute(v:exception, '^Vim:', '', "")
- catch /^Vim\((\a\+)\)\=:/
- " An error exception has been thrown after the original error.
- let v:errmsg = ""
- finally
- call MSG(t)
- let t = t + 1
- XloopNEXT
- continue " discard an aborting error
- endtry
- endwhile
- catch /.*/
- Xpath 512 " X: 0
- Xout v:exception "in" ExtraVimThrowpoint()
- endtry
-
- try
- let t = 10
- XloopINIT 1024 2
- while t <= 18
- Xloop 1 " X: 1024 * 511
- try
- if t == 10
- let v{INT(t) + CONT(t)} = 0
- elseif t == 11
- let v{INT(t) + CONT(t)}
- elseif t == 12
- let var = exists('v{INT(t) + CONT(t)}')
- elseif t == 13
- unlet v{INT(t) + CONT(t)}
- elseif t == 14
- function F{INT(t) + CONT(t)}()
- endfunction
- elseif t == 15
- function F{INT(t) + CONT(t)}
- elseif t == 16
- let var = exists('*F{INT(t) + CONT(t)}')
- elseif t == 17
- delfunction F{INT(t) + CONT(t)}
- elseif t == 18
- let var = INT(t) + CONT(t)
- endif
- catch /^Vim\((\a\+)\)\=:\(Interrupt\)\@!/
- " An error exception has been triggered after the interrupt.
- let v:errmsg = substitute(v:exception,
- \ '^Vim\((\a\+)\)\=:', '', "")
- finally
- call MSG(t)
- let t = t + 1
- XloopNEXT
- continue " discard interrupt
- endtry
- endwhile
- catch /.*/
- Xpath 524288 " X: 0
- Xout v:exception "in" ExtraVimThrowpoint()
- endtry
-
- try
- let t = 19
- XloopINIT 1048576 2
- while t <= 27
- Xloop 1 " X: 1048576 * 511
- try
- if t == 19
- let v{THR(t) + CONT(t)} = 0
- elseif t == 20
- let v{THR(t) + CONT(t)}
- elseif t == 21
- let var = exists('v{THR(t) + CONT(t)}')
- elseif t == 22
- unlet v{THR(t) + CONT(t)}
- elseif t == 23
- function F{THR(t) + CONT(t)}()
- endfunction
- elseif t == 24
- function F{THR(t) + CONT(t)}
- elseif t == 25
- let var = exists('*F{THR(t) + CONT(t)}')
- elseif t == 26
- delfunction F{THR(t) + CONT(t)}
- elseif t == 27
- let var = THR(t) + CONT(t)
- endif
- catch /^Vim\((\a\+)\)\=:/
- " An error exception has been triggered after the :throw.
- let v:errmsg = substitute(v:exception,
- \ '^Vim\((\a\+)\)\=:', '', "")
- finally
- call MSG(t)
- let t = t + 1
- XloopNEXT
- continue " discard exception
- endtry
- endwhile
- catch /.*/
- Xpath 536870912 " X: 0
- Xout v:exception "in" ExtraVimThrowpoint()
- endtry
-
- let v{ERR(28) + CONT(28)} = 0
- call MSG(28)
- let v{ERR(29) + CONT(29)}
- call MSG(29)
- let var = exists('v{ERR(30) + CONT(30)}')
- call MSG(30)
- unlet v{ERR(31) + CONT(31)}
- call MSG(31)
- function F{ERR(32) + CONT(32)}()
- endfunction
- call MSG(32)
- function F{ERR(33) + CONT(33)}
- call MSG(33)
- let var = exists('*F{ERR(34) + CONT(34)}')
- call MSG(34)
- delfunction F{ERR(35) + CONT(35)}
- call MSG(35)
- let var = ERR(36) + CONT(36)
- call MSG(36)
-
- let saved_errmsg = ""
-
- let v{WRAP(37, ERRabort(37)) + CONT(37)} = 0
- call MSG(37)
- let v{WRAP(38, ERRabort(38)) + CONT(38)}
- call MSG(38)
- let var = exists('v{WRAP(39, ERRabort(39)) + CONT(39)}')
- call MSG(39)
- unlet v{WRAP(40, ERRabort(40)) + CONT(40)}
- call MSG(40)
- function F{WRAP(41, ERRabort(41)) + CONT(41)}()
- endfunction
- call MSG(41)
- function F{WRAP(42, ERRabort(42)) + CONT(42)}
- call MSG(42)
- let var = exists('*F{WRAP(43, ERRabort(43)) + CONT(43)}')
- call MSG(43)
- delfunction F{WRAP(44, ERRabort(44)) + CONT(44)}
- call MSG(44)
- let var = ERRabort(45) + CONT(45)
- call MSG(45)
-
- Xpath 1073741824 " X: 1073741824
-
- let expected = ""
- \ . "E1M1E2M2E3M3E4M4E5M5E6M6E7M7E8M8E9M9"
- \ . "I10M10I11M11I12M12I13M13I14M14I15M15I16M16I17M17I18M18"
- \ . "T19M19T20M20T21M21T22M22T23M23T24M24T25M25T26M26T27M27"
- \ . "E28C28M28E29C29M29E30C30M30E31C31M31E32C32M32E33C33M33"
- \ . "E34C34M34E35C35M35E36C36M36"
- \ . "A37W37C37M37A38W38C38M38A39W39C39M39A40W40C40M40A41W41C41M41"
- \ . "A42W42C42M42A43W43C43M43A44W44C44M44A45C45M45"
-
- if taken != expected
- " The Xpath command does not accept 2^31 (negative); display explicitly:
- exec "!echo 2147483648 >>" . g:ExtraVimResult
- " X: 0
- Xout "'taken' is" taken "instead of" expected
- if substitute(taken,
- \ '\(.*\)E3C3M3x\(.*\)E30C30M30x\(.*\)A39C39M39x\(.*\)',
- \ '\1E3M3\2E30C30M30\3A39C39M39\4',
- \ "") == expected
- Xout "Is ++emsg_skip for var with expr_start non-NULL"
- \ "in f_exists ok?"
- endif
- endif
-
- unlet! v var saved_errmsg taken expected
- call delete(WA_t5)
- call delete(WA_t14)
- call delete(WA_t23)
- unlet! WA_t5 WA_t14 WA_t23
- delfunction WA_t5
- delfunction WA_t14
- delfunction WA_t23
-
-endif
-
-Xcheck 1610087935
-
-
-"-------------------------------------------------------------------------------
-" Test 77: Errors, interrupts, :throw in name{brace-expression} {{{1
-"
-" When a function call made during evaluation of an expression in
-" braces as part of a function name after ":function" is aborted due
-" to an error inside a :try/:endtry region or due to an interrupt or
-" a :throw, the expression evaluation is aborted as well, and the
-" function definition is ignored, skipping all commands to the
-" ":endfunction". On an error not inside :try/:endtry, the expression
-" evaluation continues and the function gets defined, and can be
-" called and deleted.
-"-------------------------------------------------------------------------------
-
-XpathINIT
-
-XloopINIT 1 4
-
-function! ERR() abort
- Xloop 1 " X: 1 + 4 + 16 + 64
- asdf
-endfunction " returns -1
-
-function! OK()
- Xloop 2 " X: 2 * (1 + 4 + 16)
- let v:errmsg = ""
- return 0
-endfunction
-
-let v:errmsg = ""
-
-Xpath 4096 " X: 4096
-function! F{1 + ERR() + OK()}(arg)
- " F0 should be defined.
- if exists("a:arg") && a:arg == "calling"
- Xpath 8192 " X: 8192
- else
- Xpath 16384 " X: 0
- endif
-endfunction
-if v:errmsg != ""
- Xpath 32768 " X: 0
-endif
-XloopNEXT
-
-Xpath 65536 " X: 65536
-call F{1 + ERR() + OK()}("calling")
-if v:errmsg != ""
- Xpath 131072 " X: 0
-endif
-XloopNEXT
-
-Xpath 262144 " X: 262144
-delfunction F{1 + ERR() + OK()}
-if v:errmsg != ""
- Xpath 524288 " X: 0
-endif
-XloopNEXT
-
-try
- while 1
- let caught = 0
- try
- Xpath 1048576 " X: 1048576
- function! G{1 + ERR() + OK()}(arg)
- " G0 should not be defined, and the function body should be
- " skipped.
- if exists("a:arg") && a:arg == "calling"
- Xpath 2097152 " X: 0
- else
- Xpath 4194304 " X: 0
- endif
- " Use an unmatched ":finally" to check whether the body is
- " skipped when an error occurs in ERR(). This works whether or
- " not the exception is converted to an exception.
- finally
- Xpath 8388608 " X: 0
- Xout "Body of G{1 + ERR() + OK()}() not skipped"
- " Discard the aborting error or exception, and break the
- " while loop.
- break
- " End the try conditional and start a new one to avoid
- " ":catch after :finally" errors.
- endtry
- try
- Xpath 16777216 " X: 0
- endfunction
-
- " When the function was not defined, this won't be reached - whether
- " the body was skipped or not. When the function was defined, it
- " can be called and deleted here.
- Xpath 33554432 " X: 0
- Xout "G0() has been defined"
- XloopNEXT
- try
- call G{1 + ERR() + OK()}("calling")
- catch /.*/
- Xpath 67108864 " X: 0
- endtry
- Xpath 134217728 " X: 0
- XloopNEXT
- try
- delfunction G{1 + ERR() + OK()}
- catch /.*/
- Xpath 268435456 " X: 0
- endtry
- catch /asdf/
- " Jumped to when the function is not defined and the body is
- " skipped.
- let caught = 1
- catch /.*/
- Xpath 536870912 " X: 0
- finally
- if !caught && !$VIMNOERRTHROW
- Xpath 1073741824 " X: 0
- endif
- break " discard error for $VIMNOERRTHROW
- endtry " jumped to when the body is not skipped
- endwhile
-catch /.*/
- " The Xpath command does not accept 2^31 (negative); add explicitly:
- let Xpath = Xpath + 2147483648 " X: 0
- Xout "Body of G{1 + ERR() + OK()}() not skipped, exception caught"
- Xout v:exception "in" v:throwpoint
-endtry
-
-Xcheck 1388671
-
-
-"-------------------------------------------------------------------------------
-" Test 78: Messages on parsing errors in expression evaluation {{{1
-"
-" When an expression evaluation detects a parsing error, an error
-" message is given and converted to an exception, and the expression
-" evaluation is aborted.
-"-------------------------------------------------------------------------------
-
-XpathINIT
-
-if ExtraVim()
-
- let taken = ""
-
- function! F(n)
- let g:taken = g:taken . "F" . a:n
- endfunction
-
- function! MSG(n, enr, emsg)
- let g:taken = g:taken . "M" . a:n
- let english = v:lang == "C" || v:lang =~ '^[Ee]n'
- if a:enr == ""
- Xout "TODO: Add message number for:" a:emsg
- let v:errmsg = ":" . v:errmsg
- endif
- if v:errmsg !~ '^'.a:enr.':' || (english && v:errmsg !~ a:emsg)
- if v:errmsg == ""
- Xout "Expr" a:n.": Message missing."
- let g:taken = g:taken . "x"
- else
- let v:errmsg = escape(v:errmsg, '"')
- Xout "Expr" a:n.": Unexpected message:" v:errmsg
- Xout "Expected: " . a:enr . ': ' . a:emsg
- let g:taken = g:taken . "X"
- endif
- endif
- endfunction
-
- function! CONT(n)
- let g:taken = g:taken . "C" . a:n
- endfunction
-
- let v:errmsg = ""
- XloopINIT 1 2
-
- try
- let t = 1
- while t <= 14
- let g:taken = g:taken . "T" . t
- let v:errmsg = ""
- try
- let caught = 0
- if t == 1
- let v{novar + CONT(t)} = 0
- elseif t == 2
- let v{novar + CONT(t)}
- elseif t == 3
- let var = exists('v{novar + CONT(t)}')
- elseif t == 4
- unlet v{novar + CONT(t)}
- elseif t == 5
- function F{novar + CONT(t)}()
- endfunction
- elseif t == 6
- function F{novar + CONT(t)}
- elseif t == 7
- let var = exists('*F{novar + CONT(t)}')
- elseif t == 8
- delfunction F{novar + CONT(t)}
- elseif t == 9
- echo novar + CONT(t)
- elseif t == 10
- echo v{novar + CONT(t)}
- elseif t == 11
- echo F{novar + CONT(t)}
- elseif t == 12
- let var = novar + CONT(t)
- elseif t == 13
- let var = v{novar + CONT(t)}
- elseif t == 14
- let var = F{novar + CONT(t)}()
- endif
- catch /^Vim\((\a\+)\)\=:/
- " v:errmsg is not set when the error message is converted to an
- " exception. Set it to the original error message.
- let v:errmsg = substitute(v:exception,
- \ '^Vim\((\a\+)\)\=:', '', "")
- let caught = 1
- finally
- if t <= 8 && t != 3 && t != 7
- call MSG(t, 'E475', 'Invalid argument\>')
- else
- if !caught " no error exceptions ($VIMNOERRTHROW set)
- call MSG(t, 'E15', "Invalid expression")
- else
- call MSG(t, 'E121', "Undefined variable")
- endif
- endif
- let t = t + 1
- XloopNEXT
- continue " discard an aborting error
- endtry
- endwhile
- catch /.*/
- Xloop 1 " X: 0
- Xout t.":" v:exception "in" ExtraVimThrowpoint()
- endtry
-
- function! T(n, expr, enr, emsg)
- try
- let g:taken = g:taken . "T" . a:n
- let v:errmsg = ""
- try
- let caught = 0
- execute "let var = " . a:expr
- catch /^Vim\((\a\+)\)\=:/
- " v:errmsg is not set when the error message is converted to an
- " exception. Set it to the original error message.
- let v:errmsg = substitute(v:exception,
- \ '^Vim\((\a\+)\)\=:', '', "")
- let caught = 1
- finally
- if !caught " no error exceptions ($VIMNOERRTHROW set)
- call MSG(a:n, 'E15', "Invalid expression")
- else
- call MSG(a:n, a:enr, a:emsg)
- endif
- XloopNEXT
- " Discard an aborting error:
- return
- endtry
- catch /.*/
- Xloop 1 " X: 0
- Xout a:n.":" v:exception "in" ExtraVimThrowpoint()
- endtry
- endfunction
-
- call T(15, 'Nofunc() + CONT(15)', 'E117', "Unknown function")
- call T(16, 'F(1 2 + CONT(16))', 'E116', "Invalid arguments")
- call T(17, 'F(1, 2) + CONT(17)', 'E118', "Too many arguments")
- call T(18, 'F() + CONT(18)', 'E119', "Not enough arguments")
- call T(19, '{(1} + CONT(19)', 'E110', "Missing ')'")
- call T(20, '("abc"[1) + CONT(20)', 'E111', "Missing ']'")
- call T(21, '(1 +) + CONT(21)', 'E15', "Invalid expression")
- call T(22, '1 2 + CONT(22)', 'E15', "Invalid expression")
- call T(23, '(1 ? 2) + CONT(23)', 'E109', "Missing ':' after '?'")
- call T(24, '("abc) + CONT(24)', 'E114', "Missing quote")
- call T(25, "('abc) + CONT(25)", 'E115', "Missing quote")
- call T(26, '& + CONT(26)', 'E112', "Option name missing")
- call T(27, '&asdf + CONT(27)', 'E113', "Unknown option")
-
- Xpath 134217728 " X: 134217728
-
- let expected = ""
- \ . "T1M1T2M2T3M3T4M4T5M5T6M6T7M7T8M8T9M9T10M10T11M11T12M12T13M13T14M14"
- \ . "T15M15T16M16T17M17T18M18T19M19T20M20T21M21T22M22T23M23T24M24T25M25"
- \ . "T26M26T27M27"
-
- if taken != expected
- Xpath 268435456 " X: 0
- Xout "'taken' is" taken "instead of" expected
- if substitute(taken, '\(.*\)T3M3x\(.*\)', '\1T3M3\2', "") == expected
- Xout "Is ++emsg_skip for var with expr_start non-NULL"
- \ "in f_exists ok?"
- endif
- endif
-
- unlet! var caught taken expected
- call delete(WA_t5)
- unlet! WA_t5
- delfunction WA_t5
-
-endif
-
-Xcheck 134217728
-
-
-"-------------------------------------------------------------------------------
-" Test 79: Throwing one of several errors for the same command {{{1
-"
-" When several errors appear in a row (for instance during expression
-" evaluation), the first as the most specific one is used when
-" throwing an error exception. If, however, a syntax error is
-" detected afterwards, this one is used for the error exception.
-" On a syntax error, the next command is not executed, on a normal
-" error, however, it is (relevant only in a function without the
-" "abort" flag). v:errmsg is not set.
-"
-" If throwing error exceptions is configured off, v:errmsg is always
-" set to the latest error message, that is, to the more general
-" message or the syntax error, respectively.
-"-------------------------------------------------------------------------------
-
-XpathINIT
-
-XloopINIT 1 2
-
-function! NEXT(cmd)
- exec a:cmd . " | Xloop 1"
-endfunction
-
-call NEXT('echo novar') " X: 1 * 1 (checks nextcmd)
-XloopNEXT
-call NEXT('let novar #') " X: 0 * 2 (skips nextcmd)
-XloopNEXT
-call NEXT('unlet novar #') " X: 0 * 4 (skips nextcmd)
-XloopNEXT
-call NEXT('let {novar}') " X: 0 * 8 (skips nextcmd)
-XloopNEXT
-call NEXT('unlet{ novar}') " X: 0 * 16 (skips nextcmd)
-
-function! EXEC(cmd)
- exec a:cmd
-endfunction
-
-function! MATCH(expected, msg, enr, emsg)
- let msg = a:msg
- if a:enr == ""
- Xout "TODO: Add message number for:" a:emsg
- let msg = ":" . msg
- endif
- let english = v:lang == "C" || v:lang =~ '^[Ee]n'
- if msg !~ '^'.a:enr.':' || (english && msg !~ a:emsg)
- let match = 0
- if a:expected " no match although expected
- if a:msg == ""
- Xout "Message missing."
- else
- let msg = escape(msg, '"')
- Xout "Unexpected message:" msg
- Xout "Expected:" a:enr . ": " . a:emsg
- endif
- endif
- else
- let match = 1
- if !a:expected " match although not expected
- let msg = escape(msg, '"')
- Xout "Unexpected message:" msg
- Xout "Expected none."
- endif
- endif
- return match
-endfunction
-
-try
-
- while 1 " dummy loop
- try
- let v:errmsg = ""
- let caught = 0
- let thrmsg = ""
- call EXEC('echo novar') " normal error
- catch /^Vim\((\a\+)\)\=:/
- let caught = 1
- let thrmsg = substitute(v:exception, '^Vim\((\a\+)\)\=:', '', "")
- finally
- Xpath 32 " X: 32
- if !caught
- if !$VIMNOERRTHROW
- Xpath 64 " X: 0
- endif
- elseif !MATCH(1, thrmsg, 'E121', "Undefined variable")
- \ || v:errmsg != ""
- Xpath 128 " X: 0
- endif
- if !caught && !MATCH(1, v:errmsg, 'E15', "Invalid expression")
- Xpath 256 " X: 0
- endif
- break " discard error if $VIMNOERRTHROW == 1
- endtry
- endwhile
-
- Xpath 512 " X: 512
- let cmd = "let"
- XloopINIT 1024 32
- while cmd != ""
- try
- let v:errmsg = ""
- let caught = 0
- let thrmsg = ""
- call EXEC(cmd . ' novar #') " normal plus syntax error
- catch /^Vim\((\a\+)\)\=:/
- let caught = 1
- let thrmsg = substitute(v:exception, '^Vim\((\a\+)\)\=:', '', "")
- finally
- Xloop 1 " X: 1024 * (1 + 32)
- if !caught
- if !$VIMNOERRTHROW
- Xloop 2 " X: 0
- endif
- else
- if cmd == "let"
- let match = MATCH(0, thrmsg, 'E121', "Undefined variable")
- elseif cmd == "unlet"
- let match = MATCH(0, thrmsg, 'E108', "No such variable")
- endif
- if match " normal error
- Xloop 4 " X: 0
- endif
- if !MATCH(1, thrmsg, 'E488', "Trailing characters")
- \|| v:errmsg != ""
- " syntax error
- Xloop 8 " X: 0
- endif
- endif
- if !caught && !MATCH(1, v:errmsg, 'E488', "Trailing characters")
- " last error
- Xloop 16 " X: 0
- endif
- if cmd == "let"
- let cmd = "unlet"
- else
- let cmd = ""
- endif
- XloopNEXT
- continue " discard error if $VIMNOERRTHROW == 1
- endtry
- endwhile
-
- Xpath 1048576 " X: 1048576
- let cmd = "let"
- XloopINIT 2097152 32
- while cmd != ""
- try
- let v:errmsg = ""
- let caught = 0
- let thrmsg = ""
- call EXEC(cmd . ' {novar}') " normal plus syntax error
- catch /^Vim\((\a\+)\)\=:/
- let caught = 1
- let thrmsg = substitute(v:exception, '^Vim\((\a\+)\)\=:', '', "")
- finally
- Xloop 1 " X: 2097152 * (1 + 32)
- if !caught
- if !$VIMNOERRTHROW
- Xloop 2 " X: 0
- endif
- else
- if MATCH(0, thrmsg, 'E121', "Undefined variable") " normal error
- Xloop 4 " X: 0
- endif
- if !MATCH(1, thrmsg, 'E475', 'Invalid argument\>')
- \ || v:errmsg != "" " syntax error
- Xloop 8 " X: 0
- endif
- endif
- if !caught && !MATCH(1, v:errmsg, 'E475', 'Invalid argument\>')
- " last error
- Xloop 16 " X: 0
- endif
- if cmd == "let"
- let cmd = "unlet"
- else
- let cmd = ""
- endif
- XloopNEXT
- continue " discard error if $VIMNOERRTHROW == 1
- endtry
- endwhile
-
-catch /.*/
- " The Xpath command does not accept 2^31 (negative); add explicitly:
- let Xpath = Xpath + 2147483648 " X: 0
- Xout v:exception "in" v:throwpoint
-endtry
-
-unlet! next_command thrmsg match
-delfunction NEXT
-delfunction EXEC
-delfunction MATCH
-
-Xcheck 70288929
-
-
-"-------------------------------------------------------------------------------
-" Test 80: Syntax error in expression for illegal :elseif {{{1
-"
-" If there is a syntax error in the expression after an illegal
-" :elseif, an error message is given (or an error exception thrown)
-" for the illegal :elseif rather than the expression error.
-"-------------------------------------------------------------------------------
-
-XpathINIT
-
-function! MSG(enr, emsg)
- let english = v:lang == "C" || v:lang =~ '^[Ee]n'
- if a:enr == ""
- Xout "TODO: Add message number for:" a:emsg
- let v:errmsg = ":" . v:errmsg
- endif
- let match = 1
- if v:errmsg !~ '^'.a:enr.':' || (english && v:errmsg !~ a:emsg)
- let match = 0
- if v:errmsg == ""
- Xout "Message missing."
- else
- let v:errmsg = escape(v:errmsg, '"')
- Xout "Unexpected message:" v:errmsg
- endif
- endif
- return match
-endfunction
-
-let v:errmsg = ""
-if 0
-else
-elseif 1 ||| 2
-endif
-Xpath 1 " X: 1
-if !MSG('E584', ":elseif after :else")
- Xpath 2 " X: 0
-endif
-
-let v:errmsg = ""
-if 1
-else
-elseif 1 ||| 2
-endif
-Xpath 4 " X: 4
-if !MSG('E584', ":elseif after :else")
- Xpath 8 " X: 0
-endif
-
-let v:errmsg = ""
-elseif 1 ||| 2
-Xpath 16 " X: 16
-if !MSG('E582', ":elseif without :if")
- Xpath 32 " X: 0
-endif
-
-let v:errmsg = ""
-while 1
- elseif 1 ||| 2
-endwhile
-Xpath 64 " X: 64
-if !MSG('E582', ":elseif without :if")
- Xpath 128 " X: 0
-endif
-
-while 1
- try
- try
- let v:errmsg = ""
- let caught = 0
- if 0
- else
- elseif 1 ||| 2
- endif
- catch /^Vim\((\a\+)\)\=:/
- let caught = 1
- let v:errmsg = substitute(v:exception, '^Vim\((\a\+)\)\=:', '', "")
- finally
- Xpath 256 " X: 256
- if !caught && !$VIMNOERRTHROW
- Xpath 512 " X: 0
- endif
- if !MSG('E584', ":elseif after :else")
- Xpath 1024 " X: 0
- endif
- endtry
- catch /.*/
- Xpath 2048 " X: 0
- Xout v:exception "in" v:throwpoint
- finally
- break " discard error for $VIMNOERRTHROW
- endtry
-endwhile
-
-while 1
- try
- try
- let v:errmsg = ""
- let caught = 0
- if 1
- else
- elseif 1 ||| 2
- endif
- catch /^Vim\((\a\+)\)\=:/
- let caught = 1
- let v:errmsg = substitute(v:exception, '^Vim\((\a\+)\)\=:', '', "")
- finally
- Xpath 4096 " X: 4096
- if !caught && !$VIMNOERRTHROW
- Xpath 8192 " X: 0
- endif
- if !MSG('E584', ":elseif after :else")
- Xpath 16384 " X: 0
- endif
- endtry
- catch /.*/
- Xpath 32768 " X: 0
- Xout v:exception "in" v:throwpoint
- finally
- break " discard error for $VIMNOERRTHROW
- endtry
-endwhile
-
-while 1
- try
- try
- let v:errmsg = ""
- let caught = 0
- elseif 1 ||| 2
- catch /^Vim\((\a\+)\)\=:/
- let caught = 1
- let v:errmsg = substitute(v:exception, '^Vim\((\a\+)\)\=:', '', "")
- finally
- Xpath 65536 " X: 65536
- if !caught && !$VIMNOERRTHROW
- Xpath 131072 " X: 0
- endif
- if !MSG('E582', ":elseif without :if")
- Xpath 262144 " X: 0
- endif
- endtry
- catch /.*/
- Xpath 524288 " X: 0
- Xout v:exception "in" v:throwpoint
- finally
- break " discard error for $VIMNOERRTHROW
- endtry
-endwhile
-
-while 1
- try
- try
- let v:errmsg = ""
- let caught = 0
- while 1
- elseif 1 ||| 2
- endwhile
- catch /^Vim\((\a\+)\)\=:/
- let caught = 1
- let v:errmsg = substitute(v:exception, '^Vim\((\a\+)\)\=:', '', "")
- finally
- Xpath 1048576 " X: 1048576
- if !caught && !$VIMNOERRTHROW
- Xpath 2097152 " X: 0
- endif
- if !MSG('E582', ":elseif without :if")
- Xpath 4194304 " X: 0
- endif
- endtry
- catch /.*/
- Xpath 8388608 " X: 0
- Xout v:exception "in" v:throwpoint
- finally
- break " discard error for $VIMNOERRTHROW
- endtry
-endwhile
-
-Xpath 16777216 " X: 16777216
-
-unlet! caught
-delfunction MSG
-
-Xcheck 17895765
-
-
-"-------------------------------------------------------------------------------
-" Test 81: Discarding exceptions after an error or interrupt {{{1
-"
-" When an exception is thrown from inside a :try conditional without
-" :catch and :finally clauses and an error or interrupt occurs before
-" the :endtry is reached, the exception is discarded.
-"-------------------------------------------------------------------------------
-
-XpathINIT
-
-if ExtraVim()
- try
- Xpath 1 " X: 1
- try
- Xpath 2 " X: 2
- throw "arrgh"
- Xpath 4 " X: 0
-" if 1
- Xpath 8 " X: 0
- " error after :throw: missing :endif
- endtry
- Xpath 16 " X: 0
- catch /arrgh/
- Xpath 32 " X: 0
- endtry
- Xpath 64 " X: 0
-endif
-
-if ExtraVim()
- try
- Xpath 128 " X: 128
- try
- Xpath 256 " X: 256
- throw "arrgh"
- Xpath 512 " X: 0
- endtry " INTERRUPT
- Xpath 1024 " X: 0
- catch /arrgh/
- Xpath 2048 " X: 0
- endtry
- Xpath 4096 " X: 0
-endif
-
-Xcheck 387
-
+" Following tests were moved to test_vimscript.vim:
+" 1-24, 27-31, 34-40, 49-50, 52-68, 76-81, 87
+" Following tests were moved to test_trycatch.vim:
+" 25-26, 32-33, 41-48, 51, 69-75
+let Xtest = 82
"-------------------------------------------------------------------------------
" Test 82: Ignoring :catch clauses after an error or interrupt {{{1
diff --git a/src/nvim/testdir/test_arglist.vim b/src/nvim/testdir/test_arglist.vim
index 443a217143..cae71e10f3 100644
--- a/src/nvim/testdir/test_arglist.vim
+++ b/src/nvim/testdir/test_arglist.vim
@@ -1,5 +1,6 @@
" Test argument list commands
+source check.vim
source shared.vim
source term_util.vim
@@ -552,9 +553,7 @@ endfunc
" Test for quitting Vim with unedited files in the argument list
func Test_quit_with_arglist()
- if !CanRunVimInTerminal()
- throw 'Skipped: cannot run vim in terminal'
- endif
+ CheckRunVimInTerminal
let buf = RunVimInTerminal('', {'rows': 6})
call term_sendkeys(buf, ":set nomore\n")
call term_sendkeys(buf, ":args a b c\n")
diff --git a/src/nvim/testdir/test_assert.vim b/src/nvim/testdir/test_assert.vim
index 8723a0a38d..431908e95c 100644
--- a/src/nvim/testdir/test_assert.vim
+++ b/src/nvim/testdir/test_assert.vim
@@ -48,6 +48,11 @@ func Test_assert_equal()
call assert_equal('XxxxxxxxxxxxxxxxxxxxxxX', 'XyyyyyyyyyyyyyyyyyyyyyyyyyX')
call assert_match("Expected 'X\\\\\\[x occurs 21 times]X' but got 'X\\\\\\[y occurs 25 times]X'", v:errors[0])
call remove(v:errors, 0)
+
+ " special characters are escaped
+ call assert_equal("\b\e\f\n\t\r\\\x01\x7f", 'x')
+ call assert_match('Expected ''\\b\\e\\f\\n\\t\\r\\\\\\x01\\x7f'' but got ''x''', v:errors[0])
+ call remove(v:errors, 0)
endfunc
func Test_assert_equal_dict()
@@ -146,6 +151,14 @@ func Test_assert_exception()
try
nocommand
catch
+ call assert_equal(1, assert_exception('E12345:'))
+ endtry
+ call assert_match("Expected 'E12345:' but got 'Vim:E492: ", v:errors[0])
+ call remove(v:errors, 0)
+
+ try
+ nocommand
+ catch
try
" illegal argument, get NULL for error
call assert_equal(1, assert_exception([]))
@@ -153,6 +166,10 @@ func Test_assert_exception()
call assert_equal(0, assert_exception('E730:'))
endtry
endtry
+
+ call assert_equal(1, assert_exception('E492:'))
+ call assert_match('v:exception is not set', v:errors[0])
+ call remove(v:errors, 0)
endfunc
func Test_wrong_error_type()
@@ -202,6 +219,14 @@ func Test_assert_fail_fails()
call assert_match("stupid: Expected 'E9876' but got 'E492:", v:errors[0])
call remove(v:errors, 0)
+ call assert_equal(1, assert_fails('xxx', ['E9876']))
+ call assert_match("Expected \\['E9876'\\] but got 'E492:", v:errors[0])
+ call remove(v:errors, 0)
+
+ call assert_equal(1, assert_fails('xxx', ['E492:', 'E9876']))
+ call assert_match("Expected \\['E492:', 'E9876'\\] but got 'E492:", v:errors[0])
+ call remove(v:errors, 0)
+
call assert_equal(1, assert_fails('echo', '', 'echo command'))
call assert_match("command did not fail: echo command", v:errors[0])
call remove(v:errors, 0)
@@ -209,6 +234,41 @@ func Test_assert_fail_fails()
call assert_equal(1, 'echo'->assert_fails('', 'echo command'))
call assert_match("command did not fail: echo command", v:errors[0])
call remove(v:errors, 0)
+
+ try
+ call assert_equal(1, assert_fails('xxx', []))
+ catch
+ let exp = v:exception
+ endtry
+ call assert_match("E856: assert_fails() second argument", exp)
+
+ try
+ call assert_equal(1, assert_fails('xxx', ['1', '2', '3']))
+ catch
+ let exp = v:exception
+ endtry
+ call assert_match("E856: assert_fails() second argument", exp)
+
+ try
+ call assert_equal(1, assert_fails('xxx', #{one: 1}))
+ catch
+ let exp = v:exception
+ endtry
+ call assert_match("E856: assert_fails() second argument", exp)
+
+ try
+ call assert_equal(1, assert_fails('xxx', 'E492', '', 'burp'))
+ catch
+ let exp = v:exception
+ endtry
+ call assert_match("E1115: assert_fails() fourth argument must be a number", exp)
+
+ try
+ call assert_equal(1, assert_fails('xxx', 'E492', '', 54, 123))
+ catch
+ let exp = v:exception
+ endtry
+ call assert_match("E1116: assert_fails() fifth argument must be a string", exp)
endfunc
func Test_assert_fails_in_try_block()
diff --git a/src/nvim/testdir/test_autochdir.vim b/src/nvim/testdir/test_autochdir.vim
index 4229095f9f..a8810047a0 100644
--- a/src/nvim/testdir/test_autochdir.vim
+++ b/src/nvim/testdir/test_autochdir.vim
@@ -122,9 +122,7 @@ endfunc
func Test_multibyte()
" using an invalid character should not cause a crash
set wic
- " Except on Windows, E472 is also thrown last, but v8.1.1183 isn't ported yet
- " call assert_fails('tc *', has('win32') ? 'E480:' : 'E344:')
- call assert_fails('tc *', has('win32') ? 'E480:' : 'E472:')
+ call assert_fails('tc *', has('win32') ? 'E480:' : 'E344:')
set nowic
endfunc
diff --git a/src/nvim/testdir/test_autocmd.vim b/src/nvim/testdir/test_autocmd.vim
index 8c15249f97..50904bab34 100644
--- a/src/nvim/testdir/test_autocmd.vim
+++ b/src/nvim/testdir/test_autocmd.vim
@@ -175,9 +175,7 @@ func Test_autocmd_bufunload_avoiding_SEGV_01()
exe 'autocmd BufUnload <buffer> ' . (lastbuf + 1) . 'bwipeout!'
augroup END
- " Todo: check for E937 generated first
- " call assert_fails('edit bb.txt', 'E937:')
- call assert_fails('edit bb.txt', 'E517:')
+ call assert_fails('edit bb.txt', ['E937:', 'E517:'])
autocmd! test_autocmd_bufunload
augroup! test_autocmd_bufunload
@@ -533,6 +531,8 @@ func Test_augroup_warning()
redir END
call assert_notmatch("W19:", res)
au! VimEnter
+
+ call assert_fails('augroup!', 'E471:')
endfunc
func Test_BufReadCmdHelp()
@@ -2931,7 +2931,7 @@ func Test_BufDelete_changebuf()
augroup END
let save_cpo = &cpo
set cpo+=f
- call assert_fails('r Xfile', 'E484:')
+ call assert_fails('r Xfile', ['E812:', 'E484:'])
call assert_equal('somefile', @%)
let &cpo = save_cpo
augroup TestAuCmd
diff --git a/src/nvim/testdir/test_backup.vim b/src/nvim/testdir/test_backup.vim
index ce2bfe72bc..7eff818732 100644
--- a/src/nvim/testdir/test_backup.vim
+++ b/src/nvim/testdir/test_backup.vim
@@ -1,5 +1,7 @@
" Tests for the backup function
+source check.vim
+
func Test_backup()
set backup backupdir=. backupskip=
new
@@ -56,3 +58,19 @@ func Test_backup2_backupcopy()
call delete(f)
set backup&vim backupdir&vim backupcopy&vim backupskip&vim
endfunc
+
+" Test for using a non-existing directory as a backup directory
+func Test_non_existing_backupdir()
+ throw 'Skipped: Nvim auto-creates backup directory'
+ CheckNotBSD
+ let save_backup = &backupdir
+ set backupdir=./non_existing_dir
+ call writefile(['line1'], 'Xfile')
+ new Xfile
+ " TODO: write doesn't fail in Cirrus FreeBSD CI test
+ call assert_fails('write', 'E510:')
+ let &backupdir = save_backup
+ call delete('Xfile')
+endfunc
+
+" vim: shiftwidth=2 sts=2 expandtab
diff --git a/src/nvim/testdir/test_blob.vim b/src/nvim/testdir/test_blob.vim
index 770b2d16ef..046acb81e1 100644
--- a/src/nvim/testdir/test_blob.vim
+++ b/src/nvim/testdir/test_blob.vim
@@ -252,6 +252,7 @@ func Test_blob_func_remove()
call assert_fails("call remove(b, 3, 2)", 'E979:')
call assert_fails("call remove(1, 0)", 'E896:')
call assert_fails("call remove(b, b)", 'E974:')
+ call assert_fails("call remove(b, 1, [])", 'E745:')
call assert_fails("call remove(v:_null_blob, 1, 2)", 'E979:')
" Translated from v8.2.3284
@@ -300,6 +301,9 @@ func Test_blob_index()
call assert_equal(3, 0z11110111->index(0x11, 2))
call assert_equal(2, index(0z11111111, 0x11, -2))
call assert_equal(3, index(0z11110111, 0x11, -2))
+ call assert_equal(0, index(0z11110111, 0x11, -10))
+ call assert_fails("echo index(0z11110111, 0x11, [])", 'E745:')
+ call assert_equal(-1, index(v:_null_blob, 1))
call assert_fails('call index("asdf", 0)', 'E897:')
endfunc
diff --git a/src/nvim/testdir/test_breakindent.vim b/src/nvim/testdir/test_breakindent.vim
index ed4d886fd1..995683c68c 100644
--- a/src/nvim/testdir/test_breakindent.vim
+++ b/src/nvim/testdir/test_breakindent.vim
@@ -8,6 +8,7 @@ source check.vim
CheckOption breakindent
source view_util.vim
+source screendump.vim
let s:input ="\tabcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOP"
@@ -421,6 +422,7 @@ func Test_breakindent11()
let width = strlen(text[1:]) + indent(2) + strlen(&sbr) * 3 " text wraps 3 times
call assert_equal(width, strdisplaywidth(text))
call s:close_windows('set sbr=')
+ call assert_equal(4, strdisplaywidth("\t", 4))
endfunc
func Test_breakindent11_vartabs()
@@ -875,17 +877,164 @@ endfunc
func Test_window_resize_with_linebreak()
new
53vnew
- set linebreak
- set showbreak=>>
- set breakindent
- set breakindentopt=shift:4
+ setl linebreak
+ setl showbreak=>>
+ setl breakindent
+ setl breakindentopt=shift:4
call setline(1, "\naaaaaaaaa\n\na\naaaaa\n¯aaaaaaaaaa\naaaaaaaaaaaa\naaa\n\"a:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa - aaaaaaaa\"\naaaaaaaa\n\"a")
redraw!
call assert_equal([" >>aa^@\"a: "], ScreenLines(2, 14))
vertical resize 52
redraw!
call assert_equal([" >>aaa^@\"a:"], ScreenLines(2, 14))
+ set linebreak& showbreak& breakindent& breakindentopt&
%bw!
endfunc
+func Test_cursor_position_with_showbreak()
+ CheckScreendump
+
+ let lines =<< trim END
+ vim9script
+ &signcolumn = 'yes'
+ &showbreak = '+ '
+ var leftcol: number = win_getid()->getwininfo()->get(0, {})->get('textoff')
+ repeat('x', &columns - leftcol - 1)->setline(1)
+ 'second line'->setline(2)
+ END
+ call writefile(lines, 'XscriptShowbreak')
+ let buf = RunVimInTerminal('-S XscriptShowbreak', #{rows: 6})
+
+ call term_sendkeys(buf, "AX")
+ call VerifyScreenDump(buf, 'Test_cursor_position_with_showbreak', {})
+
+ call StopVimInTerminal(buf)
+ call delete('XscriptShowbreak')
+endfunc
+
+func Test_no_spurious_match()
+ let s:input = printf('- y %s y %s', repeat('x', 50), repeat('x', 50))
+ call s:test_windows('setl breakindent breakindentopt=list:-1 formatlistpat=^- hls')
+ let @/ = '\%>3v[y]'
+ redraw!
+ call searchcount().total->assert_equal(1)
+ " cleanup
+ set hls&vim
+ let s:input = "\tabcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOP"
+ bwipeout!
+endfunc
+
+func Test_no_extra_indent()
+ call s:test_windows('setl breakindent breakindentopt=list:-1,min:10')
+ %d
+ let &l:formatlistpat='^\s*\d\+\.\s\+'
+ let text = 'word '
+ let len = text->strcharlen()
+ let line1 = text->repeat((winwidth(0) / len) * 2)
+ let line2 = repeat(' ', 2) .. '1. ' .. line1
+ call setline(1, [line2])
+ redraw!
+ " 1) matches formatlist pattern, so indent
+ let expect = [
+ \ " 1. word word word ",
+ \ " word word word ",
+ \ " word word ",
+ \ "~ ",
+ \ ]
+ let lines = s:screen_lines2(1, 4, 20)
+ call s:compare_lines(expect, lines)
+ " 2) change formatlist pattern
+ " -> indent adjusted
+ let &l:formatlistpat='^\s*\d\+\.'
+ let expect = [
+ \ " 1. word word word ",
+ \ " word word word ",
+ \ " word word ",
+ \ "~ ",
+ \ ]
+ let lines = s:screen_lines2(1, 4, 20)
+ " 3) no local formatlist pattern,
+ " so use global one -> indent
+ let g_flp = &g:flp
+ let &g:formatlistpat='^\s*\d\+\.\s\+'
+ let &l:formatlistpat=''
+ let expect = [
+ \ " 1. word word word ",
+ \ " word word word ",
+ \ " word word ",
+ \ "~ ",
+ \ ]
+ let lines = s:screen_lines2(1, 4, 20)
+ call s:compare_lines(expect, lines)
+ let &g:flp = g_flp
+ let &l:formatlistpat='^\s*\d\+\.'
+ " 4) add something in front, no additional indent
+ norm! gg0
+ exe ":norm! 5iword \<esc>"
+ redraw!
+ let expect = [
+ \ "word word word word ",
+ \ "word 1. word word ",
+ \ "word word word word ",
+ \ "word word ",
+ \ "~ ",
+ \ ]
+ let lines = s:screen_lines2(1, 5, 20)
+ call s:compare_lines(expect, lines)
+ bwipeout!
+endfunc
+
+func Test_breakindent_column()
+ " restore original
+ let s:input ="\tabcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOP"
+ call s:test_windows('setl breakindent breakindentopt=column:10')
+ redraw!
+ " 1) default: does not indent, too wide :(
+ let expect = [
+ \ " ",
+ \ " abcdefghijklmnop",
+ \ "qrstuvwxyzABCDEFGHIJ",
+ \ "KLMNOP "
+ \ ]
+ let lines = s:screen_lines2(1, 4, 20)
+ call s:compare_lines(expect, lines)
+ " 2) lower min value, so that breakindent works
+ setl breakindentopt+=min:5
+ redraw!
+ let expect = [
+ \ " ",
+ \ " abcdefghijklmnop",
+ \ " qrstuvwxyz",
+ \ " ABCDEFGHIJ",
+ \ " KLMNOP "
+ \ ]
+ let lines = s:screen_lines2(1, 5, 20)
+ " 3) set shift option -> no influence
+ setl breakindentopt+=shift:5
+ redraw!
+ let expect = [
+ \ " ",
+ \ " abcdefghijklmnop",
+ \ " qrstuvwxyz",
+ \ " ABCDEFGHIJ",
+ \ " KLMNOP "
+ \ ]
+ let lines = s:screen_lines2(1, 5, 20)
+ call s:compare_lines(expect, lines)
+ " 4) add showbreak value
+ setl showbreak=++
+ redraw!
+ let expect = [
+ \ " ",
+ \ " abcdefghijklmnop",
+ \ " ++qrstuvwx",
+ \ " ++yzABCDEF",
+ \ " ++GHIJKLMN",
+ \ " ++OP "
+ \ ]
+ let lines = s:screen_lines2(1, 6, 20)
+ call s:compare_lines(expect, lines)
+ bwipeout!
+endfunc
+
" vim: shiftwidth=2 sts=2 expandtab
diff --git a/src/nvim/testdir/test_buffer.vim b/src/nvim/testdir/test_buffer.vim
index 4def3b5df9..27c2d5d442 100644
--- a/src/nvim/testdir/test_buffer.vim
+++ b/src/nvim/testdir/test_buffer.vim
@@ -76,7 +76,7 @@ func Test_bunload_with_offset()
let caught_E90 = 1
endtry
call assert_equal(1, caught_E90)
- call assert_fails('$bunload', 'E515:')
+ call assert_fails('$bunload', 'E90:')
endfunc
" Test for :buffer, :bnext, :bprevious, :brewind, :blast and :bmodified
@@ -282,7 +282,7 @@ func Test_goto_buf_with_confirm()
call assert_equal(1, &modified)
call assert_equal('', @%)
call feedkeys('y', 'L')
- call assert_fails('confirm b Xfile', 'E37:')
+ call assert_fails('confirm b Xfile', ['', 'E37:'])
call assert_equal(1, &modified)
call assert_equal('', @%)
call feedkeys('n', 'L')
diff --git a/src/nvim/testdir/test_bufline.vim b/src/nvim/testdir/test_bufline.vim
index 8f853fe44e..2867f13cbc 100644
--- a/src/nvim/testdir/test_bufline.vim
+++ b/src/nvim/testdir/test_bufline.vim
@@ -19,13 +19,25 @@ func Test_setbufline_getbufline()
call setline(1, ['a', 'b', 'c'])
let b = bufnr('%')
wincmd w
+
+ call assert_equal(1, setbufline(b, 5, 'x'))
call assert_equal(1, setbufline(b, 5, ['x']))
+ call assert_equal(1, setbufline(b, 5, []))
+ call assert_equal(1, setbufline(b, 5, v:_null_list))
+
+ call assert_equal(1, 'x'->setbufline(bufnr('$') + 1, 1))
call assert_equal(1, ['x']->setbufline(bufnr('$') + 1, 1))
+ call assert_equal(1, []->setbufline(bufnr('$') + 1, 1))
+ call assert_equal(1, v:_null_list->setbufline(bufnr('$') + 1, 1))
+
+ call assert_equal(['a', 'b', 'c'], getbufline(b, 1, '$'))
+
call assert_equal(0, setbufline(b, 4, ['d', 'e']))
call assert_equal(['c'], b->getbufline(3))
call assert_equal(['d'], getbufline(b, 4))
call assert_equal(['e'], getbufline(b, 5))
call assert_equal([], getbufline(b, 6))
+ call assert_equal([], getbufline(b, 2, 1))
exe "bwipe! " . b
endfunc
@@ -83,9 +95,29 @@ func Test_appendbufline()
call setline(1, ['a', 'b', 'c'])
let b = bufnr('%')
wincmd w
+
+ call assert_equal(1, appendbufline(b, -1, 'x'))
call assert_equal(1, appendbufline(b, -1, ['x']))
+ call assert_equal(1, appendbufline(b, -1, []))
+ call assert_equal(1, appendbufline(b, -1, v:_null_list))
+
+ call assert_equal(1, appendbufline(b, 4, 'x'))
call assert_equal(1, appendbufline(b, 4, ['x']))
+ call assert_equal(1, appendbufline(b, 4, []))
+ call assert_equal(1, appendbufline(b, 4, v:_null_list))
+
+ call assert_equal(1, appendbufline(1234, 1, 'x'))
call assert_equal(1, appendbufline(1234, 1, ['x']))
+ call assert_equal(1, appendbufline(1234, 1, []))
+ call assert_equal(1, appendbufline(1234, 1, v:_null_list))
+
+ call assert_equal(0, appendbufline(b, 1, []))
+ call assert_equal(0, appendbufline(b, 1, v:_null_list))
+ call assert_equal(1, appendbufline(b, 3, []))
+ call assert_equal(1, appendbufline(b, 3, v:_null_list))
+
+ call assert_equal(['a', 'b', 'c'], getbufline(b, 1, '$'))
+
call assert_equal(0, appendbufline(b, 3, ['d', 'e']))
call assert_equal(['c'], getbufline(b, 3))
call assert_equal(['d'], getbufline(b, 4))
diff --git a/src/nvim/testdir/test_cd.vim b/src/nvim/testdir/test_cd.vim
index d6d44d1901..2a2437f542 100644
--- a/src/nvim/testdir/test_cd.vim
+++ b/src/nvim/testdir/test_cd.vim
@@ -5,7 +5,7 @@ source check.vim
func Test_cd_large_path()
" This used to crash with a heap write overflow.
- call assert_fails('cd ' . repeat('x', 5000), 'E472:')
+ call assert_fails('cd ' . repeat('x', 5000), 'E344:')
endfunc
func Test_cd_up_and_down()
@@ -45,9 +45,7 @@ func Test_cd_minus()
call assert_equal(path, getcwd())
" Test for :cd - after a failed :cd
- " v8.2.1183 is not ported yet
- " call assert_fails('cd /nonexistent', 'E344:')
- call assert_fails('cd /nonexistent', 'E472:')
+ call assert_fails('cd /nonexistent', 'E344:')
call assert_equal(path, getcwd())
cd -
call assert_equal(path_dotdot, getcwd())
@@ -68,30 +66,6 @@ func Test_cd_minus()
call delete('Xresult')
endfunc
-func Test_cd_with_cpo_chdir()
- e Xfoo
- call setline(1, 'foo')
- let path = getcwd()
- " set cpo+=.
-
- " :cd should fail when buffer is modified and 'cpo' contains dot.
- " call assert_fails('cd ..', 'E747:')
- call assert_equal(path, getcwd())
-
- " :cd with exclamation mark should succeed.
- cd! ..
- call assert_notequal(path, getcwd())
-
- " :cd should succeed when buffer has been written.
- w!
- exe 'cd ' .. fnameescape(path)
- call assert_equal(path, getcwd())
-
- call delete('Xfoo')
- set cpo&
- bw!
-endfunc
-
" Test for chdir()
func Test_chdir_func()
let topdir = getcwd()
@@ -127,7 +101,7 @@ func Test_chdir_func()
call assert_equal('testdir', fnamemodify(getcwd(1, 1), ':t'))
" Error case
- call assert_fails("call chdir('dir-abcd')", 'E472:')
+ call assert_fails("call chdir('dir-abcd')", 'E344:')
silent! let d = chdir("dir_abcd")
call assert_equal("", d)
" Should not crash
diff --git a/src/nvim/testdir/test_charsearch.vim b/src/nvim/testdir/test_charsearch.vim
index d386d74f8d..54e0a62ce5 100644
--- a/src/nvim/testdir/test_charsearch.vim
+++ b/src/nvim/testdir/test_charsearch.vim
@@ -43,36 +43,6 @@ func Test_charsearch()
enew!
endfunc
-" Test for t,f,F,T movement commands and 'cpo-;' setting
-func Test_search_cmds()
- enew!
- call append(0, ["aaa two three four", " zzz", "yyy ",
- \ "bbb yee yoo four", "ccc two three four",
- \ "ddd yee yoo four"])
- set cpo-=;
- 1
- normal! 0tt;D
- 2
- normal! 0fz;D
- 3
- normal! $Fy;D
- 4
- normal! $Ty;D
- set cpo+=;
- 5
- normal! 0tt;;D
- 6
- normal! $Ty;;D
-
- call assert_equal('aaa two', getline(1))
- call assert_equal(' z', getline(2))
- call assert_equal('y', getline(3))
- call assert_equal('bbb y', getline(4))
- call assert_equal('ccc', getline(5))
- call assert_equal('ddd yee y', getline(6))
- enew!
-endfunc
-
" Test for character search in virtual edit mode with <Tab>
func Test_csearch_virtualedit()
new
@@ -81,7 +51,7 @@ func Test_csearch_virtualedit()
normal! tb
call assert_equal([0, 1, 2, 6], getpos('.'))
set virtualedit&
- close!
+ bw!
endfunc
" Test for character search failure in latin1 encoding
@@ -95,7 +65,34 @@ func Test_charsearch_latin1()
call assert_beeps('normal $Fz')
call assert_beeps('normal $Tx')
let &encoding = save_enc
- close!
+ bw!
+endfunc
+
+" Test for using character search to find a multibyte character with composing
+" characters.
+func Test_charsearch_composing_char()
+ new
+ call setline(1, "one two thq\u0328\u0301r\u0328\u0301ree")
+ call feedkeys("fr\u0328\u0301", 'xt')
+ call assert_equal([0, 1, 16, 0, 12], getcurpos())
+
+ " use character search with a multi-byte character followed by a
+ " non-composing character
+ call setline(1, "abc deȉf ghi")
+ call feedkeys("ggcf\u0209\u0210", 'xt')
+ call assert_equal("\u0210f ghi", getline(1))
+ bw!
+endfunc
+
+" Test for character search with 'hkmap'
+func Test_charsearch_hkmap()
+ new
+ set hkmap
+ call setline(1, "ùðáâ÷ëòéïçìêöî")
+ call feedkeys("fë", 'xt')
+ call assert_equal([0, 1, 11, 0, 6], getcurpos())
+ set hkmap&
+ bw!
endfunc
" vim: shiftwidth=2 sts=2 expandtab
diff --git a/src/nvim/testdir/test_clientserver.vim b/src/nvim/testdir/test_clientserver.vim
index 943f79d98f..19a92dce3c 100644
--- a/src/nvim/testdir/test_clientserver.vim
+++ b/src/nvim/testdir/test_clientserver.vim
@@ -102,7 +102,7 @@ func Test_client_server()
call remote_send(v:servername, ":let g:testvar2 = 75\<CR>")
call feedkeys('', 'x')
call assert_equal(75, g:testvar2)
- call assert_fails('let v = remote_expr(v:servername, "/2")', 'E449:')
+ call assert_fails('let v = remote_expr(v:servername, "/2")', ['E15:.*/2'])
call remote_send(name, ":call server2client(expand('<client>'), 'got it')\<CR>", 'g:myserverid')
call assert_equal('got it', g:myserverid->remote_read(2))
@@ -182,9 +182,10 @@ func Test_client_server()
endif
endtry
+ call assert_fails('call remote_startserver([])', 'E730:')
call assert_fails("let x = remote_peek([])", 'E730:')
- call assert_fails("let x = remote_read('vim10')", 'E277:')
- call assert_fails("call server2client('abc', 'xyz')", 'E258:')
+ call assert_fails("let x = remote_read('vim10')", ['E573:.*vim10'])
+ call assert_fails("call server2client('abc', 'xyz')", ['E573:.*abc'])
endfunc
" Uncomment this line to get a debugging log
diff --git a/src/nvim/testdir/test_cmdline.vim b/src/nvim/testdir/test_cmdline.vim
index 00bfadec93..c00172ed68 100644
--- a/src/nvim/testdir/test_cmdline.vim
+++ b/src/nvim/testdir/test_cmdline.vim
@@ -89,6 +89,13 @@ func Test_complete_wildmenu()
call assert_equal('"e Xtestfile3 Xtestfile4', @:)
cd -
+ cnoremap <expr> <F2> wildmenumode()
+ call feedkeys(":cd Xdir\<Tab>\<F2>\<C-B>\"\<CR>", 'tx')
+ call assert_equal('"cd Xdir1/0', @:)
+ call feedkeys(":e Xdir1/\<Tab>\<F2>\<C-B>\"\<CR>", 'tx')
+ call assert_equal('"e Xdir1/Xdir2/1', @:)
+ cunmap <F2>
+
" cleanup
%bwipe
call delete('Xdir1/Xdir2/Xtestfile4')
@@ -1147,7 +1154,7 @@ func Test_cmdline_search_range()
call assert_equal('B', getline(2))
let @/ = 'apple'
- call assert_fails('\/print', 'E486:')
+ call assert_fails('\/print', ['E486:.*apple'])
bwipe!
endfunc
@@ -1263,6 +1270,11 @@ func Test_verbosefile()
let log = readfile('Xlog')
call assert_match("foo\nbar", join(log, "\n"))
call delete('Xlog')
+ call mkdir('Xdir')
+ if !has('win32') " FIXME: no error on Windows, libuv bug?
+ call assert_fails('set verbosefile=Xdir', ['E484:.*Xdir', 'E474:'])
+ endif
+ call delete('Xdir', 'd')
endfunc
func Test_verbose_option()
@@ -1513,7 +1525,7 @@ func Test_cmdwin_jump_to_win()
call assert_fails('call feedkeys("q:\<C-W>\<C-W>\<CR>", "xt")', 'E11:')
new
set modified
- call assert_fails('call feedkeys("q/:qall\<CR>", "xt")', 'E162:')
+ call assert_fails('call feedkeys("q/:qall\<CR>", "xt")', ['E37:', 'E162:'])
close!
call feedkeys("q/:close\<CR>", "xt")
call assert_equal(1, winnr('$'))
@@ -1527,13 +1539,7 @@ endfunc
func Test_cmdwin_tabpage()
tabedit
- " v8.2.1919 isn't ported yet, so E492 is thrown after E11 here.
- " v8.2.1183 also isn't ported yet, so we also can't assert E11 directly.
- " For now, assert E11 and E492 separately. When v8.2.1183 is ported, the
- " assert for E492 will fail and this workaround should be removed.
- " call assert_fails("silent norm q/g :I\<Esc>", 'E11:')
- call assert_fails("silent norm q/g ", 'E11:')
- call assert_fails("silent norm q/g :I\<Esc>", 'E492:')
+ call assert_fails("silent norm q/g :I\<Esc>", 'E11:')
tabclose!
endfunc
diff --git a/src/nvim/testdir/test_cpoptions.vim b/src/nvim/testdir/test_cpoptions.vim
new file mode 100644
index 0000000000..ef51d955f1
--- /dev/null
+++ b/src/nvim/testdir/test_cpoptions.vim
@@ -0,0 +1,927 @@
+" Test for the various 'cpoptions' (cpo) flags
+
+source check.vim
+source shared.vim
+source view_util.vim
+
+" Test for the 'a' flag in 'cpo'. Reading a file should set the alternate
+" file name.
+func Test_cpo_a()
+ let save_cpo = &cpo
+ call writefile(['one'], 'Xfile')
+ " Wipe out all the buffers, so that the alternate file is empty
+ edit Xfoo | %bw
+ set cpo-=a
+ new
+ read Xfile
+ call assert_equal('', @#)
+ %d
+ set cpo+=a
+ read Xfile
+ call assert_equal('Xfile', @#)
+ close!
+ call delete('Xfile')
+ let &cpo = save_cpo
+endfunc
+
+" Test for the 'A' flag in 'cpo'. Writing a file should set the alternate
+" file name.
+func Test_cpo_A()
+ let save_cpo = &cpo
+ " Wipe out all the buffers, so that the alternate file is empty
+ edit Xfoo | %bw
+ set cpo-=A
+ new Xfile1
+ write Xfile2
+ call assert_equal('', @#)
+ %bw
+ call delete('Xfile2')
+ new Xfile1
+ set cpo+=A
+ write Xfile2
+ call assert_equal('Xfile2', @#)
+ close!
+ call delete('Xfile2')
+ let &cpo = save_cpo
+endfunc
+
+" Test for the 'b' flag in 'cpo'. "\|" at the end of a map command is
+" recognized as the end of the map.
+func Test_cpo_b()
+ let save_cpo = &cpo
+ set cpo+=b
+ nnoremap <F5> :pwd\<CR>\|let i = 1
+ call assert_equal(':pwd\<CR>\', maparg('<F5>'))
+ nunmap <F5>
+ exe "nnoremap <F5> :pwd\<C-V>|let i = 1"
+ call assert_equal(':pwd|let i = 1', maparg('<F5>'))
+ nunmap <F5>
+ set cpo-=b
+ nnoremap <F5> :pwd\<CR>\|let i = 1
+ call assert_equal(':pwd\<CR>|let i = 1', maparg('<F5>'))
+ let &cpo = save_cpo
+ nunmap <F5>
+endfunc
+
+" Test for the 'B' flag in 'cpo'. A backslash in mappings, abbreviations, user
+" commands and menu commands has no special meaning.
+func Test_cpo_B()
+ let save_cpo = &cpo
+ new
+ set cpo-=B
+ iabbr <buffer> abc ab\<BS>d
+ exe "normal iabc "
+ call assert_equal('ab<BS>d ', getline(1))
+ %d
+ set cpo+=B
+ iabbr <buffer> abc ab\<BS>d
+ exe "normal iabc "
+ call assert_equal('abd ', getline(1))
+ close!
+ let &cpo = save_cpo
+endfunc
+
+" Test for the 'c' flag in 'cpo'.
+func Test_cpo_c()
+ let save_cpo = &cpo
+ set cpo+=c
+ new
+ call setline(1, ' abababababab')
+ exe "normal gg/abab\<CR>"
+ call assert_equal(3, searchcount().total)
+ set cpo-=c
+ exe "normal gg/abab\<CR>"
+ call assert_equal(5, searchcount().total)
+ close!
+ let &cpo = save_cpo
+endfunc
+
+" Test for the 'C' flag in 'cpo' (line continuation)
+func Test_cpo_C()
+ let save_cpo = &cpo
+ call writefile(['let l = [', '\ 1,', '\ 2]'], 'Xfile')
+ set cpo-=C
+ source Xfile
+ call assert_equal([1, 2], g:l)
+ set cpo+=C
+ call assert_fails('source Xfile', ['E697:', 'E10:'])
+ call delete('Xfile')
+ let &cpo = save_cpo
+endfunc
+
+" Test for the 'd' flag in 'cpo' (tags relative to the current file)
+func Test_cpo_d()
+ let save_cpo = &cpo
+ call mkdir('Xdir')
+ call writefile(["one\tXfile1\t/^one$/"], 'tags')
+ call writefile(["two\tXfile2\t/^two$/"], 'Xdir/tags')
+ set tags=./tags
+ set cpo-=d
+ edit Xdir/Xfile
+ call assert_equal('two', taglist('.*')[0].name)
+ set cpo+=d
+ call assert_equal('one', taglist('.*')[0].name)
+ %bw!
+ call delete('tags')
+ call delete('Xdir', 'rf')
+ set tags&
+ let &cpo = save_cpo
+endfunc
+
+" Test for the 'D' flag in 'cpo' (digraph after a r, f or t)
+func Test_cpo_D()
+ CheckFeature digraphs
+ let save_cpo = &cpo
+ new
+ set cpo-=D
+ call setline(1, 'abcdefgh|')
+ exe "norm! 1gg0f\<c-k>!!"
+ call assert_equal(9, col('.'))
+ set cpo+=D
+ exe "norm! 1gg0f\<c-k>!!"
+ call assert_equal(1, col('.'))
+ set cpo-=D
+ close!
+ let &cpo = save_cpo
+endfunc
+
+" Test for the 'e' flag in 'cpo'
+func Test_cpo_e()
+ let save_cpo = &cpo
+ let @a='let i = 45'
+ set cpo+=e
+ call feedkeys(":@a\<CR>", 'xt')
+ call assert_equal(45, i)
+ set cpo-=e
+ call feedkeys(":@a\<CR>6\<CR>", 'xt')
+ call assert_equal(456, i)
+ let &cpo = save_cpo
+endfunc
+
+" Test for the 'E' flag in 'cpo' with yank, change, delete, etc. operators
+func Test_cpo_E()
+ new
+ call setline(1, '')
+ set cpo+=E
+ " yank an empty line
+ call assert_beeps('normal "ayl')
+ " change an empty line
+ call assert_beeps('normal lcTa')
+ call assert_beeps('normal 0c0')
+ " delete an empty line
+ call assert_beeps('normal D')
+ call assert_beeps('normal dl')
+ call assert_equal('', getline(1))
+ " change case of an empty line
+ call assert_beeps('normal gul')
+ call assert_beeps('normal gUl')
+ " replace a character
+ call assert_beeps('normal vrx')
+ " increment and decrement
+ call assert_beeps('exe "normal v\<C-A>"')
+ call assert_beeps('exe "normal v\<C-X>"')
+ set cpo-=E
+ close!
+endfunc
+
+" Test for the 'f' flag in 'cpo' (read in an empty buffer sets the file name)
+func Test_cpo_f()
+ let save_cpo = &cpo
+ new
+ set cpo-=f
+ read test_cpoptions.vim
+ call assert_equal('', @%)
+ %d
+ set cpo+=f
+ read test_cpoptions.vim
+ call assert_equal('test_cpoptions.vim', @%)
+ close!
+ let &cpo = save_cpo
+endfunc
+
+" Test for the 'F' flag in 'cpo' (write in an empty buffer sets the file name)
+func Test_cpo_F()
+ let save_cpo = &cpo
+ new
+ set cpo-=F
+ write Xfile
+ call assert_equal('', @%)
+ call delete('Xfile')
+ set cpo+=F
+ write Xfile
+ call assert_equal('Xfile', @%)
+ close!
+ call delete('Xfile')
+ let &cpo = save_cpo
+endfunc
+
+" Test for the 'g' flag in 'cpo' (jump to line 1 when re-editing a file)
+func Test_cpo_g()
+ throw 'Skipped: Nvim does not support cpoptions flag "g"'
+ let save_cpo = &cpo
+ new test_cpoptions.vim
+ set cpo-=g
+ normal 20G
+ edit
+ call assert_equal(20, line('.'))
+ set cpo+=g
+ edit
+ call assert_equal(1, line('.'))
+ close!
+ let &cpo = save_cpo
+endfunc
+
+" Test for inserting text in a line with only spaces ('H' flag in 'cpoptions')
+func Test_cpo_H()
+ throw 'Skipped: Nvim does not support cpoptions flag "H"'
+ let save_cpo = &cpo
+ new
+ set cpo-=H
+ call setline(1, ' ')
+ normal! Ia
+ call assert_equal(' a', getline(1))
+ set cpo+=H
+ call setline(1, ' ')
+ normal! Ia
+ call assert_equal(' a ', getline(1))
+ close!
+ let &cpo = save_cpo
+endfunc
+
+" TODO: Add a test for the 'i' flag in 'cpo'
+" Interrupting the reading of a file will leave it modified.
+
+" Test for the 'I' flag in 'cpo' (deleting autoindent when using arrow keys)
+func Test_cpo_I()
+ let save_cpo = &cpo
+ new
+ setlocal autoindent
+ set cpo+=I
+ exe "normal i one\<CR>\<Up>"
+ call assert_equal(' ', getline(2))
+ set cpo-=I
+ %d
+ exe "normal i one\<CR>\<Up>"
+ call assert_equal('', getline(2))
+ close!
+ let &cpo = save_cpo
+endfunc
+
+" Test for the 'j' flag in 'cpo' is in the test_join.vim file.
+
+" Test for the 'J' flag in 'cpo' (two spaces after a sentence)
+func Test_cpo_J()
+ let save_cpo = &cpo
+ new
+ set cpo-=J
+ call setline(1, 'one. two! three? four."'' five.)]')
+ normal 0
+ for colnr in [6, 12, 19, 28, 34]
+ normal )
+ call assert_equal(colnr, col('.'))
+ endfor
+ for colnr in [28, 19, 12, 6, 1]
+ normal (
+ call assert_equal(colnr, col('.'))
+ endfor
+ set cpo+=J
+ normal 0
+ for colnr in [12, 28, 34]
+ normal )
+ call assert_equal(colnr, col('.'))
+ endfor
+ for colnr in [28, 12, 1]
+ normal (
+ call assert_equal(colnr, col('.'))
+ endfor
+ close!
+ let &cpo = save_cpo
+endfunc
+
+" TODO: Add a test for the 'k' flag in 'cpo'.
+" Disable the recognition of raw key codes in mappings, abbreviations, and the
+" "to" part of menu commands.
+
+" TODO: Add a test for the 'K' flag in 'cpo'.
+" Don't wait for a key code to complete when it is halfway a mapping.
+
+" Test for the 'l' flag in 'cpo' (backslash in a [] range)
+func Test_cpo_l()
+ let save_cpo = &cpo
+ new
+ call setline(1, ['', "a\tc" .. '\t'])
+ set cpo-=l
+ exe 'normal gg/[\t]' .. "\<CR>"
+ call assert_equal([2, 8], [col('.'), virtcol('.')])
+ set cpo+=l
+ exe 'normal gg/[\t]' .. "\<CR>"
+ call assert_equal([4, 10], [col('.'), virtcol('.')])
+ close!
+ let &cpo = save_cpo
+endfunc
+
+" Test for inserting tab in virtual replace mode ('L' flag in 'cpoptions')
+func Test_cpo_L()
+ let save_cpo = &cpo
+ new
+ set cpo-=L
+ call setline(1, 'abcdefghijklmnopqr')
+ exe "normal 0gR\<Tab>"
+ call assert_equal("\<Tab>ijklmnopqr", getline(1))
+ set cpo+=L
+ set list
+ call setline(1, 'abcdefghijklmnopqr')
+ exe "normal 0gR\<Tab>"
+ call assert_equal("\<Tab>cdefghijklmnopqr", getline(1))
+ set nolist
+ call setline(1, 'abcdefghijklmnopqr')
+ exe "normal 0gR\<Tab>"
+ call assert_equal("\<Tab>ijklmnopqr", getline(1))
+ close!
+ let &cpo = save_cpo
+endfunc
+
+" TODO: Add a test for the 'm' flag in 'cpo'.
+" When included, a showmatch will always wait half a second. When not
+" included, a showmatch will wait half a second or until a character is typed.
+
+" Test for the 'M' flag in 'cpo' (% with escape parenthesis)
+func Test_cpo_M()
+ let save_cpo = &cpo
+ new
+ call setline(1, ['( \( )', '\( ( \)'])
+
+ set cpo-=M
+ call cursor(1, 1)
+ normal %
+ call assert_equal(6, col('.'))
+ call cursor(1, 4)
+ call assert_beeps('normal %')
+ call cursor(2, 2)
+ normal %
+ call assert_equal(7, col('.'))
+ call cursor(2, 4)
+ call assert_beeps('normal %')
+
+ set cpo+=M
+ call cursor(1, 4)
+ normal %
+ call assert_equal(6, col('.'))
+ call cursor(1, 1)
+ call assert_beeps('normal %')
+ call cursor(2, 4)
+ normal %
+ call assert_equal(7, col('.'))
+ call cursor(2, 1)
+ call assert_beeps('normal %')
+
+ close!
+ let &cpo = save_cpo
+endfunc
+
+" Test for the 'n' flag in 'cpo' (using number column for wrapped lines)
+func Test_cpo_n()
+ let save_cpo = &cpo
+ new
+ call setline(1, repeat('a', &columns))
+ setlocal number
+ set cpo-=n
+ redraw!
+ call assert_equal(' aaaa', Screenline(2))
+ set cpo+=n
+ redraw!
+ call assert_equal('aaaa', Screenline(2))
+ close!
+ let &cpo = save_cpo
+endfunc
+
+" Test for the 'o' flag in 'cpo' (line offset to search command)
+func Test_cpo_o()
+ let save_cpo = &cpo
+ new
+ call setline(1, ['', 'one', 'two', 'three', 'one', 'two', 'three'])
+ set cpo-=o
+ exe "normal /one/+2\<CR>"
+ normal n
+ call assert_equal(7, line('.'))
+ set cpo+=o
+ exe "normal /one/+2\<CR>"
+ normal n
+ call assert_equal(5, line('.'))
+ close!
+ let &cpo = save_cpo
+endfunc
+
+" Test for the 'O' flag in 'cpo' (overwriting an existing file)
+func Test_cpo_O()
+ let save_cpo = &cpo
+ new Xfile
+ call setline(1, 'one')
+ call writefile(['two'], 'Xfile')
+ set cpo-=O
+ call assert_fails('write', 'E13:')
+ set cpo+=O
+ write
+ call assert_equal(['one'], readfile('Xfile'))
+ close!
+ call delete('Xfile')
+ let &cpo = save_cpo
+endfunc
+
+" Test for the 'p' flag in 'cpo' is in the test_lispwords.vim file.
+
+" Test for the 'P' flag in 'cpo' (appending to a file sets the current file
+" name)
+func Test_cpo_P()
+ let save_cpo = &cpo
+ call writefile([], 'Xfile')
+ new
+ call setline(1, 'one')
+ set cpo+=F
+ set cpo-=P
+ write >> Xfile
+ call assert_equal('', @%)
+ set cpo+=P
+ write >> Xfile
+ call assert_equal('Xfile', @%)
+ close!
+ call delete('Xfile')
+ let &cpo = save_cpo
+endfunc
+
+" Test for the 'q' flag in 'cpo' (joining multiple lines)
+func Test_cpo_q()
+ let save_cpo = &cpo
+ new
+ call setline(1, ['one', 'two', 'three', 'four', 'five'])
+ set cpo-=q
+ normal gg4J
+ call assert_equal(14, col('.'))
+ %d
+ call setline(1, ['one', 'two', 'three', 'four', 'five'])
+ set cpo+=q
+ normal gg4J
+ call assert_equal(4, col('.'))
+ close!
+ let &cpo = save_cpo
+endfunc
+
+" Test for the 'r' flag in 'cpo' (redo command with a search motion)
+func Test_cpo_r()
+ let save_cpo = &cpo
+ new
+ call setline(1, repeat(['one two three four'], 2))
+ set cpo-=r
+ exe "normal ggc/two\<CR>abc "
+ let @/ = 'three'
+ normal 2G.
+ call assert_equal('abc two three four', getline(2))
+ %d
+ call setline(1, repeat(['one two three four'], 2))
+ set cpo+=r
+ exe "normal ggc/two\<CR>abc "
+ let @/ = 'three'
+ normal 2G.
+ call assert_equal('abc three four', getline(2))
+ close!
+ let &cpo = save_cpo
+endfunc
+
+" Test for the 'R' flag in 'cpo' (clear marks after a filter command)
+func Test_cpo_R()
+ CheckUnix
+ let save_cpo = &cpo
+ new
+ call setline(1, ['three', 'one', 'two'])
+ set cpo-=R
+ 3mark r
+ %!sort
+ call assert_equal(3, line("'r"))
+ %d
+ call setline(1, ['three', 'one', 'two'])
+ set cpo+=R
+ 3mark r
+ %!sort
+ call assert_equal(0, line("'r"))
+ close!
+ let &cpo = save_cpo
+endfunc
+
+" TODO: Add a test for the 's' flag in 'cpo'.
+" Set buffer options when entering the buffer for the first time. If not
+" present the options are set when the buffer is created.
+
+" Test for the 'S' flag in 'cpo' (copying buffer options)
+func Test_cpo_S()
+ let save_cpo = &cpo
+ new Xfile1
+ set noautoindent
+ new Xfile2
+ set cpo-=S
+ set autoindent
+ wincmd p
+ call assert_equal(0, &autoindent)
+ wincmd p
+ call assert_equal(1, &autoindent)
+ set cpo+=S
+ wincmd p
+ call assert_equal(1, &autoindent)
+ set noautoindent
+ wincmd p
+ call assert_equal(0, &autoindent)
+ wincmd t
+ close!
+ close!
+ let &cpo = save_cpo
+endfunc
+
+" Test for the 't' flag in 'cpo' is in the test_tagjump.vim file.
+
+" Test for the 'u' flag in 'cpo' (Vi-compatible undo)
+func Test_cpo_u()
+ let save_cpo = &cpo
+ new
+ set cpo-=u
+ exe "normal iabc\<C-G>udef\<C-G>ughi"
+ normal uu
+ call assert_equal('abc', getline(1))
+ %d
+ set cpo+=u
+ exe "normal iabc\<C-G>udef\<C-G>ughi"
+ normal uu
+ call assert_equal('abcdefghi', getline(1))
+ close!
+ let &cpo = save_cpo
+endfunc
+
+" TODO: Add a test for the 'v' flag in 'cpo'.
+" Backspaced characters remain visible on the screen in Insert mode.
+
+" Test for the 'w' flag in 'cpo' ('cw' on a blank character changes only one
+" character)
+func Test_cpo_w()
+ throw 'Skipped: Nvim does not support cpoptions flag "w"'
+ let save_cpo = &cpo
+ new
+ set cpo+=w
+ call setline(1, 'here are some words')
+ norm! 1gg0elcwZZZ
+ call assert_equal('hereZZZ are some words', getline('.'))
+ norm! 1gg2elcWYYY
+ call assert_equal('hereZZZ areYYY some words', getline('.'))
+ set cpo-=w
+ call setline(1, 'here are some words')
+ norm! 1gg0elcwZZZ
+ call assert_equal('hereZZZare some words', getline('.'))
+ norm! 1gg2elcWYYY
+ call assert_equal('hereZZZare someYYYwords', getline('.'))
+ close!
+ let &cpo = save_cpo
+endfunc
+
+" Test for the 'W' flag in 'cpo' is in the test_writefile.vim file
+
+" Test for the 'x' flag in 'cpo' (Esc on command-line executes command)
+func Test_cpo_x()
+ let save_cpo = &cpo
+ set cpo-=x
+ let i = 1
+ call feedkeys(":let i=10\<Esc>", 'xt')
+ call assert_equal(1, i)
+ set cpo+=x
+ call feedkeys(":let i=10\<Esc>", 'xt')
+ call assert_equal(10, i)
+ let &cpo = save_cpo
+endfunc
+
+" Test for the 'X' flag in 'cpo' ('R' with a count)
+func Test_cpo_X()
+ let save_cpo = &cpo
+ new
+ call setline(1, 'aaaaaa')
+ set cpo-=X
+ normal gg4Rx
+ call assert_equal('xxxxaa', getline(1))
+ normal ggRy
+ normal 4.
+ call assert_equal('yyyyaa', getline(1))
+ call setline(1, 'aaaaaa')
+ set cpo+=X
+ normal gg4Rx
+ call assert_equal('xxxxaaaaa', getline(1))
+ normal ggRy
+ normal 4.
+ call assert_equal('yyyyxxxaaaaa', getline(1))
+ close!
+ let &cpo = save_cpo
+endfunc
+
+" Test for the 'y' flag in 'cpo' (repeating a yank command)
+func Test_cpo_y()
+ let save_cpo = &cpo
+ new
+ call setline(1, ['one', 'two'])
+ set cpo-=y
+ normal ggyy
+ normal 2G.
+ call assert_equal("one\n", @")
+ %d
+ call setline(1, ['one', 'two'])
+ set cpo+=y
+ normal ggyy
+ normal 2G.
+ call assert_equal("two\n", @")
+ close!
+ let &cpo = save_cpo
+endfunc
+
+" Test for the 'Z' flag in 'cpo' (write! resets 'readonly')
+func Test_cpo_Z()
+ let save_cpo = &cpo
+ call writefile([], 'Xfile')
+ new Xfile
+ setlocal readonly
+ set cpo-=Z
+ write!
+ call assert_equal(0, &readonly)
+ set cpo+=Z
+ setlocal readonly
+ write!
+ call assert_equal(1, &readonly)
+ close!
+ call delete('Xfile')
+ let &cpo = save_cpo
+endfunc
+
+" Test for the '!' flag in 'cpo' is in the test_normal.vim file
+
+" Test for displaying dollar when changing text ('$' flag in 'cpoptions')
+func Test_cpo_dollar()
+ throw 'Skipped: use test/functional/legacy/cpoptions_spec.lua'
+ new
+ let g:Line = ''
+ func SaveFirstLine()
+ let g:Line = Screenline(1)
+ return ''
+ endfunc
+ inoremap <expr> <buffer> <F2> SaveFirstLine()
+ call test_override('redraw_flag', 1)
+ set cpo+=$
+ call setline(1, 'one two three')
+ redraw!
+ exe "normal c2w\<F2>vim"
+ call assert_equal('one tw$ three', g:Line)
+ call assert_equal('vim three', getline(1))
+ set cpo-=$
+ call test_override('ALL', 0)
+ delfunc SaveFirstLine
+ %bw!
+endfunc
+
+" Test for the '%' flag in 'cpo' (parenthesis matching inside strings)
+func Test_cpo_percent()
+ let save_cpo = &cpo
+ new
+ call setline(1, ' if (strcmp("ab)cd(", s))')
+ set cpo-=%
+ normal 8|%
+ call assert_equal(28, col('.'))
+ normal 15|%
+ call assert_equal(27, col('.'))
+ normal 27|%
+ call assert_equal(15, col('.'))
+ call assert_beeps("normal 19|%")
+ call assert_beeps("normal 22|%")
+ set cpo+=%
+ normal 8|%
+ call assert_equal(28, col('.'))
+ normal 15|%
+ call assert_equal(19, col('.'))
+ normal 27|%
+ call assert_equal(22, col('.'))
+ normal 19|%
+ call assert_equal(15, col('.'))
+ normal 22|%
+ call assert_equal(27, col('.'))
+ close!
+ let &cpo = save_cpo
+endfunc
+
+" Test for cursor movement with '-' in 'cpoptions'
+func Test_cpo_minus()
+ throw 'Skipped: Nvim does not support cpoptions flag "-"'
+ new
+ call setline(1, ['foo', 'bar', 'baz'])
+ let save_cpo = &cpo
+ set cpo+=-
+ call assert_beeps('normal 10j')
+ call assert_equal(1, line('.'))
+ normal G
+ call assert_beeps('normal 10k')
+ call assert_equal(3, line('.'))
+ call assert_fails(10, 'E16:')
+ close!
+ let &cpo = save_cpo
+endfunc
+
+" Test for the '+' flag in 'cpo' ('write file' command resets the 'modified'
+" flag)
+func Test_cpo_plus()
+ let save_cpo = &cpo
+ call writefile([], 'Xfile')
+ new Xfile
+ call setline(1, 'foo')
+ write X1
+ call assert_equal(1, &modified)
+ set cpo+=+
+ write X2
+ call assert_equal(0, &modified)
+ close!
+ call delete('Xfile')
+ call delete('X1')
+ call delete('X2')
+ let &cpo = save_cpo
+endfunc
+
+" Test for the '*' flag in 'cpo' (':*' is same as ':@')
+func Test_cpo_star()
+ throw 'Skipped: Nvim does not support cpoptions flag "*"'
+ let save_cpo = &cpo
+ let x = 0
+ new
+ set cpo-=*
+ let @a = 'let x += 1'
+ call assert_fails('*a', 'E20:')
+ set cpo+=*
+ *a
+ call assert_equal(1, x)
+ close!
+ let &cpo = save_cpo
+endfunc
+
+" Test for the '<' flag in 'cpo' is in the test_mapping.vim file
+
+" Test for the '>' flag in 'cpo' (use a new line when appending to a register)
+func Test_cpo_gt()
+ let save_cpo = &cpo
+ new
+ call setline(1, 'one two')
+ set cpo-=>
+ let @r = ''
+ normal gg"Rye
+ normal "Rye
+ call assert_equal("oneone", @r)
+ set cpo+=>
+ let @r = ''
+ normal gg"Rye
+ normal "Rye
+ call assert_equal("\none\none", @r)
+ close!
+ let &cpo = save_cpo
+endfunc
+
+" Test for the ';' flag in 'cpo'
+" Test for t,f,F,T movement commands and 'cpo-;' setting
+func Test_cpo_semicolon()
+ let save_cpo = &cpo
+ new
+ call append(0, ["aaa two three four", " zzz", "yyy ",
+ \ "bbb yee yoo four", "ccc two three four",
+ \ "ddd yee yoo four"])
+ set cpo-=;
+ 1
+ normal! 0tt;D
+ 2
+ normal! 0fz;D
+ 3
+ normal! $Fy;D
+ 4
+ normal! $Ty;D
+ set cpo+=;
+ 5
+ normal! 0tt;;D
+ 6
+ normal! $Ty;;D
+
+ call assert_equal('aaa two', getline(1))
+ call assert_equal(' z', getline(2))
+ call assert_equal('y', getline(3))
+ call assert_equal('bbb y', getline(4))
+ call assert_equal('ccc', getline(5))
+ call assert_equal('ddd yee y', getline(6))
+ close!
+ let &cpo = save_cpo
+endfunc
+
+" Test for the '#' flag in 'cpo' (count before 'D', 'o' and 'O' operators)
+func Test_cpo_hash()
+ throw 'Skipped: Nvim does not support cpoptions flag "#"'
+ let save_cpo = &cpo
+ new
+ set cpo-=#
+ call setline(1, ['one', 'two', 'three'])
+ normal gg2D
+ call assert_equal(['three'], getline(1, '$'))
+ normal gg2ofour
+ call assert_equal(['three', 'four', 'four'], getline(1, '$'))
+ normal gg2Otwo
+ call assert_equal(['two', 'two', 'three', 'four', 'four'], getline(1, '$'))
+ %d
+ set cpo+=#
+ call setline(1, ['one', 'two', 'three'])
+ normal gg2D
+ call assert_equal(['', 'two', 'three'], getline(1, '$'))
+ normal gg2oone
+ call assert_equal(['', 'one', 'two', 'three'], getline(1, '$'))
+ normal gg2Ozero
+ call assert_equal(['zero', '', 'one', 'two', 'three'], getline(1, '$'))
+ close!
+ let &cpo = save_cpo
+endfunc
+
+" Test for the '&' flag in 'cpo'. The swap file is kept when a buffer is still
+" loaded and ':preserve' is used.
+func Test_cpo_ampersand()
+ throw 'Skipped: Nvim does not support cpoptions flag "&"'
+ call writefile(['one'], 'Xfile')
+ let after =<< trim [CODE]
+ set cpo+=&
+ preserve
+ qall
+ [CODE]
+ if RunVim([], after, 'Xfile')
+ call assert_equal(1, filereadable('.Xfile.swp'))
+ call delete('.Xfile.swp')
+ endif
+ call delete('Xfile')
+endfunc
+
+" Test for the '\' flag in 'cpo' (backslash in a [] range in a search pattern)
+func Test_cpo_backslash()
+ throw 'Skipped: Nvim does not support cpoptions flag "\"'
+ let save_cpo = &cpo
+ new
+ call setline(1, ['', " \\-string"])
+ set cpo-=\
+ exe 'normal gg/[ \-]' .. "\<CR>n"
+ call assert_equal(3, col('.'))
+ set cpo+=\
+ exe 'normal gg/[ \-]' .. "\<CR>n"
+ call assert_equal(2, col('.'))
+ close!
+ let &cpo = save_cpo
+endfunc
+
+" Test for the '/' flag in 'cpo' is in the test_substitute.vim file
+
+" Test for the '{' flag in 'cpo' (the "{" and "}" commands stop at a {
+" character at the start of a line)
+func Test_cpo_brace()
+ throw 'Skipped: Nvim does not support cpoptions flag "{"'
+ let save_cpo = &cpo
+ new
+ call setline(1, ['', '{', ' int i;', '}', ''])
+ set cpo-={
+ normal gg}
+ call assert_equal(5, line('.'))
+ normal G{
+ call assert_equal(1, line('.'))
+ set cpo+={
+ normal gg}
+ call assert_equal(2, line('.'))
+ normal G{
+ call assert_equal(2, line('.'))
+ close!
+ let &cpo = save_cpo
+endfunc
+
+" Test for the '.' flag in 'cpo' (:cd command fails if the current buffer is
+" modified)
+func Test_cpo_dot()
+ throw 'Skipped: Nvim does not support cpoptions flag "."'
+ let save_cpo = &cpo
+ new Xfoo
+ call setline(1, 'foo')
+ let save_dir = getcwd()
+ set cpo+=.
+
+ " :cd should fail when buffer is modified and 'cpo' contains dot.
+ call assert_fails('cd ..', 'E747:')
+ call assert_equal(save_dir, getcwd())
+
+ " :cd with exclamation mark should succeed.
+ cd! ..
+ call assert_notequal(save_dir, getcwd())
+
+ " :cd should succeed when buffer has been written.
+ w!
+ exe 'cd ' .. fnameescape(save_dir)
+ call assert_equal(save_dir, getcwd())
+
+ call delete('Xfoo')
+ set cpo&
+ close!
+ let &cpo = save_cpo
+endfunc
+
+" vim: shiftwidth=2 sts=2 expandtab
diff --git a/src/nvim/testdir/test_display.vim b/src/nvim/testdir/test_display.vim
index 13796449ab..679fe89628 100644
--- a/src/nvim/testdir/test_display.vim
+++ b/src/nvim/testdir/test_display.vim
@@ -195,8 +195,6 @@ func Test_edit_long_file_name()
call VerifyScreenDump(buf, 'Test_long_file_name_1', {})
- call term_sendkeys(buf, ":q\<cr>")
-
" clean up
call StopVimInTerminal(buf)
call delete(longName)
diff --git a/src/nvim/testdir/test_edit.vim b/src/nvim/testdir/test_edit.vim
index 9783ed19a7..89fd73351d 100644
--- a/src/nvim/testdir/test_edit.vim
+++ b/src/nvim/testdir/test_edit.vim
@@ -1433,9 +1433,7 @@ endfunc
func Test_edit_rightleft()
" Cursor in rightleft mode moves differently
- if !exists("+rightleft")
- return
- endif
+ CheckFeature rightleft
call NewWindow(10, 20)
call setline(1, ['abc', 'def', 'ghi'])
call cursor(1, 2)
@@ -1480,6 +1478,13 @@ func Test_edit_rightleft()
\" ihg",
\" ~"]
call assert_equal(join(expect, "\n"), join(lines, "\n"))
+ %d _
+ " call test_override('redraw_flag', 1)
+ " call test_override('char_avail', 1)
+ call feedkeys("a\<C-V>x41", "xt")
+ redraw!
+ call assert_equal(repeat(' ', 19) .. 'A', Screenline(1))
+ " call test_override('ALL', 0)
set norightleft
bw!
endfunc
@@ -1724,40 +1729,6 @@ func Test_edit_illegal_filename()
close!
endfunc
-" Test for inserting text in a line with only spaces ('H' flag in 'cpoptions')
-func Test_edit_cpo_H()
- throw 'Skipped: Nvim does not support cpoptions flag "H"'
- new
- call setline(1, ' ')
- normal! Ia
- call assert_equal(' a', getline(1))
- set cpo+=H
- call setline(1, ' ')
- normal! Ia
- call assert_equal(' a ', getline(1))
- set cpo-=H
- close!
-endfunc
-
-" Test for inserting tab in virtual replace mode ('L' flag in 'cpoptions')
-func Test_edit_cpo_L()
- new
- call setline(1, 'abcdefghijklmnopqr')
- exe "normal 0gR\<Tab>"
- call assert_equal("\<Tab>ijklmnopqr", getline(1))
- set cpo+=L
- set list
- call setline(1, 'abcdefghijklmnopqr')
- exe "normal 0gR\<Tab>"
- call assert_equal("\<Tab>cdefghijklmnopqr", getline(1))
- set nolist
- call setline(1, 'abcdefghijklmnopqr')
- exe "normal 0gR\<Tab>"
- call assert_equal("\<Tab>ijklmnopqr", getline(1))
- set cpo-=L
- %bw!
-endfunc
-
" Test for editing a directory
func Test_edit_is_a_directory()
CheckEnglish
@@ -1902,6 +1873,107 @@ func Test_edit_insertmode_ex_edit()
call delete('Xtest_edit_insertmode_ex_edit')
endfunc
+" Pressing escape in 'insertmode' should beep
+func Test_edit_insertmode_esc_beeps()
+ throw "Skipped: Nvim does not support 'insertmode'"
+ new
+ set insertmode
+ call assert_beeps("call feedkeys(\"one\<Esc>\", 'xt')")
+ set insertmode&
+ " unsupported CTRL-G command should beep in insert mode.
+ call assert_beeps("normal i\<C-G>l")
+ close!
+endfunc
+
+" Test for 'hkmap' and 'hkmapp'
+func Test_edit_hkmap()
+ CheckFeature rightleft
+ if has('win32') && !has('gui')
+ " Test fails on the MS-Windows terminal version
+ return
+ endif
+ new
+
+ set revins hkmap
+ let str = 'abcdefghijklmnopqrstuvwxyz'
+ let str ..= 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'
+ let str ..= '`/'',.;'
+ call feedkeys('i' .. str, 'xt')
+ let expected = "óõú,.;"
+ let expected ..= "ZYXWVUTSRQPONMLKJIHGFEDCBA"
+ let expected ..= "æèñ'äåàãø/ôíîöêìçïéòë÷âáðù"
+ call assert_equal(expected, getline(1))
+
+ %d
+ set revins hkmap hkmapp
+ let str = 'abcdefghijklmnopqrstuvwxyz'
+ let str ..= 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'
+ call feedkeys('i' .. str, 'xt')
+ let expected = "õYXWVUTSRQóOïíLKJIHGFEDêBA"
+ let expected ..= "öòXùåèúæø'ôñðîì÷çéäâóǟãëáà"
+ call assert_equal(expected, getline(1))
+
+ set revins& hkmap& hkmapp&
+ close!
+endfunc
+
+" Test for 'allowrevins' and using CTRL-_ in insert mode
+func Test_edit_allowrevins()
+ CheckFeature rightleft
+ new
+ set allowrevins
+ call feedkeys("iABC\<C-_>DEF\<C-_>GHI", 'xt')
+ call assert_equal('ABCFEDGHI', getline(1))
+ set allowrevins&
+ close!
+endfunc
+
+" Test for inserting a register in insert mode using CTRL-R
+func Test_edit_insert_reg()
+ throw 'Skipped: use test/functional/legacy/edit_spec.lua'
+ new
+ let g:Line = ''
+ func SaveFirstLine()
+ let g:Line = Screenline(1)
+ return 'r'
+ endfunc
+ inoremap <expr> <buffer> <F2> SaveFirstLine()
+ call test_override('redraw_flag', 1)
+ call test_override('char_avail', 1)
+ let @r = 'sample'
+ call feedkeys("a\<C-R>=SaveFirstLine()\<CR>", "xt")
+ call assert_equal('"', g:Line)
+ call test_override('ALL', 0)
+ close!
+endfunc
+
+" When a character is inserted at the last position of the last line in a
+" window, the window contents should be scrolled one line up. If the top line
+" is part of a fold, then the entire fold should be scrolled up.
+func Test_edit_lastline_scroll()
+ new
+ let h = winheight(0)
+ let lines = ['one', 'two', 'three']
+ let lines += repeat(['vim'], h - 4)
+ call setline(1, lines)
+ call setline(h, repeat('x', winwidth(0) - 1))
+ call feedkeys("GAx", 'xt')
+ redraw!
+ call assert_equal(h - 1, winline())
+ call assert_equal(2, line('w0'))
+
+ " scroll with a fold
+ 1,2fold
+ normal gg
+ call setline(h + 1, repeat('x', winwidth(0) - 1))
+ call feedkeys("GAx", 'xt')
+ redraw!
+ call assert_equal(h - 1, winline())
+ call assert_equal(3, line('w0'))
+
+ close!
+endfunc
+
func Test_edit_browse()
" in the GUI this opens a file picker, we only test the terminal behavior
CheckNotGui
diff --git a/src/nvim/testdir/test_eval_stuff.vim b/src/nvim/testdir/test_eval_stuff.vim
index 851048ec5b..46482c34a1 100644
--- a/src/nvim/testdir/test_eval_stuff.vim
+++ b/src/nvim/testdir/test_eval_stuff.vim
@@ -20,13 +20,8 @@ func Test_nocatch_restore_silent_emsg()
throw 1
catch
endtry
- echoerr 'wrong'
- let c1 = nr2char(screenchar(&lines, 1))
- let c2 = nr2char(screenchar(&lines, 2))
- let c3 = nr2char(screenchar(&lines, 3))
- let c4 = nr2char(screenchar(&lines, 4))
- let c5 = nr2char(screenchar(&lines, 5))
- call assert_equal('wrong', c1 . c2 . c3 . c4 . c5)
+ echoerr 'wrong again'
+ call assert_equal('wrong again', ScreenLine(&lines))
endfunc
func Test_mkdir_p()
diff --git a/src/nvim/testdir/test_ex_mode.vim b/src/nvim/testdir/test_ex_mode.vim
index 2f734cba26..93100732ed 100644
--- a/src/nvim/testdir/test_ex_mode.vim
+++ b/src/nvim/testdir/test_ex_mode.vim
@@ -97,7 +97,6 @@ func Test_Ex_substitute()
call term_sendkeys(buf, ":vi\<CR>")
call WaitForAssert({-> assert_match('foo bar', term_getline(buf, 1))}, 1000)
- call term_sendkeys(buf, ":q!\n")
call StopVimInTerminal(buf)
endfunc
diff --git a/src/nvim/testdir/test_excmd.vim b/src/nvim/testdir/test_excmd.vim
index 04ab8e288f..582dcaac2c 100644
--- a/src/nvim/testdir/test_excmd.vim
+++ b/src/nvim/testdir/test_excmd.vim
@@ -481,8 +481,8 @@ func Test_redir_cmd()
call assert_fails('redir abc', 'E475:')
call assert_fails('redir => 1abc', 'E474:')
call assert_fails('redir => a b', 'E488:')
- call assert_fails('redir => abc[1]', 'E475:')
- let b=0zFF
+ call assert_fails('redir => abc[1]', 'E121:')
+ let b = 0zFF
call assert_fails('redir =>> b', 'E734:')
unlet b
diff --git a/src/nvim/testdir/test_exists.vim b/src/nvim/testdir/test_exists.vim
index 471c77853d..62c66192ef 100644
--- a/src/nvim/testdir/test_exists.vim
+++ b/src/nvim/testdir/test_exists.vim
@@ -68,6 +68,10 @@ func Test_exists()
" Existing environment variable
let $EDITOR_NAME = 'Vim Editor'
call assert_equal(1, exists('$EDITOR_NAME'))
+ if has('unix')
+ " ${name} environment variables are supported only on Unix-like systems
+ call assert_equal(1, exists('${VIM}'))
+ endif
" Non-existing environment variable
call assert_equal(0, exists('$NON_ENV_VAR'))
@@ -323,3 +327,5 @@ endfunc
func Test_exists_funcarg()
call FuncArg_Tests("arg1", "arg2")
endfunc
+
+" vim: shiftwidth=2 sts=2 expandtab
diff --git a/src/nvim/testdir/test_expand.vim b/src/nvim/testdir/test_expand.vim
index aa131a49ff..4f5bb67d21 100644
--- a/src/nvim/testdir/test_expand.vim
+++ b/src/nvim/testdir/test_expand.vim
@@ -90,14 +90,26 @@ func Test_expandcmd()
" Test for expression expansion `=
let $FOO= "blue"
call assert_equal("blue sky", expandcmd("`=$FOO .. ' sky'`"))
+ let x = expandcmd("`=axbycz`")
+ call assert_equal('`=axbycz`', x)
+ call assert_fails('let x = expandcmd("`=axbycz`", #{errmsg: 1})', 'E121:')
+ let x = expandcmd("`=axbycz`", #{abc: []})
+ call assert_equal('`=axbycz`', x)
" Test for env variable with spaces
let $FOO= "foo bar baz"
call assert_equal("e foo bar baz", expandcmd("e $FOO"))
- if has('unix')
- " test for using the shell to expand a command argument
- call assert_equal('{1..4}', expandcmd('{1..4}'))
+ if has('unix') && executable('bash')
+ " test for using the shell to expand a command argument.
+ " only bash supports the {..} syntax
+ set shell=bash
+ let x = expandcmd('{1..4}')
+ call assert_equal('{1..4}', x)
+ call assert_fails("let x = expandcmd('{1..4}', #{errmsg: v:true})", 'E77:')
+ let x = expandcmd('{1..4}', #{error: v:true})
+ call assert_equal('{1..4}', x)
+ set shell&
endif
unlet $FOO
diff --git a/src/nvim/testdir/test_expand_func.vim b/src/nvim/testdir/test_expand_func.vim
index 80bfdb8553..454d76f0aa 100644
--- a/src/nvim/testdir/test_expand_func.vim
+++ b/src/nvim/testdir/test_expand_func.vim
@@ -139,6 +139,7 @@ func Test_expand_wildignore()
call assert_equal('test_expand_func.vim', expand('test_expand_func.vim', 1))
call assert_equal(['test_expand_func.vim'],
\ expand('test_expand_func.vim', 1, 1))
+ call assert_fails("call expand('*', [])", 'E745:')
set wildignore&
endfunc
diff --git a/src/nvim/testdir/test_expr.vim b/src/nvim/testdir/test_expr.vim
index 66660ab75e..ea874cc398 100644
--- a/src/nvim/testdir/test_expr.vim
+++ b/src/nvim/testdir/test_expr.vim
@@ -65,6 +65,8 @@ func Test_strgetchar()
call assert_equal(-1, strgetchar('axb', -1))
call assert_equal(-1, strgetchar('axb', 3))
call assert_equal(-1, strgetchar('', 0))
+ call assert_fails("let c=strgetchar([], 1)", 'E730:')
+ call assert_fails("let c=strgetchar('axb', [])", 'E745:')
endfunc
func Test_strcharpart()
@@ -485,49 +487,6 @@ function Test_max_min_errors()
call assert_fails('call min(v:true)', 'min()')
endfunc
-func Test_substitute_expr()
- let g:val = 'XXX'
- call assert_equal('XXX', substitute('yyy', 'y*', '\=g:val', ''))
- call assert_equal('XXX', substitute('yyy', 'y*', {-> g:val}, ''))
- call assert_equal("-\u1b \uf2-", substitute("-%1b %f2-", '%\(\x\x\)',
- \ '\=nr2char("0x" . submatch(1))', 'g'))
- call assert_equal("-\u1b \uf2-", substitute("-%1b %f2-", '%\(\x\x\)',
- \ {-> nr2char("0x" . submatch(1))}, 'g'))
-
- call assert_equal('231', substitute('123', '\(.\)\(.\)\(.\)',
- \ {-> submatch(2) . submatch(3) . submatch(1)}, ''))
-
- func Recurse()
- return substitute('yyy', 'y\(.\)y', {-> submatch(1)}, '')
- endfunc
- " recursive call works
- call assert_equal('-y-x-', substitute('xxx', 'x\(.\)x', {-> '-' . Recurse() . '-' . submatch(1) . '-'}, ''))
-endfunc
-
-func Test_invalid_submatch()
- " This was causing invalid memory access in Vim-7.4.2232 and older
- call assert_fails("call substitute('x', '.', {-> submatch(10)}, '')", 'E935:')
-endfunc
-
-func Test_substitute_expr_arg()
- call assert_equal('123456789-123456789=', substitute('123456789',
- \ '\(.\)\(.\)\(.\)\(.\)\(.\)\(.\)\(.\)\(.\)\(.\)',
- \ {m -> m[0] . '-' . m[1] . m[2] . m[3] . m[4] . m[5] . m[6] . m[7] . m[8] . m[9] . '='}, ''))
-
- call assert_equal('123456-123456=789', substitute('123456789',
- \ '\(.\)\(.\)\(.\)\(a*\)\(n*\)\(.\)\(.\)\(.\)\(x*\)',
- \ {m -> m[0] . '-' . m[1] . m[2] . m[3] . m[4] . m[5] . m[6] . m[7] . m[8] . m[9] . '='}, ''))
-
- call assert_equal('123456789-123456789x=', substitute('123456789',
- \ '\(.\)\(.\)\(.*\)',
- \ {m -> m[0] . '-' . m[1] . m[2] . m[3] . 'x' . m[4] . m[5] . m[6] . m[7] . m[8] . m[9] . '='}, ''))
-
- call assert_fails("call substitute('xxx', '.', {m -> string(add(m, 'x'))}, '')", 'E742:')
- call assert_fails("call substitute('xxx', '.', {m -> string(insert(m, 'x'))}, '')", 'E742:')
- call assert_fails("call substitute('xxx', '.', {m -> string(extend(m, ['x']))}, '')", 'E742:')
- call assert_fails("call substitute('xxx', '.', {m -> string(remove(m, 1))}, '')", 'E742:')
-endfunc
-
func Test_function_with_funcref()
let s:f = function('type')
let s:fref = function(s:f)
@@ -569,6 +528,7 @@ func Test_setmatches()
endif
eval set->setmatches()
call assert_equal(exp, getmatches())
+ call assert_fails('let m = setmatches([], [])', 'E745:')
endfunc
func Test_empty_concatenate()
diff --git a/src/nvim/testdir/test_fixeol.vim b/src/nvim/testdir/test_fixeol.vim
index 9d6c900bdb..41d47d6a06 100644
--- a/src/nvim/testdir/test_fixeol.vim
+++ b/src/nvim/testdir/test_fixeol.vim
@@ -48,4 +48,71 @@ func Test_fixeol()
enew!
endfunc
+func Test_eof()
+ let data = 0z68656c6c6f.0d0a.776f726c64 " "hello\r\nworld"
+
+ " 1. Eol, Eof
+ " read
+ call writefile(data + 0z0d0a.1a, 'XXEolEof')
+ e! XXEolEof
+ call assert_equal(['hello', 'world'], getline(1, 2))
+ call assert_equal([1, 1], [&eol, &eof])
+ " write
+ set fixeol
+ w!
+ call assert_equal(data + 0z0d0a, readblob('XXEolEof'))
+ set nofixeol
+ w!
+ call assert_equal(data + 0z0d0a.1a, readblob('XXEolEof'))
+
+ " 2. NoEol, Eof
+ " read
+ call writefile(data + 0z1a, 'XXNoEolEof')
+ e! XXNoEolEof
+ call assert_equal(['hello', 'world'], getline(1, 2))
+ call assert_equal([0, 1], [&eol, &eof])
+ " write
+ set fixeol
+ w!
+ call assert_equal(data + 0z0d0a, readblob('XXNoEolEof'))
+ set nofixeol
+ w!
+ call assert_equal(data + 0z1a, readblob('XXNoEolEof'))
+
+ " 3. Eol, NoEof
+ " read
+ call writefile(data + 0z0d0a, 'XXEolNoEof')
+ e! XXEolNoEof
+ call assert_equal(['hello', 'world'], getline(1, 2))
+ call assert_equal([1, 0], [&eol, &eof])
+ " write
+ set fixeol
+ w!
+ call assert_equal(data + 0z0d0a, readblob('XXEolNoEof'))
+ set nofixeol
+ w!
+ call assert_equal(data + 0z0d0a, readblob('XXEolNoEof'))
+
+ " 4. NoEol, NoEof
+ " read
+ call writefile(data, 'XXNoEolNoEof')
+ e! XXNoEolNoEof
+ call assert_equal(['hello', 'world'], getline(1, 2))
+ call assert_equal([0, 0], [&eol, &eof])
+ " write
+ set fixeol
+ w!
+ call assert_equal(data + 0z0d0a, readblob('XXNoEolNoEof'))
+ set nofixeol
+ w!
+ call assert_equal(data, readblob('XXNoEolNoEof'))
+
+ call delete('XXEolEof')
+ call delete('XXNoEolEof')
+ call delete('XXEolNoEof')
+ call delete('XXNoEolNoEof')
+ set ff& fixeol& eof& eol&
+ enew!
+endfunc
+
" vim: shiftwidth=2 sts=2 expandtab
diff --git a/src/nvim/testdir/test_functions.vim b/src/nvim/testdir/test_functions.vim
index fa79aaf6d7..d2603809b9 100644
--- a/src/nvim/testdir/test_functions.vim
+++ b/src/nvim/testdir/test_functions.vim
@@ -19,6 +19,27 @@ func Test_00_bufexists()
call assert_equal(0, bufexists('Xfoo'))
endfunc
+func Test_has()
+ throw 'Skipped: Nvim has removed some features'
+ call assert_equal(1, has('eval'))
+ call assert_equal(1, has('eval', 1))
+
+ if has('unix')
+ call assert_equal(1, or(has('ttyin'), 1))
+ call assert_equal(0, and(has('ttyout'), 0))
+ call assert_equal(1, has('multi_byte_encoding'))
+ endif
+ call assert_equal(1, has('vcon', 1))
+ call assert_equal(1, has('mouse_gpm_enabled', 1))
+
+ call assert_equal(0, has('nonexistent'))
+ call assert_equal(0, has('nonexistent', 1))
+
+ " Will we ever have patch 9999?
+ let ver = 'patch-' .. v:version / 100 .. '.' .. v:version % 100 .. '.9999'
+ call assert_equal(0, has(ver))
+endfunc
+
func Test_empty()
call assert_equal(1, empty(''))
call assert_equal(0, empty('a'))
@@ -190,7 +211,7 @@ func Test_str2nr()
if has('float')
call assert_fails('call str2nr(1.2)', 'E806:')
endif
- call assert_fails('call str2nr(10, [])', 'E474:')
+ call assert_fails('call str2nr(10, [])', 'E745:')
endfunc
func Test_strftime()
@@ -383,6 +404,8 @@ func Test_strpart()
call assert_equal('abcdefg', 'abcdefg'->strpart(-2))
call assert_equal('fg', strpart('abcdefg', 5, 4))
call assert_equal('defg', strpart('abcdefg', 3))
+ call assert_equal('', strpart('abcdefg', 10))
+ call assert_fails("let s=strpart('abcdef', [])", 'E745:')
call assert_equal('lép', strpart('éléphant', 2, 4))
call assert_equal('léphant', strpart('éléphant', 2))
@@ -552,6 +575,15 @@ endfunc
func Test_tr()
call assert_equal('foo', tr('bar', 'bar', 'foo'))
call assert_equal('zxy', 'cab'->tr('abc', 'xyz'))
+ call assert_fails("let s=tr([], 'abc', 'def')", 'E730:')
+ call assert_fails("let s=tr('abc', [], 'def')", 'E730:')
+ call assert_fails("let s=tr('abc', 'abc', [])", 'E730:')
+ call assert_fails("let s=tr('abcd', 'abcd', 'def')", 'E475:')
+ " set encoding=latin1
+ call assert_fails("let s=tr('abcd', 'abcd', 'def')", 'E475:')
+ call assert_equal('hEllO', tr('hello', 'eo', 'EO'))
+ call assert_equal('hello', tr('hello', 'xy', 'ab'))
+ set encoding=utf8
endfunc
" Tests for the mode() function
@@ -766,18 +798,41 @@ func Test_mode()
delfunction OperatorFunc
endfunc
+" Test for append()
func Test_append()
enew!
split
call append(0, ["foo"])
+ call append(1, [])
+ call append(1, v:_null_list)
+ call assert_equal(['foo', ''], getline(1, '$'))
split
only
undo
+ undo
" Using $ instead of '$' must give an error
call assert_fails("call append($, 'foobar')", 'E116:')
endfunc
+" Test for setline()
+func Test_setline()
+ new
+ call setline(0, ["foo"])
+ call setline(0, [])
+ call setline(0, v:_null_list)
+ call setline(1, ["bar"])
+ call setline(1, [])
+ call setline(1, v:_null_list)
+ call setline(2, [])
+ call setline(2, v:_null_list)
+ call setline(3, [])
+ call setline(3, v:_null_list)
+ call setline(2, ["baz"])
+ call assert_equal(['bar', 'baz'], getline(1, '$'))
+ close!
+endfunc
+
func Test_getbufvar()
let bnr = bufnr('%')
let b:var_num = '1234'
@@ -851,6 +906,8 @@ func Test_stridx()
call assert_equal(-1, stridx('hello', 'l', 10))
call assert_equal(2, stridx('hello', 'll'))
call assert_equal(-1, stridx('hello', 'hello world'))
+ call assert_fails("let n=stridx('hello', [])", 'E730:')
+ call assert_fails("let n=stridx([], 'l')", 'E730:')
endfunc
func Test_strridx()
@@ -867,6 +924,8 @@ func Test_strridx()
call assert_equal(-1, strridx('hello', 'l', -1))
call assert_equal(2, strridx('hello', 'll'))
call assert_equal(-1, strridx('hello', 'hello world'))
+ call assert_fails("let n=strridx('hello', [])", 'E730:')
+ call assert_fails("let n=strridx([], 'l')", 'E730:')
endfunc
func Test_match_func()
@@ -876,6 +935,12 @@ func Test_match_func()
call assert_equal(-1, match('testing', 'ing', 8))
call assert_equal(1, match(['vim', 'testing', 'execute'], 'ing'))
call assert_equal(-1, match(['vim', 'testing', 'execute'], 'img'))
+ call assert_fails("let x=match('vim', [])", 'E730:')
+ call assert_equal(3, match(['a', 'b', 'c', 'a'], 'a', 1))
+ call assert_equal(-1, match(['a', 'b', 'c', 'a'], 'a', 5))
+ call assert_equal(4, match('testing', 'ing', -1))
+ call assert_fails("let x=match('testing', 'ing', 0, [])", 'E745:')
+ call assert_equal(-1, match(v:_null_list, 2))
endfunc
func Test_matchend()
@@ -982,6 +1047,7 @@ func Test_byte2line_line2byte()
bw!
endfunc
+" Test for byteidx() and byteidxcomp() functions
func Test_byteidx()
let a = '.é.' " one char of two bytes
call assert_equal(0, byteidx(a, 0))
@@ -1001,6 +1067,7 @@ func Test_byteidx()
call assert_equal(4, b->byteidx(2))
call assert_equal(5, b->byteidx(3))
call assert_equal(-1, b->byteidx(4))
+ call assert_fails("call byteidx([], 0)", 'E730:')
call assert_equal(0, b->byteidxcomp(0))
call assert_equal(1, b->byteidxcomp(1))
@@ -1008,6 +1075,7 @@ func Test_byteidx()
call assert_equal(4, b->byteidxcomp(3))
call assert_equal(5, b->byteidxcomp(4))
call assert_equal(-1, b->byteidxcomp(5))
+ call assert_fails("call byteidxcomp([], 0)", 'E730:')
endfunc
" Test for charidx()
@@ -1033,8 +1101,8 @@ func Test_charidx()
call assert_fails('let x = charidx([], 1)', 'E474:')
call assert_fails('let x = charidx("abc", [])', 'E474:')
call assert_fails('let x = charidx("abc", 1, [])', 'E474:')
- call assert_fails('let x = charidx("abc", 1, -1)', 'E474:')
- call assert_fails('let x = charidx("abc", 1, 2)', 'E474:')
+ call assert_fails('let x = charidx("abc", 1, -1)', 'E1023:')
+ call assert_fails('let x = charidx("abc", 1, 2)', 'E1023:')
endfunc
func Test_count()
@@ -1230,6 +1298,22 @@ func Test_col()
xunmap <F2>
delfunc T
+ " Test for the visual line start and end marks '< and '>
+ call setline(1, ['one', 'one two', 'one two three'])
+ "normal! ggVG
+ call feedkeys("ggVG\<Esc>", 'xt')
+ call assert_equal(1, col("'<"))
+ call assert_equal(14, col("'>"))
+ " Delete the last line of the visually selected region
+ $d
+ call assert_notequal(14, col("'>"))
+
+ " Test with 'virtualedit'
+ set virtualedit=all
+ call cursor(1, 10)
+ call assert_equal(4, col('.'))
+ set virtualedit&
+
bw!
endfunc
@@ -1273,12 +1357,15 @@ endfunc
" Test for the inputdialog() function
func Test_inputdialog()
- CheckNotGui
-
- call feedkeys(":let v=inputdialog('Q:', 'xx', 'yy')\<CR>\<CR>", 'xt')
- call assert_equal('xx', v)
- call feedkeys(":let v=inputdialog('Q:', 'xx', 'yy')\<CR>\<Esc>", 'xt')
- call assert_equal('yy', v)
+ if has('gui_running')
+ call assert_fails('let v=inputdialog([], "xx")', 'E730:')
+ call assert_fails('let v=inputdialog("Q", [])', 'E730:')
+ else
+ call feedkeys(":let v=inputdialog('Q:', 'xx', 'yy')\<CR>\<CR>", 'xt')
+ call assert_equal('xx', v)
+ call feedkeys(":let v=inputdialog('Q:', 'xx', 'yy')\<CR>\<Esc>", 'xt')
+ call assert_equal('yy', v)
+ endif
endfunc
" Test for inputlist()
@@ -1329,6 +1416,7 @@ func Test_balloon_show()
call balloon_show('hi!')
if !has('gui_running')
call balloon_show(range(3))
+ call balloon_show([])
endif
endfunc
@@ -1640,11 +1728,11 @@ func Test_libcall_libcallnr()
call assert_equal(4, 'abcd'->libcallnr(libc, 'strlen'))
call assert_equal(char2nr('A'), char2nr('a')->libcallnr(libc, 'toupper'))
- call assert_fails("call libcall(libc, 'Xdoesnotexist_', '')", 'E364:')
- call assert_fails("call libcallnr(libc, 'Xdoesnotexist_', '')", 'E364:')
+ call assert_fails("call libcall(libc, 'Xdoesnotexist_', '')", ['', 'E364:'])
+ call assert_fails("call libcallnr(libc, 'Xdoesnotexist_', '')", ['', 'E364:'])
- call assert_fails("call libcall('Xdoesnotexist_', 'getenv', 'HOME')", 'E364:')
- call assert_fails("call libcallnr('Xdoesnotexist_', 'strlen', 'abcd')", 'E364:')
+ call assert_fails("call libcall('Xdoesnotexist_', 'getenv', 'HOME')", ['', 'E364:'])
+ call assert_fails("call libcallnr('Xdoesnotexist_', 'strlen', 'abcd')", ['', 'E364:'])
endfunc
sandbox function Fsandbox()
@@ -1763,7 +1851,7 @@ func Test_confirm()
call assert_equal(2, a)
" confirm() should return 0 when pressing CTRL-C.
- call feedkeys("\<C-c>", 'L')
+ call feedkeys("\<C-C>", 'L')
let a = confirm('Are you sure?', "&Yes\n&No")
call assert_equal(0, a)
@@ -1858,6 +1946,7 @@ func Test_call()
call assert_equal(3, 'len'->call([123]))
call assert_fails("call call('len', 123)", 'E714:')
call assert_equal(0, call('', []))
+ call assert_equal(0, call('len', v:_null_list))
function Mylen() dict
return len(self.data)
@@ -1871,6 +1960,9 @@ endfunc
func Test_char2nr()
call assert_equal(12354, char2nr('あ', 1))
call assert_equal(120, 'x'->char2nr())
+ " set encoding=latin1
+ call assert_equal(120, 'x'->char2nr())
+ set encoding=utf-8
endfunc
func Test_charclass()
@@ -2043,6 +2135,7 @@ func Test_range()
" index()
call assert_equal(1, index(range(1, 5), 2))
+ call assert_fails("echo index([1, 2], 1, [])", 'E745:')
" inputlist()
call feedkeys(":let result = inputlist(range(10))\<CR>1\<CR>", 'x')
@@ -2204,6 +2297,14 @@ func Test_range()
" uniq()
call assert_equal([0, 1, 2, 3, 4], uniq(range(5)))
+
+ " errors
+ call assert_fails('let x=range(2, 8, 0)', 'E726:')
+ call assert_fails('let x=range(3, 1)', 'E727:')
+ call assert_fails('let x=range(1, 3, -2)', 'E727:')
+ call assert_fails('let x=range([])', 'E745:')
+ call assert_fails('let x=range(1, [])', 'E745:')
+ call assert_fails('let x=range(1, 4, [])', 'E745:')
endfunc
func Test_garbagecollect_now_fails()
@@ -2255,6 +2356,13 @@ func Test_nr2char()
call assert_equal("\x80\xfc\b" .. nr2char(0x40000000), eval('"\<M-' .. nr2char(0x40000000) .. '>"'))
endfunc
+" Test for screenattr(), screenchar() and screenchars() functions
+func Test_screen_functions()
+ call assert_equal(-1, screenattr(-1, -1))
+ call assert_equal(-1, screenchar(-1, -1))
+ call assert_equal([], screenchars(-1, -1))
+endfunc
+
" Test for getcurpos() and setpos()
func Test_getcurpos_setpos()
new
diff --git a/src/nvim/testdir/test_global.vim b/src/nvim/testdir/test_global.vim
index cb6851250c..bbfe374f51 100644
--- a/src/nvim/testdir/test_global.vim
+++ b/src/nvim/testdir/test_global.vim
@@ -39,7 +39,7 @@ endfunc
func Test_global_error()
call assert_fails('g\\a', 'E10:')
call assert_fails('g', 'E148:')
- call assert_fails('g/\(/y', 'E476:')
+ call assert_fails('g/\(/y', 'E54:')
endfunc
" Test for printing lines using :g with different search patterns
diff --git a/src/nvim/testdir/test_increment.vim b/src/nvim/testdir/test_increment.vim
index 2559654f25..3c2b88ef9f 100644
--- a/src/nvim/testdir/test_increment.vim
+++ b/src/nvim/testdir/test_increment.vim
@@ -476,6 +476,10 @@ func Test_visual_increment_20()
exec "norm! \<C-A>"
call assert_equal(["b"], getline(1, '$'))
call assert_equal([0, 1, 1, 0], getpos('.'))
+ " decrement a and A and increment z and Z
+ call setline(1, ['a', 'A', 'z', 'Z'])
+ exe "normal 1G\<C-X>2G\<C-X>3G\<C-A>4G\<C-A>"
+ call assert_equal(['a', 'A', 'z', 'Z'], getline(1, '$'))
endfunc
" 21) block-wise increment on part of hexadecimal
@@ -566,12 +570,14 @@ endfunc
" 1) <ctrl-a>
" 0b11111111111111111111111111111111
func Test_visual_increment_26()
- set nrformats+=alpha
+ set nrformats+=bin
call setline(1, ["0b11111111111111111111111111111110"])
exec "norm! \<C-V>$\<C-A>"
call assert_equal(["0b11111111111111111111111111111111"], getline(1, '$'))
call assert_equal([0, 1, 1, 0], getpos('.'))
- set nrformats-=alpha
+ exec "norm! \<C-V>$\<C-X>"
+ call assert_equal(["0b11111111111111111111111111111110"], getline(1, '$'))
+ set nrformats-=bin
endfunc
" 27) increment with 'rightreft', if supported
@@ -772,7 +778,6 @@ func Test_normal_increment_03()
endfunc
func Test_increment_empty_line()
- new
call setline(1, ['0', '0', '0', '0', '0', '0', ''])
exe "normal Gvgg\<C-A>"
call assert_equal(['1', '1', '1', '1', '1', '1', ''], getline(1, 7))
@@ -783,8 +788,13 @@ func Test_increment_empty_line()
exe "normal! c\<C-A>l"
exe "normal! c\<C-X>l"
call assert_equal('one two', getline(1))
+endfunc
- bwipe!
+" Try incrementing/decrementing a non-digit/alpha character
+func Test_increment_special_char()
+ call setline(1, '!')
+ call assert_beeps("normal \<C-A>")
+ call assert_beeps("normal \<C-X>")
endfunc
" Try incrementing/decrementing a number when nrformats contains unsigned
@@ -867,4 +877,21 @@ func Test_normal_increment_with_virtualedit()
set virtualedit&
endfunc
+" Test for incrementing a signed hexadecimal and octal number
+func Test_normal_increment_signed_hexoct_nr()
+ new
+ " negative sign before a hex number should be ignored
+ call setline(1, ["-0x9"])
+ exe "norm \<C-A>"
+ call assert_equal(["-0xa"], getline(1, '$'))
+ exe "norm \<C-X>"
+ call assert_equal(["-0x9"], getline(1, '$'))
+ call setline(1, ["-007"])
+ exe "norm \<C-A>"
+ call assert_equal(["-010"], getline(1, '$'))
+ exe "norm \<C-X>"
+ call assert_equal(["-007"], getline(1, '$'))
+ bw!
+endfunc
+
" vim: shiftwidth=2 sts=2 expandtab
diff --git a/src/nvim/testdir/test_let.vim b/src/nvim/testdir/test_let.vim
index 937076aa2a..f05e06f774 100644
--- a/src/nvim/testdir/test_let.vim
+++ b/src/nvim/testdir/test_let.vim
@@ -262,7 +262,7 @@ func Test_let_errors()
let l = [1, 2, 3]
call assert_fails('let l[:] = 5', 'E709:')
- call assert_fails('let x:lnum=5', 'E488:')
+ call assert_fails('let x:lnum=5', ['E121:', 'E488:'])
call assert_fails('let v:=5', 'E461:')
call assert_fails('let [a]', 'E474:')
call assert_fails('let [a, b] = [', 'E697:')
diff --git a/src/nvim/testdir/test_listdict.vim b/src/nvim/testdir/test_listdict.vim
index f7261b2055..ecf95ba8c0 100644
--- a/src/nvim/testdir/test_listdict.vim
+++ b/src/nvim/testdir/test_listdict.vim
@@ -336,11 +336,12 @@ func Test_dict_deepcopy()
let l = [4, d, 6]
let d[3] = l
let dc = deepcopy(d)
- call assert_fails('call deepcopy(d, 1)', 'E698')
+ call assert_fails('call deepcopy(d, 1)', 'E698:')
let l2 = [0, l, l, 3]
let l[1] = l2
let l3 = deepcopy(l2)
call assert_true(l3[1] is l3[2])
+ call assert_fails("call deepcopy([1, 2], 2)", 'E1023:')
endfunc
" Locked variables
@@ -420,6 +421,11 @@ func Test_list_locked_var()
call assert_equal(expected[depth][u][1], ps)
endfor
endfor
+ call assert_fails("let x=islocked('a b')", 'E488:')
+ let mylist = [1, 2, 3]
+ call assert_fails("let x = islocked('mylist[1:2]')", 'E786:')
+ let mydict = {'k' : 'v'}
+ call assert_fails("let x = islocked('mydict.a')", 'E716:')
endfunc
" Unletting locked variables
@@ -674,10 +680,10 @@ func Test_reverse_sort_uniq()
endif
call assert_fails('call reverse("")', 'E899:')
- call assert_fails('call uniq([1, 2], {x, y -> []})', 'E882:')
+ call assert_fails('call uniq([1, 2], {x, y -> []})', 'E745:')
call assert_fails("call sort([1, 2], function('min'), 1)", "E715:")
call assert_fails("call sort([1, 2], function('invalid_func'))", "E700:")
- call assert_fails("call sort([1, 2], function('min'))", "E702:")
+ call assert_fails("call sort([1, 2], function('min'))", "E118:")
endfunc
" reduce a list or a blob
@@ -736,6 +742,8 @@ func Test_str_split()
call assert_equal(['aa', '', 'bb', 'cc', ''], split('aa,,bb, cc,', ',\s*', 1))
call assert_equal(['a', 'b', 'c'], split('abc', '\zs'))
call assert_equal(['', 'a', '', 'b', '', 'c', ''], split('abc', '\zs', 1))
+ call assert_fails("call split('abc', [])", 'E730:')
+ call assert_fails("call split('abc', 'b', [])", 'E745:')
endfunc
" compare recursively linked list and dict
@@ -975,7 +983,7 @@ func Test_listdict_index()
call assert_fails('echo d[1:2]', 'E719:')
call assert_fails("let v = [4, 6][{-> 1}]", 'E729:')
call assert_fails("let v = range(5)[2:[]]", 'E730:')
- call assert_fails("let v = range(5)[2:{-> 2}(]", 'E116:')
+ call assert_fails("let v = range(5)[2:{-> 2}(]", ['E15:', 'E116:'])
call assert_fails("let v = range(5)[2:3", 'E111:')
call assert_fails("let l = insert([1,2,3], 4, 10)", 'E684:')
call assert_fails("let l = insert([1,2,3], 4, -10)", 'E684:')
diff --git a/src/nvim/testdir/test_mapping.vim b/src/nvim/testdir/test_mapping.vim
index 2d8c45210b..560883ba5d 100644
--- a/src/nvim/testdir/test_mapping.vim
+++ b/src/nvim/testdir/test_mapping.vim
@@ -1050,6 +1050,30 @@ func Test_mouse_drag_mapped_start_select()
set mouse&
endfunc
+func Test_mouse_drag_statusline()
+ set laststatus=2
+ set mouse=a
+ func ClickExpr()
+ call Ntest_setmouse(&lines - 1, 1)
+ return "\<LeftMouse>"
+ endfunc
+ func DragExpr()
+ call Ntest_setmouse(&lines - 2, 1)
+ return "\<LeftDrag>"
+ endfunc
+ nnoremap <expr> <F2> ClickExpr()
+ nnoremap <expr> <F3> DragExpr()
+
+ " this was causing a crash in win_drag_status_line()
+ call feedkeys("\<F2>:tabnew\<CR>\<F3>", 'tx')
+
+ nunmap <F2>
+ nunmap <F3>
+ delfunc ClickExpr
+ delfunc DragExpr
+ set laststatus& mouse&
+endfunc
+
" Test for mapping <LeftDrag> in Insert mode
func Test_mouse_drag_insert_map()
set mouse=a
diff --git a/src/nvim/testdir/test_marks.vim b/src/nvim/testdir/test_marks.vim
index 054ebf1218..b432b7bbbc 100644
--- a/src/nvim/testdir/test_marks.vim
+++ b/src/nvim/testdir/test_marks.vim
@@ -100,6 +100,8 @@ func Test_setpos()
call setpos('.', [0, 1, -1, 0])
call assert_equal([2, 2], [line('.'), col('.')])
+ call assert_fails("call setpos('ab', [0, 1, 1, 0])", 'E474:')
+
bwipe!
call win_gotoid(twowin)
bwipe!
diff --git a/src/nvim/testdir/test_match.vim b/src/nvim/testdir/test_match.vim
index fe931fefb2..5d9be99444 100644
--- a/src/nvim/testdir/test_match.vim
+++ b/src/nvim/testdir/test_match.vim
@@ -160,12 +160,14 @@ endfunc
func Test_matchadd_error()
call clearmatches()
" Nvim: not an error anymore:
+ " call assert_fails("call matchadd('GroupDoesNotExist', 'X')", 'E28:')
call matchadd('GroupDoesNotExist', 'X')
call assert_equal([{'group': 'GroupDoesNotExist', 'pattern': 'X', 'priority': 10, 'id': 1206}], getmatches())
- call assert_fails("call matchadd('Search', '\\(')", 'E475:')
+ call assert_fails("call matchadd('Search', '\\(')", 'E54:')
call assert_fails("call matchadd('Search', 'XXX', 1, 123, 1)", 'E715:')
call assert_fails("call matchadd('Error', 'XXX', 1, 3)", 'E798:')
call assert_fails("call matchadd('Error', 'XXX', 1, 0)", 'E799:')
+ call assert_fails("call matchadd('Error', 'XXX', [], 0)", 'E745:')
endfunc
func Test_matchaddpos()
@@ -305,7 +307,10 @@ func Test_matchaddpos_error()
call assert_fails("call matchaddpos('Error', [1], 1, 123, 1)", 'E715:')
call assert_fails("call matchaddpos('Error', [1], 1, 5, {'window':12345})", 'E957:')
" Why doesn't the following error have an error code E...?
+ " call assert_fails("call matchaddpos('Error', [{}])", 'E290:')
call assert_fails("call matchaddpos('Error', [{}])", 'E5031:')
+ call assert_equal(-1, matchaddpos('Error', v:_null_list))
+ call assert_fails("call matchaddpos('Error', [1], [], 1)", 'E745:')
endfunc
func OtherWindowCommon()
@@ -338,9 +343,7 @@ func Test_matchdelete_error()
endfunc
func Test_matchclear_other_window()
- if !CanRunVimInTerminal()
- throw 'Skipped: cannot make screendumps'
- endif
+ CheckRunVimInTerminal
let buf = OtherWindowCommon()
call term_sendkeys(buf, ":call clearmatches(winid)\<CR>")
call VerifyScreenDump(buf, 'Test_matchclear_1', {})
@@ -350,9 +353,7 @@ func Test_matchclear_other_window()
endfunc
func Test_matchadd_other_window()
- if !CanRunVimInTerminal()
- throw 'Skipped: cannot make screendumps'
- endif
+ CheckRunVimInTerminal
let buf = OtherWindowCommon()
call term_sendkeys(buf, ":call matchadd('Search', 'Hello', 1, -1, #{window: winid})\<CR>")
call term_sendkeys(buf, ":\<CR>")
@@ -362,5 +363,4 @@ func Test_matchadd_other_window()
call delete('XscriptMatchCommon')
endfunc
-
" vim: shiftwidth=2 sts=2 expandtab
diff --git a/src/nvim/testdir/test_matchfuzzy.vim b/src/nvim/testdir/test_matchfuzzy.vim
index c836bc87aa..b46550fbc3 100644
--- a/src/nvim/testdir/test_matchfuzzy.vim
+++ b/src/nvim/testdir/test_matchfuzzy.vim
@@ -6,9 +6,7 @@ source check.vim
" Test for matchfuzzy()
func Test_matchfuzzy()
call assert_fails('call matchfuzzy(10, "abc")', 'E686:')
- " Needs v8.2.1183; match the final error that's thrown for now
- " call assert_fails('call matchfuzzy(["abc"], [])', 'E730:')
- call assert_fails('call matchfuzzy(["abc"], [])', 'E475:')
+ call assert_fails('call matchfuzzy(["abc"], [])', 'E730:')
call assert_fails("let x = matchfuzzy(v:_null_list, 'foo')", 'E686:')
call assert_fails('call matchfuzzy(["abc"], v:_null_string)', 'E475:')
call assert_equal([], matchfuzzy([], 'abc'))
@@ -75,12 +73,9 @@ func Test_matchfuzzy()
call assert_fails("let x = matchfuzzy(l, 'day', {'text_cb' : {a, b -> 1}})", 'E119:')
call assert_equal([], matchfuzzy(l, 'cam'))
" Nvim's callback implementation is different, so E6000 is expected instead,
- " but we need v8.2.1183 to assert it
" call assert_fails("let x = matchfuzzy(l, 'cam', {'text_cb' : []})", 'E921:')
- " call assert_fails("let x = matchfuzzy(l, 'cam', {'text_cb' : []})", 'E6000:')
- call assert_fails("let x = matchfuzzy(l, 'cam', {'text_cb' : []})", 'E475:')
- " call assert_fails("let x = matchfuzzy(l, 'foo', {'key' : []})", 'E730:')
- call assert_fails("let x = matchfuzzy(l, 'foo', {'key' : []})", 'E475:')
+ call assert_fails("let x = matchfuzzy(l, 'cam', {'text_cb' : []})", 'E6000:')
+ call assert_fails("let x = matchfuzzy(l, 'foo', {'key' : []})", 'E730:')
call assert_fails("let x = matchfuzzy(l, 'cam', v:_null_dict)", 'E715:')
call assert_fails("let x = matchfuzzy(l, 'foo', {'key' : v:_null_string})", 'E475:')
" Nvim doesn't have null functions
@@ -155,12 +150,9 @@ func Test_matchfuzzypos()
call assert_fails("let x = matchfuzzypos(l, 'day', {'text_cb' : {a, b -> 1}})", 'E119:')
call assert_equal([[], [], []], matchfuzzypos(l, 'cam'))
" Nvim's callback implementation is different, so E6000 is expected instead,
- " but we need v8.2.1183 to assert it
" call assert_fails("let x = matchfuzzypos(l, 'cam', {'text_cb' : []})", 'E921:')
- " call assert_fails("let x = matchfuzzypos(l, 'cam', {'text_cb' : []})", 'E6000:')
- call assert_fails("let x = matchfuzzypos(l, 'cam', {'text_cb' : []})", 'E475:')
- " call assert_fails("let x = matchfuzzypos(l, 'foo', {'key' : []})", 'E730:')
- call assert_fails("let x = matchfuzzypos(l, 'foo', {'key' : []})", 'E475:')
+ call assert_fails("let x = matchfuzzypos(l, 'cam', {'text_cb' : []})", 'E6000:')
+ call assert_fails("let x = matchfuzzypos(l, 'foo', {'key' : []})", 'E730:')
call assert_fails("let x = matchfuzzypos(l, 'cam', v:_null_dict)", 'E715:')
call assert_fails("let x = matchfuzzypos(l, 'foo', {'key' : v:_null_string})", 'E475:')
" Nvim doesn't have null functions
diff --git a/src/nvim/testdir/test_menu.vim b/src/nvim/testdir/test_menu.vim
index 2e149ad5a5..a1121632e6 100644
--- a/src/nvim/testdir/test_menu.vim
+++ b/src/nvim/testdir/test_menu.vim
@@ -153,7 +153,7 @@ func Test_menu_errors()
call assert_fails('menu Test.Foo.Bar', 'E327:')
call assert_fails('cmenu Test.Foo', 'E328:')
call assert_fails('emenu x Test.Foo', 'E475:')
- call assert_fails('emenu Test.Foo.Bar', 'E334:')
+ call assert_fails('emenu Test.Foo.Bar', 'E327:')
call assert_fails('menutranslate Test', 'E474:')
silent! unmenu Foo
@@ -252,6 +252,7 @@ func Test_menu_info()
nmenu Test.abc <Nop>
call assert_equal('<Nop>', menu_info('Test.abc').rhs)
call assert_fails('call menu_info([])', 'E730:')
+ call assert_fails('call menu_info("", [])', 'E730:')
nunmenu Test
" Test for defining menus in different modes
diff --git a/src/nvim/testdir/test_method.vim b/src/nvim/testdir/test_method.vim
index e035b3ef50..057f4a1bea 100644
--- a/src/nvim/testdir/test_method.vim
+++ b/src/nvim/testdir/test_method.vim
@@ -131,9 +131,9 @@ func Test_method_syntax()
eval [1, 2, 3]
\ ->sort(
\ )
- call assert_fails('eval [1, 2, 3]-> sort()', 'E260:')
+ call assert_fails('eval [1, 2, 3]-> sort()', 'E15:')
call assert_fails('eval [1, 2, 3]->sort ()', 'E274:')
- call assert_fails('eval [1, 2, 3]-> sort ()', 'E260:')
+ call assert_fails('eval [1, 2, 3]-> sort ()', 'E15:')
endfunc
func Test_method_lambda()
diff --git a/src/nvim/testdir/test_normal.vim b/src/nvim/testdir/test_normal.vim
index 5730085c78..84929e2be3 100644
--- a/src/nvim/testdir/test_normal.vim
+++ b/src/nvim/testdir/test_normal.vim
@@ -120,6 +120,39 @@ func Test_normal01_keymodel()
call feedkeys("Vkk\<Up>yy", 'tx')
call assert_equal(['47', '48', '49', '50'], getreg(0, 0, 1))
+ " Test for using special keys to start visual selection
+ %d
+ call setline(1, ['red fox tail', 'red fox tail', 'red fox tail'])
+ set keymodel=startsel
+ " Test for <S-PageUp> and <S-PageDown>
+ call cursor(1, 1)
+ call feedkeys("\<S-PageDown>y", 'xt')
+ call assert_equal([0, 1, 1, 0], getpos("'<"))
+ call assert_equal([0, 3, 1, 0], getpos("'>"))
+ call feedkeys("Gz\<CR>8|\<S-PageUp>y", 'xt')
+ call assert_equal([0, 2, 1, 0], getpos("'<"))
+ call assert_equal([0, 3, 8, 0], getpos("'>"))
+ " Test for <S-C-Home> and <S-C-End>
+ call cursor(2, 12)
+ call feedkeys("\<S-C-Home>y", 'xt')
+ call assert_equal([0, 1, 1, 0], getpos("'<"))
+ call assert_equal([0, 2, 12, 0], getpos("'>"))
+ call cursor(1, 4)
+ call feedkeys("\<S-C-End>y", 'xt')
+ call assert_equal([0, 1, 4, 0], getpos("'<"))
+ call assert_equal([0, 3, 13, 0], getpos("'>"))
+ " Test for <S-C-Left> and <S-C-Right>
+ call cursor(2, 5)
+ call feedkeys("\<S-C-Right>y", 'xt')
+ call assert_equal([0, 2, 5, 0], getpos("'<"))
+ call assert_equal([0, 2, 9, 0], getpos("'>"))
+ call cursor(2, 9)
+ call feedkeys("\<S-C-Left>y", 'xt')
+ call assert_equal([0, 2, 5, 0], getpos("'<"))
+ call assert_equal([0, 2, 9, 0], getpos("'>"))
+
+ set keymodel&
+
" clean up
bw!
endfunc
@@ -140,16 +173,15 @@ func Test_normal03_join()
$
:j 10
call assert_equal('100', getline('.'))
+ call assert_beeps('normal GVJ')
" clean up
bw!
endfunc
+" basic filter test
func Test_normal04_filter()
- " basic filter test
" only test on non windows platform
- if has('win32')
- return
- endif
+ CheckNotMSWindows
call Setup_NewWindow()
1
call feedkeys("!!sed -e 's/^/| /'\n", 'tx')
@@ -222,12 +254,10 @@ func Test_normal_formatexpr_returns_nonzero()
close!
endfunc
+" basic test for formatprg
func Test_normal06_formatprg()
- " basic test for formatprg
" only test on non windows platform
- if has('win32')
- return
- endif
+ CheckNotMSWindows
" uses sed to number non-empty lines
call writefile(['#!/bin/sh', 'sed ''/./=''|sed ''/./{', 'N', 's/\n/ /', '}'''], 'Xsed_format.sh')
@@ -240,16 +270,24 @@ func Test_normal06_formatprg()
set formatprg=./Xsed_format.sh
norm! gggqG
call assert_equal(expected, getline(1, '$'))
- bw!
+ %d
- 10new
call setline(1, text)
set formatprg=donothing
setlocal formatprg=./Xsed_format.sh
norm! gggqG
call assert_equal(expected, getline(1, '$'))
- bw!
+ %d
+ " Check for the command-line ranges added to 'formatprg'
+ set formatprg=cat
+ call setline(1, ['one', 'two', 'three', 'four', 'five'])
+ call feedkeys('gggqG', 'xt')
+ call assert_equal('.,$!cat', @:)
+ call feedkeys('2Ggq2j', 'xt')
+ call assert_equal('.,.+2!cat', @:)
+
+ bw!
" clean up
set formatprg=
setlocal formatprg=
@@ -263,18 +301,16 @@ func Test_normal07_internalfmt()
10new
call setline(1, list)
set tw=12
- norm! gggqG
+ norm! ggVGgq
call assert_equal(['1 2 3', '4 5 6', '7 8 9', '10 11 '], getline(1, '$'))
" clean up
set tw=0
bw!
endfunc
+" basic tests for foldopen/folddelete
func Test_normal08_fold()
- " basic tests for foldopen/folddelete
- if !has("folding")
- return
- endif
+ CheckFeature folding
call Setup_NewWindow()
50
setl foldenable fdm=marker
@@ -506,6 +542,14 @@ func Test_normal10_expand()
call assert_equal(expected[i], expand('<cexpr>'), 'i == ' . i)
endfor
+ " Test for <cexpr> in state.val and ptr->val
+ call setline(1, 'x = state.val;')
+ call cursor(1, 10)
+ call assert_equal('state.val', expand('<cexpr>'))
+ call setline(1, 'x = ptr->val;')
+ call cursor(1, 9)
+ call assert_equal('ptr->val', expand('<cexpr>'))
+
if executable('echo')
" Test expand(`...`) i.e. backticks command expansion.
" MS-Windows has a trailing space.
@@ -520,6 +564,19 @@ func Test_normal10_expand()
bw!
endfunc
+" Test for expand() in latin1 encoding
+func Test_normal_expand_latin1()
+ new
+ let save_enc = &encoding
+ " set encoding=latin1
+ call setline(1, 'val = item->color;')
+ call cursor(1, 11)
+ call assert_equal('color', expand("<cword>"))
+ call assert_equal('item->color', expand("<cexpr>"))
+ let &encoding = save_enc
+ bw!
+endfunc
+
func Test_normal11_showcmd()
" test for 'showcmd'
10new
@@ -544,6 +601,13 @@ func Test_normal11_showcmd()
redraw!
call assert_match('1-3$', Screenline(&lines))
call feedkeys("v", 'xt')
+ " test for visually selecting the end of line
+ call setline(1, ["foobar"])
+ call feedkeys("$vl", 'xt')
+ redraw!
+ call assert_match('2$', Screenline(&lines))
+ call feedkeys("y", 'xt')
+ call assert_equal("r\n", @")
bw!
endfunc
@@ -1432,10 +1496,8 @@ func Test_normal18_z_fold()
endfunc
func Test_normal20_exmode()
- if !has("unix")
- " Reading from redirected file doesn't work on MS-Windows
- return
- endif
+ " Reading from redirected file doesn't work on MS-Windows
+ CheckNotMSWindows
call writefile(['1a', 'foo', 'bar', '.', 'w! Xfile2', 'q!'], 'Xscript')
call writefile(['1', '2'], 'Xfile')
call system(GetVimCommand() .. ' -e -s < Xscript Xfile')
@@ -1588,7 +1650,7 @@ func Test_normal23_K()
call setline(1, '---')
call assert_fails('normal! ggv2lK', 'E349:')
call setline(1, ['abc', 'xyz'])
- call assert_fails("normal! gg2lv2h\<C-]>", 'E426:')
+ call assert_fails("normal! gg2lv2h\<C-]>", 'E433:')
call assert_beeps("normal! ggVjK")
" clean up
@@ -2063,6 +2125,16 @@ func Test_normal30_changecase()
call assert_equal(['aaaaaa', 'AAAAaa'], getline(1, 2))
set whichwrap&
+ " try changing the case with a double byte encoding (DBCS)
+ %bw!
+ let enc = &enc
+ " set encoding=cp932
+ call setline(1, "\u8470")
+ normal ~
+ normal gU$gu$gUgUg~g~gugu
+ call assert_equal("\u8470", getline(1))
+ let &encoding = enc
+
" clean up
bw!
endfunc
@@ -2154,6 +2226,19 @@ func Test_normal31_r_cmd()
" r command should fail in operator pending mode
call assert_beeps('normal! cr')
+ " replace a tab character in visual mode
+ %d
+ call setline(1, ["a\tb", "c\td", "e\tf"])
+ normal gglvjjrx
+ call assert_equal(['axx', 'xxx', 'xxf'], getline(1, '$'))
+
+ " replace with a multibyte character (with multiple composing characters)
+ %d
+ new
+ call setline(1, 'aaa')
+ exe "normal $ra\u0328\u0301"
+ call assert_equal("aaa\u0328\u0301", getline(1))
+
" clean up
set noautoindent
bw!
@@ -2178,9 +2263,7 @@ endfunc
" Test for g`, g;, g,, g&, gv, gk, gj, gJ, g0, g^, g_, gm, g$, gM, g CTRL-G,
" gi and gI commands
func Test_normal33_g_cmd2()
- if !has("jumplist")
- return
- endif
+ CheckFeature jumplist
call Setup_NewWindow()
" Test for g`
clearjumps
@@ -2639,7 +2722,6 @@ endfunc
" Test for cw cW ce
func Test_normal39_cw()
" Test for cw and cW on whitespace
- " and cpo+=w setting
new
set tw=0
call append(0, 'here are some words')
@@ -2647,14 +2729,6 @@ func Test_normal39_cw()
call assert_equal('hereZZZare some words', getline('.'))
norm! 1gg0elcWYYY
call assert_equal('hereZZZareYYYsome words', getline('.'))
- " Nvim: no "w" flag in 'cpoptions'.
- " set cpo+=w
- " call setline(1, 'here are some words')
- " norm! 1gg0elcwZZZ
- " call assert_equal('hereZZZ are some words', getline('.'))
- " norm! 1gg2elcWYYY
- " call assert_equal('hereZZZ areYYY some words', getline('.'))
- set cpo-=w
norm! 2gg0cwfoo
call assert_equal('foo', getline('.'))
@@ -2849,9 +2923,8 @@ func Test_normal49_counts()
endfunc
func Test_normal50_commandline()
- if !has("timers") || !has("cmdline_hist")
- return
- endif
+ CheckFeature timers
+ CheckFeature cmdline_hist
func! DoTimerWork(id)
call assert_equal('[Command Line]', bufname(''))
" should fail, with E11, but does fail with E23?
@@ -2880,9 +2953,7 @@ func Test_normal50_commandline()
endfunc
func Test_normal51_FileChangedRO()
- if !has("autocmd")
- return
- endif
+ CheckFeature autocmd
call writefile(['foo'], 'Xreadonly.log')
new Xreadonly.log
setl ro
@@ -2897,9 +2968,7 @@ func Test_normal51_FileChangedRO()
endfunc
func Test_normal52_rl()
- if !has("rightleft")
- return
- endif
+ CheckFeature rightleft
new
call setline(1, 'abcde fghij klmnopq')
norm! 1gg$
@@ -2931,22 +3000,6 @@ func Test_normal52_rl()
bw!
endfunc
-func Test_normal53_digraph()
- if !has('digraphs')
- return
- endif
- new
- call setline(1, 'abcdefgh|')
- exe "norm! 1gg0f\<c-k>!!"
- call assert_equal(9, col('.'))
- set cpo+=D
- exe "norm! 1gg0f\<c-k>!!"
- call assert_equal(1, col('.'))
-
- set cpo-=D
- bw!
-endfunc
-
func Test_normal54_Ctrl_bsl()
new
call setline(1, 'abcdefghijklmn')
@@ -3267,46 +3320,6 @@ func Test_normal_gk_gj()
set cpoptions& number& numberwidth& wrap&
endfunc
-" Test for cursor movement with '-' in 'cpoptions'
-func Test_normal_cpo_minus()
- throw 'Skipped: Nvim does not support cpoptions flag "-"'
- new
- call setline(1, ['foo', 'bar', 'baz'])
- let save_cpo = &cpo
- set cpo+=-
- call assert_beeps('normal 10j')
- call assert_equal(1, line('.'))
- normal G
- call assert_beeps('normal 10k')
- call assert_equal(3, line('.'))
- call assert_fails(10, 'E16:')
- let &cpo = save_cpo
- close!
-endfunc
-
-" Test for displaying dollar when changing text ('$' flag in 'cpoptions')
-func Test_normal_cpo_dollar()
- throw 'Skipped: use test/functional/legacy/cpoptions_spec.lua'
- new
- let g:Line = ''
- func SaveFirstLine()
- let g:Line = Screenline(1)
- return ''
- endfunc
- inoremap <expr> <buffer> <F2> SaveFirstLine()
- call test_override('redraw_flag', 1)
- set cpo+=$
- call setline(1, 'one two three')
- redraw!
- exe "normal c2w\<F2>vim"
- call assert_equal('one tw$ three', g:Line)
- call assert_equal('vim three', getline(1))
- set cpo-=$
- call test_override('ALL', 0)
- delfunc SaveFirstLine
- %bw!
-endfunc
-
" Test for using : to run a multi-line Ex command in operator pending mode
func Test_normal_yank_with_excmd()
new
@@ -3371,6 +3384,24 @@ func Test_normal_colon_op()
close!
endfunc
+" Test for d and D commands
+func Test_normal_delete_cmd()
+ new
+ " D in an empty line
+ call setline(1, '')
+ normal D
+ call assert_equal('', getline(1))
+ " D in an empty line in virtualedit mode
+ set virtualedit=all
+ normal D
+ call assert_equal('', getline(1))
+ set virtualedit&
+ " delete to a readonly register
+ call setline(1, ['abcd'])
+ call assert_beeps('normal ":d2l')
+ close!
+endfunc
+
" Test for deleting or changing characters across lines with 'whichwrap'
" containing 's'. Should count <EOL> as one character.
func Test_normal_op_across_lines()
@@ -3478,6 +3509,27 @@ func Test_normal_percent_jump()
close!
endfunc
+" Test for << and >> commands to shift text by 'shiftwidth'
+func Test_normal_shift_rightleft()
+ new
+ call setline(1, ['one', '', "\t", ' two', "\tthree", ' four'])
+ set shiftwidth=2 tabstop=8
+ normal gg6>>
+ call assert_equal([' one', '', "\t ", ' two', "\t three", "\tfour"],
+ \ getline(1, '$'))
+ normal ggVG2>>
+ call assert_equal([' one', '', "\t ", "\ttwo",
+ \ "\t three", "\t four"], getline(1, '$'))
+ normal gg6<<
+ call assert_equal([' one', '', "\t ", ' two', "\t three",
+ \ "\t four"], getline(1, '$'))
+ normal ggVG2<<
+ call assert_equal(['one', '', "\t", ' two', "\tthree", ' four'],
+ \ getline(1, '$'))
+ set shiftwidth& tabstop&
+ bw!
+endfunc
+
" Some commands like yy, cc, dd, >>, << and !! accept a count after
" typing the first letter of the command.
func Test_normal_count_after_operator()
diff --git a/src/nvim/testdir/test_options.vim b/src/nvim/testdir/test_options.vim
index 2836e81c4a..3916d7c554 100644
--- a/src/nvim/testdir/test_options.vim
+++ b/src/nvim/testdir/test_options.vim
@@ -263,7 +263,7 @@ func Test_set_completion()
call feedkeys(":setglobal di\<C-A>\<C-B>\"\<CR>", 'tx')
call assert_equal('"setglobal dictionary diff diffexpr diffopt digraph directory display', @:)
- " Expand boolan options. When doing :set no<Tab>
+ " Expand boolean options. When doing :set no<Tab>
" vim displays the options names without "no" but completion uses "no...".
call feedkeys(":set nodi\<C-A>\<C-B>\"\<CR>", 'tx')
call assert_equal('"set nodiff digraph', @:)
diff --git a/src/nvim/testdir/test_partial.vim b/src/nvim/testdir/test_partial.vim
index 8c90f21600..3020668f1b 100644
--- a/src/nvim/testdir/test_partial.vim
+++ b/src/nvim/testdir/test_partial.vim
@@ -82,6 +82,9 @@ func Test_partial_dict()
let dict = {"tr": function('tr', ['hello', 'h', 'H'])}
call assert_equal("Hello", dict.tr())
+
+ call assert_fails("let F=function('setloclist', 10)", "E923:")
+ call assert_fails("let F=function('setloclist', [], [])", "E922:")
endfunc
func Test_partial_implicit()
@@ -354,3 +357,5 @@ func Test_compare_partials()
call assert_true(F1 isnot# F1d1) " Partial /= non-partial
call assert_true(d1.f1 isnot# d1.f1) " handle_subscript creates new partial each time
endfunc
+
+" vim: shiftwidth=2 sts=2 expandtab
diff --git a/src/nvim/testdir/test_quickfix.vim b/src/nvim/testdir/test_quickfix.vim
index dcedfe26a2..9d9fc5e77b 100644
--- a/src/nvim/testdir/test_quickfix.vim
+++ b/src/nvim/testdir/test_quickfix.vim
@@ -740,7 +740,7 @@ func s:test_xhelpgrep(cchar)
" Search for non existing help string
call assert_fails('Xhelpgrep a1b2c3', 'E480:')
" Invalid regular expression
- call assert_fails('Xhelpgrep \@<!', 'E480:')
+ call assert_fails('Xhelpgrep \@<!', 'E866:')
endfunc
func Test_helpgrep()
@@ -4101,8 +4101,8 @@ endfunc
func Test_lvimgrep_crash2()
au BufNewFile x sfind
- call assert_fails('lvimgrep x x', 'E480:')
- call assert_fails('lvimgrep x x x', 'E480:')
+ call assert_fails('lvimgrep x x', 'E471:')
+ call assert_fails('lvimgrep x x x', 'E471:')
au! BufNewFile
endfunc
@@ -5801,6 +5801,21 @@ func Test_win_gettype()
lclose
endfunc
+fun Test_vimgrep_nomatch()
+ call XexprTests('c')
+ call g:Xsetlist([{'lnum':10,'text':'Line1'}])
+ copen
+ if has("win32")
+ call assert_fails('vimgrep foo *.zzz', 'E479:')
+ let expected = [{'lnum': 10, 'bufnr': 0, 'end_lnum': 0, 'pattern': '', 'valid': 0, 'vcol': 0, 'nr': 0, 'module': '', 'type': '', 'end_col': 0, 'col': 0, 'text': 'Line1'}]
+ else
+ call assert_fails('vimgrep foo *.zzz', 'E480:')
+ let expected = []
+ endif
+ call assert_equal(expected, getqflist())
+ cclose
+endfunc
+
" Test for opening the quickfix window in two tab pages and then closing one
" of the quickfix windows. This should not make the quickfix buffer unlisted.
" (github issue #9300).
diff --git a/src/nvim/testdir/test_random.vim b/src/nvim/testdir/test_random.vim
index 6d3f7dcfd9..fb1c9ab6cd 100644
--- a/src/nvim/testdir/test_random.vim
+++ b/src/nvim/testdir/test_random.vim
@@ -33,11 +33,11 @@ func Test_Rand()
endif
call assert_fails('echo srand([1])', 'E745:')
call assert_fails('echo rand("burp")', 'E475:')
- call assert_fails('echo rand([1, 2, 3])', 'E475:')
- call assert_fails('echo rand([[1], 2, 3, 4])', 'E475:')
- call assert_fails('echo rand([1, [2], 3, 4])', 'E475:')
- call assert_fails('echo rand([1, 2, [3], 4])', 'E475:')
- call assert_fails('echo rand([1, 2, 3, [4]])', 'E475:')
+ call assert_fails('echo rand([1, 2, 3])', 'E730:')
+ call assert_fails('echo rand([[1], 2, 3, 4])', 'E730:')
+ call assert_fails('echo rand([1, [2], 3, 4])', 'E730:')
+ call assert_fails('echo rand([1, 2, [3], 4])', 'E730:')
+ call assert_fails('echo rand([1, 2, 3, [4]])', 'E730:')
" call test_settime(0)
endfunc
diff --git a/src/nvim/testdir/test_regexp_latin.vim b/src/nvim/testdir/test_regexp_latin.vim
index d08a980787..ece6ae518e 100644
--- a/src/nvim/testdir/test_regexp_latin.vim
+++ b/src/nvim/testdir/test_regexp_latin.vim
@@ -101,8 +101,33 @@ func Test_multi_failure()
set re=2
call assert_fails('/a**', 'E871:')
call assert_fails('/a*\+', 'E871:')
- call assert_fails('/a\{a}', 'E870:')
+ call assert_fails('/a\{a}', 'E554:')
+ set re=0
+endfunc
+
+func Test_column_success_failure()
+ new
+ call setline(1, 'xbar')
+
+ set re=1
+ %s/\%>0v./A/
+ call assert_equal('Abar', getline(1))
+ call assert_fails('/\%v', 'E71:')
+ call assert_fails('/\%>v', 'E71:')
+ call assert_fails('/\%c', 'E71:')
+ call assert_fails('/\%<c', 'E71:')
+ call assert_fails('/\%l', 'E71:')
+ set re=2
+ %s/\%>0v./B/
+ call assert_equal('Bbar', getline(1))
+ call assert_fails('/\%v', 'E1273:')
+ call assert_fails('/\%>v', 'E1273:')
+ call assert_fails('/\%c', 'E1273:')
+ call assert_fails('/\%<c', 'E1273:')
+ call assert_fails('/\%l', 'E1273:')
+
set re=0
+ bwipe!
endfunc
func Test_recursive_addstate()
@@ -146,6 +171,10 @@ func Test_regexp_single_line_pat()
call add(tl, [2, 'c*', 'abdef', ''])
call add(tl, [2, 'bc\+', 'abccccdef', 'bcccc'])
call add(tl, [2, 'bc\+', 'abdef']) " no match
+ " match escape character in a string
+ call add(tl, [2, '.\e.', "one\<Esc>two", "e\<Esc>t"])
+ " match backspace character in a string
+ call add(tl, [2, '.\b.', "one\<C-H>two", "e\<C-H>t"])
" match newline character in a string
call add(tl, [2, 'o\nb', "foo\nbar", "o\nb"])
@@ -895,6 +924,8 @@ func Test_regexp_error()
call assert_fails("call matchlist('x x', '\\%#=2 \\zs*')", 'E888:')
call assert_fails("call matchlist('x x', '\\%#=2 \\ze*')", 'E888:')
call assert_fails('exe "normal /\\%#=1\\%[x\\%[x]]\<CR>"', 'E369:')
+ call assert_fails("call matchstr('abcd', '\\%o841\\%o142')", 'E678:')
+ call assert_equal('', matchstr('abcd', '\%o181\%o142'))
endfunc
" Test for using the last substitute string pattern (~)
@@ -1027,6 +1058,28 @@ func Test_using_invalid_visual_position()
bwipe!
endfunc
+func Test_using_two_engines_pattern()
+ new
+ call setline(1, ['foobar=0', 'foobar=1', 'foobar=2'])
+ " \%#= at the end of the pattern
+ for i in range(0, 2)
+ for j in range(0, 2)
+ exe "set re=" .. i
+ call cursor(j + 1, 7)
+ call assert_fails("%s/foobar\\%#=" .. j, 'E1281:')
+ endfor
+ endfor
+ set re=0
+
+ " \%#= at the start of the pattern
+ for i in range(0, 2)
+ call cursor(i + 1, 7)
+ exe ":%s/\\%#=" .. i .. "foobar=" .. i .. "/xx"
+ endfor
+ call assert_equal(['xx', 'xx', 'xx'], getline(1, '$'))
+ bwipe!
+endfunc
+
func Test_recursive_substitute_expr()
new
func Repl()
diff --git a/src/nvim/testdir/test_registers.vim b/src/nvim/testdir/test_registers.vim
index 11dd3badb6..5bdbbe7a22 100644
--- a/src/nvim/testdir/test_registers.vim
+++ b/src/nvim/testdir/test_registers.vim
@@ -263,8 +263,16 @@ func Test_get_register()
call assert_equal('', getreg("\<C-F>"))
call assert_equal('', getreg("\<C-W>"))
call assert_equal('', getreg("\<C-L>"))
+ " Change the last used register to '"' for the next test
+ normal! ""yy
+ let @" = 'happy'
+ call assert_equal('happy', getreg())
+ call assert_equal('happy', getreg(''))
call assert_equal('', getregtype('!'))
+ call assert_fails('echo getregtype([])', 'E730:')
+ call assert_equal('v', getregtype())
+ call assert_equal('v', getregtype(''))
" Test for inserting an invalid register content
call assert_beeps('exe "normal i\<C-R>!"')
@@ -277,7 +285,9 @@ func Test_get_register()
" Test for inserting a multi-line register in the command line
call feedkeys(":\<C-R>r\<Esc>", 'xt')
- call assert_equal("a\rb", histget(':', -1)) " Modified because of #6137
+ " Nvim: no trailing CR because of #6137
+ " call assert_equal("a\rb\r", histget(':', -1))
+ call assert_equal("a\rb", histget(':', -1))
call assert_fails('let r = getreg("=", [])', 'E745:')
call assert_fails('let r = getreg("=", 1, [])', 'E745:')
@@ -349,6 +359,12 @@ func Test_set_register()
normal 0".gP
call assert_equal('abcabcabc', getline(1))
+ let @"=''
+ call setreg('', '1')
+ call assert_equal('1', @")
+ call setreg('@', '2')
+ call assert_equal('2', @")
+
enew!
endfunc
diff --git a/src/nvim/testdir/test_reltime.vim b/src/nvim/testdir/test_reltime.vim
index b381f1ddbb..f4ce5de118 100644
--- a/src/nvim/testdir/test_reltime.vim
+++ b/src/nvim/testdir/test_reltime.vim
@@ -24,4 +24,8 @@ func Test_reltime()
call assert_true(reltimefloat(differs) < 0.1)
call assert_true(reltimefloat(differs) > 0.0)
+ call assert_equal(0, reltime({}))
+ call assert_equal(0, reltime({}, {}))
endfunc
+
+" vim: shiftwidth=2 sts=2 expandtab
diff --git a/src/nvim/testdir/test_search.vim b/src/nvim/testdir/test_search.vim
index 0cf55c7d0b..96ed35718f 100644
--- a/src/nvim/testdir/test_search.vim
+++ b/src/nvim/testdir/test_search.vim
@@ -294,6 +294,9 @@ func Test_searchpair()
new
call setline(1, ['other code', 'here [', ' [', ' " cursor here', ' ]]'])
+ " should not give an error for using "42"
+ call assert_equal(0, searchpair('a', 'b', 'c', '', 42))
+
4
call assert_equal(3, searchpair('\[', '', ']', 'bW'))
call assert_equal([0, 3, 2, 0], getpos('.'))
@@ -897,9 +900,7 @@ func Test_incsearch_cmdline_modifier()
endfunc
func Test_incsearch_scrolling()
- if !CanRunVimInTerminal()
- throw 'Skipped: cannot make screendumps'
- endif
+ CheckRunVimInTerminal
call assert_equal(0, &scrolloff)
call writefile([
\ 'let dots = repeat(".", 120)',
@@ -1649,8 +1650,8 @@ func Test_search_with_no_last_pat()
call assert_fails(";//p", 'E35:')
call assert_fails("??p", 'E35:')
call assert_fails(";??p", 'E35:')
- call assert_fails('g//p', 'E476:')
- call assert_fails('v//p', 'E476:')
+ call assert_fails('g//p', ['E35:', 'E476:'])
+ call assert_fails('v//p', ['E35:', 'E476:'])
call writefile(v:errors, 'Xresult')
qall!
[SCRIPT]
@@ -1671,8 +1672,8 @@ func Test_search_tilde_pat()
call assert_fails('exe "normal /~\<CR>"', 'E33:')
call assert_fails('exe "normal ?~\<CR>"', 'E33:')
set regexpengine=2
- call assert_fails('exe "normal /~\<CR>"', 'E383:')
- call assert_fails('exe "normal ?~\<CR>"', 'E383:')
+ call assert_fails('exe "normal /~\<CR>"', ['E33:', 'E383:'])
+ call assert_fails('exe "normal ?~\<CR>"', ['E33:', 'E383:'])
set regexpengine&
call writefile(v:errors, 'Xresult')
qall!
@@ -1752,6 +1753,25 @@ func Test_invalid_regexp()
call assert_fails("call search('\\%#=3ab')", 'E864:')
endfunc
+" Test for searching a very complex pattern in a string. Should switch the
+" regexp engine from NFA to the old engine.
+func Test_regexp_switch_engine()
+ let l = readfile('samples/re.freeze.txt')
+ let v = substitute(l[4], '..\@<!', '', '')
+ call assert_equal(l[4], v)
+endfunc
+
+" Test for the \%V atom to search within visually selected text
+func Test_search_in_visual_area()
+ new
+ call setline(1, ['foo bar1', 'foo bar2', 'foo bar3', 'foo bar4'])
+ exe "normal 2GVjo/\\%Vbar\<CR>\<Esc>"
+ call assert_equal([2, 5], [line('.'), col('.')])
+ exe "normal 2GVj$?\\%Vbar\<CR>\<Esc>"
+ call assert_equal([3, 5], [line('.'), col('.')])
+ close!
+endfunc
+
" Test for searching with 'smartcase' and 'ignorecase'
func Test_search_smartcase()
new
diff --git a/src/nvim/testdir/test_selectmode.vim b/src/nvim/testdir/test_selectmode.vim
index f2cab45450..041f0592f1 100644
--- a/src/nvim/testdir/test_selectmode.vim
+++ b/src/nvim/testdir/test_selectmode.vim
@@ -34,6 +34,9 @@ func Test_selectmode_start()
set selectmode=cmd
call feedkeys('gvabc', 'xt')
call assert_equal('abctdef', getline(1))
+ " arrow keys without shift should not start selection
+ call feedkeys("A\<Home>\<Right>\<Left>ro", 'xt')
+ call assert_equal('roabctdef', getline(1))
set selectmode= keymodel=
bw!
endfunc
diff --git a/src/nvim/testdir/test_signals.vim b/src/nvim/testdir/test_signals.vim
index e1c6e5d11f..c291c68e0d 100644
--- a/src/nvim/testdir/test_signals.vim
+++ b/src/nvim/testdir/test_signals.vim
@@ -53,7 +53,7 @@ endfunc
" Test signal PWR, which should update the swap file.
func Test_signal_PWR()
if !HasSignal('PWR')
- return
+ throw 'Skipped: PWR signal not supported'
endif
" Set a very large 'updatetime' and 'updatecount', so that we can be sure
@@ -79,6 +79,33 @@ func Test_signal_PWR()
set updatetime& updatecount&
endfunc
+" Test signal INT. Handler sets got_int. It should be like typing CTRL-C.
+func Test_signal_INT()
+ CheckRunVimInTerminal
+ if !HasSignal('INT')
+ throw 'Skipped: INT signal not supported'
+ endif
+
+ " Skip the rest of the test when running with valgrind as signal INT is not
+ " received somehow by Vim when running with valgrind.
+ let cmd = GetVimCommand()
+ if cmd =~ 'valgrind'
+ throw 'Skipped: cannot test signal INT with valgrind'
+ endif
+
+ let buf = RunVimInTerminal('', {'rows': 6})
+ let pid_vim = term_getjob(buf)->job_info().process
+
+ " Check that an endless loop in Vim is interrupted by signal INT.
+ call term_sendkeys(buf, ":while 1 | endwhile\n")
+ call WaitForAssert({-> assert_equal(':while 1 | endwhile', term_getline(buf, 6))})
+ exe 'silent !kill -s INT ' .. pid_vim
+ call term_sendkeys(buf, ":call setline(1, 'INTERUPTED')\n")
+ call WaitForAssert({-> assert_equal('INTERUPTED', term_getline(buf, 1))})
+
+ call StopVimInTerminal(buf)
+endfunc
+
" Test a deadly signal.
"
" There are several deadly signals: SISEGV, SIBUS, SIGTERM...
@@ -92,9 +119,7 @@ func Test_deadly_signal_TERM()
if !HasSignal('TERM')
throw 'Skipped: TERM signal not supported'
endif
- if !CanRunVimInTerminal()
- throw 'Skipped: cannot run vim in terminal'
- endif
+ CheckRunVimInTerminal
let cmd = GetVimCommand()
if cmd =~ 'valgrind'
throw 'Skipped: cannot test signal TERM with valgrind'
diff --git a/src/nvim/testdir/test_signs.vim b/src/nvim/testdir/test_signs.vim
index ff9ba3d8ed..1f1b3097b1 100644
--- a/src/nvim/testdir/test_signs.vim
+++ b/src/nvim/testdir/test_signs.vim
@@ -483,13 +483,13 @@ func Test_sign_funcs()
call assert_fails('call sign_place(5, "", "sign1", "@", {"lnum" : 10})',
\ 'E158:')
call assert_fails('call sign_place(5, "", "sign1", [], {"lnum" : 10})',
- \ 'E158:')
+ \ 'E730:')
call assert_fails('call sign_place(21, "", "sign1", "Xsign",
\ {"lnum" : -1})', 'E474:')
call assert_fails('call sign_place(22, "", "sign1", "Xsign",
\ {"lnum" : 0})', 'E474:')
call assert_fails('call sign_place(22, "", "sign1", "Xsign",
- \ {"lnum" : []})', 'E474:')
+ \ {"lnum" : []})', 'E745:')
call assert_equal(-1, sign_place(1, "*", "sign1", "Xsign", {"lnum" : 10}))
" Tests for sign_getplaced()
@@ -1731,7 +1731,7 @@ func Test_sign_jump_func()
call assert_fails("call sign_jump(5, 'g5', 'foo')", 'E157:')
call assert_fails('call sign_jump([], "", "foo")', 'E745:')
call assert_fails('call sign_jump(2, [], "foo")', 'E730:')
- call assert_fails('call sign_jump(2, "", {})', 'E158:')
+ call assert_fails('call sign_jump(2, "", {})', 'E731:')
call assert_fails('call sign_jump(2, "", "baz")', 'E158:')
sign unplace * group=*
@@ -1741,9 +1741,7 @@ endfunc
" Test for correct cursor position after the sign column appears or disappears.
func Test_sign_cursor_position()
- if !CanRunVimInTerminal()
- throw 'Skipped: cannot make screendumps'
- endif
+ CheckRunVimInTerminal
let lines =<< trim END
call setline(1, [repeat('x', 75), 'mmmm', 'yyyy'])
diff --git a/src/nvim/testdir/test_sort.vim b/src/nvim/testdir/test_sort.vim
index c3e7788164..f9cbcbb55f 100644
--- a/src/nvim/testdir/test_sort.vim
+++ b/src/nvim/testdir/test_sort.vim
@@ -1360,7 +1360,7 @@ func Test_sort_cmd()
call setline(1, ['line1', 'line2'])
call assert_fails('sort no', 'E474:')
call assert_fails('sort c', 'E475:')
- call assert_fails('sort #pat%', 'E682:')
+ call assert_fails('sort #pat%', 'E654:')
enew!
endfunc
diff --git a/src/nvim/testdir/test_spell.vim b/src/nvim/testdir/test_spell.vim
index 4af02d3d31..d8495fdb9b 100644
--- a/src/nvim/testdir/test_spell.vim
+++ b/src/nvim/testdir/test_spell.vim
@@ -495,7 +495,7 @@ func Test_spellsuggest_expr_errors()
return [[{}, {}]]
endfunc
set spellsuggest=expr:MySuggest3()
- call assert_fails("call spellsuggest('baord')", 'E728:')
+ call assert_fails("call spellsuggest('baord')", 'E731:')
set nospell spellsuggest&
delfunc MySuggest
@@ -1430,3 +1430,5 @@ let g:test_data_aff_sal = [
\"SAL ZZ- _",
\"SAL Z S",
\ ]
+
+" vim: shiftwidth=2 sts=2 expandtab
diff --git a/src/nvim/testdir/test_startup.vim b/src/nvim/testdir/test_startup.vim
index b8aad1bc46..30bbd355df 100644
--- a/src/nvim/testdir/test_startup.vim
+++ b/src/nvim/testdir/test_startup.vim
@@ -809,9 +809,7 @@ func Test_issue_3969()
endfunc
func Test_start_with_tabs()
- if !CanRunVimInTerminal()
- return
- endif
+ CheckRunVimInTerminal
let buf = RunVimInTerminal('-p a b c', {})
call VerifyScreenDump(buf, 'Test_start_with_tabs', {})
@@ -968,9 +966,7 @@ endfunc
" Test for specifying a non-existing vimrc file using "-u"
func Test_missing_vimrc()
- if !CanRunVimInTerminal()
- throw 'Skipped: cannot run vim in terminal'
- endif
+ CheckRunVimInTerminal
let after =<< trim [CODE]
call assert_match('^E282:', v:errmsg)
call writefile(v:errors, 'Xtestout')
diff --git a/src/nvim/testdir/test_startup_utf8.vim b/src/nvim/testdir/test_startup_utf8.vim
index bb4304396e..2ee6ecc41d 100644
--- a/src/nvim/testdir/test_startup_utf8.vim
+++ b/src/nvim/testdir/test_startup_utf8.vim
@@ -63,9 +63,7 @@ func Test_read_fifo_utf8()
endfunc
func Test_detect_ambiwidth()
- if !CanRunVimInTerminal()
- throw 'Skipped: cannot run Vim in a terminal window'
- endif
+ CheckRunVimInTerminal
" Use the title termcap entries to output the escape sequence.
call writefile([
diff --git a/src/nvim/testdir/test_substitute.vim b/src/nvim/testdir/test_substitute.vim
index 88a3c13d65..5b476ddd7f 100644
--- a/src/nvim/testdir/test_substitute.vim
+++ b/src/nvim/testdir/test_substitute.vim
@@ -446,13 +446,18 @@ func Test_substitute_errors()
call assert_fails('s/FOO/bar/', 'E486:')
call assert_fails('s/foo/bar/@', 'E488:')
- call assert_fails('s/\(/bar/', 'E476:')
+ call assert_fails('s/\(/bar/', 'E54:')
call assert_fails('s afooabara', 'E146:')
call assert_fails('s\\a', 'E10:')
setl nomodifiable
call assert_fails('s/foo/bar/', 'E21:')
+ call assert_fails("let s=substitute([], 'a', 'A', 'g')", 'E730:')
+ call assert_fails("let s=substitute('abcda', [], 'A', 'g')", 'E730:')
+ call assert_fails("let s=substitute('abcda', 'a', [], 'g')", 'E730:')
+ call assert_fails("let s=substitute('abcda', 'a', 'A', [])", 'E730:')
+
bwipe!
endfunc
@@ -488,6 +493,9 @@ func Test_sub_replace_1()
call assert_equal("x\<C-M>x", substitute('xXx', 'X', "\r", ''))
call assert_equal("YyyY", substitute('Y', 'Y', '\L\uyYy\l\EY', ''))
call assert_equal("zZZz", substitute('Z', 'Z', '\U\lZzZ\u\Ez', ''))
+ " \v or \V after $
+ call assert_equal('abxx', substitute('abcd', 'xy$\v|cd$', 'xx', ''))
+ call assert_equal('abxx', substitute('abcd', 'xy$\V\|cd\$', 'xx', ''))
endfunc
func Test_sub_replace_2()
@@ -833,9 +841,9 @@ endfunc
func Test_sub_with_no_last_pat()
let lines =<< trim [SCRIPT]
call assert_fails('~', 'E33:')
- call assert_fails('s//abc/g', 'E476:')
- call assert_fails('s\/bar', 'E476:')
- call assert_fails('s\&bar&', 'E476:')
+ call assert_fails('s//abc/g', 'E35:')
+ call assert_fails('s\/bar', 'E35:')
+ call assert_fails('s\&bar&', 'E33:')
call writefile(v:errors, 'Xresult')
qall!
[SCRIPT]
@@ -862,6 +870,40 @@ endfunc
func Test_substitute()
call assert_equal('a1a2a3a', substitute('123', '\zs', 'a', 'g'))
+ " Substitute with special keys
+ call assert_equal("a\<End>c", substitute('abc', "a.c", "a\<End>c", ''))
+endfunc
+
+func Test_substitute_expr()
+ let g:val = 'XXX'
+ call assert_equal('XXX', substitute('yyy', 'y*', '\=g:val', ''))
+ call assert_equal('XXX', substitute('yyy', 'y*', {-> g:val}, ''))
+ call assert_equal("-\u1b \uf2-", substitute("-%1b %f2-", '%\(\x\x\)',
+ \ '\=nr2char("0x" . submatch(1))', 'g'))
+ call assert_equal("-\u1b \uf2-", substitute("-%1b %f2-", '%\(\x\x\)',
+ \ {-> nr2char("0x" . submatch(1))}, 'g'))
+
+ call assert_equal('231', substitute('123', '\(.\)\(.\)\(.\)',
+ \ {-> submatch(2) . submatch(3) . submatch(1)}, ''))
+
+ func Recurse()
+ return substitute('yyy', 'y\(.\)y', {-> submatch(1)}, '')
+ endfunc
+ " recursive call works
+ call assert_equal('-y-x-', substitute('xxx', 'x\(.\)x', {-> '-' . Recurse() . '-' . submatch(1) . '-'}, ''))
+
+ call assert_fails("let s=submatch([])", 'E745:')
+ call assert_fails("let s=submatch(2, [])", 'E745:')
+endfunc
+
+func Test_invalid_submatch()
+ " This was causing invalid memory access in Vim-7.4.2232 and older
+ call assert_fails("call substitute('x', '.', {-> submatch(10)}, '')", 'E935:')
+ call assert_fails('eval submatch(-1)', 'E935:')
+ call assert_equal('', submatch(0))
+ call assert_equal('', submatch(1))
+ call assert_equal([], submatch(0, 1))
+ call assert_equal([], submatch(1, 1))
endfunc
func Test_submatch_list_concatenate()
@@ -870,6 +912,44 @@ func Test_submatch_list_concatenate()
call substitute('A1', pat, Rep, '')->assert_equal("[['A1'], ['1']]")
endfunc
+func Test_substitute_expr_arg()
+ call assert_equal('123456789-123456789=', substitute('123456789',
+ \ '\(.\)\(.\)\(.\)\(.\)\(.\)\(.\)\(.\)\(.\)\(.\)',
+ \ {m -> m[0] . '-' . m[1] . m[2] . m[3] . m[4] . m[5] . m[6] . m[7] . m[8] . m[9] . '='}, ''))
+
+ call assert_equal('123456-123456=789', substitute('123456789',
+ \ '\(.\)\(.\)\(.\)\(a*\)\(n*\)\(.\)\(.\)\(.\)\(x*\)',
+ \ {m -> m[0] . '-' . m[1] . m[2] . m[3] . m[4] . m[5] . m[6] . m[7] . m[8] . m[9] . '='}, ''))
+
+ call assert_equal('123456789-123456789x=', substitute('123456789',
+ \ '\(.\)\(.\)\(.*\)',
+ \ {m -> m[0] . '-' . m[1] . m[2] . m[3] . 'x' . m[4] . m[5] . m[6] . m[7] . m[8] . m[9] . '='}, ''))
+
+ call assert_fails("call substitute('xxx', '.', {m -> string(add(m, 'x'))}, '')", 'E742:')
+ call assert_fails("call substitute('xxx', '.', {m -> string(insert(m, 'x'))}, '')", 'E742:')
+ call assert_fails("call substitute('xxx', '.', {m -> string(extend(m, ['x']))}, '')", 'E742:')
+ call assert_fails("call substitute('xxx', '.', {m -> string(remove(m, 1))}, '')", 'E742:')
+endfunc
+
+" Test for using a function to supply the substitute string
+func Test_substitute_using_func()
+ func Xfunc()
+ return '1234'
+ endfunc
+ call assert_equal('a1234f', substitute('abcdef', 'b..e',
+ \ function("Xfunc"), ''))
+ delfunc Xfunc
+endfunc
+
+" Test for using submatch() with a multiline match
+func Test_substitute_multiline_submatch()
+ new
+ call setline(1, ['line1', 'line2', 'line3', 'line4'])
+ %s/^line1\(\_.\+\)line4$/\=submatch(1)/
+ call assert_equal(['', 'line2', 'line3', ''], getline(1, '$'))
+ close!
+endfunc
+
func Test_substitute_skipped_range()
new
if 0
diff --git a/src/nvim/testdir/test_syntax.vim b/src/nvim/testdir/test_syntax.vim
index d686ad7e96..9d108c6ca2 100644
--- a/src/nvim/testdir/test_syntax.vim
+++ b/src/nvim/testdir/test_syntax.vim
@@ -378,7 +378,7 @@ func Test_syntax_invalid_arg()
call assert_fails('syntax sync x', 'E404:')
call assert_fails('syntax keyword Abc a[', 'E789:')
call assert_fails('syntax keyword Abc a[bc]d', 'E890:')
- call assert_fails('syntax cluster Abc add=A add=', 'E475:')
+ call assert_fails('syntax cluster Abc add=A add=', 'E406:')
" Test for too many \z\( and unmatched \z\(
" Not able to use assert_fails() here because both E50:/E879: and E475:
@@ -623,15 +623,15 @@ func Test_synstack_synIDtrans()
call assert_equal(['cComment', 'cTodo'], map(synstack(line("."), col(".")), 'synIDattr(v:val, "name")'))
call assert_equal(['Comment', 'Todo'], map(synstack(line("."), col(".")), 'synIDattr(synIDtrans(v:val), "name")'))
+ call assert_fails("let n=synIDtrans([])", 'E745:')
+
syn clear
bw!
endfunc
" Check highlighting for a small piece of C code with a screen dump.
func Test_syntax_c()
- if !CanRunVimInTerminal()
- throw 'Skipped: cannot make screendumps'
- endif
+ CheckRunVimInTerminal
call writefile([
\ '/* comment line at the top */',
\ 'int main(int argc, char **argv) { // another comment',
diff --git a/src/nvim/testdir/test_tabpage.vim b/src/nvim/testdir/test_tabpage.vim
index 6d468ec9de..b97aa409d8 100644
--- a/src/nvim/testdir/test_tabpage.vim
+++ b/src/nvim/testdir/test_tabpage.vim
@@ -591,9 +591,7 @@ func Test_tabs()
endfunc
func Test_tabpage_cmdheight()
- if !CanRunVimInTerminal()
- throw 'Skipped: cannot make screendumps'
- endif
+ CheckRunVimInTerminal
call writefile([
\ 'set laststatus=2',
\ 'set cmdheight=2',
@@ -623,6 +621,17 @@ func Test_tabpage_close_cmdwin()
tabonly
endfunc
+" Pressing <C-PageUp> in insert mode should go to the previous tab page
+" and <C-PageDown> should go to the next tab page
+func Test_tabpage_Ctrl_Pageup()
+ tabnew
+ call feedkeys("i\<C-PageUp>", 'xt')
+ call assert_equal(1, tabpagenr())
+ call feedkeys("i\<C-PageDown>", 'xt')
+ call assert_equal(2, tabpagenr())
+ %bw!
+endfunc
+
" Return the terminal key code for selecting a tab page from the tabline. This
" sequence contains the following codes: a CSI (0x9b), KS_TABLINE (0xf0),
" KS_FILLER (0x58) and then the tab page number.
diff --git a/src/nvim/testdir/test_tagfunc.vim b/src/nvim/testdir/test_tagfunc.vim
index ffc1d63b90..bdf5afa5b2 100644
--- a/src/nvim/testdir/test_tagfunc.vim
+++ b/src/nvim/testdir/test_tagfunc.vim
@@ -85,7 +85,7 @@ func Test_tagfunc()
return v:null
endfunc
set tags= tfu=NullTagFunc
- call assert_fails('tag nothing', 'E426')
+ call assert_fails('tag nothing', 'E433')
delf NullTagFunc
bwipe!
diff --git a/src/nvim/testdir/test_tagjump.vim b/src/nvim/testdir/test_tagjump.vim
index 04c0218f74..61bf9e6d0d 100644
--- a/src/nvim/testdir/test_tagjump.vim
+++ b/src/nvim/testdir/test_tagjump.vim
@@ -8,7 +8,7 @@ func Test_ptag_with_notagstack()
CheckFeature quickfix
set notagstack
- call assert_fails('ptag does_not_exist_tag_name', 'E426')
+ call assert_fails('ptag does_not_exist_tag_name', 'E433')
set tagstack&vim
endfunc
@@ -282,6 +282,7 @@ func Test_tag_file_encoding()
call delete('Xtags1')
endfunc
+" Test for emacs-style tags file (TAGS)
func Test_tagjump_etags()
if !has('emacs_tags')
return
@@ -345,7 +346,7 @@ func Test_tagjump_etags()
\ "Xmain.c,64",
\ ";;;;\x7f1,0",
\ ], 'Xtags')
- call assert_fails('tag foo', 'E426:')
+ call assert_fails('tag foo', 'E431:')
call delete('Xtags')
call delete('Xtags2')
@@ -371,6 +372,7 @@ func Test_getsettagstack()
call assert_fails("call settagstack(1, {'items' : 10})", 'E714')
call assert_fails("call settagstack(1, {'items' : []}, 10)", 'E928')
call assert_fails("call settagstack(1, {'items' : []}, 'b')", 'E962')
+ call assert_equal(-1, settagstack(0, v:_null_dict))
set tags=Xtags
call writefile(["!_TAG_FILE_ENCODING\tutf-8\t//",
@@ -1099,7 +1101,7 @@ func Test_tselect_listing()
call writefile([
\ "!_TAG_FILE_ENCODING\tutf-8\t//",
\ "first\tXfoo\t1" .. ';"' .. "\tv\ttyperef:typename:int\tfile:",
- \ "first\tXfoo\t2" .. ';"' .. "\tv\ttyperef:typename:char\tfile:"],
+ \ "first\tXfoo\t2" .. ';"' .. "\tkind:v\ttyperef:typename:char\tfile:"],
\ 'Xtags')
set tags=Xtags
@@ -1422,4 +1424,56 @@ func Test_tag_length()
set tags& taglength&
endfunc
+" Tests for errors in a tags file
+func Test_tagfile_errors()
+ set tags=Xtags
+
+ " missing search pattern or line number for a tag
+ call writefile(["!_TAG_FILE_ENCODING\tutf-8\t//",
+ \ "foo\tXfile\t"], 'Xtags', 'b')
+ call writefile(['foo'], 'Xfile')
+
+ enew
+ tag foo
+ call assert_equal('', @%)
+ let caught_431 = v:false
+ try
+ eval taglist('.*')
+ catch /:E431:/
+ let caught_431 = v:true
+ endtry
+ call assert_equal(v:true, caught_431)
+
+ call delete('Xtags')
+ call delete('Xfile')
+ set tags&
+endfunc
+
+" When :stag fails to open the file, should close the new window
+func Test_stag_close_window_on_error()
+ new | only
+ set tags=Xtags
+ call writefile(["!_TAG_FILE_ENCODING\tutf-8\t//",
+ \ "foo\tXfile\t1"], 'Xtags')
+ call writefile(['foo'], 'Xfile')
+ call writefile([], '.Xfile.swp')
+ " Remove the catch-all that runtest.vim adds
+ au! SwapExists
+ augroup StagTest
+ au!
+ autocmd SwapExists Xfile let v:swapchoice='q'
+ augroup END
+
+ stag foo
+ call assert_equal(1, winnr('$'))
+ call assert_equal('', @%)
+
+ augroup StagTest
+ au!
+ augroup END
+ call delete('Xfile')
+ call delete('.Xfile.swp')
+ set tags&
+endfunc
+
" vim: shiftwidth=2 sts=2 expandtab
diff --git a/src/nvim/testdir/test_taglist.vim b/src/nvim/testdir/test_taglist.vim
index be46773256..658485582c 100644
--- a/src/nvim/testdir/test_taglist.vim
+++ b/src/nvim/testdir/test_taglist.vim
@@ -36,6 +36,8 @@ func Test_taglist()
call assert_equal('d', cmd[0]['kind'])
call assert_equal('call cursor(3, 4)', cmd[0]['cmd'])
+ call assert_fails("let l=taglist([])", 'E730:')
+
call delete('Xtags')
set tags&
bwipe
@@ -82,13 +84,11 @@ func Test_taglist_ctags_etags()
endfunc
func Test_tags_too_long()
- call assert_fails('tag ' . repeat('x', 1020), 'E426')
+ call assert_fails('tag ' . repeat('x', 1020), ['E433', 'E426'])
tags
endfunc
func Test_tagfiles()
- " Nvim: different default for 'tags'.
- set tags=./tags,tags
call assert_equal([], tagfiles())
call writefile(["FFoo\tXfoo\t1"], 'Xtags1')
diff --git a/src/nvim/testdir/test_textformat.vim b/src/nvim/testdir/test_textformat.vim
index 4eb6e69adf..3bce2eb24d 100644
--- a/src/nvim/testdir/test_textformat.vim
+++ b/src/nvim/testdir/test_textformat.vim
@@ -1096,6 +1096,20 @@ func Test_fo_a_w()
call feedkeys("iabc abc a abc\<Esc>k0weade", 'xt')
call assert_equal(['abc abcde ', 'a abc'], getline(1, '$'))
+ " when a line ends with space, it is not broken up.
+ %d
+ call feedkeys("ione two to ", 'xt')
+ call assert_equal('one two to ', getline(1))
+
+ " when a line ends with spaces and backspace is used in the next line, the
+ " last space in the previous line should be removed.
+ %d
+ set backspace=indent,eol,start
+ call setline(1, ['one ', 'two'])
+ exe "normal 2Gi\<BS>"
+ call assert_equal(['one two'], getline(1, '$'))
+ set backspace&
+
" Test for 'a', 'w' and '1' options.
setlocal textwidth=0
setlocal fo=1aw
diff --git a/src/nvim/testdir/test_timers.vim b/src/nvim/testdir/test_timers.vim
index 3a6abb3968..f94ee6c9f3 100644
--- a/src/nvim/testdir/test_timers.vim
+++ b/src/nvim/testdir/test_timers.vim
@@ -304,9 +304,7 @@ func Test_timer_ex_mode()
endfunc
func Test_timer_restore_count()
- if !CanRunVimInTerminal()
- throw 'Skipped: cannot run Vim in a terminal window'
- endif
+ CheckRunVimInTerminal
" Check that v:count is saved and restored, not changed by a timer.
call writefile([
\ 'nnoremap <expr><silent> L v:count ? v:count . "l" : "l"',
diff --git a/src/nvim/testdir/test_trycatch.vim b/src/nvim/testdir/test_trycatch.vim
index d71bb5bbb8..8a1d2d3fa7 100644
--- a/src/nvim/testdir/test_trycatch.vim
+++ b/src/nvim/testdir/test_trycatch.vim
@@ -2000,13 +2000,11 @@ endfunc
func Test_try_catch_errors()
call assert_fails('throw |', 'E471:')
call assert_fails("throw \n ", 'E471:')
- call assert_fails('catch abc', 'E603:')
+ call assert_fails('catch abc', 'E654:')
call assert_fails('try | let i = 1| finally | catch | endtry', 'E604:')
call assert_fails('finally', 'E606:')
call assert_fails('try | finally | finally | endtry', 'E607:')
- " v8.2.3486 has been ported, but v8.2.1183 hasn't, so E170 appears here.
- " call assert_fails('try | for i in range(5) | endif | endtry', 'E580:')
- call assert_fails('try | for i in range(5) | endif | endtry', 'E170:')
+ call assert_fails('try | for i in range(5) | endif | endtry', 'E580:')
call assert_fails('try | while v:true | endtry', 'E170:')
call assert_fails('try | if v:true | endtry', 'E171:')
endfunc
@@ -2223,6 +2221,23 @@ func Test_user_command_throw_in_function_call()
unlet g:caught
endfunc
+" Test that after reporting an uncaught exception there is no error for a
+" missing :endif
+func Test_after_exception_no_endif_error()
+ function Throw()
+ throw "Failure"
+ endfunction
+
+ function Foo()
+ if 1
+ call Throw()
+ endif
+ endfunction
+ call assert_fails('call Foo()', ['E605:', 'E605:'])
+ delfunc Throw
+ delfunc Foo
+endfunc
+
" Test for using throw in a called function with following endtry {{{1
func Test_user_command_function_call_with_endtry()
let lines =<< trim END
diff --git a/src/nvim/testdir/test_utf8.vim b/src/nvim/testdir/test_utf8.vim
index 7145d303cc..aa3b02b575 100644
--- a/src/nvim/testdir/test_utf8.vim
+++ b/src/nvim/testdir/test_utf8.vim
@@ -12,7 +12,7 @@ func Test_visual_block_insert()
bwipeout!
endfunc
-" Test for built-in function strchars()
+" Test for built-in functions strchars() and strcharlen()
func Test_strchars()
let inp = ["a", "あいa", "A\u20dd", "A\u20dd\u20dd", "\u20dd"]
let exp = [[1, 1, 1], [3, 3, 3], [2, 2, 1], [3, 3, 1], [1, 1, 1]]
@@ -21,6 +21,15 @@ func Test_strchars()
call assert_equal(exp[i][1], inp[i]->strchars(0))
call assert_equal(exp[i][2], strchars(inp[i], 1))
endfor
+
+ let exp = [1, 3, 1, 1, 1]
+ for i in range(len(inp))
+ call assert_equal(exp[i], inp[i]->strcharlen())
+ call assert_equal(exp[i], strcharlen(inp[i]))
+ endfor
+
+ call assert_fails("let v=strchars('abc', [])", 'E745:')
+ call assert_fails("let v=strchars('abc', 2)", 'E1023:')
endfunc
" Test for customlist completion
diff --git a/src/nvim/testdir/test_vartabs.vim b/src/nvim/testdir/test_vartabs.vim
index 32ad64cda4..e12c71d521 100644
--- a/src/nvim/testdir/test_vartabs.vim
+++ b/src/nvim/testdir/test_vartabs.vim
@@ -379,6 +379,8 @@ func Test_vartabs_shiftwidth()
let lines = ScreenLines([1, 3], winwidth(0))
call s:compare_lines(expect4, lines)
+ call assert_fails('call shiftwidth([])', 'E745:')
+
" cleanup
bw!
bw!
diff --git a/src/nvim/testdir/test_vimscript.vim b/src/nvim/testdir/test_vimscript.vim
index f20fd12ed3..8faa9135e5 100644
--- a/src/nvim/testdir/test_vimscript.vim
+++ b/src/nvim/testdir/test_vimscript.vim
@@ -3,14 +3,12 @@
source check.vim
source shared.vim
+source script_util.vim
"-------------------------------------------------------------------------------
" Test environment {{{1
"-------------------------------------------------------------------------------
-com! XpathINIT let g:Xpath = ''
-com! -nargs=1 -bar Xpath let g:Xpath = g:Xpath . <args>
-
" Append a message to the "messages" file
func Xout(text)
split messages
@@ -20,67 +18,31 @@ endfunc
com! -nargs=1 Xout call Xout(<args>)
-" MakeScript() - Make a script file from a function. {{{2
-"
-" Create a script that consists of the body of the function a:funcname.
-" Replace any ":return" by a ":finish", any argument variable by a global
-" variable, and every ":call" by a ":source" for the next following argument
-" in the variable argument list. This function is useful if similar tests are
-" to be made for a ":return" from a function call or a ":finish" in a script
-" file.
-func MakeScript(funcname, ...)
- let script = tempname()
- execute "redir! >" . script
- execute "function" a:funcname
- redir END
- execute "edit" script
- " Delete the "function" and the "endfunction" lines. Do not include the
- " word "function" in the pattern since it might be translated if LANG is
- " set. When MakeScript() is being debugged, this deletes also the debugging
- " output of its line 3 and 4.
- exec '1,/.*' . a:funcname . '(.*)/d'
- /^\d*\s*endfunction\>/,$d
- %s/^\d*//e
- %s/return/finish/e
- %s/\<a:\(\h\w*\)/g:\1/ge
- normal gg0
- let cnt = 0
- while search('\<call\s*\%(\u\|s:\)\w*\s*(.*)', 'W') > 0
- let cnt = cnt + 1
- s/\<call\s*\%(\u\|s:\)\w*\s*(.*)/\='source ' . a:{cnt}/
- endwhile
- g/^\s*$/d
- write
- bwipeout
- return script
-endfunc
-
-" ExecAsScript - Source a temporary script made from a function. {{{2
-"
-" Make a temporary script file from the function a:funcname, ":source" it, and
-" delete it afterwards. However, if an exception is thrown the file may remain,
-" the caller should call DeleteTheScript() afterwards.
-let s:script_name = ''
-function! ExecAsScript(funcname)
- " Make a script from the function passed as argument.
- let s:script_name = MakeScript(a:funcname)
-
- " Source and delete the script.
- exec "source" s:script_name
- call delete(s:script_name)
- let s:script_name = ''
-endfunction
-
-function! DeleteTheScript()
- if s:script_name
- call delete(s:script_name)
- let s:script_name = ''
- endif
+" Create a new instance of Vim and run the commands in 'test' and then 'verify'
+" The commands in 'test' are expected to store the test results in the Xtest.out
+" file. If the test passes successfully, then Xtest.out should be empty.
+func RunInNewVim(test, verify)
+ let init =<< trim END
+ set cpo-=C " support line-continuation in sourced script
+ source script_util.vim
+ XpathINIT
+ XloopINIT
+ END
+ let cleanup =<< trim END
+ call writefile(v:errors, 'Xtest.out')
+ qall
+ END
+ call writefile(init, 'Xtest.vim')
+ call writefile(a:test, 'Xtest.vim', 'a')
+ call writefile(a:verify, 'Xverify.vim')
+ call writefile(cleanup, 'Xverify.vim', 'a')
+ call RunVim([], [], "-S Xtest.vim -S Xverify.vim")
+ call assert_equal([], readfile('Xtest.out'))
+ call delete('Xtest.out')
+ call delete('Xtest.vim')
+ call delete('Xverify.vim')
endfunc
-com! -nargs=1 -bar ExecAsScript call ExecAsScript(<f-args>)
-
-
"-------------------------------------------------------------------------------
" Test 1: :endwhile in function {{{1
"
@@ -90,7 +52,7 @@ com! -nargs=1 -bar ExecAsScript call ExecAsScript(<f-args>)
" tests will hang.
"-------------------------------------------------------------------------------
-function! T1_F()
+func T1_F()
Xpath 'a'
let first = 1
while 1
@@ -104,9 +66,9 @@ function! T1_F()
return
endif
endwhile
-endfunction
+endfunc
-function! T1_G()
+func T1_G()
Xpath 'h'
let first = 1
while 1
@@ -121,7 +83,7 @@ function! T1_G()
endif
if 1 " unmatched :if
endwhile
-endfunction
+endfunc
func Test_endwhile_function()
XpathINIT
@@ -175,7 +137,7 @@ endfunc
" Test 3: :if, :elseif, :while, :continue, :break {{{1
"-------------------------------------------------------------------------------
-function Test_if_while()
+func Test_if_while()
XpathINIT
if 1
Xpath 'a'
@@ -235,7 +197,7 @@ endfunc
" Test 4: :return {{{1
"-------------------------------------------------------------------------------
-function! T4_F()
+func T4_F()
if 1
Xpath 'a'
let loops = 3
@@ -253,15 +215,15 @@ function! T4_F()
else
Xpath 'g'
endif
-endfunction
+endfunc
-function Test_return()
+func Test_return()
XpathINIT
call T4_F()
Xpath '4'
call assert_equal('ab3e3b2c24', g:Xpath)
-endfunction
+endfunc
"-------------------------------------------------------------------------------
@@ -271,14 +233,14 @@ endfunction
" test as a script file (:return replaced by :finish).
"-------------------------------------------------------------------------------
-function Test_finish()
+func Test_finish()
XpathINIT
ExecAsScript T4_F
Xpath '5'
call DeleteTheScript()
call assert_equal('ab3e3b2c25', g:Xpath)
-endfunction
+endfunc
@@ -412,7 +374,7 @@ delfunction G31
delfunction G32
delfunction G33
-function Test_defining_functions()
+func Test_defining_functions()
call assert_equal('ade2ie3ibcg0h1g1h2g2h3fg0h1g1h2g2h3m', g:test6_result)
call assert_equal('F1G1F2G21G22G23F3G31G32G33', g:test6_calls)
endfunc
@@ -476,7 +438,7 @@ endfunc
XpathINIT
-function! T8_F()
+func T8_F()
if 1
Xpath 'a'
while 1
@@ -508,9 +470,9 @@ function! T8_F()
return novar " returns (default return value 0)
Xpath 'q'
return 1 " not reached
-endfunction
+endfunc
-function! T8_G() abort
+func T8_G() abort
if 1
Xpath 'r'
while 1
@@ -524,9 +486,9 @@ function! T8_G() abort
Xpath 'x'
return -4 " not reached
-endfunction
+endfunc
-function! T8_H() abort
+func T8_H() abort
while 1
Xpath 'A'
if 1
@@ -540,7 +502,7 @@ function! T8_H() abort
Xpath 'F'
return -4 " not reached
-endfunction
+endfunc
" Aborted functions (T8_G and T8_H) return -1.
let g:test8_sum = (T8_F() + 1) - 4 * T8_G() - 8 * T8_H()
@@ -567,7 +529,7 @@ endfunc
XpathINIT
-function! F() abort
+func F() abort
Xpath 'a'
let result = G() " not aborted
Xpath 'b'
@@ -575,30 +537,30 @@ function! F() abort
Xpath 'c'
endif
return 1
-endfunction
+endfunc
-function! G() " no abort attribute
+func G() " no abort attribute
Xpath 'd'
if H() != -1 " aborted
Xpath 'e'
endif
Xpath 'f'
return 2
-endfunction
+endfunc
-function! H() abort
+func H() abort
Xpath 'g'
call I() " aborted
Xpath 'h'
return 4
-endfunction
+endfunc
-function! I() abort
+func I() abort
Xpath 'i'
asdf " error
Xpath 'j'
return 8
-endfunction
+endfunc
if F() != 1
Xpath 'k'
@@ -626,7 +588,7 @@ endfunc
XpathINIT
-function! MSG(enr, emsg)
+func MSG(enr, emsg)
let english = v:lang == "C" || v:lang =~ '^[Ee]n'
if a:enr == ""
Xout "TODO: Add message number for:" a:emsg
@@ -710,10 +672,10 @@ XpathINIT
let calls = 0
-function! P(num)
+func P(num)
let g:calls = g:calls + a:num " side effect on call
return 0
-endfunction
+endfunc
if 1
Xpath 'a'
@@ -1092,7 +1054,4843 @@ func Test_unmatched_if_in_while()
endfunc
"-------------------------------------------------------------------------------
+" Test 18: Interrupt (Ctrl-C pressed) {{{1
+"
+" On an interrupt, the script processing is terminated immediately.
+"-------------------------------------------------------------------------------
+
+func Test_interrupt_while_if()
+ let test =<< trim [CODE]
+ try
+ if 1
+ Xpath 'a'
+ while 1
+ Xpath 'b'
+ if 1
+ Xpath 'c'
+ call interrupt()
+ call assert_report('should not get here')
+ break
+ finish
+ endif | call assert_report('should not get here')
+ call assert_report('should not get here')
+ endwhile | call assert_report('should not get here')
+ call assert_report('should not get here')
+ endif | call assert_report('should not get here')
+ call assert_report('should not get here')
+ catch /^Vim:Interrupt$/
+ Xpath 'd'
+ endtry | Xpath 'e'
+ Xpath 'f'
+ [CODE]
+ let verify =<< trim [CODE]
+ call assert_equal('abcdef', g:Xpath)
+ [CODE]
+ call RunInNewVim(test, verify)
+endfunc
+
+func Test_interrupt_try()
+ let test =<< trim [CODE]
+ try
+ try
+ Xpath 'a'
+ call interrupt()
+ call assert_report('should not get here')
+ endtry | call assert_report('should not get here')
+ call assert_report('should not get here')
+ catch /^Vim:Interrupt$/
+ Xpath 'b'
+ endtry | Xpath 'c'
+ Xpath 'd'
+ [CODE]
+ let verify =<< trim [CODE]
+ call assert_equal('abcd', g:Xpath)
+ [CODE]
+ call RunInNewVim(test, verify)
+endfunc
+
+func Test_interrupt_func_while_if()
+ let test =<< trim [CODE]
+ func F()
+ if 1
+ Xpath 'a'
+ while 1
+ Xpath 'b'
+ if 1
+ Xpath 'c'
+ call interrupt()
+ call assert_report('should not get here')
+ break
+ return
+ endif | call assert_report('should not get here')
+ call assert_report('should not get here')
+ endwhile | call assert_report('should not get here')
+ call assert_report('should not get here')
+ endif | call assert_report('should not get here')
+ call assert_report('should not get here')
+ endfunc
+
+ Xpath 'd'
+ try
+ call F() | call assert_report('should not get here')
+ catch /^Vim:Interrupt$/
+ Xpath 'e'
+ endtry | Xpath 'f'
+ Xpath 'g'
+ [CODE]
+ let verify =<< trim [CODE]
+ call assert_equal('dabcefg', g:Xpath)
+ [CODE]
+ call RunInNewVim(test, verify)
+endfunc
+
+func Test_interrupt_func_try()
+ let test =<< trim [CODE]
+ func G()
+ try
+ Xpath 'a'
+ call interrupt()
+ call assert_report('should not get here')
+ endtry | call assert_report('should not get here')
+ call assert_report('should not get here')
+ endfunc
+
+ Xpath 'b'
+ try
+ call G() | call assert_report('should not get here')
+ catch /^Vim:Interrupt$/
+ Xpath 'c'
+ endtry | Xpath 'd'
+ Xpath 'e'
+ [CODE]
+ let verify =<< trim [CODE]
+ call assert_equal('bacde', g:Xpath)
+ [CODE]
+ call RunInNewVim(test, verify)
+endfunc
+
+"-------------------------------------------------------------------------------
+" Test 19: Aborting on errors inside :try/:endtry {{{1
+"
+" An error in a command dynamically enclosed in a :try/:endtry region
+" aborts script processing immediately. It does not matter whether
+" the failing command is outside or inside a function and whether a
+" function has an "abort" attribute.
+"-------------------------------------------------------------------------------
+
+func Test_try_error_abort_1()
+ let test =<< trim [CODE]
+ func F() abort
+ Xpath 'a'
+ asdf
+ call assert_report('should not get here')
+ endfunc
+
+ try
+ Xpath 'b'
+ call F()
+ call assert_report('should not get here')
+ endtry | call assert_report('should not get here')
+ call assert_report('should not get here')
+ [CODE]
+ let verify =<< trim [CODE]
+ call assert_equal('ba', g:Xpath)
+ [CODE]
+ call RunInNewVim(test, verify)
+endfunc
+
+func Test_try_error_abort_2()
+ let test =<< trim [CODE]
+ func G()
+ Xpath 'a'
+ asdf
+ call assert_report('should not get here')
+ endfunc
+
+ try
+ Xpath 'b'
+ call G()
+ call assert_report('should not get here')
+ endtry | call assert_report('should not get here')
+ call assert_report('should not get here')
+ [CODE]
+ let verify =<< trim [CODE]
+ call assert_equal('ba', g:Xpath)
+ [CODE]
+ call RunInNewVim(test, verify)
+endfunc
+
+func Test_try_error_abort_3()
+ let test =<< trim [CODE]
+ try
+ Xpath 'a'
+ asdf
+ call assert_report('should not get here')
+ endtry | call assert_report('should not get here')
+ call assert_report('should not get here')
+ [CODE]
+ let verify =<< trim [CODE]
+ call assert_equal('a', g:Xpath)
+ [CODE]
+ call RunInNewVim(test, verify)
+endfunc
+
+func Test_try_error_abort_4()
+ let test =<< trim [CODE]
+ if 1
+ try
+ Xpath 'a'
+ asdf
+ call assert_report('should not get here')
+ endtry | call assert_report('should not get here')
+ endif | call assert_report('should not get here')
+ call assert_report('should not get here')
+ [CODE]
+ let verify =<< trim [CODE]
+ call assert_equal('a', g:Xpath)
+ [CODE]
+ call RunInNewVim(test, verify)
+endfunc
+
+func Test_try_error_abort_5()
+ let test =<< trim [CODE]
+ let p = 1
+ while p
+ let p = 0
+ try
+ Xpath 'a'
+ asdf
+ call assert_report('should not get here')
+ endtry | call assert_report('should not get here')
+ endwhile | call assert_report('should not get here')
+ call assert_report('should not get here')
+ [CODE]
+ let verify =<< trim [CODE]
+ call assert_equal('a', g:Xpath)
+ [CODE]
+ call RunInNewVim(test, verify)
+endfunc
+
+func Test_try_error_abort_6()
+ let test =<< trim [CODE]
+ let p = 1
+ Xpath 'a'
+ while p
+ Xpath 'b'
+ let p = 0
+ try
+ Xpath 'c'
+ endwhile | call assert_report('should not get here')
+ call assert_report('should not get here')
+ [CODE]
+ let verify =<< trim [CODE]
+ call assert_equal('abc', g:Xpath)
+ [CODE]
+ call RunInNewVim(test, verify)
+endfunc
+
+"-------------------------------------------------------------------------------
+" Test 20: Aborting on errors after :try/:endtry {{{1
+"
+" When an error occurs after the last active :try/:endtry region has
+" been left, termination behavior is as if no :try/:endtry has been
+" seen.
+"-------------------------------------------------------------------------------
+
+func Test_error_after_try_1()
+ let test =<< trim [CODE]
+ let p = 1
+ while p
+ let p = 0
+ Xpath 'a'
+ try
+ Xpath 'b'
+ endtry
+ asdf
+ call assert_report('should not get here')
+ endwhile | call assert_report('should not get here')
+ Xpath 'c'
+ [CODE]
+ let verify =<< trim [CODE]
+ call assert_equal('abc', g:Xpath)
+ [CODE]
+ call RunInNewVim(test, verify)
+endfunc
+
+func Test_error_after_try_2()
+ let test =<< trim [CODE]
+ while 1
+ try
+ Xpath 'a'
+ break
+ call assert_report('should not get here')
+ endtry
+ endwhile
+ Xpath 'b'
+ asdf
+ Xpath 'c'
+ [CODE]
+ let verify =<< trim [CODE]
+ call assert_equal('abc', g:Xpath)
+ [CODE]
+ call RunInNewVim(test, verify)
+endfunc
+
+func Test_error_after_try_3()
+ let test =<< trim [CODE]
+ while 1
+ try
+ Xpath 'a'
+ break
+ call assert_report('should not get here')
+ finally
+ Xpath 'b'
+ endtry
+ endwhile
+ Xpath 'c'
+ asdf
+ Xpath 'd'
+ [CODE]
+ let verify =<< trim [CODE]
+ call assert_equal('abcd', g:Xpath)
+ [CODE]
+ call RunInNewVim(test, verify)
+endfunc
+
+func Test_error_after_try_4()
+ let test =<< trim [CODE]
+ while 1
+ try
+ Xpath 'a'
+ finally
+ Xpath 'b'
+ break
+ call assert_report('should not get here')
+ endtry
+ endwhile
+ Xpath 'c'
+ asdf
+ Xpath 'd'
+ [CODE]
+ let verify =<< trim [CODE]
+ call assert_equal('abcd', g:Xpath)
+ [CODE]
+ call RunInNewVim(test, verify)
+endfunc
+
+func Test_error_after_try_5()
+ let test =<< trim [CODE]
+ let p = 1
+ while p
+ let p = 0
+ try
+ Xpath 'a'
+ continue
+ call assert_report('should not get here')
+ endtry
+ endwhile
+ Xpath 'b'
+ asdf
+ Xpath 'c'
+ [CODE]
+ let verify =<< trim [CODE]
+ call assert_equal('abc', g:Xpath)
+ [CODE]
+ call RunInNewVim(test, verify)
+endfunc
+
+func Test_error_after_try_6()
+ let test =<< trim [CODE]
+ let p = 1
+ while p
+ let p = 0
+ try
+ Xpath 'a'
+ continue
+ call assert_report('should not get here')
+ finally
+ Xpath 'b'
+ endtry
+ endwhile
+ Xpath 'c'
+ asdf
+ Xpath 'd'
+ [CODE]
+ let verify =<< trim [CODE]
+ call assert_equal('abcd', g:Xpath)
+ [CODE]
+ call RunInNewVim(test, verify)
+endfunc
+
+func Test_error_after_try_7()
+ let test =<< trim [CODE]
+ let p = 1
+ while p
+ let p = 0
+ try
+ Xpath 'a'
+ finally
+ Xpath 'b'
+ continue
+ call assert_report('should not get here')
+ endtry
+ endwhile
+ Xpath 'c'
+ asdf
+ Xpath 'd'
+ [CODE]
+ let verify =<< trim [CODE]
+ call assert_equal('abcd', g:Xpath)
+ [CODE]
+ call RunInNewVim(test, verify)
+endfunc
+
+"-------------------------------------------------------------------------------
+" Test 21: :finally for :try after :continue/:break/:return/:finish {{{1
+"
+" If a :try conditional stays inactive due to a preceding :continue,
+" :break, :return, or :finish, its :finally clause should not be
+" executed.
+"-------------------------------------------------------------------------------
+
+func Test_finally_after_loop_ctrl_statement()
+ let test =<< trim [CODE]
+ func F()
+ let loops = 2
+ while loops > 0
+ XloopNEXT
+ let loops = loops - 1
+ try
+ if loops == 1
+ Xloop 'a'
+ continue
+ call assert_report('should not get here')
+ elseif loops == 0
+ Xloop 'b'
+ break
+ call assert_report('should not get here')
+ endif
+
+ try " inactive
+ call assert_report('should not get here')
+ finally
+ call assert_report('should not get here')
+ endtry
+ finally
+ Xloop 'c'
+ endtry
+ call assert_report('should not get here')
+ endwhile
+
+ try
+ Xpath 'd'
+ return
+ call assert_report('should not get here')
+ try " inactive
+ call assert_report('should not get here')
+ finally
+ call assert_report('should not get here')
+ endtry
+ finally
+ Xpath 'e'
+ endtry
+ call assert_report('should not get here')
+ endfunc
+
+ try
+ Xpath 'f'
+ call F()
+ Xpath 'g'
+ finish
+ call assert_report('should not get here')
+ try " inactive
+ call assert_report('should not get here')
+ finally
+ call assert_report('should not get here')
+ endtry
+ finally
+ Xpath 'h'
+ endtry
+ call assert_report('should not get here')
+ [CODE]
+ let verify =<< trim [CODE]
+ call assert_equal('fa2c2b3c3degh', g:Xpath)
+ [CODE]
+ call RunInNewVim(test, verify)
+endfunc
+
+"-------------------------------------------------------------------------------
+" Test 22: :finally for a :try after an error/interrupt/:throw {{{1
+"
+" If a :try conditional stays inactive due to a preceding error or
+" interrupt or :throw, its :finally clause should not be executed.
+"-------------------------------------------------------------------------------
+
+func Test_finally_after_error_in_func()
+ let test =<< trim [CODE]
+ func Error()
+ try
+ Xpath 'b'
+ asdf " aborting error, triggering error exception
+ call assert_report('should not get here')
+ endtry
+ call assert_report('should not get here')
+ endfunc
+
+ Xpath 'a'
+ call Error()
+ call assert_report('should not get here')
+
+ if 1 " not active due to error
+ try " not active since :if inactive
+ call assert_report('should not get here')
+ finally
+ call assert_report('should not get here')
+ endtry
+ endif
+
+ try " not active due to error
+ call assert_report('should not get here')
+ finally
+ call assert_report('should not get here')
+ endtry
+ [CODE]
+ let verify =<< trim [CODE]
+ call assert_equal('ab', g:Xpath)
+ [CODE]
+ call RunInNewVim(test, verify)
+endfunc
+
+func Test_finally_after_interrupt()
+ let test =<< trim [CODE]
+ func Interrupt()
+ try
+ Xpath 'a'
+ call interrupt() " triggering interrupt exception
+ call assert_report('should not get here')
+ endtry
+ endfunc
+
+ Xpath 'b'
+ try
+ call Interrupt()
+ catch /^Vim:Interrupt$/
+ Xpath 'c'
+ finish
+ endtry
+ call assert_report('should not get here')
+
+ if 1 " not active due to interrupt
+ try " not active since :if inactive
+ call assert_report('should not get here')
+ finally
+ call assert_report('should not get here')
+ endtry
+ endif
+
+ try " not active due to interrupt
+ call assert_report('should not get here')
+ finally
+ call assert_report('should not get here')
+ endtry
+ [CODE]
+ let verify =<< trim [CODE]
+ call assert_equal('bac', g:Xpath)
+ [CODE]
+ call RunInNewVim(test, verify)
+endfunc
+
+func Test_finally_after_throw()
+ let test =<< trim [CODE]
+ func Throw()
+ Xpath 'a'
+ throw 'xyz'
+ endfunc
+
+ Xpath 'b'
+ call Throw()
+ call assert_report('should not get here')
+
+ if 1 " not active due to :throw
+ try " not active since :if inactive
+ call assert_report('should not get here')
+ finally
+ call assert_report('should not get here')
+ endtry
+ endif
+
+ try " not active due to :throw
+ call assert_report('should not get here')
+ finally
+ call assert_report('should not get here')
+ endtry
+ [CODE]
+ let verify =<< trim [CODE]
+ call assert_equal('ba', g:Xpath)
+ [CODE]
+ call RunInNewVim(test, verify)
+endfunc
+
+"-------------------------------------------------------------------------------
+" Test 23: :catch clauses for a :try after a :throw {{{1
+"
+" If a :try conditional stays inactive due to a preceding :throw,
+" none of its :catch clauses should be executed.
+"-------------------------------------------------------------------------------
+
+func Test_catch_after_throw()
+ let test =<< trim [CODE]
+ try
+ Xpath 'a'
+ throw "xyz"
+ call assert_report('should not get here')
+
+ if 1 " not active due to :throw
+ try " not active since :if inactive
+ call assert_report('should not get here')
+ catch /xyz/
+ call assert_report('should not get here')
+ endtry
+ endif
+ catch /xyz/
+ Xpath 'b'
+ endtry
+
+ Xpath 'c'
+ throw "abc"
+ call assert_report('should not get here')
+
+ try " not active due to :throw
+ call assert_report('should not get here')
+ catch /abc/
+ call assert_report('should not get here')
+ endtry
+ [CODE]
+ let verify =<< trim [CODE]
+ call assert_equal('abc', g:Xpath)
+ [CODE]
+ call RunInNewVim(test, verify)
+endfunc
+
+"-------------------------------------------------------------------------------
+" Test 24: :endtry for a :try after a :throw {{{1
+"
+" If a :try conditional stays inactive due to a preceding :throw,
+" its :endtry should not rethrow the exception to the next surrounding
+" active :try conditional.
+"-------------------------------------------------------------------------------
+
+func Test_endtry_after_throw()
+ let test =<< trim [CODE]
+ try " try 1
+ try " try 2
+ Xpath 'a'
+ throw "xyz" " makes try 2 inactive
+ call assert_report('should not get here')
+
+ try " try 3
+ call assert_report('should not get here')
+ endtry " no rethrow to try 1
+ catch /xyz/ " should catch although try 2 inactive
+ Xpath 'b'
+ endtry
+ catch /xyz/ " try 1 active, but exception already caught
+ call assert_report('should not get here')
+ endtry
+ Xpath 'c'
+ [CODE]
+ let verify =<< trim [CODE]
+ call assert_equal('abc', g:Xpath)
+ [CODE]
+ call RunInNewVim(test, verify)
+endfunc
+
+"-------------------------------------------------------------------------------
+" Test 27: Executing :finally clauses after :return {{{1
+"
+" For a :return command dynamically enclosed in a :try/:endtry region,
+" :finally clauses are executed and the called function is ended.
+"-------------------------------------------------------------------------------
+
+func T27_F()
+ try
+ Xpath 'a'
+ try
+ Xpath 'b'
+ return
+ call assert_report('should not get here')
+ finally
+ Xpath 'c'
+ endtry
+ Xpath 'd'
+ finally
+ Xpath 'e'
+ endtry
+ call assert_report('should not get here')
+endfunc
+
+func T27_G()
+ try
+ Xpath 'f'
+ return
+ call assert_report('should not get here')
+ finally
+ Xpath 'g'
+ call T27_F()
+ Xpath 'h'
+ endtry
+ call assert_report('should not get here')
+endfunc
+
+func T27_H()
+ try
+ Xpath 'i'
+ call T27_G()
+ Xpath 'j'
+ finally
+ Xpath 'k'
+ return
+ call assert_report('should not get here')
+ endtry
+ call assert_report('should not get here')
+endfunction
+
+func Test_finally_after_return()
+ XpathINIT
+ try
+ Xpath 'l'
+ call T27_H()
+ Xpath 'm'
+ finally
+ Xpath 'n'
+ endtry
+ call assert_equal('lifgabcehjkmn', g:Xpath)
+endfunc
+
+"-------------------------------------------------------------------------------
+" Test 28: Executing :finally clauses after :finish {{{1
+"
+" For a :finish command dynamically enclosed in a :try/:endtry region,
+" :finally clauses are executed and the sourced file is finished.
+"
+" This test executes the bodies of the functions F, G, and H from the
+" previous test as script files (:return replaced by :finish).
+"-------------------------------------------------------------------------------
+
+func Test_finally_after_finish()
+ XpathINIT
+
+ let scriptF = MakeScript("T27_F")
+ let scriptG = MakeScript("T27_G", scriptF)
+ let scriptH = MakeScript("T27_H", scriptG)
+
+ try
+ Xpath 'A'
+ exec "source" scriptH
+ Xpath 'B'
+ finally
+ Xpath 'C'
+ endtry
+ Xpath 'D'
+ call assert_equal('AifgabcehjkBCD', g:Xpath)
+ call delete(scriptF)
+ call delete(scriptG)
+ call delete(scriptH)
+endfunc
+
+"-------------------------------------------------------------------------------
+" Test 29: Executing :finally clauses on errors {{{1
+"
+" After an error in a command dynamically enclosed in a :try/:endtry
+" region, :finally clauses are executed and the script processing is
+" terminated.
+"-------------------------------------------------------------------------------
+
+func Test_finally_after_error_1()
+ let test =<< trim [CODE]
+ func F()
+ while 1
+ try
+ Xpath 'a'
+ while 1
+ try
+ Xpath 'b'
+ asdf " error
+ call assert_report('should not get here')
+ finally
+ Xpath 'c'
+ endtry | call assert_report('should not get here')
+ call assert_report('should not get here')
+ break
+ endwhile
+ call assert_report('should not get here')
+ finally
+ Xpath 'd'
+ endtry | call assert_report('should not get here')
+ call assert_report('should not get here')
+ break
+ endwhile
+ call assert_report('should not get here')
+ endfunc
+
+ while 1
+ try
+ Xpath 'e'
+ while 1
+ call F()
+ call assert_report('should not get here')
+ break
+ endwhile | call assert_report('should not get here')
+ call assert_report('should not get here')
+ finally
+ Xpath 'f'
+ endtry | call assert_report('should not get here')
+ endwhile | call assert_report('should not get here')
+ call assert_report('should not get here')
+ [CODE]
+ let verify =<< trim [CODE]
+ call assert_equal('eabcdf', g:Xpath)
+ [CODE]
+ call RunInNewVim(test, verify)
+endfunc
+
+func Test_finally_after_error_2()
+ let test =<< trim [CODE]
+ func G() abort
+ if 1
+ try
+ Xpath 'a'
+ asdf " error
+ call assert_report('should not get here')
+ finally
+ Xpath 'b'
+ endtry | Xpath 'c'
+ endif | Xpath 'd'
+ call assert_report('should not get here')
+ endfunc
+
+ if 1
+ try
+ Xpath 'e'
+ call G()
+ call assert_report('should not get here')
+ finally
+ Xpath 'f'
+ endtry | call assert_report('should not get here')
+ endif | call assert_report('should not get here')
+ call assert_report('should not get here')
+ [CODE]
+ let verify =<< trim [CODE]
+ call assert_equal('eabf', g:Xpath)
+ [CODE]
+ call RunInNewVim(test, verify)
+endfunc
+
+"-------------------------------------------------------------------------------
+" Test 30: Executing :finally clauses on interrupt {{{1
+"
+" After an interrupt in a command dynamically enclosed in
+" a :try/:endtry region, :finally clauses are executed and the
+" script processing is terminated.
+"-------------------------------------------------------------------------------
+
+func Test_finally_on_interrupt()
+ let test =<< trim [CODE]
+ func F()
+ try
+ Xloop 'a'
+ call interrupt()
+ call assert_report('should not get here')
+ finally
+ Xloop 'b'
+ endtry
+ call assert_report('should not get here')
+ endfunc
+
+ try
+ try
+ Xpath 'c'
+ try
+ Xpath 'd'
+ call interrupt()
+ call assert_report('should not get here')
+ finally
+ Xpath 'e'
+ try
+ Xpath 'f'
+ try
+ Xpath 'g'
+ finally
+ Xpath 'h'
+ try
+ Xpath 'i'
+ call interrupt()
+ call assert_report('should not get here')
+ endtry
+ call assert_report('should not get here')
+ endtry
+ call assert_report('should not get here')
+ endtry
+ call assert_report('should not get here')
+ endtry
+ call assert_report('should not get here')
+ finally
+ Xpath 'j'
+ try
+ Xpath 'k'
+ call F()
+ call assert_report('should not get here')
+ finally
+ Xpath 'l'
+ try
+ Xpath 'm'
+ XloopNEXT
+ ExecAsScript F
+ call assert_report('should not get here')
+ finally
+ Xpath 'n'
+ endtry
+ call assert_report('should not get here')
+ endtry
+ call assert_report('should not get here')
+ endtry
+ call assert_report('should not get here')
+ catch /^Vim:Interrupt$/
+ Xpath 'o'
+ endtry
+ [CODE]
+ let verify =<< trim [CODE]
+ call assert_equal('cdefghijka1b1lma2b2no', g:Xpath)
+ [CODE]
+ call RunInNewVim(test, verify)
+endfunc
+
+"-------------------------------------------------------------------------------
+" Test 31: Executing :finally clauses after :throw {{{1
+"
+" After a :throw dynamically enclosed in a :try/:endtry region,
+" :finally clauses are executed and the script processing is
+" terminated.
+"-------------------------------------------------------------------------------
+
+func Test_finally_after_throw_2()
+ let test =<< trim [CODE]
+ func F()
+ try
+ Xloop 'a'
+ throw "exception"
+ call assert_report('should not get here')
+ finally
+ Xloop 'b'
+ endtry
+ call assert_report('should not get here')
+ endfunc
+
+ try
+ Xpath 'c'
+ try
+ Xpath 'd'
+ throw "exception"
+ call assert_report('should not get here')
+ finally
+ Xpath 'e'
+ try
+ Xpath 'f'
+ try
+ Xpath 'g'
+ finally
+ Xpath 'h'
+ try
+ Xpath 'i'
+ throw "exception"
+ call assert_report('should not get here')
+ endtry
+ call assert_report('should not get here')
+ endtry
+ call assert_report('should not get here')
+ endtry
+ call assert_report('should not get here')
+ endtry
+ call assert_report('should not get here')
+ finally
+ Xpath 'j'
+ try
+ Xpath 'k'
+ call F()
+ call assert_report('should not get here')
+ finally
+ Xpath 'l'
+ try
+ Xpath 'm'
+ XloopNEXT
+ ExecAsScript F
+ call assert_report('should not get here')
+ finally
+ Xpath 'n'
+ endtry
+ call assert_report('should not get here')
+ endtry
+ call assert_report('should not get here')
+ endtry
+ call assert_report('should not get here')
+ [CODE]
+ let verify =<< trim [CODE]
+ call assert_equal('cdefghijka1b1lma2b2n', g:Xpath)
+ [CODE]
+ call RunInNewVim(test, verify)
+endfunc
+
+"-------------------------------------------------------------------------------
+" Test 34: :finally reason discarded by :continue {{{1
+"
+" When a :finally clause is executed due to a :continue, :break,
+" :return, :finish, error, interrupt or :throw, the jump reason is
+" discarded by a :continue in the finally clause.
+"-------------------------------------------------------------------------------
+
+func Test_finally_after_continue()
+ let test =<< trim [CODE]
+ func C(jump)
+ XloopNEXT
+ let loop = 0
+ while loop < 2
+ let loop = loop + 1
+ if loop == 1
+ try
+ if a:jump == "continue"
+ continue
+ elseif a:jump == "break"
+ break
+ elseif a:jump == "return" || a:jump == "finish"
+ return
+ elseif a:jump == "error"
+ asdf
+ elseif a:jump == "interrupt"
+ call interrupt()
+ let dummy = 0
+ elseif a:jump == "throw"
+ throw "abc"
+ endif
+ finally
+ continue " discards jump that caused the :finally
+ call assert_report('should not get here')
+ endtry
+ call assert_report('should not get here')
+ elseif loop == 2
+ Xloop 'a'
+ endif
+ endwhile
+ endfunc
+
+ call C("continue")
+ Xpath 'b'
+ call C("break")
+ Xpath 'c'
+ call C("return")
+ Xpath 'd'
+ let g:jump = "finish"
+ ExecAsScript C
+ unlet g:jump
+ Xpath 'e'
+ try
+ call C("error")
+ Xpath 'f'
+ finally
+ Xpath 'g'
+ try
+ call C("interrupt")
+ Xpath 'h'
+ finally
+ Xpath 'i'
+ call C("throw")
+ Xpath 'j'
+ endtry
+ endtry
+ Xpath 'k'
+ [CODE]
+ let verify =<< trim [CODE]
+ call assert_equal('a2ba3ca4da5ea6fga7hia8jk', g:Xpath)
+ [CODE]
+ call RunInNewVim(test, verify)
+endfunc
+
+"-------------------------------------------------------------------------------
+" Test 35: :finally reason discarded by :break {{{1
+"
+" When a :finally clause is executed due to a :continue, :break,
+" :return, :finish, error, interrupt or :throw, the jump reason is
+" discarded by a :break in the finally clause.
+"-------------------------------------------------------------------------------
+
+func Test_finally_discard_by_break()
+ let test =<< trim [CODE]
+ func B(jump)
+ XloopNEXT
+ let loop = 0
+ while loop < 2
+ let loop = loop + 1
+ if loop == 1
+ try
+ if a:jump == "continue"
+ continue
+ elseif a:jump == "break"
+ break
+ elseif a:jump == "return" || a:jump == "finish"
+ return
+ elseif a:jump == "error"
+ asdf
+ elseif a:jump == "interrupt"
+ call interrupt()
+ let dummy = 0
+ elseif a:jump == "throw"
+ throw "abc"
+ endif
+ finally
+ break " discards jump that caused the :finally
+ call assert_report('should not get here')
+ endtry
+ elseif loop == 2
+ call assert_report('should not get here')
+ endif
+ endwhile
+ Xloop 'a'
+ endfunc
+
+ call B("continue")
+ Xpath 'b'
+ call B("break")
+ Xpath 'c'
+ call B("return")
+ Xpath 'd'
+ let g:jump = "finish"
+ ExecAsScript B
+ unlet g:jump
+ Xpath 'e'
+ try
+ call B("error")
+ Xpath 'f'
+ finally
+ Xpath 'g'
+ try
+ call B("interrupt")
+ Xpath 'h'
+ finally
+ Xpath 'i'
+ call B("throw")
+ Xpath 'j'
+ endtry
+ endtry
+ Xpath 'k'
+ [CODE]
+ let verify =<< trim [CODE]
+ call assert_equal('a2ba3ca4da5ea6fga7hia8jk', g:Xpath)
+ [CODE]
+ call RunInNewVim(test, verify)
+endfunc
+
+"-------------------------------------------------------------------------------
+" Test 36: :finally reason discarded by :return {{{1
+"
+" When a :finally clause is executed due to a :continue, :break,
+" :return, :finish, error, interrupt or :throw, the jump reason is
+" discarded by a :return in the finally clause.
+"-------------------------------------------------------------------------------
+
+func Test_finally_discard_by_return()
+ let test =<< trim [CODE]
+ func R(jump, retval) abort
+ let loop = 0
+ while loop < 2
+ let loop = loop + 1
+ if loop == 1
+ try
+ if a:jump == "continue"
+ continue
+ elseif a:jump == "break"
+ break
+ elseif a:jump == "return"
+ return
+ elseif a:jump == "error"
+ asdf
+ elseif a:jump == "interrupt"
+ call interrupt()
+ let dummy = 0
+ elseif a:jump == "throw"
+ throw "abc"
+ endif
+ finally
+ return a:retval " discards jump that caused the :finally
+ call assert_report('should not get here')
+ endtry
+ elseif loop == 2
+ call assert_report('should not get here')
+ endif
+ endwhile
+ call assert_report('should not get here')
+ endfunc
+
+ let sum = -R("continue", -8)
+ Xpath 'a'
+ let sum = sum - R("break", -16)
+ Xpath 'b'
+ let sum = sum - R("return", -32)
+ Xpath 'c'
+ try
+ let sum = sum - R("error", -64)
+ Xpath 'd'
+ finally
+ Xpath 'e'
+ try
+ let sum = sum - R("interrupt", -128)
+ Xpath 'f'
+ finally
+ Xpath 'g'
+ let sum = sum - R("throw", -256)
+ Xpath 'h'
+ endtry
+ endtry
+ Xpath 'i'
+
+ let expected = 8 + 16 + 32 + 64 + 128 + 256
+ call assert_equal(sum, expected)
+ [CODE]
+ let verify =<< trim [CODE]
+ call assert_equal('abcdefghi', g:Xpath)
+ [CODE]
+ call RunInNewVim(test, verify)
+endfunc
+
+"-------------------------------------------------------------------------------
+" Test 37: :finally reason discarded by :finish {{{1
+"
+" When a :finally clause is executed due to a :continue, :break,
+" :return, :finish, error, interrupt or :throw, the jump reason is
+" discarded by a :finish in the finally clause.
+"-------------------------------------------------------------------------------
+
+func Test_finally_discard_by_finish()
+ let test =<< trim [CODE]
+ func F(jump) " not executed as function, transformed to a script
+ let loop = 0
+ while loop < 2
+ let loop = loop + 1
+ if loop == 1
+ try
+ if a:jump == "continue"
+ continue
+ elseif a:jump == "break"
+ break
+ elseif a:jump == "finish"
+ finish
+ elseif a:jump == "error"
+ asdf
+ elseif a:jump == "interrupt"
+ call interrupt()
+ let dummy = 0
+ elseif a:jump == "throw"
+ throw "abc"
+ endif
+ finally
+ finish " discards jump that caused the :finally
+ call assert_report('should not get here')
+ endtry
+ elseif loop == 2
+ call assert_report('should not get here')
+ endif
+ endwhile
+ call assert_report('should not get here')
+ endfunc
+
+ let scriptF = MakeScript("F")
+ delfunction F
+
+ let g:jump = "continue"
+ exec "source" scriptF
+ Xpath 'a'
+ let g:jump = "break"
+ exec "source" scriptF
+ Xpath 'b'
+ let g:jump = "finish"
+ exec "source" scriptF
+ Xpath 'c'
+ try
+ let g:jump = "error"
+ exec "source" scriptF
+ Xpath 'd'
+ finally
+ Xpath 'e'
+ try
+ let g:jump = "interrupt"
+ exec "source" scriptF
+ Xpath 'f'
+ finally
+ Xpath 'g'
+ try
+ let g:jump = "throw"
+ exec "source" scriptF
+ Xpath 'h'
+ finally
+ Xpath 'i'
+ endtry
+ endtry
+ endtry
+ unlet g:jump
+ call delete(scriptF)
+ [CODE]
+ let verify =<< trim [CODE]
+ call assert_equal('abcdefghi', g:Xpath)
+ [CODE]
+ call RunInNewVim(test, verify)
+endfunc
+
+"-------------------------------------------------------------------------------
+" Test 38: :finally reason discarded by an error {{{1
+"
+" When a :finally clause is executed due to a :continue, :break,
+" :return, :finish, error, interrupt or :throw, the jump reason is
+" discarded by an error in the finally clause.
+"-------------------------------------------------------------------------------
+
+func Test_finally_discard_by_error()
+ let test =<< trim [CODE]
+ func E(jump)
+ let loop = 0
+ while loop < 2
+ let loop = loop + 1
+ if loop == 1
+ try
+ if a:jump == "continue"
+ continue
+ elseif a:jump == "break"
+ break
+ elseif a:jump == "return" || a:jump == "finish"
+ return
+ elseif a:jump == "error"
+ asdf
+ elseif a:jump == "interrupt"
+ call interrupt()
+ let dummy = 0
+ elseif a:jump == "throw"
+ throw "abc"
+ endif
+ finally
+ asdf " error; discards jump that caused the :finally
+ endtry
+ elseif loop == 2
+ call assert_report('should not get here')
+ endif
+ endwhile
+ call assert_report('should not get here')
+ endfunc
+
+ try
+ Xpath 'a'
+ call E("continue")
+ call assert_report('should not get here')
+ finally
+ try
+ Xpath 'b'
+ call E("break")
+ call assert_report('should not get here')
+ finally
+ try
+ Xpath 'c'
+ call E("return")
+ call assert_report('should not get here')
+ finally
+ try
+ Xpath 'd'
+ let g:jump = "finish"
+ ExecAsScript E
+ call assert_report('should not get here')
+ finally
+ unlet g:jump
+ try
+ Xpath 'e'
+ call E("error")
+ call assert_report('should not get here')
+ finally
+ try
+ Xpath 'f'
+ call E("interrupt")
+ call assert_report('should not get here')
+ finally
+ try
+ Xpath 'g'
+ call E("throw")
+ call assert_report('should not get here')
+ finally
+ Xpath 'h'
+ delfunction E
+ endtry
+ endtry
+ endtry
+ endtry
+ endtry
+ endtry
+ endtry
+ call assert_report('should not get here')
+ [CODE]
+ let verify =<< trim [CODE]
+ call assert_equal('abcdefgh', g:Xpath)
+ [CODE]
+ call RunInNewVim(test, verify)
+endfunc
+
+"-------------------------------------------------------------------------------
+" Test 39: :finally reason discarded by an interrupt {{{1
+"
+" When a :finally clause is executed due to a :continue, :break,
+" :return, :finish, error, interrupt or :throw, the jump reason is
+" discarded by an interrupt in the finally clause.
+"-------------------------------------------------------------------------------
+
+func Test_finally_discarded_by_interrupt()
+ let test =<< trim [CODE]
+ func I(jump)
+ let loop = 0
+ while loop < 2
+ let loop = loop + 1
+ if loop == 1
+ try
+ if a:jump == "continue"
+ continue
+ elseif a:jump == "break"
+ break
+ elseif a:jump == "return" || a:jump == "finish"
+ return
+ elseif a:jump == "error"
+ asdf
+ elseif a:jump == "interrupt"
+ call interrupt()
+ let dummy = 0
+ elseif a:jump == "throw"
+ throw "abc"
+ endif
+ finally
+ call interrupt()
+ let dummy = 0
+ endtry
+ elseif loop == 2
+ call assert_report('should not get here')
+ endif
+ endwhile
+ call assert_report('should not get here')
+ endfunc
+
+ try
+ try
+ Xpath 'a'
+ call I("continue")
+ call assert_report('should not get here')
+ finally
+ try
+ Xpath 'b'
+ call I("break")
+ call assert_report('should not get here')
+ finally
+ try
+ Xpath 'c'
+ call I("return")
+ call assert_report('should not get here')
+ finally
+ try
+ Xpath 'd'
+ let g:jump = "finish"
+ ExecAsScript I
+ call assert_report('should not get here')
+ finally
+ unlet g:jump
+ try
+ Xpath 'e'
+ call I("error")
+ call assert_report('should not get here')
+ finally
+ try
+ Xpath 'f'
+ call I("interrupt")
+ call assert_report('should not get here')
+ finally
+ try
+ Xpath 'g'
+ call I("throw")
+ call assert_report('should not get here')
+ finally
+ Xpath 'h'
+ delfunction I
+ endtry
+ endtry
+ endtry
+ endtry
+ endtry
+ endtry
+ endtry
+ call assert_report('should not get here')
+ catch /^Vim:Interrupt$/
+ Xpath 'A'
+ endtry
+ [CODE]
+ let verify =<< trim [CODE]
+ call assert_equal('abcdefghA', g:Xpath)
+ [CODE]
+ call RunInNewVim(test, verify)
+endfunc
+
+"-------------------------------------------------------------------------------
+" Test 40: :finally reason discarded by :throw {{{1
+"
+" When a :finally clause is executed due to a :continue, :break,
+" :return, :finish, error, interrupt or :throw, the jump reason is
+" discarded by a :throw in the finally clause.
+"-------------------------------------------------------------------------------
+
+func Test_finally_discard_by_throw()
+ let test =<< trim [CODE]
+ func T(jump)
+ let loop = 0
+ while loop < 2
+ let loop = loop + 1
+ if loop == 1
+ try
+ if a:jump == "continue"
+ continue
+ elseif a:jump == "break"
+ break
+ elseif a:jump == "return" || a:jump == "finish"
+ return
+ elseif a:jump == "error"
+ asdf
+ elseif a:jump == "interrupt"
+ call interrupt()
+ let dummy = 0
+ elseif a:jump == "throw"
+ throw "abc"
+ endif
+ finally
+ throw "xyz" " discards jump that caused the :finally
+ endtry
+ elseif loop == 2
+ call assert_report('should not get here')
+ endif
+ endwhile
+ call assert_report('should not get here')
+ endfunc
+
+ try
+ Xpath 'a'
+ call T("continue")
+ call assert_report('should not get here')
+ finally
+ try
+ Xpath 'b'
+ call T("break")
+ call assert_report('should not get here')
+ finally
+ try
+ Xpath 'c'
+ call T("return")
+ call assert_report('should not get here')
+ finally
+ try
+ Xpath 'd'
+ let g:jump = "finish"
+ ExecAsScript T
+ call assert_report('should not get here')
+ finally
+ unlet g:jump
+ try
+ Xpath 'e'
+ call T("error")
+ call assert_report('should not get here')
+ finally
+ try
+ Xpath 'f'
+ call T("interrupt")
+ call assert_report('should not get here')
+ finally
+ try
+ Xpath 'g'
+ call T("throw")
+ call assert_report('should not get here')
+ finally
+ Xpath 'h'
+ delfunction T
+ endtry
+ endtry
+ endtry
+ endtry
+ endtry
+ endtry
+ endtry
+ call assert_report('should not get here')
+ [CODE]
+ let verify =<< trim [CODE]
+ call assert_equal('abcdefgh', g:Xpath)
+ [CODE]
+ call RunInNewVim(test, verify)
+endfunc
+
+"-------------------------------------------------------------------------------
+" Test 49: Throwing exceptions across functions {{{1
+"
+" When an exception is thrown but not caught inside a function, the
+" caller is checked for a matching :catch clause.
+"-------------------------------------------------------------------------------
+
+func T49_C()
+ try
+ Xpath 'a'
+ throw "arrgh"
+ call assert_report('should not get here')
+ catch /arrgh/
+ Xpath 'b'
+ endtry
+ Xpath 'c'
+endfunc
+
+func T49_T1()
+ XloopNEXT
+ try
+ Xloop 'd'
+ throw "arrgh"
+ call assert_report('should not get here')
+ finally
+ Xloop 'e'
+ endtry
+ Xloop 'f'
+endfunc
+
+func T49_T2()
+ try
+ Xpath 'g'
+ call T49_T1()
+ call assert_report('should not get here')
+ finally
+ Xpath 'h'
+ endtry
+ call assert_report('should not get here')
+endfunc
+
+func Test_throw_exception_across_funcs()
+ XpathINIT
+ XloopINIT
+ try
+ Xpath 'i'
+ call T49_C() " throw and catch
+ Xpath 'j'
+ catch /.*/
+ call assert_report('should not get here')
+ endtry
+
+ try
+ Xpath 'k'
+ call T49_T1() " throw, one level
+ call assert_report('should not get here')
+ catch /arrgh/
+ Xpath 'l'
+ catch /.*/
+ call assert_report('should not get here')
+ endtry
+
+ try
+ Xpath 'm'
+ call T49_T2() " throw, two levels
+ call assert_report('should not get here')
+ catch /arrgh/
+ Xpath 'n'
+ catch /.*/
+ call assert_report('should not get here')
+ endtry
+ Xpath 'o'
+
+ call assert_equal('iabcjkd2e2lmgd3e3hno', g:Xpath)
+endfunc
+
+"-------------------------------------------------------------------------------
+" Test 50: Throwing exceptions across script files {{{1
+"
+" When an exception is thrown but not caught inside a script file,
+" the sourcing script or function is checked for a matching :catch
+" clause.
+"
+" This test executes the bodies of the functions C, T1, and T2 from
+" the previous test as script files (:return replaced by :finish).
"-------------------------------------------------------------------------------
+
+func T50_F()
+ try
+ Xpath 'A'
+ exec "source" g:scriptC
+ Xpath 'B'
+ catch /.*/
+ call assert_report('should not get here')
+ endtry
+
+ try
+ Xpath 'C'
+ exec "source" g:scriptT1
+ call assert_report('should not get here')
+ catch /arrgh/
+ Xpath 'D'
+ catch /.*/
+ call assert_report('should not get here')
+ endtry
+endfunc
+
+func Test_throw_across_script()
+ XpathINIT
+ XloopINIT
+ let g:scriptC = MakeScript("T49_C")
+ let g:scriptT1 = MakeScript("T49_T1")
+ let scriptT2 = MakeScript("T49_T2", g:scriptT1)
+
+ try
+ Xpath 'E'
+ call T50_F()
+ Xpath 'F'
+ exec "source" scriptT2
+ call assert_report('should not get here')
+ catch /arrgh/
+ Xpath 'G'
+ catch /.*/
+ call assert_report('should not get here')
+ endtry
+ Xpath 'H'
+ call assert_equal('EAabcBCd2e2DFgd3e3hGH', g:Xpath)
+
+ call delete(g:scriptC)
+ call delete(g:scriptT1)
+ call delete(scriptT2)
+ unlet g:scriptC g:scriptT1 scriptT2
+endfunc
+
+"-------------------------------------------------------------------------------
+" Test 52: Uncaught exceptions {{{1
+"
+" When an exception is thrown but not caught, an error message is
+" displayed when the script is terminated. In case of an interrupt
+" or error exception, the normal interrupt or error message(s) are
+" displayed.
+"-------------------------------------------------------------------------------
+
+func Test_uncaught_exception_1()
+ CheckEnglish
+
+ let test =<< trim [CODE]
+ Xpath 'a'
+ throw "arrgh"
+ call assert_report('should not get here')`
+ [CODE]
+ let verify =<< trim [CODE]
+ call assert_equal('E605: Exception not caught: arrgh', v:errmsg)
+ call assert_equal('a', g:Xpath)
+ [CODE]
+ call RunInNewVim(test, verify)
+endfunc
+
+func Test_uncaught_exception_2()
+ CheckEnglish
+
+ let test =<< trim [CODE]
+ try
+ Xpath 'a'
+ throw "oops"
+ call assert_report('should not get here')`
+ catch /arrgh/
+ call assert_report('should not get here')`
+ endtry
+ call assert_report('should not get here')`
+ [CODE]
+ let verify =<< trim [CODE]
+ call assert_equal('E605: Exception not caught: oops', v:errmsg)
+ call assert_equal('a', g:Xpath)
+ [CODE]
+ call RunInNewVim(test, verify)
+endfunc
+
+func Test_uncaught_exception_3()
+ CheckEnglish
+
+ let test =<< trim [CODE]
+ func T()
+ Xpath 'c'
+ throw "brrr"
+ call assert_report('should not get here')`
+ endfunc
+
+ try
+ Xpath 'a'
+ throw "arrgh"
+ call assert_report('should not get here')`
+ catch /.*/
+ Xpath 'b'
+ call T()
+ call assert_report('should not get here')`
+ endtry
+ call assert_report('should not get here')`
+ [CODE]
+ let verify =<< trim [CODE]
+ call assert_equal('E605: Exception not caught: brrr', v:errmsg)
+ call assert_equal('abc', g:Xpath)
+ [CODE]
+ call RunInNewVim(test, verify)
+endfunc
+
+func Test_uncaught_exception_4()
+ CheckEnglish
+
+ let test =<< trim [CODE]
+ try
+ Xpath 'a'
+ throw "arrgh"
+ call assert_report('should not get here')`
+ finally
+ Xpath 'b'
+ throw "brrr"
+ call assert_report('should not get here')`
+ endtry
+ call assert_report('should not get here')`
+ [CODE]
+ let verify =<< trim [CODE]
+ call assert_equal('E605: Exception not caught: brrr', v:errmsg)
+ call assert_equal('ab', g:Xpath)
+ [CODE]
+ call RunInNewVim(test, verify)
+endfunc
+
+func Test_uncaught_exception_5()
+ CheckEnglish
+
+ " Need to catch and handle interrupt, otherwise the test will wait for the
+ " user to press <Enter> to continue
+ let test =<< trim [CODE]
+ try
+ try
+ Xpath 'a'
+ call interrupt()
+ call assert_report('should not get here')
+ endtry
+ call assert_report('should not get here')
+ catch /^Vim:Interrupt$/
+ Xpath 'b'
+ endtry
+ [CODE]
+ let verify =<< trim [CODE]
+ call assert_equal('ab', g:Xpath)
+ [CODE]
+ call RunInNewVim(test, verify)
+endfunc
+
+func Test_uncaught_exception_6()
+ CheckEnglish
+
+ let test =<< trim [CODE]
+ try
+ Xpath 'a'
+ let x = novar " error E121; exception: E121
+ catch /E15:/ " should not catch
+ call assert_report('should not get here')
+ endtry
+ call assert_report('should not get here')
+ [CODE]
+ let verify =<< trim [CODE]
+ call assert_equal('a', g:Xpath)
+ call assert_equal('E121: Undefined variable: novar', v:errmsg)
+ [CODE]
+ call RunInNewVim(test, verify)
+endfunc
+
+func Test_uncaught_exception_7()
+ CheckEnglish
+
+ let test =<< trim [CODE]
+ try
+ Xpath 'a'
+ " error E108/E488; exception: E488
+ unlet novar #
+ catch /E108:/ " should not catch
+ call assert_report('should not get here')
+ endtry
+ call assert_report('should not get here')
+ [CODE]
+ let verify =<< trim [CODE]
+ call assert_equal('a', g:Xpath)
+ call assert_equal('E488: Trailing characters: #', v:errmsg)
+ [CODE]
+ call RunInNewVim(test, verify)
+endfunc
+
+"-------------------------------------------------------------------------------
+" Test 53: Nesting errors: :endif/:else/:elseif {{{1
+"
+" For nesting errors of :if conditionals the correct error messages
+" should be given.
+"-------------------------------------------------------------------------------
+
+func Test_nested_if_else_errors()
+ CheckEnglish
+
+ " :endif without :if
+ let code =<< trim END
+ endif
+ END
+ call writefile(code, 'Xtest')
+ call AssertException(['source Xtest'], 'Vim(endif):E580: :endif without :if')
+
+ " :endif without :if
+ let code =<< trim END
+ while 1
+ endif
+ endwhile
+ END
+ call writefile(code, 'Xtest')
+ call AssertException(['source Xtest'], 'Vim(endif):E580: :endif without :if')
+
+ " :endif without :if
+ let code =<< trim END
+ try
+ finally
+ endif
+ endtry
+ END
+ call writefile(code, 'Xtest')
+ call AssertException(['source Xtest'], 'Vim(endif):E580: :endif without :if')
+
+ " :endif without :if
+ let code =<< trim END
+ try
+ endif
+ endtry
+ END
+ call writefile(code, 'Xtest')
+ call AssertException(['source Xtest'], 'Vim(endif):E580: :endif without :if')
+
+ " :endif without :if
+ let code =<< trim END
+ try
+ throw "a"
+ catch /a/
+ endif
+ endtry
+ END
+ call writefile(code, 'Xtest')
+ call AssertException(['source Xtest'], 'Vim(endif):E580: :endif without :if')
+
+ " :else without :if
+ let code =<< trim END
+ else
+ END
+ call writefile(code, 'Xtest')
+ call AssertException(['source Xtest'], 'Vim(else):E581: :else without :if')
+
+ " :else without :if
+ let code =<< trim END
+ while 1
+ else
+ endwhile
+ END
+ call writefile(code, 'Xtest')
+ call AssertException(['source Xtest'], 'Vim(else):E581: :else without :if')
+
+ " :else without :if
+ let code =<< trim END
+ try
+ finally
+ else
+ endtry
+ END
+ call writefile(code, 'Xtest')
+ call AssertException(['source Xtest'], 'Vim(else):E581: :else without :if')
+
+ " :else without :if
+ let code =<< trim END
+ try
+ else
+ endtry
+ END
+ call writefile(code, 'Xtest')
+ call AssertException(['source Xtest'], 'Vim(else):E581: :else without :if')
+
+ " :else without :if
+ let code =<< trim END
+ try
+ throw "a"
+ catch /a/
+ else
+ endtry
+ END
+ call writefile(code, 'Xtest')
+ call AssertException(['source Xtest'], 'Vim(else):E581: :else without :if')
+
+ " :elseif without :if
+ let code =<< trim END
+ elseif
+ END
+ call writefile(code, 'Xtest')
+ call AssertException(['source Xtest'], 'Vim(elseif):E582: :elseif without :if')
+
+ " :elseif without :if
+ let code =<< trim END
+ while 1
+ elseif
+ endwhile
+ END
+ call writefile(code, 'Xtest')
+ call AssertException(['source Xtest'], 'Vim(elseif):E582: :elseif without :if')
+
+ " :elseif without :if
+ let code =<< trim END
+ try
+ finally
+ elseif
+ endtry
+ END
+ call writefile(code, 'Xtest')
+ call AssertException(['source Xtest'], 'Vim(elseif):E582: :elseif without :if')
+
+ " :elseif without :if
+ let code =<< trim END
+ try
+ elseif
+ endtry
+ END
+ call writefile(code, 'Xtest')
+ call AssertException(['source Xtest'], 'Vim(elseif):E582: :elseif without :if')
+
+ " :elseif without :if
+ let code =<< trim END
+ try
+ throw "a"
+ catch /a/
+ elseif
+ endtry
+ END
+ call writefile(code, 'Xtest')
+ call AssertException(['source Xtest'], 'Vim(elseif):E582: :elseif without :if')
+
+ " multiple :else
+ let code =<< trim END
+ if 1
+ else
+ else
+ endif
+ END
+ call writefile(code, 'Xtest')
+ call AssertException(['source Xtest'], 'Vim(else):E583: multiple :else')
+
+ " :elseif after :else
+ let code =<< trim END
+ if 1
+ else
+ elseif 1
+ endif
+ END
+ call writefile(code, 'Xtest')
+ call AssertException(['source Xtest'], 'Vim(elseif):E584: :elseif after :else')
+
+ call delete('Xtest')
+endfunc
+
+"-------------------------------------------------------------------------------
+" Test 54: Nesting errors: :while/:endwhile {{{1
+"
+" For nesting errors of :while conditionals the correct error messages
+" should be given.
+"
+" This test reuses the function MESSAGES() from the previous test.
+" This functions checks the messages in g:msgfile.
+"-------------------------------------------------------------------------------
+
+func Test_nested_while_error()
+ CheckEnglish
+
+ " :endwhile without :while
+ let code =<< trim END
+ endwhile
+ END
+ call writefile(code, 'Xtest')
+ call AssertException(['source Xtest'], 'Vim(endwhile):E588: :endwhile without :while')
+
+ " :endwhile without :while
+ let code =<< trim END
+ if 1
+ endwhile
+ endif
+ END
+ call writefile(code, 'Xtest')
+ call AssertException(['source Xtest'], 'Vim(endwhile):E588: :endwhile without :while')
+
+ " Missing :endif
+ let code =<< trim END
+ while 1
+ if 1
+ endwhile
+ END
+ call writefile(code, 'Xtest')
+ call AssertException(['source Xtest'], 'Vim(endwhile):E171: Missing :endif')
+
+ " :endwhile without :while
+ let code =<< trim END
+ try
+ finally
+ endwhile
+ endtry
+ END
+ call writefile(code, 'Xtest')
+ call AssertException(['source Xtest'], 'Vim(endwhile):E588: :endwhile without :while')
+
+ " Missing :endtry
+ let code =<< trim END
+ while 1
+ try
+ finally
+ endwhile
+ END
+ call writefile(code, 'Xtest')
+ call AssertException(['source Xtest'], 'Vim(endwhile):E600: Missing :endtry')
+
+ " Missing :endtry
+ let code =<< trim END
+ while 1
+ if 1
+ try
+ finally
+ endwhile
+ END
+ call writefile(code, 'Xtest')
+ call AssertException(['source Xtest'], 'Vim(endwhile):E600: Missing :endtry')
+
+ " Missing :endif
+ let code =<< trim END
+ while 1
+ try
+ finally
+ if 1
+ endwhile
+ END
+ call writefile(code, 'Xtest')
+ call AssertException(['source Xtest'], 'Vim(endwhile):E171: Missing :endif')
+
+ " :endwhile without :while
+ let code =<< trim END
+ try
+ endwhile
+ endtry
+ END
+ call writefile(code, 'Xtest')
+ call AssertException(['source Xtest'], 'Vim(endwhile):E588: :endwhile without :while')
+
+ " :endwhile without :while
+ let code =<< trim END
+ while 1
+ try
+ endwhile
+ endtry
+ endwhile
+ END
+ call writefile(code, 'Xtest')
+ call AssertException(['source Xtest'], 'Vim(endwhile):E588: :endwhile without :while')
+
+ " :endwhile without :while
+ let code =<< trim END
+ try
+ throw "a"
+ catch /a/
+ endwhile
+ endtry
+ END
+ call writefile(code, 'Xtest')
+ call AssertException(['source Xtest'], 'Vim(endwhile):E588: :endwhile without :while')
+
+ " :endwhile without :while
+ let code =<< trim END
+ while 1
+ try
+ throw "a"
+ catch /a/
+ endwhile
+ endtry
+ endwhile
+ END
+ call writefile(code, 'Xtest')
+ call AssertException(['source Xtest'], 'Vim(endwhile):E588: :endwhile without :while')
+
+ call delete('Xtest')
+endfunc
+
+"-------------------------------------------------------------------------------
+" Test 55: Nesting errors: :continue/:break {{{1
+"
+" For nesting errors of :continue and :break commands the correct
+" error messages should be given.
+"
+" This test reuses the function MESSAGES() from the previous test.
+" This functions checks the messages in g:msgfile.
+"-------------------------------------------------------------------------------
+
+func Test_nested_cont_break_error()
+ CheckEnglish
+
+ " :continue without :while
+ let code =<< trim END
+ continue
+ END
+ call writefile(code, 'Xtest')
+ call AssertException(['source Xtest'], 'Vim(continue):E586: :continue without :while or :for')
+
+ " :continue without :while
+ let code =<< trim END
+ if 1
+ continue
+ endif
+ END
+ call writefile(code, 'Xtest')
+ call AssertException(['source Xtest'], 'Vim(continue):E586: :continue without :while or :for')
+
+ " :continue without :while
+ let code =<< trim END
+ try
+ finally
+ continue
+ endtry
+ END
+ call writefile(code, 'Xtest')
+ call AssertException(['source Xtest'], 'Vim(continue):E586: :continue without :while or :for')
+
+ " :continue without :while
+ let code =<< trim END
+ try
+ continue
+ endtry
+ END
+ call writefile(code, 'Xtest')
+ call AssertException(['source Xtest'], 'Vim(continue):E586: :continue without :while or :for')
+
+ " :continue without :while
+ let code =<< trim END
+ try
+ throw "a"
+ catch /a/
+ continue
+ endtry
+ END
+ call writefile(code, 'Xtest')
+ call AssertException(['source Xtest'], 'Vim(continue):E586: :continue without :while or :for')
+
+ " :break without :while
+ let code =<< trim END
+ break
+ END
+ call writefile(code, 'Xtest')
+ call AssertException(['source Xtest'], 'Vim(break):E587: :break without :while or :for')
+
+ " :break without :while
+ let code =<< trim END
+ if 1
+ break
+ endif
+ END
+ call writefile(code, 'Xtest')
+ call AssertException(['source Xtest'], 'Vim(break):E587: :break without :while or :for')
+
+ " :break without :while
+ let code =<< trim END
+ try
+ finally
+ break
+ endtry
+ END
+ call writefile(code, 'Xtest')
+ call AssertException(['source Xtest'], 'Vim(break):E587: :break without :while or :for')
+
+ " :break without :while
+ let code =<< trim END
+ try
+ break
+ endtry
+ END
+ call writefile(code, 'Xtest')
+ call AssertException(['source Xtest'], 'Vim(break):E587: :break without :while or :for')
+
+ " :break without :while
+ let code =<< trim END
+ try
+ throw "a"
+ catch /a/
+ break
+ endtry
+ END
+ call writefile(code, 'Xtest')
+ call AssertException(['source Xtest'], 'Vim(break):E587: :break without :while or :for')
+
+ call delete('Xtest')
+endfunc
+
+"-------------------------------------------------------------------------------
+" Test 56: Nesting errors: :endtry {{{1
+"
+" For nesting errors of :try conditionals the correct error messages
+" should be given.
+"
+" This test reuses the function MESSAGES() from the previous test.
+" This functions checks the messages in g:msgfile.
+"-------------------------------------------------------------------------------
+
+func Test_nested_endtry_error()
+ CheckEnglish
+
+ " :endtry without :try
+ let code =<< trim END
+ endtry
+ END
+ call writefile(code, 'Xtest')
+ call AssertException(['source Xtest'], 'Vim(endtry):E602: :endtry without :try')
+
+ " :endtry without :try
+ let code =<< trim END
+ if 1
+ endtry
+ endif
+ END
+ call writefile(code, 'Xtest')
+ call AssertException(['source Xtest'], 'Vim(endtry):E602: :endtry without :try')
+
+ " :endtry without :try
+ let code =<< trim END
+ while 1
+ endtry
+ endwhile
+ END
+ call writefile(code, 'Xtest')
+ call AssertException(['source Xtest'], 'Vim(endtry):E602: :endtry without :try')
+
+ " Missing :endif
+ let code =<< trim END
+ try
+ if 1
+ endtry
+ END
+ call writefile(code, 'Xtest')
+ call AssertException(['source Xtest'], 'Vim(endtry):E171: Missing :endif')
+
+ " Missing :endwhile
+ let code =<< trim END
+ try
+ while 1
+ endtry
+ END
+ call writefile(code, 'Xtest')
+ call AssertException(['source Xtest'], 'Vim(endtry):E170: Missing :endwhile')
+
+ " Missing :endif
+ let code =<< trim END
+ try
+ finally
+ if 1
+ endtry
+ END
+ call writefile(code, 'Xtest')
+ call AssertException(['source Xtest'], 'Vim(endtry):E171: Missing :endif')
+
+ " Missing :endwhile
+ let code =<< trim END
+ try
+ finally
+ while 1
+ endtry
+ END
+ call writefile(code, 'Xtest')
+ call AssertException(['source Xtest'], 'Vim(endtry):E170: Missing :endwhile')
+
+ " Missing :endif
+ let code =<< trim END
+ try
+ throw "a"
+ catch /a/
+ if 1
+ endtry
+ END
+ call writefile(code, 'Xtest')
+ call AssertException(['source Xtest'], 'Vim(endtry):E171: Missing :endif')
+
+ " Missing :endwhile
+ let code =<< trim END
+ try
+ throw "a"
+ catch /a/
+ while 1
+ endtry
+ END
+ call writefile(code, 'Xtest')
+ call AssertException(['source Xtest'], 'Vim(endtry):E170: Missing :endwhile')
+
+ call delete('Xtest')
+endfunc
+
+"-------------------------------------------------------------------------------
+" Test 57: v:exception and v:throwpoint for user exceptions {{{1
+"
+" v:exception evaluates to the value of the exception that was caught
+" most recently and is not finished. (A caught exception is finished
+" when the next ":catch", ":finally", or ":endtry" is reached.)
+" v:throwpoint evaluates to the script/function name and line number
+" where that exception has been thrown.
+"-------------------------------------------------------------------------------
+
+func Test_user_exception_info()
+ CheckEnglish
+
+ XpathINIT
+ XloopINIT
+
+ func FuncException()
+ let g:exception = v:exception
+ endfunc
+
+ func FuncThrowpoint()
+ let g:throwpoint = v:throwpoint
+ endfunc
+
+ let scriptException = MakeScript("FuncException")
+ let scriptThrowPoint = MakeScript("FuncThrowpoint")
+
+ command! CmdException let g:exception = v:exception
+ command! CmdThrowpoint let g:throwpoint = v:throwpoint
+
+ func T(arg, line)
+ if a:line == 2
+ throw a:arg " in line 2
+ elseif a:line == 4
+ throw a:arg " in line 4
+ elseif a:line == 6
+ throw a:arg " in line 6
+ elseif a:line == 8
+ throw a:arg " in line 8
+ endif
+ endfunc
+
+ func G(arg, line)
+ call T(a:arg, a:line)
+ endfunc
+
+ func F(arg, line)
+ call G(a:arg, a:line)
+ endfunc
+
+ let scriptT = MakeScript("T")
+ let scriptG = MakeScript("G", scriptT)
+ let scriptF = MakeScript("F", scriptG)
+
+ try
+ Xpath 'a'
+ call F("oops", 2)
+ catch /.*/
+ Xpath 'b'
+ let exception = v:exception
+ let throwpoint = v:throwpoint
+ call assert_equal("oops", v:exception)
+ call assert_match('\<F\[1]\.\.G\[1]\.\.T\>', v:throwpoint)
+ call assert_match('\<2\>', v:throwpoint)
+
+ exec "let exception = v:exception"
+ exec "let throwpoint = v:throwpoint"
+ call assert_equal("oops", v:exception)
+ call assert_match('\<F\[1]\.\.G\[1]\.\.T\>', v:throwpoint)
+ call assert_match('\<2\>', v:throwpoint)
+
+ CmdException
+ CmdThrowpoint
+ call assert_equal("oops", v:exception)
+ call assert_match('\<F\[1]\.\.G\[1]\.\.T\>', v:throwpoint)
+ call assert_match('\<2\>', v:throwpoint)
+
+ call FuncException()
+ call FuncThrowpoint()
+ call assert_equal("oops", v:exception)
+ call assert_match('\<F\[1]\.\.G\[1]\.\.T\>', v:throwpoint)
+ call assert_match('\<2\>', v:throwpoint)
+
+ exec "source" scriptException
+ exec "source" scriptThrowPoint
+ call assert_equal("oops", v:exception)
+ call assert_match('\<F\[1]\.\.G\[1]\.\.T\>', v:throwpoint)
+ call assert_match('\<2\>', v:throwpoint)
+
+ try
+ Xpath 'c'
+ call G("arrgh", 4)
+ catch /.*/
+ Xpath 'd'
+ let exception = v:exception
+ let throwpoint = v:throwpoint
+ call assert_equal("arrgh", v:exception)
+ call assert_match('\<G\[1]\.\.T\>', v:throwpoint)
+ call assert_match('\<4\>', v:throwpoint)
+
+ try
+ Xpath 'e'
+ let g:arg = "autsch"
+ let g:line = 6
+ exec "source" scriptF
+ catch /.*/
+ Xpath 'f'
+ let exception = v:exception
+ let throwpoint = v:throwpoint
+ call assert_equal("autsch", v:exception)
+ call assert_match(fnamemodify(scriptT, ':t'), v:throwpoint)
+ call assert_match('\<6\>', v:throwpoint)
+ finally
+ Xpath 'g'
+ let exception = v:exception
+ let throwpoint = v:throwpoint
+ call assert_equal("arrgh", v:exception)
+ call assert_match('\<G\[1]\.\.T\>', v:throwpoint)
+ call assert_match('\<4\>', v:throwpoint)
+ try
+ Xpath 'h'
+ let g:arg = "brrrr"
+ let g:line = 8
+ exec "source" scriptG
+ catch /.*/
+ Xpath 'i'
+ let exception = v:exception
+ let throwpoint = v:throwpoint
+ " Resolve scriptT for matching it against v:throwpoint.
+ call assert_equal("brrrr", v:exception)
+ call assert_match(fnamemodify(scriptT, ':t'), v:throwpoint)
+ call assert_match('\<8\>', v:throwpoint)
+ finally
+ Xpath 'j'
+ let exception = v:exception
+ let throwpoint = v:throwpoint
+ call assert_equal("arrgh", v:exception)
+ call assert_match('\<G\[1]\.\.T\>', v:throwpoint)
+ call assert_match('\<4\>', v:throwpoint)
+ endtry
+ Xpath 'k'
+ let exception = v:exception
+ let throwpoint = v:throwpoint
+ call assert_equal("arrgh", v:exception)
+ call assert_match('\<G\[1]\.\.T\>', v:throwpoint)
+ call assert_match('\<4\>', v:throwpoint)
+ endtry
+ Xpath 'l'
+ let exception = v:exception
+ let throwpoint = v:throwpoint
+ call assert_equal("arrgh", v:exception)
+ call assert_match('\<G\[1]\.\.T\>', v:throwpoint)
+ call assert_match('\<4\>', v:throwpoint)
+ finally
+ Xpath 'm'
+ let exception = v:exception
+ let throwpoint = v:throwpoint
+ call assert_equal("oops", v:exception)
+ call assert_match('\<F\[1]\.\.G\[1]\.\.T\>', v:throwpoint)
+ call assert_match('\<2\>', v:throwpoint)
+ endtry
+ Xpath 'n'
+ let exception = v:exception
+ let throwpoint = v:throwpoint
+ call assert_equal("oops", v:exception)
+ call assert_match('\<F\[1]\.\.G\[1]\.\.T\>', v:throwpoint)
+ call assert_match('\<2\>', v:throwpoint)
+ finally
+ Xpath 'o'
+ let exception = v:exception
+ let throwpoint = v:throwpoint
+ call assert_equal("", v:exception)
+ call assert_match('^$', v:throwpoint)
+ call assert_match('^$', v:throwpoint)
+ endtry
+
+ call assert_equal('abcdefghijklmno', g:Xpath)
+
+ unlet exception throwpoint
+ delfunction FuncException
+ delfunction FuncThrowpoint
+ call delete(scriptException)
+ call delete(scriptThrowPoint)
+ unlet scriptException scriptThrowPoint
+ delcommand CmdException
+ delcommand CmdThrowpoint
+ delfunction T
+ delfunction G
+ delfunction F
+ call delete(scriptT)
+ call delete(scriptG)
+ call delete(scriptF)
+ unlet scriptT scriptG scriptF
+endfunc
+
+"-------------------------------------------------------------------------------
+"
+" Test 58: v:exception and v:throwpoint for error/interrupt exceptions {{{1
+"
+" v:exception and v:throwpoint work also for error and interrupt
+" exceptions.
+"-------------------------------------------------------------------------------
+
+func Test_execption_info_for_error()
+ CheckEnglish
+
+ let test =<< trim [CODE]
+ func T(line)
+ if a:line == 2
+ delfunction T " error (function in use) in line 2
+ elseif a:line == 4
+ call interrupt()
+ endif
+ endfunc
+
+ while 1
+ try
+ Xpath 'a'
+ call T(2)
+ call assert_report('should not get here')
+ catch /.*/
+ Xpath 'b'
+ if v:exception !~ 'Vim(delfunction):'
+ call assert_report('should not get here')
+ endif
+ if v:throwpoint !~ '\<T\>'
+ call assert_report('should not get here')
+ endif
+ if v:throwpoint !~ '\<2\>'
+ call assert_report('should not get here')
+ endif
+ finally
+ Xpath 'c'
+ if v:exception != ""
+ call assert_report('should not get here')
+ endif
+ if v:throwpoint != ""
+ call assert_report('should not get here')
+ endif
+ break
+ endtry
+ endwhile
+
+ Xpath 'd'
+ if v:exception != ""
+ call assert_report('should not get here')
+ endif
+ if v:throwpoint != ""
+ call assert_report('should not get here')
+ endif
+
+ while 1
+ try
+ Xpath 'e'
+ call T(4)
+ call assert_report('should not get here')
+ catch /.*/
+ Xpath 'f'
+ if v:exception != 'Vim:Interrupt'
+ call assert_report('should not get here')
+ endif
+ if v:throwpoint !~ 'function T'
+ call assert_report('should not get here')
+ endif
+ if v:throwpoint !~ '\<4\>'
+ call assert_report('should not get here')
+ endif
+ finally
+ Xpath 'g'
+ if v:exception != ""
+ call assert_report('should not get here')
+ endif
+ if v:throwpoint != ""
+ call assert_report('should not get here')
+ endif
+ break
+ endtry
+ endwhile
+
+ Xpath 'h'
+ if v:exception != ""
+ call assert_report('should not get here')
+ endif
+ if v:throwpoint != ""
+ call assert_report('should not get here')
+ endif
+ [CODE]
+ let verify =<< trim [CODE]
+ call assert_equal('abcdefgh', g:Xpath)
+ [CODE]
+ call RunInNewVim(test, verify)
+endfunc
+
+"-------------------------------------------------------------------------------
+"
+" Test 59: v:exception and v:throwpoint when discarding exceptions {{{1
+"
+" When a :catch clause is left by a ":break" etc or an error or
+" interrupt exception, v:exception and v:throwpoint are reset. They
+" are not affected by an exception that is discarded before being
+" caught.
+"-------------------------------------------------------------------------------
+func Test_exception_info_on_discard()
+ CheckEnglish
+
+ let test =<< trim [CODE]
+ let sfile = expand("<sfile>")
+
+ while 1
+ try
+ throw "x1"
+ catch /.*/
+ break
+ endtry
+ endwhile
+ call assert_equal('', v:exception)
+ call assert_equal('', v:throwpoint)
+
+ while 1
+ try
+ throw "x2"
+ catch /.*/
+ break
+ finally
+ call assert_equal('', v:exception)
+ call assert_equal('', v:throwpoint)
+ endtry
+ break
+ endwhile
+ call assert_equal('', v:exception)
+ call assert_equal('', v:throwpoint)
+
+ while 1
+ try
+ let errcaught = 0
+ try
+ try
+ throw "x3"
+ catch /.*/
+ let lnum = expand("<sflnum>")
+ asdf
+ endtry
+ catch /.*/
+ let errcaught = 1
+ call assert_match('Vim:E492: Not an editor command:', v:exception)
+ call assert_match('line ' .. (lnum + 1), v:throwpoint)
+ endtry
+ finally
+ call assert_equal(1, errcaught)
+ break
+ endtry
+ endwhile
+ call assert_equal('', v:exception)
+ call assert_equal('', v:throwpoint)
+
+ Xpath 'a'
+
+ while 1
+ try
+ let intcaught = 0
+ try
+ try
+ throw "x4"
+ catch /.*/
+ let lnum = expand("<sflnum>")
+ call interrupt()
+ endtry
+ catch /.*/
+ let intcaught = 1
+ call assert_match('Vim:Interrupt', v:exception)
+ call assert_match('line ' .. (lnum + 1), v:throwpoint)
+ endtry
+ finally
+ call assert_equal(1, intcaught)
+ break
+ endtry
+ endwhile
+ call assert_equal('', v:exception)
+ call assert_equal('', v:throwpoint)
+
+ Xpath 'b'
+
+ while 1
+ try
+ let errcaught = 0
+ try
+ try
+ if 1
+ let lnum = expand("<sflnum>")
+ throw "x5"
+ " missing endif
+ catch /.*/
+ call assert_report('should not get here')
+ endtry
+ catch /.*/
+ let errcaught = 1
+ call assert_match('Vim(catch):E171: Missing :endif:', v:exception)
+ call assert_match('line ' .. (lnum + 3), v:throwpoint)
+ endtry
+ finally
+ call assert_equal(1, errcaught)
+ break
+ endtry
+ endwhile
+ call assert_equal('', v:exception)
+ call assert_equal('', v:throwpoint)
+
+ Xpath 'c'
+
+ try
+ while 1
+ try
+ throw "x6"
+ finally
+ break
+ endtry
+ break
+ endwhile
+ catch /.*/
+ call assert_report('should not get here')
+ endtry
+ call assert_equal('', v:exception)
+ call assert_equal('', v:throwpoint)
+
+ try
+ while 1
+ try
+ throw "x7"
+ finally
+ break
+ endtry
+ break
+ endwhile
+ catch /.*/
+ call assert_report('should not get here')
+ finally
+ call assert_equal('', v:exception)
+ call assert_equal('', v:throwpoint)
+ endtry
+ call assert_equal('', v:exception)
+ call assert_equal('', v:throwpoint)
+
+ while 1
+ try
+ let errcaught = 0
+ try
+ try
+ throw "x8"
+ finally
+ let lnum = expand("<sflnum>")
+ asdf
+ endtry
+ catch /.*/
+ let errcaught = 1
+ call assert_match('Vim:E492: Not an editor command:', v:exception)
+ call assert_match('line ' .. (lnum + 1), v:throwpoint)
+ endtry
+ finally
+ call assert_equal(1, errcaught)
+ break
+ endtry
+ endwhile
+ call assert_equal('', v:exception)
+ call assert_equal('', v:throwpoint)
+
+ Xpath 'd'
+
+ while 1
+ try
+ let intcaught = 0
+ try
+ try
+ throw "x9"
+ finally
+ let lnum = expand("<sflnum>")
+ call interrupt()
+ endtry
+ catch /.*/
+ let intcaught = 1
+ call assert_match('Vim:Interrupt', v:exception)
+ call assert_match('line ' .. (lnum + 1), v:throwpoint)
+ endtry
+ finally
+ call assert_equal(1, intcaught)
+ break
+ endtry
+ endwhile
+ call assert_equal('', v:exception)
+ call assert_equal('', v:throwpoint)
+
+ Xpath 'e'
+
+ while 1
+ try
+ let errcaught = 0
+ try
+ try
+ if 1
+ let lnum = expand("<sflnum>")
+ throw "x10"
+ " missing endif
+ finally
+ call assert_equal('', v:exception)
+ call assert_equal('', v:throwpoint)
+ endtry
+ catch /.*/
+ let errcaught = 1
+ call assert_match('Vim(finally):E171: Missing :endif:', v:exception)
+ call assert_match('line ' .. (lnum + 3), v:throwpoint)
+ endtry
+ finally
+ call assert_equal(1, errcaught)
+ break
+ endtry
+ endwhile
+ call assert_equal('', v:exception)
+ call assert_equal('', v:throwpoint)
+
+ Xpath 'f'
+
+ while 1
+ try
+ let errcaught = 0
+ try
+ try
+ if 1
+ let lnum = expand("<sflnum>")
+ throw "x11"
+ " missing endif
+ endtry
+ catch /.*/
+ let errcaught = 1
+ call assert_match('Vim(endtry):E171: Missing :endif:', v:exception)
+ call assert_match('line ' .. (lnum + 3), v:throwpoint)
+ endtry
+ finally
+ call assert_equal(1, errcaught)
+ break
+ endtry
+ endwhile
+ call assert_equal('', v:exception)
+ call assert_equal('', v:throwpoint)
+
+ Xpath 'g'
+ [CODE]
+ let verify =<< trim [CODE]
+ call assert_equal('abcdefg', g:Xpath)
+ [CODE]
+ call RunInNewVim(test, verify)
+endfunc
+
+"-------------------------------------------------------------------------------
+"
+" Test 60: (Re)throwing v:exception; :echoerr. {{{1
+"
+" A user exception can be rethrown after catching by throwing
+" v:exception. An error or interrupt exception cannot be rethrown
+" because Vim exceptions cannot be faked. A Vim exception using the
+" value of v:exception can, however, be triggered by the :echoerr
+" command.
+"-------------------------------------------------------------------------------
+
+func Test_rethrow_exception_1()
+ XpathINIT
+ try
+ try
+ Xpath 'a'
+ throw "oops"
+ catch /oops/
+ Xpath 'b'
+ throw v:exception " rethrow user exception
+ catch /.*/
+ call assert_report('should not get here')
+ endtry
+ catch /^oops$/ " catches rethrown user exception
+ Xpath 'c'
+ catch /.*/
+ call assert_report('should not get here')
+ endtry
+ call assert_equal('abc', g:Xpath)
+endfunc
+
+func Test_rethrow_exception_2()
+ XpathINIT
+ try
+ let caught = 0
+ try
+ Xpath 'a'
+ write /n/o/n/w/r/i/t/a/b/l/e/_/f/i/l/e
+ call assert_report('should not get here')
+ catch /^Vim(write):/
+ let caught = 1
+ throw v:exception " throw error: cannot fake Vim exception
+ catch /.*/
+ call assert_report('should not get here')
+ finally
+ Xpath 'b'
+ call assert_equal(1, caught)
+ endtry
+ catch /^Vim(throw):/ " catches throw error
+ let caught = caught + 1
+ catch /.*/
+ call assert_report('should not get here')
+ finally
+ Xpath 'c'
+ call assert_equal(2, caught)
+ endtry
+ call assert_equal('abc', g:Xpath)
+endfunc
+
+func Test_rethrow_exception_3()
+ XpathINIT
+ try
+ let caught = 0
+ try
+ Xpath 'a'
+ asdf
+ catch /^Vim/ " catch error exception
+ let caught = 1
+ " Trigger Vim error exception with value specified after :echoerr
+ let value = substitute(v:exception, '^Vim\((.*)\)\=:', '', "")
+ echoerr value
+ catch /.*/
+ call assert_report('should not get here')
+ finally
+ Xpath 'b'
+ call assert_equal(1, caught)
+ endtry
+ catch /^Vim(echoerr):/
+ let caught = caught + 1
+ call assert_match(value, v:exception)
+ catch /.*/
+ call assert_report('should not get here')
+ finally
+ Xpath 'c'
+ call assert_equal(2, caught)
+ endtry
+ call assert_equal('abc', g:Xpath)
+endfunc
+
+func Test_rethrow_exception_3()
+ XpathINIT
+ try
+ let errcaught = 0
+ try
+ Xpath 'a'
+ let intcaught = 0
+ call interrupt()
+ catch /^Vim:/ " catch interrupt exception
+ let intcaught = 1
+ " Trigger Vim error exception with value specified after :echoerr
+ echoerr substitute(v:exception, '^Vim\((.*)\)\=:', '', "")
+ catch /.*/
+ call assert_report('should not get here')
+ finally
+ Xpath 'b'
+ call assert_equal(1, intcaught)
+ endtry
+ catch /^Vim(echoerr):/
+ let errcaught = 1
+ call assert_match('Interrupt', v:exception)
+ finally
+ Xpath 'c'
+ call assert_equal(1, errcaught)
+ endtry
+ call assert_equal('abc', g:Xpath)
+endfunc
+
+"-------------------------------------------------------------------------------
+" Test 61: Catching interrupt exceptions {{{1
+"
+" When an interrupt occurs inside a :try/:endtry region, an
+" interrupt exception is thrown and can be caught. Its value is
+" "Vim:Interrupt". If the interrupt occurs after an error or a :throw
+" but before a matching :catch is reached, all following :catches of
+" that try block are ignored, but the interrupt exception can be
+" caught by the next surrounding try conditional. An interrupt is
+" ignored when there is a previous interrupt that has not been caught
+" or causes a :finally clause to be executed.
+"-------------------------------------------------------------------------------
+
+func Test_catch_intr_exception()
+ let test =<< trim [CODE]
+ while 1
+ try
+ try
+ Xpath 'a'
+ call interrupt()
+ call assert_report('should not get here')
+ catch /^Vim:Interrupt$/
+ Xpath 'b'
+ finally
+ Xpath 'c'
+ endtry
+ catch /.*/
+ call assert_report('should not get here')
+ finally
+ Xpath 'd'
+ break
+ endtry
+ endwhile
+
+ while 1
+ try
+ try
+ try
+ Xpath 'e'
+ asdf
+ call assert_report('should not get here')
+ catch /do_not_catch/
+ call assert_report('should not get here')
+ catch /.*/
+ Xpath 'f'
+ call interrupt()
+ call assert_report('should not get here')
+ catch /.*/
+ call assert_report('should not get here')
+ finally
+ Xpath 'g'
+ call interrupt()
+ call assert_report('should not get here')
+ endtry
+ catch /^Vim:Interrupt$/
+ Xpath 'h'
+ finally
+ Xpath 'i'
+ endtry
+ catch /.*/
+ call assert_report('should not get here')
+ finally
+ Xpath 'j'
+ break
+ endtry
+ endwhile
+
+ while 1
+ try
+ try
+ try
+ Xpath 'k'
+ throw "x"
+ call assert_report('should not get here')
+ catch /do_not_catch/
+ call assert_report('should not get here')
+ catch /x/
+ Xpath 'l'
+ call interrupt()
+ call assert_report('should not get here')
+ catch /.*/
+ call assert_report('should not get here')
+ endtry
+ catch /^Vim:Interrupt$/
+ Xpath 'm'
+ finally
+ Xpath 'n'
+ endtry
+ catch /.*/
+ call assert_report('should not get here')
+ finally
+ Xpath 'o'
+ break
+ endtry
+ endwhile
+
+ while 1
+ try
+ try
+ Xpath 'p'
+ call interrupt()
+ call assert_report('should not get here')
+ catch /do_not_catch/
+ call interrupt()
+ call assert_report('should not get here')
+ catch /^Vim:Interrupt$/
+ Xpath 'q'
+ finally
+ Xpath 'r'
+ endtry
+ catch /.*/
+ call assert_report('should not get here')
+ finally
+ Xpath 's'
+ break
+ endtry
+ endwhile
+
+ Xpath 't'
+ [CODE]
+ let verify =<< trim [CODE]
+ call assert_equal('abcdefghijklmnopqrst', g:Xpath)
+ [CODE]
+ call RunInNewVim(test, verify)
+endfunc
+
+"-------------------------------------------------------------------------------
+" Test 62: Catching error exceptions {{{1
+"
+" An error inside a :try/:endtry region is converted to an exception
+" and can be caught. The error exception has a "Vim(cmdname):" prefix
+" where cmdname is the name of the failing command, or a "Vim:" prefix
+" if no command name is known. The "Vim" prefixes cannot be faked.
+"-------------------------------------------------------------------------------
+
+func Test_catch_err_exception_1()
+ XpathINIT
+ while 1
+ try
+ try
+ let caught = 0
+ unlet novar
+ catch /^Vim(unlet):/
+ Xpath 'a'
+ let caught = 1
+ let v:errmsg = substitute(v:exception, '^Vim(unlet):', '', "")
+ finally
+ Xpath 'b'
+ call assert_equal(1, caught)
+ call assert_match('E108: No such variable: "novar"', v:errmsg)
+ endtry
+ catch /.*/
+ call assert_report('should not get here')
+ finally
+ Xpath 'c'
+ break
+ endtry
+ call assert_report('should not get here')
+ endwhile
+ call assert_equal('abc', g:Xpath)
+endfunc
+
+func Test_catch_err_exception_2()
+ XpathINIT
+ while 1
+ try
+ try
+ let caught = 0
+ throw novar " error in :throw
+ catch /^Vim(throw):/
+ Xpath 'a'
+ let caught = 1
+ let v:errmsg = substitute(v:exception, '^Vim(throw):', '', "")
+ finally
+ Xpath 'b'
+ call assert_equal(1, caught)
+ call assert_match('E121: Undefined variable: novar', v:errmsg)
+ endtry
+ catch /.*/
+ call assert_report('should not get here')
+ finally
+ Xpath 'c'
+ break
+ endtry
+ call assert_report('should not get here')
+ endwhile
+ call assert_equal('abc', g:Xpath)
+endfunc
+
+func Test_catch_err_exception_3()
+ XpathINIT
+ while 1
+ try
+ try
+ let caught = 0
+ throw "Vim:faked" " error: cannot fake Vim exception
+ catch /^Vim(throw):/
+ Xpath 'a'
+ let caught = 1
+ let v:errmsg = substitute(v:exception, '^Vim(throw):', '', "")
+ finally
+ Xpath 'b'
+ call assert_equal(1, caught)
+ call assert_match("E608: Cannot :throw exceptions with 'Vim' prefix",
+ \ v:errmsg)
+ endtry
+ catch /.*/
+ call assert_report('should not get here')
+ finally
+ Xpath 'c'
+ break
+ endtry
+ call assert_report('should not get here')
+ endwhile
+ call assert_equal('abc', g:Xpath)
+endfunc
+
+func Test_catch_err_exception_4()
+ XpathINIT
+ func F()
+ while 1
+ " Missing :endwhile
+ endfunc
+
+ while 1
+ try
+ try
+ let caught = 0
+ call F()
+ catch /^Vim(endfunction):/
+ Xpath 'a'
+ let caught = 1
+ let v:errmsg = substitute(v:exception, '^Vim(endfunction):', '', "")
+ finally
+ Xpath 'b'
+ call assert_equal(1, caught)
+ call assert_match("E170: Missing :endwhile", v:errmsg)
+ endtry
+ catch /.*/
+ call assert_report('should not get here')
+ finally
+ Xpath 'c'
+ break
+ endtry
+ call assert_report('should not get here')
+ endwhile
+ call assert_equal('abc', g:Xpath)
+ delfunc F
+endfunc
+
+func Test_catch_err_exception_5()
+ XpathINIT
+ func F()
+ while 1
+ " Missing :endwhile
+ endfunc
+
+ while 1
+ try
+ try
+ let caught = 0
+ ExecAsScript F
+ catch /^Vim:/
+ Xpath 'a'
+ let caught = 1
+ let v:errmsg = substitute(v:exception, '^Vim:', '', "")
+ finally
+ Xpath 'b'
+ call assert_equal(1, caught)
+ call assert_match("E170: Missing :endwhile", v:errmsg)
+ endtry
+ catch /.*/
+ call assert_report('should not get here')
+ finally
+ Xpath 'c'
+ break
+ endtry
+ call assert_report('should not get here')
+ endwhile
+ call assert_equal('abc', g:Xpath)
+ delfunc F
+endfunc
+
+func Test_catch_err_exception_6()
+ XpathINIT
+ func G()
+ call G()
+ endfunc
+
+ while 1
+ try
+ let mfd_save = &mfd
+ set mfd=3
+ try
+ let caught = 0
+ call G()
+ catch /^Vim(call):/
+ Xpath 'a'
+ let caught = 1
+ let v:errmsg = substitute(v:exception, '^Vim(call):', '', "")
+ finally
+ Xpath 'b'
+ call assert_equal(1, caught)
+ call assert_match("E132: Function call depth is higher than 'maxfuncdepth'", v:errmsg)
+ endtry
+ catch /.*/
+ call assert_report('should not get here')
+ finally
+ Xpath 'c'
+ let &mfd = mfd_save
+ break
+ endtry
+ call assert_report('should not get here')
+ endwhile
+ call assert_equal('abc', g:Xpath)
+ delfunc G
+endfunc
+
+func Test_catch_err_exception_7()
+ XpathINIT
+ func H()
+ return H()
+ endfunc
+
+ while 1
+ try
+ let mfd_save = &mfd
+ set mfd=3
+ try
+ let caught = 0
+ call H()
+ catch /^Vim(return):/
+ Xpath 'a'
+ let caught = 1
+ let v:errmsg = substitute(v:exception, '^Vim(return):', '', "")
+ finally
+ Xpath 'b'
+ call assert_equal(1, caught)
+ call assert_match("E132: Function call depth is higher than 'maxfuncdepth'", v:errmsg)
+ endtry
+ catch /.*/
+ call assert_report('should not get here')
+ finally
+ Xpath 'c'
+ let &mfd = mfd_save
+ break " discard error for $VIMNOERRTHROW
+ endtry
+ call assert_report('should not get here')
+ endwhile
+
+ call assert_equal('abc', g:Xpath)
+ delfunc H
+endfunc
+
+"-------------------------------------------------------------------------------
+" Test 63: Suppressing error exceptions by :silent!. {{{1
+"
+" A :silent! command inside a :try/:endtry region suppresses the
+" conversion of errors to an exception and the immediate abortion on
+" error. When the commands executed by the :silent! themselves open
+" a new :try/:endtry region, conversion of errors to exception and
+" immediate abortion is switched on again - until the next :silent!
+" etc. The :silent! has the effect of setting v:errmsg to the error
+" message text (without displaying it) and continuing with the next
+" script line.
+"
+" When a command triggering autocommands is executed by :silent!
+" inside a :try/:endtry, the autocommand execution is not suppressed
+" on error.
+"
+" This test reuses the function MSG() from the previous test.
+"-------------------------------------------------------------------------------
+
+func Test_silent_exception()
+ XpathINIT
+ XloopINIT
+ let g:taken = ""
+
+ func S(n) abort
+ XloopNEXT
+ let g:taken = g:taken . "E" . a:n
+ let v:errmsg = ""
+ exec "asdf" . a:n
+
+ " Check that ":silent!" continues:
+ Xloop 'a'
+
+ " Check that ":silent!" sets "v:errmsg":
+ call assert_match("E492: Not an editor command", v:errmsg)
+ endfunc
+
+ func Foo()
+ while 1
+ try
+ try
+ let caught = 0
+ " This is not silent:
+ call S(3)
+ catch /^Vim:/
+ Xpath 'b'
+ let caught = 1
+ let errmsg3 = substitute(v:exception, '^Vim:', '', "")
+ silent! call S(4)
+ finally
+ call assert_equal(1, caught)
+ Xpath 'c'
+ call assert_match("E492: Not an editor command", errmsg3)
+ silent! call S(5)
+ " Break out of try conditionals that cover ":silent!". This also
+ " discards the aborting error when $VIMNOERRTHROW is non-zero.
+ break
+ endtry
+ catch /.*/
+ call assert_report('should not get here')
+ endtry
+ endwhile
+ " This is a double ":silent!" (see caller).
+ silent! call S(6)
+ endfunc
+
+ func Bar()
+ try
+ silent! call S(2)
+ silent! execute "call Foo() | call S(7)"
+ silent! call S(8)
+ endtry " normal end of try cond that covers ":silent!"
+ " This has a ":silent!" from the caller:
+ call S(9)
+ endfunc
+
+ silent! call S(1)
+ silent! call Bar()
+ silent! call S(10)
+
+ call assert_equal("E1E2E3E4E5E6E7E8E9E10", g:taken)
+
+ augroup TMP
+ au!
+ autocmd BufWritePost * Xpath 'd'
+ augroup END
+
+ Xpath 'e'
+ silent! write /i/m/p/o/s/s/i/b/l/e
+ Xpath 'f'
+
+ call assert_equal('a2a3ba5ca6a7a8a9a10a11edf', g:Xpath)
+
+ augroup TMP
+ au!
+ augroup END
+ augroup! TMP
+ delfunction S
+ delfunction Foo
+ delfunction Bar
+endfunc
+
+"-------------------------------------------------------------------------------
+" Test 64: Error exceptions after error, interrupt or :throw {{{1
+"
+" When an error occurs after an interrupt or a :throw but before
+" a matching :catch is reached, all following :catches of that try
+" block are ignored, but the error exception can be caught by the next
+" surrounding try conditional. Any previous error exception is
+" discarded. An error is ignored when there is a previous error that
+" has not been caught.
+"-------------------------------------------------------------------------------
+
+func Test_exception_after_error_1()
+ XpathINIT
+ while 1
+ try
+ try
+ Xpath 'a'
+ let caught = 0
+ while 1
+ if 1
+ " Missing :endif
+ endwhile " throw error exception
+ catch /^Vim(/
+ Xpath 'b'
+ let caught = 1
+ finally
+ Xpath 'c'
+ call assert_equal(1, caught)
+ endtry
+ catch /.*/
+ call assert_report('should not get here')
+ finally
+ Xpath 'd'
+ break
+ endtry
+ call assert_report('should not get here')
+ endwhile
+ call assert_equal('abcd', g:Xpath)
+endfunc
+
+func Test_exception_after_error_2()
+ XpathINIT
+ while 1
+ try
+ try
+ Xpath 'a'
+ let caught = 0
+ try
+ if 1
+ " Missing :endif
+ catch /.*/ " throw error exception
+ call assert_report('should not get here')
+ catch /.*/
+ call assert_report('should not get here')
+ endtry
+ catch /^Vim(/
+ Xpath 'b'
+ let caught = 1
+ finally
+ Xpath 'c'
+ call assert_equal(1, caught)
+ endtry
+ catch /.*/
+ call assert_report('should not get here')
+ finally
+ Xpath 'd'
+ break
+ endtry
+ call assert_report('should not get here')
+ endwhile
+ call assert_equal('abcd', g:Xpath)
+endfunc
+
+func Test_exception_after_error_3()
+ XpathINIT
+ while 1
+ try
+ try
+ let caught = 0
+ try
+ Xpath 'a'
+ call interrupt()
+ catch /do_not_catch/
+ call assert_report('should not get here')
+ if 1
+ " Missing :endif
+ catch /.*/ " throw error exception
+ call assert_report('should not get here')
+ catch /.*/
+ call assert_report('should not get here')
+ endtry
+ catch /^Vim(/
+ Xpath 'b'
+ let caught = 1
+ finally
+ Xpath 'c'
+ call assert_equal(1, caught)
+ endtry
+ catch /.*/
+ call assert_report('should not get here')
+ finally
+ Xpath 'd'
+ break
+ endtry
+ call assert_report('should not get here')
+ endwhile
+ call assert_equal('abcd', g:Xpath)
+endfunc
+
+func Test_exception_after_error_4()
+ XpathINIT
+ while 1
+ try
+ try
+ let caught = 0
+ try
+ Xpath 'a'
+ throw "x"
+ catch /do_not_catch/
+ call assert_report('should not get here')
+ if 1
+ " Missing :endif
+ catch /x/ " throw error exception
+ call assert_report('should not get here')
+ catch /.*/
+ call assert_report('should not get here')
+ endtry
+ catch /^Vim(/
+ Xpath 'b'
+ let caught = 1
+ finally
+ Xpath 'c'
+ call assert_equal(1, caught)
+ endtry
+ catch /.*/
+ call assert_report('should not get here')
+ finally
+ Xpath 'd'
+ break
+ endtry
+ call assert_report('should not get here')
+ endwhile
+ call assert_equal('abcd', g:Xpath)
+endfunc
+
+func Test_exception_after_error_5()
+ XpathINIT
+ while 1
+ try
+ try
+ let caught = 0
+ Xpath 'a'
+ endif " :endif without :if; throw error exception
+ if 1
+ " Missing :endif
+ catch /do_not_catch/ " ignore new error
+ call assert_report('should not get here')
+ catch /^Vim(endif):/
+ Xpath 'b'
+ let caught = 1
+ catch /^Vim(/
+ call assert_report('should not get here')
+ finally
+ Xpath 'c'
+ call assert_equal(1, caught)
+ endtry
+ catch /.*/
+ call assert_report('should not get here')
+ finally
+ Xpath 'd'
+ break
+ endtry
+ call assert_report('should not get here')
+ endwhile
+ call assert_equal('abcd', g:Xpath)
+endfunc
+
+"-------------------------------------------------------------------------------
+" Test 65: Errors in the /pattern/ argument of a :catch {{{1
+"
+" On an error in the /pattern/ argument of a :catch, the :catch does
+" not match. Any following :catches of the same :try/:endtry don't
+" match either. Finally clauses are executed.
+"-------------------------------------------------------------------------------
+
+func Test_catch_pattern_error()
+ CheckEnglish
+ XpathINIT
+
+ try
+ try
+ Xpath 'a'
+ throw "oops"
+ catch /^oops$/
+ Xpath 'b'
+ catch /\)/ " not checked; exception has already been caught
+ call assert_report('should not get here')
+ endtry
+ Xpath 'c'
+ catch /.*/
+ call assert_report('should not get here')
+ endtry
+ call assert_equal('abc', g:Xpath)
+
+ XpathINIT
+ func F()
+ try
+ try
+ try
+ Xpath 'a'
+ throw "ab"
+ catch /abc/ " does not catch
+ call assert_report('should not get here')
+ catch /\)/ " error; discards exception
+ call assert_report('should not get here')
+ catch /.*/ " not checked
+ call assert_report('should not get here')
+ finally
+ Xpath 'b'
+ endtry
+ call assert_report('should not get here')
+ catch /^ab$/ " checked, but original exception is discarded
+ call assert_report('should not get here')
+ catch /^Vim(catch):/
+ Xpath 'c'
+ call assert_match('Vim(catch):E475: Invalid argument:', v:exception)
+ finally
+ Xpath 'd'
+ endtry
+ Xpath 'e'
+ catch /.*/
+ call assert_report('should not get here')
+ endtry
+ Xpath 'f'
+ endfunc
+
+ call F()
+ call assert_equal('abcdef', g:Xpath)
+
+ delfunc F
+endfunc
+
+"-------------------------------------------------------------------------------
+" Test 66: Stop range :call on error, interrupt, or :throw {{{1
+"
+" When a function which is multiply called for a range since it
+" doesn't handle the range itself has an error in a command
+" dynamically enclosed by :try/:endtry or gets an interrupt or
+" executes a :throw, no more calls for the remaining lines in the
+" range are made. On an error in a command not dynamically enclosed
+" by :try/:endtry, the function is executed again for the remaining
+" lines in the range.
+"-------------------------------------------------------------------------------
+
+func Test_stop_range_on_error()
+ let test =<< trim [CODE]
+ let file = tempname()
+ exec "edit" file
+ call setline(1, ['line 1', 'line 2', 'line 3'])
+ let taken = ""
+ let expected = "G1EF1E(1)F1E(2)F1E(3)G2EF2E(1)G3IF3I(1)G4TF4T(1)G5AF5A(1)"
+
+ func F(reason, n) abort
+ let g:taken = g:taken .. "F" .. a:n ..
+ \ substitute(a:reason, '\(\l\).*', '\u\1', "") ..
+ \ "(" .. line(".") .. ")"
+
+ if a:reason == "error"
+ asdf
+ elseif a:reason == "interrupt"
+ call interrupt()
+ elseif a:reason == "throw"
+ throw "xyz"
+ elseif a:reason == "aborting error"
+ XloopNEXT
+ call assert_equal(g:taken, g:expected)
+ try
+ bwipeout!
+ call delete(g:file)
+ asdf
+ endtry
+ endif
+ endfunc
+
+ func G(reason, n)
+ let g:taken = g:taken .. "G" .. a:n ..
+ \ substitute(a:reason, '\(\l\).*', '\u\1', "")
+ 1,3call F(a:reason, a:n)
+ endfunc
+
+ Xpath 'a'
+ call G("error", 1)
+ try
+ Xpath 'b'
+ try
+ call G("error", 2)
+ call assert_report('should not get here')
+ finally
+ Xpath 'c'
+ try
+ call G("interrupt", 3)
+ call assert_report('should not get here')
+ finally
+ Xpath 'd'
+ try
+ call G("throw", 4)
+ call assert_report('should not get here')
+ endtry
+ endtry
+ endtry
+ catch /xyz/
+ Xpath 'e'
+ catch /.*/
+ call assert_report('should not get here')
+ endtry
+ Xpath 'f'
+ call G("aborting error", 5)
+ call assert_report('should not get here')
+ [CODE]
+ let verify =<< trim [CODE]
+ call assert_equal('abcdef', g:Xpath)
+ [CODE]
+ call RunInNewVim(test, verify)
+endfunc
+
+"-------------------------------------------------------------------------------
+" Test 67: :throw across :call command {{{1
+"
+" On a call command, an exception might be thrown when evaluating the
+" function name, during evaluation of the arguments, or when the
+" function is being executed. The exception can be caught by the
+" caller.
+"-------------------------------------------------------------------------------
+
+func THROW(x, n)
+ if a:n == 1
+ Xpath 'A'
+ elseif a:n == 2
+ Xpath 'B'
+ elseif a:n == 3
+ Xpath 'C'
+ endif
+ throw a:x
+endfunc
+
+func NAME(x, n)
+ if a:n == 1
+ call assert_report('should not get here')
+ elseif a:n == 2
+ Xpath 'D'
+ elseif a:n == 3
+ Xpath 'E'
+ elseif a:n == 4
+ Xpath 'F'
+ endif
+ return a:x
+endfunc
+
+func ARG(x, n)
+ if a:n == 1
+ call assert_report('should not get here')
+ elseif a:n == 2
+ call assert_report('should not get here')
+ elseif a:n == 3
+ Xpath 'G'
+ elseif a:n == 4
+ Xpath 'I'
+ endif
+ return a:x
+endfunc
+
+func Test_throw_across_call_cmd()
+ XpathINIT
+
+ func F(x, n)
+ if a:n == 2
+ call assert_report('should not get here')
+ elseif a:n == 4
+ Xpath 'a'
+ endif
+ endfunc
+
+ while 1
+ try
+ let v:errmsg = ""
+
+ while 1
+ try
+ Xpath 'b'
+ call {NAME(THROW("name", 1), 1)}(ARG(4711, 1), 1)
+ call assert_report('should not get here')
+ catch /^name$/
+ Xpath 'c'
+ catch /.*/
+ call assert_report('should not get here')
+ finally
+ call assert_equal("", v:errmsg)
+ let v:errmsg = ""
+ break
+ endtry
+ endwhile
+
+ while 1
+ try
+ Xpath 'd'
+ call {NAME("F", 2)}(ARG(THROW("arg", 2), 2), 2)
+ call assert_report('should not get here')
+ catch /^arg$/
+ Xpath 'e'
+ catch /.*/
+ call assert_report('should not get here')
+ finally
+ call assert_equal("", v:errmsg)
+ let v:errmsg = ""
+ break
+ endtry
+ endwhile
+
+ while 1
+ try
+ Xpath 'f'
+ call {NAME("THROW", 3)}(ARG("call", 3), 3)
+ call assert_report('should not get here')
+ catch /^call$/
+ Xpath 'g'
+ catch /^0$/ " default return value
+ call assert_report('should not get here')
+ catch /.*/
+ call assert_report('should not get here')
+ finally
+ call assert_equal("", v:errmsg)
+ let v:errmsg = ""
+ break
+ endtry
+ endwhile
+
+ while 1
+ try
+ Xpath 'h'
+ call {NAME("F", 4)}(ARG(4711, 4), 4)
+ Xpath 'i'
+ catch /.*/
+ call assert_report('should not get here')
+ finally
+ call assert_equal("", v:errmsg)
+ let v:errmsg = ""
+ break
+ endtry
+ endwhile
+
+ catch /^0$/ " default return value
+ call assert_report('should not get here')
+ catch /.*/
+ call assert_report('should not get here')
+ finally
+ call assert_equal("", v:errmsg)
+ let v:errmsg = ""
+ break
+ endtry
+ endwhile
+
+ call assert_equal('bAcdDBefEGCghFIai', g:Xpath)
+ delfunction F
+endfunc
+
+"-------------------------------------------------------------------------------
+" Test 68: :throw across function calls in expressions {{{1
+"
+" On a function call within an expression, an exception might be
+" thrown when evaluating the function name, during evaluation of the
+" arguments, or when the function is being executed. The exception
+" can be caught by the caller.
+"
+" This test reuses the functions THROW(), NAME(), and ARG() from the
+" previous test.
+"-------------------------------------------------------------------------------
+
+func Test_throw_across_call_expr()
+ XpathINIT
+
+ func F(x, n)
+ if a:n == 2
+ call assert_report('should not get here')
+ elseif a:n == 4
+ Xpath 'a'
+ endif
+ return a:x
+ endfunction
+
+ while 1
+ try
+ let error = 0
+ let v:errmsg = ""
+
+ while 1
+ try
+ Xpath 'b'
+ let var1 = {NAME(THROW("name", 1), 1)}(ARG(4711, 1), 1)
+ call assert_report('should not get here')
+ catch /^name$/
+ Xpath 'c'
+ catch /.*/
+ call assert_report('should not get here')
+ finally
+ call assert_equal("", v:errmsg)
+ let v:errmsg = ""
+ break
+ endtry
+ endwhile
+ call assert_true(!exists('var1'))
+
+ while 1
+ try
+ Xpath 'd'
+ let var2 = {NAME("F", 2)}(ARG(THROW("arg", 2), 2), 2)
+ call assert_report('should not get here')
+ catch /^arg$/
+ Xpath 'e'
+ catch /.*/
+ call assert_report('should not get here')
+ finally
+ call assert_equal("", v:errmsg)
+ let v:errmsg = ""
+ break
+ endtry
+ endwhile
+ call assert_true(!exists('var2'))
+
+ while 1
+ try
+ Xpath 'f'
+ let var3 = {NAME("THROW", 3)}(ARG("call", 3), 3)
+ call assert_report('should not get here')
+ catch /^call$/
+ Xpath 'g'
+ catch /^0$/ " default return value
+ call assert_report('should not get here')
+ catch /.*/
+ call assert_report('should not get here')
+ finally
+ call assert_equal("", v:errmsg)
+ let v:errmsg = ""
+ break
+ endtry
+ endwhile
+ call assert_true(!exists('var3'))
+
+ while 1
+ try
+ Xpath 'h'
+ let var4 = {NAME("F", 4)}(ARG(4711, 4), 4)
+ Xpath 'i'
+ catch /.*/
+ call assert_report('should not get here')
+ finally
+ call assert_equal("", v:errmsg)
+ let v:errmsg = ""
+ break
+ endtry
+ endwhile
+ call assert_true(exists('var4') && var4 == 4711)
+
+ catch /^0$/ " default return value
+ call assert_report('should not get here')
+ catch /.*/
+ call assert_report('should not get here')
+ finally
+ call assert_equal("", v:errmsg)
+ break
+ endtry
+ endwhile
+
+ call assert_equal('bAcdDBefEGCghFIai', g:Xpath)
+ delfunc F
+endfunc
+
+"-------------------------------------------------------------------------------
+" Test 76: Errors, interrupts, :throw during expression evaluation {{{1
+"
+" When a function call made during expression evaluation is aborted
+" due to an error inside a :try/:endtry region or due to an interrupt
+" or a :throw, the expression evaluation is aborted as well. No
+" message is displayed for the cancelled expression evaluation. On an
+" error not inside :try/:endtry, the expression evaluation continues.
+"-------------------------------------------------------------------------------
+
+func Test_expr_eval_error()
+ let test =<< trim [CODE]
+ let taken = ""
+
+ func ERR(n)
+ let g:taken = g:taken .. "E" .. a:n
+ asdf
+ endfunc
+
+ func ERRabort(n) abort
+ let g:taken = g:taken .. "A" .. a:n
+ asdf
+ endfunc " returns -1; may cause follow-up msg for illegal var/func name
+
+ func WRAP(n, arg)
+ let g:taken = g:taken .. "W" .. a:n
+ let g:saved_errmsg = v:errmsg
+ return arg
+ endfunc
+
+ func INT(n)
+ let g:taken = g:taken .. "I" .. a:n
+ call interrupt()
+ endfunc
+
+ func THR(n)
+ let g:taken = g:taken .. "T" .. a:n
+ throw "should not be caught"
+ endfunc
+
+ func CONT(n)
+ let g:taken = g:taken .. "C" .. a:n
+ endfunc
+
+ func MSG(n)
+ let g:taken = g:taken .. "M" .. a:n
+ let errmsg = (a:n >= 37 && a:n <= 44) ? g:saved_errmsg : v:errmsg
+ let msgptn = (a:n >= 10 && a:n <= 27) ? "^$" : "asdf"
+ call assert_match(msgptn, errmsg)
+ let v:errmsg = ""
+ let g:saved_errmsg = ""
+ endfunc
+
+ let v:errmsg = ""
+
+ try
+ let t = 1
+ while t <= 9
+ Xloop 'a'
+ try
+ if t == 1
+ let v{ERR(t) + CONT(t)} = 0
+ elseif t == 2
+ let v{ERR(t) + CONT(t)}
+ elseif t == 3
+ let var = exists('v{ERR(t) + CONT(t)}')
+ elseif t == 4
+ unlet v{ERR(t) + CONT(t)}
+ elseif t == 5
+ function F{ERR(t) + CONT(t)}()
+ endfunction
+ elseif t == 6
+ function F{ERR(t) + CONT(t)}
+ elseif t == 7
+ let var = exists('*F{ERR(t) + CONT(t)}')
+ elseif t == 8
+ delfunction F{ERR(t) + CONT(t)}
+ elseif t == 9
+ let var = ERR(t) + CONT(t)
+ endif
+ catch /asdf/
+ " v:errmsg is not set when the error message is converted to an
+ " exception. Set it to the original error message.
+ let v:errmsg = substitute(v:exception, '^Vim:', '', "")
+ catch /^Vim\((\a\+)\)\=:/
+ " An error exception has been thrown after the original error.
+ let v:errmsg = ""
+ finally
+ call MSG(t)
+ let t = t + 1
+ XloopNEXT
+ continue " discard an aborting error
+ endtry
+ endwhile
+ catch /.*/
+ call assert_report('should not get here')
+ endtry
+
+ try
+ let t = 10
+ while t <= 18
+ Xloop 'b'
+ try
+ if t == 10
+ let v{INT(t) + CONT(t)} = 0
+ elseif t == 11
+ let v{INT(t) + CONT(t)}
+ elseif t == 12
+ let var = exists('v{INT(t) + CONT(t)}')
+ elseif t == 13
+ unlet v{INT(t) + CONT(t)}
+ elseif t == 14
+ function F{INT(t) + CONT(t)}()
+ endfunction
+ elseif t == 15
+ function F{INT(t) + CONT(t)}
+ elseif t == 16
+ let var = exists('*F{INT(t) + CONT(t)}')
+ elseif t == 17
+ delfunction F{INT(t) + CONT(t)}
+ elseif t == 18
+ let var = INT(t) + CONT(t)
+ endif
+ catch /^Vim\((\a\+)\)\=:\(Interrupt\)\@!/
+ " An error exception has been triggered after the interrupt.
+ let v:errmsg = substitute(v:exception, '^Vim\((\a\+)\)\=:', '', "")
+ finally
+ call MSG(t)
+ let t = t + 1
+ XloopNEXT
+ continue " discard interrupt
+ endtry
+ endwhile
+ catch /.*/
+ call assert_report('should not get here')
+ endtry
+
+ try
+ let t = 19
+ while t <= 27
+ Xloop 'c'
+ try
+ if t == 19
+ let v{THR(t) + CONT(t)} = 0
+ elseif t == 20
+ let v{THR(t) + CONT(t)}
+ elseif t == 21
+ let var = exists('v{THR(t) + CONT(t)}')
+ elseif t == 22
+ unlet v{THR(t) + CONT(t)}
+ elseif t == 23
+ function F{THR(t) + CONT(t)}()
+ endfunction
+ elseif t == 24
+ function F{THR(t) + CONT(t)}
+ elseif t == 25
+ let var = exists('*F{THR(t) + CONT(t)}')
+ elseif t == 26
+ delfunction F{THR(t) + CONT(t)}
+ elseif t == 27
+ let var = THR(t) + CONT(t)
+ endif
+ catch /^Vim\((\a\+)\)\=:/
+ " An error exception has been triggered after the :throw.
+ let v:errmsg = substitute(v:exception, '^Vim\((\a\+)\)\=:', '', "")
+ finally
+ call MSG(t)
+ let t = t + 1
+ XloopNEXT
+ continue " discard exception
+ endtry
+ endwhile
+ catch /.*/
+ call assert_report('should not get here')
+ endtry
+
+ let v{ERR(28) + CONT(28)} = 0
+ call MSG(28)
+ let v{ERR(29) + CONT(29)}
+ call MSG(29)
+ let var = exists('v{ERR(30) + CONT(30)}')
+ call MSG(30)
+ unlet v{ERR(31) + CONT(31)}
+ call MSG(31)
+ function F{ERR(32) + CONT(32)}()
+ endfunction
+ call MSG(32)
+ function F{ERR(33) + CONT(33)}
+ call MSG(33)
+ let var = exists('*F{ERR(34) + CONT(34)}')
+ call MSG(34)
+ delfunction F{ERR(35) + CONT(35)}
+ call MSG(35)
+ let var = ERR(36) + CONT(36)
+ call MSG(36)
+
+ let saved_errmsg = ""
+
+ let v{WRAP(37, ERRabort(37)) + CONT(37)} = 0
+ call MSG(37)
+ let v{WRAP(38, ERRabort(38)) + CONT(38)}
+ call MSG(38)
+ let var = exists('v{WRAP(39, ERRabort(39)) + CONT(39)}')
+ call MSG(39)
+ unlet v{WRAP(40, ERRabort(40)) + CONT(40)}
+ call MSG(40)
+ function F{WRAP(41, ERRabort(41)) + CONT(41)}()
+ endfunction
+ call MSG(41)
+ function F{WRAP(42, ERRabort(42)) + CONT(42)}
+ call MSG(42)
+ let var = exists('*F{WRAP(43, ERRabort(43)) + CONT(43)}')
+ call MSG(43)
+ delfunction F{WRAP(44, ERRabort(44)) + CONT(44)}
+ call MSG(44)
+ let var = ERRabort(45) + CONT(45)
+ call MSG(45)
+ Xpath 'd'
+
+ let expected = ""
+ \ .. "E1M1E2M2E3M3E4M4E5M5E6M6E7M7E8M8E9M9"
+ \ .. "I10M10I11M11I12M12I13M13I14M14I15M15I16M16I17M17I18M18"
+ \ .. "T19M19T20M20T21M21T22M22T23M23T24M24T25M25T26M26T27M27"
+ \ .. "E28C28M28E29C29M29E30C30M30E31C31M31E32C32M32E33C33M33"
+ \ .. "E34C34M34E35C35M35E36C36M36"
+ \ .. "A37W37C37M37A38W38C38M38A39W39C39M39A40W40C40M40A41W41C41M41"
+ \ .. "A42W42C42M42A43W43C43M43A44W44C44M44A45C45M45"
+ call assert_equal(expected, taken)
+ [CODE]
+ let verify =<< trim [CODE]
+ let expected = "a1a2a3a4a5a6a7a8a9"
+ \ .. "b10b11b12b13b14b15b16b17b18"
+ \ .. "c19c20c21c22c23c24c25c26c27d"
+ call assert_equal(expected, g:Xpath)
+ [CODE]
+ call RunInNewVim(test, verify)
+endfunc
+
+"-------------------------------------------------------------------------------
+" Test 77: Errors, interrupts, :throw in name{brace-expression} {{{1
+"
+" When a function call made during evaluation of an expression in
+" braces as part of a function name after ":function" is aborted due
+" to an error inside a :try/:endtry region or due to an interrupt or
+" a :throw, the expression evaluation is aborted as well, and the
+" function definition is ignored, skipping all commands to the
+" ":endfunction". On an error not inside :try/:endtry, the expression
+" evaluation continues and the function gets defined, and can be
+" called and deleted.
+"-------------------------------------------------------------------------------
+func Test_brace_expr_error()
+ let test =<< trim [CODE]
+ func ERR() abort
+ Xloop 'a'
+ asdf
+ endfunc " returns -1
+
+ func OK()
+ Xloop 'b'
+ let v:errmsg = ""
+ return 0
+ endfunc
+
+ let v:errmsg = ""
+
+ Xpath 'c'
+ func F{1 + ERR() + OK()}(arg)
+ " F0 should be defined.
+ if exists("a:arg") && a:arg == "calling"
+ Xpath 'd'
+ else
+ call assert_report('should not get here')
+ endif
+ endfunction
+ call assert_equal("", v:errmsg)
+ XloopNEXT
+
+ Xpath 'e'
+ call F{1 + ERR() + OK()}("calling")
+ call assert_equal("", v:errmsg)
+ XloopNEXT
+
+ Xpath 'f'
+ delfunction F{1 + ERR() + OK()}
+ call assert_equal("", v:errmsg)
+ XloopNEXT
+
+ try
+ while 1
+ try
+ Xpath 'g'
+ func G{1 + ERR() + OK()}(arg)
+ " G0 should not be defined, and the function body should be
+ " skipped.
+ call assert_report('should not get here')
+ " Use an unmatched ":finally" to check whether the body is
+ " skipped when an error occurs in ERR(). This works whether or
+ " not the exception is converted to an exception.
+ finally
+ call assert_report('should not get here')
+ endtry
+ try
+ call assert_report('should not get here')
+ endfunction
+
+ call assert_report('should not get here')
+ catch /asdf/
+ " Jumped to when the function is not defined and the body is
+ " skipped.
+ Xpath 'h'
+ catch /.*/
+ call assert_report('should not get here')
+ finally
+ Xpath 'i'
+ break
+ endtry " jumped to when the body is not skipped
+ endwhile
+ catch /.*/
+ call assert_report('should not get here')
+ endtry
+ [CODE]
+ let verify =<< trim [CODE]
+ call assert_equal('ca1b1ea2b2dfa3b3ga4hi', g:Xpath)
+ [CODE]
+ call RunInNewVim(test, verify)
+endfunc
+
+"-------------------------------------------------------------------------------
+" Test 78: Messages on parsing errors in expression evaluation {{{1
+"
+" When an expression evaluation detects a parsing error, an error
+" message is given and converted to an exception, and the expression
+" evaluation is aborted.
+"-------------------------------------------------------------------------------
+func Test_expr_eval_error_msg()
+ CheckEnglish
+
+ let test =<< trim [CODE]
+ let taken = ""
+
+ func F(n)
+ let g:taken = g:taken . "F" . a:n
+ endfunc
+
+ func MSG(n, enr, emsg)
+ let g:taken = g:taken . "M" . a:n
+ call assert_match('^' .. a:enr .. ':', v:errmsg)
+ call assert_match(a:emsg, v:errmsg)
+ endfunc
+
+ func CONT(n)
+ let g:taken = g:taken . "C" . a:n
+ endfunc
+
+ let v:errmsg = ""
+ try
+ let t = 1
+ while t <= 14
+ let g:taken = g:taken . "T" . t
+ let v:errmsg = ""
+ try
+ if t == 1
+ let v{novar + CONT(t)} = 0
+ elseif t == 2
+ let v{novar + CONT(t)}
+ elseif t == 3
+ let var = exists('v{novar + CONT(t)}')
+ elseif t == 4
+ unlet v{novar + CONT(t)}
+ elseif t == 5
+ function F{novar + CONT(t)}()
+ endfunction
+ elseif t == 6
+ function F{novar + CONT(t)}
+ elseif t == 7
+ let var = exists('*F{novar + CONT(t)}')
+ elseif t == 8
+ delfunction F{novar + CONT(t)}
+ elseif t == 9
+ echo novar + CONT(t)
+ elseif t == 10
+ echo v{novar + CONT(t)}
+ elseif t == 11
+ echo F{novar + CONT(t)}
+ elseif t == 12
+ let var = novar + CONT(t)
+ elseif t == 13
+ let var = v{novar + CONT(t)}
+ elseif t == 14
+ let var = F{novar + CONT(t)}()
+ endif
+ catch /^Vim\((\a\+)\)\=:/
+ Xloop 'a'
+ " v:errmsg is not set when the error message is converted to an
+ " exception. Set it to the original error message.
+ let v:errmsg = substitute(v:exception, '^Vim\((\a\+)\)\=:', '', "")
+ finally
+ Xloop 'b'
+ if t <= 8 && t != 3 && t != 7
+ call MSG(t, 'E475', 'Invalid argument\>')
+ else
+ call MSG(t, 'E121', "Undefined variable")
+ endif
+ let t = t + 1
+ XloopNEXT
+ continue " discard an aborting error
+ endtry
+ endwhile
+ catch /.*/
+ call assert_report('should not get here')
+ endtry
+
+ func T(n, expr, enr, emsg)
+ try
+ let g:taken = g:taken . "T" . a:n
+ let v:errmsg = ""
+ try
+ execute "let var = " . a:expr
+ catch /^Vim\((\a\+)\)\=:/
+ Xloop 'c'
+ " v:errmsg is not set when the error message is converted to an
+ " exception. Set it to the original error message.
+ let v:errmsg = substitute(v:exception, '^Vim\((\a\+)\)\=:', '', "")
+ finally
+ Xloop 'd'
+ call MSG(a:n, a:enr, a:emsg)
+ XloopNEXT
+ " Discard an aborting error:
+ return
+ endtry
+ catch /.*/
+ call assert_report('should not get here')
+ endtry
+ endfunc
+
+ call T(15, 'Nofunc() + CONT(15)', 'E117', "Unknown function")
+ call T(16, 'F(1 2 + CONT(16))', 'E116', "Invalid arguments")
+ call T(17, 'F(1, 2) + CONT(17)', 'E118', "Too many arguments")
+ call T(18, 'F() + CONT(18)', 'E119', "Not enough arguments")
+ call T(19, '{(1} + CONT(19)', 'E110', "Missing ')'")
+ call T(20, '("abc"[1) + CONT(20)', 'E111', "Missing ']'")
+ call T(21, '(1 +) + CONT(21)', 'E15', "Invalid expression")
+ call T(22, '1 2 + CONT(22)', 'E15', "Invalid expression")
+ call T(23, '(1 ? 2) + CONT(23)', 'E109', "Missing ':' after '?'")
+ call T(24, '("abc) + CONT(24)', 'E114', "Missing quote")
+ call T(25, "('abc) + CONT(25)", 'E115', "Missing quote")
+ call T(26, '& + CONT(26)', 'E112', "Option name missing")
+ call T(27, '&asdf + CONT(27)', 'E113', "Unknown option")
+
+ let expected = ""
+ \ .. "T1M1T2M2T3M3T4M4T5M5T6M6T7M7T8M8T9M9T10M10T11M11T12M12T13M13T14M14"
+ \ .. "T15M15T16M16T17M17T18M18T19M19T20M20T21M21T22M22T23M23T24M24T25M25"
+ \ .. "T26M26T27M27"
+
+ call assert_equal(expected, taken)
+ [CODE]
+ let verify =<< trim [CODE]
+ let expected = "a1b1a2b2a3b3a4b4a5b5a6b6a7b7a8b8a9b9a10b10a11b11a12b12"
+ \ .. "a13b13a14b14c15d15c16d16c17d17c18d18c19d19c20d20"
+ \ .. "c21d21c22d22c23d23c24d24c25d25c26d26c27d27"
+ call assert_equal(expected, g:Xpath)
+ [CODE]
+ call RunInNewVim(test, verify)
+endfunc
+
+"-------------------------------------------------------------------------------
+" Test 79: Throwing one of several errors for the same command {{{1
+"
+" When several errors appear in a row (for instance during expression
+" evaluation), the first as the most specific one is used when
+" throwing an error exception. If, however, a syntax error is
+" detected afterwards, this one is used for the error exception.
+" On a syntax error, the next command is not executed, on a normal
+" error, however, it is (relevant only in a function without the
+" "abort" flag). v:errmsg is not set.
+"
+" If throwing error exceptions is configured off, v:errmsg is always
+" set to the latest error message, that is, to the more general
+" message or the syntax error, respectively.
+"-------------------------------------------------------------------------------
+func Test_throw_multi_error()
+ CheckEnglish
+
+ let test =<< trim [CODE]
+ func NEXT(cmd)
+ exec a:cmd . " | Xloop 'a'"
+ endfun
+
+ call NEXT('echo novar') " (checks nextcmd)
+ XloopNEXT
+ call NEXT('let novar #') " (skips nextcmd)
+ XloopNEXT
+ call NEXT('unlet novar #') " (skips nextcmd)
+ XloopNEXT
+ call NEXT('let {novar}') " (skips nextcmd)
+ XloopNEXT
+ call NEXT('unlet{ novar}') " (skips nextcmd)
+
+ call assert_equal('a1', g:Xpath)
+ XpathINIT
+ XloopINIT
+
+ func EXEC(cmd)
+ exec a:cmd
+ endfunc
+
+ try
+ while 1 " dummy loop
+ try
+ let v:errmsg = ""
+ call EXEC('echo novar') " normal error
+ catch /^Vim\((\a\+)\)\=:/
+ Xpath 'b'
+ call assert_match('E121: Undefined variable: novar', v:exception)
+ finally
+ Xpath 'c'
+ call assert_equal("", v:errmsg)
+ break
+ endtry
+ endwhile
+
+ Xpath 'd'
+ let cmd = "let"
+ while cmd != ""
+ try
+ let v:errmsg = ""
+ call EXEC(cmd . ' novar #') " normal plus syntax error
+ catch /^Vim\((\a\+)\)\=:/
+ Xloop 'e'
+ call assert_match('E488: Trailing characters', v:exception)
+ finally
+ Xloop 'f'
+ call assert_equal("", v:errmsg)
+ if cmd == "let"
+ let cmd = "unlet"
+ else
+ let cmd = ""
+ endif
+ XloopNEXT
+ continue
+ endtry
+ endwhile
+
+ Xpath 'g'
+ let cmd = "let"
+ while cmd != ""
+ try
+ let v:errmsg = ""
+ call EXEC(cmd . ' {novar}') " normal plus syntax error
+ catch /^Vim\((\a\+)\)\=:/
+ Xloop 'h'
+ call assert_match('E475: Invalid argument: {novar}', v:exception)
+ finally
+ Xloop 'i'
+ call assert_equal("", v:errmsg)
+ if cmd == "let"
+ let cmd = "unlet"
+ else
+ let cmd = ""
+ endif
+ XloopNEXT
+ continue
+ endtry
+ endwhile
+ catch /.*/
+ call assert_report('should not get here')
+ endtry
+ Xpath 'j'
+ [CODE]
+ let verify =<< trim [CODE]
+ call assert_equal('bcde1f1e2f2gh3i3h4i4j', g:Xpath)
+ [CODE]
+ call RunInNewVim(test, verify)
+endfunc
+
+"-------------------------------------------------------------------------------
+" Test 80: Syntax error in expression for illegal :elseif {{{1
+"
+" If there is a syntax error in the expression after an illegal
+" :elseif, an error message is given (or an error exception thrown)
+" for the illegal :elseif rather than the expression error.
+"-------------------------------------------------------------------------------
+func Test_if_syntax_error()
+ CheckEnglish
+
+ let test =<< trim [CODE]
+ let v:errmsg = ""
+ if 0
+ else
+ elseif 1 ||| 2
+ endif
+ Xpath 'a'
+ call assert_match('E584: :elseif after :else', v:errmsg)
+
+ let v:errmsg = ""
+ if 1
+ else
+ elseif 1 ||| 2
+ endif
+ Xpath 'b'
+ call assert_match('E584: :elseif after :else', v:errmsg)
+
+ let v:errmsg = ""
+ elseif 1 ||| 2
+ Xpath 'c'
+ call assert_match('E582: :elseif without :if', v:errmsg)
+
+ let v:errmsg = ""
+ while 1
+ elseif 1 ||| 2
+ endwhile
+ Xpath 'd'
+ call assert_match('E582: :elseif without :if', v:errmsg)
+
+ while 1
+ try
+ try
+ let v:errmsg = ""
+ if 0
+ else
+ elseif 1 ||| 2
+ endif
+ catch /^Vim\((\a\+)\)\=:/
+ Xpath 'e'
+ call assert_match('E584: :elseif after :else', v:exception)
+ finally
+ Xpath 'f'
+ call assert_equal("", v:errmsg)
+ endtry
+ catch /.*/
+ call assert_report('should not get here')
+ finally
+ Xpath 'g'
+ break
+ endtry
+ endwhile
+
+ while 1
+ try
+ try
+ let v:errmsg = ""
+ if 1
+ else
+ elseif 1 ||| 2
+ endif
+ catch /^Vim\((\a\+)\)\=:/
+ Xpath 'h'
+ call assert_match('E584: :elseif after :else', v:exception)
+ finally
+ Xpath 'i'
+ call assert_equal("", v:errmsg)
+ endtry
+ catch /.*/
+ call assert_report('should not get here')
+ finally
+ Xpath 'j'
+ break
+ endtry
+ endwhile
+
+ while 1
+ try
+ try
+ let v:errmsg = ""
+ elseif 1 ||| 2
+ catch /^Vim\((\a\+)\)\=:/
+ Xpath 'k'
+ call assert_match('E582: :elseif without :if', v:exception)
+ finally
+ Xpath 'l'
+ call assert_equal("", v:errmsg)
+ endtry
+ catch /.*/
+ call assert_report('should not get here')
+ finally
+ Xpath 'm'
+ break
+ endtry
+ endwhile
+
+ while 1
+ try
+ try
+ let v:errmsg = ""
+ while 1
+ elseif 1 ||| 2
+ endwhile
+ catch /^Vim\((\a\+)\)\=:/
+ Xpath 'n'
+ call assert_match('E582: :elseif without :if', v:exception)
+ finally
+ Xpath 'o'
+ call assert_equal("", v:errmsg)
+ endtry
+ catch /.*/
+ call assert_report('should not get here')
+ finally
+ Xpath 'p'
+ break
+ endtry
+ endwhile
+ Xpath 'q'
+ [CODE]
+ let verify =<< trim [CODE]
+ call assert_equal('abcdefghijklmnopq', g:Xpath)
+ [CODE]
+ call RunInNewVim(test, verify)
+endfunc
+
+"-------------------------------------------------------------------------------
+" Test 81: Discarding exceptions after an error or interrupt {{{1
+"
+" When an exception is thrown from inside a :try conditional without
+" :catch and :finally clauses and an error or interrupt occurs before
+" the :endtry is reached, the exception is discarded.
+"-------------------------------------------------------------------------------
+
+func Test_discard_exception_after_error_1()
+ let test =<< trim [CODE]
+ try
+ Xpath 'a'
+ try
+ Xpath 'b'
+ throw "arrgh"
+ call assert_report('should not get here')
+ if 1
+ call assert_report('should not get here')
+ " error after :throw: missing :endif
+ endtry
+ call assert_report('should not get here')
+ catch /arrgh/
+ call assert_report('should not get here')
+ endtry
+ call assert_report('should not get here')
+ [CODE]
+ let verify =<< trim [CODE]
+ call assert_equal('ab', g:Xpath)
+ [CODE]
+ call RunInNewVim(test, verify)
+endfunc
+
+" TODO: Not able inject an interrupt after throwing an exception
+func Disable_Test_discard_exception_after_error_2()
+ let test =<< trim [CODE]
+ try
+ Xpath 'a'
+ try
+ Xpath 'b'
+ throw "arrgh"
+ call interrupt() " FIXME: throw is not interrupted here
+ call assert_report('should not get here')
+ endtry
+ call assert_report('should not get here')
+ catch /arrgh/
+ call assert_report('should not get here')
+ endtry
+ call assert_report('should not get here')
+ [CODE]
+ let verify =<< trim [CODE]
+ call assert_equal('ab', g:Xpath)
+ [CODE]
+ call RunInNewVim(test, verify)
+endfunc
+
"-------------------------------------------------------------------------------
" Test 87 using (expr) ? funcref : funcref {{{1
"
@@ -1443,7 +6241,7 @@ endfunc
" Undefined behavior was detected by ubsan with line continuation
" after an empty line.
"-------------------------------------------------------------------------------
-func Test_script_emty_line_continuation()
+func Test_script_empty_line_continuation()
\
endfunc
@@ -1707,9 +6505,7 @@ endfunc
" Test for deep nesting of if/for/while/try statements {{{1
func Test_deep_nest()
- if !CanRunVimInTerminal()
- throw 'Skipped: cannot run vim in terminal'
- endif
+ CheckRunVimInTerminal
let lines =<< trim [SCRIPT]
" Deep nesting of if ... endif
@@ -1812,6 +6608,7 @@ func Test_float_conversion_errors()
endif
endfunc
+" invalid function names {{{1
func Test_invalid_function_names()
" function name not starting with capital
let caught_e128 = 0
@@ -1872,7 +6669,7 @@ func Test_invalid_function_names()
call delete('Xscript')
endfunc
-" substring and variable name
+" substring and variable name {{{1
func Test_substring_var()
let str = 'abcdef'
let n = 3
@@ -1892,6 +6689,20 @@ func Test_substring_var()
unlet b:nn
endfunc
+" Test using s: with a typed command {{{1
+func Test_typed_script_var()
+ CheckRunVimInTerminal
+
+ let buf = RunVimInTerminal('', {'rows': 6})
+
+ " Deep nesting of if ... endif
+ call term_sendkeys(buf, ":echo get(s:, 'foo', 'x')\n")
+ call TermWait(buf)
+ call WaitForAssert({-> assert_match('^E116:', term_getline(buf, 5))})
+
+ call StopVimInTerminal(buf)
+endfunc
+
func Test_for_over_string()
let res = ''
for c in 'aéc̀d'
diff --git a/src/nvim/testdir/test_virtualedit.vim b/src/nvim/testdir/test_virtualedit.vim
index e712896562..2bf8c3fc77 100644
--- a/src/nvim/testdir/test_virtualedit.vim
+++ b/src/nvim/testdir/test_virtualedit.vim
@@ -80,6 +80,10 @@ func Test_edit_change()
call setline(1, "\t⒌")
normal Cx
call assert_equal('x', getline(1))
+ " Do a visual block change
+ call setline(1, ['a', 'b', 'c'])
+ exe "normal gg3l\<C-V>2jcx"
+ call assert_equal(['a x', 'b x', 'c x'], getline(1, '$'))
bwipe!
set virtualedit=
endfunc
@@ -289,6 +293,16 @@ func Test_replace_after_eol()
call append(0, '"r"')
normal gg$5lrxa
call assert_equal('"r" x', getline(1))
+ " visual block replace
+ %d _
+ call setline(1, ['a', '', 'b'])
+ exe "normal 2l\<C-V>2jrx"
+ call assert_equal(['a x', ' x', 'b x'], getline(1, '$'))
+ " visual characterwise selection replace after eol
+ %d _
+ call setline(1, 'a')
+ normal 4lv2lrx
+ call assert_equal('a xxx', getline(1))
bwipe!
set virtualedit=
endfunc
@@ -346,6 +360,48 @@ func Test_yank_paste_small_del_reg()
set virtualedit=
endfunc
+" Test for delete that breaks a tab into spaces
+func Test_delete_break_tab()
+ new
+ call setline(1, "one\ttwo")
+ set virtualedit=all
+ normal v3ld
+ call assert_equal(' two', getline(1))
+ set virtualedit&
+ close!
+endfunc
+
+" Test for using <BS>, <C-W> and <C-U> in virtual edit mode
+" to erase character, word and line.
+func Test_ve_backspace()
+ new
+ call setline(1, 'sample')
+ set virtualedit=all
+ set backspace=indent,eol,start
+ exe "normal 15|i\<BS>\<BS>"
+ call assert_equal([0, 1, 7, 5], getpos('.'))
+ exe "normal 15|i\<C-W>"
+ call assert_equal([0, 1, 6, 0], getpos('.'))
+ exe "normal 15|i\<C-U>"
+ call assert_equal([0, 1, 1, 0], getpos('.'))
+ set backspace&
+ set virtualedit&
+ close!
+endfunc
+
+" Test for delete (x) on EOL character and after EOL
+func Test_delete_past_eol()
+ new
+ call setline(1, "ab")
+ set virtualedit=all
+ exe "normal 2lx"
+ call assert_equal('ab', getline(1))
+ exe "normal 10lx"
+ call assert_equal('ab', getline(1))
+ set virtualedit&
+ bw!
+endfunc
+
" After calling s:TryVirtualeditReplace(), line 1 will contain one of these
" two strings, depending on whether virtual editing is on or off.
let s:result_ve_on = 'a x'
diff --git a/src/nvim/testdir/test_visual.vim b/src/nvim/testdir/test_visual.vim
index a9c057088d..712ea343ed 100644
--- a/src/nvim/testdir/test_visual.vim
+++ b/src/nvim/testdir/test_visual.vim
@@ -225,6 +225,15 @@ func Test_virtual_replace()
exe "normal iabcdefghijklmnopqrst\<Esc>0gRAB\tIJKLMNO\tQR"
call assert_equal(['AB......CDEFGHI.Jkl',
\ 'AB IJKLMNO QRst'], getline(12, 13))
+
+ " Test inserting Tab with 'noexpandtab' and 'softabstop' set to 4
+ %d
+ call setline(1, 'aaaaaaaaaaaaa')
+ set softtabstop=4
+ exe "normal gggR\<Tab>\<Tab>x"
+ call assert_equal("\txaaaa", getline(1))
+ set softtabstop&
+
enew!
set noai bs&vim
if exists('save_t_kD')
diff --git a/src/nvim/testdir/test_winbuf_close.vim b/src/nvim/testdir/test_winbuf_close.vim
index f4878c2397..643c1068bd 100644
--- a/src/nvim/testdir/test_winbuf_close.vim
+++ b/src/nvim/testdir/test_winbuf_close.vim
@@ -115,7 +115,7 @@ func Test_winbuf_close()
call assert_equal('Xtest2', bufname('%'))
quit!
call assert_equal('Xtest3', bufname('%'))
- call assert_fails('silent! quit!', 'E162')
+ call assert_fails('silent! quit!', 'E37')
call assert_equal('Xtest1', bufname('%'))
call delete('Xtest1')
diff --git a/src/nvim/testdir/test_window_cmd.vim b/src/nvim/testdir/test_window_cmd.vim
index 902a3791d4..20564fed66 100644
--- a/src/nvim/testdir/test_window_cmd.vim
+++ b/src/nvim/testdir/test_window_cmd.vim
@@ -501,10 +501,13 @@ func Test_win_screenpos()
call assert_equal([1, 32], win_screenpos(2))
call assert_equal([12, 1], win_screenpos(3))
call assert_equal([0, 0], win_screenpos(4))
+ call assert_fails('let l = win_screenpos([])', 'E745:')
only
endfunc
func Test_window_jump_tag()
+ CheckFeature quickfix
+
help
/iccf
call assert_match('^|iccf|', getline('.'))
@@ -542,6 +545,7 @@ func Test_window_newtab()
call assert_equal(2, tabpagenr('$'))
call assert_equal(['Xb', 'Xa'], map(tabpagebuflist(1), 'bufname(v:val)'))
call assert_equal(['Xc' ], map(2->tabpagebuflist(), 'bufname(v:val)'))
+ call assert_equal(['Xc' ], map(tabpagebuflist(), 'bufname(v:val)'))
%bw!
endfunc
@@ -733,6 +737,7 @@ func Test_relative_cursor_position_in_one_line_window()
only!
bwipe!
+ call assert_fails('call winrestview(v:_null_dict)', 'E474:')
endfunc
func Test_relative_cursor_position_after_move_and_resize()
@@ -909,6 +914,10 @@ func Test_winnr()
call assert_fails("echo winnr('ll')", 'E15:')
call assert_fails("echo winnr('5')", 'E15:')
call assert_equal(4, winnr('0h'))
+ call assert_fails("let w = winnr([])", 'E730:')
+ call assert_equal('unknown', win_gettype(-1))
+ call assert_equal(-1, winheight(-1))
+ call assert_equal(-1, winwidth(-1))
tabnew
call assert_equal(8, tabpagewinnr(1, 'j'))
@@ -929,9 +938,12 @@ func Test_winrestview()
call assert_equal(view, winsaveview())
bwipe!
+ call assert_fails('call winrestview(v:_null_dict)', 'E474:')
endfunc
func Test_win_splitmove()
+ CheckFeature quickfix
+
edit a
leftabove split b
leftabove vsplit c
@@ -957,6 +969,7 @@ func Test_win_splitmove()
call assert_equal(bufname(winbufnr(2)), 'b')
call assert_equal(bufname(winbufnr(3)), 'a')
call assert_equal(bufname(winbufnr(4)), 'd')
+ call assert_fails('call win_splitmove(winnr(), winnr("k"), v:_null_dict)', 'E474:')
only | bd
call assert_fails('call win_splitmove(winnr(), 123)', 'E957:')
@@ -1129,6 +1142,18 @@ func Test_split_cmds_with_no_room()
call Run_noroom_for_newwindow_test('v')
endfunc
+" Test for various wincmd failures
+func Test_wincmd_fails()
+ only!
+ call assert_beeps("normal \<C-W>w")
+ call assert_beeps("normal \<C-W>p")
+ call assert_beeps("normal \<C-W>gk")
+ call assert_beeps("normal \<C-W>r")
+ call assert_beeps("normal \<C-W>K")
+ call assert_beeps("normal \<C-W>H")
+ call assert_beeps("normal \<C-W>2gt")
+endfunc
+
func Test_window_resize()
" Vertical :resize (absolute, relative, min and max size).
vsplit
@@ -1214,7 +1239,7 @@ endfunc
" Test for jumping to a vertical/horizontal neighbor window based on the
" current cursor position
-func Test_window_goto_neightbor()
+func Test_window_goto_neighbor()
%bw!
" Vertical window movement
@@ -1393,17 +1418,20 @@ func Test_win_move_separator()
call assert_equal(w0, winwidth(0))
call assert_true(win_move_separator(0, -1))
call assert_equal(w0, winwidth(0))
+
" check that win_move_separator doesn't error with offsets beyond moving
" possibility
call assert_true(win_move_separator(id, 5000))
call assert_true(winwidth(id) > w)
call assert_true(win_move_separator(id, -5000))
call assert_true(winwidth(id) < w)
+
" check that win_move_separator returns false for an invalid window
wincmd =
let w = winwidth(0)
call assert_false(win_move_separator(-1, 1))
call assert_equal(w, winwidth(0))
+
" check that win_move_separator returns false for a floating window
let id = nvim_open_win(
\ 0, 0, #{relative: 'editor', row: 2, col: 2, width: 5, height: 3})
@@ -1411,6 +1439,13 @@ func Test_win_move_separator()
call assert_false(win_move_separator(id, 1))
call assert_equal(w, winwidth(id))
call nvim_win_close(id, 1)
+
+ " check that using another tabpage fails without crash
+ let id = win_getid()
+ tabnew
+ call assert_fails('call win_move_separator(id, -1)', 'E1308:')
+ tabclose
+
%bwipe!
endfunc
diff --git a/src/nvim/testdir/test_window_id.vim b/src/nvim/testdir/test_window_id.vim
index 8bf4ede350..396a49b55f 100644
--- a/src/nvim/testdir/test_window_id.vim
+++ b/src/nvim/testdir/test_window_id.vim
@@ -1,5 +1,7 @@
" Test using the window ID.
+source check.vim
+
func Test_win_getid()
edit one
let id1 = win_getid()
@@ -90,10 +92,16 @@ func Test_win_getid()
split
call assert_equal(sort([id5, win_getid()]), sort(win_findbuf(bufnr5)))
+ call assert_fails('let w = win_getid([])', 'E745:')
+ call assert_equal(0, win_getid(-1))
+ call assert_equal(-1, win_getid(1, -1))
+
only!
endfunc
func Test_win_getid_curtab()
+ CheckFeature quickfix
+
tabedit X
tabfirst
copen
@@ -127,4 +135,8 @@ func Test_winlayout()
let w2 = win_getid()
call assert_equal(['leaf', w2], 2->winlayout())
tabclose
+
+ call assert_equal([], winlayout(-1))
endfunc
+
+" vim: shiftwidth=2 sts=2 expandtab
diff --git a/src/nvim/testdir/test_writefile.vim b/src/nvim/testdir/test_writefile.vim
index adc05ab979..8fb4c8fa4c 100644
--- a/src/nvim/testdir/test_writefile.vim
+++ b/src/nvim/testdir/test_writefile.vim
@@ -260,6 +260,193 @@ func Test_write_errors()
close
call delete('Xfile')
+
+ " Nvim treats NULL list/blob more like empty list/blob
+ " call writefile(v:_null_list, 'Xfile')
+ " call assert_false(filereadable('Xfile'))
+ " call writefile(v:_null_blob, 'Xfile')
+ " call assert_false(filereadable('Xfile'))
+ call assert_fails('call writefile([], "")', 'E482:')
+
+ " very long file name
+ let long_fname = repeat('n', 5000)
+ call assert_fails('exe "w " .. long_fname', 'E75:')
+ call assert_fails('call writefile([], long_fname)', 'E482:')
+endfunc
+
+" Test for writing to a file which is modified after Vim read it
+func Test_write_file_mtime()
+ CheckEnglish
+ CheckRunVimInTerminal
+
+ " First read the file into a buffer
+ call writefile(["Line1", "Line2"], 'Xfile')
+ let old_ftime = getftime('Xfile')
+ let buf = RunVimInTerminal('Xfile', #{rows : 10})
+ call term_wait(buf)
+ call term_sendkeys(buf, ":set noswapfile\<CR>")
+ call term_wait(buf)
+
+ " Modify the file directly. Make sure the file modification time is
+ " different. Note that on Linux/Unix, the file is considered modified
+ " outside, only if the difference is 2 seconds or more
+ sleep 1
+ call writefile(["Line3", "Line4"], 'Xfile')
+ let new_ftime = getftime('Xfile')
+ while new_ftime - old_ftime < 2
+ sleep 100m
+ call writefile(["Line3", "Line4"], 'Xfile')
+ let new_ftime = getftime('Xfile')
+ endwhile
+
+ " Try to overwrite the file and check for the prompt
+ call term_sendkeys(buf, ":w\<CR>")
+ call term_wait(buf)
+ call WaitForAssert({-> assert_equal("WARNING: The file has been changed since reading it!!!", term_getline(buf, 9))})
+ call assert_equal("Do you really want to write to it (y/n)?",
+ \ term_getline(buf, 10))
+ call term_sendkeys(buf, "n\<CR>")
+ call term_wait(buf)
+ call assert_equal(new_ftime, getftime('Xfile'))
+ call term_sendkeys(buf, ":w\<CR>")
+ call term_wait(buf)
+ call term_sendkeys(buf, "y\<CR>")
+ call term_wait(buf)
+ call WaitForAssert({-> assert_equal('Line2', readfile('Xfile')[1])})
+
+ " clean up
+ call StopVimInTerminal(buf)
+ call delete('Xfile')
+endfunc
+
+" Test for an autocmd unloading a buffer during a write command
+func Test_write_autocmd_unloadbuf_lockmark()
+ augroup WriteTest
+ autocmd BufWritePre Xfile enew | write
+ augroup END
+ e Xfile
+ call assert_fails('lockmarks write', ['E32', 'E203:'])
+ augroup WriteTest
+ au!
+ augroup END
+ augroup! WriteTest
+endfunc
+
+" Test for writing a buffer with 'acwrite' but without autocmds
+func Test_write_acwrite_error()
+ new Xfile
+ call setline(1, ['line1', 'line2', 'line3'])
+ set buftype=acwrite
+ call assert_fails('write', 'E676:')
+ call assert_fails('1,2write!', 'E676:')
+ call assert_fails('w >>', 'E676:')
+ close!
+endfunc
+
+" Test for adding and removing lines from an autocmd when writing a buffer
+func Test_write_autocmd_add_remove_lines()
+ new Xfile
+ call setline(1, ['aaa', 'bbb', 'ccc', 'ddd'])
+
+ " Autocmd deleting lines from the file when writing a partial file
+ augroup WriteTest2
+ au!
+ autocmd FileWritePre Xfile 1,2d
+ augroup END
+ call assert_fails('2,3w!', 'E204:')
+
+ " Autocmd adding lines to a file when writing a partial file
+ augroup WriteTest2
+ au!
+ autocmd FileWritePre Xfile call append(0, ['xxx', 'yyy'])
+ augroup END
+ %d
+ call setline(1, ['aaa', 'bbb', 'ccc', 'ddd'])
+ 1,2w!
+ call assert_equal(['xxx', 'yyy', 'aaa', 'bbb'], readfile('Xfile'))
+
+ " Autocmd deleting lines from the file when writing the whole file
+ augroup WriteTest2
+ au!
+ autocmd BufWritePre Xfile 1,2d
+ augroup END
+ %d
+ call setline(1, ['aaa', 'bbb', 'ccc', 'ddd'])
+ w
+ call assert_equal(['ccc', 'ddd'], readfile('Xfile'))
+
+ augroup WriteTest2
+ au!
+ augroup END
+ augroup! WriteTest2
+
+ close!
+ call delete('Xfile')
+endfunc
+
+" Test for writing to a readonly file
+func Test_write_readonly()
+ " In Cirrus-CI, the freebsd tests are run under a root account. So this test
+ " doesn't fail.
+ CheckNotBSD
+ call writefile([], 'Xfile')
+ call setfperm('Xfile', "r--------")
+ edit Xfile
+ set noreadonly
+ call assert_fails('write', 'E505:')
+ let save_cpo = &cpo
+ set cpo+=W
+ call assert_fails('write!', 'E504:')
+ let &cpo = save_cpo
+ call setline(1, ['line1'])
+ write!
+ call assert_equal(['line1'], readfile('Xfile'))
+ call delete('Xfile')
+endfunc
+
+" Test for 'patchmode'
+func Test_patchmode()
+ CheckNotBSD
+ call writefile(['one'], 'Xfile')
+ set patchmode=.orig nobackup writebackup
+ new Xfile
+ call setline(1, 'two')
+ " first write should create the .orig file
+ write
+ " TODO: Xfile.orig is not created in Cirrus FreeBSD CI test
+ call assert_equal(['one'], readfile('Xfile.orig'))
+ call setline(1, 'three')
+ " subsequent writes should not create/modify the .orig file
+ write
+ call assert_equal(['one'], readfile('Xfile.orig'))
+ set patchmode& backup& writebackup&
+ call delete('Xfile')
+ call delete('Xfile.orig')
+endfunc
+
+" Test for writing to a file in a readonly directory
+func Test_write_readonly_dir()
+ if !has('unix') || has('bsd')
+ " On MS-Windows, modifying files in a read-only directory is allowed.
+ " In Cirrus-CI for Freebsd, tests are run under a root account where
+ " modifying files in a read-only directory are allowed.
+ return
+ endif
+ call mkdir('Xdir')
+ call writefile(['one'], 'Xdir/Xfile1')
+ call setfperm('Xdir', 'r-xr--r--')
+ " try to create a new file in the directory
+ new Xdir/Xfile2
+ call setline(1, 'two')
+ call assert_fails('write', 'E212:')
+ " try to create a backup file in the directory
+ edit! Xdir/Xfile1
+ set backupdir=./Xdir
+ set patchmode=.orig
+ call assert_fails('write', 'E509:')
+ call setfperm('Xdir', 'rwxr--r--')
+ call delete('Xdir', 'rf')
+ set backupdir& patchmode&
endfunc
" Test for writing a file using invalid file encoding
diff --git a/src/nvim/testing.c b/src/nvim/testing.c
index 45134db14f..9dd41224da 100644
--- a/src/nvim/testing.c
+++ b/src/nvim/testing.c
@@ -14,6 +14,12 @@
# include "testing.c.generated.h"
#endif
+static char e_assert_fails_second_arg[]
+ = N_("E856: assert_fails() second argument must be a string or a list with one or two strings");
+static char e_assert_fails_fourth_argument[]
+ = N_("E1115: assert_fails() fourth argument must be a number");
+static char e_assert_fails_fifth_argument[]
+ = N_("E1116: assert_fails() fifth argument must be a string");
static char e_calling_test_garbagecollect_now_while_v_testing_is_not_set[]
= N_("E1142: Calling test_garbagecollect_now() while v:testing is not set");
@@ -68,7 +74,7 @@ static void ga_concat_esc(garray_T *gap, const char_u *p, int clen)
case '\\':
ga_concat(gap, "\\\\"); break;
default:
- if (*p < ' ') {
+ if (*p < ' ' || *p == 0x7f) {
vim_snprintf((char *)buf, NUMBUFLEN, "\\x%02x", *p);
ga_concat(gap, (char *)buf);
} else {
@@ -124,7 +130,10 @@ static void fill_assert_error(garray_T *gap, typval_T *opt_msg_tv, char_u *exp_s
bool did_copy = false;
int omitted = 0;
- if (opt_msg_tv->v_type != VAR_UNKNOWN) {
+ if (opt_msg_tv->v_type != VAR_UNKNOWN
+ && !(opt_msg_tv->v_type == VAR_STRING
+ && (opt_msg_tv->vval.v_string == NULL
+ || *opt_msg_tv->vval.v_string == NUL))) {
tofree = (char_u *)encode_tv2echo(opt_msg_tv, NULL);
ga_concat(gap, (char *)tofree);
xfree(tofree);
@@ -244,13 +253,12 @@ static int assert_match_common(typval_T *argvars, assert_type_T atype)
{
char buf1[NUMBUFLEN];
char buf2[NUMBUFLEN];
+ const int called_emsg_before = called_emsg;
const char *const pat = tv_get_string_buf_chk(&argvars[0], buf1);
const char *const text = tv_get_string_buf_chk(&argvars[1], buf2);
- if (pat == NULL || text == NULL) {
- emsg(_(e_invarg));
- } else if (pattern_match((char *)pat, (char *)text, false)
- != (atype == ASSERT_MATCH)) {
+ if (called_emsg == called_emsg_before
+ && pattern_match(pat, text, false) != (atype == ASSERT_MATCH)) {
garray_T ga;
prepare_assert_error(&ga);
fill_assert_error(&ga, &argvars[2], NULL, &argvars[0], &argvars[1], atype);
@@ -351,11 +359,12 @@ static int assert_equalfile(typval_T *argvars)
{
char buf1[NUMBUFLEN];
char buf2[NUMBUFLEN];
+ const int called_emsg_before = called_emsg;
const char *const fname1 = tv_get_string_buf_chk(&argvars[0], buf1);
const char *const fname2 = tv_get_string_buf_chk(&argvars[1], buf2);
garray_T ga;
- if (fname1 == NULL || fname2 == NULL) {
+ if (called_emsg > called_emsg_before) {
return 0;
}
@@ -477,11 +486,13 @@ void f_assert_fails(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
garray_T ga;
int save_trylevel = trylevel;
const int called_emsg_before = called_emsg;
+ char *wrong_arg_msg = NULL;
// trylevel must be zero for a ":throw" command to be considered failed
trylevel = 0;
suppress_errthrow = true;
emsg_silent = true;
+ emsg_assert_fails_used = true;
do_cmdline_cmd(cmd);
if (called_emsg == called_emsg_before) {
@@ -493,13 +504,75 @@ void f_assert_fails(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
rettv->vval.v_number = 1;
} else if (argvars[1].v_type != VAR_UNKNOWN) {
char buf[NUMBUFLEN];
- const char *const error = tv_get_string_buf_chk(&argvars[1], buf);
+ const char *expected;
+ bool error_found = false;
+ int error_found_index = 1;
+ char *actual = emsg_assert_fails_msg == NULL ? "[unknown]" : emsg_assert_fails_msg;
+
+ if (argvars[1].v_type == VAR_STRING) {
+ expected = tv_get_string_buf_chk(&argvars[1], buf);
+ error_found = expected == NULL || strstr(actual, expected) == NULL;
+ } else if (argvars[1].v_type == VAR_LIST) {
+ const list_T *const list = argvars[1].vval.v_list;
+ if (list == NULL || tv_list_len(list) < 1 || tv_list_len(list) > 2) {
+ wrong_arg_msg = e_assert_fails_second_arg;
+ goto theend;
+ }
+ const typval_T *tv = TV_LIST_ITEM_TV(tv_list_first(list));
+ expected = tv_get_string_buf_chk(tv, buf);
+ if (!pattern_match(expected, actual, false)) {
+ error_found = true;
+ } else if (tv_list_len(list) == 2) {
+ tv = TV_LIST_ITEM_TV(tv_list_last(list));
+ actual = get_vim_var_str(VV_ERRMSG);
+ expected = tv_get_string_buf_chk(tv, buf);
+ if (!pattern_match(expected, actual, false)) {
+ error_found = true;
+ }
+ }
+ } else {
+ wrong_arg_msg = e_assert_fails_second_arg;
+ goto theend;
+ }
- if (error == NULL
- || strstr(get_vim_var_str(VV_ERRMSG), error) == NULL) {
+ if (!error_found && argvars[2].v_type != VAR_UNKNOWN
+ && argvars[3].v_type != VAR_UNKNOWN) {
+ if (argvars[3].v_type != VAR_NUMBER) {
+ wrong_arg_msg = e_assert_fails_fourth_argument;
+ goto theend;
+ } else if (argvars[3].vval.v_number >= 0
+ && argvars[3].vval.v_number != emsg_assert_fails_lnum) {
+ error_found = true;
+ error_found_index = 3;
+ }
+ if (!error_found && argvars[4].v_type != VAR_UNKNOWN) {
+ if (argvars[4].v_type != VAR_STRING) {
+ wrong_arg_msg = e_assert_fails_fifth_argument;
+ goto theend;
+ } else if (argvars[4].vval.v_string != NULL
+ && !pattern_match(argvars[4].vval.v_string,
+ emsg_assert_fails_context, false)) {
+ error_found = true;
+ error_found_index = 4;
+ }
+ }
+ }
+
+ if (error_found) {
+ typval_T actual_tv;
prepare_assert_error(&ga);
- fill_assert_error(&ga, &argvars[2], NULL, &argvars[1],
- get_vim_var_tv(VV_ERRMSG), ASSERT_OTHER);
+ if (error_found_index == 3) {
+ actual_tv.v_type = VAR_NUMBER;
+ actual_tv.vval.v_number = emsg_assert_fails_lnum;
+ } else if (error_found_index == 4) {
+ actual_tv.v_type = VAR_STRING;
+ actual_tv.vval.v_string = emsg_assert_fails_context;
+ } else {
+ actual_tv.v_type = VAR_STRING;
+ actual_tv.vval.v_string = actual;
+ }
+ fill_assert_error(&ga, &argvars[2], NULL,
+ &argvars[error_found_index], &actual_tv, ASSERT_OTHER);
ga_concat(&ga, ": ");
assert_append_cmd_or_arg(&ga, argvars, cmd);
assert_error(&ga);
@@ -508,11 +581,17 @@ void f_assert_fails(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
}
}
+theend:
trylevel = save_trylevel;
suppress_errthrow = false;
emsg_silent = false;
emsg_on_display = false;
+ emsg_assert_fails_used = false;
+ XFREE_CLEAR(emsg_assert_fails_msg);
set_vim_var_string(VV_ERRMSG, NULL, 0);
+ if (wrong_arg_msg != NULL) {
+ emsg(_(wrong_arg_msg));
+ }
}
// "assert_false(actual[, msg])" function
diff --git a/src/nvim/usercmd.c b/src/nvim/usercmd.c
index 408cdc93a7..bed4d55d4e 100644
--- a/src/nvim/usercmd.c
+++ b/src/nvim/usercmd.c
@@ -1215,7 +1215,7 @@ static size_t add_cmd_modifier(char *buf, char *mod_str, bool *multi_mods)
/// was added.
///
/// @return the number of bytes added
-size_t add_win_cmd_modifers(char *buf, const cmdmod_T *cmod, bool *multi_mods)
+size_t add_win_cmd_modifiers(char *buf, const cmdmod_T *cmod, bool *multi_mods)
{
size_t result = 0;
@@ -1320,7 +1320,7 @@ size_t uc_mods(char *buf, const cmdmod_T *cmod, bool quote)
}
}
// flags from cmod->cmod_split
- result += add_win_cmd_modifers(buf, cmod, &multi_mods);
+ result += add_win_cmd_modifiers(buf, cmod, &multi_mods);
if (quote && buf != NULL) {
buf += result - 2;
diff --git a/src/nvim/version.c b/src/nvim/version.c
index e76d3ef9bf..98f34ca11f 100644
--- a/src/nvim/version.c
+++ b/src/nvim/version.c
@@ -669,7 +669,7 @@ static const int included_patches[] = {
1829,
1828,
// 1827,
- // 1826,
+ 1826,
1825,
1824,
1823,
diff --git a/src/nvim/window.c b/src/nvim/window.c
index 4812b9ef9d..c755f58c4f 100644
--- a/src/nvim/window.c
+++ b/src/nvim/window.c
@@ -4213,6 +4213,8 @@ static int leave_tabpage(buf_T *new_curbuf, bool trigger_leave_autocmds)
return FAIL;
}
}
+
+ reset_dragwin();
tp->tp_curwin = curwin;
tp->tp_prevwin = prevwin;
tp->tp_firstwin = firstwin;
@@ -4275,6 +4277,10 @@ static void enter_tabpage(tabpage_T *tp, buf_T *old_curbuf, bool trigger_enter_a
clear_cmdline = true;
}
+ // If there was a click in a window, it won't be usable for a following
+ // drag.
+ reset_dragwin();
+
// The tabpage line may have appeared or disappeared, may need to resize the frames for that.
// When the Vim window was resized or ROWS_AVAIL changed need to update frame sizes too.
if (curtab->tp_old_Rows_avail != ROWS_AVAIL || (old_off != firstwin->w_winrow)) {
diff --git a/test/benchmark/bench_re_freeze_spec.lua b/test/benchmark/bench_regexp_spec.lua
index ea41953014..903af5f574 100644
--- a/test/benchmark/bench_re_freeze_spec.lua
+++ b/test/benchmark/bench_regexp_spec.lua
@@ -1,4 +1,4 @@
--- Test for benchmarking RE engine.
+-- Test for benchmarking the RE engine.
local helpers = require('test.functional.helpers')(after_each)
local insert, source = helpers.insert, helpers.source
@@ -7,19 +7,19 @@ local clear, command = helpers.clear, helpers.command
-- Temporary file for gathering benchmarking results for each regexp engine.
local result_file = 'benchmark.out'
-- Fixture containing an HTML fragment that can make a search appear to freeze.
-local sample_file = 'test/benchmark/samples/re.freeze.txt'
+local sample_file = 'src/nvim/testdir/samples/re.freeze.txt'
-- Vim script code that does both the work and the benchmarking of that work.
local measure_cmd =
[[call Measure(%d, ']] .. sample_file .. [[', '\s\+\%%#\@<!$', '+5')]]
local measure_script = [[
- func! Measure(re, file, pattern, arg)
- let sstart=reltime()
+ func Measure(re, file, pattern, arg)
+ let sstart = reltime()
- execute 'set re=' . a:re
+ execute 'set re=' .. a:re
execute 'split' a:arg a:file
call search(a:pattern, '', '', 10000)
- q!
+ quit!
$put =printf('file: %s, re: %d, time: %s', a:file, a:re, reltimestr(reltime(sstart)))
endfunc]]
diff --git a/test/functional/api/keymap_spec.lua b/test/functional/api/keymap_spec.lua
index 30c351b26a..5be4425162 100644
--- a/test/functional/api/keymap_spec.lua
+++ b/test/functional/api/keymap_spec.lua
@@ -1066,7 +1066,7 @@ describe('nvim_buf_set_keymap, nvim_buf_del_keymap', function()
eq({'rhs'}, bufmeths.get_lines(0, 0, 1, 1))
end)
- it("does not crash when setting keymap in a non-existing buffer #13541", function()
+ it("does not crash when setting mapping in a non-existing buffer #13541", function()
pcall_err(bufmeths.set_keymap, 100, '', 'lsh', 'irhs<Esc>', {})
helpers.assert_alive()
end)
diff --git a/test/functional/core/fileio_spec.lua b/test/functional/core/fileio_spec.lua
index 07774866a8..795f639dad 100644
--- a/test/functional/core/fileio_spec.lua
+++ b/test/functional/core/fileio_spec.lua
@@ -1,3 +1,4 @@
+local lfs = require('lfs')
local helpers = require('test.functional.helpers')(after_each)
local assert_log = helpers.assert_log
@@ -5,6 +6,7 @@ local assert_nolog = helpers.assert_nolog
local clear = helpers.clear
local command = helpers.command
local eq = helpers.eq
+local neq = helpers.neq
local ok = helpers.ok
local feed = helpers.feed
local funcs = helpers.funcs
@@ -132,6 +134,57 @@ describe('fileio', function()
eq('foo', foo_contents);
end)
+ it('backup symlinked files #11349', function()
+ if isCI('cirrus') then
+ pending('FIXME: cirrus')
+ end
+ clear()
+
+ local initial_content = 'foo'
+ local link_file_name = 'Xtest_startup_file2'
+ local backup_file_name = link_file_name .. '~'
+
+ write_file('Xtest_startup_file1', initial_content, false)
+ lfs.link('Xtest_startup_file1', link_file_name, true)
+ command('set backup')
+ command('set backupcopy=yes')
+ command('edit ' .. link_file_name)
+ feed('Abar<esc>')
+ command('write')
+
+ local backup_raw = read_file(backup_file_name)
+ neq(nil, backup_raw, "Expected backup file " .. backup_file_name .. "to exist but did not")
+ eq(initial_content, trim(backup_raw), 'Expected backup to contain original contents')
+ end)
+
+
+ it('backup symlinked files in first avialable backupdir #11349', function()
+ if isCI('cirrus') then
+ pending('FIXME: cirrus')
+ end
+ clear()
+
+ local initial_content = 'foo'
+ local backup_dir = 'Xtest_backupdir'
+ local sep = helpers.get_pathsep()
+ local link_file_name = 'Xtest_startup_file2'
+ local backup_file_name = backup_dir .. sep .. link_file_name .. '~'
+
+ write_file('Xtest_startup_file1', initial_content, false)
+ lfs.link('Xtest_startup_file1', link_file_name, true)
+ mkdir(backup_dir)
+ command('set backup')
+ command('set backupcopy=yes')
+ command('set backupdir=.__this_does_not_exist__,' .. backup_dir)
+ command('edit ' .. link_file_name)
+ feed('Abar<esc>')
+ command('write')
+
+ local backup_raw = read_file(backup_file_name)
+ neq(nil, backup_raw, "Expected backup file " .. backup_file_name .. " to exist but did not")
+ eq(initial_content, trim(backup_raw), 'Expected backup to contain original contents')
+ end)
+
it('readfile() on multibyte filename #10586', function()
clear()
local text = {
diff --git a/test/functional/core/startup_spec.lua b/test/functional/core/startup_spec.lua
index a32c801c97..2084d365a5 100644
--- a/test/functional/core/startup_spec.lua
+++ b/test/functional/core/startup_spec.lua
@@ -637,7 +637,7 @@ describe('runtime:', function()
end)
it('loads plugin/*.lua from start packages', function()
- local plugin_path = table.concat({xconfig, 'nvim', 'pack', 'catagory',
+ local plugin_path = table.concat({xconfig, 'nvim', 'pack', 'category',
'start', 'test_plugin'}, pathsep)
local plugin_folder_path = table.concat({plugin_path, 'plugin'}, pathsep)
local plugin_file_path = table.concat({plugin_folder_path, 'plugin.lua'},
diff --git a/test/functional/ex_cmds/verbose_spec.lua b/test/functional/ex_cmds/verbose_spec.lua
index e6f67ef18e..000e746f1c 100644
--- a/test/functional/ex_cmds/verbose_spec.lua
+++ b/test/functional/ex_cmds/verbose_spec.lua
@@ -77,7 +77,7 @@ nohlsearch
script_location), result)
end)
- it('"Last set" for keymap set by Lua', function()
+ it('"Last set" for mapping set by Lua', function()
local result = exec_capture(':verbose map <leader>key1')
eq(string.format([[
@@ -86,7 +86,7 @@ n \key1 * :echo "test"<CR>
script_location), result)
end)
- it('"Last set" for keymap set by vim.keymap', function()
+ it('"Last set" for mapping set by vim.keymap', function()
local result = exec_capture(':verbose map <leader>key2')
eq(string.format([[
diff --git a/test/functional/legacy/breakindent_spec.lua b/test/functional/legacy/breakindent_spec.lua
new file mode 100644
index 0000000000..d7779684a4
--- /dev/null
+++ b/test/functional/legacy/breakindent_spec.lua
@@ -0,0 +1,44 @@
+local helpers = require('test.functional.helpers')(after_each)
+local Screen = require('test.functional.ui.screen')
+local clear = helpers.clear
+local exec = helpers.exec
+local feed = helpers.feed
+
+before_each(clear)
+
+describe('breakindent', function()
+ -- oldtest: Test_cursor_position_with_showbreak()
+ it('cursor shown at correct position with showbreak', function()
+ local screen = Screen.new(75, 6)
+ screen:set_default_attr_ids({
+ [0] = {bold = true, foreground = Screen.colors.Blue}, -- NonText
+ [1] = {background = Screen.colors.Grey, foreground = Screen.colors.DarkBlue}, -- SignColumn
+ [2] = {bold = true}, -- ModeMsg
+ })
+ screen:attach()
+ exec([[
+ let &signcolumn = 'yes'
+ let &showbreak = '+'
+ let leftcol = win_getid()->getwininfo()->get(0, {})->get('textoff')
+ eval repeat('x', &columns - leftcol - 1)->setline(1)
+ eval 'second line'->setline(2)
+ ]])
+ screen:expect([[
+ {1: }^xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx |
+ {1: }second line |
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ |
+ ]])
+ feed('AX')
+ screen:expect([[
+ {1: }xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxX|
+ {1: }^second line |
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {2:-- INSERT --} |
+ ]])
+ end)
+end)
diff --git a/test/functional/legacy/digraph_spec.lua b/test/functional/legacy/digraph_spec.lua
new file mode 100644
index 0000000000..0cb0bb84be
--- /dev/null
+++ b/test/functional/legacy/digraph_spec.lua
@@ -0,0 +1,46 @@
+local helpers = require('test.functional.helpers')(after_each)
+local Screen = require('test.functional.ui.screen')
+local clear = helpers.clear
+local feed = helpers.feed
+
+before_each(clear)
+
+describe('digraph', function()
+ -- oldtest: Test_entering_digraph()
+ it('characters displayed on the screen', function()
+ local screen = Screen.new(10, 6)
+ screen:set_default_attr_ids({
+ [0] = {bold = true, foreground = Screen.colors.Blue}, -- NonText
+ [1] = {foreground = Screen.colors.Blue}, -- SpecialKey
+ [2] = {bold = true}, -- ModeMsg
+ })
+ screen:attach()
+ feed('i<C-K>')
+ screen:expect([[
+ {1:^?} |
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {2:-- INSERT -} |
+ ]])
+ feed('1')
+ screen:expect([[
+ {1:^1} |
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {2:-- INSERT -} |
+ ]])
+ feed('2')
+ screen:expect([[
+ ½^ |
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {2:-- INSERT -} |
+ ]])
+ end)
+end)
diff --git a/test/functional/legacy/edit_spec.lua b/test/functional/legacy/edit_spec.lua
index 7fc5f11a79..362d33a0fd 100644
--- a/test/functional/legacy/edit_spec.lua
+++ b/test/functional/legacy/edit_spec.lua
@@ -1,4 +1,5 @@
local helpers = require('test.functional.helpers')(after_each)
+local Screen = require('test.functional.ui.screen')
local clear = helpers.clear
local command = helpers.command
local expect = helpers.expect
@@ -7,20 +8,51 @@ local sleep = helpers.sleep
before_each(clear)
--- oldtest: Test_autoindent_remove_indent()
-it('autoindent removes indent when Insert mode is stopped', function()
- command('set autoindent')
- -- leaving insert mode in a new line with indent added by autoindent, should
- -- remove the indent.
- feed('i<Tab>foo<CR><Esc>')
- -- Need to delay for sometime, otherwise the code in getchar.c will not be
- -- exercised.
- sleep(50)
- -- when a line is wrapped and the cursor is at the start of the second line,
- -- leaving insert mode, should move the cursor back to the first line.
- feed('o' .. ('x'):rep(20) .. '<Esc>')
- -- Need to delay for sometime, otherwise the code in getchar.c will not be
- -- exercised.
- sleep(50)
- expect('\tfoo\n\n' .. ('x'):rep(20))
+describe('edit', function()
+ -- oldtest: Test_autoindent_remove_indent()
+ it('autoindent removes indent when Insert mode is stopped', function()
+ command('set autoindent')
+ -- leaving insert mode in a new line with indent added by autoindent, should
+ -- remove the indent.
+ feed('i<Tab>foo<CR><Esc>')
+ -- Need to delay for sometime, otherwise the code in getchar.c will not be
+ -- exercised.
+ sleep(50)
+ -- when a line is wrapped and the cursor is at the start of the second line,
+ -- leaving insert mode, should move the cursor back to the first line.
+ feed('o' .. ('x'):rep(20) .. '<Esc>')
+ -- Need to delay for sometime, otherwise the code in getchar.c will not be
+ -- exercised.
+ sleep(50)
+ expect('\tfoo\n\n' .. ('x'):rep(20))
+ end)
+
+ -- oldtest: Test_edit_insert_reg()
+ it('inserting a register using CTRL-R', function()
+ local screen = Screen.new(10, 6)
+ screen:set_default_attr_ids({
+ [0] = {bold = true, foreground = Screen.colors.Blue}, -- NonText
+ [1] = {foreground = Screen.colors.Blue}, -- SpecialKey
+ [2] = {bold = true}, -- ModeMsg
+ })
+ screen:attach()
+ feed('a<C-R>')
+ screen:expect([[
+ {1:^"} |
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {2:-- INSERT -} |
+ ]])
+ feed('=')
+ screen:expect([[
+ {1:"} |
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ {0:~ }|
+ =^ |
+ ]])
+ end)
end)
diff --git a/test/functional/legacy/increment_spec.lua b/test/functional/legacy/increment_spec.lua
index d51f9a2e02..d35f4bdae6 100644
--- a/test/functional/legacy/increment_spec.lua
+++ b/test/functional/legacy/increment_spec.lua
@@ -285,7 +285,7 @@ describe('Ctrl-A/Ctrl-X on visual selections', function()
" 1
" 1
" 1
- " Expexted:
+ " Expected:
" 1) g Ctrl-A on block selected indented lines
" 2
" 1
diff --git a/test/functional/legacy/vimscript_spec.lua b/test/functional/legacy/vimscript_spec.lua
new file mode 100644
index 0000000000..f59a87f824
--- /dev/null
+++ b/test/functional/legacy/vimscript_spec.lua
@@ -0,0 +1,90 @@
+local helpers = require('test.functional.helpers')(after_each)
+local Screen = require('test.functional.ui.screen')
+local clear = helpers.clear
+local exec = helpers.exec
+local feed = helpers.feed
+local meths = helpers.meths
+
+before_each(clear)
+
+describe('Vim script', function()
+ -- oldtest: Test_deep_nest()
+ it('Error when if/for/while/try/function is nested too deep',function()
+ local screen = Screen.new(80, 24)
+ screen:attach()
+ meths.set_option('laststatus', 2)
+ exec([[
+ " Deep nesting of if ... endif
+ func Test1()
+ let @a = join(repeat(['if v:true'], 51), "\n")
+ let @a ..= "\n"
+ let @a ..= join(repeat(['endif'], 51), "\n")
+ @a
+ let @a = ''
+ endfunc
+
+ " Deep nesting of for ... endfor
+ func Test2()
+ let @a = join(repeat(['for i in [1]'], 51), "\n")
+ let @a ..= "\n"
+ let @a ..= join(repeat(['endfor'], 51), "\n")
+ @a
+ let @a = ''
+ endfunc
+
+ " Deep nesting of while ... endwhile
+ func Test3()
+ let @a = join(repeat(['while v:true'], 51), "\n")
+ let @a ..= "\n"
+ let @a ..= join(repeat(['endwhile'], 51), "\n")
+ @a
+ let @a = ''
+ endfunc
+
+ " Deep nesting of try ... endtry
+ func Test4()
+ let @a = join(repeat(['try'], 51), "\n")
+ let @a ..= "\necho v:true\n"
+ let @a ..= join(repeat(['endtry'], 51), "\n")
+ @a
+ let @a = ''
+ endfunc
+
+ " Deep nesting of function ... endfunction
+ func Test5()
+ let @a = join(repeat(['function X()'], 51), "\n")
+ let @a ..= "\necho v:true\n"
+ let @a ..= join(repeat(['endfunction'], 51), "\n")
+ @a
+ let @a = ''
+ endfunc
+ ]])
+ screen:expect({any = '%[No Name%]'})
+ feed(':call Test1()<CR>')
+ screen:expect({any = 'E579: '})
+ feed('<C-C>')
+ screen:expect({any = '%[No Name%]'})
+ feed(':call Test2()<CR>')
+ screen:expect({any = 'E585: '})
+ feed('<C-C>')
+ screen:expect({any = '%[No Name%]'})
+ feed(':call Test3()<CR>')
+ screen:expect({any = 'E585: '})
+ feed('<C-C>')
+ screen:expect({any = '%[No Name%]'})
+ feed(':call Test4()<CR>')
+ screen:expect({any = 'E601: '})
+ feed('<C-C>')
+ screen:expect({any = '%[No Name%]'})
+ feed(':call Test5()<CR>')
+ screen:expect({any = 'E1058: '})
+ end)
+
+ -- oldtest: Test_typed_script_var()
+ it('using s: with a typed command', function()
+ local screen = Screen.new(80, 24)
+ screen:attach()
+ feed(":echo get(s:, 'foo', 'x')\n")
+ screen:expect({any = 'E116: '})
+ end)
+end)
diff --git a/test/functional/plugin/lsp_spec.lua b/test/functional/plugin/lsp_spec.lua
index 425427be54..a7094fff48 100644
--- a/test/functional/plugin/lsp_spec.lua
+++ b/test/functional/plugin/lsp_spec.lua
@@ -2470,7 +2470,7 @@ describe('LSP', function()
},
uri = "file:///test_a"
},
- contanerName = "TestAContainer"
+ containerName = "TestAContainer"
},
{
deprecated = false,
@@ -2489,7 +2489,7 @@ describe('LSP', function()
},
uri = "file:///test_b"
},
- contanerName = "TestBContainer"
+ containerName = "TestBContainer"
}
}
return vim.lsp.util.symbols_to_items(sym_info, nil)
diff --git a/test/functional/ui/diff_spec.lua b/test/functional/ui/diff_spec.lua
index 36dc5addcd..dd35f47ca1 100644
--- a/test/functional/ui/diff_spec.lua
+++ b/test/functional/ui/diff_spec.lua
@@ -1073,6 +1073,182 @@ int main(int argc, char **argv)
:e |
]])
end)
+
+ describe('line matching diff algorithm', function()
+ setup(function()
+ local f1 = [[if __name__ == "__main__":
+ import sys
+ app = QWidgets.QApplication(sys.args)
+ MainWindow = QtWidgets.QMainWindow()
+ ui = UI_MainWindow()
+ ui.setupUI(MainWindow)
+ MainWindow.show()
+ sys.exit(app.exec_())]]
+ write_file(fname, f1, false)
+ local f2 = [[if __name__ == "__main__":
+ import sys
+ comment these things
+ #app = QWidgets.QApplication(sys.args)
+ #MainWindow = QtWidgets.QMainWindow()
+ add a completely different line here
+ #ui = UI_MainWindow()
+ add another new line
+ ui.setupUI(MainWindow)
+ MainWindow.show()
+ sys.exit(app.exec_())]]
+ write_file(fname_2, f2, false)
+ end)
+
+ it('diffopt+=linematch:20', function()
+ reread()
+ feed(':set diffopt=internal,filler<cr>')
+ screen:expect([[
+ {1: }^if __name__ == "__│{1: }if __name__ == "_|
+ {1: } import sys │{1: } import sys |
+ {1: }{9: }{8:app = QWidgets}│{1: }{9: }{8:comment these}|
+ {1: }{9: }{8:MainWindow = Q}│{1: }{9: }{8:#app = QWidge}|
+ {1: }{9: }{8:ui = UI_}{9:MainWi}│{1: }{9: }{8:#MainWindow =}|
+ {1: }{2:------------------}│{1: }{4: add a complet}|
+ {1: }{2:------------------}│{1: }{4: #ui = UI_Main}|
+ {1: }{2:------------------}│{1: }{4: add another n}|
+ {1: } ui.setupUI(Mai│{1: } ui.setupUI(Ma|
+ {1: } MainWindow.sho│{1: } MainWindow.sh|
+ {1: } sys.exit(app.e│{1: } sys.exit(app.|
+ {6:~ }│{6:~ }|
+ {6:~ }│{6:~ }|
+ {6:~ }│{6:~ }|
+ {7:<onal-diff-screen-1 }{3:<l-diff-screen-1.2 }|
+ :set diffopt=internal,filler |
+ ]])
+
+ feed('G')
+ feed(':set diffopt+=linematch:20<cr>')
+ screen:expect([[
+ {1: }if __name__ == "__│{1: }if __name__ == "_|
+ {1: } import sys │{1: } import sys |
+ {1: }{2:------------------}│{1: }{4: comment these}|
+ {1: }{9: app = QWidgets}│{1: }{9: }{8:#}{9:app = QWidge}|
+ {1: }{9: MainWindow = Q}│{1: }{9: }{8:#}{9:MainWindow =}|
+ {1: }{2:------------------}│{1: }{4: add a complet}|
+ {1: }{9: ui = UI_MainWi}│{1: }{9: }{8:#}{9:ui = UI_Main}|
+ {1: }{2:------------------}│{1: }{4: add another n}|
+ {1: } ui.setupUI(Mai│{1: } ui.setupUI(Ma|
+ {1: } MainWindow.sho│{1: } MainWindow.sh|
+ {1: } ^sys.exit(app.e│{1: } sys.exit(app.|
+ {6:~ }│{6:~ }|
+ {6:~ }│{6:~ }|
+ {6:~ }│{6:~ }|
+ {7:<onal-diff-screen-1 }{3:<l-diff-screen-1.2 }|
+ :set diffopt+=linematch:20 |
+ ]])
+ end)
+ end)
+
+ describe('line matching diff algorithm with icase', function()
+ setup(function()
+ local f1 = [[DDD
+_aa]]
+ write_file(fname, f1, false)
+ local f2 = [[DDD
+AAA
+ccca]]
+ write_file(fname_2, f2, false)
+ end)
+ it('diffopt+=linematch:20,icase', function()
+ reread()
+ feed(':set diffopt=internal,filler,linematch:20<cr>')
+ screen:expect([[
+ {1: }^DDD │{1: }DDD |
+ {1: }{2:------------------}│{1: }{4:AAA }|
+ {1: }{8:_a}{9:a }│{1: }{8:ccc}{9:a }|
+ {6:~ }│{6:~ }|
+ {6:~ }│{6:~ }|
+ {6:~ }│{6:~ }|
+ {6:~ }│{6:~ }|
+ {6:~ }│{6:~ }|
+ {6:~ }│{6:~ }|
+ {6:~ }│{6:~ }|
+ {6:~ }│{6:~ }|
+ {6:~ }│{6:~ }|
+ {6:~ }│{6:~ }|
+ {6:~ }│{6:~ }|
+ {7:<onal-diff-screen-1 }{3:<l-diff-screen-1.2 }|
+ |
+ ]])
+ feed(':set diffopt+=icase<cr>')
+ screen:expect([[
+ {1: }^DDD │{1: }DDD |
+ {1: }{8:_}{9:aa }│{1: }{8:A}{9:AA }|
+ {1: }{2:------------------}│{1: }{4:ccca }|
+ {6:~ }│{6:~ }|
+ {6:~ }│{6:~ }|
+ {6:~ }│{6:~ }|
+ {6:~ }│{6:~ }|
+ {6:~ }│{6:~ }|
+ {6:~ }│{6:~ }|
+ {6:~ }│{6:~ }|
+ {6:~ }│{6:~ }|
+ {6:~ }│{6:~ }|
+ {6:~ }│{6:~ }|
+ {6:~ }│{6:~ }|
+ {7:<onal-diff-screen-1 }{3:<l-diff-screen-1.2 }|
+ :set diffopt+=icase |
+ ]])
+ end)
+ end)
+
+ describe('line matching diff algorithm with iwhiteall', function()
+ setup(function()
+ local f1 = [[BB
+ AAA]]
+ write_file(fname, f1, false)
+ local f2 = [[BB
+ AAB
+AAAB]]
+ write_file(fname_2, f2, false)
+ end)
+ it('diffopt+=linematch:20,iwhiteall', function()
+ reread()
+ feed(':set diffopt=internal,filler,linematch:20<cr>')
+ screen:expect{grid=[[
+ {1: }^BB │{1: }BB |
+ {1: }{9: AA}{8:A}{9: }│{1: }{9: AA}{8:B}{9: }|
+ {1: }{2:------------------}│{1: }{4:AAAB }|
+ {6:~ }│{6:~ }|
+ {6:~ }│{6:~ }|
+ {6:~ }│{6:~ }|
+ {6:~ }│{6:~ }|
+ {6:~ }│{6:~ }|
+ {6:~ }│{6:~ }|
+ {6:~ }│{6:~ }|
+ {6:~ }│{6:~ }|
+ {6:~ }│{6:~ }|
+ {6:~ }│{6:~ }|
+ {6:~ }│{6:~ }|
+ {7:<onal-diff-screen-1 }{3:<l-diff-screen-1.2 }|
+ |
+ ]]}
+ feed(':set diffopt+=iwhiteall<cr>')
+ screen:expect{grid=[[
+ {1: }^BB │{1: }BB |
+ {1: }{2:------------------}│{1: }{4: AAB }|
+ {1: }{9: AAA }│{1: }{9:AAA}{8:B}{9: }|
+ {6:~ }│{6:~ }|
+ {6:~ }│{6:~ }|
+ {6:~ }│{6:~ }|
+ {6:~ }│{6:~ }|
+ {6:~ }│{6:~ }|
+ {6:~ }│{6:~ }|
+ {6:~ }│{6:~ }|
+ {6:~ }│{6:~ }|
+ {6:~ }│{6:~ }|
+ {6:~ }│{6:~ }|
+ {6:~ }│{6:~ }|
+ {7:<onal-diff-screen-1 }{3:<l-diff-screen-1.2 }|
+ :set diffopt+=iwhiteall |
+ ]]}
+ end)
+ end)
end)
it('win_update redraws lines properly', function()
diff --git a/test/functional/ui/linematch_spec.lua b/test/functional/ui/linematch_spec.lua
new file mode 100644
index 0000000000..5601908929
--- /dev/null
+++ b/test/functional/ui/linematch_spec.lua
@@ -0,0 +1,981 @@
+local helpers = require('test.functional.helpers')(after_each)
+local Screen = require('test.functional.ui.screen')
+
+local feed = helpers.feed
+local clear = helpers.clear
+local write_file = helpers.write_file
+
+describe('Diff mode screen with 3 diffs open', function()
+ local fname = 'Xtest-functional-diff-screen-1'
+ local fname_2 = fname .. '.2'
+ local fname_3 = fname .. '.3'
+ local screen
+
+ local reread = function()
+ feed(':e<cr><c-w>w:e<cr><c-w>w:e<cr><c-w>w')
+ end
+
+ setup(function()
+ clear()
+ os.remove(fname)
+ os.remove(fname_2)
+ os.remove(fname_3)
+ end)
+
+ teardown(function()
+ os.remove(fname)
+ os.remove(fname_2)
+ os.remove(fname_3)
+ end)
+
+ before_each(function()
+ clear()
+ feed(':set diffopt+=linematch:30<cr>')
+ feed(':e ' .. fname .. '<cr>')
+ feed(':vnew ' .. fname_2 .. '<cr>')
+ feed(':vnew ' .. fname_3 .. '<cr>')
+ feed(':windo diffthis<cr>')
+
+ screen = Screen.new(100, 16)
+ screen:attach()
+ screen:set_default_attr_ids({
+ [1] = {foreground = Screen.colors.DarkBlue, background = Screen.colors.Gray};
+ [2] = {foreground = Screen.colors.Blue1, bold = true, background = Screen.colors.LightCyan1};
+ [3] = {reverse = true};
+ [4] = {background = Screen.colors.LightBlue};
+ [5] = {foreground = Screen.colors.DarkBlue, background = Screen.colors.LightGray};
+ [6] = {foreground = Screen.colors.Blue1, bold = true};
+ [7] = {reverse = true, bold = true};
+ [8] = {background = Screen.colors.Red1, bold = true};
+ [10] = {foreground = Screen.colors.Brown};
+ [9] = {background = Screen.colors.Plum1};
+})
+ feed('<c-w>=')
+ feed(':windo set nu!<cr>')
+
+
+ end)
+ describe('setup the diff screen to look like a merge conflict with 3 files in diff mode', function()
+ before_each(function()
+
+ local f1 = [[
+
+ common line
+ AAA
+ AAA
+ AAA
+ ]]
+ local f2 = [[
+
+ common line
+ <<<<<<< HEAD
+ AAA
+ AAA
+ AAA
+ =======
+ BBB
+ BBB
+ BBB
+ >>>>>>> branch1
+ ]]
+ local f3 = [[
+
+ common line
+ BBB
+ BBB
+ BBB
+ ]]
+
+ write_file(fname, f1, false)
+ write_file(fname_2, f2, false)
+ write_file(fname_3, f3, false)
+ reread()
+ end)
+
+ it('get from window 1', function()
+ feed('1<c-w>w')
+ feed(':2,6diffget screen-1.2<cr>')
+ screen:expect([[
+ {1: }{10: 1 }^ │{1: }{10: 1 } │{1: }{10: 1 } |
+ {1: }{10: 2 }common line │{1: }{10: 2 }common line │{1: }{10: 2 }common line |
+ {1: }{10: 3 }{9:<<<<<<< HEAD }│{1: }{10: 3 }{9:<<<<<<< HEAD }│{1: }{10: }{2:---------------------------}|
+ {1: }{10: 4 } AAA │{1: }{10: 4 } AAA │{1: }{10: 3 } AAA |
+ {1: }{10: 5 } AAA │{1: }{10: 5 } AAA │{1: }{10: 4 } AAA |
+ {1: }{10: 6 } AAA │{1: }{10: 6 } AAA │{1: }{10: 5 } AAA |
+ {1: }{10: 7 }{9:======= }│{1: }{10: 7 }{9:======= }│{1: }{10: }{2:---------------------------}|
+ {1: }{10: 8 }{9: BBB }│{1: }{10: 8 }{9: BBB }│{1: }{10: }{2:---------------------------}|
+ {1: }{10: 9 }{9: BBB }│{1: }{10: 9 }{9: BBB }│{1: }{10: }{2:---------------------------}|
+ {1: }{10: 10 }{9: BBB }│{1: }{10: 10 }{9: BBB }│{1: }{10: }{2:---------------------------}|
+ {1: }{10: 11 }{9:>>>>>>> branch1 }│{1: }{10: 11 }{9:>>>>>>> branch1 }│{1: }{10: }{2:---------------------------}|
+ {1: }{10: 12 } │{1: }{10: 12 } │{1: }{10: 6 } |
+ {6:~ }│{6:~ }│{6:~ }|
+ {6:~ }│{6:~ }│{6:~ }|
+ {7:<-functional-diff-screen-1.3 [+] }{3:<est-functional-diff-screen-1.2 Xtest-functional-diff-screen-1 }|
+ :2,6diffget screen-1.2 |
+ ]])
+ end)
+
+ it('get from window 2', function()
+ feed('2<c-w>w')
+ feed(':5,7diffget screen-1.3<cr>')
+ screen:expect([[
+ {1: }{10: 1 } │{1: }{10: 1 }^ │{1: }{10: 1 } |
+ {1: }{10: 2 }common line │{1: }{10: 2 }common line │{1: }{10: 2 }common line |
+ {1: }{10: }{2:---------------------------}│{1: }{10: 3 }{4:<<<<<<< HEAD }│{1: }{10: }{2:---------------------------}|
+ {1: }{10: }{2:---------------------------}│{1: }{10: 4 }{9: AAA }│{1: }{10: 3 }{9: AAA }|
+ {1: }{10: 3 }{9: BBB }│{1: }{10: 5 }{9: BBB }│{1: }{10: }{2:---------------------------}|
+ {1: }{10: 4 }{9: }{8:BBB}{9: }│{1: }{10: 6 }{9: }{8:BBB}{9: }│{1: }{10: 4 }{9: }{8:AAA}{9: }|
+ {1: }{10: 5 }{9: }{8:BBB}{9: }│{1: }{10: 7 }{9: }{8:BBB}{9: }│{1: }{10: 5 }{9: }{8:AAA}{9: }|
+ {1: }{10: }{2:---------------------------}│{1: }{10: 8 }{4:>>>>>>> branch1 }│{1: }{10: }{2:---------------------------}|
+ {1: }{10: 6 } │{1: }{10: 9 } │{1: }{10: 6 } |
+ {6:~ }│{6:~ }│{6:~ }|
+ {6:~ }│{6:~ }│{6:~ }|
+ {6:~ }│{6:~ }│{6:~ }|
+ {6:~ }│{6:~ }│{6:~ }|
+ {6:~ }│{6:~ }│{6:~ }|
+ {3:<test-functional-diff-screen-1.3 }{7:<functional-diff-screen-1.2 [+] }{3:Xtest-functional-diff-screen-1 }|
+ :5,7diffget screen-1.3 |
+ ]])
+ end)
+
+ it('get from window 3', function()
+ feed('3<c-w>w')
+ feed(':5,6diffget screen-1.2<cr>')
+ screen:expect([[
+ {1: }{10: 1 } │{1: }{10: 1 } │{1: }{10: 1 }^ |
+ {1: }{10: 2 }common line │{1: }{10: 2 }common line │{1: }{10: 2 }common line |
+ {1: }{10: }{2:---------------------------}│{1: }{10: 3 }{4:<<<<<<< HEAD }│{1: }{10: }{2:---------------------------}|
+ {1: }{10: }{2:---------------------------}│{1: }{10: 4 }{9: AAA }│{1: }{10: 3 }{9: AAA }|
+ {1: }{10: }{2:---------------------------}│{1: }{10: 5 }{9: AAA }│{1: }{10: 4 }{9: AAA }|
+ {1: }{10: }{2:---------------------------}│{1: }{10: 6 }{9: AAA }│{1: }{10: 5 }{9: AAA }|
+ {1: }{10: }{2:---------------------------}│{1: }{10: 7 }{9:======= }│{1: }{10: 6 }{9:======= }|
+ {1: }{10: 3 } BBB │{1: }{10: 8 } BBB │{1: }{10: 7 } BBB |
+ {1: }{10: 4 } BBB │{1: }{10: 9 } BBB │{1: }{10: 8 } BBB |
+ {1: }{10: 5 } BBB │{1: }{10: 10 } BBB │{1: }{10: 9 } BBB |
+ {1: }{10: }{2:---------------------------}│{1: }{10: 11 }{9:>>>>>>> branch1 }│{1: }{10: 10 }{9:>>>>>>> branch1 }|
+ {1: }{10: 6 } │{1: }{10: 12 } │{1: }{10: 11 } |
+ {6:~ }│{6:~ }│{6:~ }|
+ {6:~ }│{6:~ }│{6:~ }|
+ {3:<test-functional-diff-screen-1.3 <est-functional-diff-screen-1.2 }{7:<st-functional-diff-screen-1 [+] }|
+ :5,6diffget screen-1.2 |
+ ]])
+ end)
+
+ it('put from window 2 - part', function()
+ feed('2<c-w>w')
+ feed(':6,8diffput screen-1<cr>')
+ screen:expect([[
+ {1: }{10: 1 } │{1: }{10: 1 }^ │{1: }{10: 1 } |
+ {1: }{10: 2 }common line │{1: }{10: 2 }common line │{1: }{10: 2 }common line |
+ {1: }{10: }{2:---------------------------}│{1: }{10: 3 }{4:<<<<<<< HEAD }│{1: }{10: }{2:---------------------------}|
+ {1: }{10: }{2:---------------------------}│{1: }{10: 4 }{9: AAA }│{1: }{10: 3 }{9: AAA }|
+ {1: }{10: }{2:---------------------------}│{1: }{10: 5 }{9: AAA }│{1: }{10: 4 }{9: AAA }|
+ {1: }{10: }{2:---------------------------}│{1: }{10: 6 }{9: AAA }│{1: }{10: 5 }{9: AAA }|
+ {1: }{10: }{2:---------------------------}│{1: }{10: 7 }{9:======= }│{1: }{10: 6 }{9:======= }|
+ {1: }{10: 3 }{9: BBB }│{1: }{10: 8 }{9: BBB }│{1: }{10: }{2:---------------------------}|
+ {1: }{10: 4 }{9: BBB }│{1: }{10: 9 }{9: BBB }│{1: }{10: }{2:---------------------------}|
+ {1: }{10: 5 } BBB │{1: }{10: 10 } BBB │{1: }{10: 7 } BBB |
+ {1: }{10: }{2:---------------------------}│{1: }{10: 11 }{4:>>>>>>> branch1 }│{1: }{10: }{2:---------------------------}|
+ {1: }{10: 6 } │{1: }{10: 12 } │{1: }{10: 8 } |
+ {6:~ }│{6:~ }│{6:~ }|
+ {6:~ }│{6:~ }│{6:~ }|
+ {3:<test-functional-diff-screen-1.3 }{7:<est-functional-diff-screen-1.2 }{3:<st-functional-diff-screen-1 [+] }|
+ :6,8diffput screen-1 |
+ ]])
+
+ end)
+ it('put from window 2 - part to end', function()
+ feed('2<c-w>w')
+ feed(':6,11diffput screen-1<cr>')
+ screen:expect([[
+ {1: }{10: 1 } │{1: }{10: 1 }^ │{1: }{10: 1 } |
+ {1: }{10: 2 }common line │{1: }{10: 2 }common line │{1: }{10: 2 }common line |
+ {1: }{10: }{2:---------------------------}│{1: }{10: 3 }{4:<<<<<<< HEAD }│{1: }{10: }{2:---------------------------}|
+ {1: }{10: }{2:---------------------------}│{1: }{10: 4 }{9: AAA }│{1: }{10: 3 }{9: AAA }|
+ {1: }{10: }{2:---------------------------}│{1: }{10: 5 }{9: AAA }│{1: }{10: 4 }{9: AAA }|
+ {1: }{10: }{2:---------------------------}│{1: }{10: 6 }{9: AAA }│{1: }{10: 5 }{9: AAA }|
+ {1: }{10: }{2:---------------------------}│{1: }{10: 7 }{9:======= }│{1: }{10: 6 }{9:======= }|
+ {1: }{10: 3 } BBB │{1: }{10: 8 } BBB │{1: }{10: 7 } BBB |
+ {1: }{10: 4 } BBB │{1: }{10: 9 } BBB │{1: }{10: 8 } BBB |
+ {1: }{10: 5 } BBB │{1: }{10: 10 } BBB │{1: }{10: 9 } BBB |
+ {1: }{10: }{2:---------------------------}│{1: }{10: 11 }{9:>>>>>>> branch1 }│{1: }{10: 10 }{9:>>>>>>> branch1 }|
+ {1: }{10: 6 } │{1: }{10: 12 } │{1: }{10: 11 } |
+ {6:~ }│{6:~ }│{6:~ }|
+ {6:~ }│{6:~ }│{6:~ }|
+ {3:<test-functional-diff-screen-1.3 }{7:<est-functional-diff-screen-1.2 }{3:<st-functional-diff-screen-1 [+] }|
+ :6,11diffput screen-1 |
+ ]])
+
+ end)
+ end)
+end)
+
+describe('Diff mode screen with 2 diffs open', function()
+ local fname = 'Xtest-functional-diff-screen-1'
+ local fname_2 = fname .. '.2'
+ local screen
+
+ local reread = function()
+ feed(':e<cr><c-w>w:e<cr><c-w>w:e<cr><c-w>w')
+ end
+
+ setup(function()
+ clear()
+ os.remove(fname)
+ os.remove(fname_2)
+ end)
+
+ teardown(function()
+ os.remove(fname)
+ os.remove(fname_2)
+ end)
+
+ before_each(function()
+ clear()
+ feed(':e ' .. fname .. '<cr>')
+ feed(':vnew ' .. fname_2 .. '<cr>')
+ feed(':windo diffthis<cr>')
+
+ screen = Screen.new(100, 20)
+ screen:attach()
+ screen:set_default_attr_ids({
+ [1] = {foreground = Screen.colors.DarkBlue, background = Screen.colors.Gray};
+ [2] = {foreground = Screen.colors.Blue1, bold = true, background = Screen.colors.LightCyan1};
+ [3] = {reverse = true};
+ [4] = {background = Screen.colors.LightBlue};
+ [5] = {foreground = Screen.colors.DarkBlue, background = Screen.colors.LightGray};
+ [6] = {foreground = Screen.colors.Blue1, bold = true};
+ [7] = {reverse = true, bold = true};
+ [8] = {background = Screen.colors.Red1, bold = true};
+ [10] = {foreground = Screen.colors.Brown};
+ [9] = {background = Screen.colors.Plum1};
+})
+ feed('<c-w>=')
+ feed(':windo set nu!<cr>')
+
+
+ end)
+ describe('setup a diff with 2 files and set linematch:30', function()
+ before_each(function()
+ feed(':set diffopt+=linematch:30<cr>')
+ local f1 = [[
+
+common line
+common line
+
+DEFabc
+xyz
+xyz
+xyz
+DEFabc
+DEFabc
+DEFabc
+common line
+common line
+DEF
+common line
+DEF
+something
+ ]]
+ local f2 = [[
+
+common line
+common line
+
+ABCabc
+ABCabc
+ABCabc
+ABCabc
+common line
+common line
+common line
+something
+ ]]
+ write_file(fname, f1, false)
+ write_file(fname_2, f2, false)
+ reread()
+ end)
+
+ it('get from window 1 from line 5 to 9', function()
+ feed('1<c-w>w')
+ feed(':5,9diffget<cr>')
+ screen:expect([[
+ {1:+ }{10: 1 }{5:^+-- 7 lines: common line··················}│{1:+ }{10: 1 }{5:+-- 7 lines: common line···················}|
+ {1: }{10: 8 }xyz │{1: }{10: 8 }xyz |
+ {1: }{10: 9 }DEFabc │{1: }{10: 9 }DEFabc |
+ {1: }{10: 10 }DEFabc │{1: }{10: 10 }DEFabc |
+ {1: }{10: 11 }DEFabc │{1: }{10: 11 }DEFabc |
+ {1: }{10: 12 }common line │{1: }{10: 12 }common line |
+ {1: }{10: 13 }common line │{1: }{10: 13 }common line |
+ {1: }{10: }{2:-------------------------------------------}│{1: }{10: 14 }{4:DEF }|
+ {1: }{10: 14 }common line │{1: }{10: 15 }common line |
+ {1: }{10: }{2:-------------------------------------------}│{1: }{10: 16 }{4:DEF }|
+ {1: }{10: 15 }something │{1: }{10: 17 }something |
+ {1: }{10: 16 } │{1: }{10: 18 } |
+ {6:~ }│{6:~ }|
+ {6:~ }│{6:~ }|
+ {6:~ }│{6:~ }|
+ {6:~ }│{6:~ }|
+ {6:~ }│{6:~ }|
+ {6:~ }│{6:~ }|
+ {7:Xtest-functional-diff-screen-1.2 [+] }{3:Xtest-functional-diff-screen-1 }|
+ :5,9diffget |
+ ]])
+ end)
+ it('get from window 2 from line 5 to 10', function()
+ feed('2<c-w>w')
+ feed(':5,10diffget<cr>')
+ screen:expect([[
+ {1:- }{10: 1 } │{1:- }{10: 1 }^ |
+ {1: }{10: 2 }common line │{1: }{10: 2 }common line |
+ {1: }{10: 3 }common line │{1: }{10: 3 }common line |
+ {1: }{10: 4 } │{1: }{10: 4 } |
+ {1: }{10: 5 }ABCabc │{1: }{10: 5 }ABCabc |
+ {1: }{10: 6 }ABCabc │{1: }{10: 6 }ABCabc |
+ {1: }{10: 7 }ABCabc │{1: }{10: 7 }ABCabc |
+ {1: }{10: 8 }{8:ABC}{9:abc }│{1: }{10: 8 }{8:DEF}{9:abc }|
+ {1: }{10: 9 }common line │{1: }{10: 9 }common line |
+ {1: }{10: 10 }common line │{1: }{10: 10 }common line |
+ {1: }{10: }{2:-------------------------------------------}│{1: }{10: 11 }{4:DEF }|
+ {1: }{10: 11 }common line │{1: }{10: 12 }common line |
+ {1: }{10: }{2:-------------------------------------------}│{1: }{10: 13 }{4:DEF }|
+ {1: }{10: 12 }something │{1: }{10: 14 }something |
+ {1: }{10: 13 } │{1: }{10: 15 } |
+ {6:~ }│{6:~ }|
+ {6:~ }│{6:~ }|
+ {6:~ }│{6:~ }|
+ {3:Xtest-functional-diff-screen-1.2 }{7:Xtest-functional-diff-screen-1 [+] }|
+ :5,10diffget |
+ ]])
+ end)
+ it('get all from window 2', function()
+ feed('2<c-w>w')
+ feed(':4,17diffget<cr>')
+ screen:expect([[
+ {1: }{10: 1 } │{1: }{10: 1 }^ |
+ {1: }{10: 2 }common line │{1: }{10: 2 }common line |
+ {1: }{10: 3 }common line │{1: }{10: 3 }common line |
+ {1: }{10: 4 } │{1: }{10: 4 } |
+ {1: }{10: 5 }ABCabc │{1: }{10: 5 }ABCabc |
+ {1: }{10: 6 }ABCabc │{1: }{10: 6 }ABCabc |
+ {1: }{10: 7 }ABCabc │{1: }{10: 7 }ABCabc |
+ {1: }{10: 8 }ABCabc │{1: }{10: 8 }ABCabc |
+ {1: }{10: 9 }common line │{1: }{10: 9 }common line |
+ {1: }{10: 10 }common line │{1: }{10: 10 }common line |
+ {1: }{10: 11 }common line │{1: }{10: 11 }common line |
+ {1: }{10: 12 }something │{1: }{10: 12 }something |
+ {1: }{10: 13 } │{1: }{10: 13 } |
+ {6:~ }│{6:~ }|
+ {6:~ }│{6:~ }|
+ {6:~ }│{6:~ }|
+ {6:~ }│{6:~ }|
+ {6:~ }│{6:~ }|
+ {3:Xtest-functional-diff-screen-1.2 }{7:Xtest-functional-diff-screen-1 [+] }|
+ :4,17diffget |
+ ]])
+
+ end)
+ it('get all from window 1', function()
+ feed('1<c-w>w')
+ feed(':4,12diffget<cr>')
+ screen:expect([[
+ {1: }{10: 1 }^ │{1: }{10: 1 } |
+ {1: }{10: 2 }common line │{1: }{10: 2 }common line |
+ {1: }{10: 3 }common line │{1: }{10: 3 }common line |
+ {1: }{10: 4 } │{1: }{10: 4 } |
+ {1: }{10: 5 }DEFabc │{1: }{10: 5 }DEFabc |
+ {1: }{10: 6 }xyz │{1: }{10: 6 }xyz |
+ {1: }{10: 7 }xyz │{1: }{10: 7 }xyz |
+ {1: }{10: 8 }xyz │{1: }{10: 8 }xyz |
+ {1: }{10: 9 }DEFabc │{1: }{10: 9 }DEFabc |
+ {1: }{10: 10 }DEFabc │{1: }{10: 10 }DEFabc |
+ {1: }{10: 11 }DEFabc │{1: }{10: 11 }DEFabc |
+ {1: }{10: 12 }common line │{1: }{10: 12 }common line |
+ {1: }{10: 13 }common line │{1: }{10: 13 }common line |
+ {1: }{10: 14 }DEF │{1: }{10: 14 }DEF |
+ {1: }{10: 15 }common line │{1: }{10: 15 }common line |
+ {1: }{10: 16 }DEF │{1: }{10: 16 }DEF |
+ {1: }{10: 17 }something │{1: }{10: 17 }something |
+ {1: }{10: 18 } │{1: }{10: 18 } |
+ {7:Xtest-functional-diff-screen-1.2 [+] }{3:Xtest-functional-diff-screen-1 }|
+ :4,12diffget |
+ ]])
+ end)
+ it('get from window 1 using do 1 line 5', function()
+ feed('1<c-w>w')
+ feed('5gg')
+ feed('do')
+ screen:expect([[
+ {1: }{10: 1 } │{1: }{10: 1 } |
+ {1: }{10: 2 }common line │{1: }{10: 2 }common line |
+ {1: }{10: 3 }common line │{1: }{10: 3 }common line |
+ {1: }{10: 4 } │{1: }{10: 4 } |
+ {1: }{10: 5 }^DEFabc │{1: }{10: 5 }DEFabc |
+ {1: }{10: }{2:-------------------------------------------}│{1: }{10: 6 }{4:xyz }|
+ {1: }{10: }{2:-------------------------------------------}│{1: }{10: 7 }{4:xyz }|
+ {1: }{10: }{2:-------------------------------------------}│{1: }{10: 8 }{4:xyz }|
+ {1: }{10: 6 }{8:ABC}{9:abc }│{1: }{10: 9 }{8:DEF}{9:abc }|
+ {1: }{10: 7 }{8:ABC}{9:abc }│{1: }{10: 10 }{8:DEF}{9:abc }|
+ {1: }{10: 8 }{8:ABC}{9:abc }│{1: }{10: 11 }{8:DEF}{9:abc }|
+ {1: }{10: 9 }common line │{1: }{10: 12 }common line |
+ {1: }{10: 10 }common line │{1: }{10: 13 }common line |
+ {1: }{10: }{2:-------------------------------------------}│{1: }{10: 14 }{4:DEF }|
+ {1: }{10: 11 }common line │{1: }{10: 15 }common line |
+ {1: }{10: }{2:-------------------------------------------}│{1: }{10: 16 }{4:DEF }|
+ {1: }{10: 12 }something │{1: }{10: 17 }something |
+ {1: }{10: 13 } │{1: }{10: 18 } |
+ {7:Xtest-functional-diff-screen-1.2 [+] }{3:Xtest-functional-diff-screen-1 }|
+ :e |
+ ]])
+ end)
+ it('get from window 1 using do 2 line 6', function()
+ feed('1<c-w>w')
+ feed('6gg')
+ feed('do')
+ screen:expect([[
+ {1: }{10: 1 } │{1: }{10: 1 } |
+ {1: }{10: 2 }common line │{1: }{10: 2 }common line |
+ {1: }{10: 3 }common line │{1: }{10: 3 }common line |
+ {1: }{10: 4 } │{1: }{10: 4 } |
+ {1: }{10: 5 }{8:ABC}{9:abc }│{1: }{10: 5 }{8:DEF}{9:abc }|
+ {1: }{10: }{2:-------------------------------------------}│{1: }{10: 6 }{4:xyz }|
+ {1: }{10: }{2:-------------------------------------------}│{1: }{10: 7 }{4:xyz }|
+ {1: }{10: }{2:-------------------------------------------}│{1: }{10: 8 }{4:xyz }|
+ {1: }{10: 6 }^DEFabc │{1: }{10: 9 }DEFabc |
+ {1: }{10: 7 }DEFabc │{1: }{10: 10 }DEFabc |
+ {1: }{10: 8 }DEFabc │{1: }{10: 11 }DEFabc |
+ {1: }{10: 9 }common line │{1: }{10: 12 }common line |
+ {1: }{10: 10 }common line │{1: }{10: 13 }common line |
+ {1: }{10: }{2:-------------------------------------------}│{1: }{10: 14 }{4:DEF }|
+ {1: }{10: 11 }common line │{1: }{10: 15 }common line |
+ {1: }{10: }{2:-------------------------------------------}│{1: }{10: 16 }{4:DEF }|
+ {1: }{10: 12 }something │{1: }{10: 17 }something |
+ {1: }{10: 13 } │{1: }{10: 18 } |
+ {7:Xtest-functional-diff-screen-1.2 [+] }{3:Xtest-functional-diff-screen-1 }|
+ :e |
+ ]])
+ end)
+ it('get from window 1 using do 2 line 7', function()
+ feed('1<c-w>w')
+ feed('7gg')
+ feed('do')
+ screen:expect([[
+ {1: }{10: 1 } │{1: }{10: 1 } |
+ {1: }{10: 2 }common line │{1: }{10: 2 }common line |
+ {1: }{10: 3 }common line │{1: }{10: 3 }common line |
+ {1: }{10: 4 } │{1: }{10: 4 } |
+ {1: }{10: 5 }{8:ABC}{9:abc }│{1: }{10: 5 }{8:DEF}{9:abc }|
+ {1: }{10: }{2:-------------------------------------------}│{1: }{10: 6 }{4:xyz }|
+ {1: }{10: }{2:-------------------------------------------}│{1: }{10: 7 }{4:xyz }|
+ {1: }{10: }{2:-------------------------------------------}│{1: }{10: 8 }{4:xyz }|
+ {1: }{10: 6 }DEFabc │{1: }{10: 9 }DEFabc |
+ {1: }{10: 7 }^DEFabc │{1: }{10: 10 }DEFabc |
+ {1: }{10: 8 }DEFabc │{1: }{10: 11 }DEFabc |
+ {1: }{10: 9 }common line │{1: }{10: 12 }common line |
+ {1: }{10: 10 }common line │{1: }{10: 13 }common line |
+ {1: }{10: }{2:-------------------------------------------}│{1: }{10: 14 }{4:DEF }|
+ {1: }{10: 11 }common line │{1: }{10: 15 }common line |
+ {1: }{10: }{2:-------------------------------------------}│{1: }{10: 16 }{4:DEF }|
+ {1: }{10: 12 }something │{1: }{10: 17 }something |
+ {1: }{10: 13 } │{1: }{10: 18 } |
+ {7:Xtest-functional-diff-screen-1.2 [+] }{3:Xtest-functional-diff-screen-1 }|
+ :e |
+ ]])
+ end)
+ it('get from window 1 using do 2 line 11', function()
+ feed('1<c-w>w')
+ feed('11gg')
+ feed('do')
+ screen:expect([[
+ {1: }{10: 1 } │{1: }{10: 1 } |
+ {1: }{10: 2 }common line │{1: }{10: 2 }common line |
+ {1: }{10: 3 }common line │{1: }{10: 3 }common line |
+ {1: }{10: 4 } │{1: }{10: 4 } |
+ {1: }{10: 5 }{8:ABC}{9:abc }│{1: }{10: 5 }{8:DEF}{9:abc }|
+ {1: }{10: }{2:-------------------------------------------}│{1: }{10: 6 }{4:xyz }|
+ {1: }{10: }{2:-------------------------------------------}│{1: }{10: 7 }{4:xyz }|
+ {1: }{10: }{2:-------------------------------------------}│{1: }{10: 8 }{4:xyz }|
+ {1: }{10: 6 }{8:ABC}{9:abc }│{1: }{10: 9 }{8:DEF}{9:abc }|
+ {1: }{10: 7 }{8:ABC}{9:abc }│{1: }{10: 10 }{8:DEF}{9:abc }|
+ {1: }{10: 8 }{8:ABC}{9:abc }│{1: }{10: 11 }{8:DEF}{9:abc }|
+ {1: }{10: 9 }common line │{1: }{10: 12 }common line |
+ {1: }{10: 10 }common line │{1: }{10: 13 }common line |
+ {1: }{10: 11 }DEF │{1: }{10: 14 }DEF |
+ {1: }{10: 12 }^common line │{1: }{10: 15 }common line |
+ {1: }{10: }{2:-------------------------------------------}│{1: }{10: 16 }{4:DEF }|
+ {1: }{10: 13 }something │{1: }{10: 17 }something |
+ {1: }{10: 14 } │{1: }{10: 18 } |
+ {7:Xtest-functional-diff-screen-1.2 [+] }{3:Xtest-functional-diff-screen-1 }|
+ :e |
+ ]])
+ end)
+ it('get from window 1 using do 2 line 12', function()
+ feed('1<c-w>w')
+ feed('12gg')
+ feed('do')
+ screen:expect([[
+ {1: }{10: 1 } │{1: }{10: 1 } |
+ {1: }{10: 2 }common line │{1: }{10: 2 }common line |
+ {1: }{10: 3 }common line │{1: }{10: 3 }common line |
+ {1: }{10: 4 } │{1: }{10: 4 } |
+ {1: }{10: 5 }{8:ABC}{9:abc }│{1: }{10: 5 }{8:DEF}{9:abc }|
+ {1: }{10: }{2:-------------------------------------------}│{1: }{10: 6 }{4:xyz }|
+ {1: }{10: }{2:-------------------------------------------}│{1: }{10: 7 }{4:xyz }|
+ {1: }{10: }{2:-------------------------------------------}│{1: }{10: 8 }{4:xyz }|
+ {1: }{10: 6 }{8:ABC}{9:abc }│{1: }{10: 9 }{8:DEF}{9:abc }|
+ {1: }{10: 7 }{8:ABC}{9:abc }│{1: }{10: 10 }{8:DEF}{9:abc }|
+ {1: }{10: 8 }{8:ABC}{9:abc }│{1: }{10: 11 }{8:DEF}{9:abc }|
+ {1: }{10: 9 }common line │{1: }{10: 12 }common line |
+ {1: }{10: 10 }common line │{1: }{10: 13 }common line |
+ {1: }{10: }{2:-------------------------------------------}│{1: }{10: 14 }{4:DEF }|
+ {1: }{10: 11 }common line │{1: }{10: 15 }common line |
+ {1: }{10: 12 }DEF │{1: }{10: 16 }DEF |
+ {1: }{10: 13 }^something │{1: }{10: 17 }something |
+ {1: }{10: 14 } │{1: }{10: 18 } |
+ {7:Xtest-functional-diff-screen-1.2 [+] }{3:Xtest-functional-diff-screen-1 }|
+ :e |
+ ]])
+ end)
+ it('put from window 1 using dp 1 line 5', function()
+ feed('1<c-w>w')
+ feed('5gg')
+ feed('dp')
+ screen:expect([[
+ {1: }{10: 1 } │{1: }{10: 1 } |
+ {1: }{10: 2 }common line │{1: }{10: 2 }common line |
+ {1: }{10: 3 }common line │{1: }{10: 3 }common line |
+ {1: }{10: 4 } │{1: }{10: 4 } |
+ {1: }{10: 5 }^ABCabc │{1: }{10: 5 }ABCabc |
+ {1: }{10: }{2:-------------------------------------------}│{1: }{10: 6 }{4:xyz }|
+ {1: }{10: }{2:-------------------------------------------}│{1: }{10: 7 }{4:xyz }|
+ {1: }{10: }{2:-------------------------------------------}│{1: }{10: 8 }{4:xyz }|
+ {1: }{10: 6 }{8:ABC}{9:abc }│{1: }{10: 9 }{8:DEF}{9:abc }|
+ {1: }{10: 7 }{8:ABC}{9:abc }│{1: }{10: 10 }{8:DEF}{9:abc }|
+ {1: }{10: 8 }{8:ABC}{9:abc }│{1: }{10: 11 }{8:DEF}{9:abc }|
+ {1: }{10: 9 }common line │{1: }{10: 12 }common line |
+ {1: }{10: 10 }common line │{1: }{10: 13 }common line |
+ {1: }{10: }{2:-------------------------------------------}│{1: }{10: 14 }{4:DEF }|
+ {1: }{10: 11 }common line │{1: }{10: 15 }common line |
+ {1: }{10: }{2:-------------------------------------------}│{1: }{10: 16 }{4:DEF }|
+ {1: }{10: 12 }something │{1: }{10: 17 }something |
+ {1: }{10: 13 } │{1: }{10: 18 } |
+ {7:Xtest-functional-diff-screen-1.2 }{3:Xtest-functional-diff-screen-1 [+] }|
+ :e |
+ ]])
+ end)
+ it('put from window 1 using dp 2 line 6', function()
+ feed('1<c-w>w')
+ feed('6gg')
+ feed('dp')
+ screen:expect([[
+ {1: }{10: 1 } │{1: }{10: 1 } |
+ {1: }{10: 2 }common line │{1: }{10: 2 }common line |
+ {1: }{10: 3 }common line │{1: }{10: 3 }common line |
+ {1: }{10: 4 } │{1: }{10: 4 } |
+ {1: }{10: 5 }{8:ABC}{9:abc }│{1: }{10: 5 }{8:DEF}{9:abc }|
+ {1: }{10: }{2:-------------------------------------------}│{1: }{10: 6 }{4:xyz }|
+ {1: }{10: }{2:-------------------------------------------}│{1: }{10: 7 }{4:xyz }|
+ {1: }{10: }{2:-------------------------------------------}│{1: }{10: 8 }{4:xyz }|
+ {1: }{10: 6 }^ABCabc │{1: }{10: 9 }ABCabc |
+ {1: }{10: 7 }ABCabc │{1: }{10: 10 }ABCabc |
+ {1: }{10: 8 }ABCabc │{1: }{10: 11 }ABCabc |
+ {1: }{10: 9 }common line │{1: }{10: 12 }common line |
+ {1: }{10: 10 }common line │{1: }{10: 13 }common line |
+ {1: }{10: }{2:-------------------------------------------}│{1: }{10: 14 }{4:DEF }|
+ {1: }{10: 11 }common line │{1: }{10: 15 }common line |
+ {1: }{10: }{2:-------------------------------------------}│{1: }{10: 16 }{4:DEF }|
+ {1: }{10: 12 }something │{1: }{10: 17 }something |
+ {1: }{10: 13 } │{1: }{10: 18 } |
+ {7:Xtest-functional-diff-screen-1.2 }{3:Xtest-functional-diff-screen-1 [+] }|
+ :e |
+ ]])
+ end)
+ it('put from window 1 using dp 2 line 7', function()
+ feed('1<c-w>w')
+ feed('7gg')
+ feed('dp')
+ screen:expect([[
+ {1: }{10: 1 } │{1: }{10: 1 } |
+ {1: }{10: 2 }common line │{1: }{10: 2 }common line |
+ {1: }{10: 3 }common line │{1: }{10: 3 }common line |
+ {1: }{10: 4 } │{1: }{10: 4 } |
+ {1: }{10: 5 }{8:ABC}{9:abc }│{1: }{10: 5 }{8:DEF}{9:abc }|
+ {1: }{10: }{2:-------------------------------------------}│{1: }{10: 6 }{4:xyz }|
+ {1: }{10: }{2:-------------------------------------------}│{1: }{10: 7 }{4:xyz }|
+ {1: }{10: }{2:-------------------------------------------}│{1: }{10: 8 }{4:xyz }|
+ {1: }{10: 6 }ABCabc │{1: }{10: 9 }ABCabc |
+ {1: }{10: 7 }^ABCabc │{1: }{10: 10 }ABCabc |
+ {1: }{10: 8 }ABCabc │{1: }{10: 11 }ABCabc |
+ {1: }{10: 9 }common line │{1: }{10: 12 }common line |
+ {1: }{10: 10 }common line │{1: }{10: 13 }common line |
+ {1: }{10: }{2:-------------------------------------------}│{1: }{10: 14 }{4:DEF }|
+ {1: }{10: 11 }common line │{1: }{10: 15 }common line |
+ {1: }{10: }{2:-------------------------------------------}│{1: }{10: 16 }{4:DEF }|
+ {1: }{10: 12 }something │{1: }{10: 17 }something |
+ {1: }{10: 13 } │{1: }{10: 18 } |
+ {7:Xtest-functional-diff-screen-1.2 }{3:Xtest-functional-diff-screen-1 [+] }|
+ :e |
+ ]])
+ end)
+ it('put from window 1 using dp 2 line 11', function()
+ feed('1<c-w>w')
+ feed('11gg')
+ feed('dp')
+ screen:expect([[
+ {1: }{10: 1 } │{1: }{10: 1 } |
+ {1: }{10: 2 }common line │{1: }{10: 2 }common line |
+ {1: }{10: 3 }common line │{1: }{10: 3 }common line |
+ {1: }{10: 4 } │{1: }{10: 4 } |
+ {1: }{10: 5 }{8:ABC}{9:abc }│{1: }{10: 5 }{8:DEF}{9:abc }|
+ {1: }{10: }{2:-------------------------------------------}│{1: }{10: 6 }{4:xyz }|
+ {1: }{10: }{2:-------------------------------------------}│{1: }{10: 7 }{4:xyz }|
+ {1: }{10: }{2:-------------------------------------------}│{1: }{10: 8 }{4:xyz }|
+ {1: }{10: 6 }{8:ABC}{9:abc }│{1: }{10: 9 }{8:DEF}{9:abc }|
+ {1: }{10: 7 }{8:ABC}{9:abc }│{1: }{10: 10 }{8:DEF}{9:abc }|
+ {1: }{10: 8 }{8:ABC}{9:abc }│{1: }{10: 11 }{8:DEF}{9:abc }|
+ {1: }{10: 9 }common line │{1: }{10: 12 }common line |
+ {1: }{10: 10 }common line │{1: }{10: 13 }common line |
+ {1: }{10: 11 }^common line │{1: }{10: 14 }common line |
+ {1: }{10: }{2:-------------------------------------------}│{1: }{10: 15 }{4:DEF }|
+ {1: }{10: 12 }something │{1: }{10: 16 }something |
+ {1: }{10: 13 } │{1: }{10: 17 } |
+ {6:~ }│{6:~ }|
+ {7:Xtest-functional-diff-screen-1.2 }{3:Xtest-functional-diff-screen-1 [+] }|
+ :e |
+ ]])
+ end)
+ it('put from window 1 using dp 2 line 12', function()
+ feed('1<c-w>w')
+ feed('12gg')
+ feed('dp')
+ screen:expect([[
+ {1: }{10: 1 } │{1: }{10: 1 } |
+ {1: }{10: 2 }common line │{1: }{10: 2 }common line |
+ {1: }{10: 3 }common line │{1: }{10: 3 }common line |
+ {1: }{10: 4 } │{1: }{10: 4 } |
+ {1: }{10: 5 }{8:ABC}{9:abc }│{1: }{10: 5 }{8:DEF}{9:abc }|
+ {1: }{10: }{2:-------------------------------------------}│{1: }{10: 6 }{4:xyz }|
+ {1: }{10: }{2:-------------------------------------------}│{1: }{10: 7 }{4:xyz }|
+ {1: }{10: }{2:-------------------------------------------}│{1: }{10: 8 }{4:xyz }|
+ {1: }{10: 6 }{8:ABC}{9:abc }│{1: }{10: 9 }{8:DEF}{9:abc }|
+ {1: }{10: 7 }{8:ABC}{9:abc }│{1: }{10: 10 }{8:DEF}{9:abc }|
+ {1: }{10: 8 }{8:ABC}{9:abc }│{1: }{10: 11 }{8:DEF}{9:abc }|
+ {1: }{10: 9 }common line │{1: }{10: 12 }common line |
+ {1: }{10: 10 }common line │{1: }{10: 13 }common line |
+ {1: }{10: }{2:-------------------------------------------}│{1: }{10: 14 }{4:DEF }|
+ {1: }{10: 11 }common line │{1: }{10: 15 }common line |
+ {1: }{10: 12 }^something │{1: }{10: 16 }something |
+ {1: }{10: 13 } │{1: }{10: 17 } |
+ {6:~ }│{6:~ }|
+ {7:Xtest-functional-diff-screen-1.2 }{3:Xtest-functional-diff-screen-1 [+] }|
+ :e |
+ ]])
+ end)
+ it('put from window 2 using dp line 6', function()
+ feed('2<c-w>w')
+ feed('6gg')
+ feed('dp')
+ screen:expect([[
+ {1: }{10: 1 } │{1: }{10: 1 } |
+ {1: }{10: 2 }common line │{1: }{10: 2 }common line |
+ {1: }{10: 3 }common line │{1: }{10: 3 }common line |
+ {1: }{10: 4 } │{1: }{10: 4 } |
+ {1: }{10: 5 }{8:ABC}{9:abc }│{1: }{10: 5 }{8:DEF}{9:abc }|
+ {1: }{10: 6 }xyz │{1: }{10: 6 }^xyz |
+ {1: }{10: 7 }xyz │{1: }{10: 7 }xyz |
+ {1: }{10: 8 }xyz │{1: }{10: 8 }xyz |
+ {1: }{10: 9 }{8:ABC}{9:abc }│{1: }{10: 9 }{8:DEF}{9:abc }|
+ {1: }{10: 10 }{8:ABC}{9:abc }│{1: }{10: 10 }{8:DEF}{9:abc }|
+ {1: }{10: 11 }{8:ABC}{9:abc }│{1: }{10: 11 }{8:DEF}{9:abc }|
+ {1: }{10: 12 }common line │{1: }{10: 12 }common line |
+ {1: }{10: 13 }common line │{1: }{10: 13 }common line |
+ {1: }{10: }{2:-------------------------------------------}│{1: }{10: 14 }{4:DEF }|
+ {1: }{10: 14 }common line │{1: }{10: 15 }common line |
+ {1: }{10: }{2:-------------------------------------------}│{1: }{10: 16 }{4:DEF }|
+ {1: }{10: 15 }something │{1: }{10: 17 }something |
+ {1: }{10: 16 } │{1: }{10: 18 } |
+ {3:Xtest-functional-diff-screen-1.2 [+] }{7:Xtest-functional-diff-screen-1 }|
+ :e |
+ ]])
+ end)
+ it('put from window 2 using dp line 8', function()
+ feed('2<c-w>w')
+ feed('8gg')
+ feed('dp')
+ screen:expect([[
+ {1: }{10: 1 } │{1: }{10: 1 } |
+ {1: }{10: 2 }common line │{1: }{10: 2 }common line |
+ {1: }{10: 3 }common line │{1: }{10: 3 }common line |
+ {1: }{10: 4 } │{1: }{10: 4 } |
+ {1: }{10: 5 }{8:ABC}{9:abc }│{1: }{10: 5 }{8:DEF}{9:abc }|
+ {1: }{10: 6 }xyz │{1: }{10: 6 }xyz |
+ {1: }{10: 7 }xyz │{1: }{10: 7 }xyz |
+ {1: }{10: 8 }xyz │{1: }{10: 8 }^xyz |
+ {1: }{10: 9 }{8:ABC}{9:abc }│{1: }{10: 9 }{8:DEF}{9:abc }|
+ {1: }{10: 10 }{8:ABC}{9:abc }│{1: }{10: 10 }{8:DEF}{9:abc }|
+ {1: }{10: 11 }{8:ABC}{9:abc }│{1: }{10: 11 }{8:DEF}{9:abc }|
+ {1: }{10: 12 }common line │{1: }{10: 12 }common line |
+ {1: }{10: 13 }common line │{1: }{10: 13 }common line |
+ {1: }{10: }{2:-------------------------------------------}│{1: }{10: 14 }{4:DEF }|
+ {1: }{10: 14 }common line │{1: }{10: 15 }common line |
+ {1: }{10: }{2:-------------------------------------------}│{1: }{10: 16 }{4:DEF }|
+ {1: }{10: 15 }something │{1: }{10: 17 }something |
+ {1: }{10: 16 } │{1: }{10: 18 } |
+ {3:Xtest-functional-diff-screen-1.2 [+] }{7:Xtest-functional-diff-screen-1 }|
+ :e |
+ ]])
+ end)
+ it('put from window 2 using dp line 9', function()
+ feed('2<c-w>w')
+ feed('9gg')
+ feed('dp')
+ screen:expect([[
+ {1: }{10: 1 } │{1: }{10: 1 } |
+ {1: }{10: 2 }common line │{1: }{10: 2 }common line |
+ {1: }{10: 3 }common line │{1: }{10: 3 }common line |
+ {1: }{10: 4 } │{1: }{10: 4 } |
+ {1: }{10: 5 }{8:ABC}{9:abc }│{1: }{10: 5 }{8:DEF}{9:abc }|
+ {1: }{10: }{2:-------------------------------------------}│{1: }{10: 6 }{4:xyz }|
+ {1: }{10: }{2:-------------------------------------------}│{1: }{10: 7 }{4:xyz }|
+ {1: }{10: }{2:-------------------------------------------}│{1: }{10: 8 }{4:xyz }|
+ {1: }{10: 6 }DEFabc │{1: }{10: 9 }^DEFabc |
+ {1: }{10: 7 }DEFabc │{1: }{10: 10 }DEFabc |
+ {1: }{10: 8 }DEFabc │{1: }{10: 11 }DEFabc |
+ {1: }{10: 9 }common line │{1: }{10: 12 }common line |
+ {1: }{10: 10 }common line │{1: }{10: 13 }common line |
+ {1: }{10: }{2:-------------------------------------------}│{1: }{10: 14 }{4:DEF }|
+ {1: }{10: 11 }common line │{1: }{10: 15 }common line |
+ {1: }{10: }{2:-------------------------------------------}│{1: }{10: 16 }{4:DEF }|
+ {1: }{10: 12 }something │{1: }{10: 17 }something |
+ {1: }{10: 13 } │{1: }{10: 18 } |
+ {3:Xtest-functional-diff-screen-1.2 [+] }{7:Xtest-functional-diff-screen-1 }|
+ :e |
+ ]])
+ end)
+ it('put from window 2 using dp line 17', function()
+ feed('2<c-w>w')
+ feed('17gg')
+ feed('dp')
+ screen:expect([[
+ {1: }{10: 1 } │{1: }{10: 1 } |
+ {1: }{10: 2 }common line │{1: }{10: 2 }common line |
+ {1: }{10: 3 }common line │{1: }{10: 3 }common line |
+ {1: }{10: 4 } │{1: }{10: 4 } |
+ {1: }{10: 5 }{8:ABC}{9:abc }│{1: }{10: 5 }{8:DEF}{9:abc }|
+ {1: }{10: }{2:-------------------------------------------}│{1: }{10: 6 }{4:xyz }|
+ {1: }{10: }{2:-------------------------------------------}│{1: }{10: 7 }{4:xyz }|
+ {1: }{10: }{2:-------------------------------------------}│{1: }{10: 8 }{4:xyz }|
+ {1: }{10: 6 }{8:ABC}{9:abc }│{1: }{10: 9 }{8:DEF}{9:abc }|
+ {1: }{10: 7 }{8:ABC}{9:abc }│{1: }{10: 10 }{8:DEF}{9:abc }|
+ {1: }{10: 8 }{8:ABC}{9:abc }│{1: }{10: 11 }{8:DEF}{9:abc }|
+ {1: }{10: 9 }common line │{1: }{10: 12 }common line |
+ {1: }{10: 10 }common line │{1: }{10: 13 }common line |
+ {1: }{10: }{2:-------------------------------------------}│{1: }{10: 14 }{4:DEF }|
+ {1: }{10: 11 }common line │{1: }{10: 15 }common line |
+ {1: }{10: 12 }DEF │{1: }{10: 16 }DEF |
+ {1: }{10: 13 }something │{1: }{10: 17 }^something |
+ {1: }{10: 14 } │{1: }{10: 18 } |
+ {3:Xtest-functional-diff-screen-1.2 [+] }{7:Xtest-functional-diff-screen-1 }|
+ :e |
+ ]])
+
+ end)
+ end)
+ describe('setup a diff with 2 files and set linematch:10', function()
+ before_each(function()
+ feed(':set diffopt+=linematch:10<cr>')
+ local f1 = [[
+common line
+HIL
+
+aABCabc
+aABCabc
+aABCabc
+aABCabc
+common line
+HIL
+common line
+something
+ ]]
+ local f2 = [[
+common line
+DEF
+GHI
+something
+
+aDEFabc
+xyz
+xyz
+xyz
+aDEFabc
+aDEFabc
+aDEFabc
+common line
+DEF
+GHI
+something else
+common line
+something
+ ]]
+ write_file(fname, f1, false)
+ write_file(fname_2, f2, false)
+ reread()
+ end)
+
+ it('enable linematch for the longest diff block by increasing the number argument passed to linematch', function()
+ feed('1<c-w>w')
+ -- linematch is disabled for the longest diff because it's combined line length is over 10
+ screen:expect([[
+ {1: }{10: 1 }^common line │{1: }{10: 1 }common line |
+ {1: }{10: 2 }{4:DEF }│{1: }{10: }{2:--------------------------------------------}|
+ {1: }{10: 3 }{8:GHI}{9: }│{1: }{10: 2 }{8:HIL}{9: }|
+ {1: }{10: 4 }{4:something }│{1: }{10: }{2:--------------------------------------------}|
+ {1: }{10: 5 } │{1: }{10: 3 } |
+ {1: }{10: 6 }{9:a}{8:DEF}{9:abc }│{1: }{10: 4 }{9:a}{8:ABC}{9:abc }|
+ {1: }{10: 7 }{8:xyz}{9: }│{1: }{10: 5 }{8:aABCabc}{9: }|
+ {1: }{10: 8 }{8:xyz}{9: }│{1: }{10: 6 }{8:aABCabc}{9: }|
+ {1: }{10: 9 }{8:xyz}{9: }│{1: }{10: 7 }{8:aABCabc}{9: }|
+ {1: }{10: 10 }{4:aDEFabc }│{1: }{10: }{2:--------------------------------------------}|
+ {1: }{10: 11 }{4:aDEFabc }│{1: }{10: }{2:--------------------------------------------}|
+ {1: }{10: 12 }{4:aDEFabc }│{1: }{10: }{2:--------------------------------------------}|
+ {1: }{10: 13 }common line │{1: }{10: 8 }common line |
+ {1: }{10: 14 }{4:DEF }│{1: }{10: }{2:--------------------------------------------}|
+ {1: }{10: 15 }{8:GHI}{9: }│{1: }{10: 9 }{8:HIL}{9: }|
+ {1: }{10: 16 }{4:something else }│{1: }{10: }{2:--------------------------------------------}|
+ {1: }{10: 17 }common line │{1: }{10: 10 }common line |
+ {1: }{10: 18 }something │{1: }{10: 11 }something |
+ {7:Xtest-functional-diff-screen-1.2 }{3:Xtest-functional-diff-screen-1 }|
+ :e |
+ ]])
+ -- enable it by increasing the number
+ feed(":set diffopt-=linematch:10<cr>")
+ feed(":set diffopt+=linematch:30<cr>")
+ screen:expect([[
+ {1: }{10: 1 }^common line │{1: }{10: 1 }common line |
+ {1: }{10: 2 }{4:DEF }│{1: }{10: }{2:--------------------------------------------}|
+ {1: }{10: 3 }{8:GHI}{9: }│{1: }{10: 2 }{8:HIL}{9: }|
+ {1: }{10: 4 }{4:something }│{1: }{10: }{2:--------------------------------------------}|
+ {1: }{10: 5 } │{1: }{10: 3 } |
+ {1: }{10: 6 }{9:a}{8:DEF}{9:abc }│{1: }{10: 4 }{9:a}{8:ABC}{9:abc }|
+ {1: }{10: 7 }{4:xyz }│{1: }{10: }{2:--------------------------------------------}|
+ {1: }{10: 8 }{4:xyz }│{1: }{10: }{2:--------------------------------------------}|
+ {1: }{10: 9 }{4:xyz }│{1: }{10: }{2:--------------------------------------------}|
+ {1: }{10: 10 }{9:a}{8:DEF}{9:abc }│{1: }{10: 5 }{9:a}{8:ABC}{9:abc }|
+ {1: }{10: 11 }{9:a}{8:DEF}{9:abc }│{1: }{10: 6 }{9:a}{8:ABC}{9:abc }|
+ {1: }{10: 12 }{9:a}{8:DEF}{9:abc }│{1: }{10: 7 }{9:a}{8:ABC}{9:abc }|
+ {1: }{10: 13 }common line │{1: }{10: 8 }common line |
+ {1: }{10: 14 }{4:DEF }│{1: }{10: }{2:--------------------------------------------}|
+ {1: }{10: 15 }{8:GHI}{9: }│{1: }{10: 9 }{8:HIL}{9: }|
+ {1: }{10: 16 }{4:something else }│{1: }{10: }{2:--------------------------------------------}|
+ {1: }{10: 17 }common line │{1: }{10: 10 }common line |
+ {1: }{10: 18 }something │{1: }{10: 11 }something |
+ {7:Xtest-functional-diff-screen-1.2 }{3:Xtest-functional-diff-screen-1 }|
+ :set diffopt+=linematch:30 |
+ ]])
+ end)
+ it('get all from second window', function()
+ feed('2<c-w>w')
+ feed(':1,12diffget<cr>')
+ screen:expect([[
+ {1: }{10: 1 }common line │{1: }{10: 1 }^common line |
+ {1: }{10: 2 }DEF │{1: }{10: 2 }DEF |
+ {1: }{10: 3 }GHI │{1: }{10: 3 }GHI |
+ {1: }{10: 4 }something │{1: }{10: 4 }something |
+ {1: }{10: 5 } │{1: }{10: 5 } |
+ {1: }{10: 6 }aDEFabc │{1: }{10: 6 }aDEFabc |
+ {1: }{10: 7 }xyz │{1: }{10: 7 }xyz |
+ {1: }{10: 8 }xyz │{1: }{10: 8 }xyz |
+ {1: }{10: 9 }xyz │{1: }{10: 9 }xyz |
+ {1: }{10: 10 }aDEFabc │{1: }{10: 10 }aDEFabc |
+ {1: }{10: 11 }aDEFabc │{1: }{10: 11 }aDEFabc |
+ {1: }{10: 12 }aDEFabc │{1: }{10: 12 }aDEFabc |
+ {1: }{10: 13 }common line │{1: }{10: 13 }common line |
+ {1: }{10: 14 }DEF │{1: }{10: 14 }DEF |
+ {1: }{10: 15 }GHI │{1: }{10: 15 }GHI |
+ {1: }{10: 16 }something else │{1: }{10: 16 }something else |
+ {1: }{10: 17 }common line │{1: }{10: 17 }common line |
+ {1: }{10: 18 }something │{1: }{10: 18 }something |
+ {3:Xtest-functional-diff-screen-1.2 }{7:Xtest-functional-diff-screen-1 [+] }|
+ :1,12diffget |
+ ]])
+ end)
+ it('get all from first window', function()
+ feed('1<c-w>w')
+ feed(':1,19diffget<cr>')
+ screen:expect([[
+ {1: }{10: 1 }^common line │{1: }{10: 1 }common line |
+ {1: }{10: 2 }HIL │{1: }{10: 2 }HIL |
+ {1: }{10: 3 } │{1: }{10: 3 } |
+ {1: }{10: 4 }aABCabc │{1: }{10: 4 }aABCabc |
+ {1: }{10: 5 }aABCabc │{1: }{10: 5 }aABCabc |
+ {1: }{10: 6 }aABCabc │{1: }{10: 6 }aABCabc |
+ {1: }{10: 7 }aABCabc │{1: }{10: 7 }aABCabc |
+ {1: }{10: 8 }common line │{1: }{10: 8 }common line |
+ {1: }{10: 9 }HIL │{1: }{10: 9 }HIL |
+ {1: }{10: 10 }common line │{1: }{10: 10 }common line |
+ {1: }{10: 11 }something │{1: }{10: 11 }something |
+ {1: }{10: 12 } │{1: }{10: 12 } |
+ {6:~ }│{6:~ }|
+ {6:~ }│{6:~ }|
+ {6:~ }│{6:~ }|
+ {6:~ }│{6:~ }|
+ {6:~ }│{6:~ }|
+ {6:~ }│{6:~ }|
+ {7:Xtest-functional-diff-screen-1.2 [+] }{3:Xtest-functional-diff-screen-1 }|
+ :1,19diffget |
+ ]])
+ end)
+ it('get part of the non linematched diff block in window 2 line 7 - 8 (non line matched block)', function()
+ feed('2<c-w>w')
+ feed(':7,8diffget<cr>')
+ screen:expect([[
+ {1: }{10: 1 }common line │{1: }{10: 1 }^common line |
+ {1: }{10: 2 }{4:DEF }│{1: }{10: }{2:--------------------------------------------}|
+ {1: }{10: 3 }{8:GHI}{9: }│{1: }{10: 2 }{8:HIL}{9: }|
+ {1: }{10: 4 }{4:something }│{1: }{10: }{2:--------------------------------------------}|
+ {1: }{10: 5 } │{1: }{10: 3 } |
+ {1: }{10: 6 }{9:a}{8:DEF}{9:abc }│{1: }{10: 4 }{9:a}{8:ABC}{9:abc }|
+ {1: }{10: 7 }{8:xyz}{9: }│{1: }{10: 5 }{8:aABCabc}{9: }|
+ {1: }{10: 8 }{8:xyz}{9: }│{1: }{10: 6 }{8:aABCabc}{9: }|
+ {1: }{10: 9 }xyz │{1: }{10: 7 }xyz |
+ {1: }{10: 10 }aDEFabc │{1: }{10: 8 }aDEFabc |
+ {1: }{10: 11 }aDEFabc │{1: }{10: 9 }aDEFabc |
+ {1: }{10: 12 }aDEFabc │{1: }{10: 10 }aDEFabc |
+ {1: }{10: 13 }common line │{1: }{10: 11 }common line |
+ {1: }{10: 14 }{4:DEF }│{1: }{10: }{2:--------------------------------------------}|
+ {1: }{10: 15 }{8:GHI}{9: }│{1: }{10: 12 }{8:HIL}{9: }|
+ {1: }{10: 16 }{4:something else }│{1: }{10: }{2:--------------------------------------------}|
+ {1: }{10: 17 }common line │{1: }{10: 13 }common line |
+ {1: }{10: 18 }something │{1: }{10: 14 }something |
+ {3:Xtest-functional-diff-screen-1.2 }{7:Xtest-functional-diff-screen-1 [+] }|
+ :7,8diffget |
+ ]])
+ end)
+ it('get part of the non linematched diff block in window 2 line 8 - 10 (line matched block)', function()
+ feed('2<c-w>w')
+ feed(':8,10diffget<cr>')
+ screen:expect([[
+ {1: }{10: 1 }common line │{1: }{10: 1 }^common line |
+ {1: }{10: 2 }{4:DEF }│{1: }{10: }{2:--------------------------------------------}|
+ {1: }{10: 3 }{8:GHI}{9: }│{1: }{10: 2 }{8:HIL}{9: }|
+ {1: }{10: 4 }{4:something }│{1: }{10: }{2:--------------------------------------------}|
+ {1: }{10: 5 } │{1: }{10: 3 } |
+ {1: }{10: 6 }{9:a}{8:DEF}{9:abc }│{1: }{10: 4 }{9:a}{8:ABC}{9:abc }|
+ {1: }{10: 7 }{8:xyz}{9: }│{1: }{10: 5 }{8:aABCabc}{9: }|
+ {1: }{10: 8 }{8:xyz}{9: }│{1: }{10: 6 }{8:aABCabc}{9: }|
+ {1: }{10: 9 }{8:xyz}{9: }│{1: }{10: 7 }{8:aABCabc}{9: }|
+ {1: }{10: 10 }{4:aDEFabc }│{1: }{10: }{2:--------------------------------------------}|
+ {1: }{10: 11 }{4:aDEFabc }│{1: }{10: }{2:--------------------------------------------}|
+ {1: }{10: 12 }{4:aDEFabc }│{1: }{10: }{2:--------------------------------------------}|
+ {1: }{10: 13 }common line │{1: }{10: 8 }common line |
+ {1: }{10: 14 }DEF │{1: }{10: 9 }DEF |
+ {1: }{10: 15 }GHI │{1: }{10: 10 }GHI |
+ {1: }{10: 16 }something else │{1: }{10: 11 }something else |
+ {1: }{10: 17 }common line │{1: }{10: 12 }common line |
+ {1: }{10: 18 }something │{1: }{10: 13 }something |
+ {3:Xtest-functional-diff-screen-1.2 }{7:Xtest-functional-diff-screen-1 [+] }|
+ :8,10diffget |
+ ]])
+ end)
+ end)
+end)
diff --git a/test/functional/ui/sign_spec.lua b/test/functional/ui/sign_spec.lua
index ff3e143126..a1683a32c9 100644
--- a/test/functional/ui/sign_spec.lua
+++ b/test/functional/ui/sign_spec.lua
@@ -158,7 +158,7 @@ describe('Signs', function()
]])
end)
- it('higlights the cursorline sign with culhl', function()
+ it('highlights the cursorline sign with culhl', function()
feed('ia<cr>b<cr>c<esc>')
command('sign define piet text=>> texthl=Search culhl=ErrorMsg')
command('sign place 1 line=1 name=piet buffer=1')
diff --git a/test/functional/vimscript/eval_spec.lua b/test/functional/vimscript/eval_spec.lua
index 64a3cf5471..9b0ace0882 100644
--- a/test/functional/vimscript/eval_spec.lua
+++ b/test/functional/vimscript/eval_spec.lua
@@ -16,7 +16,6 @@ local lfs = require('lfs')
local clear = helpers.clear
local eq = helpers.eq
local exc_exec = helpers.exc_exec
-local exec = helpers.exec
local exec_lua = helpers.exec_lua
local exec_capture = helpers.exec_capture
local eval = helpers.eval
@@ -152,79 +151,6 @@ describe('List support code', function()
end)
end)
--- oldtest: Test_deep_nest()
-it('Error when if/for/while/try/function is nested too deep',function()
- clear()
- local screen = Screen.new(80, 24)
- screen:attach()
- meths.set_option('laststatus', 2)
- exec([[
- " Deep nesting of if ... endif
- func Test1()
- let @a = join(repeat(['if v:true'], 51), "\n")
- let @a ..= "\n"
- let @a ..= join(repeat(['endif'], 51), "\n")
- @a
- let @a = ''
- endfunc
-
- " Deep nesting of for ... endfor
- func Test2()
- let @a = join(repeat(['for i in [1]'], 51), "\n")
- let @a ..= "\n"
- let @a ..= join(repeat(['endfor'], 51), "\n")
- @a
- let @a = ''
- endfunc
-
- " Deep nesting of while ... endwhile
- func Test3()
- let @a = join(repeat(['while v:true'], 51), "\n")
- let @a ..= "\n"
- let @a ..= join(repeat(['endwhile'], 51), "\n")
- @a
- let @a = ''
- endfunc
-
- " Deep nesting of try ... endtry
- func Test4()
- let @a = join(repeat(['try'], 51), "\n")
- let @a ..= "\necho v:true\n"
- let @a ..= join(repeat(['endtry'], 51), "\n")
- @a
- let @a = ''
- endfunc
-
- " Deep nesting of function ... endfunction
- func Test5()
- let @a = join(repeat(['function X()'], 51), "\n")
- let @a ..= "\necho v:true\n"
- let @a ..= join(repeat(['endfunction'], 51), "\n")
- @a
- let @a = ''
- endfunc
- ]])
- screen:expect({any = '%[No Name%]'})
- feed(':call Test1()<CR>')
- screen:expect({any = 'E579: '})
- feed('<C-C>')
- screen:expect({any = '%[No Name%]'})
- feed(':call Test2()<CR>')
- screen:expect({any = 'E585: '})
- feed('<C-C>')
- screen:expect({any = '%[No Name%]'})
- feed(':call Test3()<CR>')
- screen:expect({any = 'E585: '})
- feed('<C-C>')
- screen:expect({any = '%[No Name%]'})
- feed(':call Test4()<CR>')
- screen:expect({any = 'E601: '})
- feed('<C-C>')
- screen:expect({any = '%[No Name%]'})
- feed(':call Test5()<CR>')
- screen:expect({any = 'E1058: '})
-end)
-
describe("uncaught exception", function()
before_each(clear)
after_each(function()
diff --git a/test/functional/vimscript/null_spec.lua b/test/functional/vimscript/null_spec.lua
index 2451da983e..1153baac46 100644
--- a/test/functional/vimscript/null_spec.lua
+++ b/test/functional/vimscript/null_spec.lua
@@ -69,7 +69,7 @@ describe('NULL', function()
null_expr_test('can be splice-indexed', 'L[:]', 0, {})
null_expr_test('is not locked', 'islocked("v:_null_list")', 0, 0)
null_test('is accepted by :for', 'for x in L|throw x|endfor', 0)
- null_expr_test('does not crash append()', 'append(1, L)', 0, 0, function()
+ null_expr_test('does not crash append()', 'append(0, L)', 0, 0, function()
eq({''}, curbufmeths.get_lines(0, -1, false))
end)
null_expr_test('does not crash setline()', 'setline(1, L)', 0, 0, function()