aboutsummaryrefslogtreecommitdiff
path: root/src/nvim/testdir
diff options
context:
space:
mode:
authorJosh Rahm <rahm@google.com>2022-07-18 19:37:18 +0000
committerJosh Rahm <rahm@google.com>2022-07-18 19:37:18 +0000
commit308e1940dcd64aa6c344c403d4f9e0dda58d9c5c (patch)
tree35fe43e01755e0f312650667004487a44d6b7941 /src/nvim/testdir
parent96a00c7c588b2f38a2424aeeb4ea3581d370bf2d (diff)
parente8c94697bcbe23a5c7b07c292b90a6b70aadfa87 (diff)
downloadrneovim-308e1940dcd64aa6c344c403d4f9e0dda58d9c5c.tar.gz
rneovim-308e1940dcd64aa6c344c403d4f9e0dda58d9c5c.tar.bz2
rneovim-308e1940dcd64aa6c344c403d4f9e0dda58d9c5c.zip
Merge remote-tracking branch 'upstream/master' into rahm
Diffstat (limited to 'src/nvim/testdir')
-rw-r--r--src/nvim/testdir/check.vim41
-rwxr-xr-xsrc/nvim/testdir/runnvim.sh10
-rw-r--r--src/nvim/testdir/runtest.vim16
-rw-r--r--src/nvim/testdir/setup.vim59
-rw-r--r--src/nvim/testdir/shared.vim9
-rw-r--r--src/nvim/testdir/test_alot.vim39
-rw-r--r--src/nvim/testdir/test_alot_utf8.vim1
-rw-r--r--src/nvim/testdir/test_arabic.vim28
-rw-r--r--src/nvim/testdir/test_arglist.vim42
-rw-r--r--src/nvim/testdir/test_assert.vim214
-rw-r--r--src/nvim/testdir/test_autochdir.vim71
-rw-r--r--src/nvim/testdir/test_autocmd.vim360
-rw-r--r--src/nvim/testdir/test_backspace_opt.vim4
-rw-r--r--src/nvim/testdir/test_blockedit.vim48
-rw-r--r--src/nvim/testdir/test_breakindent.vim6
-rw-r--r--src/nvim/testdir/test_buffer.vim197
-rw-r--r--src/nvim/testdir/test_bufline.vim35
-rw-r--r--src/nvim/testdir/test_bufwintabinfo.vim34
-rw-r--r--src/nvim/testdir/test_cd.vim24
-rw-r--r--src/nvim/testdir/test_cdo.vim216
-rw-r--r--src/nvim/testdir/test_changelist.vim2
-rw-r--r--src/nvim/testdir/test_charsearch.vim39
-rw-r--r--src/nvim/testdir/test_charsearch_utf8.vim2
-rw-r--r--src/nvim/testdir/test_cindent.vim5256
-rw-r--r--src/nvim/testdir/test_clientserver.vim8
-rw-r--r--src/nvim/testdir/test_cmdline.vim748
-rw-r--r--src/nvim/testdir/test_command_count.vim2
-rw-r--r--src/nvim/testdir/test_compiler.vim7
-rw-r--r--src/nvim/testdir/test_conceal.vim4
-rw-r--r--src/nvim/testdir/test_cscope.vim12
-rw-r--r--src/nvim/testdir/test_cursor_func.vim263
-rw-r--r--src/nvim/testdir/test_cursorline.vim83
-rw-r--r--src/nvim/testdir/test_debugger.vim2
-rw-r--r--src/nvim/testdir/test_delete.vim114
-rw-r--r--src/nvim/testdir/test_diffmode.vim96
-rw-r--r--src/nvim/testdir/test_digraph.vim97
-rw-r--r--src/nvim/testdir/test_display.vim50
-rw-r--r--src/nvim/testdir/test_edit.vim284
-rw-r--r--src/nvim/testdir/test_eval_stuff.vim30
-rw-r--r--src/nvim/testdir/test_ex_mode.vim135
-rw-r--r--src/nvim/testdir/test_excmd.vim252
-rw-r--r--src/nvim/testdir/test_exec_while_if.vim18
-rw-r--r--src/nvim/testdir/test_execute_func.vim27
-rw-r--r--src/nvim/testdir/test_exists.vim4
-rw-r--r--src/nvim/testdir/test_exit.vim22
-rw-r--r--src/nvim/testdir/test_expand.vim128
-rw-r--r--src/nvim/testdir/test_expand_func.vim31
-rw-r--r--src/nvim/testdir/test_expr.vim65
-rw-r--r--src/nvim/testdir/test_feedkeys.vim23
-rw-r--r--src/nvim/testdir/test_file_perm.vim30
-rw-r--r--src/nvim/testdir/test_filechanged.vim130
-rw-r--r--src/nvim/testdir/test_filetype.vim1134
-rw-r--r--src/nvim/testdir/test_filetype_lua.vim2
-rw-r--r--src/nvim/testdir/test_filter_cmd.vim43
-rw-r--r--src/nvim/testdir/test_filter_map.vim10
-rw-r--r--src/nvim/testdir/test_findfile.vim28
-rw-r--r--src/nvim/testdir/test_float_func.vim5
-rw-r--r--src/nvim/testdir/test_fnamemodify.vim19
-rw-r--r--src/nvim/testdir/test_fold.vim108
-rw-r--r--src/nvim/testdir/test_functions.vim542
-rw-r--r--src/nvim/testdir/test_gf.vim64
-rw-r--r--src/nvim/testdir/test_global.vim42
-rw-r--r--src/nvim/testdir/test_gn.vim18
-rw-r--r--src/nvim/testdir/test_goto.vim59
-rw-r--r--src/nvim/testdir/test_help.vim51
-rw-r--r--src/nvim/testdir/test_help_tagjump.vim62
-rw-r--r--src/nvim/testdir/test_highlight.vim84
-rw-r--r--src/nvim/testdir/test_history.vim130
-rw-r--r--src/nvim/testdir/test_increment.vim10
-rw-r--r--src/nvim/testdir/test_indent.vim279
-rw-r--r--src/nvim/testdir/test_ins_complete.vim230
-rw-r--r--src/nvim/testdir/test_interrupt.vim13
-rw-r--r--src/nvim/testdir/test_join.vim8
-rw-r--r--src/nvim/testdir/test_jumplist.vim41
-rw-r--r--src/nvim/testdir/test_jumps.vim11
-rw-r--r--src/nvim/testdir/test_lambda.vim163
-rw-r--r--src/nvim/testdir/test_langmap.vim30
-rw-r--r--src/nvim/testdir/test_legacy_filetype.vim4
-rw-r--r--src/nvim/testdir/test_lispwords.vim15
-rw-r--r--src/nvim/testdir/test_listchars.vim185
-rw-r--r--src/nvim/testdir/test_listdict.vim53
-rw-r--r--src/nvim/testdir/test_listlbr.vim6
-rw-r--r--src/nvim/testdir/test_listlbr_utf8.vim17
-rw-r--r--src/nvim/testdir/test_makeencoding.vim3
-rw-r--r--src/nvim/testdir/test_maparg.vim39
-rw-r--r--src/nvim/testdir/test_mapping.vim569
-rw-r--r--src/nvim/testdir/test_marks.vim71
-rw-r--r--src/nvim/testdir/test_matchadd_conceal.vim23
-rw-r--r--src/nvim/testdir/test_matchadd_conceal_utf8.vim16
-rw-r--r--src/nvim/testdir/test_matchfuzzy.vim271
-rw-r--r--src/nvim/testdir/test_menu.vim94
-rw-r--r--src/nvim/testdir/test_messages.vim195
-rw-r--r--src/nvim/testdir/test_mksession.vim156
-rw-r--r--src/nvim/testdir/test_mksession_utf8.vim5
-rw-r--r--src/nvim/testdir/test_move.vim1
-rw-r--r--src/nvim/testdir/test_normal.vim883
-rw-r--r--src/nvim/testdir/test_number.vim29
-rw-r--r--src/nvim/testdir/test_options.vim258
-rw-r--r--src/nvim/testdir/test_packadd.vim361
-rw-r--r--src/nvim/testdir/test_perl.vim6
-rw-r--r--src/nvim/testdir/test_plus_arg_edit.vim15
-rw-r--r--src/nvim/testdir/test_popup.vim57
-rw-r--r--src/nvim/testdir/test_profile.vim31
-rw-r--r--src/nvim/testdir/test_put.vim113
-rw-r--r--src/nvim/testdir/test_python2.vim5
-rw-r--r--src/nvim/testdir/test_python3.vim6
-rw-r--r--src/nvim/testdir/test_pyx2.vim5
-rw-r--r--src/nvim/testdir/test_pyx3.vim5
-rw-r--r--src/nvim/testdir/test_quickfix.vim749
-rw-r--r--src/nvim/testdir/test_quotestar.vim7
-rw-r--r--src/nvim/testdir/test_random.vim51
-rw-r--r--src/nvim/testdir/test_regex_char_classes.vim2
-rw-r--r--src/nvim/testdir/test_regexp_latin.vim270
-rw-r--r--src/nvim/testdir/test_regexp_utf8.vim43
-rw-r--r--src/nvim/testdir/test_registers.vim528
-rw-r--r--src/nvim/testdir/test_reltime.vim6
-rw-r--r--src/nvim/testdir/test_rename.vim4
-rw-r--r--src/nvim/testdir/test_retab.vim24
-rw-r--r--src/nvim/testdir/test_scriptnames.vim6
-rw-r--r--src/nvim/testdir/test_search.vim530
-rw-r--r--src/nvim/testdir/test_search_stat.vim109
-rw-r--r--src/nvim/testdir/test_searchpos.vim30
-rw-r--r--src/nvim/testdir/test_selectmode.vim57
-rw-r--r--src/nvim/testdir/test_set.vim29
-rw-r--r--src/nvim/testdir/test_sha256.vim6
-rw-r--r--src/nvim/testdir/test_smartindent.vim107
-rw-r--r--src/nvim/testdir/test_sort.vim20
-rw-r--r--src/nvim/testdir/test_source.vim42
-rw-r--r--src/nvim/testdir/test_source_utf8.vim27
-rw-r--r--src/nvim/testdir/test_spell.vim174
-rw-r--r--src/nvim/testdir/test_spell_utf8.vim67
-rw-r--r--src/nvim/testdir/test_spellfile.vim745
-rw-r--r--src/nvim/testdir/test_stat.vim42
-rw-r--r--src/nvim/testdir/test_statusline.vim73
-rw-r--r--src/nvim/testdir/test_substitute.vim483
-rw-r--r--src/nvim/testdir/test_suspend.vim4
-rw-r--r--src/nvim/testdir/test_swap.vim61
-rw-r--r--src/nvim/testdir/test_syntax.vim150
-rw-r--r--src/nvim/testdir/test_system.vim30
-rw-r--r--src/nvim/testdir/test_tabline.vim59
-rw-r--r--src/nvim/testdir/test_tabpage.vim150
-rw-r--r--src/nvim/testdir/test_tagjump.vim487
-rw-r--r--src/nvim/testdir/test_taglist.vim20
-rw-r--r--src/nvim/testdir/test_termcodes.vim60
-rw-r--r--src/nvim/testdir/test_textformat.vim318
-rw-r--r--src/nvim/testdir/test_textobjects.vim203
-rw-r--r--src/nvim/testdir/test_timers.vim133
-rw-r--r--src/nvim/testdir/test_trycatch.vim160
-rw-r--r--src/nvim/testdir/test_undo.vim162
-rw-r--r--src/nvim/testdir/test_usercommands.vim129
-rw-r--r--src/nvim/testdir/test_utf8.vim54
-rw-r--r--src/nvim/testdir/test_utf8_comparisons.vim11
-rw-r--r--src/nvim/testdir/test_vartabs.vim59
-rw-r--r--src/nvim/testdir/test_vimscript.vim222
-rw-r--r--src/nvim/testdir/test_virtualedit.vim265
-rw-r--r--src/nvim/testdir/test_visual.vim572
-rw-r--r--src/nvim/testdir/test_winbuf_close.vim19
-rw-r--r--src/nvim/testdir/test_window_cmd.vim501
-rw-r--r--src/nvim/testdir/test_writefile.vim156
159 files changed, 22577 insertions, 1740 deletions
diff --git a/src/nvim/testdir/check.vim b/src/nvim/testdir/check.vim
index 14bab33a2f..4107df99d6 100644
--- a/src/nvim/testdir/check.vim
+++ b/src/nvim/testdir/check.vim
@@ -12,9 +12,9 @@ endfunc
" Command to check for the absence of a feature.
command -nargs=1 CheckNotFeature call CheckNotFeature(<f-args>)
func CheckNotFeature(name)
- if !has(a:name, 1)
- throw 'Checking for non-existent feature ' .. a:name
- endif
+ " if !has(a:name, 1)
+ " throw 'Checking for non-existent feature ' .. a:name
+ " endif
if has(a:name)
throw 'Skipped: ' .. a:name .. ' feature present'
endif
@@ -55,6 +55,14 @@ func CheckMSWindows()
endif
endfunc
+" Command to check for NOT running on MS-Windows
+command CheckNotMSWindows call CheckNotMSWindows()
+func CheckNotMSWindows()
+ if has('win32')
+ throw 'Skipped: does not work on MS-Windows'
+ endif
+endfunc
+
" Command to check for running on Unix
command CheckUnix call CheckUnix()
func CheckUnix()
@@ -63,6 +71,15 @@ 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'
+ endif
+endfunc
+
" Command to check that making screendumps is supported.
" Caller must source screendump.vim
command CheckScreendump call CheckScreendump()
@@ -104,6 +121,14 @@ func CheckNotGui()
endif
endfunc
+" Command to check that test is not running as root
+command CheckNotRoot call CheckNotRoot()
+func CheckNotRoot()
+ if IsRoot()
+ throw 'Skipped: cannot run test as root'
+ endif
+endfunc
+
" Command to check that the current language is English
command CheckEnglish call CheckEnglish()
func CheckEnglish()
@@ -112,11 +137,11 @@ func CheckEnglish()
endif
endfunc
-" Command to check for NOT running on MS-Windows
-command CheckNotMSWindows call CheckNotMSWindows()
-func CheckNotMSWindows()
- if has('win32')
- throw 'Skipped: does not work on MS-Windows'
+" Command to check for not running under ASAN
+command CheckNotAsan call CheckNotAsan()
+func CheckNotAsan()
+ if execute('version') =~# '-fsanitize=[a-z,]*\<address\>'
+ throw 'Skipped: does not work with ASAN'
endif
endfunc
diff --git a/src/nvim/testdir/runnvim.sh b/src/nvim/testdir/runnvim.sh
index fdd3f3144b..322265737a 100755
--- a/src/nvim/testdir/runnvim.sh
+++ b/src/nvim/testdir/runnvim.sh
@@ -38,7 +38,7 @@ main() {(
-S runnvim.vim \
"$tlog" > "out-$tlog" 2> "err-$tlog"
then
- fail "$test_name" F "Nvim exited with non-zero code"
+ fail "$test_name" "Nvim exited with non-zero code"
fi
{
echo "Stdout of :terminal runner"
@@ -53,7 +53,7 @@ main() {(
if test "$oldesttest" = 1 ; then
if ! diff -q test.out "$test_name.ok" > /dev/null 2>&1 ; then
if test -f test.out ; then
- fail "$test_name" F "Oldest test .out file differs from .ok file"
+ fail "$test_name" "Oldest test .out file differs from .ok file"
{
echo "Diff between test.out and $test_name.ok"
echo "$separator"
@@ -65,9 +65,6 @@ main() {(
fi
fi
fi
- if test "$FAILED" = 1 ; then
- ci_fold start "$test_name"
- fi
valgrind_check .
if test -n "$LOG_DIR" ; then
check_sanitizer "$LOG_DIR"
@@ -78,9 +75,6 @@ main() {(
fi
rm -f "$tlog"
if test "$FAILED" = 1 ; then
- ci_fold end ""
- fi
- if test "$FAILED" = 1 ; then
echo "Test $test_name failed, see output above and summary for more details" >> test.log
# When Neovim crashed/aborted it might not have created messages.
# test.log itself is used as an indicator to exit non-zero in the Makefile.
diff --git a/src/nvim/testdir/runtest.vim b/src/nvim/testdir/runtest.vim
index b0d872e392..6b16e888a9 100644
--- a/src/nvim/testdir/runtest.vim
+++ b/src/nvim/testdir/runtest.vim
@@ -153,6 +153,9 @@ func RunTheTest(test)
" directory after executing the test.
let save_cwd = getcwd()
+ " Align Nvim defaults to Vim.
+ source setup.vim
+
if exists("*SetUp")
try
call SetUp()
@@ -361,24 +364,25 @@ let s:flaky_tests = [
\ 'Test_cursorhold_insert()',
\ 'Test_exit_callback_interval()',
\ 'Test_map_timeout_with_timer_interrupt()',
- \ 'Test_oneshot()',
\ 'Test_out_cb()',
- \ 'Test_paused()',
\ 'Test_popup_and_window_resize()',
\ 'Test_quoteplus()',
\ 'Test_quotestar()',
\ 'Test_reltime()',
- \ 'Test_repeat_many()',
- \ 'Test_repeat_three()',
\ 'Test_state()',
- \ 'Test_stop_all_in_callback()',
\ 'Test_term_mouse_double_click_to_create_tab()',
\ 'Test_term_mouse_multiple_clicks_to_visually_select()',
\ 'Test_terminal_composing_unicode()',
\ 'Test_terminal_redir_file()',
\ 'Test_terminal_tmap()',
+ \ 'Test_timer_oneshot()',
+ \ 'Test_timer_paused()',
+ \ 'Test_timer_repeat_many()',
+ \ 'Test_timer_repeat_three()',
+ \ 'Test_timer_stop_all_in_callback()',
+ \ 'Test_timer_stop_in_callback()',
+ \ 'Test_timer_with_partial_callback()',
\ 'Test_termwinscroll()',
- \ 'Test_with_partial_callback()',
\ ]
" Locate Test_ functions and execute them.
diff --git a/src/nvim/testdir/setup.vim b/src/nvim/testdir/setup.vim
index fdae0697c3..e6c0762729 100644
--- a/src/nvim/testdir/setup.vim
+++ b/src/nvim/testdir/setup.vim
@@ -1,3 +1,35 @@
+if exists('s:did_load')
+ " Align Nvim defaults to Vim.
+ set backspace=
+ set complete=.,w,b,u,t,i
+ set directory&
+ set directory^=.
+ set fillchars=vert:\|,fold:-
+ set formatoptions=tcq
+ set fsync
+ set laststatus=1
+ set listchars=eol:$
+ set joinspaces
+ set nohidden nosmarttab noautoindent noautoread noruler noshowcmd
+ set nohlsearch noincsearch
+ set nrformats=bin,octal,hex
+ set shortmess=filnxtToOS
+ set sidescroll=0
+ set tags=./tags,tags
+ set undodir&
+ set undodir^=.
+ set wildoptions=
+ set startofline
+ set sessionoptions&
+ set sessionoptions+=options
+ set viewoptions&
+ set viewoptions+=options
+ set switchbuf=
+ " Make "Q" switch to Ex mode.
+ " This does not work for all tests.
+ nnoremap Q gQ
+endif
+
" Common preparations for running tests.
" Only load this once.
@@ -6,30 +38,9 @@ if exists('s:did_load')
endif
let s:did_load = 1
-" Align Nvim defaults to Vim.
-set backspace=
-set directory^=.
-set fillchars=vert:\|,fold:-
-set laststatus=1
-set listchars=eol:$
-set joinspaces
-set nohidden nosmarttab noautoindent noautoread complete-=i noruler noshowcmd
-set nrformats+=octal
-set shortmess-=F
-set sidescroll=0
-set tags=./tags,tags
-set undodir^=.
-set wildoptions=
-set startofline
-set sessionoptions+=options
-set viewoptions+=options
-set switchbuf=
-
-" Unmap Nvim default mappings.
-unmap Y
-unmap <C-L>
-iunmap <C-U>
-iunmap <C-W>
+" Clear Nvim default mappings.
+mapclear
+mapclear!
" 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 f456ff4250..c2809844ac 100644
--- a/src/nvim/testdir/shared.vim
+++ b/src/nvim/testdir/shared.vim
@@ -343,6 +343,15 @@ func RunVimPiped(before, after, arguments, pipecmd)
return 1
endfunc
+func IsRoot()
+ if !has('unix')
+ return v:false
+ elseif $USER == 'root' || system('id -un') =~ '\<root\>'
+ return v:true
+ endif
+ return v:false
+endfunc
+
" Get all messages but drop the maintainer entry.
func GetMessages()
redir => result
diff --git a/src/nvim/testdir/test_alot.vim b/src/nvim/testdir/test_alot.vim
index c0ac4393c4..43a519bc84 100644
--- a/src/nvim/testdir/test_alot.vim
+++ b/src/nvim/testdir/test_alot.vim
@@ -3,55 +3,32 @@
source test_backup.vim
source test_behave.vim
-source test_cd.vim
-source test_changedtick.vim
source test_compiler.vim
-source test_cursor_func.vim
-source test_cursorline.vim
source test_ex_equal.vim
source test_ex_undo.vim
source test_ex_z.vim
source test_ex_mode.vim
-source test_execute_func.vim
+source test_expand.vim
source test_expand_func.vim
source test_feedkeys.vim
-source test_filter_cmd.vim
-source test_filter_map.vim
-source test_findfile.vim
-source test_float_func.vim
-source test_functions.vim
+source test_file_perm.vim
+source test_fnamemodify.vim
source test_ga.vim
+source test_glob2regpat.vim
source test_global.vim
-source test_goto.vim
-source test_join.vim
-source test_jumps.vim
-source test_fileformat.vim
-source test_filetype.vim
-source test_filetype_lua.vim
-source test_lambda.vim
+source test_lispwords.vim
source test_menu.vim
-source test_messages.vim
-source test_modeline.vim
source test_move.vim
-source test_partial.vim
-source test_popup.vim
source test_put.vim
-source test_rename.vim
+source test_reltime.vim
source test_scroll_opt.vim
+source test_searchpos.vim
+source test_set.vim
source test_shift.vim
-source test_sort.vim
source test_sha256.vim
-source test_suspend.vim
-source test_syn_attr.vim
source test_tabline.vim
-source test_tabpage.vim
source test_tagcase.vim
source test_tagfunc.vim
-source test_tagjump.vim
-source test_taglist.vim
-source test_true_false.vim
source test_unlet.vim
source test_version.vim
-source test_virtualedit.vim
-source test_window_cmd.vim
source test_wnext.vim
diff --git a/src/nvim/testdir/test_alot_utf8.vim b/src/nvim/testdir/test_alot_utf8.vim
index 70f14320a6..77f5ede4c8 100644
--- a/src/nvim/testdir/test_alot_utf8.vim
+++ b/src/nvim/testdir/test_alot_utf8.vim
@@ -6,7 +6,6 @@
source test_charsearch_utf8.vim
source test_expr_utf8.vim
-source test_matchadd_conceal_utf8.vim
source test_mksession_utf8.vim
source test_regexp_utf8.vim
source test_source_utf8.vim
diff --git a/src/nvim/testdir/test_arabic.vim b/src/nvim/testdir/test_arabic.vim
index 450c6f98f5..272937387d 100644
--- a/src/nvim/testdir/test_arabic.vim
+++ b/src/nvim/testdir/test_arabic.vim
@@ -2,9 +2,8 @@
" NOTE: This just checks if the code works. If you know Arabic please add
" functional tests that check the shaping works with real text.
-if !has('arabic')
- throw 'Skipped: arabic feature missing'
-endif
+source check.vim
+CheckFeature arabic
source view_util.vim
@@ -563,3 +562,26 @@ func Test_shape_combination_isolated()
set arabicshape&
bwipe!
endfunc
+
+" Test for entering arabic character in a search command
+func Test_arabic_chars_in_search_cmd()
+ new
+ set arabic
+ call feedkeys("i\nsghl!\<C-^>vim\<C-^>", 'tx')
+ call cursor(1, 1)
+ call feedkeys("/^sghl!\<C-^>vim$\<C-^>\<CR>", 'tx')
+ call assert_equal([2, 1], [line('.'), col('.')])
+
+ " Try searching in left-to-right mode
+ set rightleftcmd=
+ call cursor(1, 1)
+ call feedkeys("/^sghl!\<C-^>vim$\<CR>", 'tx')
+ call assert_equal([2, 1], [line('.'), col('.')])
+
+ set rightleftcmd&
+ set rightleft&
+ set arabic&
+ bwipe!
+endfunc
+
+" vim: shiftwidth=2 sts=2 expandtab
diff --git a/src/nvim/testdir/test_arglist.vim b/src/nvim/testdir/test_arglist.vim
index 164149476f..ca7c8574cb 100644
--- a/src/nvim/testdir/test_arglist.vim
+++ b/src/nvim/testdir/test_arglist.vim
@@ -1,5 +1,8 @@
" Test argument list commands
+source shared.vim
+source term_util.vim
+
func Reset_arglist()
args a | %argd
endfunc
@@ -510,3 +513,42 @@ func Test_argdo()
call assert_equal(['Xa.c', 'Xb.c', 'Xc.c'], l)
bwipe Xa.c Xb.c Xc.c
endfunc
+
+" Test for quiting Vim with unedited files in the argument list
+func Test_quit_with_arglist()
+ if !CanRunVimInTerminal()
+ throw 'Skipped: cannot run vim in terminal'
+ endif
+ let buf = RunVimInTerminal('', {'rows': 6})
+ call term_sendkeys(buf, ":set nomore\n")
+ call term_sendkeys(buf, ":args a b c\n")
+ call term_sendkeys(buf, ":quit\n")
+ call term_wait(buf)
+ call WaitForAssert({-> assert_match('^E173:', term_getline(buf, 6))})
+ call StopVimInTerminal(buf)
+
+ " Try :confirm quit with unedited files in arglist
+ let buf = RunVimInTerminal('', {'rows': 6})
+ call term_sendkeys(buf, ":set nomore\n")
+ call term_sendkeys(buf, ":args a b c\n")
+ call term_sendkeys(buf, ":confirm quit\n")
+ call term_wait(buf)
+ call WaitForAssert({-> assert_match('^\[Y\]es, (N)o: *$',
+ \ term_getline(buf, 6))})
+ call term_sendkeys(buf, "N")
+ call term_wait(buf)
+ call term_sendkeys(buf, ":confirm quit\n")
+ call WaitForAssert({-> assert_match('^\[Y\]es, (N)o: *$',
+ \ term_getline(buf, 6))})
+ call term_sendkeys(buf, "Y")
+ call term_wait(buf)
+ call WaitForAssert({-> assert_equal("finished", term_getstatus(buf))})
+ only!
+ " When this test fails, swap files are left behind which breaks subsequent
+ " tests
+ call delete('.a.swp')
+ call delete('.b.swp')
+ call delete('.c.swp')
+endfunc
+
+" vim: shiftwidth=2 sts=2 expandtab
diff --git a/src/nvim/testdir/test_assert.vim b/src/nvim/testdir/test_assert.vim
index 52f243aaea..fdd8b0bef6 100644
--- a/src/nvim/testdir/test_assert.vim
+++ b/src/nvim/testdir/test_assert.vim
@@ -1,5 +1,75 @@
" Test that the methods used for testing work.
+func Test_assert_false()
+ call assert_equal(0, assert_false(0))
+ call assert_equal(0, assert_false(v:false))
+ call assert_equal(0, v:false->assert_false())
+
+ call assert_equal(1, assert_false(123))
+ call assert_match("Expected False but got 123", v:errors[0])
+ call remove(v:errors, 0)
+
+ call assert_equal(1, 123->assert_false())
+ call assert_match("Expected False but got 123", v:errors[0])
+ call remove(v:errors, 0)
+endfunc
+
+func Test_assert_true()
+ call assert_equal(0, assert_true(1))
+ call assert_equal(0, assert_true(123))
+ call assert_equal(0, assert_true(v:true))
+ call assert_equal(0, v:true->assert_true())
+
+ call assert_equal(1, assert_true(0))
+ call assert_match("Expected True but got 0", v:errors[0])
+ call remove(v:errors, 0)
+
+ call assert_equal(1, 0->assert_true())
+ call assert_match("Expected True but got 0", v:errors[0])
+ call remove(v:errors, 0)
+endfunc
+
+func Test_assert_equal()
+ let s = 'foo'
+ call assert_equal(0, assert_equal('foo', s))
+ let n = 4
+ call assert_equal(0, assert_equal(4, n))
+ let l = [1, 2, 3]
+ call assert_equal(0, assert_equal([1, 2, 3], l))
+ call assert_equal(v:_null_list, v:_null_list)
+ call assert_equal(v:_null_list, [])
+ call assert_equal([], v:_null_list)
+
+ let s = 'foo'
+ call assert_equal(1, assert_equal('bar', s))
+ call assert_match("Expected 'bar' but got 'foo'", v:errors[0])
+ call remove(v:errors, 0)
+
+ call assert_equal('XxxxxxxxxxxxxxxxxxxxxxX', 'XyyyyyyyyyyyyyyyyyyyyyyyyyX')
+ call assert_match("Expected 'X\\\\\\[x occurs 21 times]X' but got 'X\\\\\\[y occurs 25 times]X'", v:errors[0])
+ call remove(v:errors, 0)
+endfunc
+
+func Test_assert_equal_dict()
+ call assert_equal(0, assert_equal(#{one: 1, two: 2}, #{two: 2, one: 1}))
+
+ call assert_equal(1, assert_equal(#{one: 1, two: 2}, #{two: 2, one: 3}))
+ call assert_match("Expected {'one': 1} but got {'one': 3} - 1 equal item omitted", v:errors[0])
+ call remove(v:errors, 0)
+
+ call assert_equal(1, assert_equal(#{one: 1, two: 2}, #{two: 22, one: 11}))
+ call assert_match("Expected {'one': 1, 'two': 2} but got {'one': 11, 'two': 22}", v:errors[0])
+ call remove(v:errors, 0)
+
+ call assert_equal(1, assert_equal(#{}, #{two: 2, one: 1}))
+ call assert_match("Expected {} but got {'one': 1, 'two': 2}", v:errors[0])
+ call remove(v:errors, 0)
+
+ call assert_equal(1, assert_equal(#{two: 2, one: 1}, #{}))
+ call assert_match("Expected {'one': 1, 'two': 2} but got {}", v:errors[0])
+ call remove(v:errors, 0)
+endfunc
+
func Test_assert_equalfile()
call assert_equal(1, assert_equalfile('abcabc', 'xyzxyz'))
call assert_match("E485: Can't read file abcabc", v:errors[0])
@@ -46,17 +116,129 @@ func Test_assert_equalfile()
call delete('Xtwo')
endfunc
+func Test_assert_notequal()
+ let n = 4
+ call assert_equal(0, assert_notequal('foo', n))
+ let s = 'foo'
+ call assert_equal(0, assert_notequal([1, 2, 3], s))
+
+ call assert_equal(1, assert_notequal('foo', s))
+ call assert_match("Expected not equal to 'foo'", v:errors[0])
+ call remove(v:errors, 0)
+endfunc
+
+func Test_assert_report()
+ call assert_equal(1, assert_report('something is wrong'))
+ call assert_match('something is wrong', v:errors[0])
+ call remove(v:errors, 0)
+ call assert_equal(1, 'also wrong'->assert_report())
+ call assert_match('also wrong', v:errors[0])
+ call remove(v:errors, 0)
+endfunc
+
+func Test_assert_exception()
+ try
+ nocommand
+ catch
+ call assert_equal(0, assert_exception('E492:'))
+ endtry
+
+ try
+ nocommand
+ catch
+ try
+ " illegal argument, get NULL for error
+ call assert_equal(1, assert_exception([]))
+ catch
+ call assert_equal(0, assert_exception('E730:'))
+ endtry
+ endtry
+endfunc
+
+func Test_wrong_error_type()
+ let save_verrors = v:errors
+ let v:['errors'] = {'foo': 3}
+ call assert_equal('yes', 'no')
+ let verrors = v:errors
+ let v:errors = save_verrors
+ call assert_equal(type([]), type(verrors))
+endfunc
+
+func Test_match()
+ call assert_equal(0, assert_match('^f.*b.*r$', 'foobar'))
+
+ call assert_equal(1, assert_match('bar.*foo', 'foobar'))
+ call assert_match("Pattern 'bar.*foo' does not match 'foobar'", v:errors[0])
+ call remove(v:errors, 0)
+
+ call assert_equal(1, assert_match('bar.*foo', 'foobar', 'wrong'))
+ call assert_match('wrong', v:errors[0])
+ call remove(v:errors, 0)
+
+ call assert_equal(1, 'foobar'->assert_match('bar.*foo', 'wrong'))
+ call assert_match('wrong', v:errors[0])
+ call remove(v:errors, 0)
+endfunc
+
+func Test_notmatch()
+ call assert_equal(0, assert_notmatch('foo', 'bar'))
+ call assert_equal(0, assert_notmatch('^foobar$', 'foobars'))
+
+ call assert_equal(1, assert_notmatch('foo', 'foobar'))
+ call assert_match("Pattern 'foo' does match 'foobar'", v:errors[0])
+ call remove(v:errors, 0)
+
+ call assert_equal(1, 'foobar'->assert_notmatch('foo'))
+ call assert_match("Pattern 'foo' does match 'foobar'", v:errors[0])
+ call remove(v:errors, 0)
+endfunc
+
+func Test_assert_fail_fails()
+ call assert_equal(1, assert_fails('xxx', 'E12345'))
+ call assert_match("Expected 'E12345' but got 'E492:", v:errors[0])
+ call remove(v:errors, 0)
+
+ call assert_equal(1, assert_fails('xxx', 'E9876', 'stupid'))
+ call assert_match("stupid: Expected '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)
+
+ 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)
+endfunc
+
func Test_assert_fails_in_try_block()
try
call assert_equal(0, assert_fails('throw "error"'))
endtry
endfunc
+func Test_assert_beeps()
+ new
+ call assert_equal(0, assert_beeps('normal h'))
+
+ call assert_equal(1, assert_beeps('normal 0'))
+ call assert_match("command did not beep: normal 0", v:errors[0])
+ call remove(v:errors, 0)
+
+ call assert_equal(0, 'normal h'->assert_beeps())
+ call assert_equal(1, 'normal 0'->assert_beeps())
+ call assert_match("command did not beep: normal 0", v:errors[0])
+ call remove(v:errors, 0)
+
+ bwipe
+endfunc
+
func Test_assert_inrange()
call assert_equal(0, assert_inrange(7, 7, 7))
call assert_equal(0, assert_inrange(5, 7, 5))
call assert_equal(0, assert_inrange(5, 7, 6))
call assert_equal(0, assert_inrange(5, 7, 7))
+
call assert_equal(1, assert_inrange(5, 7, 4))
call assert_match("Expected range 5 - 7, but got 4", v:errors[0])
call remove(v:errors, 0)
@@ -64,6 +246,12 @@ func Test_assert_inrange()
call assert_match("Expected range 5 - 7, but got 8", v:errors[0])
call remove(v:errors, 0)
+ call assert_equal(0, 5->assert_inrange(5, 7))
+ call assert_equal(0, 7->assert_inrange(5, 7))
+ call assert_equal(1, 8->assert_inrange(5, 7))
+ call assert_match("Expected range 5 - 7, but got 8", v:errors[0])
+ call remove(v:errors, 0)
+
call assert_fails('call assert_inrange(1, 1)', 'E119:')
if has('float')
@@ -83,6 +271,32 @@ func Test_assert_inrange()
endif
endfunc
+func Test_assert_with_msg()
+ call assert_equal('foo', 'bar', 'testing')
+ call assert_match("testing: Expected 'foo' but got 'bar'", v:errors[0])
+ call remove(v:errors, 0)
+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 feedkeys("\<LeftMouse>", "xt")
+ call assert_equal([0, 1, 5, 0], getpos('.'))
+ call test_setmouse(2, 20)
+ call feedkeys("\<LeftMouse>", "xt")
+ call assert_equal([0, 2, 8, 0], getpos('.'))
+ call test_setmouse(5, 1)
+ call feedkeys("\<LeftMouse>", "xt")
+ call assert_equal([0, 2, 1, 0], getpos('.'))
+ bwipe!
+ let &mouse = save_mouse
+endfunc
+
" Must be last.
func Test_zz_quit_detected()
" Verify that if a test function ends Vim the test script detects this.
diff --git a/src/nvim/testdir/test_autochdir.vim b/src/nvim/testdir/test_autochdir.vim
index 9ad727241e..4229095f9f 100644
--- a/src/nvim/testdir/test_autochdir.vim
+++ b/src/nvim/testdir/test_autochdir.vim
@@ -26,6 +26,54 @@ func Test_set_filename()
call delete('samples/Xtest')
endfunc
+func Test_set_filename_other_window()
+ CheckFunction test_autochdir
+ let cwd = getcwd()
+ call test_autochdir()
+ call mkdir('Xa')
+ call mkdir('Xb')
+ call mkdir('Xc')
+ try
+ args Xa/aaa.txt Xb/bbb.txt
+ set acd
+ let winid = win_getid()
+ snext
+ call assert_equal('Xb', substitute(getcwd(), '.*/\([^/]*\)$', '\1', ''))
+ call win_execute(winid, 'file ' .. cwd .. '/Xc/ccc.txt')
+ call assert_equal('Xb', substitute(getcwd(), '.*/\([^/]*\)$', '\1', ''))
+ finally
+ set noacd
+ call chdir(cwd)
+ call delete('Xa', 'rf')
+ call delete('Xb', 'rf')
+ call delete('Xc', 'rf')
+ bwipe! aaa.txt
+ bwipe! bbb.txt
+ bwipe! ccc.txt
+ endtry
+endfunc
+
+func Test_acd_win_execute()
+ CheckFunction test_autochdir
+ let cwd = getcwd()
+ set acd
+ call test_autochdir()
+
+ call mkdir('Xfile')
+ let winid = win_getid()
+ new Xfile/file
+ call assert_match('testdir.Xfile$', getcwd())
+ cd ..
+ call assert_match('testdir$', getcwd())
+ call win_execute(winid, 'echo')
+ call assert_match('testdir$', getcwd())
+
+ bwipe!
+ set noacd
+ call chdir(cwd)
+ call delete('Xfile', 'rf')
+endfunc
+
func Test_verbose_pwd()
CheckFunction test_autochdir
let cwd = getcwd()
@@ -42,20 +90,27 @@ func Test_verbose_pwd()
set acd
wincmd w
call assert_match('\[autochdir\].*testdir$', execute('verbose pwd'))
- execute 'lcd' cwd
- call assert_match('\[window\].*testdir$', execute('verbose pwd'))
execute 'tcd' cwd
call assert_match('\[tabpage\].*testdir$', execute('verbose pwd'))
execute 'cd' cwd
call assert_match('\[global\].*testdir$', execute('verbose pwd'))
+ execute 'lcd' cwd
+ call assert_match('\[window\].*testdir$', execute('verbose pwd'))
edit
call assert_match('\[autochdir\].*testdir$', execute('verbose pwd'))
+ enew
+ wincmd w
+ call assert_match('\[autochdir\].*testdir[/\\]Xautodir', execute('verbose pwd'))
+ wincmd w
+ call assert_match('\[window\].*testdir$', execute('verbose pwd'))
wincmd w
call assert_match('\[autochdir\].*testdir[/\\]Xautodir', execute('verbose pwd'))
set noacd
call assert_match('\[autochdir\].*testdir[/\\]Xautodir', execute('verbose pwd'))
wincmd w
- call assert_match('\[global\].*testdir', execute('verbose pwd'))
+ call assert_match('\[window\].*testdir$', execute('verbose pwd'))
+ execute 'cd' cwd
+ call assert_match('\[global\].*testdir$', execute('verbose pwd'))
wincmd w
call assert_match('\[window\].*testdir[/\\]Xautodir', execute('verbose pwd'))
@@ -64,4 +119,14 @@ func Test_verbose_pwd()
call delete('Xautodir', 'rf')
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:')
+ set nowic
+endfunc
+
+
" vim: shiftwidth=2 sts=2 expandtab
diff --git a/src/nvim/testdir/test_autocmd.vim b/src/nvim/testdir/test_autocmd.vim
index 45285b69a1..438851a0ad 100644
--- a/src/nvim/testdir/test_autocmd.vim
+++ b/src/nvim/testdir/test_autocmd.vim
@@ -3,8 +3,9 @@
source shared.vim
source check.vim
source term_util.vim
+source screendump.vim
-func! s:cleanup_buffers() abort
+func s:cleanup_buffers() abort
for bnr in range(1, bufnr('$'))
if bufloaded(bnr) && bufnr('%') != bnr
execute 'bd! ' . bnr
@@ -168,7 +169,9 @@ func Test_autocmd_bufunload_avoiding_SEGV_01()
exe 'autocmd BufUnload <buffer> ' . (lastbuf + 1) . 'bwipeout!'
augroup END
- call assert_fails('edit bb.txt', 'E937:')
+ " Todo: check for E937 generated first
+ " call assert_fails('edit bb.txt', 'E937:')
+ call assert_fails('edit bb.txt', 'E517:')
autocmd! test_autocmd_bufunload
augroup! test_autocmd_bufunload
@@ -260,6 +263,84 @@ func Test_win_tab_autocmd()
unlet g:record
endfunc
+func Test_WinScrolled()
+ CheckRunVimInTerminal
+
+ let lines =<< trim END
+ set nowrap scrolloff=0
+ for ii in range(1, 18)
+ call setline(ii, repeat(nr2char(96 + ii), ii * 2))
+ endfor
+ let win_id = win_getid()
+ let g:matched = v:false
+ 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>'))
+ END
+ call writefile(lines, 'Xtest_winscrolled')
+ let buf = RunVimInTerminal('-S Xtest_winscrolled', {'rows': 6})
+
+ call term_sendkeys(buf, ":echo g:scrolled\<CR>")
+ call WaitForAssert({-> assert_match('^0 ', term_getline(buf, 6))}, 1000)
+
+ " Scroll left/right in Normal mode.
+ call term_sendkeys(buf, "zlzh:echo g:scrolled\<CR>")
+ call WaitForAssert({-> assert_match('^2 ', term_getline(buf, 6))}, 1000)
+
+ " 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)
+
+ " 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)
+
+ " 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.
+ call term_sendkeys(buf, "5zl2k")
+ call term_sendkeys(buf, ":echo g:scrolled\<CR>")
+ call WaitForAssert({-> assert_match('^8 ', term_getline(buf, 6))}, 1000)
+
+ " 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)
+
+ " Ensure the expansion of <amatch> and <afile> matches the window ID.
+ 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 StopVimInTerminal(buf)
+ call delete('Xtest_winscrolled')
+endfunc
+
+func Test_WinScrolled_close_curwin()
+ CheckRunVimInTerminal
+
+ let lines =<< trim END
+ set nowrap scrolloff=0
+ call setline(1, ['aaa', 'bbb'])
+ vsplit
+ au WinScrolled * close
+ au VimLeave * call writefile(['123456'], 'Xtestout')
+ END
+ call writefile(lines, 'Xtest_winscrolled_close_curwin')
+ let buf = RunVimInTerminal('-S Xtest_winscrolled_close_curwin', {'rows': 6})
+
+ " This was using freed memory
+ call term_sendkeys(buf, "\<C-E>")
+ call TermWait(buf)
+ call StopVimInTerminal(buf)
+
+ call assert_equal(['123456'], readfile('Xtestout'))
+
+ call delete('Xtest_winscrolled_close_curwin')
+ call delete('Xtestout')
+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.
@@ -299,6 +380,40 @@ func Test_WinClosed()
unlet g:triggered
endfunc
+func Test_WinClosed_throws()
+ vnew
+ let bnr = bufnr()
+ call assert_equal(1, bufloaded(bnr))
+ augroup test-WinClosed
+ autocmd WinClosed * throw 'foo'
+ augroup END
+ try
+ close
+ catch /.*/
+ endtry
+ call assert_equal(0, bufloaded(bnr))
+
+ autocmd! test-WinClosed
+ augroup! test-WinClosed
+endfunc
+
+func Test_WinClosed_throws_with_tabs()
+ tabnew
+ let bnr = bufnr()
+ call assert_equal(1, bufloaded(bnr))
+ augroup test-WinClosed
+ autocmd WinClosed * throw 'foo'
+ augroup END
+ try
+ close
+ catch /.*/
+ endtry
+ call assert_equal(0, bufloaded(bnr))
+
+ autocmd! test-WinClosed
+ augroup! test-WinClosed
+endfunc
+
func s:AddAnAutocmd()
augroup vimBarTest
au BufReadCmd * echo 'hello'
@@ -427,7 +542,7 @@ func Test_three_windows()
e Xtestje2
sp Xtestje1
call assert_fails('e', 'E937:')
- call assert_equal('Xtestje2', expand('%'))
+ call assert_equal('Xtestje1', expand('%'))
" Test changing buffers in a BufWipeout autocommand. If this goes wrong
" there are ml_line errors and/or a Crash.
@@ -450,7 +565,6 @@ func Test_three_windows()
au!
enew
- bwipe! Xtestje1
call delete('Xtestje1')
call delete('Xtestje2')
call delete('Xtestje3')
@@ -502,7 +616,7 @@ func Test_autocmd_bufwipe_in_SessLoadPost()
[CODE]
call writefile(content, 'Xvimrc')
- call system(v:progpath. ' --headless -i NONE -u Xvimrc --noplugins -S Session.vim -c cq')
+ call system(GetVimCommand('Xvimrc') .. ' --headless --noplugins -S Session.vim -c cq')
let errors = join(readfile('Xerrors'))
call assert_match('E814', errors)
@@ -562,7 +676,7 @@ func Test_autocmd_bufwipe_in_SessLoadPost2()
[CODE]
call writefile(content, 'Xvimrc')
- call system(v:progpath. ' --headless -i NONE -u Xvimrc --noplugins -S Session.vim -c cq')
+ call system(GetVimCommand('Xvimrc') .. ' --headless --noplugins -S Session.vim -c cq')
let errors = join(readfile('Xerrors'))
" This probably only ever matches on unix.
call assert_notmatch('Caught deadly signal SEGV', errors)
@@ -1506,7 +1620,7 @@ func Test_bufunload_all()
call writefile(content, 'Xtest')
call delete('Xout')
- call system(v:progpath. ' -u NORC -i NONE -N -S Xtest')
+ call system(GetVimCommandClean() .. ' -N --headless -S Xtest')
call assert_true(filereadable('Xout'))
call delete('Xxx1')
@@ -1606,7 +1720,7 @@ func Test_Cmd_Autocmds()
au BufWriteCmd XtestE call extend(g:lines, getline(0, '$'))
wall " will write other window to 'lines'
call assert_equal(4, len(g:lines), g:lines)
- call assert_equal("\tasdf", g:lines[2])
+ call assert_equal("asdf", g:lines[2])
au! BufReadCmd
au! BufWriteCmd
@@ -1827,6 +1941,14 @@ func Test_autocommand_all_events()
call assert_fails('au * x bwipe', 'E1155:')
endfunc
+func Test_autocmd_user()
+ au User MyEvent let s:res = [expand("<afile>"), expand("<amatch>")]
+ doautocmd User MyEvent
+ call assert_equal(['MyEvent', 'MyEvent'], s:res)
+ au! User
+ unlet s:res
+endfunc
+
function s:Before_test_dirchanged()
augroup test_dirchanged
autocmd!
@@ -1850,14 +1972,23 @@ endfunc
function Test_dirchanged_global()
call s:Before_test_dirchanged()
+ autocmd test_dirchanged DirChangedPre global call add(s:li, expand("<amatch>") .. " pre cd " .. v:event.directory)
autocmd test_dirchanged DirChanged global call add(s:li, "cd:")
autocmd test_dirchanged DirChanged global call add(s:li, expand("<afile>"))
call chdir(s:dir_foo)
- call assert_equal(["cd:", s:dir_foo], s:li)
+ let expected = ["global pre cd " .. s:dir_foo, "cd:", s:dir_foo]
+ call assert_equal(expected, s:li)
call chdir(s:dir_foo)
- call assert_equal(["cd:", s:dir_foo], s:li)
+ call assert_equal(expected, s:li)
exe 'lcd ' .. fnameescape(s:dir_bar)
- call assert_equal(["cd:", s:dir_foo], s:li)
+ call assert_equal(expected, s:li)
+
+ exe 'cd ' .. s:dir_foo
+ exe 'cd ' .. s:dir_bar
+ autocmd! test_dirchanged DirChanged global let g:result = expand("<afile>")
+ cd -
+ call assert_equal(s:dir_foo, substitute(g:result, '\\', '/', 'g'))
+
call s:After_test_dirchanged()
endfunc
@@ -1879,6 +2010,7 @@ function Test_dirchanged_auto()
CheckOption autochdir
call s:Before_test_dirchanged()
call test_autochdir()
+ autocmd test_dirchanged DirChangedPre auto call add(s:li, "pre cd " .. v:event.directory)
autocmd test_dirchanged DirChanged auto call add(s:li, "auto:")
autocmd test_dirchanged DirChanged auto call add(s:li, expand("<afile>"))
set acd
@@ -1886,7 +2018,8 @@ function Test_dirchanged_auto()
call assert_equal([], s:li)
exe 'edit ' . s:dir_foo . '/Xfile'
call assert_equal(s:dir_foo, getcwd())
- call assert_equal(["auto:", s:dir_foo], s:li)
+ let expected = ["pre cd " .. s:dir_foo, "auto:", s:dir_foo]
+ call assert_equal(expected, s:li)
set noacd
bwipe!
call s:After_test_dirchanged()
@@ -2093,7 +2226,7 @@ func Test_autocmd_bufreadpre()
" (even though the position will be invalid, this should make Vim reset the
" cursor position in the other window.
wincmd p
- 1
+ 1 " set cpo+=g
" won't do anything, but try to set the cursor on an invalid lnum
autocmd BufReadPre <buffer> :norm! 70gg
" triggers BufReadPre, should not move the cursor in either window
@@ -2108,8 +2241,11 @@ func Test_autocmd_bufreadpre()
close
close
call delete('XAutocmdBufReadPre.txt')
+ " set cpo-=g
endfunc
+" FileChangedShell tested in test_filechanged.vim
+
" Tests for the following autocommands:
" - FileWritePre writing a compressed file
" - FileReadPost reading a compressed file
@@ -2331,6 +2467,19 @@ func Test_throw_in_BufWritePre()
au! throwing
endfunc
+func Test_autocmd_in_try_block()
+ call mkdir('Xdir')
+ au BufEnter * let g:fname = expand('%')
+ try
+ edit Xdir/
+ endtry
+ call assert_match('Xdir', g:fname)
+
+ unlet g:fname
+ au! BufEnter
+ call delete('Xdir', 'rf')
+endfunc
+
func Test_autocmd_CmdWinEnter()
CheckRunVimInTerminal
" There is not cmdwin switch, so
@@ -2380,7 +2529,63 @@ func Test_autocmd_was_using_freed_memory()
pclose
endfunc
-" FileChangedShell tested in test_filechanged.vim
+func Test_BufWrite_lockmarks()
+ edit! Xtest
+ call setline(1, ['a', 'b', 'c', 'd'])
+
+ " :lockmarks preserves the marks
+ call SetChangeMarks(2, 3)
+ lockmarks write
+ call assert_equal([2, 3], [line("'["), line("']")])
+
+ " *WritePre autocmds get the correct line range, but lockmarks preserves the
+ " original values for the user
+ augroup lockmarks
+ au!
+ au BufWritePre,FilterWritePre * call assert_equal([1, 4], [line("'["), line("']")])
+ au FileWritePre * call assert_equal([3, 4], [line("'["), line("']")])
+ augroup END
+
+ lockmarks write
+ call assert_equal([2, 3], [line("'["), line("']")])
+
+ if executable('cat')
+ lockmarks %!cat
+ call assert_equal([2, 3], [line("'["), line("']")])
+ endif
+
+ lockmarks 3,4write Xtest2
+ call assert_equal([2, 3], [line("'["), line("']")])
+
+ au! lockmarks
+ augroup! lockmarks
+ call delete('Xtest')
+ call delete('Xtest2')
+endfunc
+
+" Test closing a window or editing another buffer from a FileChangedRO handler
+" in a readonly buffer
+func Test_FileChangedRO_winclose()
+ augroup FileChangedROTest
+ au!
+ autocmd FileChangedRO * quit
+ augroup END
+ new
+ set readonly
+ call assert_fails('normal i', 'E788:')
+ close
+ augroup! FileChangedROTest
+
+ augroup FileChangedROTest
+ au!
+ autocmd FileChangedRO * edit Xfile
+ augroup END
+ new
+ set readonly
+ call assert_fails('normal i', 'E788:')
+ close
+ augroup! FileChangedROTest
+endfunc
func LogACmd()
call add(g:logged, line('$'))
@@ -2489,6 +2694,27 @@ func Test_autocmd_window()
%bw!
endfunc
+" Test for trying to close the temporary window used for executing an autocmd
+func Test_close_autocmd_window()
+ %bw!
+ edit one.txt
+ tabnew two.txt
+ augroup aucmd_win_test2
+ au!
+ " Nvim makes aucmd_win the last window
+ " au BufEnter * if expand('<afile>') == 'one.txt' | 1close | endif
+ au BufEnter * if expand('<afile>') == 'one.txt' | close | endif
+ augroup END
+
+ call assert_fails('doautoall BufEnter', 'E813:')
+
+ augroup aucmd_win_test2
+ au!
+ augroup END
+ augroup! aucmd_win_test2
+ %bw!
+endfunc
+
" Test for trying to close the tab that has the temporary window for exeucing
" an autocmd.
func Test_close_autocmd_tab()
@@ -2509,13 +2735,23 @@ func Test_close_autocmd_tab()
%bwipe!
endfunc
+func Test_Visual_doautoall_redraw()
+ call setline(1, ['a', 'b'])
+ new
+ wincmd p
+ call feedkeys("G\<C-V>", 'txn')
+ autocmd User Explode ++once redraw
+ doautoall User Explode
+ %bwipe!
+endfunc
+
func Test_autocmd_closes_window()
au BufNew,BufWinLeave * e %e
file yyy
au BufNew,BufWinLeave * ball
- call assert_fails('n xxx', 'E143:')
+ n xxx
- bwipe %
+ %bwipe
au! BufNew
au! BufWinLeave
endfunc
@@ -2531,9 +2767,34 @@ func Test_autocmd_quit_psearch()
augroup aucmd_win_test
au!
augroup END
+ new
+ pclose
+endfunc
+
+" Fuzzer found some strange combination that caused a crash.
+func Test_autocmd_normal_mess()
+ " For unknown reason this hangs on MS-Windows
+ CheckNotMSWindows
+
+ augroup aucmd_normal_test
+ au BufLeave,BufWinLeave,BufHidden,BufUnload,BufDelete,BufWipeout * norm 7q/qc
+ augroup END
+ " Nvim has removed :open
+ " call assert_fails('o4', 'E1159')
+ call assert_fails('e4', 'E1159')
+ silent! H
+ call assert_fails('e xx', 'E1159')
+ normal G
+
+ augroup aucmd_normal_test
+ au!
+ augroup END
endfunc
func Test_autocmd_closing_cmdwin()
+ " For unknown reason this hangs on MS-Windows
+ CheckNotMSWindows
+
au BufWinLeave * nested q
call assert_fails("norm 7q?\n", 'E855:')
@@ -2542,4 +2803,71 @@ func Test_autocmd_closing_cmdwin()
only
endfunc
+func Test_autocmd_vimgrep()
+ augroup aucmd_vimgrep
+ au QuickfixCmdPre,BufNew,BufReadCmd * sb
+ " Nvim makes aucmd_win the last window
+ " au QuickfixCmdPre,BufNew,BufReadCmd * q9
+ au QuickfixCmdPre,BufNew,BufReadCmd * exe 'q' .. (winnr('$') - (win_gettype(winnr('$')) == 'autocmd'))
+ augroup END
+ call assert_fails('lv ?a? foo', 'E926:')
+
+ augroup aucmd_vimgrep
+ au!
+ augroup END
+endfunc
+
+func Test_bufwipeout_changes_window()
+ " This should not crash, but we don't have any expectations about what
+ " happens, changing window in BufWipeout has unpredictable results.
+ tabedit
+ let g:window_id = win_getid()
+ topleft new
+ setlocal bufhidden=wipe
+ autocmd BufWipeout <buffer> call win_gotoid(g:window_id)
+ tabprevious
+ +tabclose
+
+ unlet g:window_id
+ au! BufWipeout
+ %bwipe!
+endfunc
+
+func Test_v_event_readonly()
+ autocmd CompleteChanged * let v:event.width = 0
+ call assert_fails("normal! i\<C-X>\<C-V>", 'E46:')
+ au! CompleteChanged
+
+ autocmd DirChangedPre * let v:event.directory = ''
+ call assert_fails('cd .', 'E46:')
+ au! DirChangedPre
+
+ autocmd ModeChanged * let v:event.new_mode = ''
+ call assert_fails('normal! cc', 'E46:')
+ au! ModeChanged
+
+ autocmd TextYankPost * let v:event.operator = ''
+ call assert_fails('normal! yy', 'E46:')
+ au! TextYankPost
+endfunc
+
+
+func Test_noname_autocmd()
+ augroup test_noname_autocmd_group
+ autocmd!
+ autocmd BufEnter * call add(s:li, ["BufEnter", expand("<afile>")])
+ autocmd BufDelete * call add(s:li, ["BufDelete", expand("<afile>")])
+ autocmd BufLeave * call add(s:li, ["BufLeave", expand("<afile>")])
+ autocmd BufUnload * call add(s:li, ["BufUnload", expand("<afile>")])
+ autocmd BufWipeout * call add(s:li, ["BufWipeout", expand("<afile>")])
+ augroup END
+
+ let s:li = []
+ edit foo
+ call assert_equal([['BufUnload', ''], ['BufDelete', ''], ['BufWipeout', ''], ['BufEnter', 'foo']], s:li)
+
+ au! test_noname_autocmd_group
+ augroup! test_noname_autocmd_group
+endfunc
+
" vim: shiftwidth=2 sts=2 expandtab
diff --git a/src/nvim/testdir/test_backspace_opt.vim b/src/nvim/testdir/test_backspace_opt.vim
index 11459991ea..59e94d2898 100644
--- a/src/nvim/testdir/test_backspace_opt.vim
+++ b/src/nvim/testdir/test_backspace_opt.vim
@@ -76,7 +76,7 @@ func Test_backspace_ctrl_u()
set cpo-=<
inoremap <c-u> <left><c-u>
- exe "normal Avim3\<C-U>\<Esc>\<CR>"
+ exe "normal Avim3\<*C-U>\<Esc>\<CR>"
iunmap <c-u>
exe "normal Avim4\<C-U>\<C-U>\<Esc>\<CR>"
@@ -86,7 +86,7 @@ func Test_backspace_ctrl_u()
exe "normal A vim6\<Esc>Azwei\<C-G>u\<C-U>\<Esc>\<CR>"
inoremap <c-u> <left><c-u>
- exe "normal A vim7\<C-U>\<C-U>\<Esc>\<CR>"
+ exe "normal A vim7\<*C-U>\<*C-U>\<Esc>\<CR>"
call assert_equal([
\ "1 this shouldn't be deleted",
diff --git a/src/nvim/testdir/test_blockedit.vim b/src/nvim/testdir/test_blockedit.vim
index 38978ef689..7b56b1554f 100644
--- a/src/nvim/testdir/test_blockedit.vim
+++ b/src/nvim/testdir/test_blockedit.vim
@@ -81,4 +81,52 @@ func Test_blockinsert_delete()
bwipe!
endfunc
+func Test_blockappend_eol_cursor()
+ new
+ " Test 1 Move 1 char left
+ call setline(1, ['aaa', 'bbb', 'ccc'])
+ exe "norm! gg$\<c-v>2jA\<left>x\<esc>"
+ call assert_equal(['aaxa', 'bbxb', 'ccxc'], getline(1, '$'))
+ " Test 2 Move 2 chars left
+ sil %d
+ call setline(1, ['aaa', 'bbb', 'ccc'])
+ exe "norm! gg$\<c-v>2jA\<left>\<left>x\<esc>"
+ call assert_equal(['axaa', 'bxbb', 'cxcc'], getline(1, '$'))
+ " Test 3 Move 3 chars left (outside of the visual selection)
+ sil %d
+ call setline(1, ['aaa', 'bbb', 'ccc'])
+ exe "norm! ggl$\<c-v>2jA\<left>\<left>\<left>x\<esc>"
+ call assert_equal(['xaaa', 'bbb', 'ccc'], getline(1, '$'))
+ bw!
+endfunc
+
+func Test_blockappend_eol_cursor2()
+ new
+ " Test 1 Move 1 char left
+ call setline(1, ['aaaaa', 'bbb', 'ccccc'])
+ exe "norm! gg\<c-v>$2jA\<left>x\<esc>"
+ call assert_equal(['aaaaxa', 'bbbx', 'ccccxc'], getline(1, '$'))
+ " Test 2 Move 2 chars left
+ sil %d
+ call setline(1, ['aaaaa', 'bbb', 'ccccc'])
+ exe "norm! gg\<c-v>$2jA\<left>\<left>x\<esc>"
+ call assert_equal(['aaaxaa', 'bbbx', 'cccxcc'], getline(1, '$'))
+ " Test 3 Move 3 chars left (to the beginning of the visual selection)
+ sil %d
+ call setline(1, ['aaaaa', 'bbb', 'ccccc'])
+ exe "norm! gg\<c-v>$2jA\<left>\<left>\<left>x\<esc>"
+ call assert_equal(['aaxaaa', 'bbxb', 'ccxccc'], getline(1, '$'))
+ " Test 4 Move 3 chars left (outside of the visual selection)
+ sil %d
+ call setline(1, ['aaaaa', 'bbb', 'ccccc'])
+ exe "norm! ggl\<c-v>$2jA\<left>\<left>\<left>x\<esc>"
+ call assert_equal(['aaxaaa', 'bbxb', 'ccxccc'], getline(1, '$'))
+ " Test 5 Move 4 chars left (outside of the visual selection)
+ sil %d
+ call setline(1, ['aaaaa', 'bbb', 'ccccc'])
+ exe "norm! ggl\<c-v>$2jA\<left>\<left>\<left>\<left>x\<esc>"
+ call assert_equal(['axaaaa', 'bxbb', 'cxcccc'], getline(1, '$'))
+ bw!
+endfunc
+
" vim: shiftwidth=2 sts=2 expandtab
diff --git a/src/nvim/testdir/test_breakindent.vim b/src/nvim/testdir/test_breakindent.vim
index 8d592f21ea..a37751e748 100644
--- a/src/nvim/testdir/test_breakindent.vim
+++ b/src/nvim/testdir/test_breakindent.vim
@@ -1,7 +1,7 @@
" Test for breakindent
"
" Note: if you get strange failures when adding new tests, it might be that
-" while the test is run, the breakindent cacheing gets in its way.
+" 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')
@@ -20,7 +20,7 @@ func s:screen_lines2(lnums, lnume, width) abort
return ScreenLines([a:lnums, a:lnume], a:width)
endfunc
-func! s:compare_lines(expect, actual)
+func s:compare_lines(expect, actual)
call assert_equal(join(a:expect, "\n"), join(a:actual, "\n"))
endfunc
@@ -770,7 +770,7 @@ func Test_breakindent20_list()
\ "shall make no law ",
\ ]
call s:compare_lines(expect, lines)
- " set mininum indent
+ " set minimum indent
setl briopt=min:5
redraw!
let lines = s:screen_lines2(1, 6, 20)
diff --git a/src/nvim/testdir/test_buffer.vim b/src/nvim/testdir/test_buffer.vim
index 40111fdf06..67be3e6747 100644
--- a/src/nvim/testdir/test_buffer.vim
+++ b/src/nvim/testdir/test_buffer.vim
@@ -1,5 +1,162 @@
" Tests for Vim buffer
+source check.vim
+
+" Test for the :bunload command with an offset
+func Test_bunload_with_offset()
+ %bwipe!
+ call writefile(['B1'], 'b1')
+ call writefile(['B2'], 'b2')
+ call writefile(['B3'], 'b3')
+ call writefile(['B4'], 'b4')
+
+ " Load four buffers. Unload the second and third buffers and then
+ " execute .+3bunload to unload the last buffer.
+ edit b1
+ new b2
+ new b3
+ new b4
+
+ bunload b2
+ bunload b3
+ exe bufwinnr('b1') . 'wincmd w'
+ .+3bunload
+ call assert_equal(0, getbufinfo('b4')[0].loaded)
+ call assert_equal('b1',
+ \ fnamemodify(getbufinfo({'bufloaded' : 1})[0].name, ':t'))
+
+ " Load four buffers. Unload the third and fourth buffers. Execute .+3bunload
+ " and check whether the second buffer is unloaded.
+ ball
+ bunload b3
+ bunload b4
+ exe bufwinnr('b1') . 'wincmd w'
+ .+3bunload
+ call assert_equal(0, getbufinfo('b2')[0].loaded)
+ call assert_equal('b1',
+ \ fnamemodify(getbufinfo({'bufloaded' : 1})[0].name, ':t'))
+
+ " Load four buffers. Unload the second and third buffers and from the last
+ " buffer execute .-3bunload to unload the first buffer.
+ ball
+ bunload b2
+ bunload b3
+ exe bufwinnr('b4') . 'wincmd w'
+ .-3bunload
+ call assert_equal(0, getbufinfo('b1')[0].loaded)
+ call assert_equal('b4',
+ \ fnamemodify(getbufinfo({'bufloaded' : 1})[0].name, ':t'))
+
+ " Load four buffers. Unload the first and second buffers. Execute .-3bunload
+ " from the last buffer and check whether the third buffer is unloaded.
+ ball
+ bunload b1
+ bunload b2
+ exe bufwinnr('b4') . 'wincmd w'
+ .-3bunload
+ call assert_equal(0, getbufinfo('b3')[0].loaded)
+ call assert_equal('b4',
+ \ fnamemodify(getbufinfo({'bufloaded' : 1})[0].name, ':t'))
+
+ %bwipe!
+ call delete('b1')
+ call delete('b2')
+ call delete('b3')
+ call delete('b4')
+
+ 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:')
+endfunc
+
+" Test for :buffer, :bnext, :bprevious, :brewind, :blast and :bmodified
+" commands
+func Test_buflist_browse()
+ %bwipe!
+ call assert_fails('buffer 1000', 'E86:')
+
+ call writefile(['foo1', 'foo2', 'foo3', 'foo4'], 'Xfile1')
+ call writefile(['bar1', 'bar2', 'bar3', 'bar4'], 'Xfile2')
+ call writefile(['baz1', 'baz2', 'baz3', 'baz4'], 'Xfile3')
+ edit Xfile1
+ let b1 = bufnr()
+ edit Xfile2
+ let b2 = bufnr()
+ edit +/baz4 Xfile3
+ let b3 = bufnr()
+
+ call assert_fails('buffer ' .. b1 .. ' abc', 'E488:')
+ call assert_equal(b3, bufnr())
+ call assert_equal(4, line('.'))
+ exe 'buffer +/bar2 ' .. b2
+ call assert_equal(b2, bufnr())
+ call assert_equal(2, line('.'))
+ exe 'buffer +/bar1'
+ call assert_equal(b2, bufnr())
+ call assert_equal(1, line('.'))
+
+ brewind +
+ call assert_equal(b1, bufnr())
+ call assert_equal(4, line('.'))
+
+ blast +/baz2
+ call assert_equal(b3, bufnr())
+ call assert_equal(2, line('.'))
+
+ bprevious +/bar4
+ call assert_equal(b2, bufnr())
+ call assert_equal(4, line('.'))
+
+ bnext +/baz3
+ call assert_equal(b3, bufnr())
+ call assert_equal(3, line('.'))
+
+ call assert_fails('bmodified', 'E84:')
+ call setbufvar(b2, '&modified', 1)
+ exe 'bmodified +/bar3'
+ call assert_equal(b2, bufnr())
+ call assert_equal(3, line('.'))
+
+ " With no listed buffers in the list, :bnext and :bprev should fail
+ %bwipe!
+ set nobuflisted
+ call assert_fails('bnext', 'E85:')
+ call assert_fails('bprev', 'E85:')
+ set buflisted
+
+ call assert_fails('sandbox bnext', 'E48:')
+
+ call delete('Xfile1')
+ call delete('Xfile2')
+ call delete('Xfile3')
+ %bwipe!
+endfunc
+
+" Test for :bdelete
+func Test_bdelete_cmd()
+ %bwipe!
+ call assert_fails('bdelete 5', 'E516:')
+ call assert_fails('1,1bdelete 1 2', 'E488:')
+
+ " Deleting a unlisted and unloaded buffer
+ edit Xfile1
+ let bnr = bufnr()
+ set nobuflisted
+ enew
+ call assert_fails('bdelete ' .. bnr, 'E516:')
+ %bwipe!
+endfunc
+
func Test_buffer_error()
new foo1
new foo2
@@ -30,4 +187,44 @@ func Test_balt()
call assert_equal('OtherBuffer', bufname())
endfunc
+" Test for buffer match URL(scheme) check
+" scheme is alpha and inner hyphen only.
+func Test_buffer_scheme()
+ CheckMSWindows
+
+ 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},
+ \]
+ for buf in bufnames
+ new `=buf.name`
+ if buf.match
+ call assert_equal(buf.name, getbufinfo(buf.id)[0].name)
+ else
+ " slashes will have become backslashes
+ call assert_notequal(buf.name, getbufinfo(buf.id)[0].name)
+ endif
+ bwipe
+ endfor
+
+ set shellslash&
+endfunc
+
+" this was using a NULL pointer after failing to use the pattern
+func Test_buf_pattern_invalid()
+ vsplit 0000000
+ silent! buf [0--]\&\zs*\zs*e
+ bwipe!
+
+ vsplit 00000000000000000000000000
+ silent! buf [0--]\&\zs*\zs*e
+ bwipe!
+endfunc
+
" vim: shiftwidth=2 sts=2 expandtab
diff --git a/src/nvim/testdir/test_bufline.vim b/src/nvim/testdir/test_bufline.vim
index 765ae17736..ffb8e3facd 100644
--- a/src/nvim/testdir/test_bufline.vim
+++ b/src/nvim/testdir/test_bufline.vim
@@ -153,3 +153,38 @@ func Test_appendbufline_redraw()
call StopVimInTerminal(buf)
call delete('XscriptMatchCommon')
endfunc
+
+func Test_setbufline_select_mode()
+ new
+ call setline(1, ['foo', 'bar'])
+ call feedkeys("j^v2l\<C-G>", 'nx')
+
+ let bufnr = bufadd('Xdummy')
+ call bufload(bufnr)
+ call setbufline(bufnr, 1, ['abc'])
+
+ call feedkeys("x", 'nx')
+ call assert_equal(['foo', 'x'], getline(1, 2))
+
+ exe "bwipe! " .. bufnr
+ bwipe!
+endfunc
+
+func Test_deletebufline_select_mode()
+ new
+ call setline(1, ['foo', 'bar'])
+ call feedkeys("j^v2l\<C-G>", 'nx')
+
+ let bufnr = bufadd('Xdummy')
+ call bufload(bufnr)
+ call setbufline(bufnr, 1, ['abc', 'def'])
+ call deletebufline(bufnr, 1)
+
+ call feedkeys("x", 'nx')
+ call assert_equal(['foo', 'x'], getline(1, 2))
+
+ exe "bwipe! " .. bufnr
+ bwipe!
+endfunc
+
+" vim: shiftwidth=2 sts=2 expandtab
diff --git a/src/nvim/testdir/test_bufwintabinfo.vim b/src/nvim/testdir/test_bufwintabinfo.vim
index a6eb93b4be..326aefb731 100644
--- a/src/nvim/testdir/test_bufwintabinfo.vim
+++ b/src/nvim/testdir/test_bufwintabinfo.vim
@@ -145,6 +145,13 @@ function Test_get_win_options()
endif
endfunc
+function Test_getbufinfo_lastused()
+ new Xfoo
+ let info = getbufinfo('Xfoo')[0]
+ call assert_equal(has_key(info, 'lastused'), 1)
+ call assert_equal(type(info.lastused), type(0))
+endfunc
+
func Test_getbufinfo_lines()
new Xfoo
call setline(1, ['a', 'bc', 'd'])
@@ -155,9 +162,26 @@ func Test_getbufinfo_lines()
bw!
endfunc
-function Test_getbufinfo_lastused()
- new Xfoo
- let info = getbufinfo('Xfoo')[0]
- call assert_equal(has_key(info, 'lastused'), 1)
- call assert_equal(type(info.lastused), type(0))
+func Test_getwininfo_au()
+ enew
+ call setline(1, range(1, 16))
+
+ let g:info = #{}
+ augroup T1
+ au!
+ au WinEnter * let g:info = getwininfo(win_getid())[0]
+ augroup END
+
+ 4split
+ " Check that calling getwininfo() from WinEnter returns fresh values for
+ " topline and botline.
+ call assert_equal(1, g:info.topline)
+ call assert_equal(4, g:info.botline)
+ close
+
+ unlet g:info
+ augroup! T1
+ 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 76a2620be0..a1e53df774 100644
--- a/src/nvim/testdir/test_cd.vim
+++ b/src/nvim/testdir/test_cd.vim
@@ -44,6 +44,15 @@ func Test_cd_minus()
cd -
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_equal(path, getcwd())
+ cd -
+ call assert_equal(path_dotdot, getcwd())
+ cd -
+
" Test for :cd - without a previous directory
let lines =<< trim [SCRIPT]
call assert_fails('cd -', 'E186:')
@@ -216,6 +225,21 @@ func Test_cd_from_non_existing_dir()
call assert_equal(saveddir, getcwd())
endfunc
+func Test_cd_completion()
+ call mkdir('XComplDir1', 'p')
+ call mkdir('XComplDir2', 'p')
+ call writefile([], 'XComplFile')
+
+ for cmd in ['cd', 'chdir', 'lcd', 'lchdir', 'tcd', 'tchdir']
+ call feedkeys(':' .. cmd .. " XCompl\<C-A>\<C-B>\"\<CR>", 'tx')
+ call assert_equal('"' .. cmd .. ' XComplDir1/ XComplDir2/', @:)
+ endfor
+
+ call delete('XComplDir1', 'd')
+ call delete('XComplDir2', 'd')
+ call delete('XComplFile')
+endfunc
+
func Test_cd_unknown_dir()
call mkdir('Xa')
cd Xa
diff --git a/src/nvim/testdir/test_cdo.vim b/src/nvim/testdir/test_cdo.vim
new file mode 100644
index 0000000000..dbed7df4ac
--- /dev/null
+++ b/src/nvim/testdir/test_cdo.vim
@@ -0,0 +1,216 @@
+" Tests for the :cdo, :cfdo, :ldo and :lfdo commands
+
+source check.vim
+CheckFeature quickfix
+
+" Create the files used by the tests
+func SetUp()
+ call writefile(["Line1", "Line2", "Line3"], 'Xtestfile1')
+ call writefile(["Line1", "Line2", "Line3"], 'Xtestfile2')
+ call writefile(["Line1", "Line2", "Line3"], 'Xtestfile3')
+endfunc
+
+" Remove the files used by the tests
+func TearDown()
+ call delete('Xtestfile1')
+ call delete('Xtestfile2')
+ call delete('Xtestfile3')
+endfunc
+
+" Returns the current line in '<filename> <linenum>L <column>C' format
+func GetRuler()
+ return expand('%') . ' ' . line('.') . 'L' . ' ' . col('.') . 'C'
+endfunc
+
+" Tests for the :cdo and :ldo commands
+func XdoTests(cchar)
+ enew
+
+ " Shortcuts for calling the cdo and ldo commands
+ let Xdo = a:cchar . 'do'
+ let Xgetexpr = a:cchar . 'getexpr'
+ let Xprev = a:cchar. 'prev'
+ let XdoCmd = Xdo . ' call add(l, GetRuler())'
+
+ " Try with an empty list
+ let l = []
+ exe XdoCmd
+ call assert_equal([], l)
+
+ " Populate the list and then try
+ exe Xgetexpr . " ['non-error 1', 'Xtestfile1:1:3:Line1', 'non-error 2', 'Xtestfile2:2:2:Line2', 'non-error 3', 'Xtestfile3:3:1:Line3']"
+
+ let l = []
+ exe XdoCmd
+ call assert_equal(['Xtestfile1 1L 3C', 'Xtestfile2 2L 2C', 'Xtestfile3 3L 1C'], l)
+
+ " Run command only on selected error lines
+ let l = []
+ enew
+ exe "2,3" . XdoCmd
+ call assert_equal(['Xtestfile2 2L 2C', 'Xtestfile3 3L 1C'], l)
+
+ " Boundary condition tests
+ let l = []
+ enew
+ exe "1,1" . XdoCmd
+ call assert_equal(['Xtestfile1 1L 3C'], l)
+
+ let l = []
+ enew
+ exe "3" . XdoCmd
+ call assert_equal(['Xtestfile3 3L 1C'], l)
+
+ " Range test commands
+ let l = []
+ enew
+ exe "%" . XdoCmd
+ call assert_equal(['Xtestfile1 1L 3C', 'Xtestfile2 2L 2C', 'Xtestfile3 3L 1C'], l)
+
+ let l = []
+ enew
+ exe "1,$" . XdoCmd
+ call assert_equal(['Xtestfile1 1L 3C', 'Xtestfile2 2L 2C', 'Xtestfile3 3L 1C'], l)
+
+ let l = []
+ enew
+ exe Xprev
+ exe "." . XdoCmd
+ call assert_equal(['Xtestfile2 2L 2C'], l)
+
+ let l = []
+ enew
+ exe "+" . XdoCmd
+ call assert_equal(['Xtestfile3 3L 1C'], l)
+
+ " Invalid error lines test
+ let l = []
+ enew
+ exe "silent! 27" . XdoCmd
+ exe "silent! 4,5" . XdoCmd
+ call assert_equal([], l)
+
+ " Run commands from an unsaved buffer
+ let v:errmsg=''
+ let l = []
+ enew
+ setlocal modified
+ exe "silent! 2,2" . XdoCmd
+ if v:errmsg !~# 'No write since last change'
+ call add(v:errors, 'Unsaved file change test failed')
+ endif
+
+ " If the executed command fails, then the operation should be aborted
+ enew!
+ let subst_count = 0
+ exe "silent!" . Xdo . " s/Line/xLine/ | let subst_count += 1"
+ if subst_count != 1 || getline('.') != 'xLine1'
+ call add(v:errors, 'Abort command on error test failed')
+ endif
+
+ let l = []
+ exe "2,2" . Xdo . "! call add(l, GetRuler())"
+ call assert_equal(['Xtestfile2 2L 2C'], l)
+
+ " List with no valid error entries
+ let l = []
+ edit! +2 Xtestfile1
+ exe Xgetexpr . " ['non-error 1', 'non-error 2', 'non-error 3']"
+ exe XdoCmd
+ call assert_equal([], l)
+ exe "silent! 2" . XdoCmd
+ call assert_equal([], l)
+ let v:errmsg=''
+ exe "%" . XdoCmd
+ exe "1,$" . XdoCmd
+ exe "." . XdoCmd
+ call assert_equal('', v:errmsg)
+
+ " List with only one valid entry
+ let l = []
+ exe Xgetexpr . " ['Xtestfile3:3:1:Line3']"
+ exe XdoCmd
+ call assert_equal(['Xtestfile3 3L 1C'], l)
+
+endfunc
+
+" Tests for the :cfdo and :lfdo commands
+func XfdoTests(cchar)
+ enew
+
+ " Shortcuts for calling the cfdo and lfdo commands
+ let Xfdo = a:cchar . 'fdo'
+ let Xgetexpr = a:cchar . 'getexpr'
+ let XfdoCmd = Xfdo . ' call add(l, GetRuler())'
+ let Xpfile = a:cchar. 'pfile'
+
+ " Clear the quickfix/location list
+ exe Xgetexpr . " []"
+
+ " Try with an empty list
+ let l = []
+ exe XfdoCmd
+ call assert_equal([], l)
+
+ " Populate the list and then try
+ exe Xgetexpr . " ['non-error 1', 'Xtestfile1:1:3:Line1', 'Xtestfile1:2:1:Line2', 'non-error 2', 'Xtestfile2:2:2:Line2', 'non-error 3', 'Xtestfile3:2:3:Line2', 'Xtestfile3:3:1:Line3']"
+
+ let l = []
+ exe XfdoCmd
+ call assert_equal(['Xtestfile1 1L 3C', 'Xtestfile2 2L 2C', 'Xtestfile3 2L 3C'], l)
+
+ " Run command only on selected error lines
+ let l = []
+ exe "2,3" . XfdoCmd
+ call assert_equal(['Xtestfile2 2L 2C', 'Xtestfile3 2L 3C'], l)
+
+ " Boundary condition tests
+ let l = []
+ exe "3" . XfdoCmd
+ call assert_equal(['Xtestfile3 2L 3C'], l)
+
+ " Range test commands
+ let l = []
+ exe "%" . XfdoCmd
+ call assert_equal(['Xtestfile1 1L 3C', 'Xtestfile2 2L 2C', 'Xtestfile3 2L 3C'], l)
+
+ let l = []
+ exe "1,$" . XfdoCmd
+ call assert_equal(['Xtestfile1 1L 3C', 'Xtestfile2 2L 2C', 'Xtestfile3 2L 3C'], l)
+
+ let l = []
+ exe Xpfile
+ exe "." . XfdoCmd
+ call assert_equal(['Xtestfile2 2L 2C'], l)
+
+ " List with only one valid entry
+ let l = []
+ exe Xgetexpr . " ['Xtestfile2:2:5:Line2']"
+ exe XfdoCmd
+ call assert_equal(['Xtestfile2 2L 5C'], l)
+
+endfunc
+
+" Tests for cdo and cfdo
+func Test_cdo()
+ call XdoTests('c')
+ call XfdoTests('c')
+endfunc
+
+" Tests for ldo and lfdo
+func Test_ldo()
+ call XdoTests('l')
+ call XfdoTests('l')
+endfunc
+
+" Test for making 'shm' doesn't interfere with the output.
+func Test_cdo_print()
+ enew | only!
+ cgetexpr ["Xtestfile1:1:Line1", "Xtestfile2:1:Line1", "Xtestfile3:1:Line1"]
+ cdo print
+ call assert_equal('Line1', Screenline(&lines))
+ call assert_equal('Line1', Screenline(&lines - 3))
+ call assert_equal('Line1', Screenline(&lines - 6))
+endfunc
+
+" vim: shiftwidth=2 sts=2 expandtab
diff --git a/src/nvim/testdir/test_changelist.vim b/src/nvim/testdir/test_changelist.vim
index ce77c1f3c7..3741f32e69 100644
--- a/src/nvim/testdir/test_changelist.vim
+++ b/src/nvim/testdir/test_changelist.vim
@@ -46,3 +46,5 @@ func Test_getchangelist()
call delete('Xfile1.txt')
call delete('Xfile2.txt')
endfunc
+
+" vim: shiftwidth=2 sts=2 expandtab
diff --git a/src/nvim/testdir/test_charsearch.vim b/src/nvim/testdir/test_charsearch.vim
index 6f09e85a42..d386d74f8d 100644
--- a/src/nvim/testdir/test_charsearch.vim
+++ b/src/nvim/testdir/test_charsearch.vim
@@ -1,3 +1,4 @@
+" Test for character search commands - t, T, f, F, ; and ,
func Test_charsearch()
enew!
@@ -28,6 +29,17 @@ func Test_charsearch()
set cpo-=;
normal! ;;p
call assert_equal('ZabcdeZfghijkZZemnokqretkZvwxyz', getline(3))
+
+ " check that repeating a search before and after a line fails
+ normal 3Gfv
+ call assert_beeps('normal ;')
+ call assert_beeps('normal ,')
+
+ " clear the character search
+ call setcharsearch({'char' : ''})
+ call assert_equal('', getcharsearch().char)
+
+ call assert_fails("call setcharsearch([])", 'E715:')
enew!
endfunc
@@ -60,3 +72,30 @@ func Test_search_cmds()
call assert_equal('ddd yee y', getline(6))
enew!
endfunc
+
+" Test for character search in virtual edit mode with <Tab>
+func Test_csearch_virtualedit()
+ new
+ set virtualedit=all
+ call setline(1, "a\tb")
+ normal! tb
+ call assert_equal([0, 1, 2, 6], getpos('.'))
+ set virtualedit&
+ close!
+endfunc
+
+" Test for character search failure in latin1 encoding
+func Test_charsearch_latin1()
+ new
+ let save_enc = &encoding
+ " set encoding=latin1
+ call setline(1, 'abcdefghijk')
+ call assert_beeps('normal fz')
+ call assert_beeps('normal tx')
+ call assert_beeps('normal $Fz')
+ call assert_beeps('normal $Tx')
+ let &encoding = save_enc
+ close!
+endfunc
+
+" vim: shiftwidth=2 sts=2 expandtab
diff --git a/src/nvim/testdir/test_charsearch_utf8.vim b/src/nvim/testdir/test_charsearch_utf8.vim
index 09341a90b0..82a807ac5b 100644
--- a/src/nvim/testdir/test_charsearch_utf8.vim
+++ b/src/nvim/testdir/test_charsearch_utf8.vim
@@ -1,7 +1,7 @@
" Tests for related f{char} and t{char} using utf-8.
" Test for t,f,F,T movement commands
-function! Test_search_cmds()
+func Test_search_cmds()
new!
call setline(1, "・最初から最後まで最強のVimは最高")
1
diff --git a/src/nvim/testdir/test_cindent.vim b/src/nvim/testdir/test_cindent.vim
index 562867f548..ccc8168c09 100644
--- a/src/nvim/testdir/test_cindent.vim
+++ b/src/nvim/testdir/test_cindent.vim
@@ -1,6 +1,5 @@
" Test for cinoptions and cindent
"
-" TODO: rewrite test3.in into this new style test
func Test_cino_hash()
" Test that curbuf->b_ind_hash_comment is correctly reset
@@ -128,15 +127,5249 @@ func Test_cindent_func()
bwipe!
endfunc
+func Test_cindent_1()
+ new
+ setl cindent ts=4 sw=4
+ setl cino& sts&
+
+ let code =<< trim [CODE]
+ /* start of AUTO matically checked vim: set ts=4 : */
+ {
+ if (test)
+ cmd1;
+ cmd2;
+ }
+
+ {
+ if (test)
+ cmd1;
+ else
+ cmd2;
+ }
+
+ {
+ if (test)
+ {
+ cmd1;
+ cmd2;
+ }
+ }
+
+ {
+ if (test)
+ {
+ cmd1;
+ else
+ }
+ }
+
+ {
+ while (this)
+ if (test)
+ cmd1;
+ cmd2;
+ }
+
+ {
+ while (this)
+ if (test)
+ cmd1;
+ else
+ cmd2;
+ }
+
+ {
+ if (test)
+ {
+ cmd;
+ }
+
+ if (test)
+ cmd;
+ }
+
+ {
+ if (test) {
+ cmd;
+ }
+
+ if (test) cmd;
+ }
+
+ {
+ cmd1;
+ for (blah)
+ while (this)
+ if (test)
+ cmd2;
+ cmd3;
+ }
+
+ {
+ cmd1;
+ for (blah)
+ while (this)
+ if (test)
+ cmd2;
+ cmd3;
+
+ if (test)
+ {
+ cmd1;
+ cmd2;
+ cmd3;
+ }
+ }
+
+
+ /* Test for 'cindent' do/while mixed with if/else: */
+
+ {
+ do
+ if (asdf)
+ asdfasd;
+ while (cond);
+
+ do
+ if (asdf)
+ while (asdf)
+ asdf;
+ while (asdf);
+ }
+
+ /* Test for 'cindent' with two ) on a continuation line */
+ {
+ if (asdfasdf;asldkfj asdlkfj as;ldkfj sal;d
+ aal;sdkjf ( ;asldfkja;sldfk
+ al;sdjfka ;slkdf ) sa;ldkjfsa dlk;)
+ line up here;
+ }
+
+
+ /* C++ tests: */
+
+ // foo() these three lines should remain in column 0
+ // {
+ // }
+
+ /* Test for continuation and unterminated lines: */
+ {
+ i = 99 + 14325 +
+ 21345 +
+ 21345 +
+ 21345 + ( 21345 +
+ 21345) +
+ 2345 +
+ 1234;
+ c = 1;
+ }
+
+ /*
+ testje for indent with empty line
+
+ here */
+
+ {
+ if (testing &&
+ not a joke ||
+ line up here)
+ hay;
+ if (testing &&
+ (not a joke || testing
+ )line up here)
+ hay;
+ if (testing &&
+ (not a joke || testing
+ line up here))
+ hay;
+ }
+
+
+ {
+ switch (c)
+ {
+ case xx:
+ do
+ if (asdf)
+ do
+ asdfasdf;
+ while (asdf);
+ else
+ asdfasdf;
+ while (cond);
+ case yy:
+ case xx:
+ case zz:
+ testing;
+ }
+ }
+
+ {
+ if (cond) {
+ foo;
+ }
+ else
+ {
+ bar;
+ }
+ }
+
+ {
+ if (alskdfj ;alsdkfjal;skdjf (;sadlkfsa ;dlkf j;alksdfj ;alskdjf
+ alsdkfj (asldk;fj
+ awith cino=(0 ;lf this one goes to below the paren with ==
+ ;laksjfd ;lsakdjf ;alskdf asd)
+ asdfasdf;)))
+ asdfasdf;
+ }
+
+ int
+ func(a, b)
+ int a;
+ int c;
+ {
+ if (c1 && (c2 ||
+ c3))
+ foo;
+ if (c1 &&
+ (c2 || c3)
+ )
+ }
+
+ {
+ while (asd)
+ {
+ if (asdf)
+ if (test)
+ if (that)
+ {
+ if (asdf)
+ do
+ cdasd;
+ while (as
+ df);
+ }
+ else
+ if (asdf)
+ asdf;
+ else
+ asdf;
+ asdf;
+ }
+ }
+
+ {
+ s = "/*"; b = ';'
+ s = "/*"; b = ';';
+ a = b;
+ }
+
+ {
+ switch (a)
+ {
+ case a:
+ switch (t)
+ {
+ case 1:
+ cmd;
+ break;
+ case 2:
+ cmd;
+ break;
+ }
+ cmd;
+ break;
+ case b:
+ {
+ int i;
+ cmd;
+ }
+ break;
+ case c: {
+ int i;
+ cmd;
+ }
+ case d: if (cond &&
+ test) { /* this line doesn't work right */
+ int i;
+ cmd;
+ }
+ break;
+ }
+ }
+
+ {
+ if (!(vim_strchr(p_cpo, CPO_BUFOPTGLOB) != NULL && entering) &&
+ (bp_to->b_p_initialized ||
+ (!entering && vim_strchr(p_cpo, CPO_BUFOPT) != NULL)))
+ return;
+ label :
+ asdf = asdf ?
+ asdf : asdf;
+ asdf = asdf ?
+ asdf: asdf;
+ }
+
+ /* Special Comments : This function has the added complexity (compared */
+ /* : to addtolist) of having to check for a detail */
+ /* : texture and add that to the list first. */
+
+ char *(array[100]) = {
+ "testje",
+ "foo",
+ "bar",
+ }
+
+ enum soppie
+ {
+ yes = 0,
+ no,
+ maybe
+ };
+
+ typedef enum soppie
+ {
+ yes = 0,
+ no,
+ maybe
+ };
+
+ static enum
+ {
+ yes = 0,
+ no,
+ maybe
+ } soppie;
+
+ public static enum
+ {
+ yes = 0,
+ no,
+ maybe
+ } soppie;
+
+ static private enum
+ {
+ yes = 0,
+ no,
+ maybe
+ } soppie;
+
+ {
+ int a,
+ b;
+ }
+
+ {
+ struct Type
+ {
+ int i;
+ char *str;
+ } var[] =
+ {
+ 0, "zero",
+ 1, "one",
+ 2, "two",
+ 3, "three"
+ };
+
+ float matrix[3][3] =
+ {
+ {
+ 0,
+ 1,
+ 2
+ },
+ {
+ 3,
+ 4,
+ 5
+ },
+ {
+ 6,
+ 7,
+ 8
+ }
+ };
+ }
+
+ {
+ /* blah ( blah */
+ /* where does this go? */
+
+ /* blah ( blah */
+ cmd;
+
+ func(arg1,
+ /* comment */
+ arg2);
+ a;
+ {
+ b;
+ {
+ c; /* Hey, NOW it indents?! */
+ }
+ }
+
+ {
+ func(arg1,
+ arg2,
+ arg3);
+ /* Hey, what am I doing here? Is this coz of the ","? */
+ }
+ }
+
+ main ()
+ {
+ if (cond)
+ {
+ a = b;
+ }
+ if (cond) {
+ a = c;
+ }
+ if (cond)
+ a = d;
+ return;
+ }
+
+ {
+ case 2: if (asdf &&
+ asdfasdf)
+ aasdf;
+ a = 9;
+ case 3: if (asdf)
+ aasdf;
+ a = 9;
+ case 4: x = 1;
+ y = 2;
+
+ label: if (asdf)
+ here;
+
+ label: if (asdf &&
+ asdfasdf)
+ {
+ }
+
+ label: if (asdf &&
+ asdfasdf) {
+ there;
+ }
+
+ label: if (asdf &&
+ asdfasdf)
+ there;
+ }
+
+ {
+ /*
+ hello with ":set comments= cino=c5"
+ */
+
+ /*
+ hello with ":set comments= cino="
+ */
+ }
+
+
+ {
+ if (a < b) {
+ a = a + 1;
+ } else
+ a = a + 2;
+
+ if (a)
+ do {
+ testing;
+ } while (asdfasdf);
+ a = b + 1;
+ asdfasdf
+ }
+
+ {
+ for ( int i = 0;
+ i < 10; i++ )
+ {
+ }
+ i = 0;
+ }
+
+ class bob
+ {
+ int foo() {return 1;}
+ int bar;
+ }
+
+ main()
+ {
+ while(1)
+ if (foo)
+ {
+ bar;
+ }
+ else {
+ asdf;
+ }
+ misplacedline;
+ }
+
+ {
+ if (clipboard.state == SELECT_DONE
+ && ((row == clipboard.start.lnum
+ && col >= clipboard.start.col)
+ || row > clipboard.start.lnum))
+ }
+
+ {
+ if (1) {i += 4;}
+ where_am_i;
+ return 0;
+ }
+
+ {
+ {
+ } // sdf(asdf
+ if (asdf)
+ asd;
+ }
+
+ {
+ label1:
+ label2:
+ }
+
+ {
+ int fooRet = foo(pBar1, false /*fKB*/,
+ true /*fPTB*/, 3 /*nT*/, false /*fDF*/);
+ f() {
+ for ( i = 0;
+ i < m;
+ /* c */ i++ ) {
+ a = b;
+ }
+ }
+ }
+
+ {
+ f1(/*comment*/);
+ f2();
+ }
+
+ {
+ do {
+ if (foo) {
+ } else
+ ;
+ } while (foo);
+ foo(); // was wrong
+ }
+
+ int x; // no extra indent because of the ;
+ void func()
+ {
+ }
+
+ char *tab[] = {"aaa",
+ "};", /* }; */ NULL}
+ int indented;
+ {}
+
+ char *a[] = {"aaa", "bbb",
+ "ccc", NULL};
+ // here
+
+ char *tab[] = {"aaa",
+ "xx", /* xx */}; /* asdf */
+ int not_indented;
+
+ {
+ do {
+ switch (bla)
+ {
+ case 1: if (foo)
+ bar;
+ }
+ } while (boo);
+ wrong;
+ }
+
+ int foo,
+ bar;
+ int foo;
+
+ #if defined(foo) \
+ && defined(bar)
+ char * xx = "asdf\
+ foo\
+ bor";
+ int x;
+
+ char *foo = "asdf\
+ asdf\
+ asdf",
+ *bar;
+
+ void f()
+ {
+ #if defined(foo) \
+ && defined(bar)
+ char *foo = "asdf\
+ asdf\
+ asdf",
+ *bar;
+ {
+ int i;
+ char *foo = "asdf\
+ asdf\
+ asdf",
+ *bar;
+ }
+ #endif
+ }
+ #endif
+
+ int y; // comment
+ // comment
+
+ // comment
+
+ {
+ Constructor(int a,
+ int b ) : BaseClass(a)
+ {
+ }
+ }
+
+ void foo()
+ {
+ char one,
+ two;
+ struct bla piet,
+ jan;
+ enum foo kees,
+ jannie;
+ static unsigned sdf,
+ krap;
+ unsigned int piet,
+ jan;
+ int
+ kees,
+ jan;
+ }
+
+ {
+ t(int f,
+ int d); // )
+ d();
+ }
+
+ Constructor::Constructor(int a,
+ int b
+ ) :
+ BaseClass(a,
+ b,
+ c),
+ mMember(b),
+ {
+ }
+
+ Constructor::Constructor(int a,
+ int b ) :
+ BaseClass(a)
+ {
+ }
+
+ Constructor::Constructor(int a,
+ int b ) /*x*/ : /*x*/ BaseClass(a),
+ member(b)
+ {
+ }
+
+ A::A(int a, int b)
+ : aa(a),
+ bb(b),
+ cc(c)
+ {
+ }
+
+ class CAbc :
+ public BaseClass1,
+ protected BaseClass2
+ {
+ int Test() { return FALSE; }
+ int Test1() { return TRUE; }
+
+ CAbc(int a, int b ) :
+ BaseClass(a)
+ {
+ switch(xxx)
+ {
+ case abc:
+ asdf();
+ break;
+
+ case 999:
+ baer();
+ break;
+ }
+ }
+
+ public: // <-- this was incorrectly indented before!!
+ void testfall();
+ protected:
+ void testfall();
+ };
+
+ class CAbc : public BaseClass1,
+ protected BaseClass2
+ {
+ };
+
+ static struct
+ {
+ int a;
+ int b;
+ } variable[COUNT] =
+ {
+ {
+ 123,
+ 456
+ },
+ {
+ 123,
+ 456
+ }
+ };
+
+ static struct
+ {
+ int a;
+ int b;
+ } variable[COUNT] =
+ {
+ { 123, 456 },
+ { 123, 456 }
+ };
+
+ void asdf() /* ind_maxparen may cause trouble here */
+ {
+ if ((0
+ && 1
+ && 1
+ && 1
+ && 1
+ && 1
+ && 1
+ && 1
+ && 1
+ && 1
+ && 1
+ && 1
+ && 1
+ && 1
+ && 1
+ && 1
+ && 1
+ && 1
+ && 1
+ && 1
+ && 1
+ && 1
+ && 1
+ && 1
+ && 1
+ && 1)) break;
+ }
+
+ foo()
+ {
+ a = cond ? foo() : asdf
+ + asdf;
+
+ a = cond ?
+ foo() : asdf
+ + asdf;
+ }
+
+ int main(void)
+ {
+ if (a)
+ if (b)
+ 2;
+ else 3;
+ next_line_of_code();
+ }
+
+ barry()
+ {
+ Foo::Foo (int one,
+ int two)
+ : something(4)
+ {}
+ }
+
+ barry()
+ {
+ Foo::Foo (int one, int two)
+ : something(4)
+ {}
+ }
+
+ Constructor::Constructor(int a,
+ int b
+ ) :
+ BaseClass(a,
+ b,
+ c),
+ mMember(b)
+ {
+ }
+ int main ()
+ {
+ if (lala)
+ do
+ ++(*lolo);
+ while (lili
+ && lele);
+ lulu;
+ }
+
+ int main ()
+ {
+ switch (c)
+ {
+ case 'c': if (cond)
+ {
+ }
+ }
+ }
+
+ main()
+ {
+ (void) MyFancyFuasdfadsfnction(
+ argument);
+ }
+
+ main()
+ {
+ char foo[] = "/*";
+ /* as
+ df */
+ hello
+ }
+
+ /* valid namespaces with normal indent */
+ namespace
+ {
+ {
+ 111111111111;
+ }
+ }
+ namespace /* test */
+ {
+ 11111111111111111;
+ }
+ namespace // test
+ {
+ 111111111111111111;
+ }
+ namespace
+ {
+ 111111111111111111;
+ }
+ namespace test
+ {
+ 111111111111111111;
+ }
+ namespace{
+ 111111111111111111;
+ }
+ namespace test{
+ 111111111111111111;
+ }
+ namespace {
+ 111111111111111111;
+ }
+ namespace test {
+ 111111111111111111;
+ namespace test2 {
+ 22222222222222222;
+ }
+ }
+ inline namespace {
+ 111111111111111111;
+ }
+ inline /* test */ namespace {
+ 111111111111111111;
+ }
+ inline/* test */namespace {
+ 111111111111111111;
+ }
+
+ /* invalid namespaces use block indent */
+ namespace test test2 {
+ 111111111111111111111;
+ }
+ namespace11111111111 {
+ 111111111111;
+ }
+ namespace() {
+ 1111111111111;
+ }
+ namespace()
+ {
+ 111111111111111111;
+ }
+ namespace test test2
+ {
+ 1111111111111111111;
+ }
+ namespace111111111
+ {
+ 111111111111111111;
+ }
+ inlinenamespace {
+ 111111111111111111;
+ }
+
+ void getstring() {
+ /* Raw strings */
+ const char* s = R"(
+ test {
+ # comment
+ field: 123
+ }
+ )";
+ }
+
+ void getstring() {
+ const char* s = R"foo(
+ test {
+ # comment
+ field: 123
+ }
+ )foo";
+ }
+
+ {
+ int a[4] = {
+ [0] = 0,
+ [1] = 1,
+ [2] = 2,
+ [3] = 3,
+ };
+ }
+
+ {
+ a = b[2]
+ + 3;
+ }
+
+ {
+ if (1)
+ /* aaaaa
+ * bbbbb
+ */
+ a = 1;
+ }
+
+ void func()
+ {
+ switch (foo)
+ {
+ case (bar):
+ if (baz())
+ quux();
+ break;
+ case (shmoo):
+ if (!bar)
+ {
+ }
+ case (foo1):
+ switch (bar)
+ {
+ case baz:
+ baz_f();
+ break;
+ }
+ break;
+ default:
+ baz();
+ baz();
+ break;
+ }
+ }
+
+ /* end of AUTO */
+ [CODE]
+
+ call append(0, code)
+ normal gg
+ call search('start of AUTO')
+ exe "normal =/end of AUTO\<CR>"
+
+ let expected =<< trim [CODE]
+ /* start of AUTO matically checked vim: set ts=4 : */
+ {
+ if (test)
+ cmd1;
+ cmd2;
+ }
+
+ {
+ if (test)
+ cmd1;
+ else
+ cmd2;
+ }
+
+ {
+ if (test)
+ {
+ cmd1;
+ cmd2;
+ }
+ }
+
+ {
+ if (test)
+ {
+ cmd1;
+ else
+ }
+ }
+
+ {
+ while (this)
+ if (test)
+ cmd1;
+ cmd2;
+ }
+
+ {
+ while (this)
+ if (test)
+ cmd1;
+ else
+ cmd2;
+ }
+
+ {
+ if (test)
+ {
+ cmd;
+ }
+
+ if (test)
+ cmd;
+ }
+
+ {
+ if (test) {
+ cmd;
+ }
+
+ if (test) cmd;
+ }
+
+ {
+ cmd1;
+ for (blah)
+ while (this)
+ if (test)
+ cmd2;
+ cmd3;
+ }
+
+ {
+ cmd1;
+ for (blah)
+ while (this)
+ if (test)
+ cmd2;
+ cmd3;
+
+ if (test)
+ {
+ cmd1;
+ cmd2;
+ cmd3;
+ }
+ }
+
+
+ /* Test for 'cindent' do/while mixed with if/else: */
+
+ {
+ do
+ if (asdf)
+ asdfasd;
+ while (cond);
+
+ do
+ if (asdf)
+ while (asdf)
+ asdf;
+ while (asdf);
+ }
+
+ /* Test for 'cindent' with two ) on a continuation line */
+ {
+ if (asdfasdf;asldkfj asdlkfj as;ldkfj sal;d
+ aal;sdkjf ( ;asldfkja;sldfk
+ al;sdjfka ;slkdf ) sa;ldkjfsa dlk;)
+ line up here;
+ }
+
+
+ /* C++ tests: */
+
+ // foo() these three lines should remain in column 0
+ // {
+ // }
+
+ /* Test for continuation and unterminated lines: */
+ {
+ i = 99 + 14325 +
+ 21345 +
+ 21345 +
+ 21345 + ( 21345 +
+ 21345) +
+ 2345 +
+ 1234;
+ c = 1;
+ }
+
+ /*
+ testje for indent with empty line
+
+ here */
+
+ {
+ if (testing &&
+ not a joke ||
+ line up here)
+ hay;
+ if (testing &&
+ (not a joke || testing
+ )line up here)
+ hay;
+ if (testing &&
+ (not a joke || testing
+ line up here))
+ hay;
+ }
+
+
+ {
+ switch (c)
+ {
+ case xx:
+ do
+ if (asdf)
+ do
+ asdfasdf;
+ while (asdf);
+ else
+ asdfasdf;
+ while (cond);
+ case yy:
+ case xx:
+ case zz:
+ testing;
+ }
+ }
+
+ {
+ if (cond) {
+ foo;
+ }
+ else
+ {
+ bar;
+ }
+ }
+
+ {
+ if (alskdfj ;alsdkfjal;skdjf (;sadlkfsa ;dlkf j;alksdfj ;alskdjf
+ alsdkfj (asldk;fj
+ awith cino=(0 ;lf this one goes to below the paren with ==
+ ;laksjfd ;lsakdjf ;alskdf asd)
+ asdfasdf;)))
+ asdfasdf;
+ }
+
+ int
+ func(a, b)
+ int a;
+ int c;
+ {
+ if (c1 && (c2 ||
+ c3))
+ foo;
+ if (c1 &&
+ (c2 || c3)
+ )
+ }
+
+ {
+ while (asd)
+ {
+ if (asdf)
+ if (test)
+ if (that)
+ {
+ if (asdf)
+ do
+ cdasd;
+ while (as
+ df);
+ }
+ else
+ if (asdf)
+ asdf;
+ else
+ asdf;
+ asdf;
+ }
+ }
+
+ {
+ s = "/*"; b = ';'
+ s = "/*"; b = ';';
+ a = b;
+ }
+
+ {
+ switch (a)
+ {
+ case a:
+ switch (t)
+ {
+ case 1:
+ cmd;
+ break;
+ case 2:
+ cmd;
+ break;
+ }
+ cmd;
+ break;
+ case b:
+ {
+ int i;
+ cmd;
+ }
+ break;
+ case c: {
+ int i;
+ cmd;
+ }
+ case d: if (cond &&
+ test) { /* this line doesn't work right */
+ int i;
+ cmd;
+ }
+ break;
+ }
+ }
+
+ {
+ if (!(vim_strchr(p_cpo, CPO_BUFOPTGLOB) != NULL && entering) &&
+ (bp_to->b_p_initialized ||
+ (!entering && vim_strchr(p_cpo, CPO_BUFOPT) != NULL)))
+ return;
+ label :
+ asdf = asdf ?
+ asdf : asdf;
+ asdf = asdf ?
+ asdf: asdf;
+ }
+
+ /* Special Comments : This function has the added complexity (compared */
+ /* : to addtolist) of having to check for a detail */
+ /* : texture and add that to the list first. */
+
+ char *(array[100]) = {
+ "testje",
+ "foo",
+ "bar",
+ }
+
+ enum soppie
+ {
+ yes = 0,
+ no,
+ maybe
+ };
+
+ typedef enum soppie
+ {
+ yes = 0,
+ no,
+ maybe
+ };
+
+ static enum
+ {
+ yes = 0,
+ no,
+ maybe
+ } soppie;
+
+ public static enum
+ {
+ yes = 0,
+ no,
+ maybe
+ } soppie;
+
+ static private enum
+ {
+ yes = 0,
+ no,
+ maybe
+ } soppie;
+
+ {
+ int a,
+ b;
+ }
+
+ {
+ struct Type
+ {
+ int i;
+ char *str;
+ } var[] =
+ {
+ 0, "zero",
+ 1, "one",
+ 2, "two",
+ 3, "three"
+ };
+
+ float matrix[3][3] =
+ {
+ {
+ 0,
+ 1,
+ 2
+ },
+ {
+ 3,
+ 4,
+ 5
+ },
+ {
+ 6,
+ 7,
+ 8
+ }
+ };
+ }
+
+ {
+ /* blah ( blah */
+ /* where does this go? */
+
+ /* blah ( blah */
+ cmd;
+
+ func(arg1,
+ /* comment */
+ arg2);
+ a;
+ {
+ b;
+ {
+ c; /* Hey, NOW it indents?! */
+ }
+ }
+
+ {
+ func(arg1,
+ arg2,
+ arg3);
+ /* Hey, what am I doing here? Is this coz of the ","? */
+ }
+ }
+
+ main ()
+ {
+ if (cond)
+ {
+ a = b;
+ }
+ if (cond) {
+ a = c;
+ }
+ if (cond)
+ a = d;
+ return;
+ }
+
+ {
+ case 2: if (asdf &&
+ asdfasdf)
+ aasdf;
+ a = 9;
+ case 3: if (asdf)
+ aasdf;
+ a = 9;
+ case 4: x = 1;
+ y = 2;
+
+ label: if (asdf)
+ here;
+
+ label: if (asdf &&
+ asdfasdf)
+ {
+ }
+
+ label: if (asdf &&
+ asdfasdf) {
+ there;
+ }
+
+ label: if (asdf &&
+ asdfasdf)
+ there;
+ }
+
+ {
+ /*
+ hello with ":set comments= cino=c5"
+ */
+
+ /*
+ hello with ":set comments= cino="
+ */
+ }
+
+
+ {
+ if (a < b) {
+ a = a + 1;
+ } else
+ a = a + 2;
+
+ if (a)
+ do {
+ testing;
+ } while (asdfasdf);
+ a = b + 1;
+ asdfasdf
+ }
+
+ {
+ for ( int i = 0;
+ i < 10; i++ )
+ {
+ }
+ i = 0;
+ }
+
+ class bob
+ {
+ int foo() {return 1;}
+ int bar;
+ }
+
+ main()
+ {
+ while(1)
+ if (foo)
+ {
+ bar;
+ }
+ else {
+ asdf;
+ }
+ misplacedline;
+ }
+
+ {
+ if (clipboard.state == SELECT_DONE
+ && ((row == clipboard.start.lnum
+ && col >= clipboard.start.col)
+ || row > clipboard.start.lnum))
+ }
+
+ {
+ if (1) {i += 4;}
+ where_am_i;
+ return 0;
+ }
+
+ {
+ {
+ } // sdf(asdf
+ if (asdf)
+ asd;
+ }
+
+ {
+ label1:
+ label2:
+ }
+
+ {
+ int fooRet = foo(pBar1, false /*fKB*/,
+ true /*fPTB*/, 3 /*nT*/, false /*fDF*/);
+ f() {
+ for ( i = 0;
+ i < m;
+ /* c */ i++ ) {
+ a = b;
+ }
+ }
+ }
+
+ {
+ f1(/*comment*/);
+ f2();
+ }
+
+ {
+ do {
+ if (foo) {
+ } else
+ ;
+ } while (foo);
+ foo(); // was wrong
+ }
+
+ int x; // no extra indent because of the ;
+ void func()
+ {
+ }
+
+ char *tab[] = {"aaa",
+ "};", /* }; */ NULL}
+ int indented;
+ {}
+
+ char *a[] = {"aaa", "bbb",
+ "ccc", NULL};
+ // here
+
+ char *tab[] = {"aaa",
+ "xx", /* xx */}; /* asdf */
+ int not_indented;
+
+ {
+ do {
+ switch (bla)
+ {
+ case 1: if (foo)
+ bar;
+ }
+ } while (boo);
+ wrong;
+ }
+
+ int foo,
+ bar;
+ int foo;
+
+ #if defined(foo) \
+ && defined(bar)
+ char * xx = "asdf\
+ foo\
+ bor";
+ int x;
+
+ char *foo = "asdf\
+ asdf\
+ asdf",
+ *bar;
+
+ void f()
+ {
+ #if defined(foo) \
+ && defined(bar)
+ char *foo = "asdf\
+ asdf\
+ asdf",
+ *bar;
+ {
+ int i;
+ char *foo = "asdf\
+ asdf\
+ asdf",
+ *bar;
+ }
+ #endif
+ }
+ #endif
+
+ int y; // comment
+ // comment
+
+ // comment
+
+ {
+ Constructor(int a,
+ int b ) : BaseClass(a)
+ {
+ }
+ }
+
+ void foo()
+ {
+ char one,
+ two;
+ struct bla piet,
+ jan;
+ enum foo kees,
+ jannie;
+ static unsigned sdf,
+ krap;
+ unsigned int piet,
+ jan;
+ int
+ kees,
+ jan;
+ }
+
+ {
+ t(int f,
+ int d); // )
+ d();
+ }
+
+ Constructor::Constructor(int a,
+ int b
+ ) :
+ BaseClass(a,
+ b,
+ c),
+ mMember(b),
+ {
+ }
+
+ Constructor::Constructor(int a,
+ int b ) :
+ BaseClass(a)
+ {
+ }
+
+ Constructor::Constructor(int a,
+ int b ) /*x*/ : /*x*/ BaseClass(a),
+ member(b)
+ {
+ }
+
+ A::A(int a, int b)
+ : aa(a),
+ bb(b),
+ cc(c)
+ {
+ }
+
+ class CAbc :
+ public BaseClass1,
+ protected BaseClass2
+ {
+ int Test() { return FALSE; }
+ int Test1() { return TRUE; }
+
+ CAbc(int a, int b ) :
+ BaseClass(a)
+ {
+ switch(xxx)
+ {
+ case abc:
+ asdf();
+ break;
+
+ case 999:
+ baer();
+ break;
+ }
+ }
+
+ public: // <-- this was incorrectly indented before!!
+ void testfall();
+ protected:
+ void testfall();
+ };
+
+ class CAbc : public BaseClass1,
+ protected BaseClass2
+ {
+ };
+
+ static struct
+ {
+ int a;
+ int b;
+ } variable[COUNT] =
+ {
+ {
+ 123,
+ 456
+ },
+ {
+ 123,
+ 456
+ }
+ };
+
+ static struct
+ {
+ int a;
+ int b;
+ } variable[COUNT] =
+ {
+ { 123, 456 },
+ { 123, 456 }
+ };
+
+ void asdf() /* ind_maxparen may cause trouble here */
+ {
+ if ((0
+ && 1
+ && 1
+ && 1
+ && 1
+ && 1
+ && 1
+ && 1
+ && 1
+ && 1
+ && 1
+ && 1
+ && 1
+ && 1
+ && 1
+ && 1
+ && 1
+ && 1
+ && 1
+ && 1
+ && 1
+ && 1
+ && 1
+ && 1
+ && 1
+ && 1)) break;
+ }
+
+ foo()
+ {
+ a = cond ? foo() : asdf
+ + asdf;
+
+ a = cond ?
+ foo() : asdf
+ + asdf;
+ }
+
+ int main(void)
+ {
+ if (a)
+ if (b)
+ 2;
+ else 3;
+ next_line_of_code();
+ }
+
+ barry()
+ {
+ Foo::Foo (int one,
+ int two)
+ : something(4)
+ {}
+ }
+
+ barry()
+ {
+ Foo::Foo (int one, int two)
+ : something(4)
+ {}
+ }
+
+ Constructor::Constructor(int a,
+ int b
+ ) :
+ BaseClass(a,
+ b,
+ c),
+ mMember(b)
+ {
+ }
+ int main ()
+ {
+ if (lala)
+ do
+ ++(*lolo);
+ while (lili
+ && lele);
+ lulu;
+ }
+
+ int main ()
+ {
+ switch (c)
+ {
+ case 'c': if (cond)
+ {
+ }
+ }
+ }
+
+ main()
+ {
+ (void) MyFancyFuasdfadsfnction(
+ argument);
+ }
+
+ main()
+ {
+ char foo[] = "/*";
+ /* as
+ df */
+ hello
+ }
+
+ /* valid namespaces with normal indent */
+ namespace
+ {
+ {
+ 111111111111;
+ }
+ }
+ namespace /* test */
+ {
+ 11111111111111111;
+ }
+ namespace // test
+ {
+ 111111111111111111;
+ }
+ namespace
+ {
+ 111111111111111111;
+ }
+ namespace test
+ {
+ 111111111111111111;
+ }
+ namespace{
+ 111111111111111111;
+ }
+ namespace test{
+ 111111111111111111;
+ }
+ namespace {
+ 111111111111111111;
+ }
+ namespace test {
+ 111111111111111111;
+ namespace test2 {
+ 22222222222222222;
+ }
+ }
+ inline namespace {
+ 111111111111111111;
+ }
+ inline /* test */ namespace {
+ 111111111111111111;
+ }
+ inline/* test */namespace {
+ 111111111111111111;
+ }
+
+ /* invalid namespaces use block indent */
+ namespace test test2 {
+ 111111111111111111111;
+ }
+ namespace11111111111 {
+ 111111111111;
+ }
+ namespace() {
+ 1111111111111;
+ }
+ namespace()
+ {
+ 111111111111111111;
+ }
+ namespace test test2
+ {
+ 1111111111111111111;
+ }
+ namespace111111111
+ {
+ 111111111111111111;
+ }
+ inlinenamespace {
+ 111111111111111111;
+ }
+
+ void getstring() {
+ /* Raw strings */
+ const char* s = R"(
+ test {
+ # comment
+ field: 123
+ }
+ )";
+ }
+
+ void getstring() {
+ const char* s = R"foo(
+ test {
+ # comment
+ field: 123
+ }
+ )foo";
+ }
+
+ {
+ int a[4] = {
+ [0] = 0,
+ [1] = 1,
+ [2] = 2,
+ [3] = 3,
+ };
+ }
+
+ {
+ a = b[2]
+ + 3;
+ }
+
+ {
+ if (1)
+ /* aaaaa
+ * bbbbb
+ */
+ a = 1;
+ }
+
+ void func()
+ {
+ switch (foo)
+ {
+ case (bar):
+ if (baz())
+ quux();
+ break;
+ case (shmoo):
+ if (!bar)
+ {
+ }
+ case (foo1):
+ switch (bar)
+ {
+ case baz:
+ baz_f();
+ break;
+ }
+ break;
+ default:
+ baz();
+ baz();
+ break;
+ }
+ }
+
+ /* end of AUTO */
+
+ [CODE]
+
+ call assert_equal(expected, getline(1, '$'))
+ enew! | close
+endfunc
+
+func Test_cindent_2()
+ new
+ setl cindent ts=4 sw=4
+ setl tw=0 noai fo=croq
+ let &wm = &columns - 20
+
+ let code =<< trim [CODE]
+ {
+
+ /* this is
+ * a real serious important big
+ * comment
+ */
+ /* insert " about life, the universe, and the rest" after "serious" */
+ }
+ [CODE]
+
+ call append(0, code)
+ normal gg
+ call search('serious', 'e')
+ normal a about life, the universe, and the rest
+
+ let expected =<< trim [CODE]
+ {
+
+ /* this is
+ * a real serious
+ * about life, the
+ * universe, and the
+ * rest important big
+ * comment
+ */
+ /* insert " about life, the universe, and the rest" after "serious" */
+ }
+
+ [CODE]
+
+ call assert_equal(expected, getline(1, '$'))
+ set wm&
+ enew! | close
+endfunc
+
+func Test_cindent_3()
+ new
+ setl nocindent ts=4 sw=4
+
+ let code =<< trim [CODE]
+ {
+ /*
+ * Testing for comments, without 'cin' set
+ */
+
+ /*
+ * what happens here?
+ */
+
+ /*
+ the end of the comment, try inserting a line below */
+
+ /* how about
+ this one */
+ }
+ [CODE]
+
+ call append(0, code)
+ normal gg
+ call search('comments')
+ normal joabout life
+ call search('happens')
+ normal jothere
+ call search('below')
+ normal oline
+ call search('this')
+ normal Ohello
+
+ let expected =<< trim [CODE]
+ {
+ /*
+ * Testing for comments, without 'cin' set
+ */
+ about life
+
+ /*
+ * what happens here?
+ */
+ there
+
+ /*
+ the end of the comment, try inserting a line below */
+ line
+
+ /* how about
+ hello
+ this one */
+ }
+
+ [CODE]
+
+ call assert_equal(expected, getline(1, '$'))
+ enew! | close
+endfunc
+
+func Test_cindent_4()
+ new
+ setl cindent ts=4 sw=4
+
+ let code =<< trim [CODE]
+ {
+ var = this + that + vec[0] * vec[0]
+ + vec[1] * vec[1]
+ + vec2[2] * vec[2];
+ }
+ [CODE]
+
+ call append(0, code)
+ normal gg
+ call search('vec2')
+ normal ==
+
+ let expected =<< trim [CODE]
+ {
+ var = this + that + vec[0] * vec[0]
+ + vec[1] * vec[1]
+ + vec2[2] * vec[2];
+ }
+
+ [CODE]
+
+ call assert_equal(expected, getline(1, '$'))
+ enew! | close
+endfunc
+
+func Test_cindent_5()
+ new
+ setl cindent ts=4 sw=4
+ setl cino=}4
+
+ let code =<< trim [CODE]
+ {
+ asdf asdflkajds f;
+ if (tes & ting) {
+ asdf asdf asdf ;
+ asdfa sdf asdf;
+ }
+ testing1;
+ if (tes & ting)
+ {
+ asdf asdf asdf ;
+ asdfa sdf asdf;
+ }
+ testing2;
+ }
+ [CODE]
+
+ call append(0, code)
+ normal gg
+ call search('testing1')
+ exe "normal k2==/testing2\<CR>"
+ normal k2==
+
+ let expected =<< trim [CODE]
+ {
+ asdf asdflkajds f;
+ if (tes & ting) {
+ asdf asdf asdf ;
+ asdfa sdf asdf;
+ }
+ testing1;
+ if (tes & ting)
+ {
+ asdf asdf asdf ;
+ asdfa sdf asdf;
+ }
+ testing2;
+ }
+
+ [CODE]
+
+ call assert_equal(expected, getline(1, '$'))
+ enew! | close
+endfunc
+
+func Test_cindent_6()
+ new
+ setl cindent ts=4 sw=4
+ setl cino=(0,)20
+
+ let code =<< trim [CODE]
+ main ( int first_par, /*
+ * Comment for
+ * first par
+ */
+ int second_par /*
+ * Comment for
+ * second par
+ */
+ )
+ {
+ func( first_par, /*
+ * Comment for
+ * first par
+ */
+ second_par /*
+ * Comment for
+ * second par
+ */
+ );
+
+ }
+ [CODE]
+
+ call append(0, code)
+ normal gg
+ call search('main')
+ normal =][
+
+ let expected =<< trim [CODE]
+ main ( int first_par, /*
+ * Comment for
+ * first par
+ */
+ int second_par /*
+ * Comment for
+ * second par
+ */
+ )
+ {
+ func( first_par, /*
+ * Comment for
+ * first par
+ */
+ second_par /*
+ * Comment for
+ * second par
+ */
+ );
+
+ }
+
+ [CODE]
+
+ call assert_equal(expected, getline(1, '$'))
+ enew! | close
+endfunc
+
+func Test_cindent_7()
+ new
+ setl cindent ts=4 sw=4
+ setl cino=es,n0s
+
+ let code =<< trim [CODE]
+ main(void)
+ {
+ /* Make sure that cino=X0s is not parsed like cino=Xs. */
+ if (cond)
+ foo();
+ else
+ {
+ bar();
+ }
+ }
+ [CODE]
+
+ call append(0, code)
+ normal gg
+ call search('main')
+ normal =][
+
+ let expected =<< trim [CODE]
+ main(void)
+ {
+ /* Make sure that cino=X0s is not parsed like cino=Xs. */
+ if (cond)
+ foo();
+ else
+ {
+ bar();
+ }
+ }
+
+ [CODE]
+
+ call assert_equal(expected, getline(1, '$'))
+ enew! | close
+endfunc
+
+func Test_cindent_8()
+ new
+ setl cindent ts=4 sw=4
+ setl cino=
+
+ let code =<< trim [CODE]
+
+ {
+ do
+ {
+ if ()
+ {
+ if ()
+ asdf;
+ else
+ asdf;
+ }
+ } while ();
+ cmd; /* this should go under the } */
+ }
+ [CODE]
+
+ call append(0, code)
+ normal gg
+ normal ]]=][
+
+ let expected =<< trim [CODE]
+
+ {
+ do
+ {
+ if ()
+ {
+ if ()
+ asdf;
+ else
+ asdf;
+ }
+ } while ();
+ cmd; /* this should go under the } */
+ }
+
+ [CODE]
+
+ call assert_equal(expected, getline(1, '$'))
+ enew! | close
+endfunc
+
+func Test_cindent_9()
+ new
+ setl cindent ts=4 sw=4
+
+ let code =<< trim [CODE]
+
+ void f()
+ {
+ if ( k() ) {
+ l();
+
+ } else { /* Start (two words) end */
+ m();
+ }
+
+ n();
+ }
+ [CODE]
+
+ call append(0, code)
+ normal gg
+ normal ]]=][
+
+ let expected =<< trim [CODE]
+
+ void f()
+ {
+ if ( k() ) {
+ l();
+
+ } else { /* Start (two words) end */
+ m();
+ }
+
+ n();
+ }
+
+ [CODE]
+
+ call assert_equal(expected, getline(1, '$'))
+ enew! | close
+endfunc
+
+func Test_cindent_10()
+ new
+ setl cindent ts=4 sw=4
+ setl cino={s,e-s
+
+ let code =<< trim [CODE]
+
+ void f()
+ {
+ if ( k() )
+ {
+ l();
+ } else { /* Start (two words) end */
+ m();
+ }
+ n(); /* should be under the if () */
+ }
+ [CODE]
+
+ call append(0, code)
+ normal gg
+ normal ]]=][
+
+ let expected =<< trim [CODE]
+
+ void f()
+ {
+ if ( k() )
+ {
+ l();
+ } else { /* Start (two words) end */
+ m();
+ }
+ n(); /* should be under the if () */
+ }
+
+ [CODE]
+
+ call assert_equal(expected, getline(1, '$'))
+ enew! | close
+endfunc
+
+func Test_cindent_11()
+ new
+ setl cindent ts=4 sw=4
+ setl cino={s,fs
+
+ let code =<< trim [CODE]
+ void bar(void)
+ {
+ static array[2][2] =
+ {
+ { 1, 2 },
+ { 3, 4 },
+ }
+
+ while (a)
+ {
+ foo(&a);
+ }
+
+ {
+ int a;
+ {
+ a = a + 1;
+ }
+ }
+ b = a;
+ }
+
+ void func(void)
+ {
+ a = 1;
+ {
+ b = 2;
+ }
+ c = 3;
+ d = 4;
+ }
+ /* foo */
+ [CODE]
+
+ call append(0, code)
+ normal gg
+ exe "normal ]]=/ foo\<CR>"
+
+ let expected =<< trim [CODE]
+ void bar(void)
+ {
+ static array[2][2] =
+ {
+ { 1, 2 },
+ { 3, 4 },
+ }
+
+ while (a)
+ {
+ foo(&a);
+ }
+
+ {
+ int a;
+ {
+ a = a + 1;
+ }
+ }
+ b = a;
+ }
+
+ void func(void)
+ {
+ a = 1;
+ {
+ b = 2;
+ }
+ c = 3;
+ d = 4;
+ }
+ /* foo */
+
+ [CODE]
+
+ call assert_equal(expected, getline(1, '$'))
+ enew! | close
+endfunc
+
+func Test_cindent_12()
+ new
+ setl cindent ts=4 sw=4
+ setl cino=
+
+ let code =<< trim [CODE]
+ a()
+ {
+ do {
+ a = a +
+ a;
+ } while ( a ); /* add text under this line */
+ if ( a )
+ a;
+ }
+ [CODE]
+
+ call append(0, code)
+ normal gg
+ call search('while')
+ normal ohere
+
+ let expected =<< trim [CODE]
+ a()
+ {
+ do {
+ a = a +
+ a;
+ } while ( a ); /* add text under this line */
+ here
+ if ( a )
+ a;
+ }
+
+ [CODE]
+
+ call assert_equal(expected, getline(1, '$'))
+ enew! | close
+endfunc
+
+func Test_cindent_13()
+ new
+ setl cindent ts=4 sw=4
+ setl cino= com=
+
+ let code =<< trim [CODE]
+ a()
+ {
+ label1:
+ /* hmm */
+ // comment
+ }
+ [CODE]
+
+ call append(0, code)
+ normal gg
+ call search('comment')
+ exe "normal olabel2: b();\rlabel3 /* post */:\r/* pre */ label4:\r" .
+ \ "f(/*com*/);\rif (/*com*/)\rcmd();"
+
+ let expected =<< trim [CODE]
+ a()
+ {
+ label1:
+ /* hmm */
+ // comment
+ label2: b();
+ label3 /* post */:
+ /* pre */ label4:
+ f(/*com*/);
+ if (/*com*/)
+ cmd();
+ }
+
+ [CODE]
+
+ call assert_equal(expected, getline(1, '$'))
+ enew! | close
+endfunc
+
+func Test_cindent_14()
+ new
+ setl cindent ts=4 sw=4
+ setl comments& comments^=s:/*,m:**,ex:*/
+
+ let code =<< trim [CODE]
+ /*
+ * A simple comment
+ */
+
+ /*
+ ** A different comment
+ */
+ [CODE]
+
+ call append(0, code)
+ normal gg
+ call search('simple')
+ normal =5j
+
+ let expected =<< trim [CODE]
+ /*
+ * A simple comment
+ */
+
+ /*
+ ** A different comment
+ */
+
+ [CODE]
+
+ call assert_equal(expected, getline(1, '$'))
+ enew! | close
+endfunc
+
+func Test_cindent_15()
+ new
+ setl cindent ts=4 sw=4
+ setl cino=c0
+ setl comments& comments-=s1:/* comments^=s0:/*
+
+ let code =<< trim [CODE]
+ void f()
+ {
+
+ /*********
+ A comment.
+ *********/
+ }
+ [CODE]
+
+ call append(0, code)
+ normal gg
+ normal ]]=][
+
+ let expected =<< trim [CODE]
+ void f()
+ {
+
+ /*********
+ A comment.
+ *********/
+ }
+
+ [CODE]
+
+ call assert_equal(expected, getline(1, '$'))
+ enew! | close
+endfunc
+
+func Test_cindent_16()
+ new
+ setl cindent ts=4 sw=4
+ setl cino=c0,C1
+ setl comments& comments-=s1:/* comments^=s0:/*
+
+ let code =<< trim [CODE]
+ void f()
+ {
+
+ /*********
+ A comment.
+ *********/
+ }
+ [CODE]
+
+ call append(0, code)
+ normal gg
+ normal ]]=][
+
+ let expected =<< trim [CODE]
+ void f()
+ {
+
+ /*********
+ A comment.
+ *********/
+ }
+
+ [CODE]
+
+ call assert_equal(expected, getline(1, '$'))
+ enew! | close
+endfunc
+
+func Test_cindent_17()
+ new
+ setl cindent ts=4 sw=4
+ setl cino=
+
+ let code =<< trim [CODE]
+ void f()
+ {
+ c = c1 &&
+ (
+ c2 ||
+ c3
+ ) && c4;
+ }
+ [CODE]
+
+ call append(0, code)
+ normal gg
+ normal ]]=][
+
+ let expected =<< trim [CODE]
+ void f()
+ {
+ c = c1 &&
+ (
+ c2 ||
+ c3
+ ) && c4;
+ }
+
+ [CODE]
+
+ call assert_equal(expected, getline(1, '$'))
+ enew! | close
+endfunc
+
+func Test_cindent_18()
+ new
+ setl cindent ts=4 sw=4
+ setl cino=(s
+
+ let code =<< trim [CODE]
+ void f()
+ {
+ c = c1 &&
+ (
+ c2 ||
+ c3
+ ) && c4;
+ }
+ [CODE]
+
+ call append(0, code)
+ normal gg
+ normal ]]=][
+
+ let expected =<< trim [CODE]
+ void f()
+ {
+ c = c1 &&
+ (
+ c2 ||
+ c3
+ ) && c4;
+ }
+
+ [CODE]
+
+ call assert_equal(expected, getline(1, '$'))
+ enew! | close
+endfunc
+
+func Test_cindent_19()
+ new
+ setl cindent ts=4 sw=4
+ set cino=(s,U1
+
+ let code =<< trim [CODE]
+ void f()
+ {
+ c = c1 &&
+ (
+ c2 ||
+ c3
+ ) && c4;
+ }
+ [CODE]
+
+ call append(0, code)
+ normal gg
+ normal ]]=][
+
+ let expected =<< trim [CODE]
+ void f()
+ {
+ c = c1 &&
+ (
+ c2 ||
+ c3
+ ) && c4;
+ }
+
+ [CODE]
+
+ call assert_equal(expected, getline(1, '$'))
+ enew! | close
+endfunc
+
+func Test_cindent_20()
+ new
+ setl cindent ts=4 sw=4
+ setl cino=(0
+
+ let code =<< trim [CODE]
+ void f()
+ {
+ if ( c1
+ && ( c2
+ || c3))
+ foo;
+ }
+ [CODE]
+
+ call append(0, code)
+ normal gg
+ normal ]]=][
+
+ let expected =<< trim [CODE]
+ void f()
+ {
+ if ( c1
+ && ( c2
+ || c3))
+ foo;
+ }
+
+ [CODE]
+
+ call assert_equal(expected, getline(1, '$'))
+ enew! | close
+endfunc
+
+func Test_cindent_21()
+ new
+ setl cindent ts=4 sw=4
+ setl cino=(0,w1
+
+ let code =<< trim [CODE]
+ void f()
+ {
+ if ( c1
+ && ( c2
+ || c3))
+ foo;
+ }
+ [CODE]
+
+ call append(0, code)
+ normal gg
+ normal ]]=][
+
+ let expected =<< trim [CODE]
+ void f()
+ {
+ if ( c1
+ && ( c2
+ || c3))
+ foo;
+ }
+
+ [CODE]
+
+ call assert_equal(expected, getline(1, '$'))
+ enew! | close
+endfunc
+
+func Test_cindent_22()
+ new
+ setl cindent ts=4 sw=4
+ setl cino=(s
+
+ let code =<< trim [CODE]
+ void f()
+ {
+ c = c1 && (
+ c2 ||
+ c3
+ ) && c4;
+ if (
+ c1 && c2
+ )
+ foo;
+ }
+ [CODE]
+
+ call append(0, code)
+ normal gg
+ normal ]]=][
+
+ let expected =<< trim [CODE]
+ void f()
+ {
+ c = c1 && (
+ c2 ||
+ c3
+ ) && c4;
+ if (
+ c1 && c2
+ )
+ foo;
+ }
+
+ [CODE]
+
+ call assert_equal(expected, getline(1, '$'))
+ enew! | close
+endfunc
+
+func Test_cindent_23()
+ new
+ setl cindent ts=4 sw=4
+ setl cino=(s,m1
+
+ let code =<< trim [CODE]
+ void f()
+ {
+ c = c1 && (
+ c2 ||
+ c3
+ ) && c4;
+ if (
+ c1 && c2
+ )
+ foo;
+ }
+ [CODE]
+
+ call append(0, code)
+ normal gg
+ normal ]]=][
+
+ let expected =<< trim [CODE]
+ void f()
+ {
+ c = c1 && (
+ c2 ||
+ c3
+ ) && c4;
+ if (
+ c1 && c2
+ )
+ foo;
+ }
+
+ [CODE]
+
+ call assert_equal(expected, getline(1, '$'))
+ enew! | close
+endfunc
+
+func Test_cindent_24()
+ new
+ setl cindent ts=4 sw=4
+ setl cino=b1
+
+ let code =<< trim [CODE]
+ void f()
+ {
+ switch (x)
+ {
+ case 1:
+ a = b;
+ break;
+ default:
+ a = 0;
+ break;
+ }
+ }
+ [CODE]
+
+ call append(0, code)
+ normal gg
+ normal ]]=][
+
+ let expected =<< trim [CODE]
+ void f()
+ {
+ switch (x)
+ {
+ case 1:
+ a = b;
+ break;
+ default:
+ a = 0;
+ break;
+ }
+ }
+
+ [CODE]
+
+ call assert_equal(expected, getline(1, '$'))
+ enew! | close
+endfunc
+
+func Test_cindent_25()
+ new
+ setl cindent ts=4 sw=4
+ setl cino=(0,W5
+
+ let code =<< trim [CODE]
+ void f()
+ {
+ invokeme(
+ argu,
+ ment);
+ invokeme(
+ argu,
+ ment
+ );
+ invokeme(argu,
+ ment
+ );
+ }
+ [CODE]
+
+ call append(0, code)
+ normal gg
+ normal ]]=][
+
+ let expected =<< trim [CODE]
+ void f()
+ {
+ invokeme(
+ argu,
+ ment);
+ invokeme(
+ argu,
+ ment
+ );
+ invokeme(argu,
+ ment
+ );
+ }
+
+ [CODE]
+
+ call assert_equal(expected, getline(1, '$'))
+ enew! | close
+endfunc
+
+func Test_cindent_26()
+ new
+ setl cindent ts=4 sw=4
+ setl cino=/6
+
+ let code =<< trim [CODE]
+ void f()
+ {
+ statement;
+ // comment 1
+ // comment 2
+ }
+ [CODE]
+
+ call append(0, code)
+ normal gg
+ normal ]]=][
+
+ let expected =<< trim [CODE]
+ void f()
+ {
+ statement;
+ // comment 1
+ // comment 2
+ }
+
+ [CODE]
+
+ call assert_equal(expected, getline(1, '$'))
+ enew! | close
+endfunc
+
+func Test_cindent_27()
+ new
+ setl cindent ts=4 sw=4
+ setl cino=
+
+ let code =<< trim [CODE]
+ void f()
+ {
+ statement;
+ // comment 1
+ // comment 2
+ }
+ [CODE]
+
+ call append(0, code)
+ normal gg
+ exe "normal ]]/comment 1/+1\<CR>=="
+
+ let expected =<< trim [CODE]
+ void f()
+ {
+ statement;
+ // comment 1
+ // comment 2
+ }
+
+ [CODE]
+
+ call assert_equal(expected, getline(1, '$'))
+ enew! | close
+endfunc
+
+func Test_cindent_28()
+ new
+ setl cindent ts=4 sw=4
+ setl cino=g0
+
+ let code =<< trim [CODE]
+ class CAbc
+ {
+ int Test() { return FALSE; }
+
+ public: // comment
+ void testfall();
+ protected:
+ void testfall();
+ };
+ [CODE]
+
+ call append(0, code)
+ normal gg
+ normal ]]=][
+
+ let expected =<< trim [CODE]
+ class CAbc
+ {
+ int Test() { return FALSE; }
+
+ public: // comment
+ void testfall();
+ protected:
+ void testfall();
+ };
+
+ [CODE]
+
+ call assert_equal(expected, getline(1, '$'))
+ enew! | close
+endfunc
+
+func Test_cindent_29()
+ new
+ setl cindent ts=4 sw=4
+ setl cino=(0,gs,hs
+
+ let code =<< trim [CODE]
+ class Foo : public Bar
+ {
+ public:
+ virtual void method1(void) = 0;
+ virtual void method2(int arg1,
+ int arg2,
+ int arg3) = 0;
+ };
+ [CODE]
+
+ call append(0, code)
+ normal gg
+ normal ]]=][
+
+ let expected =<< trim [CODE]
+ class Foo : public Bar
+ {
+ public:
+ virtual void method1(void) = 0;
+ virtual void method2(int arg1,
+ int arg2,
+ int arg3) = 0;
+ };
+
+ [CODE]
+
+ call assert_equal(expected, getline(1, '$'))
+ enew! | close
+endfunc
+
+func Test_cindent_30()
+ new
+ setl cindent ts=4 sw=4
+ setl cino=+20
+
+ let code =<< [CODE]
+ void
+foo()
+{
+ if (a)
+ {
+ } else
+ asdf;
+}
+[CODE]
+
+ call append(0, code)
+ normal gg
+ normal ]]=][
+
+ let expected =<< [CODE]
+ void
+foo()
+{
+ if (a)
+ {
+ } else
+ asdf;
+}
+
+[CODE]
+
+ call assert_equal(expected, getline(1, '$'))
+ enew! | close
+endfunc
+
+func Test_cindent_31()
+ new
+ setl cindent ts=4 sw=4
+ setl cino=(0,W2s
+
+ let code =<< trim [CODE]
+
+ {
+ averylongfunctionnamelongfunctionnameaverylongfunctionname()->asd(
+ asdasdf,
+ func(asdf,
+ asdfadsf),
+ asdfasdf
+ );
+
+ /* those are ugly, but consequent */
+
+ func()->asd(asdasdf,
+ averylongfunctionname(
+ abc,
+ dec)->averylongfunctionname(
+ asdfadsf,
+ asdfasdf,
+ asdfasdf,
+ ),
+ func(asdfadf,
+ asdfasdf
+ ),
+ asdasdf
+ );
+
+ averylongfunctionnameaverylongfunctionnameavery()->asd(fasdf(
+ abc,
+ dec)->asdfasdfasdf(
+ asdfadsf,
+ asdfasdf,
+ asdfasdf,
+ ),
+ func(asdfadf,
+ asdfasdf),
+ asdasdf
+ );
+ }
+ [CODE]
+
+ call append(0, code)
+ normal gg
+ normal ]]=][
+
+ let expected =<< trim [CODE]
+
+ {
+ averylongfunctionnamelongfunctionnameaverylongfunctionname()->asd(
+ asdasdf,
+ func(asdf,
+ asdfadsf),
+ asdfasdf
+ );
+
+ /* those are ugly, but consequent */
+
+ func()->asd(asdasdf,
+ averylongfunctionname(
+ abc,
+ dec)->averylongfunctionname(
+ asdfadsf,
+ asdfasdf,
+ asdfasdf,
+ ),
+ func(asdfadf,
+ asdfasdf
+ ),
+ asdasdf
+ );
+
+ averylongfunctionnameaverylongfunctionnameavery()->asd(fasdf(
+ abc,
+ dec)->asdfasdfasdf(
+ asdfadsf,
+ asdfasdf,
+ asdfasdf,
+ ),
+ func(asdfadf,
+ asdfasdf),
+ asdasdf
+ );
+ }
+
+ [CODE]
+
+ call assert_equal(expected, getline(1, '$'))
+ enew! | close
+endfunc
+
+func Test_cindent_32()
+ new
+ setl cindent ts=4 sw=4
+ setl cino=M1
+
+ let code =<< trim [CODE]
+ int main ()
+ {
+ if (cond1 &&
+ cond2
+ )
+ foo;
+ }
+ [CODE]
+
+ call append(0, code)
+ normal gg
+ normal ]]=][
+
+ let expected =<< trim [CODE]
+ int main ()
+ {
+ if (cond1 &&
+ cond2
+ )
+ foo;
+ }
+
+ [CODE]
+
+ call assert_equal(expected, getline(1, '$'))
+ enew! | close
+endfunc
+
+func Test_cindent_33()
+ new
+ setl cindent ts=4 sw=4
+ setl cino=(0,ts
+
+ let code =<< trim [CODE]
+ void func(int a
+ #if defined(FOO)
+ , int b
+ , int c
+ #endif
+ )
+ {
+ }
+ [CODE]
+
+ call append(0, code)
+ normal gg
+ normal 2j=][
+
+ let expected =<< trim [CODE]
+ void func(int a
+ #if defined(FOO)
+ , int b
+ , int c
+ #endif
+ )
+ {
+ }
+
+ [CODE]
+
+ call assert_equal(expected, getline(1, '$'))
+ enew! | close
+endfunc
+
+func Test_cindent_34()
+ new
+ setl cindent ts=4 sw=4
+ setl cino=(0
+
+ let code =<< trim [CODE]
+
+ void
+ func(int a
+ #if defined(FOO)
+ , int b
+ , int c
+ #endif
+ )
+ {
+ }
+ [CODE]
+
+ call append(0, code)
+ normal gg
+ normal =][
+
+ let expected =<< trim [CODE]
+
+ void
+ func(int a
+ #if defined(FOO)
+ , int b
+ , int c
+ #endif
+ )
+ {
+ }
+
+ [CODE]
+
+ call assert_equal(expected, getline(1, '$'))
+ enew! | close
+endfunc
+
+func Test_cindent_35()
+ new
+ setl cindent ts=4 sw=4
+ setl cino&
+
+ let code =<< trim [CODE]
+ void func(void)
+ {
+ if(x==y)
+ if(y==z)
+ foo=1;
+ else { bar=1;
+ baz=2;
+ }
+ printf("Foo!\n");
+ }
+
+ void func1(void)
+ {
+ char* tab[] = {"foo", "bar",
+ "baz", "quux",
+ "this line used", "to be indented incorrectly"};
+ foo();
+ }
+
+ void func2(void)
+ {
+ int tab[] =
+ {1, 2,
+ 3, 4,
+ 5, 6};
+
+ printf("This line used to be indented incorrectly.\n");
+ }
+
+ int foo[]
+ #ifdef BAR
+
+ = { 1, 2, 3,
+ 4, 5, 6 }
+
+ #endif
+ ;
+ int baz;
+
+ void func3(void)
+ {
+ int tab[] = {
+ 1, 2,
+ 3, 4,
+ 5, 6};
+
+ printf("Don't you dare indent this line incorrectly!\n");
+ }
+
+ void
+ func4(a, b,
+ c)
+ int a;
+ int b;
+ int c;
+ {
+ }
+
+ void
+ func5(
+ int a,
+ int b)
+ {
+ }
+
+ void
+ func6(
+ int a)
+ {
+ }
+ [CODE]
+
+ call append(0, code)
+ normal gg
+ normal ]]=7][
+
+ let expected =<< trim [CODE]
+ void func(void)
+ {
+ if(x==y)
+ if(y==z)
+ foo=1;
+ else { bar=1;
+ baz=2;
+ }
+ printf("Foo!\n");
+ }
+
+ void func1(void)
+ {
+ char* tab[] = {"foo", "bar",
+ "baz", "quux",
+ "this line used", "to be indented incorrectly"};
+ foo();
+ }
+
+ void func2(void)
+ {
+ int tab[] =
+ {1, 2,
+ 3, 4,
+ 5, 6};
+
+ printf("This line used to be indented incorrectly.\n");
+ }
+
+ int foo[]
+ #ifdef BAR
+
+ = { 1, 2, 3,
+ 4, 5, 6 }
+
+ #endif
+ ;
+ int baz;
+
+ void func3(void)
+ {
+ int tab[] = {
+ 1, 2,
+ 3, 4,
+ 5, 6};
+
+ printf("Don't you dare indent this line incorrectly!\n");
+ }
+
+ void
+ func4(a, b,
+ c)
+ int a;
+ int b;
+ int c;
+ {
+ }
+
+ void
+ func5(
+ int a,
+ int b)
+ {
+ }
+
+ void
+ func6(
+ int a)
+ {
+ }
+
+ [CODE]
+
+ call assert_equal(expected, getline(1, '$'))
+ enew! | close
+endfunc
+
+func Test_cindent_36()
+ new
+ setl cindent ts=4 sw=4
+ setl cino&
+ setl cino+=l1
+
+ let code =<< trim [CODE]
+ void func(void)
+ {
+ int tab[] =
+ {
+ 1, 2, 3,
+ 4, 5, 6};
+
+ printf("Indent this line correctly!\n");
+
+ switch (foo)
+ {
+ case bar:
+ printf("bar");
+ break;
+ case baz: {
+ printf("baz");
+ break;
+ }
+ case quux:
+ printf("But don't break the indentation of this instruction\n");
+ break;
+ }
+ }
+ [CODE]
+
+ call append(0, code)
+ normal gg
+ normal ]]=][
+
+ let expected =<< trim [CODE]
+ void func(void)
+ {
+ int tab[] =
+ {
+ 1, 2, 3,
+ 4, 5, 6};
+
+ printf("Indent this line correctly!\n");
+
+ switch (foo)
+ {
+ case bar:
+ printf("bar");
+ break;
+ case baz: {
+ printf("baz");
+ break;
+ }
+ case quux:
+ printf("But don't break the indentation of this instruction\n");
+ break;
+ }
+ }
+
+ [CODE]
+
+ call assert_equal(expected, getline(1, '$'))
+ enew! | close
+endfunc
+
+func Test_cindent_37()
+ new
+ setl cindent ts=4 sw=4
+ setl cino&
+
+ let code =<< trim [CODE]
+ void func(void)
+ {
+ cout << "a"
+ << "b"
+ << ") :"
+ << "c";
+ }
+ [CODE]
+
+ call append(0, code)
+ normal gg
+ normal ]]=][
+
+ let expected =<< trim [CODE]
+ void func(void)
+ {
+ cout << "a"
+ << "b"
+ << ") :"
+ << "c";
+ }
+
+ [CODE]
+
+ call assert_equal(expected, getline(1, '$'))
+ enew! | close
+endfunc
+
+func Test_cindent_38()
+ new
+ setl cindent ts=4 sw=4
+ setl com=s1:/*,m:*,ex:*/
+
+ let code =<< trim [CODE]
+ void func(void)
+ {
+ /*
+ * This is a comment.
+ */
+ }
+ [CODE]
+
+ call append(0, code)
+ normal gg
+ normal ]]3jofoo();
+
+ let expected =<< trim [CODE]
+ void func(void)
+ {
+ /*
+ * This is a comment.
+ */
+ foo();
+ }
+
+ [CODE]
+
+ call assert_equal(expected, getline(1, '$'))
+ enew! | close
+endfunc
+
+func Test_cindent_39()
+ new
+ setl cindent ts=4 sw=4
+ setl cino&
+
+ let code =<< trim [CODE]
+ void func(void)
+ {
+ for (int i = 0; i < 10; ++i)
+ if (i & 1) {
+ foo(1);
+ } else
+ foo(0);
+ baz();
+ }
+ [CODE]
+
+ call append(0, code)
+ normal gg
+ normal ]]=][
+
+ let expected =<< trim [CODE]
+ void func(void)
+ {
+ for (int i = 0; i < 10; ++i)
+ if (i & 1) {
+ foo(1);
+ } else
+ foo(0);
+ baz();
+ }
+
+ [CODE]
+
+ call assert_equal(expected, getline(1, '$'))
+ enew! | close
+endfunc
+
+func Test_cindent_40()
+ new
+ setl cindent ts=4 sw=4
+ setl cino=k2s,(0
+
+ let code =<< trim [CODE]
+ void func(void)
+ {
+ if (condition1
+ && condition2)
+ action();
+ function(argument1
+ && argument2);
+
+ if (c1 && (c2 ||
+ c3))
+ foo;
+ if (c1 &&
+ (c2 || c3))
+ {
+ }
+
+ if ( c1
+ && ( c2
+ || c3))
+ foo;
+ func( c1
+ && ( c2
+ || c3))
+ foo;
+ }
+ [CODE]
+
+ call append(0, code)
+ normal gg
+ normal ]]=][
+
+ let expected =<< trim [CODE]
+ void func(void)
+ {
+ if (condition1
+ && condition2)
+ action();
+ function(argument1
+ && argument2);
+
+ if (c1 && (c2 ||
+ c3))
+ foo;
+ if (c1 &&
+ (c2 || c3))
+ {
+ }
+
+ if ( c1
+ && ( c2
+ || c3))
+ foo;
+ func( c1
+ && ( c2
+ || c3))
+ foo;
+ }
+
+ [CODE]
+
+ call assert_equal(expected, getline(1, '$'))
+ enew! | close
+endfunc
+
+func Test_cindent_41()
+ new
+ setl cindent ts=4 sw=4
+ setl cino=k2s,(s
+
+ let code =<< trim [CODE]
+ void func(void)
+ {
+ if (condition1
+ && condition2)
+ action();
+ function(argument1
+ && argument2);
+
+ if (c1 && (c2 ||
+ c3))
+ foo;
+ if (c1 &&
+ (c2 || c3))
+ {
+ }
+
+ if ( c1
+ && ( c2
+ || c3))
+ foo;
+ func( c1
+ && ( c2
+ || c3))
+ foo;
+ }
+ [CODE]
+
+ call append(0, code)
+ normal gg
+ normal ]]=][
+
+ let expected =<< trim [CODE]
+ void func(void)
+ {
+ if (condition1
+ && condition2)
+ action();
+ function(argument1
+ && argument2);
+
+ if (c1 && (c2 ||
+ c3))
+ foo;
+ if (c1 &&
+ (c2 || c3))
+ {
+ }
+
+ if ( c1
+ && ( c2
+ || c3))
+ foo;
+ func( c1
+ && ( c2
+ || c3))
+ foo;
+ }
+
+ [CODE]
+
+ call assert_equal(expected, getline(1, '$'))
+ enew! | close
+endfunc
+
+func Test_cindent_42()
+ new
+ setl cindent ts=4 sw=4
+ setl cino=k2s,(s,U1
+
+ let code =<< trim [CODE]
+ void func(void)
+ {
+ if (condition1
+ && condition2)
+ action();
+ function(argument1
+ && argument2);
+
+ if (c1 && (c2 ||
+ c3))
+ foo;
+ if (c1 &&
+ (c2 || c3))
+ {
+ }
+ if (c123456789
+ && (c22345
+ || c3))
+ printf("foo\n");
+
+ c = c1 &&
+ (
+ c2 ||
+ c3
+ ) && c4;
+ }
+ [CODE]
+
+ call append(0, code)
+ normal gg
+ normal ]]=][
+
+ let expected =<< trim [CODE]
+ void func(void)
+ {
+ if (condition1
+ && condition2)
+ action();
+ function(argument1
+ && argument2);
+
+ if (c1 && (c2 ||
+ c3))
+ foo;
+ if (c1 &&
+ (c2 || c3))
+ {
+ }
+ if (c123456789
+ && (c22345
+ || c3))
+ printf("foo\n");
+
+ c = c1 &&
+ (
+ c2 ||
+ c3
+ ) && c4;
+ }
+
+ [CODE]
+
+ call assert_equal(expected, getline(1, '$'))
+ enew! | close
+endfunc
+
+func Test_cindent_43()
+ new
+ setl cindent ts=4 sw=4
+ setl cino=k2s,(0,W4
+
+ let code =<< trim [CODE]
+ void func(void)
+ {
+ if (condition1
+ && condition2)
+ action();
+ function(argument1
+ && argument2);
+
+ if (c1 && (c2 ||
+ c3))
+ foo;
+ if (c1 &&
+ (c2 || c3))
+ {
+ }
+ if (c123456789
+ && (c22345
+ || c3))
+ printf("foo\n");
+
+ if ( c1
+ && ( c2
+ || c3))
+ foo;
+
+ a_long_line(
+ argument,
+ argument);
+ a_short_line(argument,
+ argument);
+ }
+ [CODE]
+
+ call append(0, code)
+ normal gg
+ normal ]]=][
+
+ let expected =<< trim [CODE]
+ void func(void)
+ {
+ if (condition1
+ && condition2)
+ action();
+ function(argument1
+ && argument2);
+
+ if (c1 && (c2 ||
+ c3))
+ foo;
+ if (c1 &&
+ (c2 || c3))
+ {
+ }
+ if (c123456789
+ && (c22345
+ || c3))
+ printf("foo\n");
+
+ if ( c1
+ && ( c2
+ || c3))
+ foo;
+
+ a_long_line(
+ argument,
+ argument);
+ a_short_line(argument,
+ argument);
+ }
+
+ [CODE]
+
+ call assert_equal(expected, getline(1, '$'))
+ enew! | close
+endfunc
+
+func Test_cindent_44()
+ new
+ setl cindent ts=4 sw=4
+ setl cino=k2s,u2
+
+ let code =<< trim [CODE]
+ void func(void)
+ {
+ if (condition1
+ && condition2)
+ action();
+ function(argument1
+ && argument2);
+
+ if (c1 && (c2 ||
+ c3))
+ foo;
+ if (c1 &&
+ (c2 || c3))
+ {
+ }
+ if (c123456789
+ && (c22345
+ || c3))
+ printf("foo\n");
+ }
+ [CODE]
+
+ call append(0, code)
+ normal gg
+ normal ]]=][
+
+ let expected =<< trim [CODE]
+ void func(void)
+ {
+ if (condition1
+ && condition2)
+ action();
+ function(argument1
+ && argument2);
+
+ if (c1 && (c2 ||
+ c3))
+ foo;
+ if (c1 &&
+ (c2 || c3))
+ {
+ }
+ if (c123456789
+ && (c22345
+ || c3))
+ printf("foo\n");
+ }
+
+ [CODE]
+
+ call assert_equal(expected, getline(1, '$'))
+ enew! | close
+endfunc
+
+func Test_cindent_45()
+ new
+ setl cindent ts=4 sw=4
+ setl cino=k2s,(0,w1
+
+ let code =<< trim [CODE]
+ void func(void)
+ {
+ if (condition1
+ && condition2)
+ action();
+ function(argument1
+ && argument2);
+
+ if (c1 && (c2 ||
+ c3))
+ foo;
+ if (c1 &&
+ (c2 || c3))
+ {
+ }
+ if (c123456789
+ && (c22345
+ || c3))
+ printf("foo\n");
+
+ if ( c1
+ && ( c2
+ || c3))
+ foo;
+ func( c1
+ && ( c2
+ || c3))
+ foo;
+ }
+ [CODE]
+
+ call append(0, code)
+ normal gg
+ normal ]]=][
+
+ let expected =<< trim [CODE]
+ void func(void)
+ {
+ if (condition1
+ && condition2)
+ action();
+ function(argument1
+ && argument2);
+
+ if (c1 && (c2 ||
+ c3))
+ foo;
+ if (c1 &&
+ (c2 || c3))
+ {
+ }
+ if (c123456789
+ && (c22345
+ || c3))
+ printf("foo\n");
+
+ if ( c1
+ && ( c2
+ || c3))
+ foo;
+ func( c1
+ && ( c2
+ || c3))
+ foo;
+ }
+
+ [CODE]
+
+ call assert_equal(expected, getline(1, '$'))
+ enew! | close
+endfunc
+
+func Test_cindent_46()
+ new
+ setl cindent ts=4 sw=4
+ setl cino=k2,(s
+
+ let code =<< trim [CODE]
+ void func(void)
+ {
+ if (condition1
+ && condition2)
+ action();
+ function(argument1
+ && argument2);
+
+ if (c1 && (c2 ||
+ c3))
+ foo;
+ if (c1 &&
+ (c2 || c3))
+ {
+ }
+ }
+ [CODE]
+
+ call append(0, code)
+ normal gg
+ normal ]]=][
+
+ let expected =<< trim [CODE]
+ void func(void)
+ {
+ if (condition1
+ && condition2)
+ action();
+ function(argument1
+ && argument2);
+
+ if (c1 && (c2 ||
+ c3))
+ foo;
+ if (c1 &&
+ (c2 || c3))
+ {
+ }
+ }
+
+ [CODE]
+
+ call assert_equal(expected, getline(1, '$'))
+ enew! | close
+endfunc
+
+func Test_cindent_47()
+ new
+ setl cindent ts=4 sw=4
+ setl cino=N-s
+
+ let code =<< trim [CODE]
+ NAMESPACESTART
+ /* valid namespaces with normal indent */
+ namespace
+ {
+ {
+ 111111111111;
+ }
+ }
+ namespace /* test */
+ {
+ 11111111111111111;
+ }
+ namespace // test
+ {
+ 111111111111111111;
+ }
+ namespace
+ {
+ 111111111111111111;
+ }
+ namespace test
+ {
+ 111111111111111111;
+ }
+ namespace test::cpp17
+ {
+ 111111111111111111;
+ }
+ namespace ::incorrectcpp17
+ {
+ 111111111111111111;
+ }
+ namespace test::incorrectcpp17::
+ {
+ 111111111111111111;
+ }
+ namespace test:incorrectcpp17
+ {
+ 111111111111111111;
+ }
+ namespace test:::incorrectcpp17
+ {
+ 111111111111111111;
+ }
+ namespace{
+ 111111111111111111;
+ }
+ namespace test{
+ 111111111111111111;
+ }
+ namespace {
+ 111111111111111111;
+ }
+ namespace test {
+ 111111111111111111;
+ namespace test2 {
+ 22222222222222222;
+ }
+ }
+ inline namespace {
+ 111111111111111111;
+ }
+ inline /* test */ namespace {
+ 111111111111111111;
+ }
+ inline/* test */namespace {
+ 111111111111111111;
+ }
+
+ /* invalid namespaces use block indent */
+ namespace test test2 {
+ 111111111111111111111;
+ }
+ namespace11111111111 {
+ 111111111111;
+ }
+ namespace() {
+ 1111111111111;
+ }
+ namespace()
+ {
+ 111111111111111111;
+ }
+ namespace test test2
+ {
+ 1111111111111111111;
+ }
+ namespace111111111
+ {
+ 111111111111111111;
+ }
+ inlinenamespace {
+ 111111111111111111;
+ }
+ NAMESPACEEND
+ [CODE]
+
+ call append(0, code)
+ normal gg
+ call search('^NAMESPACESTART')
+ exe "normal =/^NAMESPACEEND\n"
+
+ let expected =<< trim [CODE]
+ NAMESPACESTART
+ /* valid namespaces with normal indent */
+ namespace
+ {
+ {
+ 111111111111;
+ }
+ }
+ namespace /* test */
+ {
+ 11111111111111111;
+ }
+ namespace // test
+ {
+ 111111111111111111;
+ }
+ namespace
+ {
+ 111111111111111111;
+ }
+ namespace test
+ {
+ 111111111111111111;
+ }
+ namespace test::cpp17
+ {
+ 111111111111111111;
+ }
+ namespace ::incorrectcpp17
+ {
+ 111111111111111111;
+ }
+ namespace test::incorrectcpp17::
+ {
+ 111111111111111111;
+ }
+ namespace test:incorrectcpp17
+ {
+ 111111111111111111;
+ }
+ namespace test:::incorrectcpp17
+ {
+ 111111111111111111;
+ }
+ namespace{
+ 111111111111111111;
+ }
+ namespace test{
+ 111111111111111111;
+ }
+ namespace {
+ 111111111111111111;
+ }
+ namespace test {
+ 111111111111111111;
+ namespace test2 {
+ 22222222222222222;
+ }
+ }
+ inline namespace {
+ 111111111111111111;
+ }
+ inline /* test */ namespace {
+ 111111111111111111;
+ }
+ inline/* test */namespace {
+ 111111111111111111;
+ }
+
+ /* invalid namespaces use block indent */
+ namespace test test2 {
+ 111111111111111111111;
+ }
+ namespace11111111111 {
+ 111111111111;
+ }
+ namespace() {
+ 1111111111111;
+ }
+ namespace()
+ {
+ 111111111111111111;
+ }
+ namespace test test2
+ {
+ 1111111111111111111;
+ }
+ namespace111111111
+ {
+ 111111111111111111;
+ }
+ inlinenamespace {
+ 111111111111111111;
+ }
+ NAMESPACEEND
+
+ [CODE]
+
+ call assert_equal(expected, getline(1, '$'))
+ enew! | close
+endfunc
+
+func Test_cindent_48()
+ new
+ setl cindent ts=4 sw=4
+ setl cino=j1,J1
+
+ let code =<< trim [CODE]
+ JSSTART
+ var bar = {
+ foo: {
+ that: this,
+ some: ok,
+ },
+ "bar":{
+ a : 2,
+ b: "123abc",
+ x: 4,
+ "y": 5
+ }
+ }
+ JSEND
+ [CODE]
+
+ call append(0, code)
+ normal gg
+ call search('^JSSTART')
+ exe "normal =/^JSEND\n"
+
+ let expected =<< trim [CODE]
+ JSSTART
+ var bar = {
+ foo: {
+ that: this,
+ some: ok,
+ },
+ "bar":{
+ a : 2,
+ b: "123abc",
+ x: 4,
+ "y": 5
+ }
+ }
+ JSEND
+
+ [CODE]
+
+ call assert_equal(expected, getline(1, '$'))
+ enew! | close
+endfunc
+
+func Test_cindent_49()
+ new
+ setl cindent ts=4 sw=4
+ setl cino=j1,J1
+
+ let code =<< trim [CODE]
+ JSSTART
+ var foo = [
+ 1,
+ 2,
+ 3
+ ];
+ JSEND
+ [CODE]
+
+ call append(0, code)
+ normal gg
+ call search('^JSSTART')
+ exe "normal =/^JSEND\n"
+
+ let expected =<< trim [CODE]
+ JSSTART
+ var foo = [
+ 1,
+ 2,
+ 3
+ ];
+ JSEND
+
+ [CODE]
+
+ call assert_equal(expected, getline(1, '$'))
+ enew! | close
+endfunc
+
+func Test_cindent_50()
+ new
+ setl cindent ts=4 sw=4
+ setl cino=j1,J1
+
+ let code =<< trim [CODE]
+ JSSTART
+ function bar() {
+ var foo = [
+ 1,
+ 2,
+ 3
+ ];
+ }
+ JSEND
+ [CODE]
+
+ call append(0, code)
+ normal gg
+ call search('^JSSTART')
+ exe "normal =/^JSEND\n"
+
+ let expected =<< trim [CODE]
+ JSSTART
+ function bar() {
+ var foo = [
+ 1,
+ 2,
+ 3
+ ];
+ }
+ JSEND
+
+ [CODE]
+
+ call assert_equal(expected, getline(1, '$'))
+ enew! | close
+endfunc
+
+func Test_cindent_51()
+ new
+ setl cindent ts=4 sw=4
+ setl cino=j1,J1
+
+ let code =<< trim [CODE]
+ JSSTART
+ (function($){
+
+ if (cond &&
+ cond) {
+ stmt;
+ }
+ window.something.left =
+ (width - 50 + offset) + "px";
+ var class_name='myclass';
+
+ function private_method() {
+ }
+
+ var public_method={
+ method: function(options,args){
+ private_method();
+ }
+ }
+
+ function init(options) {
+
+ $(this).data(class_name+'_public',$.extend({},{
+ foo: 'bar',
+ bar: 2,
+ foobar: [
+ 1,
+ 2,
+ 3
+ ],
+ callback: function(){
+ return true;
+ }
+ }, options||{}));
+ }
+
+ $.fn[class_name]=function() {
+
+ var _arguments=arguments;
+ return this.each(function(){
+
+ var options=$(this).data(class_name+'_public');
+ if (!options) {
+ init.apply(this,_arguments);
+
+ } else {
+ var method=public_method[_arguments[0]];
+
+ if (typeof(method)!='function') {
+ console.log(class_name+' has no method "'+_arguments[0]+'"');
+ return false;
+ }
+ _arguments[0]=options;
+ method.apply(this,_arguments);
+ }
+ });
+ }
+
+ })(jQuery);
+ JSEND
+ [CODE]
+
+ call append(0, code)
+ normal gg
+ call search('^JSSTART')
+ exe "normal =/^JSEND\n"
+
+ let expected =<< trim [CODE]
+ JSSTART
+ (function($){
+
+ if (cond &&
+ cond) {
+ stmt;
+ }
+ window.something.left =
+ (width - 50 + offset) + "px";
+ var class_name='myclass';
+
+ function private_method() {
+ }
+
+ var public_method={
+ method: function(options,args){
+ private_method();
+ }
+ }
+
+ function init(options) {
+
+ $(this).data(class_name+'_public',$.extend({},{
+ foo: 'bar',
+ bar: 2,
+ foobar: [
+ 1,
+ 2,
+ 3
+ ],
+ callback: function(){
+ return true;
+ }
+ }, options||{}));
+ }
+
+ $.fn[class_name]=function() {
+
+ var _arguments=arguments;
+ return this.each(function(){
+
+ var options=$(this).data(class_name+'_public');
+ if (!options) {
+ init.apply(this,_arguments);
+
+ } else {
+ var method=public_method[_arguments[0]];
+
+ if (typeof(method)!='function') {
+ console.log(class_name+' has no method "'+_arguments[0]+'"');
+ return false;
+ }
+ _arguments[0]=options;
+ method.apply(this,_arguments);
+ }
+ });
+ }
+
+ })(jQuery);
+ JSEND
+
+ [CODE]
+
+ call assert_equal(expected, getline(1, '$'))
+ enew! | close
+endfunc
+
+func Test_cindent_52()
+ new
+ setl cindent ts=4 sw=4
+ setl cino=j1,J1
+
+ let code =<< trim [CODE]
+ JSSTART
+ function init(options) {
+ $(this).data(class_name+'_public',$.extend({},{
+ foo: 'bar',
+ bar: 2,
+ foobar: [
+ 1,
+ 2,
+ 3
+ ],
+ callback: function(){
+ return true;
+ }
+ }, options||{}));
+ }
+ JSEND
+ [CODE]
+
+ call append(0, code)
+ normal gg
+ call search('^JSSTART')
+ exe "normal =/^JSEND\n"
+
+ let expected =<< trim [CODE]
+ JSSTART
+ function init(options) {
+ $(this).data(class_name+'_public',$.extend({},{
+ foo: 'bar',
+ bar: 2,
+ foobar: [
+ 1,
+ 2,
+ 3
+ ],
+ callback: function(){
+ return true;
+ }
+ }, options||{}));
+ }
+ JSEND
+
+ [CODE]
+
+ call assert_equal(expected, getline(1, '$'))
+ enew! | close
+endfunc
+
+func Test_cindent_53()
+ new
+ setl cindent ts=4 sw=4
+ setl cino=j1,J1
+
+ let code =<< trim [CODE]
+ JSSTART
+ (function($){
+ function init(options) {
+ $(this).data(class_name+'_public',$.extend({},{
+ foo: 'bar',
+ bar: 2,
+ foobar: [
+ 1,
+ 2,
+ 3
+ ],
+ callback: function(){
+ return true;
+ }
+ }, options||{}));
+ }
+ })(jQuery);
+ JSEND
+ [CODE]
+
+ call append(0, code)
+ normal gg
+ call search('^JSSTART')
+ exe "normal =/^JSEND\n"
+
+ let expected =<< trim [CODE]
+ JSSTART
+ (function($){
+ function init(options) {
+ $(this).data(class_name+'_public',$.extend({},{
+ foo: 'bar',
+ bar: 2,
+ foobar: [
+ 1,
+ 2,
+ 3
+ ],
+ callback: function(){
+ return true;
+ }
+ }, options||{}));
+ }
+ })(jQuery);
+ JSEND
+
+ [CODE]
+
+ call assert_equal(expected, getline(1, '$'))
+ enew! | close
+endfunc
+
+func Test_cindent_54()
+ new
+ setl cindent ts=4 sw=4
+ setl cino=j1,J1,+2
+
+ let code =<< trim [CODE]
+ JSSTART
+ // Results of JavaScript indent
+ // 1
+ (function(){
+ var a = [
+ 'a',
+ 'b',
+ 'c',
+ 'd',
+ 'e',
+ 'f',
+ 'g',
+ 'h',
+ 'i'
+ ];
+ }())
+
+ // 2
+ (function(){
+ var a = [
+ 0 +
+ 5 *
+ 9 *
+ 'a',
+ 'b',
+ 0 +
+ 5 *
+ 9 *
+ 'c',
+ 'd',
+ 'e',
+ 'f',
+ 'g',
+ 'h',
+ 'i'
+ ];
+ }())
+
+ // 3
+ (function(){
+ var a = [
+ 0 +
+ // comment 1
+ 5 *
+ /* comment 2 */
+ 9 *
+ 'a',
+ 'b',
+ 0 +
+ 5 *
+ 9 *
+ 'c',
+ 'd',
+ 'e',
+ 'f',
+ 'g',
+ 'h',
+ 'i'
+ ];
+ }())
+
+ // 4
+ {
+ var a = [
+ 0,
+ 1
+ ];
+ var b;
+ var c;
+ }
+
+ // 5
+ {
+ var a = [
+ [
+ 0
+ ],
+ 2,
+ 3
+ ];
+ }
+
+ // 6
+ {
+ var a = [
+ [
+ 0,
+ 1
+ ],
+ 2,
+ 3
+ ];
+ }
+
+ // 7
+ {
+ var a = [
+ // [
+ 0,
+ // 1
+ // ],
+ 2,
+ 3
+ ];
+ }
+
+ // 8
+ var x = [
+ (function(){
+ var a,
+ b,
+ c,
+ d,
+ e,
+ f,
+ g,
+ h,
+ i;
+ })
+ ];
+
+ // 9
+ var a = [
+ 0 +
+ 5 *
+ 9 *
+ 'a',
+ 'b',
+ 0 +
+ 5 *
+ 9 *
+ 'c',
+ 'd',
+ 'e',
+ 'f',
+ 'g',
+ 'h',
+ 'i'
+ ];
+
+ // 10
+ var a,
+ b,
+ c,
+ d,
+ e,
+ f,
+ g,
+ h,
+ i;
+ JSEND
+ [CODE]
+
+ call append(0, code)
+ normal gg
+ call search('^JSSTART')
+ exe "normal =/^JSEND\n"
+
+ let expected =<< trim [CODE]
+ JSSTART
+ // Results of JavaScript indent
+ // 1
+ (function(){
+ var a = [
+ 'a',
+ 'b',
+ 'c',
+ 'd',
+ 'e',
+ 'f',
+ 'g',
+ 'h',
+ 'i'
+ ];
+ }())
+
+ // 2
+ (function(){
+ var a = [
+ 0 +
+ 5 *
+ 9 *
+ 'a',
+ 'b',
+ 0 +
+ 5 *
+ 9 *
+ 'c',
+ 'd',
+ 'e',
+ 'f',
+ 'g',
+ 'h',
+ 'i'
+ ];
+ }())
+
+ // 3
+ (function(){
+ var a = [
+ 0 +
+ // comment 1
+ 5 *
+ /* comment 2 */
+ 9 *
+ 'a',
+ 'b',
+ 0 +
+ 5 *
+ 9 *
+ 'c',
+ 'd',
+ 'e',
+ 'f',
+ 'g',
+ 'h',
+ 'i'
+ ];
+ }())
+
+ // 4
+ {
+ var a = [
+ 0,
+ 1
+ ];
+ var b;
+ var c;
+ }
+
+ // 5
+ {
+ var a = [
+ [
+ 0
+ ],
+ 2,
+ 3
+ ];
+ }
+
+ // 6
+ {
+ var a = [
+ [
+ 0,
+ 1
+ ],
+ 2,
+ 3
+ ];
+ }
+
+ // 7
+ {
+ var a = [
+ // [
+ 0,
+ // 1
+ // ],
+ 2,
+ 3
+ ];
+ }
+
+ // 8
+ var x = [
+ (function(){
+ var a,
+ b,
+ c,
+ d,
+ e,
+ f,
+ g,
+ h,
+ i;
+ })
+ ];
+
+ // 9
+ var a = [
+ 0 +
+ 5 *
+ 9 *
+ 'a',
+ 'b',
+ 0 +
+ 5 *
+ 9 *
+ 'c',
+ 'd',
+ 'e',
+ 'f',
+ 'g',
+ 'h',
+ 'i'
+ ];
+
+ // 10
+ var a,
+ b,
+ c,
+ d,
+ e,
+ f,
+ g,
+ h,
+ i;
+ JSEND
+
+ [CODE]
+
+ call assert_equal(expected, getline(1, '$'))
+ enew! | close
+endfunc
+
+func Test_cindent_55()
+ new
+ setl cindent ts=4 sw=4
+ setl cino&
+
+ let code =<< trim [CODE]
+ /* start of define */
+ {
+ }
+ #define AAA \
+ BBB\
+ CCC
+
+ #define CNT \
+ 1 + \
+ 2 + \
+ 4
+ /* end of define */
+ [CODE]
+
+ call append(0, code)
+ normal gg
+ call search('start of define')
+ exe "normal =/end of define\n"
+
+ let expected =<< trim [CODE]
+ /* start of define */
+ {
+ }
+ #define AAA \
+ BBB\
+ CCC
+
+ #define CNT \
+ 1 + \
+ 2 + \
+ 4
+ /* end of define */
+
+ [CODE]
+
+ call assert_equal(expected, getline(1, '$'))
+ enew! | close
+endfunc
+
+func Test_cindent_56()
+ new
+ setl cindent ts=4 sw=4
+ setl cino&
+
+ let code =<< trim [CODE]
+ {
+ a = second/*bug*/*line;
+ }
+ [CODE]
+
+ call append(0, code)
+ normal gg
+ call search('a = second')
+ normal ox
+
+ let expected =<< trim [CODE]
+ {
+ a = second/*bug*/*line;
+ x
+ }
+
+ [CODE]
+
+ call assert_equal(expected, getline(1, '$'))
+ enew! | close
+endfunc
+
" this was going beyond the end of the line.
func Test_cindent_case()
new
- call setline(1, "case x: // x")
+ call setline(1, 'case x: // x')
set cindent
norm! f:a:
+ call assert_equal('case x:: // x', getline(1))
+ set cindent&
+ bwipe!
+endfunc
+
+" Test for changing multiple lines (using c) with cindent
+func Test_cindent_change_multline()
+ new
+ setlocal cindent
+ call setline(1, ['if (a)', '{', ' i = 1;', '}'])
+ normal! jc3jm = 2;
+ call assert_equal("\tm = 2;", getline(2))
+ close!
+endfunc
+
+" This was reading past the end of the line
+func Test_cindent_check_funcdecl()
+ new
+ sil norm o0('\0=L
bwipe!
endfunc
+func Test_cindent_scopedecls()
+ new
+ setl cindent ts=4 sw=4
+ setl cino=g0
+ setl cinsd+=public\ slots,signals
+
+ let code =<< trim [CODE]
+ class Foo
+ {
+ public:
+ virtual void foo() = 0;
+ public slots:
+ void onBar();
+ signals:
+ void baz();
+ private:
+ int x;
+ };
+ [CODE]
+
+ call append(0, code)
+ normal gg
+ normal ]]=][
+
+ let expected =<< trim [CODE]
+ class Foo
+ {
+ public:
+ virtual void foo() = 0;
+ public slots:
+ void onBar();
+ signals:
+ void baz();
+ private:
+ int x;
+ };
+
+ [CODE]
+
+ call assert_equal(expected, getline(1, '$'))
+ enew! | close
+endfunc
+
func Test_cindent_pragma()
new
setl cindent ts=4 sw=4
@@ -173,4 +5406,23 @@ func Test_cindent_pragma()
enew! | close
endfunc
+func Test_backslash_at_end_of_line()
+ new
+ exe "norm v>O'\\\<C-m>-"
+ exe "norm \<C-q>="
+ bwipe!
+endfunc
+
+func Test_find_brace_backwards()
+ " this was looking beyond the end of the line
+ new
+ norm R/*
+ norm o0{
+ norm o//
+ norm V{=
+ call assert_equal(['/*', ' 0{', '//'], getline(1, 3))
+ bwipe!
+endfunc
+
+
" vim: shiftwidth=2 sts=2 expandtab
diff --git a/src/nvim/testdir/test_clientserver.vim b/src/nvim/testdir/test_clientserver.vim
index 922803438f..db62fe5fa6 100644
--- a/src/nvim/testdir/test_clientserver.vim
+++ b/src/nvim/testdir/test_clientserver.vim
@@ -39,6 +39,8 @@ func Test_client_server()
call remote_send(name, ":let testvar = 'yes'\<CR>")
call WaitFor('remote_expr("' . name . '", "exists(\"testvar\") ? testvar : \"\"", "", 1) == "yes"')
call assert_equal('yes', remote_expr(name, "testvar", "", 2))
+ call assert_fails("let x=remote_expr(name, '2+x')", 'E449:')
+ call assert_fails("let x=remote_expr('[], '2+2')", 'E116:')
if has('unix') && has('gui') && !has('gui_running')
" Running in a terminal and the GUI is available: Tell the server to open
@@ -75,6 +77,7 @@ func Test_client_server()
eval 'MYSELF'->remote_startserver()
" May get MYSELF1 when running the test again.
call assert_match('MYSELF', v:servername)
+ call assert_fails("call remote_startserver('MYSELF')", 'E941:')
endif
let g:testvar = 'myself'
call assert_equal('myself', remote_expr(v:servername, 'testvar'))
@@ -107,7 +110,12 @@ func Test_client_server()
call job_stop(job, 'kill')
endif
endtry
+
+ call assert_fails("let x=remote_peek([])", 'E730:')
+ call assert_fails("let x=remote_read('vim10')", 'E277:')
endfunc
" Uncomment this line to get a debugging log
" call ch_logfile('channellog', 'w')
+
+" vim: shiftwidth=2 sts=2 expandtab
diff --git a/src/nvim/testdir/test_cmdline.vim b/src/nvim/testdir/test_cmdline.vim
index 1672b0e840..276bb7fb71 100644
--- a/src/nvim/testdir/test_cmdline.vim
+++ b/src/nvim/testdir/test_cmdline.vim
@@ -2,6 +2,7 @@
source check.vim
source screendump.vim
+source view_util.vim
func Test_complete_tab()
call writefile(['testfile'], 'Xtestfile')
@@ -18,6 +19,11 @@ func Test_complete_list()
" We can't see the output, but at least we check the code runs properly.
call feedkeys(":e test\<C-D>\r", "tx")
call assert_equal('test', expand('%:t'))
+
+ " If a command doesn't support completion, then CTRL-D should be literally
+ " used.
+ call feedkeys(":chistory \<C-D>\<C-B>\"\<CR>", 'xt')
+ call assert_equal("\"chistory \<C-D>", @:)
endfunc
func Test_complete_wildmenu()
@@ -71,6 +77,17 @@ func Test_complete_wildmenu()
cunmap <C-K>
endif
+ " Test for canceling the wild menu by adding a character
+ redrawstatus
+ call feedkeys(":e Xdir1/\<Tab>x\<C-B>\"\<CR>", 'xt')
+ call assert_equal('"e Xdir1/Xdir2/x', @:)
+
+ " Completion using a relative path
+ cd Xdir1/Xdir2
+ call feedkeys(":e ../\<Tab>\<Right>\<Down>\<C-A>\<C-B>\"\<CR>", 'tx')
+ call assert_equal('"e Xtestfile3 Xtestfile4', @:)
+ cd -
+
" cleanup
%bwipe
call delete('Xdir1/Xdir2/Xtestfile4')
@@ -305,7 +322,7 @@ func Test_getcompletion()
call assert_equal([], l)
let l = getcompletion('', 'dir')
- call assert_true(index(l, expand('sautest/')) >= 0)
+ call assert_true(index(l, 'sautest/') >= 0)
let l = getcompletion('NoMatch', 'dir')
call assert_equal([], l)
@@ -415,7 +432,7 @@ func Test_getcompletion()
" Command line completion tests
let l = getcompletion('cd ', 'cmdline')
- call assert_true(index(l, expand('sautest/')) >= 0)
+ call assert_true(index(l, 'sautest/') >= 0)
let l = getcompletion('cd NoMatch', 'cmdline')
call assert_equal([], l)
let l = getcompletion('let v:n', 'cmdline')
@@ -500,8 +517,16 @@ func Test_fullcommand()
for [in, want] in items(tests)
call assert_equal(want, fullcommand(in))
endfor
+ call assert_equal('', fullcommand(v:_null_string))
call assert_equal('syntax', 'syn'->fullcommand())
+
+ command -buffer BufferLocalCommand :
+ command GlobalCommand :
+ call assert_equal('GlobalCommand', fullcommand('GlobalCom'))
+ call assert_equal('BufferLocalCommand', fullcommand('BufferL'))
+ delcommand BufferLocalCommand
+ delcommand GlobalCommand
endfunc
func Test_shellcmd_completion()
@@ -531,7 +556,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 '.expand('a/b/fileXname'), getreg(':'))
+ call assert_equal('find a/b/fileXname', getreg(':'))
bwipe!
call delete('a', 'rf')
endfunc
@@ -573,6 +598,29 @@ func Test_cmdline_paste()
" ignore error E32
endtry
call assert_equal("Xtestfile", bufname("%"))
+
+ " Try to paste an invalid register using <C-R>
+ call feedkeys(":\"one\<C-R>\<C-X>two\<CR>", 'xt')
+ call assert_equal('"onetwo', @:)
+
+ " Test for pasting register containing CTRL-H using CTRL-R and CTRL-R CTRL-R
+ let @a = "xy\<C-H>z"
+ call feedkeys(":\"\<C-R>a\<CR>", 'xt')
+ call assert_equal('"xz', @:)
+ call feedkeys(":\"\<C-R>\<C-R>a\<CR>", 'xt')
+ call assert_equal("\"xy\<C-H>z", @:)
+ call feedkeys(":\"\<C-R>\<C-O>a\<CR>", 'xt')
+ call assert_equal("\"xy\<C-H>z", @:)
+
+ " Test for pasting register containing CTRL-V using CTRL-R and CTRL-R CTRL-R
+ let @a = "xy\<C-V>z"
+ call feedkeys(":\"\<C-R>=@a\<CR>\<cr>", 'xt')
+ call assert_equal('"xyz', @:)
+ call feedkeys(":\"\<C-R>\<C-R>=@a\<CR>\<cr>", 'xt')
+ call assert_equal("\"xy\<C-V>z", @:)
+
+ call assert_beeps('call feedkeys(":\<C-R>=\<C-R>=\<Esc>", "xt")')
+
bwipe!
endfunc
@@ -628,6 +676,14 @@ func Test_illegal_address2()
call delete('Xtest.vim')
endfunc
+func Test_mark_from_line_zero()
+ " this was reading past the end of the first (empty) line
+ new
+ norm oxxxx
+ call assert_fails("0;'(", 'E20:')
+ bwipe!
+endfunc
+
func Test_cmdline_complete_wildoptions()
help
call feedkeys(":tag /\<c-a>\<c-b>\"\<cr>", 'tx')
@@ -741,6 +797,15 @@ funct Test_cmdline_complete_languages()
endif
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
+
func Test_cmdline_complete_expression()
let g:SomeVar = 'blah'
for cmd in ['exe', 'echo', 'echon', 'echomsg']
@@ -752,6 +817,158 @@ func Test_cmdline_complete_expression()
unlet g:SomeVar
endfunc
+" Test for various command-line completion
+func Test_cmdline_complete_various()
+ " completion for a command starting with a comment
+ call feedkeys(": :|\"\<C-A>\<C-B>\"\<CR>", 'xt')
+ call assert_equal("\" :|\"\<C-A>", @:)
+
+ " completion for a range followed by a comment
+ call feedkeys(":1,2\"\<C-A>\<C-B>\"\<CR>", 'xt')
+ call assert_equal("\"1,2\"\<C-A>", @:)
+
+ " completion for :k command
+ call feedkeys(":ka\<C-A>\<C-B>\"\<CR>", 'xt')
+ call assert_equal("\"ka\<C-A>", @:)
+
+ " completion for short version of the :s command
+ call feedkeys(":sI \<C-A>\<C-B>\"\<CR>", 'xt')
+ call assert_equal("\"sI \<C-A>", @:)
+
+ " completion for :write command
+ call mkdir('Xdir')
+ call writefile(['one'], 'Xdir/Xfile1')
+ let save_cwd = getcwd()
+ cd Xdir
+ call feedkeys(":w >> \<C-A>\<C-B>\"\<CR>", 'xt')
+ call assert_equal("\"w >> Xfile1", @:)
+ call chdir(save_cwd)
+ call delete('Xdir', 'rf')
+
+ " completion for :w ! and :r ! commands
+ call feedkeys(":w !invalid_xyz_cmd\<C-A>\<C-B>\"\<CR>", 'xt')
+ call assert_equal("\"w !invalid_xyz_cmd", @:)
+ call feedkeys(":r !invalid_xyz_cmd\<C-A>\<C-B>\"\<CR>", 'xt')
+ call assert_equal("\"r !invalid_xyz_cmd", @:)
+
+ " completion for :>> and :<< commands
+ call feedkeys(":>>>\<C-A>\<C-B>\"\<CR>", 'xt')
+ call assert_equal("\">>>\<C-A>", @:)
+ call feedkeys(":<<<\<C-A>\<C-B>\"\<CR>", 'xt')
+ call assert_equal("\"<<<\<C-A>", @:)
+
+ " completion for command with +cmd argument
+ call feedkeys(":buffer +/pat Xabc\<C-A>\<C-B>\"\<CR>", 'xt')
+ call assert_equal("\"buffer +/pat Xabc", @:)
+ call feedkeys(":buffer +/pat\<C-A>\<C-B>\"\<CR>", 'xt')
+ call assert_equal("\"buffer +/pat\<C-A>", @:)
+
+ " completion for a command with a trailing comment
+ call feedkeys(":ls \" comment\<C-A>\<C-B>\"\<CR>", 'xt')
+ call assert_equal("\"ls \" comment\<C-A>", @:)
+
+ " completion for a command with a trailing command
+ call feedkeys(":ls | ls\<C-A>\<C-B>\"\<CR>", 'xt')
+ call assert_equal("\"ls | ls", @:)
+
+ " completion for a command with an CTRL-V escaped argument
+ call feedkeys(":ls \<C-V>\<C-V>a\<C-A>\<C-B>\"\<CR>", 'xt')
+ call assert_equal("\"ls \<C-V>a\<C-A>", @:)
+
+ " completion for a command that doesn't take additional arguments
+ call feedkeys(":all abc\<C-A>\<C-B>\"\<CR>", 'xt')
+ call assert_equal("\"all abc\<C-A>", @:)
+
+ " completion for a command with a command modifier
+ call feedkeys(":topleft new\<C-A>\<C-B>\"\<CR>", 'xt')
+ call assert_equal("\"topleft new", @:)
+
+ " completion for the :match command
+ 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>", @:)
+
+ " completion for the :augroup command
+ augroup XTest
+ augroup END
+ call feedkeys(":augroup X\<C-A>\<C-B>\"\<CR>", 'xt')
+ call assert_equal("\"augroup XTest", @:)
+ augroup! XTest
+
+ " completion for the :unlet command
+ call feedkeys(":unlet one two\<C-A>\<C-B>\"\<CR>", 'xt')
+ call assert_equal("\"unlet one two", @:)
+
+ " completion for the :buffer command with curlies
+ " FIXME: what should happen on MS-Windows?
+ if !has('win32')
+ edit \{someFile}
+ call feedkeys(":buf someFile\<C-A>\<C-B>\"\<CR>", 'xt')
+ call assert_equal("\"buf {someFile}", @:)
+ bwipe {someFile}
+ endif
+
+ " completion for the :bdelete command
+ call feedkeys(":bdel a b c\<C-A>\<C-B>\"\<CR>", 'xt')
+ call assert_equal("\"bdel a b c", @:)
+
+ " completion for the :mapclear command
+ call feedkeys(":mapclear \<C-A>\<C-B>\"\<CR>", 'xt')
+ call assert_equal("\"mapclear <buffer>", @:)
+
+ " completion for user defined commands with menu names
+ menu Test.foo :ls<CR>
+ com -nargs=* -complete=menu MyCmd
+ call feedkeys(":MyCmd Te\<C-A>\<C-B>\"\<CR>", 'xt')
+ call assert_equal('"MyCmd Test.', @:)
+ delcom MyCmd
+ unmenu Test
+
+ " completion for user defined commands with mappings
+ mapclear
+ map <F3> :ls<CR>
+ com -nargs=* -complete=mapping MyCmd
+ call feedkeys(":MyCmd <F\<C-A>\<C-B>\"\<CR>", 'xt')
+ call assert_equal('"MyCmd <F3>', @:)
+ mapclear
+ delcom MyCmd
+
+ " completion for :set path= with multiple backslashes
+ call feedkeys(":set path=a\\\\\\ b\<C-A>\<C-B>\"\<CR>", 'xt')
+ call assert_equal('"set path=a\\\ b', @:)
+
+ " completion for :set dir= with a backslash
+ call feedkeys(":set dir=a\\ b\<C-A>\<C-B>\"\<CR>", 'xt')
+ call assert_equal('"set dir=a\ b', @:)
+
+ " completion for the :py3 commands
+ call feedkeys(":py3\<C-A>\<C-B>\"\<CR>", 'xt')
+ call assert_equal('"py3 py3do py3file', @:)
+
+ " redir @" is not the start of a comment. So complete after that
+ call feedkeys(":redir @\" | cwin\t\<C-B>\"\<CR>", 'xt')
+ call assert_equal('"redir @" | cwindow', @:)
+
+ " completion after a backtick
+ 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("', @=)
+endfunc
+
func Test_cmdline_write_alternatefile()
new
call setline('.', ['one', 'two'])
@@ -793,9 +1010,32 @@ func Test_cmdline_search_range()
1,\&s/b/B/
call assert_equal('B', getline(2))
+ let @/ = 'apple'
+ call assert_fails('\/print', 'E486:')
+
bwipe!
endfunc
+" Test for the tick mark (') in an excmd range
+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_fails("',print", 'E78:')
+endfunc
+
+" Test for using a line number followed by a search pattern as range
+func Test_lnum_and_pattern_as_range()
+ new
+ call setline(1, ['foo 1', 'foo 2', 'foo 3'])
+ let @" = ''
+ 2/foo/yank
+ call assert_equal("foo 3\n", @")
+ call assert_equal(1, line('.'))
+ close!
+endfunc
+
" Tests for getcmdline(), getcmdpos() and getcmdtype()
func Check_cmdline(cmdtype)
call assert_equal('MyCmd a', getcmdline())
@@ -828,6 +1068,8 @@ func Test_getcmdtype()
cnoremap <expr> <F6> Check_cmdline('=')
call feedkeys("a\<C-R>=MyCmd a\<F6>\<Esc>\<Esc>", "xt")
cunmap <F6>
+
+ call assert_equal('', getcmdline())
endfunc
func Test_getcmdwintype()
@@ -877,22 +1119,6 @@ func Test_getcmdwin_autocmd()
augroup END
endfunc
-" Test error: "E135: *Filter* Autocommands must not change current buffer"
-func Test_cmd_bang_E135()
- new
- call setline(1, ['a', 'b', 'c', 'd'])
- augroup test_cmd_filter_E135
- au!
- autocmd FilterReadPost * help
- augroup END
- call assert_fails('2,3!echo "x"', 'E135:')
-
- augroup test_cmd_filter_E135
- au!
- augroup END
- %bwipe!
-endfunc
-
func Test_verbosefile()
set verbosefile=Xlog
echomsg 'foo'
@@ -973,34 +1199,6 @@ func Test_cmdline_overstrike()
let &encoding = encoding_save
endfunc
-func Test_cmdwin_feedkeys()
- " This should not generate E488
- call feedkeys("q:\<CR>", 'x')
-endfunc
-
-" Tests for the issues fixed in 7.4.441.
-" When 'cedit' is set to Ctrl-C, opening the command window hangs Vim
-func Test_cmdwin_cedit()
- exe "set cedit=\<C-c>"
- normal! :
- call assert_equal(1, winnr('$'))
-
- let g:cmd_wintype = ''
- func CmdWinType()
- let g:cmd_wintype = getcmdwintype()
- let g:wintype = win_gettype()
- return ''
- endfunc
-
- call feedkeys("\<C-c>a\<C-R>=CmdWinType()\<CR>\<CR>")
- echo input('')
- call assert_equal('@', g:cmd_wintype)
- call assert_equal('command', g:wintype)
-
- set cedit&vim
- delfunc CmdWinType
-endfunc
-
func Test_cmdwin_restore()
CheckScreendump
@@ -1077,6 +1275,38 @@ func Test_buffers_lastused()
bwipeout bufc
endfunc
+func Test_cmdwin_feedkeys()
+ " This should not generate E488
+ call feedkeys("q:\<CR>", 'x')
+ " Using feedkeys with q: only should automatically close the cmd window
+ call feedkeys('q:', 'xt')
+ call assert_equal(1, winnr('$'))
+ call assert_equal('', getcmdwintype())
+endfunc
+
+" Tests for the issues fixed in 7.4.441.
+" When 'cedit' is set to Ctrl-C, opening the command window hangs Vim
+func Test_cmdwin_cedit()
+ exe "set cedit=\<C-c>"
+ normal! :
+ call assert_equal(1, winnr('$'))
+
+ let g:cmd_wintype = ''
+ func CmdWinType()
+ let g:cmd_wintype = getcmdwintype()
+ let g:wintype = win_gettype()
+ return ''
+ endfunc
+
+ call feedkeys("\<C-c>a\<C-R>=CmdWinType()\<CR>\<CR>")
+ echo input('')
+ call assert_equal('@', g:cmd_wintype)
+ call assert_equal('command', g:wintype)
+
+ set cedit&vim
+ delfunc CmdWinType
+endfunc
+
" Test for CmdwinEnter autocmd
func Test_cmdwin_autocmd()
CheckFeature cmdwin
@@ -1115,6 +1345,377 @@ func Test_cmdlineclear_tabenter()
call delete('XtestCmdlineClearTabenter')
endfunc
+" Test for expanding special keywords in cmdline
+func Test_cmdline_expand_special()
+ new
+ %bwipe!
+ call assert_fails('e #', 'E194:')
+ 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
+ call feedkeys(":e %:r\<C-A>\<C-B>\"\<CR>", 'xt')
+ call assert_equal('"e Xfile.cpp Xfile.java', @:)
+ close
+ call delete('Xfile.cpp')
+ call delete('Xfile.java')
+endfunc
+
+func Test_cmdwin_jump_to_win()
+ call assert_fails('call feedkeys("q:\<C-W>\<C-W>\<CR>", "xt")', 'E11:')
+ new
+ set modified
+ call assert_fails('call feedkeys("q/:qall\<CR>", "xt")', 'E162:')
+ close!
+ call feedkeys("q/:close\<CR>", "xt")
+ call assert_equal(1, winnr('$'))
+ call feedkeys("q/:exit\<CR>", "xt")
+ call assert_equal(1, winnr('$'))
+
+ " opening command window twice should fail
+ call assert_beeps('call feedkeys("q:q:\<CR>\<CR>", "xt")')
+ call assert_equal(1, winnr('$'))
+endfunc
+
+" Test for backtick expression in the command line
+func Test_cmd_backtick()
+ %argd
+ argadd `=['a', 'b', 'c']`
+ call assert_equal(['a', 'b', 'c'], argv())
+ %argd
+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:')
+ tabclose!
+endfunc
+
+" Test for the :! command
+func Test_cmd_bang()
+ if !has('unix')
+ return
+ endif
+
+ let lines =<< trim [SCRIPT]
+ " Test for no previous command
+ call assert_fails('!!', 'E34:')
+ set nomore
+ " Test for cmdline expansion with :!
+ call setline(1, 'foo!')
+ silent !echo <cWORD> > Xfile.out
+ call assert_equal(['foo!'], readfile('Xfile.out'))
+ " Test for using previous command
+ silent !echo \! !
+ call assert_equal(['! echo foo!'], readfile('Xfile.out'))
+ call writefile(v:errors, 'Xresult')
+ call delete('Xfile.out')
+ qall!
+ [SCRIPT]
+ call writefile(lines, 'Xscript')
+ if RunVim([], [], '--clean -S Xscript')
+ call assert_equal([], readfile('Xresult'))
+ endif
+ call delete('Xscript')
+ call delete('Xresult')
+endfunc
+
+" Test error: "E135: *Filter* Autocommands must not change current buffer"
+func Test_cmd_bang_E135()
+ new
+ call setline(1, ['a', 'b', 'c', 'd'])
+ augroup test_cmd_filter_E135
+ au!
+ autocmd FilterReadPost * help
+ augroup END
+ call assert_fails('2,3!echo "x"', 'E135:')
+
+ augroup test_cmd_filter_E135
+ au!
+ augroup END
+ %bwipe!
+endfunc
+
+" Test for using ~ for home directory in cmdline completion matches
+func Test_cmdline_expand_home()
+ call mkdir('Xdir')
+ call writefile([], 'Xdir/Xfile1')
+ call writefile([], 'Xdir/Xfile2')
+ cd Xdir
+ let save_HOME = $HOME
+ let $HOME = getcwd()
+ call feedkeys(":e ~/\<C-A>\<C-B>\"\<CR>", 'xt')
+ call assert_equal('"e ~/Xfile1 ~/Xfile2', @:)
+ let $HOME = save_HOME
+ cd ..
+ call delete('Xdir', 'rf')
+endfunc
+
+" Test for using CTRL-\ CTRL-G in the command line to go back to normal mode
+" or insert mode (when 'insertmode' is set)
+func Test_cmdline_ctrl_g()
+ new
+ call setline(1, 'abc')
+ call cursor(1, 3)
+ " If command line is entered from insert mode, using C-\ C-G should back to
+ " insert mode
+ call feedkeys("i\<C-O>:\<C-\>\<C-G>xy", 'xt')
+ call assert_equal('abxyc', getline(1))
+ call assert_equal(4, col('.'))
+
+ " If command line is entered in 'insertmode', using C-\ C-G should back to
+ " 'insertmode'
+ " call feedkeys(":set im\<cr>\<C-L>:\<C-\>\<C-G>12\<C-L>:set noim\<cr>", 'xt')
+ " call assert_equal('ab12xyc', getline(1))
+ close!
+endfunc
+
+" Test for 'wildmode'
+func Test_wildmode()
+ 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 assert_equal('oneA oneB oneC', g:Sline)
+ call assert_equal('"MyCmd oneA', @:)
+
+ set wildmode=longest,full
+ call feedkeys(":MyCmd o\t\<C-B>\"\<CR>", 'xt')
+ call assert_equal('"MyCmd one', @:)
+ call feedkeys(":MyCmd o\t\t\t\t\<C-B>\"\<CR>", 'xt')
+ call assert_equal('"MyCmd oneC', @:)
+
+ set wildmode=longest
+ call feedkeys(":MyCmd one\t\t\<C-B>\"\<CR>", 'xt')
+ call assert_equal('"MyCmd one', @:)
+
+ set wildmode=list:longest
+ let g:Sline = ''
+ call feedkeys(":MyCmd \t\<F2>\<C-B>\"\<CR>", 'xt')
+ call assert_equal('oneA oneB oneC', g:Sline)
+ call assert_equal('"MyCmd one', @:)
+
+ set wildmode=""
+ call feedkeys(":MyCmd \t\t\<C-B>\"\<CR>", 'xt')
+ call assert_equal('"MyCmd oneA', @:)
+
+ " 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', @:)
+ 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 assert_equal('"b A', @:)
+
+ %argdelete
+ delcommand MyCmd
+ delfunc T
+ delfunc SaveScreenLine
+ cunmap <F2>
+ set wildmode&
+ %bwipe!
+endfunc
+
+" Test for interrupting the command-line completion
+func Test_interrupt_compl()
+ func F(lead, cmdl, p)
+ if a:lead =~ 'tw'
+ call interrupt()
+ return
+ endif
+ return "one\ntwo\nthree"
+ endfunc
+ command -nargs=1 -complete=custom,F Tcmd
+
+ set nowildmenu
+ set wildmode=full
+ let interrupted = 0
+ try
+ call feedkeys(":Tcmd tw\<Tab>\<C-B>\"\<CR>", 'xt')
+ catch /^Vim:Interrupt$/
+ let interrupted = 1
+ endtry
+ call assert_equal(1, interrupted)
+
+ delcommand Tcmd
+ delfunc F
+ set wildmode&
+endfunc
+
+" Test for moving the cursor on the : command line
+func Test_cmdline_edit()
+ let str = ":one two\<C-U>"
+ let str ..= "one two\<C-W>\<C-W>"
+ let str ..= "four\<BS>\<C-H>\<Del>\<kDel>"
+ let str ..= "\<Left>five\<Right>"
+ let str ..= "\<Home>two "
+ let str ..= "\<C-Left>one "
+ let str ..= "\<C-Right> three"
+ let str ..= "\<End>\<S-Left>four "
+ let str ..= "\<S-Right> six"
+ let str ..= "\<C-B>\"\<C-E> seven\<CR>"
+ call feedkeys(str, 'xt')
+ call assert_equal("\"one two three four five six seven", @:)
+endfunc
+
+" Test for moving the cursor on the / command line in 'rightleft' mode
+func Test_cmdline_edit_rightleft()
+ CheckFeature rightleft
+ set rightleft
+ set rightleftcmd=search
+ let str = "/one two\<C-U>"
+ let str ..= "one two\<C-W>\<C-W>"
+ let str ..= "four\<BS>\<C-H>\<Del>\<kDel>"
+ let str ..= "\<Right>five\<Left>"
+ let str ..= "\<Home>two "
+ let str ..= "\<C-Right>one "
+ let str ..= "\<C-Left> three"
+ let str ..= "\<End>\<S-Right>four "
+ let str ..= "\<S-Left> six"
+ let str ..= "\<C-B>\"\<C-E> seven\<CR>"
+ call assert_fails("call feedkeys(str, 'xt')", 'E486:')
+ call assert_equal("\"one two three four five six seven", @/)
+ set rightleftcmd&
+ set rightleft&
+endfunc
+
+" Test for using <C-\>e in the command line to evaluate an expression
+func Test_cmdline_expr()
+ " Evaluate an expression from the beginning of a command line
+ call feedkeys(":abc\<C-B>\<C-\>e\"\\\"hello\"\<CR>\<CR>", 'xt')
+ call assert_equal('"hello', @:)
+
+ " Use an invalid expression for <C-\>e
+ call assert_beeps('call feedkeys(":\<C-\>einvalid\<CR>", "tx")')
+
+ " Insert literal <CTRL-\> in the command line
+ call feedkeys(":\"e \<C-\>\<C-Y>\<CR>", 'xt')
+ call assert_equal("\"e \<C-\>\<C-Y>", @:)
+endfunc
+
+" Test for 'imcmdline' and 'imsearch'
+" This test doesn't actually test the input method functionality.
+func Test_cmdline_inputmethod()
+ new
+ call setline(1, ['', 'abc', ''])
+ set imcmdline
+
+ call feedkeys(":\"abc\<CR>", 'xt')
+ call assert_equal("\"abc", @:)
+ call feedkeys(":\"\<C-^>abc\<C-^>\<CR>", 'xt')
+ call assert_equal("\"abc", @:)
+ call feedkeys("/abc\<CR>", 'xt')
+ call assert_equal([2, 1], [line('.'), col('.')])
+ call feedkeys("/\<C-^>abc\<C-^>\<CR>", 'xt')
+ call assert_equal([2, 1], [line('.'), col('.')])
+
+ " set imsearch=2
+ call cursor(1, 1)
+ call feedkeys("/abc\<CR>", 'xt')
+ call assert_equal([2, 1], [line('.'), col('.')])
+ call cursor(1, 1)
+ call feedkeys("/\<C-^>abc\<C-^>\<CR>", 'xt')
+ call assert_equal([2, 1], [line('.'), col('.')])
+ set imdisable
+ call feedkeys("/\<C-^>abc\<C-^>\<CR>", 'xt')
+ call assert_equal([2, 1], [line('.'), col('.')])
+ set imdisable&
+ set imsearch&
+
+ set imcmdline&
+ %bwipe!
+endfunc
+
+" Test for recursively getting multiple command line inputs
+func Test_cmdwin_multi_input()
+ call feedkeys(":\<C-R>=input('P: ')\<CR>\"cyan\<CR>\<CR>", 'xt')
+ call assert_equal('"cyan', @:)
+endfunc
+
+" Test for using CTRL-_ in the command line with 'allowrevins'
+func Test_cmdline_revins()
+ CheckNotMSWindows
+ CheckFeature rightleft
+ call feedkeys(":\"abc\<c-_>\<cr>", 'xt')
+ call assert_equal("\"abc\<c-_>", @:)
+ set allowrevins
+ call feedkeys(":\"abc\<c-_>xyz\<c-_>\<CR>", 'xt')
+ call assert_equal('"abcñèæ', @:)
+ set allowrevins&
+endfunc
+
+" Test for typing UTF-8 composing characters in the command line
+func Test_cmdline_composing_chars()
+ call feedkeys(":\"\<C-V>u3046\<C-V>u3099\<CR>", 'xt')
+ call assert_equal('"ゔ', @:)
+endfunc
+
+" Test for normal mode commands not supported in the cmd window
+func Test_cmdwin_blocked_commands()
+ call assert_fails('call feedkeys("q:\<C-T>\<CR>", "xt")', 'E11:')
+ call assert_fails('call feedkeys("q:\<C-]>\<CR>", "xt")', 'E11:')
+ call assert_fails('call feedkeys("q:\<C-^>\<CR>", "xt")', 'E11:')
+ call assert_fails('call feedkeys("q:Q\<CR>", "xt")', 'E11:')
+ call assert_fails('call feedkeys("q:Z\<CR>", "xt")', 'E11:')
+ call assert_fails('call feedkeys("q:\<F1>\<CR>", "xt")', 'E11:')
+ call assert_fails('call feedkeys("q:\<C-W>s\<CR>", "xt")', 'E11:')
+ call assert_fails('call feedkeys("q:\<C-W>v\<CR>", "xt")', 'E11:')
+ call assert_fails('call feedkeys("q:\<C-W>^\<CR>", "xt")', 'E11:')
+ call assert_fails('call feedkeys("q:\<C-W>n\<CR>", "xt")', 'E11:')
+ call assert_fails('call feedkeys("q:\<C-W>z\<CR>", "xt")', 'E11:')
+ call assert_fails('call feedkeys("q:\<C-W>o\<CR>", "xt")', 'E11:')
+ call assert_fails('call feedkeys("q:\<C-W>w\<CR>", "xt")', 'E11:')
+ call assert_fails('call feedkeys("q:\<C-W>j\<CR>", "xt")', 'E11:')
+ call assert_fails('call feedkeys("q:\<C-W>k\<CR>", "xt")', 'E11:')
+ call assert_fails('call feedkeys("q:\<C-W>h\<CR>", "xt")', 'E11:')
+ call assert_fails('call feedkeys("q:\<C-W>l\<CR>", "xt")', 'E11:')
+ call assert_fails('call feedkeys("q:\<C-W>T\<CR>", "xt")', 'E11:')
+ call assert_fails('call feedkeys("q:\<C-W>x\<CR>", "xt")', 'E11:')
+ call assert_fails('call feedkeys("q:\<C-W>r\<CR>", "xt")', 'E11:')
+ call assert_fails('call feedkeys("q:\<C-W>R\<CR>", "xt")', 'E11:')
+ call assert_fails('call feedkeys("q:\<C-W>K\<CR>", "xt")', 'E11:')
+ call assert_fails('call feedkeys("q:\<C-W>}\<CR>", "xt")', 'E11:')
+ call assert_fails('call feedkeys("q:\<C-W>]\<CR>", "xt")', 'E11:')
+ call assert_fails('call feedkeys("q:\<C-W>f\<CR>", "xt")', 'E11:')
+ call assert_fails('call feedkeys("q:\<C-W>d\<CR>", "xt")', 'E11:')
+ call assert_fails('call feedkeys("q:\<C-W>g\<CR>", "xt")', 'E11:')
+endfunc
+
+" Close the Cmd-line window in insert mode using CTRL-C
+func Test_cmdwin_insert_mode_close()
+ %bw!
+ let s = ''
+ exe "normal q:a\<C-C>let s='Hello'\<CR>"
+ call assert_equal('Hello', s)
+ call assert_equal(1, winnr('$'))
+endfunc
+
" test that ";" works to find a match at the start of the first line
func Test_zero_line_search()
new
@@ -1192,4 +1793,57 @@ func Test_recalling_cmdline()
cunmap <Plug>(save-cmdline)
endfunc
+" this was going over the end of IObuff
+func Test_report_error_with_composing()
+ let caught = 'no'
+ try
+ exe repeat('0', 987) .. "0\xdd\x80\xdd\x80\xdd\x80\xdd\x80"
+ catch /E492:/
+ let caught = 'yes'
+ endtry
+ call assert_equal('yes', caught)
+endfunc
+
+" Test for expanding 2-letter and 3-letter :substitute command arguments.
+" These commands don't accept an argument.
+func Test_cmdline_complete_substitute_short()
+ for cmd in ['sc', 'sce', 'scg', 'sci', 'scI', 'scn', 'scp', 'scl',
+ \ 'sgc', 'sge', 'sg', 'sgi', 'sgI', 'sgn', 'sgp', 'sgl', 'sgr',
+ \ 'sic', 'sie', 'si', 'siI', 'sin', 'sip', 'sir',
+ \ 'sIc', 'sIe', 'sIg', 'sIi', 'sI', 'sIn', 'sIp', 'sIl', 'sIr',
+ \ 'src', 'srg', 'sri', 'srI', 'srn', 'srp', 'srl', 'sr']
+ call feedkeys(':' .. cmd .. " \<Tab>\<C-B>\"\<CR>", 'tx')
+ call assert_equal('"' .. cmd .. " \<Tab>", @:)
+ endfor
+endfunc
+
+func Check_completion()
+ call assert_equal('let a', getcmdline())
+ call assert_equal(6, getcmdpos())
+ call assert_equal(7, getcmdscreenpos())
+ call assert_equal('var', getcmdcompltype())
+ return ''
+endfunc
+
+func Test_screenpos_and_completion()
+ call feedkeys(":let a\<C-R>=Check_completion()\<CR>\<Esc>", "xt")
+endfunc
+
+func Test_recursive_register()
+ let @= = ''
+ silent! ?e/
+ let caught = 'no'
+ try
+ normal //
+ catch /E169:/
+ let caught = 'yes'
+ endtry
+ call assert_equal('yes', caught)
+endfunc
+
+func Test_long_error_message()
+ " the error should be truncated, not overrun IObuff
+ silent! norm Q00000000000000     000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000                                                                                                                                                                                                                        
+endfunc
+
" vim: shiftwidth=2 sts=2 expandtab
diff --git a/src/nvim/testdir/test_command_count.vim b/src/nvim/testdir/test_command_count.vim
index c7dddf4164..55b230373f 100644
--- a/src/nvim/testdir/test_command_count.vim
+++ b/src/nvim/testdir/test_command_count.vim
@@ -33,7 +33,7 @@ func Test_command_count_0()
delcommand RangeBuffers
delcommand RangeBuffersAll
- set nohidden
+ set hidden&
set swapfile&
endfunc
diff --git a/src/nvim/testdir/test_compiler.vim b/src/nvim/testdir/test_compiler.vim
index aaa2301bca..3dc8710d63 100644
--- a/src/nvim/testdir/test_compiler.vim
+++ b/src/nvim/testdir/test_compiler.vim
@@ -19,6 +19,9 @@ func Test_compiler()
call assert_equal('perl', b:current_compiler)
call assert_fails('let g:current_compiler', 'E121:')
+ let verbose_efm = execute('verbose set efm')
+ call assert_match('Last set from .*[/\\]compiler[/\\]perl.vim ', verbose_efm)
+
call setline(1, ['#!/usr/bin/perl -w', 'use strict;', 'my $foo=1'])
w!
call feedkeys(":make\<CR>\<CR>", 'tx')
@@ -65,5 +68,9 @@ func Test_compiler_completion()
endfunc
func Test_compiler_error()
+ let g:current_compiler = 'abc'
call assert_fails('compiler doesnotexist', 'E666:')
+ call assert_equal('abc', g:current_compiler)
+ call assert_fails('compiler! doesnotexist', 'E666:')
+ unlet! g:current_compiler
endfunc
diff --git a/src/nvim/testdir/test_conceal.vim b/src/nvim/testdir/test_conceal.vim
index 1306dbe5cf..bffc2f49d3 100644
--- a/src/nvim/testdir/test_conceal.vim
+++ b/src/nvim/testdir/test_conceal.vim
@@ -4,10 +4,10 @@ source check.vim
CheckFeature conceal
source screendump.vim
-" CheckScreendump
func Test_conceal_two_windows()
CheckScreendump
+
let code =<< trim [CODE]
let lines = ["one one one one one", "two |hidden| here", "three |hidden| three"]
call setline(1, lines)
@@ -111,6 +111,7 @@ endfunc
func Test_conceal_with_cursorline()
CheckScreendump
+
" Opens a help window, where 'conceal' is set, switches to the other window
" where 'cursorline' needs to be updated when the cursor moves.
let code =<< trim [CODE]
@@ -139,6 +140,7 @@ endfunc
func Test_conceal_resize_term()
CheckScreendump
+
let code =<< trim [CODE]
call setline(1, '`one` `two` `three` `four` `five`, the backticks should be concealed')
setl cocu=n cole=3
diff --git a/src/nvim/testdir/test_cscope.vim b/src/nvim/testdir/test_cscope.vim
index cc6154af69..76ea35fa10 100644
--- a/src/nvim/testdir/test_cscope.vim
+++ b/src/nvim/testdir/test_cscope.vim
@@ -1,7 +1,11 @@
" Test for cscope commands.
-if !has('cscope') || !executable('cscope') || !has('quickfix')
- finish
+source check.vim
+CheckFeature cscope
+CheckFeature quickfix
+
+if !executable('cscope')
+ throw 'Skipped: cscope program missing'
endif
func CscopeSetupOrClean(setup)
@@ -102,7 +106,7 @@ func Test_cscopeWithCscopeConnections()
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\+C')
+ call assert_true(a =~ '"Xmemfile_test.c" \d\+L, \d\+B')
call assert_equal('Xmemfile_test.c', @%)
endfor
@@ -112,7 +116,7 @@ func Test_cscopeWithCscopeConnections()
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\+C')
+ 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
diff --git a/src/nvim/testdir/test_cursor_func.vim b/src/nvim/testdir/test_cursor_func.vim
index e8c4a952ee..3b8a5f27ad 100644
--- a/src/nvim/testdir/test_cursor_func.vim
+++ b/src/nvim/testdir/test_cursor_func.vim
@@ -1,4 +1,4 @@
-" Tests for cursor().
+" Tests for cursor() and other functions that get/set the cursor position
func Test_wrong_arguments()
call assert_fails('call cursor(1. 3)', 'E474:')
@@ -24,6 +24,9 @@ func Test_move_cursor()
" below last line goes to last line
call cursor(9, 1)
call assert_equal([4, 1, 0, 1], getcurpos()[1:])
+ " pass string arguments
+ call cursor('3', '3')
+ call assert_equal([3, 3, 0, 3], getcurpos()[1:])
call setline(1, ["\<TAB>"])
call cursor(1, 1, 1)
@@ -72,7 +75,6 @@ func Test_curswant_with_cursorline()
endfunc
func Test_screenpos()
- throw 'skipped: TODO: '
rightbelow new
rightbelow 20vsplit
call setline(1, ["\tsome text", "long wrapping line here", "next line"])
@@ -97,12 +99,15 @@ func Test_screenpos()
\ 'curscol': wincol + 9,
\ 'endcol': wincol + 9}, screenpos(winid, 2, 22))
close
+ call assert_equal({}, screenpos(999, 1, 1))
bwipe!
call assert_equal({'col': 1, 'row': 1, 'endcol': 1, 'curscol': 1}, screenpos(win_getid(), 1, 1))
- nmenu WinBar.TEST :
+ " nmenu WinBar.TEST :
+ setlocal winbar=TEST
call assert_equal({'col': 1, 'row': 2, 'endcol': 1, 'curscol': 1}, screenpos(win_getid(), 1, 1))
- nunmenu WinBar.TEST
+ " nunmenu WinBar.TEST
+ setlocal winbar&
endfunc
func Test_screenpos_number()
@@ -119,3 +124,253 @@ func Test_screenpos_number()
close
bwipe!
endfunc
+
+" Save the visual start character position
+func SaveVisualStartCharPos()
+ call add(g:VisualStartPos, getcharpos('v'))
+ return ''
+endfunc
+
+" Save the current cursor character position in insert mode
+func SaveInsertCurrentCharPos()
+ call add(g:InsertCurrentPos, getcharpos('.'))
+ return ''
+endfunc
+
+" Test for the getcharpos() function
+func Test_getcharpos()
+ call assert_fails('call getcharpos({})', 'E731:')
+ call assert_equal([0, 0, 0, 0], getcharpos(0))
+ new
+ call setline(1, ['', "01\tà4è678", 'Ⅵ', '012345678', ' │ x'])
+
+ " Test for '.' and '$'
+ normal 1G
+ call assert_equal([0, 1, 1, 0], getcharpos('.'))
+ call assert_equal([0, 5, 1, 0], getcharpos('$'))
+ normal 2G6l
+ call assert_equal([0, 2, 7, 0], getcharpos('.'))
+ normal 3G$
+ call assert_equal([0, 3, 1, 0], getcharpos('.'))
+ normal 4G$
+ call assert_equal([0, 4, 9, 0], getcharpos('.'))
+
+ " Test for a mark
+ normal 2G7lmmgg
+ call assert_equal([0, 2, 8, 0], getcharpos("'m"))
+ delmarks m
+ call assert_equal([0, 0, 0, 0], getcharpos("'m"))
+
+ " Check mark does not move
+ normal 5Gfxma
+ call assert_equal([0, 5, 5, 0], getcharpos("'a"))
+ call assert_equal([0, 5, 5, 0], getcharpos("'a"))
+ call assert_equal([0, 5, 5, 0], getcharpos("'a"))
+
+ " Test for the visual start column
+ vnoremap <expr> <F3> SaveVisualStartCharPos()
+ let g:VisualStartPos = []
+ exe "normal 2G6lv$\<F3>ohh\<F3>o\<F3>"
+ call assert_equal([[0, 2, 7, 0], [0, 2, 10, 0], [0, 2, 5, 0]], g:VisualStartPos)
+ call assert_equal([0, 2, 9, 0], getcharpos('v'))
+ let g:VisualStartPos = []
+ exe "normal 3Gv$\<F3>o\<F3>"
+ call assert_equal([[0, 3, 1, 0], [0, 3, 2, 0]], g:VisualStartPos)
+ let g:VisualStartPos = []
+ exe "normal 1Gv$\<F3>o\<F3>"
+ call assert_equal([[0, 1, 1, 0], [0, 1, 1, 0]], g:VisualStartPos)
+ vunmap <F3>
+
+ " Test for getting the position in insert mode with the cursor after the
+ " last character in a line
+ inoremap <expr> <F3> SaveInsertCurrentCharPos()
+ let g:InsertCurrentPos = []
+ exe "normal 1GA\<F3>"
+ exe "normal 2GA\<F3>"
+ exe "normal 3GA\<F3>"
+ exe "normal 4GA\<F3>"
+ exe "normal 2G6li\<F3>"
+ call assert_equal([[0, 1, 1, 0], [0, 2, 10, 0], [0, 3, 2, 0], [0, 4, 10, 0],
+ \ [0, 2, 7, 0]], g:InsertCurrentPos)
+ iunmap <F3>
+
+ %bw!
+endfunc
+
+" Test for the setcharpos() function
+func Test_setcharpos()
+ call assert_equal(-1, setcharpos('.', v:_null_list))
+ new
+ call setline(1, ['', "01\tà4è678", 'Ⅵ', '012345678'])
+ call setcharpos('.', [0, 1, 1, 0])
+ call assert_equal([1, 1], [line('.'), col('.')])
+ call setcharpos('.', [0, 2, 7, 0])
+ call assert_equal([2, 9], [line('.'), col('.')])
+ call setcharpos('.', [0, 3, 4, 0])
+ call assert_equal([3, 1], [line('.'), col('.')])
+ call setcharpos('.', [0, 3, 1, 0])
+ call assert_equal([3, 1], [line('.'), col('.')])
+ call setcharpos('.', [0, 4, 0, 0])
+ call assert_equal([4, 1], [line('.'), col('.')])
+ call setcharpos('.', [0, 4, 20, 0])
+ call assert_equal([4, 9], [line('.'), col('.')])
+
+ " Test for mark
+ delmarks m
+ call setcharpos("'m", [0, 2, 9, 0])
+ normal `m
+ call assert_equal([2, 11], [line('.'), col('.')])
+ " unload the buffer and try to set the mark
+ let bnr = bufnr()
+ enew!
+ call assert_equal(-1, setcharpos("'m", [bnr, 2, 2, 0]))
+
+ %bw!
+ call assert_equal(-1, setcharpos('.', [10, 3, 1, 0]))
+endfunc
+
+func SaveVisualStartCharCol()
+ call add(g:VisualStartCol, charcol('v'))
+ return ''
+endfunc
+
+func SaveInsertCurrentCharCol()
+ call add(g:InsertCurrentCol, charcol('.'))
+ return ''
+endfunc
+
+" Test for the charcol() function
+func Test_charcol()
+ call assert_fails('call charcol({})', 'E731:')
+ call assert_equal(0, charcol(0))
+ new
+ call setline(1, ['', "01\tà4è678", 'Ⅵ', '012345678'])
+
+ " Test for '.' and '$'
+ normal 1G
+ call assert_equal(1, charcol('.'))
+ call assert_equal(1, charcol('$'))
+ normal 2G6l
+ call assert_equal(7, charcol('.'))
+ call assert_equal(10, charcol('$'))
+ normal 3G$
+ call assert_equal(1, charcol('.'))
+ call assert_equal(2, charcol('$'))
+ normal 4G$
+ call assert_equal(9, charcol('.'))
+ call assert_equal(10, charcol('$'))
+
+ " Test for [lnum, '$']
+ call assert_equal(1, charcol([1, '$']))
+ call assert_equal(10, charcol([2, '$']))
+ call assert_equal(2, charcol([3, '$']))
+ call assert_equal(0, charcol([5, '$']))
+
+ " Test for a mark
+ normal 2G7lmmgg
+ call assert_equal(8, charcol("'m"))
+ delmarks m
+ call assert_equal(0, charcol("'m"))
+
+ " Test for the visual start column
+ vnoremap <expr> <F3> SaveVisualStartCharCol()
+ let g:VisualStartCol = []
+ exe "normal 2G6lv$\<F3>ohh\<F3>o\<F3>"
+ call assert_equal([7, 10, 5], g:VisualStartCol)
+ call assert_equal(9, charcol('v'))
+ let g:VisualStartCol = []
+ exe "normal 3Gv$\<F3>o\<F3>"
+ call assert_equal([1, 2], g:VisualStartCol)
+ let g:VisualStartCol = []
+ exe "normal 1Gv$\<F3>o\<F3>"
+ call assert_equal([1, 1], g:VisualStartCol)
+ vunmap <F3>
+
+ " Test for getting the column number in insert mode with the cursor after
+ " the last character in a line
+ inoremap <expr> <F3> SaveInsertCurrentCharCol()
+ let g:InsertCurrentCol = []
+ exe "normal 1GA\<F3>"
+ exe "normal 2GA\<F3>"
+ exe "normal 3GA\<F3>"
+ exe "normal 4GA\<F3>"
+ exe "normal 2G6li\<F3>"
+ call assert_equal([1, 10, 2, 10, 7], g:InsertCurrentCol)
+ iunmap <F3>
+
+ %bw!
+endfunc
+
+func SaveInsertCursorCharPos()
+ call add(g:InsertCursorPos, getcursorcharpos('.'))
+ return ''
+endfunc
+
+" Test for getcursorcharpos()
+func Test_getcursorcharpos()
+ call assert_equal(getcursorcharpos(), getcursorcharpos(0))
+ call assert_equal([0, 0, 0, 0, 0], getcursorcharpos(-1))
+ call assert_equal([0, 0, 0, 0, 0], getcursorcharpos(1999))
+
+ new
+ call setline(1, ['', "01\tà4è678", 'Ⅵ', '012345678'])
+ normal 1G9l
+ call assert_equal([0, 1, 1, 0, 1], getcursorcharpos())
+ normal 2G9l
+ call assert_equal([0, 2, 9, 0, 14], getcursorcharpos())
+ normal 3G9l
+ call assert_equal([0, 3, 1, 0, 1], getcursorcharpos())
+ normal 4G9l
+ call assert_equal([0, 4, 9, 0, 9], getcursorcharpos())
+
+ " Test for getting the cursor position in insert mode with the cursor after
+ " the last character in a line
+ inoremap <expr> <F3> SaveInsertCursorCharPos()
+ let g:InsertCursorPos = []
+ exe "normal 1GA\<F3>"
+ exe "normal 2GA\<F3>"
+ exe "normal 3GA\<F3>"
+ exe "normal 4GA\<F3>"
+ exe "normal 2G6li\<F3>"
+ call assert_equal([[0, 1, 1, 0, 1], [0, 2, 10, 0, 15], [0, 3, 2, 0, 2],
+ \ [0, 4, 10, 0, 10], [0, 2, 7, 0, 12]], g:InsertCursorPos)
+ iunmap <F3>
+
+ let winid = win_getid()
+ normal 2G5l
+ wincmd w
+ call assert_equal([0, 2, 6, 0, 11], getcursorcharpos(winid))
+ %bw!
+endfunc
+
+" Test for setcursorcharpos()
+func Test_setcursorcharpos()
+ call assert_fails('call setcursorcharpos(v:_null_list)', 'E474:')
+ call assert_fails('call setcursorcharpos([1])', 'E474:')
+ call assert_fails('call setcursorcharpos([1, 1, 1, 1, 1])', 'E474:')
+ new
+ call setline(1, ['', "01\tà4è678", 'Ⅵ', '012345678'])
+ 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(3, 4)
+ call assert_equal([3, 1], [line('.'), col('.')])
+ call setcursorcharpos([3, 1])
+ call assert_equal([3, 1], [line('.'), col('.')])
+ call setcursorcharpos([4, 0, 0, 0])
+ call assert_equal([4, 1], [line('.'), col('.')])
+ call setcursorcharpos([4, 20])
+ call assert_equal([4, 9], [line('.'), col('.')])
+ normal 1G
+ call setcursorcharpos([100, 100, 100, 100])
+ call assert_equal([4, 9], [line('.'), col('.')])
+ normal 1G
+ call setcursorcharpos('$', 1)
+ call assert_equal([4, 1], [line('.'), col('.')])
+
+ %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 39d8b901ed..e85e9304a3 100644
--- a/src/nvim/testdir/test_cursorline.vim
+++ b/src/nvim/testdir/test_cursorline.vim
@@ -268,4 +268,87 @@ END
call delete('Xtextfile')
endfunc
+func Test_cursorline_callback()
+ CheckScreendump
+ CheckFeature timers
+
+ let lines =<< trim END
+ call setline(1, ['aaaaa', 'bbbbb', 'ccccc', 'ddddd'])
+ set cursorline
+ call cursor(4, 1)
+
+ func Func(timer)
+ call cursor(2, 1)
+ endfunc
+
+ call timer_start(300, 'Func')
+ END
+ call writefile(lines, 'Xcul_timer')
+
+ let buf = RunVimInTerminal('-S Xcul_timer', #{rows: 8})
+ call TermWait(buf, 310)
+ call VerifyScreenDump(buf, 'Test_cursorline_callback_1', {})
+
+ call StopVimInTerminal(buf)
+ call delete('Xcul_timer')
+endfunc
+
+func Test_cursorline_screenline_update()
+ CheckScreendump
+
+ let lines =<< trim END
+ call setline(1, repeat('xyz ', 30))
+ set cursorline cursorlineopt=screenline
+ inoremap <F2> <Cmd>call cursor(1, 1)<CR>
+ END
+ call writefile(lines, 'Xcul_screenline')
+
+ let buf = RunVimInTerminal('-S Xcul_screenline', #{rows: 8})
+ call term_sendkeys(buf, "A")
+ call VerifyScreenDump(buf, 'Test_cursorline_screenline_1', {})
+ call term_sendkeys(buf, "\<F2>")
+ call VerifyScreenDump(buf, 'Test_cursorline_screenline_2', {})
+ call term_sendkeys(buf, "\<Esc>")
+
+ call StopVimInTerminal(buf)
+ call delete('Xcul_screenline')
+endfunc
+
+func Test_cursorline_cursorbind_horizontal_scroll()
+ CheckScreendump
+
+ 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')
+ set nowrap
+ " The following makes the cursor apparent on the screen dump
+ set sidescroll=1 cursorcolumn
+ " add empty lines, required for cursorcolumn
+ call append(1, ['','','',''])
+ 20vsp
+ windo :set cursorbind
+ END
+ call writefile(lines, 'Xhor_scroll')
+
+ let buf = RunVimInTerminal('-S Xhor_scroll', #{rows: 8})
+ call term_sendkeys(buf, "20l")
+ call VerifyScreenDump(buf, 'Test_hor_scroll_1', {})
+ call term_sendkeys(buf, "10l")
+ call VerifyScreenDump(buf, 'Test_hor_scroll_2', {})
+ call term_sendkeys(buf, ":windo :set cursorline\<cr>")
+ call term_sendkeys(buf, "0")
+ call term_sendkeys(buf, "20l")
+ call VerifyScreenDump(buf, 'Test_hor_scroll_3', {})
+ call term_sendkeys(buf, "10l")
+ call VerifyScreenDump(buf, 'Test_hor_scroll_4', {})
+ call term_sendkeys(buf, ":windo :set nocursorline nocursorcolumn\<cr>")
+ call term_sendkeys(buf, "0")
+ call term_sendkeys(buf, "40l")
+ call VerifyScreenDump(buf, 'Test_hor_scroll_5', {})
+
+ call StopVimInTerminal(buf)
+ call delete('Xhor_scroll')
+endfunc
+
+
" vim: shiftwidth=2 sts=2 expandtab
diff --git a/src/nvim/testdir/test_debugger.vim b/src/nvim/testdir/test_debugger.vim
index a396efc09e..e038c0096a 100644
--- a/src/nvim/testdir/test_debugger.vim
+++ b/src/nvim/testdir/test_debugger.vim
@@ -976,7 +976,7 @@ func Test_debug_backtrace_level()
\ 'line 1: let s:file1_var = ''file1'''
\ ])
- " step throught the initial declarations
+ " step through the initial declarations
call RunDbgCmd(buf, 'step', [ 'line 2: let g:global_var = ''global''' ] )
call RunDbgCmd(buf, 'step', [ 'line 4: func s:File1Func( arg )' ] )
call RunDbgCmd(buf, 'echo s:file1_var', [ 'file1' ] )
diff --git a/src/nvim/testdir/test_delete.vim b/src/nvim/testdir/test_delete.vim
new file mode 100644
index 0000000000..b23a3bd025
--- /dev/null
+++ b/src/nvim/testdir/test_delete.vim
@@ -0,0 +1,114 @@
+" Test for delete().
+
+func Test_file_delete()
+ split Xfile
+ call setline(1, ['a', 'b'])
+ wq
+ call assert_equal(['a', 'b'], readfile('Xfile'))
+ call assert_equal(0, delete('Xfile'))
+ call assert_fails('call readfile("Xfile")', 'E484:')
+ call assert_equal(-1, delete('Xfile'))
+ bwipe Xfile
+endfunc
+
+func Test_dir_delete()
+ call mkdir('Xdir1')
+ call assert_true(isdirectory('Xdir1'))
+ call assert_equal(0, delete('Xdir1', 'd'))
+ call assert_false(isdirectory('Xdir1'))
+ call assert_equal(-1, delete('Xdir1', 'd'))
+endfunc
+
+func Test_recursive_delete()
+ call mkdir('Xdir1')
+ call mkdir('Xdir1/subdir')
+ call mkdir('Xdir1/empty')
+ split Xdir1/Xfile
+ call setline(1, ['a', 'b'])
+ w
+ w Xdir1/subdir/Xfile
+ close
+ call assert_true(isdirectory('Xdir1'))
+ call assert_equal(['a', 'b'], readfile('Xdir1/Xfile'))
+ call assert_true(isdirectory('Xdir1/subdir'))
+ call assert_equal(['a', 'b'], readfile('Xdir1/subdir/Xfile'))
+ call assert_true('Xdir1/empty'->isdirectory())
+ call assert_equal(0, delete('Xdir1', 'rf'))
+ call assert_false(isdirectory('Xdir1'))
+ call assert_equal(-1, delete('Xdir1', 'd'))
+ bwipe Xdir1/Xfile
+ bwipe Xdir1/subdir/Xfile
+endfunc
+
+func Test_symlink_delete()
+ if !has('unix')
+ return
+ endif
+ split Xfile
+ call setline(1, ['a', 'b'])
+ wq
+ silent !ln -s Xfile Xlink
+ " Delete the link, not the file
+ call assert_equal(0, delete('Xlink'))
+ call assert_equal(-1, delete('Xlink'))
+ call assert_equal(0, delete('Xfile'))
+ bwipe Xfile
+endfunc
+
+func Test_symlink_dir_delete()
+ if !has('unix')
+ return
+ endif
+ call mkdir('Xdir1')
+ silent !ln -s Xdir1 Xlink
+ call assert_true(isdirectory('Xdir1'))
+ call assert_true(isdirectory('Xlink'))
+ " Delete the link, not the directory
+ call assert_equal(0, delete('Xlink'))
+ call assert_equal(-1, delete('Xlink'))
+ call assert_equal(0, delete('Xdir1', 'd'))
+endfunc
+
+func Test_symlink_recursive_delete()
+ if !has('unix')
+ return
+ endif
+ call mkdir('Xdir3')
+ call mkdir('Xdir3/subdir')
+ call mkdir('Xdir4')
+ split Xdir3/Xfile
+ call setline(1, ['a', 'b'])
+ w
+ w Xdir3/subdir/Xfile
+ w Xdir4/Xfile
+ close
+ silent !ln -s ../Xdir4 Xdir3/Xlink
+
+ call assert_true(isdirectory('Xdir3'))
+ call assert_equal(['a', 'b'], readfile('Xdir3/Xfile'))
+ call assert_true(isdirectory('Xdir3/subdir'))
+ call assert_equal(['a', 'b'], readfile('Xdir3/subdir/Xfile'))
+ call assert_true(isdirectory('Xdir4'))
+ call assert_true(isdirectory('Xdir3/Xlink'))
+ call assert_equal(['a', 'b'], readfile('Xdir4/Xfile'))
+
+ call assert_equal(0, delete('Xdir3', 'rf'))
+ call assert_false(isdirectory('Xdir3'))
+ call assert_equal(-1, delete('Xdir3', 'd'))
+ " symlink is deleted, not the directory it points to
+ call assert_true(isdirectory('Xdir4'))
+ call assert_equal(['a', 'b'], readfile('Xdir4/Xfile'))
+ call assert_equal(0, delete('Xdir4/Xfile'))
+ call assert_equal(0, delete('Xdir4', 'd'))
+
+ bwipe Xdir3/Xfile
+ bwipe Xdir3/subdir/Xfile
+ bwipe Xdir4/Xfile
+endfunc
+
+func Test_delete_errors()
+ call assert_fails('call delete('''')', 'E474:')
+ call assert_fails('call delete(''foo'', 0)', 'E15:')
+endfunc
+
+" vim: shiftwidth=2 sts=2 expandtab
diff --git a/src/nvim/testdir/test_diffmode.vim b/src/nvim/testdir/test_diffmode.vim
index 3a0c615cf6..8c20c647f1 100644
--- a/src/nvim/testdir/test_diffmode.vim
+++ b/src/nvim/testdir/test_diffmode.vim
@@ -540,7 +540,7 @@ func Test_diffopt_hiddenoff()
bwipe!
bwipe!
- set nohidden diffopt&
+ set hidden& diffopt&
endfunc
func Test_diffoff_hidden()
@@ -577,7 +577,7 @@ func Test_diffoff_hidden()
bwipe!
bwipe!
- set nohidden diffopt&
+ set hidden& diffopt&
endfunc
func Test_setting_cursor()
@@ -1017,6 +1017,32 @@ func Test_diff_with_cursorline()
call delete('Xtest_diff_cursorline')
endfunc
+func Test_diff_with_cursorline_number()
+ CheckScreendump
+
+ let lines =<< trim END
+ hi CursorLine ctermbg=red ctermfg=white
+ hi CursorLineNr ctermbg=white ctermfg=black cterm=underline
+ set cursorline number
+ call setline(1, ["baz", "foo", "foo", "bar"])
+ 2
+ vnew
+ call setline(1, ["foo", "foo", "bar"])
+ windo diffthis
+ 1wincmd w
+ END
+ call writefile(lines, 'Xtest_diff_cursorline_number')
+ let buf = RunVimInTerminal('-S Xtest_diff_cursorline_number', {})
+
+ call VerifyScreenDump(buf, 'Test_diff_with_cursorline_number_01', {})
+ call term_sendkeys(buf, ":set cursorlineopt=number\r")
+ call VerifyScreenDump(buf, 'Test_diff_with_cursorline_number_02', {})
+
+ " clean up
+ call StopVimInTerminal(buf)
+ call delete('Xtest_diff_cursorline_number')
+endfunc
+
func Test_diff_with_cursorline_breakindent()
CheckScreendump
@@ -1146,6 +1172,35 @@ func Test_diff_followwrap()
bwipe!
endfunc
+func Test_diff_maintains_change_mark()
+ func DiffMaintainsChangeMark()
+ enew!
+ call setline(1, ['a', 'b', 'c', 'd'])
+ diffthis
+ new
+ call setline(1, ['a', 'b', 'c', 'e'])
+ " Set '[ and '] marks
+ 2,3yank
+ call assert_equal([2, 3], [line("'["), line("']")])
+ " Verify they aren't affected by the implicit diff
+ diffthis
+ call assert_equal([2, 3], [line("'["), line("']")])
+ " Verify they aren't affected by an explicit diff
+ diffupdate
+ call assert_equal([2, 3], [line("'["), line("']")])
+ bwipe!
+ bwipe!
+ endfunc
+
+ set diffopt-=internal
+ call DiffMaintainsChangeMark()
+ set diffopt+=internal
+ call DiffMaintainsChangeMark()
+
+ set diffopt&
+ delfunc DiffMaintainsChangeMark
+endfunc
+
func Test_diff_rnu()
CheckScreendump
@@ -1240,4 +1295,41 @@ func Test_diff_filler_cursorcolumn()
endfunc
+func Test_diff_binary()
+ CheckScreendump
+
+ let content =<< trim END
+ call setline(1, ['a', 'b', "c\n", 'd', 'e', 'f', 'g'])
+ vnew
+ call setline(1, ['A', 'b', 'c', 'd', 'E', 'f', 'g'])
+ windo diffthis
+ wincmd p
+ norm! gg0
+ redraw!
+ END
+ call writefile(content, 'Xtest_diff_bin')
+ let buf = RunVimInTerminal('-S Xtest_diff_bin', {})
+
+ " Test using internal diff
+ call VerifyScreenDump(buf, 'Test_diff_bin_01', {})
+
+ " Test using internal diff and case folding
+ call term_sendkeys(buf, ":set diffopt+=icase\<cr>")
+ call term_sendkeys(buf, "\<C-l>")
+ call VerifyScreenDump(buf, 'Test_diff_bin_02', {})
+ " Test using external diff
+ call term_sendkeys(buf, ":set diffopt=filler\<cr>")
+ call term_sendkeys(buf, "\<C-l>")
+ call VerifyScreenDump(buf, 'Test_diff_bin_03', {})
+ " Test using external diff and case folding
+ call term_sendkeys(buf, ":set diffopt=filler,icase\<cr>")
+ call term_sendkeys(buf, "\<C-l>")
+ call VerifyScreenDump(buf, 'Test_diff_bin_04', {})
+
+ " clean up
+ call StopVimInTerminal(buf)
+ call delete('Xtest_diff_bin')
+ set diffopt&vim
+endfunc
+
" vim: shiftwidth=2 sts=2 expandtab
diff --git a/src/nvim/testdir/test_digraph.vim b/src/nvim/testdir/test_digraph.vim
index d23748a3e3..acc34e5e7c 100644
--- a/src/nvim/testdir/test_digraph.vim
+++ b/src/nvim/testdir/test_digraph.vim
@@ -81,7 +81,7 @@ func Test_digraphs()
call Put_Dig(".e")
call Put_Dig("a.") " not defined
call assert_equal(['ḃ', 'ė', '.'], getline(line('.')-2,line('.')))
- " Diaresis
+ " Diaeresis
call Put_Dig("a:")
call Put_Dig(":u")
call Put_Dig("b:") " not defined
@@ -212,7 +212,7 @@ func Test_digraphs()
call Put_Dig("el")
call assert_equal(['␀', 'ü', '∞', 'l'], getline(line('.')-3,line('.')))
call assert_fails('digraph xy z', 'E39:')
- call assert_fails('digraph x', 'E474:')
+ call assert_fails('digraph x', 'E1214:')
bw!
endfunc
@@ -288,7 +288,7 @@ func Test_digraphs_option()
call Put_Dig_BS(".","e")
call Put_Dig_BS("a",".") " not defined
call assert_equal(['ḃ', 'ė', '.'], getline(line('.')-2,line('.')))
- " Diaresis
+ " Diaeresis
call Put_Dig_BS("a",":")
call Put_Dig_BS(":","u")
call Put_Dig_BS("b",":") " not defined
@@ -466,10 +466,12 @@ endfunc
func Test_digraph_cmndline()
" Create digraph on commandline
- " This is a hack, to let Vim create the digraph in commandline mode
- let s = ''
- exe "sil! norm! :let s.='\<c-k>Eu'\<cr>"
- call assert_equal("€", s)
+ call feedkeys(":\"\<c-k>Eu\<cr>", 'xt')
+ call assert_equal('"€', @:)
+
+ " Canceling a CTRL-K on the cmdline
+ call feedkeys(":\"a\<c-k>\<esc>b\<cr>", 'xt')
+ call assert_equal('"ab', @:)
endfunc
func Test_show_digraph()
@@ -505,4 +507,85 @@ func Test_entering_digraph()
call StopVimInTerminal(buf)
endfunc
+func Test_digraph_set_function()
+ new
+ call digraph_set('aa', 'あ')
+ call Put_Dig('aa')
+ call assert_equal('あ', getline('$'))
+ call digraph_set(' i', 'い')
+ call Put_Dig(' i')
+ call assert_equal('い', getline('$'))
+ call digraph_set(' ', 'う')
+ call Put_Dig(' ')
+ call assert_equal('う', getline('$'))
+
+ eval 'aa'->digraph_set('え')
+ call Put_Dig('aa')
+ call assert_equal('え', getline('$'))
+
+ call assert_fails('call digraph_set("aaa", "あ")', 'E1214: Digraph must be just two characters: aaa')
+ call assert_fails('call digraph_set("b", "あ")', 'E1214: Digraph must be just two characters: b')
+ call assert_fails('call digraph_set("あ", "あ")', 'E1214: Digraph must be just two characters: あ')
+ call assert_fails('call digraph_set("aa", "ああ")', 'E1215: Digraph must be one character: ああ')
+ call assert_fails('call digraph_set("aa", "か" .. nr2char(0x3099))', 'E1215: Digraph must be one character: か' .. nr2char(0x3099))
+ bwipe!
+endfunc
+
+func Test_digraph_get_function()
+ " Built-in digraphs
+ call assert_equal('∞', digraph_get('00'))
+
+ " User-defined digraphs
+ call digraph_set('aa', 'あ')
+ call digraph_set(' i', 'い')
+ call digraph_set(' ', 'う')
+ call assert_equal('あ', digraph_get('aa'))
+ call assert_equal('あ', 'aa'->digraph_get())
+ call assert_equal('い', digraph_get(' i'))
+ call assert_equal('う', digraph_get(' '))
+ call assert_fails('call digraph_get("aaa")', 'E1214: Digraph must be just two characters: aaa')
+ call assert_fails('call digraph_get("b")', 'E1214: Digraph must be just two characters: b')
+endfunc
+
+func Test_digraph_get_function_encode()
+ throw 'Skipped: Nvim does not support setting encoding=japan'
+ CheckFeature iconv
+
+ let testcases = {
+ \'00': '∞',
+ \'aa': 'あ',
+ \}
+ for [key, ch] in items(testcases)
+ call digraph_set(key, ch)
+ set encoding=japan
+ call assert_equal(iconv(ch, 'utf-8', 'japan'), digraph_get(key))
+ set encoding=utf-8
+ endfor
+endfunc
+
+func Test_digraph_setlist_function()
+ call digraph_setlist([['aa', 'き'], ['bb', 'く']])
+ call assert_equal('き', digraph_get('aa'))
+ call assert_equal('く', digraph_get('bb'))
+
+ call assert_fails('call digraph_setlist([[]])', 'E1216:')
+ call assert_fails('call digraph_setlist([["aa", "b", "cc"]])', '1216:')
+ call assert_fails('call digraph_setlist([["あ", "あ"]])', 'E1214: Digraph must be just two characters: あ')
+endfunc
+
+func Test_digraph_getlist_function()
+ " Make sure user-defined digraphs are defined
+ call digraph_setlist([['aa', 'き'], ['bb', 'く']])
+
+ for pair in digraph_getlist(1)
+ call assert_equal(digraph_get(pair[0]), pair[1])
+ endfor
+
+ " We don't know how many digraphs are registered before, so check the number
+ " of digraphs returned.
+ call assert_equal(digraph_getlist()->len(), digraph_getlist(0)->len())
+ call assert_notequal((digraph_getlist()->len()), digraph_getlist(1)->len())
+endfunc
+
+
" vim: shiftwidth=2 sts=2 expandtab
diff --git a/src/nvim/testdir/test_display.vim b/src/nvim/testdir/test_display.vim
index c2a9683f7c..6938abbc28 100644
--- a/src/nvim/testdir/test_display.vim
+++ b/src/nvim/testdir/test_display.vim
@@ -41,7 +41,7 @@ func Test_display_foldcolumn()
quit!
endfunc
-func! Test_display_foldtext_mbyte()
+func Test_display_foldtext_mbyte()
CheckFeature folding
call NewWindow(10, 40)
@@ -263,6 +263,27 @@ func Test_display_scroll_at_topline()
call StopVimInTerminal(buf)
endfunc
+func Test_display_scroll_update_visual()
+ CheckScreendump
+
+ let lines =<< trim END
+ set scrolloff=0
+ call setline(1, repeat(['foo'], 10))
+ call sign_define('foo', { 'text': '>' })
+ call sign_place(1, 'bar', 'foo', bufnr(), { 'lnum': 2 })
+ call sign_place(2, 'bar', 'foo', bufnr(), { 'lnum': 1 })
+ autocmd CursorMoved * if getcurpos()[1] == 2 | call sign_unplace('bar', { 'id': 1 }) | endif
+ END
+ call writefile(lines, 'XupdateVisual.vim')
+
+ let buf = RunVimInTerminal('-S XupdateVisual.vim', #{rows: 8, cols: 60})
+ call term_sendkeys(buf, "VG7kk")
+ call VerifyScreenDump(buf, 'Test_display_scroll_update_visual', {})
+
+ call StopVimInTerminal(buf)
+ call delete('XupdateVisual.vim')
+endfunc
+
" Test for 'eob' (EndOfBuffer) item in 'fillchars'
func Test_eob_fillchars()
" default value (skipped)
@@ -304,4 +325,31 @@ func Test_display_linebreak_breakat()
let &breakat=_breakat
endfunc
+func Test_display_lastline()
+ CheckScreendump
+
+ let lines =<< trim END
+ call setline(1, ['aaa', 'b'->repeat(100)])
+ set display=truncate
+ vsplit
+ 100wincmd <
+ END
+ call writefile(lines, 'XdispLastline')
+ let buf = RunVimInTerminal('-S XdispLastline', #{rows: 10})
+ call VerifyScreenDump(buf, 'Test_display_lastline_1', {})
+
+ call term_sendkeys(buf, ":set display=lastline\<CR>")
+ call VerifyScreenDump(buf, 'Test_display_lastline_2', {})
+
+ call term_sendkeys(buf, ":100wincmd >\<CR>")
+ call VerifyScreenDump(buf, 'Test_display_lastline_3', {})
+
+ call term_sendkeys(buf, ":set display=truncate\<CR>")
+ call VerifyScreenDump(buf, 'Test_display_lastline_4', {})
+
+ call StopVimInTerminal(buf)
+ call delete('XdispLastline')
+endfunc
+
+
" vim: shiftwidth=2 sts=2 expandtab
diff --git a/src/nvim/testdir/test_edit.vim b/src/nvim/testdir/test_edit.vim
index fc4e80f0d6..42c77518e4 100644
--- a/src/nvim/testdir/test_edit.vim
+++ b/src/nvim/testdir/test_edit.vim
@@ -16,8 +16,9 @@ func Test_edit_00b()
call setline(1, ['abc '])
inoreabbr <buffer> h here some more
call cursor(1, 4)
- " <c-l> expands the abbreviation and ends insertmode
- call feedkeys(":set im\<cr> h\<c-l>:set noim\<cr>", 'tix')
+ " <esc> expands the abbreviation and ends insert mode
+ " call feedkeys(":set im\<cr> h\<c-l>:set noim\<cr>", 'tix')
+ call feedkeys("i h\<esc>", 'tix')
call assert_equal(['abc here some more '], getline(1,'$'))
iunabbr <buffer> h
bw!
@@ -213,7 +214,7 @@ func Test_edit_07()
bw!
endfunc
-func! Test_edit_08()
+func Test_edit_08()
throw 'skipped: moved to test/functional/legacy/edit_spec.lua'
" reset insertmode from i_ctrl-r_=
let g:bufnr = bufnr('%')
@@ -234,15 +235,18 @@ func Test_edit_09()
call setline(1, ['abc', 'def', 'ghi'])
call cursor(1, 1)
" 1) CTRL-\ CTLR-N
- call feedkeys(":set im\<cr>\<c-\>\<c-n>ccABC\<c-l>", 'txin')
+ " call feedkeys(":set im\<cr>\<c-\>\<c-n>ccABC\<c-l>", 'txin')
+ call feedkeys("i\<c-\>\<c-n>ccABC\<esc>", 'txin')
call assert_equal(['ABC', 'def', 'ghi'], getline(1,'$'))
call setline(1, ['ABC', 'def', 'ghi'])
" 2) CTRL-\ CTLR-G
- call feedkeys("j0\<c-\>\<c-g>ZZZ\<cr>\<c-l>", 'txin')
- call assert_equal(['ABC', 'ZZZ', 'def', 'ghi'], getline(1,'$'))
- call feedkeys("I\<c-\>\<c-g>YYY\<c-l>", 'txin')
- call assert_equal(['ABC', 'ZZZ', 'YYYdef', 'ghi'], getline(1,'$'))
- set noinsertmode
+ " CTRL-\ CTRL-G goes to Insert mode when 'insertmode' is set, but
+ " 'insertmode' is now removed so skip this test
+ " call feedkeys("j0\<c-\>\<c-g>ZZZ\<cr>\<esc>", 'txin')
+ " call assert_equal(['ABC', 'ZZZ', 'def', 'ghi'], getline(1,'$'))
+ " call feedkeys("I\<c-\>\<c-g>YYY\<c-l>", 'txin')
+ " call assert_equal(['ABC', 'ZZZ', 'YYYdef', 'ghi'], getline(1,'$'))
+ " set noinsertmode
" 3) CTRL-\ CTRL-O
call setline(1, ['ABC', 'ZZZ', 'def', 'ghi'])
call cursor(1, 1)
@@ -266,6 +270,10 @@ func Test_edit_10()
call cursor(1, 4)
call feedkeys("A\<s-home>start\<esc>", 'txin')
call assert_equal(['startdef', 'ghi'], getline(1, '$'))
+ " start select mode again with gv
+ set selectmode=cmd
+ call feedkeys('gvabc', 'xt')
+ call assert_equal('abctdef', getline(1))
set selectmode= keymodel=
bw!
endfunc
@@ -278,7 +286,7 @@ func Test_edit_11()
call cursor(2, 1)
call feedkeys("i\<c-f>int c;\<esc>", 'tnix')
call cursor(3, 1)
- call feedkeys("i/* comment */", 'tnix')
+ call feedkeys("\<Insert>/* comment */", 'tnix')
call assert_equal(['{', "\<tab>int c;", "/* comment */"], getline(1, '$'))
" added changed cindentkeys slightly
set cindent cinkeys+=*/
@@ -341,8 +349,8 @@ func Test_edit_11_indentexpr()
bw!
endfunc
+" Test changing indent in replace mode
func Test_edit_12()
- " Test changing indent in replace mode
new
call setline(1, ["\tabc", "\tdef"])
call cursor(2, 4)
@@ -381,29 +389,27 @@ func Test_edit_12()
call feedkeys("R\<c-t>\<c-t>", 'tnix')
call assert_equal(["\tabc", "\t\t\tdef"], getline(1, '$'))
call assert_equal([0, 2, 2, 0], getpos('.'))
- set et
- set sw& et&
+ set sw&
+
+ " In replace mode, after hitting enter in a line with tab characters,
+ " pressing backspace should restore the tab characters.
%d
- call setline(1, ["\t/*"])
- set formatoptions=croql
- call cursor(1, 3)
- call feedkeys("A\<cr>\<cr>/", 'tnix')
- call assert_equal(["\t/*", " *", " */"], getline(1, '$'))
- set formatoptions&
+ setlocal autoindent backspace=2
+ call setline(1, "\tone\t\ttwo")
+ exe "normal ggRred\<CR>six" .. repeat("\<BS>", 8)
+ call assert_equal(["\tone\t\ttwo"], getline(1, '$'))
bw!
endfunc
func Test_edit_13()
" Test smartindenting
- if exists("+smartindent")
- new
- set smartindent autoindent
- call setline(1, ["\tabc"])
- call feedkeys("A {\<cr>more\<cr>}\<esc>", 'tnix')
- call assert_equal(["\tabc {", "\t\tmore", "\t}"], getline(1, '$'))
- set smartindent& autoindent&
- bwipe!
- endif
+ new
+ set smartindent autoindent
+ call setline(1, ["\tabc"])
+ call feedkeys("A {\<cr>more\<cr>}\<esc>", 'tnix')
+ call assert_equal(["\tabc {", "\t\tmore", "\t}"], getline(1, '$'))
+ set smartindent& autoindent&
+ bwipe!
" Test autoindent removing indent of blank line.
new
@@ -414,16 +420,49 @@ func Test_edit_13()
call assert_equal("", getline(2))
call assert_equal(" baz", getline(3))
set autoindent&
+
+ " pressing <C-U> to erase line should keep the indent with 'autoindent'
+ set backspace=2 autoindent
+ %d
+ exe "normal i\tone\<CR>three\<C-U>two"
+ call assert_equal(["\tone", "\ttwo"], getline(1, '$'))
+ set backspace& autoindent&
+
bwipe!
endfunc
-func! Test_edit_CR()
+" Test for autoindent removing indent when insert mode is stopped. Some parts
+" of the code is exercised only when interactive mode is used. So use Vim in a
+" terminal.
+func Test_autoindent_remove_indent()
+ CheckRunVimInTerminal
+ let buf = RunVimInTerminal('-N Xfile', {'rows': 6, 'cols' : 20})
+ call TermWait(buf)
+ call term_sendkeys(buf, ":set autoindent\n")
+ " leaving insert mode in a new line with indent added by autoindent, should
+ " remove the indent.
+ call term_sendkeys(buf, "i\<Tab>foo\<CR>\<Esc>")
+ " Need to delay for sometime, otherwise the code in getchar.c will not be
+ " exercised.
+ call TermWait(buf, 50)
+ " when a line is wrapped and the cursor is at the start of the second line,
+ " leaving insert mode, should move the cursor back to the first line.
+ call term_sendkeys(buf, "o" .. repeat('x', 20) .. "\<Esc>")
+ " Need to delay for sometime, otherwise the code in getchar.c will not be
+ " exercised.
+ call TermWait(buf, 50)
+ call term_sendkeys(buf, ":w\n")
+ call TermWait(buf)
+ call StopVimInTerminal(buf)
+ call assert_equal(["\tfoo", '', repeat('x', 20)], readfile('Xfile'))
+ call delete('Xfile')
+endfunc
+
+func Test_edit_CR()
" Test for <CR> in insert mode
" basically only in quickfix mode ist tested, the rest
" has been taken care of by other tests
- if !has("quickfix")
- return
- endif
+ CheckFeature quickfix
botright new
call writefile(range(1, 10), 'Xqflist.txt')
call setqflist([{'filename': 'Xqflist.txt', 'lnum': 2}])
@@ -450,7 +489,7 @@ func! Test_edit_CR()
call delete('Xqflist.txt')
endfunc
-func! Test_edit_CTRL_()
+func Test_edit_CTRL_()
" disabled for Windows builds, why?
if !has("rightleft") || has("win32")
return
@@ -590,7 +629,7 @@ func Test_edit_CTRL_K()
call feedkeys("A\<c-x>\<c-k>\<down>\<down>\<down>\<down>\<cr>\<esc>", 'tnix')
call assert_equal(['AA'], getline(1, '$'))
- " press an unexecpted key after dictionary completion
+ " press an unexpected key after dictionary completion
%d
call setline(1, 'A')
call cursor(1, 1)
@@ -734,7 +773,7 @@ func Test_edit_CTRL_O()
bw!
endfunc
-func! Test_edit_CTRL_R()
+func Test_edit_CTRL_R()
" Insert Register
new
" call test_override("ALL", 1)
@@ -979,6 +1018,22 @@ func Test_edit_CTRL_U()
bw!
endfunc
+func Test_edit_completefunc_delete()
+ func CompleteFunc(findstart, base)
+ if a:findstart == 1
+ return col('.') - 1
+ endif
+ normal dd
+ return ['a', 'b']
+ endfunc
+ new
+ set completefunc=CompleteFunc
+ call setline(1, ['', 'abcd', ''])
+ 2d
+ call assert_fails("normal 2G$a\<C-X>\<C-U>", 'E565:')
+ bwipe!
+endfunc
+
func Test_edit_CTRL_Z()
" Ctrl-Z when insertmode is not set inserts it literally
new
@@ -1006,16 +1061,14 @@ func Test_edit_DROP()
endfunc
func Test_edit_CTRL_V()
- if has("ebcdic")
- return
- endif
new
call setline(1, ['abc'])
call cursor(2, 1)
+
" force some redraws
set showmode showcmd
- "call test_override_char_avail(1)
- " call test_override('ALL', 1)
+ " call test_override('char_avail', 1)
+
call feedkeys("A\<c-v>\<c-n>\<c-v>\<c-l>\<c-v>\<c-b>\<esc>", 'tnix')
call assert_equal(["abc\x0e\x0c\x02"], getline(1, '$'))
@@ -1028,15 +1081,27 @@ func Test_edit_CTRL_V()
set norl
endif
- " call test_override('ALL', 0)
set noshowmode showcmd
+ " call test_override('char_avail', 0)
+
+ " No modifiers should be applied to the char typed using i_CTRL-V_digit.
+ call feedkeys(":append\<CR>\<C-V>76c\<C-V>76\<C-F2>\<C-V>u3c0j\<C-V>u3c0\<M-F3>\<CR>.\<CR>", 'tnix')
+ call assert_equal('LcL<C-F2>πjπ<M-F3>', getline(2))
+
+ if has('osx')
+ " A char with a modifier should not be a valid char for i_CTRL-V_digit.
+ call feedkeys("o\<C-V>\<D-j>\<C-V>\<D-1>\<C-V>\<D-o>\<C-V>\<D-x>\<C-V>\<D-u>", 'tnix')
+ call assert_equal('<D-j><D-1><D-o><D-x><D-u>', getline(3))
+ endif
+
bw!
endfunc
func Test_edit_F1()
" Pressing <f1>
new
- call feedkeys(":set im\<cr>\<f1>\<c-l>", 'tnix')
+ " call feedkeys(":set im\<cr>\<f1>\<c-l>", 'tnix')
+ call feedkeys("i\<f1>\<esc>", 'tnix')
set noinsertmode
call assert_equal('help', &buftype)
bw
@@ -1132,26 +1197,38 @@ endfunc
func Test_edit_MOUSE()
" This is a simple test, since we not really using the mouse here
- if !has("mouse")
- return
- endif
+ CheckFeature mouse
10new
call setline(1, range(1, 100))
call cursor(1, 1)
+ call assert_equal(1, line('w0'))
+ call assert_equal(10, line('w$'))
set mouse=a
+ " One scroll event moves three lines.
call feedkeys("A\<ScrollWheelDown>\<esc>", 'tnix')
- call assert_equal([0, 4, 1, 0], getpos('.'))
- " This should move by one pageDown, but only moves
- " by one line when the test is run...
+ call assert_equal(4, line('w0'))
+ call assert_equal(13, line('w$'))
+ " This should move by one page down.
call feedkeys("A\<S-ScrollWheelDown>\<esc>", 'tnix')
- call assert_equal([0, 5, 1, 0], getpos('.'))
+ call assert_equal(14, line('w0'))
set nostartofline
+ " Another page down.
call feedkeys("A\<C-ScrollWheelDown>\<esc>", 'tnix')
- call assert_equal([0, 6, 1, 0], getpos('.'))
+ 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 feedkeys("A\<LeftMouse>\<esc>", 'tnix')
- call assert_equal([0, 6, 1, 0], getpos('.'))
- call feedkeys("A\<RightMouse>\<esc>", 'tnix')
- call assert_equal([0, 6, 1, 0], getpos('.'))
+ call 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 feedkeys("A\<RightMouse>\<esc>\<esc>", 'tnix')
+ call assert_equal([0, 28, 2, 0], getpos('.'))
+ set mousemodel&
call cursor(1, 100)
norm! zt
" this should move by a screen up, but when the test
@@ -1303,7 +1380,7 @@ func Test_edit_forbidden()
try
call feedkeys("ix\<esc>", 'tnix')
call assert_fails(1, 'textlock')
- catch /^Vim\%((\a\+)\)\=:E523/ " catch E523: not allowed here
+ catch /^Vim\%((\a\+)\)\=:E565/ " catch E565: not allowed here
endtry
" TODO: Might be a bug: should x really be inserted here
call assert_equal(['xa'], getline(1, '$'))
@@ -1328,7 +1405,7 @@ func Test_edit_forbidden()
try
call feedkeys("i\<c-x>\<c-u>\<esc>", 'tnix')
call assert_fails(1, 'change in complete function')
- catch /^Vim\%((\a\+)\)\=:E523/ " catch E523
+ catch /^Vim\%((\a\+)\)\=:E565/ " catch E565
endtry
delfu Complete
set completefunc=
@@ -1550,11 +1627,7 @@ endfunc
func Test_edit_special_chars()
new
- if has("ebcdic")
- let t = "o\<C-V>193\<C-V>xc2\<C-V>o303 \<C-V>90a\<C-V>xfg\<C-V>o578\<Esc>"
- else
- let t = "o\<C-V>65\<C-V>x42\<C-V>o103 \<C-V>33a\<C-V>xfg\<C-V>o78\<Esc>"
- endif
+ let t = "o\<C-V>65\<C-V>x42\<C-V>o103 \<C-V>33a\<C-V>xfg\<C-V>o78\<Esc>"
exe "normal " . t
call assert_equal("ABC !a\<C-O>g\<C-G>8", getline(2))
@@ -1577,6 +1650,22 @@ func Test_edit_startinsert()
bwipe!
endfunc
+" Test for :startreplace and :startgreplace
+func Test_edit_startreplace()
+ new
+ call setline(1, 'abc')
+ call feedkeys("l:startreplace\<CR>xyz\e", 'xt')
+ call assert_equal('axyz', getline(1))
+ call feedkeys("0:startreplace!\<CR>abc\e", 'xt')
+ call assert_equal('axyzabc', getline(1))
+ call setline(1, "a\tb")
+ call feedkeys("0l:startgreplace\<CR>xyz\e", 'xt')
+ call assert_equal("axyz\tb", getline(1))
+ call feedkeys("0i\<C-R>=execute('startreplace')\<CR>12\e", 'xt')
+ call assert_equal("12axyz\tb", getline(1))
+ close!
+endfunc
+
func Test_edit_noesckeys()
CheckNotGui
new
@@ -1597,6 +1686,58 @@ func Test_edit_noesckeys()
" set esckeys
endfunc
+" Test for running an invalid ex command in insert mode using CTRL-O
+" Note that vim has a hard-coded sleep of 3 seconds. So this test will take
+" more than 3 seconds to complete.
+func Test_edit_ctrl_o_invalid_cmd()
+ new
+ set showmode showcmd
+ let caught_e492 = 0
+ try
+ call feedkeys("i\<C-O>:invalid\<CR>abc\<Esc>", "xt")
+ catch /E492:/
+ let caught_e492 = 1
+ endtry
+ call assert_equal(1, caught_e492)
+ call assert_equal('abc', getline(1))
+ set showmode& showcmd&
+ close!
+endfunc
+
+" Test for inserting text in a line with only spaces ('H' flag in 'cpoptions')
+func Test_edit_cpo_H()
+ throw 'Skipped: Nvim does not support cpoptions flag "H"'
+ new
+ call setline(1, ' ')
+ normal! Ia
+ call assert_equal(' a', getline(1))
+ set cpo+=H
+ call setline(1, ' ')
+ normal! Ia
+ call assert_equal(' a ', getline(1))
+ set cpo-=H
+ close!
+endfunc
+
+" Test for inserting tab in virtual replace mode ('L' flag in 'cpoptions')
+func Test_edit_cpo_L()
+ new
+ call setline(1, 'abcdefghijklmnopqr')
+ exe "normal 0gR\<Tab>"
+ call assert_equal("\<Tab>ijklmnopqr", getline(1))
+ set cpo+=L
+ set list
+ call setline(1, 'abcdefghijklmnopqr')
+ exe "normal 0gR\<Tab>"
+ call assert_equal("\<Tab>cdefghijklmnopqr", getline(1))
+ set nolist
+ call setline(1, 'abcdefghijklmnopqr')
+ exe "normal 0gR\<Tab>"
+ call assert_equal("\<Tab>ijklmnopqr", getline(1))
+ set cpo-=L
+ %bw!
+endfunc
+
" Test for editing a directory
func Test_edit_is_a_directory()
CheckEnglish
@@ -1622,6 +1763,29 @@ func Test_edit_is_a_directory()
call delete(dirname, 'rf')
endfunc
+" Using :edit without leaving 'insertmode' should not cause Insert mode to be
+" re-entered immediately after <C-L>
+func Test_edit_insertmode_ex_edit()
+ CheckRunVimInTerminal
+
+ let lines =<< trim END
+ set insertmode noruler
+ inoremap <C-B> <Cmd>edit Xfoo<CR>
+ END
+ 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 term_sendkeys(buf, "\<C-B>\<C-L>")
+ call TermWait(buf, 50)
+ call assert_notmatch('^-- INSERT --\s*$', term_getline(buf, 6))
+
+ " clean up
+ call StopVimInTerminal(buf)
+ call delete('Xtest_edit_insertmode_ex_edit')
+endfunc
+
func Test_edit_browse()
" in the GUI this opens a file picker, we only test the terminal behavior
CheckNotGui
diff --git a/src/nvim/testdir/test_eval_stuff.vim b/src/nvim/testdir/test_eval_stuff.vim
index 883ba5de3d..811c6c946d 100644
--- a/src/nvim/testdir/test_eval_stuff.vim
+++ b/src/nvim/testdir/test_eval_stuff.vim
@@ -65,11 +65,9 @@ func Test_E963()
endfunc
func Test_for_invalid()
- " Vim gives incorrect emsg here until v8.2.3284, but the exact emsg from that
- " patch cannot be used until v8.2.2658 is ported (for loop over Strings)
- call assert_fails("for x in 99", 'E897:')
- call assert_fails("for x in function('winnr')", 'E897:')
- call assert_fails("for x in {'a': 9}", 'E897:')
+ call assert_fails("for x in 99", 'E1098:')
+ call assert_fails("for x in function('winnr')", 'E1098:')
+ call assert_fails("for x in {'a': 9}", 'E1098:')
if 0
/1/5/2/s/\n
@@ -322,4 +320,26 @@ func Test_curly_assignment()
unlet g:gvar
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,
+func Test_modified_char_no_escape_special()
+ nnoremap <M-…> <Cmd>let g:got_m_ellipsis += 1<CR>
+ call feedkeys("\<M-…>", 't')
+ call assert_equal("\<M-…>", getchar())
+ let g:got_m_ellipsis = 0
+ call feedkeys("\<M-…>", 'xt')
+ call assert_equal(1, g:got_m_ellipsis)
+ func Func()
+ return "\<M-…>"
+ endfunc
+ nmap <expr> <F2> Func()
+ call feedkeys("\<F2>", 'xt')
+ call assert_equal(2, g:got_m_ellipsis)
+ delfunc Func
+ nunmap <F2>
+ unlet g:got_m_ellipsis
+ nunmap <M-…>
+endfunc
+
" vim: shiftwidth=2 sts=2 expandtab
diff --git a/src/nvim/testdir/test_ex_mode.vim b/src/nvim/testdir/test_ex_mode.vim
index 92e0559618..122572f32a 100644
--- a/src/nvim/testdir/test_ex_mode.vim
+++ b/src/nvim/testdir/test_ex_mode.vim
@@ -29,12 +29,11 @@ endfunc
" Test editing line in Ex mode (both Q and gQ)
func Test_ex_mode()
- throw 'skipped: TODO: '
+ throw 'Skipped: Nvim only supports Vim Ex mode'
let encoding_save = &encoding
set sw=2
- " for e in ['utf8', 'latin1']
- for e in ['utf8']
+ for e in ['utf8', 'latin1']
exe 'set encoding=' . e
call assert_equal(['bar', 'bar'], Ex("foo bar\<C-u>bar"), e)
@@ -52,22 +51,131 @@ func Test_ex_mode()
call assert_equal([' foo', ' foo'], Ex(" foo\<C-d>"), e)
call assert_equal(['foo', ' foo0'], Ex(" foo0\<C-d>"), e)
call assert_equal(['foo', ' foo^'], Ex(" foo^\<C-d>"), e)
+ call assert_equal(['foo', 'foo'],
+ \ Ex("\<BS>\<C-H>\<Del>\<kDel>foo"), e)
+ " default wildchar <Tab> interferes with this test
+ set wildchar=<c-e>
+ call assert_equal(["a\tb", "a\tb"], Ex("a\t\t\<C-H>b"), e)
+ call assert_equal(["\t mn", "\tm\<C-T>n"], Ex("\tm\<C-T>n"), e)
+ set wildchar&
endfor
set sw&
let &encoding = encoding_save
endfunc
+" Test substitute confirmation prompt :%s/pat/str/c in Ex mode
+func Test_Ex_substitute()
+ CheckRunVimInTerminal
+ let buf = RunVimInTerminal('', {'rows': 6})
+
+ call term_sendkeys(buf, ":call setline(1, ['foo foo', 'foo foo', 'foo foo'])\<CR>")
+ call term_sendkeys(buf, ":set number\<CR>")
+ call term_sendkeys(buf, "gQ")
+ call WaitForAssert({-> assert_match(':', term_getline(buf, 6))}, 1000)
+
+ call term_sendkeys(buf, "%s/foo/bar/gc\<CR>")
+ call WaitForAssert({-> assert_match(' 1 foo foo', term_getline(buf, 5))},
+ \ 1000)
+ call WaitForAssert({-> assert_match(' ^^^', term_getline(buf, 6))}, 1000)
+ call term_sendkeys(buf, "N\<CR>")
+ call term_wait(buf)
+ call WaitForAssert({-> assert_match(' ^^^', term_getline(buf, 6))}, 1000)
+ call term_sendkeys(buf, "n\<CR>")
+ call WaitForAssert({-> assert_match(' ^^^', term_getline(buf, 6))},
+ \ 1000)
+ call term_sendkeys(buf, "y\<CR>")
+
+ call term_sendkeys(buf, "q\<CR>")
+ call WaitForAssert({-> assert_match(':', term_getline(buf, 6))}, 1000)
+
+ " Pressing enter in ex mode should print the current line
+ call term_sendkeys(buf, "\<CR>")
+ call WaitForAssert({-> assert_match(' 3 foo foo',
+ \ term_getline(buf, 5))}, 1000)
+
+ call term_sendkeys(buf, ":vi\<CR>")
+ call WaitForAssert({-> assert_match('foo bar', term_getline(buf, 1))}, 1000)
+
+ call term_sendkeys(buf, ":q!\n")
+ call StopVimInTerminal(buf)
+endfunc
+
+" Test for displaying lines from an empty buffer in Ex mode
+func Test_Ex_emptybuf()
+ new
+ call assert_fails('call feedkeys("Q\<CR>", "xt")', 'E749:')
+ call setline(1, "abc")
+ call assert_fails('call feedkeys("Q\<CR>", "xt")', 'E501:')
+ call assert_fails('call feedkeys("Q%d\<CR>", "xt")', 'E749:')
+ close!
+endfunc
+
+" Test for the :open command
+func Test_open_command()
+ throw 'Skipped: Nvim does not have :open'
+ new
+ call setline(1, ['foo foo', 'foo bar', 'foo baz'])
+ call feedkeys("Qopen\<CR>j", 'xt')
+ call assert_equal('foo bar', getline('.'))
+ call feedkeys("Qopen /bar/\<CR>", 'xt')
+ call assert_equal(5, col('.'))
+ call assert_fails('call feedkeys("Qopen /baz/\<CR>", "xt")', 'E479:')
+ close!
+endfunc
+
+" Test for :g/pat/visual to run vi commands in Ex mode
+" This used to hang Vim before 8.2.0274.
+func Test_Ex_global()
+ new
+ call setline(1, ['', 'foo', 'bar', 'foo', 'bar', 'foo'])
+ call feedkeys("Q\<bs>g/bar/visual\<CR>$rxQ$ryQvisual\<CR>j", "xt")
+ call assert_equal('bax', getline(3))
+ call assert_equal('bay', getline(5))
+ bwipe!
+endfunc
+
+" In Ex-mode, a backslash escapes a newline
+func Test_Ex_escape_enter()
+ call feedkeys("gQlet l = \"a\\\<kEnter>b\"\<cr>vi\<cr>", 'xt')
+ call assert_equal("a\rb", l)
+endfunc
+
+" Test for :append! command in Ex mode
+func Test_Ex_append()
+ throw 'Skipped: Nvim only supports Vim Ex mode'
+ new
+ call setline(1, "\t abc")
+ call feedkeys("Qappend!\npqr\nxyz\n.\nvisual\n", 'xt')
+ call assert_equal(["\t abc", "\t pqr", "\t xyz"], getline(1, '$'))
+ close!
+endfunc
+
+" In Ex-mode, backslashes at the end of a command should be halved.
+func Test_Ex_echo_backslash()
+ throw 'Skipped: Nvim only supports Vim Ex mode'
+ " This test works only when the language is English
+ if v:lang != "C" && v:lang !~ '^[Ee]n'
+ return
+ endif
+ let bsl = '\\\\'
+ let bsl2 = '\\\'
+ call assert_fails('call feedkeys("Qecho " .. bsl .. "\nvisual\n", "xt")',
+ \ "E15: Invalid expression: \\\\")
+ call assert_fails('call feedkeys("Qecho " .. bsl2 .. "\nm\nvisual\n", "xt")',
+ \ "E15: Invalid expression: \\\nm")
+endfunc
+
func Test_ex_mode_errors()
" Not allowed to enter ex mode when text is locked
au InsertCharPre <buffer> normal! gQ<CR>
- let caught_e523 = 0
+ let caught_e565 = 0
try
call feedkeys("ix\<esc>", 'xt')
- catch /^Vim\%((\a\+)\)\=:E523/ " catch E523
- let caught_e523 = 1
+ catch /^Vim\%((\a\+)\)\=:E565/ " catch E565
+ let caught_e565 = 1
endtry
- call assert_equal(1, caught_e523)
+ call assert_equal(1, caught_e565)
au! InsertCharPre
new
@@ -83,6 +191,9 @@ func Test_ex_mode_errors()
endfunc
func Test_ex_mode_count_overflow()
+ " The multiplication causes an integer overflow
+ CheckNotAsan
+
" this used to cause a crash
let lines =<< trim END
call feedkeys("\<Esc>gQ\<CR>")
@@ -98,4 +209,14 @@ func Test_ex_mode_count_overflow()
call delete('Xexmodescript')
endfunc
+func Test_ex_mode_large_indent()
+ new
+ set ts=500 ai
+ call setline(1, "\t")
+ exe "normal gQi\<CR>."
+ set ts=8 noai
+ bwipe!
+endfunc
+
+
" vim: shiftwidth=2 sts=2 expandtab
diff --git a/src/nvim/testdir/test_excmd.vim b/src/nvim/testdir/test_excmd.vim
index 1c053c824f..7d581d5efd 100644
--- a/src/nvim/testdir/test_excmd.vim
+++ b/src/nvim/testdir/test_excmd.vim
@@ -22,6 +22,7 @@ func Test_range_error()
call assert_fails(':\/echo 1', 'E481:')
normal vv
call assert_fails(":'<,'>echo 1", 'E481:')
+ call assert_fails(":\\xcenter", 'E10:')
endfunc
func Test_buffers_lastused()
@@ -65,6 +66,10 @@ func Test_copy()
1,3copy 2
call assert_equal(['L1', 'L2', 'L1', 'L2', 'L3', 'L3', 'L4'], getline(1, 7))
+ " Specifying a count before using : to run an ex-command
+ exe "normal! gg4:yank\<CR>"
+ call assert_equal("L1\nL2\nL1\nL2\n", @")
+
close!
endfunc
@@ -147,7 +152,6 @@ endfunc
" Test for the :insert command
func Test_insert_cmd()
- set noautoindent " test assumes noautoindent, but it's on by default in Nvim
new
call setline(1, [' L1'])
call feedkeys(":insert\<CR> L2\<CR> L3\<CR>.\<CR>", 'xt')
@@ -197,7 +201,6 @@ endfunc
" Test for the :change command
func Test_change_cmd()
- set noautoindent " test assumes noautoindent, but it's on by default in Nvim
new
call setline(1, [' L1', 'L2', 'L3'])
call feedkeys(":change\<CR> L4\<CR> L5\<CR>.\<CR>", 'xt')
@@ -224,12 +227,24 @@ func Test_change_cmd()
close!
endfunc
+" Test for the :language command
+func Test_language_cmd()
+ CheckNotMSWindows " FIXME: why does this fail on Windows CI?
+ CheckNotBSD " FIXME: why does this fail on OpenBSD CI?
+ CheckFeature multi_lang
+
+ call assert_fails('language ctype non_existing_lang', 'E197:')
+ call assert_fails('language time non_existing_lang', 'E197:')
+endfunc
+
" Test for the :confirm command dialog
func Test_confirm_cmd()
CheckNotGui
CheckRunVimInTerminal
+
call writefile(['foo1'], 'foo')
call writefile(['bar1'], 'bar')
+
" Test for saving all the modified buffers
let buf = RunVimInTerminal('', {'rows': 20})
call term_sendkeys(buf, ":set nomore\n")
@@ -242,8 +257,10 @@ func Test_confirm_cmd()
call WaitForAssert({-> assert_match('\[Y\]es, (N)o, Save (A)ll, (D)iscard All, (C)ancel: ', term_getline(buf, 20))}, 1000)
call term_sendkeys(buf, "A")
call StopVimInTerminal(buf)
+
call assert_equal(['foo2'], readfile('foo'))
call assert_equal(['bar2'], readfile('bar'))
+
" Test for discarding all the changes to modified buffers
let buf = RunVimInTerminal('', {'rows': 20})
call term_sendkeys(buf, ":set nomore\n")
@@ -256,8 +273,10 @@ func Test_confirm_cmd()
call WaitForAssert({-> assert_match('\[Y\]es, (N)o, Save (A)ll, (D)iscard All, (C)ancel: ', term_getline(buf, 20))}, 1000)
call term_sendkeys(buf, "D")
call StopVimInTerminal(buf)
+
call assert_equal(['foo2'], readfile('foo'))
call assert_equal(['bar2'], readfile('bar'))
+
" Test for saving and discarding changes to some buffers
let buf = RunVimInTerminal('', {'rows': 20})
call term_sendkeys(buf, ":set nomore\n")
@@ -272,6 +291,7 @@ func Test_confirm_cmd()
call WaitForAssert({-> assert_match('\[Y\]es, (N)o, (C)ancel: ', term_getline(buf, 20))}, 1000)
call term_sendkeys(buf, "Y")
call StopVimInTerminal(buf)
+
call assert_equal(['foo4'], readfile('foo'))
call assert_equal(['bar2'], readfile('bar'))
@@ -393,6 +413,11 @@ func Test_confirm_write_partial_file()
call delete('Xscript')
endfunc
+" Test for the :print command
+func Test_print_cmd()
+ call assert_fails('print', 'E749:')
+endfunc
+
" Test for the :winsize command
func Test_winsize_cmd()
call assert_fails('winsize 1', 'E465:')
@@ -400,3 +425,226 @@ func Test_winsize_cmd()
call assert_fails('win_getid(1)', 'E475: Invalid argument: _getid(1)')
" Actually changing the window size would be flaky.
endfunc
+
+" Test for the :redir command
+func Test_redir_cmd()
+ call assert_fails('redir @@', 'E475:')
+ call assert_fails('redir abc', 'E475:')
+ if has('unix')
+ call mkdir('Xdir')
+ call assert_fails('redir > Xdir', 'E17:')
+ call delete('Xdir', 'd')
+ endif
+ if !has('bsd')
+ call writefile([], 'Xfile')
+ call setfperm('Xfile', 'r--r--r--')
+ call assert_fails('redir! > Xfile', 'E190:')
+ call delete('Xfile')
+ endif
+
+ " Test for redirecting to a register
+ redir @q> | echon 'clean ' | redir END
+ redir @q>> | echon 'water' | redir END
+ call assert_equal('clean water', @q)
+
+ " Test for redirecting to a variable
+ redir => color | echon 'blue ' | redir END
+ redir =>> color | echon 'sky' | redir END
+ call assert_equal('blue sky', color)
+endfunc
+
+" Test for the :filetype command
+func Test_filetype_cmd()
+ call assert_fails('filetype abc', 'E475:')
+endfunc
+
+" Test for the :mode command
+func Test_mode_cmd()
+ call assert_fails('mode abc', 'E359:')
+endfunc
+
+" Test for the :sleep command
+func Test_sleep_cmd()
+ call assert_fails('sleep x', 'E475:')
+endfunc
+
+" Test for the :read command
+func Test_read_cmd()
+ call writefile(['one'], 'Xfile')
+ new
+ call assert_fails('read', 'E32:')
+ edit Xfile
+ read
+ call assert_equal(['one', 'one'], getline(1, '$'))
+ close!
+ new
+ read Xfile
+ call assert_equal(['', 'one'], getline(1, '$'))
+ call deletebufline('', 1, '$')
+ call feedkeys("Qr Xfile\<CR>visual\<CR>", 'xt')
+ call assert_equal(['one'], getline(1, '$'))
+ close!
+ call delete('Xfile')
+endfunc
+
+" Test for running Ex commands when text is locked.
+" <C-\>e in the command line is used to lock the text
+func Test_run_excmd_with_text_locked()
+ " :quit
+ let cmd = ":\<C-\>eexecute('quit')\<CR>\<C-C>"
+ call assert_fails("call feedkeys(cmd, 'xt')", 'E565:')
+
+ " :qall
+ let cmd = ":\<C-\>eexecute('qall')\<CR>\<C-C>"
+ call assert_fails("call feedkeys(cmd, 'xt')", 'E565:')
+
+ " :exit
+ let cmd = ":\<C-\>eexecute('exit')\<CR>\<C-C>"
+ call assert_fails("call feedkeys(cmd, 'xt')", 'E565:')
+
+ " :close - should be ignored
+ new
+ let cmd = ":\<C-\>eexecute('close')\<CR>\<C-C>"
+ call assert_equal(2, winnr('$'))
+ close
+
+ call assert_fails("call feedkeys(\":\<C-R>=execute('bnext')\<CR>\", 'xt')", 'E565:')
+
+ " :tabfirst
+ tabnew
+ call assert_fails("call feedkeys(\":\<C-R>=execute('tabfirst')\<CR>\", 'xt')", 'E565:')
+ tabclose
+endfunc
+
+" Test for the :verbose command
+func Test_verbose_cmd()
+ call assert_equal([' verbose=1'], split(execute('verbose set vbs'), "\n"))
+ call assert_equal([' verbose=0'], split(execute('0verbose set vbs'), "\n"))
+ let l = execute("4verbose set verbose | set verbose")
+ call assert_equal([' verbose=4', ' verbose=0'], split(l, "\n"))
+endfunc
+
+" Test for the :delete command and the related abbreviated commands
+func Test_excmd_delete()
+ new
+ call setline(1, ['foo', "\tbar"])
+ call assert_equal(['^Ibar$'], split(execute('dl'), "\n"))
+ call setline(1, ['foo', "\tbar"])
+ call assert_equal(['^Ibar$'], split(execute('dell'), "\n"))
+ call setline(1, ['foo', "\tbar"])
+ call assert_equal(['^Ibar$'], split(execute('delel'), "\n"))
+ call setline(1, ['foo', "\tbar"])
+ call assert_equal(['^Ibar$'], split(execute('deletl'), "\n"))
+ call setline(1, ['foo', "\tbar"])
+ call assert_equal(['^Ibar$'], split(execute('deletel'), "\n"))
+ call setline(1, ['foo', "\tbar"])
+ call assert_equal([' bar'], split(execute('dp'), "\n"))
+ call setline(1, ['foo', "\tbar"])
+ call assert_equal([' bar'], split(execute('dep'), "\n"))
+ call setline(1, ['foo', "\tbar"])
+ call assert_equal([' bar'], split(execute('delp'), "\n"))
+ call setline(1, ['foo', "\tbar"])
+ call assert_equal([' bar'], split(execute('delep'), "\n"))
+ call setline(1, ['foo', "\tbar"])
+ call assert_equal([' bar'], split(execute('deletp'), "\n"))
+ call setline(1, ['foo', "\tbar"])
+ call assert_equal([' bar'], split(execute('deletep'), "\n"))
+ close!
+endfunc
+
+" Test for commands that are blocked in a sandbox
+func Sandbox_tests()
+ call assert_fails("call histadd(':', 'ls')", 'E48:')
+ call assert_fails("call mkdir('Xdir')", 'E48:')
+ call assert_fails("call rename('a', 'b')", 'E48:')
+ call assert_fails("call setbufvar(1, 'myvar', 1)", 'E48:')
+ call assert_fails("call settabvar(1, 'myvar', 1)", 'E48:')
+ call assert_fails("call settabwinvar(1, 1, 'myvar', 1)", 'E48:')
+ call assert_fails("call setwinvar(1, 'myvar', 1)", 'E48:')
+ call assert_fails("call timer_start(100, '')", 'E48:')
+ if has('channel')
+ call assert_fails("call prompt_setcallback(1, '')", 'E48:')
+ call assert_fails("call prompt_setinterrupt(1, '')", 'E48:')
+ call assert_fails("call prompt_setprompt(1, '')", 'E48:')
+ endif
+ call assert_fails("let $TESTVAR=1", 'E48:')
+ call assert_fails("call feedkeys('ivim')", 'E48:')
+ call assert_fails("source! Xfile", 'E48:')
+ call assert_fails("call delete('Xfile')", 'E48:')
+ call assert_fails("call writefile([], 'Xfile')", 'E48:')
+ call assert_fails('!ls', 'E48:')
+ " call assert_fails('shell', 'E48:')
+ call assert_fails('stop', 'E48:')
+ call assert_fails('exe "normal \<C-Z>"', 'E48:')
+ " set insertmode
+ " call assert_fails('call feedkeys("\<C-Z>", "xt")', 'E48:')
+ " set insertmode&
+ call assert_fails('suspend', 'E48:')
+ call assert_fails('call system("ls")', 'E48:')
+ call assert_fails('call systemlist("ls")', 'E48:')
+ if has('clientserver')
+ call assert_fails('let s=remote_expr("gvim", "2+2")', 'E48:')
+ if !has('win32')
+ " remote_foreground() doesn't thrown an error message on MS-Windows
+ call assert_fails('call remote_foreground("gvim")', 'E48:')
+ endif
+ call assert_fails('let s=remote_peek("gvim")', 'E48:')
+ call assert_fails('let s=remote_read("gvim")', 'E48:')
+ call assert_fails('let s=remote_send("gvim", "abc")', 'E48:')
+ call assert_fails('let s=server2client("gvim", "abc")', 'E48:')
+ endif
+ if has('terminal')
+ call assert_fails('terminal', 'E48:')
+ call assert_fails('call term_start("vim")', 'E48:')
+ call assert_fails('call term_dumpwrite(1, "Xfile")', 'E48:')
+ endif
+ if has('channel')
+ call assert_fails("call ch_logfile('chlog')", 'E48:')
+ call assert_fails("call ch_open('localhost:8765')", 'E48:')
+ endif
+ if has('job')
+ call assert_fails("call job_start('vim')", 'E48:')
+ endif
+ if has('unix') && has('libcall')
+ call assert_fails("echo libcall('libc.so', 'getenv', 'HOME')", 'E48:')
+ endif
+ if has('unix')
+ call assert_fails('cd `pwd`', 'E48:')
+ endif
+endfunc
+
+func Test_sandbox()
+ sandbox call Sandbox_tests()
+endfunc
+
+func Test_not_break_expression_register()
+ call setreg('=', '1+1')
+ if 0
+ put =1
+ endif
+ call assert_equal('1+1', getreg('=', 1))
+endfunc
+
+func Test_address_line_overflow()
+ throw 'Skipped: v:sizeoflong is N/A' " use legacy/excmd_spec.lua instead
+
+ if v:sizeoflong < 8
+ throw 'Skipped: only works with 64 bit long ints'
+ endif
+ new
+ call setline(1, 'text')
+ call assert_fails('|.44444444444444444444444', 'E1247:')
+ call assert_fails('|.9223372036854775806', 'E1247:')
+ bwipe!
+endfunc
+
+" This was leaving the cursor in line zero
+func Test_using_zero_in_range()
+ new
+ norm o00
+ silent! 0;s/\%')
+ bwipe!
+endfunc
+
+
+" vim: shiftwidth=2 sts=2 expandtab
diff --git a/src/nvim/testdir/test_exec_while_if.vim b/src/nvim/testdir/test_exec_while_if.vim
index 3da2784d77..3f13b09945 100644
--- a/src/nvim/testdir/test_exec_while_if.vim
+++ b/src/nvim/testdir/test_exec_while_if.vim
@@ -6,11 +6,7 @@ func Test_exec_while_if()
let i = 0
while i < 12
let i = i + 1
- if has("ebcdic")
- execute "normal o" . i . "\047"
- else
- execute "normal o" . i . "\033"
- endif
+ execute "normal o" . i . "\033"
if i % 2
normal Ax
if i == 9
@@ -21,21 +17,13 @@ func Test_exec_while_if()
else
let j = 9
while j > 0
- if has("ebcdic")
- execute "normal" j . "a" . j . "\x27"
- else
- execute "normal" j . "a" . j . "\x1b"
- endif
+ execute "normal" j . "a" . j . "\x1b"
let j = j - 1
endwhile
endif
endif
if i == 9
- if has("ebcdic")
- execute "normal Az\047"
- else
- execute "normal Az\033"
- endif
+ execute "normal Az\033"
endif
endwhile
unlet i j
diff --git a/src/nvim/testdir/test_execute_func.vim b/src/nvim/testdir/test_execute_func.vim
index 2cb6d73407..16cc20e9a7 100644
--- a/src/nvim/testdir/test_execute_func.vim
+++ b/src/nvim/testdir/test_execute_func.vim
@@ -147,3 +147,30 @@ func Test_win_execute_other_tab()
tabclose
unlet xyz
endfunc
+
+func Test_win_execute_visual_redraw()
+ call setline(1, ['a', 'b', 'c'])
+ new
+ wincmd p
+ " start Visual in current window, redraw in other window with fewer lines
+ call feedkeys("G\<C-V>", 'txn')
+ call win_execute(winnr('#')->win_getid(), 'redraw')
+ call feedkeys("\<Esc>", 'txn')
+ bwipe!
+ bwipe!
+
+ enew
+ new
+ call setline(1, ['a', 'b', 'c'])
+ let winid = win_getid()
+ wincmd p
+ " start Visual in current window, extend it in other window with more lines
+ call feedkeys("\<C-V>", 'txn')
+ call win_execute(winid, 'call feedkeys("G\<C-V>", ''txn'')')
+ redraw
+
+ bwipe!
+ bwipe!
+endfunc
+
+" vim: shiftwidth=2 sts=2 expandtab
diff --git a/src/nvim/testdir/test_exists.vim b/src/nvim/testdir/test_exists.vim
index fd34be83b0..471c77853d 100644
--- a/src/nvim/testdir/test_exists.vim
+++ b/src/nvim/testdir/test_exists.vim
@@ -94,8 +94,12 @@ func Test_exists()
call assert_equal(0, exists(':edit/a'))
" Valid internal command (partial match)
call assert_equal(1, exists(':q'))
+ " Valid internal command with a digit
+ call assert_equal(2, exists(':2match'))
" Non-existing internal command
call assert_equal(0, exists(':invalidcmd'))
+ " Internal command with a count
+ call assert_equal(0, exists(':3buffer'))
" User defined command (full match)
command! MyCmd :echo 'My command'
diff --git a/src/nvim/testdir/test_exit.vim b/src/nvim/testdir/test_exit.vim
index bd3e9eb4d4..befcaec2b2 100644
--- a/src/nvim/testdir/test_exit.vim
+++ b/src/nvim/testdir/test_exit.vim
@@ -1,6 +1,7 @@
" Tests for exiting Vim.
source shared.vim
+source check.vim
func Test_exiting()
let after =<< trim [CODE]
@@ -109,4 +110,25 @@ func Test_exit_code()
call delete('Xtestout')
endfunc
+func Test_exit_error_reading_input()
+ throw 'Skipped: Nvim does not exit after stdin is read'
+
+ CheckNotGui
+ CheckNotMSWindows
+ " The early exit causes memory not to be freed somehow
+ CheckNotAsan
+
+ call writefile([":au VimLeave * call writefile(['l = ' .. v:exiting], 'Xtestout')", ":tabnew", "q:"], 'Xscript', 'b')
+
+ " Nvim requires "-s -" to read stdin as Normal mode input
+ " if RunVim([], [], '<Xscript')
+ if RunVim([], [], '-s - <Xscript')
+ call assert_equal(1, v:shell_error)
+ call assert_equal(['l = 1'], readfile('Xtestout'))
+ endif
+ call delete('Xscript')
+ call delete('Xtestout')
+endfun
+
+
" vim: shiftwidth=2 sts=2 expandtab
diff --git a/src/nvim/testdir/test_expand.vim b/src/nvim/testdir/test_expand.vim
new file mode 100644
index 0000000000..d86fea4f45
--- /dev/null
+++ b/src/nvim/testdir/test_expand.vim
@@ -0,0 +1,128 @@
+" Test for expanding file names
+
+source shared.vim
+
+func Test_with_directories()
+ call mkdir('Xdir1')
+ call mkdir('Xdir2')
+ call mkdir('Xdir3')
+ cd Xdir3
+ call mkdir('Xdir4')
+ cd ..
+
+ split Xdir1/file
+ call setline(1, ['a', 'b'])
+ w
+ w Xdir3/Xdir4/file
+ close
+
+ next Xdir?/*/file
+ call assert_equal('Xdir3/Xdir4/file', expand('%'))
+ if has('unix')
+ next! Xdir?/*/nofile
+ call assert_equal('Xdir?/*/nofile', expand('%'))
+ endif
+ " Edit another file, on MS-Windows the swap file would be in use and can't
+ " be deleted.
+ edit foo
+
+ call assert_equal(0, delete('Xdir1', 'rf'))
+ call assert_equal(0, delete('Xdir2', 'rf'))
+ call assert_equal(0, delete('Xdir3', 'rf'))
+endfunc
+
+func Test_with_tilde()
+ let dir = getcwd()
+ call mkdir('Xdir ~ dir')
+ call assert_true(isdirectory('Xdir ~ dir'))
+ cd Xdir\ ~\ dir
+ call assert_true(getcwd() =~ 'Xdir \~ dir')
+ call chdir(dir)
+ call delete('Xdir ~ dir', 'd')
+ call assert_false(isdirectory('Xdir ~ dir'))
+endfunc
+
+func Test_expand_tilde_filename()
+ split ~
+ call assert_equal('~', expand('%'))
+ call assert_notequal(expand('%:p'), expand('~/'))
+ call assert_match('\~', expand('%:p'))
+ bwipe!
+endfunc
+
+func Test_expandcmd()
+ let $FOO = 'Test'
+ call assert_equal('e x/Test/y', expandcmd('e x/$FOO/y'))
+ unlet $FOO
+
+ new
+ edit Xfile1
+ call assert_equal('e Xfile1', expandcmd('e %'))
+ edit Xfile2
+ edit Xfile1
+ call assert_equal('e Xfile2', 'e #'->expandcmd())
+ edit Xfile2
+ edit Xfile3
+ edit Xfile4
+ let bnum = bufnr('Xfile2')
+ call assert_equal('e Xfile2', expandcmd('e #' . bnum))
+ call setline('.', 'Vim!@#')
+ call assert_equal('e Vim', expandcmd('e <cword>'))
+ call assert_equal('e Vim!@#', expandcmd('e <cWORD>'))
+ enew!
+ edit Xfile.java
+ call assert_equal('e Xfile.py', expandcmd('e %:r.py'))
+ call assert_equal('make abc.java', expandcmd('make abc.%:e'))
+ call assert_equal('make Xabc.java', expandcmd('make %:s?file?abc?'))
+ edit a1a2a3.rb
+ call assert_equal('make b1b2b3.rb a1a2a3 Xfile.o', expandcmd('make %:gs?a?b? %< #<.o'))
+
+ call assert_fails('call expandcmd("make <afile>")', 'E495:')
+ call assert_fails('call expandcmd("make <afile>")', 'E495:')
+ enew
+ call assert_fails('call expandcmd("make %")', 'E499:')
+ let $FOO="blue\tsky"
+ call setline(1, "$FOO")
+ call assert_equal("grep pat blue\tsky", expandcmd('grep pat <cfile>'))
+ unlet $FOO
+ close!
+endfunc
+
+" Test for expanding <sfile>, <slnum> and <sflnum> outside of sourcing a script
+func Test_source_sfile()
+ let lines =<< trim [SCRIPT]
+ :call assert_fails('echo expandcmd("<sfile>")', 'E498:')
+ :call assert_fails('echo expandcmd("<slnum>")', 'E842:')
+ :call assert_fails('echo expandcmd("<sflnum>")', 'E961:')
+ :call assert_fails('call expandcmd("edit <cfile>")', 'E446:')
+ :call assert_fails('call expandcmd("edit #")', 'E194:')
+ :call assert_fails('call expandcmd("edit #<2")', 'E684:')
+ :call assert_fails('call expandcmd("edit <cword>")', 'E348:')
+ :call assert_fails('call expandcmd("edit <cexpr>")', 'E348:')
+ :call assert_fails('autocmd User MyCmd echo "<sfile>"', 'E498:')
+ :call writefile(v:errors, 'Xresult')
+ :qall!
+
+ [SCRIPT]
+ call writefile(lines, 'Xscript')
+ if RunVim([], [], '--clean -s Xscript')
+ call assert_equal([], readfile('Xresult'))
+ endif
+ call delete('Xscript')
+ call delete('Xresult')
+endfunc
+
+" Test for expanding filenames multiple times in a command line
+func Test_expand_filename_multicmd()
+ edit foo
+ call setline(1, 'foo!')
+ new
+ call setline(1, 'foo!')
+ new <cword> | new <cWORD>
+ call assert_equal(4, winnr('$'))
+ call assert_equal('foo!', bufname(winbufnr(1)))
+ call assert_equal('foo', bufname(winbufnr(2)))
+ %bwipe!
+endfunc
+
+" vim: shiftwidth=2 sts=2 expandtab
diff --git a/src/nvim/testdir/test_expand_func.vim b/src/nvim/testdir/test_expand_func.vim
index 44d2c156d5..b48c2e8a19 100644
--- a/src/nvim/testdir/test_expand_func.vim
+++ b/src/nvim/testdir/test_expand_func.vim
@@ -37,15 +37,6 @@ func Test_expand_sflnum()
delcommand Flnum
endfunc
-func Test_expand()
- new
- 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.
- quit
-endfunc
-
func Test_expand_sfile()
call assert_match('test_expand_func\.vim$', s:sfile)
call assert_match('^function .*\.\.Test_expand_sfile$', expand('<sfile>'))
@@ -77,6 +68,15 @@ func Test_expand_slnum()
delcommand Slnum
endfunc
+func Test_expand()
+ new
+ 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.
+ quit
+endfunc
+
func s:sid_test()
return 'works'
endfunc
@@ -87,4 +87,17 @@ func Test_expand_SID()
call assert_equal('works', g:sid_result)
endfunc
+
+" Test for 'wildignore' with expand()
+func Test_expand_wildignore()
+ set wildignore=*.vim
+ call assert_equal('', expand('test_expand_func.vim'))
+ call assert_equal('', expand('test_expand_func.vim', 0))
+ call assert_equal([], expand('test_expand_func.vim', 0, 1))
+ 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))
+ set wildignore&
+endfunc
+
" vim: shiftwidth=2 sts=2 expandtab
diff --git a/src/nvim/testdir/test_expr.vim b/src/nvim/testdir/test_expr.vim
index 1d7fd3e385..5b10e691e5 100644
--- a/src/nvim/testdir/test_expr.vim
+++ b/src/nvim/testdir/test_expr.vim
@@ -283,6 +283,71 @@ function Test_printf_misc()
call assert_equal('🐍', printf('%.2S', '🐍🐍'))
call assert_equal('', printf('%.1S', '🐍🐍'))
+ call assert_equal('[ あいう]', printf('[%10.6S]', 'あいうえお'))
+ call assert_equal('[ あいうえ]', printf('[%10.8S]', 'あいうえお'))
+ call assert_equal('[あいうえお]', printf('[%10.10S]', 'あいうえお'))
+ call assert_equal('[あいうえお]', printf('[%10.12S]', 'あいうえお'))
+
+ call assert_equal('あいう', printf('%S', 'あいう'))
+ call assert_equal('あいう', printf('%#S', 'あいう'))
+
+ call assert_equal('あb', printf('%2S', 'あb'))
+ call assert_equal('あb', printf('%.4S', 'あb'))
+ call assert_equal('あ', printf('%.2S', 'あb'))
+ call assert_equal(' あb', printf('%4S', 'あb'))
+ call assert_equal('0あb', printf('%04S', 'あb'))
+ call assert_equal('あb ', printf('%-4S', 'あb'))
+ call assert_equal('あ ', printf('%-4.2S', 'あb'))
+
+ call assert_equal('aい', printf('%2S', 'aい'))
+ call assert_equal('aい', printf('%.4S', 'aい'))
+ call assert_equal('a', printf('%.2S', 'aい'))
+ call assert_equal(' aい', printf('%4S', 'aい'))
+ call assert_equal('0aい', printf('%04S', 'aい'))
+ call assert_equal('aい ', printf('%-4S', 'aい'))
+ call assert_equal('a ', printf('%-4.2S', 'aい'))
+
+ call assert_equal('[あいう]', printf('[%05S]', 'あいう'))
+ call assert_equal('[あいう]', printf('[%06S]', 'あいう'))
+ call assert_equal('[0あいう]', printf('[%07S]', 'あいう'))
+
+ call assert_equal('[あiう]', printf('[%05S]', 'あiう'))
+ call assert_equal('[0あiう]', printf('[%06S]', 'あiう'))
+ call assert_equal('[00あiう]', printf('[%07S]', 'あiう'))
+
+ call assert_equal('[0あい]', printf('[%05.4S]', 'あいう'))
+ call assert_equal('[00あい]', printf('[%06.4S]', 'あいう'))
+ call assert_equal('[000あい]', printf('[%07.4S]', 'あいう'))
+
+ call assert_equal('[00あi]', printf('[%05.4S]', 'あiう'))
+ call assert_equal('[000あi]', printf('[%06.4S]', 'あiう'))
+ call assert_equal('[0000あi]', printf('[%07.4S]', 'あiう'))
+
+ call assert_equal('[0あい]', printf('[%05.5S]', 'あいう'))
+ call assert_equal('[00あい]', printf('[%06.5S]', 'あいう'))
+ call assert_equal('[000あい]', printf('[%07.5S]', 'あいう'))
+
+ call assert_equal('[あiう]', printf('[%05.5S]', 'あiう'))
+ call assert_equal('[0あiう]', printf('[%06.5S]', 'あiう'))
+ call assert_equal('[00あiう]', printf('[%07.5S]', 'あiう'))
+
+ call assert_equal('[0000000000]', printf('[%010.0S]', 'あいう'))
+ call assert_equal('[0000000000]', printf('[%010.1S]', 'あいう'))
+ call assert_equal('[00000000あ]', printf('[%010.2S]', 'あいう'))
+ call assert_equal('[00000000あ]', printf('[%010.3S]', 'あいう'))
+ call assert_equal('[000000あい]', printf('[%010.4S]', 'あいう'))
+ call assert_equal('[000000あい]', printf('[%010.5S]', 'あいう'))
+ call assert_equal('[0000あいう]', printf('[%010.6S]', 'あいう'))
+ call assert_equal('[0000あいう]', printf('[%010.7S]', 'あいう'))
+
+ call assert_equal('[0000000000]', printf('[%010.1S]', 'あiう'))
+ call assert_equal('[00000000あ]', printf('[%010.2S]', 'あiう'))
+ call assert_equal('[0000000あi]', printf('[%010.3S]', 'あiう'))
+ call assert_equal('[0000000あi]', printf('[%010.4S]', 'あiう'))
+ call assert_equal('[00000あiう]', printf('[%010.5S]', 'あiう'))
+ call assert_equal('[00000あiう]', printf('[%010.6S]', 'あiう'))
+ call assert_equal('[00000あiう]', printf('[%010.7S]', 'あiう'))
+
call assert_equal('1%', printf('%d%%', 1))
endfunc
diff --git a/src/nvim/testdir/test_feedkeys.vim b/src/nvim/testdir/test_feedkeys.vim
index 70500f2bb5..fb64711863 100644
--- a/src/nvim/testdir/test_feedkeys.vim
+++ b/src/nvim/testdir/test_feedkeys.vim
@@ -12,3 +12,26 @@ func Test_feedkeys_x_with_empty_string()
call assert_equal('foo', getline('.'))
quit!
endfunc
+
+func Test_feedkeys_with_abbreviation()
+ new
+ inoreabbrev trigger value
+ call feedkeys("atrigger ", 'x')
+ call feedkeys("atrigger ", 'x')
+ call assert_equal('value value ', getline(1))
+ bwipe!
+ iunabbrev trigger
+endfunc
+
+func Test_feedkeys_escape_special()
+ nnoremap … <Cmd>let g:got_ellipsis += 1<CR>
+ call feedkeys('…', 't')
+ call assert_equal('…', getcharstr())
+ let g:got_ellipsis = 0
+ call feedkeys('…', 'xt')
+ call assert_equal(1, g:got_ellipsis)
+ unlet g:got_ellipsis
+ nunmap …
+endfunc
+
+" vim: shiftwidth=2 sts=2 expandtab
diff --git a/src/nvim/testdir/test_file_perm.vim b/src/nvim/testdir/test_file_perm.vim
new file mode 100644
index 0000000000..1cb09e8647
--- /dev/null
+++ b/src/nvim/testdir/test_file_perm.vim
@@ -0,0 +1,30 @@
+" Test getting and setting file permissions.
+
+func Test_file_perm()
+ call assert_equal('', getfperm('Xtest'))
+ call assert_equal(0, 'Xtest'->setfperm('r--------'))
+
+ call writefile(['one'], 'Xtest')
+ call assert_true(len('Xtest'->getfperm()) == 9)
+
+ call assert_equal(1, setfperm('Xtest', 'rwx------'))
+ if has('win32')
+ call assert_equal('rw-rw-rw-', getfperm('Xtest'))
+ else
+ call assert_equal('rwx------', getfperm('Xtest'))
+ endif
+
+ call assert_equal(1, setfperm('Xtest', 'r--r--r--'))
+ call assert_equal('r--r--r--', getfperm('Xtest'))
+
+ call assert_fails("setfperm('Xtest', '---')")
+
+ call assert_equal(1, setfperm('Xtest', 'rwx------'))
+ call delete('Xtest')
+
+ call assert_fails("call setfperm(['Xfile'], 'rw-rw-rw-')", 'E730:')
+ call assert_fails("call setfperm('Xfile', [])", 'E730:')
+ call assert_fails("call setfperm('Xfile', 'rwxrwxrwxrw')", 'E475:')
+endfunc
+
+" vim: shiftwidth=2 sts=2 expandtab
diff --git a/src/nvim/testdir/test_filechanged.vim b/src/nvim/testdir/test_filechanged.vim
index b95cd5faf8..c6e781a1ef 100644
--- a/src/nvim/testdir/test_filechanged.vim
+++ b/src/nvim/testdir/test_filechanged.vim
@@ -1,9 +1,10 @@
" Tests for when a file was changed outside of Vim.
+source check.vim
+
func Test_FileChangedShell_reload()
- if !has('unix')
- return
- endif
+ CheckUnix
+
augroup testreload
au FileChangedShell Xchanged_r let g:reason = v:fcs_reason | let v:fcs_choice = 'reload'
augroup END
@@ -90,11 +91,108 @@ func Test_FileChangedShell_reload()
call delete('Xchanged_r')
endfunc
+func Test_FileChangedShell_edit()
+ CheckUnix
+
+ new Xchanged_r
+ call setline(1, 'reload this')
+ set fileformat=unix
+ write
+
+ " File format changed, reload (content only, no 'ff' etc)
+ augroup testreload
+ au!
+ au FileChangedShell Xchanged_r let g:reason = v:fcs_reason | let v:fcs_choice = 'reload'
+ augroup END
+ call assert_equal(&fileformat, 'unix')
+ sleep 10m " make the test less flaky in Nvim
+ call writefile(["line1\r", "line2\r"], 'Xchanged_r')
+ let g:reason = ''
+ checktime
+ call assert_equal('changed', g:reason)
+ call assert_equal(&fileformat, 'unix')
+ call assert_equal("line1\r", getline(1))
+ call assert_equal("line2\r", getline(2))
+ %s/\r
+ write
+
+ " File format changed, reload with 'ff', etc
+ augroup testreload
+ au!
+ au FileChangedShell Xchanged_r let g:reason = v:fcs_reason | let v:fcs_choice = 'edit'
+ augroup END
+ call assert_equal(&fileformat, 'unix')
+ sleep 10m " make the test less flaky in Nvim
+ call writefile(["line1\r", "line2\r"], 'Xchanged_r')
+ let g:reason = ''
+ checktime
+ call assert_equal('changed', g:reason)
+ call assert_equal(&fileformat, 'dos')
+ call assert_equal('line1', getline(1))
+ call assert_equal('line2', getline(2))
+ set fileformat=unix
+ write
+
+ au! testreload
+ bwipe!
+ call delete(undofile('Xchanged_r'))
+ call delete('Xchanged_r')
+endfunc
+
+func Test_FileChangedShell_edit_dialog()
+ throw 'Skipped: requires a UI to be active'
+ CheckNotGui
+ CheckUnix " Using low level feedkeys() does not work on MS-Windows.
+
+ new Xchanged_r
+ call setline(1, 'reload this')
+ set fileformat=unix
+ write
+
+ " File format changed, reload (content only) via prompt
+ augroup testreload
+ au!
+ au FileChangedShell Xchanged_r let g:reason = v:fcs_reason | let v:fcs_choice = 'ask'
+ augroup END
+ call assert_equal(&fileformat, 'unix')
+ call writefile(["line1\r", "line2\r"], 'Xchanged_r')
+ let g:reason = ''
+ call feedkeys('L', 'L') " load file content only
+ checktime
+ call assert_equal('changed', g:reason)
+ call assert_equal(&fileformat, 'unix')
+ call assert_equal("line1\r", getline(1))
+ call assert_equal("line2\r", getline(2))
+ %s/\r
+ write
+
+ " File format changed, reload (file and options) via prompt
+ augroup testreload
+ au!
+ au FileChangedShell Xchanged_r let g:reason = v:fcs_reason | let v:fcs_choice = 'ask'
+ augroup END
+ call assert_equal(&fileformat, 'unix')
+ call writefile(["line1\r", "line2\r"], 'Xchanged_r')
+ let g:reason = ''
+ call feedkeys('a', 'L') " load file content and options
+ checktime
+ call assert_equal('changed', g:reason)
+ call assert_equal(&fileformat, 'dos')
+ call assert_equal("line1", getline(1))
+ call assert_equal("line2", getline(2))
+ set fileformat=unix
+ write
+
+ au! testreload
+ bwipe!
+ call delete(undofile('Xchanged_r'))
+ call delete('Xchanged_r')
+endfunc
+
func Test_file_changed_dialog()
- throw 'skipped: TODO: '
- if !has('unix') || has('gui_running')
- return
- endif
+ throw 'Skipped: requires a UI to be active'
+ CheckUnix
+ CheckNotGui
au! FileChangedShell
new Xchanged_d
@@ -139,7 +237,7 @@ func Test_file_changed_dialog()
sleep 2
silent !touch Xchanged_d
let v:warningmsg = ''
- checktime
+ checktime Xchanged_d
call assert_equal('', v:warningmsg)
call assert_equal(1, line('$'))
call assert_equal('new line', getline(1))
@@ -147,3 +245,19 @@ func Test_file_changed_dialog()
bwipe!
call delete('Xchanged_d')
endfunc
+
+" Test for editing a new buffer from a FileChangedShell autocmd
+func Test_FileChangedShell_newbuf()
+ call writefile(['one', 'two'], 'Xfile')
+ new Xfile
+ augroup testnewbuf
+ autocmd FileChangedShell * enew
+ augroup END
+ sleep 10m " make the test less flaky in Nvim
+ call writefile(['red'], 'Xfile')
+ call assert_fails('checktime', 'E811:')
+ au! testnewbuf
+ call delete('Xfile')
+endfunc
+
+" vim: shiftwidth=2 sts=2 expandtab
diff --git a/src/nvim/testdir/test_filetype.vim b/src/nvim/testdir/test_filetype.vim
index 6e92baa939..59b272d563 100644
--- a/src/nvim/testdir/test_filetype.vim
+++ b/src/nvim/testdir/test_filetype.vim
@@ -76,15 +76,18 @@ let s:filename_checks = {
\ 'ave': ['file.ave'],
\ 'awk': ['file.awk', 'file.gawk'],
\ 'b': ['file.mch', 'file.ref', 'file.imp'],
- \ 'bzl': ['file.bazel', 'file.bzl', 'WORKSPACE'],
+ \ 'basic': ['file.bas', 'file.bi', 'file.bm'],
\ 'bc': ['file.bc'],
\ 'bdf': ['file.bdf'],
- \ 'bib': ['file.bib'],
\ 'beancount': ['file.beancount'],
+ \ 'bib': ['file.bib'],
+ \ 'bicep': ['file.bicep'],
\ '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'],
\ 'bsdl': ['file.bsd', 'file.bsdl', 'bsd', 'some-bsd'],
\ 'bst': ['file.bst'],
+ \ 'bzl': ['file.bazel', 'file.bzl', 'WORKSPACE'],
\ 'bzr': ['bzr_log.any', 'bzr_log.file'],
\ 'c': ['enlightenment/file.cfg', 'file.qc', 'file.c', 'some-enlightenment/file.cfg'],
\ 'cabal': ['file.cabal'],
@@ -97,7 +100,7 @@ let s:filename_checks = {
\ 'cdrtoc': ['file.toc'],
\ 'cf': ['file.cfm', 'file.cfi', 'file.cfc'],
\ 'cfengine': ['cfengine.conf'],
- \ 'cfg': ['file.cfg', 'file.hgrc', 'filehgrc', 'hgrc', 'some-hgrc'],
+ \ 'cfg': ['file.hgrc', 'filehgrc', 'hgrc', 'some-hgrc'],
\ 'ch': ['file.chf'],
\ 'chaiscript': ['file.chai'],
\ 'chaskell': ['file.chs'],
@@ -107,13 +110,16 @@ let s:filename_checks = {
\ 'clean': ['file.dcl', 'file.icl'],
\ 'clojure': ['file.clj', 'file.cljs', 'file.cljx', 'file.cljc'],
\ 'cmake': ['CMakeLists.txt', 'file.cmake', 'file.cmake.in'],
+ \ 'cmod': ['file.cmod'],
\ 'cmusrc': ['any/.cmus/autosave', 'any/.cmus/rc', 'any/.cmus/command-history', 'any/.cmus/file.theme', 'any/cmus/rc', 'any/cmus/file.theme', '/.cmus/autosave', '/.cmus/command-history', '/.cmus/file.theme', '/.cmus/rc', '/cmus/file.theme', '/cmus/rc'],
\ 'cobol': ['file.cbl', 'file.cob', 'file.lib'],
\ 'coco': ['file.atg'],
\ 'conaryrecipe': ['file.recipe'],
\ 'conf': ['auto.master'],
- \ 'config': ['configure.in', 'configure.ac', '/etc/hostname.file'],
+ \ 'config': ['configure.in', 'configure.ac', '/etc/hostname.file', 'any/etc/hostname.file'],
+ \ 'confini': ['/etc/pacman.conf', 'any/etc/pacman.conf', 'mpv.conf'],
\ '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'],
\ 'crm': ['file.crm'],
\ 'crontab': ['crontab', 'crontab.file', '/etc/cron.d/file', 'any/etc/cron.d/file'],
@@ -123,6 +129,7 @@ let s:filename_checks = {
\ 'csp': ['file.csp', 'file.fdr'],
\ 'css': ['file.css'],
\ 'cterm': ['file.con'],
+ \ 'csv': ['file.csv'],
\ 'cucumber': ['file.feature'],
\ 'cuda': ['file.cu', 'file.cuh'],
\ 'cupl': ['file.pld'],
@@ -130,6 +137,7 @@ let s:filename_checks = {
\ 'cvs': ['cvs123'],
\ 'cvsrc': ['.cvsrc'],
\ 'cynpp': ['file.cyn'],
+ \ 'd': ['file.d'],
\ 'dart': ['file.dart', 'file.drt'],
\ 'datascript': ['file.ds'],
\ 'dcd': ['file.dcd'],
@@ -146,12 +154,13 @@ let s:filename_checks = {
\ 'diff': ['file.diff', 'file.rej'],
\ 'dircolors': ['.dir_colors', '.dircolors', '/etc/DIR_COLORS', 'any/etc/DIR_COLORS'],
\ 'dnsmasq': ['/etc/dnsmasq.conf', '/etc/dnsmasq.d/file', 'any/etc/dnsmasq.conf', 'any/etc/dnsmasq.d/file'],
- \ 'dockerfile': ['Containerfile', 'Dockerfile', 'file.Dockerfile', 'Dockerfile.debian', 'Containerfile.something'],
- \ 'dosbatch': ['file.bat', 'file.sys'],
- \ 'dosini': ['.editorconfig', '/etc/pacman.conf', '/etc/yum.conf', 'file.ini', 'npmrc', '.npmrc', 'php.ini', 'php.ini-5', 'php.ini-file', '/etc/yum.repos.d/file', 'any/etc/pacman.conf', 'any/etc/yum.conf', 'any/etc/yum.repos.d/file', 'file.wrap'],
+ \ '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'],
\ 'dot': ['file.dot', 'file.gv'],
\ 'dracula': ['file.drac', 'file.drc', 'filelvs', 'filelpe', 'drac.file', 'lpe', 'lvs', 'some-lpe', 'some-lvs'],
\ 'dtd': ['file.dtd'],
+ \ 'dtrace': ['/usr/lib/dtrace/io.d'],
\ 'dts': ['file.dts', 'file.dtsi'],
\ 'dune': ['jbuild', 'dune', 'dune-project', 'dune-workspace'],
\ 'dylan': ['file.dylan'],
@@ -159,11 +168,12 @@ let s:filename_checks = {
\ 'dylanlid': ['file.lid'],
\ 'ecd': ['file.ecd'],
\ 'edif': ['file.edf', 'file.edif', 'file.edo'],
+ \ 'eelixir': ['file.eex', 'file.leex'],
\ 'elinks': ['elinks.conf'],
\ 'elixir': ['file.ex', 'file.exs', 'mix.lock'],
- \ 'eelixir': ['file.eex', 'file.leex'],
\ 'elm': ['file.elm'],
\ 'elmfilt': ['filter-rules'],
+ \ 'elvish': ['file.elv'],
\ 'epuppet': ['file.epp'],
\ 'erlang': ['file.erl', 'file.hrl', 'file.yaws'],
\ 'eruby': ['file.erb', 'file.rhtml'],
@@ -182,66 +192,70 @@ let s:filename_checks = {
\ 'fgl': ['file.4gl', 'file.4gh', 'file.m4gl'],
\ 'fish': ['file.fish'],
\ 'focexec': ['file.fex', 'file.focexec'],
+ \ 'form': ['file.frm'],
\ 'forth': ['file.ft', 'file.fth'],
\ 'fortran': ['file.f', 'file.for', 'file.fortran', 'file.fpp', 'file.ftn', 'file.f77', 'file.f90', 'file.f95', 'file.f03', 'file.f08'],
\ 'fpcmake': ['file.fpc'],
\ 'framescript': ['file.fsl'],
- \ 'freebasic': ['file.fb', 'file.bi'],
+ \ 'freebasic': ['file.fb'],
\ 'fsharp': ['file.fs', 'file.fsi', 'file.fsx'],
\ 'fstab': ['fstab', 'mtab'],
+ \ 'fusion': ['file.fusion'],
\ 'fvwm': ['/.fvwm/file', 'any/.fvwm/file'],
- \ 'gdb': ['.gdbinit', 'gdbinit'],
+ \ 'gdb': ['.gdbinit', 'gdbinit', 'file.gdb', '.config/gdbearlyinit', '.gdbearlyinit'],
\ 'gdmo': ['file.mo', 'file.gdmo'],
+ \ 'gdresource': ['file.tscn', 'file.tres'],
+ \ 'gdscript': ['file.gd'],
\ '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'],
\ 'gitcommit': ['COMMIT_EDITMSG', 'MERGE_MSG', 'TAG_EDITMSG', 'NOTES_EDITMSG', 'EDIT_DESCRIPTION'],
- \ 'gitconfig': ['file.git/config', '.gitconfig', '.gitmodules', 'file.git/modules//config', '/.config/git/config', '/etc/gitconfig', '/etc/gitconfig.d/file', '/.gitconfig.d/file', 'any/.config/git/config', 'any/.gitconfig.d/file', 'some.git/config', 'some.git/modules/any/config'],
+ \ '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'],
\ 'gitolite': ['gitolite.conf', '/gitolite-admin/conf/file', 'any/gitolite-admin/conf/file'],
\ 'gitrebase': ['git-rebase-todo'],
\ 'gitsendemail': ['.gitsendemail.msg.xxxxxx'],
\ 'gkrellmrc': ['gkrellmrc', 'gkrellmrc_x'],
+ \ 'gleam': ['file.gleam'],
+ \ 'glsl': ['file.glsl'],
\ 'gnash': ['gnashrc', '.gnashrc', 'gnashpluginrc', '.gnashpluginrc'],
- \ 'gnuplot': ['file.gpi'],
+ \ 'gnuplot': ['file.gpi', '.gnuplot'],
\ 'go': ['file.go'],
\ 'gomod': ['go.mod'],
+ \ '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'],
\ 'grads': ['file.gs'],
+ \ 'graphql': ['file.graphql', 'file.graphqls', 'file.gql'],
\ 'gretl': ['file.gretl'],
\ 'groovy': ['file.gradle', 'file.groovy'],
\ 'group': ['any/etc/group', 'any/etc/group-', 'any/etc/group.edit', 'any/etc/gshadow', 'any/etc/gshadow-', 'any/etc/gshadow.edit', 'any/var/backups/group.bak', 'any/var/backups/gshadow.bak', '/etc/group', '/etc/group-', '/etc/group.edit', '/etc/gshadow', '/etc/gshadow-', '/etc/gshadow.edit', '/var/backups/group.bak', '/var/backups/gshadow.bak'],
\ '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'],
+ \ 'hack': ['file.hack', 'file.hackpartial'],
\ 'haml': ['file.haml'],
\ 'hamster': ['file.hsm'],
+ \ 'handlebars': ['file.hbs'],
+ \ 'hare': ['file.ha'],
\ 'haskell': ['file.hs', 'file.hsc', 'file.hs-boot', 'file.hsig'],
\ 'haste': ['file.ht'],
\ 'hastepreproc': ['file.htpp'],
\ 'hb': ['file.hb'],
+ \ 'hcl': ['file.hcl'],
+ \ 'heex': ['file.heex'],
\ 'hercules': ['file.vc', 'file.ev', 'file.sum', 'file.errsum'],
\ 'hex': ['file.hex', 'file.h32'],
\ 'hgcommit': ['hg-editor-file.txt'],
+ \ 'hjson': ['file.hjson'],
\ 'hog': ['file.hog', 'snort.conf', 'vision.conf'],
\ 'hollywood': ['file.hws'],
+ \ 'hoon': ['file.hoon'],
\ 'hostconf': ['/etc/host.conf', 'any/etc/host.conf'],
\ 'hostsaccess': ['/etc/hosts.allow', '/etc/hosts.deny', 'any/etc/hosts.allow', 'any/etc/hosts.deny'],
- \ 'i3config': ['/home/user/.i3/config', '/home/user/.config/i3/config', '/etc/i3/config', '/etc/xdg/i3/config'],
- \ 'logcheck': ['/etc/logcheck/file.d-some/file', '/etc/logcheck/file.d/file', 'any/etc/logcheck/file.d-some/file', 'any/etc/logcheck/file.d/file'],
- \ 'modula3': ['file.m3', 'file.mg', 'file.i3', 'file.ig'],
- \ 'natural': ['file.NSA', 'file.NSC', 'file.NSG', 'file.NSL', 'file.NSM', 'file.NSN', 'file.NSP', 'file.NSS'],
- \ 'neomuttrc': ['Neomuttrc', '.neomuttrc', '.neomuttrc-file', '/.neomutt/neomuttrc', '/.neomutt/neomuttrc-file', 'Neomuttrc', 'Neomuttrc-file', 'any/.neomutt/neomuttrc', 'any/.neomutt/neomuttrc-file', 'neomuttrc', 'neomuttrc-file'],
- \ 'opl': ['file.OPL', 'file.OPl', 'file.OpL', 'file.Opl', 'file.oPL', 'file.oPl', 'file.opL', 'file.opl'],
- \ 'pcmk': ['file.pcmk'],
- \ 'r': ['file.r'],
- \ 'rhelp': ['file.rd'],
- \ 'rmd': ['file.rmd', 'file.smd'],
- \ 'rnoweb': ['file.rnw', 'file.snw'],
- \ 'rrst': ['file.rrst', 'file.srst'],
- \ 'template': ['file.tmpl'],
+ \ 'html': ['file.html', 'file.htm', 'file.cshtml'],
\ 'htmlm4': ['file.html.m4'],
\ 'httest': ['file.htt', 'file.htb'],
+ \ 'i3config': ['/home/user/.i3/config', '/home/user/.config/i3/config', '/etc/i3/config', '/etc/xdg/i3/config'],
\ 'ibasic': ['file.iba', 'file.ibi'],
\ 'icemenu': ['/.icewm/menu', 'any/.icewm/menu'],
\ 'icon': ['file.icn'],
@@ -258,12 +272,14 @@ let s:filename_checks = {
\ 'java': ['file.java', 'file.jav'],
\ 'javacc': ['file.jj', 'file.jjt'],
\ 'javascript': ['file.js', 'file.javascript', 'file.es', 'file.mjs', 'file.cjs'],
+ \ 'javascript.glimmer': ['file.gjs'],
\ 'javascriptreact': ['file.jsx'],
\ 'jess': ['file.clp'],
\ 'jgraph': ['file.jgr'],
\ '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'],
+ \ 'json5': ['file.json5'],
\ 'jsonc': ['file.jsonc'],
\ 'jsp': ['file.jsp'],
\ 'julia': ['file.jl'],
@@ -271,12 +287,14 @@ let s:filename_checks = {
\ 'kivy': ['file.kv'],
\ 'kix': ['file.kix'],
\ 'kotlin': ['file.kt', 'file.ktm', 'file.kts'],
+ \ 'krl': ['file.sub', 'file.Sub', 'file.SUB'],
\ 'kscript': ['file.ks'],
\ 'kwt': ['file.k'],
\ 'lace': ['file.ace', 'file.ACE'],
\ 'latte': ['file.latte', 'file.lte'],
\ 'ld': ['file.ld'],
\ 'ldif': ['file.ldif'],
+ \ 'ledger': ['file.ldg', 'file.ledger', 'file.journal'],
\ 'less': ['file.less'],
\ 'lex': ['file.lex', 'file.l', 'file.lxx', 'file.l++'],
\ 'lftp': ['lftp.conf', '.lftprc', 'anylftp/rc', 'lftp/rc', 'some-lftp/rc'],
@@ -284,22 +302,23 @@ let s:filename_checks = {
\ 'libao': ['/etc/libao.conf', '/.libao', 'any/.libao', 'any/etc/libao.conf'],
\ 'lifelines': ['file.ll'],
\ 'lilo': ['lilo.conf', 'lilo.conf-file'],
+ \ 'lilypond': ['file.ly', 'file.ily'],
\ 'limits': ['/etc/limits', '/etc/anylimits.conf', '/etc/anylimits.d/file.conf', '/etc/limits.conf', '/etc/limits.d/file.conf', '/etc/some-limits.conf', '/etc/some-limits.d/file.conf', 'any/etc/limits', 'any/etc/limits.conf', 'any/etc/limits.d/file.conf', 'any/etc/some-limits.conf', 'any/etc/some-limits.d/file.conf'],
\ 'liquid': ['file.liquid'],
\ 'lisp': ['file.lsp', 'file.lisp', 'file.asd', 'file.el', 'file.cl', '.emacs', '.sawfishrc', 'sbclrc', '.sbclrc'],
\ 'lite': ['file.lite', 'file.lt'],
\ 'litestep': ['/LiteStep/any/file.rc', 'any/LiteStep/any/file.rc'],
+ \ 'logcheck': ['/etc/logcheck/file.d-some/file', '/etc/logcheck/file.d/file', 'any/etc/logcheck/file.d-some/file', 'any/etc/logcheck/file.d/file'],
\ 'loginaccess': ['/etc/login.access', 'any/etc/login.access'],
\ 'logindefs': ['/etc/login.defs', 'any/etc/login.defs'],
\ 'logtalk': ['file.lgt'],
\ 'lotos': ['file.lot', 'file.lotos'],
\ 'lout': ['file.lou', 'file.lout'],
- \ 'lprolog': ['file.sig'],
+ \ 'lpc': ['file.lpc', 'file.ulpc'],
\ 'lsl': ['file.lsl'],
\ 'lss': ['file.lss'],
\ 'lua': ['file.lua', 'file.rockspec', 'file.nse'],
\ 'lynx': ['lynx.cfg'],
- \ 'matlab': ['file.m'],
\ 'm3build': ['m3makefile', 'm3overrides'],
\ 'm3quake': ['file.quake', 'cm3.cfg'],
\ 'm4': ['file.at'],
@@ -314,6 +333,9 @@ let s:filename_checks = {
\ 'markdown': ['file.markdown', 'file.mdown', 'file.mkd', 'file.mkdn', 'file.mdwn', 'file.md'],
\ 'mason': ['file.mason', 'file.mhtml', 'file.comp'],
\ 'master': ['file.mas', 'file.master'],
+ \ 'matlab': ['file.m'],
+ \ 'maxima': ['file.demo', 'file.dmt', 'file.dm1', 'file.dm2', 'file.dm3',
+ \ 'file.wxm', 'maxima-init.mac'],
\ 'mel': ['file.mel'],
\ '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',
@@ -332,8 +354,10 @@ 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'],
\ 'monk': ['file.isc', 'file.monk', 'file.ssc', 'file.tsc'],
\ 'moo': ['file.moo'],
+ \ 'moonscript': ['file.moon'],
\ 'mp': ['file.mp'],
\ 'mplayerconf': ['mplayer.conf', '/.mplayer/config', 'any/.mplayer/config'],
\ 'mrxvtrc': ['mrxvtrc', '.mrxvtrc'],
@@ -346,10 +370,13 @@ let s:filename_checks = {
\ 'n1ql': ['file.n1ql', 'file.nql'],
\ 'named': ['namedfile.conf', 'rndcfile.conf', 'named-file.conf', 'named.conf', 'rndc-file.conf', 'rndc-file.key', 'rndc.conf', 'rndc.key'],
\ 'nanorc': ['/etc/nanorc', 'file.nanorc', 'any/etc/nanorc'],
+ \ 'natural': ['file.NSA', 'file.NSC', 'file.NSG', 'file.NSL', 'file.NSM', 'file.NSN', 'file.NSP', 'file.NSS'],
\ 'ncf': ['file.ncf'],
+ \ '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'],
\ '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'],
@@ -360,7 +387,10 @@ let s:filename_checks = {
\ 'omnimark': ['file.xom', 'file.xin'],
\ 'opam': ['opam', 'file.opam', 'file.opam.template'],
\ 'openroad': ['file.or'],
+ \ 'openscad': ['file.scad'],
+ \ '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'],
\ 'pamconf': ['/etc/pam.conf', '/etc/pam.d/file', 'any/etc/pam.conf', 'any/etc/pam.d/file'],
\ 'pamenv': ['/etc/security/pam_env.conf', '/home/user/.pam_environment', '.pam_environment', 'pam_env.conf'],
\ 'papp': ['file.papp', 'file.pxml', 'file.pxsl'],
@@ -368,14 +398,13 @@ let s:filename_checks = {
\ 'passwd': ['any/etc/passwd', 'any/etc/passwd-', 'any/etc/passwd.edit', 'any/etc/shadow', 'any/etc/shadow-', 'any/etc/shadow.edit', 'any/var/backups/passwd.bak', 'any/var/backups/shadow.bak', '/etc/passwd', '/etc/passwd-', '/etc/passwd.edit', '/etc/shadow', '/etc/shadow-', '/etc/shadow.edit', '/var/backups/passwd.bak', '/var/backups/shadow.bak'],
\ 'pbtxt': ['file.pbtxt'],
\ 'pccts': ['file.g'],
+ \ 'pcmk': ['file.pcmk'],
\ 'pdf': ['file.pdf'],
\ 'perl': ['file.plx', 'file.al', 'file.psgi', 'gitolite.rc', '.gitolite.rc', 'example.gitolite.rc'],
\ 'pf': ['pf.conf'],
\ 'pfmain': ['main.cf'],
- \ 'php': ['file.php', 'file.php9', 'file.phtml', 'file.ctp'],
- \ 'lpc': ['file.lpc', 'file.ulpc'],
+ \ 'php': ['file.php', 'file.php9', 'file.phtml', 'file.ctp', 'file.phpt'],
\ 'pike': ['file.pike', 'file.pmod'],
- \ 'cmod': ['file.cmod'],
\ 'pilrc': ['file.rcp'],
\ 'pine': ['.pinerc', 'pinerc', '.pinercex', 'pinercex'],
\ 'pinfo': ['/etc/pinforc', '/.pinforc', 'any/.pinforc', 'any/etc/pinforc'],
@@ -391,6 +420,7 @@ let s:filename_checks = {
\ 'povini': ['.povrayrc'],
\ 'ppd': ['file.ppd'],
\ 'ppwiz': ['file.it', 'file.ih'],
+ \ 'prisma': ['file.prisma'],
\ 'privoxy': ['file.action'],
\ 'proc': ['file.pc'],
\ 'procmail': ['.procmail', '.procmailrc'],
@@ -402,74 +432,84 @@ let s:filename_checks = {
\ 'ps1xml': ['file.ps1xml'],
\ 'psf': ['file.psf'],
\ 'psl': ['file.psl'],
+ \ 'pug': ['file.pug'],
\ 'puppet': ['file.pp'],
\ 'pyret': ['file.arr'],
\ 'pyrex': ['file.pyx', 'file.pxd'],
\ 'python': ['file.py', 'file.pyw', '.pythonstartup', '.pythonrc', 'file.ptl', 'file.pyi', 'SConstruct'],
+ \ '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'],
+ \ 'r': ['file.r'],
\ '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'],
\ 'ratpoison': ['.ratpoisonrc', 'ratpoisonrc'],
\ 'rbs': ['file.rbs'],
\ 'rc': ['file.rc', 'file.rch'],
\ 'rcs': ['file,v'],
\ 'readline': ['.inputrc', 'inputrc'],
- \ 'remind': ['.reminders', 'file.remind', 'file.rem', '.reminders-file'],
\ 'rego': ['file.rego'],
+ \ 'remind': ['.reminders', 'file.remind', 'file.rem', '.reminders-file'],
+ \ 'rescript': ['file.res', 'file.resi'],
\ 'resolv': ['resolv.conf'],
\ 'reva': ['file.frt'],
\ 'rexx': ['file.rex', 'file.orx', 'file.rxo', 'file.rxj', 'file.jrexx', 'file.rexxj', 'file.rexx', 'file.testGroup', 'file.testUnit'],
+ \ 'rhelp': ['file.rd'],
\ 'rib': ['file.rib'],
+ \ 'rmd': ['file.rmd', 'file.smd'],
\ 'rnc': ['file.rnc'],
\ 'rng': ['file.rng'],
+ \ 'rnoweb': ['file.rnw', 'file.snw'],
+ \ 'robot': ['file.robot', 'file.resource'],
\ 'robots': ['robots.txt'],
\ 'routeros': ['file.rsc'],
\ 'rpcgen': ['file.x'],
\ 'rpl': ['file.rpl'],
+ \ 'rrst': ['file.rrst', 'file.srst'],
\ 'rst': ['file.rst'],
\ 'rtf': ['file.rtf'],
- \ 'ruby': ['.irbrc', 'irbrc', 'file.rb', 'file.rbw', 'file.gemspec', 'file.ru', 'Gemfile', 'file.builder', 'file.rxml', 'file.rjs', 'file.rant', 'file.rake', 'rakefile', 'Rakefile', 'rantfile', 'Rantfile', 'rakefile-file', 'Rakefile-file', 'Puppetfile'],
+ \ 'ruby': ['.irbrc', 'irbrc', 'file.rb', 'file.rbw', 'file.gemspec', 'file.ru', 'Gemfile', 'file.builder', 'file.rxml', 'file.rjs', 'file.rant', 'file.rake', 'rakefile', 'Rakefile', 'rantfile', 'Rantfile', 'rakefile-file', 'Rakefile-file', 'Puppetfile', 'Vagrantfile'],
\ 'rust': ['file.rs'],
\ 'samba': ['smb.conf'],
\ 'sas': ['file.sas'],
\ 'sass': ['file.sass'],
\ 'sather': ['file.sa'],
\ 'sbt': ['file.sbt'],
- \ 'scala': ['file.scala', 'file.sc'],
+ \ 'scala': ['file.scala'],
\ 'scheme': ['file.scm', 'file.ss', 'file.sld', 'file.rkt', 'file.rktd', 'file.rktl'],
\ 'scilab': ['file.sci', 'file.sce'],
\ 'screen': ['.screenrc', 'screenrc'],
- \ 'sexplib': ['file.sexp'],
- \ 'scdoc': ['file.scd'],
\ 'scss': ['file.scss'],
\ 'sd': ['file.sd'],
\ 'sdc': ['file.sdc'],
\ 'sdl': ['file.sdl', 'file.pr'],
\ 'sed': ['file.sed'],
- \ 'sensors': ['/etc/sensors.conf', '/etc/sensors3.conf', 'any/etc/sensors.conf', 'any/etc/sensors3.conf'],
+ \ 'sensors': ['/etc/sensors.conf', '/etc/sensors3.conf', '/etc/sensors.d/file', 'any/etc/sensors.conf', 'any/etc/sensors3.conf', 'any/etc/sensors.d/file'],
\ 'services': ['/etc/services', 'any/etc/services'],
\ 'setserial': ['/etc/serial.conf', 'any/etc/serial.conf'],
+ \ 'sexplib': ['file.sexp'],
\ 'sh': ['.bashrc', 'file.bash', '/usr/share/doc/bash-completion/filter.sh','/etc/udev/cdsymlinks.conf', 'any/etc/udev/cdsymlinks.conf'],
\ 'sieve': ['file.siv', 'file.sieve'],
+ \ 'sil': ['file.sil'],
\ 'simula': ['file.sim'],
\ 'sinda': ['file.sin', 'file.s85'],
\ 'sisu': ['file.sst', 'file.ssm', 'file.ssi', 'file.-sst', 'file._sst', 'file.sst.meta', 'file.-sst.meta', 'file._sst.meta'],
\ 'skill': ['file.il', 'file.ils', 'file.cdf'],
\ 'slang': ['file.sl'],
\ 'slice': ['file.ice'],
- \ 'solution': ['file.sln'],
\ 'slpconf': ['/etc/slp.conf', 'any/etc/slp.conf'],
\ 'slpreg': ['/etc/slp.reg', 'any/etc/slp.reg'],
\ 'slpspi': ['/etc/slp.spi', 'any/etc/slp.spi'],
\ 'slrnrc': ['.slrnrc'],
\ 'slrnsc': ['file.score'],
\ 'sm': ['sendmail.cf'],
- \ 'svelte': ['file.svelte'],
\ 'smarty': ['file.tpl'],
\ 'smcl': ['file.hlp', 'file.ihlp', 'file.smcl'],
\ 'smith': ['file.smt', 'file.smith'],
\ 'sml': ['file.sml'],
\ 'snobol4': ['file.sno', 'file.spt'],
+ \ 'solidity': ['file.sol'],
+ \ 'solution': ['file.sln'],
\ 'sparql': ['file.rq', 'file.sparql'],
\ 'spec': ['file.spec'],
\ 'spice': ['file.sp', 'file.spice'],
@@ -487,11 +527,13 @@ let s:filename_checks = {
\ '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'],
+ \ 'surface': ['file.sface'],
+ \ 'svelte': ['file.svelte'],
\ 'svg': ['file.svg'],
\ 'svn': ['svn-commitfile.tmp', 'svn-commit-file.tmp', 'svn-commit.tmp'],
\ 'swift': ['file.swift'],
\ 'swiftgyb': ['file.swift.gyb'],
- \ 'sil': ['file.sil'],
\ 'sysctl': ['/etc/sysctl.conf', '/etc/sysctl.d/file.conf', 'any/etc/sysctl.conf', 'any/etc/sysctl.d/file.conf'],
\ 'systemd': ['any/systemd/file.automount', 'any/systemd/file.dnssd', 'any/systemd/file.link', 'any/systemd/file.mount', 'any/systemd/file.netdev', 'any/systemd/file.network', 'any/systemd/file.nspawn', 'any/systemd/file.path', 'any/systemd/file.service', 'any/systemd/file.slice', 'any/systemd/file.socket', 'any/systemd/file.swap', 'any/systemd/file.target', 'any/systemd/file.timer', '/etc/systemd/some.conf.d/file.conf', '/etc/systemd/system/some.d/file.conf', '/etc/systemd/system/some.d/.#file', '/etc/systemd/system/.#otherfile', '/home/user/.config/systemd/user/some.d/mine.conf', '/home/user/.config/systemd/user/some.d/.#file', '/home/user/.config/systemd/user/.#otherfile', '/.config/systemd/user/.#', '/.config/systemd/user/.#-file', '/.config/systemd/user/file.d/.#', '/.config/systemd/user/file.d/.#-file', '/.config/systemd/user/file.d/file.conf', '/etc/systemd/file.conf.d/file.conf', '/etc/systemd/system/.#', '/etc/systemd/system/.#-file', '/etc/systemd/system/file.d/.#', '/etc/systemd/system/file.d/.#-file', '/etc/systemd/system/file.d/file.conf', '/systemd/file.automount', '/systemd/file.dnssd', '/systemd/file.link', '/systemd/file.mount', '/systemd/file.netdev', '/systemd/file.network', '/systemd/file.nspawn', '/systemd/file.path', '/systemd/file.service', '/systemd/file.slice', '/systemd/file.socket', '/systemd/file.swap', '/systemd/file.target', '/systemd/file.timer', 'any/.config/systemd/user/.#', 'any/.config/systemd/user/.#-file', 'any/.config/systemd/user/file.d/.#', 'any/.config/systemd/user/file.d/.#-file', 'any/.config/systemd/user/file.d/file.conf', 'any/etc/systemd/file.conf.d/file.conf', 'any/etc/systemd/system/.#', 'any/etc/systemd/system/.#-file', 'any/etc/systemd/system/file.d/.#', 'any/etc/systemd/system/file.d/.#-file', 'any/etc/systemd/system/file.d/file.conf'],
\ 'systemverilog': ['file.sv', 'file.svh'],
@@ -500,8 +542,11 @@ let s:filename_checks = {
\ 'taskdata': ['pending.data', 'completed.data', 'undo.data'],
\ 'taskedit': ['file.task'],
\ 'tcl': ['file.tcl', 'file.tm', 'file.tk', 'file.itcl', 'file.itk', 'file.jacl', '.tclshrc', 'tclsh.rc', '.wishrc'],
+ \ 'teal': ['file.tl'],
+ \ 'template': ['file.tmpl'],
\ 'teraterm': ['file.ttl'],
\ 'terminfo': ['file.ti'],
+ \ 'terraform': ['file.tfvars'],
\ 'tex': ['file.latex', 'file.sty', 'file.dtx', 'file.ltx', 'file.bbl'],
\ 'texinfo': ['file.texinfo', 'file.texi', 'file.txi'],
\ 'texmf': ['texmf.cnf'],
@@ -509,6 +554,7 @@ let s:filename_checks = {
\ 'tf': ['file.tf', '.tfrc', 'tfrc'],
\ 'tidy': ['.tidyrc', 'tidyrc', 'tidy.conf'],
\ 'tilde': ['file.t.html'],
+ \ 'tla': ['file.tla'],
\ 'tli': ['file.tli'],
\ 'tmux': ['tmuxfile.conf', '.tmuxfile.conf', '.tmux-file.conf', '.tmux.conf', 'tmux-file.conf', 'tmux.conf', 'tmux.conf.local'],
\ 'toml': ['file.toml', 'Gopkg.lock', 'Pipfile', '/home/user/.cargo/config'],
@@ -519,7 +565,9 @@ let s:filename_checks = {
\ 'tsscl': ['file.tsscl'],
\ 'tssgm': ['file.tssgm'],
\ 'tssop': ['file.tssop'],
+ \ 'tsv': ['file.tsv'],
\ 'twig': ['file.twig'],
+ \ 'typescript.glimmer': ['file.gts'],
\ 'typescriptreact': ['file.tsx'],
\ 'uc': ['file.uc'],
\ 'udevconf': ['/etc/udev/udev.conf', 'any/etc/udev/udev.conf'],
@@ -533,6 +581,7 @@ let s:filename_checks = {
\ 'upstreamlog': ['fdrupstream.log', 'upstream.log', 'UPSTREAM.LOG', 'upstream.file.log', 'UPSTREAM.FILE.LOG', 'file.upstream.log', 'FILE.UPSTREAM.LOG', 'UPSTREAM-file.log', 'UPSTREAM-FILE.LOG'],
\ 'usserverlog': ['usserver.log', 'USSERVER.LOG', 'usserver.file.log', 'USSERVER.FILE.LOG', 'file.usserver.log', 'FILE.USSERVER.LOG'],
\ 'usw2kagtlog': ['usw2kagt.log', 'USW2KAGT.LOG', 'usw2kagt.file.log', 'USW2KAGT.FILE.LOG', 'file.usw2kagt.log', 'FILE.USW2KAGT.LOG'],
+ \ 'vala': ['file.vala'],
\ 'vb': ['file.sba', 'file.vb', 'file.vbs', 'file.dsm', 'file.ctl'],
\ 'vera': ['file.vr', 'file.vri', 'file.vrh'],
\ 'verilog': ['file.v'],
@@ -549,18 +598,19 @@ let s:filename_checks = {
\ 'wast': ['file.wast', 'file.wat'],
\ 'webmacro': ['file.wm'],
\ 'wget': ['.wgetrc', 'wgetrc'],
+ \ 'wget2': ['.wget2rc', 'wget2rc'],
\ 'winbatch': ['file.wbt'],
\ 'wml': ['file.wml'],
\ 'wsh': ['file.wsf', 'file.wsc'],
\ 'wsml': ['file.wsml'],
\ 'wvdial': ['wvdial.conf', '.wvdialrc'],
\ 'xdefaults': ['.Xdefaults', '.Xpdefaults', '.Xresources', 'xdm-config', 'file.ad', '/Xresources/file', '/app-defaults/file', 'Xresources', 'Xresources-file', 'any/Xresources/file', 'any/app-defaults/file'],
+ \ 'xf86conf': ['xorg.conf', 'xorg.conf-4'],
\ 'xhtml': ['file.xhtml', 'file.xht'],
\ 'xinetd': ['/etc/xinetd.conf', '/etc/xinetd.d/file', 'any/etc/xinetd.conf', 'any/etc/xinetd.d/file'],
\ 'xmath': ['file.msc', 'file.msf'],
\ 'xml': ['/etc/blkid.tab', '/etc/blkid.tab.old', 'file.xmi', 'file.csproj', 'file.csproj.user', 'file.fsproj', 'file.fsproj.user', 'file.vbproj', 'file.vbproj.user', 'file.ui', 'file.tpm', '/etc/xdg/menus/file.menu', 'fglrxrc', 'file.xlf', 'file.xliff', 'file.xul', 'file.wsdl', 'file.wpl', 'any/etc/blkid.tab', 'any/etc/blkid.tab.old', 'any/etc/xdg/menus/file.menu', 'file.atom', 'file.rss', 'file.cdxml', 'file.psc1', 'file.mpd'],
\ 'xmodmap': ['anyXmodmap', 'Xmodmap', 'some-Xmodmap', 'some-xmodmap', 'some-xmodmap-file', 'xmodmap', 'xmodmap-file'],
- \ 'xf86conf': ['xorg.conf', 'xorg.conf-4'],
\ 'xpm': ['file.xpm'],
\ 'xpm2': ['file.xpm2'],
\ 'xquery': ['file.xq', 'file.xql', 'file.xqm', 'file.xquery', 'file.xqy'],
@@ -569,7 +619,7 @@ let s:filename_checks = {
\ 'xslt': ['file.xsl', 'file.xslt'],
\ 'yacc': ['file.yy', 'file.yxx', 'file.y++'],
\ 'yaml': ['file.yaml', 'file.yml'],
- \ 'raml': ['file.raml'],
+ \ 'yang': ['file.yang'],
\ 'z8a': ['file.z8a'],
\ 'zig': ['file.zig'],
\ 'zimbu': ['file.zu'],
@@ -580,7 +630,7 @@ let s:filename_checks = {
\ }
let s:filename_case_checks = {
- \ 'modula2': ['file.DEF', 'file.MOD'],
+ \ 'modula2': ['file.DEF'],
\ 'bzl': ['file.BUILD', 'BUILD'],
\ }
@@ -653,12 +703,13 @@ let s:script_checks = {
\ ['#!/path/nodejs'],
\ ['#!/path/rhino']],
\ 'bc': [['#!/path/bc']],
- \ 'sed': [['#!/path/sed']],
+ \ 'sed': [['#!/path/sed'], ['#n'], ['#n comment']],
\ 'ocaml': [['#!/path/ocaml']],
\ 'awk': [['#!/path/awk'],
\ ['#!/path/gawk']],
\ 'wml': [['#!/path/wml']],
- \ 'scheme': [['#!/path/scheme']],
+ \ 'scheme': [['#!/path/scheme'],
+ \ ['#!/path/guile']],
\ 'cfengine': [['#!/path/cfengine']],
\ 'erlang': [['#!/path/escript']],
\ 'haskell': [['#!/path/haskell']],
@@ -670,6 +721,7 @@ let s:script_checks = {
\ 'routeros': [['#!/path/rsc']],
\ 'fish': [['#!/path/fish']],
\ 'forth': [['#!/path/gforth']],
+ \ 'icon': [['#!/path/icon']],
\ }
" Various forms of "env" optional arguments.
@@ -706,83 +758,252 @@ func Test_setfiletype_completion()
call assert_equal('"setfiletype java javacc javascript javascriptreact', @:)
endfunc
-func Test_hook_file()
+" Test for ':filetype detect' command for a buffer without a file
+func Test_emptybuf_ftdetect()
+ new
+ call setline(1, '#!/bin/sh')
+ call assert_equal('', &filetype)
+ filetype detect
+ call assert_equal('sh', &filetype)
+ close!
+endfunc
+
+" Test for ':filetype indent on' and ':filetype indent off' commands
+func Test_filetype_indent_off()
+ new Xtest.vim
+ filetype indent on
+ call assert_equal(1, g:did_indent_on)
+ call assert_equal(['filetype detection:ON plugin:OFF indent:ON'],
+ \ execute('filetype')->split("\n"))
+ filetype indent off
+ call assert_equal(0, exists('g:did_indent_on'))
+ call assert_equal(['filetype detection:ON plugin:OFF indent:OFF'],
+ \ execute('filetype')->split("\n"))
+ close
+endfunc
+
+"""""""""""""""""""""""""""""""""""""""""""""""""
+" Tests for specific extensions and filetypes.
+" Keep sorted.
+"""""""""""""""""""""""""""""""""""""""""""""""""
+
+func Test_bas_file()
filetype on
- call writefile(['[Trigger]', 'this is pacman config'], 'Xfile.hook')
- split Xfile.hook
- call assert_equal('dosini', &filetype)
+ call writefile(['looks like BASIC'], 'Xfile.bas')
+ split Xfile.bas
+ call assert_equal('basic', &filetype)
bwipe!
- call writefile(['not pacman'], 'Xfile.hook')
- split Xfile.hook
- call assert_notequal('dosini', &filetype)
+ " Test dist#ft#FTbas()
+
+ let g:filetype_bas = 'freebasic'
+ split Xfile.bas
+ call assert_equal('freebasic', &filetype)
bwipe!
+ unlet g:filetype_bas
- call delete('Xfile.hook')
+ " FreeBASIC
+
+ call writefile(["/' FreeBASIC multiline comment '/"], 'Xfile.bas')
+ split Xfile.bas
+ call assert_equal('freebasic', &filetype)
+ bwipe!
+
+ call writefile(['#define TESTING'], 'Xfile.bas')
+ split Xfile.bas
+ call assert_equal('freebasic', &filetype)
+ bwipe!
+
+ call writefile(['option byval'], 'Xfile.bas')
+ split Xfile.bas
+ call assert_equal('freebasic', &filetype)
+ bwipe!
+
+ call writefile(['extern "C"'], 'Xfile.bas')
+ split Xfile.bas
+ call assert_equal('freebasic', &filetype)
+ bwipe!
+
+ " QB64
+
+ call writefile(['$LET TESTING = 1'], 'Xfile.bas')
+ split Xfile.bas
+ call assert_equal('qb64', &filetype)
+ bwipe!
+
+ call writefile(['OPTION _EXPLICIT'], 'Xfile.bas')
+ split Xfile.bas
+ call assert_equal('qb64', &filetype)
+ bwipe!
+
+ " Visual Basic
+
+ call writefile(['Attribute VB_NAME = "Testing"', 'Enum Foo', 'End Enum'], 'Xfile.bas')
+ split Xfile.bas
+ call assert_equal('vb', &filetype)
+ bwipe!
+
+ call delete('Xfile.bas')
filetype off
endfunc
-func Test_ts_file()
+" Test dist#ft#FTcfg()
+func Test_cfg_file()
filetype on
- call writefile(['<?xml version="1.0" encoding="utf-8"?>'], 'Xfile.ts')
- split Xfile.ts
- call assert_equal('xml', &filetype)
+ " *.cfg defaults to cfg
+ call writefile(['looks like cfg'], 'cfgfile.cfg')
+ split cfgfile.cfg
+ call assert_equal('cfg', &filetype)
+
+ let g:filetype_cfg = 'other'
+ edit
+ call assert_equal('other', &filetype)
+ bwipe!
+ unlet g:filetype_cfg
+
+ " RAPID cfg
+ let ext = 'cfg'
+ for i in ['EIO', 'MMC', 'MOC', 'PROC', 'SIO', 'SYS']
+ call writefile([i .. ':CFG'], 'cfgfile.' .. ext)
+ execute "split cfgfile." .. ext
+ call assert_equal('rapid', &filetype)
+ bwipe!
+ call delete('cfgfile.' .. ext)
+ " check different case of file extension
+ let ext = substitute(ext, '\(\l\)', '\u\1', '')
+ endfor
+
+ " clean up
+ filetype off
+endfunc
+
+func Test_d_file()
+ filetype on
+
+ call writefile(['looks like D'], 'Xfile.d')
+ split Xfile.d
+ call assert_equal('d', &filetype)
bwipe!
- call writefile(['// looks like Typescript'], 'Xfile.ts')
- split Xfile.ts
- call assert_equal('typescript', &filetype)
+ call writefile(['#!/some/bin/dtrace'], 'Xfile.d')
+ split Xfile.d
+ call assert_equal('dtrace', &filetype)
+ bwipe!
+
+ call writefile(['#pragma D option'], 'Xfile.d')
+ split Xfile.d
+ call assert_equal('dtrace', &filetype)
+ bwipe!
+
+ call writefile([':some:thing:'], 'Xfile.d')
+ split Xfile.d
+ call assert_equal('dtrace', &filetype)
+ bwipe!
+
+ call writefile(['module this', '#pragma D option'], 'Xfile.d')
+ split Xfile.d
+ call assert_equal('d', &filetype)
+ bwipe!
+
+ call writefile(['import that', '#pragma D option'], 'Xfile.d')
+ split Xfile.d
+ call assert_equal('d', &filetype)
bwipe!
- call delete('Xfile.hook')
filetype off
endfunc
-func Test_ttl_file()
+func Test_dat_file()
filetype on
- call writefile(['@base <http://example.org/> .'], 'Xfile.ttl')
- split Xfile.ttl
- call assert_equal('turtle', &filetype)
+ " KRL header start with "&WORD", but is not always present.
+ call writefile(['&ACCESS'], 'datfile.dat')
+ split datfile.dat
+ call assert_equal('krl', &filetype)
bwipe!
+ call delete('datfile.dat')
- call writefile(['looks like Tera Term Language'], 'Xfile.ttl')
- split Xfile.ttl
- call assert_equal('teraterm', &filetype)
+ " KRL defdat with leading spaces, for KRL file extension is not case
+ " sensitive.
+ call writefile([' DEFDAT datfile'], 'datfile.Dat')
+ split datfile.Dat
+ call assert_equal('krl', &filetype)
bwipe!
+ call delete('datfile.Dat')
+
+ " KRL defdat with embedded spaces, file starts with empty line(s).
+ call writefile(['', 'defdat datfile public'], 'datfile.DAT')
+ split datfile.DAT
+ call assert_equal('krl', &filetype)
+ bwipe!
+
+ " User may overrule file inspection
+ let g:filetype_dat = 'dat'
+ split datfile.DAT
+ call assert_equal('dat', &filetype)
+ bwipe!
+ call delete('datfile.DAT')
+ unlet g:filetype_dat
- call delete('Xfile.ttl')
filetype off
endfunc
-func Test_pp_file()
+func Test_dep3patch_file()
filetype on
- call writefile(['looks like puppet'], 'Xfile.pp')
- split Xfile.pp
- call assert_equal('puppet', &filetype)
+ call assert_true(mkdir('debian/patches', 'p'))
+
+ " series files are not patches
+ call writefile(['Description: some awesome patch'], 'debian/patches/series')
+ split debian/patches/series
+ call assert_notequal('dep3patch', &filetype)
bwipe!
- let g:filetype_pp = 'pascal'
- split Xfile.pp
- call assert_equal('pascal', &filetype)
+ " diff/patch files without the right headers should still show up as ft=diff
+ call writefile([], 'debian/patches/foo.diff')
+ split debian/patches/foo.diff
+ call assert_equal('diff', &filetype)
bwipe!
- unlet g:filetype_pp
- " Test dist#ft#FTpp()
- call writefile(['{ pascal comment'], 'Xfile.pp')
- split Xfile.pp
- call assert_equal('pascal', &filetype)
+ " Files with the right headers are detected as dep3patch, even if they don't
+ " have a diff/patch extension
+ call writefile(['Subject: dep3patches'], 'debian/patches/bar')
+ split debian/patches/bar
+ call assert_equal('dep3patch', &filetype)
bwipe!
- call writefile(['procedure pascal'], 'Xfile.pp')
- split Xfile.pp
- call assert_equal('pascal', &filetype)
+ " Files in sub-directories are detected
+ call assert_true(mkdir('debian/patches/s390x', 'p'))
+ call writefile(['Subject: dep3patches'], 'debian/patches/s390x/bar')
+ split debian/patches/s390x/bar
+ call assert_equal('dep3patch', &filetype)
bwipe!
- call delete('Xfile.pp')
+ " The detection stops when seeing the "header end" marker
+ call writefile(['---', 'Origin: the cloud'], 'debian/patches/baz')
+ split debian/patches/baz
+ call assert_notequal('dep3patch', &filetype)
+ bwipe!
+
+ call delete('debian', 'rf')
+endfunc
+
+func Test_dsl_file()
+ filetype on
+
+ call writefile([' <!doctype dsssl-spec ['], 'dslfile.dsl')
+ split dslfile.dsl
+ call assert_equal('dsl', &filetype)
+ bwipe!
+
+ call writefile(['workspace {'], 'dslfile.dsl')
+ split dslfile.dsl
+ call assert_equal('structurizr', &filetype)
+ bwipe!
+
+ call delete('dslfile.dsl')
filetype off
endfunc
@@ -823,20 +1044,183 @@ func Test_ex_file()
filetype off
endfunc
-func Test_dsl_file()
+func Test_foam_file()
filetype on
+ call assert_true(mkdir('0', 'p'))
+ call assert_true(mkdir('0.orig', 'p'))
- call writefile([' <!doctype dsssl-spec ['], 'dslfile.dsl')
- split dslfile.dsl
- call assert_equal('dsl', &filetype)
+ call writefile(['FoamFile {', ' object something;'], 'Xfile1Dict')
+ split Xfile1Dict
+ call assert_equal('foam', &filetype)
bwipe!
- call writefile(['workspace {'], 'dslfile.dsl')
- split dslfile.dsl
- call assert_equal('structurizr', &filetype)
+ call writefile(['FoamFile {', ' object something;'], 'Xfile1Dict.something')
+ split Xfile1Dict.something
+ call assert_equal('foam', &filetype)
bwipe!
- call delete('dslfile.dsl')
+ call writefile(['FoamFile {', ' object something;'], 'XfileProperties')
+ split XfileProperties
+ call assert_equal('foam', &filetype)
+ bwipe!
+
+ call writefile(['FoamFile {', ' object something;'], 'XfileProperties.something')
+ split XfileProperties.something
+ call assert_equal('foam', &filetype)
+ bwipe!
+
+ call writefile(['FoamFile {', ' object something;'], 'XfileProperties')
+ split XfileProperties
+ call assert_equal('foam', &filetype)
+ bwipe!
+
+ call writefile(['FoamFile {', ' object something;'], 'XfileProperties.something')
+ split XfileProperties.something
+ call assert_equal('foam', &filetype)
+ bwipe!
+
+ call writefile(['FoamFile {', ' object something;'], '0/Xfile')
+ split 0/Xfile
+ call assert_equal('foam', &filetype)
+ bwipe!
+
+ call writefile(['FoamFile {', ' object something;'], '0.orig/Xfile')
+ split 0.orig/Xfile
+ call assert_equal('foam', &filetype)
+ bwipe!
+
+ call delete('0', 'rf')
+ call delete('0.orig', 'rf')
+ call delete('Xfile1Dict')
+ call delete('Xfile1Dict.something')
+ call delete('XfileProperties')
+ call delete('XfileProperties.something')
+ filetype off
+endfunc
+
+func Test_frm_file()
+ filetype on
+
+ call writefile(['looks like FORM'], 'Xfile.frm')
+ split Xfile.frm
+ call assert_equal('form', &filetype)
+ bwipe!
+
+ " Test dist#ft#FTfrm()
+
+ let g:filetype_frm = 'form'
+ split Xfile.frm
+ call assert_equal('form', &filetype)
+ bwipe!
+ unlet g:filetype_frm
+
+ " Visual Basic
+
+ call writefile(['Begin VB.Form Form1'], 'Xfile.frm')
+ split Xfile.frm
+ call assert_equal('vb', &filetype)
+ bwipe!
+
+ call delete('Xfile.frm')
+ filetype off
+endfunc
+
+func Test_fs_file()
+ filetype on
+
+ call writefile(['looks like F#'], 'Xfile.fs')
+ split Xfile.fs
+ call assert_equal('fsharp', &filetype)
+ bwipe!
+
+ let g:filetype_fs = 'forth'
+ split Xfile.fs
+ call assert_equal('forth', &filetype)
+ bwipe!
+ unlet g:filetype_fs
+
+ " Test dist#ft#FTfs()
+
+ " Forth (Gforth)
+
+ call writefile(['( Forth inline comment )'], 'Xfile.fs')
+ split Xfile.fs
+ call assert_equal('forth', &filetype)
+ bwipe!
+
+ call writefile(['.( Forth displayed inline comment )'], 'Xfile.fs')
+ split Xfile.fs
+ call assert_equal('forth', &filetype)
+ bwipe!
+
+ call writefile(['\ Forth line comment'], 'Xfile.fs')
+ split Xfile.fs
+ call assert_equal('forth', &filetype)
+ bwipe!
+
+ " empty line comment - no space required
+ call writefile(['\'], 'Xfile.fs')
+ split Xfile.fs
+ call assert_equal('forth', &filetype)
+ bwipe!
+
+ call writefile(['\G Forth documentation comment '], 'Xfile.fs')
+ split Xfile.fs
+ call assert_equal('forth', &filetype)
+ bwipe!
+
+ call writefile([': squared ( n -- n^2 )', 'dup * ;'], 'Xfile.fs')
+ split Xfile.fs
+ call assert_equal('forth', &filetype)
+ bwipe!
+
+ call delete('Xfile.fs')
+ filetype off
+endfunc
+
+func Test_git_file()
+ filetype on
+
+ call assert_true(mkdir('Xrepo.git', 'p'))
+
+ call writefile([], 'Xrepo.git/HEAD')
+ split Xrepo.git/HEAD
+ call assert_equal('', &filetype)
+ bwipe!
+
+ call writefile(['0000000000000000000000000000000000000000'], 'Xrepo.git/HEAD')
+ split Xrepo.git/HEAD
+ call assert_equal('git', &filetype)
+ bwipe!
+
+ call writefile(['0000000000000000000000000000000000000000000000000000000000000000'], 'Xrepo.git/HEAD')
+ split Xrepo.git/HEAD
+ call assert_equal('git', &filetype)
+ bwipe!
+
+ call writefile(['ref: refs/heads/master'], 'Xrepo.git/HEAD')
+ split Xrepo.git/HEAD
+ call assert_equal('git', &filetype)
+ bwipe!
+
+ call delete('Xrepo.git', 'rf')
+ filetype off
+endfunc
+
+func Test_hook_file()
+ filetype on
+
+ call writefile(['[Trigger]', 'this is pacman config'], 'Xfile.hook')
+ split Xfile.hook
+ call assert_equal('conf', &filetype)
+ bwipe!
+
+ call writefile(['not pacman'], 'Xfile.hook')
+ split Xfile.hook
+ call assert_notequal('conf', &filetype)
+ bwipe!
+
+ call delete('Xfile.hook')
filetype off
endfunc
@@ -940,209 +1324,547 @@ func Test_m_file()
filetype off
endfunc
-func Test_xpm_file()
+func Test_mod_file()
filetype on
- call writefile(['this is XPM2'], 'file.xpm')
- split file.xpm
- call assert_equal('xpm2', &filetype)
+ " *.mod defaults to Modsim III
+ call writefile(['locks like Modsim III'], 'modfile.mod')
+ split modfile.mod
+ call assert_equal('modsim3', &filetype)
bwipe!
- call delete('file.xpm')
+ " Users preference set by g:filetype_mod
+ let g:filetype_mod = 'lprolog'
+ split modfile.mod
+ call assert_equal('lprolog', &filetype)
+ unlet g:filetype_mod
+ bwipe!
+
+ " RAPID header start with a line containing only "%%%",
+ " but is not always present.
+ call writefile(['%%%'], 'modfile.mod')
+ split modfile.mod
+ call assert_equal('rapid', &filetype)
+ bwipe!
+ call delete('modfile.mod')
+
+ " RAPID supports umlauts in module names, leading spaces,
+ " the .mod extension is not case sensitive.
+ call writefile([' module ÜmlautModule'], 'modfile.Mod')
+ split modfile.Mod
+ call assert_equal('rapid', &filetype)
+ bwipe!
+ call delete('modfile.Mod')
+
+ " 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
+ call assert_equal('rapid', &filetype)
+ bwipe!
+
+ " Modula-2 MODULE not start of line
+ call writefile(['IMPLEMENTATION MODULE Module2Mod;'], 'modfile.MOD')
+ split modfile.MOD
+ call assert_equal('modula2', &filetype)
+ bwipe!
+
+ " Modula-2 with comment and empty lines prior MODULE
+ call writefile(['', '(* with', ' comment *)', '', 'MODULE Module2Mod;'], 'modfile.MOD')
+ split modfile.MOD
+ call assert_equal('modula2', &filetype)
+ bwipe!
+ call delete('modfile.MOD')
+
+ " LambdaProlog module
+ call writefile(['module lpromod.'], 'modfile.mod')
+ split modfile.mod
+ call assert_equal('lprolog', &filetype)
+ bwipe!
+
+ " LambdaProlog with comment and empty lines prior module
+ call writefile(['', '% with', '% comment', '', 'module lpromod.'], 'modfile.mod')
+ split modfile.mod
+ call assert_equal('lprolog', &filetype)
+ bwipe!
+ call delete('modfile.mod')
+
+ " go.mod
+ call writefile(['module example.com/M'], 'go.mod')
+ split go.mod
+ call assert_equal('gomod', &filetype)
+ bwipe!
+ call delete('go.mod')
+
filetype off
endfunc
-func Test_fs_file()
+func Test_patch_file()
filetype on
- call writefile(['looks like F#'], 'Xfile.fs')
- split Xfile.fs
- call assert_equal('fsharp', &filetype)
+ call writefile([], 'Xfile.patch')
+ split Xfile.patch
+ call assert_equal('diff', &filetype)
bwipe!
- let g:filetype_fs = 'forth'
- split Xfile.fs
- call assert_equal('forth', &filetype)
+ call writefile(['From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001'], 'Xfile.patch')
+ split Xfile.patch
+ call assert_equal('gitsendemail', &filetype)
bwipe!
- unlet g:filetype_fs
- " Test dist#ft#FTfs()
+ call writefile(['From 0000000000000000000000000000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001'], 'Xfile.patch')
+ split Xfile.patch
+ call assert_equal('gitsendemail', &filetype)
+ bwipe!
- " Forth (Gforth)
+ call delete('Xfile.patch')
+ filetype off
+endfunc
- call writefile(['( Forth inline comment )'], 'Xfile.fs')
- split Xfile.fs
- call assert_equal('forth', &filetype)
+func Test_perl_file()
+ filetype on
+
+ " only tests one case, should do more
+ let lines =<< trim END
+
+ use a
+ END
+ call writefile(lines, "Xfile.t")
+ split Xfile.t
+ call assert_equal('perl', &filetype)
+ bwipe
+
+ call delete('Xfile.t')
+ filetype off
+endfunc
+
+func Test_pp_file()
+ filetype on
+
+ call writefile(['looks like puppet'], 'Xfile.pp')
+ split Xfile.pp
+ call assert_equal('puppet', &filetype)
bwipe!
- call writefile(['.( Forth displayed inline comment )'], 'Xfile.fs')
- split Xfile.fs
- call assert_equal('forth', &filetype)
+ let g:filetype_pp = 'pascal'
+ split Xfile.pp
+ call assert_equal('pascal', &filetype)
bwipe!
+ unlet g:filetype_pp
- call writefile(['\ Forth line comment'], 'Xfile.fs')
- split Xfile.fs
- call assert_equal('forth', &filetype)
+ " Test dist#ft#FTpp()
+ call writefile(['{ pascal comment'], 'Xfile.pp')
+ split Xfile.pp
+ call assert_equal('pascal', &filetype)
bwipe!
- " empty line comment - no space required
- call writefile(['\'], 'Xfile.fs')
- split Xfile.fs
- call assert_equal('forth', &filetype)
+ call writefile(['procedure pascal'], 'Xfile.pp')
+ split Xfile.pp
+ call assert_equal('pascal', &filetype)
bwipe!
- call writefile(['\G Forth documentation comment '], 'Xfile.fs')
- split Xfile.fs
- call assert_equal('forth', &filetype)
+ call delete('Xfile.pp')
+ filetype off
+endfunc
+
+" Test dist#ft#FTprg()
+func Test_prg_file()
+ filetype on
+
+ " *.prg defaults to clipper
+ call writefile(['looks like clipper'], 'prgfile.prg')
+ split prgfile.prg
+ call assert_equal('clipper', &filetype)
bwipe!
- call writefile([': squared ( n -- n^2 )', 'dup * ;'], 'Xfile.fs')
- split Xfile.fs
- call assert_equal('forth', &filetype)
+ " Users preference set by g:filetype_prg
+ let g:filetype_prg = 'eviews'
+ split prgfile.prg
+ call assert_equal('eviews', &filetype)
+ unlet g:filetype_prg
bwipe!
- call delete('Xfile.fs')
+ " RAPID header start with a line containing only "%%%",
+ " but is not always present.
+ call writefile(['%%%'], 'prgfile.prg')
+ split prgfile.prg
+ call assert_equal('rapid', &filetype)
+ bwipe!
+ call delete('prgfile.prg')
+
+ " RAPID supports umlauts in module names, leading spaces,
+ " the .prg extension is not case sensitive.
+ call writefile([' module ÜmlautModule'], 'prgfile.Prg')
+ split prgfile.Prg
+ call assert_equal('rapid', &filetype)
+ bwipe!
+ call delete('prgfile.Prg')
+
+ " 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
+ call assert_equal('rapid', &filetype)
+ bwipe!
+ call delete('prgfile.PRG')
+
filetype off
endfunc
-func Test_dep3patch_file()
+" Test dist#ft#FTsc()
+func Test_sc_file()
filetype on
- call assert_true(mkdir('debian/patches', 'p'))
+ " 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')
- " series files are not patches
- call writefile(['Description: some awesome patch'], 'debian/patches/series')
- split debian/patches/series
- call assert_notequal('dep3patch', &filetype)
+ " SC classes are defined with '+ Class {}'
+ call writefile(['+ SCNvim {', '*methodArgs {|method|'], 'srcfile.sc')
+ split srcfile.sc
+ call assert_equal('supercollider', &filetype)
bwipe!
+ call delete('srcfile.sc')
- " diff/patch files without the right headers should still show up as ft=diff
- call writefile([], 'debian/patches/foo.diff')
- split debian/patches/foo.diff
- call assert_equal('diff', &filetype)
+ " Some SC class files start with comment and define methods many lines later
+ call writefile(['// Query', '//Method','^this {'], 'srcfile.sc')
+ split srcfile.sc
+ call assert_equal('supercollider', &filetype)
bwipe!
+ call delete('srcfile.sc')
- " Files with the right headers are detected as dep3patch, even if they don't
- " have a diff/patch extension
- call writefile(['Subject: dep3patches'], 'debian/patches/bar')
- split debian/patches/bar
- call assert_equal('dep3patch', &filetype)
+ " Some SC class files put comments between method declaration after class
+ call writefile(['PingPong {', '//comment','*ar { arg'], 'srcfile.sc')
+ split srcfile.sc
+ call assert_equal('supercollider', &filetype)
bwipe!
+ call delete('srcfile.sc')
- " Files in sub-directories are detected
- call assert_true(mkdir('debian/patches/s390x', 'p'))
- call writefile(['Subject: dep3patches'], 'debian/patches/s390x/bar')
- split debian/patches/s390x/bar
- call assert_equal('dep3patch', &filetype)
+ filetype off
+endfunc
+
+" Test dist#ft#FTscd()
+func Test_scd_file()
+ filetype on
+
+ call writefile(['ijq(1)'], 'srcfile.scd')
+ split srcfile.scd
+ call assert_equal('scdoc', &filetype)
bwipe!
+ call delete('srcfile.scd')
- " The detection stops when seeing the "header end" marker
- call writefile(['---', 'Origin: the cloud'], 'debian/patches/baz')
- split debian/patches/baz
- call assert_notequal('dep3patch', &filetype)
+ filetype off
+endfunc
+
+func Test_src_file()
+ filetype on
+
+ " KRL header start with "&WORD", but is not always present.
+ call writefile(['&ACCESS'], 'srcfile.src')
+ split srcfile.src
+ call assert_equal('krl', &filetype)
bwipe!
+ call delete('srcfile.src')
- call delete('debian', 'rf')
+ " KRL def with leading spaces, for KRL file extension is not case sensitive.
+ call writefile([' DEF srcfile()'], 'srcfile.Src')
+ split srcfile.Src
+ call assert_equal('krl', &filetype)
+ bwipe!
+ call delete('srcfile.Src')
+
+ " KRL global deffct with embedded spaces, file starts with empty line(s).
+ for text in ['global def srcfile()', 'global deffct srcfile()']
+ call writefile(['', text], 'srcfile.SRC')
+ split srcfile.SRC
+ call assert_equal('krl', &filetype, text)
+ bwipe!
+ endfor
+
+ " User may overrule file inspection
+ let g:filetype_src = 'src'
+ split srcfile.SRC
+ call assert_equal('src', &filetype)
+ bwipe!
+ call delete('srcfile.SRC')
+ unlet g:filetype_src
+
+ filetype off
endfunc
-func Test_patch_file()
+func Test_sys_file()
filetype on
- call writefile([], 'Xfile.patch')
- split Xfile.patch
- call assert_equal('diff', &filetype)
+ " *.sys defaults to Batch file for MSDOS
+ call writefile(['looks like dos batch'], 'sysfile.sys')
+ split sysfile.sys
+ call assert_equal('bat', &filetype)
bwipe!
- call writefile(['From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001'], 'Xfile.patch')
- split Xfile.patch
- call assert_equal('gitsendemail', &filetype)
+ " Users preference set by g:filetype_sys
+ let g:filetype_sys = 'sys'
+ split sysfile.sys
+ call assert_equal('sys', &filetype)
+ unlet g:filetype_sys
bwipe!
- call writefile(['From 0000000000000000000000000000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001'], 'Xfile.patch')
- split Xfile.patch
- call assert_equal('gitsendemail', &filetype)
+ " RAPID header start with a line containing only "%%%",
+ " but is not always present.
+ call writefile(['%%%'], 'sysfile.sys')
+ split sysfile.sys
+ call assert_equal('rapid', &filetype)
bwipe!
+ call delete('sysfile.sys')
+
+ " RAPID supports umlauts in module names, leading spaces,
+ " the .sys extension is not case sensitive.
+ call writefile([' module ÜmlautModule'], 'sysfile.Sys')
+ split sysfile.Sys
+ call assert_equal('rapid', &filetype)
+ bwipe!
+ call delete('sysfile.Sys')
+
+ " 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
+ call assert_equal('rapid', &filetype)
+ bwipe!
+ call delete('sysfile.SYS')
- call delete('Xfile.patch')
filetype off
endfunc
-func Test_git_file()
+func Test_tex_file()
filetype on
- call assert_true(mkdir('Xrepo.git', 'p'))
+ " only tests one case, should do more
+ let lines =<< trim END
+ % This is a sentence.
- call writefile([], 'Xrepo.git/HEAD')
- split Xrepo.git/HEAD
+ This is a sentence.
+ END
+ call writefile(lines, "Xfile.tex")
+ split Xfile.tex
+ call assert_equal('plaintex', &filetype)
+ bwipe
+
+ call delete('Xfile.tex')
+ filetype off
+endfunc
+
+func Test_tf_file()
+ filetype on
+
+ call writefile([';;; TF MUD client is super duper cool'], 'Xfile.tf')
+ split Xfile.tf
+ call assert_equal('tf', &filetype)
+ bwipe!
+
+ call writefile(['provider "azurerm" {'], 'Xfile.tf')
+ split Xfile.tf
+ call assert_equal('terraform', &filetype)
+ bwipe!
+
+ call delete('Xfile.tf')
+ filetype off
+endfunc
+
+func Test_ts_file()
+ filetype on
+
+ call writefile(['<?xml version="1.0" encoding="utf-8"?>'], 'Xfile.ts')
+ split Xfile.ts
+ call assert_equal('xml', &filetype)
+ bwipe!
+
+ call writefile(['// looks like Typescript'], 'Xfile.ts')
+ split Xfile.ts
+ call assert_equal('typescript', &filetype)
+ bwipe!
+
+ call delete('Xfile.ts')
+ filetype off
+endfunc
+
+func Test_ttl_file()
+ filetype on
+
+ call writefile(['@base <http://example.org/> .'], 'Xfile.ttl')
+ split Xfile.ttl
+ call assert_equal('turtle', &filetype)
+ bwipe!
+
+ call writefile(['looks like Tera Term Language'], 'Xfile.ttl')
+ split Xfile.ttl
+ call assert_equal('teraterm', &filetype)
+ bwipe!
+
+ call delete('Xfile.ttl')
+ filetype off
+endfunc
+
+func Test_xpm_file()
+ filetype on
+
+ call writefile(['this is XPM2'], 'file.xpm')
+ split file.xpm
+ call assert_equal('xpm2', &filetype)
+ bwipe!
+
+ call delete('file.xpm')
+ filetype off
+endfunc
+
+func Test_cls_file()
+ filetype on
+
+ call writefile(['looks like Smalltalk'], 'Xfile.cls')
+ split Xfile.cls
+ call assert_equal('st', &filetype)
+ bwipe!
+
+ " Test dist#ft#FTcls()
+
+ let g:filetype_cls = 'vb'
+ split Xfile.cls
+ call assert_equal('vb', &filetype)
+ bwipe!
+ unlet g:filetype_cls
+
+ " TeX
+
+ call writefile(['%'], 'Xfile.cls')
+ split Xfile.cls
+ call assert_equal('tex', &filetype)
+ bwipe!
+
+ " Rexx
+
+ call writefile(['# rexx'], 'Xfile.cls')
+ split Xfile.cls
+ call assert_equal('rexx', &filetype)
+ bwipe!
+
+ " Visual Basic
+
+ call writefile(['VERSION 1.0 CLASS'], 'Xfile.cls')
+ split Xfile.cls
+ call assert_equal('vb', &filetype)
+ bwipe!
+
+ call delete('Xfile.cls')
+ filetype off
+endfunc
+
+func Test_sig_file()
+ filetype on
+
+ call writefile(['this is neither Lambda Prolog nor SML'], 'Xfile.sig')
+ split Xfile.sig
call assert_equal('', &filetype)
bwipe!
- call writefile(['0000000000000000000000000000000000000000'], 'Xrepo.git/HEAD')
- split Xrepo.git/HEAD
- call assert_equal('git', &filetype)
+ " Test dist#ft#FTsig()
+
+ let g:filetype_sig = 'sml'
+ split Xfile.sig
+ call assert_equal('sml', &filetype)
bwipe!
+ unlet g:filetype_sig
- call writefile(['0000000000000000000000000000000000000000000000000000000000000000'], 'Xrepo.git/HEAD')
- split Xrepo.git/HEAD
- call assert_equal('git', &filetype)
+ " Lambda Prolog
+
+ call writefile(['sig foo.'], 'Xfile.sig')
+ split Xfile.sig
+ call assert_equal('lprolog', &filetype)
bwipe!
- call writefile(['ref: refs/heads/master'], 'Xrepo.git/HEAD')
- split Xrepo.git/HEAD
- call assert_equal('git', &filetype)
+ call writefile(['/* ... */'], 'Xfile.sig')
+ split Xfile.sig
+ call assert_equal('lprolog', &filetype)
bwipe!
- call delete('Xrepo.git', 'rf')
+ call writefile(['% ...'], 'Xfile.sig')
+ split Xfile.sig
+ call assert_equal('lprolog', &filetype)
+ bwipe!
+
+ " SML signature file
+
+ call writefile(['signature FOO ='], 'Xfile.sig')
+ split Xfile.sig
+ call assert_equal('sml', &filetype)
+ bwipe!
+
+ call writefile(['structure FOO ='], 'Xfile.sig')
+ split Xfile.sig
+ call assert_equal('sml', &filetype)
+ bwipe!
+
+ call writefile(['(* ... *)'], 'Xfile.sig')
+ split Xfile.sig
+ call assert_equal('sml', &filetype)
+ bwipe!
+
+ call delete('Xfile.sig')
filetype off
endfunc
-func Test_foam_file()
+func Test_inc_file()
filetype on
- call assert_true(mkdir('0', 'p'))
- call assert_true(mkdir('0.orig', 'p'))
- call writefile(['FoamFile {', ' object something;'], 'Xfile1Dict')
- split Xfile1Dict
- call assert_equal('foam', &filetype)
+ call writefile(['this is the fallback'], 'Xfile.inc')
+ split Xfile.inc
+ call assert_equal('pov', &filetype)
bwipe!
- call writefile(['FoamFile {', ' object something;'], 'Xfile1Dict.something')
- split Xfile1Dict.something
- call assert_equal('foam', &filetype)
+ let g:filetype_inc = 'foo'
+ split Xfile.inc
+ call assert_equal('foo', &filetype)
bwipe!
+ unlet g:filetype_inc
- call writefile(['FoamFile {', ' object something;'], 'XfileProperties')
- split XfileProperties
- call assert_equal('foam', &filetype)
+ " aspperl
+ call writefile(['perlscript'], 'Xfile.inc')
+ split Xfile.inc
+ call assert_equal('aspperl', &filetype)
bwipe!
- call writefile(['FoamFile {', ' object something;'], 'XfileProperties.something')
- split XfileProperties.something
- call assert_equal('foam', &filetype)
+ " aspvbs
+ call writefile(['<% something'], 'Xfile.inc')
+ split Xfile.inc
+ call assert_equal('aspvbs', &filetype)
bwipe!
- call writefile(['FoamFile {', ' object something;'], 'XfileProperties')
- split XfileProperties
- call assert_equal('foam', &filetype)
+ " php
+ call writefile(['<?php'], 'Xfile.inc')
+ split Xfile.inc
+ call assert_equal('php', &filetype)
bwipe!
- call writefile(['FoamFile {', ' object something;'], 'XfileProperties.something')
- split XfileProperties.something
- call assert_equal('foam', &filetype)
+ " pascal
+ call writefile(['program'], 'Xfile.inc')
+ split Xfile.inc
+ call assert_equal('pascal', &filetype)
bwipe!
- call writefile(['FoamFile {', ' object something;'], '0/Xfile')
- split 0/Xfile
- call assert_equal('foam', &filetype)
+ " bitbake
+ call writefile(['require foo'], 'Xfile.inc')
+ split Xfile.inc
+ call assert_equal('bitbake', &filetype)
bwipe!
- call writefile(['FoamFile {', ' object something;'], '0.orig/Xfile')
- split 0.orig/Xfile
- call assert_equal('foam', &filetype)
+ " asm
+ call writefile(['asmsyntax=bar'], 'Xfile.inc')
+ split Xfile.inc
+ call assert_equal('bar', &filetype)
bwipe!
- call delete('0', 'rf')
- call delete('0.orig', 'rf')
+ call delete('Xfile.inc')
filetype off
endfunc
diff --git a/src/nvim/testdir/test_filetype_lua.vim b/src/nvim/testdir/test_filetype_lua.vim
deleted file mode 100644
index f73e4ca33f..0000000000
--- a/src/nvim/testdir/test_filetype_lua.vim
+++ /dev/null
@@ -1,2 +0,0 @@
-let g:do_filetype_lua = 1
-source test_filetype.vim
diff --git a/src/nvim/testdir/test_filter_cmd.vim b/src/nvim/testdir/test_filter_cmd.vim
index 0c45db049b..dae164b11c 100644
--- a/src/nvim/testdir/test_filter_cmd.vim
+++ b/src/nvim/testdir/test_filter_cmd.vim
@@ -45,6 +45,14 @@ func Test_filter_fails()
call assert_fails('filter /pat', 'E476:')
call assert_fails('filter /pat/', 'E476:')
call assert_fails('filter /pat/ asdf', 'E492:')
+ " Using assert_fails() causes E476 instead of E866. So use a try-catch.
+ let caught_e866 = 0
+ try
+ filter /\@>b/ ls
+ catch /E866:/
+ let caught_e866 = 1
+ endtry
+ call assert_equal(1, caught_e866)
call assert_fails('filter!', 'E471:')
call assert_fails('filter! pat', 'E476:')
@@ -145,3 +153,38 @@ func Test_filter_commands()
bwipe! file.h
bwipe! file.hs
endfunc
+
+func Test_filter_display()
+ edit Xdoesnotmatch
+ let @a = '!!willmatch'
+ let @b = '!!doesnotmatch'
+ let @c = "oneline\ntwoline\nwillmatch\n"
+ let @/ = '!!doesnotmatch'
+ call feedkeys(":echo '!!doesnotmatch:'\<CR>", 'ntx')
+ let lines = map(split(execute('filter /willmatch/ display'), "\n"), 'v:val[5:6]')
+
+ call assert_true(index(lines, '"a') >= 0)
+ call assert_false(index(lines, '"b') >= 0)
+ call assert_true(index(lines, '"c') >= 0)
+ call assert_false(index(lines, '"/') >= 0)
+ call assert_false(index(lines, '":') >= 0)
+ call assert_false(index(lines, '"%') >= 0)
+
+ let lines = map(split(execute('filter /doesnotmatch/ display'), "\n"), 'v:val[5:6]')
+ call assert_true(index(lines, '"a') < 0)
+ call assert_false(index(lines, '"b') < 0)
+ call assert_true(index(lines, '"c') < 0)
+ call assert_false(index(lines, '"/') < 0)
+ call assert_false(index(lines, '":') < 0)
+ call assert_false(index(lines, '"%') < 0)
+
+ bwipe!
+endfunc
+
+func Test_filter_scriptnames()
+ let lines = split(execute('filter /test_filter_cmd/ scriptnames'), "\n")
+ call assert_equal(1, len(lines))
+ call assert_match('filter_cmd', lines[0])
+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 a52a66ac2f..1cd3a2287b 100644
--- a/src/nvim/testdir/test_filter_map.vim
+++ b/src/nvim/testdir/test_filter_map.vim
@@ -88,4 +88,14 @@ func Test_map_filter_fails()
call assert_fails("let l = filter('abc', '\"> \" . v:val')", 'E896:')
endfunc
+func Test_map_and_modify()
+ let l = ["abc"]
+ " cannot change the list halfway a map()
+ call assert_fails('call map(l, "remove(l, 0)[0]")', 'E741:')
+
+ let d = #{a: 1, b: 2, c: 3}
+ call assert_fails('call map(d, "remove(d, v:key)[0]")', 'E741:')
+ call assert_fails('echo map(d, {k,v -> remove(d, k)})', 'E741:')
+endfunc
+
" vim: shiftwidth=2 sts=2 expandtab
diff --git a/src/nvim/testdir/test_findfile.vim b/src/nvim/testdir/test_findfile.vim
index 5a20475d3d..0f4b30aec2 100644
--- a/src/nvim/testdir/test_findfile.vim
+++ b/src/nvim/testdir/test_findfile.vim
@@ -193,12 +193,14 @@ func Test_find_cmd()
set path=.,./**/*
call CreateFiles()
cd Xdir1
+
" Test for :find
find foo
call assert_equal('foo', expand('%:.'))
2find foo
call assert_equal('Xdir2/foo', expand('%:.'))
call assert_fails('3find foo', 'E347:')
+
" Test for :sfind
enew
sfind barfoo
@@ -207,6 +209,7 @@ func Test_find_cmd()
close
call assert_fails('sfind baz', 'E345:')
call assert_equal(2, winnr('$'))
+
" Test for :tabfind
enew
tabfind foobar
@@ -215,7 +218,8 @@ func Test_find_cmd()
tabclose
call assert_fails('tabfind baz', 'E345:')
call assert_equal(1, tabpagenr('$'))
- " call chdir(save_dir)
+
+ call chdir(save_dir)
exe 'cd ' . save_dir
call CleanFiles()
let &path = save_path
@@ -226,4 +230,26 @@ func Test_find_cmd()
call assert_fails('tabfind', 'E471:')
endfunc
+func Test_find_non_existing_path()
+ new
+ let save_path = &path
+ let save_dir = getcwd()
+ call mkdir('dir1/dir2', 'p')
+ call writefile([], 'dir1/file.txt')
+ call writefile([], 'dir1/dir2/base.txt')
+ call chdir('dir1/dir2')
+ e base.txt
+ set path=../include
+
+ call assert_fails(':find file.txt', 'E345:')
+
+ call chdir(save_dir)
+ bw!
+ call delete('dir1/dir2/base.txt', 'rf')
+ call delete('dir1/dir2', 'rf')
+ call delete('dir1/file.txt', 'rf')
+ call delete('dir1', 'rf')
+ let &path = save_path
+endfunc
+
" vim: shiftwidth=2 sts=2 expandtab
diff --git a/src/nvim/testdir/test_float_func.vim b/src/nvim/testdir/test_float_func.vim
index 1e0c75c49d..902a011a9d 100644
--- a/src/nvim/testdir/test_float_func.vim
+++ b/src/nvim/testdir/test_float_func.vim
@@ -1,8 +1,7 @@
" test float functions
-if !has('float')
- finish
-end
+source check.vim
+CheckFeature float
func Test_abs()
call assert_equal('1.23', string(abs(1.23)))
diff --git a/src/nvim/testdir/test_fnamemodify.vim b/src/nvim/testdir/test_fnamemodify.vim
index 411f7ebbb3..5ae2a5ee17 100644
--- a/src/nvim/testdir/test_fnamemodify.vim
+++ b/src/nvim/testdir/test_fnamemodify.vim
@@ -3,8 +3,10 @@
func Test_fnamemodify()
let save_home = $HOME
let save_shell = &shell
+ let save_shellslash = &shellslash
let $HOME = fnamemodify('.', ':p:h:h')
set shell=sh
+ set shellslash
call assert_equal('/', fnamemodify('.', ':p')[-1:])
call assert_equal('r', fnamemodify('.', ':p:h')[-1:])
@@ -27,6 +29,21 @@ func Test_fnamemodify()
call assert_equal('fb2.tar.gz', fnamemodify('abc.fb2.tar.gz', ':e:e:e'))
call assert_equal('fb2.tar.gz', fnamemodify('abc.fb2.tar.gz', ':e:e:e:e'))
call assert_equal('tar', fnamemodify('abc.fb2.tar.gz', ':e:e:r'))
+ call assert_equal(getcwd(), fnamemodify('', ':p:h'))
+
+ let cwd = getcwd()
+ call chdir($HOME)
+ call assert_equal('foobar', fnamemodify('~/foobar', ':~:.'))
+ call chdir(cwd)
+ call mkdir($HOME . '/XXXXXXXX/a', 'p')
+ call mkdir($HOME . '/XXXXXXXX/b', 'p')
+ call chdir($HOME . '/XXXXXXXX/a/')
+ call assert_equal('foo', fnamemodify($HOME . '/XXXXXXXX/a/foo', ':p:~:.'))
+ call assert_equal('~/XXXXXXXX/b/foo', fnamemodify($HOME . '/XXXXXXXX/b/foo', ':p:~:.'))
+ call mkdir($HOME . '/XXXXXXXX/a.ext', 'p')
+ call assert_equal('~/XXXXXXXX/a.ext/foo', fnamemodify($HOME . '/XXXXXXXX/a.ext/foo', ':p:~:.'))
+ call chdir(cwd)
+ call delete($HOME . '/XXXXXXXX', 'rf')
call assert_equal('''abc def''', fnamemodify('abc def', ':S'))
call assert_equal('''abc" "def''', fnamemodify('abc" "def', ':S'))
@@ -44,6 +61,7 @@ func Test_fnamemodify()
let $HOME = save_home
let &shell = save_shell
+ let &shellslash = save_shellslash
endfunc
func Test_fnamemodify_er()
@@ -73,6 +91,7 @@ func Test_fnamemodify_er()
call assert_equal('b.c', fnamemodify('a.b.c.d.e', ':r:r:e:e:e'))
call assert_equal('b.c', fnamemodify('a.b.c.d.e', ':r:r:e:e:e:e'))
+ call assert_equal('', fnamemodify('', ':p:t'))
call assert_equal('', fnamemodify(v:_null_string, v:_null_string))
endfunc
diff --git a/src/nvim/testdir/test_fold.vim b/src/nvim/testdir/test_fold.vim
index 6da1b3d4a0..327f0f73f2 100644
--- a/src/nvim/testdir/test_fold.vim
+++ b/src/nvim/testdir/test_fold.vim
@@ -217,6 +217,26 @@ func Test_update_folds_expr_read()
set foldmethod& foldexpr&
endfunc
+" Test for what patch 8.1.0535 fixes.
+func Test_foldexpr_no_interrupt_addsub()
+ new
+ func! FoldFunc()
+ call setpos('.', getcurpos())
+ return '='
+ endfunc
+
+ set foldmethod=expr
+ set foldexpr=FoldFunc()
+ call setline(1, '1.2')
+
+ exe "norm! $\<C-A>"
+ call assert_equal('1.3', getline(1))
+
+ bwipe!
+ delfunc FoldFunc
+ set foldmethod& foldexpr&
+endfunc
+
func Check_foldlevels(expected)
call assert_equal(a:expected, map(range(1, line('$')), 'foldlevel(v:val)'))
endfunc
@@ -881,4 +901,92 @@ func Test_fold_relative_move()
set fdm& sw& wrap& tw&
endfunc
+" Make sure a fold containing a nested fold is split correctly when using
+" foldmethod=indent
+func Test_fold_split()
+ new
+ let lines =<< trim END
+ line 1
+ line 2
+ line 3
+ line 4
+ line 5
+ END
+ call setline(1, lines)
+ setlocal sw=2
+ setlocal foldmethod=indent foldenable
+ call assert_equal([0, 1, 1, 2, 2], range(1, 5)->map('foldlevel(v:val)'))
+ call append(2, 'line 2.5')
+ call assert_equal([0, 1, 0, 1, 2, 2], range(1, 6)->map('foldlevel(v:val)'))
+ bw!
+endfunc
+
+" Make sure that when you append under a blank line that is under a fold with
+" the same indent level as your appended line, the fold expands across the
+" blank line
+func Test_indent_append_under_blank_line()
+ new
+ let lines =<< trim END
+ line 1
+ line 2
+ line 3
+ END
+ call setline(1, lines)
+ setlocal sw=2
+ setlocal foldmethod=indent foldenable
+ call assert_equal([0, 1, 1], range(1, 3)->map('foldlevel(v:val)'))
+ call append(3, '')
+ call append(4, ' line 5')
+ call assert_equal([0, 1, 1, 1, 1], range(1, 5)->map('foldlevel(v:val)'))
+ bw!
+endfunc
+
+" Make sure that when you delete 1 line of a fold whose length is 2 lines, the
+" fold can't be closed since its length (1) is now less than foldminlines.
+func Test_indent_one_line_fold_close()
+ let lines =<< trim END
+ line 1
+ line 2
+ line 3
+ END
+
+ new
+ setlocal sw=2 foldmethod=indent
+ call setline(1, lines)
+ " open all folds, delete line, then close all folds
+ normal zR
+ 3delete
+ normal zM
+ call assert_equal(-1, foldclosed(2)) " the fold should not be closed
+
+ " Now do the same, but delete line 2 this time; this covers different code.
+ " (Combining this code with the above code doesn't expose both bugs.)
+ 1,$delete
+ call setline(1, lines)
+ normal zR
+ 2delete
+ normal zM
+ call assert_equal(-1, foldclosed(2))
+ bw!
+endfunc
+
+" Make sure that when appending [an indented line then a blank line] right
+" before a single indented line, the resulting extended fold can be closed
+func Test_indent_append_blank_small_fold_close()
+ new
+ setlocal sw=2 foldmethod=indent
+ " at first, the fold at the second line can't be closed since it's smaller
+ " than foldminlines
+ let lines =<< trim END
+ line 1
+ line 4
+ END
+ call setline(1, lines)
+ call append(1, [' line 2', ''])
+ " close all folds
+ normal zM
+ call assert_notequal(-1, foldclosed(2)) " the fold should be closed now
+ bw!
+endfunc
+
" vim: shiftwidth=2 sts=2 expandtab
diff --git a/src/nvim/testdir/test_functions.vim b/src/nvim/testdir/test_functions.vim
index 0edbeb420a..9b8d740efb 100644
--- a/src/nvim/testdir/test_functions.vim
+++ b/src/nvim/testdir/test_functions.vim
@@ -185,7 +185,9 @@ func Test_str2nr()
call assert_fails('call str2nr([])', 'E730:')
call assert_fails('call str2nr({->2})', 'E729:')
- call assert_fails('call str2nr(1.2)', 'E806:')
+ if has('float')
+ call assert_fails('call str2nr(1.2)', 'E806:')
+ endif
call assert_fails('call str2nr(10, [])', 'E474:')
endfunc
@@ -325,42 +327,18 @@ func Test_simplify()
call assert_equal('./file', simplify('./dir/../file'))
call assert_equal('../dir/file', simplify('dir/../../dir/file'))
call assert_equal('./file', simplify('dir/.././file'))
+ call assert_equal('../dir', simplify('./../dir'))
+ call assert_equal('..', simplify('../testdir/..'))
+ call mkdir('Xdir')
+ call assert_equal('.', simplify('Xdir/../.'))
+ call delete('Xdir', 'd')
call assert_fails('call simplify({->0})', 'E729:')
call assert_fails('call simplify([])', 'E730:')
call assert_fails('call simplify({})', 'E731:')
- call assert_fails('call simplify(1.2)', 'E806:')
-endfunc
-
-func Test_setbufvar_options()
- " This tests that aucmd_prepbuf() and aucmd_restbuf() properly restore the
- " window layout.
- call assert_equal(1, winnr('$'))
- split dummy_preview
- resize 2
- set winfixheight winfixwidth
- let prev_id = win_getid()
-
- wincmd j
- let wh = winheight(0)
- let dummy_buf = bufnr('dummy_buf1', v:true)
- call setbufvar(dummy_buf, '&buftype', 'nofile')
- execute 'belowright vertical split #' . dummy_buf
- call assert_equal(wh, winheight(0))
- let dum1_id = win_getid()
-
- wincmd h
- let wh = winheight(0)
- let dummy_buf = bufnr('dummy_buf2', v:true)
- eval 'nofile'->setbufvar(dummy_buf, '&buftype')
- execute 'belowright vertical split #' . dummy_buf
- call assert_equal(wh, winheight(0))
-
- bwipe!
- call win_gotoid(prev_id)
- bwipe!
- call win_gotoid(dum1_id)
- bwipe!
+ if has('float')
+ call assert_fails('call simplify(1.2)', 'E806:')
+ endif
endfunc
func Test_pathshorten()
@@ -376,6 +354,25 @@ func Test_pathshorten()
call assert_equal('~.f/bar', pathshorten('~.foo/bar'))
call assert_equal('.~f/bar', pathshorten('.~foo/bar'))
call assert_equal('~/f/bar', pathshorten('~/foo/bar'))
+ call assert_fails('call pathshorten([])', 'E730:')
+
+ " test pathshorten with optional variable to set preferred size of shortening
+ call assert_equal('', pathshorten('', 2))
+ call assert_equal('foo', pathshorten('foo', 2))
+ call assert_equal('/foo', pathshorten('/foo', 2))
+ call assert_equal('fo/', pathshorten('foo/', 2))
+ call assert_equal('fo/bar', pathshorten('foo/bar', 2))
+ call assert_equal('fo/ba/foobar', pathshorten('foo/bar/foobar', 2))
+ call assert_equal('/fo/ba/foobar', pathshorten('/foo/bar/foobar', 2))
+ call assert_equal('.fo/bar', pathshorten('.foo/bar', 2))
+ call assert_equal('~fo/bar', pathshorten('~foo/bar', 2))
+ call assert_equal('~.fo/bar', pathshorten('~.foo/bar', 2))
+ call assert_equal('.~fo/bar', pathshorten('.~foo/bar', 2))
+ call assert_equal('~/fo/bar', pathshorten('~/foo/bar', 2))
+ call assert_fails('call pathshorten([],2)', 'E730:')
+ call assert_notequal('~/fo/bar', pathshorten('~/foo/bar', 3))
+ call assert_equal('~/foo/bar', pathshorten('~/foo/bar', 3))
+ call assert_equal('~/f/bar', pathshorten('~/foo/bar', 0))
endfunc
func Test_strpart()
@@ -1192,6 +1189,55 @@ func Test_col()
bw!
endfunc
+" Test for input()
+func Test_input_func()
+ " Test for prompt with multiple lines
+ redir => v
+ call feedkeys(":let c = input(\"A\\nB\\nC\\n? \")\<CR>B\<CR>", 'xt')
+ redir END
+ call assert_equal("B", c)
+ call assert_equal(['A', 'B', 'C'], split(v, "\n"))
+
+ " Test for default value
+ call feedkeys(":let c = input('color? ', 'red')\<CR>\<CR>", 'xt')
+ call assert_equal('red', c)
+
+ " Test for completion at the input prompt
+ func! Tcomplete(arglead, cmdline, pos)
+ return "item1\nitem2\nitem3"
+ endfunc
+ call feedkeys(":let c = input('Q? ', '', 'custom,Tcomplete')\<CR>"
+ \ .. "\<C-A>\<CR>", 'xt')
+ delfunc Tcomplete
+ call assert_equal('item1 item2 item3', c)
+
+ " Test for using special characters as default input
+ call feedkeys(":let c = input('name? ', \"x\\<BS>y\")\<CR>\<CR>", 'xt')
+ call assert_equal('y', c)
+
+ " Test for using text with composing characters as default input
+ call feedkeys(":let c = input('name? ', \"ã̳\")\<CR>\<CR>", 'xt')
+ call assert_equal('ã̳', c)
+
+ " Test for using <CR> as default input
+ call feedkeys(":let c = input('name? ', \"\\<CR>\")\<CR>x\<CR>", 'xt')
+ call assert_equal(' x', c)
+
+ call assert_fails("call input('F:', '', 'invalid')", 'E180:')
+ call assert_fails("call input('F:', '', [])", 'E730:')
+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)
+endfunc
+
+" Test for inputlist()
func Test_inputlist()
call feedkeys(":let c = inputlist(['Select color:', '1. red', '2. green', '3. blue'])\<cr>1\<cr>", 'tx')
call assert_equal(1, c)
@@ -1274,6 +1320,37 @@ func Test_shellescape()
let &shell = save_shell
endfunc
+func Test_setbufvar_options()
+ " This tests that aucmd_prepbuf() and aucmd_restbuf() properly restore the
+ " window layout.
+ call assert_equal(1, winnr('$'))
+ split dummy_preview
+ resize 2
+ set winfixheight winfixwidth
+ let prev_id = win_getid()
+
+ wincmd j
+ let wh = winheight(0)
+ let dummy_buf = bufnr('dummy_buf1', v:true)
+ call setbufvar(dummy_buf, '&buftype', 'nofile')
+ execute 'belowright vertical split #' . dummy_buf
+ call assert_equal(wh, winheight(0))
+ let dum1_id = win_getid()
+
+ wincmd h
+ let wh = winheight(0)
+ let dummy_buf = bufnr('dummy_buf2', v:true)
+ eval 'nofile'->setbufvar(dummy_buf, '&buftype')
+ execute 'belowright vertical split #' . dummy_buf
+ call assert_equal(wh, winheight(0))
+
+ bwipe!
+ call win_gotoid(prev_id)
+ bwipe!
+ call win_gotoid(dum1_id)
+ bwipe!
+endfunc
+
func Test_redo_in_nested_functions()
nnoremap g. :set opfunc=Operator<CR>g@
function Operator( type, ... )
@@ -1331,68 +1408,6 @@ func Test_trim()
call assert_equal("x", trim(chars . "x" . chars))
endfunc
-func EditAnotherFile()
- let word = expand('<cword>')
- edit Xfuncrange2
-endfunc
-
-func Test_func_range_with_edit()
- " Define a function that edits another buffer, then call it with a range that
- " is invalid in that buffer.
- call writefile(['just one line'], 'Xfuncrange2')
- new
- eval 10->range()->setline(1)
- write Xfuncrange1
- call assert_fails('5,8call EditAnotherFile()', 'E16:')
-
- call delete('Xfuncrange1')
- call delete('Xfuncrange2')
- bwipe!
-endfunc
-
-func Test_func_exists_on_reload()
- call writefile(['func ExistingFunction()', 'echo "yes"', 'endfunc'], 'Xfuncexists')
- call assert_equal(0, exists('*ExistingFunction'))
- source Xfuncexists
- call assert_equal(1, '*ExistingFunction'->exists())
- " Redefining a function when reloading a script is OK.
- source Xfuncexists
- call assert_equal(1, exists('*ExistingFunction'))
-
- " But redefining in another script is not OK.
- call writefile(['func ExistingFunction()', 'echo "yes"', 'endfunc'], 'Xfuncexists2')
- call assert_fails('source Xfuncexists2', 'E122:')
-
- delfunc ExistingFunction
- call assert_equal(0, exists('*ExistingFunction'))
- call writefile([
- \ 'func ExistingFunction()', 'echo "yes"', 'endfunc',
- \ 'func ExistingFunction()', 'echo "no"', 'endfunc',
- \ ], 'Xfuncexists')
- call assert_fails('source Xfuncexists', 'E122:')
- call assert_equal(1, exists('*ExistingFunction'))
-
- call delete('Xfuncexists2')
- call delete('Xfuncexists')
- delfunc ExistingFunction
-endfunc
-
-sandbox function Fsandbox()
- normal ix
-endfunc
-
-func Test_func_sandbox()
- sandbox let F = {-> 'hello'}
- call assert_equal('hello', F())
-
- sandbox let F = {-> "normal ix\<Esc>"->execute()}
- call assert_fails('call F()', 'E48:')
- unlet F
-
- call assert_fails('call Fsandbox()', 'E48:')
- delfunc Fsandbox
-endfunc
-
" Test for reg_recording() and reg_executing()
func Test_reg_executing_and_recording()
let s:reg_stat = ''
@@ -1494,6 +1509,10 @@ func Test_getchar()
call assert_equal('', getcharstr(0))
call assert_equal('', getcharstr(1))
+ call feedkeys("\<M-F2>", '')
+ call assert_equal("\<M-F2>", getchar(0))
+ call assert_equal(0, getchar(0))
+
call setline(1, 'xxxx')
" call test_setmouse(1, 3)
" let v:mouse_win = 9
@@ -1519,24 +1538,31 @@ func Test_libcall_libcallnr()
let libc = 'msvcrt.dll'
elseif has('mac')
let libc = 'libSystem.B.dylib'
- elseif system('uname -s') =~ 'SunOS'
- " Set the path to libc.so according to the architecture.
- let test_bits = system('file ' . GetVimProg())
- let test_arch = system('uname -p')
- if test_bits =~ '64-bit' && test_arch =~ 'sparc'
- let libc = '/usr/lib/sparcv9/libc.so'
- elseif test_bits =~ '64-bit' && test_arch =~ 'i386'
- let libc = '/usr/lib/amd64/libc.so'
+ elseif executable('ldd')
+ let libc = matchstr(split(system('ldd ' . GetVimProg())), '/libc\.so\>')
+ endif
+ if get(l:, 'libc', '') ==# ''
+ " On Unix, libc.so can be in various places.
+ if has('linux')
+ " There is not documented but regarding the 1st argument of glibc's
+ " dlopen an empty string and nullptr are equivalent, so using an empty
+ " string for the 1st argument of libcall allows to call functions.
+ let libc = ''
+ elseif has('sun')
+ " Set the path to libc.so according to the architecture.
+ let test_bits = system('file ' . GetVimProg())
+ let test_arch = system('uname -p')
+ if test_bits =~ '64-bit' && test_arch =~ 'sparc'
+ let libc = '/usr/lib/sparcv9/libc.so'
+ elseif test_bits =~ '64-bit' && test_arch =~ 'i386'
+ let libc = '/usr/lib/amd64/libc.so'
+ else
+ let libc = '/usr/lib/libc.so'
+ endif
else
- let libc = '/usr/lib/libc.so'
+ " Unfortunately skip this test until a good way is found.
+ return
endif
- elseif system('uname -s') =~ 'OpenBSD'
- let libc = 'libc.so'
- else
- " On Unix, libc.so can be in various places.
- " Interestingly, using an empty string for the 1st argument of libcall
- " allows to call functions from libc which is not documented.
- let libc = ''
endif
if has('win32')
@@ -1559,54 +1585,99 @@ func Test_libcall_libcallnr()
call assert_fails("call libcallnr('Xdoesnotexist_', 'strlen', 'abcd')", 'E364:')
endfunc
-func Test_bufadd_bufload()
- call assert_equal(0, bufexists('someName'))
- let buf = bufadd('someName')
- call assert_notequal(0, buf)
- call assert_equal(1, bufexists('someName'))
- call assert_equal(0, getbufvar(buf, '&buflisted'))
- call assert_equal(0, bufloaded(buf))
- call bufload(buf)
- call assert_equal(1, bufloaded(buf))
- call assert_equal([''], getbufline(buf, 1, '$'))
+sandbox function Fsandbox()
+ normal ix
+endfunc
- let curbuf = bufnr('')
- eval ['some', 'text']->writefile('XotherName')
- let buf = 'XotherName'->bufadd()
- call assert_notequal(0, buf)
- eval 'XotherName'->bufexists()->assert_equal(1)
- call assert_equal(0, getbufvar(buf, '&buflisted'))
- call assert_equal(0, bufloaded(buf))
- eval buf->bufload()
- call assert_equal(1, bufloaded(buf))
- call assert_equal(['some', 'text'], getbufline(buf, 1, '$'))
- call assert_equal(curbuf, bufnr(''))
+func Test_func_sandbox()
+ sandbox let F = {-> 'hello'}
+ call assert_equal('hello', F())
- let buf1 = bufadd('')
- let buf2 = bufadd('')
- call assert_notequal(0, buf1)
- call assert_notequal(0, buf2)
- call assert_notequal(buf1, buf2)
- call assert_equal(1, bufexists(buf1))
- call assert_equal(1, bufexists(buf2))
- call assert_equal(0, bufloaded(buf1))
- exe 'bwipe ' .. buf1
- call assert_equal(0, bufexists(buf1))
- call assert_equal(1, bufexists(buf2))
- exe 'bwipe ' .. buf2
- call assert_equal(0, bufexists(buf2))
+ sandbox let F = {-> "normal ix\<Esc>"->execute()}
+ call assert_fails('call F()', 'E48:')
+ unlet F
- bwipe someName
- bwipe XotherName
- call assert_equal(0, bufexists('someName'))
- call delete('XotherName')
+ call assert_fails('call Fsandbox()', 'E48:')
+ delfunc Fsandbox
endfunc
-func Test_readdir()
- if isdirectory('Xdir')
- call delete('Xdir', 'rf')
+func EditAnotherFile()
+ let word = expand('<cword>')
+ edit Xfuncrange2
+endfunc
+
+func Test_func_range_with_edit()
+ " Define a function that edits another buffer, then call it with a range that
+ " is invalid in that buffer.
+ call writefile(['just one line'], 'Xfuncrange2')
+ new
+ eval 10->range()->setline(1)
+ write Xfuncrange1
+ call assert_fails('5,8call EditAnotherFile()', 'E16:')
+
+ call delete('Xfuncrange1')
+ call delete('Xfuncrange2')
+ bwipe!
+endfunc
+
+func Test_func_exists_on_reload()
+ call writefile(['func ExistingFunction()', 'echo "yes"', 'endfunc'], 'Xfuncexists')
+ call assert_equal(0, exists('*ExistingFunction'))
+ source Xfuncexists
+ call assert_equal(1, '*ExistingFunction'->exists())
+ " Redefining a function when reloading a script is OK.
+ source Xfuncexists
+ call assert_equal(1, exists('*ExistingFunction'))
+
+ " But redefining in another script is not OK.
+ call writefile(['func ExistingFunction()', 'echo "yes"', 'endfunc'], 'Xfuncexists2')
+ call assert_fails('source Xfuncexists2', 'E122:')
+
+ delfunc ExistingFunction
+ call assert_equal(0, exists('*ExistingFunction'))
+ call writefile([
+ \ 'func ExistingFunction()', 'echo "yes"', 'endfunc',
+ \ 'func ExistingFunction()', 'echo "no"', 'endfunc',
+ \ ], 'Xfuncexists')
+ call assert_fails('source Xfuncexists', 'E122:')
+ call assert_equal(1, exists('*ExistingFunction'))
+
+ call delete('Xfuncexists2')
+ call delete('Xfuncexists')
+ delfunc ExistingFunction
+endfunc
+
+func Test_platform_name()
+ " The system matches at most only one name.
+ let names = ['amiga', 'beos', 'bsd', 'hpux', 'linux', 'mac', 'qnx', 'sun', 'vms', 'win32', 'win32unix']
+ call assert_inrange(0, 1, len(filter(copy(names), 'has(v:val)')))
+
+ " Is Unix?
+ call assert_equal(has('beos'), has('beos') && has('unix'))
+ call assert_equal(has('bsd'), has('bsd') && has('unix'))
+ call assert_equal(has('hpux'), has('hpux') && has('unix'))
+ call assert_equal(has('linux'), has('linux') && has('unix'))
+ call assert_equal(has('mac'), has('mac') && has('unix'))
+ call assert_equal(has('qnx'), has('qnx') && has('unix'))
+ call assert_equal(has('sun'), has('sun') && has('unix'))
+ call assert_equal(has('win32'), has('win32') && !has('unix'))
+ call assert_equal(has('win32unix'), has('win32unix') && has('unix'))
+
+ if has('unix') && executable('uname')
+ let uname = system('uname')
+ call assert_equal(uname =~? 'BeOS', has('beos'))
+ " GNU userland on BSD kernels (e.g., GNU/kFreeBSD) don't have BSD defined
+ call assert_equal(uname =~? '\%(GNU/k\w\+\)\@<!BSD\|DragonFly', has('bsd'))
+ call assert_equal(uname =~? 'HP-UX', has('hpux'))
+ call assert_equal(uname =~? 'Linux', has('linux'))
+ call assert_equal(uname =~? 'Darwin', has('mac'))
+ call assert_equal(uname =~? 'QNX', has('qnx'))
+ call assert_equal(uname =~? 'SunOS', has('sun'))
+ call assert_equal(uname =~? 'CYGWIN\|MSYS', has('win32unix'))
endif
+endfunc
+func Test_readdir()
call mkdir('Xdir')
call writefile([], 'Xdir/foo.txt')
call writefile([], 'Xdir/bar.txt')
@@ -1636,6 +1707,30 @@ func Test_readdir()
call delete('Xdir', 'rf')
endfunc
+func Test_delete_rf()
+ call mkdir('Xdir')
+ call writefile([], 'Xdir/foo.txt')
+ call writefile([], 'Xdir/bar.txt')
+ call mkdir('Xdir/[a-1]') " issue #696
+ call writefile([], 'Xdir/[a-1]/foo.txt')
+ call writefile([], 'Xdir/[a-1]/bar.txt')
+ call assert_true(filereadable('Xdir/foo.txt'))
+ call assert_true('Xdir/[a-1]/foo.txt'->filereadable())
+
+ call assert_equal(0, delete('Xdir', 'rf'))
+ call assert_false(filereadable('Xdir/foo.txt'))
+ call assert_false(filereadable('Xdir/[a-1]/foo.txt'))
+
+ if has('unix')
+ call mkdir('Xdir/Xdir2', 'p')
+ silent !chmod 555 Xdir
+ call assert_equal(-1, delete('Xdir/Xdir2', 'rf'))
+ call assert_equal(-1, delete('Xdir', 'rf'))
+ silent !chmod 755 Xdir
+ call assert_equal(0, delete('Xdir', 'rf'))
+ endif
+endfunc
+
func Test_call()
call assert_equal(3, call('len', [123]))
call assert_equal(3, 'len'->call([123]))
@@ -1658,6 +1753,49 @@ func Test_eventhandler()
call assert_equal(0, eventhandler())
endfunc
+func Test_bufadd_bufload()
+ call assert_equal(0, bufexists('someName'))
+ let buf = bufadd('someName')
+ call assert_notequal(0, buf)
+ call assert_equal(1, bufexists('someName'))
+ call assert_equal(0, getbufvar(buf, '&buflisted'))
+ call assert_equal(0, bufloaded(buf))
+ call bufload(buf)
+ call assert_equal(1, bufloaded(buf))
+ call assert_equal([''], getbufline(buf, 1, '$'))
+
+ let curbuf = bufnr('')
+ eval ['some', 'text']->writefile('XotherName')
+ let buf = 'XotherName'->bufadd()
+ call assert_notequal(0, buf)
+ eval 'XotherName'->bufexists()->assert_equal(1)
+ call assert_equal(0, getbufvar(buf, '&buflisted'))
+ call assert_equal(0, bufloaded(buf))
+ eval buf->bufload()
+ call assert_equal(1, bufloaded(buf))
+ call assert_equal(['some', 'text'], getbufline(buf, 1, '$'))
+ call assert_equal(curbuf, bufnr(''))
+
+ let buf1 = bufadd('')
+ let buf2 = bufadd('')
+ call assert_notequal(0, buf1)
+ call assert_notequal(0, buf2)
+ call assert_notequal(buf1, buf2)
+ call assert_equal(1, bufexists(buf1))
+ call assert_equal(1, bufexists(buf2))
+ call assert_equal(0, bufloaded(buf1))
+ exe 'bwipe ' .. buf1
+ call assert_equal(0, bufexists(buf1))
+ call assert_equal(1, bufexists(buf2))
+ exe 'bwipe ' .. buf2
+ call assert_equal(0, bufexists(buf2))
+
+ bwipe someName
+ bwipe XotherName
+ call assert_equal(0, bufexists('someName'))
+ call delete('XotherName')
+endfunc
+
" Test for the eval() function
func Test_eval()
call assert_fails("call eval('5 a')", 'E488:')
@@ -1671,8 +1809,104 @@ func Test_nr2char()
call assert_equal('a', nr2char(97, 1))
call assert_equal('a', nr2char(97, 0))
- call assert_equal("\x80\xfc\b\xf4\x80\xfeX\x80\xfeX\x80\xfeX", eval('"\<M-' .. nr2char(0x100000) .. '>"'))
- call assert_equal("\x80\xfc\b\xfd\x80\xfeX\x80\xfeX\x80\xfeX\x80\xfeX\x80\xfeX", eval('"\<M-' .. nr2char(0x40000000) .. '>"'))
+ call assert_equal("\x80\xfc\b" .. nr2char(0x100000), eval('"\<M-' .. nr2char(0x100000) .. '>"'))
+ call assert_equal("\x80\xfc\b" .. nr2char(0x40000000), eval('"\<M-' .. nr2char(0x40000000) .. '>"'))
+endfunc
+
+" Test for getcurpos() and setpos()
+func Test_getcurpos_setpos()
+ new
+ call setline(1, ['012345678', '012345678'])
+ normal gg6l
+ let sp = getcurpos()
+ normal 0
+ call setpos('.', sp)
+ normal jyl
+ call assert_equal('6', @")
+ call assert_equal(-1, setpos('.', v:_null_list))
+ call assert_equal(-1, setpos('.', {}))
+
+ let winid = win_getid()
+ normal G$
+ let pos = getcurpos()
+ wincmd w
+ call assert_equal(pos, getcurpos(winid))
+
+ wincmd w
+ close!
+
+ call assert_equal(getcurpos(), getcurpos(0))
+ call assert_equal([0, 0, 0, 0, 0], getcurpos(-1))
+ call assert_equal([0, 0, 0, 0, 0], getcurpos(1999))
+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 assert_equal(#{
+ \ screenrow: 1,
+ \ screencol: 1,
+ \ winid: win_getid(),
+ \ winrow: 1,
+ \ wincol: 1,
+ \ 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 assert_equal(#{
+ \ screenrow: 1,
+ \ screencol: 25,
+ \ winid: win_getid(),
+ \ winrow: 1,
+ \ wincol: 25,
+ \ 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 assert_equal(#{
+ \ screenrow: 1,
+ \ screencol: 50,
+ \ winid: win_getid(),
+ \ winrow: 1,
+ \ wincol: 50,
+ \ line: 1,
+ \ column: 8,
+ \ }, 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 assert_equal(#{
+ \ screenrow: 2,
+ \ screencol: 25,
+ \ winid: win_getid(),
+ \ winrow: 2,
+ \ wincol: 25,
+ \ 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 assert_equal(#{
+ \ screenrow: 2,
+ \ screencol: 50,
+ \ winid: win_getid(),
+ \ winrow: 2,
+ \ wincol: 50,
+ \ line: 1,
+ \ column: 8,
+ \ }, getmousepos())
+ bwipe!
endfunc
func HasDefault(msg = 'msg')
diff --git a/src/nvim/testdir/test_gf.vim b/src/nvim/testdir/test_gf.vim
index 43efd6248e..1569177d66 100644
--- a/src/nvim/testdir/test_gf.vim
+++ b/src/nvim/testdir/test_gf.vim
@@ -19,11 +19,7 @@ func Test_gf_url()
call search("^second")
call search("URL")
call assert_equal("URL://machine.name/tmp/vimtest2b", expand("<cfile>"))
- if has("ebcdic")
- set isf=@,240-249,/,.,-,_,+,,,$,:,~,\
- else
- set isf=@,48-57,/,.,-,_,+,,,$,~,\
- endif
+ set isf=@,48-57,/,.,-,_,+,,,$,~,\
call search("^third")
call search("name")
call assert_equal("URL:\\\\machine.name\\vimtest2c", expand("<cfile>"))
@@ -39,6 +35,13 @@ func Test_gf_url()
call search("URL")
call assert_equal("URL://machine.name:1234?q=vim", expand("<cfile>"))
+ %d
+ call setline(1, "demo://remote_file")
+ wincmd f
+ call assert_equal('demo://remote_file', @%)
+ call assert_equal(2, winnr('$'))
+ close!
+
set isf&vim
enew!
endfunc
@@ -67,20 +70,23 @@ func Test_gF()
call assert_equal('Xfile', bufname('%'))
call assert_equal(2, getcurpos()[1])
+ " jumping to the file/line with CTRL-W_F
+ %bw!
+ edit Xfile1
+ call setline(1, ['one', 'Xfile:4', 'three'])
+ exe "normal 2G\<C-W>F"
+ call assert_equal('Xfile', bufname('%'))
+ call assert_equal(4, getcurpos()[1])
+
set isfname&
call delete('Xfile')
call delete('Xfile2')
- bwipe Xfile
- bwipe Xfile2
+ %bw!
endfunc
" Test for invoking 'gf' on a ${VAR} variable
func Test_gf()
- if has("ebcdic")
- set isfname=@,240-249,/,.,-,_,+,,,$,:,~,{,}
- else
- set isfname=@,48-57,/,.,-,_,+,,,$,:,~,{,}
- endif
+ set isfname=@,48-57,/,.,-,_,+,,,$,:,~,{,}
call writefile(["Test for gf command"], "Xtest1")
if has("unix")
@@ -145,7 +151,7 @@ func Test_gf_visual()
bwipe!
call delete('Xtest_gf_visual')
- set nohidden
+ set hidden&
endfunc
func Test_gf_error()
@@ -155,5 +161,37 @@ func Test_gf_error()
call setline(1, '/doesnotexist')
call assert_fails('normal gf', 'E447:')
call assert_fails('normal gF', 'E447:')
+ call assert_fails('normal [f', 'E447:')
+
+ " gf is not allowed when text is locked
+ au InsertCharPre <buffer> normal! gF<CR>
+ let caught_e565 = 0
+ try
+ call feedkeys("ix\<esc>", 'xt')
+ catch /^Vim\%((\a\+)\)\=:E565/ " catch E565
+ let caught_e565 = 1
+ endtry
+ call assert_equal(1, caught_e565)
+ au! InsertCharPre
+
bwipe!
endfunc
+
+" If a file is not found by 'gf', then 'includeexpr' should be used to locate
+" the file.
+func Test_gf_includeexpr()
+ new
+ let g:Inc_fname = ''
+ func IncFunc()
+ let g:Inc_fname = v:fname
+ return v:fname
+ endfunc
+ setlocal includeexpr=IncFunc()
+ call setline(1, 'somefile.java')
+ call assert_fails('normal gf', 'E447:')
+ call assert_equal('somefile.java', g:Inc_fname)
+ close!
+ delfunc IncFunc
+endfunc
+
+" vim: shiftwidth=2 sts=2 expandtab
diff --git a/src/nvim/testdir/test_global.vim b/src/nvim/testdir/test_global.vim
index 8edc9c2608..feddf85346 100644
--- a/src/nvim/testdir/test_global.vim
+++ b/src/nvim/testdir/test_global.vim
@@ -36,6 +36,48 @@ func Test_global_error()
call assert_fails('g/\(/y', 'E476:')
endfunc
+" Test for printing lines using :g with different search patterns
+func Test_global_print()
+ new
+ call setline(1, ['foo', 'bar', 'foo', 'foo'])
+ let @/ = 'foo'
+ let t = execute("g/")->trim()->split("\n")
+ call assert_equal(['foo', 'foo', 'foo'], t)
+
+ " Test for Vi compatible patterns
+ let @/ = 'bar'
+ let t = execute('g\/')->trim()->split("\n")
+ call assert_equal(['bar'], t)
+
+ normal gg
+ s/foo/foo/
+ let t = execute('g\&')->trim()->split("\n")
+ call assert_equal(['foo', 'foo', 'foo'], t)
+
+ let @/ = 'bar'
+ let t = execute('g?')->trim()->split("\n")
+ call assert_equal(['bar'], t)
+
+ " Test for the 'Pattern found in every line' message
+ let v:statusmsg = ''
+ v/foo\|bar/p
+ call assert_notequal('', v:statusmsg)
+
+ close!
+endfunc
+
+" Test for global command with newline character
+func Test_global_newline()
+ new
+ call setline(1, ['foo'])
+ exe "g/foo/s/f/h/\<NL>s/o$/w/"
+ call assert_equal('how', getline(1))
+ call setline(1, ["foo\<NL>bar"])
+ exe "g/foo/s/foo\\\<NL>bar/xyz/"
+ call assert_equal('xyz', getline(1))
+ close!
+endfunc
+
func Test_wrong_delimiter()
call assert_fails('g x^bxd', 'E146:')
endfunc
diff --git a/src/nvim/testdir/test_gn.vim b/src/nvim/testdir/test_gn.vim
index d09b25b0e7..c4a41a6742 100644
--- a/src/nvim/testdir/test_gn.vim
+++ b/src/nvim/testdir/test_gn.vim
@@ -154,8 +154,24 @@ func Test_gn_command()
norm! gg0f2vf7gNd
call assert_equal(['1678'], getline(1,'$'))
sil! %d _
-
set wrapscan&vim
+
+ " Without 'wrapscan', in visual mode, running gn without a match should fail
+ " but the visual mode should be kept.
+ set nowrapscan
+ call setline('.', 'one two')
+ let @/ = 'one'
+ call assert_beeps('normal 0wvlgn')
+ exe "normal y"
+ call assert_equal('tw', @")
+
+ " with exclusive selection, run gn and gN
+ set selection=exclusive
+ normal 0gny
+ call assert_equal('one', @")
+ normal 0wgNy
+ call assert_equal('one', @")
+ set selection&
endfunc
func Test_gN_repeat()
diff --git a/src/nvim/testdir/test_goto.vim b/src/nvim/testdir/test_goto.vim
index 19513b315a..49095400ef 100644
--- a/src/nvim/testdir/test_goto.vim
+++ b/src/nvim/testdir/test_goto.vim
@@ -334,21 +334,24 @@ endfunc
func Test_motion_if_elif_else_endif()
new
- a
-/* Test pressing % on #if, #else #elsif and #endif,
- * with nested #if
- */
-#if FOO
-/* ... */
-# if BAR
-/* ... */
-# endif
-#elif BAR
-/* ... */
-#else
-/* ... */
-#endif
-.
+ let lines =<< trim END
+ /* Test pressing % on #if, #else #elsif and #endif,
+ * with nested #if
+ */
+ #if FOO
+ /* ... */
+ # if BAR
+ /* ... */
+ # endif
+ #elif BAR
+ /* ... */
+ #else
+ /* ... */
+ #endif
+
+ #define FOO 1
+ END
+ call setline(1, lines)
/#if FOO
norm %
call assert_equal([9, 1], getpos('.')[1:2])
@@ -364,6 +367,30 @@ func Test_motion_if_elif_else_endif()
norm $%
call assert_equal([6, 1], getpos('.')[1:2])
+ " Test for [# and ]# command
+ call cursor(5, 1)
+ normal [#
+ call assert_equal([4, 1], getpos('.')[1:2])
+ call cursor(5, 1)
+ normal ]#
+ call assert_equal([9, 1], getpos('.')[1:2])
+ call cursor(10, 1)
+ normal [#
+ call assert_equal([9, 1], getpos('.')[1:2])
+ call cursor(10, 1)
+ normal ]#
+ call assert_equal([11, 1], getpos('.')[1:2])
+
+ " Finding a match before the first line or after the last line should fail
+ normal gg
+ call assert_beeps('normal [#')
+ normal G
+ call assert_beeps('normal ]#')
+
+ " Finding a match for a macro definition (#define) should fail
+ normal G
+ call assert_beeps('normal %')
+
bw!
endfunc
@@ -393,3 +420,5 @@ func Test_motion_c_comment()
bw!
endfunc
+
+" vim: shiftwidth=2 sts=2 expandtab
diff --git a/src/nvim/testdir/test_help.vim b/src/nvim/testdir/test_help.vim
index 8e59efd22d..dbb36facee 100644
--- a/src/nvim/testdir/test_help.vim
+++ b/src/nvim/testdir/test_help.vim
@@ -1,4 +1,3 @@
-
" Tests for :help
func Test_help_restore_snapshot()
@@ -10,9 +9,45 @@ func Test_help_restore_snapshot()
helpclose
endfunc
+func Test_help_restore_snapshot_split()
+ " Squeeze the unnamed buffer, Xfoo and the help one side-by-side and focus
+ " the first one before calling :help.
+ let bnr = bufnr()
+ botright vsp Xfoo
+ wincmd h
+ help
+ wincmd L
+ let g:did_bufenter = v:false
+ augroup T
+ au!
+ au BufEnter Xfoo let g:did_bufenter = v:true
+ augroup END
+ helpclose
+ augroup! T
+ " We're back to the unnamed buffer.
+ call assert_equal(bnr, bufnr())
+ " No BufEnter was triggered for Xfoo.
+ call assert_equal(v:false, g:did_bufenter)
+
+ close!
+ bwipe!
+endfunc
+
func Test_help_errors()
call assert_fails('help doesnotexist', 'E149:')
call assert_fails('help!', 'E478:')
+ if has('multi_lang')
+ call assert_fails('help help@xy', 'E661:')
+ endif
+
+ let save_hf = &helpfile
+ set helpfile=help_missing
+ help
+ call assert_equal(1, winnr('$'))
+ call assert_notequal('help', &buftype)
+ let &helpfile = save_hf
+
+ call assert_fails('help ' . repeat('a', 1048), 'E149:')
new
set keywordprg=:help
@@ -57,6 +92,11 @@ func Test_help_local_additions()
let &rtp = rtp_save
endfunc
+func Test_help_completion()
+ call feedkeys(":help :undo\<C-A>\<C-B>\"\<CR>", 'tx')
+ call assert_equal('"help :undo :undoj :undol :undojoin :undolist', @:)
+endfunc
+
" Test for the :helptags command
func Test_helptag_cmd()
call mkdir('Xdir/a/doc', 'p')
@@ -101,4 +141,13 @@ func Test_helptag_cmd()
call delete('Xdir', 'rf')
endfunc
+func Test_help_long_argument()
+ try
+ exe 'help \%' .. repeat('0', 1021)
+ catch
+ call assert_match("E149:", v:exception)
+ endtry
+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 a6494c531c..e84726bbfc 100644
--- a/src/nvim/testdir/test_help_tagjump.vim
+++ b/src/nvim/testdir/test_help_tagjump.vim
@@ -23,11 +23,30 @@ func Test_help_tagjump()
call assert_true(getline('.') =~ '\*bar\*')
helpclose
+ help "
+ call assert_equal("help", &filetype)
+ call assert_true(getline('.') =~ '\*quote\*')
+ helpclose
+
+ help *
+ call assert_equal("help", &filetype)
+ call assert_true(getline('.') =~ '\*star\*')
+ helpclose
+
help "*
call assert_equal("help", &filetype)
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 ??
+ call assert_equal("help", &filetype)
+ call assert_true(getline('.') =~ '\*g??\*')
+ helpclose
+
help ch?ckhealth
call assert_equal("help", &filetype)
call assert_true(getline('.') =~ '\*:checkhealth\*')
@@ -86,11 +105,45 @@ func Test_help_tagjump()
call assert_true(getline('.') =~ '\*i_^_CTRL-D\*')
helpclose
+ help i^x^y
+ call assert_equal("help", &filetype)
+ call assert_true(getline('.') =~ '\*i_CTRL-X_CTRL-Y\*')
+ helpclose
+
+ exe "help i\<C-\>\<C-G>"
+ call assert_equal("help", &filetype)
+ call assert_true(getline('.') =~ '\*i_CTRL-\\_CTRL-G\*')
+ helpclose
+
exec "help \<C-V>"
call assert_equal("help", &filetype)
call assert_true(getline('.') =~ '\*CTRL-V\*')
helpclose
+ help /\|
+ call assert_equal("help", &filetype)
+ call assert_true(getline('.') =~ '\*/\\bar\*')
+ helpclose
+
+ help \_$
+ call assert_equal("help", &filetype)
+ call assert_true(getline('.') =~ '\*/\\_$\*')
+ helpclose
+
+ help CTRL-\_CTRL-N
+ call assert_equal("help", &filetype)
+ call assert_true(getline('.') =~ '\*CTRL-\\_CTRL-N\*')
+ helpclose
+
+ help `:pwd`,
+ call assert_equal("help", &filetype)
+ call assert_true(getline('.') =~ '\*:pwd\*')
+ helpclose
+
+ help `:ls`.
+ call assert_equal("help", &filetype)
+ call assert_true(getline('.') =~ '\*:ls\*')
+ helpclose
exec "help! ('textwidth'"
call assert_equal("help", &filetype)
@@ -122,6 +175,15 @@ func Test_help_tagjump()
call assert_true(getline('.') =~ '\*{address}\*')
helpclose
+ " Use special patterns in the help tag
+ for h in ['/\w', '/\%^', '/\%(', '/\zs', '/\@<=', '/\_$', '[++opt]', '/\{']
+ exec "help! " . h
+ call assert_equal("help", &filetype)
+ let pat = '\*' . escape(h, '\$[') . '\*'
+ call assert_true(getline('.') =~ pat, pat)
+ helpclose
+ endfor
+
exusage
call assert_equal("help", &filetype)
call assert_true(getline('.') =~ '\*:index\*')
diff --git a/src/nvim/testdir/test_highlight.vim b/src/nvim/testdir/test_highlight.vim
index 899eb530ec..efdf44a0d6 100644
--- a/src/nvim/testdir/test_highlight.vim
+++ b/src/nvim/testdir/test_highlight.vim
@@ -146,7 +146,7 @@ func Test_highlight_eol_with_cursorline_vertsplit()
" 'abcd |abcd '
" ^^^^ ^^^^^^^^^ no highlight
" ^ 'Search' highlight
- " ^ 'VertSplit' highlight
+ " ^ 'WinSeparator' highlight
let attrs0 = ScreenAttrs(1, 15)[0]
call assert_equal(repeat([attrs0[0]], 4), attrs0[0:3])
call assert_equal(repeat([attrs0[0]], 9), attrs0[6:14])
@@ -160,7 +160,7 @@ func Test_highlight_eol_with_cursorline_vertsplit()
" 'abcd |abcd '
" ^^^^ underline
" ^ 'Search' highlight with underline
- " ^ 'VertSplit' highlight
+ " ^ 'WinSeparator' highlight
" ^^^^^^^^^ no highlight
" underline
@@ -597,6 +597,86 @@ func Test_cursorline_with_visualmode()
call delete('Xtest_cursorline_with_visualmode')
endfunc
+func Test_cursorcolumn_insert_on_tab()
+ CheckScreendump
+
+ let lines =<< trim END
+ call setline(1, ['123456789', "a\tb"])
+ set cursorcolumn
+ call cursor(2, 2)
+ END
+ call writefile(lines, 'Xcuc_insert_on_tab')
+
+ let buf = RunVimInTerminal('-S Xcuc_insert_on_tab', #{rows: 8})
+ call TermWait(buf)
+ call VerifyScreenDump(buf, 'Test_cursorcolumn_insert_on_tab_1', {})
+
+ call term_sendkeys(buf, 'i')
+ call TermWait(buf)
+ call VerifyScreenDump(buf, 'Test_cursorcolumn_insert_on_tab_2', {})
+
+ call term_sendkeys(buf, "\<C-O>")
+ call TermWait(buf)
+ call VerifyScreenDump(buf, 'Test_cursorcolumn_insert_on_tab_3', {})
+
+ call term_sendkeys(buf, 'i')
+ call TermWait(buf)
+ call VerifyScreenDump(buf, 'Test_cursorcolumn_insert_on_tab_2', {})
+
+ call StopVimInTerminal(buf)
+ call delete('Xcuc_insert_on_tab')
+endfunc
+
+func Test_cursorcolumn_callback()
+ CheckScreendump
+ CheckFeature timers
+
+ let lines =<< trim END
+ call setline(1, ['aaaaa', 'bbbbb', 'ccccc', 'ddddd'])
+ set cursorcolumn
+ call cursor(4, 5)
+
+ func Func(timer)
+ call cursor(1, 1)
+ endfunc
+
+ call timer_start(300, 'Func')
+ END
+ call writefile(lines, 'Xcuc_timer')
+
+ let buf = RunVimInTerminal('-S Xcuc_timer', #{rows: 8})
+ call TermWait(buf, 310)
+ call VerifyScreenDump(buf, 'Test_cursorcolumn_callback_1', {})
+
+ call StopVimInTerminal(buf)
+ call delete('Xcuc_timer')
+endfunc
+
+func Test_colorcolumn()
+ CheckScreendump
+
+ " check that setting 'colorcolumn' when entering a buffer works
+ let lines =<< trim END
+ split
+ edit X
+ call setline(1, ["1111111111","22222222222","3333333333"])
+ set nomodified
+ set colorcolumn=3,9
+ set number cursorline cursorlineopt=number
+ wincmd w
+ buf X
+ END
+ call writefile(lines, 'Xtest_colorcolumn')
+ let buf = RunVimInTerminal('-S Xtest_colorcolumn', {'rows': 10})
+ call term_sendkeys(buf, ":\<CR>")
+ call term_wait(buf)
+ call VerifyScreenDump(buf, 'Test_colorcolumn_1', {})
+
+ " clean up
+ call StopVimInTerminal(buf)
+ call delete('Xtest_colorcolumn')
+endfunc
+
func Test_colorcolumn_bri()
CheckScreendump
diff --git a/src/nvim/testdir/test_history.vim b/src/nvim/testdir/test_history.vim
index 2f0dc2dae1..feb521e232 100644
--- a/src/nvim/testdir/test_history.vim
+++ b/src/nvim/testdir/test_history.vim
@@ -1,8 +1,7 @@
" Tests for the history functions
-if !has('cmdline_hist')
- finish
-endif
+source check.vim
+CheckFeature cmdline_hist
set history=7
@@ -71,6 +70,14 @@ function History_Tests(hist)
call assert_equal('', histget(a:hist, i))
call assert_equal('', histget(a:hist, i - 7 - 1))
endfor
+
+ " Test for freeing an entry at the beginning of the history list
+ for i in range(1, 4)
+ call histadd(a:hist, 'text_' . i)
+ endfor
+ call histdel(a:hist, 1)
+ call assert_equal('', histget(a:hist, 1))
+ call assert_equal('text_4', histget(a:hist, 4))
endfunction
function Test_History()
@@ -86,6 +93,8 @@ function Test_History()
call assert_fails('call histget([])', 'E730:')
call assert_equal(-1, histnr('abc'))
call assert_fails('call histnr([])', 'E730:')
+ call assert_fails('history xyz', 'E488:')
+ call assert_fails('history ,abc', 'E488:')
endfunction
function Test_Search_history_window()
@@ -105,7 +114,122 @@ function Test_Search_history_window()
bwipe!
endfunc
+" Test for :history command option completion
function Test_history_completion()
call feedkeys(":history \<C-A>\<C-B>\"\<CR>", 'tx')
call assert_equal('"history / : = > ? @ all cmd debug expr input search', @:)
endfunc
+
+" Test for increasing the 'history' option value
+func Test_history_size()
+ let save_histsz = &history
+ set history=10
+ call histadd(':', 'ls')
+ call histdel(':')
+ for i in range(1, 5)
+ call histadd(':', 'cmd' .. i)
+ endfor
+ call assert_equal(5, histnr(':'))
+ call assert_equal('cmd5', histget(':', -1))
+
+ set history=15
+ for i in range(6, 10)
+ call histadd(':', 'cmd' .. i)
+ endfor
+ call assert_equal(10, histnr(':'))
+ call assert_equal('cmd1', histget(':', 1))
+ call assert_equal('cmd10', histget(':', -1))
+
+ set history=5
+ call histadd(':', 'abc')
+ call assert_equal('', histget(':', 6))
+ call assert_equal('', histget(':', 12))
+ call assert_equal('cmd7', histget(':', 7))
+ call assert_equal('abc', histget(':', -1))
+
+ " This test works only when the language is English
+ if v:lang == "C" || v:lang =~ '^[Ee]n'
+ set history=0
+ redir => v
+ call feedkeys(":history\<CR>", 'xt')
+ redir END
+ call assert_equal(["'history' option is zero"], split(v, "\n"))
+ endif
+
+ let &history=save_histsz
+endfunc
+
+" Test for recalling old search patterns in /
+func Test_history_search()
+ call histdel('/')
+ let g:pat = []
+ func SavePat()
+ call add(g:pat, getcmdline())
+ return ''
+ endfunc
+ cnoremap <F2> <C-\>eSavePat()<CR>
+ call histadd('/', 'pat1')
+ call histadd('/', 'pat2')
+ let @/ = ''
+ call feedkeys("/\<Up>\<F2>\<Up>\<F2>\<Down>\<Down>\<F2>\<Esc>", 'xt')
+ call assert_equal(['pat2', 'pat1', ''], g:pat)
+ cunmap <F2>
+ delfunc SavePat
+
+ " Search for a pattern that is not present in the history
+ call assert_beeps('call feedkeys("/a1b2\<Up>\<CR>", "xt")')
+
+ " Recall patterns with 'history' set to 0
+ set history=0
+ let @/ = 'abc'
+ let cmd = 'call feedkeys("/\<Up>\<Down>\<S-Up>\<S-Down>\<CR>", "xt")'
+ call assert_fails(cmd, 'E486:')
+ set history&
+
+ " Recall patterns till the end of history
+ set history=4
+ call histadd('/', 'pat')
+ call histdel('/')
+ call histadd('/', 'pat1')
+ call histadd('/', 'pat2')
+ call assert_beeps('call feedkeys("/\<Up>\<Up>\<Up>\<C-U>\<cr>", "xt")')
+ call assert_beeps('call feedkeys("/\<Down><cr>", "xt")')
+
+ " Test for wrapping around the history list
+ for i in range(3, 7)
+ call histadd('/', 'pat' .. i)
+ endfor
+ let upcmd = "\<up>\<up>\<up>\<up>\<up>"
+ let downcmd = "\<down>\<down>\<down>\<down>\<down>"
+ try
+ call feedkeys("/" .. upcmd .. "\<cr>", 'xt')
+ catch /E486:/
+ endtry
+ call assert_equal('pat4', @/)
+ try
+ call feedkeys("/" .. upcmd .. downcmd .. "\<cr>", 'xt')
+ catch /E486:/
+ endtry
+ call assert_equal('pat4', @/)
+
+ " Test for changing the search command separator in the history
+ call assert_fails('call feedkeys("/def/\<cr>", "xt")', 'E486:')
+ call assert_fails('call feedkeys("?\<up>\<cr>", "xt")', 'E486:')
+ call assert_equal('def?', histget('/', -1))
+
+ call assert_fails('call feedkeys("/ghi?\<cr>", "xt")', 'E486:')
+ call assert_fails('call feedkeys("?\<up>\<cr>", "xt")', 'E486:')
+ call assert_equal('ghi\?', histget('/', -1))
+
+ set history&
+endfunc
+
+" Test for making sure the key value is not stored in history
+func Test_history_crypt_key()
+ CheckFeature cryptv
+ call feedkeys(":set bs=2 key=abc ts=8\<CR>", 'xt')
+ call assert_equal('set bs=2 key= ts=8', histget(':'))
+ set key& bs& ts&
+endfunc
+
+" vim: shiftwidth=2 sts=2 expandtab
diff --git a/src/nvim/testdir/test_increment.vim b/src/nvim/testdir/test_increment.vim
index 6d08cd40a8..2559654f25 100644
--- a/src/nvim/testdir/test_increment.vim
+++ b/src/nvim/testdir/test_increment.vim
@@ -285,7 +285,7 @@ endfunc
" 1
" 1
" 1
-" Expexted:
+" Expected:
" 1) g Ctrl-A on block selected indented lines
" 2
" 1
@@ -776,6 +776,14 @@ func Test_increment_empty_line()
call setline(1, ['0', '0', '0', '0', '0', '0', ''])
exe "normal Gvgg\<C-A>"
call assert_equal(['1', '1', '1', '1', '1', '1', ''], getline(1, 7))
+
+ " Ctrl-A/Ctrl-X should do nothing in operator pending mode
+ %d
+ call setline(1, 'one two')
+ exe "normal! c\<C-A>l"
+ exe "normal! c\<C-X>l"
+ call assert_equal('one two', getline(1))
+
bwipe!
endfunc
diff --git a/src/nvim/testdir/test_indent.vim b/src/nvim/testdir/test_indent.vim
new file mode 100644
index 0000000000..3b5b643177
--- /dev/null
+++ b/src/nvim/testdir/test_indent.vim
@@ -0,0 +1,279 @@
+" Test for various indent options
+
+func Test_preserveindent()
+ new
+ " Test for autoindent copying indent from the previous line
+ setlocal autoindent
+ call setline(1, [repeat(' ', 16) .. 'line1'])
+ call feedkeys("A\nline2", 'xt')
+ call assert_equal("\t\tline2", getline(2))
+ setlocal autoindent&
+
+ " Test for using CTRL-T with and without 'preserveindent'
+ set shiftwidth=4
+ call cursor(1, 1)
+ call setline(1, " \t ")
+ call feedkeys("Al\<C-T>", 'xt')
+ call assert_equal("\t\tl", getline(1))
+ set preserveindent
+ call setline(1, " \t ")
+ call feedkeys("Al\<C-T>", 'xt')
+ call assert_equal(" \t \tl", getline(1))
+ set pi& sw&
+
+ " Test for using CTRL-T with 'expandtab' and 'preserveindent'
+ call cursor(1, 1)
+ call setline(1, "\t \t")
+ set shiftwidth=4 expandtab preserveindent
+ call feedkeys("Al\<C-T>", 'xt')
+ call assert_equal("\t \t l", getline(1))
+ set sw& et& pi&
+
+ close!
+endfunc
+
+" Test for indent()
+func Test_indent_func()
+ call assert_equal(-1, indent(-1))
+ new
+ call setline(1, "\tabc")
+ call assert_equal(8, indent(1))
+ call setline(1, " abc")
+ call assert_equal(4, indent(1))
+ call setline(1, " \t abc")
+ call assert_equal(12, indent(1))
+ close!
+endfunc
+
+" Test for reindenting a line using the '=' operator
+func Test_reindent()
+ new
+ call setline(1, 'abc')
+ set nomodifiable
+ call assert_fails('normal ==', 'E21:')
+ set modifiable
+
+ call setline(1, ['foo', 'bar'])
+ call feedkeys('ggVG=', 'xt')
+ call assert_equal(['foo', 'bar'], getline(1, 2))
+ close!
+endfunc
+
+" Test indent operator creating one undo entry
+func Test_indent_operator_undo()
+ enew
+ call setline(1, range(12)->map('"\t" .. v:val'))
+ func FoldExpr()
+ let g:foldcount += 1
+ return '='
+ endfunc
+ set foldmethod=expr foldexpr=FoldExpr()
+ let g:foldcount = 0
+ redraw
+ call assert_equal(12, g:foldcount)
+ normal gg=G
+ call assert_equal(24, g:foldcount)
+ undo
+ call assert_equal(38, g:foldcount)
+
+ bwipe!
+ set foldmethod& foldexpr=
+ delfunc FoldExpr
+ unlet g:foldcount
+endfunc
+
+" Test for shifting a line with a preprocessor directive ('#')
+func Test_preproc_indent()
+ new
+ set sw=4
+ call setline(1, '#define FOO 1')
+ normal >>
+ call assert_equal(' #define FOO 1', getline(1))
+
+ " with 'smartindent'
+ call setline(1, '#define FOO 1')
+ set smartindent
+ normal >>
+ call assert_equal('#define FOO 1', getline(1))
+ set smartindent&
+
+ " with 'cindent'
+ set cindent
+ normal >>
+ call assert_equal('#define FOO 1', getline(1))
+ set cindent&
+
+ close!
+endfunc
+
+" Test for 'copyindent'
+func Test_copyindent()
+ new
+ set shiftwidth=4 autoindent expandtab copyindent
+ call setline(1, " \t abc")
+ call feedkeys("ol", 'xt')
+ call assert_equal(" \t l", getline(2))
+ set noexpandtab
+ call setline(1, " \t abc")
+ call feedkeys("ol", 'xt')
+ call assert_equal(" \t l", getline(2))
+ set sw& ai& et& ci&
+ close!
+endfunc
+
+" Test for changing multiple lines with lisp indent
+func Test_lisp_indent_change_multiline()
+ new
+ setlocal lisp autoindent
+ call setline(1, ['(if a', ' (if b', ' (return 5)))'])
+ normal! jc2j(return 4))
+ call assert_equal(' (return 4))', getline(2))
+ close!
+endfunc
+
+func Test_lisp_indent()
+ new
+ setlocal lisp autoindent
+ call setline(1, ['(if a', ' ;; comment', ' \ abc', '', ' " str1\', ' " st\b', ' (return 5)'])
+ normal! jo;; comment
+ normal! jo\ abc
+ normal! jo;; ret
+ normal! jostr1"
+ normal! jostr2"
+ call assert_equal([' ;; comment', ' ;; comment', ' \ abc', ' \ abc', '', ' ;; ret', ' " str1\', ' str1"', ' " st\b', ' str2"'], getline(2, 11))
+ close!
+endfunc
+
+func Test_lisp_indent_quoted()
+ " This was going past the end of the line
+ new
+ setlocal lisp autoindent
+ call setline(1, ['"[', '='])
+ normal Gvk=
+
+ bwipe!
+endfunc
+
+" Test for setting the 'indentexpr' from a modeline
+func Test_modeline_indent_expr()
+ let modeline = &modeline
+ set modeline
+ func GetIndent()
+ return line('.') * 2
+ endfunc
+ call writefile(['# vim: indentexpr=GetIndent()'], 'Xfile.txt')
+ set modelineexpr
+ new Xfile.txt
+ call assert_equal('GetIndent()', &indentexpr)
+ exe "normal Oa\nb\n"
+ call assert_equal([' a', ' b'], getline(1, 2))
+
+ set modelineexpr&
+ delfunc GetIndent
+ let &modeline = modeline
+ close!
+ call delete('Xfile.txt')
+endfunc
+
+func Test_indent_func_with_gq()
+
+ function GetTeXIndent()
+ " Sample indent expression for TeX files
+ let lnum = prevnonblank(v:lnum - 1)
+ " At the start of the file use zero indent.
+ if lnum == 0
+ return 0
+ endif
+ let line = getline(lnum)
+ let ind = indent(lnum)
+ " Add a 'shiftwidth' after beginning of environments.
+ if line =~ '\\begin{center}'
+ let ind = ind + shiftwidth()
+ endif
+ return ind
+ endfunction
+
+ new
+ setl et sw=2 sts=2 ts=2 tw=50 indentexpr=GetTeXIndent()
+ put =[ '\documentclass{article}', '', '\begin{document}', '',
+ \ 'Lorem ipsum dolor sit amet, consectetur adipiscing elit. Fusce ut enim non',
+ \ 'libero efficitur aliquet. Maecenas metus justo, facilisis convallis blandit',
+ \ 'non, semper eu urna. Suspendisse diam diam, iaculis faucibus lorem eu,',
+ \ 'fringilla condimentum lectus. Quisque euismod diam at convallis vulputate.',
+ \ 'Pellentesque laoreet tortor sit amet mauris euismod ornare. Sed varius',
+ \ 'bibendum orci vel vehicula. Pellentesque tempor, ipsum et auctor accumsan,',
+ \ 'metus lectus ultrices odio, sed elementum mi ante at arcu.', '', '\begin{center}', '',
+ \ 'Proin nec risus consequat nunc dapibus consectetur. Mauris lacinia est a augue',
+ \ 'tristique accumsan. Morbi pretium, felis molestie eleifend condimentum, arcu',
+ \ 'ipsum congue nisl, quis euismod purus libero in ante.', '',
+ \ 'Donec id semper purus.',
+ \ 'Suspendisse eget aliquam nunc. Maecenas fringilla mauris vitae maximus',
+ \ 'condimentum. Cras a quam in mi dictum eleifend at a lorem. Sed convallis',
+ \ 'ante a commodo facilisis. Nam suscipit vulputate odio, vel dapibus nisl',
+ \ 'dignissim facilisis. Vestibulum ante ipsum primis in faucibus orci luctus et',
+ \ 'ultrices posuere cubilia curae;', '', '']
+ 1d_
+ call cursor(5, 1)
+ ka
+ call cursor(14, 1)
+ kb
+ norm! 'agqap
+ norm! 'bgqG
+ let expected = [ '\documentclass{article}', '', '\begin{document}', '',
+ \ 'Lorem ipsum dolor sit amet, consectetur adipiscing',
+ \ 'elit. Fusce ut enim non libero efficitur aliquet.',
+ \ 'Maecenas metus justo, facilisis convallis blandit',
+ \ 'non, semper eu urna. Suspendisse diam diam,',
+ \ 'iaculis faucibus lorem eu, fringilla condimentum',
+ \ 'lectus. Quisque euismod diam at convallis',
+ \ 'vulputate. Pellentesque laoreet tortor sit amet',
+ \ 'mauris euismod ornare. Sed varius bibendum orci',
+ \ 'vel vehicula. Pellentesque tempor, ipsum et auctor',
+ \ 'accumsan, metus lectus ultrices odio, sed',
+ \ 'elementum mi ante at arcu.', '', '\begin{center}', '',
+ \ ' Proin nec risus consequat nunc dapibus',
+ \ ' consectetur. Mauris lacinia est a augue',
+ \ ' tristique accumsan. Morbi pretium, felis',
+ \ ' molestie eleifend condimentum, arcu ipsum congue',
+ \ ' nisl, quis euismod purus libero in ante.',
+ \ '',
+ \ ' Donec id semper purus. Suspendisse eget aliquam',
+ \ ' nunc. Maecenas fringilla mauris vitae maximus',
+ \ ' condimentum. Cras a quam in mi dictum eleifend',
+ \ ' at a lorem. Sed convallis ante a commodo',
+ \ ' facilisis. Nam suscipit vulputate odio, vel',
+ \ ' dapibus nisl dignissim facilisis. Vestibulum',
+ \ ' ante ipsum primis in faucibus orci luctus et',
+ \ ' ultrices posuere cubilia curae;', '', '']
+ call assert_equal(expected, getline(1, '$'))
+
+ bwipe!
+ delmark ab
+ delfunction GetTeXIndent
+endfu
+
+func Test_formatting_keeps_first_line_indent()
+ let lines =<< trim END
+ foo()
+ {
+ int x; // manually positioned
+ // more text that will be formatted
+ // but not reindented
+ END
+ new
+ call setline(1, lines)
+ setlocal sw=4 cindent tw=45 et
+ normal! 4Ggqj
+ let expected =<< trim END
+ foo()
+ {
+ int x; // manually positioned
+ // more text that will be
+ // formatted but not
+ // reindented
+ END
+ call assert_equal(expected, getline(1, '$'))
+ bwipe!
+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 ce75799551..93ab17955d 100644
--- a/src/nvim/testdir/test_ins_complete.vim
+++ b/src/nvim/testdir/test_ins_complete.vim
@@ -95,7 +95,7 @@ func Test_ins_complete()
call delete('Xtest11.one')
call delete('Xtest11.two')
call delete('Xtestdata')
- set cpt& cot& def& tags& tagbsearch& nohidden
+ set cpt& cot& def& tags& tagbsearch& hidden&
cd ..
call delete('Xdir', 'rf')
endfunc
@@ -109,7 +109,7 @@ func s:CompleteDone_CompleteFuncNone( findstart, base )
return v:none
endfunc
-function! s:CompleteDone_CompleteFuncDict( findstart, base )
+func s:CompleteDone_CompleteFuncDict( findstart, base )
if a:findstart
return 0
endif
@@ -126,7 +126,7 @@ function! s:CompleteDone_CompleteFuncDict( findstart, base )
\ }
\ ]
\ }
-endfunction
+endfunc
func s:CompleteDone_CheckCompletedItemNone()
let s:called_completedone = 1
@@ -287,6 +287,30 @@ func Test_omni_dash()
set omnifunc=
endfunc
+func Test_omni_throw()
+ let g:CallCount = 0
+ func Omni(findstart, base)
+ let g:CallCount += 1
+ if a:findstart
+ throw "he he he"
+ endif
+ endfunc
+ set omnifunc=Omni
+ new
+ try
+ exe "normal ifoo\<C-x>\<C-o>"
+ call assert_false(v:true, 'command should have failed')
+ catch
+ call assert_exception('he he he')
+ call assert_equal(1, g:CallCount)
+ endtry
+
+ bwipe!
+ delfunc Omni
+ unlet g:CallCount
+ set omnifunc=
+endfunc
+
func Test_completefunc_args()
let s:args = []
func! CompleteFunc(findstart, base)
@@ -341,6 +365,14 @@ func Test_compl_feedkeys()
set completeopt&
endfunc
+func s:ComplInCmdwin_GlobalCompletion(a, l, p)
+ return 'global'
+endfunc
+
+func s:ComplInCmdwin_LocalCompletion(a, l, p)
+ return 'local'
+endfunc
+
func Test_compl_in_cmdwin()
set wildmenu wildchar=<Tab>
com! -nargs=1 -complete=command GetInput let input = <q-args>
@@ -376,6 +408,47 @@ func Test_compl_in_cmdwin()
call feedkeys("q::GetInput b:test_\<Tab>\<CR>:q\<CR>", 'tx!')
call assert_equal('b:test_', input)
+
+ " Argument completion of buffer-local command
+ func s:ComplInCmdwin_GlobalCompletionList(a, l, p)
+ return ['global']
+ endfunc
+
+ func s:ComplInCmdwin_LocalCompletionList(a, l, p)
+ return ['local']
+ endfunc
+
+ func s:ComplInCmdwin_CheckCompletion(arg)
+ call assert_equal('local', a:arg)
+ endfunc
+
+ com! -nargs=1 -complete=custom,<SID>ComplInCmdwin_GlobalCompletion
+ \ TestCommand call s:ComplInCmdwin_CheckCompletion(<q-args>)
+ com! -buffer -nargs=1 -complete=custom,<SID>ComplInCmdwin_LocalCompletion
+ \ TestCommand call s:ComplInCmdwin_CheckCompletion(<q-args>)
+ call feedkeys("q:iTestCommand \<Tab>\<CR>", 'tx!')
+
+ com! -nargs=1 -complete=customlist,<SID>ComplInCmdwin_GlobalCompletionList
+ \ TestCommand call s:ComplInCmdwin_CheckCompletion(<q-args>)
+ com! -buffer -nargs=1 -complete=customlist,<SID>ComplInCmdwin_LocalCompletionList
+ \ TestCommand call s:ComplInCmdwin_CheckCompletion(<q-args>)
+
+ call feedkeys("q:iTestCommand \<Tab>\<CR>", 'tx!')
+
+ func! s:ComplInCmdwin_CheckCompletion(arg)
+ call assert_equal('global', a:arg)
+ endfunc
+ new
+ call feedkeys("q:iTestCommand \<Tab>\<CR>", 'tx!')
+ quit
+
+ delfunc s:ComplInCmdwin_GlobalCompletion
+ delfunc s:ComplInCmdwin_LocalCompletion
+ delfunc s:ComplInCmdwin_GlobalCompletionList
+ delfunc s:ComplInCmdwin_LocalCompletionList
+ delfunc s:ComplInCmdwin_CheckCompletion
+
+ delcom -buffer TestCommand
delcom TestCommand
delcom GetInput
unlet w:test_winvar
@@ -445,6 +518,37 @@ func Test_issue_7021()
set completeslash=
endfunc
+func Test_pum_stopped_by_timer()
+ CheckScreendump
+
+ let lines =<< trim END
+ call setline(1, ['hello', 'hullo', 'heeee', ''])
+ func StartCompl()
+ call timer_start(100, { -> execute('stopinsert') })
+ call feedkeys("Gah\<C-N>")
+ endfunc
+ END
+
+ call writefile(lines, 'Xpumscript')
+ let buf = RunVimInTerminal('-S Xpumscript', #{rows: 12})
+ call term_sendkeys(buf, ":call StartCompl()\<CR>")
+ call TermWait(buf, 200)
+ call term_sendkeys(buf, "k")
+ call VerifyScreenDump(buf, 'Test_pum_stopped_by_timer', {})
+
+ call StopVimInTerminal(buf)
+ call delete('Xpumscript')
+endfunc
+
+func Test_complete_stopinsert_startinsert()
+ nnoremap <F2> <Cmd>startinsert<CR>
+ inoremap <F2> <Cmd>stopinsert<CR>
+ " This just checks if this causes an error
+ call feedkeys("i\<C-X>\<C-N>\<F2>\<F2>", 'x')
+ nunmap <F2>
+ iunmap <F2>
+endfunc
+
func Test_pum_with_folds_two_tabs()
CheckScreendump
@@ -497,6 +601,107 @@ func Test_ins_compl_tag_sft()
%bwipe!
endfunc
+" Test for 'completefunc' deleting text
+func Test_completefunc_error()
+ new
+ " delete text when called for the first time
+ func CompleteFunc(findstart, base)
+ if a:findstart == 1
+ normal dd
+ return col('.') - 1
+ endif
+ return ['a', 'b']
+ endfunc
+ set completefunc=CompleteFunc
+ call setline(1, ['', 'abcd', ''])
+ call assert_fails('exe "normal 2G$a\<C-X>\<C-U>"', 'E565:')
+
+ " delete text when called for the second time
+ func CompleteFunc2(findstart, base)
+ if a:findstart == 1
+ return col('.') - 1
+ endif
+ normal dd
+ return ['a', 'b']
+ endfunc
+ set completefunc=CompleteFunc2
+ call setline(1, ['', 'abcd', ''])
+ call assert_fails('exe "normal 2G$a\<C-X>\<C-U>"', 'E565:')
+
+ " Jump to a different window from the complete function
+ func CompleteFunc3(findstart, base)
+ if a:findstart == 1
+ return col('.') - 1
+ endif
+ wincmd p
+ return ['a', 'b']
+ endfunc
+ set completefunc=CompleteFunc3
+ new
+ call assert_fails('exe "normal a\<C-X>\<C-U>"', 'E565:')
+ close!
+
+ set completefunc&
+ delfunc CompleteFunc
+ delfunc CompleteFunc2
+ delfunc CompleteFunc3
+ close!
+endfunc
+
+" Test for returning non-string values from 'completefunc'
+func Test_completefunc_invalid_data()
+ new
+ func! CompleteFunc(findstart, base)
+ if a:findstart == 1
+ return col('.') - 1
+ endif
+ return [{}, '', 'moon']
+ endfunc
+ set completefunc=CompleteFunc
+ exe "normal i\<C-X>\<C-U>"
+ call assert_equal('moon', getline(1))
+ set completefunc&
+ close!
+endfunc
+
+" Test for errors in using complete() function
+func Test_complete_func_error()
+ call assert_fails('call complete(1, ["a"])', 'E785:')
+ func ListColors()
+ call complete(col('.'), "blue")
+ endfunc
+ call assert_fails('exe "normal i\<C-R>=ListColors()\<CR>"', 'E474:')
+ func ListMonths()
+ call complete(col('.'), test_null_list())
+ endfunc
+ " Nvim allows a NULL list
+ " call assert_fails('exe "normal i\<C-R>=ListMonths()\<CR>"', 'E474:')
+ delfunc ListColors
+ delfunc ListMonths
+ call assert_fails('call complete_info({})', 'E714:')
+ call assert_equal([], complete_info(['items']).items)
+endfunc
+
+" Test for completing words following a completed word in a line
+func Test_complete_wrapscan()
+ " complete words from another buffer
+ new
+ call setline(1, ['one two', 'three four'])
+ new
+ setlocal complete=w
+ call feedkeys("itw\<C-N>\<C-X>\<C-N>\<C-X>\<C-N>\<C-X>\<C-N>", 'xt')
+ call assert_equal('two three four', getline(1))
+ close!
+ " complete words from the current buffer
+ setlocal complete=.
+ %d
+ call setline(1, ['one two', ''])
+ call cursor(2, 1)
+ call feedkeys("ion\<C-N>\<C-X>\<C-N>\<C-X>\<C-N>\<C-X>\<C-N>", 'xt')
+ call assert_equal('one two one two', getline(2))
+ close!
+endfunc
+
" Test for completing special characters
func Test_complete_special_chars()
new
@@ -636,4 +841,23 @@ func Test_z1_complete_no_history()
close!
endfunc
+func FooBarComplete(findstart, base)
+ if a:findstart
+ return col('.') - 1
+ else
+ return ["Foo", "Bar", "}"]
+ endif
+endfunc
+
+func Test_complete_smartindent()
+ new
+ setlocal smartindent completefunc=FooBarComplete
+
+ exe "norm! o{\<cr>\<c-x>\<c-u>\<c-p>}\<cr>\<esc>"
+ let result = getline(1,'$')
+ call assert_equal(['', '{','}',''], result)
+ bw!
+ delfunction! FooBarComplete
+endfunc
+
" vim: shiftwidth=2 sts=2 expandtab
diff --git a/src/nvim/testdir/test_interrupt.vim b/src/nvim/testdir/test_interrupt.vim
index 111752d16a..aa7f634302 100644
--- a/src/nvim/testdir/test_interrupt.vim
+++ b/src/nvim/testdir/test_interrupt.vim
@@ -13,15 +13,20 @@ func s:bufwritepost()
endfunction
func Test_interrupt()
- new Xfile
+ new Xinterrupt
let n = 0
try
- au BufWritePre Xfile call s:bufwritepre()
- au BufWritePost Xfile call s:bufwritepost()
+ au BufWritePre Xinterrupt call s:bufwritepre()
+ au BufWritePost Xinterrupt call s:bufwritepost()
w!
catch /^Vim:Interrupt$/
endtry
call assert_equal(1, s:bufwritepre_called)
call assert_equal(0, s:bufwritepost_called)
- call assert_equal(0, filereadable('Xfile'))
+ call assert_equal(0, filereadable('Xinterrupt'))
+
+ au! BufWritePre
+ au! BufWritePost
endfunc
+
+" vim: shiftwidth=2 sts=2 expandtab
diff --git a/src/nvim/testdir/test_join.vim b/src/nvim/testdir/test_join.vim
index ecb969d10a..1f7a0825a5 100644
--- a/src/nvim/testdir/test_join.vim
+++ b/src/nvim/testdir/test_join.vim
@@ -51,7 +51,7 @@ func Test_join_marks()
/^This line/;'}-join
call assert_equal([0, 4, 11, 0], getpos("'["))
- call assert_equal([0, 4, 66, 0], getpos("']"))
+ call assert_equal([0, 4, 67, 0], getpos("']"))
enew!
endfunc
@@ -437,5 +437,11 @@ func Test_join_lines()
call setline(1, ['a', 'b', '', 'c', 'd'])
normal 5J
call assert_equal('a b c d', getline(1))
+ call setline(1, ['a', 'b', 'c'])
+ 2,2join
+ call assert_equal(['a', 'b', 'c'], getline(1, '$'))
+ call assert_equal(2, line('.'))
+ 2join
+ call assert_equal(['a', 'b c'], getline(1, '$'))
bwipe!
endfunc
diff --git a/src/nvim/testdir/test_jumplist.vim b/src/nvim/testdir/test_jumplist.vim
index 9cfbbe2029..91ad940e18 100644
--- a/src/nvim/testdir/test_jumplist.vim
+++ b/src/nvim/testdir/test_jumplist.vim
@@ -64,3 +64,44 @@ func Test_getjumplist()
call delete("Xtest")
endfunc
+
+func Test_jumplist_invalid()
+ new
+ clearjumps
+ " put some randome text
+ put ='a'
+ let prev = bufnr('%')
+ setl nomodified bufhidden=wipe
+ e XXJumpListBuffer
+ let bnr = bufnr('%')
+ " 1) empty jumplist
+ let expected = [[
+ \ {'lnum': 2, 'bufnr': prev, 'col': 0, 'coladd': 0}], 1]
+ call assert_equal(expected, getjumplist())
+ let jumps = execute(':jumps')
+ call assert_equal('>', jumps[-1:])
+ " now jump back
+ exe ":norm! \<c-o>"
+ let expected = [[
+ \ {'lnum': 2, 'bufnr': prev, 'col': 0, 'coladd': 0},
+ \ {'lnum': 1, 'bufnr': bnr, 'col': 0, 'coladd': 0}], 0]
+ call assert_equal(expected, getjumplist())
+ let jumps = execute(':jumps')
+ call assert_match('> 0 2 0 -invalid-', jumps)
+endfunc
+
+" Test for '' mark in an empty buffer
+
+func Test_empty_buffer()
+ new
+ insert
+a
+b
+c
+d
+.
+ call assert_equal(1, line("''"))
+ bwipe!
+endfunc
+
+" vim: shiftwidth=2 sts=2 expandtab
diff --git a/src/nvim/testdir/test_jumps.vim b/src/nvim/testdir/test_jumps.vim
deleted file mode 100644
index 5a3717d165..0000000000
--- a/src/nvim/testdir/test_jumps.vim
+++ /dev/null
@@ -1,11 +0,0 @@
-func Test_empty_buffer()
- new
- insert
-a
-b
-c
-d
-.
- call assert_equal(1, line("''"))
- bwipe!
-endfunc
diff --git a/src/nvim/testdir/test_lambda.vim b/src/nvim/testdir/test_lambda.vim
index 63bb4ae1ef..c1fe47d1c9 100644
--- a/src/nvim/testdir/test_lambda.vim
+++ b/src/nvim/testdir/test_lambda.vim
@@ -1,24 +1,24 @@
" Test for lambda and closure
-function! Test_lambda_feature()
+func Test_lambda_feature()
call assert_equal(1, has('lambda'))
-endfunction
+endfunc
-function! Test_lambda_with_filter()
+func Test_lambda_with_filter()
let s:x = 2
call assert_equal([2, 3], filter([1, 2, 3], {i, v -> v >= s:x}))
-endfunction
+endfunc
-function! Test_lambda_with_map()
+func Test_lambda_with_map()
let s:x = 1
call assert_equal([2, 3, 4], map([1, 2, 3], {i, v -> v + s:x}))
-endfunction
+endfunc
-function! Test_lambda_with_sort()
+func Test_lambda_with_sort()
call assert_equal([1, 2, 3, 4, 7], sort([3,7,2,1,4], {a, b -> a - b}))
-endfunction
+endfunc
-function! Test_lambda_with_timer()
+func Test_lambda_with_timer()
if !has('timers')
return
endif
@@ -54,10 +54,10 @@ function! Test_lambda_with_timer()
call assert_true(s:n > m)
endfunc
-function! Test_lambda_with_partial()
+func Test_lambda_with_partial()
let l:Cb = function({... -> ['zero', a:1, a:2, a:3]}, ['one', 'two'])
call assert_equal(['zero', 'one', 'two', 'three'], l:Cb('three'))
-endfunction
+endfunc
function Test_lambda_fails()
call assert_equal(3, {a, b -> a + b}(1, 2))
@@ -70,59 +70,59 @@ func Test_not_lambda()
call assert_equal('foo', x['>'])
endfunc
-function! Test_lambda_capture_by_reference()
+func Test_lambda_capture_by_reference()
let v = 1
let l:F = {x -> x + v}
let v = 2
call assert_equal(12, l:F(10))
-endfunction
+endfunc
-function! Test_lambda_side_effect()
- function! s:update_and_return(arr)
+func Test_lambda_side_effect()
+ func! s:update_and_return(arr)
let a:arr[1] = 5
return a:arr
- endfunction
+ endfunc
- function! s:foo(arr)
+ func! s:foo(arr)
return {-> s:update_and_return(a:arr)}
- endfunction
+ endfunc
let arr = [3,2,1]
call assert_equal([3, 5, 1], s:foo(arr)())
-endfunction
+endfunc
-function! Test_lambda_refer_local_variable_from_other_scope()
- function! s:foo(X)
+func Test_lambda_refer_local_variable_from_other_scope()
+ func! s:foo(X)
return a:X() " refer l:x in s:bar()
- endfunction
+ endfunc
- function! s:bar()
+ func! s:bar()
let x = 123
return s:foo({-> x})
- endfunction
+ endfunc
call assert_equal(123, s:bar())
-endfunction
+endfunc
-function! Test_lambda_do_not_share_local_variable()
- function! s:define_funcs()
+func Test_lambda_do_not_share_local_variable()
+ func! s:define_funcs()
let l:One = {-> split(execute("let a = 'abc' | echo a"))[0]}
let l:Two = {-> exists("a") ? a : "no"}
return [l:One, l:Two]
- endfunction
+ endfunc
let l:F = s:define_funcs()
call assert_equal('no', l:F[1]())
call assert_equal('abc', l:F[0]())
call assert_equal('no', l:F[1]())
-endfunction
+endfunc
-function! Test_lambda_closure_counter()
- function! s:foo()
+func Test_lambda_closure_counter()
+ func! s:foo()
let x = 0
return {-> [execute("let x += 1"), x][-1]}
- endfunction
+ endfunc
let l:F = s:foo()
call garbagecollect()
@@ -130,52 +130,52 @@ function! Test_lambda_closure_counter()
call assert_equal(2, l:F())
call assert_equal(3, l:F())
call assert_equal(4, l:F())
-endfunction
+endfunc
-function! Test_lambda_with_a_var()
- function! s:foo()
+func Test_lambda_with_a_var()
+ func! s:foo()
let x = 2
return {... -> a:000 + [x]}
- endfunction
- function! s:bar()
+ endfunc
+ func! s:bar()
return s:foo()(1)
- endfunction
+ endfunc
call assert_equal([1, 2], s:bar())
-endfunction
+endfunc
-function! Test_lambda_call_lambda_from_lambda()
- function! s:foo(x)
+func Test_lambda_call_lambda_from_lambda()
+ func! s:foo(x)
let l:F1 = {-> {-> a:x}}
return {-> l:F1()}
- endfunction
+ endfunc
let l:F = s:foo(1)
call assert_equal(1, l:F()())
-endfunction
+endfunc
-function! Test_lambda_delfunc()
- function! s:gen()
+func Test_lambda_delfunc()
+ func! s:gen()
let pl = l:
let l:Foo = {-> get(pl, "Foo", get(pl, "Bar", {-> 0}))}
let l:Bar = l:Foo
delfunction l:Foo
return l:Bar
- endfunction
+ endfunc
let l:F = s:gen()
call assert_fails(':call l:F()', 'E933:')
-endfunction
+endfunc
-function! Test_lambda_scope()
- function! s:NewCounter()
+func Test_lambda_scope()
+ func! s:NewCounter()
let c = 0
return {-> [execute('let c += 1'), c][-1]}
- endfunction
+ endfunc
- function! s:NewCounter2()
+ func! s:NewCounter2()
return {-> [execute('let c += 100'), c][-1]}
- endfunction
+ endfunc
let l:C = s:NewCounter()
let l:D = s:NewCounter2()
@@ -183,37 +183,37 @@ function! Test_lambda_scope()
call assert_equal(1, l:C())
call assert_fails(':call l:D()', 'E121:')
call assert_equal(2, l:C())
-endfunction
+endfunc
-function! Test_lambda_share_scope()
- function! s:New()
+func Test_lambda_share_scope()
+ func! s:New()
let c = 0
let l:Inc0 = {-> [execute('let c += 1'), c][-1]}
let l:Dec0 = {-> [execute('let c -= 1'), c][-1]}
return [l:Inc0, l:Dec0]
- endfunction
+ endfunc
let [l:Inc, l:Dec] = s:New()
call assert_equal(1, l:Inc())
call assert_equal(2, l:Inc())
call assert_equal(1, l:Dec())
-endfunction
+endfunc
-function! Test_lambda_circular_reference()
- function! s:Foo()
+func Test_lambda_circular_reference()
+ func! s:Foo()
let d = {}
let d.f = {-> d}
return d.f
- endfunction
+ endfunc
call s:Foo()
call garbagecollect()
let i = 0 | while i < 10000 | call s:Foo() | let i+= 1 | endwhile
call garbagecollect()
-endfunction
+endfunc
-function! Test_lambda_combination()
+func Test_lambda_combination()
call assert_equal(2, {x -> {x -> x}}(1)(2))
call assert_equal(10, {y -> {x -> x(y)(10)}({y -> y})}({z -> z}))
call assert_equal(5.0, {x -> {y -> x / y}}(10)(2.0))
@@ -226,17 +226,17 @@ function! Test_lambda_combination()
let Z = {f -> {x -> f({y -> x(x)(y)})}({x -> f({y -> x(x)(y)})})}
let Fact = {f -> {x -> x == 0 ? 1 : x * f(x - 1)}}
call assert_equal(120, Z(Fact)(5))
-endfunction
+endfunc
-function! Test_closure_counter()
- function! s:foo()
+func Test_closure_counter()
+ func! s:foo()
let x = 0
- function! s:bar() closure
+ func! s:bar() closure
let x += 1
return x
- endfunction
+ endfunc
return function('s:bar')
- endfunction
+ endfunc
let l:F = s:foo()
call garbagecollect()
@@ -244,30 +244,30 @@ function! Test_closure_counter()
call assert_equal(2, l:F())
call assert_equal(3, l:F())
call assert_equal(4, l:F())
-endfunction
+endfunc
-function! Test_closure_unlet()
- function! s:foo()
+func Test_closure_unlet()
+ func! s:foo()
let x = 1
- function! s:bar() closure
+ func! s:bar() closure
unlet x
- endfunction
+ endfunc
call s:bar()
return l:
- endfunction
+ endfunc
call assert_false(has_key(s:foo(), 'x'))
call garbagecollect()
-endfunction
+endfunc
-function! LambdaFoo()
+func LambdaFoo()
let x = 0
- function! LambdaBar() closure
+ func! LambdaBar() closure
let x += 1
return x
- endfunction
+ endfunc
return function('LambdaBar')
-endfunction
+endfunc
func Test_closure_refcount()
let g:Count = LambdaFoo()
@@ -303,3 +303,8 @@ func Test_lambda_with_index()
let Extract = {-> function(List, ['foobar'])()[0]}
call assert_equal('foobar', Extract())
endfunc
+
+func Test_lambda_error()
+ " This was causing a crash
+ call assert_fails('ec{@{->{d->()()', 'E15')
+endfunc
diff --git a/src/nvim/testdir/test_langmap.vim b/src/nvim/testdir/test_langmap.vim
index 066c3bf2bd..4f831aa40b 100644
--- a/src/nvim/testdir/test_langmap.vim
+++ b/src/nvim/testdir/test_langmap.vim
@@ -1,5 +1,8 @@
" tests for 'langmap'
+source check.vim
+CheckFeature langmap
+
func Test_langmap()
new
set langmap=}l,^x,%v
@@ -20,5 +23,32 @@ func Test_langmap()
silent! call feedkeys("gg0}%}\<C-G>}^\<Esc>00", 'tx')
call assert_equal('a}^de', getline(1))
+ " Error cases
+ call assert_fails('set langmap=aA,b', 'E357:')
+ call assert_fails('set langmap=z;y;y;z', 'E358:')
+
+ " Map character > 256
+ enew!
+ set langmap=āx,ăl,āx
+ call setline(1, ['abcde'])
+ call feedkeys('gg2lā', 'tx')
+ call assert_equal('abde', getline(1))
+
+ " special characters in langmap
+ enew!
+ call setline(1, ['Hello World'])
+ set langmap=\\;\\,,\\,\\;
+ call feedkeys('ggfo,', 'tx')
+ call assert_equal(8, col('.'))
+ call feedkeys(';', 'tx')
+ call assert_equal(5, col('.'))
+ set langmap&
+ set langmap=\\;\\,;\\,\\;
+ call feedkeys('ggfo,', 'tx')
+ call assert_equal(8, col('.'))
+ call feedkeys(';', 'tx')
+ call assert_equal(5, col('.'))
+
+ set langmap&
quit!
endfunc
diff --git a/src/nvim/testdir/test_legacy_filetype.vim b/src/nvim/testdir/test_legacy_filetype.vim
new file mode 100644
index 0000000000..772faaadb0
--- /dev/null
+++ b/src/nvim/testdir/test_legacy_filetype.vim
@@ -0,0 +1,4 @@
+let g:do_legacy_filetype = 1
+filetype on
+
+source test_filetype.vim
diff --git a/src/nvim/testdir/test_lispwords.vim b/src/nvim/testdir/test_lispwords.vim
index aa5a738bdf..4144fb0521 100644
--- a/src/nvim/testdir/test_lispwords.vim
+++ b/src/nvim/testdir/test_lispwords.vim
@@ -1,4 +1,5 @@
-" Tests for 'lispwords' settings being global-local
+" Tests for 'lispwords' settings being global-local.
+" And other lisp indent stuff.
set nocompatible viminfo+=nviminfo
@@ -45,6 +46,7 @@ func Test_lisp_indent()
\ ])
call assert_equal(7, lispindent(2))
call assert_equal(5, 6->lispindent())
+ call assert_equal(-1, lispindent(-1))
set lisp
set lispwords&
@@ -83,3 +85,14 @@ func Test_lisp_indent()
let &cpoptions=save_copt
set nolisp
endfunc
+
+func Test_lisp_indent_works()
+ " This was reading beyond the end of the line
+ new
+ exe "norm a\tü(\<CR>="
+ set lisp
+ norm ==
+ bwipe!
+endfunc
+
+" vim: shiftwidth=2 sts=2 expandtab
diff --git a/src/nvim/testdir/test_listchars.vim b/src/nvim/testdir/test_listchars.vim
index 0bcbd9c4a5..eed4d7e30c 100644
--- a/src/nvim/testdir/test_listchars.vim
+++ b/src/nvim/testdir/test_listchars.vim
@@ -1,6 +1,8 @@
" Tests for 'listchars' display with 'list' and :list
+source check.vim
source view_util.vim
+source screendump.vim
func Test_listchars()
enew!
@@ -130,7 +132,7 @@ func Test_listchars()
\ 'h<<<<<<<<<<<$',
\ '<<<<<<<<<<<<$',
\ '>>>>0xx0<<<<$',
- \ '$'
+ \ '$'
\ ]
redraw!
for i in range(1, 5)
@@ -160,7 +162,7 @@ func Test_listchars()
\ ' hyYzZyYzZyY$',
\ 'yYzZyYzZyYj $',
\ 'yYzZ0yY0yYzZ$',
- \ '$'
+ \ '$'
\ ]
redraw!
for i in range(1, 5)
@@ -170,7 +172,133 @@ func Test_listchars()
call assert_equal(expected, split(execute("%list"), "\n"))
+ " Test leadmultispace + multispace
+ normal ggdG
+ set listchars=eol:$,multispace:yYzZ,nbsp:S
+ set listchars+=leadmultispace:.-+*
+ set list
+
+ call append(0, [
+ \ ' ffff ',
+ \ ' i i  gg',
+ \ ' h ',
+ \ ' j ',
+ \ ' 0 0 ',
+ \ ])
+
+ let expected = [
+ \ '.-+*ffffyYzZ$',
+ \ '.-i iSyYzZgg$',
+ \ ' hyYzZyYzZyY$',
+ \ '.-+*.-+*.-j $',
+ \ '.-+*0yY0yYzZ$',
+ \ '$'
+ \ ]
+ redraw!
+ call assert_equal('eol:$,multispace:yYzZ,nbsp:S,leadmultispace:.-+*', &listchars)
+ for i in range(1, 5)
+ call cursor(i, 1)
+ call assert_equal([expected[i - 1]], ScreenLines(i, virtcol('$')))
+ endfor
+
+ call assert_equal(expected, split(execute("%list"), "\n"))
+
+ " Test leadmultispace without multispace
+ normal ggdG
+ set listchars-=multispace:yYzZ
+ set listchars+=space:+,trail:>,eol:$
+ set list
+
+ call append(0, [
+ \ ' ffff ',
+ \ ' i i gg',
+ \ ' h ',
+ \ ' j ',
+ \ ' 0 0 ',
+ \ ])
+
+ let expected = [
+ \ '.-+*ffff>>>>$',
+ \ '.-i+i+++++gg$',
+ \ '+h>>>>>>>>>>$',
+ \ '.-+*.-+*.-j>$',
+ \ '.-+*0++0>>>>$',
+ \ '$',
+ \ ]
+
+ redraw!
+ call assert_equal('eol:$,nbsp:S,leadmultispace:.-+*,space:+,trail:>,eol:$', &listchars)
+ for i in range(1, 5)
+ call cursor(i, 1)
+ call assert_equal([expected[i - 1]], ScreenLines(i, virtcol('$')))
+ endfor
+
+ call assert_equal(expected, split(execute("%list"), "\n"))
+
+ " Test leadmultispace only
+ normal ggdG
+ set listchars=eol:$ " Accommodate Nvim default
+ set listchars=leadmultispace:.-+*
+ set list
+
+ call append(0, [
+ \ ' ffff ',
+ \ ' i i gg',
+ \ ' h ',
+ \ ' j ',
+ \ ' 0 0 ',
+ \ ])
+
+ let expected = [
+ \ '.-+*ffff ',
+ \ '.-i i gg',
+ \ ' h ',
+ \ '.-+*.-+*.-j ',
+ \ '.-+*0 0 ',
+ \ ' ',
+ \ ]
+ redraw!
+ call assert_equal('leadmultispace:.-+*', &listchars)
+ for i in range(1, 5)
+ call cursor(i, 1)
+ call assert_equal([expected[i - 1]], ScreenLines(i, 12))
+ endfor
+ call assert_equal(expected, split(execute("%list"), "\n"))
+
+ " Test leadmultispace and lead and space
+ normal ggdG
+ set listchars=eol:$ " Accommodate Nvim default
+ set listchars+=lead:<,space:-
+ set listchars+=leadmultispace:.-+*
+ set list
+
+ call append(0, [
+ \ ' ffff ',
+ \ ' i i gg',
+ \ ' h ',
+ \ ' j ',
+ \ ' 0 0 ',
+ \ ])
+
+ let expected = [
+ \ '.-+*ffff----$',
+ \ '.-i-i-----gg$',
+ \ '<h----------$',
+ \ '.-+*.-+*.-j-$',
+ \ '.-+*0--0----$',
+ \ '$',
+ \ ]
+ redraw!
+ call assert_equal('eol:$,lead:<,space:-,leadmultispace:.-+*', &listchars)
+ for i in range(1, 5)
+ call cursor(i, 1)
+ call assert_equal([expected[i - 1]], ScreenLines(i, virtcol('$')))
+ endfor
+ call assert_equal(expected, split(execute("%list"), "\n"))
+
" the last occurrence of 'multispace:' is used
+ set listchars=eol:$ " Accommodate Nvim default
+ set listchars+=multispace:yYzZ
set listchars+=space:x,multispace:XyY
let expected = [
@@ -179,9 +307,10 @@ func Test_listchars()
\ 'xhXyYXyYXyYX$',
\ 'XyYXyYXyYXjx$',
\ 'XyYX0Xy0XyYX$',
- \ '$'
+ \ '$'
\ ]
redraw!
+ call assert_equal('eol:$,multispace:yYzZ,space:x,multispace:XyY', &listchars)
for i in range(1, 5)
call cursor(i, 1)
call assert_equal([expected[i - 1]], ScreenLines(i, virtcol('$')))
@@ -197,7 +326,7 @@ func Test_listchars()
\ '>h<<<<<<<<<<$',
\ '>>>>>>>>>>j<$',
\ '>>>>0Xy0<<<<$',
- \ '$'
+ \ '$'
\ ]
redraw!
for i in range(1, 5)
@@ -217,7 +346,7 @@ func Test_listchars()
\ '>h<<<<<<<<<<$',
\ '>>>>>>>>>>j<$',
\ '>>>>0xx0<<<<$',
- \ '$'
+ \ '$'
\ ]
redraw!
for i in range(1, 5)
@@ -313,11 +442,13 @@ func Test_listchars_invalid()
call assert_fails('set listchars=x', 'E474:')
call assert_fails('set listchars=x', 'E474:')
call assert_fails('set listchars=multispace', 'E474:')
+ call assert_fails('set listchars=leadmultispace', 'E474:')
" Too short
call assert_fails('set listchars=space:', 'E474:')
call assert_fails('set listchars=tab:x', 'E474:')
call assert_fails('set listchars=multispace:', 'E474:')
+ call assert_fails('set listchars=leadmultispace:', 'E474:')
" One occurrence too short
call assert_fails('set listchars=space:,space:x', 'E474:')
@@ -326,6 +457,8 @@ func Test_listchars_invalid()
call assert_fails('set listchars=tab:xx,tab:x', 'E474:')
call assert_fails('set listchars=multispace:,multispace:x', 'E474:')
call assert_fails('set listchars=multispace:x,multispace:', 'E474:')
+ call assert_fails('set listchars=leadmultispace:,leadmultispace:x', 'E474:')
+ call assert_fails('set listchars=leadmultispace:x,leadmultispace:', 'E474:')
" Too long
call assert_fails('set listchars=space:xx', 'E474:')
@@ -338,6 +471,8 @@ func Test_listchars_invalid()
call assert_fails('set listchars=tab:xx·', 'E474:')
call assert_fails('set listchars=multispace:·', 'E474:')
call assert_fails('set listchars=multispace:xxx·', 'E474:')
+ call assert_fails('set listchars=leadmultispace:·', 'E474:')
+ call assert_fails('set listchars=leadmultispace:xxx·', 'E474:')
" Has control character
call assert_fails("set listchars=space:\x01", 'E474:')
@@ -352,6 +487,10 @@ func Test_listchars_invalid()
call assert_fails('set listchars=tab:xx\\x01', 'E474:')
call assert_fails('set listchars=multispace:\\x01', 'E474:')
call assert_fails('set listchars=multispace:xxx\\x01', 'E474:')
+ call assert_fails("set listchars=leadmultispace:\x01", 'E474:')
+ call assert_fails('set listchars=leadmultispace:\\x01', 'E474:')
+ call assert_fails("set listchars=leadmultispace:xxx\x01", 'E474:')
+ call assert_fails('set listchars=leadmultispace:xxx\\x01', 'E474:')
enew!
set ambiwidth& listchars& ff&
@@ -517,4 +656,40 @@ func Test_listchars_window_local()
set list& listchars&
endfunc
+func Test_listchars_foldcolumn()
+ CheckScreendump
+
+ let lines =<< trim END
+ call setline(1, ['aaa', '', 'a', 'aaaaaa'])
+ vsplit
+ vsplit
+ windo set signcolumn=yes foldcolumn=1 winminwidth=0 nowrap list listchars=extends:>,precedes:<
+ END
+ call writefile(lines, 'XTest_listchars')
+
+ let buf = RunVimInTerminal('-S XTest_listchars', {'rows': 10, 'cols': 60})
+
+ call term_sendkeys(buf, "13\<C-W>>")
+ call VerifyScreenDump(buf, 'Test_listchars_01', {})
+ call term_sendkeys(buf, "\<C-W>>")
+ call VerifyScreenDump(buf, 'Test_listchars_02', {})
+ call term_sendkeys(buf, "\<C-W>>")
+ call VerifyScreenDump(buf, 'Test_listchars_03', {})
+ call term_sendkeys(buf, "\<C-W>>")
+ call VerifyScreenDump(buf, 'Test_listchars_04', {})
+ call term_sendkeys(buf, "\<C-W>>")
+ call VerifyScreenDump(buf, 'Test_listchars_05', {})
+ call term_sendkeys(buf, "\<C-W>h")
+ call term_sendkeys(buf, ":set nowrap foldcolumn=4\<CR>")
+ call term_sendkeys(buf, "15\<C-W><")
+ call VerifyScreenDump(buf, 'Test_listchars_06', {})
+ call term_sendkeys(buf, "4\<C-W><")
+ call VerifyScreenDump(buf, 'Test_listchars_07', {})
+
+ " clean up
+ call StopVimInTerminal(buf)
+ call delete('XTest_listchars')
+endfunc
+
+
" vim: shiftwidth=2 sts=2 expandtab
diff --git a/src/nvim/testdir/test_listdict.vim b/src/nvim/testdir/test_listdict.vim
index f6c404d390..aa66d86af1 100644
--- a/src/nvim/testdir/test_listdict.vim
+++ b/src/nvim/testdir/test_listdict.vim
@@ -516,22 +516,22 @@ func Test_dict_lock_operator()
endfunc
" No remove() of write-protected scope-level variable
-func! Tfunc(this_is_a_long_parameter_name)
+func Tfunc1(this_is_a_long_parameter_name)
call assert_fails("call remove(a:, 'this_is_a_long_parameter_name')", 'E742')
-endfun
+endfunc
func Test_dict_scope_var_remove()
- call Tfunc('testval')
+ call Tfunc1('testval')
endfunc
" No extend() of write-protected scope-level variable
func Test_dict_scope_var_extend()
call assert_fails("call extend(a:, {'this_is_a_long_parameter_name': 1234})", 'E742')
endfunc
-func! Tfunc(this_is_a_long_parameter_name)
+func Tfunc2(this_is_a_long_parameter_name)
call assert_fails("call extend(a:, {'this_is_a_long_parameter_name': 1234})", 'E742')
endfunc
func Test_dict_scope_var_extend_overwrite()
- call Tfunc('testval')
+ call Tfunc2('testval')
endfunc
" No :unlet of variable in locked scope
@@ -620,6 +620,49 @@ func Test_reverse_sort_uniq()
call assert_fails('call reverse("")', 'E899:')
endfunc
+" reduce a list or a blob
+func Test_reduce()
+ call assert_equal(1, reduce([], { acc, val -> acc + val }, 1))
+ call assert_equal(10, reduce([1, 3, 5], { acc, val -> acc + val }, 1))
+ call assert_equal(2 * (2 * ((2 * 1) + 2) + 3) + 4, reduce([2, 3, 4], { acc, val -> 2 * acc + val }, 1))
+ call assert_equal('a x y z', ['x', 'y', 'z']->reduce({ acc, val -> acc .. ' ' .. val}, 'a'))
+ call assert_equal(#{ x: 1, y: 1, z: 1 }, ['x', 'y', 'z']->reduce({ acc, val -> extend(acc, { val: 1 }) }, {}))
+ call assert_equal([0, 1, 2, 3], reduce([1, 2, 3], function('add'), [0]))
+
+ let l = ['x', 'y', 'z']
+ call assert_equal(42, reduce(l, function('get'), #{ x: #{ y: #{ z: 42 } } }))
+ call assert_equal(['x', 'y', 'z'], l)
+
+ call assert_equal(1, reduce([1], { acc, val -> acc + val }))
+ call assert_equal('x y z', reduce(['x', 'y', 'z'], { acc, val -> acc .. ' ' .. val }))
+ call assert_equal(120, range(1, 5)->reduce({ acc, val -> acc * val }))
+ call assert_fails("call reduce([], { acc, val -> acc + val })", 'E998: Reduce of an empty List with no initial value')
+
+ call assert_equal(1, reduce(0z, { acc, val -> acc + val }, 1))
+ call assert_equal(1 + 0xaf + 0xbf + 0xcf, reduce(0zAFBFCF, { acc, val -> acc + val }, 1))
+ call assert_equal(2 * (2 * 1 + 0xaf) + 0xbf, 0zAFBF->reduce({ acc, val -> 2 * acc + val }, 1))
+
+ call assert_equal(0xff, reduce(0zff, { acc, val -> acc + val }))
+ call assert_equal(2 * (2 * 0xaf + 0xbf) + 0xcf, reduce(0zAFBFCF, { acc, val -> 2 * acc + val }))
+ call assert_fails("call reduce(0z, { acc, val -> acc + val })", 'E998: Reduce of an empty Blob with no initial value')
+
+ call assert_fails("call reduce({}, { acc, val -> acc + val }, 1)", 'E897:')
+ call assert_fails("call reduce(0, { acc, val -> acc + val }, 1)", 'E897:')
+ call assert_fails("call reduce('', { acc, val -> acc + val }, 1)", 'E897:')
+
+ let g:lut = [1, 2, 3, 4]
+ func EvilRemove()
+ call remove(g:lut, 1)
+ return 1
+ endfunc
+ call assert_fails("call reduce(g:lut, { acc, val -> EvilRemove() }, 1)", 'E742:')
+ unlet g:lut
+ delfunc EvilRemove
+
+ call assert_equal(42, reduce(v:_null_list, function('add'), 42))
+ call assert_equal(42, reduce(v:_null_blob, function('add'), 42))
+endfunc
+
" splitting a string to a List
func Test_str_split()
call assert_equal(['aa', 'bb'], split(' aa bb '))
diff --git a/src/nvim/testdir/test_listlbr.vim b/src/nvim/testdir/test_listlbr.vim
index 2fda12d8b4..affa0f96fa 100644
--- a/src/nvim/testdir/test_listlbr.vim
+++ b/src/nvim/testdir/test_listlbr.vim
@@ -2,9 +2,9 @@
scriptencoding latin1
-if !exists("+linebreak") || !has("conceal")
- finish
-endif
+source check.vim
+CheckOption linebreak
+CheckFeature conceal
source view_util.vim
diff --git a/src/nvim/testdir/test_listlbr_utf8.vim b/src/nvim/testdir/test_listlbr_utf8.vim
index c38e0c5f3c..df1ed78119 100644
--- a/src/nvim/testdir/test_listlbr_utf8.vim
+++ b/src/nvim/testdir/test_listlbr_utf8.vim
@@ -3,9 +3,10 @@
set encoding=utf-8
scriptencoding utf-8
-if !exists("+linebreak") || !has("conceal") || !has("signs")
- finish
-endif
+source check.vim
+CheckOption linebreak
+CheckFeature conceal
+CheckFeature signs
source view_util.vim
@@ -69,6 +70,16 @@ func Test_nolinebreak_with_list()
call s:close_windows()
endfunc
+" this was causing a crash
+func Test_linebreak_with_list_and_tabs()
+ set linebreak list listchars=tab:⇤\ ⇥ tabstop=100
+ new
+ call setline(1, "\t\t\ttext")
+ redraw
+ bwipe!
+ set nolinebreak nolist listchars&vim tabstop=8
+endfunc
+
func Test_linebreak_with_nolist()
call s:test_windows('setl nolist')
call setline(1, "\t*mask = nil;")
diff --git a/src/nvim/testdir/test_makeencoding.vim b/src/nvim/testdir/test_makeencoding.vim
index 2b346e0720..c53c07d991 100644
--- a/src/nvim/testdir/test_makeencoding.vim
+++ b/src/nvim/testdir/test_makeencoding.vim
@@ -4,8 +4,7 @@ source shared.vim
let s:python = PythonProg()
if s:python == ''
- " Can't run this test.
- finish
+ throw 'Skipped: python program missing'
endif
let s:script = 'test_makeencoding.py'
diff --git a/src/nvim/testdir/test_maparg.vim b/src/nvim/testdir/test_maparg.vim
index 5b082198cf..f9429a8020 100644
--- a/src/nvim/testdir/test_maparg.vim
+++ b/src/nvim/testdir/test_maparg.vim
@@ -42,14 +42,53 @@ function Test_maparg()
map abc y<S-char-114>y
call assert_equal("yRy", maparg('abc'))
+ " character with K_SPECIAL byte
+ nmap abc …
+ call assert_equal('…', maparg('abc'))
+
+ " modified character with K_SPECIAL byte
+ nmap abc <M-…>
+ call assert_equal('<M-…>', maparg('abc'))
+
+ " illegal bytes
+ let str = ":\x7f:\x80:\x90:\xd0:"
+ exe 'nmap abc ' .. str
+ call assert_equal(str, maparg('abc'))
+ unlet str
+
omap { w
let d = maparg('{', 'o', 0, 1)
call assert_equal(['{', 'w', 'o'], [d.lhs, d.rhs, d.mode])
ounmap {
+ lmap { w
+ let d = maparg('{', 'l', 0, 1)
+ call assert_equal(['{', 'w', 'l'], [d.lhs, d.rhs, d.mode])
+ lunmap {
+
+ nmap { w
+ let d = maparg('{', 'n', 0, 1)
+ call assert_equal(['{', 'w', 'n'], [d.lhs, d.rhs, d.mode])
+ nunmap {
+
+ xmap { w
+ let d = maparg('{', 'x', 0, 1)
+ call assert_equal(['{', 'w', 'x'], [d.lhs, d.rhs, d.mode])
+ xunmap {
+
+ smap { w
+ let d = maparg('{', 's', 0, 1)
+ call assert_equal(['{', 'w', 's'], [d.lhs, d.rhs, d.mode])
+ sunmap {
+
map abc <Nop>
call assert_equal("<Nop>", maparg('abc'))
unmap abc
+
+ call feedkeys(":abbr esc \<C-V>\<C-V>\<C-V>\<C-V>\<C-V>\<Esc>\<CR>", "xt")
+ let d = maparg('esc', 'i', 1, 1)
+ call assert_equal(['esc', "\<C-V>\<C-V>\<Esc>", '!'], [d.lhs, d.rhs, d.mode])
+ abclear
endfunction
func Test_mapcheck()
diff --git a/src/nvim/testdir/test_mapping.vim b/src/nvim/testdir/test_mapping.vim
index f88e8cf843..e1d0b9a9ba 100644
--- a/src/nvim/testdir/test_mapping.vim
+++ b/src/nvim/testdir/test_mapping.vim
@@ -1,6 +1,8 @@
" Tests for mappings and abbreviations
source shared.vim
+source check.vim
+source screendump.vim
func Test_abbreviation()
" abbreviation with 0x80 should work
@@ -29,6 +31,7 @@ func Test_abclear()
abclear
call assert_equal("\n\nNo abbreviation found", execute('abbrev'))
+ call assert_fails('%abclear', 'E481:')
endfunc
func Test_abclear_buffer()
@@ -60,7 +63,7 @@ func Test_map_ctrl_c_insert()
inoremap <c-c> <ctrl-c>
cnoremap <c-c> dummy
cunmap <c-c>
- call feedkeys("GoTEST2: CTRL-C |\<C-C>A|\<Esc>", "xt")
+ call feedkeys("GoTEST2: CTRL-C |\<*C-C>A|\<Esc>", "xt")
call assert_equal('TEST2: CTRL-C |<ctrl-c>A|', getline('$'))
unmap! <c-c>
set nomodified
@@ -69,7 +72,7 @@ endfunc
func Test_map_ctrl_c_visual()
" mapping of ctrl-c in Visual mode
vnoremap <c-c> :<C-u>$put ='vmap works'
- call feedkeys("GV\<C-C>\<CR>", "xt")
+ call feedkeys("GV\<*C-C>\<CR>", "xt")
call assert_equal('vmap works', getline('$'))
vunmap <c-c>
set nomodified
@@ -219,7 +222,7 @@ endfunc
func Test_map_meta_quotes()
imap <M-"> foo
- call feedkeys("Go-\<M-\">-\<Esc>", "xt")
+ call feedkeys("Go-\<*M-\">-\<Esc>", "xt")
call assert_equal("-foo-", getline('$'))
set nomodified
iunmap <M-">
@@ -427,6 +430,85 @@ func Test_error_in_map_expr()
exe buf .. 'bwipe!'
endfunc
+func Test_list_mappings()
+ " Remove default mappings
+ imapclear
+
+ " reset 'isident' to check it isn't used
+ set isident=
+ inoremap <C-m> CtrlM
+ inoremap <A-S> AltS
+ inoremap <S-/> ShiftSlash
+ set isident&
+ call assert_equal([
+ \ 'i <S-/> * ShiftSlash',
+ \ 'i <M-S> * AltS',
+ \ 'i <C-M> * CtrlM',
+ \], execute('imap')->trim()->split("\n"))
+ iunmap <C-M>
+ iunmap <A-S>
+ call assert_equal(['i <S-/> * ShiftSlash'], execute('imap')->trim()->split("\n"))
+ iunmap <S-/>
+ call assert_equal(['No mapping found'], execute('imap')->trim()->split("\n"))
+
+ " List global, buffer local and script local mappings
+ nmap ,f /^\k\+ (<CR>
+ nmap <buffer> ,f /^\k\+ (<CR>
+ nmap <script> ,fs /^\k\+ (<CR>
+ call assert_equal(['n ,f @/^\k\+ (<CR>',
+ \ 'n ,fs & /^\k\+ (<CR>',
+ \ 'n ,f /^\k\+ (<CR>'],
+ \ execute('nmap ,f')->trim()->split("\n"))
+
+ " List <Nop> mapping
+ nmap ,n <Nop>
+ call assert_equal(['n ,n <Nop>'],
+ \ execute('nmap ,n')->trim()->split("\n"))
+
+ " verbose map
+ call assert_match("\tLast set from .*/test_mapping.vim line \\d\\+$",
+ \ execute('verbose map ,n')->trim()->split("\n")[1])
+
+ " character with K_SPECIAL byte in rhs
+ nmap foo …
+ call assert_equal(['n foo …'],
+ \ execute('nmap foo')->trim()->split("\n"))
+
+ " modified character with K_SPECIAL byte in rhs
+ nmap foo <M-…>
+ call assert_equal(['n foo <M-…>'],
+ \ execute('nmap foo')->trim()->split("\n"))
+
+ " character with K_SPECIAL byte in lhs
+ nmap … foo
+ call assert_equal(['n … foo'],
+ \ execute('nmap …')->trim()->split("\n"))
+
+ " modified character with K_SPECIAL byte in lhs
+ nmap <M-…> foo
+ call assert_equal(['n <M-…> foo'],
+ \ execute('nmap <M-…>')->trim()->split("\n"))
+
+ " illegal bytes
+ let str = ":\x7f:\x80:\x90:\xd0:"
+ exe 'nmap foo ' .. str
+ call assert_equal(['n foo ' .. strtrans(str)],
+ \ execute('nmap foo')->trim()->split("\n"))
+ unlet str
+
+ " map to CTRL-V
+ exe "nmap ,k \<C-V>"
+ call assert_equal(['n ,k <Nop>'],
+ \ execute('nmap ,k')->trim()->split("\n"))
+
+ " map with space at the beginning
+ exe "nmap \<C-V> w <Nop>"
+ call assert_equal(['n <Space>w <Nop>'],
+ \ execute("nmap \<C-V> w")->trim()->split("\n"))
+
+ nmapclear
+endfunc
+
func Test_expr_map_gets_cursor()
new
call setline(1, ['one', 'some w!rd'])
@@ -451,6 +533,82 @@ func Test_expr_map_gets_cursor()
nunmap !
endfunc
+func Test_expr_map_restore_cursor()
+ CheckScreendump
+
+ let lines =<< trim END
+ call setline(1, ['one', 'two', 'three'])
+ 2
+ set ls=2
+ hi! link StatusLine ErrorMsg
+ noremap <expr> <C-B> Func()
+ func Func()
+ let g:on = !get(g:, 'on', 0)
+ redraws
+ return ''
+ endfunc
+ func Status()
+ return get(g:, 'on', 0) ? '[on]' : ''
+ endfunc
+ set stl=%{Status()}
+ END
+ call writefile(lines, 'XtestExprMap')
+ let buf = RunVimInTerminal('-S XtestExprMap', #{rows: 10})
+ call term_sendkeys(buf, "\<C-B>")
+ call VerifyScreenDump(buf, 'Test_map_expr_1', {})
+
+ " clean up
+ call StopVimInTerminal(buf)
+ call delete('XtestExprMap')
+endfunc
+
+func Test_map_listing()
+ CheckScreendump
+
+ let lines =<< trim END
+ nmap a b
+ END
+ call writefile(lines, 'XtestMapList')
+ let buf = RunVimInTerminal('-S XtestMapList', #{rows: 6})
+ call term_sendkeys(buf, ": nmap a\<CR>")
+ call VerifyScreenDump(buf, 'Test_map_list_1', {})
+
+ " clean up
+ call StopVimInTerminal(buf)
+ call delete('XtestMapList')
+endfunc
+
+func Test_expr_map_error()
+ CheckScreendump
+
+ let lines =<< trim END
+ func Func()
+ throw 'test'
+ return ''
+ endfunc
+
+ nnoremap <expr> <F2> Func()
+ cnoremap <expr> <F2> Func()
+
+ call test_override('ui_delay', 10)
+ END
+ call writefile(lines, 'XtestExprMap')
+ let buf = RunVimInTerminal('-S XtestExprMap', #{rows: 10})
+ call term_sendkeys(buf, "\<F2>")
+ call TermWait(buf)
+ call term_sendkeys(buf, "\<CR>")
+ call VerifyScreenDump(buf, 'Test_map_expr_2', {})
+
+ call term_sendkeys(buf, ":abc\<F2>")
+ call VerifyScreenDump(buf, 'Test_map_expr_3', {})
+ call term_sendkeys(buf, "\<Esc>0")
+ call VerifyScreenDump(buf, 'Test_map_expr_4', {})
+
+ " clean up
+ call StopVimInTerminal(buf)
+ call delete('XtestExprMap')
+endfunc
+
" Test for mapping errors
func Test_map_error()
call assert_fails('unmap', 'E474:')
@@ -476,6 +634,22 @@ func Test_map_error()
call assert_fails('mapclear abc', 'E474:')
call assert_fails('abclear abc', 'E474:')
+ call assert_fails('abbr $xyz abc', 'E474:')
+
+ " space character in an abbreviation
+ call assert_fails('abbr ab<space> ABC', 'E474:')
+
+ " invalid <expr> map
+ map <expr> ,f abc
+ call assert_fails('normal ,f', 'E121:')
+ unmap <expr> ,f
+
+ " Recursive use of :normal in a map
+ set maxmapdepth=100
+ map gq :normal gq<CR>
+ call assert_fails('normal gq', 'E192:')
+ unmap gq
+ set maxmapdepth&
endfunc
" Test for <special> key mapping
@@ -503,11 +677,66 @@ endfunc
" Test for hasmapto()
func Test_hasmapto()
call assert_equal(0, hasmapto('/^\k\+ ('))
+ map ,f /^\k\+ (<CR>
+ call assert_equal(1, hasmapto('/^\k\+ ('))
+ unmap ,f
+
+ " Insert mode mapping
+ call assert_equal(0, hasmapto('/^\k\+ (', 'i'))
+ imap ,f /^\k\+ (<CR>
+ call assert_equal(1, hasmapto('/^\k\+ (', 'i'))
+ iunmap ,f
+
+ " Normal mode mapping
call assert_equal(0, hasmapto('/^\k\+ (', 'n'))
nmap ,f /^\k\+ (<CR>
call assert_equal(1, hasmapto('/^\k\+ ('))
call assert_equal(1, hasmapto('/^\k\+ (', 'n'))
+ nunmap ,f
+
+ " Visual and Select mode mapping
call assert_equal(0, hasmapto('/^\k\+ (', 'v'))
+ call assert_equal(0, hasmapto('/^\k\+ (', 'x'))
+ call assert_equal(0, hasmapto('/^\k\+ (', 's'))
+ vmap ,f /^\k\+ (<CR>
+ call assert_equal(1, hasmapto('/^\k\+ (', 'v'))
+ call assert_equal(1, hasmapto('/^\k\+ (', 'x'))
+ call assert_equal(1, hasmapto('/^\k\+ (', 's'))
+ vunmap ,f
+
+ " Visual mode mapping
+ call assert_equal(0, hasmapto('/^\k\+ (', 'x'))
+ xmap ,f /^\k\+ (<CR>
+ call assert_equal(1, hasmapto('/^\k\+ (', 'v'))
+ call assert_equal(1, hasmapto('/^\k\+ (', 'x'))
+ call assert_equal(0, hasmapto('/^\k\+ (', 's'))
+ xunmap ,f
+
+ " Select mode mapping
+ call assert_equal(0, hasmapto('/^\k\+ (', 's'))
+ smap ,f /^\k\+ (<CR>
+ call assert_equal(1, hasmapto('/^\k\+ (', 'v'))
+ call assert_equal(0, hasmapto('/^\k\+ (', 'x'))
+ call assert_equal(1, hasmapto('/^\k\+ (', 's'))
+ sunmap ,f
+
+ " Operator-pending mode mapping
+ call assert_equal(0, hasmapto('/^\k\+ (', 'o'))
+ omap ,f /^\k\+ (<CR>
+ call assert_equal(1, hasmapto('/^\k\+ (', 'o'))
+ ounmap ,f
+
+ " Language mapping
+ call assert_equal(0, hasmapto('/^\k\+ (', 'l'))
+ lmap ,f /^\k\+ (<CR>
+ call assert_equal(1, hasmapto('/^\k\+ (', 'l'))
+ lunmap ,f
+
+ " Cmdline mode mapping
+ call assert_equal(0, hasmapto('/^\k\+ (', 'c'))
+ cmap ,f /^\k\+ (<CR>
+ call assert_equal(1, hasmapto('/^\k\+ (', 'c'))
+ cunmap ,f
call assert_equal(0, hasmapto('/^\k\+ (', 'n', 1))
endfunc
@@ -519,8 +748,176 @@ func Test_mapcomplete()
\ getcompletion('', 'mapping'))
call assert_equal([], getcompletion(',d', 'mapping'))
+ call feedkeys(":unmap <buf\<C-A>\<C-B>\"\<CR>", 'tx')
+ call assert_equal('"unmap <buffer>', @:)
+
+ call feedkeys(":unabbr <buf\<C-A>\<C-B>\"\<CR>", 'tx')
+ call assert_equal('"unabbr <buffer>', @:)
+
call feedkeys(":abbr! \<C-A>\<C-B>\"\<CR>", 'tx')
- call assert_match("abbr! \x01", @:)
+ call assert_equal("\"abbr! \x01", @:)
+
+ " Multiple matches for a map
+ nmap ,f /H<CR>
+ omap ,f /H<CR>
+ call feedkeys(":map ,\<C-A>\<C-B>\"\<CR>", 'tx')
+ call assert_equal('"map ,f', @:)
+ mapclear
+endfunc
+
+" Test for <expr> in abbreviation
+func Test_expr_abbr()
+ new
+ iabbr <expr> teh "the"
+ call feedkeys("iteh ", "tx")
+ call assert_equal('the ', getline(1))
+ iabclear
+ call setline(1, '')
+
+ " invalid <expr> abbreviation
+ abbr <expr> hte GetAbbr()
+ call assert_fails('normal ihte ', 'E117:')
+ call assert_equal(' ', getline(1))
+ unabbr <expr> hte
+
+ close!
+endfunc
+
+" Test for storing mappings in different modes in a vimrc file
+func Test_mkvimrc_mapmodes()
+ map a1 /a1
+ nmap a2 /a2
+ vmap a3 /a3
+ smap a4 /a4
+ xmap a5 /a5
+ omap a6 /a6
+ map! a7 /a7
+ imap a8 /a8
+ lmap a9 /a9
+ cmap a10 /a10
+ tmap a11 /a11
+ " Normal + Visual map
+ map a12 /a12
+ sunmap a12
+ ounmap a12
+ " Normal + Selectmode map
+ map a13 /a13
+ xunmap a13
+ ounmap a13
+ " Normal + OpPending map
+ map a14 /a14
+ vunmap a14
+ " Visual + Selectmode map
+ map a15 /a15
+ nunmap a15
+ ounmap a15
+ " Visual + OpPending map
+ map a16 /a16
+ nunmap a16
+ sunmap a16
+ " Selectmode + OpPending map
+ map a17 /a17
+ nunmap a17
+ xunmap a17
+ " Normal + Visual + Selectmode map
+ map a18 /a18
+ ounmap a18
+ " Normal + Visual + OpPending map
+ map a19 /a19
+ sunmap a19
+ " Normal + Selectmode + OpPending map
+ map a20 /a20
+ xunmap a20
+ " Visual + Selectmode + OpPending map
+ map a21 /a21
+ nunmap a21
+ " Mapping to Nop
+ map a22 <Nop>
+ " Script local mapping
+ map <script> a23 /a23
+
+ " Newline in {lhs} and {rhs} of a map
+ exe "map a24\<C-V>\<C-J> ia24\<C-V>\<C-J><Esc>"
+
+ " Abbreviation
+ abbr a25 A25
+ cabbr a26 A26
+ iabbr a27 A27
+
+ mkvimrc! Xvimrc
+ let l = readfile('Xvimrc')
+ call assert_equal(['map a1 /a1'], filter(copy(l), 'v:val =~ " a1 "'))
+ call assert_equal(['nmap a2 /a2'], filter(copy(l), 'v:val =~ " a2 "'))
+ call assert_equal(['vmap a3 /a3'], filter(copy(l), 'v:val =~ " a3 "'))
+ call assert_equal(['smap a4 /a4'], filter(copy(l), 'v:val =~ " a4 "'))
+ call assert_equal(['xmap a5 /a5'], filter(copy(l), 'v:val =~ " a5 "'))
+ call assert_equal(['omap a6 /a6'], filter(copy(l), 'v:val =~ " a6 "'))
+ call assert_equal(['map! a7 /a7'], filter(copy(l), 'v:val =~ " a7 "'))
+ call assert_equal(['imap a8 /a8'], filter(copy(l), 'v:val =~ " a8 "'))
+ call assert_equal(['lmap a9 /a9'], filter(copy(l), 'v:val =~ " a9 "'))
+ call assert_equal(['cmap a10 /a10'], filter(copy(l), 'v:val =~ " a10 "'))
+ call assert_equal(['tmap a11 /a11'], filter(copy(l), 'v:val =~ " a11 "'))
+ call assert_equal(['nmap a12 /a12', 'xmap a12 /a12'],
+ \ filter(copy(l), 'v:val =~ " a12 "'))
+ call assert_equal(['nmap a13 /a13', 'smap a13 /a13'],
+ \ filter(copy(l), 'v:val =~ " a13 "'))
+ call assert_equal(['nmap a14 /a14', 'omap a14 /a14'],
+ \ filter(copy(l), 'v:val =~ " a14 "'))
+ call assert_equal(['vmap a15 /a15'], filter(copy(l), 'v:val =~ " a15 "'))
+ call assert_equal(['xmap a16 /a16', 'omap a16 /a16'],
+ \ filter(copy(l), 'v:val =~ " a16 "'))
+ call assert_equal(['smap a17 /a17', 'omap a17 /a17'],
+ \ filter(copy(l), 'v:val =~ " a17 "'))
+ call assert_equal(['nmap a18 /a18', 'vmap a18 /a18'],
+ \ filter(copy(l), 'v:val =~ " a18 "'))
+ call assert_equal(['nmap a19 /a19', 'xmap a19 /a19', 'omap a19 /a19'],
+ \ filter(copy(l), 'v:val =~ " a19 "'))
+ call assert_equal(['nmap a20 /a20', 'smap a20 /a20', 'omap a20 /a20'],
+ \ filter(copy(l), 'v:val =~ " a20 "'))
+ call assert_equal(['vmap a21 /a21', 'omap a21 /a21'],
+ \ filter(copy(l), 'v:val =~ " a21 "'))
+ call assert_equal(['map a22 <Nop>'], filter(copy(l), 'v:val =~ " a22 "'))
+ call assert_equal([], filter(copy(l), 'v:val =~ " a23 "'))
+ call assert_equal(["map a24<NL> ia24<NL>\x16\e"],
+ \ filter(copy(l), 'v:val =~ " a24"'))
+
+ call assert_equal(['abbr a25 A25'], filter(copy(l), 'v:val =~ " a25 "'))
+ call assert_equal(['cabbr a26 A26'], filter(copy(l), 'v:val =~ " a26 "'))
+ call assert_equal(['iabbr a27 A27'], filter(copy(l), 'v:val =~ " a27 "'))
+ call delete('Xvimrc')
+
+ mapclear
+ nmapclear
+ vmapclear
+ xmapclear
+ smapclear
+ omapclear
+ imapclear
+ lmapclear
+ cmapclear
+ tmapclear
+endfunc
+
+" Test for recursive mapping ('maxmapdepth')
+func Test_map_recursive()
+ map x y
+ map y x
+ call assert_fails('normal x', 'E223:')
+ unmap x
+ unmap y
+endfunc
+
+" Test for removing an abbreviation using {rhs} and with space after {lhs}
+func Test_abbr_remove()
+ abbr foo bar
+ let d = maparg('foo', 'i', 1, 1)
+ call assert_equal(['foo', 'bar', '!'], [d.lhs, d.rhs, d.mode])
+ unabbr bar
+ call assert_equal({}, maparg('foo', 'i', 1, 1))
+
+ abbr foo bar
+ unabbr foo<space><tab>
+ call assert_equal({}, maparg('foo', 'i', 1, 1))
endfunc
func Test_map_cmdkey_redo()
@@ -559,6 +956,16 @@ func Test_map_cmdkey_redo()
ounmap i-
endfunc
+" Test for using <script> with a map to remap characters in rhs
+func Test_script_local_remap()
+ new
+ inoremap <buffer> <SID>xyz mno
+ inoremap <buffer> <script> abc st<SID>xyzre
+ normal iabc
+ call assert_equal('stmnore', getline(1))
+ bwipe!
+endfunc
+
func Test_abbreviate_multi_byte()
new
iabbrev foo bar
@@ -568,4 +975,158 @@ func Test_abbreviate_multi_byte()
bwipe!
endfunc
+" Test for <Plug> always being mapped, even when used with "noremap".
+func Test_plug_remap()
+ let g:foo = 0
+ nnoremap <Plug>(Increase_x) <Cmd>let g:foo += 1<CR>
+ nmap <F2> <Plug>(Increase_x)
+ nnoremap <F3> <Plug>(Increase_x)
+ call feedkeys("\<F2>", 'xt')
+ call assert_equal(1, g:foo)
+ call feedkeys("\<F3>", 'xt')
+ call assert_equal(2, g:foo)
+ nnoremap x <Nop>
+ nmap <F4> x<Plug>(Increase_x)x
+ nnoremap <F5> x<Plug>(Increase_x)x
+ call setline(1, 'Some text')
+ normal! gg$
+ call feedkeys("\<F4>", 'xt')
+ call assert_equal(3, g:foo)
+ call assert_equal('Some text', getline(1))
+ call feedkeys("\<F5>", 'xt')
+ call assert_equal(4, g:foo)
+ call assert_equal('Some te', getline(1))
+ nunmap <Plug>(Increase_x)
+ nunmap <F2>
+ nunmap <F3>
+ nunmap <F4>
+ nunmap <F5>
+ unlet g:foo
+ %bw!
+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)
+ return "\<LeftMouse>"
+ endfunc
+ func DragExpr()
+ call test_setmouse(1, 2)
+ return "\<LeftDrag>"
+ endfunc
+ nnoremap <expr> <F2> ClickExpr()
+ nmap <expr> <F3> DragExpr()
+
+ nnoremap <LeftDrag> <LeftDrag><Cmd><CR>
+ exe "normal \<F2>\<F3>"
+ call assert_equal('s', mode())
+ exe "normal! \<C-\>\<C-N>"
+
+ nunmap <LeftDrag>
+ nunmap <F2>
+ nunmap <F3>
+ delfunc ClickExpr
+ delfunc DragExpr
+ set selectmode&
+ set 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)
+ return "\<LeftMouse>"
+ endfunc
+ func DragExpr()
+ call test_setmouse(1, 2)
+ return "\<LeftDrag>"
+ endfunc
+ inoremap <expr> <F2> ClickExpr()
+ imap <expr> <F3> DragExpr()
+
+ inoremap <LeftDrag> <LeftDrag><Cmd>let g:dragged = 1<CR>
+ exe "normal i\<F2>\<F3>"
+ call assert_equal(1, g:dragged)
+ call assert_equal('v', mode())
+ exe "normal! \<C-\>\<C-N>"
+ unlet g:dragged
+
+ inoremap <LeftDrag> <LeftDrag><C-\><C-N>
+ exe "normal i\<F2>\<F3>"
+ call assert_equal('n', mode())
+
+ iunmap <LeftDrag>
+ iunmap <F2>
+ iunmap <F3>
+ delfunc ClickExpr
+ delfunc DragExpr
+ set mouse&
+endfunc
+
+func Test_unmap_simplifiable()
+ map <C-I> foo
+ map <Tab> bar
+ call assert_equal('foo', maparg('<C-I>'))
+ call assert_equal('bar', maparg('<Tab>'))
+ unmap <C-I>
+ call assert_equal('', maparg('<C-I>'))
+ call assert_equal('bar', maparg('<Tab>'))
+ unmap <Tab>
+
+ map <C-I> foo
+ unmap <Tab>
+ " This should not error
+ unmap <C-I>
+endfunc
+
+func Test_expr_map_escape_special()
+ nnoremap … <Cmd>let g:got_ellipsis += 1<CR>
+ func Func()
+ return '…'
+ endfunc
+ nmap <expr> <F2> Func()
+ let g:got_ellipsis = 0
+ call feedkeys("\<F2>", 'xt')
+ call assert_equal(1, g:got_ellipsis)
+ delfunc Func
+ nunmap <F2>
+ unlet g:got_ellipsis
+ nunmap …
+endfunc
+
+" Testing for mapping after an <Nop> mapping is triggered on timeout.
+" Test for what patch 8.1.0052 fixes.
+func Test_map_after_timed_out_nop()
+ CheckRunVimInTerminal
+
+ let lines =<< trim END
+ set timeout timeoutlen=400
+ inoremap ab TEST
+ inoremap a <Nop>
+ END
+ call writefile(lines, 'Xtest_map_after_timed_out_nop')
+ let buf = RunVimInTerminal('-S Xtest_map_after_timed_out_nop', #{rows: 6})
+
+ " Enter Insert mode
+ call term_sendkeys(buf, 'i')
+ " Wait for the "a" mapping to timeout
+ call term_sendkeys(buf, 'a')
+ call term_wait(buf, 500)
+ " Send "a" and wait for a period shorter than 'timeoutlen'
+ call term_sendkeys(buf, 'a')
+ call term_wait(buf, 100)
+ " Send "b", should trigger the "ab" mapping
+ call term_sendkeys(buf, 'b')
+ call WaitForAssert({-> assert_equal("TEST", term_getline(buf, 1))})
+
+ " clean up
+ call StopVimInTerminal(buf)
+ call delete('Xtest_map_after_timed_out_nop')
+endfunc
+
" vim: shiftwidth=2 sts=2 expandtab
diff --git a/src/nvim/testdir/test_marks.vim b/src/nvim/testdir/test_marks.vim
index b3035d73ce..74e63d9d69 100644
--- a/src/nvim/testdir/test_marks.vim
+++ b/src/nvim/testdir/test_marks.vim
@@ -1,6 +1,6 @@
" Test that a deleted mark is restored after delete-undo-redo-undo.
-function! Test_Restore_DelMark()
+func Test_Restore_DelMark()
enew!
call append(0, [" textline A", " textline B", " textline C"])
normal! 2gg
@@ -11,10 +11,10 @@ function! Test_Restore_DelMark()
call assert_equal(2, pos[1])
call assert_equal(1, pos[2])
enew!
-endfunction
+endfunc
" Test that CTRL-A and CTRL-X updates last changed mark '[, '].
-function! Test_Incr_Marks()
+func Test_Incr_Marks()
enew!
call append(0, ["123 123 123", "123 123 123", "123 123 123"])
normal! gg
@@ -23,7 +23,17 @@ function! Test_Incr_Marks()
call assert_equal("123 XXXXXXX", getline(2))
call assert_equal("XXX 123 123", getline(3))
enew!
-endfunction
+endfunc
+
+func Test_previous_jump_mark()
+ new
+ call setline(1, ['']->repeat(6))
+ normal Ggg
+ call assert_equal(6, getpos("''")[1])
+ normal jjjjj
+ call assert_equal(6, getpos("''")[1])
+ bwipe!
+endfunc
func Test_setpos()
new Xone
@@ -205,6 +215,57 @@ func Test_mark_error()
call assert_fails('mark', 'E471:')
call assert_fails('mark xx', 'E488:')
call assert_fails('mark _', 'E191:')
+ call assert_beeps('normal! m~')
+
+ call setpos("'k", [0, 100, 1, 0])
+ call assert_fails("normal 'k", 'E19:')
+endfunc
+
+" Test for :lockmarks when pasting content
+func Test_lockmarks_with_put()
+ new
+ call append(0, repeat(['sky is blue'], 4))
+ normal gg
+ 1,2yank r
+ put r
+ normal G
+ lockmarks put r
+ call assert_equal(2, line("'["))
+ call assert_equal(3, line("']"))
+
+ bwipe!
+endfunc
+
+" Test for :k command to set a mark
+func Test_marks_k_cmd()
+ new
+ call setline(1, ['foo', 'bar', 'baz', 'qux'])
+ 1,3kr
+ call assert_equal([0, 3, 1, 0], getpos("'r"))
+ close!
+endfunc
+
+" Test for file marks (A-Z)
+func Test_file_mark()
+ new Xone
+ call setline(1, ['aaa', 'bbb'])
+ norm! G$mB
+ w!
+ new Xtwo
+ call setline(1, ['ccc', 'ddd'])
+ norm! GmD
+ w!
+
+ enew
+ normal! `B
+ call assert_equal('Xone', bufname())
+ call assert_equal([2, 3], [line('.'), col('.')])
+ normal! 'D
+ call assert_equal('Xtwo', bufname())
+ call assert_equal([2, 1], [line('.'), col('.')])
+
+ call delete('Xone')
+ call delete('Xtwo')
endfunc
" Test for the getmarklist() function
@@ -231,3 +292,5 @@ func Test_getmarklist()
call assert_equal([], {}->getmarklist())
close!
endfunc
+
+" vim: shiftwidth=2 sts=2 expandtab
diff --git a/src/nvim/testdir/test_matchadd_conceal.vim b/src/nvim/testdir/test_matchadd_conceal.vim
index 2cbaf5cb76..1b5fc8313f 100644
--- a/src/nvim/testdir/test_matchadd_conceal.vim
+++ b/src/nvim/testdir/test_matchadd_conceal.vim
@@ -7,7 +7,7 @@ source shared.vim
source term_util.vim
source view_util.vim
-function! Test_simple_matchadd()
+func Test_simple_matchadd()
new
1put='# This is a Test'
@@ -333,7 +333,26 @@ func Test_matchadd_and_syn_conceal()
call assert_notequal(screenattr(1, 10) , screenattr(1, 11))
call assert_notequal(screenattr(1, 11) , screenattr(1, 12))
call assert_equal(screenattr(1, 11) , screenattr(1, 32))
-endfunction
+endfunc
+
+func Test_interaction_matchadd_syntax()
+ new
+ " Test for issue #7268 fix.
+ " When redrawing the second column, win_line() was comparing the sequence
+ " number of the syntax-concealed region with a bogus zero value that was
+ " returned for the matchadd-concealed region. Before 8.0.0672 the sequence
+ " number was never reset, thus masking the problem.
+ call setline(1, 'aaa|bbb|ccc')
+ call matchadd('Conceal', '^..', 10, -1, #{conceal: 'X'})
+ syn match foobar '^.'
+ setl concealcursor=n conceallevel=1
+ redraw!
+
+ call assert_equal('Xa|bbb|ccc', Screenline(1))
+ call assert_notequal(screenattr(1, 1), screenattr(1, 2))
+
+ bwipe!
+endfunc
func Test_cursor_column_in_concealed_line_after_window_scroll()
CheckRunVimInTerminal
diff --git a/src/nvim/testdir/test_matchadd_conceal_utf8.vim b/src/nvim/testdir/test_matchadd_conceal_utf8.vim
index 7bfac13ad8..f33c7f694c 100644
--- a/src/nvim/testdir/test_matchadd_conceal_utf8.vim
+++ b/src/nvim/testdir/test_matchadd_conceal_utf8.vim
@@ -1,21 +1,21 @@
" Test for matchadd() and conceal feature using utf-8.
-if !has('conceal')
- finish
-endif
-function! s:screenline(lnum) abort
+source check.vim
+CheckFeature conceal
+
+func s:screenline(lnum) abort
let line = []
for c in range(1, winwidth(0))
call add(line, nr2char(a:lnum->screenchar(c)))
endfor
return s:trim(join(line, ''))
-endfunction
+endfunc
-function! s:trim(str) abort
+func s:trim(str) abort
return matchstr(a:str,'^\s*\zs.\{-}\ze\s*$')
-endfunction
+endfunc
-function! Test_match_using_multibyte_conceal_char()
+func Test_match_using_multibyte_conceal_char()
new
setlocal concealcursor=n conceallevel=1
diff --git a/src/nvim/testdir/test_matchfuzzy.vim b/src/nvim/testdir/test_matchfuzzy.vim
new file mode 100644
index 0000000000..c836bc87aa
--- /dev/null
+++ b/src/nvim/testdir/test_matchfuzzy.vim
@@ -0,0 +1,271 @@
+" Tests for fuzzy matching
+
+source shared.vim
+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("let x = matchfuzzy(v:_null_list, 'foo')", 'E686:')
+ call assert_fails('call matchfuzzy(["abc"], v:_null_string)', 'E475:')
+ call assert_equal([], matchfuzzy([], 'abc'))
+ call assert_equal([], matchfuzzy(['abc'], ''))
+ call assert_equal(['abc'], matchfuzzy(['abc', 10], 'ac'))
+ call assert_equal([], matchfuzzy([10, 20], 'ac'))
+ call assert_equal(['abc'], matchfuzzy(['abc'], 'abc'))
+ call assert_equal(['crayon', 'camera'], matchfuzzy(['camera', 'crayon'], 'cra'))
+ call assert_equal(['aabbaa', 'aaabbbaaa', 'aaaabbbbaaaa', 'aba'], matchfuzzy(['aba', 'aabbaa', 'aaabbbaaa', 'aaaabbbbaaaa'], 'aa'))
+ call assert_equal(['one'], matchfuzzy(['one', 'two'], 'one'))
+ call assert_equal(['oneTwo', 'onetwo'], matchfuzzy(['onetwo', 'oneTwo'], 'oneTwo'))
+ call assert_equal(['onetwo', 'one_two'], matchfuzzy(['onetwo', 'one_two'], 'oneTwo'))
+ call assert_equal(['aaaaaaaaaaaaaaaaaaaaaaaaaaaaaa'], matchfuzzy(['aaaaaaaaaaaaaaaaaaaaaaaaaaaaaa'], 'aa'))
+ call assert_equal(256, matchfuzzy([repeat('a', 256)], repeat('a', 256))[0]->len())
+ call assert_equal([], matchfuzzy([repeat('a', 300)], repeat('a', 257)))
+ " matches with same score should not be reordered
+ let l = ['abc1', 'abc2', 'abc3']
+ call assert_equal(l, l->matchfuzzy('abc'))
+
+ " Tests for match preferences
+ " preference for camel case match
+ call assert_equal(['oneTwo', 'onetwo'], ['onetwo', 'oneTwo']->matchfuzzy('onetwo'))
+ " preference for match after a separator (_ or space)
+ call assert_equal(['onetwo', 'one_two', 'one two'], ['onetwo', 'one_two', 'one two']->matchfuzzy('onetwo'))
+ " preference for leading letter match
+ call assert_equal(['onetwo', 'xonetwo'], ['xonetwo', 'onetwo']->matchfuzzy('onetwo'))
+ " preference for sequential match
+ call assert_equal(['onetwo', 'oanbectdweo'], ['oanbectdweo', 'onetwo']->matchfuzzy('onetwo'))
+ " non-matching leading letter(s) penalty
+ call assert_equal(['xonetwo', 'xxonetwo'], ['xxonetwo', 'xonetwo']->matchfuzzy('onetwo'))
+ " total non-matching letter(s) penalty
+ call assert_equal(['one', 'onex', 'onexx'], ['onexx', 'one', 'onex']->matchfuzzy('one'))
+ " prefer complete matches over separator matches
+ call assert_equal(['.vim/vimrc', '.vim/vimrc_colors', '.vim/v_i_m_r_c'], ['.vim/vimrc', '.vim/vimrc_colors', '.vim/v_i_m_r_c']->matchfuzzy('vimrc'))
+ " gap penalty
+ call assert_equal(['xxayybxxxx', 'xxayyybxxx', 'xxayyyybxx'], ['xxayyyybxx', 'xxayyybxxx', 'xxayybxxxx']->matchfuzzy('ab'))
+ " path separator vs word separator
+ call assert_equal(['color/setup.vim', 'color\\setup.vim', 'color setup.vim', 'color_setup.vim', 'colorsetup.vim'], matchfuzzy(['colorsetup.vim', 'color setup.vim', 'color/setup.vim', 'color_setup.vim', 'color\\setup.vim'], 'setup.vim'))
+
+ " match multiple words (separated by space)
+ call assert_equal(['foo bar baz'], ['foo bar baz', 'foo', 'foo bar', 'baz bar']->matchfuzzy('baz foo'))
+ call assert_equal([], ['foo bar baz', 'foo', 'foo bar', 'baz bar']->matchfuzzy('one two'))
+ call assert_equal([], ['foo bar']->matchfuzzy(" \t "))
+
+ " test for matching a sequence of words
+ call assert_equal(['bar foo'], ['foo bar', 'bar foo', 'foobar', 'barfoo']->matchfuzzy('bar foo', {'matchseq' : 1}))
+ call assert_equal([#{text: 'two one'}], [#{text: 'one two'}, #{text: 'two one'}]->matchfuzzy('two one', #{key: 'text', matchseq: v:true}))
+
+ %bw!
+ eval ['somebuf', 'anotherone', 'needle', 'yetanotherone']->map({_, v -> bufadd(v) + bufload(v)})
+ let l = getbufinfo()->map({_, v -> fnamemodify(v.name, ':t')})->matchfuzzy('ndl')
+ call assert_equal(1, len(l))
+ call assert_match('needle', l[0])
+
+ " Test for fuzzy matching dicts
+ let l = [{'id' : 5, 'val' : 'crayon'}, {'id' : 6, 'val' : 'camera'}]
+ call assert_equal([{'id' : 6, 'val' : 'camera'}], matchfuzzy(l, 'cam', {'text_cb' : {v -> v.val}}))
+ call assert_equal([{'id' : 6, 'val' : 'camera'}], matchfuzzy(l, 'cam', {'key' : 'val'}))
+ call assert_equal([], matchfuzzy(l, 'day', {'text_cb' : {v -> v.val}}))
+ call assert_equal([], matchfuzzy(l, 'day', {'key' : 'val'}))
+ call assert_fails("let x = matchfuzzy(l, 'cam', 'random')", 'E715:')
+ call assert_equal([], matchfuzzy(l, 'day', {'text_cb' : {v -> []}}))
+ call assert_equal([], matchfuzzy(l, 'day', {'text_cb' : {v -> 1}}))
+ 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', v:_null_dict)", 'E715:')
+ call assert_fails("let x = matchfuzzy(l, 'foo', {'key' : v:_null_string})", 'E475:')
+ " Nvim doesn't have null functions
+ " call assert_fails("let x = matchfuzzy(l, 'foo', {'text_cb' : test_null_function()})", 'E475:')
+ " matches with same score should not be reordered
+ let l = [#{text: 'abc', id: 1}, #{text: 'abc', id: 2}, #{text: 'abc', id: 3}]
+ call assert_equal(l, l->matchfuzzy('abc', #{key: 'text'}))
+
+ let l = [{'id' : 5, 'name' : 'foo'}, {'id' : 6, 'name' : []}, {'id' : 7}]
+ call assert_fails("let x = matchfuzzy(l, 'foo', {'key' : 'name'})", 'E730:')
+
+ " Test in latin1 encoding
+ let save_enc = &encoding
+ " Nvim supports utf-8 encoding only
+ " set encoding=latin1
+ call assert_equal(['abc'], matchfuzzy(['abc'], 'abc'))
+ let &encoding = save_enc
+endfunc
+
+" Test for the matchfuzzypos() function
+func Test_matchfuzzypos()
+ call assert_equal([['curl', 'world'], [[2,3], [2,3]], [128, 127]], matchfuzzypos(['world', 'curl'], 'rl'))
+ call assert_equal([['curl', 'world'], [[2,3], [2,3]], [128, 127]], matchfuzzypos(['world', 'one', 'curl'], 'rl'))
+ call assert_equal([['hello', 'hello world hello world'],
+ \ [[0, 1, 2, 3, 4], [0, 1, 2, 3, 4]], [275, 257]],
+ \ matchfuzzypos(['hello world hello world', 'hello', 'world'], 'hello'))
+ call assert_equal([['aaaaaaa'], [[0, 1, 2]], [191]], matchfuzzypos(['aaaaaaa'], 'aaa'))
+ call assert_equal([['a b'], [[0, 3]], [219]], matchfuzzypos(['a b'], 'a b'))
+ call assert_equal([['a b'], [[0, 3]], [219]], matchfuzzypos(['a b'], 'a b'))
+ call assert_equal([['a b'], [[0]], [112]], matchfuzzypos(['a b'], ' a '))
+ call assert_equal([[], [], []], matchfuzzypos(['a b'], ' '))
+ call assert_equal([[], [], []], matchfuzzypos(['world', 'curl'], 'ab'))
+ let x = matchfuzzypos([repeat('a', 256)], repeat('a', 256))
+ call assert_equal(range(256), x[1][0])
+ call assert_equal([[], [], []], matchfuzzypos([repeat('a', 300)], repeat('a', 257)))
+ call assert_equal([[], [], []], matchfuzzypos([], 'abc'))
+
+ " match in a long string
+ call assert_equal([[repeat('x', 300) .. 'abc'], [[300, 301, 302]], [-135]],
+ \ matchfuzzypos([repeat('x', 300) .. 'abc'], 'abc'))
+
+ " preference for camel case match
+ call assert_equal([['xabcxxaBc'], [[6, 7, 8]], [189]], matchfuzzypos(['xabcxxaBc'], 'abc'))
+ " preference for match after a separator (_ or space)
+ call assert_equal([['xabx_ab'], [[5, 6]], [145]], matchfuzzypos(['xabx_ab'], 'ab'))
+ " preference for leading letter match
+ call assert_equal([['abcxabc'], [[0, 1]], [150]], matchfuzzypos(['abcxabc'], 'ab'))
+ " preference for sequential match
+ call assert_equal([['aobncedone'], [[7, 8, 9]], [158]], matchfuzzypos(['aobncedone'], 'one'))
+ " best recursive match
+ call assert_equal([['xoone'], [[2, 3, 4]], [168]], matchfuzzypos(['xoone'], 'one'))
+
+ " match multiple words (separated by space)
+ call assert_equal([['foo bar baz'], [[8, 9, 10, 0, 1, 2]], [369]], ['foo bar baz', 'foo', 'foo bar', 'baz bar']->matchfuzzypos('baz foo'))
+ call assert_equal([[], [], []], ['foo bar baz', 'foo', 'foo bar', 'baz bar']->matchfuzzypos('baz foo', {'matchseq': 1}))
+ call assert_equal([['foo bar baz'], [[0, 1, 2, 8, 9, 10]], [369]], ['foo bar baz', 'foo', 'foo bar', 'baz bar']->matchfuzzypos('foo baz'))
+ call assert_equal([['foo bar baz'], [[0, 1, 2, 3, 4, 5, 10]], [326]], ['foo bar baz', 'foo', 'foo bar', 'baz bar']->matchfuzzypos('foo baz', {'matchseq': 1}))
+ call assert_equal([[], [], []], ['foo bar baz', 'foo', 'foo bar', 'baz bar']->matchfuzzypos('one two'))
+ call assert_equal([[], [], []], ['foo bar']->matchfuzzypos(" \t "))
+ call assert_equal([['grace'], [[1, 2, 3, 4, 2, 3, 4, 0, 1, 2, 3, 4]], [657]], ['grace']->matchfuzzypos('race ace grace'))
+
+ let l = [{'id' : 5, 'val' : 'crayon'}, {'id' : 6, 'val' : 'camera'}]
+ call assert_equal([[{'id' : 6, 'val' : 'camera'}], [[0, 1, 2]], [192]],
+ \ matchfuzzypos(l, 'cam', {'text_cb' : {v -> v.val}}))
+ call assert_equal([[{'id' : 6, 'val' : 'camera'}], [[0, 1, 2]], [192]],
+ \ matchfuzzypos(l, 'cam', {'key' : 'val'}))
+ call assert_equal([[], [], []], matchfuzzypos(l, 'day', {'text_cb' : {v -> v.val}}))
+ call assert_equal([[], [], []], matchfuzzypos(l, 'day', {'key' : 'val'}))
+ call assert_fails("let x = matchfuzzypos(l, 'cam', 'random')", 'E715:')
+ call assert_equal([[], [], []], matchfuzzypos(l, 'day', {'text_cb' : {v -> []}}))
+ call assert_equal([[], [], []], matchfuzzypos(l, 'day', {'text_cb' : {v -> 1}}))
+ 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', v:_null_dict)", 'E715:')
+ call assert_fails("let x = matchfuzzypos(l, 'foo', {'key' : v:_null_string})", 'E475:')
+ " Nvim doesn't have null functions
+ " call assert_fails("let x = matchfuzzypos(l, 'foo', {'text_cb' : test_null_function()})", 'E475:')
+
+ let l = [{'id' : 5, 'name' : 'foo'}, {'id' : 6, 'name' : []}, {'id' : 7}]
+ call assert_fails("let x = matchfuzzypos(l, 'foo', {'key' : 'name'})", 'E730:')
+endfunc
+
+" Test for matchfuzzy() with multibyte characters
+func Test_matchfuzzy_mbyte()
+ CheckFeature multi_lang
+ call assert_equal(['ンヹㄇヺヴ'], matchfuzzy(['ンヹㄇヺヴ'], 'ヹヺ'))
+ " reverse the order of characters
+ call assert_equal([], matchfuzzy(['ンヹㄇヺヴ'], 'ヺヹ'))
+ call assert_equal(['αβΩxxx', 'xαxβxΩx'],
+ \ matchfuzzy(['αβΩxxx', 'xαxβxΩx'], 'αβΩ'))
+ call assert_equal(['ππbbππ', 'πππbbbπππ', 'ππππbbbbππππ', 'πbπ'],
+ \ matchfuzzy(['πbπ', 'ππbbππ', 'πππbbbπππ', 'ππππbbbbππππ'], 'ππ'))
+
+ " match multiple words (separated by space)
+ call assert_equal(['세 마리의 작은 돼지'], ['세 마리의 작은 돼지', '마리의', '마리의 작은', '작은 돼지']->matchfuzzy('돼지 마리의'))
+ call assert_equal([], ['세 마리의 작은 돼지', '마리의', '마리의 작은', '작은 돼지']->matchfuzzy('파란 하늘'))
+
+ " preference for camel case match
+ call assert_equal(['oneĄwo', 'oneąwo'],
+ \ ['oneąwo', 'oneĄwo']->matchfuzzy('oneąwo'))
+ " preference for complete match then match after separator (_ or space)
+ call assert_equal(['ⅠⅡabㄟㄠ'] + sort(['ⅠⅡa_bㄟㄠ', 'ⅠⅡa bㄟㄠ']),
+ \ ['ⅠⅡabㄟㄠ', 'ⅠⅡa bㄟㄠ', 'ⅠⅡa_bㄟㄠ']->matchfuzzy('ⅠⅡabㄟㄠ'))
+ " preference for match after a separator (_ or space)
+ call assert_equal(['ㄓㄔabㄟㄠ', 'ㄓㄔa_bㄟㄠ', 'ㄓㄔa bㄟㄠ'],
+ \ ['ㄓㄔa_bㄟㄠ', 'ㄓㄔa bㄟㄠ', 'ㄓㄔabㄟㄠ']->matchfuzzy('ㄓㄔabㄟㄠ'))
+ " preference for leading letter match
+ call assert_equal(['ŗŝţũŵż', 'xŗŝţũŵż'],
+ \ ['xŗŝţũŵż', 'ŗŝţũŵż']->matchfuzzy('ŗŝţũŵż'))
+ " preference for sequential match
+ call assert_equal(['ㄞㄡㄤfffifl', 'ㄞaㄡbㄤcffdfiefl'],
+ \ ['ㄞaㄡbㄤcffdfiefl', 'ㄞㄡㄤfffifl']->matchfuzzy('ㄞㄡㄤfffifl'))
+ " non-matching leading letter(s) penalty
+ call assert_equal(['xㄞㄡㄤfffifl', 'xxㄞㄡㄤfffifl'],
+ \ ['xxㄞㄡㄤfffifl', 'xㄞㄡㄤfffifl']->matchfuzzy('ㄞㄡㄤfffifl'))
+ " total non-matching letter(s) penalty
+ call assert_equal(['ŗŝţ', 'ŗŝţx', 'ŗŝţxx'],
+ \ ['ŗŝţxx', 'ŗŝţ', 'ŗŝţx']->matchfuzzy('ŗŝţ'))
+endfunc
+
+" Test for matchfuzzypos() with multibyte characters
+func Test_matchfuzzypos_mbyte()
+ CheckFeature multi_lang
+ call assert_equal([['こんにちは世界'], [[0, 1, 2, 3, 4]], [273]],
+ \ matchfuzzypos(['こんにちは世界'], 'こんにちは'))
+ call assert_equal([['ンヹㄇヺヴ'], [[1, 3]], [88]], matchfuzzypos(['ンヹㄇヺヴ'], 'ヹヺ'))
+ " reverse the order of characters
+ call assert_equal([[], [], []], matchfuzzypos(['ンヹㄇヺヴ'], 'ヺヹ'))
+ call assert_equal([['αβΩxxx', 'xαxβxΩx'], [[0, 1, 2], [1, 3, 5]], [222, 113]],
+ \ matchfuzzypos(['αβΩxxx', 'xαxβxΩx'], 'αβΩ'))
+ call assert_equal([['ππbbππ', 'πππbbbπππ', 'ππππbbbbππππ', 'πbπ'],
+ \ [[0, 1], [0, 1], [0, 1], [0, 2]], [151, 148, 145, 110]],
+ \ matchfuzzypos(['πbπ', 'ππbbππ', 'πππbbbπππ', 'ππππbbbbππππ'], 'ππ'))
+ call assert_equal([['ααααααα'], [[0, 1, 2]], [191]],
+ \ matchfuzzypos(['ααααααα'], 'ααα'))
+
+ call assert_equal([[], [], []], matchfuzzypos(['ンヹㄇ', 'ŗŝţ'], 'fffifl'))
+ let x = matchfuzzypos([repeat('Ψ', 256)], repeat('Ψ', 256))
+ call assert_equal(range(256), x[1][0])
+ call assert_equal([[], [], []], matchfuzzypos([repeat('✓', 300)], repeat('✓', 257)))
+
+ " match multiple words (separated by space)
+ call assert_equal([['세 마리의 작은 돼지'], [[9, 10, 2, 3, 4]], [328]], ['세 마리의 작은 돼지', '마리의', '마리의 작은', '작은 돼지']->matchfuzzypos('돼지 마리의'))
+ call assert_equal([[], [], []], ['세 마리의 작은 돼지', '마리의', '마리의 작은', '작은 돼지']->matchfuzzypos('파란 하늘'))
+
+ " match in a long string
+ call assert_equal([[repeat('ぶ', 300) .. 'ẼẼẼ'], [[300, 301, 302]], [-135]],
+ \ matchfuzzypos([repeat('ぶ', 300) .. 'ẼẼẼ'], 'ẼẼẼ'))
+ " preference for camel case match
+ call assert_equal([['xѳѵҁxxѳѴҁ'], [[6, 7, 8]], [189]], matchfuzzypos(['xѳѵҁxxѳѴҁ'], 'ѳѵҁ'))
+ " preference for match after a separator (_ or space)
+ call assert_equal([['xちだx_ちだ'], [[5, 6]], [145]], matchfuzzypos(['xちだx_ちだ'], 'ちだ'))
+ " preference for leading letter match
+ call assert_equal([['ѳѵҁxѳѵҁ'], [[0, 1]], [150]], matchfuzzypos(['ѳѵҁxѳѵҁ'], 'ѳѵ'))
+ " preference for sequential match
+ call assert_equal([['aンbヹcㄇdンヹㄇ'], [[7, 8, 9]], [158]], matchfuzzypos(['aンbヹcㄇdンヹㄇ'], 'ンヹㄇ'))
+ " best recursive match
+ call assert_equal([['xффйд'], [[2, 3, 4]], [168]], matchfuzzypos(['xффйд'], 'фйд'))
+endfunc
+
+" Test for matchfuzzy() with limit
+func Test_matchfuzzy_limit()
+ let x = ['1', '2', '3', '2']
+ call assert_equal(['2', '2'], x->matchfuzzy('2'))
+ call assert_equal(['2', '2'], x->matchfuzzy('2', #{}))
+ call assert_equal(['2', '2'], x->matchfuzzy('2', #{limit: 0}))
+ call assert_equal(['2'], x->matchfuzzy('2', #{limit: 1}))
+ call assert_equal(['2', '2'], x->matchfuzzy('2', #{limit: 2}))
+ call assert_equal(['2', '2'], x->matchfuzzy('2', #{limit: 3}))
+ call assert_fails("call matchfuzzy(x, '2', #{limit: '2'})", 'E475:')
+
+ let l = [{'id': 5, 'val': 'crayon'}, {'id': 6, 'val': 'camera'}]
+ call assert_equal([{'id': 5, 'val': 'crayon'}, {'id': 6, 'val': 'camera'}], l->matchfuzzy('c', #{text_cb: {v -> v.val}}))
+ call assert_equal([{'id': 5, 'val': 'crayon'}, {'id': 6, 'val': 'camera'}], l->matchfuzzy('c', #{key: 'val'}))
+ call assert_equal([{'id': 5, 'val': 'crayon'}, {'id': 6, 'val': 'camera'}], l->matchfuzzy('c', #{text_cb: {v -> v.val}, limit: 0}))
+ call assert_equal([{'id': 5, 'val': 'crayon'}, {'id': 6, 'val': 'camera'}], l->matchfuzzy('c', #{key: 'val', limit: 0}))
+ call assert_equal([{'id': 5, 'val': 'crayon'}], l->matchfuzzy('c', #{text_cb: {v -> v.val}, limit: 1}))
+ call assert_equal([{'id': 5, 'val': 'crayon'}], l->matchfuzzy('c', #{key: 'val', limit: 1}))
+endfunc
+
+" vim: shiftwidth=2 sts=2 expandtab
diff --git a/src/nvim/testdir/test_menu.vim b/src/nvim/testdir/test_menu.vim
index de6d4aa359..4af75be514 100644
--- a/src/nvim/testdir/test_menu.vim
+++ b/src/nvim/testdir/test_menu.vim
@@ -1,8 +1,7 @@
" Test that the system menu can be loaded.
-if !has('menu')
- finish
-endif
+source check.vim
+CheckFeature menu
func Test_load_menu()
try
@@ -36,3 +35,92 @@ func Test_translate_menu()
source $VIMRUNTIME/delmenu.vim
endfunc
+
+func Test_menu_commands()
+ nmenu 2 Test.FooBar :let g:did_menu = 'normal'<CR>
+ vmenu 2 Test.FooBar :let g:did_menu = 'visual'<CR>
+ smenu 2 Test.FooBar :let g:did_menu = 'select'<CR>
+ omenu 2 Test.FooBar :let g:did_menu = 'op-pending'<CR>
+ tlmenu 2 Test.FooBar :let g:did_menu = 'terminal'<CR>
+ imenu 2 Test.FooBar :let g:did_menu = 'insert'<CR>
+ cmenu 2 Test.FooBar :let g:did_menu = 'cmdline'<CR>
+ emenu n Test.FooBar
+
+ call feedkeys(":menu Test.FooB\<C-A>\<C-B>\"\<CR>", 'tx')
+ call assert_equal('"menu Test.FooBar', @:)
+
+ call assert_equal('normal', g:did_menu)
+ emenu v Test.FooBar
+ call assert_equal('visual', g:did_menu)
+ emenu s Test.FooBar
+ call assert_equal('select', g:did_menu)
+ emenu o Test.FooBar
+ call assert_equal('op-pending', g:did_menu)
+ emenu t Test.FooBar
+ call assert_equal('terminal', g:did_menu)
+ emenu i Test.FooBar
+ call assert_equal('insert', g:did_menu)
+ emenu c Test.FooBar
+ call assert_equal('cmdline', g:did_menu)
+
+ nunmenu Test.FooBar
+ call assert_fails('emenu n Test.FooBar', 'E335: Menu not defined for Normal mode')
+ vunmenu Test.FooBar
+ call assert_fails('emenu v Test.FooBar', 'E335: Menu not defined for Visual mode')
+ vmenu 2 Test.FooBar :let g:did_menu = 'visual'<CR>
+ sunmenu Test.FooBar
+ call assert_fails('emenu s Test.FooBar', 'E335: Menu not defined for Select mode')
+ ounmenu Test.FooBar
+ call assert_fails('emenu o Test.FooBar', 'E335: Menu not defined for Op-pending mode')
+ iunmenu Test.FooBar
+ call assert_fails('emenu i Test.FooBar', 'E335: Menu not defined for Insert mode')
+ cunmenu Test.FooBar
+ call assert_fails('emenu c Test.FooBar', 'E335: Menu not defined for Cmdline mode')
+ tlunmenu Test.FooBar
+ call assert_fails('emenu t Test.FooBar', 'E335: Menu not defined for Terminal mode')
+
+ aunmenu Test.FooBar
+ call assert_fails('emenu n Test.FooBar', 'E334:')
+
+ nmenu 2 Test.FooBar.Child :let g:did_menu = 'foobar'<CR>
+ call assert_fails('emenu n Test.FooBar', 'E333:')
+ nunmenu Test.FooBar.Child
+
+ unlet g:did_menu
+endfun
+
+" Test for menu item completion in command line
+func Test_menu_expand()
+ " Create the menu itmes for test
+ for i in range(1, 4)
+ let m = 'menu Xmenu.A' .. i .. '.A' .. i
+ for j in range(1, 4)
+ exe m .. 'B' .. j .. ' :echo "A' .. i .. 'B' .. j .. '"' .. "<CR>"
+ endfor
+ endfor
+ set wildmenu
+
+ " Test for <CR> selecting a submenu
+ call feedkeys(":emenu Xmenu.A\<Tab>\<CR>\<Right>x\<BS>\<C-B>\"\<CR>", 'xt')
+ call assert_equal('"emenu Xmenu.A1.A1B2', @:)
+
+ " Test for <Down> selecting a submenu
+ call feedkeys(":emenu Xmenu.A\<Tab>\<Right>\<Right>\<Down>" ..
+ \ "\<C-A>\<C-B>\"\<CR>", 'xt')
+ call assert_equal('"emenu Xmenu.A3.A3B1 A3B2 A3B3 A3B4', @:)
+
+ " Test for <Up> to go up a submenu
+ call feedkeys(":emenu Xmenu.A\<Tab>\<Down>\<Up>\<Right>\<Right>" ..
+ \ "\<Left>\<Down>\<C-A>\<C-B>\"\<CR>", 'xt')
+ call assert_equal('"emenu Xmenu.A2.A2B1 A2B2 A2B3 A2B4', @:)
+
+ " Test for <Up> to go up a menu
+ call feedkeys(":emenu Xmenu.A\<Tab>\<Down>\<Up>\<Up>\<Up>" ..
+ \ "\<C-A>\<C-B>\"\<CR>", 'xt')
+ call assert_equal('"emenu Buffers. Xmenu.', @:)
+
+ set wildmenu&
+ unmenu Xmenu
+endfunc
+
+" vim: shiftwidth=2 sts=2 expandtab
diff --git a/src/nvim/testdir/test_messages.vim b/src/nvim/testdir/test_messages.vim
index e0286548d9..5670368936 100644
--- a/src/nvim/testdir/test_messages.vim
+++ b/src/nvim/testdir/test_messages.vim
@@ -2,6 +2,9 @@
source check.vim
source shared.vim
+source term_util.vim
+source view_util.vim
+source screendump.vim
func Test_messages()
let oldmore = &more
@@ -40,7 +43,7 @@ endfunc
" indicator (e.g., "-- INSERT --") when ":stopinsert" is invoked. Message
" output could then be disturbed when 'cmdheight' was greater than one.
" This test ensures that the bugfix for this issue remains in place.
-function! Test_stopinsert_does_not_break_message_output()
+func Test_stopinsert_does_not_break_message_output()
set cmdheight=2
redraw!
@@ -55,7 +58,7 @@ function! Test_stopinsert_does_not_break_message_output()
redraw!
set cmdheight&
-endfunction
+endfunc
func Test_message_completion()
call feedkeys(":message \<C-A>\<C-B>\"\<CR>", 'tx')
@@ -109,6 +112,160 @@ func Test_echospace()
set ruler& showcmd&
endfunc
+" Test more-prompt (see :help more-prompt).
+func Test_message_more()
+ CheckRunVimInTerminal
+ let buf = RunVimInTerminal('', {'rows': 6})
+ call term_sendkeys(buf, ":call setline(1, range(1, 100))\n")
+
+ call term_sendkeys(buf, ":%p#\n")
+ call WaitForAssert({-> assert_equal(' 5 5', term_getline(buf, 5))})
+ call WaitForAssert({-> assert_equal('-- More --', term_getline(buf, 6))})
+
+ call term_sendkeys(buf, '?')
+ call WaitForAssert({-> assert_equal(' 5 5', term_getline(buf, 5))})
+ call WaitForAssert({-> assert_equal('-- More -- SPACE/d/j: screen/page/line down, b/u/k: up, q: quit ', term_getline(buf, 6))})
+
+ " Down a line with j, <CR>, <NL> or <Down>.
+ call term_sendkeys(buf, "j")
+ call WaitForAssert({-> assert_equal(' 6 6', term_getline(buf, 5))})
+ call WaitForAssert({-> assert_equal('-- More --', term_getline(buf, 6))})
+ call term_sendkeys(buf, "\<NL>")
+ call WaitForAssert({-> assert_equal(' 7 7', term_getline(buf, 5))})
+ call term_sendkeys(buf, "\<CR>")
+ call WaitForAssert({-> assert_equal(' 8 8', term_getline(buf, 5))})
+ call term_sendkeys(buf, "\<Down>")
+ call WaitForAssert({-> assert_equal(' 9 9', term_getline(buf, 5))})
+
+ " Down a screen with <Space>, f, or <PageDown>.
+ call term_sendkeys(buf, 'f')
+ call WaitForAssert({-> assert_equal(' 14 14', term_getline(buf, 5))})
+ call WaitForAssert({-> assert_equal('-- More --', term_getline(buf, 6))})
+ call term_sendkeys(buf, ' ')
+ call WaitForAssert({-> assert_equal(' 19 19', term_getline(buf, 5))})
+ call term_sendkeys(buf, "\<PageDown>")
+ call WaitForAssert({-> assert_equal(' 24 24', term_getline(buf, 5))})
+
+ " Down a page (half a screen) with d.
+ call term_sendkeys(buf, 'd')
+ call WaitForAssert({-> assert_equal(' 27 27', term_getline(buf, 5))})
+
+ " Down all the way with 'G'.
+ call term_sendkeys(buf, 'G')
+ call WaitForAssert({-> assert_equal('100 100', term_getline(buf, 5))})
+ call WaitForAssert({-> assert_equal('Press ENTER or type command to continue', term_getline(buf, 6))})
+
+ " Up a line k, <BS> or <Up>.
+ call term_sendkeys(buf, 'k')
+ call WaitForAssert({-> assert_equal(' 99 99', term_getline(buf, 5))})
+ call term_sendkeys(buf, "\<BS>")
+ call WaitForAssert({-> assert_equal(' 98 98', term_getline(buf, 5))})
+ call term_sendkeys(buf, "\<Up>")
+ call WaitForAssert({-> assert_equal(' 97 97', term_getline(buf, 5))})
+
+ " Up a screen with b or <PageUp>.
+ call term_sendkeys(buf, 'b')
+ call WaitForAssert({-> assert_equal(' 92 92', term_getline(buf, 5))})
+ call term_sendkeys(buf, "\<PageUp>")
+ call WaitForAssert({-> assert_equal(' 87 87', term_getline(buf, 5))})
+
+ " Up a page (half a screen) with u.
+ call term_sendkeys(buf, 'u')
+ call WaitForAssert({-> assert_equal(' 84 84', term_getline(buf, 5))})
+
+ " Up all the way with 'g'.
+ call term_sendkeys(buf, 'g')
+ call WaitForAssert({-> assert_equal(' 5 5', term_getline(buf, 5))})
+ call WaitForAssert({-> assert_equal('-- More --', term_getline(buf, 6))})
+
+ " All the way down. Pressing f should do nothing but pressing
+ " space should end the more prompt.
+ call term_sendkeys(buf, 'G')
+ call WaitForAssert({-> assert_equal('100 100', term_getline(buf, 5))})
+ call WaitForAssert({-> assert_equal('Press ENTER or type command to continue', term_getline(buf, 6))})
+ call term_sendkeys(buf, 'f')
+ call WaitForAssert({-> assert_equal('100 100', term_getline(buf, 5))})
+ call term_sendkeys(buf, ' ')
+ call WaitForAssert({-> assert_equal('100', term_getline(buf, 5))})
+
+ " Pressing g< shows the previous command output.
+ call term_sendkeys(buf, 'g<')
+ call WaitForAssert({-> assert_equal('100 100', term_getline(buf, 5))})
+ call WaitForAssert({-> assert_equal('Press ENTER or type command to continue', term_getline(buf, 6))})
+
+ call term_sendkeys(buf, ":%p#\n")
+ call WaitForAssert({-> assert_equal(' 5 5', term_getline(buf, 5))})
+ call WaitForAssert({-> assert_equal('-- More --', term_getline(buf, 6))})
+
+ " Stop command output with q, <Esc> or CTRL-C.
+ call term_sendkeys(buf, 'q')
+ call WaitForAssert({-> assert_equal('100', term_getline(buf, 5))})
+
+ " Execute a : command from the more prompt
+ call term_sendkeys(buf, ":%p#\n")
+ call term_wait(buf)
+ call WaitForAssert({-> assert_equal('-- More --', term_getline(buf, 6))})
+ call term_sendkeys(buf, ":")
+ call term_wait(buf)
+ call WaitForAssert({-> assert_equal(':', term_getline(buf, 6))})
+ call term_sendkeys(buf, "echo 'Hello'\n")
+ call term_wait(buf)
+ call WaitForAssert({-> assert_equal('Hello ', term_getline(buf, 5))})
+
+ call StopVimInTerminal(buf)
+endfunc
+
+func Test_ask_yesno()
+ CheckRunVimInTerminal
+ let buf = RunVimInTerminal('', {'rows': 6})
+ call term_sendkeys(buf, ":call setline(1, range(1, 2))\n")
+
+ call term_sendkeys(buf, ":2,1s/^/n/\n")
+ call WaitForAssert({-> assert_equal('Backwards range given, OK to swap (y/n)?', term_getline(buf, 6))})
+ call term_sendkeys(buf, "n")
+ call WaitForAssert({-> assert_match('^Backwards range given, OK to swap (y/n)?n *1,1 *All$', term_getline(buf, 6))})
+ call WaitForAssert({-> assert_equal('1', term_getline(buf, 1))})
+
+ call term_sendkeys(buf, ":2,1s/^/Esc/\n")
+ call WaitForAssert({-> assert_equal('Backwards range given, OK to swap (y/n)?', term_getline(buf, 6))})
+ call term_sendkeys(buf, "\<Esc>")
+ call WaitForAssert({-> assert_match('^Backwards range given, OK to swap (y/n)?n *1,1 *All$', term_getline(buf, 6))})
+ call WaitForAssert({-> assert_equal('1', term_getline(buf, 1))})
+
+ call term_sendkeys(buf, ":2,1s/^/y/\n")
+ call WaitForAssert({-> assert_equal('Backwards range given, OK to swap (y/n)?', term_getline(buf, 6))})
+ call term_sendkeys(buf, "y")
+ call WaitForAssert({-> assert_match('^Backwards range given, OK to swap (y/n)?y *2,1 *All$', term_getline(buf, 6))})
+ call WaitForAssert({-> assert_equal('y1', term_getline(buf, 1))})
+ call WaitForAssert({-> assert_equal('y2', term_getline(buf, 2))})
+
+ call StopVimInTerminal(buf)
+endfunc
+
+func Test_mapping_at_hit_return_prompt()
+ nnoremap <C-B> :echo "hit ctrl-b"<CR>
+ call feedkeys(":ls\<CR>", "xt")
+ call feedkeys("\<*C-B>", "xt")
+ call assert_match('hit ctrl-b', Screenline(&lines - 1))
+ nunmap <C-B>
+endfunc
+
+func Test_quit_long_message()
+ CheckScreendump
+
+ 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 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
func Test_echo_string_partial()
function CountSpaces()
@@ -116,3 +273,37 @@ func Test_echo_string_partial()
call assert_equal("function('CountSpaces', [{'ccccccccccc': ['ab', 'cd'], 'aaaaaaaaaaa': v:false, 'bbbbbbbbbbbb': ''}])", string(function('CountSpaces', [#{aaaaaaaaaaa: v:false, bbbbbbbbbbbb: '', ccccccccccc: ['ab', 'cd']}])))
endfunc
+" Message output was previously overwritten by the fileinfo display, shown
+" when switching buffers. If a buffer is switched to, then a message if
+" echoed, we should show the message, rather than overwriting it with
+" fileinfo.
+func Test_fileinfo_after_echo()
+ CheckScreendump
+
+ let content =<< trim END
+ file a.txt
+
+ hide edit b.txt
+ call setline(1, "hi")
+ setlocal modified
+
+ hide buffer a.txt
+
+ autocmd CursorHold * buf b.txt | w | echo "'b' written"
+ END
+
+ call writefile(content, 'Xtest_fileinfo_after_echo')
+ let buf = RunVimInTerminal('-S Xtest_fileinfo_after_echo', #{rows: 6})
+ call term_sendkeys(buf, ":set updatetime=50\<CR>")
+ call term_sendkeys(buf, "0$")
+ call VerifyScreenDump(buf, 'Test_fileinfo_after_echo', {})
+
+ call term_sendkeys(buf, ":q\<CR>")
+
+ " clean up
+ call StopVimInTerminal(buf)
+ call delete('Xtest_fileinfo_after_echo')
+ call delete('b.txt')
+endfunc
+
+" vim: shiftwidth=2 sts=2 expandtab
diff --git a/src/nvim/testdir/test_mksession.vim b/src/nvim/testdir/test_mksession.vim
index 057895047d..8ec408e62e 100644
--- a/src/nvim/testdir/test_mksession.vim
+++ b/src/nvim/testdir/test_mksession.vim
@@ -2,9 +2,8 @@
scriptencoding latin1
-if !has('mksession')
- finish
-endif
+source check.vim
+CheckFeature mksession
source shared.vim
source term_util.vim
@@ -43,9 +42,9 @@ func Test_mksession()
\ ' four leadinG spaces',
\ 'two consecutive tabs',
\ 'two tabs in one line',
- \ 'one ä multibyteCharacter',
- \ 'aä Ä two multiByte characters',
- \ 'Aäöü three mulTibyte characters',
+ \ 'one multibyteCharacter',
+ \ 'a two multiByte characters',
+ \ 'A three mulTibyte characters',
\ 'short line',
\ ])
let tmpfile = 'Xtemp'
@@ -219,6 +218,7 @@ func Test_mksession_one_buffer_two_windows()
let count1 = 0
let count2 = 0
let count2buf = 0
+ let bufexists = 0
for line in lines
if line =~ 'edit \f*Xtest1$'
let count1 += 1
@@ -229,10 +229,14 @@ func Test_mksession_one_buffer_two_windows()
if line =~ 'buffer \f\{-}Xtest2'
let count2buf += 1
endif
+ if line =~ 'bufexists(fnamemodify(.*, ":p")'
+ let bufexists += 1
+ endif
endfor
call assert_equal(1, count1, 'Xtest1 count')
call assert_equal(2, count2, 'Xtest2 count')
call assert_equal(2, count2buf, 'Xtest2 buffer count')
+ call assert_equal(2, bufexists)
close
bwipe!
@@ -309,6 +313,31 @@ func Test_mksession_buffer_count()
set nohidden
endfunc
+func Test_mksession_buffer_order()
+ %bwipe!
+ e Xfoo | e Xbar | e Xbaz | e Xqux
+ bufdo write
+ mksession! Xtest_mks.out
+
+ " Verify that loading the session preserves order of buffers
+ %bwipe!
+ source Xtest_mks.out
+
+ let s:buf_info = getbufinfo()
+ call assert_true(s:buf_info[0]['name'] =~# 'Xfoo$')
+ call assert_true(s:buf_info[1]['name'] =~# 'Xbar$')
+ call assert_true(s:buf_info[2]['name'] =~# 'Xbaz$')
+ call assert_true(s:buf_info[3]['name'] =~# 'Xqux$')
+
+ " Clean up.
+ call delete('Xfoo')
+ call delete('Xbar')
+ call delete('Xbaz')
+ call delete('Xqux')
+ call delete('Xtest_mks.out')
+ %bwipe!
+endfunc
+
if has('extra_search')
func Test_mksession_hlsearch()
@@ -333,21 +362,29 @@ func Test_mkview_open_folds()
call append(0, ['a', 'b', 'c'])
1,3fold
+ write! Xtestfile
+
+ call assert_notequal(-1, foldclosed(1))
+ call assert_notequal(-1, foldclosed(2))
+ call assert_notequal(-1, foldclosed(3))
+
+ " Save the view with folds closed
+ mkview! Xtestview
+
" zR affects 'foldlevel', make sure the option is applied after the folds
" have been recreated.
+ " Open folds to ensure they get closed when restoring the view
normal zR
- write! Xtestfile
call assert_equal(-1, foldclosed(1))
call assert_equal(-1, foldclosed(2))
call assert_equal(-1, foldclosed(3))
- mkview! Xtestview
source Xtestview
- call assert_equal(-1, foldclosed(1))
- call assert_equal(-1, foldclosed(2))
- call assert_equal(-1, foldclosed(3))
+ call assert_notequal(-1, foldclosed(1))
+ call assert_notequal(-1, foldclosed(2))
+ call assert_notequal(-1, foldclosed(3))
call delete('Xtestview')
call delete('Xtestfile')
@@ -696,6 +733,36 @@ func Test_mksession_foldopt()
set sessionoptions&
endfunc
+" Test for mksession with "help" but not "options" in 'sessionoptions'
+func Test_mksession_help_noopt()
+ set sessionoptions-=options
+ set sessionoptions+=help
+ help
+ let fname = expand('%')
+ mksession! Xtest_mks.out
+ bwipe
+
+ source Xtest_mks.out
+ call assert_equal('help', &buftype)
+ call assert_equal('help', &filetype)
+ call assert_equal(fname, expand('%'))
+ call assert_false(&modifiable)
+ call assert_true(&readonly)
+
+ helpclose
+ help index
+ let fname = expand('%')
+ mksession! Xtest_mks.out
+ bwipe
+
+ source Xtest_mks.out
+ call assert_equal('help', &buftype)
+ call assert_equal(fname, expand('%'))
+
+ call delete('Xtest_mks.out')
+ set sessionoptions&
+endfunc
+
" Test for mksession with window position
func Test_mksession_winpos()
if !has('gui_running')
@@ -735,6 +802,73 @@ func Test_mksession_winminheight()
set sessionoptions&
endfunc
+" Test for mksession with and without options restores shortmess
+func Test_mksession_shortmess()
+ " Without options
+ set sessionoptions-=options
+ split
+ mksession! Xtest_mks.out
+ let found_save = 0
+ let found_restore = 0
+ let lines = readfile('Xtest_mks.out')
+ for line in lines
+ let line = trim(line)
+
+ if line ==# 'let s:shortmess_save = &shortmess'
+ let found_save += 1
+ endif
+
+ if found_save !=# 0 && line ==# 'let &shortmess = s:shortmess_save'
+ let found_restore += 1
+ endif
+ endfor
+ call assert_equal(1, found_save)
+ call assert_equal(1, found_restore)
+ call delete('Xtest_mks.out')
+ close
+ set sessionoptions&
+
+ " With options
+ set sessionoptions+=options
+ split
+ mksession! Xtest_mks.out
+ let found_restore = 0
+ let lines = readfile('Xtest_mks.out')
+ for line in lines
+ if line =~# 's:shortmess_save'
+ let found_restore += 1
+ endif
+ endfor
+ call assert_equal(0, found_restore)
+ call delete('Xtest_mks.out')
+ close
+ set sessionoptions&
+endfunc
+
+" Test that when Vim loading session has 'A' in 'shortmess' it does not
+" complain about an existing swapfile.
+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')
+ set sessionoptions-=options
+ mksession Xtestsession
+ bwipe!
+
+ " Recreate the swap file to pretend the file is being edited
+ call writefile(cont, fname)
+ set shortmess+=A
+ source Xtestsession
+
+ set shortmess&
+ set sessionoptions&
+ call delete('Xtestsession')
+ call delete(fname)
+endfunc
+
" Test for mksession with 'compatible' option
func Test_mksession_compatible()
throw 'skipped: Nvim does not support "compatible" option'
diff --git a/src/nvim/testdir/test_mksession_utf8.vim b/src/nvim/testdir/test_mksession_utf8.vim
index 722fd28beb..4e593cc21a 100644
--- a/src/nvim/testdir/test_mksession_utf8.vim
+++ b/src/nvim/testdir/test_mksession_utf8.vim
@@ -3,9 +3,8 @@
set encoding=utf-8
scriptencoding utf-8
-if !has('mksession')
- finish
-endif
+source check.vim
+CheckFeature mksession
func Test_mksession_utf8()
tabnew
diff --git a/src/nvim/testdir/test_move.vim b/src/nvim/testdir/test_move.vim
index f666a904b0..8c40369dbd 100644
--- a/src/nvim/testdir/test_move.vim
+++ b/src/nvim/testdir/test_move.vim
@@ -38,6 +38,7 @@ func Test_move()
call assert_fails("move -100", 'E16:')
call assert_fails("move +100", 'E16:')
call assert_fails('move', 'E16:')
+ call assert_fails("move 'r", 'E20:')
%bwipeout!
endfunc
diff --git a/src/nvim/testdir/test_normal.vim b/src/nvim/testdir/test_normal.vim
index aff22f5d01..9fbd1f774a 100644
--- a/src/nvim/testdir/test_normal.vim
+++ b/src/nvim/testdir/test_normal.vim
@@ -1,6 +1,8 @@
" Test for various Normal mode commands
source shared.vim
+source check.vim
+source view_util.vim
func Setup_NewWindow()
10new
@@ -53,7 +55,7 @@ func OpfuncDummy(type, ...)
let g:bufnr=bufnr('%')
endfunc
-fun! Test_normal00_optrans()
+func Test_normal00_optrans()
new
call append(0, ['1 This is a simple test: abcd', '2 This is the second line', '3 this is the third line'])
1
@@ -95,6 +97,12 @@ func Test_normal01_keymodel()
50
call feedkeys("\<S-Up>y", 'tx')
call assert_equal(['49', '5'], getreg(0, 0, 1))
+ " Use the different Shift special keys
+ 50
+ call feedkeys("\<S-Right>\<S-Left>\<S-Up>\<S-Down>\<S-Home>\<S-End>y", 'tx')
+ call assert_equal(['50'], getline("'<", "'>"))
+ call assert_equal(['50', ''], getreg(0, 0, 1))
+
" Do not start visual mode when keymodel=
set keymodel=
50
@@ -115,8 +123,8 @@ func Test_normal01_keymodel()
bw!
endfunc
+" Test for select mode
func Test_normal02_selectmode()
- " some basic select mode tests
call Setup_NewWindow()
50
norm! gHy
@@ -133,7 +141,8 @@ func Test_normal02_selectmode2()
" some basic select mode tests
call Setup_NewWindow()
50
- call feedkeys(":set im\n\<c-o>gHc\<c-o>:set noim\n", 'tx')
+ " call feedkeys(":set im\n\<c-o>gHc\<c-o>:set noim\n", 'tx')
+ call feedkeys("i\<c-o>gHc\<esc>", 'tx')
call assert_equal('c51', getline('.'))
" clean up
bw!
@@ -344,7 +353,7 @@ func Test_normal08_fold()
bw!
endfunc
-func Test_normal09_operatorfunc()
+func Test_normal09a_operatorfunc()
" Test operatorfunc
call Setup_NewWindow()
" Add some spaces for counting
@@ -374,7 +383,7 @@ func Test_normal09_operatorfunc()
bw!
endfunc
-func Test_normal09a_operatorfunc()
+func Test_normal09b_operatorfunc()
" Test operatorfunc
call Setup_NewWindow()
" Add some spaces for counting
@@ -396,10 +405,45 @@ func Test_normal09a_operatorfunc()
" clean up
unmap <buffer> ,,
set opfunc=
+ call assert_fails('normal Vg@', 'E774:')
bw!
unlet! g:opt
endfunc
+func OperatorfuncRedo(_)
+ let g:opfunc_count = v:count
+endfunc
+
+func Underscorize(_)
+ normal! '[V']r_
+endfunc
+
+func Test_normal09c_operatorfunc()
+ " Test redoing operatorfunc
+ new
+ call setline(1, 'some text')
+ set operatorfunc=OperatorfuncRedo
+ normal v3g@
+ call assert_equal(3, g:opfunc_count)
+ let g:opfunc_count = 0
+ normal .
+ call assert_equal(3, g:opfunc_count)
+
+ bw!
+ unlet g:opfunc_count
+
+ " Test redoing Visual mode
+ set operatorfunc=Underscorize
+ new
+ call setline(1, ['first', 'first', 'third', 'third', 'second'])
+ normal! 1GVjg@
+ normal! 5G.
+ normal! 3G.
+ call assert_equal(['_____', '_____', '_____', '_____', '______'], getline(1, '$'))
+ bwipe!
+ set operatorfunc=
+endfunc
+
func Test_normal10_expand()
" Test for expand()
10new
@@ -450,13 +494,33 @@ func Test_normal11_showcmd()
bw!
endfunc
+" Test for nv_error and normal command errors
func Test_normal12_nv_error()
- " Test for nv_error
10new
call setline(1, range(1,5))
" should not do anything, just beep
- exe "norm! <c-k>"
+ call assert_beeps('exe "norm! <c-k>"')
call assert_equal(map(range(1,5), 'string(v:val)'), getline(1,'$'))
+ call assert_beeps('normal! G2dd')
+ call assert_beeps("normal! g\<C-A>")
+ call assert_beeps("normal! g\<C-X>")
+ call assert_beeps("normal! g\<C-B>")
+ " call assert_beeps("normal! vQ\<Esc>")
+ call assert_beeps("normal! 2[[")
+ call assert_beeps("normal! 2]]")
+ call assert_beeps("normal! 2[]")
+ call assert_beeps("normal! 2][")
+ call assert_beeps("normal! 4[z")
+ call assert_beeps("normal! 4]z")
+ call assert_beeps("normal! 4[c")
+ call assert_beeps("normal! 4]c")
+ call assert_beeps("normal! 200%")
+ call assert_beeps("normal! %")
+ call assert_beeps("normal! 2{")
+ call assert_beeps("normal! 2}")
+ call assert_beeps("normal! r\<Right>")
+ call assert_beeps("normal! 8ry")
+ call assert_beeps('normal! "@')
bw!
endfunc
@@ -618,6 +682,13 @@ func Test_normal16_z_scroll_hor()
$put =lineB
1d
+ " Test for zl and zh with a count
+ norm! 0z10l
+ call assert_equal([11, 1], [col('.'), wincol()])
+ norm! z4h
+ call assert_equal([11, 5], [col('.'), wincol()])
+ normal! 2gg
+
" Test for zl
1
norm! 5zl
@@ -740,15 +811,134 @@ func Test_normal17_z_scroll_hor2()
bw!
endfunc
+" Test for commands that scroll the window horizontally. Test with folds.
+" H, M, L, CTRL-E, CTRL-Y, CTRL-U, CTRL-D, PageUp, PageDown commands
+func Test_vert_scroll_cmds()
+ 15new
+ call setline(1, range(1, 100))
+ exe "normal! 30ggz\<CR>"
+ set foldenable
+ 33,36fold
+ 40,43fold
+ 46,49fold
+ let h = winheight(0)
+
+ " Test for H, M and L commands
+ " Top of the screen = 30
+ " Folded lines = 9
+ " Bottom of the screen = 30 + h + 9 - 1
+ normal! 4L
+ call assert_equal(35 + h, line('.'))
+ normal! 4H
+ call assert_equal(33, line('.'))
+
+ " Test for the CTRL-E and CTRL-Y commands with folds
+ %d
+ call setline(1, range(1, 10))
+ 3,5fold
+ exe "normal 6G3\<C-E>"
+ call assert_equal(6, line('w0'))
+ exe "normal 2\<C-Y>"
+ call assert_equal(2, line('w0'))
+
+ " Test for CTRL-Y on a folded line
+ %d
+ call setline(1, range(1, 100))
+ exe (h + 2) .. "," .. (h + 4) .. "fold"
+ exe h + 5
+ normal z-
+ exe "normal \<C-Y>\<C-Y>"
+ call assert_equal(h + 1, line('w$'))
+
+ " Using <PageUp> and <PageDown> in an empty buffer should beep
+ %d
+ call assert_beeps('exe "normal \<PageUp>"')
+ call assert_beeps('exe "normal \<C-B>"')
+ call assert_beeps('exe "normal \<PageDown>"')
+ call assert_beeps('exe "normal \<C-F>"')
+
+ " Test for <C-U> and <C-D> with fold
+ %d
+ call setline(1, range(1, 100))
+ 10,35fold
+ set scroll=10
+ exe "normal \<C-D>"
+ call assert_equal(36, line('.'))
+ exe "normal \<C-D>"
+ call assert_equal(46, line('.'))
+ exe "normal \<C-U>"
+ call assert_equal(36, line('.'))
+ exe "normal \<C-U>"
+ call assert_equal(10, line('.'))
+ exe "normal \<C-U>"
+ call assert_equal(1, line('.'))
+ set scroll&
+
+ " Test for scrolling to the top of the file with <C-U> and a fold
+ 10
+ normal ztL
+ exe "normal \<C-U>\<C-U>"
+ call assert_equal(1, line('w0'))
+
+ " Test for CTRL-D on a folded line
+ %d
+ call setline(1, range(1, 100))
+ 50,100fold
+ 75
+ normal z-
+ exe "normal \<C-D>"
+ call assert_equal(50, line('.'))
+ call assert_equal(100, line('w$'))
+ normal z.
+ let lnum = winline()
+ exe "normal \<C-D>"
+ call assert_equal(lnum, winline())
+ call assert_equal(50, line('.'))
+ normal zt
+ exe "normal \<C-D>"
+ call assert_equal(50, line('w0'))
+
+ set foldenable&
+ close!
+endfunc
+
+" Test for the 'sidescroll' option
+func Test_sidescroll_opt()
+ new
+ 20vnew
+
+ " scroll by 2 characters horizontally
+ set sidescroll=2 nowrap
+ call setline(1, repeat('a', 40))
+ normal g$l
+ call assert_equal(19, screenpos(0, 1, 21).col)
+ normal l
+ call assert_equal(20, screenpos(0, 1, 22).col)
+ normal g0h
+ call assert_equal(2, screenpos(0, 1, 2).col)
+ call assert_equal(20, screenpos(0, 1, 20).col)
+
+ " when 'sidescroll' is 0, cursor positioned at the center
+ set sidescroll=0
+ normal g$l
+ call assert_equal(11, screenpos(0, 1, 21).col)
+ normal g0h
+ call assert_equal(10, screenpos(0, 1, 10).col)
+
+ %bw!
+ set wrap& sidescroll&
+endfunc
+
+" basic tests for foldopen/folddelete
func Test_normal18_z_fold()
- " basic tests for foldopen/folddelete
- if !has("folding")
- return
- endif
+ CheckFeature folding
call Setup_NewWindow()
50
setl foldenable fdm=marker foldlevel=5
+ call assert_beeps('normal! zj')
+ call assert_beeps('normal! zk')
+
" Test for zF
" First fold
norm! 4zF
@@ -1118,7 +1308,7 @@ func Test_normal20_exmode()
endif
call writefile(['1a', 'foo', 'bar', '.', 'w! Xfile2', 'q!'], 'Xscript')
call writefile(['1', '2'], 'Xfile')
- call system(v:progpath .' -e -s < Xscript Xfile')
+ call system(GetVimCommand() .. ' -e -s < Xscript Xfile')
let a=readfile('Xfile2')
call assert_equal(['1', 'foo', 'bar', '2'], a)
@@ -1171,16 +1361,19 @@ func Test_normal22_zet()
endfor
call writefile(['1', '2'], 'Xfile_Test_normal22_zet')
- let args = ' --headless -u NONE -N -U NONE -i NONE --noplugins'
- call system(v:progpath . args . ' -c "%d" -c ":norm! ZZ" Xfile_Test_normal22_zet')
+ let args = ' -N -i NONE --noplugins -X --headless'
+ call system(GetVimCommand() .. args .. ' -c "%d" -c ":norm! ZZ" Xfile_Test_normal22_zet')
let a = readfile('Xfile_Test_normal22_zet')
call assert_equal([], a)
" Test for ZQ
call writefile(['1', '2'], 'Xfile_Test_normal22_zet')
- call system(v:progpath . args . ' -c "%d" -c ":norm! ZQ" Xfile_Test_normal22_zet')
+ call system(GetVimCommand() . args . ' -c "%d" -c ":norm! ZQ" Xfile_Test_normal22_zet')
let a = readfile('Xfile_Test_normal22_zet')
call assert_equal(['1', '2'], a)
+ " Unsupported Z command
+ call assert_beeps('normal! ZW')
+
" Nvim: This sometimes hangs the TSAN build.
" for file in ['Xfile_Test_normal22_zet']
" call delete(file)
@@ -1249,6 +1442,15 @@ func Test_normal23_K()
call assert_match("man --pager=cat 'man'", a)
endif
+ " Error cases
+ call setline(1, '#$#')
+ call assert_fails('normal! ggK', 'E349:')
+ call setline(1, '---')
+ call assert_fails('normal! ggv2lK', 'E349:')
+ call setline(1, ['abc', 'xyz'])
+ call assert_fails("normal! gg2lv2h\<C-]>", 'E426:')
+ call assert_beeps("normal! ggVjK")
+
" clean up
let &keywordprg = k
bw!
@@ -1382,9 +1584,16 @@ func Test_normal27_bracket()
call assert_equal(5, line('.'))
call assert_equal(3, col('.'))
- " No mark after line 21, cursor moves to first non blank on current line
+ " No mark before line 1, cursor moves to first non-blank on current line
+ 1
+ norm! 5|['
+ call assert_equal(' 1 b', getline('.'))
+ call assert_equal(1, line('.'))
+ call assert_equal(3, col('.'))
+
+ " No mark after line 21, cursor moves to first non-blank on current line
21
- norm! $]'
+ norm! 5|]'
call assert_equal(' 21 b', getline('.'))
call assert_equal(21, line('.'))
call assert_equal(3, col('.'))
@@ -1401,12 +1610,40 @@ func Test_normal27_bracket()
call assert_equal(20, line('.'))
call assert_equal(8, col('.'))
+ " No mark before line 1, cursor does not move
+ 1
+ norm! 5|[`
+ call assert_equal(' 1 b', getline('.'))
+ call assert_equal(1, line('.'))
+ call assert_equal(5, col('.'))
+
+ " No mark after line 21, cursor does not move
+ 21
+ norm! 5|]`
+ call assert_equal(' 21 b', getline('.'))
+ call assert_equal(21, line('.'))
+ call assert_equal(5, col('.'))
+
+ " Count too large for [`
+ " cursor moves to first lowercase mark
+ norm! 99[`
+ call assert_equal(' 1 b', getline('.'))
+ call assert_equal(1, line('.'))
+ call assert_equal(7, col('.'))
+
+ " Count too large for ]`
+ " cursor moves to last lowercase mark
+ norm! 99]`
+ call assert_equal(' 20 b', getline('.'))
+ call assert_equal(20, line('.'))
+ call assert_equal(8, col('.'))
+
" clean up
bw!
endfunc
+" Test for ( and ) sentence movements
func Test_normal28_parenthesis()
- " basic testing for ( and )
new
call append(0, ['This is a test. With some sentences!', '', 'Even with a question? And one more. And no sentence here'])
@@ -1424,12 +1661,43 @@ func Test_normal28_parenthesis()
norm! $d(
call assert_equal(['With some sentences!', '', ' ', '', 'This is a long sentence', ''], getline(1, '$'))
+ " Move to the next sentence from a paragraph macro
+ %d
+ call setline(1, ['.LP', 'blue sky!. blue sky.', 'blue sky. blue sky.'])
+ call cursor(1, 1)
+ normal )
+ call assert_equal([2, 1], [line('.'), col('.')])
+ normal )
+ call assert_equal([2, 12], [line('.'), col('.')])
+ normal ((
+ call assert_equal([1, 1], [line('.'), col('.')])
+
+ " It is an error if a next sentence is not found
+ %d
+ call setline(1, '.SH')
+ call assert_beeps('normal )')
+
+ " If only dot is present, don't treat that as a sentence
+ call setline(1, '. This is a sentence.')
+ normal $((
+ call assert_equal(3, col('.'))
+
+ " Jumping to a fold should open the fold
+ call setline(1, ['', '', 'one', 'two', 'three'])
+ set foldenable
+ 2,$fold
+ call feedkeys(')', 'xt')
+ call assert_equal(3, line('.'))
+ call assert_equal(1, foldlevel('.'))
+ call assert_equal(-1, foldclosed('.'))
+ set foldenable&
+
" clean up
bw!
endfunc
-fun! Test_normal29_brace()
- " basic test for { and } movements
+" Test for { and } paragraph movements
+func Test_normal29_brace()
let text =<< trim [DATA]
A paragraph begins after each empty line, and also at each of a set of
paragraph macros, specified by the pairs of characters in the 'paragraphs'
@@ -1582,12 +1850,24 @@ fun! Test_normal29_brace()
" [DATA]
" call assert_equal(expected, getline(1, '$'))
+ " Jumping to a fold should open the fold
+ " %d
+ " call setline(1, ['', 'one', 'two', ''])
+ " set foldenable
+ " 2,$fold
+ " call feedkeys('}', 'xt')
+ " call assert_equal(4, line('.'))
+ " call assert_equal(1, foldlevel('.'))
+ " call assert_equal(-1, foldclosed('.'))
+ " set foldenable&
+
" clean up
set cpo-={
bw!
endfunc
-fun! Test_normal30_changecase()
+" Test for ~ command
+func Test_normal30_changecase()
new
call append(0, 'This is a simple test: äüöß')
norm! 1ggVu
@@ -1607,8 +1887,23 @@ fun! Test_normal30_changecase()
norm! V~
call assert_equal('THIS IS A simple test: äüöss', getline('.'))
- " Turkish ASCII turns to multi-byte. On some systems Turkish locale
- " is available but toupper()/tolower() don't do the right thing.
+ " Test for changing case across lines using 'whichwrap'
+ call setline(1, ['aaaaaa', 'aaaaaa'])
+ normal! gg10~
+ call assert_equal(['AAAAAA', 'aaaaaa'], getline(1, 2))
+ set whichwrap+=~
+ normal! gg10~
+ call assert_equal(['aaaaaa', 'AAAAaa'], getline(1, 2))
+ set whichwrap&
+
+ " clean up
+ bw!
+endfunc
+
+" Turkish ASCII turns to multi-byte. On some systems Turkish locale
+" is available but toupper()/tolower() don't do the right thing.
+func Test_normal_changecase_turkish()
+ new
try
lang tr_TR.UTF-8
set casemap=
@@ -1652,13 +1947,11 @@ fun! Test_normal30_changecase()
" can't use Turkish locale
throw 'Skipped: Turkish locale not available'
endtry
-
- " clean up
- bw!
+ close!
endfunc
-fun! Test_normal31_r_cmd()
- " Test for r command
+" Test for r (replace) command
+func Test_normal31_r_cmd()
new
call append(0, 'This is a simple test: abcd')
exe "norm! 1gg$r\<cr>"
@@ -1677,13 +1970,29 @@ fun! Test_normal31_r_cmd()
exe "norm! 1gg05rf"
call assert_equal('fffffis a', getline(1))
+ " When replacing characters, copy characters from above and below lines
+ " using CTRL-Y and CTRL-E.
+ " Different code paths are used for utf-8 and latin1 encodings
+ set showmatch
+ for enc in ['latin1', 'utf-8']
+ enew!
+ let &encoding = enc
+ call setline(1, [' {a}', 'xxxxxxxxxx', ' [b]'])
+ exe "norm! 2gg5r\<C-Y>l5r\<C-E>"
+ call assert_equal(' {a}x [b]x', getline(2))
+ endfor
+ set showmatch&
+
+ " r command should fail in operator pending mode
+ call assert_beeps('normal! cr')
+
" clean up
set noautoindent
bw!
endfunc
+" Test for g*, g#
func Test_normal32_g_cmd1()
- " Test for g*, g#
new
call append(0, ['abc.x_foo', 'x_foobar.abc'])
1
@@ -1698,11 +2007,12 @@ func Test_normal32_g_cmd1()
bw!
endfunc
-fun! Test_normal33_g_cmd2()
+" 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
- " Tests for g cmds
call Setup_NewWindow()
" Test for g`
clearjumps
@@ -1714,6 +2024,10 @@ fun! Test_normal33_g_cmd2()
call assert_equal('>', a[-1:])
call assert_equal(1, line('.'))
call assert_equal('1', getline('.'))
+ call cursor(10, 1)
+ norm! g'a
+ call assert_equal('>', a[-1:])
+ call assert_equal(1, line('.'))
" Test for g; and g,
norm! g;
@@ -1744,6 +2058,16 @@ fun! Test_normal33_g_cmd2()
norm! g&
call assert_equal(['11', '22', '33', '44', '55', '66', '77', '88', '9', '110', 'a', 'b', 'c', 'dd'], getline(1, '$'))
+ " Jumping to a fold using gg should open the fold
+ set foldenable
+ set foldopen+=jump
+ 5,8fold
+ call feedkeys('6gg', 'xt')
+ call assert_equal(1, foldlevel('.'))
+ call assert_equal(-1, foldclosed('.'))
+ set foldopen-=jump
+ set foldenable&
+
" Test for gv
%d
call append('$', repeat(['abcdefgh'], 8))
@@ -1755,14 +2079,20 @@ fun! Test_normal33_g_cmd2()
exe "norm! G0\<c-v>4k4ly"
exe "norm! gvood"
call assert_equal(['', 'abfgh', 'abfgh', 'abfgh', 'fgh', 'fgh', 'fgh', 'fgh', 'fgh'], getline(1,'$'))
+ " gv cannot be used in operator pending mode
+ call assert_beeps('normal! cgv')
+ " gv should beep without a previously selected visual area
+ new
+ call assert_beeps('normal! gv')
+ close
" Test for gk/gj
%d
15vsp
set wrap listchars= sbr=
- let lineA='abcdefghijklmnopqrstuvwxyz'
- let lineB='0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ'
- let lineC='0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz01234567890123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789'
+ let lineA = 'abcdefghijklmnopqrstuvwxyz'
+ let lineB = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ'
+ let lineC = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz01234567890123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789'
$put =lineA
$put =lineB
@@ -1795,8 +2125,39 @@ fun! Test_normal33_g_cmd2()
norm! g^yl
call assert_equal(15, col('.'))
call assert_equal('l', getreg(0))
+ call assert_beeps('normal 5g$')
+
+ " Test for g$ with double-width character half displayed
+ vsplit
+ 9wincmd |
+ setlocal nowrap nonumber
+ call setline(2, 'asdfasdfヨ')
+ 2
+ normal 0g$
+ call assert_equal(8, col('.'))
+ 10wincmd |
+ normal 0g$
+ call assert_equal(9, col('.'))
+
+ setlocal signcolumn=yes
+ 11wincmd |
+ normal 0g$
+ call assert_equal(8, col('.'))
+ 12wincmd |
+ normal 0g$
+ call assert_equal(9, col('.'))
+
+ close
+
+ " Test for g_
+ call assert_beeps('normal! 100g_')
+ call setline(2, [' foo ', ' foobar '])
+ normal! 2ggg_
+ call assert_equal(5, col('.'))
+ normal! 2g_
+ call assert_equal(8, col('.'))
- norm! 2ggdd
+ norm! 2ggdG
$put =lineC
" Test for gM
@@ -1812,7 +2173,15 @@ fun! Test_normal33_g_cmd2()
call assert_equal(87, col('.'))
call assert_equal('E', getreg(0))
+ " Test for gM with Tab characters
+ call setline('.', "\ta\tb\tc\td\te\tf")
+ norm! gMyl
+ call assert_equal(6, col('.'))
+ call assert_equal("c", getreg(0))
+
" Test for g Ctrl-G
+ call setline('.', lineC)
+ norm! 60gMyl
set ff=unix
let a=execute(":norm! g\<c-g>")
call assert_match('Col 87 of 144; Line 2 of 2; Word 1 of 1; Byte 88 of 146', a)
@@ -1830,17 +2199,46 @@ fun! Test_normal33_g_cmd2()
$put ='third line'
norm! gi another word
call assert_equal(['foobar next word another word', 'new line', 'third line'], getline(1,'$'))
+ call setline(1, 'foobar')
+ normal! Ggifirst line
+ call assert_equal('foobarfirst line', getline(1))
+ " Test gi in 'virtualedit' mode with cursor after the end of the line
+ set virtualedit=all
+ call setline(1, 'foo')
+ exe "normal! Abar\<Right>\<Right>\<Right>\<Right>"
+ call setline(1, 'foo')
+ normal! Ggifirst line
+ call assert_equal('foo first line', getline(1))
+ set virtualedit&
+
+ " Test for aboring a g command using CTRL-\ CTRL-G
+ exe "normal! g\<C-\>\<C-G>"
+ call assert_equal('foo first line', getline('.'))
" clean up
bw!
endfunc
+func Test_normal_ex_substitute()
+ " This was hanging on the substitute prompt.
+ new
+ call setline(1, 'a')
+ exe "normal! gggQs/a/b/c\<CR>"
+ call assert_equal('a', getline(1))
+ bwipe!
+endfunc
+
+" Test for g CTRL-G
func Test_g_ctrl_g()
new
let a = execute(":norm! g\<c-g>")
call assert_equal("\n--No lines in buffer--", a)
+ " Test for CTRL-G (same as :file)
+ let a = execute(":norm! \<c-g>")
+ call assert_equal("\n\n\"[No Name]\" --No lines in buffer--", a)
+
call setline(1, ['first line', 'second line'])
" Test g CTRL-g with dos, mac and unix file type.
@@ -1908,8 +2306,8 @@ func Test_g_ctrl_g()
bwipe!
endfunc
-fun! Test_normal34_g_cmd3()
- " Test for g8
+" Test for g8
+func Test_normal34_g_cmd3()
new
let a=execute(':norm! 1G0g8')
call assert_equal("\nNUL", a)
@@ -1926,11 +2324,10 @@ fun! Test_normal34_g_cmd3()
bw!
endfunc
+" Test 8g8 which finds invalid utf8 at or after the cursor.
func Test_normal_8g8()
new
- " Test 8g8 which finds invalid utf8 at or after the cursor.
-
" With invalid byte.
call setline(1, "___\xff___")
norm! 1G08g8g
@@ -1959,8 +2356,8 @@ func Test_normal_8g8()
bw!
endfunc
-fun! Test_normal35_g_cmd4()
- " Test for g<
+" Test for g<
+func Test_normal35_g_cmd4()
" Cannot capture its output,
" probably a bug, therefore, test disabled:
throw "Skipped: output of g< can't be tested currently"
@@ -1969,7 +2366,8 @@ fun! Test_normal35_g_cmd4()
call assert_true(!empty(b), 'failed `execute(g<)`')
endfunc
-fun! Test_normal36_g_cmd5()
+" Test for gp gP go
+func Test_normal36_g_cmd5()
new
call append(0, 'abcdefghijklmnopqrstuvwxyz')
set ff=unix
@@ -2007,8 +2405,8 @@ fun! Test_normal36_g_cmd5()
bw!
endfunc
-fun! Test_normal37_g_cmd6()
- " basic test for gt and gT
+" Test for gt and gT
+func Test_normal37_g_cmd6()
tabnew 1.txt
tabnew 2.txt
tabnew 3.txt
@@ -2031,11 +2429,11 @@ fun! Test_normal37_g_cmd6()
tabclose
endfor
" clean up
- call assert_fails(':tabclose', 'E784')
+ call assert_fails(':tabclose', 'E784:')
endfunc
-fun! Test_normal38_nvhome()
- " Test for <Home> and <C-Home> key
+" Test for <Home> and <C-Home> key
+func Test_normal38_nvhome()
new
call setline(1, range(10))
$
@@ -2050,12 +2448,28 @@ fun! Test_normal38_nvhome()
call assert_equal([0, 5, 1, 0, 1], getcurpos())
exe "norm! \<c-home>"
call assert_equal([0, 1, 1, 0, 1], getcurpos())
+ exe "norm! G\<c-kHome>"
+ call assert_equal([0, 1, 1, 0, 1], getcurpos())
" clean up
bw!
endfunc
-fun! Test_normal39_cw()
+" Test for <End> and <C-End> keys
+func Test_normal_nvend()
+ new
+ call setline(1, map(range(1, 10), '"line" .. v:val'))
+ exe "normal! \<End>"
+ call assert_equal(5, col('.'))
+ exe "normal! 4\<End>"
+ call assert_equal([4, 5], [line('.'), col('.')])
+ exe "normal! \<C-End>"
+ call assert_equal([10, 6], [line('.'), col('.')])
+ close!
+endfunc
+
+" Test for cw cW ce
+func Test_normal39_cw()
" Test for cw and cW on whitespace
" and cpo+=w setting
new
@@ -2076,12 +2490,27 @@ fun! Test_normal39_cw()
norm! 2gg0cwfoo
call assert_equal('foo', getline('.'))
+ call setline(1, 'one; two')
+ call cursor(1, 1)
+ call feedkeys('cwvim', 'xt')
+ call assert_equal('vim; two', getline(1))
+ call feedkeys('0cWone', 'xt')
+ call assert_equal('one two', getline(1))
+ "When cursor is at the end of a word 'ce' will change until the end of the
+ "next word, but 'cw' will change only one character
+ call setline(1, 'one two')
+ call feedkeys('0ecwce', 'xt')
+ call assert_equal('once two', getline(1))
+ call setline(1, 'one two')
+ call feedkeys('0ecely', 'xt')
+ call assert_equal('only', getline(1))
+
" clean up
bw!
endfunc
-fun! Test_normal40_ctrl_bsl()
- " Basic test for CTRL-\ commands
+" Test for CTRL-\ commands
+func Test_normal40_ctrl_bsl()
new
call append(0, 'here are some words')
exe "norm! 1gg0a\<C-\>\<C-N>"
@@ -2095,19 +2524,23 @@ fun! Test_normal40_ctrl_bsl()
call assert_equal('n', mode())
call assert_equal(1, col('.'))
"imap <buffer> , <c-\><c-n>
- set im
+ " set im
exe ":norm! \<c-\>\<c-n>dw"
- set noim
+ " set noim
call assert_equal('are some words', getline(1))
call assert_false(&insertmode)
+ call assert_beeps("normal! \<C-\>\<C-A>")
+
+ " Using CTRL-\ CTRL-N in cmd window should close the window
+ call feedkeys("q:\<C-\>\<C-N>", 'xt')
+ call assert_equal('', getcmdwintype())
" clean up
bw!
endfunc
-fun! Test_normal41_insert_reg()
- " Test for <c-r>=, <c-r><c-r>= and <c-r><c-o>=
- " in insert mode
+" Test for <c-r>=, <c-r><c-r>= and <c-r><c-o>= in insert mode
+func Test_normal41_insert_reg()
new
set sts=2 sw=2 ts=8 tw=0
call append(0, ["aaa\tbbb\tccc", '', '', ''])
@@ -2125,8 +2558,8 @@ fun! Test_normal41_insert_reg()
bw!
endfunc
+" Test for Ctrl-D and Ctrl-U
func Test_normal42_halfpage()
- " basic test for Ctrl-D and Ctrl-U
call Setup_NewWindow()
call assert_equal(5, &scroll)
exe "norm! \<c-d>"
@@ -2162,92 +2595,6 @@ func Test_normal42_halfpage()
bw!
endfunc
-fun! Test_normal43_textobject1()
- " basic tests for text object aw
- new
- call append(0, ['foobar,eins,foobar', 'foo,zwei,foo '])
- " diw
- norm! 1gg0diw
- call assert_equal([',eins,foobar', 'foo,zwei,foo ', ''], getline(1,'$'))
- " daw
- norm! 2ggEdaw
- call assert_equal([',eins,foobar', 'foo,zwei,', ''], getline(1, '$'))
- %d
- call append(0, ["foo\teins\tfoobar", "foo\tzwei\tfoo "])
- " diW
- norm! 2ggwd2iW
- call assert_equal(['foo eins foobar', 'foo foo ', ''], getline(1,'$'))
- " daW
- norm! 1ggd2aW
- call assert_equal(['foobar', 'foo foo ', ''], getline(1,'$'))
-
- %d
- call append(0, ["foo\teins\tfoobar", "foo\tzwei\tfoo "])
- " aw in visual line mode switches to characterwise mode
- norm! 2gg$Vawd
- call assert_equal(['foo eins foobar', 'foo zwei foo'], getline(1,'$'))
- norm! 1gg$Viwd
- call assert_equal(['foo eins ', 'foo zwei foo'], getline(1,'$'))
-
- " clean up
- bw!
-endfunc
-
-func Test_normal44_textobjects2()
- " basic testing for is and as text objects
- new
- call append(0, ['This is a test. With some sentences!', '', 'Even with a question? And one more. And no sentence here'])
- " Test for dis - does not remove trailing whitespace
- norm! 1gg0dis
- call assert_equal([' With some sentences!', '', 'Even with a question? And one more. And no sentence here', ''], getline(1,'$'))
- " Test for das - removes leading whitespace
- norm! 3ggf?ldas
- call assert_equal([' With some sentences!', '', 'Even with a question? And no sentence here', ''], getline(1,'$'))
- " when used in visual mode, is made characterwise
- norm! 3gg$Visy
- call assert_equal('v', visualmode())
- " reset visualmode()
- norm! 3ggVy
- norm! 3gg$Vasy
- call assert_equal('v', visualmode())
- " basic testing for textobjects a< and at
- %d
- call setline(1, ['<div> ','<a href="foobar" class="foo">xyz</a>',' </div>', ' '])
- " a<
- norm! 1gg0da<
- call assert_equal([' ', '<a href="foobar" class="foo">xyz</a>', ' </div>', ' '], getline(1,'$'))
- norm! 1pj
- call assert_equal([' <div>', '<a href="foobar" class="foo">xyz</a>', ' </div>', ' '], getline(1,'$'))
- " at
- norm! d2at
- call assert_equal([' '], getline(1,'$'))
- %d
- call setline(1, ['<div> ','<a href="foobar" class="foo">xyz</a>',' </div>', ' '])
- " i<
- norm! 1gg0di<
- call assert_equal(['<> ', '<a href="foobar" class="foo">xyz</a>', ' </div>', ' '], getline(1,'$'))
- norm! 1Pj
- call assert_equal(['<div> ', '<a href="foobar" class="foo">xyz</a>', ' </div>', ' '], getline(1,'$'))
- norm! d2it
- call assert_equal(['<div></div>',' '], getline(1,'$'))
- " basic testing for a[ and i[ text object
- %d
- call setline(1, [' ', '[', 'one [two]', 'thre', ']'])
- norm! 3gg0di[
- call assert_equal([' ', '[', ']'], getline(1,'$'))
- call setline(1, [' ', '[', 'one [two]', 'thre', ']'])
- norm! 3gg0ftd2a[
- call assert_equal([' '], getline(1,'$'))
- %d
- " Test for i" when cursor is in front of a quoted object
- call append(0, 'foo "bar"')
- norm! 1gg0di"
- call assert_equal(['foo ""', ''], getline(1,'$'))
-
- " clean up
- bw!
-endfunc
-
func Test_normal45_drop()
if !has('dnd')
" The ~ register does not exist
@@ -2334,7 +2681,7 @@ func Test_normal49_counts()
endfunc
func Test_normal50_commandline()
- if !has("timers") || !has("cmdline_hist") || !has("vertsplit")
+ if !has("timers") || !has("cmdline_hist")
return
endif
func! DoTimerWork(id)
@@ -2396,6 +2743,8 @@ func Test_normal52_rl()
call assert_equal(19, col('.'))
call feedkeys("\<right>", 'tx')
call assert_equal(18, col('.'))
+ call feedkeys("\<left>", 'tx')
+ call assert_equal(19, col('.'))
call feedkeys("\<s-right>", 'tx')
call assert_equal(13, col('.'))
call feedkeys("\<c-right>", 'tx')
@@ -2485,6 +2834,18 @@ func Test_gr_command()
normal 4gro
call assert_equal('ooooecond line', getline(2))
let &cpo = save_cpo
+ normal! ggvegrx
+ call assert_equal('xxxxx line', getline(1))
+ exe "normal! gggr\<C-V>122"
+ call assert_equal('zxxxx line', getline(1))
+ set virtualedit=all
+ normal! 15|grl
+ call assert_equal('zxxxx line l', getline(1))
+ set virtualedit&
+ set nomodifiable
+ call assert_fails('normal! grx', 'E21:')
+ call assert_fails('normal! gRx', 'E21:')
+ set modifiable&
enew!
endfunc
@@ -2507,6 +2868,8 @@ func Test_changelist()
normal g;
call assert_equal([2, 2], [line('.'), col('.')])
call assert_fails('normal g;', 'E662:')
+ new
+ call assert_fails('normal g;', 'E664:')
%bwipe!
let &ul = save_ul
endfunc
@@ -2553,6 +2916,10 @@ endfunc
" Jumping to beginning and end of methods in Java-like languages
func Test_java_motion()
new
+ call assert_beeps('normal! [m')
+ call assert_beeps('normal! ]m')
+ call assert_beeps('normal! [M')
+ call assert_beeps('normal! ]M')
a
Piece of Java
{
@@ -2627,7 +2994,7 @@ Piece of Java
close!
endfunc
-fun! Test_normal_gdollar_cmd()
+func Test_normal_gdollar_cmd()
if !has("jumplist")
return
endif
@@ -2682,10 +3049,11 @@ fun! Test_normal_gdollar_cmd()
bw!
endfunc
-func Test_normal_gk()
+func Test_normal_gk_gj()
" needs 80 column new window
new
vert 80new
+ call assert_beeps('normal gk')
put =[repeat('x',90)..' {{{1', 'x {{{1']
norm! gk
" In a 80 column wide terminal the window will be only 78 char
@@ -2700,12 +3068,12 @@ func Test_normal_gk()
norm! gk
call assert_equal(95, col('.'))
call assert_equal(95, virtcol('.'))
- bw!
- bw!
+ %bw!
" needs 80 column new window
new
vert 80new
+ call assert_beeps('normal gj')
set number
set numberwidth=10
set cpoptions+=n
@@ -2724,9 +3092,191 @@ func Test_normal_gk()
call assert_equal(1, col('.'))
norm! gj
call assert_equal(76, col('.'))
- bw!
- bw!
- set cpoptions& number& numberwidth&
+ " When 'nowrap' is set, gk and gj behave like k and j
+ set nowrap
+ normal! gk
+ call assert_equal([2, 76], [line('.'), col('.')])
+ normal! gj
+ call assert_equal([3, 76], [line('.'), col('.')])
+ %bw!
+ 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
+ call setline(1, ['foo', 'bar', 'baz'])
+ let @a = ''
+ call feedkeys("\"ay:if v:true\<CR>normal l\<CR>endif\<CR>", 'xt')
+ call assert_equal('f', @a)
+ close!
+endfunc
+
+" Test for supplying a count to a normal-mode command across a cursorhold call
+func Test_normal_cursorhold_with_count()
+ throw 'Skipped: Nvim removed <CursorHold> key'
+ func s:cHold()
+ let g:cHold_Called += 1
+ endfunc
+ new
+ augroup normalcHoldTest
+ au!
+ au CursorHold <buffer> call s:cHold()
+ augroup END
+ let g:cHold_Called = 0
+ call feedkeys("3\<CursorHold>2ix", 'xt')
+ call assert_equal(1, g:cHold_Called)
+ call assert_equal(repeat('x', 32), getline(1))
+ augroup normalcHoldTest
+ au!
+ augroup END
+ au! normalcHoldTest
+ close!
+ delfunc s:cHold
+endfunc
+
+" Test for using a count and a command with CTRL-W
+func Test_wincmd_with_count()
+ call feedkeys("\<C-W>12n", 'xt')
+ call assert_equal(12, winheight(0))
+endfunc
+
+" Test for 'b', 'B' 'ge' and 'gE' commands
+func Test_horiz_motion()
+ new
+ normal! gg
+ call assert_beeps('normal! b')
+ call assert_beeps('normal! B')
+ call assert_beeps('normal! gE')
+ call assert_beeps('normal! ge')
+ " <S-Backspace> moves one word left and <C-Backspace> moves one WORD left
+ call setline(1, 'one ,two ,three')
+ exe "normal! $\<S-BS>"
+ call assert_equal(11, col('.'))
+ exe "normal! $\<C-BS>"
+ call assert_equal(10, col('.'))
+ close!
+endfunc
+
+" Test for using a : command in operator pending mode
+func Test_normal_colon_op()
+ new
+ call setline(1, ['one', 'two'])
+ call assert_beeps("normal! Gc:d\<CR>")
+ close!
+endfunc
+
+" Test for 'w' and 'b' commands
+func Test_normal_word_move()
+ new
+ call setline(1, ['foo bar a', '', 'foo bar b'])
+ " copy a single character word at the end of a line
+ normal 1G$yw
+ call assert_equal('a', @")
+ " copy a single character word at the end of a file
+ normal G$yw
+ call assert_equal('b', @")
+ " check for a word movement handling an empty line properly
+ normal 1G$vwy
+ call assert_equal("a\n\n", @")
+
+ " copy using 'b' command
+ %d
+ " non-empty blank line at the start of file
+ call setline(1, [' ', 'foo bar'])
+ normal 2Gyb
+ call assert_equal(" \n", @")
+ " try to copy backwards from the start of the file
+ call setline(1, ['one two', 'foo bar'])
+ call assert_beeps('normal ggyb')
+ " 'b' command should stop at an empty line
+ call setline(1, ['one two', '', 'foo bar'])
+ normal 3Gyb
+ call assert_equal("\n", @")
+ normal 3Gy2b
+ call assert_equal("two\n", @")
+ " 'b' command should not stop at a non-empty blank line
+ call setline(1, ['one two', ' ', 'foo bar'])
+ normal 3Gyb
+ call assert_equal("two\n ", @")
+
+ close!
+endfunc
+
+" Test for 'scrolloff' with a long line that doesn't fit in the screen
+func Test_normal_scroloff()
+ 10new
+ 80vnew
+ call setline(1, repeat('a', 1000))
+ set scrolloff=10
+ normal gg10gj
+ call assert_equal(8, winline())
+ normal 10gj
+ call assert_equal(10, winline())
+ normal 10gk
+ call assert_equal(3, winline())
+ set scrolloff&
+ close!
+endfunc
+
+" Test for vertical scrolling with CTRL-F and CTRL-B with a long line
+func Test_normal_vert_scroll_longline()
+ 10new
+ 80vnew
+ call setline(1, range(1, 10))
+ call append(5, repeat('a', 1000))
+ exe "normal gg\<C-F>"
+ call assert_equal(6, line('.'))
+ exe "normal \<C-F>\<C-F>"
+ call assert_equal(11, line('.'))
+ call assert_equal(1, winline())
+ exe "normal \<C-B>"
+ call assert_equal(10, line('.'))
+ call assert_equal(3, winline())
+ exe "normal \<C-B>\<C-B>"
+ call assert_equal(5, line('.'))
+ call assert_equal(5, winline())
+ close!
endfunc
" Some commands like yy, cc, dd, >>, << and !! accept a count after
@@ -2759,4 +3309,37 @@ func Test_normal_count_after_operator()
bw!
endfunc
+func Test_normal_gj_on_extra_wide_char()
+ new | 25vsp
+ let text='1 foooooooo ar e ins‍zwe1 foooooooo ins‍zwei' .
+ \ ' i drei vier fünf sechs sieben acht un zehn elf zwöfl' .
+ \ ' dreizehn v ierzehn fünfzehn'
+ put =text
+ call cursor(2,1)
+ norm! gj
+ call assert_equal([0,2,25,0], getpos('.'))
+ bw!
+endfunc
+
+func Test_normal_count_out_of_range()
+ new
+ call setline(1, 'text')
+ normal 44444444444|
+ call assert_equal(999999999, v:count)
+ normal 444444444444|
+ call assert_equal(999999999, v:count)
+ normal 4444444444444|
+ call assert_equal(999999999, v:count)
+ normal 4444444444444444444|
+ call assert_equal(999999999, v:count)
+
+ normal 9y99999999|
+ call assert_equal(899999991, v:count)
+ normal 10y99999999|
+ call assert_equal(999999999, v:count)
+ normal 44444444444y44444444444|
+ call assert_equal(999999999, v:count)
+ bwipe!
+endfunc
+
" vim: shiftwidth=2 sts=2 expandtab
diff --git a/src/nvim/testdir/test_number.vim b/src/nvim/testdir/test_number.vim
index d737ebe9f0..521b0cf706 100644
--- a/src/nvim/testdir/test_number.vim
+++ b/src/nvim/testdir/test_number.vim
@@ -284,10 +284,10 @@ func Test_relativenumber_colors()
" Default colors
call VerifyScreenDump(buf, 'Test_relnr_colors_1', {})
- call term_sendkeys(buf, ":hi LineNrAbove ctermfg=blue\<CR>")
+ call term_sendkeys(buf, ":hi LineNrAbove ctermfg=blue\<CR>:\<CR>")
call VerifyScreenDump(buf, 'Test_relnr_colors_2', {})
- call term_sendkeys(buf, ":hi LineNrBelow ctermfg=green\<CR>")
+ call term_sendkeys(buf, ":hi LineNrBelow ctermfg=green\<CR>:\<CR>")
call VerifyScreenDump(buf, 'Test_relnr_colors_3', {})
call term_sendkeys(buf, ":hi clear LineNrAbove\<CR>")
@@ -298,6 +298,31 @@ func Test_relativenumber_colors()
call delete('XTest_relnr')
endfunc
+func Test_relativenumber_callback()
+ CheckScreendump
+ CheckFeature timers
+
+ let lines =<< trim END
+ call setline(1, ['aaaaa', 'bbbbb', 'ccccc', 'ddddd'])
+ set relativenumber
+ call cursor(4, 1)
+
+ func Func(timer)
+ call cursor(1, 1)
+ endfunc
+
+ call timer_start(300, 'Func')
+ END
+ call writefile(lines, 'Xrnu_timer')
+
+ let buf = RunVimInTerminal('-S Xrnu_timer', #{rows: 8})
+ call TermWait(buf, 310)
+ call VerifyScreenDump(buf, 'Test_relativenumber_callback_1', {})
+
+ call StopVimInTerminal(buf)
+ call delete('Xrnu_timer')
+endfunc
+
" Test for displaying line numbers with 'rightleft'
func Test_number_rightleft()
CheckFeature rightleft
diff --git a/src/nvim/testdir/test_options.vim b/src/nvim/testdir/test_options.vim
index 5946732937..1f003041e6 100644
--- a/src/nvim/testdir/test_options.vim
+++ b/src/nvim/testdir/test_options.vim
@@ -22,16 +22,36 @@ func Test_whichwrap()
call assert_equal('h', &whichwrap)
set whichwrap&
-endfunction
+endfunc
-function! Test_isfname()
+func Test_isfname()
" This used to cause Vim to access uninitialized memory.
set isfname=
call assert_equal("~X", expand("~X"))
set isfname&
-endfunction
+endfunc
+
+" Test for getting the value of 'pastetoggle'
+func Test_pastetoggle()
+ " character with K_SPECIAL byte
+ let &pastetoggle = '…'
+ call assert_equal('…', &pastetoggle)
+ call assert_equal("\n pastetoggle=…", execute('set pastetoggle?'))
+
+ " modified character with K_SPECIAL byte
+ let &pastetoggle = '<M-…>'
+ call assert_equal('<M-…>', &pastetoggle)
+ call assert_equal("\n pastetoggle=<M-…>", execute('set pastetoggle?'))
+
+ " illegal bytes
+ let str = ":\x7f:\x80:\x90:\xd0:"
+ let &pastetoggle = str
+ call assert_equal(str, &pastetoggle)
+ call assert_equal("\n pastetoggle=" .. strtrans(str), execute('set pastetoggle?'))
+ unlet str
+endfunc
-function Test_wildchar()
+func Test_wildchar()
" Empty 'wildchar' used to access invalid memory.
call assert_fails('set wildchar=', 'E521:')
call assert_fails('set wildchar=abc', 'E521:')
@@ -42,7 +62,7 @@ function Test_wildchar()
let a=execute('set wildchar?')
call assert_equal("\n wildchar=<Esc>", a)
set wildchar&
-endfunction
+endfunc
func Test_wildoptions()
set wildoptions=
@@ -51,7 +71,7 @@ func Test_wildoptions()
call assert_equal('tagfile', &wildoptions)
endfunc
-function! Test_options()
+func Test_options_command()
let caught = 'ok'
try
options
@@ -78,6 +98,19 @@ function! Test_options()
" close option-window
close
+ " Open the option-window at the top.
+ set splitbelow
+ topleft options
+ call assert_equal(1, winnr())
+ close
+
+ " Open the option-window at the bottom.
+ set nosplitbelow
+ botright options
+ call assert_equal(winnr('$'), winnr())
+ close
+ set splitbelow&
+
" Open the option-window in a new tab.
tab options
" Check if the option-window is opened in a tab.
@@ -85,12 +118,18 @@ function! Test_options()
call assert_notequal('option-window', bufname(''))
normal gt
call assert_equal('option-window', bufname(''))
-
" close option-window
close
-endfunction
-function! Test_path_keep_commas()
+ " Open the options window browse
+ if has('browse')
+ browse set
+ call assert_equal('option-window', bufname(''))
+ close
+ endif
+endfunc
+
+func Test_path_keep_commas()
" Test that changing 'path' keeps two commas.
set path=foo,,bar
set path-=bar
@@ -98,7 +137,7 @@ function! Test_path_keep_commas()
call assert_equal('foo,,bar', &path)
set path&
-endfunction
+endfunc
func Test_filetype_valid()
set ft=valid_name
@@ -199,6 +238,12 @@ func Test_set_completion()
call feedkeys(":set di\<C-A>\<C-B>\"\<CR>", 'tx')
call assert_equal('"set dictionary diff diffexpr diffopt digraph directory display', @:)
+ call feedkeys(":setlocal di\<C-A>\<C-B>\"\<CR>", 'tx')
+ call assert_equal('"setlocal dictionary diff diffexpr diffopt digraph directory display', @:)
+
+ 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>
" vim displays the options names without "no" but completion uses "no...".
call feedkeys(":set nodi\<C-A>\<C-B>\"\<CR>", 'tx')
@@ -229,6 +274,7 @@ func Test_set_completion()
call feedkeys(":set tags=./\\\\ dif\<C-A>\<C-B>\"\<CR>", 'tx')
call assert_equal('"set tags=./\\ diff diffexpr diffopt', @:)
+
set tags&
" Expand values for 'filetype'
@@ -244,9 +290,10 @@ func Test_set_errors()
call assert_fails('set regexpengine=3', 'E474:')
call assert_fails('set history=10001', 'E474:')
call assert_fails('set numberwidth=21', 'E474:')
- call assert_fails('set colorcolumn=-a')
- call assert_fails('set colorcolumn=a')
- call assert_fails('set colorcolumn=1,')
+ call assert_fails('set colorcolumn=-a', 'E474:')
+ call assert_fails('set colorcolumn=a', 'E474:')
+ call assert_fails('set colorcolumn=1,', 'E474:')
+ call assert_fails('set colorcolumn=1;', 'E474:')
call assert_fails('set cmdheight=-1', 'E487:')
call assert_fails('set cmdwinheight=-1', 'E487:')
if has('conceal')
@@ -259,6 +306,8 @@ func Test_set_errors()
call assert_fails('set shiftwidth=-1', 'E487:')
call assert_fails('set sidescroll=-1', 'E487:')
call assert_fails('set tabstop=-1', 'E487:')
+ call assert_fails('set tabstop=10000', 'E474:')
+ call assert_fails('set tabstop=5500000000', 'E474:')
call assert_fails('set textwidth=-1', 'E487:')
call assert_fails('set timeoutlen=-1', 'E487:')
call assert_fails('set updatecount=-1', 'E487:')
@@ -279,17 +328,29 @@ func Test_set_errors()
call assert_fails('set rulerformat=%15(%%', 'E542:')
call assert_fails('set statusline=%$', 'E539:')
call assert_fails('set statusline=%{', 'E540:')
+ call assert_fails('set statusline=%{%', 'E540:')
+ call assert_fails('set statusline=%{%}', 'E539:')
call assert_fails('set statusline=%(', 'E542:')
call assert_fails('set statusline=%)', 'E542:')
+ call assert_fails('set tabline=%$', 'E539:')
+ call assert_fails('set tabline=%{', 'E540:')
+ call assert_fails('set tabline=%{%', 'E540:')
+ call assert_fails('set tabline=%{%}', 'E539:')
+ call assert_fails('set tabline=%(', 'E542:')
+ call assert_fails('set tabline=%)', 'E542:')
if has('cursorshape')
" This invalid value for 'guicursor' used to cause Vim to crash.
call assert_fails('set guicursor=i-ci,r-cr:h', 'E545:')
call assert_fails('set guicursor=i-ci', 'E545:')
call assert_fails('set guicursor=x', 'E545:')
+ call assert_fails('set guicursor=x:', 'E546:')
call assert_fails('set guicursor=r-cr:horx', 'E548:')
call assert_fails('set guicursor=r-cr:hor0', 'E549:')
endif
+ if has('mouseshape')
+ call assert_fails('se mouseshape=i-r:x', 'E547:')
+ endif
call assert_fails('set backupext=~ patchmode=~', 'E589:')
call assert_fails('set winminheight=10 winheight=9', 'E591:')
call assert_fails('set winminwidth=10 winwidth=9', 'E592:')
@@ -312,21 +373,50 @@ func Test_set_errors()
set modifiable&
endfunc
+func CheckWasSet(name)
+ let verb_cm = execute('verbose set ' .. a:name .. '?')
+ call assert_match('Last set from.*test_options.vim', verb_cm)
+endfunc
+func CheckWasNotSet(name)
+ let verb_cm = execute('verbose set ' .. a:name .. '?')
+ call assert_notmatch('Last set from', verb_cm)
+endfunc
+
" Must be executed before other tests that set 'term'.
func Test_000_term_option_verbose()
if has('nvim') || has('gui_running')
return
endif
- let verb_cm = execute('verbose set t_cm')
- call assert_notmatch('Last set from', verb_cm)
+
+ call CheckWasNotSet('t_cm')
let term_save = &term
set term=ansi
- let verb_cm = execute('verbose set t_cm')
- call assert_match('Last set from.*test_options.vim', verb_cm)
+ call CheckWasSet('t_cm')
let &term = term_save
endfunc
+func Test_copy_context()
+ setlocal list
+ call CheckWasSet('list')
+ split
+ call CheckWasSet('list')
+ quit
+ setlocal nolist
+
+ set ai
+ call CheckWasSet('ai')
+ set filetype=perl
+ call CheckWasSet('filetype')
+ set fo=tcroq
+ call CheckWasSet('fo')
+
+ split Xsomebuf
+ call CheckWasSet('ai')
+ call CheckWasNotSet('filetype')
+ call CheckWasSet('fo')
+endfunc
+
func Test_set_ttytype()
" Nvim does not support 'ttytype'.
if !has('nvim') && !has('gui_running') && has('unix')
@@ -368,10 +458,19 @@ func Test_set_all()
set tw& iskeyword& splitbelow&
endfunc
+func Test_set_one_column()
+ let out_mult = execute('set all')->split("\n")
+ let out_one = execute('set! all')->split("\n")
+ " one column should be two to four times as many lines
+ call assert_inrange(len(out_mult) * 2, len(out_mult) * 4, len(out_one))
+endfunc
+
func Test_set_values()
- " The file is only generated when running "make test" in the src directory.
+ " opt_test.vim is generated from ../optiondefs.h using gen_opt_test.vim
if filereadable('opt_test.vim')
source opt_test.vim
+ else
+ throw 'Skipped: opt_test.vim does not exist'
endif
endfunc
@@ -538,7 +637,7 @@ func Test_copy_winopt()
call assert_equal(4,&numberwidth)
bw!
- set nohidden
+ set hidden&
endfunc
func Test_shortmess_F()
@@ -644,7 +743,62 @@ func Test_buftype()
call setline(1, ['L1'])
set buftype=nowrite
call assert_fails('write', 'E382:')
- close!
+
+ " for val in ['', 'nofile', 'nowrite', 'acwrite', 'quickfix', 'help', 'terminal', 'prompt', 'popup']
+ for val in ['', 'nofile', 'nowrite', 'acwrite', 'quickfix', 'help', 'prompt']
+ exe 'set buftype=' .. val
+ call writefile(['something'], 'XBuftype')
+ call assert_fails('write XBuftype', 'E13:', 'with buftype=' .. val)
+ endfor
+
+ call delete('XBuftype')
+ bwipe!
+endfunc
+
+" Test for the 'shell' option
+func Test_shell()
+ throw 'Skipped: Nvim does not have :shell'
+ CheckUnix
+ let save_shell = &shell
+ set shell=
+ call assert_fails('shell', 'E91:')
+ let &shell = save_shell
+endfunc
+
+" Test for the 'shellquote' option
+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 'rightleftcmd' option
+func Test_rightleftcmd()
+ CheckFeature rightleft
+ set rightleft
+ set rightleftcmd
+
+ let g:l = []
+ func AddPos()
+ call add(g:l, screencol())
+ return ''
+ endfunc
+ cmap <expr> <F2> AddPos()
+
+ call feedkeys("/\<F2>abc\<Left>\<F2>\<Right>\<Right>\<F2>" ..
+ \ "\<Left>\<F2>\<Esc>", 'xt')
+ call assert_equal([&co - 1, &co - 4, &co - 2, &co - 3], g:l)
+
+ cunmap <F2>
+ unlet g:l
+ set rightleftcmd&
+ set rightleft&
endfunc
" Test for setting option values using v:false and v:true
@@ -661,6 +815,47 @@ func Test_opt_boolean()
set number&
endfunc
+" Test for the 'window' option
+func Test_window_opt()
+ " Needs only one open widow
+ %bw!
+ call setline(1, range(1, 8))
+ set window=5
+ exe "normal \<C-F>"
+ call assert_equal(4, line('w0'))
+ exe "normal \<C-F>"
+ call assert_equal(7, line('w0'))
+ exe "normal \<C-F>"
+ call assert_equal(8, line('w0'))
+ exe "normal \<C-B>"
+ call assert_equal(5, line('w0'))
+ exe "normal \<C-B>"
+ call assert_equal(2, line('w0'))
+ exe "normal \<C-B>"
+ call assert_equal(1, line('w0'))
+ set window=1
+ exe "normal gg\<C-F>"
+ call assert_equal(2, line('w0'))
+ exe "normal \<C-F>"
+ call assert_equal(3, line('w0'))
+ exe "normal \<C-B>"
+ call assert_equal(2, line('w0'))
+ exe "normal \<C-B>"
+ call assert_equal(1, line('w0'))
+ enew!
+ set window&
+endfunc
+
+" Test for the 'winminheight' option
+func Test_opt_winminheight()
+ only!
+ let &winheight = &lines + 4
+ call assert_fails('let &winminheight = &lines + 2', 'E36:')
+ call assert_true(&winminheight <= &lines)
+ set winminheight&
+ set winheight&
+endfunc
+
func Test_opt_winminheight_term()
" See test/functional/legacy/options_spec.lua
CheckRunVimInTerminal
@@ -704,6 +899,16 @@ func Test_opt_winminheight_term_tabs()
call delete('Xwinminheight')
endfunc
+" Test for the 'winminwidth' option
+func Test_opt_winminwidth()
+ only!
+ let &winwidth = &columns + 4
+ call assert_fails('let &winminwidth = &columns + 2', 'E36:')
+ call assert_true(&winminwidth <= &columns)
+ set winminwidth&
+ set winwidth&
+endfunc
+
" Test for setting option value containing spaces with isfname+=32
func Test_isfname_with_options()
set isfname+=32
@@ -753,4 +958,17 @@ func Test_opt_cdhome()
set cdhome&
endfunc
+func Test_switchbuf_reset()
+ set switchbuf=useopen
+ sblast
+ call assert_equal(1, winnr('$'))
+ set all&
+ " Nvim has a different default for 'switchbuf'
+ " call assert_equal('', &switchbuf)
+ call assert_equal('uselast', &switchbuf)
+ sblast
+ call assert_equal(2, winnr('$'))
+ only!
+endfunc
+
" vim: shiftwidth=2 sts=2 expandtab
diff --git a/src/nvim/testdir/test_packadd.vim b/src/nvim/testdir/test_packadd.vim
new file mode 100644
index 0000000000..fcb8b8033b
--- /dev/null
+++ b/src/nvim/testdir/test_packadd.vim
@@ -0,0 +1,361 @@
+" Tests for 'packpath' and :packadd
+
+
+func SetUp()
+ let s:topdir = getcwd() . '/Xdir'
+ exe 'set packpath=' . s:topdir
+ let s:plugdir = s:topdir . '/pack/mine/opt/mytest'
+endfunc
+
+func TearDown()
+ call delete(s:topdir, 'rf')
+endfunc
+
+func Test_packadd()
+ if !exists('s:plugdir')
+ echomsg 'when running this test manually, call SetUp() first'
+ return
+ endif
+
+ call mkdir(s:plugdir . '/plugin/also', 'p')
+ call mkdir(s:plugdir . '/ftdetect', 'p')
+ call mkdir(s:plugdir . '/after', 'p')
+ set rtp&
+ let rtp = &rtp
+ filetype on
+
+ let rtp_entries = split(rtp, ',')
+ for entry in rtp_entries
+ if entry =~? '\<after\>'
+ let first_after_entry = entry
+ break
+ endif
+ endfor
+
+ exe 'split ' . s:plugdir . '/plugin/test.vim'
+ call setline(1, 'let g:plugin_works = 42')
+ wq
+
+ exe 'split ' . s:plugdir . '/plugin/also/loaded.vim'
+ call setline(1, 'let g:plugin_also_works = 77')
+ wq
+
+ exe 'split ' . s:plugdir . '/ftdetect/test.vim'
+ call setline(1, 'let g:ftdetect_works = 17')
+ wq
+
+ packadd mytest
+
+ call assert_equal(42, g:plugin_works)
+ call assert_equal(77, g:plugin_also_works)
+ call assert_equal(17, g:ftdetect_works)
+ call assert_true(len(&rtp) > len(rtp))
+ call assert_match('/testdir/Xdir/pack/mine/opt/mytest\($\|,\)', &rtp)
+
+ let new_after = match(&rtp, '/testdir/Xdir/pack/mine/opt/mytest/after,')
+ let forwarded = substitute(first_after_entry, '\\', '[/\\\\]', 'g')
+ let old_after = match(&rtp, ',' . forwarded . '\>')
+ call assert_true(new_after > 0, 'rtp is ' . &rtp)
+ call assert_true(old_after > 0, 'match ' . forwarded . ' in ' . &rtp)
+ call assert_true(new_after < old_after, 'rtp is ' . &rtp)
+
+ " NOTE: '/.../opt/myte' forwardly matches with '/.../opt/mytest'
+ call mkdir(fnamemodify(s:plugdir, ':h') . '/myte', 'p')
+ let rtp = &rtp
+ packadd myte
+
+ " Check the path of 'myte' is added
+ call assert_true(len(&rtp) > len(rtp))
+ call assert_match('/testdir/Xdir/pack/mine/opt/myte\($\|,\)', &rtp)
+
+ " Check exception
+ call assert_fails("packadd directorynotfound", 'E919:')
+ call assert_fails("packadd", 'E471:')
+endfunc
+
+func Test_packadd_start()
+ let plugdir = s:topdir . '/pack/mine/start/other'
+ call mkdir(plugdir . '/plugin', 'p')
+ set rtp&
+ let rtp = &rtp
+ filetype on
+
+ exe 'split ' . plugdir . '/plugin/test.vim'
+ call setline(1, 'let g:plugin_works = 24')
+ wq
+
+ packadd other
+
+ call assert_equal(24, g:plugin_works)
+ call assert_true(len(&rtp) > len(rtp))
+ call assert_match('/testdir/Xdir/pack/mine/start/other\($\|,\)', &rtp)
+endfunc
+
+func Test_packadd_noload()
+ call mkdir(s:plugdir . '/plugin', 'p')
+ call mkdir(s:plugdir . '/syntax', 'p')
+ set rtp&
+ let rtp = &rtp
+
+ exe 'split ' . s:plugdir . '/plugin/test.vim'
+ call setline(1, 'let g:plugin_works = 42')
+ wq
+ let g:plugin_works = 0
+
+ packadd! mytest
+
+ call assert_true(len(&rtp) > len(rtp))
+ call assert_match('testdir/Xdir/pack/mine/opt/mytest\($\|,\)', &rtp)
+ call assert_equal(0, g:plugin_works)
+
+ " check the path is not added twice
+ let new_rtp = &rtp
+ packadd! mytest
+ call assert_equal(new_rtp, &rtp)
+endfunc
+
+func Test_packadd_symlink_dir()
+ if !has('unix')
+ return
+ endif
+ let top2_dir = s:topdir . '/Xdir2'
+ let real_dir = s:topdir . '/Xsym'
+ call mkdir(real_dir, 'p')
+ exec "silent !ln -s Xsym" top2_dir
+ let &rtp = top2_dir . ',' . top2_dir . '/after'
+ let &packpath = &rtp
+
+ let s:plugdir = top2_dir . '/pack/mine/opt/mytest'
+ call mkdir(s:plugdir . '/plugin', 'p')
+
+ exe 'split ' . s:plugdir . '/plugin/test.vim'
+ call setline(1, 'let g:plugin_works = 44')
+ wq
+ let g:plugin_works = 0
+
+ packadd mytest
+
+ " Must have been inserted in the middle, not at the end
+ call assert_match('/pack/mine/opt/mytest,', &rtp)
+ call assert_equal(44, g:plugin_works)
+
+ " No change when doing it again.
+ let rtp_before = &rtp
+ packadd mytest
+ call assert_equal(rtp_before, &rtp)
+
+ set rtp&
+ let rtp = &rtp
+ exec "silent !rm" top2_dir
+endfunc
+
+func Test_packadd_symlink_dir2()
+ if !has('unix')
+ return
+ endif
+ let top2_dir = s:topdir . '/Xdir2'
+ let real_dir = s:topdir . '/Xsym/pack'
+ call mkdir(top2_dir, 'p')
+ call mkdir(real_dir, 'p')
+ let &rtp = top2_dir . ',' . top2_dir . '/after'
+ let &packpath = &rtp
+
+ exec "silent !ln -s ../Xsym/pack" top2_dir . '/pack'
+ let s:plugdir = top2_dir . '/pack/mine/opt/mytest'
+ call mkdir(s:plugdir . '/plugin', 'p')
+
+ exe 'split ' . s:plugdir . '/plugin/test.vim'
+ call setline(1, 'let g:plugin_works = 48')
+ wq
+ let g:plugin_works = 0
+
+ packadd mytest
+
+ " Must have been inserted in the middle, not at the end
+ call assert_match('/Xdir2/pack/mine/opt/mytest,', &rtp)
+ call assert_equal(48, g:plugin_works)
+
+ " No change when doing it again.
+ let rtp_before = &rtp
+ packadd mytest
+ call assert_equal(rtp_before, &rtp)
+
+ set rtp&
+ let rtp = &rtp
+ exec "silent !rm" top2_dir . '/pack'
+ exec "silent !rmdir" top2_dir
+endfunc
+
+" Check command-line completion for 'packadd'
+func Test_packadd_completion()
+ let optdir1 = &packpath . '/pack/mine/opt'
+ let optdir2 = &packpath . '/pack/candidate/opt'
+
+ call mkdir(optdir1 . '/pluginA', 'p')
+ call mkdir(optdir1 . '/pluginC', 'p')
+ call mkdir(optdir2 . '/pluginB', 'p')
+ call mkdir(optdir2 . '/pluginC', 'p')
+
+ let li = []
+ call feedkeys(":packadd \<Tab>')\<C-B>call add(li, '\<CR>", 't')
+ call feedkeys(":packadd " . repeat("\<Tab>", 2) . "')\<C-B>call add(li, '\<CR>", 't')
+ call feedkeys(":packadd " . repeat("\<Tab>", 3) . "')\<C-B>call add(li, '\<CR>", 't')
+ call feedkeys(":packadd " . repeat("\<Tab>", 4) . "')\<C-B>call add(li, '\<CR>", 'tx')
+ call assert_equal("packadd pluginA", li[0])
+ call assert_equal("packadd pluginB", li[1])
+ call assert_equal("packadd pluginC", li[2])
+ call assert_equal("packadd ", li[3])
+endfunc
+
+func Test_packloadall()
+ " plugin foo with an autoload directory
+ let fooplugindir = &packpath . '/pack/mine/start/foo/plugin'
+ call mkdir(fooplugindir, 'p')
+ call writefile(['let g:plugin_foo_number = 1234',
+ \ 'let g:plugin_foo_auto = bbb#value',
+ \ 'let g:plugin_extra_auto = extra#value'], fooplugindir . '/bar.vim')
+ let fooautodir = &packpath . '/pack/mine/start/foo/autoload'
+ call mkdir(fooautodir, 'p')
+ call writefile(['let bar#value = 77'], fooautodir . '/bar.vim')
+
+ " plugin aaa with an autoload directory
+ let aaaplugindir = &packpath . '/pack/mine/start/aaa/plugin'
+ call mkdir(aaaplugindir, 'p')
+ call writefile(['let g:plugin_aaa_number = 333',
+ \ 'let g:plugin_aaa_auto = bar#value'], aaaplugindir . '/bbb.vim')
+ let aaaautodir = &packpath . '/pack/mine/start/aaa/autoload'
+ call mkdir(aaaautodir, 'p')
+ call writefile(['let bbb#value = 55'], aaaautodir . '/bbb.vim')
+
+ " plugin extra with only an autoload directory
+ let extraautodir = &packpath . '/pack/mine/start/extra/autoload'
+ call mkdir(extraautodir, 'p')
+ call writefile(['let extra#value = 99'], extraautodir . '/extra.vim')
+
+ packloadall
+ call assert_equal(1234, g:plugin_foo_number)
+ call assert_equal(55, g:plugin_foo_auto)
+ call assert_equal(99, g:plugin_extra_auto)
+ call assert_equal(333, g:plugin_aaa_number)
+ call assert_equal(77, g:plugin_aaa_auto)
+
+ " only works once
+ call writefile(['let g:plugin_bar_number = 4321'], fooplugindir . '/bar2.vim')
+ packloadall
+ call assert_false(exists('g:plugin_bar_number'))
+
+ " works when ! used
+ packloadall!
+ call assert_equal(4321, g:plugin_bar_number)
+endfunc
+
+func Test_helptags()
+ let docdir1 = &packpath . '/pack/mine/start/foo/doc'
+ let docdir2 = &packpath . '/pack/mine/start/bar/doc'
+ call mkdir(docdir1, 'p')
+ call mkdir(docdir2, 'p')
+ call writefile(['look here: *look-here*'], docdir1 . '/bar.txt')
+ call writefile(['look away: *look-away*'], docdir2 . '/foo.txt')
+ exe 'set rtp=' . &packpath . '/pack/mine/start/foo,' . &packpath . '/pack/mine/start/bar'
+
+ helptags ALL
+
+ let tags1 = readfile(docdir1 . '/tags')
+ call assert_match('look-here', tags1[0])
+ let tags2 = readfile(docdir2 . '/tags')
+ call assert_match('look-away', tags2[0])
+
+ call assert_fails('helptags abcxyz', 'E150:')
+endfunc
+
+func Test_colorscheme()
+ let colordirrun = &packpath . '/runtime/colors'
+ let colordirstart = &packpath . '/pack/mine/start/foo/colors'
+ let colordiropt = &packpath . '/pack/mine/opt/bar/colors'
+ call mkdir(colordirrun, 'p')
+ call mkdir(colordirstart, 'p')
+ call mkdir(colordiropt, 'p')
+ call writefile(['let g:found_one = 1'], colordirrun . '/one.vim')
+ call writefile(['let g:found_two = 1'], colordirstart . '/two.vim')
+ call writefile(['let g:found_three = 1'], colordiropt . '/three.vim')
+ exe 'set rtp=' . &packpath . '/runtime'
+
+ colorscheme one
+ call assert_equal(1, g:found_one)
+ colorscheme two
+ call assert_equal(1, g:found_two)
+ colorscheme three
+ call assert_equal(1, g:found_three)
+endfunc
+
+func Test_colorscheme_completion()
+ let colordirrun = &packpath . '/runtime/colors'
+ let colordirstart = &packpath . '/pack/mine/start/foo/colors'
+ let colordiropt = &packpath . '/pack/mine/opt/bar/colors'
+ call mkdir(colordirrun, 'p')
+ call mkdir(colordirstart, 'p')
+ call mkdir(colordiropt, 'p')
+ call writefile(['let g:found_one = 1'], colordirrun . '/one.vim')
+ call writefile(['let g:found_two = 1'], colordirstart . '/two.vim')
+ call writefile(['let g:found_three = 1'], colordiropt . '/three.vim')
+ exe 'set rtp=' . &packpath . '/runtime'
+
+ let li=[]
+ call feedkeys(":colorscheme " . repeat("\<Tab>", 1) . "')\<C-B>call add(li, '\<CR>", 't')
+ call feedkeys(":colorscheme " . repeat("\<Tab>", 2) . "')\<C-B>call add(li, '\<CR>", 't')
+ call feedkeys(":colorscheme " . repeat("\<Tab>", 3) . "')\<C-B>call add(li, '\<CR>", 't')
+ call feedkeys(":colorscheme " . repeat("\<Tab>", 4) . "')\<C-B>call add(li, '\<CR>", 'tx')
+ call assert_equal("colorscheme one", li[0])
+ call assert_equal("colorscheme three", li[1])
+ call assert_equal("colorscheme two", li[2])
+ call assert_equal("colorscheme ", li[3])
+endfunc
+
+func Test_runtime()
+ let rundir = &packpath . '/runtime/extra'
+ let startdir = &packpath . '/pack/mine/start/foo/extra'
+ let optdir = &packpath . '/pack/mine/opt/bar/extra'
+ call mkdir(rundir, 'p')
+ call mkdir(startdir, 'p')
+ call mkdir(optdir, 'p')
+ call writefile(['let g:sequence .= "run"'], rundir . '/bar.vim')
+ call writefile(['let g:sequence .= "start"'], startdir . '/bar.vim')
+ call writefile(['let g:sequence .= "foostart"'], startdir . '/foo.vim')
+ call writefile(['let g:sequence .= "opt"'], optdir . '/bar.vim')
+ call writefile(['let g:sequence .= "xxxopt"'], optdir . '/xxx.vim')
+ exe 'set rtp=' . &packpath . '/runtime'
+
+ let g:sequence = ''
+ runtime extra/bar.vim
+ call assert_equal('run', g:sequence)
+ let g:sequence = ''
+ runtime START extra/bar.vim
+ call assert_equal('start', g:sequence)
+ let g:sequence = ''
+ runtime OPT extra/bar.vim
+ call assert_equal('opt', g:sequence)
+ let g:sequence = ''
+ runtime PACK extra/bar.vim
+ call assert_equal('start', g:sequence)
+ let g:sequence = ''
+ runtime! PACK extra/bar.vim
+ call assert_equal('startopt', g:sequence)
+ let g:sequence = ''
+ runtime PACK extra/xxx.vim
+ call assert_equal('xxxopt', g:sequence)
+
+ let g:sequence = ''
+ runtime ALL extra/bar.vim
+ call assert_equal('run', g:sequence)
+ let g:sequence = ''
+ runtime ALL extra/foo.vim
+ call assert_equal('foostart', g:sequence)
+ let g:sequence = ''
+ runtime! ALL extra/xxx.vim
+ call assert_equal('xxxopt', g:sequence)
+ let g:sequence = ''
+ runtime! ALL extra/bar.vim
+ call assert_equal('runstartopt', g:sequence)
+endfunc
+
+" vim: shiftwidth=2 sts=2 expandtab
diff --git a/src/nvim/testdir/test_perl.vim b/src/nvim/testdir/test_perl.vim
index b911a982f9..558d0a5d6b 100644
--- a/src/nvim/testdir/test_perl.vim
+++ b/src/nvim/testdir/test_perl.vim
@@ -1,8 +1,8 @@
" Tests for Perl interface
-if !has('perl') || has('win32')
- finish
-endif
+source check.vim
+CheckFeature perl
+CheckNotMSWindows
" FIXME: RunTest don't see any error when Perl abort...
perl $SIG{__WARN__} = sub { die "Unexpected warnings from perl: @_" };
diff --git a/src/nvim/testdir/test_plus_arg_edit.vim b/src/nvim/testdir/test_plus_arg_edit.vim
index e31680e7b6..c52044d064 100644
--- a/src/nvim/testdir/test_plus_arg_edit.vim
+++ b/src/nvim/testdir/test_plus_arg_edit.vim
@@ -18,7 +18,7 @@ func Test_edit_bad()
e! ++enc=utf8 Xfile
call assert_equal('[?][?][???][??]', getline(1))
- e! ++enc=utf8 ++bad=_ Xfile
+ e! ++encoding=utf8 ++bad=_ Xfile
call assert_equal('[_][_][___][__]', getline(1))
e! ++enc=utf8 ++bad=drop Xfile
@@ -32,3 +32,16 @@ func Test_edit_bad()
bw!
call delete('Xfile')
endfunc
+
+" Test for ++bin and ++nobin arguments
+func Test_binary_arg()
+ new
+ edit ++bin Xfile1
+ call assert_equal(1, &binary)
+ edit ++nobin Xfile2
+ call assert_equal(0, &binary)
+ call assert_fails('edit ++binabc Xfile3', 'E474:')
+ close!
+endfunc
+
+" vim: shiftwidth=2 sts=2 expandtab
diff --git a/src/nvim/testdir/test_popup.vim b/src/nvim/testdir/test_popup.vim
index eb367cfe5c..a5e4be49f4 100644
--- a/src/nvim/testdir/test_popup.vim
+++ b/src/nvim/testdir/test_popup.vim
@@ -325,6 +325,21 @@ func Test_compl_vim_cmds_after_register_expr()
bwipe!
endfunc
+func Test_compl_ignore_mappings()
+ call setline(1, ['foo', 'bar', 'baz', 'foobar'])
+ inoremap <C-P> (C-P)
+ inoremap <C-N> (C-N)
+ normal! G
+ call feedkeys("o\<C-X>\<C-N>\<C-N>\<C-N>\<C-P>\<C-N>\<C-Y>", 'tx')
+ call assert_equal('baz', getline('.'))
+ " Also test with unsimplified keys
+ call feedkeys("o\<C-X>\<*C-N>\<*C-N>\<*C-N>\<*C-P>\<*C-N>\<C-Y>", 'tx')
+ call assert_equal('baz', getline('.'))
+ iunmap <C-P>
+ iunmap <C-N>
+ bwipe!
+endfunc
+
func DummyCompleteOne(findstart, base)
if a:findstart
return 0
@@ -334,19 +349,17 @@ func DummyCompleteOne(findstart, base)
endif
endfunc
-" Test that nothing happens if the 'completefunc' opens
-" a new window (no completion, no crash)
+" Test that nothing happens if the 'completefunc' tries to open
+" a new window (fails to open window, continues)
func Test_completefunc_opens_new_window_one()
new
let winid = win_getid()
setlocal completefunc=DummyCompleteOne
call setline(1, 'one')
/^one
- call assert_fails('call feedkeys("A\<C-X>\<C-U>\<C-N>\<Esc>", "x")', 'E839:')
- call assert_notequal(winid, win_getid())
- q!
+ call assert_fails('call feedkeys("A\<C-X>\<C-U>\<C-N>\<Esc>", "x")', 'E565:')
call assert_equal(winid, win_getid())
- call assert_equal('', getline(1))
+ call assert_equal('oneDEF', getline(1))
q!
endfunc
@@ -369,11 +382,11 @@ func Test_completefunc_opens_new_window_two()
setlocal completefunc=DummyCompleteTwo
call setline(1, 'two')
/^two
- call assert_fails('call feedkeys("A\<C-X>\<C-U>\<C-N>\<Esc>", "x")', 'E764:')
- call assert_notequal(winid, win_getid())
- q!
+ call assert_fails('call feedkeys("A\<C-X>\<C-U>\<C-N>\<Esc>", "x")', 'E565:')
call assert_equal(winid, win_getid())
- call assert_equal('two', getline(1))
+ " v8.2.1919 hasn't been ported yet
+ " call assert_equal('twodef', getline(1))
+ call assert_equal('twoDEF', getline(1))
q!
endfunc
@@ -642,8 +655,8 @@ func Test_complete_func_mess()
set completefunc=MessComplete
new
call setline(1, 'Ju')
- call feedkeys("A\<c-x>\<c-u>/\<esc>", 'tx')
- call assert_equal('Oct/Oct', getline(1))
+ call assert_fails('call feedkeys("A\<c-x>\<c-u>/\<esc>", "tx")', 'E565:')
+ call assert_equal('Jan/', getline(1))
bwipe!
set completefunc=
endfunc
@@ -898,7 +911,7 @@ func Test_popup_complete_backwards_ctrl_p()
bwipe!
endfunc
-fun! Test_complete_o_tab()
+func Test_complete_o_tab()
CheckFunction test_override
let s:o_char_pressed = 0
@@ -907,7 +920,7 @@ fun! Test_complete_o_tab()
let s:o_char_pressed = 0
call feedkeys("\<c-x>\<c-n>", 'i')
endif
- endf
+ endfunc
set completeopt=menu,noselect
new
@@ -926,7 +939,21 @@ fun! Test_complete_o_tab()
bwipe!
set completeopt&
delfunc s:act_on_text_changed
-endf
+endfunc
+
+func Test_menu_only_exists_in_terminal()
+ if !exists(':tlmenu') || has('gui_running')
+ return
+ endif
+ tlnoremenu &Edit.&Paste<Tab>"+gP <C-W>"+
+ aunmenu *
+ try
+ popup Edit
+ call assert_false(1, 'command should have failed')
+ catch
+ call assert_exception('E328:')
+ endtry
+endfunc
func Test_popup_complete_info_01()
new
diff --git a/src/nvim/testdir/test_profile.vim b/src/nvim/testdir/test_profile.vim
index 4b0097617e..fdb6f13e2b 100644
--- a/src/nvim/testdir/test_profile.vim
+++ b/src/nvim/testdir/test_profile.vim
@@ -1,8 +1,9 @@
" Test Vim profiler
-if !has('profile')
- finish
-endif
+source check.vim
+CheckFeature profile
+
+source shared.vim
source screendump.vim
func Test_profile_func()
@@ -37,7 +38,7 @@ func Test_profile_func()
[CODE]
call writefile(lines, 'Xprofile_func.vim')
- call system(v:progpath
+ call system(GetVimCommand()
\ . ' -es --clean'
\ . ' -c "so Xprofile_func.vim"'
\ . ' -c "qall!"')
@@ -124,8 +125,8 @@ func Test_profile_func_with_ifelse()
[CODE]
call writefile(lines, 'Xprofile_func.vim')
- call system(v:progpath
- \ . ' -es -u NONE -U NONE -i NONE --noplugin'
+ call system(GetVimCommand()
+ \ . ' -es -i NONE --noplugin'
\ . ' -c "profile start Xprofile_func.log"'
\ . ' -c "profile func Foo*"'
\ . ' -c "so Xprofile_func.vim"'
@@ -237,8 +238,8 @@ func Test_profile_func_with_trycatch()
[CODE]
call writefile(lines, 'Xprofile_func.vim')
- call system(v:progpath
- \ . ' -es -u NONE -U NONE -i NONE --noplugin'
+ call system(GetVimCommand()
+ \ . ' -es -i NONE --noplugin'
\ . ' -c "profile start Xprofile_func.log"'
\ . ' -c "profile func Foo*"'
\ . ' -c "so Xprofile_func.vim"'
@@ -324,8 +325,8 @@ func Test_profile_file()
[CODE]
call writefile(lines, 'Xprofile_file.vim')
- call system(v:progpath
- \ . ' -es --clean'
+ call system(GetVimCommandClean()
+ \ . ' -es'
\ . ' -c "profile start Xprofile_file.log"'
\ . ' -c "profile file Xprofile_file.vim"'
\ . ' -c "so Xprofile_file.vim"'
@@ -369,8 +370,8 @@ func Test_profile_file_with_cont()
\ ]
call writefile(lines, 'Xprofile_file.vim')
- call system(v:progpath
- \ . ' -es -u NONE -U NONE -i NONE --noplugin'
+ call system(GetVimCommandClean()
+ \ . ' -es'
\ . ' -c "profile start Xprofile_file.log"'
\ . ' -c "profile file Xprofile_file.vim"'
\ . ' -c "so Xprofile_file.vim"'
@@ -427,7 +428,7 @@ func Test_profile_truncate_mbyte()
\ ]
call writefile(lines, 'Xprofile_file.vim')
- call system(v:progpath
+ call system(GetVimCommandClean()
\ . ' -es --cmd "set enc=utf-8"'
\ . ' -c "profile start Xprofile_file.log"'
\ . ' -c "profile file Xprofile_file.vim"'
@@ -474,7 +475,7 @@ func Test_profdel_func()
call Foo3()
[CODE]
call writefile(lines, 'Xprofile_file.vim')
- call system(v:progpath . ' -es --clean -c "so Xprofile_file.vim" -c q')
+ call system(GetVimCommandClean() . ' -es -c "so Xprofile_file.vim" -c q')
call assert_equal(0, v:shell_error)
let lines = readfile('Xprofile_file.log')
@@ -509,7 +510,7 @@ func Test_profdel_star()
call Foo()
[CODE]
call writefile(lines, 'Xprofile_file.vim')
- call system(v:progpath . ' -es --clean -c "so Xprofile_file.vim" -c q')
+ call system(GetVimCommandClean() . ' -es -c "so Xprofile_file.vim" -c q')
call assert_equal(0, v:shell_error)
let lines = readfile('Xprofile_file.log')
diff --git a/src/nvim/testdir/test_put.vim b/src/nvim/testdir/test_put.vim
index 440717eaa8..97af3699a8 100644
--- a/src/nvim/testdir/test_put.vim
+++ b/src/nvim/testdir/test_put.vim
@@ -1,5 +1,7 @@
" Tests for put commands, e.g. ":put", "p", "gp", "P", "gP", etc.
+source check.vim
+
func Test_put_block()
new
call feedkeys("i\<C-V>u2500\<CR>x\<ESC>", 'x')
@@ -112,6 +114,93 @@ func Test_put_p_indent_visual()
bwipe!
endfunc
+" Test for deleting all the contents of a buffer with a put
+func Test_put_visual_delete_all_lines()
+ new
+ call setline(1, ['one', 'two', 'three'])
+ let @r = ''
+ normal! VG"rgp
+ call assert_equal(1, line('$'))
+ close!
+endfunc
+
+func Test_gp_with_count_leaves_cursor_at_end()
+ new
+ call setline(1, '<---->')
+ call setreg('@', "foo\nbar", 'c')
+ normal 1G3|3gp
+ call assert_equal([0, 4, 4, 0], getpos("."))
+ call assert_equal(['<--foo', 'barfoo', 'barfoo', 'bar-->'], getline(1, '$'))
+ call assert_equal([0, 4, 3, 0], getpos("']"))
+
+ bwipe!
+endfunc
+
+func Test_p_with_count_leaves_mark_at_end()
+ new
+ call setline(1, '<---->')
+ call setreg('@', "start\nend", 'c')
+ normal 1G3|3p
+ call assert_equal([0, 1, 4, 0], getpos("."))
+ call assert_equal(['<--start', 'endstart', 'endstart', 'end-->'], getline(1, '$'))
+ call assert_equal([0, 4, 3, 0], getpos("']"))
+
+ bwipe!
+endfunc
+
+func Test_very_large_count()
+ new
+ " total put-length (21474837 * 100) brings 32 bit int overflow
+ let @" = repeat('x', 100)
+ call assert_fails('norm 21474837p', 'E1240:')
+ bwipe!
+endfunc
+
+func Test_very_large_count_64bit()
+ throw 'Skipped: v:sizeoflong is N/A' " use legacy/put_spec.lua instead
+
+ if v:sizeoflong < 8
+ throw 'Skipped: only works with 64 bit long ints'
+ endif
+
+ new
+ let @" = repeat('x', 100)
+ call assert_fails('norm 999999999p', 'E1240:')
+ bwipe!
+endfunc
+
+func Test_very_large_count_block()
+ new
+ " total put-length (21474837 * 100) brings 32 bit int overflow
+ call setline(1, repeat('x', 100))
+ exe "norm \<C-V>99ly"
+ call assert_fails('norm 21474837p', 'E1240:')
+ bwipe!
+endfunc
+
+func Test_very_large_count_block_64bit()
+ throw 'Skipped: v:sizeoflong is N/A' " use legacy/put_spec.lua instead
+
+ if v:sizeoflong < 8
+ throw 'Skipped: only works with 64 bit long ints'
+ endif
+
+ new
+ call setline(1, repeat('x', 100))
+ exe "norm \<C-V>$y"
+ call assert_fails('norm 999999999p', 'E1240:')
+ bwipe!
+endfunc
+
+func Test_put_above_first_line()
+ new
+ let @" = 'text'
+ silent! normal 0o00
+ 0put
+ call assert_equal('text', getline(1))
+ bwipe!
+endfunc
+
func Test_multibyte_op_end_mark()
new
call setline(1, 'тест')
@@ -124,3 +213,27 @@ func Test_multibyte_op_end_mark()
call assert_equal([0, 2, 7, 0], getpos("']"))
bwipe!
endfunc
+
+" this was putting a mark before the start of a line
+func Test_put_empty_register()
+ new
+ norm yy
+ norm [Pi00ggv)s0
+ sil! norm [P
+ bwipe!
+endfunc
+
+" this was putting the end mark after the end of the line
+func Test_put_visual_mode()
+ edit! SomeNewBuffer
+ set selection=exclusive
+ exe "norm o\t"
+ m0
+ sil! norm  p p
+
+ bwipe!
+ set selection&
+endfunc
+
+
+" vim: shiftwidth=2 sts=2 expandtab
diff --git a/src/nvim/testdir/test_python2.vim b/src/nvim/testdir/test_python2.vim
index ae8bc57c7f..745b7da086 100644
--- a/src/nvim/testdir/test_python2.vim
+++ b/src/nvim/testdir/test_python2.vim
@@ -1,9 +1,8 @@
" Test for python 2 commands.
" TODO: move tests from test86.in here.
-if !has('python')
- finish
-endif
+source check.vim
+CheckFeature python
func Test_pydo()
" Check deleting lines does not trigger ml_get error.
diff --git a/src/nvim/testdir/test_python3.vim b/src/nvim/testdir/test_python3.vim
index 54da3d2eba..69f5f6dcc0 100644
--- a/src/nvim/testdir/test_python3.vim
+++ b/src/nvim/testdir/test_python3.vim
@@ -1,9 +1,8 @@
" Test for python 3 commands.
" TODO: move tests from test87.in here.
-if !has('python3')
- finish
-endif
+source check.vim
+CheckFeature python3
func Test_py3do()
" Check deleting lines does not trigger an ml_get error.
@@ -69,6 +68,7 @@ func Test_vim_function()
endfunc
func Test_skipped_python3_command_does_not_affect_pyxversion()
+ throw 'skipped: Nvim hardcodes pyxversion=3'
set pyxversion=0
if 0
python3 import vim
diff --git a/src/nvim/testdir/test_pyx2.vim b/src/nvim/testdir/test_pyx2.vim
index b6ed80f842..eee825fa9b 100644
--- a/src/nvim/testdir/test_pyx2.vim
+++ b/src/nvim/testdir/test_pyx2.vim
@@ -1,9 +1,8 @@
" Test for pyx* commands and functions with Python 2.
+source check.vim
+CheckFeature python
set pyx=2
-if !has('python')
- finish
-endif
let s:py2pattern = '^2\.[0-7]\.\d\+'
let s:py3pattern = '^3\.\d\+\.\d\+'
diff --git a/src/nvim/testdir/test_pyx3.vim b/src/nvim/testdir/test_pyx3.vim
index 2044af3abe..db39f5134a 100644
--- a/src/nvim/testdir/test_pyx3.vim
+++ b/src/nvim/testdir/test_pyx3.vim
@@ -1,9 +1,8 @@
" Test for pyx* commands and functions with Python 3.
set pyx=3
-if !has('python3')
- finish
-endif
+source check.vim
+CheckFeature python3
let s:py2pattern = '^2\.[0-7]\.\d\+'
let s:py3pattern = '^3\.\d\+\.\d\+'
diff --git a/src/nvim/testdir/test_quickfix.vim b/src/nvim/testdir/test_quickfix.vim
index 6db679c5f9..ddd4229f17 100644
--- a/src/nvim/testdir/test_quickfix.vim
+++ b/src/nvim/testdir/test_quickfix.vim
@@ -1,4 +1,4 @@
-" Test for the quickfix commands.
+" Test for the quickfix feature.
source check.vim
CheckFeature quickfix
@@ -32,7 +32,7 @@ func s:setup_commands(cchar)
command! -count -nargs=* -bang Xnfile <mods><count>cnfile<bang> <args>
command! -nargs=* -bang Xpfile <mods>cpfile<bang> <args>
command! -nargs=* Xexpr <mods>cexpr <args>
- command! -count -nargs=* Xvimgrep <mods> <count>vimgrep <args>
+ command! -count=999 -nargs=* Xvimgrep <mods> <count>vimgrep <args>
command! -nargs=* Xvimgrepadd <mods> vimgrepadd <args>
command! -nargs=* Xgrep <mods> grep <args>
command! -nargs=* Xgrepadd <mods> grepadd <args>
@@ -69,7 +69,7 @@ func s:setup_commands(cchar)
command! -count -nargs=* -bang Xnfile <mods><count>lnfile<bang> <args>
command! -nargs=* -bang Xpfile <mods>lpfile<bang> <args>
command! -nargs=* Xexpr <mods>lexpr <args>
- command! -count -nargs=* Xvimgrep <mods> <count>lvimgrep <args>
+ command! -count=999 -nargs=* Xvimgrep <mods> <count>lvimgrep <args>
command! -nargs=* Xvimgrepadd <mods> lvimgrepadd <args>
command! -nargs=* Xgrep <mods> lgrep <args>
command! -nargs=* Xgrepadd <mods> lgrepadd <args>
@@ -169,8 +169,8 @@ func XlistTests(cchar)
\ {'lnum':30,'col':15,'type':'W','filename':'Data/Text.hs','text':'FileWarning','nr':33,'valid':v:true}])
let l = split(execute('Xlist', ""), "\n")
call assert_equal([' 1 Data.Text:10 col 5 warning 11: ModuleWarning',
- \ ' 2 Data.Text:20 col 10 warning 22: ModuleWarning',
- \ ' 3 Data/Text.hs:30 col 15 warning 33: FileWarning'], l)
+ \ ' 2 Data.Text:20 col 10 warning 22: ModuleWarning',
+ \ ' 3 Data/Text.hs:30 col 15 warning 33: FileWarning'], l)
" For help entries in the quickfix list, only the filename without directory
" should be displayed
@@ -301,6 +301,23 @@ func XwindowTests(cchar)
call assert_equal(12, winwidth(0))
Xclose
+ " Horizontally or vertically splitting the quickfix window should create a
+ " normal window/buffer
+ Xopen
+ wincmd s
+ call assert_equal(0, getwininfo(win_getid())[0].quickfix)
+ call assert_equal(0, getwininfo(win_getid())[0].loclist)
+ call assert_notequal('quickfix', &buftype)
+ close
+ Xopen
+ wincmd v
+ call assert_equal(0, getwininfo(win_getid())[0].quickfix)
+ call assert_equal(0, getwininfo(win_getid())[0].loclist)
+ call assert_notequal('quickfix', &buftype)
+ close
+ Xopen
+ Xclose
+
if a:cchar == 'c'
" Opening the quickfix window in multiple tab pages should reuse the
" quickfix buffer
@@ -499,13 +516,14 @@ func Xtest_browse(cchar)
\ 'RegularLine2']
Xfirst
+ call assert_fails('-5Xcc', 'E16:')
call assert_fails('Xprev', 'E553')
call assert_fails('Xpfile', 'E553')
Xnfile
- call assert_equal('Xqftestfile2', bufname('%'))
+ call assert_equal('Xqftestfile2', @%)
call assert_equal(10, line('.'))
Xpfile
- call assert_equal('Xqftestfile1', bufname('%'))
+ call assert_equal('Xqftestfile1', @%)
call assert_equal(6, line('.'))
5Xcc
call assert_equal(5, g:Xgetlist({'idx':0}).idx)
@@ -521,7 +539,7 @@ func Xtest_browse(cchar)
call assert_equal(6, g:Xgetlist({'idx':0}).idx)
Xlast
Xprev
- call assert_equal('Xqftestfile2', bufname('%'))
+ call assert_equal('Xqftestfile2', @%)
call assert_equal(11, line('.'))
call assert_fails('Xnext', 'E553')
call assert_fails('Xnfile', 'E553')
@@ -534,14 +552,14 @@ func Xtest_browse(cchar)
endif
call assert_equal(6, g:Xgetlist({'idx':0}).idx)
Xrewind
- call assert_equal('Xqftestfile1', bufname('%'))
+ call assert_equal('Xqftestfile1', @%)
call assert_equal(5, line('.'))
10Xnext
- call assert_equal('Xqftestfile2', bufname('%'))
+ call assert_equal('Xqftestfile2', @%)
call assert_equal(11, line('.'))
10Xprev
- call assert_equal('Xqftestfile1', bufname('%'))
+ call assert_equal('Xqftestfile1', @%)
call assert_equal(5, line('.'))
" Jumping to an error from the error window using cc command
@@ -552,14 +570,23 @@ func Xtest_browse(cchar)
Xopen
10Xcc
call assert_equal(11, line('.'))
- call assert_equal('Xqftestfile2', bufname('%'))
+ call assert_equal('Xqftestfile2', @%)
+ Xopen
+ call cursor(2, 1)
+ if a:cchar == 'c'
+ .cc
+ else
+ .ll
+ endif
+ call assert_equal(6, line('.'))
+ call assert_equal('Xqftestfile1', @%)
" Jumping to an error from the error window (when only the error window is
" present)
Xopen | only
Xlast 1
call assert_equal(5, line('.'))
- call assert_equal('Xqftestfile1', bufname('%'))
+ call assert_equal('Xqftestfile1', @%)
Xexpr ""
call assert_fails('Xnext', 'E42:')
@@ -796,101 +823,102 @@ func ReadTestProtocol(name)
endfunc
func Test_locationlist()
- enew
+ enew
- augroup testgroup
- au!
- autocmd BufReadCmd test://* call ReadTestProtocol(expand("<amatch>"))
- augroup END
+ augroup testgroup
+ au!
+ autocmd BufReadCmd test://* call ReadTestProtocol(expand("<amatch>"))
+ augroup END
- let words = [ "foo", "bar", "baz", "quux", "shmoo", "spam", "eggs" ]
+ let words = [ "foo", "bar", "baz", "quux", "shmoo", "spam", "eggs" ]
- let qflist = []
- for word in words
- call add(qflist, {'filename': 'test://' . word . '.txt', 'text': 'file ' . word . '.txt', })
- " NOTE: problem 1:
- " intentionally not setting 'lnum' so that the quickfix entries are not
- " valid
- eval qflist->setloclist(0, ' ')
- endfor
+ let qflist = []
+ for word in words
+ call add(qflist, {'filename': 'test://' . word . '.txt', 'text': 'file ' . word . '.txt', })
+ " NOTE: problem 1:
+ " intentionally not setting 'lnum' so that the quickfix entries are not
+ " valid
+ eval qflist->setloclist(0, ' ')
+ endfor
- " Test A
- lrewind
- enew
- lopen
- 4lnext
- vert split
- wincmd L
- lopen
- wincmd p
- lnext
- let fileName = expand("%")
- wincmd p
- let locationListFileName = substitute(getline(line('.')), '\([^|]*\)|.*', '\1', '')
- let fileName = substitute(fileName, '\\', '/', 'g')
- let locationListFileName = substitute(locationListFileName, '\\', '/', 'g')
- call assert_equal("test://bar.txt", fileName)
- call assert_equal("test://bar.txt", locationListFileName)
+ " Test A
+ lrewind
+ enew
+ lopen
+ 4lnext
+ vert split
+ wincmd L
+ lopen
+ wincmd p
+ lnext
+ let fileName = expand("%")
+ wincmd p
+ let locationListFileName = substitute(getline(line('.')), '\([^|]*\)|.*', '\1', '')
+ let fileName = substitute(fileName, '\\', '/', 'g')
+ let locationListFileName = substitute(locationListFileName, '\\', '/', 'g')
+ call assert_equal("test://bar.txt", fileName)
+ call assert_equal("test://bar.txt", locationListFileName)
- wincmd n | only
+ wincmd n | only
- " Test B:
- lrewind
- lopen
- 2
- exe "normal \<CR>"
- wincmd p
- 3
- exe "normal \<CR>"
- wincmd p
- 4
- exe "normal \<CR>"
- call assert_equal(2, winnr('$'))
- wincmd n | only
+ " Test B:
+ lrewind
+ lopen
+ 2
+ exe "normal \<CR>"
+ wincmd p
+ 3
+ exe "normal \<CR>"
+ wincmd p
+ 4
+ exe "normal \<CR>"
+ call assert_equal(2, winnr('$'))
+ wincmd n | only
- " Test C:
- lrewind
- lopen
- " Let's move the location list window to the top to check whether it (the
- " first window found) will be reused when we try to open new windows:
- wincmd K
- 2
- exe "normal \<CR>"
- wincmd p
- 3
- exe "normal \<CR>"
- wincmd p
- 4
- exe "normal \<CR>"
- 1wincmd w
- call assert_equal('quickfix', &buftype)
- 2wincmd w
- let bufferName = expand("%")
- let bufferName = substitute(bufferName, '\\', '/', 'g')
- call assert_equal('test://quux.txt', bufferName)
+ " Test C:
+ lrewind
+ lopen
+ " Let's move the location list window to the top to check whether it (the
+ " first window found) will be reused when we try to open new windows:
+ wincmd K
+ 2
+ exe "normal \<CR>"
+ wincmd p
+ 3
+ exe "normal \<CR>"
+ wincmd p
+ 4
+ exe "normal \<CR>"
+ 1wincmd w
+ call assert_equal('quickfix', &buftype)
+ 2wincmd w
+ let bufferName = expand("%")
+ let bufferName = substitute(bufferName, '\\', '/', 'g')
+ call assert_equal('test://quux.txt', bufferName)
- wincmd n | only
+ wincmd n | only
- augroup! testgroup
+ augroup! testgroup
endfunc
func Test_locationlist_curwin_was_closed()
- augroup testgroup
- au!
- autocmd BufReadCmd test_curwin.txt call R(expand("<amatch>"))
- augroup END
+ augroup testgroup
+ au!
+ autocmd BufReadCmd test_curwin.txt call R(expand("<amatch>"))
+ augroup END
- func! R(n)
- quit
- endfunc
+ func! R(n)
+ quit
+ endfunc
- new
- let q = []
- call add(q, {'filename': 'test_curwin.txt' })
- call setloclist(0, q)
- call assert_fails('lrewind', 'E924:')
+ new
+ let q = []
+ call add(q, {'filename': 'test_curwin.txt' })
+ call setloclist(0, q)
+ call assert_fails('lrewind', 'E924:')
- augroup! testgroup
+ augroup! testgroup
+ delfunc R
endfunc
func Test_locationlist_cross_tab_jump()
@@ -1037,21 +1065,20 @@ func s:dir_stack_tests(cchar)
let save_efm=&efm
set efm=%DEntering\ dir\ '%f',%f:%l:%m,%XLeaving\ dir\ '%f'
- let lines =<< trim [DATA]
- 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
- [DATA]
+ 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'"
+ \]
Xexpr ""
for l in lines
@@ -1060,17 +1087,17 @@ func s:dir_stack_tests(cchar)
let qf = g:Xgetlist()
- call assert_equal(expand('dir1/a/habits2.txt'), bufname(qf[1].bufnr))
+ call assert_equal('dir1/a/habits2.txt', bufname(qf[1].bufnr))
call assert_equal(1, qf[1].lnum)
- call assert_equal(expand('dir1/a/b/habits3.txt'), bufname(qf[3].bufnr))
+ call assert_equal('dir1/a/b/habits3.txt', bufname(qf[3].bufnr))
call assert_equal(2, qf[3].lnum)
- call assert_equal(expand('dir1/a/habits2.txt'), bufname(qf[4].bufnr))
+ call assert_equal('dir1/a/habits2.txt', bufname(qf[4].bufnr))
call assert_equal(7, qf[4].lnum)
- call assert_equal(expand('dir1/c/habits4.txt'), bufname(qf[6].bufnr))
+ call assert_equal('dir1/c/habits4.txt', bufname(qf[6].bufnr))
call assert_equal(3, qf[6].lnum)
call assert_equal('habits1.txt', bufname(qf[9].bufnr))
call assert_equal(4, qf[9].lnum)
- call assert_equal(expand('dir2/habits5.txt'), bufname(qf[11].bufnr))
+ call assert_equal('dir2/habits5.txt', bufname(qf[11].bufnr))
call assert_equal(5, qf[11].lnum)
let &efm=save_efm
@@ -1085,19 +1112,18 @@ func Test_efm_dirstack()
call mkdir('dir1/c')
call mkdir('dir2')
- let lines =<< trim [DATA]
- 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
- [DATA]
+ 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"
+ \ ]
call writefile(lines, 'habits1.txt')
call writefile(lines, 'dir1/a/habits2.txt')
@@ -1219,6 +1245,7 @@ func Test_efm2()
(67,3) warning: 's' already defined
--
[DATA]
+
set efm=%+P[%f]%r,(%l\\,%c)%*[\ ]%t%*[^:]:\ %m,%+Q--%r
" To exercise the push/pop file functionality in quickfix, the test files
" need to be created.
@@ -1279,27 +1306,28 @@ func Test_efm2()
" Test for %A, %C and other formats
let lines =<< trim [DATA]
- ==============================================================
- FAIL: testGetTypeIdCachesResult (dbfacadeTest.DjsDBFacadeTest)
- --------------------------------------------------------------
- Traceback (most recent call last):
- File "unittests/dbfacadeTest.py", line 89, in testFoo
- self.assertEquals(34, dtid)
- File "/usr/lib/python2.2/unittest.py", line 286, in
- failUnlessEqual
- raise self.failureException, \\
- W:AssertionError: 34 != 33
-
- --------------------------------------------------------------
- Ran 27 tests in 0.063s
+ ==============================================================
+ FAIL: testGetTypeIdCachesResult (dbfacadeTest.DjsDBFacadeTest)
+ --------------------------------------------------------------
+ Traceback (most recent call last):
+ File "unittests/dbfacadeTest.py", line 89, in testFoo
+ self.assertEquals(34, dtid)
+ File "/usr/lib/python2.2/unittest.py", line 286, in
+ failUnlessEqual
+ raise self.failureException, \\
+ W:AssertionError: 34 != 33
+
+ --------------------------------------------------------------
+ Ran 27 tests in 0.063s
[DATA]
+
set efm=%C\ %.%#,%A\ \ File\ \"%f\"\\,\ line\ %l%.%#,%Z%[%^\ ]%\\@=%t:%m
cgetexpr lines
let l = getqflist()
call assert_equal(8, len(l))
call assert_equal(89, l[4].lnum)
call assert_equal(1, l[4].valid)
- call assert_equal(expand('unittests/dbfacadeTest.py'), bufname(l[4].bufnr))
+ call assert_equal('unittests/dbfacadeTest.py', bufname(l[4].bufnr))
call assert_equal('W', l[4].type)
" Test for %o
@@ -1384,6 +1412,29 @@ func Test_efm_error_type()
let &efm = save_efm
endfunc
+" Test for end_lnum ('%e') and end_col ('%k') fields in 'efm'
+func Test_efm_end_lnum_col()
+ let save_efm = &efm
+
+ " single line
+ set efm=%f:%l-%e:%c-%k:%t:%m
+ cexpr ["Xfile1:10-20:1-2:E:msg1", "Xfile1:20-30:2-3:W:msg2",]
+ let output = split(execute('clist'), "\n")
+ call assert_equal([
+ \ ' 1 Xfile1:10-20 col 1-2 error: msg1',
+ \ ' 2 Xfile1:20-30 col 2-3 warning: msg2'], output)
+
+ " 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 output = split(execute('clist'), "\n")
+ call assert_equal([
+ \ ' 1 Xfile1:14-24 col 1-2 error 1: msg1',
+ \ ' 2 Xfile1:24-34 col 3-4 error 2: msg2'], output)
+ let &efm = save_efm
+endfunc
+
func XquickfixChangedByAutocmd(cchar)
call s:setup_commands(a:cchar)
if a:cchar == 'c'
@@ -1632,7 +1683,7 @@ func XquickfixSetListWithAct(cchar)
\ {'filename': 'fnameD', 'text': 'D'},
\ {'filename': 'fnameE', 'text': 'E'}]
- " {action} is unspecified. Same as specifing ' '.
+ " {action} is unspecified. Same as specifying ' '.
new | only
silent! Xnewer 99
call g:Xsetlist(list1)
@@ -1910,10 +1961,11 @@ func Test_switchbuf()
copen | only
cfirst
call assert_equal(1, tabpagenr())
- call assert_equal('Xqftestfile1', bufname(''))
+ call assert_equal('Xqftestfile1', @%)
" If opening a file changes 'switchbuf', then the new value should be
" retained.
+ set modeline&vim
call writefile(["vim: switchbuf=split"], 'Xqftestfile1')
enew | only
set switchbuf&vim
@@ -1996,6 +2048,7 @@ func s:test_xgrep(cchar)
enew
set makeef=Temp_File_##
silent Xgrepadd GrepAdd_Test_Text: test_quickfix.vim
+ call assert_true(len(g:Xgetlist()) == 9)
" Try with 'grepprg' set to 'internal'
set grepprg=internal
@@ -2004,12 +2057,12 @@ func s:test_xgrep(cchar)
call assert_true(len(g:Xgetlist()) == 9)
set grepprg&vim
- call writefile(['Vim'], 'XtestTempFile')
- set makeef=XtestTempFile
- silent Xgrep Grep_Test_Text: test_quickfix.vim
- call assert_equal(5, len(g:Xgetlist()))
- call assert_false(filereadable('XtestTempFile'))
- set makeef&vim
+ call writefile(['Vim'], 'XtestTempFile')
+ set makeef=XtestTempFile
+ silent Xgrep Grep_Test_Text: test_quickfix.vim
+ call assert_equal(5, len(g:Xgetlist()))
+ call assert_false(filereadable('XtestTempFile'))
+ set makeef&vim
endfunc
func Test_grep()
@@ -2048,11 +2101,11 @@ func Test_two_windows()
laddexpr 'one.txt:3:one one one'
let loc_one = getloclist(one_id)
- call assert_equal(expand('Xone/a/one.txt'), bufname(loc_one[1].bufnr))
+ call assert_equal('Xone/a/one.txt', bufname(loc_one[1].bufnr))
call assert_equal(3, loc_one[1].lnum)
let loc_two = getloclist(two_id)
- call assert_equal(expand('Xtwo/a/two.txt'), bufname(loc_two[1].bufnr))
+ call assert_equal('Xtwo/a/two.txt', bufname(loc_two[1].bufnr))
call assert_equal(5, loc_two[1].lnum)
call win_gotoid(one_id)
@@ -2682,7 +2735,7 @@ func Test_cwindow_jump()
" Open a new window and create a location list
" Open the location list window and close the other window
" Jump to an entry.
- " Should create a new window and jump to the entry. The scrtach buffer
+ " Should create a new window and jump to the entry. The scratch buffer
" should not be used.
enew | only
set buftype=nofile
@@ -2715,7 +2768,26 @@ func Test_cwindow_jump()
call assert_true(winnr('$') == 2)
call assert_true(winnr() == 1)
- " Jumping to a file from the location list window should find a usuable
+ " open the quickfix buffer in two windows and jump to an entry. Should open
+ " the file in the first quickfix window.
+ enew | only
+ copen
+ let bnum = bufnr('')
+ exe 'sbuffer ' . bnum
+ wincmd b
+ cfirst
+ call assert_equal(2, winnr())
+ call assert_equal('F1', @%)
+ enew | only
+ exe 'sb' bnum
+ exe 'botright sb' bnum
+ wincmd t
+ clast
+ call assert_equal(2, winnr())
+ call assert_equal('quickfix', getwinvar(1, '&buftype'))
+ call assert_equal('quickfix', getwinvar(3, '&buftype'))
+
+ " Jumping to a file from the location list window should find a usable
" window by wrapping around the window list.
enew | only
call setloclist(0, [], 'f')
@@ -2795,7 +2867,7 @@ func XvimgrepTests(cchar)
edit +3 Xtestfile2
Xvimgrep +\cemacs+j Xtestfile1
let l = g:Xgetlist()
- call assert_equal('Xtestfile2', bufname(''))
+ call assert_equal('Xtestfile2', @%)
call assert_equal('Editor:Emacs EmAcS', l[0].text)
" Test for unloading a buffer after vimgrep searched the buffer
@@ -2837,6 +2909,21 @@ func Test_vimgrep_incsearch()
set noincsearch
endfunc
+" Test vimgrep with the last search pattern not set
+func Test_vimgrep_with_no_last_search_pat()
+ let lines =<< trim [SCRIPT]
+ call assert_fails('vimgrep // *', 'E35:')
+ call writefile(v:errors, 'Xresult')
+ qall!
+ [SCRIPT]
+ call writefile(lines, 'Xscript')
+ if RunVim([], [], '--clean -S Xscript')
+ call assert_equal([], readfile('Xresult'))
+ endif
+ call delete('Xscript')
+ call delete('Xresult')
+endfunc
+
" Test vimgrep without swap file
func Test_vimgrep_without_swap_file()
let lines =<< trim [SCRIPT]
@@ -3037,20 +3124,80 @@ func Test_file_from_copen()
endfunc
func Test_resize_from_copen()
+ augroup QF_Test
+ au!
+ au FileType qf resize 5
+ augroup END
+ try
+ " This should succeed without any exception. No other buffers are
+ " involved in the autocmd.
+ copen
+ finally
augroup QF_Test
- au!
- au FileType qf resize 5
+ au!
augroup END
- try
- " This should succeed without any exception. No other buffers are
- " involved in the autocmd.
- copen
- finally
- augroup QF_Test
- au!
- augroup END
- augroup! QF_Test
- endtry
+ augroup! QF_Test
+ endtry
+endfunc
+
+func Test_vimgrep_with_textlock()
+ new
+
+ " Simple way to execute something with "textlock" set.
+ " Check that vimgrep without jumping can be executed.
+ au InsertCharPre * vimgrep /RunTheTest/j runtest.vim
+ normal ax
+ let qflist = getqflist()
+ call assert_true(len(qflist) > 0)
+ call assert_match('RunTheTest', qflist[0].text)
+ call setqflist([], 'r')
+ au! InsertCharPre
+
+ " Check that vimgrepadd without jumping can be executed.
+ au InsertCharPre * vimgrepadd /RunTheTest/j runtest.vim
+ normal ax
+ let qflist = getqflist()
+ call assert_true(len(qflist) > 0)
+ call assert_match('RunTheTest', qflist[0].text)
+ call setqflist([], 'r')
+ au! InsertCharPre
+
+ " Check that lvimgrep without jumping can be executed.
+ au InsertCharPre * lvimgrep /RunTheTest/j runtest.vim
+ normal ax
+ let qflist = getloclist(0)
+ call assert_true(len(qflist) > 0)
+ call assert_match('RunTheTest', qflist[0].text)
+ call setloclist(0, [], 'r')
+ au! InsertCharPre
+
+ " Check that lvimgrepadd without jumping can be executed.
+ au InsertCharPre * lvimgrepadd /RunTheTest/j runtest.vim
+ normal ax
+ let qflist = getloclist(0)
+ call assert_true(len(qflist) > 0)
+ call assert_match('RunTheTest', qflist[0].text)
+ call setloclist(0, [], 'r')
+ au! InsertCharPre
+
+ " trying to jump will give an error
+ au InsertCharPre * vimgrep /RunTheTest/ runtest.vim
+ call assert_fails('normal ax', 'E565:')
+ au! InsertCharPre
+
+ au InsertCharPre * vimgrepadd /RunTheTest/ runtest.vim
+ call assert_fails('normal ax', 'E565:')
+ au! InsertCharPre
+
+ au InsertCharPre * lvimgrep /RunTheTest/ runtest.vim
+ call assert_fails('normal ax', 'E565:')
+ au! InsertCharPre
+
+ au InsertCharPre * lvimgrepadd /RunTheTest/ runtest.vim
+ call assert_fails('normal ax', 'E565:')
+ au! InsertCharPre
+
+ bwipe!
endfunc
" Tests for the quickfix buffer b:changedtick variable
@@ -3449,7 +3596,7 @@ func Xqfjump_tests(cchar)
Xopen | only
2Xnext
call assert_equal(3, g:Xgetlist({'idx' : 0}).idx)
- call assert_equal('F3', bufname('%'))
+ call assert_equal('F3', @%)
Xnext
call assert_equal(7, col('.'))
Xnext
@@ -3524,20 +3671,21 @@ func Xgetlist_empty_tests(cchar)
call assert_equal(0, g:Xgetlist({'changedtick' : 0}).changedtick)
if a:cchar == 'c'
call assert_equal({'context' : '', 'id' : 0, 'idx' : 0,
- \ 'items' : [], 'nr' : 0, 'size' : 0,
+ \ 'items' : [], 'nr' : 0, 'size' : 0, 'qfbufnr' : 0,
\ 'title' : '', 'winid' : 0, 'changedtick': 0,
\ 'quickfixtextfunc' : ''}, g:Xgetlist({'all' : 0}))
else
call assert_equal({'context' : '', 'id' : 0, 'idx' : 0,
\ 'items' : [], 'nr' : 0, 'size' : 0, 'title' : '',
\ 'winid' : 0, 'changedtick': 0, 'filewinid' : 0,
- \ 'quickfixtextfunc' : ''},
+ \ 'qfbufnr' : 0, 'quickfixtextfunc' : ''},
\ g:Xgetlist({'all' : 0}))
endif
" Quickfix window with empty stack
silent! Xopen
let qfwinid = (a:cchar == 'c') ? win_getid() : 0
+ let qfbufnr = (a:cchar == 'c') ? bufnr('') : 0
call assert_equal(qfwinid, g:Xgetlist({'winid' : 0}).winid)
Xclose
@@ -3569,12 +3717,12 @@ func Xgetlist_empty_tests(cchar)
if a:cchar == 'c'
call assert_equal({'context' : '', 'id' : 0, 'idx' : 0, 'items' : [],
\ 'nr' : 0, 'size' : 0, 'title' : '', 'winid' : 0,
- \ 'quickfixtextfunc' : '',
+ \ 'qfbufnr' : qfbufnr, 'quickfixtextfunc' : '',
\ 'changedtick' : 0}, g:Xgetlist({'id' : qfid, 'all' : 0}))
else
call assert_equal({'context' : '', 'id' : 0, 'idx' : 0, 'items' : [],
\ 'nr' : 0, 'size' : 0, 'title' : '', 'winid' : 0,
- \ 'changedtick' : 0, 'filewinid' : 0,
+ \ 'changedtick' : 0, 'filewinid' : 0, 'qfbufnr' : 0,
\ 'quickfixtextfunc' : ''},
\ g:Xgetlist({'id' : qfid, 'all' : 0}))
endif
@@ -3592,12 +3740,12 @@ func Xgetlist_empty_tests(cchar)
if a:cchar == 'c'
call assert_equal({'context' : '', 'id' : 0, 'idx' : 0, 'items' : [],
\ 'nr' : 0, 'size' : 0, 'title' : '', 'winid' : 0,
- \ 'changedtick' : 0,
+ \ 'changedtick' : 0, 'qfbufnr' : qfbufnr,
\ 'quickfixtextfunc' : ''}, g:Xgetlist({'nr' : 5, 'all' : 0}))
else
call assert_equal({'context' : '', 'id' : 0, 'idx' : 0, 'items' : [],
\ 'nr' : 0, 'size' : 0, 'title' : '', 'winid' : 0,
- \ 'changedtick' : 0, 'filewinid' : 0,
+ \ 'changedtick' : 0, 'filewinid' : 0, 'qfbufnr' : 0,
\ 'quickfixtextfunc' : ''}, g:Xgetlist({'nr' : 5, 'all' : 0}))
endif
endfunc
@@ -4142,20 +4290,20 @@ func Xjumpto_first_error_test(cchar)
" Test for cexpr/lexpr
enew
Xexpr l
- call assert_equal('Xtestfile1', bufname(''))
+ call assert_equal('Xtestfile1', @%)
call assert_equal(2, line('.'))
" Test for cfile/lfile
enew
call writefile(l, 'Xerr')
Xfile Xerr
- call assert_equal('Xtestfile1', bufname(''))
+ call assert_equal('Xtestfile1', @%)
call assert_equal(2, line('.'))
" Test for cbuffer/lbuffer
edit Xerr
Xbuffer
- call assert_equal('Xtestfile1', bufname(''))
+ call assert_equal('Xtestfile1', @%)
call assert_equal(2, line('.'))
call delete('Xerr')
@@ -4180,7 +4328,7 @@ func Xautocmd_changelist(cchar)
autocmd QuickFixCmdPost * Xolder
call writefile(['Xtestfile2:4:Line4'], 'Xerr')
Xfile Xerr
- call assert_equal('Xtestfile2', bufname(''))
+ call assert_equal('Xtestfile2', @%)
call assert_equal(4, line('.'))
autocmd! QuickFixCmdPost
@@ -4191,7 +4339,7 @@ func Xautocmd_changelist(cchar)
call writefile(['Xtestfile2:4:Line4'], 'Xerr')
edit Xerr
Xbuffer
- call assert_equal('Xtestfile2', bufname(''))
+ call assert_equal('Xtestfile2', @%)
call assert_equal(4, line('.'))
autocmd! QuickFixCmdPost
@@ -4200,7 +4348,7 @@ func Xautocmd_changelist(cchar)
Xexpr 'Xtestfile1:2:Line2'
autocmd QuickFixCmdPost * Xolder
Xexpr 'Xtestfile2:4:Line4'
- call assert_equal('Xtestfile2', bufname(''))
+ call assert_equal('Xtestfile2', @%)
call assert_equal(4, line('.'))
autocmd! QuickFixCmdPost
@@ -4211,7 +4359,7 @@ func Xautocmd_changelist(cchar)
Xexpr 'Xtestfile1:2:Line2'
autocmd QuickFixCmdPost * Xolder
silent Xgrep Line5 Xtestfile2
- call assert_equal('Xtestfile2', bufname(''))
+ call assert_equal('Xtestfile2', @%)
call assert_equal(5, line('.'))
autocmd! QuickFixCmdPost
endif
@@ -4221,7 +4369,7 @@ func Xautocmd_changelist(cchar)
Xexpr 'Xtestfile1:2:Line2'
autocmd QuickFixCmdPost * Xolder
silent Xvimgrep Line5 Xtestfile2
- call assert_equal('Xtestfile2', bufname(''))
+ call assert_equal('Xtestfile2', @%)
call assert_equal(5, line('.'))
autocmd! QuickFixCmdPost
@@ -4336,7 +4484,7 @@ func Test_splitview()
new | only
" When split opening files from a helpgrep location list window, a new help
- " window should be opend with a copy of the location list.
+ " window should be opened with a copy of the location list.
lhelpgrep window
let locid = getloclist(0, {'id' : 0}).id
lwindow
@@ -4345,6 +4493,20 @@ func Test_splitview()
call assert_equal(0, getloclist(0, {'winid' : 0}).winid)
new | only
+ " Using :split or :vsplit from a quickfix window should behave like a :new
+ " or a :vnew command
+ copen
+ split
+ call assert_equal(3, winnr('$'))
+ let l = getwininfo()
+ call assert_equal([0, 0, 1], [l[0].quickfix, l[1].quickfix, l[2].quickfix])
+ close
+ copen
+ vsplit
+ let l = getwininfo()
+ call assert_equal([0, 0, 1], [l[0].quickfix, l[1].quickfix, l[2].quickfix])
+ new | only
+
call delete('Xtestfile1')
call delete('Xtestfile2')
endfunc
@@ -4432,11 +4594,19 @@ func Xqfbuf_test(cchar)
Xclose
" Even after the quickfix window is closed, the buffer should be loaded
call assert_true(bufloaded(qfbnum))
+ call assert_true(qfbnum, g:Xgetlist({'qfbufnr' : 0}).qfbufnr)
Xopen
" Buffer should be reused when opening the window again
call assert_equal(qfbnum, bufnr(''))
Xclose
+ " When quickfix buffer is wiped out, getqflist() should return 0
+ %bw!
+ Xexpr ""
+ Xopen
+ bw!
+ call assert_equal(0, g:Xgetlist({'qfbufnr': 0}).qfbufnr)
+
if a:cchar == 'l'
%bwipe
" For a location list, when both the file window and the location list
@@ -4450,7 +4620,7 @@ func Xqfbuf_test(cchar)
close
" When the location list window is closed, the buffer name should not
" change to 'Quickfix List'
- call assert_match(qfbnum . ' h- "\[Location List]"', execute('ls'))
+ call assert_match(qfbnum . 'u h- "\[Location List]"', execute('ls!'))
call assert_true(bufloaded(qfbnum))
" After deleting a location list buffer using ":bdelete", opening the
@@ -4467,6 +4637,7 @@ func Xqfbuf_test(cchar)
" removed
call setloclist(0, [], 'f')
call assert_false(bufexists(qfbnum))
+ call assert_equal(0, getloclist(0, {'qfbufnr' : 0}).qfbufnr)
" When the location list is freed with the location list window open, the
" location list buffer should not be lost. It should be reused when the
@@ -4491,11 +4662,36 @@ func Xqfbuf_test(cchar)
endfunc
func Test_qfbuf()
- throw 'skipped: enable after porting patch 8.1.0877'
call Xqfbuf_test('c')
call Xqfbuf_test('l')
endfunc
+" If there is an autocmd to use only one window, then opening the location
+" list window used to crash Vim.
+func Test_winonly_autocmd()
+ call s:create_test_file('Xtest1')
+ " Autocmd to show only one Vim window at a time
+ autocmd WinEnter * only
+ new
+ " Load the location list
+ lexpr "Xtest1:5:Line5\nXtest1:10:Line10\nXtest1:15:Line15"
+ let loclistid = getloclist(0, {'id' : 0}).id
+ " Open the location list window. Only this window will be shown and the file
+ " window is closed.
+ lopen
+ call assert_equal(loclistid, getloclist(0, {'id' : 0}).id)
+ " Jump to an entry in the location list and make sure that the cursor is
+ " positioned correctly.
+ ll 3
+ call assert_equal(loclistid, getloclist(0, {'id' : 0}).id)
+ call assert_equal('Xtest1', @%)
+ call assert_equal(15, line('.'))
+ " Cleanup
+ autocmd! WinEnter
+ new | only
+ call delete('Xtest1')
+endfunc
+
" Test to make sure that an empty quickfix buffer is not reused for loading
" a normal buffer.
func Test_empty_qfbuf()
@@ -4549,51 +4745,51 @@ func Xtest_below(cchar)
Xexpr ["X1:5:3:L5", "X2:5:2:L5", "X2:10:3:L10", "X2:15:4:L15", "X3:3:5:L3"]
edit +7 X2
Xabove
- call assert_equal(['X2', 5], [bufname(''), line('.')])
+ call assert_equal(['X2', 5], [@%, line('.')])
call assert_fails('Xabove', 'E553:')
normal 7G
Xbefore
- call assert_equal(['X2', 5, 2], [bufname(''), line('.'), col('.')])
+ call assert_equal(['X2', 5, 2], [@%, line('.'), col('.')])
call assert_fails('Xbefore', 'E553:')
normal 2j
Xbelow
- call assert_equal(['X2', 10], [bufname(''), line('.')])
+ call assert_equal(['X2', 10], [@%, line('.')])
normal 7G
Xafter
- call assert_equal(['X2', 10, 3], [bufname(''), line('.'), col('.')])
+ call assert_equal(['X2', 10, 3], [@%, line('.'), col('.')])
" Last error in this file
Xbelow 99
- call assert_equal(['X2', 15], [bufname(''), line('.')])
+ call assert_equal(['X2', 15], [@%, line('.')])
call assert_fails('Xbelow', 'E553:')
normal gg
Xafter 99
- call assert_equal(['X2', 15, 4], [bufname(''), line('.'), col('.')])
+ call assert_equal(['X2', 15, 4], [@%, line('.'), col('.')])
call assert_fails('Xafter', 'E553:')
" First error in this file
Xabove 99
- call assert_equal(['X2', 5], [bufname(''), line('.')])
+ call assert_equal(['X2', 5], [@%, line('.')])
call assert_fails('Xabove', 'E553:')
normal G
Xbefore 99
- call assert_equal(['X2', 5, 2], [bufname(''), line('.'), col('.')])
+ call assert_equal(['X2', 5, 2], [@%, line('.'), col('.')])
call assert_fails('Xbefore', 'E553:')
normal gg
Xbelow 2
- call assert_equal(['X2', 10], [bufname(''), line('.')])
+ call assert_equal(['X2', 10], [@%, line('.')])
normal gg
Xafter 2
- call assert_equal(['X2', 10, 3], [bufname(''), line('.'), col('.')])
+ call assert_equal(['X2', 10, 3], [@%, line('.'), col('.')])
normal G
Xabove 2
- call assert_equal(['X2', 10], [bufname(''), line('.')])
+ call assert_equal(['X2', 10], [@%, line('.')])
normal G
Xbefore 2
- call assert_equal(['X2', 10, 3], [bufname(''), line('.'), col('.')])
+ call assert_equal(['X2', 10, 3], [@%, line('.'), col('.')])
edit X4
call assert_fails('Xabove', 'E42:')
@@ -4617,45 +4813,45 @@ func Xtest_below(cchar)
\ "X2:15:1:L15_1", "X2:15:2:L15_2", "X2:15:3:L15_3", "X3:3:L3"]
edit +1 X2
Xbelow 2
- call assert_equal(['X2', 10, 1], [bufname(''), line('.'), col('.')])
+ call assert_equal(['X2', 10, 1], [@%, line('.'), col('.')])
normal 1G
Xafter 2
- call assert_equal(['X2', 5, 2], [bufname(''), line('.'), col('.')])
+ call assert_equal(['X2', 5, 2], [@%, line('.'), col('.')])
normal gg
Xbelow 99
- call assert_equal(['X2', 15, 1], [bufname(''), line('.'), col('.')])
+ call assert_equal(['X2', 15, 1], [@%, line('.'), col('.')])
normal gg
Xafter 99
- call assert_equal(['X2', 15, 3], [bufname(''), line('.'), col('.')])
+ call assert_equal(['X2', 15, 3], [@%, line('.'), col('.')])
normal G
Xabove 2
- call assert_equal(['X2', 10, 1], [bufname(''), line('.'), col('.')])
+ call assert_equal(['X2', 10, 1], [@%, line('.'), col('.')])
normal G
Xbefore 2
- call assert_equal(['X2', 15, 2], [bufname(''), line('.'), col('.')])
+ call assert_equal(['X2', 15, 2], [@%, line('.'), col('.')])
normal G
Xabove 99
- call assert_equal(['X2', 5, 1], [bufname(''), line('.'), col('.')])
+ call assert_equal(['X2', 5, 1], [@%, line('.'), col('.')])
normal G
Xbefore 99
- call assert_equal(['X2', 5, 1], [bufname(''), line('.'), col('.')])
+ call assert_equal(['X2', 5, 1], [@%, line('.'), col('.')])
normal 10G
Xabove
- call assert_equal(['X2', 5, 1], [bufname(''), line('.'), col('.')])
+ call assert_equal(['X2', 5, 1], [@%, line('.'), col('.')])
normal 10G$
2Xbefore
- call assert_equal(['X2', 10, 2], [bufname(''), line('.'), col('.')])
+ call assert_equal(['X2', 10, 2], [@%, line('.'), col('.')])
normal 10G
Xbelow
- call assert_equal(['X2', 15, 1], [bufname(''), line('.'), col('.')])
+ call assert_equal(['X2', 15, 1], [@%, line('.'), col('.')])
normal 9G
5Xafter
- call assert_equal(['X2', 15, 2], [bufname(''), line('.'), col('.')])
+ call assert_equal(['X2', 15, 2], [@%, line('.'), col('.')])
" Invalid range
if a:cchar == 'c'
@@ -4969,7 +5165,7 @@ func Test_quickfix_window_fails_to_open()
call delete('XquickfixFails')
endfunc
-" Test for updating the quickfix buffer whenever the assocaited quickfix list
+" Test for updating the quickfix buffer whenever the associated quickfix list
" is changed.
func Xqfbuf_update(cchar)
call s:setup_commands(a:cchar)
@@ -5027,6 +5223,52 @@ func Test_qfbuf_update()
call Xqfbuf_update('l')
endfunc
+" Test for the :vimgrep 'f' flag (fuzzy match)
+func Xvimgrep_fuzzy_match(cchar)
+ call s:setup_commands(a:cchar)
+
+ Xvimgrep /three one/f Xfile*
+ let l = g:Xgetlist()
+ call assert_equal(2, len(l))
+ call assert_equal(['Xfile1', 1, 9, 'one two three'],
+ \ [bufname(l[0].bufnr), l[0].lnum, l[0].col, l[0].text])
+ call assert_equal(['Xfile2', 2, 1, 'three one two'],
+ \ [bufname(l[1].bufnr), l[1].lnum, l[1].col, l[1].text])
+
+ Xvimgrep /the/f Xfile*
+ let l = g:Xgetlist()
+ call assert_equal(3, len(l))
+ call assert_equal(['Xfile1', 1, 9, 'one two three'],
+ \ [bufname(l[0].bufnr), l[0].lnum, l[0].col, l[0].text])
+ call assert_equal(['Xfile2', 2, 1, 'three one two'],
+ \ [bufname(l[1].bufnr), l[1].lnum, l[1].col, l[1].text])
+ call assert_equal(['Xfile2', 4, 4, 'aaathreeaaa'],
+ \ [bufname(l[2].bufnr), l[2].lnum, l[2].col, l[2].text])
+
+ Xvimgrep /aaa/fg Xfile*
+ let l = g:Xgetlist()
+ call assert_equal(4, len(l))
+ call assert_equal(['Xfile1', 2, 1, 'aaaaaa'],
+ \ [bufname(l[0].bufnr), l[0].lnum, l[0].col, l[0].text])
+ call assert_equal(['Xfile1', 2, 4, 'aaaaaa'],
+ \ [bufname(l[1].bufnr), l[1].lnum, l[1].col, l[1].text])
+ call assert_equal(['Xfile2', 4, 1, 'aaathreeaaa'],
+ \ [bufname(l[2].bufnr), l[2].lnum, l[2].col, l[2].text])
+ call assert_equal(['Xfile2', 4, 9, 'aaathreeaaa'],
+ \ [bufname(l[3].bufnr), l[3].lnum, l[3].col, l[3].text])
+
+ call assert_fails('Xvimgrep /xyz/fg Xfile*', 'E480:')
+endfunc
+
+func Test_vimgrep_fuzzy_match()
+ call writefile(['one two three', 'aaaaaa'], 'Xfile1')
+ call writefile(['one', 'three one two', 'two', 'aaathreeaaa'], 'Xfile2')
+ call Xvimgrep_fuzzy_match('c')
+ call Xvimgrep_fuzzy_match('l')
+ call delete('Xfile1')
+ call delete('Xfile2')
+endfunc
+
" Test for getting a specific item from a quickfix list
func Xtest_getqflist_by_idx(cchar)
call s:setup_commands(a:cchar)
@@ -5137,16 +5379,14 @@ func Xtest_qftextfunc(cchar)
" Non-existing function
set quickfixtextfunc=Tabc
- " call assert_fails("Xexpr ['F1:10:2:green', 'F1:20:4:blue']", 'E117:')
- Xexpr ['F1:10:2:green', 'F1:20:4:blue']"
+ call assert_fails("Xexpr ['F1:10:2:green', 'F1:20:4:blue']", 'E117:')
call assert_fails("Xwindow", 'E117:')
Xclose
set quickfixtextfunc&
" set option to a non-function
set quickfixtextfunc=[10,\ 20]
- " call assert_fails("Xexpr ['F1:10:2:green', 'F1:20:4:blue']", 'E117:')
- Xexpr ['F1:10:2:green', 'F1:20:4:blue']"
+ call assert_fails("Xexpr ['F1:10:2:green', 'F1:20:4:blue']", 'E117:')
call assert_fails("Xwindow", 'E117:')
Xclose
set quickfixtextfunc&
@@ -5156,8 +5396,7 @@ func Xtest_qftextfunc(cchar)
return a:a .. a:b .. a:c
endfunc
set quickfixtextfunc=Xqftext
- " call assert_fails("Xexpr ['F1:10:2:green', 'F1:20:4:blue']", 'E119:')
- Xexpr ['F1:10:2:green', 'F1:20:4:blue']"
+ call assert_fails("Xexpr ['F1:10:2:green', 'F1:20:4:blue']", 'E119:')
call assert_fails("Xwindow", 'E119:')
Xclose
@@ -5166,9 +5405,8 @@ func Xtest_qftextfunc(cchar)
return ['one', [], 'two']
endfunc
set quickfixtextfunc=Xqftext2
- " call assert_fails("Xexpr ['F1:10:2:green', 'F1:20:4:blue', 'F1:30:6:red']",
- " \ 'E730:')
- Xexpr ['F1:10:2:green', 'F1:20:4:blue', 'F1:30:6:red']
+ call assert_fails("Xexpr ['F1:10:2:green', 'F1:20:4:blue', 'F1:30:6:red']",
+ \ 'E730:')
call assert_fails('Xwindow', 'E730:')
call assert_equal(['one', 'F1|20 col 4| blue', 'F1|30 col 6| red'],
\ getline(1, '$'))
@@ -5332,4 +5570,81 @@ func Test_win_gettype()
lclose
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).
+func Test_two_qf_windows()
+ cexpr "F1:1:line1"
+ copen
+ tabnew
+ copen
+ call assert_true(&buflisted)
+ cclose
+ tabfirst
+ call assert_true(&buflisted)
+ let bnum = bufnr()
+ cclose
+ " if all the quickfix windows are closed, then buffer should be unlisted.
+ call assert_false(buflisted(bnum))
+ %bw!
+
+ " Repeat the test for a location list
+ lexpr "F2:2:line2"
+ lopen
+ let bnum = bufnr()
+ tabnew
+ exe "buffer" bnum
+ tabfirst
+ lclose
+ tablast
+ call assert_true(buflisted(bnum))
+ tabclose
+ lopen
+ call assert_true(buflisted(bnum))
+ lclose
+ call assert_false(buflisted(bnum))
+ %bw!
+endfunc
+
+" Weird sequence of commands that caused entering a wiped-out buffer
+func Test_lopen_bwipe()
+ func R()
+ silent! tab lopen
+ e x
+ silent! lfile
+ endfunc
+
+ cal R()
+ cal R()
+ cal R()
+ bw!
+ delfunc R
+endfunc
+
+" Another sequence of commands that caused all buffers to be wiped out
+func Test_lopen_bwipe_all()
+ let lines =<< trim END
+ func R()
+ silent! tab lopen
+ e foo
+ silent! lfile
+ endfunc
+ cal R()
+ exe "norm \<C-W>\<C-V>0"
+ cal R()
+ bwipe
+
+ call writefile(['done'], 'Xresult')
+ qall!
+ END
+ call writefile(lines, 'Xscript')
+ if RunVim([], [], '--clean -n -S Xscript')
+ call assert_equal(['done'], readfile('Xresult'))
+ endif
+
+ call delete('Xscript')
+ call delete('Xresult')
+endfunc
+
+
" vim: shiftwidth=2 sts=2 expandtab
diff --git a/src/nvim/testdir/test_quotestar.vim b/src/nvim/testdir/test_quotestar.vim
index 6e6f91362b..93865869fa 100644
--- a/src/nvim/testdir/test_quotestar.vim
+++ b/src/nvim/testdir/test_quotestar.vim
@@ -1,10 +1,9 @@
" *-register (quotestar) tests
-if !has('clipboard')
- finish
-endif
-
source shared.vim
+source check.vim
+
+CheckFeature clipboard_working
func Do_test_quotestar_for_macunix()
if empty(exepath('pbcopy')) || empty(exepath('pbpaste'))
diff --git a/src/nvim/testdir/test_random.vim b/src/nvim/testdir/test_random.vim
new file mode 100644
index 0000000000..6d3f7dcfd9
--- /dev/null
+++ b/src/nvim/testdir/test_random.vim
@@ -0,0 +1,51 @@
+" Tests for srand() and rand()
+
+func Test_Rand()
+ let r = srand(123456789)
+ call assert_equal([1573771921, 319883699, 2742014374, 1324369493], r)
+ call assert_equal(4284103975, rand(r))
+ call assert_equal(1001954530, rand(r))
+ call assert_equal(2701803082, rand(r))
+ 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
+
+ " Nvim does not support test_srand_seed
+ " call test_srand_seed(123456789)
+ " call assert_equal(4284103975, rand())
+ " call assert_equal(1001954530, rand())
+ " call test_srand_seed()
+
+ if has('float')
+ call assert_fails('echo srand(1.2)', 'E805:')
+ 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)
+endfunc
+
+func Test_issue_5587()
+ call rand()
+ call garbagecollect()
+ call rand()
+endfunc
+
+" vim: shiftwidth=2 sts=2 expandtab
diff --git a/src/nvim/testdir/test_regex_char_classes.vim b/src/nvim/testdir/test_regex_char_classes.vim
index c1a4202c2b..db16f057c8 100644
--- a/src/nvim/testdir/test_regex_char_classes.vim
+++ b/src/nvim/testdir/test_regex_char_classes.vim
@@ -293,3 +293,5 @@ func Test_regex_char_classes()
enew!
close
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 712f1e6025..82d250e8b3 100644
--- a/src/nvim/testdir/test_regexp_latin.vim
+++ b/src/nvim/testdir/test_regexp_latin.vim
@@ -6,7 +6,10 @@ scriptencoding latin1
source check.vim
func s:equivalence_test()
- let str = "AÀÁÂÃÄÅ B C D EÈÉÊË F G H IÌÍÎÏ J K L M NÑ OÒÓÔÕÖØ P Q R S T UÙÚÛÜ V W X YÝ Z aàáâãäå b c d eèéêë f g h iìíîï j k l m nñ oòóôõöø p q r s t uùúûü v w x yýÿ z"
+ let str = 'A B C D E F G H I J K L M N O P Q R S T U V W X Y Z '
+ \ .. 'a b c d e f g h i j k l m n o p q r s t u v w x y z '
+ \ .. "0 1 2 3 4 5 6 7 8 9 "
+ \ .. "` ~ ! ? ; : . , / \\ ' \" | < > [ ] { } ( ) @ # $ % ^ & * _ - + \b \e \f \n \r \t"
let groups = split(str)
for group1 in groups
for c in split(group1, '\zs')
@@ -119,7 +122,10 @@ endfunc
" Tests for regexp patterns without multi-byte support.
func Test_regexp_single_line_pat()
" tl is a List of Lists with:
- " regexp engine
+ " regexp engines to test
+ " 0 - test with 'regexpengine' values 0 and 1
+ " 1 - test with 'regexpengine' values 0 and 2
+ " 2 - test with 'regexpengine' values 0, 1 and 2
" regexp pattern
" text to test the pattern on
" expected match (optional)
@@ -140,6 +146,8 @@ func Test_regexp_single_line_pat()
call add(tl, [2, 'c*', 'abdef', ''])
call add(tl, [2, 'bc\+', 'abccccdef', 'bcccc'])
call add(tl, [2, 'bc\+', 'abdef']) " no match
+ " match newline character in a string
+ call add(tl, [2, 'o\nb', "foo\nbar", "o\nb"])
" operator \|
call add(tl, [2, 'a\|ab', 'cabd', 'a']) " alternation is ordered
@@ -337,7 +345,7 @@ func Test_regexp_single_line_pat()
call add(tl, [2, '\v((ab)|c*)+', 'abcccaba', 'abcccab', '', 'ab'])
call add(tl, [2, '\v(a(c*)+b)+', 'acbababaaa', 'acbabab', 'ab', ''])
call add(tl, [2, '\v(a|b*)+', 'aaaa', 'aaaa', ''])
- call add(tl, [2, '\p*', 'aá ', 'aá '])
+ call add(tl, [2, '\p*', 'a ', 'a '])
" Test greedy-ness and lazy-ness
call add(tl, [2, 'a\{-2,7}','aaaaaaaaaaaaa', 'aa'])
@@ -563,6 +571,9 @@ func Test_regexp_single_line_pat()
" Test \%V atom
call add(tl, [2, '\%>70vGesamt', 'Jean-Michel Charlier & Victor Hubinon\Gesamtausgabe [Salleck] Buck Danny {Jean-Michel Charlier & Victor Hubinon}\Gesamtausgabe', 'Gesamt'])
+ " Test for ignoring case and matching repeated characters
+ call add(tl, [2, '\cb\+', 'aAbBbBcC', 'bBbB'])
+
" Run the tests
for t in tl
let re = t[0]
@@ -622,6 +633,14 @@ endfunc
" Tests for multi-line regexp patterns without multi-byte support.
func Test_regexp_multiline_pat()
+ " tl is a List of Lists with:
+ " regexp engines to test
+ " 0 - test with 'regexpengine' values 0 and 1
+ " 1 - test with 'regexpengine' values 0 and 2
+ " 2 - test with 'regexpengine' values 0, 1 and 2
+ " regexp pattern
+ " List with text to test the pattern on
+ " List with the expected match
let tl = []
" back references
@@ -631,6 +650,70 @@ func Test_regexp_multiline_pat()
" line breaks
call add(tl, [2, '\S.*\nx', ['abc', 'def', 'ghi', 'xjk', 'lmn'], ['abc', 'def', 'XXjk', 'lmn']])
+ " Any single character or end-of-line
+ call add(tl, [2, '\_.\+', ['a', 'b', 'c'], ['XX']])
+ " Any identifier or end-of-line
+ call add(tl, [2, '\_i\+', ['a', 'b', ';', '2'], ['XX;XX']])
+ " Any identifier but excluding digits or end-of-line
+ call add(tl, [2, '\_I\+', ['a', 'b', ';', '2'], ['XX;XX2XX']])
+ " Any keyword or end-of-line
+ call add(tl, [2, '\_k\+', ['a', 'b', '=', '2'], ['XX=XX']])
+ " Any keyword but excluding digits or end-of-line
+ call add(tl, [2, '\_K\+', ['a', 'b', '=', '2'], ['XX=XX2XX']])
+ " Any filename character or end-of-line
+ call add(tl, [2, '\_f\+', ['a', 'b', '.', '5'], ['XX']])
+ " Any filename character but excluding digits or end-of-line
+ call add(tl, [2, '\_F\+', ['a', 'b', '.', '5'], ['XX5XX']])
+ " Any printable character or end-of-line
+ call add(tl, [2, '\_p\+', ['a', 'b', '=', '4'], ['XX']])
+ " Any printable character excluding digits or end-of-line
+ call add(tl, [2, '\_P\+', ['a', 'b', '=', '4'], ['XX4XX']])
+ " Any whitespace character or end-of-line
+ call add(tl, [2, '\_s\+', [' ', ' ', 'a', 'b'], ['XXaXXbXX']])
+ " Any non-whitespace character or end-of-line
+ call add(tl, [2, '\_S\+', [' ', ' ', 'a', 'b'], [' XX XX']])
+ " Any decimal digit or end-of-line
+ call add(tl, [2, '\_d\+', ['1', 'a', '2', 'b', '3'], ['XXaXXbXX']])
+ " Any non-decimal digit or end-of-line
+ call add(tl, [2, '\_D\+', ['1', 'a', '2', 'b', '3'], ['1XX2XX3XX']])
+ " Any hexadecimal digit or end-of-line
+ call add(tl, [2, '\_x\+', ['1', 'a', 'g', '9', '8'], ['XXgXX']])
+ " Any non-hexadecimal digit or end-of-line
+ call add(tl, [2, '\_X\+', ['1', 'a', 'g', '9', '8'], ['1XXaXX9XX8XX']])
+ " Any octal digit or end-of-line
+ call add(tl, [2, '\_o\+', ['0', '7', '8', '9', '0'], ['XX8XX9XX']])
+ " Any non-octal digit or end-of-line
+ call add(tl, [2, '\_O\+', ['0', '7', '8', '9', '0'], ['0XX7XX0XX']])
+ " Any word character or end-of-line
+ call add(tl, [2, '\_w\+', ['A', 'B', '=', 'C', 'D'], ['XX=XX']])
+ " Any non-word character or end-of-line
+ call add(tl, [2, '\_W\+', ['A', 'B', '=', 'C', 'D'], ['AXXBXXCXXDXX']])
+ " Any head-of-word character or end-of-line
+ call add(tl, [2, '\_h\+', ['a', '1', 'b', '2', 'c'], ['XX1XX2XX']])
+ " Any non-head-of-word character or end-of-line
+ call add(tl, [2, '\_H\+', ['a', '1', 'b', '2', 'c'], ['aXXbXXcXX']])
+ " Any alphabetic character or end-of-line
+ call add(tl, [2, '\_a\+', ['a', '1', 'b', '2', 'c'], ['XX1XX2XX']])
+ " Any non-alphabetic character or end-of-line
+ call add(tl, [2, '\_A\+', ['a', '1', 'b', '2', 'c'], ['aXXbXXcXX']])
+ " Any lowercase character or end-of-line
+ call add(tl, [2, '\_l\+', ['a', 'A', 'b', 'B'], ['XXAXXBXX']])
+ " Any non-lowercase character or end-of-line
+ call add(tl, [2, '\_L\+', ['a', 'A', 'b', 'B'], ['aXXbXX']])
+ " Any uppercase character or end-of-line
+ call add(tl, [2, '\_u\+', ['a', 'A', 'b', 'B'], ['aXXbXX']])
+ " Any non-uppercase character or end-of-line
+ call add(tl, [2, '\_U\+', ['a', 'A', 'b', 'B'], ['XXAXXBXX']])
+ " Collection or end-of-line
+ call add(tl, [2, '\_[a-z]\+', ['a', 'A', 'b', 'B'], ['XXAXXBXX']])
+ " start of line anywhere in the text
+ call add(tl, [2, 'one\zs\_s*\_^\zetwo',
+ \ ['', 'one', ' two', 'one', '', 'two'],
+ \ ['', 'one', ' two', 'oneXXtwo']])
+ " end of line anywhere in the text
+ call add(tl, [2, 'one\zs\_$\_s*two',
+ \ ['', 'one', ' two', 'one', '', 'two'], ['', 'oneXX', 'oneXX']])
+
" Check that \_[0-9] matching EOL does not break a following \>
call add(tl, [2, '\<\(\(25\_[0-5]\|2\_[0-4]\_[0-9]\|\_[01]\?\_[0-9]\_[0-9]\?\)\.\)\{3\}\(25\_[0-5]\|2\_[0-4]\_[0-9]\|\_[01]\?\_[0-9]\_[0-9]\?\)\>', ['', 'localnet/192.168.0.1', ''], ['', 'localnet/XX', '']])
@@ -646,7 +729,7 @@ func Test_regexp_multiline_pat()
let before = t[2]
let after = t[3]
for engine in [0, 1, 2]
- if engine == 2 && re == 0 || engine == 1 && re ==1
+ if engine == 2 && re == 0 || engine == 1 && re == 1
continue
endif
let &regexpengine = engine
@@ -683,7 +766,7 @@ func Test_matchstr_with_ze()
bwipe!
endfunc
-" Check a pattern with a look beind crossing a line boundary
+" Check a pattern with a look behind crossing a line boundary
func Test_lookbehind_across_line()
new
call append(0, ['Behind:', 'asdfasd<yyy', 'xxstart1', 'asdfasd<yy',
@@ -694,9 +777,8 @@ func Test_lookbehind_across_line()
bwipe!
endfunc
-" Check matching Visual area
-func Test_matching_visual_area()
- new
+" Test for the \%V atom (match inside the visual area)
+func Regex_Match_Visual_Area()
call append(0, ['Visual:', 'thexe the thexethe', 'andaxand andaxand',
\ 'oooxofor foroxooo', 'oooxofor foroxooo'])
call cursor(1, 1)
@@ -705,12 +787,22 @@ func Test_matching_visual_area()
exe "normal jfx\<C-V>fxj:s/\\%Vo/O/g\<CR>"
call assert_equal(['Visual:', 'thexE thE thExethe', 'AndAxAnd AndAxAnd',
\ 'oooxOfOr fOrOxooo', 'oooxOfOr fOrOxooo', ''], getline(1, '$'))
+ %d
+endfunc
+
+" Check matching Visual area
+func Test_matching_visual_area()
+ new
+ set regexpengine=1
+ call Regex_Match_Visual_Area()
+ set regexpengine=2
+ call Regex_Match_Visual_Area()
+ set regexpengine&
bwipe!
endfunc
" Check matching marks
-func Test_matching_marks()
- new
+func Regex_Mark()
call append(0, ['', '', '', 'Marks:', 'asdfSasdfsadfEasdf', 'asdfSas',
\ 'dfsadfEasdf', '', '', '', '', ''])
call cursor(4, 1)
@@ -718,6 +810,15 @@ func Test_matching_marks()
exe "normal jfSmsj0fEme:.-4,.+6s/.\\%>'s\\_.*\\%<'e../again/\<CR>"
call assert_equal(['', '', '', 'Marks:', 'asdfhereasdf', 'asdfagainasdf',
\ '', '', '', '', '', ''], getline(1, '$'))
+ %d
+endfunc
+
+func Test_matching_marks()
+ new
+ set regexpengine=1
+ call Regex_Mark()
+ set regexpengine=2
+ call Regex_Mark()
bwipe!
endfunc
@@ -758,8 +859,7 @@ func Test_matching_curpos()
endfunc
" Test for matching the start and end of a buffer
-func Test_start_end_of_buffer_match()
- new
+func Regex_start_end_buffer()
call setline(1, repeat(['vim edit'], 20))
/\%^
call assert_equal([0, 1, 1, 0], getpos('.'))
@@ -769,6 +869,15 @@ func Test_start_end_of_buffer_match()
call assert_equal([0, 20, 8, 0], getpos('.'))
exe "normal 6gg/..\\%$\<CR>"
call assert_equal([0, 20, 7, 0], getpos('.'))
+ %d
+endfunc
+
+func Test_start_end_of_buffer_match()
+ new
+ set regexpengine=1
+ call Regex_start_end_buffer()
+ set regexpengine=2
+ call Regex_start_end_buffer()
bwipe!
endfunc
@@ -781,10 +890,141 @@ endfunc
" Check for detecting error
func Test_regexp_error()
- set regexpengine=2
- call assert_fails("call matchlist('x x', ' \\ze*')", 'E888:')
- call assert_fails("call matchlist('x x', ' \\zs*')", 'E888:')
+ call assert_fails("call matchlist('x x', '\\%#=1 \\zs*')", 'E888:')
+ call assert_fails("call matchlist('x x', '\\%#=1 \\ze*')", 'E888:')
+ call assert_fails("call matchlist('x x', '\\%#=2 \\zs*')", 'E888:')
+ call assert_fails("call matchlist('x x', '\\%#=2 \\ze*')", 'E888:')
+ call assert_fails('exe "normal /\\%#=1\\%[x\\%[x]]\<CR>"', 'E369:')
+endfunc
+
+" Test for using the last substitute string pattern (~)
+func Test_regexp_last_subst_string()
+ new
+ s/bar/baz/e
+ call assert_equal(matchstr("foo\nbaz\nbar", "\\%#=1\~"), "baz")
+ call assert_equal(matchstr("foo\nbaz\nbar", "\\%#=2\~"), "baz")
+ close!
+endfunc
+
+" Check patterns matching cursor position.
+func s:curpos_test2()
+ new
+ call setline(1, ['1', '2 foobar eins zwei drei vier fnf sechse',
+ \ '3 foobar eins zwei drei vier fnf sechse',
+ \ '4 foobar eins zwei drei vier fnf sechse',
+ \ '5 foobar eins zwei drei vier fnf sechse',
+ \ '6 foobar eins zwei drei vier fnf sechse',
+ \ '7 foobar eins zwei drei vier fnf sechse'])
+ call setpos('.', [0, 2, 10, 0])
+ s/\%.c.*//g
+ call setpos('.', [0, 3, 15, 0])
+ s/\%.l.*//g
+ call setpos('.', [0, 5, 3, 0])
+ s/\%.v.*/_/g
+ call assert_equal(['1',
+ \ '2 foobar ',
+ \ '',
+ \ '4 foobar eins zwei drei vier fnf sechse',
+ \ '5 _',
+ \ '6 foobar eins zwei drei vier fnf sechse',
+ \ '7 foobar eins zwei drei vier fnf sechse'],
+ \ getline(1, '$'))
+ call assert_fails('call search("\\%.1l")', 'E1204:')
+ call assert_fails('call search("\\%.1c")', 'E1204:')
+ call assert_fails('call search("\\%.1v")', 'E1204:')
+ bwipe!
+endfunc
+
+" Check patterns matching before or after cursor position.
+func s:curpos_test3()
+ new
+ call setline(1, ['1', '2 foobar eins zwei drei vier fnf sechse',
+ \ '3 foobar eins zwei drei vier fnf sechse',
+ \ '4 foobar eins zwei drei vier fnf sechse',
+ \ '5 foobar eins zwei drei vier fnf sechse',
+ \ '6 foobar eins zwei drei vier fnf sechse',
+ \ '7 foobar eins zwei drei vier fnf sechse'])
+ call setpos('.', [0, 2, 10, 0])
+ " Note: This removes all columns, except for the column directly in front of
+ " the cursor. Bug????
+ :s/^.*\%<.c//
+ call setpos('.', [0, 3, 10, 0])
+ :s/\%>.c.*$//
+ call setpos('.', [0, 5, 4, 0])
+ " Note: This removes all columns, except for the column directly in front of
+ " the cursor. Bug????
+ :s/^.*\%<.v/_/
+ call setpos('.', [0, 6, 4, 0])
+ :s/\%>.v.*$/_/
+ call assert_equal(['1',
+ \ ' eins zwei drei vier fnf sechse',
+ \ '3 foobar e',
+ \ '4 foobar eins zwei drei vier fnf sechse',
+ \ '_foobar eins zwei drei vier fnf sechse',
+ \ '6 fo_',
+ \ '7 foobar eins zwei drei vier fnf sechse'],
+ \ getline(1, '$'))
+ sil %d
+ call setline(1, ['1', '2 foobar eins zwei drei vier fnf sechse',
+ \ '3 foobar eins zwei drei vier fnf sechse',
+ \ '4 foobar eins zwei drei vier fnf sechse',
+ \ '5 foobar eins zwei drei vier fnf sechse',
+ \ '6 foobar eins zwei drei vier fnf sechse',
+ \ '7 foobar eins zwei drei vier fnf sechse'])
+ call setpos('.', [0, 4, 4, 0])
+ %s/\%<.l.*//
+ call setpos('.', [0, 5, 4, 0])
+ %s/\%>.l.*//
+ call assert_equal(['', '', '',
+ \ '4 foobar eins zwei drei vier fnf sechse',
+ \ '5 foobar eins zwei drei vier fnf sechse',
+ \ '', ''],
+ \ getline(1, '$'))
+ bwipe!
+endfunc
+
+" Test that matching below, at or after the
+" cursor position work
+func Test_matching_pos()
+ for val in range(3)
+ exe "set re=" .. val
+ " Match at cursor position
+ call s:curpos_test2()
+ " Match before or after cursor position
+ call s:curpos_test3()
+ endfor
set re&
endfunc
+func Test_using_mark_position()
+ " this was using freed memory
+ " new engine
+ new
+ norm O0
+ call assert_fails("s/\\%')", 'E486:')
+ bwipe!
+
+ " old engine
+ new
+ norm O0
+ call assert_fails("s/\\%#=1\\%')", 'E486:')
+ bwipe!
+endfunc
+
+func Test_using_visual_position()
+ " this was using freed memory
+ new
+ exe "norm 0o\<Esc>\<C-V>k\<C-X>o0"
+ /\%V
+ bwipe!
+endfunc
+
+func Test_using_invalid_visual_position()
+ " this was going beyond the end of the line
+ new
+ exe "norm 0o000\<Esc>0\<C-V>$s0"
+ /\%V
+ bwipe!
+endfunc
+
" vim: shiftwidth=2 sts=2 expandtab
diff --git a/src/nvim/testdir/test_regexp_utf8.vim b/src/nvim/testdir/test_regexp_utf8.vim
index c568805f87..191cd948ac 100644
--- a/src/nvim/testdir/test_regexp_utf8.vim
+++ b/src/nvim/testdir/test_regexp_utf8.vim
@@ -1,21 +1,21 @@
" Tests for regexp in utf8 encoding
func s:equivalence_test()
- let str = "AÀÁÂÃÄÅĀĂĄǍǞǠẢ BḂḆ CÇĆĈĊČ DĎĐḊḎḐ EÈÉÊËĒĔĖĘĚẺẼ FḞ GĜĞĠĢǤǦǴḠ HĤĦḢḦḨ IÌÍÎÏĨĪĬĮİǏỈ JĴ KĶǨḰḴ LĹĻĽĿŁḺ MḾṀ NÑŃŅŇṄṈ OÒÓÔÕÖØŌŎŐƠǑǪǬỎ PṔṖ Q RŔŖŘṘṞ SŚŜŞŠṠ TŢŤŦṪṮ UÙÚÛÜŨŪŬŮŰŲƯǓỦ VṼ WŴẀẂẄẆ XẊẌ YÝŶŸẎỲỶỸ ZŹŻŽƵẐẔ aàáâãäåāăąǎǟǡả bḃḇ cçćĉċč dďđḋḏḑ eèéêëēĕėęěẻẽ fḟ gĝğġģǥǧǵḡ hĥħḣḧḩẖ iìíîïĩīĭįǐỉ jĵǰ kķǩḱḵ lĺļľŀłḻ mḿṁ nñńņňʼnṅṉ oòóôõöøōŏőơǒǫǭỏ pṕṗ q rŕŗřṙṟ sśŝşšṡ tţťŧṫṯẗ uùúûüũūŭůűųưǔủ vṽ wŵẁẃẅẇẘ xẋẍ yýÿŷẏẙỳỷỹ zźżžƶẑẕ"
+ let str = "AÀÁÂÃÄÅĀĂĄǍǞǠǺȂȦȺḀẠẢẤẦẨẪẬẮẰẲẴẶ BƁɃḂḄḆ CÇĆĈĊČƇȻḈꞒ DĎĐƊḊḌḎḐḒ EÈÉÊËĒĔĖĘĚȄȆȨɆḔḖḘḚḜẸẺẼẾỀỂỄỆ FƑḞꞘ GĜĞĠĢƓǤǦǴḠꞠ HĤĦȞḢḤḦḨḪⱧ IÌÍÎÏĨĪĬĮİƗǏȈȊḬḮỈỊ JĴɈ KĶƘǨḰḲḴⱩꝀ LĹĻĽĿŁȽḶḸḺḼⱠ MḾṀṂ NÑŃŅŇǸṄṆṈṊꞤ OÒÓÔÕÖØŌŎŐƟƠǑǪǬǾȌȎȪȬȮȰṌṎṐṒỌỎỐỒỔỖỘỚỜỞỠỢ PƤṔṖⱣ QɊ RŔŖŘȐȒɌṘṚṜṞⱤꞦ SŚŜŞŠȘṠṢṤṦṨⱾꞨ TŢŤŦƬƮȚȾṪṬṮṰ UÙÚÛÜŨŪŬŮŰƯǕǙǛǓǗȔȖɄṲṴṶṸṺỤỦỨỪỬỮỰ VƲṼṾ WŴẀẂẄẆẈ XẊẌ YÝŶŸƳȲɎẎỲỴỶỸ ZŹŻŽƵẐẒẔⱫ aàáâãäåāăąǎǟǡǻȃȧᶏḁẚạảấầẩẫậắằẳẵặⱥ bƀɓᵬᶀḃḅḇ cçćĉċčƈȼḉꞓꞔ dďđɗᵭᶁᶑḋḍḏḑḓ eèéêëēĕėęěȅȇȩɇᶒḕḗḙḛḝẹẻẽếềểễệ fƒᵮᶂḟꞙ gĝğġģǥǧǵɠᶃḡꞡ hĥħȟḣḥḧḩḫẖⱨꞕ iìíîïĩīĭįǐȉȋɨᶖḭḯỉị jĵǰɉ kķƙǩᶄḱḳḵⱪꝁ lĺļľŀłƚḷḹḻḽⱡ mᵯḿṁṃ nñńņňʼnǹᵰᶇṅṇṉṋꞥ oòóôõöøōŏőơǒǫǭǿȍȏȫȭȯȱɵṍṏṑṓọỏốồổỗộớờởỡợ pƥᵱᵽᶈṕṗ qɋʠ rŕŗřȑȓɍɽᵲᵳᶉṛṝṟꞧ sśŝşšșȿᵴᶊṡṣṥṧṩꞩ tţťŧƫƭțʈᵵṫṭṯṱẗⱦ uùúûüũūŭůűųǚǖưǔǘǜȕȗʉᵾᶙṳṵṷṹṻụủứừửữự vʋᶌṽṿ wŵẁẃẅẇẉẘ xẋẍ yýÿŷƴȳɏẏẙỳỵỷỹ zźżžƶᵶᶎẑẓẕⱬ"
let groups = split(str)
for group1 in groups
- for c in split(group1, '\zs')
- " next statement confirms that equivalence class matches every
- " character in group
- call assert_match('^[[=' . c . '=]]*$', group1)
- for group2 in groups
- if group2 != group1
- " next statement converts that equivalence class doesn't match
- " character in any other group
- call assert_equal(-1, match(group2, '[[=' . c . '=]]'))
- endif
+ for c in split(group1, '\zs')
+ " next statement confirms that equivalence class matches every
+ " character in group
+ call assert_match('^[[=' .. c .. '=]]*$', group1)
+ for group2 in groups
+ if group2 != group1
+ " next statement converts that equivalence class doesn't match
+ " character in any other group
+ call assert_equal(-1, match(group2, '[[=' .. c .. '=]]'), c)
+ endif
+ endfor
endfor
- endfor
endfor
endfunc
@@ -152,9 +152,6 @@ func s:classes_test()
if has('win32')
let identchars_ok = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ_abcdefghijklmnopqrstuvwxyz€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›œžŸ ¡¢£¤¥¦§µÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖØÙÚÛÜÝÞßàáâãäåæçèéêëìíîïðñòóôõöøùúûüýþÿ'
let kwordchars_ok = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ_abcdefghijklmnopqrstuvwxyzµÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖרÙÚÛÜÝÞßàáâãäåæçèéêëìíîïðñòóôõö÷øùúûüýþÿ'
- elseif has('ebcdic')
- let identchars_ok = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ_abcdefghijklmnopqrstuvwxyz€ŒŽœž¬®µº¿ÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖØÙÚÛÜÝÞßàáâãäåæçèéêëìíîïðñòóôõö÷øùúûüýþÿ'
- let kwordchars_ok = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ_abcdefghijklmnopqrstuvwxyz€ŒŽœž¬®µº¿ÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖØÙÚÛÜÝÞßàáâãäåæçèéêëìíîïðñòóôõö÷øùúûüýþÿ'
else
let identchars_ok = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ_abcdefghijklmnopqrstuvwxyzµÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖרÙÚÛÜÝÞßàáâãäåæçèéêëìíîïðñòóôõö÷øùúûüýþÿ'
let kwordchars_ok = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ_abcdefghijklmnopqrstuvwxyzµÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖרÙÚÛÜÝÞßàáâãäåæçèéêëìíîïðñòóôõö÷øùúûüýþÿ'
@@ -166,8 +163,6 @@ func s:classes_test()
let fnamechars_ok = '$+,-./0123456789:ABCDEFGHIJKLMNOPQRSTUVWXYZ_abcdefghijklmnopqrstuvwxyz~ ¡¢£¤¥¦§¨©ª«¬­®¯°±²³´µ¶·¸¹º»¼½¾¿ÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖרÙÚÛÜÝÞßàáâãäåæçèéêëìíîïðñòóôõö÷øùúûüýþÿ'
elseif has('vms')
let fnamechars_ok = '#$%+,-./0123456789:;<>ABCDEFGHIJKLMNOPQRSTUVWXYZ[]_abcdefghijklmnopqrstuvwxyz~ ¡¢£¤¥¦§¨©ª«¬­®¯°±²³´µ¶·¸¹º»¼½¾¿ÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖרÙÚÛÜÝÞßàáâãäåæçèéêëìíîïðñòóôõö÷øùúûüýþÿ'
- elseif has('ebcdic')
- let fnamechars_ok = '#$%+,-./=ABCDEFGHIJKLMNOPQRSTUVWXYZ_abcdefghijklmnopqrstuvwxyz~ ¡¢£¤¥¦§¨©ª«¬­®¯°±²³´µ¶·¸¹º»¼½¾¿ÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖרÙÚÛÜÝÞßàáâãäåæçèéêëìíîïðñòóôõö÷øùúûüýþÿ'
else
let fnamechars_ok = '#$%+,-./0123456789=ABCDEFGHIJKLMNOPQRSTUVWXYZ_abcdefghijklmnopqrstuvwxyz~ ¡¢£¤¥¦§¨©ª«¬­®¯°±²³´µ¶·¸¹º»¼½¾¿ÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖרÙÚÛÜÝÞßàáâãäåæçèéêëìíîïðñòóôõö÷øùúûüýþÿ'
endif
@@ -228,7 +223,7 @@ endfunc
func Test_reversed_range()
for re in range(0, 2)
exe 'set re=' . re
- call assert_fails('call match("abc def", "[c-a]")', 'E944:')
+ call assert_fails('call match("abc def", "[c-a]")', 'E944:', re)
endfor
set re=0
endfunc
@@ -545,7 +540,6 @@ endfunc
" Check that [[:upper:]] matches for automatic engine
func Test_match_char_class_upper()
new
- let _engine=&regexpengine
" Test 1: [[:upper:]]\{2,\}
set regexpengine=0
@@ -586,7 +580,7 @@ func Test_match_char_class_upper()
call assert_equal(4, searchcount().total, 'TEST 3 lower')
" clean up
- let &regexpengine=_engine
+ set regexpengine=0
bwipe!
endfunc
@@ -598,4 +592,13 @@ func Test_match_invalid_byte()
call delete('Xinvalid')
endfunc
+func Test_match_too_complicated()
+ set regexpengine=1
+ exe "noswapfile vsplit \xeb\xdb\x99"
+ silent! buf \&\zs*\zs*0
+ bwipe!
+ set regexpengine=0
+endfunc
+
+
" vim: shiftwidth=2 sts=2 expandtab
diff --git a/src/nvim/testdir/test_registers.vim b/src/nvim/testdir/test_registers.vim
index 84a5aca3d5..52e745438d 100644
--- a/src/nvim/testdir/test_registers.vim
+++ b/src/nvim/testdir/test_registers.vim
@@ -1,6 +1,4 @@
-"
" Tests for register operations
-"
source check.vim
source view_util.vim
@@ -13,6 +11,8 @@ func Test_aaa_empty_reg_test()
call assert_fails('normal @!', 'E354:')
call assert_fails('normal @:', 'E30:')
call assert_fails('normal @.', 'E29:')
+ call assert_fails('put /', 'E35:')
+ call assert_fails('put .', 'E29:')
endfunc
func Test_yank_shows_register()
@@ -62,7 +62,6 @@ func Test_display_registers()
call assert_match('^\nType Name Content\n'
\ . ' c "" a\n'
\ . ' c "0 ba\n'
- \ . ' c "1 b\n'
\ . ' c "a b\n'
\ . '.*'
\ . ' c "- a\n'
@@ -85,6 +84,90 @@ func Test_display_registers()
let g:clipboard = save_clipboard
endfunc
+func Test_register_one()
+ " delete a line goes into register one
+ new
+ call setline(1, "one")
+ normal dd
+ call assert_equal("one\n", @1)
+
+ " delete a word does not change register one, does change "-
+ call setline(1, "two")
+ normal de
+ call assert_equal("one\n", @1)
+ call assert_equal("two", @-)
+
+ " delete a word with a register does not change register one
+ call setline(1, "three")
+ normal "ade
+ call assert_equal("three", @a)
+ call assert_equal("one\n", @1)
+
+ " delete a word with register DOES change register one with one of a list of
+ " operators
+ " %
+ call setline(1, ["(12)3"])
+ normal "ad%
+ call assert_equal("(12)", @a)
+ call assert_equal("(12)", @1)
+
+ " (
+ call setline(1, ["first second"])
+ normal $"ad(
+ call assert_equal("first secon", @a)
+ call assert_equal("first secon", @1)
+
+ " )
+ call setline(1, ["First Second."])
+ normal gg0"ad)
+ call assert_equal("First Second.", @a)
+ call assert_equal("First Second.", @1)
+
+ " `
+ call setline(1, ["start here."])
+ normal gg0fhmx0"ad`x
+ call assert_equal("start ", @a)
+ call assert_equal("start ", @1)
+
+ " /
+ call setline(1, ["searchX"])
+ exe "normal gg0\"ad/X\<CR>"
+ call assert_equal("search", @a)
+ call assert_equal("search", @1)
+
+ " ?
+ call setline(1, ["Ysearch"])
+ exe "normal gg$\"ad?Y\<CR>"
+ call assert_equal("Ysearc", @a)
+ call assert_equal("Ysearc", @1)
+
+ " n
+ call setline(1, ["Ynext"])
+ normal gg$"adn
+ call assert_equal("Ynex", @a)
+ call assert_equal("Ynex", @1)
+
+ " N
+ call setline(1, ["prevY"])
+ normal gg0"adN
+ call assert_equal("prev", @a)
+ call assert_equal("prev", @1)
+
+ " }
+ call setline(1, ["one", ""])
+ normal gg0"ad}
+ call assert_equal("one\n", @a)
+ call assert_equal("one\n", @1)
+
+ " {
+ call setline(1, ["", "two"])
+ normal 2G$"ad{
+ call assert_equal("\ntw", @a)
+ call assert_equal("\ntw", @1)
+
+ bwipe!
+endfunc
+
func Test_recording_status_in_ex_line()
norm qx
redraw!
@@ -119,6 +202,17 @@ func Test_recording_esc_sequence()
endif
endfunc
+func Test_recording_with_select_mode()
+ new
+ call feedkeys("qacc12345\<Esc>gH98765\<Esc>q", "tx")
+ call assert_equal("98765", getline(1))
+ call assert_equal("cc12345\<Esc>gH98765\<Esc>", @a)
+ call setline(1, 'asdf')
+ normal! @a
+ call assert_equal("98765", getline(1))
+ bwipe!
+endfunc
+
" Test for executing the last used register (@)
func Test_last_used_exec_reg()
" Test for the @: command
@@ -141,6 +235,14 @@ func Test_last_used_exec_reg()
normal @@
call assert_equal('EditEdit', a)
+ " Test for repeating the last command-line in visual mode
+ call append(0, 'register')
+ normal gg
+ let @r = ''
+ call feedkeys("v:yank R\<CR>", 'xt')
+ call feedkeys("v@:", 'xt')
+ call assert_equal("\nregister\nregister\n", @r)
+
enew!
endfunc
@@ -164,6 +266,19 @@ func Test_get_register()
call assert_equal('', getregtype('!'))
+ " Test for inserting an invalid register content
+ call assert_beeps('exe "normal i\<C-R>!"')
+
+ " Test for inserting a register with multiple lines
+ call deletebufline('', 1, '$')
+ call setreg('r', ['a', 'b'])
+ exe "normal i\<C-R>r"
+ call assert_equal(['a', 'b', ''], getline(1, '$'))
+
+ " 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
+
enew!
endfunc
@@ -187,9 +302,214 @@ func Test_set_register()
call setreg('=', 'b', 'a')
call assert_equal('regwrite', getreg('='))
+ " Test for setting a list of lines to special registers
+ call setreg('/', [])
+ call assert_equal('', @/)
+ call setreg('=', [])
+ call assert_equal('', @=)
+ call assert_fails("call setreg('/', ['a', 'b'])", 'E883:')
+ call assert_fails("call setreg('=', ['a', 'b'])", 'E883:')
+ call assert_equal(0, setreg('_', ['a', 'b']))
+
+ " Test for recording to a invalid register
+ call assert_beeps('normal q$')
+
+ " Appending to a register when recording
+ call append(0, "text for clipboard test")
+ normal gg
+ call feedkeys('qrllq', 'xt')
+ call feedkeys('qRhhq', 'xt')
+ call assert_equal('llhh', getreg('r'))
+
+ " Appending a list of characters to a register from different lines
+ let @r = ''
+ call append(0, ['abcdef', '123456'])
+ normal gg"ry3l
+ call cursor(2, 4)
+ normal "Ry3l
+ call assert_equal('abc456', @r)
+
+ " Test for gP with multiple lines selected using characterwise motion
+ %delete
+ call append(0, ['vim editor', 'vim editor'])
+ let @r = ''
+ exe "normal ggwy/vim /e\<CR>gP"
+ call assert_equal(['vim editor', 'vim editor', 'vim editor'], getline(1, 3))
+
+ " Test for gP with . register
+ %delete
+ normal iabc
+ normal ".gp
+ call assert_equal('abcabc', getline(1))
+ normal 0".gP
+ call assert_equal('abcabcabc', getline(1))
+
enew!
endfunc
+" Test for clipboard registers (* and +)
+func Test_clipboard_regs()
+ throw 'skipped: needs clipboard=autoselect,autoselectplus'
+
+ CheckNotGui
+ CheckFeature clipboard_working
+
+ new
+ call append(0, "text for clipboard test")
+ normal gg"*yiw
+ call assert_equal('text', getreg('*'))
+ normal gg2w"+yiw
+ call assert_equal('clipboard', getreg('+'))
+
+ " Test for replacing the clipboard register contents
+ set clipboard=unnamed
+ let @* = 'food'
+ normal ggviw"*p
+ call assert_equal('text', getreg('*'))
+ call assert_equal('food for clipboard test', getline(1))
+ normal ggviw"*p
+ call assert_equal('food', getreg('*'))
+ call assert_equal('text for clipboard test', getline(1))
+
+ " Test for replacing the selection register contents
+ set clipboard=unnamedplus
+ let @+ = 'food'
+ normal ggviw"+p
+ call assert_equal('text', getreg('+'))
+ call assert_equal('food for clipboard test', getline(1))
+ normal ggviw"+p
+ call assert_equal('food', getreg('+'))
+ call assert_equal('text for clipboard test', getline(1))
+
+ " Test for auto copying visually selected text to clipboard register
+ call setline(1, "text for clipboard test")
+ let @* = ''
+ set clipboard=autoselect
+ normal ggwwviwy
+ call assert_equal('clipboard', @*)
+
+ " Test for auto copying visually selected text to selection register
+ let @+ = ''
+ set clipboard=autoselectplus
+ normal ggwviwy
+ call assert_equal('for', @+)
+
+ set clipboard&vim
+ bwipe!
+endfunc
+
+" Test for restarting the current mode (insert or virtual replace) after
+" executing the contents of a register
+func Test_put_reg_restart_mode()
+ new
+ call append(0, 'editor')
+ normal gg
+ let @r = "ivim \<Esc>"
+ call feedkeys("i\<C-O>@r\<C-R>=mode()\<CR>", 'xt')
+ call assert_equal('vimi editor', getline(1))
+
+ call setline(1, 'editor')
+ normal gg
+ call feedkeys("gR\<C-O>@r\<C-R>=mode()\<CR>", 'xt')
+ call assert_equal('vimReditor', getline(1))
+
+ bwipe!
+endfunc
+
+" Test for executing a register using :@ command
+func Test_execute_register()
+ call setreg('r', [])
+ call assert_beeps('@r')
+ let i = 1
+ let @q = 'let i+= 1'
+ @q
+ @
+ call assert_equal(3, i)
+
+ " cannot execute a register in operator pending mode
+ call assert_beeps('normal! c@r')
+endfunc
+
+" Test for getting register info
+func Test_get_reginfo()
+ enew
+ call setline(1, ['foo', 'bar'])
+
+ exe 'norm! "zyy'
+ let info = getreginfo('"')
+ call assert_equal('z', info.points_to)
+ call setreg('y', 'baz')
+ call assert_equal('z', getreginfo('').points_to)
+ call setreg('y', { 'isunnamed': v:true })
+ call assert_equal('y', getreginfo('"').points_to)
+
+ exe '$put'
+ call assert_equal(getreg('y'), getline(3))
+ call setreg('', 'qux')
+ call assert_equal('0', getreginfo('').points_to)
+ call setreg('x', 'quux')
+ call assert_equal('0', getreginfo('').points_to)
+
+ let info = getreginfo('')
+ call assert_equal(getreg('', 1, 1), info.regcontents)
+ call assert_equal(getregtype(''), info.regtype)
+
+ exe "norm! 0\<c-v>e" .. '"zy'
+ let info = getreginfo('z')
+ call assert_equal(getreg('z', 1, 1), info.regcontents)
+ call assert_equal(getregtype('z'), info.regtype)
+ call assert_equal(1, +info.isunnamed)
+
+ let info = getreginfo('"')
+ call assert_equal('z', info.points_to)
+
+ bwipe!
+endfunc
+
+" Test for restoring register with dict from getreginfo
+func Test_set_register_dict()
+ enew!
+
+ call setreg('"', #{ regcontents: ['one', 'two'],
+ \ regtype: 'V', points_to: 'z' })
+ call assert_equal(['one', 'two'], getreg('"', 1, 1))
+ let info = getreginfo('"')
+ call assert_equal('z', info.points_to)
+ call assert_equal('V', info.regtype)
+ call assert_equal(1, +getreginfo('z').isunnamed)
+
+ call setreg('x', #{ regcontents: ['three', 'four'],
+ \ regtype: 'v', isunnamed: v:true })
+ call assert_equal(['three', 'four'], getreg('"', 1, 1))
+ let info = getreginfo('"')
+ call assert_equal('x', info.points_to)
+ call assert_equal('v', info.regtype)
+ call assert_equal(1, +getreginfo('x').isunnamed)
+
+ call setreg('y', #{ regcontents: 'five',
+ \ regtype: "\<c-v>", isunnamed: v:false })
+ call assert_equal("\<c-v>4", getreginfo('y').regtype)
+ call assert_equal(0, +getreginfo('y').isunnamed)
+ call assert_equal(['three', 'four'], getreg('"', 1, 1))
+ call assert_equal('x', getreginfo('"').points_to)
+
+ call setreg('"', #{ regcontents: 'six' })
+ call assert_equal('0', getreginfo('"').points_to)
+ call assert_equal(1, +getreginfo('0').isunnamed)
+ call assert_equal(['six'], getreginfo('0').regcontents)
+ call assert_equal(['six'], getreginfo('"').regcontents)
+
+ let @x = 'one'
+ call setreg('x', {})
+ call assert_equal(1, len(split(execute('reg x'), '\n')))
+
+ call assert_fails("call setreg('0', #{regtype: 'V'}, 'v')", 'E118:')
+ call assert_fails("call setreg('0', #{regtype: 'X'})", 'E475:')
+ call assert_fails("call setreg('0', #{regtype: 'vy'})", 'E475:')
+
+ bwipe!
+endfunc
+
func Test_v_register()
enew
call setline(1, 'nothing')
@@ -259,6 +579,82 @@ func Test_v_register()
bwipe!
endfunc
+" Test for executing the contents of a register as an Ex command with line
+" continuation.
+func Test_execute_reg_as_ex_cmd()
+ " Line continuation with just two lines
+ let code =<< trim END
+ let l = [
+ \ 1]
+ END
+ let @r = code->join("\n")
+ let l = []
+ @r
+ call assert_equal([1], l)
+
+ " Line continuation with more than two lines
+ let code =<< trim END
+ let l = [
+ \ 1,
+ \ 2,
+ \ 3]
+ END
+ let @r = code->join("\n")
+ let l = []
+ @r
+ call assert_equal([1, 2, 3], l)
+
+ " use comments interspersed with code
+ let code =<< trim END
+ let l = [
+ "\ one
+ \ 1,
+ "\ two
+ \ 2,
+ "\ three
+ \ 3]
+ END
+ let @r = code->join("\n")
+ let l = []
+ @r
+ call assert_equal([1, 2, 3], l)
+
+ " use line continuation in the middle
+ let code =<< trim END
+ let a = "one"
+ let l = [
+ \ 1,
+ \ 2]
+ let b = "two"
+ END
+ let @r = code->join("\n")
+ let l = []
+ @r
+ call assert_equal([1, 2], l)
+ call assert_equal("one", a)
+ call assert_equal("two", b)
+
+ " only one line with a \
+ let @r = "\\let l = 1"
+ call assert_fails('@r', 'E10:')
+
+ " only one line with a "\
+ let @r = ' "\ let i = 1'
+ @r
+ call assert_false(exists('i'))
+
+ " first line also begins with a \
+ let @r = "\\let l = [\n\\ 1]"
+ call assert_fails('@r', 'E10:')
+
+ " Test with a large number of lines
+ let @r = "let str = \n"
+ let @r ..= repeat(" \\ 'abcdefghijklmnopqrstuvwxyz' ..\n", 312)
+ let @r ..= ' \ ""'
+ @r
+ call assert_equal(repeat('abcdefghijklmnopqrstuvwxyz', 312), str)
+endfunc
+
func Test_ve_blockpaste()
new
set ve=all
@@ -288,84 +684,74 @@ func Test_insert_small_delete()
bwipe!
endfunc
-" Test for getting register info
-func Test_get_reginfo()
- enew
- call setline(1, ['foo', 'bar'])
-
- exe 'norm! "zyy'
- let info = getreginfo('"')
- call assert_equal('z', info.points_to)
- call setreg('y', 'baz')
- call assert_equal('z', getreginfo('').points_to)
- call setreg('y', { 'isunnamed': v:true })
- call assert_equal('y', getreginfo('"').points_to)
-
- exe '$put'
- call assert_equal(getreg('y'), getline(3))
- call setreg('', 'qux')
- call assert_equal('0', getreginfo('').points_to)
- call setreg('x', 'quux')
- call assert_equal('0', getreginfo('').points_to)
-
- let info = getreginfo('')
- call assert_equal(getreg('', 1, 1), info.regcontents)
- call assert_equal(getregtype(''), info.regtype)
-
- exe "norm! 0\<c-v>e" .. '"zy'
- let info = getreginfo('z')
- call assert_equal(getreg('z', 1, 1), info.regcontents)
- call assert_equal(getregtype('z'), info.regtype)
- call assert_equal(1, +info.isunnamed)
-
- let info = getreginfo('"')
- call assert_equal('z', info.points_to)
-
+" Record in insert mode using CTRL-O
+func Test_record_in_insert_mode()
+ new
+ let @r = ''
+ call setline(1, ['foo'])
+ call feedkeys("i\<C-O>qrbaz\<C-O>q", 'xt')
+ call assert_equal('baz', @r)
bwipe!
endfunc
-" Test for restoring register with dict from getreginfo
-func Test_set_register_dict()
- enew!
-
- call setreg('"', #{ regcontents: ['one', 'two'],
- \ regtype: 'V', points_to: 'z' })
- call assert_equal(['one', 'two'], getreg('"', 1, 1))
- let info = getreginfo('"')
- call assert_equal('z', info.points_to)
- call assert_equal('V', info.regtype)
- call assert_equal(1, +getreginfo('z').isunnamed)
+func Test_record_in_select_mode()
+ new
+ call setline(1, 'text')
+ sil norm q00
+ sil norm q
+ call assert_equal('0ext', getline(1))
+
+ %delete
+ let @r = ''
+ call setline(1, ['abc', 'abc', 'abc'])
+ smap <F2> <Right><Right>,
+ call feedkeys("qrgh\<F2>Dk\<Esc>q", 'xt')
+ call assert_equal("gh\<F2>Dk\<Esc>", @r)
+ norm j0@rj0@@
+ call assert_equal([',Dk', ',Dk', ',Dk'], getline(1, 3))
+ sunmap <F2>
- call setreg('x', #{ regcontents: ['three', 'four'],
- \ regtype: 'v', isunnamed: v:true })
- call assert_equal(['three', 'four'], getreg('"', 1, 1))
- let info = getreginfo('"')
- call assert_equal('x', info.points_to)
- call assert_equal('v', info.regtype)
- call assert_equal(1, +getreginfo('x').isunnamed)
+ bwipe!
+endfunc
- call setreg('y', #{ regcontents: 'five',
- \ regtype: "\<c-v>", isunnamed: v:false })
- call assert_equal("\<c-v>4", getreginfo('y').regtype)
- call assert_equal(0, +getreginfo('y').isunnamed)
- call assert_equal(['three', 'four'], getreg('"', 1, 1))
- call assert_equal('x', getreginfo('"').points_to)
+" mapping that ends macro recording should be removed from recorded macro
+func Test_end_record_using_mapping()
+ call setline(1, 'aaa')
+ nnoremap s q
+ call feedkeys('safas', 'tx')
+ call assert_equal('fa', @a)
+ nunmap s
- call setreg('"', #{ regcontents: 'six' })
- call assert_equal('0', getreginfo('"').points_to)
- call assert_equal(1, +getreginfo('0').isunnamed)
- call assert_equal(['six'], getreginfo('0').regcontents)
- call assert_equal(['six'], getreginfo('"').regcontents)
+ nnoremap xx q
+ call feedkeys('0xxafaxx', 'tx')
+ call assert_equal('fa', @a)
+ nunmap xx
- let @x = 'one'
- call setreg('x', {})
- call assert_equal(1, len(split(execute('reg x'), '\n')))
+ nnoremap xsx q
+ call feedkeys('0qafaxsx', 'tx')
+ call assert_equal('fa', @a)
+ nunmap xsx
- call assert_fails("call setreg('0', #{regtype: 'V'}, 'v')", 'E118:')
- call assert_fails("call setreg('0', #{regtype: 'X'})", 'E475:')
- call assert_fails("call setreg('0', #{regtype: 'vy'})", 'E475:')
+ bwipe!
+endfunc
+func Test_end_reg_executing()
+ nnoremap s <Nop>
+ let @a = 's'
+ call feedkeys("@aqaq\<Esc>", 'tx')
+ call assert_equal('', @a)
+ call assert_equal('', getline(1))
+
+ call setline(1, 'aaa')
+ nnoremap s qa
+ let @a = 'fa'
+ call feedkeys("@asq\<Esc>", 'tx')
+ call assert_equal('', @a)
+ call assert_equal('aaa', getline(1))
+
+ nunmap s
bwipe!
endfunc
+
" vim: shiftwidth=2 sts=2 expandtab
diff --git a/src/nvim/testdir/test_reltime.vim b/src/nvim/testdir/test_reltime.vim
index 37b9e783c6..b381f1ddbb 100644
--- a/src/nvim/testdir/test_reltime.vim
+++ b/src/nvim/testdir/test_reltime.vim
@@ -1,8 +1,8 @@
" Tests for reltime()
-if !has('reltime') || !has('float')
- finish
-endif
+source check.vim
+CheckFeature reltime
+CheckFeature float
func Test_reltime()
let now = reltime()
diff --git a/src/nvim/testdir/test_rename.vim b/src/nvim/testdir/test_rename.vim
index 3887fcfabf..5359b84923 100644
--- a/src/nvim/testdir/test_rename.vim
+++ b/src/nvim/testdir/test_rename.vim
@@ -1,5 +1,7 @@
" Test rename()
+source shared.vim
+
func Test_rename_file_to_file()
call writefile(['foo'], 'Xrename1')
@@ -81,7 +83,7 @@ func Test_rename_copy()
call assert_equal(0, rename('Xrenamedir/Xrenamefile', 'Xrenamefile'))
- if !has('win32')
+ if !has('win32') && !IsRoot()
" On Windows, the source file is removed despite
" its directory being made not writable.
call assert_equal(['foo'], readfile('Xrenamedir/Xrenamefile'))
diff --git a/src/nvim/testdir/test_retab.vim b/src/nvim/testdir/test_retab.vim
index f11a32bade..1650a03876 100644
--- a/src/nvim/testdir/test_retab.vim
+++ b/src/nvim/testdir/test_retab.vim
@@ -69,9 +69,33 @@ func Test_retab()
call assert_equal(" a b c ", Retab('!', 3))
call assert_equal(" a b c ", Retab('', 5))
call assert_equal(" a b c ", Retab('!', 5))
+
+ set tabstop& expandtab&
endfunc
func Test_retab_error()
call assert_fails('retab -1', 'E487:')
call assert_fails('retab! -1', 'E487:')
+ call assert_fails('ret -1000', 'E487:')
+ call assert_fails('ret 10000', 'E475:')
+ call assert_fails('ret 80000000000000000000', 'E475:')
endfunc
+
+func Test_retab_endless()
+ new
+ call setline(1, "\t0\t")
+ let caught = 'no'
+ try
+ while 1
+ set ts=4000
+ retab 4
+ endwhile
+ catch /E1240/
+ let caught = 'yes'
+ endtry
+ bwipe!
+ set tabstop&
+endfunc
+
+
+" vim: shiftwidth=2 sts=2 expandtab
diff --git a/src/nvim/testdir/test_scriptnames.vim b/src/nvim/testdir/test_scriptnames.vim
index fc6c910bfa..44ec146666 100644
--- a/src/nvim/testdir/test_scriptnames.vim
+++ b/src/nvim/testdir/test_scriptnames.vim
@@ -23,4 +23,10 @@ func Test_scriptnames()
bwipe
call delete('Xscripting')
+
+ let msgs = execute('messages')
+ scriptnames
+ call assert_equal(msgs, execute('messages'))
endfunc
+
+" vim: shiftwidth=2 sts=2 expandtab
diff --git a/src/nvim/testdir/test_search.vim b/src/nvim/testdir/test_search.vim
index c796f1f676..3d1bbfb726 100644
--- a/src/nvim/testdir/test_search.vim
+++ b/src/nvim/testdir/test_search.vim
@@ -19,9 +19,9 @@ func Test_search_cmdline()
set noincsearch
:1
call feedkeys("/foobar\<cr>", 'tx')
- call feedkeys("/the\<cr>",'tx')
+ call feedkeys("/the\<cr>", 'tx')
call assert_equal('the', @/)
- call feedkeys("/thes\<C-P>\<C-P>\<cr>",'tx')
+ call feedkeys("/thes\<C-P>\<C-P>\<cr>", 'tx')
call assert_equal('foobar', @/)
" Test 2
@@ -292,15 +292,84 @@ endfunc
func Test_searchpair()
new
- call setline(1, ['other code here', '', '[', '" cursor here', ']'])
+ call setline(1, ['other code', 'here [', ' [', ' " cursor here', ' ]]'])
+
+ 4
+ call assert_equal(3, searchpair('\[', '', ']', 'bW'))
+ call assert_equal([0, 3, 2, 0], getpos('.'))
+ 4
+ call assert_equal(2, searchpair('\[', '', ']', 'bWr'))
+ call assert_equal([0, 2, 6, 0], getpos('.'))
+ 4
+ call assert_equal(1, searchpair('\[', '', ']', 'bWm'))
+ call assert_equal([0, 3, 2, 0], getpos('.'))
+ 4|norm ^
+ call assert_equal(5, searchpair('\[', '', ']', 'Wn'))
+ call assert_equal([0, 4, 2, 0], getpos('.'))
+ 4
+ call assert_equal(2, searchpair('\[', '', ']', 'bW',
+ \ 'getline(".") =~ "^\\s*\["'))
+ call assert_equal([0, 2, 6, 0], getpos('.'))
+ set nomagic
+ 4
+ call assert_equal(3, searchpair('\[', '', ']', 'bW'))
+ call assert_equal([0, 3, 2, 0], getpos('.'))
+ set magic
+ 4|norm ^
+ call assert_equal(0, searchpair('{', '', '}', 'bW'))
+ call assert_equal([0, 4, 2, 0], getpos('.'))
+
+ %d
+ call setline(1, ['if 1', ' if 2', ' else', ' endif 2', 'endif 1'])
+
+ /\<if 1
+ call assert_equal(5, searchpair('\<if\>', '\<else\>', '\<endif\>', 'W'))
+ call assert_equal([0, 5, 1, 0], getpos('.'))
+ /\<if 2
+ call assert_equal(3, searchpair('\<if\>', '\<else\>', '\<endif\>', 'W'))
+ call assert_equal([0, 3, 3, 0], getpos('.'))
+
+ q!
+endfunc
+
+func Test_searchpairpos()
+ new
+ call setline(1, ['other code', 'here [', ' [', ' " cursor here', ' ]]'])
+
4
- let a = searchpair('\[','',']','bW')
- call assert_equal(3, a)
+ call assert_equal([3, 2], searchpairpos('\[', '', ']', 'bW'))
+ call assert_equal([0, 3, 2, 0], getpos('.'))
+ 4
+ call assert_equal([2, 6], searchpairpos('\[', '', ']', 'bWr'))
+ call assert_equal([0, 2, 6, 0], getpos('.'))
+ 4|norm ^
+ call assert_equal([5, 2], searchpairpos('\[', '', ']', 'Wn'))
+ call assert_equal([0, 4, 2, 0], getpos('.'))
+ 4
+ call assert_equal([2, 6], searchpairpos('\[', '', ']', 'bW',
+ \ 'getline(".") =~ "^\\s*\["'))
+ call assert_equal([0, 2, 6, 0], getpos('.'))
+ 4
+ call assert_equal([2, 6], searchpairpos('\[', '', ']', 'bWr'))
+ call assert_equal([0, 2, 6, 0], getpos('.'))
set nomagic
4
- let a = searchpair('\[','',']','bW')
- call assert_equal(3, a)
+ call assert_equal([3, 2], searchpairpos('\[', '', ']', 'bW'))
+ call assert_equal([0, 3, 2, 0], getpos('.'))
set magic
+ 4|norm ^
+ call assert_equal([0, 0], searchpairpos('{', '', '}', 'bW'))
+ call assert_equal([0, 4, 2, 0], getpos('.'))
+
+ %d
+ call setline(1, ['if 1', ' if 2', ' else', ' endif 2', 'endif 1'])
+ /\<if 1
+ call assert_equal([5, 1], searchpairpos('\<if\>', '\<else\>', '\<endif\>', 'W'))
+ call assert_equal([0, 5, 1, 0], getpos('.'))
+ /\<if 2
+ call assert_equal([3, 3], searchpairpos('\<if\>', '\<else\>', '\<endif\>', 'W'))
+ call assert_equal([0, 3, 3, 0], getpos('.'))
+
q!
endfunc
@@ -309,17 +378,29 @@ func Test_searchpair_errors()
call assert_fails("call searchpair('start', {-> 0}, 'end', 'bW', 'skip', 99, 100)", 'E729: using Funcref as a String')
call assert_fails("call searchpair('start', 'middle', {'one': 1}, 'bW', 'skip', 99, 100)", 'E731: using Dictionary as a String')
call assert_fails("call searchpair('start', 'middle', 'end', 'flags', 'skip', 99, 100)", 'E475: Invalid argument: flags')
- call assert_fails("call searchpair('start', 'middle', 'end', 'bW', 0, 99, 100)", 'E475: Invalid argument: 0')
call assert_fails("call searchpair('start', 'middle', 'end', 'bW', 'func', -99, 100)", 'E475: Invalid argument: -99')
call assert_fails("call searchpair('start', 'middle', 'end', 'bW', 'func', 99, -100)", 'E475: Invalid argument: -100')
+ call assert_fails("call searchpair('start', 'middle', 'end', 'e')", 'E475: Invalid argument: e')
+ call assert_fails("call searchpair('start', 'middle', 'end', 'sn')", 'E475: Invalid argument: sn')
+endfunc
+
+func Test_searchpairpos_errors()
+ call assert_fails("call searchpairpos([0], 'middle', 'end', 'bW', 'skip', 99, 100)", 'E730: using List as a String')
+ call assert_fails("call searchpairpos('start', {-> 0}, 'end', 'bW', 'skip', 99, 100)", 'E729: using Funcref as a String')
+ call assert_fails("call searchpairpos('start', 'middle', {'one': 1}, 'bW', 'skip', 99, 100)", 'E731: using Dictionary as a String')
+ call assert_fails("call searchpairpos('start', 'middle', 'end', 'flags', 'skip', 99, 100)", 'E475: Invalid argument: flags')
+ call assert_fails("call searchpairpos('start', 'middle', 'end', 'bW', 'func', -99, 100)", 'E475: Invalid argument: -99')
+ call assert_fails("call searchpairpos('start', 'middle', 'end', 'bW', 'func', 99, -100)", 'E475: Invalid argument: -100')
+ call assert_fails("call searchpairpos('start', 'middle', 'end', 'e')", 'E475: Invalid argument: e')
+ call assert_fails("call searchpairpos('start', 'middle', 'end', 'sn')", 'E475: Invalid argument: sn')
endfunc
func Test_searchpair_skip()
func Zero()
- return 0
+ return 0
endfunc
func Partial(x)
- return a:x
+ return a:x
endfunc
new
call setline(1, ['{', 'foo', 'foo', 'foo', '}'])
@@ -574,10 +655,49 @@ func Test_search_cmdline7()
bw!
endfunc
-" Tests for regexp with various magic settings
-func Test_search_regexp()
- enew!
+func Test_search_cmdline8()
+ " Highlighting is cleared in all windows
+ " since hls applies to all windows
+ CheckOption incsearch
+ CheckFeature terminal
+ CheckNotGui
+ if has("win32")
+ throw "Skipped: Bug with sending <ESC> to terminal window not fixed yet"
+ endif
+ let h = winheight(0)
+ if h < 3
+ return
+ endif
+ " Prepare buffer text
+ let lines = ['abb vim vim vi', 'vimvivim']
+ call writefile(lines, 'Xsearch.txt')
+ let buf = term_start([GetVimProg(), '--clean', '-c', 'set noswapfile', 'Xsearch.txt'], {'term_rows': 3})
+
+ call WaitForAssert({-> assert_equal(lines, [term_getline(buf, 1), term_getline(buf, 2)])})
+
+ call term_sendkeys(buf, ":set incsearch hlsearch\<cr>")
+ call term_sendkeys(buf, ":14vsp\<cr>")
+ call term_sendkeys(buf, "/vim\<cr>")
+ call term_sendkeys(buf, "/b\<esc>")
+ call term_sendkeys(buf, "gg0")
+ call TermWait(buf, 250)
+ let screen_line = term_scrape(buf, 1)
+ let [a0,a1,a2,a3] = [screen_line[3].attr, screen_line[4].attr,
+ \ screen_line[18].attr, screen_line[19].attr]
+ call assert_notequal(a0, a1)
+ call assert_notequal(a0, a3)
+ call assert_notequal(a1, a2)
+ call assert_equal(a0, a2)
+ call assert_equal(a1, a3)
+ " clean up
+ call delete('Xsearch.txt')
+
+ bwipe!
+endfunc
+
+" Tests for regexp with various magic settings
+func Run_search_regexp_magic_opt()
put ='1 a aa abb abbccc'
exe 'normal! /a*b\{2}c\+/e' . "\<CR>"
call assert_equal([0, 2, 17, 0], getpos('.'))
@@ -612,6 +732,18 @@ func Test_search_regexp()
exe 'normal! /\V[ab]\(\[xy]\)\1' . "\<CR>"
call assert_equal([0, 9, 7, 0], getpos('.'))
+ %d
+endfunc
+
+func Test_search_regexp()
+ enew!
+
+ set regexpengine=1
+ call Run_search_regexp_magic_opt()
+ set regexpengine=2
+ call Run_search_regexp_magic_opt()
+ set regexpengine&
+
set undolevels=100
put ='9 foobar'
put =''
@@ -619,12 +751,12 @@ func Test_search_regexp()
normal G
exe 'normal! dv?bar?' . "\<CR>"
call assert_equal('9 foo', getline('.'))
- call assert_equal([0, 10, 5, 0], getpos('.'))
- call assert_equal(10, line('$'))
+ call assert_equal([0, 2, 5, 0], getpos('.'))
+ call assert_equal(2, line('$'))
normal u
call assert_equal('9 foobar', getline('.'))
- call assert_equal([0, 10, 6, 0], getpos('.'))
- call assert_equal(11, line('$'))
+ call assert_equal([0, 2, 6, 0], getpos('.'))
+ call assert_equal(3, line('$'))
set undolevels&
enew!
@@ -844,6 +976,26 @@ func Test_hlsearch_block_visual_match()
call delete('Xhlsearch_block')
endfunc
+func Test_hlsearch_and_visual()
+ CheckOption hlsearch
+ CheckScreendump
+
+ call writefile([
+ \ 'set hlsearch',
+ \ 'call setline(1, repeat(["xxx yyy zzz"], 3))',
+ \ 'hi Search cterm=bold',
+ \ '/yyy',
+ \ 'call cursor(1, 6)',
+ \ ], 'Xhlvisual_script')
+ let buf = RunVimInTerminal('-S Xhlvisual_script', {'rows': 6, 'cols': 40})
+ call term_sendkeys(buf, "vjj")
+ call VerifyScreenDump(buf, 'Test_hlsearch_visual_1', {})
+ call term_sendkeys(buf, "\<Esc>")
+
+ call StopVimInTerminal(buf)
+ call delete('Xhlvisual_script')
+endfunc
+
func Test_incsearch_substitute()
CheckFunction test_override
CheckOption incsearch
@@ -865,6 +1017,51 @@ func Test_incsearch_substitute()
call Incsearch_cleanup()
endfunc
+func Test_hlsearch_cursearch()
+ CheckScreendump
+
+ let lines =<< trim END
+ set hlsearch scrolloff=0
+ call setline(1, ['one', 'foo', 'bar', 'baz', 'foo the foo and foo', 'bar'])
+ hi Search ctermbg=yellow
+ hi CurSearch ctermbg=blue
+ END
+ call writefile(lines, 'Xhlsearch_cursearch')
+ let buf = RunVimInTerminal('-S Xhlsearch_cursearch', {'rows': 9, 'cols': 60})
+
+ call term_sendkeys(buf, "gg/foo\<CR>")
+ call VerifyScreenDump(buf, 'Test_hlsearch_cursearch_single_line_1', {})
+
+ call term_sendkeys(buf, "n")
+ call VerifyScreenDump(buf, 'Test_hlsearch_cursearch_single_line_2', {})
+
+ call term_sendkeys(buf, "n")
+ call VerifyScreenDump(buf, 'Test_hlsearch_cursearch_single_line_2a', {})
+
+ call term_sendkeys(buf, "n")
+ call VerifyScreenDump(buf, 'Test_hlsearch_cursearch_single_line_2b', {})
+
+ call term_sendkeys(buf, ":call setline(5, 'foo')\<CR>")
+ call term_sendkeys(buf, "0?\<CR>")
+ call VerifyScreenDump(buf, 'Test_hlsearch_cursearch_single_line_3', {})
+
+ call term_sendkeys(buf, "gg/foo\\nbar\<CR>")
+ call VerifyScreenDump(buf, 'Test_hlsearch_cursearch_multiple_line_1', {})
+
+ call term_sendkeys(buf, ":call setline(1, ['---', 'abcdefg', 'hijkl', '---', 'abcdefg', 'hijkl'])\<CR>")
+ call term_sendkeys(buf, "gg/efg\\nhij\<CR>")
+ call VerifyScreenDump(buf, 'Test_hlsearch_cursearch_multiple_line_2', {})
+ call term_sendkeys(buf, "h\<C-L>")
+ call VerifyScreenDump(buf, 'Test_hlsearch_cursearch_multiple_line_3', {})
+ call term_sendkeys(buf, "j\<C-L>")
+ call VerifyScreenDump(buf, 'Test_hlsearch_cursearch_multiple_line_4', {})
+ call term_sendkeys(buf, "h\<C-L>")
+ call VerifyScreenDump(buf, 'Test_hlsearch_cursearch_multiple_line_5', {})
+
+ call StopVimInTerminal(buf)
+ call delete('Xhlsearch_cursearch')
+endfunc
+
" Similar to Test_incsearch_substitute() but with a screendump halfway.
func Test_incsearch_substitute_dump()
CheckOption incsearch
@@ -1192,7 +1389,7 @@ endfunc
" This was causing E874. Also causes an invalid read?
func Test_look_behind()
new
- call setline(1, '0\|\&\n\@<=')
+ call setline(1, '0\|\&\n\@<=')
call search(getline("."))
bwipe!
endfunc
@@ -1236,11 +1433,11 @@ endfunc
func Test_search_Ctrl_L_combining()
" Make sure, that Ctrl-L works correctly with combining characters.
" It uses an artificial example of an 'a' with 4 combining chars:
- " 'a' U+0061 Dec:97 LATIN SMALL LETTER A &#x61; /\%u61\Z "\u0061"
+ " 'a' U+0061 Dec:97 LATIN SMALL LETTER A &#x61; /\%u61\Z "\u0061"
" ' ̀' U+0300 Dec:768 COMBINING GRAVE ACCENT &#x300; /\%u300\Z "\u0300"
" ' ́' U+0301 Dec:769 COMBINING ACUTE ACCENT &#x301; /\%u301\Z "\u0301"
" ' ̇' U+0307 Dec:775 COMBINING DOT ABOVE &#x307; /\%u307\Z "\u0307"
- " ' ̣' U+0323 Dec:803 COMBINING DOT BELOW &#x323; /\%u323 "\u0323"
+ " ' ̣' U+0323 Dec:803 COMBINING DOT BELOW &#x323; /\%u323 "\u0323"
" Those should also appear on the commandline
CheckOption incsearch
@@ -1287,7 +1484,7 @@ func Test_large_hex_chars2()
endfunc
func Test_one_error_msg()
- " This was also giving an internal error
+ " This was also giving an internal error
call assert_fails('call search(" \\((\\v[[=P=]]){185}+ ")', 'E871:')
endfunc
@@ -1332,6 +1529,20 @@ func Test_search_match_at_curpos()
close!
endfunc
+" Test for error cases with the search() function
+func Test_search_errors()
+ call assert_fails("call search('pat', [])", 'E730:')
+ call assert_fails("call search('pat', 'b', {})", 'E728:')
+ call assert_fails("call search('pat', 'b', 1, [])", 'E745:')
+ call assert_fails("call search('pat', 'ns')", 'E475:')
+ call assert_fails("call search('pat', 'mr')", 'E475:')
+
+ new
+ call setline(1, ['foo', 'bar'])
+ call assert_fails('call feedkeys("/foo/;/bar/;\<CR>", "tx")', 'E386:')
+ bwipe!
+endfunc
+
func Test_search_display_pattern()
new
call setline(1, ['foo', 'bar', 'foobar'])
@@ -1395,6 +1606,160 @@ func Test_search_special()
exe "norm /\x80PS"
endfunc
+" Test for command failures when the last search pattern is not set.
+" Need to run this in a new vim instance where last search pattern is not set.
+func Test_search_with_no_last_pat()
+ let lines =<< trim [SCRIPT]
+ call assert_fails("normal i\<C-R>/\e", 'E35:')
+ call assert_fails("exe '/'", 'E35:')
+ call assert_fails("exe '?'", 'E35:')
+ call assert_fails("/", 'E35:')
+ call assert_fails("?", 'E35:')
+ call assert_fails("normal n", 'E35:')
+ call assert_fails("normal N", 'E35:')
+ call assert_fails("normal gn", 'E35:')
+ call assert_fails("normal gN", 'E35:')
+ call assert_fails("normal cgn", 'E35:')
+ call assert_fails("normal cgN", 'E35:')
+ let p = []
+ let p = @/
+ call assert_equal('', p)
+ call assert_fails("normal :\<C-R>/", 'E35:')
+ call assert_fails("//p", 'E35:')
+ call assert_fails(";//p", 'E35:')
+ call assert_fails("??p", 'E35:')
+ call assert_fails(";??p", 'E35:')
+ call assert_fails('g//p', 'E476:')
+ call assert_fails('v//p', 'E476:')
+ call writefile(v:errors, 'Xresult')
+ qall!
+ [SCRIPT]
+ call writefile(lines, 'Xscript')
+
+ if RunVim([], [], '--clean -S Xscript')
+ call assert_equal([], readfile('Xresult'))
+ endif
+ call delete('Xscript')
+ call delete('Xresult')
+endfunc
+
+" Test for using tilde (~) atom in search. This should use the last used
+" substitute pattern
+func Test_search_tilde_pat()
+ let lines =<< trim [SCRIPT]
+ set regexpengine=1
+ call assert_fails('exe "normal /~\<CR>"', 'E33:')
+ call assert_fails('exe "normal ?~\<CR>"', 'E33:')
+ set regexpengine=2
+ call assert_fails('exe "normal /~\<CR>"', 'E383:')
+ call assert_fails('exe "normal ?~\<CR>"', 'E383:')
+ set regexpengine&
+ call writefile(v:errors, 'Xresult')
+ qall!
+ [SCRIPT]
+ call writefile(lines, 'Xscript')
+ if RunVim([], [], '--clean -S Xscript')
+ call assert_equal([], readfile('Xresult'))
+ endif
+ call delete('Xscript')
+ call delete('Xresult')
+endfunc
+
+" Test for searching a pattern that is not present with 'nowrapscan'
+func Test_search_pat_not_found()
+ new
+ set nowrapscan
+ let @/ = '1abcxyz2'
+ call assert_fails('normal n', 'E385:')
+ call assert_fails('normal N', 'E384:')
+ set wrapscan&
+ close
+endfunc
+
+" Test for v:searchforward variable
+func Test_searchforward_var()
+ new
+ call setline(1, ['foo', '', 'foo'])
+ call cursor(2, 1)
+ let @/ = 'foo'
+ let v:searchforward = 0
+ normal N
+ call assert_equal(3, line('.'))
+ call cursor(2, 1)
+ let v:searchforward = 1
+ normal N
+ call assert_equal(1, line('.'))
+ close!
+endfunc
+
+" Test for invalid regular expressions
+func Test_invalid_regexp()
+ set regexpengine=1
+ call assert_fails("call search(repeat('\\(.\\)', 10))", 'E51:')
+ call assert_fails("call search('\\%(')", 'E53:')
+ call assert_fails("call search('\\(')", 'E54:')
+ call assert_fails("call search('\\)')", 'E55:')
+ call assert_fails("call search('x\\@#')", 'E59:')
+ call assert_fails('call search(''\v%(%(%(%(%(%(%(%(%(%(%(a){1}){1}){1}){1}){1}){1}){1}){1}){1}){1}){1}'')', 'E60:')
+ call assert_fails("call search('a\\+*')", 'E61:')
+ call assert_fails("call search('\\_m')", 'E63:')
+ call assert_fails("call search('\\+')", 'E64:')
+ call assert_fails("call search('\\1')", 'E65:')
+ call assert_fails("call search('\\z\\(\\)')", 'E66:')
+ call assert_fails("call search('\\z2')", 'E67:')
+ call assert_fails("call search('\\zx')", 'E68:')
+ call assert_fails("call search('\\%[ab')", 'E69:')
+ call assert_fails("call search('\\%[]')", 'E70:')
+ call assert_fails("call search('\\%a')", 'E71:')
+ call assert_fails("call search('ab\\%[\\(cd\\)]')", 'E369:')
+ call assert_fails("call search('ab\\%[\\%(cd\\)]')", 'E369:')
+ set regexpengine=2
+ call assert_fails("call search('\\_')", 'E865:')
+ call assert_fails("call search('\\+')", 'E866:')
+ call assert_fails("call search('\\zx')", 'E867:')
+ call assert_fails("call search('\\%a')", 'E867:')
+ call assert_fails("call search('x\\@#')", 'E869:')
+ call assert_fails("call search(repeat('\\(.\\)', 10))", 'E872:')
+ call assert_fails("call search('\\_m')", 'E877:')
+ call assert_fails("call search('\\%(')", 'E53:')
+ call assert_fails("call search('\\(')", 'E54:')
+ call assert_fails("call search('\\)')", 'E55:')
+ call assert_fails("call search('\\z\\(\\)')", 'E66:')
+ call assert_fails("call search('\\%[ab')", 'E69:')
+ call assert_fails("call search('\\%[]')", 'E70:')
+ call assert_fails("call search('\\%9999999999999999999999999999v')", 'E951:')
+ set regexpengine&
+ call assert_fails("call search('\\%#=3ab')", 'E864:')
+endfunc
+
+" Test for searching with 'smartcase' and 'ignorecase'
+func Test_search_smartcase()
+ new
+ call setline(1, ['', 'Hello'])
+ set noignorecase nosmartcase
+ call assert_fails('exe "normal /\\a\\_.\\(.*\\)O\<CR>"', 'E486:')
+
+ set ignorecase nosmartcase
+ exe "normal /\\a\\_.\\(.*\\)O\<CR>"
+ call assert_equal([2, 1], [line('.'), col('.')])
+
+ call cursor(1, 1)
+ set ignorecase smartcase
+ call assert_fails('exe "normal /\\a\\_.\\(.*\\)O\<CR>"', 'E486:')
+
+ exe "normal /\\a\\_.\\(.*\\)o\<CR>"
+ call assert_equal([2, 1], [line('.'), col('.')])
+
+ " Test for using special atoms with 'smartcase'
+ call setline(1, ['', ' Hello\ '])
+ call cursor(1, 1)
+ call feedkeys('/\_.\%(\uello\)\' .. "\<CR>", 'xt')
+ call assert_equal([2, 4], [line('.'), col('.')])
+
+ set ignorecase& smartcase&
+ close!
+endfun
+
" Test 'smartcase' with utf-8.
func Test_search_smartcase_utf8()
new
@@ -1414,6 +1779,102 @@ func Test_search_smartcase_utf8()
close!
endfunc
+" Test searching past the end of a file
+func Test_search_past_eof()
+ new
+ call setline(1, ['Line'])
+ exe "normal /\\n\\zs\<CR>"
+ call assert_equal([1, 4], [line('.'), col('.')])
+ close!
+endfunc
+
+" Test for various search offsets
+func Test_search_offset()
+ " With /e, for a match in the first column of a line, the cursor should be
+ " placed at the end of the previous line.
+ new
+ call setline(1, ['one two', 'three four'])
+ call search('two\_.', 'e')
+ call assert_equal([1, 7], [line('.'), col('.')])
+
+ " with cursor at the beginning of the file, use /s+1
+ call cursor(1, 1)
+ exe "normal /two/s+1\<CR>"
+ call assert_equal([1, 6], [line('.'), col('.')])
+
+ " with cursor at the end of the file, use /e-1
+ call cursor(2, 10)
+ exe "normal ?three?e-1\<CR>"
+ call assert_equal([2, 4], [line('.'), col('.')])
+
+ " line offset - after the last line
+ call cursor(1, 1)
+ exe "normal /three/+1\<CR>"
+ call assert_equal([2, 1], [line('.'), col('.')])
+
+ " line offset - before the first line
+ call cursor(2, 1)
+ exe "normal ?one?-1\<CR>"
+ call assert_equal([1, 1], [line('.'), col('.')])
+
+ " character offset - before the first character in the file
+ call cursor(2, 1)
+ exe "normal ?one?s-1\<CR>"
+ call assert_equal([1, 1], [line('.'), col('.')])
+ call cursor(2, 1)
+ exe "normal ?one?e-3\<CR>"
+ call assert_equal([1, 1], [line('.'), col('.')])
+
+ " character offset - after the last character in the file
+ call cursor(1, 1)
+ exe "normal /four/s+4\<CR>"
+ call assert_equal([2, 10], [line('.'), col('.')])
+ call cursor(1, 1)
+ exe "normal /four/e+1\<CR>"
+ call assert_equal([2, 10], [line('.'), col('.')])
+
+ close!
+endfunc
+
+" Test for searching for matching parenthesis using %
+func Test_search_match_paren()
+ new
+ call setline(1, "abc(def')'ghi'('jk'\\t'lm)no")
+ " searching for a matching parenthesis should skip single quoted characters
+ call cursor(1, 4)
+ normal %
+ call assert_equal([1, 25], [line('.'), col('.')])
+ normal %
+ call assert_equal([1, 4], [line('.'), col('.')])
+ call cursor(1, 5)
+ normal ])
+ call assert_equal([1, 25], [line('.'), col('.')])
+ call cursor(1, 24)
+ normal [(
+ call assert_equal([1, 4], [line('.'), col('.')])
+
+ " matching parenthesis in 'virtualedit' mode with cursor after the eol
+ call setline(1, 'abc(defgh)')
+ set virtualedit=all
+ normal 20|%
+ call assert_equal(4, col('.'))
+ set virtualedit&
+ close!
+endfunc
+
+" Test for searching a pattern and stopping before a specified line
+func Test_search_stopline()
+ new
+ call setline(1, ['', '', '', 'vim'])
+ call assert_equal(0, search('vim', 'n', 3))
+ call assert_equal(4, search('vim', 'n', 4))
+ call setline(1, ['vim', '', '', ''])
+ call cursor(4, 1)
+ call assert_equal(0, search('vim', 'bn', 2))
+ call assert_equal(1, search('vim', 'bn', 1))
+ close!
+endfunc
+
func Test_incsearch_highlighting_newline()
CheckRunVimInTerminal
CheckOption incsearch
@@ -1446,4 +1907,31 @@ func Test_incsearch_highlighting_newline()
bw
endfunc
+func Test_no_last_search_pattern()
+ CheckOption incsearch
+
+ let @/ = ""
+ set incsearch
+ " these were causing a crash
+ call feedkeys("//\<C-G>", 'xt')
+ call feedkeys("//\<C-T>", 'xt')
+ call feedkeys("??\<C-G>", 'xt')
+ call feedkeys("??\<C-T>", 'xt')
+endfunc
+
+func Test_search_with_invalid_range()
+ new
+ let lines =<< trim END
+ /\%.v
+ 5/
+ c
+ END
+ call writefile(lines, 'Xrangesearch')
+ source Xrangesearch
+
+ bwipe!
+ call delete('Xrangesearch')
+endfunc
+
+
" vim: shiftwidth=2 sts=2 expandtab
diff --git a/src/nvim/testdir/test_search_stat.vim b/src/nvim/testdir/test_search_stat.vim
index f7f7467e91..89e09cf85b 100644
--- a/src/nvim/testdir/test_search_stat.vim
+++ b/src/nvim/testdir/test_search_stat.vim
@@ -1,14 +1,15 @@
" Tests for search_stats, when "S" is not in 'shortmess'
-source screendump.vim
source check.vim
+source screendump.vim
func Test_search_stat()
new
set shortmess-=S
" Append 50 lines with text to search for, "foobar" appears 20 times
call append(0, repeat(['foobar', 'foo', 'fooooobar', 'foba', 'foobar'], 10))
- call nvim_win_set_cursor(0, [1, 0])
+
+ call cursor(1, 1)
" searchcount() returns an empty dictionary when previous pattern was not set
call assert_equal({}, searchcount(#{pattern: ''}))
@@ -45,7 +46,6 @@ func Test_search_stat()
\ searchcount(#{pattern: 'fooooobar', maxcount: 1}))
" match at second line
- call cursor(1, 1)
let messages_before = execute('messages')
let @/ = 'fo*\(bar\?\)\?'
let g:a = execute(':unsilent :norm! n')
@@ -262,6 +262,34 @@ func Test_searchcount_fails()
call assert_fails('echo searchcount("boo!")', 'E715:')
endfunc
+func Test_searchcount_in_statusline()
+ CheckScreendump
+
+ let lines =<< trim END
+ set shortmess-=S
+ call append(0, 'this is something')
+ function TestSearchCount() abort
+ let search_count = searchcount()
+ if !empty(search_count)
+ return '[' . search_count.current . '/' . search_count.total . ']'
+ else
+ return ''
+ endif
+ endfunction
+ set hlsearch
+ set laststatus=2 statusline+=%{TestSearchCount()}
+ END
+ call writefile(lines, 'Xsearchstatusline')
+ let buf = RunVimInTerminal('-S Xsearchstatusline', #{rows: 10})
+ call TermWait(buf)
+ call term_sendkeys(buf, "/something")
+ call VerifyScreenDump(buf, 'Test_searchstat_4', {})
+
+ call term_sendkeys(buf, "\<Esc>")
+ call StopVimInTerminal(buf)
+ call delete('Xsearchstatusline')
+endfunc
+
func Test_search_stat_foldopen()
CheckScreendump
@@ -319,30 +347,71 @@ func! Test_search_stat_screendump()
call delete('Xsearchstat')
endfunc
-func Test_searchcount_in_statusline()
+func Test_search_stat_then_gd()
CheckScreendump
let lines =<< trim END
+ call setline(1, ['int cat;', 'int dog;', 'cat = dog;'])
set shortmess-=S
- call append(0, 'this is something')
- function TestSearchCount() abort
- let search_count = searchcount()
- if !empty(search_count)
- return '[' . search_count.current . '/' . search_count.total . ']'
- else
- return ''
- endif
- endfunction
set hlsearch
- set laststatus=2 statusline+=%{TestSearchCount()}
END
- call writefile(lines, 'Xsearchstatusline')
- let buf = RunVimInTerminal('-S Xsearchstatusline', #{rows: 10})
+ call writefile(lines, 'Xsearchstatgd')
+
+ let buf = RunVimInTerminal('-S Xsearchstatgd', #{rows: 10})
+ call term_sendkeys(buf, "/dog\<CR>")
call TermWait(buf)
- call term_sendkeys(buf, "/something")
- call VerifyScreenDump(buf, 'Test_searchstat_4', {})
+ call VerifyScreenDump(buf, 'Test_searchstatgd_1', {})
+
+ call term_sendkeys(buf, "G0gD")
+ call TermWait(buf)
+ call VerifyScreenDump(buf, 'Test_searchstatgd_2', {})
- call term_sendkeys(buf, "\<Esc>")
call StopVimInTerminal(buf)
- call delete('Xsearchstatusline')
+ call delete('Xsearchstatgd')
endfunc
+
+func Test_search_stat_and_incsearch()
+ CheckScreendump
+
+ let lines =<< trim END
+ call setline(1, ['abc--c', '--------abc', '--abc'])
+ set hlsearch
+ set incsearch
+ set bg=dark
+ set showtabline=2
+
+ function MyTabLine()
+ try
+ let a=searchcount(#{recompute: 1, maxcount: -1})
+ return a.current .. '/' .. a.total
+ catch
+ return ''
+ endtry
+ endfunction
+
+ set tabline=%!MyTabLine()
+ END
+ call writefile(lines, 'Xsearchstat_inc')
+
+ let buf = RunVimInTerminal('-S Xsearchstat_inc', #{rows: 10})
+ call term_sendkeys(buf, "/abc")
+ call TermWait(buf)
+ call VerifyScreenDump(buf, 'Test_searchstat_inc_1', {})
+
+ call term_sendkeys(buf, "\<c-g>")
+ call TermWait(buf)
+ call VerifyScreenDump(buf, 'Test_searchstat_inc_2', {})
+
+ call term_sendkeys(buf, "\<c-g>")
+ call TermWait(buf)
+ call VerifyScreenDump(buf, 'Test_searchstat_inc_3', {})
+
+ call term_sendkeys(buf, "\<esc>:qa\<cr>")
+ call TermWait(buf)
+
+ call StopVimInTerminal(buf)
+ call delete('Xsearchstat_inc')
+endfunc
+
+
+" vim: shiftwidth=2 sts=2 expandtab
diff --git a/src/nvim/testdir/test_searchpos.vim b/src/nvim/testdir/test_searchpos.vim
new file mode 100644
index 0000000000..dd13c305c5
--- /dev/null
+++ b/src/nvim/testdir/test_searchpos.vim
@@ -0,0 +1,30 @@
+" Tests for searchpos()
+
+func Test_searchpos()
+ new one
+ 0put ='1a3'
+ 1put ='123xyz'
+ call cursor(1, 1)
+ call assert_equal([1, 1, 2], searchpos('\%(\([a-z]\)\|\_.\)\{-}xyz', 'pcW'))
+ call cursor(1, 2)
+ call assert_equal([2, 1, 1], '\%(\([a-z]\)\|\_.\)\{-}xyz'->searchpos('pcW'))
+ set cpo-=c
+ call cursor(1, 2)
+ call assert_equal([1, 2, 2], searchpos('\%(\([a-z]\)\|\_.\)\{-}xyz', 'pcW'))
+ call cursor(1, 3)
+ call assert_equal([1, 3, 1], searchpos('\%(\([a-z]\)\|\_.\)\{-}xyz', 'pcW'))
+
+ " Now with \zs, first match is in column 0, "a" is matched.
+ call cursor(1, 3)
+ call assert_equal([2, 4, 2], searchpos('\%(\([a-z]\)\|\_.\)\{-}\zsxyz', 'pcW'))
+ " With z flag start at cursor column, don't see the "a".
+ call cursor(1, 3)
+ call assert_equal([2, 4, 1], searchpos('\%(\([a-z]\)\|\_.\)\{-}\zsxyz', 'pcWz'))
+
+ set cpo+=c
+ " close the window
+ q!
+
+endfunc
+
+" vim: shiftwidth=2 sts=2 expandtab
diff --git a/src/nvim/testdir/test_selectmode.vim b/src/nvim/testdir/test_selectmode.vim
new file mode 100644
index 0000000000..b483841060
--- /dev/null
+++ b/src/nvim/testdir/test_selectmode.vim
@@ -0,0 +1,57 @@
+" Test for Select-mode
+
+source shared.vim
+
+" Test for selecting a register with CTRL-R
+func Test_selectmode_register()
+ new
+
+ " Default behavior: use unnamed register
+ call setline(1, 'foo')
+ call setreg('"', 'bar')
+ call setreg('a', 'baz')
+ exe ":norm! v\<c-g>a"
+ call assert_equal(getline('.'), 'aoo')
+ call assert_equal('f', getreg('"'))
+ call assert_equal('baz', getreg('a'))
+
+ " Use the black hole register
+ call setline(1, 'foo')
+ call setreg('"', 'bar')
+ call setreg('a', 'baz')
+ exe ":norm! v\<c-g>\<c-r>_a"
+ call assert_equal(getline('.'), 'aoo')
+ call assert_equal('bar', getreg('"'))
+ call assert_equal('baz', getreg('a'))
+
+ " Invalid register: use unnamed register
+ call setline(1, 'foo')
+ call setreg('"', 'bar')
+ call setreg('a', 'baz')
+ exe ":norm! v\<c-g>\<c-r>?a"
+ call assert_equal(getline('.'), 'aoo')
+ call assert_equal('f', getreg('"'))
+ call assert_equal('baz', getreg('a'))
+
+ " Use unnamed register
+ call setline(1, 'foo')
+ call setreg('"', 'bar')
+ call setreg('a', 'baz')
+ exe ":norm! v\<c-g>\<c-r>\"a"
+ call assert_equal(getline('.'), 'aoo')
+ call assert_equal('f', getreg('"'))
+ call assert_equal('baz', getreg('a'))
+
+ " use specicifed register, unnamed register is also written
+ call setline(1, 'foo')
+ call setreg('"', 'bar')
+ call setreg('a', 'baz')
+ exe ":norm! v\<c-g>\<c-r>aa"
+ call assert_equal(getline('.'), 'aoo')
+ call assert_equal('f', getreg('"'))
+ call assert_equal('f', getreg('a'))
+
+ bw!
+endfunc
+
+" vim: shiftwidth=2 sts=2 expandtab
diff --git a/src/nvim/testdir/test_set.vim b/src/nvim/testdir/test_set.vim
new file mode 100644
index 0000000000..2b1e9eeee0
--- /dev/null
+++ b/src/nvim/testdir/test_set.vim
@@ -0,0 +1,29 @@
+" Tests for the :set command
+
+function Test_set_backslash()
+ let isk_save = &isk
+
+ set isk=a,b,c
+ set isk+=d
+ call assert_equal('a,b,c,d', &isk)
+ set isk+=\\,e
+ call assert_equal('a,b,c,d,\,e', &isk)
+ set isk-=e
+ call assert_equal('a,b,c,d,\', &isk)
+ set isk-=\\
+ call assert_equal('a,b,c,d', &isk)
+
+ let &isk = isk_save
+endfunction
+
+function Test_set_add()
+ let wig_save = &wig
+
+ set wildignore=*.png,
+ set wildignore+=*.jpg
+ call assert_equal('*.png,*.jpg', &wig)
+
+ let &wig = wig_save
+endfunction
+
+" vim: shiftwidth=2 sts=2 expandtab
diff --git a/src/nvim/testdir/test_sha256.vim b/src/nvim/testdir/test_sha256.vim
index 76d1306836..f6f430b04e 100644
--- a/src/nvim/testdir/test_sha256.vim
+++ b/src/nvim/testdir/test_sha256.vim
@@ -1,8 +1,8 @@
" Tests for the sha256() function.
-if !has('cryptv') || !exists('*sha256')
- finish
-endif
+source check.vim
+CheckFeature cryptv
+CheckFunction sha256
function Test_sha256()
" test for empty string:
diff --git a/src/nvim/testdir/test_smartindent.vim b/src/nvim/testdir/test_smartindent.vim
index e89ad19d34..e2d028e828 100644
--- a/src/nvim/testdir/test_smartindent.vim
+++ b/src/nvim/testdir/test_smartindent.vim
@@ -21,9 +21,7 @@ endfunc
func Test_smartindent_has_no_effect()
new
exe "normal! i\<Tab>one\<Esc>"
- set noautoindent
- set smartindent
- set indentexpr=
+ setlocal noautoindent smartindent indentexpr=
exe "normal! Gotwo\<Esc>"
call assert_equal("\ttwo", getline("$"))
@@ -32,9 +30,106 @@ func Test_smartindent_has_no_effect()
call assert_equal("three", getline("$"))
delfunction! MyIndent
- set autoindent&
- set smartindent&
- set indentexpr&
+ bwipe!
+endfunc
+
+" Test for inserting '{' and '} with smartindent
+func Test_smartindent_braces()
+ new
+ setlocal smartindent shiftwidth=4
+ call setline(1, [' if (a)', "\tif (b)", "\t return 1"])
+ normal 2ggO{
+ normal 3ggA {
+ normal 4ggo}
+ normal o}
+ normal 4ggO#define FOO 1
+ call assert_equal([
+ \ ' if (a)',
+ \ ' {',
+ \ "\tif (b) {",
+ \ '#define FOO 1',
+ \ "\t return 1",
+ \ "\t}",
+ \ ' }'
+ \ ], getline(1, '$'))
+ close!
+endfunc
+
+" Test for adding a new line before and after comments with smartindent
+func Test_si_add_line_around_comment()
+ new
+ setlocal smartindent shiftwidth=4
+ call setline(1, [' A', '# comment1', '# comment2'])
+ exe "normal GoC\<Esc>2GOB"
+ call assert_equal([' A', ' B', '# comment1', '# comment2', ' C'],
+ \ getline(1, '$'))
+ close!
+endfunc
+
+" After a C style comment, indent for a following line should line up with the
+" line containing the start of the comment.
+func Test_si_indent_after_c_comment()
+ new
+ setlocal smartindent shiftwidth=4 fo+=ro
+ exe "normal i\<C-t>/*\ncomment\n/\n#define FOOBAR\n75\<Esc>ggOabc"
+ normal 3jOcont
+ call assert_equal([' abc', ' /*', ' * comment', ' * cont',
+ \ ' */', '#define FOOBAR', ' 75'], getline(1, '$'))
+ close!
+endfunc
+
+" Test for indenting a statement after a if condition split across lines
+func Test_si_if_cond_split_across_lines()
+ new
+ setlocal smartindent shiftwidth=4
+ exe "normal i\<C-t>if (cond1 &&\n\<C-t>cond2) {\ni = 10;\n}"
+ call assert_equal([' if (cond1 &&', "\t cond2) {", "\ti = 10;",
+ \ ' }'], getline(1, '$'))
+ close!
+endfunc
+
+" Test for inserting lines before and after a one line comment
+func Test_si_one_line_comment()
+ new
+ setlocal smartindent shiftwidth=4
+ exe "normal i\<C-t>abc;\n\<C-t>/* comment */"
+ normal oi = 10;
+ normal kOj = 1;
+ call assert_equal([' abc;', "\tj = 1;", "\t/* comment */", "\ti = 10;"],
+ \ getline(1, '$'))
+ close!
+endfunc
+
+" Test for smartindent with a comment continued across multiple lines
+func Test_si_comment_line_continuation()
+ new
+ setlocal smartindent shiftwidth=4
+ call setline(1, ['# com1', '# com2 \', ' contd', '# com3', ' xyz'])
+ normal ggOabc
+ call assert_equal([' abc', '# com1', '# com2 \', ' contd', '# com3',
+ \ ' xyz'], getline(1, '$'))
+ close!
+endfunc
+
+func Test_si_after_completion()
+ new
+ setlocal ai smartindent indentexpr=
+ call setline(1, 'foo foot')
+ call feedkeys("o f\<C-X>\<C-N>#", 'tx')
+ call assert_equal(' foo#', getline(2))
+
+ call setline(2, '')
+ call feedkeys("1Go f\<C-X>\<C-N>}", 'tx')
+ call assert_equal(' foo}', getline(2))
+
+ bwipe!
+endfunc
+
+func Test_no_si_after_completion()
+ new
+ call setline(1, 'foo foot')
+ call feedkeys("o f\<C-X>\<C-N>#", 'tx')
+ call assert_equal(' foo#', getline(2))
bwipe!
endfunc
diff --git a/src/nvim/testdir/test_sort.vim b/src/nvim/testdir/test_sort.vim
index 570c4415c6..9895ad754c 100644
--- a/src/nvim/testdir/test_sort.vim
+++ b/src/nvim/testdir/test_sort.vim
@@ -12,6 +12,7 @@ func Compare2(a, b) abort
endfunc
func Test_sort_strings()
+ CheckNotMSWindows " FIXME: Why does this fail with MSVC?
" numbers compared as strings
call assert_equal([1, 2, 3], sort([3, 2, 1]))
call assert_equal([13, 28, 3], sort([3, 28, 13]))
@@ -58,6 +59,7 @@ endfunc
func Test_sort_numbers()
call assert_equal([3, 13, 28], sort([13, 28, 3], 'N'))
call assert_equal(['3', '13', '28'], sort(['13', '28', '3'], 'N'))
+ call assert_equal([3997, 4996], sort([4996, 3997], 'Compare1'))
endfunc
func Test_sort_float()
@@ -1354,7 +1356,7 @@ func Test_sort_cmd()
endif
endfor
- " Needs atleast two lines for this test
+ " Needs at least two lines for this test
call setline(1, ['line1', 'line2'])
call assert_fails('sort no', 'E474:')
call assert_fails('sort c', 'E475:')
@@ -1487,6 +1489,22 @@ func Test_sort_last_search_pat()
close!
endfunc
+" Test for :sort with no last search pattern
+func Test_sort_with_no_last_search_pat()
+ let lines =<< trim [SCRIPT]
+ call setline(1, ['3b', '1c', '2a'])
+ call assert_fails('sort //', 'E35:')
+ call writefile(v:errors, 'Xresult')
+ qall!
+ [SCRIPT]
+ call writefile(lines, 'Xscript')
+ if RunVim([], [], '--clean -S Xscript')
+ call assert_equal([], readfile('Xresult'))
+ endif
+ call delete('Xscript')
+ call delete('Xresult')
+endfunc
+
" Test for retaining marks across a :sort
func Test_sort_with_marks()
new
diff --git a/src/nvim/testdir/test_source.vim b/src/nvim/testdir/test_source.vim
index 09baec0b7d..ba6fd5ad95 100644
--- a/src/nvim/testdir/test_source.vim
+++ b/src/nvim/testdir/test_source.vim
@@ -46,3 +46,45 @@ func Test_source_sandbox()
bwipe!
call delete('Xsourcehello')
endfunc
+
+" When deleting a file and immediately creating a new one the inode may be
+" recycled. Vim should not recognize it as the same script.
+func Test_different_script()
+ call writefile(['let s:var = "asdf"'], 'XoneScript')
+ source XoneScript
+ call delete('XoneScript')
+ call writefile(['let g:var = s:var'], 'XtwoScript')
+ call assert_fails('source XtwoScript', 'E121:')
+ call delete('XtwoScript')
+endfunc
+
+" When sourcing a vim script, shebang should be ignored.
+func Test_source_ignore_shebang()
+ call writefile(['#!./xyzabc', 'let g:val=369'], 'Xfile.vim')
+ source Xfile.vim
+ call assert_equal(g:val, 369)
+ call delete('Xfile.vim')
+endfunc
+
+" Test for expanding <sfile> in a autocmd and for <slnum> and <sflnum>
+func Test_source_autocmd_sfile()
+ let code =<< trim [CODE]
+ let g:SfileName = ''
+ augroup sfiletest
+ au!
+ autocmd User UserAutoCmd let g:Sfile = '<sfile>:t'
+ augroup END
+ doautocmd User UserAutoCmd
+ let g:Slnum = expand('<slnum>')
+ let g:Sflnum = expand('<sflnum>')
+ augroup! sfiletest
+ [CODE]
+ call writefile(code, 'Xscript.vim')
+ source Xscript.vim
+ call assert_equal('Xscript.vim', g:Sfile)
+ call assert_equal('7', g:Slnum)
+ call assert_equal('8', g:Sflnum)
+ call delete('Xscript.vim')
+endfunc
+
+" vim: shiftwidth=2 sts=2 expandtab
diff --git a/src/nvim/testdir/test_source_utf8.vim b/src/nvim/testdir/test_source_utf8.vim
index e93ea29dff..66fabe0442 100644
--- a/src/nvim/testdir/test_source_utf8.vim
+++ b/src/nvim/testdir/test_source_utf8.vim
@@ -1,4 +1,5 @@
" Test the :source! command
+source check.vim
func Test_source_utf8()
" check that sourcing a script with 0x80 as second byte works
@@ -31,24 +32,24 @@ endfunc
" Test for sourcing a file with CTRL-V's at the end of the line
func Test_source_ctrl_v()
- call writefile(['map __1 afirst',
- \ 'map __2 asecond',
- \ 'map __3 athird',
- \ 'map __4 afourth',
- \ 'map __5 afifth',
- \ "map __1 asd\<C-V>",
- \ "map __2 asd\<C-V>\<C-V>",
- \ "map __3 asd\<C-V>\<C-V>",
- \ "map __4 asd\<C-V>\<C-V>\<C-V>",
- \ "map __5 asd\<C-V>\<C-V>\<C-V>",
- \ ], 'Xtestfile')
+ call writefile(['map __1 afirst',
+ \ 'map __2 asecond',
+ \ 'map __3 athird',
+ \ 'map __4 afourth',
+ \ 'map __5 afifth',
+ \ "map __1 asd\<C-V>",
+ \ "map __2 asd\<C-V>\<C-V>",
+ \ "map __3 asd\<C-V>\<C-V>",
+ \ "map __4 asd\<C-V>\<C-V>\<C-V>",
+ \ "map __5 asd\<C-V>\<C-V>\<C-V>",
+ \ ], 'Xtestfile')
source Xtestfile
enew!
exe "normal __1\<Esc>\<Esc>__2\<Esc>__3\<Esc>\<Esc>__4\<Esc>__5\<Esc>"
exe "%s/\<C-J>/0/g"
call assert_equal(['sd',
- \ "map __2 asd\<Esc>secondsd\<Esc>sd0map __5 asd0fifth"],
- \ getline(1, 2))
+ \ "map __2 asd\<Esc>secondsd\<Esc>sd0map __5 asd0fifth"],
+ \ getline(1, 2))
enew!
call delete('Xtestfile')
diff --git a/src/nvim/testdir/test_spell.vim b/src/nvim/testdir/test_spell.vim
index 1ecb5c8070..7744c5bcca 100644
--- a/src/nvim/testdir/test_spell.vim
+++ b/src/nvim/testdir/test_spell.vim
@@ -2,9 +2,7 @@
" Note: this file uses latin1 encoding, but is used with utf-8 encoding.
source check.vim
-if !has('spell')
- finish
-endif
+CheckFeature spell
source screendump.vim
@@ -16,6 +14,8 @@ func TearDown()
call delete('Xtest.latin1.add.spl')
call delete('Xtest.latin1.spl')
call delete('Xtest.latin1.sug')
+ " set 'encoding' to clear the word list
+ set encoding=utf-8
endfunc
func Test_wrap_search()
@@ -72,6 +72,16 @@ func Test_z_equal_on_invalid_utf8_word()
bwipe!
endfunc
+func Test_z_equal_on_single_character()
+ " this was decrementing the index below zero
+ new
+ norm a0\
+ norm zW
+ norm z=
+
+ bwipe!
+endfunc
+
" Test spellbadword() with argument
func Test_spellbadword()
set spell
@@ -121,6 +131,106 @@ foobar/?
set spell&
endfunc
+func Test_spell_file_missing()
+ let s:spell_file_missing = 0
+ augroup TestSpellFileMissing
+ autocmd! SpellFileMissing * let s:spell_file_missing += 1
+ augroup END
+
+ set spell spelllang=ab_cd
+ let messages = GetMessages()
+ " This message is not shown in Nvim because of #3027
+ " call assert_equal('Warning: Cannot find word list "ab.utf-8.spl" or "ab.ascii.spl"', messages[-1])
+ call assert_equal(1, s:spell_file_missing)
+
+ new XTestSpellFileMissing
+ augroup TestSpellFileMissing
+ autocmd! SpellFileMissing * bwipe
+ augroup END
+ call assert_fails('set spell spelllang=ab_cd', 'E797:')
+
+ " clean up
+ augroup TestSpellFileMissing
+ autocmd! SpellFileMissing
+ augroup END
+ augroup! TestSpellFileMissing
+ unlet s:spell_file_missing
+ set spell& spelllang&
+ %bwipe!
+endfunc
+
+func Test_spelldump()
+ " In case the spell file is not found avoid getting the download dialog, we
+ " would get stuck at the prompt.
+ let g:en_not_found = 0
+ augroup TestSpellFileMissing
+ au! SpellFileMissing * let g:en_not_found = 1
+ augroup END
+ set spell spelllang=en
+ spellrare! emacs
+ if g:en_not_found
+ call assert_report("Could not find English spell file")
+ else
+ spelldump
+
+ " Check assumption about region: 1: us, 2: au, 3: ca, 4: gb, 5: nz.
+ call assert_equal('/regions=usaucagbnz', getline(1))
+ call assert_notequal(0, search('^theater/1$')) " US English only.
+ call assert_notequal(0, search('^theatre/2345$')) " AU, CA, GB or NZ English.
+
+ call assert_notequal(0, search('^emacs/?$')) " ? for a rare word.
+ call assert_notequal(0, search('^the the/!$')) " ! for a wrong word.
+ endif
+
+ " clean up
+ unlet g:en_not_found
+ augroup TestSpellFileMissing
+ autocmd! SpellFileMissing
+ augroup END
+ augroup! TestSpellFileMissing
+ bwipe
+ set spell&
+endfunc
+
+func Test_spelldump_bang()
+ new
+ call setline(1, 'This is a sample sentence.')
+ redraw
+
+ " In case the spell file is not found avoid getting the download dialog, we
+ " would get stuck at the prompt.
+ let g:en_not_found = 0
+ augroup TestSpellFileMissing
+ au! SpellFileMissing * let g:en_not_found = 1
+ augroup END
+
+ set spell
+
+ if g:en_not_found
+ call assert_report("Could not find English spell file")
+ else
+ redraw
+ spelldump!
+
+ " :spelldump! includes the number of times a word was found while updating
+ " the screen.
+ " Common word count starts at 10, regular word count starts at 0.
+ call assert_notequal(0, search("^is\t11$")) " common word found once.
+ call assert_notequal(0, search("^the\t10$")) " common word never found.
+ call assert_notequal(0, search("^sample\t1$")) " regular word found once.
+ call assert_equal(0, search("^screen\t")) " regular word never found.
+ endif
+
+ " clean up
+ unlet g:en_not_found
+ augroup TestSpellFileMissing
+ autocmd! SpellFileMissing
+ augroup END
+ augroup! TestSpellFileMissing
+ %bwipe!
+ set spell&
+endfunc
+
func Test_spelllang_inv_region()
set spell spelllang=en_xx
let messages = GetMessages()
@@ -175,6 +285,18 @@ func Test_spellreall()
bwipe!
endfunc
+func Test_spell_dump_word_length()
+ " this was running over MAXWLEN
+ new
+ noremap 0 0a0zW0000000
+ sil! norm 0z=0
+ sil norm 0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
+ sil! norm 0z=0
+
+ bwipe!
+ nunmap 0
+endfunc
+
" Test spellsuggest({word} [, {max} [, {capital}]])
func Test_spellsuggest()
" Verify suggestions are given even when spell checking is not enabled.
@@ -407,7 +529,7 @@ func Test_zz_basic()
\ )
call assert_equal("gebletegek", soundfold('goobledygoook'))
- call assert_equal("kepereneven", 'kóopërÿnôven'->soundfold())
+ call assert_equal("kepereneven", 'koprnven'->soundfold())
call assert_equal("everles gesvets etele", soundfold('oeverloos gezwets edale'))
endfunc
@@ -588,7 +710,7 @@ func Test_zz_sal_and_addition()
mkspell! Xtest Xtest
set spl=Xtest.latin1.spl spell
call assert_equal('kbltykk', soundfold('goobledygoook'))
- call assert_equal('kprnfn', soundfold('kóopërÿnôven'))
+ call assert_equal('kprnfn', soundfold('koprnven'))
call assert_equal('*fls kswts tl', soundfold('oeverloos gezwets edale'))
"also use an addition file
@@ -616,6 +738,10 @@ func Test_zz_sal_and_addition()
set spl=Xtest_ca.latin1.spl
call assert_equal("elequint", FirstSpellWord())
call assert_equal("elekwint", SecondSpellWord())
+
+ bwipe!
+ set spellfile=
+ set spl&
endfunc
func Test_spellfile_value()
@@ -681,6 +807,36 @@ func Test_spell_long_word()
set nospell
endfunc
+func Test_spellsuggest_too_deep()
+ " This was incrementing "depth" over MAXWLEN.
+ new
+ norm s000G00000000000000
+ sil norm ..vzG................vvzG0 v z=
+ bwipe!
+endfunc
+
+func Test_spell_good_word_invalid()
+ " This was adding a word with a 0x02 byte, which causes havoc.
+ enew
+ norm o0
+ sil! norm rzzWs00/
+ 2
+ sil! norm VzGprzzW
+ sil! norm z=
+
+ bwipe!
+endfunc
+
+func Test_spell_good_word_slash()
+ " This caused E1280.
+ new
+ norm afoo /
+ 1
+ norm zG
+
+ bwipe!
+endfunc
+
func LoadAffAndDic(aff_contents, dic_contents)
throw 'skipped: Nvim does not support enc=latin1'
set enc=latin1
@@ -768,14 +924,6 @@ func Test_spell_screendump()
call delete('XtestSpell')
endfunc
-func Test_spell_single_word()
- new
- silent! norm 0R00
- spell!
- silent 0norm 0r$ Dvz=
- bwipe!
-endfunc
-
let g:test_data_aff1 = [
\"SET ISO8859-1",
\"TRY esianrtolcdugmphbyfvkwjkqxz-\xEB\xE9\xE8\xEA\xEF\xEE\xE4\xE0\xE2\xF6\xFC\xFB'ESIANRTOLCDUGMPHBYFVKWJKQXZ",
diff --git a/src/nvim/testdir/test_spell_utf8.vim b/src/nvim/testdir/test_spell_utf8.vim
index 3d159f3352..b7e3da37cb 100644
--- a/src/nvim/testdir/test_spell_utf8.vim
+++ b/src/nvim/testdir/test_spell_utf8.vim
@@ -13,6 +13,8 @@ func TearDown()
call delete('Xtest.utf-8.add.spl')
call delete('Xtest.utf-8.spl')
call delete('Xtest.utf-8.sug')
+ " set 'encoding' to clear the word list
+ set encoding=utf-8
endfunc
let g:test_data_aff1 = [
@@ -484,7 +486,6 @@ let g:test_data_aff_sal = [
\ ]
func LoadAffAndDic(aff_contents, dic_contents)
- set enc=utf-8
set spellfile=
call writefile(a:aff_contents, "Xtest.aff")
call writefile(a:dic_contents, "Xtest.dic")
@@ -576,7 +577,6 @@ endfunc
"Compound words
func Test_spell_compound()
- throw 'skipped: TODO: '
call LoadAffAndDic(g:test_data_aff3, g:test_data_dic3)
call RunGoodBad("foo m\u00EF foobar foofoobar barfoo barbarfoo",
\ "bad: bar la foom\u00EF barm\u00EF m\u00EFfoo m\u00EFbar m\u00EFm\u00EF lala m\u00EFla lam\u00EF foola labar",
@@ -624,14 +624,14 @@ endfunc
" Test affix flags with two characters
func Test_spell_affix()
- throw 'skipped: TODO: '
+ CheckNotMSWindows " FIXME: Why does this fail with MSVC?
call LoadAffAndDic(g:test_data_aff5, g:test_data_dic5)
call RunGoodBad("fooa1 fooa\u00E9 bar prebar barbork prebarbork startprebar start end startend startmiddleend nouend",
\ "bad: foo fooa2 prabar probarbirk middle startmiddle middleend endstart startprobar startnouend",
\ ["bar", "barbork", "end", "fooa1", "fooa\u00E9", "nouend", "prebar", "prebarbork", "start"],
\ [
\ ["bad", ["bar", "end", "fooa1"]],
- \ ["foo", ["fooa1", "fooa\u00E9", "bar"]],
+ \ ["foo", ["fooa1", "bar", "end"]],
\ ["fooa2", ["fooa1", "fooa\u00E9", "bar"]],
\ ["prabar", ["prebar", "bar", "bar bar"]],
\ ["probarbirk", ["prebarbork"]],
@@ -649,7 +649,7 @@ func Test_spell_affix()
\ ["bar", "barbork", "end", "lead", "meea1", "meea\u00E9", "prebar", "prebarbork"],
\ [
\ ["bad", ["bar", "end", "lead"]],
- \ ["mee", ["meea1", "meea\u00E9", "bar"]],
+ \ ["mee", ["meea1", "bar", "end"]],
\ ["meea2", ["meea1", "meea\u00E9", "lead"]],
\ ["prabar", ["prebar", "bar", "leadbar"]],
\ ["probarbirk", ["prebarbork"]],
@@ -666,7 +666,7 @@ func Test_spell_affix()
\ ["bar", "barmeat", "lead", "meea1", "meea\u00E9", "meezero", "prebar", "prebarmeat", "tail"],
\ [
\ ["bad", ["bar", "lead", "tail"]],
- \ ["mee", ["meea1", "meea\u00E9", "bar"]],
+ \ ["mee", ["meea1", "bar", "lead"]],
\ ["meea2", ["meea1", "meea\u00E9", "lead"]],
\ ["prabar", ["prebar", "bar", "leadbar"]],
\ ["probarmaat", ["prebarmeat"]],
@@ -700,7 +700,6 @@ endfunc
" Affix flags
func Test_spell_affix_flags()
- throw 'skipped: TODO: '
call LoadAffAndDic(g:test_data_aff10, g:test_data_dic10)
call RunGoodBad("drink drinkable drinkables drinktable drinkabletable",
\ "bad: drinks drinkstable drinkablestable",
@@ -761,11 +760,65 @@ func Test_spell_sal_and_addition()
set spl=Xtest_ca.utf-8.spl
call assert_equal("elequint", FirstSpellWord())
call assert_equal("elekwint", SecondSpellWord())
+
+ bwipe!
+ set spellfile=
+ set spl&
endfunc
func Test_spellfile_value()
set spellfile=Xdir/Xtest.utf-8.add
set spellfile=Xdir/Xtest.utf-8.add,Xtest_other.add
+ set spellfile=
endfunc
+func Test_no_crash_with_weird_text()
+ new
+ let lines =<< trim END
+ r<sfile>
+ €
+
+
+ €
+ END
+ call setline(1, lines)
+ try
+ exe "%norm \<C-v>ez=>\<C-v>wzG"
+ catch /E1280:/
+ let caught = 'yes'
+ endtry
+ call assert_equal('yes', caught)
+
+ bwipe!
+endfunc
+
+" Invalid bytes may cause trouble when creating the word list.
+func Test_check_for_valid_word()
+ call assert_fails("spellgood! 0\xac", 'E1280:')
+endfunc
+
+" This was going over the end of the word
+func Test_word_index()
+ new
+ norm R0
+ spellgood! fl0
+ sil norm z=
+
+ bwipe!
+ call delete('Xtmpfile')
+endfunc
+
+func Test_check_empty_line()
+ " This was using freed memory
+ enew
+ spellgood! fl
+ norm z=
+ norm yy
+ sil! norm P]svc
+ norm P]s
+
+ bwipe!
+endfunc
+
+
" vim: shiftwidth=2 sts=2 expandtab
diff --git a/src/nvim/testdir/test_spellfile.vim b/src/nvim/testdir/test_spellfile.vim
index 0f48ab8f6f..b028e9d969 100644
--- a/src/nvim/testdir/test_spellfile.vim
+++ b/src/nvim/testdir/test_spellfile.vim
@@ -167,8 +167,632 @@ func Test_spell_normal()
call assert_equal([], glob('Xspellfile.add',0,1))
call assert_equal([], glob('Xspellfile2.add',0,1))
+ set spellfile= spell& spelllang&
+ bw!
+endfunc
+
+" Spell file content test. Write 'content' to the spell file prefixed by the
+" spell file header and then enable spell checking. If 'emsg' is not empty,
+" then check for error.
+func Spellfile_Test(content, emsg)
+ let splfile = './Xtest/spell/Xtest.utf-8.spl'
+ " Add the spell file header and version (VIMspell2)
+ let v = 0z56494D7370656C6C32 + a:content
+ call writefile(v, splfile, 'b')
+ set runtimepath=./Xtest
+ set spelllang=Xtest
+ if a:emsg != ''
+ call assert_fails('set spell', a:emsg)
+ else
+ " FIXME: With some invalid spellfile contents, there are no error
+ " messages. So don't know how to check for the test result.
+ set spell
+ endif
+ set nospell spelllang& rtp&
+endfunc
+
+" Test for spell file format errors.
+" The spell file format is described in spellfile.c
+func Test_spellfile_format_error()
+ let save_rtp = &rtp
+ call mkdir('Xtest/spell', 'p')
+ let splfile = './Xtest/spell/Xtest.utf-8.spl'
+
+ " empty spell file
+ call writefile([], splfile)
+ set runtimepath=./Xtest
+ set spelllang=Xtest
+ call assert_fails('set spell', 'E757:')
+ set nospell spelllang&
+
+ " invalid file ID
+ call writefile(0z56494D, splfile, 'b')
+ set runtimepath=./Xtest
+ set spelllang=Xtest
+ call assert_fails('set spell', 'E757:')
+ set nospell spelllang&
+
+ " missing version number
+ call writefile(0z56494D7370656C6C, splfile, 'b')
+ set runtimepath=./Xtest
+ set spelllang=Xtest
+ call assert_fails('set spell', 'E771:')
+ set nospell spelllang&
+
+ " invalid version number
+ call writefile(0z56494D7370656C6C7A, splfile, 'b')
+ set runtimepath=./Xtest
+ set spelllang=Xtest
+ call assert_fails('set spell', 'E772:')
+ set nospell spelllang&
+
+ " no sections
+ call Spellfile_Test(0z, 'E758:')
+
+ " missing section length
+ call Spellfile_Test(0z00, 'E758:')
+
+ " unsupported required section
+ call Spellfile_Test(0z7A0100000004, 'E770:')
+
+ " unsupported not-required section
+ call Spellfile_Test(0z7A0000000004, 'E758:')
+
+ " SN_REGION: invalid number of region names
+ call Spellfile_Test(0z0000000000FF, 'E759:')
+
+ " SN_CHARFLAGS: missing <charflagslen> length
+ call Spellfile_Test(0z010000000004, 'E758:')
+
+ " SN_CHARFLAGS: invalid <charflagslen> length
+ call Spellfile_Test(0z0100000000010201, '')
+
+ " SN_CHARFLAGS: charflagslen == 0 and folcharslen != 0
+ call Spellfile_Test(0z01000000000400000101, 'E759:')
+
+ " SN_CHARFLAGS: missing <folcharslen> length
+ call Spellfile_Test(0z01000000000100, 'E758:')
+
+ " SN_PREFCOND: invalid prefcondcnt
+ call Spellfile_Test(0z03000000000100, 'E759:')
+
+ " SN_PREFCOND: invalid condlen
+ call Spellfile_Test(0z0300000000020001, 'E759:')
+
+ " SN_REP: invalid repcount
+ call Spellfile_Test(0z04000000000100, 'E758:')
+
+ " SN_REP: missing rep
+ call Spellfile_Test(0z0400000000020004, 'E758:')
+
+ " SN_REP: zero repfromlen
+ call Spellfile_Test(0z040000000003000100, 'E759:')
+
+ " SN_REP: invalid reptolen
+ call Spellfile_Test(0z0400000000050001014101, '')
+
+ " SN_REP: zero reptolen
+ call Spellfile_Test(0z0400000000050001014100, 'E759:')
+
+ " SN_SAL: missing salcount
+ call Spellfile_Test(0z05000000000102, 'E758:')
+
+ " SN_SAL: missing salfromlen
+ call Spellfile_Test(0z050000000003080001, 'E758:')
+
+ " SN_SAL: missing saltolen
+ call Spellfile_Test(0z0500000000050400010161, 'E758:')
+
+ " SN_WORDS: non-NUL terminated word
+ call Spellfile_Test(0z0D000000000376696D, 'E758:')
+
+ " SN_WORDS: very long word
+ let v = eval('0z0D000000012C' .. repeat('41', 300))
+ call Spellfile_Test(v, 'E759:')
+
+ " SN_SOFO: missing sofofromlen
+ call Spellfile_Test(0z06000000000100, 'E758:')
+
+ " SN_SOFO: missing sofotolen
+ call Spellfile_Test(0z06000000000400016100, 'E758:')
+
+ " SN_SOFO: missing sofoto
+ call Spellfile_Test(0z0600000000050001610000, 'E759:')
+
+ " SN_COMPOUND: compmax is less than 2
+ call Spellfile_Test(0z08000000000101, 'E759:')
+
+ " SN_COMPOUND: missing compsylmax and other options
+ call Spellfile_Test(0z0800000000020401, 'E759:')
+
+ " SN_COMPOUND: missing compoptions
+ call Spellfile_Test(0z080000000005040101, 'E758:')
+
+ " SN_INFO: missing info
+ call Spellfile_Test(0z0F0000000005040101, '')
+
+ " SN_MIDWORD: missing midword
+ call Spellfile_Test(0z0200000000040102, '')
+
+ " SN_MAP: missing midword
+ call Spellfile_Test(0z0700000000040102, '')
+
+ " SN_SYLLABLE: missing SYLLABLE item
+ call Spellfile_Test(0z0900000000040102, '')
+
+ " SN_SYLLABLE: More than SY_MAXLEN size
+ let v = eval('0z090000000022612F' .. repeat('62', 32))
+ call Spellfile_Test(v, '')
+
+ " LWORDTREE: missing
+ call Spellfile_Test(0zFF, 'E758:')
+
+ " LWORDTREE: missing tree node
+ call Spellfile_Test(0zFF00000004, 'E758:')
+
+ " LWORDTREE: missing tree node value
+ call Spellfile_Test(0zFF0000000402, 'E758:')
+
+ " KWORDTREE: missing tree node
+ call Spellfile_Test(0zFF0000000000000004, 'E758:')
+
+ " PREFIXTREE: missing tree node
+ call Spellfile_Test(0zFF000000000000000000000004, 'E758:')
+
+ let &rtp = save_rtp
+ call delete('Xtest', 'rf')
+endfunc
+
+" Test for format errors in suggest file
+func Test_sugfile_format_error()
+ let save_rtp = &rtp
+ call mkdir('Xtest/spell', 'p')
+ let splfile = './Xtest/spell/Xtest.utf-8.spl'
+ let sugfile = './Xtest/spell/Xtest.utf-8.sug'
+
+ " create an empty spell file with a suggest timestamp
+ call writefile(0z56494D7370656C6C320B00000000080000000000000044FF000000000000000000000000, splfile, 'b')
+
+ " 'encoding' is set before each test to clear the previously loaded suggest
+ " file from memory.
+
+ " empty suggest file
+ set encoding=utf-8
+ call writefile([], sugfile)
+ set runtimepath=./Xtest
+ set spelllang=Xtest
+ set spell
+ call assert_fails("let s = spellsuggest('abc')", 'E778:')
+ set nospell spelllang&
+
+ " zero suggest version
+ set encoding=utf-8
+ call writefile(0z56494D73756700, sugfile)
+ set runtimepath=./Xtest
+ set spelllang=Xtest
+ set spell
+ call assert_fails("let s = spellsuggest('abc')", 'E779:')
+ set nospell spelllang&
+
+ " unsupported suggest version
+ set encoding=utf-8
+ call writefile(0z56494D7375671F, sugfile)
+ set runtimepath=./Xtest
+ set spelllang=Xtest
+ set spell
+ call assert_fails("let s = spellsuggest('abc')", 'E780:')
+ set nospell spelllang&
+
+ " missing suggest timestamp
+ set encoding=utf-8
+ call writefile(0z56494D73756701, sugfile)
+ set runtimepath=./Xtest
+ set spelllang=Xtest
+ set spell
+ call assert_fails("let s = spellsuggest('abc')", 'E781:')
+ set nospell spelllang&
+
+ " incorrect suggest timestamp
+ set encoding=utf-8
+ call writefile(0z56494D7375670100000000000000FF, sugfile)
+ set runtimepath=./Xtest
+ set spelllang=Xtest
+ set spell
+ call assert_fails("let s = spellsuggest('abc')", 'E781:')
+ set nospell spelllang&
+
+ " missing suggest wordtree
+ set encoding=utf-8
+ call writefile(0z56494D737567010000000000000044, sugfile)
+ set runtimepath=./Xtest
+ set spelllang=Xtest
+ set spell
+ call assert_fails("let s = spellsuggest('abc')", 'E782:')
+ set nospell spelllang&
+
+ " invalid suggest word count in SUGTABLE
+ set encoding=utf-8
+ call writefile(0z56494D7375670100000000000000440000000022, sugfile)
+ set runtimepath=./Xtest
+ set spelllang=Xtest
+ set spell
+ call assert_fails("let s = spellsuggest('abc')", 'E782:')
+ set nospell spelllang&
+
+ " missing sugline in SUGTABLE
+ set encoding=utf-8
+ call writefile(0z56494D7375670100000000000000440000000000000005, sugfile)
+ set runtimepath=./Xtest
+ set spelllang=Xtest
+ set spell
+ call assert_fails("let s = spellsuggest('abc')", 'E782:')
+ set nospell spelllang&
+
+ let &rtp = save_rtp
+ call delete('Xtest', 'rf')
+endfunc
+
+" Test for using :mkspell to create a spell file from a list of words
+func Test_wordlist_dic()
+ " duplicate encoding
+ let lines =<< trim [END]
+ # This is an example word list
+
+ /encoding=latin1
+ /encoding=latin1
+ example
+ [END]
+ call writefile(lines, 'Xwordlist.dic')
+ let output = execute('mkspell Xwordlist.spl Xwordlist.dic')
+ call assert_match('Duplicate /encoding= line ignored in Xwordlist.dic line 4: /encoding=latin1', output)
+
+ " multiple encoding for a word
+ let lines =<< trim [END]
+ example
+ /encoding=latin1
+ example
+ [END]
+ call writefile(lines, 'Xwordlist.dic')
+ let output = execute('mkspell! Xwordlist.spl Xwordlist.dic')
+ call assert_match('/encoding= line after word ignored in Xwordlist.dic line 2: /encoding=latin1', output)
+
+ " unsupported encoding for a word
+ let lines =<< trim [END]
+ /encoding=Xtest
+ example
+ [END]
+ call writefile(lines, 'Xwordlist.dic')
+ let output = execute('mkspell! Xwordlist.spl Xwordlist.dic')
+ call assert_match('Conversion in Xwordlist.dic not supported: from Xtest to utf-8', output)
+
+ " duplicate region
+ let lines =<< trim [END]
+ /regions=usca
+ /regions=usca
+ example
+ [END]
+ call writefile(lines, 'Xwordlist.dic')
+ let output = execute('mkspell! Xwordlist.spl Xwordlist.dic')
+ call assert_match('Duplicate /regions= line ignored in Xwordlist.dic line 2: regions=usca', output)
+
+ " maximum regions
+ let lines =<< trim [END]
+ /regions=uscauscauscauscausca
+ example
+ [END]
+ call writefile(lines, 'Xwordlist.dic')
+ let output = execute('mkspell! Xwordlist.spl Xwordlist.dic')
+ call assert_match('Too many regions in Xwordlist.dic line 1: uscauscauscauscausca', output)
+
+ " unsupported '/' value
+ let lines =<< trim [END]
+ /test=abc
+ example
+ [END]
+ call writefile(lines, 'Xwordlist.dic')
+ let output = execute('mkspell! Xwordlist.spl Xwordlist.dic')
+ call assert_match('/ line ignored in Xwordlist.dic line 1: /test=abc', output)
+
+ " unsupported flag
+ let lines =<< trim [END]
+ example/+
+ [END]
+ call writefile(lines, 'Xwordlist.dic')
+ let output = execute('mkspell! Xwordlist.spl Xwordlist.dic')
+ call assert_match('Unrecognized flags in Xwordlist.dic line 1: +', output)
+
+ " non-ascii word
+ call writefile(["ʀʀ"], 'Xwordlist.dic')
+ let output = execute('mkspell! -ascii Xwordlist.spl Xwordlist.dic')
+ call assert_match('Ignored 1 words with non-ASCII characters', output)
+
+ call delete('Xwordlist.spl')
+ call delete('Xwordlist.dic')
+endfunc
+
+" Test for the :mkspell command
+func Test_mkspell()
+ call assert_fails('mkspell Xtest_us.spl', 'E751:')
+ call assert_fails('mkspell a b c d e f g h i j k', 'E754:')
+
+ call writefile([], 'Xtest.spl')
+ call writefile([], 'Xtest.dic')
+ call assert_fails('mkspell Xtest.spl Xtest.dic', 'E13:')
+ call delete('Xtest.spl')
+ call delete('Xtest.dic')
+
+ call mkdir('Xtest.spl')
+ call assert_fails('mkspell! Xtest.spl Xtest.dic', 'E17:')
+ call delete('Xtest.spl', 'rf')
+
+ " can't write the .spl file as its directory does not exist
+ call writefile([], 'Xtest.aff')
+ call writefile([], 'Xtest.dic')
+ call assert_fails('mkspell DOES_NOT_EXIT/Xtest.spl Xtest.dic', 'E484:')
+ call delete('Xtest.aff')
+ call delete('Xtest.dic')
+
+ call assert_fails('mkspell en en_US abc_xyz', 'E755:')
+endfunc
+
+" Tests for :mkspell with a .dic and .aff file
+func Test_aff_file_format_error()
+ " FIXME: For some reason, the :mkspell command below doesn't fail on the
+ " MS-Windows CI build. Disable this test on MS-Windows for now.
+ CheckNotMSWindows
+
+ " No word count in .dic file
+ call writefile([], 'Xtest.dic')
+ call writefile([], 'Xtest.aff')
+ call assert_fails('mkspell! Xtest.spl Xtest', 'E760:')
+
+ " create a .dic file for the tests below
+ call writefile(['1', 'work'], 'Xtest.dic')
+
+ " Invalid encoding in .aff file
+ call writefile(['# comment', 'SET Xinvalidencoding'], 'Xtest.aff')
+ let output = execute('mkspell! Xtest.spl Xtest')
+ call assert_match('Conversion in Xtest.aff not supported: from xinvalidencoding', output)
+
+ " Invalid flag in .aff file
+ call writefile(['FLAG xxx'], 'Xtest.aff')
+ let output = execute('mkspell! Xtest.spl Xtest')
+ call assert_match('Invalid value for FLAG in Xtest.aff line 1: xxx', output)
+
+ " set FLAGS after using flag for an affix
+ call writefile(['SFX L Y 1', 'SFX L 0 re [^x]', 'FLAG long'], 'Xtest.aff')
+ let output = execute('mkspell! Xtest.spl Xtest')
+ call assert_match('FLAG after using flags in Xtest.aff line 3: long', output)
+
+ " INFO in affix file
+ let save_encoding = &encoding
+ call mkdir('Xrtp/spell', 'p')
+ call writefile(['1', 'work'], 'Xrtp/spell/Xtest.dic')
+ call writefile(['NAME klingon', 'VERSION 1.4', 'AUTHOR Spock'],
+ \ 'Xrtp/spell/Xtest.aff')
+ silent mkspell! Xrtp/spell/Xtest.utf-8.spl Xrtp/spell/Xtest
+ let save_rtp = &rtp
+ set runtimepath=./Xrtp
+ set spelllang=Xtest
+ set spell
+ let output = split(execute('spellinfo'), "\n")
+ call assert_equal("NAME klingon", output[1])
+ call assert_equal("VERSION 1.4", output[2])
+ call assert_equal("AUTHOR Spock", output[3])
+ let &rtp = save_rtp
+ call delete('Xrtp', 'rf')
+ set spell& spelllang& spellfile&
+ %bw!
+ " 'encoding' must be set again to clear the spell file in memory
+ let &encoding = save_encoding
+
+ " COMPOUNDFORBIDFLAG flag after PFX in an affix file
+ call writefile(['PFX L Y 1', 'PFX L 0 re x', 'COMPOUNDFLAG c', 'COMPOUNDFORBIDFLAG x'],
+ \ 'Xtest.aff')
+ let output = execute('mkspell! Xtest.spl Xtest')
+ call assert_match('Defining COMPOUNDFORBIDFLAG after PFX item may give wrong results in Xtest.aff line 4', output)
+
+ " COMPOUNDPERMITFLAG flag after PFX in an affix file
+ call writefile(['PFX L Y 1', 'PFX L 0 re x', 'COMPOUNDPERMITFLAG c'],
+ \ 'Xtest.aff')
+ let output = execute('mkspell! Xtest.spl Xtest')
+ call assert_match('Defining COMPOUNDPERMITFLAG after PFX item may give wrong results in Xtest.aff line 3', output)
+
+ " Wrong COMPOUNDRULES flag value in an affix file
+ call writefile(['COMPOUNDRULES a'], 'Xtest.aff')
+ let output = execute('mkspell! Xtest.spl Xtest')
+ call assert_match('Wrong COMPOUNDRULES value in Xtest.aff line 1: a', output)
+
+ " Wrong COMPOUNDWORDMAX flag value in an affix file
+ call writefile(['COMPOUNDWORDMAX 0'], 'Xtest.aff')
+ let output = execute('mkspell! Xtest.spl Xtest')
+ call assert_match('Wrong COMPOUNDWORDMAX value in Xtest.aff line 1: 0', output)
+
+ " Wrong COMPOUNDMIN flag value in an affix file
+ call writefile(['COMPOUNDMIN 0'], 'Xtest.aff')
+ let output = execute('mkspell! Xtest.spl Xtest')
+ call assert_match('Wrong COMPOUNDMIN value in Xtest.aff line 1: 0', output)
+
+ " Wrong COMPOUNDSYLMAX flag value in an affix file
+ call writefile(['COMPOUNDSYLMAX 0'], 'Xtest.aff')
+ let output = execute('mkspell! Xtest.spl Xtest')
+ call assert_match('Wrong COMPOUNDSYLMAX value in Xtest.aff line 1: 0', output)
+
+ " Wrong CHECKCOMPOUNDPATTERN flag value in an affix file
+ call writefile(['CHECKCOMPOUNDPATTERN 0'], 'Xtest.aff')
+ let output = execute('mkspell! Xtest.spl Xtest')
+ call assert_match('Wrong CHECKCOMPOUNDPATTERN value in Xtest.aff line 1: 0', output)
+
+ " Both compounding and NOBREAK specified
+ call writefile(['COMPOUNDFLAG c', 'NOBREAK'], 'Xtest.aff')
+ let output = execute('mkspell! Xtest.spl Xtest')
+ call assert_match('Warning: both compounding and NOBREAK specified', output)
+
+ " Duplicate affix entry in an affix file
+ call writefile(['PFX L Y 1', 'PFX L 0 re x', 'PFX L Y 1', 'PFX L 0 re x'],
+ \ 'Xtest.aff')
+ let output = execute('mkspell! Xtest.spl Xtest')
+ call assert_match('Duplicate affix in Xtest.aff line 3: L', output)
+
+ " Duplicate affix entry in an affix file
+ call writefile(['PFX L Y 1', 'PFX L Y 1'], 'Xtest.aff')
+ let output = execute('mkspell! Xtest.spl Xtest')
+ call assert_match('Unrecognized or duplicate item in Xtest.aff line 2: PFX', output)
+
+ " Different combining flags in an affix file
+ call writefile(['PFX L Y 1', 'PFX L 0 re x', 'PFX L N 1'], 'Xtest.aff')
+ let output = execute('mkspell! Xtest.spl Xtest')
+ call assert_match('Different combining flag in continued affix block in Xtest.aff line 3', output)
+
+ " Try to reuse a affix used for BAD flag
+ call writefile(['BAD x', 'PFX x Y 1', 'PFX x 0 re x'], 'Xtest.aff')
+ let output = execute('mkspell! Xtest.spl Xtest')
+ call assert_match('Affix also used for BAD/RARE/KEEPCASE/NEEDAFFIX/NEEDCOMPOUND/NOSUGGEST in Xtest.aff line 2: x', output)
+
+ " Trailing characters in an affix entry
+ call writefile(['PFX L Y 1 Test', 'PFX L 0 re x'], 'Xtest.aff')
+ let output = execute('mkspell! Xtest.spl Xtest')
+ call assert_match('Trailing text in Xtest.aff line 1: Test', output)
+
+ " Trailing characters in an affix entry
+ call writefile(['PFX L Y 1', 'PFX L 0 re x Test'], 'Xtest.aff')
+ let output = execute('mkspell! Xtest.spl Xtest')
+ call assert_match('Trailing text in Xtest.aff line 2: Test', output)
+
+ " Incorrect combine flag in an affix entry
+ call writefile(['PFX L X 1', 'PFX L 0 re x'], 'Xtest.aff')
+ let output = execute('mkspell! Xtest.spl Xtest')
+ call assert_match('Expected Y or N in Xtest.aff line 1: X', output)
+
+ " Invalid count for REP item
+ call writefile(['REP a'], 'Xtest.aff')
+ let output = execute('mkspell! Xtest.spl Xtest')
+ call assert_match('Expected REP(SAL) count in Xtest.aff line 1', output)
+
+ " Trailing characters in REP item
+ call writefile(['REP 1', 'REP f ph test'], 'Xtest.aff')
+ let output = execute('mkspell! Xtest.spl Xtest')
+ call assert_match('Trailing text in Xtest.aff line 2: test', output)
+
+ " Invalid count for MAP item
+ call writefile(['MAP a'], 'Xtest.aff')
+ let output = execute('mkspell! Xtest.spl Xtest')
+ call assert_match('Expected MAP count in Xtest.aff line 1', output)
+
+ " Duplicate character in a MAP item
+ call writefile(['MAP 2', 'MAP xx', 'MAP yy'], 'Xtest.aff')
+ let output = execute('mkspell! Xtest.spl Xtest')
+ call assert_match('Duplicate character in MAP in Xtest.aff line 2', output)
+
+ " Use COMPOUNDSYLMAX without SYLLABLE
+ call writefile(['COMPOUNDSYLMAX 2'], 'Xtest.aff')
+ let output = execute('mkspell! Xtest.spl Xtest')
+ call assert_match('COMPOUNDSYLMAX used without SYLLABLE', output)
+
+ " Missing SOFOTO
+ call writefile(['SOFOFROM abcdef'], 'Xtest.aff')
+ let output = execute('mkspell! Xtest.spl Xtest')
+ call assert_match('Missing SOFOTO line in Xtest.aff', output)
+
+ " Length of SOFOFROM and SOFOTO differ
+ call writefile(['SOFOFROM abcde', 'SOFOTO ABCD'], 'Xtest.aff')
+ call assert_fails('mkspell! Xtest.spl Xtest', 'E759:')
+
+ " Both SAL and SOFOFROM/SOFOTO items
+ call writefile(['SOFOFROM abcd', 'SOFOTO ABCD', 'SAL CIA X'], 'Xtest.aff')
+ let output = execute('mkspell! Xtest.spl Xtest')
+ call assert_match('Both SAL and SOFO lines in Xtest.aff', output)
+
+ " use an alphabet flag when FLAG is num
+ call writefile(['FLAG num', 'SFX L Y 1', 'SFX L 0 re [^x]'], 'Xtest.aff')
+ let output = execute('mkspell! Xtest.spl Xtest')
+ call assert_match('Flag is not a number in Xtest.aff line 2: L', output)
+
+ " use number and alphabet flag when FLAG is num
+ call writefile(['FLAG num', 'SFX 4f Y 1', 'SFX 4f 0 re [^x]'], 'Xtest.aff')
+ let output = execute('mkspell! Xtest.spl Xtest')
+ call assert_match('Affix name too long in Xtest.aff line 2: 4f', output)
+
+ " use a single character flag when FLAG is long
+ call writefile(['FLAG long', 'SFX L Y 1', 'SFX L 0 re [^x]'], 'Xtest.aff')
+ let output = execute('mkspell! Xtest.spl Xtest')
+ call assert_match('Illegal flag in Xtest.aff line 2: L', output)
+
+ " duplicate word in the .dic file
+ call writefile(['2', 'good', 'good', 'good'], 'Xtest.dic')
+ call writefile(['NAME vim'], 'Xtest.aff')
+ let output = execute('mkspell! Xtest.spl Xtest')
+ call assert_match('First duplicate word in Xtest.dic line 3: good', output)
+ call assert_match('2 duplicate word(s) in Xtest.dic', output)
+
+ call delete('Xtest.dic')
+ call delete('Xtest.aff')
+ call delete('Xtest.spl')
+ call delete('Xtest.sug')
+endfunc
+
+func Test_spell_add_word()
set spellfile=
+ call assert_fails('spellgood abc', 'E764:')
+
+ set spellfile=Xtest.utf-8.add
+ call assert_fails('2spellgood abc', 'E765:')
+
+ edit Xtest.utf-8.add
+ call setline(1, 'sample')
+ call assert_fails('spellgood abc', 'E139:')
+ set spellfile&
+ %bw!
+endfunc
+
+func Test_spellfile_verbose()
+ call writefile(['1', 'one'], 'XtestVerbose.dic')
+ call writefile([], 'XtestVerbose.aff')
+ mkspell! XtestVerbose-utf8.spl XtestVerbose
+ set spell
+
+ " First time: the spl file should be read.
+ let a = execute('3verbose set spelllang=XtestVerbose-utf8.spl')
+ call assert_match('Reading spell file "XtestVerbose-utf8.spl"', a)
+
+ " Second time time: the spl file should not be read (already read).
+ let a = execute('3verbose set spelllang=XtestVerbose-utf8.spl')
+ call assert_notmatch('Reading spell file "XtestVerbose-utf8.spl"', a)
+
+ set spell& spelllang&
+ call delete('XtestVerbose.dic')
+ call delete('XtestVerbose.aff')
+ call delete('XtestVerbose-utf8.spl')
+endfunc
+
+" Test NOBREAK (see :help spell-NOBREAK)
+func Test_NOBREAK()
+ call writefile(['3', 'one', 'two', 'three' ], 'XtestNOBREAK.dic')
+ call writefile(['NOBREAK' ], 'XtestNOBREAK.aff')
+
+ mkspell! XtestNOBREAK-utf8.spl XtestNOBREAK
+ set spell spelllang=XtestNOBREAK-utf8.spl
+
+ call assert_equal(['', ''], spellbadword('One two three onetwo onetwothree threetwoone'))
+
+ call assert_equal(['x', 'bad'], spellbadword('x'))
+ call assert_equal(['y', 'bad'], spellbadword('yone'))
+ call assert_equal(['z', 'bad'], spellbadword('onez'))
+ call assert_equal(['zero', 'bad'], spellbadword('Onetwozerothree'))
+
+ new
+ call setline(1, 'Onetwwothree')
+ norm! fw1z=
+ call assert_equal('Onetwothree', getline(1))
+ call setline(1, 'Onetwothre')
+ norm! fh1z=
+ call assert_equal('Onetwothree', getline(1))
+
bw!
+ set spell& spelllang&
+ call delete('XtestNOBREAK.dic')
+ call delete('XtestNOBREAK.aff')
+ call delete('XtestNOBREAK-utf8.spl')
endfunc
" Test CHECKCOMPOUNDPATTERN (see :help spell-CHECKCOMPOUNDPATTERN)
@@ -183,7 +807,7 @@ func Test_spellfile_CHECKCOMPOUNDPATTERN()
\ 'CHECKCOMPOUNDPATTERN wo on',
\ 'COMPOUNDFLAG c'], 'XtestCHECKCOMPOUNDPATTERN.aff')
- let output = execute('mkspell! XtestCHECKCOMPOUNDPATTERN-utf8.spl XtestCHECKCOMPOUNDPATTERN')
+ mkspell! XtestCHECKCOMPOUNDPATTERN-utf8.spl XtestCHECKCOMPOUNDPATTERN
set spell spelllang=XtestCHECKCOMPOUNDPATTERN-utf8.spl
" Check valid words with and without valid compounds.
@@ -268,7 +892,7 @@ func Test_spellfile_COMMON()
\ 'ted'], 'XtestCOMMON.dic')
call writefile(['COMMON the and'], 'XtestCOMMON.aff')
- let output = execute('mkspell! XtestCOMMON-utf8.spl XtestCOMMON')
+ mkspell! XtestCOMMON-utf8.spl XtestCOMMON
set spell spelllang=XtestCOMMON-utf8.spl
" COMMON words 'and' and 'the' should be the top suggestions.
@@ -283,4 +907,121 @@ func Test_spellfile_COMMON()
call delete('XtestCOMMON-utf8.spl')
endfunc
+" Test CIRCUMFIX (see: :help spell-CIRCUMFIX)
+func Test_spellfile_CIRCUMFIX()
+ " Example taken verbatim from https://github.com/hunspell/hunspell/tree/master/tests
+ call writefile(['1',
+ \ 'nagy/C po:adj'], 'XtestCIRCUMFIX.dic')
+ call writefile(['# circumfixes: ~ obligate prefix/suffix combinations',
+ \ '# superlative in Hungarian: leg- (prefix) AND -bb (suffix)',
+ \ '',
+ \ 'CIRCUMFIX X',
+ \ '',
+ \ 'PFX A Y 1',
+ \ 'PFX A 0 leg/X .',
+ \ '',
+ \ 'PFX B Y 1',
+ \ 'PFX B 0 legesleg/X .',
+ \ '',
+ \ 'SFX C Y 3',
+ \ 'SFX C 0 obb . is:COMPARATIVE',
+ \ 'SFX C 0 obb/AX . is:SUPERLATIVE',
+ \ 'SFX C 0 obb/BX . is:SUPERSUPERLATIVE'], 'XtestCIRCUMFIX.aff')
+
+ mkspell! XtestCIRCUMFIX-utf8.spl XtestCIRCUMFIX
+ set spell spelllang=XtestCIRCUMFIX-utf8.spl
+
+ " From https://catalog.ldc.upenn.edu/docs/LDC2008T01/acta04.pdf:
+ " Hungarian English
+ " --------- -------
+ " nagy great
+ " nagyobb greater
+ " legnagyobb greatest
+ " legeslegnagyob most greatest
+ call assert_equal(['', ''], spellbadword('nagy nagyobb legnagyobb legeslegnagyobb'))
+
+ for badword in ['legnagy', 'legeslegnagy', 'legobb', 'legeslegobb']
+ call assert_equal([badword, 'bad'], spellbadword(badword))
+ endfor
+
+ set spell& spelllang&
+ call delete('XtestCIRCUMFIX.dic')
+ call delete('XtestCIRCUMFIX.aff')
+ call delete('XtestCIRCUMFIX-utf8.spl')
+endfunc
+
+" Test SFX that strips/chops characters
+func Test_spellfile_SFX_strip()
+ " Simplified conjugation of Italian verbs ending in -are (first conjugation).
+ call writefile(['SFX A Y 4',
+ \ 'SFX A are iamo [^icg]are',
+ \ 'SFX A are hiamo [cg]are',
+ \ 'SFX A re mo iare',
+ \ 'SFX A re vamo are'],
+ \ 'XtestSFX.aff')
+ " Examples of Italian verbs:
+ " - cantare = to sing
+ " - cercare = to search
+ " - odiare = to hate
+ call writefile(['3', 'cantare/A', 'cercare/A', 'odiare/A'], 'XtestSFX.dic')
+
+ mkspell! XtestSFX-utf8.spl XtestSFX
+ set spell spelllang=XtestSFX-utf8.spl
+
+ " To sing, we're singing, we were singing.
+ call assert_equal(['', ''], spellbadword('cantare cantiamo cantavamo'))
+
+ " To search, we're searching, we were searching.
+ call assert_equal(['', ''], spellbadword('cercare cerchiamo cercavamo'))
+
+ " To hate, we hate, we were hating.
+ call assert_equal(['', ''], spellbadword('odiare odiamo odiavamo'))
+
+ for badword in ['canthiamo', 'cerciamo', 'cantarevamo', 'odiiamo']
+ call assert_equal([badword, 'bad'], spellbadword(badword))
+ endfor
+
+ call assert_equal(['cantiamo'], spellsuggest('canthiamo', 1))
+ call assert_equal(['cerchiamo'], spellsuggest('cerciamo', 1))
+ call assert_equal(['cantavamo'], spellsuggest('cantarevamo', 1))
+ call assert_equal(['odiamo'], spellsuggest('odiiamo', 1))
+
+ set spell& spelllang&
+ call delete('XtestSFX.dic')
+ call delete('XtestSFX.aff')
+ call delete('XtestSFX-utf8.spl')
+endfunc
+
+" When 'spellfile' is not set, adding a new good word will automatically set
+" the 'spellfile'
+func Test_init_spellfile()
+ let save_rtp = &rtp
+ let save_encoding = &encoding
+ call mkdir('Xrtp/spell', 'p')
+ call writefile(['vim'], 'Xrtp/spell/Xtest.dic')
+ silent mkspell Xrtp/spell/Xtest.utf-8.spl Xrtp/spell/Xtest.dic
+ set runtimepath=./Xrtp
+ set spelllang=Xtest
+ set spell
+ silent spellgood abc
+ call assert_equal('./Xrtp/spell/Xtest.utf-8.add', &spellfile)
+ call assert_equal(['abc'], readfile('Xrtp/spell/Xtest.utf-8.add'))
+ call assert_true(filereadable('Xrtp/spell/Xtest.utf-8.spl'))
+ set spell& spelllang& spellfile&
+ call delete('Xrtp', 'rf')
+ let &encoding = save_encoding
+ let &rtp = save_rtp
+ %bw!
+endfunc
+
+" Test for the 'mkspellmem' option
+func Test_mkspellmem_opt()
+ call assert_fails('set mkspellmem=1000', 'E474:')
+ call assert_fails('set mkspellmem=1000,', 'E474:')
+ call assert_fails('set mkspellmem=1000,50', 'E474:')
+ call assert_fails('set mkspellmem=1000,50,', 'E474:')
+ call assert_fails('set mkspellmem=1000,50,10,', 'E474:')
+ call assert_fails('set mkspellmem=1000,50,0', 'E474:')
+endfunc
+
" vim: shiftwidth=2 sts=2 expandtab
diff --git a/src/nvim/testdir/test_stat.vim b/src/nvim/testdir/test_stat.vim
index 170358e023..d3059664e9 100644
--- a/src/nvim/testdir/test_stat.vim
+++ b/src/nvim/testdir/test_stat.vim
@@ -1,11 +1,13 @@
" Tests for stat functions and checktime
+source check.vim
+
func CheckFileTime(doSleep)
let fnames = ['Xtest1.tmp', 'Xtest2.tmp', 'Xtest3.tmp']
let times = []
let result = 0
- " Use three files istead of localtim(), with a network filesystem the file
+ " Use three files instead of localtim(), with a network filesystem the file
" times may differ at bit
let fl = ['Hello World!']
for fname in fnames
@@ -74,6 +76,44 @@ func Test_checktime()
call delete(fname)
endfunc
+func Test_checktime_fast()
+ CheckFeature nanotime
+
+ let fname = 'Xtest.tmp'
+
+ let fl = ['Hello World!']
+ call writefile(fl, fname)
+ set autoread
+ exec 'e' fname
+ let fl = readfile(fname)
+ let fl[0] .= ' - checktime'
+ sleep 10m " make test less flaky in Nvim
+ call writefile(fl, fname)
+ checktime
+ call assert_equal(fl[0], getline(1))
+
+ call delete(fname)
+endfunc
+
+func Test_autoread_fast()
+ CheckFeature nanotime
+
+ " this is timing sensitive
+ let g:test_is_flaky = 1
+
+ new Xautoread
+ setlocal autoread
+ call setline(1, 'foo')
+ w!
+ sleep 10m
+ call writefile(['bar'], 'Xautoread')
+ sleep 10m
+ checktime
+ call assert_equal('bar', trim(getline(1)))
+
+ call delete('Xautoread')
+endfunc
+
func Test_autoread_file_deleted()
new Xautoread
set autoread
diff --git a/src/nvim/testdir/test_statusline.vim b/src/nvim/testdir/test_statusline.vim
index a3e4dcdd25..ec35fac964 100644
--- a/src/nvim/testdir/test_statusline.vim
+++ b/src/nvim/testdir/test_statusline.vim
@@ -2,13 +2,15 @@
"
" Not tested yet:
" %N
-" %T
-" %X
source view_util.vim
source check.vim
source term_util.vim
+func SetUp()
+ set laststatus=2
+endfunc
+
func s:get_statusline()
return ScreenLines(&lines - 1, &columns)[0]
endfunc
@@ -104,6 +106,18 @@ func Test_statusline()
set statusline=%F
call assert_match('/testdir/Xstatusline\s*$', s:get_statusline())
+ " Test for min and max width with %(. For some reason, if this test is moved
+ " after the below test for the help buffer flag, then the code to truncate
+ " the string is not executed.
+ set statusline=%015(%f%)
+ call assert_match('^ Xstatusline\s*$', s:get_statusline())
+ set statusline=%.6(%f%)
+ call assert_match('^<sline\s*$', s:get_statusline())
+ set statusline=%14f
+ call assert_match('^ Xstatusline\s*$', s:get_statusline())
+ set statusline=%.4L
+ call assert_match('^10>3\s*$', s:get_statusline())
+
" %h: Help buffer flag, text is "[help]".
" %H: Help buffer flag, text is ",HLP".
set statusline=%h,%H
@@ -186,7 +200,16 @@ func Test_statusline()
set virtualedit=all
norm 10|
call assert_match('^10,-10\s*$', s:get_statusline())
+ set list
+ call assert_match('^10,-10\s*$', s:get_statusline())
set virtualedit&
+ exe "norm A\<Tab>\<Tab>a\<Esc>"
+ " In list mode a <Tab> is shown as "^I", which is 2-wide.
+ call assert_match('^9,-9\s*$', s:get_statusline())
+ set list&
+ " Now the second <Tab> ends at the 16th screen column.
+ call assert_match('^17,-17\s*$', s:get_statusline())
+ undo
" %w: Preview window flag, text is "[Preview]".
" %W: Preview window flag, text is ",PRV".
@@ -452,7 +475,6 @@ func Test_statusline_removed_group()
call writefile(lines, 'XTest_statusline')
let buf = RunVimInTerminal('-S XTest_statusline', {'rows': 10, 'cols': 50})
- call term_wait(buf, 100)
call VerifyScreenDump(buf, 'Test_statusline_1', {})
" clean up
@@ -498,5 +520,50 @@ func Test_statusline_after_split_vsplit()
set ls& stl&
endfunc
+" Test using a multibyte character for 'stl' and 'stlnc' items in 'fillchars'
+" with a custom 'statusline'
+func Test_statusline_mbyte_fillchar()
+ only
+ set laststatus=2
+ set fillchars=vert:\|,fold:-,stl:━,stlnc:═
+ set statusline=a%=b
+ call assert_match('^a\+━\+b$', s:get_statusline())
+ vnew
+ call assert_match('^a\+━\+b━a\+═\+b$', s:get_statusline())
+ wincmd w
+ call assert_match('^a\+═\+b═a\+━\+b$', s:get_statusline())
+ set statusline& fillchars& laststatus&
+ %bw!
+endfunc
+
+" Used to write beyond allocated memory. This assumes MAXPATHL is 4096 bytes.
+func Test_statusline_verylong_filename()
+ let fname = repeat('x', 4090)
+ " Nvim's swap file creation fails on Windows (E303) due to fname's length
+ " exe "new " .. fname
+ exe "noswapfile new " .. fname
+ set buftype=help
+ set previewwindow
+ redraw
+ bwipe!
+endfunc
+
+func Test_statusline_highlight_truncate()
+ CheckScreendump
+
+ let lines =<< trim END
+ set laststatus=2
+ hi! link User1 Directory
+ hi! link User2 ErrorMsg
+ set statusline=%.5(%1*ABC%2*DEF%1*GHI%)
+ END
+ call writefile(lines, 'XTest_statusline')
+
+ let buf = RunVimInTerminal('-S XTest_statusline', {'rows': 6})
+ call VerifyScreenDump(buf, 'Test_statusline_hl', {})
+
+ call StopVimInTerminal(buf)
+ call delete('XTest_statusline')
+endfunc
" vim: shiftwidth=2 sts=2 expandtab
diff --git a/src/nvim/testdir/test_substitute.vim b/src/nvim/testdir/test_substitute.vim
index 20b760ac15..f795d1c0cf 100644
--- a/src/nvim/testdir/test_substitute.vim
+++ b/src/nvim/testdir/test_substitute.vim
@@ -1,4 +1,6 @@
-" Tests for multi-line regexps with ":s".
+" Tests for the substitute (:s) command
+
+source shared.vim
func Test_multiline_subst()
enew!
@@ -51,10 +53,12 @@ func Test_substitute_variants()
\ { 'cmd': ':s/t/r/cg', 'exp': 'Tesring srring', 'prompt': 'a' },
\ { 'cmd': ':s/t/r/ci', 'exp': 'resting string', 'prompt': 'y' },
\ { 'cmd': ':s/t/r/cI', 'exp': 'Tesring string', 'prompt': 'y' },
+ \ { 'cmd': ':s/t/r/c', 'exp': 'Testing string', 'prompt': 'n' },
\ { 'cmd': ':s/t/r/cn', 'exp': ln },
\ { 'cmd': ':s/t/r/cp', 'exp': 'Tesring string', 'prompt': 'y' },
\ { 'cmd': ':s/t/r/cl', 'exp': 'Tesring string', 'prompt': 'y' },
\ { 'cmd': ':s/t/r/gc', 'exp': 'Tesring srring', 'prompt': 'a' },
+ \ { 'cmd': ':s/i/I/gc', 'exp': 'TestIng string', 'prompt': 'l' },
\ { 'cmd': ':s/foo/bar/ge', 'exp': ln },
\ { 'cmd': ':s/t/r/g', 'exp': 'Tesring srring' },
\ { 'cmd': ':s/t/r/gi', 'exp': 'resring srring' },
@@ -86,6 +90,7 @@ func Test_substitute_variants()
\ { 'cmd': ':s//r/rp', 'exp': 'Testr string' },
\ { 'cmd': ':s//r/rl', 'exp': 'Testr string' },
\ { 'cmd': ':s//r/r', 'exp': 'Testr string' },
+ \ { 'cmd': ':s/i/I/gc', 'exp': 'Testing string', 'prompt': 'q' },
\]
for var in variants
@@ -105,7 +110,7 @@ func Test_substitute_variants()
call assert_equal(var.exp, getline('.'), msg)
endfor
endfor
-endfunction
+endfunc
" Test the l, p, # flags.
func Test_substitute_flags_lp()
@@ -137,7 +142,7 @@ func Test_substitute_repeat()
" This caused an invalid memory access.
split Xfile
s/^/x
- call feedkeys("gQsc\<CR>y", 'tx')
+ call feedkeys("Qsc\<CR>y", 'tx')
bwipe!
endfunc
@@ -149,7 +154,6 @@ func Run_SubCmd_Tests(tests)
for t in a:tests
let start = line('.') + 1
let end = start + len(t[2]) - 1
- " TODO: why is there a one second delay the first time we get here?
exe "normal o" . t[0]
call cursor(start, 1)
exe t[1]
@@ -184,7 +188,8 @@ func Test_sub_cmd_1()
\ ['sSs', 's/S/\c/', ['scs']],
\ ['tTt', "s/T/\<C-V>\<C-J>/", ["t\<C-V>\<C-J>t"]],
\ ['U', 's/U/\L\uuUu\l\EU/', ['UuuU']],
- \ ['V', 's/V/\U\lVvV\u\Ev/', ['vVVv']]
+ \ ['V', 's/V/\U\lVvV\u\Ev/', ['vVVv']],
+ \ ['\', 's/\\/\\\\/', ['\\']]
\ ]
call Run_SubCmd_Tests(tests)
endfunc
@@ -215,7 +220,8 @@ func Test_sub_cmd_2()
\ ['sSs', 's/S/\c/', ['scs']],
\ ['tTt', "s/T/\<C-V>\<C-J>/", ["t\<C-V>\<C-J>t"]],
\ ['U', 's/U/\L\uuUu\l\EU/', ['UuuU']],
- \ ['V', 's/V/\U\lVvV\u\Ev/', ['vVVv']]
+ \ ['V', 's/V/\U\lVvV\u\Ev/', ['vVVv']],
+ \ ['\', 's/\\/\\\\/', ['\\']]
\ ]
call Run_SubCmd_Tests(tests)
endfunc
@@ -288,7 +294,7 @@ endfunc
" Test for *:s%* on :substitute.
func Test_sub_cmd_6()
- throw "skipped: Nvim removed POSIX-related 'cpoptions' flags"
+ throw 'Skipped: Nvim does not support cpoptions flag "/"'
set magic&
set cpo+=/
@@ -384,6 +390,10 @@ func Test_substitute_join()
call assert_equal(["foo\tbarbar\<C-H>foo"], getline(1, '$'))
call assert_equal('\n', histget("search", -1))
+ call setline(1, ['foo', 'bar', 'baz', 'qux'])
+ call execute('1,2s/\n//')
+ call assert_equal(['foobarbaz', 'qux'], getline(1, '$'))
+
bwipe!
endfunc
@@ -398,6 +408,11 @@ func Test_substitute_count()
call assert_fails('s/foo/bar/0', 'E939:')
+ call setline(1, ['foo foo', 'foo foo', 'foo foo', 'foo foo', 'foo foo'])
+ 2,4s/foo/bar/ 10
+ call assert_equal(['foo foo', 'foo foo', 'foo foo', 'bar foo', 'bar foo'],
+ \ getline(1, '$'))
+
bwipe!
endfunc
@@ -416,6 +431,10 @@ func Test_substitute_flag_n()
" No substitution should have been done.
call assert_equal(lines, getline(1, '$'))
+ %delete _
+ call setline(1, ['A', 'Bar', 'Baz'])
+ call assert_equal("\n1 match on 1 line", execute('s/\nB\@=//gn'))
+
bwipe!
endfunc
@@ -656,10 +675,11 @@ func Test_nocatch_sub_failure_handling()
endfunc
new
call setline(1, ['1 aaa', '2 aaa', '3 aaa'])
- %s/aaa/\=Foo()/g
+ " need silent! to avoid a delay when entering Insert mode
+ silent! %s/aaa/\=Foo()/g
call assert_equal(['1 0', '2 0', '3 0'], getline(1, 3))
- " Trow without try-catch causes abort after the first line.
+ " Throw without try-catch causes abort after the first line.
" We cannot test this, since it would stop executing the test script.
" try/catch does not result in any changes
@@ -749,6 +769,80 @@ func Test_sub_beyond_end()
bwipe!
endfunc
+" Test for repeating last substitution using :~ and :&r
+func Test_repeat_last_sub()
+ new
+ call setline(1, ['blue green yellow orange white'])
+ s/blue/red/
+ let @/ = 'yellow'
+ ~
+ let @/ = 'white'
+ :&r
+ let @/ = 'green'
+ s//gray
+ call assert_equal('red gray red orange red', getline(1))
+ close!
+endfunc
+
+" Test for Vi compatible substitution:
+" \/{string}/, \?{string}? and \&{string}&
+func Test_sub_vi_compatibility()
+ new
+ call setline(1, ['blue green yellow orange blue'])
+ let @/ = 'orange'
+ s\/white/
+ let @/ = 'blue'
+ s\?amber?
+ let @/ = 'white'
+ s\&green&
+ call assert_equal('amber green yellow white green', getline(1))
+ close!
+endfunc
+
+" Test for substitute with the new text longer than the original text
+func Test_sub_expand_text()
+ new
+ call setline(1, 'abcabcabcabcabcabcabcabc')
+ s/b/\=repeat('B', 10)/g
+ call assert_equal(repeat('aBBBBBBBBBBc', 8), getline(1))
+ close!
+endfunc
+
+" Test for command failures when the last substitute pattern is not set.
+func Test_sub_with_no_last_pat()
+ let lines =<< trim [SCRIPT]
+ call assert_fails('~', 'E33:')
+ call assert_fails('s//abc/g', 'E476:')
+ call assert_fails('s\/bar', 'E476:')
+ call assert_fails('s\&bar&', 'E476:')
+ call writefile(v:errors, 'Xresult')
+ qall!
+ [SCRIPT]
+ call writefile(lines, 'Xscript')
+ if RunVim([], [], '--clean -S Xscript')
+ call assert_equal([], readfile('Xresult'))
+ endif
+
+ " Nvim does not support cpoptions flag "/"'
+ " let lines =<< trim [SCRIPT]
+ " set cpo+=/
+ " call assert_fails('s/abc/%/', 'E33:')
+ " call writefile(v:errors, 'Xresult')
+ " qall!
+ " [SCRIPT]
+ " call writefile(lines, 'Xscript')
+ " if RunVim([], [], '--clean -S Xscript')
+ " call assert_equal([], readfile('Xresult'))
+ " endif
+
+ call delete('Xscript')
+ call delete('Xresult')
+endfunc
+
+func Test_substitute()
+ call assert_equal('a1a2a3a', substitute('123', '\zs', 'a', 'g'))
+endfunc
+
func Test_submatch_list_concatenate()
let pat = 'A\(.\)'
let Rep = {-> string([submatch(0, 1)] + [[submatch(1)]])}
@@ -764,4 +858,375 @@ func Test_substitute_skipped_range()
bwipe!
endfunc
+" This was using "old_sub" after it was freed.
+func Test_using_old_sub()
+ " set compatible maxfuncdepth=10
+ set maxfuncdepth=10
+ new
+ call setline(1, 'some text.')
+ func Repl()
+ ~
+ s/
+ endfunc
+ silent! s/\%')/\=Repl()
+
+ delfunc Repl
+ bwipe!
+ set nocompatible
+endfunc
+
+" This was switching windows in between computing the length and using it.
+func Test_sub_change_window()
+ silent! lfile
+ sil! norm o0000000000000000000000000000000000000000000000000000
+ func Repl()
+ lopen
+ endfunc
+ silent! s/\%')/\=Repl()
+ bwipe!
+ bwipe!
+ delfunc Repl
+endfunc
+
+" This was undoign a change in between computing the length and using it.
+func Do_Test_sub_undo_change()
+ new
+ norm o0000000000000000000000000000000000000000000000000000
+ silent! s/\%')/\=Repl()
+ bwipe!
+endfunc
+
+func Test_sub_undo_change()
+ func Repl()
+ silent! norm g-
+ endfunc
+ call Do_Test_sub_undo_change()
+
+ func! Repl()
+ silent earlier
+ endfunc
+ call Do_Test_sub_undo_change()
+
+ delfunc Repl
+endfunc
+
+" This was opening a command line window from the expression
+func Test_sub_open_cmdline_win()
+ " the error only happens in a very specific setup, run a new Vim instance to
+ " get a clean starting point.
+ let lines =<< trim [SCRIPT]
+ set vb t_vb=
+ norm o0000000000000000000000000000000000000000000000000000
+ func Replace()
+ norm q/
+ endfunc
+ s/\%')/\=Replace()
+ redir >Xresult
+ messages
+ redir END
+ qall!
+ [SCRIPT]
+ call writefile(lines, 'Xscript')
+ if RunVim([], [], '-u NONE -S Xscript')
+ call assert_match('E565: Not allowed to change text or change window',
+ \ readfile('Xresult')->join('XX'))
+ endif
+
+ call delete('Xscript')
+ call delete('Xresult')
+endfunc
+
+" Test for the 2-letter and 3-letter :substitute commands
+func Test_substitute_short_cmd()
+ new
+ call setline(1, ['one', 'one one one'])
+ s/one/two
+ call cursor(2, 1)
+
+ " :sc
+ call feedkeys(":sc\<CR>y", 'xt')
+ call assert_equal('two one one', getline(2))
+
+ " :scg
+ call setline(2, 'one one one')
+ call feedkeys(":scg\<CR>nyq", 'xt')
+ call assert_equal('one two one', getline(2))
+
+ " :sci
+ call setline(2, 'ONE One onE')
+ call feedkeys(":sci\<CR>y", 'xt')
+ call assert_equal('two One onE', getline(2))
+
+ " :scI
+ set ignorecase
+ call setline(2, 'ONE One one')
+ call feedkeys(":scI\<CR>y", 'xt')
+ call assert_equal('ONE One two', getline(2))
+ set ignorecase&
+
+ " :scn
+ call setline(2, 'one one one')
+ let t = execute('scn')->split("\n")
+ call assert_equal(['1 match on 1 line'], t)
+ call assert_equal('one one one', getline(2))
+
+ " :scp
+ call setline(2, "\tone one one")
+ redir => output
+ call feedkeys(":scp\<CR>y", 'xt')
+ redir END
+ call assert_equal(' two one one', output->split("\n")[-1])
+ call assert_equal("\ttwo one one", getline(2))
+
+ " :scl
+ call setline(2, "\tone one one")
+ redir => output
+ call feedkeys(":scl\<CR>y", 'xt')
+ redir END
+ call assert_equal("^Itwo one one$", output->split("\n")[-1])
+ call assert_equal("\ttwo one one", getline(2))
+
+ " :sgc
+ call setline(2, 'one one one one one')
+ call feedkeys(":sgc\<CR>nyyq", 'xt')
+ call assert_equal('one two two one one', getline(2))
+
+ " :sg
+ call setline(2, 'one one one')
+ sg
+ call assert_equal('two two two', getline(2))
+
+ " :sgi
+ call setline(2, 'ONE One onE')
+ sgi
+ call assert_equal('two two two', getline(2))
+
+ " :sgI
+ set ignorecase
+ call setline(2, 'ONE One one')
+ sgI
+ call assert_equal('ONE One two', getline(2))
+ set ignorecase&
+
+ " :sgn
+ call setline(2, 'one one one')
+ let t = execute('sgn')->split("\n")
+ call assert_equal(['3 matches on 1 line'], t)
+ call assert_equal('one one one', getline(2))
+
+ " :sgp
+ call setline(2, "\tone one one")
+ redir => output
+ sgp
+ redir END
+ call assert_equal(' two two two', output->split("\n")[-1])
+ call assert_equal("\ttwo two two", getline(2))
+
+ " :sgl
+ call setline(2, "\tone one one")
+ redir => output
+ sgl
+ redir END
+ call assert_equal("^Itwo two two$", output->split("\n")[-1])
+ call assert_equal("\ttwo two two", getline(2))
+
+ " :sgr
+ call setline(2, "one one one")
+ call cursor(2, 1)
+ s/abc/xyz/e
+ let @/ = 'one'
+ sgr
+ call assert_equal('xyz xyz xyz', getline(2))
+
+ " :sic
+ call cursor(1, 1)
+ s/one/two/e
+ call setline(2, "ONE One one")
+ call cursor(2, 1)
+ call feedkeys(":sic\<CR>y", 'xt')
+ call assert_equal('two One one', getline(2))
+
+ " :si
+ call setline(2, "ONE One one")
+ si
+ call assert_equal('two One one', getline(2))
+
+ " :siI
+ call setline(2, "ONE One one")
+ siI
+ call assert_equal('ONE One two', getline(2))
+
+ " :sin
+ call setline(2, 'ONE One onE')
+ let t = execute('sin')->split("\n")
+ call assert_equal(['1 match on 1 line'], t)
+ call assert_equal('ONE One onE', getline(2))
+
+ " :sip
+ call setline(2, "\tONE One onE")
+ redir => output
+ sip
+ redir END
+ call assert_equal(' two One onE', output->split("\n")[-1])
+ call assert_equal("\ttwo One onE", getline(2))
+
+ " :sir
+ call setline(2, "ONE One onE")
+ call cursor(2, 1)
+ s/abc/xyz/e
+ let @/ = 'one'
+ sir
+ call assert_equal('xyz One onE', getline(2))
+
+ " :sIc
+ call cursor(1, 1)
+ s/one/two/e
+ call setline(2, "ONE One one")
+ call cursor(2, 1)
+ call feedkeys(":sIc\<CR>y", 'xt')
+ call assert_equal('ONE One two', getline(2))
+
+ " :sIg
+ call setline(2, "ONE one onE one")
+ sIg
+ call assert_equal('ONE two onE two', getline(2))
+
+ " :sIi
+ call setline(2, "ONE One one")
+ sIi
+ call assert_equal('two One one', getline(2))
+
+ " :sI
+ call setline(2, "ONE One one")
+ sI
+ call assert_equal('ONE One two', getline(2))
+
+ " :sIn
+ call setline(2, 'ONE One one')
+ let t = execute('sIn')->split("\n")
+ call assert_equal(['1 match on 1 line'], t)
+ call assert_equal('ONE One one', getline(2))
+
+ " :sIp
+ call setline(2, "\tONE One one")
+ redir => output
+ sIp
+ redir END
+ call assert_equal(' ONE One two', output->split("\n")[-1])
+ call assert_equal("\tONE One two", getline(2))
+
+ " :sIl
+ call setline(2, "\tONE onE one")
+ redir => output
+ sIl
+ redir END
+ call assert_equal("^IONE onE two$", output->split("\n")[-1])
+ call assert_equal("\tONE onE two", getline(2))
+
+ " :sIr
+ call setline(2, "ONE one onE")
+ call cursor(2, 1)
+ s/abc/xyz/e
+ let @/ = 'one'
+ sIr
+ call assert_equal('ONE xyz onE', getline(2))
+
+ " :src
+ call setline(2, "ONE one one")
+ call cursor(2, 1)
+ s/abc/xyz/e
+ let @/ = 'one'
+ call feedkeys(":src\<CR>y", 'xt')
+ call assert_equal('ONE xyz one', getline(2))
+
+ " :srg
+ call setline(2, "one one one")
+ call cursor(2, 1)
+ s/abc/xyz/e
+ let @/ = 'one'
+ srg
+ call assert_equal('xyz xyz xyz', getline(2))
+
+ " :sri
+ call setline(2, "ONE one onE")
+ call cursor(2, 1)
+ s/abc/xyz/e
+ let @/ = 'one'
+ sri
+ call assert_equal('xyz one onE', getline(2))
+
+ " :srI
+ call setline(2, "ONE one onE")
+ call cursor(2, 1)
+ s/abc/xyz/e
+ let @/ = 'one'
+ srI
+ call assert_equal('ONE xyz onE', getline(2))
+
+ " :srn
+ call setline(2, "ONE one onE")
+ call cursor(2, 1)
+ s/abc/xyz/e
+ let @/ = 'one'
+ let t = execute('srn')->split("\n")
+ call assert_equal(['1 match on 1 line'], t)
+ call assert_equal('ONE one onE', getline(2))
+
+ " :srp
+ call setline(2, "\tONE one onE")
+ call cursor(2, 1)
+ s/abc/xyz/e
+ let @/ = 'one'
+ redir => output
+ srp
+ redir END
+ call assert_equal(' ONE xyz onE', output->split("\n")[-1])
+ call assert_equal("\tONE xyz onE", getline(2))
+
+ " :srl
+ call setline(2, "\tONE one onE")
+ call cursor(2, 1)
+ s/abc/xyz/e
+ let @/ = 'one'
+ redir => output
+ srl
+ redir END
+ call assert_equal("^IONE xyz onE$", output->split("\n")[-1])
+ call assert_equal("\tONE xyz onE", getline(2))
+
+ " :sr
+ call setline(2, "ONE one onE")
+ call cursor(2, 1)
+ s/abc/xyz/e
+ let @/ = 'one'
+ sr
+ call assert_equal('ONE xyz onE', getline(2))
+
+ " :sce
+ s/abc/xyz/e
+ call assert_fails("sc", 'E486:')
+ sce
+ " :sge
+ call assert_fails("sg", 'E486:')
+ sge
+ " :sie
+ call assert_fails("si", 'E486:')
+ sie
+ " :sIe
+ call assert_fails("sI", 'E486:')
+ sIe
+
+ bw!
+endfunc
+
+" This should be done last to reveal a memory leak when vim_regsub_both() is
+" called to evaluate an expression but it is not used in a second call.
+func Test_z_substitute_expr_leak()
+ func SubExpr()
+ ~n
+ endfunc
+ silent! s/\%')/\=SubExpr()
+ delfunc SubExpr
+endfunc
+
" vim: shiftwidth=2 sts=2 expandtab
diff --git a/src/nvim/testdir/test_suspend.vim b/src/nvim/testdir/test_suspend.vim
index 4b3bd5eadf..bf88bd4453 100644
--- a/src/nvim/testdir/test_suspend.vim
+++ b/src/nvim/testdir/test_suspend.vim
@@ -26,8 +26,8 @@ func Test_suspend()
" Wait for shell prompt.
call WaitForAssert({-> assert_match('[$#] $', term_getline(buf, '.'))})
- call term_sendkeys(buf, v:progpath
- \ . " --clean -X"
+ call term_sendkeys(buf, GetVimCommandClean()
+ \ . " -X"
\ . " -c 'set nu'"
\ . " -c 'call setline(1, \"foo\")'"
\ . " Xfoo\<CR>")
diff --git a/src/nvim/testdir/test_swap.vim b/src/nvim/testdir/test_swap.vim
index b3018b2b0d..923e1cbf50 100644
--- a/src/nvim/testdir/test_swap.vim
+++ b/src/nvim/testdir/test_swap.vim
@@ -1,6 +1,7 @@
" Tests for the swap feature
source check.vim
+source shared.vim
func s:swapname()
return trim(execute('swapname'))
@@ -198,14 +199,17 @@ func Test_swapfile_delete()
quit
call assert_equal(fnamemodify(swapfile_name, ':t'), fnamemodify(s:swapname, ':t'))
- " 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
- call writefile(swapfile_bytes, swapfile_name)
- let s:swapname = ''
- split XswapfileText
- quit
- call assert_equal('', s:swapname)
+ " 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
+ call writefile(swapfile_bytes, swapfile_name)
+ let s:swapname = ''
+ split XswapfileText
+ quit
+ call assert_equal('', s:swapname)
+ endif
" Now set the modified flag, the swap file will not be deleted
let swapfile_bytes[28 + 80 + 899] = 0x55
@@ -274,7 +278,6 @@ func Test_swap_recover_ext()
autocmd SwapExists * let v:swapchoice = 'r'
augroup END
-
" Create a valid swapfile by editing a file with a special extension.
split Xtest.scr
call setline(1, ['one', 'two', 'three'])
@@ -307,6 +310,46 @@ func Test_swap_recover_ext()
augroup! test_swap_recover_ext
endfunc
+" Test for closing a split window automatically when a swap file is detected
+" and 'Q' is selected in the confirmation prompt.
+func Test_swap_split_win()
+ autocmd! SwapExists
+ augroup test_swap_splitwin
+ autocmd!
+ autocmd SwapExists * let v:swapchoice = 'q'
+ augroup END
+
+ " Create a valid swapfile by editing a file with a special extension.
+ split Xtest.scr
+ call setline(1, ['one', 'two', 'three'])
+ write " file is written, not modified
+ write " write again to make sure the swapfile is created
+ " read the swapfile as a Blob
+ let swapfile_name = swapname('%')
+ let swapfile_bytes = readfile(swapfile_name, 'B')
+
+ " Close and delete the file and recreate the swap file.
+ quit
+ call delete('Xtest.scr')
+ call writefile(swapfile_bytes, swapfile_name)
+ " Split edit the file again. This should fail to open the window
+ try
+ split Xtest.scr
+ catch
+ " E308 should be caught, not E306.
+ call assert_exception('E308:') " Original file may have been changed
+ endtry
+ call assert_equal(1, winnr('$'))
+
+ call delete('Xtest.scr')
+ call delete(swapfile_name)
+
+ augroup test_swap_splitwin
+ autocmd!
+ augroup END
+ augroup! test_swap_splitwin
+endfunc
+
" Test for selecting 'q' in the attention prompt
func Test_swap_prompt_splitwin()
CheckRunVimInTerminal
diff --git a/src/nvim/testdir/test_syntax.vim b/src/nvim/testdir/test_syntax.vim
index 757866f5dc..7ba0149971 100644
--- a/src/nvim/testdir/test_syntax.vim
+++ b/src/nvim/testdir/test_syntax.vim
@@ -1,5 +1,8 @@
" Test for syntax and syntax iskeyword option
+source check.vim
+CheckFeature syntax
+
source view_util.vim
source screendump.vim
@@ -197,6 +200,12 @@ func Test_syntax_completion()
call assert_match('^"syn match Boolean Character ', @:)
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', @:)
+endfunc
+
func Test_syntax_arg_skipped()
syn clear
syntax case ignore
@@ -728,6 +737,134 @@ func Test_syntax_foldlevel()
quit!
endfunc
+func Test_search_syntax_skip()
+ new
+ let lines =<< trim END
+
+ /* This is VIM */
+ Another Text for VIM
+ let a = "VIM"
+ END
+ call setline(1, lines)
+ syntax on
+ syntax match Comment "^/\*.*\*/"
+ syntax match String '".*"'
+
+ " Skip argument using string evaluation.
+ 1
+ call search('VIM', 'w', '', 0, 'synIDattr(synID(line("."), col("."), 1), "name") =~? "comment"')
+ call assert_equal('Another Text for VIM', getline('.'))
+
+ 1
+ call search('VIM', 'cw', '', 0, 'synIDattr(synID(line("."), col("."), 1), "name") !~? "string"')
+ call assert_equal(' let a = "VIM"', getline('.'))
+
+ " Skip argument using Lambda.
+ 1
+ call search('VIM', 'w', '', 0, { -> synIDattr(synID(line("."), col("."), 1), "name") =~? "comment"})
+ call assert_equal('Another Text for VIM', getline('.'))
+
+ 1
+ call search('VIM', 'cw', '', 0, { -> synIDattr(synID(line("."), col("."), 1), "name") !~? "string"})
+ call assert_equal(' let a = "VIM"', getline('.'))
+
+ " Skip argument using funcref.
+ func InComment()
+ return synIDattr(synID(line("."), col("."), 1), "name") =~? "comment"
+ endfunc
+ func NotInString()
+ return synIDattr(synID(line("."), col("."), 1), "name") !~? "string"
+ endfunc
+
+ 1
+ call search('VIM', 'w', '', 0, function('InComment'))
+ call assert_equal('Another Text for VIM', getline('.'))
+
+ 1
+ call search('VIM', 'cw', '', 0, function('NotInString'))
+ call assert_equal(' let a = "VIM"', getline('.'))
+
+ delfunc InComment
+ delfunc NotInString
+ bwipe!
+endfunc
+
+func Test_syn_contained_transparent()
+ " Comments starting with "Regression:" show the result when the highlighting
+ " span of the containing item is assigned to the contained region.
+ syntax on
+
+ let l:case = "Transparent region contained in region"
+ new
+ syntax region X start=/\[/ end=/\]/ contained transparent
+ syntax region Y start=/(/ end=/)/ contains=X
+
+ call setline(1, "==(--[~~]--)==")
+ let l:expected = " YYYYYYYYYY "
+ eval AssertHighlightGroups(1, 1, l:expected, 1, l:case)
+ syntax clear Y X
+ bw!
+
+ let l:case = "Transparent region extends region"
+ new
+ syntax region X start=/\[/ end=/\]/ contained transparent
+ syntax region Y start=/(/ end=/)/ end=/e/ contains=X
+
+ call setline(1, "==(--[~~e~~]--)==")
+ let l:expected = " YYYYYYYYYYYYY "
+ " Regression: " YYYYYYY YYY "
+ eval AssertHighlightGroups(1, 1, l:expected, 1, l:case)
+ syntax clear Y X
+ bw!
+
+ let l:case = "Nested transparent regions extend region"
+ new
+ syntax region X start=/\[/ end=/\]/ contained transparent
+ syntax region Y start=/(/ end=/)/ end=/e/ contains=X
+
+ call setline(1, "==(--[~~e~~[~~e~~]~~e~~]--)==")
+ let l:expected = " YYYYYYYYYYYYYYYYYYYYYYYYY "
+ " Regression: " YYYYYYY YYYYYYYYY "
+ eval AssertHighlightGroups(1, 1, l:expected, 1, l:case)
+ syntax clear Y X
+ bw!
+
+ let l:case = "Transparent region contained in match"
+ new
+ syntax region X start=/\[/ end=/\]/ contained transparent
+ syntax match Y /(.\{-})/ contains=X
+
+ call setline(1, "==(--[~~]--)==")
+ let l:expected = " YYYYYYYYYY "
+ eval AssertHighlightGroups(1, 1, l:expected, 1, l:case)
+ syntax clear Y X
+ bw!
+
+ let l:case = "Transparent region extends match"
+ new
+ syntax region X start=/\[/ end=/\]/ contained transparent
+ syntax match Y /(.\{-}[e)]/ contains=X
+
+ call setline(1, "==(--[~~e~~]--)==")
+ let l:expected = " YYYYYYYYYY "
+ " Regression: " YYYYYYY "
+ eval AssertHighlightGroups(1, 1, l:expected, 1, l:case)
+ syntax clear Y X
+ bw!
+
+ let l:case = "Nested transparent regions extend match"
+ new
+ syntax region X start=/\[/ end=/\]/ contained transparent
+ syntax match Y /(.\{-}[e)]/ contains=X
+
+ call setline(1, "==(--[~~e~~[~~e~~]~~e~~]--)==")
+ let l:expected = " YYYYYYYYYYYYYYYYYYYYYY "
+ " Regression: " YYYYYYY YYYYYY "
+ eval AssertHighlightGroups(1, 1, l:expected, 1, l:case)
+ syntax clear Y X
+ bw!
+endfunc
+
func Test_syn_include_contains_TOP()
let l:case = "TOP in included syntax means its group list name"
new
@@ -744,5 +881,18 @@ func Test_syn_include_contains_TOP()
bw!
endfunc
+" This was using freed memory
+func Test_WinEnter_synstack_synID()
+ autocmd WinEnter * call synstack(line("."), col("."))
+ autocmd WinEnter * call synID(line('.'), col('.') - 1, 1)
+ call setline(1, 'aaaaa')
+ normal! $
+ new
+ close
+
+ au! WinEnter
+ bw!
+endfunc
+
" vim: shiftwidth=2 sts=2 expandtab
diff --git a/src/nvim/testdir/test_system.vim b/src/nvim/testdir/test_system.vim
index 1858b48807..18692f42c9 100644
--- a/src/nvim/testdir/test_system.vim
+++ b/src/nvim/testdir/test_system.vim
@@ -46,15 +46,15 @@ func Test_System()
bwipe!
call assert_fails('call system("wc -l", 99999)', 'E86:')
-endfunction
+endfunc
-function! Test_system_exmode()
+func Test_system_exmode()
if has('unix') " echo $? only works on Unix
- let cmd = ' -es --headless -u NONE -c "source Xscript" +q; echo "result=$?"'
+ let cmd = ' -es -c "source Xscript" +q; echo "result=$?"'
" Need to put this in a script, "catch" isn't found after an unknown
" function.
call writefile(['try', 'call doesnotexist()', 'catch', 'endtry'], 'Xscript')
- let a = system(v:progpath . cmd)
+ let a = system(GetVimCommand() . cmd)
call assert_match('result=0', a)
call assert_equal(0, v:shell_error)
endif
@@ -62,33 +62,33 @@ function! Test_system_exmode()
" Error before try does set error flag.
call writefile(['call nosuchfunction()', 'try', 'call doesnotexist()', 'catch', 'endtry'], 'Xscript')
if has('unix') " echo $? only works on Unix
- let a = system(v:progpath . cmd)
+ let a = system(GetVimCommand() . cmd)
call assert_notequal('0', a[0])
endif
- let cmd = ' -es --headless -u NONE -c "source Xscript" +q'
- let a = system(v:progpath . cmd)
+ let cmd = ' -es -c "source Xscript" +q'
+ let a = system(GetVimCommand() . cmd)
call assert_notequal(0, v:shell_error)
call delete('Xscript')
if has('unix') " echo $? only works on Unix
- let cmd = ' -es --headless -u NONE -c "call doesnotexist()" +q; echo $?'
- let a = system(v:progpath. cmd)
+ let cmd = ' -es -c "call doesnotexist()" +q; echo $?'
+ let a = system(GetVimCommand() . cmd)
call assert_notequal(0, a[0])
endif
- let cmd = ' -es --headless -u NONE -c "call doesnotexist()" +q'
- let a = system(v:progpath. cmd)
+ let cmd = ' -es -c "call doesnotexist()" +q'
+ let a = system(GetVimCommand(). cmd)
call assert_notequal(0, v:shell_error)
if has('unix') " echo $? only works on Unix
- let cmd = ' -es --headless -u NONE -c "call doesnotexist()|let a=1" +q; echo $?'
- let a = system(v:progpath. cmd)
+ let cmd = ' -es -c "call doesnotexist()|let a=1" +q; echo $?'
+ let a = system(GetVimCommand() . cmd)
call assert_notequal(0, a[0])
endif
- let cmd = ' -es --headless -u NONE -c "call doesnotexist()|let a=1" +q'
- let a = system(v:progpath. cmd)
+ let cmd = ' -es -c "call doesnotexist()|let a=1" +q'
+ let a = system(GetVimCommand() . cmd)
call assert_notequal(0, v:shell_error)
endfunc
diff --git a/src/nvim/testdir/test_tabline.vim b/src/nvim/testdir/test_tabline.vim
index 117d962d08..e58a412c5a 100644
--- a/src/nvim/testdir/test_tabline.vim
+++ b/src/nvim/testdir/test_tabline.vim
@@ -1,3 +1,4 @@
+" Test for tabline
source shared.vim
@@ -17,6 +18,9 @@ func TablineWithError()
endfunc
func Test_caught_error_in_tabline()
+ if has('gui')
+ set guioptions-=e
+ endif
let showtabline_save = &showtabline
set showtabline=2
let s:func_in_tabline_called = 0
@@ -30,6 +34,9 @@ func Test_caught_error_in_tabline()
endfunc
func Test_tabline_will_be_disabled_with_error()
+ if has('gui')
+ set guioptions-=e
+ endif
let showtabline_save = &showtabline
set showtabline=2
let s:func_in_tabline_called = 0
@@ -65,6 +72,47 @@ func Test_redrawtabline()
au! Bufadd
endfunc
+" Test for the "%T" and "%X" flags in the 'tabline' option
+func MyTabLine()
+ let s = ''
+ for i in range(tabpagenr('$'))
+ " set the tab page number (for mouse clicks)
+ let s .= '%' . (i + 1) . 'T'
+
+ " the label is made by MyTabLabel()
+ let s .= ' %{MyTabLabel(' . (i + 1) . ')} '
+ endfor
+
+ " after the last tab fill with TabLineFill and reset tab page nr
+ let s .= '%T'
+
+ " right-align the label to close the current tab page
+ if tabpagenr('$') > 1
+ let s .= '%=%Xclose'
+ endif
+
+ return s
+endfunc
+
+func MyTabLabel(n)
+ let buflist = tabpagebuflist(a:n)
+ let winnr = tabpagewinnr(a:n)
+ return bufname(buflist[winnr - 1])
+endfunc
+
+func Test_tabline_flags()
+ if has('gui')
+ set guioptions-=e
+ endif
+ set tabline=%!MyTabLine()
+ edit Xtabline1
+ tabnew Xtabline2
+ redrawtabline
+ call assert_match('^ Xtabline1 Xtabline2\s\+close$', Screenline(1))
+ set tabline=
+ %bw!
+endfunc
+
function EmptyTabname()
return ""
endfunction
@@ -86,6 +134,17 @@ func Test_tabline_empty_group()
set tabline=
endfunc
+" When there are exactly 20 tabline format items (the exact size of the
+" initial tabline items array), test that we don't write beyond the size
+" of the array.
+func Test_tabline_20_format_items_no_overrun()
+ set showtabline=2
+
+ let tabline = repeat('%#StatColorHi2#', 20)
+ let &tabline = tabline
+ redrawtabline
+ set showtabline& tabline&
+endfunc
" vim: shiftwidth=2 sts=2 expandtab
diff --git a/src/nvim/testdir/test_tabpage.vim b/src/nvim/testdir/test_tabpage.vim
index 9869dc7590..d891684ecb 100644
--- a/src/nvim/testdir/test_tabpage.vim
+++ b/src/nvim/testdir/test_tabpage.vim
@@ -128,6 +128,8 @@ function Test_tabpage()
1tabmove
call assert_equal(2, tabpagenr())
+ call assert_fails('let t = tabpagenr("@")', 'E15:')
+ call assert_equal(0, tabpagewinnr(-1))
call assert_fails("99tabmove", 'E16:')
call assert_fails("+99tabmove", 'E16:')
call assert_fails("-99tabmove", 'E16:')
@@ -137,7 +139,13 @@ function Test_tabpage()
call assert_fails("tabmove -99", 'E474:')
call assert_fails("tabmove -3+", 'E474:')
call assert_fails("tabmove $3", 'E474:')
+ call assert_fails("%tabonly", 'E16:')
1tabonly!
+ tabmove 1
+ call assert_equal(1, tabpagenr())
+ tabnew
+ call assert_fails("-2tabmove", 'E474:')
+ tabonly!
endfunc
" Test autocommands
@@ -605,6 +613,16 @@ func Test_tabpage_cmdheight()
call delete('XTest_tabpage_cmdheight')
endfunc
+" Test for closing the tab page from a command window
+func Test_tabpage_close_cmdwin()
+ tabnew
+ call feedkeys("q/:tabclose\<CR>\<Esc>", 'xt')
+ call assert_equal(2, tabpagenr('$'))
+ call feedkeys("q/:tabonly\<CR>\<Esc>", 'xt')
+ call assert_equal(2, tabpagenr('$'))
+ tabonly
+endfunc
+
" Return the terminal key code for selecting a tab page from the tabline. This
" sequence contains the following codes: a CSI (0x9b), KS_TABLINE (0xf0),
" KS_FILLER (0x58) and then the tab page number.
@@ -683,4 +701,136 @@ func Test_tabline_tabmenu()
%bw!
endfunc
+" Test for changing the current tab page from an autocmd when closing a tab
+" page.
+func Test_tabpage_switchtab_on_close()
+ only
+ tabnew
+ tabnew
+ " Test for BufLeave
+ augroup T1
+ au!
+ au BufLeave * tabfirst
+ augroup END
+ tabclose
+ call assert_equal(1, tabpagenr())
+ augroup T1
+ au!
+ augroup END
+
+ " Test for WinLeave
+ $tabnew
+ augroup T1
+ au!
+ au WinLeave * tabfirst
+ augroup END
+ tabclose
+ call assert_equal(1, tabpagenr())
+ augroup T1
+ au!
+ augroup END
+
+ " Test for TabLeave
+ $tabnew
+ augroup T1
+ au!
+ au TabLeave * tabfirst
+ augroup END
+ tabclose
+ call assert_equal(1, tabpagenr())
+ augroup T1
+ au!
+ augroup END
+ augroup! T1
+ tabonly
+endfunc
+
+" Test for closing the destination tabpage when jumping from one to another.
+func Test_tabpage_close_on_switch()
+ tabnew
+ tabnew
+ edit Xfile
+ augroup T2
+ au!
+ au BufLeave Xfile 1tabclose
+ augroup END
+ tabfirst
+ call assert_equal(2, tabpagenr())
+ call assert_equal('Xfile', @%)
+ augroup T2
+ au!
+ augroup END
+ augroup! T2
+ %bw!
+endfunc
+
+" Test for jumping to last accessed tabpage
+func Test_lastused_tabpage()
+ tabonly!
+ call assert_equal(0, tabpagenr('#'))
+ call assert_beeps('call feedkeys("g\<Tab>", "xt")')
+ call assert_beeps('call feedkeys("\<C-Tab>", "xt")')
+ call assert_beeps('call feedkeys("\<C-W>g\<Tab>", "xt")')
+ call assert_fails('tabnext #', 'E475:')
+
+ " open four tab pages
+ tabnew
+ tabnew
+ tabnew
+
+ 2tabnext
+
+ " Test for g<Tab>
+ call assert_equal(4, tabpagenr('#'))
+ call feedkeys("g\<Tab>", "xt")
+ call assert_equal(4, tabpagenr())
+ call assert_equal(2, tabpagenr('#'))
+
+ " Test for <C-Tab>
+ call feedkeys("\<C-Tab>", "xt")
+ call assert_equal(2, tabpagenr())
+ call assert_equal(4, tabpagenr('#'))
+
+ " Test for <C-W>g<Tab>
+ call feedkeys("\<C-W>g\<Tab>", "xt")
+ call assert_equal(4, tabpagenr())
+ call assert_equal(2, tabpagenr('#'))
+
+ " Test for :tabnext #
+ tabnext #
+ call assert_equal(2, tabpagenr())
+ call assert_equal(4, tabpagenr('#'))
+
+ " Try to jump to a closed tab page
+ tabclose #
+ call assert_equal(0, tabpagenr('#'))
+ call feedkeys("g\<Tab>", "xt")
+ call assert_equal(2, tabpagenr())
+ call feedkeys("\<C-Tab>", "xt")
+ call assert_equal(2, tabpagenr())
+ call feedkeys("\<C-W>g\<Tab>", "xt")
+ call assert_equal(2, tabpagenr())
+ call assert_fails('tabnext #', 'E475:')
+ call assert_equal(2, tabpagenr())
+
+ " Test for :tabonly #
+ let wnum = win_getid()
+ $tabnew
+ tabonly #
+ call assert_equal(wnum, win_getid())
+ call assert_equal(1, tabpagenr('$'))
+
+ " Test for :tabmove #
+ tabnew
+ let wnum = win_getid()
+ tabnew
+ tabnew
+ tabnext 2
+ tabmove #
+ call assert_equal(4, tabpagenr())
+ call assert_equal(wnum, win_getid())
+
+ tabonly!
+endfunc
+
" vim: shiftwidth=2 sts=2 expandtab
diff --git a/src/nvim/testdir/test_tagjump.vim b/src/nvim/testdir/test_tagjump.vim
index 2aa04df42a..1dd656ece5 100644
--- a/src/nvim/testdir/test_tagjump.vim
+++ b/src/nvim/testdir/test_tagjump.vim
@@ -5,12 +5,57 @@ source screendump.vim
" SEGV occurs in older versions. (At least 7.4.1748 or older)
func Test_ptag_with_notagstack()
+ CheckFeature quickfix
+
set notagstack
call assert_fails('ptag does_not_exist_tag_name', 'E426')
set tagstack&vim
endfunc
+func Test_ptjump()
+ CheckFeature quickfix
+
+ set tags=Xtags
+ call writefile(["!_TAG_FILE_ENCODING\tutf-8\t//",
+ \ "one\tXfile\t1",
+ \ "three\tXfile\t3",
+ \ "two\tXfile\t2"],
+ \ 'Xtags')
+ call writefile(['one', 'two', 'three'], 'Xfile')
+
+ %bw!
+ ptjump two
+ call assert_equal(2, winnr())
+ wincmd p
+ call assert_equal(1, &previewwindow)
+ call assert_equal('Xfile', expand("%:p:t"))
+ call assert_equal(2, line('.'))
+ call assert_equal(2, winnr('$'))
+ call assert_equal(1, winnr())
+ close
+ call setline(1, ['one', 'two', 'three'])
+ exe "normal 3G\<C-W>g}"
+ call assert_equal(2, winnr())
+ wincmd p
+ call assert_equal(1, &previewwindow)
+ call assert_equal('Xfile', expand("%:p:t"))
+ call assert_equal(3, line('.'))
+ call assert_equal(2, winnr('$'))
+ call assert_equal(1, winnr())
+ close
+ exe "normal 3G5\<C-W>\<C-G>}"
+ wincmd p
+ call assert_equal(5, winheight(0))
+ close
+
+ call delete('Xtags')
+ call delete('Xfile')
+ set tags&
+endfunc
+
func Test_cancel_ptjump()
+ CheckFeature quickfix
+
set tags=Xtags
call writefile(["!_TAG_FILE_ENCODING\tutf-8\t//",
\ "word\tfile1\tcmd1",
@@ -70,6 +115,8 @@ func Test_duplicate_tagjump()
endfunc
func Test_tagjump_switchbuf()
+ CheckFeature quickfix
+
set tags=Xtags
call writefile(["!_TAG_FILE_ENCODING\tutf-8\t//",
\ "second\tXfile1\t2",
@@ -641,7 +688,7 @@ func Test_tag_envvar()
endfunc
" Test for :ptag
-func Test_ptag()
+func Test_tag_preview()
call writefile(["!_TAG_FILE_ENCODING\tutf-8\t//",
\ "second\tXfile1\t2",
\ "third\tXfile1\t3",],
@@ -655,11 +702,19 @@ func Test_ptag()
call assert_equal(2, winnr('$'))
call assert_equal(1, getwinvar(1, '&previewwindow'))
call assert_equal(0, getwinvar(2, '&previewwindow'))
- wincmd w
+ wincmd P
call assert_equal(3, line('.'))
" jump to the tag again
+ wincmd w
ptag third
+ wincmd P
+ call assert_equal(3, line('.'))
+
+ " jump to the newer tag
+ wincmd w
+ ptag
+ wincmd P
call assert_equal(3, line('.'))
" close the preview window
@@ -829,8 +884,8 @@ func Test_tag_last_search_pat()
%bwipe
endfunc
-" Test for jumping to a tag when the tag stack is full
-func Test_tag_stack_full()
+" Tag stack tests
+func Test_tag_stack()
let l = []
for i in range(10, 31)
let l += ["var" .. i .. "\tXfoo\t/^int var" .. i .. ";$/"]
@@ -844,6 +899,7 @@ func Test_tag_stack_full()
endfor
call writefile(l, 'Xfoo')
+ " Jump to a tag when the tag stack is full. Oldest entry should be removed.
enew
for i in range(10, 30)
exe "tag var" .. i
@@ -856,9 +912,15 @@ func Test_tag_stack_full()
call assert_equal('var12', l.items[0].tagname)
call assert_equal('var31', l.items[19].tagname)
- " Jump from the top of the stack
+ " Use tnext with a single match
+ call assert_fails('tnext', 'E427:')
+
+ " Jump to newest entry from the top of the stack
call assert_fails('tag', 'E556:')
+ " Pop with zero count from the top of the stack
+ call assert_fails('0pop', 'E556:')
+
" Pop from an unsaved buffer
enew!
call append(1, "sample text")
@@ -869,6 +931,13 @@ func Test_tag_stack_full()
" Pop all the entries in the tag stack
call assert_fails('30pop', 'E555:')
+ " Pop with a count when already at the bottom of the stack
+ call assert_fails('exe "normal 4\<C-T>"', 'E555:')
+ call assert_equal(1, gettagstack().curidx)
+
+ " Jump to newest entry from the bottom of the stack with zero count
+ call assert_fails('0tag', 'E555:')
+
" Pop the tag stack when it is empty
call settagstack(1, {'items' : []})
call assert_fails('pop', 'E73:')
@@ -895,6 +964,7 @@ func Test_tag_multimatch()
[CODE]
call writefile(code, 'Xfoo')
+ call settagstack(1, {'items' : []})
tag first
tlast
call assert_equal(3, line('.'))
@@ -903,12 +973,419 @@ func Test_tag_multimatch()
call assert_equal(1, line('.'))
call assert_fails('tprev', 'E425:')
+ tlast
+ call feedkeys("5\<CR>", 't')
+ tselect first
+ call assert_equal(2, gettagstack().curidx)
+
+ set ignorecase
+ tag FIRST
+ tnext
+ call assert_equal(2, line('.'))
+ tlast
+ tprev
+ call assert_equal(2, line('.'))
+ tNext
+ call assert_equal(1, line('.'))
+ set ignorecase&
+
+ call delete('Xtags')
+ call delete('Xfoo')
+ set tags&
+ %bwipe
+endfunc
+
+" Test for previewing multiple matching tags
+func Test_preview_tag_multimatch()
+ call writefile([
+ \ "!_TAG_FILE_ENCODING\tutf-8\t//",
+ \ "first\tXfoo\t1",
+ \ "first\tXfoo\t2",
+ \ "first\tXfoo\t3"],
+ \ 'Xtags')
+ set tags=Xtags
+ let code =<< trim [CODE]
+ int first() {}
+ int first() {}
+ int first() {}
+ [CODE]
+ call writefile(code, 'Xfoo')
+
+ enew | only
+ ptag first
+ ptlast
+ wincmd P
+ call assert_equal(3, line('.'))
+ wincmd w
+ call assert_fails('ptnext', 'E428:')
+ ptprev
+ wincmd P
+ call assert_equal(2, line('.'))
+ wincmd w
+ ptfirst
+ wincmd P
+ call assert_equal(1, line('.'))
+ wincmd w
+ call assert_fails('ptprev', 'E425:')
+ ptnext
+ wincmd P
+ call assert_equal(2, line('.'))
+ wincmd w
+ ptlast
+ call feedkeys("5\<CR>", 't')
+ ptselect first
+ wincmd P
+ call assert_equal(3, line('.'))
+
+ pclose
+
+ call delete('Xtags')
+ call delete('Xfoo')
+ set tags&
+ %bwipe
+endfunc
+
+" Test for jumping to multiple matching tags across multiple :tags commands
+func Test_tnext_multimatch()
+ call writefile([
+ \ "!_TAG_FILE_ENCODING\tutf-8\t//",
+ \ "first\tXfoo1\t1",
+ \ "first\tXfoo2\t1",
+ \ "first\tXfoo3\t1"],
+ \ 'Xtags')
+ set tags=Xtags
+ let code =<< trim [CODE]
+ int first() {}
+ [CODE]
+ call writefile(code, 'Xfoo1')
+ call writefile(code, 'Xfoo2')
+ call writefile(code, 'Xfoo3')
+
+ tag first
+ tag first
+ pop
+ tnext
+ tnext
+ call assert_fails('tnext', 'E428:')
+
+ call delete('Xtags')
+ call delete('Xfoo1')
+ call delete('Xfoo2')
+ call delete('Xfoo3')
+ set tags&
+ %bwipe
+endfunc
+
+" Test for jumping to multiple matching tags in non-existing files
+func Test_multimatch_non_existing_files()
+ call writefile([
+ \ "!_TAG_FILE_ENCODING\tutf-8\t//",
+ \ "first\tXfoo1\t1",
+ \ "first\tXfoo2\t1",
+ \ "first\tXfoo3\t1"],
+ \ 'Xtags')
+ set tags=Xtags
+
+ call settagstack(1, {'items' : []})
+ call assert_fails('tag first', 'E429:')
+ call assert_equal(3, gettagstack().items[0].matchnr)
+
+ call delete('Xtags')
+ set tags&
+ %bwipe
+endfunc
+
+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:"],
+ \ 'Xtags')
+ set tags=Xtags
+
+ let code =<< trim [CODE]
+ static int first;
+ static char first;
+ [CODE]
+ call writefile(code, 'Xfoo')
+
+ call feedkeys("\<CR>", "t")
+ let l = split(execute("tselect first"), "\n")
+ let expected =<< [DATA]
+ # pri kind tag file
+ 1 FS v first Xfoo
+ typeref:typename:int
+ 1
+ 2 FS v first Xfoo
+ typeref:typename:char
+ 2
+Type number and <Enter> (q or empty cancels):
+[DATA]
+ call assert_equal(expected, l)
+
call delete('Xtags')
call delete('Xfoo')
set tags&
%bwipe
endfunc
+" Test for :isearch, :ilist, :ijump and :isplit commands
+" Test for [i, ]i, [I, ]I, [ CTRL-I, ] CTRL-I and CTRL-W i commands
+func Test_inc_search()
+ new
+ call setline(1, ['1:foo', '2:foo', 'foo', '3:foo', '4:foo'])
+ call cursor(3, 1)
+
+ " Test for [i and ]i
+ call assert_equal('1:foo', execute('normal [i'))
+ call assert_equal('2:foo', execute('normal 2[i'))
+ call assert_fails('normal 3[i', 'E387:')
+ call assert_equal('3:foo', execute('normal ]i'))
+ call assert_equal('4:foo', execute('normal 2]i'))
+ call assert_fails('normal 3]i', 'E389:')
+
+ " Test for :isearch
+ call assert_equal('1:foo', execute('isearch foo'))
+ call assert_equal('3:foo', execute('isearch 4 /foo/'))
+ call assert_fails('isearch 3 foo', 'E387:')
+ call assert_equal('3:foo', execute('+1,$isearch foo'))
+ call assert_fails('1,.-1isearch 3 foo', 'E389:')
+ call assert_fails('isearch bar', 'E389:')
+ call assert_fails('isearch /foo/3', 'E488:')
+
+ " Test for [I and ]I
+ call assert_equal([
+ \ ' 1: 1 1:foo',
+ \ ' 2: 2 2:foo',
+ \ ' 3: 3 foo',
+ \ ' 4: 4 3:foo',
+ \ ' 5: 5 4:foo'], split(execute('normal [I'), "\n"))
+ call assert_equal([
+ \ ' 1: 4 3:foo',
+ \ ' 2: 5 4:foo'], split(execute('normal ]I'), "\n"))
+
+ " Test for :ilist
+ call assert_equal([
+ \ ' 1: 1 1:foo',
+ \ ' 2: 2 2:foo',
+ \ ' 3: 3 foo',
+ \ ' 4: 4 3:foo',
+ \ ' 5: 5 4:foo'], split(execute('ilist foo'), "\n"))
+ call assert_equal([
+ \ ' 1: 4 3:foo',
+ \ ' 2: 5 4:foo'], split(execute('+1,$ilist /foo/'), "\n"))
+ call assert_fails('ilist bar', 'E389:')
+
+ " Test for [ CTRL-I and ] CTRL-I
+ exe "normal [\t"
+ call assert_equal([1, 3], [line('.'), col('.')])
+ exe "normal 2j4[\t"
+ call assert_equal([4, 3], [line('.'), col('.')])
+ call assert_fails("normal k3[\t", 'E387:')
+ call assert_fails("normal 6[\t", 'E389:')
+ exe "normal ]\t"
+ call assert_equal([4, 3], [line('.'), col('.')])
+ exe "normal k2]\t"
+ call assert_equal([5, 3], [line('.'), col('.')])
+ call assert_fails("normal 2k3]\t", 'E389:')
+
+ " Test for :ijump
+ call cursor(3, 1)
+ ijump foo
+ call assert_equal([1, 3], [line('.'), col('.')])
+ call cursor(3, 1)
+ ijump 4 /foo/
+ call assert_equal([4, 3], [line('.'), col('.')])
+ call cursor(3, 1)
+ call assert_fails('ijump 3 foo', 'E387:')
+ +,$ijump 2 foo
+ call assert_equal([5, 3], [line('.'), col('.')])
+ call assert_fails('ijump bar', 'E389:')
+
+ " Test for CTRL-W i
+ call cursor(3, 1)
+ wincmd i
+ call assert_equal([1, 3, 3], [line('.'), col('.'), winnr('$')])
+ close
+ 5wincmd i
+ call assert_equal([5, 3, 3], [line('.'), col('.'), winnr('$')])
+ close
+ call assert_fails('3wincmd i', 'E387:')
+ call assert_fails('6wincmd i', 'E389:')
+
+ " Test for :isplit
+ isplit foo
+ call assert_equal([1, 3, 3], [line('.'), col('.'), winnr('$')])
+ close
+ isplit 5 /foo/
+ call assert_equal([5, 3, 3], [line('.'), col('.'), winnr('$')])
+ close
+ call assert_fails('isplit 3 foo', 'E387:')
+ call assert_fails('isplit 6 foo', 'E389:')
+ call assert_fails('isplit bar', 'E389:')
+
+ close!
+endfunc
+
+" this was using a line from ml_get() freed by the regexp
+func Test_isearch_copy_line()
+ new
+ norm o
+ norm 0
+ 0norm o
+ sil! norm bc0
+ sil! isearch \%')
+ bwipe!
+endfunc
+
+" Test for :dsearch, :dlist, :djump and :dsplit commands
+" Test for [d, ]d, [D, ]D, [ CTRL-D, ] CTRL-D and CTRL-W d commands
+func Test_macro_search()
+ new
+ call setline(1, ['#define FOO 1', '#define FOO 2', '#define FOO 3',
+ \ '#define FOO 4', '#define FOO 5'])
+ call cursor(3, 9)
+
+ " Test for [d and ]d
+ call assert_equal('#define FOO 1', execute('normal [d'))
+ call assert_equal('#define FOO 2', execute('normal 2[d'))
+ call assert_fails('normal 3[d', 'E387:')
+ call assert_equal('#define FOO 4', execute('normal ]d'))
+ call assert_equal('#define FOO 5', execute('normal 2]d'))
+ call assert_fails('normal 3]d', 'E388:')
+
+ " Test for :dsearch
+ call assert_equal('#define FOO 1', execute('dsearch FOO'))
+ call assert_equal('#define FOO 5', execute('dsearch 5 /FOO/'))
+ call assert_fails('dsearch 3 FOO', 'E387:')
+ call assert_equal('#define FOO 4', execute('+1,$dsearch FOO'))
+ call assert_fails('1,.-1dsearch 3 FOO', 'E388:')
+ call assert_fails('dsearch BAR', 'E388:')
+
+ " Test for [D and ]D
+ call assert_equal([
+ \ ' 1: 1 #define FOO 1',
+ \ ' 2: 2 #define FOO 2',
+ \ ' 3: 3 #define FOO 3',
+ \ ' 4: 4 #define FOO 4',
+ \ ' 5: 5 #define FOO 5'], split(execute('normal [D'), "\n"))
+ call assert_equal([
+ \ ' 1: 4 #define FOO 4',
+ \ ' 2: 5 #define FOO 5'], split(execute('normal ]D'), "\n"))
+
+ " Test for :dlist
+ call assert_equal([
+ \ ' 1: 1 #define FOO 1',
+ \ ' 2: 2 #define FOO 2',
+ \ ' 3: 3 #define FOO 3',
+ \ ' 4: 4 #define FOO 4',
+ \ ' 5: 5 #define FOO 5'], split(execute('dlist FOO'), "\n"))
+ call assert_equal([
+ \ ' 1: 4 #define FOO 4',
+ \ ' 2: 5 #define FOO 5'], split(execute('+1,$dlist /FOO/'), "\n"))
+ call assert_fails('dlist BAR', 'E388:')
+
+ " Test for [ CTRL-D and ] CTRL-D
+ exe "normal [\<C-D>"
+ call assert_equal([1, 9], [line('.'), col('.')])
+ exe "normal 2j4[\<C-D>"
+ call assert_equal([4, 9], [line('.'), col('.')])
+ call assert_fails("normal k3[\<C-D>", 'E387:')
+ call assert_fails("normal 6[\<C-D>", 'E388:')
+ exe "normal ]\<C-D>"
+ call assert_equal([4, 9], [line('.'), col('.')])
+ exe "normal k2]\<C-D>"
+ call assert_equal([5, 9], [line('.'), col('.')])
+ call assert_fails("normal 2k3]\<C-D>", 'E388:')
+
+ " Test for :djump
+ call cursor(3, 9)
+ djump FOO
+ call assert_equal([1, 9], [line('.'), col('.')])
+ call cursor(3, 9)
+ djump 4 /FOO/
+ call assert_equal([4, 9], [line('.'), col('.')])
+ call cursor(3, 9)
+ call assert_fails('djump 3 FOO', 'E387:')
+ +,$djump 2 FOO
+ call assert_equal([5, 9], [line('.'), col('.')])
+ call assert_fails('djump BAR', 'E388:')
+
+ " Test for CTRL-W d
+ call cursor(3, 9)
+ wincmd d
+ call assert_equal([1, 9, 3], [line('.'), col('.'), winnr('$')])
+ close
+ 5wincmd d
+ call assert_equal([5, 9, 3], [line('.'), col('.'), winnr('$')])
+ close
+ call assert_fails('3wincmd d', 'E387:')
+ call assert_fails('6wincmd d', 'E388:')
+ new
+ call assert_fails("normal \<C-W>d", 'E349:')
+ call assert_fails("normal \<C-W>\<C-D>", 'E349:')
+ close
+
+ " Test for :dsplit
+ dsplit FOO
+ call assert_equal([1, 9, 3], [line('.'), col('.'), winnr('$')])
+ close
+ dsplit 5 /FOO/
+ call assert_equal([5, 9, 3], [line('.'), col('.'), winnr('$')])
+ close
+ call assert_fails('dsplit 3 FOO', 'E387:')
+ call assert_fails('dsplit 6 FOO', 'E388:')
+ call assert_fails('dsplit BAR', 'E388:')
+
+ close!
+endfunc
+
+func Test_define_search()
+ " this was accessing freed memory
+ new
+ call setline(1, ['first line', '', '#define something 0'])
+ sil norm o0
+ sil! norm 
+ bwipe!
+
+ new somefile
+ call setline(1, ['first line', '', '#define something 0'])
+ sil norm 0o0
+ sil! norm ]d
+ bwipe!
+endfunc
+
+" Test for [*, [/, ]* and ]/
+func Test_comment_search()
+ new
+ call setline(1, ['', '/*', ' *', ' *', ' */'])
+ normal! 4gg[/
+ call assert_equal([2, 1], [line('.'), col('.')])
+ normal! 3gg[*
+ call assert_equal([2, 1], [line('.'), col('.')])
+ normal! 3gg]/
+ call assert_equal([5, 3], [line('.'), col('.')])
+ normal! 3gg]*
+ call assert_equal([5, 3], [line('.'), col('.')])
+ %d
+ call setline(1, ['', '/*', ' *', ' *'])
+ call assert_beeps('normal! 3gg]/')
+ %d
+ call setline(1, ['', ' *', ' *', ' */'])
+ call assert_beeps('normal! 4gg[/')
+ %d
+ call setline(1, ' /* comment */')
+ normal! 15|[/
+ call assert_equal(9, col('.'))
+ normal! 15|]/
+ call assert_equal(21, col('.'))
+ call setline(1, ' comment */')
+ call assert_beeps('normal! 15|[/')
+ call setline(1, ' /* comment')
+ call assert_beeps('normal! 15|]/')
+ close!
+endfunc
+
" Test for the 'taglength' option
func Test_tag_length()
set tags=Xtags
diff --git a/src/nvim/testdir/test_taglist.vim b/src/nvim/testdir/test_taglist.vim
index e11815ff33..be46773256 100644
--- a/src/nvim/testdir/test_taglist.vim
+++ b/src/nvim/testdir/test_taglist.vim
@@ -1,5 +1,7 @@
" test taglist(), tagfiles() functions and :tags command
+source view_util.vim
+
func Test_taglist()
call writefile([
\ "FFoo\tXfoo\t1",
@@ -222,3 +224,21 @@ func Test_format_error()
set tags&
call delete('Xtags')
endfunc
+
+" Test for :tag command completion with 'wildoptions' set to 'tagfile'
+func Test_tag_complete_wildoptions()
+ call writefile(["foo\ta.c\t10;\"\tf", "bar\tb.c\t20;\"\td"], 'Xtags')
+ set tags=Xtags
+ set wildoptions=tagfile
+
+ call feedkeys(":tag \<C-D>\<C-R>=Screenline(&lines - 1)\<CR> : "
+ \ .. "\<C-R>=Screenline(&lines - 2)\<CR>\<C-B>\"\<CR>", 'xt')
+
+ call assert_equal('"tag bar d b.c : foo f a.c', @:)
+
+ call delete('Xtags')
+ set wildoptions&
+ 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
new file mode 100644
index 0000000000..c0712aa892
--- /dev/null
+++ b/src/nvim/testdir/test_termcodes.vim
@@ -0,0 +1,60 @@
+
+" Test for terminal keycodes that doesn't have termcap entries
+func Test_special_term_keycodes()
+ new
+ " Test for <xHome>, <S-xHome> and <C-xHome>
+ " send <K_SPECIAL> <KS_EXTRA> keycode
+ call feedkeys("i\<C-K>\x80\xfd\x3f\n", 'xt')
+ " send <K_SPECIAL> <KS_MODIFIER> bitmap <K_SPECIAL> <KS_EXTRA> keycode
+ call feedkeys("i\<C-K>\x80\xfc\x2\x80\xfd\x3f\n", 'xt')
+ call feedkeys("i\<C-K>\x80\xfc\x4\x80\xfd\x3f\n", 'xt')
+ " Test for <xEnd>, <S-xEnd> and <C-xEnd>
+ call feedkeys("i\<C-K>\x80\xfd\x3d\n", 'xt')
+ call feedkeys("i\<C-K>\x80\xfc\x2\x80\xfd\x3d\n", 'xt')
+ call feedkeys("i\<C-K>\x80\xfc\x4\x80\xfd\x3d\n", 'xt')
+ " Test for <zHome>, <S-zHome> and <C-zHome>
+ call feedkeys("i\<C-K>\x80\xfd\x40\n", 'xt')
+ call feedkeys("i\<C-K>\x80\xfc\x2\x80\xfd\x40\n", 'xt')
+ call feedkeys("i\<C-K>\x80\xfc\x4\x80\xfd\x40\n", 'xt')
+ " Test for <zEnd>, <S-zEnd> and <C-zEnd>
+ call feedkeys("i\<C-K>\x80\xfd\x3e\n", 'xt')
+ call feedkeys("i\<C-K>\x80\xfc\x2\x80\xfd\x3e\n", 'xt')
+ call feedkeys("i\<C-K>\x80\xfc\x4\x80\xfd\x3e\n", 'xt')
+ " Test for <xUp>, <xDown>, <xLeft> and <xRight>
+ call feedkeys("i\<C-K>\x80\xfd\x41\n", 'xt')
+ call feedkeys("i\<C-K>\x80\xfd\x42\n", 'xt')
+ call feedkeys("i\<C-K>\x80\xfd\x43\n", 'xt')
+ call feedkeys("i\<C-K>\x80\xfd\x44\n", 'xt')
+ call assert_equal(['<Home>', '<S-Home>', '<C-Home>',
+ \ '<End>', '<S-End>', '<C-End>',
+ \ '<Home>', '<S-Home>', '<C-Home>',
+ \ '<End>', '<S-End>', '<C-End>',
+ \ '<Up>', '<Down>', '<Left>', '<Right>', ''], getline(1, '$'))
+ bw!
+endfunc
+
+func Test_simplify_ctrl_at()
+ " feeding unsimplified CTRL-@ should still trigger i_CTRL-@
+ call feedkeys("ifoo\<Esc>A\<*C-@>x", 'xt')
+ call assert_equal('foofo', getline(1))
+ bw!
+endfunc
+
+func Test_simplify_noremap()
+ call feedkeys("i\<*C-M>", 'nx')
+ call assert_equal('', getline(1))
+ call assert_equal([0, 2, 1, 0, 1], getcurpos())
+ bw!
+endfunc
+
+func Test_simplify_timedout()
+ inoremap <C-M>a b
+ call feedkeys("i\<*C-M>", 'xt')
+ call assert_equal('', getline(1))
+ call assert_equal([0, 2, 1, 0, 1], getcurpos())
+ iunmap <C-M>a
+ bw!
+endfunc
+
+
+" vim: shiftwidth=2 sts=2 expandtab
diff --git a/src/nvim/testdir/test_textformat.vim b/src/nvim/testdir/test_textformat.vim
index bf0706a0c2..970f5ae0d0 100644
--- a/src/nvim/testdir/test_textformat.vim
+++ b/src/nvim/testdir/test_textformat.vim
@@ -196,6 +196,184 @@ func Test_text_format()
enew!
endfunc
+func Test_format_c_comment()
+ new
+ setl ai cindent tw=40 et fo=croql
+ let text =<< trim END
+ var = 2345; // asdf asdf asdf asdf asdf asdf asdf asdf asdf asdf
+ END
+ call setline(1, text)
+ normal gql
+ let expected =<< trim END
+ var = 2345; // asdf asdf asdf asdf asdf
+ // asdf asdf asdf asdf asdf
+ END
+ call assert_equal(expected, getline(1, '$'))
+
+ %del
+ let text =<< trim END
+ var = 2345; // asdf asdf asdf asdf asdf asdf asdf asdf asdf asdf asdf asdf
+ END
+ call setline(1, text)
+ normal gql
+ let expected =<< trim END
+ var = 2345; // asdf asdf asdf asdf asdf
+ // asdf asdf asdf asdf asdf
+ // asdf asdf
+ END
+ call assert_equal(expected, getline(1, '$'))
+
+ %del
+ let text =<< trim END
+ #if 0 // This is another long end of
+ // line comment that
+ // wraps.
+ END
+ call setline(1, text)
+ normal gq2j
+ let expected =<< trim END
+ #if 0 // This is another long
+ // end of line comment
+ // that wraps.
+ END
+ call assert_equal(expected, getline(1, '$'))
+
+ " Using either "o" or "O" repeats a line comment occupying a whole line.
+ %del
+ let text =<< trim END
+ nop;
+ // This is a comment
+ val = val;
+ END
+ call setline(1, text)
+ normal 2Go
+ let expected =<< trim END
+ nop;
+ // This is a comment
+ //
+ val = val;
+ END
+ call assert_equal(expected, getline(1, '$'))
+ normal 2GO
+ let expected =<< trim END
+ nop;
+ //
+ // This is a comment
+ //
+ val = val;
+ END
+ call assert_equal(expected, getline(1, '$'))
+
+ " Using "o" repeats a line comment after a statement, "O" does not.
+ %del
+ let text =<< trim END
+ nop;
+ val = val; // This is a comment
+ END
+ call setline(1, text)
+ normal 2Go
+ let expected =<< trim END
+ nop;
+ val = val; // This is a comment
+ //
+ END
+ call assert_equal(expected, getline(1, '$'))
+ 3delete
+
+ " No comment repeated with a slash in 'formatoptions'
+ set fo+=/
+ normal 2Gox
+ let expected =<< trim END
+ nop;
+ val = val; // This is a comment
+ x
+ END
+ call assert_equal(expected, getline(1, '$'))
+
+ " Comment is formatted when it wraps
+ normal 2GA with some more text added
+ let expected =<< trim END
+ nop;
+ val = val; // This is a comment
+ // with some more text
+ // added
+ x
+ END
+ call assert_equal(expected, getline(1, '$'))
+
+ set fo-=/
+
+ " using 'indentexpr' instead of 'cindent' does not repeat a comment
+ setl nocindent indentexpr=2
+ %del
+ let text =<< trim END
+ nop;
+ val = val; // This is a comment
+ END
+ call setline(1, text)
+ normal 2Gox
+ let expected =<< trim END
+ nop;
+ val = val; // This is a comment
+ x
+ END
+ call assert_equal(expected, getline(1, '$'))
+ setl cindent indentexpr=
+ 3delete
+
+ normal 2GO
+ let expected =<< trim END
+ nop;
+
+ val = val; // This is a comment
+ END
+ call assert_equal(expected, getline(1, '$'))
+
+ " Using "o" does not repeat a comment in a string
+ %del
+ let text =<< trim END
+ nop;
+ val = " // This is not a comment";
+ END
+ call setline(1, text)
+ normal 2Gox
+ let expected =<< trim END
+ nop;
+ val = " // This is not a comment";
+ x
+ END
+ call assert_equal(expected, getline(1, '$'))
+
+ " Using CTRL-U after "o" fixes the indent
+ %del
+ let text =<< trim END
+ {
+ val = val; // This is a comment
+ END
+ call setline(1, text)
+ exe "normal! 2Go\<C-U>x\<Esc>"
+ let expected =<< trim END
+ {
+ val = val; // This is a comment
+ x
+ END
+ call assert_equal(expected, getline(1, '$'))
+
+ " typing comment text auto-wraps
+ %del
+ call setline(1, text)
+ exe "normal! 2GA blah more text blah.\<Esc>"
+ let expected =<< trim END
+ {
+ val = val; // This is a comment
+ // blah more text
+ // blah.
+ END
+ call assert_equal(expected, getline(1, '$'))
+
+ bwipe!
+endfunc
+
" Tests for :right, :center and :left on text with embedded TAB.
func Test_format_align()
enew!
@@ -433,6 +611,21 @@ func Test_format_align()
call assert_equal("\t\t Vim", getline(1))
q!
+ " align text with 'rightleft'
+ if has('rightleft')
+ new
+ call setline(1, 'Vim')
+ setlocal rightleft
+ left 20
+ setlocal norightleft
+ call assert_equal("\t\t Vim", getline(1))
+ setlocal rightleft
+ right
+ setlocal norightleft
+ call assert_equal("Vim", getline(1))
+ close!
+ endif
+
set tw&
endfunc
@@ -867,7 +1060,7 @@ func Test_tw_2_fo_tm_replace()
endfunc
" Test for 'matchpairs' with multibyte chars
-func Test_mps()
+func Test_mps_multibyte()
new
let t =<< trim END
{
@@ -891,6 +1084,30 @@ func Test_mps()
bwipe!
endfunc
+" Test for 'matchpairs' in latin1 encoding
+func Test_mps_latin1()
+ new
+ let save_enc = &encoding
+ " set encoding=latin1
+ call setline(1, 'abc(def)ghi')
+ normal %
+ call assert_equal(8, col('.'))
+ normal %
+ call assert_equal(4, col('.'))
+ call cursor(1, 6)
+ normal [(
+ call assert_equal(4, col('.'))
+ normal %
+ call assert_equal(8, col('.'))
+ call cursor(1, 6)
+ normal ])
+ call assert_equal(8, col('.'))
+ normal %
+ call assert_equal(4, col('.'))
+ let &encoding = save_enc
+ close!
+endfunc
+
func Test_empty_matchpairs()
split
set matchpairs= showmatch
@@ -944,8 +1161,103 @@ func Test_whichwrap_multi_byte()
bwipe!
endfunc
-func Test_substitute()
- call assert_equal('a1a2a3a', substitute('123', '\zs', 'a', 'g'))
+" 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' and 'w' flags in 'formatoptions'
diff --git a/src/nvim/testdir/test_textobjects.vim b/src/nvim/testdir/test_textobjects.vim
index 2b6bb8b302..eeb2946a8b 100644
--- a/src/nvim/testdir/test_textobjects.vim
+++ b/src/nvim/testdir/test_textobjects.vim
@@ -1,8 +1,7 @@
" Test for textobjects
-if !has('textobjects')
- finish
-endif
+source check.vim
+CheckFeature textobjects
func CpoM(line, useM, expected)
new
@@ -42,6 +41,24 @@ func Test_inner_block_with_cpo_M_right_backslash()
call CpoM('(red (blue\) green)', 1, ['red (blue\) green', 'blue\', 'red (blue\) green'])
endfunc
+func Test_inner_block_single_char()
+ new
+ call setline(1, "(a)")
+
+ set selection=inclusive
+ let @" = ''
+ call assert_nobeep('norm! 0faviby')
+ call assert_equal('a', @")
+
+ set selection=exclusive
+ let @" = ''
+ call assert_nobeep('norm! 0faviby')
+ call assert_equal('a', @")
+
+ set selection&
+ bwipe!
+endfunc
+
func Test_quote_selection_selection_exclusive()
new
call setline(1, "a 'bcde' f")
@@ -50,11 +67,11 @@ func Test_quote_selection_selection_exclusive()
exe "norm! fdvhi'y"
call assert_equal('bcde', @")
- let @"='dummy'
+ let @" = 'dummy'
exe "norm! $gevi'y"
call assert_equal('bcde', @")
- let @"='dummy'
+ let @" = 'dummy'
exe "norm! 0fbhvi'y"
call assert_equal('bcde', @")
@@ -188,10 +205,18 @@ func Test_string_html_objects()
call assert_equal("<div><div\nattr=\"attr\"\n></div></div>", @", e)
set quoteescape&
+
+ " this was going beyond the end of the line
+ %del
+ sil! norm i"\
+ sil! norm i"\
+ sil! norm i"\
+ call assert_equal('"\', getline(1))
+
+ bwipe!
endfor
set enc=utf-8
- bwipe!
endfunc
func Test_empty_html_tag()
@@ -208,6 +233,10 @@ func Test_empty_html_tag()
normal 0f<vitsaaa
call assert_equal('aaa', getline(1))
+ " selecting a tag block in an non-empty blank line should fail
+ call setline(1, ' ')
+ call assert_beeps('normal $vaty')
+
bwipe!
endfunc
@@ -342,6 +371,168 @@ func Test_sentence_with_cursor_on_delimiter()
%delete _
endfunc
+" Test for the paragraph (ap) text object
+func Test_paragraph()
+ new
+ call setline(1, ['First line.', 'Second line.', 'Third line.'])
+ call cursor(2, 1)
+ normal vapy
+ call assert_equal("First line.\nSecond line.\nThird line.\n", @")
+
+ call cursor(2, 1)
+ call assert_beeps('normal vapapy')
+
+ call setline(1, ['First line.', 'Second line.', ' ', ''])
+ call cursor(1, 1)
+ normal vapy
+ call assert_equal("First line.\nSecond line.\n \n\n", @")
+
+ call setline(1, ['', '', '', 'First line.', 'Second line.'])
+ call cursor(2, 1)
+ normal yap
+ call assert_equal("\n\n\nFirst line.\nSecond line.\n", @")
+ call assert_beeps('normal 3yap')
+ exe "normal \<C-C>"
+
+ %d
+ call setline(1, [' ', ' ', ' '])
+ call cursor(2, 1)
+ normal Vipy
+ call assert_equal(" \n \n \n", @")
+ call cursor(2, 1)
+ call assert_beeps("normal Vipip")
+ exe "normal \<C-C>"
+
+ close!
+endfunc
+
+" Tests for text object aw
+func Test_textobj_a_word()
+ new
+ call append(0, ['foobar,eins,foobar', 'foo,zwei,foo '])
+ " diw
+ norm! 1gg0diw
+ call assert_equal([',eins,foobar', 'foo,zwei,foo ', ''], getline(1,'$'))
+ " daw
+ norm! 2ggEdaw
+ call assert_equal([',eins,foobar', 'foo,zwei,', ''], getline(1, '$'))
+ " daw the last word in a line
+ call setline(1, ['foo bar', 'foo bar', ''])
+ call cursor(1, 5)
+ normal daw
+ call assert_equal('foo', getline(1))
+ " aw in visual mode
+ call cursor(2, 5)
+ normal! vawx
+ call assert_equal('foo', getline(2))
+ %d
+ call append(0, ["foo\teins\tfoobar", "foo\tzwei\tfoo "])
+ " diW
+ norm! 2ggwd2iW
+ call assert_equal(['foo eins foobar', 'foo foo ', ''], getline(1,'$'))
+ " daW
+ norm! 1ggd2aW
+ call assert_equal(['foobar', 'foo foo ', ''], getline(1,'$'))
+
+ %d
+ call append(0, ["foo\teins\tfoobar", "foo\tzwei\tfoo "])
+ " aw in visual line mode switches to characterwise mode
+ norm! 2gg$Vawd
+ call assert_equal(['foo eins foobar', 'foo zwei foo'], getline(1,'$'))
+ norm! 1gg$Viwd
+ call assert_equal(['foo eins ', 'foo zwei foo'], getline(1,'$'))
+
+ " visually selecting a tab before a word with 'selection' set to 'exclusive'
+ set selection=exclusive
+ normal gg3lvlawy
+ call assert_equal("\teins", @")
+ " visually selecting a tab before a word with 'selection' set to 'inclusive'
+ set selection=inclusive
+ normal gg3lvlawy
+ call assert_equal("\teins\t", @")
+ set selection&
+
+ " selecting a word with no non-space characters in a buffer fails
+ %d
+ call setline(1, ' ')
+ call assert_beeps('normal 3lyaw')
+
+ " visually selecting words backwards with no more words to select
+ call setline(1, 'one two')
+ call assert_beeps('normal 2lvh2aw')
+ exe "normal \<C-C>"
+ call assert_beeps('normal $vh3aw')
+ exe "normal \<C-C>"
+ call setline(1, ['', 'one two'])
+ call assert_beeps('normal 2G2lvh3aw')
+ exe "normal \<C-C>"
+
+ " selecting words forward with no more words to select
+ %d
+ call setline(1, 'one a')
+ call assert_beeps('normal 0y3aw')
+ call setline(1, 'one two ')
+ call assert_beeps('normal 0y3aw')
+ call assert_beeps('normal 03ly2aw')
+
+ " clean up
+ bw!
+endfunc
+
+" Test for is and as text objects
+func Test_textobj_sentence()
+ new
+ call append(0, ['This is a test. With some sentences!', '',
+ \ 'Even with a question? And one more. And no sentence here'])
+ " Test for dis - does not remove trailing whitespace
+ norm! 1gg0dis
+ call assert_equal([' With some sentences!', '',
+ \ 'Even with a question? And one more. And no sentence here', ''],
+ \ getline(1,'$'))
+ " Test for das - removes leading whitespace
+ norm! 3ggf?ldas
+ call assert_equal([' With some sentences!', '',
+ \ 'Even with a question? And no sentence here', ''], getline(1,'$'))
+ " when used in visual mode, is made characterwise
+ norm! 3gg$Visy
+ call assert_equal('v', visualmode())
+ " reset visualmode()
+ norm! 3ggVy
+ norm! 3gg$Vasy
+ call assert_equal('v', visualmode())
+ " basic testing for textobjects a< and at
+ %d
+ call setline(1, ['<div> ','<a href="foobar" class="foo">xyz</a>',' </div>', ' '])
+ " a<
+ norm! 1gg0da<
+ call assert_equal([' ', '<a href="foobar" class="foo">xyz</a>', ' </div>', ' '], getline(1,'$'))
+ norm! 1pj
+ call assert_equal([' <div>', '<a href="foobar" class="foo">xyz</a>', ' </div>', ' '], getline(1,'$'))
+ " at
+ norm! d2at
+ call assert_equal([' '], getline(1,'$'))
+ %d
+ call setline(1, ['<div> ','<a href="foobar" class="foo">xyz</a>',' </div>', ' '])
+ " i<
+ norm! 1gg0di<
+ call assert_equal(['<> ', '<a href="foobar" class="foo">xyz</a>', ' </div>', ' '], getline(1,'$'))
+ norm! 1Pj
+ call assert_equal(['<div> ', '<a href="foobar" class="foo">xyz</a>', ' </div>', ' '], getline(1,'$'))
+ norm! d2it
+ call assert_equal(['<div></div>',' '], getline(1,'$'))
+ " basic testing for a[ and i[ text object
+ %d
+ call setline(1, [' ', '[', 'one [two]', 'thre', ']'])
+ norm! 3gg0di[
+ call assert_equal([' ', '[', ']'], getline(1,'$'))
+ call setline(1, [' ', '[', 'one [two]', 'thre', ']'])
+ norm! 3gg0ftd2a[
+ call assert_equal([' '], getline(1,'$'))
+
+ " clean up
+ bw!
+endfunc
+
" Test for quote (', " and `) textobjects
func Test_textobj_quote()
new
diff --git a/src/nvim/testdir/test_timers.vim b/src/nvim/testdir/test_timers.vim
index aae315b2c5..56a5ec96af 100644
--- a/src/nvim/testdir/test_timers.vim
+++ b/src/nvim/testdir/test_timers.vim
@@ -1,13 +1,16 @@
" Test for timers
-if !has('timers')
- finish
-endif
+source check.vim
+CheckFeature timers
source shared.vim
source term_util.vim
source load.vim
+func SetUp()
+ call timer_stopall()
+endfunc
+
func MyHandler(timer)
let g:val += 1
endfunc
@@ -16,7 +19,7 @@ func MyHandlerWithLists(lists, timer)
let x = string(a:lists)
endfunc
-func Test_oneshot()
+func Test_timer_oneshot()
let g:val = 0
let timer = timer_start(50, 'MyHandler')
let slept = WaitFor('g:val == 1')
@@ -28,7 +31,7 @@ func Test_oneshot()
endif
endfunc
-func Test_repeat_three()
+func Test_timer_repeat_three()
let g:val = 0
let timer = timer_start(50, 'MyHandler', {'repeat': 3})
let slept = WaitFor('g:val == 3')
@@ -40,8 +43,7 @@ func Test_repeat_three()
endif
endfunc
-func Test_repeat_many()
- call timer_stopall()
+func Test_timer_repeat_many()
let g:val = 0
let timer = timer_start(50, 'MyHandler', {'repeat': -1})
if has('mac')
@@ -52,7 +54,7 @@ func Test_repeat_many()
call assert_inrange((has('mac') ? 1 : 2), LoadAdjust(5), g:val)
endfunc
-func Test_with_partial_callback()
+func Test_timer_with_partial_callback()
let g:val = 0
let meow = {'one': 1}
function meow.bite(...)
@@ -69,13 +71,13 @@ func Test_with_partial_callback()
endif
endfunc
-func Test_retain_partial()
+func Test_timer_retain_partial()
call timer_start(50, function('MyHandlerWithLists', [['a']]))
- call garbagecollect()
+ call test_garbagecollect_now()
sleep 100m
endfunc
-func Test_info()
+func Test_timer_info()
let id = timer_start(1000, 'MyHandler')
let info = id->timer_info()
call assert_equal(id, info[0]['id'])
@@ -92,10 +94,11 @@ func Test_info()
call timer_stop(id)
call assert_equal([], timer_info(id))
+
+ call assert_fails('call timer_info("abc")', 'E39:')
endfunc
-func Test_stopall()
- call timer_stopall()
+func Test_timer_stopall()
let id1 = timer_start(1000, 'MyHandler')
let id2 = timer_start(2000, 'MyHandler')
let info = timer_info()
@@ -106,7 +109,7 @@ func Test_stopall()
call assert_equal(0, len(info))
endfunc
-func Test_paused()
+func Test_timer_paused()
let g:val = 0
let id = timer_start(50, 'MyHandler')
@@ -130,6 +133,8 @@ func Test_paused()
else
call assert_inrange(0, 10, slept)
endif
+
+ call assert_fails('call timer_pause("abc", 1)', 'E39:')
endfunc
func StopMyself(timer)
@@ -139,7 +144,7 @@ func StopMyself(timer)
endif
endfunc
-func Test_delete_myself()
+func Test_timer_delete_myself()
let g:called = 0
let t = timer_start(10, 'StopMyself', {'repeat': -1})
call WaitForAssert({-> assert_equal(2, g:called)})
@@ -151,33 +156,45 @@ func StopTimer1(timer)
let g:timer2 = 10->timer_start('StopTimer2')
" avoid maxfuncdepth error
call timer_pause(g:timer1, 1)
- sleep 40m
+ sleep 20m
endfunc
func StopTimer2(timer)
call timer_stop(g:timer1)
endfunc
-func Test_stop_in_callback()
+func Test_timer_stop_in_callback()
+ call assert_equal(0, len(timer_info()))
let g:timer1 = timer_start(10, 'StopTimer1')
- sleep 40m
+ let slept = 0
+ for i in range(10)
+ if len(timer_info()) == 0
+ break
+ endif
+ sleep 10m
+ let slept += 10
+ endfor
+ " This should take only 30 msec, but on Mac it's often longer
+ call assert_inrange(0, 50, slept)
endfunc
func StopTimerAll(timer)
call timer_stopall()
endfunc
-func Test_stop_all_in_callback()
- call timer_stopall()
- let g:timer1 = timer_start(10, 'StopTimerAll')
- let info = timer_info()
- call assert_equal(1, len(info))
- if has('mac')
- sleep 100m
- endif
- sleep 40m
- let info = timer_info()
- call assert_equal(0, len(info))
+func Test_timer_stop_all_in_callback()
+ call assert_equal(0, len(timer_info()))
+ call timer_start(10, 'StopTimerAll')
+ call assert_equal(1, len(timer_info()))
+ let slept = 0
+ for i in range(10)
+ if len(timer_info()) == 0
+ break
+ endif
+ sleep 10m
+ let slept += 10
+ endfor
+ call assert_inrange(0, 30, slept)
endfunc
func FeedkeysCb(timer)
@@ -190,7 +207,7 @@ func InputCb(timer)
call Resume()
endfunc
-func Test_input_in_timer()
+func Test_timer_input_in_timer()
let g:val = ''
call timer_start(10, 'InputCb')
call Standby(1000)
@@ -212,6 +229,10 @@ func Test_timer_errors()
call WaitForAssert({-> assert_equal(3, g:call_count)})
sleep 50m
call assert_equal(3, g:call_count)
+
+ call assert_fails('call timer_start(100, "MyHandler", "abc")', 'E475:')
+ call assert_fails('call timer_start(100, [])', 'E921:')
+ call assert_fails('call timer_stop("abc")', 'E39:')
endfunc
func FuncWithCaughtError(timer)
@@ -243,7 +264,7 @@ func Interrupt(timer)
call nvim_input("\<C-C>")
endfunc
-func Test_peek_and_get_char()
+func Test_timer_peek_and_get_char()
if !has('unix') && !has('gui_running')
return
endif
@@ -254,7 +275,7 @@ func Test_peek_and_get_char()
eval intr->timer_stop()
endfunc
-func Test_getchar_zero()
+func Test_timer_getchar_zero()
if has('win32') && !has('gui_running')
" Console: no low-level input
return
@@ -272,20 +293,20 @@ func Test_getchar_zero()
call timer_stop(id)
endfunc
-func Test_ex_mode()
+func Test_timer_ex_mode()
" Function with an empty line.
func Foo(...)
endfunc
let timer = timer_start(40, function('g:Foo'), {'repeat':-1})
" This used to throw error E749.
- exe "normal gQsleep 100m\rvi\r"
+ exe "normal Qsleep 100m\rvi\r"
call timer_stop(timer)
endfunc
-func Test_restore_count()
+func Test_timer_restore_count()
if !CanRunVimInTerminal()
- return
+ throw 'Skipped: cannot run Vim in a terminal window'
endif
" Check that v:count is saved and restored, not changed by a timer.
call writefile([
@@ -316,9 +337,9 @@ endfunc
" Test that the garbage collector isn't triggered if a timer callback invokes
" vgetc().
-func Test_nocatch_garbage_collect()
- CheckFunction test_garbagecollect_soon
- CheckFunction test_override
+func Test_timer_nocatch_garbage_collect()
+ " skipped: Nvim does not support test_garbagecollect_soon(), test_override()
+ return
" 'uptimetime. must be bigger than the timer timeout
set ut=200
call test_garbagecollect_soon()
@@ -340,7 +361,7 @@ func Test_nocatch_garbage_collect()
delfunc FeedChar
endfunc
-func Test_error_in_timer_callback()
+func Test_timer_error_in_timer_callback()
if !has('terminal') || (has('win32') && has('gui_running'))
throw 'Skipped: cannot run Vim in a terminal window'
endif
@@ -375,8 +396,40 @@ func Test_error_in_timer_callback()
exe buf .. 'bwipe!'
endfunc
+" Test for garbage collection when a timer is still running
+func Test_timer_garbage_collect()
+ let timer = timer_start(1000, function('MyHandler'), {'repeat' : 10})
+ call test_garbagecollect_now()
+ let l = timer_info(timer)
+ call assert_equal(function('MyHandler'), l[0].callback)
+ call timer_stop(timer)
+endfunc
+
func Test_timer_invalid_callback()
call assert_fails('call timer_start(0, "0")', 'E921')
endfunc
+func Test_timer_using_win_execute_undo_sync()
+ let bufnr1 = bufnr()
+ new
+ let g:bufnr2 = bufnr()
+ let g:winid = win_getid()
+ exe "buffer " .. bufnr1
+ wincmd w
+ call setline(1, ['test'])
+ autocmd InsertEnter * call timer_start(100, { -> win_execute(g:winid, 'buffer ' .. g:bufnr2) })
+ call timer_start(200, { -> feedkeys("\<CR>bbbb\<Esc>") })
+ call feedkeys("Oaaaa", 'x!t')
+ " will hang here until the second timer fires
+ call assert_equal(['aaaa', 'bbbb', 'test'], getline(1, '$'))
+ undo
+ call assert_equal(['test'], getline(1, '$'))
+
+ bwipe!
+ bwipe!
+ unlet g:winid
+ unlet g:bufnr2
+ au! InsertEnter
+endfunc
+
" vim: shiftwidth=2 sts=2 expandtab
diff --git a/src/nvim/testdir/test_trycatch.vim b/src/nvim/testdir/test_trycatch.vim
index 7e513180a3..598402fafe 100644
--- a/src/nvim/testdir/test_trycatch.vim
+++ b/src/nvim/testdir/test_trycatch.vim
@@ -1972,6 +1972,162 @@ func Test_builtin_func_error()
call assert_equal('jlmnpqrtueghivyzACD', g:Xpath)
endfunc
-" Modelines {{{1
+func Test_reload_in_try_catch()
+ call writefile(['x'], 'Xreload')
+ set autoread
+ edit Xreload
+ tabnew
+ call writefile(['xx'], 'Xreload')
+ augroup ReLoad
+ au FileReadPost Xreload let x = doesnotexist
+ au BufReadPost Xreload let x = doesnotexist
+ augroup END
+ try
+ edit Xreload
+ catch
+ endtry
+ tabnew
+
+ tabclose
+ tabclose
+ autocmd! ReLoad
+ set noautoread
+ bwipe! Xreload
+ call delete('Xreload')
+endfunc
+
+" Test for errors with :catch, :throw, :finally {{{1
+func Test_try_catch_errors()
+ call assert_fails('throw |', 'E471:')
+ call assert_fails("throw \n ", 'E471:')
+ call assert_fails('catch abc', 'E603:')
+ call assert_fails('try | let i = 1| finally | catch | endtry', 'E604:')
+ call assert_fails('finally', 'E606:')
+ call assert_fails('try | finally | finally | endtry', 'E607:')
+ " v8.2.3486 has been ported, but v8.2.1183 hasn't, so E170 appears here.
+ " call assert_fails('try | for i in range(5) | endif | endtry', 'E580:')
+ call assert_fails('try | for i in range(5) | endif | endtry', 'E170:')
+ call assert_fails('try | while v:true | endtry', 'E170:')
+ call assert_fails('try | if v:true | endtry', 'E171:')
+endfunc
+
+" Test for verbose messages with :try :catch, and :finally {{{1
+func Test_try_catch_verbose()
+ " This test works only when the language is English
+ if v:lang != "C" && v:lang !~ '^[Ee]n'
+ return
+ endif
+
+ set verbose=14
+ redir => msg
+ try
+ echo i
+ catch /E121:/
+ finally
+ endtry
+ redir END
+ let expected = [
+ \ 'Exception thrown: Vim(echo):E121: Undefined variable: i',
+ \ '',
+ \ 'Exception caught: Vim(echo):E121: Undefined variable: i',
+ \ '',
+ \ 'Exception finished: Vim(echo):E121: Undefined variable: i'
+ \ ]
+ call assert_equal(expected, split(msg, "\n"))
+ set verbose&
+endfunc
+
+" Test for using throw in a called function with following error {{{1
+func Test_user_command_throw_in_function_call()
+ let lines =<< trim END
+ function s:get_dict() abort
+ throw 'my_error'
+ endfunction
+
+ try
+ call s:get_dict().foo()
+ catch /my_error/
+ let caught = 'yes'
+ catch
+ let caught = v:exception
+ endtry
+ call assert_equal('yes', caught)
+ END
+ call writefile(lines, 'XtestThrow')
+ source XtestThrow
+
+ call delete('XtestThrow')
+ unlet g:caught
+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
+ funct s:throw(msg) abort
+ throw a:msg
+ endfunc
+ func s:main() abort
+ try
+ try
+ throw 'err1'
+ catch
+ call s:throw('err2') | endtry
+ catch
+ let s:caught = 'yes'
+ endtry
+ endfunc
+
+ call s:main()
+ call assert_equal('yes', s:caught)
+ END
+ call writefile(lines, 'XtestThrow')
+ source XtestThrow
+
+ call delete('XtestThrow')
+endfunc
+
+func ThisWillFail()
+
+endfunc
+
+" This was crashing prior to the fix in 8.2.3478.
+func Test_error_in_catch_and_finally()
+ let lines =<< trim END
+ try
+ echo x
+ catch
+ for l in []
+ finally
+ END
+ call writefile(lines, 'XtestCatchAndFinally')
+ try
+ source XtestCatchAndFinally
+ catch /E600:/
+ endtry
+
+ call delete('XtestCatchAndFinally')
+endfunc
+
+" This was causing an illegal memory access
+func Test_leave_block_in_endtry_not_called()
+ let lines =<< trim END
+ " vim9script
+ " try #
+ try "
+ for x in []
+ if
+ endwhile
+ if
+ endtry
+ END
+ call writefile(lines, 'XtestEndtry')
+ try
+ source XtestEndtry
+ catch /E171:/
+ endtry
+
+ call delete('XtestEndtry')
+endfunc
+
+" Modeline {{{1
" vim: ts=8 sw=2 sts=2 expandtab tw=80 fdm=marker
-"-------------------------------------------------------------------------------
diff --git a/src/nvim/testdir/test_undo.vim b/src/nvim/testdir/test_undo.vim
index 30e00e7ad4..a9ec405aa4 100644
--- a/src/nvim/testdir/test_undo.vim
+++ b/src/nvim/testdir/test_undo.vim
@@ -3,8 +3,6 @@
" undo-able pieces. Do that by setting 'undolevels'.
" Also tests :earlier and :later.
-source check.vim
-
func Test_undotree()
new
@@ -137,8 +135,7 @@ func BackOne(expected)
endfunc
func Test_undo_del_chars()
- CheckFunction test_settime
-
+ throw 'Skipped: Nvim does not support test_settime()'
" Setup a buffer without creating undo entries
new
set ul=-1
@@ -299,6 +296,8 @@ func Test_undo_write()
close!
call delete('Xtest')
bwipe! Xtest
+
+ call assert_fails('earlier xyz', 'E475:')
endfunc
func Test_insert_expr()
@@ -332,8 +331,9 @@ func Test_insert_expr()
endfunc
func Test_undofile_earlier()
- CheckFunction test_settime
-
+ throw 'Skipped: Nvim does not support test_settime()'
+ " Issue #1254
+ " create undofile with timestamps older than Vim startup time.
let t0 = localtime() - 43200
call test_settime(t0)
new Xfile
@@ -366,7 +366,7 @@ func Test_wundo_errors()
bwipe!
endfunc
-" Check that reading a truncted undo file doesn't hang.
+" Check that reading a truncated undo file doesn't hang.
func Test_undofile_truncated()
new
call setline(1, 'hello')
@@ -429,6 +429,59 @@ func Test_cmd_in_reg_undo()
let @a = ''
endfunc
+" This used to cause an illegal memory access
+func Test_undo_append()
+ new
+ call feedkeys("axx\<Esc>v", 'xt')
+ undo
+ norm o
+ quit
+endfunc
+
+func Test_undo_0()
+ new
+ set ul=100
+ normal i1
+ undo
+ normal i2
+ undo
+ normal i3
+
+ undo 0
+ let d = undotree()
+ call assert_equal('', getline(1))
+ call assert_equal(0, d.seq_cur)
+
+ redo
+ let d = undotree()
+ call assert_equal('3', getline(1))
+ call assert_equal(3, d.seq_cur)
+
+ undo 2
+ undo 0
+ let d = undotree()
+ call assert_equal('', getline(1))
+ call assert_equal(0, d.seq_cur)
+
+ redo
+ let d = undotree()
+ call assert_equal('2', getline(1))
+ call assert_equal(2, d.seq_cur)
+
+ undo 1
+ undo 0
+ let d = undotree()
+ call assert_equal('', getline(1))
+ call assert_equal(0, d.seq_cur)
+
+ redo
+ let d = undotree()
+ call assert_equal('1', getline(1))
+ call assert_equal(1, d.seq_cur)
+
+ bwipe!
+endfunc
+
" undo or redo are noop if there is nothing to undo or redo
func Test_undo_redo_noop()
new
@@ -454,15 +507,6 @@ func Test_redo_empty_line()
bwipe!
endfunc
-" This used to cause an illegal memory access
-func Test_undo_append()
- new
- call feedkeys("axx\<Esc>v", 'xt')
- undo
- norm o
- quit
-endfunc
-
funct Test_undofile()
" Test undofile() without setting 'undodir'.
if has('persistent_undo')
@@ -504,50 +548,6 @@ funct Test_undofile()
set undodir&
endfunc
-func Test_undo_0()
- new
- set ul=100
- normal i1
- undo
- normal i2
- undo
- normal i3
-
- undo 0
- let d = undotree()
- call assert_equal('', getline(1))
- call assert_equal(0, d.seq_cur)
-
- redo
- let d = undotree()
- call assert_equal('3', getline(1))
- call assert_equal(3, d.seq_cur)
-
- undo 2
- undo 0
- let d = undotree()
- call assert_equal('', getline(1))
- call assert_equal(0, d.seq_cur)
-
- redo
- let d = undotree()
- call assert_equal('2', getline(1))
- call assert_equal(2, d.seq_cur)
-
- undo 1
- undo 0
- let d = undotree()
- call assert_equal('', getline(1))
- call assert_equal(0, d.seq_cur)
-
- redo
- let d = undotree()
- call assert_equal('1', getline(1))
- call assert_equal(1, d.seq_cur)
-
- bwipe!
-endfunc
-
" Tests for the undo file
" Explicitly break changes up in undo-able pieces by setting 'undolevels'.
func Test_undofile_2()
@@ -579,7 +579,7 @@ func Test_undofile_2()
" add 10 lines, delete 6 lines, undo 3
set undofile
- call setbufline(0, 1, ['one', 'two', 'three', 'four', 'five', 'six',
+ call setbufline('%', 1, ['one', 'two', 'three', 'four', 'five', 'six',
\ 'seven', 'eight', 'nine', 'ten'])
set undolevels=100
normal 3Gdd
@@ -733,4 +733,44 @@ func Test_undofile_cryptmethod_blowfish2()
set undofile& undolevels& cryptmethod&
endfunc
+" Test for redoing with incrementing numbered registers
+func Test_redo_repeat_numbered_register()
+ new
+ for [i, v] in [[1, 'one'], [2, 'two'], [3, 'three'],
+ \ [4, 'four'], [5, 'five'], [6, 'six'],
+ \ [7, 'seven'], [8, 'eight'], [9, 'nine']]
+ exe 'let @' .. i .. '="' .. v .. '\n"'
+ endfor
+ call feedkeys('"1p.........', 'xt')
+ call assert_equal(['', 'one', 'two', 'three', 'four', 'five', 'six',
+ \ 'seven', 'eight', 'nine', 'nine'], getline(1, '$'))
+ bwipe!
+endfunc
+
+" Test for redo in insert mode using CTRL-O with multibyte characters
+func Test_redo_multibyte_in_insert_mode()
+ new
+ call feedkeys("a\<C-K>ft", 'xt')
+ call feedkeys("uiHe\<C-O>.llo", 'xt')
+ call assert_equal("He\ufb05llo", getline(1))
+ bwipe!
+endfunc
+
+func Test_undo_mark()
+ new
+ " The undo is applied to the only line.
+ call setline(1, 'hello')
+ call feedkeys("ggyiw$p", 'xt')
+ undo
+ call assert_equal([0, 1, 1, 0], getpos("'["))
+ call assert_equal([0, 1, 1, 0], getpos("']"))
+ " The undo removes the last line.
+ call feedkeys("Goaaaa\<Esc>", 'xt')
+ call feedkeys("obbbb\<Esc>", 'xt')
+ undo
+ call assert_equal([0, 2, 1, 0], getpos("'["))
+ call assert_equal([0, 2, 1, 0], getpos("']"))
+ 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 29e578ac6d..e37fe43b22 100644
--- a/src/nvim/testdir/test_usercommands.vim
+++ b/src/nvim/testdir/test_usercommands.vim
@@ -4,63 +4,112 @@
function Test_cmdmods()
let g:mods = ''
- command! -nargs=* MyCmd let g:mods .= '<mods> '
+ command! -nargs=* MyCmd let g:mods = '<mods>'
MyCmd
+ call assert_equal('', g:mods)
aboveleft MyCmd
+ call assert_equal('aboveleft', g:mods)
abo MyCmd
+ call assert_equal('aboveleft', g:mods)
belowright MyCmd
+ call assert_equal('belowright', g:mods)
bel MyCmd
+ call assert_equal('belowright', g:mods)
botright MyCmd
+ call assert_equal('botright', g:mods)
bo MyCmd
+ call assert_equal('botright', g:mods)
browse MyCmd
+ call assert_equal('browse', g:mods)
bro MyCmd
+ call assert_equal('browse', g:mods)
confirm MyCmd
+ call assert_equal('confirm', g:mods)
conf MyCmd
+ call assert_equal('confirm', g:mods)
hide MyCmd
+ call assert_equal('hide', g:mods)
hid MyCmd
+ call assert_equal('hide', g:mods)
keepalt MyCmd
+ call assert_equal('keepalt', g:mods)
keepa MyCmd
+ call assert_equal('keepalt', g:mods)
keepjumps MyCmd
+ call assert_equal('keepjumps', g:mods)
keepj MyCmd
+ call assert_equal('keepjumps', g:mods)
keepmarks MyCmd
+ call assert_equal('keepmarks', g:mods)
kee MyCmd
+ call assert_equal('keepmarks', g:mods)
keeppatterns MyCmd
+ call assert_equal('keeppatterns', g:mods)
keepp MyCmd
+ call assert_equal('keeppatterns', g:mods)
leftabove MyCmd " results in :aboveleft
+ call assert_equal('aboveleft', g:mods)
lefta MyCmd
+ call assert_equal('aboveleft', g:mods)
lockmarks MyCmd
+ call assert_equal('lockmarks', g:mods)
loc MyCmd
- " noautocmd MyCmd
+ call assert_equal('lockmarks', g:mods)
+ noautocmd MyCmd
+ call assert_equal('noautocmd', g:mods)
+ noa MyCmd
+ call assert_equal('noautocmd', g:mods)
noswapfile MyCmd
+ call assert_equal('noswapfile', g:mods)
nos MyCmd
+ call assert_equal('noswapfile', g:mods)
rightbelow MyCmd " results in :belowright
+ call assert_equal('belowright', g:mods)
rightb MyCmd
+ call assert_equal('belowright', g:mods)
" sandbox MyCmd
silent MyCmd
+ call assert_equal('silent', g:mods)
sil MyCmd
+ call assert_equal('silent', g:mods)
+ silent! MyCmd
+ call assert_equal('silent!', g:mods)
+ sil! MyCmd
+ call assert_equal('silent!', g:mods)
tab MyCmd
+ call assert_equal('tab', g:mods)
topleft MyCmd
+ call assert_equal('topleft', g:mods)
to MyCmd
- " unsilent MyCmd
+ call assert_equal('topleft', g:mods)
+ unsilent MyCmd
+ call assert_equal('unsilent', g:mods)
+ uns MyCmd
+ call assert_equal('unsilent', g:mods)
verbose MyCmd
+ call assert_equal('verbose', g:mods)
verb MyCmd
+ call assert_equal('verbose', g:mods)
+ 0verbose MyCmd
+ call assert_equal('0verbose', g:mods)
+ 3verbose MyCmd
+ call assert_equal('3verbose', g:mods)
+ 999verbose MyCmd
+ call assert_equal('999verbose', g:mods)
vertical MyCmd
+ call assert_equal('vertical', g:mods)
vert MyCmd
+ call assert_equal('vertical', g:mods)
aboveleft belowright botright browse confirm hide keepalt keepjumps
- \ keepmarks keeppatterns lockmarks noswapfile silent tab
- \ topleft verbose vertical MyCmd
-
- call assert_equal(' aboveleft aboveleft belowright belowright botright ' .
- \ 'botright browse browse confirm confirm hide hide ' .
- \ 'keepalt keepalt keepjumps keepjumps keepmarks keepmarks ' .
- \ 'keeppatterns keeppatterns aboveleft aboveleft lockmarks lockmarks noswapfile ' .
- \ 'noswapfile belowright belowright silent silent tab topleft topleft verbose verbose ' .
- \ 'vertical vertical ' .
- \ 'aboveleft belowright botright browse confirm hide keepalt keepjumps ' .
- \ 'keepmarks keeppatterns lockmarks noswapfile silent tab topleft ' .
- \ 'verbose vertical ', g:mods)
+ \ keepmarks keeppatterns lockmarks noautocmd noswapfile silent
+ \ tab topleft unsilent verbose vertical MyCmd
+
+ call assert_equal('browse confirm hide keepalt keepjumps ' .
+ \ 'keepmarks keeppatterns lockmarks noswapfile unsilent noautocmd ' .
+ \ 'silent verbose aboveleft belowright botright tab topleft vertical',
+ \ g:mods)
let g:mods = ''
command! -nargs=* MyQCmd let g:mods .= '<q-mods> '
@@ -264,15 +313,15 @@ func CustomComplete(A, L, P)
endfunc
func CustomCompleteList(A, L, P)
- return [ "Monday", "Tuesday", "Wednesday" ]
+ return [ "Monday", "Tuesday", "Wednesday", {}]
endfunc
func Test_CmdCompletion()
call feedkeys(":com -\<C-A>\<C-B>\"\<CR>", 'tx')
- call assert_equal('"com -addr bang bar buffer complete count nargs range register', @:)
+ call assert_equal('"com -addr bang bar buffer complete count keepscript nargs range register', @:)
call feedkeys(":com -nargs=0 -\<C-A>\<C-B>\"\<CR>", 'tx')
- call assert_equal('"com -nargs=0 -addr bang bar buffer complete count nargs range register', @:)
+ call assert_equal('"com -nargs=0 -addr bang bar buffer complete count keepscript nargs range register', @:)
call feedkeys(":com -nargs=\<C-A>\<C-B>\"\<CR>", 'tx')
call assert_equal('"com -nargs=* + 0 1 ?', @:)
@@ -350,7 +399,6 @@ func Test_use_execute_in_completion()
endfunc
func Test_addr_all()
- throw 'skipped: requires patch v8.1.0341 to pass'
command! -addr=lines DoSomething let g:a1 = <line1> | let g:a2 = <line2>
%DoSomething
call assert_equal(1, g:a1)
@@ -551,3 +599,46 @@ func Test_command_list()
call assert_equal("\nNo user-defined commands found", execute(':command Xxx'))
call assert_equal("\nNo user-defined commands found", execute('command'))
endfunc
+
+func Test_delcommand_buffer()
+ command Global echo 'global'
+ command -buffer OneBuffer echo 'one'
+ new
+ command -buffer TwoBuffer echo 'two'
+ call assert_equal(0, exists(':OneBuffer'))
+ call assert_equal(2, exists(':Global'))
+ call assert_equal(2, exists(':TwoBuffer'))
+ delcommand -buffer TwoBuffer
+ call assert_equal(0, exists(':TwoBuffer'))
+ call assert_fails('delcommand -buffer Global', 'E1237:')
+ call assert_fails('delcommand -buffer OneBuffer', 'E1237:')
+ bwipe!
+ call assert_equal(2, exists(':OneBuffer'))
+ delcommand -buffer OneBuffer
+ call assert_equal(0, exists(':OneBuffer'))
+ call assert_fails('delcommand -buffer Global', 'E1237:')
+ delcommand Global
+ call assert_equal(0, exists(':Global'))
+endfunc
+
+func DefCmd(name)
+ if len(a:name) > 30
+ return
+ endif
+ exe 'command ' .. a:name .. ' call DefCmd("' .. a:name .. 'x")'
+ echo a:name
+ exe a:name
+endfunc
+
+func Test_recursive_define()
+ call DefCmd('Command')
+
+ let name = 'Command'
+ while len(name) < 30
+ exe 'delcommand ' .. name
+ let name ..= 'x'
+ endwhile
+endfunc
+
+
+" vim: shiftwidth=2 sts=2 expandtab
diff --git a/src/nvim/testdir/test_utf8.vim b/src/nvim/testdir/test_utf8.vim
index 0818c2e4b0..9b010a5dbc 100644
--- a/src/nvim/testdir/test_utf8.vim
+++ b/src/nvim/testdir/test_utf8.vim
@@ -1,5 +1,6 @@
" Tests for Unicode manipulations
+source check.vim
source view_util.vim
" Visual block Insert adjusts for multi-byte char
@@ -7,7 +8,7 @@ func Test_visual_block_insert()
new
call setline(1, ["aaa", "あああ", "bbb"])
exe ":norm! gg0l\<C-V>jjIx\<Esc>"
- call assert_equal(['axaa', 'xあああ', 'bxbb'], getline(1, '$'))
+ call assert_equal(['axaa', ' xあああ', 'bxbb'], getline(1, '$'))
bwipeout!
endfunc
@@ -148,4 +149,55 @@ func Test_print_overlong()
bwipe!
endfunc
+func Test_recording_with_select_mode_utf8()
+ call Run_test_recording_with_select_mode_utf8()
+endfunc
+
+func Run_test_recording_with_select_mode_utf8()
+ new
+
+ " No escaping
+ call feedkeys("qacc12345\<Esc>gH哦\<Esc>q", "tx")
+ call assert_equal("哦", getline(1))
+ call assert_equal("cc12345\<Esc>gH哦\<Esc>", @a)
+ call setline(1, 'asdf')
+ normal! @a
+ call assert_equal("哦", getline(1))
+
+ " 固 is 0xE5 0x9B 0xBA where 0x9B is CSI
+ call feedkeys("qacc12345\<Esc>gH固\<Esc>q", "tx")
+ call assert_equal("固", getline(1))
+ call assert_equal("cc12345\<Esc>gH固\<Esc>", @a)
+ call setline(1, 'asdf')
+ normal! @a
+ call assert_equal("固", getline(1))
+
+ " 四 is 0xE5 0x9B 0x9B where 0x9B is CSI
+ call feedkeys("qacc12345\<Esc>gH四\<Esc>q", "tx")
+ call assert_equal("四", getline(1))
+ call assert_equal("cc12345\<Esc>gH四\<Esc>", @a)
+ call setline(1, 'asdf')
+ normal! @a
+ call assert_equal("四", getline(1))
+
+ " 倒 is 0xE5 0x80 0x92 where 0x80 is K_SPECIAL
+ call feedkeys("qacc12345\<Esc>gH倒\<Esc>q", "tx")
+ call assert_equal("倒", getline(1))
+ call assert_equal("cc12345\<Esc>gH倒\<Esc>", @a)
+ call setline(1, 'asdf')
+ normal! @a
+ call assert_equal("倒", getline(1))
+
+ bwipe!
+endfunc
+
+" This must be done as one of the last tests, because it starts the GUI, which
+" cannot be undone.
+func Test_zz_recording_with_select_mode_utf8_gui()
+ CheckCanRunGui
+
+ gui -f
+ call Run_test_recording_with_select_mode_utf8()
+endfunc
+
" vim: shiftwidth=2 sts=2 expandtab
diff --git a/src/nvim/testdir/test_utf8_comparisons.vim b/src/nvim/testdir/test_utf8_comparisons.vim
index fdf9d80802..f3c86b44fb 100644
--- a/src/nvim/testdir/test_utf8_comparisons.vim
+++ b/src/nvim/testdir/test_utf8_comparisons.vim
@@ -1,12 +1,12 @@
" Tests for case-insensitive UTF-8 comparisons (utf_strnicmp() in mbyte.c)
" Also test "g~ap".
-function! Ch(a, op, b, expected)
+func Ch(a, op, b, expected)
call assert_equal(eval(printf('"%s" %s "%s"', a:a, a:op, a:b)), a:expected,
\ printf('"%s" %s "%s" should return %d', a:a, a:op, a:b, a:expected))
-endfunction
+endfunc
-function! Chk(a, b, result)
+func Chk(a, b, result)
if a:result == 0
call Ch(a:a, '==?', a:b, 1)
call Ch(a:a, '!=?', a:b, 0)
@@ -86,6 +86,9 @@ endfunc
" test that g~ap changes one paragraph only.
func Test_gap()
new
- call feedkeys("iabcd\n\ndefggg0g~ap", "tx")
+ " setup text
+ call feedkeys("iabcd\<cr>\<cr>defg", "tx")
+ " modify only first line
+ call feedkeys("gg0g~ap", "tx")
call assert_equal(["ABCD", "", "defg"], getline(1,3))
endfunc
diff --git a/src/nvim/testdir/test_vartabs.vim b/src/nvim/testdir/test_vartabs.vim
index 46e0d62313..68fe15ff93 100644
--- a/src/nvim/testdir/test_vartabs.vim
+++ b/src/nvim/testdir/test_vartabs.vim
@@ -1,8 +1,7 @@
" Test for variable tabstops
-if !has("vartabs")
- finish
-endif
+source check.vim
+CheckFeature vartabs
source view_util.vim
@@ -92,6 +91,18 @@ func Test_vartabs()
let expect = "l\<tab> l\<tab>l l\<tab> l\<tab> l"
call assert_equal(expect, getline(1))
+ " Test for 'retab' with vts
+ set ts=8 sts=0 vts=5,3,6,2 vsts=
+ exe "norm! S l"
+ .retab!
+ call assert_equal("\t\t\t\tl", getline(1))
+
+ " Test for 'retab' with same vlaues as vts
+ set ts=8 sts=0 vts=5,3,6,2 vsts=
+ exe "norm! S l"
+ .retab! 5,3,6,2
+ call assert_equal("\t\t\t\tl", getline(1))
+
" Check that global and local values are set.
set ts=4 vts=6 sts=8 vsts=10
call assert_equal(&ts, 4)
@@ -135,7 +146,17 @@ func Test_vartabs()
bwipeout!
endfunc
-func! Test_vartabs_breakindent()
+func Test_retab_invalid_arg()
+ new
+ call setline(1, "\ttext")
+ retab 0
+ call assert_fails("retab -8", 'E487: Argument must be positive')
+ call assert_fails("retab 10000", 'E475:')
+ call assert_fails("retab 720575940379279360", 'E475:')
+ bwipe!
+endfunc
+
+func Test_vartabs_breakindent()
if !exists("+breakindent")
return
endif
@@ -379,3 +400,33 @@ func Test_vartabs_reset()
set all&
call assert_equal('', &vts)
endfunc
+
+func s:SaveCol(l)
+ call add(a:l, [col('.'), virtcol('.')])
+ return ''
+endfunc
+
+" Test for 'varsofttabstop'
+func Test_varsofttabstop()
+ new
+ inoremap <expr> <F2> s:SaveCol(g:cols)
+
+ set backspace=indent,eol,start
+ set varsofttabstop=6,2,5,3
+ let g:cols = []
+ call feedkeys("a\t\<F2>\t\<F2>\t\<F2>\t\<F2> ", 'xt')
+ call assert_equal("\t\t ", getline(1))
+ call assert_equal([[7, 7], [2, 9], [7, 14], [3, 17]], g:cols)
+
+ let g:cols = []
+ call feedkeys("a\<bs>\<F2>\<bs>\<F2>\<bs>\<F2>\<bs>\<F2>\<bs>\<F2>", 'xt')
+ call assert_equal('', getline(1))
+ call assert_equal([[3, 17], [7, 14], [2, 9], [7, 7], [1, 1]], g:cols)
+
+ set varsofttabstop&
+ set backspace&
+ iunmap <F2>
+ close!
+endfunc
+
+" vim: shiftwidth=2 sts=2 expandtab
diff --git a/src/nvim/testdir/test_vimscript.vim b/src/nvim/testdir/test_vimscript.vim
index 34733f127f..1323288676 100644
--- a/src/nvim/testdir/test_vimscript.vim
+++ b/src/nvim/testdir/test_vimscript.vim
@@ -1,6 +1,9 @@
" Test various aspects of the Vim script language.
" Most of this was formerly in test49.
+source check.vim
+source shared.vim
+
"-------------------------------------------------------------------------------
" Test environment {{{1
"-------------------------------------------------------------------------------
@@ -25,7 +28,7 @@ com! -nargs=1 Xout call Xout(<args>)
" 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.
-function! MakeScript(funcname, ...)
+func MakeScript(funcname, ...)
let script = tempname()
execute "redir! >" . script
execute "function" a:funcname
@@ -1156,6 +1159,82 @@ func Test_type()
call assert_equal(v:t_list, type(v:_null_list))
call assert_equal(v:t_dict, type(v:_null_dict))
call assert_equal(v:t_blob, type(v:_null_blob))
+
+ call assert_equal(0, 0 + v:false)
+ call assert_equal(1, 0 + v:true)
+ " call assert_equal(0, 0 + v:none)
+ call assert_equal(0, 0 + v:null)
+
+ call assert_equal('false', '' . v:false)
+ call assert_equal('true', '' . v:true)
+ " call assert_equal('none', '' . v:none)
+ call assert_equal('null', '' . v:null)
+
+ call assert_true(v:false == 0)
+ call assert_false(v:false != 0)
+ call assert_true(v:true == 1)
+ call assert_false(v:true != 1)
+ call assert_false(v:true == v:false)
+ call assert_true(v:true != v:false)
+
+ call assert_true(v:null == 0)
+ call assert_false(v:null != 0)
+ " call assert_true(v:none == 0)
+ " call assert_false(v:none != 0)
+
+ call assert_true(v:false is v:false)
+ call assert_true(v:true is v:true)
+ " call assert_true(v:none is v:none)
+ call assert_true(v:null is v:null)
+
+ call assert_false(v:false isnot v:false)
+ call assert_false(v:true isnot v:true)
+ " call assert_false(v:none isnot v:none)
+ call assert_false(v:null isnot v:null)
+
+ call assert_false(v:false is 0)
+ call assert_false(v:true is 1)
+ call assert_false(v:true is v:false)
+ " call assert_false(v:none is 0)
+ call assert_false(v:null is 0)
+ " call assert_false(v:null is v:none)
+
+ call assert_true(v:false isnot 0)
+ call assert_true(v:true isnot 1)
+ call assert_true(v:true isnot v:false)
+ " call assert_true(v:none isnot 0)
+ call assert_true(v:null isnot 0)
+ " call assert_true(v:null isnot v:none)
+
+ call assert_equal(v:false, eval(string(v:false)))
+ call assert_equal(v:true, eval(string(v:true)))
+ " call assert_equal(v:none, eval(string(v:none)))
+ call assert_equal(v:null, eval(string(v:null)))
+
+ call assert_equal(v:false, copy(v:false))
+ call assert_equal(v:true, copy(v:true))
+ " call assert_equal(v:none, copy(v:none))
+ call assert_equal(v:null, copy(v:null))
+
+ call assert_equal([v:false], deepcopy([v:false]))
+ call assert_equal([v:true], deepcopy([v:true]))
+ " call assert_equal([v:none], deepcopy([v:none]))
+ call assert_equal([v:null], deepcopy([v:null]))
+
+ call assert_true(empty(v:false))
+ call assert_false(empty(v:true))
+ call assert_true(empty(v:null))
+ " call assert_true(empty(v:none))
+
+ func ChangeYourMind()
+ try
+ return v:true
+ finally
+ return 'something else'
+ endtry
+ endfunc
+
+ call ChangeYourMind()
endfunc
"-------------------------------------------------------------------------------
@@ -1668,7 +1747,7 @@ func Test_function_defined_line()
[CODE]
call writefile(lines, 'Xtest.vim')
- let res = system(v:progpath .. ' --clean -es -X -S 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:]]*')
@@ -1692,6 +1771,145 @@ func Test_function_defined_line()
call delete('Xtest.vim')
endfunc
+" Test for missing :endif, :endfor, :endwhile and :endtry {{{1
+func Test_missing_end()
+ call writefile(['if 2 > 1', 'echo ">"'], 'Xscript')
+ call assert_fails('source Xscript', 'E171:')
+ call writefile(['for i in range(5)', 'echo i'], 'Xscript')
+ call assert_fails('source Xscript', 'E170:')
+ call writefile(['while v:true', 'echo "."'], 'Xscript')
+ call assert_fails('source Xscript', 'E170:')
+ call writefile(['try', 'echo "."'], 'Xscript')
+ call assert_fails('source Xscript', 'E600:')
+ call delete('Xscript')
+
+ " Using endfor with :while
+ let caught_e732 = 0
+ try
+ while v:true
+ endfor
+ catch /E732:/
+ let caught_e732 = 1
+ endtry
+ call assert_equal(1, caught_e732)
+
+ " Using endwhile with :for
+ let caught_e733 = 0
+ try
+ for i in range(1)
+ endwhile
+ catch /E733:/
+ let caught_e733 = 1
+ endtry
+ call assert_equal(1, caught_e733)
+
+ " Missing 'in' in a :for statement
+ call assert_fails('for i range(1) | endfor', 'E690:')
+endfunc
+
+" Test for deep nesting of if/for/while/try statements {{{1
+func Test_deep_nest()
+ if !CanRunVimInTerminal()
+ throw 'Skipped: cannot run vim in terminal'
+ endif
+
+ let lines =<< trim [SCRIPT]
+ " Deep nesting of if ... endif
+ func Test1()
+ let @a = join(repeat(['if v:true'], 51), "\n")
+ let @a ..= "\n"
+ let @a ..= join(repeat(['endif'], 51), "\n")
+ @a
+ let @a = ''
+ endfunc
+
+ " Deep nesting of for ... endfor
+ func Test2()
+ let @a = join(repeat(['for i in [1]'], 51), "\n")
+ let @a ..= "\n"
+ let @a ..= join(repeat(['endfor'], 51), "\n")
+ @a
+ let @a = ''
+ endfunc
+
+ " Deep nesting of while ... endwhile
+ func Test3()
+ let @a = join(repeat(['while v:true'], 51), "\n")
+ let @a ..= "\n"
+ let @a ..= join(repeat(['endwhile'], 51), "\n")
+ @a
+ let @a = ''
+ endfunc
+
+ " Deep nesting of try ... endtry
+ func Test4()
+ let @a = join(repeat(['try'], 51), "\n")
+ let @a ..= "\necho v:true\n"
+ let @a ..= join(repeat(['endtry'], 51), "\n")
+ @a
+ let @a = ''
+ endfunc
+ [SCRIPT]
+ call writefile(lines, 'Xscript')
+
+ let buf = RunVimInTerminal('-S Xscript', {'rows': 6})
+
+ " Deep nesting of if ... endif
+ call term_sendkeys(buf, ":call Test1()\n")
+ call WaitForAssert({-> assert_match('^E579:', term_getline(buf, 5))})
+
+ " Deep nesting of for ... endfor
+ call term_sendkeys(buf, ":call Test2()\n")
+ call WaitForAssert({-> assert_match('^E585:', term_getline(buf, 5))})
+
+ " Deep nesting of while ... endwhile
+ call term_sendkeys(buf, ":call Test3()\n")
+ call WaitForAssert({-> assert_match('^E585:', term_getline(buf, 5))})
+
+ " Deep nesting of try ... endtry
+ call term_sendkeys(buf, ":call Test4()\n")
+ call WaitForAssert({-> assert_match('^E601:', term_getline(buf, 5))})
+
+ "let l = ''
+ "for i in range(1, 6)
+ " let l ..= term_getline(buf, i) . "\n"
+ "endfor
+ "call assert_report(l)
+
+ call StopVimInTerminal(buf)
+ call delete('Xscript')
+endfunc
+
+" Test for <sfile>, <slnum> in a function {{{1
+func Test_sfile_in_function()
+ func Xfunc()
+ call assert_match('..Test_sfile_in_function\[5]..Xfunc', expand('<sfile>'))
+ call assert_equal('2', expand('<slnum>'))
+ endfunc
+ call Xfunc()
+ delfunc Xfunc
+endfunc
+
+func Test_for_over_string()
+ let res = ''
+ for c in 'aéc̀d'
+ let res ..= c .. '-'
+ endfor
+ call assert_equal('a-é-c̀-d-', res)
+
+ let res = ''
+ for c in ''
+ let res ..= c .. '-'
+ endfor
+ call assert_equal('', res)
+
+ let res = ''
+ for c in v:_null_string
+ let res ..= c .. '-'
+ endfor
+ call assert_equal('', res)
+endfunc
+
"-------------------------------------------------------------------------------
" Modelines {{{1
" vim: ts=8 sw=2 sts=2 expandtab tw=80 fdm=marker
diff --git a/src/nvim/testdir/test_virtualedit.vim b/src/nvim/testdir/test_virtualedit.vim
index 8f992f7501..522ca17675 100644
--- a/src/nvim/testdir/test_virtualedit.vim
+++ b/src/nvim/testdir/test_virtualedit.vim
@@ -81,6 +81,133 @@ func Test_edit_change()
normal Cx
call assert_equal('x', getline(1))
bwipe!
+ set virtualedit=
+endfunc
+
+" Tests for pasting at the beginning, end and middle of a tab character
+" in virtual edit mode.
+func Test_paste_in_tab()
+ new
+ call append(0, '')
+ set virtualedit=all
+
+ " Tests for pasting a register with characterwise mode type
+ call setreg('"', 'xyz', 'c')
+
+ " paste (p) unnamed register at the beginning of a tab
+ call setline(1, "a\tb")
+ call cursor(1, 2, 0)
+ normal p
+ call assert_equal('a xyz b', getline(1))
+
+ " paste (P) unnamed register at the beginning of a tab
+ call setline(1, "a\tb")
+ call cursor(1, 2, 0)
+ normal P
+ call assert_equal("axyz\tb", getline(1))
+
+ " paste (p) unnamed register at the end of a tab
+ call setline(1, "a\tb")
+ call cursor(1, 2, 6)
+ normal p
+ call assert_equal("a\txyzb", getline(1))
+
+ " paste (P) unnamed register at the end of a tab
+ call setline(1, "a\tb")
+ call cursor(1, 2, 6)
+ normal P
+ call assert_equal('a xyz b', getline(1))
+
+ " Tests for pasting a register with blockwise mode type
+ call setreg('"', 'xyz', 'b')
+
+ " paste (p) unnamed register at the beginning of a tab
+ call setline(1, "a\tb")
+ call cursor(1, 2, 0)
+ normal p
+ call assert_equal('a xyz b', getline(1))
+
+ " paste (P) unnamed register at the beginning of a tab
+ call setline(1, "a\tb")
+ call cursor(1, 2, 0)
+ normal P
+ call assert_equal("axyz\tb", getline(1))
+
+ " paste (p) unnamed register at the end of a tab
+ call setline(1, "a\tb")
+ call cursor(1, 2, 6)
+ normal p
+ call assert_equal("a\txyzb", getline(1))
+
+ " paste (P) unnamed register at the end of a tab
+ call setline(1, "a\tb")
+ call cursor(1, 2, 6)
+ normal P
+ call assert_equal('a xyz b', getline(1))
+
+ " Tests for pasting with gp and gP in virtual edit mode
+
+ " paste (gp) unnamed register at the beginning of a tab
+ call setline(1, "a\tb")
+ call cursor(1, 2, 0)
+ normal gp
+ call assert_equal('a xyz b', getline(1))
+ call assert_equal([0, 1, 12, 0, 12], getcurpos())
+
+ " paste (gP) unnamed register at the beginning of a tab
+ call setline(1, "a\tb")
+ call cursor(1, 2, 0)
+ normal gP
+ call assert_equal("axyz\tb", getline(1))
+ call assert_equal([0, 1, 5, 0, 5], getcurpos())
+
+ " paste (gp) unnamed register at the end of a tab
+ call setline(1, "a\tb")
+ call cursor(1, 2, 6)
+ normal gp
+ call assert_equal("a\txyzb", getline(1))
+ call assert_equal([0, 1, 6, 0, 12], getcurpos())
+
+ " paste (gP) unnamed register at the end of a tab
+ call setline(1, "a\tb")
+ call cursor(1, 2, 6)
+ normal gP
+ call assert_equal('a xyz b', getline(1))
+ call assert_equal([0, 1, 12, 0, 12], getcurpos())
+
+ " Tests for pasting a named register
+ let @r = 'xyz'
+
+ " paste (gp) named register in the middle of a tab
+ call setline(1, "a\tb")
+ call cursor(1, 2, 2)
+ normal "rgp
+ call assert_equal('a xyz b', getline(1))
+ call assert_equal([0, 1, 8, 0, 8], getcurpos())
+
+ " paste (gP) named register in the middle of a tab
+ call setline(1, "a\tb")
+ call cursor(1, 2, 2)
+ normal "rgP
+ call assert_equal('a xyz b', getline(1))
+ call assert_equal([0, 1, 7, 0, 7], getcurpos())
+
+ bwipe!
+ set virtualedit=
+endfunc
+
+" Test for yanking a few spaces within a tab to a register
+func Test_yank_in_tab()
+ new
+ let @r = ''
+ call setline(1, "a\tb")
+ set virtualedit=all
+ call cursor(1, 2, 2)
+ normal "ry5l
+ call assert_equal(' ', @r)
+
+ bwipe!
+ set virtualedit=
endfunc
" Insert "keyword keyw", ESC, C CTRL-N, shows "keyword ykeyword".
@@ -174,6 +301,9 @@ func Test_replace_on_tab()
call append(0, "'r'\t")
normal gg^5lrxAy
call assert_equal("'r' x y", getline(1))
+ call setline(1, 'aaaaaaaaaaaa')
+ exe "normal! gg2lgR\<Tab>"
+ call assert_equal("aa\taaaa", getline(1))
bwipe!
set virtualedit=
endfunc
@@ -216,4 +346,139 @@ func Test_yank_paste_small_del_reg()
set virtualedit=
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'
+let s:result_ve_off = 'x'
+
+" Utility function for Test_global_local_virtualedit()
+func s:TryVirtualeditReplace()
+ call setline(1, 'a')
+ normal gg7l
+ normal rx
+endfunc
+
+" Test for :set and :setlocal
+func Test_global_local_virtualedit()
+ new
+
+ " Verify that 'virtualedit' is initialized to empty, can be set globally to
+ " all and to empty, and can be set locally to all and to empty.
+ call s:TryVirtualeditReplace()
+ call assert_equal(s:result_ve_off, getline(1))
+ set ve=all
+ call s:TryVirtualeditReplace()
+ call assert_equal(s:result_ve_on, getline(1))
+ set ve=
+ call s:TryVirtualeditReplace()
+ call assert_equal(s:result_ve_off, getline(1))
+ setlocal ve=all
+ call s:TryVirtualeditReplace()
+ call assert_equal(s:result_ve_on, getline(1))
+ setlocal ve=
+ call s:TryVirtualeditReplace()
+ call assert_equal(s:result_ve_off, getline(1))
+
+ " Verify that :set affects multiple windows.
+ split
+ set ve=all
+ call s:TryVirtualeditReplace()
+ call assert_equal(s:result_ve_on, getline(1))
+ wincmd p
+ call s:TryVirtualeditReplace()
+ call assert_equal(s:result_ve_on, getline(1))
+ set ve=
+ wincmd p
+ call s:TryVirtualeditReplace()
+ call assert_equal(s:result_ve_off, getline(1))
+ bwipe!
+
+ " Verify that :setlocal affects only the current window.
+ new
+ split
+ setlocal ve=all
+ call s:TryVirtualeditReplace()
+ call assert_equal(s:result_ve_on, getline(1))
+ wincmd p
+ call s:TryVirtualeditReplace()
+ call assert_equal(s:result_ve_off, getline(1))
+ bwipe!
+ call s:TryVirtualeditReplace()
+ call assert_equal(s:result_ve_off, getline(1))
+
+ " Verify that the buffer 'virtualedit' state follows the global value only
+ " when empty and that "none" works as expected.
+ "
+ " 'virtualedit' State
+ " +--------+--------------------------+
+ " | Local | Global |
+ " | | |
+ " +--------+--------+--------+--------+
+ " | | "" | "all" | "none" |
+ " +--------+--------+--------+--------+
+ " | "" | off | on | off |
+ " | "all" | on | on | on |
+ " | "none" | off | off | off |
+ " +--------+--------+--------+--------+
+ new
+
+ setglobal ve=
+ setlocal ve=
+ call s:TryVirtualeditReplace()
+ call assert_equal(s:result_ve_off, getline(1))
+ setlocal ve=all
+ call s:TryVirtualeditReplace()
+ call assert_equal(s:result_ve_on, getline(1))
+ setlocal ve=none
+ call s:TryVirtualeditReplace()
+ call assert_equal(s:result_ve_off, getline(1))
+
+ setglobal ve=all
+ setlocal ve=
+ call s:TryVirtualeditReplace()
+ call assert_equal(s:result_ve_on, getline(1))
+ setlocal ve=all
+ call s:TryVirtualeditReplace()
+ call assert_equal(s:result_ve_on, getline(1))
+ setlocal ve=none
+ call s:TryVirtualeditReplace()
+ call assert_equal(s:result_ve_off, getline(1))
+ setlocal ve=NONE
+ call s:TryVirtualeditReplace()
+ call assert_equal(s:result_ve_off, getline(1))
+
+ setglobal ve=none
+ setlocal ve=
+ call s:TryVirtualeditReplace()
+ call assert_equal(s:result_ve_off, getline(1))
+ setlocal ve=all
+ call s:TryVirtualeditReplace()
+ call assert_equal(s:result_ve_on, getline(1))
+ setlocal ve=none
+ call s:TryVirtualeditReplace()
+ call assert_equal(s:result_ve_off, getline(1))
+
+ bwipe!
+
+ " Verify that the 'virtualedit' state is copied to new windows.
+ new
+ call s:TryVirtualeditReplace()
+ call assert_equal(s:result_ve_off, getline(1))
+ split
+ setlocal ve=all
+ call s:TryVirtualeditReplace()
+ call assert_equal(s:result_ve_on, getline(1))
+ split
+ call s:TryVirtualeditReplace()
+ call assert_equal(s:result_ve_on, getline(1))
+ setlocal ve=
+ split
+ call s:TryVirtualeditReplace()
+ call assert_equal(s:result_ve_off, getline(1))
+ bwipe!
+
+ setlocal virtualedit&
+ set virtualedit&
+endfunc
+
" vim: shiftwidth=2 sts=2 expandtab
diff --git a/src/nvim/testdir/test_visual.vim b/src/nvim/testdir/test_visual.vim
index 8344598486..f9ac0e0884 100644
--- a/src/nvim/testdir/test_visual.vim
+++ b/src/nvim/testdir/test_visual.vim
@@ -22,6 +22,14 @@ func Test_block_shift_overflow()
q!
endfunc
+func Test_dotregister_paste()
+ new
+ exe "norm! ihello world\<esc>"
+ norm! 0ve".p
+ call assert_equal('hello world world', getline(1))
+ q!
+endfunc
+
func Test_Visual_ctrl_o()
new
call setline(1, ['one', 'two', 'three'])
@@ -42,14 +50,6 @@ func Test_Visual_vapo()
bwipe!
endfunc
-func Test_dotregister_paste()
- new
- exe "norm! ihello world\<esc>"
- norm! 0ve".p
- call assert_equal('hello world world', getline(1))
- q!
-endfunc
-
func Test_Visual_inner_quote()
new
normal oxX
@@ -57,9 +57,37 @@ func Test_Visual_inner_quote()
bwipe!
endfunc
+" Test for Visual mode not being reset causing E315 error.
+func TriggerTheProblem()
+ " At this point there is no visual selection because :call reset it.
+ " Let's restore the selection:
+ normal gv
+ '<,'>del _
+ try
+ exe "normal \<Esc>"
+ catch /^Vim\%((\a\+)\)\=:E315/
+ echom 'Snap! E315 error!'
+ let g:msg = 'Snap! E315 error!'
+ endtry
+endfunc
+
+func Test_visual_mode_reset()
+ enew
+ let g:msg = "Everything's fine."
+ enew
+ setl buftype=nofile
+ call append(line('$'), 'Delete this line.')
+
+ " NOTE: this has to be done by a call to a function because executing :del
+ " the ex-way will require the colon operator which resets the visual mode
+ " thus preventing the problem:
+ exe "normal! GV:call TriggerTheProblem()\<CR>"
+ call assert_equal("Everything's fine.", g:msg)
+endfunc
+
" Test for visual block shift and tab characters.
func Test_block_shift_tab()
- enew!
+ new
call append(0, repeat(['one two three'], 5))
call cursor(1,1)
exe "normal i\<C-G>u"
@@ -68,7 +96,7 @@ func Test_block_shift_tab()
call assert_equal('on1 two three', getline(2))
call assert_equal('on1 two three', getline(5))
- enew!
+ %d _
call append(0, repeat(['abcdefghijklmnopqrstuvwxyz'], 5))
call cursor(1,1)
exe "normal \<C-V>4jI \<Esc>j<<11|D"
@@ -93,12 +121,26 @@ func Test_block_shift_tab()
call assert_equal(" abc\<Tab>\<Tab>defghijklmnopqrstuvwxyz", getline(4))
call assert_equal(" abc\<Tab> defghijklmnopqrstuvwxyz", getline(5))
- enew!
+ " Test for block shift with space characters at the beginning and with
+ " 'noexpandtab' and 'expandtab'
+ %d _
+ call setline(1, [" 1", " 2", " 3"])
+ setlocal shiftwidth=2 noexpandtab
+ exe "normal gg\<C-V>3j>"
+ call assert_equal(["\t1", "\t2", "\t3"], getline(1, '$'))
+ %d _
+ call setline(1, [" 1", " 2", " 3"])
+ setlocal shiftwidth=2 expandtab
+ exe "normal gg\<C-V>3j>"
+ call assert_equal([" 1", " 2", " 3"], getline(1, '$'))
+ setlocal shiftwidth&
+
+ bw!
endfunc
" Tests Blockwise Visual when there are TABs before the text.
func Test_blockwise_visual()
- enew!
+ new
call append(0, ['123456',
\ '234567',
\ '345678',
@@ -120,26 +162,31 @@ func Test_blockwise_visual()
\ "\t\tsomext",
\ "\t\ttesext"], getline(1, 7))
- enew!
+ bw!
endfunc
" Test swapping corners in blockwise visual mode with o and O
func Test_blockwise_visual_o_O()
- enew!
+ new
exe "norm! 10i.\<Esc>Y4P3lj\<C-V>4l2jr "
exe "norm! gvO\<Esc>ra"
exe "norm! gvO\<Esc>rb"
exe "norm! gvo\<C-c>rc"
exe "norm! gvO\<C-c>rd"
+ set selection=exclusive
+ exe "norm! gvOo\<C-c>re"
+ call assert_equal('...a be.', getline(4))
+ exe "norm! gvOO\<C-c>rf"
+ set selection&
call assert_equal(['..........',
\ '...c d..',
\ '... ..',
- \ '...a b..',
+ \ '...a bf.',
\ '..........'], getline(1, '$'))
- enew!
+ bw!
endfun
" Test Virtual replace mode.
@@ -237,40 +284,20 @@ func Test_virtual_replace2()
call assert_equal(['abcd',
\ 'efgh',
\ 'ijkl'], getline(1, '$'))
+
+ " Test for truncating spaces in a newly added line using 'autoindent' if
+ " characters are not added to that line.
+ %d_
+ call setline(1, [' app', ' bee', ' cat'])
+ setlocal autoindent
+ exe "normal gg$gRt\n\nr"
+ call assert_equal([' apt', '', ' rat'], getline(1, '$'))
+
" clean up
%d_
set bs&vim
endfunc
-" Test for Visual mode not being reset causing E315 error.
-func TriggerTheProblem()
- " At this point there is no visual selection because :call reset it.
- " Let's restore the selection:
- normal gv
- '<,'>del _
- try
- exe "normal \<Esc>"
- catch /^Vim\%((\a\+)\)\=:E315/
- echom 'Snap! E315 error!'
- let g:msg = 'Snap! E315 error!'
- endtry
-endfunc
-
-func Test_visual_mode_reset()
- enew
- let g:msg = "Everything's fine."
- enew
- setl buftype=nofile
- call append(line('$'), 'Delete this line.')
-
- " NOTE: this has to be done by a call to a function because executing :del
- " the ex-way will require the colon operator which resets the visual mode
- " thus preventing the problem:
- exe "normal! GV:call TriggerTheProblem()\<CR>"
- call assert_equal("Everything's fine.", g:msg)
-
-endfunc
-
func Test_Visual_word_textobject()
new
call setline(1, ['First sentence. Second sentence.'])
@@ -349,17 +376,6 @@ func Test_Visual_sentence_textobject()
bwipe!
endfunc
-func Test_curswant_not_changed()
- new
- call setline(1, ['one', 'two'])
- au InsertLeave * call getcurpos()
- call feedkeys("gg0\<C-V>jI123 \<Esc>j", 'xt')
- call assert_equal([0, 2, 1, 0, 1], getcurpos())
-
- bwipe!
- au! InsertLeave
-endfunc
-
func Test_Visual_paragraph_textobject()
new
call setline(1, ['First line.',
@@ -409,6 +425,17 @@ func Test_Visual_paragraph_textobject()
bwipe!
endfunc
+func Test_curswant_not_changed()
+ new
+ call setline(1, ['one', 'two'])
+ au InsertLeave * call getcurpos()
+ call feedkeys("gg0\<C-V>jI123 \<Esc>j", 'xt')
+ call assert_equal([0, 2, 1, 0, 1], getcurpos())
+
+ bwipe!
+ au! InsertLeave
+endfunc
+
" Tests for "vaBiB", end could be wrong.
func Test_Visual_Block()
new
@@ -433,13 +460,15 @@ func Test_Visual_Block()
close!
endfunc
-func Test_visual_put_in_block()
+" Test for 'p'ut in visual block mode
+func Test_visual_block_put()
new
- call setline(1, ['xxxx', 'y∞yy', 'zzzz'])
- normal 1G2yl
- exe "normal 1G2l\<C-V>jjlp"
- call assert_equal(['xxxx', 'y∞xx', 'zzxx'], getline(1, 3))
- bwipe!
+ call append(0, ['One', 'Two', 'Three'])
+ normal gg
+ yank
+ call feedkeys("jl\<C-V>ljp", 'xt')
+ call assert_equal(['One', 'T', 'Tee', 'One', ''], getline(1, '$'))
+ bw!
endfunc
" Visual modes (v V CTRL-V) followed by an operator; count; repeating
@@ -610,6 +639,17 @@ func Test_characterwise_visual_mode()
normal Gkvj$d
call assert_equal(['', 'a', ''], getline(1, '$'))
+ " characterwise visual mode: replace a single character line and the eol
+ %d _
+ call setline(1, "a")
+ normal v$rx
+ call assert_equal(['x'], getline(1, '$'))
+
+ " replace a character with composing characters
+ call setline(1, "xã̳x")
+ normal gg0lvrb
+ call assert_equal("xbx", getline(1))
+
bwipe!
endfunc
@@ -645,6 +685,16 @@ func Test_characterwise_select_mode()
exe "normal Gkgh\<Down>\<End>\<Del>"
call assert_equal(['', 'a', ''], getline(1, '$'))
+ " CTRL-H in select mode behaves like 'x'
+ call setline(1, 'abcdef')
+ exe "normal! gggh\<Right>\<Right>\<Right>\<C-H>"
+ call assert_equal('ef', getline(1))
+
+ " CTRL-O in select mode switches to visual mode for one command
+ call setline(1, 'abcdef')
+ exe "normal! gggh\<C-O>3lm"
+ call assert_equal('mef', getline(1))
+
sunmap <lt>End>
sunmap <lt>Down>
sunmap <lt>Del>
@@ -659,7 +709,6 @@ func Test_linewise_select_mode()
exe "normal GkkgH\<Del>"
call assert_equal(['', 'b', 'c'], getline(1, '$'))
-
" linewise select mode: delete middle two lines
call deletebufline('', 1, '$')
call append('$', ['a', 'b', 'c'])
@@ -681,6 +730,15 @@ func Test_linewise_select_mode()
bwipe!
endfunc
+" Test for blockwise select mode (g CTRL-H)
+func Test_blockwise_select_mode()
+ new
+ call setline(1, ['foo', 'bar'])
+ call feedkeys("g\<BS>\<Right>\<Down>mm", 'xt')
+ call assert_equal(['mmo', 'mmr'], getline(1, '$'))
+ close!
+endfunc
+
func Test_visual_mode_put()
new
@@ -744,8 +802,7 @@ endfunc
func Test_visual_block_mode()
new
call append(0, '')
- call setline(1, ['abcdefghijklm', 'abcdefghijklm', 'abcdefghijklm',
- \ 'abcdefghijklm', 'abcdefghijklm'])
+ call setline(1, repeat(['abcdefghijklm'], 5))
call cursor(1, 1)
" Test shift-right of a block
@@ -764,6 +821,76 @@ func Test_visual_block_mode()
\ 'axyzqqqqefgmnoklm',
\ 'abcdqqqqijklm'], getline(1, 5))
+ " Test 'C' to change till the end of the line
+ call cursor(3, 4)
+ exe "normal! \<C-V>j3lCooo"
+ call assert_equal(['axyooo', 'axyooo'], getline(3, 4))
+
+ " Test 'D' to delete till the end of the line
+ call cursor(3, 3)
+ exe "normal! \<C-V>j2lD"
+ call assert_equal(['ax', 'ax'], getline(3, 4))
+
+ " Test block insert with a short line that ends before the block
+ %d _
+ call setline(1, [" one", "a", " two"])
+ exe "normal gg\<C-V>2jIx"
+ call assert_equal([" xone", "a", " xtwo"], getline(1, '$'))
+
+ " Test block append at EOL with '$' and without '$'
+ %d _
+ call setline(1, ["one", "a", "two"])
+ exe "normal gg$\<C-V>2jAx"
+ call assert_equal(["onex", "ax", "twox"], getline(1, '$'))
+ %d _
+ call setline(1, ["one", "a", "two"])
+ exe "normal gg3l\<C-V>2jAx"
+ call assert_equal(["onex", "a x", "twox"], getline(1, '$'))
+
+ " Test block replace with an empty line in the middle and use $ to jump to
+ " the end of the line.
+ %d _
+ call setline(1, ['one', '', 'two'])
+ exe "normal gg$\<C-V>2jrx"
+ call assert_equal(["onx", "", "twx"], getline(1, '$'))
+
+ " Test block replace with an empty line in the middle and move cursor to the
+ " end of the line
+ %d _
+ call setline(1, ['one', '', 'two'])
+ exe "normal gg2l\<C-V>2jrx"
+ call assert_equal(["onx", "", "twx"], getline(1, '$'))
+
+ " Replace odd number of characters with a multibyte character
+ %d _
+ call setline(1, ['abcd', 'efgh'])
+ exe "normal ggl\<C-V>2ljr\u1100"
+ call assert_equal(["a\u1100 ", "e\u1100 "], getline(1, '$'))
+
+ " During visual block append, if the cursor moved outside of the selected
+ " range, then the edit should not be applied to the block.
+ %d _
+ call setline(1, ['aaa', 'bbb', 'ccc'])
+ exe "normal 2G\<C-V>jAx\<Up>"
+ call assert_equal(['aaa', 'bxbb', 'ccc'], getline(1, '$'))
+
+ " During visual block append, if the cursor is moved before the start of the
+ " block, then the new text should be appended there.
+ %d _
+ call setline(1, ['aaa', 'bbb', 'ccc'])
+ exe "normal $\<C-V>2jA\<Left>x"
+ call assert_equal(['aaxa', 'bbxb', 'ccxc'], getline(1, '$'))
+ " Repeat the previous test but use 'l' to move the cursor instead of '$'
+ call setline(1, ['aaa', 'bbb', 'ccc'])
+ exe "normal! gg2l\<C-V>2jA\<Left>x"
+ call assert_equal(['aaxa', 'bbxb', 'ccxc'], getline(1, '$'))
+
+ " Change a characterwise motion to a blockwise motion using CTRL-V
+ %d _
+ call setline(1, ['123', '456', '789'])
+ exe "normal ld\<C-V>j"
+ call assert_equal(['13', '46', '789'], getline(1, '$'))
+
" Test from ':help v_b_I_example'
%d _
setlocal tabstop=8 shiftwidth=4
@@ -995,6 +1122,105 @@ func Test_block_insert_replace_tabs()
bwipe!
endfunc
+" Test for * register in :
+func Test_star_register()
+ call assert_fails('*bfirst', 'E16:')
+ new
+ call setline(1, ['foo', 'bar', 'baz', 'qux'])
+ exe "normal jVj\<ESC>"
+ *yank r
+ call assert_equal("bar\nbaz\n", @r)
+
+ delmarks < >
+ call assert_fails('*yank', 'E20:')
+ close!
+endfunc
+
+" Test for using visual mode maps in select mode
+func Test_select_mode_map()
+ new
+ vmap <buffer> <F2> 3l
+ call setline(1, 'Test line')
+ call feedkeys("gh\<F2>map", 'xt')
+ call assert_equal('map line', getline(1))
+
+ vmap <buffer> <F2> ygV
+ call feedkeys("0gh\<Right>\<Right>\<F2>cwabc", 'xt')
+ call assert_equal('abc line', getline(1))
+
+ vmap <buffer> <F2> :<C-U>let v=100<CR>
+ call feedkeys("gggh\<Right>\<Right>\<F2>foo", 'xt')
+ call assert_equal('foo line', getline(1))
+
+ " reselect the select mode using gv from a visual mode map
+ vmap <buffer> <F2> gv
+ set selectmode=cmd
+ call feedkeys("0gh\<F2>map", 'xt')
+ call assert_equal('map line', getline(1))
+ set selectmode&
+
+ close!
+endfunc
+
+" Test for changing text in visual mode with 'exclusive' selection
+func Test_exclusive_selection()
+ new
+ call setline(1, ['one', 'two'])
+ set selection=exclusive
+ call feedkeys("vwcabc", 'xt')
+ call assert_equal('abctwo', getline(1))
+ call setline(1, ["\tone"])
+ set virtualedit=all
+ call feedkeys('0v2lcl', 'xt')
+ call assert_equal('l one', getline(1))
+ set virtualedit&
+ set selection&
+ close!
+endfunc
+
+" Test for starting visual mode with a count.
+" This test should be run without any previous visual modes. So this should be
+" run as a first test.
+func Test_AAA_start_visual_mode_with_count()
+ new
+ call setline(1, ['aaaaaaa', 'aaaaaaa', 'aaaaaaa', 'aaaaaaa'])
+ normal! gg2Vy
+ call assert_equal("aaaaaaa\naaaaaaa\n", @")
+ close!
+endfunc
+
+" Test for visually selecting an inner block (iB)
+func Test_visual_inner_block()
+ new
+ call setline(1, ['one', '{', 'two', '{', 'three', '}', 'four', '}', 'five'])
+ call cursor(5, 1)
+ " visually select all the lines in the block and then execute iB
+ call feedkeys("ViB\<C-C>", 'xt')
+ call assert_equal([0, 5, 1, 0], getpos("'<"))
+ call assert_equal([0, 5, 6, 0], getpos("'>"))
+ " visually select two inner blocks
+ call feedkeys("ViBiB\<C-C>", 'xt')
+ call assert_equal([0, 3, 1, 0], getpos("'<"))
+ call assert_equal([0, 7, 5, 0], getpos("'>"))
+ " try to select non-existing inner block
+ call cursor(5, 1)
+ call assert_beeps('normal ViBiBiB')
+ " try to select a unclosed inner block
+ 8,9d
+ call cursor(5, 1)
+ call assert_beeps('normal ViBiB')
+ close!
+endfunc
+
+func Test_visual_put_in_block()
+ new
+ call setline(1, ['xxxx', 'y∞yy', 'zzzz'])
+ normal 1G2yl
+ exe "normal 1G2l\<C-V>jjlp"
+ call assert_equal(['xxxx', 'y∞xx', 'zzxx'], getline(1, 3))
+ bwipe!
+endfunc
+
func Test_visual_put_in_block_using_zp()
new
" paste using zP
@@ -1090,6 +1316,13 @@ func Test_visual_put_blockedit_zy_and_zp()
bw!
endfunc
+func Test_visual_block_yank_zy()
+ new
+ " this was reading before the start of the line
+ exe "norm o\<C-T>\<Esc>\<C-V>zy"
+ bwipe!
+endfunc
+
func Test_visual_block_with_virtualedit()
CheckScreendump
@@ -1104,10 +1337,217 @@ func Test_visual_block_with_virtualedit()
call term_sendkeys(buf, "\<C-V>gg$")
call VerifyScreenDump(buf, 'Test_visual_block_with_virtualedit', {})
+ call term_sendkeys(buf, "\<Esc>gg\<C-V>G$")
+ call VerifyScreenDump(buf, 'Test_visual_block_with_virtualedit2', {})
+
" clean up
call term_sendkeys(buf, "\<Esc>")
call StopVimInTerminal(buf)
- call delete('XTest_beval')
+ call delete('XTest_block')
+endfunc
+
+func Test_visual_block_ctrl_w_f()
+ " Emtpy block selected in new buffer should not result in an error.
+ au! BufNew foo sil norm f
+ edit foo
+
+ au! BufNew
+endfunc
+
+func Test_visual_block_append_invalid_char()
+ " this was going over the end of the line
+ set isprint=@,161-255
+ new
+ call setline(1, [' let xxx', 'xxxxxˆ', 'xxxxxxxxxxx'])
+ exe "normal 0\<C-V>jjA-\<Esc>"
+ call assert_equal([' - let xxx', 'xxxxx -ˆ', 'xxxxxxxx-xxx'], getline(1, 3))
+ bwipe!
+ set isprint&
+endfunc
+
+func Test_visual_block_with_substitute()
+ " this was reading beyond the end of the line
+ new
+ norm a0)
+ sil! norm  O
+ s/)
+ sil! norm 
+ bwipe!
+endfunc
+
+func Test_visual_reselect_with_count()
+ " this was causing an illegal memory access
+ let lines =<< trim END
+
+
+
+ :
+ r<sfile>
+ exe "%norm e3\<c-v>kr\t"
+ :
+
+ :
+ END
+ call writefile(lines, 'XvisualReselect')
+ source XvisualReselect
+
+ bwipe!
+ call delete('XvisualReselect')
+endfunc
+
+func Test_visual_block_insert_round_off()
+ new
+ " The number of characters are tuned to fill a 4096 byte allocated block,
+ " so that valgrind reports going over the end.
+ call setline(1, ['xxxxx', repeat('0', 1350), "\t", repeat('x', 60)])
+ exe "normal gg0\<C-V>GI" .. repeat('0', 1320) .. "\<Esc>"
+ bwipe!
+endfunc
+
+" this was causing an ml_get error
+func Test_visual_exchange_windows()
+ enew!
+ new
+ call setline(1, ['foo', 'bar'])
+ exe "normal G\<C-V>gg\<C-W>\<C-X>OO\<Esc>"
+ bwipe!
+ bwipe!
+endfunc
+
+" this was leaving the end of the Visual area beyond the end of a line
+func Test_visual_ex_copy_line()
+ new
+ call setline(1, ["aaa", "bbbbbbbbbxbb"])
+ /x
+ exe "normal ggvjfxO"
+ t0
+ normal gNU
+ bwipe!
+endfunc
+
+" This was leaving the end of the Visual area beyond the end of a line.
+" Set 'undolevels' to start a new undo block.
+func Test_visual_undo_deletes_last_line()
+ new
+ call setline(1, ["aaa", "ccc", "dyd"])
+ set undolevels=100
+ exe "normal obbbbbbbbbxbb\<Esc>"
+ set undolevels=100
+ /y
+ exe "normal ggvjfxO"
+ undo
+ normal gNU
+
+ bwipe!
+endfunc
+
+func Test_visual_paste()
+ new
+
+ " v_p overwrites unnamed register.
+ call setline(1, ['xxxx'])
+ call setreg('"', 'foo')
+ call setreg('-', 'bar')
+ normal gg0vp
+ call assert_equal('x', @")
+ call assert_equal('x', @-)
+ call assert_equal('fooxxx', getline(1))
+ normal $vp
+ call assert_equal('x', @")
+ call assert_equal('x', @-)
+ call assert_equal('fooxxx', getline(1))
+ " Test with a different register as unnamed register.
+ call setline(2, ['baz'])
+ normal 2gg0"rD
+ call assert_equal('baz', @")
+ normal gg0vp
+ call assert_equal('f', @")
+ call assert_equal('f', @-)
+ call assert_equal('bazooxxx', getline(1))
+ normal $vp
+ call assert_equal('x', @")
+ call assert_equal('x', @-)
+ call assert_equal('bazooxxf', getline(1))
+
+ bwipe!
+endfunc
+
+func Test_visual_paste_clipboard()
+ CheckFeature clipboard_working
+
+ if has('gui')
+ " auto select feature breaks tests
+ set guioptions-=a
+ endif
+
+ " v_P does not overwrite unnamed register.
+ call setline(1, ['xxxx'])
+ call setreg('"', 'foo')
+ call setreg('-', 'bar')
+ normal gg0vP
+ call assert_equal('foo', @")
+ call assert_equal('bar', @-)
+ call assert_equal('fooxxx', getline(1))
+ normal $vP
+ call assert_equal('foo', @")
+ call assert_equal('bar', @-)
+ call assert_equal('fooxxfoo', getline(1))
+ " Test with a different register as unnamed register.
+ call setline(2, ['baz'])
+ normal 2gg0"rD
+ call assert_equal('baz', @")
+ normal gg0vP
+ call assert_equal('baz', @")
+ call assert_equal('bar', @-)
+ call assert_equal('bazooxxfoo', getline(1))
+ normal $vP
+ call assert_equal('baz', @")
+ call assert_equal('bar', @-)
+ call assert_equal('bazooxxfobaz', getline(1))
+
+ " Test for unnamed clipboard
+ set clipboard=unnamed
+ call setline(1, ['xxxx'])
+ call setreg('"', 'foo')
+ call setreg('-', 'bar')
+ call setreg('*', 'baz')
+ normal gg0vP
+ call assert_equal('foo', @")
+ call assert_equal('bar', @-)
+ call assert_equal('baz', @*)
+ call assert_equal('bazxxx', getline(1))
+
+ " Test for unnamedplus clipboard
+ if has('unnamedplus')
+ set clipboard=unnamedplus
+ call setline(1, ['xxxx'])
+ call setreg('"', 'foo')
+ call setreg('-', 'bar')
+ call setreg('+', 'baz')
+ normal gg0vP
+ call assert_equal('foo', @")
+ call assert_equal('bar', @-)
+ call assert_equal('baz', @+)
+ call assert_equal('bazxxx', getline(1))
+ endif
+
+ set clipboard&
+ if has('gui')
+ set guioptions&
+ endif
+ bwipe!
+endfunc
+
+func Test_visual_area_adjusted_when_hiding()
+ " The Visual area ended after the end of the line after :hide
+ call setline(1, 'xxx')
+ vsplit Xfile
+ call setline(1, 'xxxxxxxx')
+ norm! $o
+ hid
+ norm! zW
+ bwipe!
+ bwipe!
endfunc
diff --git a/src/nvim/testdir/test_winbuf_close.vim b/src/nvim/testdir/test_winbuf_close.vim
index 7f5b80e8d3..f4878c2397 100644
--- a/src/nvim/testdir/test_winbuf_close.vim
+++ b/src/nvim/testdir/test_winbuf_close.vim
@@ -194,3 +194,22 @@ func Test_tabwin_close()
call assert_true(v:true)
%bwipe!
endfunc
+
+" Test when closing a split window (above/below) restores space to the window
+" below when 'noequalalways' and 'splitright' are set.
+func Test_window_close_splitright_noequalalways()
+ set noequalalways
+ set splitright
+ new
+ let w1 = win_getid()
+ new
+ let w2 = win_getid()
+ execute "normal \<c-w>b"
+ let h = winheight(0)
+ let w = win_getid()
+ new
+ q
+ call assert_equal(h, winheight(0), "Window height does not match eight before opening and closing another window")
+ call assert_equal(w, win_getid(), "Did not return to original window after opening and closing a window")
+endfunc
+
diff --git a/src/nvim/testdir/test_window_cmd.vim b/src/nvim/testdir/test_window_cmd.vim
index a200bf7d42..7decac2c36 100644
--- a/src/nvim/testdir/test_window_cmd.vim
+++ b/src/nvim/testdir/test_window_cmd.vim
@@ -34,7 +34,16 @@ func Test_window_cmd_cmdwin_with_vsp()
set ls&vim
endfunc
-function Test_window_cmd_wincmd_gf()
+" Test for jumping to windows
+func Test_window_jump()
+ new
+ " jumping to a window with a count greater than the max windows
+ exe "normal 4\<C-W>w"
+ call assert_equal(2, winnr())
+ only
+endfunc
+
+func Test_window_cmd_wincmd_gf()
let fname = 'test_gf.txt'
let swp_fname = '.' . fname . '.swp'
call writefile([], fname)
@@ -172,6 +181,35 @@ func Test_window_split_edit_bufnr()
%bw!
endfunc
+func Test_window_split_no_room()
+ " N horizontal windows need >= 2*N + 1 lines:
+ " - 1 line + 1 status line in each window
+ " - 1 Ex command line
+ "
+ " 2*N + 1 <= &lines
+ " N <= (lines - 1)/2
+ "
+ " Beyond that number of windows, E36: Not enough room is expected.
+ let hor_win_count = (&lines - 1)/2
+ let hor_split_count = hor_win_count - 1
+ for s in range(1, hor_split_count) | split | endfor
+ call assert_fails('split', 'E36:')
+
+ " N vertical windows need >= 2*(N - 1) + 1 columns:
+ " - 1 column + 1 separator for each window (except last window)
+ " - 1 column for the last window which does not have separator
+ "
+ " 2*(N - 1) + 1 <= &columns
+ " 2*N - 1 <= &columns
+ " N <= (&columns + 1)/2
+ let ver_win_count = (&columns + 1)/2
+ let ver_split_count = ver_win_count - 1
+ for s in range(1, ver_split_count) | vsplit | endfor
+ call assert_fails('vsplit', 'E36:')
+
+ %bw!
+endfunc
+
func Test_window_exchange()
e Xa
@@ -513,14 +551,15 @@ func Test_window_colon_command()
endfunc
func Test_access_freed_mem()
+ call assert_equal(&columns, winwidth(0))
" This was accessing freed memory (but with what events?)
au BufEnter,BufLeave,WinEnter,WinLeave 0 vs xxx
arg 0
argadd
- all
- all
+ call assert_fails("all", "E242:")
au!
bwipe xxx
+ call assert_equal(&columns, winwidth(0))
endfunc
func Test_visual_cleared_after_window_split()
@@ -575,7 +614,7 @@ func Test_winrestcmd()
only
endfunc
-function! Fun_RenewFile()
+func Fun_RenewFile()
" Need to wait a bit for the timestamp to be older.
let old_ftime = getftime("tmp.txt")
while getftime("tmp.txt") == old_ftime
@@ -585,7 +624,7 @@ function! Fun_RenewFile()
sp
wincmd p
edit! tmp.txt
-endfunction
+endfunc
func Test_window_prevwin()
" Can we make this work on MS-Windows?
@@ -611,7 +650,7 @@ func Test_window_prevwin()
" reset
q
call delete('tmp.txt')
- set nohidden autoread&vim
+ set hidden&vim autoread&vim
delfunc Fun_RenewFile
endfunc
@@ -885,7 +924,157 @@ func Test_floatwin_splitmove()
bwipe
endfunc
+" Test for the :only command
+func Test_window_only()
+ new
+ set modified
+ new
+ call assert_fails('only', 'E445:')
+ only!
+ " Test for :only with a count
+ let wid = win_getid()
+ new
+ new
+ 3only
+ call assert_equal(1, winnr('$'))
+ call assert_equal(wid, win_getid())
+ call assert_fails('close', 'E444:')
+ call assert_fails('%close', 'E16:')
+endfunc
+
+" Test for errors with :wincmd
+func Test_wincmd_errors()
+ call assert_fails('wincmd g', 'E474:')
+ call assert_fails('wincmd ab', 'E474:')
+endfunc
+
+" Test for errors with :winpos
+func Test_winpos_errors()
+ throw 'Skipped: Nvim does not have :winpos'
+ if !has("gui_running") && !has('win32')
+ call assert_fails('winpos', 'E188:')
+ endif
+ call assert_fails('winpos 10', 'E466:')
+endfunc
+
+" Test for +cmd in a :split command
+func Test_split_cmd()
+ split +set\ readonly
+ call assert_equal(1, &readonly)
+ call assert_equal(2, winnr('$'))
+ close
+endfunc
+
+" Create maximum number of horizontally or vertically split windows and then
+" run commands that create a new horizontally/vertically split window
+func Run_noroom_for_newwindow_test(dir_arg)
+ let dir = (a:dir_arg == 'v') ? 'vert ' : ''
+
+ " Open as many windows as possible
+ for i in range(500)
+ try
+ exe dir . 'new'
+ catch /E36:/
+ break
+ endtry
+ endfor
+
+ call writefile(['first', 'second', 'third'], 'Xfile1')
+ call writefile([], 'Xfile2')
+ call writefile([], 'Xfile3')
+
+ " Argument list related commands
+ args Xfile1 Xfile2 Xfile3
+ next
+ for cmd in ['sargument 2', 'snext', 'sprevious', 'sNext', 'srewind',
+ \ 'sfirst', 'slast']
+ call assert_fails(dir .. cmd, 'E36:')
+ endfor
+ %argdelete
+
+ " Buffer related commands
+ set modified
+ hide enew
+ for cmd in ['sbuffer Xfile1', 'sbnext', 'sbprevious', 'sbNext', 'sbrewind',
+ \ 'sbfirst', 'sblast', 'sball', 'sbmodified', 'sunhide']
+ call assert_fails(dir .. cmd, 'E36:')
+ endfor
+
+ " Window related commands
+ for cmd in ['split', 'split Xfile2', 'new', 'new Xfile3', 'sview Xfile1',
+ \ 'sfind runtest.vim']
+ call assert_fails(dir .. cmd, 'E36:')
+ endfor
+
+ " Help
+ call assert_fails(dir .. 'help', 'E36:')
+ call assert_fails(dir .. 'helpgrep window', 'E36:')
+
+ " Command-line window
+ if a:dir_arg == 'h'
+ " Cmd-line window is always a horizontally split window
+ call assert_beeps('call feedkeys("q:\<CR>", "xt")')
+ endif
+
+ " Quickfix and location list window
+ if has('quickfix')
+ cexpr ''
+ call assert_fails(dir .. 'copen', 'E36:')
+ lexpr ''
+ call assert_fails(dir .. 'lopen', 'E36:')
+
+ " Preview window
+ call assert_fails(dir .. 'pedit Xfile2', 'E36:')
+ call setline(1, 'abc')
+ call assert_fails(dir .. 'psearch abc', 'E36:')
+ endif
+
+ " Window commands (CTRL-W ^ and CTRL-W f)
+ if a:dir_arg == 'h'
+ call assert_fails('call feedkeys("\<C-W>^", "xt")', 'E36:')
+ call setline(1, 'Xfile1')
+ call assert_fails('call feedkeys("gg\<C-W>f", "xt")', 'E36:')
+ endif
+ enew!
+
+ " Tag commands (:stag, :stselect and :stjump)
+ call writefile(["!_TAG_FILE_ENCODING\tutf-8\t//",
+ \ "second\tXfile1\t2",
+ \ "third\tXfile1\t3",],
+ \ 'Xtags')
+ set tags=Xtags
+ call assert_fails(dir .. 'stag second', 'E36:')
+ call assert_fails('call feedkeys(":" .. dir .. "stselect second\n1\n", "xt")', 'E36:')
+ call assert_fails(dir .. 'stjump second', 'E36:')
+ call assert_fails(dir .. 'ptag second', 'E36:')
+ set tags&
+ call delete('Xtags')
+
+ " :isplit and :dsplit
+ call setline(1, ['#define FOO 1', 'FOO'])
+ normal 2G
+ call assert_fails(dir .. 'isplit FOO', 'E36:')
+ call assert_fails(dir .. 'dsplit FOO', 'E36:')
+
+ " terminal
+ if has('terminal')
+ call assert_fails(dir .. 'terminal', 'E36:')
+ endif
+
+ %bwipe!
+ call delete('Xfile1')
+ call delete('Xfile2')
+ call delete('Xfile3')
+ only
+endfunc
+
+func Test_split_cmds_with_no_room()
+ call Run_noroom_for_newwindow_test('h')
+ call Run_noroom_for_newwindow_test('v')
+endfunc
+
func Test_window_resize()
+ throw 'Skipped: Nvim supports cmdheight=0'
" Vertical :resize (absolute, relative, min and max size).
vsplit
vert resize 8
@@ -939,4 +1128,304 @@ func Test_window_resize()
%bwipe!
endfunc
+" Test for adjusting the window width when a window is closed with some
+" windows using 'winfixwidth'
+func Test_window_width_adjust()
+ only
+ " Three vertical windows. Windows 1 and 2 have 'winfixwidth' set and close
+ " window 2.
+ wincmd v
+ vert resize 10
+ set winfixwidth
+ wincmd v
+ set winfixwidth
+ wincmd c
+ call assert_inrange(10, 12, winwidth(1))
+ " Three vertical windows. Windows 2 and 3 have 'winfixwidth' set and close
+ " window 3.
+ only
+ set winfixwidth
+ wincmd v
+ vert resize 10
+ set winfixwidth
+ wincmd v
+ set nowinfixwidth
+ wincmd b
+ wincmd c
+ call assert_inrange(10, 12, winwidth(2))
+
+ new | only
+endfunc
+
+" Test for jumping to a vertical/horizontal neighbor window based on the
+" current cursor position
+func Test_window_goto_neightbor()
+ %bw!
+
+ " Vertical window movement
+
+ " create the following window layout:
+ " +--+--+
+ " |w1|w3|
+ " +--+ |
+ " |w2| |
+ " +--+--+
+ " |w4 |
+ " +-----+
+ new
+ vsplit
+ split
+ " vertically jump from w4
+ wincmd b
+ call setline(1, repeat(' ', &columns))
+ call cursor(1, 1)
+ wincmd k
+ call assert_equal(2, winnr())
+ wincmd b
+ call cursor(1, &columns)
+ redraw!
+ wincmd k
+ call assert_equal(3, winnr())
+ %bw!
+
+ " create the following window layout:
+ " +--+--+--+
+ " |w1|w2|w3|
+ " +--+--+--+
+ " |w4 |
+ " +--------+
+ new
+ vsplit
+ vsplit
+ wincmd b
+ call setline(1, repeat(' ', &columns))
+ call cursor(1, 1)
+ wincmd k
+ call assert_equal(1, winnr())
+ wincmd b
+ call cursor(1, &columns / 2)
+ redraw!
+ wincmd k
+ call assert_equal(2, winnr())
+ wincmd b
+ call cursor(1, &columns)
+ redraw!
+ wincmd k
+ call assert_equal(3, winnr())
+ %bw!
+
+ " Horizontal window movement
+
+ " create the following window layout:
+ " +--+--+--+
+ " |w1|w2|w4|
+ " +--+--+ |
+ " |w3 | |
+ " +-----+--+
+ vsplit
+ split
+ vsplit
+ 4wincmd l
+ call setline(1, repeat([' '], &lines))
+ call cursor(1, 1)
+ redraw!
+ wincmd h
+ call assert_equal(2, winnr())
+ 4wincmd l
+ call cursor(&lines, 1)
+ redraw!
+ wincmd h
+ call assert_equal(3, winnr())
+ %bw!
+
+ " create the following window layout:
+ " +--+--+
+ " |w1|w4|
+ " +--+ +
+ " |w2| |
+ " +--+ +
+ " |w3| |
+ " +--+--+
+ vsplit
+ split
+ split
+ wincmd l
+ call setline(1, repeat([' '], &lines))
+ call cursor(1, 1)
+ redraw!
+ wincmd h
+ call assert_equal(1, winnr())
+ wincmd l
+ call cursor(&lines / 2, 1)
+ redraw!
+ wincmd h
+ call assert_equal(2, winnr())
+ wincmd l
+ call cursor(&lines, 1)
+ redraw!
+ wincmd h
+ call assert_equal(3, winnr())
+ %bw!
+endfunc
+
+" Test for an autocmd closing the destination window when jumping from one
+" window to another.
+func Test_close_dest_window()
+ split
+ edit Xfile
+
+ " Test for BufLeave
+ augroup T1
+ au!
+ au BufLeave Xfile $wincmd c
+ augroup END
+ wincmd b
+ call assert_equal(1, winnr('$'))
+ call assert_equal('Xfile', @%)
+ augroup T1
+ au!
+ augroup END
+
+ " Test for WinLeave
+ new
+ wincmd p
+ augroup T1
+ au!
+ au WinLeave * 1wincmd c
+ augroup END
+ wincmd t
+ call assert_equal(1, winnr('$'))
+ call assert_equal('Xfile', @%)
+ augroup T1
+ au!
+ augroup END
+ augroup! T1
+ %bw!
+endfunc
+
+func Test_win_move_separator()
+ edit a
+ leftabove vsplit b
+ let w = winwidth(0)
+ " check win_move_separator from left window on left window
+ call assert_equal(1, winnr())
+ for offset in range(5)
+ call assert_true(win_move_separator(0, offset))
+ call assert_equal(w + offset, winwidth(0))
+ call assert_true(0->win_move_separator(-offset))
+ call assert_equal(w, winwidth(0))
+ endfor
+ " check win_move_separator from right window on left window number
+ wincmd l
+ call assert_notequal(1, winnr())
+ for offset in range(5)
+ call assert_true(1->win_move_separator(offset))
+ call assert_equal(w + offset, winwidth(1))
+ call assert_true(win_move_separator(1, -offset))
+ call assert_equal(w, winwidth(1))
+ endfor
+ " check win_move_separator from right window on left window ID
+ let id = win_getid(1)
+ for offset in range(5)
+ call assert_true(win_move_separator(id, offset))
+ call assert_equal(w + offset, winwidth(id))
+ call assert_true(id->win_move_separator(-offset))
+ call assert_equal(w, winwidth(id))
+ endfor
+ " check win_move_separator from right window on right window is no-op
+ let w0 = winwidth(0)
+ call assert_true(win_move_separator(0, 1))
+ 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})
+ let w = winwidth(id)
+ call assert_false(win_move_separator(id, 1))
+ call assert_equal(w, winwidth(id))
+ call nvim_win_close(id, 1)
+ %bwipe!
+endfunc
+
+func Test_win_move_statusline()
+ redraw " This test fails in Nvim without a redraw to clear messages.
+ edit a
+ leftabove split b
+ let h = winheight(0)
+ " check win_move_statusline from top window on top window
+ call assert_equal(1, winnr())
+ for offset in range(5)
+ call assert_true(win_move_statusline(0, offset))
+ call assert_equal(h + offset, winheight(0))
+ call assert_true(0->win_move_statusline(-offset))
+ call assert_equal(h, winheight(0))
+ endfor
+ " check win_move_statusline from bottom window on top window number
+ wincmd j
+ call assert_notequal(1, winnr())
+ for offset in range(5)
+ call assert_true(1->win_move_statusline(offset))
+ call assert_equal(h + offset, winheight(1))
+ call assert_true(win_move_statusline(1, -offset))
+ call assert_equal(h, winheight(1))
+ endfor
+ " check win_move_statusline from bottom window on bottom window
+ let h0 = winheight(0)
+ for offset in range(5)
+ call assert_true(0->win_move_statusline(-offset))
+ call assert_equal(h0 - offset, winheight(0))
+ call assert_equal(1 + offset, &cmdheight)
+ call assert_true(win_move_statusline(0, offset))
+ call assert_equal(h0, winheight(0))
+ call assert_equal(1, &cmdheight)
+ endfor
+ " Nvim supports cmdheight=0
+ set cmdheight=0
+ call assert_true(win_move_statusline(0, 1))
+ "call assert_equal(h0, winheight(0))
+ "call assert_equal(1, &cmdheight)
+ call assert_equal(h0 + 1, winheight(0))
+ call assert_equal(0, &cmdheight)
+ set cmdheight&
+ " check win_move_statusline from bottom window on top window ID
+ let id = win_getid(1)
+ for offset in range(5)
+ call assert_true(win_move_statusline(id, offset))
+ call assert_equal(h + offset, winheight(id))
+ 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})
+ let h = winheight(id)
+ call assert_false(win_move_statusline(id, 1))
+ call assert_equal(h, winheight(id))
+ call nvim_win_close(id, 1)
+ %bwipe!
+endfunc
+
" vim: shiftwidth=2 sts=2 expandtab
diff --git a/src/nvim/testdir/test_writefile.vim b/src/nvim/testdir/test_writefile.vim
index aa7882d129..bfbba1f793 100644
--- a/src/nvim/testdir/test_writefile.vim
+++ b/src/nvim/testdir/test_writefile.vim
@@ -43,7 +43,7 @@ func Test_writefile_fails_gently()
endfunc
func Test_writefile_fails_conversion()
- if !has('iconv') || system('uname -s') =~ 'SunOS'
+ if !has('iconv') || has('sun')
return
endif
" Without a backup file the write won't happen if there is a conversion
@@ -169,9 +169,7 @@ endfunc
" Test for ':w !<cmd>' to pipe lines from the current buffer to an external
" command.
func Test_write_pipe_to_cmd()
- if !has('unix')
- return
- endif
+ CheckUnix
new
call setline(1, ['L1', 'L2', 'L3', 'L4'])
2,3w !cat > Xfile
@@ -208,6 +206,8 @@ func Test_write_errors()
call assert_fails('1,2write', 'E140:')
close!
+ call assert_fails('w > Xtest', 'E494:')
+
" Try to overwrite a directory
if has('unix')
call mkdir('Xdir1')
@@ -371,6 +371,154 @@ func Test_write_file_encoding()
%bw!
endfunc
+" Test for writing and reading a file starting with a BOM.
+" Byte Order Mark (BOM) character for various encodings is below:
+" UTF-8 : EF BB BF
+" UTF-16 (BE): FE FF
+" UTF-16 (LE): FF FE
+" UTF-32 (BE): 00 00 FE FF
+" UTF-32 (LE): FF FE 00 00
+func Test_readwrite_file_with_bom()
+ let utf8_bom = "\xEF\xBB\xBF"
+ let utf16be_bom = "\xFE\xFF"
+ let utf16le_bom = "\xFF\xFE"
+ let utf32be_bom = "\n\n\xFE\xFF"
+ let utf32le_bom = "\xFF\xFE\n\n"
+ let save_fileencoding = &fileencoding
+ set cpoptions+=S
+
+ " Check that editing a latin1 file doesn't see a BOM
+ call writefile(["\xFE\xFElatin-1"], 'Xtest1')
+ edit Xtest1
+ call assert_equal('latin1', &fileencoding)
+ call assert_equal(0, &bomb)
+ set fenc=latin1
+ write Xfile2
+ call assert_equal(["\xFE\xFElatin-1", ''], readfile('Xfile2', 'b'))
+ set bomb fenc=latin1
+ write Xtest3
+ call assert_equal(["\xFE\xFElatin-1", ''], readfile('Xtest3', 'b'))
+ set bomb&
+
+ " Check utf-8 BOM
+ %bw!
+ call writefile([utf8_bom .. "utf-8"], 'Xtest1')
+ edit! Xtest1
+ call assert_equal('utf-8', &fileencoding)
+ call assert_equal(1, &bomb)
+ call assert_equal('utf-8', getline(1))
+ set fenc=latin1
+ write! Xfile2
+ call assert_equal(['utf-8', ''], readfile('Xfile2', 'b'))
+ set fenc=utf-8
+ w! Xtest3
+ call assert_equal([utf8_bom .. "utf-8", ''], readfile('Xtest3', 'b'))
+
+ " Check utf-8 with an error (will fall back to latin-1)
+ %bw!
+ call writefile([utf8_bom .. "utf-8\x80err"], 'Xtest1')
+ edit! Xtest1
+ call assert_equal('latin1', &fileencoding)
+ call assert_equal(0, &bomb)
+ call assert_equal("\xC3\xAF\xC2\xBB\xC2\xBFutf-8\xC2\x80err", getline(1))
+ set fenc=latin1
+ write! Xfile2
+ call assert_equal([utf8_bom .. "utf-8\x80err", ''], readfile('Xfile2', 'b'))
+ set fenc=utf-8
+ w! Xtest3
+ call assert_equal(["\xC3\xAF\xC2\xBB\xC2\xBFutf-8\xC2\x80err", ''],
+ \ readfile('Xtest3', 'b'))
+
+ " Check ucs-2 BOM
+ %bw!
+ call writefile([utf16be_bom .. "\nu\nc\ns\n-\n2\n"], 'Xtest1')
+ edit! Xtest1
+ call assert_equal('utf-16', &fileencoding)
+ call assert_equal(1, &bomb)
+ call assert_equal('ucs-2', getline(1))
+ set fenc=latin1
+ write! Xfile2
+ call assert_equal(["ucs-2", ''], readfile('Xfile2', 'b'))
+ set fenc=ucs-2
+ w! Xtest3
+ call assert_equal([utf16be_bom .. "\nu\nc\ns\n-\n2\n", ''],
+ \ readfile('Xtest3', 'b'))
+
+ " Check ucs-2le BOM
+ %bw!
+ call writefile([utf16le_bom .. "u\nc\ns\n-\n2\nl\ne\n"], 'Xtest1')
+ " Need to add a NUL byte after the NL byte
+ call writefile(0z00, 'Xtest1', 'a')
+ edit! Xtest1
+ call assert_equal('utf-16le', &fileencoding)
+ call assert_equal(1, &bomb)
+ call assert_equal('ucs-2le', getline(1))
+ set fenc=latin1
+ write! Xfile2
+ call assert_equal(["ucs-2le", ''], readfile('Xfile2', 'b'))
+ set fenc=ucs-2le
+ w! Xtest3
+ call assert_equal([utf16le_bom .. "u\nc\ns\n-\n2\nl\ne\n", "\n"],
+ \ readfile('Xtest3', 'b'))
+
+ " Check ucs-4 BOM
+ %bw!
+ call writefile([utf32be_bom .. "\n\n\nu\n\n\nc\n\n\ns\n\n\n-\n\n\n4\n\n\n"], 'Xtest1')
+ edit! Xtest1
+ call assert_equal('ucs-4', &fileencoding)
+ call assert_equal(1, &bomb)
+ call assert_equal('ucs-4', getline(1))
+ set fenc=latin1
+ write! Xfile2
+ call assert_equal(["ucs-4", ''], readfile('Xfile2', 'b'))
+ set fenc=ucs-4
+ w! Xtest3
+ call assert_equal([utf32be_bom .. "\n\n\nu\n\n\nc\n\n\ns\n\n\n-\n\n\n4\n\n\n", ''], readfile('Xtest3', 'b'))
+
+ " Check ucs-4le BOM
+ %bw!
+ call writefile([utf32le_bom .. "u\n\n\nc\n\n\ns\n\n\n-\n\n\n4\n\n\nl\n\n\ne\n\n\n"], 'Xtest1')
+ " Need to add three NUL bytes after the NL byte
+ call writefile(0z000000, 'Xtest1', 'a')
+ edit! Xtest1
+ call assert_equal('ucs-4le', &fileencoding)
+ call assert_equal(1, &bomb)
+ call assert_equal('ucs-4le', getline(1))
+ set fenc=latin1
+ write! Xfile2
+ call assert_equal(["ucs-4le", ''], readfile('Xfile2', 'b'))
+ set fenc=ucs-4le
+ w! Xtest3
+ call assert_equal([utf32le_bom .. "u\n\n\nc\n\n\ns\n\n\n-\n\n\n4\n\n\nl\n\n\ne\n\n\n", "\n\n\n"], readfile('Xtest3', 'b'))
+
+ set cpoptions-=S
+ let &fileencoding = save_fileencoding
+ call delete('Xtest1')
+ call delete('Xfile2')
+ call delete('Xtest3')
+ %bw!
+endfunc
+
+func Test_read_write_bin()
+ " write file missing EOL
+ call writefile(['noeol'], "XNoEolSetEol", 'bS')
+ call assert_equal(0z6E6F656F6C, readfile('XNoEolSetEol', 'B'))
+
+ " when file is read 'eol' is off
+ set nofixeol
+ e! ++ff=unix XNoEolSetEol
+ call assert_equal(0, &eol)
+
+ " writing with 'eol' set adds the newline
+ setlocal eol
+ w
+ call assert_equal(0z6E6F656F6C0A, readfile('XNoEolSetEol', 'B'))
+
+ call delete('XNoEolSetEol')
+ set ff&
+ bwipe! XNoEolSetEol
+endfunc
+
" Check that buffer is written before triggering QuitPre
func Test_wq_quitpre_autocommand()
edit Xsomefile