aboutsummaryrefslogtreecommitdiff
path: root/src/nvim/testdir
diff options
context:
space:
mode:
Diffstat (limited to 'src/nvim/testdir')
-rw-r--r--src/nvim/testdir/Make_all.mak1
-rw-r--r--src/nvim/testdir/Makefile34
-rw-r--r--src/nvim/testdir/check.vim58
-rw-r--r--src/nvim/testdir/runtest.vim45
-rw-r--r--src/nvim/testdir/samples/re.freeze.txt6
-rw-r--r--src/nvim/testdir/sautest/autoload/foo.vim4
-rw-r--r--src/nvim/testdir/script_util.vim6
-rw-r--r--src/nvim/testdir/setup.vim7
-rw-r--r--src/nvim/testdir/shared.vim28
-rw-r--r--src/nvim/testdir/test42.inbin2387 -> 0 bytes
-rw-r--r--src/nvim/testdir/test42.okbin409 -> 0 bytes
-rw-r--r--src/nvim/testdir/test49.in31
-rw-r--r--src/nvim/testdir/test49.ok56
-rw-r--r--src/nvim/testdir/test49.vim6724
-rw-r--r--src/nvim/testdir/test_alot.vim1
-rw-r--r--src/nvim/testdir/test_arglist.vim180
-rw-r--r--src/nvim/testdir/test_assert.vim67
-rw-r--r--src/nvim/testdir/test_autochdir.vim4
-rw-r--r--src/nvim/testdir/test_autocmd.vim535
-rw-r--r--src/nvim/testdir/test_autoload.vim6
-rw-r--r--src/nvim/testdir/test_backup.vim35
-rw-r--r--src/nvim/testdir/test_blob.vim12
-rw-r--r--src/nvim/testdir/test_breakindent.vim202
-rw-r--r--src/nvim/testdir/test_buffer.vim256
-rw-r--r--src/nvim/testdir/test_bufline.vim116
-rw-r--r--src/nvim/testdir/test_cd.vim36
-rw-r--r--src/nvim/testdir/test_charsearch.vim61
-rw-r--r--src/nvim/testdir/test_checkpath.vim17
-rw-r--r--src/nvim/testdir/test_clientserver.vim35
-rw-r--r--src/nvim/testdir/test_cmdline.vim1733
-rw-r--r--src/nvim/testdir/test_comments.vim277
-rw-r--r--src/nvim/testdir/test_compiler.vim8
-rw-r--r--src/nvim/testdir/test_const.vim18
-rw-r--r--src/nvim/testdir/test_cpoptions.vim927
-rw-r--r--src/nvim/testdir/test_cscope.vim344
-rw-r--r--src/nvim/testdir/test_cursor_func.vim141
-rw-r--r--src/nvim/testdir/test_cursorline.vim18
-rw-r--r--src/nvim/testdir/test_debugger.vim64
-rw-r--r--src/nvim/testdir/test_delete.vim14
-rw-r--r--src/nvim/testdir/test_diffmode.vim180
-rw-r--r--src/nvim/testdir/test_digraph.vim13
-rw-r--r--src/nvim/testdir/test_display.vim159
-rw-r--r--src/nvim/testdir/test_edit.vim307
-rw-r--r--src/nvim/testdir/test_escaped_glob.vim2
-rw-r--r--src/nvim/testdir/test_eval_stuff.vim61
-rw-r--r--src/nvim/testdir/test_ex_mode.vim1
-rw-r--r--src/nvim/testdir/test_excmd.vim54
-rw-r--r--src/nvim/testdir/test_exists.vim6
-rw-r--r--src/nvim/testdir/test_exit.vim1
-rw-r--r--src/nvim/testdir/test_expand.vim89
-rw-r--r--src/nvim/testdir/test_expand_func.vim8
-rw-r--r--src/nvim/testdir/test_expr.vim190
-rw-r--r--src/nvim/testdir/test_filechanged.vim6
-rw-r--r--src/nvim/testdir/test_fileformat.vim9
-rw-r--r--src/nvim/testdir/test_filetype.vim204
-rw-r--r--src/nvim/testdir/test_filter_map.vim7
-rw-r--r--src/nvim/testdir/test_fixeol.vim90
-rw-r--r--src/nvim/testdir/test_fnamemodify.vim6
-rw-r--r--src/nvim/testdir/test_fold.vim619
-rw-r--r--src/nvim/testdir/test_functions.vim700
-rw-r--r--src/nvim/testdir/test_getcwd.vim2
-rw-r--r--src/nvim/testdir/test_getvar.vim9
-rw-r--r--src/nvim/testdir/test_gf.vim26
-rw-r--r--src/nvim/testdir/test_global.vim19
-rw-r--r--src/nvim/testdir/test_gui.vim43
-rw-r--r--src/nvim/testdir/test_hardcopy.vim204
-rw-r--r--src/nvim/testdir/test_help.vim134
-rw-r--r--src/nvim/testdir/test_help_tagjump.vim28
-rw-r--r--src/nvim/testdir/test_hide.vim2
-rw-r--r--src/nvim/testdir/test_highlight.vim29
-rw-r--r--src/nvim/testdir/test_history.vim17
-rw-r--r--src/nvim/testdir/test_increment.vim35
-rw-r--r--src/nvim/testdir/test_ins_complete.vim1353
-rw-r--r--src/nvim/testdir/test_lambda.vim38
-rw-r--r--src/nvim/testdir/test_langmap.vim35
-rw-r--r--src/nvim/testdir/test_legacy_filetype.vim4
-rw-r--r--src/nvim/testdir/test_let.vim115
-rw-r--r--src/nvim/testdir/test_lispindent.vim (renamed from src/nvim/testdir/test_lispwords.vim)31
-rw-r--r--src/nvim/testdir/test_listdict.vim212
-rw-r--r--src/nvim/testdir/test_listlbr.vim40
-rw-r--r--src/nvim/testdir/test_makeencoding.vim16
-rw-r--r--src/nvim/testdir/test_maparg.vim35
-rw-r--r--src/nvim/testdir/test_mapping.vim79
-rw-r--r--src/nvim/testdir/test_marks.vim24
-rw-r--r--src/nvim/testdir/test_match.vim127
-rw-r--r--src/nvim/testdir/test_matchfuzzy.vim18
-rw-r--r--src/nvim/testdir/test_menu.vim34
-rw-r--r--src/nvim/testdir/test_messages.vim100
-rw-r--r--src/nvim/testdir/test_method.vim23
-rw-r--r--src/nvim/testdir/test_mksession.vim49
-rw-r--r--src/nvim/testdir/test_modeline.vim84
-rw-r--r--src/nvim/testdir/test_normal.vim655
-rw-r--r--src/nvim/testdir/test_options.vim360
-rw-r--r--src/nvim/testdir/test_partial.vim5
-rw-r--r--src/nvim/testdir/test_paste.vim76
-rw-r--r--src/nvim/testdir/test_popup.vim58
-rw-r--r--src/nvim/testdir/test_preview.vim7
-rw-r--r--src/nvim/testdir/test_profile.vim47
-rw-r--r--src/nvim/testdir/test_prompt_buffer.vim4
-rw-r--r--src/nvim/testdir/test_quickfix.vim1004
-rw-r--r--src/nvim/testdir/test_quotestar.vim7
-rw-r--r--src/nvim/testdir/test_random.vim44
-rw-r--r--src/nvim/testdir/test_recover.vim414
-rw-r--r--src/nvim/testdir/test_regexp_latin.vim55
-rw-r--r--src/nvim/testdir/test_regexp_utf8.vim3
-rw-r--r--src/nvim/testdir/test_registers.vim34
-rw-r--r--src/nvim/testdir/test_reltime.vim4
-rw-r--r--src/nvim/testdir/test_retab.vim32
-rw-r--r--src/nvim/testdir/test_search.vim238
-rw-r--r--src/nvim/testdir/test_search_stat.vim8
-rw-r--r--src/nvim/testdir/test_selectmode.vim3
-rw-r--r--src/nvim/testdir/test_set.vim19
-rw-r--r--src/nvim/testdir/test_shell.vim209
-rw-r--r--src/nvim/testdir/test_signals.vim41
-rw-r--r--src/nvim/testdir/test_signs.vim68
-rw-r--r--src/nvim/testdir/test_sleep.vim1
-rw-r--r--src/nvim/testdir/test_sort.vim5
-rw-r--r--src/nvim/testdir/test_source.vim23
-rw-r--r--src/nvim/testdir/test_spell.vim68
-rw-r--r--src/nvim/testdir/test_startup.vim135
-rw-r--r--src/nvim/testdir/test_startup_utf8.vim4
-rw-r--r--src/nvim/testdir/test_statusline.vim41
-rw-r--r--src/nvim/testdir/test_substitute.vim123
-rw-r--r--src/nvim/testdir/test_swap.vim184
-rw-r--r--src/nvim/testdir/test_syntax.vim113
-rw-r--r--src/nvim/testdir/test_system.vim2
-rw-r--r--src/nvim/testdir/test_tabline.vim57
-rw-r--r--src/nvim/testdir/test_tabpage.vim15
-rw-r--r--src/nvim/testdir/test_tagfunc.vim299
-rw-r--r--src/nvim/testdir/test_tagjump.vim214
-rw-r--r--src/nvim/testdir/test_taglist.vim43
-rw-r--r--src/nvim/testdir/test_termcodes.vim26
-rw-r--r--src/nvim/testdir/test_textformat.vim302
-rw-r--r--src/nvim/testdir/test_timers.vim45
-rw-r--r--src/nvim/testdir/test_trycatch.vim220
-rw-r--r--src/nvim/testdir/test_undo.vim29
-rw-r--r--src/nvim/testdir/test_unlet.vim25
-rw-r--r--src/nvim/testdir/test_user_func.vim337
-rw-r--r--src/nvim/testdir/test_usercommands.vim108
-rw-r--r--src/nvim/testdir/test_utf8.vim87
-rw-r--r--src/nvim/testdir/test_vartabs.vim18
-rw-r--r--src/nvim/testdir/test_viminfo.vim26
-rw-r--r--src/nvim/testdir/test_vimscript.vim5870
-rw-r--r--src/nvim/testdir/test_virtualedit.vim105
-rw-r--r--src/nvim/testdir/test_visual.vim36
-rw-r--r--src/nvim/testdir/test_winbuf_close.vim20
-rw-r--r--src/nvim/testdir/test_window_cmd.vim410
-rw-r--r--src/nvim/testdir/test_window_id.vim12
-rw-r--r--src/nvim/testdir/test_writefile.vim466
-rw-r--r--src/nvim/testdir/view_util.vim16
-rw-r--r--src/nvim/testdir/vim9.vim112
151 files changed, 21188 insertions, 9588 deletions
diff --git a/src/nvim/testdir/Make_all.mak b/src/nvim/testdir/Make_all.mak
new file mode 100644
index 0000000000..b917877422
--- /dev/null
+++ b/src/nvim/testdir/Make_all.mak
@@ -0,0 +1 @@
+# Tests may depend on the existence of this file.
diff --git a/src/nvim/testdir/Makefile b/src/nvim/testdir/Makefile
index 4641408069..9511b311e6 100644
--- a/src/nvim/testdir/Makefile
+++ b/src/nvim/testdir/Makefile
@@ -11,16 +11,7 @@ ROOT := ../../..
export SHELL := sh
export NVIM_PRG := $(NVIM_PRG)
-export TMPDIR := $(abspath Xtest-tmpdir)
-
-SCRIPTS_DEFAULT = \
- test42.out \
-
-ifneq ($(OS),Windows_NT)
- SCRIPTS_DEFAULTS := $(SCRIPTS_DEFAULT) \
- test49.out \
-
-endif
+export TMPDIR := $(abspath X-test-tmpdir)
ifeq ($(OS),Windows_NT)
FIXFF = fixff
@@ -28,8 +19,6 @@ else
FIXFF =
endif
-SCRIPTS ?= $(SCRIPTS_DEFAULT)
-
# Tests using runtest.vim.
NEW_TESTS_ALOT := test_alot_utf8 test_alot test_alot_latin
NEW_TESTS_IN_ALOT := $(shell sed -n '/^source/ s/^source //; s/\.vim$$//p' $(addsuffix .vim,$(NEW_TESTS_ALOT)))
@@ -66,11 +55,7 @@ else
endif
endif
-ifdef TESTNUM
- SCRIPTS := test$(TESTNUM).out
-endif
-
-nongui: nolog $(FIXFF) $(SCRIPTS) newtests report
+nongui: nolog $(FIXFF) newtests report
.gdbinit:
@echo "[OLDTEST-PREP] Setting up .gdbinit"
@@ -88,8 +73,6 @@ report:
test1.out: $(NVIM_PRG)
-$(SCRIPTS): $(NVIM_PRG) test1.out
-
NO_PLUGINS = --noplugin --headless
# In vim, if the -u command line option is specified, compatible is turned on
# and viminfo is not read. Unlike vim, neovim reads viminfo and requires the
@@ -147,17 +130,6 @@ test1.out: .gdbinit test1.in
@rm -f wrongtermsize
@rm -rf X* viminfo
-%.out: %.in .gdbinit
- @echo "[OLDESTTEST] Running" $*
- @rm -rf $*.failed test.ok $(RM_ON_RUN)
- @mkdir -p $(TMPDIR)
- @cp $*.ok test.ok
- @/bin/sh runnvim.sh --oldesttest $(ROOT) $(NVIM_PRG) $* $(RUN_VIM) $*.in
- @rm -rf X* test.ok viminfo
-
-# Explicit dependencies.
-test49.out: test49.vim
-
nolog:
@echo "[OLDTEST-PREP] Removing test.log and messages"
@rm -f test.log messages
@@ -179,4 +151,4 @@ newtestssilent: $(NEW_TESTS_RES)
@echo "[OLDTEST] Running" $*
@rm -rf $*.failed test.ok $(RM_ON_RUN)
@mkdir -p $(TMPDIR)
- @/bin/sh runnvim.sh $(ROOT) $(NVIM_PRG) $* $(RUN_VIMTEST) $(NO_INITS) -u NONE -S runtest.vim $*.vim
+ @/bin/sh runnvim.sh $(ROOT) $(NVIM_PRG) $* $(RUN_VIMTEST) $(NO_INITS) -u NONE --cmd "set shortmess-=F" -S runtest.vim $*.vim
diff --git a/src/nvim/testdir/check.vim b/src/nvim/testdir/check.vim
index 4107df99d6..680a59006b 100644
--- a/src/nvim/testdir/check.vim
+++ b/src/nvim/testdir/check.vim
@@ -1,11 +1,16 @@
source shared.vim
source term_util.vim
+command -nargs=1 MissingFeature throw 'Skipped: ' .. <args> .. ' feature missing'
+
" Command to check for the presence of a feature.
command -nargs=1 CheckFeature call CheckFeature(<f-args>)
func CheckFeature(name)
+ " if !has(a:name, 1)
+ " throw 'Checking for non-existent feature ' .. a:name
+ " endif
if !has(a:name)
- throw 'Skipped: ' .. a:name .. ' feature missing'
+ MissingFeature a:name
endif
endfunc
@@ -39,6 +44,22 @@ func CheckFunction(name)
endif
endfunc
+" Command to check for the presence of an Ex command
+command -nargs=1 CheckCommand call CheckCommand(<f-args>)
+func CheckCommand(name)
+ if !exists(':' .. a:name)
+ throw 'Skipped: ' .. a:name .. ' command not supported'
+ endif
+endfunc
+
+" Command to check for the presence of a shell command
+command -nargs=1 CheckExecutable call CheckExecutable(<f-args>)
+func CheckExecutable(name)
+ if !executable(a:name)
+ throw 'Skipped: ' .. a:name .. ' program not executable'
+ endif
+endfunc
+
" Command to check for the presence of python. Argument should have been
" obtained with PythonProg()
func CheckPython(name)
@@ -71,12 +92,11 @@ func CheckUnix()
endif
endfunc
-" Command to check for not running on a BSD system.
-" TODO: using this checks should not be needed
-command CheckNotBSD call CheckNotBSD()
-func CheckNotBSD()
- if has('bsd')
- throw 'Skipped: does not work on BSD'
+" Command to check for running on Linux
+command CheckLinux call CheckLinux()
+func CheckLinux()
+ if !has('linux')
+ throw 'Skipped: only works on Linux'
endif
endfunc
@@ -105,6 +125,14 @@ func CheckCanRunGui()
endif
endfunc
+" Command to Check for an environment variable
+command -nargs=1 CheckEnv call CheckEnv(<f-args>)
+func CheckEnv(name)
+ if empty(eval('$' .. a:name))
+ throw 'Skipped: Environment variable ' .. a:name .. ' is not set'
+ endif
+endfunc
+
" Command to check that we are using the GUI
command CheckGui call CheckGui()
func CheckGui()
@@ -145,6 +173,22 @@ func CheckNotAsan()
endif
endfunc
+" Command to check for not running under valgrind
+command CheckNotValgrind call CheckNotValgrind()
+func CheckNotValgrind()
+ if RunningWithValgrind()
+ throw 'Skipped: does not work well with valgrind'
+ endif
+endfunc
+
+" Command to check for X11 based GUI
+command CheckX11BasedGui call CheckX11BasedGui()
+func CheckX11BasedGui()
+ if !g:x11_based_gui
+ throw 'Skipped: requires X11 based GUI'
+ endif
+endfunc
+
" Command to check for satisfying any of the conditions.
" e.g. CheckAnyOf Feature:bsd Feature:sun Linux
command -nargs=+ CheckAnyOf call CheckAnyOf(<f-args>)
diff --git a/src/nvim/testdir/runtest.vim b/src/nvim/testdir/runtest.vim
index fcd3d5724c..3c5699af73 100644
--- a/src/nvim/testdir/runtest.vim
+++ b/src/nvim/testdir/runtest.vim
@@ -105,7 +105,7 @@ set nomore
lang mess C
" Nvim: append runtime from build dir, which contains the generated doc/tags.
-let &runtimepath .= ','.expand($BUILD_DIR).'/runtime/'
+let &runtimepath ..= ',' .. expand($BUILD_DIR) .. '/runtime/'
let s:t_bold = &t_md
let s:t_normal = &t_me
@@ -114,6 +114,13 @@ if has('win32')
let $PROMPT = '$P$G'
endif
+if has('mac')
+ " In MacOS, when starting a shell in a terminal, a bash deprecation warning
+ " message is displayed. This breaks the terminal test. Disable the warning
+ " message.
+ let $BASH_SILENCE_DEPRECATION_WARNING = 1
+endif
+
" Prepare for calling test_garbagecollect_now().
let v:testing = 1
@@ -164,16 +171,19 @@ func RunTheTest(test)
endtry
endif
+ au VimLeavePre * call EarlyExit(g:testfunc)
if a:test =~ 'Test_nocatch_'
" Function handles errors itself. This avoids skipping commands after the
" error.
+ let g:skipped_reason = ''
exe 'call ' . a:test
+ if g:skipped_reason != ''
+ call add(s:messages, ' Skipped')
+ call add(s:skipped, 'SKIPPED ' . a:test . ': ' . g:skipped_reason)
+ endif
else
try
- let s:test = a:test
- au VimLeavePre * call EarlyExit(s:test)
exe 'call ' . a:test
- au! VimLeavePre
catch /^\cskipped/
call add(s:messages, ' Skipped')
call add(s:skipped, 'SKIPPED ' . a:test . ': ' . substitute(v:exception, '^\S*\s\+', '', ''))
@@ -181,6 +191,7 @@ func RunTheTest(test)
call add(v:errors, 'Caught exception in ' . a:test . ': ' . v:exception . ' @ ' . v:throwpoint)
endtry
endif
+ au! VimLeavePre
" In case 'insertmode' was set and something went wrong, make sure it is
" reset to avoid trouble with anything else.
@@ -243,11 +254,11 @@ func AfterTheTest(func_name)
if len(v:errors) > 0
if match(s:may_fail_list, '^' .. a:func_name) >= 0
let s:fail_expected += 1
- call add(s:errors_expected, 'Found errors in ' . s:test . ':')
+ call add(s:errors_expected, 'Found errors in ' . g:testfunc . ':')
call extend(s:errors_expected, v:errors)
else
let s:fail += 1
- call add(s:errors, 'Found errors in ' . s:test . ':')
+ call add(s:errors, 'Found errors in ' . g:testfunc . ':')
call extend(s:errors, v:errors)
endif
let v:errors = []
@@ -408,22 +419,22 @@ endif
let s:may_fail_list = []
if $TEST_MAY_FAIL != ''
- " Split the list at commas and add () to make it match s:test.
+ " Split the list at commas and add () to make it match g:testfunc.
let s:may_fail_list = split($TEST_MAY_FAIL, ',')->map({i, v -> v .. '()'})
endif
" Execute the tests in alphabetical order.
-for s:test in sort(s:tests)
+for g:testfunc in sort(s:tests)
" Silence, please!
set belloff=all
let prev_error = ''
let total_errors = []
- let run_nr = 1
+ let g:run_nr = 1
" A test can set g:test_is_flaky to retry running the test.
let g:test_is_flaky = 0
- call RunTheTest(s:test)
+ call RunTheTest(g:testfunc)
" Repeat a flaky test. Give up when:
" - $TEST_NO_RETRY is not empty
@@ -431,16 +442,16 @@ for s:test in sort(s:tests)
" - it fails five times (with a different message)
if len(v:errors) > 0
\ && $TEST_NO_RETRY == ''
- \ && (index(s:flaky_tests, s:test) >= 0
+ \ && (index(s:flaky_tests, g:testfunc) >= 0
\ || g:test_is_flaky)
while 1
- call add(s:messages, 'Found errors in ' . s:test . ':')
+ call add(s:messages, 'Found errors in ' . g:testfunc . ':')
call extend(s:messages, v:errors)
- call add(total_errors, 'Run ' . run_nr . ':')
+ call add(total_errors, 'Run ' . g:run_nr . ':')
call extend(total_errors, v:errors)
- if run_nr == 5 || prev_error == v:errors[0]
+ if g:run_nr >= 5 || prev_error == v:errors[0]
call add(total_errors, 'Flaky test failed too often, giving up')
let v:errors = total_errors
break
@@ -455,9 +466,9 @@ for s:test in sort(s:tests)
let prev_error = v:errors[0]
let v:errors = []
- let run_nr += 1
+ let g:run_nr += 1
- call RunTheTest(s:test)
+ call RunTheTest(g:testfunc)
if len(v:errors) == 0
" Test passed on rerun.
@@ -466,7 +477,7 @@ for s:test in sort(s:tests)
endwhile
endif
- call AfterTheTest(s:test)
+ call AfterTheTest(g:testfunc)
endfor
call FinishTesting()
diff --git a/src/nvim/testdir/samples/re.freeze.txt b/src/nvim/testdir/samples/re.freeze.txt
new file mode 100644
index 0000000000..d768c23c5e
--- /dev/null
+++ b/src/nvim/testdir/samples/re.freeze.txt
@@ -0,0 +1,6 @@
+:set re=0 or 2
+Search for the pattern: /\s\+\%#\@<!$/
+vim should not freeze.
+
+<td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td><td style="border-bottom windowtext 0.5pt solid; border-left windowtext;" class=abc align=right><font face=arial><font color=#ff0000><b>5</b></font></font></td>
+
diff --git a/src/nvim/testdir/sautest/autoload/foo.vim b/src/nvim/testdir/sautest/autoload/foo.vim
index 298e7275d8..21d33a0f4d 100644
--- a/src/nvim/testdir/sautest/autoload/foo.vim
+++ b/src/nvim/testdir/sautest/autoload/foo.vim
@@ -9,3 +9,7 @@ endfunc
func foo#addFoo(head)
return a:head .. 'foo'
endfunc
+
+func foo#()
+ return 'empty'
+endfunc
diff --git a/src/nvim/testdir/script_util.vim b/src/nvim/testdir/script_util.vim
index 9913b1dfaf..28d6a621d6 100644
--- a/src/nvim/testdir/script_util.vim
+++ b/src/nvim/testdir/script_util.vim
@@ -48,7 +48,7 @@ endfunc
" delete it afterwards. However, if an exception is thrown the file may remain,
" the caller should call DeleteTheScript() afterwards.
let s:script_name = ''
-function! ExecAsScript(funcname)
+func ExecAsScript(funcname)
" Make a script from the function passed as argument.
let s:script_name = MakeScript(a:funcname)
@@ -56,9 +56,9 @@ function! ExecAsScript(funcname)
exec "source" s:script_name
call delete(s:script_name)
let s:script_name = ''
-endfunction
+endfunc
-function! DeleteTheScript()
+func DeleteTheScript()
if s:script_name
call delete(s:script_name)
let s:script_name = ''
diff --git a/src/nvim/testdir/setup.vim b/src/nvim/testdir/setup.vim
index 6bc3607b69..f895287469 100644
--- a/src/nvim/testdir/setup.vim
+++ b/src/nvim/testdir/setup.vim
@@ -5,7 +5,7 @@ if exists('s:did_load')
set directory&
set directory^=.
set display=
- set fillchars=vert:\|,fold:-
+ set fillchars=vert:\|,foldsep:\|,fold:-
set formatoptions=tcq
set fsync
set laststatus=1
@@ -45,6 +45,11 @@ mapclear!
aunmenu *
tlunmenu *
+" roughly equivalent to test_setmouse() in Vim
+func Ntest_setmouse(row, col)
+ call nvim_input_mouse('move', '', '', 0, a:row - 1, a:col - 1)
+endfunc
+
" Prevent Nvim log from writing to stderr.
let $NVIM_LOG_FILE = exists($NVIM_LOG_FILE) ? $NVIM_LOG_FILE : 'Xnvim.log'
diff --git a/src/nvim/testdir/shared.vim b/src/nvim/testdir/shared.vim
index c2809844ac..33f6d9a2d0 100644
--- a/src/nvim/testdir/shared.vim
+++ b/src/nvim/testdir/shared.vim
@@ -9,7 +9,7 @@ source view_util.vim
" {Nvim}
" Filepath captured from output may be truncated, like this:
-" /home/va...estdir/Xtest-tmpdir/nvimxbXN4i/10
+" /home/va...estdir/X-test-tmpdir/nvimxbXN4i/10
" Get last 2 segments, then combine with $TMPDIR.
func! Fix_truncated_tmpfile(fname)
" sanity check
@@ -285,6 +285,12 @@ func GetVimCommand(...)
return cmd
endfunc
+" Return one when it looks like the tests are run with valgrind, which means
+" that everything is much slower.
+func RunningWithValgrind()
+ return GetVimCommand() =~ '\<valgrind\>'
+endfunc
+
" Get the command to run Vim, with --clean instead of "-u NONE".
func GetVimCommandClean()
let cmd = GetVimCommand()
@@ -317,7 +323,6 @@ func RunVim(before, after, arguments)
endfunc
func RunVimPiped(before, after, arguments, pipecmd)
- let $NVIM_LOG_FILE = exists($NVIM_LOG_FILE) ? $NVIM_LOG_FILE : 'Xnvim.log'
let cmd = GetVimCommand()
let args = ''
if len(a:before) > 0
@@ -332,7 +337,9 @@ func RunVimPiped(before, after, arguments, pipecmd)
" Optionally run Vim under valgrind
" let cmd = 'valgrind --tool=memcheck --leak-check=yes --num-callers=25 --log-file=valgrind ' . cmd
- exe "silent !" . a:pipecmd . cmd . args . ' ' . a:arguments
+ let $NVIM_LOG_FILE = exists($NVIM_LOG_FILE) ? $NVIM_LOG_FILE : 'Xnvim.log'
+ " Nvim does not support -Z flag, remove it.
+ exe "silent !" . a:pipecmd . cmd . args . ' ' . substitute(a:arguments, '-Z', '', 'g')
if len(a:before) > 0
call delete('Xbefore.vim')
@@ -364,4 +371,19 @@ func GetMessages()
return msg_list
endfunc
+" Run the list of commands in 'cmds' and look for 'errstr' in exception.
+" Note that assert_fails() cannot be used in some places and this function
+" can be used.
+func AssertException(cmds, errstr)
+ let save_exception = ''
+ try
+ for cmd in a:cmds
+ exe cmd
+ endfor
+ catch
+ let save_exception = v:exception
+ endtry
+ call assert_match(a:errstr, save_exception)
+endfunc
+
" vim: shiftwidth=2 sts=2 expandtab
diff --git a/src/nvim/testdir/test42.in b/src/nvim/testdir/test42.in
deleted file mode 100644
index 456f9ddb07..0000000000
--- a/src/nvim/testdir/test42.in
+++ /dev/null
Binary files differ
diff --git a/src/nvim/testdir/test42.ok b/src/nvim/testdir/test42.ok
deleted file mode 100644
index 183430d71c..0000000000
--- a/src/nvim/testdir/test42.ok
+++ /dev/null
Binary files differ
diff --git a/src/nvim/testdir/test49.in b/src/nvim/testdir/test49.in
deleted file mode 100644
index 435e62765b..0000000000
--- a/src/nvim/testdir/test49.in
+++ /dev/null
@@ -1,31 +0,0 @@
-This is a test of the script language.
-
-If after adding a new test, the test output doesn't appear properly in
-test49.failed, try to add one or more "G"s at the line ending in "test.out"
-
-STARTTEST
-:se nomore
-:lang mess C
-:so test49.vim
-:" Go back to this file and append the results from register r.
-:buf test49.in
-G"rp:/^Results/,$w! test.out
-:"
-:" make valgrind happy
-:redir => funclist
-:silent func
-:redir END
-:for line in split(funclist, "\n")
-: let name = matchstr(line, 'function \zs[A-Z]\w*\ze(')
-: if name != ''
-: exe "delfunc " . name
-: endif
-:endfor
-:for v in keys(g:)
-: silent! exe "unlet " . v
-:endfor
-:unlet v
-:qa!
-ENDTEST
-
-Results of test49.vim:
diff --git a/src/nvim/testdir/test49.ok b/src/nvim/testdir/test49.ok
deleted file mode 100644
index 9f283e808b..0000000000
--- a/src/nvim/testdir/test49.ok
+++ /dev/null
@@ -1,56 +0,0 @@
-Results of test49.vim:
-*** Test 18: OK (67224583)
-*** Test 19: OK (69275973)
-*** Test 20: OK (1874575085)
-*** Test 21: OK (147932225)
-*** Test 22: OK (4161)
-*** Test 23: OK (49)
-*** Test 24: OK (41)
-*** Test 27: OK (1996459)
-*** Test 28: OK (1996459)
-*** Test 29: OK (170428555)
-*** Test 30: OK (190905173)
-*** Test 31: OK (190905173)
-*** Test 34: OK (2146584868)
-*** Test 35: OK (2146584868)
-*** Test 36: OK (1071644672)
-*** Test 37: OK (1071644672)
-*** Test 38: OK (357908480)
-*** Test 39: OK (357908480)
-*** Test 40: OK (357908480)
-*** Test 49: OK (179000669)
-*** Test 50: OK (363550045)
-*** Test 52: OK (1247112011)
-*** Test 53: OK (131071)
-*** Test 54: OK (2047)
-*** Test 55: OK (1023)
-*** Test 56: OK (511)
-*** Test 57: OK (2147450880)
-*** Test 58: OK (624945)
-*** Test 59: OK (2038431743)
-*** Test 60: OK (311511339)
-*** Test 61: OK (374889517)
-*** Test 62: OK (286331153)
-*** Test 63: OK (236978127)
-*** Test 64: OK (1499645335)
-*** Test 65: OK (70187)
-*** Test 66: OK (5464)
-*** Test 67: OK (212514423)
-*** Test 68: OK (212514423)
-*** Test 76: OK (1610087935)
-*** Test 77: OK (1388671)
-*** Test 78: OK (134217728)
-*** Test 79: OK (70288929)
-*** Test 80: OK (17895765)
-*** Test 81: OK (387)
-*** Test 82: OK (8454401)
-*** Test 83: OK (2835)
-*** Test 84: OK (934782101)
-*** Test 85: OK (198689)
---- Test 86: No Crash for vimgrep on BufUnload
-*** Test 86: OK (0)
---- Test 88: All tests were run with throwing exceptions on error.
- The $VIMNOERRTHROW control is not configured.
---- Test 88: All tests were run with throwing exceptions on interrupt.
- The $VIMNOINTTHROW control is not configured.
-*** Test 88: OK (50443995)
diff --git a/src/nvim/testdir/test49.vim b/src/nvim/testdir/test49.vim
deleted file mode 100644
index 3ee5e9ff7c..0000000000
--- a/src/nvim/testdir/test49.vim
+++ /dev/null
@@ -1,6724 +0,0 @@
-" Vim script language tests
-" Author: Servatius Brandt <Servatius.Brandt@fujitsu-siemens.com>
-" Last Change: 2019 Nov 03
-
-"-------------------------------------------------------------------------------
-" Test environment {{{1
-"-------------------------------------------------------------------------------
-
-
-" Adding new tests easily. {{{2
-"
-" Writing new tests is eased considerably with the following functions and
-" abbreviations (see "Commands for recording the execution path", "Automatic
-" argument generation").
-"
-" To get the abbreviations, execute the command
-"
-" :let test49_set_env = 1 | source test49.vim
-"
-" To get them always (from src/nvim/testdir), put a line
-"
-" au! BufRead test49.vim let test49_set_env = 1 | source test49.vim
-"
-" into the local .vimrc file in the src/nvim/testdir directory.
-"
-if exists("test49_set_env") && test49_set_env
-
- " Automatic argument generation for the test environment commands.
-
- function! Xsum()
- let addend = substitute(getline("."), '^.*"\s*X:\s*\|^.*', '', "")
- " Evaluate arithmetic expression.
- if addend != ""
- exec "let g:Xsum = g:Xsum + " . addend
- endif
- endfunction
-
- function! Xcheck()
- let g:Xsum=0
- ?XpathINIT?,.call Xsum()
- exec "norm A "
- return g:Xsum
- endfunction
-
- iab Xcheck Xcheck<Space><C-R>=Xcheck()<CR><C-O>x
-
- function! Xcomment(num)
- let str = ""
- let tabwidth = &sts ? &sts : &ts
- let tabs = (48+tabwidth - a:num - virtcol(".")) / tabwidth
- while tabs > 0
- let str = str . "\t"
- let tabs = tabs - 1
- endwhile
- let str = str . '" X:'
- return str
- endfunction
-
- function! Xloop()
- let back = line(".") . "|norm" . virtcol(".") . "|"
- norm 0
- let last = search('X\(loop\|path\)INIT\|Xloop\>', "bW")
- exec back
- let theline = getline(last)
- if theline =~ 'X\(loop\|path\)INIT'
- let num = 1
- else
- let num = 2 * substitute(theline, '.*Xloop\s*\(\d\+\).*', '\1', "")
- endif
- ?X\(loop\|path\)INIT?
- \s/\(XloopINIT!\=\s*\d\+\s\+\)\@<=\(\d\+\)/\=2*submatch(2)/
- exec back
- exec "norm a "
- return num . Xcomment(strlen(num))
- endfunction
-
- iab Xloop Xloop<Space><C-R>=Xloop()<CR><C-O>x
-
- function! Xpath(loopinit)
- let back = line(".") . "|norm" . virtcol(".") . "|"
- norm 0
- let last = search('XpathINIT\|Xpath\>\|XloopINIT', "bW")
- exec back
- let theline = getline(last)
- if theline =~ 'XpathINIT'
- let num = 1
- elseif theline =~ 'Xpath\>'
- let num = 2 * substitute(theline, '.*Xpath\s*\(\d\+\).*', '\1', "")
- else
- let pattern = '.*XloopINIT!\=\s*\(\d\+\)\s*\(\d\+\).*'
- let num = substitute(theline, pattern, '\1', "")
- let factor = substitute(theline, pattern, '\2', "")
- " The "<C-O>x" from the "Xpath" iab and the character triggering its
- " expansion are in the input buffer. Save and clear typeahead so
- " that it is not read away by the call to "input()" below. Restore
- " afterwards.
- call inputsave()
- let loops = input("Number of iterations in previous loop? ")
- call inputrestore()
- while (loops > 0)
- let num = num * factor
- let loops = loops - 1
- endwhile
- endif
- exec "norm a "
- if a:loopinit
- return num . " 1"
- endif
- return num . Xcomment(strlen(num))
- endfunction
-
- iab Xpath Xpath<Space><C-R>=Xpath(0)<CR><C-O>x
- iab XloopINIT XloopINIT<Space><C-R>=Xpath(1)<CR><C-O>x
-
- " Also useful (see ExtraVim below):
- aug ExtraVim
- au!
- au BufEnter <sfile> syn region ExtraVim
- \ start=+^if\s\+ExtraVim(.*)+ end=+^endif+
- \ transparent keepend
- au BufEnter <sfile> syn match ExtraComment /^"/
- \ contained containedin=ExtraVim
- au BufEnter <sfile> hi link ExtraComment vimComment
- aug END
-
- aug Xpath
- au BufEnter <sfile> syn keyword Xpath
- \ XpathINIT Xpath XloopINIT Xloop XloopNEXT Xcheck Xout
- au BufEnter <sfile> hi link Xpath Special
- aug END
-
- do BufEnter <sfile>
-
- " Do not execute the tests when sourcing this file for getting the functions
- " and abbreviations above, which are intended for easily adding new test
- " cases; they are not needed for test execution. Unlet the variable
- " controlling this so that an explicit ":source" command for this file will
- " execute the tests.
- unlet test49_set_env
- finish
-
-endif
-
-
-" Commands for recording the execution path. {{{2
-"
-" The Xpath/Xloop commands can be used for computing the eXecution path by
-" adding (different) powers of 2 from those script lines, for which the
-" execution should be checked. Xloop provides different addends for each
-" execution of a loop. Permitted values are 2^0 to 2^30, so that 31 execution
-" points (multiply counted inside loops) can be tested.
-"
-" Note that the arguments of the following commands can be generated
-" automatically, see below.
-"
-" Usage: {{{3
-"
-" - Use XpathINIT at the beginning of the test.
-"
-" - Use Xpath to check if a line is executed.
-" Argument: power of 2 (decimal).
-"
-" - To check multiple execution of loops use Xloop for automatically
-" computing Xpath values:
-"
-" - Use XloopINIT before the loop.
-" Two arguments:
-" - the first Xpath value (power of 2) to be used (Xnext),
-" - factor for computing a new Xnext value when reexecuting a loop
-" (by a ":continue" or ":endwhile"); this should be 2^n where
-" n is the number of Xloop commands inside the loop.
-" If XloopINIT! is used, the first execution of XloopNEXT is
-" a no-operation.
-"
-" - Use Xloop inside the loop:
-" One argument:
-" The argument and the Xnext value are multiplied to build the
-" next Xpath value. No new Xnext value is prepared. The argument
-" should be 2^(n-1) for the nth Xloop command inside the loop.
-" If the loop has only one Xloop command, the argument can be
-" omitted (default: 1).
-"
-" - Use XloopNEXT before ":continue" and ":endwhile". This computes a new
-" Xnext value for the next execution of the loop by multiplying the old
-" one with the factor specified in the XloopINIT command. No Argument.
-" Alternatively, when XloopINIT! is used, a single XloopNEXT at the
-" beginning of the loop can be used.
-"
-" Nested loops are not supported.
-"
-" - Use Xcheck at end of each test. It prints the test number, the expected
-" execution path value, the test result ("OK" or "FAIL"), and, if the tests
-" fails, the actual execution path.
-" One argument:
-" Expected Xpath/Xloop sum for the correct execution path.
-" In order that this value can be computed automatically, do the
-" following: For each line in the test with an Xpath and Xloop
-" command, add a comment starting with "X:" and specifying an
-" expression that evaluates to the value contributed by this line to
-" the correct execution path. (For copying an Xpath argument of at
-" least two digits into the comment, press <C-P>.) At the end of the
-" test, just type "Xcheck" and press <Esc>.
-"
-" - In order to add additional information to the test output file, use the
-" Xout command. Argument(s) like ":echo".
-"
-" Automatic argument generation: {{{3
-"
-" The arguments of the Xpath, XloopINIT, Xloop, and Xcheck commands can be
-" generated automatically, so that new tests can easily be written without
-" mental arithmetic. The Xcheck argument is computed from the "X:" comments
-" of the preceding Xpath and Xloop commands. See the commands and
-" abbreviations at the beginning of this file.
-"
-" Implementation: {{{3
-" XpathINIT, Xpath, XloopINIT, Xloop, XloopNEXT, Xcheck, Xout.
-"
-" The variants for existing g:ExtraVimResult are needed when executing a script
-" in an extra Vim process, see ExtraVim below.
-
-" EXTRA_VIM_START - do not change or remove this line.
-
-com! XpathINIT let g:Xpath = 0
-
-if exists("g:ExtraVimResult")
- com! -count -bar Xpath exec "!echo <count> >>" . g:ExtraVimResult
-else
- com! -count -bar Xpath let g:Xpath = g:Xpath + <count>
-endif
-
-com! -count -nargs=1 -bang
- \ XloopINIT let g:Xnext = <count> |
- \ let g:Xfactor = <args> |
- \ let g:Xskip = strlen("<bang>")
-
-if exists("g:ExtraVimResult")
- com! -count=1 -bar Xloop exec "!echo " . (g:Xnext * <count>) . " >>" .
- \ g:ExtraVimResult
-else
- com! -count=1 -bar Xloop let g:Xpath = g:Xpath + g:Xnext * <count>
-endif
-
-com! XloopNEXT let g:Xnext = g:Xnext *
- \ (g:Xskip ? 1 : g:Xfactor) |
- \ let g:Xskip = 0
-
-let @r = ""
-let Xtest = 1
-com! -count Xcheck let Xresult = "*** Test " .
- \ (Xtest<10?" ":Xtest<100?" ":"") .
- \ Xtest . ": " . (
- \ (Xpath==<count>) ? "OK (".Xpath.")" :
- \ "FAIL (".Xpath." instead of <count>)"
- \ ) |
- \ let @R = Xresult . "\n" |
- \ echo Xresult |
- \ let Xtest = Xtest + 1
-
-if exists("g:ExtraVimResult")
- com! -nargs=+ Xoutq exec "!echo @R:'" .
- \ substitute(substitute(<q-args>,
- \ "'", '&\\&&', "g"), "\n", "@NL@", "g")
- \ . "' >>" . g:ExtraVimResult
-else
- com! -nargs=+ Xoutq let @R = "--- Test " .
- \ (g:Xtest<10?" ":g:Xtest<100?" ":"") .
- \ g:Xtest . ": " . substitute(<q-args>,
- \ "\n", "&\t ", "g") . "\n"
-endif
-com! -nargs=+ Xout exec 'Xoutq' <args>
-
-" Switch off storing of lines for undoing changes. Speeds things up a little.
-set undolevels=-1
-
-" EXTRA_VIM_STOP - do not change or remove this line.
-
-
-" ExtraVim() - Run a script file in an extra Vim process. {{{2
-"
-" This is useful for testing immediate abortion of the script processing due to
-" an error in a command dynamically enclosed by a :try/:tryend region or when an
-" exception is thrown but not caught or when an interrupt occurs. It can also
-" be used for testing :finish.
-"
-" An interrupt location can be specified by an "INTERRUPT" comment. A number
-" telling how often this location is reached (in a loop or in several function
-" calls) should be specified as argument. When missing, once per script
-" invocation or function call is assumed. INTERRUPT locations are tested by
-" setting a breakpoint in that line and using the ">quit" debug command when
-" the breakpoint is reached. A function for which an INTERRUPT location is
-" specified must be defined before calling it (or executing it as a script by
-" using ExecAsScript below).
-"
-" This function is only called in normal modus ("g:ExtraVimResult" undefined).
-"
-" Tests to be executed as an extra script should be written as follows:
-"
-" column 1 column 1
-" | |
-" v v
-"
-" XpathINIT XpathINIT
-" if ExtraVim() if ExtraVim()
-" ... " ...
-" ... " ...
-" endif endif
-" Xcheck <number> Xcheck <number>
-"
-" Double quotes in column 1 are removed before the script is executed.
-" They should be used if the test has unbalanced conditionals (:if/:endif,
-" :while:/endwhile, :try/:endtry) or for a line with a syntax error. The
-" extra script may use Xpath, XloopINIT, Xloop, XloopNEXT, and Xout as usual.
-"
-" A file name may be specified as argument. All messages of the extra Vim
-" process are then redirected to the file. An existing file is overwritten.
-"
-let ExtraVimCount = 0
-let ExtraVimBase = expand("<sfile>")
-let ExtraVimTestEnv = ""
-"
-function ExtraVim(...)
- " Count how often this function is called.
- let g:ExtraVimCount = g:ExtraVimCount + 1
-
- " Disable folds to prevent that the ranges in the ":write" commands below
- " are extended up to the end of a closed fold. This also speeds things up
- " considerably.
- set nofoldenable
-
- " Open a buffer for this test script and copy the test environment to
- " a temporary file. Take account of parts relevant for the extra script
- " execution only.
- let current_buffnr = bufnr("%")
- execute "view +1" g:ExtraVimBase
- if g:ExtraVimCount == 1
- let g:ExtraVimTestEnv = tempname()
- execute "/E" . "XTRA_VIM_START/+,/E" . "XTRA_VIM_STOP/-w"
- \ g:ExtraVimTestEnv "|']+"
- execute "/E" . "XTRA_VIM_START/+,/E" . "XTRA_VIM_STOP/-w >>"
- \ g:ExtraVimTestEnv "|']+"
- execute "/E" . "XTRA_VIM_START/+,/E" . "XTRA_VIM_STOP/-w >>"
- \ g:ExtraVimTestEnv "|']+"
- execute "/E" . "XTRA_VIM_START/+,/E" . "XTRA_VIM_STOP/-w >>"
- \ g:ExtraVimTestEnv "|']+"
- endif
-
- " Start the extra Vim script with a ":source" command for the test
- " environment. The source line number where the extra script will be
- " appended, needs to be passed as variable "ExtraVimBegin" to the script.
- let extra_script = tempname()
- exec "!echo 'source " . g:ExtraVimTestEnv . "' >" . extra_script
- let extra_begin = 1
-
- " Starting behind the test environment, skip over the first g:ExtraVimCount
- " occurrences of "if ExtraVim()" and copy the following lines up to the
- " matching "endif" to the extra Vim script.
- execute "/E" . "ND_OF_TEST_ENVIRONMENT/"
- exec 'norm ' . g:ExtraVimCount . '/^\s*if\s\+ExtraVim(.*)/+' . "\n"
- execute ".,/^endif/-write >>" . extra_script
-
- " Open a buffer for the extra Vim script, delete all ^", and write the
- " script if was actually modified.
- execute "edit +" . (extra_begin + 1) extra_script
- ,$s/^"//e
- update
-
- " Count the INTERRUPTs and build the breakpoint and quit commands.
- let breakpoints = ""
- let debug_quits = ""
- let in_func = 0
- exec extra_begin
- while search(
- \ '"\s*INTERRUPT\h\@!\|^\s*fu\%[nction]\>!\=\s*\%(\u\|s:\)\w*\s*(\|'
- \ . '^\s*\\\|^\s*endf\%[unction]\>\|'
- \ . '\%(^\s*fu\%[nction]!\=\s*\)\@<!\%(\u\|s:\)\w*\s*(\|'
- \ . 'ExecAsScript\s\+\%(\u\|s:\)\w*',
- \ "W") > 0
- let theline = getline(".")
- if theline =~ '^\s*fu'
- " Function definition.
- let in_func = 1
- let func_start = line(".")
- let func_name = substitute(theline,
- \ '^\s*fu\%[nction]!\=\s*\(\%(\u\|s:\)\w*\).*', '\1', "")
- elseif theline =~ '^\s*endf'
- " End of function definition.
- let in_func = 0
- else
- let finding = substitute(theline, '.*\(\%' . col(".") . 'c.*\)',
- \ '\1', "")
- if finding =~ '^"\s*INTERRUPT\h\@!'
- " Interrupt comment. Compose as many quit commands as
- " specified.
- let cnt = substitute(finding,
- \ '^"\s*INTERRUPT\s*\(\d*\).*$', '\1', "")
- let quits = ""
- while cnt > 0
- " Use "\r" rather than "\n" to separate the quit commands.
- " "\r" is not interpreted as command separator by the ":!"
- " command below but works to separate commands in the
- " external vim.
- let quits = quits . "q\r"
- let cnt = cnt - 1
- endwhile
- if in_func
- " Add the function breakpoint and note the number of quits
- " to be used, if specified, or one for every call else.
- let breakpoints = breakpoints . " -c 'breakadd func " .
- \ (line(".") - func_start) . " " .
- \ func_name . "'"
- if quits != ""
- let debug_quits = debug_quits . quits
- elseif !exists("quits{func_name}")
- let quits{func_name} = "q\r"
- else
- let quits{func_name} = quits{func_name} . "q\r"
- endif
- else
- " Add the file breakpoint and the quits to be used for it.
- let breakpoints = breakpoints . " -c 'breakadd file " .
- \ line(".") . " " . extra_script . "'"
- if quits == ""
- let quits = "q\r"
- endif
- let debug_quits = debug_quits . quits
- endif
- else
- " Add the quits to be used for calling the function or executing
- " it as script file.
- if finding =~ '^ExecAsScript'
- " Sourcing function as script.
- let finding = substitute(finding,
- \ '^ExecAsScript\s\+\(\%(\u\|s:\)\w*\).*', '\1', "")
- else
- " Function call.
- let finding = substitute(finding,
- \ '^\(\%(\u\|s:\)\w*\).*', '\1', "")
- endif
- if exists("quits{finding}")
- let debug_quits = debug_quits . quits{finding}
- endif
- endif
- endif
- endwhile
-
- " Close the buffer for the script and create an (empty) resultfile.
- bwipeout
- let resultfile = tempname()
- exec "!>" . resultfile
-
- " Run the script in an extra vim. Switch to extra modus by passing the
- " resultfile in ExtraVimResult. Redirect messages to the file specified as
- " argument if any. Use ":debuggreedy" so that the commands provided on the
- " pipe are consumed at the debug prompt. Use "-N" to enable command-line
- " continuation ("C" in 'cpo'). Add "nviminfo" to 'viminfo' to avoid
- " messing up the user's viminfo file.
- let redirect = a:0 ?
- \ " -c 'au VimLeave * redir END' -c 'redir\\! >" . a:1 . "'" : ""
- exec "!echo '" . debug_quits . "q' | " .. v:progpath .. " -u NONE -N -es" . redirect .
- \ " -c 'debuggreedy|set viminfo+=nviminfo'" .
- \ " -c 'let ExtraVimBegin = " . extra_begin . "'" .
- \ " -c 'let ExtraVimResult = \"" . resultfile . "\"'" . breakpoints .
- \ " -S " . extra_script
-
- " Build the resulting sum for resultfile and add it to g:Xpath. Add Xout
- " information provided by the extra Vim process to the test output.
- let sum = 0
- exec "edit" resultfile
- let line = 1
- while line <= line("$")
- let theline = getline(line)
- if theline =~ '^@R:'
- exec 'Xout "' . substitute(substitute(
- \ escape(escape(theline, '"'), '\"'),
- \ '^@R:', '', ""), '@NL@', "\n", "g") . '"'
- else
- let sum = sum + getline(line)
- endif
- let line = line + 1
- endwhile
- bwipeout
- let g:Xpath = g:Xpath + sum
-
- " Delete the extra script and the resultfile.
- call delete(extra_script)
- call delete(resultfile)
-
- " Switch back to the buffer that was active when this function was entered.
- exec "buffer" current_buffnr
-
- " Return 0. This protects extra scripts from being run in the main Vim
- " process.
- return 0
-endfunction
-
-
-" ExtraVimThrowpoint() - Relative throwpoint in ExtraVim script {{{2
-"
-" Evaluates v:throwpoint and returns the throwpoint relative to the beginning of
-" an ExtraVim script as passed by ExtraVim() in ExtraVimBegin.
-"
-" EXTRA_VIM_START - do not change or remove this line.
-function ExtraVimThrowpoint()
- if !exists("g:ExtraVimBegin")
- Xout "ExtraVimThrowpoint() used outside ExtraVim() script."
- return v:throwpoint
- endif
-
- if v:throwpoint =~ '^function\>'
- return v:throwpoint
- endif
-
- return "line " .
- \ (substitute(v:throwpoint, '.*, line ', '', "") - g:ExtraVimBegin) .
- \ " of ExtraVim() script"
-endfunction
-" EXTRA_VIM_STOP - do not change or remove this line.
-
-
-" MakeScript() - Make a script file from a function. {{{2
-"
-" Create a script that consists of the body of the function a:funcname.
-" Replace any ":return" by a ":finish", any argument variable by a global
-" variable, and every ":call" by a ":source" for the next following argument
-" in the variable argument list. This function is useful if similar tests are
-" to be made for a ":return" from a function call or a ":finish" in a script
-" file.
-"
-" In order to execute a function specifying an INTERRUPT location (see ExtraVim)
-" as a script file, use ExecAsScript below.
-"
-" EXTRA_VIM_START - do not change or remove this line.
-function MakeScript(funcname, ...)
- let script = tempname()
- execute "redir! >" . script
- execute "function" a:funcname
- redir END
- execute "edit" script
- " Delete the "function" and the "endfunction" lines. Do not include the
- " word "function" in the pattern since it might be translated if LANG is
- " set. When MakeScript() is being debugged, this deletes also the debugging
- " output of its line 3 and 4.
- exec '1,/.*' . a:funcname . '(.*)/d'
- /^\d*\s*endfunction\>/,$d
- %s/^\d*//e
- %s/return/finish/e
- %s/\<a:\(\h\w*\)/g:\1/ge
- normal gg0
- let cnt = 0
- while search('\<call\s*\%(\u\|s:\)\w*\s*(.*)', 'W') > 0
- let cnt = cnt + 1
- s/\<call\s*\%(\u\|s:\)\w*\s*(.*)/\='source ' . a:{cnt}/
- endwhile
- g/^\s*$/d
- write
- bwipeout
- return script
-endfunction
-" EXTRA_VIM_STOP - do not change or remove this line.
-
-
-" ExecAsScript - Source a temporary script made from a function. {{{2
-"
-" Make a temporary script file from the function a:funcname, ":source" it, and
-" delete it afterwards.
-"
-" When inside ":if ExtraVim()", add a file breakpoint for each INTERRUPT
-" location specified in the function.
-"
-" EXTRA_VIM_START - do not change or remove this line.
-function ExecAsScript(funcname)
- " Make a script from the function passed as argument.
- let script = MakeScript(a:funcname)
-
- " When running in an extra Vim process, add a file breakpoint for each
- " function breakpoint set when the extra Vim process was invoked by
- " ExtraVim().
- if exists("g:ExtraVimResult")
- let bplist = tempname()
- execute "redir! >" . bplist
- breaklist
- redir END
- execute "edit" bplist
- " Get the line number from the function breakpoint. Works also when
- " LANG is set.
- execute 'v/^\s*\d\+\s\+func\s\+' . a:funcname . '\s.*/d'
- %s/^\s*\d\+\s\+func\s\+\%(\u\|s:\)\w*\s\D*\(\d*\).*/\1/e
- let cnt = 0
- while cnt < line("$")
- let cnt = cnt + 1
- if getline(cnt) != ""
- execute "breakadd file" getline(cnt) script
- endif
- endwhile
- bwipeout!
- call delete(bplist)
- endif
-
- " Source and delete the script.
- exec "source" script
- call delete(script)
-endfunction
-
-com! -nargs=1 -bar ExecAsScript call ExecAsScript(<f-args>)
-" EXTRA_VIM_STOP - do not change or remove this line.
-
-
-" END_OF_TEST_ENVIRONMENT - do not change or remove this line.
-
-
-" Tests 1 to 17 were moved to test_vimscript.vim
-let Xtest = 18
-
-"-------------------------------------------------------------------------------
-" Test 18: Interrupt (Ctrl-C pressed) {{{1
-"
-" On an interrupt, the script processing is terminated immediately.
-"-------------------------------------------------------------------------------
-
-XpathINIT
-
-if ExtraVim()
- if 1
- Xpath 1 " X: 1
- while 1
- Xpath 2 " X: 2
- if 1
- Xpath 4 " X: 4
- "INTERRUPT
- Xpath 8 " X: 0
- break
- finish
- endif | Xpath 16 " X: 0
- Xpath 32 " X: 0
- endwhile | Xpath 64 " X: 0
- Xpath 128 " X: 0
- endif | Xpath 256 " X: 0
- Xpath 512 " X: 0
-endif
-
-if ExtraVim()
- try
- Xpath 1024 " X: 1024
- "INTERRUPT
- Xpath 2048 " X: 0
- endtry | Xpath 4096 " X: 0
- Xpath 8192 " X: 0
-endif
-
-if ExtraVim()
- function! F()
- if 1
- Xpath 16384 " X: 16384
- while 1
- Xpath 32768 " X: 32768
- if 1
- Xpath 65536 " X: 65536
- "INTERRUPT
- Xpath 131072 " X: 0
- break
- return
- endif | Xpath 262144 " X: 0
- Xpath Xpath 524288 " X: 0
- endwhile | Xpath 1048576 " X: 0
- Xpath Xpath 2097152 " X: 0
- endif | Xpath Xpath 4194304 " X: 0
- Xpath Xpath 8388608 " X: 0
- endfunction
-
- call F() | Xpath 16777216 " X: 0
- Xpath 33554432 " X: 0
-endif
-
-if ExtraVim()
- function! G()
- try
- Xpath 67108864 " X: 67108864
- "INTERRUPT
- Xpath 134217728 " X: 0
- endtry | Xpath 268435456 " X: 0
- Xpath 536870912 " X: 0
- endfunction
-
- call G() | Xpath 1073741824 " X: 0
- " The Xpath command does not accept 2^31 (negative); display explicitly:
- exec "!echo 2147483648 >>" . g:ExtraVimResult
- " X: 0
-endif
-
-Xcheck 67224583
-
-
-"-------------------------------------------------------------------------------
-" Test 19: Aborting on errors inside :try/:endtry {{{1
-"
-" An error in a command dynamically enclosed in a :try/:endtry region
-" aborts script processing immediately. It does not matter whether
-" the failing command is outside or inside a function and whether a
-" function has an "abort" attribute.
-"-------------------------------------------------------------------------------
-
-XpathINIT
-
-if ExtraVim()
- function! F() abort
- Xpath 1 " X: 1
- asdf
- Xpath 2 " X: 0
- endfunction
-
- try
- Xpath 4 " X: 4
- call F()
- Xpath 8 " X: 0
- endtry | Xpath 16 " X: 0
- Xpath 32 " X: 0
-endif
-
-if ExtraVim()
- function! G()
- Xpath 64 " X: 64
- asdf
- Xpath 128 " X: 0
- endfunction
-
- try
- Xpath 256 " X: 256
- call G()
- Xpath 512 " X: 0
- endtry | Xpath 1024 " X: 0
- Xpath 2048 " X: 0
-endif
-
-if ExtraVim()
- try
- Xpath 4096 " X: 4096
- asdf
- Xpath 8192 " X: 0
- endtry | Xpath 16384 " X: 0
- Xpath 32768 " X: 0
-endif
-
-if ExtraVim()
- if 1
- try
- Xpath 65536 " X: 65536
- asdf
- Xpath 131072 " X: 0
- endtry | Xpath 262144 " X: 0
- endif | Xpath 524288 " X: 0
- Xpath 1048576 " X: 0
-endif
-
-if ExtraVim()
- let p = 1
- while p
- let p = 0
- try
- Xpath 2097152 " X: 2097152
- asdf
- Xpath 4194304 " X: 0
- endtry | Xpath 8388608 " X: 0
- endwhile | Xpath 16777216 " X: 0
- Xpath 33554432 " X: 0
-endif
-
-if ExtraVim()
- let p = 1
- while p
- let p = 0
-" try
- Xpath 67108864 " X: 67108864
- endwhile | Xpath 134217728 " X: 0
- Xpath 268435456 " X: 0
-endif
-
-Xcheck 69275973
-"-------------------------------------------------------------------------------
-" Test 20: Aborting on errors after :try/:endtry {{{1
-"
-" When an error occurs after the last active :try/:endtry region has
-" been left, termination behavior is as if no :try/:endtry has been
-" seen.
-"-------------------------------------------------------------------------------
-
-XpathINIT
-
-if ExtraVim()
- let p = 1
- while p
- let p = 0
- try
- Xpath 1 " X: 1
- endtry
- asdf
- endwhile | Xpath 2 " X: 0
- Xpath 4 " X: 4
-endif
-
-if ExtraVim()
- while 1
- try
- Xpath 8 " X: 8
- break
- Xpath 16 " X: 0
- endtry
- endwhile
- Xpath 32 " X: 32
- asdf
- Xpath 64 " X: 64
-endif
-
-if ExtraVim()
- while 1
- try
- Xpath 128 " X: 128
- break
- Xpath 256 " X: 0
- finally
- Xpath 512 " X: 512
- endtry
- endwhile
- Xpath 1024 " X: 1024
- asdf
- Xpath 2048 " X: 2048
-endif
-
-if ExtraVim()
- while 1
- try
- Xpath 4096 " X: 4096
- finally
- Xpath 8192 " X: 8192
- break
- Xpath 16384 " X: 0
- endtry
- endwhile
- Xpath 32768 " X: 32768
- asdf
- Xpath 65536 " X: 65536
-endif
-
-if ExtraVim()
- let p = 1
- while p
- let p = 0
- try
- Xpath 131072 " X: 131072
- continue
- Xpath 262144 " X: 0
- endtry
- endwhile
- Xpath 524288 " X: 524288
- asdf
- Xpath 1048576 " X: 1048576
-endif
-
-if ExtraVim()
- let p = 1
- while p
- let p = 0
- try
- Xpath 2097152 " X: 2097152
- continue
- Xpath 4194304 " X: 0
- finally
- Xpath 8388608 " X: 8388608
- endtry
- endwhile
- Xpath 16777216 " X: 16777216
- asdf
- Xpath 33554432 " X: 33554432
-endif
-
-if ExtraVim()
- let p = 1
- while p
- let p = 0
- try
- Xpath 67108864 " X: 67108864
- finally
- Xpath 134217728 " X: 134217728
- continue
- Xpath 268435456 " X: 0
- endtry
- endwhile
- Xpath 536870912 " X: 536870912
- asdf
- Xpath 1073741824 " X: 1073741824
-endif
-
-Xcheck 1874575085
-
-
-"-------------------------------------------------------------------------------
-" Test 21: :finally for :try after :continue/:break/:return/:finish {{{1
-"
-" If a :try conditional stays inactive due to a preceding :continue,
-" :break, :return, or :finish, its :finally clause should not be
-" executed.
-"-------------------------------------------------------------------------------
-
-XpathINIT
-
-if ExtraVim()
- function F()
- let loops = 2
- XloopINIT! 1 256
- while loops > 0
- XloopNEXT
- let loops = loops - 1
- try
- if loops == 1
- Xloop 1 " X: 1
- continue
- Xloop 2 " X: 0
- elseif loops == 0
- Xloop 4 " X: 4*256
- break
- Xloop 8 " X: 0
- endif
-
- try " inactive
- Xloop 16 " X: 0
- finally
- Xloop 32 " X: 0
- endtry
- finally
- Xloop 64 " X: 64 + 64*256
- endtry
- Xloop 128 " X: 0
- endwhile
-
- try
- Xpath 65536 " X: 65536
- return
- Xpath 131072 " X: 0
- try " inactive
- Xpath 262144 " X: 0
- finally
- Xpath 524288 " X: 0
- endtry
- finally
- Xpath 1048576 " X: 1048576
- endtry
- Xpath 2097152 " X: 0
- endfunction
-
- try
- Xpath 4194304 " X: 4194304
- call F()
- Xpath 8388608 " X: 8388608
- finish
- Xpath 16777216 " X: 0
- try " inactive
- Xpath 33554432 " X: 0
- finally
- Xpath 67108864 " X: 0
- endtry
- finally
- Xpath 134217728 " X: 134217728
- endtry
- Xpath 268435456 " X: 0
-endif
-
-Xcheck 147932225
-
-
-"-------------------------------------------------------------------------------
-" Test 22: :finally for a :try after an error/interrupt/:throw {{{1
-"
-" If a :try conditional stays inactive due to a preceding error or
-" interrupt or :throw, its :finally clause should not be executed.
-"-------------------------------------------------------------------------------
-
-XpathINIT
-
-if ExtraVim()
- function! Error()
- try
- asdf " aborting error, triggering error exception
- endtry
- endfunction
-
- Xpath 1 " X: 1
- call Error()
- Xpath 2 " X: 0
-
- if 1 " not active due to error
- try " not active since :if inactive
- Xpath 4 " X: 0
- finally
- Xpath 8 " X: 0
- endtry
- endif
-
- try " not active due to error
- Xpath 16 " X: 0
- finally
- Xpath 32 " X: 0
- endtry
-endif
-
-if ExtraVim()
- function! Interrupt()
- try
- "INTERRUPT " triggering interrupt exception
- endtry
- endfunction
-
- Xpath 64 " X: 64
- call Interrupt()
- Xpath 128 " X: 0
-
- if 1 " not active due to interrupt
- try " not active since :if inactive
- Xpath 256 " X: 0
- finally
- Xpath 512 " X: 0
- endtry
- endif
-
- try " not active due to interrupt
- Xpath 1024 " X: 0
- finally
- Xpath 2048 " X: 0
- endtry
-endif
-
-if ExtraVim()
- function! Throw()
- throw "xyz"
- endfunction
-
- Xpath 4096 " X: 4096
- call Throw()
- Xpath 8192 " X: 0
-
- if 1 " not active due to :throw
- try " not active since :if inactive
- Xpath 16384 " X: 0
- finally
- Xpath 32768 " X: 0
- endtry
- endif
-
- try " not active due to :throw
- Xpath 65536 " X: 0
- finally
- Xpath 131072 " X: 0
- endtry
-endif
-
-Xcheck 4161
-
-
-"-------------------------------------------------------------------------------
-" Test 23: :catch clauses for a :try after a :throw {{{1
-"
-" If a :try conditional stays inactive due to a preceding :throw,
-" none of its :catch clauses should be executed.
-"-------------------------------------------------------------------------------
-
-XpathINIT
-
-if ExtraVim()
- try
- Xpath 1 " X: 1
- throw "xyz"
- Xpath 2 " X: 0
-
- if 1 " not active due to :throw
- try " not active since :if inactive
- Xpath 4 " X: 0
- catch /xyz/
- Xpath 8 " X: 0
- endtry
- endif
- catch /xyz/
- Xpath 16 " X: 16
- endtry
-
- Xpath 32 " X: 32
- throw "abc"
- Xpath 64 " X: 0
-
- try " not active due to :throw
- Xpath 128 " X: 0
- catch /abc/
- Xpath 256 " X: 0
- endtry
-endif
-
-Xcheck 49
-
-
-"-------------------------------------------------------------------------------
-" Test 24: :endtry for a :try after a :throw {{{1
-"
-" If a :try conditional stays inactive due to a preceding :throw,
-" its :endtry should not rethrow the exception to the next surrounding
-" active :try conditional.
-"-------------------------------------------------------------------------------
-
-XpathINIT
-
-if ExtraVim()
- try " try 1
- try " try 2
- Xpath 1 " X: 1
- throw "xyz" " makes try 2 inactive
- Xpath 2 " X: 0
-
- try " try 3
- Xpath 4 " X: 0
- endtry " no rethrow to try 1
- catch /xyz/ " should catch although try 2 inactive
- Xpath 8 " X: 8
- endtry
- catch /xyz/ " try 1 active, but exception already caught
- Xpath 16 " X: 0
- endtry
- Xpath 32 " X: 32
-endif
-
-Xcheck 41
-
-" Tests 25 and 26 were moved to test_trycatch.vim
-let Xtest = 27
-
-
-"-------------------------------------------------------------------------------
-" Test 27: Executing :finally clauses after :return {{{1
-"
-" For a :return command dynamically enclosed in a :try/:endtry region,
-" :finally clauses are executed and the called function is ended.
-"-------------------------------------------------------------------------------
-
-XpathINIT
-
-function! F()
- try
- Xpath 1 " X: 1
- try
- Xpath 2 " X: 2
- return
- Xpath 4 " X: 0
- finally
- Xpath 8 " X: 8
- endtry
- Xpath 16 " X: 0
- finally
- Xpath 32 " X: 32
- endtry
- Xpath 64 " X: 0
-endfunction
-
-function! G()
- try
- Xpath 128 " X: 128
- return
- Xpath 256 " X: 0
- finally
- Xpath 512 " X: 512
- call F()
- Xpath 1024 " X: 1024
- endtry
- Xpath 2048 " X: 0
-endfunction
-
-function! H()
- try
- Xpath 4096 " X: 4096
- call G()
- Xpath 8192 " X: 8192
- finally
- Xpath 16384 " X: 16384
- return
- Xpath 32768 " X: 0
- endtry
- Xpath 65536 " X: 0
-endfunction
-
-try
- Xpath 131072 " X: 131072
- call H()
- Xpath 262144 " X: 262144
-finally
- Xpath 524288 " X: 524288
-endtry
-Xpath 1048576 " X: 1048576
-
-Xcheck 1996459
-
-" Leave F, G, and H for execution as scripts in the next test.
-
-
-"-------------------------------------------------------------------------------
-" Test 28: Executing :finally clauses after :finish {{{1
-"
-" For a :finish command dynamically enclosed in a :try/:endtry region,
-" :finally clauses are executed and the sourced file is finished.
-"
-" This test executes the bodies of the functions F, G, and H from the
-" previous test as script files (:return replaced by :finish).
-"-------------------------------------------------------------------------------
-
-XpathINIT
-
-let scriptF = MakeScript("F") " X: 1 + 2 + 8 + 32
-let scriptG = MakeScript("G", scriptF) " X: 128 + 512 + 1024
-let scriptH = MakeScript("H", scriptG) " X: 4096 + 8192 + 16384
-
-try
- Xpath 131072 " X: 131072
- exec "source" scriptH
- Xpath 262144 " X: 262144
-finally
- Xpath 524288 " X: 524288
-endtry
-Xpath 1048576 " X: 1048576
-
-call delete(scriptF)
-call delete(scriptG)
-call delete(scriptH)
-unlet scriptF scriptG scriptH
-delfunction F
-delfunction G
-delfunction H
-
-Xcheck 1996459
-
-
-"-------------------------------------------------------------------------------
-" Test 29: Executing :finally clauses on errors {{{1
-"
-" After an error in a command dynamically enclosed in a :try/:endtry
-" region, :finally clauses are executed and the script processing is
-" terminated.
-"-------------------------------------------------------------------------------
-
-XpathINIT
-
-if ExtraVim()
- function! F()
- while 1
- try
- Xpath 1 " X: 1
- while 1
- try
- Xpath 2 " X: 2
- asdf " error
- Xpath 4 " X: 0
- finally
- Xpath 8 " X: 8
- endtry | Xpath 16 " X: 0
- Xpath 32 " X: 0
- break
- endwhile
- Xpath 64 " X: 0
- finally
- Xpath 128 " X: 128
- endtry | Xpath 256 " X: 0
- Xpath 512 " X: 0
- break
- endwhile
- Xpath 1024 " X: 0
- endfunction
-
- while 1
- try
- Xpath 2048 " X: 2048
- while 1
- call F()
- Xpath 4096 " X: 0
- break
- endwhile | Xpath 8192 " X: 0
- Xpath 16384 " X: 0
- finally
- Xpath 32768 " X: 32768
- endtry | Xpath 65536 " X: 0
- endwhile | Xpath 131072 " X: 0
- Xpath 262144 " X: 0
-endif
-
-if ExtraVim()
- function! G() abort
- if 1
- try
- Xpath 524288 " X: 524288
- asdf " error
- Xpath 1048576 " X: 0
- finally
- Xpath 2097152 " X: 2097152
- endtry | Xpath 4194304 " X: 0
- endif | Xpath 8388608 " X: 0
- Xpath 16777216 " X: 0
- endfunction
-
- if 1
- try
- Xpath 33554432 " X: 33554432
- call G()
- Xpath 67108864 " X: 0
- finally
- Xpath 134217728 " X: 134217728
- endtry | Xpath 268435456 " X: 0
- endif | Xpath 536870912 " X: 0
- Xpath 1073741824 " X: 0
-endif
-
-Xcheck 170428555
-
-
-"-------------------------------------------------------------------------------
-" Test 30: Executing :finally clauses on interrupt {{{1
-"
-" After an interrupt in a command dynamically enclosed in
-" a :try/:endtry region, :finally clauses are executed and the
-" script processing is terminated.
-"-------------------------------------------------------------------------------
-
-XpathINIT
-
-if ExtraVim()
- XloopINIT 1 16
-
- function! F()
- try
- Xloop 1 " X: 1 + 1*16
- "INTERRUPT
- Xloop 2 " X: 0
- finally
- Xloop 4 " X: 4 + 4*16
- endtry
- Xloop 8 " X: 0
- endfunction
-
- try
- Xpath 256 " X: 256
- try
- Xpath 512 " X: 512
- "INTERRUPT
- Xpath 1024 " X: 0
- finally
- Xpath 2048 " X: 2048
- try
- Xpath 4096 " X: 4096
- try
- Xpath 8192 " X: 8192
- finally
- Xpath 16384 " X: 16384
- try
- Xpath 32768 " X: 32768
- "INTERRUPT
- Xpath 65536 " X: 0
- endtry
- Xpath 131072 " X: 0
- endtry
- Xpath 262144 " X: 0
- endtry
- Xpath 524288 " X: 0
- endtry
- Xpath 1048576 " X: 0
- finally
- Xpath 2097152 " X: 2097152
- try
- Xpath 4194304 " X: 4194304
- call F()
- Xpath 8388608 " X: 0
- finally
- Xpath 16777216 " X: 16777216
- try
- Xpath 33554432 " X: 33554432
- XloopNEXT
- ExecAsScript F
- Xpath 67108864 " X: 0
- finally
- Xpath 134217728 " X: 134217728
- endtry
- Xpath 268435456 " X: 0
- endtry
- Xpath 536870912 " X: 0
- endtry
- Xpath 1073741824 " X: 0
-endif
-
-Xcheck 190905173
-
-
-"-------------------------------------------------------------------------------
-" Test 31: Executing :finally clauses after :throw {{{1
-"
-" After a :throw dynamically enclosed in a :try/:endtry region,
-" :finally clauses are executed and the script processing is
-" terminated.
-"-------------------------------------------------------------------------------
-
-XpathINIT
-
-if ExtraVim()
- XloopINIT 1 16
-
- function! F()
- try
- Xloop 1 " X: 1 + 1*16
- throw "exception"
- Xloop 2 " X: 0
- finally
- Xloop 4 " X: 4 + 4*16
- endtry
- Xloop 8 " X: 0
- endfunction
-
- try
- Xpath 256 " X: 256
- try
- Xpath 512 " X: 512
- throw "exception"
- Xpath 1024 " X: 0
- finally
- Xpath 2048 " X: 2048
- try
- Xpath 4096 " X: 4096
- try
- Xpath 8192 " X: 8192
- finally
- Xpath 16384 " X: 16384
- try
- Xpath 32768 " X: 32768
- throw "exception"
- Xpath 65536 " X: 0
- endtry
- Xpath 131072 " X: 0
- endtry
- Xpath 262144 " X: 0
- endtry
- Xpath 524288 " X: 0
- endtry
- Xpath 1048576 " X: 0
- finally
- Xpath 2097152 " X: 2097152
- try
- Xpath 4194304 " X: 4194304
- call F()
- Xpath 8388608 " X: 0
- finally
- Xpath 16777216 " X: 16777216
- try
- Xpath 33554432 " X: 33554432
- XloopNEXT
- ExecAsScript F
- Xpath 67108864 " X: 0
- finally
- Xpath 134217728 " X: 134217728
- endtry
- Xpath 268435456 " X: 0
- endtry
- Xpath 536870912 " X: 0
- endtry
- Xpath 1073741824 " X: 0
-endif
-
-Xcheck 190905173
-
-" Tests 32 and 33 were moved to test_trycatch.vim
-let Xtest = 34
-
-
-"-------------------------------------------------------------------------------
-" Test 34: :finally reason discarded by :continue {{{1
-"
-" When a :finally clause is executed due to a :continue, :break,
-" :return, :finish, error, interrupt or :throw, the jump reason is
-" discarded by a :continue in the finally clause.
-"-------------------------------------------------------------------------------
-
-XpathINIT
-
-if ExtraVim()
-
- XloopINIT! 1 8
-
- function! C(jump)
- XloopNEXT
- let loop = 0
- while loop < 2
- let loop = loop + 1
- if loop == 1
- try
- if a:jump == "continue"
- continue
- elseif a:jump == "break"
- break
- elseif a:jump == "return" || a:jump == "finish"
- return
- elseif a:jump == "error"
- asdf
- elseif a:jump == "interrupt"
- "INTERRUPT
- let dummy = 0
- elseif a:jump == "throw"
- throw "abc"
- endif
- finally
- continue " discards jump that caused the :finally
- Xloop 1 " X: 0
- endtry
- Xloop 2 " X: 0
- elseif loop == 2
- Xloop 4 " X: 4*(1+8+64+512+4096+32768+262144)
- endif
- endwhile
- endfunction
-
- call C("continue")
- Xpath 2097152 " X: 2097152
- call C("break")
- Xpath 4194304 " X: 4194304
- call C("return")
- Xpath 8388608 " X: 8388608
- let g:jump = "finish"
- ExecAsScript C
- unlet g:jump
- Xpath 16777216 " X: 16777216
- try
- call C("error")
- Xpath 33554432 " X: 33554432
- finally
- Xpath 67108864 " X: 67108864
- try
- call C("interrupt")
- Xpath 134217728 " X: 134217728
- finally
- Xpath 268435456 " X: 268435456
- call C("throw")
- Xpath 536870912 " X: 536870912
- endtry
- endtry
- Xpath 1073741824 " X: 1073741824
-
- delfunction C
-
-endif
-
-Xcheck 2146584868
-
-
-"-------------------------------------------------------------------------------
-" Test 35: :finally reason discarded by :break {{{1
-"
-" When a :finally clause is executed due to a :continue, :break,
-" :return, :finish, error, interrupt or :throw, the jump reason is
-" discarded by a :break in the finally clause.
-"-------------------------------------------------------------------------------
-
-XpathINIT
-
-if ExtraVim()
-
- XloopINIT! 1 8
-
- function! B(jump)
- XloopNEXT
- let loop = 0
- while loop < 2
- let loop = loop + 1
- if loop == 1
- try
- if a:jump == "continue"
- continue
- elseif a:jump == "break"
- break
- elseif a:jump == "return" || a:jump == "finish"
- return
- elseif a:jump == "error"
- asdf
- elseif a:jump == "interrupt"
- "INTERRUPT
- let dummy = 0
- elseif a:jump == "throw"
- throw "abc"
- endif
- finally
- break " discards jump that caused the :finally
- Xloop 1 " X: 0
- endtry
- elseif loop == 2
- Xloop 2 " X: 0
- endif
- endwhile
- Xloop 4 " X: 4*(1+8+64+512+4096+32768+262144)
- endfunction
-
- call B("continue")
- Xpath 2097152 " X: 2097152
- call B("break")
- Xpath 4194304 " X: 4194304
- call B("return")
- Xpath 8388608 " X: 8388608
- let g:jump = "finish"
- ExecAsScript B
- unlet g:jump
- Xpath 16777216 " X: 16777216
- try
- call B("error")
- Xpath 33554432 " X: 33554432
- finally
- Xpath 67108864 " X: 67108864
- try
- call B("interrupt")
- Xpath 134217728 " X: 134217728
- finally
- Xpath 268435456 " X: 268435456
- call B("throw")
- Xpath 536870912 " X: 536870912
- endtry
- endtry
- Xpath 1073741824 " X: 1073741824
-
- delfunction B
-
-endif
-
-Xcheck 2146584868
-
-
-"-------------------------------------------------------------------------------
-" Test 36: :finally reason discarded by :return {{{1
-"
-" When a :finally clause is executed due to a :continue, :break,
-" :return, :finish, error, interrupt or :throw, the jump reason is
-" discarded by a :return in the finally clause.
-"-------------------------------------------------------------------------------
-
-XpathINIT
-
-if ExtraVim()
-
- XloopINIT! 1 8
-
- function! R(jump, retval) abort
- XloopNEXT
- let loop = 0
- while loop < 2
- let loop = loop + 1
- if loop == 1
- try
- if a:jump == "continue"
- continue
- elseif a:jump == "break"
- break
- elseif a:jump == "return"
- return
- elseif a:jump == "error"
- asdf
- elseif a:jump == "interrupt"
- "INTERRUPT
- let dummy = 0
- elseif a:jump == "throw"
- throw "abc"
- endif
- finally
- return a:retval " discards jump that caused the :finally
- Xloop 1 " X: 0
- endtry
- elseif loop == 2
- Xloop 2 " X: 0
- endif
- endwhile
- Xloop 4 " X: 0
- endfunction
-
- let sum = -R("continue", -8)
- Xpath 2097152 " X: 2097152
- let sum = sum - R("break", -16)
- Xpath 4194304 " X: 4194304
- let sum = sum - R("return", -32)
- Xpath 8388608 " X: 8388608
- try
- let sum = sum - R("error", -64)
- Xpath 16777216 " X: 16777216
- finally
- Xpath 33554432 " X: 33554432
- try
- let sum = sum - R("interrupt", -128)
- Xpath 67108864 " X: 67108864
- finally
- Xpath 134217728 " X: 134217728
- let sum = sum - R("throw", -256)
- Xpath 268435456 " X: 268435456
- endtry
- endtry
- Xpath 536870912 " X: 536870912
-
- let expected = 8 + 16 + 32 + 64 + 128 + 256
- if sum != expected
- Xpath 1073741824 " X: 0
- Xout "sum =" . sum . ", expected: " . expected
- endif
-
- unlet sum expected
- delfunction R
-
-endif
-
-Xcheck 1071644672
-
-
-"-------------------------------------------------------------------------------
-" Test 37: :finally reason discarded by :finish {{{1
-"
-" When a :finally clause is executed due to a :continue, :break,
-" :return, :finish, error, interrupt or :throw, the jump reason is
-" discarded by a :finish in the finally clause.
-"-------------------------------------------------------------------------------
-
-XpathINIT
-
-if ExtraVim()
-
- XloopINIT! 1 8
-
- function! F(jump) " not executed as function, transformed to a script
- XloopNEXT
- let loop = 0
- while loop < 2
- let loop = loop + 1
- if loop == 1
- try
- if a:jump == "continue"
- continue
- elseif a:jump == "break"
- break
- elseif a:jump == "finish"
- finish
- elseif a:jump == "error"
- asdf
- elseif a:jump == "interrupt"
- "INTERRUPT
- let dummy = 0
- elseif a:jump == "throw"
- throw "abc"
- endif
- finally
- finish " discards jump that caused the :finally
- Xloop 1 " X: 0
- endtry
- elseif loop == 2
- Xloop 2 " X: 0
- endif
- endwhile
- Xloop 4 " X: 0
- endfunction
-
- let scriptF = MakeScript("F")
- delfunction F
-
- let g:jump = "continue"
- exec "source" scriptF
- Xpath 2097152 " X: 2097152
- let g:jump = "break"
- exec "source" scriptF
- Xpath 4194304 " X: 4194304
- let g:jump = "finish"
- exec "source" scriptF
- Xpath 8388608 " X: 8388608
- try
- let g:jump = "error"
- exec "source" scriptF
- Xpath 16777216 " X: 16777216
- finally
- Xpath 33554432 " X: 33554432
- try
- let g:jump = "interrupt"
- exec "source" scriptF
- Xpath 67108864 " X: 67108864
- finally
- Xpath 134217728 " X: 134217728
- try
- let g:jump = "throw"
- exec "source" scriptF
- Xpath 268435456 " X: 268435456
- finally
- Xpath 536870912 " X: 536870912
- endtry
- endtry
- endtry
- unlet g:jump
-
- call delete(scriptF)
- unlet scriptF
-
-endif
-
-Xcheck 1071644672
-
-
-"-------------------------------------------------------------------------------
-" Test 38: :finally reason discarded by an error {{{1
-"
-" When a :finally clause is executed due to a :continue, :break,
-" :return, :finish, error, interrupt or :throw, the jump reason is
-" discarded by an error in the finally clause.
-"-------------------------------------------------------------------------------
-
-XpathINIT
-
-if ExtraVim()
-
- XloopINIT! 1 4
-
- function! E(jump)
- XloopNEXT
- let loop = 0
- while loop < 2
- let loop = loop + 1
- if loop == 1
- try
- if a:jump == "continue"
- continue
- elseif a:jump == "break"
- break
- elseif a:jump == "return" || a:jump == "finish"
- return
- elseif a:jump == "error"
- asdf
- elseif a:jump == "interrupt"
- "INTERRUPT
- let dummy = 0
- elseif a:jump == "throw"
- throw "abc"
- endif
- finally
- asdf " error; discards jump that caused the :finally
- endtry
- elseif loop == 2
- Xloop 1 " X: 0
- endif
- endwhile
- Xloop 2 " X: 0
- endfunction
-
- try
- Xpath 16384 " X: 16384
- call E("continue")
- Xpath 32768 " X: 0
- finally
- try
- Xpath 65536 " X: 65536
- call E("break")
- Xpath 131072 " X: 0
- finally
- try
- Xpath 262144 " X: 262144
- call E("return")
- Xpath 524288 " X: 0
- finally
- try
- Xpath 1048576 " X: 1048576
- let g:jump = "finish"
- ExecAsScript E
- Xpath 2097152 " X: 0
- finally
- unlet g:jump
- try
- Xpath 4194304 " X: 4194304
- call E("error")
- Xpath 8388608 " X: 0
- finally
- try
- Xpath 16777216 " X: 16777216
- call E("interrupt")
- Xpath 33554432 " X: 0
- finally
- try
- Xpath 67108864 " X: 67108864
- call E("throw")
- Xpath 134217728 " X: 0
- finally
- Xpath 268435456 " X: 268435456
- delfunction E
- endtry
- endtry
- endtry
- endtry
- endtry
- endtry
- endtry
- Xpath 536870912 " X: 0
-
-endif
-
-Xcheck 357908480
-
-
-"-------------------------------------------------------------------------------
-" Test 39: :finally reason discarded by an interrupt {{{1
-"
-" When a :finally clause is executed due to a :continue, :break,
-" :return, :finish, error, interrupt or :throw, the jump reason is
-" discarded by an interrupt in the finally clause.
-"-------------------------------------------------------------------------------
-
-XpathINIT
-
-if ExtraVim()
-
- XloopINIT! 1 4
-
- function! I(jump)
- XloopNEXT
- let loop = 0
- while loop < 2
- let loop = loop + 1
- if loop == 1
- try
- if a:jump == "continue"
- continue
- elseif a:jump == "break"
- break
- elseif a:jump == "return" || a:jump == "finish"
- return
- elseif a:jump == "error"
- asdf
- elseif a:jump == "interrupt"
- "INTERRUPT
- let dummy = 0
- elseif a:jump == "throw"
- throw "abc"
- endif
- finally
- "INTERRUPT - discards jump that caused the :finally
- let dummy = 0
- endtry
- elseif loop == 2
- Xloop 1 " X: 0
- endif
- endwhile
- Xloop 2 " X: 0
- endfunction
-
- try
- Xpath 16384 " X: 16384
- call I("continue")
- Xpath 32768 " X: 0
- finally
- try
- Xpath 65536 " X: 65536
- call I("break")
- Xpath 131072 " X: 0
- finally
- try
- Xpath 262144 " X: 262144
- call I("return")
- Xpath 524288 " X: 0
- finally
- try
- Xpath 1048576 " X: 1048576
- let g:jump = "finish"
- ExecAsScript I
- Xpath 2097152 " X: 0
- finally
- unlet g:jump
- try
- Xpath 4194304 " X: 4194304
- call I("error")
- Xpath 8388608 " X: 0
- finally
- try
- Xpath 16777216 " X: 16777216
- call I("interrupt")
- Xpath 33554432 " X: 0
- finally
- try
- Xpath 67108864 " X: 67108864
- call I("throw")
- Xpath 134217728 " X: 0
- finally
- Xpath 268435456 " X: 268435456
- delfunction I
- endtry
- endtry
- endtry
- endtry
- endtry
- endtry
- endtry
- Xpath 536870912 " X: 0
-
-endif
-
-Xcheck 357908480
-
-
-"-------------------------------------------------------------------------------
-" Test 40: :finally reason discarded by :throw {{{1
-"
-" When a :finally clause is executed due to a :continue, :break,
-" :return, :finish, error, interrupt or :throw, the jump reason is
-" discarded by a :throw in the finally clause.
-"-------------------------------------------------------------------------------
-
-XpathINIT
-
-if ExtraVim()
-
- XloopINIT! 1 4
-
- function! T(jump)
- XloopNEXT
- let loop = 0
- while loop < 2
- let loop = loop + 1
- if loop == 1
- try
- if a:jump == "continue"
- continue
- elseif a:jump == "break"
- break
- elseif a:jump == "return" || a:jump == "finish"
- return
- elseif a:jump == "error"
- asdf
- elseif a:jump == "interrupt"
- "INTERRUPT
- let dummy = 0
- elseif a:jump == "throw"
- throw "abc"
- endif
- finally
- throw "xyz" " discards jump that caused the :finally
- endtry
- elseif loop == 2
- Xloop 1 " X: 0
- endif
- endwhile
- Xloop 2 " X: 0
- endfunction
-
- try
- Xpath 16384 " X: 16384
- call T("continue")
- Xpath 32768 " X: 0
- finally
- try
- Xpath 65536 " X: 65536
- call T("break")
- Xpath 131072 " X: 0
- finally
- try
- Xpath 262144 " X: 262144
- call T("return")
- Xpath 524288 " X: 0
- finally
- try
- Xpath 1048576 " X: 1048576
- let g:jump = "finish"
- ExecAsScript T
- Xpath 2097152 " X: 0
- finally
- unlet g:jump
- try
- Xpath 4194304 " X: 4194304
- call T("error")
- Xpath 8388608 " X: 0
- finally
- try
- Xpath 16777216 " X: 16777216
- call T("interrupt")
- Xpath 33554432 " X: 0
- finally
- try
- Xpath 67108864 " X: 67108864
- call T("throw")
- Xpath 134217728 " X: 0
- finally
- Xpath 268435456 " X: 268435456
- delfunction T
- endtry
- endtry
- endtry
- endtry
- endtry
- endtry
- endtry
- Xpath 536870912 " X: 0
-
-endif
-
-Xcheck 357908480
-
-" Tests 41 to 48 were moved to test_trycatch.vim
-let Xtest = 49
-
-
-"-------------------------------------------------------------------------------
-" Test 49: Throwing exceptions across functions {{{1
-"
-" When an exception is thrown but not caught inside a function, the
-" caller is checked for a matching :catch clause.
-"-------------------------------------------------------------------------------
-
-XpathINIT
-
-function! C()
- try
- Xpath 1 " X: 1
- throw "arrgh"
- Xpath 2 " X: 0
- catch /arrgh/
- Xpath 4 " X: 4
- endtry
- Xpath 8 " X: 8
-endfunction
-
-XloopINIT! 16 16
-
-function! T1()
- XloopNEXT
- try
- Xloop 1 " X: 16 + 16*16
- throw "arrgh"
- Xloop 2 " X: 0
- finally
- Xloop 4 " X: 64 + 64*16
- endtry
- Xloop 8 " X: 0
-endfunction
-
-function! T2()
- try
- Xpath 4096 " X: 4096
- call T1()
- Xpath 8192 " X: 0
- finally
- Xpath 16384 " X: 16384
- endtry
- Xpath 32768 " X: 0
-endfunction
-
-try
- Xpath 65536 " X: 65536
- call C() " throw and catch
- Xpath 131072 " X: 131072
-catch /.*/
- Xpath 262144 " X: 0
- Xout v:exception "in" v:throwpoint
-endtry
-
-try
- Xpath 524288 " X: 524288
- call T1() " throw, one level
- Xpath 1048576 " X: 0
-catch /arrgh/
- Xpath 2097152 " X: 2097152
-catch /.*/
- Xpath 4194304 " X: 0
- Xout v:exception "in" v:throwpoint
-endtry
-
-try
- Xpath 8388608 " X: 8388608
- call T2() " throw, two levels
- Xpath 16777216 " X: 0
-catch /arrgh/
- Xpath 33554432 " X: 33554432
-catch /.*/
- Xpath 67108864 " X: 0
- Xout v:exception "in" v:throwpoint
-endtry
-Xpath 134217728 " X: 134217728
-
-Xcheck 179000669
-
-" Leave C, T1, and T2 for execution as scripts in the next test.
-
-
-"-------------------------------------------------------------------------------
-" Test 50: Throwing exceptions across script files {{{1
-"
-" When an exception is thrown but not caught inside a script file,
-" the sourcing script or function is checked for a matching :catch
-" clause.
-"
-" This test executes the bodies of the functions C, T1, and T2 from
-" the previous test as script files (:return replaced by :finish).
-"-------------------------------------------------------------------------------
-
-XpathINIT
-
-let scriptC = MakeScript("C") " X: 1 + 4 + 8
-delfunction C
-
-XloopINIT! 16 16
-
-let scriptT1 = MakeScript("T1") " X: 16 + 64 + 16*16 + 64*16
-delfunction T1
-
-let scriptT2 = MakeScript("T2", scriptT1) " X: 4096 + 16384
-delfunction T2
-
-function! F()
- try
- Xpath 65536 " X: 65536
- exec "source" g:scriptC
- Xpath 131072 " X: 131072
- catch /.*/
- Xpath 262144 " X: 0
- Xout v:exception "in" v:throwpoint
- endtry
-
- try
- Xpath 524288 " X: 524288
- exec "source" g:scriptT1
- Xpath 1048576 " X: 0
- catch /arrgh/
- Xpath 2097152 " X: 2097152
- catch /.*/
- Xpath 4194304 " X: 0
- Xout v:exception "in" v:throwpoint
- endtry
-endfunction
-
-try
- Xpath 8388608 " X: 8388608
- call F()
- Xpath 16777216 " X: 16777216
- exec "source" scriptT2
- Xpath 33554432 " X: 0
-catch /arrgh/
- Xpath 67108864 " X: 67108864
-catch /.*/
- Xpath 134217728 " X: 0
- Xout v:exception "in" v:throwpoint
-endtry
-Xpath 268435456 " X: 268435456
-
-call delete(scriptC)
-call delete(scriptT1)
-call delete(scriptT2)
-unlet scriptC scriptT1 scriptT2
-delfunction F
-
-Xcheck 363550045
-
-" Test 51 was moved to test_trycatch.vim
-let Xtest = 52
-
-
-"-------------------------------------------------------------------------------
-" Test 52: Uncaught exceptions {{{1
-"
-" When an exception is thrown but not caught, an error message is
-" displayed when the script is terminated. In case of an interrupt
-" or error exception, the normal interrupt or error message(s) are
-" displayed.
-"-------------------------------------------------------------------------------
-
-XpathINIT
-
-let msgfile = tempname()
-
-function! MESSAGES(...)
- try
- exec "edit" g:msgfile
- catch /^Vim(edit):/
- return 0
- endtry
-
- let english = v:lang == "C" || v:lang =~ '^[Ee]n'
- let match = 1
- norm gg
-
- let num = a:0 / 2
- let cnt = 1
- while cnt <= num
- let enr = a:{2*cnt - 1}
- let emsg= a:{2*cnt}
- let cnt = cnt + 1
-
- if enr == ""
- Xout "TODO: Add message number for:" emsg
- elseif enr == "INT"
- let enr = ""
- endif
- if enr == "" && !english
- continue
- endif
- let pattern = (enr != "") ? enr . ':.*' : ''
- if english
- let pattern = pattern . emsg
- endif
- if !search(pattern, "W")
- let match = 0
- Xout "No match for:" pattern
- endif
- norm $
- endwhile
-
- bwipeout!
- return match
-endfunction
-
-if ExtraVim(msgfile)
- Xpath 1 " X: 1
- throw "arrgh"
-endif
-
-Xpath 2 " X: 2
-if !MESSAGES('E605', "Exception not caught")
- Xpath 4 " X: 0
-endif
-
-if ExtraVim(msgfile)
- try
- Xpath 8 " X: 8
- throw "oops"
- catch /arrgh/
- Xpath 16 " X: 0
- endtry
- Xpath 32 " X: 0
-endif
-
-Xpath 64 " X: 64
-if !MESSAGES('E605', "Exception not caught")
- Xpath 128 " X: 0
-endif
-
-if ExtraVim(msgfile)
- function! T()
- throw "brrr"
- endfunction
-
- try
- Xpath 256 " X: 256
- throw "arrgh"
- catch /.*/
- Xpath 512 " X: 512
- call T()
- endtry
- Xpath 1024 " X: 0
-endif
-
-Xpath 2048 " X: 2048
-if !MESSAGES('E605', "Exception not caught")
- Xpath 4096 " X: 0
-endif
-
-if ExtraVim(msgfile)
- try
- Xpath 8192 " X: 8192
- throw "arrgh"
- finally
- Xpath 16384 " X: 16384
- throw "brrr"
- endtry
- Xpath 32768 " X: 0
-endif
-
-Xpath 65536 " X: 65536
-if !MESSAGES('E605', "Exception not caught")
- Xpath 131072 " X: 0
-endif
-
-if ExtraVim(msgfile)
- try
- Xpath 262144 " X: 262144
- "INTERRUPT
- endtry
- Xpath 524288 " X: 0
-endif
-
-Xpath 1048576 " X: 1048576
-if !MESSAGES('INT', "Interrupted")
- Xpath 2097152 " X: 0
-endif
-
-if ExtraVim(msgfile)
- try
- Xpath 4194304 " X: 4194304
- let x = novar " error E121/E15; exception: E121
- catch /E15:/ " should not catch
- Xpath 8388608 " X: 0
- endtry
- Xpath 16777216 " X: 0
-endif
-
-Xpath 33554432 " X: 33554432
-if !MESSAGES('E121', "Undefined variable", 'E15', "Invalid expression")
- Xpath 67108864 " X: 0
-endif
-
-if ExtraVim(msgfile)
- try
- Xpath 134217728 " X: 134217728
-" unlet novar # " error E108/E488; exception: E488
- catch /E108:/ " should not catch
- Xpath 268435456 " X: 0
- endtry
- Xpath 536870912 " X: 0
-endif
-
-Xpath 1073741824 " X: 1073741824
-if !MESSAGES('E108', "No such variable", 'E488', "Trailing characters")
- " The Xpath command does not accept 2^31 (negative); add explicitly:
- let Xpath = Xpath + 2147483648 " X: 0
-endif
-
-call delete(msgfile)
-unlet msgfile
-
-Xcheck 1247112011
-
-" Leave MESSAGES() for the next tests.
-
-
-"-------------------------------------------------------------------------------
-" Test 53: Nesting errors: :endif/:else/:elseif {{{1
-"
-" For nesting errors of :if conditionals the correct error messages
-" should be given.
-"
-" This test reuses the function MESSAGES() from the previous test.
-" This functions checks the messages in g:msgfile.
-"-------------------------------------------------------------------------------
-
-XpathINIT
-
-let msgfile = tempname()
-
-if ExtraVim(msgfile)
-" endif
-endif
-if MESSAGES('E580', ":endif without :if")
- Xpath 1 " X: 1
-endif
-
-if ExtraVim(msgfile)
-" while 1
-" endif
-" endwhile
-endif
-if MESSAGES('E580', ":endif without :if")
- Xpath 2 " X: 2
-endif
-
-if ExtraVim(msgfile)
-" try
-" finally
-" endif
-" endtry
-endif
-if MESSAGES('E580', ":endif without :if")
- Xpath 4 " X: 4
-endif
-
-if ExtraVim(msgfile)
-" try
-" endif
-" endtry
-endif
-if MESSAGES('E580', ":endif without :if")
- Xpath 8 " X: 8
-endif
-
-if ExtraVim(msgfile)
-" try
-" throw "a"
-" catch /a/
-" endif
-" endtry
-endif
-if MESSAGES('E580', ":endif without :if")
- Xpath 16 " X: 16
-endif
-
-if ExtraVim(msgfile)
-" else
-endif
-if MESSAGES('E581', ":else without :if")
- Xpath 32 " X: 32
-endif
-
-if ExtraVim(msgfile)
-" while 1
-" else
-" endwhile
-endif
-if MESSAGES('E581', ":else without :if")
- Xpath 64 " X: 64
-endif
-
-if ExtraVim(msgfile)
-" try
-" finally
-" else
-" endtry
-endif
-if MESSAGES('E581', ":else without :if")
- Xpath 128 " X: 128
-endif
-
-if ExtraVim(msgfile)
-" try
-" else
-" endtry
-endif
-if MESSAGES('E581', ":else without :if")
- Xpath 256 " X: 256
-endif
-
-if ExtraVim(msgfile)
-" try
-" throw "a"
-" catch /a/
-" else
-" endtry
-endif
-if MESSAGES('E581', ":else without :if")
- Xpath 512 " X: 512
-endif
-
-if ExtraVim(msgfile)
-" elseif
-endif
-if MESSAGES('E582', ":elseif without :if")
- Xpath 1024 " X: 1024
-endif
-
-if ExtraVim(msgfile)
-" while 1
-" elseif
-" endwhile
-endif
-if MESSAGES('E582', ":elseif without :if")
- Xpath 2048 " X: 2048
-endif
-
-if ExtraVim(msgfile)
-" try
-" finally
-" elseif
-" endtry
-endif
-if MESSAGES('E582', ":elseif without :if")
- Xpath 4096 " X: 4096
-endif
-
-if ExtraVim(msgfile)
-" try
-" elseif
-" endtry
-endif
-if MESSAGES('E582', ":elseif without :if")
- Xpath 8192 " X: 8192
-endif
-
-if ExtraVim(msgfile)
-" try
-" throw "a"
-" catch /a/
-" elseif
-" endtry
-endif
-if MESSAGES('E582', ":elseif without :if")
- Xpath 16384 " X: 16384
-endif
-
-if ExtraVim(msgfile)
-" if 1
-" else
-" else
-" endif
-endif
-if MESSAGES('E583', "multiple :else")
- Xpath 32768 " X: 32768
-endif
-
-if ExtraVim(msgfile)
-" if 1
-" else
-" elseif 1
-" endif
-endif
-if MESSAGES('E584', ":elseif after :else")
- Xpath 65536 " X: 65536
-endif
-
-call delete(msgfile)
-unlet msgfile
-
-Xcheck 131071
-
-" Leave MESSAGES() for the next test.
-
-
-"-------------------------------------------------------------------------------
-" Test 54: Nesting errors: :while/:endwhile {{{1
-"
-" For nesting errors of :while conditionals the correct error messages
-" should be given.
-"
-" This test reuses the function MESSAGES() from the previous test.
-" This functions checks the messages in g:msgfile.
-"-------------------------------------------------------------------------------
-
-XpathINIT
-
-let msgfile = tempname()
-
-if ExtraVim(msgfile)
-" endwhile
-endif
-if MESSAGES('E588', ":endwhile without :while")
- Xpath 1 " X: 1
-endif
-
-if ExtraVim(msgfile)
-" if 1
-" endwhile
-" endif
-endif
-if MESSAGES('E588', ":endwhile without :while")
- Xpath 2 " X: 2
-endif
-
-if ExtraVim(msgfile)
-" while 1
-" if 1
-" endwhile
-endif
-if MESSAGES('E171', "Missing :endif")
- Xpath 4 " X: 4
-endif
-
-if ExtraVim(msgfile)
-" try
-" finally
-" endwhile
-" endtry
-endif
-if MESSAGES('E588', ":endwhile without :while")
- Xpath 8 " X: 8
-endif
-
-if ExtraVim(msgfile)
-" while 1
-" try
-" finally
-" endwhile
-endif
-if MESSAGES('E600', "Missing :endtry")
- Xpath 16 " X: 16
-endif
-
-if ExtraVim(msgfile)
-" while 1
-" if 1
-" try
-" finally
-" endwhile
-endif
-if MESSAGES('E600', "Missing :endtry")
- Xpath 32 " X: 32
-endif
-
-if ExtraVim(msgfile)
-" while 1
-" try
-" finally
-" if 1
-" endwhile
-endif
-if MESSAGES('E171', "Missing :endif")
- Xpath 64 " X: 64
-endif
-
-if ExtraVim(msgfile)
-" try
-" endwhile
-" endtry
-endif
-if MESSAGES('E588', ":endwhile without :while")
- Xpath 128 " X: 128
-endif
-
-if ExtraVim(msgfile)
-" while 1
-" try
-" endwhile
-" endtry
-" endwhile
-endif
-if MESSAGES('E588', ":endwhile without :while")
- Xpath 256 " X: 256
-endif
-
-if ExtraVim(msgfile)
-" try
-" throw "a"
-" catch /a/
-" endwhile
-" endtry
-endif
-if MESSAGES('E588', ":endwhile without :while")
- Xpath 512 " X: 512
-endif
-
-if ExtraVim(msgfile)
-" while 1
-" try
-" throw "a"
-" catch /a/
-" endwhile
-" endtry
-" endwhile
-endif
-if MESSAGES('E588', ":endwhile without :while")
- Xpath 1024 " X: 1024
-endif
-
-
-call delete(msgfile)
-unlet msgfile
-
-Xcheck 2047
-
-" Leave MESSAGES() for the next test.
-
-
-"-------------------------------------------------------------------------------
-" Test 55: Nesting errors: :continue/:break {{{1
-"
-" For nesting errors of :continue and :break commands the correct
-" error messages should be given.
-"
-" This test reuses the function MESSAGES() from the previous test.
-" This functions checks the messages in g:msgfile.
-"-------------------------------------------------------------------------------
-
-XpathINIT
-
-let msgfile = tempname()
-
-if ExtraVim(msgfile)
-" continue
-endif
-if MESSAGES('E586', ":continue without :while")
- Xpath 1 " X: 1
-endif
-
-if ExtraVim(msgfile)
-" if 1
-" continue
-" endif
-endif
-if MESSAGES('E586', ":continue without :while")
- Xpath 2 " X: 2
-endif
-
-if ExtraVim(msgfile)
-" try
-" finally
-" continue
-" endtry
-endif
-if MESSAGES('E586', ":continue without :while")
- Xpath 4 " X: 4
-endif
-
-if ExtraVim(msgfile)
-" try
-" continue
-" endtry
-endif
-if MESSAGES('E586', ":continue without :while")
- Xpath 8 " X: 8
-endif
-
-if ExtraVim(msgfile)
-" try
-" throw "a"
-" catch /a/
-" continue
-" endtry
-endif
-if MESSAGES('E586', ":continue without :while")
- Xpath 16 " X: 16
-endif
-
-if ExtraVim(msgfile)
-" break
-endif
-if MESSAGES('E587', ":break without :while")
- Xpath 32 " X: 32
-endif
-
-if ExtraVim(msgfile)
-" if 1
-" break
-" endif
-endif
-if MESSAGES('E587', ":break without :while")
- Xpath 64 " X: 64
-endif
-
-if ExtraVim(msgfile)
-" try
-" finally
-" break
-" endtry
-endif
-if MESSAGES('E587', ":break without :while")
- Xpath 128 " X: 128
-endif
-
-if ExtraVim(msgfile)
-" try
-" break
-" endtry
-endif
-if MESSAGES('E587', ":break without :while")
- Xpath 256 " X: 256
-endif
-
-if ExtraVim(msgfile)
-" try
-" throw "a"
-" catch /a/
-" break
-" endtry
-endif
-if MESSAGES('E587', ":break without :while")
- Xpath 512 " X: 512
-endif
-
-call delete(msgfile)
-unlet msgfile
-
-Xcheck 1023
-
-" Leave MESSAGES() for the next test.
-
-
-"-------------------------------------------------------------------------------
-" Test 56: Nesting errors: :endtry {{{1
-"
-" For nesting errors of :try conditionals the correct error messages
-" should be given.
-"
-" This test reuses the function MESSAGES() from the previous test.
-" This functions checks the messages in g:msgfile.
-"-------------------------------------------------------------------------------
-
-XpathINIT
-
-let msgfile = tempname()
-
-if ExtraVim(msgfile)
-" endtry
-endif
-if MESSAGES('E602', ":endtry without :try")
- Xpath 1 " X: 1
-endif
-
-if ExtraVim(msgfile)
-" if 1
-" endtry
-" endif
-endif
-if MESSAGES('E602', ":endtry without :try")
- Xpath 2 " X: 2
-endif
-
-if ExtraVim(msgfile)
-" while 1
-" endtry
-" endwhile
-endif
-if MESSAGES('E602', ":endtry without :try")
- Xpath 4 " X: 4
-endif
-
-if ExtraVim(msgfile)
-" try
-" if 1
-" endtry
-endif
-if MESSAGES('E171', "Missing :endif")
- Xpath 8 " X: 8
-endif
-
-if ExtraVim(msgfile)
-" try
-" while 1
-" endtry
-endif
-if MESSAGES('E170', "Missing :endwhile")
- Xpath 16 " X: 16
-endif
-
-if ExtraVim(msgfile)
-" try
-" finally
-" if 1
-" endtry
-endif
-if MESSAGES('E171', "Missing :endif")
- Xpath 32 " X: 32
-endif
-
-if ExtraVim(msgfile)
-" try
-" finally
-" while 1
-" endtry
-endif
-if MESSAGES('E170', "Missing :endwhile")
- Xpath 64 " X: 64
-endif
-
-if ExtraVim(msgfile)
- try
- Xpath 4194304 " X: 4194304
- let x = novar " error E121; exception: E121
- catch /E15:/ " should not catch
- Xpath 8388608 " X: 0
- endtry
- Xpath 16777216 " X: 0
-endif
-
-Xpath 33554432 " X: 33554432
-if !MESSAGES('E121', "Undefined variable")
- Xpath 67108864 " X: 0
-endif
-
-if ExtraVim(msgfile)
-" try
-" throw "a"
-" catch /a/
-" while 1
-" endtry
-endif
-if MESSAGES('E170', "Missing :endwhile")
- Xpath 256 " X: 256
-endif
-
-call delete(msgfile)
-unlet msgfile
-
-delfunction MESSAGES
-
-Xcheck 511
-
-
-"-------------------------------------------------------------------------------
-" Test 57: v:exception and v:throwpoint for user exceptions {{{1
-"
-" v:exception evaluates to the value of the exception that was caught
-" most recently and is not finished. (A caught exception is finished
-" when the next ":catch", ":finally", or ":endtry" is reached.)
-" v:throwpoint evaluates to the script/function name and line number
-" where that exception has been thrown.
-"-------------------------------------------------------------------------------
-
-XpathINIT
-
-function! FuncException()
- let g:exception = v:exception
-endfunction
-
-function! FuncThrowpoint()
- let g:throwpoint = v:throwpoint
-endfunction
-
-let scriptException = MakeScript("FuncException")
-let scriptThrowPoint = MakeScript("FuncThrowpoint")
-
-command! CmdException let g:exception = v:exception
-command! CmdThrowpoint let g:throwpoint = v:throwpoint
-
-XloopINIT! 1 2
-
-function! CHECK(n, exception, throwname, throwline)
- XloopNEXT
- let error = 0
- if v:exception != a:exception
- Xout a:n.": v:exception is" v:exception "instead of" a:exception
- let error = 1
- endif
- if v:throwpoint !~ a:throwname
- let name = escape(a:throwname, '\')
- Xout a:n.": v:throwpoint (".v:throwpoint.") does not match" name
- let error = 1
- endif
- if v:throwpoint !~ a:throwline
- let line = escape(a:throwline, '\')
- Xout a:n.": v:throwpoint (".v:throwpoint.") does not match" line
- let error = 1
- endif
- if error
- Xloop 1 " X: 0
- endif
-endfunction
-
-function! T(arg, line)
- if a:line == 2
- throw a:arg " in line 2
- elseif a:line == 4
- throw a:arg " in line 4
- elseif a:line == 6
- throw a:arg " in line 6
- elseif a:line == 8
- throw a:arg " in line 8
- endif
-endfunction
-
-function! G(arg, line)
- call T(a:arg, a:line)
-endfunction
-
-function! F(arg, line)
- call G(a:arg, a:line)
-endfunction
-
-let scriptT = MakeScript("T")
-let scriptG = MakeScript("G", scriptT)
-let scriptF = MakeScript("F", scriptG)
-
-try
- Xpath 32768 " X: 32768
- call F("oops", 2)
-catch /.*/
- Xpath 65536 " X: 65536
- let exception = v:exception
- let throwpoint = v:throwpoint
- call CHECK(1, "oops", '\<F\[1]\.\.G\[1]\.\.T\>', '\<2\>')
- exec "let exception = v:exception"
- exec "let throwpoint = v:throwpoint"
- call CHECK(2, "oops", '\<F\[1]\.\.G\[1]\.\.T\>', '\<2\>')
- CmdException
- CmdThrowpoint
- call CHECK(3, "oops", '\<F\[1]\.\.G\[1]\.\.T\>', '\<2\>')
- call FuncException()
- call FuncThrowpoint()
- call CHECK(4, "oops", '\<F\[1]\.\.G\[1]\.\.T\>', '\<2\>')
- exec "source" scriptException
- exec "source" scriptThrowPoint
- call CHECK(5, "oops", '\<F\[1]\.\.G\[1]\.\.T\>', '\<2\>')
- try
- Xpath 131072 " X: 131072
- call G("arrgh", 4)
- catch /.*/
- Xpath 262144 " X: 262144
- let exception = v:exception
- let throwpoint = v:throwpoint
- call CHECK(6, "arrgh", '\<G\[1]\.\.T\>', '\<4\>')
- try
- Xpath 524288 " X: 524288
- let g:arg = "autsch"
- let g:line = 6
- exec "source" scriptF
- catch /.*/
- Xpath 1048576 " X: 1048576
- let exception = v:exception
- let throwpoint = v:throwpoint
- " Symbolic links in tempname()s are not resolved, whereas resolving
- " is done for v:throwpoint. Resolve the temporary file name for
- " scriptT, so that it can be matched against v:throwpoint.
- call CHECK(7, "autsch", resolve(scriptT), '\<6\>')
- finally
- Xpath 2097152 " X: 2097152
- let exception = v:exception
- let throwpoint = v:throwpoint
- call CHECK(8, "arrgh", '\<G\[1]\.\.T\>', '\<4\>')
- try
- Xpath 4194304 " X: 4194304
- let g:arg = "brrrr"
- let g:line = 8
- exec "source" scriptG
- catch /.*/
- Xpath 8388608 " X: 8388608
- let exception = v:exception
- let throwpoint = v:throwpoint
- " Resolve scriptT for matching it against v:throwpoint.
- call CHECK(9, "brrrr", resolve(scriptT), '\<8\>')
- finally
- Xpath 16777216 " X: 16777216
- let exception = v:exception
- let throwpoint = v:throwpoint
- call CHECK(10, "arrgh", '\<G\[1]\.\.T\>', '\<4\>')
- endtry
- Xpath 33554432 " X: 33554432
- let exception = v:exception
- let throwpoint = v:throwpoint
- call CHECK(11, "arrgh", '\<G\[1]\.\.T\>', '\<4\>')
- endtry
- Xpath 67108864 " X: 67108864
- let exception = v:exception
- let throwpoint = v:throwpoint
- call CHECK(12, "arrgh", '\<G\[1]\.\.T\>', '\<4\>')
- finally
- Xpath 134217728 " X: 134217728
- let exception = v:exception
- let throwpoint = v:throwpoint
- call CHECK(13, "oops", '\<F\[1]\.\.G\[1]\.\.T\>', '\<2\>')
- endtry
- Xpath 268435456 " X: 268435456
- let exception = v:exception
- let throwpoint = v:throwpoint
- call CHECK(14, "oops", '\<F\[1]\.\.G\[1]\.\.T\>', '\<2\>')
-finally
- Xpath 536870912 " X: 536870912
- let exception = v:exception
- let throwpoint = v:throwpoint
- call CHECK(15, "", '^$', '^$')
-endtry
-
-Xpath 1073741824 " X: 1073741824
-
-unlet exception throwpoint
-delfunction FuncException
-delfunction FuncThrowpoint
-call delete(scriptException)
-call delete(scriptThrowPoint)
-unlet scriptException scriptThrowPoint
-delcommand CmdException
-delcommand CmdThrowpoint
-delfunction T
-delfunction G
-delfunction F
-call delete(scriptT)
-call delete(scriptG)
-call delete(scriptF)
-unlet scriptT scriptG scriptF
-
-Xcheck 2147450880
-
-
-"-------------------------------------------------------------------------------
-"
-" Test 58: v:exception and v:throwpoint for error/interrupt exceptions {{{1
-"
-" v:exception and v:throwpoint work also for error and interrupt
-" exceptions.
-"-------------------------------------------------------------------------------
-
-XpathINIT
-
-if ExtraVim()
-
- function! T(line)
- if a:line == 2
- delfunction T " error (function in use) in line 2
- elseif a:line == 4
- let dummy = 0 " INTERRUPT1 - interrupt in line 4
- endif
- endfunction
-
- while 1
- try
- Xpath 1 " X: 1
- let caught = 0
- call T(2)
- catch /.*/
- let caught = 1
- if v:exception !~ 'Vim(delfunction):'
- Xpath 2 " X: 0
- endif
- if v:throwpoint !~ '\<T\>'
- Xpath 4 " X: 0
- endif
- if v:throwpoint !~ '\<2\>'
- Xpath 8 " X: 0
- endif
- finally
- Xpath 16 " X: 16
- if caught || $VIMNOERRTHROW
- Xpath 32 " X: 32
- endif
- if v:exception != ""
- Xpath 64 " X: 0
- endif
- if v:throwpoint != ""
- Xpath 128 " X: 0
- endif
- break " discard error for $VIMNOERRTHROW
- endtry
- endwhile
-
- Xpath 256 " X: 256
- if v:exception != ""
- Xpath 512 " X: 0
- endif
- if v:throwpoint != ""
- Xpath 1024 " X: 0
- endif
-
- while 1
- try
- Xpath 2048 " X: 2048
- let caught = 0
- call T(4)
- catch /.*/
- let caught = 1
- if v:exception != 'Vim:Interrupt'
- Xpath 4096 " X: 0
- endif
- if v:throwpoint !~ '\<T\>'
- Xpath 8192 " X: 0
- endif
- if v:throwpoint !~ '\<4\>'
- Xpath 16384 " X: 0
- endif
- finally
- Xpath 32768 " X: 32768
- if caught || $VIMNOINTTHROW
- Xpath 65536 " X: 65536
- endif
- if v:exception != ""
- Xpath 131072 " X: 0
- endif
- if v:throwpoint != ""
- Xpath 262144 " X: 0
- endif
- break " discard error for $VIMNOERRTHROW
- endtry
- endwhile
-
- Xpath 524288 " X: 524288
- if v:exception != ""
- Xpath 1048576 " X: 0
- endif
- if v:throwpoint != ""
- Xpath 2097152 " X: 0
- endif
-
-endif
-
-Xcheck 624945
-
-
-"-------------------------------------------------------------------------------
-"
-" Test 59: v:exception and v:throwpoint when discarding exceptions {{{1
-"
-" When a :catch clause is left by a ":break" etc or an error or
-" interrupt exception, v:exception and v:throwpoint are reset. They
-" are not affected by an exception that is discarded before being
-" caught.
-"-------------------------------------------------------------------------------
-
-XpathINIT
-
-if ExtraVim()
-
- XloopINIT! 1 2
-
- let sfile = expand("<sfile>")
-
- function! LineNumber()
- return substitute(substitute(v:throwpoint, g:sfile, '', ""),
- \ '\D*\(\d*\).*', '\1', "")
- endfunction
-
- command! -nargs=1 SetLineNumber
- \ try | throw "line" | catch /.*/ | let <args> = LineNumber() | endtry
-
- " Check v:exception/v:throwpoint against second/fourth parameter if
- " specified, check for being empty else.
- function! CHECK(n, ...)
- XloopNEXT
- let exception = a:0 != 0 ? a:1 : "" " second parameter (optional)
- let emsg = a:0 != 0 ? a:2 : "" " third parameter (optional)
- let line = a:0 != 0 ? a:3 : 0 " fourth parameter (optional)
- let error = 0
- if emsg != ""
- " exception is the error number, emsg the English error message text
- if exception !~ '^E\d\+$'
- Xout "TODO: Add message number for:" emsg
- elseif v:lang == "C" || v:lang =~ '^[Ee]n'
- if exception == "E492" && emsg == "Not an editor command"
- let exception = '^Vim:' . exception . ': ' . emsg
- else
- let exception = '^Vim(\a\+):' . exception . ': ' . emsg
- endif
- else
- if exception == "E492"
- let exception = '^Vim:' . exception
- else
- let exception = '^Vim(\a\+):' . exception
- endif
- endif
- endif
- if exception == "" && v:exception != ""
- Xout a:n.": v:exception is set:" v:exception
- let error = 1
- elseif exception != "" && v:exception !~ exception
- Xout a:n.": v:exception (".v:exception.") does not match" exception
- let error = 1
- endif
- if line == 0 && v:throwpoint != ""
- Xout a:n.": v:throwpoint is set:" v:throwpoint
- let error = 1
- elseif line != 0 && v:throwpoint !~ '\<' . line . '\>'
- Xout a:n.": v:throwpoint (".v:throwpoint.") does not match" line
- let error = 1
- endif
- if !error
- Xloop 1 " X: 2097151
- endif
- endfunction
-
- while 1
- try
- throw "x1"
- catch /.*/
- break
- endtry
- endwhile
- call CHECK(1)
-
- while 1
- try
- throw "x2"
- catch /.*/
- break
- finally
- call CHECK(2)
- endtry
- break
- endwhile
- call CHECK(3)
-
- while 1
- try
- let errcaught = 0
- try
- try
- throw "x3"
- catch /.*/
- SetLineNumber line_before_error
- asdf
- endtry
- catch /.*/
- let errcaught = 1
- call CHECK(4, 'E492', "Not an editor command",
- \ line_before_error + 1)
- endtry
- finally
- if !errcaught && $VIMNOERRTHROW
- call CHECK(4)
- endif
- break " discard error for $VIMNOERRTHROW
- endtry
- endwhile
- call CHECK(5)
-
- Xpath 2097152 " X: 2097152
-
- while 1
- try
- let intcaught = 0
- try
- try
- throw "x4"
- catch /.*/
- SetLineNumber two_lines_before_interrupt
- "INTERRUPT
- let dummy = 0
- endtry
- catch /.*/
- let intcaught = 1
- call CHECK(6, "Vim:Interrupt", '',
- \ two_lines_before_interrupt + 2)
- endtry
- finally
- if !intcaught && $VIMNOINTTHROW
- call CHECK(6)
- endif
- break " discard interrupt for $VIMNOINTTHROW
- endtry
- endwhile
- call CHECK(7)
-
- Xpath 4194304 " X: 4194304
-
- while 1
- try
- let errcaught = 0
- try
- try
-" if 1
- SetLineNumber line_before_throw
- throw "x5"
- " missing endif
- catch /.*/
- Xpath 8388608 " X: 0
- endtry
- catch /.*/
- let errcaught = 1
- call CHECK(8, 'E171', "Missing :endif", line_before_throw + 3)
- endtry
- finally
- if !errcaught && $VIMNOERRTHROW
- call CHECK(8)
- endif
- break " discard error for $VIMNOERRTHROW
- endtry
- endwhile
- call CHECK(9)
-
- Xpath 16777216 " X: 16777216
-
- try
- while 1
- try
- throw "x6"
- finally
- break
- endtry
- break
- endwhile
- catch /.*/
- Xpath 33554432 " X: 0
- endtry
- call CHECK(10)
-
- try
- while 1
- try
- throw "x7"
- finally
- break
- endtry
- break
- endwhile
- catch /.*/
- Xpath 67108864 " X: 0
- finally
- call CHECK(11)
- endtry
- call CHECK(12)
-
- while 1
- try
- let errcaught = 0
- try
- try
- throw "x8"
- finally
- SetLineNumber line_before_error
- asdf
- endtry
- catch /.*/
- let errcaught = 1
- call CHECK(13, 'E492', "Not an editor command",
- \ line_before_error + 1)
- endtry
- finally
- if !errcaught && $VIMNOERRTHROW
- call CHECK(13)
- endif
- break " discard error for $VIMNOERRTHROW
- endtry
- endwhile
- call CHECK(14)
-
- Xpath 134217728 " X: 134217728
-
- while 1
- try
- let intcaught = 0
- try
- try
- throw "x9"
- finally
- SetLineNumber two_lines_before_interrupt
- "INTERRUPT
- endtry
- catch /.*/
- let intcaught = 1
- call CHECK(15, "Vim:Interrupt", '',
- \ two_lines_before_interrupt + 2)
- endtry
- finally
- if !intcaught && $VIMNOINTTHROW
- call CHECK(15)
- endif
- break " discard interrupt for $VIMNOINTTHROW
- endtry
- endwhile
- call CHECK(16)
-
- Xpath 268435456 " X: 268435456
-
- while 1
- try
- let errcaught = 0
- try
- try
-" if 1
- SetLineNumber line_before_throw
- throw "x10"
- " missing endif
- finally
- call CHECK(17)
- endtry
- catch /.*/
- let errcaught = 1
- call CHECK(18, 'E171', "Missing :endif", line_before_throw + 3)
- endtry
- finally
- if !errcaught && $VIMNOERRTHROW
- call CHECK(18)
- endif
- break " discard error for $VIMNOERRTHROW
- endtry
- endwhile
- call CHECK(19)
-
- Xpath 536870912 " X: 536870912
-
- while 1
- try
- let errcaught = 0
- try
- try
-" if 1
- SetLineNumber line_before_throw
- throw "x11"
- " missing endif
- endtry
- catch /.*/
- let errcaught = 1
- call CHECK(20, 'E171', "Missing :endif", line_before_throw + 3)
- endtry
- finally
- if !errcaught && $VIMNOERRTHROW
- call CHECK(20)
- endif
- break " discard error for $VIMNOERRTHROW
- endtry
- endwhile
- call CHECK(21)
-
- Xpath 1073741824 " X: 1073741824
-
-endif
-
-Xcheck 2038431743
-
-
-"-------------------------------------------------------------------------------
-"
-" Test 60: (Re)throwing v:exception; :echoerr. {{{1
-"
-" A user exception can be rethrown after catching by throwing
-" v:exception. An error or interrupt exception cannot be rethrown
-" because Vim exceptions cannot be faked. A Vim exception using the
-" value of v:exception can, however, be triggered by the :echoerr
-" command.
-"-------------------------------------------------------------------------------
-
-XpathINIT
-
-try
- try
- Xpath 1 " X: 1
- throw "oops"
- catch /oops/
- Xpath 2 " X: 2
- throw v:exception " rethrow user exception
- catch /.*/
- Xpath 4 " X: 0
- endtry
-catch /^oops$/ " catches rethrown user exception
- Xpath 8 " X: 8
-catch /.*/
- Xpath 16 " X: 0
-endtry
-
-function! F()
- try
- let caught = 0
- try
- Xpath 32 " X: 32
- write /n/o/n/w/r/i/t/a/b/l/e/_/f/i/l/e
- Xpath 64 " X: 0
- Xout "did_emsg was reset before executing " .
- \ "BufWritePost autocommands."
- catch /^Vim(write):/
- let caught = 1
- throw v:exception " throw error: cannot fake Vim exception
- catch /.*/
- Xpath 128 " X: 0
- finally
- Xpath 256 " X: 256
- if !caught && !$VIMNOERRTHROW
- Xpath 512 " X: 0
- endif
- endtry
- catch /^Vim(throw):/ " catches throw error
- let caught = caught + 1
- catch /.*/
- Xpath 1024 " X: 0
- finally
- Xpath 2048 " X: 2048
- if caught != 2
- if !caught && !$VIMNOERRTHROW
- Xpath 4096 " X: 0
- elseif caught
- Xpath 8192 " X: 0
- endif
- return | " discard error for $VIMNOERRTHROW
- endif
- endtry
-endfunction
-
-call F()
-delfunction F
-
-function! G()
- try
- let caught = 0
- try
- Xpath 16384 " X: 16384
- asdf
- catch /^Vim/ " catch error exception
- let caught = 1
- " Trigger Vim error exception with value specified after :echoerr
- let value = substitute(v:exception, '^Vim\((.*)\)\=:', '', "")
- echoerr value
- catch /.*/
- Xpath 32768 " X: 0
- finally
- Xpath 65536 " X: 65536
- if !caught
- if !$VIMNOERRTHROW
- Xpath 131072 " X: 0
- else
- let value = "Error"
- echoerr value
- endif
- endif
- endtry
- catch /^Vim(echoerr):/
- let caught = caught + 1
- if v:exception !~ value
- Xpath 262144 " X: 0
- endif
- catch /.*/
- Xpath 524288 " X: 0
- finally
- Xpath 1048576 " X: 1048576
- if caught != 2
- if !caught && !$VIMNOERRTHROW
- Xpath 2097152 " X: 0
- elseif caught
- Xpath 4194304 " X: 0
- endif
- return | " discard error for $VIMNOERRTHROW
- endif
- endtry
-endfunction
-
-call G()
-delfunction G
-
-unlet! value caught
-
-if ExtraVim()
- try
- let errcaught = 0
- try
- Xpath 8388608 " X: 8388608
- let intcaught = 0
- "INTERRUPT
- catch /^Vim:/ " catch interrupt exception
- let intcaught = 1
- " Trigger Vim error exception with value specified after :echoerr
- echoerr substitute(v:exception, '^Vim\((.*)\)\=:', '', "")
- catch /.*/
- Xpath 16777216 " X: 0
- finally
- Xpath 33554432 " X: 33554432
- if !intcaught
- if !$VIMNOINTTHROW
- Xpath 67108864 " X: 0
- else
- echoerr "Interrupt"
- endif
- endif
- endtry
- catch /^Vim(echoerr):/
- let errcaught = 1
- if v:exception !~ "Interrupt"
- Xpath 134217728 " X: 0
- endif
- finally
- Xpath 268435456 " X: 268435456
- if !errcaught && !$VIMNOERRTHROW
- Xpath 536870912 " X: 0
- endif
- endtry
-endif
-
-Xcheck 311511339
-
-
-"-------------------------------------------------------------------------------
-" Test 61: Catching interrupt exceptions {{{1
-"
-" When an interrupt occurs inside a :try/:endtry region, an
-" interrupt exception is thrown and can be caught. Its value is
-" "Vim:Interrupt". If the interrupt occurs after an error or a :throw
-" but before a matching :catch is reached, all following :catches of
-" that try block are ignored, but the interrupt exception can be
-" caught by the next surrounding try conditional. An interrupt is
-" ignored when there is a previous interrupt that has not been caught
-" or causes a :finally clause to be executed.
-"-------------------------------------------------------------------------------
-
-XpathINIT
-
-if ExtraVim()
-
- while 1
- try
- try
- Xpath 1 " X: 1
- let caught = 0
- "INTERRUPT
- Xpath 2 " X: 0
- catch /^Vim:Interrupt$/
- let caught = 1
- finally
- Xpath 4 " X: 4
- if caught || $VIMNOINTTHROW
- Xpath 8 " X: 8
- endif
- endtry
- catch /.*/
- Xpath 16 " X: 0
- Xout v:exception "in" v:throwpoint
- finally
- break " discard interrupt for $VIMNOINTTHROW
- endtry
- endwhile
-
- while 1
- try
- try
- let caught = 0
- try
- Xpath 32 " X: 32
- asdf
- Xpath 64 " X: 0
- catch /do_not_catch/
- Xpath 128 " X: 0
- catch /.*/ "INTERRUPT - throw interrupt if !$VIMNOERRTHROW
- Xpath 256 " X: 0
- catch /.*/
- Xpath 512 " X: 0
- finally "INTERRUPT - throw interrupt if $VIMNOERRTHROW
- Xpath 1024 " X: 1024
- endtry
- catch /^Vim:Interrupt$/
- let caught = 1
- finally
- Xpath 2048 " X: 2048
- if caught || $VIMNOINTTHROW
- Xpath 4096 " X: 4096
- endif
- endtry
- catch /.*/
- Xpath 8192 " X: 0
- Xout v:exception "in" v:throwpoint
- finally
- break " discard interrupt for $VIMNOINTTHROW
- endtry
- endwhile
-
- while 1
- try
- try
- let caught = 0
- try
- Xpath 16384 " X: 16384
- throw "x"
- Xpath 32768 " X: 0
- catch /do_not_catch/
- Xpath 65536 " X: 0
- catch /x/ "INTERRUPT
- Xpath 131072 " X: 0
- catch /.*/
- Xpath 262144 " X: 0
- endtry
- catch /^Vim:Interrupt$/
- let caught = 1
- finally
- Xpath 524288 " X: 524288
- if caught || $VIMNOINTTHROW
- Xpath 1048576 " X: 1048576
- endif
- endtry
- catch /.*/
- Xpath 2097152 " X: 0
- Xout v:exception "in" v:throwpoint
- finally
- break " discard interrupt for $VIMNOINTTHROW
- endtry
- endwhile
-
- while 1
- try
- let caught = 0
- try
- Xpath 4194304 " X: 4194304
- "INTERRUPT
- Xpath 8388608 " X: 0
- catch /do_not_catch/ "INTERRUPT
- Xpath 16777216 " X: 0
- catch /^Vim:Interrupt$/
- let caught = 1
- finally
- Xpath 33554432 " X: 33554432
- if caught || $VIMNOINTTHROW
- Xpath 67108864 " X: 67108864
- endif
- endtry
- catch /.*/
- Xpath 134217728 " X: 0
- Xout v:exception "in" v:throwpoint
- finally
- break " discard interrupt for $VIMNOINTTHROW
- endtry
- endwhile
-
- Xpath 268435456 " X: 268435456
-
-endif
-
-Xcheck 374889517
-
-
-"-------------------------------------------------------------------------------
-" Test 62: Catching error exceptions {{{1
-"
-" An error inside a :try/:endtry region is converted to an exception
-" and can be caught. The error exception has a "Vim(cmdname):" prefix
-" where cmdname is the name of the failing command, or a "Vim:" prefix
-" if no command name is known. The "Vim" prefixes cannot be faked.
-"-------------------------------------------------------------------------------
-
-XpathINIT
-
-function! MSG(enr, emsg)
- let english = v:lang == "C" || v:lang =~ '^[Ee]n'
- if a:enr == ""
- Xout "TODO: Add message number for:" a:emsg
- let v:errmsg = ":" . v:errmsg
- endif
- let match = 1
- if v:errmsg !~ '^'.a:enr.':' || (english && v:errmsg !~ a:emsg)
- let match = 0
- if v:errmsg == ""
- Xout "Message missing."
- else
- let v:errmsg = escape(v:errmsg, '"')
- Xout "Unexpected message:" v:errmsg
- endif
- endif
- return match
-endfunction
-
-while 1
- try
- try
- let caught = 0
- unlet novar
- catch /^Vim(unlet):/
- let caught = 1
- let v:errmsg = substitute(v:exception, '^Vim(unlet):', '', "")
- finally
- Xpath 1 " X: 1
- if !caught && !$VIMNOERRTHROW
- Xpath 2 " X: 0
- endif
- if !MSG('E108', "No such variable")
- Xpath 4 " X: 0
- endif
- endtry
- catch /.*/
- Xpath 8 " X: 0
- Xout v:exception "in" v:throwpoint
- finally
- break " discard error for $VIMNOERRTHROW
- endtry
-endwhile
-
-while 1
- try
- try
- let caught = 0
- throw novar " error in :throw
- catch /^Vim(throw):/
- let caught = 1
- let v:errmsg = substitute(v:exception, '^Vim(throw):', '', "")
- finally
- Xpath 16 " X: 16
- if !caught && !$VIMNOERRTHROW
- Xpath 32 " X: 0
- endif
- if caught ? !MSG('E121', "Undefined variable")
- \ : !MSG('E15', "Invalid expression")
- Xpath 64 " X: 0
- endif
- endtry
- catch /.*/
- Xpath 128 " X: 0
- Xout v:exception "in" v:throwpoint
- finally
- break " discard error for $VIMNOERRTHROW
- endtry
-endwhile
-
-while 1
- try
- try
- let caught = 0
- throw "Vim:faked" " error: cannot fake Vim exception
- catch /^Vim(throw):/
- let caught = 1
- let v:errmsg = substitute(v:exception, '^Vim(throw):', '', "")
- finally
- Xpath 256 " X: 256
- if !caught && !$VIMNOERRTHROW
- Xpath 512 " X: 0
- endif
- if !MSG('E608', "Cannot :throw exceptions with 'Vim' prefix")
- Xpath 1024 " X: 0
- endif
- endtry
- catch /.*/
- Xpath 2048 " X: 0
- Xout v:exception "in" v:throwpoint
- finally
- break " discard error for $VIMNOERRTHROW
- endtry
-endwhile
-
-function! F()
- while 1
- " Missing :endwhile
-endfunction
-
-while 1
- try
- try
- let caught = 0
- call F()
- catch /^Vim(endfunction):/
- let caught = 1
- let v:errmsg = substitute(v:exception, '^Vim(endfunction):', '', "")
- finally
- Xpath 4096 " X: 4096
- if !caught && !$VIMNOERRTHROW
- Xpath 8192 " X: 0
- endif
- if !MSG('E170', "Missing :endwhile")
- Xpath 16384 " X: 0
- endif
- endtry
- catch /.*/
- Xpath 32768 " X: 0
- Xout v:exception "in" v:throwpoint
- finally
- break " discard error for $VIMNOERRTHROW
- endtry
-endwhile
-
-while 1
- try
- try
- let caught = 0
- ExecAsScript F
- catch /^Vim:/
- let caught = 1
- let v:errmsg = substitute(v:exception, '^Vim:', '', "")
- finally
- Xpath 65536 " X: 65536
- if !caught && !$VIMNOERRTHROW
- Xpath 131072 " X: 0
- endif
- if !MSG('E170', "Missing :endwhile")
- Xpath 262144 " X: 0
- endif
- endtry
- catch /.*/
- Xpath 524288 " X: 0
- Xout v:exception "in" v:throwpoint
- finally
- break " discard error for $VIMNOERRTHROW
- endtry
-endwhile
-
-function! G()
- call G()
-endfunction
-
-while 1
- try
- let mfd_save = &mfd
- set mfd=3
- try
- let caught = 0
- call G()
- catch /^Vim(call):/
- let caught = 1
- let v:errmsg = substitute(v:exception, '^Vim(call):', '', "")
- finally
- Xpath 1048576 " X: 1048576
- if !caught && !$VIMNOERRTHROW
- Xpath 2097152 " X: 0
- endif
- if !MSG('E132', "Function call depth is higher than 'maxfuncdepth'")
- Xpath 4194304 " X: 0
- endif
- endtry
- catch /.*/
- Xpath 8388608 " X: 0
- Xout v:exception "in" v:throwpoint
- finally
- let &mfd = mfd_save
- break " discard error for $VIMNOERRTHROW
- endtry
-endwhile
-
-function! H()
- return H()
-endfunction
-
-while 1
- try
- let mfd_save = &mfd
- set mfd=3
- try
- let caught = 0
- call H()
- catch /^Vim(return):/
- let caught = 1
- let v:errmsg = substitute(v:exception, '^Vim(return):', '', "")
- finally
- Xpath 16777216 " X: 16777216
- if !caught && !$VIMNOERRTHROW
- Xpath 33554432 " X: 0
- endif
- if !MSG('E132', "Function call depth is higher than 'maxfuncdepth'")
- Xpath 67108864 " X: 0
- endif
- endtry
- catch /.*/
- Xpath 134217728 " X: 0
- Xout v:exception "in" v:throwpoint
- finally
- let &mfd = mfd_save
- break " discard error for $VIMNOERRTHROW
- endtry
-endwhile
-
-unlet! caught mfd_save
-delfunction F
-delfunction G
-delfunction H
-Xpath 268435456 " X: 268435456
-
-Xcheck 286331153
-
-" Leave MSG() for the next test.
-
-
-"-------------------------------------------------------------------------------
-" Test 63: Suppressing error exceptions by :silent!. {{{1
-"
-" A :silent! command inside a :try/:endtry region suppresses the
-" conversion of errors to an exception and the immediate abortion on
-" error. When the commands executed by the :silent! themselves open
-" a new :try/:endtry region, conversion of errors to exception and
-" immediate abortion is switched on again - until the next :silent!
-" etc. The :silent! has the effect of setting v:errmsg to the error
-" message text (without displaying it) and continuing with the next
-" script line.
-"
-" When a command triggering autocommands is executed by :silent!
-" inside a :try/:endtry, the autocommand execution is not suppressed
-" on error.
-"
-" This test reuses the function MSG() from the previous test.
-"-------------------------------------------------------------------------------
-
-XpathINIT
-
-XloopINIT! 1 4
-
-let taken = ""
-
-function! S(n) abort
- XloopNEXT
- let g:taken = g:taken . "E" . a:n
- let v:errmsg = ""
- exec "asdf" . a:n
-
- " Check that ":silent!" continues:
- Xloop 1
-
- " Check that ":silent!" sets "v:errmsg":
- if MSG('E492', "Not an editor command")
- Xloop 2
- endif
-endfunction
-
-function! Foo()
- while 1
- try
- try
- let caught = 0
- " This is not silent:
- call S(3) " X: 0 * 16
- catch /^Vim:/
- let caught = 1
- let errmsg3 = substitute(v:exception, '^Vim:', '', "")
- silent! call S(4) " X: 3 * 64
- finally
- if !caught
- let errmsg3 = v:errmsg
- " Do call S(4) here if not executed in :catch.
- silent! call S(4)
- endif
- Xpath 1048576 " X: 1048576
- if !caught && !$VIMNOERRTHROW
- Xpath 2097152 " X: 0
- endif
- let v:errmsg = errmsg3
- if !MSG('E492', "Not an editor command")
- Xpath 4194304 " X: 0
- endif
- silent! call S(5) " X: 3 * 256
- " Break out of try conditionals that cover ":silent!". This also
- " discards the aborting error when $VIMNOERRTHROW is non-zero.
- break
- endtry
- catch /.*/
- Xpath 8388608 " X: 0
- Xout v:exception "in" v:throwpoint
- endtry
- endwhile
- " This is a double ":silent!" (see caller).
- silent! call S(6) " X: 3 * 1024
-endfunction
-
-function! Bar()
- try
- silent! call S(2) " X: 3 * 4
- " X: 3 * 4096
- silent! execute "call Foo() | call S(7)"
- silent! call S(8) " X: 3 * 16384
- endtry " normal end of try cond that covers ":silent!"
- " This has a ":silent!" from the caller:
- call S(9) " X: 3 * 65536
-endfunction
-
-silent! call S(1) " X: 3 * 1
-silent! call Bar()
-silent! call S(10) " X: 3 * 262144
-
-let expected = "E1E2E3E4E5E6E7E8E9E10"
-if taken != expected
- Xpath 16777216 " X: 0
- Xout "'taken' is" taken "instead of" expected
-endif
-
-augroup TMP
- autocmd BufWritePost * Xpath 33554432 " X: 33554432
-augroup END
-
-Xpath 67108864 " X: 67108864
-write /i/m/p/o/s/s/i/b/l/e
-Xpath 134217728 " X: 134217728
-
-autocmd! TMP
-unlet! caught errmsg3 taken expected
-delfunction S
-delfunction Foo
-delfunction Bar
-delfunction MSG
-
-Xcheck 236978127
-
-
-"-------------------------------------------------------------------------------
-" Test 64: Error exceptions after error, interrupt or :throw {{{1
-"
-" When an error occurs after an interrupt or a :throw but before
-" a matching :catch is reached, all following :catches of that try
-" block are ignored, but the error exception can be caught by the next
-" surrounding try conditional. Any previous error exception is
-" discarded. An error is ignored when there is a previous error that
-" has not been caught.
-"-------------------------------------------------------------------------------
-
-XpathINIT
-
-if ExtraVim()
-
- while 1
- try
- try
- Xpath 1 " X: 1
- let caught = 0
- while 1
-" if 1
- " Missing :endif
- endwhile " throw error exception
- catch /^Vim(/
- let caught = 1
- finally
- Xpath 2 " X: 2
- if caught || $VIMNOERRTHROW
- Xpath 4 " X: 4
- endif
- endtry
- catch /.*/
- Xpath 8 " X: 0
- Xout v:exception "in" v:throwpoint
- finally
- break " discard error for $VIMNOERRTHROW
- endtry
- endwhile
-
- while 1
- try
- try
- Xpath 16 " X: 16
- let caught = 0
- try
-" if 1
- " Missing :endif
- catch /.*/ " throw error exception
- Xpath 32 " X: 0
- catch /.*/
- Xpath 64 " X: 0
- endtry
- catch /^Vim(/
- let caught = 1
- finally
- Xpath 128 " X: 128
- if caught || $VIMNOERRTHROW
- Xpath 256 " X: 256
- endif
- endtry
- catch /.*/
- Xpath 512 " X: 0
- Xout v:exception "in" v:throwpoint
- finally
- break " discard error for $VIMNOERRTHROW
- endtry
- endwhile
-
- while 1
- try
- try
- let caught = 0
- try
- Xpath 1024 " X: 1024
- "INTERRUPT
- catch /do_not_catch/
- Xpath 2048 " X: 0
-" if 1
- " Missing :endif
- catch /.*/ " throw error exception
- Xpath 4096 " X: 0
- catch /.*/
- Xpath 8192 " X: 0
- endtry
- catch /^Vim(/
- let caught = 1
- finally
- Xpath 16384 " X: 16384
- if caught || $VIMNOERRTHROW
- Xpath 32768 " X: 32768
- endif
- endtry
- catch /.*/
- Xpath 65536 " X: 0
- Xout v:exception "in" v:throwpoint
- finally
- break " discard error for $VIMNOERRTHROW
- endtry
- endwhile
-
- while 1
- try
- try
- let caught = 0
- try
- Xpath 131072 " X: 131072
- throw "x"
- catch /do_not_catch/
- Xpath 262144 " X: 0
-" if 1
- " Missing :endif
- catch /x/ " throw error exception
- Xpath 524288 " X: 0
- catch /.*/
- Xpath 1048576 " X: 0
- endtry
- catch /^Vim(/
- let caught = 1
- finally
- Xpath 2097152 " X: 2097152
- if caught || $VIMNOERRTHROW
- Xpath 4194304 " X: 4194304
- endif
- endtry
- catch /.*/
- Xpath 8388608 " X: 0
- Xout v:exception "in" v:throwpoint
- finally
- break " discard error for $VIMNOERRTHROW
- endtry
- endwhile
-
- while 1
- try
- try
- let caught = 0
- Xpath 16777216 " X: 16777216
-" endif " :endif without :if; throw error exception
-" if 1
- " Missing :endif
- catch /do_not_catch/ " ignore new error
- Xpath 33554432 " X: 0
- catch /^Vim(endif):/
- let caught = 1
- catch /^Vim(/
- Xpath 67108864 " X: 0
- finally
- Xpath 134217728 " X: 134217728
- if caught || $VIMNOERRTHROW
- Xpath 268435456 " X: 268435456
- endif
- endtry
- catch /.*/
- Xpath 536870912 " X: 0
- Xout v:exception "in" v:throwpoint
- finally
- break " discard error for $VIMNOERRTHROW
- endtry
- endwhile
-
- Xpath 1073741824 " X: 1073741824
-
-endif
-
-Xcheck 1499645335
-
-
-"-------------------------------------------------------------------------------
-" Test 65: Errors in the /pattern/ argument of a :catch {{{1
-"
-" On an error in the /pattern/ argument of a :catch, the :catch does
-" not match. Any following :catches of the same :try/:endtry don't
-" match either. Finally clauses are executed.
-"-------------------------------------------------------------------------------
-
-XpathINIT
-
-function! MSG(enr, emsg)
- let english = v:lang == "C" || v:lang =~ '^[Ee]n'
- if a:enr == ""
- Xout "TODO: Add message number for:" a:emsg
- let v:errmsg = ":" . v:errmsg
- endif
- let match = 1
- if v:errmsg !~ '^'.a:enr.':' || (english && v:errmsg !~ a:emsg)
- let match = 0
- if v:errmsg == ""
- Xout "Message missing."
- else
- let v:errmsg = escape(v:errmsg, '"')
- Xout "Unexpected message:" v:errmsg
- endif
- endif
- return match
-endfunction
-
-try
- try
- Xpath 1 " X: 1
- throw "oops"
- catch /^oops$/
- Xpath 2 " X: 2
- catch /\)/ " not checked; exception has already been caught
- Xpath 4 " X: 0
- endtry
- Xpath 8 " X: 8
-catch /.*/
- Xpath 16 " X: 0
- Xout v:exception "in" v:throwpoint
-endtry
-
-function! F()
- try
- let caught = 0
- try
- try
- Xpath 32 " X: 32
- throw "ab"
- catch /abc/ " does not catch
- Xpath 64 " X: 0
- catch /\)/ " error; discards exception
- Xpath 128 " X: 0
- catch /.*/ " not checked
- Xpath 256 " X: 0
- finally
- Xpath 512 " X: 512
- endtry
- Xpath 1024 " X: 0
- catch /^ab$/ " checked, but original exception is discarded
- Xpath 2048 " X: 0
- catch /^Vim(catch):/
- let caught = 1
- let v:errmsg = substitute(v:exception, '^Vim(catch):', '', "")
- finally
- Xpath 4096 " X: 4096
- if !caught && !$VIMNOERRTHROW
- Xpath 8192 " X: 0
- endif
- if !MSG('E475', "Invalid argument")
- Xpath 16384 " X: 0
- endif
- if !caught
- return | " discard error
- endif
- endtry
- catch /.*/
- Xpath 32768 " X: 0
- Xout v:exception "in" v:throwpoint
- endtry
-endfunction
-
-call F()
-Xpath 65536 " X: 65536
-
-delfunction MSG
-delfunction F
-unlet! caught
-
-Xcheck 70187
-
-
-"-------------------------------------------------------------------------------
-" Test 66: Stop range :call on error, interrupt, or :throw {{{1
-"
-" When a function which is multiply called for a range since it
-" doesn't handle the range itself has an error in a command
-" dynamically enclosed by :try/:endtry or gets an interrupt or
-" executes a :throw, no more calls for the remaining lines in the
-" range are made. On an error in a command not dynamically enclosed
-" by :try/:endtry, the function is executed again for the remaining
-" lines in the range.
-"-------------------------------------------------------------------------------
-
-XpathINIT
-
-if ExtraVim()
-
- let file = tempname()
- exec "edit" file
-
- insert
-line 1
-line 2
-line 3
-.
-
- XloopINIT! 1 2
-
- let taken = ""
- let expected = "G1EF1E(1)F1E(2)F1E(3)G2EF2E(1)G3IF3I(1)G4TF4T(1)G5AF5A(1)"
-
- function! F(reason, n) abort
- let g:taken = g:taken . "F" . a:n .
- \ substitute(a:reason, '\(\l\).*', '\u\1', "") .
- \ "(" . line(".") . ")"
-
- if a:reason == "error"
- asdf
- elseif a:reason == "interrupt"
- "INTERRUPT
- let dummy = 0
- elseif a:reason == "throw"
- throw "xyz"
- elseif a:reason == "aborting error"
- XloopNEXT
- if g:taken != g:expected
- Xloop 1 " X: 0
- Xout "'taken' is" g:taken "instead of" g:expected
- endif
- try
- bwipeout!
- call delete(file)
- asdf
- endtry
- endif
- endfunction
-
- function! G(reason, n)
- let g:taken = g:taken . "G" . a:n .
- \ substitute(a:reason, '\(\l\).*', '\u\1', "")
- 1,3call F(a:reason, a:n)
- endfunction
-
- Xpath 8 " X: 8
- call G("error", 1)
- try
- Xpath 16 " X: 16
- try
- call G("error", 2)
- Xpath 32 " X: 0
- finally
- Xpath 64 " X: 64
- try
- call G("interrupt", 3)
- Xpath 128 " X: 0
- finally
- Xpath 256 " X: 256
- try
- call G("throw", 4)
- Xpath 512 " X: 0
- endtry
- endtry
- endtry
- catch /xyz/
- Xpath 1024 " X: 1024
- catch /.*/
- Xpath 2048 " X: 0
- Xout v:exception "in" ExtraVimThrowpoint()
- endtry
- Xpath 4096 " X: 4096
- call G("aborting error", 5)
- Xpath 8192 " X: 0
- Xout "'taken' is" taken "instead of" expected
-
-endif
-
-Xcheck 5464
-
-
-"-------------------------------------------------------------------------------
-" Test 67: :throw across :call command {{{1
-"
-" On a call command, an exception might be thrown when evaluating the
-" function name, during evaluation of the arguments, or when the
-" function is being executed. The exception can be caught by the
-" caller.
-"-------------------------------------------------------------------------------
-
-XpathINIT
-
-function! THROW(x, n)
- if a:n == 1
- Xpath 1 " X: 1
- elseif a:n == 2
- Xpath 2 " X: 2
- elseif a:n == 3
- Xpath 4 " X: 4
- endif
- throw a:x
-endfunction
-
-function! NAME(x, n)
- if a:n == 1
- Xpath 8 " X: 0
- elseif a:n == 2
- Xpath 16 " X: 16
- elseif a:n == 3
- Xpath 32 " X: 32
- elseif a:n == 4
- Xpath 64 " X: 64
- endif
- return a:x
-endfunction
-
-function! ARG(x, n)
- if a:n == 1
- Xpath 128 " X: 0
- elseif a:n == 2
- Xpath 256 " X: 0
- elseif a:n == 3
- Xpath 512 " X: 512
- elseif a:n == 4
- Xpath 1024 " X: 1024
- endif
- return a:x
-endfunction
-
-function! F(x, n)
- if a:n == 2
- Xpath 2048 " X: 0
- elseif a:n == 4
- Xpath 4096 " X: 4096
- endif
-endfunction
-
-while 1
- try
- let error = 0
- let v:errmsg = ""
-
- while 1
- try
- Xpath 8192 " X: 8192
- call {NAME(THROW("name", 1), 1)}(ARG(4711, 1), 1)
- Xpath 16384 " X: 0
- catch /^name$/
- Xpath 32768 " X: 32768
- catch /.*/
- let error = 1
- Xout "1:" v:exception "in" v:throwpoint
- finally
- if !error && $VIMNOERRTHROW && v:errmsg != ""
- let error = 1
- Xout "1:" v:errmsg
- endif
- if error
- Xpath 65536 " X: 0
- endif
- let error = 0
- let v:errmsg = ""
- break " discard error for $VIMNOERRTHROW
- endtry
- endwhile
-
- while 1
- try
- Xpath 131072 " X: 131072
- call {NAME("F", 2)}(ARG(THROW("arg", 2), 2), 2)
- Xpath 262144 " X: 0
- catch /^arg$/
- Xpath 524288 " X: 524288
- catch /.*/
- let error = 1
- Xout "2:" v:exception "in" v:throwpoint
- finally
- if !error && $VIMNOERRTHROW && v:errmsg != ""
- let error = 1
- Xout "2:" v:errmsg
- endif
- if error
- Xpath 1048576 " X: 0
- endif
- let error = 0
- let v:errmsg = ""
- break " discard error for $VIMNOERRTHROW
- endtry
- endwhile
-
- while 1
- try
- Xpath 2097152 " X: 2097152
- call {NAME("THROW", 3)}(ARG("call", 3), 3)
- Xpath 4194304 " X: 0
- catch /^call$/
- Xpath 8388608 " X: 8388608
- catch /^0$/ " default return value
- Xpath 16777216 " X: 0
- Xout "3:" v:throwpoint
- catch /.*/
- let error = 1
- Xout "3:" v:exception "in" v:throwpoint
- finally
- if !error && $VIMNOERRTHROW && v:errmsg != ""
- let error = 1
- Xout "3:" v:errmsg
- endif
- if error
- Xpath 33554432 " X: 0
- endif
- let error = 0
- let v:errmsg = ""
- break " discard error for $VIMNOERRTHROW
- endtry
- endwhile
-
- while 1
- try
- Xpath 67108864 " X: 67108864
- call {NAME("F", 4)}(ARG(4711, 4), 4)
- Xpath 134217728 " X: 134217728
- catch /.*/
- let error = 1
- Xout "4:" v:exception "in" v:throwpoint
- finally
- if !error && $VIMNOERRTHROW && v:errmsg != ""
- let error = 1
- Xout "4:" v:errmsg
- endif
- if error
- Xpath 268435456 " X: 0
- endif
- let error = 0
- let v:errmsg = ""
- break " discard error for $VIMNOERRTHROW
- endtry
- endwhile
-
- catch /^0$/ " default return value
- Xpath 536870912 " X: 0
- Xout v:throwpoint
- catch /.*/
- let error = 1
- Xout v:exception "in" v:throwpoint
- finally
- if !error && $VIMNOERRTHROW && v:errmsg != ""
- let error = 1
- Xout v:errmsg
- endif
- if error
- Xpath 1073741824 " X: 0
- endif
- break " discard error for $VIMNOERRTHROW
- endtry
-endwhile
-
-unlet error
-delfunction F
-
-Xcheck 212514423
-
-" Leave THROW(), NAME(), and ARG() for the next test.
-
-
-"-------------------------------------------------------------------------------
-" Test 68: :throw across function calls in expressions {{{1
-"
-" On a function call within an expression, an exception might be
-" thrown when evaluating the function name, during evaluation of the
-" arguments, or when the function is being executed. The exception
-" can be caught by the caller.
-"
-" This test reuses the functions THROW(), NAME(), and ARG() from the
-" previous test.
-"-------------------------------------------------------------------------------
-
-XpathINIT
-
-function! F(x, n)
- if a:n == 2
- Xpath 2048 " X: 0
- elseif a:n == 4
- Xpath 4096 " X: 4096
- endif
- return a:x
-endfunction
-
-unlet! var1 var2 var3 var4
-
-while 1
- try
- let error = 0
- let v:errmsg = ""
-
- while 1
- try
- Xpath 8192 " X: 8192
- let var1 = {NAME(THROW("name", 1), 1)}(ARG(4711, 1), 1)
- Xpath 16384 " X: 0
- catch /^name$/
- Xpath 32768 " X: 32768
- catch /.*/
- let error = 1
- Xout "1:" v:exception "in" v:throwpoint
- finally
- if !error && $VIMNOERRTHROW && v:errmsg != ""
- let error = 1
- Xout "1:" v:errmsg
- endif
- if error
- Xpath 65536 " X: 0
- endif
- let error = 0
- let v:errmsg = ""
- break " discard error for $VIMNOERRTHROW
- endtry
- endwhile
-
- while 1
- try
- Xpath 131072 " X: 131072
- let var2 = {NAME("F", 2)}(ARG(THROW("arg", 2), 2), 2)
- Xpath 262144 " X: 0
- catch /^arg$/
- Xpath 524288 " X: 524288
- catch /.*/
- let error = 1
- Xout "2:" v:exception "in" v:throwpoint
- finally
- if !error && $VIMNOERRTHROW && v:errmsg != ""
- let error = 1
- Xout "2:" v:errmsg
- endif
- if error
- Xpath 1048576 " X: 0
- endif
- let error = 0
- let v:errmsg = ""
- break " discard error for $VIMNOERRTHROW
- endtry
- endwhile
-
- while 1
- try
- Xpath 2097152 " X: 2097152
- let var3 = {NAME("THROW", 3)}(ARG("call", 3), 3)
- Xpath 4194304 " X: 0
- catch /^call$/
- Xpath 8388608 " X: 8388608
- catch /^0$/ " default return value
- Xpath 16777216 " X: 0
- Xout "3:" v:throwpoint
- catch /.*/
- let error = 1
- Xout "3:" v:exception "in" v:throwpoint
- finally
- if !error && $VIMNOERRTHROW && v:errmsg != ""
- let error = 1
- Xout "3:" v:errmsg
- endif
- if error
- Xpath 33554432 " X: 0
- endif
- let error = 0
- let v:errmsg = ""
- break " discard error for $VIMNOERRTHROW
- endtry
- endwhile
-
- while 1
- try
- Xpath 67108864 " X: 67108864
- let var4 = {NAME("F", 4)}(ARG(4711, 4), 4)
- Xpath 134217728 " X: 134217728
- catch /.*/
- let error = 1
- Xout "4:" v:exception "in" v:throwpoint
- finally
- if !error && $VIMNOERRTHROW && v:errmsg != ""
- let error = 1
- Xout "4:" v:errmsg
- endif
- if error
- Xpath 268435456 " X: 0
- endif
- let error = 0
- let v:errmsg = ""
- break " discard error for $VIMNOERRTHROW
- endtry
- endwhile
-
- catch /^0$/ " default return value
- Xpath 536870912 " X: 0
- Xout v:throwpoint
- catch /.*/
- let error = 1
- Xout v:exception "in" v:throwpoint
- finally
- if !error && $VIMNOERRTHROW && v:errmsg != ""
- let error = 1
- Xout v:errmsg
- endif
- if error
- Xpath 1073741824 " X: 0
- endif
- break " discard error for $VIMNOERRTHROW
- endtry
-endwhile
-
-if exists("var1") || exists("var2") || exists("var3") ||
- \ !exists("var4") || var4 != 4711
- " The Xpath command does not accept 2^31 (negative); add explicitly:
- let Xpath = Xpath + 2147483648 " X: 0
- if exists("var1")
- Xout "var1 =" var1
- endif
- if exists("var2")
- Xout "var2 =" var2
- endif
- if exists("var3")
- Xout "var3 =" var3
- endif
- if !exists("var4")
- Xout "var4 unset"
- elseif var4 != 4711
- Xout "var4 =" var4
- endif
-endif
-
-unlet! error var1 var2 var3 var4
-delfunction THROW
-delfunction NAME
-delfunction ARG
-delfunction F
-
-Xcheck 212514423
-
-" Tests 69 to 75 were moved to test_trycatch.vim
-let Xtest = 76
-
-
-"-------------------------------------------------------------------------------
-" Test 76: Errors, interrupts, :throw during expression evaluation {{{1
-"
-" When a function call made during expression evaluation is aborted
-" due to an error inside a :try/:endtry region or due to an interrupt
-" or a :throw, the expression evaluation is aborted as well. No
-" message is displayed for the cancelled expression evaluation. On an
-" error not inside :try/:endtry, the expression evaluation continues.
-"-------------------------------------------------------------------------------
-
-XpathINIT
-
-if ExtraVim()
-
- let taken = ""
-
- function! ERR(n)
- let g:taken = g:taken . "E" . a:n
- asdf
- endfunction
-
- function! ERRabort(n) abort
- let g:taken = g:taken . "A" . a:n
- asdf
- endfunction " returns -1; may cause follow-up msg for illegal var/func name
-
- function! WRAP(n, arg)
- let g:taken = g:taken . "W" . a:n
- let g:saved_errmsg = v:errmsg
- return arg
- endfunction
-
- function! INT(n)
- let g:taken = g:taken . "I" . a:n
- "INTERRUPT9
- let dummy = 0
- endfunction
-
- function! THR(n)
- let g:taken = g:taken . "T" . a:n
- throw "should not be caught"
- endfunction
-
- function! CONT(n)
- let g:taken = g:taken . "C" . a:n
- endfunction
-
- function! MSG(n)
- let g:taken = g:taken . "M" . a:n
- let errmsg = (a:n >= 37 && a:n <= 44) ? g:saved_errmsg : v:errmsg
- let msgptn = (a:n >= 10 && a:n <= 27) ? "^$" : "asdf"
- if errmsg !~ msgptn
- let g:taken = g:taken . "x"
- Xout "Expr" a:n.": Unexpected message:" v:errmsg
- endif
- let v:errmsg = ""
- let g:saved_errmsg = ""
- endfunction
-
- let v:errmsg = ""
-
- try
- let t = 1
- XloopINIT 1 2
- while t <= 9
- Xloop 1 " X: 511
- try
- if t == 1
- let v{ERR(t) + CONT(t)} = 0
- elseif t == 2
- let v{ERR(t) + CONT(t)}
- elseif t == 3
- let var = exists('v{ERR(t) + CONT(t)}')
- elseif t == 4
- unlet v{ERR(t) + CONT(t)}
- elseif t == 5
- function F{ERR(t) + CONT(t)}()
- endfunction
- elseif t == 6
- function F{ERR(t) + CONT(t)}
- elseif t == 7
- let var = exists('*F{ERR(t) + CONT(t)}')
- elseif t == 8
- delfunction F{ERR(t) + CONT(t)}
- elseif t == 9
- let var = ERR(t) + CONT(t)
- endif
- catch /asdf/
- " v:errmsg is not set when the error message is converted to an
- " exception. Set it to the original error message.
- let v:errmsg = substitute(v:exception, '^Vim:', '', "")
- catch /^Vim\((\a\+)\)\=:/
- " An error exception has been thrown after the original error.
- let v:errmsg = ""
- finally
- call MSG(t)
- let t = t + 1
- XloopNEXT
- continue " discard an aborting error
- endtry
- endwhile
- catch /.*/
- Xpath 512 " X: 0
- Xout v:exception "in" ExtraVimThrowpoint()
- endtry
-
- try
- let t = 10
- XloopINIT 1024 2
- while t <= 18
- Xloop 1 " X: 1024 * 511
- try
- if t == 10
- let v{INT(t) + CONT(t)} = 0
- elseif t == 11
- let v{INT(t) + CONT(t)}
- elseif t == 12
- let var = exists('v{INT(t) + CONT(t)}')
- elseif t == 13
- unlet v{INT(t) + CONT(t)}
- elseif t == 14
- function F{INT(t) + CONT(t)}()
- endfunction
- elseif t == 15
- function F{INT(t) + CONT(t)}
- elseif t == 16
- let var = exists('*F{INT(t) + CONT(t)}')
- elseif t == 17
- delfunction F{INT(t) + CONT(t)}
- elseif t == 18
- let var = INT(t) + CONT(t)
- endif
- catch /^Vim\((\a\+)\)\=:\(Interrupt\)\@!/
- " An error exception has been triggered after the interrupt.
- let v:errmsg = substitute(v:exception,
- \ '^Vim\((\a\+)\)\=:', '', "")
- finally
- call MSG(t)
- let t = t + 1
- XloopNEXT
- continue " discard interrupt
- endtry
- endwhile
- catch /.*/
- Xpath 524288 " X: 0
- Xout v:exception "in" ExtraVimThrowpoint()
- endtry
-
- try
- let t = 19
- XloopINIT 1048576 2
- while t <= 27
- Xloop 1 " X: 1048576 * 511
- try
- if t == 19
- let v{THR(t) + CONT(t)} = 0
- elseif t == 20
- let v{THR(t) + CONT(t)}
- elseif t == 21
- let var = exists('v{THR(t) + CONT(t)}')
- elseif t == 22
- unlet v{THR(t) + CONT(t)}
- elseif t == 23
- function F{THR(t) + CONT(t)}()
- endfunction
- elseif t == 24
- function F{THR(t) + CONT(t)}
- elseif t == 25
- let var = exists('*F{THR(t) + CONT(t)}')
- elseif t == 26
- delfunction F{THR(t) + CONT(t)}
- elseif t == 27
- let var = THR(t) + CONT(t)
- endif
- catch /^Vim\((\a\+)\)\=:/
- " An error exception has been triggered after the :throw.
- let v:errmsg = substitute(v:exception,
- \ '^Vim\((\a\+)\)\=:', '', "")
- finally
- call MSG(t)
- let t = t + 1
- XloopNEXT
- continue " discard exception
- endtry
- endwhile
- catch /.*/
- Xpath 536870912 " X: 0
- Xout v:exception "in" ExtraVimThrowpoint()
- endtry
-
- let v{ERR(28) + CONT(28)} = 0
- call MSG(28)
- let v{ERR(29) + CONT(29)}
- call MSG(29)
- let var = exists('v{ERR(30) + CONT(30)}')
- call MSG(30)
- unlet v{ERR(31) + CONT(31)}
- call MSG(31)
- function F{ERR(32) + CONT(32)}()
- endfunction
- call MSG(32)
- function F{ERR(33) + CONT(33)}
- call MSG(33)
- let var = exists('*F{ERR(34) + CONT(34)}')
- call MSG(34)
- delfunction F{ERR(35) + CONT(35)}
- call MSG(35)
- let var = ERR(36) + CONT(36)
- call MSG(36)
-
- let saved_errmsg = ""
-
- let v{WRAP(37, ERRabort(37)) + CONT(37)} = 0
- call MSG(37)
- let v{WRAP(38, ERRabort(38)) + CONT(38)}
- call MSG(38)
- let var = exists('v{WRAP(39, ERRabort(39)) + CONT(39)}')
- call MSG(39)
- unlet v{WRAP(40, ERRabort(40)) + CONT(40)}
- call MSG(40)
- function F{WRAP(41, ERRabort(41)) + CONT(41)}()
- endfunction
- call MSG(41)
- function F{WRAP(42, ERRabort(42)) + CONT(42)}
- call MSG(42)
- let var = exists('*F{WRAP(43, ERRabort(43)) + CONT(43)}')
- call MSG(43)
- delfunction F{WRAP(44, ERRabort(44)) + CONT(44)}
- call MSG(44)
- let var = ERRabort(45) + CONT(45)
- call MSG(45)
-
- Xpath 1073741824 " X: 1073741824
-
- let expected = ""
- \ . "E1M1E2M2E3M3E4M4E5M5E6M6E7M7E8M8E9M9"
- \ . "I10M10I11M11I12M12I13M13I14M14I15M15I16M16I17M17I18M18"
- \ . "T19M19T20M20T21M21T22M22T23M23T24M24T25M25T26M26T27M27"
- \ . "E28C28M28E29C29M29E30C30M30E31C31M31E32C32M32E33C33M33"
- \ . "E34C34M34E35C35M35E36C36M36"
- \ . "A37W37C37M37A38W38C38M38A39W39C39M39A40W40C40M40A41W41C41M41"
- \ . "A42W42C42M42A43W43C43M43A44W44C44M44A45C45M45"
-
- if taken != expected
- " The Xpath command does not accept 2^31 (negative); display explicitly:
- exec "!echo 2147483648 >>" . g:ExtraVimResult
- " X: 0
- Xout "'taken' is" taken "instead of" expected
- if substitute(taken,
- \ '\(.*\)E3C3M3x\(.*\)E30C30M30x\(.*\)A39C39M39x\(.*\)',
- \ '\1E3M3\2E30C30M30\3A39C39M39\4',
- \ "") == expected
- Xout "Is ++emsg_skip for var with expr_start non-NULL"
- \ "in f_exists ok?"
- endif
- endif
-
- unlet! v var saved_errmsg taken expected
- call delete(WA_t5)
- call delete(WA_t14)
- call delete(WA_t23)
- unlet! WA_t5 WA_t14 WA_t23
- delfunction WA_t5
- delfunction WA_t14
- delfunction WA_t23
-
-endif
-
-Xcheck 1610087935
-
-
-"-------------------------------------------------------------------------------
-" Test 77: Errors, interrupts, :throw in name{brace-expression} {{{1
-"
-" When a function call made during evaluation of an expression in
-" braces as part of a function name after ":function" is aborted due
-" to an error inside a :try/:endtry region or due to an interrupt or
-" a :throw, the expression evaluation is aborted as well, and the
-" function definition is ignored, skipping all commands to the
-" ":endfunction". On an error not inside :try/:endtry, the expression
-" evaluation continues and the function gets defined, and can be
-" called and deleted.
-"-------------------------------------------------------------------------------
-
-XpathINIT
-
-XloopINIT 1 4
-
-function! ERR() abort
- Xloop 1 " X: 1 + 4 + 16 + 64
- asdf
-endfunction " returns -1
-
-function! OK()
- Xloop 2 " X: 2 * (1 + 4 + 16)
- let v:errmsg = ""
- return 0
-endfunction
-
-let v:errmsg = ""
-
-Xpath 4096 " X: 4096
-function! F{1 + ERR() + OK()}(arg)
- " F0 should be defined.
- if exists("a:arg") && a:arg == "calling"
- Xpath 8192 " X: 8192
- else
- Xpath 16384 " X: 0
- endif
-endfunction
-if v:errmsg != ""
- Xpath 32768 " X: 0
-endif
-XloopNEXT
-
-Xpath 65536 " X: 65536
-call F{1 + ERR() + OK()}("calling")
-if v:errmsg != ""
- Xpath 131072 " X: 0
-endif
-XloopNEXT
-
-Xpath 262144 " X: 262144
-delfunction F{1 + ERR() + OK()}
-if v:errmsg != ""
- Xpath 524288 " X: 0
-endif
-XloopNEXT
-
-try
- while 1
- let caught = 0
- try
- Xpath 1048576 " X: 1048576
- function! G{1 + ERR() + OK()}(arg)
- " G0 should not be defined, and the function body should be
- " skipped.
- if exists("a:arg") && a:arg == "calling"
- Xpath 2097152 " X: 0
- else
- Xpath 4194304 " X: 0
- endif
- " Use an unmatched ":finally" to check whether the body is
- " skipped when an error occurs in ERR(). This works whether or
- " not the exception is converted to an exception.
- finally
- Xpath 8388608 " X: 0
- Xout "Body of G{1 + ERR() + OK()}() not skipped"
- " Discard the aborting error or exception, and break the
- " while loop.
- break
- " End the try conditional and start a new one to avoid
- " ":catch after :finally" errors.
- endtry
- try
- Xpath 16777216 " X: 0
- endfunction
-
- " When the function was not defined, this won't be reached - whether
- " the body was skipped or not. When the function was defined, it
- " can be called and deleted here.
- Xpath 33554432 " X: 0
- Xout "G0() has been defined"
- XloopNEXT
- try
- call G{1 + ERR() + OK()}("calling")
- catch /.*/
- Xpath 67108864 " X: 0
- endtry
- Xpath 134217728 " X: 0
- XloopNEXT
- try
- delfunction G{1 + ERR() + OK()}
- catch /.*/
- Xpath 268435456 " X: 0
- endtry
- catch /asdf/
- " Jumped to when the function is not defined and the body is
- " skipped.
- let caught = 1
- catch /.*/
- Xpath 536870912 " X: 0
- finally
- if !caught && !$VIMNOERRTHROW
- Xpath 1073741824 " X: 0
- endif
- break " discard error for $VIMNOERRTHROW
- endtry " jumped to when the body is not skipped
- endwhile
-catch /.*/
- " The Xpath command does not accept 2^31 (negative); add explicitly:
- let Xpath = Xpath + 2147483648 " X: 0
- Xout "Body of G{1 + ERR() + OK()}() not skipped, exception caught"
- Xout v:exception "in" v:throwpoint
-endtry
-
-Xcheck 1388671
-
-
-"-------------------------------------------------------------------------------
-" Test 78: Messages on parsing errors in expression evaluation {{{1
-"
-" When an expression evaluation detects a parsing error, an error
-" message is given and converted to an exception, and the expression
-" evaluation is aborted.
-"-------------------------------------------------------------------------------
-
-XpathINIT
-
-if ExtraVim()
-
- let taken = ""
-
- function! F(n)
- let g:taken = g:taken . "F" . a:n
- endfunction
-
- function! MSG(n, enr, emsg)
- let g:taken = g:taken . "M" . a:n
- let english = v:lang == "C" || v:lang =~ '^[Ee]n'
- if a:enr == ""
- Xout "TODO: Add message number for:" a:emsg
- let v:errmsg = ":" . v:errmsg
- endif
- if v:errmsg !~ '^'.a:enr.':' || (english && v:errmsg !~ a:emsg)
- if v:errmsg == ""
- Xout "Expr" a:n.": Message missing."
- let g:taken = g:taken . "x"
- else
- let v:errmsg = escape(v:errmsg, '"')
- Xout "Expr" a:n.": Unexpected message:" v:errmsg
- Xout "Expected: " . a:enr . ': ' . a:emsg
- let g:taken = g:taken . "X"
- endif
- endif
- endfunction
-
- function! CONT(n)
- let g:taken = g:taken . "C" . a:n
- endfunction
-
- let v:errmsg = ""
- XloopINIT 1 2
-
- try
- let t = 1
- while t <= 14
- let g:taken = g:taken . "T" . t
- let v:errmsg = ""
- try
- let caught = 0
- if t == 1
- let v{novar + CONT(t)} = 0
- elseif t == 2
- let v{novar + CONT(t)}
- elseif t == 3
- let var = exists('v{novar + CONT(t)}')
- elseif t == 4
- unlet v{novar + CONT(t)}
- elseif t == 5
- function F{novar + CONT(t)}()
- endfunction
- elseif t == 6
- function F{novar + CONT(t)}
- elseif t == 7
- let var = exists('*F{novar + CONT(t)}')
- elseif t == 8
- delfunction F{novar + CONT(t)}
- elseif t == 9
- echo novar + CONT(t)
- elseif t == 10
- echo v{novar + CONT(t)}
- elseif t == 11
- echo F{novar + CONT(t)}
- elseif t == 12
- let var = novar + CONT(t)
- elseif t == 13
- let var = v{novar + CONT(t)}
- elseif t == 14
- let var = F{novar + CONT(t)}()
- endif
- catch /^Vim\((\a\+)\)\=:/
- " v:errmsg is not set when the error message is converted to an
- " exception. Set it to the original error message.
- let v:errmsg = substitute(v:exception,
- \ '^Vim\((\a\+)\)\=:', '', "")
- let caught = 1
- finally
- if t <= 8 && t != 3 && t != 7
- call MSG(t, 'E475', 'Invalid argument\>')
- else
- if !caught " no error exceptions ($VIMNOERRTHROW set)
- call MSG(t, 'E15', "Invalid expression")
- else
- call MSG(t, 'E121', "Undefined variable")
- endif
- endif
- let t = t + 1
- XloopNEXT
- continue " discard an aborting error
- endtry
- endwhile
- catch /.*/
- Xloop 1 " X: 0
- Xout t.":" v:exception "in" ExtraVimThrowpoint()
- endtry
-
- function! T(n, expr, enr, emsg)
- try
- let g:taken = g:taken . "T" . a:n
- let v:errmsg = ""
- try
- let caught = 0
- execute "let var = " . a:expr
- catch /^Vim\((\a\+)\)\=:/
- " v:errmsg is not set when the error message is converted to an
- " exception. Set it to the original error message.
- let v:errmsg = substitute(v:exception,
- \ '^Vim\((\a\+)\)\=:', '', "")
- let caught = 1
- finally
- if !caught " no error exceptions ($VIMNOERRTHROW set)
- call MSG(a:n, 'E15', "Invalid expression")
- else
- call MSG(a:n, a:enr, a:emsg)
- endif
- XloopNEXT
- " Discard an aborting error:
- return
- endtry
- catch /.*/
- Xloop 1 " X: 0
- Xout a:n.":" v:exception "in" ExtraVimThrowpoint()
- endtry
- endfunction
-
- call T(15, 'Nofunc() + CONT(15)', 'E117', "Unknown function")
- call T(16, 'F(1 2 + CONT(16))', 'E116', "Invalid arguments")
- call T(17, 'F(1, 2) + CONT(17)', 'E118', "Too many arguments")
- call T(18, 'F() + CONT(18)', 'E119', "Not enough arguments")
- call T(19, '{(1} + CONT(19)', 'E110', "Missing ')'")
- call T(20, '("abc"[1) + CONT(20)', 'E111', "Missing ']'")
- call T(21, '(1 +) + CONT(21)', 'E15', "Invalid expression")
- call T(22, '1 2 + CONT(22)', 'E15', "Invalid expression")
- call T(23, '(1 ? 2) + CONT(23)', 'E109', "Missing ':' after '?'")
- call T(24, '("abc) + CONT(24)', 'E114', "Missing quote")
- call T(25, "('abc) + CONT(25)", 'E115', "Missing quote")
- call T(26, '& + CONT(26)', 'E112', "Option name missing")
- call T(27, '&asdf + CONT(27)', 'E113', "Unknown option")
-
- Xpath 134217728 " X: 134217728
-
- let expected = ""
- \ . "T1M1T2M2T3M3T4M4T5M5T6M6T7M7T8M8T9M9T10M10T11M11T12M12T13M13T14M14"
- \ . "T15M15T16M16T17M17T18M18T19M19T20M20T21M21T22M22T23M23T24M24T25M25"
- \ . "T26M26T27M27"
-
- if taken != expected
- Xpath 268435456 " X: 0
- Xout "'taken' is" taken "instead of" expected
- if substitute(taken, '\(.*\)T3M3x\(.*\)', '\1T3M3\2', "") == expected
- Xout "Is ++emsg_skip for var with expr_start non-NULL"
- \ "in f_exists ok?"
- endif
- endif
-
- unlet! var caught taken expected
- call delete(WA_t5)
- unlet! WA_t5
- delfunction WA_t5
-
-endif
-
-Xcheck 134217728
-
-
-"-------------------------------------------------------------------------------
-" Test 79: Throwing one of several errors for the same command {{{1
-"
-" When several errors appear in a row (for instance during expression
-" evaluation), the first as the most specific one is used when
-" throwing an error exception. If, however, a syntax error is
-" detected afterwards, this one is used for the error exception.
-" On a syntax error, the next command is not executed, on a normal
-" error, however, it is (relevant only in a function without the
-" "abort" flag). v:errmsg is not set.
-"
-" If throwing error exceptions is configured off, v:errmsg is always
-" set to the latest error message, that is, to the more general
-" message or the syntax error, respectively.
-"-------------------------------------------------------------------------------
-
-XpathINIT
-
-XloopINIT 1 2
-
-function! NEXT(cmd)
- exec a:cmd . " | Xloop 1"
-endfunction
-
-call NEXT('echo novar') " X: 1 * 1 (checks nextcmd)
-XloopNEXT
-call NEXT('let novar #') " X: 0 * 2 (skips nextcmd)
-XloopNEXT
-call NEXT('unlet novar #') " X: 0 * 4 (skips nextcmd)
-XloopNEXT
-call NEXT('let {novar}') " X: 0 * 8 (skips nextcmd)
-XloopNEXT
-call NEXT('unlet{ novar}') " X: 0 * 16 (skips nextcmd)
-
-function! EXEC(cmd)
- exec a:cmd
-endfunction
-
-function! MATCH(expected, msg, enr, emsg)
- let msg = a:msg
- if a:enr == ""
- Xout "TODO: Add message number for:" a:emsg
- let msg = ":" . msg
- endif
- let english = v:lang == "C" || v:lang =~ '^[Ee]n'
- if msg !~ '^'.a:enr.':' || (english && msg !~ a:emsg)
- let match = 0
- if a:expected " no match although expected
- if a:msg == ""
- Xout "Message missing."
- else
- let msg = escape(msg, '"')
- Xout "Unexpected message:" msg
- Xout "Expected:" a:enr . ": " . a:emsg
- endif
- endif
- else
- let match = 1
- if !a:expected " match although not expected
- let msg = escape(msg, '"')
- Xout "Unexpected message:" msg
- Xout "Expected none."
- endif
- endif
- return match
-endfunction
-
-try
-
- while 1 " dummy loop
- try
- let v:errmsg = ""
- let caught = 0
- let thrmsg = ""
- call EXEC('echo novar') " normal error
- catch /^Vim\((\a\+)\)\=:/
- let caught = 1
- let thrmsg = substitute(v:exception, '^Vim\((\a\+)\)\=:', '', "")
- finally
- Xpath 32 " X: 32
- if !caught
- if !$VIMNOERRTHROW
- Xpath 64 " X: 0
- endif
- elseif !MATCH(1, thrmsg, 'E121', "Undefined variable")
- \ || v:errmsg != ""
- Xpath 128 " X: 0
- endif
- if !caught && !MATCH(1, v:errmsg, 'E15', "Invalid expression")
- Xpath 256 " X: 0
- endif
- break " discard error if $VIMNOERRTHROW == 1
- endtry
- endwhile
-
- Xpath 512 " X: 512
- let cmd = "let"
- XloopINIT 1024 32
- while cmd != ""
- try
- let v:errmsg = ""
- let caught = 0
- let thrmsg = ""
- call EXEC(cmd . ' novar #') " normal plus syntax error
- catch /^Vim\((\a\+)\)\=:/
- let caught = 1
- let thrmsg = substitute(v:exception, '^Vim\((\a\+)\)\=:', '', "")
- finally
- Xloop 1 " X: 1024 * (1 + 32)
- if !caught
- if !$VIMNOERRTHROW
- Xloop 2 " X: 0
- endif
- else
- if cmd == "let"
- let match = MATCH(0, thrmsg, 'E121', "Undefined variable")
- elseif cmd == "unlet"
- let match = MATCH(0, thrmsg, 'E108', "No such variable")
- endif
- if match " normal error
- Xloop 4 " X: 0
- endif
- if !MATCH(1, thrmsg, 'E488', "Trailing characters")
- \|| v:errmsg != ""
- " syntax error
- Xloop 8 " X: 0
- endif
- endif
- if !caught && !MATCH(1, v:errmsg, 'E488', "Trailing characters")
- " last error
- Xloop 16 " X: 0
- endif
- if cmd == "let"
- let cmd = "unlet"
- else
- let cmd = ""
- endif
- XloopNEXT
- continue " discard error if $VIMNOERRTHROW == 1
- endtry
- endwhile
-
- Xpath 1048576 " X: 1048576
- let cmd = "let"
- XloopINIT 2097152 32
- while cmd != ""
- try
- let v:errmsg = ""
- let caught = 0
- let thrmsg = ""
- call EXEC(cmd . ' {novar}') " normal plus syntax error
- catch /^Vim\((\a\+)\)\=:/
- let caught = 1
- let thrmsg = substitute(v:exception, '^Vim\((\a\+)\)\=:', '', "")
- finally
- Xloop 1 " X: 2097152 * (1 + 32)
- if !caught
- if !$VIMNOERRTHROW
- Xloop 2 " X: 0
- endif
- else
- if MATCH(0, thrmsg, 'E121', "Undefined variable") " normal error
- Xloop 4 " X: 0
- endif
- if !MATCH(1, thrmsg, 'E475', 'Invalid argument\>')
- \ || v:errmsg != "" " syntax error
- Xloop 8 " X: 0
- endif
- endif
- if !caught && !MATCH(1, v:errmsg, 'E475', 'Invalid argument\>')
- " last error
- Xloop 16 " X: 0
- endif
- if cmd == "let"
- let cmd = "unlet"
- else
- let cmd = ""
- endif
- XloopNEXT
- continue " discard error if $VIMNOERRTHROW == 1
- endtry
- endwhile
-
-catch /.*/
- " The Xpath command does not accept 2^31 (negative); add explicitly:
- let Xpath = Xpath + 2147483648 " X: 0
- Xout v:exception "in" v:throwpoint
-endtry
-
-unlet! next_command thrmsg match
-delfunction NEXT
-delfunction EXEC
-delfunction MATCH
-
-Xcheck 70288929
-
-
-"-------------------------------------------------------------------------------
-" Test 80: Syntax error in expression for illegal :elseif {{{1
-"
-" If there is a syntax error in the expression after an illegal
-" :elseif, an error message is given (or an error exception thrown)
-" for the illegal :elseif rather than the expression error.
-"-------------------------------------------------------------------------------
-
-XpathINIT
-
-function! MSG(enr, emsg)
- let english = v:lang == "C" || v:lang =~ '^[Ee]n'
- if a:enr == ""
- Xout "TODO: Add message number for:" a:emsg
- let v:errmsg = ":" . v:errmsg
- endif
- let match = 1
- if v:errmsg !~ '^'.a:enr.':' || (english && v:errmsg !~ a:emsg)
- let match = 0
- if v:errmsg == ""
- Xout "Message missing."
- else
- let v:errmsg = escape(v:errmsg, '"')
- Xout "Unexpected message:" v:errmsg
- endif
- endif
- return match
-endfunction
-
-let v:errmsg = ""
-if 0
-else
-elseif 1 ||| 2
-endif
-Xpath 1 " X: 1
-if !MSG('E584', ":elseif after :else")
- Xpath 2 " X: 0
-endif
-
-let v:errmsg = ""
-if 1
-else
-elseif 1 ||| 2
-endif
-Xpath 4 " X: 4
-if !MSG('E584', ":elseif after :else")
- Xpath 8 " X: 0
-endif
-
-let v:errmsg = ""
-elseif 1 ||| 2
-Xpath 16 " X: 16
-if !MSG('E582', ":elseif without :if")
- Xpath 32 " X: 0
-endif
-
-let v:errmsg = ""
-while 1
- elseif 1 ||| 2
-endwhile
-Xpath 64 " X: 64
-if !MSG('E582', ":elseif without :if")
- Xpath 128 " X: 0
-endif
-
-while 1
- try
- try
- let v:errmsg = ""
- let caught = 0
- if 0
- else
- elseif 1 ||| 2
- endif
- catch /^Vim\((\a\+)\)\=:/
- let caught = 1
- let v:errmsg = substitute(v:exception, '^Vim\((\a\+)\)\=:', '', "")
- finally
- Xpath 256 " X: 256
- if !caught && !$VIMNOERRTHROW
- Xpath 512 " X: 0
- endif
- if !MSG('E584', ":elseif after :else")
- Xpath 1024 " X: 0
- endif
- endtry
- catch /.*/
- Xpath 2048 " X: 0
- Xout v:exception "in" v:throwpoint
- finally
- break " discard error for $VIMNOERRTHROW
- endtry
-endwhile
-
-while 1
- try
- try
- let v:errmsg = ""
- let caught = 0
- if 1
- else
- elseif 1 ||| 2
- endif
- catch /^Vim\((\a\+)\)\=:/
- let caught = 1
- let v:errmsg = substitute(v:exception, '^Vim\((\a\+)\)\=:', '', "")
- finally
- Xpath 4096 " X: 4096
- if !caught && !$VIMNOERRTHROW
- Xpath 8192 " X: 0
- endif
- if !MSG('E584', ":elseif after :else")
- Xpath 16384 " X: 0
- endif
- endtry
- catch /.*/
- Xpath 32768 " X: 0
- Xout v:exception "in" v:throwpoint
- finally
- break " discard error for $VIMNOERRTHROW
- endtry
-endwhile
-
-while 1
- try
- try
- let v:errmsg = ""
- let caught = 0
- elseif 1 ||| 2
- catch /^Vim\((\a\+)\)\=:/
- let caught = 1
- let v:errmsg = substitute(v:exception, '^Vim\((\a\+)\)\=:', '', "")
- finally
- Xpath 65536 " X: 65536
- if !caught && !$VIMNOERRTHROW
- Xpath 131072 " X: 0
- endif
- if !MSG('E582', ":elseif without :if")
- Xpath 262144 " X: 0
- endif
- endtry
- catch /.*/
- Xpath 524288 " X: 0
- Xout v:exception "in" v:throwpoint
- finally
- break " discard error for $VIMNOERRTHROW
- endtry
-endwhile
-
-while 1
- try
- try
- let v:errmsg = ""
- let caught = 0
- while 1
- elseif 1 ||| 2
- endwhile
- catch /^Vim\((\a\+)\)\=:/
- let caught = 1
- let v:errmsg = substitute(v:exception, '^Vim\((\a\+)\)\=:', '', "")
- finally
- Xpath 1048576 " X: 1048576
- if !caught && !$VIMNOERRTHROW
- Xpath 2097152 " X: 0
- endif
- if !MSG('E582', ":elseif without :if")
- Xpath 4194304 " X: 0
- endif
- endtry
- catch /.*/
- Xpath 8388608 " X: 0
- Xout v:exception "in" v:throwpoint
- finally
- break " discard error for $VIMNOERRTHROW
- endtry
-endwhile
-
-Xpath 16777216 " X: 16777216
-
-unlet! caught
-delfunction MSG
-
-Xcheck 17895765
-
-
-"-------------------------------------------------------------------------------
-" Test 81: Discarding exceptions after an error or interrupt {{{1
-"
-" When an exception is thrown from inside a :try conditional without
-" :catch and :finally clauses and an error or interrupt occurs before
-" the :endtry is reached, the exception is discarded.
-"-------------------------------------------------------------------------------
-
-XpathINIT
-
-if ExtraVim()
- try
- Xpath 1 " X: 1
- try
- Xpath 2 " X: 2
- throw "arrgh"
- Xpath 4 " X: 0
-" if 1
- Xpath 8 " X: 0
- " error after :throw: missing :endif
- endtry
- Xpath 16 " X: 0
- catch /arrgh/
- Xpath 32 " X: 0
- endtry
- Xpath 64 " X: 0
-endif
-
-if ExtraVim()
- try
- Xpath 128 " X: 128
- try
- Xpath 256 " X: 256
- throw "arrgh"
- Xpath 512 " X: 0
- endtry " INTERRUPT
- Xpath 1024 " X: 0
- catch /arrgh/
- Xpath 2048 " X: 0
- endtry
- Xpath 4096 " X: 0
-endif
-
-Xcheck 387
-
-
-"-------------------------------------------------------------------------------
-" Test 82: Ignoring :catch clauses after an error or interrupt {{{1
-"
-" When an exception is thrown and an error or interrupt occurs before
-" the matching :catch clause is reached, the exception is discarded
-" and the :catch clause is ignored (also for the error or interrupt
-" exception being thrown then).
-"-------------------------------------------------------------------------------
-
-XpathINIT
-
-if ExtraVim()
- try
- try
- Xpath 1 " X: 1
- throw "arrgh"
- Xpath 2 " X: 0
-" if 1
- Xpath 4 " X: 0
- " error after :throw: missing :endif
- catch /.*/
- Xpath 8 " X: 0
- Xout v:exception "in" ExtraVimThrowpoint()
- catch /.*/
- Xpath 16 " X: 0
- Xout v:exception "in" ExtraVimThrowpoint()
- endtry
- Xpath 32 " X: 0
- catch /arrgh/
- Xpath 64 " X: 0
- endtry
- Xpath 128 " X: 0
-endif
-
-if ExtraVim()
- function! E()
- try
- try
- Xpath 256 " X: 256
- throw "arrgh"
- Xpath 512 " X: 0
-" if 1
- Xpath 1024 " X: 0
- " error after :throw: missing :endif
- catch /.*/
- Xpath 2048 " X: 0
- Xout v:exception "in" ExtraVimThrowpoint()
- catch /.*/
- Xpath 4096 " X: 0
- Xout v:exception "in" ExtraVimThrowpoint()
- endtry
- Xpath 8192 " X: 0
- catch /arrgh/
- Xpath 16384 " X: 0
- endtry
- endfunction
-
- call E()
- Xpath 32768 " X: 0
-endif
-
-if ExtraVim()
- try
- try
- Xpath 65536 " X: 65536
- throw "arrgh"
- Xpath 131072 " X: 0
- catch /.*/ "INTERRUPT
- Xpath 262144 " X: 0
- Xout v:exception "in" ExtraVimThrowpoint()
- catch /.*/
- Xpath 524288 " X: 0
- Xout v:exception "in" ExtraVimThrowpoint()
- endtry
- Xpath 1048576 " X: 0
- catch /arrgh/
- Xpath 2097152 " X: 0
- endtry
- Xpath 4194304 " X: 0
-endif
-
-if ExtraVim()
- function I()
- try
- try
- Xpath 8388608 " X: 8388608
- throw "arrgh"
- Xpath 16777216 " X: 0
- catch /.*/ "INTERRUPT
- Xpath 33554432 " X: 0
- Xout v:exception "in" ExtraVimThrowpoint()
- catch /.*/
- Xpath 67108864 " X: 0
- Xout v:exception "in" ExtraVimThrowpoint()
- endtry
- Xpath 134217728 " X: 0
- catch /arrgh/
- Xpath 268435456 " X: 0
- endtry
- endfunction
-
- call I()
- Xpath 536870912 " X: 0
-endif
-
-Xcheck 8454401
-
-
-"-------------------------------------------------------------------------------
-" Test 83: Executing :finally clauses after an error or interrupt {{{1
-"
-" When an exception is thrown and an error or interrupt occurs before
-" the :finally of the innermost :try is reached, the exception is
-" discarded and the :finally clause is executed.
-"-------------------------------------------------------------------------------
-
-XpathINIT
-
-if ExtraVim()
- try
- Xpath 1 " X: 1
- try
- Xpath 2 " X: 2
- throw "arrgh"
- Xpath 4 " X: 0
-" if 1
- Xpath 8 " X: 0
- " error after :throw: missing :endif
- finally
- Xpath 16 " X: 16
- endtry
- Xpath 32 " X: 0
- catch /arrgh/
- Xpath 64 " X: 0
- endtry
- Xpath 128 " X: 0
-endif
-
-if ExtraVim()
- try
- Xpath 256 " X: 256
- try
- Xpath 512 " X: 512
- throw "arrgh"
- Xpath 1024 " X: 0
- finally "INTERRUPT
- Xpath 2048 " X: 2048
- endtry
- Xpath 4096 " X: 0
- catch /arrgh/
- Xpath 8192 " X: 0
- endtry
- Xpath 16384 " X: 0
-endif
-
-Xcheck 2835
-
-
-"-------------------------------------------------------------------------------
-" Test 84: Exceptions in autocommand sequences. {{{1
-"
-" When an exception occurs in a sequence of autocommands for
-" a specific event, the rest of the sequence is not executed. The
-" command that triggered the autocommand execution aborts, and the
-" exception is propagated to the caller.
-"
-" For the FuncUndefined event under a function call expression or
-" :call command, the function is not executed, even when it has
-" been defined by the autocommands before the exception occurred.
-"-------------------------------------------------------------------------------
-
-XpathINIT
-
-if ExtraVim()
-
- function! INT()
- "INTERRUPT
- let dummy = 0
- endfunction
-
- aug TMP
- autocmd!
-
- autocmd User x1 Xpath 1 " X: 1
- autocmd User x1 throw "x1"
- autocmd User x1 Xpath 2 " X: 0
-
- autocmd User x2 Xpath 4 " X: 4
- autocmd User x2 asdf
- autocmd User x2 Xpath 8 " X: 0
-
- autocmd User x3 Xpath 16 " X: 16
- autocmd User x3 call INT()
- autocmd User x3 Xpath 32 " X: 0
-
- autocmd FuncUndefined U1 function! U1()
- autocmd FuncUndefined U1 Xpath 64 " X: 0
- autocmd FuncUndefined U1 endfunction
- autocmd FuncUndefined U1 Xpath 128 " X: 128
- autocmd FuncUndefined U1 throw "U1"
- autocmd FuncUndefined U1 Xpath 256 " X: 0
-
- autocmd FuncUndefined U2 function! U2()
- autocmd FuncUndefined U2 Xpath 512 " X: 0
- autocmd FuncUndefined U2 endfunction
- autocmd FuncUndefined U2 Xpath 1024 " X: 1024
- autocmd FuncUndefined U2 ASDF
- autocmd FuncUndefined U2 Xpath 2048 " X: 0
-
- autocmd FuncUndefined U3 function! U3()
- autocmd FuncUndefined U3 Xpath 4096 " X: 0
- autocmd FuncUndefined U3 endfunction
- autocmd FuncUndefined U3 Xpath 8192 " X: 8192
- autocmd FuncUndefined U3 call INT()
- autocmd FuncUndefined U3 Xpath 16384 " X: 0
- aug END
-
- try
- try
- Xpath 32768 " X: 32768
- doautocmd User x1
- catch /x1/
- Xpath 65536 " X: 65536
- endtry
-
- while 1
- try
- Xpath 131072 " X: 131072
- let caught = 0
- doautocmd User x2
- catch /asdf/
- let caught = 1
- finally
- Xpath 262144 " X: 262144
- if !caught && !$VIMNOERRTHROW
- Xpath 524288 " X: 0
- " Propagate uncaught error exception,
- else
- " ... but break loop for caught error exception,
- " or discard error and break loop if $VIMNOERRTHROW
- break
- endif
- endtry
- endwhile
-
- while 1
- try
- Xpath 1048576 " X: 1048576
- let caught = 0
- doautocmd User x3
- catch /Vim:Interrupt/
- let caught = 1
- finally
- Xpath 2097152 " X: 2097152
- if !caught && !$VIMNOINTTHROW
- Xpath 4194304 " X: 0
- " Propagate uncaught interrupt exception,
- else
- " ... but break loop for caught interrupt exception,
- " or discard interrupt and break loop if $VIMNOINTTHROW
- break
- endif
- endtry
- endwhile
-
- if exists("*U1") | delfunction U1 | endif
- if exists("*U2") | delfunction U2 | endif
- if exists("*U3") | delfunction U3 | endif
-
- try
- Xpath 8388608 " X: 8388608
- call U1()
- catch /U1/
- Xpath 16777216 " X: 16777216
- endtry
-
- while 1
- try
- Xpath 33554432 " X: 33554432
- let caught = 0
- call U2()
- catch /ASDF/
- let caught = 1
- finally
- Xpath 67108864 " X: 67108864
- if !caught && !$VIMNOERRTHROW
- Xpath 134217728 " X: 0
- " Propagate uncaught error exception,
- else
- " ... but break loop for caught error exception,
- " or discard error and break loop if $VIMNOERRTHROW
- break
- endif
- endtry
- endwhile
-
- while 1
- try
- Xpath 268435456 " X: 268435456
- let caught = 0
- call U3()
- catch /Vim:Interrupt/
- let caught = 1
- finally
- Xpath 536870912 " X: 536870912
- if !caught && !$VIMNOINTTHROW
- Xpath 1073741824 " X: 0
- " Propagate uncaught interrupt exception,
- else
- " ... but break loop for caught interrupt exception,
- " or discard interrupt and break loop if $VIMNOINTTHROW
- break
- endif
- endtry
- endwhile
- catch /.*/
- " The Xpath command does not accept 2^31 (negative); display explicitly:
- exec "!echo 2147483648 >>" . g:ExtraVimResult
- Xout "Caught" v:exception "in" v:throwpoint
- endtry
-
- unlet caught
- delfunction INT
- delfunction U1
- delfunction U2
- delfunction U3
- au! TMP
- aug! TMP
-endif
-
-Xcheck 934782101
-
-
-"-------------------------------------------------------------------------------
-" Test 85: Error exceptions in autocommands for I/O command events {{{1
-"
-" When an I/O command is inside :try/:endtry, autocommands to be
-" executed after it should be skipped on an error (exception) in the
-" command itself or in autocommands to be executed before the command.
-" In the latter case, the I/O command should not be executed either.
-" Example 1: BufWritePre, :write, BufWritePost
-" Example 2: FileReadPre, :read, FileReadPost.
-"-------------------------------------------------------------------------------
-
-XpathINIT
-
-function! MSG(enr, emsg)
- let english = v:lang == "C" || v:lang =~ '^[Ee]n'
- if a:enr == ""
- Xout "TODO: Add message number for:" a:emsg
- let v:errmsg = ":" . v:errmsg
- endif
- let match = 1
- if v:errmsg !~ '^'.a:enr.':' || (english && v:errmsg !~ a:emsg)
- let match = 0
- if v:errmsg == ""
- Xout "Message missing."
- else
- let v:errmsg = escape(v:errmsg, '"')
- Xout "Unexpected message:" v:errmsg
- endif
- endif
- return match
-endfunction
-
-" Remove the autocommands for the events specified as arguments in all used
-" autogroups.
-function Delete_autocommands(...)
- let augfile = tempname()
- while 1
- try
- exec "redir >" . augfile
- aug
- redir END
- exec "edit" augfile
- g/^$/d
- norm G$
- let wrap = "w"
- while search('\%( \|^\)\@<=.\{-}\%( \)\@=', wrap) > 0
- let wrap = "W"
- exec "norm y/ \n"
- let argno = 1
- while argno <= a:0
- exec "au!" escape(@", " ") a:{argno}
- let argno = argno + 1
- endwhile
- endwhile
- catch /.*/
- finally
- bwipeout!
- call delete(augfile)
- break " discard errors for $VIMNOERRTHROW
- endtry
- endwhile
-endfunction
-
-call Delete_autocommands("BufWritePre", "BufWritePost")
-
-while 1
- try
- try
- let post = 0
- aug TMP
- au! BufWritePost * let post = 1
- aug END
- let caught = 0
- write /n/o/n/e/x/i/s/t/e/n/t
- catch /^Vim(write):/
- let caught = 1
- let v:errmsg = substitute(v:exception, '^Vim(write):', '', "")
- finally
- Xpath 1 " X: 1
- if !caught && !$VIMNOERRTHROW
- Xpath 2 " X: 0
- endif
- let v:errmsg = substitute(v:errmsg, '^"/n/o/n/e/x/i/s/t/e/n/t" ',
- \ '', "")
- if !MSG('E212', "Can't open file for writing")
- Xpath 4 " X: 0
- endif
- if post
- Xpath 8 " X: 0
- Xout "BufWritePost commands executed after write error"
- endif
- au! TMP
- aug! TMP
- endtry
- catch /.*/
- Xpath 16 " X: 0
- Xout v:exception "in" v:throwpoint
- finally
- break " discard error for $VIMNOERRTHROW
- endtry
-endwhile
-
-while 1
- try
- try
- let post = 0
- aug TMP
- au! BufWritePre * asdf
- au! BufWritePost * let post = 1
- aug END
- let tmpfile = tempname()
- let caught = 0
- exec "write" tmpfile
- catch /^Vim\((write)\)\=:/
- let caught = 1
- let v:errmsg = substitute(v:exception, '^Vim\((write)\)\=:', '', "")
- finally
- Xpath 32 " X: 32
- if !caught && !$VIMNOERRTHROW
- Xpath 64 " X: 0
- endif
- let v:errmsg = substitute(v:errmsg, '^"'.tmpfile.'" ', '', "")
- if !MSG('E492', "Not an editor command")
- Xpath 128 " X: 0
- endif
- if filereadable(tmpfile)
- Xpath 256 " X: 0
- Xout ":write command not suppressed after BufWritePre error"
- endif
- if post
- Xpath 512 " X: 0
- Xout "BufWritePost commands executed after BufWritePre error"
- endif
- au! TMP
- aug! TMP
- endtry
- catch /.*/
- Xpath 1024 " X: 0
- Xout v:exception "in" v:throwpoint
- finally
- break " discard error for $VIMNOERRTHROW
- endtry
-endwhile
-
-call delete(tmpfile)
-
-call Delete_autocommands("BufWritePre", "BufWritePost",
- \ "BufReadPre", "BufReadPost", "FileReadPre", "FileReadPost")
-
-while 1
- try
- try
- let post = 0
- aug TMP
- au! FileReadPost * let post = 1
- aug END
- let caught = 0
- read /n/o/n/e/x/i/s/t/e/n/t
- catch /^Vim(read):/
- let caught = 1
- let v:errmsg = substitute(v:exception, '^Vim(read):', '', "")
- finally
- Xpath 2048 " X: 2048
- if !caught && !$VIMNOERRTHROW
- Xpath 4096 " X: 0
- endif
- let v:errmsg = substitute(v:errmsg, ' /n/o/n/e/x/i/s/t/e/n/t$',
- \ '', "")
- if !MSG('E484', "Can't open file")
- Xpath 8192 " X: 0
- endif
- if post
- Xpath 16384 " X: 0
- Xout "FileReadPost commands executed after write error"
- endif
- au! TMP
- aug! TMP
- endtry
- catch /.*/
- Xpath 32768 " X: 0
- Xout v:exception "in" v:throwpoint
- finally
- break " discard error for $VIMNOERRTHROW
- endtry
-endwhile
-
-while 1
- try
- let infile = tempname()
- let tmpfile = tempname()
- exec "!echo XYZ >" . infile
- exec "edit" tmpfile
- try
- Xpath 65536 " X: 65536
- try
- let post = 0
- aug TMP
- au! FileReadPre * asdf
- au! FileReadPost * let post = 1
- aug END
- let caught = 0
- exec "0read" infile
- catch /^Vim\((read)\)\=:/
- let caught = 1
- let v:errmsg = substitute(v:exception, '^Vim\((read)\)\=:', '',
- \ "")
- finally
- Xpath 131072 " X: 131072
- if !caught && !$VIMNOERRTHROW
- Xpath 262144 " X: 0
- endif
- let v:errmsg = substitute(v:errmsg, ' '.infile.'$', '', "")
- if !MSG('E492', "Not an editor command")
- Xpath 524288 " X: 0
- endif
- if getline("1") == "XYZ"
- Xpath 1048576 " X: 0
- Xout ":read command not suppressed after FileReadPre error"
- endif
- if post
- Xpath 2097152 " X: 0
- Xout "FileReadPost commands executed after " .
- \ "FileReadPre error"
- endif
- au! TMP
- aug! TMP
- endtry
- finally
- bwipeout!
- endtry
- catch /.*/
- Xpath 4194304 " X: 0
- Xout v:exception "in" v:throwpoint
- finally
- break " discard error for $VIMNOERRTHROW
- endtry
-endwhile
-
-call delete(infile)
-call delete(tmpfile)
-unlet! caught post infile tmpfile
-delfunction MSG
-delfunction Delete_autocommands
-
-Xcheck 198689
-
-"-------------------------------------------------------------------------------
-" Test 86: setloclist crash {{{1
-"
-" Executing a setloclist() on BufUnload shouldn't crash Vim
-"-------------------------------------------------------------------------------
-
-func F
- au BufUnload * :call setloclist(0, [{'bufnr':1, 'lnum':1, 'col':1, 'text': 'tango down'}])
-
- :lvimgrep /.*/ *.mak
-endfunc
-
-XpathINIT
-
-ExecAsScript F
-
-delfunction F
-Xout "No Crash for vimgrep on BufUnload"
-Xcheck 0
-
-" Test 87 was moved to test_vimscript.vim
-let Xtest = 88
-
-
-"-------------------------------------------------------------------------------
-" Test 88: $VIMNOERRTHROW and $VIMNOINTTHROW support {{{1
-"
-" It is possible to configure Vim for throwing exceptions on error
-" or interrupt, controlled by variables $VIMNOERRTHROW and
-" $VIMNOINTTHROW. This is just for increasing the number of tests.
-" All tests here should run for all four combinations of setting
-" these variables to 0 or 1. The variables are intended for the
-" development phase only. In the final release, Vim should be
-" configured to always use error and interrupt exceptions.
-"
-" The test result is "OK",
-"
-" - if the $VIMNOERRTHROW and the $VIMNOINTTHROW control are not
-" configured and exceptions are thrown on error and on
-" interrupt.
-"
-" - if the $VIMNOERRTHROW or the $VIMNOINTTHROW control is
-" configured and works as intended.
-"
-" What actually happens, is shown in the test output.
-"
-" Otherwise, the test result is "FAIL", and the test output describes
-" the problem.
-"
-" IMPORTANT: This must be the last test because it sets $VIMNOERRTHROW and
-" $VIMNOINTTHROW.
-"-------------------------------------------------------------------------------
-
-XpathINIT
-
-if ExtraVim()
-
- function! ThrowOnError()
- XloopNEXT
- let caught = 0
- try
- Xloop 1 " X: 1 + 8 + 64
- asdf
- catch /.*/
- let caught = 1 " error exception caught
- finally
- Xloop 2 " X: 2 + 16 + 128
- return caught " discard aborting error
- endtry
- Xloop 4 " X: 0
- endfunction
-
- let quits_skipped = 0
-
- function! ThrowOnInterrupt()
- XloopNEXT
- let caught = 0
- try
- Xloop 1 " X: (1 + 8 + 64) * 512
- "INTERRUPT3
- let dummy = 0
- let g:quits_skipped = g:quits_skipped + 1
- catch /.*/
- let caught = 1 " interrupt exception caught
- finally
- Xloop 2 " X: (2 + 16 + 128) * 512
- return caught " discard interrupt
- endtry
- Xloop 4 " X: 0
- endfunction
-
- function! CheckThrow(Type)
- execute 'return ThrowOn' . a:Type . '()'
- endfunction
-
- function! CheckConfiguration(type) " type is "error" or "interrupt"
-
- let type = a:type
- let Type = substitute(type, '.*', '\u&', "")
- let VAR = '$VIMNO' . substitute(type, '\(...\).*', '\U\1', "") . 'THROW'
-
- if type == "error"
- XloopINIT! 1 8
- elseif type == "interrupt"
- XloopINIT! 512 8
- endif
-
- exec 'let requested_for_tests = exists(VAR) && ' . VAR . ' == 0'
- exec 'let suppressed_for_tests = ' . VAR . ' != 0'
- let used_in_tests = CheckThrow(Type)
-
- exec 'let ' . VAR . ' = 0'
- let request_works = CheckThrow(Type)
-
- exec 'let ' . VAR . ' = 1'
- let suppress_works = !CheckThrow(Type)
-
- if type == "error"
- XloopINIT! 262144 8
- elseif type == "interrupt"
- XloopINIT! 2097152 8
-
- if g:quits_skipped != 0
- Xloop 1 " X: 0*2097152
- Xout "Test environment error. Interrupt breakpoints skipped: "
- \ . g:quits_skipped . ".\n"
- \ . "Cannot check whether interrupt exceptions are thrown."
- return
- endif
- endif
-
- let failure =
- \ !suppressed_for_tests && !used_in_tests
- \ || !request_works
-
- let contradiction =
- \ used_in_tests
- \ ? suppressed_for_tests && !request_works
- \ : !suppressed_for_tests
-
- if failure
- " Failure in configuration.
- Xloop 2 " X: 0 * 2* (262144 + 2097152)
- elseif contradiction
- " Failure in test logic. Should not happen.
- Xloop 4 " X: 0 * 4 * (262144 + 2097152)
- endif
-
- let var_control_configured =
- \ request_works != used_in_tests
- \ || suppress_works == used_in_tests
-
- let var_control_not_configured =
- \ requested_for_tests || suppressed_for_tests
- \ ? request_works && !suppress_works
- \ : request_works == used_in_tests
- \ && suppress_works != used_in_tests
-
- let with = used_in_tests ? "with" : "without"
-
- let set = suppressed_for_tests ? "non-zero" :
- \ requested_for_tests ? "0" : "unset"
-
- let although = contradiction && !var_control_not_configured
- \ ? ",\nalthough "
- \ : ".\n"
-
- let output = "All tests were run " . with . " throwing exceptions on "
- \ . type . although
-
- if !var_control_not_configured
- let output = output . VAR . " was " . set . "."
-
- if !request_works && !requested_for_tests
- let output = output .
- \ "\n" . Type . " exceptions are not thrown when " . VAR .
- \ " is\nset to 0."
- endif
-
- if !suppress_works && (!used_in_tests ||
- \ !request_works &&
- \ !requested_for_tests && !suppressed_for_tests)
- let output = output .
- \ "\n" . Type . " exceptions are thrown when " . VAR .
- \ " is set to 1."
- endif
-
- if !failure && var_control_configured
- let output = output .
- \ "\nRun tests also with " . substitute(VAR, '^\$', '', "")
- \ . "=" . used_in_tests . "."
- \ . "\nThis is for testing in the development phase only."
- \ . " Remove the \n"
- \ . VAR . " control in the final release."
- endif
- else
- let output = output .
- \ "The " . VAR . " control is not configured."
- endif
-
- Xout output
- endfunction
-
- call CheckConfiguration("error")
- Xpath 16777216 " X: 16777216
- call CheckConfiguration("interrupt")
- Xpath 33554432 " X: 33554432
-endif
-
-Xcheck 50443995
-
-" IMPORTANT: No test should be added after this test because it changes
-" $VIMNOERRTHROW and $VIMNOINTTHROW.
-
-
-"-------------------------------------------------------------------------------
-" Modelines {{{1
-" vim: ts=8 sw=4 tw=80 fdm=marker
-"-------------------------------------------------------------------------------
diff --git a/src/nvim/testdir/test_alot.vim b/src/nvim/testdir/test_alot.vim
index a83ef50abc..a3d240f27e 100644
--- a/src/nvim/testdir/test_alot.vim
+++ b/src/nvim/testdir/test_alot.vim
@@ -15,7 +15,6 @@ source test_fnamemodify.vim
source test_ga.vim
source test_glob2regpat.vim
source test_global.vim
-source test_lispwords.vim
source test_move.vim
source test_put.vim
source test_reltime.vim
diff --git a/src/nvim/testdir/test_arglist.vim b/src/nvim/testdir/test_arglist.vim
index 521c3fcd57..fb8b17cd16 100644
--- a/src/nvim/testdir/test_arglist.vim
+++ b/src/nvim/testdir/test_arglist.vim
@@ -1,5 +1,6 @@
" Test argument list commands
+source check.vim
source shared.vim
source term_util.vim
@@ -417,15 +418,19 @@ func Test_argdedupe()
call Reset_arglist()
argdedupe
call assert_equal([], argv())
+
args a a a aa b b a b aa
argdedupe
call assert_equal(['a', 'aa', 'b'], argv())
+
args a b c
argdedupe
call assert_equal(['a', 'b', 'c'], argv())
+
args a
argdedupe
call assert_equal(['a'], argv())
+
args a A b B
argdedupe
if has('fname_case')
@@ -433,11 +438,17 @@ func Test_argdedupe()
else
call assert_equal(['a', 'b'], argv())
endif
+
args a b a c a b
last
argdedupe
next
call assert_equal('c', expand('%:t'))
+
+ args a ./a
+ argdedupe
+ call assert_equal(['a'], argv())
+
%argd
endfunc
@@ -509,18 +520,14 @@ func Test_arglist_autocmd()
new
" redefine arglist; go to Xxx1
next! Xxx1 Xxx2 Xxx3
- " open window for all args; Reading Xxx2 will change the arglist and the
- " third window will get Xxx1:
- " win 1: Xxx1
- " win 2: Xxx2
- " win 3: Xxx1
- all
+ " open window for all args; Reading Xxx2 will try to change the arglist and
+ " that will fail
+ call assert_fails("all", "E1156:")
call assert_equal('test file Xxx1', getline(1))
wincmd w
- wincmd w
- call assert_equal('test file Xxx1', getline(1))
- rewind
call assert_equal('test file Xxx2', getline(1))
+ wincmd w
+ call assert_equal('test file Xxx3', getline(1))
autocmd! BufReadPost Xxx2
enew! | only
@@ -554,11 +561,9 @@ func Test_argdo()
bwipe Xa.c Xb.c Xc.c
endfunc
-" Test for quiting Vim with unedited files in the argument list
+" Test for quitting Vim with unedited files in the argument list
func Test_quit_with_arglist()
- if !CanRunVimInTerminal()
- throw 'Skipped: cannot run vim in terminal'
- endif
+ CheckRunVimInTerminal
let buf = RunVimInTerminal('', {'rows': 6})
call term_sendkeys(buf, ":set nomore\n")
call term_sendkeys(buf, ":args a b c\n")
@@ -591,4 +596,153 @@ func Test_quit_with_arglist()
call delete('.c.swp')
endfunc
+" Test for ":all" not working when in the cmdline window
+func Test_all_not_allowed_from_cmdwin()
+ au BufEnter * all
+ next x
+ " Use try/catch here, somehow assert_fails() doesn't work on MS-Windows
+ " console.
+ let caught = 'no'
+ try
+ exe ":norm! 7q?apat\<CR>"
+ catch /E11:/
+ let caught = 'yes'
+ endtry
+ call assert_equal('yes', caught)
+ au! BufEnter
+endfunc
+
+func Test_clear_arglist_in_all()
+ n 0 00 000 0000 00000 000000
+ au WinNew 0 n 0
+ call assert_fails("all", "E1156")
+ au! *
+endfunc
+
+" Test for the :all command
+func Test_all_command()
+ %argdelete
+
+ " :all command should not close windows with files in the argument list,
+ " but can rearrange the windows.
+ args Xargnew1 Xargnew2
+ %bw!
+ edit Xargold1
+ split Xargnew1
+ let Xargnew1_winid = win_getid()
+ split Xargold2
+ split Xargnew2
+ let Xargnew2_winid = win_getid()
+ split Xargold3
+ all
+ call assert_equal(2, winnr('$'))
+ call assert_equal([Xargnew1_winid, Xargnew2_winid],
+ \ [win_getid(1), win_getid(2)])
+ call assert_equal([bufnr('Xargnew1'), bufnr('Xargnew2')],
+ \ [winbufnr(1), winbufnr(2)])
+
+ " :all command should close windows for files which are not in the
+ " argument list in the current tab page.
+ %bw!
+ edit Xargold1
+ split Xargold2
+ tabedit Xargold3
+ split Xargold4
+ tabedit Xargold5
+ tabfirst
+ all
+ call assert_equal(3, tabpagenr('$'))
+ call assert_equal([bufnr('Xargnew1'), bufnr('Xargnew2')], tabpagebuflist(1))
+ call assert_equal([bufnr('Xargold4'), bufnr('Xargold3')], tabpagebuflist(2))
+ call assert_equal([bufnr('Xargold5')], tabpagebuflist(3))
+
+ " :tab all command should close windows for files which are not in the
+ " argument list across all the tab pages.
+ %bw!
+ edit Xargold1
+ split Xargold2
+ tabedit Xargold3
+ split Xargold4
+ tabedit Xargold5
+ tabfirst
+ args Xargnew1 Xargnew2
+ tab all
+ call assert_equal(2, tabpagenr('$'))
+ call assert_equal([bufnr('Xargnew1')], tabpagebuflist(1))
+ call assert_equal([bufnr('Xargnew2')], tabpagebuflist(2))
+
+ " If a count is specified, then :all should open only that many windows.
+ %bw!
+ args Xargnew1 Xargnew2 Xargnew3 Xargnew4 Xargnew5
+ all 3
+ call assert_equal(3, winnr('$'))
+ call assert_equal([bufnr('Xargnew1'), bufnr('Xargnew2'), bufnr('Xargnew3')],
+ \ [winbufnr(1), winbufnr(2), winbufnr(3)])
+
+ " The :all command should not open more than 'tabpagemax' tab pages.
+ " If there are more files, then they should be opened in the last tab page.
+ %bw!
+ set tabpagemax=3
+ tab all
+ call assert_equal(3, tabpagenr('$'))
+ call assert_equal([bufnr('Xargnew1')], tabpagebuflist(1))
+ call assert_equal([bufnr('Xargnew2')], tabpagebuflist(2))
+ call assert_equal([bufnr('Xargnew3'), bufnr('Xargnew4'), bufnr('Xargnew5')],
+ \ tabpagebuflist(3))
+ set tabpagemax&
+
+ " Without the 'hidden' option, modified buffers should not be closed.
+ args Xargnew1 Xargnew2
+ %bw!
+ edit Xargtemp1
+ call setline(1, 'temp buffer 1')
+ split Xargtemp2
+ call setline(1, 'temp buffer 2')
+ all
+ call assert_equal(4, winnr('$'))
+ call assert_equal([bufnr('Xargtemp2'), bufnr('Xargtemp1'), bufnr('Xargnew1'),
+ \ bufnr('Xargnew2')],
+ \ [winbufnr(1), winbufnr(2), winbufnr(3), winbufnr(4)])
+
+ " With the 'hidden' option set, both modified and unmodified buffers in
+ " closed windows should be hidden.
+ set hidden
+ all
+ call assert_equal(2, winnr('$'))
+ call assert_equal([bufnr('Xargnew1'), bufnr('Xargnew2')],
+ \ [winbufnr(1), winbufnr(2)])
+ call assert_equal([1, 1, 0, 0], [getbufinfo('Xargtemp1')[0].hidden,
+ \ getbufinfo('Xargtemp2')[0].hidden,
+ \ getbufinfo('Xargnew1')[0].hidden,
+ \ getbufinfo('Xargnew2')[0].hidden])
+ set nohidden
+
+ " When 'winheight' is set to a large value, :all should open only one
+ " window.
+ args Xargnew1 Xargnew2 Xargnew3 Xargnew4 Xargnew5
+ %bw!
+ set winheight=9999
+ call assert_fails('all', 'E36:')
+ call assert_equal([1, bufnr('Xargnew1')], [winnr('$'), winbufnr(1)])
+ set winheight&
+
+ " When 'winwidth' is set to a large value, :vert all should open only one
+ " window.
+ %bw!
+ set winwidth=9999
+ call assert_fails('vert all', 'E36:')
+ call assert_equal([1, bufnr('Xargnew1')], [winnr('$'), winbufnr(1)])
+ set winwidth&
+
+ " empty argument list tests
+ %bw!
+ %argdelete
+ call assert_equal('', execute('args'))
+ all
+ call assert_equal(1, winnr('$'))
+
+ %argdelete
+ %bw!
+endfunc
+
" vim: shiftwidth=2 sts=2 expandtab
diff --git a/src/nvim/testdir/test_assert.vim b/src/nvim/testdir/test_assert.vim
index fdd8b0bef6..431908e95c 100644
--- a/src/nvim/testdir/test_assert.vim
+++ b/src/nvim/testdir/test_assert.vim
@@ -48,6 +48,11 @@ func Test_assert_equal()
call assert_equal('XxxxxxxxxxxxxxxxxxxxxxX', 'XyyyyyyyyyyyyyyyyyyyyyyyyyX')
call assert_match("Expected 'X\\\\\\[x occurs 21 times]X' but got 'X\\\\\\[y occurs 25 times]X'", v:errors[0])
call remove(v:errors, 0)
+
+ " special characters are escaped
+ call assert_equal("\b\e\f\n\t\r\\\x01\x7f", 'x')
+ call assert_match('Expected ''\\b\\e\\f\\n\\t\\r\\\\\\x01\\x7f'' but got ''x''', v:errors[0])
+ call remove(v:errors, 0)
endfunc
func Test_assert_equal_dict()
@@ -146,6 +151,14 @@ func Test_assert_exception()
try
nocommand
catch
+ call assert_equal(1, assert_exception('E12345:'))
+ endtry
+ call assert_match("Expected 'E12345:' but got 'Vim:E492: ", v:errors[0])
+ call remove(v:errors, 0)
+
+ try
+ nocommand
+ catch
try
" illegal argument, get NULL for error
call assert_equal(1, assert_exception([]))
@@ -153,6 +166,10 @@ func Test_assert_exception()
call assert_equal(0, assert_exception('E730:'))
endtry
endtry
+
+ call assert_equal(1, assert_exception('E492:'))
+ call assert_match('v:exception is not set', v:errors[0])
+ call remove(v:errors, 0)
endfunc
func Test_wrong_error_type()
@@ -202,6 +219,14 @@ func Test_assert_fail_fails()
call assert_match("stupid: Expected 'E9876' but got 'E492:", v:errors[0])
call remove(v:errors, 0)
+ call assert_equal(1, assert_fails('xxx', ['E9876']))
+ call assert_match("Expected \\['E9876'\\] but got 'E492:", v:errors[0])
+ call remove(v:errors, 0)
+
+ call assert_equal(1, assert_fails('xxx', ['E492:', 'E9876']))
+ call assert_match("Expected \\['E492:', 'E9876'\\] but got 'E492:", v:errors[0])
+ call remove(v:errors, 0)
+
call assert_equal(1, assert_fails('echo', '', 'echo command'))
call assert_match("command did not fail: echo command", v:errors[0])
call remove(v:errors, 0)
@@ -209,6 +234,41 @@ func Test_assert_fail_fails()
call assert_equal(1, 'echo'->assert_fails('', 'echo command'))
call assert_match("command did not fail: echo command", v:errors[0])
call remove(v:errors, 0)
+
+ try
+ call assert_equal(1, assert_fails('xxx', []))
+ catch
+ let exp = v:exception
+ endtry
+ call assert_match("E856: assert_fails() second argument", exp)
+
+ try
+ call assert_equal(1, assert_fails('xxx', ['1', '2', '3']))
+ catch
+ let exp = v:exception
+ endtry
+ call assert_match("E856: assert_fails() second argument", exp)
+
+ try
+ call assert_equal(1, assert_fails('xxx', #{one: 1}))
+ catch
+ let exp = v:exception
+ endtry
+ call assert_match("E856: assert_fails() second argument", exp)
+
+ try
+ call assert_equal(1, assert_fails('xxx', 'E492', '', 'burp'))
+ catch
+ let exp = v:exception
+ endtry
+ call assert_match("E1115: assert_fails() fourth argument must be a number", exp)
+
+ try
+ call assert_equal(1, assert_fails('xxx', 'E492', '', 54, 123))
+ catch
+ let exp = v:exception
+ endtry
+ call assert_match("E1116: assert_fails() fifth argument must be a string", exp)
endfunc
func Test_assert_fails_in_try_block()
@@ -278,19 +338,18 @@ func Test_assert_with_msg()
endfunc
func Test_mouse_position()
- throw 'Skipped: Nvim does not have test_setmouse()'
let save_mouse = &mouse
set mouse=a
new
call setline(1, ['line one', 'line two'])
call assert_equal([0, 1, 1, 0], getpos('.'))
- call test_setmouse(1, 5)
+ call Ntest_setmouse(1, 5)
call feedkeys("\<LeftMouse>", "xt")
call assert_equal([0, 1, 5, 0], getpos('.'))
- call test_setmouse(2, 20)
+ call Ntest_setmouse(2, 20)
call feedkeys("\<LeftMouse>", "xt")
call assert_equal([0, 2, 8, 0], getpos('.'))
- call test_setmouse(5, 1)
+ call Ntest_setmouse(5, 1)
call feedkeys("\<LeftMouse>", "xt")
call assert_equal([0, 2, 1, 0], getpos('.'))
bwipe!
diff --git a/src/nvim/testdir/test_autochdir.vim b/src/nvim/testdir/test_autochdir.vim
index 4229095f9f..a8810047a0 100644
--- a/src/nvim/testdir/test_autochdir.vim
+++ b/src/nvim/testdir/test_autochdir.vim
@@ -122,9 +122,7 @@ endfunc
func Test_multibyte()
" using an invalid character should not cause a crash
set wic
- " Except on Windows, E472 is also thrown last, but v8.1.1183 isn't ported yet
- " call assert_fails('tc *', has('win32') ? 'E480:' : 'E344:')
- call assert_fails('tc *', has('win32') ? 'E480:' : 'E472:')
+ call assert_fails('tc *', has('win32') ? 'E480:' : 'E344:')
set nowic
endfunc
diff --git a/src/nvim/testdir/test_autocmd.vim b/src/nvim/testdir/test_autocmd.vim
index 716511210d..83af0f6be0 100644
--- a/src/nvim/testdir/test_autocmd.vim
+++ b/src/nvim/testdir/test_autocmd.vim
@@ -4,6 +4,7 @@ source shared.vim
source check.vim
source term_util.vim
source screendump.vim
+source load.vim
func s:cleanup_buffers() abort
for bnr in range(1, bufnr('$'))
@@ -20,8 +21,35 @@ func Test_vim_did_enter()
" becomes one.
endfunc
+" Test for the CursorHold autocmd
+func Test_CursorHold_autocmd()
+ CheckRunVimInTerminal
+ call writefile(['one', 'two', 'three'], 'Xfile')
+ let before =<< trim END
+ set updatetime=10
+ au CursorHold * call writefile([line('.')], 'Xoutput', 'a')
+ END
+ call writefile(before, 'Xinit')
+ let buf = RunVimInTerminal('-S Xinit Xfile', {})
+ call term_sendkeys(buf, "G")
+ call term_wait(buf, 20)
+ call term_sendkeys(buf, "gg")
+ call term_wait(buf)
+ call WaitForAssert({-> assert_equal(['1'], readfile('Xoutput')[-1:-1])})
+ call term_sendkeys(buf, "j")
+ call term_wait(buf)
+ call WaitForAssert({-> assert_equal(['1', '2'], readfile('Xoutput')[-2:-1])})
+ call term_sendkeys(buf, "j")
+ call term_wait(buf)
+ call WaitForAssert({-> assert_equal(['1', '2', '3'], readfile('Xoutput')[-3:-1])})
+ call StopVimInTerminal(buf)
+
+ call delete('Xinit')
+ call delete('Xoutput')
+ call delete('Xfile')
+endfunc
+
if has('timers')
- source load.vim
func ExitInsertMode(id)
call feedkeys("\<Esc>")
@@ -148,6 +176,12 @@ func Test_autocmd_bufunload_with_tabnext()
quit
endfunc
+func Test_argdelete_in_next()
+ au BufNew,BufEnter,BufLeave,BufWinEnter * argdel
+ call assert_fails('next a b', 'E1156:')
+ au! BufNew,BufEnter,BufLeave,BufWinEnter *
+endfunc
+
func Test_autocmd_bufwinleave_with_tabfirst()
tabedit
augroup sample
@@ -169,9 +203,7 @@ func Test_autocmd_bufunload_avoiding_SEGV_01()
exe 'autocmd BufUnload <buffer> ' . (lastbuf + 1) . 'bwipeout!'
augroup END
- " Todo: check for E937 generated first
- " call assert_fails('edit bb.txt', 'E937:')
- call assert_fails('edit bb.txt', 'E517:')
+ call assert_fails('edit bb.txt', 'E937:')
autocmd! test_autocmd_bufunload
augroup! test_autocmd_bufunload
@@ -263,6 +295,61 @@ func Test_win_tab_autocmd()
unlet g:record
endfunc
+func Test_WinResized()
+ CheckRunVimInTerminal
+
+ let lines =<< trim END
+ set scrolloff=0
+ call setline(1, ['111', '222'])
+ vnew
+ call setline(1, ['aaa', 'bbb'])
+ new
+ call setline(1, ['foo', 'bar'])
+
+ let g:resized = 0
+ au WinResized * let g:resized += 1
+
+ func WriteResizedEvent()
+ call writefile([json_encode(v:event)], 'XresizeEvent')
+ endfunc
+ au WinResized * call WriteResizedEvent()
+ END
+ call writefile(lines, 'Xtest_winresized', 'D')
+ let buf = RunVimInTerminal('-S Xtest_winresized', {'rows': 10})
+
+ " redraw now to avoid a redraw after the :echo command
+ call term_sendkeys(buf, ":redraw!\<CR>")
+ call TermWait(buf)
+
+ call term_sendkeys(buf, ":echo g:resized\<CR>")
+ call WaitForAssert({-> assert_match('^0$', term_getline(buf, 10))}, 1000)
+
+ " increase window height, two windows will be reported
+ call term_sendkeys(buf, "\<C-W>+")
+ call TermWait(buf)
+ call term_sendkeys(buf, ":echo g:resized\<CR>")
+ call WaitForAssert({-> assert_match('^1$', term_getline(buf, 10))}, 1000)
+
+ let event = readfile('XresizeEvent')[0]->json_decode()
+ call assert_equal({
+ \ 'windows': [1002, 1001],
+ \ }, event)
+
+ " increase window width, three windows will be reported
+ call term_sendkeys(buf, "\<C-W>>")
+ call TermWait(buf)
+ call term_sendkeys(buf, ":echo g:resized\<CR>")
+ call WaitForAssert({-> assert_match('^2$', term_getline(buf, 10))}, 1000)
+
+ let event = readfile('XresizeEvent')[0]->json_decode()
+ call assert_equal({
+ \ 'windows': [1002, 1001, 1000],
+ \ }, event)
+
+ call delete('XresizeEvent')
+ call StopVimInTerminal(buf)
+endfunc
+
func Test_WinScrolled()
CheckRunVimInTerminal
@@ -273,13 +360,17 @@ func Test_WinScrolled()
endfor
let win_id = win_getid()
let g:matched = v:false
+ func WriteScrollEvent()
+ call writefile([json_encode(v:event)], 'XscrollEvent')
+ endfunc
execute 'au WinScrolled' win_id 'let g:matched = v:true'
let g:scrolled = 0
au WinScrolled * let g:scrolled += 1
au WinScrolled * let g:amatch = str2nr(expand('<amatch>'))
au WinScrolled * let g:afile = str2nr(expand('<afile>'))
+ au WinScrolled * call WriteScrollEvent()
END
- call writefile(lines, 'Xtest_winscrolled')
+ call writefile(lines, 'Xtest_winscrolled', 'D')
let buf = RunVimInTerminal('-S Xtest_winscrolled', {'rows': 6})
call term_sendkeys(buf, ":echo g:scrolled\<CR>")
@@ -289,15 +380,33 @@ func Test_WinScrolled()
call term_sendkeys(buf, "zlzh:echo g:scrolled\<CR>")
call WaitForAssert({-> assert_match('^2 ', term_getline(buf, 6))}, 1000)
+ let event = readfile('XscrollEvent')[0]->json_decode()
+ call assert_equal({
+ \ 'all': {'leftcol': 1, 'topline': 0, 'topfill': 0, 'width': 0, 'height': 0, 'skipcol': 0},
+ \ '1000': {'leftcol': -1, 'topline': 0, 'topfill': 0, 'width': 0, 'height': 0, 'skipcol': 0}
+ \ }, event)
+
" Scroll up/down in Normal mode.
call term_sendkeys(buf, "\<c-e>\<c-y>:echo g:scrolled\<CR>")
call WaitForAssert({-> assert_match('^4 ', term_getline(buf, 6))}, 1000)
+ let event = readfile('XscrollEvent')[0]->json_decode()
+ call assert_equal({
+ \ 'all': {'leftcol': 0, 'topline': 1, 'topfill': 0, 'width': 0, 'height': 0, 'skipcol': 0},
+ \ '1000': {'leftcol': 0, 'topline': -1, 'topfill': 0, 'width': 0, 'height': 0, 'skipcol': 0}
+ \ }, event)
+
" Scroll up/down in Insert mode.
call term_sendkeys(buf, "Mi\<c-x>\<c-e>\<Esc>i\<c-x>\<c-y>\<Esc>")
call term_sendkeys(buf, ":echo g:scrolled\<CR>")
call WaitForAssert({-> assert_match('^6 ', term_getline(buf, 6))}, 1000)
+ let event = readfile('XscrollEvent')[0]->json_decode()
+ call assert_equal({
+ \ 'all': {'leftcol': 0, 'topline': 1, 'topfill': 0, 'width': 0, 'height': 0, 'skipcol': 0},
+ \ '1000': {'leftcol': 0, 'topline': -1, 'topfill': 0, 'width': 0, 'height': 0, 'skipcol': 0}
+ \ }, event)
+
" Scroll the window horizontally to focus the last letter of the third line
" containing only six characters. Moving to the previous and shorter lines
" should trigger another autocommand as Vim has to make them visible.
@@ -305,6 +414,12 @@ func Test_WinScrolled()
call term_sendkeys(buf, ":echo g:scrolled\<CR>")
call WaitForAssert({-> assert_match('^8 ', term_getline(buf, 6))}, 1000)
+ let event = readfile('XscrollEvent')[0]->json_decode()
+ call assert_equal({
+ \ 'all': {'leftcol': 5, 'topline': 0, 'topfill': 0, 'width': 0, 'height': 0, 'skipcol': 0},
+ \ '1000': {'leftcol': -5, 'topline': 0, 'topfill': 0, 'width': 0, 'height': 0, 'skipcol': 0}
+ \ }, event)
+
" Ensure the command was triggered for the specified window ID.
call term_sendkeys(buf, ":echo g:matched\<CR>")
call WaitForAssert({-> assert_match('^v:true ', term_getline(buf, 6))}, 1000)
@@ -313,8 +428,38 @@ func Test_WinScrolled()
call term_sendkeys(buf, ":echo g:amatch == win_id && g:afile == win_id\<CR>")
call WaitForAssert({-> assert_match('^v:true ', term_getline(buf, 6))}, 1000)
+ call delete('XscrollEvent')
+ call StopVimInTerminal(buf)
+endfunc
+
+func Test_WinScrolled_mouse()
+ CheckRunVimInTerminal
+
+ let lines =<< trim END
+ set nowrap scrolloff=0
+ set mouse=a term=xterm ttymouse=sgr mousetime=200 clipboard=
+ call setline(1, ['foo']->repeat(32))
+ split
+ let g:scrolled = 0
+ au WinScrolled * let g:scrolled += 1
+ END
+ call writefile(lines, 'Xtest_winscrolled_mouse', 'D')
+ let buf = RunVimInTerminal('-S Xtest_winscrolled_mouse', {'rows': 10})
+
+ " With the upper split focused, send a scroll-down event to the unfocused one.
+ call test_setmouse(7, 1)
+ call term_sendkeys(buf, "\<ScrollWheelDown>")
+ call TermWait(buf)
+ call term_sendkeys(buf, ":echo g:scrolled\<CR>")
+ call WaitForAssert({-> assert_match('^1', term_getline(buf, 10))}, 1000)
+
+ " Again, but this time while we're in insert mode.
+ call term_sendkeys(buf, "i\<ScrollWheelDown>\<Esc>")
+ call TermWait(buf)
+ call term_sendkeys(buf, ":echo g:scrolled\<CR>")
+ call WaitForAssert({-> assert_match('^2', term_getline(buf, 10))}, 1000)
+
call StopVimInTerminal(buf)
- call delete('Xtest_winscrolled')
endfunc
func Test_WinScrolled_close_curwin()
@@ -327,7 +472,7 @@ func Test_WinScrolled_close_curwin()
au WinScrolled * close
au VimLeave * call writefile(['123456'], 'Xtestout')
END
- call writefile(lines, 'Xtest_winscrolled_close_curwin')
+ call writefile(lines, 'Xtest_winscrolled_close_curwin', 'D')
let buf = RunVimInTerminal('-S Xtest_winscrolled_close_curwin', {'rows': 6})
" This was using freed memory
@@ -335,12 +480,158 @@ func Test_WinScrolled_close_curwin()
call TermWait(buf)
call StopVimInTerminal(buf)
+ " check the startup script finished to the end
call assert_equal(['123456'], readfile('Xtestout'))
-
- call delete('Xtest_winscrolled_close_curwin')
call delete('Xtestout')
endfunc
+func Test_WinScrolled_once_only()
+ CheckRunVimInTerminal
+
+ let lines =<< trim END
+ set cmdheight=2
+ call setline(1, ['aaa', 'bbb'])
+ let trigger_count = 0
+ func ShowInfo(id)
+ echo g:trigger_count g:winid winlayout()
+ endfunc
+
+ vsplit
+ split
+ " use a timer to show the info after a redraw
+ au WinScrolled * let trigger_count += 1 | let winid = expand('<amatch>') | call timer_start(100, 'ShowInfo')
+ wincmd j
+ wincmd l
+ END
+ call writefile(lines, 'Xtest_winscrolled_once', 'D')
+ let buf = RunVimInTerminal('-S Xtest_winscrolled_once', #{rows: 10, cols: 60, statusoff: 2})
+
+ call term_sendkeys(buf, "\<C-E>")
+ call VerifyScreenDump(buf, 'Test_winscrolled_once_only_1', {})
+
+ call StopVimInTerminal(buf)
+endfunc
+
+" Check that WinScrolled is not triggered immediately when defined and there
+" are split windows.
+func Test_WinScrolled_not_when_defined()
+ CheckRunVimInTerminal
+
+ let lines =<< trim END
+ call setline(1, ['aaa', 'bbb'])
+ echo 'nothing happened'
+ func ShowTriggered(id)
+ echo 'triggered'
+ endfunc
+ END
+ call writefile(lines, 'Xtest_winscrolled_not', 'D')
+ let buf = RunVimInTerminal('-S Xtest_winscrolled_not', #{rows: 10, cols: 60, statusoff: 2})
+ call term_sendkeys(buf, ":split\<CR>")
+ call TermWait(buf)
+ " use a timer to show the message after redrawing
+ call term_sendkeys(buf, ":au WinScrolled * call timer_start(100, 'ShowTriggered')\<CR>")
+ call VerifyScreenDump(buf, 'Test_winscrolled_not_when_defined_1', {})
+
+ call term_sendkeys(buf, "\<C-E>")
+ call VerifyScreenDump(buf, 'Test_winscrolled_not_when_defined_2', {})
+
+ call StopVimInTerminal(buf)
+endfunc
+
+func Test_WinScrolled_long_wrapped()
+ CheckRunVimInTerminal
+
+ let lines =<< trim END
+ set scrolloff=0
+ let height = winheight(0)
+ let width = winwidth(0)
+ let g:scrolled = 0
+ au WinScrolled * let g:scrolled += 1
+ call setline(1, repeat('foo', height * width))
+ call cursor(1, height * width)
+ END
+ call writefile(lines, 'Xtest_winscrolled_long_wrapped', 'D')
+ let buf = RunVimInTerminal('-S Xtest_winscrolled_long_wrapped', {'rows': 6})
+
+ call term_sendkeys(buf, ":echo g:scrolled\<CR>")
+ call WaitForAssert({-> assert_match('^0 ', term_getline(buf, 6))}, 1000)
+
+ call term_sendkeys(buf, 'gj')
+ call term_sendkeys(buf, ":echo g:scrolled\<CR>")
+ call WaitForAssert({-> assert_match('^1 ', term_getline(buf, 6))}, 1000)
+
+ call term_sendkeys(buf, '0')
+ call term_sendkeys(buf, ":echo g:scrolled\<CR>")
+ call WaitForAssert({-> assert_match('^2 ', term_getline(buf, 6))}, 1000)
+
+ call term_sendkeys(buf, '$')
+ call term_sendkeys(buf, ":echo g:scrolled\<CR>")
+ call WaitForAssert({-> assert_match('^3 ', term_getline(buf, 6))}, 1000)
+
+ call StopVimInTerminal(buf)
+endfunc
+
+func Test_WinScrolled_diff()
+ CheckRunVimInTerminal
+
+ let lines =<< trim END
+ set diffopt+=foldcolumn:0
+ call setline(1, ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i'])
+ vnew
+ call setline(1, ['d', 'e', 'f', 'g', 'h', 'i'])
+ windo diffthis
+ func WriteScrollEvent()
+ call writefile([json_encode(v:event)], 'XscrollEvent')
+ endfunc
+ au WinScrolled * call WriteScrollEvent()
+ END
+ call writefile(lines, 'Xtest_winscrolled_diff', 'D')
+ let buf = RunVimInTerminal('-S Xtest_winscrolled_diff', {'rows': 8})
+
+ call term_sendkeys(buf, "\<C-E>")
+ call WaitForAssert({-> assert_match('^d', term_getline(buf, 3))}, 1000)
+
+ let event = readfile('XscrollEvent')[0]->json_decode()
+ call assert_equal({
+ \ 'all': {'leftcol': 0, 'topline': 1, 'topfill': 1, 'width': 0, 'height': 0, 'skipcol': 0},
+ \ '1000': {'leftcol': 0, 'topline': 1, 'topfill': 0, 'width': 0, 'height': 0, 'skipcol': 0},
+ \ '1001': {'leftcol': 0, 'topline': 0, 'topfill': -1, 'width': 0, 'height': 0, 'skipcol': 0}
+ \ }, event)
+
+ call term_sendkeys(buf, "2\<C-E>")
+ call WaitForAssert({-> assert_match('^f', term_getline(buf, 3))}, 1000)
+
+ let event = readfile('XscrollEvent')[0]->json_decode()
+ call assert_equal({
+ \ 'all': {'leftcol': 0, 'topline': 2, 'topfill': 2, 'width': 0, 'height': 0, 'skipcol': 0},
+ \ '1000': {'leftcol': 0, 'topline': 2, 'topfill': 0, 'width': 0, 'height': 0, 'skipcol': 0},
+ \ '1001': {'leftcol': 0, 'topline': 0, 'topfill': -2, 'width': 0, 'height': 0, 'skipcol': 0}
+ \ }, event)
+
+ call term_sendkeys(buf, "\<C-E>")
+ call WaitForAssert({-> assert_match('^g', term_getline(buf, 3))}, 1000)
+
+ let event = readfile('XscrollEvent')[0]->json_decode()
+ call assert_equal({
+ \ 'all': {'leftcol': 0, 'topline': 2, 'topfill': 0, 'width': 0, 'height': 0, 'skipcol': 0},
+ \ '1000': {'leftcol': 0, 'topline': 1, 'topfill': 0, 'width': 0, 'height': 0, 'skipcol': 0},
+ \ '1001': {'leftcol': 0, 'topline': 1, 'topfill': 0, 'width': 0, 'height': 0, 'skipcol': 0}
+ \ }, event)
+
+ call term_sendkeys(buf, "2\<C-Y>")
+ call WaitForAssert({-> assert_match('^e', term_getline(buf, 3))}, 1000)
+
+ let event = readfile('XscrollEvent')[0]->json_decode()
+ call assert_equal({
+ \ 'all': {'leftcol': 0, 'topline': 3, 'topfill': 1, 'width': 0, 'height': 0, 'skipcol': 0},
+ \ '1000': {'leftcol': 0, 'topline': -2, 'topfill': 0, 'width': 0, 'height': 0, 'skipcol': 0},
+ \ '1001': {'leftcol': 0, 'topline': -1, 'topfill': 1, 'width': 0, 'height': 0, 'skipcol': 0}
+ \ }, event)
+
+ call StopVimInTerminal(buf)
+ call delete('XscrollEvent')
+endfunc
+
func Test_WinClosed()
" Test that the pattern is matched against the closed window's ID, and both
" <amatch> and <afile> are set to it.
@@ -414,6 +705,26 @@ func Test_WinClosed_throws_with_tabs()
augroup! test-WinClosed
endfunc
+" This used to trigger WinClosed twice for the same window, and the window's
+" buffer was NULL in the second autocommand.
+func Test_WinClosed_switch_tab()
+ edit Xa
+ split Xb
+ split Xc
+ tab split
+ new
+ augroup test-WinClosed
+ autocmd WinClosed * tabprev | bwipe!
+ augroup END
+ close
+ " Check that the tabline has been fully removed
+ call assert_equal([1, 1], win_screenpos(0))
+
+ autocmd! test-WinClosed
+ augroup! test-WinClosed
+ %bwipe!
+endfunc
+
func s:AddAnAutocmd()
augroup vimBarTest
au BufReadCmd * echo 'hello'
@@ -424,17 +735,20 @@ endfunc
func Test_early_bar()
" test that a bar is recognized before the {event}
call s:AddAnAutocmd()
- augroup vimBarTest | au! | augroup END
+ augroup vimBarTest | au! | let done = 77 | augroup END
call assert_equal(1, len(split(execute('au vimBarTest'), "\n")))
+ call assert_equal(77, done)
call s:AddAnAutocmd()
- augroup vimBarTest| au!| augroup END
+ augroup vimBarTest| au!| let done = 88 | augroup END
call assert_equal(1, len(split(execute('au vimBarTest'), "\n")))
+ call assert_equal(88, done)
" test that a bar is recognized after the {event}
call s:AddAnAutocmd()
- augroup vimBarTest| au!BufReadCmd| augroup END
+ augroup vimBarTest| au!BufReadCmd| let done = 99 | augroup END
call assert_equal(1, len(split(execute('au vimBarTest'), "\n")))
+ call assert_equal(99, done)
" test that a bar is recognized after the {group}
call s:AddAnAutocmd()
@@ -474,6 +788,8 @@ func Test_augroup_warning()
redir END
call assert_notmatch("W19:", res)
au! VimEnter
+
+ call assert_fails('augroup!', 'E471:')
endfunc
func Test_BufReadCmdHelp()
@@ -493,6 +809,28 @@ func Test_BufReadCmdHelpJump()
au! BufReadCmd
endfunc
+" BufReadCmd is triggered for a "nofile" buffer. Check all values.
+func Test_BufReadCmdNofile()
+ for val in ['nofile',
+ \ 'nowrite',
+ \ 'acwrite',
+ \ 'quickfix',
+ \ 'help',
+ "\ 'terminal',
+ \ 'prompt',
+ "\ 'popup',
+ \ ]
+ new somefile
+ exe 'set buftype=' .. val
+ au BufReadCmd somefile call setline(1, 'triggered')
+ edit
+ call assert_equal('triggered', getline(1))
+
+ au! BufReadCmd
+ bwipe!
+ endfor
+endfunc
+
func Test_augroup_deleted()
" This caused a crash before E936 was introduced
augroup x
@@ -587,9 +925,28 @@ func Test_BufEnter()
" On MS-Windows we can't edit the directory, make sure we wipe the right
" buffer.
bwipe! Xdir
-
call delete('Xdir', 'd')
au! BufEnter
+
+ " Editing a "nofile" buffer doesn't read the file but does trigger BufEnter
+ " for historic reasons. Also test other 'buftype' values.
+ for val in ['nofile',
+ \ 'nowrite',
+ \ 'acwrite',
+ \ 'quickfix',
+ \ 'help',
+ "\ 'terminal',
+ \ 'prompt',
+ "\ 'popup',
+ \ ]
+ new somefile
+ exe 'set buftype=' .. val
+ au BufEnter somefile call setline(1, 'some text')
+ edit
+ call assert_equal('some text', getline(1))
+ bwipe!
+ au! BufEnter
+ endfor
endfunc
" Closing a window might cause an endless loop
@@ -1766,6 +2123,21 @@ func Test_BufReadCmd()
au! BufWriteCmd
endfunc
+func Test_BufWriteCmd()
+ autocmd BufWriteCmd Xbufwritecmd let g:written = 1
+ new
+ file Xbufwritecmd
+ set buftype=acwrite
+ call mkdir('Xbufwritecmd')
+ write
+ " BufWriteCmd should be triggered even if a directory has the same name
+ call assert_equal(1, g:written)
+ call delete('Xbufwritecmd', 'd')
+ unlet g:written
+ au! BufWriteCmd
+ bwipe!
+endfunc
+
func SetChangeMarks(start, end)
exe a:start .. 'mark ['
exe a:end .. 'mark ]'
@@ -1860,9 +2232,7 @@ func Test_change_mark_in_autocmds()
endfunc
func Test_Filter_noshelltemp()
- if !executable('cat')
- return
- endif
+ CheckExecutable cat
enew!
call setline(1, ['a', 'b', 'c', 'd'])
@@ -1939,6 +2309,7 @@ endfunc
func Test_autocommand_all_events()
call assert_fails('au * * bwipe', 'E1155:')
call assert_fails('au * x bwipe', 'E1155:')
+ call assert_fails('au! * x bwipe', 'E1155:')
endfunc
func Test_autocmd_user()
@@ -2026,9 +2397,8 @@ function Test_dirchanged_auto()
endfunc
" Test TextChangedI and TextChangedP
-" See test/functional/viml/completion_spec.lua'
func Test_ChangedP()
- CheckFunction test_override
+ throw 'Skipped: use test/functional/editor/completion_spec.lua'
new
call setline(1, ['foo', 'bar', 'foobar'])
call test_override("char_avail", 1)
@@ -2549,7 +2919,7 @@ func Test_autocmd_CmdWinEnter()
call term_sendkeys(buf, "q:")
call term_wait(buf)
call term_sendkeys(buf, ":echo b:dummy_var\<cr>")
- call WaitForAssert({-> assert_match('^This is a dummy', term_getline(buf, 6))}, 1000)
+ call WaitForAssert({-> assert_match('^This is a dummy', term_getline(buf, 6))}, 2000)
call term_sendkeys(buf, ":echo &buftype\<cr>")
call WaitForAssert({-> assert_notmatch('^nofile', term_getline(buf, 6))}, 1000)
call term_sendkeys(buf, ":echo winnr\<cr>")
@@ -2636,6 +3006,17 @@ func Test_FileType_spell()
setglobal spellfile=
endfunc
+" this was wiping out the current buffer and using freed memory
+func Test_SpellFileMissing_bwipe()
+ next 0
+ au SpellFileMissing 0 bwipe
+ call assert_fails('set spell spelllang=0', 'E937:')
+
+ au! SpellFileMissing
+ set nospell spelllang=en
+ bwipe
+endfunc
+
" Test closing a window or editing another buffer from a FileChangedRO handler
" in a readonly buffer
func Test_FileChangedRO_winclose()
@@ -2724,6 +3105,31 @@ func Test_autocmd_FileReadCmd()
delfunc ReadFileCmd
endfunc
+" Test for passing invalid arguments to autocmd
+func Test_autocmd_invalid_args()
+ " Additional character after * for event
+ call assert_fails('autocmd *a Xfile set ff=unix', 'E215:')
+ augroup Test
+ augroup END
+ " Invalid autocmd event
+ call assert_fails('autocmd Bufabc Xfile set ft=vim', 'E216:')
+ " Invalid autocmd event in a autocmd group
+ call assert_fails('autocmd Test Bufabc Xfile set ft=vim', 'E216:')
+ augroup! Test
+ " Execute all autocmds
+ call assert_fails('doautocmd * BufEnter', 'E217:')
+ call assert_fails('augroup! x1a2b3', 'E367:')
+ call assert_fails('autocmd BufNew <buffer=999> pwd', 'E680:')
+ call assert_fails('autocmd BufNew \) set ff=unix', 'E55:')
+endfunc
+
+" Test for deep nesting of autocmds
+func Test_autocmd_deep_nesting()
+ autocmd BufEnter Xfile doautocmd BufEnter Xfile
+ call assert_fails('doautocmd BufEnter Xfile', 'E218:')
+ autocmd! BufEnter Xfile
+endfunc
+
" Tests for SigUSR1 autocmd event, which is only available on posix systems.
func Test_autocmd_sigusr1()
CheckUnix
@@ -2781,7 +3187,7 @@ func Test_BufDelete_changebuf()
augroup END
let save_cpo = &cpo
set cpo+=f
- call assert_fails('r Xfile', 'E484:')
+ call assert_fails('r Xfile', ['E812:', 'E484:'])
call assert_equal('somefile', @%)
let &cpo = save_cpo
augroup TestAuCmd
@@ -2871,6 +3277,15 @@ func Test_Visual_doautoall_redraw()
%bwipe!
endfunc
+" This was using freed memory.
+func Test_BufNew_arglocal()
+ arglocal
+ au BufNew * arglocal
+ call assert_fails('drop xx', 'E1156:')
+
+ au! BufNew
+endfunc
+
func Test_autocmd_closes_window()
au BufNew,BufWinLeave * e %e
file yyy
@@ -3039,19 +3454,29 @@ func Test_mode_changes()
call assert_equal(5, g:nori_to_any)
endif
- if has('cmdwin')
- let g:n_to_c = 0
- au ModeChanged n:c let g:n_to_c += 1
- let g:c_to_n = 0
- au ModeChanged c:n let g:c_to_n += 1
- let g:mode_seq += ['c', 'n', 'c', 'n']
- call feedkeys("q:\<C-C>\<Esc>", 'tnix')
- call assert_equal(len(g:mode_seq) - 1, g:index)
- call assert_equal(2, g:n_to_c)
- call assert_equal(2, g:c_to_n)
- unlet g:n_to_c
- unlet g:c_to_n
- endif
+ let g:n_to_c = 0
+ au ModeChanged n:c let g:n_to_c += 1
+ let g:c_to_n = 0
+ au ModeChanged c:n let g:c_to_n += 1
+ let g:mode_seq += ['c', 'n', 'c', 'n']
+ call feedkeys("q:\<C-C>\<Esc>", 'tnix')
+ call assert_equal(len(g:mode_seq) - 1, g:index)
+ call assert_equal(2, g:n_to_c)
+ call assert_equal(2, g:c_to_n)
+ unlet g:n_to_c
+ unlet g:c_to_n
+
+ let g:n_to_v = 0
+ au ModeChanged n:v let g:n_to_v += 1
+ let g:v_to_n = 0
+ au ModeChanged v:n let g:v_to_n += 1
+ let g:mode_seq += ['v', 'n']
+ call feedkeys("v\<C-C>", 'tnix')
+ call assert_equal(len(g:mode_seq) - 1, g:index)
+ call assert_equal(1, g:n_to_v)
+ call assert_equal(1, g:v_to_n)
+ unlet g:n_to_v
+ unlet g:v_to_n
au! ModeChanged
delfunc TestMode
@@ -3100,4 +3525,48 @@ func Test_noname_autocmd()
augroup! test_noname_autocmd_group
endfunc
+func Test_autocmd_split_dummy()
+ " Autocommand trying to split a window containing a dummy buffer.
+ auto BufReadPre * exe "sbuf " .. expand("<abuf>")
+ " Avoid the "W11" prompt
+ au FileChangedShell * let v:fcs_choice = 'reload'
+ func Xautocmd_changelist()
+ cal writefile(['Xtestfile2:4:4'], 'Xerr')
+ edit Xerr
+ lex 'Xtestfile2:4:4'
+ endfunc
+ call Xautocmd_changelist()
+ " Should get E86, but it doesn't always happen (timing?)
+ silent! call Xautocmd_changelist()
+
+ au! BufReadPre
+ au! FileChangedShell
+ delfunc Xautocmd_changelist
+ bwipe! Xerr
+ call delete('Xerr')
+endfunc
+
+" This was crashing because there was only one window to execute autocommands
+" in.
+func Test_autocmd_nested_setbufvar()
+ CheckFeature python3
+
+ set hidden
+ edit Xaaa
+ edit Xbbb
+ call setline(1, 'bar')
+ enew
+ au BufWriteCmd Xbbb ++nested call setbufvar('Xaaa', '&ft', 'foo') | bw! Xaaa
+ au FileType foo call py3eval('vim.current.buffer.options["cindent"]')
+ wall
+
+ au! BufWriteCmd
+ au! FileType foo
+ set nohidden
+ call delete('Xaaa')
+ call delete('Xbbb')
+ %bwipe!
+endfunc
+
+
" vim: shiftwidth=2 sts=2 expandtab
diff --git a/src/nvim/testdir/test_autoload.vim b/src/nvim/testdir/test_autoload.vim
index b8c4fa251f..e89fe3943b 100644
--- a/src/nvim/testdir/test_autoload.vim
+++ b/src/nvim/testdir/test_autoload.vim
@@ -10,6 +10,9 @@ func Test_autoload_dict_func()
call assert_equal(1, g:called_foo_bar_echo)
eval 'bar'->g:foo#addFoo()->assert_equal('barfoo')
+
+ " empty name works in legacy script
+ call assert_equal('empty', foo#())
endfunc
func Test_source_autoload()
@@ -17,3 +20,6 @@ func Test_source_autoload()
source sautest/autoload/sourced.vim
call assert_equal(1, g:loaded_sourced_vim)
endfunc
+
+
+" vim: shiftwidth=2 sts=2 expandtab
diff --git a/src/nvim/testdir/test_backup.vim b/src/nvim/testdir/test_backup.vim
index ce2bfe72bc..d304773da4 100644
--- a/src/nvim/testdir/test_backup.vim
+++ b/src/nvim/testdir/test_backup.vim
@@ -1,5 +1,7 @@
" Tests for the backup function
+source check.vim
+
func Test_backup()
set backup backupdir=. backupskip=
new
@@ -17,6 +19,22 @@ func Test_backup()
call delete('Xbackup.txt~')
endfunc
+func Test_backup_backupskip()
+ set backup backupdir=. backupskip=*.txt
+ new
+ call setline(1, ['line1', 'line2'])
+ :f Xbackup.txt
+ :w! Xbackup.txt
+ " backup file is only created after
+ " writing a second time (before overwriting)
+ :w! Xbackup.txt
+ call assert_false(filereadable('Xbackup.txt~'))
+ bw!
+ set backup&vim backupdir&vim backupskip&vim
+ call delete('Xbackup.txt')
+ call delete('Xbackup.txt~')
+endfunc
+
func Test_backup2()
set backup backupdir=.// backupskip=
new
@@ -28,7 +46,7 @@ func Test_backup2()
:w! Xbackup.txt
sp *Xbackup.txt~
call assert_equal(['line1', 'line2', 'line3'], getline(1,'$'))
- let f=expand('%')
+ let f = expand('%')
call assert_match('%testdir%Xbackup.txt\~', f)
bw!
bw!
@@ -48,7 +66,7 @@ func Test_backup2_backupcopy()
:w! Xbackup.txt
sp *Xbackup.txt~
call assert_equal(['line1', 'line2', 'line3'], getline(1,'$'))
- let f=expand('%')
+ let f = expand('%')
call assert_match('%testdir%Xbackup.txt\~', f)
bw!
bw!
@@ -56,3 +74,16 @@ func Test_backup2_backupcopy()
call delete(f)
set backup&vim backupdir&vim backupcopy&vim backupskip&vim
endfunc
+
+" Test for using a non-existing directory as a backup directory
+func Test_non_existing_backupdir()
+ throw 'Skipped: Nvim auto-creates backup directory'
+ set backupdir=./non_existing_dir backupskip=
+ call writefile(['line1'], 'Xfile')
+ new Xfile
+ call assert_fails('write', 'E510:')
+ set backupdir&vim backupskip&vim
+ call delete('Xfile')
+endfunc
+
+" vim: shiftwidth=2 sts=2 expandtab
diff --git a/src/nvim/testdir/test_blob.vim b/src/nvim/testdir/test_blob.vim
index af42b3857d..046acb81e1 100644
--- a/src/nvim/testdir/test_blob.vim
+++ b/src/nvim/testdir/test_blob.vim
@@ -88,6 +88,7 @@ func Test_blob_get_range()
call assert_equal(0z0011223344, b[:])
call assert_equal(0z0011223344, b[:-1])
call assert_equal(0z, b[5:6])
+ call assert_equal(0z0011, b[-10:1])
endfunc
func Test_blob_get()
@@ -208,6 +209,7 @@ func Test_blob_add()
call assert_equal(0z001122, b)
call add(b, '51')
call assert_equal(0z00112233, b)
+ call assert_equal(1, add(v:_null_blob, 0x22))
call assert_fails('call add(b, [9])', 'E745:')
call assert_fails('call add("", 0x01)', 'E897:')
@@ -250,6 +252,7 @@ func Test_blob_func_remove()
call assert_fails("call remove(b, 3, 2)", 'E979:')
call assert_fails("call remove(1, 0)", 'E896:')
call assert_fails("call remove(b, b)", 'E974:')
+ call assert_fails("call remove(b, 1, [])", 'E745:')
call assert_fails("call remove(v:_null_blob, 1, 2)", 'E979:')
" Translated from v8.2.3284
@@ -272,6 +275,7 @@ endfunc
" filter() item in blob
func Test_blob_filter()
+ call assert_equal(v:_null_blob, filter(v:_null_blob, '0'))
call assert_equal(0z, filter(0zDEADBEEF, '0'))
call assert_equal(0zADBEEF, filter(0zDEADBEEF, 'v:val != 0xDE'))
call assert_equal(0zDEADEF, filter(0zDEADBEEF, 'v:val != 0xBE'))
@@ -294,9 +298,12 @@ func Test_blob_index()
call assert_equal(2, index(0zDEADBEEF, 0xBE))
call assert_equal(-1, index(0zDEADBEEF, 0))
call assert_equal(2, index(0z11111111, 0x11, 2))
- call assert_equal(3, index(0z11110111, 0x11, 2))
+ call assert_equal(3, 0z11110111->index(0x11, 2))
call assert_equal(2, index(0z11111111, 0x11, -2))
call assert_equal(3, index(0z11110111, 0x11, -2))
+ call assert_equal(0, index(0z11110111, 0x11, -10))
+ call assert_fails("echo index(0z11110111, 0x11, [])", 'E745:')
+ call assert_equal(-1, index(v:_null_blob, 1))
call assert_fails('call index("asdf", 0)', 'E897:')
endfunc
@@ -313,6 +320,9 @@ func Test_blob_insert()
call assert_fails('call insert(b, -1)', 'E475:')
call assert_fails('call insert(b, 257)', 'E475:')
call assert_fails('call insert(b, 0, [9])', 'E745:')
+ call assert_fails('call insert(b, 0, -20)', 'E475:')
+ call assert_fails('call insert(b, 0, 20)', 'E475:')
+ call assert_fails('call insert(b, [])', 'E745:')
call assert_equal(0, insert(v:_null_blob, 0x33))
" Translated from v8.2.3284
diff --git a/src/nvim/testdir/test_breakindent.vim b/src/nvim/testdir/test_breakindent.vim
index a37751e748..2e377aa434 100644
--- a/src/nvim/testdir/test_breakindent.vim
+++ b/src/nvim/testdir/test_breakindent.vim
@@ -4,11 +4,11 @@
" while the test is run, the breakindent caching gets in its way.
" It helps to change the tabstop setting and force a redraw (e.g. see
" Test_breakindent08())
-if !exists('+breakindent')
- throw 'Skipped: breakindent option not supported'
-endif
+source check.vim
+CheckOption breakindent
source view_util.vim
+source screendump.vim
let s:input ="\tabcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOP"
@@ -422,6 +422,7 @@ func Test_breakindent11()
let width = strlen(text[1:]) + indent(2) + strlen(&sbr) * 3 " text wraps 3 times
call assert_equal(width, strdisplaywidth(text))
call s:close_windows('set sbr=')
+ call assert_equal(4, strdisplaywidth("\t", 4))
endfunc
func Test_breakindent11_vartabs()
@@ -855,7 +856,7 @@ func Test_breakindent20_list()
" check formatlistpat indent with different list level
" showbreak and sbr
- setl briopt=min:5,sbr,list:-1,shift:2
+ setl briopt=min:5,sbr,list:-1
setl showbreak=>
redraw!
let expect = [
@@ -868,6 +869,44 @@ func Test_breakindent20_list()
\ ]
let lines = s:screen_lines2(1, 6, 20)
call s:compare_lines(expect, lines)
+
+ " check formatlistpat indent with different list level
+ " showbreak sbr and shift
+ setl briopt=min:5,sbr,list:-1,shift:2
+ setl showbreak=>
+ redraw!
+ let expect = [
+ \ "* Congress shall ",
+ \ "> make no law ",
+ \ "*** Congress shall ",
+ \ "> make no law ",
+ \ "**** Congress shall ",
+ \ "> make no law ",
+ \ ]
+ let lines = s:screen_lines2(1, 6, 20)
+ call s:compare_lines(expect, lines)
+
+ " check breakindent works if breakindentopt=list:-1
+ " for a non list content
+ %delete _
+ call setline(1, [' Congress shall make no law',
+ \ ' Congress shall make no law',
+ \ ' Congress shall make no law'])
+ norm! 1gg
+ setl briopt=min:5,list:-1
+ setl showbreak=
+ redraw!
+ let expect = [
+ \ " Congress shall ",
+ \ " make no law ",
+ \ " Congress shall ",
+ \ " make no law ",
+ \ " Congress shall ",
+ \ " make no law ",
+ \ ]
+ let lines = s:screen_lines2(1, 6, 20)
+ call s:compare_lines(expect, lines)
+
call s:close_windows('set breakindent& briopt& linebreak& list& listchars& showbreak&')
endfunc
@@ -876,17 +915,164 @@ endfunc
func Test_window_resize_with_linebreak()
new
53vnew
- set linebreak
- set showbreak=>>
- set breakindent
- set breakindentopt=shift:4
+ setl linebreak
+ setl showbreak=>>
+ setl breakindent
+ setl breakindentopt=shift:4
call setline(1, "\naaaaaaaaa\n\na\naaaaa\n¯aaaaaaaaaa\naaaaaaaaaaaa\naaa\n\"a:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa - aaaaaaaa\"\naaaaaaaa\n\"a")
redraw!
call assert_equal([" >>aa^@\"a: "], ScreenLines(2, 14))
vertical resize 52
redraw!
call assert_equal([" >>aaa^@\"a:"], ScreenLines(2, 14))
+ set linebreak& showbreak& breakindent& breakindentopt&
%bw!
endfunc
+func Test_cursor_position_with_showbreak()
+ CheckScreendump
+
+ let lines =<< trim END
+ vim9script
+ &signcolumn = 'yes'
+ &showbreak = '+ '
+ var leftcol: number = win_getid()->getwininfo()->get(0, {})->get('textoff')
+ repeat('x', &columns - leftcol - 1)->setline(1)
+ 'second line'->setline(2)
+ END
+ call writefile(lines, 'XscriptShowbreak')
+ let buf = RunVimInTerminal('-S XscriptShowbreak', #{rows: 6})
+
+ call term_sendkeys(buf, "AX")
+ call VerifyScreenDump(buf, 'Test_cursor_position_with_showbreak', {})
+
+ call StopVimInTerminal(buf)
+ call delete('XscriptShowbreak')
+endfunc
+
+func Test_no_spurious_match()
+ let s:input = printf('- y %s y %s', repeat('x', 50), repeat('x', 50))
+ call s:test_windows('setl breakindent breakindentopt=list:-1 formatlistpat=^- hls')
+ let @/ = '\%>3v[y]'
+ redraw!
+ call searchcount().total->assert_equal(1)
+ " cleanup
+ set hls&vim
+ let s:input = "\tabcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOP"
+ bwipeout!
+endfunc
+
+func Test_no_extra_indent()
+ call s:test_windows('setl breakindent breakindentopt=list:-1,min:10')
+ %d
+ let &l:formatlistpat='^\s*\d\+\.\s\+'
+ let text = 'word '
+ let len = text->strcharlen()
+ let line1 = text->repeat((winwidth(0) / len) * 2)
+ let line2 = repeat(' ', 2) .. '1. ' .. line1
+ call setline(1, [line2])
+ redraw!
+ " 1) matches formatlist pattern, so indent
+ let expect = [
+ \ " 1. word word word ",
+ \ " word word word ",
+ \ " word word ",
+ \ "~ ",
+ \ ]
+ let lines = s:screen_lines2(1, 4, 20)
+ call s:compare_lines(expect, lines)
+ " 2) change formatlist pattern
+ " -> indent adjusted
+ let &l:formatlistpat='^\s*\d\+\.'
+ let expect = [
+ \ " 1. word word word ",
+ \ " word word word ",
+ \ " word word ",
+ \ "~ ",
+ \ ]
+ let lines = s:screen_lines2(1, 4, 20)
+ " 3) no local formatlist pattern,
+ " so use global one -> indent
+ let g_flp = &g:flp
+ let &g:formatlistpat='^\s*\d\+\.\s\+'
+ let &l:formatlistpat=''
+ let expect = [
+ \ " 1. word word word ",
+ \ " word word word ",
+ \ " word word ",
+ \ "~ ",
+ \ ]
+ let lines = s:screen_lines2(1, 4, 20)
+ call s:compare_lines(expect, lines)
+ let &g:flp = g_flp
+ let &l:formatlistpat='^\s*\d\+\.'
+ " 4) add something in front, no additional indent
+ norm! gg0
+ exe ":norm! 5iword \<esc>"
+ redraw!
+ let expect = [
+ \ "word word word word ",
+ \ "word 1. word word ",
+ \ "word word word word ",
+ \ "word word ",
+ \ "~ ",
+ \ ]
+ let lines = s:screen_lines2(1, 5, 20)
+ call s:compare_lines(expect, lines)
+ bwipeout!
+endfunc
+
+func Test_breakindent_column()
+ " restore original
+ let s:input ="\tabcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOP"
+ call s:test_windows('setl breakindent breakindentopt=column:10')
+ redraw!
+ " 1) default: does not indent, too wide :(
+ let expect = [
+ \ " ",
+ \ " abcdefghijklmnop",
+ \ "qrstuvwxyzABCDEFGHIJ",
+ \ "KLMNOP "
+ \ ]
+ let lines = s:screen_lines2(1, 4, 20)
+ call s:compare_lines(expect, lines)
+ " 2) lower min value, so that breakindent works
+ setl breakindentopt+=min:5
+ redraw!
+ let expect = [
+ \ " ",
+ \ " abcdefghijklmnop",
+ \ " qrstuvwxyz",
+ \ " ABCDEFGHIJ",
+ \ " KLMNOP "
+ \ ]
+ let lines = s:screen_lines2(1, 5, 20)
+ " 3) set shift option -> no influence
+ setl breakindentopt+=shift:5
+ redraw!
+ let expect = [
+ \ " ",
+ \ " abcdefghijklmnop",
+ \ " qrstuvwxyz",
+ \ " ABCDEFGHIJ",
+ \ " KLMNOP "
+ \ ]
+ let lines = s:screen_lines2(1, 5, 20)
+ call s:compare_lines(expect, lines)
+ " 4) add showbreak value
+ setl showbreak=++
+ redraw!
+ let expect = [
+ \ " ",
+ \ " abcdefghijklmnop",
+ \ " ++qrstuvwx",
+ \ " ++yzABCDEF",
+ \ " ++GHIJKLMN",
+ \ " ++OP "
+ \ ]
+ let lines = s:screen_lines2(1, 6, 20)
+ call s:compare_lines(expect, lines)
+ bwipeout!
+endfunc
+
" vim: shiftwidth=2 sts=2 expandtab
diff --git a/src/nvim/testdir/test_buffer.vim b/src/nvim/testdir/test_buffer.vim
index 67be3e6747..9220cc17b9 100644
--- a/src/nvim/testdir/test_buffer.vim
+++ b/src/nvim/testdir/test_buffer.vim
@@ -67,16 +67,7 @@ func Test_bunload_with_offset()
call assert_fails('1,4bunload', 'E16:')
call assert_fails(',100bunload', 'E16:')
- " Use a try-catch for this test. When assert_fails() is used for this
- " test, the command fails with E515: instead of E90:
- let caught_E90 = 0
- try
- $bunload
- catch /E90:/
- let caught_E90 = 1
- endtry
- call assert_equal(1, caught_E90)
- call assert_fails('$bunload', 'E515:')
+ call assert_fails('$bunload', 'E90:')
endfunc
" Test for :buffer, :bnext, :bprevious, :brewind, :blast and :bmodified
@@ -147,6 +138,7 @@ func Test_bdelete_cmd()
%bwipe!
call assert_fails('bdelete 5', 'E516:')
call assert_fails('1,1bdelete 1 2', 'E488:')
+ call assert_fails('bdelete \)', 'E55:')
" Deleting a unlisted and unloaded buffer
edit Xfile1
@@ -154,6 +146,24 @@ func Test_bdelete_cmd()
set nobuflisted
enew
call assert_fails('bdelete ' .. bnr, 'E516:')
+
+ " Deleting more than one buffer
+ new Xbuf1
+ new Xbuf2
+ exe 'bdel ' .. bufnr('Xbuf2') .. ' ' .. bufnr('Xbuf1')
+ call assert_equal(1, winnr('$'))
+ call assert_equal(0, getbufinfo('Xbuf1')[0].loaded)
+ call assert_equal(0, getbufinfo('Xbuf2')[0].loaded)
+
+ " Deleting more than one buffer and an invalid buffer
+ new Xbuf1
+ new Xbuf2
+ let cmd = "exe 'bdel ' .. bufnr('Xbuf2') .. ' xxx ' .. bufnr('Xbuf1')"
+ call assert_fails(cmd, 'E94:')
+ call assert_equal(2, winnr('$'))
+ call assert_equal(1, getbufinfo('Xbuf1')[0].loaded)
+ call assert_equal(0, getbufinfo('Xbuf2')[0].loaded)
+
%bwipe!
endfunc
@@ -168,6 +178,194 @@ func Test_buffer_error()
%bwipe
endfunc
+" Test for the status messages displayed when unloading, deleting or wiping
+" out buffers
+func Test_buffer_statusmsg()
+ CheckEnglish
+ set report=1
+ new Xbuf1
+ new Xbuf2
+ let bnr = bufnr()
+ exe "normal 2\<C-G>"
+ call assert_match('buf ' .. bnr .. ':', v:statusmsg)
+ bunload Xbuf1 Xbuf2
+ call assert_equal('2 buffers unloaded', v:statusmsg)
+ bdel Xbuf1 Xbuf2
+ call assert_equal('2 buffers deleted', v:statusmsg)
+ bwipe Xbuf1 Xbuf2
+ call assert_equal('2 buffers wiped out', v:statusmsg)
+ set report&
+endfunc
+
+" Test for quitting the 'swapfile exists' dialog with the split buffer
+" command.
+func Test_buffer_sbuf_cleanup()
+ call writefile([], 'Xfile')
+ " first open the file in a buffer
+ new Xfile
+ let bnr = bufnr()
+ close
+ " create the swap file
+ call writefile([], '.Xfile.swp')
+ " Remove the catch-all that runtest.vim adds
+ au! SwapExists
+ augroup BufTest
+ au!
+ autocmd SwapExists Xfile let v:swapchoice='q'
+ augroup END
+ exe 'sbuf ' . bnr
+ call assert_equal(1, winnr('$'))
+ call assert_equal(0, getbufinfo('Xfile')[0].loaded)
+
+ " test for :sball
+ sball
+ call assert_equal(1, winnr('$'))
+ call assert_equal(0, getbufinfo('Xfile')[0].loaded)
+
+ %bw!
+ set shortmess+=F
+ let v:statusmsg = ''
+ edit Xfile
+ call assert_equal('', v:statusmsg)
+ call assert_equal(1, winnr('$'))
+ call assert_equal(0, getbufinfo('Xfile')[0].loaded)
+ set shortmess&
+
+ call delete('Xfile')
+ call delete('.Xfile.swp')
+ augroup BufTest
+ au!
+ augroup END
+ augroup! BufTest
+endfunc
+
+" Test for deleting a modified buffer with :confirm
+func Test_bdel_with_confirm()
+ " requires a UI to be active
+ throw 'Skipped: use test/functional/legacy/buffer_spec.lua'
+ CheckUnix
+ CheckNotGui
+ CheckFeature dialog_con
+ new
+ call setline(1, 'test')
+ call assert_fails('bdel', 'E89:')
+ call feedkeys('c', 'L')
+ confirm bdel
+ call assert_equal(2, winnr('$'))
+ call assert_equal(1, &modified)
+ call feedkeys('n', 'L')
+ confirm bdel
+ call assert_equal(1, winnr('$'))
+endfunc
+
+" Test for editing another buffer from a modified buffer with :confirm
+func Test_goto_buf_with_confirm()
+ " requires a UI to be active
+ throw 'Skipped: use test/functional/legacy/buffer_spec.lua'
+ CheckUnix
+ CheckNotGui
+ CheckFeature dialog_con
+ new Xfile
+ enew
+ call setline(1, 'test')
+ call assert_fails('b Xfile', 'E37:')
+ call feedkeys('c', 'L')
+ call assert_fails('confirm b Xfile', 'E37:')
+ call assert_equal(1, &modified)
+ call assert_equal('', @%)
+ call feedkeys('y', 'L')
+ call assert_fails('confirm b Xfile', ['', 'E37:'])
+ call assert_equal(1, &modified)
+ call assert_equal('', @%)
+ call feedkeys('n', 'L')
+ confirm b Xfile
+ call assert_equal('Xfile', @%)
+ close!
+endfunc
+
+" Test for splitting buffer with 'switchbuf'
+func Test_buffer_switchbuf()
+ new Xfile
+ wincmd w
+ set switchbuf=useopen
+ sbuf Xfile
+ call assert_equal(1, winnr())
+ call assert_equal(2, winnr('$'))
+ set switchbuf=usetab
+ tabnew
+ sbuf Xfile
+ call assert_equal(1, tabpagenr())
+ call assert_equal(2, tabpagenr('$'))
+ set switchbuf&
+ %bw
+endfunc
+
+" Test for BufAdd autocommand wiping out the buffer
+func Test_bufadd_autocmd_bwipe()
+ %bw!
+ augroup BufAdd_Wipe
+ au!
+ autocmd BufAdd Xfile %bw!
+ augroup END
+ edit Xfile
+ call assert_equal('', @%)
+ call assert_equal(0, bufexists('Xfile'))
+ augroup BufAdd_Wipe
+ au!
+ augroup END
+ augroup! BufAdd_Wipe
+endfunc
+
+" Test for trying to load a buffer with text locked
+" <C-\>e in the command line is used to lock the text
+func Test_load_buf_with_text_locked()
+ new Xfile1
+ edit Xfile2
+ let cmd = ":\<C-\>eexecute(\"normal \<C-O>\")\<CR>\<C-C>"
+ call assert_fails("call feedkeys(cmd, 'xt')", 'E565:')
+ %bw!
+endfunc
+
+" Test for using CTRL-^ to edit the alternative file keeping the cursor
+" position with 'nostartofline'. Also test using the 'buf' command.
+func Test_buffer_edit_altfile()
+ call writefile(repeat(['one two'], 50), 'Xfile1')
+ call writefile(repeat(['five six'], 50), 'Xfile2')
+ set nosol
+ edit Xfile1
+ call cursor(25, 5)
+ edit Xfile2
+ call cursor(30, 4)
+ exe "normal \<C-^>"
+ call assert_equal([0, 25, 5, 0], getpos('.'))
+ exe "normal \<C-^>"
+ call assert_equal([0, 30, 4, 0], getpos('.'))
+ buf Xfile1
+ call assert_equal([0, 25, 5, 0], getpos('.'))
+ buf Xfile2
+ call assert_equal([0, 30, 4, 0], getpos('.'))
+ set sol&
+ call delete('Xfile1')
+ call delete('Xfile2')
+endfunc
+
+" Test for running the :sball command with a maximum window count and a
+" modified buffer
+func Test_sball_with_count()
+ %bw!
+ edit Xfile1
+ call setline(1, ['abc'])
+ new Xfile2
+ new Xfile3
+ new Xfile4
+ 2sball
+ call assert_equal(bufnr('Xfile4'), winbufnr(1))
+ call assert_equal(bufnr('Xfile1'), winbufnr(2))
+ call assert_equal(0, getbufinfo('Xfile2')[0].loaded)
+ call assert_equal(0, getbufinfo('Xfile3')[0].loaded)
+ %bw!
+endfunc
+
func Test_badd_options()
new SomeNewBuffer
setlocal numberwidth=3
@@ -195,12 +393,12 @@ func Test_buffer_scheme()
set noshellslash
%bwipe!
let bufnames = [
- \ #{id: 'b0', name: 'test://xyz/foo/b0' , match: 1},
- \ #{id: 'b1', name: 'test+abc://xyz/foo/b1', match: 0},
- \ #{id: 'b2', name: 'test_abc://xyz/foo/b2', match: 0},
- \ #{id: 'b3', name: 'test-abc://xyz/foo/b3', match: 1},
- \ #{id: 'b4', name: '-test://xyz/foo/b4' , match: 0},
- \ #{id: 'b5', name: 'test-://xyz/foo/b5' , match: 0},
+ \ #{id: 'ssb0', name: 'test://xyz/foo/ssb0' , match: 1},
+ \ #{id: 'ssb1', name: 'test+abc://xyz/foo/ssb1', match: 0},
+ \ #{id: 'ssb2', name: 'test_abc://xyz/foo/ssb2', match: 0},
+ \ #{id: 'ssb3', name: 'test-abc://xyz/foo/ssb3', match: 1},
+ \ #{id: 'ssb4', name: '-test://xyz/foo/ssb4' , match: 0},
+ \ #{id: 'ssb5', name: 'test-://xyz/foo/ssb5' , match: 0},
\]
for buf in bufnames
new `=buf.name`
@@ -225,6 +423,32 @@ func Test_buf_pattern_invalid()
vsplit 00000000000000000000000000
silent! buf [0--]\&\zs*\zs*e
bwipe!
+
+ " similar case with different code path
+ split 0
+ edit ÿ
+ silent! buf [0--]\&\zs*\zs*0
+ bwipe!
+endfunc
+
+" Test for the 'maxmem' and 'maxmemtot' options
+func Test_buffer_maxmem()
+ " use 1KB per buffer and 2KB for all the buffers
+ " set maxmem=1 maxmemtot=2
+ new
+ let v:errmsg = ''
+ " try opening some files
+ edit test_arglist.vim
+ call assert_equal('test_arglist.vim', bufname())
+ edit test_eval_stuff.vim
+ call assert_equal('test_eval_stuff.vim', bufname())
+ b test_arglist.vim
+ call assert_equal('test_arglist.vim', bufname())
+ b test_eval_stuff.vim
+ call assert_equal('test_eval_stuff.vim', bufname())
+ close
+ call assert_equal('', v:errmsg)
+ " set maxmem& maxmemtot&
endfunc
" vim: shiftwidth=2 sts=2 expandtab
diff --git a/src/nvim/testdir/test_bufline.vim b/src/nvim/testdir/test_bufline.vim
index 579d3a5eb5..0468025f55 100644
--- a/src/nvim/testdir/test_bufline.vim
+++ b/src/nvim/testdir/test_bufline.vim
@@ -2,14 +2,18 @@
source shared.vim
source screendump.vim
+source check.vim
func Test_setbufline_getbufline()
+ " similar to Test_set_get_bufline()
new
let b = bufnr('%')
hide
call assert_equal(0, setbufline(b, 1, ['foo', 'bar']))
call assert_equal(['foo'], getbufline(b, 1))
+ call assert_equal('foo', getbufoneline(b, 1))
call assert_equal(['bar'], getbufline(b, '$'))
+ call assert_equal('bar', getbufoneline(b, '$'))
call assert_equal(['foo', 'bar'], getbufline(b, 1, 2))
exe "bd!" b
call assert_equal([], getbufline(b, 1, 2))
@@ -18,13 +22,36 @@ func Test_setbufline_getbufline()
call setline(1, ['a', 'b', 'c'])
let b = bufnr('%')
wincmd w
+
+ call assert_equal(1, setbufline(b, 5, 'x'))
call assert_equal(1, setbufline(b, 5, ['x']))
- call assert_equal(1, setbufline(bufnr('$') + 1, 1, ['x']))
+ call assert_equal(1, setbufline(b, 5, []))
+ call assert_equal(1, setbufline(b, 5, v:_null_list))
+
+ call assert_equal(1, 'x'->setbufline(bufnr('$') + 1, 1))
+ call assert_equal(1, ['x']->setbufline(bufnr('$') + 1, 1))
+ call assert_equal(1, []->setbufline(bufnr('$') + 1, 1))
+ call assert_equal(1, v:_null_list->setbufline(bufnr('$') + 1, 1))
+
+ call assert_equal(['a', 'b', 'c'], getbufline(b, 1, '$'))
+
call assert_equal(0, setbufline(b, 4, ['d', 'e']))
call assert_equal(['c'], b->getbufline(3))
+ call assert_equal('c', b->getbufoneline(3))
call assert_equal(['d'], getbufline(b, 4))
+ call assert_equal('d', getbufoneline(b, 4))
call assert_equal(['e'], getbufline(b, 5))
+ call assert_equal('e', getbufoneline(b, 5))
call assert_equal([], getbufline(b, 6))
+ call assert_equal([], getbufline(b, 2, 1))
+
+ if has('job')
+ call setbufline(b, 2, [function('eval'), #{key: 123}, test_null_job()])
+ call assert_equal(["function('eval')",
+ \ "{'key': 123}",
+ \ "no process"],
+ \ getbufline(b, 2, 4))
+ endif
exe "bwipe! " . b
endfunc
@@ -71,20 +98,53 @@ func Test_appendbufline()
new
let b = bufnr('%')
hide
+
+ new
+ call setline(1, ['line1', 'line2', 'line3'])
+ normal! 2gggg
+ call assert_equal(2, line("''"))
+
call assert_equal(0, appendbufline(b, 0, ['foo', 'bar']))
call assert_equal(['foo'], getbufline(b, 1))
call assert_equal(['bar'], getbufline(b, 2))
call assert_equal(['foo', 'bar'], getbufline(b, 1, 2))
+ call assert_equal(0, appendbufline(b, 0, 'baz'))
+ call assert_equal(['baz', 'foo', 'bar'], getbufline(b, 1, 3))
+
+ " appendbufline() in a hidden buffer shouldn't move marks in current window.
+ call assert_equal(2, line("''"))
+ bwipe!
+
exe "bd!" b
- call assert_equal([], getbufline(b, 1, 2))
+ call assert_equal([], getbufline(b, 1, 3))
split Xtest
call setline(1, ['a', 'b', 'c'])
let b = bufnr('%')
wincmd w
+
+ call assert_equal(1, appendbufline(b, -1, 'x'))
call assert_equal(1, appendbufline(b, -1, ['x']))
+ call assert_equal(1, appendbufline(b, -1, []))
+ call assert_equal(1, appendbufline(b, -1, v:_null_list))
+
+ call assert_equal(1, appendbufline(b, 4, 'x'))
call assert_equal(1, appendbufline(b, 4, ['x']))
+ call assert_equal(1, appendbufline(b, 4, []))
+ call assert_equal(1, appendbufline(b, 4, v:_null_list))
+
+ call assert_equal(1, appendbufline(1234, 1, 'x'))
call assert_equal(1, appendbufline(1234, 1, ['x']))
+ call assert_equal(1, appendbufline(1234, 1, []))
+ call assert_equal(1, appendbufline(1234, 1, v:_null_list))
+
+ call assert_equal(0, appendbufline(b, 1, []))
+ call assert_equal(0, appendbufline(b, 1, v:_null_list))
+ call assert_equal(1, appendbufline(b, 3, []))
+ call assert_equal(1, appendbufline(b, 3, v:_null_list))
+
+ call assert_equal(['a', 'b', 'c'], getbufline(b, 1, '$'))
+
call assert_equal(0, appendbufline(b, 3, ['d', 'e']))
call assert_equal(['c'], getbufline(b, 3))
call assert_equal(['d'], getbufline(b, 4))
@@ -98,10 +158,21 @@ func Test_deletebufline()
let b = bufnr('%')
call setline(1, ['aaa', 'bbb', 'ccc'])
hide
+
+ new
+ call setline(1, ['line1', 'line2', 'line3'])
+ normal! 2gggg
+ call assert_equal(2, line("''"))
+
call assert_equal(0, deletebufline(b, 2))
call assert_equal(['aaa', 'ccc'], getbufline(b, 1, 2))
call assert_equal(0, deletebufline(b, 2, 8))
call assert_equal(['aaa'], getbufline(b, 1, 2))
+
+ " deletebufline() in a hidden buffer shouldn't move marks in current window.
+ call assert_equal(2, line("''"))
+ bwipe!
+
exe "bd!" b
call assert_equal(1, b->deletebufline(1))
@@ -130,9 +201,8 @@ func Test_deletebufline()
endfunc
func Test_appendbufline_redraw()
- if !CanRunVimInTerminal()
- throw 'Skipped: cannot make screendumps'
- endif
+ CheckScreendump
+
let lines =<< trim END
new foo
let winnr = 'foo'->bufwinnr()
@@ -187,4 +257,40 @@ func Test_deletebufline_select_mode()
bwipe!
endfunc
+func Test_setbufline_startup_nofile()
+ let before =<< trim [CODE]
+ set shortmess+=F
+ file Xresult
+ set buftype=nofile
+ call setbufline('', 1, 'success')
+ [CODE]
+ let after =<< trim [CODE]
+ set buftype=
+ write
+ quit
+ [CODE]
+
+ if !RunVim(before, after, '--clean')
+ return
+ endif
+ call assert_equal(['success'], readfile('Xresult'))
+ call delete('Xresult')
+endfunc
+
+" Test that setbufline(), appendbufline() and deletebufline() should fail and
+" return 1 when "textlock" is active.
+func Test_change_bufline_with_textlock()
+ new
+ inoremap <buffer> <expr> <F2> setbufline('', 1, '')
+ call assert_fails("normal a\<F2>", 'E565:')
+ call assert_equal('1', getline(1))
+ inoremap <buffer> <expr> <F2> appendbufline('', 1, '')
+ call assert_fails("normal a\<F2>", 'E565:')
+ call assert_equal('11', getline(1))
+ inoremap <buffer> <expr> <F2> deletebufline('', 1)
+ call assert_fails("normal a\<F2>", 'E565:')
+ call assert_equal('111', getline(1))
+ bwipe!
+endfunc
+
" vim: shiftwidth=2 sts=2 expandtab
diff --git a/src/nvim/testdir/test_cd.vim b/src/nvim/testdir/test_cd.vim
index a1e53df774..2b37f2c7c0 100644
--- a/src/nvim/testdir/test_cd.vim
+++ b/src/nvim/testdir/test_cd.vim
@@ -5,7 +5,7 @@ source check.vim
func Test_cd_large_path()
" This used to crash with a heap write overflow.
- call assert_fails('cd ' . repeat('x', 5000), 'E472:')
+ call assert_fails('cd ' . repeat('x', 5000), 'E344:')
endfunc
func Test_cd_up_and_down()
@@ -45,9 +45,7 @@ func Test_cd_minus()
call assert_equal(path, getcwd())
" Test for :cd - after a failed :cd
- " v8.2.1183 is not ported yet
- " call assert_fails('cd /nonexistent', 'E344:')
- call assert_fails('cd /nonexistent', 'E472:')
+ call assert_fails('cd /nonexistent', 'E344:')
call assert_equal(path, getcwd())
cd -
call assert_equal(path_dotdot, getcwd())
@@ -68,30 +66,6 @@ func Test_cd_minus()
call delete('Xresult')
endfunc
-func Test_cd_with_cpo_chdir()
- e Xfoo
- call setline(1, 'foo')
- let path = getcwd()
- " set cpo+=.
-
- " :cd should fail when buffer is modified and 'cpo' contains dot.
- " call assert_fails('cd ..', 'E747:')
- call assert_equal(path, getcwd())
-
- " :cd with exclamation mark should succeed.
- cd! ..
- call assert_notequal(path, getcwd())
-
- " :cd should succeed when buffer has been written.
- w!
- exe 'cd ' .. fnameescape(path)
- call assert_equal(path, getcwd())
-
- call delete('Xfoo')
- set cpo&
- bw!
-endfunc
-
" Test for chdir()
func Test_chdir_func()
let topdir = getcwd()
@@ -113,7 +87,7 @@ func Test_chdir_func()
call assert_equal('z', fnamemodify(3->getcwd(2), ':t'))
tabnext | wincmd t
call assert_match('^\[tabpage\] .*/y$', trim(execute('verbose pwd')))
- call chdir('..')
+ eval '..'->chdir()
call assert_equal('Xdir', fnamemodify(getcwd(1, 2), ':t'))
call assert_equal('Xdir', fnamemodify(getcwd(2, 2), ':t'))
call assert_equal('z', fnamemodify(getcwd(3, 2), ':t'))
@@ -127,7 +101,7 @@ func Test_chdir_func()
call assert_equal('testdir', fnamemodify(getcwd(1, 1), ':t'))
" Error case
- call assert_fails("call chdir('dir-abcd')", 'E472:')
+ call assert_fails("call chdir('dir-abcd')", 'E344:')
silent! let d = chdir("dir_abcd")
call assert_equal("", d)
" Should not crash
@@ -259,6 +233,8 @@ endfunc
func Test_getcwd_actual_dir()
CheckFunction test_autochdir
+ CheckOption autochdir
+
let startdir = getcwd()
call mkdir('Xactual')
call test_autochdir()
diff --git a/src/nvim/testdir/test_charsearch.vim b/src/nvim/testdir/test_charsearch.vim
index d386d74f8d..54e0a62ce5 100644
--- a/src/nvim/testdir/test_charsearch.vim
+++ b/src/nvim/testdir/test_charsearch.vim
@@ -43,36 +43,6 @@ func Test_charsearch()
enew!
endfunc
-" Test for t,f,F,T movement commands and 'cpo-;' setting
-func Test_search_cmds()
- enew!
- call append(0, ["aaa two three four", " zzz", "yyy ",
- \ "bbb yee yoo four", "ccc two three four",
- \ "ddd yee yoo four"])
- set cpo-=;
- 1
- normal! 0tt;D
- 2
- normal! 0fz;D
- 3
- normal! $Fy;D
- 4
- normal! $Ty;D
- set cpo+=;
- 5
- normal! 0tt;;D
- 6
- normal! $Ty;;D
-
- call assert_equal('aaa two', getline(1))
- call assert_equal(' z', getline(2))
- call assert_equal('y', getline(3))
- call assert_equal('bbb y', getline(4))
- call assert_equal('ccc', getline(5))
- call assert_equal('ddd yee y', getline(6))
- enew!
-endfunc
-
" Test for character search in virtual edit mode with <Tab>
func Test_csearch_virtualedit()
new
@@ -81,7 +51,7 @@ func Test_csearch_virtualedit()
normal! tb
call assert_equal([0, 1, 2, 6], getpos('.'))
set virtualedit&
- close!
+ bw!
endfunc
" Test for character search failure in latin1 encoding
@@ -95,7 +65,34 @@ func Test_charsearch_latin1()
call assert_beeps('normal $Fz')
call assert_beeps('normal $Tx')
let &encoding = save_enc
- close!
+ bw!
+endfunc
+
+" Test for using character search to find a multibyte character with composing
+" characters.
+func Test_charsearch_composing_char()
+ new
+ call setline(1, "one two thq\u0328\u0301r\u0328\u0301ree")
+ call feedkeys("fr\u0328\u0301", 'xt')
+ call assert_equal([0, 1, 16, 0, 12], getcurpos())
+
+ " use character search with a multi-byte character followed by a
+ " non-composing character
+ call setline(1, "abc deȉf ghi")
+ call feedkeys("ggcf\u0209\u0210", 'xt')
+ call assert_equal("\u0210f ghi", getline(1))
+ bw!
+endfunc
+
+" Test for character search with 'hkmap'
+func Test_charsearch_hkmap()
+ new
+ set hkmap
+ call setline(1, "ùðáâ÷ëòéïçìêöî")
+ call feedkeys("fë", 'xt')
+ call assert_equal([0, 1, 11, 0, 6], getcurpos())
+ set hkmap&
+ bw!
endfunc
" vim: shiftwidth=2 sts=2 expandtab
diff --git a/src/nvim/testdir/test_checkpath.vim b/src/nvim/testdir/test_checkpath.vim
index eff30cf205..f6a3bbce08 100644
--- a/src/nvim/testdir/test_checkpath.vim
+++ b/src/nvim/testdir/test_checkpath.vim
@@ -102,3 +102,20 @@ func Test_checkpath3()
set include&
set includeexpr&
endfunc
+
+" Test for invalid regex in 'include' and 'define' options
+func Test_checkpath_errors()
+ let save_include = &include
+ set include=\\%(
+ call assert_fails('checkpath', 'E53:')
+ let &include = save_include
+
+ let save_define = &define
+ set define=\\%(
+ call assert_fails('dsearch abc', 'E53:')
+ let &define = save_define
+
+ call assert_fails('psearch \%(', 'E53:')
+endfunc
+
+" vim: shiftwidth=2 sts=2 expandtab
diff --git a/src/nvim/testdir/test_clientserver.vim b/src/nvim/testdir/test_clientserver.vim
index edf36b413b..d8b29f6c42 100644
--- a/src/nvim/testdir/test_clientserver.vim
+++ b/src/nvim/testdir/test_clientserver.vim
@@ -2,15 +2,18 @@
source check.vim
CheckFeature job
+
+if !has('clientserver')
+ call assert_fails('call remote_startserver("local")', 'E942:')
+endif
+
CheckFeature clientserver
source shared.vim
func Check_X11_Connection()
if has('x11')
- if empty($DISPLAY)
- throw 'Skipped: $DISPLAY is not set'
- endif
+ CheckEnv DISPLAY
try
call remote_send('xxx', '')
catch
@@ -59,15 +62,16 @@ func Test_client_server()
" the GUI and check that the remote command still works.
" Need to wait for the GUI to start up, otherwise the send hangs in trying
" to send to the terminal window.
- if has('gui_athena') || has('gui_motif')
- " For those GUIs, ignore the 'failed to create input context' error.
+ if has('gui_motif')
+ " For this GUI ignore the 'failed to create input context' error.
call remote_send(name, ":call test_ignore_error('E285') | gui -f\<CR>")
else
call remote_send(name, ":gui -f\<CR>")
endif
" Wait for the server to be up and answering requests.
- sleep 100m
- call WaitForAssert({-> assert_true(name->remote_expr("v:version", "", 1) != "")})
+ " When using valgrind this can be very, very slow.
+ sleep 1
+ call WaitForAssert({-> assert_match('\d', name->remote_expr("v:version", "", 1))}, 10000)
call remote_send(name, ":let testvar = 'maybe'\<CR>")
call WaitForAssert({-> assert_equal('maybe', remote_expr(name, "testvar", "", 2))})
@@ -83,6 +87,7 @@ func Test_client_server()
call writefile(['one', 'two'], 'Xclientfile')
call system(cmd)
call WaitForAssert({-> assert_equal('two', remote_expr(name, "getline(2)", "", 2))})
+ call delete('Xclientfile')
" Expression evaluated locally.
if v:servername == ''
@@ -96,7 +101,7 @@ func Test_client_server()
call remote_send(v:servername, ":let g:testvar2 = 75\<CR>")
call feedkeys('', 'x')
call assert_equal(75, g:testvar2)
- call assert_fails('let v = remote_expr(v:servername, "/2")', 'E449:')
+ call assert_fails('let v = remote_expr(v:servername, "/2")', ['E15:.*/2'])
call remote_send(name, ":call server2client(expand('<client>'), 'got it')\<CR>", 'g:myserverid')
call assert_equal('got it', g:myserverid->remote_read(2))
@@ -136,19 +141,19 @@ func Test_client_server()
" Edit multiple files using --remote
call system(cmd .. ' --remote Xfile1 Xfile2 Xfile3')
- call assert_equal("Xfile1\nXfile2\nXfile3\n", remote_expr(name, 'argv()'))
+ call assert_match(".*Xfile1\n.*Xfile2\n.*Xfile3\n", remote_expr(name, 'argv()'))
eval name->remote_send(":%bw!\<CR>")
" Edit files in separate tab pages
call system(cmd .. ' --remote-tab Xfile1 Xfile2 Xfile3')
- call assert_equal('3', remote_expr(name, 'tabpagenr("$")'))
- call assert_equal('Xfile2', remote_expr(name, 'bufname(tabpagebuflist(2)[0])'))
+ call WaitForAssert({-> assert_equal('3', remote_expr(name, 'tabpagenr("$")'))})
+ call assert_match('.*\<Xfile2', remote_expr(name, 'bufname(tabpagebuflist(2)[0])'))
eval name->remote_send(":%bw!\<CR>")
" Edit a file using --remote-wait
eval name->remote_send(":source $VIMRUNTIME/plugin/rrhelper.vim\<CR>")
call system(cmd .. ' --remote-wait +enew Xfile1')
- call assert_equal("Xfile1", remote_expr(name, 'bufname("#")'))
+ call assert_match('.*\<Xfile1', remote_expr(name, 'bufname("#")'))
eval name->remote_send(":%bw!\<CR>")
" Edit files using --remote-tab-wait
@@ -176,8 +181,12 @@ func Test_client_server()
endif
endtry
+ call assert_fails('call remote_startserver([])', 'E730:')
call assert_fails("let x = remote_peek([])", 'E730:')
- call assert_fails("let x = remote_read('vim10')", 'E277:')
+ call assert_fails("let x = remote_read('vim10')",
+ \ has('unix') ? ['E573:.*vim10'] : 'E277:')
+ call assert_fails("call server2client('abc', 'xyz')",
+ \ has('unix') ? ['E573:.*abc'] : 'E258:')
endfunc
" Uncomment this line to get a debugging log
diff --git a/src/nvim/testdir/test_cmdline.vim b/src/nvim/testdir/test_cmdline.vim
index 35886d42c5..cf1d56ae38 100644
--- a/src/nvim/testdir/test_cmdline.vim
+++ b/src/nvim/testdir/test_cmdline.vim
@@ -3,10 +3,24 @@
source check.vim
source screendump.vim
source view_util.vim
+source shared.vim
+
+func SetUp()
+ func SaveLastScreenLine()
+ let g:Sline = Screenline(&lines - 1)
+ return ''
+ endfunc
+ cnoremap <expr> <F4> SaveLastScreenLine()
+endfunc
+
+func TearDown()
+ delfunc SaveLastScreenLine
+ cunmap <F4>
+endfunc
func Test_complete_tab()
call writefile(['testfile'], 'Xtestfile')
- call feedkeys(":e Xtestf\t\r", "tx")
+ call feedkeys(":e Xtest\t\r", "tx")
call assert_equal('testfile', getline(1))
" Pressing <Tab> after '%' completes the current file, also on MS-Windows
@@ -24,6 +38,47 @@ func Test_complete_list()
" used.
call feedkeys(":chistory \<C-D>\<C-B>\"\<CR>", 'xt')
call assert_equal("\"chistory \<C-D>", @:)
+
+ " Test for displaying the tail of the completion matches
+ set wildmode=longest,full
+ call mkdir('Xtest')
+ call writefile([], 'Xtest/a.c')
+ call writefile([], 'Xtest/a.h')
+ let g:Sline = ''
+ call feedkeys(":e Xtest/\<C-D>\<F4>\<C-B>\"\<CR>", 'xt')
+ call assert_equal('a.c a.h', g:Sline)
+ call assert_equal('"e Xtest/', @:)
+ if has('win32')
+ " Test for 'completeslash'
+ set completeslash=backslash
+ call feedkeys(":e Xtest\<Tab>\<C-B>\"\<CR>", 'xt')
+ call assert_equal('"e Xtest\', @:)
+ call feedkeys(":e Xtest/\<Tab>\<C-B>\"\<CR>", 'xt')
+ call assert_equal('"e Xtest\a.', @:)
+ set completeslash=slash
+ call feedkeys(":e Xtest\<Tab>\<C-B>\"\<CR>", 'xt')
+ call assert_equal('"e Xtest/', @:)
+ call feedkeys(":e Xtest\\\<Tab>\<C-B>\"\<CR>", 'xt')
+ call assert_equal('"e Xtest/a.', @:)
+ set completeslash&
+ endif
+
+ " Test for displaying the tail with wildcards
+ let g:Sline = ''
+ call feedkeys(":e Xtes?/\<C-D>\<F4>\<C-B>\"\<CR>", 'xt')
+ call assert_equal('Xtest/a.c Xtest/a.h', g:Sline)
+ call assert_equal('"e Xtes?/', @:)
+ let g:Sline = ''
+ call feedkeys(":e Xtes*/\<C-D>\<F4>\<C-B>\"\<CR>", 'xt')
+ call assert_equal('Xtest/a.c Xtest/a.h', g:Sline)
+ call assert_equal('"e Xtes*/', @:)
+ let g:Sline = ''
+ call feedkeys(":e Xtes[/\<C-D>\<F4>\<C-B>\"\<CR>", 'xt')
+ call assert_equal(':e Xtes[/', g:Sline)
+ call assert_equal('"e Xtes[/', @:)
+
+ call delete('Xtest', 'rf')
+ set wildmode&
endfunc
func Test_complete_wildmenu()
@@ -88,14 +143,25 @@ func Test_complete_wildmenu()
call assert_equal('"e Xtestfile3 Xtestfile4', @:)
cd -
+ " test for wildmenumode()
+ cnoremap <expr> <F2> wildmenumode()
+ call feedkeys(":cd Xdir\<Tab>\<F2>\<C-B>\"\<CR>", 'tx')
+ call assert_equal('"cd Xdir1/0', @:)
+ call feedkeys(":e Xdir1/\<Tab>\<F2>\<C-B>\"\<CR>", 'tx')
+ call assert_equal('"e Xdir1/Xdir2/1', @:)
+ cunmap <F2>
+
+ " Test for canceling the wild menu by pressing <PageDown> or <PageUp>.
+ " After this pressing <Left> or <Right> should not change the selection.
+ call feedkeys(":sign \<Tab>\<PageDown>\<Left>\<Right>\<C-A>\<C-B>\"\<CR>", 'tx')
+ call assert_equal('"sign define', @:)
+ call histadd('cmd', 'TestWildMenu')
+ call feedkeys(":sign \<Tab>\<PageUp>\<Left>\<Right>\<C-A>\<C-B>\"\<CR>", 'tx')
+ call assert_equal('"TestWildMenu', @:)
+
" cleanup
%bwipe
- call delete('Xdir1/Xdir2/Xtestfile4')
- call delete('Xdir1/Xdir2/Xtestfile3')
- call delete('Xdir1/Xtestfile2')
- call delete('Xdir1/Xtestfile1')
- call delete('Xdir1/Xdir2', 'd')
- call delete('Xdir1', 'd')
+ call delete('Xdir1', 'rf')
set nowildmenu
endfunc
@@ -126,13 +192,74 @@ func Test_wildmenu_screendump()
call delete('XTest_wildmenu')
endfunc
+func Test_redraw_in_autocmd()
+ CheckScreendump
+
+ let lines =<< trim END
+ set cmdheight=2
+ autocmd CmdlineChanged * redraw
+ END
+ call writefile(lines, 'XTest_redraw', 'D')
+
+ let buf = RunVimInTerminal('-S XTest_redraw', {'rows': 8})
+ call term_sendkeys(buf, ":for i in range(3)\<CR>")
+ call VerifyScreenDump(buf, 'Test_redraw_in_autocmd_1', {})
+
+ call term_sendkeys(buf, "let i =")
+ call VerifyScreenDump(buf, 'Test_redraw_in_autocmd_2', {})
+
+ " clean up
+ call term_sendkeys(buf, "\<CR>")
+ call StopVimInTerminal(buf)
+endfunc
+
+func Test_redrawstatus_in_autocmd()
+ CheckScreendump
+
+ let lines =<< trim END
+ set laststatus=2
+ set statusline=%=:%{getcmdline()}
+ autocmd CmdlineChanged * redrawstatus
+ END
+ call writefile(lines, 'XTest_redrawstatus', 'D')
+
+ let buf = RunVimInTerminal('-S XTest_redrawstatus', {'rows': 8})
+ " :redrawstatus is postponed if messages have scrolled
+ call term_sendkeys(buf, ":echo \"one\\ntwo\\nthree\\nfour\"\<CR>")
+ call term_sendkeys(buf, ":foobar")
+ call VerifyScreenDump(buf, 'Test_redrawstatus_in_autocmd_1', {})
+ " it is not postponed if messages have not scrolled
+ call term_sendkeys(buf, "\<Esc>:for in in range(3)")
+ call VerifyScreenDump(buf, 'Test_redrawstatus_in_autocmd_2', {})
+ " with cmdheight=1 messages have scrolled when typing :endfor
+ call term_sendkeys(buf, "\<CR>:endfor")
+ call VerifyScreenDump(buf, 'Test_redrawstatus_in_autocmd_3', {})
+ call term_sendkeys(buf, "\<CR>:set cmdheight=2\<CR>")
+ " with cmdheight=2 messages haven't scrolled when typing :for or :endfor
+ call term_sendkeys(buf, ":for in in range(3)")
+ call VerifyScreenDump(buf, 'Test_redrawstatus_in_autocmd_4', {})
+ call term_sendkeys(buf, "\<CR>:endfor")
+ call VerifyScreenDump(buf, 'Test_redrawstatus_in_autocmd_5', {})
+
+ " clean up
+ call term_sendkeys(buf, "\<CR>")
+ call StopVimInTerminal(buf)
+endfunc
+
func Test_changing_cmdheight()
CheckScreendump
let lines =<< trim END
set cmdheight=1 laststatus=2
+ func EchoTwo()
+ set laststatus=2
+ set cmdheight=5
+ echo 'foo'
+ echo 'bar'
+ set cmdheight=1
+ endfunc
END
- call writefile(lines, 'XTest_cmdheight')
+ call writefile(lines, 'XTest_cmdheight', 'D')
let buf = RunVimInTerminal('-S XTest_cmdheight', {'rows': 8})
call term_sendkeys(buf, ":resize -3\<CR>")
@@ -150,20 +277,30 @@ func Test_changing_cmdheight()
call term_sendkeys(buf, ":set cmdheight-=2\<CR>")
call VerifyScreenDump(buf, 'Test_changing_cmdheight_4', {})
- " reducing window size and then setting cmdheight
+ " reducing window size and then setting cmdheight
call term_sendkeys(buf, ":resize -1\<CR>")
call term_sendkeys(buf, ":set cmdheight=1\<CR>")
call VerifyScreenDump(buf, 'Test_changing_cmdheight_5', {})
+ " setting 'cmdheight' works after outputting two messages
+ call term_sendkeys(buf, ":call EchoTwo()\<CR>")
+ call VerifyScreenDump(buf, 'Test_changing_cmdheight_6', {})
+
+ " clean up
+ call StopVimInTerminal(buf)
+endfunc
+
+func Test_cmdheight_tabline()
+ CheckScreendump
+
+ let buf = RunVimInTerminal('-c "set ls=2" -c "set stal=2" -c "set cmdheight=1"', {'rows': 6})
+ call VerifyScreenDump(buf, 'Test_cmdheight_tabline_1', {})
+
" clean up
call StopVimInTerminal(buf)
- call delete('XTest_cmdheight')
endfunc
func Test_map_completion()
- if !has('cmdline_compl')
- return
- endif
call feedkeys(":map <unique> <si\<Tab>\<Home>\"\<CR>", 'xt')
call assert_equal('"map <unique> <silent>', getreg(':'))
call feedkeys(":map <script> <un\<Tab>\<Home>\"\<CR>", 'xt')
@@ -234,29 +371,30 @@ func Test_map_completion()
unmap <Left>
" set cpo-=k
+ call assert_fails('call feedkeys(":map \\\\%(\<Tab>\<Home>\"\<CR>", "xt")', 'E53:')
+
unmap <Middle>x
set cpo&vim
endfunc
func Test_match_completion()
- if !has('cmdline_compl')
- return
- endif
hi Aardig ctermfg=green
- call feedkeys(":match \<Tab>\<Home>\"\<CR>", 'xt')
- call assert_equal('"match Aardig', getreg(':'))
+ " call feedkeys(":match \<Tab>\<Home>\"\<CR>", 'xt')
+ call feedkeys(":match A\<Tab>\<Home>\"\<CR>", 'xt')
+ call assert_equal('"match Aardig', @:)
call feedkeys(":match \<S-Tab>\<Home>\"\<CR>", 'xt')
- call assert_equal('"match none', getreg(':'))
+ call assert_equal('"match none', @:)
+ call feedkeys(":match | chist\<Tab>\<C-B>\"\<CR>", 'xt')
+ call assert_equal('"match | chistory', @:)
endfunc
func Test_highlight_completion()
- if !has('cmdline_compl')
- return
- endif
hi Aardig ctermfg=green
- call feedkeys(":hi \<Tab>\<Home>\"\<CR>", 'xt')
+ " call feedkeys(":hi \<Tab>\<Home>\"\<CR>", 'xt')
+ call feedkeys(":hi A\<Tab>\<Home>\"\<CR>", 'xt')
call assert_equal('"hi Aardig', getreg(':'))
- call feedkeys(":hi default \<Tab>\<Home>\"\<CR>", 'xt')
+ " call feedkeys(":hi default \<Tab>\<Home>\"\<CR>", 'xt')
+ call feedkeys(":hi default A\<Tab>\<Home>\"\<CR>", 'xt')
call assert_equal('"hi default Aardig', getreg(':'))
call feedkeys(":hi clear Aa\<Tab>\<Home>\"\<CR>", 'xt')
call assert_equal('"hi clear Aardig', getreg(':'))
@@ -276,39 +414,7 @@ func Test_highlight_completion()
call assert_equal([], getcompletion('A', 'highlight'))
endfunc
-func Test_expr_completion()
- if !has('cmdline_compl')
- return
- endif
- for cmd in [
- \ 'let a = ',
- \ 'const a = ',
- \ 'if',
- \ 'elseif',
- \ 'while',
- \ 'for',
- \ 'echo',
- \ 'echon',
- \ 'execute',
- \ 'echomsg',
- \ 'echoerr',
- \ 'call',
- \ 'return',
- \ 'cexpr',
- \ 'caddexpr',
- \ 'cgetexpr',
- \ 'lexpr',
- \ 'laddexpr',
- \ 'lgetexpr']
- call feedkeys(":" . cmd . " getl\<Tab>\<Home>\"\<CR>", 'xt')
- call assert_equal('"' . cmd . ' getline(', getreg(':'))
- endfor
-endfunc
-
func Test_getcompletion()
- if !has('cmdline_compl')
- return
- endif
let groupcount = len(getcompletion('', 'event'))
call assert_true(groupcount > 0)
let matchcount = len('File'->getcompletion('event'))
@@ -323,6 +429,7 @@ func Test_getcompletion()
call assert_true(matchcount > 0)
let matchcount = len(getcompletion('File.', 'menu'))
call assert_true(matchcount > 0)
+ source $VIMRUNTIME/delmenu.vim
endif
let l = getcompletion('v:n', 'var')
@@ -333,6 +440,8 @@ func Test_getcompletion()
args a.c b.c
let l = getcompletion('', 'arglist')
call assert_equal(['a.c', 'b.c'], l)
+ let l = getcompletion('a.', 'buffer')
+ call assert_equal(['a.c'], l)
%argdelete
let l = getcompletion('', 'augroup')
@@ -388,6 +497,11 @@ func Test_getcompletion()
let l = getcompletion('run', 'file', 1)
call assert_true(index(l, 'runtest.vim') < 0)
set wildignore&
+ " Directory name with space character
+ call mkdir('Xdir with space')
+ call assert_equal(['Xdir with space/'], getcompletion('Xdir\ w', 'shellcmd'))
+ call assert_equal(['./Xdir with space/'], getcompletion('./Xdir', 'shellcmd'))
+ call delete('Xdir with space', 'd')
let l = getcompletion('ha', 'filetype')
call assert_true(index(l, 'hamster') >= 0)
@@ -462,11 +576,17 @@ func Test_getcompletion()
call assert_equal(cmds, l)
let l = getcompletion('list ', 'sign')
call assert_equal(['Testing'], l)
+ let l = getcompletion('de*', 'sign')
+ call assert_equal(['define'], l)
+ let l = getcompletion('p?', 'sign')
+ call assert_equal(['place'], l)
+ let l = getcompletion('j.', 'sign')
+ call assert_equal(['jump'], l)
endif
" Command line completion tests
let l = getcompletion('cd ', 'cmdline')
- call assert_true(index(l, 'sautest/') >= 0)
+ call assert_true(index(l, 'samples/') >= 0)
let l = getcompletion('cd NoMatch', 'cmdline')
call assert_equal([], l)
let l = getcompletion('let v:n', 'cmdline')
@@ -514,10 +634,39 @@ func Test_getcompletion()
call delete('Xtags')
set tags&
+ edit a~b
+ enew
+ call assert_equal(['a~b'], getcompletion('a~', 'buffer'))
+ bw a~b
+
+ if has('unix')
+ edit Xtest\
+ enew
+ call assert_equal(['Xtest\'], getcompletion('Xtest\', 'buffer'))
+ bw Xtest\
+ endif
+
+ call assert_fails("call getcompletion('\\\\@!\\\\@=', 'buffer')", 'E871:')
call assert_fails('call getcompletion("", "burp")', 'E475:')
call assert_fails('call getcompletion("abc", [])', 'E475:')
endfunc
+" Test for getcompletion() with "fuzzy" in 'wildoptions'
+func Test_getcompletion_wildoptions()
+ let save_wildoptions = &wildoptions
+ set wildoptions&
+ let l = getcompletion('space', 'option')
+ call assert_equal([], l)
+ let l = getcompletion('ier', 'command')
+ call assert_equal([], l)
+ set wildoptions=fuzzy
+ let l = getcompletion('space', 'option')
+ call assert_true(index(l, 'backspace') >= 0)
+ let l = getcompletion('ier', 'command')
+ call assert_true(index(l, 'compiler') >= 0)
+ let &wildoptions = save_wildoptions
+endfunc
+
func Test_fullcommand()
let tests = {
\ '': '',
@@ -590,7 +739,7 @@ func Test_expand_star_star()
call mkdir('a/b', 'p')
call writefile(['asdfasdf'], 'a/b/fileXname')
call feedkeys(":find **/fileXname\<Tab>\<CR>", 'xt')
- call assert_equal('find a/b/fileXname', getreg(':'))
+ call assert_equal('find a/b/fileXname', @:)
bwipe!
call delete('a', 'rf')
endfunc
@@ -738,7 +887,31 @@ func Test_cmdline_complete_user_cmd()
call assert_equal('"Foo blue', @:)
call feedkeys(":Foo b\<Tab>\<Home>\"\<cr>", 'tx')
call assert_equal('"Foo blue', @:)
+ call feedkeys(":Foo a b\<Tab>\<Home>\"\<cr>", 'tx')
+ call assert_equal('"Foo a blue', @:)
+ call feedkeys(":Foo b\\\<Tab>\<Home>\"\<cr>", 'tx')
+ call assert_equal('"Foo b\', @:)
+ call feedkeys(":Foo b\\x\<Tab>\<Home>\"\<cr>", 'tx')
+ call assert_equal('"Foo b\x', @:)
delcommand Foo
+
+ redraw
+ call assert_equal('~', Screenline(&lines - 1))
+ command! FooOne :
+ command! FooTwo :
+
+ set nowildmenu
+ call feedkeys(":Foo\<Tab>\<Home>\"\<cr>", 'tx')
+ call assert_equal('"FooOne', @:)
+ call assert_equal('~', Screenline(&lines - 1))
+
+ call feedkeys(":Foo\<S-Tab>\<Home>\"\<cr>", 'tx')
+ call assert_equal('"FooTwo', @:)
+ call assert_equal('~', Screenline(&lines - 1))
+
+ delcommand FooOne
+ delcommand FooTwo
+ set wildmenu&
endfunc
func Test_complete_user_cmd()
@@ -809,7 +982,7 @@ func Test_cmdline_complete_bang()
endif
endfunc
-funct Test_cmdline_complete_languages()
+func Test_cmdline_complete_languages()
let lang = substitute(execute('language time'), '.*"\(.*\)"$', '\1', '')
call assert_equal(lang, v:lc_time)
@@ -846,10 +1019,8 @@ endfunc
func Test_cmdline_complete_env_variable()
let $X_VIM_TEST_COMPLETE_ENV = 'foo'
-
call feedkeys(":edit $X_VIM_TEST_COMPLETE_E\<C-A>\<C-B>\"\<CR>", 'tx')
call assert_match('"edit $X_VIM_TEST_COMPLETE_ENV', @:)
-
unlet $X_VIM_TEST_COMPLETE_ENV
endfunc
@@ -926,6 +1097,10 @@ func Test_cmdline_complete_various()
call feedkeys(":all abc\<C-A>\<C-B>\"\<CR>", 'xt')
call assert_equal("\"all abc\<C-A>", @:)
+ " completion for :wincmd with :horizontal modifier
+ call feedkeys(":horizontal wincm\<C-A>\<C-B>\"\<CR>", 'xt')
+ call assert_equal("\"horizontal wincmd", @:)
+
" completion for a command with a command modifier
call feedkeys(":topleft new\<C-A>\<C-B>\"\<CR>", 'xt')
call assert_equal("\"topleft new", @:)
@@ -934,14 +1109,6 @@ func Test_cmdline_complete_various()
call feedkeys(":match Search /pat/\<C-A>\<C-B>\"\<CR>", 'xt')
call assert_equal("\"match Search /pat/\<C-A>", @:)
- " completion for the :s command
- call feedkeys(":s/from/to/g\<C-A>\<C-B>\"\<CR>", 'xt')
- call assert_equal("\"s/from/to/g\<C-A>", @:)
-
- " completion for the :dlist command
- call feedkeys(":dlist 10 /pat/ a\<C-A>\<C-B>\"\<CR>", 'xt')
- call assert_equal("\"dlist 10 /pat/ a\<C-A>", @:)
-
" completion for the :doautocmd command
call feedkeys(":doautocmd User MyCmd a.c\<C-A>\<C-B>\"\<CR>", 'xt')
call assert_equal("\"doautocmd User MyCmd a.c\<C-A>", @:)
@@ -1001,7 +1168,7 @@ func Test_cmdline_complete_various()
map <F3> :ls<CR>
com -nargs=* -complete=mapping MyCmd
call feedkeys(":MyCmd <F\<C-A>\<C-B>\"\<CR>", 'xt')
- call assert_equal('"MyCmd <F3>', @:)
+ call assert_equal('"MyCmd <F3> <F4>', @:)
mapclear
delcom MyCmd
@@ -1025,9 +1192,77 @@ func Test_cmdline_complete_various()
call feedkeys(":e `a1b2c\t\<C-B>\"\<CR>", 'xt')
call assert_equal('"e `a1b2c', @:)
- " completion for the expression register
- call feedkeys(":\"\<C-R>=float2\t\"\<C-B>\"\<CR>", 'xt')
- call assert_equal('"float2nr("', @=)
+ " completion for :language command with an invalid argument
+ call feedkeys(":language dummy \t\<C-B>\"\<CR>", 'xt')
+ call assert_equal("\"language dummy \t", @:)
+
+ " completion for commands after a :global command
+ call feedkeys(":g/a\\xb/clearj\t\<C-B>\"\<CR>", 'xt')
+ call assert_equal('"g/a\xb/clearjumps', @:)
+
+ " completion with ambiguous user defined commands
+ com TCmd1 echo 'TCmd1'
+ com TCmd2 echo 'TCmd2'
+ call feedkeys(":TCmd \t\<C-B>\"\<CR>", 'xt')
+ call assert_equal('"TCmd ', @:)
+ delcom TCmd1
+ delcom TCmd2
+
+ " completion after a range followed by a pipe (|) character
+ call feedkeys(":1,10 | chist\t\<C-B>\"\<CR>", 'xt')
+ call assert_equal('"1,10 | chistory', @:)
+
+ " completion after a :global command
+ call feedkeys(":g/a/chist\t\<C-B>\"\<CR>", 'xt')
+ call assert_equal('"g/a/chistory', @:)
+ call feedkeys(":g/a\\/chist\t\<C-B>\"\<CR>", 'xt')
+ call assert_equal("\"g/a\\/chist\t", @:)
+
+ " use <Esc> as the 'wildchar' for completion
+ set wildchar=<Esc>
+ call feedkeys(":g/a\\xb/clearj\<Esc>\<C-B>\"\<CR>", 'xt')
+ call assert_equal('"g/a\xb/clearjumps', @:)
+ " pressing <esc> twice should cancel the command
+ call feedkeys(":chist\<Esc>\<Esc>", 'xt')
+ call assert_equal('"g/a\xb/clearjumps', @:)
+ set wildchar&
+
+ if has('unix')
+ " should be able to complete a file name that starts with a '~'.
+ call writefile([], '~Xtest')
+ call feedkeys(":e \\~X\<Tab>\<C-B>\"\<CR>", 'xt')
+ call assert_equal('"e \~Xtest', @:)
+ call delete('~Xtest')
+
+ " should be able to complete a file name that has a '*'
+ call writefile([], 'Xx*Yy')
+ call feedkeys(":e Xx\*\<Tab>\<C-B>\"\<CR>", 'xt')
+ call assert_equal('"e Xx\*Yy', @:)
+ call delete('Xx*Yy')
+
+ " use a literal star
+ call feedkeys(":e \\*\<Tab>\<C-B>\"\<CR>", 'xt')
+ call assert_equal('"e \*', @:)
+ endif
+
+ call feedkeys(":py3f\<Tab>\<C-B>\"\<CR>", 'xt')
+ call assert_equal('"py3file', @:)
+endfunc
+
+" Test for 'wildignorecase'
+func Test_cmdline_wildignorecase()
+ CheckUnix
+ call writefile([], 'XTEST')
+ set wildignorecase
+ call feedkeys(":e xt\<Tab>\<C-B>\"\<CR>", 'xt')
+ call assert_equal('"e XTEST', @:)
+ call assert_equal(['XTEST'], getcompletion('xt', 'file'))
+ let g:Sline = ''
+ call feedkeys(":e xt\<C-d>\<F4>\<C-B>\"\<CR>", 'xt')
+ call assert_equal('"e xt', @:)
+ call assert_equal('XTEST', g:Sline)
+ set wildignorecase&
+ call delete('XTEST')
endfunc
func Test_cmdline_write_alternatefile()
@@ -1051,6 +1286,18 @@ func Test_cmdline_write_alternatefile()
bw!
endfunc
+func Test_cmdline_expand_cur_alt_file()
+ enew
+ file http://some.com/file.txt
+ call feedkeys(":e %\<Tab>\<C-B>\"\<CR>", 'xt')
+ call assert_equal('"e http://some.com/file.txt', @:)
+ edit another
+ call feedkeys(":e #\<Tab>\<C-B>\"\<CR>", 'xt')
+ call assert_equal('"e http://some.com/file.txt', @:)
+ bwipe
+ bwipe http://some.com/file.txt
+endfunc
+
" using a leading backslash here
set cpo+=C
@@ -1072,7 +1319,7 @@ func Test_cmdline_search_range()
call assert_equal('B', getline(2))
let @/ = 'apple'
- call assert_fails('\/print', 'E486:')
+ call assert_fails('\/print', ['E486:.*apple'])
bwipe!
endfunc
@@ -1082,7 +1329,7 @@ func Test_tick_mark_in_range()
" If only the tick is passed as a range and no command is specified, there
" should not be an error
call feedkeys(":'\<CR>", 'xt')
- call assert_equal("'", getreg(':'))
+ call assert_equal("'", @:)
call assert_fails("',print", 'E78:')
endfunc
@@ -1188,6 +1435,11 @@ func Test_verbosefile()
let log = readfile('Xlog')
call assert_match("foo\nbar", join(log, "\n"))
call delete('Xlog')
+ call mkdir('Xdir')
+ if !has('win32') " FIXME: no error on Windows, libuv bug?
+ call assert_fails('set verbosefile=Xdir', ['E484:.*Xdir', 'E474:'])
+ endif
+ call delete('Xdir', 'd')
endfunc
func Test_verbose_option()
@@ -1260,6 +1512,16 @@ func Test_cmdline_overstrike()
let &encoding = encoding_save
endfunc
+func Test_cmdwin_bug()
+ let winid = win_getid()
+ sp
+ try
+ call feedkeys("q::call win_gotoid(" .. winid .. ")\<CR>:q\<CR>", 'x!')
+ catch /^Vim\%((\a\+)\)\=:E11/
+ endtry
+ bw!
+endfunc
+
func Test_cmdwin_restore()
CheckScreendump
@@ -1414,6 +1676,7 @@ func Test_cmdline_expand_special()
call assert_fails('e <afile>', 'E495:')
call assert_fails('e <abuf>', 'E496:')
call assert_fails('e <amatch>', 'E497:')
+
call writefile([], 'Xfile.cpp')
call writefile([], 'Xfile.java')
new Xfile.cpp
@@ -1428,7 +1691,7 @@ func Test_cmdwin_jump_to_win()
call assert_fails('call feedkeys("q:\<C-W>\<C-W>\<CR>", "xt")', 'E11:')
new
set modified
- call assert_fails('call feedkeys("q/:qall\<CR>", "xt")', 'E162:')
+ call assert_fails('call feedkeys("q/:qall\<CR>", "xt")', ['E37:', 'E162:'])
close!
call feedkeys("q/:close\<CR>", "xt")
call assert_equal(1, winnr('$'))
@@ -1442,16 +1705,36 @@ endfunc
func Test_cmdwin_tabpage()
tabedit
- " v8.2.1919 isn't ported yet, so E492 is thrown after E11 here.
- " v8.2.1183 also isn't ported yet, so we also can't assert E11 directly.
- " For now, assert E11 and E492 separately. When v8.2.1183 is ported, the
- " assert for E492 will fail and this workaround should be removed.
- " call assert_fails("silent norm q/g :I\<Esc>", 'E11:')
- call assert_fails("silent norm q/g ", 'E11:')
- call assert_fails("silent norm q/g :I\<Esc>", 'E492:')
+ call assert_fails("silent norm q/g :I\<Esc>", 'E11:')
tabclose!
endfunc
+func Test_cmdwin_interrupted()
+ CheckScreendump
+
+ " aborting the :smile output caused the cmdline window to use the current
+ " buffer.
+ let lines =<< trim [SCRIPT]
+ au WinNew * smile
+ [SCRIPT]
+ call writefile(lines, 'XTest_cmdwin')
+
+ let buf = RunVimInTerminal('-S XTest_cmdwin', {'rows': 18})
+ " open cmdwin
+ call term_sendkeys(buf, "q:")
+ call WaitForAssert({-> assert_match('-- More --', term_getline(buf, 18))})
+ " quit more prompt for :smile command
+ call term_sendkeys(buf, "q")
+ call WaitForAssert({-> assert_match('^$', term_getline(buf, 18))})
+ " execute a simple command
+ call term_sendkeys(buf, "aecho 'done'\<CR>")
+ call VerifyScreenDump(buf, 'Test_cmdwin_interrupted', {})
+
+ " clean up
+ call StopVimInTerminal(buf)
+ call delete('XTest_cmdwin')
+endfunc
+
" Test for backtick expression in the command line
func Test_cmd_backtick()
CheckNotMSWindows " FIXME: see #19297
@@ -1508,6 +1791,53 @@ func Test_cmd_bang_E135()
%bwipe!
endfunc
+func Test_cmd_bang_args()
+ new
+ :.!
+ call assert_equal(0, v:shell_error)
+
+ " Note that below there is one space char after the '!'. This caused a
+ " shell error in the past, see https://github.com/vim/vim/issues/11495.
+ :.!
+ call assert_equal(0, v:shell_error)
+ bwipe!
+
+ CheckUnix
+ :.!pwd
+ call assert_equal(0, v:shell_error)
+ :.! pwd
+ call assert_equal(0, v:shell_error)
+
+ " Note there is one space after 'pwd'.
+ :.! pwd
+ call assert_equal(0, v:shell_error)
+
+ " Note there are two spaces after 'pwd'.
+ :.! pwd
+ call assert_equal(0, v:shell_error)
+ :.!ls ~
+ call assert_equal(0, v:shell_error)
+
+ " Note there is one space char after '~'.
+ :.!ls ~
+ call assert_equal(0, v:shell_error)
+
+ " Note there are two spaces after '~'.
+ :.!ls ~
+ call assert_equal(0, v:shell_error)
+
+ :.!echo "foo"
+ call assert_equal(getline('.'), "foo")
+ :.!echo "foo "
+ call assert_equal(getline('.'), "foo ")
+ :.!echo " foo "
+ call assert_equal(getline('.'), " foo ")
+ :.!echo " foo "
+ call assert_equal(getline('.'), " foo ")
+
+ %bwipe!
+endfunc
+
" Test for using ~ for home directory in cmdline completion matches
func Test_cmdline_expand_home()
call mkdir('Xdir')
@@ -1543,22 +1873,16 @@ func Test_cmdline_ctrl_g()
endfunc
" Test for 'wildmode'
-func Test_wildmode()
+func Wildmode_tests()
func T(a, c, p)
return "oneA\noneB\noneC"
endfunc
command -nargs=1 -complete=custom,T MyCmd
- func SaveScreenLine()
- let g:Sline = Screenline(&lines - 1)
- return ''
- endfunc
- cnoremap <expr> <F2> SaveScreenLine()
-
set nowildmenu
set wildmode=full,list
let g:Sline = ''
- call feedkeys(":MyCmd \t\t\<F2>\<C-B>\"\<CR>", 'xt')
+ call feedkeys(":MyCmd \t\t\<F4>\<C-B>\"\<CR>", 'xt')
call assert_equal('oneA oneB oneC', g:Sline)
call assert_equal('"MyCmd oneA', @:)
@@ -1574,7 +1898,7 @@ func Test_wildmode()
set wildmode=list:longest
let g:Sline = ''
- call feedkeys(":MyCmd \t\<F2>\<C-B>\"\<CR>", 'xt')
+ call feedkeys(":MyCmd \t\<F4>\<C-B>\"\<CR>", 'xt')
call assert_equal('oneA oneB oneC', g:Sline)
call assert_equal('"MyCmd one', @:)
@@ -1585,27 +1909,67 @@ func Test_wildmode()
" Test for wildmode=longest with 'fileignorecase' set
set wildmode=longest
set fileignorecase
- argadd AA AAA AAAA
- call feedkeys(":buffer \t\<C-B>\"\<CR>", 'xt')
- call assert_equal('"buffer AA', @:)
+ argadd AAA AAAA AAAAA
+ call feedkeys(":buffer a\t\<C-B>\"\<CR>", 'xt')
+ call assert_equal('"buffer AAA', @:)
set fileignorecase&
" Test for listing files with wildmode=list
set wildmode=list
let g:Sline = ''
- call feedkeys(":b A\t\t\<F2>\<C-B>\"\<CR>", 'xt')
- call assert_equal('AA AAA AAAA', g:Sline)
+ call feedkeys(":b A\t\t\<F4>\<C-B>\"\<CR>", 'xt')
+ call assert_equal('AAA AAAA AAAAA', g:Sline)
call assert_equal('"b A', @:)
+ " when using longest completion match, matches shorter than the argument
+ " should be ignored (happens with :help)
+ set wildmode=longest,full
+ set wildmenu
+ call feedkeys(":help a*\t\<C-B>\"\<CR>", 'xt')
+ call assert_equal('"help a', @:)
+ " non existing file
+ call feedkeys(":e a1b2y3z4\t\<C-B>\"\<CR>", 'xt')
+ call assert_equal('"e a1b2y3z4', @:)
+ set wildmenu&
+
+ " Test for longest file name completion with 'fileignorecase'
+ " On MS-Windows, file names are case insensitive.
+ if has('unix')
+ call writefile([], 'XTESTfoo')
+ call writefile([], 'Xtestbar')
+ set nofileignorecase
+ call feedkeys(":e XT\<Tab>\<C-B>\"\<CR>", 'xt')
+ call assert_equal('"e XTESTfoo', @:)
+ call feedkeys(":e Xt\<Tab>\<C-B>\"\<CR>", 'xt')
+ call assert_equal('"e Xtestbar', @:)
+ set fileignorecase
+ call feedkeys(":e XT\<Tab>\<C-B>\"\<CR>", 'xt')
+ call assert_equal('"e Xtest', @:)
+ call feedkeys(":e Xt\<Tab>\<C-B>\"\<CR>", 'xt')
+ call assert_equal('"e Xtest', @:)
+ set fileignorecase&
+ call delete('XTESTfoo')
+ call delete('Xtestbar')
+ endif
+
%argdelete
delcommand MyCmd
delfunc T
- delfunc SaveScreenLine
- cunmap <F2>
set wildmode&
%bwipe!
endfunc
+func Test_wildmode()
+ " Test with utf-8 encoding
+ call Wildmode_tests()
+
+ " Test with latin1 encoding
+ let save_encoding = &encoding
+ " set encoding=latin1
+ " call Wildmode_tests()
+ let &encoding = save_encoding
+endfunc
+
" Test for interrupting the command-line completion
func Test_interrupt_compl()
func F(lead, cmdl, p)
@@ -1627,6 +1991,14 @@ func Test_interrupt_compl()
endtry
call assert_equal(1, interrupted)
+ let interrupted = 0
+ try
+ call feedkeys(":Tcmd tw\<C-d>\<C-B>\"\<CR>", 'xt')
+ catch /^Vim:Interrupt$/
+ let interrupted = 1
+ endtry
+ call assert_equal(1, interrupted)
+
delcommand Tcmd
delfunc F
set wildmode&
@@ -1683,6 +2055,11 @@ func Test_cmdline_expr()
call assert_equal("\"e \<C-\>\<C-Y>", @:)
endfunc
+" This was making the insert position negative
+func Test_cmdline_expr_register()
+ exe "sil! norm! ?\<C-\>e0\<C-R>0\<Esc>?\<C-\>e0\<CR>"
+endfunc
+
" Test for 'imcmdline' and 'imsearch'
" This test doesn't actually test the input method functionality.
func Test_cmdline_inputmethod()
@@ -1809,8 +2186,45 @@ func Test_read_shellcmd()
endif
endfunc
+" Test for going up and down the directory tree using 'wildmenu'
+func Test_wildmenu_dirstack()
+ CheckUnix
+ %bw!
+ call mkdir('Xdir1/dir2/dir3/dir4', 'p')
+ call writefile([], 'Xdir1/file1_1.txt')
+ call writefile([], 'Xdir1/file1_2.txt')
+ call writefile([], 'Xdir1/dir2/file2_1.txt')
+ call writefile([], 'Xdir1/dir2/file2_2.txt')
+ call writefile([], 'Xdir1/dir2/dir3/file3_1.txt')
+ call writefile([], 'Xdir1/dir2/dir3/file3_2.txt')
+ call writefile([], 'Xdir1/dir2/dir3/dir4/file4_1.txt')
+ call writefile([], 'Xdir1/dir2/dir3/dir4/file4_2.txt')
+ set wildmenu
+
+ cd Xdir1/dir2/dir3/dir4
+ call feedkeys(":e \<Tab>\<C-B>\"\<CR>", 'xt')
+ call assert_equal('"e file4_1.txt', @:)
+ call feedkeys(":e \<Tab>\<Up>\<C-B>\"\<CR>", 'xt')
+ call assert_equal('"e ../dir4/', @:)
+ call feedkeys(":e \<Tab>\<Up>\<Up>\<C-B>\"\<CR>", 'xt')
+ call assert_equal('"e ../../dir3/', @:)
+ call feedkeys(":e \<Tab>\<Up>\<Up>\<Up>\<C-B>\"\<CR>", 'xt')
+ call assert_equal('"e ../../../dir2/', @:)
+ call feedkeys(":e \<Tab>\<Up>\<Up>\<Down>\<C-B>\"\<CR>", 'xt')
+ call assert_equal('"e ../../dir3/dir4/', @:)
+ call feedkeys(":e \<Tab>\<Up>\<Up>\<Down>\<Down>\<C-B>\"\<CR>", 'xt')
+ call assert_equal('"e ../../dir3/dir4/file4_1.txt', @:)
+ cd -
+ call feedkeys(":e Xdir1/\<Tab>\<Down>\<Down>\<Down>\<C-B>\"\<CR>", 'xt')
+ call assert_equal('"e Xdir1/dir2/dir3/dir4/file4_1.txt', @:)
+
+ call delete('Xdir1', 'rf')
+ set wildmenu&
+endfunc
+
" Test for recalling newer or older cmdline from history with <Up>, <Down>,
-" <S-Up>, <S-Down>, <PageUp>, <PageDown>, <C-p>, or <C-n>.
+" <S-Up>, <S-Down>, <PageUp>, <PageDown>, <kPageUp>, <kPageDown>, <C-p>, or
+" <C-n>.
func Test_recalling_cmdline()
CheckFeature cmdline_hist
@@ -1818,17 +2232,18 @@ func Test_recalling_cmdline()
cnoremap <Plug>(save-cmdline) <Cmd>let g:cmdlines += [getcmdline()]<CR>
let histories = [
- \ {'name': 'cmd', 'enter': ':', 'exit': "\<Esc>"},
- \ {'name': 'search', 'enter': '/', 'exit': "\<Esc>"},
- \ {'name': 'expr', 'enter': ":\<C-r>=", 'exit': "\<Esc>\<Esc>"},
- \ {'name': 'input', 'enter': ":call input('')\<CR>", 'exit': "\<CR>"},
+ \ #{name: 'cmd', enter: ':', exit: "\<Esc>"},
+ \ #{name: 'search', enter: '/', exit: "\<Esc>"},
+ \ #{name: 'expr', enter: ":\<C-r>=", exit: "\<Esc>\<Esc>"},
+ \ #{name: 'input', enter: ":call input('')\<CR>", exit: "\<CR>"},
"\ TODO: {'name': 'debug', ...}
\]
let keypairs = [
- \ {'older': "\<Up>", 'newer': "\<Down>", 'prefixmatch': v:true},
- \ {'older': "\<S-Up>", 'newer': "\<S-Down>", 'prefixmatch': v:false},
- \ {'older': "\<PageUp>", 'newer': "\<PageDown>", 'prefixmatch': v:false},
- \ {'older': "\<C-p>", 'newer': "\<C-n>", 'prefixmatch': v:false},
+ \ #{older: "\<Up>", newer: "\<Down>", prefixmatch: v:true},
+ \ #{older: "\<S-Up>", newer: "\<S-Down>", prefixmatch: v:false},
+ \ #{older: "\<PageUp>", newer: "\<PageDown>", prefixmatch: v:false},
+ \ #{older: "\<kPageUp>", newer: "\<kPageDown>", prefixmatch: v:false},
+ \ #{older: "\<C-p>", newer: "\<C-n>", prefixmatch: v:false},
\]
let prefix = 'vi'
for h in histories
@@ -1857,6 +2272,59 @@ func Test_recalling_cmdline()
cunmap <Plug>(save-cmdline)
endfunc
+func Test_cmd_map_cmdlineChanged()
+ let g:log = []
+ cnoremap <F1> l<Cmd><CR>s
+ augroup test
+ autocmd!
+ autocmd CmdlineChanged : let g:log += [getcmdline()]
+ augroup END
+
+ call feedkeys(":\<F1>\<CR>", 'xt')
+ call assert_equal(['l', 'ls'], g:log)
+
+ let @b = 'b'
+ cnoremap <F1> a<C-R>b
+ let g:log = []
+ call feedkeys(":\<F1>\<CR>", 'xt')
+ call assert_equal(['a', 'ab'], g:log)
+
+ unlet g:log
+ cunmap <F1>
+ augroup test
+ autocmd!
+ augroup END
+endfunc
+
+" Test for the 'suffixes' option
+func Test_suffixes_opt()
+ call writefile([], 'Xfile')
+ call writefile([], 'Xfile.c')
+ call writefile([], 'Xfile.o')
+ set suffixes=
+ call feedkeys(":e Xfi*\<C-A>\<C-B>\"\<CR>", 'xt')
+ call assert_equal('"e Xfile Xfile.c Xfile.o', @:)
+ call feedkeys(":e Xfi*\<Tab>\<Tab>\<C-B>\"\<CR>", 'xt')
+ call assert_equal('"e Xfile.c', @:)
+ set suffixes=.c
+ call feedkeys(":e Xfi*\<C-A>\<C-B>\"\<CR>", 'xt')
+ call assert_equal('"e Xfile Xfile.o Xfile.c', @:)
+ call feedkeys(":e Xfi*\<Tab>\<Tab>\<C-B>\"\<CR>", 'xt')
+ call assert_equal('"e Xfile.o', @:)
+ set suffixes=,,
+ call feedkeys(":e Xfi*\<C-A>\<C-B>\"\<CR>", 'xt')
+ call assert_equal('"e Xfile.c Xfile.o Xfile', @:)
+ call feedkeys(":e Xfi*\<Tab>\<Tab>\<C-B>\"\<CR>", 'xt')
+ call assert_equal('"e Xfile.o', @:)
+ set suffixes&
+ " Test for getcompletion() with different patterns
+ call assert_equal(['Xfile', 'Xfile.c', 'Xfile.o'], getcompletion('Xfile', 'file'))
+ call assert_equal(['Xfile'], getcompletion('Xfile$', 'file'))
+ call delete('Xfile')
+ call delete('Xfile.c')
+ call delete('Xfile.o')
+endfunc
+
" Test for using a popup menu for the command line completion matches
" (wildoptions=pum)
func Test_wildmenu_pum()
@@ -1868,39 +2336,63 @@ func Test_wildmenu_pum()
set shm+=I
set noruler
set noshowcmd
+
+ func CmdCompl(a, b, c)
+ return repeat(['aaaa'], 120)
+ endfunc
+ command -nargs=* -complete=customlist,CmdCompl Tcmd
+
+ func MyStatusLine() abort
+ return 'status'
+ endfunc
+ func SetupStatusline()
+ set statusline=%!MyStatusLine()
+ set laststatus=2
+ endfunc
+
+ func MyTabLine()
+ return 'my tab line'
+ endfunc
+ func SetupTabline()
+ set statusline=
+ set tabline=%!MyTabLine()
+ set showtabline=2
+ endfunc
+
+ func DoFeedKeys()
+ let &wildcharm = char2nr("\t")
+ call feedkeys(":edit $VIMRUNTIME/\<Tab>\<Left>\<C-U>ab\<Tab>")
+ endfunc
[CODE]
call writefile(commands, 'Xtest')
let buf = RunVimInTerminal('-S Xtest', #{rows: 10})
call term_sendkeys(buf, ":sign \<Tab>")
- call TermWait(buf)
call VerifyScreenDump(buf, 'Test_wildmenu_pum_01', {})
+ " going down the popup menu using <Down>
call term_sendkeys(buf, "\<Down>\<Down>")
- call TermWait(buf)
call VerifyScreenDump(buf, 'Test_wildmenu_pum_02', {})
+ " going down the popup menu using <C-N>
call term_sendkeys(buf, "\<C-N>")
- call TermWait(buf)
call VerifyScreenDump(buf, 'Test_wildmenu_pum_03', {})
+ " going up the popup menu using <C-P>
call term_sendkeys(buf, "\<C-P>")
- call TermWait(buf)
call VerifyScreenDump(buf, 'Test_wildmenu_pum_04', {})
+ " going up the popup menu using <Up>
call term_sendkeys(buf, "\<Up>")
- call TermWait(buf)
call VerifyScreenDump(buf, 'Test_wildmenu_pum_05', {})
" pressing <C-E> should end completion and go back to the original match
call term_sendkeys(buf, "\<C-E>")
- call TermWait(buf)
call VerifyScreenDump(buf, 'Test_wildmenu_pum_06', {})
" pressing <C-Y> should select the current match and end completion
call term_sendkeys(buf, "\<Tab>\<C-P>\<C-P>\<C-Y>")
- call TermWait(buf)
call VerifyScreenDump(buf, 'Test_wildmenu_pum_07', {})
" With 'wildmode' set to 'longest,full', completing a match should display
@@ -1908,31 +2400,25 @@ func Test_wildmenu_pum()
call term_sendkeys(buf, ":\<C-U>set wildmode=longest,full\<CR>")
call TermWait(buf)
call term_sendkeys(buf, ":sign u\<Tab>")
- call TermWait(buf)
call VerifyScreenDump(buf, 'Test_wildmenu_pum_08', {})
" pressing <Tab> should display the wildmenu
call term_sendkeys(buf, "\<Tab>")
- call TermWait(buf)
call VerifyScreenDump(buf, 'Test_wildmenu_pum_09', {})
" pressing <Tab> second time should select the next entry in the menu
call term_sendkeys(buf, "\<Tab>")
- call TermWait(buf)
call VerifyScreenDump(buf, 'Test_wildmenu_pum_10', {})
call term_sendkeys(buf, ":\<C-U>set wildmode=full\<CR>")
- " " showing popup menu in different columns in the cmdline
+ " showing popup menu in different columns in the cmdline
call term_sendkeys(buf, ":sign define \<Tab>")
- call TermWait(buf)
call VerifyScreenDump(buf, 'Test_wildmenu_pum_11', {})
call term_sendkeys(buf, " \<Tab>")
- call TermWait(buf)
call VerifyScreenDump(buf, 'Test_wildmenu_pum_12', {})
call term_sendkeys(buf, " \<Tab>")
- call TermWait(buf)
call VerifyScreenDump(buf, 'Test_wildmenu_pum_13', {})
" Directory name completion
@@ -1942,95 +2428,77 @@ func Test_wildmenu_pum()
call writefile([], 'Xdir/XdirA/XdirB/XfileC')
call term_sendkeys(buf, "\<C-U>e Xdi\<Tab>\<Tab>")
- call TermWait(buf)
call VerifyScreenDump(buf, 'Test_wildmenu_pum_14', {})
" Pressing <Right> on a directory name should go into that directory
call term_sendkeys(buf, "\<Right>")
- call TermWait(buf)
call VerifyScreenDump(buf, 'Test_wildmenu_pum_15', {})
" Pressing <Left> on a directory name should go to the parent directory
call term_sendkeys(buf, "\<Left>")
- call TermWait(buf)
call VerifyScreenDump(buf, 'Test_wildmenu_pum_16', {})
" Pressing <C-A> when the popup menu is displayed should list all the
- " matches and remove the popup menu
+ " matches but the popup menu should still remain
call term_sendkeys(buf, "\<C-U>sign \<Tab>\<C-A>")
- call TermWait(buf)
call VerifyScreenDump(buf, 'Test_wildmenu_pum_17', {})
" Pressing <C-D> when the popup menu is displayed should remove the popup
" menu
call term_sendkeys(buf, "\<C-U>sign \<Tab>\<C-D>")
- call TermWait(buf)
call VerifyScreenDump(buf, 'Test_wildmenu_pum_18', {})
" Pressing <S-Tab> should open the popup menu with the last entry selected
call term_sendkeys(buf, "\<C-U>\<CR>:sign \<S-Tab>\<C-P>")
- call TermWait(buf)
call VerifyScreenDump(buf, 'Test_wildmenu_pum_19', {})
" Pressing <Esc> should close the popup menu and cancel the cmd line
call term_sendkeys(buf, "\<C-U>\<CR>:sign \<Tab>\<Esc>")
- call TermWait(buf)
call VerifyScreenDump(buf, 'Test_wildmenu_pum_20', {})
" Typing a character when the popup is open, should close the popup
call term_sendkeys(buf, ":sign \<Tab>x")
- call TermWait(buf)
call VerifyScreenDump(buf, 'Test_wildmenu_pum_21', {})
" When the popup is open, entering the cmdline window should close the popup
call term_sendkeys(buf, "\<C-U>sign \<Tab>\<C-F>")
- call TermWait(buf)
call VerifyScreenDump(buf, 'Test_wildmenu_pum_22', {})
call term_sendkeys(buf, ":q\<CR>")
" After the last popup menu item, <C-N> should show the original string
call term_sendkeys(buf, ":sign u\<Tab>\<C-N>\<C-N>")
- call TermWait(buf)
call VerifyScreenDump(buf, 'Test_wildmenu_pum_23', {})
" Use the popup menu for the command name
call term_sendkeys(buf, "\<C-U>bu\<Tab>")
- call TermWait(buf)
call VerifyScreenDump(buf, 'Test_wildmenu_pum_24', {})
" Pressing the left arrow should remove the popup menu
call term_sendkeys(buf, "\<Left>\<Left>")
- call TermWait(buf)
call VerifyScreenDump(buf, 'Test_wildmenu_pum_25', {})
" Pressing <BS> should remove the popup menu and erase the last character
call term_sendkeys(buf, "\<C-E>\<C-U>sign \<Tab>\<BS>")
- call TermWait(buf)
call VerifyScreenDump(buf, 'Test_wildmenu_pum_26', {})
" Pressing <C-W> should remove the popup menu and erase the previous word
call term_sendkeys(buf, "\<C-E>\<C-U>sign \<Tab>\<C-W>")
- call TermWait(buf)
call VerifyScreenDump(buf, 'Test_wildmenu_pum_27', {})
" Pressing <C-U> should remove the popup menu and erase the entire line
call term_sendkeys(buf, "\<C-E>\<C-U>sign \<Tab>\<C-U>")
- call TermWait(buf)
call VerifyScreenDump(buf, 'Test_wildmenu_pum_28', {})
" Using <C-E> to cancel the popup menu and then pressing <Up> should recall
" the cmdline from history
call term_sendkeys(buf, "sign xyz\<Esc>:sign \<Tab>\<C-E>\<Up>")
- call TermWait(buf)
call VerifyScreenDump(buf, 'Test_wildmenu_pum_29', {})
" Check "list" still works
call term_sendkeys(buf, "\<C-U>set wildmode=longest,list\<CR>")
call term_sendkeys(buf, ":cn\<Tab>")
- call TermWait(buf)
call VerifyScreenDump(buf, 'Test_wildmenu_pum_30', {})
call term_sendkeys(buf, "s")
- call TermWait(buf)
call VerifyScreenDump(buf, 'Test_wildmenu_pum_31', {})
" Tests a directory name contained full-width characters.
@@ -2041,15 +2509,933 @@ func Test_wildmenu_pum()
call term_sendkeys(buf, "\<C-U>set wildmode&\<CR>")
call term_sendkeys(buf, ":\<C-U>e Xdir/あいう/\<Tab>")
- call TermWait(buf)
call VerifyScreenDump(buf, 'Test_wildmenu_pum_32', {})
+ " Pressing <C-A> when the popup menu is displayed should list all the
+ " matches and pressing a key after that should remove the popup menu
+ call term_sendkeys(buf, "\<C-U>set wildmode=full\<CR>")
+ call term_sendkeys(buf, ":sign \<Tab>\<C-A>x")
+ call VerifyScreenDump(buf, 'Test_wildmenu_pum_33', {})
+
+ " Pressing <C-A> when the popup menu is displayed should list all the
+ " matches and pressing <Left> after that should move the cursor
+ call term_sendkeys(buf, "\<C-U>abc\<Esc>")
+ call term_sendkeys(buf, ":sign \<Tab>\<C-A>\<Left>")
+ call VerifyScreenDump(buf, 'Test_wildmenu_pum_34', {})
+
+ " When <C-A> displays a lot of matches (screen scrolls), all the matches
+ " should be displayed correctly on the screen.
+ call term_sendkeys(buf, "\<End>\<C-U>Tcmd \<Tab>\<C-A>\<Left>\<Left>")
+ call VerifyScreenDump(buf, 'Test_wildmenu_pum_35', {})
+
+ " After using <C-A> to expand all the filename matches, pressing <Up>
+ " should not open the popup menu again.
+ call term_sendkeys(buf, "\<C-E>\<C-U>:cd Xdir/XdirA\<CR>")
+ call term_sendkeys(buf, ":e \<Tab>\<C-A>\<Up>")
+ call VerifyScreenDump(buf, 'Test_wildmenu_pum_36', {})
+ call term_sendkeys(buf, "\<C-E>\<C-U>:cd -\<CR>")
+
+ " After using <C-A> to expand all the matches, pressing <S-Tab> used to
+ " crash Vim
+ call term_sendkeys(buf, ":sign \<Tab>\<C-A>\<S-Tab>")
+ call VerifyScreenDump(buf, 'Test_wildmenu_pum_37', {})
+
+ " After removing the pum the command line is redrawn
+ call term_sendkeys(buf, ":edit foo\<CR>")
+ call term_sendkeys(buf, ":edit bar\<CR>")
+ call term_sendkeys(buf, ":ls\<CR>")
+ call term_sendkeys(buf, ":com\<Tab> ")
+ call VerifyScreenDump(buf, 'Test_wildmenu_pum_38', {})
+ call term_sendkeys(buf, "\<C-U>\<CR>")
+
+ " Esc still works to abort the command when 'statusline' is set
+ call term_sendkeys(buf, ":call SetupStatusline()\<CR>")
+ call term_sendkeys(buf, ":si\<Tab>")
+ call term_sendkeys(buf, "\<Esc>")
+ call VerifyScreenDump(buf, 'Test_wildmenu_pum_39', {})
+
+ " Esc still works to abort the command when 'tabline' is set
+ call term_sendkeys(buf, ":call SetupTabline()\<CR>")
+ call term_sendkeys(buf, ":si\<Tab>")
+ call term_sendkeys(buf, "\<Esc>")
+ call VerifyScreenDump(buf, 'Test_wildmenu_pum_40', {})
+
+ " popup is cleared also when 'lazyredraw' is set
+ call term_sendkeys(buf, ":set showtabline=1 laststatus=1 lazyredraw\<CR>")
+ call term_sendkeys(buf, ":call DoFeedKeys()\<CR>")
+ call VerifyScreenDump(buf, 'Test_wildmenu_pum_41', {})
+ call term_sendkeys(buf, "\<Esc>")
+
+ " Pressing <PageDown> should scroll the menu downward
+ call term_sendkeys(buf, ":sign \<Tab>\<PageDown>")
+ call VerifyScreenDump(buf, 'Test_wildmenu_pum_42', {})
+ call term_sendkeys(buf, "\<PageDown>")
+ call VerifyScreenDump(buf, 'Test_wildmenu_pum_43', {})
+ call term_sendkeys(buf, "\<PageDown>")
+ call VerifyScreenDump(buf, 'Test_wildmenu_pum_44', {})
+ call term_sendkeys(buf, "\<PageDown>")
+ call VerifyScreenDump(buf, 'Test_wildmenu_pum_45', {})
+ call term_sendkeys(buf, "\<C-U>sign \<Tab>\<Down>\<Down>\<PageDown>")
+ call VerifyScreenDump(buf, 'Test_wildmenu_pum_46', {})
+
+ " Pressing <PageUp> should scroll the menu upward
+ call term_sendkeys(buf, "\<C-U>sign \<Tab>\<PageUp>")
+ call VerifyScreenDump(buf, 'Test_wildmenu_pum_47', {})
+ call term_sendkeys(buf, "\<PageUp>")
+ call VerifyScreenDump(buf, 'Test_wildmenu_pum_48', {})
+ call term_sendkeys(buf, "\<PageUp>")
+ call VerifyScreenDump(buf, 'Test_wildmenu_pum_49', {})
+ call term_sendkeys(buf, "\<PageUp>")
+ call VerifyScreenDump(buf, 'Test_wildmenu_pum_50', {})
+
call term_sendkeys(buf, "\<C-U>\<CR>")
call StopVimInTerminal(buf)
call delete('Xtest')
call delete('Xdir', 'rf')
endfunc
+" Test for wildmenumode() with the cmdline popup menu
+func Test_wildmenumode_with_pum()
+ set wildmenu
+ set wildoptions=pum
+ cnoremap <expr> <F2> wildmenumode()
+ call feedkeys(":sign \<Tab>\<F2>\<F2>\<C-B>\"\<CR>", 'xt')
+ call assert_equal('"sign define10', @:)
+ call feedkeys(":sign \<Tab>\<C-A>\<F2>\<C-B>\"\<CR>", 'xt')
+ call assert_equal('"sign define jump list place undefine unplace0', @:)
+ call feedkeys(":sign \<Tab>\<C-E>\<F2>\<C-B>\"\<CR>", 'xt')
+ call assert_equal('"sign 0', @:)
+ call feedkeys(":sign \<Tab>\<C-Y>\<F2>\<C-B>\"\<CR>", 'xt')
+ call assert_equal('"sign define0', @:)
+ set nowildmenu wildoptions&
+ cunmap <F2>
+endfunc
+
+" Test for opening the cmdline completion popup menu from the terminal window.
+" The popup menu should be positioned correctly over the status line of the
+" bottom-most window.
+func Test_wildmenu_pum_from_terminal()
+ CheckRunVimInTerminal
+ let python = PythonProg()
+ call CheckPython(python)
+
+ %bw!
+ let cmds = ['set wildmenu wildoptions=pum']
+ let pcmd = python .. ' -c "import sys; sys.stdout.write(sys.stdin.read())"'
+ call add(cmds, "call term_start('" .. pcmd .. "')")
+ call writefile(cmds, 'Xtest')
+ let buf = RunVimInTerminal('-S Xtest', #{rows: 10})
+ call term_sendkeys(buf, "\r\r\r")
+ call term_wait(buf)
+ call term_sendkeys(buf, "\<C-W>:sign \<Tab>")
+ call term_wait(buf)
+ call VerifyScreenDump(buf, 'Test_wildmenu_pum_term_01', {})
+ call term_wait(buf)
+ call StopVimInTerminal(buf)
+ call delete('Xtest')
+endfunc
+
+func Test_wildmenu_pum_clear_entries()
+ CheckRunVimInTerminal
+
+ " This was using freed memory. Run in a terminal to get the pum to update.
+ let lines =<< trim END
+ set wildoptions=pum
+ set wildchar=<C-E>
+ END
+ call writefile(lines, 'XwildmenuTest', 'D')
+ let buf = RunVimInTerminal('-S XwildmenuTest', #{rows: 10})
+
+ call term_sendkeys(buf, ":\<C-E>\<C-E>")
+ call VerifyScreenDump(buf, 'Test_wildmenu_pum_clear_entries_1', {})
+
+ set wildoptions& wildchar&
+endfunc
+
+" Test for completion after a :substitute command followed by a pipe (|)
+" character
+func Test_cmdline_complete_substitute()
+ call feedkeys(":s | \t\<C-B>\"\<CR>", 'xt')
+ call assert_equal("\"s | \t", @:)
+ call feedkeys(":s/ | \t\<C-B>\"\<CR>", 'xt')
+ call assert_equal("\"s/ | \t", @:)
+ call feedkeys(":s/one | \t\<C-B>\"\<CR>", 'xt')
+ call assert_equal("\"s/one | \t", @:)
+ call feedkeys(":s/one/ | \t\<C-B>\"\<CR>", 'xt')
+ call assert_equal("\"s/one/ | \t", @:)
+ call feedkeys(":s/one/two | \t\<C-B>\"\<CR>", 'xt')
+ call assert_equal("\"s/one/two | \t", @:)
+ call feedkeys(":s/one/two/ | chist\t\<C-B>\"\<CR>", 'xt')
+ call assert_equal('"s/one/two/ | chistory', @:)
+ call feedkeys(":s/one/two/g \t\<C-B>\"\<CR>", 'xt')
+ call assert_equal("\"s/one/two/g \t", @:)
+ call feedkeys(":s/one/two/g | chist\t\<C-B>\"\<CR>", 'xt')
+ call assert_equal("\"s/one/two/g | chistory", @:)
+ call feedkeys(":s/one/t\\/ | \t\<C-B>\"\<CR>", 'xt')
+ call assert_equal("\"s/one/t\\/ | \t", @:)
+ call feedkeys(":s/one/t\"o/ | chist\t\<C-B>\"\<CR>", 'xt')
+ call assert_equal('"s/one/t"o/ | chistory', @:)
+ call feedkeys(":s/one/t|o/ | chist\t\<C-B>\"\<CR>", 'xt')
+ call assert_equal('"s/one/t|o/ | chistory', @:)
+ call feedkeys(":&\t\<C-B>\"\<CR>", 'xt')
+ call assert_equal("\"&\t", @:)
+endfunc
+
+" Test for the :dlist command completion
+func Test_cmdline_complete_dlist()
+ call feedkeys(":dlist 10 /pat/ a\<C-A>\<C-B>\"\<CR>", 'xt')
+ call assert_equal("\"dlist 10 /pat/ a\<C-A>", @:)
+ call feedkeys(":dlist 10 /pat/ \t\<C-B>\"\<CR>", 'xt')
+ call assert_equal("\"dlist 10 /pat/ \t", @:)
+ call feedkeys(":dlist 10 /pa\\t/\t\<C-B>\"\<CR>", 'xt')
+ call assert_equal("\"dlist 10 /pa\\t/\t", @:)
+ call feedkeys(":dlist 10 /pat\\\t\<C-B>\"\<CR>", 'xt')
+ call assert_equal("\"dlist 10 /pat\\\t", @:)
+ call feedkeys(":dlist 10 /pat/ | chist\<Tab>\<C-B>\"\<CR>", 'xt')
+ call assert_equal("\"dlist 10 /pat/ | chistory", @:)
+endfunc
+
+" argument list (only for :argdel) fuzzy completion
+func Test_fuzzy_completion_arglist()
+ argadd change.py count.py charge.py
+ set wildoptions&
+ call feedkeys(":argdel cge\<C-A>\<C-B>\"\<CR>", 'tx')
+ call assert_equal('"argdel cge', @:)
+ set wildoptions=fuzzy
+ call feedkeys(":argdel cge\<C-A>\<C-B>\"\<CR>", 'tx')
+ call assert_equal('"argdel change.py charge.py', @:)
+ %argdelete
+ set wildoptions&
+endfunc
+
+" autocmd group name fuzzy completion
+func Test_fuzzy_completion_autocmd()
+ set wildoptions&
+ augroup MyFuzzyGroup
+ augroup END
+ call feedkeys(":augroup mfg\<Tab>\<C-B>\"\<CR>", 'tx')
+ call assert_equal('"augroup mfg', @:)
+ call feedkeys(":augroup My*p\<Tab>\<C-B>\"\<CR>", 'tx')
+ call assert_equal('"augroup MyFuzzyGroup', @:)
+ set wildoptions=fuzzy
+ call feedkeys(":augroup mfg\<Tab>\<C-B>\"\<CR>", 'tx')
+ call assert_equal('"augroup MyFuzzyGroup', @:)
+ call feedkeys(":augroup My*p\<Tab>\<C-B>\"\<CR>", 'tx')
+ call assert_equal('"augroup My*p', @:)
+ augroup! MyFuzzyGroup
+ set wildoptions&
+endfunc
+
+" buffer name fuzzy completion
+func Test_fuzzy_completion_bufname()
+ set wildoptions&
+ " Use a long name to reduce the risk of matching a random directory name
+ edit SomeRandomFileWithLetters.txt
+ enew
+ call feedkeys(":b SRFWL\<Tab>\<C-B>\"\<CR>", 'tx')
+ call assert_equal('"b SRFWL', @:)
+ call feedkeys(":b S*FileWithLetters.txt\<Tab>\<C-B>\"\<CR>", 'tx')
+ call assert_equal('"b SomeRandomFileWithLetters.txt', @:)
+ set wildoptions=fuzzy
+ call feedkeys(":b SRFWL\<Tab>\<C-B>\"\<CR>", 'tx')
+ call assert_equal('"b SomeRandomFileWithLetters.txt', @:)
+ call feedkeys(":b S*FileWithLetters.txt\<Tab>\<C-B>\"\<CR>", 'tx')
+ call assert_equal('"b S*FileWithLetters.txt', @:)
+ %bw!
+ set wildoptions&
+endfunc
+
+" buffer name (full path) fuzzy completion
+func Test_fuzzy_completion_bufname_fullpath()
+ CheckUnix
+ set wildoptions&
+ call mkdir('Xcmd/Xstate/Xfile.js', 'p')
+ edit Xcmd/Xstate/Xfile.js
+ cd Xcmd/Xstate
+ enew
+ call feedkeys(":b CmdStateFile\<Tab>\<C-B>\"\<CR>", 'tx')
+ call assert_equal('"b CmdStateFile', @:)
+ set wildoptions=fuzzy
+ call feedkeys(":b CmdStateFile\<Tab>\<C-B>\"\<CR>", 'tx')
+ call assert_match('Xcmd/Xstate/Xfile.js$', @:)
+ cd -
+ call delete('Xcmd', 'rf')
+ set wildoptions&
+endfunc
+
+" :behave suboptions fuzzy completion
+func Test_fuzzy_completion_behave()
+ set wildoptions&
+ call feedkeys(":behave xm\<Tab>\<C-B>\"\<CR>", 'tx')
+ call assert_equal('"behave xm', @:)
+ call feedkeys(":behave xt*m\<Tab>\<C-B>\"\<CR>", 'tx')
+ call assert_equal('"behave xterm', @:)
+ set wildoptions=fuzzy
+ call feedkeys(":behave xm\<Tab>\<C-B>\"\<CR>", 'tx')
+ call assert_equal('"behave xterm', @:)
+ call feedkeys(":behave xt*m\<Tab>\<C-B>\"\<CR>", 'tx')
+ call assert_equal('"behave xt*m', @:)
+ let g:Sline = ''
+ call feedkeys(":behave win\<C-D>\<F4>\<C-B>\"\<CR>", 'tx')
+ call assert_equal('mswin', g:Sline)
+ call assert_equal('"behave win', @:)
+ set wildoptions&
+endfunc
+
+" " colorscheme name fuzzy completion - NOT supported
+" func Test_fuzzy_completion_colorscheme()
+" endfunc
+
+" built-in command name fuzzy completion
+func Test_fuzzy_completion_cmdname()
+ set wildoptions&
+ call feedkeys(":sbwin\<Tab>\<C-B>\"\<CR>", 'tx')
+ call assert_equal('"sbwin', @:)
+ call feedkeys(":sbr*d\<Tab>\<C-B>\"\<CR>", 'tx')
+ call assert_equal('"sbrewind', @:)
+ set wildoptions=fuzzy
+ call feedkeys(":sbwin\<Tab>\<C-B>\"\<CR>", 'tx')
+ call assert_equal('"sbrewind', @:)
+ call feedkeys(":sbr*d\<Tab>\<C-B>\"\<CR>", 'tx')
+ call assert_equal('"sbr*d', @:)
+ set wildoptions&
+endfunc
+
+" " compiler name fuzzy completion - NOT supported
+" func Test_fuzzy_completion_compiler()
+" endfunc
+
+" :cscope suboptions fuzzy completion
+func Test_fuzzy_completion_cscope()
+ CheckFeature cscope
+ set wildoptions&
+ call feedkeys(":cscope ret\<Tab>\<C-B>\"\<CR>", 'tx')
+ call assert_equal('"cscope ret', @:)
+ call feedkeys(":cscope re*t\<Tab>\<C-B>\"\<CR>", 'tx')
+ call assert_equal('"cscope reset', @:)
+ set wildoptions=fuzzy
+ call feedkeys(":cscope ret\<Tab>\<C-B>\"\<CR>", 'tx')
+ call assert_equal('"cscope reset', @:)
+ call feedkeys(":cscope re*t\<Tab>\<C-B>\"\<CR>", 'tx')
+ call assert_equal('"cscope re*t', @:)
+ set wildoptions&
+endfunc
+
+" :diffget/:diffput buffer name fuzzy completion
+func Test_fuzzy_completion_diff()
+ new SomeBuffer
+ diffthis
+ new OtherBuffer
+ diffthis
+ set wildoptions&
+ call feedkeys(":diffget sbuf\<Tab>\<C-B>\"\<CR>", 'tx')
+ call assert_equal('"diffget sbuf', @:)
+ call feedkeys(":diffput sbuf\<Tab>\<C-B>\"\<CR>", 'tx')
+ call assert_equal('"diffput sbuf', @:)
+ set wildoptions=fuzzy
+ call feedkeys(":diffget sbuf\<Tab>\<C-B>\"\<CR>", 'tx')
+ call assert_equal('"diffget SomeBuffer', @:)
+ call feedkeys(":diffput sbuf\<Tab>\<C-B>\"\<CR>", 'tx')
+ call assert_equal('"diffput SomeBuffer', @:)
+ %bw!
+ set wildoptions&
+endfunc
+
+" " directory name fuzzy completion - NOT supported
+" func Test_fuzzy_completion_dirname()
+" endfunc
+
+" environment variable name fuzzy completion
+func Test_fuzzy_completion_env()
+ set wildoptions&
+ call feedkeys(":echo $VUT\<Tab>\<C-B>\"\<CR>", 'tx')
+ call assert_equal('"echo $VUT', @:)
+ set wildoptions=fuzzy
+ call feedkeys(":echo $VUT\<Tab>\<C-B>\"\<CR>", 'tx')
+ call assert_equal('"echo $VIMRUNTIME', @:)
+ set wildoptions&
+endfunc
+
+" autocmd event fuzzy completion
+func Test_fuzzy_completion_autocmd_event()
+ set wildoptions&
+ call feedkeys(":autocmd BWout\<Tab>\<C-B>\"\<CR>", 'tx')
+ call assert_equal('"autocmd BWout', @:)
+ set wildoptions=fuzzy
+ call feedkeys(":autocmd BWout\<Tab>\<C-B>\"\<CR>", 'tx')
+ call assert_equal('"autocmd BufWipeout', @:)
+ set wildoptions&
+endfunc
+
+" vim expression fuzzy completion
+func Test_fuzzy_completion_expr()
+ let g:PerPlaceCount = 10
+ set wildoptions&
+ call feedkeys(":let c = ppc\<Tab>\<C-B>\"\<CR>", 'tx')
+ call assert_equal('"let c = ppc', @:)
+ set wildoptions=fuzzy
+ call feedkeys(":let c = ppc\<Tab>\<C-B>\"\<CR>", 'tx')
+ call assert_equal('"let c = PerPlaceCount', @:)
+ set wildoptions&
+endfunc
+
+" " file name fuzzy completion - NOT supported
+" func Test_fuzzy_completion_filename()
+" endfunc
+
+" " files in path fuzzy completion - NOT supported
+" func Test_fuzzy_completion_filesinpath()
+" endfunc
+
+" " filetype name fuzzy completion - NOT supported
+" func Test_fuzzy_completion_filetype()
+" endfunc
+
+" user defined function name completion
+func Test_fuzzy_completion_userdefined_func()
+ set wildoptions&
+ call feedkeys(":call Test_f_u_f\<Tab>\<C-B>\"\<CR>", 'tx')
+ call assert_equal('"call Test_f_u_f', @:)
+ set wildoptions=fuzzy
+ call feedkeys(":call Test_f_u_f\<Tab>\<C-B>\"\<CR>", 'tx')
+ call assert_equal('"call Test_fuzzy_completion_userdefined_func()', @:)
+ set wildoptions&
+endfunc
+
+" <SNR> functions should be sorted to the end
+func Test_fuzzy_completion_userdefined_snr_func()
+ func s:Sendmail()
+ endfunc
+ func SendSomemail()
+ endfunc
+ func S1e2n3dmail()
+ endfunc
+ set wildoptions=fuzzy
+ call feedkeys(":call sendmail\<C-A>\<C-B>\"\<CR>", 'tx')
+ call assert_equal('"call SendSomemail() S1e2n3dmail() '
+ \ .. expand("<SID>") .. 'Sendmail()', @:)
+ set wildoptions&
+ delfunc s:Sendmail
+ delfunc SendSomemail
+ delfunc S1e2n3dmail
+endfunc
+
+" user defined command name completion
+func Test_fuzzy_completion_userdefined_cmd()
+ set wildoptions&
+ call feedkeys(":MsFeat\<Tab>\<C-B>\"\<CR>", 'tx')
+ call assert_equal('"MsFeat', @:)
+ set wildoptions=fuzzy
+ call feedkeys(":MsFeat\<Tab>\<C-B>\"\<CR>", 'tx')
+ call assert_equal('"MissingFeature', @:)
+ set wildoptions&
+endfunc
+
+" " :help tag fuzzy completion - NOT supported
+" func Test_fuzzy_completion_helptag()
+" endfunc
+
+" highlight group name fuzzy completion
+func Test_fuzzy_completion_hlgroup()
+ set wildoptions&
+ call feedkeys(":highlight SKey\<Tab>\<C-B>\"\<CR>", 'tx')
+ call assert_equal('"highlight SKey', @:)
+ call feedkeys(":highlight Sp*Key\<Tab>\<C-B>\"\<CR>", 'tx')
+ call assert_equal('"highlight SpecialKey', @:)
+ set wildoptions=fuzzy
+ call feedkeys(":highlight SKey\<Tab>\<C-B>\"\<CR>", 'tx')
+ call assert_equal('"highlight SpecialKey', @:)
+ call feedkeys(":highlight Sp*Key\<Tab>\<C-B>\"\<CR>", 'tx')
+ call assert_equal('"highlight Sp*Key', @:)
+ set wildoptions&
+endfunc
+
+" :history suboptions fuzzy completion
+func Test_fuzzy_completion_history()
+ set wildoptions&
+ call feedkeys(":history dg\<Tab>\<C-B>\"\<CR>", 'tx')
+ call assert_equal('"history dg', @:)
+ call feedkeys(":history se*h\<Tab>\<C-B>\"\<CR>", 'tx')
+ call assert_equal('"history search', @:)
+ set wildoptions=fuzzy
+ call feedkeys(":history dg\<Tab>\<C-B>\"\<CR>", 'tx')
+ call assert_equal('"history debug', @:)
+ call feedkeys(":history se*h\<Tab>\<C-B>\"\<CR>", 'tx')
+ call assert_equal('"history se*h', @:)
+ set wildoptions&
+endfunc
+
+" :language locale name fuzzy completion
+func Test_fuzzy_completion_lang()
+ CheckUnix
+ set wildoptions&
+ call feedkeys(":lang psx\<Tab>\<C-B>\"\<CR>", 'tx')
+ call assert_equal('"lang psx', @:)
+ set wildoptions=fuzzy
+ call feedkeys(":lang psx\<Tab>\<C-B>\"\<CR>", 'tx')
+ call assert_equal('"lang POSIX', @:)
+ set wildoptions&
+endfunc
+
+" :mapclear buffer argument fuzzy completion
+func Test_fuzzy_completion_mapclear()
+ set wildoptions&
+ call feedkeys(":mapclear buf\<Tab>\<C-B>\"\<CR>", 'tx')
+ call assert_equal('"mapclear buf', @:)
+ set wildoptions=fuzzy
+ call feedkeys(":mapclear buf\<Tab>\<C-B>\"\<CR>", 'tx')
+ call assert_equal('"mapclear <buffer>', @:)
+ set wildoptions&
+endfunc
+
+" map name fuzzy completion
+func Test_fuzzy_completion_mapname()
+ " test regex completion works
+ set wildoptions=fuzzy
+ call feedkeys(":cnoremap <ex\<Tab> <esc> \<Tab>\<C-B>\"\<CR>", 'tx')
+ call assert_equal("\"cnoremap <expr> <esc> \<Tab>", @:)
+ nmap <plug>MyLongMap :p<CR>
+ call feedkeys(":nmap MLM\<Tab>\<C-B>\"\<CR>", 'tx')
+ call assert_equal("\"nmap <Plug>MyLongMap", @:)
+ call feedkeys(":nmap MLM \<Tab>\<C-B>\"\<CR>", 'tx')
+ call assert_equal("\"nmap MLM \t", @:)
+ call feedkeys(":nmap <F2> one two \<Tab>\<C-B>\"\<CR>", 'tx')
+ call assert_equal("\"nmap <F2> one two \t", @:)
+ " duplicate entries should be removed
+ vmap <plug>MyLongMap :<C-U>#<CR>
+ call feedkeys(":nmap MLM\<Tab>\<C-B>\"\<CR>", 'tx')
+ call assert_equal("\"nmap <Plug>MyLongMap", @:)
+ nunmap <plug>MyLongMap
+ vunmap <plug>MyLongMap
+ call feedkeys(":nmap ABC\<Tab>\<C-B>\"\<CR>", 'tx')
+ call assert_equal("\"nmap ABC\t", @:)
+ " results should be sorted by best match
+ nmap <Plug>format :
+ nmap <Plug>goformat :
+ nmap <Plug>TestFOrmat :
+ nmap <Plug>fendoff :
+ nmap <Plug>state :
+ nmap <Plug>FendingOff :
+ call feedkeys(":nmap <Plug>fo\<C-A>\<C-B>\"\<CR>", 'tx')
+ call assert_equal("\"nmap <Plug>format <Plug>TestFOrmat <Plug>FendingOff <Plug>goformat <Plug>fendoff", @:)
+ nunmap <Plug>format
+ nunmap <Plug>goformat
+ nunmap <Plug>TestFOrmat
+ nunmap <Plug>fendoff
+ nunmap <Plug>state
+ nunmap <Plug>FendingOff
+ set wildoptions&
+endfunc
+
+" abbreviation fuzzy completion
+func Test_fuzzy_completion_abbr()
+ set wildoptions=fuzzy
+ call feedkeys(":iabbr wait\<Tab>\<C-B>\"\<CR>", 'tx')
+ call assert_equal("\"iabbr <nowait>", @:)
+ iabbr WaitForCompletion WFC
+ call feedkeys(":iabbr fcl\<Tab>\<C-B>\"\<CR>", 'tx')
+ call assert_equal("\"iabbr WaitForCompletion", @:)
+ call feedkeys(":iabbr a1z\<Tab>\<C-B>\"\<CR>", 'tx')
+ call assert_equal("\"iabbr a1z\t", @:)
+
+ iunabbrev WaitForCompletion
+ set wildoptions&
+endfunc
+
+" menu name fuzzy completion
+func Test_fuzzy_completion_menu()
+ CheckFeature menu
+
+ source $VIMRUNTIME/menu.vim
+ set wildoptions&
+ call feedkeys(":menu pup\<Tab>\<C-B>\"\<CR>", 'tx')
+ call assert_equal('"menu pup', @:)
+ set wildoptions=fuzzy
+ call feedkeys(":menu pup\<Tab>\<C-B>\"\<CR>", 'tx')
+ call assert_equal('"menu PopUp.', @:)
+
+ set wildoptions&
+ source $VIMRUNTIME/delmenu.vim
+endfunc
+
+" :messages suboptions fuzzy completion
+func Test_fuzzy_completion_messages()
+ set wildoptions&
+ call feedkeys(":messages clr\<Tab>\<C-B>\"\<CR>", 'tx')
+ call assert_equal('"messages clr', @:)
+ set wildoptions=fuzzy
+ call feedkeys(":messages clr\<Tab>\<C-B>\"\<CR>", 'tx')
+ call assert_equal('"messages clear', @:)
+ set wildoptions&
+endfunc
+
+" :set option name fuzzy completion
+func Test_fuzzy_completion_option()
+ set wildoptions&
+ call feedkeys(":set brkopt\<Tab>\<C-B>\"\<CR>", 'tx')
+ call assert_equal('"set brkopt', @:)
+ set wildoptions=fuzzy
+ call feedkeys(":set brkopt\<Tab>\<C-B>\"\<CR>", 'tx')
+ call assert_equal('"set breakindentopt', @:)
+ set wildoptions&
+ call feedkeys(":set fixeol\<Tab>\<C-B>\"\<CR>", 'tx')
+ call assert_equal('"set fixendofline', @:)
+ set wildoptions=fuzzy
+ call feedkeys(":set fixeol\<Tab>\<C-B>\"\<CR>", 'tx')
+ call assert_equal('"set fixendofline', @:)
+ set wildoptions&
+endfunc
+
+" :set <term_option>
+func Test_fuzzy_completion_term_option()
+ throw 'Skipped: Nvim does not support term options'
+ set wildoptions&
+ call feedkeys(":set t_E\<Tab>\<C-B>\"\<CR>", 'tx')
+ call assert_equal('"set t_EC', @:)
+ call feedkeys(":set <t_E\<Tab>\<C-B>\"\<CR>", 'tx')
+ call assert_equal('"set <t_EC>', @:)
+ set wildoptions=fuzzy
+ call feedkeys(":set t_E\<Tab>\<C-B>\"\<CR>", 'tx')
+ call assert_equal('"set t_EC', @:)
+ call feedkeys(":set <t_E\<Tab>\<C-B>\"\<CR>", 'tx')
+ call assert_equal('"set <t_EC>', @:)
+ set wildoptions&
+endfunc
+
+" " :packadd directory name fuzzy completion - NOT supported
+" func Test_fuzzy_completion_packadd()
+" endfunc
+
+" " shell command name fuzzy completion - NOT supported
+" func Test_fuzzy_completion_shellcmd()
+" endfunc
+
+" :sign suboptions fuzzy completion
+func Test_fuzzy_completion_sign()
+ set wildoptions&
+ call feedkeys(":sign ufe\<Tab>\<C-B>\"\<CR>", 'tx')
+ call assert_equal('"sign ufe', @:)
+ set wildoptions=fuzzy
+ call feedkeys(":sign ufe\<Tab>\<C-B>\"\<CR>", 'tx')
+ call assert_equal('"sign undefine', @:)
+ set wildoptions&
+endfunc
+
+" :syntax suboptions fuzzy completion
+func Test_fuzzy_completion_syntax_cmd()
+ set wildoptions&
+ call feedkeys(":syntax kwd\<Tab>\<C-B>\"\<CR>", 'tx')
+ call assert_equal('"syntax kwd', @:)
+ set wildoptions=fuzzy
+ call feedkeys(":syntax kwd\<Tab>\<C-B>\"\<CR>", 'tx')
+ call assert_equal('"syntax keyword', @:)
+ set wildoptions&
+endfunc
+
+" syntax group name fuzzy completion
+func Test_fuzzy_completion_syntax_group()
+ set wildoptions&
+ call feedkeys(":syntax list mpar\<Tab>\<C-B>\"\<CR>", 'tx')
+ call assert_equal('"syntax list mpar', @:)
+ set wildoptions=fuzzy
+ call feedkeys(":syntax list mpar\<Tab>\<C-B>\"\<CR>", 'tx')
+ " Fuzzy match prefers NvimParenthesis over MatchParen
+ " call assert_equal('"syntax list MatchParen', @:)
+ call assert_equal('"syntax list NvimParenthesis', @:)
+ set wildoptions&
+endfunc
+
+" :syntime suboptions fuzzy completion
+func Test_fuzzy_completion_syntime()
+ CheckFeature profile
+ set wildoptions&
+ call feedkeys(":syntime clr\<Tab>\<C-B>\"\<CR>", 'tx')
+ call assert_equal('"syntime clr', @:)
+ set wildoptions=fuzzy
+ call feedkeys(":syntime clr\<Tab>\<C-B>\"\<CR>", 'tx')
+ call assert_equal('"syntime clear', @:)
+ set wildoptions&
+endfunc
+
+" " tag name fuzzy completion - NOT supported
+" func Test_fuzzy_completion_tagname()
+" endfunc
+
+" " tag name and file fuzzy completion - NOT supported
+" func Test_fuzzy_completion_tagfile()
+" endfunc
+
+" " user names fuzzy completion - how to test this functionality?
+" func Test_fuzzy_completion_username()
+" endfunc
+
+" user defined variable name fuzzy completion
+func Test_fuzzy_completion_userdefined_var()
+ let g:SomeVariable=10
+ set wildoptions&
+ call feedkeys(":let SVar\<Tab>\<C-B>\"\<CR>", 'tx')
+ call assert_equal('"let SVar', @:)
+ set wildoptions=fuzzy
+ call feedkeys(":let SVar\<Tab>\<C-B>\"\<CR>", 'tx')
+ call assert_equal('"let SomeVariable', @:)
+ set wildoptions&
+endfunc
+
+" Test for sorting the results by the best match
+func Test_fuzzy_completion_cmd_sort_results()
+ %bw!
+ command T123format :
+ command T123goformat :
+ command T123TestFOrmat :
+ command T123fendoff :
+ command T123state :
+ command T123FendingOff :
+ set wildoptions=fuzzy
+ call feedkeys(":T123fo\<C-A>\<C-B>\"\<CR>", 'tx')
+ call assert_equal('"T123format T123TestFOrmat T123FendingOff T123goformat T123fendoff', @:)
+ delcommand T123format
+ delcommand T123goformat
+ delcommand T123TestFOrmat
+ delcommand T123fendoff
+ delcommand T123state
+ delcommand T123FendingOff
+ %bw
+ set wildoptions&
+endfunc
+
+" Test for fuzzy completion of a command with lower case letters and a number
+func Test_fuzzy_completion_cmd_alnum()
+ command Foo2Bar :
+ set wildoptions=fuzzy
+ call feedkeys(":foo2\<Tab>\<C-B>\"\<CR>", 'tx')
+ call assert_equal('"Foo2Bar', @:)
+ call feedkeys(":foo\<Tab>\<C-B>\"\<CR>", 'tx')
+ call assert_equal('"Foo2Bar', @:)
+ call feedkeys(":bar\<Tab>\<C-B>\"\<CR>", 'tx')
+ call assert_equal('"Foo2Bar', @:)
+ delcommand Foo2Bar
+ set wildoptions&
+endfunc
+
+" Test for command completion for a command starting with 'k'
+func Test_fuzzy_completion_cmd_k()
+ command KillKillKill :
+ set wildoptions&
+ call feedkeys(":killkill\<Tab>\<C-B>\"\<CR>", 'tx')
+ call assert_equal("\"killkill\<Tab>", @:)
+ set wildoptions=fuzzy
+ call feedkeys(":killkill\<Tab>\<C-B>\"\<CR>", 'tx')
+ call assert_equal('"KillKillKill', @:)
+ delcom KillKillKill
+ set wildoptions&
+endfunc
+
+" Test for fuzzy completion for user defined custom completion function
+func Test_fuzzy_completion_custom_func()
+ func Tcompl(a, c, p)
+ return "format\ngoformat\nTestFOrmat\nfendoff\nstate"
+ endfunc
+ command -nargs=* -complete=custom,Tcompl Fuzzy :
+ set wildoptions&
+ call feedkeys(":Fuzzy fo\<C-A>\<C-B>\"\<CR>", 'tx')
+ call assert_equal("\"Fuzzy format", @:)
+ call feedkeys(":Fuzzy xy\<Tab>\<C-B>\"\<CR>", 'tx')
+ call assert_equal("\"Fuzzy xy", @:)
+ call feedkeys(":Fuzzy ttt\<C-A>\<C-B>\"\<CR>", 'tx')
+ call assert_equal("\"Fuzzy ttt", @:)
+ set wildoptions=fuzzy
+ call feedkeys(":Fuzzy \<C-A>\<C-B>\"\<CR>", 'tx')
+ call assert_equal("\"Fuzzy format goformat TestFOrmat fendoff state", @:)
+ call feedkeys(":Fuzzy fo\<C-A>\<C-B>\"\<CR>", 'tx')
+ call assert_equal("\"Fuzzy format TestFOrmat goformat fendoff", @:)
+ call feedkeys(":Fuzzy xy\<Tab>\<C-B>\"\<CR>", 'tx')
+ call assert_equal("\"Fuzzy xy", @:)
+ call feedkeys(":Fuzzy ttt\<C-A>\<C-B>\"\<CR>", 'tx')
+ call assert_equal("\"Fuzzy TestFOrmat", @:)
+ delcom Fuzzy
+ set wildoptions&
+endfunc
+
+" Test for :breakadd argument completion
+func Test_cmdline_complete_breakadd()
+ call feedkeys(":breakadd \<C-A>\<C-B>\"\<CR>", 'tx')
+ call assert_equal("\"breakadd expr file func here", @:)
+ call feedkeys(":breakadd \<Tab>\<C-B>\"\<CR>", 'tx')
+ call assert_equal("\"breakadd expr", @:)
+ call feedkeys(":breakadd \<Tab>\<C-B>\"\<CR>", 'tx')
+ call assert_equal("\"breakadd expr", @:)
+ call feedkeys(":breakadd he\<Tab>\<C-B>\"\<CR>", 'tx')
+ call assert_equal("\"breakadd here", @:)
+ call feedkeys(":breakadd he\<Tab>\<C-B>\"\<CR>", 'tx')
+ call assert_equal("\"breakadd here", @:)
+ call feedkeys(":breakadd abc\<Tab>\<C-B>\"\<CR>", 'tx')
+ call assert_equal("\"breakadd abc", @:)
+ call assert_equal(['expr', 'file', 'func', 'here'], getcompletion('', 'breakpoint'))
+ let l = getcompletion('not', 'breakpoint')
+ call assert_equal([], l)
+
+ " Test for :breakadd file [lnum] <file>
+ call writefile([], 'Xscript')
+ call feedkeys(":breakadd file Xsc\<Tab>\<C-B>\"\<CR>", 'tx')
+ call assert_equal("\"breakadd file Xscript", @:)
+ call feedkeys(":breakadd file Xsc\<Tab>\<C-B>\"\<CR>", 'tx')
+ call assert_equal("\"breakadd file Xscript", @:)
+ call feedkeys(":breakadd file 20 Xsc\<Tab>\<C-B>\"\<CR>", 'tx')
+ call assert_equal("\"breakadd file 20 Xscript", @:)
+ call feedkeys(":breakadd file 20 Xsc\<Tab>\<C-B>\"\<CR>", 'tx')
+ call assert_equal("\"breakadd file 20 Xscript", @:)
+ call feedkeys(":breakadd file 20x Xsc\<Tab>\<C-B>\"\<CR>", 'tx')
+ call assert_equal("\"breakadd file 20x Xsc\t", @:)
+ call feedkeys(":breakadd file 20\<Tab>\<C-B>\"\<CR>", 'tx')
+ call assert_equal("\"breakadd file 20\t", @:)
+ call feedkeys(":breakadd file 20x\<Tab>\<C-B>\"\<CR>", 'tx')
+ call assert_equal("\"breakadd file 20x\t", @:)
+ call feedkeys(":breakadd file Xscript \<Tab>\<C-B>\"\<CR>", 'tx')
+ call assert_equal("\"breakadd file Xscript ", @:)
+ call feedkeys(":breakadd file X1B2C3\<Tab>\<C-B>\"\<CR>", 'tx')
+ call assert_equal("\"breakadd file X1B2C3", @:)
+ call delete('Xscript')
+
+ " Test for :breakadd func [lnum] <function>
+ func Xbreak_func()
+ endfunc
+ call feedkeys(":breakadd func Xbr\<Tab>\<C-B>\"\<CR>", 'tx')
+ call assert_equal("\"breakadd func Xbreak_func", @:)
+ call feedkeys(":breakadd func Xbr\<Tab>\<C-B>\"\<CR>", 'tx')
+ call assert_equal("\"breakadd func Xbreak_func", @:)
+ call feedkeys(":breakadd func 20 Xbr\<Tab>\<C-B>\"\<CR>", 'tx')
+ call assert_equal("\"breakadd func 20 Xbreak_func", @:)
+ call feedkeys(":breakadd func 20 Xbr\<Tab>\<C-B>\"\<CR>", 'tx')
+ call assert_equal("\"breakadd func 20 Xbreak_func", @:)
+ call feedkeys(":breakadd func 20x Xbr\<Tab>\<C-B>\"\<CR>", 'tx')
+ call assert_equal("\"breakadd func 20x Xbr\t", @:)
+ call feedkeys(":breakadd func 20\<Tab>\<C-B>\"\<CR>", 'tx')
+ call assert_equal("\"breakadd func 20\t", @:)
+ call feedkeys(":breakadd func 20x\<Tab>\<C-B>\"\<CR>", 'tx')
+ call assert_equal("\"breakadd func 20x\t", @:)
+ call feedkeys(":breakadd func Xbreak_func \<Tab>\<C-B>\"\<CR>", 'tx')
+ call assert_equal("\"breakadd func Xbreak_func ", @:)
+ call feedkeys(":breakadd func X1B2C3\<Tab>\<C-B>\"\<CR>", 'tx')
+ call assert_equal("\"breakadd func X1B2C3", @:)
+ delfunc Xbreak_func
+
+ " Test for :breakadd expr <expression>
+ let g:Xtest_var = 10
+ call feedkeys(":breakadd expr Xtest\<Tab>\<C-B>\"\<CR>", 'tx')
+ call assert_equal("\"breakadd expr Xtest_var", @:)
+ call feedkeys(":breakadd expr Xtest\<Tab>\<C-B>\"\<CR>", 'tx')
+ call assert_equal("\"breakadd expr Xtest_var", @:)
+ call feedkeys(":breakadd expr Xtest_var \<Tab>\<C-B>\"\<CR>", 'tx')
+ call assert_equal("\"breakadd expr Xtest_var ", @:)
+ call feedkeys(":breakadd expr X1B2C3\<Tab>\<C-B>\"\<CR>", 'tx')
+ call assert_equal("\"breakadd expr X1B2C3", @:)
+ unlet g:Xtest_var
+
+ " Test for :breakadd here
+ call feedkeys(":breakadd here Xtest\<Tab>\<C-B>\"\<CR>", 'tx')
+ call assert_equal("\"breakadd here Xtest", @:)
+ call feedkeys(":breakadd here Xtest\<Tab>\<C-B>\"\<CR>", 'tx')
+ call assert_equal("\"breakadd here Xtest", @:)
+ call feedkeys(":breakadd here \<Tab>\<C-B>\"\<CR>", 'tx')
+ call assert_equal("\"breakadd here ", @:)
+endfunc
+
+" Test for :breakdel argument completion
+func Test_cmdline_complete_breakdel()
+ call feedkeys(":breakdel \<C-A>\<C-B>\"\<CR>", 'tx')
+ call assert_equal("\"breakdel file func here", @:)
+ call feedkeys(":breakdel \<Tab>\<C-B>\"\<CR>", 'tx')
+ call assert_equal("\"breakdel file", @:)
+ call feedkeys(":breakdel \<Tab>\<C-B>\"\<CR>", 'tx')
+ call assert_equal("\"breakdel file", @:)
+ call feedkeys(":breakdel he\<Tab>\<C-B>\"\<CR>", 'tx')
+ call assert_equal("\"breakdel here", @:)
+ call feedkeys(":breakdel he\<Tab>\<C-B>\"\<CR>", 'tx')
+ call assert_equal("\"breakdel here", @:)
+ call feedkeys(":breakdel abc\<Tab>\<C-B>\"\<CR>", 'tx')
+ call assert_equal("\"breakdel abc", @:)
+
+ " Test for :breakdel file [lnum] <file>
+ call writefile([], 'Xscript')
+ call feedkeys(":breakdel file Xsc\<Tab>\<C-B>\"\<CR>", 'tx')
+ call assert_equal("\"breakdel file Xscript", @:)
+ call feedkeys(":breakdel file Xsc\<Tab>\<C-B>\"\<CR>", 'tx')
+ call assert_equal("\"breakdel file Xscript", @:)
+ call feedkeys(":breakdel file 20 Xsc\<Tab>\<C-B>\"\<CR>", 'tx')
+ call assert_equal("\"breakdel file 20 Xscript", @:)
+ call feedkeys(":breakdel file 20 Xsc\<Tab>\<C-B>\"\<CR>", 'tx')
+ call assert_equal("\"breakdel file 20 Xscript", @:)
+ call feedkeys(":breakdel file 20x Xsc\<Tab>\<C-B>\"\<CR>", 'tx')
+ call assert_equal("\"breakdel file 20x Xsc\t", @:)
+ call feedkeys(":breakdel file 20\<Tab>\<C-B>\"\<CR>", 'tx')
+ call assert_equal("\"breakdel file 20\t", @:)
+ call feedkeys(":breakdel file 20x\<Tab>\<C-B>\"\<CR>", 'tx')
+ call assert_equal("\"breakdel file 20x\t", @:)
+ call feedkeys(":breakdel file Xscript \<Tab>\<C-B>\"\<CR>", 'tx')
+ call assert_equal("\"breakdel file Xscript ", @:)
+ call feedkeys(":breakdel file X1B2C3\<Tab>\<C-B>\"\<CR>", 'tx')
+ call assert_equal("\"breakdel file X1B2C3", @:)
+ call delete('Xscript')
+
+ " Test for :breakdel func [lnum] <function>
+ func Xbreak_func()
+ endfunc
+ call feedkeys(":breakdel func Xbr\<Tab>\<C-B>\"\<CR>", 'tx')
+ call assert_equal("\"breakdel func Xbreak_func", @:)
+ call feedkeys(":breakdel func Xbr\<Tab>\<C-B>\"\<CR>", 'tx')
+ call assert_equal("\"breakdel func Xbreak_func", @:)
+ call feedkeys(":breakdel func 20 Xbr\<Tab>\<C-B>\"\<CR>", 'tx')
+ call assert_equal("\"breakdel func 20 Xbreak_func", @:)
+ call feedkeys(":breakdel func 20 Xbr\<Tab>\<C-B>\"\<CR>", 'tx')
+ call assert_equal("\"breakdel func 20 Xbreak_func", @:)
+ call feedkeys(":breakdel func 20x Xbr\<Tab>\<C-B>\"\<CR>", 'tx')
+ call assert_equal("\"breakdel func 20x Xbr\t", @:)
+ call feedkeys(":breakdel func 20\<Tab>\<C-B>\"\<CR>", 'tx')
+ call assert_equal("\"breakdel func 20\t", @:)
+ call feedkeys(":breakdel func 20x\<Tab>\<C-B>\"\<CR>", 'tx')
+ call assert_equal("\"breakdel func 20x\t", @:)
+ call feedkeys(":breakdel func Xbreak_func \<Tab>\<C-B>\"\<CR>", 'tx')
+ call assert_equal("\"breakdel func Xbreak_func ", @:)
+ call feedkeys(":breakdel func X1B2C3\<Tab>\<C-B>\"\<CR>", 'tx')
+ call assert_equal("\"breakdel func X1B2C3", @:)
+ delfunc Xbreak_func
+
+ " Test for :breakdel here
+ call feedkeys(":breakdel here Xtest\<Tab>\<C-B>\"\<CR>", 'tx')
+ call assert_equal("\"breakdel here Xtest", @:)
+ call feedkeys(":breakdel here Xtest\<Tab>\<C-B>\"\<CR>", 'tx')
+ call assert_equal("\"breakdel here Xtest", @:)
+ call feedkeys(":breakdel here \<Tab>\<C-B>\"\<CR>", 'tx')
+ call assert_equal("\"breakdel here ", @:)
+endfunc
+
+" Test for :scriptnames argument completion
+func Test_cmdline_complete_scriptnames()
+ set wildmenu
+ call writefile(['let a = 1'], 'Xa1b2c3.vim')
+ source Xa1b2c3.vim
+ call feedkeys(":script \<Tab>\<Left>\<Left>\<C-B>\"\<CR>", 'tx')
+ call assert_match("\"script .*Xa1b2c3.vim$", @:)
+ call feedkeys(":script \<Tab>\<Left>\<Left>\<C-B>\"\<CR>", 'tx')
+ call assert_match("\"script .*Xa1b2c3.vim$", @:)
+ call feedkeys(":script b2c3\<Tab>\<C-B>\"\<CR>", 'tx')
+ call assert_equal("\"script b2c3", @:)
+ call feedkeys(":script 2\<Tab>\<C-B>\"\<CR>", 'tx')
+ call assert_match("\"script 2\<Tab>$", @:)
+ call feedkeys(":script \<Tab>\<Left>\<Left> \<Tab>\<C-B>\"\<CR>", 'tx')
+ call assert_match("\"script .*Xa1b2c3.vim $", @:)
+ call feedkeys(":script \<Tab>\<Left>\<C-B>\"\<CR>", 'tx')
+ call assert_equal("\"script ", @:)
+ call assert_match('Xa1b2c3.vim$', getcompletion('.*Xa1b2.*', 'scriptnames')[0])
+ call assert_equal([], getcompletion('Xa1b2', 'scriptnames'))
+ new
+ call feedkeys(":script \<Tab>\<Left>\<Left>\<CR>", 'tx')
+ call assert_equal('Xa1b2c3.vim', fnamemodify(@%, ':t'))
+ bw!
+ call delete('Xa1b2c3.vim')
+ set wildmenu&
+endfunc
+
" this was going over the end of IObuff
func Test_report_error_with_composing()
let caught = 'no'
@@ -2074,6 +3460,16 @@ func Test_cmdline_complete_substitute_short()
endfor
endfunc
+" Test for :! shell command argument completion
+func Test_cmdline_complete_bang_cmd_argument()
+ set wildoptions=fuzzy
+ call feedkeys(":!vim test_cmdline.\<Tab>\<C-B>\"\<CR>", 'xt')
+ call assert_equal('"!vim test_cmdline.vim', @:)
+ set wildoptions&
+ call feedkeys(":!vim test_cmdline.\<Tab>\<C-B>\"\<CR>", 'xt')
+ call assert_equal('"!vim test_cmdline.vim', @:)
+endfunc
+
func Check_completion()
call assert_equal('let a', getcmdline())
call assert_equal(6, getcmdpos())
@@ -2129,4 +3525,57 @@ func Test_wildmenu_pum_disable_while_shown()
set wildoptions& wildmenu&
endfunc
+func Test_setcmdline()
+ func SetText(text, pos)
+ autocmd CmdlineChanged * let g:cmdtype = expand('<afile>')
+ call assert_equal(0, setcmdline(a:text))
+ call assert_equal(a:text, getcmdline())
+ call assert_equal(len(a:text) + 1, getcmdpos())
+ call assert_equal(getcmdtype(), g:cmdtype)
+ unlet g:cmdtype
+ autocmd! CmdlineChanged
+
+ call assert_equal(0, setcmdline(a:text, a:pos))
+ call assert_equal(a:text, getcmdline())
+ call assert_equal(a:pos, getcmdpos())
+
+ call assert_fails('call setcmdline("' .. a:text .. '", -1)', 'E487:')
+ call assert_fails('call setcmdline({}, 0)', 'E1174:')
+ call assert_fails('call setcmdline("' .. a:text .. '", {})', 'E1210:')
+
+ return ''
+ endfunc
+
+ call feedkeys(":\<C-R>=SetText('set rtp?', 2)\<CR>\<CR>", 'xt')
+ call assert_equal('set rtp?', @:)
+
+ call feedkeys(":let g:str = input('? ')\<CR>", 't')
+ call feedkeys("\<C-R>=SetText('foo', 4)\<CR>\<CR>", 'xt')
+ call assert_equal('foo', g:str)
+ unlet g:str
+
+ delfunc SetText
+
+ " setcmdline() returns 1 when not editing the command line.
+ call assert_equal(1, 'foo'->setcmdline())
+
+ " Called in custom function
+ func CustomComplete(A, L, P)
+ call assert_equal(0, setcmdline("DoCmd "))
+ return "January\nFebruary\nMars\n"
+ endfunc
+
+ com! -nargs=* -complete=custom,CustomComplete DoCmd :
+ call feedkeys(":DoCmd \<C-A>\<C-B>\"\<CR>", 'tx')
+ call assert_equal('"DoCmd January February Mars', @:)
+ delcom DoCmd
+ delfunc CustomComplete
+
+ " Called in <expr>
+ cnoremap <expr>a setcmdline('let foo=')
+ call feedkeys(":a\<CR>", 'tx')
+ call assert_equal('let foo=0', @:)
+ cunmap a
+endfunc
+
" vim: shiftwidth=2 sts=2 expandtab
diff --git a/src/nvim/testdir/test_comments.vim b/src/nvim/testdir/test_comments.vim
new file mode 100644
index 0000000000..c34b85c42d
--- /dev/null
+++ b/src/nvim/testdir/test_comments.vim
@@ -0,0 +1,277 @@
+" Tests for the various flags in the 'comments' option
+
+" Test for the 'n' flag in 'comments'
+func Test_comment_nested()
+ new
+ setlocal comments=n:> fo+=ro
+ exe "normal i> B\nD\<C-C>ggOA\<C-C>joC\<C-C>Go\<BS>>>> F\nH"
+ exe "normal 5GOE\<C-C>6GoG"
+ let expected =<< trim END
+ > A
+ > B
+ > C
+ > D
+ >>>> E
+ >>>> F
+ >>>> G
+ >>>> H
+ END
+ call assert_equal(expected, getline(1, '$'))
+ close!
+endfunc
+
+" Test for the 'b' flag in 'comments'
+func Test_comment_blank()
+ new
+ setlocal comments=b:* fo+=ro
+ exe "normal i* E\nF\n\<BS>G\nH\<C-C>ggOC\<C-C>O\<BS>B\<C-C>OA\<C-C>2joD"
+ let expected =<< trim END
+ A
+ *B
+ * C
+ * D
+ * E
+ * F
+ *G
+ H
+ END
+ call assert_equal(expected, getline(1, '$'))
+ close!
+endfunc
+
+" Test for the 'f' flag in 'comments' (only the first line has a comment
+" string)
+func Test_comment_firstline()
+ new
+ setlocal comments=f:- fo+=ro
+ exe "normal i- B\nD\<C-C>ggoC\<C-C>ggOA\<C-C>"
+ call assert_equal(['A', '- B', ' C', ' D'], getline(1, '$'))
+ %d
+ setlocal comments=:-
+ exe "normal i- B\nD\<C-C>ggoC\<C-C>ggOA\<C-C>"
+ call assert_equal(['- A', '- B', '- C', '- D'], getline(1, '$'))
+ close!
+endfunc
+
+" Test for the 's', 'm' and 'e' flags in 'comments'
+" Test for automatically adding comment leaders in insert mode
+func Test_comment_threepiece()
+ new
+ setlocal expandtab
+ call setline(1, ["\t/*"])
+ setlocal formatoptions=croql
+ call cursor(1, 3)
+ call feedkeys("A\<cr>\<cr>/", 'tnix')
+ call assert_equal(["\t/*", " *", " */"], getline(1, '$'))
+
+ " If a comment ends in a single line, then don't add it in the next line
+ %d
+ call setline(1, '/* line1 */')
+ call feedkeys("A\<CR>next line", 'xt')
+ call assert_equal(['/* line1 */', 'next line'], getline(1, '$'))
+
+ %d
+ " Copy the trailing indentation from the leader comment to a new line
+ setlocal autoindent noexpandtab
+ call feedkeys("a\t/*\tone\ntwo\n/", 'xt')
+ call assert_equal(["\t/*\tone", "\t *\ttwo", "\t */"], getline(1, '$'))
+ close!
+endfunc
+
+" Test for the 'r' flag in 'comments' (right align comment)
+func Test_comment_rightalign()
+ new
+ setlocal comments=sr:/***,m:**,ex-2:******/ fo+=ro
+ exe "normal i=\<C-C>o\t /***\nD\n/"
+ exe "normal 2GOA\<C-C>joB\<C-C>jOC\<C-C>joE\<C-C>GOF\<C-C>joG"
+ let expected =<< trim END
+ =
+ A
+ /***
+ ** B
+ ** C
+ ** D
+ ** E
+ ** F
+ ******/
+ G
+ END
+ call assert_equal(expected, getline(1, '$'))
+ close!
+endfunc
+
+" Test for the 'O' flag in 'comments'
+func Test_comment_O()
+ new
+ setlocal comments=Ob:* fo+=ro
+ exe "normal i* B\nD\<C-C>kOA\<C-C>joC"
+ let expected =<< trim END
+ A
+ * B
+ * C
+ * D
+ END
+ call assert_equal(expected, getline(1, '$'))
+ close!
+endfunc
+
+" Test for using a multibyte character as a comment leader
+func Test_comment_multibyte_leader()
+ new
+ let t =<< trim END
+ {
+ X
+ Xa
+ XaY
+ XY
+ XYZ
+ X Y
+ X YZ
+ XX
+ XXa
+ XXY
+ }
+ END
+ call setline(1, t)
+ call cursor(2, 1)
+
+ set tw=2 fo=cqm comments=n:X
+ exe "normal gqgqjgqgqjgqgqjgqgqjgqgqjgqgqjgqgqjgqgqjgqgqjgqgq"
+ let t =<< trim END
+ X
+ Xa
+ XaY
+ XY
+ XYZ
+ X Y
+ X YZ
+ XX
+ XXa
+ XXY
+ END
+ exe "normal o\n" . join(t, "\n")
+
+ let expected =<< trim END
+ {
+ X
+ Xa
+ Xa
+ XY
+ XY
+ XY
+ XZ
+ X Y
+ X Y
+ X Z
+ XX
+ XXa
+ XXY
+
+ X
+ Xa
+ Xa
+ XY
+ XY
+ XY
+ XZ
+ X Y
+ X Y
+ X Z
+ XX
+ XXa
+ XXY
+ }
+ END
+ call assert_equal(expected, getline(1, '$'))
+
+ set tw& fo& comments&
+ close!
+endfunc
+
+" Test for a space character in 'comments' setting
+func Test_comment_space()
+ new
+ setlocal comments=b:\ > fo+=ro
+ exe "normal i> B\nD\<C-C>ggOA\<C-C>joC"
+ exe "normal Go > F\nH\<C-C>kOE\<C-C>joG"
+ let expected =<< trim END
+ A
+ > B
+ C
+ D
+ > E
+ > F
+ > G
+ > H
+ END
+ call assert_equal(expected, getline(1, '$'))
+ close!
+endfunc
+
+" Test for formatting lines with and without comments
+func Test_comment_format_lines()
+ new
+ call setline(1, ['one', '/* two */', 'three'])
+ normal gggqG
+ call assert_equal(['one', '/* two */', 'three'], getline(1, '$'))
+ close!
+endfunc
+
+" Test for using 'a' in 'formatoptions' with comments
+func Test_comment_autoformat()
+ new
+ setlocal formatoptions+=a
+ call feedkeys("a- one\n- two\n", 'xt')
+ call assert_equal(['- one', '- two', ''], getline(1, '$'))
+
+ %d
+ call feedkeys("a\none\n", 'xt')
+ call assert_equal(['', 'one', ''], getline(1, '$'))
+
+ setlocal formatoptions+=aw
+ %d
+ call feedkeys("aone \ntwo\n", 'xt')
+ call assert_equal(['one two', ''], getline(1, '$'))
+
+ %d
+ call feedkeys("aone\ntwo\n", 'xt')
+ call assert_equal(['one', 'two', ''], getline(1, '$'))
+
+ close!
+endfunc
+
+" Test for joining lines with comments ('j' flag in 'formatoptions')
+func Test_comment_join_lines_fo_j()
+ new
+ setlocal fo+=j comments=://
+ call setline(1, ['i++; // comment1', ' // comment2'])
+ normal J
+ call assert_equal('i++; // comment1 comment2', getline(1))
+ setlocal fo-=j
+ call setline(1, ['i++; // comment1', ' // comment2'])
+ normal J
+ call assert_equal('i++; // comment1 // comment2', getline(1))
+ " Test with nested comments
+ setlocal fo+=j comments=n:>,n:)
+ call setline(1, ['i++; > ) > ) comment1', ' > ) comment2'])
+ normal J
+ call assert_equal('i++; > ) > ) comment1 comment2', getline(1))
+ close!
+endfunc
+
+" Test for formatting lines where only the first line has a comment.
+func Test_comment_format_firstline_comment()
+ new
+ setlocal formatoptions=tcq
+ call setline(1, ['- one two', 'three'])
+ normal gggqG
+ call assert_equal(['- one two three'], getline(1, '$'))
+
+ %d
+ call setline(1, ['- one', '- two'])
+ normal gggqG
+ call assert_equal(['- one', '- two'], getline(1, '$'))
+ close!
+endfunc
+
+" vim: shiftwidth=2 sts=2 expandtab
diff --git a/src/nvim/testdir/test_compiler.vim b/src/nvim/testdir/test_compiler.vim
index 3dc8710d63..ec7d143030 100644
--- a/src/nvim/testdir/test_compiler.vim
+++ b/src/nvim/testdir/test_compiler.vim
@@ -1,9 +1,11 @@
" Test the :compiler command
+source check.vim
+source shared.vim
+
func Test_compiler()
- if !executable('perl')
- return
- endif
+ CheckExecutable perl
+ CheckFeature quickfix
" $LANG changes the output of Perl.
if $LANG != ''
diff --git a/src/nvim/testdir/test_const.vim b/src/nvim/testdir/test_const.vim
index 0d064617a5..4a6c8779dd 100644
--- a/src/nvim/testdir/test_const.vim
+++ b/src/nvim/testdir/test_const.vim
@@ -194,6 +194,14 @@ func Test_lockvar()
if 0 | lockvar x | endif
let x = 'again'
+
+ let val = [1, 2, 3]
+ lockvar 0 val
+ let val[0] = 9
+ call assert_equal([9, 2, 3], val)
+ call add(val, 4)
+ call assert_equal([9, 2, 3, 4], val)
+ call assert_fails('let val = [4, 5, 6]', 'E1122:')
endfunc
@@ -231,6 +239,14 @@ func Test_const_with_special_variables()
call assert_fails('const &filetype = "vim"', 'E996:')
call assert_fails('const &l:filetype = "vim"', 'E996:')
call assert_fails('const &g:encoding = "utf-8"', 'E996:')
+
+ call assert_fails('const [a, $CONST_FOO] = [369, "abc"]', 'E996:')
+ call assert_equal(369, a)
+ call assert_equal(v:null, getenv("CONST_FOO"))
+
+ call assert_fails('const [b; $CONST_FOO] = [246, 2, "abc"]', 'E996:')
+ call assert_equal(246, b)
+ call assert_equal(v:null, getenv("CONST_FOO"))
endfunc
func Test_const_with_eval_name()
@@ -274,3 +290,5 @@ func Test_lock_depth_is_2()
const d2 = #{a: 0, b: lvar, c: 4}
let d2.b[1] = 'd'
endfunc
+
+" vim: shiftwidth=2 sts=2 expandtab
diff --git a/src/nvim/testdir/test_cpoptions.vim b/src/nvim/testdir/test_cpoptions.vim
new file mode 100644
index 0000000000..b9307ab30b
--- /dev/null
+++ b/src/nvim/testdir/test_cpoptions.vim
@@ -0,0 +1,927 @@
+" Test for the various 'cpoptions' (cpo) flags
+
+source check.vim
+source shared.vim
+source view_util.vim
+
+" Test for the 'a' flag in 'cpo'. Reading a file should set the alternate
+" file name.
+func Test_cpo_a()
+ let save_cpo = &cpo
+ call writefile(['one'], 'XfileCpoA')
+ " Wipe out all the buffers, so that the alternate file is empty
+ edit Xfoo | %bw
+ set cpo-=a
+ new
+ read XfileCpoA
+ call assert_equal('', @#)
+ %d
+ set cpo+=a
+ read XfileCpoA
+ call assert_equal('XfileCpoA', @#)
+ close!
+ call delete('XfileCpoA')
+ let &cpo = save_cpo
+endfunc
+
+" Test for the 'A' flag in 'cpo'. Writing a file should set the alternate
+" file name.
+func Test_cpo_A()
+ let save_cpo = &cpo
+ " Wipe out all the buffers, so that the alternate file is empty
+ edit Xfoo | %bw
+ set cpo-=A
+ new Xfile1
+ write Xfile2
+ call assert_equal('', @#)
+ %bw
+ call delete('Xfile2')
+ new Xfile1
+ set cpo+=A
+ write Xfile2
+ call assert_equal('Xfile2', @#)
+ close!
+ call delete('Xfile2')
+ let &cpo = save_cpo
+endfunc
+
+" Test for the 'b' flag in 'cpo'. "\|" at the end of a map command is
+" recognized as the end of the map.
+func Test_cpo_b()
+ let save_cpo = &cpo
+ set cpo+=b
+ nnoremap <F5> :pwd\<CR>\|let i = 1
+ call assert_equal(':pwd\<CR>\', maparg('<F5>'))
+ nunmap <F5>
+ exe "nnoremap <F5> :pwd\<C-V>|let i = 1"
+ call assert_equal(':pwd|let i = 1', maparg('<F5>'))
+ nunmap <F5>
+ set cpo-=b
+ nnoremap <F5> :pwd\<CR>\|let i = 1
+ call assert_equal(':pwd\<CR>|let i = 1', maparg('<F5>'))
+ let &cpo = save_cpo
+ nunmap <F5>
+endfunc
+
+" Test for the 'B' flag in 'cpo'. A backslash in mappings, abbreviations, user
+" commands and menu commands has no special meaning.
+func Test_cpo_B()
+ let save_cpo = &cpo
+ new
+ set cpo-=B
+ iabbr <buffer> abc ab\<BS>d
+ exe "normal iabc "
+ call assert_equal('ab<BS>d ', getline(1))
+ %d
+ set cpo+=B
+ iabbr <buffer> abc ab\<BS>d
+ exe "normal iabc "
+ call assert_equal('abd ', getline(1))
+ close!
+ let &cpo = save_cpo
+endfunc
+
+" Test for the 'c' flag in 'cpo'.
+func Test_cpo_c()
+ let save_cpo = &cpo
+ set cpo+=c
+ new
+ call setline(1, ' abababababab')
+ exe "normal gg/abab\<CR>"
+ call assert_equal(3, searchcount().total)
+ set cpo-=c
+ exe "normal gg/abab\<CR>"
+ call assert_equal(5, searchcount().total)
+ close!
+ let &cpo = save_cpo
+endfunc
+
+" Test for the 'C' flag in 'cpo' (line continuation)
+func Test_cpo_C()
+ let save_cpo = &cpo
+ call writefile(['let l = [', '\ 1,', '\ 2]'], 'XfileCpoC')
+ set cpo-=C
+ source XfileCpoC
+ call assert_equal([1, 2], g:l)
+ set cpo+=C
+ call assert_fails('source XfileCpoC', ['E697:', 'E10:'])
+ call delete('XfileCpoC')
+ let &cpo = save_cpo
+endfunc
+
+" Test for the 'd' flag in 'cpo' (tags relative to the current file)
+func Test_cpo_d()
+ let save_cpo = &cpo
+ call mkdir('XdirCpoD')
+ call writefile(["one\tXfile1\t/^one$/"], 'tags')
+ call writefile(["two\tXfile2\t/^two$/"], 'XdirCpoD/tags')
+ set tags=./tags
+ set cpo-=d
+ edit XdirCpoD/Xfile
+ call assert_equal('two', taglist('.*')[0].name)
+ set cpo+=d
+ call assert_equal('one', taglist('.*')[0].name)
+ %bw!
+ call delete('tags')
+ call delete('XdirCpoD', 'rf')
+ set tags&
+ let &cpo = save_cpo
+endfunc
+
+" Test for the 'D' flag in 'cpo' (digraph after a r, f or t)
+func Test_cpo_D()
+ CheckFeature digraphs
+ let save_cpo = &cpo
+ new
+ set cpo-=D
+ call setline(1, 'abcdefgh|')
+ exe "norm! 1gg0f\<c-k>!!"
+ call assert_equal(9, col('.'))
+ set cpo+=D
+ exe "norm! 1gg0f\<c-k>!!"
+ call assert_equal(1, col('.'))
+ set cpo-=D
+ close!
+ let &cpo = save_cpo
+endfunc
+
+" Test for the 'e' flag in 'cpo'
+func Test_cpo_e()
+ let save_cpo = &cpo
+ let @a='let i = 45'
+ set cpo+=e
+ call feedkeys(":@a\<CR>", 'xt')
+ call assert_equal(45, i)
+ set cpo-=e
+ call feedkeys(":@a\<CR>6\<CR>", 'xt')
+ call assert_equal(456, i)
+ let &cpo = save_cpo
+endfunc
+
+" Test for the 'E' flag in 'cpo' with yank, change, delete, etc. operators
+func Test_cpo_E()
+ new
+ call setline(1, '')
+ set cpo+=E
+ " yank an empty line
+ call assert_beeps('normal "ayl')
+ " change an empty line
+ call assert_beeps('normal lcTa')
+ call assert_beeps('normal 0c0')
+ " delete an empty line
+ call assert_beeps('normal D')
+ call assert_beeps('normal dl')
+ call assert_equal('', getline(1))
+ " change case of an empty line
+ call assert_beeps('normal gul')
+ call assert_beeps('normal gUl')
+ " replace a character
+ call assert_beeps('normal vrx')
+ " increment and decrement
+ call assert_beeps('exe "normal v\<C-A>"')
+ call assert_beeps('exe "normal v\<C-X>"')
+ set cpo-=E
+ close!
+endfunc
+
+" Test for the 'f' flag in 'cpo' (read in an empty buffer sets the file name)
+func Test_cpo_f()
+ let save_cpo = &cpo
+ new
+ set cpo-=f
+ read test_cpoptions.vim
+ call assert_equal('', @%)
+ %d
+ set cpo+=f
+ read test_cpoptions.vim
+ call assert_equal('test_cpoptions.vim', @%)
+ close!
+ let &cpo = save_cpo
+endfunc
+
+" Test for the 'F' flag in 'cpo' (write in an empty buffer sets the file name)
+func Test_cpo_F()
+ let save_cpo = &cpo
+ new
+ set cpo-=F
+ write XfileCpoF
+ call assert_equal('', @%)
+ call delete('XfileCpoF')
+ set cpo+=F
+ write XfileCpoF
+ call assert_equal('XfileCpoF', @%)
+ close!
+ call delete('XfileCpoF')
+ let &cpo = save_cpo
+endfunc
+
+" Test for the 'g' flag in 'cpo' (jump to line 1 when re-editing a file)
+func Test_cpo_g()
+ throw 'Skipped: Nvim does not support cpoptions flag "g"'
+ let save_cpo = &cpo
+ new test_cpoptions.vim
+ set cpo-=g
+ normal 20G
+ edit
+ call assert_equal(20, line('.'))
+ set cpo+=g
+ edit
+ call assert_equal(1, line('.'))
+ close!
+ let &cpo = save_cpo
+endfunc
+
+" Test for inserting text in a line with only spaces ('H' flag in 'cpoptions')
+func Test_cpo_H()
+ throw 'Skipped: Nvim does not support cpoptions flag "H"'
+ let save_cpo = &cpo
+ new
+ set cpo-=H
+ call setline(1, ' ')
+ normal! Ia
+ call assert_equal(' a', getline(1))
+ set cpo+=H
+ call setline(1, ' ')
+ normal! Ia
+ call assert_equal(' a ', getline(1))
+ close!
+ let &cpo = save_cpo
+endfunc
+
+" TODO: Add a test for the 'i' flag in 'cpo'
+" Interrupting the reading of a file will leave it modified.
+
+" Test for the 'I' flag in 'cpo' (deleting autoindent when using arrow keys)
+func Test_cpo_I()
+ let save_cpo = &cpo
+ new
+ setlocal autoindent
+ set cpo+=I
+ exe "normal i one\<CR>\<Up>"
+ call assert_equal(' ', getline(2))
+ set cpo-=I
+ %d
+ exe "normal i one\<CR>\<Up>"
+ call assert_equal('', getline(2))
+ close!
+ let &cpo = save_cpo
+endfunc
+
+" Test for the 'j' flag in 'cpo' is in the test_join.vim file.
+
+" Test for the 'J' flag in 'cpo' (two spaces after a sentence)
+func Test_cpo_J()
+ let save_cpo = &cpo
+ new
+ set cpo-=J
+ call setline(1, 'one. two! three? four."'' five.)]')
+ normal 0
+ for colnr in [6, 12, 19, 28, 34]
+ normal )
+ call assert_equal(colnr, col('.'))
+ endfor
+ for colnr in [28, 19, 12, 6, 1]
+ normal (
+ call assert_equal(colnr, col('.'))
+ endfor
+ set cpo+=J
+ normal 0
+ for colnr in [12, 28, 34]
+ normal )
+ call assert_equal(colnr, col('.'))
+ endfor
+ for colnr in [28, 12, 1]
+ normal (
+ call assert_equal(colnr, col('.'))
+ endfor
+ close!
+ let &cpo = save_cpo
+endfunc
+
+" TODO: Add a test for the 'k' flag in 'cpo'.
+" Disable the recognition of raw key codes in mappings, abbreviations, and the
+" "to" part of menu commands.
+
+" TODO: Add a test for the 'K' flag in 'cpo'.
+" Don't wait for a key code to complete when it is halfway a mapping.
+
+" Test for the 'l' flag in 'cpo' (backslash in a [] range)
+func Test_cpo_l()
+ let save_cpo = &cpo
+ new
+ call setline(1, ['', "a\tc" .. '\t'])
+ set cpo-=l
+ exe 'normal gg/[\t]' .. "\<CR>"
+ call assert_equal([2, 8], [col('.'), virtcol('.')])
+ set cpo+=l
+ exe 'normal gg/[\t]' .. "\<CR>"
+ call assert_equal([4, 10], [col('.'), virtcol('.')])
+ close!
+ let &cpo = save_cpo
+endfunc
+
+" Test for inserting tab in virtual replace mode ('L' flag in 'cpoptions')
+func Test_cpo_L()
+ let save_cpo = &cpo
+ new
+ set cpo-=L
+ call setline(1, 'abcdefghijklmnopqr')
+ exe "normal 0gR\<Tab>"
+ call assert_equal("\<Tab>ijklmnopqr", getline(1))
+ set cpo+=L
+ set list
+ call setline(1, 'abcdefghijklmnopqr')
+ exe "normal 0gR\<Tab>"
+ call assert_equal("\<Tab>cdefghijklmnopqr", getline(1))
+ set nolist
+ call setline(1, 'abcdefghijklmnopqr')
+ exe "normal 0gR\<Tab>"
+ call assert_equal("\<Tab>ijklmnopqr", getline(1))
+ close!
+ let &cpo = save_cpo
+endfunc
+
+" TODO: Add a test for the 'm' flag in 'cpo'.
+" When included, a showmatch will always wait half a second. When not
+" included, a showmatch will wait half a second or until a character is typed.
+
+" Test for the 'M' flag in 'cpo' (% with escape parenthesis)
+func Test_cpo_M()
+ let save_cpo = &cpo
+ new
+ call setline(1, ['( \( )', '\( ( \)'])
+
+ set cpo-=M
+ call cursor(1, 1)
+ normal %
+ call assert_equal(6, col('.'))
+ call cursor(1, 4)
+ call assert_beeps('normal %')
+ call cursor(2, 2)
+ normal %
+ call assert_equal(7, col('.'))
+ call cursor(2, 4)
+ call assert_beeps('normal %')
+
+ set cpo+=M
+ call cursor(1, 4)
+ normal %
+ call assert_equal(6, col('.'))
+ call cursor(1, 1)
+ call assert_beeps('normal %')
+ call cursor(2, 4)
+ normal %
+ call assert_equal(7, col('.'))
+ call cursor(2, 1)
+ call assert_beeps('normal %')
+
+ close!
+ let &cpo = save_cpo
+endfunc
+
+" Test for the 'n' flag in 'cpo' (using number column for wrapped lines)
+func Test_cpo_n()
+ let save_cpo = &cpo
+ new
+ call setline(1, repeat('a', &columns))
+ setlocal number
+ set cpo-=n
+ redraw!
+ call assert_equal(' aaaa', Screenline(2))
+ set cpo+=n
+ redraw!
+ call assert_equal('aaaa', Screenline(2))
+ close!
+ let &cpo = save_cpo
+endfunc
+
+" Test for the 'o' flag in 'cpo' (line offset to search command)
+func Test_cpo_o()
+ let save_cpo = &cpo
+ new
+ call setline(1, ['', 'one', 'two', 'three', 'one', 'two', 'three'])
+ set cpo-=o
+ exe "normal /one/+2\<CR>"
+ normal n
+ call assert_equal(7, line('.'))
+ set cpo+=o
+ exe "normal /one/+2\<CR>"
+ normal n
+ call assert_equal(5, line('.'))
+ close!
+ let &cpo = save_cpo
+endfunc
+
+" Test for the 'O' flag in 'cpo' (overwriting an existing file)
+func Test_cpo_O()
+ let save_cpo = &cpo
+ new XfileCpoO
+ call setline(1, 'one')
+ call writefile(['two'], 'XfileCpoO')
+ set cpo-=O
+ call assert_fails('write', 'E13:')
+ set cpo+=O
+ write
+ call assert_equal(['one'], readfile('XfileCpoO'))
+ close!
+ call delete('XfileCpoO')
+ let &cpo = save_cpo
+endfunc
+
+" Test for the 'p' flag in 'cpo' is in the test_lispwords.vim file.
+
+" Test for the 'P' flag in 'cpo' (appending to a file sets the current file
+" name)
+func Test_cpo_P()
+ let save_cpo = &cpo
+ call writefile([], 'XfileCpoP')
+ new
+ call setline(1, 'one')
+ set cpo+=F
+ set cpo-=P
+ write >> XfileCpoP
+ call assert_equal('', @%)
+ set cpo+=P
+ write >> XfileCpoP
+ call assert_equal('XfileCpoP', @%)
+ close!
+ call delete('XfileCpoP')
+ let &cpo = save_cpo
+endfunc
+
+" Test for the 'q' flag in 'cpo' (joining multiple lines)
+func Test_cpo_q()
+ let save_cpo = &cpo
+ new
+ call setline(1, ['one', 'two', 'three', 'four', 'five'])
+ set cpo-=q
+ normal gg4J
+ call assert_equal(14, col('.'))
+ %d
+ call setline(1, ['one', 'two', 'three', 'four', 'five'])
+ set cpo+=q
+ normal gg4J
+ call assert_equal(4, col('.'))
+ close!
+ let &cpo = save_cpo
+endfunc
+
+" Test for the 'r' flag in 'cpo' (redo command with a search motion)
+func Test_cpo_r()
+ let save_cpo = &cpo
+ new
+ call setline(1, repeat(['one two three four'], 2))
+ set cpo-=r
+ exe "normal ggc/two\<CR>abc "
+ let @/ = 'three'
+ normal 2G.
+ call assert_equal('abc two three four', getline(2))
+ %d
+ call setline(1, repeat(['one two three four'], 2))
+ set cpo+=r
+ exe "normal ggc/two\<CR>abc "
+ let @/ = 'three'
+ normal 2G.
+ call assert_equal('abc three four', getline(2))
+ close!
+ let &cpo = save_cpo
+endfunc
+
+" Test for the 'R' flag in 'cpo' (clear marks after a filter command)
+func Test_cpo_R()
+ CheckUnix
+ let save_cpo = &cpo
+ new
+ call setline(1, ['three', 'one', 'two'])
+ set cpo-=R
+ 3mark r
+ %!sort
+ call assert_equal(3, line("'r"))
+ %d
+ call setline(1, ['three', 'one', 'two'])
+ set cpo+=R
+ 3mark r
+ %!sort
+ call assert_equal(0, line("'r"))
+ close!
+ let &cpo = save_cpo
+endfunc
+
+" TODO: Add a test for the 's' flag in 'cpo'.
+" Set buffer options when entering the buffer for the first time. If not
+" present the options are set when the buffer is created.
+
+" Test for the 'S' flag in 'cpo' (copying buffer options)
+func Test_cpo_S()
+ let save_cpo = &cpo
+ new Xfile1
+ set noautoindent
+ new Xfile2
+ set cpo-=S
+ set autoindent
+ wincmd p
+ call assert_equal(0, &autoindent)
+ wincmd p
+ call assert_equal(1, &autoindent)
+ set cpo+=S
+ wincmd p
+ call assert_equal(1, &autoindent)
+ set noautoindent
+ wincmd p
+ call assert_equal(0, &autoindent)
+ wincmd t
+ close!
+ close!
+ let &cpo = save_cpo
+endfunc
+
+" Test for the 't' flag in 'cpo' is in the test_tagjump.vim file.
+
+" Test for the 'u' flag in 'cpo' (Vi-compatible undo)
+func Test_cpo_u()
+ let save_cpo = &cpo
+ new
+ set cpo-=u
+ exe "normal iabc\<C-G>udef\<C-G>ughi"
+ normal uu
+ call assert_equal('abc', getline(1))
+ %d
+ set cpo+=u
+ exe "normal iabc\<C-G>udef\<C-G>ughi"
+ normal uu
+ call assert_equal('abcdefghi', getline(1))
+ close!
+ let &cpo = save_cpo
+endfunc
+
+" TODO: Add a test for the 'v' flag in 'cpo'.
+" Backspaced characters remain visible on the screen in Insert mode.
+
+" Test for the 'w' flag in 'cpo' ('cw' on a blank character changes only one
+" character)
+func Test_cpo_w()
+ throw 'Skipped: Nvim does not support cpoptions flag "w"'
+ let save_cpo = &cpo
+ new
+ set cpo+=w
+ call setline(1, 'here are some words')
+ norm! 1gg0elcwZZZ
+ call assert_equal('hereZZZ are some words', getline('.'))
+ norm! 1gg2elcWYYY
+ call assert_equal('hereZZZ areYYY some words', getline('.'))
+ set cpo-=w
+ call setline(1, 'here are some words')
+ norm! 1gg0elcwZZZ
+ call assert_equal('hereZZZare some words', getline('.'))
+ norm! 1gg2elcWYYY
+ call assert_equal('hereZZZare someYYYwords', getline('.'))
+ close!
+ let &cpo = save_cpo
+endfunc
+
+" Test for the 'W' flag in 'cpo' is in the test_writefile.vim file
+
+" Test for the 'x' flag in 'cpo' (Esc on command-line executes command)
+func Test_cpo_x()
+ let save_cpo = &cpo
+ set cpo-=x
+ let i = 1
+ call feedkeys(":let i=10\<Esc>", 'xt')
+ call assert_equal(1, i)
+ set cpo+=x
+ call feedkeys(":let i=10\<Esc>", 'xt')
+ call assert_equal(10, i)
+ let &cpo = save_cpo
+endfunc
+
+" Test for the 'X' flag in 'cpo' ('R' with a count)
+func Test_cpo_X()
+ let save_cpo = &cpo
+ new
+ call setline(1, 'aaaaaa')
+ set cpo-=X
+ normal gg4Rx
+ call assert_equal('xxxxaa', getline(1))
+ normal ggRy
+ normal 4.
+ call assert_equal('yyyyaa', getline(1))
+ call setline(1, 'aaaaaa')
+ set cpo+=X
+ normal gg4Rx
+ call assert_equal('xxxxaaaaa', getline(1))
+ normal ggRy
+ normal 4.
+ call assert_equal('yyyyxxxaaaaa', getline(1))
+ close!
+ let &cpo = save_cpo
+endfunc
+
+" Test for the 'y' flag in 'cpo' (repeating a yank command)
+func Test_cpo_y()
+ let save_cpo = &cpo
+ new
+ call setline(1, ['one', 'two'])
+ set cpo-=y
+ normal ggyy
+ normal 2G.
+ call assert_equal("one\n", @")
+ %d
+ call setline(1, ['one', 'two'])
+ set cpo+=y
+ normal ggyy
+ normal 2G.
+ call assert_equal("two\n", @")
+ close!
+ let &cpo = save_cpo
+endfunc
+
+" Test for the 'Z' flag in 'cpo' (write! resets 'readonly')
+func Test_cpo_Z()
+ let save_cpo = &cpo
+ call writefile([], 'XfileCpoZ')
+ new XfileCpoZ
+ setlocal readonly
+ set cpo-=Z
+ write!
+ call assert_equal(0, &readonly)
+ set cpo+=Z
+ setlocal readonly
+ write!
+ call assert_equal(1, &readonly)
+ close!
+ call delete('XfileCpoZ')
+ let &cpo = save_cpo
+endfunc
+
+" Test for the '!' flag in 'cpo' is in the test_normal.vim file
+
+" Test for displaying dollar when changing text ('$' flag in 'cpoptions')
+func Test_cpo_dollar()
+ throw 'Skipped: use test/functional/legacy/cpoptions_spec.lua'
+ new
+ let g:Line = ''
+ func SaveFirstLine()
+ let g:Line = Screenline(1)
+ return ''
+ endfunc
+ inoremap <expr> <buffer> <F2> SaveFirstLine()
+ call test_override('redraw_flag', 1)
+ set cpo+=$
+ call setline(1, 'one two three')
+ redraw!
+ exe "normal c2w\<F2>vim"
+ call assert_equal('one tw$ three', g:Line)
+ call assert_equal('vim three', getline(1))
+ set cpo-=$
+ call test_override('ALL', 0)
+ delfunc SaveFirstLine
+ %bw!
+endfunc
+
+" Test for the '%' flag in 'cpo' (parenthesis matching inside strings)
+func Test_cpo_percent()
+ let save_cpo = &cpo
+ new
+ call setline(1, ' if (strcmp("ab)cd(", s))')
+ set cpo-=%
+ normal 8|%
+ call assert_equal(28, col('.'))
+ normal 15|%
+ call assert_equal(27, col('.'))
+ normal 27|%
+ call assert_equal(15, col('.'))
+ call assert_beeps("normal 19|%")
+ call assert_beeps("normal 22|%")
+ set cpo+=%
+ normal 8|%
+ call assert_equal(28, col('.'))
+ normal 15|%
+ call assert_equal(19, col('.'))
+ normal 27|%
+ call assert_equal(22, col('.'))
+ normal 19|%
+ call assert_equal(15, col('.'))
+ normal 22|%
+ call assert_equal(27, col('.'))
+ close!
+ let &cpo = save_cpo
+endfunc
+
+" Test for cursor movement with '-' in 'cpoptions'
+func Test_cpo_minus()
+ throw 'Skipped: Nvim does not support cpoptions flag "-"'
+ new
+ call setline(1, ['foo', 'bar', 'baz'])
+ let save_cpo = &cpo
+ set cpo+=-
+ call assert_beeps('normal 10j')
+ call assert_equal(1, line('.'))
+ normal G
+ call assert_beeps('normal 10k')
+ call assert_equal(3, line('.'))
+ call assert_fails(10, 'E16:')
+ close!
+ let &cpo = save_cpo
+endfunc
+
+" Test for the '+' flag in 'cpo' ('write file' command resets the 'modified'
+" flag)
+func Test_cpo_plus()
+ let save_cpo = &cpo
+ call writefile([], 'XfileCpoPlus')
+ new XfileCpoPlus
+ call setline(1, 'foo')
+ write X1
+ call assert_equal(1, &modified)
+ set cpo+=+
+ write X2
+ call assert_equal(0, &modified)
+ close!
+ call delete('XfileCpoPlus')
+ call delete('X1')
+ call delete('X2')
+ let &cpo = save_cpo
+endfunc
+
+" Test for the '*' flag in 'cpo' (':*' is same as ':@')
+func Test_cpo_star()
+ throw 'Skipped: Nvim does not support cpoptions flag "*"'
+ let save_cpo = &cpo
+ let x = 0
+ new
+ set cpo-=*
+ let @a = 'let x += 1'
+ call assert_fails('*a', 'E20:')
+ set cpo+=*
+ *a
+ call assert_equal(1, x)
+ close!
+ let &cpo = save_cpo
+endfunc
+
+" Test for the '<' flag in 'cpo' is in the test_mapping.vim file
+
+" Test for the '>' flag in 'cpo' (use a new line when appending to a register)
+func Test_cpo_gt()
+ let save_cpo = &cpo
+ new
+ call setline(1, 'one two')
+ set cpo-=>
+ let @r = ''
+ normal gg"Rye
+ normal "Rye
+ call assert_equal("oneone", @r)
+ set cpo+=>
+ let @r = ''
+ normal gg"Rye
+ normal "Rye
+ call assert_equal("\none\none", @r)
+ close!
+ let &cpo = save_cpo
+endfunc
+
+" Test for the ';' flag in 'cpo'
+" Test for t,f,F,T movement commands and 'cpo-;' setting
+func Test_cpo_semicolon()
+ let save_cpo = &cpo
+ new
+ call append(0, ["aaa two three four", " zzz", "yyy ",
+ \ "bbb yee yoo four", "ccc two three four",
+ \ "ddd yee yoo four"])
+ set cpo-=;
+ 1
+ normal! 0tt;D
+ 2
+ normal! 0fz;D
+ 3
+ normal! $Fy;D
+ 4
+ normal! $Ty;D
+ set cpo+=;
+ 5
+ normal! 0tt;;D
+ 6
+ normal! $Ty;;D
+
+ call assert_equal('aaa two', getline(1))
+ call assert_equal(' z', getline(2))
+ call assert_equal('y', getline(3))
+ call assert_equal('bbb y', getline(4))
+ call assert_equal('ccc', getline(5))
+ call assert_equal('ddd yee y', getline(6))
+ close!
+ let &cpo = save_cpo
+endfunc
+
+" Test for the '#' flag in 'cpo' (count before 'D', 'o' and 'O' operators)
+func Test_cpo_hash()
+ throw 'Skipped: Nvim does not support cpoptions flag "#"'
+ let save_cpo = &cpo
+ new
+ set cpo-=#
+ call setline(1, ['one', 'two', 'three'])
+ normal gg2D
+ call assert_equal(['three'], getline(1, '$'))
+ normal gg2ofour
+ call assert_equal(['three', 'four', 'four'], getline(1, '$'))
+ normal gg2Otwo
+ call assert_equal(['two', 'two', 'three', 'four', 'four'], getline(1, '$'))
+ %d
+ set cpo+=#
+ call setline(1, ['one', 'two', 'three'])
+ normal gg2D
+ call assert_equal(['', 'two', 'three'], getline(1, '$'))
+ normal gg2oone
+ call assert_equal(['', 'one', 'two', 'three'], getline(1, '$'))
+ normal gg2Ozero
+ call assert_equal(['zero', '', 'one', 'two', 'three'], getline(1, '$'))
+ close!
+ let &cpo = save_cpo
+endfunc
+
+" Test for the '&' flag in 'cpo'. The swap file is kept when a buffer is still
+" loaded and ':preserve' is used.
+func Test_cpo_ampersand()
+ throw 'Skipped: Nvim does not support cpoptions flag "&"'
+ call writefile(['one'], 'XfileCpoAmp')
+ let after =<< trim [CODE]
+ set cpo+=&
+ preserve
+ qall
+ [CODE]
+ if RunVim([], after, 'XfileCpoAmp')
+ call assert_equal(1, filereadable('.XfileCpoAmp.swp'))
+ call delete('.XfileCpoAmp.swp')
+ endif
+ call delete('XfileCpoAmp')
+endfunc
+
+" Test for the '\' flag in 'cpo' (backslash in a [] range in a search pattern)
+func Test_cpo_backslash()
+ throw 'Skipped: Nvim does not support cpoptions flag "\"'
+ let save_cpo = &cpo
+ new
+ call setline(1, ['', " \\-string"])
+ set cpo-=\
+ exe 'normal gg/[ \-]' .. "\<CR>n"
+ call assert_equal(3, col('.'))
+ set cpo+=\
+ exe 'normal gg/[ \-]' .. "\<CR>n"
+ call assert_equal(2, col('.'))
+ close!
+ let &cpo = save_cpo
+endfunc
+
+" Test for the '/' flag in 'cpo' is in the test_substitute.vim file
+
+" Test for the '{' flag in 'cpo' (the "{" and "}" commands stop at a {
+" character at the start of a line)
+func Test_cpo_brace()
+ throw 'Skipped: Nvim does not support cpoptions flag "{"'
+ let save_cpo = &cpo
+ new
+ call setline(1, ['', '{', ' int i;', '}', ''])
+ set cpo-={
+ normal gg}
+ call assert_equal(5, line('.'))
+ normal G{
+ call assert_equal(1, line('.'))
+ set cpo+={
+ normal gg}
+ call assert_equal(2, line('.'))
+ normal G{
+ call assert_equal(2, line('.'))
+ close!
+ let &cpo = save_cpo
+endfunc
+
+" Test for the '.' flag in 'cpo' (:cd command fails if the current buffer is
+" modified)
+func Test_cpo_dot()
+ throw 'Skipped: Nvim does not support cpoptions flag "."'
+ let save_cpo = &cpo
+ new Xfoo
+ call setline(1, 'foo')
+ let save_dir = getcwd()
+ set cpo+=.
+
+ " :cd should fail when buffer is modified and 'cpo' contains dot.
+ call assert_fails('cd ..', 'E747:')
+ call assert_equal(save_dir, getcwd())
+
+ " :cd with exclamation mark should succeed.
+ cd! ..
+ call assert_notequal(save_dir, getcwd())
+
+ " :cd should succeed when buffer has been written.
+ w!
+ exe 'cd ' .. fnameescape(save_dir)
+ call assert_equal(save_dir, getcwd())
+
+ call delete('Xfoo')
+ set cpo&
+ close!
+ let &cpo = save_cpo
+endfunc
+
+" vim: shiftwidth=2 sts=2 expandtab
diff --git a/src/nvim/testdir/test_cscope.vim b/src/nvim/testdir/test_cscope.vim
deleted file mode 100644
index 76ea35fa10..0000000000
--- a/src/nvim/testdir/test_cscope.vim
+++ /dev/null
@@ -1,344 +0,0 @@
-" Test for cscope commands.
-
-source check.vim
-CheckFeature cscope
-CheckFeature quickfix
-
-if !executable('cscope')
- throw 'Skipped: cscope program missing'
-endif
-
-func CscopeSetupOrClean(setup)
- if a:setup
- noa sp samples/memfile_test.c
- saveas! Xmemfile_test.c
- call system('cscope -bk -fXcscope.out Xmemfile_test.c')
- call system('cscope -bk -fXcscope2.out Xmemfile_test.c')
- cscope add Xcscope.out
- set cscopequickfix=s-,g-,d-,c-,t-,e-,f-,i-,a-
- else
- cscope kill -1
- for file in ['Xcscope.out', 'Xcscope2.out', 'Xmemfile_test.c']
- call delete(file)
- endfo
- endif
-endfunc
-
-func Test_cscopeWithCscopeConnections()
- call CscopeSetupOrClean(1)
- " Test: E568: duplicate cscope database not added
- try
- set nocscopeverbose
- cscope add Xcscope.out
- set cscopeverbose
- catch
- call assert_report('exception thrown')
- endtry
- call assert_fails('cscope add', 'E560')
- call assert_fails('cscope add Xcscope.out', 'E568')
- call assert_fails('cscope add doesnotexist.out', 'E563')
- if has('unix')
- call assert_fails('cscope add /dev/null', 'E564:')
- endif
-
- " Test: Find this C-Symbol
- for cmd in ['cs find s main', 'cs find 0 main']
- let a = execute(cmd)
- " Test where it moves the cursor
- call assert_equal('main(void)', getline('.'))
- " Test the output of the :cs command
- call assert_match('\n(1 of 1): <<main>> main(void )', a)
- endfor
-
- " Test: Find this definition
- for cmd in ['cs find g test_mf_hash',
- \ 'cs find 1 test_mf_hash',
- \ 'cs find 1 test_mf_hash'] " leading space ignored.
- exe cmd
- call assert_equal(['', '/*', ' * Test mf_hash_*() functions.', ' */', ' static void', 'test_mf_hash(void)', '{'], getline(line('.')-5, line('.')+1))
- endfor
-
- " Test: Find functions called by this function
- for cmd in ['cs find d test_mf_hash', 'cs find 2 test_mf_hash']
- let a = execute(cmd)
- call assert_match('\n(1 of 42): <<mf_hash_init>> mf_hash_init(&ht);', a)
- call assert_equal(' mf_hash_init(&ht);', getline('.'))
- endfor
-
- " Test: Find functions calling this function
- for cmd in ['cs find c test_mf_hash', 'cs find 3 test_mf_hash']
- let a = execute(cmd)
- call assert_match('\n(1 of 1): <<main>> test_mf_hash();', a)
- call assert_equal(' test_mf_hash();', getline('.'))
- endfor
-
- " Test: Find this text string
- for cmd in ['cs find t Bram', 'cs find 4 Bram']
- let a = execute(cmd)
- call assert_match('(1 of 1): <<<unknown>>> \* VIM - Vi IMproved^Iby Bram Moolenaar', a)
- call assert_equal(' * VIM - Vi IMproved by Bram Moolenaar', getline('.'))
- endfor
-
- " Test: Find this egrep pattern
- " test all matches returned by cscope
- for cmd in ['cs find e ^\#includ.', 'cs find 6 ^\#includ.']
- let a = execute(cmd)
- call assert_match('\n(1 of 3): <<<unknown>>> #include <assert.h>', a)
- call assert_equal('#include <assert.h>', getline('.'))
- cnext
- call assert_equal('#include "main.c"', getline('.'))
- cnext
- call assert_equal('#include "memfile.c"', getline('.'))
- call assert_fails('cnext', 'E553:')
- endfor
-
- " Test: Find the same egrep pattern using lcscope this time.
- let a = execute('lcs find e ^\#includ.')
- call assert_match('\n(1 of 3): <<<unknown>>> #include <assert.h>', a)
- call assert_equal('#include <assert.h>', getline('.'))
- lnext
- call assert_equal('#include "main.c"', getline('.'))
- lnext
- call assert_equal('#include "memfile.c"', getline('.'))
- call assert_fails('lnext', 'E553:')
-
- " Test: Find this file
- for cmd in ['cs find f Xmemfile_test.c', 'cs find 7 Xmemfile_test.c']
- enew
- let a = execute(cmd)
- call assert_true(a =~ '"Xmemfile_test.c" \d\+L, \d\+B')
- call assert_equal('Xmemfile_test.c', @%)
- endfor
-
- " Test: Find files #including this file
- for cmd in ['cs find i assert.h', 'cs find 8 assert.h']
- enew
- let a = execute(cmd)
- let alines = split(a, '\n', 1)
- call assert_equal('', alines[0])
- call assert_true(alines[1] =~ '"Xmemfile_test.c" \d\+L, \d\+B')
- call assert_equal('(1 of 1): <<global>> #include <assert.h>', alines[2])
- call assert_equal('#include <assert.h>', getline('.'))
- endfor
-
- " Test: Invalid find command
- call assert_fails('cs find', 'E560:')
- call assert_fails('cs find x', 'E560:')
-
- if has('float')
- " Test: Find places where this symbol is assigned a value
- " this needs a cscope >= 15.8
- " unfortunately, Travis has cscope version 15.7
- let cscope_version = systemlist('cscope --version')[0]
- let cs_version = str2float(matchstr(cscope_version, '\d\+\(\.\d\+\)\?'))
- if cs_version >= 15.8
- for cmd in ['cs find a item', 'cs find 9 item']
- let a = execute(cmd)
- call assert_equal(['', '(1 of 4): <<test_mf_hash>> item = (mf_hashitem_T *)lalloc_clear(sizeof(*item), FALSE);'], split(a, '\n', 1))
- call assert_equal(' item = (mf_hashitem_T *)lalloc_clear(sizeof(*item), FALSE);', getline('.'))
- cnext
- call assert_equal(' item = mf_hash_find(&ht, key);', getline('.'))
- cnext
- call assert_equal(' item = mf_hash_find(&ht, key);', getline('.'))
- cnext
- call assert_equal(' item = mf_hash_find(&ht, key);', getline('.'))
- endfor
- endif
- endif
-
- " Test: leading whitespace is not removed for cscope find text
- let a = execute('cscope find t test_mf_hash')
- call assert_equal(['', '(1 of 1): <<<unknown>>> test_mf_hash();'], split(a, '\n', 1))
- call assert_equal(' test_mf_hash();', getline('.'))
-
- " Test: test with scscope
- let a = execute('scs find t Bram')
- call assert_match('(1 of 1): <<<unknown>>> \* VIM - Vi IMproved^Iby Bram Moolenaar', a)
- call assert_equal(' * VIM - Vi IMproved by Bram Moolenaar', getline('.'))
-
- " Test: cscope help
- for cmd in ['cs', 'cs help', 'cs xxx']
- let a = execute(cmd)
- call assert_match('^cscope commands:\n', a)
- call assert_match('\nadd :', a)
- call assert_match('\nfind :', a)
- call assert_match('\nhelp : Show this message', a)
- call assert_match('\nkill : Kill a connection', a)
- call assert_match('\nreset: Reinit all connections', a)
- call assert_match('\nshow : Show connections', a)
- endfor
- let a = execute('scscope help')
- call assert_match('This cscope command does not support splitting the window\.', a)
-
- " Test: reset connections
- let a = execute('cscope reset')
- call assert_match('\nAdded cscope database.*Xcscope.out (#0)', a)
- call assert_match('\nAll cscope databases reset', a)
-
- " Test: cscope show
- let a = execute('cscope show')
- call assert_match('\n 0 \d\+.*Xcscope.out\s*<none>', a)
-
- " Test: cstag and 'csto' option
- set csto=0
- let a = execute('cstag TEST_COUNT')
- call assert_match('(1 of 1): <<TEST_COUNT>> #define TEST_COUNT 50000', a)
- call assert_equal('#define TEST_COUNT 50000', getline('.'))
- call assert_fails('cstag DOES_NOT_EXIST', 'E257:')
- set csto=1
- let a = execute('cstag index_to_key')
- call assert_match('(1 of 1): <<index_to_key>> #define index_to_key(i) ((i) ^ 15167)', a)
- call assert_equal('#define index_to_key(i) ((i) ^ 15167)', getline('.'))
- call assert_fails('cstag DOES_NOT_EXIST', 'E257:')
- call assert_fails('cstag', 'E562:')
- let save_tags = &tags
- set tags=
- call assert_fails('cstag DOES_NOT_EXIST', 'E257:')
- let a = execute('cstag index_to_key')
- call assert_match('(1 of 1): <<index_to_key>> #define index_to_key(i) ((i) ^ 15167)', a)
- let &tags = save_tags
-
- " Test: 'cst' option
- set nocst
- call assert_fails('tag TEST_COUNT', 'E426:')
- set cst
- let a = execute('tag TEST_COUNT')
- call assert_match('(1 of 1): <<TEST_COUNT>> #define TEST_COUNT 50000', a)
- call assert_equal('#define TEST_COUNT 50000', getline('.'))
- let a = execute('tags')
- call assert_match('1 1 TEST_COUNT\s\+\d\+\s\+#define index_to_key', a)
-
- " Test: 'cscoperelative'
- call mkdir('Xcscoperelative')
- cd Xcscoperelative
- let a = execute('cs find g test_mf_hash')
- call assert_notequal('test_mf_hash(void)', getline('.'))
- set cscoperelative
- let a = execute('cs find g test_mf_hash')
- call assert_equal('test_mf_hash(void)', getline('.'))
- set nocscoperelative
- cd ..
- call delete('Xcscoperelative', 'd')
-
- " Test: E259: no match found
- call assert_fails('cscope find g DOES_NOT_EXIST', 'E259:')
-
- " Test: this should trigger call to cs_print_tags()
- " Unclear how to check result though, we just exercise the code.
- set cst cscopequickfix=s0
- call feedkeys(":cs find s main\<CR>", 't')
-
- " Test: cscope kill
- call assert_fails('cscope kill', 'E560:')
- call assert_fails('cscope kill 2', 'E261:')
- call assert_fails('cscope kill xxx', 'E261:')
-
- let a = execute('cscope kill 0')
- call assert_match('cscope connection 0 closed', a)
-
- cscope add Xcscope.out
- let a = execute('cscope kill Xcscope.out')
- call assert_match('cscope connection Xcscope.out closed', a)
-
- cscope add Xcscope.out .
- let a = execute('cscope kill -1')
- call assert_match('cscope connection .*Xcscope.out closed', a)
- let a = execute('cscope kill -1')
- call assert_equal('', a)
-
- " Test: 'csprg' option
- call assert_equal('cscope', &csprg)
- set csprg=doesnotexist
- call assert_fails('cscope add Xcscope2.out', 'E609:')
- set csprg=cscope
-
- " Test: multiple cscope connections
- cscope add Xcscope.out
- cscope add Xcscope2.out . -C
- let a = execute('cscope show')
- call assert_match('\n 0 \d\+.*Xcscope.out\s*<none>', a)
- call assert_match('\n 1 \d\+.*Xcscope2.out\s*\.', a)
-
- " Test: test Ex command line completion
- call feedkeys(":cs \<C-A>\<C-B>\"\<CR>", 'tx')
- call assert_equal('"cs add find help kill reset show', @:)
-
- call feedkeys(":scs \<C-A>\<C-B>\"\<CR>", 'tx')
- call assert_equal('"scs find', @:)
-
- call feedkeys(":cs find \<C-A>\<C-B>\"\<CR>", 'tx')
- call assert_equal('"cs find a c d e f g i s t', @:)
-
- call feedkeys(":cs kill \<C-A>\<C-B>\"\<CR>", 'tx')
- call assert_equal('"cs kill -1 0 1', @:)
-
- call feedkeys(":cs add Xcscope\<C-A>\<C-B>\"\<CR>", 'tx')
- call assert_equal('"cs add Xcscope.out Xcscope2.out', @:)
-
- " Test: cscope_connection()
- call assert_equal(cscope_connection(), 1)
- call assert_equal(cscope_connection(0, 'out'), 1)
- call assert_equal(cscope_connection(0, 'xxx'), 1)
-
- call assert_equal(cscope_connection(1, 'out'), 1)
- call assert_equal(cscope_connection(1, 'xxx'), 0)
-
- call assert_equal(cscope_connection(2, 'out'), 0)
- call assert_equal(cscope_connection(2, getcwd() .. '/Xcscope.out', 1), 1)
-
- call assert_equal(cscope_connection(3, 'xxx', '..'), 0)
- call assert_equal(cscope_connection(3, 'out', 'xxx'), 0)
- call assert_equal(cscope_connection(3, 'out', '.'), 1)
-
- call assert_equal(cscope_connection(4, 'out', '.'), 0)
-
- call assert_equal(cscope_connection(5, 'out'), 0)
- call assert_equal(cscope_connection(-1, 'out'), 0)
-
- call CscopeSetupOrClean(0)
-endfunc
-
-" Test ":cs add {dir}" (add the {dir}/cscope.out database)
-func Test_cscope_add_dir()
- call mkdir('Xcscopedir', 'p')
-
- " Cscope doesn't handle symlinks, so this needs to be resolved in case a
- " shadow directory is being used.
- let memfile = resolve('./samples/memfile_test.c')
- call system('cscope -bk -fXcscopedir/cscope.out ' . memfile)
-
- cs add Xcscopedir
- let a = execute('cscope show')
- let lines = split(a, "\n", 1)
- call assert_equal(3, len(lines))
- call assert_equal(' # pid database name prepend path', lines[0])
- call assert_equal('', lines[1])
- call assert_match('^ 0 \d\+.*Xcscopedir/cscope.out\s\+<none>$', lines[2])
-
- cs kill -1
- call delete('Xcscopedir/cscope.out')
- call assert_fails('cs add Xcscopedir', 'E563:')
-
- call delete('Xcscopedir', 'd')
-endfunc
-
-func Test_cscopequickfix()
- set cscopequickfix=s-,g-,d+,c-,t+,e-,f0,i-,a-
- call assert_equal('s-,g-,d+,c-,t+,e-,f0,i-,a-', &cscopequickfix)
-
- call assert_fails('set cscopequickfix=x-', 'E474:')
- call assert_fails('set cscopequickfix=s', 'E474:')
- call assert_fails('set cscopequickfix=s7', 'E474:')
- call assert_fails('set cscopequickfix=s-a', 'E474:')
-endfunc
-
-func Test_withoutCscopeConnection()
- call assert_equal(cscope_connection(), 0)
-
- call assert_fails('cscope find s main', 'E567:')
- let a = execute('cscope show')
- call assert_match('no cscope connections', a)
-endfunc
-
-
-" vim: shiftwidth=2 sts=2 expandtab
diff --git a/src/nvim/testdir/test_cursor_func.vim b/src/nvim/testdir/test_cursor_func.vim
index 3b8a5f27ad..bb8e7cd5c5 100644
--- a/src/nvim/testdir/test_cursor_func.vim
+++ b/src/nvim/testdir/test_cursor_func.vim
@@ -1,7 +1,10 @@
" Tests for cursor() and other functions that get/set the cursor position
+source check.vim
+
func Test_wrong_arguments()
call assert_fails('call cursor(1. 3)', 'E474:')
+ call assert_fails('call cursor(v:_null_list)', 'E474:')
endfunc
func Test_move_cursor()
@@ -22,7 +25,7 @@ func Test_move_cursor()
call cursor(3, 0)
call assert_equal([3, 1, 0, 1], getcurpos()[1:])
" below last line goes to last line
- call cursor(9, 1)
+ eval [9, 1]->cursor()
call assert_equal([4, 1, 0, 1], getcurpos()[1:])
" pass string arguments
call cursor('3', '3')
@@ -32,7 +35,7 @@ func Test_move_cursor()
call cursor(1, 1, 1)
call assert_equal([1, 1, 1], getcurpos()[1:3])
- call assert_equal(-1, cursor(-1, -1))
+ call assert_fails('call cursor(-1, -1)', 'E475:')
quit!
endfunc
@@ -82,34 +85,85 @@ func Test_screenpos()
let winid = win_getid()
let [winrow, wincol] = win_screenpos(winid)
call assert_equal({'row': winrow,
- \ 'col': wincol + 0,
- \ 'curscol': wincol + 7,
- \ 'endcol': wincol + 7}, winid->screenpos(1, 1))
+ \ 'col': wincol + 0,
+ \ 'curscol': wincol + 7,
+ \ 'endcol': wincol + 7}, winid->screenpos(1, 1))
call assert_equal({'row': winrow,
- \ 'col': wincol + 13,
- \ 'curscol': wincol + 13,
- \ 'endcol': wincol + 13}, winid->screenpos(1, 7))
+ \ 'col': wincol + 13,
+ \ 'curscol': wincol + 13,
+ \ 'endcol': wincol + 13}, winid->screenpos(1, 7))
call assert_equal({'row': winrow + 2,
- \ 'col': wincol + 1,
- \ 'curscol': wincol + 1,
- \ 'endcol': wincol + 1}, screenpos(winid, 2, 22))
+ \ 'col': wincol + 1,
+ \ 'curscol': wincol + 1,
+ \ 'endcol': wincol + 1}, screenpos(winid, 2, 22))
setlocal number
call assert_equal({'row': winrow + 3,
- \ 'col': wincol + 9,
- \ 'curscol': wincol + 9,
- \ 'endcol': wincol + 9}, screenpos(winid, 2, 22))
+ \ 'col': wincol + 9,
+ \ 'curscol': wincol + 9,
+ \ 'endcol': wincol + 9}, screenpos(winid, 2, 22))
+
+ let wininfo = getwininfo(winid)[0]
+ call setline(3, ['x']->repeat(wininfo.height))
+ call setline(line('$') + 1, 'x'->repeat(wininfo.width * 3))
+ setlocal nonumber display=lastline so=0
+ exe "normal G\<C-Y>\<C-Y>"
+ redraw
+ call assert_equal({'row': winrow + wininfo.height - 1,
+ \ 'col': wincol + 7,
+ \ 'curscol': wincol + 7,
+ \ 'endcol': wincol + 7}, winid->screenpos(line('$'), 8))
+ call assert_equal({'row': 0, 'col': 0, 'curscol': 0, 'endcol': 0},
+ \ winid->screenpos(line('$'), 22))
+
close
call assert_equal({}, screenpos(999, 1, 1))
+
bwipe!
+ set display&
- call assert_equal({'col': 1, 'row': 1, 'endcol': 1, 'curscol': 1}, screenpos(win_getid(), 1, 1))
+ call assert_equal(#{col: 1, row: 1, endcol: 1, curscol: 1}, screenpos(win_getid(), 1, 1))
" nmenu WinBar.TEST :
setlocal winbar=TEST
- call assert_equal({'col': 1, 'row': 2, 'endcol': 1, 'curscol': 1}, screenpos(win_getid(), 1, 1))
+ call assert_equal(#{col: 1, row: 2, endcol: 1, curscol: 1}, screenpos(win_getid(), 1, 1))
" nunmenu WinBar.TEST
setlocal winbar&
endfunc
+func Test_screenpos_fold()
+ CheckFeature folding
+
+ enew!
+ call setline(1, range(10))
+ 3,5fold
+ redraw
+ call assert_equal(2, screenpos(1, 2, 1).row)
+ call assert_equal(#{col: 1, row: 3, endcol: 1, curscol: 1}, screenpos(1, 3, 1))
+ call assert_equal(#{col: 1, row: 3, endcol: 1, curscol: 1}, screenpos(1, 4, 1))
+ call assert_equal(#{col: 1, row: 3, endcol: 1, curscol: 1}, screenpos(1, 5, 1))
+ setlocal number
+ call assert_equal(#{col: 5, row: 3, endcol: 5, curscol: 5}, screenpos(1, 3, 1))
+ call assert_equal(#{col: 5, row: 3, endcol: 5, curscol: 5}, screenpos(1, 4, 1))
+ call assert_equal(#{col: 5, row: 3, endcol: 5, curscol: 5}, screenpos(1, 5, 1))
+ call assert_equal(4, screenpos(1, 6, 1).row)
+ bwipe!
+endfunc
+
+func Test_screenpos_diff()
+ CheckFeature diff
+
+ enew!
+ call setline(1, ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i'])
+ vnew
+ call setline(1, ['a', 'b', 'c', 'g', 'h', 'i'])
+ windo diffthis
+ wincmd w
+ call assert_equal(#{col: 3, row: 7, endcol: 3, curscol: 3}, screenpos(0, 4, 1))
+
+ windo diffoff
+ bwipe!
+ bwipe!
+endfunc
+
func Test_screenpos_number()
rightbelow new
rightbelow 73vsplit
@@ -121,6 +175,9 @@ func Test_screenpos_number()
let pos = screenpos(winid, 1, 66)
call assert_equal(winrow, pos.row)
call assert_equal(wincol + 66 + 3, pos.col)
+
+ call assert_fails('echo screenpos(0, 2, 1)', 'E966:')
+
close
bwipe!
endfunc
@@ -241,8 +298,9 @@ endfunc
" Test for the charcol() function
func Test_charcol()
- call assert_fails('call charcol({})', 'E731:')
- call assert_equal(0, charcol(0))
+ call assert_fails('call charcol({})', 'E1222:')
+ call assert_fails('call charcol(".", [])', 'E1210:')
+ call assert_fails('call charcol(0)', 'E1222:')
new
call setline(1, ['', "01\tà4è678", 'Ⅵ', '012345678'])
@@ -298,6 +356,25 @@ func Test_charcol()
call assert_equal([1, 10, 2, 10, 7], g:InsertCurrentCol)
iunmap <F3>
+ " Test for getting the column number in another window.
+ let winid = win_getid()
+ new
+ call win_execute(winid, 'normal 1G')
+ call assert_equal(1, charcol('.', winid))
+ call assert_equal(1, charcol('$', winid))
+ call win_execute(winid, 'normal 2G6l')
+ call assert_equal(7, charcol('.', winid))
+ call assert_equal(10, charcol('$', winid))
+
+ " calling from another tab page also works
+ tabnew
+ call assert_equal(7, charcol('.', winid))
+ call assert_equal(10, charcol('$', winid))
+ tabclose
+
+ " unknown window ID
+ call assert_equal(0, charcol('.', 10001))
+
%bw!
endfunc
@@ -353,8 +430,14 @@ func Test_setcursorcharpos()
normal G
call setcursorcharpos([1, 1])
call assert_equal([1, 1], [line('.'), col('.')])
+
call setcursorcharpos([2, 7, 0])
call assert_equal([2, 9], [line('.'), col('.')])
+ call setcursorcharpos([0, 7, 0])
+ call assert_equal([2, 9], [line('.'), col('.')])
+ call setcursorcharpos(0, 7, 0)
+ call assert_equal([2, 9], [line('.'), col('.')])
+
call setcursorcharpos(3, 4)
call assert_equal([3, 1], [line('.'), col('.')])
call setcursorcharpos([3, 1])
@@ -373,4 +456,26 @@ func Test_setcursorcharpos()
%bw!
endfunc
+" Test for virtcol2col()
+func Test_virtcol2col()
+ new
+ call setline(1, ["a\tb\tc"])
+ call assert_equal(1, virtcol2col(0, 1, 1))
+ call assert_equal(2, virtcol2col(0, 1, 2))
+ call assert_equal(2, virtcol2col(0, 1, 8))
+ call assert_equal(3, virtcol2col(0, 1, 9))
+ call assert_equal(4, virtcol2col(0, 1, 10))
+ call assert_equal(4, virtcol2col(0, 1, 16))
+ call assert_equal(5, virtcol2col(0, 1, 17))
+ call assert_equal(-1, virtcol2col(10, 1, 1))
+ call assert_equal(-1, virtcol2col(0, 10, 1))
+ call assert_equal(-1, virtcol2col(0, -1, 1))
+ call assert_equal(-1, virtcol2col(0, 1, -1))
+ call assert_equal(5, virtcol2col(0, 1, 20))
+ call assert_fails('echo virtcol2col("0", 1, 20)', 'E1210:')
+ call assert_fails('echo virtcol2col(0, "1", 20)', 'E1210:')
+ call assert_fails('echo virtcol2col(0, 1, "1")', 'E1210:')
+ bw!
+endfunc
+
" vim: shiftwidth=2 sts=2 expandtab
diff --git a/src/nvim/testdir/test_cursorline.vim b/src/nvim/testdir/test_cursorline.vim
index e85e9304a3..70f39a8601 100644
--- a/src/nvim/testdir/test_cursorline.vim
+++ b/src/nvim/testdir/test_cursorline.vim
@@ -3,26 +3,26 @@
source check.vim
source screendump.vim
-function! s:screen_attr(lnum) abort
+func s:screen_attr(lnum) abort
return map(range(1, 8), 'screenattr(a:lnum, v:val)')
-endfunction
+endfunc
-function! s:test_windows(h, w) abort
+func s:test_windows(h, w) abort
call NewWindow(a:h, a:w)
-endfunction
+endfunc
-function! s:close_windows() abort
+func s:close_windows() abort
call CloseWindow()
-endfunction
+endfunc
-function! s:new_hi() abort
+func s:new_hi() abort
redir => save_hi
silent! hi CursorLineNr
redir END
let save_hi = join(split(substitute(save_hi, '\s*xxx\s*', ' ', ''), "\n"), '')
exe 'hi' save_hi 'ctermbg=0 guibg=Black'
return save_hi
-endfunction
+endfunc
func Test_cursorline_highlight1()
let save_hi = s:new_hi()
@@ -319,7 +319,7 @@ func Test_cursorline_cursorbind_horizontal_scroll()
let lines =<< trim END
call setline(1, 'aa bb cc dd ee ff gg hh ii jj kk ll mm' ..
- \ ' nn oo pp qq rr ss tt uu vv ww xx yy zz')
+ \ ' nn oo pp qq rr ss tt uu vv ww xx yy zz')
set nowrap
" The following makes the cursor apparent on the screen dump
set sidescroll=1 cursorcolumn
diff --git a/src/nvim/testdir/test_debugger.vim b/src/nvim/testdir/test_debugger.vim
index e038c0096a..f5177c8fb2 100644
--- a/src/nvim/testdir/test_debugger.vim
+++ b/src/nvim/testdir/test_debugger.vim
@@ -15,14 +15,18 @@ func CheckCWD()
endfunc
command! -nargs=0 -bar CheckCWD call CheckCWD()
+" "options" argument can contain:
+" 'msec' - time to wait for a match
+" 'match' - "pattern" to use "lines" as pattern instead of text
func CheckDbgOutput(buf, lines, options = {})
" Verify the expected output
let lnum = 20 - len(a:lines)
+ let msec = get(a:options, 'msec', 1000)
for l in a:lines
if get(a:options, 'match', 'equal') ==# 'pattern'
- call WaitForAssert({-> assert_match(l, term_getline(a:buf, lnum))}, 200)
+ call WaitForAssert({-> assert_match(l, term_getline(a:buf, lnum))}, msec)
else
- call WaitForAssert({-> assert_equal(l, term_getline(a:buf, lnum))}, 200)
+ call WaitForAssert({-> assert_equal(l, term_getline(a:buf, lnum))}, msec)
endif
let lnum += 1
endfor
@@ -32,7 +36,7 @@ endfunc
" If the expected output argument is supplied, then check for it.
func RunDbgCmd(buf, cmd, ...)
call term_sendkeys(a:buf, a:cmd . "\r")
- call term_wait(a:buf)
+ call term_wait(a:buf, 20)
if a:0 != 0
let options = #{match: 'equal'}
@@ -198,7 +202,7 @@ func Test_Debugger()
" Start a debug session, so that reading the last line from the terminal
" works properly.
- call RunDbgCmd(buf, ':debug echo Foo()')
+ call RunDbgCmd(buf, ':debug echo Foo()', ['cmd: echo Foo()'])
" No breakpoints
call RunDbgCmd(buf, 'breakl', ['No breakpoints defined'])
@@ -814,9 +818,10 @@ func Test_Backtrace_CmdLine()
\ '-S Xtest1.vim -c "debug call GlobalFunction()"',
\ {'wait_for_ruler': 0})
- " Need to wait for the vim-in-terminal to be ready
+ " Need to wait for the vim-in-terminal to be ready.
+ " With valgrind this can take quite long.
call CheckDbgOutput(buf, ['command line',
- \ 'cmd: call GlobalFunction()'])
+ \ 'cmd: call GlobalFunction()'], #{msec: 5000})
" At this point the ontly thing in the stack is the cmdline
call RunDbgCmd(buf, 'backtrace', [
@@ -967,14 +972,14 @@ func Test_debug_backtrace_level()
" set a breakpoint and source file1.vim
let buf = RunVimInTerminal(
\ '-c "breakadd file 1 Xtest1.vim" -S Xtest1.vim',
- \ #{ wait_for_ruler: 0 } )
+ \ #{wait_for_ruler: 0})
call CheckDbgOutput(buf, [
\ 'Breakpoint in "' .. file1 .. '" line 1',
\ 'Entering Debug mode. Type "cont" to continue.',
\ 'command line..script ' .. file1,
\ 'line 1: let s:file1_var = ''file1'''
- \ ])
+ \ ], #{msec: 5000})
" step through the initial declarations
call RunDbgCmd(buf, 'step', [ 'line 2: let g:global_var = ''global''' ] )
@@ -1140,7 +1145,6 @@ func Test_breakpt_endif_intr()
let caught_intr = 0
debuggreedy
call feedkeys(":call F()\<CR>quit\<CR>", "xt")
- call F()
catch /^Vim:Interrupt$/
call assert_match('\.F, line 4', v:throwpoint)
let caught_intr = 1
@@ -1171,7 +1175,6 @@ func Test_breakpt_else_intr()
let caught_intr = 0
debuggreedy
call feedkeys(":call F()\<CR>quit\<CR>", "xt")
- call F()
catch /^Vim:Interrupt$/
call assert_match('\.F, line 4', v:throwpoint)
let caught_intr = 1
@@ -1200,7 +1203,6 @@ func Test_breakpt_endwhile_intr()
let caught_intr = 0
debuggreedy
call feedkeys(":call F()\<CR>quit\<CR>", "xt")
- call F()
catch /^Vim:Interrupt$/
call assert_match('\.F, line 4', v:throwpoint)
let caught_intr = 1
@@ -1212,38 +1214,24 @@ func Test_breakpt_endwhile_intr()
delfunc F
endfunc
-" Test for setting a breakpoint on an :endtry where an exception is pending to
-" be processed and then quit the script. This should generate an interrupt and
-" the thrown exception should be ignored.
-func Test_breakpt_endtry_intr()
- func F()
- try
- let g:Xpath ..= 'a'
- throw "abc"
- endtry
- invalid_command
+" Test for setting a breakpoint on a script local function
+func Test_breakpt_scriptlocal_func()
+ let g:Xpath = ''
+ func s:G()
+ let g:Xpath ..= 'a'
endfunc
- let g:Xpath = ''
- breakadd func 4 F
- try
- let caught_intr = 0
- let caught_abc = 0
- debuggreedy
- call feedkeys(":call F()\<CR>quit\<CR>", "xt")
- call F()
- catch /abc/
- let caught_abc = 1
- catch /^Vim:Interrupt$/
- call assert_match('\.F, line 4', v:throwpoint)
- let caught_intr = 1
- endtry
+ let funcname = expand("<SID>") .. "G"
+ exe "breakadd func 1 " .. funcname
+ debuggreedy
+ redir => output
+ call feedkeys(":call " .. funcname .. "()\<CR>c\<CR>", "xt")
+ redir END
0debuggreedy
- call assert_equal(1, caught_intr)
- call assert_equal(0, caught_abc)
+ call assert_match('Breakpoint in "' .. funcname .. '" line 1', output)
call assert_equal('a', g:Xpath)
breakdel *
- delfunc F
+ exe "delfunc " .. funcname
endfunc
" vim: shiftwidth=2 sts=2 expandtab
diff --git a/src/nvim/testdir/test_delete.vim b/src/nvim/testdir/test_delete.vim
index b23a3bd025..6b49f153c6 100644
--- a/src/nvim/testdir/test_delete.vim
+++ b/src/nvim/testdir/test_delete.vim
@@ -1,5 +1,7 @@
" Test for delete().
+source check.vim
+
func Test_file_delete()
split Xfile
call setline(1, ['a', 'b'])
@@ -41,9 +43,7 @@ func Test_recursive_delete()
endfunc
func Test_symlink_delete()
- if !has('unix')
- return
- endif
+ CheckUnix
split Xfile
call setline(1, ['a', 'b'])
wq
@@ -56,9 +56,7 @@ func Test_symlink_delete()
endfunc
func Test_symlink_dir_delete()
- if !has('unix')
- return
- endif
+ CheckUnix
call mkdir('Xdir1')
silent !ln -s Xdir1 Xlink
call assert_true(isdirectory('Xdir1'))
@@ -70,9 +68,7 @@ func Test_symlink_dir_delete()
endfunc
func Test_symlink_recursive_delete()
- if !has('unix')
- return
- endif
+ CheckUnix
call mkdir('Xdir3')
call mkdir('Xdir3/subdir')
call mkdir('Xdir4')
diff --git a/src/nvim/testdir/test_diffmode.vim b/src/nvim/testdir/test_diffmode.vim
index ea453b7174..0049398776 100644
--- a/src/nvim/testdir/test_diffmode.vim
+++ b/src/nvim/testdir/test_diffmode.vim
@@ -1,4 +1,5 @@
" Tests for diff mode
+
source shared.vim
source screendump.vim
source check.vim
@@ -243,6 +244,36 @@ func Test_diffput_two()
bwipe! b
endfunc
+" Test for :diffget/:diffput with a range that is inside a diff chunk
+func Test_diffget_diffput_range()
+ call setline(1, range(1, 10))
+ new
+ call setline(1, range(11, 20))
+ windo diffthis
+ 3,5diffget
+ call assert_equal(['13', '14', '15'], getline(3, 5))
+ call setline(1, range(1, 10))
+ 4,8diffput
+ wincmd p
+ call assert_equal(['13', '4', '5', '6', '7', '8', '19'], getline(3, 9))
+ %bw!
+endfunc
+
+" Test for :diffget/:diffput with an empty buffer and a non-empty buffer
+func Test_diffget_diffput_empty_buffer()
+ %d _
+ new
+ call setline(1, 'one')
+ windo diffthis
+ diffget
+ call assert_equal(['one'], getline(1, '$'))
+ %d _
+ diffput
+ wincmd p
+ call assert_equal([''], getline(1, '$'))
+ %bw!
+endfunc
+
" :diffput and :diffget completes names of buffers which
" are in diff mode and which are different then current buffer.
" No completion when the current window is not in diff mode.
@@ -621,9 +652,7 @@ func Test_diff_move_to()
endfunc
func Test_diffexpr()
- if !executable('diff')
- return
- endif
+ CheckExecutable diff
func DiffExpr()
" Prepend some text to check diff type detection
@@ -647,17 +676,31 @@ func Test_diffexpr()
call assert_equal(normattr, screenattr(1, 1))
call assert_equal(normattr, screenattr(2, 1))
call assert_notequal(normattr, screenattr(3, 1))
+ diffoff!
+ " Try using an non-existing function for 'diffexpr'.
+ set diffexpr=NewDiffFunc()
+ call assert_fails('windo diffthis', ['E117:', 'E97:'])
diffoff!
+
+ " Using a script-local function
+ func s:NewDiffExpr()
+ endfunc
+ set diffexpr=s:NewDiffExpr()
+ call assert_equal(expand('<SID>') .. 'NewDiffExpr()', &diffexpr)
+ set diffexpr=<SID>NewDiffExpr()
+ call assert_equal(expand('<SID>') .. 'NewDiffExpr()', &diffexpr)
+
%bwipe!
set diffexpr& diffopt&
+ delfunc DiffExpr
+ delfunc s:NewDiffExpr
endfunc
func Test_diffpatch()
" The patch program on MS-Windows may fail or hang.
- if !executable('patch') || !has('unix')
- return
- endif
+ CheckExecutable patch
+ CheckUnix
new
insert
***************
@@ -744,17 +787,13 @@ func Test_diff_hlID()
call diff_hlID(-1, 1)->synIDattr("name")->assert_equal("")
- call assert_equal(diff_hlID(1, 1), hlID("DiffChange"))
call diff_hlID(1, 1)->synIDattr("name")->assert_equal("DiffChange")
- call assert_equal(diff_hlID(1, 2), hlID("DiffText"))
call diff_hlID(1, 2)->synIDattr("name")->assert_equal("DiffText")
call diff_hlID(2, 1)->synIDattr("name")->assert_equal("")
- call assert_equal(diff_hlID(3, 1), hlID("DiffAdd"))
call diff_hlID(3, 1)->synIDattr("name")->assert_equal("DiffAdd")
- call diff_hlID(4, 1)->synIDattr("name")->assert_equal("")
+ eval 4->diff_hlID(1)->synIDattr("name")->assert_equal("")
wincmd w
- call assert_equal(diff_hlID(1, 1), hlID("DiffChange"))
call assert_equal(synIDattr(diff_hlID(1, 1), "name"), "DiffChange")
call assert_equal(synIDattr(diff_hlID(2, 1), "name"), "")
call assert_equal(synIDattr(diff_hlID(3, 1), "name"), "")
@@ -1202,6 +1241,42 @@ func Test_diff_maintains_change_mark()
delfunc DiffMaintainsChangeMark
endfunc
+" Test for 'patchexpr'
+func Test_patchexpr()
+ let g:patch_args = []
+ func TPatch()
+ call add(g:patch_args, readfile(v:fname_in))
+ call add(g:patch_args, readfile(v:fname_diff))
+ call writefile(['output file'], v:fname_out)
+ endfunc
+ set patchexpr=TPatch()
+
+ call writefile(['input file'], 'Xinput')
+ call writefile(['diff file'], 'Xdiff')
+ %bwipe!
+ edit Xinput
+ diffpatch Xdiff
+ call assert_equal('output file', getline(1))
+ call assert_equal('Xinput.new', bufname())
+ call assert_equal(2, winnr('$'))
+ call assert_true(&diff)
+
+ " Using a script-local function
+ func s:NewPatchExpr()
+ endfunc
+ set patchexpr=s:NewPatchExpr()
+ call assert_equal(expand('<SID>') .. 'NewPatchExpr()', &patchexpr)
+ set patchexpr=<SID>NewPatchExpr()
+ call assert_equal(expand('<SID>') .. 'NewPatchExpr()', &patchexpr)
+
+ call delete('Xinput')
+ call delete('Xdiff')
+ set patchexpr&
+ delfunc TPatch
+ delfunc s:NewPatchExpr
+ %bwipe!
+endfunc
+
func Test_diff_rnu()
CheckScreendump
@@ -1295,6 +1370,89 @@ func Test_diff_filler_cursorcolumn()
call delete('Xtest_diff_cuc')
endfunc
+" Test for adding/removing lines inside diff chunks, between diff chunks
+" and before diff chunks
+func Test_diff_modify_chunks()
+ enew!
+ let w2_id = win_getid()
+ call setline(1, ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i'])
+ new
+ let w1_id = win_getid()
+ call setline(1, ['a', '2', '3', 'd', 'e', 'f', '7', '8', 'i'])
+ windo diffthis
+
+ " remove a line between two diff chunks and create a new diff chunk
+ call win_gotoid(w2_id)
+ 5d
+ call win_gotoid(w1_id)
+ call diff_hlID(5, 1)->synIDattr('name')->assert_equal('DiffAdd')
+
+ " add a line between two diff chunks
+ call win_gotoid(w2_id)
+ normal! 4Goe
+ call win_gotoid(w1_id)
+ call diff_hlID(4, 1)->synIDattr('name')->assert_equal('')
+ call diff_hlID(5, 1)->synIDattr('name')->assert_equal('')
+
+ " remove all the lines in a diff chunk.
+ call win_gotoid(w2_id)
+ 7,8d
+ call win_gotoid(w1_id)
+ let hl = range(1, 9)->map({_, lnum -> diff_hlID(lnum, 1)->synIDattr('name')})
+ call assert_equal(['', 'DiffText', 'DiffText', '', '', '', 'DiffAdd',
+ \ 'DiffAdd', ''], hl)
+
+ " remove lines from one diff chunk to just before the next diff chunk
+ call win_gotoid(w2_id)
+ call setline(1, ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i'])
+ 2,6d
+ call win_gotoid(w1_id)
+ let hl = range(1, 9)->map({_, lnum -> diff_hlID(lnum, 1)->synIDattr('name')})
+ call assert_equal(['', 'DiffText', 'DiffText', 'DiffAdd', 'DiffAdd',
+ \ 'DiffAdd', 'DiffAdd', 'DiffAdd', ''], hl)
+
+ " remove lines just before the top of a diff chunk
+ call win_gotoid(w2_id)
+ call setline(1, ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i'])
+ 5,6d
+ call win_gotoid(w1_id)
+ let hl = range(1, 9)->map({_, lnum -> diff_hlID(lnum, 1)->synIDattr('name')})
+ call assert_equal(['', 'DiffText', 'DiffText', '', 'DiffText', 'DiffText',
+ \ 'DiffAdd', 'DiffAdd', ''], hl)
+
+ " remove line after the end of a diff chunk
+ call win_gotoid(w2_id)
+ call setline(1, ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i'])
+ 4d
+ call win_gotoid(w1_id)
+ let hl = range(1, 9)->map({_, lnum -> diff_hlID(lnum, 1)->synIDattr('name')})
+ call assert_equal(['', 'DiffText', 'DiffText', 'DiffAdd', '', '', 'DiffText',
+ \ 'DiffText', ''], hl)
+
+ " remove lines starting from the end of one diff chunk and ending inside
+ " another diff chunk
+ call win_gotoid(w2_id)
+ call setline(1, ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i'])
+ 4,7d
+ call win_gotoid(w1_id)
+ let hl = range(1, 9)->map({_, lnum -> diff_hlID(lnum, 1)->synIDattr('name')})
+ call assert_equal(['', 'DiffText', 'DiffText', 'DiffText', 'DiffAdd',
+ \ 'DiffAdd', 'DiffAdd', 'DiffAdd', ''], hl)
+
+ " removing the only remaining diff chunk should make the files equal
+ call win_gotoid(w2_id)
+ call setline(1, ['a', '2', '3', 'x', 'd', 'e', 'f', 'x', '7', '8', 'i'])
+ 8d
+ let hl = range(1, 10)->map({_, lnum -> diff_hlID(lnum, 1)->synIDattr('name')})
+ call assert_equal(['', '', '', 'DiffAdd', '', '', '', '', '', ''], hl)
+ call win_gotoid(w2_id)
+ 4d
+ call win_gotoid(w1_id)
+ let hl = range(1, 9)->map({_, lnum -> diff_hlID(lnum, 1)->synIDattr('name')})
+ call assert_equal(['', '', '', '', '', '', '', '', ''], hl)
+
+ %bw!
+endfunc
func Test_diff_binary()
CheckScreendump
diff --git a/src/nvim/testdir/test_digraph.vim b/src/nvim/testdir/test_digraph.vim
index acc34e5e7c..f08dff8605 100644
--- a/src/nvim/testdir/test_digraph.vim
+++ b/src/nvim/testdir/test_digraph.vim
@@ -211,6 +211,8 @@ func Test_digraphs()
call Put_Dig("00")
call Put_Dig("el")
call assert_equal(['␀', 'ü', '∞', 'l'], getline(line('.')-3,line('.')))
+ call assert_fails('exe "digraph a\<Esc> 100"', 'E104:')
+ call assert_fails('exe "digraph \<Esc>a 100"', 'E104:')
call assert_fails('digraph xy z', 'E39:')
call assert_fails('digraph x', 'E1214:')
bw!
@@ -491,6 +493,17 @@ func Test_show_digraph_cp1251()
bwipe!
endfunc
+" Test for error in a keymap file
+func Test_loadkeymap_error()
+ if !has('keymap')
+ return
+ endif
+ call assert_fails('loadkeymap', 'E105:')
+ call writefile(['loadkeymap', 'a'], 'Xkeymap')
+ call assert_fails('source Xkeymap', 'E791:')
+ call delete('Xkeymap')
+endfunc
+
" Test for the characters displayed on the screen when entering a digraph
func Test_entering_digraph()
CheckRunVimInTerminal
diff --git a/src/nvim/testdir/test_display.vim b/src/nvim/testdir/test_display.vim
index 6938abbc28..b642f39c9f 100644
--- a/src/nvim/testdir/test_display.vim
+++ b/src/nvim/testdir/test_display.vim
@@ -195,8 +195,6 @@ func Test_edit_long_file_name()
call VerifyScreenDump(buf, 'Test_long_file_name_1', {})
- call term_sendkeys(buf, ":q\<cr>")
-
" clean up
call StopVimInTerminal(buf)
call delete(longName)
@@ -228,7 +226,6 @@ endfunc
" Test for scrolling that modifies buffer during visual block
func Test_visual_block_scroll()
- " See test/functional/legacy/visual_mode_spec.lua
CheckScreendump
let lines =<< trim END
@@ -239,7 +236,7 @@ func Test_visual_block_scroll()
END
let filename = 'Xvisualblockmodifiedscroll'
- call writefile(lines, filename)
+ call writefile(lines, filename, 'D')
let buf = RunVimInTerminal('-S '.filename, #{rows: 7})
call term_sendkeys(buf, "V\<C-D>\<C-D>")
@@ -247,11 +244,40 @@ func Test_visual_block_scroll()
call VerifyScreenDump(buf, 'Test_display_visual_block_scroll', {})
call StopVimInTerminal(buf)
- call delete(filename)
+endfunc
+
+" Test for clearing paren highlight when switching buffers
+func Test_matchparen_clear_highlight()
+ CheckScreendump
+
+ let lines =<< trim END
+ source $VIMRUNTIME/plugin/matchparen.vim
+ set hidden
+ call setline(1, ['()'])
+ normal 0
+
+ func OtherBuffer()
+ enew
+ exe "normal iaa\<Esc>0"
+ endfunc
+ END
+ call writefile(lines, 'XMatchparenClear', 'D')
+ let buf = RunVimInTerminal('-S XMatchparenClear', #{rows: 5})
+ call VerifyScreenDump(buf, 'Test_matchparen_clear_highlight_1', {})
+
+ call term_sendkeys(buf, ":call OtherBuffer()\<CR>:\<Esc>")
+ call VerifyScreenDump(buf, 'Test_matchparen_clear_highlight_2', {})
+
+ call term_sendkeys(buf, "\<C-^>:\<Esc>")
+ call VerifyScreenDump(buf, 'Test_matchparen_clear_highlight_1', {})
+
+ call term_sendkeys(buf, "\<C-^>:\<Esc>")
+ call VerifyScreenDump(buf, 'Test_matchparen_clear_highlight_2', {})
+
+ call StopVimInTerminal(buf)
endfunc
func Test_display_scroll_at_topline()
- " See test/functional/legacy/display_spec.lua
CheckScreendump
let buf = RunVimInTerminal('', #{cols: 20})
@@ -309,6 +335,88 @@ func Test_eob_fillchars()
close
endfunc
+" Test for 'foldopen', 'foldclose' and 'foldsep' in 'fillchars'
+func Test_fold_fillchars()
+ new
+ set fdc=2 foldenable foldmethod=manual
+ call setline(1, ['one', 'two', 'three', 'four', 'five'])
+ 2,4fold
+ " First check for the default setting for a closed fold
+ let lines = ScreenLines([1, 3], 8)
+ let expected = [
+ \ ' one ',
+ \ '+ +-- 3',
+ \ ' five '
+ \ ]
+ call assert_equal(expected, lines)
+ normal 2Gzo
+ " check the characters for an open fold
+ let lines = ScreenLines([1, 5], 8)
+ let expected = [
+ \ ' one ',
+ \ '- two ',
+ \ '| three ',
+ \ '| four ',
+ \ ' five '
+ \ ]
+ call assert_equal(expected, lines)
+
+ " change the setting
+ set fillchars=vert:\|,fold:-,eob:~,foldopen:[,foldclose:],foldsep:-
+
+ " check the characters for an open fold
+ let lines = ScreenLines([1, 5], 8)
+ let expected = [
+ \ ' one ',
+ \ '[ two ',
+ \ '- three ',
+ \ '- four ',
+ \ ' five '
+ \ ]
+ call assert_equal(expected, lines)
+
+ " check the characters for a closed fold
+ normal 2Gzc
+ let lines = ScreenLines([1, 3], 8)
+ let expected = [
+ \ ' one ',
+ \ '] +-- 3',
+ \ ' five '
+ \ ]
+ call assert_equal(expected, lines)
+
+ %bw!
+ set fillchars& fdc& foldmethod& foldenable&
+endfunc
+
+func Test_local_fillchars()
+ CheckScreendump
+
+ let lines =<< trim END
+ call setline(1, ['window 1']->repeat(3))
+ setlocal fillchars=stl:1,stlnc:a,vert:=,eob:x
+ vnew
+ call setline(1, ['window 2']->repeat(3))
+ setlocal fillchars=stl:2,stlnc:b,vert:+,eob:y
+ new
+ wincmd J
+ call setline(1, ['window 3']->repeat(3))
+ setlocal fillchars=stl:3,stlnc:c,vert:<,eob:z
+ vnew
+ call setline(1, ['window 4']->repeat(3))
+ setlocal fillchars=stl:4,stlnc:d,vert:>,eob:o
+ END
+ call writefile(lines, 'Xdisplayfillchars')
+ let buf = RunVimInTerminal('-S Xdisplayfillchars', #{rows: 12})
+ call VerifyScreenDump(buf, 'Test_display_fillchars_1', {})
+
+ call term_sendkeys(buf, ":wincmd k\r")
+ call VerifyScreenDump(buf, 'Test_display_fillchars_2', {})
+
+ call StopVimInTerminal(buf)
+ call delete('Xdisplayfillchars')
+endfunc
+
func Test_display_linebreak_breakat()
new
vert resize 25
@@ -325,30 +433,49 @@ func Test_display_linebreak_breakat()
let &breakat=_breakat
endfunc
-func Test_display_lastline()
- CheckScreendump
-
+func Run_Test_display_lastline(euro)
let lines =<< trim END
- call setline(1, ['aaa', 'b'->repeat(100)])
+ call setline(1, ['aaa', 'b'->repeat(200)])
set display=truncate
+
vsplit
100wincmd <
END
- call writefile(lines, 'XdispLastline')
+ if a:euro != ''
+ let lines[2] = 'set fillchars=vert:\|,lastline:€'
+ endif
+ call writefile(lines, 'XdispLastline', 'D')
let buf = RunVimInTerminal('-S XdispLastline', #{rows: 10})
- call VerifyScreenDump(buf, 'Test_display_lastline_1', {})
+ call VerifyScreenDump(buf, $'Test_display_lastline_{a:euro}1', {})
call term_sendkeys(buf, ":set display=lastline\<CR>")
- call VerifyScreenDump(buf, 'Test_display_lastline_2', {})
+ call VerifyScreenDump(buf, $'Test_display_lastline_{a:euro}2', {})
call term_sendkeys(buf, ":100wincmd >\<CR>")
- call VerifyScreenDump(buf, 'Test_display_lastline_3', {})
+ call VerifyScreenDump(buf, $'Test_display_lastline_{a:euro}3', {})
call term_sendkeys(buf, ":set display=truncate\<CR>")
- call VerifyScreenDump(buf, 'Test_display_lastline_4', {})
+ call VerifyScreenDump(buf, $'Test_display_lastline_{a:euro}4', {})
+
+ call term_sendkeys(buf, ":close\<CR>")
+ call term_sendkeys(buf, ":3split\<CR>")
+ call VerifyScreenDump(buf, $'Test_display_lastline_{a:euro}5', {})
+
+ call term_sendkeys(buf, ":close\<CR>")
+ call term_sendkeys(buf, ":2vsplit\<CR>")
+ call VerifyScreenDump(buf, $'Test_display_lastline_{a:euro}6', {})
call StopVimInTerminal(buf)
- call delete('XdispLastline')
+endfunc
+
+func Test_display_lastline()
+ CheckScreendump
+
+ call Run_Test_display_lastline('')
+ call Run_Test_display_lastline('euro_')
+
+ call assert_fails(':set fillchars=lastline:', 'E474:')
+ call assert_fails(':set fillchars=lastline:〇', 'E474:')
endfunc
diff --git a/src/nvim/testdir/test_edit.vim b/src/nvim/testdir/test_edit.vim
index e26bbdc5be..fd54f77ccb 100644
--- a/src/nvim/testdir/test_edit.vim
+++ b/src/nvim/testdir/test_edit.vim
@@ -330,6 +330,16 @@ func Test_edit_11_indentexpr()
set cinkeys&vim indentkeys&vim
set nocindent indentexpr=
delfu Do_Indent
+
+ " Using a script-local function
+ func s:NewIndentExpr()
+ endfunc
+ set indentexpr=s:NewIndentExpr()
+ call assert_equal(expand('<SID>') .. 'NewIndentExpr()', &indentexpr)
+ set indentexpr=<SID>NewIndentExpr()
+ call assert_equal(expand('<SID>') .. 'NewIndentExpr()', &indentexpr)
+ set indentexpr&
+
bw!
endfunc
@@ -713,23 +723,32 @@ endfunc
func Test_edit_CTRL_N()
" Check keyword completion
- new
- set complete=.
- call setline(1, ['INFER', 'loWER', '', '', ])
- call cursor(3, 1)
- call feedkeys("Ai\<c-n>\<cr>\<esc>", "tnix")
- call feedkeys("ILO\<c-n>\<cr>\<esc>", 'tnix')
- call assert_equal(['INFER', 'loWER', 'i', 'LO', '', ''], getline(1, '$'))
- %d
- call setline(1, ['INFER', 'loWER', '', '', ])
- call cursor(3, 1)
- set ignorecase infercase
- call feedkeys("Ii\<c-n>\<cr>\<esc>", "tnix")
- call feedkeys("ILO\<c-n>\<cr>\<esc>", 'tnix')
- call assert_equal(['INFER', 'loWER', 'infer', 'LOWER', '', ''], getline(1, '$'))
-
- set noignorecase noinfercase complete&
- bw!
+ " for e in ['latin1', 'utf-8']
+ for e in ['utf-8']
+ exe 'set encoding=' .. e
+ new
+ set complete=.
+ call setline(1, ['INFER', 'loWER', '', '', ])
+ call cursor(3, 1)
+ call feedkeys("Ai\<c-n>\<cr>\<esc>", "tnix")
+ call feedkeys("ILO\<c-n>\<cr>\<esc>", 'tnix')
+ call assert_equal(['INFER', 'loWER', 'i', 'LO', '', ''], getline(1, '$'), e)
+ %d
+ call setline(1, ['INFER', 'loWER', '', '', ])
+ call cursor(3, 1)
+ set ignorecase infercase
+ call feedkeys("Ii\<c-n>\<cr>\<esc>", "tnix")
+ call feedkeys("ILO\<c-n>\<cr>\<esc>", 'tnix')
+ call assert_equal(['INFER', 'loWER', 'infer', 'LOWER', '', ''], getline(1, '$'), e)
+ set noignorecase noinfercase
+ %d
+ call setline(1, ['one word', 'two word'])
+ exe "normal! Goo\<C-P>\<C-X>\<C-P>"
+ call assert_equal('one word', getline(3))
+ %d
+ set complete&
+ bw!
+ endfor
endfunc
func Test_edit_CTRL_O()
@@ -893,6 +912,24 @@ func Test_edit_CTRL_T()
bw!
endfunc
+" Test thesaurus completion with different encodings
+func Test_thesaurus_complete_with_encoding()
+ call writefile(['angry furious mad enraged'], 'Xthesaurus')
+ set thesaurus=Xthesaurus
+ " for e in ['latin1', 'utf-8']
+ for e in ['utf-8']
+ exe 'set encoding=' .. e
+ new
+ call setline(1, 'mad')
+ call cursor(1, 1)
+ call feedkeys("A\<c-x>\<c-t>\<cr>\<esc>", 'tnix')
+ call assert_equal(['mad', ''], getline(1, '$'))
+ bw!
+ endfor
+ set thesaurus=
+ call delete('Xthesaurus')
+endfunc
+
" Test 'thesaurusfunc'
func MyThesaurus(findstart, base)
let mythesaurus = [
@@ -1201,15 +1238,11 @@ func Test_edit_MOUSE()
call assert_equal(24, line('w0'))
call assert_equal([0, 24, 2, 0], getpos('.'))
- " call test_setmouse(4, 3)
- call nvim_input_mouse('left', 'press', '', 0, 3, 2) " set mouse position
- call getchar() " discard mouse event but keep mouse position
+ call Ntest_setmouse(4, 3)
call feedkeys("A\<LeftMouse>\<esc>", 'tnix')
call assert_equal([0, 27, 2, 0], getpos('.'))
set mousemodel=extend
- " call test_setmouse(5, 3)
- call nvim_input_mouse('right', 'press', '', 0, 4, 2) " set mouse position
- call getchar() " discard mouse event but keep mouse position
+ call Ntest_setmouse(5, 3)
call feedkeys("A\<RightMouse>\<esc>\<esc>", 'tnix')
call assert_equal([0, 28, 2, 0], getpos('.'))
set mousemodel&
@@ -1410,9 +1443,7 @@ endfunc
func Test_edit_rightleft()
" Cursor in rightleft mode moves differently
- if !exists("+rightleft")
- return
- endif
+ CheckFeature rightleft
call NewWindow(10, 20)
call setline(1, ['abc', 'def', 'ghi'])
call cursor(1, 2)
@@ -1457,6 +1488,13 @@ func Test_edit_rightleft()
\" ihg",
\" ~"]
call assert_equal(join(expect, "\n"), join(lines, "\n"))
+ %d _
+ " call test_override('redraw_flag', 1)
+ " call test_override('char_avail', 1)
+ call feedkeys("a\<C-V>x41", "xt")
+ redraw!
+ call assert_equal(repeat(' ', 19) .. 'A', Screenline(1))
+ " call test_override('ALL', 0)
set norightleft
bw!
endfunc
@@ -1701,40 +1739,6 @@ func Test_edit_illegal_filename()
close!
endfunc
-" Test for inserting text in a line with only spaces ('H' flag in 'cpoptions')
-func Test_edit_cpo_H()
- throw 'Skipped: Nvim does not support cpoptions flag "H"'
- new
- call setline(1, ' ')
- normal! Ia
- call assert_equal(' a', getline(1))
- set cpo+=H
- call setline(1, ' ')
- normal! Ia
- call assert_equal(' a ', getline(1))
- set cpo-=H
- close!
-endfunc
-
-" Test for inserting tab in virtual replace mode ('L' flag in 'cpoptions')
-func Test_edit_cpo_L()
- new
- call setline(1, 'abcdefghijklmnopqr')
- exe "normal 0gR\<Tab>"
- call assert_equal("\<Tab>ijklmnopqr", getline(1))
- set cpo+=L
- set list
- call setline(1, 'abcdefghijklmnopqr')
- exe "normal 0gR\<Tab>"
- call assert_equal("\<Tab>cdefghijklmnopqr", getline(1))
- set nolist
- call setline(1, 'abcdefghijklmnopqr')
- exe "normal 0gR\<Tab>"
- call assert_equal("\<Tab>ijklmnopqr", getline(1))
- set cpo-=L
- %bw!
-endfunc
-
" Test for editing a directory
func Test_edit_is_a_directory()
CheckEnglish
@@ -1842,7 +1846,8 @@ endfunc
" Test for editing a file without read permission
func Test_edit_file_no_read_perm()
CheckUnix
- CheckNotBSD
+ CheckNotRoot
+
call writefile(['one', 'two'], 'Xfile')
call setfperm('Xfile', '-w-------')
new
@@ -1868,17 +1873,117 @@ func Test_edit_insertmode_ex_edit()
call writefile(lines, 'Xtest_edit_insertmode_ex_edit')
let buf = RunVimInTerminal('-S Xtest_edit_insertmode_ex_edit', #{rows: 6})
- call TermWait(buf, 50)
- call assert_match('^-- INSERT --\s*$', term_getline(buf, 6))
+ call WaitForAssert({-> assert_match('^-- INSERT --\s*$', term_getline(buf, 6))})
call term_sendkeys(buf, "\<C-B>\<C-L>")
- call TermWait(buf, 50)
- call assert_notmatch('^-- INSERT --\s*$', term_getline(buf, 6))
+ call WaitForAssert({-> assert_notmatch('^-- INSERT --\s*$', term_getline(buf, 6))})
" clean up
call StopVimInTerminal(buf)
call delete('Xtest_edit_insertmode_ex_edit')
endfunc
+" Pressing escape in 'insertmode' should beep
+" FIXME: Execute this later, when using valgrind it makes the next test
+" Test_edit_insertmode_ex_edit() fail.
+func Test_z_edit_insertmode_esc_beeps()
+ new
+ " set insertmode
+ " call assert_beeps("call feedkeys(\"one\<Esc>\", 'xt')")
+ set insertmode&
+ " unsupported "CTRL-G l" command should beep in insert mode.
+ call assert_beeps("normal i\<C-G>l")
+ bwipe!
+endfunc
+
+" Test for 'hkmap' and 'hkmapp'
+func Test_edit_hkmap()
+ CheckFeature rightleft
+ if has('win32') && !has('gui')
+ " Test fails on the MS-Windows terminal version
+ return
+ endif
+ new
+
+ set revins hkmap
+ let str = 'abcdefghijklmnopqrstuvwxyz'
+ let str ..= 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'
+ let str ..= '`/'',.;'
+ call feedkeys('i' .. str, 'xt')
+ let expected = "óõú,.;"
+ let expected ..= "ZYXWVUTSRQPONMLKJIHGFEDCBA"
+ let expected ..= "æèñ'äåàãø/ôíîöêìçïéòë÷âáðù"
+ call assert_equal(expected, getline(1))
+
+ %d
+ set revins hkmap hkmapp
+ let str = 'abcdefghijklmnopqrstuvwxyz'
+ let str ..= 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'
+ call feedkeys('i' .. str, 'xt')
+ let expected = "õYXWVUTSRQóOïíLKJIHGFEDêBA"
+ let expected ..= "öòXùåèúæø'ôñðîì÷çéäâóǟãëáà"
+ call assert_equal(expected, getline(1))
+
+ set revins& hkmap& hkmapp&
+ close!
+endfunc
+
+" Test for 'allowrevins' and using CTRL-_ in insert mode
+func Test_edit_allowrevins()
+ CheckFeature rightleft
+ new
+ set allowrevins
+ call feedkeys("iABC\<C-_>DEF\<C-_>GHI", 'xt')
+ call assert_equal('ABCFEDGHI', getline(1))
+ set allowrevins&
+ close!
+endfunc
+
+" Test for inserting a register in insert mode using CTRL-R
+func Test_edit_insert_reg()
+ throw 'Skipped: use test/functional/legacy/edit_spec.lua'
+ new
+ let g:Line = ''
+ func SaveFirstLine()
+ let g:Line = Screenline(1)
+ return 'r'
+ endfunc
+ inoremap <expr> <buffer> <F2> SaveFirstLine()
+ call test_override('redraw_flag', 1)
+ call test_override('char_avail', 1)
+ let @r = 'sample'
+ call feedkeys("a\<C-R>=SaveFirstLine()\<CR>", "xt")
+ call assert_equal('"', g:Line)
+ call test_override('ALL', 0)
+ close!
+endfunc
+
+" When a character is inserted at the last position of the last line in a
+" window, the window contents should be scrolled one line up. If the top line
+" is part of a fold, then the entire fold should be scrolled up.
+func Test_edit_lastline_scroll()
+ new
+ let h = winheight(0)
+ let lines = ['one', 'two', 'three']
+ let lines += repeat(['vim'], h - 4)
+ call setline(1, lines)
+ call setline(h, repeat('x', winwidth(0) - 1))
+ call feedkeys("GAx", 'xt')
+ redraw!
+ call assert_equal(h - 1, winline())
+ call assert_equal(2, line('w0'))
+
+ " scroll with a fold
+ 1,2fold
+ normal gg
+ call setline(h + 1, repeat('x', winwidth(0) - 1))
+ call feedkeys("GAx", 'xt')
+ redraw!
+ call assert_equal(h - 1, winline())
+ call assert_equal(3, line('w0'))
+
+ close!
+endfunc
+
func Test_edit_browse()
" in the GUI this opens a file picker, we only test the terminal behavior
CheckNotGui
@@ -1904,4 +2009,76 @@ func Test_read_invalid()
set encoding=utf-8
endfunc
+" Test for the 'revins' option
+func Test_edit_revins()
+ CheckFeature rightleft
+ new
+ set revins
+ exe "normal! ione\ttwo three"
+ call assert_equal("eerht owt\teno", getline(1))
+ call setline(1, "one\ttwo three")
+ normal! gg$bi a
+ call assert_equal("one\ttwo a three", getline(1))
+ exe "normal! $bi\<BS>\<BS>"
+ call assert_equal("one\ttwo a ree", getline(1))
+ exe "normal! 0wi\<C-W>"
+ call assert_equal("one\t a ree", getline(1))
+ exe "normal! 0wi\<C-U>"
+ call assert_equal("one\t ", getline(1))
+ " newline in insert mode starts at the end of the line
+ call setline(1, 'one two three')
+ exe "normal! wi\nfour"
+ call assert_equal(['one two three', 'ruof'], getline(1, '$'))
+ set revins&
+ bw!
+endfunc
+
+" Test for getting the character of the line below after "p"
+func Test_edit_put_CTRL_E()
+ " set encoding=latin1
+ new
+ let @" = ''
+ sil! norm orggRx
+ sil! norm pr
+ call assert_equal(['r', 'r'], getline(1, 2))
+ bwipe!
+ set encoding=utf-8
+endfunc
+
+" Test toggling of input method. See :help i_CTRL-^
+func Test_edit_CTRL_hat()
+ CheckFeature xim
+
+ " FIXME: test fails with Motif GUI.
+ " test also fails when running in the GUI.
+ CheckFeature gui_gtk
+ CheckNotGui
+
+ new
+
+ call assert_equal(0, &iminsert)
+ call feedkeys("i\<C-^>", 'xt')
+ call assert_equal(2, &iminsert)
+ call feedkeys("i\<C-^>", 'xt')
+ call assert_equal(0, &iminsert)
+
+ bwipe!
+endfunc
+
+" Weird long file name was going over the end of NameBuff
+func Test_edit_overlong_file_name()
+ CheckUnix
+
+ file 0000000000000000000000000000
+ file %%%%%%%%%%%%%%%%%%%%%%%%%%
+ file %%%%%%
+ set readonly
+ set ls=2
+
+ redraw!
+ set noreadonly ls&
+ bwipe!
+endfunc
+
+
" vim: shiftwidth=2 sts=2 expandtab
diff --git a/src/nvim/testdir/test_escaped_glob.vim b/src/nvim/testdir/test_escaped_glob.vim
index 1a4fd8bdab..9f53c76a2c 100644
--- a/src/nvim/testdir/test_escaped_glob.vim
+++ b/src/nvim/testdir/test_escaped_glob.vim
@@ -1,7 +1,7 @@
" Test whether glob()/globpath() return correct results with certain escaped
" characters.
-function SetUp()
+func SetUp()
" consistent sorting of file names
set nofileignorecase
endfunction
diff --git a/src/nvim/testdir/test_eval_stuff.vim b/src/nvim/testdir/test_eval_stuff.vim
index eff1376d3c..46482c34a1 100644
--- a/src/nvim/testdir/test_eval_stuff.vim
+++ b/src/nvim/testdir/test_eval_stuff.vim
@@ -1,5 +1,8 @@
" Tests for various eval things.
+source view_util.vim
+source shared.vim
+
function s:foo() abort
try
return [] == 0
@@ -17,13 +20,8 @@ func Test_nocatch_restore_silent_emsg()
throw 1
catch
endtry
- echoerr 'wrong'
- let c1 = nr2char(screenchar(&lines, 1))
- let c2 = nr2char(screenchar(&lines, 2))
- let c3 = nr2char(screenchar(&lines, 3))
- let c4 = nr2char(screenchar(&lines, 4))
- let c5 = nr2char(screenchar(&lines, 5))
- call assert_equal('wrong', c1 . c2 . c3 . c4 . c5)
+ echoerr 'wrong again'
+ call assert_equal('wrong again', ScreenLine(&lines))
endfunc
func Test_mkdir_p()
@@ -87,22 +85,54 @@ func Test_for_over_null_string()
let &enc = save_enc
endfunc
+func Test_for_invalid_line_count()
+ let lines =<< trim END
+ 111111111111111111111111 for line in ['one']
+ endfor
+ END
+ call writefile(lines, 'XinvalidFor')
+ " only test that this doesn't crash
+ call RunVim([], [], '-u NONE -e -s -S XinvalidFor -c qa')
+
+ call delete('XinvalidFor')
+endfunc
+
func Test_readfile_binary()
new
call setline(1, ['one', 'two', 'three'])
setlocal ff=dos
- silent write XReadfile
- let lines = readfile('XReadfile')
+ silent write XReadfile_bin
+ let lines = 'XReadfile_bin'->readfile()
call assert_equal(['one', 'two', 'three'], lines)
- let lines = readfile('XReadfile', '', 2)
+ let lines = readfile('XReadfile_bin', '', 2)
call assert_equal(['one', 'two'], lines)
- let lines = readfile('XReadfile', 'b')
+ let lines = readfile('XReadfile_bin', 'b')
call assert_equal(["one\r", "two\r", "three\r", ""], lines)
- let lines = readfile('XReadfile', 'b', 2)
+ let lines = readfile('XReadfile_bin', 'b', 2)
call assert_equal(["one\r", "two\r"], lines)
bwipe!
- call delete('XReadfile')
+ call delete('XReadfile_bin')
+endfunc
+
+func Test_readfile_binary_empty()
+ call writefile([], 'Xempty-file')
+ " This used to compare uninitialized memory in Vim <= 8.2.4065
+ call assert_equal([''], readfile('Xempty-file', 'b'))
+ call delete('Xempty-file')
+endfunc
+
+func Test_readfile_bom()
+ call writefile(["\ufeffFOO", "FOO\ufeffBAR"], 'XReadfile_bom')
+ call assert_equal(['FOO', 'FOOBAR'], readfile('XReadfile_bom'))
+ call delete('XReadfile_bom')
+endfunc
+
+func Test_readfile_max()
+ call writefile(range(1, 4), 'XReadfile_max')
+ call assert_equal(['1', '2'], readfile('XReadfile_max', '', 2))
+ call assert_equal(['3', '4'], readfile('XReadfile_max', '', -2))
+ call delete('XReadfile_max')
endfunc
func Test_let_errmsg()
@@ -332,6 +362,11 @@ func Test_curly_assignment()
unlet g:gvar
endfunc
+func Test_deep_recursion()
+ " this was running out of stack
+ call assert_fails("exe 'if ' .. repeat('(', 1002)", 'E1169: Expression too recursive: ((')
+endfunc
+
" K_SPECIAL in the modified character used be escaped, which causes
" double-escaping with feedkeys() or as the return value of an <expr> mapping,
" and doesn't match what getchar() returns,
diff --git a/src/nvim/testdir/test_ex_mode.vim b/src/nvim/testdir/test_ex_mode.vim
index 2f734cba26..93100732ed 100644
--- a/src/nvim/testdir/test_ex_mode.vim
+++ b/src/nvim/testdir/test_ex_mode.vim
@@ -97,7 +97,6 @@ func Test_Ex_substitute()
call term_sendkeys(buf, ":vi\<CR>")
call WaitForAssert({-> assert_match('foo bar', term_getline(buf, 1))}, 1000)
- call term_sendkeys(buf, ":q!\n")
call StopVimInTerminal(buf)
endfunc
diff --git a/src/nvim/testdir/test_excmd.vim b/src/nvim/testdir/test_excmd.vim
index dac7a6989d..44bed890f5 100644
--- a/src/nvim/testdir/test_excmd.vim
+++ b/src/nvim/testdir/test_excmd.vim
@@ -78,6 +78,14 @@ func Test_file_cmd()
call assert_fails('3file', 'E474:')
call assert_fails('0,0file', 'E474:')
call assert_fails('0file abc', 'E474:')
+ if !has('win32')
+ " Change the name of the buffer to the same name
+ new Xfile1
+ file Xfile1
+ call assert_equal('Xfile1', @%)
+ call assert_equal('Xfile1', @#)
+ bw!
+ endif
endfunc
" Test for the :drop command
@@ -230,7 +238,6 @@ endfunc
" Test for the :language command
func Test_language_cmd()
CheckNotMSWindows " FIXME: why does this fail on Windows CI?
- CheckNotBSD " FIXME: why does this fail on OpenBSD CI?
CheckFeature multi_lang
call assert_fails('language ctype non_existing_lang', 'E197:')
@@ -477,20 +484,23 @@ func Test_winsize_cmd()
endfunc
" Test for the :redir command
+" NOTE: if you run tests as root this will fail. Don't run tests as root!
func Test_redir_cmd()
call assert_fails('redir @@', 'E475:')
call assert_fails('redir abc', 'E475:')
+ call assert_fails('redir => 1abc', 'E474:')
+ call assert_fails('redir => a b', 'E488:')
+ call assert_fails('redir => abc[1]', 'E121:')
+ let b = 0zFF
+ call assert_fails('redir =>> b', 'E734:')
+ unlet b
+
if has('unix')
+ " Redirecting to a directory name
call mkdir('Xdir')
call assert_fails('redir > Xdir', 'E17:')
call delete('Xdir', 'd')
endif
- if !has('bsd')
- call writefile([], 'Xfile')
- call setfperm('Xfile', 'r--r--r--')
- call assert_fails('redir! > Xfile', 'E190:')
- call delete('Xfile')
- endif
" Test for redirecting to a register
redir @q> | echon 'clean ' | redir END
@@ -503,6 +513,16 @@ func Test_redir_cmd()
call assert_equal('blue sky', color)
endfunc
+func Test_redir_cmd_readonly()
+ CheckNotRoot
+
+ " Redirecting to a read-only file
+ call writefile([], 'Xfile')
+ call setfperm('Xfile', 'r--r--r--')
+ call assert_fails('redir! > Xfile', 'E190:')
+ call delete('Xfile')
+endfunc
+
" Test for the :filetype command
func Test_filetype_cmd()
call assert_fails('filetype abc', 'E475:')
@@ -568,10 +588,12 @@ endfunc
" Test for the :verbose command
func Test_verbose_cmd()
- call assert_equal([' verbose=1'], split(execute('verbose set vbs'), "\n"))
+ set verbose=3
+ call assert_match(' verbose=1\n\s*Last set from ', execute('verbose set vbs'), "\n")
call assert_equal([' verbose=0'], split(execute('0verbose set vbs'), "\n"))
- let l = execute("4verbose set verbose | set verbose")
- call assert_equal([' verbose=4', ' verbose=0'], split(l, "\n"))
+ set verbose=0
+ call assert_match(' verbose=4\n\s*Last set from .*\n verbose=0',
+ \ execute("4verbose set verbose | set verbose"))
endfunc
" Test for the :delete command and the related abbreviated commands
@@ -661,12 +683,24 @@ func Sandbox_tests()
if has('unix')
call assert_fails('cd `pwd`', 'E48:')
endif
+ " some options cannot be changed in a sandbox
+ call assert_fails('set exrc', 'E48:')
+ call assert_fails('set cdpath', 'E48:')
+ if has('xim') && has('gui_gtk')
+ call assert_fails('set imstyle', 'E48:')
+ endif
endfunc
func Test_sandbox()
sandbox call Sandbox_tests()
endfunc
+func Test_command_not_implemented_E319()
+ if !has('mzscheme')
+ call assert_fails('mzscheme', 'E319:')
+ endif
+endfunc
+
func Test_not_break_expression_register()
call setreg('=', '1+1')
if 0
diff --git a/src/nvim/testdir/test_exists.vim b/src/nvim/testdir/test_exists.vim
index 471c77853d..62c66192ef 100644
--- a/src/nvim/testdir/test_exists.vim
+++ b/src/nvim/testdir/test_exists.vim
@@ -68,6 +68,10 @@ func Test_exists()
" Existing environment variable
let $EDITOR_NAME = 'Vim Editor'
call assert_equal(1, exists('$EDITOR_NAME'))
+ if has('unix')
+ " ${name} environment variables are supported only on Unix-like systems
+ call assert_equal(1, exists('${VIM}'))
+ endif
" Non-existing environment variable
call assert_equal(0, exists('$NON_ENV_VAR'))
@@ -323,3 +327,5 @@ endfunc
func Test_exists_funcarg()
call FuncArg_Tests("arg1", "arg2")
endfunc
+
+" vim: shiftwidth=2 sts=2 expandtab
diff --git a/src/nvim/testdir/test_exit.vim b/src/nvim/testdir/test_exit.vim
index 37be293950..6dbfb7047c 100644
--- a/src/nvim/testdir/test_exit.vim
+++ b/src/nvim/testdir/test_exit.vim
@@ -117,6 +117,7 @@ func Test_exit_error_reading_input()
CheckNotMSWindows
" The early exit causes memory not to be freed somehow
CheckNotAsan
+ CheckNotValgrind
call writefile([":au VimLeave * call writefile(['l = ' .. v:exiting], 'Xtestout')", ":tabnew", "q:"], 'Xscript', 'b')
diff --git a/src/nvim/testdir/test_expand.vim b/src/nvim/testdir/test_expand.vim
index ce414e4b11..4f5bb67d21 100644
--- a/src/nvim/testdir/test_expand.vim
+++ b/src/nvim/testdir/test_expand.vim
@@ -90,14 +90,26 @@ func Test_expandcmd()
" Test for expression expansion `=
let $FOO= "blue"
call assert_equal("blue sky", expandcmd("`=$FOO .. ' sky'`"))
+ let x = expandcmd("`=axbycz`")
+ call assert_equal('`=axbycz`', x)
+ call assert_fails('let x = expandcmd("`=axbycz`", #{errmsg: 1})', 'E121:')
+ let x = expandcmd("`=axbycz`", #{abc: []})
+ call assert_equal('`=axbycz`', x)
" Test for env variable with spaces
let $FOO= "foo bar baz"
call assert_equal("e foo bar baz", expandcmd("e $FOO"))
- if has('unix')
- " test for using the shell to expand a command argument
- call assert_equal('{1..4}', expandcmd('{1..4}'))
+ if has('unix') && executable('bash')
+ " test for using the shell to expand a command argument.
+ " only bash supports the {..} syntax
+ set shell=bash
+ let x = expandcmd('{1..4}')
+ call assert_equal('{1..4}', x)
+ call assert_fails("let x = expandcmd('{1..4}', #{errmsg: v:true})", 'E77:')
+ let x = expandcmd('{1..4}', #{error: v:true})
+ call assert_equal('{1..4}', x)
+ set shell&
endif
unlet $FOO
@@ -116,13 +128,21 @@ func Test_source_sfile()
:call assert_equal('edit <cword>', expandcmd("edit <cword>"))
:call assert_equal('edit <cexpr>', expandcmd("edit <cexpr>"))
:call assert_fails('autocmd User MyCmd echo "<sfile>"', 'E498:')
+ :
+ :call assert_equal('', expand('<script>'))
+ :verbose echo expand('<script>')
+ :call add(v:errors, v:errmsg)
+ :verbose echo expand('<sfile>')
+ :call add(v:errors, v:errmsg)
:call writefile(v:errors, 'Xresult')
:qall!
-
[SCRIPT]
call writefile(lines, 'Xscript')
if RunVim([], [], '--clean -s Xscript')
- call assert_equal([], readfile('Xresult'))
+ call assert_equal([
+ \ 'E1274: No script file name to substitute for "<script>"',
+ \ 'E498: no :source file name to substitute for "<sfile>"'],
+ \ readfile('Xresult'))
endif
call delete('Xscript')
call delete('Xresult')
@@ -147,4 +167,63 @@ func Test_expandcmd_shell_nonomatch()
call assert_equal('$*', expandcmd('$*'))
endfunc
+func Test_expand_script_source()
+ let lines0 =<< trim [SCRIPT]
+ call extend(g:script_level, [expand('<script>:t')])
+ so Xscript1
+ func F0()
+ call extend(g:func_level, [expand('<script>:t')])
+ endfunc
+
+ au User * call extend(g:au_level, [expand('<script>:t')])
+ [SCRIPT]
+
+ let lines1 =<< trim [SCRIPT]
+ call extend(g:script_level, [expand('<script>:t')])
+ so Xscript2
+ func F1()
+ call extend(g:func_level, [expand('<script>:t')])
+ endfunc
+
+ au User * call extend(g:au_level, [expand('<script>:t')])
+ [SCRIPT]
+
+ let lines2 =<< trim [SCRIPT]
+ call extend(g:script_level, [expand('<script>:t')])
+ func F2()
+ call extend(g:func_level, [expand('<script>:t')])
+ endfunc
+
+ au User * call extend(g:au_level, [expand('<script>:t')])
+ [SCRIPT]
+
+ call writefile(lines0, 'Xscript0')
+ call writefile(lines1, 'Xscript1')
+ call writefile(lines2, 'Xscript2')
+
+ " Check the expansion of <script> at different levels.
+ let g:script_level = []
+ let g:func_level = []
+ let g:au_level = []
+
+ so Xscript0
+ call F0()
+ call F1()
+ call F2()
+ doautocmd User
+
+ call assert_equal(['Xscript0', 'Xscript1', 'Xscript2'], g:script_level)
+ call assert_equal(['Xscript0', 'Xscript1', 'Xscript2'], g:func_level)
+ call assert_equal(['Xscript2', 'Xscript1', 'Xscript0'], g:au_level)
+
+ unlet g:script_level g:func_level
+ delfunc F0
+ delfunc F1
+ delfunc F2
+
+ call delete('Xscript0')
+ call delete('Xscript1')
+ call delete('Xscript2')
+endfunc
+
" vim: shiftwidth=2 sts=2 expandtab
diff --git a/src/nvim/testdir/test_expand_func.vim b/src/nvim/testdir/test_expand_func.vim
index df01d84f19..454d76f0aa 100644
--- a/src/nvim/testdir/test_expand_func.vim
+++ b/src/nvim/testdir/test_expand_func.vim
@@ -107,10 +107,15 @@ endfunc
func Test_expand()
new
- call assert_equal("", expand('%:S'))
+ call assert_equal("", expand('%:S'))
call assert_equal('3', '<slnum>'->expand())
call assert_equal(['4'], expand('<slnum>', v:false, v:true))
" Don't add any line above this, otherwise <slnum> will change.
+ call assert_equal("", expand('%'))
+ set verbose=1
+ call assert_equal("", expand('%'))
+ set verbose=0
+ call assert_equal("", expand('%:p'))
quit
endfunc
@@ -134,6 +139,7 @@ func Test_expand_wildignore()
call assert_equal('test_expand_func.vim', expand('test_expand_func.vim', 1))
call assert_equal(['test_expand_func.vim'],
\ expand('test_expand_func.vim', 1, 1))
+ call assert_fails("call expand('*', [])", 'E745:')
set wildignore&
endfunc
diff --git a/src/nvim/testdir/test_expr.vim b/src/nvim/testdir/test_expr.vim
index 5b10e691e5..47f7f5eb0e 100644
--- a/src/nvim/testdir/test_expr.vim
+++ b/src/nvim/testdir/test_expr.vim
@@ -1,5 +1,7 @@
" Tests for expressions.
+source check.vim
+
func Test_equal()
let base = {}
func base.method()
@@ -44,6 +46,7 @@ func Test_dict()
call assert_equal('zero', d[0])
call assert_true(has_key(d, ''))
call assert_true(has_key(d, 'a'))
+ call assert_fails("let i = has_key([], 'a')", 'E715:')
let d[''] = 'none'
let d['a'] = 'aaa'
@@ -62,6 +65,8 @@ func Test_strgetchar()
call assert_equal(-1, strgetchar('axb', -1))
call assert_equal(-1, strgetchar('axb', 3))
call assert_equal(-1, strgetchar('', 0))
+ call assert_fails("let c=strgetchar([], 1)", 'E730:')
+ call assert_fails("let c=strgetchar('axb', [])", 'E745:')
endfunc
func Test_strcharpart()
@@ -76,22 +81,27 @@ func Test_strcharpart()
call assert_equal('', strcharpart('axb', -2, 2))
call assert_equal('a', strcharpart('axb', -1, 2))
+
+ call assert_equal('edit', "editor"[-10:3])
+endfunc
+
+func Test_getreg_empty_list()
+ call assert_equal('', getreg('x'))
+ call assert_equal([], getreg('x', 1, 1))
+ let x = getreg('x', 1, 1)
+ let y = x
+ call add(x, 'foo')
+ call assert_equal(['foo'], y)
+ call assert_fails('call getreg([])', 'E730:')
endfunc
func Test_loop_over_null_list()
- let null_list = submatch(1, 1)
+ let null_list = v:_null_list
for i in null_list
call assert_report('should not get here')
endfor
endfunc
-func Test_compare_null_dict()
- call assert_fails('let x = v:_null_dict[10]')
- call assert_equal({}, {})
- call assert_equal(v:_null_dict, v:_null_dict)
- call assert_notequal({}, v:_null_dict)
-endfunc
-
func Test_set_reg_null_list()
call setreg('x', v:_null_list)
endfunc
@@ -478,49 +488,6 @@ function Test_max_min_errors()
call assert_fails('call min(v:true)', 'min()')
endfunc
-func Test_substitute_expr()
- let g:val = 'XXX'
- call assert_equal('XXX', substitute('yyy', 'y*', '\=g:val', ''))
- call assert_equal('XXX', substitute('yyy', 'y*', {-> g:val}, ''))
- call assert_equal("-\u1b \uf2-", substitute("-%1b %f2-", '%\(\x\x\)',
- \ '\=nr2char("0x" . submatch(1))', 'g'))
- call assert_equal("-\u1b \uf2-", substitute("-%1b %f2-", '%\(\x\x\)',
- \ {-> nr2char("0x" . submatch(1))}, 'g'))
-
- call assert_equal('231', substitute('123', '\(.\)\(.\)\(.\)',
- \ {-> submatch(2) . submatch(3) . submatch(1)}, ''))
-
- func Recurse()
- return substitute('yyy', 'y\(.\)y', {-> submatch(1)}, '')
- endfunc
- " recursive call works
- call assert_equal('-y-x-', substitute('xxx', 'x\(.\)x', {-> '-' . Recurse() . '-' . submatch(1) . '-'}, ''))
-endfunc
-
-func Test_invalid_submatch()
- " This was causing invalid memory access in Vim-7.4.2232 and older
- call assert_fails("call substitute('x', '.', {-> submatch(10)}, '')", 'E935:')
-endfunc
-
-func Test_substitute_expr_arg()
- call assert_equal('123456789-123456789=', substitute('123456789',
- \ '\(.\)\(.\)\(.\)\(.\)\(.\)\(.\)\(.\)\(.\)\(.\)',
- \ {m -> m[0] . '-' . m[1] . m[2] . m[3] . m[4] . m[5] . m[6] . m[7] . m[8] . m[9] . '='}, ''))
-
- call assert_equal('123456-123456=789', substitute('123456789',
- \ '\(.\)\(.\)\(.\)\(a*\)\(n*\)\(.\)\(.\)\(.\)\(x*\)',
- \ {m -> m[0] . '-' . m[1] . m[2] . m[3] . m[4] . m[5] . m[6] . m[7] . m[8] . m[9] . '='}, ''))
-
- call assert_equal('123456789-123456789x=', substitute('123456789',
- \ '\(.\)\(.\)\(.*\)',
- \ {m -> m[0] . '-' . m[1] . m[2] . m[3] . 'x' . m[4] . m[5] . m[6] . m[7] . m[8] . m[9] . '='}, ''))
-
- call assert_fails("call substitute('xxx', '.', {m -> string(add(m, 'x'))}, '')", 'E742:')
- call assert_fails("call substitute('xxx', '.', {m -> string(insert(m, 'x'))}, '')", 'E742:')
- call assert_fails("call substitute('xxx', '.', {m -> string(extend(m, ['x']))}, '')", 'E742:')
- call assert_fails("call substitute('xxx', '.', {m -> string(remove(m, 1))}, '')", 'E742:')
-endfunc
-
func Test_function_with_funcref()
let s:f = function('type')
let s:fref = function(s:f)
@@ -529,6 +496,14 @@ func Test_function_with_funcref()
call assert_fails("call function('foo()')", 'E475:')
call assert_fails("call function('foo()')", 'foo()')
+ call assert_fails("function('')", 'E129:')
+
+ let Len = {s -> strlen(s)}
+ call assert_equal(6, Len('foobar'))
+ let name = string(Len)
+ " can evaluate "function('<lambda>99')"
+ call execute('let Ref = ' .. name)
+ call assert_equal(4, Ref('text'))
endfunc
func Test_funcref()
@@ -547,6 +522,22 @@ func Test_funcref()
call assert_fails('echo funcref("{")', 'E475:')
let OneByRef = funcref("One", repeat(["foo"], 20))
call assert_fails('let OneByRef = funcref("One", repeat(["foo"], 21))', 'E118:')
+ call assert_fails('echo function("min") =~ function("min")', 'E694:')
+endfunc
+
+" Test for calling function() and funcref() outside of a Vim script context.
+func Test_function_outside_script()
+ let cleanup =<< trim END
+ call writefile([execute('messages')], 'Xtest.out')
+ qall
+ END
+ call writefile(cleanup, 'Xverify.vim')
+ call RunVim([], [], "-c \"echo function('s:abc')\" -S Xverify.vim")
+ call assert_match('E81: Using <SID> not in a', readfile('Xtest.out')[0])
+ call RunVim([], [], "-c \"echo funcref('s:abc')\" -S Xverify.vim")
+ call assert_match('E81: Using <SID> not in a', readfile('Xtest.out')[0])
+ call delete('Xtest.out')
+ call delete('Xverify.vim')
endfunc
func Test_setmatches()
@@ -560,6 +551,7 @@ func Test_setmatches()
endif
eval set->setmatches()
call assert_equal(exp, getmatches())
+ call assert_fails('let m = setmatches([], [])', 'E745:')
endfunc
func Test_empty_concatenate()
@@ -586,3 +578,99 @@ func Test_eval_after_if()
if 0 | eval SetVal('a') | endif | call SetVal('b')
call assert_equal('b', s:val)
endfunc
+
+func Test_divide_by_zero()
+ " only tests that this doesn't crash, the result is not important
+ echo 0 / 0
+ echo 0 / 0 / -1
+endfunc
+
+" Test for command-line completion of expressions
+func Test_expr_completion()
+ CheckFeature cmdline_compl
+ for cmd in [
+ \ 'let a = ',
+ \ 'const a = ',
+ \ 'if',
+ \ 'elseif',
+ \ 'while',
+ \ 'for',
+ \ 'echo',
+ \ 'echon',
+ \ 'execute',
+ \ 'echomsg',
+ \ 'echoerr',
+ \ 'call',
+ \ 'return',
+ \ 'cexpr',
+ \ 'caddexpr',
+ \ 'cgetexpr',
+ \ 'lexpr',
+ \ 'laddexpr',
+ \ 'lgetexpr']
+ call feedkeys(":" . cmd . " getl\<Tab>\<Home>\"\<CR>", 'xt')
+ call assert_equal('"' . cmd . ' getline(', getreg(':'))
+ endfor
+
+ " completion for the expression register
+ call feedkeys(":\"\<C-R>=float2\t\"\<C-B>\"\<CR>", 'xt')
+ call assert_equal('"float2nr("', @=)
+
+ " completion for window local variables
+ let w:wvar1 = 10
+ let w:wvar2 = 10
+ call feedkeys(":echo w:wvar\<C-A>\<C-B>\"\<CR>", 'xt')
+ call assert_equal('"echo w:wvar1 w:wvar2', @:)
+ unlet w:wvar1 w:wvar2
+
+ " completion for tab local variables
+ let t:tvar1 = 10
+ let t:tvar2 = 10
+ call feedkeys(":echo t:tvar\<C-A>\<C-B>\"\<CR>", 'xt')
+ call assert_equal('"echo t:tvar1 t:tvar2', @:)
+ unlet t:tvar1 t:tvar2
+
+ " completion for variables
+ let g:tvar1 = 1
+ let g:tvar2 = 2
+ call feedkeys(":let g:tv\<C-A>\<C-B>\"\<CR>", 'xt')
+ call assert_equal('"let g:tvar1 g:tvar2', @:)
+ " completion for variables after a ||
+ call feedkeys(":echo 1 || g:tv\<C-A>\<C-B>\"\<CR>", 'xt')
+ call assert_equal('"echo 1 || g:tvar1 g:tvar2', @:)
+
+ " completion for options
+ call feedkeys(":echo &compat\<C-A>\<C-B>\"\<CR>", 'xt')
+ call assert_equal('"echo &compatible', @:)
+ call feedkeys(":echo 1 && &compat\<C-A>\<C-B>\"\<CR>", 'xt')
+ call assert_equal('"echo 1 && &compatible', @:)
+ call feedkeys(":echo &g:equala\<C-A>\<C-B>\"\<CR>", 'xt')
+ call assert_equal('"echo &g:equalalways', @:)
+
+ " completion for string
+ call feedkeys(":echo \"Hello\\ World\"\<C-A>\<C-B>\"\<CR>", 'xt')
+ call assert_equal("\"echo \"Hello\\ World\"\<C-A>", @:)
+ call feedkeys(":echo 'Hello World'\<C-A>\<C-B>\"\<CR>", 'xt')
+ call assert_equal("\"echo 'Hello World'\<C-A>", @:)
+
+ " completion for command after a |
+ call feedkeys(":echo 'Hello' | cwin\<C-A>\<C-B>\"\<CR>", 'xt')
+ call assert_equal("\"echo 'Hello' | cwindow", @:)
+
+ " completion for environment variable
+ let $X_VIM_TEST_COMPLETE_ENV = 'foo'
+ call feedkeys(":let $X_VIM_TEST_COMPLETE_E\<C-A>\<C-B>\"\<CR>", 'tx')
+ call assert_match('"let $X_VIM_TEST_COMPLETE_ENV', @:)
+ unlet $X_VIM_TEST_COMPLETE_ENV
+endfunc
+
+" Test for errors in expression evaluation
+func Test_expr_eval_error()
+ call assert_fails("let i = 'abc' . []", 'E730:')
+ call assert_fails("let l = [] + 10", 'E745:')
+ call assert_fails("let v = 10 + []", 'E745:')
+ call assert_fails("let v = 10 / []", 'E745:')
+ call assert_fails("let v = -{}", 'E728:')
+endfunc
+
+" vim: shiftwidth=2 sts=2 expandtab
diff --git a/src/nvim/testdir/test_filechanged.vim b/src/nvim/testdir/test_filechanged.vim
index b77f02afd1..fef0eb732f 100644
--- a/src/nvim/testdir/test_filechanged.vim
+++ b/src/nvim/testdir/test_filechanged.vim
@@ -140,7 +140,8 @@ func Test_FileChangedShell_edit()
endfunc
func Test_FileChangedShell_edit_dialog()
- throw 'Skipped: requires a UI to be active'
+ " requires a UI to be active
+ throw 'Skipped: use test/functional/legacy/filechanged_spec.lua'
CheckNotGui
CheckUnix " Using low level feedkeys() does not work on MS-Windows.
@@ -190,7 +191,8 @@ func Test_FileChangedShell_edit_dialog()
endfunc
func Test_file_changed_dialog()
- throw 'Skipped: requires a UI to be active'
+ " requires a UI to be active
+ throw 'Skipped: use test/functional/legacy/filechanged_spec.lua'
CheckUnix
CheckNotGui
au! FileChangedShell
diff --git a/src/nvim/testdir/test_fileformat.vim b/src/nvim/testdir/test_fileformat.vim
index 81127ea59a..8d727a68c4 100644
--- a/src/nvim/testdir/test_fileformat.vim
+++ b/src/nvim/testdir/test_fileformat.vim
@@ -31,6 +31,15 @@ func Test_fileformat_autocommand()
bw!
endfunc
+func Test_fileformat_nomodifiable()
+ new
+ setlocal nomodifiable
+
+ call assert_fails('set fileformat=latin1', 'E21:')
+
+ bw
+endfunc
+
" Convert the contents of a file into a literal string
func s:file2str(fname)
let b = readfile(a:fname, 'B')
diff --git a/src/nvim/testdir/test_filetype.vim b/src/nvim/testdir/test_filetype.vim
index e3a8370661..cddb1349f5 100644
--- a/src/nvim/testdir/test_filetype.vim
+++ b/src/nvim/testdir/test_filetype.vim
@@ -88,15 +88,17 @@ let s:filename_checks = {
\ 'bindzone': ['named.root', '/bind/db.file', '/named/db.file', 'any/bind/db.file', 'any/named/db.file'],
\ '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'],
\ 'blank': ['file.bl'],
+ \ 'blueprint': ['file.blp'],
\ 'bsdl': ['file.bsd', 'file.bsdl'],
\ 'bst': ['file.bst'],
- \ 'bzl': ['file.bazel', 'file.bzl', 'WORKSPACE'],
+ \ 'bzl': ['file.bazel', 'file.bzl', 'WORKSPACE', 'WORKSPACE.bzlmod'],
\ 'bzr': ['bzr_log.any', 'bzr_log.file'],
\ 'c': ['enlightenment/file.cfg', 'file.qc', 'file.c', 'some-enlightenment/file.cfg'],
\ 'cabal': ['file.cabal'],
\ 'cabalconfig': ['cabal.config'],
\ 'cabalproject': ['cabal.project', 'cabal.project.local'],
\ 'calendar': ['calendar', '/.calendar/file', '/share/calendar/any/calendar.file', '/share/calendar/calendar.file', 'any/share/calendar/any/calendar.file', 'any/share/calendar/calendar.file'],
+ \ 'capnp': ['file.capnp'],
\ 'catalog': ['catalog', 'sgml.catalogfile', 'sgml.catalog', 'sgml.catalog-file'],
\ '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'],
@@ -107,6 +109,7 @@ let s:filename_checks = {
\ 'ch': ['file.chf'],
\ 'chaiscript': ['file.chai'],
\ 'chaskell': ['file.chs'],
+ \ 'chatito': ['file.chatito'],
\ 'chill': ['file..ch'],
\ 'chordpro': ['file.chopro', 'file.crd', 'file.cho', 'file.crdpro', 'file.chordpro'],
\ 'cl': ['file.eni'],
@@ -120,10 +123,11 @@ let s:filename_checks = {
\ 'conaryrecipe': ['file.recipe'],
\ 'conf': ['auto.master'],
\ 'config': ['configure.in', 'configure.ac', '/etc/hostname.file', 'any/etc/hostname.file'],
- \ 'confini': ['/etc/pacman.conf', 'any/etc/pacman.conf', 'mpv.conf'],
+ \ 'confini': ['/etc/pacman.conf', 'any/etc/pacman.conf', 'mpv.conf', 'any/.aws/config', 'any/.aws/credentials'],
\ 'context': ['tex/context/any/file.tex', 'file.mkii', 'file.mkiv', 'file.mkvi', 'file.mkxl', 'file.mklx'],
\ 'cook': ['file.cook'],
\ 'cpp': ['file.cxx', 'file.c++', 'file.hh', 'file.hxx', 'file.hpp', 'file.ipp', 'file.moc', 'file.tcc', 'file.inl', 'file.tlh'],
+ \ 'cqlang': ['file.cql'],
\ 'crm': ['file.crm'],
\ 'crontab': ['crontab', 'crontab.file', '/etc/cron.d/file', 'any/etc/cron.d/file'],
\ 'cs': ['file.cs', 'file.csx'],
@@ -159,7 +163,7 @@ let s:filename_checks = {
\ 'dnsmasq': ['/etc/dnsmasq.conf', '/etc/dnsmasq.d/file', 'any/etc/dnsmasq.conf', 'any/etc/dnsmasq.d/file'],
\ 'dockerfile': ['Containerfile', 'Dockerfile', 'dockerfile', 'file.Dockerfile', 'file.dockerfile', 'Dockerfile.debian', 'Containerfile.something'],
\ 'dosbatch': ['file.bat'],
- \ 'dosini': ['.editorconfig', '/etc/yum.conf', 'file.ini', 'npmrc', '.npmrc', 'php.ini', 'php.ini-5', 'php.ini-file', '/etc/yum.repos.d/file', 'any/etc/yum.conf', 'any/etc/yum.repos.d/file', 'file.wrap'],
+ \ 'dosini': ['/etc/yum.conf', 'file.ini', 'npmrc', '.npmrc', 'php.ini', 'php.ini-5', 'php.ini-file', '/etc/yum.repos.d/file', 'any/etc/yum.conf', 'any/etc/yum.repos.d/file', 'file.wrap'],
\ 'dot': ['file.dot', 'file.gv'],
\ 'dracula': ['file.drac', 'file.drc', 'filelvs', 'filelpe', 'drac.file', 'lpe', 'lvs', 'some-lpe', 'some-lvs'],
\ 'dtd': ['file.dtd'],
@@ -171,6 +175,7 @@ let s:filename_checks = {
\ 'dylanlid': ['file.lid'],
\ 'ecd': ['file.ecd'],
\ 'edif': ['file.edf', 'file.edif', 'file.edo'],
+ \ 'editorconfig': ['.editorconfig'],
\ 'eelixir': ['file.eex', 'file.leex'],
\ 'elinks': ['elinks.conf'],
\ 'elixir': ['file.ex', 'file.exs', 'mix.lock'],
@@ -201,6 +206,7 @@ let s:filename_checks = {
\ 'fpcmake': ['file.fpc'],
\ 'framescript': ['file.fsl'],
\ 'freebasic': ['file.fb'],
+ \ 'fsh': ['file.fsh'],
\ 'fsharp': ['file.fs', 'file.fsi', 'file.fsx'],
\ 'fstab': ['fstab', 'mtab'],
\ 'fusion': ['file.fusion'],
@@ -209,11 +215,14 @@ let s:filename_checks = {
\ 'gdmo': ['file.mo', 'file.gdmo'],
\ 'gdresource': ['file.tscn', 'file.tres'],
\ 'gdscript': ['file.gd'],
+ \ 'gdshader': ['file.gdshader', 'file.shader'],
\ 'gedcom': ['file.ged', 'lltxxxxx.txt', '/tmp/lltmp', '/tmp/lltmp-file', 'any/tmp/lltmp', 'any/tmp/lltmp-file'],
\ 'gemtext': ['file.gmi', 'file.gemini'],
\ 'gift': ['file.gift'],
+ \ 'gitattributes': ['file.git/info/attributes', '.gitattributes', '/.config/git/attributes', '/etc/gitattributes', '/usr/local/etc/gitattributes', 'some.git/info/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'],
+ \ 'gitignore': ['file.git/info/exclude', '.gitignore', '/.config/git/ignore', 'some.git/info/exclude'],
\ 'gitolite': ['gitolite.conf', '/gitolite-admin/conf/file', 'any/gitolite-admin/conf/file'],
\ 'gitrebase': ['git-rebase-todo'],
\ 'gitsendemail': ['.gitsendemail.msg.xxxxxx'],
@@ -224,6 +233,7 @@ let s:filename_checks = {
\ 'gnuplot': ['file.gpi', '.gnuplot'],
\ 'go': ['file.go'],
\ 'gomod': ['go.mod'],
+ \ 'gosum': ['go.sum'],
\ 'gowork': ['go.work'],
\ 'gp': ['file.gp', '.gprc'],
\ 'gpg': ['/.gnupg/options', '/.gnupg/gpg.conf', '/usr/any/gnupg/options.skel', 'any/.gnupg/gpg.conf', 'any/.gnupg/options', 'any/usr/any/gnupg/options.skel'],
@@ -235,6 +245,7 @@ let s:filename_checks = {
\ 'grub': ['/boot/grub/menu.lst', '/boot/grub/grub.conf', '/etc/grub.conf', 'any/boot/grub/grub.conf', 'any/boot/grub/menu.lst', 'any/etc/grub.conf'],
\ 'gsp': ['file.gsp'],
\ 'gtkrc': ['.gtkrc', 'gtkrc', '.gtkrc-file', 'gtkrc-file'],
+ \ 'gyp': ['file.gyp', 'file.gypi'],
\ 'hack': ['file.hack', 'file.hackpartial'],
\ 'haml': ['file.haml'],
\ 'hamster': ['file.hsm'],
@@ -250,6 +261,7 @@ let s:filename_checks = {
\ 'hex': ['file.hex', 'file.h32'],
\ 'hgcommit': ['hg-editor-file.txt'],
\ 'hjson': ['file.hjson'],
+ \ 'hlsplaylist': ['file.m3u', 'file.m3u8'],
\ 'hog': ['file.hog', 'snort.conf', 'vision.conf'],
\ 'hollywood': ['file.hws'],
\ 'hoon': ['file.hoon'],
@@ -274,16 +286,18 @@ let s:filename_checks = {
\ 'jam': ['file.jpl', 'file.jpr', 'JAM-file.file', 'JAM.file', 'Prl-file.file', 'Prl.file'],
\ 'java': ['file.java', 'file.jav'],
\ 'javacc': ['file.jj', 'file.jjt'],
- \ 'javascript': ['file.js', 'file.javascript', 'file.es', 'file.mjs', 'file.cjs'],
+ \ 'javascript': ['file.js', 'file.jsm', 'file.javascript', 'file.es', 'file.mjs', 'file.cjs'],
\ 'javascript.glimmer': ['file.gjs'],
\ 'javascriptreact': ['file.jsx'],
\ 'jess': ['file.clp'],
\ 'jgraph': ['file.jgr'],
+ \ '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'],
- \ 'json': ['file.json', 'file.jsonp', 'file.json-patch', 'file.webmanifest', 'Pipfile.lock', 'file.ipynb', '.babelrc', '.eslintrc', '.prettierrc', '.firebaserc', 'file.slnf'],
+ \ '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.webmanifest', 'Pipfile.lock', 'file.ipynb', '.prettierrc', '.firebaserc', 'file.slnf'],
\ 'json5': ['file.json5'],
- \ 'jsonc': ['file.jsonc'],
+ \ 'jsonc': ['file.jsonc', '.babelrc', '.eslintrc', '.jsfmtrc', '.jshintrc', '.hintrc', '.swrc', 'jsconfig.json', 'tsconfig.json', 'tsconfig.test.json', 'tsconfig-test.json'],
+ \ 'jsonnet': ['file.jsonnet', 'file.libsonnet'],
\ 'jsp': ['file.jsp'],
\ 'julia': ['file.jl'],
\ 'kconfig': ['Kconfig', 'Kconfig.debug', 'Kconfig.file'],
@@ -320,8 +334,9 @@ let s:filename_checks = {
\ 'lpc': ['file.lpc', 'file.ulpc'],
\ 'lsl': ['file.lsl'],
\ 'lss': ['file.lss'],
- \ 'lua': ['file.lua', 'file.rockspec', 'file.nse'],
+ \ 'lua': ['file.lua', 'file.rockspec', 'file.nse', '.luacheckrc'],
\ 'lynx': ['lynx.cfg'],
+ \ 'lyrics': ['file.lrc'],
\ 'm3build': ['m3makefile', 'm3overrides'],
\ 'm3quake': ['file.quake', 'cm3.cfg'],
\ 'm4': ['file.at'],
@@ -340,6 +355,7 @@ let s:filename_checks = {
\ 'maxima': ['file.demo', 'file.dmt', 'file.dm1', 'file.dm2', 'file.dm3',
\ 'file.wxm', 'maxima-init.mac'],
\ 'mel': ['file.mel'],
+ \ 'mermaid': ['file.mmd', 'file.mmdc', 'file.mermaid'],
\ 'meson': ['meson.build', 'meson_options.txt'],
\ 'messages': ['/log/auth', '/log/cron', '/log/daemon', '/log/debug', '/log/kern', '/log/lpr', '/log/mail', '/log/messages', '/log/news/news', '/log/syslog', '/log/user',
\ '/log/auth.log', '/log/cron.log', '/log/daemon.log', '/log/debug.log', '/log/kern.log', '/log/lpr.log', '/log/mail.log', '/log/messages.log', '/log/news/news.log', '/log/syslog.log', '/log/user.log',
@@ -357,7 +373,7 @@ let s:filename_checks = {
\ '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'],
\ 'modula2': ['file.m2', 'file.mi'],
- \ 'modula3': ['file.m3', 'file.mg', 'file.i3', 'file.ig'],
+ \ 'modula3': ['file.m3', 'file.mg', 'file.i3', 'file.ig', 'file.lm3'],
\ 'monk': ['file.isc', 'file.monk', 'file.ssc', 'file.tsc'],
\ 'moo': ['file.moo'],
\ 'moonscript': ['file.moon'],
@@ -378,12 +394,14 @@ let s:filename_checks = {
\ 'neomuttrc': ['Neomuttrc', '.neomuttrc', '.neomuttrc-file', '/.neomutt/neomuttrc', '/.neomutt/neomuttrc-file', 'Neomuttrc', 'Neomuttrc-file', 'any/.neomutt/neomuttrc', 'any/.neomutt/neomuttrc-file', 'neomuttrc', 'neomuttrc-file'],
\ 'netrc': ['.netrc'],
\ 'nginx': ['file.nginx', 'nginxfile.conf', 'filenginx.conf', 'any/etc/nginx/file', 'any/usr/local/nginx/conf/file', 'any/nginx/file.conf'],
+ \ 'nim': ['file.nim', 'file.nims', 'file.nimble'],
\ 'ninja': ['file.ninja'],
\ 'nix': ['file.nix'],
\ 'nqc': ['file.nqc'],
\ 'nroff': ['file.tr', 'file.nr', 'file.roff', 'file.tmac', 'file.mom', 'tmac.file'],
\ 'nsis': ['file.nsi', 'file.nsh'],
\ 'obj': ['file.obj'],
+ \ 'obse': ['file.obl', 'file.obse', 'file.oblivion', 'file.obscript'],
\ 'ocaml': ['file.ml', 'file.mli', 'file.mll', 'file.mly', '.ocamlinit', 'file.mlt', 'file.mlp', 'file.mlip', 'file.mli.cppo', 'file.ml.cppo'],
\ 'occam': ['file.occ'],
\ 'octave': ['octaverc', '.octaverc', 'octave.conf'],
@@ -391,6 +409,7 @@ let s:filename_checks = {
\ 'opam': ['opam', 'file.opam', 'file.opam.template'],
\ 'openroad': ['file.or'],
\ 'openscad': ['file.scad'],
+ \ 'openvpn': ['file.ovpn', '/etc/openvpn/client/client.conf', '/usr/share/openvpn/examples/server.conf'],
\ 'opl': ['file.OPL', 'file.OPl', 'file.OpL', 'file.Opl', 'file.oPL', 'file.oPl', 'file.opL', 'file.opl'],
\ 'ora': ['file.ora'],
\ 'org': ['file.org', 'file.org_archive'],
@@ -403,10 +422,10 @@ let s:filename_checks = {
\ 'pccts': ['file.g'],
\ 'pcmk': ['file.pcmk'],
\ 'pdf': ['file.pdf'],
- \ 'perl': ['file.plx', 'file.al', 'file.psgi', 'gitolite.rc', '.gitolite.rc', 'example.gitolite.rc'],
+ \ 'perl': ['file.plx', 'file.al', 'file.psgi', 'gitolite.rc', '.gitolite.rc', 'example.gitolite.rc', '.latexmkrc', 'latexmkrc'],
\ 'pf': ['pf.conf'],
- \ 'pfmain': ['main.cf'],
- \ 'php': ['file.php', 'file.php9', 'file.phtml', 'file.ctp', 'file.phpt'],
+ \ 'pfmain': ['main.cf', 'main.cf.proto'],
+ \ 'php': ['file.php', 'file.php9', 'file.phtml', 'file.ctp', 'file.phpt', 'file.theme'],
\ 'pike': ['file.pike', 'file.pmod'],
\ 'pilrc': ['file.rcp'],
\ 'pine': ['.pinerc', 'pinerc', '.pinercex', 'pinercex'],
@@ -417,6 +436,7 @@ let s:filename_checks = {
\ 'plsql': ['file.pls', 'file.plsql'],
\ 'po': ['file.po', 'file.pot'],
\ 'pod': ['file.pod'],
+ \ 'poefilter': ['file.filter'],
\ 'poke': ['file.pk'],
\ 'postscr': ['file.ps', 'file.pfa', 'file.afm', 'file.eps', 'file.epsf', 'file.epsi', 'file.ai'],
\ 'pov': ['file.pov'],
@@ -443,7 +463,7 @@ let s:filename_checks = {
\ 'ql': ['file.ql', 'file.qll'],
\ 'quake': ['anybaseq2/file.cfg', 'anyid1/file.cfg', 'quake3/file.cfg', 'baseq2/file.cfg', 'id1/file.cfg', 'quake1/file.cfg', 'some-baseq2/file.cfg', 'some-id1/file.cfg', 'some-quake1/file.cfg'],
\ 'quarto': ['file.qmd'],
- \ 'r': ['file.r'],
+ \ 'r': ['file.r', '.Rprofile', 'Rprofile', 'Rprofile.site'],
\ 'radiance': ['file.rad', 'file.mat'],
\ 'raku': ['file.pm6', 'file.p6', 'file.t6', 'file.pod6', 'file.raku', 'file.rakumod', 'file.rakudoc', 'file.rakutest'],
\ 'raml': ['file.raml'],
@@ -507,9 +527,11 @@ let s:filename_checks = {
\ 'slrnrc': ['.slrnrc'],
\ 'slrnsc': ['file.score'],
\ 'sm': ['sendmail.cf'],
+ \ 'smali': ['file.smali'],
\ 'smarty': ['file.tpl'],
\ 'smcl': ['file.hlp', 'file.ihlp', 'file.smcl'],
\ 'smith': ['file.smt', 'file.smith'],
+ \ 'smithy': ['file.smithy'],
\ 'sml': ['file.sml'],
\ 'snobol4': ['file.sno', 'file.spt'],
\ 'solidity': ['file.sol'],
@@ -525,13 +547,15 @@ let s:filename_checks = {
\ 'squid': ['squid.conf'],
\ 'squirrel': ['file.nut'],
\ 'srec': ['file.s19', 'file.s28', 'file.s37', 'file.mot', 'file.srec'],
+ \ 'srt': ['file.srt'],
+ \ 'ssa': ['file.ass', 'file.ssa'],
\ 'sshconfig': ['ssh_config', '/.ssh/config', '/etc/ssh/ssh_config.d/file.conf', 'any/etc/ssh/ssh_config.d/file.conf', 'any/.ssh/config', 'any/.ssh/file.conf'],
\ 'sshdconfig': ['sshd_config', '/etc/ssh/sshd_config.d/file.conf', 'any/etc/ssh/sshd_config.d/file.conf'],
\ 'st': ['file.st'],
\ 'stata': ['file.ado', 'file.do', 'file.imata', 'file.mata'],
\ 'stp': ['file.stp'],
\ 'sudoers': ['any/etc/sudoers', 'sudoers.tmp', '/etc/sudoers', 'any/etc/sudoers.d/file'],
- \ 'supercollider': ['file.quark'],
+ \ 'supercollider': ['file.quark'],
\ 'surface': ['file.sface'],
\ 'svelte': ['file.svelte'],
\ 'svg': ['file.svg'],
@@ -557,6 +581,7 @@ let s:filename_checks = {
\ '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'],
\ 'tf': ['file.tf', '.tfrc', 'tfrc'],
+ \ 'thrift': ['file.thrift'],
\ 'tidy': ['.tidyrc', 'tidyrc', 'tidy.conf'],
\ 'tilde': ['file.t.html'],
\ 'tla': ['file.tla'],
@@ -572,6 +597,7 @@ let s:filename_checks = {
\ 'tssop': ['file.tssop'],
\ 'tsv': ['file.tsv'],
\ 'twig': ['file.twig'],
+ \ 'typescript': ['file.mts', 'file.cts'],
\ 'typescript.glimmer': ['file.gts'],
\ 'typescriptreact': ['file.tsx'],
\ 'uc': ['file.uc'],
@@ -588,11 +614,16 @@ let s:filename_checks = {
\ 'usw2kagtlog': ['usw2kagt.log', 'USW2KAGT.LOG', 'usw2kagt.file.log', 'USW2KAGT.FILE.LOG', 'file.usw2kagt.log', 'FILE.USW2KAGT.LOG'],
\ 'vala': ['file.vala'],
\ 'vb': ['file.sba', 'file.vb', 'file.vbs', 'file.dsm', 'file.ctl'],
+ \ 'vdf': ['file.vdf'],
+ \ 'vdmpp': ['file.vpp', 'file.vdmpp'],
+ \ 'vdmrt': ['file.vdmrt'],
+ \ 'vdmsl': ['file.vdm', 'file.vdmsl'],
\ 'vera': ['file.vr', 'file.vri', 'file.vrh'],
\ 'verilog': ['file.v'],
\ 'verilogams': ['file.va', 'file.vams'],
\ 'vgrindefs': ['vgrindefs'],
\ 'vhdl': ['file.hdl', 'file.vhd', 'file.vhdl', 'file.vbe', 'file.vst', 'file.vhdl_123', 'file.vho', 'some.vhdl_1', 'some.vhdl_1-file'],
+ \ 'vhs': ['file.tape'],
\ 'vim': ['file.vim', 'file.vba', '.exrc', '_exrc', 'some-vimrc', 'some-vimrc-file', 'vimrc', 'vimrc-file'],
\ 'viminfo': ['.viminfo', '_viminfo'],
\ 'vmasm': ['file.mar'],
@@ -601,6 +632,7 @@ let s:filename_checks = {
\ 'vroom': ['file.vroom'],
\ 'vue': ['file.vue'],
\ 'wast': ['file.wast', 'file.wat'],
+ \ 'wdl': ['file.wdl'],
\ 'webmacro': ['file.wm'],
\ 'wget': ['.wgetrc', 'wgetrc'],
\ 'wget2': ['.wget2rc', 'wget2rc'],
@@ -623,12 +655,13 @@ let s:filename_checks = {
\ 'xsd': ['file.xsd'],
\ 'xslt': ['file.xsl', 'file.xslt'],
\ 'yacc': ['file.yy', 'file.yxx', 'file.y++'],
- \ 'yaml': ['file.yaml', 'file.yml'],
+ \ 'yaml': ['file.yaml', 'file.yml', '.clang-format', '.clang-tidy'],
\ 'yang': ['file.yang'],
\ 'z8a': ['file.z8a'],
\ 'zig': ['file.zig'],
\ 'zimbu': ['file.zu'],
\ 'zimbutempl': ['file.zut'],
+ \ 'zir': ['file.zir'],
\ 'zsh': ['.zprofile', '/etc/zprofile', '.zfbfmarks', 'file.zsh', '.zcompdump', '.zlogin', '.zlogout', '.zshenv', '.zshrc', '.zcompdump-file', '.zlog', '.zlog-file', '.zsh', '.zsh-file', 'any/etc/zprofile', 'zlog', 'zlog-file', 'zsh', 'zsh-file'],
\
\ 'help': [$VIMRUNTIME . '/doc/help.txt'],
@@ -682,6 +715,13 @@ let s:script_checks = {
\ ['__libc_start_main and something']],
\ 'clojure': [['#!/path/clojure']],
\ 'scala': [['#!/path/scala']],
+ \ 'sh': [['#!/path/sh'],
+ \ ['#!/path/bash'],
+ \ ['#!/path/bash2'],
+ \ ['#!/path/dash'],
+ \ ['#!/path/ksh'],
+ \ ['#!/path/ksh93']],
+ \ 'csh': [['#!/path/csh']],
\ 'tcsh': [['#!/path/tcsh']],
\ 'zsh': [['#!/path/zsh']],
\ 'tcl': [['#!/path/tclsh'],
@@ -918,7 +958,9 @@ func Test_d_file()
call assert_equal('d', &filetype)
bwipe!
+ " clean up
filetype off
+ call delete('Xfile.d')
endfunc
func Test_dat_file()
@@ -1346,7 +1388,7 @@ func Test_mod_file()
unlet g:filetype_mod
bwipe!
- " RAPID header start with a line containing only "%%%",
+ " RAPID header start with a line containing only "%%%",
" but is not always present.
call writefile(['%%%'], 'modfile.mod')
split modfile.mod
@@ -1362,7 +1404,7 @@ func Test_mod_file()
bwipe!
call delete('modfile.Mod')
- " RAPID is not case sensitive, embedded spaces, sysmodule,
+ " RAPID is not case sensitive, embedded spaces, sysmodule,
" file starts with empty line(s).
call writefile(['', 'MODULE rapidmödüle (SYSMODULE,NOSTEPIN)'], 'modfile.MOD')
split modfile.MOD
@@ -1490,7 +1532,7 @@ func Test_prg_file()
unlet g:filetype_prg
bwipe!
- " RAPID header start with a line containing only "%%%",
+ " RAPID header start with a line containing only "%%%",
" but is not always present.
call writefile(['%%%'], 'prgfile.prg')
split prgfile.prg
@@ -1506,7 +1548,7 @@ func Test_prg_file()
bwipe!
call delete('prgfile.Prg')
- " RAPID is not case sensitive, embedded spaces, sysmodule,
+ " RAPID is not case sensitive, embedded spaces, sysmodule,
" file starts with empty line(s).
call writefile(['', 'MODULE rapidmödüle (SYSMODULE,NOSTEPIN)'], 'prgfile.PRG')
split prgfile.PRG
@@ -1521,13 +1563,6 @@ endfunc
func Test_sc_file()
filetype on
- " SC file methods are defined 'Class : Method'
- call writefile(['SCNvimDocRenderer : SCDocHTMLRenderer {'], 'srcfile.sc')
- split srcfile.sc
- call assert_equal('supercollider', &filetype)
- bwipe!
- call delete('srcfile.sc')
-
" SC classes are defined with '+ Class {}'
call writefile(['+ SCNvim {', '*methodArgs {|method|'], 'srcfile.sc')
split srcfile.sc
@@ -1617,7 +1652,7 @@ func Test_sys_file()
unlet g:filetype_sys
bwipe!
- " RAPID header start with a line containing only "%%%",
+ " RAPID header start with a line containing only "%%%",
" but is not always present.
call writefile(['%%%'], 'sysfile.sys')
split sysfile.sys
@@ -1633,7 +1668,7 @@ func Test_sys_file()
bwipe!
call delete('sysfile.Sys')
- " RAPID is not case sensitive, embedded spaces, sysmodule,
+ " RAPID is not case sensitive, embedded spaces, sysmodule,
" file starts with empty line(s).
call writefile(['', 'MODULE rapidmödüle (SYSMODULE,NOSTEPIN)'], 'sysfile.SYS')
split sysfile.SYS
@@ -1647,17 +1682,45 @@ endfunc
func Test_tex_file()
filetype on
- " only tests one case, should do more
+ call writefile(['%& pdflatex'], 'Xfile.tex')
+ split Xfile.tex
+ call assert_equal('tex', &filetype)
+ bwipe
+
+ call writefile(['\newcommand{\test}{some text}'], 'Xfile.tex')
+ split Xfile.tex
+ call assert_equal('tex', &filetype)
+ bwipe
+
+ " tex_flavor is unset
+ call writefile(['%& plain'], 'Xfile.tex')
+ split Xfile.tex
+ call assert_equal('plaintex', &filetype)
+ bwipe
+
+ let g:tex_flavor = 'plain'
+ call writefile(['just some text'], 'Xfile.tex')
+ split Xfile.tex
+ call assert_equal('plaintex', &filetype)
+ bwipe
+
let lines =<< trim END
- % This is a sentence.
+ % This is a comment.
- This is a sentence.
+ \usemodule[translate]
END
- call writefile(lines, "Xfile.tex")
+ call writefile(lines, 'Xfile.tex')
split Xfile.tex
- call assert_equal('plaintex', &filetype)
+ call assert_equal('context', &filetype)
bwipe
+ let g:tex_flavor = 'context'
+ call writefile(['just some text'], 'Xfile.tex')
+ split Xfile.tex
+ call assert_equal('context', &filetype)
+ bwipe
+ unlet g:tex_flavor
+
call delete('Xfile.tex')
filetype off
endfunc
@@ -1748,6 +1811,11 @@ func Test_cls_file()
call assert_equal('tex', &filetype)
bwipe!
+ call writefile(['\NeedsTeXFormat{LaTeX2e}'], 'Xfile.cls')
+ split Xfile.cls
+ call assert_equal('tex', &filetype)
+ bwipe!
+
" Rexx
call writefile(['# rexx'], 'Xfile.cls')
@@ -1820,6 +1888,44 @@ func Test_sig_file()
filetype off
endfunc
+" Test dist#ft#FTsil()
+func Test_sil_file()
+ filetype on
+
+ split Xfile.sil
+ call assert_equal('sil', &filetype)
+ bwipe!
+
+ let lines =<< trim END
+ // valid
+ let protoErasedPathA = \ABCProtocol.a
+
+ // also valid
+ let protoErasedPathA =
+ \ABCProtocol.a
+ END
+ call writefile(lines, 'Xfile.sil')
+
+ split Xfile.sil
+ call assert_equal('sil', &filetype)
+ bwipe!
+
+ " SILE
+
+ call writefile(['% some comment'], 'Xfile.sil')
+ split Xfile.sil
+ call assert_equal('sile', &filetype)
+ bwipe!
+
+ call writefile(['\begin[papersize=a6]{document}foo\end{document}'], 'Xfile.sil')
+ split Xfile.sil
+ call assert_equal('sile', &filetype)
+ bwipe!
+
+ call delete('Xfile.sil')
+ filetype off
+endfunc
+
func Test_inc_file()
filetype on
@@ -1899,4 +2005,36 @@ func Test_inc_file()
filetype off
endfunc
+func Test_lsl_file()
+ filetype on
+
+ call writefile(['looks like Linden Scripting Language'], 'Xfile.lsl')
+ split Xfile.lsl
+ call assert_equal('lsl', &filetype)
+ bwipe!
+
+ " Test dist#ft#FTlsl()
+
+ let g:filetype_lsl = 'larch'
+ split Xfile.lsl
+ call assert_equal('larch', &filetype)
+ bwipe!
+ unlet g:filetype_lsl
+
+ " Larch Shared Language
+
+ call writefile(['% larch comment'], 'Xfile.lsl')
+ split Xfile.lsl
+ call assert_equal('larch', &filetype)
+ bwipe!
+
+ call writefile(['foo: trait'], 'Xfile.lsl')
+ split Xfile.lsl
+ call assert_equal('larch', &filetype)
+ bwipe!
+
+ call delete('Xfile.lsl')
+ filetype off
+endfunc
+
" vim: shiftwidth=2 sts=2 expandtab
diff --git a/src/nvim/testdir/test_filter_map.vim b/src/nvim/testdir/test_filter_map.vim
index 1cd3a2287b..c75177ea39 100644
--- a/src/nvim/testdir/test_filter_map.vim
+++ b/src/nvim/testdir/test_filter_map.vim
@@ -86,6 +86,13 @@ func Test_map_filter_fails()
call assert_fails('call filter([1], "42 +")', 'E15:')
call assert_fails("let l = map('abc', '\"> \" . v:val')", 'E896:')
call assert_fails("let l = filter('abc', '\"> \" . v:val')", 'E896:')
+ call assert_fails("let l = filter([1, 2, 3], '{}')", 'E728:')
+ call assert_fails("let l = filter({'k' : 10}, '{}')", 'E728:')
+ call assert_fails("let l = filter([1, 2], {})", 'E731:')
+ call assert_equal(v:_null_list, filter(v:_null_list, 0))
+ call assert_equal(v:_null_dict, filter(v:_null_dict, 0))
+ call assert_equal(v:_null_list, map(v:_null_list, '"> " .. v:val'))
+ call assert_equal(v:_null_dict, map(v:_null_dict, '"> " .. v:val'))
endfunc
func Test_map_and_modify()
diff --git a/src/nvim/testdir/test_fixeol.vim b/src/nvim/testdir/test_fixeol.vim
index 32cb059e26..41d47d6a06 100644
--- a/src/nvim/testdir/test_fixeol.vim
+++ b/src/nvim/testdir/test_fixeol.vim
@@ -1,16 +1,17 @@
-" Tests for 'fixeol' and 'eol'
+" Tests for 'fixeol', 'eof' and 'eol'
+
func Test_fixeol()
" first write two test files – with and without trailing EOL
" use Unix fileformat for consistency
set ff=unix
enew!
- call setline('.', 'with eol')
+ call setline('.', 'with eol or eof')
w! XXEol
enew!
- set noeol nofixeol
- call setline('.', 'without eol')
+ set noeof noeol nofixeol
+ call setline('.', 'without eol or eof')
w! XXNoEol
- set eol fixeol
+ set eol eof fixeol
bwipe XXEol XXNoEol
" try editing files with 'fixeol' disabled
@@ -33,16 +34,85 @@ func Test_fixeol()
w >>XXTestEol
w >>XXTestNoEol
- call assert_equal(['with eol', 'END'], readfile('XXEol'))
- call assert_equal(['without eolEND'], readfile('XXNoEol'))
- call assert_equal(['with eol', 'stays eol', 'END'], readfile('XXTestEol'))
- call assert_equal(['without eol', 'stays withoutEND'],
+ call assert_equal(['with eol or eof', 'END'], readfile('XXEol'))
+ call assert_equal(['without eol or eofEND'], readfile('XXNoEol'))
+ call assert_equal(['with eol or eof', 'stays eol', 'END'], readfile('XXTestEol'))
+ call assert_equal(['without eol or eof', 'stays withoutEND'],
\ readfile('XXTestNoEol'))
call delete('XXEol')
call delete('XXNoEol')
call delete('XXTestEol')
call delete('XXTestNoEol')
- set ff& fixeol& eol&
+ set ff& fixeol& eof& eol&
+ enew!
+endfunc
+
+func Test_eof()
+ let data = 0z68656c6c6f.0d0a.776f726c64 " "hello\r\nworld"
+
+ " 1. Eol, Eof
+ " read
+ call writefile(data + 0z0d0a.1a, 'XXEolEof')
+ e! XXEolEof
+ call assert_equal(['hello', 'world'], getline(1, 2))
+ call assert_equal([1, 1], [&eol, &eof])
+ " write
+ set fixeol
+ w!
+ call assert_equal(data + 0z0d0a, readblob('XXEolEof'))
+ set nofixeol
+ w!
+ call assert_equal(data + 0z0d0a.1a, readblob('XXEolEof'))
+
+ " 2. NoEol, Eof
+ " read
+ call writefile(data + 0z1a, 'XXNoEolEof')
+ e! XXNoEolEof
+ call assert_equal(['hello', 'world'], getline(1, 2))
+ call assert_equal([0, 1], [&eol, &eof])
+ " write
+ set fixeol
+ w!
+ call assert_equal(data + 0z0d0a, readblob('XXNoEolEof'))
+ set nofixeol
+ w!
+ call assert_equal(data + 0z1a, readblob('XXNoEolEof'))
+
+ " 3. Eol, NoEof
+ " read
+ call writefile(data + 0z0d0a, 'XXEolNoEof')
+ e! XXEolNoEof
+ call assert_equal(['hello', 'world'], getline(1, 2))
+ call assert_equal([1, 0], [&eol, &eof])
+ " write
+ set fixeol
+ w!
+ call assert_equal(data + 0z0d0a, readblob('XXEolNoEof'))
+ set nofixeol
+ w!
+ call assert_equal(data + 0z0d0a, readblob('XXEolNoEof'))
+
+ " 4. NoEol, NoEof
+ " read
+ call writefile(data, 'XXNoEolNoEof')
+ e! XXNoEolNoEof
+ call assert_equal(['hello', 'world'], getline(1, 2))
+ call assert_equal([0, 0], [&eol, &eof])
+ " write
+ set fixeol
+ w!
+ call assert_equal(data + 0z0d0a, readblob('XXNoEolNoEof'))
+ set nofixeol
+ w!
+ call assert_equal(data, readblob('XXNoEolNoEof'))
+
+ call delete('XXEolEof')
+ call delete('XXNoEolEof')
+ call delete('XXEolNoEof')
+ call delete('XXNoEolNoEof')
+ set ff& fixeol& eof& eol&
enew!
endfunc
+
+" vim: shiftwidth=2 sts=2 expandtab
diff --git a/src/nvim/testdir/test_fnamemodify.vim b/src/nvim/testdir/test_fnamemodify.vim
index 5ae2a5ee17..258a2093bd 100644
--- a/src/nvim/testdir/test_fnamemodify.vim
+++ b/src/nvim/testdir/test_fnamemodify.vim
@@ -11,6 +11,7 @@ func Test_fnamemodify()
call assert_equal('/', fnamemodify('.', ':p')[-1:])
call assert_equal('r', fnamemodify('.', ':p:h')[-1:])
call assert_equal('t', fnamemodify('test.out', ':p')[-1:])
+ call assert_equal($HOME .. "/foo" , fnamemodify('~/foo', ':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', ':~'))
@@ -95,4 +96,9 @@ func Test_fnamemodify_er()
call assert_equal('', fnamemodify(v:_null_string, v:_null_string))
endfunc
+func Test_fnamemodify_fail()
+ call assert_fails('call fnamemodify({}, ":p")', 'E731:')
+ call assert_fails('call fnamemodify("x", {})', 'E731:')
+endfunc
+
" vim: shiftwidth=2 sts=2 expandtab
diff --git a/src/nvim/testdir/test_fold.vim b/src/nvim/testdir/test_fold.vim
index 327f0f73f2..19415286ad 100644
--- a/src/nvim/testdir/test_fold.vim
+++ b/src/nvim/testdir/test_fold.vim
@@ -1,5 +1,6 @@
" Test for folding
+source check.vim
source view_util.vim
source screendump.vim
@@ -71,6 +72,54 @@ func Test_address_fold()
quit!
endfunc
+func Test_address_offsets()
+ " check the help for :range-closed-fold
+ enew
+ call setline(1, [
+ \ '1 one',
+ \ '2 two',
+ \ '3 three',
+ \ '4 four FOLDED',
+ \ '5 five FOLDED',
+ \ '6 six',
+ \ '7 seven',
+ \ '8 eight',
+ \])
+ set foldmethod=manual
+ normal 4Gvjzf
+ 3,4+2yank
+ call assert_equal([
+ \ '3 three',
+ \ '4 four FOLDED',
+ \ '5 five FOLDED',
+ \ '6 six',
+ \ '7 seven',
+ \ ], getreg(0,1,1))
+
+ enew!
+ call setline(1, [
+ \ '1 one',
+ \ '2 two',
+ \ '3 three FOLDED',
+ \ '4 four FOLDED',
+ \ '5 five FOLDED',
+ \ '6 six FOLDED',
+ \ '7 seven',
+ \ '8 eight',
+ \])
+ normal 3Gv3jzf
+ 2,4-1yank
+ call assert_equal([
+ \ '2 two',
+ \ '3 three FOLDED',
+ \ '4 four FOLDED',
+ \ '5 five FOLDED',
+ \ '6 six FOLDED',
+ \ ], getreg(0,1,1))
+
+ bwipe!
+endfunc
+
func Test_indent_fold()
new
call setline(1, ['', 'a', ' b', ' c'])
@@ -93,10 +142,44 @@ func Test_indent_fold2()
bw!
endfunc
+" Test for fold indent with indents greater than 'foldnestmax'
+func Test_indent_fold_max()
+ new
+ setlocal foldmethod=indent
+ setlocal shiftwidth=2
+ " 'foldnestmax' default value is 20
+ call setline(1, "\t\t\t\t\t\ta")
+ call assert_equal(20, foldlevel(1))
+ setlocal foldnestmax=10
+ call assert_equal(10, foldlevel(1))
+ setlocal foldnestmax=-1
+ call assert_equal(0, foldlevel(1))
+ bw!
+endfunc
+
+func Test_indent_fold_tabstop()
+ call setline(1, ['0', ' 1', ' 1', "\t2", "\t2"])
+ setlocal shiftwidth=4
+ setlocal foldcolumn=1
+ setlocal foldlevel=2
+ setlocal foldmethod=indent
+ redraw
+ call assert_equal('2 2', ScreenLines(5, 10)[0])
+ vsplit
+ windo diffthis
+ botright new
+ " This 'tabstop' value should not be used for folding in other buffers.
+ setlocal tabstop=4
+ diffoff!
+ redraw
+ call assert_equal('2 2', ScreenLines(5, 10)[0])
+
+ bwipe!
+ bwipe!
+endfunc
+
func Test_manual_fold_with_filter()
- if !executable('cat')
- return
- endif
+ CheckExecutable cat
for type in ['manual', 'marker']
exe 'set foldmethod=' . type
new
@@ -418,27 +501,6 @@ func Test_move_folds_around_indent()
bw!
endfunc
-" test for patch 7.3.637
-" Cannot catch the error caused by a foldopen when there is no fold.
-func Test_foldopen_exception()
- enew!
- let a = 'No error caught'
- try
- foldopen
- catch
- let a = matchstr(v:exception,'^[^ ]*')
- endtry
- call assert_equal('Vim(foldopen):E490:', a)
-
- let a = 'No error caught'
- try
- foobar
- catch
- let a = matchstr(v:exception,'^[^ ]*')
- endtry
- call assert_match('E492:', a)
-endfunc
-
func Test_folddoopen_folddoclosed()
new
call setline(1, range(1, 9))
@@ -492,11 +554,24 @@ func Test_fold_error()
bw!
endfunc
+func Test_foldtext_recursive()
+ new
+ call setline(1, ['{{{', 'some text', '}}}'])
+ setlocal foldenable foldmethod=marker foldtext=foldtextresult(v\:foldstart)
+ " This was crashing because of endless recursion.
+ 2foldclose
+ redraw
+ call assert_equal(1, foldlevel(2))
+ call assert_equal(1, foldclosed(2))
+ call assert_equal(3, foldclosedend(2))
+ bwipe!
+endfunc
+
" Various fold related tests
" Basic test if a fold can be created, opened, moving to the end and closed
func Test_fold_manual()
- enew!
+ new
set fdm=manual
let content = ['1 aa', '2 bb', '3 cc']
@@ -511,13 +586,67 @@ func Test_fold_manual()
normal zc
call assert_equal('1 aa', getline(foldclosed('.')))
+ " Create a fold inside a closed fold after setting 'foldlevel'
+ %d _
+ call setline(1, range(1, 5))
+ 1,5fold
+ normal zR
+ 2,4fold
+ set foldlevel=1
+ 3fold
+ call assert_equal([1, 3, 3, 3, 1], map(range(1, 5), {->foldlevel(v:val)}))
+ set foldlevel&
+
+ " Create overlapping folds (at the start and at the end)
+ normal zE
+ 2,3fold
+ normal zR
+ 3,4fold
+ call assert_equal([0, 2, 2, 1, 0], map(range(1, 5), {->foldlevel(v:val)}))
+ normal zE
+ 3,4fold
+ normal zR
+ 2,3fold
+ call assert_equal([0, 1, 2, 2, 0], map(range(1, 5), {->foldlevel(v:val)}))
+
+ " Create a nested fold across two non-adjoining folds
+ %d _
+ call setline(1, range(1, 7))
+ 1,2fold
+ normal zR
+ 4,5fold
+ normal zR
+ 6,7fold
+ normal zR
+ 1,5fold
+ call assert_equal([2, 2, 1, 2, 2, 1, 1],
+ \ map(range(1, 7), {->foldlevel(v:val)}))
+
+ " A newly created nested fold should be closed
+ %d _
+ call setline(1, range(1, 6))
+ 1,6fold
+ normal zR
+ 3,4fold
+ normal zR
+ 2,5fold
+ call assert_equal([1, 2, 3, 3, 2, 1], map(range(1, 6), {->foldlevel(v:val)}))
+ call assert_equal(2, foldclosed(4))
+ call assert_equal(5, foldclosedend(4))
+
+ " Test zO, zC and zA on a line with no folds.
+ normal zE
+ call assert_fails('normal zO', 'E490:')
+ call assert_fails('normal zC', 'E490:')
+ call assert_fails('normal zA', 'E490:')
+
set fdm&
- enew!
+ bw!
endfunc
" test folding with markers.
func Test_fold_marker()
- enew!
+ new
set fdm=marker fdl=1 fdc=3
let content = ['4 dd {{{', '5 ee {{{ }}}', '6 ff }}}']
@@ -531,13 +660,22 @@ func Test_fold_marker()
normal kYpj
call assert_equal(0, foldlevel('.'))
+ " Use only closing fold marker (without and with a count)
+ set fdl&
+ %d _
+ call setline(1, ['one }}}', 'two'])
+ call assert_equal([0, 0], [foldlevel(1), foldlevel(2)])
+ %d _
+ call setline(1, ['one }}}4', 'two'])
+ call assert_equal([4, 3], [foldlevel(1), foldlevel(2)])
+
set fdm& fdl& fdc&
- enew!
+ bw!
endfunc
" test create fold markers with C filetype
func Test_fold_create_marker_in_C()
- enew!
+ bw!
set fdm=marker fdl=9
set filetype=c
@@ -562,12 +700,12 @@ func Test_fold_create_marker_in_C()
endfor
set fdm& fdl&
- enew!
+ bw!
endfunc
" test folding with indent
func Test_fold_indent()
- enew!
+ new
set fdm=indent sw=2
let content = ['1 aa', '2 bb', '3 cc']
@@ -579,16 +717,14 @@ func Test_fold_indent()
call assert_equal(1, foldlevel('.'))
set fdm& sw&
- enew!
+ bw!
endfunc
" test syntax folding
func Test_fold_syntax()
- if !has('syntax')
- return
- endif
+ CheckFeature syntax
- enew!
+ new
set fdm=syntax fdl=0
syn region Hup start="dd" end="ii" fold contains=Fd1,Fd2,Fd3
@@ -612,7 +748,7 @@ func Test_fold_syntax()
syn clear Fd1 Fd2 Fd3 Hup
set fdm& fdl&
- enew!
+ bw!
endfunc
func Flvl()
@@ -631,7 +767,7 @@ endfun
" test expression folding
func Test_fold_expr()
- enew!
+ new
set fdm=expr fde=Flvl()
let content = ['1 aa',
@@ -659,14 +795,14 @@ func Test_fold_expr()
call assert_equal(0, foldlevel('.'))
set fdm& fde&
- enew!
+ bw!
endfunc
" Bug with fdm=indent and moving folds
" Moving a fold a few times, messes up the folds below the moved fold.
" Fixed by 7.4.700
func Test_fold_move()
- enew!
+ new
set fdm=indent sw=2 fdl=0
let content = ['', '', 'Line1', ' Line2', ' Line3',
@@ -686,24 +822,33 @@ func Test_fold_move()
call assert_equal('+-- 2 lines: Line8', 10->foldtextresult())
set fdm& sw& fdl&
- enew!
+ bw!
endfunc
-func Test_foldtext_recursive()
+" test for patch 7.3.637
+" Cannot catch the error caused by a foldopen when there is no fold.
+func Test_foldopen_exception()
new
- call setline(1, ['{{{', 'some text', '}}}'])
- setlocal foldenable foldmethod=marker foldtext=foldtextresult(v\:foldstart)
- " This was crashing because of endless recursion.
- 2foldclose
- redraw
- call assert_equal(1, foldlevel(2))
- call assert_equal(1, foldclosed(2))
- call assert_equal(3, foldclosedend(2))
- bwipe!
+ let a = 'No error caught'
+ try
+ foldopen
+ catch
+ let a = matchstr(v:exception,'^[^ ]*')
+ endtry
+ call assert_equal('Vim(foldopen):E490:', a)
+
+ let a = 'No error caught'
+ try
+ foobar
+ catch
+ let a = matchstr(v:exception,'^[^ ]*')
+ endtry
+ call assert_match('E492:', a)
+ bw!
endfunc
func Test_fold_last_line_with_pagedown()
- enew!
+ new
set fdm=manual
let expect = '+-- 11 lines: 9---'
@@ -723,13 +868,11 @@ func Test_fold_last_line_with_pagedown()
call assert_equal(expect, ScreenLines(1, len(expect))[0])
set fdm&
- enew!
+ bw!
endfunc
func Test_folds_with_rnu()
- if !CanRunVimInTerminal()
- throw 'Skipped: cannot make screendumps'
- endif
+ CheckScreendump
call writefile([
\ 'set fdm=marker rnu foldcolumn=2',
@@ -816,6 +959,55 @@ func Test_fold_delete_first_line()
set foldmethod&
endfunc
+" Add a test for deleting the outer fold of a nested fold and promoting the
+" inner folds to one level up with already a fold at that level following the
+" nested fold.
+func Test_fold_delete_recursive_fold()
+ new
+ call setline(1, range(1, 7))
+ 2,3fold
+ normal zR
+ 4,5fold
+ normal zR
+ 1,5fold
+ normal zR
+ 6,7fold
+ normal zR
+ normal 1Gzd
+ normal 1Gzj
+ call assert_equal(2, line('.'))
+ normal zj
+ call assert_equal(4, line('.'))
+ normal zj
+ call assert_equal(6, line('.'))
+ bw!
+endfunc
+
+" Test for errors in 'foldexpr'
+func Test_fold_expr_error()
+ new
+ call setline(1, ['one', 'two', 'three'])
+ " In a window with no folds, foldlevel() should return 0
+ call assert_equal(0, foldlevel(1))
+
+ " Return a list from the expression
+ set foldexpr=[]
+ set foldmethod=expr
+ for i in range(3)
+ call assert_equal(0, foldlevel(i))
+ endfor
+
+ " expression error
+ set foldexpr=[{]
+ set foldmethod=expr
+ for i in range(3)
+ call assert_equal(0, foldlevel(i))
+ endfor
+
+ set foldmethod& foldexpr&
+ close!
+endfunc
+
func Test_undo_fold_deletion()
new
set fdm=marker
@@ -899,6 +1091,264 @@ func Test_fold_relative_move()
call assert_equal(2, winline())
set fdm& sw& wrap& tw&
+ bw!
+endfunc
+
+" Test for calling foldlevel() from a fold expression
+let g:FoldLevels = []
+func FoldExpr1(lnum)
+ let f = [a:lnum]
+ for i in range(1, line('$'))
+ call add(f, foldlevel(i))
+ endfor
+ call add(g:FoldLevels, f)
+ return getline(a:lnum)[0] == "\t"
+endfunc
+
+func Test_foldexpr_foldlevel()
+ new
+ call setline(1, ['one', "\ttwo", "\tthree"])
+ setlocal foldmethod=expr
+ setlocal foldexpr=FoldExpr1(v:lnum)
+ setlocal foldenable
+ setlocal foldcolumn=3
+ redraw!
+ call assert_equal([[1, -1, -1, -1], [2, -1, -1, -1], [3, 0, 1, -1]],
+ \ g:FoldLevels)
+ set foldmethod& foldexpr& foldenable& foldcolumn&
+ bw!
+endfunc
+
+" Test for returning different values from a fold expression
+func FoldExpr2(lnum)
+ if a:lnum == 1 || a:lnum == 4
+ return -2
+ elseif a:lnum == 2
+ return 'a1'
+ elseif a:lnum == 3
+ return 's4'
+ endif
+ return '='
+endfunc
+
+func Test_foldexpr_2()
+ new
+ call setline(1, ['one', 'two', 'three', 'four'])
+ setlocal foldexpr=FoldExpr2(v:lnum)
+ setlocal foldmethod=expr
+ call assert_equal([0, 1, 1, 0], [foldlevel(1), foldlevel(2), foldlevel(3),
+ \ foldlevel(4)])
+ bw!
+endfunc
+
+" Test for the 'foldclose' option
+func Test_foldclose_opt()
+ CheckScreendump
+
+ let lines =<< trim END
+ set foldmethod=manual foldclose=all foldopen=all
+ call setline(1, ['one', 'two', 'three', 'four'])
+ 2,3fold
+ func XsaveFoldLevels()
+ redraw!
+ call writefile([json_encode([foldclosed(1), foldclosed(2), foldclosed(3),
+ \ foldclosed(4)])], 'Xoutput', 'a')
+ endfunc
+ END
+ call writefile(lines, 'Xscript')
+ let rows = 10
+ let buf = RunVimInTerminal('-S Xscript', {'rows': rows})
+ call term_wait(buf)
+ call term_sendkeys(buf, ":set noruler\n")
+ call term_wait(buf)
+ call term_sendkeys(buf, ":call XsaveFoldLevels()\n")
+ call term_sendkeys(buf, "2G")
+ call WaitForAssert({-> assert_equal('two', term_getline(buf, 2))})
+ call term_sendkeys(buf, ":call XsaveFoldLevels()\n")
+ call term_sendkeys(buf, "4G")
+ call WaitForAssert({-> assert_equal('four', term_getline(buf, 3))})
+ call term_sendkeys(buf, ":call XsaveFoldLevels()\n")
+ call term_sendkeys(buf, "3G")
+ call WaitForAssert({-> assert_equal('three', term_getline(buf, 3))})
+ call term_sendkeys(buf, ":call XsaveFoldLevels()\n")
+ call term_sendkeys(buf, "1G")
+ call WaitForAssert({-> assert_equal('four', term_getline(buf, 3))})
+ call term_sendkeys(buf, ":call XsaveFoldLevels()\n")
+ call term_sendkeys(buf, "2G")
+ call WaitForAssert({-> assert_equal('two', term_getline(buf, 2))})
+ call term_sendkeys(buf, "k")
+ call WaitForAssert({-> assert_equal('four', term_getline(buf, 3))})
+
+ " clean up
+ call StopVimInTerminal(buf)
+
+ call assert_equal(['[-1,2,2,-1]', '[-1,-1,-1,-1]', '[-1,2,2,-1]',
+ \ '[-1,-1,-1,-1]', '[-1,2,2,-1]'], readfile('Xoutput'))
+ call delete('Xscript')
+ call delete('Xoutput')
+endfunc
+
+" Test for foldtextresult()
+func Test_foldtextresult()
+ new
+ call assert_equal('', foldtextresult(-1))
+ call assert_equal('', foldtextresult(0))
+ call assert_equal('', foldtextresult(1))
+ call setline(1, ['one', 'two', 'three', 'four'])
+ 2,3fold
+ call assert_equal('', foldtextresult(1))
+ call assert_equal('+-- 2 lines: two', foldtextresult(2))
+ setlocal foldtext=
+ call assert_equal('+-- 2 lines folded ', foldtextresult(2))
+
+ " Fold text for a C comment fold
+ %d _
+ setlocal foldtext&
+ call setline(1, ['', '/*', ' * Comment', ' */', ''])
+ 2,4fold
+ call assert_equal('+-- 3 lines: Comment', foldtextresult(2))
+
+ bw!
+endfunc
+
+" Test for merging two recursive folds when an intermediate line with no fold
+" is removed
+func Test_fold_merge_recursive()
+ new
+ call setline(1, [' one', ' two', 'xxxx', ' three',
+ \ ' four', "\tfive"])
+ setlocal foldmethod=indent shiftwidth=2
+ 3d_
+ %foldclose
+ call assert_equal([1, 5], [foldclosed(5), foldclosedend(1)])
+ bw!
+endfunc
+
+" Test for moving a line which is the start of a fold from a recursive fold to
+" outside. The fold length should reduce.
+func Test_fold_move_foldlevel()
+ new
+ call setline(1, ['a{{{', 'b{{{', 'c{{{', 'd}}}', 'e}}}', 'f}}}', 'g'])
+ setlocal foldmethod=marker
+ normal zR
+ call assert_equal([3, 2, 1], [foldlevel(4), foldlevel(5), foldlevel(6)])
+ 3move 7
+ call assert_equal([2, 1, 0], [foldlevel(3), foldlevel(4), foldlevel(5)])
+ call assert_equal(1, foldlevel(7))
+
+ " Move a line from outside a fold to inside the fold.
+ %d _
+ call setline(1, ['a', 'b{{{', 'c}}}'])
+ normal zR
+ 1move 2
+ call assert_equal([1, 1, 1], [foldlevel(1), foldlevel(2), foldlevel(3)])
+
+ " Move the start of one fold to inside another fold
+ %d _
+ call setline(1, ['a', 'b{{{', 'c}}}', 'd{{{', 'e}}}'])
+ normal zR
+ call assert_equal([0, 1, 1, 1, 1], [foldlevel(1), foldlevel(2),
+ \ foldlevel(3), foldlevel(4), foldlevel(5)])
+ 1,2move 4
+ call assert_equal([0, 1, 1, 2, 2], [foldlevel(1), foldlevel(2),
+ \ foldlevel(3), foldlevel(4), foldlevel(5)])
+
+ bw!
+endfunc
+
+" Test for using zj and zk to move downwards and upwards to the start and end
+" of the next fold.
+" Test for using [z and ]z in a closed fold to jump to the beginning and end
+" of the fold.
+func Test_fold_jump()
+ new
+ call setline(1, ["\t1", "\t2", "\t\t3", "\t\t4", "\t\t\t5", "\t\t\t6", "\t\t7", "\t\t8", "\t9", "\t10"])
+ setlocal foldmethod=indent
+ normal zR
+ normal zj
+ call assert_equal(3, line('.'))
+ normal zj
+ call assert_equal(5, line('.'))
+ call assert_beeps('normal zj')
+ call assert_equal(5, line('.'))
+ call assert_beeps('normal 9Gzj')
+ call assert_equal(9, line('.'))
+ normal Gzk
+ call assert_equal(8, line('.'))
+ normal zk
+ call assert_equal(6, line('.'))
+ call assert_beeps('normal zk')
+ call assert_equal(6, line('.'))
+ call assert_beeps('normal 2Gzk')
+ call assert_equal(2, line('.'))
+
+ " Using [z or ]z in a closed fold should not move the cursor
+ %d _
+ call setline(1, ["1", "\t2", "\t3", "\t4", "\t5", "\t6", "7"])
+ normal zR4Gzc
+ call assert_equal(4, line('.'))
+ call assert_beeps('normal [z')
+ call assert_equal(4, line('.'))
+ call assert_beeps('normal ]z')
+ call assert_equal(4, line('.'))
+ bw!
+endfunc
+
+" Test for using a script-local function for 'foldexpr'
+func Test_foldexpr_scriptlocal_func()
+ func! s:FoldFunc()
+ let g:FoldLnum = v:lnum
+ endfunc
+ new | only
+ call setline(1, 'abc')
+ let g:FoldLnum = 0
+ set foldmethod=expr foldexpr=s:FoldFunc()
+ redraw!
+ call assert_equal(expand('<SID>') .. 'FoldFunc()', &foldexpr)
+ call assert_equal(1, g:FoldLnum)
+ set foldmethod& foldexpr=
+ bw!
+ new | only
+ call setline(1, 'abc')
+ let g:FoldLnum = 0
+ set foldmethod=expr foldexpr=<SID>FoldFunc()
+ redraw!
+ call assert_equal(expand('<SID>') .. 'FoldFunc()', &foldexpr)
+ call assert_equal(1, g:FoldLnum)
+ set foldmethod& foldexpr=
+ delfunc s:FoldFunc
+ bw!
+endfunc
+
+" Test for using a script-local function for 'foldtext'
+func Test_foldtext_scriptlocal_func()
+ func! s:FoldText()
+ let g:FoldTextArgs = [v:foldstart, v:foldend]
+ return foldtext()
+ endfunc
+ new | only
+ call setline(1, range(50))
+ let g:FoldTextArgs = []
+ set foldmethod=manual
+ set foldtext=s:FoldText()
+ norm! 4Gzf4j
+ redraw!
+ call assert_equal(expand('<SID>') .. 'FoldText()', &foldtext)
+ call assert_equal([4, 8], g:FoldTextArgs)
+ set foldtext&
+ bw!
+ new | only
+ call setline(1, range(50))
+ let g:FoldTextArgs = []
+ set foldmethod=manual
+ set foldtext=<SID>FoldText()
+ norm! 8Gzf4j
+ redraw!
+ call assert_equal(expand('<SID>') .. 'FoldText()', &foldtext)
+ call assert_equal([8, 12], g:FoldTextArgs)
+ set foldtext&
+ bw!
+ delfunc s:FoldText
endfunc
" Make sure a fold containing a nested fold is split correctly when using
@@ -989,4 +1439,61 @@ func Test_indent_append_blank_small_fold_close()
bw!
endfunc
+func Test_sort_closed_fold()
+ CheckExecutable sort
+
+ call setline(1, [
+ \ 'Section 1',
+ \ ' how',
+ \ ' now',
+ \ ' brown',
+ \ ' cow',
+ \ 'Section 2',
+ \ ' how',
+ \ ' now',
+ \ ' brown',
+ \ ' cow',
+ \])
+ setlocal foldmethod=indent sw=3
+ normal 2G
+
+ " The "!!" expands to ".,.+3" and must only sort four lines
+ call feedkeys("!!sort\<CR>", 'xt')
+ call assert_equal([
+ \ 'Section 1',
+ \ ' brown',
+ \ ' cow',
+ \ ' how',
+ \ ' now',
+ \ 'Section 2',
+ \ ' how',
+ \ ' now',
+ \ ' brown',
+ \ ' cow',
+ \ ], getline(1, 10))
+
+ bwipe!
+endfunc
+
+func Test_indent_with_L_command()
+ " The "L" command moved the cursor to line zero, causing the text saved for
+ " undo to use line number -1, which caused trouble for undo later.
+ new
+ sil! norm 8R V{zf8=Lu
+ bwipe!
+endfunc
+
+" Make sure that when there is a fold at the bottom of the buffer and a newline
+" character is appended to the line, the fold gets expanded (instead of the new
+" line not being part of the fold).
+func Test_expand_fold_at_bottom_of_buffer()
+ new
+ " create a fold on the only line
+ fold
+ execute "normal A\<CR>"
+ call assert_equal([1, 1], range(1, 2)->map('foldlevel(v:val)'))
+
+ bwipe!
+endfunc
+
" vim: shiftwidth=2 sts=2 expandtab
diff --git a/src/nvim/testdir/test_functions.vim b/src/nvim/testdir/test_functions.vim
index 44b6f0373e..500c30c76b 100644
--- a/src/nvim/testdir/test_functions.vim
+++ b/src/nvim/testdir/test_functions.vim
@@ -2,6 +2,9 @@
source shared.vim
source check.vim
+source term_util.vim
+source screendump.vim
+source vim9.vim
" Must be done first, since the alternate buffer must be unset.
func Test_00_bufexists()
@@ -19,6 +22,27 @@ func Test_00_bufexists()
call assert_equal(0, bufexists('Xfoo'))
endfunc
+func Test_has()
+ throw 'Skipped: Nvim has removed some features'
+ call assert_equal(1, has('eval'))
+ call assert_equal(1, has('eval', 1))
+
+ if has('unix')
+ call assert_equal(1, or(has('ttyin'), 1))
+ call assert_equal(0, and(has('ttyout'), 0))
+ call assert_equal(1, has('multi_byte_encoding'))
+ endif
+ call assert_equal(1, has('vcon', 1))
+ call assert_equal(1, has('mouse_gpm_enabled', 1))
+
+ call assert_equal(0, has('nonexistent'))
+ call assert_equal(0, has('nonexistent', 1))
+
+ " Will we ever have patch 9999?
+ let ver = 'patch-' .. v:version / 100 .. '.' .. v:version % 100 .. '.9999'
+ call assert_equal(0, has(ver))
+endfunc
+
func Test_empty()
call assert_equal(1, empty(''))
call assert_equal(0, empty('a'))
@@ -67,9 +91,11 @@ func Test_len()
call assert_equal(2, len('ab'))
call assert_equal(0, len([]))
+ call assert_equal(0, len(v:_null_list))
call assert_equal(2, len([2, 1]))
call assert_equal(0, len({}))
+ call assert_equal(0, len(v:_null_dict))
call assert_equal(2, len({'a': 1, 'b': 2}))
" call assert_fails('call len(v:none)', 'E701:')
@@ -87,6 +113,10 @@ func Test_max()
call assert_fails('call max(1)', 'E712:')
" call assert_fails('call max(v:none)', 'E712:')
+
+ " check we only get one error
+ call assert_fails('call max([#{}, [1]])', ['E728:', 'E728:'])
+ call assert_fails('call max(#{a: {}, b: [1]})', ['E728:', 'E728:'])
endfunc
func Test_min()
@@ -100,6 +130,11 @@ func Test_min()
call assert_fails('call min(1)', 'E712:')
" call assert_fails('call min(v:none)', 'E712:')
+ call assert_fails('call min([1, {}])', 'E728:')
+
+ " check we only get one error
+ call assert_fails('call min([[1], #{}])', ['E745:', 'E745:'])
+ call assert_fails('call min(#{a: [1], b: #{}})', ['E745:', 'E745:'])
endfunc
func Test_strwidth()
@@ -188,7 +223,7 @@ func Test_str2nr()
if has('float')
call assert_fails('call str2nr(1.2)', 'E806:')
endif
- call assert_fails('call str2nr(10, [])', 'E474:')
+ call assert_fails('call str2nr(10, [])', 'E745:')
endfunc
func Test_strftime()
@@ -381,6 +416,8 @@ func Test_strpart()
call assert_equal('abcdefg', 'abcdefg'->strpart(-2))
call assert_equal('fg', strpart('abcdefg', 5, 4))
call assert_equal('defg', strpart('abcdefg', 3))
+ call assert_equal('', strpart('abcdefg', 10))
+ call assert_fails("let s=strpart('abcdef', [])", 'E745:')
call assert_equal('lép', strpart('éléphant', 2, 4))
call assert_equal('léphant', strpart('éléphant', 2))
@@ -462,6 +499,12 @@ func Test_tolower()
" invalid memory.
call tolower("\xC0\x80\xC0")
call tolower("123\xC0\x80\xC0")
+
+ " Test in latin1 encoding
+ let save_enc = &encoding
+ " set encoding=latin1
+ call assert_equal("abc", tolower("ABC"))
+ let &encoding = save_enc
endfunc
func Test_toupper()
@@ -533,11 +576,27 @@ func Test_toupper()
" invalid memory.
call toupper("\xC0\x80\xC0")
call toupper("123\xC0\x80\xC0")
+
+ " Test in latin1 encoding
+ let save_enc = &encoding
+ " set encoding=latin1
+ call assert_equal("ABC", toupper("abc"))
+ let &encoding = save_enc
endfunc
func Test_tr()
call assert_equal('foo', tr('bar', 'bar', 'foo'))
call assert_equal('zxy', 'cab'->tr('abc', 'xyz'))
+ call assert_fails("let s=tr([], 'abc', 'def')", 'E730:')
+ call assert_fails("let s=tr('abc', [], 'def')", 'E730:')
+ call assert_fails("let s=tr('abc', 'abc', [])", 'E730:')
+ call assert_fails("let s=tr('abcd', 'abcd', 'def')", 'E475:')
+ " set encoding=latin1
+ call assert_fails("let s=tr('abcd', 'abcd', 'def')", 'E475:')
+ call assert_equal('hEllO', tr('hello', 'eo', 'EO'))
+ call assert_equal('hello', tr('hello', 'xy', 'ab'))
+ call assert_fails('call tr("abc", "123", "₁₂")', 'E475:')
+ set encoding=utf8
endfunc
" Tests for the mode() function
@@ -752,13 +811,41 @@ func Test_mode()
delfunction OperatorFunc
endfunc
+" Test for append()
func Test_append()
enew!
split
call append(0, ["foo"])
+ call append(1, [])
+ call append(1, v:_null_list)
+ call assert_equal(['foo', ''], getline(1, '$'))
split
only
undo
+ undo
+
+ " Using $ instead of '$' must give an error
+ call assert_fails("call append($, 'foobar')", 'E116:')
+
+ call assert_fails("call append({}, '')", ['E728:', 'E728:'])
+endfunc
+
+" Test for setline()
+func Test_setline()
+ new
+ call setline(0, ["foo"])
+ call setline(0, [])
+ call setline(0, v:_null_list)
+ call setline(1, ["bar"])
+ call setline(1, [])
+ call setline(1, v:_null_list)
+ call setline(2, [])
+ call setline(2, v:_null_list)
+ call setline(3, [])
+ call setline(3, v:_null_list)
+ call setline(2, ["baz"])
+ call assert_equal(['bar', 'baz'], getline(1, '$'))
+ close!
endfunc
func Test_getbufvar()
@@ -792,6 +879,10 @@ func Test_getbufvar()
call assert_equal(0, getbufvar(bnr, '&autoindent'))
call assert_equal(0, getbufvar(bnr, '&autoindent', 1))
+ " Set and get a buffer-local variable
+ call setbufvar(bnr, 'bufvar_test', ['one', 'two'])
+ call assert_equal(['one', 'two'], getbufvar(bnr, 'bufvar_test'))
+
" Open new window with forced option values
set fileformats=unix,dos
new ++ff=dos ++bin ++enc=iso-8859-2
@@ -830,6 +921,8 @@ func Test_stridx()
call assert_equal(-1, stridx('hello', 'l', 10))
call assert_equal(2, stridx('hello', 'll'))
call assert_equal(-1, stridx('hello', 'hello world'))
+ call assert_fails("let n=stridx('hello', [])", 'E730:')
+ call assert_fails("let n=stridx([], 'l')", 'E730:')
endfunc
func Test_strridx()
@@ -846,6 +939,8 @@ func Test_strridx()
call assert_equal(-1, strridx('hello', 'l', -1))
call assert_equal(2, strridx('hello', 'll'))
call assert_equal(-1, strridx('hello', 'hello world'))
+ call assert_fails("let n=strridx('hello', [])", 'E730:')
+ call assert_fails("let n=strridx([], 'l')", 'E730:')
endfunc
func Test_match_func()
@@ -855,6 +950,13 @@ func Test_match_func()
call assert_equal(-1, match('testing', 'ing', 8))
call assert_equal(1, match(['vim', 'testing', 'execute'], 'ing'))
call assert_equal(-1, match(['vim', 'testing', 'execute'], 'img'))
+ call assert_fails("let x=match('vim', [])", 'E730:')
+ call assert_equal(3, match(['a', 'b', 'c', 'a'], 'a', 1))
+ call assert_equal(-1, match(['a', 'b', 'c', 'a'], 'a', 5))
+ call assert_equal(4, match('testing', 'ing', -1))
+ call assert_fails("let x=match('testing', 'ing', 0, [])", 'E745:')
+ call assert_equal(-1, match(v:_null_list, 2))
+ call assert_equal(-1, match('abc', '\\%('))
endfunc
func Test_matchend()
@@ -961,6 +1063,7 @@ func Test_byte2line_line2byte()
bw!
endfunc
+" Test for byteidx() and byteidxcomp() functions
func Test_byteidx()
let a = '.é.' " one char of two bytes
call assert_equal(0, byteidx(a, 0))
@@ -980,6 +1083,7 @@ func Test_byteidx()
call assert_equal(4, b->byteidx(2))
call assert_equal(5, b->byteidx(3))
call assert_equal(-1, b->byteidx(4))
+ call assert_fails("call byteidx([], 0)", 'E730:')
call assert_equal(0, b->byteidxcomp(0))
call assert_equal(1, b->byteidxcomp(1))
@@ -987,6 +1091,7 @@ func Test_byteidx()
call assert_equal(4, b->byteidxcomp(3))
call assert_equal(5, b->byteidxcomp(4))
call assert_equal(-1, b->byteidxcomp(5))
+ call assert_fails("call byteidxcomp([], 0)", 'E730:')
endfunc
" Test for charidx()
@@ -997,7 +1102,9 @@ func Test_charidx()
call assert_equal(2, charidx(a, 4))
call assert_equal(3, charidx(a, 7))
call assert_equal(-1, charidx(a, 8))
+ call assert_equal(-1, charidx(a, -1))
call assert_equal(-1, charidx('', 0))
+ call assert_equal(-1, charidx(v:_null_string, 0))
" count composing characters
call assert_equal(0, charidx(a, 0, 1))
@@ -1010,8 +1117,8 @@ func Test_charidx()
call assert_fails('let x = charidx([], 1)', 'E474:')
call assert_fails('let x = charidx("abc", [])', 'E474:')
call assert_fails('let x = charidx("abc", 1, [])', 'E474:')
- call assert_fails('let x = charidx("abc", 1, -1)', 'E474:')
- call assert_fails('let x = charidx("abc", 1, 2)', 'E474:')
+ call assert_fails('let x = charidx("abc", 1, -1)', 'E1023:')
+ call assert_fails('let x = charidx("abc", 1, 2)', 'E1023:')
endfunc
func Test_count()
@@ -1096,6 +1203,10 @@ func Test_filewritable()
call assert_equal(0, filewritable('doesnotexist'))
+ call mkdir('Xdir')
+ call assert_equal(2, filewritable('Xdir'))
+ call delete('Xdir', 'd')
+
call delete('Xfilewritable')
bw!
endfunc
@@ -1179,6 +1290,7 @@ func Test_col()
norm gg4|mx6|mY2|
call assert_equal(2, col('.'))
call assert_equal(7, col('$'))
+ call assert_equal(2, col('v'))
call assert_equal(4, col("'x"))
call assert_equal(6, col("'Y"))
call assert_equal(2, [1, 2]->col())
@@ -1189,6 +1301,47 @@ func Test_col()
call assert_equal(0, col([2, '$']))
call assert_equal(0, col([1, 100]))
call assert_equal(0, col([1]))
+ call assert_equal(0, col(v:_null_list))
+ call assert_fails('let c = col({})', 'E1222:')
+ call assert_fails('let c = col(".", [])', 'E1210:')
+
+ " test for getting the visual start column
+ func T()
+ let g:Vcol = col('v')
+ return ''
+ endfunc
+ let g:Vcol = 0
+ xmap <expr> <F2> T()
+ exe "normal gg3|ve\<F2>"
+ call assert_equal(3, g:Vcol)
+ xunmap <F2>
+ delfunc T
+
+ " Test for the visual line start and end marks '< and '>
+ call setline(1, ['one', 'one two', 'one two three'])
+ "normal! ggVG
+ call feedkeys("ggVG\<Esc>", 'xt')
+ call assert_equal(1, col("'<"))
+ call assert_equal(14, col("'>"))
+ " Delete the last line of the visually selected region
+ $d
+ call assert_notequal(14, col("'>"))
+
+ " Test with 'virtualedit'
+ set virtualedit=all
+ call cursor(1, 10)
+ call assert_equal(4, col('.'))
+ set virtualedit&
+
+ " Test for getting the column number in another window
+ let winid = win_getid()
+ new
+ call win_execute(winid, 'normal 1G$')
+ call assert_equal(3, col('.', winid))
+ call win_execute(winid, 'normal 2G')
+ call assert_equal(8, col('$', winid))
+ call assert_equal(0, col('.', 5001))
+
bw!
endfunc
@@ -1232,12 +1385,15 @@ endfunc
" Test for the inputdialog() function
func Test_inputdialog()
- CheckNotGui
-
- call feedkeys(":let v=inputdialog('Q:', 'xx', 'yy')\<CR>\<CR>", 'xt')
- call assert_equal('xx', v)
- call feedkeys(":let v=inputdialog('Q:', 'xx', 'yy')\<CR>\<Esc>", 'xt')
- call assert_equal('yy', v)
+ if has('gui_running')
+ call assert_fails('let v=inputdialog([], "xx")', 'E730:')
+ call assert_fails('let v=inputdialog("Q", [])', 'E730:')
+ else
+ call feedkeys(":let v=inputdialog('Q:', 'xx', 'yy')\<CR>\<CR>", 'xt')
+ call assert_equal('xx', v)
+ call feedkeys(":let v=inputdialog('Q:', 'xx', 'yy')\<CR>\<Esc>", 'xt')
+ call assert_equal('yy', v)
+ endif
endfunc
" Test for inputlist()
@@ -1270,26 +1426,39 @@ func Test_inputlist()
call assert_equal(2, c)
" Use mouse to make a selection
- " call test_setmouse(&lines - 3, 2)
- call nvim_input_mouse('left', 'press', '', 0, &lines - 4, 1) " set mouse position
- call getchar() " discard mouse event but keep mouse position
+ call Ntest_setmouse(&lines - 3, 2)
call feedkeys(":let c = inputlist(['Select color:', '1. red', '2. green', '3. blue'])\<cr>\<LeftMouse>", 'tx')
call assert_equal(1, c)
" Mouse click outside of the list
- " call test_setmouse(&lines - 6, 2)
- call nvim_input_mouse('left', 'press', '', 0, &lines - 7, 1) " set mouse position
- call getchar() " discard mouse event but keep mouse position
+ call Ntest_setmouse(&lines - 6, 2)
call feedkeys(":let c = inputlist(['Select color:', '1. red', '2. green', '3. blue'])\<cr>\<LeftMouse>", 'tx')
call assert_equal(-2, c)
call assert_fails('call inputlist("")', 'E686:')
endfunc
+func Test_range_inputlist()
+ " flush out any garbage left in the buffer
+ while getchar(0)
+ endwhile
+
+ call feedkeys(":let result = inputlist(range(10))\<CR>1\<CR>", 'x')
+ call assert_equal(1, result)
+ call feedkeys(":let result = inputlist(range(3, 10))\<CR>1\<CR>", 'x')
+ call assert_equal(1, result)
+
+ unlet result
+endfunc
+
func Test_balloon_show()
CheckFeature balloon_eval
" This won't do anything but must not crash either.
call balloon_show('hi!')
+ if !has('gui_running')
+ call balloon_show(range(3))
+ call balloon_show([])
+ endif
endfunc
func Test_shellescape()
@@ -1420,12 +1589,15 @@ func Test_trim()
call assert_equal("vim", trim(" vim ", " ", 0))
call assert_equal("vim ", trim(" vim ", " ", 1))
call assert_equal(" vim", trim(" vim ", " ", 2))
- call assert_fails('call trim(" vim ", " ", [])', 'E745:')
- call assert_fails('call trim(" vim ", " ", -1)', 'E475:')
- call assert_fails('call trim(" vim ", " ", 3)', 'E475:')
+ call assert_fails('eval trim(" vim ", " ", [])', 'E745:')
+ call assert_fails('eval trim(" vim ", " ", -1)', 'E475:')
+ call assert_fails('eval trim(" vim ", " ", 3)', 'E475:')
+ call assert_fails('eval trim(" vim ", 0)', 'E475:')
let chars = join(map(range(1, 0x20) + [0xa0], {n -> n->nr2char()}), '')
call assert_equal("x", trim(chars . "x" . chars))
+
+ call assert_fails('let c=trim([])', 'E730:')
endfunc
" Test for reg_recording() and reg_executing()
@@ -1534,13 +1706,12 @@ func Test_getchar()
call assert_equal(0, getchar(0))
call setline(1, 'xxxx')
- " call test_setmouse(1, 3)
- " let v:mouse_win = 9
- " let v:mouse_winid = 9
- " let v:mouse_lnum = 9
- " let v:mouse_col = 9
- " call feedkeys("\<S-LeftMouse>", '')
- call nvim_input_mouse('left', 'press', 'S', 0, 0, 2)
+ call Ntest_setmouse(1, 3)
+ let v:mouse_win = 9
+ let v:mouse_winid = 9
+ let v:mouse_lnum = 9
+ let v:mouse_col = 9
+ call feedkeys("\<S-LeftMouse>", '')
call assert_equal("\<S-LeftMouse>", getchar())
call assert_equal(1, v:mouse_win)
call assert_equal(win_getid(1), v:mouse_winid)
@@ -1598,11 +1769,11 @@ func Test_libcall_libcallnr()
call assert_equal(4, 'abcd'->libcallnr(libc, 'strlen'))
call assert_equal(char2nr('A'), char2nr('a')->libcallnr(libc, 'toupper'))
- call assert_fails("call libcall(libc, 'Xdoesnotexist_', '')", 'E364:')
- call assert_fails("call libcallnr(libc, 'Xdoesnotexist_', '')", 'E364:')
+ call assert_fails("call libcall(libc, 'Xdoesnotexist_', '')", ['', 'E364:'])
+ call assert_fails("call libcallnr(libc, 'Xdoesnotexist_', '')", ['', 'E364:'])
- call assert_fails("call libcall('Xdoesnotexist_', 'getenv', 'HOME')", 'E364:')
- call assert_fails("call libcallnr('Xdoesnotexist_', 'strlen', 'abcd')", 'E364:')
+ call assert_fails("call libcall('Xdoesnotexist_', 'getenv', 'HOME')", ['', 'E364:'])
+ call assert_fails("call libcallnr('Xdoesnotexist_', 'strlen', 'abcd')", ['', 'E364:'])
endfunc
sandbox function Fsandbox()
@@ -1619,6 +1790,10 @@ func Test_func_sandbox()
call assert_fails('call Fsandbox()', 'E48:')
delfunc Fsandbox
+
+ " From a sandbox try to set a predefined variable (which cannot be modified
+ " from a sandbox)
+ call assert_fails('sandbox let v:lnum = 10', 'E794:')
endfunc
func EditAnotherFile()
@@ -1697,6 +1872,62 @@ func Test_platform_name()
endif
endfunc
+" Test confirm({msg} [, {choices} [, {default} [, {type}]]])
+func Test_confirm()
+ " requires a UI to be active
+ throw 'Skipped: use test/functional/vimscript/input_spec.lua'
+ CheckUnix
+ CheckNotGui
+
+ call feedkeys('o', 'L')
+ let a = confirm('Press O to proceed')
+ call assert_equal(1, a)
+
+ call feedkeys('y', 'L')
+ let a = 'Are you sure?'->confirm("&Yes\n&No")
+ call assert_equal(1, a)
+
+ call feedkeys('n', 'L')
+ let a = confirm('Are you sure?', "&Yes\n&No")
+ call assert_equal(2, a)
+
+ " confirm() should return 0 when pressing CTRL-C.
+ call feedkeys("\<C-C>", 'L')
+ let a = confirm('Are you sure?', "&Yes\n&No")
+ call assert_equal(0, a)
+
+ " <Esc> requires another character to avoid it being seen as the start of an
+ " escape sequence. Zero should be harmless.
+ eval "\<Esc>0"->feedkeys('L')
+ let a = confirm('Are you sure?', "&Yes\n&No")
+ call assert_equal(0, a)
+
+ " Default choice is returned when pressing <CR>.
+ call feedkeys("\<CR>", 'L')
+ let a = confirm('Are you sure?', "&Yes\n&No")
+ call assert_equal(1, a)
+
+ call feedkeys("\<CR>", 'L')
+ let a = confirm('Are you sure?', "&Yes\n&No", 2)
+ call assert_equal(2, a)
+
+ call feedkeys("\<CR>", 'L')
+ let a = confirm('Are you sure?', "&Yes\n&No", 0)
+ call assert_equal(0, a)
+
+ " Test with the {type} 4th argument
+ for type in ['Error', 'Question', 'Info', 'Warning', 'Generic']
+ call feedkeys('y', 'L')
+ let a = confirm('Are you sure?', "&Yes\n&No\n", 1, type)
+ call assert_equal(1, a)
+ endfor
+
+ call assert_fails('call confirm([])', 'E730:')
+ call assert_fails('call confirm("Are you sure?", [])', 'E730:')
+ call assert_fails('call confirm("Are you sure?", "&Yes\n&No\n", [])', 'E745:')
+ call assert_fails('call confirm("Are you sure?", "&Yes\n&No\n", 0, [])', 'E730:')
+endfunc
+
func Test_readdir()
call mkdir('Xdir')
call writefile([], 'Xdir/foo.txt')
@@ -1724,7 +1955,7 @@ func Test_readdir()
let files = readdir('Xdir', {x -> len(add(l, x)) == 2 ? -1 : 1})
call assert_equal(1, len(files))
- call delete('Xdir', 'rf')
+ eval 'Xdir'->delete('rf')
endfunc
func Test_delete_rf()
@@ -1756,6 +1987,7 @@ func Test_call()
call assert_equal(3, 'len'->call([123]))
call assert_fails("call call('len', 123)", 'E714:')
call assert_equal(0, call('', []))
+ call assert_equal(0, call('len', v:_null_list))
function Mylen() dict
return len(self.data)
@@ -1763,10 +1995,15 @@ func Test_call()
let mydict = {'data': [0, 1, 2, 3], 'len': function("Mylen")}
eval mydict.len->call([], mydict)->assert_equal(4)
call assert_fails("call call('Mylen', [], 0)", 'E715:')
+ call assert_fails('call foo', 'E107:')
endfunc
func Test_char2nr()
call assert_equal(12354, char2nr('あ', 1))
+ call assert_equal(120, 'x'->char2nr())
+ " set encoding=latin1
+ call assert_equal(120, 'x'->char2nr())
+ set encoding=utf-8
endfunc
func Test_charclass()
@@ -1819,17 +2056,329 @@ func Test_bufadd_bufload()
exe 'bwipe ' .. buf2
call assert_equal(0, bufexists(buf2))
+ " When 'buftype' is "nofile" then bufload() does not read the file.
+ " Other values too.
+ for val in [['nofile', 0],
+ \ ['nowrite', 1],
+ \ ['acwrite', 1],
+ \ ['quickfix', 0],
+ \ ['help', 1],
+ "\ ['terminal', 0],
+ \ ['prompt', 0],
+ "\ ['popup', 0],
+ \ ]
+ bwipe! XotherName
+ let buf = bufadd('XotherName')
+ call setbufvar(buf, '&bt', val[0])
+ call bufload(buf)
+ call assert_equal(val[1] ? ['some', 'text'] : [''], getbufline(buf, 1, '$'), val[0])
+ endfor
+
bwipe someName
bwipe XotherName
call assert_equal(0, bufexists('someName'))
call delete('XotherName')
endfunc
+func Test_range()
+ " destructuring
+ let [x, y] = range(2)
+ call assert_equal([0, 1], [x, y])
+
+ " index
+ call assert_equal(4, range(1, 10)[3])
+
+ " add()
+ call assert_equal([0, 1, 2, 3], add(range(3), 3))
+ call assert_equal([0, 1, 2, [0, 1, 2]], add([0, 1, 2], range(3)))
+ call assert_equal([0, 1, 2, [0, 1, 2]], add(range(3), range(3)))
+
+ " append()
+ new
+ call append('.', range(5))
+ call assert_equal(['', '0', '1', '2', '3', '4'], getline(1, '$'))
+ bwipe!
+
+ " appendbufline()
+ new
+ call appendbufline(bufnr(''), '.', range(5))
+ call assert_equal(['0', '1', '2', '3', '4', ''], getline(1, '$'))
+ bwipe!
+
+ " call()
+ func TwoArgs(a, b)
+ return [a:a, a:b]
+ endfunc
+ call assert_equal([0, 1], call('TwoArgs', range(2)))
+
+ " col()
+ new
+ call setline(1, ['foo', 'bar'])
+ call assert_equal(2, col(range(1, 2)))
+ bwipe!
+
+ " complete()
+ execute "normal! a\<C-r>=[complete(col('.'), range(10)), ''][1]\<CR>"
+ " complete_info()
+ execute "normal! a\<C-r>=[complete(col('.'), range(10)), ''][1]\<CR>\<C-r>=[complete_info(range(5)), ''][1]\<CR>"
+
+ " copy()
+ call assert_equal([1, 2, 3], copy(range(1, 3)))
+
+ " count()
+ call assert_equal(0, count(range(0), 3))
+ call assert_equal(0, count(range(2), 3))
+ call assert_equal(1, count(range(5), 3))
+
+ " cursor()
+ new
+ call setline(1, ['aaa', 'bbb', 'ccc'])
+ call cursor(range(1, 2))
+ call assert_equal([2, 1], [col('.'), line('.')])
+ bwipe!
+
+ " deepcopy()
+ call assert_equal([1, 2, 3], deepcopy(range(1, 3)))
+
+ " empty()
+ call assert_true(empty(range(0)))
+ call assert_false(empty(range(2)))
+
+ " execute()
+ new
+ call setline(1, ['aaa', 'bbb', 'ccc'])
+ call execute(range(3))
+ call assert_equal(2, line('.'))
+ bwipe!
+
+ " extend()
+ call assert_equal([1, 2, 3, 4], extend([1], range(2, 4)))
+ call assert_equal([1, 2, 3, 4], extend(range(1, 1), range(2, 4)))
+ call assert_equal([1, 2, 3, 4], extend(range(1, 1), [2, 3, 4]))
+
+ " filter()
+ call assert_equal([1, 3], filter(range(5), 'v:val % 2'))
+
+ " funcref()
+ call assert_equal([0, 1], funcref('TwoArgs', range(2))())
+
+ " function()
+ call assert_equal([0, 1], function('TwoArgs', range(2))())
+
+ " garbagecollect()
+ let thelist = [1, range(2), 3]
+ let otherlist = range(3)
+ call test_garbagecollect_now()
+
+ " get()
+ call assert_equal(4, get(range(1, 10), 3))
+ call assert_equal(-1, get(range(1, 10), 42, -1))
+
+ " index()
+ call assert_equal(1, index(range(1, 5), 2))
+ call assert_fails("echo index([1, 2], 1, [])", 'E745:')
+
+ " insert()
+ call assert_equal([42, 1, 2, 3, 4, 5], insert(range(1, 5), 42))
+ call assert_equal([42, 1, 2, 3, 4, 5], insert(range(1, 5), 42, 0))
+ call assert_equal([1, 42, 2, 3, 4, 5], insert(range(1, 5), 42, 1))
+ call assert_equal([1, 2, 3, 4, 42, 5], insert(range(1, 5), 42, 4))
+ call assert_equal([1, 2, 3, 4, 42, 5], insert(range(1, 5), 42, -1))
+ call assert_equal([1, 2, 3, 4, 5, 42], insert(range(1, 5), 42, 5))
+
+ " join()
+ call assert_equal('0 1 2 3 4', join(range(5)))
+
+ " json_encode()
+ " call assert_equal('[0,1,2,3]', json_encode(range(4)))
+ call assert_equal('[0, 1, 2, 3]', json_encode(range(4)))
+
+ " len()
+ call assert_equal(0, len(range(0)))
+ call assert_equal(2, len(range(2)))
+ call assert_equal(5, len(range(0, 12, 3)))
+ call assert_equal(4, len(range(3, 0, -1)))
+
+ " list2str()
+ call assert_equal('ABC', list2str(range(65, 67)))
+ call assert_fails('let s = list2str(5)', 'E474:')
+
+ " lock()
+ let thelist = range(5)
+ lockvar thelist
+
+ " map()
+ call assert_equal([0, 2, 4, 6, 8], map(range(5), 'v:val * 2'))
+
+ " match()
+ call assert_equal(3, match(range(5), 3))
+
+ " matchaddpos()
+ highlight MyGreenGroup ctermbg=green guibg=green
+ call matchaddpos('MyGreenGroup', range(line('.'), line('.')))
+
+ " matchend()
+ call assert_equal(4, matchend(range(5), '4'))
+ call assert_equal(3, matchend(range(1, 5), '4'))
+ call assert_equal(-1, matchend(range(1, 5), '42'))
+
+ " matchstrpos()
+ call assert_equal(['4', 4, 0, 1], matchstrpos(range(5), '4'))
+ call assert_equal(['4', 3, 0, 1], matchstrpos(range(1, 5), '4'))
+ call assert_equal(['', -1, -1, -1], matchstrpos(range(1, 5), '42'))
+
+ " max() reverse()
+ call assert_equal(0, max(range(0)))
+ call assert_equal(0, max(range(10, 9)))
+ call assert_equal(9, max(range(10)))
+ call assert_equal(18, max(range(0, 20, 3)))
+ call assert_equal(20, max(range(20, 0, -3)))
+ call assert_equal(99999, max(range(100000)))
+ call assert_equal(99999, max(range(99999, 0, -1)))
+ call assert_equal(99999, max(reverse(range(100000))))
+ call assert_equal(99999, max(reverse(range(99999, 0, -1))))
+
+ " min() reverse()
+ call assert_equal(0, min(range(0)))
+ call assert_equal(0, min(range(10, 9)))
+ call assert_equal(5, min(range(5, 10)))
+ call assert_equal(5, min(range(5, 10, 3)))
+ call assert_equal(2, min(range(20, 0, -3)))
+ call assert_equal(0, min(range(100000)))
+ call assert_equal(0, min(range(99999, 0, -1)))
+ call assert_equal(0, min(reverse(range(100000))))
+ call assert_equal(0, min(reverse(range(99999, 0, -1))))
+
+ " remove()
+ call assert_equal(1, remove(range(1, 10), 0))
+ call assert_equal(2, remove(range(1, 10), 1))
+ call assert_equal(9, remove(range(1, 10), 8))
+ call assert_equal(10, remove(range(1, 10), 9))
+ call assert_equal(10, remove(range(1, 10), -1))
+ call assert_equal([3, 4, 5], remove(range(1, 10), 2, 4))
+
+ " repeat()
+ call assert_equal([0, 1, 2, 0, 1, 2], repeat(range(3), 2))
+ call assert_equal([0, 1, 2], repeat(range(3), 1))
+ call assert_equal([], repeat(range(3), 0))
+ call assert_equal([], repeat(range(5, 4), 2))
+ call assert_equal([], repeat(range(5, 4), 0))
+
+ " reverse()
+ call assert_equal([2, 1, 0], reverse(range(3)))
+ call assert_equal([0, 1, 2, 3], reverse(range(3, 0, -1)))
+ call assert_equal([9, 8, 7, 6, 5, 4, 3, 2, 1, 0], reverse(range(10)))
+ call assert_equal([20, 19, 18, 17, 16, 15, 14, 13, 12, 11, 10], reverse(range(10, 20)))
+ call assert_equal([16, 13, 10], reverse(range(10, 18, 3)))
+ call assert_equal([19, 16, 13, 10], reverse(range(10, 19, 3)))
+ call assert_equal([19, 16, 13, 10], reverse(range(10, 20, 3)))
+ call assert_equal([11, 14, 17, 20], reverse(range(20, 10, -3)))
+ call assert_equal([], reverse(range(0)))
+
+ " TODO: setpos()
+ " new
+ " call setline(1, repeat([''], bufnr('')))
+ " call setline(bufnr('') + 1, repeat('x', bufnr('') * 2 + 6))
+ " call setpos('x', range(bufnr(''), bufnr('') + 3))
+ " bwipe!
+
+ " setreg()
+ call setreg('a', range(3))
+ call assert_equal("0\n1\n2\n", getreg('a'))
+
+ " settagstack()
+ call settagstack(1, #{items : range(4)})
+
+ " sign_define()
+ call assert_fails("call sign_define(range(5))", "E715:")
+ call assert_fails("call sign_placelist(range(5))", "E715:")
+
+ " sign_undefine()
+ " call assert_fails("call sign_undefine(range(5))", "E908:")
+ call assert_fails("call sign_undefine(range(5))", "E155:")
+
+ " sign_unplacelist()
+ call assert_fails("call sign_unplacelist(range(5))", "E715:")
+
+ " sort()
+ call assert_equal([0, 1, 2, 3, 4, 5], sort(range(5, 0, -1)))
+
+ " string()
+ call assert_equal('[0, 1, 2, 3, 4]', string(range(5)))
+
+ " taglist() with 'tagfunc'
+ func TagFunc(pattern, flags, info)
+ return range(10)
+ endfunc
+ set tagfunc=TagFunc
+ call assert_fails("call taglist('asdf')", 'E987:')
+ set tagfunc=
+
+ " term_start()
+ if has('terminal') && has('termguicolors')
+ call assert_fails('call term_start(range(3, 4))', 'E474:')
+ let g:terminal_ansi_colors = range(16)
+ if has('win32')
+ let cmd = "cmd /c dir"
+ else
+ let cmd = "ls"
+ endif
+ call assert_fails('call term_start("' .. cmd .. '", #{term_finish: "close"})', 'E475:')
+ unlet g:terminal_ansi_colors
+ endif
+
+ " type()
+ call assert_equal(v:t_list, type(range(5)))
+
+ " uniq()
+ call assert_equal([0, 1, 2, 3, 4], uniq(range(5)))
+
+ " errors
+ call assert_fails('let x=range(2, 8, 0)', 'E726:')
+ call assert_fails('let x=range(3, 1)', 'E727:')
+ call assert_fails('let x=range(1, 3, -2)', 'E727:')
+ call assert_fails('let x=range([])', 'E745:')
+ call assert_fails('let x=range(1, [])', 'E745:')
+ call assert_fails('let x=range(1, 4, [])', 'E745:')
+endfunc
+
+func Test_garbagecollect_now_fails()
+ let v:testing = 0
+ call assert_fails('call test_garbagecollect_now()', 'E1142:')
+ let v:testing = 1
+endfunc
+
" Test for the eval() function
func Test_eval()
call assert_fails("call eval('5 a')", 'E488:')
endfunc
+" Test for the keytrans() function
+func Test_keytrans()
+ call assert_equal('<Space>', keytrans(' '))
+ call assert_equal('<lt>', keytrans('<'))
+ call assert_equal('<lt>Tab>', keytrans('<Tab>'))
+ call assert_equal('<Tab>', keytrans("\<Tab>"))
+ call assert_equal('<C-V>', keytrans("\<C-V>"))
+ call assert_equal('<BS>', keytrans("\<BS>"))
+ call assert_equal('<Home>', keytrans("\<Home>"))
+ call assert_equal('<C-Home>', keytrans("\<C-Home>"))
+ call assert_equal('<M-Home>', keytrans("\<M-Home>"))
+ call assert_equal('<C-Space>', keytrans("\<C-Space>"))
+ call assert_equal('<M-Space>', keytrans("\<*M-Space>"))
+ call assert_equal('<M-x>', "\<*M-x>"->keytrans())
+ call assert_equal('<C-I>', "\<*C-I>"->keytrans())
+ call assert_equal('<S-3>', "\<*S-3>"->keytrans())
+ call assert_equal('π', 'π'->keytrans())
+ call assert_equal('<M-π>', "\<M-π>"->keytrans())
+ call assert_equal('ě', 'ě'->keytrans())
+ call assert_equal('<M-ě>', "\<M-ě>"->keytrans())
+ call assert_equal('', ''->keytrans())
+ call assert_equal('', v:_null_string->keytrans())
+ call assert_fails('call keytrans(1)', 'E1174:')
+ call assert_fails('call keytrans()', 'E119:')
+endfunc
+
" Test for the nr2char() function
func Test_nr2char()
" set encoding=latin1
@@ -1842,6 +2391,13 @@ func Test_nr2char()
call assert_equal("\x80\xfc\b" .. nr2char(0x40000000), eval('"\<M-' .. nr2char(0x40000000) .. '>"'))
endfunc
+" Test for screenattr(), screenchar() and screenchars() functions
+func Test_screen_functions()
+ call assert_equal(-1, screenattr(-1, -1))
+ call assert_equal(-1, screenchar(-1, -1))
+ call assert_equal([], screenchars(-1, -1))
+endfunc
+
" Test for getcurpos() and setpos()
func Test_getcurpos_setpos()
new
@@ -1872,9 +2428,7 @@ endfunc
func Test_getmousepos()
enew!
call setline(1, "\t\t\t1234")
- " call test_setmouse(1, 1)
- call nvim_input_mouse('left', 'press', '', 0, 0, 0)
- call getchar() " wait for and consume the mouse press
+ call Ntest_setmouse(1, 1)
call assert_equal(#{
\ screenrow: 1,
\ screencol: 1,
@@ -1884,9 +2438,7 @@ func Test_getmousepos()
\ line: 1,
\ column: 1,
\ }, getmousepos())
- " call test_setmouse(1, 25)
- call nvim_input_mouse('left', 'press', '', 0, 0, 24)
- call getchar() " wait for and consume the mouse press
+ call Ntest_setmouse(1, 25)
call assert_equal(#{
\ screenrow: 1,
\ screencol: 25,
@@ -1896,9 +2448,7 @@ func Test_getmousepos()
\ line: 1,
\ column: 4,
\ }, getmousepos())
- " call test_setmouse(1, 50)
- call nvim_input_mouse('left', 'press', '', 0, 0, 49)
- call getchar() " wait for and consume the mouse press
+ call Ntest_setmouse(1, 50)
call assert_equal(#{
\ screenrow: 1,
\ screencol: 50,
@@ -1911,9 +2461,7 @@ func Test_getmousepos()
" If the mouse is positioned past the last buffer line, "line" and "column"
" should act like it's positioned on the last buffer line.
- " call test_setmouse(2, 25)
- call nvim_input_mouse('left', 'press', '', 0, 1, 24)
- call getchar() " wait for and consume the mouse press
+ call Ntest_setmouse(2, 25)
call assert_equal(#{
\ screenrow: 2,
\ screencol: 25,
@@ -1923,9 +2471,7 @@ func Test_getmousepos()
\ line: 1,
\ column: 4,
\ }, getmousepos())
- " call test_setmouse(2, 50)
- call nvim_input_mouse('left', 'press', '', 0, 1, 49)
- call getchar() " wait for and consume the mouse press
+ call Ntest_setmouse(2, 50)
call assert_equal(#{
\ screenrow: 2,
\ screencol: 50,
@@ -1938,6 +2484,28 @@ func Test_getmousepos()
bwipe!
endfunc
+" Test for glob()
+func Test_glob()
+ call assert_equal('', glob(v:_null_string))
+ call assert_equal('', globpath(v:_null_string, v:_null_string))
+ call assert_fails("let x = globpath(&rtp, 'syntax/c.vim', [])", 'E745:')
+
+ call writefile([], 'Xglob1')
+ call writefile([], 'XGLOB2')
+ set wildignorecase
+ " Sort output of glob() otherwise we end up with different
+ " ordering depending on whether file system is case-sensitive.
+ call assert_equal(['XGLOB2', 'Xglob1'], sort(glob('Xglob[12]', 0, 1)))
+ " wildignorecase shall be applied even when the pattern contains no wildcards.
+ call assert_equal('XGLOB2', glob('xglob2'))
+ set wildignorecase&
+
+ call delete('Xglob1')
+ call delete('XGLOB2')
+
+ call assert_fails("call glob('*', 0, {})", 'E728:')
+endfunc
+
func HasDefault(msg = 'msg')
return a:msg
endfunc
@@ -1946,4 +2514,46 @@ func Test_default_arg_value()
call assert_equal('msg', HasDefault())
endfunc
+" Test for gettext()
+func Test_gettext()
+ call assert_fails('call gettext(1)', 'E475:')
+endfunc
+
+func Test_builtin_check()
+ call assert_fails('let g:["trim"] = {x -> " " .. x}', 'E704:')
+ call assert_fails('let g:.trim = {x -> " " .. x}', 'E704:')
+ call assert_fails('let l:["trim"] = {x -> " " .. x}', 'E704:')
+ call assert_fails('let l:.trim = {x -> " " .. x}', 'E704:')
+ let lines =<< trim END
+ vim9script
+ var s:trim = (x) => " " .. x
+ END
+ call CheckScriptFailure(lines, 'E704:')
+
+ call assert_fails('call extend(g:, #{foo: { -> "foo" }})', 'E704:')
+ let g:bar = 123
+ call extend(g:, #{bar: { -> "foo" }}, "keep")
+ call assert_fails('call extend(g:, #{bar: { -> "foo" }}, "force")', 'E704:')
+ unlet g:bar
+
+ call assert_fails('call extend(l:, #{foo: { -> "foo" }})', 'E704:')
+ let bar = 123
+ call extend(l:, #{bar: { -> "foo" }}, "keep")
+ call assert_fails('call extend(l:, #{bar: { -> "foo" }}, "force")', 'E704:')
+ unlet bar
+
+ call assert_fails('call extend(g:, #{foo: function("extend")})', 'E704:')
+ let g:bar = 123
+ call extend(g:, #{bar: function("extend")}, "keep")
+ call assert_fails('call extend(g:, #{bar: function("extend")}, "force")', 'E704:')
+ unlet g:bar
+
+ call assert_fails('call extend(l:, #{foo: function("extend")})', 'E704:')
+ let bar = 123
+ call extend(l:, #{bar: function("extend")}, "keep")
+ call assert_fails('call extend(l:, #{bar: function("extend")}, "force")', 'E704:')
+ unlet bar
+endfunc
+
+
" vim: shiftwidth=2 sts=2 expandtab
diff --git a/src/nvim/testdir/test_getcwd.vim b/src/nvim/testdir/test_getcwd.vim
index a75583cd2c..073f8303dc 100644
--- a/src/nvim/testdir/test_getcwd.vim
+++ b/src/nvim/testdir/test_getcwd.vim
@@ -24,7 +24,7 @@ endfunc
" Do all test in a separate window to avoid E211 when we recursively
" delete the Xtopdir directory during cleanup
-function SetUp()
+func SetUp()
set visualbell
set nocp viminfo+=nviminfo
diff --git a/src/nvim/testdir/test_getvar.vim b/src/nvim/testdir/test_getvar.vim
index 5a96548893..e6b6341fce 100644
--- a/src/nvim/testdir/test_getvar.vim
+++ b/src/nvim/testdir/test_getvar.vim
@@ -133,11 +133,20 @@ func Test_get_lambda()
call assert_equal([], get(l:L, 'args'))
endfunc
+func s:FooBar()
+endfunc
+
" get({func}, {what} [, {default}])
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'))
+
+ let Fb_func = function('s:FooBar')
+ call assert_match('<SNR>\d\+_FooBar', get(Fb_func, 'name'))
+ let Fb_ref = funcref('s:FooBar')
+ call assert_match('<SNR>\d\+_FooBar', get(Fb_ref, 'name'))
+
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'))
diff --git a/src/nvim/testdir/test_gf.vim b/src/nvim/testdir/test_gf.vim
index b2bb189688..e369645328 100644
--- a/src/nvim/testdir/test_gf.vim
+++ b/src/nvim/testdir/test_gf.vim
@@ -226,6 +226,32 @@ func Test_gf_includeexpr()
delfunc IncFunc
endfunc
+" Test for using a script-local function for 'includeexpr'
+func Test_includeexpr_scriptlocal_func()
+ func! s:IncludeFunc()
+ let g:IncludeFname = v:fname
+ return ''
+ endfunc
+ set includeexpr=s:IncludeFunc()
+ call assert_equal(expand('<SID>') .. 'IncludeFunc()', &includeexpr)
+ new | only
+ call setline(1, 'TestFile1')
+ let g:IncludeFname = ''
+ call assert_fails('normal! gf', 'E447:')
+ call assert_equal('TestFile1', g:IncludeFname)
+ bw!
+ set includeexpr=<SID>IncludeFunc()
+ call assert_equal(expand('<SID>') .. 'IncludeFunc()', &includeexpr)
+ new | only
+ call setline(1, 'TestFile2')
+ let g:IncludeFname = ''
+ call assert_fails('normal! gf', 'E447:')
+ call assert_equal('TestFile2', g:IncludeFname)
+ set includeexpr&
+ delfunc s:IncludeFunc
+ bw!
+endfunc
+
" Check that expanding directories can handle more than 255 entries.
func Test_gf_subdirs_wildcard()
let cwd = getcwd()
diff --git a/src/nvim/testdir/test_global.vim b/src/nvim/testdir/test_global.vim
index cb6851250c..44a8784348 100644
--- a/src/nvim/testdir/test_global.vim
+++ b/src/nvim/testdir/test_global.vim
@@ -39,7 +39,7 @@ endfunc
func Test_global_error()
call assert_fails('g\\a', 'E10:')
call assert_fails('g', 'E148:')
- call assert_fails('g/\(/y', 'E476:')
+ call assert_fails('g/\(/y', 'E54:')
endfunc
" Test for printing lines using :g with different search patterns
@@ -72,6 +72,18 @@ func Test_global_print()
close!
endfunc
+func Test_global_empty_pattern()
+ " populate history
+ silent g/hello/
+
+ redir @a
+ g//
+ redir END
+
+ call assert_match('Pattern not found: hello', @a)
+ " ^~~~~ this was previously empty
+endfunc
+
" Test for global command with newline character
func Test_global_newline()
new
@@ -91,6 +103,7 @@ endfunc
" Test for interrupting :global using Ctrl-C
func Test_interrupt_global()
CheckRunVimInTerminal
+
let lines =<< trim END
cnoremap ; <Cmd>sleep 10<CR>
call setline(1, repeat(['foo'], 5))
@@ -100,14 +113,14 @@ func Test_interrupt_global()
call term_sendkeys(buf, ":g/foo/norm :\<C-V>;\<CR>")
" Wait for :sleep to start
- call term_wait(buf)
+ call TermWait(buf, 100)
call term_sendkeys(buf, "\<C-C>")
call WaitForAssert({-> assert_match('Interrupted', term_getline(buf, 6))}, 1000)
" Also test in Ex mode
call term_sendkeys(buf, "gQg/foo/norm :\<C-V>;\<CR>")
" Wait for :sleep to start
- call term_wait(buf)
+ call TermWait(buf, 100)
call term_sendkeys(buf, "\<C-C>")
call WaitForAssert({-> assert_match('Interrupted', term_getline(buf, 5))}, 1000)
diff --git a/src/nvim/testdir/test_gui.vim b/src/nvim/testdir/test_gui.vim
new file mode 100644
index 0000000000..c3f1f3163a
--- /dev/null
+++ b/src/nvim/testdir/test_gui.vim
@@ -0,0 +1,43 @@
+
+func Test_colorscheme()
+ " call assert_equal('16777216', &t_Co)
+
+ let colorscheme_saved = exists('g:colors_name') ? g:colors_name : 'default'
+ let g:color_count = 0
+ augroup TestColors
+ au!
+ au ColorScheme * let g:color_count += 1
+ \ | let g:after_colors = g:color_count
+ \ | let g:color_after = expand('<amatch>')
+ au ColorSchemePre * let g:color_count += 1
+ \ | let g:before_colors = g:color_count
+ \ | let g:color_pre = expand('<amatch>')
+ augroup END
+
+ colorscheme torte
+ redraw!
+ call assert_equal('dark', &background)
+ call assert_equal(1, g:before_colors)
+ call assert_equal(2, g:after_colors)
+ call assert_equal('torte', g:color_pre)
+ call assert_equal('torte', g:color_after)
+ call assert_equal("\ntorte", execute('colorscheme'))
+
+ let a = substitute(execute('hi Search'), "\n\\s\\+", ' ', 'g')
+ " FIXME: temporarily check less while the colorscheme changes
+ " call assert_match("\nSearch xxx term=reverse cterm=reverse ctermfg=196 ctermbg=16 gui=reverse guifg=#ff0000 guibg=#000000", a)
+ " call assert_match("\nSearch xxx term=reverse ", a)
+
+ call assert_fails('colorscheme does_not_exist', 'E185:')
+ call assert_equal('does_not_exist', g:color_pre)
+ call assert_equal('torte', g:color_after)
+
+ exec 'colorscheme' colorscheme_saved
+ augroup TestColors
+ au!
+ augroup END
+ unlet g:color_count g:after_colors g:before_colors
+ redraw!
+endfunc
+
+" vim: shiftwidth=2 sts=2 expandtab
diff --git a/src/nvim/testdir/test_hardcopy.vim b/src/nvim/testdir/test_hardcopy.vim
deleted file mode 100644
index e390bd5cc8..0000000000
--- a/src/nvim/testdir/test_hardcopy.vim
+++ /dev/null
@@ -1,204 +0,0 @@
-" Test :hardcopy
-
-source check.vim
-
-func Test_printoptions()
- edit test_hardcopy.vim
- syn on
-
- for opt in ['left:5in,right:10pt,top:8mm,bottom:2pc',
- \ 'left:2in,top:30pt,right:16mm,bottom:3pc',
- \ 'header:3,syntax:y,number:y,wrap:n',
- \ 'header:3,syntax:n,number:y,wrap:y',
- \ 'header:0,syntax:a,number:y,wrap:y',
- \ 'duplex:short,collate:n,jobsplit:y,portrait:n',
- \ 'duplex:long,collate:y,jobsplit:n,portrait:y',
- \ 'duplex:off,collate:y,jobsplit:y,portrait:y',
- \ 'paper:10x14',
- \ 'paper:A3',
- \ 'paper:A4',
- \ 'paper:A5',
- \ 'paper:B4',
- \ 'paper:B5',
- \ 'paper:executive',
- \ 'paper:folio',
- \ 'paper:ledger',
- \ 'paper:legal',
- \ 'paper:letter',
- \ 'paper:quarto',
- \ 'paper:statement',
- \ 'paper:tabloid',
- \ 'formfeed:y',
- \ '']
- exe 'set printoptions=' .. opt
- if has('postscript')
- 1,50hardcopy > Xhardcopy_printoptions
- let lines = readfile('Xhardcopy_printoptions')
- call assert_true(len(lines) > 20, opt)
- call assert_true(lines[0] =~ 'PS-Adobe', opt)
- call delete('Xhardcopy_printoptions')
- endif
- endfor
-
- call assert_fails('set printoptions=paper', 'E550:')
- call assert_fails('set printoptions=shredder:on', 'E551:')
- call assert_fails('set printoptions=left:no', 'E552:')
- set printoptions&
- bwipe
-endfunc
-
-func Test_printmbfont()
- " Print a help page which contains tabs, underlines (etc) to recover more code.
- help syntax.txt
- syn on
-
- for opt in [':WadaMin-Regular,b:WadaMin-Bold,i:WadaMin-Italic,o:WadaMin-Bold-Italic,c:yes,a:no',
- \ '']
- exe 'set printmbfont=' .. opt
- if has('postscript')
- hardcopy > Xhardcopy_printmbfont
- let lines = readfile('Xhardcopy_printmbfont')
- call assert_true(len(lines) > 20, opt)
- call assert_true(lines[0] =~ 'PS-Adobe', opt)
- call delete('Xhardcopy_printmbfont')
- endif
- endfor
- set printmbfont&
- bwipe
-endfunc
-
-func Test_printmbcharset()
- CheckFeature postscript
-
- " digraph.txt has plenty of non-latin1 characters.
- help digraph.txt
- set printmbcharset=ISO10646 printencoding=utf-8
- for courier in ['yes', 'no']
- for ascii in ['yes', 'no']
- exe 'set printmbfont=r:WadaMin-Regular,b:WadaMin-Bold,i:WadaMin-Italic,o:WadaMin-BoldItalic'
- \ .. ',c:' .. courier .. ',a:' .. ascii
- hardcopy > Xhardcopy_printmbcharset
- let lines = readfile('Xhardcopy_printmbcharset')
- call assert_true(len(lines) > 20)
- call assert_true(lines[0] =~ 'PS-Adobe')
- endfor
- endfor
-
- set printmbcharset=does-not-exist printencoding=utf-8 printmbfont=r:WadaMin-Regular
- call assert_fails('hardcopy > Xhardcopy_printmbcharset', 'E456:')
-
- set printmbcharset=GB_2312-80 printencoding=utf-8 printmbfont=r:WadaMin-Regular
- call assert_fails('hardcopy > Xhardcopy_printmbcharset', 'E673:')
-
- set printmbcharset=ISO10646 printencoding=utf-8 printmbfont=
- call assert_fails('hardcopy > Xhardcopy_printmbcharset', 'E675:')
-
- call delete('Xhardcopy_printmbcharset')
- set printmbcharset& printencoding& printmbfont&
- bwipe
-endfunc
-
-func Test_printexpr()
- CheckFeature postscript
-
- " Not a very useful printexpr value, but enough to test
- " hardcopy with 'printexpr'.
- function PrintFile(fname)
- call writefile(['Test printexpr: ' .. v:cmdarg],
- \ 'Xhardcopy_printexpr')
- call delete(a:fname)
- return 0
- endfunc
- set printexpr=PrintFile(v:fname_in)
-
- help help
- hardcopy dummy args
- call assert_equal(['Test printexpr: dummy args'],
- \ readfile('Xhardcopy_printexpr'))
- call delete('Xhardcopy_printexpr')
-
- " Function returns 1 to test print failure.
- function PrintFails(fname)
- call delete(a:fname)
- return 1
- endfunc
- set printexpr=PrintFails(v:fname_in)
- call assert_fails('hardcopy', 'E365:')
-
- set printexpr&
- bwipe
-endfunc
-
-func Test_errors()
- CheckFeature postscript
-
- edit test_hardcopy.vim
- call assert_fails('hardcopy >', 'E324:')
- bwipe
-endfunc
-
-func Test_dark_background()
- edit test_hardcopy.vim
- syn on
-
- for bg in ['dark', 'light']
- exe 'set background=' .. bg
-
- if has('postscript')
- hardcopy > Xhardcopy_dark_background
- let lines = readfile('Xhardcopy_dark_background')
- call assert_true(len(lines) > 20)
- call assert_true(lines[0] =~ 'PS-Adobe')
- call delete('Xhardcopy_dark_background')
- endif
- endfor
-
- set background&
- bwipe
-endfun
-
-func Test_empty_buffer()
- CheckFeature postscript
-
- new
- call assert_equal("\nNo text to be printed", execute('hardcopy'))
- bwipe
-endfunc
-
-func Test_printheader_parsing()
- " Only test that this doesn't throw an error.
- set printheader=%<%f\ %h%m%r%=%-14.(%l,%c%V%)\ %P
- set printheader=%<%f%h%m%r%=%b\ 0x%B\ \ %l,%c%V\ %P
- set printheader=%<%f%=\ [%1*%M%*%n%R%H]\ %-19(%3l,%02c%03V%)%O'%02b'
- set printheader=...%r%{VarExists('b:gzflag','\ [GZ]')}%h...
- set printheader=
- set printheader&
-endfunc
-
-func Test_fname_with_spaces()
- CheckFeature postscript
-
- split t\ e\ s\ t.txt
- call setline(1, ['just', 'some', 'text'])
- hardcopy > %.ps
- call assert_true(filereadable('t e s t.txt.ps'))
- call delete('t e s t.txt.ps')
- bwipe!
-endfunc
-
-func Test_illegal_byte()
- CheckFeature postscript
- if &enc != 'utf-8'
- return
- endif
-
- new
- " conversion of 0xff will fail, this used to cause a crash
- call setline(1, "\xff")
- hardcopy >Xpstest
-
- bwipe!
- call delete('Xpstest')
-endfunc
-
-" vim: shiftwidth=2 sts=2 expandtab
diff --git a/src/nvim/testdir/test_help.vim b/src/nvim/testdir/test_help.vim
index dbb36facee..08dd3dcb9a 100644
--- a/src/nvim/testdir/test_help.vim
+++ b/src/nvim/testdir/test_help.vim
@@ -1,5 +1,23 @@
" Tests for :help
+source check.vim
+source vim9.vim
+
+func SetUp()
+ let s:vimruntime = $VIMRUNTIME
+ let s:runtimepath = &runtimepath
+ " Set $VIMRUNTIME to $BUILD_DIR/runtime and remove the original $VIMRUNTIME
+ " path from &runtimepath so that ":h local-additions" won't pick up builtin
+ " help files.
+ let $VIMRUNTIME = expand($BUILD_DIR) .. '/runtime'
+ set runtimepath-=../../../runtime
+endfunc
+
+func TearDown()
+ let $VIMRUNTIME = s:vimruntime
+ let &runtimepath = s:runtimepath
+endfunc
+
func Test_help_restore_snapshot()
help
set buftype=
@@ -79,16 +97,42 @@ func Test_help_local_additions()
call writefile(['*mydoc-ext.txt* my extended awesome doc'], 'Xruntime/doc/mydoc-ext.txt')
let rtp_save = &rtp
set rtp+=./Xruntime
- help
- 1
- call search('mydoc.txt')
- call assert_equal('|mydoc.txt| my awesome doc', getline('.'))
- 1
- call search('mydoc-ext.txt')
- call assert_equal('|mydoc-ext.txt| my extended awesome doc', getline('.'))
+ help local-additions
+ let lines = getline(line(".") + 1, search("^$") - 1)
+ call assert_equal([
+ \ '|mydoc-ext.txt| my extended awesome doc',
+ \ '|mydoc.txt| my awesome doc'
+ \ ], lines)
+ call delete('Xruntime/doc/mydoc-ext.txt')
+ close
+
+ call mkdir('Xruntime-ja/doc', 'p')
+ call writefile(["local-additions\thelp.jax\t/*local-additions*"], 'Xruntime-ja/doc/tags-ja')
+ call writefile(['*help.txt* This is jax file', '',
+ \ 'LOCAL ADDITIONS: *local-additions*', ''], 'Xruntime-ja/doc/help.jax')
+ call writefile(['*work.txt* This is jax file'], 'Xruntime-ja/doc/work.jax')
+ call writefile(['*work2.txt* This is jax file'], 'Xruntime-ja/doc/work2.jax')
+ set rtp+=./Xruntime-ja
+
+ help local-additions@en
+ let lines = getline(line(".") + 1, search("^$") - 1)
+ call assert_equal([
+ \ '|mydoc.txt| my awesome doc'
+ \ ], lines)
+ close
+
+ help local-additions@ja
+ let lines = getline(line(".") + 1, search("^$") - 1)
+ call assert_equal([
+ \ '|mydoc.txt| my awesome doc',
+ \ '|help.txt| This is jax file',
+ \ '|work.txt| This is jax file',
+ \ '|work2.txt| This is jax file',
+ \ ], lines)
close
call delete('Xruntime', 'rf')
+ call delete('Xruntime-ja', 'rf')
let &rtp = rtp_save
endfunc
@@ -98,6 +142,7 @@ func Test_help_completion()
endfunc
" Test for the :helptags command
+" NOTE: if you run tests as root this will fail. Don't run tests as root!
func Test_helptag_cmd()
call mkdir('Xdir/a/doc', 'p')
@@ -111,28 +156,12 @@ func Test_helptag_cmd()
call assert_equal(["help-tags\ttags\t1"], readfile('Xdir/tags'))
call delete('Xdir/tags')
- " The following tests fail on FreeBSD for some reason
- if has('unix') && !has('bsd')
- " Read-only tags file
- call mkdir('Xdir/doc', 'p')
- call writefile([''], 'Xdir/doc/tags')
- call writefile([], 'Xdir/doc/sample.txt')
- call setfperm('Xdir/doc/tags', 'r-xr--r--')
- call assert_fails('helptags Xdir/doc', 'E152:', getfperm('Xdir/doc/tags'))
-
- let rtp = &rtp
- let &rtp = 'Xdir'
- helptags ALL
- let &rtp = rtp
-
- call delete('Xdir/doc/tags')
-
- " No permission to read the help file
- call setfperm('Xdir/a/doc/sample.txt', '-w-------')
- call assert_fails('helptags Xdir', 'E153:', getfperm('Xdir/a/doc/sample.txt'))
- call delete('Xdir/a/doc/sample.txt')
- call delete('Xdir/tags')
- endif
+ " Test parsing tags
+ call writefile(['*tag1*', 'Example: >', ' *notag*', 'Example end: *tag2*'],
+ \ 'Xdir/a/doc/sample.txt')
+ helptags Xdir
+ call assert_equal(["tag1\ta/doc/sample.txt\t/*tag1*",
+ \ "tag2\ta/doc/sample.txt\t/*tag2*"], readfile('Xdir/tags'))
" Duplicate tags in the help file
call writefile(['*tag1*', '*tag1*', '*tag2*'], 'Xdir/a/doc/sample.txt')
@@ -141,6 +170,43 @@ func Test_helptag_cmd()
call delete('Xdir', 'rf')
endfunc
+func Test_helptag_cmd_readonly()
+ CheckUnix
+ CheckNotRoot
+
+ " Read-only tags file
+ call mkdir('Xdir/doc', 'p')
+ call writefile([''], 'Xdir/doc/tags')
+ call writefile([], 'Xdir/doc/sample.txt')
+ call setfperm('Xdir/doc/tags', 'r-xr--r--')
+ call assert_fails('helptags Xdir/doc', 'E152:', getfperm('Xdir/doc/tags'))
+
+ let rtp = &rtp
+ let &rtp = 'Xdir'
+ helptags ALL
+ let &rtp = rtp
+
+ call delete('Xdir/doc/tags')
+
+ " No permission to read the help file
+ call mkdir('Xdir/b/doc', 'p')
+ call writefile([], 'Xdir/b/doc/sample.txt')
+ call setfperm('Xdir/b/doc/sample.txt', '-w-------')
+ call assert_fails('helptags Xdir', 'E153:', getfperm('Xdir/b/doc/sample.txt'))
+ call delete('Xdir', 'rf')
+endfunc
+
+" Test for setting the 'helpheight' option in the help window
+func Test_help_window_height()
+ let &cmdheight = &lines - 23
+ set helpheight=10
+ help
+ set helpheight=14
+ call assert_equal(14, winheight(0))
+ set helpheight& cmdheight=1
+ close
+endfunc
+
func Test_help_long_argument()
try
exe 'help \%' .. repeat('0', 1021)
@@ -149,5 +215,15 @@ func Test_help_long_argument()
endtry
endfunc
+func Test_help_using_visual_match()
+ let lines =<< trim END
+ call setline(1, ' ')
+ /^
+ exe "normal \<C-V>\<C-V>"
+ h5\%V€]
+ END
+ call CheckScriptFailure(lines, 'E149:')
+endfunc
+
" vim: shiftwidth=2 sts=2 expandtab
diff --git a/src/nvim/testdir/test_help_tagjump.vim b/src/nvim/testdir/test_help_tagjump.vim
index e84726bbfc..eae1a241e3 100644
--- a/src/nvim/testdir/test_help_tagjump.vim
+++ b/src/nvim/testdir/test_help_tagjump.vim
@@ -1,17 +1,5 @@
" Tests for :help! {subject}
-func SetUp()
- " v:progpath is …/build/bin/nvim and we need …/build/runtime
- " to be added to &rtp
- let builddir = fnamemodify(exepath(v:progpath), ':h:h')
- let s:rtp = &rtp
- let &rtp .= printf(',%s/runtime', builddir)
-endfunc
-
-func TearDown()
- let &rtp = s:rtp
-endfunc
-
func Test_help_tagjump()
help
call assert_equal("help", &filetype)
@@ -38,18 +26,18 @@ func Test_help_tagjump()
call assert_true(getline('.') =~ '\*quotestar\*')
helpclose
- " The test result is different in vim. There ":help ??" will jump to the
- " falsy operator ??, which hasn't been ported to neovim yet. Instead, neovim
- " jumps to the tag "g??". This test result needs to be changed if neovim
- " ports the falsy operator.
- help ??
+ " help sm?le
+ help ch?ckhealth
call assert_equal("help", &filetype)
- call assert_true(getline('.') =~ '\*g??\*')
+ " call assert_true(getline('.') =~ '\*:smile\*')
+ call assert_true(getline('.') =~ '\*:checkhealth\*')
helpclose
- help ch?ckhealth
+ help ??
call assert_equal("help", &filetype)
- call assert_true(getline('.') =~ '\*:checkhealth\*')
+ " *??* tag needs patch 8.2.1794
+ " call assert_true(getline('.') =~ '\*??\*')
+ call assert_true(getline('.') =~ '\*g??\*')
helpclose
help :?
diff --git a/src/nvim/testdir/test_hide.vim b/src/nvim/testdir/test_hide.vim
index 41b1a4ad7c..b3ce395523 100644
--- a/src/nvim/testdir/test_hide.vim
+++ b/src/nvim/testdir/test_hide.vim
@@ -1,6 +1,6 @@
" Tests for :hide command/modifier and 'hidden' option
-function SetUp()
+func SetUp()
let s:save_hidden = &hidden
let s:save_bufhidden = &bufhidden
let s:save_autowrite = &autowrite
diff --git a/src/nvim/testdir/test_highlight.vim b/src/nvim/testdir/test_highlight.vim
index efdf44a0d6..8a102f2e65 100644
--- a/src/nvim/testdir/test_highlight.vim
+++ b/src/nvim/testdir/test_highlight.vim
@@ -536,9 +536,7 @@ func Test_termguicolors()
endfunc
func Test_cursorline_after_yank()
- if !CanRunVimInTerminal()
- throw 'Skipped: cannot make screendumps'
- endif
+ CheckScreendump
call writefile([
\ 'set cul rnu',
@@ -578,9 +576,7 @@ func Test_put_before_cursorline()
endfunc
func Test_cursorline_with_visualmode()
- if !CanRunVimInTerminal()
- throw 'Skipped: cannot make screendumps'
- endif
+ CheckScreendump
call writefile([
\ 'set cul',
@@ -722,7 +718,7 @@ func Test_1_highlight_Normalgroup_exists()
elseif has('gui_gtk2') || has('gui_gnome') || has('gui_gtk3')
" expect is DEFAULT_FONT of gui_gtk_x11.c
call assert_match('hi Normal\s*font=Monospace 10', hlNormal)
- elseif has('gui_motif') || has('gui_athena')
+ elseif has('gui_motif')
" expect is DEFAULT_FONT of gui_x11.c
call assert_match('hi Normal\s*font=7x13', hlNormal)
elseif has('win32')
@@ -731,7 +727,8 @@ func Test_1_highlight_Normalgroup_exists()
endif
endfunc
-function Test_no_space_before_xxx()
+" Do this test last, sometimes restoring the columns doesn't work
+func Test_z_no_space_before_xxx()
" Note: we need to create this highlight group in the test because it does not exist in Neovim
execute('hi StatusLineTermNC ctermfg=green')
let l:org_columns = &columns
@@ -739,13 +736,23 @@ function Test_no_space_before_xxx()
let l:hi_StatusLineTermNC = join(split(execute('hi StatusLineTermNC')))
call assert_match('StatusLineTermNC xxx', l:hi_StatusLineTermNC)
let &columns = l:org_columns
-endfunction
+endfunc
" Test for :highlight command errors
func Test_highlight_cmd_errors()
if has('gui_running') || has('nvim')
+ " This test doesn't fail in the MS-Windows console version.
+ call assert_fails('hi Xcomment ctermfg=fg', 'E419:')
+ call assert_fails('hi Xcomment ctermfg=bg', 'E420:')
call assert_fails('hi ' .. repeat('a', 201) .. ' ctermfg=black', 'E1249:')
endif
+
+ " Try using a very long terminal code. Define a dummy terminal code for this
+ " test.
+ let &t_fo = "\<Esc>1;"
+ let c = repeat("t_fo,", 100) . "t_fo"
+ " call assert_fails('exe "hi Xgroup1 start=" . c', 'E422:')
+ let &t_fo = ""
endfunc
" Test for using RGB color values in a highlight group
@@ -812,11 +819,11 @@ func Test_highlight_clear_restores_context()
let patContextDefault = fnamemodify(scriptContextDefault, ':t') .. ' line 1'
let patContextRelink = fnamemodify(scriptContextRelink, ':t') .. ' line 2'
- exec "source" scriptContextDefault
+ exec 'source ' .. scriptContextDefault
let hlContextDefault = execute("verbose hi Context")
call assert_match(patContextDefault, hlContextDefault)
- exec "source" scriptContextRelink
+ exec 'source ' .. scriptContextRelink
let hlContextRelink = execute("verbose hi Context")
call assert_match(patContextRelink, hlContextRelink)
diff --git a/src/nvim/testdir/test_history.vim b/src/nvim/testdir/test_history.vim
index feb521e232..f1c31dee04 100644
--- a/src/nvim/testdir/test_history.vim
+++ b/src/nvim/testdir/test_history.vim
@@ -95,6 +95,23 @@ function Test_History()
call assert_fails('call histnr([])', 'E730:')
call assert_fails('history xyz', 'E488:')
call assert_fails('history ,abc', 'E488:')
+ call assert_fails('call histdel(":", "\\%(")', 'E53:')
+endfunction
+
+function Test_history_truncates_long_entry()
+ " History entry short enough to fit on the screen should not be truncated.
+ call histadd(':', 'echo x' .. repeat('y', &columns - 17) .. 'z')
+ let a = execute('history : -1')
+
+ call assert_match("^\n # cmd history\n"
+ \ .. "> *\\d\\+ echo x" .. repeat('y', &columns - 17) .. 'z$', a)
+
+ " Long history entry should be truncated to fit on the screen, with, '...'
+ " inserted in the string to indicate the that there is truncation.
+ call histadd(':', 'echo x' .. repeat('y', &columns - 16) .. 'z')
+ let a = execute('history : -1')
+ call assert_match("^\n # cmd history\n"
+ \ .. "> *\\d\\+ echo xy\\+\.\.\.y\\+z$", a)
endfunction
function Test_Search_history_window()
diff --git a/src/nvim/testdir/test_increment.vim b/src/nvim/testdir/test_increment.vim
index 2559654f25..3c2b88ef9f 100644
--- a/src/nvim/testdir/test_increment.vim
+++ b/src/nvim/testdir/test_increment.vim
@@ -476,6 +476,10 @@ func Test_visual_increment_20()
exec "norm! \<C-A>"
call assert_equal(["b"], getline(1, '$'))
call assert_equal([0, 1, 1, 0], getpos('.'))
+ " decrement a and A and increment z and Z
+ call setline(1, ['a', 'A', 'z', 'Z'])
+ exe "normal 1G\<C-X>2G\<C-X>3G\<C-A>4G\<C-A>"
+ call assert_equal(['a', 'A', 'z', 'Z'], getline(1, '$'))
endfunc
" 21) block-wise increment on part of hexadecimal
@@ -566,12 +570,14 @@ endfunc
" 1) <ctrl-a>
" 0b11111111111111111111111111111111
func Test_visual_increment_26()
- set nrformats+=alpha
+ set nrformats+=bin
call setline(1, ["0b11111111111111111111111111111110"])
exec "norm! \<C-V>$\<C-A>"
call assert_equal(["0b11111111111111111111111111111111"], getline(1, '$'))
call assert_equal([0, 1, 1, 0], getpos('.'))
- set nrformats-=alpha
+ exec "norm! \<C-V>$\<C-X>"
+ call assert_equal(["0b11111111111111111111111111111110"], getline(1, '$'))
+ set nrformats-=bin
endfunc
" 27) increment with 'rightreft', if supported
@@ -772,7 +778,6 @@ func Test_normal_increment_03()
endfunc
func Test_increment_empty_line()
- new
call setline(1, ['0', '0', '0', '0', '0', '0', ''])
exe "normal Gvgg\<C-A>"
call assert_equal(['1', '1', '1', '1', '1', '1', ''], getline(1, 7))
@@ -783,8 +788,13 @@ func Test_increment_empty_line()
exe "normal! c\<C-A>l"
exe "normal! c\<C-X>l"
call assert_equal('one two', getline(1))
+endfunc
- bwipe!
+" Try incrementing/decrementing a non-digit/alpha character
+func Test_increment_special_char()
+ call setline(1, '!')
+ call assert_beeps("normal \<C-A>")
+ call assert_beeps("normal \<C-X>")
endfunc
" Try incrementing/decrementing a number when nrformats contains unsigned
@@ -867,4 +877,21 @@ func Test_normal_increment_with_virtualedit()
set virtualedit&
endfunc
+" Test for incrementing a signed hexadecimal and octal number
+func Test_normal_increment_signed_hexoct_nr()
+ new
+ " negative sign before a hex number should be ignored
+ call setline(1, ["-0x9"])
+ exe "norm \<C-A>"
+ call assert_equal(["-0xa"], getline(1, '$'))
+ exe "norm \<C-X>"
+ call assert_equal(["-0x9"], getline(1, '$'))
+ call setline(1, ["-007"])
+ exe "norm \<C-A>"
+ call assert_equal(["-010"], getline(1, '$'))
+ exe "norm \<C-X>"
+ call assert_equal(["-007"], getline(1, '$'))
+ bw!
+endfunc
+
" vim: shiftwidth=2 sts=2 expandtab
diff --git a/src/nvim/testdir/test_ins_complete.vim b/src/nvim/testdir/test_ins_complete.vim
index 179218e48a..ec1379a378 100644
--- a/src/nvim/testdir/test_ins_complete.vim
+++ b/src/nvim/testdir/test_ins_complete.vim
@@ -1,5 +1,8 @@
+" Test for insert completion
+
source screendump.vim
source check.vim
+source vim9.vim
" Test for insert expansion
func Test_ins_complete()
@@ -44,11 +47,11 @@ func Test_ins_complete()
exe "normal o\<C-X>\<C-P>\<C-P>\<C-X>\<C-X>\<C-N>\<C-X>\<C-N>\<C-N>"
call assert_equal('run1 run2', getline('.'))
- set cpt=.,w,i
+ set cpt=.,\ ,w,i
" i-add-expands and switches to local
exe "normal OM\<C-N>\<C-X>\<C-N>\<C-X>\<C-N>\<C-X>\<C-X>\<C-X>\<C-P>"
call assert_equal("Makefile\tto\trun3", getline('.'))
- " add-expands lines (it would end in an empty line if it didn't ignored
+ " add-expands lines (it would end in an empty line if it didn't ignore
" itself)
exe "normal o\<C-X>\<C-L>\<C-X>\<C-L>\<C-P>\<C-P>"
call assert_equal("Makefile\tto\trun3", getline('.'))
@@ -68,6 +71,11 @@ func Test_ins_complete()
call assert_equal('Xtest11.one', getline('.'))
normal ddk
+ " Test for expanding a non-existing filename
+ exe "normal oa1b2X3Y4\<C-X>\<C-F>"
+ call assert_equal('a1b2X3Y4', getline('.'))
+ normal ddk
+
set cpt=w
" checks make_cyclic in other window
exe "normal oST\<C-N>\<C-P>\<C-P>\<C-P>\<C-P>"
@@ -183,17 +191,17 @@ func s:CompleteDone_CompleteFuncDict( findstart, base )
endif
return {
- \ 'words': [
- \ {
- \ 'word': 'aword',
- \ 'abbr': 'wrd',
- \ 'menu': 'extra text',
- \ 'info': 'words are cool',
- \ 'kind': 'W',
- \ 'user_data': ['one', 'two']
- \ }
- \ ]
- \ }
+ \ 'words': [
+ \ {
+ \ 'word': 'aword',
+ \ 'abbr': 'wrd',
+ \ 'menu': 'extra text',
+ \ 'info': 'words are cool',
+ \ 'kind': 'W',
+ \ 'user_data': ['one', 'two']
+ \ }
+ \ ]
+ \ }
endfunc
func s:CompleteDone_CheckCompletedItemNone()
@@ -253,16 +261,16 @@ func s:CompleteDone_CompleteFuncDictNoUserData(findstart, base)
endif
return {
- \ 'words': [
- \ {
- \ 'word': 'aword',
- \ 'abbr': 'wrd',
- \ 'menu': 'extra text',
- \ 'info': 'words are cool',
- \ 'kind': 'W'
- \ }
- \ ]
- \ }
+ \ 'words': [
+ \ {
+ \ 'word': 'aword',
+ \ 'abbr': 'wrd',
+ \ 'menu': 'extra text',
+ \ 'info': 'words are cool',
+ \ 'kind': 'W',
+ \ }
+ \ ]
+ \ }
endfunc
func s:CompleteDone_CheckCompletedItemDictNoUserData()
@@ -573,6 +581,33 @@ func Test_pum_with_folds_two_tabs()
call delete('Xpumscript')
endfunc
+func Test_pum_with_preview_win()
+ CheckScreendump
+
+ let lines =<< trim END
+ funct Omni_test(findstart, base)
+ if a:findstart
+ return col(".") - 1
+ endif
+ return [#{word: "one", info: "1info"}, #{word: "two", info: "2info"}, #{word: "three", info: "3info"}]
+ endfunc
+ set omnifunc=Omni_test
+ set completeopt+=longest
+ END
+
+ call writefile(lines, 'Xpreviewscript')
+ let buf = RunVimInTerminal('-S Xpreviewscript', #{rows: 12})
+ call term_wait(buf, 100)
+ call term_sendkeys(buf, "Gi\<C-X>\<C-O>")
+ call term_wait(buf, 200)
+ call term_sendkeys(buf, "\<C-N>")
+ call VerifyScreenDump(buf, 'Test_pum_with_preview_win', {})
+
+ call term_sendkeys(buf, "\<Esc>")
+ call StopVimInTerminal(buf)
+ call delete('Xpreviewscript')
+endfunc
+
" Test for inserting the tag search pattern in insert mode
func Test_ins_compl_tag_sft()
call writefile([
@@ -682,6 +717,42 @@ func Test_complete_func_error()
call assert_equal([], complete_info(['items']).items)
endfunc
+" Test for recursively starting completion mode using complete()
+func Test_recursive_complete_func()
+ func ListColors()
+ call complete(5, ["red", "blue"])
+ return ''
+ endfunc
+ new
+ call setline(1, ['a1', 'a2'])
+ set complete=.
+ exe "normal Goa\<C-X>\<C-L>\<C-R>=ListColors()\<CR>\<C-N>"
+ call assert_equal('a2blue', getline(3))
+ delfunc ListColors
+ bw!
+endfunc
+
+" Test for using complete() with completeopt+=longest
+func Test_complete_with_longest()
+ new
+ inoremap <buffer> <f3> <cmd>call complete(1, ["iaax", "iaay", "iaaz"])<cr>
+
+ " default: insert first match
+ set completeopt&
+ call setline(1, ['i'])
+ exe "normal Aa\<f3>\<esc>"
+ call assert_equal('iaax', getline(1))
+
+ " with longest: insert longest prefix
+ set completeopt+=longest
+ call setline(1, ['i'])
+ exe "normal Aa\<f3>\<esc>"
+ call assert_equal('iaa', getline(1))
+ set completeopt&
+ bwipe!
+endfunc
+
+
" Test for completing words following a completed word in a line
func Test_complete_wrapscan()
" complete words from another buffer
@@ -721,6 +792,17 @@ func Test_complete_across_line()
close!
endfunc
+" Test for completing words with a '.' at the end of a word.
+func Test_complete_joinspaces()
+ new
+ call setline(1, ['one two.', 'three. four'])
+ set joinspaces
+ exe "normal Goon\<C-P>\<C-X>\<C-P>\<C-X>\<C-P>\<C-X>\<C-P>\<C-X>\<C-P>"
+ call assert_equal("one two. three. four", getline(3))
+ set joinspaces&
+ bw!
+endfunc
+
" Test for using CTRL-L to add one character when completing matching
func Test_complete_add_onechar()
new
@@ -741,6 +823,39 @@ func Test_complete_add_onechar()
close!
endfunc
+" Test for using CTRL-X CTRL-L to complete whole lines lines
+func Test_complete_wholeline()
+ new
+ " complete one-line
+ call setline(1, ['a1', 'a2'])
+ exe "normal ggoa\<C-X>\<C-L>"
+ call assert_equal(['a1', 'a1', 'a2'], getline(1, '$'))
+ " go to the next match (wrapping around the buffer)
+ exe "normal 2GCa\<C-X>\<C-L>\<C-N>"
+ call assert_equal(['a1', 'a', 'a2'], getline(1, '$'))
+ " go to the next match
+ exe "normal 2GCa\<C-X>\<C-L>\<C-N>\<C-N>"
+ call assert_equal(['a1', 'a2', 'a2'], getline(1, '$'))
+ exe "normal 2GCa\<C-X>\<C-L>\<C-N>\<C-N>\<C-N>"
+ call assert_equal(['a1', 'a1', 'a2'], getline(1, '$'))
+ " repeat the test using CTRL-L
+ " go to the next match (wrapping around the buffer)
+ exe "normal 2GCa\<C-X>\<C-L>\<C-L>"
+ call assert_equal(['a1', 'a2', 'a2'], getline(1, '$'))
+ " go to the next match
+ exe "normal 2GCa\<C-X>\<C-L>\<C-L>\<C-L>"
+ call assert_equal(['a1', 'a', 'a2'], getline(1, '$'))
+ exe "normal 2GCa\<C-X>\<C-L>\<C-L>\<C-L>\<C-L>"
+ call assert_equal(['a1', 'a1', 'a2'], getline(1, '$'))
+ %d
+ " use CTRL-X CTRL-L to add one more line
+ call setline(1, ['a1', 'b1'])
+ setlocal complete=.
+ exe "normal ggOa\<C-X>\<C-L>\<C-X>\<C-L>\<C-X>\<C-L>"
+ call assert_equal(['a1', 'b1', '', 'a1', 'b1'], getline(1, '$'))
+ bw!
+endfunc
+
" Test insert completion with 'cindent' (adjust the indent)
func Test_complete_with_cindent()
new
@@ -829,6 +944,25 @@ func Test_complete_stop()
close!
endfunc
+" Test for typing CTRL-R in insert completion mode to insert a register
+" content.
+func Test_complete_reginsert()
+ new
+ call setline(1, ['a1', 'a12', 'a123', 'a1234'])
+
+ " if a valid CTRL-X mode key is returned from <C-R>=, then it should be
+ " processed. Otherwise, CTRL-X mode should be stopped and the key should be
+ " inserted.
+ exe "normal Goa\<C-P>\<C-R>=\"\\<C-P>\"\<CR>"
+ call assert_equal('a123', getline(5))
+ let @r = "\<C-P>\<C-P>"
+ exe "normal GCa\<C-P>\<C-R>r"
+ call assert_equal('a12', getline(5))
+ exe "normal GCa\<C-P>\<C-R>=\"x\"\<CR>"
+ call assert_equal('a1234x', getline(5))
+ bw!
+endfunc
+
func Test_issue_7021()
CheckMSWindows
@@ -842,6 +976,322 @@ func Test_issue_7021()
set completeslash=
endfunc
+" Test for 'longest' setting in 'completeopt' with latin1 and utf-8 encodings
+func Test_complete_longest_match()
+ " for e in ['latin1', 'utf-8']
+ for e in ['utf-8']
+ exe 'set encoding=' .. e
+ new
+ set complete=.
+ set completeopt=menu,longest
+ call setline(1, ['pfx_a1', 'pfx_a12', 'pfx_a123', 'pfx_b1'])
+ exe "normal Gopfx\<C-P>"
+ call assert_equal('pfx_', getline(5))
+ bw!
+ endfor
+
+ " Test for completing additional words with longest match set
+ new
+ call setline(1, ['abc1', 'abd2'])
+ exe "normal Goab\<C-P>\<C-X>\<C-P>"
+ call assert_equal('ab', getline(3))
+ bw!
+ set complete& completeopt&
+endfunc
+
+" Test for removing the first displayed completion match and selecting the
+" match just before that.
+func Test_complete_erase_firstmatch()
+ new
+ call setline(1, ['a12', 'a34', 'a56'])
+ set complete=.
+ exe "normal Goa\<C-P>\<BS>\<BS>3\<CR>"
+ call assert_equal('a34', getline('$'))
+ set complete&
+ bw!
+endfunc
+
+" Test for completing words from unloaded buffers
+func Test_complete_from_unloadedbuf()
+ call writefile(['abc'], "Xfile1")
+ call writefile(['def'], "Xfile2")
+ edit Xfile1
+ edit Xfile2
+ new | close
+ enew
+ bunload Xfile1 Xfile2
+ set complete=u
+ " complete from an unloaded buffer
+ exe "normal! ia\<C-P>"
+ call assert_equal('abc', getline(1))
+ exe "normal! od\<C-P>"
+ call assert_equal('def', getline(2))
+ set complete&
+ %bw!
+ call delete("Xfile1")
+ call delete("Xfile2")
+endfunc
+
+" Test for completing whole lines from unloaded buffers
+func Test_complete_wholeline_unloadedbuf()
+ call writefile(['a line1', 'a line2', 'a line3'], "Xfile1")
+ edit Xfile1
+ enew
+ set complete=u
+ exe "normal! ia\<C-X>\<C-L>\<C-P>"
+ call assert_equal('a line2', getline(1))
+ %d
+ " completing from an unlisted buffer should fail
+ bdel Xfile1
+ exe "normal! ia\<C-X>\<C-L>\<C-P>"
+ call assert_equal('a', getline(1))
+ set complete&
+ %bw!
+ call delete("Xfile1")
+endfunc
+
+" Test for completing words from unlisted buffers
+func Test_complete_from_unlistedbuf()
+ call writefile(['abc'], "Xfile1")
+ call writefile(['def'], "Xfile2")
+ edit Xfile1
+ edit Xfile2
+ new | close
+ bdel Xfile1 Xfile2
+ set complete=U
+ " complete from an unlisted buffer
+ exe "normal! ia\<C-P>"
+ call assert_equal('abc', getline(1))
+ exe "normal! od\<C-P>"
+ call assert_equal('def', getline(2))
+ set complete&
+ %bw!
+ call delete("Xfile1")
+ call delete("Xfile2")
+endfunc
+
+" Test for completing whole lines from unlisted buffers
+func Test_complete_wholeline_unlistedbuf()
+ call writefile(['a line1', 'a line2', 'a line3'], "Xfile1")
+ edit Xfile1
+ enew
+ set complete=U
+ " completing from a unloaded buffer should fail
+ exe "normal! ia\<C-X>\<C-L>\<C-P>"
+ call assert_equal('a', getline(1))
+ %d
+ bdel Xfile1
+ exe "normal! ia\<C-X>\<C-L>\<C-P>"
+ call assert_equal('a line2', getline(1))
+ set complete&
+ %bw!
+ call delete("Xfile1")
+endfunc
+
+" Test for adding a multibyte character using CTRL-L in completion mode
+func Test_complete_mbyte_char_add()
+ new
+ set complete=.
+ call setline(1, 'abė')
+ exe "normal! oa\<C-P>\<BS>\<BS>\<C-L>\<C-L>"
+ call assert_equal('abė', getline(2))
+ " Test for a leader with multibyte character
+ %d
+ call setline(1, 'abėĕ')
+ exe "normal! oabė\<C-P>"
+ call assert_equal('abėĕ', getline(2))
+ bw!
+endfunc
+
+" Test for using <C-X><C-P> for local expansion even if 'complete' is set to
+" not to complete matches from the local buffer. Also test using multiple
+" <C-X> to cancel the current completion mode.
+func Test_complete_local_expansion()
+ new
+ set complete=t
+ call setline(1, ['abc', 'def'])
+ exe "normal! Go\<C-X>\<C-P>"
+ call assert_equal("def", getline(3))
+ exe "normal! Go\<C-P>"
+ call assert_equal("", getline(4))
+ exe "normal! Go\<C-X>\<C-N>"
+ call assert_equal("abc", getline(5))
+ exe "normal! Go\<C-N>"
+ call assert_equal("", getline(6))
+
+ " use multiple <C-X> to cancel the previous completion mode
+ exe "normal! Go\<C-P>\<C-X>\<C-P>"
+ call assert_equal("", getline(7))
+ exe "normal! Go\<C-P>\<C-X>\<C-X>\<C-P>"
+ call assert_equal("", getline(8))
+ exe "normal! Go\<C-P>\<C-X>\<C-X>\<C-X>\<C-P>"
+ call assert_equal("abc", getline(9))
+
+ " interrupt the current completion mode
+ set completeopt=menu,noinsert
+ exe "normal! Go\<C-X>\<C-F>\<C-X>\<C-X>\<C-P>\<C-Y>"
+ call assert_equal("abc", getline(10))
+
+ " when only one <C-X> is used to interrupt, do normal expansion
+ exe "normal! Go\<C-X>\<C-F>\<C-X>\<C-P>"
+ call assert_equal("", getline(11))
+ set completeopt&
+
+ " using two <C-X> in non-completion mode and restarting the same mode
+ exe "normal! God\<C-X>\<C-X>\<C-P>\<C-X>\<C-X>\<C-P>\<C-Y>"
+ call assert_equal("def", getline(12))
+
+ " test for adding a match from the original empty text
+ %d
+ call setline(1, 'abc def g')
+ exe "normal! o\<C-X>\<C-P>\<C-N>\<C-X>\<C-P>"
+ call assert_equal('def', getline(2))
+ exe "normal! 0C\<C-X>\<C-N>\<C-P>\<C-X>\<C-N>"
+ call assert_equal('abc', getline(2))
+
+ bw!
+endfunc
+
+" Test for undoing changes after a insert-mode completion
+func Test_complete_undo()
+ new
+ set complete=.
+ " undo with 'ignorecase'
+ call setline(1, ['ABOVE', 'BELOW'])
+ set ignorecase
+ exe "normal! Goab\<C-G>u\<C-P>"
+ call assert_equal("ABOVE", getline(3))
+ undo
+ call assert_equal("ab", getline(3))
+ set ignorecase&
+ %d
+ " undo with longest match
+ set completeopt=menu,longest
+ call setline(1, ['above', 'about'])
+ exe "normal! Goa\<C-G>u\<C-P>"
+ call assert_equal("abo", getline(3))
+ undo
+ call assert_equal("a", getline(3))
+ set completeopt&
+ %d
+ " undo for line completion
+ call setline(1, ['above that change', 'below that change'])
+ exe "normal! Goabove\<C-G>u\<C-X>\<C-L>"
+ call assert_equal("above that change", getline(3))
+ undo
+ call assert_equal("above", getline(3))
+
+ bw!
+endfunc
+
+" Test for completing a very long word
+func Test_complete_long_word()
+ set complete&
+ new
+ call setline(1, repeat('x', 950) .. ' one two three')
+ exe "normal! Gox\<C-X>\<C-P>\<C-X>\<C-P>\<C-X>\<C-P>\<C-X>\<C-P>"
+ call assert_equal(repeat('x', 950) .. ' one two three', getline(2))
+ %d
+ " should fail when more than 950 characters are in a word
+ call setline(1, repeat('x', 951) .. ' one two three')
+ exe "normal! Gox\<C-X>\<C-P>\<C-X>\<C-P>\<C-X>\<C-P>\<C-X>\<C-P>"
+ call assert_equal(repeat('x', 951), getline(2))
+
+ " Test for adding a very long word to an existing completion
+ %d
+ call setline(1, ['abc', repeat('x', 1016) .. '012345'])
+ exe "normal! Goab\<C-P>\<C-X>\<C-P>"
+ call assert_equal('abc ' .. repeat('x', 1016) .. '0123', getline(3))
+ bw!
+endfunc
+
+" Test for some fields in the complete items used by complete()
+func Test_complete_items()
+ func CompleteItems(idx)
+ let items = [[#{word: "one", dup: 1, user_data: 'u1'}, #{word: "one", dup: 1, user_data: 'u2'}],
+ \ [#{word: "one", dup: 0, user_data: 'u3'}, #{word: "one", dup: 0, user_data: 'u4'}],
+ \ [#{word: "one", icase: 1, user_data: 'u7'}, #{word: "oNE", icase: 1, user_data: 'u8'}],
+ \ [#{user_data: 'u9'}],
+ \ [#{word: "", user_data: 'u10'}],
+ \ [#{word: "", empty: 1, user_data: 'u11'}]]
+ call complete(col('.'), items[a:idx])
+ return ''
+ endfunc
+ new
+ exe "normal! i\<C-R>=CompleteItems(0)\<CR>\<C-N>\<C-Y>"
+ call assert_equal('u2', v:completed_item.user_data)
+ call assert_equal('one', getline(1))
+ exe "normal! o\<C-R>=CompleteItems(1)\<CR>\<C-Y>"
+ call assert_equal('u3', v:completed_item.user_data)
+ call assert_equal('one', getline(2))
+ exe "normal! o\<C-R>=CompleteItems(1)\<CR>\<C-N>"
+ call assert_equal('', getline(3))
+ set completeopt=menu,noinsert
+ exe "normal! o\<C-R>=CompleteItems(2)\<CR>one\<C-N>\<C-Y>"
+ call assert_equal('oNE', getline(4))
+ call assert_equal('u8', v:completed_item.user_data)
+ set completeopt&
+ exe "normal! o\<C-R>=CompleteItems(3)\<CR>"
+ call assert_equal('', getline(5))
+ exe "normal! o\<C-R>=CompleteItems(4)\<CR>"
+ call assert_equal('', getline(6))
+ exe "normal! o\<C-R>=CompleteItems(5)\<CR>"
+ call assert_equal('', getline(7))
+ call assert_equal('u11', v:completed_item.user_data)
+ " pass invalid argument to complete()
+ let cmd = "normal! o\<C-R>=complete(1, [[]])\<CR>"
+ call assert_fails('exe cmd', 'E730:')
+ bw!
+ delfunc CompleteItems
+endfunc
+
+" Test for the "refresh" item in the dict returned by an insert completion
+" function
+func Test_complete_item_refresh_always()
+ let g:CallCount = 0
+ func! Tcomplete(findstart, base)
+ if a:findstart
+ " locate the start of the word
+ let line = getline('.')
+ let start = col('.') - 1
+ while start > 0 && line[start - 1] =~ '\a'
+ let start -= 1
+ endwhile
+ return start
+ else
+ let g:CallCount += 1
+ let res = ["update1", "update12", "update123"]
+ return #{words: res, refresh: 'always'}
+ endif
+ endfunc
+ new
+ set completeopt=menu,longest
+ set completefunc=Tcomplete
+ exe "normal! iup\<C-X>\<C-U>\<BS>\<BS>\<BS>\<BS>\<BS>"
+ call assert_equal('up', getline(1))
+ call assert_equal(2, g:CallCount)
+ set completeopt&
+ set completefunc&
+ bw!
+ delfunc Tcomplete
+endfunc
+
+" Test for completing from a thesaurus file without read permission
+func Test_complete_unreadable_thesaurus_file()
+ CheckUnix
+ CheckNotRoot
+
+ call writefile(['about', 'above'], 'Xfile')
+ call setfperm('Xfile', '---r--r--')
+ new
+ set complete=sXfile
+ exe "normal! ia\<C-P>"
+ call assert_equal('a', getline(1))
+ bw!
+ call delete('Xfile')
+ set complete&
+endfunc
+
" Test to ensure 'Scanning...' messages are not recorded in messages history
func Test_z1_complete_no_history()
new
@@ -857,7 +1307,7 @@ endfunc
" A mapping is not used for the key after CTRL-X.
func Test_no_mapping_for_ctrl_x_key()
new
- inoremap <C-K> <Cmd>let was_mapped = 'yes'<CR>
+ inoremap <buffer> <C-K> <Cmd>let was_mapped = 'yes'<CR>
setlocal dictionary=README.txt
call feedkeys("aexam\<C-X>\<C-K> ", 'xt')
call assert_equal('example ', getline(1))
@@ -865,6 +1315,813 @@ func Test_no_mapping_for_ctrl_x_key()
bwipe!
endfunc
+" Test for different ways of setting the 'completefunc' option
+func Test_completefunc_callback()
+ func CompleteFunc1(callnr, findstart, base)
+ call add(g:CompleteFunc1Args, [a:callnr, a:findstart, a:base])
+ return a:findstart ? 0 : []
+ endfunc
+ func CompleteFunc2(findstart, base)
+ call add(g:CompleteFunc2Args, [a:findstart, a:base])
+ return a:findstart ? 0 : []
+ endfunc
+
+ let lines =<< trim END
+ #" Test for using a global function name
+ LET &completefunc = 'g:CompleteFunc2'
+ new
+ call setline(1, 'global')
+ LET g:CompleteFunc2Args = []
+ call feedkeys("A\<C-X>\<C-U>\<Esc>", 'x')
+ call assert_equal([[1, ''], [0, 'global']], g:CompleteFunc2Args)
+ bw!
+
+ #" Test for using a function()
+ set completefunc=function('g:CompleteFunc1',\ [10])
+ new
+ call setline(1, 'one')
+ LET g:CompleteFunc1Args = []
+ call feedkeys("A\<C-X>\<C-U>\<Esc>", 'x')
+ call assert_equal([[10, 1, ''], [10, 0, 'one']], g:CompleteFunc1Args)
+ bw!
+
+ #" Using a funcref variable to set 'completefunc'
+ VAR Fn = function('g:CompleteFunc1', [11])
+ LET &completefunc = Fn
+ new
+ call setline(1, 'two')
+ LET g:CompleteFunc1Args = []
+ call feedkeys("A\<C-X>\<C-U>\<Esc>", 'x')
+ call assert_equal([[11, 1, ''], [11, 0, 'two']], g:CompleteFunc1Args)
+ bw!
+
+ #" Using string(funcref_variable) to set 'completefunc'
+ LET Fn = function('g:CompleteFunc1', [12])
+ LET &completefunc = string(Fn)
+ new
+ call setline(1, 'two')
+ LET g:CompleteFunc1Args = []
+ call feedkeys("A\<C-X>\<C-U>\<Esc>", 'x')
+ call assert_equal([[12, 1, ''], [12, 0, 'two']], g:CompleteFunc1Args)
+ bw!
+
+ #" Test for using a funcref()
+ set completefunc=funcref('g:CompleteFunc1',\ [13])
+ new
+ call setline(1, 'three')
+ LET g:CompleteFunc1Args = []
+ call feedkeys("A\<C-X>\<C-U>\<Esc>", 'x')
+ call assert_equal([[13, 1, ''], [13, 0, 'three']], g:CompleteFunc1Args)
+ bw!
+
+ #" Using a funcref variable to set 'completefunc'
+ LET Fn = funcref('g:CompleteFunc1', [14])
+ LET &completefunc = Fn
+ new
+ call setline(1, 'four')
+ LET g:CompleteFunc1Args = []
+ call feedkeys("A\<C-X>\<C-U>\<Esc>", 'x')
+ call assert_equal([[14, 1, ''], [14, 0, 'four']], g:CompleteFunc1Args)
+ bw!
+
+ #" Using a string(funcref_variable) to set 'completefunc'
+ LET Fn = funcref('g:CompleteFunc1', [15])
+ LET &completefunc = string(Fn)
+ new
+ call setline(1, 'four')
+ LET g:CompleteFunc1Args = []
+ call feedkeys("A\<C-X>\<C-U>\<Esc>", 'x')
+ call assert_equal([[15, 1, ''], [15, 0, 'four']], g:CompleteFunc1Args)
+ bw!
+
+ #" Test for using a lambda function with set
+ VAR optval = "LSTART a, b LMIDDLE CompleteFunc1(16, a, b) LEND"
+ LET optval = substitute(optval, ' ', '\\ ', 'g')
+ exe "set completefunc=" .. optval
+ new
+ call setline(1, 'five')
+ LET g:CompleteFunc1Args = []
+ call feedkeys("A\<C-X>\<C-U>\<Esc>", 'x')
+ call assert_equal([[16, 1, ''], [16, 0, 'five']], g:CompleteFunc1Args)
+ bw!
+
+ #" Set 'completefunc' to a lambda expression
+ LET &completefunc = LSTART a, b LMIDDLE CompleteFunc1(17, a, b) LEND
+ new
+ call setline(1, 'six')
+ LET g:CompleteFunc1Args = []
+ call feedkeys("A\<C-X>\<C-U>\<Esc>", 'x')
+ call assert_equal([[17, 1, ''], [17, 0, 'six']], g:CompleteFunc1Args)
+ bw!
+
+ #" Set 'completefunc' to string(lambda_expression)
+ LET &completefunc = 'LSTART a, b LMIDDLE CompleteFunc1(18, a, b) LEND'
+ new
+ call setline(1, 'six')
+ LET g:CompleteFunc1Args = []
+ call feedkeys("A\<C-X>\<C-U>\<Esc>", 'x')
+ call assert_equal([[18, 1, ''], [18, 0, 'six']], g:CompleteFunc1Args)
+ bw!
+
+ #" Set 'completefunc' to a variable with a lambda expression
+ VAR Lambda = LSTART a, b LMIDDLE CompleteFunc1(19, a, b) LEND
+ LET &completefunc = Lambda
+ new
+ call setline(1, 'seven')
+ LET g:CompleteFunc1Args = []
+ call feedkeys("A\<C-X>\<C-U>\<Esc>", 'x')
+ call assert_equal([[19, 1, ''], [19, 0, 'seven']], g:CompleteFunc1Args)
+ bw!
+
+ #" Set 'completefunc' to a string(variable with a lambda expression)
+ LET Lambda = LSTART a, b LMIDDLE CompleteFunc1(20, a, b) LEND
+ LET &completefunc = string(Lambda)
+ new
+ call setline(1, 'seven')
+ LET g:CompleteFunc1Args = []
+ call feedkeys("A\<C-X>\<C-U>\<Esc>", 'x')
+ call assert_equal([[20, 1, ''], [20, 0, 'seven']], g:CompleteFunc1Args)
+ bw!
+
+ #" Test for using a lambda function with incorrect return value
+ LET Lambda = LSTART a, b LMIDDLE strlen(a) LEND
+ LET &completefunc = Lambda
+ new
+ call setline(1, 'eight')
+ call feedkeys("A\<C-X>\<C-U>\<Esc>", 'x')
+ bw!
+
+ #" Test for clearing the 'completefunc' option
+ set completefunc=''
+ set completefunc&
+ call assert_fails("set completefunc=function('abc')", "E700:")
+ call assert_fails("set completefunc=funcref('abc')", "E700:")
+
+ #" set 'completefunc' to a non-existing function
+ set completefunc=CompleteFunc2
+ call setline(1, 'five')
+ call assert_fails("set completefunc=function('NonExistingFunc')", 'E700:')
+ call assert_fails("LET &completefunc = function('NonExistingFunc')", 'E700:')
+ LET g:CompleteFunc2Args = []
+ call feedkeys("A\<C-X>\<C-U>\<Esc>", 'x')
+ call assert_equal([[1, ''], [0, 'five']], g:CompleteFunc2Args)
+ bw!
+ END
+ call CheckLegacyAndVim9Success(lines)
+
+ " Test for using a script-local function name
+ func s:CompleteFunc3(findstart, base)
+ call add(g:CompleteFunc3Args, [a:findstart, a:base])
+ return a:findstart ? 0 : []
+ endfunc
+ set completefunc=s:CompleteFunc3
+ new
+ call setline(1, 'script1')
+ let g:CompleteFunc3Args = []
+ call feedkeys("A\<C-X>\<C-U>\<Esc>", 'x')
+ call assert_equal([[1, ''], [0, 'script1']], g:CompleteFunc3Args)
+ bw!
+
+ let &completefunc = 's:CompleteFunc3'
+ new
+ call setline(1, 'script2')
+ let g:CompleteFunc3Args = []
+ call feedkeys("A\<C-X>\<C-U>\<Esc>", 'x')
+ call assert_equal([[1, ''], [0, 'script2']], g:CompleteFunc3Args)
+ bw!
+ delfunc s:CompleteFunc3
+
+ " invalid return value
+ let &completefunc = {a -> 'abc'}
+ call feedkeys("A\<C-X>\<C-U>\<Esc>", 'x')
+
+ " Using Vim9 lambda expression in legacy context should fail
+ " set completefunc=(a,\ b)\ =>\ CompleteFunc1(21,\ a,\ b)
+ new | only
+ let g:CompleteFunc1Args = []
+ " call assert_fails('call feedkeys("A\<C-X>\<C-U>\<Esc>", "x")', 'E117:')
+ call assert_equal([], g:CompleteFunc1Args)
+
+ " set 'completefunc' to a partial with dict. This used to cause a crash.
+ func SetCompleteFunc()
+ let params = {'complete': function('g:DictCompleteFunc')}
+ let &completefunc = params.complete
+ endfunc
+ func g:DictCompleteFunc(_) dict
+ endfunc
+ call SetCompleteFunc()
+ new
+ call SetCompleteFunc()
+ bw
+ call test_garbagecollect_now()
+ new
+ set completefunc=
+ wincmd w
+ set completefunc=
+ %bw!
+ delfunc g:DictCompleteFunc
+ delfunc SetCompleteFunc
+
+ " Vim9 tests
+ let lines =<< trim END
+ vim9script
+
+ def Vim9CompleteFunc(callnr: number, findstart: number, base: string): any
+ add(g:Vim9completeFuncArgs, [callnr, findstart, base])
+ return findstart ? 0 : []
+ enddef
+
+ # Test for using a def function with completefunc
+ set completefunc=function('Vim9CompleteFunc',\ [60])
+ new | only
+ setline(1, 'one')
+ g:Vim9completeFuncArgs = []
+ feedkeys("A\<C-X>\<C-U>\<Esc>", 'x')
+ assert_equal([[60, 1, ''], [60, 0, 'one']], g:Vim9completeFuncArgs)
+ bw!
+
+ # Test for using a global function name
+ &completefunc = g:CompleteFunc2
+ new | only
+ setline(1, 'two')
+ g:CompleteFunc2Args = []
+ feedkeys("A\<C-X>\<C-U>\<Esc>", 'x')
+ assert_equal([[1, ''], [0, 'two']], g:CompleteFunc2Args)
+ bw!
+
+ # Test for using a script-local function name
+ def s:LocalCompleteFunc(findstart: number, base: string): any
+ add(g:LocalCompleteFuncArgs, [findstart, base])
+ return findstart ? 0 : []
+ enddef
+ &completefunc = s:LocalCompleteFunc
+ new | only
+ setline(1, 'three')
+ g:LocalCompleteFuncArgs = []
+ feedkeys("A\<C-X>\<C-U>\<Esc>", 'x')
+ assert_equal([[1, ''], [0, 'three']], g:LocalCompleteFuncArgs)
+ bw!
+ END
+ call CheckScriptSuccess(lines)
+
+ " cleanup
+ set completefunc&
+ delfunc CompleteFunc1
+ delfunc CompleteFunc2
+ unlet g:CompleteFunc1Args g:CompleteFunc2Args
+ %bw!
+endfunc
+
+" Test for different ways of setting the 'omnifunc' option
+func Test_omnifunc_callback()
+ func OmniFunc1(callnr, findstart, base)
+ call add(g:OmniFunc1Args, [a:callnr, a:findstart, a:base])
+ return a:findstart ? 0 : []
+ endfunc
+ func OmniFunc2(findstart, base)
+ call add(g:OmniFunc2Args, [a:findstart, a:base])
+ return a:findstart ? 0 : []
+ endfunc
+
+ let lines =<< trim END
+ #" Test for using a function name
+ LET &omnifunc = 'g:OmniFunc2'
+ new
+ call setline(1, 'zero')
+ LET g:OmniFunc2Args = []
+ call feedkeys("A\<C-X>\<C-O>\<Esc>", 'x')
+ call assert_equal([[1, ''], [0, 'zero']], g:OmniFunc2Args)
+ bw!
+
+ #" Test for using a function()
+ set omnifunc=function('g:OmniFunc1',\ [10])
+ new
+ call setline(1, 'one')
+ LET g:OmniFunc1Args = []
+ call feedkeys("A\<C-X>\<C-O>\<Esc>", 'x')
+ call assert_equal([[10, 1, ''], [10, 0, 'one']], g:OmniFunc1Args)
+ bw!
+
+ #" Using a funcref variable to set 'omnifunc'
+ VAR Fn = function('g:OmniFunc1', [11])
+ LET &omnifunc = Fn
+ new
+ call setline(1, 'two')
+ LET g:OmniFunc1Args = []
+ call feedkeys("A\<C-X>\<C-O>\<Esc>", 'x')
+ call assert_equal([[11, 1, ''], [11, 0, 'two']], g:OmniFunc1Args)
+ bw!
+
+ #" Using a string(funcref_variable) to set 'omnifunc'
+ LET Fn = function('g:OmniFunc1', [12])
+ LET &omnifunc = string(Fn)
+ new
+ call setline(1, 'two')
+ LET g:OmniFunc1Args = []
+ call feedkeys("A\<C-X>\<C-O>\<Esc>", 'x')
+ call assert_equal([[12, 1, ''], [12, 0, 'two']], g:OmniFunc1Args)
+ bw!
+
+ #" Test for using a funcref()
+ set omnifunc=funcref('g:OmniFunc1',\ [13])
+ new
+ call setline(1, 'three')
+ LET g:OmniFunc1Args = []
+ call feedkeys("A\<C-X>\<C-O>\<Esc>", 'x')
+ call assert_equal([[13, 1, ''], [13, 0, 'three']], g:OmniFunc1Args)
+ bw!
+
+ #" Use let to set 'omnifunc' to a funcref
+ LET Fn = funcref('g:OmniFunc1', [14])
+ LET &omnifunc = Fn
+ new
+ call setline(1, 'four')
+ LET g:OmniFunc1Args = []
+ call feedkeys("A\<C-X>\<C-O>\<Esc>", 'x')
+ call assert_equal([[14, 1, ''], [14, 0, 'four']], g:OmniFunc1Args)
+ bw!
+
+ #" Using a string(funcref) to set 'omnifunc'
+ LET Fn = funcref("g:OmniFunc1", [15])
+ LET &omnifunc = string(Fn)
+ new
+ call setline(1, 'four')
+ LET g:OmniFunc1Args = []
+ call feedkeys("A\<C-X>\<C-O>\<Esc>", 'x')
+ call assert_equal([[15, 1, ''], [15, 0, 'four']], g:OmniFunc1Args)
+ bw!
+
+ #" Test for using a lambda function with set
+ VAR optval = "LSTART a, b LMIDDLE OmniFunc1(16, a, b) LEND"
+ LET optval = substitute(optval, ' ', '\\ ', 'g')
+ exe "set omnifunc=" .. optval
+ new
+ call setline(1, 'five')
+ LET g:OmniFunc1Args = []
+ call feedkeys("A\<C-X>\<C-O>\<Esc>", 'x')
+ call assert_equal([[16, 1, ''], [16, 0, 'five']], g:OmniFunc1Args)
+ bw!
+
+ #" Set 'omnifunc' to a lambda expression
+ LET &omnifunc = LSTART a, b LMIDDLE OmniFunc1(17, a, b) LEND
+ new
+ call setline(1, 'six')
+ LET g:OmniFunc1Args = []
+ call feedkeys("A\<C-X>\<C-O>\<Esc>", 'x')
+ call assert_equal([[17, 1, ''], [17, 0, 'six']], g:OmniFunc1Args)
+ bw!
+
+ #" Set 'omnifunc' to a string(lambda_expression)
+ LET &omnifunc = 'LSTART a, b LMIDDLE OmniFunc1(18, a, b) LEND'
+ new
+ call setline(1, 'six')
+ LET g:OmniFunc1Args = []
+ call feedkeys("A\<C-X>\<C-O>\<Esc>", 'x')
+ call assert_equal([[18, 1, ''], [18, 0, 'six']], g:OmniFunc1Args)
+ bw!
+
+ #" Set 'omnifunc' to a variable with a lambda expression
+ VAR Lambda = LSTART a, b LMIDDLE OmniFunc1(19, a, b) LEND
+ LET &omnifunc = Lambda
+ new
+ call setline(1, 'seven')
+ LET g:OmniFunc1Args = []
+ call feedkeys("A\<C-X>\<C-O>\<Esc>", 'x')
+ call assert_equal([[19, 1, ''], [19, 0, 'seven']], g:OmniFunc1Args)
+ bw!
+
+ #" Set 'omnifunc' to a string(variable with a lambda expression)
+ LET Lambda = LSTART a, b LMIDDLE OmniFunc1(20, a, b) LEND
+ LET &omnifunc = string(Lambda)
+ new
+ call setline(1, 'seven')
+ LET g:OmniFunc1Args = []
+ call feedkeys("A\<C-X>\<C-O>\<Esc>", 'x')
+ call assert_equal([[20, 1, ''], [20, 0, 'seven']], g:OmniFunc1Args)
+ bw!
+
+ #" Test for using a lambda function with incorrect return value
+ LET Lambda = LSTART a, b LMIDDLE strlen(a) LEND
+ LET &omnifunc = Lambda
+ new
+ call setline(1, 'eight')
+ call feedkeys("A\<C-X>\<C-O>\<Esc>", 'x')
+ bw!
+
+ #" Test for clearing the 'omnifunc' option
+ set omnifunc=''
+ set omnifunc&
+ call assert_fails("set omnifunc=function('abc')", "E700:")
+ call assert_fails("set omnifunc=funcref('abc')", "E700:")
+
+ #" set 'omnifunc' to a non-existing function
+ set omnifunc=OmniFunc2
+ call setline(1, 'nine')
+ call assert_fails("set omnifunc=function('NonExistingFunc')", 'E700:')
+ call assert_fails("LET &omnifunc = function('NonExistingFunc')", 'E700:')
+ LET g:OmniFunc2Args = []
+ call feedkeys("A\<C-X>\<C-O>\<Esc>", 'x')
+ call assert_equal([[1, ''], [0, 'nine']], g:OmniFunc2Args)
+ bw!
+ END
+ call CheckLegacyAndVim9Success(lines)
+
+ " Test for using a script-local function name
+ func s:OmniFunc3(findstart, base)
+ call add(g:OmniFunc3Args, [a:findstart, a:base])
+ return a:findstart ? 0 : []
+ endfunc
+ set omnifunc=s:OmniFunc3
+ new
+ call setline(1, 'script1')
+ let g:OmniFunc3Args = []
+ call feedkeys("A\<C-X>\<C-O>\<Esc>", 'x')
+ call assert_equal([[1, ''], [0, 'script1']], g:OmniFunc3Args)
+ bw!
+
+ let &omnifunc = 's:OmniFunc3'
+ new
+ call setline(1, 'script2')
+ let g:OmniFunc3Args = []
+ call feedkeys("A\<C-X>\<C-O>\<Esc>", 'x')
+ call assert_equal([[1, ''], [0, 'script2']], g:OmniFunc3Args)
+ bw!
+ delfunc s:OmniFunc3
+
+ " invalid return value
+ let &omnifunc = {a -> 'abc'}
+ call feedkeys("A\<C-X>\<C-O>\<Esc>", 'x')
+
+ " Using Vim9 lambda expression in legacy context should fail
+ " set omnifunc=(a,\ b)\ =>\ OmniFunc1(21,\ a,\ b)
+ new | only
+ let g:OmniFunc1Args = []
+ " call assert_fails('call feedkeys("A\<C-X>\<C-O>\<Esc>", "x")', 'E117:')
+ call assert_equal([], g:OmniFunc1Args)
+
+ " set 'omnifunc' to a partial with dict. This used to cause a crash.
+ func SetOmniFunc()
+ let params = {'omni': function('g:DictOmniFunc')}
+ let &omnifunc = params.omni
+ endfunc
+ func g:DictOmniFunc(_) dict
+ endfunc
+ call SetOmniFunc()
+ new
+ call SetOmniFunc()
+ bw
+ call test_garbagecollect_now()
+ new
+ set omnifunc=
+ wincmd w
+ set omnifunc=
+ %bw!
+ delfunc g:DictOmniFunc
+ delfunc SetOmniFunc
+
+ " Vim9 tests
+ let lines =<< trim END
+ vim9script
+
+ def Vim9omniFunc(callnr: number, findstart: number, base: string): any
+ add(g:Vim9omniFunc_Args, [callnr, findstart, base])
+ return findstart ? 0 : []
+ enddef
+
+ # Test for using a def function with omnifunc
+ set omnifunc=function('Vim9omniFunc',\ [60])
+ new | only
+ setline(1, 'one')
+ g:Vim9omniFunc_Args = []
+ feedkeys("A\<C-X>\<C-O>\<Esc>", 'x')
+ assert_equal([[60, 1, ''], [60, 0, 'one']], g:Vim9omniFunc_Args)
+ bw!
+
+ # Test for using a global function name
+ &omnifunc = g:OmniFunc2
+ new | only
+ setline(1, 'two')
+ g:OmniFunc2Args = []
+ feedkeys("A\<C-X>\<C-O>\<Esc>", 'x')
+ assert_equal([[1, ''], [0, 'two']], g:OmniFunc2Args)
+ bw!
+
+ # Test for using a script-local function name
+ def s:LocalOmniFunc(findstart: number, base: string): any
+ add(g:LocalOmniFuncArgs, [findstart, base])
+ return findstart ? 0 : []
+ enddef
+ &omnifunc = s:LocalOmniFunc
+ new | only
+ setline(1, 'three')
+ g:LocalOmniFuncArgs = []
+ feedkeys("A\<C-X>\<C-O>\<Esc>", 'x')
+ assert_equal([[1, ''], [0, 'three']], g:LocalOmniFuncArgs)
+ bw!
+ END
+ call CheckScriptSuccess(lines)
+
+ " cleanup
+ set omnifunc&
+ delfunc OmniFunc1
+ delfunc OmniFunc2
+ unlet g:OmniFunc1Args g:OmniFunc2Args
+ %bw!
+endfunc
+
+" Test for different ways of setting the 'thesaurusfunc' option
+func Test_thesaurusfunc_callback()
+ func TsrFunc1(callnr, findstart, base)
+ call add(g:TsrFunc1Args, [a:callnr, a:findstart, a:base])
+ return a:findstart ? 0 : []
+ endfunc
+ func TsrFunc2(findstart, base)
+ call add(g:TsrFunc2Args, [a:findstart, a:base])
+ return a:findstart ? 0 : ['sunday']
+ endfunc
+
+ let lines =<< trim END
+ #" Test for using a function name
+ LET &thesaurusfunc = 'g:TsrFunc2'
+ new
+ call setline(1, 'zero')
+ LET g:TsrFunc2Args = []
+ call feedkeys("A\<C-X>\<C-T>\<Esc>", 'x')
+ call assert_equal([[1, ''], [0, 'zero']], g:TsrFunc2Args)
+ bw!
+
+ #" Test for using a function()
+ set thesaurusfunc=function('g:TsrFunc1',\ [10])
+ new
+ call setline(1, 'one')
+ LET g:TsrFunc1Args = []
+ call feedkeys("A\<C-X>\<C-T>\<Esc>", 'x')
+ call assert_equal([[10, 1, ''], [10, 0, 'one']], g:TsrFunc1Args)
+ bw!
+
+ #" Using a funcref variable to set 'thesaurusfunc'
+ VAR Fn = function('g:TsrFunc1', [11])
+ LET &thesaurusfunc = Fn
+ new
+ call setline(1, 'two')
+ LET g:TsrFunc1Args = []
+ call feedkeys("A\<C-X>\<C-T>\<Esc>", 'x')
+ call assert_equal([[11, 1, ''], [11, 0, 'two']], g:TsrFunc1Args)
+ bw!
+
+ #" Using a string(funcref_variable) to set 'thesaurusfunc'
+ LET Fn = function('g:TsrFunc1', [12])
+ LET &thesaurusfunc = string(Fn)
+ new
+ call setline(1, 'two')
+ LET g:TsrFunc1Args = []
+ call feedkeys("A\<C-X>\<C-T>\<Esc>", 'x')
+ call assert_equal([[12, 1, ''], [12, 0, 'two']], g:TsrFunc1Args)
+ bw!
+
+ #" Test for using a funcref()
+ set thesaurusfunc=funcref('g:TsrFunc1',\ [13])
+ new
+ call setline(1, 'three')
+ LET g:TsrFunc1Args = []
+ call feedkeys("A\<C-X>\<C-T>\<Esc>", 'x')
+ call assert_equal([[13, 1, ''], [13, 0, 'three']], g:TsrFunc1Args)
+ bw!
+
+ #" Using a funcref variable to set 'thesaurusfunc'
+ LET Fn = funcref('g:TsrFunc1', [14])
+ LET &thesaurusfunc = Fn
+ new
+ call setline(1, 'four')
+ LET g:TsrFunc1Args = []
+ call feedkeys("A\<C-X>\<C-T>\<Esc>", 'x')
+ call assert_equal([[14, 1, ''], [14, 0, 'four']], g:TsrFunc1Args)
+ bw!
+
+ #" Using a string(funcref_variable) to set 'thesaurusfunc'
+ LET Fn = funcref('g:TsrFunc1', [15])
+ LET &thesaurusfunc = string(Fn)
+ new
+ call setline(1, 'four')
+ LET g:TsrFunc1Args = []
+ call feedkeys("A\<C-X>\<C-T>\<Esc>", 'x')
+ call assert_equal([[15, 1, ''], [15, 0, 'four']], g:TsrFunc1Args)
+ bw!
+
+ #" Test for using a lambda function
+ VAR optval = "LSTART a, b LMIDDLE TsrFunc1(16, a, b) LEND"
+ LET optval = substitute(optval, ' ', '\\ ', 'g')
+ exe "set thesaurusfunc=" .. optval
+ new
+ call setline(1, 'five')
+ LET g:TsrFunc1Args = []
+ call feedkeys("A\<C-X>\<C-T>\<Esc>", 'x')
+ call assert_equal([[16, 1, ''], [16, 0, 'five']], g:TsrFunc1Args)
+ bw!
+
+ #" Test for using a lambda function with set
+ LET &thesaurusfunc = LSTART a, b LMIDDLE TsrFunc1(17, a, b) LEND
+ new
+ call setline(1, 'six')
+ LET g:TsrFunc1Args = []
+ call feedkeys("A\<C-X>\<C-T>\<Esc>", 'x')
+ call assert_equal([[17, 1, ''], [17, 0, 'six']], g:TsrFunc1Args)
+ bw!
+
+ #" Set 'thesaurusfunc' to a string(lambda expression)
+ LET &thesaurusfunc = 'LSTART a, b LMIDDLE TsrFunc1(18, a, b) LEND'
+ new
+ call setline(1, 'six')
+ LET g:TsrFunc1Args = []
+ call feedkeys("A\<C-X>\<C-T>\<Esc>", 'x')
+ call assert_equal([[18, 1, ''], [18, 0, 'six']], g:TsrFunc1Args)
+ bw!
+
+ #" Set 'thesaurusfunc' to a variable with a lambda expression
+ VAR Lambda = LSTART a, b LMIDDLE TsrFunc1(19, a, b) LEND
+ LET &thesaurusfunc = Lambda
+ new
+ call setline(1, 'seven')
+ LET g:TsrFunc1Args = []
+ call feedkeys("A\<C-X>\<C-T>\<Esc>", 'x')
+ call assert_equal([[19, 1, ''], [19, 0, 'seven']], g:TsrFunc1Args)
+ bw!
+
+ #" Set 'thesaurusfunc' to a string(variable with a lambda expression)
+ LET Lambda = LSTART a, b LMIDDLE TsrFunc1(20, a, b) LEND
+ LET &thesaurusfunc = string(Lambda)
+ new
+ call setline(1, 'seven')
+ LET g:TsrFunc1Args = []
+ call feedkeys("A\<C-X>\<C-T>\<Esc>", 'x')
+ call assert_equal([[20, 1, ''], [20, 0, 'seven']], g:TsrFunc1Args)
+ bw!
+
+ #" Test for using a lambda function with incorrect return value
+ LET Lambda = LSTART a, b LMIDDLE strlen(a) LEND
+ LET &thesaurusfunc = Lambda
+ new
+ call setline(1, 'eight')
+ call feedkeys("A\<C-X>\<C-T>\<Esc>", 'x')
+ bw!
+
+ #" Test for clearing the 'thesaurusfunc' option
+ set thesaurusfunc=''
+ set thesaurusfunc&
+ call assert_fails("set thesaurusfunc=function('abc')", "E700:")
+ call assert_fails("set thesaurusfunc=funcref('abc')", "E700:")
+
+ #" set 'thesaurusfunc' to a non-existing function
+ set thesaurusfunc=TsrFunc2
+ call setline(1, 'ten')
+ call assert_fails("set thesaurusfunc=function('NonExistingFunc')", 'E700:')
+ call assert_fails("LET &thesaurusfunc = function('NonExistingFunc')", 'E700:')
+ LET g:TsrFunc2Args = []
+ call feedkeys("A\<C-X>\<C-T>\<Esc>", 'x')
+ call assert_equal([[1, ''], [0, 'ten']], g:TsrFunc2Args)
+ bw!
+
+ #" Use a buffer-local value and a global value
+ set thesaurusfunc&
+ setlocal thesaurusfunc=function('g:TsrFunc1',\ [22])
+ call setline(1, 'sun')
+ LET g:TsrFunc1Args = []
+ call feedkeys("A\<C-X>\<C-T>\<Esc>", "x")
+ call assert_equal('sun', getline(1))
+ call assert_equal([[22, 1, ''], [22, 0, 'sun']], g:TsrFunc1Args)
+ new
+ call setline(1, 'sun')
+ LET g:TsrFunc1Args = []
+ call feedkeys("A\<C-X>\<C-T>\<Esc>", "x")
+ call assert_equal('sun', getline(1))
+ call assert_equal([], g:TsrFunc1Args)
+ set thesaurusfunc=function('g:TsrFunc1',\ [23])
+ wincmd w
+ call setline(1, 'sun')
+ LET g:TsrFunc1Args = []
+ call feedkeys("A\<C-X>\<C-T>\<Esc>", "x")
+ call assert_equal('sun', getline(1))
+ call assert_equal([[22, 1, ''], [22, 0, 'sun']], g:TsrFunc1Args)
+ :%bw!
+ END
+ call CheckLegacyAndVim9Success(lines)
+
+ " Test for using a script-local function name
+ func s:TsrFunc3(findstart, base)
+ call add(g:TsrFunc3Args, [a:findstart, a:base])
+ return a:findstart ? 0 : []
+ endfunc
+ set tsrfu=s:TsrFunc3
+ new
+ call setline(1, 'script1')
+ let g:TsrFunc3Args = []
+ call feedkeys("A\<C-X>\<C-T>\<Esc>", 'x')
+ call assert_equal([[1, ''], [0, 'script1']], g:TsrFunc3Args)
+ bw!
+
+ let &tsrfu = 's:TsrFunc3'
+ new
+ call setline(1, 'script2')
+ let g:TsrFunc3Args = []
+ call feedkeys("A\<C-X>\<C-T>\<Esc>", 'x')
+ call assert_equal([[1, ''], [0, 'script2']], g:TsrFunc3Args)
+ bw!
+ delfunc s:TsrFunc3
+
+ " invalid return value
+ let &thesaurusfunc = {a -> 'abc'}
+ call feedkeys("A\<C-X>\<C-T>\<Esc>", 'x')
+
+ " Using Vim9 lambda expression in legacy context should fail
+ " set thesaurusfunc=(a,\ b)\ =>\ TsrFunc1(21,\ a,\ b)
+ new | only
+ let g:TsrFunc1Args = []
+ " call assert_fails('call feedkeys("A\<C-X>\<C-T>\<Esc>", "x")', 'E117:')
+ call assert_equal([], g:TsrFunc1Args)
+ bw!
+
+ " set 'thesaurusfunc' to a partial with dict. This used to cause a crash.
+ func SetTsrFunc()
+ let params = {'thesaurus': function('g:DictTsrFunc')}
+ let &thesaurusfunc = params.thesaurus
+ endfunc
+ func g:DictTsrFunc(_) dict
+ endfunc
+ call SetTsrFunc()
+ new
+ call SetTsrFunc()
+ bw
+ call test_garbagecollect_now()
+ new
+ set thesaurusfunc=
+ wincmd w
+ %bw!
+ delfunc SetTsrFunc
+
+ " set buffer-local 'thesaurusfunc' to a partial with dict. This used to
+ " cause a crash.
+ func SetLocalTsrFunc()
+ let params = {'thesaurus': function('g:DictTsrFunc')}
+ let &l:thesaurusfunc = params.thesaurus
+ endfunc
+ call SetLocalTsrFunc()
+ call test_garbagecollect_now()
+ call SetLocalTsrFunc()
+ set thesaurusfunc=
+ bw!
+ delfunc g:DictTsrFunc
+ delfunc SetLocalTsrFunc
+
+ " Vim9 tests
+ let lines =<< trim END
+ vim9script
+
+ def Vim9tsrFunc(callnr: number, findstart: number, base: string): any
+ add(g:Vim9tsrFunc_Args, [callnr, findstart, base])
+ return findstart ? 0 : []
+ enddef
+
+ # Test for using a def function with thesaurusfunc
+ set thesaurusfunc=function('Vim9tsrFunc',\ [60])
+ new | only
+ setline(1, 'one')
+ g:Vim9tsrFunc_Args = []
+ feedkeys("A\<C-X>\<C-T>\<Esc>", 'x')
+ assert_equal([[60, 1, ''], [60, 0, 'one']], g:Vim9tsrFunc_Args)
+ bw!
+
+ # Test for using a global function name
+ &thesaurusfunc = g:TsrFunc2
+ new | only
+ setline(1, 'two')
+ g:TsrFunc2Args = []
+ feedkeys("A\<C-X>\<C-T>\<Esc>", 'x')
+ assert_equal([[1, ''], [0, 'two']], g:TsrFunc2Args)
+ bw!
+
+ # Test for using a script-local function name
+ def s:LocalTsrFunc(findstart: number, base: string): any
+ add(g:LocalTsrFuncArgs, [findstart, base])
+ return findstart ? 0 : []
+ enddef
+ &thesaurusfunc = s:LocalTsrFunc
+ new | only
+ setline(1, 'three')
+ g:LocalTsrFuncArgs = []
+ feedkeys("A\<C-X>\<C-T>\<Esc>", 'x')
+ assert_equal([[1, ''], [0, 'three']], g:LocalTsrFuncArgs)
+ bw!
+ END
+ call CheckScriptSuccess(lines)
+
+ " cleanup
+ set thesaurusfunc&
+ delfunc TsrFunc1
+ delfunc TsrFunc2
+ unlet g:TsrFunc1Args g:TsrFunc2Args
+ %bw!
+endfunc
+
func FooBarComplete(findstart, base)
if a:findstart
return col('.') - 1
@@ -884,4 +2141,52 @@ func Test_complete_smartindent()
delfunction! FooBarComplete
endfunc
+func Test_complete_overrun()
+ " this was going past the end of the copied text
+ new
+ sil norm si”0s0 
+ bwipe!
+endfunc
+
+func Test_infercase_very_long_line()
+ " this was truncating the line when inferring case
+ new
+ let longLine = "blah "->repeat(300)
+ let verylongLine = "blah "->repeat(400)
+ call setline(1, verylongLine)
+ call setline(2, longLine)
+ set ic infercase
+ exe "normal 2Go\<C-X>\<C-L>\<Esc>"
+ call assert_equal(longLine, getline(3))
+
+ " check that the too long text is NUL terminated
+ %del
+ norm o
+ norm 1987ax
+ exec "norm ox\<C-X>\<C-L>"
+ call assert_equal(repeat('x', 1987), getline(3))
+
+ bwipe!
+ set noic noinfercase
+endfunc
+
+func Test_ins_complete_add()
+ " this was reading past the end of allocated memory
+ new
+ norm o
+ norm 7o€€
+ sil! norm o
+
+ bwipe!
+endfunc
+
+func Test_ins_complete_end_of_line()
+ " this was reading past the end of the line
+ new
+ norm 8o€ý 
+ sil! norm o
+
+ bwipe!
+endfunc
+
" vim: shiftwidth=2 sts=2 expandtab
diff --git a/src/nvim/testdir/test_lambda.vim b/src/nvim/testdir/test_lambda.vim
index c1fe47d1c9..025eb016a8 100644
--- a/src/nvim/testdir/test_lambda.vim
+++ b/src/nvim/testdir/test_lambda.vim
@@ -62,7 +62,8 @@ endfunc
function Test_lambda_fails()
call assert_equal(3, {a, b -> a + b}(1, 2))
call assert_fails('echo {a, a -> a + a}(1, 2)', 'E853:')
- call assert_fails('echo {a, b -> a + b)}(1, 2)', 'E15:')
+ call assert_fails('echo {a, b -> a + b)}(1, 2)', 'E451:')
+ echo assert_fails('echo 10->{a -> a + 2}', 'E107:')
endfunc
func Test_not_lambda()
@@ -125,7 +126,7 @@ func Test_lambda_closure_counter()
endfunc
let l:F = s:foo()
- call garbagecollect()
+ call test_garbagecollect_now()
call assert_equal(1, l:F())
call assert_equal(2, l:F())
call assert_equal(3, l:F())
@@ -208,9 +209,9 @@ func Test_lambda_circular_reference()
endfunc
call s:Foo()
- call garbagecollect()
+ call test_garbagecollect_now()
let i = 0 | while i < 10000 | call s:Foo() | let i+= 1 | endwhile
- call garbagecollect()
+ call test_garbagecollect_now()
endfunc
func Test_lambda_combination()
@@ -239,11 +240,16 @@ func Test_closure_counter()
endfunc
let l:F = s:foo()
- call garbagecollect()
+ call test_garbagecollect_now()
call assert_equal(1, l:F())
call assert_equal(2, l:F())
call assert_equal(3, l:F())
call assert_equal(4, l:F())
+
+ call assert_match("^\n function <SNR>\\d\\+_bar() closure"
+ \ .. "\n1 let x += 1"
+ \ .. "\n2 return x"
+ \ .. "\n endfunction$", execute('func s:bar'))
endfunc
func Test_closure_unlet()
@@ -257,7 +263,7 @@ func Test_closure_unlet()
endfunc
call assert_false(has_key(s:foo(), 'x'))
- call garbagecollect()
+ call test_garbagecollect_now()
endfunc
func LambdaFoo()
@@ -294,7 +300,7 @@ func Test_named_function_closure()
endfunc
call Afoo()
call assert_equal(14, s:Abar())
- call garbagecollect()
+ call test_garbagecollect_now()
call assert_equal(14, s:Abar())
endfunc
@@ -308,3 +314,21 @@ func Test_lambda_error()
" This was causing a crash
call assert_fails('ec{@{->{d->()()', 'E15')
endfunc
+
+func Test_closure_error()
+ let l =<< trim END
+ func F1() closure
+ return 1
+ endfunc
+ END
+ call writefile(l, 'Xscript')
+ let caught_932 = 0
+ try
+ source Xscript
+ catch /E932:/
+ let caught_932 = 1
+ endtry
+ call assert_equal(1, caught_932)
+endfunc
+
+" vim: shiftwidth=2 sts=2 expandtab
diff --git a/src/nvim/testdir/test_langmap.vim b/src/nvim/testdir/test_langmap.vim
index 4f831aa40b..aaed77e109 100644
--- a/src/nvim/testdir/test_langmap.vim
+++ b/src/nvim/testdir/test_langmap.vim
@@ -49,6 +49,41 @@ func Test_langmap()
call feedkeys(';', 'tx')
call assert_equal(5, col('.'))
+ set langmap=RL
+ let g:counter = 0
+ nnoremap L;L <Cmd>let g:counter += 1<CR>
+ nnoremap <C-L> <Cmd>throw 'This mapping should not be triggered'<CR>
+
+ " 'langmap' is applied to keys without modifiers when matching a mapping
+ call feedkeys('R;R', 'tx')
+ call assert_equal(1, g:counter)
+ nunmap L;L
+ unlet g:counter
+
+ delete
+ call assert_equal('', getline(1))
+ undo
+ call assert_equal('Hello World', getline(1))
+ " 'langmap' does not change Ctrl-R to Ctrl-L for consistency
+ call feedkeys("\<*C-R>", 'tx')
+ call assert_equal('', getline(1))
+
+ set langmap=6L
+ undo
+ setlocal bufhidden=hide
+ let oldbuf = bufnr()
+ enew
+ call assert_notequal(oldbuf, bufnr())
+ " 'langmap' does not change Ctrl-6 to Ctrl-L for consistency
+ " Ctrl-6 becomes Ctrl-^ after merging the Ctrl modifier
+ call feedkeys("\<*C-6>", 'tx')
+ call assert_equal(oldbuf, bufnr())
+ setlocal bufhidden&
+
+ nunmap <C-L>
+
set langmap&
quit!
endfunc
+
+" vim: shiftwidth=2 sts=2 expandtab
diff --git a/src/nvim/testdir/test_legacy_filetype.vim b/src/nvim/testdir/test_legacy_filetype.vim
deleted file mode 100644
index 772faaadb0..0000000000
--- a/src/nvim/testdir/test_legacy_filetype.vim
+++ /dev/null
@@ -1,4 +0,0 @@
-let g:do_legacy_filetype = 1
-filetype on
-
-source test_filetype.vim
diff --git a/src/nvim/testdir/test_let.vim b/src/nvim/testdir/test_let.vim
index 6cb736a38a..35745e9c6a 100644
--- a/src/nvim/testdir/test_let.vim
+++ b/src/nvim/testdir/test_let.vim
@@ -6,6 +6,10 @@ func Test_let()
let Test104#numvar = function('tr')
call assert_equal("function('tr')", string(Test104#numvar))
+ let foo#tr = function('tr')
+ call assert_equal("function('tr')", string(foo#tr))
+ unlet foo#tr
+
let a = 1
let b = 2
@@ -25,9 +29,62 @@ func Test_let()
let s = "\na #1\nb #2"
call assert_equal(s, out)
+ " Test for displaying a string variable
+ let s = 'vim'
+ let out = execute('let s')
+ let s = "\ns vim"
+ call assert_equal(s, out)
+
+ " Test for displaying a list variable
+ let l = [1, 2]
+ let out = execute('let l')
+ let s = "\nl [1, 2]"
+ call assert_equal(s, out)
+
+ " Test for displaying a dict variable
+ let d = {'k' : 'v'}
+ let out = execute('let d')
+ let s = "\nd {'k': 'v'}"
+ call assert_equal(s, out)
+
+ " Test for displaying a function reference variable
+ let F = function('min')
+ let out = execute('let F')
+ let s = "\nF *min()"
+ call assert_equal(s, out)
+
let x = 0
if 0 | let x = 1 | endif
call assert_equal(0, x)
+
+ " Display a list item using an out of range index
+ let l = [10]
+ call assert_fails('let l[1]', 'E684:')
+
+ " List special variable dictionaries
+ let g:Test_Global_Var = 5
+ call assert_match("\nTest_Global_Var #5", execute('let g:'))
+ unlet g:Test_Global_Var
+
+ let b:Test_Buf_Var = 8
+ call assert_match("\nb:Test_Buf_Var #8", execute('let b:'))
+ unlet b:Test_Buf_Var
+
+ let w:Test_Win_Var = 'foo'
+ call assert_equal("\nw:Test_Win_Var foo", execute('let w:'))
+ unlet w:Test_Win_Var
+
+ let t:Test_Tab_Var = 'bar'
+ call assert_equal("\nt:Test_Tab_Var bar", execute('let t:'))
+ unlet t:Test_Tab_Var
+
+ let s:Test_Script_Var = [7]
+ call assert_match("\ns:Test_Script_Var \\[7]", execute('let s:'))
+ unlet s:Test_Script_Var
+
+ let l:Test_Local_Var = {'k' : 5}
+ call assert_match("\nl:Test_Local_Var {'k': 5}", execute('let l:'))
+ call assert_match("v:errors []", execute('let v:'))
endfunc
func s:set_arg1(a) abort
@@ -201,16 +258,68 @@ func Test_let_option_error()
let &fillchars = _w
endfunc
+" Errors with the :let statement
func Test_let_errors()
let s = 'abcd'
call assert_fails('let s[1] = 5', 'E689:')
let l = [1, 2, 3]
call assert_fails('let l[:] = 5', 'E709:')
+
+ call assert_fails('let x:lnum=5', ['E121:', 'E488:'])
+ call assert_fails('let v:=5', 'E461:')
+ call assert_fails('let [a]', 'E474:')
+ call assert_fails('let [a, b] = [', 'E697:')
+ call assert_fails('let [a, b] = [10, 20', 'E696:')
+ call assert_fails('let [a, b] = 10', 'E714:')
+ call assert_fails('let [a, , b] = [10, 20]', 'E475:')
+ call assert_fails('let [a, b&] = [10, 20]', 'E475:')
+ call assert_fails('let $ = 10', 'E475:')
+ call assert_fails('let $FOO[1] = "abc"', 'E18:')
+ call assert_fails('let &buftype[1] = "nofile"', 'E18:')
+ let s = "var"
+ let var = 1
+ call assert_fails('let var += [1,2]', 'E734:')
+ call assert_fails('let {s}.1 = 2', 'E1203:')
+ call assert_fails('let a[1] = 5', 'E121:')
+ let l = [[1,2]]
+ call assert_fails('let l[:][0] = [5]', 'E708:')
+ let d = {'k' : 4}
+ call assert_fails('let d.# = 5', 'E488:')
+ call assert_fails('let d.m += 5', 'E716:')
+ call assert_fails('let m = d[{]', 'E15:')
+ let l = [1, 2]
+ call assert_fails('let l[2] = 0', 'E684:')
+ call assert_fails('let l[0:1] = [1, 2, 3]', 'E710:')
+ call assert_fails('let l[-2:-3] = [3, 4]', 'E684:')
+ call assert_fails('let l[0:4] = [5, 6]', 'E711:')
+ call assert_fails('let l -= 2', 'E734:')
+ call assert_fails('let l += 2', 'E734:')
+ call assert_fails('let g:["a;b"] = 10', 'E461:')
+ call assert_fails('let g:.min = function("max")', 'E704:')
+ call assert_fails('let g:cos = "" | let g:.cos = {-> 42}', 'E704:')
+ if has('channel')
+ let ch = test_null_channel()
+ call assert_fails('let ch += 1', 'E734:')
+ endif
+ call assert_fails('let name = "a" .. "b",', 'E488: Trailing characters: ,')
+
+ " This test works only when the language is English
+ if v:lang == "C" || v:lang =~ '^[Ee]n'
+ call assert_fails('let [a ; b;] = [10, 20]',
+ \ 'Double ; in list of variables')
+ endif
endfunc
func Test_let_heredoc_fails()
call assert_fails('let v =<< marker', 'E991:')
+ try
+ exe "let v =<< TEXT | abc | TEXT"
+ call assert_report('No exception thrown')
+ catch /E488:/
+ catch
+ call assert_report("Caught exception: " .. v:exception)
+ endtry
let text =<< trim END
func WrongSyntax()
@@ -243,6 +352,10 @@ func Test_let_heredoc_fails()
call writefile(text, 'XheredocBadMarker')
call assert_fails('source XheredocBadMarker', 'E221:')
call delete('XheredocBadMarker')
+
+ call writefile(['let v =<< TEXT', 'abc'], 'XheredocMissingMarker')
+ call assert_fails('source XheredocMissingMarker', 'E990:')
+ call delete('XheredocMissingMarker')
endfunc
func Test_let_heredoc_trim_no_indent_marker()
@@ -361,3 +474,5 @@ E
END
call assert_equal([' x', ' \y', ' z'], [a, b, c])
endfunc
+
+" vim: shiftwidth=2 sts=2 expandtab
diff --git a/src/nvim/testdir/test_lispwords.vim b/src/nvim/testdir/test_lispindent.vim
index 4144fb0521..2d6060bba3 100644
--- a/src/nvim/testdir/test_lispwords.vim
+++ b/src/nvim/testdir/test_lispindent.vim
@@ -86,6 +86,37 @@ func Test_lisp_indent()
set nolisp
endfunc
+func Test_lispindent_negative()
+ " in legacy script there is no error
+ call assert_equal(-1, lispindent(-1))
+endfunc
+
+func Test_lispindent_with_indentexpr()
+ enew
+ setl ai lisp nocin indentexpr=11
+ exe "normal a(x\<CR>1\<CR>2)\<Esc>"
+ let expected = ['(x', ' 1', ' 2)']
+ call assert_equal(expected, getline(1, 3))
+ " with Lisp indenting the first line is not indented
+ normal 1G=G
+ call assert_equal(expected, getline(1, 3))
+
+ %del
+ setl lispoptions=expr:1 indentexpr=5
+ exe "normal a(x\<CR>1\<CR>2)\<Esc>"
+ let expected_expr = ['(x', ' 1', ' 2)']
+ call assert_equal(expected_expr, getline(1, 3))
+ normal 2G2<<=G
+ call assert_equal(expected_expr, getline(1, 3))
+
+ setl lispoptions=expr:0
+ " with Lisp indenting the first line is not indented
+ normal 1G3<<=G
+ call assert_equal(expected, getline(1, 3))
+
+ bwipe!
+endfunc
+
func Test_lisp_indent_works()
" This was reading beyond the end of the line
new
diff --git a/src/nvim/testdir/test_listdict.vim b/src/nvim/testdir/test_listdict.vim
index 2f4e1db4a1..9ecd83265a 100644
--- a/src/nvim/testdir/test_listdict.vim
+++ b/src/nvim/testdir/test_listdict.vim
@@ -31,6 +31,12 @@ func Test_list_slice()
call assert_equal([1, 'as''d', [1, 2, function('strlen')]], l[:-2])
call assert_equal([1, 'as''d', [1, 2, function('strlen')], {'a': 1}], l[0:8])
call assert_equal([], l[8:-1])
+ call assert_equal([], l[0:-10])
+ " perform an operation on a list slice
+ let l = [1, 2, 3]
+ let l[:1] += [1, 2]
+ let l[2:] -= [1]
+ call assert_equal([2, 4, 2], l)
endfunc
" List identity
@@ -104,6 +110,8 @@ func Test_list_range_assign()
let l = [0]
let l[:] = [1, 2]
call assert_equal([1, 2], l)
+ let l[-4:-1] = [5, 6]
+ call assert_equal([5, 6], l)
endfunc
" Test removing items in list
@@ -143,6 +151,20 @@ func Test_list_func_remove()
call assert_fails("call remove(l, l)", 'E745:')
endfunc
+" List add() function
+func Test_list_add()
+ let l = []
+ call add(l, 1)
+ call add(l, [2, 3])
+ call add(l, [])
+ call add(l, v:_null_list)
+ call add(l, {'k' : 3})
+ call add(l, {})
+ call add(l, v:_null_dict)
+ call assert_equal([1, [2, 3], [], [], {'k' : 3}, {}, {}], l)
+ " call assert_equal(1, add(v:_null_list, 4))
+endfunc
+
" Tests for Dictionary type
func Test_dict()
@@ -165,6 +187,26 @@ func Test_dict()
call assert_equal({'c': 'ccc', '1': 99, 'b': [1, 2, function('strlen')], '3': 33, '-1': {'a': 1}}, d)
call filter(d, 'v:key =~ ''[ac391]''')
call assert_equal({'c': 'ccc', '1': 99, '3': 33, '-1': {'a': 1}}, d)
+
+ " duplicate key
+ call assert_fails("let d = {'k' : 10, 'k' : 20}", 'E721:')
+ " missing comma
+ call assert_fails("let d = {'k' : 10 'k' : 20}", 'E722:')
+ " missing curly brace
+ call assert_fails("let d = {'k' : 10,", 'E723:')
+ " invalid key
+ call assert_fails('let d = #{++ : 10}', 'E15:')
+ " wrong type for key
+ call assert_fails('let d={[] : 10}', 'E730:')
+ " undefined variable as value
+ call assert_fails("let d={'k' : i}", 'E121:')
+
+ " allow key starting with number at the start, not a curly expression
+ call assert_equal({'1foo': 77}, #{1foo: 77})
+
+ " #{expr} is not a curly expression
+ let x = 'x'
+ call assert_equal(#{g: x}, #{g:x})
endfunc
" Dictionary identity
@@ -247,6 +289,16 @@ func Test_dict_func()
call assert_equal('xxx3', Fn('xxx'))
endfunc
+func Test_dict_assign()
+ let d = {}
+ let d.1 = 1
+ let d._ = 2
+ call assert_equal({'1': 1, '_': 2}, d)
+
+ let n = 0
+ call assert_fails('let n.key = 3', 'E1203: Dot can only be used on a dictionary: n.key = 3')
+endfunc
+
" Function in script-local List or Dict
func Test_script_local_dict_func()
let g:dict = {}
@@ -259,7 +311,7 @@ func Test_script_local_dict_func()
unlet g:dict
endfunc
-" Test removing items in la dictionary
+" Test removing items in a dictionary
func Test_dict_func_remove()
let d = {1:'a', 2:'b', 3:'c'}
call assert_equal('b', remove(d, 2))
@@ -294,17 +346,18 @@ func Test_dict_deepcopy()
let l = [4, d, 6]
let d[3] = l
let dc = deepcopy(d)
- call assert_fails('call deepcopy(d, 1)', 'E698')
+ call assert_fails('call deepcopy(d, 1)', 'E698:')
let l2 = [0, l, l, 3]
let l[1] = l2
let l3 = deepcopy(l2)
call assert_true(l3[1] is l3[2])
+ call assert_fails("call deepcopy([1, 2], 2)", 'E1023:')
endfunc
" Locked variables
func Test_list_locked_var()
let expected = [
- \ [['0000-000', 'ppppppp'],
+ \ [['1000-000', 'ppppppF'],
\ ['0000-000', 'ppppppp'],
\ ['0000-000', 'ppppppp']],
\ [['1000-000', 'ppppppF'],
@@ -331,7 +384,7 @@ func Test_list_locked_var()
exe "unlockvar " . depth . " l"
endif
let ps = islocked("l").islocked("l[1]").islocked("l[1][1]").islocked("l[1][1][0]").'-'.islocked("l[2]").islocked("l[2]['6']").islocked("l[2]['6'][7]")
- call assert_equal(expected[depth][u][0], ps)
+ call assert_equal(expected[depth][u][0], ps, 'depth: ' .. depth)
let ps = ''
try
let l[1][1][0] = 99
@@ -375,15 +428,20 @@ func Test_list_locked_var()
catch
let ps .= 'F'
endtry
- call assert_equal(expected[depth][u][1], ps)
+ call assert_equal(expected[depth][u][1], ps, 'depth: ' .. depth)
endfor
endfor
+ call assert_fails("let x=islocked('a b')", 'E488:')
+ let mylist = [1, 2, 3]
+ call assert_fails("let x = islocked('mylist[1:2]')", 'E786:')
+ let mydict = {'k' : 'v'}
+ call assert_fails("let x = islocked('mydict.a')", 'E716:')
endfunc
" Unletting locked variables
func Test_list_locked_var_unlet()
let expected = [
- \ [['0000-000', 'ppppppp'],
+ \ [['1000-000', 'ppppppp'],
\ ['0000-000', 'ppppppp'],
\ ['0000-000', 'ppppppp']],
\ [['1000-000', 'ppFppFp'],
@@ -411,7 +469,7 @@ func Test_list_locked_var_unlet()
exe "unlockvar " . depth . " l"
endif
let ps = islocked("l").islocked("l[1]").islocked("l[1][1]").islocked("l[1][1][0]").'-'.islocked("l[2]").islocked("l[2]['6']").islocked("l[2]['6'][7]")
- call assert_equal(expected[depth][u][0], ps)
+ call assert_equal(expected[depth][u][0], ps, 'depth: ' .. depth)
let ps = ''
try
unlet l[2]['6'][7]
@@ -458,6 +516,11 @@ func Test_list_locked_var_unlet()
call assert_equal(expected[depth][u][1], ps)
endfor
endfor
+ " Deleting a list range should fail if the range is locked
+ let l = [1, 2, 3, 4]
+ lockvar l[1:2]
+ call assert_fails('unlet l[1:2]', 'E741:')
+ unlet l
endfunc
" Locked variables and :unlet or list / dict functions
@@ -567,6 +630,18 @@ func Test_let_lock_list()
unlet l
endfunc
+" Locking part of the list
+func Test_let_lock_list_items()
+ let l = [1, 2, 3, 4]
+ lockvar l[2:]
+ call assert_equal(0, islocked('l[0]'))
+ call assert_equal(1, islocked('l[2]'))
+ call assert_equal(1, islocked('l[3]'))
+ call assert_fails('let l[2] = 10', 'E741:')
+ call assert_fails('let l[3] = 20', 'E741:')
+ unlet l
+endfunc
+
" lockvar/islocked() triggering script autoloading
func Test_lockvar_script_autoload()
let old_rtp = &rtp
@@ -598,26 +673,35 @@ func Test_func_arg_list()
call s:arg_list_test(1, 2, [3, 4], {5: 6})
endfunc
+func Test_dict_item_locked()
+endfunc
+
" Tests for reverse(), sort(), uniq()
func Test_reverse_sort_uniq()
let l = ['-0', 'A11', 2, 2, 'xaaa', 4, 'foo', 'foo6', 'foo', [0, 1, 2], 'x8', [0, 1, 2], 1.5]
call assert_equal(['-0', 'A11', 2, 'xaaa', 4, 'foo', 'foo6', 'foo', [0, 1, 2], 'x8', [0, 1, 2], 1.5], uniq(copy(l)))
call assert_equal([1.5, [0, 1, 2], 'x8', [0, 1, 2], 'foo', 'foo6', 'foo', 4, 'xaaa', 2, 2, 'A11', '-0'], reverse(l))
call assert_equal([1.5, [0, 1, 2], 'x8', [0, 1, 2], 'foo', 'foo6', 'foo', 4, 'xaaa', 2, 2, 'A11', '-0'], reverse(reverse(l)))
- call assert_equal(['-0', 'A11', 'foo', 'foo', 'foo6', 'x8', 'xaaa', 1.5, 2, 2, 4, [0, 1, 2], [0, 1, 2]], sort(l))
- call assert_equal([[0, 1, 2], [0, 1, 2], 4, 2, 2, 1.5, 'xaaa', 'x8', 'foo6', 'foo', 'foo', 'A11', '-0'], reverse(sort(l)))
- call assert_equal(['-0', 'A11', 'foo', 'foo', 'foo6', 'x8', 'xaaa', 1.5, 2, 2, 4, [0, 1, 2], [0, 1, 2]], sort(reverse(sort(l))))
- call assert_equal(['-0', 'A11', 'foo', 'foo6', 'x8', 'xaaa', 1.5, 2, 4, [0, 1, 2]], uniq(sort(l)))
-
- let l=[7, 9, 'one', 18, 12, 22, 'two', 10.0e-16, -1, 'three', 0xff, 0.22, 'four']
- call assert_equal([-1, 'one', 'two', 'three', 'four', 1.0e-15, 0.22, 7, 9, 12, 18, 22, 255], sort(copy(l), 'n'))
-
- let l=[7, 9, 18, 12, 22, 10.0e-16, -1, 0xff, 0, -0, 0.22, 'bar', 'BAR', 'Bar', 'Foo', 'FOO', 'foo', 'FOOBAR', {}, []]
- call assert_equal(['bar', 'BAR', 'Bar', 'Foo', 'FOO', 'foo', 'FOOBAR', -1, 0, 0, 0.22, 1.0e-15, 12, 18, 22, 255, 7, 9, [], {}], sort(copy(l), 1))
- call assert_equal(['bar', 'BAR', 'Bar', 'Foo', 'FOO', 'foo', 'FOOBAR', -1, 0, 0, 0.22, 1.0e-15, 12, 18, 22, 255, 7, 9, [], {}], sort(copy(l), 'i'))
- call assert_equal(['BAR', 'Bar', 'FOO', 'FOOBAR', 'Foo', 'bar', 'foo', -1, 0, 0, 0.22, 1.0e-15, 12, 18, 22, 255, 7, 9, [], {}], sort(copy(l)))
+ if has('float')
+ call assert_equal(['-0', 'A11', 'foo', 'foo', 'foo6', 'x8', 'xaaa', 1.5, 2, 2, 4, [0, 1, 2], [0, 1, 2]], sort(l))
+ call assert_equal([[0, 1, 2], [0, 1, 2], 4, 2, 2, 1.5, 'xaaa', 'x8', 'foo6', 'foo', 'foo', 'A11', '-0'], reverse(sort(l)))
+ call assert_equal(['-0', 'A11', 'foo', 'foo', 'foo6', 'x8', 'xaaa', 1.5, 2, 2, 4, [0, 1, 2], [0, 1, 2]], sort(reverse(sort(l))))
+ call assert_equal(['-0', 'A11', 'foo', 'foo6', 'x8', 'xaaa', 1.5, 2, 4, [0, 1, 2]], uniq(sort(l)))
+
+ let l = [7, 9, 'one', 18, 12, 22, 'two', 10.0e-16, -1, 'three', 0xff, 0.22, 'four']
+ call assert_equal([-1, 'one', 'two', 'three', 'four', 1.0e-15, 0.22, 7, 9, 12, 18, 22, 255], sort(copy(l), 'n'))
+
+ let l = [7, 9, 18, 12, 22, 10.0e-16, -1, 0xff, 0, -0, 0.22, 'bar', 'BAR', 'Bar', 'Foo', 'FOO', 'foo', 'FOOBAR', {}, []]
+ call assert_equal(['bar', 'BAR', 'Bar', 'Foo', 'FOO', 'foo', 'FOOBAR', -1, 0, 0, 0.22, 1.0e-15, 12, 18, 22, 255, 7, 9, [], {}], sort(copy(l), 1))
+ call assert_equal(['bar', 'BAR', 'Bar', 'Foo', 'FOO', 'foo', 'FOOBAR', -1, 0, 0, 0.22, 1.0e-15, 12, 18, 22, 255, 7, 9, [], {}], sort(copy(l), 'i'))
+ call assert_equal(['BAR', 'Bar', 'FOO', 'FOOBAR', 'Foo', 'bar', 'foo', -1, 0, 0, 0.22, 1.0e-15, 12, 18, 22, 255, 7, 9, [], {}], sort(copy(l)))
+ endif
call assert_fails('call reverse("")', 'E899:')
+ call assert_fails('call uniq([1, 2], {x, y -> []})', 'E745:')
+ call assert_fails("call sort([1, 2], function('min'), 1)", "E715:")
+ call assert_fails("call sort([1, 2], function('invalid_func'))", "E700:")
+ call assert_fails("call sort([1, 2], function('min'))", "E118:")
endfunc
" reduce a list or a blob
@@ -665,7 +749,7 @@ func Test_reduce()
call assert_equal(42, reduce(v:_null_blob, function('add'), 42))
endfunc
-" splitting a string to a List
+" splitting a string to a List using split()
func Test_str_split()
call assert_equal(['aa', 'bb'], split(' aa bb '))
call assert_equal(['aa', 'bb'], split(' aa bb ', '\W\+', 0))
@@ -676,6 +760,9 @@ func Test_str_split()
call assert_equal(['aa', '', 'bb', 'cc', ''], split('aa,,bb, cc,', ',\s*', 1))
call assert_equal(['a', 'b', 'c'], split('abc', '\zs'))
call assert_equal(['', 'a', '', 'b', '', 'c', ''], split('abc', '\zs', 1))
+ call assert_fails("call split('abc', [])", 'E730:')
+ call assert_fails("call split('abc', 'b', [])", 'E745:')
+ call assert_equal(['abc'], split('abc', '\\%('))
endfunc
" compare recursively linked list and dict
@@ -687,6 +774,12 @@ func Test_listdict_compare()
call assert_true(d == d)
call assert_false(l != deepcopy(l))
call assert_false(d != deepcopy(d))
+
+ " comparison errors
+ call assert_fails('echo [1, 2] =~ {}', 'E691:')
+ call assert_fails('echo [1, 2] =~ [1, 2]', 'E692:')
+ call assert_fails('echo {} =~ 5', 'E735:')
+ call assert_fails('echo {} =~ {}', 'E736:')
endfunc
" compare complex recursively linked list and dict
@@ -860,6 +953,67 @@ func Test_scope_dict()
call s:check_scope_dict('v', v:true)
endfunc
+" Test for deep nesting of lists (> 100)
+func Test_deep_nested_list()
+ let deep_list = []
+ let l = deep_list
+ for i in range(102)
+ let newlist = []
+ call add(l, newlist)
+ let l = newlist
+ endfor
+ call add(l, 102)
+
+ call assert_fails('let m = deepcopy(deep_list)', 'E698:')
+ call assert_fails('lockvar 110 deep_list', 'E743:')
+ call assert_fails('unlockvar 110 deep_list', 'E743:')
+ " Nvim implements :echo very differently
+ " call assert_fails('let x = execute("echo deep_list")', 'E724:')
+ call test_garbagecollect_now()
+ unlet deep_list
+endfunc
+
+" Test for deep nesting of dicts (> 100)
+func Test_deep_nested_dict()
+ let deep_dict = {}
+ let d = deep_dict
+ for i in range(102)
+ let newdict = {}
+ let d.k = newdict
+ let d = newdict
+ endfor
+ let d.k = 'v'
+
+ call assert_fails('let m = deepcopy(deep_dict)', 'E698:')
+ call assert_fails('lockvar 110 deep_dict', 'E743:')
+ call assert_fails('unlockvar 110 deep_dict', 'E743:')
+ " Nvim implements :echo very differently
+ " call assert_fails('let x = execute("echo deep_dict")', 'E724:')
+ call test_garbagecollect_now()
+ unlet deep_dict
+endfunc
+
+" List and dict indexing tests
+func Test_listdict_index()
+ call assert_fails('echo function("min")[0]', 'E695:')
+ call assert_fails('echo v:true[0]', 'E909:')
+ let d = {'k' : 10}
+ call assert_fails('echo d.', 'E15:')
+ call assert_fails('echo d[1:2]', 'E719:')
+ call assert_fails("let v = [4, 6][{-> 1}]", 'E729:')
+ call assert_fails("let v = range(5)[2:[]]", 'E730:')
+ call assert_fails("let v = range(5)[2:{-> 2}(]", ['E15:', 'E116:'])
+ call assert_fails("let v = range(5)[2:3", 'E111:')
+ call assert_fails("let l = insert([1,2,3], 4, 10)", 'E684:')
+ call assert_fails("let l = insert([1,2,3], 4, -10)", 'E684:')
+ call assert_fails("let l = insert([1,2,3], 4, [])", 'E745:')
+ let l = [1, 2, 3]
+ call assert_fails("let l[i] = 3", 'E121:')
+ call assert_fails("let l[1.1] = 4", 'E806:')
+ call assert_fails("let l[:i] = [4, 5]", 'E121:')
+ call assert_fails("let l[:3.2] = [4, 5]", 'E806:')
+endfunc
+
" Test for a null list
func Test_null_list()
let l = v:_null_list
@@ -896,3 +1050,21 @@ func Test_null_list()
call assert_equal(1, islocked('l'))
unlockvar l
endfunc
+
+" Test for a null dict
+func Test_null_dict()
+ call assert_equal(v:_null_dict, v:_null_dict)
+ let d = v:_null_dict
+ call assert_equal({}, d)
+ call assert_equal(0, len(d))
+ call assert_equal(1, empty(d))
+ call assert_equal(0, items(d))
+ call assert_equal(0, keys(d))
+ call assert_equal(0, values(d))
+ call assert_false(has_key(d, 'k'))
+ call assert_equal('{}', string(d))
+ call assert_fails('let x = v:_null_dict[10]')
+ call assert_equal({}, {})
+endfunc
+
+" vim: shiftwidth=2 sts=2 expandtab
diff --git a/src/nvim/testdir/test_listlbr.vim b/src/nvim/testdir/test_listlbr.vim
index affa0f96fa..1cbdba5d76 100644
--- a/src/nvim/testdir/test_listlbr.vim
+++ b/src/nvim/testdir/test_listlbr.vim
@@ -7,6 +7,7 @@ CheckOption linebreak
CheckFeature conceal
source view_util.vim
+source screendump.vim
function s:screen_lines(lnum, width) abort
return ScreenLines(a:lnum, a:width)
@@ -133,6 +134,45 @@ func Test_linebreak_with_visual_operations()
call s:close_windows()
endfunc
+" Test that cursor is drawn at correct position after an operator when
+" 'linebreak' is enabled.
+func Test_linebreak_reset_restore()
+ CheckScreendump
+
+ " f_wincol() calls validate_cursor()
+ let lines =<< trim END
+ set linebreak showcmd noshowmode formatexpr=wincol()-wincol()
+ call setline(1, repeat('a', &columns - 10) .. ' bbbbbbbbbb c')
+ END
+ call writefile(lines, 'XlbrResetRestore', 'D')
+ let buf = RunVimInTerminal('-S XlbrResetRestore', {'rows': 8})
+
+ call term_sendkeys(buf, '$v$')
+ call WaitForAssert({-> assert_equal(13, term_getcursor(buf)[1])})
+ call term_sendkeys(buf, 'zo')
+ call WaitForAssert({-> assert_equal(12, term_getcursor(buf)[1])})
+
+ call term_sendkeys(buf, '$v$')
+ call WaitForAssert({-> assert_equal(13, term_getcursor(buf)[1])})
+ call term_sendkeys(buf, 'gq')
+ call WaitForAssert({-> assert_equal(12, term_getcursor(buf)[1])})
+
+ call term_sendkeys(buf, "$\<C-V>$")
+ call WaitForAssert({-> assert_equal(13, term_getcursor(buf)[1])})
+ call term_sendkeys(buf, 'I')
+ call WaitForAssert({-> assert_equal(12, term_getcursor(buf)[1])})
+
+ call term_sendkeys(buf, "\<Esc>$v$")
+ call WaitForAssert({-> assert_equal(13, term_getcursor(buf)[1])})
+ call term_sendkeys(buf, 's')
+ call WaitForAssert({-> assert_equal(12, term_getcursor(buf)[1])})
+ call VerifyScreenDump(buf, 'Test_linebreak_reset_restore_1', {})
+
+ " clean up
+ call term_sendkeys(buf, "\<Esc>")
+ call StopVimInTerminal(buf)
+endfunc
+
func Test_virtual_block()
call s:test_windows('setl sbr=+')
call setline(1, [
diff --git a/src/nvim/testdir/test_makeencoding.vim b/src/nvim/testdir/test_makeencoding.vim
index c53c07d991..e297bdc228 100644
--- a/src/nvim/testdir/test_makeencoding.vim
+++ b/src/nvim/testdir/test_makeencoding.vim
@@ -107,3 +107,19 @@ func Test_make()
lclose
endfor
endfunc
+
+" Test for an error file with a long line that needs an encoding conversion
+func Test_longline_conversion()
+ new
+ call setline(1, ['Xfile:10:' .. repeat("\xe0", 2000)])
+ write ++enc=latin1 Xerr.out
+ bw!
+ set errorformat&
+ set makeencoding=latin1
+ cfile Xerr.out
+ call assert_equal(repeat("\u00e0", 2000), getqflist()[0].text)
+ call delete('Xerr.out')
+ set makeencoding&
+endfunc
+
+" vim: shiftwidth=2 sts=2 expandtab
diff --git a/src/nvim/testdir/test_maparg.vim b/src/nvim/testdir/test_maparg.vim
index dad4c81a7b..f903f5b934 100644
--- a/src/nvim/testdir/test_maparg.vim
+++ b/src/nvim/testdir/test_maparg.vim
@@ -158,11 +158,11 @@ func Test_range_map()
call assert_equal("abcd", getline(1))
endfunc
-func One_mapset_test(keys)
- exe 'nnoremap ' .. a:keys .. ' original<CR>'
+func One_mapset_test(keys, rhs)
+ exe 'nnoremap ' .. a:keys .. ' ' .. a:rhs
let orig = maparg(a:keys, 'n', 0, 1)
call assert_equal(a:keys, orig.lhs)
- call assert_equal('original<CR>', orig.rhs)
+ call assert_equal(a:rhs, orig.rhs)
call assert_equal('n', orig.mode)
exe 'nunmap ' .. a:keys
@@ -172,15 +172,16 @@ func One_mapset_test(keys)
call mapset('n', 0, orig)
let d = maparg(a:keys, 'n', 0, 1)
call assert_equal(a:keys, d.lhs)
- call assert_equal('original<CR>', d.rhs)
+ call assert_equal(a:rhs, d.rhs)
call assert_equal('n', d.mode)
exe 'nunmap ' .. a:keys
endfunc
func Test_mapset()
- call One_mapset_test('K')
- call One_mapset_test('<F3>')
+ call One_mapset_test('K', 'original<CR>')
+ call One_mapset_test('<F3>', 'original<CR>')
+ call One_mapset_test('<F3>', '<lt>Nop>')
" Check <> key conversion
new
@@ -203,6 +204,26 @@ func Test_mapset()
iunmap K
+ " Test that <Nop> is restored properly
+ inoremap K <Nop>
+ call feedkeys("SK\<Esc>", 'xt')
+ call assert_equal('', getline(1))
+
+ let orig = maparg('K', 'i', 0, 1)
+ call assert_equal('K', orig.lhs)
+ call assert_equal('<Nop>', orig.rhs)
+ call assert_equal('i', orig.mode)
+
+ inoremap K foo
+ call feedkeys("SK\<Esc>", 'xt')
+ call assert_equal('foo', getline(1))
+
+ call mapset('i', 0, orig)
+ call feedkeys("SK\<Esc>", 'xt')
+ call assert_equal('', getline(1))
+
+ iunmap K
+
" Test literal <CR> using a backslash
let cpo_save = &cpo
set cpo-=B
@@ -248,6 +269,8 @@ func Test_mapset()
bwipe!
call assert_fails('call mapset([], v:false, {})', 'E730:')
+ call assert_fails('call mapset("i", 0, "")', 'E715:')
+ call assert_fails('call mapset("i", 0, {})', 'E460:')
endfunc
func Check_ctrlb_map(d, check_alt)
diff --git a/src/nvim/testdir/test_mapping.vim b/src/nvim/testdir/test_mapping.vim
index e1d0b9a9ba..5c5a65d4ca 100644
--- a/src/nvim/testdir/test_mapping.vim
+++ b/src/nvim/testdir/test_mapping.vim
@@ -395,7 +395,9 @@ func Test_motionforce_omap()
endfunc
func Test_error_in_map_expr()
- if !has('terminal') || (has('win32') && has('gui_running'))
+ " Unlike CheckRunVimInTerminal this does work in a win32 console
+ CheckFeature terminal
+ if has('win32') && has('gui_running')
throw 'Skipped: cannot run Vim in a terminal window'
endif
@@ -765,6 +767,11 @@ func Test_mapcomplete()
mapclear
endfunc
+func GetAbbrText()
+ unabbr hola
+ return 'hello'
+endfunc
+
" Test for <expr> in abbreviation
func Test_expr_abbr()
new
@@ -777,10 +784,17 @@ func Test_expr_abbr()
" invalid <expr> abbreviation
abbr <expr> hte GetAbbr()
call assert_fails('normal ihte ', 'E117:')
- call assert_equal(' ', getline(1))
+ call assert_equal('', getline(1))
unabbr <expr> hte
- close!
+ " evaluating the expression deletes the abbreviation
+ abbr <expr> hola GetAbbrText()
+ call assert_equal('GetAbbrText()', maparg('hola', 'i', '1'))
+ call feedkeys("ahola \<Esc>", 'xt')
+ call assert_equal('hello ', getline('.'))
+ call assert_equal('', maparg('hola', 'i', '1'))
+
+ bwipe!
endfunc
" Test for storing mappings in different modes in a vimrc file
@@ -975,6 +989,21 @@ func Test_abbreviate_multi_byte()
bwipe!
endfunc
+" Test for abbreviations with 'latin1' encoding
+func Test_abbreviate_latin1_encoding()
+ " set encoding=latin1
+ call assert_fails('abbr ab#$c ABC', 'E474:')
+ new
+ iabbr <buffer> #i #include
+ iabbr <buffer> ## #enddef
+ exe "normal i#i\<C-]>"
+ call assert_equal('#include', getline(1))
+ exe "normal 0Di##\<C-]>"
+ call assert_equal('#enddef', getline(1))
+ %bw!
+ set encoding=utf-8
+endfunc
++
" Test for <Plug> always being mapped, even when used with "noremap".
func Test_plug_remap()
let g:foo = 0
@@ -1006,15 +1035,14 @@ func Test_plug_remap()
endfunc
func Test_mouse_drag_mapped_start_select()
- CheckFunction test_setmouse
set mouse=a
set selectmode=key,mouse
func ClickExpr()
- call test_setmouse(1, 1)
+ call Ntest_setmouse(1, 1)
return "\<LeftMouse>"
endfunc
func DragExpr()
- call test_setmouse(1, 2)
+ call Ntest_setmouse(1, 2)
return "\<LeftDrag>"
endfunc
nnoremap <expr> <F2> ClickExpr()
@@ -1034,16 +1062,39 @@ func Test_mouse_drag_mapped_start_select()
set mouse&
endfunc
+func Test_mouse_drag_statusline()
+ set laststatus=2
+ set mouse=a
+ func ClickExpr()
+ call Ntest_setmouse(&lines - 1, 1)
+ return "\<LeftMouse>"
+ endfunc
+ func DragExpr()
+ call Ntest_setmouse(&lines - 2, 1)
+ return "\<LeftDrag>"
+ endfunc
+ nnoremap <expr> <F2> ClickExpr()
+ nnoremap <expr> <F3> DragExpr()
+
+ " this was causing a crash in win_drag_status_line()
+ call feedkeys("\<F2>:tabnew\<CR>\<F3>", 'tx')
+
+ nunmap <F2>
+ nunmap <F3>
+ delfunc ClickExpr
+ delfunc DragExpr
+ set laststatus& mouse&
+endfunc
+
" Test for mapping <LeftDrag> in Insert mode
func Test_mouse_drag_insert_map()
- CheckFunction test_setmouse
set mouse=a
func ClickExpr()
- call test_setmouse(1, 1)
+ call Ntest_setmouse(1, 1)
return "\<LeftMouse>"
endfunc
func DragExpr()
- call test_setmouse(1, 2)
+ call Ntest_setmouse(1, 2)
return "\<LeftDrag>"
endfunc
inoremap <expr> <F2> ClickExpr()
@@ -1129,4 +1180,14 @@ func Test_map_after_timed_out_nop()
call delete('Xtest_map_after_timed_out_nop')
endfunc
+func Test_using_past_typeahead()
+ nnoremap :00 0
+ exe "norm :set \x80\xfb0=0\<CR>"
+ exe "sil norm :0\x0f\<C-U>\<CR>"
+
+ exe "norm :set \x80\xfb0=\<CR>"
+ nunmap :00
+endfunc
+
+
" vim: shiftwidth=2 sts=2 expandtab
diff --git a/src/nvim/testdir/test_marks.vim b/src/nvim/testdir/test_marks.vim
index 74e63d9d69..a7ccca498c 100644
--- a/src/nvim/testdir/test_marks.vim
+++ b/src/nvim/testdir/test_marks.vim
@@ -91,6 +91,17 @@ func Test_setpos()
call assert_equal([0, 1, 21341234, 0], getpos("'a"))
call assert_equal(4, virtcol("'a"))
+ " Test with invalid buffer number, line number and column number
+ call cursor(2, 2)
+ call setpos('.', [-1, 1, 1, 0])
+ call assert_equal([2, 2], [line('.'), col('.')])
+ call setpos('.', [0, -1, 1, 0])
+ call assert_equal([2, 2], [line('.'), col('.')])
+ call setpos('.', [0, 1, -1, 0])
+ call assert_equal([2, 2], [line('.'), col('.')])
+
+ call assert_fails("call setpos('ab', [0, 1, 1, 0])", 'E474:')
+
bwipe!
call win_gotoid(twowin)
bwipe!
@@ -293,4 +304,17 @@ func Test_getmarklist()
close!
endfunc
+" This was using freed memory
+func Test_jump_mark_autocmd()
+ next 00
+ edit 0
+ sargument
+ au BufEnter 0 all
+ sil norm 
+
+ au! BufEnter
+ bwipe!
+endfunc
+
+
" vim: shiftwidth=2 sts=2 expandtab
diff --git a/src/nvim/testdir/test_match.vim b/src/nvim/testdir/test_match.vim
index 70271aa32f..600b6132a9 100644
--- a/src/nvim/testdir/test_match.vim
+++ b/src/nvim/testdir/test_match.vim
@@ -2,6 +2,7 @@
" matchaddpos(), matcharg(), matchdelete(), and setmatches().
source screendump.vim
+source check.vim
function Test_match()
highlight MyGroup1 term=bold ctermbg=red guibg=red
@@ -35,8 +36,8 @@ function Test_match()
let m1 = matchadd("MyGroup1", "TODO")
let m2 = matchadd("MyGroup2", "FIXME", 42)
let m3 = matchadd("MyGroup3", "XXX", 60, 17)
- let ans = [{'group': 'MyGroup1', 'pattern': 'TODO', 'priority': 10, 'id': 4},
- \ {'group': 'MyGroup2', 'pattern': 'FIXME', 'priority': 42, 'id': 5},
+ let ans = [{'group': 'MyGroup1', 'pattern': 'TODO', 'priority': 10, 'id': 1000},
+ \ {'group': 'MyGroup2', 'pattern': 'FIXME', 'priority': 42, 'id': 1001},
\ {'group': 'MyGroup3', 'pattern': 'XXX', 'priority': 60, 'id': 17}]
call assert_equal(ans, getmatches())
@@ -117,7 +118,7 @@ function Test_match()
call clearmatches()
call setline(1, 'abcdΣabcdef')
- eval "MyGroup1"->matchaddpos([[1, 4, 2], [1, 9, 2]])
+ eval "MyGroup1"->matchaddpos([[1, 4, 2], [1, 9, 2]], 10, 42)
1
redraw!
let v1 = screenattr(1, 1)
@@ -128,7 +129,7 @@ function Test_match()
let v8 = screenattr(1, 8)
let v9 = screenattr(1, 9)
let v10 = screenattr(1, 10)
- call assert_equal([{'group': 'MyGroup1', 'id': 11, 'priority': 10, 'pos1': [1, 4, 2], 'pos2': [1, 9, 2]}], getmatches())
+ call assert_equal([{'group': 'MyGroup1', 'id': 42, 'priority': 10, 'pos1': [1, 4, 2], 'pos2': [1, 9, 2]}], getmatches())
call assert_notequal(v1, v4)
call assert_equal(v5, v4)
call assert_equal(v6, v1)
@@ -142,7 +143,7 @@ function Test_match()
let m=getmatches()
call clearmatches()
call setmatches(m)
- call assert_equal([{'group': 'MyGroup1', 'id': 11, 'priority': 10, 'pos1': [1, 4, 2], 'pos2': [1,9, 2]}, {'group': 'MyGroup1', 'pattern': '\%2lmatchadd', 'priority': 10, 'id': 12}], getmatches())
+ call assert_equal([{'group': 'MyGroup1', 'id': 42, 'priority': 10, 'pos1': [1, 4, 2], 'pos2': [1,9, 2]}, {'group': 'MyGroup1', 'pattern': '\%2lmatchadd', 'priority': 10, 'id': 1106}], getmatches())
highlight MyGroup1 NONE
highlight MyGroup2 NONE
@@ -159,12 +160,14 @@ endfunc
func Test_matchadd_error()
call clearmatches()
" Nvim: not an error anymore:
+ " call assert_fails("call matchadd('GroupDoesNotExist', 'X')", 'E28:')
call matchadd('GroupDoesNotExist', 'X')
- call assert_equal([{'group': 'GroupDoesNotExist', 'pattern': 'X', 'priority': 10, 'id': 13}], getmatches())
- call assert_fails("call matchadd('Search', '\\(')", 'E475:')
+ call assert_equal([{'group': 'GroupDoesNotExist', 'pattern': 'X', 'priority': 10, 'id': 1206}], getmatches())
+ call assert_fails("call matchadd('Search', '\\(')", 'E54:')
call assert_fails("call matchadd('Search', 'XXX', 1, 123, 1)", 'E715:')
call assert_fails("call matchadd('Error', 'XXX', 1, 3)", 'E798:')
call assert_fails("call matchadd('Error', 'XXX', 1, 0)", 'E799:')
+ call assert_fails("call matchadd('Error', 'XXX', [], 0)", 'E745:')
endfunc
func Test_matchaddpos()
@@ -219,6 +222,21 @@ func Test_matchaddpos()
set hlsearch&
endfunc
+" Add 12 match positions (previously the limit was 8 positions).
+func Test_matchaddpos_dump()
+ CheckScreendump
+
+ let lines =<< trim END
+ call setline(1, ['1234567890123']->repeat(14))
+ call matchaddpos('Search', range(1, 12)->map({i, v -> [v, v]}))
+ END
+ call writefile(lines, 'Xmatchaddpos', 'D')
+ let buf = RunVimInTerminal('-S Xmatchaddpos', #{rows: 14})
+ call VerifyScreenDump(buf, 'Test_matchaddpos_1', {})
+
+ call StopVimInTerminal(buf)
+endfunc
+
func Test_matchaddpos_otherwin()
syntax on
new
@@ -237,8 +255,8 @@ func Test_matchaddpos_otherwin()
let savematches = getmatches(winid)
let expect = [
- \ {'group': 'Search', 'pattern': '4', 'priority': 10, 'id': 4},
- \ {'group': 'Error', 'id': 5, 'priority': 10, 'pos1': [1, 2, 1], 'pos2': [2, 2, 1]},
+ \ {'group': 'Search', 'pattern': '4', 'priority': 10, 'id': 1000},
+ \ {'group': 'Error', 'id': 1001, 'priority': 10, 'pos1': [1, 2, 1], 'pos2': [2, 2, 1]},
\]
call assert_equal(expect, savematches)
@@ -289,7 +307,10 @@ func Test_matchaddpos_error()
call assert_fails("call matchaddpos('Error', [1], 1, 123, 1)", 'E715:')
call assert_fails("call matchaddpos('Error', [1], 1, 5, {'window':12345})", 'E957:')
" Why doesn't the following error have an error code E...?
+ " call assert_fails("call matchaddpos('Error', [{}])", 'E290:')
call assert_fails("call matchaddpos('Error', [{}])", 'E5031:')
+ call assert_equal(-1, matchaddpos('Error', v:_null_list))
+ call assert_fails("call matchaddpos('Error', [1], [], 1)", 'E745:')
endfunc
func OtherWindowCommon()
@@ -306,9 +327,8 @@ func OtherWindowCommon()
endfunc
func Test_matchdelete_other_window()
- if !CanRunVimInTerminal()
- throw 'Skipped: cannot make screendumps'
- endif
+ CheckScreendump
+
let buf = OtherWindowCommon()
call term_sendkeys(buf, ":call matchdelete(mid, winid)\<CR>")
call VerifyScreenDump(buf, 'Test_matchdelete_1', {})
@@ -323,9 +343,7 @@ func Test_matchdelete_error()
endfunc
func Test_matchclear_other_window()
- if !CanRunVimInTerminal()
- throw 'Skipped: cannot make screendumps'
- endif
+ CheckRunVimInTerminal
let buf = OtherWindowCommon()
call term_sendkeys(buf, ":call clearmatches(winid)\<CR>")
call VerifyScreenDump(buf, 'Test_matchclear_1', {})
@@ -335,9 +353,7 @@ func Test_matchclear_other_window()
endfunc
func Test_matchadd_other_window()
- if !CanRunVimInTerminal()
- throw 'Skipped: cannot make screendumps'
- endif
+ CheckRunVimInTerminal
let buf = OtherWindowCommon()
call term_sendkeys(buf, ":call matchadd('Search', 'Hello', 1, -1, #{window: winid})\<CR>")
call term_sendkeys(buf, ":\<CR>")
@@ -347,5 +363,80 @@ func Test_matchadd_other_window()
call delete('XscriptMatchCommon')
endfunc
+func Test_match_in_linebreak()
+ CheckRunVimInTerminal
+
+ let lines =<< trim END
+ set breakindent linebreak breakat+=]
+ call printf('%s]%s', repeat('x', 50), repeat('x', 70))->setline(1)
+ call matchaddpos('ErrorMsg', [[1, 51]])
+ END
+ call writefile(lines, 'XscriptMatchLinebreak')
+ let buf = RunVimInTerminal('-S XscriptMatchLinebreak', #{rows: 10})
+ call TermWait(buf)
+ call VerifyScreenDump(buf, 'Test_match_linebreak', {})
+
+ call StopVimInTerminal(buf)
+ call delete('XscriptMatchLinebreak')
+endfunc
+
+func Test_match_with_incsearch()
+ CheckRunVimInTerminal
+
+ let lines =<< trim END
+ set incsearch
+ call setline(1, range(20))
+ call matchaddpos('ErrorMsg', [3])
+ END
+ call writefile(lines, 'XmatchWithIncsearch')
+ let buf = RunVimInTerminal('-S XmatchWithIncsearch', #{rows: 6})
+ call TermWait(buf)
+ call VerifyScreenDump(buf, 'Test_match_with_incsearch_1', {})
+
+ call term_sendkeys(buf, ":s/0")
+ call VerifyScreenDump(buf, 'Test_match_with_incsearch_2', {})
+
+ call term_sendkeys(buf, "\<CR>")
+ call StopVimInTerminal(buf)
+ call delete('XmatchWithIncsearch')
+endfunc
+
+" Test for deleting matches outside of the screen redraw top/bottom lines
+" This should cause a redraw of those lines.
+func Test_matchdelete_redraw()
+ new
+ call setline(1, range(1, 500))
+ call cursor(250, 1)
+ let m1 = matchaddpos('Search', [[250]])
+ let m2 = matchaddpos('Search', [[10], [450]])
+ redraw!
+ let m3 = matchaddpos('Search', [[240], [260]])
+ call matchdelete(m2)
+ let m = getmatches()
+ call assert_equal(2, len(m))
+ call assert_equal([250], m[0].pos1)
+ redraw!
+ call matchdelete(m1)
+ call assert_equal(1, len(getmatches()))
+ bw!
+endfunc
+
+func Test_match_tab_with_linebreak()
+ CheckRunVimInTerminal
+
+ let lines =<< trim END
+ set linebreak
+ call setline(1, "\tix")
+ call matchadd('ErrorMsg', '\t')
+ END
+ call writefile(lines, 'XscriptMatchTabLinebreak')
+ let buf = RunVimInTerminal('-S XscriptMatchTabLinebreak', #{rows: 10})
+ call TermWait(buf)
+ call VerifyScreenDump(buf, 'Test_match_tab_linebreak', {})
+
+ call StopVimInTerminal(buf)
+ call delete('XscriptMatchTabLinebreak')
+endfunc
+
" vim: shiftwidth=2 sts=2 expandtab
diff --git a/src/nvim/testdir/test_matchfuzzy.vim b/src/nvim/testdir/test_matchfuzzy.vim
index c836bc87aa..b46550fbc3 100644
--- a/src/nvim/testdir/test_matchfuzzy.vim
+++ b/src/nvim/testdir/test_matchfuzzy.vim
@@ -6,9 +6,7 @@ source check.vim
" Test for matchfuzzy()
func Test_matchfuzzy()
call assert_fails('call matchfuzzy(10, "abc")', 'E686:')
- " Needs v8.2.1183; match the final error that's thrown for now
- " call assert_fails('call matchfuzzy(["abc"], [])', 'E730:')
- call assert_fails('call matchfuzzy(["abc"], [])', 'E475:')
+ call assert_fails('call matchfuzzy(["abc"], [])', 'E730:')
call assert_fails("let x = matchfuzzy(v:_null_list, 'foo')", 'E686:')
call assert_fails('call matchfuzzy(["abc"], v:_null_string)', 'E475:')
call assert_equal([], matchfuzzy([], 'abc'))
@@ -75,12 +73,9 @@ func Test_matchfuzzy()
call assert_fails("let x = matchfuzzy(l, 'day', {'text_cb' : {a, b -> 1}})", 'E119:')
call assert_equal([], matchfuzzy(l, 'cam'))
" Nvim's callback implementation is different, so E6000 is expected instead,
- " but we need v8.2.1183 to assert it
" call assert_fails("let x = matchfuzzy(l, 'cam', {'text_cb' : []})", 'E921:')
- " call assert_fails("let x = matchfuzzy(l, 'cam', {'text_cb' : []})", 'E6000:')
- call assert_fails("let x = matchfuzzy(l, 'cam', {'text_cb' : []})", 'E475:')
- " call assert_fails("let x = matchfuzzy(l, 'foo', {'key' : []})", 'E730:')
- call assert_fails("let x = matchfuzzy(l, 'foo', {'key' : []})", 'E475:')
+ call assert_fails("let x = matchfuzzy(l, 'cam', {'text_cb' : []})", 'E6000:')
+ call assert_fails("let x = matchfuzzy(l, 'foo', {'key' : []})", 'E730:')
call assert_fails("let x = matchfuzzy(l, 'cam', v:_null_dict)", 'E715:')
call assert_fails("let x = matchfuzzy(l, 'foo', {'key' : v:_null_string})", 'E475:')
" Nvim doesn't have null functions
@@ -155,12 +150,9 @@ func Test_matchfuzzypos()
call assert_fails("let x = matchfuzzypos(l, 'day', {'text_cb' : {a, b -> 1}})", 'E119:')
call assert_equal([[], [], []], matchfuzzypos(l, 'cam'))
" Nvim's callback implementation is different, so E6000 is expected instead,
- " but we need v8.2.1183 to assert it
" call assert_fails("let x = matchfuzzypos(l, 'cam', {'text_cb' : []})", 'E921:')
- " call assert_fails("let x = matchfuzzypos(l, 'cam', {'text_cb' : []})", 'E6000:')
- call assert_fails("let x = matchfuzzypos(l, 'cam', {'text_cb' : []})", 'E475:')
- " call assert_fails("let x = matchfuzzypos(l, 'foo', {'key' : []})", 'E730:')
- call assert_fails("let x = matchfuzzypos(l, 'foo', {'key' : []})", 'E475:')
+ call assert_fails("let x = matchfuzzypos(l, 'cam', {'text_cb' : []})", 'E6000:')
+ call assert_fails("let x = matchfuzzypos(l, 'foo', {'key' : []})", 'E730:')
call assert_fails("let x = matchfuzzypos(l, 'cam', v:_null_dict)", 'E715:')
call assert_fails("let x = matchfuzzypos(l, 'foo', {'key' : v:_null_string})", 'E475:')
" Nvim doesn't have null functions
diff --git a/src/nvim/testdir/test_menu.vim b/src/nvim/testdir/test_menu.vim
index 75992d3313..a1121632e6 100644
--- a/src/nvim/testdir/test_menu.vim
+++ b/src/nvim/testdir/test_menu.vim
@@ -153,7 +153,7 @@ func Test_menu_errors()
call assert_fails('menu Test.Foo.Bar', 'E327:')
call assert_fails('cmenu Test.Foo', 'E328:')
call assert_fails('emenu x Test.Foo', 'E475:')
- call assert_fails('emenu Test.Foo.Bar', 'E334:')
+ call assert_fails('emenu Test.Foo.Bar', 'E327:')
call assert_fails('menutranslate Test', 'E474:')
silent! unmenu Foo
@@ -252,6 +252,7 @@ func Test_menu_info()
nmenu Test.abc <Nop>
call assert_equal('<Nop>', menu_info('Test.abc').rhs)
call assert_fails('call menu_info([])', 'E730:')
+ call assert_fails('call menu_info("", [])', 'E730:')
nunmenu Test
" Test for defining menus in different modes
@@ -429,7 +430,7 @@ func Test_menu_special()
nunmenu Test.Sign
endfunc
-" Test for "icon=filname" in a toolbar
+" Test for "icon=filename" in a toolbar
func Test_menu_icon()
CheckFeature toolbar
nmenu icon=myicon.xpm Toolbar.Foo :echo "Foo"<CR>
@@ -481,6 +482,35 @@ func Test_popup_menu()
unmenu PopUp
endfunc
+" Test for MenuPopup autocommand
+func Test_autocmd_MenuPopup()
+ CheckNotGui
+
+ set mouse=a
+ set mousemodel=popup
+ aunmenu *
+ autocmd MenuPopup * exe printf(
+ \ 'anoremenu PopUp.Foo <Cmd>let g:res = ["%s", "%s"]<CR>',
+ \ expand('<afile>'), expand('<amatch>'))
+
+ call feedkeys("\<RightMouse>\<Down>\<CR>", 'tnix')
+ call assert_equal(['n', 'n'], g:res)
+
+ call feedkeys("v\<RightMouse>\<Down>\<CR>\<Esc>", 'tnix')
+ call assert_equal(['v', 'v'], g:res)
+
+ call feedkeys("gh\<RightMouse>\<Down>\<CR>\<Esc>", 'tnix')
+ call assert_equal(['s', 's'], g:res)
+
+ call feedkeys("i\<RightMouse>\<Down>\<CR>\<Esc>", 'tnix')
+ call assert_equal(['i', 'i'], g:res)
+
+ autocmd! MenuPopup
+ aunmenu PopUp.Foo
+ unlet g:res
+ set mouse& mousemodel&
+endfunc
+
" Test for listing the menus using the :menu command
func Test_show_menus()
" In the GUI, tear-off menu items are present in the output below
diff --git a/src/nvim/testdir/test_messages.vim b/src/nvim/testdir/test_messages.vim
index 3a607ff533..bfdebdac79 100644
--- a/src/nvim/testdir/test_messages.vim
+++ b/src/nvim/testdir/test_messages.vim
@@ -171,6 +171,38 @@ func Test_echospace()
set ruler& showcmd&
endfunc
+func Test_warning_scroll()
+ CheckRunVimInTerminal
+ let lines =<< trim END
+ call test_override('ui_delay', 50)
+ set noruler
+ set readonly
+ undo
+ END
+ call writefile(lines, 'XTestWarningScroll', 'D')
+ let buf = RunVimInTerminal('', #{rows: 8})
+
+ " When the warning comes from a script, messages are scrolled so that the
+ " stacktrace is visible.
+ call term_sendkeys(buf, ":source XTestWarningScroll\n")
+ " only match the final colon in the line that shows the source
+ call WaitForAssert({-> assert_match(':$', term_getline(buf, 5))})
+ call WaitForAssert({-> assert_equal('line 4:W10: Warning: Changing a readonly file', term_getline(buf, 6))})
+ call WaitForAssert({-> assert_equal('Already at oldest change', term_getline(buf, 7))})
+ call WaitForAssert({-> assert_equal('Press ENTER or type command to continue', term_getline(buf, 8))})
+ call term_sendkeys(buf, "\n")
+
+ " When the warning does not come from a script, messages are not scrolled.
+ call term_sendkeys(buf, ":enew\n")
+ call term_sendkeys(buf, ":set readonly\n")
+ call term_sendkeys(buf, 'u')
+ call WaitForAssert({-> assert_equal('W10: Warning: Changing a readonly file', term_getline(buf, 8))})
+ call WaitForAssert({-> assert_equal('Already at oldest change', term_getline(buf, 8))})
+
+ " clean up
+ call StopVimInTerminal(buf)
+endfunc
+
" Test more-prompt (see :help more-prompt).
func Test_message_more()
CheckRunVimInTerminal
@@ -284,6 +316,66 @@ func Test_message_more()
call StopVimInTerminal(buf)
endfunc
+" Test more-prompt scrollback
+func Test_message_more_scrollback()
+ CheckRunVimInTerminal
+
+ let lines =<< trim END
+ set t_ut=
+ hi Normal ctermfg=15 ctermbg=0
+ for i in range(100)
+ echo i
+ endfor
+ END
+ call writefile(lines, 'XmoreScrollback', 'D')
+ let buf = RunVimInTerminal('-S XmoreScrollback', {'rows': 10})
+ call VerifyScreenDump(buf, 'Test_more_scrollback_1', {})
+
+ call term_sendkeys(buf, 'f')
+ call TermWait(buf)
+ call term_sendkeys(buf, 'b')
+ call VerifyScreenDump(buf, 'Test_more_scrollback_2', {})
+
+ call term_sendkeys(buf, 'q')
+ call TermWait(buf)
+ call StopVimInTerminal(buf)
+endfunc
+
+" Test verbose message before echo command
+func Test_echo_verbose_system()
+ CheckRunVimInTerminal
+ CheckUnix
+
+ let buf = RunVimInTerminal('', {'rows': 10})
+ call term_sendkeys(buf, ":4 verbose echo system('seq 20')\<CR>")
+ " Note that the screendump is filtered to remove the name of the temp file
+ call VerifyScreenDump(buf, 'Test_verbose_system_1', {})
+
+ " display a page and go back, results in exactly the same view
+ call term_sendkeys(buf, ' ')
+ call TermWait(buf, 50)
+ call term_sendkeys(buf, 'b')
+ call VerifyScreenDump(buf, 'Test_verbose_system_1', {})
+
+ " do the same with 'cmdheight' set to 2
+ call term_sendkeys(buf, 'q')
+ call TermWait(buf)
+ call term_sendkeys(buf, ":set ch=2\<CR>")
+ call TermWait(buf)
+ call term_sendkeys(buf, ":4 verbose echo system('seq 20')\<CR>")
+ call VerifyScreenDump(buf, 'Test_verbose_system_2', {})
+
+ call term_sendkeys(buf, ' ')
+ call TermWait(buf, 50)
+ call term_sendkeys(buf, 'b')
+ call VerifyScreenDump(buf, 'Test_verbose_system_2', {})
+
+ call term_sendkeys(buf, 'q')
+ call TermWait(buf)
+ call StopVimInTerminal(buf)
+endfunc
+
+
func Test_ask_yesno()
CheckRunVimInTerminal
let buf = RunVimInTerminal('', {'rows': 6})
@@ -325,14 +417,14 @@ func Test_quit_long_message()
let content =<< trim END
echom range(9999)->join("\x01")
END
- call writefile(content, 'Xtest_quit_message')
- let buf = RunVimInTerminal('-S Xtest_quit_message', #{rows: 6})
+ call writefile(content, 'Xtest_quit_message', 'D')
+ let buf = RunVimInTerminal('-S Xtest_quit_message', #{rows: 10, wait_for_ruler: 0})
+ call WaitForAssert({-> assert_match('^-- More --', term_getline(buf, 10))})
call term_sendkeys(buf, "q")
call VerifyScreenDump(buf, 'Test_quit_long_message', {})
" clean up
call StopVimInTerminal(buf)
- call delete('Xtest_quit_message')
endfunc
" this was missing a terminating NUL
@@ -398,7 +490,7 @@ func Test_cmdheight_zero()
" Check change/restore cmdheight when macro
call feedkeys("qa", "xt")
- call assert_equal(1, &cmdheight)
+ call assert_equal(0, &cmdheight)
call feedkeys("q", "xt")
call assert_equal(0, &cmdheight)
diff --git a/src/nvim/testdir/test_method.vim b/src/nvim/testdir/test_method.vim
index cdf688b857..ca3b736429 100644
--- a/src/nvim/testdir/test_method.vim
+++ b/src/nvim/testdir/test_method.vim
@@ -35,6 +35,7 @@ func Test_list_method()
call assert_equal(v:t_list, l->type())
call assert_equal([1, 2, 3], [1, 1, 2, 3, 3]->uniq())
call assert_fails('eval l->values()', 'E715:')
+ call assert_fails('echo []->len', 'E107:')
endfunc
func Test_dict_method()
@@ -130,9 +131,9 @@ func Test_method_syntax()
eval [1, 2, 3]
\ ->sort(
\ )
- call assert_fails('eval [1, 2, 3]-> sort()', 'E260:')
+ call assert_fails('eval [1, 2, 3]-> sort()', 'E15:')
call assert_fails('eval [1, 2, 3]->sort ()', 'E274:')
- call assert_fails('eval [1, 2, 3]-> sort ()', 'E260:')
+ call assert_fails('eval [1, 2, 3]-> sort ()', 'E15:')
endfunc
func Test_method_lambda()
@@ -152,6 +153,22 @@ endfunc
func Test_method_not_supported()
call assert_fails('eval 123->changenr()', 'E276:')
+ call assert_fails('echo "abc"->invalidfunc()', 'E117:')
+ " Test for too many or too few arguments to a method
+ call assert_fails('let n="abc"->len(2)', 'E118:')
+ call assert_fails('let n=10->setwinvar()', 'E119:')
endfunc
-" vim: shiftwidth=2 sts=2 expandtab
+" Test for passing optional arguments to methods
+func Test_method_args()
+ let v:errors = []
+ let n = 10->assert_inrange(1, 5, "Test_assert_inrange")
+ if v:errors[0] !~ 'Test_assert_inrange'
+ call assert_report(v:errors[0])
+ else
+ " Test passed
+ let v:errors = []
+ endif
+endfunc
+
+" vim: ts=8 sw=2 sts=2 expandtab tw=80 fdm=marker
diff --git a/src/nvim/testdir/test_mksession.vim b/src/nvim/testdir/test_mksession.vim
index 8ec408e62e..972397cb91 100644
--- a/src/nvim/testdir/test_mksession.vim
+++ b/src/nvim/testdir/test_mksession.vim
@@ -851,9 +851,7 @@ func Test_mksession_shortmess_with_A()
edit Xtestfile
write
let fname = swapname('%')
- " readblob() needs patch 8.2.2343
- " let cont = readblob(fname)
- let cont = readfile(fname, 'B')
+ let cont = readblob(fname)
set sessionoptions-=options
mksession Xtestsession
bwipe!
@@ -942,6 +940,19 @@ func Test_mkvimrc()
endfor
call s:ClearMappings()
+
+ " the 'pastetoggle', 'wildchar' and 'wildcharm' option values should be
+ " stored as key names in the vimrc file
+ set pastetoggle=<F5>
+ set wildchar=<F6>
+ set wildcharm=<F7>
+ call assert_fails('mkvimrc Xtestvimrc')
+ mkvimrc! Xtestvimrc
+ call assert_notequal(-1, index(readfile('Xtestvimrc'), 'set pastetoggle=<F5>'))
+ call assert_notequal(-1, index(readfile('Xtestvimrc'), 'set wildchar=<F6>'))
+ call assert_notequal(-1, index(readfile('Xtestvimrc'), 'set wildcharm=<F7>'))
+ set pastetoggle& wildchar& wildcharm&
+
call delete('Xtestvimrc')
endfunc
@@ -979,6 +990,38 @@ func Test_altfile()
call assert_equal('Xtwoalt', bufname('#'))
only
bwipe!
+ call delete('Xtest_altfile')
+endfunc
+
+" Test for creating views with manual folds
+func Test_mkview_manual_fold()
+ call writefile(range(1,10), 'Xfile')
+ new Xfile
+ " create recursive folds
+ 5,6fold
+ 4,7fold
+ mkview Xview
+ normal zE
+ source Xview
+ call assert_equal([-1, 4, 4, 4, 4, -1], [foldclosed(3), foldclosed(4),
+ \ foldclosed(5), foldclosed(6), foldclosed(7), foldclosed(8)])
+ " open one level of fold
+ 4foldopen
+ mkview! Xview
+ normal zE
+ source Xview
+ call assert_equal([-1, -1, 5, 5, -1, -1], [foldclosed(3), foldclosed(4),
+ \ foldclosed(5), foldclosed(6), foldclosed(7), foldclosed(8)])
+ " open all the folds
+ %foldopen!
+ mkview! Xview
+ normal zE
+ source Xview
+ call assert_equal([-1, -1, -1, -1, -1, -1], [foldclosed(3), foldclosed(4),
+ \ foldclosed(5), foldclosed(6), foldclosed(7), foldclosed(8)])
+ call delete('Xfile')
+ call delete('Xview')
+ bw!
endfunc
" vim: shiftwidth=2 sts=2 expandtab
diff --git a/src/nvim/testdir/test_modeline.vim b/src/nvim/testdir/test_modeline.vim
index b3fe79f545..613722fdbd 100644
--- a/src/nvim/testdir/test_modeline.vim
+++ b/src/nvim/testdir/test_modeline.vim
@@ -1,5 +1,7 @@
" Tests for parsing the modeline.
+source check.vim
+
func Test_modeline_invalid()
" This was reading allocated memory in the past.
call writefile(['vi:0', 'nothing'], 'Xmodeline')
@@ -281,6 +283,88 @@ func Test_modeline_fails_modelineexpr()
call s:modeline_fails('titlestring', 'titlestring=Something()', 'E992:')
endfunc
+func Test_modeline_setoption_verbose()
+ let modeline = &modeline
+ set modeline
+
+ let lines =<< trim END
+ 1 vim:ts=2
+ 2 two
+ 3 three
+ 4 four
+ 5 five
+ 6 six
+ 7 seven
+ 8 eight
+ END
+ call writefile(lines, 'Xmodeline')
+ edit Xmodeline
+ let info = split(execute('verbose set tabstop?'), "\n")
+ call assert_match('^\s*Last set from modeline line 1$', info[-1])
+ bwipe!
+
+ let lines =<< trim END
+ 1 one
+ 2 two
+ 3 three
+ 4 vim:ts=4
+ 5 five
+ 6 six
+ 7 seven
+ 8 eight
+ END
+ call writefile(lines, 'Xmodeline')
+ edit Xmodeline
+ let info = split(execute('verbose set tabstop?'), "\n")
+ call assert_match('^\s*Last set from modeline line 4$', info[-1])
+ bwipe!
+
+ let lines =<< trim END
+ 1 one
+ 2 two
+ 3 three
+ 4 four
+ 5 five
+ 6 six
+ 7 seven
+ 8 vim:ts=8
+ END
+ call writefile(lines, 'Xmodeline')
+ edit Xmodeline
+ let info = split(execute('verbose set tabstop?'), "\n")
+ call assert_match('^\s*Last set from modeline line 8$', info[-1])
+ bwipe!
+
+ let &modeline = modeline
+ call delete('Xmodeline')
+endfunc
+
+" Test for the 'modeline' default value in compatible and non-compatible modes
+" for root and non-root accounts
+func Test_modeline_default()
+ " set compatible
+ " call assert_false(&modeline)
+ set nocompatible
+ call assert_equal(IsRoot() ? 0 : 1, &modeline)
+ " set compatible&vi
+ " call assert_false(&modeline)
+ set compatible&vim
+ call assert_equal(IsRoot() ? 0 : 1, &modeline)
+ set compatible& modeline&
+endfunc
+
+" Some options cannot be set from the modeline when 'diff' option is set
+func Test_modeline_diff_buffer()
+ call writefile(['vim: diff foldmethod=marker wrap'], 'Xfile')
+ set foldmethod& nowrap
+ new Xfile
+ call assert_equal('manual', &foldmethod)
+ call assert_false(&wrap)
+ set wrap&
+ call delete('Xfile')
+ bw
+endfunc
+
func Test_modeline_disable()
set modeline
call writefile(['vim: sw=2', 'vim: nomodeline', 'vim: sw=3'], 'Xmodeline_disable')
diff --git a/src/nvim/testdir/test_normal.vim b/src/nvim/testdir/test_normal.vim
index 2092b508ea..7c90b444e5 100644
--- a/src/nvim/testdir/test_normal.vim
+++ b/src/nvim/testdir/test_normal.vim
@@ -3,6 +3,7 @@
source shared.vim
source check.vim
source view_util.vim
+source vim9.vim
source screendump.vim
func Setup_NewWindow()
@@ -35,14 +36,14 @@ func CountSpaces(type, ...)
else
silent exe "normal! `[v`]y"
endif
- let g:a=strlen(substitute(@@, '[^ ]', '', 'g'))
+ let g:a = strlen(substitute(@@, '[^ ]', '', 'g'))
let &selection = sel_save
let @@ = reg_save
endfunc
func OpfuncDummy(type, ...)
" for testing operatorfunc
- let g:opt=&linebreak
+ let g:opt = &linebreak
if a:0 " Invoked from Visual mode, use gv command.
silent exe "normal! gvy"
@@ -53,7 +54,7 @@ func OpfuncDummy(type, ...)
endif
" Create a new dummy window
new
- let g:bufnr=bufnr('%')
+ let g:bufnr = bufnr('%')
endfunc
func Test_normal00_optrans()
@@ -120,6 +121,39 @@ func Test_normal01_keymodel()
call feedkeys("Vkk\<Up>yy", 'tx')
call assert_equal(['47', '48', '49', '50'], getreg(0, 0, 1))
+ " Test for using special keys to start visual selection
+ %d
+ call setline(1, ['red fox tail', 'red fox tail', 'red fox tail'])
+ set keymodel=startsel
+ " Test for <S-PageUp> and <S-PageDown>
+ call cursor(1, 1)
+ call feedkeys("\<S-PageDown>y", 'xt')
+ call assert_equal([0, 1, 1, 0], getpos("'<"))
+ call assert_equal([0, 3, 1, 0], getpos("'>"))
+ call feedkeys("Gz\<CR>8|\<S-PageUp>y", 'xt')
+ call assert_equal([0, 2, 1, 0], getpos("'<"))
+ call assert_equal([0, 3, 8, 0], getpos("'>"))
+ " Test for <S-C-Home> and <S-C-End>
+ call cursor(2, 12)
+ call feedkeys("\<S-C-Home>y", 'xt')
+ call assert_equal([0, 1, 1, 0], getpos("'<"))
+ call assert_equal([0, 2, 12, 0], getpos("'>"))
+ call cursor(1, 4)
+ call feedkeys("\<S-C-End>y", 'xt')
+ call assert_equal([0, 1, 4, 0], getpos("'<"))
+ call assert_equal([0, 3, 13, 0], getpos("'>"))
+ " Test for <S-C-Left> and <S-C-Right>
+ call cursor(2, 5)
+ call feedkeys("\<S-C-Right>y", 'xt')
+ call assert_equal([0, 2, 5, 0], getpos("'<"))
+ call assert_equal([0, 2, 9, 0], getpos("'>"))
+ call cursor(2, 9)
+ call feedkeys("\<S-C-Left>y", 'xt')
+ call assert_equal([0, 2, 5, 0], getpos("'<"))
+ call assert_equal([0, 2, 9, 0], getpos("'>"))
+
+ set keymodel&
+
" clean up
bw!
endfunc
@@ -140,16 +174,15 @@ func Test_normal03_join()
$
:j 10
call assert_equal('100', getline('.'))
+ call assert_beeps('normal GVJ')
" clean up
bw!
endfunc
+" basic filter test
func Test_normal04_filter()
- " basic filter test
" only test on non windows platform
- if has('win32')
- return
- endif
+ CheckNotMSWindows
call Setup_NewWindow()
1
call feedkeys("!!sed -e 's/^/| /'\n", 'tx')
@@ -222,12 +255,49 @@ func Test_normal_formatexpr_returns_nonzero()
close!
endfunc
+" Test for using a script-local function for 'formatexpr'
+func Test_formatexpr_scriptlocal_func()
+ func! s:Format()
+ let g:FormatArgs = [v:lnum, v:count]
+ endfunc
+ set formatexpr=s:Format()
+ call assert_equal(expand('<SID>') .. 'Format()', &formatexpr)
+ new | only
+ call setline(1, range(1, 40))
+ let g:FormatArgs = []
+ normal! 2GVjgq
+ call assert_equal([2, 2], g:FormatArgs)
+ bw!
+ set formatexpr=<SID>Format()
+ call assert_equal(expand('<SID>') .. 'Format()', &formatexpr)
+ new | only
+ call setline(1, range(1, 40))
+ let g:FormatArgs = []
+ normal! 4GVjgq
+ call assert_equal([4, 2], g:FormatArgs)
+ bw!
+ let &formatexpr = 's:Format()'
+ new | only
+ call setline(1, range(1, 40))
+ let g:FormatArgs = []
+ normal! 6GVjgq
+ call assert_equal([6, 2], g:FormatArgs)
+ bw!
+ let &formatexpr = '<SID>Format()'
+ new | only
+ call setline(1, range(1, 40))
+ let g:FormatArgs = []
+ normal! 8GVjgq
+ call assert_equal([8, 2], g:FormatArgs)
+ setlocal formatexpr=
+ delfunc s:Format
+ bw!
+endfunc
+
+" basic test for formatprg
func Test_normal06_formatprg()
- " basic test for formatprg
" only test on non windows platform
- if has('win32')
- return
- endif
+ CheckNotMSWindows
" uses sed to number non-empty lines
call writefile(['#!/bin/sh', 'sed ''/./=''|sed ''/./{', 'N', 's/\n/ /', '}'''], 'Xsed_format.sh')
@@ -240,16 +310,24 @@ func Test_normal06_formatprg()
set formatprg=./Xsed_format.sh
norm! gggqG
call assert_equal(expected, getline(1, '$'))
- bw!
+ %d
- 10new
call setline(1, text)
set formatprg=donothing
setlocal formatprg=./Xsed_format.sh
norm! gggqG
call assert_equal(expected, getline(1, '$'))
- bw!
+ %d
+
+ " Check for the command-line ranges added to 'formatprg'
+ set formatprg=cat
+ call setline(1, ['one', 'two', 'three', 'four', 'five'])
+ call feedkeys('gggqG', 'xt')
+ call assert_equal('.,$!cat', @:)
+ call feedkeys('2Ggq2j', 'xt')
+ call assert_equal('.,.+2!cat', @:)
+ bw!
" clean up
set formatprg=
setlocal formatprg=
@@ -263,18 +341,16 @@ func Test_normal07_internalfmt()
10new
call setline(1, list)
set tw=12
- norm! gggqG
+ norm! ggVGgq
call assert_equal(['1 2 3', '4 5 6', '7 8 9', '10 11 '], getline(1, '$'))
" clean up
set tw=0
bw!
endfunc
+" basic tests for foldopen/folddelete
func Test_normal08_fold()
- " basic tests for foldopen/folddelete
- if !has("folding")
- return
- endif
+ CheckFeature folding
call Setup_NewWindow()
50
setl foldenable fdm=marker
@@ -352,70 +428,6 @@ func Test_normal09a_operatorfunc()
norm V10j,,
call assert_equal(22, g:a)
- " Use a lambda function for 'opfunc'
- unmap <buffer> ,,
- call cursor(1, 1)
- let g:a=0
- nmap <buffer><silent> ,, :set opfunc={type\ ->\ CountSpaces(type)}<CR>g@
- vmap <buffer><silent> ,, :<C-U>call CountSpaces(visualmode(), 1)<CR>
- 50
- norm V2j,,
- call assert_equal(6, g:a)
- norm V,,
- call assert_equal(2, g:a)
- norm ,,l
- call assert_equal(0, g:a)
- 50
- exe "norm 0\<c-v>10j2l,,"
- call assert_equal(11, g:a)
- 50
- norm V10j,,
- call assert_equal(22, g:a)
-
- " use a partial function for 'opfunc'
- let g:OpVal = 0
- func! Test_opfunc1(x, y, type)
- let g:OpVal = a:x + a:y
- endfunc
- set opfunc=function('Test_opfunc1',\ [5,\ 7])
- normal! g@l
- call assert_equal(12, g:OpVal)
- " delete the function and try to use g@
- delfunc Test_opfunc1
- call test_garbagecollect_now()
- call assert_fails('normal! g@l', 'E117:')
- set opfunc=
-
- " use a funcref for 'opfunc'
- let g:OpVal = 0
- func! Test_opfunc2(x, y, type)
- let g:OpVal = a:x + a:y
- endfunc
- set opfunc=funcref('Test_opfunc2',\ [4,\ 3])
- normal! g@l
- call assert_equal(7, g:OpVal)
- " delete the function and try to use g@
- delfunc Test_opfunc2
- call test_garbagecollect_now()
- call assert_fails('normal! g@l', 'E933:')
- set opfunc=
-
- " Try to use a function with two arguments for 'operatorfunc'
- let g:OpVal = 0
- func! Test_opfunc3(x, y)
- let g:OpVal = 4
- endfunc
- set opfunc=Test_opfunc3
- call assert_fails('normal! g@l', 'E119:')
- call assert_equal(0, g:OpVal)
- set opfunc=
- delfunc Test_opfunc3
- unlet g:OpVal
-
- " Try to use a lambda function with two arguments for 'operatorfunc'
- set opfunc={x,\ y\ ->\ 'done'}
- call assert_fails('normal! g@l', 'E119:')
-
" clean up
unmap <buffer> ,,
set opfunc=
@@ -484,6 +496,227 @@ func Test_normal09c_operatorfunc()
set operatorfunc=
endfunc
+" Test for different ways of setting the 'operatorfunc' option
+func Test_opfunc_callback()
+ new
+ func OpFunc1(callnr, type)
+ let g:OpFunc1Args = [a:callnr, a:type]
+ endfunc
+ func OpFunc2(type)
+ let g:OpFunc2Args = [a:type]
+ endfunc
+
+ let lines =<< trim END
+ #" Test for using a function name
+ LET &opfunc = 'g:OpFunc2'
+ LET g:OpFunc2Args = []
+ normal! g@l
+ call assert_equal(['char'], g:OpFunc2Args)
+
+ #" Test for using a function()
+ set opfunc=function('g:OpFunc1',\ [10])
+ LET g:OpFunc1Args = []
+ normal! g@l
+ call assert_equal([10, 'char'], g:OpFunc1Args)
+
+ #" Using a funcref variable to set 'operatorfunc'
+ VAR Fn = function('g:OpFunc1', [11])
+ LET &opfunc = Fn
+ LET g:OpFunc1Args = []
+ normal! g@l
+ call assert_equal([11, 'char'], g:OpFunc1Args)
+
+ #" Using a string(funcref_variable) to set 'operatorfunc'
+ LET Fn = function('g:OpFunc1', [12])
+ LET &operatorfunc = string(Fn)
+ LET g:OpFunc1Args = []
+ normal! g@l
+ call assert_equal([12, 'char'], g:OpFunc1Args)
+
+ #" Test for using a funcref()
+ set operatorfunc=funcref('g:OpFunc1',\ [13])
+ LET g:OpFunc1Args = []
+ normal! g@l
+ call assert_equal([13, 'char'], g:OpFunc1Args)
+
+ #" Using a funcref variable to set 'operatorfunc'
+ LET Fn = funcref('g:OpFunc1', [14])
+ LET &opfunc = Fn
+ LET g:OpFunc1Args = []
+ normal! g@l
+ call assert_equal([14, 'char'], g:OpFunc1Args)
+
+ #" Using a string(funcref_variable) to set 'operatorfunc'
+ LET Fn = funcref('g:OpFunc1', [15])
+ LET &opfunc = string(Fn)
+ LET g:OpFunc1Args = []
+ normal! g@l
+ call assert_equal([15, 'char'], g:OpFunc1Args)
+
+ #" Test for using a lambda function using set
+ VAR optval = "LSTART a LMIDDLE OpFunc1(16, a) LEND"
+ LET optval = substitute(optval, ' ', '\\ ', 'g')
+ exe "set opfunc=" .. optval
+ LET g:OpFunc1Args = []
+ normal! g@l
+ call assert_equal([16, 'char'], g:OpFunc1Args)
+
+ #" Test for using a lambda function using LET
+ LET &opfunc = LSTART a LMIDDLE OpFunc1(17, a) LEND
+ LET g:OpFunc1Args = []
+ normal! g@l
+ call assert_equal([17, 'char'], g:OpFunc1Args)
+
+ #" Set 'operatorfunc' to a string(lambda expression)
+ LET &opfunc = 'LSTART a LMIDDLE OpFunc1(18, a) LEND'
+ LET g:OpFunc1Args = []
+ normal! g@l
+ call assert_equal([18, 'char'], g:OpFunc1Args)
+
+ #" Set 'operatorfunc' to a variable with a lambda expression
+ VAR Lambda = LSTART a LMIDDLE OpFunc1(19, a) LEND
+ LET &opfunc = Lambda
+ LET g:OpFunc1Args = []
+ normal! g@l
+ call assert_equal([19, 'char'], g:OpFunc1Args)
+
+ #" Set 'operatorfunc' to a string(variable with a lambda expression)
+ LET Lambda = LSTART a LMIDDLE OpFunc1(20, a) LEND
+ LET &opfunc = string(Lambda)
+ LET g:OpFunc1Args = []
+ normal! g@l
+ call assert_equal([20, 'char'], g:OpFunc1Args)
+
+ #" Try to use 'operatorfunc' after the function is deleted
+ func g:TmpOpFunc1(type)
+ let g:TmpOpFunc1Args = [21, a:type]
+ endfunc
+ LET &opfunc = function('g:TmpOpFunc1')
+ delfunc g:TmpOpFunc1
+ call test_garbagecollect_now()
+ LET g:TmpOpFunc1Args = []
+ call assert_fails('normal! g@l', 'E117:')
+ call assert_equal([], g:TmpOpFunc1Args)
+
+ #" Try to use a function with two arguments for 'operatorfunc'
+ func g:TmpOpFunc2(x, y)
+ let g:TmpOpFunc2Args = [a:x, a:y]
+ endfunc
+ set opfunc=TmpOpFunc2
+ LET g:TmpOpFunc2Args = []
+ call assert_fails('normal! g@l', 'E119:')
+ call assert_equal([], g:TmpOpFunc2Args)
+ delfunc TmpOpFunc2
+
+ #" Try to use a lambda function with two arguments for 'operatorfunc'
+ LET &opfunc = LSTART a, b LMIDDLE OpFunc1(22, b) LEND
+ LET g:OpFunc1Args = []
+ call assert_fails('normal! g@l', 'E119:')
+ call assert_equal([], g:OpFunc1Args)
+
+ #" Test for clearing the 'operatorfunc' option
+ set opfunc=''
+ set opfunc&
+ call assert_fails("set opfunc=function('abc')", "E700:")
+ call assert_fails("set opfunc=funcref('abc')", "E700:")
+
+ #" set 'operatorfunc' to a non-existing function
+ LET &opfunc = function('g:OpFunc1', [23])
+ call assert_fails("set opfunc=function('NonExistingFunc')", 'E700:')
+ call assert_fails("LET &opfunc = function('NonExistingFunc')", 'E700:')
+ LET g:OpFunc1Args = []
+ normal! g@l
+ call assert_equal([23, 'char'], g:OpFunc1Args)
+ END
+ call CheckTransLegacySuccess(lines)
+
+ " Test for using a script-local function name
+ func s:OpFunc3(type)
+ let g:OpFunc3Args = [a:type]
+ endfunc
+ set opfunc=s:OpFunc3
+ let g:OpFunc3Args = []
+ normal! g@l
+ call assert_equal(['char'], g:OpFunc3Args)
+
+ let &opfunc = 's:OpFunc3'
+ let g:OpFunc3Args = []
+ normal! g@l
+ call assert_equal(['char'], g:OpFunc3Args)
+ delfunc s:OpFunc3
+
+ " Using Vim9 lambda expression in legacy context should fail
+ " set opfunc=(a)\ =>\ OpFunc1(24,\ a)
+ let g:OpFunc1Args = []
+ " call assert_fails('normal! g@l', 'E117:')
+ call assert_equal([], g:OpFunc1Args)
+
+ " set 'operatorfunc' to a partial with dict. This used to cause a crash.
+ func SetOpFunc()
+ let operator = {'execute': function('OperatorExecute')}
+ let &opfunc = operator.execute
+ endfunc
+ func OperatorExecute(_) dict
+ endfunc
+ call SetOpFunc()
+ call test_garbagecollect_now()
+ set operatorfunc=
+ delfunc SetOpFunc
+ delfunc OperatorExecute
+
+ " Vim9 tests
+ let lines =<< trim END
+ vim9script
+
+ def g:Vim9opFunc(val: number, type: string): void
+ g:OpFunc1Args = [val, type]
+ enddef
+
+ # Test for using a def function with opfunc
+ set opfunc=function('g:Vim9opFunc',\ [60])
+ g:OpFunc1Args = []
+ normal! g@l
+ assert_equal([60, 'char'], g:OpFunc1Args)
+
+ # Test for using a global function name
+ &opfunc = g:OpFunc2
+ g:OpFunc2Args = []
+ normal! g@l
+ assert_equal(['char'], g:OpFunc2Args)
+ bw!
+
+ # Test for using a script-local function name
+ def s:LocalOpFunc(type: string): void
+ g:LocalOpFuncArgs = [type]
+ enddef
+ &opfunc = s:LocalOpFunc
+ g:LocalOpFuncArgs = []
+ normal! g@l
+ assert_equal(['char'], g:LocalOpFuncArgs)
+ bw!
+ END
+ call CheckScriptSuccess(lines)
+
+ " setting 'opfunc' to a script local function outside of a script context
+ " should fail
+ let cleanup =<< trim END
+ call writefile([execute('messages')], 'Xtest.out')
+ qall
+ END
+ call writefile(cleanup, 'Xverify.vim')
+ call RunVim([], [], "-c \"set opfunc=s:abc\" -S Xverify.vim")
+ call assert_match('E81: Using <SID> not in a', readfile('Xtest.out')[0])
+ call delete('Xtest.out')
+ call delete('Xverify.vim')
+
+ " cleanup
+ set opfunc&
+ delfunc OpFunc1
+ delfunc OpFunc2
+ unlet g:OpFunc1Args g:OpFunc2Args
+ %bw!
+endfunc
+
func Test_normal10_expand()
" Test for expand()
10new
@@ -506,6 +739,14 @@ func Test_normal10_expand()
call assert_equal(expected[i], expand('<cexpr>'), 'i == ' . i)
endfor
+ " Test for <cexpr> in state.val and ptr->val
+ call setline(1, 'x = state.val;')
+ call cursor(1, 10)
+ call assert_equal('state.val', expand('<cexpr>'))
+ call setline(1, 'x = ptr->val;')
+ call cursor(1, 9)
+ call assert_equal('ptr->val', expand('<cexpr>'))
+
if executable('echo')
" Test expand(`...`) i.e. backticks command expansion.
" MS-Windows has a trailing space.
@@ -514,11 +755,25 @@ func Test_normal10_expand()
" Test expand(`=...`) i.e. backticks expression expansion
call assert_equal('5', expand('`=2+3`'))
+ call assert_equal('3.14', expand('`=3.14`'))
" clean up
bw!
endfunc
+" Test for expand() in latin1 encoding
+func Test_normal_expand_latin1()
+ new
+ let save_enc = &encoding
+ " set encoding=latin1
+ call setline(1, 'val = item->color;')
+ call cursor(1, 11)
+ call assert_equal('color', expand("<cword>"))
+ call assert_equal('item->color', expand("<cexpr>"))
+ let &encoding = save_enc
+ bw!
+endfunc
+
func Test_normal11_showcmd()
" test for 'showcmd'
10new
@@ -543,6 +798,13 @@ func Test_normal11_showcmd()
redraw!
call assert_match('1-3$', Screenline(&lines))
call feedkeys("v", 'xt')
+ " test for visually selecting the end of line
+ call setline(1, ["foobar"])
+ call feedkeys("$vl", 'xt')
+ redraw!
+ call assert_match('2$', Screenline(&lines))
+ call feedkeys("y", 'xt')
+ call assert_equal("r\n", @")
bw!
endfunc
@@ -1024,6 +1286,22 @@ func Test_vert_scroll_cmds()
close!
endfunc
+func Test_scroll_in_ex_mode()
+ " This was using invalid memory because w_botline was invalid.
+ let lines =<< trim END
+ diffsplit
+ norm os00(
+ call writefile(['done'], 'Xdone')
+ qa!
+ END
+ call writefile(lines, 'Xscript')
+ call assert_equal(1, RunVim([], [], '--clean -X -Z -e -s -S Xscript'))
+ call assert_equal(['done'], readfile('Xdone'))
+
+ call delete('Xscript')
+ call delete('Xdone')
+endfunc
+
" Test for the 'sidescroll' option
func Test_sidescroll_opt()
new
@@ -1431,10 +1709,8 @@ func Test_normal18_z_fold()
endfunc
func Test_normal20_exmode()
- if !has("unix")
- " Reading from redirected file doesn't work on MS-Windows
- return
- endif
+ " Reading from redirected file doesn't work on MS-Windows
+ CheckNotMSWindows
call writefile(['1a', 'foo', 'bar', '.', 'w! Xfile2', 'q!'], 'Xscript')
call writefile(['1', '2'], 'Xfile')
call system(GetVimCommand() .. ' -e -s < Xscript Xfile')
@@ -1455,6 +1731,7 @@ func Test_normal21_nv_hat()
edit Xfoo | %bw
call assert_fails(':buffer #', 'E86')
call assert_fails(':execute "normal! \<C-^>"', 'E23')
+ call assert_fails("normal i\<C-R>#", 'E23:')
" Test for the expected behavior when switching between two named buffers.
edit Xfoo | edit Xbar
@@ -1586,7 +1863,7 @@ func Test_normal23_K()
call setline(1, '---')
call assert_fails('normal! ggv2lK', 'E349:')
call setline(1, ['abc', 'xyz'])
- call assert_fails("normal! gg2lv2h\<C-]>", 'E426:')
+ call assert_fails("normal! gg2lv2h\<C-]>", 'E433:')
call assert_beeps("normal! ggVjK")
" clean up
@@ -2061,6 +2338,16 @@ func Test_normal30_changecase()
call assert_equal(['aaaaaa', 'AAAAaa'], getline(1, 2))
set whichwrap&
+ " try changing the case with a double byte encoding (DBCS)
+ %bw!
+ let enc = &enc
+ " set encoding=cp932
+ call setline(1, "\u8470")
+ normal ~
+ normal gU$gu$gUgUg~g~gugu
+ call assert_equal("\u8470", getline(1))
+ let &encoding = enc
+
" clean up
bw!
endfunc
@@ -2152,6 +2439,19 @@ func Test_normal31_r_cmd()
" r command should fail in operator pending mode
call assert_beeps('normal! cr')
+ " replace a tab character in visual mode
+ %d
+ call setline(1, ["a\tb", "c\td", "e\tf"])
+ normal gglvjjrx
+ call assert_equal(['axx', 'xxx', 'xxf'], getline(1, '$'))
+
+ " replace with a multibyte character (with multiple composing characters)
+ %d
+ new
+ call setline(1, 'aaa')
+ exe "normal $ra\u0328\u0301"
+ call assert_equal("aaa\u0328\u0301", getline(1))
+
" clean up
set noautoindent
bw!
@@ -2176,9 +2476,7 @@ endfunc
" Test for g`, g;, g,, g&, gv, gk, gj, gJ, g0, g^, g_, gm, g$, gM, g CTRL-G,
" gi and gI commands
func Test_normal33_g_cmd2()
- if !has("jumplist")
- return
- endif
+ CheckFeature jumplist
call Setup_NewWindow()
" Test for g`
clearjumps
@@ -2637,7 +2935,6 @@ endfunc
" Test for cw cW ce
func Test_normal39_cw()
" Test for cw and cW on whitespace
- " and cpo+=w setting
new
set tw=0
call append(0, 'here are some words')
@@ -2645,14 +2942,6 @@ func Test_normal39_cw()
call assert_equal('hereZZZare some words', getline('.'))
norm! 1gg0elcWYYY
call assert_equal('hereZZZareYYYsome words', getline('.'))
- " Nvim: no "w" flag in 'cpoptions'.
- " set cpo+=w
- " call setline(1, 'here are some words')
- " norm! 1gg0elcwZZZ
- " call assert_equal('hereZZZ are some words', getline('.'))
- " norm! 1gg2elcWYYY
- " call assert_equal('hereZZZ areYYY some words', getline('.'))
- set cpo-=w
norm! 2gg0cwfoo
call assert_equal('foo', getline('.'))
@@ -2812,24 +3101,6 @@ func Test_normal47_visual_buf_wipe()
set nomodified
endfunc
-func Test_normal47_autocmd()
- " disabled, does not seem to be possible currently
- throw "Skipped: not possible to test cursorhold autocmd while waiting for input in normal_cmd"
- new
- call append(0, repeat('-',20))
- au CursorHold * call feedkeys('2l', '')
- 1
- set updatetime=20
- " should delete 12 chars (d12l)
- call feedkeys('d1', '!')
- call assert_equal('--------', getline(1))
-
- " clean up
- au! CursorHold
- set updatetime=4000
- bw!
-endfunc
-
func Test_normal48_wincmd()
new
exe "norm! \<c-w>c"
@@ -2847,9 +3118,8 @@ func Test_normal49_counts()
endfunc
func Test_normal50_commandline()
- if !has("timers") || !has("cmdline_hist")
- return
- endif
+ CheckFeature timers
+ CheckFeature cmdline_hist
func! DoTimerWork(id)
call assert_equal('[Command Line]', bufname(''))
" should fail, with E11, but does fail with E23?
@@ -2878,9 +3148,7 @@ func Test_normal50_commandline()
endfunc
func Test_normal51_FileChangedRO()
- if !has("autocmd")
- return
- endif
+ CheckFeature autocmd
call writefile(['foo'], 'Xreadonly.log')
new Xreadonly.log
setl ro
@@ -2895,9 +3163,7 @@ func Test_normal51_FileChangedRO()
endfunc
func Test_normal52_rl()
- if !has("rightleft")
- return
- endif
+ CheckFeature rightleft
new
call setline(1, 'abcde fghij klmnopq')
norm! 1gg$
@@ -2929,22 +3195,6 @@ func Test_normal52_rl()
bw!
endfunc
-func Test_normal53_digraph()
- if !has('digraphs')
- return
- endif
- new
- call setline(1, 'abcdefgh|')
- exe "norm! 1gg0f\<c-k>!!"
- call assert_equal(9, col('.'))
- set cpo+=D
- exe "norm! 1gg0f\<c-k>!!"
- call assert_equal(1, col('.'))
-
- set cpo-=D
- bw!
-endfunc
-
func Test_normal54_Ctrl_bsl()
new
call setline(1, 'abcdefghijklmn')
@@ -3265,46 +3515,6 @@ func Test_normal_gk_gj()
set cpoptions& number& numberwidth& wrap&
endfunc
-" Test for cursor movement with '-' in 'cpoptions'
-func Test_normal_cpo_minus()
- throw 'Skipped: Nvim does not support cpoptions flag "-"'
- new
- call setline(1, ['foo', 'bar', 'baz'])
- let save_cpo = &cpo
- set cpo+=-
- call assert_beeps('normal 10j')
- call assert_equal(1, line('.'))
- normal G
- call assert_beeps('normal 10k')
- call assert_equal(3, line('.'))
- call assert_fails(10, 'E16:')
- let &cpo = save_cpo
- close!
-endfunc
-
-" Test for displaying dollar when changing text ('$' flag in 'cpoptions')
-func Test_normal_cpo_dollar()
- throw 'Skipped: use test/functional/legacy/cpoptions_spec.lua'
- new
- let g:Line = ''
- func SaveFirstLine()
- let g:Line = Screenline(1)
- return ''
- endfunc
- inoremap <expr> <buffer> <F2> SaveFirstLine()
- call test_override('redraw_flag', 1)
- set cpo+=$
- call setline(1, 'one two three')
- redraw!
- exe "normal c2w\<F2>vim"
- call assert_equal('one tw$ three', g:Line)
- call assert_equal('vim three', getline(1))
- set cpo-=$
- call test_override('ALL', 0)
- delfunc SaveFirstLine
- %bw!
-endfunc
-
" Test for using : to run a multi-line Ex command in operator pending mode
func Test_normal_yank_with_excmd()
new
@@ -3369,6 +3579,31 @@ func Test_normal_colon_op()
close!
endfunc
+" Test for d and D commands
+func Test_normal_delete_cmd()
+ new
+ " D in an empty line
+ call setline(1, '')
+ normal D
+ call assert_equal('', getline(1))
+ " D in an empty line in virtualedit mode
+ set virtualedit=all
+ normal D
+ call assert_equal('', getline(1))
+ set virtualedit&
+ " delete to a readonly register
+ call setline(1, ['abcd'])
+ call assert_beeps('normal ":d2l')
+
+ " D and d with 'nomodifiable'
+ call setline(1, ['abcd'])
+ setlocal nomodifiable
+ call assert_fails('normal D', 'E21:')
+ call assert_fails('normal d$', 'E21:')
+
+ close!
+endfunc
+
" Test for deleting or changing characters across lines with 'whichwrap'
" containing 's'. Should count <EOL> as one character.
func Test_normal_op_across_lines()
@@ -3476,6 +3711,27 @@ func Test_normal_percent_jump()
close!
endfunc
+" Test for << and >> commands to shift text by 'shiftwidth'
+func Test_normal_shift_rightleft()
+ new
+ call setline(1, ['one', '', "\t", ' two', "\tthree", ' four'])
+ set shiftwidth=2 tabstop=8
+ normal gg6>>
+ call assert_equal([' one', '', "\t ", ' two', "\t three", "\tfour"],
+ \ getline(1, '$'))
+ normal ggVG2>>
+ call assert_equal([' one', '', "\t ", "\ttwo",
+ \ "\t three", "\t four"], getline(1, '$'))
+ normal gg6<<
+ call assert_equal([' one', '', "\t ", ' two', "\t three",
+ \ "\t four"], getline(1, '$'))
+ normal ggVG2<<
+ call assert_equal(['one', '', "\t", ' two', "\tthree", ' four'],
+ \ getline(1, '$'))
+ set shiftwidth& tabstop&
+ bw!
+endfunc
+
" Some commands like yy, cc, dd, >>, << and !! accept a count after
" typing the first letter of the command.
func Test_normal_count_after_operator()
@@ -3539,4 +3795,37 @@ func Test_normal_count_out_of_range()
bwipe!
endfunc
+" Test that mouse shape is restored to Normal mode after failed "c" operation.
+func Test_mouse_shape_after_failed_change()
+ CheckFeature mouseshape
+ CheckCanRunGui
+
+ let lines =<< trim END
+ set mouseshape+=o:busy
+ setlocal nomodifiable
+ let g:mouse_shapes = []
+
+ func SaveMouseShape(timer)
+ let g:mouse_shapes += [getmouseshape()]
+ endfunc
+
+ func SaveAndQuit(timer)
+ call writefile(g:mouse_shapes, 'Xmouseshapes')
+ quit
+ endfunc
+
+ call timer_start(50, {_ -> feedkeys('c')})
+ call timer_start(100, 'SaveMouseShape')
+ call timer_start(150, {_ -> feedkeys('c')})
+ call timer_start(200, 'SaveMouseShape')
+ call timer_start(250, 'SaveAndQuit')
+ END
+ call writefile(lines, 'Xmouseshape.vim', 'D')
+ call RunVim([], [], "-g -S Xmouseshape.vim")
+ sleep 300m
+ call assert_equal(['busy', 'arrow'], readfile('Xmouseshapes'))
+
+ call delete('Xmouseshapes')
+endfunc
+
" vim: shiftwidth=2 sts=2 expandtab
diff --git a/src/nvim/testdir/test_options.vim b/src/nvim/testdir/test_options.vim
index fdfc1c0f89..f51de94bac 100644
--- a/src/nvim/testdir/test_options.vim
+++ b/src/nvim/testdir/test_options.vim
@@ -22,6 +22,21 @@ func Test_whichwrap()
set whichwrap=h,h,h
call assert_equal('h', &whichwrap)
+ " For compatibility with Vim 3.0 and before, number values are also
+ " supported for 'whichwrap'
+ set whichwrap=1
+ call assert_equal('b', &whichwrap)
+ set whichwrap=2
+ call assert_equal('s', &whichwrap)
+ set whichwrap=4
+ call assert_equal('h,l', &whichwrap)
+ set whichwrap=8
+ call assert_equal('<,>', &whichwrap)
+ set whichwrap=16
+ call assert_equal('[,]', &whichwrap)
+ set whichwrap=31
+ call assert_equal('b,s,h,l,<,>,[,]', &whichwrap)
+
set whichwrap&
endfunc
@@ -142,6 +157,20 @@ func Test_path_keep_commas()
set path&
endfunc
+func Test_path_too_long()
+ exe 'set path=' .. repeat('x', 10000)
+ call assert_fails('find x', 'E854:')
+ set path&
+endfunc
+
+func Test_signcolumn()
+ CheckFeature signs
+ call assert_equal("auto", &signcolumn)
+ set signcolumn=yes
+ set signcolumn=no
+ call assert_fails('set signcolumn=nope')
+endfunc
+
func Test_filetype_valid()
set ft=valid_name
call assert_equal("valid_name", &filetype)
@@ -234,6 +263,7 @@ func Test_complete()
new
call feedkeys("i\<C-N>\<Esc>", 'xt')
bwipe!
+ call assert_fails('set complete=ix', 'E535:')
set complete&
endfun
@@ -247,7 +277,7 @@ func Test_set_completion()
call feedkeys(":setglobal di\<C-A>\<C-B>\"\<CR>", 'tx')
call assert_equal('"setglobal dictionary diff diffexpr diffopt digraph directory display', @:)
- " Expand boolan options. When doing :set no<Tab>
+ " Expand boolean options. When doing :set no<Tab>
" vim displays the options names without "no" but completion uses "no...".
call feedkeys(":set nodi\<C-A>\<C-B>\"\<CR>", 'tx')
call assert_equal('"set nodiff digraph', @:)
@@ -266,6 +296,15 @@ func Test_set_completion()
call feedkeys(":set fileencodings:\<C-A>\<C-B>\"\<CR>", 'tx')
call assert_equal('"set fileencodings:ucs-bom,utf-8,default,latin1', @:)
+ " Expand key codes.
+ " call feedkeys(":set <H\<C-A>\<C-B>\"\<CR>", 'tx')
+ " call assert_equal('"set <Help> <Home>', @:)
+
+ " Expand terminal options.
+ " call feedkeys(":set t_A\<C-A>\<C-B>\"\<CR>", 'tx')
+ " call assert_equal('"set t_AB t_AF t_AU t_AL', @:)
+ " call assert_fails('call feedkeys(":set <t_afoo>=\<C-A>\<CR>", "xt")', 'E474:')
+
" Expand directories.
call feedkeys(":set cdpath=./\<C-A>\<C-B>\"\<CR>", 'tx')
call assert_match('./samples/ ', @:)
@@ -361,10 +400,20 @@ func Test_set_errors()
call assert_fails('set winminwidth=10 winwidth=9', 'E592:')
call assert_fails("set showbreak=\x01", 'E595:')
call assert_fails('set t_foo=', 'E846:')
+ call assert_fails('set tabstop??', 'E488:')
+ call assert_fails('set wrapscan!!', 'E488:')
+ call assert_fails('set tabstop&&', 'E488:')
+ call assert_fails('set wrapscan<<', 'E488:')
+ call assert_fails('set wrapscan=1', 'E474:')
+ call assert_fails('set autoindent@', 'E488:')
+ call assert_fails('set wildchar=<abc>', 'E474:')
+ call assert_fails('set cmdheight=1a', 'E521:')
+ call assert_fails('set invcmdheight', 'E474:')
if has('python') || has('python3')
call assert_fails('set pyxversion=6', 'E474:')
endif
call assert_fails("let &tabstop='ab'", 'E521:')
+ call assert_fails('set spellcapcheck=%\\(', 'E54:')
call assert_fails('set sessionoptions=curdir,sesdir', 'E474:')
call assert_fails('set foldmarker={{{,', 'E474:')
call assert_fails('set sessionoptions=sesdir,curdir', 'E474:')
@@ -384,6 +433,7 @@ func Test_set_errors()
set nomodifiable
call assert_fails('set fileencoding=latin1', 'E21:')
set modifiable&
+ " call assert_fails('set t_#-&', 'E522:')
endfunc
func CheckWasSet(name)
@@ -397,9 +447,8 @@ endfunc
" Must be executed before other tests that set 'term'.
func Test_000_term_option_verbose()
- if has('nvim') || has('gui_running')
- return
- endif
+ throw "Skipped: Nvim does not support setting 'term'"
+ CheckNotGui
call CheckWasNotSet('t_cm')
@@ -431,32 +480,37 @@ func Test_copy_context()
endfunc
func Test_set_ttytype()
- " Nvim does not support 'ttytype'.
- if !has('nvim') && !has('gui_running') && has('unix')
- " Setting 'ttytype' used to cause a double-free when exiting vim and
- " when vim is compiled with -DEXITFREE.
- set ttytype=ansi
- call assert_equal('ansi', &ttytype)
- call assert_equal(&ttytype, &term)
- set ttytype=xterm
- call assert_equal('xterm', &ttytype)
- call assert_equal(&ttytype, &term)
- try
- set ttytype=
- call assert_report('set ttytype= did not fail')
- catch /E529/
- endtry
-
- " Some systems accept any terminal name and return dumb settings,
- " check for failure of finding the entry and for missing 'cm' entry.
- try
- set ttytype=xxx
- call assert_report('set ttytype=xxx did not fail')
- catch /E522\|E437/
- endtry
-
- set ttytype&
- call assert_equal(&ttytype, &term)
+ throw "Skipped: Nvim does not support 'ttytype'"
+ CheckUnix
+ CheckNotGui
+
+ " Setting 'ttytype' used to cause a double-free when exiting vim and
+ " when vim is compiled with -DEXITFREE.
+ set ttytype=ansi
+ call assert_equal('ansi', &ttytype)
+ call assert_equal(&ttytype, &term)
+ set ttytype=xterm
+ call assert_equal('xterm', &ttytype)
+ call assert_equal(&ttytype, &term)
+ try
+ set ttytype=
+ call assert_report('set ttytype= did not fail')
+ catch /E529/
+ endtry
+
+ " Some systems accept any terminal name and return dumb settings,
+ " check for failure of finding the entry and for missing 'cm' entry.
+ try
+ set ttytype=xxx
+ call assert_report('set ttytype=xxx did not fail')
+ catch /E522\|E437/
+ endtry
+
+ set ttytype&
+ call assert_equal(&ttytype, &term)
+
+ if has('gui') && !has('gui_running')
+ call assert_fails('set term=gui', 'E531:')
endif
endfunc
@@ -774,7 +828,13 @@ func Test_shell()
CheckUnix
let save_shell = &shell
set shell=
- call assert_fails('shell', 'E91:')
+ let caught_e91 = 0
+ try
+ shell
+ catch /E91:/
+ let caught_e91 = 1
+ endtry
+ call assert_equal(1, caught_e91)
let &shell = save_shell
endfunc
@@ -833,6 +893,107 @@ func Test_debug_option()
set debug&
endfunc
+" Test for the default CDPATH option
+func Test_opt_default_cdpath()
+ let after =<< trim [CODE]
+ call assert_equal(',/path/to/dir1,/path/to/dir2', &cdpath)
+ call writefile(v:errors, 'Xtestout')
+ qall
+ [CODE]
+ if has('unix')
+ let $CDPATH='/path/to/dir1:/path/to/dir2'
+ else
+ let $CDPATH='/path/to/dir1;/path/to/dir2'
+ endif
+ if RunVim([], after, '')
+ call assert_equal([], readfile('Xtestout'))
+ call delete('Xtestout')
+ endif
+endfunc
+
+" Test for setting keycodes using set
+func Test_opt_set_keycode()
+ call assert_fails('set <t_k1=l', 'E474:')
+ call assert_fails('set <Home=l', 'E474:')
+ set <t_k9>=abcd
+ " call assert_equal('abcd', &t_k9)
+ set <t_k9>&
+ set <F9>=xyz
+ " call assert_equal('xyz', &t_k9)
+ set <t_k9>&
+endfunc
+
+" Test for changing options in a sandbox
+func Test_opt_sandbox()
+ for opt in ['backupdir', 'cdpath', 'exrc']
+ call assert_fails('sandbox set ' .. opt .. '?', 'E48:')
+ endfor
+endfunc
+
+" Test for setting an option with local value to global value
+func Test_opt_local_to_global()
+ setglobal equalprg=gprg
+ setlocal equalprg=lprg
+ call assert_equal('gprg', &g:equalprg)
+ call assert_equal('lprg', &l:equalprg)
+ call assert_equal('lprg', &equalprg)
+ set equalprg<
+ call assert_equal('', &l:equalprg)
+ call assert_equal('gprg', &equalprg)
+ setglobal equalprg=gnewprg
+ setlocal equalprg=lnewprg
+ setlocal equalprg<
+ call assert_equal('gnewprg', &l:equalprg)
+ call assert_equal('gnewprg', &equalprg)
+ set equalprg&
+
+ " Test for setting the global/local value of a boolean option
+ setglobal autoread
+ setlocal noautoread
+ call assert_false(&autoread)
+ set autoread<
+ call assert_true(&autoread)
+ setglobal noautoread
+ setlocal autoread
+ setlocal autoread<
+ call assert_false(&autoread)
+ set autoread&
+endfunc
+
+func Test_set_in_sandbox()
+ " Some boolean options cannot be set in sandbox, some can.
+ call assert_fails('sandbox set modelineexpr', 'E48:')
+ sandbox set number
+ call assert_true(&number)
+ set number&
+
+ " Some boolean options cannot be set in sandbox, some can.
+ if has('python') || has('python3')
+ call assert_fails('sandbox set pyxversion=3', 'E48:')
+ endif
+ sandbox set tabstop=4
+ call assert_equal(4, &tabstop)
+ set tabstop&
+
+ " Some string options cannot be set in sandbox, some can.
+ call assert_fails('sandbox set backupdir=/tmp', 'E48:')
+ sandbox set filetype=perl
+ call assert_equal('perl', &filetype)
+ set filetype&
+endfunc
+
+" Test for incrementing, decrementing and multiplying a number option value
+func Test_opt_num_op()
+ set shiftwidth=4
+ set sw+=2
+ call assert_equal(6, &sw)
+ set sw-=2
+ call assert_equal(4, &sw)
+ set sw^=2
+ call assert_equal(8, &sw)
+ set shiftwidth&
+endfunc
+
" Test for setting option values using v:false and v:true
func Test_opt_boolean()
set number&
@@ -969,6 +1130,93 @@ func Test_opt_reset_scroll()
call delete('Xscroll')
endfunc
+" Check that VIM_POSIX env variable influences default value of 'cpo' and 'shm'
+func Test_VIM_POSIX()
+ throw 'Skipped: Nvim does not support $VIM_POSIX'
+ let saved_VIM_POSIX = getenv("VIM_POSIX")
+
+ call setenv('VIM_POSIX', "1")
+ let after =<< trim [CODE]
+ call writefile([&cpo, &shm], 'X_VIM_POSIX')
+ qall
+ [CODE]
+ if RunVim([], after, '')
+ call assert_equal(['aAbBcCdDeEfFgHiIjJkKlLmMnoOpPqrRsStuvwWxXyZ$!%*-+<>#{|&/\.;',
+ \ 'AS'], readfile('X_VIM_POSIX'))
+ endif
+
+ call setenv('VIM_POSIX', v:null)
+ let after =<< trim [CODE]
+ call writefile([&cpo, &shm], 'X_VIM_POSIX')
+ qall
+ [CODE]
+ if RunVim([], after, '')
+ call assert_equal(['aAbBcCdDeEfFgHiIjJkKlLmMnoOpPqrRsStuvwWxXyZ$!%*-+<>;',
+ \ 'S'], readfile('X_VIM_POSIX'))
+ endif
+
+ call delete('X_VIM_POSIX')
+ call setenv('VIM_POSIX', saved_VIM_POSIX)
+endfunc
+
+" Test for setting an option to a Vi or Vim default
+func Test_opt_default()
+ throw 'Skipped: Nvim has different defaults'
+ set formatoptions&vi
+ call assert_equal('vt', &formatoptions)
+ set formatoptions&vim
+ call assert_equal('tcq', &formatoptions)
+endfunc
+
+" Test for the 'cmdheight' option
+func Test_cmdheight()
+ %bw!
+ let ht = &lines
+ set cmdheight=9999
+ call assert_equal(1, winheight(0))
+ call assert_equal(ht - 1, &cmdheight)
+ set cmdheight&
+endfunc
+
+" To specify a control character as a option value, '^' can be used
+func Test_opt_control_char()
+ set wildchar=^v
+ call assert_equal("\<C-V>", nr2char(&wildchar))
+ set wildcharm=^r
+ call assert_equal("\<C-R>", nr2char(&wildcharm))
+ " Bug: This doesn't work for the 'cedit' and 'termwinkey' options
+ set wildchar& wildcharm&
+endfunc
+
+" Test for the 'errorbells' option
+func Test_opt_errorbells()
+ set errorbells
+ call assert_beeps('s/a1b2/x1y2/')
+ set noerrorbells
+endfunc
+
+func Test_opt_scrolljump()
+ help
+ resize 10
+
+ " Test with positive 'scrolljump'.
+ set scrolljump=2
+ norm! Lj
+ call assert_equal({'lnum':11, 'leftcol':0, 'col':0, 'topfill':0,
+ \ 'topline':3, 'coladd':0, 'skipcol':0, 'curswant':0},
+ \ winsaveview())
+
+ " Test with negative 'scrolljump' (percentage of window height).
+ set scrolljump=-40
+ norm! ggLj
+ call assert_equal({'lnum':11, 'leftcol':0, 'col':0, 'topfill':0,
+ \ 'topline':5, 'coladd':0, 'skipcol':0, 'curswant':0},
+ \ winsaveview())
+
+ set scrolljump&
+ bw
+endfunc
+
" Test for the 'cdhome' option
func Test_opt_cdhome()
if has('unix') || has('vms')
@@ -990,6 +1238,30 @@ func Test_opt_cdhome()
set cdhome&
endfunc
+func Test_set_completion_2()
+ CheckOption termguicolors
+
+ " Test default option completion
+ set wildoptions=
+ call feedkeys(":set termg\<C-A>\<C-B>\"\<CR>", 'tx')
+ call assert_equal('"set termguicolors', @:)
+
+ call feedkeys(":set notermg\<C-A>\<C-B>\"\<CR>", 'tx')
+ call assert_equal('"set notermguicolors', @:)
+
+ " Test fuzzy option completion
+ set wildoptions=fuzzy
+ call feedkeys(":set termg\<C-A>\<C-B>\"\<CR>", 'tx')
+ " Nvim doesn't have 'termencoding'
+ " call assert_equal('"set termguicolors termencoding', @:)
+ call assert_equal('"set termguicolors', @:)
+
+ call feedkeys(":set notermg\<C-A>\<C-B>\"\<CR>", 'tx')
+ call assert_equal('"set notermguicolors', @:)
+
+ set wildoptions=
+endfunc
+
func Test_switchbuf_reset()
set switchbuf=useopen
sblast
@@ -1003,4 +1275,30 @@ func Test_switchbuf_reset()
only!
endfunc
+" :set empty string for global 'keywordprg' falls back to ":help"
+func Test_keywordprg_empty()
+ let k = &keywordprg
+ set keywordprg=man
+ call assert_equal('man', &keywordprg)
+ set keywordprg=
+ call assert_equal(':help', &keywordprg)
+ set keywordprg=man
+ call assert_equal('man', &keywordprg)
+ call assert_equal("\n keywordprg=:help", execute('set kp= kp?'))
+ let &keywordprg = k
+endfunc
+
+" check that the very first buffer created does not have 'endoffile' set
+func Test_endoffile_default()
+ let after =<< trim [CODE]
+ call writefile([execute('set eof?')], 'Xtestout')
+ qall!
+ [CODE]
+ if RunVim([], after, '')
+ call assert_equal(["\nnoendoffile"], readfile('Xtestout'))
+ endif
+ call delete('Xtestout')
+endfunc
+
+
" vim: shiftwidth=2 sts=2 expandtab
diff --git a/src/nvim/testdir/test_partial.vim b/src/nvim/testdir/test_partial.vim
index 8c90f21600..3020668f1b 100644
--- a/src/nvim/testdir/test_partial.vim
+++ b/src/nvim/testdir/test_partial.vim
@@ -82,6 +82,9 @@ func Test_partial_dict()
let dict = {"tr": function('tr', ['hello', 'h', 'H'])}
call assert_equal("Hello", dict.tr())
+
+ call assert_fails("let F=function('setloclist', 10)", "E923:")
+ call assert_fails("let F=function('setloclist', [], [])", "E922:")
endfunc
func Test_partial_implicit()
@@ -354,3 +357,5 @@ func Test_compare_partials()
call assert_true(F1 isnot# F1d1) " Partial /= non-partial
call assert_true(d1.f1 isnot# d1.f1) " handle_subscript creates new partial each time
endfunc
+
+" vim: shiftwidth=2 sts=2 expandtab
diff --git a/src/nvim/testdir/test_paste.vim b/src/nvim/testdir/test_paste.vim
new file mode 100644
index 0000000000..dad3c2c6a0
--- /dev/null
+++ b/src/nvim/testdir/test_paste.vim
@@ -0,0 +1,76 @@
+
+" Test for 'pastetoggle'
+func Test_pastetoggle()
+ new
+ set pastetoggle=<F4>
+ set nopaste
+ call feedkeys("iHello\<F4>", 'xt')
+ call assert_true(&paste)
+ call feedkeys("i\<F4>", 'xt')
+ call assert_false(&paste)
+ call assert_equal('Hello', getline(1))
+ " command-line completion for 'pastetoggle' value
+ call feedkeys(":set pastetoggle=\<Tab>\<C-B>\"\<CR>", 'xt')
+ call assert_equal('"set pastetoggle=<F4>', @:)
+ set pastetoggle&
+ bwipe!
+endfunc
+
+" Test for restoring option values when 'paste' is disabled
+func Test_paste_opt_restore()
+ set autoindent expandtab ruler showmatch
+ if has('rightleft')
+ set revins hkmap
+ endif
+ set smarttab softtabstop=3 textwidth=27 wrapmargin=12
+ if has('vartabs')
+ set varsofttabstop=10,20
+ endif
+
+ " enabling 'paste' should reset the above options
+ set paste
+ call assert_false(&autoindent)
+ call assert_false(&expandtab)
+ if has('rightleft')
+ call assert_false(&revins)
+ call assert_false(&hkmap)
+ endif
+ call assert_false(&ruler)
+ call assert_false(&showmatch)
+ call assert_false(&smarttab)
+ call assert_equal(0, &softtabstop)
+ call assert_equal(0, &textwidth)
+ call assert_equal(0, &wrapmargin)
+ if has('vartabs')
+ call assert_equal('', &varsofttabstop)
+ endif
+
+ " disabling 'paste' should restore the option values
+ set nopaste
+ call assert_true(&autoindent)
+ call assert_true(&expandtab)
+ if has('rightleft')
+ call assert_true(&revins)
+ call assert_true(&hkmap)
+ endif
+ call assert_true(&ruler)
+ call assert_true(&showmatch)
+ call assert_true(&smarttab)
+ call assert_equal(3, &softtabstop)
+ call assert_equal(27, &textwidth)
+ call assert_equal(12, &wrapmargin)
+ if has('vartabs')
+ call assert_equal('10,20', &varsofttabstop)
+ endif
+
+ set autoindent& expandtab& ruler& showmatch&
+ if has('rightleft')
+ set revins& hkmap&
+ endif
+ set smarttab& softtabstop& textwidth& wrapmargin&
+ if has('vartabs')
+ set varsofttabstop&
+ endif
+endfunc
+
+" vim: shiftwidth=2 sts=2 expandtab
diff --git a/src/nvim/testdir/test_popup.vim b/src/nvim/testdir/test_popup.vim
index 3d1e3fa6db..791cce4431 100644
--- a/src/nvim/testdir/test_popup.vim
+++ b/src/nvim/testdir/test_popup.vim
@@ -359,7 +359,7 @@ func Test_completefunc_opens_new_window_one()
/^one
call assert_fails('call feedkeys("A\<C-X>\<C-U>\<C-N>\<Esc>", "x")', 'E565:')
call assert_equal(winid, win_getid())
- call assert_equal('oneDEF', getline(1))
+ call assert_equal('onedef', getline(1))
q!
endfunc
@@ -384,9 +384,7 @@ func Test_completefunc_opens_new_window_two()
/^two
call assert_fails('call feedkeys("A\<C-X>\<C-U>\<C-N>\<Esc>", "x")', 'E565:')
call assert_equal(winid, win_getid())
- " v8.2.1919 hasn't been ported yet
- " call assert_equal('twodef', getline(1))
- call assert_equal('twoDEF', getline(1))
+ call assert_equal('twodef', getline(1))
q!
endfunc
@@ -677,9 +675,9 @@ func Test_complete_CTRLN_startofbuffer()
endfunc
func Test_popup_and_window_resize()
- if !has('terminal') || has('gui_running')
- return
- endif
+ CheckFeature terminal
+ CheckNotGui
+
let h = winheight(0)
if h < 15
return
@@ -864,7 +862,6 @@ func Test_popup_position()
endfunc
func Test_popup_command()
- CheckScreendump
CheckFeature menu
menu Test.Foo Foo
@@ -872,6 +869,23 @@ func Test_popup_command()
call assert_fails('popup Test.Foo.X', 'E327:')
call assert_fails('popup Foo', 'E337:')
unmenu Test.Foo
+endfunc
+
+func Test_popup_command_dump()
+ CheckFeature menu
+ CheckScreendump
+
+ let script =<< trim END
+ func StartTimer()
+ call timer_start(100, {-> ChangeMenu()})
+ endfunc
+ func ChangeMenu()
+ aunmenu PopUp.&Paste
+ nnoremenu 1.40 PopUp.&Paste :echomsg "pasted"<CR>
+ echomsg 'changed'
+ endfunc
+ END
+ call writefile(script, 'XtimerScript')
let lines =<< trim END
one two three four five
@@ -879,12 +893,12 @@ func Test_popup_command()
one more two three four five
END
call writefile(lines, 'Xtest')
- let buf = RunVimInTerminal('Xtest', {})
+ let buf = RunVimInTerminal('-S XtimerScript Xtest', {})
call term_sendkeys(buf, ":source $VIMRUNTIME/menu.vim\<CR>")
call term_sendkeys(buf, "/X\<CR>:popup PopUp\<CR>")
call VerifyScreenDump(buf, 'Test_popup_command_01', {})
- " Select a word
+ " go to the Paste entry in the menu
call term_sendkeys(buf, "jj")
call VerifyScreenDump(buf, 'Test_popup_command_02', {})
@@ -893,8 +907,20 @@ func Test_popup_command()
call VerifyScreenDump(buf, 'Test_popup_command_03', {})
call term_sendkeys(buf, "\<Esc>")
+
+ " Set a timer to change a menu entry while it's displayed. The text should
+ " not change but the command does. Making the screendump also verifies that
+ " "changed" shows up, which means the timer triggered
+ call term_sendkeys(buf, "/X\<CR>:call StartTimer() | popup PopUp\<CR>")
+ call VerifyScreenDump(buf, 'Test_popup_command_04', {})
+
+ " Select the Paste entry, executes the changed menu item.
+ call term_sendkeys(buf, "jj\<CR>")
+ call VerifyScreenDump(buf, 'Test_popup_command_05', {})
+
call StopVimInTerminal(buf)
call delete('Xtest')
+ call delete('XtimerScript')
endfunc
func Test_popup_complete_backwards()
@@ -948,9 +974,9 @@ func Test_complete_o_tab()
endfunc
func Test_menu_only_exists_in_terminal()
- if !exists(':tlmenu') || has('gui_running')
- return
- endif
+ CheckCommand tlmenu
+ CheckNotGui
+
tlnoremenu &Edit.&Paste<Tab>"+gP <C-W>"+
aunmenu *
try
@@ -1129,15 +1155,15 @@ func Test_CompleteChanged()
autocmd! AAAAA_Group
set complete& completeopt&
- delfunc! OnPumchange
+ delfunc! OnPumChange
bw!
endfunc
-function! GetPumPosition()
+func GetPumPosition()
call assert_true( pumvisible() )
let g:pum_pos = pum_getpos()
return ''
-endfunction
+endfunc
func Test_pum_getpos()
new
diff --git a/src/nvim/testdir/test_preview.vim b/src/nvim/testdir/test_preview.vim
index 6c4ae414d3..b7b908e761 100644
--- a/src/nvim/testdir/test_preview.vim
+++ b/src/nvim/testdir/test_preview.vim
@@ -1,5 +1,8 @@
" Tests for the preview window
+source check.vim
+CheckFeature quickfix
+
func Test_Psearch()
" this used to cause ml_get errors
help
@@ -13,6 +16,8 @@ func Test_Psearch()
endfunc
func Test_window_preview()
+ CheckFeature quickfix
+
" Open a preview window
pedit Xa
call assert_equal(2, winnr('$'))
@@ -32,6 +37,8 @@ func Test_window_preview()
endfunc
func Test_window_preview_from_help()
+ CheckFeature quickfix
+
filetype on
call writefile(['/* some C code */'], 'Xpreview.c')
help
diff --git a/src/nvim/testdir/test_profile.vim b/src/nvim/testdir/test_profile.vim
index fdb6f13e2b..9165f7bace 100644
--- a/src/nvim/testdir/test_profile.vim
+++ b/src/nvim/testdir/test_profile.vim
@@ -40,8 +40,8 @@ func Test_profile_func()
call writefile(lines, 'Xprofile_func.vim')
call system(GetVimCommand()
\ . ' -es --clean'
- \ . ' -c "so Xprofile_func.vim"'
- \ . ' -c "qall!"')
+ \ . ' --cmd "so Xprofile_func.vim"'
+ \ . ' --cmd "qall!"')
call assert_equal(0, v:shell_error)
let lines = readfile('Xprofile_func.log')
@@ -403,6 +403,47 @@ func Test_profile_completion()
call feedkeys(":profile start test_prof\<C-A>\<C-B>\"\<CR>", 'tx')
call assert_match('^"profile start.* test_profile\.vim', @:)
+
+ call feedkeys(":profile file test_prof\<Tab>\<C-B>\"\<CR>", 'tx')
+ call assert_match('"profile file test_profile\.vim', @:)
+ call feedkeys(":profile file test_prof\<Tab>\<C-B>\"\<CR>", 'tx')
+ call assert_match('"profile file test_profile\.vim', @:)
+ call feedkeys(":profile file test_prof \<Tab>\<C-B>\"\<CR>", 'tx')
+ call assert_match('"profile file test_prof ', @:)
+ call feedkeys(":profile file X1B2C3\<Tab>\<C-B>\"\<CR>", 'tx')
+ call assert_match('"profile file X1B2C3', @:)
+
+ func Xprof_test()
+ endfunc
+ call feedkeys(":profile func Xprof\<Tab>\<C-B>\"\<CR>", 'tx')
+ call assert_equal('"profile func Xprof_test', @:)
+ call feedkeys(":profile func Xprof\<Tab>\<C-B>\"\<CR>", 'tx')
+ call assert_equal('"profile func Xprof_test', @:)
+ call feedkeys(":profile func Xprof \<Tab>\<C-B>\"\<CR>", 'tx')
+ call assert_equal('"profile func Xprof ', @:)
+ call feedkeys(":profile func X1B2C3\<Tab>\<C-B>\"\<CR>", 'tx')
+ call assert_equal('"profile func X1B2C3', @:)
+
+ call feedkeys(":profdel \<C-A>\<C-B>\"\<CR>", 'tx')
+ call assert_equal('"profdel file func', @:)
+ call feedkeys(":profdel fu\<Tab>\<C-B>\"\<CR>", 'tx')
+ call assert_equal('"profdel func', @:)
+ call feedkeys(":profdel he\<Tab>\<C-B>\"\<CR>", 'tx')
+ call assert_equal('"profdel he', @:)
+ call feedkeys(":profdel here \<Tab>\<C-B>\"\<CR>", 'tx')
+ call assert_equal('"profdel here ', @:)
+ call feedkeys(":profdel file test_prof\<Tab>\<C-B>\"\<CR>", 'tx')
+ call assert_equal('"profdel file test_profile.vim', @:)
+ call feedkeys(":profdel file X1B2C3\<Tab>\<C-B>\"\<CR>", 'tx')
+ call assert_equal('"profdel file X1B2C3', @:)
+ call feedkeys(":profdel func Xprof\<Tab>\<C-B>\"\<CR>", 'tx')
+ call assert_equal('"profdel func Xprof_test', @:)
+ call feedkeys(":profdel func Xprof_test \<Tab>\<C-B>\"\<CR>", 'tx')
+ call assert_equal('"profdel func Xprof_test ', @:)
+ call feedkeys(":profdel func X1B2C3\<Tab>\<C-B>\"\<CR>", 'tx')
+ call assert_equal('"profdel func X1B2C3', @:)
+
+ delfunc Xprof_test
endfunc
func Test_profile_errors()
@@ -475,7 +516,7 @@ func Test_profdel_func()
call Foo3()
[CODE]
call writefile(lines, 'Xprofile_file.vim')
- call system(GetVimCommandClean() . ' -es -c "so Xprofile_file.vim" -c q')
+ call system(GetVimCommandClean() . ' -es --cmd "so Xprofile_file.vim" --cmd q')
call assert_equal(0, v:shell_error)
let lines = readfile('Xprofile_file.log')
diff --git a/src/nvim/testdir/test_prompt_buffer.vim b/src/nvim/testdir/test_prompt_buffer.vim
index 8f94a8572b..b8f6c5240c 100644
--- a/src/nvim/testdir/test_prompt_buffer.vim
+++ b/src/nvim/testdir/test_prompt_buffer.vim
@@ -180,6 +180,8 @@ func Test_prompt_buffer_edit()
call assert_beeps('normal! S')
call assert_beeps("normal! \<C-A>")
call assert_beeps("normal! \<C-X>")
+ call assert_beeps("normal! dp")
+ call assert_beeps("normal! do")
" pressing CTRL-W in the prompt buffer should trigger the window commands
call assert_equal(1, winnr())
exe "normal A\<C-W>\<C-W>"
@@ -223,7 +225,7 @@ func Test_prompt_buffer_getbufinfo()
%bwipe!
endfunc
-function! Test_prompt_while_writing_to_hidden_buffer()
+func Test_prompt_while_writing_to_hidden_buffer()
throw 'skipped: TODO'
call CanTestPromptBuffer()
CheckUnix
diff --git a/src/nvim/testdir/test_quickfix.vim b/src/nvim/testdir/test_quickfix.vim
index f6d573d76b..8dc4173d60 100644
--- a/src/nvim/testdir/test_quickfix.vim
+++ b/src/nvim/testdir/test_quickfix.vim
@@ -1,6 +1,7 @@
" Test for the quickfix feature.
source check.vim
+source vim9.vim
CheckFeature quickfix
source screendump.vim
@@ -85,6 +86,12 @@ func s:setup_commands(cchar)
endif
endfunc
+" This must be run before any error lists are created.
+func Test_AA_cc_no_errors()
+ call assert_fails('cc', 'E42:')
+ call assert_fails('ll', 'E42:')
+endfunc
+
" Tests for the :clist and :llist commands
func XlistTests(cchar)
call s:setup_commands(a:cchar)
@@ -98,9 +105,15 @@ func XlistTests(cchar)
call assert_true(v:errmsg ==# 'E42: No Errors')
" Populate the list and then try
- Xgetexpr ['non-error 1', 'Xtestfile1:1:3:Line1',
- \ 'non-error 2', 'Xtestfile2:2:2:Line2',
- \ 'non-error| 3', 'Xtestfile3:3:1:Line3']
+ let lines =<< trim END
+ non-error 1
+ Xtestfile1:1:3:Line1
+ non-error 2
+ Xtestfile2:2:2:Line2
+ non-error| 3
+ Xtestfile3:3:1:Line3
+ END
+ Xgetexpr lines
" List only valid entries
let l = split(execute('Xlist', ''), "\n")
@@ -255,6 +268,7 @@ func XwindowTests(cchar)
" Opening the location list window without any errors should fail
if a:cchar == 'l'
call assert_fails('lopen', 'E776:')
+ call assert_fails('lwindow', 'E776:')
endif
" Create a list with no valid entries
@@ -265,8 +279,12 @@ func XwindowTests(cchar)
call assert_true(winnr('$') == 1)
" Create a list with valid entries
- Xgetexpr ['Xtestfile1:1:3:Line1', 'Xtestfile2:2:2:Line2',
- \ 'Xtestfile3:3:1:Line3']
+ let lines =<< trim END
+ Xtestfile1:1:3:Line1
+ Xtestfile2:2:2:Line2
+ Xtestfile3:3:1:Line3
+ END
+ Xgetexpr lines
" Open the window
Xwindow
@@ -329,8 +347,12 @@ func XwindowTests(cchar)
if a:cchar == 'c'
" Opening the quickfix window in multiple tab pages should reuse the
" quickfix buffer
- Xgetexpr ['Xtestfile1:1:3:Line1', 'Xtestfile2:2:2:Line2',
- \ 'Xtestfile3:3:1:Line3']
+ let lines =<< trim END
+ Xtestfile1:1:3:Line1
+ Xtestfile2:2:2:Line2
+ Xtestfile3:3:1:Line3
+ END
+ Xgetexpr lines
Xopen
let qfbufnum = bufnr('%')
tabnew
@@ -365,14 +387,16 @@ func Test_copenHeight_tabline()
set tabline& showtabline&
endfunc
-
" Tests for the :cfile, :lfile, :caddfile, :laddfile, :cgetfile and :lgetfile
" commands.
func XfileTests(cchar)
call s:setup_commands(a:cchar)
- call writefile(['Xtestfile1:700:10:Line 700',
- \ 'Xtestfile2:800:15:Line 800'], 'Xqftestfile1')
+ let lines =<< trim END
+ Xtestfile1:700:10:Line 700
+ Xtestfile2:800:15:Line 800
+ END
+ call writefile(lines, 'Xqftestfile1')
enew!
Xfile Xqftestfile1
@@ -396,8 +420,11 @@ func XfileTests(cchar)
call assert_true(len(l) == 3 &&
\ l[2].lnum == 900 && l[2].col == 30 && l[2].text ==# 'Line 900')
- call writefile(['Xtestfile1:222:77:Line 222',
- \ 'Xtestfile2:333:88:Line 333'], 'Xqftestfile1')
+ let lines =<< trim END
+ Xtestfile1:222:77:Line 222
+ Xtestfile2:333:88:Line 333
+ END
+ call writefile(lines, 'Xqftestfile1')
enew!
Xgetfile Xqftestfile1
@@ -427,8 +454,11 @@ func XbufferTests(cchar)
call s:setup_commands(a:cchar)
enew!
- silent! call setline(1, ['Xtestfile7:700:10:Line 700',
- \ 'Xtestfile8:800:15:Line 800'])
+ let lines =<< trim END
+ Xtestfile7:700:10:Line 700
+ Xtestfile8:800:15:Line 800
+ END
+ silent! call setline(1, lines)
Xbuffer!
let l = g:Xgetlist()
call assert_true(len(l) == 2 &&
@@ -436,8 +466,11 @@ func XbufferTests(cchar)
\ l[1].lnum == 800 && l[1].col == 15 && l[1].text ==# 'Line 800')
enew!
- silent! call setline(1, ['Xtestfile9:900:55:Line 900',
- \ 'Xtestfile10:950:66:Line 950'])
+ let lines =<< trim END
+ Xtestfile9:900:55:Line 900
+ Xtestfile10:950:66:Line 950
+ END
+ silent! call setline(1, lines)
Xgetbuffer
let l = g:Xgetlist()
call assert_true(len(l) == 2 &&
@@ -445,8 +478,11 @@ func XbufferTests(cchar)
\ l[1].lnum == 950 && l[1].col == 66 && l[1].text ==# 'Line 950')
enew!
- silent! call setline(1, ['Xtestfile11:700:20:Line 700',
- \ 'Xtestfile12:750:25:Line 750'])
+ let lines =<< trim END
+ Xtestfile11:700:20:Line 700
+ Xtestfile12:750:25:Line 750
+ END
+ silent! call setline(1, lines)
Xaddbuffer
let l = g:Xgetlist()
call assert_true(len(l) == 4 &&
@@ -516,12 +552,15 @@ func Xtest_browse(cchar)
call s:create_test_file('Xqftestfile1')
call s:create_test_file('Xqftestfile2')
- Xgetexpr ['Xqftestfile1:5:Line5',
- \ 'Xqftestfile1:6:Line6',
- \ 'Xqftestfile2:10:Line10',
- \ 'Xqftestfile2:11:Line11',
- \ 'RegularLine1',
- \ 'RegularLine2']
+ let lines =<< trim END
+ Xqftestfile1:5:Line5
+ Xqftestfile1:6:Line6
+ Xqftestfile2:10:Line10
+ Xqftestfile2:11:Line11
+ RegularLine1
+ RegularLine2
+ END
+ Xgetexpr lines
Xfirst
call assert_fails('-5Xcc', 'E16:')
@@ -571,10 +610,13 @@ func Xtest_browse(cchar)
call assert_equal(5, line('.'))
" Jumping to an error from the error window using cc command
- Xgetexpr ['Xqftestfile1:5:Line5',
- \ 'Xqftestfile1:6:Line6',
- \ 'Xqftestfile2:10:Line10',
- \ 'Xqftestfile2:11:Line11']
+ let lines =<< trim END
+ Xqftestfile1:5:Line5
+ Xqftestfile1:6:Line6
+ Xqftestfile2:10:Line10
+ Xqftestfile2:11:Line11
+ END
+ Xgetexpr lines
Xopen
10Xcc
call assert_equal(11, line('.'))
@@ -699,7 +741,7 @@ func s:test_xhelpgrep(cchar)
" Search for non existing help string
call assert_fails('Xhelpgrep a1b2c3', 'E480:')
" Invalid regular expression
- call assert_fails('Xhelpgrep \@<!', 'E480:')
+ call assert_fails('Xhelpgrep \@<!', 'E866:')
endfunc
func Test_helpgrep()
@@ -708,6 +750,35 @@ func Test_helpgrep()
call s:test_xhelpgrep('l')
endfunc
+" When running the :helpgrep command, if an autocmd modifies the 'cpoptions'
+" value, then Vim crashes. (issue fixed by 7.2b-004 and 8.2.4453)
+func Test_helpgrep_restore_cpo_aucmd()
+ let save_cpo = &cpo
+ augroup QF_Test
+ au!
+ autocmd BufNew * set cpo=acd
+ augroup END
+
+ helpgrep quickfix
+ call assert_equal('acd', &cpo)
+ %bw!
+
+ set cpo&vim
+ augroup QF_Test
+ au!
+ autocmd BufReadPost * set cpo=
+ augroup END
+
+ helpgrep buffer
+ call assert_equal('', &cpo)
+
+ augroup QF_Test
+ au!
+ augroup END
+ %bw!
+ let &cpo = save_cpo
+endfunc
+
func Test_errortitle()
augroup QfBufWinEnter
au!
@@ -1073,20 +1144,21 @@ func s:dir_stack_tests(cchar)
let save_efm=&efm
set efm=%DEntering\ dir\ '%f',%f:%l:%m,%XLeaving\ dir\ '%f'
- let lines = ["Entering dir 'dir1/a'",
- \ 'habits2.txt:1:Nine Healthy Habits',
- \ "Entering dir 'b'",
- \ 'habits3.txt:2:0 Hours of television',
- \ 'habits2.txt:7:5 Small meals',
- \ "Entering dir 'dir1/c'",
- \ 'habits4.txt:3:1 Hour of exercise',
- \ "Leaving dir 'dir1/c'",
- \ "Leaving dir 'dir1/a'",
- \ 'habits1.txt:4:2 Liters of water',
- \ "Entering dir 'dir2'",
- \ 'habits5.txt:5:3 Cups of hot green tea',
- \ "Leaving dir 'dir2'"
- \]
+ let lines =<< trim END
+ Entering dir 'dir1/a'
+ habits2.txt:1:Nine Healthy Habits
+ Entering dir 'b'
+ habits3.txt:2:0 Hours of television
+ habits2.txt:7:5 Small meals
+ Entering dir 'dir1/c'
+ habits4.txt:3:1 Hour of exercise
+ Leaving dir 'dir1/c'
+ Leaving dir 'dir1/a'
+ habits1.txt:4:2 Liters of water
+ Entering dir 'dir2'
+ habits5.txt:5:3 Cups of hot green tea
+ Leaving dir 'dir2'
+ END
Xexpr ""
for l in lines
@@ -1120,19 +1192,19 @@ func Test_efm_dirstack()
call mkdir('dir1/c')
call mkdir('dir2')
- let lines = ["Nine Healthy Habits",
- \ "0 Hours of television",
- \ "1 Hour of exercise",
- \ "2 Liters of water",
- \ "3 Cups of hot green tea",
- \ "4 Short mental breaks",
- \ "5 Small meals",
- \ "6 AM wake up time",
- \ "7 Minutes of laughter",
- \ "8 Hours of sleep (at least)",
- \ "9 PM end of the day and off to bed"
- \ ]
-
+ let lines =<< trim END
+ Nine Healthy Habits
+ 0 Hours of television
+ 1 Hour of exercise
+ 2 Liters of water
+ 3 Cups of hot green tea
+ 4 Short mental breaks
+ 5 Small meals
+ 6 AM wake up time
+ 7 Minutes of laughter
+ 8 Hours of sleep (at least)
+ 9 PM end of the day and off to bed
+ END
call writefile(lines, 'habits1.txt')
call writefile(lines, 'dir1/a/habits2.txt')
call writefile(lines, 'dir1/a/b/habits3.txt')
@@ -1158,7 +1230,13 @@ func Xefm_ignore_continuations(cchar)
\ '%-Wignored %m %l,' .
\ '%+Cmore ignored %m %l,' .
\ '%Zignored end'
- Xgetexpr ['ignored warning 1', 'more ignored continuation 2', 'ignored end', 'error resync 4']
+ let lines =<< trim END
+ ignored warning 1
+ more ignored continuation 2
+ ignored end
+ error resync 4
+ END
+ Xgetexpr lines
let l = map(g:Xgetlist(), '[v:val.text, v:val.valid, v:val.lnum, v:val.type]')
call assert_equal([['resync', 1, 4, 'E']], l)
@@ -1204,8 +1282,14 @@ func Xinvalid_efm_Tests(cchar)
set efm=
call assert_fails('Xexpr "abc.txt:1:Hello world"', 'E378:')
+ " Empty directory name. When there is an error in parsing new entries, make
+ " sure the previous quickfix list is made the current list.
+ set efm&
+ cexpr ["one", "two"]
+ let qf_id = getqflist(#{id: 0}).id
set efm=%DEntering\ dir\ abc,%f:%l:%m
call assert_fails('Xexpr ["Entering dir abc", "abc.txt:1:Hello world"]', 'E379:')
+ call assert_equal(qf_id, getqflist(#{id: 0}).id)
let &efm = save_efm
endfunc
@@ -1396,8 +1480,14 @@ func Test_efm_error_type()
" error type
set efm=%f:%l:%t:%m
- cexpr ["Xfile1:10:E:msg1", "Xfile1:20:W:msg2", "Xfile1:30:I:msg3",
- \ "Xfile1:40:N:msg4", "Xfile1:50:R:msg5"]
+ let lines =<< trim END
+ Xfile1:10:E:msg1
+ Xfile1:20:W:msg2
+ Xfile1:30:I:msg3
+ Xfile1:40:N:msg4
+ Xfile1:50:R:msg5
+ END
+ cexpr lines
let output = split(execute('clist'), "\n")
call assert_equal([
\ ' 1 Xfile1:10 error: msg1',
@@ -1408,8 +1498,14 @@ func Test_efm_error_type()
" error type and a error number
set efm=%f:%l:%t:%n:%m
- cexpr ["Xfile1:10:E:2:msg1", "Xfile1:20:W:4:msg2", "Xfile1:30:I:6:msg3",
- \ "Xfile1:40:N:8:msg4", "Xfile1:50:R:3:msg5"]
+ let lines =<< trim END
+ Xfile1:10:E:2:msg1
+ Xfile1:20:W:4:msg2
+ Xfile1:30:I:6:msg3
+ Xfile1:40:N:8:msg4
+ Xfile1:50:R:3:msg5
+ END
+ cexpr lines
let output = split(execute('clist'), "\n")
call assert_equal([
\ ' 1 Xfile1:10 error 2: msg1',
@@ -1434,8 +1530,13 @@ func Test_efm_end_lnum_col()
" multiple lines
set efm=%A%n)%m,%Z%f:%l-%e:%c-%k
- cexpr ["1)msg1", "Xfile1:14-24:1-2",
- \ "2)msg2", "Xfile1:24-34:3-4"]
+ let lines =<< trim END
+ 1)msg1
+ Xfile1:14-24:1-2
+ 2)msg2
+ Xfile1:24-34:3-4
+ END
+ cexpr lines
let output = split(execute('clist'), "\n")
call assert_equal([
\ ' 1 Xfile1:14-24 col 1-2 error 1: msg1',
@@ -1459,7 +1560,7 @@ func XquickfixChangedByAutocmd(cchar)
endfunc
endif
- augroup testgroup
+ augroup QF_Test
au!
autocmd BufReadCmd test_changed.txt call ReadFunc()
augroup END
@@ -1473,7 +1574,24 @@ func XquickfixChangedByAutocmd(cchar)
endfor
call assert_fails('Xrewind', ErrorNr . ':')
- augroup! testgroup
+ augroup QF_Test
+ au!
+ augroup END
+
+ if a:cchar == 'c'
+ cexpr ["Xtest1:1:Line"]
+ cwindow
+ only
+ augroup QF_Test
+ au!
+ autocmd WinEnter * call setqflist([], 'f')
+ augroup END
+ call assert_fails('exe "normal \<CR>"', 'E925:')
+ augroup QF_Test
+ au!
+ augroup END
+ endif
+ %bw!
endfunc
func Test_quickfix_was_changed_by_autocmd()
@@ -1611,6 +1729,9 @@ func SetXlistTests(cchar, bnum)
\ " {'bufnr':999, 'lnum':5}])", 'E92:')
call g:Xsetlist([[1, 2,3]])
call assert_equal(0, len(g:Xgetlist()))
+ call assert_fails('call g:Xsetlist([], [])', 'E928:')
+ call g:Xsetlist([v:_null_dict])
+ call assert_equal([], g:Xgetlist())
endfunc
func Test_setqflist()
@@ -1825,12 +1946,12 @@ func Test_cgetfile_on_long_lines()
" Problematic values if the line is longer than 4096 bytes. Then 1024 bytes
" are read at a time.
for len in [4078, 4079, 4080, 5102, 5103, 5104, 6126, 6127, 6128, 7150, 7151, 7152]
- let lines = [
- \ '/tmp/file1:1:1:aaa',
- \ '/tmp/file2:1:1:%s',
- \ '/tmp/file3:1:1:bbb',
- \ '/tmp/file4:1:1:ccc',
- \ ]
+ let lines =<< trim END
+ /tmp/file1:1:1:aaa
+ /tmp/file2:1:1:%s
+ /tmp/file3:1:1:bbb
+ /tmp/file4:1:1:ccc
+ END
let lines[1] = substitute(lines[1], '%s', repeat('x', len), '')
call writefile(lines, 'Xcqetfile.txt')
cgetfile Xcqetfile.txt
@@ -1857,12 +1978,15 @@ func Test_switchbuf()
let file1_winid = win_getid()
new Xqftestfile2
let file2_winid = win_getid()
- cgetexpr ['Xqftestfile1:5:Line5',
- \ 'Xqftestfile1:6:Line6',
- \ 'Xqftestfile2:10:Line10',
- \ 'Xqftestfile2:11:Line11',
- \ 'Xqftestfile3:15:Line15',
- \ 'Xqftestfile3:16:Line16']
+ let lines =<< trim END
+ Xqftestfile1:5:Line5
+ Xqftestfile1:6:Line6
+ Xqftestfile2:10:Line10
+ Xqftestfile2:11:Line11
+ Xqftestfile3:15:Line15
+ Xqftestfile3:16:Line16
+ END
+ cgetexpr lines
new
let winid = win_getid()
@@ -2524,21 +2648,23 @@ func Test_Autocmd()
silent! cexpr non_existing_func()
silent! caddexpr non_existing_func()
silent! cgetexpr non_existing_func()
- let l = ['precexpr',
- \ 'postcexpr',
- \ 'precaddexpr',
- \ 'postcaddexpr',
- \ 'precgetexpr',
- \ 'postcgetexpr',
- \ 'precexpr',
- \ 'postcexpr',
- \ 'precaddexpr',
- \ 'postcaddexpr',
- \ 'precgetexpr',
- \ 'postcgetexpr',
- \ 'precexpr',
- \ 'precaddexpr',
- \ 'precgetexpr']
+ let l =<< trim END
+ precexpr
+ postcexpr
+ precaddexpr
+ postcaddexpr
+ precgetexpr
+ postcgetexpr
+ precexpr
+ postcexpr
+ precaddexpr
+ postcaddexpr
+ precgetexpr
+ postcgetexpr
+ precexpr
+ precaddexpr
+ precgetexpr
+ END
call assert_equal(l, g:acmds)
let g:acmds = []
@@ -2556,15 +2682,17 @@ func Test_Autocmd()
exe 'silent! cgetbuffer ' . bnum
exe 'silent! caddbuffer ' . bnum
enew!
- let l = ['precbuffer',
- \ 'postcbuffer',
- \ 'precgetbuffer',
- \ 'postcgetbuffer',
- \ 'precaddbuffer',
- \ 'postcaddbuffer',
- \ 'precbuffer',
- \ 'precgetbuffer',
- \ 'precaddbuffer']
+ let l =<< trim END
+ precbuffer
+ postcbuffer
+ precgetbuffer
+ postcgetbuffer
+ precaddbuffer
+ postcaddbuffer
+ precbuffer
+ precgetbuffer
+ precaddbuffer
+ END
call assert_equal(l, g:acmds)
call writefile(['Xtest:1:Line1'], 'Xtest')
@@ -2579,24 +2707,26 @@ func Test_Autocmd()
silent! cfile do_not_exist
silent! caddfile do_not_exist
silent! cgetfile do_not_exist
- let l = ['precfile',
- \ 'postcfile',
- \ 'precaddfile',
- \ 'postcaddfile',
- \ 'precgetfile',
- \ 'postcgetfile',
- \ 'precfile',
- \ 'postcfile',
- \ 'precaddfile',
- \ 'postcaddfile',
- \ 'precgetfile',
- \ 'postcgetfile',
- \ 'precfile',
- \ 'postcfile',
- \ 'precaddfile',
- \ 'postcaddfile',
- \ 'precgetfile',
- \ 'postcgetfile']
+ let l =<< trim END
+ precfile
+ postcfile
+ precaddfile
+ postcaddfile
+ precgetfile
+ postcgetfile
+ precfile
+ postcfile
+ precaddfile
+ postcaddfile
+ precgetfile
+ postcgetfile
+ precfile
+ postcfile
+ precaddfile
+ postcaddfile
+ precgetfile
+ postcgetfile
+ END
call assert_equal(l, g:acmds)
let g:acmds = []
@@ -2609,20 +2739,22 @@ func Test_Autocmd()
set makeprg=
silent! make
set makeprg&
- let l = ['prehelpgrep',
- \ 'posthelpgrep',
- \ 'prehelpgrep',
- \ 'posthelpgrep',
- \ 'previmgrep',
- \ 'postvimgrep',
- \ 'previmgrepadd',
- \ 'postvimgrepadd',
- \ 'previmgrep',
- \ 'postvimgrep',
- \ 'previmgrepadd',
- \ 'postvimgrepadd',
- \ 'premake',
- \ 'postmake']
+ let l =<< trim END
+ prehelpgrep
+ posthelpgrep
+ prehelpgrep
+ posthelpgrep
+ previmgrep
+ postvimgrep
+ previmgrepadd
+ postvimgrepadd
+ previmgrep
+ postvimgrep
+ previmgrepadd
+ postvimgrepadd
+ premake
+ postmake
+ END
call assert_equal(l, g:acmds)
if has('unix')
@@ -2642,22 +2774,24 @@ func Test_Autocmd()
silent lgrep Grep_Autocmd_Text test_quickfix.vim
silent lgrepadd GrepAdd_Autocmd_Text test_quickfix.vim
set grepprg&vim
- let l = ['pregrep',
- \ 'postgrep',
- \ 'pregrepadd',
- \ 'postgrepadd',
- \ 'pregrep',
- \ 'postgrep',
- \ 'pregrepadd',
- \ 'postgrepadd',
- \ 'pregrep',
- \ 'postgrep',
- \ 'pregrepadd',
- \ 'postgrepadd',
- \ 'prelgrep',
- \ 'postlgrep',
- \ 'prelgrepadd',
- \ 'postlgrepadd']
+ let l =<< trim END
+ pregrep
+ postgrep
+ pregrepadd
+ postgrepadd
+ pregrep
+ postgrep
+ pregrepadd
+ postgrepadd
+ pregrep
+ postgrep
+ pregrepadd
+ postgrepadd
+ prelgrep
+ postlgrep
+ prelgrepadd
+ postlgrepadd
+ END
call assert_equal(l, g:acmds)
endif
@@ -2816,15 +2950,16 @@ func Test_cwindow_highlight()
CheckScreendump
let lines =<< trim END
- call setline(1, ['some', 'text', 'with', 'matches'])
- write XCwindow
- vimgrep e XCwindow
- redraw
- cwindow 4
+ call setline(1, ['some', 'text', 'with', 'matches'])
+ write XCwindow
+ vimgrep e XCwindow
+ redraw
+ cwindow 4
END
call writefile(lines, 'XtestCwindow')
let buf = RunVimInTerminal('-S XtestCwindow', #{rows: 12})
call VerifyScreenDump(buf, 'Test_quickfix_cwindow_1', {})
+
call term_sendkeys(buf, ":cnext\<CR>")
call VerifyScreenDump(buf, 'Test_quickfix_cwindow_2', {})
@@ -2837,10 +2972,13 @@ endfunc
func XvimgrepTests(cchar)
call s:setup_commands(a:cchar)
- call writefile(['Editor:VIM vim',
- \ 'Editor:Emacs EmAcS',
- \ 'Editor:Notepad NOTEPAD'], 'Xtestfile1')
- call writefile(['Linux', 'MacOS', 'MS-Windows'], 'Xtestfile2')
+ let lines =<< trim END
+ Editor:VIM vim
+ Editor:Emacs EmAcS
+ Editor:Notepad NOTEPAD
+ END
+ call writefile(lines, 'Xtestfile1')
+ call writefile(['Linux', 'macOS', 'MS-Windows'], 'Xtestfile2')
" Error cases
call assert_fails('Xvimgrep /abc *', 'E682:')
@@ -2854,7 +2992,7 @@ func XvimgrepTests(cchar)
Xexpr ""
Xvimgrepadd Notepad Xtestfile1
- Xvimgrepadd MacOS Xtestfile2
+ Xvimgrepadd macOS Xtestfile2
let l = g:Xgetlist()
call assert_equal(2, len(l))
call assert_equal('Editor:Notepad NOTEPAD', l[0].text)
@@ -2884,6 +3022,19 @@ func XvimgrepTests(cchar)
call assert_equal(0, getbufinfo('Xtestfile1')[0].loaded)
call assert_equal([], getbufinfo('Xtestfile2'))
+ " Test for opening the dummy buffer used by vimgrep in a window. The new
+ " window should be closed
+ %bw!
+ augroup QF_Test
+ au!
+ autocmd BufReadPre * exe "sb " .. expand("<abuf>")
+ augroup END
+ call assert_fails("Xvimgrep /sublime/ Xtestfile1", 'E480:')
+ call assert_equal(1, winnr('$'))
+ augroup QF_Test
+ au!
+ augroup END
+
call delete('Xtestfile1')
call delete('Xtestfile2')
endfunc
@@ -3087,7 +3238,7 @@ func Test_cclose_from_copen()
endfunc
func Test_cclose_in_autocmd()
- " Problem is only triggered if "starting" is zero, so that the OptionsSet
+ " Problem is only triggered if "starting" is zero, so that the OptionSet
" event will be triggered.
" call test_override('starting', 1)
augroup QF_Test
@@ -3102,7 +3253,7 @@ func Test_cclose_in_autocmd()
" call test_override('starting', 0)
endfunc
-" Check that ":file" without an argument is possible even when curbuf is locked
+" Check that ":file" without an argument is possible even when "curbuf->b_ro_locked"
" is set.
func Test_file_from_copen()
" Works without argument.
@@ -3148,6 +3299,21 @@ func Test_resize_from_copen()
endtry
endfunc
+func Test_filetype_autocmd()
+ " this changes the location list while it is in use to fill a buffer
+ lexpr ''
+ lopen
+ augroup FT_loclist
+ au FileType * call setloclist(0, [], 'f')
+ augroup END
+ silent! lolder
+ lexpr ''
+
+ augroup FT_loclist
+ au! FileType
+ augroup END
+endfunc
+
func Test_vimgrep_with_textlock()
new
@@ -3291,9 +3457,9 @@ func Xmultidirstack_tests(cchar)
let l1 = g:Xgetlist({'nr':1, 'items':1})
let l2 = g:Xgetlist({'nr':2, 'items':1})
- call assert_equal(expand('Xone/a/one.txt'), bufname(l1.items[1].bufnr))
+ call assert_equal('Xone/a/one.txt', bufname(l1.items[1].bufnr))
call assert_equal(3, l1.items[1].lnum)
- call assert_equal(expand('Xtwo/a/two.txt'), bufname(l2.items[1].bufnr))
+ call assert_equal('Xtwo/a/two.txt', bufname(l2.items[1].bufnr))
call assert_equal(5, l2.items[1].lnum)
endfunc
@@ -3337,14 +3503,15 @@ func Xmultifilestack_tests(cchar)
" error line ends with a file stack.
let efm_val = 'Error\ l%l\ in\ %f,'
let efm_val .= '%-P%>(%f%r,Error\ l%l\ in\ %m,%-Q)%r'
- let l = g:Xgetlist({'lines' : [
- \ '(one.txt',
- \ 'Error l4 in one.txt',
- \ ') (two.txt',
- \ 'Error l6 in two.txt',
- \ ')',
- \ 'Error l8 in one.txt'
- \ ], 'efm' : efm_val})
+ let lines =<< trim END
+ (one.txt
+ Error l4 in one.txt
+ ) (two.txt
+ Error l6 in two.txt
+ )
+ Error l8 in one.txt
+ END
+ let l = g:Xgetlist({'lines': lines, 'efm' : efm_val})
call assert_equal(3, len(l.items))
call assert_equal('one.txt', bufname(l.items[0].bufnr))
call assert_equal(4, l.items[0].lnum)
@@ -3622,7 +3789,15 @@ func Xqfjump_tests(cchar)
call g:Xsetlist([], 'f')
setlocal buftype=nofile
new
- call g:Xsetlist([], ' ', {'lines' : ['F1:1:1:Line1', 'F1:2:2:Line2', 'F2:1:1:Line1', 'F2:2:2:Line2', 'F3:1:1:Line1', 'F3:2:2:Line2']})
+ let lines =<< trim END
+ F1:1:1:Line1
+ F1:2:2:Line2
+ F2:1:1:Line1
+ F2:2:2:Line2
+ F3:1:1:Line1
+ F3:2:2:Line2
+ END
+ call g:Xsetlist([], ' ', {'lines': lines})
Xopen
let winid = win_getid()
wincmd p
@@ -3758,6 +3933,22 @@ func Xgetlist_empty_tests(cchar)
endif
endfunc
+func Test_empty_list_quickfixtextfunc()
+ " This was crashing. Can only reproduce by running it in a separate Vim
+ " instance.
+ let lines =<< trim END
+ func s:Func(o)
+ cgetexpr '0'
+ endfunc
+ cope
+ let &quickfixtextfunc = 's:Func'
+ cgetfile [ex
+ END
+ call writefile(lines, 'Xquickfixtextfunc')
+ call RunVim([], [], '-e -s -S Xquickfixtextfunc -c qa')
+ call delete('Xquickfixtextfunc')
+endfunc
+
func Test_getqflist()
call Xgetlist_empty_tests('c')
call Xgetlist_empty_tests('l')
@@ -3943,8 +4134,8 @@ endfunc
func Test_lvimgrep_crash2()
au BufNewFile x sfind
- call assert_fails('lvimgrep x x', 'E480:')
- call assert_fails('lvimgrep x x x', 'E480:')
+ call assert_fails('lvimgrep x x', 'E471:')
+ call assert_fails('lvimgrep x x x', 'E471:')
au! BufNewFile
endfunc
@@ -4055,14 +4246,19 @@ endfunc
" The following test used to crash Vim
func Test_lhelpgrep_autocmd()
lhelpgrep quickfix
- autocmd QuickFixCmdPost * call setloclist(0, [], 'f')
+ augroup QF_Test
+ au!
+ autocmd QuickFixCmdPost * call setloclist(0, [], 'f')
+ augroup END
lhelpgrep buffer
call assert_equal('help', &filetype)
call assert_equal(0, getloclist(0, {'nr' : '$'}).nr)
lhelpgrep tabpage
call assert_equal('help', &filetype)
call assert_equal(1, getloclist(0, {'nr' : '$'}).nr)
- au! QuickFixCmdPost
+ augroup QF_Test
+ au!
+ augroup END
new | only
augroup QF_Test
@@ -4075,7 +4271,7 @@ func Test_lhelpgrep_autocmd()
wincmd w
call assert_fails('helpgrep quickfix', 'E925:')
augroup QF_Test
- au! BufEnter
+ au!
augroup END
new | only
@@ -4085,7 +4281,7 @@ func Test_lhelpgrep_autocmd()
augroup END
call assert_fails('helpgrep quickfix', 'E925:')
augroup QF_Test
- au! BufEnter
+ au!
augroup END
new | only
@@ -4095,10 +4291,43 @@ func Test_lhelpgrep_autocmd()
augroup END
call assert_fails('lhelpgrep quickfix', 'E926:')
augroup QF_Test
- au! BufEnter
+ au!
augroup END
+ " Replace the contents of a help window location list when it is still in
+ " use.
new | only
+ lhelpgrep quickfix
+ wincmd w
+ augroup QF_Test
+ au!
+ autocmd WinEnter * call setloclist(0, [], 'r')
+ augroup END
+ call assert_fails('lhelpgrep win_getid', 'E926:')
+ augroup QF_Test
+ au!
+ augroup END
+
+ %bw!
+endfunc
+
+" The following test used to crash Vim
+func Test_lhelpgrep_autocmd_free_loclist()
+ %bw!
+ lhelpgrep quickfix
+ wincmd w
+ augroup QF_Test
+ au!
+ autocmd WinEnter * call setloclist(0, [], 'f')
+ augroup END
+ lhelpgrep win_getid
+ wincmd w
+ wincmd w
+ wincmd w
+ augroup QF_Test
+ au!
+ augroup END
+ %bw!
endfunc
" Test for shortening/simplifying the file name when opening the
@@ -4816,9 +5045,20 @@ func Xtest_below(cchar)
endif
" Test for lines with multiple quickfix entries
- Xexpr ["X1:5:L5", "X2:5:1:L5_1", "X2:5:2:L5_2", "X2:5:3:L5_3",
- \ "X2:10:1:L10_1", "X2:10:2:L10_2", "X2:10:3:L10_3",
- \ "X2:15:1:L15_1", "X2:15:2:L15_2", "X2:15:3:L15_3", "X3:3:L3"]
+ let lines =<< trim END
+ X1:5:L5
+ X2:5:1:L5_1
+ X2:5:2:L5_2
+ X2:5:3:L5_3
+ X2:10:1:L10_1
+ X2:10:2:L10_2
+ X2:10:3:L10_3
+ X2:15:1:L15_1
+ X2:15:2:L15_2
+ X2:15:3:L15_3
+ X3:3:L3
+ END
+ Xexpr lines
edit +1 X2
Xbelow 2
call assert_equal(['X2', 10, 1], [@%, line('.'), col('.')])
@@ -4882,33 +5122,32 @@ func Test_cbelow()
endfunc
func Test_quickfix_count()
- let commands = [
- \ 'cNext',
- \ 'cNfile',
- \ 'cabove',
- \ 'cbelow',
- \ 'cfirst',
- \ 'clast',
- \ 'cnewer',
- \ 'cnext',
- \ 'cnfile',
- \ 'colder',
- \ 'cprevious',
- \ 'crewind',
- \
- \ 'lNext',
- \ 'lNfile',
- \ 'labove',
- \ 'lbelow',
- \ 'lfirst',
- \ 'llast',
- \ 'lnewer',
- \ 'lnext',
- \ 'lnfile',
- \ 'lolder',
- \ 'lprevious',
- \ 'lrewind',
- \ ]
+ let commands =<< trim END
+ cNext
+ cNfile
+ cabove
+ cbelow
+ cfirst
+ clast
+ cnewer
+ cnext
+ cnfile
+ colder
+ cprevious
+ crewind
+ lNext
+ lNfile
+ labove
+ lbelow
+ lfirst
+ llast
+ lnewer
+ lnext
+ lnfile
+ lolder
+ lprevious
+ lrewind
+ END
for cmd in commands
call assert_fails('-1' .. cmd, 'E16:')
call assert_fails('.' .. cmd, 'E16:')
@@ -5090,6 +5329,29 @@ func Test_lhelpgrep_from_help_window()
new | only!
endfunc
+" Test for the crash fixed by 7.3.715
+func Test_setloclist_crash()
+ %bw!
+ let g:BufNum = bufnr()
+ augroup QF_Test
+ au!
+ au BufUnload * call setloclist(0, [{'bufnr':g:BufNum, 'lnum':1, 'col':1, 'text': 'tango down'}])
+ augroup END
+
+ try
+ lvimgrep /.*/ *.mak
+ catch /E926:/
+ endtry
+ call assert_equal('tango down', getloclist(0, {'items' : 0}).items[0].text)
+ call assert_equal(1, getloclist(0, {'size' : 0}).size)
+
+ augroup QF_Test
+ au!
+ augroup END
+ unlet g:BufNum
+ %bw!
+endfunc
+
" Test for adding an invalid entry with the quickfix window open and making
" sure that the window contents are not changed
func Test_add_invalid_entry_with_qf_window()
@@ -5289,6 +5551,7 @@ func Xtest_getqflist_by_idx(cchar)
call assert_equal('L20', l[0].text)
call assert_equal([], g:Xgetlist({'idx' : -1, 'items' : 0}).items)
call assert_equal([], g:Xgetlist({'idx' : 3, 'items' : 0}).items)
+ call assert_equal({}, g:Xgetlist(#{idx: "abc"}))
%bwipe!
endfunc
@@ -5347,6 +5610,19 @@ func Xtest_qftextfunc(cchar)
call assert_equal('F1|10 col 2-7| green', getline(1))
call assert_equal('F1|20-25 col 4-8| blue', getline(2))
Xclose
+
+ set efm=%f:%l:%c:%m
+ set quickfixtextfunc=Tqfexpr
+ " Update the list with only the cwindow
+ Xwindow
+ only
+ call g:Xsetlist([
+ \ { 'filename': 'F2', 'lnum': 20, 'col': 2,
+ \ 'end_col': 7, 'text': 'red'}
+ \ ])
+ call assert_equal(['F2-L20C2-red'], getline(1, '$'))
+ new
+ Xclose
set efm&
set quickfixtextfunc&
@@ -5470,6 +5746,155 @@ func Test_qftextfunc()
call Xtest_qftextfunc('l')
endfunc
+func Test_qftextfunc_callback()
+ let lines =<< trim END
+ set efm=%f:%l:%c:%m
+
+ #" Test for using a function name
+ LET &qftf = 'g:Tqfexpr'
+ cexpr "F0:0:0:L0"
+ copen
+ call assert_equal('F0-L0C0-L0', getline(1))
+ cclose
+
+ #" Test for using a function()
+ set qftf=function('g:Tqfexpr')
+ cexpr "F1:1:1:L1"
+ copen
+ call assert_equal('F1-L1C1-L1', getline(1))
+ cclose
+
+ #" Using a funcref variable to set 'quickfixtextfunc'
+ VAR Fn = function('g:Tqfexpr')
+ LET &qftf = Fn
+ cexpr "F2:2:2:L2"
+ copen
+ call assert_equal('F2-L2C2-L2', getline(1))
+ cclose
+
+ #" Using string(funcref_variable) to set 'quickfixtextfunc'
+ LET Fn = function('g:Tqfexpr')
+ LET &qftf = string(Fn)
+ cexpr "F3:3:3:L3"
+ copen
+ call assert_equal('F3-L3C3-L3', getline(1))
+ cclose
+
+ #" Test for using a funcref()
+ set qftf=funcref('g:Tqfexpr')
+ cexpr "F4:4:4:L4"
+ copen
+ call assert_equal('F4-L4C4-L4', getline(1))
+ cclose
+
+ #" Using a funcref variable to set 'quickfixtextfunc'
+ LET Fn = funcref('g:Tqfexpr')
+ LET &qftf = Fn
+ cexpr "F5:5:5:L5"
+ copen
+ call assert_equal('F5-L5C5-L5', getline(1))
+ cclose
+
+ #" Using a string(funcref_variable) to set 'quickfixtextfunc'
+ LET Fn = funcref('g:Tqfexpr')
+ LET &qftf = string(Fn)
+ cexpr "F5:5:5:L5"
+ copen
+ call assert_equal('F5-L5C5-L5', getline(1))
+ cclose
+
+ #" Test for using a lambda function with set
+ VAR optval = "LSTART a LMIDDLE Tqfexpr(a) LEND"
+ LET optval = substitute(optval, ' ', '\\ ', 'g')
+ exe "set qftf=" .. optval
+ cexpr "F6:6:6:L6"
+ copen
+ call assert_equal('F6-L6C6-L6', getline(1))
+ cclose
+
+ #" Set 'quickfixtextfunc' to a lambda expression
+ LET &qftf = LSTART a LMIDDLE Tqfexpr(a) LEND
+ cexpr "F7:7:7:L7"
+ copen
+ call assert_equal('F7-L7C7-L7', getline(1))
+ cclose
+
+ #" Set 'quickfixtextfunc' to string(lambda_expression)
+ LET &qftf = "LSTART a LMIDDLE Tqfexpr(a) LEND"
+ cexpr "F8:8:8:L8"
+ copen
+ call assert_equal('F8-L8C8-L8', getline(1))
+ cclose
+
+ #" Set 'quickfixtextfunc' to a variable with a lambda expression
+ VAR Lambda = LSTART a LMIDDLE Tqfexpr(a) LEND
+ LET &qftf = Lambda
+ cexpr "F9:9:9:L9"
+ copen
+ call assert_equal('F9-L9C9-L9', getline(1))
+ cclose
+
+ #" Set 'quickfixtextfunc' to a string(variable with a lambda expression)
+ LET Lambda = LSTART a LMIDDLE Tqfexpr(a) LEND
+ LET &qftf = string(Lambda)
+ cexpr "F9:9:9:L9"
+ copen
+ call assert_equal('F9-L9C9-L9', getline(1))
+ cclose
+ END
+ call CheckLegacyAndVim9Success(lines)
+
+ " Test for using a script-local function name
+ func s:TqfFunc2(info)
+ let g:TqfFunc2Args = [a:info.start_idx, a:info.end_idx]
+ return ''
+ endfunc
+ let g:TqfFunc2Args = []
+ set quickfixtextfunc=s:TqfFunc2
+ cexpr "F10:10:10:L10"
+ cclose
+ call assert_equal([1, 1], g:TqfFunc2Args)
+
+ let &quickfixtextfunc = 's:TqfFunc2'
+ cexpr "F11:11:11:L11"
+ cclose
+ call assert_equal([1, 1], g:TqfFunc2Args)
+ delfunc s:TqfFunc2
+
+ " set 'quickfixtextfunc' to a partial with dict. This used to cause a crash.
+ func SetQftfFunc()
+ let params = {'qftf': function('g:DictQftfFunc')}
+ let &quickfixtextfunc = params.qftf
+ endfunc
+ func g:DictQftfFunc(_) dict
+ endfunc
+ call SetQftfFunc()
+ new
+ call SetQftfFunc()
+ bw
+ call test_garbagecollect_now()
+ new
+ set qftf=
+ wincmd w
+ set qftf=
+ :%bw!
+
+ " set per-quickfix list 'quickfixtextfunc' to a partial with dict. This used
+ " to cause a crash.
+ let &qftf = ''
+ func SetLocalQftfFunc()
+ let params = {'qftf': function('g:DictQftfFunc')}
+ call setqflist([], 'a', {'quickfixtextfunc' : params.qftf})
+ endfunc
+ call SetLocalQftfFunc()
+ call test_garbagecollect_now()
+ call setqflist([], 'a', {'quickfixtextfunc' : ''})
+ delfunc g:DictQftfFunc
+ delfunc SetQftfFunc
+ delfunc SetLocalQftfFunc
+ set efm&
+endfunc
+
" Test for updating a location list for some other window and check that
" 'qftextfunc' uses the correct location list.
func Test_qftextfunc_other_loclist()
@@ -5535,9 +5960,12 @@ func Test_locationlist_open_in_newtab()
%bwipe!
- lgetexpr ['Xqftestfile1:5:Line5',
- \ 'Xqftestfile2:10:Line10',
- \ 'Xqftestfile3:16:Line16']
+ let lines =<< trim END
+ Xqftestfile1:5:Line5
+ Xqftestfile2:10:Line10
+ Xqftestfile3:16:Line16
+ END
+ lgetexpr lines
silent! llast
call assert_equal(1, tabpagenr('$'))
@@ -5578,6 +6006,21 @@ func Test_win_gettype()
lclose
endfunc
+fun Test_vimgrep_nomatch()
+ call XexprTests('c')
+ call g:Xsetlist([{'lnum':10,'text':'Line1'}])
+ copen
+ if has("win32")
+ call assert_fails('vimgrep foo *.zzz', 'E479:')
+ let expected = [{'lnum': 10, 'bufnr': 0, 'end_lnum': 0, 'pattern': '', 'valid': 0, 'vcol': 0, 'nr': 0, 'module': '', 'type': '', 'end_col': 0, 'col': 0, 'text': 'Line1'}]
+ else
+ call assert_fails('vimgrep foo *.zzz', 'E480:')
+ let expected = []
+ endif
+ call assert_equal(expected, getqflist())
+ cclose
+endfunc
+
" Test for opening the quickfix window in two tab pages and then closing one
" of the quickfix windows. This should not make the quickfix buffer unlisted.
" (github issue #9300).
@@ -5646,7 +6089,7 @@ func Test_lopen_bwipe_all()
qall!
END
call writefile(lines, 'Xscript')
- if RunVim([], [], '--clean -n -S Xscript')
+ if RunVim([], [], '-u NONE -n -X -Z -e -m -s -S Xscript')
call assert_equal(['done'], readfile('Xresult'))
endif
@@ -5654,5 +6097,140 @@ func Test_lopen_bwipe_all()
call delete('Xresult')
endfunc
+" Test for calling setqflist() function recursively
+func Test_recursive_setqflist()
+ augroup QF_Test
+ au!
+ autocmd BufWinEnter quickfix call setqflist([], 'r')
+ augroup END
+
+ copen
+ call assert_fails("call setqflist([], 'a')", 'E952:')
+
+ augroup QF_Test
+ au!
+ augroup END
+ %bw!
+endfunc
+
+" Test for failure to create a new window when selecting a file from the
+" quickfix window
+func Test_cwindow_newwin_fails()
+ cgetexpr ["Xfile1:10:L10", "Xfile1:20:L20"]
+ cwindow
+ only
+ let qf_wid = win_getid()
+ " create the maximum number of scratch windows
+ let hor_win_count = (&lines - 1)/2
+ let hor_split_count = hor_win_count - 1
+ for s in range(1, hor_split_count) | new | set buftype=nofile | endfor
+ call win_gotoid(qf_wid)
+ call assert_fails('exe "normal \<CR>"', 'E36:')
+ %bw!
+endfunc
+
+" Test for updating the location list when only the location list window is
+" present and the corresponding file window is closed.
+func Test_loclist_update_with_llwin_only()
+ %bw!
+ new
+ wincmd w
+ lexpr ["Xfile1:1:Line1"]
+ lopen
+ wincmd p
+ close
+ call setloclist(2, [], 'r', {'lines': ["Xtest2:2:Line2"]})
+ call assert_equal(['Xtest2|2| Line2'], getbufline(winbufnr(2), 1, '$'))
+ %bw!
+endfunc
+
+" Test for getting the quickfix list after a buffer with an error is wiped out
+func Test_getqflist_wiped_out_buffer()
+ %bw!
+ cexpr ["Xtest1:34:Wiped out"]
+ let bnum = bufnr('Xtest1')
+ call assert_equal(bnum, getqflist()[0].bufnr)
+ bw Xtest1
+ call assert_equal(0, getqflist()[0].bufnr)
+ %bw!
+endfunc
+
+" Test for the status message that is displayed when opening a new quickfix
+" list
+func Test_qflist_statusmsg()
+ cexpr "1\n2"
+ cexpr "1\n2\n3\ntest_quickfix.vim:1:msg"
+ call assert_equal('(4 of 4): msg', v:statusmsg)
+ call setqflist([], 'f')
+ %bw!
+
+ " When creating a new quickfix list, if an autocmd changes the quickfix list
+ " in the stack, then an error message should be displayed.
+ augroup QF_Test
+ au!
+ au BufEnter test_quickfix.vim colder
+ augroup END
+ cexpr "1\n2"
+ call assert_fails('cexpr "1\n2\n3\ntest_quickfix.vim:1:msg"', 'E925:')
+ call setqflist([], 'f')
+ augroup QF_Test
+ au!
+ augroup END
+ %bw!
+
+ augroup QF_Test
+ au!
+ au BufEnter test_quickfix.vim caddexpr "4"
+ augroup END
+ call assert_fails('cexpr "1\n2\n3\ntest_quickfix.vim:1:msg"', 'E925:')
+ call setqflist([], 'f')
+ augroup QF_Test
+ au!
+ augroup END
+ %bw!
+endfunc
+
+func Test_quickfixtextfunc_recursive()
+ func s:QFTfunc(o)
+ cgete '0'
+ endfunc
+ copen
+ let &quickfixtextfunc = 's:QFTfunc'
+ cex ""
+
+ let &quickfixtextfunc = ''
+ cclose
+endfunc
+
+" Test for replacing the location list from an autocmd. This used to cause a
+" read from freed memory.
+func Test_loclist_replace_autocmd()
+ %bw!
+ call setloclist(0, [], 'f')
+ let s:bufnr = bufnr()
+ cal setloclist(0, [{'0': 0, '': ''}])
+ au BufEnter * cal setloclist(1, [{'t': ''}, {'bufnr': s:bufnr}], 'r')
+ lopen
+ try
+ exe "norm j\<CR>"
+ catch
+ endtry
+ lnext
+ %bw!
+ call setloclist(0, [], 'f')
+endfunc
+
+func s:QfTf(_)
+endfunc
+
+func Test_setqflist_cb_arg()
+ " This was changing the callback name in the dictionary.
+ let d = #{quickfixtextfunc: 's:QfTf'}
+ call setqflist([], 'a', d)
+ call assert_equal('s:QfTf', d.quickfixtextfunc)
+
+ call setqflist([], 'f')
+endfunc
+
" vim: shiftwidth=2 sts=2 expandtab
diff --git a/src/nvim/testdir/test_quotestar.vim b/src/nvim/testdir/test_quotestar.vim
index 93865869fa..6a6719da8b 100644
--- a/src/nvim/testdir/test_quotestar.vim
+++ b/src/nvim/testdir/test_quotestar.vim
@@ -98,16 +98,17 @@ func Do_test_quotestar_for_x11()
" Running in a terminal and the GUI is available: Tell the server to open
" the GUI and check that the remote command still works.
- " Need to wait for the GUI to start up, otherwise the send hangs in trying
- " to send to the terminal window.
- if has('gui_athena') || has('gui_motif')
+ if has('gui_motif')
" For those GUIs, ignore the 'failed to create input context' error.
call remote_send(name, ":call test_ignore_error('E285') | gui -f\<CR>")
else
call remote_send(name, ":gui -f\<CR>")
endif
" Wait for the server in the GUI to be up and answering requests.
+ " First need to wait for the GUI to start up, otherwise the send hangs in
+ " trying to send to the terminal window.
" On some systems and with valgrind this can be very slow.
+ sleep 1
call WaitForAssert({-> assert_match("1", remote_expr(name, "has('gui_running')", "", 1))}, 10000)
call remote_send(name, ":let @* = 'maybe'\<CR>")
diff --git a/src/nvim/testdir/test_random.vim b/src/nvim/testdir/test_random.vim
index 6d3f7dcfd9..5fdbfe9cd8 100644
--- a/src/nvim/testdir/test_random.vim
+++ b/src/nvim/testdir/test_random.vim
@@ -1,5 +1,8 @@
" Tests for srand() and rand()
+source check.vim
+source shared.vim
+
func Test_Rand()
let r = srand(123456789)
call assert_equal([1573771921, 319883699, 2742014374, 1324369493], r)
@@ -9,18 +12,9 @@ func Test_Rand()
call assert_equal(2658065534, rand(r))
call assert_equal(3104308804, rand(r))
- " Nvim does not support test_settime
- " call test_settime(12341234)
let s = srand()
- if !has('win32') && filereadable('/dev/urandom')
- " using /dev/urandom
- call assert_notequal(s, srand())
- " else
- " " using time()
- " call assert_equal(s, srand())
- " call test_settime(12341235)
- " call assert_notequal(s, srand())
- endif
+ " using /dev/urandom or used time, result is different each time
+ call assert_notequal(s, srand())
" Nvim does not support test_srand_seed
" call test_srand_seed(123456789)
@@ -33,13 +27,11 @@ func Test_Rand()
endif
call assert_fails('echo srand([1])', 'E745:')
call assert_fails('echo rand("burp")', 'E475:')
- call assert_fails('echo rand([1, 2, 3])', 'E475:')
- call assert_fails('echo rand([[1], 2, 3, 4])', 'E475:')
- call assert_fails('echo rand([1, [2], 3, 4])', 'E475:')
- call assert_fails('echo rand([1, 2, [3], 4])', 'E475:')
- call assert_fails('echo rand([1, 2, 3, [4]])', 'E475:')
-
- " call test_settime(0)
+ call assert_fails('echo rand([1, 2, 3])', 'E730:')
+ call assert_fails('echo rand([[1], 2, 3, 4])', 'E730:')
+ call assert_fails('echo rand([1, [2], 3, 4])', 'E730:')
+ call assert_fails('echo rand([1, 2, [3], 4])', 'E730:')
+ call assert_fails('echo rand([1, 2, 3, [4]])', 'E730:')
endfunc
func Test_issue_5587()
@@ -48,4 +40,20 @@ func Test_issue_5587()
call rand()
endfunc
+func Test_srand()
+ CheckNotGui
+
+ let cmd = GetVimCommand() .. ' -V -es -c "echo rand()" -c qa!'
+ let bad = 0
+ for _ in range(10)
+ echo cmd
+ let result1 = system(cmd)
+ let result2 = system(cmd)
+ if result1 ==# result2
+ let bad += 1
+ endif
+ endfor
+ call assert_inrange(0, 4, bad)
+endfunc
+
" vim: shiftwidth=2 sts=2 expandtab
diff --git a/src/nvim/testdir/test_recover.vim b/src/nvim/testdir/test_recover.vim
index fc073cacd2..92e22687af 100644
--- a/src/nvim/testdir/test_recover.vim
+++ b/src/nvim/testdir/test_recover.vim
@@ -1,5 +1,7 @@
" Test :recover
+source check.vim
+
func Test_recover_root_dir()
" This used to access invalid memory.
split Xtest
@@ -23,6 +25,21 @@ func Test_recover_root_dir()
set dir&
endfunc
+" Make a copy of the current swap file to "Xswap".
+" Return the name of the swap file.
+func CopySwapfile()
+ preserve
+ " get the name of the swap file
+ let swname = split(execute("swapname"))[0]
+ let swname = substitute(swname, '[[:blank:][:cntrl:]]*\(.\{-}\)[[:blank:][:cntrl:]]*$', '\1', '')
+ " make a copy of the swap file in Xswap
+ set binary
+ exe 'sp ' . swname
+ w! Xswap
+ set nobinary
+ return swname
+endfunc
+
" Inserts 10000 lines with text to fill the swap file with two levels of pointer
" blocks. Then recovers from the swap file and checks all text is restored.
"
@@ -40,15 +57,9 @@ func Test_swap_file()
let i += 1
endwhile
$delete
- preserve
- " get the name of the swap file
- let swname = split(execute("swapname"))[0]
- let swname = substitute(swname, '[[:blank:][:cntrl:]]*\(.\{-}\)[[:blank:][:cntrl:]]*$', '\1', '')
- " make a copy of the swap file in Xswap
- set binary
- exe 'sp ' . swname
- w! Xswap
- set nobinary
+
+ let swname = CopySwapfile()
+
new
only!
bwipe! Xtest
@@ -69,3 +80,388 @@ func Test_swap_file()
set undolevels&
enew! | only
endfunc
+
+func Test_nocatch_process_still_running()
+ let g:skipped_reason = 'test_override() is N/A'
+ return
+ " sysinfo.uptime probably only works on Linux
+ if !has('linux')
+ let g:skipped_reason = 'only works on Linux'
+ return
+ endif
+ " the GUI dialog can't be handled
+ if has('gui_running')
+ let g:skipped_reason = 'only works in the terminal'
+ return
+ endif
+
+ " don't intercept existing swap file here
+ au! SwapExists
+
+ " Edit a file and grab its swapfile.
+ edit Xswaptest
+ call setline(1, ['a', 'b', 'c'])
+ let swname = CopySwapfile()
+
+ " Forget we edited this file
+ new
+ only!
+ bwipe! Xswaptest
+
+ call rename('Xswap', swname)
+ call feedkeys('e', 'tL')
+ redir => editOutput
+ edit Xswaptest
+ redir END
+ call assert_match('E325: ATTENTION', editOutput)
+ call assert_match('file name: .*Xswaptest', editOutput)
+ call assert_match('process ID: \d* (STILL RUNNING)', editOutput)
+
+ " Forget we edited this file
+ new
+ only!
+ bwipe! Xswaptest
+
+ " pretend we rebooted
+ call test_override("uptime", 0)
+ sleep 1
+
+ call feedkeys('e', 'tL')
+ redir => editOutput
+ edit Xswaptest
+ redir END
+ call assert_match('E325: ATTENTION', editOutput)
+ call assert_notmatch('(STILL RUNNING)', editOutput)
+
+ call test_override("ALL", 0)
+ call delete(swname)
+endfunc
+
+" Test for :recover with multiple swap files
+func Test_recover_multiple_swap_files()
+ CheckUnix
+ new Xfile1
+ call setline(1, ['a', 'b', 'c'])
+ preserve
+ let b = readblob(swapname(''))
+ call writefile(b, '.Xfile1.swm')
+ call writefile(b, '.Xfile1.swn')
+ call writefile(b, '.Xfile1.swo')
+ %bw!
+ call feedkeys(":recover Xfile1\<CR>3\<CR>q", 'xt')
+ call assert_equal(['a', 'b', 'c'], getline(1, '$'))
+ " try using out-of-range number to select a swap file
+ bw!
+ call feedkeys(":recover Xfile1\<CR>4\<CR>q", 'xt')
+ call assert_equal('Xfile1', @%)
+ call assert_equal([''], getline(1, '$'))
+ bw!
+ call feedkeys(":recover Xfile1\<CR>0\<CR>q", 'xt')
+ call assert_equal('Xfile1', @%)
+ call assert_equal([''], getline(1, '$'))
+ bw!
+
+ call delete('.Xfile1.swm')
+ call delete('.Xfile1.swn')
+ call delete('.Xfile1.swo')
+endfunc
+
+" Test for :recover using an empty swap file
+func Test_recover_empty_swap_file()
+ CheckUnix
+ call writefile([], '.Xfile1.swp')
+ let msg = execute('recover Xfile1')
+ call assert_match('Unable to read block 0 from .Xfile1.swp', msg)
+ call assert_equal('Xfile1', @%)
+ bw!
+
+ " make sure there are no old swap files laying around
+ for f in glob('.sw?', 0, 1)
+ call delete(f)
+ endfor
+
+ " :recover from an empty buffer
+ call assert_fails('recover', 'E305:')
+ call delete('.Xfile1.swp')
+endfunc
+
+" Test for :recover using a corrupted swap file
+" Refer to the comments in the memline.c file for the swap file headers
+" definition.
+func Test_recover_corrupted_swap_file()
+ CheckUnix
+
+ " recover using a partial swap file
+ call writefile(0z1234, '.Xfile1.swp')
+ call assert_fails('recover Xfile1', 'E295:')
+ bw!
+
+ " recover using invalid content in the swap file
+ call writefile([repeat('1', 2*1024)], '.Xfile1.swp')
+ call assert_fails('recover Xfile1', 'E307:')
+ call delete('.Xfile1.swp')
+
+ " :recover using a swap file with a corrupted header
+ edit Xfile1
+ preserve
+ let sn = swapname('')
+ let b = readblob(sn)
+ let save_b = copy(b)
+ bw!
+
+ " Not all fields are written in a system-independent manner. Detect whether
+ " the test is running on a little or big-endian system, so the correct
+ " corruption values can be set.
+ " The B0_MAGIC_LONG field may be 32-bit or 64-bit, depending on the system,
+ " even though the value stored is only 32-bits. Therefore, need to check
+ " both the high and low 32-bits to compute these values.
+ let little_endian = (b[1008:1011] == 0z33323130) || (b[1012:1015] == 0z33323130)
+ let system_64bit = little_endian ? (b[1012:1015] == 0z00000000) : (b[1008:1011] == 0z00000000)
+
+ " clear the B0_MAGIC_LONG field
+ if system_64bit
+ let b[1008:1015] = 0z00000000.00000000
+ else
+ let b[1008:1011] = 0z00000000
+ endif
+ call writefile(b, sn)
+ let msg = execute('recover Xfile1')
+ call assert_match('the file has been damaged', msg)
+ call assert_equal('Xfile1', @%)
+ call assert_equal([''], getline(1, '$'))
+ bw!
+
+ " reduce the page size
+ let b = copy(save_b)
+ let b[12:15] = 0z00010000
+ call writefile(b, sn)
+ let msg = execute('recover Xfile1')
+ call assert_match('page size is smaller than minimum value', msg)
+ call assert_equal('Xfile1', @%)
+ call assert_equal([''], getline(1, '$'))
+ bw!
+
+ " clear the pointer ID
+ let b = copy(save_b)
+ let b[4096:4097] = 0z0000
+ call writefile(b, sn)
+ call assert_fails('recover Xfile1', 'E310:')
+ call assert_equal('Xfile1', @%)
+ call assert_equal([''], getline(1, '$'))
+ bw!
+
+ " set the number of pointers in a pointer block to zero
+ let b = copy(save_b)
+ let b[4098:4099] = 0z0000
+ call writefile(b, sn)
+ call assert_fails('recover Xfile1', 'E312:')
+ call assert_equal('Xfile1', @%)
+ call assert_equal(['???EMPTY BLOCK'], getline(1, '$'))
+ bw!
+
+ " set the block number in a pointer entry to a negative number
+ let b = copy(save_b)
+ if system_64bit
+ let b[4104:4111] = little_endian ? 0z00000000.00000080 : 0z80000000.00000000
+ else
+ let b[4104:4107] = little_endian ? 0z00000080 : 0z80000000
+ endif
+ call writefile(b, sn)
+ call assert_fails('recover Xfile1', 'E312:')
+ call assert_equal('Xfile1', @%)
+ call assert_equal(['???LINES MISSING'], getline(1, '$'))
+ bw!
+
+ " clear the data block ID
+ let b = copy(save_b)
+ let b[8192:8193] = 0z0000
+ call writefile(b, sn)
+ call assert_fails('recover Xfile1', 'E312:')
+ call assert_equal('Xfile1', @%)
+ call assert_equal(['???BLOCK MISSING'], getline(1, '$'))
+ bw!
+
+ " set the number of lines in the data block to zero
+ let b = copy(save_b)
+ if system_64bit
+ let b[8208:8215] = 0z00000000.00000000
+ else
+ let b[8208:8211] = 0z00000000
+ endif
+ call writefile(b, sn)
+ call assert_fails('recover Xfile1', 'E312:')
+ call assert_equal('Xfile1', @%)
+ call assert_equal(['??? from here until ???END lines may have been inserted/deleted',
+ \ '???END'], getline(1, '$'))
+ bw!
+
+ " use an invalid text start for the lines in a data block
+ let b = copy(save_b)
+ if system_64bit
+ let b[8216:8219] = 0z00000000
+ else
+ let b[8212:8215] = 0z00000000
+ endif
+ call writefile(b, sn)
+ call assert_fails('recover Xfile1', 'E312:')
+ call assert_equal('Xfile1', @%)
+ call assert_equal(['???'], getline(1, '$'))
+ bw!
+
+ " use an incorrect text end (db_txt_end) for the data block
+ let b = copy(save_b)
+ let b[8204:8207] = little_endian ? 0z80000000 : 0z00000080
+ call writefile(b, sn)
+ call assert_fails('recover Xfile1', 'E312:')
+ call assert_equal('Xfile1', @%)
+ call assert_equal(['??? from here until ???END lines may be messed up', '',
+ \ '???END'], getline(1, '$'))
+ bw!
+
+ " remove the data block
+ let b = copy(save_b)
+ call writefile(b[:8191], sn)
+ call assert_fails('recover Xfile1', 'E312:')
+ call assert_equal('Xfile1', @%)
+ call assert_equal(['???MANY LINES MISSING'], getline(1, '$'))
+
+ bw!
+ call delete(sn)
+endfunc
+
+" Test for :recover using an encrypted swap file
+func Test_recover_encrypted_swap_file()
+ CheckFeature cryptv
+ CheckUnix
+
+ " Recover an encrypted file from the swap file without the original file
+ new Xfile1
+ call feedkeys(":X\<CR>vim\<CR>vim\<CR>", 'xt')
+ call setline(1, ['aaa', 'bbb', 'ccc'])
+ preserve
+ let b = readblob('.Xfile1.swp')
+ call writefile(b, '.Xfile1.swm')
+ bw!
+ call feedkeys(":recover Xfile1\<CR>vim\<CR>\<CR>", 'xt')
+ call assert_equal(['aaa', 'bbb', 'ccc'], getline(1, '$'))
+ bw!
+ call delete('.Xfile1.swm')
+
+ " Recover an encrypted file from the swap file with the original file
+ new Xfile1
+ call feedkeys(":X\<CR>vim\<CR>vim\<CR>", 'xt')
+ call setline(1, ['aaa', 'bbb', 'ccc'])
+ update
+ call setline(1, ['111', '222', '333'])
+ preserve
+ let b = readblob('.Xfile1.swp')
+ call writefile(b, '.Xfile1.swm')
+ bw!
+ call feedkeys(":recover Xfile1\<CR>vim\<CR>\<CR>", 'xt')
+ call assert_equal(['111', '222', '333'], getline(1, '$'))
+ call assert_true(&modified)
+ bw!
+ call delete('.Xfile1.swm')
+ call delete('Xfile1')
+endfunc
+
+" Test for :recover using a unreadable swap file
+func Test_recover_unreadble_swap_file()
+ CheckUnix
+ CheckNotRoot
+ new Xfile1
+ let b = readblob('.Xfile1.swp')
+ call writefile(b, '.Xfile1.swm')
+ bw!
+ call setfperm('.Xfile1.swm', '-w-------')
+ call assert_fails('recover Xfile1', 'E306:')
+ call delete('.Xfile1.swm')
+endfunc
+
+" Test for using :recover when the original file and the swap file have the
+" same contents.
+func Test_recover_unmodified_file()
+ CheckUnix
+ call writefile(['aaa', 'bbb', 'ccc'], 'Xfile1')
+ edit Xfile1
+ preserve
+ let b = readblob('.Xfile1.swp')
+ %bw!
+ call writefile(b, '.Xfile1.swz')
+ let msg = execute('recover Xfile1')
+ call assert_equal(['aaa', 'bbb', 'ccc'], getline(1, '$'))
+ call assert_false(&modified)
+ call assert_match('Buffer contents equals file contents', msg)
+ bw!
+ call delete('Xfile1')
+ call delete('.Xfile1.swz')
+endfunc
+
+" Test for recovering a file when editing a symbolically linked file
+func Test_recover_symbolic_link()
+ CheckUnix
+ call writefile(['aaa', 'bbb', 'ccc'], 'Xfile1')
+ silent !ln -s Xfile1 Xfile2
+ edit Xfile2
+ call assert_equal('.Xfile1.swp', fnamemodify(swapname(''), ':t'))
+ preserve
+ let b = readblob('.Xfile1.swp')
+ %bw!
+ call writefile([], 'Xfile1')
+ call writefile(b, '.Xfile1.swp')
+ silent! recover Xfile2
+ call assert_equal(['aaa', 'bbb', 'ccc'], getline(1, '$'))
+ call assert_true(&modified)
+ update
+ %bw!
+ call assert_equal(['aaa', 'bbb', 'ccc'], readfile('Xfile1'))
+ call delete('Xfile1')
+ call delete('Xfile2')
+ call delete('.Xfile1.swp')
+endfunc
+
+" Test for recovering a file when an autocmd moves the cursor to an invalid
+" line. This used to result in an internal error (E315) which is fixed
+" by 8.2.2966.
+func Test_recover_invalid_cursor_pos()
+ call writefile([], 'Xfile1')
+ edit Xfile1
+ preserve
+ let b = readblob('.Xfile1.swp')
+ bw!
+ augroup Test
+ au!
+ au BufReadPost Xfile1 normal! 3G
+ augroup END
+ call writefile(range(1, 3), 'Xfile1')
+ call writefile(b, '.Xfile1.swp')
+ try
+ recover Xfile1
+ catch /E308:/
+ " this test is for the :E315 internal error.
+ " ignore the 'E308: Original file may have been changed' error
+ endtry
+ redraw!
+ augroup Test
+ au!
+ augroup END
+ augroup! Test
+ call delete('Xfile1')
+ call delete('.Xfile1.swp')
+endfunc
+
+" Test for recovering a buffer without a name
+func Test_noname_buffer()
+ new
+ call setline(1, ['one', 'two'])
+ preserve
+ let sn = swapname('')
+ let b = readblob(sn)
+ bw!
+ call writefile(b, sn)
+ exe "recover " .. sn
+ call assert_equal(['one', 'two'], getline(1, '$'))
+ call delete(sn)
+endfunc
+
+" vim: shiftwidth=2 sts=2 expandtab
diff --git a/src/nvim/testdir/test_regexp_latin.vim b/src/nvim/testdir/test_regexp_latin.vim
index d08a980787..ece6ae518e 100644
--- a/src/nvim/testdir/test_regexp_latin.vim
+++ b/src/nvim/testdir/test_regexp_latin.vim
@@ -101,8 +101,33 @@ func Test_multi_failure()
set re=2
call assert_fails('/a**', 'E871:')
call assert_fails('/a*\+', 'E871:')
- call assert_fails('/a\{a}', 'E870:')
+ call assert_fails('/a\{a}', 'E554:')
+ set re=0
+endfunc
+
+func Test_column_success_failure()
+ new
+ call setline(1, 'xbar')
+
+ set re=1
+ %s/\%>0v./A/
+ call assert_equal('Abar', getline(1))
+ call assert_fails('/\%v', 'E71:')
+ call assert_fails('/\%>v', 'E71:')
+ call assert_fails('/\%c', 'E71:')
+ call assert_fails('/\%<c', 'E71:')
+ call assert_fails('/\%l', 'E71:')
+ set re=2
+ %s/\%>0v./B/
+ call assert_equal('Bbar', getline(1))
+ call assert_fails('/\%v', 'E1273:')
+ call assert_fails('/\%>v', 'E1273:')
+ call assert_fails('/\%c', 'E1273:')
+ call assert_fails('/\%<c', 'E1273:')
+ call assert_fails('/\%l', 'E1273:')
+
set re=0
+ bwipe!
endfunc
func Test_recursive_addstate()
@@ -146,6 +171,10 @@ func Test_regexp_single_line_pat()
call add(tl, [2, 'c*', 'abdef', ''])
call add(tl, [2, 'bc\+', 'abccccdef', 'bcccc'])
call add(tl, [2, 'bc\+', 'abdef']) " no match
+ " match escape character in a string
+ call add(tl, [2, '.\e.', "one\<Esc>two", "e\<Esc>t"])
+ " match backspace character in a string
+ call add(tl, [2, '.\b.', "one\<C-H>two", "e\<C-H>t"])
" match newline character in a string
call add(tl, [2, 'o\nb', "foo\nbar", "o\nb"])
@@ -895,6 +924,8 @@ func Test_regexp_error()
call assert_fails("call matchlist('x x', '\\%#=2 \\zs*')", 'E888:')
call assert_fails("call matchlist('x x', '\\%#=2 \\ze*')", 'E888:')
call assert_fails('exe "normal /\\%#=1\\%[x\\%[x]]\<CR>"', 'E369:')
+ call assert_fails("call matchstr('abcd', '\\%o841\\%o142')", 'E678:')
+ call assert_equal('', matchstr('abcd', '\%o181\%o142'))
endfunc
" Test for using the last substitute string pattern (~)
@@ -1027,6 +1058,28 @@ func Test_using_invalid_visual_position()
bwipe!
endfunc
+func Test_using_two_engines_pattern()
+ new
+ call setline(1, ['foobar=0', 'foobar=1', 'foobar=2'])
+ " \%#= at the end of the pattern
+ for i in range(0, 2)
+ for j in range(0, 2)
+ exe "set re=" .. i
+ call cursor(j + 1, 7)
+ call assert_fails("%s/foobar\\%#=" .. j, 'E1281:')
+ endfor
+ endfor
+ set re=0
+
+ " \%#= at the start of the pattern
+ for i in range(0, 2)
+ call cursor(i + 1, 7)
+ exe ":%s/\\%#=" .. i .. "foobar=" .. i .. "/xx"
+ endfor
+ call assert_equal(['xx', 'xx', 'xx'], getline(1, '$'))
+ bwipe!
+endfunc
+
func Test_recursive_substitute_expr()
new
func Repl()
diff --git a/src/nvim/testdir/test_regexp_utf8.vim b/src/nvim/testdir/test_regexp_utf8.vim
index 14b9724d67..2253242a7c 100644
--- a/src/nvim/testdir/test_regexp_utf8.vim
+++ b/src/nvim/testdir/test_regexp_utf8.vim
@@ -258,8 +258,7 @@ func Test_multibyte_chars()
" When there is no match use only the first two items.
let tl = []
- " Multi-byte character tests. These will fail unless vim is compiled
- " with Multibyte (FEAT_MBYTE) or BIG/HUGE features.
+ " Multi-byte character tests.
call add(tl, [2, '[[:alpha:][=a=]]\+', '879 aiaãâaiuvna ', 'aiaãâaiuvna'])
call add(tl, [2, '[[=a=]]\+', 'ddaãâbcd', 'aãâ']) " equivalence classes
call add(tl, [2, '[^ม ]\+', 'มม oijasoifjos ifjoisj f osij j มมมมม abcd', 'oijasoifjos'])
diff --git a/src/nvim/testdir/test_registers.vim b/src/nvim/testdir/test_registers.vim
index 11dd3badb6..bbf1aa53b5 100644
--- a/src/nvim/testdir/test_registers.vim
+++ b/src/nvim/testdir/test_registers.vim
@@ -263,8 +263,16 @@ func Test_get_register()
call assert_equal('', getreg("\<C-F>"))
call assert_equal('', getreg("\<C-W>"))
call assert_equal('', getreg("\<C-L>"))
+ " Change the last used register to '"' for the next test
+ normal! ""yy
+ let @" = 'happy'
+ call assert_equal('happy', getreg())
+ call assert_equal('happy', getreg(''))
call assert_equal('', getregtype('!'))
+ call assert_fails('echo getregtype([])', 'E730:')
+ call assert_equal('v', getregtype())
+ call assert_equal('v', getregtype(''))
" Test for inserting an invalid register content
call assert_beeps('exe "normal i\<C-R>!"')
@@ -277,7 +285,9 @@ func Test_get_register()
" Test for inserting a multi-line register in the command line
call feedkeys(":\<C-R>r\<Esc>", 'xt')
- call assert_equal("a\rb", histget(':', -1)) " Modified because of #6137
+ " Nvim: no trailing CR because of #6137
+ " call assert_equal("a\rb\r", histget(':', -1))
+ call assert_equal("a\rb", histget(':', -1))
call assert_fails('let r = getreg("=", [])', 'E745:')
call assert_fails('let r = getreg("=", 1, [])', 'E745:')
@@ -289,6 +299,7 @@ endfunc
func Test_set_register()
call assert_fails("call setreg('#', 200)", 'E86:')
+ " call assert_fails("call setreg('a', test_unknown())", 'E908:')
edit Xfile_alt_1
let b1 = bufnr('')
@@ -349,6 +360,12 @@ func Test_set_register()
normal 0".gP
call assert_equal('abcabcabc', getline(1))
+ let @"=''
+ call setreg('', '1')
+ call assert_equal('1', @")
+ call setreg('@', '2')
+ call assert_equal('2', @")
+
enew!
endfunc
@@ -474,6 +491,21 @@ func Test_get_reginfo()
let info = getreginfo('"')
call assert_equal('z', info.points_to)
+ let @a="a1b2"
+ nnoremap <F2> <Cmd>let g:RegInfo = getreginfo()<CR>
+ exe "normal \"a\<F2>"
+ call assert_equal({'regcontents': ['a1b2'], 'isunnamed': v:false,
+ \ 'regtype': 'v'}, g:RegInfo)
+ nunmap <F2>
+ unlet g:RegInfo
+
+ " The type of "isunnamed" was VAR_SPECIAL but should be VAR_BOOL. Can only
+ " be noticed when using json_encod().
+ call setreg('a', 'foo')
+ let reginfo = getreginfo('a')
+ let expected = #{regcontents: ['foo'], isunnamed: v:false, regtype: 'v'}
+ call assert_equal(json_encode(expected), json_encode(reginfo))
+
bwipe!
endfunc
diff --git a/src/nvim/testdir/test_reltime.vim b/src/nvim/testdir/test_reltime.vim
index b381f1ddbb..f4ce5de118 100644
--- a/src/nvim/testdir/test_reltime.vim
+++ b/src/nvim/testdir/test_reltime.vim
@@ -24,4 +24,8 @@ func Test_reltime()
call assert_true(reltimefloat(differs) < 0.1)
call assert_true(reltimefloat(differs) > 0.0)
+ call assert_equal(0, reltime({}))
+ call assert_equal(0, reltime({}, {}))
endfunc
+
+" vim: shiftwidth=2 sts=2 expandtab
diff --git a/src/nvim/testdir/test_retab.vim b/src/nvim/testdir/test_retab.vim
index 1650a03876..a4f95053c0 100644
--- a/src/nvim/testdir/test_retab.vim
+++ b/src/nvim/testdir/test_retab.vim
@@ -1,4 +1,7 @@
" Test :retab
+
+source check.vim
+
func SetUp()
new
call setline(1, "\ta \t b c ")
@@ -81,19 +84,32 @@ func Test_retab_error()
call assert_fails('ret 80000000000000000000', 'E475:')
endfunc
+func RetabLoop()
+ while 1
+ set ts=4000
+ retab 4
+ endwhile
+endfunc
+
func Test_retab_endless()
- new
+ " inside try/catch we can catch the error message
call setline(1, "\t0\t")
let caught = 'no'
try
- while 1
- set ts=4000
- retab 4
- endwhile
- catch /E1240/
- let caught = 'yes'
+ call RetabLoop()
+ catch /E1240:/
+ let caught = v:exception
endtry
- bwipe!
+ call assert_match('E1240:', caught)
+
+ set tabstop&
+endfunc
+
+func Test_nocatch_retab_endless()
+ " when not inside try/catch an interrupt is generated to get out of loops
+ call setline(1, "\t0\t")
+ call assert_fails('call RetabLoop()', ['E1240:', 'Interrupted'])
+
set tabstop&
endfunc
diff --git a/src/nvim/testdir/test_search.vim b/src/nvim/testdir/test_search.vim
index 3d1bbfb726..885043accf 100644
--- a/src/nvim/testdir/test_search.vim
+++ b/src/nvim/testdir/test_search.vim
@@ -294,6 +294,9 @@ func Test_searchpair()
new
call setline(1, ['other code', 'here [', ' [', ' " cursor here', ' ]]'])
+ " should not give an error for using "42"
+ call assert_equal(0, searchpair('a', 'b', 'c', '', 42))
+
4
call assert_equal(3, searchpair('\[', '', ']', 'bW'))
call assert_equal([0, 3, 2, 0], getpos('.'))
@@ -897,9 +900,7 @@ func Test_incsearch_cmdline_modifier()
endfunc
func Test_incsearch_scrolling()
- if !CanRunVimInTerminal()
- throw 'Skipped: cannot make screendumps'
- endif
+ CheckRunVimInTerminal
call assert_equal(0, &scrolloff)
call writefile([
\ 'let dots = repeat(".", 120)',
@@ -956,24 +957,24 @@ func Test_incsearch_search_dump()
call delete('Xis_search_script')
endfunc
-func Test_hlsearch_block_visual_match()
+func Test_hlsearch_dump()
+ CheckOption hlsearch
CheckScreendump
- let lines =<< trim END
- set hlsearch
- call setline(1, ['aa', 'bbbb', 'cccccc'])
- END
- call writefile(lines, 'Xhlsearch_block')
- let buf = RunVimInTerminal('-S Xhlsearch_block', {'rows': 9, 'cols': 60})
+ call writefile([
+ \ 'set hlsearch cursorline',
+ \ 'call setline(1, ["xxx", "xxx", "xxx"])',
+ \ '/.*',
+ \ '2',
+ \ ], 'Xhlsearch_script')
+ let buf = RunVimInTerminal('-S Xhlsearch_script', {'rows': 6, 'cols': 50})
+ call VerifyScreenDump(buf, 'Test_hlsearch_1', {})
- call term_sendkeys(buf, "G\<C-V>$kk\<Esc>")
- sleep 100m
- call term_sendkeys(buf, "/\\%V\<CR>")
- sleep 100m
- call VerifyScreenDump(buf, 'Test_hlsearch_block_visual_match', {})
+ call term_sendkeys(buf, "/\\_.*\<CR>")
+ call VerifyScreenDump(buf, 'Test_hlsearch_2', {})
call StopVimInTerminal(buf)
- call delete('Xhlsearch_block')
+ call delete('Xhlsearch_script')
endfunc
func Test_hlsearch_and_visual()
@@ -996,6 +997,26 @@ func Test_hlsearch_and_visual()
call delete('Xhlvisual_script')
endfunc
+func Test_hlsearch_block_visual_match()
+ CheckScreendump
+
+ let lines =<< trim END
+ set hlsearch
+ call setline(1, ['aa', 'bbbb', 'cccccc'])
+ END
+ call writefile(lines, 'Xhlsearch_block')
+ let buf = RunVimInTerminal('-S Xhlsearch_block', {'rows': 9, 'cols': 60})
+
+ call term_sendkeys(buf, "G\<C-V>$kk\<Esc>")
+ sleep 100m
+ call term_sendkeys(buf, "/\\%V\<CR>")
+ sleep 100m
+ call VerifyScreenDump(buf, 'Test_hlsearch_block_visual_match', {})
+
+ call StopVimInTerminal(buf)
+ call delete('Xhlsearch_block')
+endfunc
+
func Test_incsearch_substitute()
CheckFunction test_override
CheckOption incsearch
@@ -1017,6 +1038,21 @@ func Test_incsearch_substitute()
call Incsearch_cleanup()
endfunc
+func Test_incsearch_substitute_long_line()
+ CheckFunction test_override
+ new
+ call test_override("char_avail", 1)
+ set incsearch
+
+ call repeat('x', 100000)->setline(1)
+ call feedkeys(':s/\%c', 'xt')
+ redraw
+ call feedkeys("\<Esc>", 'xt')
+
+ call Incsearch_cleanup()
+ bwipe!
+endfunc
+
func Test_hlsearch_cursearch()
CheckScreendump
@@ -1341,18 +1377,19 @@ func Test_subst_word_under_cursor()
set noincsearch
endfunc
-func Test_incsearch_substitute_long_line()
- CheckFunction test_override
- new
- call test_override("char_avail", 1)
- set incsearch
-
- call repeat('x', 100000)->setline(1)
- call feedkeys(':s/\%c', 'xt')
- redraw
- call feedkeys("\<Esc>", 'xt')
+func Test_search_skip_all_matches()
+ enew
+ call setline(1, ['no match here',
+ \ 'match this line',
+ \ 'nope',
+ \ 'match in this line',
+ \ 'last line',
+ \ ])
+ call cursor(1, 1)
+ let lnum = search('this', '', 0, 0, 'getline(".") =~ "this line"')
+ " Only check that no match is found. Previously it searched forever.
+ call assert_equal(0, lnum)
- call Incsearch_cleanup()
bwipe!
endfunc
@@ -1629,8 +1666,8 @@ func Test_search_with_no_last_pat()
call assert_fails(";//p", 'E35:')
call assert_fails("??p", 'E35:')
call assert_fails(";??p", 'E35:')
- call assert_fails('g//p', 'E476:')
- call assert_fails('v//p', 'E476:')
+ call assert_fails('g//p', ['E35:', 'E476:'])
+ call assert_fails('v//p', ['E35:', 'E476:'])
call writefile(v:errors, 'Xresult')
qall!
[SCRIPT]
@@ -1651,8 +1688,8 @@ func Test_search_tilde_pat()
call assert_fails('exe "normal /~\<CR>"', 'E33:')
call assert_fails('exe "normal ?~\<CR>"', 'E33:')
set regexpengine=2
- call assert_fails('exe "normal /~\<CR>"', 'E383:')
- call assert_fails('exe "normal ?~\<CR>"', 'E383:')
+ call assert_fails('exe "normal /~\<CR>"', ['E33:', 'E383:'])
+ call assert_fails('exe "normal ?~\<CR>"', ['E33:', 'E383:'])
set regexpengine&
call writefile(v:errors, 'Xresult')
qall!
@@ -1732,6 +1769,25 @@ func Test_invalid_regexp()
call assert_fails("call search('\\%#=3ab')", 'E864:')
endfunc
+" Test for searching a very complex pattern in a string. Should switch the
+" regexp engine from NFA to the old engine.
+func Test_regexp_switch_engine()
+ let l = readfile('samples/re.freeze.txt')
+ let v = substitute(l[4], '..\@<!', '', '')
+ call assert_equal(l[4], v)
+endfunc
+
+" Test for the \%V atom to search within visually selected text
+func Test_search_in_visual_area()
+ new
+ call setline(1, ['foo bar1', 'foo bar2', 'foo bar3', 'foo bar4'])
+ exe "normal 2GVjo/\\%Vbar\<CR>\<Esc>"
+ call assert_equal([2, 5], [line('.'), col('.')])
+ exe "normal 2GVj$?\\%Vbar\<CR>\<Esc>"
+ call assert_equal([3, 5], [line('.'), col('.')])
+ close!
+endfunc
+
" Test for searching with 'smartcase' and 'ignorecase'
func Test_search_smartcase()
new
@@ -1776,7 +1832,7 @@ func Test_search_smartcase_utf8()
set ignorecase& smartcase&
let &encoding = save_enc
- close!
+ bwipe!
endfunc
" Test searching past the end of a file
@@ -1785,7 +1841,29 @@ func Test_search_past_eof()
call setline(1, ['Line'])
exe "normal /\\n\\zs\<CR>"
call assert_equal([1, 4], [line('.'), col('.')])
- close!
+ bwipe!
+endfunc
+
+" Test setting the start of the match and still finding a next match in the
+" same line.
+func Test_search_set_start_same_line()
+ new
+ set cpo-=c
+
+ call setline(1, ['1', '2', '3 .', '4', '5'])
+ exe "normal /\\_s\\zs\\S\<CR>"
+ call assert_equal([2, 1], [line('.'), col('.')])
+ exe 'normal n'
+ call assert_equal([3, 1], [line('.'), col('.')])
+ exe 'normal n'
+ call assert_equal([3, 3], [line('.'), col('.')])
+ exe 'normal n'
+ call assert_equal([4, 1], [line('.'), col('.')])
+ exe 'normal n'
+ call assert_equal([5, 1], [line('.'), col('.')])
+
+ set cpo+=c
+ bwipe!
endfunc
" Test for various search offsets
@@ -1907,6 +1985,100 @@ func Test_incsearch_highlighting_newline()
bw
endfunc
+func Test_incsearch_substitute_dump2()
+ CheckOption incsearch
+ CheckScreendump
+
+ call writefile([
+ \ 'set incsearch hlsearch scrolloff=0',
+ \ 'for n in range(1, 4)',
+ \ ' call setline(n, "foo " . n)',
+ \ 'endfor',
+ \ 'call setline(5, "abc|def")',
+ \ '3',
+ \ ], 'Xis_subst_script2')
+ let buf = RunVimInTerminal('-S Xis_subst_script2', {'rows': 9, 'cols': 70})
+
+ call term_sendkeys(buf, ':%s/\vabc|')
+ sleep 100m
+ call VerifyScreenDump(buf, 'Test_incsearch_sub_01', {})
+ call term_sendkeys(buf, "\<Esc>")
+
+ " The following should not be highlighted
+ call term_sendkeys(buf, ':1,5s/\v|')
+ sleep 100m
+ call VerifyScreenDump(buf, 'Test_incsearch_sub_02', {})
+
+
+ call StopVimInTerminal(buf)
+ call delete('Xis_subst_script2')
+endfunc
+
+func Test_pattern_is_uppercase_smartcase()
+ new
+ let input=['abc', 'ABC', 'Abc', 'abC']
+ call setline(1, input)
+ call cursor(1,1)
+ " default, matches firstline
+ %s/abc//g
+ call assert_equal(['', 'ABC', 'Abc', 'abC'],
+ \ getline(1, '$'))
+
+ set smartcase ignorecase
+ sil %d
+ call setline(1, input)
+ call cursor(1,1)
+ " with smartcase and incsearch set, matches everything
+ %s/abc//g
+ call assert_equal(['', '', '', ''], getline(1, '$'))
+
+ sil %d
+ call setline(1, input)
+ call cursor(1,1)
+ " with smartcase and incsearch set and found an uppercase letter,
+ " match only that.
+ %s/abC//g
+ call assert_equal(['abc', 'ABC', 'Abc', ''],
+ \ getline(1, '$'))
+
+ sil %d
+ call setline(1, input)
+ call cursor(1,1)
+ exe "norm! vG$\<esc>"
+ " \%V should not be detected as uppercase letter
+ %s/\%Vabc//g
+ call assert_equal(['', '', '', ''], getline(1, '$'))
+
+ call setline(1, input)
+ call cursor(1,1)
+ exe "norm! vG$\<esc>"
+ " \v%V should not be detected as uppercase letter
+ %s/\v%Vabc//g
+ call assert_equal(['', '', '', ''], getline(1, '$'))
+
+ call setline(1, input)
+ call cursor(1,1)
+ exe "norm! vG$\<esc>"
+ " \v%VabC should be detected as uppercase letter
+ %s/\v%VabC//g
+ call assert_equal(['abc', 'ABC', 'Abc', ''],
+ \ getline(1, '$'))
+
+ call setline(1, input)
+ call cursor(1,1)
+ " \Vabc should match everything
+ %s/\Vabc//g
+ call assert_equal(['', '', '', ''], getline(1, '$'))
+
+ call setline(1, input + ['_abc'])
+ " _ matches normally
+ %s/\v_.*//g
+ call assert_equal(['abc', 'ABC', 'Abc', 'abC', ''], getline(1, '$'))
+
+ set smartcase& ignorecase&
+ bw!
+endfunc
+
func Test_no_last_search_pattern()
CheckOption incsearch
diff --git a/src/nvim/testdir/test_search_stat.vim b/src/nvim/testdir/test_search_stat.vim
index 89e09cf85b..77bd50ada2 100644
--- a/src/nvim/testdir/test_search_stat.vim
+++ b/src/nvim/testdir/test_search_stat.vim
@@ -260,6 +260,14 @@ endfunc
func Test_searchcount_fails()
call assert_fails('echo searchcount("boo!")', 'E715:')
+ call assert_fails('echo searchcount({"timeout" : []})', 'E745:')
+ call assert_fails('echo searchcount({"maxcount" : []})', 'E745:')
+ call assert_fails('echo searchcount({"pattern" : []})', 'E730:')
+ call assert_fails('echo searchcount({"pos" : 1})', 'E475:')
+ call assert_fails('echo searchcount({"pos" : [1]})', 'E475:')
+ call assert_fails('echo searchcount({"pos" : [[], 2, 3]})', 'E745:')
+ call assert_fails('echo searchcount({"pos" : [1, [], 3]})', 'E745:')
+ call assert_fails('echo searchcount({"pos" : [1, 2, []]})', 'E745:')
endfunc
func Test_searchcount_in_statusline()
diff --git a/src/nvim/testdir/test_selectmode.vim b/src/nvim/testdir/test_selectmode.vim
index f2cab45450..041f0592f1 100644
--- a/src/nvim/testdir/test_selectmode.vim
+++ b/src/nvim/testdir/test_selectmode.vim
@@ -34,6 +34,9 @@ func Test_selectmode_start()
set selectmode=cmd
call feedkeys('gvabc', 'xt')
call assert_equal('abctdef', getline(1))
+ " arrow keys without shift should not start selection
+ call feedkeys("A\<Home>\<Right>\<Left>ro", 'xt')
+ call assert_equal('roabctdef', getline(1))
set selectmode= keymodel=
bw!
endfunc
diff --git a/src/nvim/testdir/test_set.vim b/src/nvim/testdir/test_set.vim
index 2b1e9eeee0..7215772a00 100644
--- a/src/nvim/testdir/test_set.vim
+++ b/src/nvim/testdir/test_set.vim
@@ -26,4 +26,23 @@ function Test_set_add()
let &wig = wig_save
endfunction
+
+" :set, :setlocal, :setglobal without arguments show values of options.
+func Test_set_no_arg()
+ set textwidth=79
+ let a = execute('set')
+ call assert_match("^\n--- Options ---\n.*textwidth=79\\>", a)
+ set textwidth&
+
+ setlocal textwidth=78
+ let a = execute('setlocal')
+ call assert_match("^\n--- Local option values ---\n.*textwidth=78\\>", a)
+ setlocal textwidth&
+
+ setglobal textwidth=77
+ let a = execute('setglobal')
+ call assert_match("^\n--- Global option values ---\n.*textwidth=77\\>", a)
+ setglobal textwidth&
+endfunc
+
" vim: shiftwidth=2 sts=2 expandtab
diff --git a/src/nvim/testdir/test_shell.vim b/src/nvim/testdir/test_shell.vim
new file mode 100644
index 0000000000..8b9c7a5b12
--- /dev/null
+++ b/src/nvim/testdir/test_shell.vim
@@ -0,0 +1,209 @@
+" Test for the shell related options ('shell', 'shellcmdflag', 'shellpipe',
+" 'shellquote', 'shellredir', 'shellxescape', and 'shellxquote')
+
+source check.vim
+source shared.vim
+
+func Test_shell_options()
+ " The expected value of 'shellcmdflag', 'shellpipe', 'shellquote',
+ " 'shellredir', 'shellxescape', 'shellxquote' for the supported shells.
+ let shells = []
+ if has('unix')
+ let shells += [['sh', '-c', '2>&1| tee', '', '>%s 2>&1', '', ''],
+ \ ['ksh', '-c', '2>&1| tee', '', '>%s 2>&1', '', ''],
+ \ ['mksh', '-c', '2>&1| tee', '', '>%s 2>&1', '', ''],
+ \ ['zsh', '-c', '2>&1| tee', '', '>%s 2>&1', '', ''],
+ \ ['zsh-beta', '-c', '2>&1| tee', '', '>%s 2>&1', '', ''],
+ \ ['bash', '-c', '2>&1| tee', '', '>%s 2>&1', '', ''],
+ \ ['fish', '-c', '2>&1| tee', '', '>%s 2>&1', '', ''],
+ \ ['ash', '-c', '2>&1| tee', '', '>%s 2>&1', '', ''],
+ \ ['dash', '-c', '2>&1| tee', '', '>%s 2>&1', '', ''],
+ \ ['csh', '-c', '|& tee', '', '>&', '', ''],
+ \ ['tcsh', '-c', '|& tee', '', '>&', '', '']]
+ endif
+ if has('win32')
+ let shells += [['cmd', '/s /c', '>%s 2>&1', '', '>%s 2>&1', '', '"']]
+ endif
+
+ " start a new Vim instance with 'shell' set to each of the supported shells
+ " and check the default shell option settings
+ let after =<< trim END
+ let l = [&shell, &shellcmdflag, &shellpipe, &shellquote]
+ let l += [&shellredir, &shellxescape, &shellxquote]
+ call writefile([json_encode(l)], 'Xtestout')
+ qall!
+ END
+ for e in shells
+ if RunVim([], after, '--cmd "set shell=' .. e[0] .. '"')
+ call assert_equal(e, json_decode(readfile('Xtestout')[0]))
+ endif
+ endfor
+
+ " Test shellescape() for each of the shells.
+ for e in shells
+ exe 'set shell=' .. e[0]
+ if e[0] =~# '.*csh$' || e[0] =~# '.*csh.exe$'
+ let str1 = "'cmd \"arg1\" '\\''arg2'\\'' \\!%#'"
+ let str2 = "'cmd \"arg1\" '\\''arg2'\\'' \\\\!\\%\\#'"
+ elseif e[0] =~# '.*powershell$' || e[0] =~# '.*powershell.exe$'
+ let str1 = "'cmd \"arg1\" ''arg2'' !%#'"
+ let str2 = "'cmd \"arg1\" ''arg2'' \\!\\%\\#'"
+ else
+ let str1 = "'cmd \"arg1\" '\\''arg2'\\'' !%#'"
+ let str2 = "'cmd \"arg1\" '\\''arg2'\\'' \\!\\%\\#'"
+ endif
+ call assert_equal(str1, shellescape("cmd \"arg1\" 'arg2' !%#"), e[0])
+ call assert_equal(str2, shellescape("cmd \"arg1\" 'arg2' !%#", 1), e[0])
+
+ " Try running an external command with the shell.
+ if executable(e[0])
+ " set the shell options for the current 'shell'
+ let [&shellcmdflag, &shellpipe, &shellquote, &shellredir,
+ \ &shellxescape, &shellxquote] = e[1:6]
+ new
+ r !echo hello
+ call assert_equal('hello', substitute(getline(2), '\W', '', 'g'), e[0])
+ bwipe!
+ endif
+ endfor
+ set shell& shellcmdflag& shellpipe& shellquote&
+ set shellredir& shellxescape& shellxquote&
+ call delete('Xtestout')
+endfunc
+
+" Test for the 'shell' option
+func Test_shell()
+ throw 'Skipped: Nvim missing :shell currently'
+ CheckUnix
+ let save_shell = &shell
+ set shell=
+ let caught_e91 = 0
+ try
+ shell
+ catch /E91:/
+ let caught_e91 = 1
+ endtry
+ call assert_equal(1, caught_e91)
+ let &shell = save_shell
+endfunc
+
+" Test for the 'shellquote' option
+func Test_shellquote()
+ CheckUnix
+ set shellquote=#
+ set verbose=20
+ redir => v
+ silent! !echo Hello
+ redir END
+ set verbose&
+ set shellquote&
+ call assert_match(': "#echo Hello#"', v)
+endfunc
+
+" Test for the 'shellescape' option
+func Test_shellescape()
+ let save_shell = &shell
+ set shell=bash
+ call assert_equal("'text'", shellescape('text'))
+ call assert_equal("'te\"xt'", 'te"xt'->shellescape())
+ call assert_equal("'te'\\''xt'", shellescape("te'xt"))
+
+ call assert_equal("'te%xt'", shellescape("te%xt"))
+ call assert_equal("'te\\%xt'", shellescape("te%xt", 1))
+ call assert_equal("'te#xt'", shellescape("te#xt"))
+ call assert_equal("'te\\#xt'", shellescape("te#xt", 1))
+ call assert_equal("'te!xt'", shellescape("te!xt"))
+ call assert_equal("'te\\!xt'", shellescape("te!xt", 1))
+
+ call assert_equal("'te\nxt'", shellescape("te\nxt"))
+ call assert_equal("'te\\\nxt'", shellescape("te\nxt", 1))
+ set shell=tcsh
+ call assert_equal("'te\\!xt'", shellescape("te!xt"))
+ call assert_equal("'te\\\\!xt'", shellescape("te!xt", 1))
+ call assert_equal("'te\\\nxt'", shellescape("te\nxt"))
+ call assert_equal("'te\\\\\nxt'", shellescape("te\nxt", 1))
+
+ let &shell = save_shell
+endfunc
+
+" Test for 'shellslash'
+func Test_shellslash()
+ CheckOption shellslash
+ let save_shellslash = &shellslash
+ " The shell and cmdflag, and expected slash in tempname with shellslash set or
+ " unset. The assert checks the file separator before the leafname.
+ " ".*\\\\[^\\\\]*$"
+ let shells = [['cmd', '/c', '/', '/'],
+ \ ['powershell', '-Command', '/', '/'],
+ \ ['sh', '-c', '/', '/']]
+ for e in shells
+ exe 'set shell=' .. e[0] .. ' | set shellcmdflag=' .. e[1]
+ set noshellslash
+ let file = tempname()
+ call assert_match('^.\+' .. e[2] .. '[^' .. e[2] .. ']\+$', file, e[0] .. ' ' .. e[1] .. ' nossl')
+ set shellslash
+ let file = tempname()
+ call assert_match('^.\+' .. e[3] .. '[^' .. e[3] .. ']\+$', file, e[0] .. ' ' .. e[1] .. ' ssl')
+ endfor
+ let &shellslash = save_shellslash
+endfunc
+
+" Test for 'shellxquote'
+func Test_shellxquote()
+ CheckUnix
+
+ let save_shell = &shell
+ let save_sxq = &shellxquote
+ let save_sxe = &shellxescape
+
+ call writefile(['#!/bin/sh', 'echo "Cmd: [$*]" > Xlog'], 'Xtestshell')
+ call setfperm('Xtestshell', "r-x------")
+ set shell=./Xtestshell
+
+ set shellxquote=\\"
+ call feedkeys(":!pwd\<CR>\<CR>", 'xt')
+ call assert_equal(['Cmd: [-c "pwd"]'], readfile('Xlog'))
+
+ set shellxquote=(
+ call feedkeys(":!pwd\<CR>\<CR>", 'xt')
+ call assert_equal(['Cmd: [-c (pwd)]'], readfile('Xlog'))
+
+ set shellxquote=\\"(
+ call feedkeys(":!pwd\<CR>\<CR>", 'xt')
+ call assert_equal(['Cmd: [-c "(pwd)"]'], readfile('Xlog'))
+
+ set shellxescape=\"&<<()@^
+ set shellxquote=(
+ call feedkeys(":!pwd\"&<<{}@^\<CR>\<CR>", 'xt')
+ call assert_equal(['Cmd: [-c (pwd^"^&^<^<{}^@^^)]'], readfile('Xlog'))
+
+ let &shell = save_shell
+ let &shellxquote = save_sxq
+ let &shellxescape = save_sxe
+ call delete('Xtestshell')
+ call delete('Xlog')
+endfunc
+
+" Test for using the shell set in the $SHELL environment variable
+func Test_set_shell()
+ let after =<< trim [CODE]
+ call writefile([&shell], "Xtestout")
+ quit!
+ [CODE]
+
+ if has('win32')
+ let $SHELL = 'C:\with space\cmd.exe'
+ let expected = '"C:\with space\cmd.exe"'
+ else
+ let $SHELL = '/bin/with space/sh'
+ let expected = '"/bin/with space/sh"'
+ endif
+
+ if RunVimPiped([], after, '', '')
+ let lines = readfile('Xtestout')
+ call assert_equal(expected, lines[0])
+ endif
+ call delete('Xtestout')
+endfunc
+
+" vim: shiftwidth=2 sts=2 expandtab
diff --git a/src/nvim/testdir/test_signals.vim b/src/nvim/testdir/test_signals.vim
index 338c0d79ff..c291c68e0d 100644
--- a/src/nvim/testdir/test_signals.vim
+++ b/src/nvim/testdir/test_signals.vim
@@ -16,8 +16,9 @@ endfunc
" Test signal WINCH (window resize signal)
func Test_signal_WINCH()
throw 'skipped: Nvim cannot avoid terminal resize'
- if has('gui_running') || !HasSignal('WINCH')
- return
+ CheckNotGui
+ if !HasSignal('WINCH')
+ throw 'Skipped: WINCH signal not supported'
endif
" We do not actually want to change the size of the terminal.
@@ -52,7 +53,7 @@ endfunc
" Test signal PWR, which should update the swap file.
func Test_signal_PWR()
if !HasSignal('PWR')
- return
+ throw 'Skipped: PWR signal not supported'
endif
" Set a very large 'updatetime' and 'updatecount', so that we can be sure
@@ -78,6 +79,33 @@ func Test_signal_PWR()
set updatetime& updatecount&
endfunc
+" Test signal INT. Handler sets got_int. It should be like typing CTRL-C.
+func Test_signal_INT()
+ CheckRunVimInTerminal
+ if !HasSignal('INT')
+ throw 'Skipped: INT signal not supported'
+ endif
+
+ " Skip the rest of the test when running with valgrind as signal INT is not
+ " received somehow by Vim when running with valgrind.
+ let cmd = GetVimCommand()
+ if cmd =~ 'valgrind'
+ throw 'Skipped: cannot test signal INT with valgrind'
+ endif
+
+ let buf = RunVimInTerminal('', {'rows': 6})
+ let pid_vim = term_getjob(buf)->job_info().process
+
+ " Check that an endless loop in Vim is interrupted by signal INT.
+ call term_sendkeys(buf, ":while 1 | endwhile\n")
+ call WaitForAssert({-> assert_equal(':while 1 | endwhile', term_getline(buf, 6))})
+ exe 'silent !kill -s INT ' .. pid_vim
+ call term_sendkeys(buf, ":call setline(1, 'INTERUPTED')\n")
+ call WaitForAssert({-> assert_equal('INTERUPTED', term_getline(buf, 1))})
+
+ call StopVimInTerminal(buf)
+endfunc
+
" Test a deadly signal.
"
" There are several deadly signals: SISEGV, SIBUS, SIGTERM...
@@ -91,9 +119,7 @@ func Test_deadly_signal_TERM()
if !HasSignal('TERM')
throw 'Skipped: TERM signal not supported'
endif
- if !CanRunVimInTerminal()
- throw 'Skipped: cannot run vim in terminal'
- endif
+ CheckRunVimInTerminal
let cmd = GetVimCommand()
if cmd =~ 'valgrind'
throw 'Skipped: cannot test signal TERM with valgrind'
@@ -128,8 +154,7 @@ func Test_deadly_signal_TERM()
call assert_equal(['foo'], getline(1, '$'))
let result = readfile('XautoOut')
- call assert_match('VimLeavePre triggered', result[0])
- call assert_match('VimLeave triggered', result[1])
+ call assert_equal(["VimLeavePre triggered", "VimLeave triggered"], result)
%bwipe!
call delete('.Xsig_TERM.swp')
diff --git a/src/nvim/testdir/test_signs.vim b/src/nvim/testdir/test_signs.vim
index ff9ba3d8ed..8311955a15 100644
--- a/src/nvim/testdir/test_signs.vim
+++ b/src/nvim/testdir/test_signs.vim
@@ -15,13 +15,13 @@ func Test_sign()
" the icon name when listing signs.
sign define Sign1 text=x
- call Sign_command_ignore_error('sign define Sign2 text=xy texthl=Title linehl=Error culhl=Search icon=../../pixmaps/stock_vim_find_help.png')
+ call Sign_command_ignore_error('sign define Sign2 text=xy texthl=Title linehl=Error culhl=Search numhl=Number icon=../../pixmaps/stock_vim_find_help.png')
" Test listing signs.
let a=execute('sign list')
call assert_match('^\nsign Sign1 text=x \nsign Sign2 ' .
\ 'icon=../../pixmaps/stock_vim_find_help.png .*text=xy ' .
- \ 'linehl=Error texthl=Title culhl=Search$', a)
+ \ 'linehl=Error texthl=Title culhl=Search numhl=Number$', a)
let a=execute('sign list Sign1')
call assert_equal("\nsign Sign1 text=x ", a)
@@ -127,26 +127,34 @@ func Test_sign()
call assert_fails("sign define Sign4 text=\\ ab linehl=Comment", 'E239:')
" an empty highlight argument for an existing sign clears it
- sign define SignY texthl=TextHl culhl=CulHl linehl=LineHl
+ sign define SignY texthl=TextHl culhl=CulHl linehl=LineHl numhl=NumHl
let sl = sign_getdefined('SignY')[0]
call assert_equal('TextHl', sl.texthl)
call assert_equal('CulHl', sl.culhl)
call assert_equal('LineHl', sl.linehl)
+ call assert_equal('NumHl', sl.numhl)
- sign define SignY texthl= culhl=CulHl linehl=LineHl
+ sign define SignY texthl= culhl=CulHl linehl=LineHl numhl=NumHl
let sl = sign_getdefined('SignY')[0]
call assert_false(has_key(sl, 'texthl'))
call assert_equal('CulHl', sl.culhl)
call assert_equal('LineHl', sl.linehl)
+ call assert_equal('NumHl', sl.numhl)
sign define SignY linehl=
let sl = sign_getdefined('SignY')[0]
call assert_false(has_key(sl, 'linehl'))
call assert_equal('CulHl', sl.culhl)
+ call assert_equal('NumHl', sl.numhl)
sign define SignY culhl=
let sl = sign_getdefined('SignY')[0]
call assert_false(has_key(sl, 'culhl'))
+ call assert_equal('NumHl', sl.numhl)
+
+ sign define SignY numhl=
+ let sl = sign_getdefined('SignY')[0]
+ call assert_false(has_key(sl, 'numhl'))
sign undefine SignY
@@ -158,7 +166,7 @@ func Test_sign()
sign define Sign5 text=X\ linehl=Comment
sign undefine Sign5
- sign define Sign5 linehl=Comment text=X\
+ sign define Sign5 linehl=Comment text=X\
sign undefine Sign5
" define sign with backslash
@@ -417,8 +425,8 @@ func Test_sign_funcs()
let attr = {'text' : '=>', 'linehl' : 'Search', 'texthl' : 'Error',
\ 'culhl': 'Visual', 'numhl': 'Number'}
call assert_equal(0, "sign1"->sign_define(attr))
- call assert_equal([{'name' : 'sign1', 'texthl' : 'Error', 'linehl': 'Search',
- \ 'culhl': 'Visual', 'numhl': 'Number', 'text' : '=>'}],
+ call assert_equal([{'name' : 'sign1', 'texthl' : 'Error', 'linehl' : 'Search',
+ \ 'culhl' : 'Visual', 'numhl': 'Number', 'text' : '=>'}],
\ sign_getdefined())
" Define a new sign without attributes and then update it
@@ -483,13 +491,13 @@ func Test_sign_funcs()
call assert_fails('call sign_place(5, "", "sign1", "@", {"lnum" : 10})',
\ 'E158:')
call assert_fails('call sign_place(5, "", "sign1", [], {"lnum" : 10})',
- \ 'E158:')
+ \ 'E730:')
call assert_fails('call sign_place(21, "", "sign1", "Xsign",
\ {"lnum" : -1})', 'E474:')
call assert_fails('call sign_place(22, "", "sign1", "Xsign",
\ {"lnum" : 0})', 'E474:')
call assert_fails('call sign_place(22, "", "sign1", "Xsign",
- \ {"lnum" : []})', 'E474:')
+ \ {"lnum" : []})', 'E745:')
call assert_equal(-1, sign_place(1, "*", "sign1", "Xsign", {"lnum" : 10}))
" Tests for sign_getplaced()
@@ -535,9 +543,9 @@ func Test_sign_funcs()
call assert_equal(15, sign_place(15, '', 'sign1', 'Xsign', {'lnum' : 20}))
call assert_equal(15, sign_place(15, '', 'sign2', 'Xsign'))
call assert_equal([{'bufnr' : bufnr(''), 'signs' :
- \ [{'id' : 15, 'group' : '', 'lnum' : 20, 'name' : 'sign2',
- \ 'priority' : 10}]}],
- \ sign_getplaced())
+ \ [{'id' : 15, 'group' : '', 'lnum' : 20, 'name' : 'sign2',
+ \ 'priority' : 10}]}],
+ \ sign_getplaced())
" Tests for sign_undefine()
call assert_equal(0, sign_undefine("sign1"))
@@ -1165,7 +1173,7 @@ func Test_sign_unplace()
call delete("Xsign2")
endfunc
-" Tests for auto-generating the sign identifier
+" Tests for auto-generating the sign identifier.
func Test_aaa_sign_id_autogen()
enew | only
call sign_unplace('*')
@@ -1650,10 +1658,34 @@ func Test_sign_lnum_adjust()
" changes made by this function.
let &undolevels=&undolevels
+ " Nvim: make sign adjustment when deleting lines match Vim
+ set signcolumn=yes:1
+
" Delete the line with the sign
call deletebufline('', 4)
let l = sign_getplaced(bufnr(''))
- call assert_equal(0, len(l[0].signs))
+ call assert_equal(4, l[0].signs[0].lnum)
+
+ " Undo the delete operation
+ undo
+ let l = sign_getplaced(bufnr(''))
+ call assert_equal(5, l[0].signs[0].lnum)
+
+ " Break the undo
+ let &undolevels=&undolevels
+
+ " Delete few lines at the end of the buffer including the line with the sign
+ " Sign line number should not change (as it is placed outside of the buffer)
+ call deletebufline('', 3, 6)
+ let l = sign_getplaced(bufnr(''))
+ call assert_equal(5, l[0].signs[0].lnum)
+
+ " Undo the delete operation. Sign should be restored to the previous line
+ undo
+ let l = sign_getplaced(bufnr(''))
+ call assert_equal(5, l[0].signs[0].lnum)
+
+ set signcolumn&
sign unplace * group=*
sign undefine sign1
@@ -1731,7 +1763,7 @@ func Test_sign_jump_func()
call assert_fails("call sign_jump(5, 'g5', 'foo')", 'E157:')
call assert_fails('call sign_jump([], "", "foo")', 'E745:')
call assert_fails('call sign_jump(2, [], "foo")', 'E730:')
- call assert_fails('call sign_jump(2, "", {})', 'E158:')
+ call assert_fails('call sign_jump(2, "", {})', 'E731:')
call assert_fails('call sign_jump(2, "", "baz")', 'E158:')
sign unplace * group=*
@@ -1741,9 +1773,7 @@ endfunc
" Test for correct cursor position after the sign column appears or disappears.
func Test_sign_cursor_position()
- if !CanRunVimInTerminal()
- throw 'Skipped: cannot make screendumps'
- endif
+ CheckRunVimInTerminal
let lines =<< trim END
call setline(1, [repeat('x', 75), 'mmmm', 'yyyy'])
@@ -1790,8 +1820,8 @@ func Test_sign_numcol()
set number
set signcolumn=number
sign define sign1 text==>
- sign place 10 line=1 name=sign1
sign define sign2 text=V
+ sign place 10 line=1 name=sign1
redraw!
call assert_equal("=> 01234", s:ScreenLine(1, 1, 8))
diff --git a/src/nvim/testdir/test_sleep.vim b/src/nvim/testdir/test_sleep.vim
index f71855fd4b..a428f380b0 100644
--- a/src/nvim/testdir/test_sleep.vim
+++ b/src/nvim/testdir/test_sleep.vim
@@ -21,6 +21,7 @@ func! Test_sleep_bang()
call s:assert_takes_longer('sl 50m', 50)
call s:assert_takes_longer('sl! 50m', 50)
call s:assert_takes_longer('1sleep', 1000)
+ call s:assert_takes_longer('normal 1gs', 1000)
endfunc
" vim: shiftwidth=2 sts=2 expandtab
diff --git a/src/nvim/testdir/test_sort.vim b/src/nvim/testdir/test_sort.vim
index 9895ad754c..534393b724 100644
--- a/src/nvim/testdir/test_sort.vim
+++ b/src/nvim/testdir/test_sort.vim
@@ -80,7 +80,7 @@ func Test_sort_default()
call assert_equal(['2', 'A', 'AA', 'a', 1, 3.3], sort([3.3, 1, "2", "A", "a", "AA"], ''))
call assert_equal(['2', 'A', 'AA', 'a', 1, 3.3], sort([3.3, 1, "2", "A", "a", "AA"], 0))
call assert_equal(['2', 'A', 'a', 'AA', 1, 3.3], sort([3.3, 1, "2", "A", "a", "AA"], 1))
- call assert_fails('call sort([3.3, 1, "2"], 3)', "E474")
+ call assert_fails('call sort([3.3, 1, "2"], 3)', "E474:")
endfunc
" Tests for the ":sort" command.
@@ -1360,7 +1360,8 @@ func Test_sort_cmd()
call setline(1, ['line1', 'line2'])
call assert_fails('sort no', 'E474:')
call assert_fails('sort c', 'E475:')
- call assert_fails('sort #pat%', 'E682:')
+ call assert_fails('sort #pat%', 'E654:')
+ call assert_fails('sort /\%(/', 'E53:')
enew!
endfunc
diff --git a/src/nvim/testdir/test_source.vim b/src/nvim/testdir/test_source.vim
index ba6fd5ad95..d4d96e36bf 100644
--- a/src/nvim/testdir/test_source.vim
+++ b/src/nvim/testdir/test_source.vim
@@ -1,5 +1,8 @@
" Tests for the :source command.
+source check.vim
+source view_util.vim
+
func Test_source_autocmd()
call writefile([
\ 'let did_source = 1',
@@ -87,4 +90,24 @@ func Test_source_autocmd_sfile()
call delete('Xscript.vim')
endfunc
+func Test_source_error()
+ call assert_fails('scriptencoding utf-8', 'E167:')
+ call assert_fails('finish', 'E168:')
+ " call assert_fails('scriptversion 2', 'E984:')
+endfunc
+
+" Test for sourcing a script recursively
+func Test_nested_script()
+ CheckRunVimInTerminal
+ call writefile([':source! Xscript.vim', ''], 'Xscript.vim')
+ let buf = RunVimInTerminal('', {'rows': 6})
+ call term_wait(buf)
+ call term_sendkeys(buf, ":set noruler\n")
+ call term_sendkeys(buf, ":source! Xscript.vim\n")
+ call term_wait(buf)
+ call WaitForAssert({-> assert_match('E22: Scripts nested too deep\s*', term_getline(buf, 6))})
+ call delete('Xscript.vim')
+ call StopVimInTerminal(buf)
+endfunc
+
" vim: shiftwidth=2 sts=2 expandtab
diff --git a/src/nvim/testdir/test_spell.vim b/src/nvim/testdir/test_spell.vim
index 8ab8204b10..c840e834b9 100644
--- a/src/nvim/testdir/test_spell.vim
+++ b/src/nvim/testdir/test_spell.vim
@@ -147,7 +147,7 @@ func Test_spell_file_missing()
augroup TestSpellFileMissing
autocmd! SpellFileMissing * bwipe
augroup END
- call assert_fails('set spell spelllang=ab_cd', 'E797:')
+ call assert_fails('set spell spelllang=ab_cd', 'E937:')
" clean up
augroup TestSpellFileMissing
@@ -159,6 +159,19 @@ func Test_spell_file_missing()
%bwipe!
endfunc
+func Test_spell_file_missing_bwipe()
+ " this was using a window that was wiped out in a SpellFileMissing autocmd
+ set spelllang=xy
+ au SpellFileMissing * n0
+ set spell
+ au SpellFileMissing * bw
+ snext somefile
+
+ au! SpellFileMissing
+ bwipe!
+ set nospell spelllang=en
+endfunc
+
func Test_spelldump()
" In case the spell file is not found avoid getting the download dialog, we
" would get stuck at the prompt.
@@ -329,6 +342,11 @@ func Test_spellsuggest()
call assert_equal(['Third'], spellsuggest('THird', 1))
call assert_equal(['All'], spellsuggest('ALl', 1))
+ " Special suggestion for repeated 'the the'.
+ call assert_inrange(0, 2, index(spellsuggest('the the', 3), 'the'))
+ call assert_inrange(0, 2, index(spellsuggest('the the', 3), 'the'))
+ call assert_inrange(0, 2, index(spellsuggest('The the', 3), 'The'))
+
call assert_fails("call spellsuggest('maxch', [])", 'E745:')
call assert_fails("call spellsuggest('maxch', 2, [])", 'E745:')
@@ -474,6 +492,35 @@ func Test_spellsuggest_option_expr()
bwipe!
endfunc
+" Test for 'spellsuggest' expr errrors
+func Test_spellsuggest_expr_errors()
+ " 'spellsuggest'
+ func MySuggest()
+ return range(3)
+ endfunc
+ set spell spellsuggest=expr:MySuggest()
+ call assert_equal([], spellsuggest('baord', 3))
+
+ " Test for 'spellsuggest' expression returning a non-list value
+ func! MySuggest2()
+ return 'good'
+ endfunc
+ set spellsuggest=expr:MySuggest2()
+ call assert_equal([], spellsuggest('baord'))
+
+ " Test for 'spellsuggest' expression returning a list with dict values
+ func! MySuggest3()
+ return [[{}, {}]]
+ endfunc
+ set spellsuggest=expr:MySuggest3()
+ call assert_fails("call spellsuggest('baord')", 'E731:')
+
+ set nospell spellsuggest&
+ delfunc MySuggest
+ delfunc MySuggest2
+ delfunc MySuggest3
+endfunc
+
func Test_spellsuggest_timeout()
set spellsuggest=timeout:30
set spellsuggest=timeout:-123
@@ -484,8 +531,23 @@ func Test_spellsuggest_timeout()
call assert_fails('set spellsuggest=timeout:--9', 'E474:')
endfunc
+func Test_spellsuggest_visual_end_of_line()
+ let enc_save = &encoding
+ " set encoding=iso8859
+
+ " This was reading beyond the end of the line.
+ norm R00000000000
+ sil norm 0
+ sil! norm i00000)
+ sil! norm i00000)
+ call feedkeys("\<CR>")
+ norm z=
+
+ let &encoding = enc_save
+endfunc
+
func Test_spellinfo()
- throw 'skipped: Nvim does not support enc=latin1'
+ throw 'Skipped: Nvim does not support enc=latin1'
new
let runtime = substitute($VIMRUNTIME, '\\', '/', 'g')
@@ -1401,3 +1463,5 @@ let g:test_data_aff_sal = [
\"SAL ZZ- _",
\"SAL Z S",
\ ]
+
+" vim: shiftwidth=2 sts=2 expandtab
diff --git a/src/nvim/testdir/test_startup.vim b/src/nvim/testdir/test_startup.vim
index 39fafbf7b4..1ee1d0dfe3 100644
--- a/src/nvim/testdir/test_startup.vim
+++ b/src/nvim/testdir/test_startup.vim
@@ -267,10 +267,9 @@ endfunc
" Test the -V[N] argument to set the 'verbose' option to [N]
func Test_V_arg()
- if has('gui_running')
- " Can't catch the output of gvim.
- return
- endif
+ " Can't catch the output of gvim.
+ CheckNotGui
+
let out = system(GetVimCommand() . ' --clean -es -X -V0 -c "set verbose?" -cq')
call assert_equal(" verbose=0\n", out)
@@ -431,7 +430,7 @@ endfunction
" Test the -reverse and +reverse arguments (for GUI only).
func Test_reverse()
CheckCanRunGui
- CheckAnyOf Feature:gui_gtk Feature:gui_motif Feature:gui_athena
+ CheckAnyOf Feature:gui_gtk Feature:gui_motif
let after =<< trim [CODE]
call writefile([&background], "Xtest_reverse")
@@ -452,7 +451,7 @@ endfunc
" Test the -background and -foreground arguments (for GUI only).
func Test_background_foreground()
CheckCanRunGui
- CheckAnyOf Feature:gui_gtk Feature:gui_motif Feature:gui_athena
+ CheckAnyOf Feature:gui_gtk Feature:gui_motif
" Is there a better way to check the effect of -background & -foreground
" other than merely looking at &background (dark or light)?
@@ -479,7 +478,7 @@ func Test_font()
if has('gui_gtk')
let font = 'Courier 14'
- elseif has('gui_motif') || has('gui_athena')
+ elseif has('gui_motif')
let font = '-misc-fixed-bold-*'
else
throw 'Skipped: test does not set a valid font for this GUI'
@@ -501,10 +500,10 @@ endfunc
" Test the -geometry argument (for GUI only).
func Test_geometry()
CheckCanRunGui
- CheckAnyOf Feature:gui_gtk Feature:gui_motif Feature:gui_athena
+ CheckAnyOf Feature:gui_gtk Feature:gui_motif
- if has('gui_motif') || has('gui_athena')
- " FIXME: With GUI Athena or Motif, the value of getwinposx(),
+ if has('gui_motif')
+ " FIXME: With GUI Motif the value of getwinposx(),
" getwinposy() and getwinpos() do not match exactly the
" value given in -geometry. Why?
" So only check &columns and &lines for those GUIs.
@@ -521,9 +520,18 @@ func Test_geometry()
call writefile([&columns, &lines, getwinposx(), getwinposy(), string(getwinpos())], "Xtest_geometry")
qall
[CODE]
- if RunVim([], after, '-f -g -geometry 31x13+41+43')
+ " Some window managers have a bar at the top that pushes windows down,
+ " need to use at least 130, let's do 150
+ if RunVim([], after, '-f -g -geometry 31x13+41+150')
let lines = readfile('Xtest_geometry')
- call assert_equal(['31', '13', '41', '43', '[41, 43]'], lines)
+ " Depending on the GUI library and the windowing system the final size
+ " might be a bit different, allow for some tolerance. Tuned based on
+ " actual failures.
+ call assert_inrange(31, 35, str2nr(lines[0]))
+ call assert_equal('13', lines[1])
+ call assert_equal('41', lines[2])
+ call assert_equal('150', lines[3])
+ call assert_equal('[41, 150]', lines[4])
endif
endif
@@ -533,7 +541,7 @@ endfunc
" Test the -iconic argument (for GUI only).
func Test_iconic()
CheckCanRunGui
- CheckAnyOf Feature:gui_gtk Feature:gui_motif Feature:gui_athena
+ CheckAnyOf Feature:gui_gtk Feature:gui_motif
call RunVim([], [], '-f -g -iconic -cq')
@@ -543,10 +551,9 @@ endfunc
func Test_invalid_args()
- if !has('unix') || has('gui_running')
- " can't get output of Vim.
- return
- endif
+ " must be able to get the output of Vim.
+ CheckUnix
+ CheckNotGui
for opt in ['-Y', '--does-not-exist']
let out = split(system(GetVimCommand() .. ' ' .. opt), "\n")
@@ -603,7 +610,7 @@ func Test_invalid_args()
call assert_equal(0, v:shell_error)
if has('quickfix')
- " Detect invalid repeated arguments '-t foo -t foo", '-q foo -q foo'.
+ " Detect invalid repeated arguments '-t foo -t foo', '-q foo -q foo'.
for opt in ['-t', '-q']
let out = split(system(GetVimCommand() .. repeat(' ' .. opt .. ' foo', 2)), "\n")
call assert_equal(1, v:shell_error)
@@ -622,6 +629,12 @@ func Test_invalid_args()
endfor
if has('gui_gtk')
+ let out = split(system(GetVimCommand() .. ' --socketid'), "\n")
+ call assert_equal(1, v:shell_error)
+ call assert_match('^VIM - Vi IMproved .* (.*)$', out[0])
+ call assert_equal('Argument missing after: "--socketid"', out[1])
+ call assert_equal('More info with: "vim -h"', out[2])
+
for opt in ['--socketid x', '--socketid 0xg']
let out = split(system(GetVimCommand() .. ' ' .. opt), "\n")
call assert_equal(1, v:shell_error)
@@ -629,6 +642,7 @@ func Test_invalid_args()
call assert_equal('Invalid argument for: "--socketid"', out[1])
call assert_equal('More info with: "vim -h"', out[2])
endfor
+
endif
endfunc
@@ -711,27 +725,6 @@ func Test_read_stdin()
call delete('Xtestout')
endfunc
-func Test_set_shell()
- let after =<< trim [CODE]
- call writefile([&shell], "Xtestout")
- quit!
- [CODE]
-
- if has('win32')
- let $SHELL = 'C:\with space\cmd.exe'
- let expected = '"C:\with space\cmd.exe"'
- else
- let $SHELL = '/bin/with space/sh'
- let expected = '"/bin/with space/sh"'
- endif
-
- if RunVimPiped([], after, '', '')
- let lines = readfile('Xtestout')
- call assert_equal(expected, lines[0])
- endif
- call delete('Xtestout')
-endfunc
-
func Test_progpath()
" Tests normally run with "./vim" or "../vim", these must have been expanded
" to a full path.
@@ -747,10 +740,9 @@ func Test_progpath()
endfunc
func Test_silent_ex_mode()
- if !has('unix') || has('gui_running')
- " can't get output of Vim.
- return
- endif
+ " must be able to get the output of Vim.
+ CheckUnix
+ CheckNotGui
" This caused an ml_get error.
let out = system(GetVimCommand() . ' -u NONE -es -c''set verbose=1|h|exe "%norm\<c-y>\<c-d>"'' -c cq')
@@ -758,10 +750,9 @@ func Test_silent_ex_mode()
endfunc
func Test_default_term()
- if !has('unix') || has('gui_running')
- " can't get output of Vim.
- return
- endif
+ " must be able to get the output of Vim.
+ CheckUnix
+ CheckNotGui
let save_term = $TERM
let $TERM = 'unknownxxx'
@@ -796,10 +787,17 @@ func Test_zzz_startinsert()
call delete('Xtestout')
endfunc
+func Test_issue_3969()
+ " Can't catch the output of gvim.
+ CheckNotGui
+
+ " Check that message is not truncated.
+ let out = system(GetVimCommand() . ' -es -X -V1 -c "echon ''hello''" -cq')
+ call assert_equal('hello', out)
+endfunc
+
func Test_start_with_tabs()
- if !CanRunVimInTerminal()
- return
- endif
+ CheckRunVimInTerminal
let buf = RunVimInTerminal('-p a b c', {})
call VerifyScreenDump(buf, 'Test_start_with_tabs', {})
@@ -855,7 +853,7 @@ func Test_t_arg()
call writefile([' first', ' second', ' third'], 'Xfile1')
for t_arg in ['-t second', '-tsecond']
- if RunVim(before, after, '-t second')
+ if RunVim(before, after, t_arg)
call assert_equal(['Xfile1:L2C5'], readfile('Xtestout'), t_arg)
call delete('Xtestout')
endif
@@ -943,6 +941,7 @@ endfunc
" Test for enabling the lisp mode on startup
func Test_l_arg()
+ throw 'Skipped: Nvim -l arg differs from Vim'
let after =<< trim [CODE]
let s = 'lisp=' .. &lisp .. ', showmatch=' .. &showmatch
call writefile([s], 'Xtestout')
@@ -956,9 +955,7 @@ endfunc
" Test for specifying a non-existing vimrc file using "-u"
func Test_missing_vimrc()
- if !CanRunVimInTerminal()
- throw 'Skipped: cannot run vim in terminal'
- endif
+ CheckRunVimInTerminal
let after =<< trim [CODE]
call assert_match('^E282:', v:errmsg)
call writefile(v:errors, 'Xtestout')
@@ -1016,6 +1013,7 @@ endfunc
" Test for using the 'exrc' option
func Test_exrc()
+ throw 'Skipped: Nvim requires user input for the exrc option'
let after =<< trim [CODE]
call assert_equal(1, &exrc)
call assert_equal(1, &secure)
@@ -1045,7 +1043,7 @@ func Test_io_not_a_terminal()
\ 'Vim: Warning: Input is not from a terminal'], l)
endfunc
-" Test for --not-a-term avoiding escape codes.
+" Test for not being a term avoiding escape codes.
func Test_not_a_term()
CheckUnix
CheckNotGui
@@ -1056,18 +1054,14 @@ func Test_not_a_term()
let redir = &shellredir .. ' Xvimout'
endif
- " Without --not-a-term there are a few escape sequences.
- " This will take 2 seconds because of the missing --not-a-term
+ " As nvim checks the environment by itself there will be no escape sequences
+ " This will also happen to take two (2) seconds.
let cmd = GetVimProg() .. ' --cmd quit ' .. redir
exe "silent !" . cmd
- call assert_match("\<Esc>", readfile('Xvimout')->join())
+ call assert_notmatch("\e", readfile('Xvimout')->join())
call delete('Xvimout')
- " With --not-a-term there are no escape sequences.
- let cmd = GetVimProg() .. ' --not-a-term --cmd quit ' .. redir
- exe "silent !" . cmd
- call assert_notmatch("\<Esc>", readfile('Xvimout')->join())
- call delete('Xvimout')
+ " --not-a-term flag has thus been deleted
endfunc
@@ -1271,4 +1265,19 @@ func Test_progname()
call delete('Xprogname', 'd')
endfunc
+" Test for doing a write from .vimrc
+func Test_write_in_vimrc()
+ call writefile(['silent! write'], 'Xvimrc')
+ let after =<< trim [CODE]
+ call assert_match('E32: ', v:errmsg)
+ call writefile(v:errors, 'Xtestout')
+ qall
+ [CODE]
+ if RunVim([], after, '-u Xvimrc')
+ call assert_equal([], readfile('Xtestout'))
+ call delete('Xtestout')
+ endif
+ call delete('Xvimrc')
+endfunc
+
" vim: shiftwidth=2 sts=2 expandtab
diff --git a/src/nvim/testdir/test_startup_utf8.vim b/src/nvim/testdir/test_startup_utf8.vim
index bb4304396e..2ee6ecc41d 100644
--- a/src/nvim/testdir/test_startup_utf8.vim
+++ b/src/nvim/testdir/test_startup_utf8.vim
@@ -63,9 +63,7 @@ func Test_read_fifo_utf8()
endfunc
func Test_detect_ambiwidth()
- if !CanRunVimInTerminal()
- throw 'Skipped: cannot run Vim in a terminal window'
- endif
+ CheckRunVimInTerminal
" Use the title termcap entries to output the escape sequence.
call writefile([
diff --git a/src/nvim/testdir/test_statusline.vim b/src/nvim/testdir/test_statusline.vim
index 6bde052442..990c852ccd 100644
--- a/src/nvim/testdir/test_statusline.vim
+++ b/src/nvim/testdir/test_statusline.vim
@@ -565,4 +565,45 @@ func Test_statusline_highlight_truncate()
call delete('XTest_statusline')
endfunc
+func Test_statusline_showcmd()
+ CheckScreendump
+
+ let lines =<< trim END
+ func MyStatusLine()
+ return '%S'
+ endfunc
+
+ set laststatus=2
+ set statusline=%!MyStatusLine()
+ set showcmdloc=statusline
+ call setline(1, ['a', 'b', 'c'])
+ set foldopen+=jump
+ 1,2fold
+ 3
+ END
+ call writefile(lines, 'XTest_statusline', 'D')
+
+ let buf = RunVimInTerminal('-S XTest_statusline', {'rows': 6})
+
+ call term_sendkeys(buf, "g")
+ call VerifyScreenDump(buf, 'Test_statusline_showcmd_1', {})
+
+ " typing "gg" should open the fold
+ call term_sendkeys(buf, "g")
+ call VerifyScreenDump(buf, 'Test_statusline_showcmd_2', {})
+
+ call term_sendkeys(buf, "\<C-V>Gl")
+ call VerifyScreenDump(buf, 'Test_statusline_showcmd_3', {})
+
+ call term_sendkeys(buf, "\<Esc>1234")
+ call VerifyScreenDump(buf, 'Test_statusline_showcmd_4', {})
+
+ call term_sendkeys(buf, "\<Esc>:set statusline=\<CR>")
+ call term_sendkeys(buf, ":\<CR>")
+ call term_sendkeys(buf, "1234")
+ call VerifyScreenDump(buf, 'Test_statusline_showcmd_5', {})
+
+ call StopVimInTerminal(buf)
+endfunc
+
" vim: shiftwidth=2 sts=2 expandtab
diff --git a/src/nvim/testdir/test_substitute.vim b/src/nvim/testdir/test_substitute.vim
index b3a80072d9..c99a0d456d 100644
--- a/src/nvim/testdir/test_substitute.vim
+++ b/src/nvim/testdir/test_substitute.vim
@@ -1,6 +1,8 @@
" Tests for the substitute (:s) command
source shared.vim
+source check.vim
+source screendump.vim
func Test_multiline_subst()
enew!
@@ -444,13 +446,19 @@ func Test_substitute_errors()
call assert_fails('s/FOO/bar/', 'E486:')
call assert_fails('s/foo/bar/@', 'E488:')
- call assert_fails('s/\(/bar/', 'E476:')
+ call assert_fails('s/\(/bar/', 'E54:')
call assert_fails('s afooabara', 'E146:')
call assert_fails('s\\a', 'E10:')
setl nomodifiable
call assert_fails('s/foo/bar/', 'E21:')
+ call assert_fails("let s=substitute([], 'a', 'A', 'g')", 'E730:')
+ call assert_fails("let s=substitute('abcda', [], 'A', 'g')", 'E730:')
+ call assert_fails("let s=substitute('abcda', 'a', [], 'g')", 'E730:')
+ call assert_fails("let s=substitute('abcda', 'a', 'A', [])", 'E730:')
+ call assert_fails("let s=substitute('abc', '\\%(', 'A', 'g')", 'E53:')
+
bwipe!
endfunc
@@ -486,6 +494,9 @@ func Test_sub_replace_1()
call assert_equal("x\<C-M>x", substitute('xXx', 'X', "\r", ''))
call assert_equal("YyyY", substitute('Y', 'Y', '\L\uyYy\l\EY', ''))
call assert_equal("zZZz", substitute('Z', 'Z', '\U\lZzZ\u\Ez', ''))
+ " \v or \V after $
+ call assert_equal('abxx', substitute('abcd', 'xy$\v|cd$', 'xx', ''))
+ call assert_equal('abxx', substitute('abcd', 'xy$\V\|cd\$', 'xx', ''))
endfunc
func Test_sub_replace_2()
@@ -637,12 +648,16 @@ endfunc
func SubReplacer(text, submatches)
return a:text .. a:submatches[0] .. a:text
endfunc
+func SubReplacerVar(text, ...)
+ return a:text .. a:1[0] .. a:text
+endfunc
func SubReplacer20(t1, t2, t3, t4, t5, t6, t7, t8, t9, t10, t11, t12, t13, t14, t15, t16, t17, t18, t19, submatches)
return a:t3 .. a:submatches[0] .. a:t11
endfunc
func Test_substitute_partial()
call assert_equal('1foo2foo3', substitute('123', '2', function('SubReplacer', ['foo']), 'g'))
+ call assert_equal('1foo2foo3', substitute('123', '2', function('SubReplacerVar', ['foo']), 'g'))
" 19 arguments plus one is just OK
let Replacer = function('SubReplacer20', repeat(['foo'], 19))
@@ -668,6 +683,21 @@ func Test_sub_cmd_9()
bw!
endfunc
+func Test_sub_highlight_zero_match()
+ CheckRunVimInTerminal
+
+ let lines =<< trim END
+ call setline(1, ['one', 'two', 'three'])
+ END
+ call writefile(lines, 'XscriptSubHighlight', 'D')
+ let buf = RunVimInTerminal('-S XscriptSubHighlight', #{rows: 8, cols: 60})
+ call term_sendkeys(buf, ":%s/^/ /c\<CR>")
+ call VerifyScreenDump(buf, 'Test_sub_highlight_zer_match_1', {})
+
+ call term_sendkeys(buf, "\<Esc>")
+ call StopVimInTerminal(buf)
+endfunc
+
func Test_nocatch_sub_failure_handling()
" normal error results in all replacements
func Foo()
@@ -812,9 +842,9 @@ endfunc
func Test_sub_with_no_last_pat()
let lines =<< trim [SCRIPT]
call assert_fails('~', 'E33:')
- call assert_fails('s//abc/g', 'E476:')
- call assert_fails('s\/bar', 'E476:')
- call assert_fails('s\&bar&', 'E476:')
+ call assert_fails('s//abc/g', 'E35:')
+ call assert_fails('s\/bar', 'E35:')
+ call assert_fails('s\&bar&', 'E33:')
call writefile(v:errors, 'Xresult')
qall!
[SCRIPT]
@@ -841,6 +871,40 @@ endfunc
func Test_substitute()
call assert_equal('a1a2a3a', substitute('123', '\zs', 'a', 'g'))
+ " Substitute with special keys
+ call assert_equal("a\<End>c", substitute('abc', "a.c", "a\<End>c", ''))
+endfunc
+
+func Test_substitute_expr()
+ let g:val = 'XXX'
+ call assert_equal('XXX', substitute('yyy', 'y*', '\=g:val', ''))
+ call assert_equal('XXX', substitute('yyy', 'y*', {-> g:val}, ''))
+ call assert_equal("-\u1b \uf2-", substitute("-%1b %f2-", '%\(\x\x\)',
+ \ '\=nr2char("0x" . submatch(1))', 'g'))
+ call assert_equal("-\u1b \uf2-", substitute("-%1b %f2-", '%\(\x\x\)',
+ \ {-> nr2char("0x" . submatch(1))}, 'g'))
+
+ call assert_equal('231', substitute('123', '\(.\)\(.\)\(.\)',
+ \ {-> submatch(2) . submatch(3) . submatch(1)}, ''))
+
+ func Recurse()
+ return substitute('yyy', 'y\(.\)y', {-> submatch(1)}, '')
+ endfunc
+ " recursive call works
+ call assert_equal('-y-x-', substitute('xxx', 'x\(.\)x', {-> '-' . Recurse() . '-' . submatch(1) . '-'}, ''))
+
+ call assert_fails("let s=submatch([])", 'E745:')
+ call assert_fails("let s=submatch(2, [])", 'E745:')
+endfunc
+
+func Test_invalid_submatch()
+ " This was causing invalid memory access in Vim-7.4.2232 and older
+ call assert_fails("call substitute('x', '.', {-> submatch(10)}, '')", 'E935:')
+ call assert_fails('eval submatch(-1)', 'E935:')
+ call assert_equal('', submatch(0))
+ call assert_equal('', submatch(1))
+ call assert_equal([], submatch(0, 1))
+ call assert_equal([], submatch(1, 1))
endfunc
func Test_submatch_list_concatenate()
@@ -849,6 +913,44 @@ func Test_submatch_list_concatenate()
call substitute('A1', pat, Rep, '')->assert_equal("[['A1'], ['1']]")
endfunc
+func Test_substitute_expr_arg()
+ call assert_equal('123456789-123456789=', substitute('123456789',
+ \ '\(.\)\(.\)\(.\)\(.\)\(.\)\(.\)\(.\)\(.\)\(.\)',
+ \ {m -> m[0] . '-' . m[1] . m[2] . m[3] . m[4] . m[5] . m[6] . m[7] . m[8] . m[9] . '='}, ''))
+
+ call assert_equal('123456-123456=789', substitute('123456789',
+ \ '\(.\)\(.\)\(.\)\(a*\)\(n*\)\(.\)\(.\)\(.\)\(x*\)',
+ \ {m -> m[0] . '-' . m[1] . m[2] . m[3] . m[4] . m[5] . m[6] . m[7] . m[8] . m[9] . '='}, ''))
+
+ call assert_equal('123456789-123456789x=', substitute('123456789',
+ \ '\(.\)\(.\)\(.*\)',
+ \ {m -> m[0] . '-' . m[1] . m[2] . m[3] . 'x' . m[4] . m[5] . m[6] . m[7] . m[8] . m[9] . '='}, ''))
+
+ call assert_fails("call substitute('xxx', '.', {m -> string(add(m, 'x'))}, '')", 'E742:')
+ call assert_fails("call substitute('xxx', '.', {m -> string(insert(m, 'x'))}, '')", 'E742:')
+ call assert_fails("call substitute('xxx', '.', {m -> string(extend(m, ['x']))}, '')", 'E742:')
+ call assert_fails("call substitute('xxx', '.', {m -> string(remove(m, 1))}, '')", 'E742:')
+endfunc
+
+" Test for using a function to supply the substitute string
+func Test_substitute_using_func()
+ func Xfunc()
+ return '1234'
+ endfunc
+ call assert_equal('a1234f', substitute('abcdef', 'b..e',
+ \ function("Xfunc"), ''))
+ delfunc Xfunc
+endfunc
+
+" Test for using submatch() with a multiline match
+func Test_substitute_multiline_submatch()
+ new
+ call setline(1, ['line1', 'line2', 'line3', 'line4'])
+ %s/^line1\(\_.\+\)line4$/\=submatch(1)/
+ call assert_equal(['', 'line2', 'line3', ''], getline(1, '$'))
+ close!
+endfunc
+
func Test_substitute_skipped_range()
new
if 0
@@ -974,6 +1076,19 @@ func Test_sub_open_cmdline_win()
call delete('Xresult')
endfunc
+" This was editing a script file from the expression
+func Test_sub_edit_scriptfile()
+ new
+ norm o0000000000000000000000000000000000000000000000000000
+ func EditScript()
+ silent! scr! Xfile
+ endfunc
+ s/\%')/\=EditScript()
+
+ delfunc EditScript
+ bwipe!
+endfunc
+
" Test for the 2-letter and 3-letter :substitute commands
func Test_substitute_short_cmd()
new
diff --git a/src/nvim/testdir/test_swap.vim b/src/nvim/testdir/test_swap.vim
index 923e1cbf50..cf46b4c5bd 100644
--- a/src/nvim/testdir/test_swap.vim
+++ b/src/nvim/testdir/test_swap.vim
@@ -2,6 +2,7 @@
source check.vim
source shared.vim
+source term_util.vim
func s:swapname()
return trim(execute('swapname'))
@@ -202,8 +203,8 @@ func Test_swapfile_delete()
" This test won't work as root because root can successfully run kill(1, 0)
if !IsRoot()
" Write the swapfile with a modified PID, now it will be automatically
- " deleted. Process one should never be Vim.
- let swapfile_bytes[24:27] = 0z01000000
+ " deleted. Process 0x3fffffff most likely does not exist.
+ let swapfile_bytes[24:27] = 0zffffff3f
call writefile(swapfile_bytes, swapfile_name)
let s:swapname = ''
split XswapfileText
@@ -374,24 +375,26 @@ func Test_swap_prompt_splitwin()
call WaitForAssert({-> assert_match('^1$', term_getline(buf, 20))})
call StopVimInTerminal(buf)
- " This caused Vim to crash when typing "q".
- " TODO: it does not actually reproduce the crash.
- call writefile(['au BufAdd * set virtualedit=all'], 'Xvimrc')
-
- let buf = RunVimInTerminal('-u Xvimrc Xfile1', {'rows': 20, 'wait_for_ruler': 0})
- call TermWait(buf)
- call WaitForAssert({-> assert_match('^\[O\]pen Read-Only, (E)dit anyway, (R)ecover, (Q)uit, (A)bort:', term_getline(buf, 20))})
+ " This caused Vim to crash when typing "q" at the swap file prompt.
+ let buf = RunVimInTerminal('-c "au bufadd * let foo_w = wincol()"', {'rows': 18})
+ call term_sendkeys(buf, ":e Xfile1\<CR>")
+ call WaitForAssert({-> assert_match('More', term_getline(buf, 18))})
+ call term_sendkeys(buf, " ")
+ call WaitForAssert({-> assert_match('^\[O\]pen Read-Only, (E)dit anyway, (R)ecover, (Q)uit, (A)bort:', term_getline(buf, 18))})
call term_sendkeys(buf, "q")
+ call TermWait(buf)
+ " check that Vim is still running
+ call term_sendkeys(buf, ":echo 'hello'\<CR>")
+ call WaitForAssert({-> assert_match('^hello', term_getline(buf, 18))})
+ call term_sendkeys(buf, ":%bwipe!\<CR>")
+ call StopVimInTerminal(buf)
%bwipe!
call delete('Xfile1')
- call delete('Xvimrc')
endfunc
func Test_swap_symlink()
- if !has("unix")
- return
- endif
+ CheckUnix
call writefile(['text'], 'Xtestfile')
silent !ln -s -f Xtestfile Xtestlink
@@ -418,6 +421,161 @@ func Test_swap_symlink()
call delete('Xswapdir', 'rf')
endfunc
+func s:get_unused_pid(base)
+ if has('job')
+ " Execute 'echo' as a temporary job, and return its pid as an unused pid.
+ if has('win32')
+ let cmd = 'cmd /c echo'
+ else
+ let cmd = 'echo'
+ endif
+ let j = job_start(cmd)
+ while job_status(j) ==# 'run'
+ sleep 10m
+ endwhile
+ if job_status(j) ==# 'dead'
+ return job_info(j).process
+ endif
+ endif
+ " Must add four for MS-Windows to see it as a different one.
+ return a:base + 4
+endfunc
+
+func s:blob_to_pid(b)
+ return a:b[3] * 16777216 + a:b[2] * 65536 + a:b[1] * 256 + a:b[0]
+endfunc
+
+func s:pid_to_blob(i)
+ let b = 0z
+ let b[0] = and(a:i, 0xff)
+ let b[1] = and(a:i / 256, 0xff)
+ let b[2] = and(a:i / 65536, 0xff)
+ let b[3] = and(a:i / 16777216, 0xff)
+ return b
+endfunc
+
+func Test_swap_auto_delete()
+ " Create a valid swapfile by editing a file with a special extension.
+ split Xtest.scr
+ call setline(1, ['one', 'two', 'three'])
+ write " file is written, not modified
+ write " write again to make sure the swapfile is created
+ " read the swapfile as a Blob
+ let swapfile_name = swapname('%')
+ let swapfile_bytes = readfile(swapfile_name, 'B')
+
+ " Forget about the file, recreate the swap file, then edit it again. The
+ " swap file should be automatically deleted.
+ bwipe!
+ " Change the process ID to avoid the "still running" warning.
+ let swapfile_bytes[24:27] = s:pid_to_blob(s:get_unused_pid(
+ \ s:blob_to_pid(swapfile_bytes[24:27])))
+ call writefile(swapfile_bytes, swapfile_name)
+ edit Xtest.scr
+ " will end up using the same swap file after deleting the existing one
+ call assert_equal(swapfile_name, swapname('%'))
+ bwipe!
+
+ " create the swap file again, but change the host name so that it won't be
+ " deleted
+ autocmd! SwapExists
+ augroup test_swap_recover_ext
+ autocmd!
+ autocmd SwapExists * let v:swapchoice = 'e'
+ augroup END
+
+ " change the host name
+ let swapfile_bytes[28 + 40] = swapfile_bytes[28 + 40] + 2
+ call writefile(swapfile_bytes, swapfile_name)
+ edit Xtest.scr
+ call assert_equal(1, filereadable(swapfile_name))
+ " will use another same swap file name
+ call assert_notequal(swapfile_name, swapname('%'))
+ bwipe!
+
+ call delete('Xtest.scr')
+ call delete(swapfile_name)
+ augroup test_swap_recover_ext
+ autocmd!
+ augroup END
+ augroup! test_swap_recover_ext
+endfunc
+
+" Test for renaming a buffer when the swap file is deleted out-of-band
+func Test_missing_swap_file()
+ CheckUnix
+ new Xfile2
+ call delete(swapname(''))
+ call assert_fails('file Xfile3', 'E301:')
+ call assert_equal('Xfile3', bufname())
+ call assert_true(bufexists('Xfile2'))
+ call assert_true(bufexists('Xfile3'))
+ %bw!
+endfunc
+
+" Test for :preserve command
+func Test_preserve()
+ new Xfile4
+ setlocal noswapfile
+ call assert_fails('preserve', 'E313:')
+ bw!
+endfunc
+
+" Test for the v:swapchoice variable
+func Test_swapchoice()
+ call writefile(['aaa', 'bbb'], 'Xfile5')
+ edit Xfile5
+ preserve
+ let swapfname = swapname('')
+ let b = readblob(swapfname)
+ bw!
+ call writefile(b, swapfname)
+
+ autocmd! SwapExists
+
+ " Test for v:swapchoice = 'o' (readonly)
+ augroup test_swapchoice
+ autocmd!
+ autocmd SwapExists * let v:swapchoice = 'o'
+ augroup END
+ edit Xfile5
+ call assert_true(&readonly)
+ call assert_equal(['aaa', 'bbb'], getline(1, '$'))
+ %bw!
+ call assert_true(filereadable(swapfname))
+
+ " Test for v:swapchoice = 'a' (abort)
+ augroup test_swapchoice
+ autocmd!
+ autocmd SwapExists * let v:swapchoice = 'a'
+ augroup END
+ try
+ edit Xfile5
+ catch /^Vim:Interrupt$/
+ endtry
+ call assert_equal('', @%)
+ call assert_true(bufexists('Xfile5'))
+ %bw!
+ call assert_true(filereadable(swapfname))
+
+ " Test for v:swapchoice = 'd' (delete)
+ augroup test_swapchoice
+ autocmd!
+ autocmd SwapExists * let v:swapchoice = 'd'
+ augroup END
+ edit Xfile5
+ call assert_equal('Xfile5', @%)
+ %bw!
+ call assert_false(filereadable(swapfname))
+
+ call delete('Xfile5')
+ call delete(swapfname)
+ augroup test_swapchoice
+ autocmd!
+ augroup END
+ augroup! test_swapchoice
+endfunc
+
func Test_no_swap_file()
call assert_equal("\nNo swap file", execute('swapname'))
endfunc
diff --git a/src/nvim/testdir/test_syntax.vim b/src/nvim/testdir/test_syntax.vim
index 7ba0149971..45230c4208 100644
--- a/src/nvim/testdir/test_syntax.vim
+++ b/src/nvim/testdir/test_syntax.vim
@@ -113,6 +113,9 @@ func Test_syntime()
let a = execute('syntime report')
call assert_equal("\nNo Syntax items defined for this buffer", a)
+ let a = execute('syntime clear')
+ call assert_equal("\nNo Syntax items defined for this buffer", a)
+
view samples/memfile_test.c
setfiletype cpp
redraw
@@ -171,6 +174,10 @@ func Test_syntax_list()
let a = execute('syntax list')
call assert_equal("\nNo Syntax items defined for this buffer", a)
+ syntax keyword Type int containedin=g1 skipwhite skipempty skipnl nextgroup=Abc
+ let exp = "Type xxx containedin=g1 nextgroup=Abc skipnl skipwhite skipempty int"
+ call assert_equal(exp, split(execute("syntax list"), "\n")[1])
+
bd
endfunc
@@ -188,22 +195,26 @@ func Test_syntax_completion()
call assert_equal('"syn sync ccomment clear fromstart linebreaks= linecont lines= match maxlines= minlines= region', @:)
" Check that clearing "Aap" avoids it showing up before Boolean.
- hi Aap ctermfg=blue
+ hi @Aap ctermfg=blue
call feedkeys(":syn list \<C-A>\<C-B>\"\<CR>", 'tx')
- call assert_match('^"syn list Aap Boolean Character ', @:)
- hi clear Aap
+ call assert_match('^"syn list @Aap @boolean @character ', @:)
+ hi clear @Aap
call feedkeys(":syn list \<C-A>\<C-B>\"\<CR>", 'tx')
- call assert_match('^"syn list Boolean Character ', @:)
+ call assert_match('^"syn list @boolean @character ', @:)
call feedkeys(":syn match \<C-A>\<C-B>\"\<CR>", 'tx')
- call assert_match('^"syn match Boolean Character ', @:)
+ call assert_match('^"syn match @boolean @character ', @:)
+
+ syn cluster Aax contains=Aap
+ call feedkeys(":syn list @A\<C-A>\<C-B>\"\<CR>", 'tx')
+ call assert_match('^"syn list @Aax', @:)
endfunc
func Test_echohl_completion()
call feedkeys(":echohl no\<C-A>\<C-B>\"\<CR>", 'tx')
" call assert_equal('"echohl NonText Normal none', @:)
- call assert_equal('"echohl NonText Normal NormalFloat NormalNC none', @:)
+ call assert_equal('"echohl NonText Normal NormalFloat none', @:)
endfunc
func Test_syntax_arg_skipped()
@@ -343,6 +354,18 @@ func Test_syntax_arg_skipped()
syn clear
endfunc
+" Check for an error. Used when multiple errors are thrown and we are checking
+" for an earliest error.
+func AssertFails(cmd, errcode)
+ let save_exception = ''
+ try
+ exe a:cmd
+ catch
+ let save_exception = v:exception
+ endtry
+ call assert_match(a:errcode, save_exception)
+endfunc
+
func Test_syntax_invalid_arg()
call assert_fails('syntax case asdf', 'E390:')
if has('conceal')
@@ -350,11 +373,51 @@ func Test_syntax_invalid_arg()
endif
call assert_fails('syntax spell asdf', 'E390:')
call assert_fails('syntax clear @ABCD', 'E391:')
- call assert_fails('syntax include @Xxx', 'E397:')
- call assert_fails('syntax region X start="{"', 'E399:')
+ call assert_fails('syntax include random_file', 'E484:')
+ call assert_fails('syntax include <afile>', 'E495:')
call assert_fails('syntax sync x', 'E404:')
call assert_fails('syntax keyword Abc a[', 'E789:')
call assert_fails('syntax keyword Abc a[bc]d', 'E890:')
+ call assert_fails('syntax cluster Abc add=A add=', 'E406:')
+
+ " Test for too many \z\( and unmatched \z\(
+ " Not able to use assert_fails() here because both E50:/E879: and E475:
+ " messages are emitted.
+ set regexpengine=1
+ call AssertFails("syntax region MyRegion start='\\z\\(' end='\\*/'", 'E52:')
+
+ let cmd = "syntax region MyRegion start='"
+ let cmd ..= repeat("\\z\\(.\\)", 10) .. "' end='\*/'"
+ call AssertFails(cmd, 'E50:')
+
+ set regexpengine=2
+ call AssertFails("syntax region MyRegion start='\\z\\(' end='\\*/'", 'E54:')
+
+ let cmd = "syntax region MyRegion start='"
+ let cmd ..= repeat("\\z\\(.\\)", 10) .. "' end='\*/'"
+ call AssertFails(cmd, 'E879:')
+ set regexpengine&
+
+ call AssertFails('syntax keyword cMyItem grouphere G1', 'E393:')
+ call AssertFails('syntax sync match Abc grouphere MyItem "abc"', 'E394:')
+ call AssertFails('syn keyword Type contains int', 'E395:')
+ call assert_fails('syntax include @Xxx', 'E397:')
+ call AssertFails('syntax region X start', 'E398:')
+ call assert_fails('syntax region X start="{"', 'E399:')
+ call AssertFails('syntax cluster contains=Abc', 'E400:')
+ call AssertFails("syntax match Character /'.'", 'E401:')
+ call AssertFails("syntax match Character /'.'/a", 'E402:')
+ call assert_fails('syntax sync linecont /\%(/', 'E53:')
+ call assert_fails('syntax sync linecont /pat', 'E404:')
+ call assert_fails('syntax sync linecont', 'E404:')
+ call assert_fails('syntax sync linecont /pat1/ linecont /pat2/', 'E403:')
+ call assert_fails('syntax sync minlines=a', 'E404:')
+ call AssertFails('syntax match ABC /x/ contains=', 'E406:')
+ call AssertFails("syntax match Character contains /'.'/", 'E405:')
+ call AssertFails('syntax match ccFoo "Foo" nextgroup=ALLBUT,F', 'E407:')
+ call AssertFails('syntax region Block start="{" contains=F,ALLBUT', 'E408:')
+ call AssertFails("syntax match Characters contains=a.*x /'.'/", 'E409:')
+ call assert_fails('syntax match Search /abc/ contains=ALLBUT,/\%(/', 'E53:')
endfunc
func Test_syn_sync()
@@ -382,6 +445,7 @@ func Test_syn_clear()
hi clear Foo
call assert_equal('Foo', synIDattr(hlID("Foo"), "name"))
hi clear Bar
+ call assert_fails('syntax clear invalid_syngroup', 'E28:')
endfunc
func Test_invalid_name()
@@ -389,7 +453,7 @@ func Test_invalid_name()
syn keyword Nop yes
call assert_fails("syntax keyword Wr\x17ong bar", 'E669:')
syntax keyword @Wrong bar
- call assert_match('W18:', execute('1messages'))
+ call assert_fails("syntax keyword @#Wrong bar", 'E5248:')
syn clear
hi clear Nop
hi clear @Wrong
@@ -475,15 +539,16 @@ func Test_conceal()
call assert_match('16 ', ScreenLines(2, 7)[0])
call assert_equal([[0, '', 0], [1, '', 1], [1, '', 1], [1, '', 2], [1, '', 2], [0, '', 0]], map(range(1, 6), 'synconcealed(2, v:val)'))
+ call AssertFails("syntax match Entity '&amp;' conceal cchar=\<Tab>", 'E844:')
+
syn clear
set conceallevel&
bw!
endfunc
func Test_bg_detection()
- if has('gui_running')
- return
- endif
+ CheckNotGui
+
" auto-detection of &bg, make sure sure it isn't set anywhere before
" this test
hi Normal ctermbg=0
@@ -560,15 +625,15 @@ func Test_synstack_synIDtrans()
call assert_equal(['cComment', 'cTodo'], map(synstack(line("."), col(".")), 'synIDattr(v:val, "name")'))
call assert_equal(['Comment', 'Todo'], map(synstack(line("."), col(".")), 'synIDattr(synIDtrans(v:val), "name")'))
+ call assert_fails("let n=synIDtrans([])", 'E745:')
+
syn clear
bw!
endfunc
" Check highlighting for a small piece of C code with a screen dump.
func Test_syntax_c()
- if !CanRunVimInTerminal()
- throw 'Skipped: cannot make screendumps'
- endif
+ CheckRunVimInTerminal
call writefile([
\ '/* comment line at the top */',
\ 'int main(int argc, char **argv) { // another comment',
@@ -603,6 +668,24 @@ func Test_syntax_c()
call delete('Xtest.c')
endfun
+" Test \z(...) along with \z1
+func Test_syn_zsub()
+ new
+ syntax on
+ call setline(1, 'xxx start foo xxx not end foo xxx end foo xxx')
+ let l:expected = ' ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ '
+
+ for l:re in [0, 1, 2]
+ " Example taken from :help :syn-ext-match
+ syntax region Z start="start \z(\I\i*\)" skip="not end \z1" end="end \z1"
+ eval AssertHighlightGroups(1, 1, l:expected, 1, 'regexp=' .. l:re)
+ syntax clear Z
+ endfor
+
+ set re&
+ bw!
+endfunc
+
" Using \z() in a region with NFA failing should not crash.
func Test_syn_wrong_z_one()
new
diff --git a/src/nvim/testdir/test_system.vim b/src/nvim/testdir/test_system.vim
index 18692f42c9..6c8373b335 100644
--- a/src/nvim/testdir/test_system.vim
+++ b/src/nvim/testdir/test_system.vim
@@ -141,3 +141,5 @@ func Test_system_with_shell_quote()
call delete('Xdir with spaces', 'rf')
endtry
endfunc
+
+" vim: shiftwidth=2 sts=2 expandtab
diff --git a/src/nvim/testdir/test_tabline.vim b/src/nvim/testdir/test_tabline.vim
index e58a412c5a..d9bef09067 100644
--- a/src/nvim/testdir/test_tabline.vim
+++ b/src/nvim/testdir/test_tabline.vim
@@ -1,6 +1,9 @@
" Test for tabline
source shared.vim
+source view_util.vim
+source check.vim
+source screendump.vim
func TablineWithCaughtError()
let s:func_in_tabline_called = 1
@@ -147,4 +150,58 @@ func Test_tabline_20_format_items_no_overrun()
set showtabline& tabline&
endfunc
+func Test_mouse_click_in_tab()
+ " This used to crash because TabPageIdxs[] was not initialized
+ let lines =<< trim END
+ tabnew
+ set mouse=a
+ exe "norm \<LeftMouse>"
+ END
+ call writefile(lines, 'Xclickscript')
+ call RunVim([], [], "-e -s -S Xclickscript -c qa")
+
+ call delete('Xclickscript')
+endfunc
+
+func Test_tabline_showcmd()
+ CheckScreendump
+
+ let lines =<< trim END
+ func MyTabLine()
+ return '%S'
+ endfunc
+
+ set showtabline=2
+ set tabline=%!MyTabLine()
+ set showcmdloc=tabline
+ call setline(1, ['a', 'b', 'c'])
+ set foldopen+=jump
+ 1,2fold
+ 3
+ END
+ call writefile(lines, 'XTest_tabline', 'D')
+
+ let buf = RunVimInTerminal('-S XTest_tabline', {'rows': 6})
+
+ call term_sendkeys(buf, "g")
+ call VerifyScreenDump(buf, 'Test_tabline_showcmd_1', {})
+
+ " typing "gg" should open the fold
+ call term_sendkeys(buf, "g")
+ call VerifyScreenDump(buf, 'Test_tabline_showcmd_2', {})
+
+ call term_sendkeys(buf, "\<C-V>Gl")
+ call VerifyScreenDump(buf, 'Test_tabline_showcmd_3', {})
+
+ call term_sendkeys(buf, "\<Esc>1234")
+ call VerifyScreenDump(buf, 'Test_tabline_showcmd_4', {})
+
+ call term_sendkeys(buf, "\<Esc>:set tabline=\<CR>")
+ call term_sendkeys(buf, ":\<CR>")
+ call term_sendkeys(buf, "1234")
+ call VerifyScreenDump(buf, 'Test_tabline_showcmd_5', {})
+
+ call StopVimInTerminal(buf)
+endfunc
+
" vim: shiftwidth=2 sts=2 expandtab
diff --git a/src/nvim/testdir/test_tabpage.vim b/src/nvim/testdir/test_tabpage.vim
index 6d468ec9de..b97aa409d8 100644
--- a/src/nvim/testdir/test_tabpage.vim
+++ b/src/nvim/testdir/test_tabpage.vim
@@ -591,9 +591,7 @@ func Test_tabs()
endfunc
func Test_tabpage_cmdheight()
- if !CanRunVimInTerminal()
- throw 'Skipped: cannot make screendumps'
- endif
+ CheckRunVimInTerminal
call writefile([
\ 'set laststatus=2',
\ 'set cmdheight=2',
@@ -623,6 +621,17 @@ func Test_tabpage_close_cmdwin()
tabonly
endfunc
+" Pressing <C-PageUp> in insert mode should go to the previous tab page
+" and <C-PageDown> should go to the next tab page
+func Test_tabpage_Ctrl_Pageup()
+ tabnew
+ call feedkeys("i\<C-PageUp>", 'xt')
+ call assert_equal(1, tabpagenr())
+ call feedkeys("i\<C-PageDown>", 'xt')
+ call assert_equal(2, tabpagenr())
+ %bw!
+endfunc
+
" Return the terminal key code for selecting a tab page from the tabline. This
" sequence contains the following codes: a CSI (0x9b), KS_TABLINE (0xf0),
" KS_FILLER (0x58) and then the tab page number.
diff --git a/src/nvim/testdir/test_tagfunc.vim b/src/nvim/testdir/test_tagfunc.vim
index ffc1d63b90..cba96d3504 100644
--- a/src/nvim/testdir/test_tagfunc.vim
+++ b/src/nvim/testdir/test_tagfunc.vim
@@ -1,5 +1,9 @@
" Test 'tagfunc'
+source vim9.vim
+source check.vim
+source screendump.vim
+
func TagFunc(pat, flag, info)
let g:tagfunc_args = [a:pat, a:flag, a:info]
let tags = []
@@ -85,7 +89,7 @@ func Test_tagfunc()
return v:null
endfunc
set tags= tfu=NullTagFunc
- call assert_fails('tag nothing', 'E426')
+ call assert_fails('tag nothing', 'E433')
delf NullTagFunc
bwipe!
@@ -117,4 +121,297 @@ func Test_tagfunc_settagstack()
delfunc Mytagfunc2
endfunc
+" Script local tagfunc callback function
+func s:ScriptLocalTagFunc(pat, flags, info)
+ let g:ScriptLocalFuncArgs = [a:pat, a:flags, a:info]
+ return v:null
+endfunc
+
+" Test for different ways of setting the 'tagfunc' option
+func Test_tagfunc_callback()
+ func TagFunc1(callnr, pat, flags, info)
+ let g:TagFunc1Args = [a:callnr, a:pat, a:flags, a:info]
+ return v:null
+ endfunc
+ func TagFunc2(pat, flags, info)
+ let g:TagFunc2Args = [a:pat, a:flags, a:info]
+ return v:null
+ endfunc
+
+ let lines =<< trim END
+ #" Test for using a function name
+ LET &tagfunc = 'g:TagFunc2'
+ new
+ LET g:TagFunc2Args = []
+ call assert_fails('tag a10', 'E433:')
+ call assert_equal(['a10', '', {}], g:TagFunc2Args)
+ bw!
+
+ #" Test for using a function()
+ set tagfunc=function('g:TagFunc1',\ [10])
+ new
+ LET g:TagFunc1Args = []
+ call assert_fails('tag a11', 'E433:')
+ call assert_equal([10, 'a11', '', {}], g:TagFunc1Args)
+ bw!
+
+ #" Using a funcref variable to set 'tagfunc'
+ VAR Fn = function('g:TagFunc1', [11])
+ LET &tagfunc = Fn
+ new
+ LET g:TagFunc1Args = []
+ call assert_fails('tag a12', 'E433:')
+ call assert_equal([11, 'a12', '', {}], g:TagFunc1Args)
+ bw!
+
+ #" Using a string(funcref_variable) to set 'tagfunc'
+ LET Fn = function('g:TagFunc1', [12])
+ LET &tagfunc = string(Fn)
+ new
+ LET g:TagFunc1Args = []
+ call assert_fails('tag a12', 'E433:')
+ call assert_equal([12, 'a12', '', {}], g:TagFunc1Args)
+ bw!
+
+ #" Test for using a funcref()
+ set tagfunc=funcref('g:TagFunc1',\ [13])
+ new
+ LET g:TagFunc1Args = []
+ call assert_fails('tag a13', 'E433:')
+ call assert_equal([13, 'a13', '', {}], g:TagFunc1Args)
+ bw!
+
+ #" Using a funcref variable to set 'tagfunc'
+ LET Fn = funcref('g:TagFunc1', [14])
+ LET &tagfunc = Fn
+ new
+ LET g:TagFunc1Args = []
+ call assert_fails('tag a14', 'E433:')
+ call assert_equal([14, 'a14', '', {}], g:TagFunc1Args)
+ bw!
+
+ #" Using a string(funcref_variable) to set 'tagfunc'
+ LET Fn = funcref('g:TagFunc1', [15])
+ LET &tagfunc = string(Fn)
+ new
+ LET g:TagFunc1Args = []
+ call assert_fails('tag a14', 'E433:')
+ call assert_equal([15, 'a14', '', {}], g:TagFunc1Args)
+ bw!
+
+ #" Test for using a lambda function
+ VAR optval = "LSTART a, b, c LMIDDLE TagFunc1(16, a, b, c) LEND"
+ LET optval = substitute(optval, ' ', '\\ ', 'g')
+ exe "set tagfunc=" .. optval
+ new
+ LET g:TagFunc1Args = []
+ call assert_fails('tag a17', 'E433:')
+ call assert_equal([16, 'a17', '', {}], g:TagFunc1Args)
+ bw!
+
+ #" Set 'tagfunc' to a lambda expression
+ LET &tagfunc = LSTART a, b, c LMIDDLE TagFunc1(17, a, b, c) LEND
+ new
+ LET g:TagFunc1Args = []
+ call assert_fails('tag a18', 'E433:')
+ call assert_equal([17, 'a18', '', {}], g:TagFunc1Args)
+ bw!
+
+ #" Set 'tagfunc' to a string(lambda expression)
+ LET &tagfunc = 'LSTART a, b, c LMIDDLE TagFunc1(18, a, b, c) LEND'
+ new
+ LET g:TagFunc1Args = []
+ call assert_fails('tag a18', 'E433:')
+ call assert_equal([18, 'a18', '', {}], g:TagFunc1Args)
+ bw!
+
+ #" Set 'tagfunc' to a variable with a lambda expression
+ VAR Lambda = LSTART a, b, c LMIDDLE TagFunc1(19, a, b, c) LEND
+ LET &tagfunc = Lambda
+ new
+ LET g:TagFunc1Args = []
+ call assert_fails("tag a19", "E433:")
+ call assert_equal([19, 'a19', '', {}], g:TagFunc1Args)
+ bw!
+
+ #" Set 'tagfunc' to a string(variable with a lambda expression)
+ LET Lambda = LSTART a, b, c LMIDDLE TagFunc1(20, a, b, c) LEND
+ LET &tagfunc = string(Lambda)
+ new
+ LET g:TagFunc1Args = []
+ call assert_fails("tag a19", "E433:")
+ call assert_equal([20, 'a19', '', {}], g:TagFunc1Args)
+ bw!
+
+ #" Test for using a lambda function with incorrect return value
+ LET Lambda = LSTART a, b, c LMIDDLE strlen(a) LEND
+ LET &tagfunc = string(Lambda)
+ new
+ call assert_fails("tag a20", "E987:")
+ bw!
+
+ #" Test for clearing the 'tagfunc' option
+ set tagfunc=''
+ set tagfunc&
+ call assert_fails("set tagfunc=function('abc')", "E700:")
+ call assert_fails("set tagfunc=funcref('abc')", "E700:")
+
+ #" set 'tagfunc' to a non-existing function
+ LET &tagfunc = function('g:TagFunc2', [21])
+ LET g:TagFunc2Args = []
+ call assert_fails("set tagfunc=function('NonExistingFunc')", 'E700:')
+ call assert_fails("LET &tagfunc = function('NonExistingFunc')", 'E700:')
+ call assert_fails("tag axb123", 'E426:')
+ call assert_equal([], g:TagFunc2Args)
+ bw!
+ END
+ call CheckLegacyAndVim9Success(lines)
+
+ " Test for using a script-local function name
+ func s:TagFunc3(pat, flags, info)
+ let g:TagFunc3Args = [a:pat, a:flags, a:info]
+ return v:null
+ endfunc
+ set tagfunc=s:TagFunc3
+ new
+ let g:TagFunc3Args = []
+ call assert_fails('tag a21', 'E433:')
+ call assert_equal(['a21', '', {}], g:TagFunc3Args)
+ bw!
+ let &tagfunc = 's:TagFunc3'
+ new
+ let g:TagFunc3Args = []
+ call assert_fails('tag a22', 'E433:')
+ call assert_equal(['a22', '', {}], g:TagFunc3Args)
+ bw!
+ delfunc s:TagFunc3
+
+ " invalid return value
+ let &tagfunc = "{a -> 'abc'}"
+ call assert_fails("echo taglist('a')", "E987:")
+
+ " Using Vim9 lambda expression in legacy context should fail
+ " set tagfunc=(a,\ b,\ c)\ =>\ g:TagFunc1(21,\ a,\ b,\ c)
+ new
+ let g:TagFunc1Args = []
+ " call assert_fails("tag a17", "E117:")
+ call assert_equal([], g:TagFunc1Args)
+ bw!
+
+ " Test for using a script local function
+ set tagfunc=<SID>ScriptLocalTagFunc
+ new
+ let g:ScriptLocalFuncArgs = []
+ call assert_fails('tag a15', 'E433:')
+ call assert_equal(['a15', '', {}], g:ScriptLocalFuncArgs)
+ bw!
+
+ " Test for using a script local funcref variable
+ let Fn = function("s:ScriptLocalTagFunc")
+ let &tagfunc= Fn
+ new
+ let g:ScriptLocalFuncArgs = []
+ call assert_fails('tag a16', 'E433:')
+ call assert_equal(['a16', '', {}], g:ScriptLocalFuncArgs)
+ bw!
+
+ " Test for using a string(script local funcref variable)
+ let Fn = function("s:ScriptLocalTagFunc")
+ let &tagfunc= string(Fn)
+ new
+ let g:ScriptLocalFuncArgs = []
+ call assert_fails('tag a16', 'E433:')
+ call assert_equal(['a16', '', {}], g:ScriptLocalFuncArgs)
+ bw!
+
+ " set 'tagfunc' to a partial with dict. This used to cause a crash.
+ func SetTagFunc()
+ let params = {'tagfn': function('g:DictTagFunc')}
+ let &tagfunc = params.tagfn
+ endfunc
+ func g:DictTagFunc(_) dict
+ endfunc
+ call SetTagFunc()
+ new
+ call SetTagFunc()
+ bw
+ call test_garbagecollect_now()
+ new
+ set tagfunc=
+ wincmd w
+ set tagfunc=
+ :%bw!
+ delfunc g:DictTagFunc
+ delfunc SetTagFunc
+
+ " Vim9 tests
+ let lines =<< trim END
+ vim9script
+
+ def Vim9tagFunc(callnr: number, pat: string, flags: string, info: dict<any>): any
+ g:Vim9tagFuncArgs = [callnr, pat, flags, info]
+ return null
+ enddef
+
+ # Test for using a def function with completefunc
+ set tagfunc=function('Vim9tagFunc',\ [60])
+ new
+ g:Vim9tagFuncArgs = []
+ assert_fails('tag a10', 'E433:')
+ assert_equal([60, 'a10', '', {}], g:Vim9tagFuncArgs)
+
+ # Test for using a global function name
+ &tagfunc = g:TagFunc2
+ new
+ g:TagFunc2Args = []
+ assert_fails('tag a11', 'E433:')
+ assert_equal(['a11', '', {}], g:TagFunc2Args)
+ bw!
+
+ # Test for using a script-local function name
+ def s:LocalTagFunc(pat: string, flags: string, info: dict<any> ): any
+ g:LocalTagFuncArgs = [pat, flags, info]
+ return null
+ enddef
+ &tagfunc = s:LocalTagFunc
+ new
+ g:LocalTagFuncArgs = []
+ assert_fails('tag a12', 'E433:')
+ assert_equal(['a12', '', {}], g:LocalTagFuncArgs)
+ bw!
+ END
+ call CheckScriptSuccess(lines)
+
+ " cleanup
+ delfunc TagFunc1
+ delfunc TagFunc2
+ set tagfunc&
+ %bw!
+endfunc
+
+func Test_tagfunc_wipes_buffer()
+ func g:Tag0unc0(t,f,o)
+ bwipe
+ endfunc
+ set tagfunc=g:Tag0unc0
+ new
+ cal assert_fails('tag 0', 'E987:')
+
+ delfunc g:Tag0unc0
+ set tagfunc=
+endfunc
+
+func Test_tagfunc_closes_window()
+ split any
+ func MytagfuncClose(pat, flags, info)
+ close
+ return [{'name' : 'mytag', 'filename' : 'Xtest', 'cmd' : '1'}]
+ endfunc
+ set tagfunc=MytagfuncClose
+ call assert_fails('tag xyz', 'E1299:')
+
+ set tagfunc=
+endfunc
+
+
" vim: shiftwidth=2 sts=2 expandtab
diff --git a/src/nvim/testdir/test_tagjump.vim b/src/nvim/testdir/test_tagjump.vim
index 04c0218f74..be60a3535c 100644
--- a/src/nvim/testdir/test_tagjump.vim
+++ b/src/nvim/testdir/test_tagjump.vim
@@ -8,7 +8,7 @@ func Test_ptag_with_notagstack()
CheckFeature quickfix
set notagstack
- call assert_fails('ptag does_not_exist_tag_name', 'E426')
+ call assert_fails('ptag does_not_exist_tag_name', 'E433')
set tagstack&vim
endfunc
@@ -184,6 +184,10 @@ function Test_keyword_jump()
call search("start")
exe "normal! 5\<C-W>\<C-I>"
call assert_equal(" start OK if found this line", getline('.'))
+
+ " invalid tag search pattern
+ call assert_fails('tag /\%(/', 'E426:')
+
enew! | only
call delete('Xtestfile')
call delete('Xinclude')
@@ -227,15 +231,13 @@ func Test_tag_symbolic()
endfunc
" Tests for tag search with !_TAG_FILE_ENCODING.
-" Depends on the test83-tags2 and test83-tags3 files.
func Test_tag_file_encoding()
- throw 'skipped: Nvim removed test83-tags2, test83-tags3'
if has('vms')
- return
+ throw 'Skipped: does not work on VMS'
endif
if !has('iconv') || iconv("\x82\x60", "cp932", "utf-8") != "\uff21"
- return
+ throw 'Skipped: iconv does not work'
endif
let save_enc = &encoding
@@ -260,18 +262,31 @@ func Test_tag_file_encoding()
" case2:
new
- set tags=test83-tags2
+ let content = ['!_TAG_FILE_ENCODING cp932 //',
+ \ "\x82`\x82a\x82b Xtags2.txt /\x82`\x82a\x82b"]
+ call writefile(content, 'Xtags')
+ set tags=Xtags
tag /.BC
call assert_equal('Xtags2.txt', expand('%:t'))
call assert_equal('ABC', getline('.'))
+ call delete('Xtags')
close
" case3:
new
- set tags=test83-tags3
+ let contents = [
+ \ "!_TAG_FILE_SORTED 1 //",
+ \ "!_TAG_FILE_ENCODING cp932 //"]
+ for i in range(1, 100)
+ call add(contents, 'abc' .. i
+ \ .. " Xtags3.txt /\x82`\x82a\x82b")
+ endfor
+ call writefile(contents, 'Xtags')
+ set tags=Xtags
tag abc50
call assert_equal('Xtags3.txt', expand('%:t'))
call assert_equal('ABC', getline('.'))
+ call delete('Xtags')
close
set tags&
@@ -282,6 +297,7 @@ func Test_tag_file_encoding()
call delete('Xtags1')
endfunc
+" Test for emacs-style tags file (TAGS)
func Test_tagjump_etags()
if !has('emacs_tags')
return
@@ -322,6 +338,7 @@ func Test_tagjump_etags()
\ ], 'Xtags2')
tag main
call assert_equal(2, line('.'))
+ call assert_fails('tag bar', 'E426:')
" corrupted tag line
call writefile([
@@ -345,7 +362,28 @@ func Test_tagjump_etags()
\ "Xmain.c,64",
\ ";;;;\x7f1,0",
\ ], 'Xtags')
- call assert_fails('tag foo', 'E426:')
+ call assert_fails('tag foo', 'E431:')
+
+ " end of file after a CTRL-L line
+ call writefile([
+ \ "\x0c",
+ \ "Xmain.c,64",
+ \ "void foo() {}\x7ffoo\x011,0",
+ \ "\x0c",
+ \ ], 'Xtags')
+ call assert_fails('tag main', 'E426:')
+
+ " error in an included tags file
+ call writefile([
+ \ "\x0c",
+ \ "Xtags2,include"
+ \ ], 'Xtags')
+ call writefile([
+ \ "\x0c",
+ \ "Xmain.c,64",
+ \ "void foo() {}",
+ \ ], 'Xtags2')
+ call assert_fails('tag foo', 'E431:')
call delete('Xtags')
call delete('Xtags2')
@@ -371,6 +409,7 @@ func Test_getsettagstack()
call assert_fails("call settagstack(1, {'items' : 10})", 'E714')
call assert_fails("call settagstack(1, {'items' : []}, 10)", 'E928')
call assert_fails("call settagstack(1, {'items' : []}, 'b')", 'E962')
+ call assert_equal(-1, settagstack(0, v:_null_dict))
set tags=Xtags
call writefile(["!_TAG_FILE_ENCODING\tutf-8\t//",
@@ -766,11 +805,11 @@ endfunc
" Test for an unsorted tags file
func Test_tag_sort()
- call writefile([
+ let l = [
\ "first\tXfoo\t1",
\ "ten\tXfoo\t3",
- \ "six\tXfoo\t2"],
- \ 'Xtags')
+ \ "six\tXfoo\t2"]
+ call writefile(l, 'Xtags')
set tags=Xtags
let code =<< trim [CODE]
int first() {}
@@ -781,7 +820,14 @@ func Test_tag_sort()
call assert_fails('tag first', 'E432:')
+ " When multiple tag files are not sorted, then message should be displayed
+ " multiple times
+ call writefile(l, 'Xtags2')
+ set tags=Xtags,Xtags2
+ call assert_fails('tag first', ['E432:', 'E432:'])
+
call delete('Xtags')
+ call delete('Xtags2')
call delete('Xfoo')
set tags&
%bwipe
@@ -1099,7 +1145,7 @@ func Test_tselect_listing()
call writefile([
\ "!_TAG_FILE_ENCODING\tutf-8\t//",
\ "first\tXfoo\t1" .. ';"' .. "\tv\ttyperef:typename:int\tfile:",
- \ "first\tXfoo\t2" .. ';"' .. "\tv\ttyperef:typename:char\tfile:"],
+ \ "first\tXfoo\t2" .. ';"' .. "\tkind:v\ttyperef:typename:char\tfile:"],
\ 'Xtags')
set tags=Xtags
@@ -1422,4 +1468,148 @@ func Test_tag_length()
set tags& taglength&
endfunc
+" Tests for errors in a tags file
+func Test_tagfile_errors()
+ set tags=Xtags
+
+ " missing search pattern or line number for a tag
+ call writefile(["!_TAG_FILE_ENCODING\tutf-8\t//",
+ \ "foo\tXfile\t"], 'Xtags', 'b')
+ call writefile(['foo'], 'Xfile')
+
+ enew
+ tag foo
+ call assert_equal('', @%)
+ let caught_431 = v:false
+ try
+ eval taglist('.*')
+ catch /:E431:/
+ let caught_431 = v:true
+ endtry
+ call assert_equal(v:true, caught_431)
+
+ " tag name and file name are not separated by a tab
+ call writefile(["!_TAG_FILE_ENCODING\tutf-8\t//",
+ \ "foo Xfile 1"], 'Xtags')
+ call assert_fails('tag foo', 'E431:')
+
+ " file name and search pattern are not separated by a tab
+ call writefile(["!_TAG_FILE_ENCODING\tutf-8\t//",
+ \ "foo\tXfile 1;"], 'Xtags')
+ call assert_fails('tag foo', 'E431:')
+
+ call delete('Xtags')
+ call delete('Xfile')
+ set tags&
+endfunc
+
+" When :stag fails to open the file, should close the new window
+func Test_stag_close_window_on_error()
+ new | only
+ set tags=Xtags
+ call writefile(["!_TAG_FILE_ENCODING\tutf-8\t//",
+ \ "foo\tXfile\t1"], 'Xtags')
+ call writefile(['foo'], 'Xfile')
+ call writefile([], '.Xfile.swp')
+ " Remove the catch-all that runtest.vim adds
+ au! SwapExists
+ augroup StagTest
+ au!
+ autocmd SwapExists Xfile let v:swapchoice='q'
+ augroup END
+
+ stag foo
+ call assert_equal(1, winnr('$'))
+ call assert_equal('', @%)
+
+ augroup StagTest
+ au!
+ augroup END
+ call delete('Xfile')
+ call delete('.Xfile.swp')
+ set tags&
+endfunc
+
+" Test for 'tagbsearch' (binary search)
+func Test_tagbsearch()
+ " If a tags file header says the tags are sorted, but the tags are actually
+ " unsorted, then binary search should fail and linear search should work.
+ call writefile([
+ \ "!_TAG_FILE_ENCODING\tutf-8\t//",
+ \ "!_TAG_FILE_SORTED\t1\t/0=unsorted, 1=sorted, 2=foldcase/",
+ \ "third\tXfoo\t3",
+ \ "second\tXfoo\t2",
+ \ "first\tXfoo\t1"],
+ \ 'Xtags')
+ set tags=Xtags
+ let code =<< trim [CODE]
+ int first() {}
+ int second() {}
+ int third() {}
+ [CODE]
+ call writefile(code, 'Xfoo')
+
+ enew
+ set tagbsearch
+ call assert_fails('tag first', 'E426:')
+ call assert_equal('', bufname())
+ call assert_fails('tag second', 'E426:')
+ call assert_equal('', bufname())
+ tag third
+ call assert_equal('Xfoo', bufname())
+ call assert_equal(3, line('.'))
+ %bw!
+
+ set notagbsearch
+ tag first
+ call assert_equal('Xfoo', bufname())
+ call assert_equal(1, line('.'))
+ enew
+ tag second
+ call assert_equal('Xfoo', bufname())
+ call assert_equal(2, line('.'))
+ enew
+ tag third
+ call assert_equal('Xfoo', bufname())
+ call assert_equal(3, line('.'))
+ %bw!
+
+ " If a tags file header says the tags are unsorted, but the tags are
+ " actually sorted, then binary search should work.
+ call writefile([
+ \ "!_TAG_FILE_ENCODING\tutf-8\t//",
+ \ "!_TAG_FILE_SORTED\t0\t/0=unsorted, 1=sorted, 2=foldcase/",
+ \ "first\tXfoo\t1",
+ \ "second\tXfoo\t2",
+ \ "third\tXfoo\t3"],
+ \ 'Xtags')
+
+ set tagbsearch
+ tag first
+ call assert_equal('Xfoo', bufname())
+ call assert_equal(1, line('.'))
+ enew
+ tag second
+ call assert_equal('Xfoo', bufname())
+ call assert_equal(2, line('.'))
+ enew
+ tag third
+ call assert_equal('Xfoo', bufname())
+ call assert_equal(3, line('.'))
+ %bw!
+
+ " Binary search fails on EOF
+ call writefile([
+ \ "!_TAG_FILE_ENCODING\tutf-8\t//",
+ \ "!_TAG_FILE_SORTED\t1\t/0=unsorted, 1=sorted, 2=foldcase/",
+ \ "bar\tXfoo\t1",
+ \ "foo\tXfoo\t2"],
+ \ 'Xtags')
+ call assert_fails('tag bbb', 'E426:')
+
+ call delete('Xtags')
+ call delete('Xfoo')
+ set tags& tagbsearch&
+endfunc
+
" vim: shiftwidth=2 sts=2 expandtab
diff --git a/src/nvim/testdir/test_taglist.vim b/src/nvim/testdir/test_taglist.vim
index be46773256..0387ef2bd8 100644
--- a/src/nvim/testdir/test_taglist.vim
+++ b/src/nvim/testdir/test_taglist.vim
@@ -36,6 +36,14 @@ func Test_taglist()
call assert_equal('d', cmd[0]['kind'])
call assert_equal('call cursor(3, 4)', cmd[0]['cmd'])
+ " Use characters with value > 127 in the tag extra field.
+ call writefile([
+ \ "vFoo\tXfoo\t4" .. ';"' .. "\ttypename:int\ta£££\tv",
+ \ ], 'Xtags')
+ call assert_equal('v', taglist('vFoo')[0].kind)
+
+ call assert_fails("let l=taglist([])", 'E730:')
+
call delete('Xtags')
set tags&
bwipe
@@ -82,13 +90,11 @@ func Test_taglist_ctags_etags()
endfunc
func Test_tags_too_long()
- call assert_fails('tag ' . repeat('x', 1020), 'E426')
+ call assert_fails('tag ' . repeat('x', 1020), ['E433', 'E426'])
tags
endfunc
func Test_tagfiles()
- " Nvim: different default for 'tags'.
- set tags=./tags,tags
call assert_equal([], tagfiles())
call writefile(["FFoo\tXfoo\t1"], 'Xtags1')
@@ -221,6 +227,11 @@ func Test_format_error()
endtry
call assert_true(caught_exception)
+ " no field after the filename for a tag
+ call writefile(["!_TAG_FILE_ENCODING\tutf-8\t//",
+ \ "foo\tXfile"], 'Xtags')
+ call assert_fails("echo taglist('foo')", 'E431:')
+
set tags&
call delete('Xtags')
endfunc
@@ -241,4 +252,30 @@ func Test_tag_complete_wildoptions()
set tags&
endfunc
+func Test_tag_complete_with_overlong_line()
+ let tagslines =<< trim END
+ !_TAG_FILE_FORMAT 2 //
+ !_TAG_FILE_SORTED 1 //
+ !_TAG_FILE_ENCODING utf-8 //
+ inboundGSV a 1;" r
+ inboundGovernor a 2;" kind:⊢ type:forall (muxMode :: MuxMode) socket peerAddr versionNumber m a b. (MonadAsync m, MonadCatch m, MonadEvaluate m, MonadThrow m, MonadThrow (STM m), MonadTime m, MonadTimer m, MonadMask m, Ord peerAddr, HasResponder muxMode ~ True) => Tracer m (RemoteTransitionTrace peerAddr) -> Tracer m (InboundGovernorTrace peerAddr) -> ServerControlChannel muxMode peerAddr ByteString m a b -> DiffTime -> MuxConnectionManager muxMode socket peerAddr versionNumber ByteString m a b -> StrictTVar m InboundGovernorObservableState -> m Void
+ inboundGovernorCounters a 3;" kind:⊢ type:InboundGovernorState muxMode peerAddr m a b -> InboundGovernorCounters
+ END
+ call writefile(tagslines, 'Xtags')
+ set tags=Xtags
+
+ " try with binary search
+ set tagbsearch
+ call feedkeys(":tag inbou\<C-A>\<C-B>\"\<CR>", 'xt')
+ call assert_equal('"tag inboundGSV inboundGovernor inboundGovernorCounters', @:)
+ " try with linear search
+ set notagbsearch
+ call feedkeys(":tag inbou\<C-A>\<C-B>\"\<CR>", 'xt')
+ call assert_equal('"tag inboundGSV inboundGovernor inboundGovernorCounters', @:)
+ set tagbsearch&
+
+ call delete('Xtags')
+ set tags&
+endfunc
+
" vim: shiftwidth=2 sts=2 expandtab
diff --git a/src/nvim/testdir/test_termcodes.vim b/src/nvim/testdir/test_termcodes.vim
index eda485c512..99bc2d1d37 100644
--- a/src/nvim/testdir/test_termcodes.vim
+++ b/src/nvim/testdir/test_termcodes.vim
@@ -1,4 +1,30 @@
+" Test for translation of special key codes (<xF1>, <xF2>, etc.)
+func Test_Keycode_Translation()
+ let keycodes = [
+ \ ["<xUp>", "<Up>"],
+ \ ["<xDown>", "<Down>"],
+ \ ["<xLeft>", "<Left>"],
+ \ ["<xRight>", "<Right>"],
+ \ ["<xHome>", "<Home>"],
+ \ ["<xEnd>", "<End>"],
+ \ ["<zHome>", "<Home>"],
+ \ ["<zEnd>", "<End>"],
+ \ ["<xF1>", "<F1>"],
+ \ ["<xF2>", "<F2>"],
+ \ ["<xF3>", "<F3>"],
+ \ ["<xF4>", "<F4>"],
+ \ ["<S-xF1>", "<S-F1>"],
+ \ ["<S-xF2>", "<S-F2>"],
+ \ ["<S-xF3>", "<S-F3>"],
+ \ ["<S-xF4>", "<S-F4>"]]
+ for [k1, k2] in keycodes
+ exe "nnoremap " .. k1 .. " 2wx"
+ call assert_true(maparg(k1, 'n', 0, 1).lhs == k2)
+ exe "nunmap " .. k1
+ endfor
+endfunc
+
" Test for terminal keycodes that doesn't have termcap entries
func Test_special_term_keycodes()
new
diff --git a/src/nvim/testdir/test_textformat.vim b/src/nvim/testdir/test_textformat.vim
index 0fc56083aa..7a13de12f4 100644
--- a/src/nvim/testdir/test_textformat.vim
+++ b/src/nvim/testdir/test_textformat.vim
@@ -962,78 +962,6 @@ func Test_tw_2_fo_tm_noai()
bwipe!
endfunc
-func Test_tw_2_fo_cqm_com()
- new
- let t =<< trim END
- {
- X
- Xa
- XaY
- XY
- XYZ
- X Y
- X YZ
- XX
- XXa
- XXY
- }
- END
- call setline(1, t)
- call cursor(2, 1)
-
- set tw=2 fo=cqm comments=n:X
- exe "normal gqgqjgqgqjgqgqjgqgqjgqgqjgqgqjgqgqjgqgqjgqgqjgqgq"
- let t =<< trim END
- X
- Xa
- XaY
- XY
- XYZ
- X Y
- X YZ
- XX
- XXa
- XXY
- END
- exe "normal o\n" . join(t, "\n")
-
- let expected =<< trim END
- {
- X
- Xa
- Xa
- XY
- XY
- XY
- XZ
- X Y
- X Y
- X Z
- XX
- XXa
- XXY
-
- X
- Xa
- Xa
- XY
- XY
- XY
- XZ
- X Y
- X Y
- X Z
- XX
- XXa
- XXY
- }
- END
- call assert_equal(expected, getline(1, '$'))
-
- set tw& fo& comments&
- bwipe!
-endfunc
-
func Test_tw_2_fo_tm_replace()
new
let t =<< trim END
@@ -1116,6 +1044,22 @@ func Test_empty_matchpairs()
bwipe!
endfunc
+func Test_mps_error()
+ let encoding_save = &encoding
+
+ " for e in ['utf-8', 'latin1']
+ for e in ['utf-8']
+ exe 'set encoding=' .. e
+
+ call assert_fails('set mps=<:', 'E474:', e)
+ call assert_fails('set mps=:>', 'E474:', e)
+ call assert_fails('set mps=<>', 'E474:', e)
+ call assert_fails('set mps=<:>_', 'E474:', e)
+ endfor
+
+ let &encoding = encoding_save
+endfunc
+
" Test for ra on multi-byte characters
func Test_ra_multibyte()
new
@@ -1161,140 +1105,6 @@ func Test_whichwrap_multi_byte()
bwipe!
endfunc
-" Test for automatically adding comment leaders in insert mode
-func Test_threepiece_comment()
- new
- setlocal expandtab
- call setline(1, ["\t/*"])
- setlocal formatoptions=croql
- call cursor(1, 3)
- call feedkeys("A\<cr>\<cr>/", 'tnix')
- call assert_equal(["\t/*", " *", " */"], getline(1, '$'))
-
- " If a comment ends in a single line, then don't add it in the next line
- %d
- call setline(1, '/* line1 */')
- call feedkeys("A\<CR>next line", 'xt')
- call assert_equal(['/* line1 */', 'next line'], getline(1, '$'))
-
- %d
- " Copy the trailing indentation from the leader comment to a new line
- setlocal autoindent noexpandtab
- call feedkeys("a\t/*\tone\ntwo\n/", 'xt')
- call assert_equal(["\t/*\tone", "\t *\ttwo", "\t */"], getline(1, '$'))
- close!
-endfunc
-
-" Test for the 'f' flag in 'comments' (only the first line has the comment
-" string)
-func Test_firstline_comment()
- new
- setlocal comments=f:- fo+=ro
- exe "normal i- B\nD\<C-C>ggoC\<C-C>ggOA\<C-C>"
- call assert_equal(['A', '- B', ' C', ' D'], getline(1, '$'))
- %d
- setlocal comments=:-
- exe "normal i- B\nD\<C-C>ggoC\<C-C>ggOA\<C-C>"
- call assert_equal(['- A', '- B', '- C', '- D'], getline(1, '$'))
- %bw!
-endfunc
-
-" Test for the 'r' flag in 'comments' (right align comment)
-func Test_comment_rightalign()
- new
- setlocal comments=sr:/***,m:**,ex-2:******/ fo+=ro
- exe "normal i=\<C-C>o\t /***\nD\n/"
- exe "normal 2GOA\<C-C>joB\<C-C>jOC\<C-C>joE\<C-C>GOF\<C-C>joG"
- let expected =<< trim END
- =
- A
- /***
- ** B
- ** C
- ** D
- ** E
- ** F
- ******/
- G
- END
- call assert_equal(expected, getline(1, '$'))
- %bw!
-endfunc
-
-" Test for the 'b' flag in 'comments'
-func Test_comment_blank()
- new
- setlocal comments=b:* fo+=ro
- exe "normal i* E\nF\n\<BS>G\nH\<C-C>ggOC\<C-C>O\<BS>B\<C-C>OA\<C-C>2joD"
- let expected =<< trim END
- A
- *B
- * C
- * D
- * E
- * F
- *G
- H
- END
- call assert_equal(expected, getline(1, '$'))
- %bw!
-endfunc
-
-" Test for the 'n' flag in comments
-func Test_comment_nested()
- new
- setlocal comments=n:> fo+=ro
- exe "normal i> B\nD\<C-C>ggOA\<C-C>joC\<C-C>Go\<BS>>>> F\nH"
- exe "normal 5GOE\<C-C>6GoG"
- let expected =<< trim END
- > A
- > B
- > C
- > D
- >>>> E
- >>>> F
- >>>> G
- >>>> H
- END
- call assert_equal(expected, getline(1, '$'))
- %bw!
-endfunc
-
-" Test for a space character in 'comments' setting
-func Test_comment_space()
- new
- setlocal comments=b:\ > fo+=ro
- exe "normal i> B\nD\<C-C>ggOA\<C-C>joC"
- exe "normal Go > F\nH\<C-C>kOE\<C-C>joG"
- let expected =<< trim END
- A
- > B
- C
- D
- > E
- > F
- > G
- > H
- END
- call assert_equal(expected, getline(1, '$'))
- %bw!
-endfunc
-
-" Test for the 'O' flag in 'comments'
-func Test_comment_O()
- new
- setlocal comments=Ob:* fo+=ro
- exe "normal i* B\nD\<C-C>kOA\<C-C>joC"
- let expected =<< trim END
- A
- * B
- * C
- * D
- END
- call assert_equal(expected, getline(1, '$'))
- %bw!
-endfunc
-
" Test for 'a' and 'w' flags in 'formatoptions'
func Test_fo_a_w()
new
@@ -1302,6 +1112,20 @@ func Test_fo_a_w()
call feedkeys("iabc abc a abc\<Esc>k0weade", 'xt')
call assert_equal(['abc abcde ', 'a abc'], getline(1, '$'))
+ " when a line ends with space, it is not broken up.
+ %d
+ call feedkeys("ione two to ", 'xt')
+ call assert_equal('one two to ', getline(1))
+
+ " when a line ends with spaces and backspace is used in the next line, the
+ " last space in the previous line should be removed.
+ %d
+ set backspace=indent,eol,start
+ call setline(1, ['one ', 'two'])
+ exe "normal 2Gi\<BS>"
+ call assert_equal(['one two'], getline(1, '$'))
+ set backspace&
+
" Test for 'a', 'w' and '1' options.
setlocal textwidth=0
setlocal fo=1aw
@@ -1334,25 +1158,6 @@ func Test_fo_a_w()
%bw!
endfunc
-" Test for 'j' flag in 'formatoptions'
-func Test_fo_j()
- new
- setlocal fo+=j comments=://
- call setline(1, ['i++; // comment1', ' // comment2'])
- normal J
- call assert_equal('i++; // comment1 comment2', getline(1))
- setlocal fo-=j
- call setline(1, ['i++; // comment1', ' // comment2'])
- normal J
- call assert_equal('i++; // comment1 // comment2', getline(1))
- " Test with nested comments
- setlocal fo+=j comments=n:>,n:)
- call setline(1, ['i++; > ) > ) comment1', ' > ) comment2'])
- normal J
- call assert_equal('i++; > ) > ) comment1 comment2', getline(1))
- %bw!
-endfunc
-
" Test for formatting lines using gq in visual mode
func Test_visual_gq_format()
new
@@ -1487,53 +1292,6 @@ func Test_fo_2()
close!
endfunc
-" Test for formatting lines where only the first line has a comment.
-func Test_fo_gq_with_firstline_comment()
- new
- setlocal formatoptions=tcq
- call setline(1, ['- one two', 'three'])
- normal gggqG
- call assert_equal(['- one two three'], getline(1, '$'))
-
- %d
- call setline(1, ['- one', '- two'])
- normal gggqG
- call assert_equal(['- one', '- two'], getline(1, '$'))
- close!
-endfunc
-
-" Test for trying to join a comment line with a non-comment line
-func Test_join_comments()
- new
- call setline(1, ['one', '/* two */', 'three'])
- normal gggqG
- call assert_equal(['one', '/* two */', 'three'], getline(1, '$'))
- close!
-endfunc
-
-" Test for using 'a' in 'formatoptions' with comments
-func Test_autoformat_comments()
- new
- setlocal formatoptions+=a
- call feedkeys("a- one\n- two\n", 'xt')
- call assert_equal(['- one', '- two', ''], getline(1, '$'))
-
- %d
- call feedkeys("a\none\n", 'xt')
- call assert_equal(['', 'one', ''], getline(1, '$'))
-
- setlocal formatoptions+=aw
- %d
- call feedkeys("aone \ntwo\n", 'xt')
- call assert_equal(['one two', ''], getline(1, '$'))
-
- %d
- call feedkeys("aone\ntwo\n", 'xt')
- call assert_equal(['one', 'two', ''], getline(1, '$'))
-
- close!
-endfunc
-
" This was leaving the cursor after the end of a line. Complicated way to
" have the problem show up with valgrind.
func Test_correct_cursor_position()
diff --git a/src/nvim/testdir/test_timers.vim b/src/nvim/testdir/test_timers.vim
index 6adf503f14..f94ee6c9f3 100644
--- a/src/nvim/testdir/test_timers.vim
+++ b/src/nvim/testdir/test_timers.vim
@@ -3,6 +3,7 @@
source check.vim
CheckFeature timers
+source screendump.vim
source shared.vim
source term_util.vim
source load.vim
@@ -46,9 +47,6 @@ endfunc
func Test_timer_repeat_many()
let g:val = 0
let timer = timer_start(50, 'MyHandler', {'repeat': -1})
- if has('mac')
- sleep 200m
- endif
sleep 200m
call timer_stop(timer)
call assert_inrange((has('mac') ? 1 : 2), LoadAdjust(5), g:val)
@@ -266,8 +264,9 @@ endfunc
func Test_timer_peek_and_get_char()
if !has('unix') && !has('gui_running')
- return
+ throw 'Skipped: cannot feed low-level input'
endif
+
call timer_start(0, 'FeedAndPeek')
let intr = timer_start(100, 'Interrupt')
let c = getchar()
@@ -277,9 +276,9 @@ endfunc
func Test_timer_getchar_zero()
if has('win32') && !has('gui_running')
- " Console: no low-level input
- return
+ throw 'Skipped: cannot feed low-level input'
endif
+ CheckFunction reltimefloat
" Measure the elapsed time to avoid a hang when it fails.
let start = reltime()
@@ -305,9 +304,7 @@ func Test_timer_ex_mode()
endfunc
func Test_timer_restore_count()
- if !CanRunVimInTerminal()
- throw 'Skipped: cannot run Vim in a terminal window'
- endif
+ CheckRunVimInTerminal
" Check that v:count is saved and restored, not changed by a timer.
call writefile([
\ 'nnoremap <expr><silent> L v:count ? v:count . "l" : "l"',
@@ -349,11 +346,13 @@ func Test_nocatch_timer_garbage_collect()
let a = {'foo', 'bar'}
endfunc
func FeedChar(id)
- call feedkeys('x', 't')
+ call feedkeys(":\<CR>", 't')
endfunc
call timer_start(300, 'FeedChar')
call timer_start(100, 'CauseAnError')
- let x = getchar()
+ let x = getchar() " wait for error in timer
+ let x = getchar(0) " read any remaining chars
+ let x = getchar(0)
set ut&
call test_override('no_wait_return', 1)
@@ -409,6 +408,30 @@ func Test_timer_invalid_callback()
call assert_fails('call timer_start(0, "0")', 'E921')
endfunc
+func Test_timer_changing_function_list()
+ CheckRunVimInTerminal
+
+ " Create a large number of functions. Should get the "more" prompt.
+ " The typing "G" triggers the timer, which changes the function table.
+ let lines =<< trim END
+ for func in map(range(1,99), "'Func' .. v:val")
+ exe "func " .. func .. "()"
+ endfunc
+ endfor
+ au CmdlineLeave : call timer_start(0, {-> 0})
+ END
+ call writefile(lines, 'XTest_timerchange')
+ let buf = RunVimInTerminal('-S XTest_timerchange', #{rows: 10})
+ call term_sendkeys(buf, ":fu\<CR>")
+ call WaitForAssert({-> assert_match('-- More --', term_getline(buf, 10))})
+ call term_sendkeys(buf, "G")
+ call WaitForAssert({-> assert_match('E454', term_getline(buf, 9))})
+ call term_sendkeys(buf, "\<Esc>")
+
+ call StopVimInTerminal(buf)
+ call delete('XTest_timerchange')
+endfunc
+
func Test_timer_using_win_execute_undo_sync()
let bufnr1 = bufnr()
new
diff --git a/src/nvim/testdir/test_trycatch.vim b/src/nvim/testdir/test_trycatch.vim
index 646594e482..ef20e03126 100644
--- a/src/nvim/testdir/test_trycatch.vim
+++ b/src/nvim/testdir/test_trycatch.vim
@@ -3,6 +3,7 @@
source check.vim
source shared.vim
+source vim9.vim
"-------------------------------------------------------------------------------
" Test environment {{{1
@@ -2000,15 +2001,34 @@ endfunc
func Test_try_catch_errors()
call assert_fails('throw |', 'E471:')
call assert_fails("throw \n ", 'E471:')
- call assert_fails('catch abc', 'E603:')
+ call assert_fails('catch abc', 'E654:')
call assert_fails('try | let i = 1| finally | catch | endtry', 'E604:')
call assert_fails('finally', 'E606:')
call assert_fails('try | finally | finally | endtry', 'E607:')
- " v8.2.3486 has been ported, but v8.2.1183 hasn't, so E170 appears here.
- " call assert_fails('try | for i in range(5) | endif | endtry', 'E580:')
- call assert_fails('try | for i in range(5) | endif | endtry', 'E170:')
+ call assert_fails('try | for i in range(5) | endif | endtry', 'E580:')
call assert_fails('try | while v:true | endtry', 'E170:')
call assert_fails('try | if v:true | endtry', 'E171:')
+
+ " this was using a negative index in cstack[]
+ let lines =<< trim END
+ try
+ for
+ if
+ endwhile
+ if
+ finally
+ END
+ call CheckScriptFailure(lines, 'E690:')
+
+ let lines =<< trim END
+ try
+ for
+ if
+ endwhile
+ if
+ endtry
+ END
+ call CheckScriptFailure(lines, 'E690:')
endfunc
" Test for verbose messages with :try :catch, and :finally {{{1
@@ -2027,16 +2047,179 @@ func Test_try_catch_verbose()
endtry
redir END
let expected = [
- \ 'Exception thrown: Vim(echo):E121: Undefined variable: i',
- \ '',
- \ 'Exception caught: Vim(echo):E121: Undefined variable: i',
- \ '',
- \ 'Exception finished: Vim(echo):E121: Undefined variable: i'
- \ ]
+ \ 'Exception thrown: Vim(echo):E121: Undefined variable: i', '',
+ \ 'Exception caught: Vim(echo):E121: Undefined variable: i', '',
+ \ 'Exception finished: Vim(echo):E121: Undefined variable: i']
+ call assert_equal(expected, split(msg, "\n"))
+
+ " Test for verbose messages displayed when an exception is discarded
+ redir => msg
+ try
+ try
+ throw 'abc'
+ finally
+ throw 'xyz'
+ endtry
+ catch
+ endtry
+ redir END
+ let expected = [
+ \ 'Exception thrown: abc', '',
+ \ 'Exception made pending: abc', '',
+ \ 'Exception thrown: xyz', '',
+ \ 'Exception discarded: abc', '',
+ \ 'Exception caught: xyz', '',
+ \ 'Exception finished: xyz']
+ call assert_equal(expected, split(msg, "\n"))
+
+ " Test for messages displayed when :throw is resumed after :finally
+ redir => msg
+ try
+ try
+ throw 'abc'
+ finally
+ endtry
+ catch
+ endtry
+ redir END
+ let expected = [
+ \ 'Exception thrown: abc', '',
+ \ 'Exception made pending: abc', '',
+ \ 'Exception resumed: abc', '',
+ \ 'Exception caught: abc', '',
+ \ 'Exception finished: abc']
+ call assert_equal(expected, split(msg, "\n"))
+
+ " Test for messages displayed when :break is resumed after :finally
+ redir => msg
+ for i in range(1)
+ try
+ break
+ finally
+ endtry
+ endfor
+ redir END
+ let expected = [':break made pending', '', ':break resumed']
call assert_equal(expected, split(msg, "\n"))
+
+ " Test for messages displayed when :continue is resumed after :finally
+ redir => msg
+ for i in range(1)
+ try
+ continue
+ finally
+ endtry
+ endfor
+ redir END
+ let expected = [':continue made pending', '', ':continue resumed']
+ call assert_equal(expected, split(msg, "\n"))
+
+ " Test for messages displayed when :return is resumed after :finally
+ func Xtest()
+ try
+ return 'vim'
+ finally
+ endtry
+ endfunc
+ redir => msg
+ call Xtest()
+ redir END
+ let expected = [
+ \ 'calling Xtest()', '',
+ \ ':return vim made pending', '',
+ \ ':return vim resumed', '',
+ \ 'Xtest returning ''vim''', '',
+ \ 'continuing in Test_try_catch_verbose']
+ call assert_equal(expected, split(msg, "\n"))
+ delfunc Xtest
+
+ " Test for messages displayed when :finish is resumed after :finally
+ call writefile(['try', 'finish', 'finally', 'endtry'], 'Xscript')
+ redir => msg
+ source Xscript
+ redir END
+ let expected = [
+ \ ':finish made pending', '',
+ \ ':finish resumed', '',
+ \ 'finished sourcing Xscript',
+ \ 'continuing in Test_try_catch_verbose']
+ call assert_equal(expected, split(msg, "\n")[1:])
+ call delete('Xscript')
+
+ " Test for messages displayed when a pending :continue is discarded by an
+ " exception in a finally handler
+ redir => msg
+ try
+ for i in range(1)
+ try
+ continue
+ finally
+ throw 'abc'
+ endtry
+ endfor
+ catch
+ endtry
+ redir END
+ let expected = [
+ \ ':continue made pending', '',
+ \ 'Exception thrown: abc', '',
+ \ ':continue discarded', '',
+ \ 'Exception caught: abc', '',
+ \ 'Exception finished: abc']
+ call assert_equal(expected, split(msg, "\n"))
+
set verbose&
endfunc
+" Test for throwing an exception from a BufEnter autocmd {{{1
+func Test_BufEnter_exception()
+ augroup bufenter_exception
+ au!
+ autocmd BufEnter Xfile1 throw 'abc'
+ augroup END
+
+ let caught_abc = 0
+ try
+ sp Xfile1
+ catch /^abc/
+ let caught_abc = 1
+ endtry
+ call assert_equal(1, caught_abc)
+ call assert_equal(1, winnr('$'))
+
+ augroup bufenter_exception
+ au!
+ augroup END
+ augroup! bufenter_exception
+ %bwipe!
+
+ " Test for recursively throwing exceptions in autocmds
+ augroup bufenter_exception
+ au!
+ autocmd BufEnter Xfile1 throw 'bufenter'
+ autocmd BufLeave Xfile1 throw 'bufleave'
+ augroup END
+
+ let ex_count = 0
+ try
+ try
+ sp Xfile1
+ catch /^bufenter/
+ let ex_count += 1
+ endtry
+ catch /^bufleave/
+ let ex_count += 10
+ endtry
+ call assert_equal(10, ex_count)
+ call assert_equal(2, winnr('$'))
+
+ augroup bufenter_exception
+ au!
+ augroup END
+ augroup! bufenter_exception
+ %bwipe!
+endfunc
+
" Test for using throw in a called function with following error {{{1
func Test_user_command_throw_in_function_call()
let lines =<< trim END
@@ -2060,6 +2243,23 @@ func Test_user_command_throw_in_function_call()
unlet g:caught
endfunc
+" Test that after reporting an uncaught exception there is no error for a
+" missing :endif
+func Test_after_exception_no_endif_error()
+ function Throw()
+ throw "Failure"
+ endfunction
+
+ function Foo()
+ if 1
+ call Throw()
+ endif
+ endfunction
+ call assert_fails('call Foo()', ['E605:', 'E605:'])
+ delfunc Throw
+ delfunc Foo
+endfunc
+
" Test for using throw in a called function with following endtry {{{1
func Test_user_command_function_call_with_endtry()
let lines =<< trim END
diff --git a/src/nvim/testdir/test_undo.vim b/src/nvim/testdir/test_undo.vim
index eb47af08d7..ee8b52caaf 100644
--- a/src/nvim/testdir/test_undo.vim
+++ b/src/nvim/testdir/test_undo.vim
@@ -3,6 +3,9 @@
" undo-able pieces. Do that by setting 'undolevels'.
" Also tests :earlier and :later.
+source check.vim
+source screendump.vim
+
func Test_undotree()
new
@@ -773,4 +776,30 @@ func Test_undo_mark()
bwipe!
endfunc
+func Test_undo_after_write()
+ " use a terminal to make undo work like when text is typed
+ CheckRunVimInTerminal
+
+ let lines =<< trim END
+ edit Xtestfile.txt
+ set undolevels=100 undofile
+ imap . <Cmd>write<CR>
+ write
+ END
+ call writefile(lines, 'Xtest_undo_after_write', 'D')
+ let buf = RunVimInTerminal('-S Xtest_undo_after_write', #{rows: 6})
+
+ call term_sendkeys(buf, "Otest.\<CR>boo!!!\<Esc>")
+ sleep 100m
+ call term_sendkeys(buf, "u")
+ call VerifyScreenDump(buf, 'Test_undo_after_write_1', {})
+
+ call term_sendkeys(buf, "u")
+ call VerifyScreenDump(buf, 'Test_undo_after_write_2', {})
+
+ call StopVimInTerminal(buf)
+ call delete('Xtestfile.txt')
+endfunc
+
+
" vim: shiftwidth=2 sts=2 expandtab
diff --git a/src/nvim/testdir/test_unlet.vim b/src/nvim/testdir/test_unlet.vim
index b02bdaab3b..4779d17906 100644
--- a/src/nvim/testdir/test_unlet.vim
+++ b/src/nvim/testdir/test_unlet.vim
@@ -1,12 +1,9 @@
" Tests for :unlet
func Test_read_only()
- try
- " this caused a crash
- unlet v:count
- catch
- call assert_true(v:exception =~ ':E795:')
- endtry
+ " these caused a crash
+ call assert_fails('unlet v:count', 'E795:')
+ call assert_fails('unlet v:errmsg', 'E795:')
endfunc
func Test_existing()
@@ -18,15 +15,19 @@ endfunc
func Test_not_existing()
unlet! does_not_exist
- try
- unlet does_not_exist
- catch
- call assert_true(v:exception =~ ':E108:')
- endtry
+ call assert_fails('unlet does_not_exist', 'E108:')
endfunc
func Test_unlet_fails()
call assert_fails('unlet v:["count"]', 'E46:')
+ call assert_fails('unlet $', 'E475:')
+ let v = {}
+ call assert_fails('unlet v[:]', 'E719:')
+ let l = []
+ call assert_fails("unlet l['k'", 'E111:')
+ let d = {'k' : 1}
+ call assert_fails("unlet d.k2", 'E716:')
+ call assert_fails("unlet {a};", 'E488:')
endfunc
func Test_unlet_env()
@@ -62,3 +63,5 @@ func Test_unlet_complete()
call feedkeys(":unlet $FOO\t\n", 'tx')
call assert_true(!exists('$FOOBAR') || empty($FOOBAR))
endfunc
+
+" vim: shiftwidth=2 sts=2 expandtab
diff --git a/src/nvim/testdir/test_user_func.vim b/src/nvim/testdir/test_user_func.vim
index 5231ef7b4f..4742293ed5 100644
--- a/src/nvim/testdir/test_user_func.vim
+++ b/src/nvim/testdir/test_user_func.vim
@@ -3,6 +3,9 @@
" Also test that a builtin function cannot be replaced.
" Also test for regression when calling arbitrary expression.
+source check.vim
+source shared.vim
+
func Table(title, ...)
let ret = a:title
let idx = 1
@@ -83,10 +86,14 @@ func Test_user_func()
normal o[(one again
call assert_equal('1. one again', getline('.'))
+ " Try to overwrite a function in the global (g:) scope
call assert_equal(3, max([1, 2, 3]))
call assert_fails("call extend(g:, {'max': function('min')})", 'E704')
call assert_equal(3, max([1, 2, 3]))
+ " Try to overwrite an user defined function with a function reference
+ call assert_fails("let Expr1 = function('min')", 'E705:')
+
" Regression: the first line below used to throw ?E110: Missing ')'?
" Second is here just to prove that this line is correct when not skipping
" rhs of &&.
@@ -142,8 +149,8 @@ func Test_default_arg()
call assert_equal(res.optional, 2)
call assert_equal(res['0'], 1)
- call assert_fails("call MakeBadFunc()", 'E989')
- call assert_fails("fu F(a=1 ,) | endf", 'E475')
+ call assert_fails("call MakeBadFunc()", 'E989:')
+ call assert_fails("fu F(a=1 ,) | endf", 'E1068:')
" Since neovim does not have v:none, the ability to use the default
" argument with the intermediate argument set to v:none has been omitted.
@@ -156,6 +163,16 @@ func Test_default_arg()
\ .. "1 return deepcopy(a:)\n"
\ .. " endfunction",
\ execute('func Args2'))
+
+ " Error in default argument expression
+ let l =<< trim END
+ func F1(x = y)
+ return a:x * 2
+ endfunc
+ echo F1()
+ END
+ let @a = l->join("\n")
+ call assert_fails("exe @a", 'E121:')
endfunc
func s:addFoo(lead)
@@ -169,3 +186,319 @@ endfunc
func Test_failed_call_in_try()
try | call UnknownFunc() | catch | endtry
endfunc
+
+" Test for listing user-defined functions
+func Test_function_list()
+ call assert_fails("function Xabc", 'E123:')
+endfunc
+
+" Test for <sfile>, <slnum> in a function
+func Test_sfile_in_function()
+ func Xfunc()
+ call assert_match('..Test_sfile_in_function\[5]..Xfunc', expand('<sfile>'))
+ call assert_equal('2', expand('<slnum>'))
+ endfunc
+ call Xfunc()
+ delfunc Xfunc
+endfunc
+
+" Test trailing text after :endfunction {{{1
+func Test_endfunction_trailing()
+ call assert_false(exists('*Xtest'))
+
+ exe "func Xtest()\necho 'hello'\nendfunc\nlet done = 'yes'"
+ call assert_true(exists('*Xtest'))
+ call assert_equal('yes', done)
+ delfunc Xtest
+ unlet done
+
+ exe "func Xtest()\necho 'hello'\nendfunc|let done = 'yes'"
+ call assert_true(exists('*Xtest'))
+ call assert_equal('yes', done)
+ delfunc Xtest
+ unlet done
+
+ " trailing line break
+ exe "func Xtest()\necho 'hello'\nendfunc\n"
+ call assert_true(exists('*Xtest'))
+ delfunc Xtest
+
+ set verbose=1
+ exe "func Xtest()\necho 'hello'\nendfunc \" garbage"
+ call assert_notmatch('W22:', split(execute('1messages'), "\n")[0])
+ call assert_true(exists('*Xtest'))
+ delfunc Xtest
+
+ exe "func Xtest()\necho 'hello'\nendfunc garbage"
+ call assert_match('W22:', split(execute('1messages'), "\n")[0])
+ call assert_true(exists('*Xtest'))
+ delfunc Xtest
+ set verbose=0
+
+ func Xtest(a1, a2)
+ echo a:a1 .. a:a2
+ endfunc
+ set verbose=15
+ redir @a
+ call Xtest(123, repeat('x', 100))
+ redir END
+ call assert_match('calling Xtest(123, ''xxxxxxx.*x\.\.\.x.*xxxx'')', getreg('a'))
+ delfunc Xtest
+ set verbose=0
+
+ function Foo()
+ echo 'hello'
+ endfunction | echo 'xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx'
+ delfunc Foo
+endfunc
+
+func Test_delfunction_force()
+ delfunc! Xtest
+ delfunc! Xtest
+ func Xtest()
+ echo 'nothing'
+ endfunc
+ delfunc! Xtest
+ delfunc! Xtest
+
+ " Try deleting the current function
+ call assert_fails('delfunc Test_delfunction_force', 'E131:')
+endfunc
+
+func Test_function_defined_line()
+ CheckNotGui
+
+ let lines =<< trim [CODE]
+ " F1
+ func F1()
+ " F2
+ func F2()
+ "
+ "
+ "
+ return
+ endfunc
+ " F3
+ execute "func F3()\n\n\n\nreturn\nendfunc"
+ " F4
+ execute "func F4()\n
+ \\n
+ \\n
+ \\n
+ \return\n
+ \endfunc"
+ endfunc
+ " F5
+ execute "func F5()\n\n\n\nreturn\nendfunc"
+ " F6
+ execute "func F6()\n
+ \\n
+ \\n
+ \\n
+ \return\n
+ \endfunc"
+ call F1()
+ verbose func F1
+ verbose func F2
+ verbose func F3
+ verbose func F4
+ verbose func F5
+ verbose func F6
+ qall!
+ [CODE]
+
+ call writefile(lines, 'Xtest.vim')
+ let res = system(GetVimCommandClean() .. ' -es -X -S Xtest.vim')
+ call assert_equal(0, v:shell_error)
+
+ let m = matchstr(res, 'function F1()[^[:print:]]*[[:print:]]*')
+ call assert_match(' line 2$', m)
+
+ let m = matchstr(res, 'function F2()[^[:print:]]*[[:print:]]*')
+ call assert_match(' line 4$', m)
+
+ let m = matchstr(res, 'function F3()[^[:print:]]*[[:print:]]*')
+ call assert_match(' line 11$', m)
+
+ let m = matchstr(res, 'function F4()[^[:print:]]*[[:print:]]*')
+ call assert_match(' line 13$', m)
+
+ let m = matchstr(res, 'function F5()[^[:print:]]*[[:print:]]*')
+ call assert_match(' line 21$', m)
+
+ let m = matchstr(res, 'function F6()[^[:print:]]*[[:print:]]*')
+ call assert_match(' line 23$', m)
+
+ call delete('Xtest.vim')
+endfunc
+
+" Test for defining a function reference in the global scope
+func Test_add_funcref_to_global_scope()
+ let x = g:
+ let caught_E862 = 0
+ try
+ func x.Xfunc()
+ return 1
+ endfunc
+ catch /E862:/
+ let caught_E862 = 1
+ endtry
+ call assert_equal(1, caught_E862)
+endfunc
+
+func Test_funccall_garbage_collect()
+ func Func(x, ...)
+ call add(a:x, a:000)
+ endfunc
+ call Func([], [])
+ " Must not crash cause by invalid freeing
+ call test_garbagecollect_now()
+ call assert_true(v:true)
+ delfunc Func
+endfunc
+
+" Test for script-local function
+func <SID>DoLast()
+ call append(line('$'), "last line")
+endfunc
+
+func s:DoNothing()
+ call append(line('$'), "nothing line")
+endfunc
+
+func Test_script_local_func()
+ set nocp nomore viminfo+=nviminfo
+ new
+ nnoremap <buffer> _x :call <SID>DoNothing()<bar>call <SID>DoLast()<bar>delfunc <SID>DoNothing<bar>delfunc <SID>DoLast<cr>
+
+ normal _x
+ call assert_equal('nothing line', getline(2))
+ call assert_equal('last line', getline(3))
+ close!
+
+ " Try to call a script local function in global scope
+ let lines =<< trim [CODE]
+ :call assert_fails('call s:Xfunc()', 'E81:')
+ :call assert_fails('let x = call("<SID>Xfunc", [])', 'E120:')
+ :call writefile(v:errors, 'Xresult')
+ :qall
+
+ [CODE]
+ call writefile(lines, 'Xscript')
+ if RunVim([], [], '-s Xscript')
+ call assert_equal([], readfile('Xresult'))
+ endif
+ call delete('Xresult')
+ call delete('Xscript')
+endfunc
+
+" Test for errors in defining new functions
+func Test_func_def_error()
+ call assert_fails('func Xfunc abc ()', 'E124:')
+ call assert_fails('func Xfunc(', 'E125:')
+ call assert_fails('func xfunc()', 'E128:')
+
+ " Try to redefine a function that is in use
+ let caught_E127 = 0
+ try
+ func! Test_func_def_error()
+ endfunc
+ catch /E127:/
+ let caught_E127 = 1
+ endtry
+ call assert_equal(1, caught_E127)
+
+ " Try to define a function in a dict twice
+ let d = {}
+ let lines =<< trim END
+ func d.F1()
+ return 1
+ endfunc
+ END
+ let l = join(lines, "\n") . "\n"
+ exe l
+ call assert_fails('exe l', 'E717:')
+
+ " Define an autoload function with an incorrect file name
+ call writefile(['func foo#Bar()', 'return 1', 'endfunc'], 'Xscript')
+ call assert_fails('source Xscript', 'E746:')
+ call delete('Xscript')
+
+ " Try to list functions using an invalid search pattern
+ call assert_fails('function /\%(/', 'E53:')
+endfunc
+
+" Test for deleting a function
+func Test_del_func()
+ call assert_fails('delfunction Xabc', 'E130:')
+ let d = {'a' : 10}
+ call assert_fails('delfunc d.a', 'E718:')
+ func d.fn()
+ return 1
+ endfunc
+
+ " cannot delete the dict function by number
+ let nr = substitute(execute('echo d'), '.*function(''\(\d\+\)'').*', '\1', '')
+ call assert_fails('delfunction g:' .. nr, 'E475: Invalid argument: g:')
+
+ delfunc d.fn
+ call assert_equal({'a' : 10}, d)
+endfunc
+
+" Test for calling return outside of a function
+func Test_return_outside_func()
+ call writefile(['return 10'], 'Xscript')
+ call assert_fails('source Xscript', 'E133:')
+ call delete('Xscript')
+endfunc
+
+" Test for errors in calling a function
+func Test_func_arg_error()
+ " Too many arguments
+ call assert_fails("call call('min', range(1,20))", 'E118:')
+ call assert_fails("call call('min', range(1,21))", 'E699:')
+ call assert_fails('echo min(0,1,2,3,4,5,6,7,8,9,1,2,3,4,5,6,7,8,9,0,1)',
+ \ 'E740:')
+
+ " Missing dict argument
+ func Xfunc() dict
+ return 1
+ endfunc
+ call assert_fails('call Xfunc()', 'E725:')
+ delfunc Xfunc
+endfunc
+
+func Test_func_dict()
+ let mydict = {'a': 'b'}
+ function mydict.somefunc() dict
+ return len(self)
+ endfunc
+
+ call assert_equal("{'a': 'b', 'somefunc': function('3')}", string(mydict))
+ call assert_equal(2, mydict.somefunc())
+ call assert_match("^\n function \\d\\\+() dict"
+ \ .. "\n1 return len(self)"
+ \ .. "\n endfunction$", execute('func mydict.somefunc'))
+ call assert_fails('call mydict.nonexist()', 'E716:')
+endfunc
+
+func Test_func_range()
+ new
+ call setline(1, range(1, 8))
+ func FuncRange() range
+ echo a:firstline
+ echo a:lastline
+ endfunc
+ 3
+ call assert_equal("\n3\n3", execute('call FuncRange()'))
+ call assert_equal("\n4\n6", execute('4,6 call FuncRange()'))
+ call assert_equal("\n function FuncRange() range"
+ \ .. "\n1 echo a:firstline"
+ \ .. "\n2 echo a:lastline"
+ \ .. "\n endfunction",
+ \ execute('function FuncRange'))
+
+ bwipe!
+endfunc
+
+" vim: shiftwidth=2 sts=2 expandtab
diff --git a/src/nvim/testdir/test_usercommands.vim b/src/nvim/testdir/test_usercommands.vim
index e37fe43b22..6910361345 100644
--- a/src/nvim/testdir/test_usercommands.vim
+++ b/src/nvim/testdir/test_usercommands.vim
@@ -79,6 +79,19 @@ function Test_cmdmods()
call assert_equal('silent!', g:mods)
tab MyCmd
call assert_equal('tab', g:mods)
+ 0tab MyCmd
+ call assert_equal('0tab', g:mods)
+ tab split
+ tab MyCmd
+ call assert_equal('tab', g:mods)
+ 1tab MyCmd
+ call assert_equal('1tab', g:mods)
+ tabprev
+ tab MyCmd
+ call assert_equal('tab', g:mods)
+ 2tab MyCmd
+ call assert_equal('2tab', g:mods)
+ 2tabclose
topleft MyCmd
call assert_equal('topleft', g:mods)
to MyCmd
@@ -101,6 +114,10 @@ function Test_cmdmods()
call assert_equal('vertical', g:mods)
vert MyCmd
call assert_equal('vertical', g:mods)
+ horizontal MyCmd
+ call assert_equal('horizontal', g:mods)
+ hor MyCmd
+ call assert_equal('horizontal', g:mods)
aboveleft belowright botright browse confirm hide keepalt keepjumps
\ keepmarks keeppatterns lockmarks noautocmd noswapfile silent
@@ -306,6 +323,11 @@ func Test_CmdErrors()
call assert_fails('com DoCmd :', 'E174:')
comclear
call assert_fails('delcom DoCmd', 'E184:')
+
+ " These used to leak memory
+ call assert_fails('com! -complete=custom,CustomComplete _ :', 'E182:')
+ call assert_fails('com! -complete=custom,CustomComplete docmd :', 'E183:')
+ call assert_fails('com! -complete=custom,CustomComplete -xxx DoCmd :', 'E181:')
endfunc
func CustomComplete(A, L, P)
@@ -313,7 +335,7 @@ func CustomComplete(A, L, P)
endfunc
func CustomCompleteList(A, L, P)
- return [ "Monday", "Tuesday", "Wednesday", {}]
+ return [ "Monday", "Tuesday", "Wednesday", {}, v:_null_string]
endfunc
func Test_CmdCompletion()
@@ -332,6 +354,14 @@ func Test_CmdCompletion()
call feedkeys(":com -complete=co\<C-A>\<C-B>\"\<CR>", 'tx')
call assert_equal('"com -complete=color command compiler', @:)
+ " try completion for unsupported argument values
+ call feedkeys(":com -newarg=\<Tab>\<C-B>\"\<CR>", 'tx')
+ call assert_equal("\"com -newarg=\t", @:)
+
+ " command completion after the name in a user defined command
+ call feedkeys(":com MyCmd chist\<Tab>\<C-B>\"\<CR>", 'tx')
+ call assert_equal("\"com MyCmd chistory", @:)
+
command! DoCmd1 :
command! DoCmd2 :
call feedkeys(":com \<C-A>\<C-B>\"\<CR>", 'tx')
@@ -343,6 +373,10 @@ func Test_CmdCompletion()
call feedkeys(":delcom DoC\<C-A>\<C-B>\"\<CR>", 'tx')
call assert_equal('"delcom DoCmd1 DoCmd2', @:)
+ " try argument completion for a command without completion
+ call feedkeys(":DoCmd1 \<Tab>\<C-B>\"\<CR>", 'tx')
+ call assert_equal("\"DoCmd1 \t", @:)
+
delcom DoCmd1
call feedkeys(":delcom DoC\<C-A>\<C-B>\"\<CR>", 'tx')
call assert_equal('"delcom DoCmd2', @:)
@@ -361,6 +395,21 @@ func Test_CmdCompletion()
call feedkeys(":DoCmd \<C-A>\<C-B>\"\<CR>", 'tx')
call assert_equal('"DoCmd mswin xterm', @:)
+ " Test for file name completion
+ com! -nargs=1 -complete=file DoCmd :
+ call feedkeys(":DoCmd READM\<Tab>\<C-B>\"\<CR>", 'tx')
+ call assert_equal('"DoCmd README.txt', @:)
+
+ " Test for buffer name completion
+ com! -nargs=1 -complete=buffer DoCmd :
+ let bnum = bufadd('BufForUserCmd')
+ call setbufvar(bnum, '&buflisted', 1)
+ call feedkeys(":DoCmd BufFor\<Tab>\<C-B>\"\<CR>", 'tx')
+ call assert_equal('"DoCmd BufForUserCmd', @:)
+ bwipe BufForUserCmd
+ call feedkeys(":DoCmd BufFor\<Tab>\<C-B>\"\<CR>", 'tx')
+ call assert_equal('"DoCmd BufFor', @:)
+
com! -nargs=* -complete=custom,CustomComplete DoCmd :
call feedkeys(":DoCmd \<C-A>\<C-B>\"\<CR>", 'tx')
call assert_equal('"DoCmd January February Mars', @:)
@@ -383,6 +432,17 @@ func Test_CmdCompletion()
com! -nargs=? -complete=custom,min DoCmd
call assert_fails("call feedkeys(':DoCmd \t', 'tx')", 'E118:')
+ " custom completion for a pattern with a backslash
+ let g:ArgLead = ''
+ func! CustCompl(A, L, P)
+ let g:ArgLead = a:A
+ return ['one', 'two', 'three']
+ endfunc
+ com! -nargs=? -complete=customlist,CustCompl DoCmd
+ call feedkeys(":DoCmd a\\\t", 'xt')
+ call assert_equal('a\', g:ArgLead)
+ delfunc CustCompl
+
delcom DoCmd
endfunc
@@ -600,6 +660,27 @@ func Test_command_list()
call assert_equal("\nNo user-defined commands found", execute('command'))
endfunc
+" Test for a custom user completion returning the wrong value type
+func Test_usercmd_custom()
+ func T1(a, c, p)
+ return "a\nb\n"
+ endfunc
+ command -nargs=* -complete=customlist,T1 TCmd1
+ call feedkeys(":TCmd1 \<C-A>\<C-B>\"\<CR>", 'xt')
+ call assert_equal('"TCmd1 ', @:)
+ delcommand TCmd1
+ delfunc T1
+
+ func T2(a, c, p)
+ return {}
+ endfunc
+ command -nargs=* -complete=customlist,T2 TCmd2
+ call feedkeys(":TCmd2 \<C-A>\<C-B>\"\<CR>", 'xt')
+ call assert_equal('"TCmd2 ', @:)
+ delcommand TCmd2
+ delfunc T2
+endfunc
+
func Test_delcommand_buffer()
command Global echo 'global'
command -buffer OneBuffer echo 'one'
@@ -640,5 +721,30 @@ func Test_recursive_define()
endwhile
endfunc
+" Test for using buffer-local ambiguous user-defined commands
+func Test_buflocal_ambiguous_usercmd()
+ new
+ command -buffer -nargs=1 -complete=sign TestCmd1 echo "Hello"
+ command -buffer -nargs=1 -complete=sign TestCmd2 echo "World"
+
+ call assert_fails("call feedkeys(':TestCmd\<CR>', 'xt')", 'E464:')
+ call feedkeys(":TestCmd \<Tab>\<C-B>\"\<CR>", 'xt')
+ call assert_equal('"TestCmd ', @:)
+
+ delcommand TestCmd1
+ delcommand TestCmd2
+ bw!
+endfunc
+
+" Test for using a multibyte character in a user command
+func Test_multibyte_in_usercmd()
+ command SubJapanesePeriodToDot exe "%s/\u3002/./g"
+ new
+ call setline(1, "Hello\u3002")
+ SubJapanesePeriodToDot
+ call assert_equal('Hello.', getline(1))
+ bw!
+ delcommand SubJapanesePeriodToDot
+endfunc
" vim: shiftwidth=2 sts=2 expandtab
diff --git a/src/nvim/testdir/test_utf8.vim b/src/nvim/testdir/test_utf8.vim
index ab3503c282..e5f6d68720 100644
--- a/src/nvim/testdir/test_utf8.vim
+++ b/src/nvim/testdir/test_utf8.vim
@@ -2,6 +2,7 @@
source check.vim
source view_util.vim
+source screendump.vim
" Visual block Insert adjusts for multi-byte char
func Test_visual_block_insert()
@@ -12,7 +13,7 @@ func Test_visual_block_insert()
bwipeout!
endfunc
-" Test for built-in function strchars()
+" Test for built-in functions strchars() and strcharlen()
func Test_strchars()
let inp = ["a", "あいa", "A\u20dd", "A\u20dd\u20dd", "\u20dd"]
let exp = [[1, 1, 1], [3, 3, 3], [2, 2, 1], [3, 3, 1], [1, 1, 1]]
@@ -21,6 +22,15 @@ func Test_strchars()
call assert_equal(exp[i][1], inp[i]->strchars(0))
call assert_equal(exp[i][2], strchars(inp[i], 1))
endfor
+
+ let exp = [1, 3, 1, 1, 1]
+ for i in range(len(inp))
+ call assert_equal(exp[i], inp[i]->strcharlen())
+ call assert_equal(exp[i], strcharlen(inp[i]))
+ endfor
+
+ call assert_fails("let v=strchars('abc', [])", 'E745:')
+ call assert_fails("let v=strchars('abc', 2)", 'E1023:')
endfunc
" Test for customlist completion
@@ -131,9 +141,13 @@ func Test_list2str_str2list_latin1()
let save_encoding = &encoding
" set encoding=latin1
-
+
let lres = str2list(s, 1)
let sres = list2str(l, 1)
+ call assert_equal([65, 66, 67], str2list("ABC"))
+
+ " Try converting a list to a string in latin-1 encoding
+ call assert_equal([1, 2, 3], str2list(list2str([1, 2, 3])))
let &encoding = save_encoding
call assert_equal(l, lres)
@@ -153,6 +167,39 @@ func Test_setcellwidths()
call assert_equal(2, strwidth("\u1339"))
call assert_equal(1, strwidth("\u133a"))
+ for aw in ['single', 'double']
+ exe 'set ambiwidth=' . aw
+ " Handle \u0080 to \u009F as control chars even on MS-Windows.
+ set isprint=@,161-255
+
+ call setcellwidths([])
+ " Control chars
+ call assert_equal(4, strwidth("\u0081"))
+ call assert_equal(6, strwidth("\uFEFF"))
+ " Ambiguous width chars
+ call assert_equal((aw == 'single') ? 1 : 2, strwidth("\u00A1"))
+ call assert_equal((aw == 'single') ? 1 : 2, strwidth("\u2010"))
+
+ call setcellwidths([[0x81, 0x81, 1], [0xA1, 0xA1, 1],
+ \ [0x2010, 0x2010, 1], [0xFEFF, 0xFEFF, 1]])
+ " Control chars
+ call assert_equal(4, strwidth("\u0081"))
+ call assert_equal(6, strwidth("\uFEFF"))
+ " Ambiguous width chars
+ call assert_equal(1, strwidth("\u00A1"))
+ call assert_equal(1, strwidth("\u2010"))
+
+ call setcellwidths([[0x81, 0x81, 2], [0xA1, 0xA1, 2],
+ \ [0x2010, 0x2010, 2], [0xFEFF, 0xFEFF, 2]])
+ " Control chars
+ call assert_equal(4, strwidth("\u0081"))
+ call assert_equal(6, strwidth("\uFEFF"))
+ " Ambiguous width chars
+ call assert_equal(2, strwidth("\u00A1"))
+ call assert_equal(2, strwidth("\u2010"))
+ endfor
+ set ambiwidth& isprint&
+
call setcellwidths([])
call assert_fails('call setcellwidths(1)', 'E714:')
@@ -185,6 +232,42 @@ func Test_setcellwidths()
call setcellwidths([])
endfunc
+func Test_getcellwidths()
+ call setcellwidths([])
+ call assert_equal([], getcellwidths())
+
+ let widthlist = [
+ \ [0x1330, 0x1330, 2],
+ \ [9999, 10000, 1],
+ \ [0x1337, 0x1339, 2],
+ \]
+ let widthlistsorted = [
+ \ [0x1330, 0x1330, 2],
+ \ [0x1337, 0x1339, 2],
+ \ [9999, 10000, 1],
+ \]
+ call setcellwidths(widthlist)
+ call assert_equal(widthlistsorted, getcellwidths())
+
+ call setcellwidths([])
+endfunc
+
+func Test_setcellwidths_dump()
+ CheckRunVimInTerminal
+
+ let lines =<< trim END
+ call setline(1, "\ue5ffDesktop")
+ END
+ call writefile(lines, 'XCellwidths', 'D')
+ let buf = RunVimInTerminal('-S XCellwidths', {'rows': 6})
+ call VerifyScreenDump(buf, 'Test_setcellwidths_dump_1', {})
+
+ call term_sendkeys(buf, ":call setcellwidths([[0xe5ff, 0xe5ff, 2]])\<CR>")
+ call VerifyScreenDump(buf, 'Test_setcellwidths_dump_2', {})
+
+ call StopVimInTerminal(buf)
+endfunc
+
func Test_print_overlong()
" Text with more composing characters than MB_MAXBYTES.
new
diff --git a/src/nvim/testdir/test_vartabs.vim b/src/nvim/testdir/test_vartabs.vim
index 68fe15ff93..e12c71d521 100644
--- a/src/nvim/testdir/test_vartabs.vim
+++ b/src/nvim/testdir/test_vartabs.vim
@@ -97,7 +97,7 @@ func Test_vartabs()
.retab!
call assert_equal("\t\t\t\tl", getline(1))
- " Test for 'retab' with same vlaues as vts
+ " Test for 'retab' with same values as vts
set ts=8 sts=0 vts=5,3,6,2 vsts=
exe "norm! S l"
.retab! 5,3,6,2
@@ -379,6 +379,8 @@ func Test_vartabs_shiftwidth()
let lines = ScreenLines([1, 3], winwidth(0))
call s:compare_lines(expect4, lines)
+ call assert_fails('call shiftwidth([])', 'E745:')
+
" cleanup
bw!
bw!
@@ -429,4 +431,18 @@ func Test_varsofttabstop()
close!
endfunc
+" Setting 'shiftwidth' to a negative value, should set it to either the value
+" of 'tabstop' (if 'vartabstop' is not set) or to the first value in
+" 'vartabstop'
+func Test_shiftwidth_vartabstop()
+ throw 'Skipped: Nvim removed this behavior in #6377'
+ setlocal tabstop=7 vartabstop=
+ call assert_fails('set shiftwidth=-1', 'E487:')
+ call assert_equal(7, &shiftwidth)
+ setlocal tabstop=7 vartabstop=5,7,10
+ call assert_fails('set shiftwidth=-1', 'E487:')
+ call assert_equal(5, &shiftwidth)
+ setlocal shiftwidth& vartabstop& tabstop&
+endfunc
+
" vim: shiftwidth=2 sts=2 expandtab
diff --git a/src/nvim/testdir/test_viminfo.vim b/src/nvim/testdir/test_viminfo.vim
new file mode 100644
index 0000000000..e792db90ab
--- /dev/null
+++ b/src/nvim/testdir/test_viminfo.vim
@@ -0,0 +1,26 @@
+
+" Test for errors in setting 'viminfo'
+func Test_viminfo_option_error()
+ " Missing number
+ call assert_fails('set viminfo=\"', 'E526:')
+ for c in split("'/:<@s", '\zs')
+ call assert_fails('set viminfo=' .. c, 'E526:')
+ endfor
+
+ " Missing comma
+ call assert_fails('set viminfo=%10!', 'E527:')
+ call assert_fails('set viminfo=!%10', 'E527:')
+ call assert_fails('set viminfo=h%10', 'E527:')
+ call assert_fails('set viminfo=c%10', 'E527:')
+ call assert_fails('set viminfo=:10%10', 'E527:')
+
+ " Missing ' setting
+ call assert_fails('set viminfo=%10', 'E528:')
+endfunc
+
+func Test_viminfo_oldfiles_newfile()
+ let v:oldfiles = v:_null_list
+ call assert_equal("\nNo old files", execute('oldfiles'))
+endfunc
+
+" vim: shiftwidth=2 sts=2 expandtab
diff --git a/src/nvim/testdir/test_vimscript.vim b/src/nvim/testdir/test_vimscript.vim
index 0f204cdd0c..b0c4baf7c2 100644
--- a/src/nvim/testdir/test_vimscript.vim
+++ b/src/nvim/testdir/test_vimscript.vim
@@ -1,16 +1,15 @@
" Test various aspects of the Vim script language.
-" Most of this was formerly in test49.
+" Most of this was formerly in test49.vim (developed by Servatius Brandt
+" <Servatius.Brandt@fujitsu-siemens.com>)
source check.vim
source shared.vim
+source script_util.vim
"-------------------------------------------------------------------------------
" Test environment {{{1
"-------------------------------------------------------------------------------
-com! XpathINIT let g:Xpath = ''
-com! -nargs=1 -bar Xpath let g:Xpath = g:Xpath . <args>
-
" Append a message to the "messages" file
func Xout(text)
split messages
@@ -20,67 +19,31 @@ endfunc
com! -nargs=1 Xout call Xout(<args>)
-" MakeScript() - Make a script file from a function. {{{2
-"
-" Create a script that consists of the body of the function a:funcname.
-" Replace any ":return" by a ":finish", any argument variable by a global
-" variable, and every ":call" by a ":source" for the next following argument
-" in the variable argument list. This function is useful if similar tests are
-" to be made for a ":return" from a function call or a ":finish" in a script
-" file.
-func MakeScript(funcname, ...)
- let script = tempname()
- execute "redir! >" . script
- execute "function" a:funcname
- redir END
- execute "edit" script
- " Delete the "function" and the "endfunction" lines. Do not include the
- " word "function" in the pattern since it might be translated if LANG is
- " set. When MakeScript() is being debugged, this deletes also the debugging
- " output of its line 3 and 4.
- exec '1,/.*' . a:funcname . '(.*)/d'
- /^\d*\s*endfunction\>/,$d
- %s/^\d*//e
- %s/return/finish/e
- %s/\<a:\(\h\w*\)/g:\1/ge
- normal gg0
- let cnt = 0
- while search('\<call\s*\%(\u\|s:\)\w*\s*(.*)', 'W') > 0
- let cnt = cnt + 1
- s/\<call\s*\%(\u\|s:\)\w*\s*(.*)/\='source ' . a:{cnt}/
- endwhile
- g/^\s*$/d
- write
- bwipeout
- return script
-endfunc
-
-" ExecAsScript - Source a temporary script made from a function. {{{2
-"
-" Make a temporary script file from the function a:funcname, ":source" it, and
-" delete it afterwards. However, if an exception is thrown the file may remain,
-" the caller should call DeleteTheScript() afterwards.
-let s:script_name = ''
-function! ExecAsScript(funcname)
- " Make a script from the function passed as argument.
- let s:script_name = MakeScript(a:funcname)
-
- " Source and delete the script.
- exec "source" s:script_name
- call delete(s:script_name)
- let s:script_name = ''
-endfunction
-
-function! DeleteTheScript()
- if s:script_name
- call delete(s:script_name)
- let s:script_name = ''
- endif
+" Create a new instance of Vim and run the commands in 'test' and then 'verify'
+" The commands in 'test' are expected to store the test results in the Xtest.out
+" file. If the test passes successfully, then Xtest.out should be empty.
+func RunInNewVim(test, verify)
+ let init =<< trim END
+ set cpo-=C " support line-continuation in sourced script
+ source script_util.vim
+ XpathINIT
+ XloopINIT
+ END
+ let cleanup =<< trim END
+ call writefile(v:errors, 'Xtest.out')
+ qall
+ END
+ call writefile(init, 'Xtest.vim')
+ call writefile(a:test, 'Xtest.vim', 'a')
+ call writefile(a:verify, 'Xverify.vim')
+ call writefile(cleanup, 'Xverify.vim', 'a')
+ call RunVim([], [], "-S Xtest.vim -S Xverify.vim")
+ call assert_equal([], readfile('Xtest.out'))
+ call delete('Xtest.out')
+ call delete('Xtest.vim')
+ call delete('Xverify.vim')
endfunc
-com! -nargs=1 -bar ExecAsScript call ExecAsScript(<f-args>)
-
-
"-------------------------------------------------------------------------------
" Test 1: :endwhile in function {{{1
"
@@ -90,7 +53,7 @@ com! -nargs=1 -bar ExecAsScript call ExecAsScript(<f-args>)
" tests will hang.
"-------------------------------------------------------------------------------
-function! T1_F()
+func T1_F()
Xpath 'a'
let first = 1
while 1
@@ -104,9 +67,9 @@ function! T1_F()
return
endif
endwhile
-endfunction
+endfunc
-function! T1_G()
+func T1_G()
Xpath 'h'
let first = 1
while 1
@@ -121,7 +84,7 @@ function! T1_G()
endif
if 1 " unmatched :if
endwhile
-endfunction
+endfunc
func Test_endwhile_function()
XpathINIT
@@ -175,7 +138,7 @@ endfunc
" Test 3: :if, :elseif, :while, :continue, :break {{{1
"-------------------------------------------------------------------------------
-function Test_if_while()
+func Test_if_while()
XpathINIT
if 1
Xpath 'a'
@@ -231,11 +194,21 @@ function Test_if_while()
call assert_equal('ab3j3b2c2b1f1h1km', g:Xpath)
endfunc
+" Check double quote after skipped "elseif" does not give error E15
+func Test_skipped_elseif()
+ if "foo" ==? "foo"
+ let result = "first"
+ elseif "foo" ==? "foo"
+ let result = "second"
+ endif
+ call assert_equal('first', result)
+endfunc
+
"-------------------------------------------------------------------------------
" Test 4: :return {{{1
"-------------------------------------------------------------------------------
-function! T4_F()
+func T4_F()
if 1
Xpath 'a'
let loops = 3
@@ -253,15 +226,15 @@ function! T4_F()
else
Xpath 'g'
endif
-endfunction
+endfunc
-function Test_return()
+func Test_return()
XpathINIT
call T4_F()
Xpath '4'
call assert_equal('ab3e3b2c24', g:Xpath)
-endfunction
+endfunc
"-------------------------------------------------------------------------------
@@ -271,14 +244,14 @@ endfunction
" test as a script file (:return replaced by :finish).
"-------------------------------------------------------------------------------
-function Test_finish()
+func Test_finish()
XpathINIT
ExecAsScript T4_F
Xpath '5'
call DeleteTheScript()
call assert_equal('ab3e3b2c25', g:Xpath)
-endfunction
+endfunc
@@ -412,7 +385,7 @@ delfunction G31
delfunction G32
delfunction G33
-function Test_defining_functions()
+func Test_defining_functions()
call assert_equal('ade2ie3ibcg0h1g1h2g2h3fg0h1g1h2g2h3m', g:test6_result)
call assert_equal('F1G1F2G21G22G23F3G31G32G33', g:test6_calls)
endfunc
@@ -476,7 +449,7 @@ endfunc
XpathINIT
-function! T8_F()
+func T8_F()
if 1
Xpath 'a'
while 1
@@ -508,9 +481,9 @@ function! T8_F()
return novar " returns (default return value 0)
Xpath 'q'
return 1 " not reached
-endfunction
+endfunc
-function! T8_G() abort
+func T8_G() abort
if 1
Xpath 'r'
while 1
@@ -524,9 +497,9 @@ function! T8_G() abort
Xpath 'x'
return -4 " not reached
-endfunction
+endfunc
-function! T8_H() abort
+func T8_H() abort
while 1
Xpath 'A'
if 1
@@ -540,7 +513,7 @@ function! T8_H() abort
Xpath 'F'
return -4 " not reached
-endfunction
+endfunc
" Aborted functions (T8_G and T8_H) return -1.
let g:test8_sum = (T8_F() + 1) - 4 * T8_G() - 8 * T8_H()
@@ -567,7 +540,7 @@ endfunc
XpathINIT
-function! F() abort
+func F() abort
Xpath 'a'
let result = G() " not aborted
Xpath 'b'
@@ -575,30 +548,30 @@ function! F() abort
Xpath 'c'
endif
return 1
-endfunction
+endfunc
-function! G() " no abort attribute
+func G() " no abort attribute
Xpath 'd'
if H() != -1 " aborted
Xpath 'e'
endif
Xpath 'f'
return 2
-endfunction
+endfunc
-function! H() abort
+func H() abort
Xpath 'g'
call I() " aborted
Xpath 'h'
return 4
-endfunction
+endfunc
-function! I() abort
+func I() abort
Xpath 'i'
asdf " error
Xpath 'j'
return 8
-endfunction
+endfunc
if F() != 1
Xpath 'k'
@@ -626,7 +599,7 @@ endfunc
XpathINIT
-function! MSG(enr, emsg)
+func MSG(enr, emsg)
let english = v:lang == "C" || v:lang =~ '^[Ee]n'
if a:enr == ""
Xout "TODO: Add message number for:" a:emsg
@@ -710,10 +683,10 @@ XpathINIT
let calls = 0
-function! P(num)
+func P(num)
let g:calls = g:calls + a:num " side effect on call
return 0
-endfunction
+endfunc
if 1
Xpath 'a'
@@ -756,23 +729,23 @@ endfunc
XpathINIT
-function! NULL()
+func NULL()
Xpath 'a'
return 0
-endfunction
+endfunc
-function! ZERO()
+func ZERO()
Xpath 'b'
return 0
-endfunction
+endfunc
-function! F0()
+func! F0()
Xpath 'c'
-endfunction
+endfunc
-function! F1(arg)
+func! F1(arg)
Xpath 'e'
-endfunction
+endfunc
let V0 = 1
@@ -1092,7 +1065,5387 @@ func Test_unmatched_if_in_while()
endfunc
"-------------------------------------------------------------------------------
+" Test 18: Interrupt (Ctrl-C pressed) {{{1
+"
+" On an interrupt, the script processing is terminated immediately.
+"-------------------------------------------------------------------------------
+
+func Test_interrupt_while_if()
+ let test =<< trim [CODE]
+ try
+ if 1
+ Xpath 'a'
+ while 1
+ Xpath 'b'
+ if 1
+ Xpath 'c'
+ call interrupt()
+ call assert_report('should not get here')
+ break
+ finish
+ endif | call assert_report('should not get here')
+ call assert_report('should not get here')
+ endwhile | call assert_report('should not get here')
+ call assert_report('should not get here')
+ endif | call assert_report('should not get here')
+ call assert_report('should not get here')
+ catch /^Vim:Interrupt$/
+ Xpath 'd'
+ endtry | Xpath 'e'
+ Xpath 'f'
+ [CODE]
+ let verify =<< trim [CODE]
+ call assert_equal('abcdef', g:Xpath)
+ [CODE]
+ call RunInNewVim(test, verify)
+endfunc
+
+func Test_interrupt_try()
+ let test =<< trim [CODE]
+ try
+ try
+ Xpath 'a'
+ call interrupt()
+ call assert_report('should not get here')
+ endtry | call assert_report('should not get here')
+ call assert_report('should not get here')
+ catch /^Vim:Interrupt$/
+ Xpath 'b'
+ endtry | Xpath 'c'
+ Xpath 'd'
+ [CODE]
+ let verify =<< trim [CODE]
+ call assert_equal('abcd', g:Xpath)
+ [CODE]
+ call RunInNewVim(test, verify)
+endfunc
+
+func Test_interrupt_func_while_if()
+ let test =<< trim [CODE]
+ func F()
+ if 1
+ Xpath 'a'
+ while 1
+ Xpath 'b'
+ if 1
+ Xpath 'c'
+ call interrupt()
+ call assert_report('should not get here')
+ break
+ return
+ endif | call assert_report('should not get here')
+ call assert_report('should not get here')
+ endwhile | call assert_report('should not get here')
+ call assert_report('should not get here')
+ endif | call assert_report('should not get here')
+ call assert_report('should not get here')
+ endfunc
+
+ Xpath 'd'
+ try
+ call F() | call assert_report('should not get here')
+ catch /^Vim:Interrupt$/
+ Xpath 'e'
+ endtry | Xpath 'f'
+ Xpath 'g'
+ [CODE]
+ let verify =<< trim [CODE]
+ call assert_equal('dabcefg', g:Xpath)
+ [CODE]
+ call RunInNewVim(test, verify)
+endfunc
+
+func Test_interrupt_func_try()
+ let test =<< trim [CODE]
+ func G()
+ try
+ Xpath 'a'
+ call interrupt()
+ call assert_report('should not get here')
+ endtry | call assert_report('should not get here')
+ call assert_report('should not get here')
+ endfunc
+
+ Xpath 'b'
+ try
+ call G() | call assert_report('should not get here')
+ catch /^Vim:Interrupt$/
+ Xpath 'c'
+ endtry | Xpath 'd'
+ Xpath 'e'
+ [CODE]
+ let verify =<< trim [CODE]
+ call assert_equal('bacde', g:Xpath)
+ [CODE]
+ call RunInNewVim(test, verify)
+endfunc
+
+"-------------------------------------------------------------------------------
+" Test 19: Aborting on errors inside :try/:endtry {{{1
+"
+" An error in a command dynamically enclosed in a :try/:endtry region
+" aborts script processing immediately. It does not matter whether
+" the failing command is outside or inside a function and whether a
+" function has an "abort" attribute.
+"-------------------------------------------------------------------------------
+
+func Test_try_error_abort_1()
+ let test =<< trim [CODE]
+ func F() abort
+ Xpath 'a'
+ asdf
+ call assert_report('should not get here')
+ endfunc
+
+ try
+ Xpath 'b'
+ call F()
+ call assert_report('should not get here')
+ endtry | call assert_report('should not get here')
+ call assert_report('should not get here')
+ [CODE]
+ let verify =<< trim [CODE]
+ call assert_equal('ba', g:Xpath)
+ [CODE]
+ call RunInNewVim(test, verify)
+endfunc
+
+func Test_try_error_abort_2()
+ let test =<< trim [CODE]
+ func G()
+ Xpath 'a'
+ asdf
+ call assert_report('should not get here')
+ endfunc
+
+ try
+ Xpath 'b'
+ call G()
+ call assert_report('should not get here')
+ endtry | call assert_report('should not get here')
+ call assert_report('should not get here')
+ [CODE]
+ let verify =<< trim [CODE]
+ call assert_equal('ba', g:Xpath)
+ [CODE]
+ call RunInNewVim(test, verify)
+endfunc
+
+func Test_try_error_abort_3()
+ let test =<< trim [CODE]
+ try
+ Xpath 'a'
+ asdf
+ call assert_report('should not get here')
+ endtry | call assert_report('should not get here')
+ call assert_report('should not get here')
+ [CODE]
+ let verify =<< trim [CODE]
+ call assert_equal('a', g:Xpath)
+ [CODE]
+ call RunInNewVim(test, verify)
+endfunc
+
+func Test_try_error_abort_4()
+ let test =<< trim [CODE]
+ if 1
+ try
+ Xpath 'a'
+ asdf
+ call assert_report('should not get here')
+ endtry | call assert_report('should not get here')
+ endif | call assert_report('should not get here')
+ call assert_report('should not get here')
+ [CODE]
+ let verify =<< trim [CODE]
+ call assert_equal('a', g:Xpath)
+ [CODE]
+ call RunInNewVim(test, verify)
+endfunc
+
+func Test_try_error_abort_5()
+ let test =<< trim [CODE]
+ let p = 1
+ while p
+ let p = 0
+ try
+ Xpath 'a'
+ asdf
+ call assert_report('should not get here')
+ endtry | call assert_report('should not get here')
+ endwhile | call assert_report('should not get here')
+ call assert_report('should not get here')
+ [CODE]
+ let verify =<< trim [CODE]
+ call assert_equal('a', g:Xpath)
+ [CODE]
+ call RunInNewVim(test, verify)
+endfunc
+
+func Test_try_error_abort_6()
+ let test =<< trim [CODE]
+ let p = 1
+ Xpath 'a'
+ while p
+ Xpath 'b'
+ let p = 0
+ try
+ Xpath 'c'
+ endwhile | call assert_report('should not get here')
+ call assert_report('should not get here')
+ [CODE]
+ let verify =<< trim [CODE]
+ call assert_equal('abc', g:Xpath)
+ [CODE]
+ call RunInNewVim(test, verify)
+endfunc
+
+"-------------------------------------------------------------------------------
+" Test 20: Aborting on errors after :try/:endtry {{{1
+"
+" When an error occurs after the last active :try/:endtry region has
+" been left, termination behavior is as if no :try/:endtry has been
+" seen.
+"-------------------------------------------------------------------------------
+
+func Test_error_after_try_1()
+ let test =<< trim [CODE]
+ let p = 1
+ while p
+ let p = 0
+ Xpath 'a'
+ try
+ Xpath 'b'
+ endtry
+ asdf
+ call assert_report('should not get here')
+ endwhile | call assert_report('should not get here')
+ Xpath 'c'
+ [CODE]
+ let verify =<< trim [CODE]
+ call assert_equal('abc', g:Xpath)
+ [CODE]
+ call RunInNewVim(test, verify)
+endfunc
+
+func Test_error_after_try_2()
+ let test =<< trim [CODE]
+ while 1
+ try
+ Xpath 'a'
+ break
+ call assert_report('should not get here')
+ endtry
+ endwhile
+ Xpath 'b'
+ asdf
+ Xpath 'c'
+ [CODE]
+ let verify =<< trim [CODE]
+ call assert_equal('abc', g:Xpath)
+ [CODE]
+ call RunInNewVim(test, verify)
+endfunc
+
+func Test_error_after_try_3()
+ let test =<< trim [CODE]
+ while 1
+ try
+ Xpath 'a'
+ break
+ call assert_report('should not get here')
+ finally
+ Xpath 'b'
+ endtry
+ endwhile
+ Xpath 'c'
+ asdf
+ Xpath 'd'
+ [CODE]
+ let verify =<< trim [CODE]
+ call assert_equal('abcd', g:Xpath)
+ [CODE]
+ call RunInNewVim(test, verify)
+endfunc
+
+func Test_error_after_try_4()
+ let test =<< trim [CODE]
+ while 1
+ try
+ Xpath 'a'
+ finally
+ Xpath 'b'
+ break
+ call assert_report('should not get here')
+ endtry
+ endwhile
+ Xpath 'c'
+ asdf
+ Xpath 'd'
+ [CODE]
+ let verify =<< trim [CODE]
+ call assert_equal('abcd', g:Xpath)
+ [CODE]
+ call RunInNewVim(test, verify)
+endfunc
+
+func Test_error_after_try_5()
+ let test =<< trim [CODE]
+ let p = 1
+ while p
+ let p = 0
+ try
+ Xpath 'a'
+ continue
+ call assert_report('should not get here')
+ endtry
+ endwhile
+ Xpath 'b'
+ asdf
+ Xpath 'c'
+ [CODE]
+ let verify =<< trim [CODE]
+ call assert_equal('abc', g:Xpath)
+ [CODE]
+ call RunInNewVim(test, verify)
+endfunc
+
+func Test_error_after_try_6()
+ let test =<< trim [CODE]
+ let p = 1
+ while p
+ let p = 0
+ try
+ Xpath 'a'
+ continue
+ call assert_report('should not get here')
+ finally
+ Xpath 'b'
+ endtry
+ endwhile
+ Xpath 'c'
+ asdf
+ Xpath 'd'
+ [CODE]
+ let verify =<< trim [CODE]
+ call assert_equal('abcd', g:Xpath)
+ [CODE]
+ call RunInNewVim(test, verify)
+endfunc
+
+func Test_error_after_try_7()
+ let test =<< trim [CODE]
+ let p = 1
+ while p
+ let p = 0
+ try
+ Xpath 'a'
+ finally
+ Xpath 'b'
+ continue
+ call assert_report('should not get here')
+ endtry
+ endwhile
+ Xpath 'c'
+ asdf
+ Xpath 'd'
+ [CODE]
+ let verify =<< trim [CODE]
+ call assert_equal('abcd', g:Xpath)
+ [CODE]
+ call RunInNewVim(test, verify)
+endfunc
+
+"-------------------------------------------------------------------------------
+" Test 21: :finally for :try after :continue/:break/:return/:finish {{{1
+"
+" If a :try conditional stays inactive due to a preceding :continue,
+" :break, :return, or :finish, its :finally clause should not be
+" executed.
+"-------------------------------------------------------------------------------
+
+func Test_finally_after_loop_ctrl_statement()
+ let test =<< trim [CODE]
+ func F()
+ let loops = 2
+ while loops > 0
+ XloopNEXT
+ let loops = loops - 1
+ try
+ if loops == 1
+ Xloop 'a'
+ continue
+ call assert_report('should not get here')
+ elseif loops == 0
+ Xloop 'b'
+ break
+ call assert_report('should not get here')
+ endif
+
+ try " inactive
+ call assert_report('should not get here')
+ finally
+ call assert_report('should not get here')
+ endtry
+ finally
+ Xloop 'c'
+ endtry
+ call assert_report('should not get here')
+ endwhile
+
+ try
+ Xpath 'd'
+ return
+ call assert_report('should not get here')
+ try " inactive
+ call assert_report('should not get here')
+ finally
+ call assert_report('should not get here')
+ endtry
+ finally
+ Xpath 'e'
+ endtry
+ call assert_report('should not get here')
+ endfunc
+
+ try
+ Xpath 'f'
+ call F()
+ Xpath 'g'
+ finish
+ call assert_report('should not get here')
+ try " inactive
+ call assert_report('should not get here')
+ finally
+ call assert_report('should not get here')
+ endtry
+ finally
+ Xpath 'h'
+ endtry
+ call assert_report('should not get here')
+ [CODE]
+ let verify =<< trim [CODE]
+ call assert_equal('fa2c2b3c3degh', g:Xpath)
+ [CODE]
+ call RunInNewVim(test, verify)
+endfunc
+
+"-------------------------------------------------------------------------------
+" Test 22: :finally for a :try after an error/interrupt/:throw {{{1
+"
+" If a :try conditional stays inactive due to a preceding error or
+" interrupt or :throw, its :finally clause should not be executed.
+"-------------------------------------------------------------------------------
+
+func Test_finally_after_error_in_func()
+ let test =<< trim [CODE]
+ func Error()
+ try
+ Xpath 'b'
+ asdf " aborting error, triggering error exception
+ call assert_report('should not get here')
+ endtry
+ call assert_report('should not get here')
+ endfunc
+
+ Xpath 'a'
+ call Error()
+ call assert_report('should not get here')
+
+ if 1 " not active due to error
+ try " not active since :if inactive
+ call assert_report('should not get here')
+ finally
+ call assert_report('should not get here')
+ endtry
+ endif
+
+ try " not active due to error
+ call assert_report('should not get here')
+ finally
+ call assert_report('should not get here')
+ endtry
+ [CODE]
+ let verify =<< trim [CODE]
+ call assert_equal('ab', g:Xpath)
+ [CODE]
+ call RunInNewVim(test, verify)
+endfunc
+
+func Test_finally_after_interrupt()
+ let test =<< trim [CODE]
+ func Interrupt()
+ try
+ Xpath 'a'
+ call interrupt() " triggering interrupt exception
+ call assert_report('should not get here')
+ endtry
+ endfunc
+
+ Xpath 'b'
+ try
+ call Interrupt()
+ catch /^Vim:Interrupt$/
+ Xpath 'c'
+ finish
+ endtry
+ call assert_report('should not get here')
+
+ if 1 " not active due to interrupt
+ try " not active since :if inactive
+ call assert_report('should not get here')
+ finally
+ call assert_report('should not get here')
+ endtry
+ endif
+
+ try " not active due to interrupt
+ call assert_report('should not get here')
+ finally
+ call assert_report('should not get here')
+ endtry
+ [CODE]
+ let verify =<< trim [CODE]
+ call assert_equal('bac', g:Xpath)
+ [CODE]
+ call RunInNewVim(test, verify)
+endfunc
+
+func Test_finally_after_throw()
+ let test =<< trim [CODE]
+ func Throw()
+ Xpath 'a'
+ throw 'xyz'
+ endfunc
+
+ Xpath 'b'
+ call Throw()
+ call assert_report('should not get here')
+
+ if 1 " not active due to :throw
+ try " not active since :if inactive
+ call assert_report('should not get here')
+ finally
+ call assert_report('should not get here')
+ endtry
+ endif
+
+ try " not active due to :throw
+ call assert_report('should not get here')
+ finally
+ call assert_report('should not get here')
+ endtry
+ [CODE]
+ let verify =<< trim [CODE]
+ call assert_equal('ba', g:Xpath)
+ [CODE]
+ call RunInNewVim(test, verify)
+endfunc
+
+"-------------------------------------------------------------------------------
+" Test 23: :catch clauses for a :try after a :throw {{{1
+"
+" If a :try conditional stays inactive due to a preceding :throw,
+" none of its :catch clauses should be executed.
+"-------------------------------------------------------------------------------
+
+func Test_catch_after_throw()
+ let test =<< trim [CODE]
+ try
+ Xpath 'a'
+ throw "xyz"
+ call assert_report('should not get here')
+
+ if 1 " not active due to :throw
+ try " not active since :if inactive
+ call assert_report('should not get here')
+ catch /xyz/
+ call assert_report('should not get here')
+ endtry
+ endif
+ catch /xyz/
+ Xpath 'b'
+ endtry
+
+ Xpath 'c'
+ throw "abc"
+ call assert_report('should not get here')
+
+ try " not active due to :throw
+ call assert_report('should not get here')
+ catch /abc/
+ call assert_report('should not get here')
+ endtry
+ [CODE]
+ let verify =<< trim [CODE]
+ call assert_equal('abc', g:Xpath)
+ [CODE]
+ call RunInNewVim(test, verify)
+endfunc
+
+"-------------------------------------------------------------------------------
+" Test 24: :endtry for a :try after a :throw {{{1
+"
+" If a :try conditional stays inactive due to a preceding :throw,
+" its :endtry should not rethrow the exception to the next surrounding
+" active :try conditional.
+"-------------------------------------------------------------------------------
+
+func Test_endtry_after_throw()
+ let test =<< trim [CODE]
+ try " try 1
+ try " try 2
+ Xpath 'a'
+ throw "xyz" " makes try 2 inactive
+ call assert_report('should not get here')
+
+ try " try 3
+ call assert_report('should not get here')
+ endtry " no rethrow to try 1
+ catch /xyz/ " should catch although try 2 inactive
+ Xpath 'b'
+ endtry
+ catch /xyz/ " try 1 active, but exception already caught
+ call assert_report('should not get here')
+ endtry
+ Xpath 'c'
+ [CODE]
+ let verify =<< trim [CODE]
+ call assert_equal('abc', g:Xpath)
+ [CODE]
+ call RunInNewVim(test, verify)
+endfunc
+
+"-------------------------------------------------------------------------------
+" Test 27: Executing :finally clauses after :return {{{1
+"
+" For a :return command dynamically enclosed in a :try/:endtry region,
+" :finally clauses are executed and the called function is ended.
+"-------------------------------------------------------------------------------
+
+func T27_F()
+ try
+ Xpath 'a'
+ try
+ Xpath 'b'
+ return
+ call assert_report('should not get here')
+ finally
+ Xpath 'c'
+ endtry
+ Xpath 'd'
+ finally
+ Xpath 'e'
+ endtry
+ call assert_report('should not get here')
+endfunc
+
+func T27_G()
+ try
+ Xpath 'f'
+ return
+ call assert_report('should not get here')
+ finally
+ Xpath 'g'
+ call T27_F()
+ Xpath 'h'
+ endtry
+ call assert_report('should not get here')
+endfunc
+
+func T27_H()
+ try
+ Xpath 'i'
+ call T27_G()
+ Xpath 'j'
+ finally
+ Xpath 'k'
+ return
+ call assert_report('should not get here')
+ endtry
+ call assert_report('should not get here')
+endfunction
+
+func Test_finally_after_return()
+ XpathINIT
+ try
+ Xpath 'l'
+ call T27_H()
+ Xpath 'm'
+ finally
+ Xpath 'n'
+ endtry
+ call assert_equal('lifgabcehjkmn', g:Xpath)
+endfunc
+
+"-------------------------------------------------------------------------------
+" Test 28: Executing :finally clauses after :finish {{{1
+"
+" For a :finish command dynamically enclosed in a :try/:endtry region,
+" :finally clauses are executed and the sourced file is finished.
+"
+" This test executes the bodies of the functions F, G, and H from the
+" previous test as script files (:return replaced by :finish).
+"-------------------------------------------------------------------------------
+
+func Test_finally_after_finish()
+ XpathINIT
+
+ let scriptF = MakeScript("T27_F")
+ let scriptG = MakeScript("T27_G", scriptF)
+ let scriptH = MakeScript("T27_H", scriptG)
+
+ try
+ Xpath 'A'
+ exec "source" scriptH
+ Xpath 'B'
+ finally
+ Xpath 'C'
+ endtry
+ Xpath 'D'
+ call assert_equal('AifgabcehjkBCD', g:Xpath)
+ call delete(scriptF)
+ call delete(scriptG)
+ call delete(scriptH)
+endfunc
+
+"-------------------------------------------------------------------------------
+" Test 29: Executing :finally clauses on errors {{{1
+"
+" After an error in a command dynamically enclosed in a :try/:endtry
+" region, :finally clauses are executed and the script processing is
+" terminated.
+"-------------------------------------------------------------------------------
+
+func Test_finally_after_error_1()
+ let test =<< trim [CODE]
+ func F()
+ while 1
+ try
+ Xpath 'a'
+ while 1
+ try
+ Xpath 'b'
+ asdf " error
+ call assert_report('should not get here')
+ finally
+ Xpath 'c'
+ endtry | call assert_report('should not get here')
+ call assert_report('should not get here')
+ break
+ endwhile
+ call assert_report('should not get here')
+ finally
+ Xpath 'd'
+ endtry | call assert_report('should not get here')
+ call assert_report('should not get here')
+ break
+ endwhile
+ call assert_report('should not get here')
+ endfunc
+
+ while 1
+ try
+ Xpath 'e'
+ while 1
+ call F()
+ call assert_report('should not get here')
+ break
+ endwhile | call assert_report('should not get here')
+ call assert_report('should not get here')
+ finally
+ Xpath 'f'
+ endtry | call assert_report('should not get here')
+ endwhile | call assert_report('should not get here')
+ call assert_report('should not get here')
+ [CODE]
+ let verify =<< trim [CODE]
+ call assert_equal('eabcdf', g:Xpath)
+ [CODE]
+ call RunInNewVim(test, verify)
+endfunc
+
+func Test_finally_after_error_2()
+ let test =<< trim [CODE]
+ func G() abort
+ if 1
+ try
+ Xpath 'a'
+ asdf " error
+ call assert_report('should not get here')
+ finally
+ Xpath 'b'
+ endtry | Xpath 'c'
+ endif | Xpath 'd'
+ call assert_report('should not get here')
+ endfunc
+
+ if 1
+ try
+ Xpath 'e'
+ call G()
+ call assert_report('should not get here')
+ finally
+ Xpath 'f'
+ endtry | call assert_report('should not get here')
+ endif | call assert_report('should not get here')
+ call assert_report('should not get here')
+ [CODE]
+ let verify =<< trim [CODE]
+ call assert_equal('eabf', g:Xpath)
+ [CODE]
+ call RunInNewVim(test, verify)
+endfunc
+
+"-------------------------------------------------------------------------------
+" Test 30: Executing :finally clauses on interrupt {{{1
+"
+" After an interrupt in a command dynamically enclosed in
+" a :try/:endtry region, :finally clauses are executed and the
+" script processing is terminated.
+"-------------------------------------------------------------------------------
+
+func Test_finally_on_interrupt()
+ let test =<< trim [CODE]
+ func F()
+ try
+ Xloop 'a'
+ call interrupt()
+ call assert_report('should not get here')
+ finally
+ Xloop 'b'
+ endtry
+ call assert_report('should not get here')
+ endfunc
+
+ try
+ try
+ Xpath 'c'
+ try
+ Xpath 'd'
+ call interrupt()
+ call assert_report('should not get here')
+ finally
+ Xpath 'e'
+ try
+ Xpath 'f'
+ try
+ Xpath 'g'
+ finally
+ Xpath 'h'
+ try
+ Xpath 'i'
+ call interrupt()
+ call assert_report('should not get here')
+ endtry
+ call assert_report('should not get here')
+ endtry
+ call assert_report('should not get here')
+ endtry
+ call assert_report('should not get here')
+ endtry
+ call assert_report('should not get here')
+ finally
+ Xpath 'j'
+ try
+ Xpath 'k'
+ call F()
+ call assert_report('should not get here')
+ finally
+ Xpath 'l'
+ try
+ Xpath 'm'
+ XloopNEXT
+ ExecAsScript F
+ call assert_report('should not get here')
+ finally
+ Xpath 'n'
+ endtry
+ call assert_report('should not get here')
+ endtry
+ call assert_report('should not get here')
+ endtry
+ call assert_report('should not get here')
+ catch /^Vim:Interrupt$/
+ Xpath 'o'
+ endtry
+ [CODE]
+ let verify =<< trim [CODE]
+ call assert_equal('cdefghijka1b1lma2b2no', g:Xpath)
+ [CODE]
+ call RunInNewVim(test, verify)
+endfunc
+
+"-------------------------------------------------------------------------------
+" Test 31: Executing :finally clauses after :throw {{{1
+"
+" After a :throw dynamically enclosed in a :try/:endtry region,
+" :finally clauses are executed and the script processing is
+" terminated.
+"-------------------------------------------------------------------------------
+
+func Test_finally_after_throw_2()
+ let test =<< trim [CODE]
+ func F()
+ try
+ Xloop 'a'
+ throw "exception"
+ call assert_report('should not get here')
+ finally
+ Xloop 'b'
+ endtry
+ call assert_report('should not get here')
+ endfunc
+
+ try
+ Xpath 'c'
+ try
+ Xpath 'd'
+ throw "exception"
+ call assert_report('should not get here')
+ finally
+ Xpath 'e'
+ try
+ Xpath 'f'
+ try
+ Xpath 'g'
+ finally
+ Xpath 'h'
+ try
+ Xpath 'i'
+ throw "exception"
+ call assert_report('should not get here')
+ endtry
+ call assert_report('should not get here')
+ endtry
+ call assert_report('should not get here')
+ endtry
+ call assert_report('should not get here')
+ endtry
+ call assert_report('should not get here')
+ finally
+ Xpath 'j'
+ try
+ Xpath 'k'
+ call F()
+ call assert_report('should not get here')
+ finally
+ Xpath 'l'
+ try
+ Xpath 'm'
+ XloopNEXT
+ ExecAsScript F
+ call assert_report('should not get here')
+ finally
+ Xpath 'n'
+ endtry
+ call assert_report('should not get here')
+ endtry
+ call assert_report('should not get here')
+ endtry
+ call assert_report('should not get here')
+ [CODE]
+ let verify =<< trim [CODE]
+ call assert_equal('cdefghijka1b1lma2b2n', g:Xpath)
+ [CODE]
+ call RunInNewVim(test, verify)
+endfunc
+
+"-------------------------------------------------------------------------------
+" Test 34: :finally reason discarded by :continue {{{1
+"
+" When a :finally clause is executed due to a :continue, :break,
+" :return, :finish, error, interrupt or :throw, the jump reason is
+" discarded by a :continue in the finally clause.
+"-------------------------------------------------------------------------------
+
+func Test_finally_after_continue()
+ let test =<< trim [CODE]
+ func C(jump)
+ XloopNEXT
+ let loop = 0
+ while loop < 2
+ let loop = loop + 1
+ if loop == 1
+ try
+ if a:jump == "continue"
+ continue
+ elseif a:jump == "break"
+ break
+ elseif a:jump == "return" || a:jump == "finish"
+ return
+ elseif a:jump == "error"
+ asdf
+ elseif a:jump == "interrupt"
+ call interrupt()
+ let dummy = 0
+ elseif a:jump == "throw"
+ throw "abc"
+ endif
+ finally
+ continue " discards jump that caused the :finally
+ call assert_report('should not get here')
+ endtry
+ call assert_report('should not get here')
+ elseif loop == 2
+ Xloop 'a'
+ endif
+ endwhile
+ endfunc
+
+ call C("continue")
+ Xpath 'b'
+ call C("break")
+ Xpath 'c'
+ call C("return")
+ Xpath 'd'
+ let g:jump = "finish"
+ ExecAsScript C
+ unlet g:jump
+ Xpath 'e'
+ try
+ call C("error")
+ Xpath 'f'
+ finally
+ Xpath 'g'
+ try
+ call C("interrupt")
+ Xpath 'h'
+ finally
+ Xpath 'i'
+ call C("throw")
+ Xpath 'j'
+ endtry
+ endtry
+ Xpath 'k'
+ [CODE]
+ let verify =<< trim [CODE]
+ call assert_equal('a2ba3ca4da5ea6fga7hia8jk', g:Xpath)
+ [CODE]
+ call RunInNewVim(test, verify)
+endfunc
+
+"-------------------------------------------------------------------------------
+" Test 35: :finally reason discarded by :break {{{1
+"
+" When a :finally clause is executed due to a :continue, :break,
+" :return, :finish, error, interrupt or :throw, the jump reason is
+" discarded by a :break in the finally clause.
+"-------------------------------------------------------------------------------
+
+func Test_finally_discard_by_break()
+ let test =<< trim [CODE]
+ func B(jump)
+ XloopNEXT
+ let loop = 0
+ while loop < 2
+ let loop = loop + 1
+ if loop == 1
+ try
+ if a:jump == "continue"
+ continue
+ elseif a:jump == "break"
+ break
+ elseif a:jump == "return" || a:jump == "finish"
+ return
+ elseif a:jump == "error"
+ asdf
+ elseif a:jump == "interrupt"
+ call interrupt()
+ let dummy = 0
+ elseif a:jump == "throw"
+ throw "abc"
+ endif
+ finally
+ break " discards jump that caused the :finally
+ call assert_report('should not get here')
+ endtry
+ elseif loop == 2
+ call assert_report('should not get here')
+ endif
+ endwhile
+ Xloop 'a'
+ endfunc
+
+ call B("continue")
+ Xpath 'b'
+ call B("break")
+ Xpath 'c'
+ call B("return")
+ Xpath 'd'
+ let g:jump = "finish"
+ ExecAsScript B
+ unlet g:jump
+ Xpath 'e'
+ try
+ call B("error")
+ Xpath 'f'
+ finally
+ Xpath 'g'
+ try
+ call B("interrupt")
+ Xpath 'h'
+ finally
+ Xpath 'i'
+ call B("throw")
+ Xpath 'j'
+ endtry
+ endtry
+ Xpath 'k'
+ [CODE]
+ let verify =<< trim [CODE]
+ call assert_equal('a2ba3ca4da5ea6fga7hia8jk', g:Xpath)
+ [CODE]
+ call RunInNewVim(test, verify)
+endfunc
+
+"-------------------------------------------------------------------------------
+" Test 36: :finally reason discarded by :return {{{1
+"
+" When a :finally clause is executed due to a :continue, :break,
+" :return, :finish, error, interrupt or :throw, the jump reason is
+" discarded by a :return in the finally clause.
+"-------------------------------------------------------------------------------
+
+func Test_finally_discard_by_return()
+ let test =<< trim [CODE]
+ func R(jump, retval) abort
+ let loop = 0
+ while loop < 2
+ let loop = loop + 1
+ if loop == 1
+ try
+ if a:jump == "continue"
+ continue
+ elseif a:jump == "break"
+ break
+ elseif a:jump == "return"
+ return
+ elseif a:jump == "error"
+ asdf
+ elseif a:jump == "interrupt"
+ call interrupt()
+ let dummy = 0
+ elseif a:jump == "throw"
+ throw "abc"
+ endif
+ finally
+ return a:retval " discards jump that caused the :finally
+ call assert_report('should not get here')
+ endtry
+ elseif loop == 2
+ call assert_report('should not get here')
+ endif
+ endwhile
+ call assert_report('should not get here')
+ endfunc
+
+ let sum = -R("continue", -8)
+ Xpath 'a'
+ let sum = sum - R("break", -16)
+ Xpath 'b'
+ let sum = sum - R("return", -32)
+ Xpath 'c'
+ try
+ let sum = sum - R("error", -64)
+ Xpath 'd'
+ finally
+ Xpath 'e'
+ try
+ let sum = sum - R("interrupt", -128)
+ Xpath 'f'
+ finally
+ Xpath 'g'
+ let sum = sum - R("throw", -256)
+ Xpath 'h'
+ endtry
+ endtry
+ Xpath 'i'
+
+ let expected = 8 + 16 + 32 + 64 + 128 + 256
+ call assert_equal(sum, expected)
+ [CODE]
+ let verify =<< trim [CODE]
+ call assert_equal('abcdefghi', g:Xpath)
+ [CODE]
+ call RunInNewVim(test, verify)
+endfunc
+
+"-------------------------------------------------------------------------------
+" Test 37: :finally reason discarded by :finish {{{1
+"
+" When a :finally clause is executed due to a :continue, :break,
+" :return, :finish, error, interrupt or :throw, the jump reason is
+" discarded by a :finish in the finally clause.
+"-------------------------------------------------------------------------------
+
+func Test_finally_discard_by_finish()
+ let test =<< trim [CODE]
+ func F(jump) " not executed as function, transformed to a script
+ let loop = 0
+ while loop < 2
+ let loop = loop + 1
+ if loop == 1
+ try
+ if a:jump == "continue"
+ continue
+ elseif a:jump == "break"
+ break
+ elseif a:jump == "finish"
+ finish
+ elseif a:jump == "error"
+ asdf
+ elseif a:jump == "interrupt"
+ call interrupt()
+ let dummy = 0
+ elseif a:jump == "throw"
+ throw "abc"
+ endif
+ finally
+ finish " discards jump that caused the :finally
+ call assert_report('should not get here')
+ endtry
+ elseif loop == 2
+ call assert_report('should not get here')
+ endif
+ endwhile
+ call assert_report('should not get here')
+ endfunc
+
+ let scriptF = MakeScript("F")
+ delfunction F
+
+ let g:jump = "continue"
+ exec "source" scriptF
+ Xpath 'a'
+ let g:jump = "break"
+ exec "source" scriptF
+ Xpath 'b'
+ let g:jump = "finish"
+ exec "source" scriptF
+ Xpath 'c'
+ try
+ let g:jump = "error"
+ exec "source" scriptF
+ Xpath 'd'
+ finally
+ Xpath 'e'
+ try
+ let g:jump = "interrupt"
+ exec "source" scriptF
+ Xpath 'f'
+ finally
+ Xpath 'g'
+ try
+ let g:jump = "throw"
+ exec "source" scriptF
+ Xpath 'h'
+ finally
+ Xpath 'i'
+ endtry
+ endtry
+ endtry
+ unlet g:jump
+ call delete(scriptF)
+ [CODE]
+ let verify =<< trim [CODE]
+ call assert_equal('abcdefghi', g:Xpath)
+ [CODE]
+ call RunInNewVim(test, verify)
+endfunc
+
+"-------------------------------------------------------------------------------
+" Test 38: :finally reason discarded by an error {{{1
+"
+" When a :finally clause is executed due to a :continue, :break,
+" :return, :finish, error, interrupt or :throw, the jump reason is
+" discarded by an error in the finally clause.
+"-------------------------------------------------------------------------------
+
+func Test_finally_discard_by_error()
+ let test =<< trim [CODE]
+ func E(jump)
+ let loop = 0
+ while loop < 2
+ let loop = loop + 1
+ if loop == 1
+ try
+ if a:jump == "continue"
+ continue
+ elseif a:jump == "break"
+ break
+ elseif a:jump == "return" || a:jump == "finish"
+ return
+ elseif a:jump == "error"
+ asdf
+ elseif a:jump == "interrupt"
+ call interrupt()
+ let dummy = 0
+ elseif a:jump == "throw"
+ throw "abc"
+ endif
+ finally
+ asdf " error; discards jump that caused the :finally
+ endtry
+ elseif loop == 2
+ call assert_report('should not get here')
+ endif
+ endwhile
+ call assert_report('should not get here')
+ endfunc
+
+ try
+ Xpath 'a'
+ call E("continue")
+ call assert_report('should not get here')
+ finally
+ try
+ Xpath 'b'
+ call E("break")
+ call assert_report('should not get here')
+ finally
+ try
+ Xpath 'c'
+ call E("return")
+ call assert_report('should not get here')
+ finally
+ try
+ Xpath 'd'
+ let g:jump = "finish"
+ ExecAsScript E
+ call assert_report('should not get here')
+ finally
+ unlet g:jump
+ try
+ Xpath 'e'
+ call E("error")
+ call assert_report('should not get here')
+ finally
+ try
+ Xpath 'f'
+ call E("interrupt")
+ call assert_report('should not get here')
+ finally
+ try
+ Xpath 'g'
+ call E("throw")
+ call assert_report('should not get here')
+ finally
+ Xpath 'h'
+ delfunction E
+ endtry
+ endtry
+ endtry
+ endtry
+ endtry
+ endtry
+ endtry
+ call assert_report('should not get here')
+ [CODE]
+ let verify =<< trim [CODE]
+ call assert_equal('abcdefgh', g:Xpath)
+ [CODE]
+ call RunInNewVim(test, verify)
+endfunc
+
+"-------------------------------------------------------------------------------
+" Test 39: :finally reason discarded by an interrupt {{{1
+"
+" When a :finally clause is executed due to a :continue, :break,
+" :return, :finish, error, interrupt or :throw, the jump reason is
+" discarded by an interrupt in the finally clause.
+"-------------------------------------------------------------------------------
+
+func Test_finally_discarded_by_interrupt()
+ let test =<< trim [CODE]
+ func I(jump)
+ let loop = 0
+ while loop < 2
+ let loop = loop + 1
+ if loop == 1
+ try
+ if a:jump == "continue"
+ continue
+ elseif a:jump == "break"
+ break
+ elseif a:jump == "return" || a:jump == "finish"
+ return
+ elseif a:jump == "error"
+ asdf
+ elseif a:jump == "interrupt"
+ call interrupt()
+ let dummy = 0
+ elseif a:jump == "throw"
+ throw "abc"
+ endif
+ finally
+ call interrupt()
+ let dummy = 0
+ endtry
+ elseif loop == 2
+ call assert_report('should not get here')
+ endif
+ endwhile
+ call assert_report('should not get here')
+ endfunc
+
+ try
+ try
+ Xpath 'a'
+ call I("continue")
+ call assert_report('should not get here')
+ finally
+ try
+ Xpath 'b'
+ call I("break")
+ call assert_report('should not get here')
+ finally
+ try
+ Xpath 'c'
+ call I("return")
+ call assert_report('should not get here')
+ finally
+ try
+ Xpath 'd'
+ let g:jump = "finish"
+ ExecAsScript I
+ call assert_report('should not get here')
+ finally
+ unlet g:jump
+ try
+ Xpath 'e'
+ call I("error")
+ call assert_report('should not get here')
+ finally
+ try
+ Xpath 'f'
+ call I("interrupt")
+ call assert_report('should not get here')
+ finally
+ try
+ Xpath 'g'
+ call I("throw")
+ call assert_report('should not get here')
+ finally
+ Xpath 'h'
+ delfunction I
+ endtry
+ endtry
+ endtry
+ endtry
+ endtry
+ endtry
+ endtry
+ call assert_report('should not get here')
+ catch /^Vim:Interrupt$/
+ Xpath 'A'
+ endtry
+ [CODE]
+ let verify =<< trim [CODE]
+ call assert_equal('abcdefghA', g:Xpath)
+ [CODE]
+ call RunInNewVim(test, verify)
+endfunc
+
+"-------------------------------------------------------------------------------
+" Test 40: :finally reason discarded by :throw {{{1
+"
+" When a :finally clause is executed due to a :continue, :break,
+" :return, :finish, error, interrupt or :throw, the jump reason is
+" discarded by a :throw in the finally clause.
+"-------------------------------------------------------------------------------
+
+func Test_finally_discard_by_throw()
+ let test =<< trim [CODE]
+ func T(jump)
+ let loop = 0
+ while loop < 2
+ let loop = loop + 1
+ if loop == 1
+ try
+ if a:jump == "continue"
+ continue
+ elseif a:jump == "break"
+ break
+ elseif a:jump == "return" || a:jump == "finish"
+ return
+ elseif a:jump == "error"
+ asdf
+ elseif a:jump == "interrupt"
+ call interrupt()
+ let dummy = 0
+ elseif a:jump == "throw"
+ throw "abc"
+ endif
+ finally
+ throw "xyz" " discards jump that caused the :finally
+ endtry
+ elseif loop == 2
+ call assert_report('should not get here')
+ endif
+ endwhile
+ call assert_report('should not get here')
+ endfunc
+
+ try
+ Xpath 'a'
+ call T("continue")
+ call assert_report('should not get here')
+ finally
+ try
+ Xpath 'b'
+ call T("break")
+ call assert_report('should not get here')
+ finally
+ try
+ Xpath 'c'
+ call T("return")
+ call assert_report('should not get here')
+ finally
+ try
+ Xpath 'd'
+ let g:jump = "finish"
+ ExecAsScript T
+ call assert_report('should not get here')
+ finally
+ unlet g:jump
+ try
+ Xpath 'e'
+ call T("error")
+ call assert_report('should not get here')
+ finally
+ try
+ Xpath 'f'
+ call T("interrupt")
+ call assert_report('should not get here')
+ finally
+ try
+ Xpath 'g'
+ call T("throw")
+ call assert_report('should not get here')
+ finally
+ Xpath 'h'
+ delfunction T
+ endtry
+ endtry
+ endtry
+ endtry
+ endtry
+ endtry
+ endtry
+ call assert_report('should not get here')
+ [CODE]
+ let verify =<< trim [CODE]
+ call assert_equal('abcdefgh', g:Xpath)
+ [CODE]
+ call RunInNewVim(test, verify)
+endfunc
+
+"-------------------------------------------------------------------------------
+" Test 49: Throwing exceptions across functions {{{1
+"
+" When an exception is thrown but not caught inside a function, the
+" caller is checked for a matching :catch clause.
+"-------------------------------------------------------------------------------
+
+func T49_C()
+ try
+ Xpath 'a'
+ throw "arrgh"
+ call assert_report('should not get here')
+ catch /arrgh/
+ Xpath 'b'
+ endtry
+ Xpath 'c'
+endfunc
+
+func T49_T1()
+ XloopNEXT
+ try
+ Xloop 'd'
+ throw "arrgh"
+ call assert_report('should not get here')
+ finally
+ Xloop 'e'
+ endtry
+ Xloop 'f'
+endfunc
+
+func T49_T2()
+ try
+ Xpath 'g'
+ call T49_T1()
+ call assert_report('should not get here')
+ finally
+ Xpath 'h'
+ endtry
+ call assert_report('should not get here')
+endfunc
+
+func Test_throw_exception_across_funcs()
+ XpathINIT
+ XloopINIT
+ try
+ Xpath 'i'
+ call T49_C() " throw and catch
+ Xpath 'j'
+ catch /.*/
+ call assert_report('should not get here')
+ endtry
+
+ try
+ Xpath 'k'
+ call T49_T1() " throw, one level
+ call assert_report('should not get here')
+ catch /arrgh/
+ Xpath 'l'
+ catch /.*/
+ call assert_report('should not get here')
+ endtry
+
+ try
+ Xpath 'm'
+ call T49_T2() " throw, two levels
+ call assert_report('should not get here')
+ catch /arrgh/
+ Xpath 'n'
+ catch /.*/
+ call assert_report('should not get here')
+ endtry
+ Xpath 'o'
+
+ call assert_equal('iabcjkd2e2lmgd3e3hno', g:Xpath)
+endfunc
+
+"-------------------------------------------------------------------------------
+" Test 50: Throwing exceptions across script files {{{1
+"
+" When an exception is thrown but not caught inside a script file,
+" the sourcing script or function is checked for a matching :catch
+" clause.
+"
+" This test executes the bodies of the functions C, T1, and T2 from
+" the previous test as script files (:return replaced by :finish).
+"-------------------------------------------------------------------------------
+
+func T50_F()
+ try
+ Xpath 'A'
+ exec "source" g:scriptC
+ Xpath 'B'
+ catch /.*/
+ call assert_report('should not get here')
+ endtry
+
+ try
+ Xpath 'C'
+ exec "source" g:scriptT1
+ call assert_report('should not get here')
+ catch /arrgh/
+ Xpath 'D'
+ catch /.*/
+ call assert_report('should not get here')
+ endtry
+endfunc
+
+func Test_throw_across_script()
+ XpathINIT
+ XloopINIT
+ let g:scriptC = MakeScript("T49_C")
+ let g:scriptT1 = MakeScript("T49_T1")
+ let scriptT2 = MakeScript("T49_T2", g:scriptT1)
+
+ try
+ Xpath 'E'
+ call T50_F()
+ Xpath 'F'
+ exec "source" scriptT2
+ call assert_report('should not get here')
+ catch /arrgh/
+ Xpath 'G'
+ catch /.*/
+ call assert_report('should not get here')
+ endtry
+ Xpath 'H'
+ call assert_equal('EAabcBCd2e2DFgd3e3hGH', g:Xpath)
+
+ call delete(g:scriptC)
+ call delete(g:scriptT1)
+ call delete(scriptT2)
+ unlet g:scriptC g:scriptT1 scriptT2
+endfunc
+
+"-------------------------------------------------------------------------------
+" Test 52: Uncaught exceptions {{{1
+"
+" When an exception is thrown but not caught, an error message is
+" displayed when the script is terminated. In case of an interrupt
+" or error exception, the normal interrupt or error message(s) are
+" displayed.
+"-------------------------------------------------------------------------------
+
+func Test_uncaught_exception_1()
+ CheckEnglish
+
+ let test =<< trim [CODE]
+ Xpath 'a'
+ throw "arrgh"
+ call assert_report('should not get here')`
+ [CODE]
+ let verify =<< trim [CODE]
+ call assert_equal('E605: Exception not caught: arrgh', v:errmsg)
+ call assert_equal('a', g:Xpath)
+ [CODE]
+ call RunInNewVim(test, verify)
+endfunc
+
+func Test_uncaught_exception_2()
+ CheckEnglish
+
+ let test =<< trim [CODE]
+ try
+ Xpath 'a'
+ throw "oops"
+ call assert_report('should not get here')`
+ catch /arrgh/
+ call assert_report('should not get here')`
+ endtry
+ call assert_report('should not get here')`
+ [CODE]
+ let verify =<< trim [CODE]
+ call assert_equal('E605: Exception not caught: oops', v:errmsg)
+ call assert_equal('a', g:Xpath)
+ [CODE]
+ call RunInNewVim(test, verify)
+endfunc
+
+func Test_uncaught_exception_3()
+ CheckEnglish
+
+ let test =<< trim [CODE]
+ func T()
+ Xpath 'c'
+ throw "brrr"
+ call assert_report('should not get here')`
+ endfunc
+
+ try
+ Xpath 'a'
+ throw "arrgh"
+ call assert_report('should not get here')`
+ catch /.*/
+ Xpath 'b'
+ call T()
+ call assert_report('should not get here')`
+ endtry
+ call assert_report('should not get here')`
+ [CODE]
+ let verify =<< trim [CODE]
+ call assert_equal('E605: Exception not caught: brrr', v:errmsg)
+ call assert_equal('abc', g:Xpath)
+ [CODE]
+ call RunInNewVim(test, verify)
+endfunc
+
+func Test_uncaught_exception_4()
+ CheckEnglish
+
+ let test =<< trim [CODE]
+ try
+ Xpath 'a'
+ throw "arrgh"
+ call assert_report('should not get here')`
+ finally
+ Xpath 'b'
+ throw "brrr"
+ call assert_report('should not get here')`
+ endtry
+ call assert_report('should not get here')`
+ [CODE]
+ let verify =<< trim [CODE]
+ call assert_equal('E605: Exception not caught: brrr', v:errmsg)
+ call assert_equal('ab', g:Xpath)
+ [CODE]
+ call RunInNewVim(test, verify)
+endfunc
+
+func Test_uncaught_exception_5()
+ CheckEnglish
+
+ " Need to catch and handle interrupt, otherwise the test will wait for the
+ " user to press <Enter> to continue
+ let test =<< trim [CODE]
+ try
+ try
+ Xpath 'a'
+ call interrupt()
+ call assert_report('should not get here')
+ endtry
+ call assert_report('should not get here')
+ catch /^Vim:Interrupt$/
+ Xpath 'b'
+ endtry
+ [CODE]
+ let verify =<< trim [CODE]
+ call assert_equal('ab', g:Xpath)
+ [CODE]
+ call RunInNewVim(test, verify)
+endfunc
+
+func Test_uncaught_exception_6()
+ CheckEnglish
+
+ let test =<< trim [CODE]
+ try
+ Xpath 'a'
+ let x = novar " error E121; exception: E121
+ catch /E15:/ " should not catch
+ call assert_report('should not get here')
+ endtry
+ call assert_report('should not get here')
+ [CODE]
+ let verify =<< trim [CODE]
+ call assert_equal('a', g:Xpath)
+ call assert_equal('E121: Undefined variable: novar', v:errmsg)
+ [CODE]
+ call RunInNewVim(test, verify)
+endfunc
+
+func Test_uncaught_exception_7()
+ CheckEnglish
+
+ let test =<< trim [CODE]
+ try
+ Xpath 'a'
+ " error E108/E488; exception: E488
+ unlet novar #
+ catch /E108:/ " should not catch
+ call assert_report('should not get here')
+ endtry
+ call assert_report('should not get here')
+ [CODE]
+ let verify =<< trim [CODE]
+ call assert_equal('a', g:Xpath)
+ call assert_equal('E488: Trailing characters: #', v:errmsg)
+ [CODE]
+ call RunInNewVim(test, verify)
+endfunc
+
+"-------------------------------------------------------------------------------
+" Test 53: Nesting errors: :endif/:else/:elseif {{{1
+"
+" For nesting errors of :if conditionals the correct error messages
+" should be given.
+"-------------------------------------------------------------------------------
+
+func Test_nested_if_else_errors()
+ CheckEnglish
+
+ " :endif without :if
+ let code =<< trim END
+ endif
+ END
+ call writefile(code, 'Xtest')
+ call AssertException(['source Xtest'], 'Vim(endif):E580: :endif without :if')
+
+ " :endif without :if
+ let code =<< trim END
+ while 1
+ endif
+ endwhile
+ END
+ call writefile(code, 'Xtest')
+ call AssertException(['source Xtest'], 'Vim(endif):E580: :endif without :if')
+
+ " :endif without :if
+ let code =<< trim END
+ try
+ finally
+ endif
+ endtry
+ END
+ call writefile(code, 'Xtest')
+ call AssertException(['source Xtest'], 'Vim(endif):E580: :endif without :if')
+
+ " :endif without :if
+ let code =<< trim END
+ try
+ endif
+ endtry
+ END
+ call writefile(code, 'Xtest')
+ call AssertException(['source Xtest'], 'Vim(endif):E580: :endif without :if')
+
+ " :endif without :if
+ let code =<< trim END
+ try
+ throw "a"
+ catch /a/
+ endif
+ endtry
+ END
+ call writefile(code, 'Xtest')
+ call AssertException(['source Xtest'], 'Vim(endif):E580: :endif without :if')
+
+ " :else without :if
+ let code =<< trim END
+ else
+ END
+ call writefile(code, 'Xtest')
+ call AssertException(['source Xtest'], 'Vim(else):E581: :else without :if')
+
+ " :else without :if
+ let code =<< trim END
+ while 1
+ else
+ endwhile
+ END
+ call writefile(code, 'Xtest')
+ call AssertException(['source Xtest'], 'Vim(else):E581: :else without :if')
+
+ " :else without :if
+ let code =<< trim END
+ try
+ finally
+ else
+ endtry
+ END
+ call writefile(code, 'Xtest')
+ call AssertException(['source Xtest'], 'Vim(else):E581: :else without :if')
+
+ " :else without :if
+ let code =<< trim END
+ try
+ else
+ endtry
+ END
+ call writefile(code, 'Xtest')
+ call AssertException(['source Xtest'], 'Vim(else):E581: :else without :if')
+
+ " :else without :if
+ let code =<< trim END
+ try
+ throw "a"
+ catch /a/
+ else
+ endtry
+ END
+ call writefile(code, 'Xtest')
+ call AssertException(['source Xtest'], 'Vim(else):E581: :else without :if')
+
+ " :elseif without :if
+ let code =<< trim END
+ elseif 1
+ END
+ call writefile(code, 'Xtest')
+ call AssertException(['source Xtest'], 'Vim(elseif):E582: :elseif without :if')
+
+ " :elseif without :if
+ let code =<< trim END
+ while 1
+ elseif 1
+ endwhile
+ END
+ call writefile(code, 'Xtest')
+ call AssertException(['source Xtest'], 'Vim(elseif):E582: :elseif without :if')
+
+ " :elseif without :if
+ let code =<< trim END
+ try
+ finally
+ elseif 1
+ endtry
+ END
+ call writefile(code, 'Xtest')
+ call AssertException(['source Xtest'], 'Vim(elseif):E582: :elseif without :if')
+
+ " :elseif without :if
+ let code =<< trim END
+ try
+ elseif 1
+ endtry
+ END
+ call writefile(code, 'Xtest')
+ call AssertException(['source Xtest'], 'Vim(elseif):E582: :elseif without :if')
+
+ " :elseif without :if
+ let code =<< trim END
+ try
+ throw "a"
+ catch /a/
+ elseif 1
+ endtry
+ END
+ call writefile(code, 'Xtest')
+ call AssertException(['source Xtest'], 'Vim(elseif):E582: :elseif without :if')
+
+ " multiple :else
+ let code =<< trim END
+ if 1
+ else
+ else
+ endif
+ END
+ call writefile(code, 'Xtest')
+ call AssertException(['source Xtest'], 'Vim(else):E583: multiple :else')
+
+ " :elseif after :else
+ let code =<< trim END
+ if 1
+ else
+ elseif 1
+ endif
+ END
+ call writefile(code, 'Xtest')
+ call AssertException(['source Xtest'], 'Vim(elseif):E584: :elseif after :else')
+
+ call delete('Xtest')
+endfunc
+
+"-------------------------------------------------------------------------------
+" Test 54: Nesting errors: :while/:endwhile {{{1
+"
+" For nesting errors of :while conditionals the correct error messages
+" should be given.
+"
+" This test reuses the function MESSAGES() from the previous test.
+" This functions checks the messages in g:msgfile.
"-------------------------------------------------------------------------------
+
+func Test_nested_while_error()
+ CheckEnglish
+
+ " :endwhile without :while
+ let code =<< trim END
+ endwhile
+ END
+ call writefile(code, 'Xtest')
+ call AssertException(['source Xtest'], 'Vim(endwhile):E588: :endwhile without :while')
+
+ " :endwhile without :while
+ let code =<< trim END
+ if 1
+ endwhile
+ endif
+ END
+ call writefile(code, 'Xtest')
+ call AssertException(['source Xtest'], 'Vim(endwhile):E588: :endwhile without :while')
+
+ " Missing :endif
+ let code =<< trim END
+ while 1
+ if 1
+ endwhile
+ END
+ call writefile(code, 'Xtest')
+ call AssertException(['source Xtest'], 'Vim(endwhile):E171: Missing :endif')
+
+ " :endwhile without :while
+ let code =<< trim END
+ try
+ finally
+ endwhile
+ endtry
+ END
+ call writefile(code, 'Xtest')
+ call AssertException(['source Xtest'], 'Vim(endwhile):E588: :endwhile without :while')
+
+ " Missing :endtry
+ let code =<< trim END
+ while 1
+ try
+ finally
+ endwhile
+ END
+ call writefile(code, 'Xtest')
+ call AssertException(['source Xtest'], 'Vim(endwhile):E600: Missing :endtry')
+
+ " Missing :endtry
+ let code =<< trim END
+ while 1
+ if 1
+ try
+ finally
+ endwhile
+ END
+ call writefile(code, 'Xtest')
+ call AssertException(['source Xtest'], 'Vim(endwhile):E600: Missing :endtry')
+
+ " Missing :endif
+ let code =<< trim END
+ while 1
+ try
+ finally
+ if 1
+ endwhile
+ END
+ call writefile(code, 'Xtest')
+ call AssertException(['source Xtest'], 'Vim(endwhile):E171: Missing :endif')
+
+ " :endwhile without :while
+ let code =<< trim END
+ try
+ endwhile
+ endtry
+ END
+ call writefile(code, 'Xtest')
+ call AssertException(['source Xtest'], 'Vim(endwhile):E588: :endwhile without :while')
+
+ " :endwhile without :while
+ let code =<< trim END
+ while 1
+ try
+ endwhile
+ endtry
+ endwhile
+ END
+ call writefile(code, 'Xtest')
+ call AssertException(['source Xtest'], 'Vim(endwhile):E588: :endwhile without :while')
+
+ " :endwhile without :while
+ let code =<< trim END
+ try
+ throw "a"
+ catch /a/
+ endwhile
+ endtry
+ END
+ call writefile(code, 'Xtest')
+ call AssertException(['source Xtest'], 'Vim(endwhile):E588: :endwhile without :while')
+
+ " :endwhile without :while
+ let code =<< trim END
+ while 1
+ try
+ throw "a"
+ catch /a/
+ endwhile
+ endtry
+ endwhile
+ END
+ call writefile(code, 'Xtest')
+ call AssertException(['source Xtest'], 'Vim(endwhile):E588: :endwhile without :while')
+
+ call delete('Xtest')
+endfunc
+
+"-------------------------------------------------------------------------------
+" Test 55: Nesting errors: :continue/:break {{{1
+"
+" For nesting errors of :continue and :break commands the correct
+" error messages should be given.
+"
+" This test reuses the function MESSAGES() from the previous test.
+" This functions checks the messages in g:msgfile.
+"-------------------------------------------------------------------------------
+
+func Test_nested_cont_break_error()
+ CheckEnglish
+
+ " :continue without :while
+ let code =<< trim END
+ continue
+ END
+ call writefile(code, 'Xtest')
+ call AssertException(['source Xtest'], 'Vim(continue):E586: :continue without :while or :for')
+
+ " :continue without :while
+ let code =<< trim END
+ if 1
+ continue
+ endif
+ END
+ call writefile(code, 'Xtest')
+ call AssertException(['source Xtest'], 'Vim(continue):E586: :continue without :while or :for')
+
+ " :continue without :while
+ let code =<< trim END
+ try
+ finally
+ continue
+ endtry
+ END
+ call writefile(code, 'Xtest')
+ call AssertException(['source Xtest'], 'Vim(continue):E586: :continue without :while or :for')
+
+ " :continue without :while
+ let code =<< trim END
+ try
+ continue
+ endtry
+ END
+ call writefile(code, 'Xtest')
+ call AssertException(['source Xtest'], 'Vim(continue):E586: :continue without :while or :for')
+
+ " :continue without :while
+ let code =<< trim END
+ try
+ throw "a"
+ catch /a/
+ continue
+ endtry
+ END
+ call writefile(code, 'Xtest')
+ call AssertException(['source Xtest'], 'Vim(continue):E586: :continue without :while or :for')
+
+ " :break without :while
+ let code =<< trim END
+ break
+ END
+ call writefile(code, 'Xtest')
+ call AssertException(['source Xtest'], 'Vim(break):E587: :break without :while or :for')
+
+ " :break without :while
+ let code =<< trim END
+ if 1
+ break
+ endif
+ END
+ call writefile(code, 'Xtest')
+ call AssertException(['source Xtest'], 'Vim(break):E587: :break without :while or :for')
+
+ " :break without :while
+ let code =<< trim END
+ try
+ finally
+ break
+ endtry
+ END
+ call writefile(code, 'Xtest')
+ call AssertException(['source Xtest'], 'Vim(break):E587: :break without :while or :for')
+
+ " :break without :while
+ let code =<< trim END
+ try
+ break
+ endtry
+ END
+ call writefile(code, 'Xtest')
+ call AssertException(['source Xtest'], 'Vim(break):E587: :break without :while or :for')
+
+ " :break without :while
+ let code =<< trim END
+ try
+ throw "a"
+ catch /a/
+ break
+ endtry
+ END
+ call writefile(code, 'Xtest')
+ call AssertException(['source Xtest'], 'Vim(break):E587: :break without :while or :for')
+
+ call delete('Xtest')
+endfunc
+
+"-------------------------------------------------------------------------------
+" Test 56: Nesting errors: :endtry {{{1
+"
+" For nesting errors of :try conditionals the correct error messages
+" should be given.
+"
+" This test reuses the function MESSAGES() from the previous test.
+" This functions checks the messages in g:msgfile.
+"-------------------------------------------------------------------------------
+
+func Test_nested_endtry_error()
+ CheckEnglish
+
+ " :endtry without :try
+ let code =<< trim END
+ endtry
+ END
+ call writefile(code, 'Xtest')
+ call AssertException(['source Xtest'], 'Vim(endtry):E602: :endtry without :try')
+
+ " :endtry without :try
+ let code =<< trim END
+ if 1
+ endtry
+ endif
+ END
+ call writefile(code, 'Xtest')
+ call AssertException(['source Xtest'], 'Vim(endtry):E602: :endtry without :try')
+
+ " :endtry without :try
+ let code =<< trim END
+ while 1
+ endtry
+ endwhile
+ END
+ call writefile(code, 'Xtest')
+ call AssertException(['source Xtest'], 'Vim(endtry):E602: :endtry without :try')
+
+ " Missing :endif
+ let code =<< trim END
+ try
+ if 1
+ endtry
+ END
+ call writefile(code, 'Xtest')
+ call AssertException(['source Xtest'], 'Vim(endtry):E171: Missing :endif')
+
+ " Missing :endwhile
+ let code =<< trim END
+ try
+ while 1
+ endtry
+ END
+ call writefile(code, 'Xtest')
+ call AssertException(['source Xtest'], 'Vim(endtry):E170: Missing :endwhile')
+
+ " Missing :endif
+ let code =<< trim END
+ try
+ finally
+ if 1
+ endtry
+ END
+ call writefile(code, 'Xtest')
+ call AssertException(['source Xtest'], 'Vim(endtry):E171: Missing :endif')
+
+ " Missing :endwhile
+ let code =<< trim END
+ try
+ finally
+ while 1
+ endtry
+ END
+ call writefile(code, 'Xtest')
+ call AssertException(['source Xtest'], 'Vim(endtry):E170: Missing :endwhile')
+
+ " Missing :endif
+ let code =<< trim END
+ try
+ throw "a"
+ catch /a/
+ if 1
+ endtry
+ END
+ call writefile(code, 'Xtest')
+ call AssertException(['source Xtest'], 'Vim(endtry):E171: Missing :endif')
+
+ " Missing :endwhile
+ let code =<< trim END
+ try
+ throw "a"
+ catch /a/
+ while 1
+ endtry
+ END
+ call writefile(code, 'Xtest')
+ call AssertException(['source Xtest'], 'Vim(endtry):E170: Missing :endwhile')
+
+ call delete('Xtest')
+endfunc
+
+"-------------------------------------------------------------------------------
+" Test 57: v:exception and v:throwpoint for user exceptions {{{1
+"
+" v:exception evaluates to the value of the exception that was caught
+" most recently and is not finished. (A caught exception is finished
+" when the next ":catch", ":finally", or ":endtry" is reached.)
+" v:throwpoint evaluates to the script/function name and line number
+" where that exception has been thrown.
+"-------------------------------------------------------------------------------
+
+func Test_user_exception_info()
+ CheckEnglish
+
+ XpathINIT
+ XloopINIT
+
+ func FuncException()
+ let g:exception = v:exception
+ endfunc
+
+ func FuncThrowpoint()
+ let g:throwpoint = v:throwpoint
+ endfunc
+
+ let scriptException = MakeScript("FuncException")
+ let scriptThrowPoint = MakeScript("FuncThrowpoint")
+
+ command! CmdException let g:exception = v:exception
+ command! CmdThrowpoint let g:throwpoint = v:throwpoint
+
+ func T(arg, line)
+ if a:line == 2
+ throw a:arg " in line 2
+ elseif a:line == 4
+ throw a:arg " in line 4
+ elseif a:line == 6
+ throw a:arg " in line 6
+ elseif a:line == 8
+ throw a:arg " in line 8
+ endif
+ endfunc
+
+ func G(arg, line)
+ call T(a:arg, a:line)
+ endfunc
+
+ func F(arg, line)
+ call G(a:arg, a:line)
+ endfunc
+
+ let scriptT = MakeScript("T")
+ let scriptG = MakeScript("G", scriptT)
+ let scriptF = MakeScript("F", scriptG)
+
+ try
+ Xpath 'a'
+ call F("oops", 2)
+ catch /.*/
+ Xpath 'b'
+ let exception = v:exception
+ let throwpoint = v:throwpoint
+ call assert_equal("oops", v:exception)
+ call assert_match('\<F\[1]\.\.G\[1]\.\.T\>', v:throwpoint)
+ call assert_match('\<2\>', v:throwpoint)
+
+ exec "let exception = v:exception"
+ exec "let throwpoint = v:throwpoint"
+ call assert_equal("oops", v:exception)
+ call assert_match('\<F\[1]\.\.G\[1]\.\.T\>', v:throwpoint)
+ call assert_match('\<2\>', v:throwpoint)
+
+ CmdException
+ CmdThrowpoint
+ call assert_equal("oops", v:exception)
+ call assert_match('\<F\[1]\.\.G\[1]\.\.T\>', v:throwpoint)
+ call assert_match('\<2\>', v:throwpoint)
+
+ call FuncException()
+ call FuncThrowpoint()
+ call assert_equal("oops", v:exception)
+ call assert_match('\<F\[1]\.\.G\[1]\.\.T\>', v:throwpoint)
+ call assert_match('\<2\>', v:throwpoint)
+
+ exec "source" scriptException
+ exec "source" scriptThrowPoint
+ call assert_equal("oops", v:exception)
+ call assert_match('\<F\[1]\.\.G\[1]\.\.T\>', v:throwpoint)
+ call assert_match('\<2\>', v:throwpoint)
+
+ try
+ Xpath 'c'
+ call G("arrgh", 4)
+ catch /.*/
+ Xpath 'd'
+ let exception = v:exception
+ let throwpoint = v:throwpoint
+ call assert_equal("arrgh", v:exception)
+ call assert_match('\<G\[1]\.\.T\>', v:throwpoint)
+ call assert_match('\<4\>', v:throwpoint)
+
+ try
+ Xpath 'e'
+ let g:arg = "autsch"
+ let g:line = 6
+ exec "source" scriptF
+ catch /.*/
+ Xpath 'f'
+ let exception = v:exception
+ let throwpoint = v:throwpoint
+ call assert_equal("autsch", v:exception)
+ call assert_match(fnamemodify(scriptT, ':t'), v:throwpoint)
+ call assert_match('\<6\>', v:throwpoint)
+ finally
+ Xpath 'g'
+ let exception = v:exception
+ let throwpoint = v:throwpoint
+ call assert_equal("arrgh", v:exception)
+ call assert_match('\<G\[1]\.\.T\>', v:throwpoint)
+ call assert_match('\<4\>', v:throwpoint)
+ try
+ Xpath 'h'
+ let g:arg = "brrrr"
+ let g:line = 8
+ exec "source" scriptG
+ catch /.*/
+ Xpath 'i'
+ let exception = v:exception
+ let throwpoint = v:throwpoint
+ " Resolve scriptT for matching it against v:throwpoint.
+ call assert_equal("brrrr", v:exception)
+ call assert_match(fnamemodify(scriptT, ':t'), v:throwpoint)
+ call assert_match('\<8\>', v:throwpoint)
+ finally
+ Xpath 'j'
+ let exception = v:exception
+ let throwpoint = v:throwpoint
+ call assert_equal("arrgh", v:exception)
+ call assert_match('\<G\[1]\.\.T\>', v:throwpoint)
+ call assert_match('\<4\>', v:throwpoint)
+ endtry
+ Xpath 'k'
+ let exception = v:exception
+ let throwpoint = v:throwpoint
+ call assert_equal("arrgh", v:exception)
+ call assert_match('\<G\[1]\.\.T\>', v:throwpoint)
+ call assert_match('\<4\>', v:throwpoint)
+ endtry
+ Xpath 'l'
+ let exception = v:exception
+ let throwpoint = v:throwpoint
+ call assert_equal("arrgh", v:exception)
+ call assert_match('\<G\[1]\.\.T\>', v:throwpoint)
+ call assert_match('\<4\>', v:throwpoint)
+ finally
+ Xpath 'm'
+ let exception = v:exception
+ let throwpoint = v:throwpoint
+ call assert_equal("oops", v:exception)
+ call assert_match('\<F\[1]\.\.G\[1]\.\.T\>', v:throwpoint)
+ call assert_match('\<2\>', v:throwpoint)
+ endtry
+ Xpath 'n'
+ let exception = v:exception
+ let throwpoint = v:throwpoint
+ call assert_equal("oops", v:exception)
+ call assert_match('\<F\[1]\.\.G\[1]\.\.T\>', v:throwpoint)
+ call assert_match('\<2\>', v:throwpoint)
+ finally
+ Xpath 'o'
+ let exception = v:exception
+ let throwpoint = v:throwpoint
+ call assert_equal("", v:exception)
+ call assert_match('^$', v:throwpoint)
+ call assert_match('^$', v:throwpoint)
+ endtry
+
+ call assert_equal('abcdefghijklmno', g:Xpath)
+
+ unlet exception throwpoint
+ delfunction FuncException
+ delfunction FuncThrowpoint
+ call delete(scriptException)
+ call delete(scriptThrowPoint)
+ unlet scriptException scriptThrowPoint
+ delcommand CmdException
+ delcommand CmdThrowpoint
+ delfunction T
+ delfunction G
+ delfunction F
+ call delete(scriptT)
+ call delete(scriptG)
+ call delete(scriptF)
+ unlet scriptT scriptG scriptF
+endfunc
+
+"-------------------------------------------------------------------------------
+"
+" Test 58: v:exception and v:throwpoint for error/interrupt exceptions {{{1
+"
+" v:exception and v:throwpoint work also for error and interrupt
+" exceptions.
+"-------------------------------------------------------------------------------
+
+func Test_execption_info_for_error()
+ CheckEnglish
+
+ let test =<< trim [CODE]
+ func T(line)
+ if a:line == 2
+ delfunction T " error (function in use) in line 2
+ elseif a:line == 4
+ call interrupt()
+ endif
+ endfunc
+
+ while 1
+ try
+ Xpath 'a'
+ call T(2)
+ call assert_report('should not get here')
+ catch /.*/
+ Xpath 'b'
+ if v:exception !~ 'Vim(delfunction):'
+ call assert_report('should not get here')
+ endif
+ if v:throwpoint !~ '\<T\>'
+ call assert_report('should not get here')
+ endif
+ if v:throwpoint !~ '\<2\>'
+ call assert_report('should not get here')
+ endif
+ finally
+ Xpath 'c'
+ if v:exception != ""
+ call assert_report('should not get here')
+ endif
+ if v:throwpoint != ""
+ call assert_report('should not get here')
+ endif
+ break
+ endtry
+ endwhile
+
+ Xpath 'd'
+ if v:exception != ""
+ call assert_report('should not get here')
+ endif
+ if v:throwpoint != ""
+ call assert_report('should not get here')
+ endif
+
+ while 1
+ try
+ Xpath 'e'
+ call T(4)
+ call assert_report('should not get here')
+ catch /.*/
+ Xpath 'f'
+ if v:exception != 'Vim:Interrupt'
+ call assert_report('should not get here')
+ endif
+ if v:throwpoint !~ 'function T'
+ call assert_report('should not get here')
+ endif
+ if v:throwpoint !~ '\<4\>'
+ call assert_report('should not get here')
+ endif
+ finally
+ Xpath 'g'
+ if v:exception != ""
+ call assert_report('should not get here')
+ endif
+ if v:throwpoint != ""
+ call assert_report('should not get here')
+ endif
+ break
+ endtry
+ endwhile
+
+ Xpath 'h'
+ if v:exception != ""
+ call assert_report('should not get here')
+ endif
+ if v:throwpoint != ""
+ call assert_report('should not get here')
+ endif
+ [CODE]
+ let verify =<< trim [CODE]
+ call assert_equal('abcdefgh', g:Xpath)
+ [CODE]
+ call RunInNewVim(test, verify)
+endfunc
+
+"-------------------------------------------------------------------------------
+"
+" Test 59: v:exception and v:throwpoint when discarding exceptions {{{1
+"
+" When a :catch clause is left by a ":break" etc or an error or
+" interrupt exception, v:exception and v:throwpoint are reset. They
+" are not affected by an exception that is discarded before being
+" caught.
+"-------------------------------------------------------------------------------
+func Test_exception_info_on_discard()
+ CheckEnglish
+
+ let test =<< trim [CODE]
+ let sfile = expand("<sfile>")
+
+ while 1
+ try
+ throw "x1"
+ catch /.*/
+ break
+ endtry
+ endwhile
+ call assert_equal('', v:exception)
+ call assert_equal('', v:throwpoint)
+
+ while 1
+ try
+ throw "x2"
+ catch /.*/
+ break
+ finally
+ call assert_equal('', v:exception)
+ call assert_equal('', v:throwpoint)
+ endtry
+ break
+ endwhile
+ call assert_equal('', v:exception)
+ call assert_equal('', v:throwpoint)
+
+ while 1
+ try
+ let errcaught = 0
+ try
+ try
+ throw "x3"
+ catch /.*/
+ let lnum = expand("<sflnum>")
+ asdf
+ endtry
+ catch /.*/
+ let errcaught = 1
+ call assert_match('Vim:E492: Not an editor command:', v:exception)
+ call assert_match('line ' .. (lnum + 1), v:throwpoint)
+ endtry
+ finally
+ call assert_equal(1, errcaught)
+ break
+ endtry
+ endwhile
+ call assert_equal('', v:exception)
+ call assert_equal('', v:throwpoint)
+
+ Xpath 'a'
+
+ while 1
+ try
+ let intcaught = 0
+ try
+ try
+ throw "x4"
+ catch /.*/
+ let lnum = expand("<sflnum>")
+ call interrupt()
+ endtry
+ catch /.*/
+ let intcaught = 1
+ call assert_match('Vim:Interrupt', v:exception)
+ call assert_match('line ' .. (lnum + 1), v:throwpoint)
+ endtry
+ finally
+ call assert_equal(1, intcaught)
+ break
+ endtry
+ endwhile
+ call assert_equal('', v:exception)
+ call assert_equal('', v:throwpoint)
+
+ Xpath 'b'
+
+ while 1
+ try
+ let errcaught = 0
+ try
+ try
+ if 1
+ let lnum = expand("<sflnum>")
+ throw "x5"
+ " missing endif
+ catch /.*/
+ call assert_report('should not get here')
+ endtry
+ catch /.*/
+ let errcaught = 1
+ call assert_match('Vim(catch):E171: Missing :endif:', v:exception)
+ call assert_match('line ' .. (lnum + 3), v:throwpoint)
+ endtry
+ finally
+ call assert_equal(1, errcaught)
+ break
+ endtry
+ endwhile
+ call assert_equal('', v:exception)
+ call assert_equal('', v:throwpoint)
+
+ Xpath 'c'
+
+ try
+ while 1
+ try
+ throw "x6"
+ finally
+ break
+ endtry
+ break
+ endwhile
+ catch /.*/
+ call assert_report('should not get here')
+ endtry
+ call assert_equal('', v:exception)
+ call assert_equal('', v:throwpoint)
+
+ try
+ while 1
+ try
+ throw "x7"
+ finally
+ break
+ endtry
+ break
+ endwhile
+ catch /.*/
+ call assert_report('should not get here')
+ finally
+ call assert_equal('', v:exception)
+ call assert_equal('', v:throwpoint)
+ endtry
+ call assert_equal('', v:exception)
+ call assert_equal('', v:throwpoint)
+
+ while 1
+ try
+ let errcaught = 0
+ try
+ try
+ throw "x8"
+ finally
+ let lnum = expand("<sflnum>")
+ asdf
+ endtry
+ catch /.*/
+ let errcaught = 1
+ call assert_match('Vim:E492: Not an editor command:', v:exception)
+ call assert_match('line ' .. (lnum + 1), v:throwpoint)
+ endtry
+ finally
+ call assert_equal(1, errcaught)
+ break
+ endtry
+ endwhile
+ call assert_equal('', v:exception)
+ call assert_equal('', v:throwpoint)
+
+ Xpath 'd'
+
+ while 1
+ try
+ let intcaught = 0
+ try
+ try
+ throw "x9"
+ finally
+ let lnum = expand("<sflnum>")
+ call interrupt()
+ endtry
+ catch /.*/
+ let intcaught = 1
+ call assert_match('Vim:Interrupt', v:exception)
+ call assert_match('line ' .. (lnum + 1), v:throwpoint)
+ endtry
+ finally
+ call assert_equal(1, intcaught)
+ break
+ endtry
+ endwhile
+ call assert_equal('', v:exception)
+ call assert_equal('', v:throwpoint)
+
+ Xpath 'e'
+
+ while 1
+ try
+ let errcaught = 0
+ try
+ try
+ if 1
+ let lnum = expand("<sflnum>")
+ throw "x10"
+ " missing endif
+ finally
+ call assert_equal('', v:exception)
+ call assert_equal('', v:throwpoint)
+ endtry
+ catch /.*/
+ let errcaught = 1
+ call assert_match('Vim(finally):E171: Missing :endif:', v:exception)
+ call assert_match('line ' .. (lnum + 3), v:throwpoint)
+ endtry
+ finally
+ call assert_equal(1, errcaught)
+ break
+ endtry
+ endwhile
+ call assert_equal('', v:exception)
+ call assert_equal('', v:throwpoint)
+
+ Xpath 'f'
+
+ while 1
+ try
+ let errcaught = 0
+ try
+ try
+ if 1
+ let lnum = expand("<sflnum>")
+ throw "x11"
+ " missing endif
+ endtry
+ catch /.*/
+ let errcaught = 1
+ call assert_match('Vim(endtry):E171: Missing :endif:', v:exception)
+ call assert_match('line ' .. (lnum + 3), v:throwpoint)
+ endtry
+ finally
+ call assert_equal(1, errcaught)
+ break
+ endtry
+ endwhile
+ call assert_equal('', v:exception)
+ call assert_equal('', v:throwpoint)
+
+ Xpath 'g'
+ [CODE]
+ let verify =<< trim [CODE]
+ call assert_equal('abcdefg', g:Xpath)
+ [CODE]
+ call RunInNewVim(test, verify)
+endfunc
+
+"-------------------------------------------------------------------------------
+"
+" Test 60: (Re)throwing v:exception; :echoerr. {{{1
+"
+" A user exception can be rethrown after catching by throwing
+" v:exception. An error or interrupt exception cannot be rethrown
+" because Vim exceptions cannot be faked. A Vim exception using the
+" value of v:exception can, however, be triggered by the :echoerr
+" command.
+"-------------------------------------------------------------------------------
+
+func Test_rethrow_exception_1()
+ XpathINIT
+ try
+ try
+ Xpath 'a'
+ throw "oops"
+ catch /oops/
+ Xpath 'b'
+ throw v:exception " rethrow user exception
+ catch /.*/
+ call assert_report('should not get here')
+ endtry
+ catch /^oops$/ " catches rethrown user exception
+ Xpath 'c'
+ catch /.*/
+ call assert_report('should not get here')
+ endtry
+ call assert_equal('abc', g:Xpath)
+endfunc
+
+func Test_rethrow_exception_2()
+ XpathINIT
+ try
+ let caught = 0
+ try
+ Xpath 'a'
+ write /n/o/n/w/r/i/t/a/b/l/e/_/f/i/l/e
+ call assert_report('should not get here')
+ catch /^Vim(write):/
+ let caught = 1
+ throw v:exception " throw error: cannot fake Vim exception
+ catch /.*/
+ call assert_report('should not get here')
+ finally
+ Xpath 'b'
+ call assert_equal(1, caught)
+ endtry
+ catch /^Vim(throw):/ " catches throw error
+ let caught = caught + 1
+ catch /.*/
+ call assert_report('should not get here')
+ finally
+ Xpath 'c'
+ call assert_equal(2, caught)
+ endtry
+ call assert_equal('abc', g:Xpath)
+endfunc
+
+func Test_rethrow_exception_3()
+ XpathINIT
+ try
+ let caught = 0
+ try
+ Xpath 'a'
+ asdf
+ catch /^Vim/ " catch error exception
+ let caught = 1
+ " Trigger Vim error exception with value specified after :echoerr
+ let value = substitute(v:exception, '^Vim\((.*)\)\=:', '', "")
+ echoerr value
+ catch /.*/
+ call assert_report('should not get here')
+ finally
+ Xpath 'b'
+ call assert_equal(1, caught)
+ endtry
+ catch /^Vim(echoerr):/
+ let caught = caught + 1
+ call assert_match(value, v:exception)
+ catch /.*/
+ call assert_report('should not get here')
+ finally
+ Xpath 'c'
+ call assert_equal(2, caught)
+ endtry
+ call assert_equal('abc', g:Xpath)
+endfunc
+
+func Test_rethrow_exception_3()
+ XpathINIT
+ try
+ let errcaught = 0
+ try
+ Xpath 'a'
+ let intcaught = 0
+ call interrupt()
+ catch /^Vim:/ " catch interrupt exception
+ let intcaught = 1
+ " Trigger Vim error exception with value specified after :echoerr
+ echoerr substitute(v:exception, '^Vim\((.*)\)\=:', '', "")
+ catch /.*/
+ call assert_report('should not get here')
+ finally
+ Xpath 'b'
+ call assert_equal(1, intcaught)
+ endtry
+ catch /^Vim(echoerr):/
+ let errcaught = 1
+ call assert_match('Interrupt', v:exception)
+ finally
+ Xpath 'c'
+ call assert_equal(1, errcaught)
+ endtry
+ call assert_equal('abc', g:Xpath)
+endfunc
+
+"-------------------------------------------------------------------------------
+" Test 61: Catching interrupt exceptions {{{1
+"
+" When an interrupt occurs inside a :try/:endtry region, an
+" interrupt exception is thrown and can be caught. Its value is
+" "Vim:Interrupt". If the interrupt occurs after an error or a :throw
+" but before a matching :catch is reached, all following :catches of
+" that try block are ignored, but the interrupt exception can be
+" caught by the next surrounding try conditional. An interrupt is
+" ignored when there is a previous interrupt that has not been caught
+" or causes a :finally clause to be executed.
+"-------------------------------------------------------------------------------
+
+func Test_catch_intr_exception()
+ let test =<< trim [CODE]
+ while 1
+ try
+ try
+ Xpath 'a'
+ call interrupt()
+ call assert_report('should not get here')
+ catch /^Vim:Interrupt$/
+ Xpath 'b'
+ finally
+ Xpath 'c'
+ endtry
+ catch /.*/
+ call assert_report('should not get here')
+ finally
+ Xpath 'd'
+ break
+ endtry
+ endwhile
+
+ while 1
+ try
+ try
+ try
+ Xpath 'e'
+ asdf
+ call assert_report('should not get here')
+ catch /do_not_catch/
+ call assert_report('should not get here')
+ catch /.*/
+ Xpath 'f'
+ call interrupt()
+ call assert_report('should not get here')
+ catch /.*/
+ call assert_report('should not get here')
+ finally
+ Xpath 'g'
+ call interrupt()
+ call assert_report('should not get here')
+ endtry
+ catch /^Vim:Interrupt$/
+ Xpath 'h'
+ finally
+ Xpath 'i'
+ endtry
+ catch /.*/
+ call assert_report('should not get here')
+ finally
+ Xpath 'j'
+ break
+ endtry
+ endwhile
+
+ while 1
+ try
+ try
+ try
+ Xpath 'k'
+ throw "x"
+ call assert_report('should not get here')
+ catch /do_not_catch/
+ call assert_report('should not get here')
+ catch /x/
+ Xpath 'l'
+ call interrupt()
+ call assert_report('should not get here')
+ catch /.*/
+ call assert_report('should not get here')
+ endtry
+ catch /^Vim:Interrupt$/
+ Xpath 'm'
+ finally
+ Xpath 'n'
+ endtry
+ catch /.*/
+ call assert_report('should not get here')
+ finally
+ Xpath 'o'
+ break
+ endtry
+ endwhile
+
+ while 1
+ try
+ try
+ Xpath 'p'
+ call interrupt()
+ call assert_report('should not get here')
+ catch /do_not_catch/
+ call interrupt()
+ call assert_report('should not get here')
+ catch /^Vim:Interrupt$/
+ Xpath 'q'
+ finally
+ Xpath 'r'
+ endtry
+ catch /.*/
+ call assert_report('should not get here')
+ finally
+ Xpath 's'
+ break
+ endtry
+ endwhile
+
+ Xpath 't'
+ [CODE]
+ let verify =<< trim [CODE]
+ call assert_equal('abcdefghijklmnopqrst', g:Xpath)
+ [CODE]
+ call RunInNewVim(test, verify)
+endfunc
+
+"-------------------------------------------------------------------------------
+" Test 62: Catching error exceptions {{{1
+"
+" An error inside a :try/:endtry region is converted to an exception
+" and can be caught. The error exception has a "Vim(cmdname):" prefix
+" where cmdname is the name of the failing command, or a "Vim:" prefix
+" if no command name is known. The "Vim" prefixes cannot be faked.
+"-------------------------------------------------------------------------------
+
+func Test_catch_err_exception_1()
+ XpathINIT
+ while 1
+ try
+ try
+ let caught = 0
+ unlet novar
+ catch /^Vim(unlet):/
+ Xpath 'a'
+ let caught = 1
+ let v:errmsg = substitute(v:exception, '^Vim(unlet):', '', "")
+ finally
+ Xpath 'b'
+ call assert_equal(1, caught)
+ call assert_match('E108: No such variable: "novar"', v:errmsg)
+ endtry
+ catch /.*/
+ call assert_report('should not get here')
+ finally
+ Xpath 'c'
+ break
+ endtry
+ call assert_report('should not get here')
+ endwhile
+ call assert_equal('abc', g:Xpath)
+endfunc
+
+func Test_catch_err_exception_2()
+ XpathINIT
+ while 1
+ try
+ try
+ let caught = 0
+ throw novar " error in :throw
+ catch /^Vim(throw):/
+ Xpath 'a'
+ let caught = 1
+ let v:errmsg = substitute(v:exception, '^Vim(throw):', '', "")
+ finally
+ Xpath 'b'
+ call assert_equal(1, caught)
+ call assert_match('E121: Undefined variable: novar', v:errmsg)
+ endtry
+ catch /.*/
+ call assert_report('should not get here')
+ finally
+ Xpath 'c'
+ break
+ endtry
+ call assert_report('should not get here')
+ endwhile
+ call assert_equal('abc', g:Xpath)
+endfunc
+
+func Test_catch_err_exception_3()
+ XpathINIT
+ while 1
+ try
+ try
+ let caught = 0
+ throw "Vim:faked" " error: cannot fake Vim exception
+ catch /^Vim(throw):/
+ Xpath 'a'
+ let caught = 1
+ let v:errmsg = substitute(v:exception, '^Vim(throw):', '', "")
+ finally
+ Xpath 'b'
+ call assert_equal(1, caught)
+ call assert_match("E608: Cannot :throw exceptions with 'Vim' prefix",
+ \ v:errmsg)
+ endtry
+ catch /.*/
+ call assert_report('should not get here')
+ finally
+ Xpath 'c'
+ break
+ endtry
+ call assert_report('should not get here')
+ endwhile
+ call assert_equal('abc', g:Xpath)
+endfunc
+
+func Test_catch_err_exception_4()
+ XpathINIT
+ func F()
+ while 1
+ " Missing :endwhile
+ endfunc
+
+ while 1
+ try
+ try
+ let caught = 0
+ call F()
+ catch /^Vim(endfunction):/
+ Xpath 'a'
+ let caught = 1
+ let v:errmsg = substitute(v:exception, '^Vim(endfunction):', '', "")
+ finally
+ Xpath 'b'
+ call assert_equal(1, caught)
+ call assert_match("E170: Missing :endwhile", v:errmsg)
+ endtry
+ catch /.*/
+ call assert_report('should not get here')
+ finally
+ Xpath 'c'
+ break
+ endtry
+ call assert_report('should not get here')
+ endwhile
+ call assert_equal('abc', g:Xpath)
+ delfunc F
+endfunc
+
+func Test_catch_err_exception_5()
+ XpathINIT
+ func F()
+ while 1
+ " Missing :endwhile
+ endfunc
+
+ while 1
+ try
+ try
+ let caught = 0
+ ExecAsScript F
+ catch /^Vim:/
+ Xpath 'a'
+ let caught = 1
+ let v:errmsg = substitute(v:exception, '^Vim:', '', "")
+ finally
+ Xpath 'b'
+ call assert_equal(1, caught)
+ call assert_match("E170: Missing :endwhile", v:errmsg)
+ endtry
+ catch /.*/
+ call assert_report('should not get here')
+ finally
+ Xpath 'c'
+ break
+ endtry
+ call assert_report('should not get here')
+ endwhile
+ call assert_equal('abc', g:Xpath)
+ delfunc F
+endfunc
+
+func Test_catch_err_exception_6()
+ XpathINIT
+ func G()
+ call G()
+ endfunc
+
+ while 1
+ try
+ let mfd_save = &mfd
+ set mfd=3
+ try
+ let caught = 0
+ call G()
+ catch /^Vim(call):/
+ Xpath 'a'
+ let caught = 1
+ let v:errmsg = substitute(v:exception, '^Vim(call):', '', "")
+ finally
+ Xpath 'b'
+ call assert_equal(1, caught)
+ call assert_match("E132: Function call depth is higher than 'maxfuncdepth'", v:errmsg)
+ endtry
+ catch /.*/
+ call assert_report('should not get here')
+ finally
+ Xpath 'c'
+ let &mfd = mfd_save
+ break
+ endtry
+ call assert_report('should not get here')
+ endwhile
+ call assert_equal('abc', g:Xpath)
+ delfunc G
+endfunc
+
+func Test_catch_err_exception_7()
+ XpathINIT
+ func H()
+ return H()
+ endfunc
+
+ while 1
+ try
+ let mfd_save = &mfd
+ set mfd=3
+ try
+ let caught = 0
+ call H()
+ catch /^Vim(return):/
+ Xpath 'a'
+ let caught = 1
+ let v:errmsg = substitute(v:exception, '^Vim(return):', '', "")
+ finally
+ Xpath 'b'
+ call assert_equal(1, caught)
+ call assert_match("E132: Function call depth is higher than 'maxfuncdepth'", v:errmsg)
+ endtry
+ catch /.*/
+ call assert_report('should not get here')
+ finally
+ Xpath 'c'
+ let &mfd = mfd_save
+ break " discard error for $VIMNOERRTHROW
+ endtry
+ call assert_report('should not get here')
+ endwhile
+
+ call assert_equal('abc', g:Xpath)
+ delfunc H
+endfunc
+
+"-------------------------------------------------------------------------------
+" Test 63: Suppressing error exceptions by :silent!. {{{1
+"
+" A :silent! command inside a :try/:endtry region suppresses the
+" conversion of errors to an exception and the immediate abortion on
+" error. When the commands executed by the :silent! themselves open
+" a new :try/:endtry region, conversion of errors to exception and
+" immediate abortion is switched on again - until the next :silent!
+" etc. The :silent! has the effect of setting v:errmsg to the error
+" message text (without displaying it) and continuing with the next
+" script line.
+"
+" When a command triggering autocommands is executed by :silent!
+" inside a :try/:endtry, the autocommand execution is not suppressed
+" on error.
+"
+" This test reuses the function MSG() from the previous test.
+"-------------------------------------------------------------------------------
+
+func Test_silent_exception()
+ XpathINIT
+ XloopINIT
+ let g:taken = ""
+
+ func S(n) abort
+ XloopNEXT
+ let g:taken = g:taken . "E" . a:n
+ let v:errmsg = ""
+ exec "asdf" . a:n
+
+ " Check that ":silent!" continues:
+ Xloop 'a'
+
+ " Check that ":silent!" sets "v:errmsg":
+ call assert_match("E492: Not an editor command", v:errmsg)
+ endfunc
+
+ func Foo()
+ while 1
+ try
+ try
+ let caught = 0
+ " This is not silent:
+ call S(3)
+ catch /^Vim:/
+ Xpath 'b'
+ let caught = 1
+ let errmsg3 = substitute(v:exception, '^Vim:', '', "")
+ silent! call S(4)
+ finally
+ call assert_equal(1, caught)
+ Xpath 'c'
+ call assert_match("E492: Not an editor command", errmsg3)
+ silent! call S(5)
+ " Break out of try conditionals that cover ":silent!". This also
+ " discards the aborting error when $VIMNOERRTHROW is non-zero.
+ break
+ endtry
+ catch /.*/
+ call assert_report('should not get here')
+ endtry
+ endwhile
+ " This is a double ":silent!" (see caller).
+ silent! call S(6)
+ endfunc
+
+ func Bar()
+ try
+ silent! call S(2)
+ silent! execute "call Foo() | call S(7)"
+ silent! call S(8)
+ endtry " normal end of try cond that covers ":silent!"
+ " This has a ":silent!" from the caller:
+ call S(9)
+ endfunc
+
+ silent! call S(1)
+ silent! call Bar()
+ silent! call S(10)
+
+ call assert_equal("E1E2E3E4E5E6E7E8E9E10", g:taken)
+
+ augroup TMP
+ au!
+ autocmd BufWritePost * Xpath 'd'
+ augroup END
+
+ Xpath 'e'
+ silent! write /i/m/p/o/s/s/i/b/l/e
+ Xpath 'f'
+
+ call assert_equal('a2a3ba5ca6a7a8a9a10a11edf', g:Xpath)
+
+ augroup TMP
+ au!
+ augroup END
+ augroup! TMP
+ delfunction S
+ delfunction Foo
+ delfunction Bar
+endfunc
+
+"-------------------------------------------------------------------------------
+" Test 64: Error exceptions after error, interrupt or :throw {{{1
+"
+" When an error occurs after an interrupt or a :throw but before
+" a matching :catch is reached, all following :catches of that try
+" block are ignored, but the error exception can be caught by the next
+" surrounding try conditional. Any previous error exception is
+" discarded. An error is ignored when there is a previous error that
+" has not been caught.
+"-------------------------------------------------------------------------------
+
+func Test_exception_after_error_1()
+ XpathINIT
+ while 1
+ try
+ try
+ Xpath 'a'
+ let caught = 0
+ while 1
+ if 1
+ " Missing :endif
+ endwhile " throw error exception
+ catch /^Vim(/
+ Xpath 'b'
+ let caught = 1
+ finally
+ Xpath 'c'
+ call assert_equal(1, caught)
+ endtry
+ catch /.*/
+ call assert_report('should not get here')
+ finally
+ Xpath 'd'
+ break
+ endtry
+ call assert_report('should not get here')
+ endwhile
+ call assert_equal('abcd', g:Xpath)
+endfunc
+
+func Test_exception_after_error_2()
+ XpathINIT
+ while 1
+ try
+ try
+ Xpath 'a'
+ let caught = 0
+ try
+ if 1
+ " Missing :endif
+ catch /.*/ " throw error exception
+ call assert_report('should not get here')
+ catch /.*/
+ call assert_report('should not get here')
+ endtry
+ catch /^Vim(/
+ Xpath 'b'
+ let caught = 1
+ finally
+ Xpath 'c'
+ call assert_equal(1, caught)
+ endtry
+ catch /.*/
+ call assert_report('should not get here')
+ finally
+ Xpath 'd'
+ break
+ endtry
+ call assert_report('should not get here')
+ endwhile
+ call assert_equal('abcd', g:Xpath)
+endfunc
+
+func Test_exception_after_error_3()
+ XpathINIT
+ while 1
+ try
+ try
+ let caught = 0
+ try
+ Xpath 'a'
+ call interrupt()
+ catch /do_not_catch/
+ call assert_report('should not get here')
+ if 1
+ " Missing :endif
+ catch /.*/ " throw error exception
+ call assert_report('should not get here')
+ catch /.*/
+ call assert_report('should not get here')
+ endtry
+ catch /^Vim(/
+ Xpath 'b'
+ let caught = 1
+ finally
+ Xpath 'c'
+ call assert_equal(1, caught)
+ endtry
+ catch /.*/
+ call assert_report('should not get here')
+ finally
+ Xpath 'd'
+ break
+ endtry
+ call assert_report('should not get here')
+ endwhile
+ call assert_equal('abcd', g:Xpath)
+endfunc
+
+func Test_exception_after_error_4()
+ XpathINIT
+ while 1
+ try
+ try
+ let caught = 0
+ try
+ Xpath 'a'
+ throw "x"
+ catch /do_not_catch/
+ call assert_report('should not get here')
+ if 1
+ " Missing :endif
+ catch /x/ " throw error exception
+ call assert_report('should not get here')
+ catch /.*/
+ call assert_report('should not get here')
+ endtry
+ catch /^Vim(/
+ Xpath 'b'
+ let caught = 1
+ finally
+ Xpath 'c'
+ call assert_equal(1, caught)
+ endtry
+ catch /.*/
+ call assert_report('should not get here')
+ finally
+ Xpath 'd'
+ break
+ endtry
+ call assert_report('should not get here')
+ endwhile
+ call assert_equal('abcd', g:Xpath)
+endfunc
+
+func Test_exception_after_error_5()
+ XpathINIT
+ while 1
+ try
+ try
+ let caught = 0
+ Xpath 'a'
+ endif " :endif without :if; throw error exception
+ if 1
+ " Missing :endif
+ catch /do_not_catch/ " ignore new error
+ call assert_report('should not get here')
+ catch /^Vim(endif):/
+ Xpath 'b'
+ let caught = 1
+ catch /^Vim(/
+ call assert_report('should not get here')
+ finally
+ Xpath 'c'
+ call assert_equal(1, caught)
+ endtry
+ catch /.*/
+ call assert_report('should not get here')
+ finally
+ Xpath 'd'
+ break
+ endtry
+ call assert_report('should not get here')
+ endwhile
+ call assert_equal('abcd', g:Xpath)
+endfunc
+
+"-------------------------------------------------------------------------------
+" Test 65: Errors in the /pattern/ argument of a :catch {{{1
+"
+" On an error in the /pattern/ argument of a :catch, the :catch does
+" not match. Any following :catches of the same :try/:endtry don't
+" match either. Finally clauses are executed.
+"-------------------------------------------------------------------------------
+
+func Test_catch_pattern_error()
+ CheckEnglish
+ XpathINIT
+
+ try
+ try
+ Xpath 'a'
+ throw "oops"
+ catch /^oops$/
+ Xpath 'b'
+ catch /\)/ " not checked; exception has already been caught
+ call assert_report('should not get here')
+ endtry
+ Xpath 'c'
+ catch /.*/
+ call assert_report('should not get here')
+ endtry
+ call assert_equal('abc', g:Xpath)
+
+ XpathINIT
+ func F()
+ try
+ try
+ try
+ Xpath 'a'
+ throw "ab"
+ catch /abc/ " does not catch
+ call assert_report('should not get here')
+ catch /\)/ " error; discards exception
+ call assert_report('should not get here')
+ catch /.*/ " not checked
+ call assert_report('should not get here')
+ finally
+ Xpath 'b'
+ endtry
+ call assert_report('should not get here')
+ catch /^ab$/ " checked, but original exception is discarded
+ call assert_report('should not get here')
+ catch /^Vim(catch):/
+ Xpath 'c'
+ call assert_match('Vim(catch):E475: Invalid argument:', v:exception)
+ finally
+ Xpath 'd'
+ endtry
+ Xpath 'e'
+ catch /.*/
+ call assert_report('should not get here')
+ endtry
+ Xpath 'f'
+ endfunc
+
+ call F()
+ call assert_equal('abcdef', g:Xpath)
+
+ delfunc F
+endfunc
+
+"-------------------------------------------------------------------------------
+" Test 66: Stop range :call on error, interrupt, or :throw {{{1
+"
+" When a function which is multiply called for a range since it
+" doesn't handle the range itself has an error in a command
+" dynamically enclosed by :try/:endtry or gets an interrupt or
+" executes a :throw, no more calls for the remaining lines in the
+" range are made. On an error in a command not dynamically enclosed
+" by :try/:endtry, the function is executed again for the remaining
+" lines in the range.
+"-------------------------------------------------------------------------------
+
+func Test_stop_range_on_error()
+ let test =<< trim [CODE]
+ let file = tempname()
+ exec "edit" file
+ call setline(1, ['line 1', 'line 2', 'line 3'])
+ let taken = ""
+ let expected = "G1EF1E(1)F1E(2)F1E(3)G2EF2E(1)G3IF3I(1)G4TF4T(1)G5AF5A(1)"
+
+ func F(reason, n) abort
+ let g:taken = g:taken .. "F" .. a:n ..
+ \ substitute(a:reason, '\(\l\).*', '\u\1', "") ..
+ \ "(" .. line(".") .. ")"
+
+ if a:reason == "error"
+ asdf
+ elseif a:reason == "interrupt"
+ call interrupt()
+ elseif a:reason == "throw"
+ throw "xyz"
+ elseif a:reason == "aborting error"
+ XloopNEXT
+ call assert_equal(g:taken, g:expected)
+ try
+ bwipeout!
+ call delete(g:file)
+ asdf
+ endtry
+ endif
+ endfunc
+
+ func G(reason, n)
+ let g:taken = g:taken .. "G" .. a:n ..
+ \ substitute(a:reason, '\(\l\).*', '\u\1', "")
+ 1,3call F(a:reason, a:n)
+ endfunc
+
+ Xpath 'a'
+ call G("error", 1)
+ try
+ Xpath 'b'
+ try
+ call G("error", 2)
+ call assert_report('should not get here')
+ finally
+ Xpath 'c'
+ try
+ call G("interrupt", 3)
+ call assert_report('should not get here')
+ finally
+ Xpath 'd'
+ try
+ call G("throw", 4)
+ call assert_report('should not get here')
+ endtry
+ endtry
+ endtry
+ catch /xyz/
+ Xpath 'e'
+ catch /.*/
+ call assert_report('should not get here')
+ endtry
+ Xpath 'f'
+ call G("aborting error", 5)
+ call assert_report('should not get here')
+ [CODE]
+ let verify =<< trim [CODE]
+ call assert_equal('abcdef', g:Xpath)
+ [CODE]
+ call RunInNewVim(test, verify)
+endfunc
+
+"-------------------------------------------------------------------------------
+" Test 67: :throw across :call command {{{1
+"
+" On a call command, an exception might be thrown when evaluating the
+" function name, during evaluation of the arguments, or when the
+" function is being executed. The exception can be caught by the
+" caller.
+"-------------------------------------------------------------------------------
+
+func THROW(x, n)
+ if a:n == 1
+ Xpath 'A'
+ elseif a:n == 2
+ Xpath 'B'
+ elseif a:n == 3
+ Xpath 'C'
+ endif
+ throw a:x
+endfunc
+
+func NAME(x, n)
+ if a:n == 1
+ call assert_report('should not get here')
+ elseif a:n == 2
+ Xpath 'D'
+ elseif a:n == 3
+ Xpath 'E'
+ elseif a:n == 4
+ Xpath 'F'
+ endif
+ return a:x
+endfunc
+
+func ARG(x, n)
+ if a:n == 1
+ call assert_report('should not get here')
+ elseif a:n == 2
+ call assert_report('should not get here')
+ elseif a:n == 3
+ Xpath 'G'
+ elseif a:n == 4
+ Xpath 'I'
+ endif
+ return a:x
+endfunc
+
+func Test_throw_across_call_cmd()
+ XpathINIT
+
+ func F(x, n)
+ if a:n == 2
+ call assert_report('should not get here')
+ elseif a:n == 4
+ Xpath 'a'
+ endif
+ endfunc
+
+ while 1
+ try
+ let v:errmsg = ""
+
+ while 1
+ try
+ Xpath 'b'
+ call {NAME(THROW("name", 1), 1)}(ARG(4711, 1), 1)
+ call assert_report('should not get here')
+ catch /^name$/
+ Xpath 'c'
+ catch /.*/
+ call assert_report('should not get here')
+ finally
+ call assert_equal("", v:errmsg)
+ let v:errmsg = ""
+ break
+ endtry
+ endwhile
+
+ while 1
+ try
+ Xpath 'd'
+ call {NAME("F", 2)}(ARG(THROW("arg", 2), 2), 2)
+ call assert_report('should not get here')
+ catch /^arg$/
+ Xpath 'e'
+ catch /.*/
+ call assert_report('should not get here')
+ finally
+ call assert_equal("", v:errmsg)
+ let v:errmsg = ""
+ break
+ endtry
+ endwhile
+
+ while 1
+ try
+ Xpath 'f'
+ call {NAME("THROW", 3)}(ARG("call", 3), 3)
+ call assert_report('should not get here')
+ catch /^call$/
+ Xpath 'g'
+ catch /^0$/ " default return value
+ call assert_report('should not get here')
+ catch /.*/
+ call assert_report('should not get here')
+ finally
+ call assert_equal("", v:errmsg)
+ let v:errmsg = ""
+ break
+ endtry
+ endwhile
+
+ while 1
+ try
+ Xpath 'h'
+ call {NAME("F", 4)}(ARG(4711, 4), 4)
+ Xpath 'i'
+ catch /.*/
+ call assert_report('should not get here')
+ finally
+ call assert_equal("", v:errmsg)
+ let v:errmsg = ""
+ break
+ endtry
+ endwhile
+
+ catch /^0$/ " default return value
+ call assert_report('should not get here')
+ catch /.*/
+ call assert_report('should not get here')
+ finally
+ call assert_equal("", v:errmsg)
+ let v:errmsg = ""
+ break
+ endtry
+ endwhile
+
+ call assert_equal('bAcdDBefEGCghFIai', g:Xpath)
+ delfunction F
+endfunc
+
+"-------------------------------------------------------------------------------
+" Test 68: :throw across function calls in expressions {{{1
+"
+" On a function call within an expression, an exception might be
+" thrown when evaluating the function name, during evaluation of the
+" arguments, or when the function is being executed. The exception
+" can be caught by the caller.
+"
+" This test reuses the functions THROW(), NAME(), and ARG() from the
+" previous test.
+"-------------------------------------------------------------------------------
+
+func Test_throw_across_call_expr()
+ XpathINIT
+
+ func F(x, n)
+ if a:n == 2
+ call assert_report('should not get here')
+ elseif a:n == 4
+ Xpath 'a'
+ endif
+ return a:x
+ endfunction
+
+ while 1
+ try
+ let error = 0
+ let v:errmsg = ""
+
+ while 1
+ try
+ Xpath 'b'
+ let var1 = {NAME(THROW("name", 1), 1)}(ARG(4711, 1), 1)
+ call assert_report('should not get here')
+ catch /^name$/
+ Xpath 'c'
+ catch /.*/
+ call assert_report('should not get here')
+ finally
+ call assert_equal("", v:errmsg)
+ let v:errmsg = ""
+ break
+ endtry
+ endwhile
+ call assert_true(!exists('var1'))
+
+ while 1
+ try
+ Xpath 'd'
+ let var2 = {NAME("F", 2)}(ARG(THROW("arg", 2), 2), 2)
+ call assert_report('should not get here')
+ catch /^arg$/
+ Xpath 'e'
+ catch /.*/
+ call assert_report('should not get here')
+ finally
+ call assert_equal("", v:errmsg)
+ let v:errmsg = ""
+ break
+ endtry
+ endwhile
+ call assert_true(!exists('var2'))
+
+ while 1
+ try
+ Xpath 'f'
+ let var3 = {NAME("THROW", 3)}(ARG("call", 3), 3)
+ call assert_report('should not get here')
+ catch /^call$/
+ Xpath 'g'
+ catch /^0$/ " default return value
+ call assert_report('should not get here')
+ catch /.*/
+ call assert_report('should not get here')
+ finally
+ call assert_equal("", v:errmsg)
+ let v:errmsg = ""
+ break
+ endtry
+ endwhile
+ call assert_true(!exists('var3'))
+
+ while 1
+ try
+ Xpath 'h'
+ let var4 = {NAME("F", 4)}(ARG(4711, 4), 4)
+ Xpath 'i'
+ catch /.*/
+ call assert_report('should not get here')
+ finally
+ call assert_equal("", v:errmsg)
+ let v:errmsg = ""
+ break
+ endtry
+ endwhile
+ call assert_true(exists('var4') && var4 == 4711)
+
+ catch /^0$/ " default return value
+ call assert_report('should not get here')
+ catch /.*/
+ call assert_report('should not get here')
+ finally
+ call assert_equal("", v:errmsg)
+ break
+ endtry
+ endwhile
+
+ call assert_equal('bAcdDBefEGCghFIai', g:Xpath)
+ delfunc F
+endfunc
+
+"-------------------------------------------------------------------------------
+" Test 76: Errors, interrupts, :throw during expression evaluation {{{1
+"
+" When a function call made during expression evaluation is aborted
+" due to an error inside a :try/:endtry region or due to an interrupt
+" or a :throw, the expression evaluation is aborted as well. No
+" message is displayed for the cancelled expression evaluation. On an
+" error not inside :try/:endtry, the expression evaluation continues.
+"-------------------------------------------------------------------------------
+
+func Test_expr_eval_error()
+ let test =<< trim [CODE]
+ let taken = ""
+
+ func ERR(n)
+ let g:taken = g:taken .. "E" .. a:n
+ asdf
+ endfunc
+
+ func ERRabort(n) abort
+ let g:taken = g:taken .. "A" .. a:n
+ asdf
+ endfunc " returns -1; may cause follow-up msg for illegal var/func name
+
+ func WRAP(n, arg)
+ let g:taken = g:taken .. "W" .. a:n
+ let g:saved_errmsg = v:errmsg
+ return arg
+ endfunc
+
+ func INT(n)
+ let g:taken = g:taken .. "I" .. a:n
+ call interrupt()
+ endfunc
+
+ func THR(n)
+ let g:taken = g:taken .. "T" .. a:n
+ throw "should not be caught"
+ endfunc
+
+ func CONT(n)
+ let g:taken = g:taken .. "C" .. a:n
+ endfunc
+
+ func MSG(n)
+ let g:taken = g:taken .. "M" .. a:n
+ let errmsg = (a:n >= 37 && a:n <= 44) ? g:saved_errmsg : v:errmsg
+ let msgptn = (a:n >= 10 && a:n <= 27) ? "^$" : "asdf"
+ call assert_match(msgptn, errmsg)
+ let v:errmsg = ""
+ let g:saved_errmsg = ""
+ endfunc
+
+ let v:errmsg = ""
+
+ try
+ let t = 1
+ while t <= 9
+ Xloop 'a'
+ try
+ if t == 1
+ let v{ERR(t) + CONT(t)} = 0
+ elseif t == 2
+ let v{ERR(t) + CONT(t)}
+ elseif t == 3
+ let var = exists('v{ERR(t) + CONT(t)}')
+ elseif t == 4
+ unlet v{ERR(t) + CONT(t)}
+ elseif t == 5
+ function F{ERR(t) + CONT(t)}()
+ endfunction
+ elseif t == 6
+ function F{ERR(t) + CONT(t)}
+ elseif t == 7
+ let var = exists('*F{ERR(t) + CONT(t)}')
+ elseif t == 8
+ delfunction F{ERR(t) + CONT(t)}
+ elseif t == 9
+ let var = ERR(t) + CONT(t)
+ endif
+ catch /asdf/
+ " v:errmsg is not set when the error message is converted to an
+ " exception. Set it to the original error message.
+ let v:errmsg = substitute(v:exception, '^Vim:', '', "")
+ catch /^Vim\((\a\+)\)\=:/
+ " An error exception has been thrown after the original error.
+ let v:errmsg = ""
+ finally
+ call MSG(t)
+ let t = t + 1
+ XloopNEXT
+ continue " discard an aborting error
+ endtry
+ endwhile
+ catch /.*/
+ call assert_report('should not get here')
+ endtry
+
+ try
+ let t = 10
+ while t <= 18
+ Xloop 'b'
+ try
+ if t == 10
+ let v{INT(t) + CONT(t)} = 0
+ elseif t == 11
+ let v{INT(t) + CONT(t)}
+ elseif t == 12
+ let var = exists('v{INT(t) + CONT(t)}')
+ elseif t == 13
+ unlet v{INT(t) + CONT(t)}
+ elseif t == 14
+ function F{INT(t) + CONT(t)}()
+ endfunction
+ elseif t == 15
+ function F{INT(t) + CONT(t)}
+ elseif t == 16
+ let var = exists('*F{INT(t) + CONT(t)}')
+ elseif t == 17
+ delfunction F{INT(t) + CONT(t)}
+ elseif t == 18
+ let var = INT(t) + CONT(t)
+ endif
+ catch /^Vim\((\a\+)\)\=:\(Interrupt\)\@!/
+ " An error exception has been triggered after the interrupt.
+ let v:errmsg = substitute(v:exception, '^Vim\((\a\+)\)\=:', '', "")
+ finally
+ call MSG(t)
+ let t = t + 1
+ XloopNEXT
+ continue " discard interrupt
+ endtry
+ endwhile
+ catch /.*/
+ call assert_report('should not get here')
+ endtry
+
+ try
+ let t = 19
+ while t <= 27
+ Xloop 'c'
+ try
+ if t == 19
+ let v{THR(t) + CONT(t)} = 0
+ elseif t == 20
+ let v{THR(t) + CONT(t)}
+ elseif t == 21
+ let var = exists('v{THR(t) + CONT(t)}')
+ elseif t == 22
+ unlet v{THR(t) + CONT(t)}
+ elseif t == 23
+ function F{THR(t) + CONT(t)}()
+ endfunction
+ elseif t == 24
+ function F{THR(t) + CONT(t)}
+ elseif t == 25
+ let var = exists('*F{THR(t) + CONT(t)}')
+ elseif t == 26
+ delfunction F{THR(t) + CONT(t)}
+ elseif t == 27
+ let var = THR(t) + CONT(t)
+ endif
+ catch /^Vim\((\a\+)\)\=:/
+ " An error exception has been triggered after the :throw.
+ let v:errmsg = substitute(v:exception, '^Vim\((\a\+)\)\=:', '', "")
+ finally
+ call MSG(t)
+ let t = t + 1
+ XloopNEXT
+ continue " discard exception
+ endtry
+ endwhile
+ catch /.*/
+ call assert_report('should not get here')
+ endtry
+
+ let v{ERR(28) + CONT(28)} = 0
+ call MSG(28)
+ let v{ERR(29) + CONT(29)}
+ call MSG(29)
+ let var = exists('v{ERR(30) + CONT(30)}')
+ call MSG(30)
+ unlet v{ERR(31) + CONT(31)}
+ call MSG(31)
+ function F{ERR(32) + CONT(32)}()
+ endfunction
+ call MSG(32)
+ function F{ERR(33) + CONT(33)}
+ call MSG(33)
+ let var = exists('*F{ERR(34) + CONT(34)}')
+ call MSG(34)
+ delfunction F{ERR(35) + CONT(35)}
+ call MSG(35)
+ let var = ERR(36) + CONT(36)
+ call MSG(36)
+
+ let saved_errmsg = ""
+
+ let v{WRAP(37, ERRabort(37)) + CONT(37)} = 0
+ call MSG(37)
+ let v{WRAP(38, ERRabort(38)) + CONT(38)}
+ call MSG(38)
+ let var = exists('v{WRAP(39, ERRabort(39)) + CONT(39)}')
+ call MSG(39)
+ unlet v{WRAP(40, ERRabort(40)) + CONT(40)}
+ call MSG(40)
+ function F{WRAP(41, ERRabort(41)) + CONT(41)}()
+ endfunction
+ call MSG(41)
+ function F{WRAP(42, ERRabort(42)) + CONT(42)}
+ call MSG(42)
+ let var = exists('*F{WRAP(43, ERRabort(43)) + CONT(43)}')
+ call MSG(43)
+ delfunction F{WRAP(44, ERRabort(44)) + CONT(44)}
+ call MSG(44)
+ let var = ERRabort(45) + CONT(45)
+ call MSG(45)
+ Xpath 'd'
+
+ let expected = ""
+ \ .. "E1M1E2M2E3M3E4M4E5M5E6M6E7M7E8M8E9M9"
+ \ .. "I10M10I11M11I12M12I13M13I14M14I15M15I16M16I17M17I18M18"
+ \ .. "T19M19T20M20T21M21T22M22T23M23T24M24T25M25T26M26T27M27"
+ \ .. "E28C28M28E29C29M29E30C30M30E31C31M31E32C32M32E33C33M33"
+ \ .. "E34C34M34E35C35M35E36C36M36"
+ \ .. "A37W37C37M37A38W38C38M38A39W39C39M39A40W40C40M40A41W41C41M41"
+ \ .. "A42W42C42M42A43W43C43M43A44W44C44M44A45C45M45"
+ call assert_equal(expected, taken)
+ [CODE]
+ let verify =<< trim [CODE]
+ let expected = "a1a2a3a4a5a6a7a8a9"
+ \ .. "b10b11b12b13b14b15b16b17b18"
+ \ .. "c19c20c21c22c23c24c25c26c27d"
+ call assert_equal(expected, g:Xpath)
+ [CODE]
+ call RunInNewVim(test, verify)
+endfunc
+
+"-------------------------------------------------------------------------------
+" Test 77: Errors, interrupts, :throw in name{brace-expression} {{{1
+"
+" When a function call made during evaluation of an expression in
+" braces as part of a function name after ":function" is aborted due
+" to an error inside a :try/:endtry region or due to an interrupt or
+" a :throw, the expression evaluation is aborted as well, and the
+" function definition is ignored, skipping all commands to the
+" ":endfunction". On an error not inside :try/:endtry, the expression
+" evaluation continues and the function gets defined, and can be
+" called and deleted.
+"-------------------------------------------------------------------------------
+func Test_brace_expr_error()
+ let test =<< trim [CODE]
+ func ERR() abort
+ Xloop 'a'
+ asdf
+ endfunc " returns -1
+
+ func OK()
+ Xloop 'b'
+ let v:errmsg = ""
+ return 0
+ endfunc
+
+ let v:errmsg = ""
+
+ Xpath 'c'
+ func F{1 + ERR() + OK()}(arg)
+ " F0 should be defined.
+ if exists("a:arg") && a:arg == "calling"
+ Xpath 'd'
+ else
+ call assert_report('should not get here')
+ endif
+ endfunction
+ call assert_equal("", v:errmsg)
+ XloopNEXT
+
+ Xpath 'e'
+ call F{1 + ERR() + OK()}("calling")
+ call assert_equal("", v:errmsg)
+ XloopNEXT
+
+ Xpath 'f'
+ delfunction F{1 + ERR() + OK()}
+ call assert_equal("", v:errmsg)
+ XloopNEXT
+
+ try
+ while 1
+ try
+ Xpath 'g'
+ func G{1 + ERR() + OK()}(arg)
+ " G0 should not be defined, and the function body should be
+ " skipped.
+ call assert_report('should not get here')
+ " Use an unmatched ":finally" to check whether the body is
+ " skipped when an error occurs in ERR(). This works whether or
+ " not the exception is converted to an exception.
+ finally
+ call assert_report('should not get here')
+ endtry
+ try
+ call assert_report('should not get here')
+ endfunction
+
+ call assert_report('should not get here')
+ catch /asdf/
+ " Jumped to when the function is not defined and the body is
+ " skipped.
+ Xpath 'h'
+ catch /.*/
+ call assert_report('should not get here')
+ finally
+ Xpath 'i'
+ break
+ endtry " jumped to when the body is not skipped
+ endwhile
+ catch /.*/
+ call assert_report('should not get here')
+ endtry
+ [CODE]
+ let verify =<< trim [CODE]
+ call assert_equal('ca1b1ea2b2dfa3b3ga4hi', g:Xpath)
+ [CODE]
+ call RunInNewVim(test, verify)
+endfunc
+
+"-------------------------------------------------------------------------------
+" Test 78: Messages on parsing errors in expression evaluation {{{1
+"
+" When an expression evaluation detects a parsing error, an error
+" message is given and converted to an exception, and the expression
+" evaluation is aborted.
+"-------------------------------------------------------------------------------
+func Test_expr_eval_error_msg()
+ CheckEnglish
+
+ let test =<< trim [CODE]
+ let taken = ""
+
+ func F(n)
+ let g:taken = g:taken . "F" . a:n
+ endfunc
+
+ func MSG(n, enr, emsg)
+ let g:taken = g:taken . "M" . a:n
+ call assert_match('^' .. a:enr .. ':', v:errmsg)
+ call assert_match(a:emsg, v:errmsg)
+ endfunc
+
+ func CONT(n)
+ let g:taken = g:taken . "C" . a:n
+ endfunc
+
+ let v:errmsg = ""
+ try
+ let t = 1
+ while t <= 14
+ let g:taken = g:taken . "T" . t
+ let v:errmsg = ""
+ try
+ if t == 1
+ let v{novar + CONT(t)} = 0
+ elseif t == 2
+ let v{novar + CONT(t)}
+ elseif t == 3
+ let var = exists('v{novar + CONT(t)}')
+ elseif t == 4
+ unlet v{novar + CONT(t)}
+ elseif t == 5
+ function F{novar + CONT(t)}()
+ endfunction
+ elseif t == 6
+ function F{novar + CONT(t)}
+ elseif t == 7
+ let var = exists('*F{novar + CONT(t)}')
+ elseif t == 8
+ delfunction F{novar + CONT(t)}
+ elseif t == 9
+ echo novar + CONT(t)
+ elseif t == 10
+ echo v{novar + CONT(t)}
+ elseif t == 11
+ echo F{novar + CONT(t)}
+ elseif t == 12
+ let var = novar + CONT(t)
+ elseif t == 13
+ let var = v{novar + CONT(t)}
+ elseif t == 14
+ let var = F{novar + CONT(t)}()
+ endif
+ catch /^Vim\((\a\+)\)\=:/
+ Xloop 'a'
+ " v:errmsg is not set when the error message is converted to an
+ " exception. Set it to the original error message.
+ let v:errmsg = substitute(v:exception, '^Vim\((\a\+)\)\=:', '', "")
+ finally
+ Xloop 'b'
+ if t <= 8 && t != 3 && t != 7
+ call MSG(t, 'E475', 'Invalid argument\>')
+ else
+ call MSG(t, 'E121', "Undefined variable")
+ endif
+ let t = t + 1
+ XloopNEXT
+ continue " discard an aborting error
+ endtry
+ endwhile
+ catch /.*/
+ call assert_report('should not get here')
+ endtry
+
+ func T(n, expr, enr, emsg)
+ try
+ let g:taken = g:taken . "T" . a:n
+ let v:errmsg = ""
+ try
+ execute "let var = " . a:expr
+ catch /^Vim\((\a\+)\)\=:/
+ Xloop 'c'
+ " v:errmsg is not set when the error message is converted to an
+ " exception. Set it to the original error message.
+ let v:errmsg = substitute(v:exception, '^Vim\((\a\+)\)\=:', '', "")
+ finally
+ Xloop 'd'
+ call MSG(a:n, a:enr, a:emsg)
+ XloopNEXT
+ " Discard an aborting error:
+ return
+ endtry
+ catch /.*/
+ call assert_report('should not get here')
+ endtry
+ endfunc
+
+ call T(15, 'Nofunc() + CONT(15)', 'E117', "Unknown function")
+ call T(16, 'F(1 2 + CONT(16))', 'E116', "Invalid arguments")
+ call T(17, 'F(1, 2) + CONT(17)', 'E118', "Too many arguments")
+ call T(18, 'F() + CONT(18)', 'E119', "Not enough arguments")
+ call T(19, '{(1} + CONT(19)', 'E110', "Missing ')'")
+ call T(20, '("abc"[1) + CONT(20)', 'E111', "Missing ']'")
+ call T(21, '(1 +) + CONT(21)', 'E15', "Invalid expression")
+ call T(22, '1 2 + CONT(22)', 'E488', "Trailing characters: 2 +")
+ call T(23, '(1 ? 2) + CONT(23)', 'E109', "Missing ':' after '?'")
+ call T(24, '("abc) + CONT(24)', 'E114', "Missing quote")
+ call T(25, "('abc) + CONT(25)", 'E115', "Missing quote")
+ call T(26, '& + CONT(26)', 'E112', "Option name missing")
+ call T(27, '&asdf + CONT(27)', 'E113', "Unknown option")
+
+ let expected = ""
+ \ .. "T1M1T2M2T3M3T4M4T5M5T6M6T7M7T8M8T9M9T10M10T11M11T12M12T13M13T14M14"
+ \ .. "T15M15T16M16T17M17T18M18T19M19T20M20T21M21T22M22T23M23T24M24T25M25"
+ \ .. "T26M26T27M27"
+
+ call assert_equal(expected, taken)
+ [CODE]
+ let verify =<< trim [CODE]
+ let expected = "a1b1a2b2a3b3a4b4a5b5a6b6a7b7a8b8a9b9a10b10a11b11a12b12"
+ \ .. "a13b13a14b14c15d15c16d16c17d17c18d18c19d19c20d20"
+ \ .. "c21d21c22d22c23d23c24d24c25d25c26d26c27d27"
+ call assert_equal(expected, g:Xpath)
+ [CODE]
+ call RunInNewVim(test, verify)
+endfunc
+
+"-------------------------------------------------------------------------------
+" Test 79: Throwing one of several errors for the same command {{{1
+"
+" When several errors appear in a row (for instance during expression
+" evaluation), the first as the most specific one is used when
+" throwing an error exception. If, however, a syntax error is
+" detected afterwards, this one is used for the error exception.
+" On a syntax error, the next command is not executed, on a normal
+" error, however, it is (relevant only in a function without the
+" "abort" flag). v:errmsg is not set.
+"
+" If throwing error exceptions is configured off, v:errmsg is always
+" set to the latest error message, that is, to the more general
+" message or the syntax error, respectively.
+"-------------------------------------------------------------------------------
+func Test_throw_multi_error()
+ CheckEnglish
+
+ let test =<< trim [CODE]
+ func NEXT(cmd)
+ exec a:cmd . " | Xloop 'a'"
+ endfun
+
+ call NEXT('echo novar') " (checks nextcmd)
+ XloopNEXT
+ call NEXT('let novar #') " (skips nextcmd)
+ XloopNEXT
+ call NEXT('unlet novar #') " (skips nextcmd)
+ XloopNEXT
+ call NEXT('let {novar}') " (skips nextcmd)
+ XloopNEXT
+ call NEXT('unlet{ novar}') " (skips nextcmd)
+
+ call assert_equal('a1', g:Xpath)
+ XpathINIT
+ XloopINIT
+
+ func EXEC(cmd)
+ exec a:cmd
+ endfunc
+
+ try
+ while 1 " dummy loop
+ try
+ let v:errmsg = ""
+ call EXEC('echo novar') " normal error
+ catch /^Vim\((\a\+)\)\=:/
+ Xpath 'b'
+ call assert_match('E121: Undefined variable: novar', v:exception)
+ finally
+ Xpath 'c'
+ call assert_equal("", v:errmsg)
+ break
+ endtry
+ endwhile
+
+ Xpath 'd'
+ let cmd = "let"
+ while cmd != ""
+ try
+ let v:errmsg = ""
+ call EXEC(cmd . ' novar #') " normal plus syntax error
+ catch /^Vim\((\a\+)\)\=:/
+ Xloop 'e'
+ call assert_match('E488: Trailing characters', v:exception)
+ finally
+ Xloop 'f'
+ call assert_equal("", v:errmsg)
+ if cmd == "let"
+ let cmd = "unlet"
+ else
+ let cmd = ""
+ endif
+ XloopNEXT
+ continue
+ endtry
+ endwhile
+
+ Xpath 'g'
+ let cmd = "let"
+ while cmd != ""
+ try
+ let v:errmsg = ""
+ call EXEC(cmd . ' {novar}') " normal plus syntax error
+ catch /^Vim\((\a\+)\)\=:/
+ Xloop 'h'
+ call assert_match('E475: Invalid argument: {novar}', v:exception)
+ finally
+ Xloop 'i'
+ call assert_equal("", v:errmsg)
+ if cmd == "let"
+ let cmd = "unlet"
+ else
+ let cmd = ""
+ endif
+ XloopNEXT
+ continue
+ endtry
+ endwhile
+ catch /.*/
+ call assert_report('should not get here')
+ endtry
+ Xpath 'j'
+ [CODE]
+ let verify =<< trim [CODE]
+ call assert_equal('bcde1f1e2f2gh3i3h4i4j', g:Xpath)
+ [CODE]
+ call RunInNewVim(test, verify)
+endfunc
+
+"-------------------------------------------------------------------------------
+" Test 80: Syntax error in expression for illegal :elseif {{{1
+"
+" If there is a syntax error in the expression after an illegal
+" :elseif, an error message is given (or an error exception thrown)
+" for the illegal :elseif rather than the expression error.
+"-------------------------------------------------------------------------------
+func Test_if_syntax_error()
+ CheckEnglish
+
+ let test =<< trim [CODE]
+ let v:errmsg = ""
+ if 0
+ else
+ elseif 1 ||| 2
+ endif
+ Xpath 'a'
+ call assert_match('E584: :elseif after :else', v:errmsg)
+
+ let v:errmsg = ""
+ if 1
+ else
+ elseif 1 ||| 2
+ endif
+ Xpath 'b'
+ call assert_match('E584: :elseif after :else', v:errmsg)
+
+ let v:errmsg = ""
+ elseif 1 ||| 2
+ Xpath 'c'
+ call assert_match('E582: :elseif without :if', v:errmsg)
+
+ let v:errmsg = ""
+ while 1
+ elseif 1 ||| 2
+ endwhile
+ Xpath 'd'
+ call assert_match('E582: :elseif without :if', v:errmsg)
+
+ while 1
+ try
+ try
+ let v:errmsg = ""
+ if 0
+ else
+ elseif 1 ||| 2
+ endif
+ catch /^Vim\((\a\+)\)\=:/
+ Xpath 'e'
+ call assert_match('E584: :elseif after :else', v:exception)
+ finally
+ Xpath 'f'
+ call assert_equal("", v:errmsg)
+ endtry
+ catch /.*/
+ call assert_report('should not get here')
+ finally
+ Xpath 'g'
+ break
+ endtry
+ endwhile
+
+ while 1
+ try
+ try
+ let v:errmsg = ""
+ if 1
+ else
+ elseif 1 ||| 2
+ endif
+ catch /^Vim\((\a\+)\)\=:/
+ Xpath 'h'
+ call assert_match('E584: :elseif after :else', v:exception)
+ finally
+ Xpath 'i'
+ call assert_equal("", v:errmsg)
+ endtry
+ catch /.*/
+ call assert_report('should not get here')
+ finally
+ Xpath 'j'
+ break
+ endtry
+ endwhile
+
+ while 1
+ try
+ try
+ let v:errmsg = ""
+ elseif 1 ||| 2
+ catch /^Vim\((\a\+)\)\=:/
+ Xpath 'k'
+ call assert_match('E582: :elseif without :if', v:exception)
+ finally
+ Xpath 'l'
+ call assert_equal("", v:errmsg)
+ endtry
+ catch /.*/
+ call assert_report('should not get here')
+ finally
+ Xpath 'm'
+ break
+ endtry
+ endwhile
+
+ while 1
+ try
+ try
+ let v:errmsg = ""
+ while 1
+ elseif 1 ||| 2
+ endwhile
+ catch /^Vim\((\a\+)\)\=:/
+ Xpath 'n'
+ call assert_match('E582: :elseif without :if', v:exception)
+ finally
+ Xpath 'o'
+ call assert_equal("", v:errmsg)
+ endtry
+ catch /.*/
+ call assert_report('should not get here')
+ finally
+ Xpath 'p'
+ break
+ endtry
+ endwhile
+ Xpath 'q'
+ [CODE]
+ let verify =<< trim [CODE]
+ call assert_equal('abcdefghijklmnopq', g:Xpath)
+ [CODE]
+ call RunInNewVim(test, verify)
+endfunc
+
+"-------------------------------------------------------------------------------
+" Test 81: Discarding exceptions after an error or interrupt {{{1
+"
+" When an exception is thrown from inside a :try conditional without
+" :catch and :finally clauses and an error or interrupt occurs before
+" the :endtry is reached, the exception is discarded.
+"-------------------------------------------------------------------------------
+
+func Test_discard_exception_after_error_1()
+ let test =<< trim [CODE]
+ try
+ Xpath 'a'
+ try
+ Xpath 'b'
+ throw "arrgh"
+ call assert_report('should not get here')
+ if 1
+ call assert_report('should not get here')
+ " error after :throw: missing :endif
+ endtry
+ call assert_report('should not get here')
+ catch /arrgh/
+ call assert_report('should not get here')
+ endtry
+ call assert_report('should not get here')
+ [CODE]
+ let verify =<< trim [CODE]
+ call assert_equal('ab', g:Xpath)
+ [CODE]
+ call RunInNewVim(test, verify)
+endfunc
+
+" interrupt the code before the endtry is invoked
+func Test_discard_exception_after_error_2()
+ XpathINIT
+ let lines =<< trim [CODE]
+ try
+ Xpath 'a'
+ try
+ Xpath 'b'
+ throw "arrgh"
+ call assert_report('should not get here')
+ endtry " interrupt here
+ call assert_report('should not get here')
+ catch /arrgh/
+ call assert_report('should not get here')
+ endtry
+ call assert_report('should not get here')
+ [CODE]
+ call writefile(lines, 'Xscript')
+
+ breakadd file 7 Xscript
+ try
+ let caught_intr = 0
+ debuggreedy
+ call feedkeys(":source Xscript\<CR>quit\<CR>", "xt")
+ catch /^Vim:Interrupt$/
+ call assert_match('Xscript, line 7', v:throwpoint)
+ let caught_intr = 1
+ endtry
+ 0debuggreedy
+ call assert_equal(1, caught_intr)
+ call assert_equal('ab', g:Xpath)
+ breakdel *
+ call delete('Xscript')
+endfunc
+
+"-------------------------------------------------------------------------------
+" Test 82: Ignoring :catch clauses after an error or interrupt {{{1
+"
+" When an exception is thrown and an error or interrupt occurs before
+" the matching :catch clause is reached, the exception is discarded
+" and the :catch clause is ignored (also for the error or interrupt
+" exception being thrown then).
+"-------------------------------------------------------------------------------
+
+func Test_ignore_catch_after_error_1()
+ let test =<< trim [CODE]
+ try
+ try
+ Xpath 'a'
+ throw "arrgh"
+ call assert_report('should not get here')
+ if 1
+ call assert_report('should not get here')
+ " error after :throw: missing :endif
+ catch /.*/
+ call assert_report('should not get here')
+ catch /.*/
+ call assert_report('should not get here')
+ endtry
+ call assert_report('should not get here')
+ catch /arrgh/
+ call assert_report('should not get here')
+ endtry
+ call assert_report('should not get here')
+ [CODE]
+ let verify =<< trim [CODE]
+ call assert_equal('a', g:Xpath)
+ [CODE]
+ call RunInNewVim(test, verify)
+endfunc
+
+func Test_ignore_catch_after_error_2()
+ let test =<< trim [CODE]
+ func E()
+ try
+ try
+ Xpath 'a'
+ throw "arrgh"
+ call assert_report('should not get here')
+ if 1
+ call assert_report('should not get here')
+ " error after :throw: missing :endif
+ catch /.*/
+ call assert_report('should not get here')
+ catch /.*/
+ call assert_report('should not get here')
+ endtry
+ call assert_report('should not get here')
+ catch /arrgh/
+ call assert_report('should not get here')
+ endtry
+ endfunc
+
+ call E()
+ call assert_report('should not get here')
+ [CODE]
+ let verify =<< trim [CODE]
+ call assert_equal('a', g:Xpath)
+ [CODE]
+ call RunInNewVim(test, verify)
+endfunc
+
+" interrupt right before a catch is invoked in a script
+func Test_ignore_catch_after_intr_1()
+ XpathINIT
+ let lines =<< trim [CODE]
+ try
+ try
+ Xpath 'a'
+ throw "arrgh"
+ call assert_report('should not get here')
+ catch /.*/ " interrupt here
+ call assert_report('should not get here')
+ catch /.*/
+ call assert_report('should not get here')
+ endtry
+ call assert_report('should not get here')
+ catch /arrgh/
+ call assert_report('should not get here')
+ endtry
+ call assert_report('should not get here')
+ [CODE]
+ call writefile(lines, 'Xscript')
+
+ breakadd file 6 Xscript
+ try
+ let caught_intr = 0
+ debuggreedy
+ call feedkeys(":source Xscript\<CR>quit\<CR>", "xt")
+ catch /^Vim:Interrupt$/
+ call assert_match('Xscript, line 6', v:throwpoint)
+ let caught_intr = 1
+ endtry
+ 0debuggreedy
+ call assert_equal(1, caught_intr)
+ call assert_equal('a', g:Xpath)
+ breakdel *
+ call delete('Xscript')
+endfunc
+
+" interrupt right before a catch is invoked inside a function.
+func Test_ignore_catch_after_intr_2()
+ XpathINIT
+ func F()
+ try
+ try
+ Xpath 'a'
+ throw "arrgh"
+ call assert_report('should not get here')
+ catch /.*/ " interrupt here
+ call assert_report('should not get here')
+ catch /.*/
+ call assert_report('should not get here')
+ endtry
+ call assert_report('should not get here')
+ catch /arrgh/
+ call assert_report('should not get here')
+ endtry
+ call assert_report('should not get here')
+ endfunc
+
+ breakadd func 6 F
+ try
+ let caught_intr = 0
+ debuggreedy
+ call feedkeys(":call F()\<CR>quit\<CR>", "xt")
+ catch /^Vim:Interrupt$/
+ call assert_match('\.F, line 6', v:throwpoint)
+ let caught_intr = 1
+ endtry
+ 0debuggreedy
+ call assert_equal(1, caught_intr)
+ call assert_equal('a', g:Xpath)
+ breakdel *
+ delfunc F
+endfunc
+
+"-------------------------------------------------------------------------------
+" Test 83: Executing :finally clauses after an error or interrupt {{{1
+"
+" When an exception is thrown and an error or interrupt occurs before
+" the :finally of the innermost :try is reached, the exception is
+" discarded and the :finally clause is executed.
+"-------------------------------------------------------------------------------
+
+func Test_finally_after_error()
+ let test =<< trim [CODE]
+ try
+ Xpath 'a'
+ try
+ Xpath 'b'
+ throw "arrgh"
+ call assert_report('should not get here')
+ if 1
+ call assert_report('should not get here')
+ " error after :throw: missing :endif
+ finally
+ Xpath 'c'
+ endtry
+ call assert_report('should not get here')
+ catch /arrgh/
+ call assert_report('should not get here')
+ endtry
+ call assert_report('should not get here')
+ [CODE]
+ let verify =<< trim [CODE]
+ call assert_equal('abc', g:Xpath)
+ [CODE]
+ call RunInNewVim(test, verify)
+endfunc
+
+" interrupt the code right before the finally is invoked
+func Test_finally_after_intr()
+ XpathINIT
+ let lines =<< trim [CODE]
+ try
+ Xpath 'a'
+ try
+ Xpath 'b'
+ throw "arrgh"
+ call assert_report('should not get here')
+ finally " interrupt here
+ Xpath 'c'
+ endtry
+ call assert_report('should not get here')
+ catch /arrgh/
+ call assert_report('should not get here')
+ endtry
+ call assert_report('should not get here')
+ [CODE]
+ call writefile(lines, 'Xscript')
+
+ breakadd file 7 Xscript
+ try
+ let caught_intr = 0
+ debuggreedy
+ call feedkeys(":source Xscript\<CR>quit\<CR>", "xt")
+ catch /^Vim:Interrupt$/
+ call assert_match('Xscript, line 7', v:throwpoint)
+ let caught_intr = 1
+ endtry
+ 0debuggreedy
+ call assert_equal(1, caught_intr)
+ call assert_equal('abc', g:Xpath)
+ breakdel *
+ call delete('Xscript')
+endfunc
+
+"-------------------------------------------------------------------------------
+" Test 84: Exceptions in autocommand sequences. {{{1
+"
+" When an exception occurs in a sequence of autocommands for
+" a specific event, the rest of the sequence is not executed. The
+" command that triggered the autocommand execution aborts, and the
+" exception is propagated to the caller.
+"
+" For the FuncUndefined event under a function call expression or
+" :call command, the function is not executed, even when it has
+" been defined by the autocommands before the exception occurred.
+"-------------------------------------------------------------------------------
+
+func Test_autocmd_exception()
+ let test =<< trim [CODE]
+ func INT()
+ call interrupt()
+ endfunc
+
+ aug TMP
+ autocmd!
+
+ autocmd User x1 Xpath 'a'
+ autocmd User x1 throw "x1"
+ autocmd User x1 call assert_report('should not get here')
+
+ autocmd User x2 Xpath 'b'
+ autocmd User x2 asdf
+ autocmd User x2 call assert_report('should not get here')
+
+ autocmd User x3 Xpath 'c'
+ autocmd User x3 call INT()
+ autocmd User x3 call assert_report('should not get here')
+
+ autocmd FuncUndefined U1 func U1()
+ autocmd FuncUndefined U1 call assert_report('should not get here')
+ autocmd FuncUndefined U1 endfunc
+ autocmd FuncUndefined U1 Xpath 'd'
+ autocmd FuncUndefined U1 throw "U1"
+ autocmd FuncUndefined U1 call assert_report('should not get here')
+
+ autocmd FuncUndefined U2 func U2()
+ autocmd FuncUndefined U2 call assert_report('should not get here')
+ autocmd FuncUndefined U2 endfunc
+ autocmd FuncUndefined U2 Xpath 'e'
+ autocmd FuncUndefined U2 ASDF
+ autocmd FuncUndefined U2 call assert_report('should not get here')
+
+ autocmd FuncUndefined U3 func U3()
+ autocmd FuncUndefined U3 call assert_report('should not get here')
+ autocmd FuncUndefined U3 endfunc
+ autocmd FuncUndefined U3 Xpath 'f'
+ autocmd FuncUndefined U3 call INT()
+ autocmd FuncUndefined U3 call assert_report('should not get here')
+ aug END
+
+ try
+ try
+ Xpath 'g'
+ doautocmd User x1
+ catch /x1/
+ Xpath 'h'
+ endtry
+
+ while 1
+ try
+ Xpath 'i'
+ doautocmd User x2
+ catch /asdf/
+ Xpath 'j'
+ finally
+ Xpath 'k'
+ break
+ endtry
+ endwhile
+
+ while 1
+ try
+ Xpath 'l'
+ doautocmd User x3
+ catch /Vim:Interrupt/
+ Xpath 'm'
+ finally
+ Xpath 'n'
+ " ... but break loop for caught interrupt exception,
+ " or discard interrupt and break loop if $VIMNOINTTHROW
+ break
+ endtry
+ endwhile
+
+ if exists("*U1") | delfunction U1 | endif
+ if exists("*U2") | delfunction U2 | endif
+ if exists("*U3") | delfunction U3 | endif
+
+ try
+ Xpath 'o'
+ call U1()
+ catch /U1/
+ Xpath 'p'
+ endtry
+
+ while 1
+ try
+ Xpath 'q'
+ call U2()
+ catch /ASDF/
+ Xpath 'r'
+ finally
+ Xpath 's'
+ " ... but break loop for caught error exception,
+ " or discard error and break loop if $VIMNOERRTHROW
+ break
+ endtry
+ endwhile
+
+ while 1
+ try
+ Xpath 't'
+ call U3()
+ catch /Vim:Interrupt/
+ Xpath 'u'
+ finally
+ Xpath 'v'
+ " ... but break loop for caught interrupt exception,
+ " or discard interrupt and break loop if $VIMNOINTTHROW
+ break
+ endtry
+ endwhile
+ catch /.*/
+ call assert_report('should not get here')
+ endtry
+ Xpath 'w'
+ [CODE]
+ let verify =<< trim [CODE]
+ call assert_equal('gahibjklcmnodpqerstfuvw', g:Xpath)
+ [CODE]
+ call RunInNewVim(test, verify)
+endfunc
+
+"-------------------------------------------------------------------------------
+" Test 85: Error exceptions in autocommands for I/O command events {{{1
+"
+" When an I/O command is inside :try/:endtry, autocommands to be
+" executed after it should be skipped on an error (exception) in the
+" command itself or in autocommands to be executed before the command.
+" In the latter case, the I/O command should not be executed either.
+" Example 1: BufWritePre, :write, BufWritePost
+" Example 2: FileReadPre, :read, FileReadPost.
+"-------------------------------------------------------------------------------
+
+func Test_autocmd_error_io_exception()
+ let test =<< trim [CODE]
+ " Remove the autocommands for the events specified as arguments in all used
+ " autogroups.
+ func Delete_autocommands(...)
+ let augfile = tempname()
+ while 1
+ try
+ exec "redir >" . augfile
+ aug
+ redir END
+ exec "edit" augfile
+ g/^$/d
+ norm G$
+ let wrap = "w"
+ while search('\%( \|^\)\@<=.\{-}\%( \)\@=', wrap) > 0
+ let wrap = "W"
+ exec "norm y/ \n"
+ let argno = 1
+ while argno <= a:0
+ exec "au!" escape(@", " ") a:{argno}
+ let argno = argno + 1
+ endwhile
+ endwhile
+ catch /.*/
+ finally
+ bwipeout!
+ call delete(augfile)
+ break
+ endtry
+ endwhile
+ endfunc
+
+ call Delete_autocommands("BufWritePre", "BufWritePost")
+
+ while 1
+ try
+ try
+ let post = 0
+ aug TMP
+ au! BufWritePost * let post = 1
+ aug END
+ write /n/o/n/e/x/i/s/t/e/n/t
+ catch /^Vim(write):/
+ Xpath 'a'
+ call assert_match("E212: Can't open file for writing", v:exception)
+ finally
+ Xpath 'b'
+ call assert_equal(0, post)
+ au! TMP
+ aug! TMP
+ endtry
+ catch /.*/
+ call assert_report('should not get here')
+ finally
+ Xpath 'c'
+ break
+ endtry
+ endwhile
+
+ while 1
+ try
+ try
+ let post = 0
+ aug TMP
+ au! BufWritePre * asdf
+ au! BufWritePost * let post = 1
+ aug END
+ let tmpfile = tempname()
+ exec "write" tmpfile
+ catch /^Vim\((write)\)\=:/
+ Xpath 'd'
+ call assert_match('E492: Not an editor command', v:exception)
+ finally
+ Xpath 'e'
+ if filereadable(tmpfile)
+ call assert_report('should not get here')
+ endif
+ call assert_equal(0, post)
+ au! TMP
+ aug! TMP
+ endtry
+ catch /.*/
+ call assert_report('should not get here')
+ finally
+ Xpath 'f'
+ break
+ endtry
+ endwhile
+
+ call delete(tmpfile)
+
+ call Delete_autocommands("BufWritePre", "BufWritePost",
+ \ "BufReadPre", "BufReadPost", "FileReadPre", "FileReadPost")
+
+ while 1
+ try
+ try
+ let post = 0
+ aug TMP
+ au! FileReadPost * let post = 1
+ aug END
+ let caught = 0
+ read /n/o/n/e/x/i/s/t/e/n/t
+ catch /^Vim(read):/
+ Xpath 'g'
+ call assert_match("E484: Can't open file", v:exception)
+ finally
+ Xpath 'h'
+ call assert_equal(0, post)
+ au! TMP
+ aug! TMP
+ endtry
+ catch /.*/
+ call assert_report('should not get here')
+ finally
+ Xpath 'i'
+ break
+ endtry
+ endwhile
+
+ while 1
+ try
+ let infile = tempname()
+ let tmpfile = tempname()
+ call writefile(["XYZ"], infile)
+ exec "edit" tmpfile
+ try
+ Xpath 'j'
+ try
+ let post = 0
+ aug TMP
+ au! FileReadPre * asdf
+ au! FileReadPost * let post = 1
+ aug END
+ exec "0read" infile
+ catch /^Vim\((read)\)\=:/
+ Xpath 'k'
+ call assert_match('E492: Not an editor command', v:exception)
+ finally
+ Xpath 'l'
+ if getline("1") == "XYZ"
+ call assert_report('should not get here')
+ endif
+ call assert_equal(0, post)
+ au! TMP
+ aug! TMP
+ endtry
+ finally
+ Xpath 'm'
+ bwipeout!
+ endtry
+ catch /.*/
+ call assert_report('should not get here')
+ finally
+ Xpath 'n'
+ break
+ endtry
+ endwhile
+
+ call delete(infile)
+ call delete(tmpfile)
+ [CODE]
+ let verify =<< trim [CODE]
+ call assert_equal('abcdefghijklmn', g:Xpath)
+ [CODE]
+ call RunInNewVim(test, verify)
+endfunc
+
"-------------------------------------------------------------------------------
" Test 87 using (expr) ? funcref : funcref {{{1
"
@@ -1370,10 +6723,10 @@ endfunc
" Test 95: lines of :append, :change, :insert {{{1
"-------------------------------------------------------------------------------
-function! DefineFunction(name, body)
+func DefineFunction(name, body)
let func = join(['function! ' . a:name . '()'] + a:body + ['endfunction'], "\n")
exec func
-endfunction
+endfunc
func Test_script_lines()
" :append
@@ -1443,7 +6796,7 @@ endfunc
" Undefined behavior was detected by ubsan with line continuation
" after an empty line.
"-------------------------------------------------------------------------------
-func Test_script_emty_line_continuation()
+func Test_script_empty_line_continuation()
\
endfunc
@@ -1495,55 +6848,6 @@ func Test_bitwise_functions()
call assert_fails("call invert({})", 'E728:')
endfunc
-" Test trailing text after :endfunction {{{1
-func Test_endfunction_trailing()
- call assert_false(exists('*Xtest'))
-
- exe "func Xtest()\necho 'hello'\nendfunc\nlet done = 'yes'"
- call assert_true(exists('*Xtest'))
- call assert_equal('yes', done)
- delfunc Xtest
- unlet done
-
- exe "func Xtest()\necho 'hello'\nendfunc|let done = 'yes'"
- call assert_true(exists('*Xtest'))
- call assert_equal('yes', done)
- delfunc Xtest
- unlet done
-
- " trailing line break
- exe "func Xtest()\necho 'hello'\nendfunc\n"
- call assert_true(exists('*Xtest'))
- delfunc Xtest
-
- set verbose=1
- exe "func Xtest()\necho 'hello'\nendfunc \" garbage"
- call assert_notmatch('W22:', split(execute('1messages'), "\n")[0])
- call assert_true(exists('*Xtest'))
- delfunc Xtest
-
- exe "func Xtest()\necho 'hello'\nendfunc garbage"
- call assert_match('W22:', split(execute('1messages'), "\n")[0])
- call assert_true(exists('*Xtest'))
- delfunc Xtest
- set verbose=0
-
- function Foo()
- echo 'hello'
- endfunction | echo 'xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx'
- delfunc Foo
-endfunc
-
-func Test_delfunction_force()
- delfunc! Xtest
- delfunc! Xtest
- func Xtest()
- echo 'nothing'
- endfunc
- delfunc! Xtest
- delfunc! Xtest
-endfunc
-
" Test using bang after user command {{{1
func Test_user_command_with_bang()
command -bang Nieuw let nieuw = 1
@@ -1553,26 +6857,6 @@ func Test_user_command_with_bang()
delcommand Nieuw
endfunc
-" Test for script-local function
-func <SID>DoLast()
- call append(line('$'), "last line")
-endfunc
-
-func s:DoNothing()
- call append(line('$'), "nothing line")
-endfunc
-
-func Test_script_local_func()
- set nocp nomore viminfo+=nviminfo
- new
- nnoremap <buffer> _x :call <SID>DoNothing()<bar>call <SID>DoLast()<bar>delfunc <SID>DoNothing<bar>delfunc <SID>DoLast<cr>
-
- normal _x
- call assert_equal('nothing line', getline(2))
- call assert_equal('last line', getline(3))
- enew! | close
-endfunc
-
func Test_script_expand_sfile()
let lines =<< trim END
func s:snr()
@@ -1653,6 +6937,22 @@ func Test_compound_assignment_operators()
call assert_equal(4.2, x)
call assert_fails('let x %= 0.5', 'E734')
call assert_fails('let x .= "f"', 'E734')
+ let x = !3.14
+ call assert_equal(0.0, x)
+
+ " integer and float operations
+ let x = 1
+ let x *= 2.1
+ call assert_equal(2.1, x)
+ let x = 1
+ let x /= 0.25
+ call assert_equal(4.0, x)
+ let x = 1
+ call assert_fails('let x %= 0.25', 'E734:')
+ let x = 1
+ call assert_fails('let x .= 0.25', 'E734:')
+ let x = 1.0
+ call assert_fails('let x += [1.1]', 'E734:')
endif
" Test for environment variable
@@ -1716,87 +7016,6 @@ func Test_unlet_env()
call assert_equal('', $TESTVAR)
endfunc
-func Test_funccall_garbage_collect()
- func Func(x, ...)
- call add(a:x, a:000)
- endfunc
- call Func([], [])
- " Must not crash cause by invalid freeing
- call test_garbagecollect_now()
- call assert_true(v:true)
- delfunc Func
-endfunc
-
-func Test_function_defined_line()
- if has('gui_running')
- " Can't catch the output of gvim.
- return
- endif
-
- let lines =<< trim [CODE]
- " F1
- func F1()
- " F2
- func F2()
- "
- "
- "
- return
- endfunc
- " F3
- execute "func F3()\n\n\n\nreturn\nendfunc"
- " F4
- execute "func F4()\n
- \\n
- \\n
- \\n
- \return\n
- \endfunc"
- endfunc
- " F5
- execute "func F5()\n\n\n\nreturn\nendfunc"
- " F6
- execute "func F6()\n
- \\n
- \\n
- \\n
- \return\n
- \endfunc"
- call F1()
- verbose func F1
- verbose func F2
- verbose func F3
- verbose func F4
- verbose func F5
- verbose func F6
- qall!
- [CODE]
-
- call writefile(lines, 'Xtest.vim')
- let res = system(GetVimCommandClean() .. ' -es -X -S Xtest.vim')
- call assert_equal(0, v:shell_error)
-
- let m = matchstr(res, 'function F1()[^[:print:]]*[[:print:]]*')
- call assert_match(' line 2$', m)
-
- let m = matchstr(res, 'function F2()[^[:print:]]*[[:print:]]*')
- call assert_match(' line 4$', m)
-
- let m = matchstr(res, 'function F3()[^[:print:]]*[[:print:]]*')
- call assert_match(' line 11$', m)
-
- let m = matchstr(res, 'function F4()[^[:print:]]*[[:print:]]*')
- call assert_match(' line 13$', m)
-
- let m = matchstr(res, 'function F5()[^[:print:]]*[[:print:]]*')
- call assert_match(' line 21$', m)
-
- let m = matchstr(res, 'function F6()[^[:print:]]*[[:print:]]*')
- call assert_match(' line 23$', m)
-
- call delete('Xtest.vim')
-endfunc
-
" Test for missing :endif, :endfor, :endwhile and :endtry {{{1
func Test_missing_end()
call writefile(['if 2 > 1', 'echo ">"'], 'Xscript')
@@ -1829,15 +7048,19 @@ func Test_missing_end()
endtry
call assert_equal(1, caught_e733)
+ " Using endfunc with :if
+ call assert_fails('exe "if 1 | endfunc | endif"', 'E193:')
+
" Missing 'in' in a :for statement
call assert_fails('for i range(1) | endfor', 'E690:')
+
+ " Incorrect number of variables in for
+ call assert_fails('for [i,] in range(3) | endfor', 'E475:')
endfunc
" Test for deep nesting of if/for/while/try statements {{{1
func Test_deep_nest()
- if !CanRunVimInTerminal()
- throw 'Skipped: cannot run vim in terminal'
- endif
+ CheckRunVimInTerminal
let lines =<< trim [SCRIPT]
" Deep nesting of if ... endif
@@ -1875,6 +7098,15 @@ func Test_deep_nest()
@a
let @a = ''
endfunc
+
+ " Deep nesting of function ... endfunction
+ func Test5()
+ let @a = join(repeat(['function X()'], 51), "\n")
+ let @a ..= "\necho v:true\n"
+ let @a ..= join(repeat(['endfunction'], 51), "\n")
+ @a
+ let @a = ''
+ endfunc
[SCRIPT]
call writefile(lines, 'Xscript')
@@ -1882,20 +7114,31 @@ func Test_deep_nest()
" Deep nesting of if ... endif
call term_sendkeys(buf, ":call Test1()\n")
+ call term_wait(buf)
call WaitForAssert({-> assert_match('^E579:', term_getline(buf, 5))})
" Deep nesting of for ... endfor
call term_sendkeys(buf, ":call Test2()\n")
+ call term_wait(buf)
call WaitForAssert({-> assert_match('^E585:', term_getline(buf, 5))})
" Deep nesting of while ... endwhile
call term_sendkeys(buf, ":call Test3()\n")
+ call term_wait(buf)
call WaitForAssert({-> assert_match('^E585:', term_getline(buf, 5))})
" Deep nesting of try ... endtry
call term_sendkeys(buf, ":call Test4()\n")
+ call term_wait(buf)
call WaitForAssert({-> assert_match('^E601:', term_getline(buf, 5))})
+ " Deep nesting of function ... endfunction
+ call term_sendkeys(buf, ":call Test5()\n")
+ call term_wait(buf)
+ call WaitForAssert({-> assert_match('^E1058:', term_getline(buf, 4))})
+ call term_sendkeys(buf, "\<C-C>\n")
+ call term_wait(buf)
+
"let l = ''
"for i in range(1, 6)
" let l ..= term_getline(buf, i) . "\n"
@@ -1906,14 +7149,113 @@ func Test_deep_nest()
call delete('Xscript')
endfunc
-" Test for <sfile>, <slnum> in a function {{{1
-func Test_sfile_in_function()
- func Xfunc()
- call assert_match('..Test_sfile_in_function\[5]..Xfunc', expand('<sfile>'))
- call assert_equal('2', expand('<slnum>'))
- endfunc
- call Xfunc()
- delfunc Xfunc
+" Test for errors in converting to float from various types {{{1
+func Test_float_conversion_errors()
+ if has('float')
+ call assert_fails('let x = 4.0 % 2.0', 'E804')
+ call assert_fails('echo 1.1[0]', 'E806')
+ call assert_fails('echo sort([function("min"), 1], "f")', 'E891:')
+ call assert_fails('echo 3.2 == "vim"', 'E892:')
+ call assert_fails('echo sort([[], 1], "f")', 'E893:')
+ call assert_fails('echo sort([{}, 1], "f")', 'E894:')
+ call assert_fails('echo 3.2 == v:true', 'E362:')
+ " call assert_fails('echo 3.2 == v:none', 'E907:')
+ endif
+endfunc
+
+" invalid function names {{{1
+func Test_invalid_function_names()
+ " function name not starting with capital
+ let caught_e128 = 0
+ try
+ func! g:test()
+ echo "test"
+ endfunc
+ catch /E128:/
+ let caught_e128 = 1
+ endtry
+ call assert_equal(1, caught_e128)
+
+ " function name includes a colon
+ let caught_e884 = 0
+ try
+ func! b:test()
+ echo "test"
+ endfunc
+ catch /E884:/
+ let caught_e884 = 1
+ endtry
+ call assert_equal(1, caught_e884)
+
+ " function name followed by #
+ let caught_e128 = 0
+ try
+ func! test2() "#
+ echo "test2"
+ endfunc
+ catch /E128:/
+ let caught_e128 = 1
+ endtry
+ call assert_equal(1, caught_e128)
+
+ " function name starting with/without "g:", buffer-local funcref.
+ function! g:Foo(n)
+ return 'called Foo(' . a:n . ')'
+ endfunction
+ let b:my_func = function('Foo')
+ call assert_equal('called Foo(1)', b:my_func(1))
+ call assert_equal('called Foo(2)', g:Foo(2))
+ call assert_equal('called Foo(3)', Foo(3))
+ delfunc g:Foo
+
+ " script-local function used in Funcref must exist.
+ let lines =<< trim END
+ func s:Testje()
+ return "foo"
+ endfunc
+ let Bar = function('s:Testje')
+ call assert_equal(0, exists('s:Testje'))
+ call assert_equal(1, exists('*s:Testje'))
+ call assert_equal(1, exists('Bar'))
+ call assert_equal(1, exists('*Bar'))
+ END
+ call writefile(lines, 'Xscript')
+ source Xscript
+ call delete('Xscript')
+endfunc
+
+" substring and variable name {{{1
+func Test_substring_var()
+ let str = 'abcdef'
+ let n = 3
+ call assert_equal('def', str[n:])
+ call assert_equal('abcd', str[:n])
+ call assert_equal('d', str[n:n])
+ unlet n
+ let nn = 3
+ call assert_equal('def', str[nn:])
+ call assert_equal('abcd', str[:nn])
+ call assert_equal('d', str[nn:nn])
+ unlet nn
+ let b:nn = 4
+ call assert_equal('ef', str[b:nn:])
+ call assert_equal('abcde', str[:b:nn])
+ call assert_equal('e', str[b:nn:b:nn])
+ unlet b:nn
+endfunc
+
+" Test using s: with a typed command {{{1
+func Test_typed_script_var()
+ CheckRunVimInTerminal
+
+ let buf = RunVimInTerminal('', {'rows': 6})
+
+ " Deep nesting of if ... endif
+ call term_sendkeys(buf, ":echo get(s:, 'foo', 'x')\n")
+ call TermWait(buf)
+ call WaitForAssert({-> assert_match('^E116:', term_getline(buf, 5))})
+
+ call StopVimInTerminal(buf)
endfunc
func Test_for_over_string()
diff --git a/src/nvim/testdir/test_virtualedit.vim b/src/nvim/testdir/test_virtualedit.vim
index 522ca17675..2bf8c3fc77 100644
--- a/src/nvim/testdir/test_virtualedit.vim
+++ b/src/nvim/testdir/test_virtualedit.vim
@@ -80,6 +80,10 @@ func Test_edit_change()
call setline(1, "\t⒌")
normal Cx
call assert_equal('x', getline(1))
+ " Do a visual block change
+ call setline(1, ['a', 'b', 'c'])
+ exe "normal gg3l\<C-V>2jcx"
+ call assert_equal(['a x', 'b x', 'c x'], getline(1, '$'))
bwipe!
set virtualedit=
endfunc
@@ -289,6 +293,16 @@ func Test_replace_after_eol()
call append(0, '"r"')
normal gg$5lrxa
call assert_equal('"r" x', getline(1))
+ " visual block replace
+ %d _
+ call setline(1, ['a', '', 'b'])
+ exe "normal 2l\<C-V>2jrx"
+ call assert_equal(['a x', ' x', 'b x'], getline(1, '$'))
+ " visual characterwise selection replace after eol
+ %d _
+ call setline(1, 'a')
+ normal 4lv2lrx
+ call assert_equal('a xxx', getline(1))
bwipe!
set virtualedit=
endfunc
@@ -346,6 +360,48 @@ func Test_yank_paste_small_del_reg()
set virtualedit=
endfunc
+" Test for delete that breaks a tab into spaces
+func Test_delete_break_tab()
+ new
+ call setline(1, "one\ttwo")
+ set virtualedit=all
+ normal v3ld
+ call assert_equal(' two', getline(1))
+ set virtualedit&
+ close!
+endfunc
+
+" Test for using <BS>, <C-W> and <C-U> in virtual edit mode
+" to erase character, word and line.
+func Test_ve_backspace()
+ new
+ call setline(1, 'sample')
+ set virtualedit=all
+ set backspace=indent,eol,start
+ exe "normal 15|i\<BS>\<BS>"
+ call assert_equal([0, 1, 7, 5], getpos('.'))
+ exe "normal 15|i\<C-W>"
+ call assert_equal([0, 1, 6, 0], getpos('.'))
+ exe "normal 15|i\<C-U>"
+ call assert_equal([0, 1, 1, 0], getpos('.'))
+ set backspace&
+ set virtualedit&
+ close!
+endfunc
+
+" Test for delete (x) on EOL character and after EOL
+func Test_delete_past_eol()
+ new
+ call setline(1, "ab")
+ set virtualedit=all
+ exe "normal 2lx"
+ call assert_equal('ab', getline(1))
+ exe "normal 10lx"
+ call assert_equal('ab', getline(1))
+ set virtualedit&
+ bw!
+endfunc
+
" After calling s:TryVirtualeditReplace(), line 1 will contain one of these
" two strings, depending on whether virtual editing is on or off.
let s:result_ve_on = 'a x'
@@ -481,4 +537,53 @@ func Test_global_local_virtualedit()
set virtualedit&
endfunc
+func Test_virtualedit_mouse()
+ let save_mouse = &mouse
+ set mouse=a
+ set virtualedit=all
+ new
+
+ call setline(1, ["text\tword"])
+ redraw
+ call Ntest_setmouse(1, 4)
+ call feedkeys("\<LeftMouse>", "xt")
+ call assert_equal([0, 1, 4, 0, 4], getcurpos())
+ call Ntest_setmouse(1, 5)
+ call feedkeys("\<LeftMouse>", "xt")
+ call assert_equal([0, 1, 5, 0, 5], getcurpos())
+ call Ntest_setmouse(1, 6)
+ call feedkeys("\<LeftMouse>", "xt")
+ call assert_equal([0, 1, 5, 1, 6], getcurpos())
+ call Ntest_setmouse(1, 7)
+ call feedkeys("\<LeftMouse>", "xt")
+ call assert_equal([0, 1, 5, 2, 7], getcurpos())
+ call Ntest_setmouse(1, 8)
+ call feedkeys("\<LeftMouse>", "xt")
+ call assert_equal([0, 1, 5, 3, 8], getcurpos())
+ call Ntest_setmouse(1, 9)
+ call feedkeys("\<LeftMouse>", "xt")
+ call assert_equal([0, 1, 6, 0, 9], getcurpos())
+ call Ntest_setmouse(1, 15)
+ call feedkeys("\<LeftMouse>", "xt")
+ call assert_equal([0, 1, 10, 2, 15], getcurpos())
+
+ bwipe!
+ let &mouse = save_mouse
+ set virtualedit&
+endfunc
+
+" this was replacing the NUL at the end of the line
+func Test_virtualedit_replace_after_tab()
+ new
+ s/\v/ 0
+ set ve=all
+ let @" = ''
+ sil! norm vPvr0
+
+ call assert_equal("\t0", getline(1))
+ set ve&
+ bwipe!
+endfunc
+
+
" vim: shiftwidth=2 sts=2 expandtab
diff --git a/src/nvim/testdir/test_visual.vim b/src/nvim/testdir/test_visual.vim
index 9c1ad0c099..14d62089cf 100644
--- a/src/nvim/testdir/test_visual.vim
+++ b/src/nvim/testdir/test_visual.vim
@@ -225,6 +225,15 @@ func Test_virtual_replace()
exe "normal iabcdefghijklmnopqrst\<Esc>0gRAB\tIJKLMNO\tQR"
call assert_equal(['AB......CDEFGHI.Jkl',
\ 'AB IJKLMNO QRst'], getline(12, 13))
+
+ " Test inserting Tab with 'noexpandtab' and 'softabstop' set to 4
+ %d
+ call setline(1, 'aaaaaaaaaaaaa')
+ set softtabstop=4
+ exe "normal gggR\<Tab>\<Tab>x"
+ call assert_equal("\txaaaa", getline(1))
+ set softtabstop&
+
enew!
set noai bs&vim
if exists('save_t_kD')
@@ -474,6 +483,18 @@ func Test_visual_block_put()
bw!
endfunc
+func Test_visual_block_put_invalid()
+ enew!
+ behave mswin
+ norm yy
+ norm v)Ps/^/
+ " this was causing the column to become negative
+ silent norm ggv)P
+
+ bwipe!
+ behave xterm
+endfunc
+
" Visual modes (v V CTRL-V) followed by an operator; count; repeating
func Test_visual_mode_op()
new
@@ -1269,7 +1290,7 @@ func Test_visual_block_with_virtualedit()
endfunc
func Test_visual_block_ctrl_w_f()
- " Emtpy block selected in new buffer should not result in an error.
+ " Empty block selected in new buffer should not result in an error.
au! BufNew foo sil norm f
edit foo
@@ -1317,6 +1338,18 @@ func Test_visual_reselect_with_count()
call delete('XvisualReselect')
endfunc
+func Test_visual_reselect_exclusive()
+ new
+ call setline(1, ['abcde', 'abcde'])
+ set selection=exclusive
+ normal 1G0viwd
+ normal 2G01vd
+ call assert_equal(['', ''], getline(1, 2))
+
+ set selection&
+ bwipe!
+endfunc
+
func Test_visual_block_insert_round_off()
new
" The number of characters are tuned to fill a 4096 byte allocated block,
@@ -1492,5 +1525,4 @@ func Test_switch_buffer_ends_visual_mode()
exe 'bwipe!' buf2
endfunc
-
" vim: shiftwidth=2 sts=2 expandtab
diff --git a/src/nvim/testdir/test_winbuf_close.vim b/src/nvim/testdir/test_winbuf_close.vim
index f4878c2397..26b4ba8778 100644
--- a/src/nvim/testdir/test_winbuf_close.vim
+++ b/src/nvim/testdir/test_winbuf_close.vim
@@ -115,7 +115,7 @@ func Test_winbuf_close()
call assert_equal('Xtest2', bufname('%'))
quit!
call assert_equal('Xtest3', bufname('%'))
- call assert_fails('silent! quit!', 'E162')
+ call assert_fails('silent! quit!', 'E37')
call assert_equal('Xtest1', bufname('%'))
call delete('Xtest1')
@@ -192,7 +192,23 @@ func Test_tabwin_close()
call win_execute(l:wid, 'close')
" Should not crash.
call assert_true(v:true)
- %bwipe!
+
+ " This tests closing a window in another tab, while leaving the tab open
+ " i.e. two windows in another tab.
+ tabedit
+ let w:this_win = 42
+ new
+ let othertab_wid = win_getid()
+ tabprevious
+ call win_execute(othertab_wid, 'q')
+ " drawing the tabline helps check that the other tab's windows and buffers
+ " are still valid
+ redrawtabline
+ " but to be certain, ensure we can focus the other tab too
+ tabnext
+ call assert_equal(42, w:this_win)
+
+ bwipe!
endfunc
" Test when closing a split window (above/below) restores space to the window
diff --git a/src/nvim/testdir/test_window_cmd.vim b/src/nvim/testdir/test_window_cmd.vim
index 83a3216534..c25b1f1157 100644
--- a/src/nvim/testdir/test_window_cmd.vim
+++ b/src/nvim/testdir/test_window_cmd.vim
@@ -1,5 +1,8 @@
" Tests for window cmd (:wincmd, :split, :vsplit, :resize and etc...)
+source check.vim
+source screendump.vim
+
func Test_window_cmd_ls0_with_split()
set ls=0
set splitbelow
@@ -343,6 +346,46 @@ func Test_window_height()
bw Xa Xb Xc
endfunc
+func Test_wincmd_equal()
+ edit Xone
+ below split Xtwo
+ rightbelow vsplit Xthree
+ call assert_equal('Xone', bufname(winbufnr(1)))
+ call assert_equal('Xtwo', bufname(winbufnr(2)))
+ call assert_equal('Xthree', bufname(winbufnr(3)))
+
+ " Xone and Xtwo should be about the same height
+ let [wh1, wh2] = [winheight(1), winheight(2)]
+ call assert_inrange(wh1 - 1, wh1 + 1, wh2)
+ " Xtwo and Xthree should be about the same width
+ let [ww2, ww3] = [winwidth(2), winwidth(3)]
+ call assert_inrange(ww2 - 1, ww2 + 1, ww3)
+
+ 1wincmd w
+ 10wincmd _
+ 2wincmd w
+ 20wincmd |
+ call assert_equal(10, winheight(1))
+ call assert_equal(20, winwidth(2))
+
+ " equalizing horizontally doesn't change the heights
+ hor wincmd =
+ call assert_equal(10, winheight(1))
+ let [ww2, ww3] = [winwidth(2), winwidth(3)]
+ call assert_inrange(ww2 - 1, ww2 + 1, ww3)
+
+ 2wincmd w
+ 20wincmd |
+ call assert_equal(20, winwidth(2))
+ " equalizing vertically doesn't change the widths
+ vert wincmd =
+ call assert_equal(20, winwidth(2))
+ let [wh1, wh2] = [winheight(1), winheight(2)]
+ call assert_inrange(wh1 - 1, wh1 + 1, wh2)
+
+ bwipe Xone Xtwo Xthree
+endfunc
+
func Test_window_width()
e Xa
vsplit Xb
@@ -393,7 +436,15 @@ func Test_window_width()
call assert_inrange(ww1, ww1 + 1, ww2)
call assert_inrange(ww3, ww3 + 1, ww2)
- bw Xa Xb Xc
+ " when the current window width is less than the new 'winwidth', the current
+ " window width should be increased.
+ enew | only
+ split
+ 10vnew
+ set winwidth=15
+ call assert_equal(15, winwidth(0))
+
+ %bw!
endfunc
func Test_equalalways_on_close()
@@ -450,10 +501,13 @@ func Test_win_screenpos()
call assert_equal([1, 32], win_screenpos(2))
call assert_equal([12, 1], win_screenpos(3))
call assert_equal([0, 0], win_screenpos(4))
+ call assert_fails('let l = win_screenpos([])', 'E745:')
only
endfunc
func Test_window_jump_tag()
+ CheckFeature quickfix
+
help
/iccf
call assert_match('^|iccf|', getline('.'))
@@ -491,6 +545,7 @@ func Test_window_newtab()
call assert_equal(2, tabpagenr('$'))
call assert_equal(['Xb', 'Xa'], map(tabpagebuflist(1), 'bufname(v:val)'))
call assert_equal(['Xc' ], map(2->tabpagebuflist(), 'bufname(v:val)'))
+ call assert_equal(['Xc' ], map(tabpagebuflist(), 'bufname(v:val)'))
%bw!
endfunc
@@ -541,6 +596,11 @@ func Test_window_contents()
call assert_equal(59, line("w0"))
call assert_equal('59 ', s3)
+ %d
+ call setline(1, ['one', 'two', 'three'])
+ call assert_equal(1, line('w0'))
+ call assert_equal(3, line('w$'))
+
bwipeout!
call test_garbagecollect_now()
endfunc
@@ -677,6 +737,7 @@ func Test_relative_cursor_position_in_one_line_window()
only!
bwipe!
+ call assert_fails('call winrestview(v:_null_dict)', 'E474:')
endfunc
func Test_relative_cursor_position_after_move_and_resize()
@@ -853,6 +914,10 @@ func Test_winnr()
call assert_fails("echo winnr('ll')", 'E15:')
call assert_fails("echo winnr('5')", 'E15:')
call assert_equal(4, winnr('0h'))
+ call assert_fails("let w = winnr([])", 'E730:')
+ call assert_equal('unknown', win_gettype(-1))
+ call assert_equal(-1, winheight(-1))
+ call assert_equal(-1, winwidth(-1))
tabnew
call assert_equal(8, tabpagewinnr(1, 'j'))
@@ -873,9 +938,12 @@ func Test_winrestview()
call assert_equal(view, winsaveview())
bwipe!
+ call assert_fails('call winrestview(v:_null_dict)', 'E474:')
endfunc
func Test_win_splitmove()
+ CheckFeature quickfix
+
edit a
leftabove split b
leftabove vsplit c
@@ -901,6 +969,7 @@ func Test_win_splitmove()
call assert_equal(bufname(winbufnr(2)), 'b')
call assert_equal(bufname(winbufnr(3)), 'a')
call assert_equal(bufname(winbufnr(4)), 'd')
+ call assert_fails('call win_splitmove(winnr(), winnr("k"), v:_null_dict)', 'E474:')
only | bd
call assert_fails('call win_splitmove(winnr(), 123)', 'E957:')
@@ -1073,6 +1142,18 @@ func Test_split_cmds_with_no_room()
call Run_noroom_for_newwindow_test('v')
endfunc
+" Test for various wincmd failures
+func Test_wincmd_fails()
+ only!
+ call assert_beeps("normal \<C-W>w")
+ call assert_beeps("normal \<C-W>p")
+ call assert_beeps("normal \<C-W>gk")
+ call assert_beeps("normal \<C-W>r")
+ call assert_beeps("normal \<C-W>K")
+ call assert_beeps("normal \<C-W>H")
+ call assert_beeps("normal \<C-W>2gt")
+endfunc
+
func Test_window_resize()
" Vertical :resize (absolute, relative, min and max size).
vsplit
@@ -1158,7 +1239,7 @@ endfunc
" Test for jumping to a vertical/horizontal neighbor window based on the
" current cursor position
-func Test_window_goto_neightbor()
+func Test_window_goto_neighbor()
%bw!
" Vertical window movement
@@ -1337,17 +1418,20 @@ func Test_win_move_separator()
call assert_equal(w0, winwidth(0))
call assert_true(win_move_separator(0, -1))
call assert_equal(w0, winwidth(0))
+
" check that win_move_separator doesn't error with offsets beyond moving
" possibility
call assert_true(win_move_separator(id, 5000))
call assert_true(winwidth(id) > w)
call assert_true(win_move_separator(id, -5000))
call assert_true(winwidth(id) < w)
+
" check that win_move_separator returns false for an invalid window
wincmd =
let w = winwidth(0)
call assert_false(win_move_separator(-1, 1))
call assert_equal(w, winwidth(0))
+
" check that win_move_separator returns false for a floating window
let id = nvim_open_win(
\ 0, 0, #{relative: 'editor', row: 2, col: 2, width: 5, height: 3})
@@ -1355,6 +1439,13 @@ func Test_win_move_separator()
call assert_false(win_move_separator(id, 1))
call assert_equal(w, winwidth(id))
call nvim_win_close(id, 1)
+
+ " check that using another tabpage fails without crash
+ let id = win_getid()
+ tabnew
+ call assert_fails('call win_move_separator(id, -1)', 'E1308:')
+ tabclose
+
%bwipe!
endfunc
@@ -1403,17 +1494,20 @@ func Test_win_move_statusline()
call assert_true(id->win_move_statusline(-offset))
call assert_equal(h, winheight(id))
endfor
+
" check that win_move_statusline doesn't error with offsets beyond moving
" possibility
call assert_true(win_move_statusline(id, 5000))
call assert_true(winheight(id) > h)
call assert_true(win_move_statusline(id, -5000))
call assert_true(winheight(id) < h)
+
" check that win_move_statusline returns false for an invalid window
wincmd =
let h = winheight(0)
call assert_false(win_move_statusline(-1, 1))
call assert_equal(h, winheight(0))
+
" check that win_move_statusline returns false for a floating window
let id = nvim_open_win(
\ 0, 0, #{relative: 'editor', row: 2, col: 2, width: 5, height: 3})
@@ -1421,7 +1515,319 @@ func Test_win_move_statusline()
call assert_false(win_move_statusline(id, 1))
call assert_equal(h, winheight(id))
call nvim_win_close(id, 1)
+
+ " check that using another tabpage fails without crash
+ let id = win_getid()
+ tabnew
+ call assert_fails('call win_move_statusline(id, -1)', 'E1308:')
+ tabclose
+
%bwipe!
endfunc
+func Test_win_equal_last_status()
+ let save_lines = &lines
+ set lines=20
+ set splitbelow
+ set laststatus=0
+
+ split | split | quit
+ call assert_equal(winheight(1), winheight(2))
+
+ let &lines = save_lines
+ set splitbelow&
+ set laststatus&
+endfunc
+
+" Test "screen" and "cursor" values for 'splitkeep' with a sequence of
+" split operations for various options: with and without a winbar,
+" tabline, for each possible value of 'laststatus', 'scrolloff',
+" 'equalalways', and with the cursor at the top, middle and bottom.
+func Test_splitkeep_options()
+ " disallow window resizing
+ " let save_WS = &t_WS
+ " set t_WS=
+
+ let gui = has("gui_running")
+ inoremap <expr> c "<cmd>copen<bar>wincmd k<CR>"
+ for run in range(0, 20)
+ let &splitkeep = run > 10 ? 'topline' : 'screen'
+ let &scrolloff = (!(run % 4) ? 0 : run)
+ let &laststatus = (run % 3)
+ let &splitbelow = (run % 3)
+ let &equalalways = (run % 2)
+ " Nvim: both windows have a winbar after splitting
+ " let wsb = (run % 2) && &splitbelow
+ let wsb = 0
+ let tl = (gui ? 0 : ((run % 5) ? 1 : 0))
+ let pos = !(run % 3) ? 'H' : ((run % 2) ? 'M' : 'L')
+ tabnew | tabonly! | redraw
+ execute (run % 5) ? 'tabnew' : ''
+ " execute (run % 2) ? 'nnoremenu 1.10 WinBar.Test :echo' : ''
+ let &winbar = (run % 2) ? '%f' : ''
+ call setline(1, range(1, 256))
+ " No scroll for restore_snapshot
+ norm G
+ try
+ copen | close | colder
+ catch /E380/
+ endtry
+ call assert_equal(257 - winheight(0), line("w0"))
+
+ " No scroll for firstwin horizontal split
+ execute 'norm gg' . pos
+ split | redraw | wincmd k
+ call assert_equal(1, line("w0"))
+ call assert_equal(&scroll, winheight(0) / 2)
+ wincmd j
+ call assert_equal(&spk == 'topline' ? 1 : win_screenpos(0)[0] - tl - wsb, line("w0"))
+
+ " No scroll when resizing windows
+ wincmd k | resize +2 | redraw
+ call assert_equal(1, line("w0"))
+ wincmd j
+ call assert_equal(&spk == 'topline' ? 1 : win_screenpos(0)[0] - tl - wsb, line("w0"))
+
+ " No scroll when dragging statusline
+ call win_move_statusline(1, -3)
+ call assert_equal(&spk == 'topline' ? 1 : win_screenpos(0)[0] - tl - wsb, line("w0"))
+ wincmd k
+ call assert_equal(1, line("w0"))
+
+ " No scroll when changing shellsize
+ set lines+=2
+ call assert_equal(1, line("w0"))
+ wincmd j
+ call assert_equal(&spk == 'topline' ? 1 : win_screenpos(0)[0] - tl - wsb, line("w0"))
+ set lines-=2
+ call assert_equal(&spk == 'topline' ? 1 : win_screenpos(0)[0] - tl - wsb, line("w0"))
+ wincmd k
+ call assert_equal(1, line("w0"))
+
+ " No scroll when equalizing windows
+ wincmd =
+ call assert_equal(1, line("w0"))
+ wincmd j
+ call assert_equal(&spk == 'topline' ? 1 : win_screenpos(0)[0] - tl - wsb, line("w0"))
+ wincmd k
+ call assert_equal(1, line("w0"))
+
+ " No scroll in windows split multiple times
+ vsplit | split | 4wincmd w
+ call assert_equal(&spk == 'topline' ? 1 : win_screenpos(0)[0] - tl - wsb, line("w0"))
+ 1wincmd w | quit | wincmd l | split
+ call assert_equal(&spk == 'topline' ? 1 : win_screenpos(0)[0] - tl - wsb, line("w0"))
+ wincmd j
+ call assert_equal(&spk == 'topline' ? 1 : win_screenpos(0)[0] - tl - wsb, line("w0"))
+
+ " No scroll in small window
+ 2wincmd w | only | 5split | wincmd k
+ call assert_equal(1, line("w0"))
+ wincmd j
+ call assert_equal(&spk == 'topline' ? 1 : win_screenpos(0)[0] - tl - wsb, line("w0"))
+
+ " No scroll for vertical split
+ quit | vsplit | wincmd l
+ call assert_equal(1, line("w0"))
+ wincmd h
+ call assert_equal(1, line("w0"))
+
+ " No scroll in windows split and quit multiple times
+ quit | redraw | split | split | quit | redraw
+ call assert_equal(&spk == 'topline' ? 1 : win_screenpos(0)[0] - tl - wsb, line("w0"))
+
+ " No scroll for new buffer
+ 1wincmd w | only | copen | wincmd k
+ call assert_equal(1, line("w0"))
+ only
+ call assert_equal(1, line("w0"))
+ above copen | wincmd j
+ call assert_equal(&spk == 'topline' ? 1 : win_screenpos(0)[0] - tl, line("w0"))
+
+ " No scroll when opening cmdwin, and no cursor move when closing cmdwin.
+ only | norm ggL
+ let curpos = getcurpos()
+ norm q:
+ call assert_equal(1, line("w0"))
+ call assert_equal(curpos, getcurpos())
+
+ " Scroll when cursor becomes invalid in insert mode
+ norm Lic
+ call assert_equal(curpos, getcurpos())
+
+ " No scroll when topline not equal to 1
+ only | execute "norm gg5\<C-e>" | split | wincmd k
+ call assert_equal(6, line("w0"))
+ wincmd j
+ call assert_equal(&spk == 'topline' ? 6 : 5 + win_screenpos(0)[0] - tl - wsb, line("w0"))
+ endfor
+
+ tabnew | tabonly! | %bwipeout!
+ iunmap c
+ set scrolloff&
+ set splitbelow&
+ set laststatus&
+ set equalalways&
+ set splitkeep&
+ " let &t_WS = save_WS
+endfunc
+
+function Test_splitkeep_cmdwin_cursor_position()
+ set splitkeep=screen
+ call setline(1, range(&lines))
+
+ " No scroll when cursor is at near bottom of window and cusor position
+ " recompution (done by line('w0') in this test) happens while in cmdwin.
+ normal! G
+ let firstline = line('w0')
+ autocmd CmdwinEnter * ++once autocmd WinEnter * ++once call line('w0')
+ execute "normal! q:\<C-w>q"
+ redraw!
+ call assert_equal(firstline, line('w0'))
+
+ " User script can change cursor position successfully while in cmdwin and it
+ " shouldn't be changed when closing cmdwin.
+ execute "normal! Gq:\<Cmd>call win_execute(winnr('#')->win_getid(), 'call cursor(1, 1)')\<CR>\<C-w>q"
+ call assert_equal(1, line('.'))
+ call assert_equal(1, col('.'))
+
+ execute "normal! Gq:\<Cmd>autocmd WinEnter * ++once call cursor(1, 1)\<CR>\<C-w>q"
+ call assert_equal(1, line('.'))
+ call assert_equal(1, col('.'))
+
+ %bwipeout!
+ set splitkeep&
+endfunction
+
+function Test_splitkeep_misc()
+ set splitkeep=screen
+ set splitbelow
+
+ call setline(1, range(1, &lines))
+ norm Gzz
+ let top = line('w0')
+ " No scroll when aucmd_win is opened
+ call setbufvar(bufnr("test", 1) , '&buftype', 'nofile')
+ call assert_equal(top, line('w0'))
+ " No scroll when tab is changed/closed
+ tab help | close
+ call assert_equal(top, line('w0'))
+ " No scroll when help is closed and buffer line count < window height
+ norm ggdG
+ call setline(1, range(1, &lines - 10))
+ norm G
+ let top = line('w0')
+ help | quit
+ call assert_equal(top, line('w0'))
+ " No error when resizing window in autocmd and buffer length changed
+ autocmd FileType qf exe "resize" line('$')
+ cexpr getline(1, '$')
+ copen
+ wincmd p
+ norm dd
+ cexpr getline(1, '$')
+
+ %bwipeout!
+ set splitbelow&
+ set splitkeep&
+endfunc
+
+function Test_splitkeep_callback()
+ CheckScreendump
+ let lines =<< trim END
+ set splitkeep=screen
+ call setline(1, range(&lines))
+ function C1(a, b)
+ split | wincmd p
+ endfunction
+ function C2(a, b)
+ close | split
+ endfunction
+ nn j <cmd>call job_start([&sh, &shcf, "true"], { 'exit_cb': 'C1' })<CR>
+ nn t <cmd>call popup_create(term_start([&sh, &shcf, "true"],
+ \ { 'hidden': 1, 'exit_cb': 'C2' }), {})<CR>
+ END
+ call writefile(lines, 'XTestSplitkeepCallback', 'D')
+ let buf = RunVimInTerminal('-S XTestSplitkeepCallback', #{rows: 8})
+
+ call term_sendkeys(buf, "j")
+ call VerifyScreenDump(buf, 'Test_splitkeep_callback_1', {})
+
+ call term_sendkeys(buf, ":quit\<CR>Ht")
+ call VerifyScreenDump(buf, 'Test_splitkeep_callback_2', {})
+
+ call term_sendkeys(buf, ":set sb\<CR>:quit\<CR>Gj")
+ call VerifyScreenDump(buf, 'Test_splitkeep_callback_3', {})
+
+ call term_sendkeys(buf, ":quit\<CR>Gt")
+ call VerifyScreenDump(buf, 'Test_splitkeep_callback_4', {})
+
+ call StopVimInTerminal(buf)
+endfunc
+
+function Test_splitkeep_fold()
+ CheckScreendump
+
+ let lines =<< trim END
+ set splitkeep=screen
+ set foldmethod=marker
+ set number
+ let line = 1
+ for n in range(1, &lines)
+ call setline(line, ['int FuncName() {/*{{{*/', 1, 2, 3, 4, 5, '}/*}}}*/',
+ \ 'after fold'])
+ let line += 8
+ endfor
+ END
+ call writefile(lines, 'XTestSplitkeepFold', 'D')
+ let buf = RunVimInTerminal('-S XTestSplitkeepFold', #{rows: 10})
+
+ call term_sendkeys(buf, "L:wincmd s\<CR>")
+ call VerifyScreenDump(buf, 'Test_splitkeep_fold_1', {})
+
+ call term_sendkeys(buf, ":quit\<CR>")
+ call VerifyScreenDump(buf, 'Test_splitkeep_fold_2', {})
+
+ call term_sendkeys(buf, "H:below split\<CR>")
+ call VerifyScreenDump(buf, 'Test_splitkeep_fold_3', {})
+
+ call term_sendkeys(buf, ":wincmd k\<CR>:quit\<CR>")
+ call VerifyScreenDump(buf, 'Test_splitkeep_fold_4', {})
+
+ call StopVimInTerminal(buf)
+endfunction
+
+function Test_splitkeep_status()
+ CheckScreendump
+
+ let lines =<< trim END
+ call setline(1, ['a', 'b', 'c'])
+ set nomodified
+ set splitkeep=screen
+ let win = winnr()
+ wincmd s
+ wincmd j
+ END
+ call writefile(lines, 'XTestSplitkeepStatus', 'D')
+ let buf = RunVimInTerminal('-S XTestSplitkeepStatus', #{rows: 10})
+
+ call term_sendkeys(buf, ":call win_move_statusline(win, 1)\<CR>")
+ call VerifyScreenDump(buf, 'Test_splitkeep_status_1', {})
+
+ call StopVimInTerminal(buf)
+endfunction
+
+function Test_new_help_window_on_error()
+ help change.txt
+ execute "normal! /CTRL-@\<CR>"
+ silent! execute "normal! \<C-W>]"
+
+ let wincount = winnr('$')
+ help 'mod'
+
+ call assert_equal(wincount, winnr('$'))
+ call assert_equal(expand("<cword>"), "'mod'")
+endfunction
+
+
" vim: shiftwidth=2 sts=2 expandtab
diff --git a/src/nvim/testdir/test_window_id.vim b/src/nvim/testdir/test_window_id.vim
index 8bf4ede350..396a49b55f 100644
--- a/src/nvim/testdir/test_window_id.vim
+++ b/src/nvim/testdir/test_window_id.vim
@@ -1,5 +1,7 @@
" Test using the window ID.
+source check.vim
+
func Test_win_getid()
edit one
let id1 = win_getid()
@@ -90,10 +92,16 @@ func Test_win_getid()
split
call assert_equal(sort([id5, win_getid()]), sort(win_findbuf(bufnr5)))
+ call assert_fails('let w = win_getid([])', 'E745:')
+ call assert_equal(0, win_getid(-1))
+ call assert_equal(-1, win_getid(1, -1))
+
only!
endfunc
func Test_win_getid_curtab()
+ CheckFeature quickfix
+
tabedit X
tabfirst
copen
@@ -127,4 +135,8 @@ func Test_winlayout()
let w2 = win_getid()
call assert_equal(['leaf', w2], 2->winlayout())
tabclose
+
+ call assert_equal([], winlayout(-1))
endfunc
+
+" vim: shiftwidth=2 sts=2 expandtab
diff --git a/src/nvim/testdir/test_writefile.vim b/src/nvim/testdir/test_writefile.vim
index a8735bcaf1..6019cee193 100644
--- a/src/nvim/testdir/test_writefile.vim
+++ b/src/nvim/testdir/test_writefile.vim
@@ -57,7 +57,29 @@ func Test_writefile_fails_conversion()
call assert_fails('write ++enc=cp932', 'E513:')
call assert_equal(contents, readfile('Xfile'))
+ " With 'backupcopy' set, if there is a conversion error, the backup file is
+ " still created.
+ set backupcopy=yes writebackup& backup&
+ call delete('Xfile' .. &backupext)
+ call assert_fails('write ++enc=cp932', 'E513:')
+ call assert_equal(contents, readfile('Xfile'))
+ call assert_equal(contents, readfile('Xfile' .. &backupext))
+ set backupcopy&
+ %bw!
+
+ " Conversion error during write
+ new
+ call setline(1, ["\U10000000"])
+ let output = execute('write! ++enc=utf-16 Xfile')
+ call assert_match('CONVERSION ERROR', output)
+ let output = execute('write! ++enc=ucs-2 Xfile')
+ call assert_match('CONVERSION ERROR', output)
+ call delete('Xfilz~')
+ call delete('Xfily~')
+ %bw!
+
call delete('Xfile')
+ call delete('Xfile' .. &backupext)
bwipe!
set backup& writebackup& backupdir&vim backupskip&vim
endfunc
@@ -136,9 +158,7 @@ func Test_writefile_sync_arg()
endfunc
func Test_writefile_sync_dev_stdout()
- if !has('unix')
- return
- endif
+ CheckUnix
if filewritable('/dev/stdout')
" Just check that this doesn't cause an error.
call writefile(['one'], '/dev/stdout', 's')
@@ -216,6 +236,12 @@ func Test_saveas()
syntax off
%bw!
call delete('Xsaveas.pl')
+
+ " :saveas fails for "nofile" buffer
+ set buftype=nofile
+ call assert_fails('saveas Xsafile', 'E676: No matching autocommands for buftype=nofile buffer')
+
+ bwipe!
endfunc
func Test_write_errors()
@@ -254,6 +280,225 @@ func Test_write_errors()
close
call delete('Xfile')
+
+ " Nvim treats NULL list/blob more like empty list/blob
+ " call writefile(v:_null_list, 'Xfile')
+ " call assert_false(filereadable('Xfile'))
+ " call writefile(v:_null_blob, 'Xfile')
+ " call assert_false(filereadable('Xfile'))
+ call assert_fails('call writefile([], "")', 'E482:')
+
+ " very long file name
+ let long_fname = repeat('n', 5000)
+ call assert_fails('exe "w " .. long_fname', 'E75:')
+ call assert_fails('call writefile([], long_fname)', 'E482:')
+
+ " Test for writing to a block device on Unix-like systems
+ if has('unix') && getfperm('/dev/loop0') != ''
+ \ && getftype('/dev/loop0') == 'bdev' && !IsRoot()
+ new
+ edit /dev/loop0
+ call assert_fails('write', 'E503: ')
+ call assert_fails('write!', 'E503: ')
+ close!
+ endif
+endfunc
+
+" Test for writing to a file which is modified after Vim read it
+func Test_write_file_mtime()
+ CheckEnglish
+ CheckRunVimInTerminal
+
+ " First read the file into a buffer
+ call writefile(["Line1", "Line2"], 'Xfile')
+ let old_ftime = getftime('Xfile')
+ let buf = RunVimInTerminal('Xfile', #{rows : 10})
+ call term_wait(buf)
+ call term_sendkeys(buf, ":set noswapfile\<CR>")
+ call term_wait(buf)
+
+ " Modify the file directly. Make sure the file modification time is
+ " different. Note that on Linux/Unix, the file is considered modified
+ " outside, only if the difference is 2 seconds or more
+ sleep 1
+ call writefile(["Line3", "Line4"], 'Xfile')
+ let new_ftime = getftime('Xfile')
+ while new_ftime - old_ftime < 2
+ sleep 100m
+ call writefile(["Line3", "Line4"], 'Xfile')
+ let new_ftime = getftime('Xfile')
+ endwhile
+
+ " Try to overwrite the file and check for the prompt
+ call term_sendkeys(buf, ":w\<CR>")
+ call term_wait(buf)
+ call WaitForAssert({-> assert_equal("WARNING: The file has been changed since reading it!!!", term_getline(buf, 9))})
+ call assert_equal("Do you really want to write to it (y/n)?",
+ \ term_getline(buf, 10))
+ call term_sendkeys(buf, "n\<CR>")
+ call term_wait(buf)
+ call assert_equal(new_ftime, getftime('Xfile'))
+ call term_sendkeys(buf, ":w\<CR>")
+ call term_wait(buf)
+ call term_sendkeys(buf, "y\<CR>")
+ call term_wait(buf)
+ call WaitForAssert({-> assert_equal('Line2', readfile('Xfile')[1])})
+
+ " clean up
+ call StopVimInTerminal(buf)
+ call delete('Xfile')
+endfunc
+
+" Test for an autocmd unloading a buffer during a write command
+func Test_write_autocmd_unloadbuf_lockmark()
+ augroup WriteTest
+ autocmd BufWritePre Xfile enew | write
+ augroup END
+ e Xfile
+ call assert_fails('lockmarks write', ['E32', 'E203:'])
+ augroup WriteTest
+ au!
+ augroup END
+ augroup! WriteTest
+endfunc
+
+" Test for writing a buffer with 'acwrite' but without autocmds
+func Test_write_acwrite_error()
+ new Xfile
+ call setline(1, ['line1', 'line2', 'line3'])
+ set buftype=acwrite
+ call assert_fails('write', 'E676:')
+ call assert_fails('1,2write!', 'E676:')
+ call assert_fails('w >>', 'E676:')
+ close!
+endfunc
+
+" Test for adding and removing lines from an autocmd when writing a buffer
+func Test_write_autocmd_add_remove_lines()
+ new Xfile
+ call setline(1, ['aaa', 'bbb', 'ccc', 'ddd'])
+
+ " Autocmd deleting lines from the file when writing a partial file
+ augroup WriteTest2
+ au!
+ autocmd FileWritePre Xfile 1,2d
+ augroup END
+ call assert_fails('2,3w!', 'E204:')
+
+ " Autocmd adding lines to a file when writing a partial file
+ augroup WriteTest2
+ au!
+ autocmd FileWritePre Xfile call append(0, ['xxx', 'yyy'])
+ augroup END
+ %d
+ call setline(1, ['aaa', 'bbb', 'ccc', 'ddd'])
+ 1,2w!
+ call assert_equal(['xxx', 'yyy', 'aaa', 'bbb'], readfile('Xfile'))
+
+ " Autocmd deleting lines from the file when writing the whole file
+ augroup WriteTest2
+ au!
+ autocmd BufWritePre Xfile 1,2d
+ augroup END
+ %d
+ call setline(1, ['aaa', 'bbb', 'ccc', 'ddd'])
+ w
+ call assert_equal(['ccc', 'ddd'], readfile('Xfile'))
+
+ augroup WriteTest2
+ au!
+ augroup END
+ augroup! WriteTest2
+
+ close!
+ call delete('Xfile')
+endfunc
+
+" Test for writing to a readonly file
+func Test_write_readonly()
+ call writefile([], 'Xfile')
+ call setfperm('Xfile', "r--------")
+ edit Xfile
+ set noreadonly backupskip=
+ call assert_fails('write', 'E505:')
+ let save_cpo = &cpo
+ set cpo+=W
+ call assert_fails('write!', 'E504:')
+ let &cpo = save_cpo
+ call setline(1, ['line1'])
+ write!
+ call assert_equal(['line1'], readfile('Xfile'))
+
+ " Auto-saving a readonly file should fail with 'autowriteall'
+ %bw!
+ e Xfile
+ set noreadonly autowriteall
+ call setline(1, ['aaaa'])
+ call assert_fails('n', 'E505:')
+ set cpo+=W
+ call assert_fails('n', 'E504:')
+ set cpo-=W
+ set autowriteall&
+
+ set backupskip&
+ call delete('Xfile')
+ %bw!
+endfunc
+
+" Test for 'patchmode'
+func Test_patchmode()
+ call writefile(['one'], 'Xfile')
+ set patchmode=.orig nobackup backupskip= writebackup
+ new Xfile
+ call setline(1, 'two')
+ " first write should create the .orig file
+ write
+ call assert_equal(['one'], readfile('Xfile.orig'))
+ call setline(1, 'three')
+ " subsequent writes should not create/modify the .orig file
+ write
+ call assert_equal(['one'], readfile('Xfile.orig'))
+
+ " use 'patchmode' with 'nobackup' and 'nowritebackup' to create an empty
+ " original file
+ call delete('Xfile')
+ call delete('Xfile.orig')
+ %bw!
+ set patchmode=.orig nobackup nowritebackup
+ edit Xfile
+ call setline(1, ['xxx'])
+ write
+ call assert_equal(['xxx'], readfile('Xfile'))
+ call assert_equal([], readfile('Xfile.orig'))
+
+ set patchmode& backup& backupskip& writebackup&
+ call delete('Xfile')
+ call delete('Xfile.orig')
+endfunc
+
+" Test for writing to a file in a readonly directory
+" NOTE: if you run tests as root this will fail. Don't run tests as root!
+func Test_write_readonly_dir()
+ " On MS-Windows, modifying files in a read-only directory is allowed.
+ CheckUnix
+ " Root can do it too.
+ CheckNotRoot
+
+ call mkdir('Xdir/')
+ call writefile(['one'], 'Xdir/Xfile1')
+ call setfperm('Xdir', 'r-xr--r--')
+ " try to create a new file in the directory
+ new Xdir/Xfile2
+ call setline(1, 'two')
+ call assert_fails('write', 'E212:')
+ " try to create a backup file in the directory
+ edit! Xdir/Xfile1
+ set backupdir=./Xdir backupskip=
+ set patchmode=.orig
+ call assert_fails('write', 'E509:')
+ call setfperm('Xdir', 'rwxr--r--')
+ call delete('Xdir', 'rf')
+ set backupdir& backupskip& patchmode&
endfunc
" Test for writing a file using invalid file encoding
@@ -266,15 +511,15 @@ endfunc
" Tests for reading and writing files with conversion for Win32.
func Test_write_file_encoding()
- throw 'skipped: Nvim does not support :w ++enc=cp1251'
+ throw 'Skipped: Nvim does not support encoding=latin1'
CheckMSWindows
let save_encoding = &encoding
let save_fileencodings = &fileencodings
- set encoding& fileencodings&
+ set encoding=latin1 fileencodings&
let text =<< trim END
- 1 utf-8 text: Для Vim version 6.2. Последнее изменение: 1970 Jan 01
- 2 cp1251 text: Äëÿ Vim version 6.2. Ïîñëåäíåå èçìåíåíèå: 1970 Jan 01
- 3 cp866 text: „«ï Vim version 6.2. ®á«¥¤­¥¥ ¨§¬¥­¥­¨¥: 1970 Jan 01
+ 1 utf-8 text: Для Vim version 6.2. Последнее изменение: 1970 Jan 01
+ 2 cp1251 text: Vim version 6.2. : 1970 Jan 01
+ 3 cp866 text: Vim version 6.2. ᫥ : 1970 Jan 01
END
call writefile(text, 'Xfile')
edit Xfile
@@ -289,9 +534,9 @@ func Test_write_file_encoding()
.w ++enc=cp866 >> Xtest
.w! ++enc=utf-8 Xutf8
let expected =<< trim END
- 1 utf-8 text: Для Vim version 6.2. Последнее изменение: 1970 Jan 01
- 1 utf-8 text: Äëÿ Vim version 6.2. Ïîñëåäíåå èçìåíåíèå: 1970 Jan 01
- 1 utf-8 text: „«ï Vim version 6.2. ®á«¥¤­¥¥ ¨§¬¥­¥­¨¥: 1970 Jan 01
+ 1 utf-8 text: Для Vim version 6.2. Последнее изменение: 1970 Jan 01
+ 1 utf-8 text: Vim version 6.2. : 1970 Jan 01
+ 1 utf-8 text: Vim version 6.2. ᫥ : 1970 Jan 01
END
call assert_equal(expected, readfile('Xtest'))
@@ -302,9 +547,9 @@ func Test_write_file_encoding()
.w ++enc=cp866 >> Xtest
.w! ++enc=cp1251 Xcp1251
let expected =<< trim END
- 2 cp1251 text: Для Vim version 6.2. Последнее изменение: 1970 Jan 01
- 2 cp1251 text: Äëÿ Vim version 6.2. Ïîñëåäíåå èçìåíåíèå: 1970 Jan 01
- 2 cp1251 text: „«ï Vim version 6.2. ®á«¥¤­¥¥ ¨§¬¥­¥­¨¥: 1970 Jan 01
+ 2 cp1251 text: Для Vim version 6.2. Последнее изменение: 1970 Jan 01
+ 2 cp1251 text: Vim version 6.2. : 1970 Jan 01
+ 2 cp1251 text: Vim version 6.2. ᫥ : 1970 Jan 01
END
call assert_equal(expected, readfile('Xtest'))
@@ -315,9 +560,9 @@ func Test_write_file_encoding()
.w ++enc=cp866 >> Xtest
.w! ++enc=cp866 Xcp866
let expected =<< trim END
- 3 cp866 text: Для Vim version 6.2. Последнее изменение: 1970 Jan 01
- 3 cp866 text: Äëÿ Vim version 6.2. Ïîñëåäíåå èçìåíåíèå: 1970 Jan 01
- 3 cp866 text: „«ï Vim version 6.2. ®á«¥¤­¥¥ ¨§¬¥­¥­¨¥: 1970 Jan 01
+ 3 cp866 text: Для Vim version 6.2. Последнее изменение: 1970 Jan 01
+ 3 cp866 text: Vim version 6.2. : 1970 Jan 01
+ 3 cp866 text: Vim version 6.2. ᫥ : 1970 Jan 01
END
call assert_equal(expected, readfile('Xtest'))
@@ -331,9 +576,9 @@ func Test_write_file_encoding()
e Xcp866
.w ++enc=utf-8 >> Xtest
let expected =<< trim END
- 1 utf-8 text: Для Vim version 6.2. Последнее изменение: 1970 Jan 01
- 2 cp1251 text: Для Vim version 6.2. Последнее изменение: 1970 Jan 01
- 3 cp866 text: Для Vim version 6.2. Последнее изменение: 1970 Jan 01
+ 1 utf-8 text: Для Vim version 6.2. Последнее изменение: 1970 Jan 01
+ 2 cp1251 text: Для Vim version 6.2. Последнее изменение: 1970 Jan 01
+ 3 cp866 text: Для Vim version 6.2. Последнее изменение: 1970 Jan 01
END
call assert_equal(expected, readfile('Xtest'))
@@ -347,9 +592,9 @@ func Test_write_file_encoding()
e Xcp866
.w ++enc=cp1251 >> Xtest
let expected =<< trim END
- 1 utf-8 text: Äëÿ Vim version 6.2. Ïîñëåäíåå èçìåíåíèå: 1970 Jan 01
- 2 cp1251 text: Äëÿ Vim version 6.2. Ïîñëåäíåå èçìåíåíèå: 1970 Jan 01
- 3 cp866 text: Äëÿ Vim version 6.2. Ïîñëåäíåå èçìåíåíèå: 1970 Jan 01
+ 1 utf-8 text: Vim version 6.2. : 1970 Jan 01
+ 2 cp1251 text: Vim version 6.2. : 1970 Jan 01
+ 3 cp866 text: Vim version 6.2. : 1970 Jan 01
END
call assert_equal(expected, readfile('Xtest'))
@@ -363,9 +608,9 @@ func Test_write_file_encoding()
e Xcp866
.w ++enc=cp866 >> Xtest
let expected =<< trim END
- 1 utf-8 text: „«ï Vim version 6.2. ®á«¥¤­¥¥ ¨§¬¥­¥­¨¥: 1970 Jan 01
- 2 cp1251 text: „«ï Vim version 6.2. ®á«¥¤­¥¥ ¨§¬¥­¥­¨¥: 1970 Jan 01
- 3 cp866 text: „«ï Vim version 6.2. ®á«¥¤­¥¥ ¨§¬¥­¥­¨¥: 1970 Jan 01
+ 1 utf-8 text: Vim version 6.2. ᫥ : 1970 Jan 01
+ 2 cp1251 text: Vim version 6.2. ᫥ : 1970 Jan 01
+ 3 cp866 text: Vim version 6.2. ᫥ : 1970 Jan 01
END
call assert_equal(expected, readfile('Xtest'))
@@ -523,10 +768,177 @@ func Test_read_write_bin()
call assert_equal(0z6E6F656F6C0A, readfile('XNoEolSetEol', 'B'))
call delete('XNoEolSetEol')
- set ff&
+ set ff& fixeol&
bwipe! XNoEolSetEol
endfunc
+" Test for the 'backupcopy' option when writing files
+func Test_backupcopy()
+ CheckUnix
+ set backupskip=
+ " With the default 'backupcopy' setting, saving a symbolic link file
+ " should not break the link.
+ set backupcopy&
+ call writefile(['1111'], 'Xfile1')
+ silent !ln -s Xfile1 Xfile2
+ new Xfile2
+ call setline(1, ['2222'])
+ write
+ close
+ call assert_equal(['2222'], readfile('Xfile1'))
+ call assert_equal('Xfile1', resolve('Xfile2'))
+ call assert_equal('link', getftype('Xfile2'))
+ call delete('Xfile1')
+ call delete('Xfile2')
+
+ " With the 'backupcopy' set to 'breaksymlink', saving a symbolic link file
+ " should break the link.
+ set backupcopy=yes,breaksymlink
+ call writefile(['1111'], 'Xfile1')
+ silent !ln -s Xfile1 Xfile2
+ new Xfile2
+ call setline(1, ['2222'])
+ write
+ close
+ call assert_equal(['1111'], readfile('Xfile1'))
+ call assert_equal(['2222'], readfile('Xfile2'))
+ call assert_equal('Xfile2', resolve('Xfile2'))
+ call assert_equal('file', getftype('Xfile2'))
+ call delete('Xfile1')
+ call delete('Xfile2')
+ set backupcopy&
+
+ " With the default 'backupcopy' setting, saving a hard link file
+ " should not break the link.
+ set backupcopy&
+ call writefile(['1111'], 'Xfile1')
+ silent !ln Xfile1 Xfile2
+ new Xfile2
+ call setline(1, ['2222'])
+ write
+ close
+ call assert_equal(['2222'], readfile('Xfile1'))
+ call delete('Xfile1')
+ call delete('Xfile2')
+
+ " With the 'backupcopy' set to 'breaksymlink', saving a hard link file
+ " should break the link.
+ set backupcopy=yes,breakhardlink
+ call writefile(['1111'], 'Xfile1')
+ silent !ln Xfile1 Xfile2
+ new Xfile2
+ call setline(1, ['2222'])
+ write
+ call assert_equal(['1111'], readfile('Xfile1'))
+ call assert_equal(['2222'], readfile('Xfile2'))
+ call delete('Xfile1')
+ call delete('Xfile2')
+
+ " If a backup file is already present, then a slightly modified filename
+ " should be used as the backup file. Try with 'backupcopy' set to 'yes' and
+ " 'no'.
+ %bw
+ call writefile(['aaaa'], 'Xfile')
+ call writefile(['bbbb'], 'Xfile.bak')
+ set backupcopy=yes backupext=.bak
+ new Xfile
+ call setline(1, ['cccc'])
+ write
+ close
+ call assert_equal(['cccc'], readfile('Xfile'))
+ call assert_equal(['bbbb'], readfile('Xfile.bak'))
+ set backupcopy=no backupext=.bak
+ new Xfile
+ call setline(1, ['dddd'])
+ write
+ close
+ call assert_equal(['dddd'], readfile('Xfile'))
+ call assert_equal(['bbbb'], readfile('Xfile.bak'))
+ call delete('Xfile')
+ call delete('Xfile.bak')
+
+ " Write to a device file (in Unix-like systems) which cannot be backed up.
+ if has('unix')
+ set writebackup backupcopy=yes nobackup
+ new
+ call setline(1, ['aaaa'])
+ let output = execute('write! /dev/null')
+ call assert_match('"/dev/null" \[Device]', output)
+ close
+ set writebackup backupcopy=no nobackup
+ new
+ call setline(1, ['aaaa'])
+ let output = execute('write! /dev/null')
+ call assert_match('"/dev/null" \[Device]', output)
+ close
+ set backup writebackup& backupcopy&
+ new
+ call setline(1, ['aaaa'])
+ let output = execute('write! /dev/null')
+ call assert_match('"/dev/null" \[Device]', output)
+ close
+ endif
+
+ set backupcopy& backupskip& backupext& backup&
+endfunc
+
+" Test for writing a file with 'encoding' set to 'utf-16'
+func Test_write_utf16()
+ new
+ call setline(1, ["\U00010001"])
+ write ++enc=utf-16 Xfile
+ bw!
+ call assert_equal(0zD800DC01, readfile('Xfile', 'B')[0:3])
+ call delete('Xfile')
+endfunc
+
+" Test for trying to save a backup file when the backup file is a symbolic
+" link to the original file. The backup file should not be modified.
+func Test_write_backup_symlink()
+ CheckUnix
+ call mkdir('Xbackup')
+ let save_backupdir = &backupdir
+ set backupdir=.,./Xbackup
+ call writefile(['1111'], 'Xfile')
+ silent !ln -s Xfile Xfile.bak
+
+ new Xfile
+ set backup backupcopy=yes backupext=.bak
+ write
+ call assert_equal('link', getftype('Xfile.bak'))
+ call assert_equal('Xfile', resolve('Xfile.bak'))
+ " backup file should be created in the 'backup' directory
+ if !has('bsd')
+ " This check fails on FreeBSD
+ call assert_true(filereadable('./Xbackup/Xfile.bak'))
+ endif
+ set backup& backupcopy& backupext&
+ %bw
+
+ call delete('Xfile')
+ call delete('Xfile.bak')
+ call delete('Xbackup', 'rf')
+ let &backupdir = save_backupdir
+endfunc
+
+" Test for ':write ++bin' and ':write ++nobin'
+func Test_write_binary_file()
+ " create a file without an eol/eof character
+ call writefile(0z616161, 'Xfile1', 'b')
+ new Xfile1
+ write ++bin Xfile2
+ write ++nobin Xfile3
+ call assert_equal(0z616161, readblob('Xfile2'))
+ if has('win32')
+ call assert_equal(0z6161610D.0A, readblob('Xfile3'))
+ else
+ call assert_equal(0z6161610A, readblob('Xfile3'))
+ endif
+ call delete('Xfile1')
+ call delete('Xfile2')
+ call delete('Xfile3')
+endfunc
+
" Check that buffer is written before triggering QuitPre
func Test_wq_quitpre_autocommand()
edit Xsomefile
diff --git a/src/nvim/testdir/view_util.vim b/src/nvim/testdir/view_util.vim
index 1cdce21602..a4d0e56af9 100644
--- a/src/nvim/testdir/view_util.vim
+++ b/src/nvim/testdir/view_util.vim
@@ -19,7 +19,7 @@ endfunc
" Get text on the screen, including composing characters.
" ScreenLines(lnum, width) or
" ScreenLines([start, end], width)
-function! ScreenLines(lnum, width) abort
+func ScreenLines(lnum, width) abort
redraw!
if type(a:lnum) == v:t_list
let start = a:lnum[0]
@@ -33,9 +33,9 @@ function! ScreenLines(lnum, width) abort
let lines += [join(map(range(1, a:width), 'screenstring(l, v:val)'), '')]
endfor
return lines
-endfunction
+endfunc
-function! ScreenAttrs(lnum, width) abort
+func ScreenAttrs(lnum, width) abort
redraw!
if type(a:lnum) == v:t_list
let start = a:lnum[0]
@@ -49,16 +49,16 @@ function! ScreenAttrs(lnum, width) abort
let attrs += [map(range(1, a:width), 'screenattr(l, v:val)')]
endfor
return attrs
-endfunction
+endfunc
-function! NewWindow(height, width) abort
+func NewWindow(height, width) abort
exe a:height . 'new'
exe a:width . 'vsp'
set winfixwidth winfixheight
redraw!
-endfunction
+endfunc
-function! CloseWindow() abort
+func CloseWindow() abort
bw!
redraw!
-endfunction
+endfunc
diff --git a/src/nvim/testdir/vim9.vim b/src/nvim/testdir/vim9.vim
new file mode 100644
index 0000000000..3c0ff2b2dd
--- /dev/null
+++ b/src/nvim/testdir/vim9.vim
@@ -0,0 +1,112 @@
+
+" Use a different file name for each run.
+let s:sequence = 1
+
+func CheckScriptFailure(lines, error, lnum = -3)
+ if get(a:lines, 0, '') ==# 'vim9script'
+ return
+ endif
+ let cwd = getcwd()
+ let fname = 'XScriptFailure' .. s:sequence
+ let s:sequence += 1
+ call writefile(a:lines, fname)
+ try
+ call assert_fails('so ' .. fname, a:error, a:lines, a:lnum)
+ finally
+ call chdir(cwd)
+ call delete(fname)
+ endtry
+endfunc
+
+func CheckScriptSuccess(lines)
+ if get(a:lines, 0, '') ==# 'vim9script'
+ return
+ endif
+ let cwd = getcwd()
+ let fname = 'XScriptSuccess' .. s:sequence
+ let s:sequence += 1
+ call writefile(a:lines, fname)
+ try
+ exe 'so ' .. fname
+ finally
+ call chdir(cwd)
+ call delete(fname)
+ endtry
+endfunc
+
+" Check that "lines" inside a legacy function has no error.
+func CheckLegacySuccess(lines)
+ let cwd = getcwd()
+ let fname = 'XlegacySuccess' .. s:sequence
+ let s:sequence += 1
+ call writefile(['func Func()'] + a:lines + ['endfunc'], fname)
+ try
+ exe 'so ' .. fname
+ call Func()
+ finally
+ delfunc! Func
+ call chdir(cwd)
+ call delete(fname)
+ endtry
+endfunc
+
+" Check that "lines" inside a legacy function results in the expected error
+func CheckLegacyFailure(lines, error)
+ let cwd = getcwd()
+ let fname = 'XlegacyFails' .. s:sequence
+ let s:sequence += 1
+ call writefile(['func Func()'] + a:lines + ['endfunc', 'call Func()'], fname)
+ try
+ call assert_fails('so ' .. fname, a:error)
+ finally
+ delfunc! Func
+ call chdir(cwd)
+ call delete(fname)
+ endtry
+endfunc
+
+" Execute "lines" in a legacy function, translated as in
+" CheckLegacyAndVim9Success()
+func CheckTransLegacySuccess(lines)
+ let legacylines = a:lines->deepcopy()->map({_, v ->
+ \ v->substitute('\<VAR\>', 'let', 'g')
+ \ ->substitute('\<LET\>', 'let', 'g')
+ \ ->substitute('\<LSTART\>', '{', 'g')
+ \ ->substitute('\<LMIDDLE\>', '->', 'g')
+ \ ->substitute('\<LEND\>', '}', 'g')
+ \ ->substitute('\<TRUE\>', '1', 'g')
+ \ ->substitute('\<FALSE\>', '0', 'g')
+ \ ->substitute('#"', ' "', 'g')
+ \ })
+ call CheckLegacySuccess(legacylines)
+endfunc
+
+" Execute "lines" in a legacy function
+" Use 'VAR' for a declaration.
+" Use 'LET' for an assignment
+" Use ' #"' for a comment
+" Use LSTART arg LMIDDLE expr LEND for lambda
+" Use 'TRUE' for 1
+" Use 'FALSE' for 0
+func CheckLegacyAndVim9Success(lines)
+ call CheckTransLegacySuccess(a:lines)
+endfunc
+
+" Execute "lines" in a legacy function
+" Use 'VAR' for a declaration.
+" Use 'LET' for an assignment
+" Use ' #"' for a comment
+func CheckLegacyAndVim9Failure(lines, error)
+ if type(a:error) == type('string')
+ let legacyError = error
+ else
+ let legacyError = error[0]
+ endif
+
+ let legacylines = a:lines->deepcopy()->map({_, v ->
+ \ v->substitute('\<VAR\>', 'let', 'g')
+ \ ->substitute('\<LET\>', 'let', 'g')
+ \ ->substitute('#"', ' "', 'g')
+ \ })
+ call CheckLegacyFailure(legacylines, legacyError)
+endfunc