summaryrefslogtreecommitdiffstats
path: root/src/testdir
diff options
context:
space:
mode:
Diffstat (limited to 'src/testdir')
-rw-r--r--src/testdir/Make_all.mak18
-rw-r--r--src/testdir/Make_mvc.mak8
-rw-r--r--src/testdir/Makefile4
-rw-r--r--src/testdir/README.txt83
-rw-r--r--src/testdir/commondumps.vim76
-rw-r--r--src/testdir/crash/dialog_changed_uafbin0 -> 552 bytes
-rw-r--r--src/testdir/crash/double_freebin0 -> 561 bytes
-rw-r--r--src/testdir/crash/heap_overflow3bin0 -> 700 bytes
-rw-r--r--src/testdir/crash/nullpointerbin0 -> 315 bytes
-rw-r--r--src/testdir/crash/reverse_text_overflowbin0 -> 314 bytes
-rw-r--r--src/testdir/dumps/Test_breakindent_with_double_width_wrap_1.dump6
-rw-r--r--src/testdir/dumps/Test_cmdwin_no_terminal.dump2
-rw-r--r--src/testdir/dumps/Test_matchparen_mbyte_1.dump10
-rw-r--r--src/testdir/dumps/Test_matchparen_mbyte_2.dump10
-rw-r--r--src/testdir/dumps/Test_matchparen_mbyte_3.dump10
-rw-r--r--src/testdir/dumps/Test_matchparen_mbyte_4.dump10
-rw-r--r--src/testdir/dumps/Test_matchparen_mbyte_5.dump10
-rw-r--r--src/testdir/dumps/Test_matchparen_mbyte_6.dump10
-rw-r--r--src/testdir/dumps/Test_matchparen_mbyte_7.dump10
-rw-r--r--src/testdir/dumps/Test_matchparen_mbyte_8.dump10
-rw-r--r--src/testdir/dumps/Test_popup_setbuf_01.dump10
-rw-r--r--src/testdir/dumps/Test_popup_setbuf_02.dump10
-rw-r--r--src/testdir/dumps/Test_popup_setbuf_03.dump10
-rw-r--r--src/testdir/dumps/Test_popup_setbuf_04.dump10
-rw-r--r--src/testdir/dumps/Test_popup_setbuf_05.dump10
-rw-r--r--src/testdir/dumps/Test_popup_setbuf_06.dump10
-rw-r--r--src/testdir/dumps/Test_prop_inserts_text_before_double_width_wrap_2.dump3
-rw-r--r--src/testdir/dumps/Test_prop_inserts_text_before_double_width_wrap_3.dump3
-rw-r--r--src/testdir/dumps/Test_pum_highlights_10.dump20
-rw-r--r--src/testdir/dumps/Test_pum_highlights_11.dump20
-rw-r--r--src/testdir/dumps/Test_pum_highlights_12.dump20
-rw-r--r--src/testdir/dumps/Test_pum_highlights_13.dump20
-rw-r--r--src/testdir/dumps/Test_pum_highlights_14.dump20
-rw-r--r--src/testdir/dumps/Test_pum_highlights_15.dump20
-rw-r--r--src/testdir/dumps/Test_pum_highlights_16.dump20
-rw-r--r--src/testdir/dumps/Test_wildmenu_pum_11.dump2
-rw-r--r--src/testdir/dumps/Test_wildmenu_pum_12.dump2
-rw-r--r--src/testdir/dumps/Test_wildmenu_pum_13.dump2
-rw-r--r--src/testdir/dumps/Test_wildmenu_pum_22.dump4
-rw-r--r--src/testdir/gen_opt_test.vim1
-rw-r--r--src/testdir/ru_RU/LC_MESSAGES/__PACKAGE__.mobin0 -> 875 bytes
-rw-r--r--src/testdir/samples/Test_tohtml_basic.c.html47
-rw-r--r--src/testdir/samples/Test_tohtml_basic_no_css.c.html40
-rw-r--r--src/testdir/samples/test.zipbin0 -> 464 bytes
-rw-r--r--src/testdir/samples/testa.zipbin0 -> 1236 bytes
-rw-r--r--src/testdir/test28.in13
-rw-r--r--src/testdir/test28.ok3
-rw-r--r--src/testdir/test_arglist.vim23
-rw-r--r--src/testdir/test_assert.vim9
-rw-r--r--src/testdir/test_autocmd.vim174
-rw-r--r--src/testdir/test_breakindent.vim11
-rw-r--r--src/testdir/test_buffer.vim46
-rw-r--r--src/testdir/test_cd.vim8
-rw-r--r--src/testdir/test_cmdline.vim39
-rw-r--r--src/testdir/test_codestyle.vim12
-rw-r--r--src/testdir/test_cpoptions.vim119
-rw-r--r--src/testdir/test_crash.vim40
-rw-r--r--src/testdir/test_eval_stuff.vim27
-rw-r--r--src/testdir/test_ex_mode.vim100
-rw-r--r--src/testdir/test_excmd.vim2
-rw-r--r--src/testdir/test_filetype.vim217
-rw-r--r--src/testdir/test_findfile.vim35
-rw-r--r--src/testdir/test_fnamemodify.vim2
-rw-r--r--src/testdir/test_fold.vim35
-rw-r--r--src/testdir/test_functions.vim32
-rw-r--r--src/testdir/test_gettext.vim18
-rw-r--r--src/testdir/test_gettext_cp1251.vim35
-rw-r--r--src/testdir/test_gettext_make.vim72
-rw-r--r--src/testdir/test_gettext_makefile_in1.vim7
-rw-r--r--src/testdir/test_gettext_makefile_in2.vim6
-rw-r--r--src/testdir/test_gettext_makefile_in3.vim4
-rw-r--r--src/testdir/test_gettext_makefile_in4.vim6
-rw-r--r--src/testdir/test_gettext_utf8.vim35
-rw-r--r--src/testdir/test_getvar.vim8
-rw-r--r--src/testdir/test_goto.vim7
-rw-r--r--src/testdir/test_gui.vim3
-rw-r--r--src/testdir/test_increment.vim38
-rw-r--r--src/testdir/test_ins_complete.vim118
-rw-r--r--src/testdir/test_jumplist.vim68
-rw-r--r--src/testdir/test_listdict.vim92
-rw-r--r--src/testdir/test_listlbr_utf8.vim6
-rw-r--r--src/testdir/test_mapping.vim43
-rw-r--r--src/testdir/test_matchparen.vim30
-rw-r--r--src/testdir/test_menu.vim41
-rw-r--r--src/testdir/test_normal.vim3
-rw-r--r--src/testdir/test_options.vim10
-rw-r--r--src/testdir/test_partial.vim22
-rw-r--r--src/testdir/test_paste.vim2
-rw-r--r--src/testdir/test_popup.vim93
-rw-r--r--src/testdir/test_popupwin.vim82
-rw-r--r--src/testdir/test_put.vim8
-rw-r--r--src/testdir/test_quickfix.vim4
-rw-r--r--src/testdir/test_regexp_utf8.vim32
-rw-r--r--src/testdir/test_search.vim31
-rw-r--r--src/testdir/test_selectmode.vim16
-rw-r--r--src/testdir/test_signs.vim40
-rw-r--r--src/testdir/test_spell.vim15
-rw-r--r--src/testdir/test_spellfile.vim16
-rw-r--r--src/testdir/test_substitute.vim15
-rw-r--r--src/testdir/test_tabpage.vim58
-rw-r--r--src/testdir/test_tagjump.vim57
-rw-r--r--src/testdir/test_taglist.vim47
-rw-r--r--src/testdir/test_termcodes.vim11
-rw-r--r--src/testdir/test_termdebug.vim205
-rw-r--r--src/testdir/test_textobjects.vim12
-rw-r--r--src/testdir/test_textprop.vim4
-rw-r--r--src/testdir/test_tohtml.vim72
-rw-r--r--src/testdir/test_usercommands.vim4
-rw-r--r--src/testdir/test_vim9_builtin.vim66
-rw-r--r--src/testdir/test_vim9_class.vim469
-rw-r--r--src/testdir/test_vim9_cmd.vim9
-rw-r--r--src/testdir/test_vim9_disassemble.vim90
-rw-r--r--src/testdir/test_vim9_func.vim10
-rw-r--r--src/testdir/test_vim9_script.vim18
-rw-r--r--src/testdir/test_vimscript.vim25
-rw-r--r--src/testdir/test_winfixbuf.vim1
-rw-r--r--src/testdir/test_xxd.vim16
-rw-r--r--src/testdir/test_zip_plugin.vim237
-rw-r--r--src/testdir/view_util.vim2
-rw-r--r--src/testdir/viewdumps.vim11
120 files changed, 3768 insertions, 210 deletions
diff --git a/src/testdir/Make_all.mak b/src/testdir/Make_all.mak
index e31d2b5..67ef641 100644
--- a/src/testdir/Make_all.mak
+++ b/src/testdir/Make_all.mak
@@ -20,7 +20,8 @@ SCRIPTS_TINY = \
test24 \
test25 \
test26 \
- test27
+ test27 \
+ test28
SCRIPTS_TINY_OUT = \
test10.out \
@@ -31,7 +32,8 @@ SCRIPTS_TINY_OUT = \
test24.out \
test25.out \
test26.out \
- test27.out
+ test27.out \
+ test28.out
# Tests for Vim9 script.
TEST_VIM9 = \
@@ -161,6 +163,10 @@ NEW_TESTS = \
test_function_lists \
test_ga \
test_getcwd \
+ test_gettext \
+ test_gettext_cp1251 \
+ test_gettext_utf8 \
+ test_gettext_make \
test_getvar \
test_gf \
test_glob2regpat \
@@ -309,6 +315,7 @@ NEW_TESTS = \
test_textobjects \
test_textprop \
test_timers \
+ test_tohtml \
test_true_false \
test_trycatch \
test_undo \
@@ -335,6 +342,7 @@ NEW_TESTS = \
test_writefile \
test_xdg \
test_xxd \
+ test_zip_plugin \
test_alot_latin \
test_alot_utf8 \
test_alot
@@ -420,6 +428,10 @@ NEW_TESTS_RES = \
test_functions.res \
test_function_lists.res \
test_getcwd.res \
+ test_gettext.res \
+ test_gettext_cp1251.res \
+ test_gettext_utf8.res \
+ test_gettext_make.res \
test_getvar.res \
test_gf.res \
test_gn.res \
@@ -550,6 +562,7 @@ NEW_TESTS_RES = \
test_textobjects.res \
test_textprop.res \
test_timers.res \
+ test_tohtml.res \
test_true_false.res \
test_trycatch.res \
test_undo.res \
@@ -571,6 +584,7 @@ NEW_TESTS_RES = \
test_writefile.res \
test_xdg.res \
test_xxd.res \
+ test_zip_plugin.res \
test_alot_latin.res \
test_alot_utf8.res \
test_alot.res
diff --git a/src/testdir/Make_mvc.mak b/src/testdir/Make_mvc.mak
index 318cd4a..1bf9eae 100644
--- a/src/testdir/Make_mvc.mak
+++ b/src/testdir/Make_mvc.mak
@@ -5,9 +5,9 @@
# Testing may be done with a debug build
!IF EXIST(..\\vimd.exe) && !EXIST(..\\vim.exe)
-VIMPROG = ..\\vimd
+VIMPROG = ..\\vimd.exe
!ELSE
-VIMPROG = ..\\vim
+VIMPROG = ..\\vim.exe
!ENDIF
@@ -42,7 +42,7 @@ report:
else ( echo No failures reported > test_result.log )
$(VIMPROG) -u NONE $(COMMON_ARGS) -S summarize.vim messages
-if exist starttime del starttime
- @echo.
+ @echo:
@echo Test results:
@cmd /c type test_result.log
@if exist test.log ( echo TEST FAILURE & exit /b 1 ) \
@@ -56,7 +56,7 @@ $(NEW_TESTS):
-if exist test.log del test.log
-if exist messages del messages
-if exist starttime del starttime
- @$(MAKE) -nologo -f Make_mvc.mak $@.res VIMPROG=$(VIMPROG)
+ @$(MAKE) -nologo -f Make_mvc.mak VIMPROG=$(VIMPROG) $@.res
@type messages
@if exist test.log exit 1
diff --git a/src/testdir/Makefile b/src/testdir/Makefile
index 4e476f9..7a4c4c4 100644
--- a/src/testdir/Makefile
+++ b/src/testdir/Makefile
@@ -84,7 +84,7 @@ test_vim9:
RM_ON_RUN = test.out X* viminfo
RM_ON_START = test.ok benchmark.out
-RUN_VIM = VIMRUNTIME=$(SCRIPTSOURCE) $(VALGRIND) $(VIMPROG) -f $(GUI_FLAG) -u unix.vim $(NO_INITS) -s dotest.in
+RUN_VIMPROG = VIMRUNTIME=$(SCRIPTSOURCE) $(VALGRIND) $(VIMPROG) -f $(GUI_FLAG) -u unix.vim $(NO_INITS) -s dotest.in
# Delete files that may interfere with running tests. This includes some files
# that may result from working on the tests, not only from running them.
@@ -114,7 +114,7 @@ tinytests: $(SCRIPTS_TINY_OUT)
@# 200 msec is sufficient, but only modern sleep supports a fraction of
@# a second, fall back to a second if it fails.
@-/bin/sh -c "sleep .2 > /dev/null 2>&1 || sleep 1"
- $(RUN_VIM) $*.in $(REDIR_TEST_TO_NULL)
+ $(RUN_VIMPROG) $*.in $(REDIR_TEST_TO_NULL)
@# Check if the test.out file matches test.ok.
@/bin/sh -c "if test -f test.out; then \
diff --git a/src/testdir/README.txt b/src/testdir/README.txt
index f72bdbf..203c324 100644
--- a/src/testdir/README.txt
+++ b/src/testdir/README.txt
@@ -97,8 +97,7 @@ tests are successful, then this file will be an empty file.
- To execute only specific test functions, add a second argument:
- $ ../vim -u NONE -S runtest.vim test_channel.vim open_delay
-
+ $ ../vim -u NONE -S runtest.vim test_channel.vim open_delay
- To run all the tests:
@@ -119,3 +118,83 @@ tests are successful, then this file will be an empty file.
- To cleanup the temporary files after running the tests:
$ make clean
+
+
+VIEWING GENERATED SCREENDUMPS (local):
+
+You may also wish to look at the whole batch of failed screendumps after
+running "make". Source the "viewdumps.vim" script for this task:
+
+ $ ../vim -u NONE -S viewdumps.vim \
+ [dumps/Test_xxd_*.dump ...]
+
+By default, all screendumps found in the "failed" directory will be added to
+the argument list and then the first one will be loaded. Loaded screendumps
+that bear filenames of screendumps found in the "dumps" directory will be
+rendering the contents of any such pair of files and the difference between
+them (:help term_dumpdiff()); otherwise, they will be rendering own contents
+(:help term_dumpload()). Remember to execute :edit when occasionally you see
+raw file contents instead of rendered.
+
+At any time, you can add, list, and abandon other screendumps:
+
+ :$argedit dumps/Test_spell_*.dump
+ :args
+ :qall
+
+The listing of argument commands can be found under :help buffer-list.
+
+
+VIEWING GENERATED SCREENDUMPS (from a CI-uploaded artifact):
+
+After you have downloaded an artifact archive containing failed screendumps
+and extracted its files in a temporary directory, you need to set up a "dumps"
+directory by creating a symlink:
+
+ $ cd /path/to/fork
+ $ ln -s $(pwd)/src/testdir/dumps /tmp/src/testdir/dumps
+
+You can now examine the extracted screendumps:
+
+ $ ./src/vim -u NONE -S src/testdir/viewdumps.vim \
+ /tmp/src/testdir/failed/*.dump
+
+
+VIEWING GENERATED SCREENDUMPS (submitted for a pull request):
+
+First, you need to check out the topic branch with the proposed changes and
+write down a difference list between the HEAD commit (index) and its parent
+commit with respect to the changed "dumps" filenames:
+
+ $ cd /path/to/fork
+ $ git switch prs/1234
+ $ git diff-index --relative=src/testdir/dumps/ \
+ --name-only prs/1234~1 > /tmp/filelist
+
+Then, you need to check out the master branch, change the current working
+directory to reconcile relative filepaths written in the filenames list,
+possibly create an empty "failed" directory, copy in this directory the old
+"dumps" files, whose names are on the same list, and follow it by checking out
+the topic branch:
+
+ $ git switch master
+ $ cd src/testdir/dumps
+ $ test -d ../failed || mkdir ../failed
+ $ cp -t ../failed $(cat /tmp/filelist)
+ $ git switch prs/1234
+
+Make note of any missing new screendumps. Please remember about the
+introduced INVERTED relation between "dumps" and "failed", i.e. the files to
+be committed are in "dumps" already and their old versions are in "failed".
+Therefore, you need to copy the missing new screendumps from "dumps" to
+"failed":
+
+ $ cp -t ../failed foo_10.dump foo_11.dump foo_12.dump
+
+After you have changed the current working directory to its parent directory,
+you can now examine the screendumps from the "failed" directory (note that new
+screendumps will be shown with no difference between their versions):
+
+ $ cd ..
+ $ ../vim -u NONE -S viewdumps.vim
+
diff --git a/src/testdir/commondumps.vim b/src/testdir/commondumps.vim
new file mode 100644
index 0000000..ed70280
--- /dev/null
+++ b/src/testdir/commondumps.vim
@@ -0,0 +1,76 @@
+vim9script
+
+# (Script-local.)
+#
+# Render a loaded screendump file or the difference of a loaded screendump
+# file and its namesake file from the "dumps" directory.
+def Render()
+ const failed_fname: string = bufname()
+ try
+ setlocal suffixesadd=.dump
+ const dumps_fname: string = findfile(
+ fnamemodify(failed_fname, ':p:t'),
+ fnamemodify(failed_fname, ':p:h:h') .. '/dumps')
+ if filereadable(dumps_fname)
+ term_dumpdiff(failed_fname, dumps_fname)
+ else
+ term_dumpload(failed_fname)
+ endif
+ finally
+ exec 'bwipeout ' .. failed_fname
+ endtry
+enddef
+
+# Search for the "failed" directory in the passed _subtreedirname_ directories
+# (usually "\<src\>" or "\<syntax\>") and, if found, select its passed _count_
+# occurence, add all its "*.dump" files to the argument list and list them;
+# also define a BufRead autocommand that would invoke "Render()" for every
+# "*.dump" file.
+def g:Init(subtreedirname: string, count: number)
+ # Support sourcing this script from any directory in the direct path that
+ # leads to the project's root directory.
+ const failed_path: string = finddir('failed', getcwd() .. '/**', -1)
+ ->filter(((cwdpath: string, parentdirname: string) =>
+ (_: number, dirpath: string) =>
+ cwdpath =~ parentdirname || dirpath =~ parentdirname)(
+ getcwd(),
+ subtreedirname))
+ ->get(count, '') .. '/'
+ var error: string = null_string
+
+ if failed_path == '/'
+ error = 'No such directory: "failed"'
+ else
+ const failed_fnames: string = failed_path .. readdir(failed_path,
+ (fname: string) => fname =~ '^.\+\.dump$')
+ ->join(' ' .. failed_path)
+
+ if failed_fnames =~ 'failed/$'
+ error = 'No such file: "*.dump"'
+ else
+ exec ':0argedit ' .. failed_fnames
+ buffers
+ endif
+ endif
+
+ autocmd_add([{
+ replace: true,
+ group: 'viewdumps',
+ event: 'BufRead',
+ pattern: '*.dump',
+ cmd: 'Render()',
+ }])
+
+ # Unconditionally help, in case a list of filenames is passed to the
+ # command, the first terminal window with its BufRead event.
+ silent doautocmd viewdumps BufRead
+
+ if error != null_string
+ # Instead of sleeping, fill half a window with blanks and prompt
+ # hit-enter.
+ echom error .. repeat("\x20",
+ (winwidth(0) * (winheight(0) / 2) - strlen(error)))
+ endif
+enddef
+
+# vim:fdm=syntax:sw=2:ts=8:noet:nolist:nosta:
diff --git a/src/testdir/crash/dialog_changed_uaf b/src/testdir/crash/dialog_changed_uaf
new file mode 100644
index 0000000..e37d18d
--- /dev/null
+++ b/src/testdir/crash/dialog_changed_uaf
Binary files differ
diff --git a/src/testdir/crash/double_free b/src/testdir/crash/double_free
new file mode 100644
index 0000000..895c4a0
--- /dev/null
+++ b/src/testdir/crash/double_free
Binary files differ
diff --git a/src/testdir/crash/heap_overflow3 b/src/testdir/crash/heap_overflow3
new file mode 100644
index 0000000..c40adbe
--- /dev/null
+++ b/src/testdir/crash/heap_overflow3
Binary files differ
diff --git a/src/testdir/crash/nullpointer b/src/testdir/crash/nullpointer
new file mode 100644
index 0000000..c8ff3a4
--- /dev/null
+++ b/src/testdir/crash/nullpointer
Binary files differ
diff --git a/src/testdir/crash/reverse_text_overflow b/src/testdir/crash/reverse_text_overflow
new file mode 100644
index 0000000..dfbfe2c
--- /dev/null
+++ b/src/testdir/crash/reverse_text_overflow
Binary files differ
diff --git a/src/testdir/dumps/Test_breakindent_with_double_width_wrap_1.dump b/src/testdir/dumps/Test_breakindent_with_double_width_wrap_1.dump
new file mode 100644
index 0000000..7b761bc
--- /dev/null
+++ b/src/testdir/dumps/Test_breakindent_with_double_width_wrap_1.dump
@@ -0,0 +1,6 @@
+| +0&#ffffff0@7|a@40|>+0#4040ff13&
+| +0#0000000&@7>å£*&@2| +&@35
+|~+0#4040ff13&| @48
+|~| @48
+|~| @48
+| +0#0000000&@31|1|,|4|3|-|5|9| @6|A|l@1|
diff --git a/src/testdir/dumps/Test_cmdwin_no_terminal.dump b/src/testdir/dumps/Test_cmdwin_no_terminal.dump
index 97d8147..6de9879 100644
--- a/src/testdir/dumps/Test_cmdwin_no_terminal.dump
+++ b/src/testdir/dumps/Test_cmdwin_no_terminal.dump
@@ -1,6 +1,6 @@
| +0&#ffffff0@74
|[+1&&|N|o| |N|a|m|e|]| @47|0|,|0|-|1| @9|A|l@1
-|:+0#4040ff13&|s+0#af5f00255&|e|t| +0#0000000&|c+0#e000e06&|m|d|h|e|i|g|h|t|=+0#0000000&|2| @58
+|:+0#4040ff13&|s+0#af5f00255&|e|t| +0#0000000&|c+0#e000e06&|m|d|h|e|i|g|h|t|=+0#af5f00255&|2+0#0000000&| @58
|:+0#4040ff13&> +0#0000000&@73
|~+0#4040ff13&| @73
|~| @73
diff --git a/src/testdir/dumps/Test_matchparen_mbyte_1.dump b/src/testdir/dumps/Test_matchparen_mbyte_1.dump
new file mode 100644
index 0000000..f5df150
--- /dev/null
+++ b/src/testdir/dumps/Test_matchparen_mbyte_1.dump
@@ -0,0 +1,10 @@
+>a+0&#ffffff0@7|(*&| +&@64
+|b@3|)*&|c+&@1| @66
+|~+0#4040ff13&| @73
+|~| @73
+|~| @73
+|~| @73
+|~| @73
+|~| @73
+|~| @73
+| +0#0000000&@56|1|,|1| @10|A|l@1|
diff --git a/src/testdir/dumps/Test_matchparen_mbyte_2.dump b/src/testdir/dumps/Test_matchparen_mbyte_2.dump
new file mode 100644
index 0000000..0e4e6e8
--- /dev/null
+++ b/src/testdir/dumps/Test_matchparen_mbyte_2.dump
@@ -0,0 +1,10 @@
+|a+0&#ffffff0@7>(*0&#40ffff15| +0&#ffffff0@64
+|b@3|)*0&#40ffff15|c+0&#ffffff0@1| @66
+|~+0#4040ff13&| @73
+|~| @73
+|~| @73
+|~| @73
+|~| @73
+|~| @73
+|~| @73
+| +0#0000000&@56|1|,|9| @10|A|l@1|
diff --git a/src/testdir/dumps/Test_matchparen_mbyte_3.dump b/src/testdir/dumps/Test_matchparen_mbyte_3.dump
new file mode 100644
index 0000000..85c462a
--- /dev/null
+++ b/src/testdir/dumps/Test_matchparen_mbyte_3.dump
@@ -0,0 +1,10 @@
+|a+0&#ffffff0@7|(*&| +&@64
+|b@3|)*&|c+&>c| @66
+|~+0#4040ff13&| @73
+|~| @73
+|~| @73
+|~| @73
+|~| @73
+|~| @73
+|~| @73
+| +0#0000000&@56|2|,|9|-|8| @8|A|l@1|
diff --git a/src/testdir/dumps/Test_matchparen_mbyte_4.dump b/src/testdir/dumps/Test_matchparen_mbyte_4.dump
new file mode 100644
index 0000000..45f5d08
--- /dev/null
+++ b/src/testdir/dumps/Test_matchparen_mbyte_4.dump
@@ -0,0 +1,10 @@
+|a+0&#ffffff0@7|(*0&#40ffff15| +0&#ffffff0@64
+|b@3>)*0&#40ffff15|c+0&#ffffff0@1| @66
+|~+0#4040ff13&| @73
+|~| @73
+|~| @73
+|~| @73
+|~| @73
+|~| @73
+|~| @73
+| +0#0000000&@56|2|,|5| @10|A|l@1|
diff --git a/src/testdir/dumps/Test_matchparen_mbyte_5.dump b/src/testdir/dumps/Test_matchparen_mbyte_5.dump
new file mode 100644
index 0000000..45c3bfa
--- /dev/null
+++ b/src/testdir/dumps/Test_matchparen_mbyte_5.dump
@@ -0,0 +1,10 @@
+|a+0&#ffffff0@7|(*&| +&@64
+>b@3|)*&|c+&@1| @66
+|~+0#4040ff13&| @73
+|~| @73
+|~| @73
+|~| @73
+|~| @73
+|~| @73
+|~| @73
+| +0#0000000&@56|2|,|1| @10|A|l@1|
diff --git a/src/testdir/dumps/Test_matchparen_mbyte_6.dump b/src/testdir/dumps/Test_matchparen_mbyte_6.dump
new file mode 100644
index 0000000..8064a98
--- /dev/null
+++ b/src/testdir/dumps/Test_matchparen_mbyte_6.dump
@@ -0,0 +1,10 @@
+|a+0&#ffffff0@7|(*0&#40ffff15> +0&#ffffff0@64
+|b@3|)*0&#40ffff15|c+0&#ffffff0@1| @66
+|~+0#4040ff13&| @73
+|~| @73
+|~| @73
+|~| @73
+|~| @73
+|~| @73
+|~| @73
+|-+2#0000000&@1| |I|N|S|E|R|T| |-@1| +0&&@44|1|,|1|2|-|1@1| @6|A|l@1|
diff --git a/src/testdir/dumps/Test_matchparen_mbyte_7.dump b/src/testdir/dumps/Test_matchparen_mbyte_7.dump
new file mode 100644
index 0000000..4d8c647
--- /dev/null
+++ b/src/testdir/dumps/Test_matchparen_mbyte_7.dump
@@ -0,0 +1,10 @@
+|a+0&#ffffff0@7|(*&| +&@64
+|b@3|)*&|c+&@1> @66
+|~+0#4040ff13&| @73
+|~| @73
+|~| @73
+|~| @73
+|~| @73
+|~| @73
+|~| @73
+|-+2#0000000&@1| |I|N|S|E|R|T| |-@1| +0&&@44|2|,|1|0|-|9| @7|A|l@1|
diff --git a/src/testdir/dumps/Test_matchparen_mbyte_8.dump b/src/testdir/dumps/Test_matchparen_mbyte_8.dump
new file mode 100644
index 0000000..c3699fd
--- /dev/null
+++ b/src/testdir/dumps/Test_matchparen_mbyte_8.dump
@@ -0,0 +1,10 @@
+|a+0&#ffffff0@7|(*0&#40ffff15| +0&#ffffff0@64
+|b@3|)*0&#40ffff15> +0&#ffffff0@68
+|~+0#4040ff13&| @73
+|~| @73
+|~| @73
+|~| @73
+|~| @73
+|~| @73
+|~| @73
+|-+2#0000000&@1| |I|N|S|E|R|T| |-@1| +0&&@44|2|,|8|-|7| @8|A|l@1|
diff --git a/src/testdir/dumps/Test_popup_setbuf_01.dump b/src/testdir/dumps/Test_popup_setbuf_01.dump
new file mode 100644
index 0000000..14359ba
--- /dev/null
+++ b/src/testdir/dumps/Test_popup_setbuf_01.dump
@@ -0,0 +1,10 @@
+> +0&#ffffff0@74
+|~+0#4040ff13&| @73
+|~| @73
+|~| @73
+|~| @33|t+0#0000001#ffd7ff255|e|s|t| +0#4040ff13#ffffff0@35
+|~| @73
+|~| @73
+|~| @73
+|~| @73
+| +0#0000000&@56|0|,|0|-|1| @8|A|l@1|
diff --git a/src/testdir/dumps/Test_popup_setbuf_02.dump b/src/testdir/dumps/Test_popup_setbuf_02.dump
new file mode 100644
index 0000000..5feb982
--- /dev/null
+++ b/src/testdir/dumps/Test_popup_setbuf_02.dump
@@ -0,0 +1,10 @@
+> +0&#ffffff0@74
+|~+0#4040ff13&| @73
+|~| @73
+|~| @73
+|~| @33|t+0#0000001#ffd7ff255|e|s|t| +0#4040ff13#ffffff0@35
+|~| @73
+|~| @73
+|~| @73
+|~| @73
+|:+0#0000000&|c|a|l@1| |p|o|p|u|p|_|s|e|t|b|u|f|(|p|,| |'|f|o@1|b|a|r|.|t|x|t|'|)| @21|0|,|0|-|1| @8|A|l@1|
diff --git a/src/testdir/dumps/Test_popup_setbuf_03.dump b/src/testdir/dumps/Test_popup_setbuf_03.dump
new file mode 100644
index 0000000..2c49576
--- /dev/null
+++ b/src/testdir/dumps/Test_popup_setbuf_03.dump
@@ -0,0 +1,10 @@
+|~+0#4040ff13#ffffff0| @73
+|~| @73
+|~| @73
+|~| @33|t+0#0000001#ffd7ff255|e|s|t| +0#4040ff13#ffffff0@35
+|~| @73
+|~| @73
+|~| @73
+|~| @73
+|E+0#ffffff16#e000002|1|2@1|0|:| |S|t|r|i|n|g| |o|r| |N|u|m|b|e|r| |r|e|q|u|i|r|e|d| |f|o|r| |a|r|g|u|m|e|n|t| |2| +0#0000000#ffffff0@27
+|P+0#00e0003&|r|e|s@1| |E|N|T|E|R| |o|r| |t|y|p|e| |c|o|m@1|a|n|d| |t|o| |c|o|n|t|i|n|u|e> +0#0000000&@35
diff --git a/src/testdir/dumps/Test_popup_setbuf_04.dump b/src/testdir/dumps/Test_popup_setbuf_04.dump
new file mode 100644
index 0000000..937fa7c
--- /dev/null
+++ b/src/testdir/dumps/Test_popup_setbuf_04.dump
@@ -0,0 +1,10 @@
+>*+0#ffffff16#ffd7ff255|h+0#e000002&|e|l|p|.|t|x|t|*+0#ffffff16&| +0#0000001&@5|F|o|r| |V+0#00e0e07&|i|m| |v|e|r|s|i|o|n| |9|.|1|.| +0#0000001&@1|L|a|s|t| |c|h|a|n|g|e|:| |2|0|2|4| |M|a|y| |2|7| @11| +0#0000000#0000001
+| +0#0000001#ffd7ff255@73| +0#0000000#a8a8a8255
+| +0#0000001#ffd7ff255@23|V|I|M| |-| |m|a|i|n| |h|e|l|p| |f|i|l|e| @29| +0#0000000#a8a8a8255
+| +0#0000001#ffd7ff255@72|k| +0#0000000#a8a8a8255
+| +0#0000001#ffd7ff255@5|M|o|v|e| |a|r|o|u|n|d|:| @1|U|s|e| |t|h|e| |c|u|r|s|o|r| |k|e|y|s|,| |o|r| |"|h|"| |t|o| |g|o| |l|e|f|t|,| @11|h| @1| +0#0000000#a8a8a8255
+| +0#0000001#ffd7ff255|l| @71| +0#0000000#a8a8a8255
+| +0#0000001#ffd7ff255@19|"|j|"| |t|o| |g|o| |d|o|w|n|,| |"|k|"| |t|o| |g|o| |u|p|,| |"|l|"| |t|o| |g|o| |r|i|g|h|t|.| @6|j| +0#0000000#a8a8a8255
+|C+0#0000001#ffd7ff255|l|o|s|e| |t|h|i|s| |w|i|n|d|o|w|:| @1|U|s|e| |"|:|q|<+0#e000e06&|E|n|t|e|r|>|"+0#0000001&|.| @37| +0#0000000#a8a8a8255
+| +0#0000001#ffd7ff255@2|G|e|t| |o|u|t| |o|f| |V|i|m|:| @1|U|s|e| |"|:|q|a|!|<+0#e000e06&|E|n|t|e|r|>|"+0#0000001&| |(|c|a|r|e|f|u|l|,| |a|l@1| |c|h|a|n|g|e|s| |a|r|e| |l|o|s|t|!|)|.| @2| +0#0000000#a8a8a8255
+| +0#0000001#ffd7ff255@73| +0#0000000#a8a8a8255
diff --git a/src/testdir/dumps/Test_popup_setbuf_05.dump b/src/testdir/dumps/Test_popup_setbuf_05.dump
new file mode 100644
index 0000000..a13dfe3
--- /dev/null
+++ b/src/testdir/dumps/Test_popup_setbuf_05.dump
@@ -0,0 +1,10 @@
+>h+0#e000002#ffffff0|e|l|p|.|t|x|t| +0#0000000&@7|F|o|r| |V+0#00e0e07&|i|m| |v|e|r|s|i|o|n| |9|.|1|.| +0#0000000&@1|L|a|s|t| |c|h|a|n|g|e|:| |2|0|2|4| |M|a|y| |2|7| @12
+@75
+@24|V|I|M| |-| |m|a|i|n| |h|e|l|p| |f|i|l|e| @30
+@73|k|
+@6|M|o|v|e| |a|r|o|u|n|d|:| @1|U|s|e| |t|h|e| |c|u|r|s|o|r| |k|e| +0#0000001#ffd7ff255|s+0#0000000#ffffff0|,| |o|r| |"|h|"| |t|o| |g|o| |l|e|f|t|,| @11|h| @2
+|l| @73
+|h+3&&|e|l|p|.|t|x|t| |[|H|e|l|p|]|[|R|O|]| @37|1|,|1| @11|T|o|p
+| +0&&@74
+|[+1&&|N|o| |N|a|m|e|]| @47|0|,|0|-|1| @9|A|l@1
+| +0&&@74
diff --git a/src/testdir/dumps/Test_popup_setbuf_06.dump b/src/testdir/dumps/Test_popup_setbuf_06.dump
new file mode 100644
index 0000000..937fa7c
--- /dev/null
+++ b/src/testdir/dumps/Test_popup_setbuf_06.dump
@@ -0,0 +1,10 @@
+>*+0#ffffff16#ffd7ff255|h+0#e000002&|e|l|p|.|t|x|t|*+0#ffffff16&| +0#0000001&@5|F|o|r| |V+0#00e0e07&|i|m| |v|e|r|s|i|o|n| |9|.|1|.| +0#0000001&@1|L|a|s|t| |c|h|a|n|g|e|:| |2|0|2|4| |M|a|y| |2|7| @11| +0#0000000#0000001
+| +0#0000001#ffd7ff255@73| +0#0000000#a8a8a8255
+| +0#0000001#ffd7ff255@23|V|I|M| |-| |m|a|i|n| |h|e|l|p| |f|i|l|e| @29| +0#0000000#a8a8a8255
+| +0#0000001#ffd7ff255@72|k| +0#0000000#a8a8a8255
+| +0#0000001#ffd7ff255@5|M|o|v|e| |a|r|o|u|n|d|:| @1|U|s|e| |t|h|e| |c|u|r|s|o|r| |k|e|y|s|,| |o|r| |"|h|"| |t|o| |g|o| |l|e|f|t|,| @11|h| @1| +0#0000000#a8a8a8255
+| +0#0000001#ffd7ff255|l| @71| +0#0000000#a8a8a8255
+| +0#0000001#ffd7ff255@19|"|j|"| |t|o| |g|o| |d|o|w|n|,| |"|k|"| |t|o| |g|o| |u|p|,| |"|l|"| |t|o| |g|o| |r|i|g|h|t|.| @6|j| +0#0000000#a8a8a8255
+|C+0#0000001#ffd7ff255|l|o|s|e| |t|h|i|s| |w|i|n|d|o|w|:| @1|U|s|e| |"|:|q|<+0#e000e06&|E|n|t|e|r|>|"+0#0000001&|.| @37| +0#0000000#a8a8a8255
+| +0#0000001#ffd7ff255@2|G|e|t| |o|u|t| |o|f| |V|i|m|:| @1|U|s|e| |"|:|q|a|!|<+0#e000e06&|E|n|t|e|r|>|"+0#0000001&| |(|c|a|r|e|f|u|l|,| |a|l@1| |c|h|a|n|g|e|s| |a|r|e| |l|o|s|t|!|)|.| @2| +0#0000000#a8a8a8255
+| +0#0000001#ffd7ff255@73| +0#0000000#a8a8a8255
diff --git a/src/testdir/dumps/Test_prop_inserts_text_before_double_width_wrap_2.dump b/src/testdir/dumps/Test_prop_inserts_text_before_double_width_wrap_2.dump
new file mode 100644
index 0000000..6022a16
--- /dev/null
+++ b/src/testdir/dumps/Test_prop_inserts_text_before_double_width_wrap_2.dump
@@ -0,0 +1,3 @@
+|a+0&#ffffff0@39|b+0#e000e06&@8|>+0#4040ff13&
+>å£*0#0000000&|1+&|2|3|4|5| @42
+@32|1|,|4|1|-|5|1| @6|A|l@1|
diff --git a/src/testdir/dumps/Test_prop_inserts_text_before_double_width_wrap_3.dump b/src/testdir/dumps/Test_prop_inserts_text_before_double_width_wrap_3.dump
new file mode 100644
index 0000000..c033399
--- /dev/null
+++ b/src/testdir/dumps/Test_prop_inserts_text_before_double_width_wrap_3.dump
@@ -0,0 +1,3 @@
+|a+0&#ffffff0@39|b+0#e000e06&@8|>+0#4040ff13&
+|+@2>å£*0#0000000&|1+&|2|3|4|5| @39
+|:|s|e|t| |s|h|o|w|b|r|e|a|k|=|+@2| @13|1|,|4|1|-|5|4| @6|A|l@1|
diff --git a/src/testdir/dumps/Test_pum_highlights_10.dump b/src/testdir/dumps/Test_pum_highlights_10.dump
new file mode 100644
index 0000000..790b028
--- /dev/null
+++ b/src/testdir/dumps/Test_pum_highlights_10.dump
@@ -0,0 +1,20 @@
+| +0&#ffffff0|h|e|l@1|o| |h|e|l|i|o| |h|e|r|o| |h|e|l@1|o> @51
+|~+0#4040ff13&| @15| +0#0000001#ffd7ff255|h+0#0000e05&|e+0#0000001&|r|o| @10| +0#4040ff13#ffffff0@41
+|~| @15| +0#0000001#ffd7ff255|h+0#0000e05&|e+0#0000001&|l|i|o| @9| +0#4040ff13#ffffff0@41
+|~| @15| +0#0000001#e0e0e08|h+0#00e0e07&|e+0#0000001&|l@1|o| @9| +0#4040ff13#ffffff0@41
+|~| @73
+|~| @73
+|~| @73
+|~| @73
+|~| @73
+|~| @73
+|~| @73
+|~| @73
+|~| @73
+|~| @73
+|~| @73
+|~| @73
+|~| @73
+|~| @73
+|~| @73
+|-+2#0000000&@1| |K|e|y|w|o|r|d| |L|o|c|a|l| |c|o|m|p|l|e|t|i|o|n| |(|^|N|^|P|)| |m+0#00e0003&|a|t|c|h| |1| |o|f| |3| +0#0000000&@27
diff --git a/src/testdir/dumps/Test_pum_highlights_11.dump b/src/testdir/dumps/Test_pum_highlights_11.dump
new file mode 100644
index 0000000..ef75a89
--- /dev/null
+++ b/src/testdir/dumps/Test_pum_highlights_11.dump
@@ -0,0 +1,20 @@
+| +0&#ffffff0|h|e|l@1|o| |h|e|l|i|o| |h|e|r|o| |h|e|l|i|o> @51
+|~+0#4040ff13&| @15| +0#0000001#ffd7ff255|h+0#0000e05&|e+0#0000001&|r|o| @10| +0#4040ff13#ffffff0@41
+|~| @15| +0#0000001#e0e0e08|h+0#00e0e07&|e+0#0000001&|l|i|o| @9| +0#4040ff13#ffffff0@41
+|~| @15| +0#0000001#ffd7ff255|h+0#0000e05&|e+0#0000001&|l@1|o| @9| +0#4040ff13#ffffff0@41
+|~| @73
+|~| @73
+|~| @73
+|~| @73
+|~| @73
+|~| @73
+|~| @73
+|~| @73
+|~| @73
+|~| @73
+|~| @73
+|~| @73
+|~| @73
+|~| @73
+|~| @73
+|-+2#0000000&@1| |K|e|y|w|o|r|d| |L|o|c|a|l| |c|o|m|p|l|e|t|i|o|n| |(|^|N|^|P|)| |m+0#00e0003&|a|t|c|h| |2| |o|f| |3| +0#0000000&@27
diff --git a/src/testdir/dumps/Test_pum_highlights_12.dump b/src/testdir/dumps/Test_pum_highlights_12.dump
new file mode 100644
index 0000000..a0d2b49
--- /dev/null
+++ b/src/testdir/dumps/Test_pum_highlights_12.dump
@@ -0,0 +1,20 @@
+|a+0&#ffffff0|w|o|r|d|1> @68
+|a+0#ff404010#e0e0e08|w|o|r|d|1| |W| |e|x|t|r|a| |t|e|x|t| |1| | +0#4040ff13#ffffff0@52
+|a+0#0000001#ffd7ff255|w|o|r|d|2| |W| |e|x|t|r|a| |t|e|x|t| |2| | +0#4040ff13#ffffff0@52
+|你*0#ff404010#ffd7ff255|好| +&@2|W| |e|x|t|r|a| |t|e|x|t| |3| | +0#4040ff13#ffffff0@52
+|~| @73
+|~| @73
+|~| @73
+|~| @73
+|~| @73
+|~| @73
+|~| @73
+|~| @73
+|~| @73
+|~| @73
+|~| @73
+|~| @73
+|~| @73
+|~| @73
+|~| @73
+|-+2#0000000&@1| |U|s|e|r| |d|e|f|i|n|e|d| |c|o|m|p|l|e|t|i|o|n| |(|^|U|^|N|^|P|)| |m+0#00e0003&|a|t|c|h| |1| |o|f| |3| +0#0000000&@26
diff --git a/src/testdir/dumps/Test_pum_highlights_13.dump b/src/testdir/dumps/Test_pum_highlights_13.dump
new file mode 100644
index 0000000..34fde12
--- /dev/null
+++ b/src/testdir/dumps/Test_pum_highlights_13.dump
@@ -0,0 +1,20 @@
+|a+0&#ffffff0|w|o|r|d|1> @68
+|a+8#ff404010#e0e0e08|w|o+0&&|r|d|1| |W| |e|x|t|r|a| |t|e|x|t| |1| | +0#4040ff13#ffffff0@52
+|a+8#0000e05#ffd7ff255|w|o+0#0000001&|r|d|2| |W| |e|x|t|r|a| |t|e|x|t| |2| | +0#4040ff13#ffffff0@52
+|你*0#ff404010#ffd7ff255|好| +&@2|W| |e|x|t|r|a| |t|e|x|t| |3| | +0#4040ff13#ffffff0@52
+|~| @73
+|~| @73
+|~| @73
+|~| @73
+|~| @73
+|~| @73
+|~| @73
+|~| @73
+|~| @73
+|~| @73
+|~| @73
+|~| @73
+|~| @73
+|~| @73
+|~| @73
+|-+2#0000000&@1| |U|s|e|r| |d|e|f|i|n|e|d| |c|o|m|p|l|e|t|i|o|n| |(|^|U|^|N|^|P|)| |m+0#00e0003&|a|t|c|h| |1| |o|f| |3| +0#0000000&@26
diff --git a/src/testdir/dumps/Test_pum_highlights_14.dump b/src/testdir/dumps/Test_pum_highlights_14.dump
new file mode 100644
index 0000000..f35b4cb
--- /dev/null
+++ b/src/testdir/dumps/Test_pum_highlights_14.dump
@@ -0,0 +1,20 @@
+|a+0&#ffffff0|w|o|r|d|2> @68
+|a+8#ff404010#ffd7ff255|w|o+0&&|r|d|1| |W| |e|x|t|r|a| |t|e|x|t| |1| | +0#4040ff13#ffffff0@52
+|a+8#00e0e07#e0e0e08|w|o+0#0000001&|r|d|2| |W| |e|x|t|r|a| |t|e|x|t| |2| | +0#4040ff13#ffffff0@52
+|你*0#ff404010#ffd7ff255|好| +&@2|W| |e|x|t|r|a| |t|e|x|t| |3| | +0#4040ff13#ffffff0@52
+|~| @73
+|~| @73
+|~| @73
+|~| @73
+|~| @73
+|~| @73
+|~| @73
+|~| @73
+|~| @73
+|~| @73
+|~| @73
+|~| @73
+|~| @73
+|~| @73
+|~| @73
+|-+2#0000000&@1| |U|s|e|r| |d|e|f|i|n|e|d| |c|o|m|p|l|e|t|i|o|n| |(|^|U|^|N|^|P|)| |m+0#00e0003&|a|t|c|h| |2| |o|f| |3| +0#0000000&@26
diff --git a/src/testdir/dumps/Test_pum_highlights_15.dump b/src/testdir/dumps/Test_pum_highlights_15.dump
new file mode 100644
index 0000000..e923b43
--- /dev/null
+++ b/src/testdir/dumps/Test_pum_highlights_15.dump
@@ -0,0 +1,20 @@
+|/+0&#ffffff0|n|o|n|_|e|x|i|t|_|f|o|l|d|e|r> @58
+|~+0#4040ff13&| @73
+|~| @73
+|~| @73
+|~| @73
+|~| @73
+|~| @73
+|~| @73
+|~| @73
+|~| @73
+|~| @73
+|~| @73
+|~| @73
+|~| @73
+|~| @73
+|~| @73
+|~| @73
+|~| @73
+|~| @73
+|-+2#0000000&@1| |F|i|l|e| |n|a|m|e| |c|o|m|p|l|e|t|i|o|n| |(|^|F|^|N|^|P|)| |P+0#ffffff16#e000002|a|t@1|e|r|n| |n|o|t| |f|o|u|n|d| +0#0000000#ffffff0@24
diff --git a/src/testdir/dumps/Test_pum_highlights_16.dump b/src/testdir/dumps/Test_pum_highlights_16.dump
new file mode 100644
index 0000000..fe2b68d
--- /dev/null
+++ b/src/testdir/dumps/Test_pum_highlights_16.dump
@@ -0,0 +1,20 @@
+|a+0&#ffffff0|w|o|r|d|1> @68
+|a+0#ff404010#e0e0e08|w|o|r|d|1| |v+0#ffff4012&|a|r|i|a|b|l|e| |e+0#ff404010&|x|t|r|a| |t|e|x|t| |1| | +0#4040ff13#ffffff0@45
+|a+0#0000001#ffd7ff255|w|o|r|d|2| |f+0#4040ff13&|u|n|c|t|i|o|n| |e+0#0000001&|x|t|r|a| |t|e|x|t| |2| | +0#4040ff13#ffffff0@45
+|你*0#0000001#ffd7ff255|好| +&@2|c+0#40ff4011&|l|a|s@1| @3|e+0#0000001&|x|t|r|a| |t|e|x|t| |3| | +0#4040ff13#ffffff0@45
+|~| @73
+|~| @73
+|~| @73
+|~| @73
+|~| @73
+|~| @73
+|~| @73
+|~| @73
+|~| @73
+|~| @73
+|~| @73
+|~| @73
+|~| @73
+|~| @73
+|~| @73
+|-+2#0000000&@1| |U|s|e|r| |d|e|f|i|n|e|d| |c|o|m|p|l|e|t|i|o|n| |(|^|U|^|N|^|P|)| |m+0#00e0003&|a|t|c|h| |1| |o|f| |3| +0#0000000&@26
diff --git a/src/testdir/dumps/Test_wildmenu_pum_11.dump b/src/testdir/dumps/Test_wildmenu_pum_11.dump
index 4697c8a..a0ffc74 100644
--- a/src/testdir/dumps/Test_wildmenu_pum_11.dump
+++ b/src/testdir/dumps/Test_wildmenu_pum_11.dump
@@ -1,10 +1,10 @@
| +0&#ffffff0@74
|~+0#4040ff13&| @73
-|~| @73
|~| @10| +0#0000001#e0e0e08|c|u|l|h|l|=| @8| +0#4040ff13#ffffff0@46
|~| @10| +0#0000001#ffd7ff255|i|c|o|n|=| @9| +0#4040ff13#ffffff0@46
|~| @10| +0#0000001#ffd7ff255|l|i|n|e|h|l|=| @7| +0#4040ff13#ffffff0@46
|~| @10| +0#0000001#ffd7ff255|n|u|m|h|l|=| @8| +0#4040ff13#ffffff0@46
+|~| @10| +0#0000001#ffd7ff255|p|r|i|o|r|i|t|y|=| @5| +0#4040ff13#ffffff0@46
|~| @10| +0#0000001#ffd7ff255|t|e|x|t|=| @9| +0#4040ff13#ffffff0@46
|~| @10| +0#0000001#ffd7ff255|t|e|x|t|h|l|=| @7| +0#4040ff13#ffffff0@46
|:+0#0000000&|s|i|g|n| |d|e|f|i|n|e| |c|u|l|h|l|=> @55
diff --git a/src/testdir/dumps/Test_wildmenu_pum_12.dump b/src/testdir/dumps/Test_wildmenu_pum_12.dump
index d93631d..12842c4 100644
--- a/src/testdir/dumps/Test_wildmenu_pum_12.dump
+++ b/src/testdir/dumps/Test_wildmenu_pum_12.dump
@@ -1,10 +1,10 @@
| +0&#ffffff0@74
|~+0#4040ff13&| @73
-|~| @73
|~| @17| +0#0000001#e0e0e08|c|u|l|h|l|=| @8| +0#4040ff13#ffffff0@39
|~| @17| +0#0000001#ffd7ff255|i|c|o|n|=| @9| +0#4040ff13#ffffff0@39
|~| @17| +0#0000001#ffd7ff255|l|i|n|e|h|l|=| @7| +0#4040ff13#ffffff0@39
|~| @17| +0#0000001#ffd7ff255|n|u|m|h|l|=| @8| +0#4040ff13#ffffff0@39
+|~| @17| +0#0000001#ffd7ff255|p|r|i|o|r|i|t|y|=| @5| +0#4040ff13#ffffff0@39
|~| @17| +0#0000001#ffd7ff255|t|e|x|t|=| @9| +0#4040ff13#ffffff0@39
|~| @17| +0#0000001#ffd7ff255|t|e|x|t|h|l|=| @7| +0#4040ff13#ffffff0@39
|:+0#0000000&|s|i|g|n| |d|e|f|i|n|e| |c|u|l|h|l|=| |c|u|l|h|l|=> @48
diff --git a/src/testdir/dumps/Test_wildmenu_pum_13.dump b/src/testdir/dumps/Test_wildmenu_pum_13.dump
index b2b1424..94a8ccc 100644
--- a/src/testdir/dumps/Test_wildmenu_pum_13.dump
+++ b/src/testdir/dumps/Test_wildmenu_pum_13.dump
@@ -1,10 +1,10 @@
| +0&#ffffff0@74
|~+0#4040ff13&| @73
-|~| @73
|~| @24| +0#0000001#e0e0e08|c|u|l|h|l|=| @8| +0#4040ff13#ffffff0@32
|~| @24| +0#0000001#ffd7ff255|i|c|o|n|=| @9| +0#4040ff13#ffffff0@32
|~| @24| +0#0000001#ffd7ff255|l|i|n|e|h|l|=| @7| +0#4040ff13#ffffff0@32
|~| @24| +0#0000001#ffd7ff255|n|u|m|h|l|=| @8| +0#4040ff13#ffffff0@32
+|~| @24| +0#0000001#ffd7ff255|p|r|i|o|r|i|t|y|=| @5| +0#4040ff13#ffffff0@32
|~| @24| +0#0000001#ffd7ff255|t|e|x|t|=| @9| +0#4040ff13#ffffff0@32
|~| @24| +0#0000001#ffd7ff255|t|e|x|t|h|l|=| @7| +0#4040ff13#ffffff0@32
|:+0#0000000&|s|i|g|n| |d|e|f|i|n|e| |c|u|l|h|l|=| |c|u|l|h|l|=| |c|u|l|h|l|=> @41
diff --git a/src/testdir/dumps/Test_wildmenu_pum_22.dump b/src/testdir/dumps/Test_wildmenu_pum_22.dump
index 3fd00ad..e774d5d 100644
--- a/src/testdir/dumps/Test_wildmenu_pum_22.dump
+++ b/src/testdir/dumps/Test_wildmenu_pum_22.dump
@@ -1,7 +1,7 @@
| +0&#ffffff0@74
|[+1&&|N|o| |N|a|m|e|]| @65
-|:+0#4040ff13&|s+0#af5f00255&|e|t| +0#0000000&|w+0#e000e06&|i|l|d|m|o|d|e|=+0#0000000&|l|o|n|g|e|s|t|,+0#af5f00255&|f+0#0000000&|u|l@1| @48
-|:+0#4040ff13&|s+0#af5f00255&|e|t| +0#0000000&|w+0#e000e06&|i|l|d|m|o|d|e|=+0#0000000&|f|u|l@1| @56
+|:+0#4040ff13&|s+0#af5f00255&|e|t| +0#0000000&|w+0#e000e06&|i|l|d|m|o|d|e|=+0#af5f00255&|l+0#0000000&|o|n|g|e|s|t|,+0#e000e06&|f+0#0000000&|u|l@1| @48
+|:+0#4040ff13&|s+0#af5f00255&|e|t| +0#0000000&|w+0#e000e06&|i|l|d|m|o|d|e|=+0#af5f00255&|f+0#0000000&|u|l@1| @56
|:+0#4040ff13&|s+0#af5f00255&|i|g|n| +0#0000000&|d|e|f|i|n|e| @62
|:+0#4040ff13&|s+0#af5f00255&|i|g|n| +0#0000000&|d|e|f|i|n|e> @62
|~+0#4040ff13&| @73
diff --git a/src/testdir/gen_opt_test.vim b/src/testdir/gen_opt_test.vim
index 8cca2b9..7674714 100644
--- a/src/testdir/gen_opt_test.vim
+++ b/src/testdir/gen_opt_test.vim
@@ -144,6 +144,7 @@ let test_values = {
\ 'splitkeep': [['cursor', 'screen', 'topline'], ['xxx']],
\ 'swapsync': [['', 'sync', 'fsync'], ['xxx']],
\ 'switchbuf': [['', 'useopen', 'split,newtab'], ['xxx']],
+ \ 'tabclose': [['', 'left', 'left,uselast'], ['xxx']],
\ 'tagcase': [['smart', 'match'], ['', 'xxx', 'smart,match']],
\ 'term': [[], []],
\ 'termguicolors': [[], []],
diff --git a/src/testdir/ru_RU/LC_MESSAGES/__PACKAGE__.mo b/src/testdir/ru_RU/LC_MESSAGES/__PACKAGE__.mo
new file mode 100644
index 0000000..300eba2
--- /dev/null
+++ b/src/testdir/ru_RU/LC_MESSAGES/__PACKAGE__.mo
Binary files differ
diff --git a/src/testdir/samples/Test_tohtml_basic.c.html b/src/testdir/samples/Test_tohtml_basic.c.html
new file mode 100644
index 0000000..d9467b5
--- /dev/null
+++ b/src/testdir/samples/Test_tohtml_basic.c.html
@@ -0,0 +1,47 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="UTF-8">
+<title>/home/jiangyinzuo/vim/src/testdir/Test_tohtml_basic.c.html</title>
+<meta name="Generator" content="Vim/9.1">
+<meta name="plugin-version" content="vim9.0_v2">
+<meta name="syntax" content="none">
+<meta name="settings" content="use_css,no_foldcolumn,pre_wrap,prevent_copy=,use_input_for_pc=none">
+<meta name="colorscheme" content="none">
+<style>
+<!--
+pre { white-space: pre-wrap; font-family: monospace; color: #000000; background-color: #ffffff; }
+body { font-family: monospace; color: #000000; background-color: #ffffff; }
+* { font-size: 1em; }
+-->
+</style>
+</head>
+<body>
+<pre id='vimCodeElement'>
+#include &lt;stdio.h&gt;
+#include &lt;stdlib.h&gt;
+
+int isprime(int n)
+{
+ if (n &lt;= 1)
+ return 0;
+
+ for (int i = 2; i &lt;= n / 2; i++)
+ if (n % i == 0)
+ return 0;
+
+ return 1;
+}
+
+int main(int argc, char *argv[])
+{
+ int n = 7;
+
+ printf(&quot;%d is %s prime\n&quot;, n, isprime(n) ? &quot;a&quot; : &quot;not a&quot;);
+
+ return 0;
+}
+</pre>
+</body>
+</html>
+<!-- vim: set foldmethod=manual : -->
diff --git a/src/testdir/samples/Test_tohtml_basic_no_css.c.html b/src/testdir/samples/Test_tohtml_basic_no_css.c.html
new file mode 100644
index 0000000..fcbcf5c
--- /dev/null
+++ b/src/testdir/samples/Test_tohtml_basic_no_css.c.html
@@ -0,0 +1,40 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
+<html>
+<head>
+<meta http-equiv="content-type" content="text/html; charset=UTF-8">
+<title>/home/jiangyinzuo/vim/src/testdir/Test_tohtml_basic_no_css.c.html</title>
+<meta name="Generator" content="Vim/9.1">
+<meta name="plugin-version" content="vim9.0_v2">
+<meta name="syntax" content="none">
+<meta name="settings" content="no_pre,no_foldcolumn,expand_tabs,prevent_copy=,use_input_for_pc=none">
+<meta name="colorscheme" content="none">
+</head>
+<body bgcolor="#ffffff" text="#000000">
+<font face="monospace">
+#include &lt;stdio.h&gt;<br>
+#include &lt;stdlib.h&gt;<br>
+<br>
+int isprime(int n)<br>
+{<br>
+&nbsp;&nbsp;if (n &lt;= 1)<br>
+&nbsp;&nbsp;&nbsp;&nbsp;return 0;<br>
+<br>
+&nbsp;&nbsp;for (int i = 2; i &lt;= n / 2; i++)<br>
+&nbsp;&nbsp;&nbsp;&nbsp;if (n % i == 0)<br>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return 0;<br>
+<br>
+&nbsp;&nbsp;return 1;<br>
+}<br>
+<br>
+int main(int argc, char *argv[])<br>
+{<br>
+&nbsp;&nbsp;int n = 7;<br>
+<br>
+&nbsp;&nbsp;printf(&quot;%d is %s prime\n&quot;, n, isprime(n) ? &quot;a&quot; : &quot;not a&quot;);<br>
+<br>
+&nbsp;&nbsp;return 0;<br>
+}<br>
+</font>
+</body>
+</html>
+<!-- vim: set foldmethod=manual : -->
diff --git a/src/testdir/samples/test.zip b/src/testdir/samples/test.zip
new file mode 100644
index 0000000..6d34ac6
--- /dev/null
+++ b/src/testdir/samples/test.zip
Binary files differ
diff --git a/src/testdir/samples/testa.zip b/src/testdir/samples/testa.zip
new file mode 100644
index 0000000..10b0346
--- /dev/null
+++ b/src/testdir/samples/testa.zip
Binary files differ
diff --git a/src/testdir/test28.in b/src/testdir/test28.in
new file mode 100644
index 0000000..3d5289d
--- /dev/null
+++ b/src/testdir/test28.in
@@ -0,0 +1,13 @@
+Test for using CTRL-A/CTRL-X in tiny mode
+
+STARTTEST
+/12352
+/12354
+:/^STARTHERE/+,$w! test.out
+:qa!
+ENDTEST
+
+STARTHERE
+12352
+
+12354
diff --git a/src/testdir/test28.ok b/src/testdir/test28.ok
new file mode 100644
index 0000000..085c133
--- /dev/null
+++ b/src/testdir/test28.ok
@@ -0,0 +1,3 @@
+12353
+
+12353
diff --git a/src/testdir/test_arglist.vim b/src/testdir/test_arglist.vim
index edc8b77..8d81a82 100644
--- a/src/testdir/test_arglist.vim
+++ b/src/testdir/test_arglist.vim
@@ -359,6 +359,7 @@ func Test_argv()
call assert_equal('', argv(1, 100))
call assert_equal([], argv(-1, 100))
call assert_equal('', argv(10, -1))
+ %argdelete
endfunc
" Test for the :argedit command
@@ -744,4 +745,26 @@ func Test_all_command()
%bw!
endfunc
+" Test for deleting buffer when creating an arglist. This was accessing freed
+" memory
+func Test_crash_arglist_uaf()
+ "%argdelete
+ new one
+ au BufAdd XUAFlocal :bw
+ "call assert_fails(':arglocal XUAFlocal', 'E163:')
+ arglocal XUAFlocal
+ au! BufAdd
+ bw! XUAFlocal
+
+ au BufAdd XUAFlocal2 :bw
+ new two
+ new three
+ arglocal
+ argadd XUAFlocal2 Xfoobar
+ bw! XUAFlocal2
+ bw! two
+
+ au! BufAdd
+endfunc
+
" vim: shiftwidth=2 sts=2 expandtab
diff --git a/src/testdir/test_assert.vim b/src/testdir/test_assert.vim
index d143f19..15b18a4 100644
--- a/src/testdir/test_assert.vim
+++ b/src/testdir/test_assert.vim
@@ -48,10 +48,19 @@ func Test_assert_equal()
call assert_match("Expected 'bar' but got 'foo'", v:errors[0])
call remove(v:errors, 0)
+ let s = 'αβγ'
+ call assert_equal(1, assert_equal('δεζ', s))
+ call assert_match("Expected 'δεζ' but got 'αβγ'", v:errors[0])
+ call remove(v:errors, 0)
+
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)
+ call assert_equal('ΩωωωωωωωωωωωωωωωωωωωωωΩ', 'ΩψψψψψψψψψψψψψψψψψψψψψψψψψΩ')
+ call assert_match("Expected 'Ω\\\\\\[ω occurs 21 times]Ω' but got 'Ω\\\\\\[ψ occurs 25 times]Ω'", 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])
diff --git a/src/testdir/test_autocmd.vim b/src/testdir/test_autocmd.vim
index c9f257a..5a91351 100644
--- a/src/testdir/test_autocmd.vim
+++ b/src/testdir/test_autocmd.vim
@@ -14,6 +14,13 @@ func s:cleanup_buffers() abort
endfor
endfunc
+func CleanUpTestAuGroup()
+ augroup testing
+ au!
+ augroup END
+ augroup! testing
+endfunc
+
func Test_vim_did_enter()
call assert_false(v:vim_did_enter)
@@ -269,6 +276,7 @@ endfunc
func Test_win_tab_autocmd()
let g:record = []
+ defer CleanUpTestAuGroup()
augroup testing
au WinNewPre * call add(g:record, 'WinNewPre')
au WinNew * call add(g:record, 'WinNew')
@@ -288,7 +296,7 @@ func Test_win_tab_autocmd()
call assert_equal([
\ 'WinNewPre', 'WinLeave', 'WinNew', 'WinEnter',
- \ 'WinLeave', 'TabLeave', 'WinNewPre', 'WinNew', 'WinEnter', 'TabNew', 'TabEnter',
+ \ 'WinLeave', 'TabLeave', 'WinNew', 'WinEnter', 'TabNew', 'TabEnter',
\ 'WinLeave', 'TabLeave', 'WinClosed', 'TabClosed', 'WinEnter', 'TabEnter',
\ 'WinLeave', 'WinClosed', 'WinEnter'
\ ], g:record)
@@ -299,7 +307,7 @@ func Test_win_tab_autocmd()
bwipe somefile
call assert_equal([
- \ 'WinLeave', 'TabLeave', 'WinNewPre', 'WinNew', 'WinEnter', 'TabNew', 'TabEnter',
+ \ 'WinLeave', 'TabLeave', 'WinNew', 'WinEnter', 'TabNew', 'TabEnter',
\ 'WinLeave', 'TabLeave', 'WinEnter', 'TabEnter',
\ 'WinClosed', 'TabClosed'
\ ], g:record)
@@ -316,9 +324,6 @@ func Test_win_tab_autocmd()
\ 'WinNewPre', 'WinLeave', 'WinNew', 'WinEnter'
\ ], g:record)
- augroup testing
- au!
- augroup END
unlet g:record
endfunc
@@ -330,17 +335,15 @@ func Test_WinNewPre()
au WinNewPre * call add(g:layouts_pre, winlayout())
au WinNew * call add(g:layouts_post, winlayout())
augroup END
+ defer CleanUpTestAuGroup()
split
call assert_notequal(g:layouts_pre[0], g:layouts_post[0])
split
call assert_equal(g:layouts_pre[1], g:layouts_post[0])
call assert_notequal(g:layouts_pre[1], g:layouts_post[1])
+ " not triggered for tabnew
tabnew
- call assert_notequal(g:layouts_pre[2], g:layouts_post[1])
- call assert_notequal(g:layouts_pre[2], g:layouts_post[2])
- augroup testing
- au!
- augroup END
+ call assert_equal(2, len(g:layouts_pre))
unlet g:layouts_pre
unlet g:layouts_post
@@ -383,9 +386,6 @@ func Test_WinNewPre()
let g:caught += 1
endtry
call assert_equal(4, g:caught)
- augroup testing
- au!
- augroup END
unlet g:caught
endfunc
@@ -2096,6 +2096,38 @@ func Test_Cmdline()
au! CmdlineEnter
au! CmdlineLeave
let &shellslash = save_shellslash
+
+ au! CursorMovedC : let g:pos += [getcmdpos()]
+ let g:pos = []
+ call feedkeys(":foo bar baz\<C-W>\<C-W>\<C-W>\<Esc>", 'xt')
+ call assert_equal([2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 9, 5, 1], g:pos)
+ let g:pos = []
+ call feedkeys(":hello\<C-B>\<Esc>", 'xt')
+ call assert_equal([2, 3, 4, 5, 6, 1], g:pos)
+ let g:pos = []
+ call feedkeys(":hello\<C-U>\<Esc>", 'xt')
+ call assert_equal([2, 3, 4, 5, 6, 1], g:pos)
+ let g:pos = []
+ call feedkeys(":hello\<Left>\<C-R>=''\<CR>\<Left>\<Right>\<Esc>", 'xt')
+ call assert_equal([2, 3, 4, 5, 6, 5, 4, 5], g:pos)
+ let g:pos = []
+ call feedkeys(":12345678\<C-R>=setcmdpos(3)??''\<CR>\<Esc>", 'xt')
+ call assert_equal([2, 3, 4, 5, 6, 7, 8, 9, 3], g:pos)
+ let g:pos = []
+ call feedkeys(":12345678\<C-R>=setcmdpos(3)??''\<CR>\<Left>\<Esc>", 'xt')
+ call assert_equal([2, 3, 4, 5, 6, 7, 8, 9, 3, 2], g:pos)
+ au! CursorMovedC
+
+ " setcmdpos() is no-op inside an autocommand
+ au! CursorMovedC : let g:pos += [getcmdpos()] | call setcmdpos(1)
+ let g:pos = []
+ call feedkeys(":hello\<Left>\<Left>\<Esc>", 'xt')
+ call assert_equal([2, 3, 4, 5, 6, 5, 4], g:pos)
+ au! CursorMovedC
+
+ unlet g:entered
+ unlet g:left
+ unlet g:pos
endfunc
" Test for BufWritePre autocommand that deletes or unloads the buffer.
@@ -2775,7 +2807,8 @@ endfunc
func Test_autocmd_nested()
let g:did_nested = 0
- augroup Testing
+ defer CleanUpTestAuGroup()
+ augroup testing
au WinNew * edit somefile
au BufNew * let g:did_nested = 1
augroup END
@@ -2785,7 +2818,7 @@ func Test_autocmd_nested()
bwipe! somefile
" old nested argument still works
- augroup Testing
+ augroup testing
au!
au WinNew * nested edit somefile
au BufNew * let g:did_nested = 1
@@ -4720,4 +4753,115 @@ func Test_BufEnter_botline()
set hidden&vim
endfunc
+func Test_KeyInputPre()
+ " Consume previous keys
+ call feedkeys('', 'ntx')
+
+ " KeyInputPre can record input keys.
+ let s:keys = []
+ au KeyInputPre n call add(s:keys, v:char)
+
+ call feedkeys('jkjkjjj', 'ntx')
+ call assert_equal(
+ \ ['j', 'k', 'j', 'k', 'j', 'j', 'j'],
+ \ s:keys)
+
+ unlet s:keys
+ au! KeyInputPre
+
+ " KeyInputPre can handle multibyte.
+ let s:keys = []
+ au KeyInputPre * call add(s:keys, v:char)
+ edit Xxx1
+
+ call feedkeys("iã‚\<ESC>", 'ntx')
+ call assert_equal(['i', "ã‚", "\<ESC>"], s:keys)
+
+ bwipe! Xxx1
+ unlet s:keys
+ au! KeyInputPre
+
+ " KeyInputPre can change input keys.
+ au KeyInputPre i if v:char ==# 'a' | let v:char = 'b' | endif
+ edit Xxx1
+
+ call feedkeys("iaabb\<ESC>", 'ntx')
+ call assert_equal(getline('.'), 'bbbb')
+
+ bwipe! Xxx1
+ au! KeyInputPre
+
+ " KeyInputPre returns multiple characters.
+ au KeyInputPre i if v:char ==# 'a' | let v:char = 'cccc' | endif
+ edit Xxx1
+
+ call feedkeys("iaabb\<ESC>", 'ntx')
+ call assert_equal(getline('.'), 'ccbb')
+
+ bwipe! Xxx1
+ au! KeyInputPre
+
+ " KeyInputPre can use special keys.
+ au KeyInputPre i if v:char ==# 'a' | let v:char = "\<Ignore>" | endif
+ edit Xxx1
+
+ call feedkeys("iaabb\<ESC>", 'ntx')
+ call assert_equal(getline('.'), 'bb')
+
+ bwipe! Xxx1
+ au! KeyInputPre
+
+ " Test for v:event.typed
+ au KeyInputPre n call assert_true(v:event.typed)
+ call feedkeys('j', 'ntx')
+
+ au! KeyInputPre
+
+ au KeyInputPre n call assert_false(v:event.typed)
+ call feedkeys('j', 'nx')
+
+ au! KeyInputPre
+
+ " Test for v:event.typedchar
+ nnoremap j k
+ au KeyInputPre n
+ \ call assert_equal(v:event.typedchar, 'j')
+ \ | call assert_equal(v:char, 'k')
+ call feedkeys('j', 'tx')
+
+ au! KeyInputPre
+endfunc
+
+" those commands caused null pointer access, see #15464
+func Test_WinNewPre_crash()
+ defer CleanUpTestAuGroup()
+ let _cmdheight=&cmdheight
+ augroup testing
+ au!
+ autocmd WinNewPre * redraw
+ augroup END
+ tabnew
+ tabclose
+ augroup testing
+ au!
+ autocmd WinNewPre * wincmd t
+ augroup END
+ tabnew
+ tabclose
+ augroup testing
+ au!
+ autocmd WinNewPre * wincmd b
+ augroup END
+ tabnew
+ tabclose
+ augroup testing
+ au!
+ autocmd WinNewPre * set cmdheight+=1
+ augroup END
+ tabnew
+ tabclose
+ let &cmdheight=_cmdheight
+endfunc
+
+
" vim: shiftwidth=2 sts=2 expandtab
diff --git a/src/testdir/test_breakindent.vim b/src/testdir/test_breakindent.vim
index 96d91c9..b306c02 100644
--- a/src/testdir/test_breakindent.vim
+++ b/src/testdir/test_breakindent.vim
@@ -1165,4 +1165,15 @@ func Test_breakindent_min_with_signcol()
call s:close_windows()
endfunc
+func Test_breakindent_with_double_width_wrap()
+ 50vnew
+ setlocal tabstop=8 breakindent nolist
+ call setline(1, "\t" .. repeat('a', winwidth(0) - 9) .. 'å£å£å£')
+ normal! $g0
+ call assert_equal(2, winline())
+ call assert_equal(9, wincol())
+
+ bwipe!
+endfunc
+
" vim: shiftwidth=2 sts=2 expandtab
diff --git a/src/testdir/test_buffer.vim b/src/testdir/test_buffer.vim
index de088bd..757ba05 100644
--- a/src/testdir/test_buffer.vim
+++ b/src/testdir/test_buffer.vim
@@ -126,6 +126,52 @@ func Test_buflist_browse()
%bwipe!
endfunc
+" Test for :bnext and :bprev when called from help and non-help buffers.
+func Test_bnext_bprev_help()
+ %bwipe!
+
+ e XHelp1 | set bt=help
+ let b1 = bufnr()
+ e Xbuf1
+ let b2 = bufnr()
+
+ " There's only one buffer of each type.
+ b XHelp1
+ bnext | call assert_equal(b1, bufnr())
+ bprev | call assert_equal(b1, bufnr())
+ b Xbuf1
+ bnext | call assert_equal(b2, bufnr())
+ bprev | call assert_equal(b2, bufnr())
+
+ " Add one more buffer of each type.
+ e XHelp2 | set bt=help
+ let b3 = bufnr()
+ e Xbuf2
+ let b4 = bufnr()
+
+ " Help buffer jumps to help buffer.
+ b XHelp1
+ bnext | call assert_equal(b3, bufnr())
+ bnext | call assert_equal(b1, bufnr())
+ bprev | call assert_equal(b3, bufnr())
+ bprev | call assert_equal(b1, bufnr())
+
+ " Regular buffer jumps to regular buffer.
+ b Xbuf1
+ bnext | call assert_equal(b4, bufnr())
+ bnext | call assert_equal(b2, bufnr())
+ bprev | call assert_equal(b4, bufnr())
+ bprev | call assert_equal(b2, bufnr())
+
+ " :brewind and :blast are not affected by the buffer type.
+ b Xbuf2
+ brewind | call assert_equal(b1, bufnr())
+ b XHelp1
+ blast | call assert_equal(b4, bufnr())
+
+ %bwipe!
+endfunc
+
" Test for :bdelete
func Test_bdelete_cmd()
%bwipe!
diff --git a/src/testdir/test_cd.vim b/src/testdir/test_cd.vim
index 9fb5958..13a3eba 100644
--- a/src/testdir/test_cd.vim
+++ b/src/testdir/test_cd.vim
@@ -200,12 +200,20 @@ endfunc
func Test_cd_completion()
call mkdir('XComplDir1', 'D')
call mkdir('XComplDir2', 'D')
+ call mkdir('sub/XComplDir3', 'pD')
call writefile([], 'XComplFile', 'D')
for cmd in ['cd', 'chdir', 'lcd', 'lchdir', 'tcd', 'tchdir']
call feedkeys(':' .. cmd .. " XCompl\<C-A>\<C-B>\"\<CR>", 'tx')
call assert_equal('"' .. cmd .. ' XComplDir1/ XComplDir2/', @:)
endfor
+
+ set cdpath+=sub
+ for cmd in ['cd', 'chdir', 'lcd', 'lchdir', 'tcd', 'tchdir']
+ call feedkeys(':' .. cmd .. " XCompl\<C-A>\<C-B>\"\<CR>", 'tx')
+ call assert_equal('"' .. cmd .. ' XComplDir1/ XComplDir2/ XComplDir3/', @:)
+ endfor
+ set cdpath&
endfunc
func Test_cd_unknown_dir()
diff --git a/src/testdir/test_cmdline.vim b/src/testdir/test_cmdline.vim
index 8b7489e..3f6918a 100644
--- a/src/testdir/test_cmdline.vim
+++ b/src/testdir/test_cmdline.vim
@@ -658,7 +658,8 @@ func Test_getcompletion()
unlet g:cmdline_compl_params
" For others test if the name is recognized.
- let names = ['buffer', 'environment', 'file_in_path', 'mapping', 'tag', 'tag_listfiles', 'user']
+ let names = ['buffer', 'environment', 'file_in_path', 'dir_in_path', 'mapping', 'tag',
+ \ 'tag_listfiles', 'user']
if has('cmdline_hist')
call add(names, 'history')
endif
@@ -3612,7 +3613,7 @@ func Test_cmdline_complete_bang_cmd_argument()
endfunc
func Call_cmd_funcs()
- return string([getcmdpos(), getcmdscreenpos(), getcmdcompltype()])
+ return [getcmdpos(), getcmdscreenpos(), getcmdcompltype()]
endfunc
func Test_screenpos_and_completion()
@@ -3620,13 +3621,24 @@ func Test_screenpos_and_completion()
call assert_equal(0, getcmdscreenpos())
call assert_equal('', getcmdcompltype())
- cnoremap <expr> <F2> string([getcmdpos(), getcmdscreenpos(), getcmdcompltype()])
+ cnoremap <expr> <F2> string(Call_cmd_funcs())
call feedkeys(":let a\<F2>\<C-B>\"\<CR>", "xt")
call assert_equal("\"let a[6, 7, 'var']", @:)
call feedkeys(":quit \<F2>\<C-B>\"\<CR>", "xt")
call assert_equal("\"quit [6, 7, '']", @:)
call feedkeys(":nosuchcommand \<F2>\<C-B>\"\<CR>", "xt")
call assert_equal("\"nosuchcommand [15, 16, '']", @:)
+
+ " Check that getcmdcompltype() doesn't interfere with cmdline completion.
+ let g:results = []
+ cnoremap <F2> <Cmd>let g:results += [[getcmdline()] + Call_cmd_funcs()]<CR>
+ call feedkeys(":sign un\<Tab>\<F2>\<Tab>\<F2>\<Tab>\<F2>\<C-C>", "xt")
+ call assert_equal([
+ \ ['sign undefine', 14, 15, 'sign'],
+ \ ['sign unplace', 13, 14, 'sign'],
+ \ ['sign un', 8, 9, 'sign']], g:results)
+
+ unlet g:results
cunmap <F2>
endfunc
@@ -3858,4 +3870,25 @@ func Test_term_option()
let &cpo = _cpo
endfunc
+func Test_ex_command_completion()
+ " required for :*
+ set cpo+=*
+ let list = filter(getcompletion('', 'command'), 'exists(":" . v:val) == 0')
+ " :++ and :-- are only valid in Vim9 Script context, so they can be ignored
+ call assert_equal(['++', '--'], sort(list))
+ call assert_equal(1, exists(':k'))
+ call assert_equal(0, exists(':ke'))
+ call assert_equal(1, exists(':kee'))
+ call assert_equal(1, exists(':keep'))
+ call assert_equal(1, exists(':keepm'))
+ call assert_equal(1, exists(':keepma'))
+ call assert_equal(1, exists(':keepmar'))
+ call assert_equal(1, exists(':keepmark'))
+ call assert_equal(2, exists(':keepmarks'))
+ call assert_equal(2, exists(':keepalt'))
+ call assert_equal(2, exists(':keepjumps'))
+ call assert_equal(2, exists(':keeppatterns'))
+ set cpo-=*
+endfunc
+
" vim: shiftwidth=2 sts=2 expandtab
diff --git a/src/testdir/test_codestyle.vim b/src/testdir/test_codestyle.vim
index a455264..83f52ef 100644
--- a/src/testdir/test_codestyle.vim
+++ b/src/testdir/test_codestyle.vim
@@ -28,6 +28,13 @@ def Test_source_files()
g:ignoreSwapExists = 'e'
exe 'edit ' .. fname
+ # Some files are generated files and may contain space errors.
+ if fname =~ 'dlldata.c'
+ || fname =~ 'if_ole.h'
+ || fname =~ 'iid_ole.c'
+ continue
+ endif
+
PerformCheck(fname, ' \t', 'space before Tab', '')
PerformCheck(fname, '\s$', 'trailing white space', '')
@@ -68,7 +75,8 @@ def Test_test_files()
&& fname !~ 'test_listchars.vim'
&& fname !~ 'test_visual.vim'
cursor(1, 1)
- var lnum = search(fname =~ "test_regexp_latin" ? '[^á] \t' : ' \t')
+ var skip = 'getline(".") =~ "codestyle: ignore"'
+ var lnum = search(fname =~ "test_regexp_latin" ? '[^á] \t' : ' \t', 'W', 0, 0, skip)
ReportError('testdir/' .. fname, lnum, 'space before Tab')
endif
@@ -155,4 +163,4 @@ def Test_help_files()
enddef
-" vim: shiftwidth=2 sts=2 expandtab
+" vim: shiftwidth=2 sts=2 expandtab nofoldenable
diff --git a/src/testdir/test_cpoptions.vim b/src/testdir/test_cpoptions.vim
index 6ff8301..7bfbcd1 100644
--- a/src/testdir/test_cpoptions.vim
+++ b/src/testdir/test_cpoptions.vim
@@ -19,7 +19,7 @@ func Test_cpo_a()
set cpo+=a
read XfileCpoA
call assert_equal('XfileCpoA', @#)
- close!
+ bw!
let &cpo = save_cpo
endfunc
@@ -39,7 +39,7 @@ func Test_cpo_A()
set cpo+=A
write XcpoAfile2
call assert_equal('XcpoAfile2', @#)
- close!
+ bw!
call delete('XcpoAfile2')
let &cpo = save_cpo
endfunc
@@ -81,7 +81,7 @@ func Test_cpo_B()
call assert_equal('abd ', getline(1))
call feedkeys(":imap <buffer> x\<C-A>\<C-B>\"\<CR>", 'tx')
call assert_equal('"imap <buffer> x\k', @:)
- close!
+ bw!
let &cpo = save_cpo
endfunc
@@ -96,7 +96,7 @@ func Test_cpo_c()
set cpo-=c
exe "normal gg/abab\<CR>"
call assert_equal(5, searchcount().total)
- close!
+ bw!
let &cpo = save_cpo
endfunc
@@ -143,7 +143,7 @@ func Test_cpo_D()
exe "norm! 1gg0f\<c-k>!!"
call assert_equal(1, col('.'))
set cpo-=D
- close!
+ bw!
let &cpo = save_cpo
endfunc
@@ -183,7 +183,7 @@ func Test_cpo_E()
call assert_beeps('exe "normal v\<C-A>"')
call assert_beeps('exe "normal v\<C-X>"')
set cpo-=E
- close!
+ bw!
endfunc
" Test for the 'f' flag in 'cpo' (read in an empty buffer sets the file name)
@@ -213,7 +213,7 @@ func Test_cpo_F()
set cpo+=F
write XfileCpoF
call assert_equal('XfileCpoF', @%)
- close!
+ bw!
call delete('XfileCpoF')
let &cpo = save_cpo
endfunc
@@ -229,7 +229,7 @@ func Test_cpo_g()
set cpo+=g
edit
call assert_equal(1, line('.'))
- close!
+ bw!
let &cpo = save_cpo
endfunc
@@ -245,7 +245,7 @@ func Test_cpo_H()
call setline(1, ' ')
normal! Ia
call assert_equal(' a ', getline(1))
- close!
+ bw!
let &cpo = save_cpo
endfunc
@@ -264,7 +264,7 @@ func Test_cpo_I()
%d
exe "normal i one\<CR>\<Up>"
call assert_equal('', getline(2))
- close!
+ bw!
let &cpo = save_cpo
endfunc
@@ -295,7 +295,7 @@ func Test_cpo_J()
normal (
call assert_equal(colnr, col('.'))
endfor
- close!
+ bw!
let &cpo = save_cpo
endfunc
@@ -317,7 +317,7 @@ func Test_cpo_l()
set cpo+=l
exe 'normal gg/[\t]' .. "\<CR>"
call assert_equal([4, 10], [col('.'), virtcol('.')])
- close!
+ bw!
let &cpo = save_cpo
endfunc
@@ -338,7 +338,7 @@ func Test_cpo_L()
call setline(1, 'abcdefghijklmnopqr')
exe "normal 0gR\<Tab>"
call assert_equal("\<Tab>ijklmnopqr", getline(1))
- close!
+ bw!
let &cpo = save_cpo
endfunc
@@ -376,7 +376,7 @@ func Test_cpo_M()
call cursor(2, 1)
call assert_beeps('normal %')
- close!
+ bw!
let &cpo = save_cpo
endfunc
@@ -392,7 +392,7 @@ func Test_cpo_n()
set cpo+=n
redraw!
call assert_equal('aaaa', Screenline(2))
- close!
+ bw!
let &cpo = save_cpo
endfunc
@@ -409,7 +409,7 @@ func Test_cpo_o()
exe "normal /one/+2\<CR>"
normal n
call assert_equal(5, line('.'))
- close!
+ bw!
let &cpo = save_cpo
endfunc
@@ -424,7 +424,7 @@ func Test_cpo_O()
set cpo+=O
write
call assert_equal(['one'], readfile('XfileCpoO'))
- close!
+ bw!
let &cpo = save_cpo
endfunc
@@ -462,7 +462,7 @@ func Test_cpo_q()
set cpo+=q
normal gg4J
call assert_equal(4, col('.'))
- close!
+ bw!
let &cpo = save_cpo
endfunc
@@ -483,7 +483,7 @@ func Test_cpo_r()
let @/ = 'three'
normal 2G.
call assert_equal('abc three four', getline(2))
- close!
+ bw!
let &cpo = save_cpo
endfunc
@@ -503,7 +503,7 @@ func Test_cpo_R()
3mark r
%!sort
call assert_equal(0, line("'r"))
- close!
+ bw!
let &cpo = save_cpo
endfunc
@@ -530,8 +530,8 @@ func Test_cpo_S()
wincmd p
call assert_equal(0, &autoindent)
wincmd t
- close!
- close!
+ bw!
+ bw!
let &cpo = save_cpo
endfunc
@@ -550,7 +550,7 @@ func Test_cpo_u()
exe "normal iabc\<C-G>udef\<C-G>ughi"
normal uu
call assert_equal('abcdefghi', getline(1))
- close!
+ bw!
let &cpo = save_cpo
endfunc
@@ -574,7 +574,7 @@ func Test_cpo_w()
call assert_equal('hereZZZare some words', getline('.'))
norm! 1gg2elcWYYY
call assert_equal('hereZZZare someYYYwords', getline('.'))
- close!
+ bw!
let &cpo = save_cpo
endfunc
@@ -611,7 +611,7 @@ func Test_cpo_X()
normal ggRy
normal 4.
call assert_equal('yyyyxxxaaaaa', getline(1))
- close!
+ bw!
let &cpo = save_cpo
endfunc
@@ -630,7 +630,7 @@ func Test_cpo_y()
normal ggyy
normal 2G.
call assert_equal("two\n", @")
- close!
+ bw!
let &cpo = save_cpo
endfunc
@@ -647,7 +647,7 @@ func Test_cpo_Z()
setlocal readonly
write!
call assert_equal(1, &readonly)
- close!
+ bw!
let &cpo = save_cpo
endfunc
@@ -700,7 +700,7 @@ func Test_cpo_percent()
call assert_equal(15, col('.'))
normal 22|%
call assert_equal(27, col('.'))
- close!
+ bw!
let &cpo = save_cpo
endfunc
@@ -716,7 +716,7 @@ func Test_cpo_minus()
call assert_beeps('normal 10k')
call assert_equal(3, line('.'))
call assert_fails(10, 'E16:')
- close!
+ bw!
let &cpo = save_cpo
endfunc
@@ -732,7 +732,7 @@ func Test_cpo_plus()
set cpo+=+
write X2
call assert_equal(0, &modified)
- close!
+ bw!
call delete('X1')
call delete('X2')
let &cpo = save_cpo
@@ -749,7 +749,7 @@ func Test_cpo_star()
set cpo+=*
*a
call assert_equal(1, x)
- close!
+ bw!
let &cpo = save_cpo
endfunc
@@ -770,7 +770,7 @@ func Test_cpo_gt()
normal gg"Rye
normal "Rye
call assert_equal("\none\none", @r)
- close!
+ bw!
let &cpo = save_cpo
endfunc
@@ -803,7 +803,7 @@ func Test_cpo_semicolon()
call assert_equal('bbb y', getline(4))
call assert_equal('ccc', getline(5))
call assert_equal('ddd yee y', getline(6))
- close!
+ bw!
let &cpo = save_cpo
endfunc
@@ -828,7 +828,7 @@ func Test_cpo_hash()
call assert_equal(['', 'one', 'two', 'three'], getline(1, '$'))
normal gg2Ozero
call assert_equal(['zero', '', 'one', 'two', 'three'], getline(1, '$'))
- close!
+ bw!
let &cpo = save_cpo
endfunc
@@ -858,7 +858,7 @@ func Test_cpo_backslash()
set cpo+=\
exe 'normal gg/[ \-]' .. "\<CR>n"
call assert_equal(2, col('.'))
- close!
+ bw!
let &cpo = save_cpo
endfunc
@@ -880,7 +880,7 @@ func Test_cpo_brace()
call assert_equal(2, line('.'))
normal G{
call assert_equal(2, line('.'))
- close!
+ bw!
let &cpo = save_cpo
endfunc
@@ -908,8 +908,53 @@ func Test_cpo_dot()
call delete('Xfoo')
set cpo&
- close!
+ bw!
let &cpo = save_cpo
endfunc
+" Test for the 'z' flag in 'cpo' (make cw and dw work similar and avoid
+" inconsistencies, see :h cpo-z)
+func Test_cpo_z()
+ let save_cpo = &cpo
+ new
+ " Test 1: dw behaves differently from cw
+ call setline(1, ['foo bar baz', 'one two three'])
+ call cursor(1, 1)
+ " dw does not delete the whitespace after the word
+ norm! wcwanother
+ set cpo-=z
+ " dw deletes the whitespace after the word
+ call cursor(2, 1)
+ norm! wcwfour
+ call assert_equal(['foo another baz', 'one fourthree'], getline(1, '$'))
+ " Test 2: d{motion} becomes linewise :h d-special
+ %d
+ call setline(1, ['one ', ' bar', ' e ', 'zwei'])
+ call cursor(2, 1)
+ set cpo+=z
+ " delete operation becomes linewise
+ call feedkeys("fbd/e\\zs\<cr>", 'tnx')
+ call assert_equal(['one ', 'zwei'], getline(1, '$'))
+ %d
+ call setline(1, ['one ', ' bar', ' e ', 'zwei'])
+ call cursor(2, 1)
+ call feedkeys("fbd2w", 'tnx')
+ call assert_equal(['one ', 'zwei'], getline(1, '$'))
+
+ " delete operation does not become line wise
+ set cpo-=z
+ call setline(1, ['one ', ' bar', ' e ', 'zwei'])
+ call cursor(2, 1)
+ call feedkeys("fbd/e\\zs\<cr>", 'tnx')
+ call assert_equal(['one ', ' ', 'zwei'], getline(1, '$')) " codestyle: ignore
+ %d
+ call setline(1, ['one ', ' bar', ' e ', 'zwei'])
+ call cursor(2, 1)
+ call feedkeys("fbd2w", 'tnx')
+ call assert_equal(['one ', ' ', 'zwei'], getline(1, '$'))
+
+ " clean up
+ bw!
+ let &cpo = save_cpo
+endfunc
" vim: shiftwidth=2 sts=2 expandtab
diff --git a/src/testdir/test_crash.vim b/src/testdir/test_crash.vim
index fd786e5..b334876 100644
--- a/src/testdir/test_crash.vim
+++ b/src/testdir/test_crash.vim
@@ -150,6 +150,13 @@ func Test_crash1_2()
\ ' ; echo "crash 4: [OK]" >> '.. result .. "\<cr>")
call TermWait(buf, 150)
+ let file = 'crash/reverse_text_overflow'
+ let cmn_args = "%s -u NONE -i NONE -n -X -m -n -e -s -S %s -c ':qa!'"
+ let args = printf(cmn_args, vim, file)
+ call term_sendkeys(buf, args ..
+ \ ' ; echo "crash 5: [OK]" >> '.. result .. "\<cr>")
+ call TermWait(buf, 150)
+
" clean up
exe buf .. "bw!"
exe "sp " .. result
@@ -158,6 +165,7 @@ func Test_crash1_2()
\ 'crash 2: [OK]',
\ 'crash 3: [OK]',
\ 'crash 4: [OK]',
+ \ 'crash 5: [OK]',
\ ]
call assert_equal(expected, getline(1, '$'))
@@ -190,6 +198,31 @@ func Test_crash1_3()
call term_sendkeys(buf, args)
call TermWait(buf, 150)
+ let file = 'crash/double_free'
+ let cmn_args = "%s -u NONE -i NONE -n -e -s -S %s -c ':qa!'\<cr>"
+ let args = printf(cmn_args, vim, file)
+ call term_sendkeys(buf, args)
+ call TermWait(buf, 50)
+
+ let file = 'crash/dialog_changed_uaf'
+ let cmn_args = "%s -u NONE -i NONE -n -e -s -S %s -c ':qa!'\<cr>"
+ let args = printf(cmn_args, vim, file)
+ call term_sendkeys(buf, args)
+ call TermWait(buf, 150)
+
+ let file = 'crash/nullpointer'
+ let cmn_args = "%s -u NONE -i NONE -n -e -s -S %s -c ':qa!'\<cr>"
+ let args = printf(cmn_args, vim, file)
+ call term_sendkeys(buf, args)
+ call TermWait(buf, 50)
+
+ let file = 'crash/heap_overflow3'
+ let cmn_args = "%s -u NONE -i NONE -n -X -m -n -e -s -S %s -c ':qa!'"
+ let args = printf(cmn_args, vim, file)
+ call term_sendkeys(buf, args)
+ call TermWait(buf, 150)
+
+
" clean up
exe buf .. "bw!"
bw!
@@ -204,4 +237,11 @@ func Test_crash2()
exe buf .. "bw!"
endfunc
+func TearDown()
+ " That file is created at Test_crash1_3() by dialog_changed_uaf
+ " but cleaning up in that test doesn't remove it. Let's try again at
+ " the end of this test script
+ call delete('Untitled')
+endfunc
+
" vim: shiftwidth=2 sts=2 expandtab
diff --git a/src/testdir/test_eval_stuff.vim b/src/testdir/test_eval_stuff.vim
index a346399..1b17108 100644
--- a/src/testdir/test_eval_stuff.vim
+++ b/src/testdir/test_eval_stuff.vim
@@ -2,6 +2,7 @@
source view_util.vim
source shared.vim
+import './vim9.vim' as v9
function s:foo() abort
try
@@ -126,7 +127,31 @@ func Test_for_invalid()
call assert_fails("for x in 99", 'E1098:')
call assert_fails("for x in function('winnr')", 'E1098:')
call assert_fails("for x in {'a': 9}", 'E1098:')
- call assert_fails("for v:maxcol in range(1)", 'E46:')
+
+ let lines =<< trim END
+ for v:maxcol in range(5)
+ endfor
+ END
+
+ let save_v_maxcol = v:maxcol
+ call v9.CheckLegacyAndVim9Failure(lines, 'E46:')
+ call assert_equal(save_v_maxcol, v:maxcol)
+
+ let lines =<< trim END
+ for g:constvar in range(5)
+ endfor
+ END
+
+ const g:constvar = 10
+ call v9.CheckLegacyAndVim9Failure(lines, 'E741:')
+ call assert_equal(10, g:constvar)
+ unlet g:constvar
+
+ let g:constvar = 10
+ lockvar 0 g:constvar
+ call v9.CheckLegacyAndVim9Failure(lines, 'E1122:')
+ call assert_equal(10, g:constvar)
+ unlet g:constvar
if 0
/1/5/2/s/\n
diff --git a/src/testdir/test_ex_mode.vim b/src/testdir/test_ex_mode.vim
index 59c28f3..aa94935 100644
--- a/src/testdir/test_ex_mode.vim
+++ b/src/testdir/test_ex_mode.vim
@@ -68,7 +68,7 @@ func Test_Ex_substitute()
CheckRunVimInTerminal
let buf = RunVimInTerminal('', {'rows': 6})
- call term_sendkeys(buf, ":call setline(1, ['foo foo', 'foo foo', 'foo foo'])\<CR>")
+ call term_sendkeys(buf, ":call setline(1, repeat(['foo foo'], 4))\<CR>")
call term_sendkeys(buf, ":set number\<CR>")
call term_sendkeys(buf, "gQ")
call WaitForAssert({-> assert_match(':', term_getline(buf, 6))}, 1000)
@@ -90,8 +90,14 @@ func Test_Ex_substitute()
" Pressing enter in ex mode should print the current line
call term_sendkeys(buf, "\<CR>")
- call WaitForAssert({-> assert_match(' 3 foo foo',
- \ term_getline(buf, 5))}, 1000)
+ call WaitForAssert({-> assert_match(' 3 foo foo', term_getline(buf, 5))}, 1000)
+ call WaitForAssert({-> assert_match(':', term_getline(buf, 6))}, 1000)
+
+ " The printed line should overwrite the colon
+ call term_sendkeys(buf, "\<CR>")
+ call WaitForAssert({-> assert_match(' 3 foo foo', term_getline(buf, 4))}, 1000)
+ call WaitForAssert({-> assert_match(' 4 foo foo', term_getline(buf, 5))}, 1000)
+ call WaitForAssert({-> assert_match(':', term_getline(buf, 6))}, 1000)
call term_sendkeys(buf, ":vi\<CR>")
call WaitForAssert({-> assert_match('foo bar', term_getline(buf, 1))}, 1000)
@@ -165,6 +171,37 @@ func Test_Ex_global()
call assert_equal('bax', getline(3))
call assert_equal('bay', getline(5))
bwipe!
+
+ new
+ call setline(1, ['foo', 'bar'])
+ call feedkeys("Qg/./i\\\na\\\n.\\\na\\\nb\\\n.", "xt")
+ call assert_equal(['a', 'b', 'foo', 'a', 'b', 'bar'], getline(1, '$'))
+ bwipe!
+endfunc
+
+func Test_Ex_shell()
+ CheckUnix
+
+ new
+ call feedkeys("Qr !echo foo\\\necho bar\n", 'xt')
+ call assert_equal(['', 'foo', 'bar'], getline(1, '$'))
+ bwipe!
+
+ new
+ call feedkeys("Qr !echo foo\\\\\nbar\n", 'xt')
+ call assert_equal(['', 'foobar'], getline(1, '$'))
+ bwipe!
+
+ new
+ call feedkeys("Qr !echo foo\\ \\\necho bar\n", 'xt')
+ call assert_equal(['', 'foo ', 'bar'], getline(1, '$'))
+ bwipe!
+
+ new
+ call setline(1, ['bar', 'baz'])
+ call feedkeys("Qg/./!echo \\\ns/b/c/", "xt")
+ call assert_equal(['car', 'caz'], getline(1, '$'))
+ bwipe!
endfunc
" Test for pressing Ctrl-C in :append inside a loop in Ex mode
@@ -204,18 +241,11 @@ func Test_Ex_append()
call feedkeys("Qappend!\npqr\nxyz\n.\nvisual\n", 'xt')
call assert_equal(["\t abc", "\t pqr", "\t xyz"], getline(1, '$'))
close!
-endfunc
-" In Ex-mode, backslashes at the end of a command should be halved.
-func Test_Ex_echo_backslash()
- " This test works only when the language is English
- CheckEnglish
- let bsl = '\\\\'
- let bsl2 = '\\\'
- call assert_fails('call feedkeys("Qecho " .. bsl .. "\nvisual\n", "xt")',
- \ 'E15: Invalid expression: "\\"')
- call assert_fails('call feedkeys("Qecho " .. bsl2 .. "\nm\nvisual\n", "xt")',
- \ "E15: Invalid expression: \"\\\nm\"")
+ new
+ call feedkeys("Qappend\na\\\n.", 'xt')
+ call assert_equal(['a\'], getline(1, '$'))
+ close!
endfunc
func Test_ex_mode_errors()
@@ -314,5 +344,47 @@ func Test_empty_command_visual_mode()
call delete('guidialogfile')
endfunc
+" Test using backslash in ex-mode
+func Test_backslash_multiline()
+ new
+ call setline(1, 'enum')
+ call feedkeys('Qg/enum/i\ \ .', "xt")
+ call assert_equal(["", "enum"], getline(1, 2))
+endfunc
+
+" Test using backslash in ex-mode after patch 9.1.0535
+func Test_backslash_multiline2()
+ new
+ call feedkeys('Qa X \\ Y .', "xt")
+ call assert_equal(['X \\', "Y"], getline(1, 2))
+endfunc
+
+" Testing implicit print command
+func Test_implicit_print()
+ new
+ call setline(1, ['one', 'two', 'three'])
+ call feedkeys('Q:let a=execute(":1,2")', 'xt')
+ call feedkeys('Q:let b=execute(":3")', 'xt')
+ call assert_equal('one two', a->split('\n')->join(' '))
+ call assert_equal('three', b->split('\n')->join(' '))
+ bw!
+endfunc
+
+" Test inserting text after the trailing bar
+func Test_insert_after_trailing_bar()
+ new
+ call feedkeys("Qi|\nfoo\n.\na|bar\nbar\n.\nc|baz\n.", "xt")
+ call assert_equal(['', 'foo', 'bar', 'baz'], getline(1, '$'))
+ bwipe!
+endfunc
+
+" Test global insert of a newline without terminating period
+func Test_global_insert_newline()
+ new
+ call setline(1, ['foo'])
+ call feedkeys("Qg/foo/i\\\n", "xt")
+ call assert_equal(['', 'foo'], getline(1, '$'))
+ bwipe!
+endfunc
" vim: shiftwidth=2 sts=2 expandtab
diff --git a/src/testdir/test_excmd.vim b/src/testdir/test_excmd.vim
index 221ceb0..3b7e489 100644
--- a/src/testdir/test_excmd.vim
+++ b/src/testdir/test_excmd.vim
@@ -703,6 +703,8 @@ func Test_address_line_overflow()
call setline(1, range(100))
call assert_fails('|.44444444444444444444444', 'E1247:')
call assert_fails('|.9223372036854775806', 'E1247:')
+ call assert_fails('.44444444444444444444444d', 'E1247:')
+ call assert_equal(range(100)->map('string(v:val)'), getline(1, '$'))
$
yank 77777777777777777777
diff --git a/src/testdir/test_filetype.vim b/src/testdir/test_filetype.vim
index d0a078f..1e6c39e 100644
--- a/src/testdir/test_filetype.vim
+++ b/src/testdir/test_filetype.vim
@@ -95,6 +95,7 @@ def s:GetFilenameChecks(): dict<list<string>>
aml: ['file.aml'],
ampl: ['file.run'],
ant: ['build.xml'],
+ antlr4: ['parser.g4'],
apache: ['.htaccess', '/etc/httpd/file.conf', '/etc/apache2/sites-2/file.com', '/etc/apache2/some.config', '/etc/apache2/conf.file/conf', '/etc/apache2/mods-some/file', '/etc/apache2/sites-some/file', '/etc/httpd/conf.d/file.config', '/etc/apache2/conf.file/file', '/etc/apache2/file.conf', '/etc/apache2/file.conf-file', '/etc/apache2/mods-file/file', '/etc/apache2/sites-file/file', '/etc/apache2/sites-file/file.com', '/etc/httpd/conf.d/file.conf', '/etc/httpd/conf.d/file.conf-file', 'access.conf', 'access.conf-file', 'any/etc/apache2/conf.file/file', 'any/etc/apache2/file.conf', 'any/etc/apache2/file.conf-file', 'any/etc/apache2/mods-file/file', 'any/etc/apache2/sites-file/file', 'any/etc/apache2/sites-file/file.com', 'any/etc/httpd/conf.d/file.conf', 'any/etc/httpd/conf.d/file.conf-file', 'any/etc/httpd/file.conf', 'apache.conf', 'apache.conf-file', 'apache2.conf', 'apache2.conf-file', 'httpd.conf', 'httpd.conf-file', 'srm.conf', 'srm.conf-file', '/etc/httpd/mods-some/file', '/etc/httpd/sites-some/file', '/etc/httpd/conf.file/conf'],
apachestyle: ['/etc/proftpd/file.config,/etc/proftpd/conf.file/file', '/etc/proftpd/conf.file/file', '/etc/proftpd/file.conf', '/etc/proftpd/file.conf-file', 'any/etc/proftpd/conf.file/file', 'any/etc/proftpd/file.conf', 'any/etc/proftpd/file.conf-file', 'proftpd.conf', 'proftpd.conf-file'],
applescript: ['file.scpt'],
@@ -106,6 +107,7 @@ def s:GetFilenameChecks(): dict<list<string>>
asn: ['file.asn', 'file.asn1'],
asterisk: ['asterisk/file.conf', 'asterisk/file.conf-file', 'some-asterisk/file.conf', 'some-asterisk/file.conf-file'],
astro: ['file.astro'],
+ asy: ['file.asy'],
atlas: ['file.atl', 'file.as'],
authzed: ['schema.zed'],
autohotkey: ['file.ahk'],
@@ -121,7 +123,7 @@ def s:GetFilenameChecks(): dict<list<string>>
beancount: ['file.beancount'],
bib: ['file.bib'],
bicep: ['file.bicep', 'file.bicepparam'],
- bindzone: ['named.root', '/bind/db.file', '/named/db.file', 'any/bind/db.file', 'any/named/db.file'],
+ bindzone: ['named.root', '/bind/db.file', '/named/db.file', 'any/bind/db.file', 'any/named/db.file', 'foobar.zone'],
bitbake: ['file.bb', 'file.bbappend', 'file.bbclass', 'build/conf/local.conf', 'meta/conf/layer.conf', 'build/conf/bbappend.conf', 'meta-layer/conf/distro/foo.conf'],
blade: ['file.blade.php'],
blank: ['file.bl'],
@@ -142,6 +144,7 @@ def s:GetFilenameChecks(): dict<list<string>>
cdl: ['file.cdl'],
cdrdaoconf: ['/etc/cdrdao.conf', '/etc/defaults/cdrdao', '/etc/default/cdrdao', '.cdrdao', 'any/etc/cdrdao.conf', 'any/etc/default/cdrdao', 'any/etc/defaults/cdrdao'],
cdrtoc: ['file.toc'],
+ cedar: ['file.cedar'],
cf: ['file.cfm', 'file.cfi', 'file.cfc'],
cfengine: ['cfengine.conf'],
cfg: ['file.hgrc', 'filehgrc', 'hgrc', 'some-hgrc'],
@@ -160,7 +163,7 @@ def s:GetFilenameChecks(): dict<list<string>>
cmakecache: ['CMakeCache.txt'],
cmod: ['file.cmod'],
cmusrc: ['any/.cmus/autosave', 'any/.cmus/rc', 'any/.cmus/command-history', 'any/.cmus/file.theme', 'any/cmus/rc', 'any/cmus/file.theme', '/.cmus/autosave', '/.cmus/command-history', '/.cmus/file.theme', '/.cmus/rc', '/cmus/file.theme', '/cmus/rc'],
- cobol: ['file.cbl', 'file.cob', 'file.lib'],
+ cobol: ['file.cbl', 'file.cob'],
coco: ['file.atg'],
conaryrecipe: ['file.recipe'],
conf: ['auto.master', 'file.conf', 'texdoc.cnf', '.x11vncrc', '.chktexrc', '.ripgreprc', 'ripgreprc', 'file.ctags', '.mbsyncrc'],
@@ -222,11 +225,11 @@ def s:GetFilenameChecks(): dict<list<string>>
'psprint.conf', 'sofficerc', 'any/.config/lxqt/globalkeyshortcuts.conf', 'any/.config/screengrab/screengrab.conf',
'any/.local/share/flatpak/repo/config', '.notmuch-config'],
dot: ['file.dot', 'file.gv'],
- dracula: ['file.drac', 'file.drc', 'filelvs', 'filelpe', 'drac.file', 'lpe', 'lvs', 'some-lpe', 'some-lvs'],
+ dracula: ['file.drac', 'file.drc', 'file.lvs', 'file.lpe', 'drac.file'],
dtd: ['file.dtd'],
dtrace: ['/usr/lib/dtrace/io.d'],
dts: ['file.dts', 'file.dtsi', 'file.dtso', 'file.its', 'file.keymap'],
- dune: ['jbuild', 'dune', 'dune-project', 'dune-workspace'],
+ dune: ['jbuild', 'dune', 'dune-project', 'dune-workspace', 'dune-file'],
dylan: ['file.dylan'],
dylanintr: ['file.intr'],
dylanlid: ['file.lid'],
@@ -256,6 +259,7 @@ def s:GetFilenameChecks(): dict<list<string>>
factor: ['file.factor'],
falcon: ['file.fal'],
fan: ['file.fan', 'file.fwt'],
+ faust: ['file.dsp', 'file.lib'],
fennel: ['file.fnl'],
fetchmail: ['.fetchmailrc'],
fgl: ['file.4gl', 'file.4gh', 'file.m4gl'],
@@ -285,17 +289,18 @@ def s:GetFilenameChecks(): dict<list<string>>
gitattributes: ['file.git/info/attributes', '.gitattributes', '/.config/git/attributes', '/etc/gitattributes', '/usr/local/etc/gitattributes', 'some.git/info/attributes'] + WhenConfigHome('$XDG_CONFIG_HOME/git/attributes'),
gitcommit: ['COMMIT_EDITMSG', 'MERGE_MSG', 'TAG_EDITMSG', 'NOTES_EDITMSG', 'EDIT_DESCRIPTION'],
gitconfig: ['file.git/config', 'file.git/config.worktree', 'file.git/worktrees/x/config.worktree', '.gitconfig', '.gitmodules', 'file.git/modules//config', '/.config/git/config', '/etc/gitconfig', '/usr/local/etc/gitconfig', '/etc/gitconfig.d/file', 'any/etc/gitconfig.d/file', '/.gitconfig.d/file', 'any/.config/git/config', 'any/.gitconfig.d/file', 'some.git/config', 'some.git/modules/any/config'] + WhenConfigHome('$XDG_CONFIG_HOME/git/config'),
- gitignore: ['file.git/info/exclude', '.gitignore', '/.config/git/ignore', 'some.git/info/exclude'] + WhenConfigHome('$XDG_CONFIG_HOME/git/ignore'),
+ gitignore: ['file.git/info/exclude', '.gitignore', '/.config/git/ignore', 'some.git/info/exclude'] + WhenConfigHome('$XDG_CONFIG_HOME/git/ignore') + ['.prettierignore'],
gitolite: ['gitolite.conf', '/gitolite-admin/conf/file', 'any/gitolite-admin/conf/file'],
gitrebase: ['git-rebase-todo'],
gitsendemail: ['.gitsendemail.msg.xxxxxx'],
gkrellmrc: ['gkrellmrc', 'gkrellmrc_x'],
gleam: ['file.gleam'],
- glsl: ['file.glsl'],
+ glsl: ['file.glsl', 'file.vert', 'file.tesc', 'file.tese', 'file.geom', 'file.frag', 'file.comp', 'file.rgen', 'file.rmiss', 'file.rchit', 'file.rahit', 'file.rint', 'file.rcall'],
gn: ['file.gn', 'file.gni'],
gnash: ['gnashrc', '.gnashrc', 'gnashpluginrc', '.gnashpluginrc'],
gnuplot: ['file.gpi', '.gnuplot', 'file.gnuplot', '.gnuplot_history'],
go: ['file.go'],
+ goaccess: ['goaccess.conf'],
gomod: ['go.mod'],
gosum: ['go.sum', 'go.work.sum'],
gowork: ['go.work'],
@@ -332,6 +337,7 @@ def s:GetFilenameChecks(): dict<list<string>>
hoon: ['file.hoon'],
hostconf: ['/etc/host.conf', 'any/etc/host.conf'],
hostsaccess: ['/etc/hosts.allow', '/etc/hosts.deny', 'any/etc/hosts.allow', 'any/etc/hosts.deny'],
+ # file.component.html should be HTML, not Angular, see #13594
html: ['file.html', 'file.htm', 'file.cshtml', 'file.component.html'],
htmlm4: ['file.html.m4'],
httest: ['file.htt', 'file.htb'],
@@ -364,7 +370,9 @@ def s:GetFilenameChecks(): dict<list<string>>
jq: ['file.jq'],
jovial: ['file.jov', 'file.j73', 'file.jovial'],
jproperties: ['file.properties', 'file.properties_xx', 'file.properties_xx_xx', 'some.properties_xx_xx_file', 'org.eclipse.xyz.prefs'],
- json: ['file.json', 'file.jsonp', 'file.json-patch', 'file.geojson', 'file.webmanifest', 'Pipfile.lock', 'file.ipynb', 'file.jupyterlab-settings', '.prettierrc', '.firebaserc', '.stylelintrc', '.lintstagedrc', 'file.slnf', 'file.sublime-project', 'file.sublime-settings', 'file.sublime-workspace', 'file.bd', 'file.bda', 'file.xci', 'flake.lock'],
+ json: ['file.json', 'file.jsonp', 'file.json-patch', 'file.geojson', 'file.webmanifest', 'Pipfile.lock', 'file.ipynb', 'file.jupyterlab-settings',
+ '.prettierrc', '.firebaserc', '.stylelintrc', '.lintstagedrc', 'file.slnf', 'file.sublime-project', 'file.sublime-settings', 'file.sublime-workspace',
+ 'file.bd', 'file.bda', 'file.xci', 'flake.lock', 'pack.mcmeta', 'deno.lock'],
json5: ['file.json5'],
jsonc: ['file.jsonc', '.babelrc', '.eslintrc', '.jsfmtrc', '.jshintrc', '.jscsrc', '.vsconfig', '.hintrc', '.swrc', 'jsconfig.json', 'tsconfig.json', 'tsconfig.test.json', 'tsconfig-test.json', '.luaurc'],
jsonl: ['file.jsonl'],
@@ -383,6 +391,7 @@ def s:GetFilenameChecks(): dict<list<string>>
lace: ['file.ace', 'file.ACE'],
latte: ['file.latte', 'file.lte'],
ld: ['file.ld', 'any/usr/lib/aarch64-xilinx-linux/ldscripts/aarch64elf32b.x'],
+ ldapconf: ['ldap.conf', '.ldaprc', 'ldaprc'],
ldif: ['file.ldif'],
lean: ['file.lean'],
ledger: ['file.ldg', 'file.ledger', 'file.journal'],
@@ -420,18 +429,19 @@ def s:GetFilenameChecks(): dict<list<string>>
mail: ['snd.123', '.letter', '.letter.123', '.followup', '.article', '.article.123', 'pico.123', 'mutt-xx-xxx', 'muttng-xx-xxx', 'ae123.txt', 'file.eml', 'reportbug-file'],
mailaliases: ['/etc/mail/aliases', '/etc/aliases', 'any/etc/aliases', 'any/etc/mail/aliases'],
mailcap: ['.mailcap', 'mailcap'],
- make: ['file.mk', 'file.mak', 'file.dsp', 'makefile', 'Makefile', 'makefile-file', 'Makefile-file', 'some-makefile', 'some-Makefile', 'Kbuild'],
+ make: ['file.mk', 'file.mak', 'makefile', 'Makefile', 'makefile-file', 'Makefile-file', 'some-makefile', 'some-Makefile', 'Kbuild'],
mallard: ['file.page'],
man: ['file.man'],
manconf: ['/etc/man.conf', 'man.config', 'any/etc/man.conf'],
map: ['file.map'],
maple: ['file.mv', 'file.mpl', 'file.mws'],
markdown: ['file.markdown', 'file.mdown', 'file.mkd', 'file.mkdn', 'file.mdwn', 'file.md'],
- mason: ['file.mason', 'file.mhtml', 'file.comp'],
+ mason: ['file.mason', 'file.mhtml'],
master: ['file.mas', 'file.master'],
matlab: ['file.m'],
maxima: ['file.demo', 'file.dmt', 'file.dm1', 'file.dm2', 'file.dm3',
'file.wxm', 'maxima-init.mac'],
+ mediawiki: ['file.mw', 'file.wiki'],
mel: ['file.mel'],
mermaid: ['file.mmd', 'file.mmdc', 'file.mermaid'],
meson: ['meson.build', 'meson.options', 'meson_options.txt'],
@@ -466,7 +476,7 @@ def s:GetFilenameChecks(): dict<list<string>>
mgp: ['file.mgp'],
mib: ['file.mib', 'file.my'],
mix: ['file.mix', 'file.mixal'],
- mma: ['file.nb'],
+ mma: ['file.nb', 'file.wl'],
mmp: ['file.mmp'],
modconf: ['/etc/modules.conf', '/etc/modules', '/etc/conf.modules', '/etc/modprobe.file', 'any/etc/conf.modules', 'any/etc/modprobe.file', 'any/etc/modules', 'any/etc/modules.conf'],
modula3: ['file.m3', 'file.mg', 'file.i3', 'file.ig', 'file.lm3'],
@@ -522,7 +532,7 @@ def s:GetFilenameChecks(): dict<list<string>>
odin: ['file.odin'],
omnimark: ['file.xom', 'file.xin'],
ondir: ['.ondirrc'],
- opam: ['opam', 'file.opam', 'file.opam.template'],
+ opam: ['opam', 'file.opam', 'file.opam.template', 'opam.locked', 'file.opam.locked'],
openroad: ['file.or'],
openscad: ['file.scad'],
openvpn: ['file.ovpn', '/etc/openvpn/client/client.conf', '/usr/share/openvpn/examples/server.conf'],
@@ -645,7 +655,8 @@ def s:GetFilenameChecks(): dict<list<string>>
sh: ['.bashrc', '.bash_profile', '.bash-profile', '.bash_logout', '.bash-logout', '.bash_aliases', '.bash-aliases', '.bash_history', '.bash-history',
'/tmp/bash-fc-3Ozjlw', '/tmp/bash-fc.3Ozjlw', 'PKGBUILD', 'APKBUILD', 'file.bash', '/usr/share/doc/bash-completion/filter.sh',
'/etc/udev/cdsymlinks.conf', 'any/etc/udev/cdsymlinks.conf', 'file.bats', '.ash_history', 'any/etc/neofetch/config.conf', '.xprofile',
- 'user-dirs.defaults', 'user-dirs.dirs', 'makepkg.conf', '.makepkg.conf', 'file.mdd', 'file.cygport'],
+ 'user-dirs.defaults', 'user-dirs.dirs', 'makepkg.conf', '.makepkg.conf', 'file.mdd', 'file.cygport', '.env', '.envrc', 'devscripts.conf',
+ '.devscripts'],
sieve: ['file.siv', 'file.sieve'],
sil: ['file.sil'],
simula: ['file.sim'],
@@ -759,7 +770,7 @@ def s:GetFilenameChecks(): dict<list<string>>
teraterm: ['file.ttl'],
terminfo: ['file.ti'],
'terraform-vars': ['file.tfvars'],
- tex: ['file.latex', 'file.sty', 'file.dtx', 'file.ltx', 'file.bbl', 'any/.texlive/texmf-config/tex/latex/file/file.cfg', 'file.pgf', 'file.nlo', 'file.nls', 'file.thm', 'file.eps_tex', 'file.pygtex', 'file.pygstyle', 'file.clo', 'file.aux', 'file.brf', 'file.ind', 'file.lof', 'file.loe', 'file.nav', 'file.vrb', 'file.ins', 'file.tikz', 'file.bbx', 'file.cbx', 'file.beamer'],
+ tex: ['file.latex', 'file.sty', 'file.dtx', 'file.ltx', 'file.bbl', 'any/.texlive/texmf-config/tex/latex/file/file.cfg', 'file.pgf', 'file.nlo', 'file.nls', 'file.thm', 'file.eps_tex', 'file.pygtex', 'file.pygstyle', 'file.clo', 'file.aux', 'file.brf', 'file.ind', 'file.lof', 'file.loe', 'file.nav', 'file.vrb', 'file.ins', 'file.tikz', 'file.bbx', 'file.cbx', 'file.beamer', 'file.pdf_tex'],
texinfo: ['file.texinfo', 'file.texi', 'file.txi'],
texmf: ['texmf.cnf'],
text: ['file.text', 'file.txt', 'README', 'LICENSE', 'COPYING', 'AUTHORS', '/usr/share/doc/bash-completion/AUTHORS', '/etc/apt/apt.conf.d/README', '/etc/Muttrc.d/README'],
@@ -854,6 +865,8 @@ def s:GetFilenameChecks(): dict<list<string>>
z8a: ['file.z8a'],
zathurarc: ['zathurarc'],
zig: ['file.zig', 'build.zig.zon'],
+ ziggy: ['file.ziggy'],
+ ziggy_schema: ['file.ziggy-schema'],
zimbu: ['file.zu'],
zimbutempl: ['file.zut'],
zserio: ['file.zs'],
@@ -1043,7 +1056,8 @@ func Test_emptybuf_ftdetect()
call assert_equal('', &filetype)
filetype detect
call assert_equal('sh', &filetype)
- close!
+ " close the swapfile
+ bw!
endfunc
" Test for ':filetype indent on' and ':filetype indent off' commands
@@ -1567,6 +1581,73 @@ func Test_hook_file()
filetype off
endfunc
+func Test_html_file()
+ filetype on
+
+ " HTML Angular
+ let content = ['@for (item of items; track item.name) {', ' <li> {{ item.name }}</li>', '} @empty {', ' <li> There are no items.</li>', '}']
+ call writefile(content, 'Xfile.html', 'D')
+ split Xfile.html
+ call assert_equal('htmlangular', &filetype)
+ bwipe!
+
+ " Django Template
+ let content = ['{% if foobar %}',
+ \ ' <ul>',
+ \ ' {% for question in list %}',
+ \ ' <li><a href="/polls/{{ question.id }}/">{{ question.question_text }}</a></li>',
+ \ ' {% endfor %}',
+ \ ' </ul>',
+ \ '{% else %}',
+ \ ' <p>No polls are available.</p>',
+ \ '{% endif %}']
+ call writefile(content, 'Xfile.html', 'D')
+ split Xfile.html
+ call assert_equal('htmldjango', &filetype)
+ bwipe!
+
+ " Super html layout
+ let content = ['<extend template="base.shtml">',
+ \ '<title id="title" var="$page.title"></title>',
+ \ '<head id="head"></head>',
+ \ '<div id="content">',
+ \ '</div>']
+ call writefile(content, 'Xfile.shtml', 'D')
+ split Xfile.shtml
+ call assert_equal('superhtml', &filetype)
+ bwipe!
+
+ " Super html template
+ let content = ['<!DOCTYPE html>',
+ \ '<html>',
+ \ ' <head id="head">',
+ \ ' <title id="title">',
+ \ ' <super>',
+ \ ' suffix',
+ \ ' </title>',
+ \ ' <super>',
+ \ ' </head>',
+ \ ' <body>',
+ \ ' <div id="content">',
+ \ ' <super>',
+ \ ' </div>',
+ \ ' </body>',
+ \ '</html>']
+ call writefile(content, 'Xfile.shtml', 'D')
+ split Xfile.shtml
+ call assert_equal('superhtml', &filetype)
+ bwipe!
+
+ " regular HTML
+ let content = ['<!DOCTYPE html>', '<html>', ' <head>Foobar</head>', ' <body>Content', ' </body>', '</html>']
+ call writefile(content, 'Xfile.html', 'D')
+ split Xfile.html
+ call assert_equal('html', &filetype)
+ bwipe!
+
+ filetype off
+endfunc
+
func Test_m_file()
filetype on
@@ -2401,6 +2482,32 @@ func Test_typ_file()
filetype off
endfunc
+func Test_dsp_file()
+ filetype on
+
+ " Microsoft Developer Studio Project file
+
+ call writefile(['# Microsoft Developer Studio Project File'], 'Xfile.dsp', 'D')
+ split Xfile.dsp
+ call assert_equal('make', &filetype)
+ bwipe!
+
+ let g:filetype_dsp = 'make'
+ split test.dsp
+ call assert_equal('make', &filetype)
+ bwipe!
+ unlet g:filetype_dsp
+
+ " Faust
+
+ call writefile(['this is a fallback'], 'Xfile.dsp')
+ split Xfile.dsp
+ call assert_equal('faust', &filetype)
+ bwipe!
+
+ filetype off
+endfunc
+
func Test_vba_file()
filetype on
@@ -2509,4 +2616,86 @@ func Test_uci_file()
filetype off
endfunc
+func Test_pro_file()
+ filetype on
+
+ "Prolog
+ call writefile([':-module(test/1,'], 'Xfile.pro', 'D')
+ split Xfile.pro
+ call assert_equal('prolog', &filetype)
+ bwipe!
+
+ call writefile(['% comment'], 'Xfile.pro', 'D')
+ split Xfile.pro
+ call assert_equal('prolog', &filetype)
+ bwipe!
+
+ call writefile(['/* multiline comment'], 'Xfile.pro', 'D')
+ split Xfile.pro
+ call assert_equal('prolog', &filetype)
+ bwipe!
+
+ call writefile(['rule(test, 1.7).'], 'Xfile.pro', 'D')
+ split Xfile.pro
+ call assert_equal('prolog', &filetype)
+ bwipe!
+
+ " IDL
+ call writefile(['x = findgen(100)/10'], 'Xfile.pro', 'D')
+ split Xfile.pro
+ call assert_equal('idlang', &filetype)
+
+ filetype off
+endfunc
+
+
+func Test_pl_file()
+ filetype on
+
+ "Prolog
+ call writefile([':-module(test/1,'], 'Xfile.pl', 'D')
+ split Xfile.pl
+ call assert_equal('prolog', &filetype)
+ bwipe!
+
+ call writefile(['% comment'], 'Xfile.pl', 'D')
+ split Xfile.pl
+ call assert_equal('prolog', &filetype)
+ bwipe!
+
+ call writefile(['/* multiline comment'], 'Xfile.pl', 'D')
+ split Xfile.pl
+ call assert_equal('prolog', &filetype)
+ bwipe!
+
+ call writefile(['rule(test, 1.7).'], 'Xfile.pl', 'D')
+ split Xfile.pl
+ call assert_equal('prolog', &filetype)
+ bwipe!
+
+ " Perl
+ call writefile(['%data = (1, 2, 3);'], 'Xfile.pl', 'D')
+ split Xfile.pl
+ call assert_equal('perl', &filetype)
+
+ filetype off
+endfunc
+
+func Test_make_file()
+ filetype on
+
+ " Microsoft Makefile
+ call writefile(['# Makefile for Windows', '!if "$(VIMDLL)" == "yes"'], 'XMakefile.mak', 'D')
+ split XMakefile.mak
+ call assert_equal(1, get(b:, 'make_microsoft', 0))
+ bwipe!
+
+ call writefile(['# get the list of tests', 'include testdir/Make_all.mak'], 'XMakefile.mak', 'D')
+ split XMakefile.mak
+ call assert_equal(0, get(b:, 'make_microsoft', 0))
+ bwipe!
+
+ filetype off
+endfunc
+
" vim: shiftwidth=2 sts=2 expandtab
diff --git a/src/testdir/test_findfile.vim b/src/testdir/test_findfile.vim
index 20d5096..a5e18b9 100644
--- a/src/testdir/test_findfile.vim
+++ b/src/testdir/test_findfile.vim
@@ -98,14 +98,48 @@ func Test_findfile()
" Test upwards search with stop-directory.
cd Xdir2
+ let l = findfile('bar', ';' . save_dir . '/Xfinddir1/Xdir2/Xdir3/', -1)
+ call assert_equal(1, len(l))
+ call assert_match('.*/Xfinddir1/Xdir2/Xdir3/bar', l[0])
+ let l = findfile('bar', ';' . save_dir . '/Xfinddir1/Xdir2/Xdir3', -1)
+ call assert_equal(1, len(l))
+ call assert_match('.*/Xfinddir1/Xdir2/Xdir3/bar', l[0])
+ let l = findfile('bar', ';../', -1)
+ call assert_equal(1, len(l))
+ call assert_match('.*/Xfinddir1/Xdir2/Xdir3/bar', l[0])
+ let l = findfile('bar', ';..', -1)
+ call assert_equal(1, len(l))
+ call assert_match('.*/Xfinddir1/Xdir2/Xdir3/bar', l[0])
+
let l = findfile('bar', ';' . save_dir . '/Xfinddir1/Xdir2/', -1)
call assert_equal(1, len(l))
call assert_match('.*/Xfinddir1/Xdir2/Xdir3/bar', l[0])
+ let l = findfile('bar', ';' . save_dir . '/Xfinddir1/Xdir2', -1)
+ call assert_equal(1, len(l))
+ call assert_match('.*/Xfinddir1/Xdir2/Xdir3/bar', l[0])
+ let l = findfile('bar', ';../../', -1)
+ call assert_equal(1, len(l))
+ call assert_match('.*/Xfinddir1/Xdir2/Xdir3/bar', l[0])
+ let l = findfile('bar', ';../..', -1)
+ call assert_equal(1, len(l))
+ call assert_match('.*/Xfinddir1/Xdir2/Xdir3/bar', l[0])
let l = findfile('bar', ';' . save_dir . '/Xfinddir1/', -1)
call assert_equal(2, len(l))
call assert_match('.*/Xfinddir1/Xdir2/Xdir3/bar', l[0])
call assert_match('.*/Xfinddir1/bar', l[1])
+ let l = findfile('bar', ';' . save_dir . '/Xfinddir1', -1)
+ call assert_equal(2, len(l))
+ call assert_match('.*/Xfinddir1/Xdir2/Xdir3/bar', l[0])
+ call assert_match('.*/Xfinddir1/bar', l[1])
+ let l = findfile('bar', ';../../../', -1)
+ call assert_equal(2, len(l))
+ call assert_match('.*/Xfinddir1/Xdir2/Xdir3/bar', l[0])
+ call assert_match('.*/Xfinddir1/bar', l[1])
+ let l = findfile('bar', ';../../..', -1)
+ call assert_equal(2, len(l))
+ call assert_match('.*/Xfinddir1/Xdir2/Xdir3/bar', l[0])
+ call assert_match('.*/Xfinddir1/bar', l[1])
" Test combined downwards and upwards search from Xdir2/.
cd ../..
@@ -133,6 +167,7 @@ func Test_finddir()
let save_shellslash = &shellslash
let save_dir = getcwd()
set path=,,
+ set shellslash
call CreateFiles()
cd Xfinddir1
diff --git a/src/testdir/test_fnamemodify.vim b/src/testdir/test_fnamemodify.vim
index c19f464..4e61343 100644
--- a/src/testdir/test_fnamemodify.vim
+++ b/src/testdir/test_fnamemodify.vim
@@ -14,6 +14,8 @@ func Test_fnamemodify()
call assert_equal($HOME .. "/foo" , fnamemodify('~/foo', ':p'))
call assert_equal(fnamemodify('.', ':p:h:h:h') .. '/', fnamemodify($HOME .. '/../', ':p'))
call assert_equal(fnamemodify('.', ':p:h:h:h') .. '/', fnamemodify($HOME .. '/..', ':p'))
+ call assert_equal(fnamemodify('.', ':p:h:h') .. '/', fnamemodify('../', ':p'))
+ call assert_equal(fnamemodify('.', ':p:h:h') .. '/', fnamemodify('..', ':p'))
call assert_equal('test.out', fnamemodify('test.out', ':.'))
call assert_equal('a', fnamemodify('../testdir/a', ':.'))
call assert_equal('~/testdir/test.out', fnamemodify('test.out', ':~'))
diff --git a/src/testdir/test_fold.vim b/src/testdir/test_fold.vim
index dedc4a2..17487a5 100644
--- a/src/testdir/test_fold.vim
+++ b/src/testdir/test_fold.vim
@@ -1914,4 +1914,39 @@ func Test_foldexpr_end_fold()
bwipe!
endfunc
+" Test moving cursor down to or beyond start of folded end of buffer.
+func Test_cursor_down_fold_eob()
+ call setline(1, range(1, 4))
+ norm Gzf2kj
+ call assert_equal(2, line('.'))
+ norm zojzc
+ call assert_equal(3, line('.'))
+ norm j
+ call assert_equal(3, line('.'))
+ norm k2j
+ call assert_equal(4, line('.'))
+ bwipe!
+endfunc
+
+" issue: #15455
+func Test_cursor_fold_marker_undo()
+ new
+ call setline(1, ['{{{', '', 'This is a Line', '', 'This is a Line', '', '}}}'])
+ let &ul=&ul
+ setl foldmethod=marker
+ call cursor(2, 1)
+ norm! zo1vjdu
+ call assert_equal(1, foldlevel('.'))
+ bwipe!
+ new
+ call setline(1, ['', '{{{', '', 'This is a Line', '', 'This is a Line', '', '}}}'])
+ let &ul=&ul
+ setl foldmethod=marker
+ call cursor(3, 1)
+ norm! zo
+ norm! vjdu
+ call assert_equal(1, foldlevel('.'))
+ bwipe!
+endfunc
+
" vim: shiftwidth=2 sts=2 expandtab
diff --git a/src/testdir/test_functions.vim b/src/testdir/test_functions.vim
index acdb954..1021d05 100644
--- a/src/testdir/test_functions.vim
+++ b/src/testdir/test_functions.vim
@@ -923,6 +923,10 @@ func Test_mode()
call feedkeys("gQ\<Insert>\<F2>vi\<CR>", 'xt')
call assert_equal("c-cvr", g:current_modes)
+ " Commandline mode in Visual mode should return "c-c", never "v-v".
+ call feedkeys("v\<Cmd>call input('')\<CR>\<F2>\<CR>\<Esc>", 'xt')
+ call assert_equal("c-c", g:current_modes)
+
" Executing commands in Vim Ex mode should return "cv", never "cvr",
" as Cmdline editing has already ended.
call feedkeys("gQcall Save_mode()\<CR>vi\<CR>", 'xt')
@@ -3822,6 +3826,29 @@ func Test_glob2()
endif
endfunc
+func Test_glob_symlinks()
+ call writefile([], 'Xglob1')
+
+ if has("win32")
+ silent !mklink XglobBad DoesNotExist
+ if v:shell_error
+ throw 'Skipped: cannot create symlinks'
+ endif
+ silent !mklink XglobOk Xglob1
+ else
+ silent !ln -s DoesNotExist XglobBad
+ silent !ln -s Xglob1 XglobOk
+ endif
+
+ " The broken symlink is excluded when alllinks is false.
+ call assert_equal(['Xglob1', 'XglobBad', 'XglobOk'], sort(glob('Xglob*', 0, 1, 1)))
+ call assert_equal(['Xglob1', 'XglobOk'], sort(glob('Xglob*', 0, 1, 0)))
+
+ call delete('Xglob1')
+ call delete('XglobBad')
+ call delete('XglobOk')
+endfunc
+
" Test for browse()
func Test_browse()
CheckFeature browse
@@ -3842,11 +3869,6 @@ func Test_default_arg_value()
call assert_equal('msg', HasDefault())
endfunc
-" Test for gettext()
-func Test_gettext()
- call assert_fails('call gettext(1)', 'E1174:')
-endfunc
-
func Test_builtin_check()
call assert_fails('let g:["trim"] = {x -> " " .. x}', 'E704:')
call assert_fails('let g:.trim = {x -> " " .. x}', 'E704:')
diff --git a/src/testdir/test_gettext.vim b/src/testdir/test_gettext.vim
new file mode 100644
index 0000000..a990121
--- /dev/null
+++ b/src/testdir/test_gettext.vim
@@ -0,0 +1,18 @@
+source check.vim
+
+CheckFeature gettext
+
+" Test for gettext()
+func Test_gettext()
+ call assert_fails('call bindtextdomain("test")', 'E119:')
+ call assert_fails('call bindtextdomain("vim", "test")', 'E475:')
+
+ call assert_fails('call gettext(1)', 'E1174:')
+ call assert_equal('xxxTESTxxx', gettext("xxxTESTxxx"))
+
+ call assert_equal('xxxTESTxxx', gettext("xxxTESTxxx", "vim"))
+ call assert_equal('xxxTESTxxx', gettext("xxxTESTxxx", "__PACKAGE__"))
+ call assert_equal('ERROR: ', gettext("ERROR: ", "__PACKAGE__"))
+endfunc
+
+" vim: shiftwidth=2 sts=2 expandtab
diff --git a/src/testdir/test_gettext_cp1251.vim b/src/testdir/test_gettext_cp1251.vim
new file mode 100644
index 0000000..69d2bbf
--- /dev/null
+++ b/src/testdir/test_gettext_cp1251.vim
@@ -0,0 +1,35 @@
+source check.vim
+" This fail on CI MacOS 14 because bindtextdomain() is not available there
+" (missing library?)
+CheckNotMac
+CheckFeature gettext
+
+" Test for gettext()
+func Test_gettext()
+ set encoding=cp1251
+ call assert_equal('ERROR: ', gettext("ERROR: ", "__PACKAGE__"))
+
+ try
+ call assert_true(bindtextdomain("__PACKAGE__", getcwd()))
+
+ try
+ language messages ru_RU
+ call assert_equal('ÎØÈÁÊÀ: ', gettext("ERROR: ", "__PACKAGE__"))
+ catch /^Vim\%((\a\+)\)\=:E197:/
+ throw "Skipped: not possible to set locale to ru (missing?)"
+ endtry
+
+ try
+ language messages en_GB.UTF-8
+ call assert_equal('ERROR: ', gettext("ERROR: ", "__PACKAGE__"))
+ catch /^Vim\%((\a\+)\)\=:E197:/
+ throw "Skipped: not possible to set locale to en (missing?)"
+ endtry
+
+ catch /^Vim\%((\a\+)\)\=:E342:/
+ throw "Skipped: out of memory executing bindtextdomain()"
+ endtry
+ set encoding&
+endfunc
+
+" vim: shiftwidth=2 sts=2 expandtab
diff --git a/src/testdir/test_gettext_make.vim b/src/testdir/test_gettext_make.vim
new file mode 100644
index 0000000..1242fa4
--- /dev/null
+++ b/src/testdir/test_gettext_make.vim
@@ -0,0 +1,72 @@
+source check.vim
+CheckNotMac
+CheckFeature gettext
+
+" Test for package translation Makefile
+func Test_gettext_makefile()
+ cd ../po
+ if has('win32')
+ if getenv('GETTEXT_PATH') == v:null
+ throw 'Skipped: %GETTEXT_PATH% is not set.'
+ endif
+ call system('nmake.exe -f Make_mvc.mak "VIMPROG=' .. getenv('VIMPROG') ..
+ \ '" "GETTEXT_PATH=' .. getenv('GETTEXT_PATH') ..
+ \ '" PLUGPACKAGE=test_gettext
+ \ "PO_PLUG_INPUTLIST=..\testdir\test_gettext_makefile_in1.vim
+ \ ..\testdir\test_gettext_makefile_in2.vim
+ \ ..\testdir\test_gettext_makefile_in3.vim
+ \ ..\testdir\test_gettext_makefile_in4.vim" test_gettext.pot')
+ else
+" Will it work on macOS?
+ call system("make -f Makefile PLUGPACKAGE=test_gettext
+ \ PO_PLUG_INPUTLIST=\"../testdir/test_gettext_makefile_in1.vim
+ \ ../testdir/test_gettext_makefile_in2.vim
+ \ ../testdir/test_gettext_makefile_in3.vim
+ \ ../testdir/test_gettext_makefile_in4.vim\" test_gettext.pot")
+ endif
+ if v:shell_error != 0
+ throw 'Fail to create test_gettext.pot. Error code: ' .. v:shell_error
+ endif
+ let expected =<< trim END
+ # SOME DESCRIPTIVE TITLE.
+ # Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
+ # This file is distributed under the same license as the test_gettext package.
+ # FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
+ #
+ #, fuzzy
+ msgid ""
+ msgstr ""
+ "Project-Id-Version: test_gettext\n"
+ "Report-Msgid-Bugs-To: \n"
+ "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
+ "Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
+ "Language-Team: LANGUAGE <LL@li.org>\n"
+ "Language: \n"
+ "MIME-Version: 1.0\n"
+ "Content-Type: text/plain; charset=CHARSET\n"
+ "Content-Transfer-Encoding: 8bit\n"
+
+ #: ../testdir/test_gettext_makefile_in1.vim:4 ../testdir/test_gettext_makefile_in1.vim:6
+ #: ../testdir/test_gettext_makefile_in2.vim:5 ../testdir/test_gettext_makefile_in4.vim:4
+ msgid "This is a test"
+ msgstr ""
+
+ #: ../testdir/test_gettext_makefile_in1.vim:5
+ msgid "This is another test"
+ msgstr ""
+
+ #: ../testdir/test_gettext_makefile_in2.vim:4
+ msgid "This is a test from the second file"
+ msgstr ""
+
+ #: ../testdir/test_gettext_makefile_in4.vim:5
+ msgid "This is a fourth test"
+ msgstr ""
+ END
+ let potfile = filter(readfile("test_gettext.pot"), 'v:val !~ "POT-Creation-Date"')
+ call assert_equal(expected, potfile)
+ call delete('test_gettext.pot')
+ cd -
+endfunc
+
+" vim: shiftwidth=2 sts=2 expandtab
diff --git a/src/testdir/test_gettext_makefile_in1.vim b/src/testdir/test_gettext_makefile_in1.vim
new file mode 100644
index 0000000..cbe1159
--- /dev/null
+++ b/src/testdir/test_gettext_makefile_in1.vim
@@ -0,0 +1,7 @@
+" Test file for gettext() package makefile
+" Last Change: 2024 Jun 01
+
+echo gettext("This is a test", "test_gettext")
+echo gettext("This is another test", "test_gettext")
+echo gettext("This is a test", "test_gettext")
+" vim: ts=8
diff --git a/src/testdir/test_gettext_makefile_in2.vim b/src/testdir/test_gettext_makefile_in2.vim
new file mode 100644
index 0000000..86d3dd9
--- /dev/null
+++ b/src/testdir/test_gettext_makefile_in2.vim
@@ -0,0 +1,6 @@
+" Test file for gettext() package makefile
+" Last Change: 2024 Jun 01
+
+echo gettext("This is a test from the second file", "test_gettext")
+echo gettext("This is a test", "test_gettext")
+" vim: ts=8
diff --git a/src/testdir/test_gettext_makefile_in3.vim b/src/testdir/test_gettext_makefile_in3.vim
new file mode 100644
index 0000000..f4cf93d
--- /dev/null
+++ b/src/testdir/test_gettext_makefile_in3.vim
@@ -0,0 +1,4 @@
+" Test file for gettext() package makefile
+" Last Change: 2024 Jun 01
+
+" vim: ts=8
diff --git a/src/testdir/test_gettext_makefile_in4.vim b/src/testdir/test_gettext_makefile_in4.vim
new file mode 100644
index 0000000..7f9f3f7
--- /dev/null
+++ b/src/testdir/test_gettext_makefile_in4.vim
@@ -0,0 +1,6 @@
+" Test file for gettext() package makefile
+" Last Change: 2024 Jun 01
+
+echo gettext("This is a test", "test_gettext")
+echo gettext("This is a fourth test", "test_gettext")
+" vim: ts=8
diff --git a/src/testdir/test_gettext_utf8.vim b/src/testdir/test_gettext_utf8.vim
new file mode 100644
index 0000000..b96f8ea
--- /dev/null
+++ b/src/testdir/test_gettext_utf8.vim
@@ -0,0 +1,35 @@
+source check.vim
+" This fail on CI MacOS 14 because bindtextdomain() is not available there
+" (missing library?)
+CheckNotMac
+CheckFeature gettext
+
+" Test for gettext()
+func Test_gettext()
+ set encoding=utf-8
+ call assert_equal('ERROR: ', gettext("ERROR: ", "__PACKAGE__"))
+
+ try
+ call assert_true(bindtextdomain("__PACKAGE__", getcwd()))
+
+ try
+ language messages ru_RU
+ call assert_equal('ОШИБКÐ: ', gettext("ERROR: ", "__PACKAGE__"))
+ catch /^Vim\%((\a\+)\)\=:E197:/
+ throw "Skipped: not possible to set locale to ru (missing?)"
+ endtry
+
+ try
+ language messages en_GB.UTF-8
+ call assert_equal('ERROR: ', gettext("ERROR: ", "__PACKAGE__"))
+ catch /^Vim\%((\a\+)\)\=:E197:/
+ throw "Skipped: not possible to set locale to en (missing?)"
+ endtry
+
+ catch /^Vim\%((\a\+)\)\=:E342:/
+ throw "Skipped: out of memory executing bindtextdomain()"
+ endtry
+ set encoding&
+endfunc
+
+" vim: shiftwidth=2 sts=2 expandtab
diff --git a/src/testdir/test_getvar.vim b/src/testdir/test_getvar.vim
index 2065186..6efb192 100644
--- a/src/testdir/test_getvar.vim
+++ b/src/testdir/test_getvar.vim
@@ -142,20 +142,28 @@ func Test_get_func()
let l:F = function('tr')
call assert_equal('tr', get(l:F, 'name'))
call assert_equal(l:F, get(l:F, 'func'))
+ call assert_equal({'required': 3, 'optional': 0, 'varargs': v:false},
+ \ get(l:F, 'arity'))
let Fb_func = function('s:FooBar')
call assert_match('<SNR>\d\+_FooBar', get(Fb_func, 'name'))
+ call assert_equal({'required': 0, 'optional': 0, 'varargs': v:false},
+ \ get(Fb_func, 'arity'))
let Fb_ref = funcref('s:FooBar')
call assert_match('<SNR>\d\+_FooBar', get(Fb_ref, 'name'))
+ call assert_equal({'required': 0, 'optional': 0, 'varargs': v:false},
+ \ get(Fb_ref, 'arity'))
call assert_equal({'func has': 'no dict'}, get(l:F, 'dict', {'func has': 'no dict'}))
call assert_equal(0, get(l:F, 'dict'))
call assert_equal([], get(l:F, 'args'))
+
let NF = test_null_function()
call assert_equal('', get(NF, 'name'))
call assert_equal(NF, get(NF, 'func'))
call assert_equal(0, get(NF, 'dict'))
call assert_equal([], get(NF, 'args'))
+ call assert_equal({'required': 0, 'optional': 0, 'varargs': v:false}, get(NF, 'arity'))
endfunc
" get({partial}, {what} [, {default}]) - in test_partial.vim
diff --git a/src/testdir/test_goto.vim b/src/testdir/test_goto.vim
index 357a8d2..b6a6695 100644
--- a/src/testdir/test_goto.vim
+++ b/src/testdir/test_goto.vim
@@ -296,6 +296,7 @@ func Test_gd_string()
return x;
}
[CODE]
+
call XTest_goto_decl('gd', lines, 4, 7)
endfunc
@@ -320,14 +321,16 @@ func Test_set_options_keep_col()
let pos = getcurpos()
normal j
set invhlsearch spell spelllang=en,cjk spelloptions=camel textwidth=80
- set cursorline cursorcolumn cursorlineopt=line colorcolumn=+1
+ set cursorline cursorcolumn cursorlineopt=line colorcolumn=+1 winfixbuf
+ set comments=:# commentstring=#%s define=function
set background=dark
set background=light
normal k
call assert_equal(pos, getcurpos())
bwipe!
set hlsearch& spell& spelllang& spelloptions& textwidth&
- set cursorline& cursorcolumn& cursorlineopt& colorcolumn&
+ set cursorline& cursorcolumn& cursorlineopt& colorcolumn& winfixbuf&
+ set comments& commentstring& define&
set background&
endfunc
diff --git a/src/testdir/test_gui.vim b/src/testdir/test_gui.vim
index d53750f..ae65310 100644
--- a/src/testdir/test_gui.vim
+++ b/src/testdir/test_gui.vim
@@ -1708,7 +1708,8 @@ func Test_gui_lowlevel_keyevent()
new
" Test for <Ctrl-A> to <Ctrl-Z> keys
- for kc in range(65, 90)
+ " FIXME: <Ctrl-C> is excluded for now. It makes the test flaky.
+ for kc in range(65, 66) + range(68, 90)
call SendKeys([0x11, kc])
try
let ch = getcharstr()
diff --git a/src/testdir/test_increment.vim b/src/testdir/test_increment.vim
index fdd7c0c..3a5f5ee 100644
--- a/src/testdir/test_increment.vim
+++ b/src/testdir/test_increment.vim
@@ -840,6 +840,44 @@ func Test_increment_unsigned()
set nrformats-=unsigned
endfunc
+" Try incrementing/decrementing a number when nrformats contains blank
+func Test_increment_blank()
+ set nrformats+=blank
+
+ " Signed
+ call setline(1, '0')
+ exec "norm! gg0\<C-X>"
+ call assert_equal('-1', getline(1))
+
+ call setline(1, '3')
+ exec "norm! gg010\<C-X>"
+ call assert_equal('-7', getline(1))
+
+ call setline(1, '-0')
+ exec "norm! gg0\<C-X>"
+ call assert_equal("-1", getline(1))
+
+ " Unsigned
+ " NOTE: 18446744073709551615 == 2^64 - 1
+ call setline(1, 'a-18446744073709551615')
+ exec "norm! gg0\<C-A>"
+ call assert_equal('a-18446744073709551615', getline(1))
+
+ call setline(1, 'a-18446744073709551615')
+ exec "norm! gg0\<C-A>"
+ call assert_equal('a-18446744073709551615', getline(1))
+
+ call setline(1, 'a-18446744073709551614')
+ exec "norm! gg08\<C-A>"
+ call assert_equal('a-18446744073709551615', getline(1))
+
+ call setline(1, 'a-1')
+ exec "norm! gg0\<C-A>"
+ call assert_equal('a-2', getline(1))
+
+ set nrformats-=blank
+endfunc
+
func Test_in_decrement_large_number()
" NOTE: 18446744073709551616 == 2^64
call setline(1, '18446744073709551616')
diff --git a/src/testdir/test_ins_complete.vim b/src/testdir/test_ins_complete.vim
index 48589ce..aee3393 100644
--- a/src/testdir/test_ins_complete.vim
+++ b/src/testdir/test_ins_complete.vim
@@ -2586,9 +2586,85 @@ func Test_complete_fuzzy_match()
call feedkeys("A\<C-X>\<C-N>\<Esc>0", 'tx!')
call assert_equal('hello help hero h', getline('.'))
+ set completeopt-=noinsert
+ call setline(1, ['xyz yxz x'])
+ call feedkeys("A\<C-X>\<C-N>\<Esc>0", 'tx!')
+ call assert_equal('xyz yxz xyz', getline('.'))
+ " can fuzzy get yxz when use Ctrl-N twice
+ call setline(1, ['xyz yxz x'])
+ call feedkeys("A\<C-X>\<C-N>\<C-N>\<Esc>0", 'tx!')
+ call assert_equal('xyz yxz yxz', getline('.'))
+
+ call setline(1, ['你好 你'])
+ call feedkeys("A\<C-X>\<C-N>\<Esc>0", 'tx!')
+ call assert_equal('你好 你好', getline('.'))
+ call setline(1, ['你的 我的 的'])
+ call feedkeys("A\<C-X>\<C-N>\<Esc>0", 'tx!')
+ call assert_equal('你的 我的 你的', getline('.'))
+ " can fuzzy get multiple-byte word when use Ctrl-N twice
+ call setline(1, ['你的 我的 的'])
+ call feedkeys("A\<C-X>\<C-N>\<C-N>\<Esc>0", 'tx!')
+ call assert_equal('你的 我的 我的', getline('.'))
+
+ " respect wrapscan
+ set nowrapscan
+ call setline(1, ["xyz", "yxz", ""])
+ call cursor(3, 1)
+ call feedkeys("Sy\<C-X>\<C-N>\<Esc>0", 'tx!')
+ call assert_equal('y', getline('.'))
+ set wrapscan
+ call feedkeys("Sy\<C-X>\<C-N>\<Esc>0", 'tx!')
+ call assert_equal('xyz', getline('.'))
+
+ " fuzzy on file
+ call writefile([''], 'fobar', 'D')
+ call writefile([''], 'foobar', 'D')
+ call setline(1, ['fob'])
+ call cursor(1, 1)
+ call feedkeys("A\<C-X>\<C-f>\<Esc>0", 'tx!')
+ call assert_equal('fobar', getline('.'))
+ call feedkeys("Sfob\<C-X>\<C-f>\<C-N>\<Esc>0", 'tx!')
+ call assert_equal('foobar', getline('.'))
+ call feedkeys("S../\<C-X>\<C-f>\<Esc>0", 'tx!')
+ call assert_match('../*', getline('.'))
+ call feedkeys("S../td\<C-X>\<C-f>\<Esc>0", 'tx!')
+ call assert_match('../testdir', getline('.'))
+
+ " can get completion from other buffer
+ set completeopt=fuzzy,menu,menuone
+ vnew
+ call setline(1, ["completeness,", "compatibility", "Composite", "Omnipotent"])
+ wincmd p
+ call feedkeys("Somp\<C-N>\<Esc>0", 'tx!')
+ call assert_equal('completeness', getline('.'))
+ call feedkeys("Somp\<C-N>\<C-N>\<Esc>0", 'tx!')
+ call assert_equal('compatibility', getline('.'))
+ call feedkeys("Somp\<C-P>\<Esc>0", 'tx!')
+ call assert_equal('Omnipotent', getline('.'))
+ call feedkeys("Somp\<C-P>\<C-P>\<Esc>0", 'tx!')
+ call assert_equal('Composite', getline('.'))
+ call feedkeys("S omp\<C-N>\<Esc>0", 'tx!')
+ call assert_equal(' completeness', getline('.'))
+
+ " fuzzy on whole line completion
+ call setline(1, ["world is on fire", "no one can save me but you", 'user can execute', ''])
+ call cursor(4, 1)
+ call feedkeys("Swio\<C-X>\<C-L>\<Esc>0", 'tx!')
+ call assert_equal('world is on fire', getline('.'))
+ call feedkeys("Su\<C-X>\<C-L>\<C-P>\<Esc>0", 'tx!')
+ call assert_equal('no one can save me but you', getline('.'))
+
+ " issue #15526
+ set completeopt=fuzzy,menuone,menu,noselect
+ call setline(1, ['Text', 'ToText', ''])
+ call cursor(2, 1)
+ call feedkeys("STe\<C-X>\<C-N>x\<CR>\<Esc>0", 'tx!')
+ call assert_equal('Tex', getline('.'))
+
" clean up
set omnifunc=
bw!
+ bw!
set complete& completeopt&
autocmd! AAAAA_Group
augroup! AAAAA_Group
@@ -2599,6 +2675,38 @@ func Test_complete_fuzzy_match()
unlet g:word
endfunc
+func Test_complete_fuzzy_with_completeslash()
+ CheckMSWindows
+
+ call writefile([''], 'fobar', 'D')
+ let orig_shellslash = &shellslash
+ set cpt&
+ new
+ set completeopt+=fuzzy
+ set noshellslash
+
+ " Test with completeslash unset
+ set completeslash=
+ call setline(1, ['.\fob'])
+ call feedkeys("A\<C-X>\<C-F>\<Esc>0", 'tx!')
+ call assert_equal('.\fobar', getline('.'))
+
+ " Test with completeslash=backslash
+ set completeslash=backslash
+ call feedkeys("S.\\fob\<C-X>\<C-F>\<Esc>0", 'tx!')
+ call assert_equal('.\fobar', getline('.'))
+
+ " Test with completeslash=slash
+ set completeslash=slash
+ call feedkeys("S.\\fob\<C-X>\<C-F>\<Esc>0", 'tx!')
+ call assert_equal('./fobar', getline('.'))
+
+ " Reset and clean up
+ let &shellslash = orig_shellslash
+ set completeslash=
+ %bw!
+endfunc
+
" Check that tie breaking is stable for completeopt+=fuzzy (which should
" behave the same on different platforms).
func Test_complete_fuzzy_match_tie()
@@ -2619,4 +2727,14 @@ func Test_complete_fuzzy_match_tie()
set completeopt&
endfunc
+func Test_complete_backwards_default()
+ new
+ call append(1, ['foobar', 'foobaz'])
+ new
+ call feedkeys("i\<c-p>", 'tx')
+ call assert_equal('foobaz', getline('.'))
+ bw!
+ bw!
+endfunc
+
" vim: shiftwidth=2 sts=2 expandtab nofoldenable
diff --git a/src/testdir/test_jumplist.vim b/src/testdir/test_jumplist.vim
index 8fbf39f..4b9fcee 100644
--- a/src/testdir/test_jumplist.vim
+++ b/src/testdir/test_jumplist.vim
@@ -59,29 +59,63 @@ func Test_getjumplist()
call assert_equal(4, l[1])
endfunc
-func Test_jumplist_invalid()
+func Test_jumplist_wipe_buf()
new
clearjumps
- " put some randome text
- put ='a'
- let prev = bufnr('%')
+ " Put some random text and fill the jump list.
+ call setline(1, ['foo', 'bar', 'baz'])
+ normal G
+ normal gg
setl nomodified bufhidden=wipe
e XXJumpListBuffer
- let bnr = bufnr('%')
- " 1) empty jumplist
- let expected = [[
- \ {'lnum': 2, 'bufnr': prev, 'col': 0, 'coladd': 0}], 1]
- call assert_equal(expected, getjumplist())
+ " The jump list is empty as the buffer was wiped out.
+ call assert_equal([[], 0], getjumplist())
let jumps = execute(':jumps')
call assert_equal('>', jumps[-1:])
- " now jump back
- exe ":norm! \<c-o>"
- let expected = [[
- \ {'lnum': 2, 'bufnr': prev, 'col': 0, 'coladd': 0},
- \ {'lnum': 1, 'bufnr': bnr, 'col': 0, 'coladd': 0}], 0]
- call assert_equal(expected, getjumplist())
- let jumps = execute(':jumps')
- call assert_match('> 0 2 0 -invalid-', jumps)
+
+ " Put some random text and fill the jump list.
+ call setline(1, ['foo', 'bar', 'baz'])
+ setl bufhidden=hide
+
+ " References to wiped buffer are deleted with multiple tabpages.
+ let [w1, t1] = [win_getid(), tabpagenr()]
+ clearjumps
+ normal G
+ normal gg
+ enew
+
+ split XXJumpListBuffer
+ let [w2, t2] = [win_getid(), tabpagenr()]
+ clearjumps
+ normal G
+ normal gg
+ enew
+
+ tabnew XXJumpListBuffer
+ let [w3, t3] = [win_getid(), tabpagenr()]
+ clearjumps
+ normal G
+ normal gg
+ enew
+
+ split XXJumpListBuffer
+ let [w4, t4] = [win_getid(), tabpagenr()]
+ clearjumps
+ normal G
+ normal gg
+ enew
+
+ for [w, t] in [[w1, t1], [w2, t2], [w3, t3], [w4, t4]]
+ call assert_equal(2, len(getjumplist(w, t)[0]))
+ endfor
+
+ bwipe! XXJumpListBuffer
+
+ for [w, t] in [[w1, t1], [w2, t2], [w3, t3], [w4, t4]]
+ call assert_equal(0, len(getjumplist(w, t)[0]))
+ endfor
+
+ %bwipe!
endfunc
" Test for '' mark in an empty buffer
diff --git a/src/testdir/test_listdict.vim b/src/testdir/test_listdict.vim
index 12a6dd4..48217cf 100644
--- a/src/testdir/test_listdict.vim
+++ b/src/testdir/test_listdict.vim
@@ -1147,6 +1147,19 @@ func Test_listdict_compare()
call assert_fails('echo {} =~ {}', 'E736:')
endfunc
+func Test_recursive_listdict_compare()
+ let l1 = [0, 1]
+ let l1[0] = l1
+ let l2 = [0, 1]
+ let l2[0] = l2
+ call assert_true(l1 == l2)
+ let d1 = {0: 0, 1: 1}
+ let d1[0] = d1
+ let d2 = {0: 0, 1: 1}
+ let d2[0] = d2
+ call assert_true(d1 == d2)
+endfunc
+
" compare complex recursively linked list and dict
func Test_listdict_compare_complex()
let lines =<< trim END
@@ -1557,4 +1570,83 @@ func Test_extendnew_leak()
for i in range(100) | silent! call extendnew({}, {}, {}) | endfor
endfunc
+" Test for comparing deeply nested List/Dict values
+func Test_deep_nested_listdict_compare()
+ let lines =<< trim END
+ def GetNestedList(sz: number): list<any>
+ var l: list<any> = []
+ var x: list<any> = l
+ for i in range(sz)
+ var y: list<any> = [1]
+ add(x, y)
+ x = y
+ endfor
+ return l
+ enddef
+
+ VAR l1 = GetNestedList(1000)
+ VAR l2 = GetNestedList(999)
+ call assert_false(l1 == l2)
+
+ #" after 1000 nested items, the lists are considered to be equal
+ VAR l3 = GetNestedList(1001)
+ VAR l4 = GetNestedList(1002)
+ call assert_true(l3 == l4)
+ END
+ call v9.CheckLegacyAndVim9Success(lines)
+
+ let lines =<< trim END
+ def GetNestedDict(sz: number): dict<any>
+ var d: dict<any> = {}
+ var x: dict<any> = d
+ for i in range(sz)
+ var y: dict<any> = {}
+ x['a'] = y
+ x = y
+ endfor
+ return d
+ enddef
+
+ VAR d1 = GetNestedDict(1000)
+ VAR d2 = GetNestedDict(999)
+ call assert_false(d1 == d2)
+
+ #" after 1000 nested items, the Dicts are considered to be equal
+ VAR d3 = GetNestedDict(1001)
+ VAR d4 = GetNestedDict(1002)
+ call assert_true(d3 == d4)
+ END
+ call v9.CheckLegacyAndVim9Success(lines)
+endfunc
+
+" Test for using id()
+def Test_id_with_dict()
+ # demonstate a way that "id(item)" differs from "string(item)"
+ var d1 = {one: 1}
+ var d2 = {one: 1}
+ var d3 = {one: 1}
+ var idDict: dict<any>
+ idDict[id(d1)] = d1
+ idDict[id(d2)] = d2
+ idDict[id(d3)] = d3
+ assert_equal(3, idDict->len())
+
+ var stringDict: dict<any>
+ stringDict[string(d1)] = d1
+ stringDict[string(d2)] = d2
+ stringDict[string(d3)] = d3
+ assert_equal(1, stringDict->len())
+
+ assert_equal('', id(3))
+
+ assert_equal('', id(null))
+ assert_equal('', id(null_blob))
+ assert_equal('', id(null_dict))
+ assert_equal('', id(null_function))
+ assert_equal('', id(null_list))
+ assert_equal('', id(null_partial))
+ assert_equal('', id(null_string))
+ assert_equal('', id(null_channel))
+ assert_equal('', id(null_job))
+enddef
" vim: shiftwidth=2 sts=2 expandtab
diff --git a/src/testdir/test_listlbr_utf8.vim b/src/testdir/test_listlbr_utf8.vim
index 313ff30..693f201 100644
--- a/src/testdir/test_listlbr_utf8.vim
+++ b/src/testdir/test_listlbr_utf8.vim
@@ -280,6 +280,9 @@ func Test_chinese_char_on_wrap_column()
call s:compare_lines(expect, lines)
call assert_equal(len(expect), winline())
call assert_equal(strwidth(trim(expect[-1], ' ', 2)), wincol())
+ norm! g0
+ call assert_equal(len(expect), winline())
+ call assert_equal(1, wincol())
call s:close_windows()
endfunc
@@ -315,6 +318,9 @@ func Test_chinese_char_on_wrap_column_sbr()
call s:compare_lines(expect, lines)
call assert_equal(len(expect), winline())
call assert_equal(strwidth(trim(expect[-1], ' ', 2)), wincol())
+ norm! g0
+ call assert_equal(len(expect), winline())
+ call assert_equal(4, wincol())
call s:close_windows()
endfunc
diff --git a/src/testdir/test_mapping.vim b/src/testdir/test_mapping.vim
index 1175310..064f8ac 100644
--- a/src/testdir/test_mapping.vim
+++ b/src/testdir/test_mapping.vim
@@ -1767,6 +1767,49 @@ func Test_unmap_simplifiable()
unmap <C-I>
endfunc
+" Test that the first byte of rhs is not remapped if rhs starts with lhs.
+func Test_map_rhs_starts_with_lhs()
+ new
+ func MapExpr()
+ return "\<C-R>\<C-P>"
+ endfunc
+
+ for expr in [v:false, v:true]
+ if expr
+ imap <buffer><expr> <C-R> MapExpr()
+ else
+ imap <buffer> <C-R> <C-R><C-P>
+ endif
+
+ for restore in [v:false, v:true]
+ if restore
+ let saved = maparg('<C-R>', 'i', v:false, v:true)
+ iunmap <buffer> <C-R>
+ call mapset(saved)
+ endif
+
+ let @a = 'foo'
+ call assert_nobeep('call feedkeys("S\<C-R>a", "tx")')
+ call assert_equal('foo', getline('.'))
+
+ let @a = 'bar'
+ call assert_nobeep('call feedkeys("S\<*C-R>a", "tx")')
+ call assert_equal('bar', getline('.'))
+ endfor
+ endfor
+
+ " When two mappings are used for <C-I> and <Tab>, remapping should work.
+ imap <buffer> <C-I> <Tab>bar
+ imap <buffer> <Tab> foo
+ call feedkeys("S\<Tab>", 'xt')
+ call assert_equal('foo', getline('.'))
+ call feedkeys("S\<*C-I>", 'xt')
+ call assert_equal('foobar', getline('.'))
+
+ delfunc MapExpr
+ bwipe!
+endfunc
+
func Test_expr_map_escape_special()
nnoremap … <Cmd>let g:got_ellipsis += 1<CR>
func Func()
diff --git a/src/testdir/test_matchparen.vim b/src/testdir/test_matchparen.vim
index 70aa38f..49d3510 100644
--- a/src/testdir/test_matchparen.vim
+++ b/src/testdir/test_matchparen.vim
@@ -108,5 +108,35 @@ func Test_matchparen_pum_clear()
call StopVimInTerminal(buf)
endfunc
+" Test that matchparen works with multibyte chars in 'matchpairs'
+func Test_matchparen_mbyte()
+ CheckScreendump
+
+ let lines =<< trim END
+ source $VIMRUNTIME/plugin/matchparen.vim
+ call setline(1, ['aaaaaaaa(', 'bbbb)cc'])
+ set matchpairs+=(:)
+ END
+
+ call writefile(lines, 'XmatchparenMbyte', 'D')
+ let buf = RunVimInTerminal('-S XmatchparenMbyte', #{rows: 10})
+ call VerifyScreenDump(buf, 'Test_matchparen_mbyte_1', {})
+ call term_sendkeys(buf, "$")
+ call VerifyScreenDump(buf, 'Test_matchparen_mbyte_2', {})
+ call term_sendkeys(buf, "j")
+ call VerifyScreenDump(buf, 'Test_matchparen_mbyte_3', {})
+ call term_sendkeys(buf, "2h")
+ call VerifyScreenDump(buf, 'Test_matchparen_mbyte_4', {})
+ call term_sendkeys(buf, "0")
+ call VerifyScreenDump(buf, 'Test_matchparen_mbyte_5', {})
+ call term_sendkeys(buf, "kA")
+ call VerifyScreenDump(buf, 'Test_matchparen_mbyte_6', {})
+ call term_sendkeys(buf, "\<Down>")
+ call VerifyScreenDump(buf, 'Test_matchparen_mbyte_7', {})
+ call term_sendkeys(buf, "\<C-W>")
+ call VerifyScreenDump(buf, 'Test_matchparen_mbyte_8', {})
+
+ call StopVimInTerminal(buf)
+endfunc
" vim: shiftwidth=2 sts=2 expandtab
diff --git a/src/testdir/test_menu.vim b/src/testdir/test_menu.vim
index 2229228..40fec40 100644
--- a/src/testdir/test_menu.vim
+++ b/src/testdir/test_menu.vim
@@ -481,13 +481,48 @@ func Test_popup_menu()
unmenu PopUp
endfunc
+func Test_popup_menu_truncated()
+ CheckNotGui
+
+ set mouse=a mousemodel=popup
+ aunmenu PopUp
+ for i in range(2 * &lines)
+ exe $'menu PopUp.{i} <Cmd>let g:res = {i}<CR>'
+ endfor
+
+ func LeftClickExpr(row, col)
+ call test_setmouse(a:row, a:col)
+ return "\<LeftMouse>"
+ endfunc
+
+ " Clicking at the bottom should place popup menu above click position.
+ " <RightRelease> should not select an item immediately.
+ let g:res = -1
+ call test_setmouse(&lines, 1)
+ nnoremap <expr><F2> LeftClickExpr(4, 1)
+ call feedkeys("\<RightMouse>\<RightRelease>\<F2>", 'tx')
+ call assert_equal(3, g:res)
+
+ " Clicking at the top should place popup menu below click position.
+ let g:res = -1
+ call test_setmouse(1, 1)
+ nnoremap <expr><F2> LeftClickExpr(5, 1)
+ call feedkeys("\<RightMouse>\<RightRelease>\<F2>", 'tx')
+ call assert_equal(3, g:res)
+
+ nunmap <F2>
+ delfunc LeftClickExpr
+ unlet g:res
+ aunmenu PopUp
+ set mouse& mousemodel&
+endfunc
+
" Test for MenuPopup autocommand
func Test_autocmd_MenuPopup()
CheckNotGui
- set mouse=a
- set mousemodel=popup
- aunmenu *
+ set mouse=a mousemodel=popup
+ aunmenu PopUp
autocmd MenuPopup * exe printf(
\ 'anoremenu PopUp.Foo <Cmd>let g:res = ["%s", "%s"]<CR>',
\ expand('<afile>'), expand('<amatch>'))
diff --git a/src/testdir/test_normal.vim b/src/testdir/test_normal.vim
index 83594d2..398bf29 100644
--- a/src/testdir/test_normal.vim
+++ b/src/testdir/test_normal.vim
@@ -4257,6 +4257,9 @@ func Test_page_cursor_topbot()
call assert_equal(18, line('.'))
exe "norm! \<C-B>\<C-F>"
call assert_equal(9, line('.'))
+ " Not when already at the start of the buffer.
+ exe "norm! ggj\<C-B>"
+ call assert_equal(2, line('.'))
bwipe!
endfunc
diff --git a/src/testdir/test_options.vim b/src/testdir/test_options.vim
index fbfbaae..94c98fe 100644
--- a/src/testdir/test_options.vim
+++ b/src/testdir/test_options.vim
@@ -548,6 +548,9 @@ func Test_set_completion_string_values()
call assert_equal('sync', getcompletion('set swapsync=', 'cmdline')[1])
call assert_equal('usetab', getcompletion('set switchbuf=', 'cmdline')[1])
call assert_equal('ignore', getcompletion('set tagcase=', 'cmdline')[1])
+ if exists('+tabclose')
+ call assert_equal('left uselast', join(sort(getcompletion('set tabclose=', 'cmdline'))), ' ')
+ endif
if exists('+termwintype')
call assert_equal('conpty', getcompletion('set termwintype=', 'cmdline')[1])
endif
@@ -1407,7 +1410,8 @@ func Test_write()
set nowrite
call assert_fails('write Xwrfile', 'E142:')
set write
- close!
+ " close swapfile
+ bw!
endfunc
" Test for 'buftype' option
@@ -1724,7 +1728,7 @@ func Test_VIM_POSIX()
qall
[CODE]
if RunVim([], after, '')
- call assert_equal(['aAbBcCdDeEfFgHiIjJkKlLmMnoOpPqrRsStuvwWxXyZ$!%*-+<>#{|&/\.;',
+ call assert_equal(['aAbBcCdDeEfFgHiIjJkKlLmMnoOpPqrRsStuvwWxXyZz$!%*-+<>#{|&/\.;',
\ 'AS'], readfile('X_VIM_POSIX'))
endif
@@ -1734,7 +1738,7 @@ func Test_VIM_POSIX()
qall
[CODE]
if RunVim([], after, '')
- call assert_equal(['aAbBcCdDeEfFgHiIjJkKlLmMnoOpPqrRsStuvwWxXyZ$!%*-+<>;',
+ call assert_equal(['aAbBcCdDeEfFgHiIjJkKlLmMnoOpPqrRsStuvwWxXyZz$!%*-+<>;',
\ 'S'], readfile('X_VIM_POSIX'))
endif
diff --git a/src/testdir/test_partial.vim b/src/testdir/test_partial.vim
index b5a58f6..acc8b73 100644
--- a/src/testdir/test_partial.vim
+++ b/src/testdir/test_partial.vim
@@ -311,6 +311,11 @@ func Test_auto_partial_rebind()
endfunc
func Test_get_partial_items()
+ func s:Qux(x, y, z=3, w=1, ...)
+ endfunc
+ func s:Qux1(x, y)
+ endfunc
+
let dict = {'name': 'hello'}
let args = ["foo", "bar"]
let Func = function('MyDictFunc')
@@ -331,6 +336,23 @@ func Test_get_partial_items()
let dict = {'partial has': 'no dict'}
call assert_equal(dict, get(P, 'dict', dict))
call assert_equal(0, get(l:P, 'dict'))
+
+ call assert_equal({'required': 2, 'optional': 2, 'varargs': v:true},
+ \ get(funcref('s:Qux', []), 'arity'))
+ call assert_equal({'required': 1, 'optional': 2, 'varargs': v:true},
+ \ get(funcref('s:Qux', [1]), 'arity'))
+ call assert_equal({'required': 0, 'optional': 2, 'varargs': v:true},
+ \ get(funcref('s:Qux', [1, 2]), 'arity'))
+ call assert_equal({'required': 0, 'optional': 1, 'varargs': v:true},
+ \ get(funcref('s:Qux', [1, 2, 3]), 'arity'))
+ call assert_equal({'required': 0, 'optional': 0, 'varargs': v:true},
+ \ get(funcref('s:Qux', [1, 2, 3, 4]), 'arity'))
+ " More args than expected is not an error
+ call assert_equal({'required': 0, 'optional': 0, 'varargs': v:false},
+ \ get(funcref('s:Qux1', [1, 2, 3, 4]), 'arity'))
+
+ delfunc s:Qux
+ delfunc s:Qux1
endfunc
func Test_compare_partials()
diff --git a/src/testdir/test_paste.vim b/src/testdir/test_paste.vim
index d079f48..b35fc81 100644
--- a/src/testdir/test_paste.vim
+++ b/src/testdir/test_paste.vim
@@ -93,7 +93,7 @@ func Test_paste_ex_mode()
call assert_equal("foo\rbar", foo)
" pasting more than 40 bytes
- exe "norm Q\<PasteStart>0000000000000000000000000000000000000000000000000000000000000000000000\<C-C>"
+ exe "norm Q\<PasteStart>s/.*/0000000000000000000000000000000000000000000000000000000000000000/\<C-C>"
endfunc
func Test_paste_onechar()
diff --git a/src/testdir/test_popup.vim b/src/testdir/test_popup.vim
index dd01a57..fe958da 100644
--- a/src/testdir/test_popup.vim
+++ b/src/testdir/test_popup.vim
@@ -1482,8 +1482,101 @@ func Test_pum_highlights_match()
call term_sendkeys(buf, "o\<BS>\<C-R>=Comp()\<CR>")
call VerifyScreenDump(buf, 'Test_pum_highlights_09', {})
+ " issue #15095 wrong select
+ call term_sendkeys(buf, "\<ESC>:set completeopt=fuzzy,menu\<CR>")
+ call TermWait(buf)
+ call term_sendkeys(buf, "S hello helio hero h\<C-X>\<C-P>")
+ call TermWait(buf, 50)
+ call VerifyScreenDump(buf, 'Test_pum_highlights_10', {})
+
+ call term_sendkeys(buf, "\<ESC>S hello helio hero h\<C-X>\<C-P>\<C-P>")
+ call TermWait(buf, 50)
+ call VerifyScreenDump(buf, 'Test_pum_highlights_11', {})
+
+ " issue #15357
+ call term_sendkeys(buf, "\<ESC>S/non_exit_folder\<C-X>\<C-F>")
+ call TermWait(buf, 50)
+ call VerifyScreenDump(buf, 'Test_pum_highlights_15', {})
+
+ call term_sendkeys(buf, "\<C-E>\<Esc>")
+ call TermWait(buf)
+
+ call StopVimInTerminal(buf)
+endfunc
+
+func Test_pum_user_hl_group()
+ CheckScreendump
+ let lines =<< trim END
+ func CompleteFunc( findstart, base )
+ if a:findstart
+ return 0
+ endif
+ return {
+ \ 'words': [
+ \ { 'word': 'aword1', 'menu': 'extra text 1', 'kind': 'W', 'hl_group': 'StrikeFake' },
+ \ { 'word': 'aword2', 'menu': 'extra text 2', 'kind': 'W', },
+ \ { 'word': '你好', 'menu': 'extra text 3', 'kind': 'W', 'hl_group': 'StrikeFake' },
+ \]}
+ endfunc
+ set completeopt=menu
+ set completefunc=CompleteFunc
+
+ hi StrikeFake ctermfg=9
+ func HlMatch()
+ hi PmenuMatchSel ctermfg=6 ctermbg=7 cterm=underline
+ hi PmenuMatch ctermfg=4 ctermbg=225 cterm=underline
+ endfunc
+ END
+ call writefile(lines, 'Xscript', 'D')
+ let buf = RunVimInTerminal('-S Xscript', {})
+
+ call TermWait(buf)
+ call term_sendkeys(buf, "Saw\<C-X>\<C-U>")
+ call VerifyScreenDump(buf, 'Test_pum_highlights_12', {})
+ call term_sendkeys(buf, "\<C-E>\<Esc>")
+
+ call TermWait(buf)
+ call term_sendkeys(buf, ":call HlMatch()\<CR>")
+
+ call TermWait(buf)
+ call term_sendkeys(buf, "Saw\<C-X>\<C-U>")
+ call VerifyScreenDump(buf, 'Test_pum_highlights_13', {})
+ call term_sendkeys(buf, "\<C-N>")
+ call VerifyScreenDump(buf, 'Test_pum_highlights_14', {})
call term_sendkeys(buf, "\<C-E>\<Esc>")
+
+ call StopVimInTerminal(buf)
+endfunc
+
+func Test_pum_user_kind_hlgroup()
+ CheckScreendump
+ let lines =<< trim END
+ func CompleteFunc( findstart, base )
+ if a:findstart
+ return 0
+ endif
+ return {
+ \ 'words': [
+ \ { 'word': 'aword1', 'menu': 'extra text 1', 'kind': 'variable', 'kind_hlgroup': 'KindVar', 'hl_group': 'StrikeFake' },
+ \ { 'word': 'aword2', 'menu': 'extra text 2', 'kind': 'function', 'kind_hlgroup': 'KindFunc' },
+ \ { 'word': '你好', 'menu': 'extra text 3', 'kind': 'class', 'kind_hlgroup': 'KindClass' },
+ \]}
+ endfunc
+ set completeopt=menu
+ set completefunc=CompleteFunc
+
+ hi StrikeFake ctermfg=9
+ hi KindVar ctermfg=yellow
+ hi KindFunc ctermfg=blue
+ hi KindClass ctermfg=green
+ END
+ call writefile(lines, 'Xscript', 'D')
+ let buf = RunVimInTerminal('-S Xscript', {})
+
call TermWait(buf)
+ call term_sendkeys(buf, "S\<C-X>\<C-U>")
+ call VerifyScreenDump(buf, 'Test_pum_highlights_16', {})
+ call term_sendkeys(buf, "\<C-E>\<Esc>")
call StopVimInTerminal(buf)
endfunc
diff --git a/src/testdir/test_popupwin.vim b/src/testdir/test_popupwin.vim
index a397f70..64aa654 100644
--- a/src/testdir/test_popupwin.vim
+++ b/src/testdir/test_popupwin.vim
@@ -2499,6 +2499,88 @@ func Test_popup_settext_null()
call popup_close(id)
endfunc
+func Test_popup_setbuf()
+ CheckScreendump
+
+ let lines =<< trim END
+ let opts = #{wrap: 0}
+ let p = popup_create('test', opts)
+ let buf = bufnr('%')
+ END
+
+ call writefile(lines, 'XtestPopupSetBuf', 'D')
+ let buf = RunVimInTerminal('-S XtestPopupSetBuf', #{rows: 10})
+ call VerifyScreenDump(buf, 'Test_popup_setbuf_01', {})
+
+ " Setting to an non-existing buffer doesn't do anything
+ call term_sendkeys(buf, ":call popup_setbuf(p, 'foobar.txt')\<CR>")
+ call VerifyScreenDump(buf, 'Test_popup_setbuf_02', {})
+
+ " Error
+ call term_sendkeys(buf, ":call popup_setbuf(p, ['a','b','c'])\<CR>")
+ call VerifyScreenDump(buf, 'Test_popup_setbuf_03', {})
+
+ " Set to help window
+ call term_sendkeys(buf, ":help\<CR>")
+ call term_sendkeys(buf, ":call popup_setbuf(p, 'help.txt')\<CR>")
+ call VerifyScreenDump(buf, 'Test_popup_setbuf_04', {})
+
+ " Setting back to original buffer
+ call term_sendkeys(buf, ":call popup_setbuf(p, buf)\<CR>")
+ call VerifyScreenDump(buf, 'Test_popup_setbuf_05', {})
+
+ " use method
+ call term_sendkeys(buf, ":echo p->popup_setbuf('help.txt')\<CR>")
+ call VerifyScreenDump(buf, 'Test_popup_setbuf_06', {})
+
+ call term_sendkeys(buf, ":echo p->popup_setbuf(buf)\<CR>")
+ call VerifyScreenDump(buf, 'Test_popup_setbuf_05', {})
+
+ " clean up
+ call StopVimInTerminal(buf)
+endfunc
+
+func Test_popup_setbuf_terminal()
+ CheckFeature terminal
+
+ " Check Terminal Feature
+ let termbuf = term_start(&shell, #{hidden: 1})
+ " Wait for shell to start
+ call WaitForAssert({-> assert_equal("run", job_status(term_getjob(termbuf)))})
+
+ let popup = popup_create('test', {})
+ call assert_true(popup->popup_setbuf(termbuf))
+ call popup_close(popup)
+
+ let popup1 = popup_create(termbuf, #{minwidth: 40, minheight: 10, border: []})
+
+ let popup = popup_create('test', {})
+ try
+ call assert_fails(call popup_setbuf(popup, termbuf))
+ catch
+ endtry
+ call popup_close(popup)
+ call popup_close(popup1)
+ call assert_equal([], popup_list())
+ " Close the terminal
+ call term_sendkeys(termbuf, "exit\<CR>")
+ " Wait for shell to exit
+ call WaitForAssert({-> assert_equal("dead", job_status(term_getjob(termbuf)))})
+endfunc
+
+func Test_popup_setbuf_null()
+ let id = popup_create('', {})
+ call assert_false(popup_setbuf(id, -1))
+ call popup_close(id)
+
+ let id = popup_create('', {})
+ call assert_true(popup_setbuf(id, test_null_string()))
+ call assert_true(popup_setbuf(id, ''))
+ call popup_close(id)
+
+ call assert_false(popup_setbuf(id, 0))
+endfunc
+
func Test_popup_hidden()
new
diff --git a/src/testdir/test_put.vim b/src/testdir/test_put.vim
index 69c2943..94e4f47 100644
--- a/src/testdir/test_put.vim
+++ b/src/testdir/test_put.vim
@@ -168,10 +168,6 @@ func Test_very_large_count()
endfunc
func Test_very_large_count_64bit()
- if v:sizeoflong < 8
- throw 'Skipped: only works with 64 bit long ints'
- endif
-
new
let @" = repeat('x', 100)
call assert_fails('norm 999999999p', 'E1240:')
@@ -188,10 +184,6 @@ func Test_very_large_count_block()
endfunc
func Test_very_large_count_block_64bit()
- if v:sizeoflong < 8
- throw 'Skipped: only works with 64 bit long ints'
- endif
-
new
call setline(1, repeat('x', 100))
exe "norm \<C-V>$y"
diff --git a/src/testdir/test_quickfix.vim b/src/testdir/test_quickfix.vim
index 0b61815..47b9b47 100644
--- a/src/testdir/test_quickfix.vim
+++ b/src/testdir/test_quickfix.vim
@@ -893,7 +893,7 @@ func Test_helpgrep()
endfunc
def Test_helpgrep_vim9_restore_cpo()
- assert_equal('aABceFs', &cpo)
+ assert_equal('aABceFsz', &cpo)
var rtp_save = &rtp
var dir = 'Xruntime/after'
@@ -905,7 +905,7 @@ def Test_helpgrep_vim9_restore_cpo()
cwindow
silent helpgrep grail
- assert_equal('aABceFs', &cpo)
+ assert_equal('aABceFsz', &cpo)
&rtp = rtp_save
cclose
helpclose
diff --git a/src/testdir/test_regexp_utf8.vim b/src/testdir/test_regexp_utf8.vim
index bc70544..51c0984 100644
--- a/src/testdir/test_regexp_utf8.vim
+++ b/src/testdir/test_regexp_utf8.vim
@@ -587,4 +587,36 @@ func Test_combining_chars_in_collection()
bw!
endfunc
+func Test_search_multibyte_match_ascii()
+ new
+ " Match single 'Å¿' and 's'
+ call setline(1, 'das abc heraus abc Å¿ich abc Å¿ind')
+ for i in range(0, 2)
+ exe "set re="..i
+ let ic_match = matchbufline('%', '\c\%u17f', 1, '$')->mapnew({idx, val -> val.text})
+ let noic_match = matchbufline('%', '\C\%u17f', 1, '$')->mapnew({idx, val -> val.text})
+ call assert_equal(['s', 's', 'Å¿','Å¿'], ic_match, "Ignorecase Regex-engine: " .. &re)
+ call assert_equal(['Å¿','Å¿'], noic_match, "No-Ignorecase Regex-engine: " .. &re)
+ endfor
+ " Match several 'Å¿Å¿' and 'ss'
+ call setline(1, 'das abc herauss abc Å¿Å¿ich abc Å¿ind')
+ for i in range(0, 2)
+ exe "set re="..i
+ let ic_match = matchbufline('%', '\c\%u17f\%u17f', 1, '$')->mapnew({idx, val -> val.text})
+ let noic_match = matchbufline('%', '\C\%u17f\%u17f', 1, '$')->mapnew({idx, val -> val.text})
+ let ic_match2 = matchbufline('%', '\c\%u17f\+', 1, '$')->mapnew({idx, val -> val.text})
+ let noic_match2 = matchbufline('%', '\C\%u17f\+', 1, '$')->mapnew({idx, val -> val.text})
+ let ic_match3 = matchbufline('%', '\c[\u17f]\+', 1, '$')->mapnew({idx, val -> val.text})
+ let noic_match3 = matchbufline('%', '\C[\u17f]\+', 1, '$')->mapnew({idx, val -> val.text})
+
+ call assert_equal(['ss', 'Å¿Å¿'], ic_match, "Ignorecase Regex-engine: " .. &re)
+ call assert_equal(['Å¿Å¿'], noic_match, "No-Ignorecase Regex-engine: " .. &re)
+ call assert_equal(['s', 'ss', 'Å¿Å¿', 'Å¿'], ic_match2, "Ignorecase Regex-engine: " .. &re)
+ call assert_equal(['Å¿Å¿','Å¿'], noic_match2, "No-Ignorecase Regex-engine: " .. &re)
+ call assert_equal(['s', 'ss', 'Å¿Å¿', 'Å¿'], ic_match3, "Ignorecase Collection Regex-engine: " .. &re)
+ call assert_equal(['Å¿Å¿','Å¿'], noic_match3, "No-Ignorecase Collection Regex-engine: " .. &re)
+ endfor
+ bw!
+endfunc
+
" vim: shiftwidth=2 sts=2 expandtab
diff --git a/src/testdir/test_search.vim b/src/testdir/test_search.vim
index 1a9f49b..708aca2 100644
--- a/src/testdir/test_search.vim
+++ b/src/testdir/test_search.vim
@@ -1747,6 +1747,37 @@ func Test_search_with_no_last_pat()
call delete('Xresult')
endfunc
+" Test for using the last substitute pattern without last search pattern.
+func Test_search_with_last_substitute_pat()
+ let lines =<< trim [SCRIPT]
+ new
+ set shortmess+=S
+ call setline(1, repeat(['foofoo'], 3))
+ %s/foo/bar/
+ call assert_equal(repeat(['barfoo'], 3), getline(1, '$'))
+
+ call cursor(1, 1)
+ call assert_equal("/foo", execute('call feedkeys("/\r", "tx")', '')->trim())
+ call assert_equal([0, 1, 4, 0], getpos('.'))
+
+ if has('rightleft')
+ set rightleft rightleftcmd=search
+ call cursor(1, 1)
+ call assert_equal("oof/", execute('call feedkeys("/\r", "tx")', '')->trim())
+ call assert_equal([0, 1, 4, 0], getpos('.'))
+ endif
+
+ call writefile(v:errors, 'Xresult')
+ qall!
+ [SCRIPT]
+ call writefile(lines, 'Xscript', 'D')
+
+ if RunVim([], [], '--clean -S Xscript')
+ call assert_equal([], readfile('Xresult'))
+ endif
+ call delete('Xresult')
+endfunc
+
" Test for using tilde (~) atom in search. This should use the last used
" substitute pattern
func Test_search_tilde_pat()
diff --git a/src/testdir/test_selectmode.vim b/src/testdir/test_selectmode.vim
index bf1b52b..63aa0b9 100644
--- a/src/testdir/test_selectmode.vim
+++ b/src/testdir/test_selectmode.vim
@@ -321,4 +321,20 @@ func Test_ins_ctrl_o_in_insert_mode_resets_selectmode()
bwipe!
endfunc
+" Test that an :lmap mapping for a printable keypad key is applied when typing
+" it in Select mode.
+func Test_selectmode_keypad_lmap()
+ new
+ lnoremap <buffer> <kPoint> ???
+ lnoremap <buffer> <kEnter> !!!
+ setlocal iminsert=1
+ call setline(1, 'abcdef')
+ call feedkeys("gH\<kPoint>\<Esc>", 'tx')
+ call assert_equal(['???'], getline(1, '$'))
+ call feedkeys("gH\<kEnter>\<Esc>", 'tx')
+ call assert_equal(['!!!'], getline(1, '$'))
+
+ bwipe!
+endfunc
+
" vim: shiftwidth=2 sts=2 expandtab
diff --git a/src/testdir/test_signs.vim b/src/testdir/test_signs.vim
index 0d76d7a..7f53d62 100644
--- a/src/testdir/test_signs.vim
+++ b/src/testdir/test_signs.vim
@@ -245,7 +245,7 @@ func Test_sign_completion()
call assert_equal('"sign define jump list place undefine unplace', @:)
call feedkeys(":sign define Sign \<C-A>\<C-B>\"\<CR>", 'tx')
- call assert_equal('"sign define Sign culhl= icon= linehl= numhl= text= texthl=', @:)
+ call assert_equal('"sign define Sign culhl= icon= linehl= numhl= priority= text= texthl=', @:)
for hl in ['culhl', 'linehl', 'numhl', 'texthl']
call feedkeys(":sign define Sign "..hl.."=Spell\<C-A>\<C-B>\"\<CR>", 'tx')
@@ -1231,6 +1231,25 @@ func Test_sign_priority()
call sign_define("sign1", attr)
call sign_define("sign2", attr)
call sign_define("sign3", attr)
+ let attr = {'text' : '=>', 'linehl' : 'Search', 'texthl' : 'Search', 'priority': 60}
+ call sign_define("sign4", attr)
+
+ " Test for :sign list
+ let a = execute('sign list')
+ call assert_equal("\nsign sign1 text==> linehl=Search texthl=Search\n" .
+ \ "sign sign2 text==> linehl=Search texthl=Search\n" .
+ \ "sign sign3 text==> linehl=Search texthl=Search\n" .
+ \ "sign sign4 text==> priority=60 linehl=Search texthl=Search", a)
+
+ " Test for sign_getdefined()
+ let s = sign_getdefined()
+ call assert_equal([
+ \ {'name': 'sign1', 'texthl': 'Search', 'linehl': 'Search', 'text': '=>'},
+ \ {'name': 'sign2', 'texthl': 'Search', 'linehl': 'Search', 'text': '=>'},
+ \ {'name': 'sign3', 'texthl': 'Search', 'linehl': 'Search', 'text': '=>'},
+ \ {'name': 'sign4', 'priority': 60, 'texthl': 'Search', 'linehl': 'Search',
+ \ 'text': '=>'}],
+ \ s)
" Place three signs with different priority in the same line
call writefile(repeat(["Sun is shining"], 30), "Xsign", 'D')
@@ -1586,6 +1605,25 @@ func Test_sign_priority()
\ " line=10 id=5 group=g1 name=sign1 priority=20\n", a)
call sign_unplace('*')
+
+ " Test for sign with default priority.
+ call sign_place(1, 'g1', 'sign4', 'Xsign', {'lnum' : 3})
+ sign place 2 line=5 name=sign4 group=g1 file=Xsign
+
+ let s = sign_getplaced('Xsign', {'group' : '*'})
+ call assert_equal([
+ \ {'id' : 1, 'name' : 'sign4', 'lnum' : 3, 'group' : 'g1',
+ \ 'priority' : 60},
+ \ {'id' : 2, 'name' : 'sign4', 'lnum' : 5, 'group' : 'g1',
+ \ 'priority' : 60}],
+ \ s[0].signs)
+
+ let a = execute('sign place group=g1')
+ call assert_equal("\n--- Signs ---\nSigns for Xsign:\n" .
+ \ " line=3 id=1 group=g1 name=sign4 priority=60\n" .
+ \ " line=5 id=2 group=g1 name=sign4 priority=60\n", a)
+
+ call sign_unplace('*')
call sign_undefine()
enew | only
endfunc
diff --git a/src/testdir/test_spell.vim b/src/testdir/test_spell.vim
index 1ddcd83..692e191 100644
--- a/src/testdir/test_spell.vim
+++ b/src/testdir/test_spell.vim
@@ -5,6 +5,7 @@ source check.vim
CheckFeature spell
source screendump.vim
+source view_util.vim
func TearDown()
set nospell
@@ -300,6 +301,20 @@ func Test_compl_with_CTRL_X_CTRL_K_using_spell()
set spell& spelllang& dictionary& ignorecase&
endfunc
+func Test_compl_with_CTRL_X_s()
+ new
+ set spell spelllang=en_us showmode
+ inoremap <buffer><F2> <Cmd>let g:msg = Screenline(&lines)<CR>
+
+ call feedkeys("STheatre\<C-X>s\<F2>\<C-Y>\<Esc>", 'tx')
+ call assert_equal(['Theater'], getline(1, '$'))
+ call assert_match('(^S^N^P)', g:msg)
+
+ bwipe!
+ set spell& spelllang& showmode&
+ unlet g:msg
+endfunc
+
func Test_spellrepall()
new
set spell
diff --git a/src/testdir/test_spellfile.vim b/src/testdir/test_spellfile.vim
index d8d954b..8abb680 100644
--- a/src/testdir/test_spellfile.vim
+++ b/src/testdir/test_spellfile.vim
@@ -845,6 +845,22 @@ func Test_spell_add_word()
%bw!
endfunc
+func Test_spell_add_long_word()
+ set spell spellfile=./Xspellfile.add spelllang=en
+
+ let word = repeat('a', 9000)
+ let v:errmsg = ''
+ " Spell checking doesn't really work for such a long word,
+ " but this should not cause an E1510 error.
+ exe 'spellgood ' .. word
+ call assert_equal('', v:errmsg)
+ call assert_equal([word], readfile('./Xspellfile.add'))
+
+ set spell& spellfile= spelllang& encoding=utf-8
+ call delete('./Xspellfile.add')
+ call delete('./Xspellfile.add.spl')
+endfunc
+
func Test_spellfile_verbose()
call writefile(['1', 'one'], 'XtestVerbose.dic', 'D')
call writefile([], 'XtestVerbose.aff', 'D')
diff --git a/src/testdir/test_substitute.vim b/src/testdir/test_substitute.vim
index afdc104..b25cd60 100644
--- a/src/testdir/test_substitute.vim
+++ b/src/testdir/test_substitute.vim
@@ -806,7 +806,7 @@ func Test_replace_keeppatterns()
a
foobar
-substitute foo asdf
+substitute foo asdf foo
one two
.
@@ -815,21 +815,26 @@ one two
/^substitute
s/foo/bar/
call assert_equal('foo', @/)
- call assert_equal('substitute bar asdf', getline('.'))
+ call assert_equal('substitute bar asdf foo', getline('.'))
/^substitute
keeppatterns s/asdf/xyz/
call assert_equal('^substitute', @/)
- call assert_equal('substitute bar xyz', getline('.'))
+ call assert_equal('substitute bar xyz foo', getline('.'))
+
+ /^substitute
+ &
+ call assert_equal('^substitute', @/)
+ call assert_equal('substitute bar xyz bar', getline('.'))
exe "normal /bar /e\<CR>"
call assert_equal(15, col('.'))
normal -
keeppatterns /xyz
call assert_equal('bar ', @/)
- call assert_equal('substitute bar xyz', getline('.'))
+ call assert_equal('substitute bar xyz bar', getline('.'))
exe "normal 0dn"
- call assert_equal('xyz', getline('.'))
+ call assert_equal('xyz bar', getline('.'))
close!
endfunc
diff --git a/src/testdir/test_tabpage.vim b/src/testdir/test_tabpage.vim
index 3624790..1a40567 100644
--- a/src/testdir/test_tabpage.vim
+++ b/src/testdir/test_tabpage.vim
@@ -965,6 +965,64 @@ func Test_tabpage_alloc_failure()
call assert_equal(1, tabpagenr('$'))
endfunc
+func Test_tabpage_tabclose()
+ " Default behaviour, move to the right.
+ call s:reconstruct_tabpage_for_test(6)
+ norm! 4gt
+ setl tcl=
+ tabclose
+ call assert_equal("n3", bufname())
+
+ " Move to the left.
+ call s:reconstruct_tabpage_for_test(6)
+ norm! 4gt
+ setl tcl=left
+ tabclose
+ call assert_equal("n1", bufname())
+
+ " Move to the last used tab page.
+ call s:reconstruct_tabpage_for_test(6)
+ norm! 5gt
+ norm! 2gt
+ setl tcl=uselast
+ tabclose
+ call assert_equal("n3", bufname())
+
+ " Same, but the last used tab page is invalid. Move to the right.
+ call s:reconstruct_tabpage_for_test(6)
+ norm! 5gt
+ norm! 3gt
+ setl tcl=uselast
+ tabclose 5
+ tabclose!
+ call assert_equal("n2", bufname())
+
+ " Same, but the last used tab page is invalid. Move to the left.
+ call s:reconstruct_tabpage_for_test(6)
+ norm! 5gt
+ norm! 3gt
+ setl tcl=uselast,left
+ tabclose 5
+ tabclose!
+ call assert_equal("n0", bufname())
+
+ " Move left when moving right is not possible.
+ call s:reconstruct_tabpage_for_test(6)
+ setl tcl=
+ norm! 6gt
+ tabclose
+ call assert_equal("n3", bufname())
+
+ " Move right when moving left is not possible.
+ call s:reconstruct_tabpage_for_test(6)
+ setl tcl=left
+ norm! 1gt
+ tabclose
+ call assert_equal("n0", bufname())
+
+ setl tcl&
+endfunc
+
" this was giving ml_get errors
func Test_tabpage_last_line()
enew
diff --git a/src/testdir/test_tagjump.vim b/src/testdir/test_tagjump.vim
index 432906e..c241937 100644
--- a/src/testdir/test_tagjump.vim
+++ b/src/testdir/test_tagjump.vim
@@ -958,8 +958,63 @@ func Test_tag_stack()
call settagstack(1, {'items' : []})
call assert_fails('pop', 'E73:')
+ " References to wiped buffer are deleted.
+ for i in range(10, 20)
+ edit Xtest
+ exe "tag var" .. i
+ endfor
+ edit Xtest
+
+ let t = gettagstack()
+ call assert_equal(11, t.length)
+ call assert_equal(12, t.curidx)
+
+ bwipe!
+
+ let t = gettagstack()
+ call assert_equal(0, t.length)
+ call assert_equal(1, t.curidx)
+
+ " References to wiped buffer are deleted with multiple tabpages.
+ let w1 = win_getid()
+ call settagstack(1, {'items' : []})
+ for i in range(10, 20) | edit Xtest | exe "tag var" .. i | endfor
+ enew
+
+ new
+ let w2 = win_getid()
+ call settagstack(1, {'items' : []})
+ for i in range(10, 20) | edit Xtest | exe "tag var" .. i | endfor
+ enew
+
+ tabnew
+ let w3 = win_getid()
+ call settagstack(1, {'items' : []})
+ for i in range(10, 20) | edit Xtest | exe "tag var" .. i | endfor
+ enew
+
+ new
+ let w4 = win_getid()
+ call settagstack(1, {'items' : []})
+ for i in range(10, 20) | edit Xtest | exe "tag var" .. i | endfor
+ enew
+
+ for w in [w1, w2, w3, w4]
+ let t = gettagstack(w)
+ call assert_equal(11, t.length)
+ call assert_equal(12, t.curidx)
+ endfor
+
+ bwipe! Xtest
+
+ for w in [w1, w2, w3, w4]
+ let t = gettagstack(w)
+ call assert_equal(0, t.length)
+ call assert_equal(1, t.curidx)
+ endfor
+
+ %bwipe!
set tags&
- %bwipe
endfunc
" Test for browsing multiple matching tags
diff --git a/src/testdir/test_taglist.vim b/src/testdir/test_taglist.vim
index 2dd2366..c5c7df2 100644
--- a/src/testdir/test_taglist.vim
+++ b/src/testdir/test_taglist.vim
@@ -100,9 +100,9 @@ func Test_tagfiles()
help
let tf = tagfiles()
- " if 'helplang includes another language, then we may find
- " 2 tagfiles (e.g.: for EN and RU)
- " we may need to adjust this, if further translated help files are included
+ " If 'helplang' includes another language, then we may find 2 tagfiles
+ " (e.g.: for EN and RU).
+ " We may need to adjust this, if further translated help files are included.
call assert_inrange(1, 2, len(tf))
call assert_equal(fnamemodify(expand('$VIMRUNTIME/doc/tags'), ':p:gs?\\?/?'),
\ fnamemodify(tf[0], ':p:gs?\\?/?'))
@@ -127,6 +127,47 @@ func Test_tagsfile_without_trailing_newline()
set tags&
endfunc
+" Check that specifying a stop directory in 'tags' works properly.
+func Test_tagfiles_stopdir()
+ let save_cwd = getcwd()
+
+ call mkdir('Xtagsdir1/Xtagsdir2/Xtagsdir3', 'pR')
+ call writefile([], 'Xtagsdir1/Xtags', 'D')
+
+ cd Xtagsdir1/
+ let &tags = './Xtags;' .. fnamemodify('..', ':p')
+ call assert_equal(1, len(tagfiles()))
+
+ cd Xtagsdir2/
+ let &tags = './Xtags;' .. fnamemodify('..', ':p')
+ call assert_equal(1, len(tagfiles()))
+
+ cd Xtagsdir3/
+ let &tags = './Xtags;' .. fnamemodify('..', ':p')
+ call assert_equal(0, len(tagfiles()))
+
+ let &tags = './Xtags;../'
+ call assert_equal(0, len(tagfiles()))
+
+ cd ..
+ call assert_equal(1, len(tagfiles()))
+
+ cd ..
+ call assert_equal(1, len(tagfiles()))
+
+ let &tags = './Xtags;..'
+ call assert_equal(1, len(tagfiles()))
+
+ cd Xtagsdir2/
+ call assert_equal(1, len(tagfiles()))
+
+ cd Xtagsdir3/
+ call assert_equal(0, len(tagfiles()))
+
+ set tags&
+ call chdir(save_cwd)
+endfunc
+
" Test for ignoring comments in a tags file
func Test_tagfile_ignore_comments()
call writefile([
diff --git a/src/testdir/test_termcodes.vim b/src/testdir/test_termcodes.vim
index 7e450d9..507753c 100644
--- a/src/testdir/test_termcodes.vim
+++ b/src/testdir/test_termcodes.vim
@@ -2256,6 +2256,17 @@ func Test_modifyOtherKeys_mapped()
iunmap '
iunmap <C-W><C-A>
+
+ " clean buffer
+ %d _
+ imap B b
+ imap BBB blimp
+ let input = repeat(GetEscCodeCSI27('B', 2), 3)
+ call feedkeys("a" .. input .. "\<Esc>", 'Lx!')
+ call assert_equal('blimp', getline(1))
+ " cleanup
+ iunmap BBB
+ iunmap B
set timeoutlen&
endfunc
diff --git a/src/testdir/test_termdebug.vim b/src/testdir/test_termdebug.vim
index a9762df..b5c12ae 100644
--- a/src/testdir/test_termdebug.vim
+++ b/src/testdir/test_termdebug.vim
@@ -63,6 +63,7 @@ func Test_termdebug_basic()
edit XTD_basic.c
Termdebug ./XTD_basic
+ call WaitForAssert({-> assert_true(get(g:, "termdebug_is_running", v:false))})
call WaitForAssert({-> assert_equal(3, winnr('$'))})
let gdb_buf = winbufnr(1)
wincmd b
@@ -123,13 +124,13 @@ func Test_termdebug_basic()
" 60 is approx spaceBuffer * 3
if winwidth(0) <= 78 + 60
Var
- call assert_equal(winnr(), winnr('$'))
- call assert_equal(winlayout(), ['col', [['leaf', 1002], ['leaf', 1001], ['leaf', 1000], ['leaf', 1003 + cn]]])
+ call assert_equal(winnr('$'), winnr())
+ call assert_equal(['col', [['leaf', 1002], ['leaf', 1001], ['leaf', 1000], ['leaf', 1003 + cn]]], winlayout())
let cn += 1
bw!
Asm
- call assert_equal(winnr(), winnr('$'))
- call assert_equal(winlayout(), ['col', [['leaf', 1002], ['leaf', 1001], ['leaf', 1000], ['leaf', 1003 + cn]]])
+ call assert_equal(winnr('$'), winnr())
+ call assert_equal(['col', [['leaf', 1002], ['leaf', 1001], ['leaf', 1000], ['leaf', 1003 + cn]]], winlayout())
let cn += 1
bw!
endif
@@ -138,16 +139,16 @@ func Test_termdebug_basic()
let winw = winwidth(0)
Var
if winwidth(0) < winw
- call assert_equal(winnr(), winnr('$') - 1)
- call assert_equal(winlayout(), ['col', [['leaf', 1002], ['leaf', 1001], ['row', [['leaf', 1003 + cn], ['leaf', 1000]]]]])
+ call assert_equal(winnr('$') - 1, winnr())
+ call assert_equal(['col', [['leaf', 1002], ['leaf', 1001], ['row', [['leaf', 1003 + cn], ['leaf', 1000]]]]], winlayout())
let cn += 1
bw!
endif
let winw = winwidth(0)
Asm
if winwidth(0) < winw
- call assert_equal(winnr(), winnr('$') - 1)
- call assert_equal(winlayout(), ['col', [['leaf', 1002], ['leaf', 1001], ['row', [['leaf', 1003 + cn], ['leaf', 1000]]]]])
+ call assert_equal(winnr('$') - 1, winnr())
+ call assert_equal(['col', [['leaf', 1002], ['leaf', 1001], ['row', [['leaf', 1003 + cn], ['leaf', 1000]]]]], winlayout())
let cn += 1
bw!
endif
@@ -160,6 +161,19 @@ func Test_termdebug_basic()
call WaitForAssert({-> assert_equal(1, winnr('$'))})
call assert_equal([], sign_getplaced('', #{group: 'TermDebug'})[0].signs)
+ for use_prompt in [v:true, v:false]
+ let g:termdebug_config = {}
+ let g:termdebug_config['use_prompt'] = use_prompt
+ TermdebugCommand ./XTD_basic arg args
+ call WaitForAssert({-> assert_true(get(g:, "termdebug_is_running", v:false))})
+ call WaitForAssert({-> assert_equal(3, winnr('$'))})
+ wincmd t
+ quit!
+ redraw!
+ call WaitForAssert({-> assert_equal(1, winnr('$'))})
+ unlet g:termdebug_config
+ endfor
+
call s:cleanup_files(bin_name)
%bw!
endfunc
@@ -174,6 +188,7 @@ func Test_termdebug_tbreak()
execute 'edit ' .. src_name
execute 'Termdebug ./' .. bin_name
+ call WaitForAssert({-> assert_true(get(g:, "termdebug_is_running", v:false))})
call WaitForAssert({-> assert_equal(3, winnr('$'))})
let gdb_buf = winbufnr(1)
wincmd b
@@ -234,6 +249,7 @@ func Test_termdebug_mapping()
call assert_true(maparg('-', 'n', 0, 1)->empty())
call assert_true(maparg('+', 'n', 0, 1)->empty())
Termdebug
+ call WaitForAssert({-> assert_true(get(g:, "termdebug_is_running", v:false))})
call WaitForAssert({-> assert_equal(3, winnr('$'))})
wincmd b
call assert_false(maparg('K', 'n', 0, 1)->empty())
@@ -256,6 +272,7 @@ func Test_termdebug_mapping()
nnoremap - :echom "-"<cr>
nnoremap + :echom "+"<cr>
Termdebug
+ call WaitForAssert({-> assert_true(get(g:, "termdebug_is_running", v:false))})
call WaitForAssert({-> assert_equal(3, winnr('$'))})
wincmd b
call assert_false(maparg('K', 'n', 0, 1)->empty())
@@ -278,76 +295,184 @@ func Test_termdebug_mapping()
call assert_equal(':echom "K"<cr>', maparg('K', 'n', 0, 1).rhs)
%bw!
+
+ " -- Test that local-buffer mappings are restored in the correct buffers --
+ " local mappings for foo
+ file foo
nnoremap <buffer> K :echom "bK"<cr>
nnoremap <buffer> - :echom "b-"<cr>
nnoremap <buffer> + :echom "b+"<cr>
+
+ " no mappings for 'bar'
+ enew
+ file bar
+
+ " Start termdebug from foo
+ buffer foo
Termdebug
+ call WaitForAssert({-> assert_true(get(g:, "termdebug_is_running", v:false))})
call WaitForAssert({-> assert_equal(3, winnr('$'))})
wincmd b
call assert_true(maparg('K', 'n', 0, 1).buffer)
call assert_true(maparg('-', 'n', 0, 1).buffer)
call assert_true(maparg('+', 'n', 0, 1).buffer)
call assert_equal(maparg('K', 'n', 0, 1).rhs, ':echom "bK"<cr>')
+
+ Source
+ buffer bar
+ call assert_false(maparg('K', 'n', 0, 1)->empty())
+ call assert_false(maparg('-', 'n', 0, 1)->empty())
+ call assert_false(maparg('+', 'n', 0, 1)->empty())
+ call assert_true(maparg('K', 'n', 0, 1).buffer->empty())
+ call assert_true(maparg('-', 'n', 0, 1).buffer->empty())
+ call assert_true(maparg('+', 'n', 0, 1).buffer->empty())
wincmd t
quit!
redraw!
call WaitForAssert({-> assert_equal(1, winnr('$'))})
+
+ " Termdebug session ended. Buffer 'bar' shall have no mappings
+ call assert_true(bufname() ==# 'bar')
+ call assert_false(maparg('K', 'n', 0, 1)->empty())
+ call assert_false(maparg('-', 'n', 0, 1)->empty())
+ call assert_false(maparg('+', 'n', 0, 1)->empty())
+ call assert_true(maparg('K', 'n', 0, 1).buffer->empty())
+ call assert_true(maparg('-', 'n', 0, 1).buffer->empty())
+ call assert_true(maparg('+', 'n', 0, 1).buffer->empty())
+
+ " Buffer 'foo' shall have the same mapping as before running the termdebug
+ " session
+ buffer foo
+ call assert_true(bufname() ==# 'foo')
call assert_true(maparg('K', 'n', 0, 1).buffer)
call assert_true(maparg('-', 'n', 0, 1).buffer)
call assert_true(maparg('+', 'n', 0, 1).buffer)
call assert_equal(':echom "bK"<cr>', maparg('K', 'n', 0, 1).rhs)
+ nunmap K
+ nunmap +
+ nunmap -
%bw!
endfunc
-func Test_termdebug_bufnames()
- " Test if user has filename/folders named gdb, Termdebug-gdb-console,
- " etc. in the current directory
+function Test_termdebug_save_restore_variables()
+ " saved mousemodel
+ let &mousemodel=''
+
+ " saved keys
+ nnoremap K :echo "hello world!"<cr>
+ let expected_map_K = maparg('K', 'n', 0 , 1)
+ nnoremap + :echo "hello plus!"<cr>
+ let expected_map_plus = maparg('+', 'n', 0 , 1)
+ let expected_map_minus = {}
+
+ " saved &columns
+ let expected_columns = &columns
+
+ " We want termdebug to overwrite 'K' map but not '+' map.
let g:termdebug_config = {}
- let g:termdebug_config['use_prompt'] = 1
- let filename = 'gdb'
- let replacement_filename = 'Termdebug-gdb-console'
+ let g:termdebug_config['map_K'] = v:true
- call writefile(['This', 'is', 'a', 'test'], filename, 'D')
- " Throw away the file once the test has done.
Termdebug
- " Once termdebug has completed the startup you should have 3 windows on screen
+ call WaitForAssert({-> assert_true(get(g:, "termdebug_is_running", v:false))})
call WaitForAssert({-> assert_equal(3, winnr('$'))})
- " A file named filename already exists in the working directory,
- " hence you must call the newly created buffer differently
- call WaitForAssert({-> assert_false(bufexists(filename))})
- call WaitForAssert({-> assert_true(bufexists(replacement_filename))})
+ call WaitForAssert({-> assert_match(&mousemodel, 'popup_setpos')})
+ wincmd t
quit!
call WaitForAssert({-> assert_equal(1, winnr('$'))})
- " Check if error message is in :message
- let g:termdebug_config['disasm_window'] = 1
- let filename = 'Termdebug-asm-listing'
- call writefile(['This', 'is', 'a', 'test'], filename, 'D')
- " Check only the head of the error message
- let error_message = "You have a file/folder named '" .. filename .. "'"
- Termdebug
- " Once termdebug has completed the startup you should have 4 windows on screen
- call WaitForAssert({-> assert_equal(4, winnr('$'))})
- call WaitForAssert({-> assert_notequal(-1, stridx(execute('messages'), error_message))})
- quit!
- wincmd b
- wincmd q
- call WaitForAssert({-> assert_equal(1, winnr('$'))})
+ call assert_true(empty(&mousemodel))
+ call assert_true(empty(expected_map_minus))
+ call assert_equal(expected_map_K.rhs, maparg('K', 'n', 0, 1).rhs)
+ call assert_equal(expected_map_plus.rhs, maparg('+', 'n', 0, 1).rhs)
+
+ call assert_equal(expected_columns, &columns)
+
+ nunmap K
+ nunmap +
unlet g:termdebug_config
-endfunc
+endfunction
-function Test_termdebug_save_restore_variables()
- let &mousemodel=''
+function Test_termdebug_sanity_check()
+ " Test if user has filename/folders with wrong names
+ let g:termdebug_config = {}
+ let s:dict = {'disasm_window': 'Termdebug-asm-listing', 'use_prompt': 'gdb', 'variables_window': 'Termdebug-variables-listing'}
+
+ for key in keys(s:dict)
+ let s:filename = s:dict[key]
+ let g:termdebug_config[key] = v:true
+ let s:error_message = "You have a file/folder named '" .. s:filename .. "'"
+
+ " Write dummy file with bad name
+ call writefile(['This', 'is', 'a', 'test'], s:filename, 'D')
+ Termdebug
+ call WaitForAssert({-> assert_true(execute('messages') =~ s:error_message)})
+ call WaitForAssert({-> assert_equal(1, winnr('$'))})
+
+ call delete(s:filename)
+ call remove(g:termdebug_config, key)
+ endfor
+
+ unlet g:termdebug_config
+endfunction
+
+function Test_termdebug_double_termdebug_instances()
+ let s:error_message = 'Terminal debugger already running, cannot run two'
Termdebug
+ call WaitForAssert({-> assert_true(get(g:, "termdebug_is_running", v:false))})
call WaitForAssert({-> assert_equal(3, winnr('$'))})
- call WaitForAssert({-> assert_match(&mousemodel, 'popup_setpos')})
+ Termdebug
+ call WaitForAssert({-> assert_true(execute('messages') =~ s:error_message)})
wincmd t
quit!
call WaitForAssert({-> assert_equal(1, winnr('$'))})
- call WaitForAssert({-> assert_true(empty(&mousemodel))})
+ :%bw!
endfunction
+function Test_termdebug_config_types()
+ " TODO Remove the deprecated features after 1 Jan 2025.
+ let g:termdebug_config = {}
+ let s:error_message = 'Deprecation Warning:'
+ call assert_true(maparg('K', 'n', 0, 1)->empty())
+
+ for key in ['disasm_window', 'variables_window', 'map_K']
+ for val in [0, 1, v:true, v:false]
+ let g:termdebug_config[key] = val
+ Termdebug
+
+ " Type check: warning is displayed
+ if typename(val) == 'number'
+ call WaitForAssert({-> assert_true(execute('messages') =~ s:error_message)})
+ endif
+
+ " Test on g:termdebug_config keys
+ if val && key != 'map_K'
+ call WaitForAssert({-> assert_equal(4, winnr('$'))})
+ call remove(g:termdebug_config, key)
+ else
+ call WaitForAssert({-> assert_equal(3, winnr('$'))})
+ endif
+
+ " Test on mapping
+ if key == 'map_K'
+ if val
+ call assert_equal(':Evaluate<CR>', maparg('K', 'n', 0, 1).rhs)
+ else
+ call assert_true(maparg('K', 'n', 0, 1)->empty())
+ endif
+ endif
+
+ " Shutoff termdebug
+ wincmd t
+ quit!
+ call WaitForAssert({-> assert_equal(1, winnr('$'))})
+ :%bw!
+
+ endfor
+ endfor
+
+ unlet g:termdebug_config
+endfunction
" vim: shiftwidth=2 sts=2 expandtab
diff --git a/src/testdir/test_textobjects.vim b/src/testdir/test_textobjects.vim
index d5e772d..2622b06 100644
--- a/src/testdir/test_textobjects.vim
+++ b/src/testdir/test_textobjects.vim
@@ -201,6 +201,18 @@ func Test_string_html_objects()
normal! 2k0vaty
call assert_equal("<div><div\nattr=\"attr\"\n></div></div>", @", e)
+ " tag, that includes a > in some attribute
+ let t = "<div attr=\"attr >> foo >> bar \">Hello</div>"
+ $put =t
+ normal! fHyit
+ call assert_equal("Hello", @", e)
+
+ " tag, that includes a > in some attribute
+ let t = "<div attr='attr >> foo >> bar '>Hello 123</div>"
+ $put =t
+ normal! fHyit
+ call assert_equal("Hello 123", @", e)
+
set quoteescape&
" this was going beyond the end of the line
diff --git a/src/testdir/test_textprop.vim b/src/testdir/test_textprop.vim
index 2bf2834..57277f7 100644
--- a/src/testdir/test_textprop.vim
+++ b/src/testdir/test_textprop.vim
@@ -2901,6 +2901,10 @@ func Test_prop_inserts_text_before_double_width_wrap()
call writefile(lines, 'XscriptPropsBeforeDoubleWidthWrap', 'D')
let buf = RunVimInTerminal('-S XscriptPropsBeforeDoubleWidthWrap', #{rows: 3, cols: 50})
call VerifyScreenDump(buf, 'Test_prop_inserts_text_before_double_width_wrap_1', {})
+ call term_sendkeys(buf, 'g0')
+ call VerifyScreenDump(buf, 'Test_prop_inserts_text_before_double_width_wrap_2', {})
+ call term_sendkeys(buf, ":set showbreak=+++\<CR>")
+ call VerifyScreenDump(buf, 'Test_prop_inserts_text_before_double_width_wrap_3', {})
call StopVimInTerminal(buf)
endfunc
diff --git a/src/testdir/test_tohtml.vim b/src/testdir/test_tohtml.vim
new file mode 100644
index 0000000..a1c8572
--- /dev/null
+++ b/src/testdir/test_tohtml.vim
@@ -0,0 +1,72 @@
+" Tests for Vim :TOhtml
+
+source check.vim
+
+func s:setup_basic(src_name)
+ let lines =<< trim END
+ #include <stdio.h>
+ #include <stdlib.h>
+
+ int isprime(int n)
+ {
+ if (n <= 1)
+ return 0;
+
+ for (int i = 2; i <= n / 2; i++)
+ if (n % i == 0)
+ return 0;
+
+ return 1;
+ }
+
+ int main(int argc, char *argv[])
+ {
+ int n = 7;
+
+ printf("%d is %s prime\n", n, isprime(n) ? "a" : "not a");
+
+ return 0;
+ }
+ END
+ call writefile(lines, a:src_name)
+ exe 'edit ' . a:src_name
+ TOhtml
+ write
+endfunc
+
+func s:cleanup_basic(src_name)
+ call delete(a:src_name)
+ call delete(a:src_name . ".html")
+endfunc
+
+source $VIMRUNTIME/plugin/tohtml.vim
+
+func Test_tohtml_basic()
+ let src_name = "Test_tohtml_basic.c"
+ call s:setup_basic(src_name)
+ let expected = readfile("samples/" . src_name . ".html")
+ let actual = readfile(src_name . ".html")
+ call assert_equal(expected[0:3], actual[0:3])
+ " Ignore the title
+ call assert_equal(expected[5:11], actual[5:11])
+ " Ignore pre and body css
+ call assert_equal(expected[14:], actual[14:])
+ call s:cleanup_basic(src_name)
+endfunc
+
+func Test_tohtml_basic_no_css()
+ let g:html_use_css = 0
+ let src_name = "Test_tohtml_basic_no_css.c"
+ call s:setup_basic(src_name)
+ let expected = readfile("samples/" . src_name . ".html")
+ let actual = readfile(src_name . ".html")
+ call assert_equal(expected[0:3], actual[0:3])
+ " Ignore the title
+ call assert_equal(expected[5:10], actual[5:10])
+ " Ignore body's inline css
+ call assert_equal(expected[12:], actual[12:])
+ call s:cleanup_basic(src_name)
+ unlet g:html_use_css
+endfunc
+
+" vim: shiftwidth=2 sts=2 expandtab
diff --git a/src/testdir/test_usercommands.vim b/src/testdir/test_usercommands.vim
index e161ee6..fe08b95 100644
--- a/src/testdir/test_usercommands.vim
+++ b/src/testdir/test_usercommands.vim
@@ -133,6 +133,10 @@ function Test_cmdmods()
\ 'silent verbose aboveleft belowright botright tab topleft vertical',
\ g:mods)
+ kee keep keepm keepma keepmar keepmarks keepa keepalt keepj keepjumps
+ \ keepp keeppatterns MyCmd
+ call assert_equal('keepalt keepjumps keepmarks keeppatterns', g:mods)
+
let g:mods = ''
command! -nargs=* MyQCmd let g:mods .= '<q-mods> '
diff --git a/src/testdir/test_vim9_builtin.vim b/src/testdir/test_vim9_builtin.vim
index 6b1a50d..7ed9123 100644
--- a/src/testdir/test_vim9_builtin.vim
+++ b/src/testdir/test_vim9_builtin.vim
@@ -497,6 +497,56 @@ def Test_call_call()
v9.CheckSourceDefAndScriptFailure(['call("reverse", [2], [1])'], ['E1013: Argument 3: type mismatch, expected dict<any> but got list<number>', 'E1206: Dictionary required for argument 3'])
enddef
+def Test_call_imports()
+ # Use call with an imported function
+ var lines =<< trim END
+ vim9script
+
+ export const foo = 'foo'
+
+ export def Imported()
+ enddef
+
+ var count: number
+ export def ImportedListArg(l: list<number>)
+ count += 1
+ l[0] += count
+ enddef
+ END
+ writefile(lines, 'Test_call_imports_importme', 'D')
+ lines =<< trim END
+ vim9script
+ import './Test_call_imports_importme' as i_imp
+
+ var l = [12]
+ call('i_imp.ImportedListArg', [l])
+ assert_equal(13, l[0])
+ const ImportedListArg = i_imp.ImportedListArg
+ call('ImportedListArg', [l])
+ assert_equal(15, l[0])
+ const Imported = i_imp.Imported
+ call("Imported", [])
+
+ assert_equal('foo', i_imp.foo)
+ const foo = i_imp.foo
+ assert_equal('foo', foo)
+ END
+ v9.CheckSourceScriptSuccess(lines)
+
+ # A few error cases
+ lines =<< trim END
+ vim9script
+ import './Test_call_imports_importme' as i_imp
+ const Imported = i_imp.Imported
+ const foo = i_imp.foo
+
+ assert_fails('call("i_imp.foo", [])', 'E117:') # foo is not a function
+ assert_fails('call("foo", [])', 'E117:') # foo is not a function
+ assert_fails('call("i_xxx.foo", [])', 'E117:') # i_xxx not imported file
+ END
+ v9.CheckSourceScriptSuccess(lines)
+enddef
+
def Test_ch_canread()
if !has('channel')
CheckFeature channel
@@ -1969,6 +2019,17 @@ def Test_getreginfo()
getreginfo('').regcontents->assert_equal(['D1E2F3'])
enddef
+def Test_getregionpos()
+ var lines =<< trim END
+ cursor(1, 1)
+ var pos = getregionpos(getpos('.'), getpos('$'))
+ for p in pos
+ assert_equal(bufnr('%'), p[0][0])
+ endfor
+ END
+ v9.CheckSourceDefSuccess(lines)
+enddef
+
def Test_getregtype()
var lines = ['aaa', 'bbb', 'ccc']
setreg('a', lines)
@@ -3152,6 +3213,11 @@ def Test_popup_settext()
v9.CheckSourceDefAndScriptFailure(['popup_settext(1, 2)'], ['E1013: Argument 2: type mismatch, expected string but got number', 'E1222: String or List required for argument 2'])
enddef
+def Test_popup_setbuf()
+ v9.CheckSourceDefAndScriptFailure(['popup_setbuf([], "abc")'], ['E1013: Argument 1: type mismatch, expected number but got list<any>', 'E1210: Number required for argument 1'])
+ v9.CheckSourceDefAndScriptFailure(['popup_setbuf(1, [])'], ['E1013: Argument 2: type mismatch, expected string but got list<any>', 'E1220: String or Number required for argument 2'])
+enddef
+
def Test_popup_show()
v9.CheckSourceDefAndScriptFailure(['popup_show("a")'], ['E1013: Argument 1: type mismatch, expected number but got string', 'E1210: Number required for argument 1'])
v9.CheckSourceDefAndScriptFailure(['popup_show(true)'], ['E1013: Argument 1: type mismatch, expected number but got bool', 'E1210: Number required for argument 1'])
diff --git a/src/testdir/test_vim9_class.vim b/src/testdir/test_vim9_class.vim
index e92fcc5..8791a52 100644
--- a/src/testdir/test_vim9_class.vim
+++ b/src/testdir/test_vim9_class.vim
@@ -661,6 +661,44 @@ def Test_object_not_set()
Func()
END
v9.CheckSourceFailure(lines, 'E1363: Incomplete type', 1)
+
+ # Reference a object variable through a null class object which is stored in a
+ # variable of type "any".
+ lines =<< trim END
+ vim9script
+
+ def Z()
+ var o: any = null_object
+ o.v = 4
+ enddef
+ Z()
+ END
+ v9.CheckSourceFailure(lines, 'E1360: Using a null object', 2)
+
+ # Do "echom" of a null object variable.
+ lines =<< trim END
+ vim9script
+
+ def X()
+ var x = null_object
+ echom x
+ enddef
+ X()
+ END
+ v9.CheckSourceFailure(lines, 'E1324: Using an Object as a String', 2)
+
+ # Use a null object variable that vim wants to force to number.
+ lines =<< trim END
+ vim9script
+
+ def X()
+ var o = null_object
+ var l = [ 1, o]
+ sort(l, 'N')
+ enddef
+ X()
+ END
+ v9.CheckSourceFailure(lines, 'E1324: Using an Object as a String', 3)
enddef
" Null object assignment and comparison
@@ -2246,6 +2284,47 @@ def Test_class_object_to_string()
assert_equal("object of TextPosition {lnum: 1, col: 22}", string(pos))
END
v9.CheckSourceSuccess(lines)
+
+ # check string() with object nesting
+ lines =<< trim END
+ vim9script
+ class C
+ var nest1: C
+ var nest2: C
+ def Init(n1: C, n2: C)
+ this.nest1 = n1
+ this.nest2 = n2
+ enddef
+ endclass
+
+ var o1 = C.new()
+ var o2 = C.new()
+ o1.Init(o1, o2)
+ o2.Init(o2, o1)
+
+ # The following previously put's vim into an infinite loop.
+
+ var expect = "object of C {nest1: object of C {...}, nest2: object of C {nest1: object of C {...}, nest2: object of C {...}}}"
+ assert_equal(expect, string(o1))
+ END
+ v9.CheckSourceSuccess(lines)
+
+ lines =<< trim END
+ vim9script
+
+ class B
+ endclass
+
+ class C
+ var b: B
+ var c: C
+ endclass
+
+ var o1 = C.new(B.new(), C.new(B.new()))
+ var expect = "object of C {b: object of B {}, c: object of C {b: object of B {}, c: object of [unknown]}}"
+ assert_equal(expect, string(o1))
+ END
+ v9.CheckSourceSuccess(lines)
enddef
def Test_interface_basics()
@@ -3173,6 +3252,141 @@ def Test_using_base_class()
v9.CheckSourceSuccess(lines)
enddef
+def Test_super_dispatch()
+ # See #15448 and #15463
+ var lines =<< trim END
+ vim9script
+
+ class A
+ def String(): string
+ return 'A'
+ enddef
+ endclass
+
+ class B extends A
+ def String(): string
+ return super.String()
+ enddef
+ endclass
+
+ class C extends B
+ endclass
+
+ assert_equal('A', C.new().String())
+ END
+ v9.CheckSourceSuccess(lines)
+
+ lines =<< trim END
+ vim9script
+
+ class A
+ def F(): string
+ return 'AA'
+ enddef
+ endclass
+
+ class B extends A
+ def F(): string
+ return 'BB'
+ enddef
+ def S(): string
+ return super.F()
+ enddef
+ def S0(): string
+ return this.S()
+ enddef
+ endclass
+
+ class C extends B
+ def F(): string
+ return 'CC'
+ enddef
+ def ToB(): string
+ return super.F()
+ enddef
+ endclass
+
+ assert_equal('AA', B.new().S())
+ assert_equal('AA', C.new().S())
+ assert_equal('AA', B.new().S0())
+ assert_equal('AA', C.new().S0())
+
+ assert_equal('BB', C.new().ToB())
+
+ assert_equal('CC', C.new().F())
+ assert_equal('BB', B.new().F())
+ assert_equal('AA', A.new().F())
+ END
+ v9.CheckSourceSuccess(lines)
+
+ lines =<< trim END
+ vim9script
+
+ var call_chain: list<string>
+
+ abstract class A
+ abstract def _G(): string
+
+ def F(): string
+ call_chain->add('A.F()')
+ return this._G()
+ enddef
+ def _H(): string
+ call_chain->add('A._H()')
+ return this.F()
+ enddef
+ endclass
+
+ class B extends A
+ def _G(): string
+ call_chain->add('B.G()')
+ return 'BBB'
+ enddef
+ def SF(): string
+ call_chain->add('B.SF()')
+ return super._H()
+ enddef
+ endclass
+
+ class C extends B
+ endclass
+
+ class D extends C
+ def SF(): string
+ call_chain->add('D.SF()')
+ return super.SF()
+ enddef
+ endclass
+
+ class E extends D
+ def SF(): string
+ call_chain->add('E.SF()')
+ return super.SF()
+ enddef
+ endclass
+
+ class F extends E
+ def _G(): string
+ call_chain->add('F._G()')
+ return 'FFF'
+ enddef
+ endclass
+
+ # E.new() -> A.F() -> B._G()
+ call_chain = []
+ var o1 = E.new()
+ assert_equal('BBB', o1.F())
+ assert_equal(['A.F()', 'B.G()'], call_chain)
+
+ # F.new() -> E.SF() -> D.SF() -> B.SF() -> A._H() -> A.F() -> F._G()
+ call_chain = []
+ var o2 = F.new()
+ assert_equal('FFF', o2.SF())
+ assert_equal(['E.SF()', 'D.SF()', 'B.SF()', 'A._H()', 'A.F()', 'F._G()'], call_chain)
+ END
+ v9.CheckSourceSuccess(lines)
+enddef
+
def Test_class_import()
var lines =<< trim END
vim9script
@@ -7162,6 +7376,47 @@ def Test_null_object_method_call()
T()
END
v9.CheckSourceFailure(lines, 'E1360: Using a null object', 2)
+
+ # Calling an object method defined in a class that is extended. This differs
+ # from the previous by invoking ISN_METHODCALL instead of ISN_DCALL.
+ lines =<< trim END
+ vim9script
+
+ class C0
+ def F()
+ enddef
+ endclass
+
+ class C extends C0
+ endclass
+
+ def X()
+ var o: C0 = null_object
+ o.F()
+ enddef
+ X()
+ END
+ v9.CheckSourceFailure(lines, 'E1360: Using a null object', 2)
+
+ # Getting a function ref an object method.
+ lines =<< trim END
+ vim9script
+
+ class C0
+ def F()
+ enddef
+ endclass
+
+ class C extends C0
+ endclass
+
+ def X()
+ var o: C0 = null_object
+ var XXX = o.F
+ enddef
+ X()
+ END
+ v9.CheckSourceFailure(lines, 'E1360: Using a null object', 2)
enddef
" Test for using a dict as an object member
@@ -10425,6 +10680,20 @@ func Test_object_string()
call v9.CheckSourceSuccess(lines)
endfunc
+" Test for using the string() builtin method with an object's method
+def Test_method_string()
+ var lines =<< trim END
+ vim9script
+ class A
+ def F()
+ enddef
+ endclass
+ assert_match('function(''<SNR>\d\+_A\.F'')', string(A.new().F))
+ END
+ v9.CheckScriptSuccess(lines)
+enddef
+
+
" Test for using a class in the class definition
def Test_Ref_Class_Within_Same_Class()
var lines =<< trim END
@@ -10486,6 +10755,156 @@ def Test_Ref_Class_Within_Same_Class()
v9.CheckScriptFailure(lines, 'E1347: Not a valid interface: A', 3)
enddef
+" Test for comparing a class referencing itself
+def Test_Object_Compare_With_Recursive_Class_Ref()
+ var lines =<< trim END
+ vim9script
+
+ class C
+ public var nest: C
+ endclass
+
+ var o1 = C.new()
+ o1.nest = o1
+
+ var result = o1 == o1
+ assert_equal(true, result)
+ END
+ v9.CheckScriptSuccess(lines)
+
+ lines =<< trim END
+ vim9script
+
+ class C
+ public var nest: C
+ endclass
+ var o1 = C.new()
+ var o2 = C.new(C.new())
+
+ var result = o1 == o2
+ assert_equal(false, result)
+ END
+ v9.CheckScriptSuccess(lines)
+
+ lines =<< trim END
+ vim9script
+ class C
+ var nest1: C
+ var nest2: C
+ def Init(n1: C, n2: C)
+ this.nest1 = n1
+ this.nest2 = n2
+ enddef
+ endclass
+
+ var o1 = C.new()
+ var o2 = C.new()
+ o1.Init(o1, o2)
+ o2.Init(o2, o1)
+
+ var result = o1 == o2
+ assert_equal(true, result)
+ END
+ v9.CheckScriptSuccess(lines)
+enddef
+
+" Test for comparing a class with nesting objects
+def Test_Object_Compare_With_Nesting_Objects()
+ # On a compare, after vim equal recurses 1000 times, not finding an unequal,
+ # return the compare is equal.
+ # Test that limit
+
+ var lines =<< trim END
+ vim9script
+ class C
+ public var n: number
+ public var nest: C
+
+ # Create a "C" that chains/nests to indicated depth.
+ # return {head: firstC, tail: lastC}
+ static def CreateNested(depth: number): dict<C>
+ var first = C.new(1, null_object)
+ var last = first
+ for i in range(2, depth)
+ last.nest = C.new(i, null_object)
+ last = last.nest
+ endfor
+ return {head: first, tail: last}
+ enddef
+
+ # Return pointer to nth item in chain.
+ def GetLink(depth: number): C
+ var count = 1
+ var p: C = this
+ while count < depth
+ p = p.nest
+ if p == null
+ throw "too deep"
+ endif
+ count += 1
+ endwhile
+ return p
+ enddef
+
+ # Return the length of the chain
+ def len(): number
+ var count = 1
+ var p: C = this
+ while p.nest != null
+ p = p.nest
+ count += 1
+ endwhile
+ return count
+ enddef
+ endclass
+
+ var chain = C.CreateNested(3)
+ var s = "object of C {n: 1, nest: object of C {n: 2, nest: object of C {n: 3, nest: object of [unknown]}}}"
+ assert_equal(s, string(chain.head))
+ assert_equal(3, chain.head->len())
+
+ var chain1 = C.CreateNested(100)
+ var chain2 = C.CreateNested(100)
+ assert_true(chain1.head == chain2.head)
+
+ # modify the tail of chain2, compare not equal
+ chain2.tail.n = 123456
+ assert_true(chain1.head != chain2.head)
+
+ # a tail of a different length compares not equal
+ chain2 = C.CreateNested(101)
+ assert_true(chain1.head != chain2.head)
+
+ chain1 = C.CreateNested(1000)
+ chain2 = C.CreateNested(1000)
+ assert_true(chain1.head == chain2.head)
+
+ # modify the tail of chain2, compare not equal
+ chain2.tail.n = 123456
+ assert_true(chain1.head != chain2.head)
+
+ # try a chain longer that the limit
+ chain1 = C.CreateNested(1001)
+ chain2 = C.CreateNested(1001)
+ assert_true(chain1.head == chain2.head)
+
+ # modify the tail, but still equal
+ chain2.tail.n = 123456
+ assert_true(chain1.head == chain2.head)
+
+ # remove 2 items from front, shorten the chain by two.
+ chain1.head = chain1.head.GetLink(3)
+ chain2.head = chain2.head.GetLink(3)
+ assert_equal(3, chain1.head.n)
+ assert_equal(3, chain2.head.n)
+ assert_equal(999, chain1.head->len())
+ assert_equal(999, chain2.head->len())
+ # Now less than the limit, compare not equal
+ assert_true(chain1.head != chain2.head)
+ END
+ v9.CheckScriptSuccess(lines)
+enddef
+
" Test for using a compound operator from a lambda function in an object method
def Test_compound_op_in_objmethod_lambda()
# Test using the "+=" operator
@@ -10744,4 +11163,54 @@ def Test_class_object_index()
v9.CheckScriptFailure(lines, 'E689: Index not allowed after a object: a[10] = 1', 5)
enddef
+def Test_class_member_init_typecheck()
+ # Ensure the class member is assigned its declared type.
+ var lines =<< trim END
+ vim9script
+ class S
+ static var l: list<string> = []
+ endclass
+ S.l->add(123)
+ END
+ v9.CheckScriptFailure(lines, 'E1012: Type mismatch; expected string but got number', 5)
+
+ # Ensure the initializer value and the declared type match.
+ lines =<< trim END
+ vim9script
+ class S
+ var l: list<string> = [1, 2, 3]
+ endclass
+ var o = S.new()
+ END
+ v9.CheckScriptFailure(lines, 'E1382: Variable "l": type mismatch, expected list<string> but got list<number>')
+
+ # Ensure the class member is assigned its declared type.
+ lines =<< trim END
+ vim9script
+ class S
+ var l: list<string> = []
+ endclass
+ var o = S.new()
+ o.l->add(123)
+ END
+ v9.CheckScriptFailure(lines, 'E1012: Type mismatch; expected string but got number', 6)
+enddef
+
+def Test_class_cast()
+ var lines =<< trim END
+ vim9script
+ class A
+ endclass
+ class B extends A
+ var mylen: number
+ endclass
+ def F(o: A): number
+ return (<B>o).mylen
+ enddef
+
+ defcompile F
+ END
+ v9.CheckScriptSuccess(lines)
+enddef
+
" vim: ts=8 sw=2 sts=2 expandtab tw=80 fdm=marker
diff --git a/src/testdir/test_vim9_cmd.vim b/src/testdir/test_vim9_cmd.vim
index a9e10e7..51ae7e6 100644
--- a/src/testdir/test_vim9_cmd.vim
+++ b/src/testdir/test_vim9_cmd.vim
@@ -2036,6 +2036,14 @@ def Test_no_space_after_command()
v9.CheckDefExecAndScriptFailure(lines, 'E486:', 1)
enddef
+def Test_lambda_crash()
+ # This used to crash Vim
+ var lines =<< trim END
+ vim9 () => super => {
+ END
+ v9.CheckScriptFailureList(lines, ["E1356:", "E1405:"])
+enddef
+
" Test for the 'previewpopup' option
def Test_previewpopup()
set previewpopup=height:10,width:60
@@ -2044,6 +2052,7 @@ def Test_previewpopup()
assert_notequal(id, 0)
assert_match('Xppfile', popup_getoptions(id).title)
popup_clear()
+ bw Xppfile
set previewpopup&
enddef
diff --git a/src/testdir/test_vim9_disassemble.vim b/src/testdir/test_vim9_disassemble.vim
index c74cce4..7746b23 100644
--- a/src/testdir/test_vim9_disassemble.vim
+++ b/src/testdir/test_vim9_disassemble.vim
@@ -1761,6 +1761,74 @@ def Test_disassemble_typecast()
instr)
enddef
+def Test_disassemble_object_cast()
+ # Downcasting.
+ var lines =<< trim END
+ vim9script
+ class A
+ endclass
+ class B extends A
+ var mylen: number
+ endclass
+ def F(o: A): number
+ return (<B>o).mylen
+ enddef
+
+ g:instr = execute('disassemble F')
+ END
+ v9.CheckScriptSuccess(lines)
+ assert_match('\<SNR>\d*_F\_s*' ..
+ 'return (<B>o).mylen\_s*' ..
+ '0 LOAD arg\[-1\]\_s*' ..
+ '1 CHECKTYPE object<B> stack\[-1\]\_s*' ..
+ '2 OBJ_MEMBER 0\_s*' ..
+ '3 RETURN\_s*',
+ g:instr)
+
+ # Upcasting.
+ lines =<< trim END
+ vim9script
+ class A
+ var mylen: number
+ endclass
+ class B extends A
+ endclass
+ def F(o: B): number
+ return (<A>o).mylen
+ enddef
+
+ g:instr = execute('disassemble F')
+ END
+ v9.CheckScriptSuccess(lines)
+ assert_match('\<SNR>\d*_F\_s*' ..
+ 'return (<A>o).mylen\_s*' ..
+ '0 LOAD arg\[-1\]\_s*' ..
+ '1 OBJ_MEMBER 0\_s*' ..
+ '2 RETURN\_s*',
+ g:instr)
+
+ # Casting, type is not statically known.
+ lines =<< trim END
+ vim9script
+ class A
+ endclass
+ class B extends A
+ endclass
+ def F(o: any): any
+ return <A>o
+ enddef
+
+ g:instr = execute('disassemble F')
+ END
+ v9.CheckScriptSuccess(lines)
+ assert_match('\<SNR>\d*_F\_s*' ..
+ 'return <A>o\_s*' ..
+ '0 LOAD arg\[-1\]\_s*' ..
+ '1 CHECKTYPE object<A> stack\[-1\]\_s*' ..
+ '2 RETURN\_s*',
+ g:instr)
+enddef
+
def s:Computing()
var nr = 3
var nrres = nr + 7
@@ -3496,4 +3564,26 @@ def Test_disassemble_compound_op_in_closure()
unlet g:instr
enddef
+def Test_disassemble_member_initializer()
+ var lines =<< trim END
+ vim9script
+ class A
+ var l: list<string> = []
+ var d: dict<string> = {}
+ endclass
+ g:instr = execute('disassemble A.new')
+ END
+ v9.CheckScriptSuccess(lines)
+ # Ensure SETTYPE is emitted and that matches the declared type.
+ assert_match('new\_s*' ..
+ '0 NEW A size \d\+\_s*' ..
+ '1 NEWLIST size 0\_s*' ..
+ '2 SETTYPE list<string>\_s*' ..
+ '3 STORE_THIS 0\_s*' ..
+ '4 NEWDICT size 0\_s*' ..
+ '5 SETTYPE dict<string>\_s*' ..
+ '6 STORE_THIS 1', g:instr)
+ unlet g:instr
+enddef
+
" vim: ts=8 sw=2 sts=2 expandtab tw=80 fdm=marker
diff --git a/src/testdir/test_vim9_func.vim b/src/testdir/test_vim9_func.vim
index d07bbfb..030ff83 100644
--- a/src/testdir/test_vim9_func.vim
+++ b/src/testdir/test_vim9_func.vim
@@ -164,6 +164,16 @@ def Test_wrong_function_name()
END
v9.CheckScriptFailure(lines, 'E1182:')
delfunc g:Define
+
+ lines =<< trim END
+ vim9script
+ var F1_ref: func
+ def Start()
+ F1_ref()
+ enddef
+ Start()
+ END
+ v9.CheckScriptFailure(lines, 'E117:')
enddef
" Check that in a legacy script a :def accesses the correct script variables.
diff --git a/src/testdir/test_vim9_script.vim b/src/testdir/test_vim9_script.vim
index 0b17150..bcb590d 100644
--- a/src/testdir/test_vim9_script.vim
+++ b/src/testdir/test_vim9_script.vim
@@ -4007,7 +4007,7 @@ def Test_restoring_cpo()
edit XanotherScript
so %
assert_equal('aABceFsMny>', &cpo)
- assert_equal('aABceFs', g:cpoval)
+ assert_equal('aABceFsz', g:cpoval)
:1del
setline(1, 'let g:cpoval = &cpo')
w
@@ -4048,10 +4048,10 @@ def Test_restoring_cpo()
exe "silent !" .. cmd
assert_equal([
- 'before: aABceFs',
- 'after: aABceFsM',
- 'later: aABceFsM',
- 'vim9: aABceFs'], readfile('Xrporesult'))
+ 'before: aABceFsz',
+ 'after: aABceFszM',
+ 'later: aABceFszM',
+ 'vim9: aABceFsz'], readfile('Xrporesult'))
$HOME = save_HOME
delete('Xrporesult')
@@ -5085,15 +5085,19 @@ def Test_null_values()
var nullValues = [
[null, 1, 'null', 7, 'special'],
[null_blob, 1, '0z', 10, 'blob'],
- [null_channel, 1, 'channel fail', 9, 'channel'],
[null_dict, 1, '{}', 4, 'dict<any>'],
[null_function, 1, "function('')", 2, 'func(...): unknown'],
- [null_job, 1, 'no process', 8, 'job'],
[null_list, 1, '[]', 3, 'list<any>'],
[null_object, 1, 'object of [unknown]', 13, 'object<Unknown>'],
[null_partial, 1, "function('')", 2, 'func(...): unknown'],
[null_string, 1, "''", 1, 'string']
]
+ if has('channel')
+ nullValues->add([null_channel, 1, 'channel fail', 9, 'channel'])
+ endif
+ if has('job')
+ nullValues->add([null_job, 1, 'no process', 8, 'job'])
+ endif
for [Val, emptyExp, stringExp, typeExp, typenameExp] in nullValues
assert_equal(emptyExp, empty(Val))
diff --git a/src/testdir/test_vimscript.vim b/src/testdir/test_vimscript.vim
index 8976779..21f894e 100644
--- a/src/testdir/test_vimscript.vim
+++ b/src/testdir/test_vimscript.vim
@@ -7536,6 +7536,31 @@ func Test_deeply_nested_source()
call system(cmd)
endfunc
+func Test_exception_silent()
+ XpathINIT
+ let lines =<< trim END
+ func Throw()
+ Xpath 'a'
+ throw "Uncaught"
+ " This line is not executed.
+ Xpath 'b'
+ endfunc
+ " The exception is suppressed due to the presence of silent!.
+ silent! call Throw()
+ try
+ call DoesNotExist()
+ catch /E117:/
+ Xpath 'c'
+ endtry
+ Xpath 'd'
+ END
+ let verify =<< trim END
+ call assert_equal('acd', g:Xpath)
+ END
+
+ call RunInNewVim(lines, verify)
+endfunc
+
"-------------------------------------------------------------------------------
" Modelines {{{1
" vim: ts=8 sw=2 sts=2 expandtab tw=80 fdm=marker
diff --git a/src/testdir/test_winfixbuf.vim b/src/testdir/test_winfixbuf.vim
index f800338..3cec4ed 100644
--- a/src/testdir/test_winfixbuf.vim
+++ b/src/testdir/test_winfixbuf.vim
@@ -2934,6 +2934,7 @@ func Test_tfirst()
\ "Xtags", 'D')
call writefile(["one", "two", "three"], "Xfile", 'D')
call writefile(["one"], "Xother", 'D')
+ tag one
edit Xother
set winfixbuf
diff --git a/src/testdir/test_xxd.vim b/src/testdir/test_xxd.vim
index a91a1fc..99e4998 100644
--- a/src/testdir/test_xxd.vim
+++ b/src/testdir/test_xxd.vim
@@ -73,21 +73,21 @@ func Test_xxd()
exe '0r! ' . s:xxd_cmd . ' -l 120 -ps -c20 ' . man_copy
$d
let expected = [
- \ '2e54482058584420312022417567757374203139',
- \ '39362220224d616e75616c207061676520666f72',
- \ '20787864220a2e5c220a2e5c222032317374204d',
- \ '617920313939360a2e5c22204d616e2070616765',
- \ '20617574686f723a0a2e5c2220202020546f6e79',
- \ '204e7567656e74203c746f6e79407363746e7567']
+ \ '2e544820585844203120224d6179203230323422',
+ \ '20224d616e75616c207061676520666f72207878',
+ \ '64220a2e5c220a2e5c222032317374204d617920',
+ \ '313939360a2e5c22204d616e2070616765206175',
+ \ '74686f723a0a2e5c2220202020546f6e79204e75',
+ \ '67656e74203c746f6e79407363746e7567656e2e']
call assert_equal(expected, getline(1,'$'), s:Mess(s:test))
" Test 6: Print the date from xxd.1
let s:test += 1
for arg in ['-l 13', '-l13', '-len 13']
%d
- exe '0r! ' . s:xxd_cmd . ' -s 0x36 ' . arg . ' -cols 13 ' . man_copy
+ exe '0r! ' . s:xxd_cmd . ' -s 0x33 ' . arg . ' -cols 13 ' . man_copy
$d
- call assert_equal('00000036: 3231 7374 204d 6179 2031 3939 36 21st May 1996', getline(1), s:Mess(s:test))
+ call assert_equal('00000033: 3231 7374 204d 6179 2031 3939 36 21st May 1996', getline(1), s:Mess(s:test))
endfor
" Cleanup after tests 5 and 6
diff --git a/src/testdir/test_zip_plugin.vim b/src/testdir/test_zip_plugin.vim
new file mode 100644
index 0000000..e831f26
--- /dev/null
+++ b/src/testdir/test_zip_plugin.vim
@@ -0,0 +1,237 @@
+so check.vim
+
+CheckExecutable unzip
+
+if 0 " Find uncovered line
+ profile start zip_profile
+ profile! file */zip*.vim
+endif
+
+runtime plugin/zipPlugin.vim
+
+def Test_zip_basic()
+
+ ### get our zip file
+ if !filecopy("samples/test.zip", "X.zip")
+ assert_report("Can't copy samples/test.zip")
+ return
+ endif
+ defer delete("X.zip")
+
+ e X.zip
+
+ ### Check header
+ assert_match('^" zip\.vim version v\d\+', getline(1))
+ assert_match('^" Browsing zipfile .*/X.zip', getline(2))
+ assert_match('^" Select a file with cursor and press ENTER', getline(3))
+ assert_match('^$', getline(4))
+
+ ### Check files listing
+ assert_equal(["Xzip/", "Xzip/dir/", "Xzip/file.txt"], getline(5, 7))
+
+ ### Check ENTER on header
+ :1
+ exe ":normal \<cr>"
+ assert_equal("X.zip", @%)
+
+ ### Check ENTER on directory
+ :1|:/^$//dir/
+ assert_match('Please specify a file, not a directory',
+ execute("normal \<CR>"))
+
+ ### Check ENTER on file
+ :1
+ search('file.txt')
+ exe ":normal \<cr>"
+ assert_match('zipfile://.*/X.zip::Xzip/file.txt', @%)
+ assert_equal('one', getline(1))
+
+ ### Check editing file
+ if executable("zip")
+ s/one/two/
+ assert_equal("two", getline(1))
+ w
+ bw|bw
+ e X.zip
+
+ :1|:/^$//file/
+ exe "normal \<cr>"
+ assert_equal("two", getline(1))
+ endif
+
+ only
+ e X.zip
+
+ ### Check extracting file
+ :1|:/^$//file/
+ normal x
+ assert_true(filereadable("Xzip/file.txt"))
+
+ ## Check not overwriting existing file
+ assert_match('<Xzip/file.txt> .* not overwriting!', execute("normal x"))
+
+ delete("Xzip", "rf")
+
+ ### Check extracting directory
+ :1|:/^$//dir/
+ assert_match('Please specify a file, not a directory', execute("normal x"))
+ assert_equal("X.zip", @%)
+
+ ### Check "x" on header
+ :1
+ normal x
+ assert_equal("X.zip", @%)
+ bw
+
+ ### Check opening zip when "unzip" program is missing
+ var save_zip_unzipcmd = g:zip_unzipcmd
+ g:zip_unzipcmd = "/"
+ assert_match('unzip not available on your system', execute("e X.zip"))
+
+ ### Check when "unzip" don't work
+ if executable("false")
+ g:zip_unzipcmd = "false"
+ assert_match('X\.zip is not a zip file', execute("e X.zip"))
+ endif
+ bw
+
+ g:zip_unzipcmd = save_zip_unzipcmd
+ e X.zip
+
+ ### Check opening file when "unzip" is missing
+ g:zip_unzipcmd = "/"
+ assert_match('sorry, your system doesn''t appear to have the / program',
+ execute("normal \<CR>"))
+
+ bw|bw
+ g:zip_unzipcmd = save_zip_unzipcmd
+ e X.zip
+
+ ### Check :write when "zip" program is missing
+ :1|:/^$//file/
+ exe "normal \<cr>Goanother\<esc>"
+ var save_zip_zipcmd = g:zip_zipcmd
+ g:zip_zipcmd = "/"
+ assert_match('sorry, your system doesn''t appear to have the / program',
+ execute("write"))
+
+ ### Check when "zip" report failure
+ if executable("false")
+ g:zip_zipcmd = "false"
+ assert_match('sorry, unable to update .*/X.zip with Xzip/file.txt',
+ execute("write"))
+ endif
+ bw!|bw
+
+ g:zip_zipcmd = save_zip_zipcmd
+
+ ### Check opening an no zipfile
+ writefile(["qsdf"], "Xcorupt.zip", "D")
+ e! Xcorupt.zip
+ assert_equal("qsdf", getline(1))
+
+ bw
+
+ ### Check no existing zipfile
+ assert_match('File not readable', execute("e Xnot_exists.zip"))
+
+ bw
+enddef
+
+def Test_zip_glob_fname()
+ CheckNotMSWindows
+ # does not work on Windows, why?
+
+ ### copy sample zip file
+ if !filecopy("samples/testa.zip", "X.zip")
+ assert_report("Can't copy samples/testa.zip")
+ return
+ endif
+ defer delete("X.zip")
+ defer delete('zipglob', 'rf')
+
+ e X.zip
+
+ ### 1) Check extracting strange files
+ :1
+ var fname = 'a[a].txt'
+ search('\V' .. fname)
+ normal x
+ assert_true(filereadable('zipglob/' .. fname))
+ delete('zipglob', 'rf')
+
+ :1
+ fname = 'a*.txt'
+ search('\V' .. fname)
+ normal x
+ assert_true(filereadable('zipglob/' .. fname))
+ delete('zipglob', 'rf')
+
+ :1
+ fname = 'a?.txt'
+ search('\V' .. fname)
+ normal x
+ assert_true(filereadable('zipglob/' .. fname))
+ delete('zipglob', 'rf')
+
+ :1
+ fname = 'a\.txt'
+ search('\V' .. escape(fname, '\\'))
+ normal x
+ assert_true(filereadable('zipglob/' .. fname))
+ delete('zipglob', 'rf')
+
+ :1
+ fname = 'a\\.txt'
+ search('\V' .. escape(fname, '\\'))
+ normal x
+ assert_true(filereadable('zipglob/' .. fname))
+ delete('zipglob', 'rf')
+
+ ### 2) Check entering strange file names
+ :1
+ fname = 'a[a].txt'
+ search('\V' .. fname)
+ exe ":normal \<cr>"
+ assert_match('zipfile://.*/X.zip::zipglob/a\[a\].txt', @%)
+ assert_equal('a test file with []', getline(1))
+ bw
+
+ e X.zip
+ :1
+ fname = 'a*.txt'
+ search('\V' .. fname)
+ exe ":normal \<cr>"
+ assert_match('zipfile://.*/X.zip::zipglob/a\*.txt', @%)
+ assert_equal('a test file with a*', getline(1))
+ bw
+
+ e X.zip
+ :1
+ fname = 'a?.txt'
+ search('\V' .. fname)
+ exe ":normal \<cr>"
+ assert_match('zipfile://.*/X.zip::zipglob/a?.txt', @%)
+ assert_equal('a test file with a?', getline(1))
+ bw
+
+ e X.zip
+ :1
+ fname = 'a\.txt'
+ search('\V' .. escape(fname, '\\'))
+ exe ":normal \<cr>"
+ assert_match('zipfile://.*/X.zip::zipglob/a\\.txt', @%)
+ assert_equal('a test file with a\', getline(1))
+ bw
+
+ e X.zip
+ :1
+ fname = 'a\\.txt'
+ search('\V' .. escape(fname, '\\'))
+ exe ":normal \<cr>"
+ assert_match('zipfile://.*/X.zip::zipglob/a\\\\.txt', @%)
+ assert_equal('a test file with a double \', getline(1))
+ bw
+
+ bw
+enddef
diff --git a/src/testdir/view_util.vim b/src/testdir/view_util.vim
index 71cb071..161c8b2 100644
--- a/src/testdir/view_util.vim
+++ b/src/testdir/view_util.vim
@@ -71,7 +71,7 @@ endfunc
" than the raw code.
" Return the modifyOtherKeys level 2 encoding for "key" with "modifier"
-" (number value, e.g. CTRL is 5).
+" (number value, e.g. CTRL is 5, Shift is 2, Alt is 3).
func GetEscCodeCSI27(key, modifier)
let key = printf("%d", char2nr(a:key))
let mod = printf("%d", a:modifier)
diff --git a/src/testdir/viewdumps.vim b/src/testdir/viewdumps.vim
new file mode 100644
index 0000000..62f7bbe
--- /dev/null
+++ b/src/testdir/viewdumps.vim
@@ -0,0 +1,11 @@
+vim9script
+
+exec 'source ' .. (((cwdpath: string) => cwdpath
+ ->strpart(0, cwdpath->strridx('/vim')))(getcwd()))
+ .. '/vim/src/testdir/commondumps.vim'
+g:Init('\<src\>', 0)
+
+# Match ":language" of runtest.vim.
+language messages C
+
+# vim:fdm=syntax:sw=2:ts=8:noet:nolist:nosta: