From fe8ebdbe5c4e116311c0c0d5937b89ded5c92d01 Mon Sep 17 00:00:00 2001 From: Dominique Pelle Date: Thu, 13 May 2021 14:55:55 +0200 Subject: [PATCH 01/26] patch 8.2.2848: crash whn calling partial MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Problem: Crash whn calling partial. Solution: Check for NULL pointer. (Dominique Pellé, closes #8202) --- src/eval.c | 11 +++++++---- src/evalfunc.c | 8 ++++---- src/testdir/test_functions.vim | 4 ++++ src/testdir/test_listdict.vim | 1 + src/version.c | 2 ++ 5 files changed, 18 insertions(+), 8 deletions(-) diff --git a/src/eval.c b/src/eval.c index aa3d0a1ec8..0d4f5fe59c 100644 --- a/src/eval.c +++ b/src/eval.c @@ -4284,10 +4284,13 @@ eval_index_inner( char_u * partial_name(partial_T *pt) { - if (pt->pt_name != NULL) - return pt->pt_name; - if (pt->pt_func != NULL) - return pt->pt_func->uf_name; + if (pt != NULL) + { + if (pt->pt_name != NULL) + return pt->pt_name; + if (pt->pt_func != NULL) + return pt->pt_func->uf_name; + } return (char_u *)""; } diff --git a/src/evalfunc.c b/src/evalfunc.c index 6a2244961e..e740f91b13 100644 --- a/src/evalfunc.c +++ b/src/evalfunc.c @@ -1971,7 +1971,7 @@ internal_func_name(int idx) } /* - * Check the argument types for builting function "idx". + * Check the argument types for builtin function "idx". * Uses the list of types on the type stack: "types". * Return FAIL and gives an error message when a type is wrong. */ @@ -2475,8 +2475,8 @@ f_call(typval_T *argvars, typval_T *rettv) } else func = tv_get_string(&argvars[0]); - if (*func == NUL) - return; // type error or empty name + if (func == NULL || *func == NUL) + return; // type error, empty name or null function if (argvars[2].v_type != VAR_UNKNOWN) { @@ -2779,7 +2779,7 @@ f_cosh(typval_T *argvars, typval_T *rettv) /* * Set the cursor position. - * If 'charcol' is TRUE, then use the column number as a character offet. + * If 'charcol' is TRUE, then use the column number as a character offset. * Otherwise use the column number as a byte offset. */ static void diff --git a/src/testdir/test_functions.vim b/src/testdir/test_functions.vim index 936a2d0609..f675697772 100644 --- a/src/testdir/test_functions.vim +++ b/src/testdir/test_functions.vim @@ -2150,6 +2150,10 @@ func Test_call() eval mydict.len->call([], mydict)->assert_equal(4) call assert_fails("call call('Mylen', [], 0)", 'E715:') call assert_fails('call foo', 'E107:') + + " This once caused a crash. + call call(test_null_function(), []) + call call(test_null_partial(), []) endfunc func Test_char2nr() diff --git a/src/testdir/test_listdict.vim b/src/testdir/test_listdict.vim index 1b0796d816..601dd17e5e 100644 --- a/src/testdir/test_listdict.vim +++ b/src/testdir/test_listdict.vim @@ -743,6 +743,7 @@ func Test_reduce() " should not crash call assert_fails('echo reduce([1], test_null_function())', 'E1132:') + call assert_fails('echo reduce([1], test_null_partial())', 'E1132:') endfunc " splitting a string to a List using split() diff --git a/src/version.c b/src/version.c index f1f2a1cc2e..3fdb588358 100644 --- a/src/version.c +++ b/src/version.c @@ -750,6 +750,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 2848, /**/ 2847, /**/ From 36f96a515109dc1fad279571a645c0f0d65f2de4 Mon Sep 17 00:00:00 2001 From: Yegappan Lakshmanan Date: Thu, 13 May 2021 18:33:16 +0200 Subject: [PATCH 02/26] patch 8.2.2849: bufwrite not sufficiently tested Problem: Bufwrite not sufficiently tested. Solution: Add a few more tests. (Yegappan Lakshmanan, closes #8192) --- src/testdir/test_startup.vim | 15 +++ src/testdir/test_writefile.vim | 197 +++++++++++++++++++++++++++++++++ src/version.c | 2 + 3 files changed, 214 insertions(+) diff --git a/src/testdir/test_startup.vim b/src/testdir/test_startup.vim index 6e814704a1..1f14e86e3b 100644 --- a/src/testdir/test_startup.vim +++ b/src/testdir/test_startup.vim @@ -1270,4 +1270,19 @@ func Test_progname() call delete('Xprogname', 'd') endfunc +" Test for doing a write from .vimrc +func Test_write_in_vimrc() + call writefile(['silent! write'], 'Xvimrc') + let after =<< trim [CODE] + call assert_match('E32: ', v:errmsg) + call writefile(v:errors, 'Xtestout') + qall + [CODE] + if RunVim([], after, '-u Xvimrc') + call assert_equal([], readfile('Xtestout')) + call delete('Xtestout') + endif + call delete('Xvimrc') +endfunc + " vim: shiftwidth=2 sts=2 expandtab diff --git a/src/testdir/test_writefile.vim b/src/testdir/test_writefile.vim index 7256c65847..8470d4e302 100644 --- a/src/testdir/test_writefile.vim +++ b/src/testdir/test_writefile.vim @@ -58,7 +58,29 @@ func Test_writefile_fails_conversion() call assert_fails('write ++enc=cp932', 'E513:') call assert_equal(contents, readfile('Xfile')) + " With 'backupcopy' set, if there is a conversion error, the backup file is + " still created. + set backupcopy=yes writebackup& backup& + call delete('Xfile' .. &backupext) + call assert_fails('write ++enc=cp932', 'E513:') + call assert_equal(contents, readfile('Xfile')) + call assert_equal(contents, readfile('Xfile' .. &backupext)) + set backupcopy& + %bw! + + " Conversion error during write + new + call setline(1, ["\U10000000"]) + let output = execute('write! ++enc=utf-16 Xfile') + call assert_match('CONVERSION ERROR', output) + let output = execute('write! ++enc=ucs-2 Xfile') + call assert_match('CONVERSION ERROR', output) + call delete('Xfilz~') + call delete('Xfily~') + %bw! + call delete('Xfile') + call delete('Xfile' .. &backupext) bwipe! set backup& writebackup& backupdir&vim backupskip&vim endfunc @@ -257,6 +279,16 @@ func Test_write_errors() let long_fname = repeat('n', 5000) call assert_fails('exe "w " .. long_fname', 'E75:') call assert_fails('call writefile([], long_fname)', 'E482:') + + " Test for writing to a block device on Unix-like systems + if has('unix') && getfperm('/dev/loop0') != '' + \ && getftype('/dev/loop0') == 'bdev' && !IsRoot() + new + edit /dev/loop0 + call assert_fails('write', 'E505: ') + call assert_fails('write!', 'E503: ') + close! + endif endfunc " Test for writing to a file which is modified after Vim read it @@ -383,8 +415,21 @@ func Test_write_readonly() call setline(1, ['line1']) write! call assert_equal(['line1'], readfile('Xfile')) + + " Auto-saving a readonly file should fail with 'autowriteall' + %bw! + e Xfile + set noreadonly autowriteall + call setline(1, ['aaaa']) + call assert_fails('n', 'E505:') + set cpo+=W + call assert_fails('n', 'E504:') + set cpo-=W + set autowriteall& + set backupskip& call delete('Xfile') + %bw! endfunc " Test for 'patchmode' @@ -400,6 +445,19 @@ func Test_patchmode() " subsequent writes should not create/modify the .orig file write call assert_equal(['one'], readfile('Xfile.orig')) + + " use 'patchmode' with 'nobackup' and 'nowritebackup' to create an empty + " original file + call delete('Xfile') + call delete('Xfile.orig') + %bw! + set patchmode=.orig nobackup nowritebackup + edit Xfile + call setline(1, ['xxx']) + write + call assert_equal(['xxx'], readfile('Xfile')) + call assert_equal([], readfile('Xfile.orig')) + set patchmode& backup& backupskip& writebackup& call delete('Xfile') call delete('Xfile.orig') @@ -700,4 +758,143 @@ func Test_read_write_bin() bwipe! XNoEolSetEol endfunc +" Test for the 'backupcopy' option when writing files +func Test_backupcopy() + CheckUnix + set backupskip= + " With the default 'backupcopy' setting, saving a symbolic link file + " should not break the link. + set backupcopy& + call writefile(['1111'], 'Xfile1') + silent !ln -s Xfile1 Xfile2 + new Xfile2 + call setline(1, ['2222']) + write + close + call assert_equal(['2222'], readfile('Xfile1')) + call assert_equal('Xfile1', resolve('Xfile2')) + call assert_equal('link', getftype('Xfile2')) + call delete('Xfile1') + call delete('Xfile2') + + " With the 'backupcopy' set to 'breaksymlink', saving a symbolic link file + " should break the link. + set backupcopy=yes,breaksymlink + call writefile(['1111'], 'Xfile1') + silent !ln -s Xfile1 Xfile2 + new Xfile2 + call setline(1, ['2222']) + write + close + call assert_equal(['1111'], readfile('Xfile1')) + call assert_equal(['2222'], readfile('Xfile2')) + call assert_equal('Xfile2', resolve('Xfile2')) + call assert_equal('file', getftype('Xfile2')) + call delete('Xfile1') + call delete('Xfile2') + set backupcopy& + + " With the default 'backupcopy' setting, saving a hard link file + " should not break the link. + set backupcopy& + call writefile(['1111'], 'Xfile1') + silent !ln Xfile1 Xfile2 + new Xfile2 + call setline(1, ['2222']) + write + close + call assert_equal(['2222'], readfile('Xfile1')) + call delete('Xfile1') + call delete('Xfile2') + + " With the 'backupcopy' set to 'breaksymlink', saving a hard link file + " should break the link. + set backupcopy=yes,breakhardlink + call writefile(['1111'], 'Xfile1') + silent !ln Xfile1 Xfile2 + new Xfile2 + call setline(1, ['2222']) + write + call assert_equal(['1111'], readfile('Xfile1')) + call assert_equal(['2222'], readfile('Xfile2')) + call delete('Xfile1') + call delete('Xfile2') + + " If a backup file is already present, then a slightly modified filename + " should be used as the backup file. Try with 'backupcopy' set to 'yes' and + " 'no'. + %bw + call writefile(['aaaa'], 'Xfile') + call writefile(['bbbb'], 'Xfile.bak') + set backupcopy=yes backupext=.bak + new Xfile + call setline(1, ['cccc']) + write + close + call assert_equal(['cccc'], readfile('Xfile')) + call assert_equal(['bbbb'], readfile('Xfile.bak')) + set backupcopy=no backupext=.bak + new Xfile + call setline(1, ['dddd']) + write + close + call assert_equal(['dddd'], readfile('Xfile')) + call assert_equal(['bbbb'], readfile('Xfile.bak')) + call delete('Xfile') + call delete('Xfile.bak') + + " Write to a device file (in Unix-like systems) which cannot be backed up. + if has('unix') + set writebackup backupcopy=yes nobackup + new + call setline(1, ['aaaa']) + let output = execute('write! /dev/null') + call assert_match('"/dev/null" \[Device]', output) + close + set writebackup backupcopy=no nobackup + new + call setline(1, ['aaaa']) + let output = execute('write! /dev/null') + call assert_match('"/dev/null" \[Device]', output) + close + set backup writebackup& backupcopy& + new + call setline(1, ['aaaa']) + let output = execute('write! /dev/null') + call assert_match('"/dev/null" \[Device]', output) + close + endif + + set backupcopy& backupskip& backupext& backup& +endfunc + +" Test for writing a file with 'encoding' set to 'utf-16' +func Test_write_utf16() + new + call setline(1, ["\U00010001"]) + write ++enc=utf-16 Xfile + bw! + call assert_equal(0zD800DC01, readfile('Xfile', 'B')[0:3]) + call delete('Xfile') +endfunc + +" Test for trying to save a backup file when the backup file is a symbolic +" link to the original file. The backup file should not be modified. +func Test_write_backup_symlink() + CheckUnix + call writefile(['1111'], 'Xfile') + silent !ln -s Xfile Xfile.bak + + new Xfile + set backup backupcopy=yes backupext=.bak + write + call assert_equal('link', getftype('Xfile.bak')) + call assert_equal('Xfile', resolve('Xfile.bak')) + set backup& backupcopy& backupext& + close + + call delete('Xfile') + call delete('Xfile.bak') +endfunc + " vim: shiftwidth=2 sts=2 expandtab diff --git a/src/version.c b/src/version.c index 3fdb588358..5fcea886d6 100644 --- a/src/version.c +++ b/src/version.c @@ -750,6 +750,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 2849, /**/ 2848, /**/ From 71c6f7a665eb467054fbf319989d97c252af28d2 Mon Sep 17 00:00:00 2001 From: obcat Date: Thu, 13 May 2021 20:23:10 +0200 Subject: [PATCH 03/26] patch 8.2.2850: recalling commands from history is not tested Problem: Recalling commands from history is not tested. Solution: Add tests. (closes #8194) --- src/testdir/test_cmdline.vim | 48 ++++++++++++++++++++++++++++++++++++ src/version.c | 2 ++ 2 files changed, 50 insertions(+) diff --git a/src/testdir/test_cmdline.vim b/src/testdir/test_cmdline.vim index 531837b223..7df80b0330 100644 --- a/src/testdir/test_cmdline.vim +++ b/src/testdir/test_cmdline.vim @@ -1751,4 +1751,52 @@ func Test_wildmenu_dirstack() set wildmenu& endfunc +" Test for recalling newer or older cmdline from history with , , +" , , , , , or . +func Test_recalling_cmdline() + CheckFeature cmdline_hist + + let g:cmdlines = [] + cnoremap (save-cmdline) let g:cmdlines += [getcmdline()] + + let histories = [ + \ {'name': 'cmd', 'enter': ':', 'exit': "\"}, + \ {'name': 'search', 'enter': '/', 'exit': "\"}, + \ {'name': 'expr', 'enter': ":\=", 'exit': "\\"}, + \ {'name': 'input', 'enter': ":call input('')\", 'exit': "\"}, + "\ TODO: {'name': 'debug', ...} + \] + let keypairs = [ + \ {'older': "\", 'newer': "\", 'prefixmatch': v:true}, + \ {'older': "\", 'newer': "\", 'prefixmatch': v:false}, + \ {'older': "\", 'newer': "\", 'prefixmatch': v:false}, + \ {'older': "\", 'newer': "\", 'prefixmatch': v:false}, + \] + let prefix = 'vi' + for h in histories + call histadd(h.name, 'vim') + call histadd(h.name, 'virtue') + call histadd(h.name, 'Virgo') + call histadd(h.name, 'vogue') + call histadd(h.name, 'emacs') + for k in keypairs + let g:cmdlines = [] + let keyseqs = h.enter + \ .. prefix + \ .. repeat(k.older .. "\(save-cmdline)", 2) + \ .. repeat(k.newer .. "\(save-cmdline)", 2) + \ .. h.exit + call feedkeys(keyseqs, 'xt') + call histdel(h.name, -1) " delete the history added by feedkeys above + let expect = k.prefixmatch + \ ? ['virtue', 'vim', 'virtue', prefix] + \ : ['emacs', 'vogue', 'emacs', prefix] + call assert_equal(expect, g:cmdlines) + endfor + endfor + + unlet g:cmdlines + cunmap (save-cmdline) +endfunc + " vim: shiftwidth=2 sts=2 expandtab diff --git a/src/version.c b/src/version.c index 5fcea886d6..83c773f234 100644 --- a/src/version.c +++ b/src/version.c @@ -750,6 +750,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 2850, /**/ 2849, /**/ From 847fe7d750001a46a09b97ad57286612d0be8100 Mon Sep 17 00:00:00 2001 From: Bram Moolenaar Date: Sat, 15 May 2021 13:19:16 +0200 Subject: [PATCH 04/26] patch 8.2.2851: using mapping on the command line triggers CmdlineChanged Problem: Using mapping on the command line triggers CmdlineChanged. (Naohiro Ono) Solution: Jump to cmdline_not_changed if the command line didn't change. (closes #8208) --- src/ex_getln.c | 14 +++++++++++--- src/testdir/test_cmdline.vim | 19 +++++++++++++++++++ src/version.c | 2 ++ 3 files changed, 32 insertions(+), 3 deletions(-) diff --git a/src/ex_getln.c b/src/ex_getln.c index a9f33e6ec2..e87b208cc2 100644 --- a/src/ex_getln.c +++ b/src/ex_getln.c @@ -1757,9 +1757,17 @@ getcmdline_int( c = safe_vgetc(); } while (c == K_IGNORE || c == K_NOP); - if (c == K_COMMAND - && do_cmdline(NULL, getcmdkeycmd, NULL, DOCMD_NOWAIT) == OK) - goto cmdline_changed; + if (c == K_COMMAND) + { + int clen = ccline.cmdlen; + + if (do_cmdline(NULL, getcmdkeycmd, NULL, DOCMD_NOWAIT) == OK) + { + if (clen == ccline.cmdlen) + goto cmdline_not_changed; + goto cmdline_changed; + } + } if (KeyTyped) { diff --git a/src/testdir/test_cmdline.vim b/src/testdir/test_cmdline.vim index 7df80b0330..5ed283f1fa 100644 --- a/src/testdir/test_cmdline.vim +++ b/src/testdir/test_cmdline.vim @@ -1799,4 +1799,23 @@ func Test_recalling_cmdline() cunmap (save-cmdline) endfunc +func Test_cmd_map_cmdlineChanged() + let g:log = [] + cnoremap ls + augroup test + autocmd! + autocmd CmdlineChanged : let g:log += [getcmdline()] + augroup END + + call feedkeys(":\\", 'xt') + call assert_equal(['l', 'ls'], g:log) + + unlet g:log + cunmap + augroup test + autocmd! + augroup END +endfunc + + " vim: shiftwidth=2 sts=2 expandtab diff --git a/src/version.c b/src/version.c index 83c773f234..0d3c2ad52b 100644 --- a/src/version.c +++ b/src/version.c @@ -750,6 +750,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 2851, /**/ 2850, /**/ From 761ead497feff5fd259c9f6ca76d184bb8755373 Mon Sep 17 00:00:00 2001 From: Natanael Copa Date: Sat, 15 May 2021 14:25:37 +0200 Subject: [PATCH 05/26] patch 8.2.2852: configure can add --as-needed a second time Problem: Configure can add --as-needed a second time. Solution: Only add --as-needed if not already there. (Natanael Copa, closes #8189, closes #8181) --- src/auto/configure | 4 +++- src/configure.ac | 4 +++- src/version.c | 2 ++ 3 files changed, 8 insertions(+), 2 deletions(-) diff --git a/src/auto/configure b/src/auto/configure index 934b34c24e..0b423a6577 100755 --- a/src/auto/configure +++ b/src/auto/configure @@ -14937,7 +14937,9 @@ $as_echo_n "checking linker --as-needed support... " >&6; } LINK_AS_NEEDED= # Check if linker supports --as-needed and --no-as-needed options if $CC -Wl,--help 2>/dev/null | grep as-needed > /dev/null; then - LDFLAGS=`echo "$LDFLAGS" | sed -e 's/ *-Wl,--as-needed//g' | sed -e 's/$/ -Wl,--as-needed/'` + if ! echo "$LDFLAGS" | grep -q -- '-Wl,[^[:space:]]*--as-needed'; then + LDFLAGS="$LDFLAGS -Wl,--as-needed" + fi LINK_AS_NEEDED=yes fi if test "$LINK_AS_NEEDED" = yes; then diff --git a/src/configure.ac b/src/configure.ac index 657cc97f70..cc8d61f7f8 100644 --- a/src/configure.ac +++ b/src/configure.ac @@ -4519,7 +4519,9 @@ AC_MSG_CHECKING(linker --as-needed support) LINK_AS_NEEDED= # Check if linker supports --as-needed and --no-as-needed options if $CC -Wl,--help 2>/dev/null | grep as-needed > /dev/null; then - LDFLAGS=`echo "$LDFLAGS" | sed -e 's/ *-Wl,--as-needed//g' | sed -e 's/$/ -Wl,--as-needed/'` + if ! echo "$LDFLAGS" | grep -q -- '-Wl,[[^[:space:]]]*--as-needed'; then + LDFLAGS="$LDFLAGS -Wl,--as-needed" + fi LINK_AS_NEEDED=yes fi if test "$LINK_AS_NEEDED" = yes; then diff --git a/src/version.c b/src/version.c index 0d3c2ad52b..f7406eec77 100644 --- a/src/version.c +++ b/src/version.c @@ -750,6 +750,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 2852, /**/ 2851, /**/ From d832c3c56ec7043322ad3e99897e312700fa1d3e Mon Sep 17 00:00:00 2001 From: Bram Moolenaar Date: Sat, 15 May 2021 15:09:06 +0200 Subject: [PATCH 06/26] patch 8.2.2853: window is not updated after using mapping Problem: Window is not updated after using mapping. Solution: So jump to cmdline_changed but skip autocommand. --- src/ex_getln.c | 9 ++++++--- src/version.c | 2 ++ 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/src/ex_getln.c b/src/ex_getln.c index e87b208cc2..4ebc341109 100644 --- a/src/ex_getln.c +++ b/src/ex_getln.c @@ -1734,6 +1734,8 @@ getcmdline_int( */ for (;;) { + int trigger_cmdlinechanged = TRUE; + redir_off = TRUE; // Don't redirect the typed command. // Repeated, because a ":redir" inside // completion may switch it on. @@ -1764,7 +1766,7 @@ getcmdline_int( if (do_cmdline(NULL, getcmdkeycmd, NULL, DOCMD_NOWAIT) == OK) { if (clen == ccline.cmdlen) - goto cmdline_not_changed; + trigger_cmdlinechanged = FALSE; goto cmdline_changed; } } @@ -2380,8 +2382,9 @@ cmdline_changed: if (is_state.winid != curwin->w_id) init_incsearch_state(&is_state); #endif - // Trigger CmdlineChanged autocommands. - trigger_cmd_autocmd(cmdline_type, EVENT_CMDLINECHANGED); + if (trigger_cmdlinechanged) + // Trigger CmdlineChanged autocommands. + trigger_cmd_autocmd(cmdline_type, EVENT_CMDLINECHANGED); #ifdef FEAT_SEARCH_EXTRA if (xpc.xp_context == EXPAND_NOTHING) diff --git a/src/version.c b/src/version.c index f7406eec77..d04ebfbf7d 100644 --- a/src/version.c +++ b/src/version.c @@ -750,6 +750,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 2853, /**/ 2852, /**/ From 30e3de21fc36153c5f7c9cf9db90bcc60dd67fb9 Mon Sep 17 00:00:00 2001 From: shadmansaleh Date: Sat, 15 May 2021 17:23:28 +0200 Subject: [PATCH 07/26] patch 8.2.2854: custom statusline cannot contain % items Problem: Custom statusline cannot contain % items. Solution: Add "%{% expr %}". (closes #8190) --- runtime/doc/options.txt | 12 ++++++ src/buffer.c | 73 +++++++++++++++++++++++++++++++-- src/optionstr.c | 4 +- src/testdir/test_statusline.vim | 20 +++++++++ src/version.c | 2 + 5 files changed, 106 insertions(+), 5 deletions(-) diff --git a/runtime/doc/options.txt b/runtime/doc/options.txt index efab64802e..9cff98da74 100644 --- a/runtime/doc/options.txt +++ b/runtime/doc/options.txt @@ -7339,6 +7339,18 @@ A jump table for the options with a short description can be found at |Q_op|. Note that there is no '%' before the closing '}'. The expression cannot contain a '}' character, call a function to work around that. See |stl-%{| below. + {% - This is almost same as { except the result of the expression is + re-evaluated as a statusline format string. Thus if the + return value of expr contains % items they will get expanded. + The expression can contain the } character, the end of + expression is denoted by %}. + The For example: > + func! Stl_filename() abort + return "%t" + endfunc +< `stl=%{Stl_filename()}` results in `"%t"` + `stl=%{%Stl_filename()%}` results in `"Name of current file"` + } - End of `{%` expression ( - Start of item group. Can be used for setting the width and alignment of a section. Must be followed by %) somewhere. ) - End of item group. No width fields allowed. diff --git a/src/buffer.c b/src/buffer.c index f80d424943..d8b7ed4f23 100644 --- a/src/buffer.c +++ b/src/buffer.c @@ -27,6 +27,12 @@ #include "vim.h" + +#ifdef FEAT_EVAL +// Determines how deeply nested %{} blocks will be evaluated in statusline. +# define MAX_STL_EVAL_DEPTH 100 +#endif + static void enter_buffer(buf_T *buf); static void buflist_getfpos(void); static char_u *buflist_match(regmatch_T *rmp, buf_T *buf, int ignore_case); @@ -4113,6 +4119,9 @@ build_stl_str_hl( int group_end_userhl; int group_start_userhl; int groupdepth; +#ifdef FEAT_EVAL + int evaldepth; +#endif int minwid; int maxwid; int zeropad; @@ -4187,6 +4196,9 @@ build_stl_str_hl( byteval = (*mb_ptr2char)(p + wp->w_cursor.col); groupdepth = 0; +#ifdef FEAT_EVAL + evaldepth = 0; +#endif p = out; curitem = 0; prevchar_isflag = TRUE; @@ -4447,6 +4459,15 @@ build_stl_str_hl( curitem++; continue; } +#ifdef FEAT_EVAL + // Denotes end of expanded %{} block + if (*s == '}' && evaldepth > 0) + { + s++; + evaldepth--; + continue; + } +#endif if (vim_strchr(STL_ALL, *s) == NULL) { s++; @@ -4482,16 +4503,27 @@ build_stl_str_hl( break; case STL_VIM_EXPR: // '{' + { +#ifdef FEAT_EVAL + char_u *block_start = s - 1; +#endif + int reevaluate = (*s == '%'); + + if (reevaluate) + s++; itemisflag = TRUE; t = p; - while (*s != '}' && *s != NUL && p + 1 < out + outlen) + while ((*s != '}' || (reevaluate && s[-1] != '%')) + && *s != NUL && p + 1 < out + outlen) *p++ = *s++; if (*s != '}') // missing '}' or out of space break; s++; - *p = 0; + if (reevaluate) + p[-1] = 0; // remove the % at the end of %{% expr %} + else + *p = 0; p = t; - #ifdef FEAT_EVAL vim_snprintf((char *)buf_tmp, sizeof(buf_tmp), "%d", curbuf->b_fnum); @@ -4525,9 +4557,42 @@ build_stl_str_hl( itemisflag = FALSE; } } + + // If the output of the expression needs to be evaluated + // replace the %{} block with the result of evaluation + if (reevaluate && str != NULL && *str != 0 + && strchr((const char *)str, '%') != NULL + && evaldepth < MAX_STL_EVAL_DEPTH) + { + size_t parsed_usefmt = (size_t)(block_start - usefmt); + size_t str_length = strlen((const char *)str); + size_t fmt_length = strlen((const char *)s); + size_t new_fmt_len = parsed_usefmt + + str_length + fmt_length + 3; + char_u *new_fmt = (char_u *)alloc(new_fmt_len * sizeof(char_u)); + char_u *new_fmt_p = new_fmt; + + new_fmt_p = (char_u *)memcpy(new_fmt_p, usefmt, parsed_usefmt) + + parsed_usefmt; + new_fmt_p = (char_u *)memcpy(new_fmt_p , str, str_length) + + str_length; + new_fmt_p = (char_u *)memcpy(new_fmt_p, "%}", 2) + 2; + new_fmt_p = (char_u *)memcpy(new_fmt_p , s, fmt_length) + + fmt_length; + *new_fmt_p = 0; + new_fmt_p = NULL; + + if (usefmt != fmt) + vim_free(usefmt); + VIM_CLEAR(str); + usefmt = new_fmt; + s = usefmt + parsed_usefmt; + evaldepth++; + continue; + } #endif break; - + } case STL_LINE: num = (wp->w_buffer->b_ml.ml_flags & ML_EMPTY) ? 0L : (long)(wp->w_cursor.lnum); diff --git a/src/optionstr.c b/src/optionstr.c index 1ec8d05d6c..f332294ed8 100644 --- a/src/optionstr.c +++ b/src/optionstr.c @@ -618,8 +618,10 @@ check_stl_option(char_u *s) } if (*s == '{') { + int reevaluate = (*s == '%'); + s++; - while (*s != '}' && *s) + while ((*s != '}' || (reevaluate && s[-1] != '%')) && *s) s++; if (*s != '}') return N_("E540: Unclosed expression sequence"); diff --git a/src/testdir/test_statusline.vim b/src/testdir/test_statusline.vim index ca28379f5d..f3eea2e71e 100644 --- a/src/testdir/test_statusline.vim +++ b/src/testdir/test_statusline.vim @@ -251,6 +251,26 @@ func Test_statusline() call assert_match('^vimLineComment\s*$', s:get_statusline()) syntax off + "%{%expr%}: evaluates enxpressions present in result of expr + func! Inner_eval() + return '%n some other text' + endfunc + func! Outer_eval() + return 'some text %{%Inner_eval()%}' + endfunc + set statusline=%{%Outer_eval()%} + call assert_match('^some text ' . bufnr() . ' some other text\s*$', s:get_statusline()) + delfunc Inner_eval + delfunc Outer_eval + + "%{%expr%}: Doesn't get stuck in recursion + func! Recurse_eval() + return '%{%Recurse_eval()%}' + endfunc + set statusline=%{%Recurse_eval()%} + call assert_match('^%{%Recurse_eval()%}\s*$', s:get_statusline()) + delfunc Recurse_eval + "%(: Start of item group. set statusline=ab%(cd%q%)de call assert_match('^abde\s*$', s:get_statusline()) diff --git a/src/version.c b/src/version.c index d04ebfbf7d..7635c2f470 100644 --- a/src/version.c +++ b/src/version.c @@ -750,6 +750,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 2854, /**/ 2853, /**/ From 0820f4de5872bfbdc25bf6cba6ec5646dbcec156 Mon Sep 17 00:00:00 2001 From: Bram Moolenaar Date: Sat, 15 May 2021 20:06:58 +0200 Subject: [PATCH 08/26] patch 8.2.2855: white space after "->" does not give E274 Problem: White space after "->" does not give E274. Solution: Do not skip white space in legacy script. (closes #8212) --- src/eval.c | 12 ++++++++++-- src/testdir/test_method.vim | 3 ++- src/version.c | 2 ++ 3 files changed, 14 insertions(+), 3 deletions(-) diff --git a/src/eval.c b/src/eval.c index 0d4f5fe59c..97c5f78dff 100644 --- a/src/eval.c +++ b/src/eval.c @@ -5916,10 +5916,18 @@ handle_subscript( } else if (p[0] == '-' && p[1] == '>') { - *arg = skipwhite(p + 2); + if (in_vim9script()) + *arg = skipwhite(p + 2); + else + *arg = p + 2; if (ret == OK) { - if ((**arg == '{' && !in_vim9script()) || **arg == '(') + if (VIM_ISWHITE(**arg)) + { + emsg(_(e_nowhitespace)); + ret = FAIL; + } + else if ((**arg == '{' && !in_vim9script()) || **arg == '(') // expr->{lambda}() or expr->(lambda)() ret = eval_lambda(arg, rettv, evalarg, verbose); else diff --git a/src/testdir/test_method.vim b/src/testdir/test_method.vim index 262c08c79b..6b62d36209 100644 --- a/src/testdir/test_method.vim +++ b/src/testdir/test_method.vim @@ -131,11 +131,12 @@ func Test_method_syntax() eval [1, 2, 3] \ ->sort( \ ) - eval [1, 2, 3]-> sort() + eval [1, 2, 3]->sort() call assert_fails('eval [1, 2, 3]->sort ()', 'E274:') call assert_fails('eval [1, 2, 3] ->sort ()', 'E274:') call assert_fails('eval [1, 2, 3]-> sort ()', 'E274:') + call assert_fails('eval [1, 2, 3]-> sort()', 'E274:') endfunc func Test_method_lambda() diff --git a/src/version.c b/src/version.c index 7635c2f470..1aef3c7d38 100644 --- a/src/version.c +++ b/src/version.c @@ -750,6 +750,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 2855, /**/ 2854, /**/ From 50157ef1c2e36d8696e79fd688bdd08312196bc6 Mon Sep 17 00:00:00 2001 From: Bram Moolenaar Date: Sat, 15 May 2021 23:21:05 +0200 Subject: [PATCH 09/26] patch 8.2.2856: get readonly error for device that can't be written to Problem: Get readonly error for device that can't be written to. Solution: Check for being able to write first. (closes #8205) --- src/ex_cmds.c | 19 ++++++++++++++++++- src/testdir/test_writefile.vim | 2 +- src/version.c | 2 ++ 3 files changed, 21 insertions(+), 2 deletions(-) diff --git a/src/ex_cmds.c b/src/ex_cmds.c index 06109d57fb..e1497a5a4a 100644 --- a/src/ex_cmds.c +++ b/src/ex_cmds.c @@ -1856,6 +1856,19 @@ ex_write(exarg_T *eap) (void)do_write(eap); } +#ifdef UNIX + static int +check_writable(char_u *fname) +{ + if (mch_nodetype(fname) == NODE_OTHER) + { + semsg(_("E503: \"%s\" is not a file or writable device"), fname); + return FAIL; + } + return OK; +} +#endif + /* * write current buffer to file 'eap->arg' * if 'eap->append' is TRUE, append to the file @@ -1942,7 +1955,11 @@ do_write(exarg_T *eap) #ifdef FEAT_QUICKFIX bt_dontwrite_msg(curbuf) || #endif - check_fname() == FAIL || check_readonly(&eap->forceit, curbuf))) + check_fname() == FAIL +#ifdef UNIX + || check_writable(curbuf->b_ffname) == FAIL +#endif + || check_readonly(&eap->forceit, curbuf))) goto theend; if (!other) diff --git a/src/testdir/test_writefile.vim b/src/testdir/test_writefile.vim index 8470d4e302..75dda81d6d 100644 --- a/src/testdir/test_writefile.vim +++ b/src/testdir/test_writefile.vim @@ -285,7 +285,7 @@ func Test_write_errors() \ && getftype('/dev/loop0') == 'bdev' && !IsRoot() new edit /dev/loop0 - call assert_fails('write', 'E505: ') + call assert_fails('write', 'E503: ') call assert_fails('write!', 'E503: ') close! endif diff --git a/src/version.c b/src/version.c index 1aef3c7d38..70e02ed8ed 100644 --- a/src/version.c +++ b/src/version.c @@ -750,6 +750,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 2856, /**/ 2855, /**/ From 3ec3217f0491e9ba8aa8ea02f7e454cd19a287ef Mon Sep 17 00:00:00 2001 From: Bram Moolenaar Date: Sun, 16 May 2021 12:39:47 +0200 Subject: [PATCH 10/26] Update runtime files --- .github/CODEOWNERS | 22 ++++++-- runtime/doc/cmdline.txt | 10 ++-- runtime/doc/eval.txt | 7 ++- runtime/doc/map.txt | 18 ++++++- runtime/doc/options.txt | 2 +- runtime/doc/pattern.txt | 36 ++++++++++++- runtime/doc/quickfix.txt | 6 +-- runtime/doc/repeat.txt | 19 +++++-- runtime/doc/starting.txt | 4 +- runtime/doc/tags | 5 +- runtime/doc/todo.txt | 30 ++++++++--- runtime/doc/version7.txt | 4 +- runtime/doc/version8.txt | 4 +- runtime/ftplugin/meson.vim | 1 + runtime/ftplugin/systemverilog.vim | 35 +++++++++++- runtime/indent/meson.vim | 1 + .../dist/opt/termdebug/plugin/termdebug.vim | 6 ++- runtime/syntax/dts.vim | 54 +++++++++++++++++-- runtime/syntax/meson.vim | 53 ++++++++---------- 19 files changed, 243 insertions(+), 74 deletions(-) diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index e4b0aa9fd7..569c469b2c 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -9,9 +9,6 @@ # So if a pull request only touches javascript files, only these owners # will be requested to review. -src/iscygpty.* @k-takata -src/libvterm/ @leonerd - runtime/autoload/getscript.vim @cecamp runtime/autoload/netrw.vim @cecamp runtime/autoload/netrwFileHandlers.vim @cecamp @@ -43,7 +40,7 @@ runtime/compiler/jshint.vim @dkearns runtime/compiler/jsonlint.vim @dkearns runtime/compiler/lazbuild.vim @dkearns runtime/compiler/php.vim @dkearns -runtime/compiler/powershell.vim @heaths +runtime/compiler/powershell.vim @heaths runtime/compiler/rake.vim @tpope @dkearns runtime/compiler/rhino.vim @dkearns runtime/compiler/rspec.vim @tpope @dkearns @@ -69,7 +66,7 @@ runtime/doc/pi_netrw.txt @cecamp runtime/doc/pi_tar.txt @cecamp runtime/doc/pi_vimball.txt @cecamp runtime/doc/pi_zip.txt @cecamp -runtime/doc/ps1.txt @heaths +runtime/doc/ps1.txt @heaths runtime/ftplugin/awk.vim @dkearns runtime/ftplugin/basic.vim @dkearns runtime/ftplugin/bst.vim @tpope @@ -96,10 +93,12 @@ runtime/ftplugin/m3build.vim @dkearns runtime/ftplugin/m3quake.vim @dkearns runtime/ftplugin/markdown.vim @tpope runtime/ftplugin/matlab.vim @cecamp +runtime/ftplugin/meson.vim @Liambeguin runtime/ftplugin/modula3.vim @dkearns runtime/ftplugin/nroff.vim @a-vrma runtime/ftplugin/nsis.vim @k-takata runtime/ftplugin/pascal.vim @dkearns +runtime/ftplugin/pbtxt.vim @lakshayg runtime/ftplugin/pdf.vim @tpope runtime/ftplugin/ps1.vim @heaths runtime/ftplugin/ps1xml.vim @heaths @@ -107,6 +106,7 @@ runtime/ftplugin/ruby.vim @tpope @dkearns runtime/ftplugin/sass.vim @tpope runtime/ftplugin/scss.vim @tpope runtime/ftplugin/spec.vim @ignatenkobrain +runtime/ftplugin/systemverilog.vim @Kocha runtime/ftplugin/tidy.vim @dkearns runtime/ftplugin/tmux.vim @ericpruitt runtime/ftplugin/typescript.vim @dkearns @@ -120,12 +120,14 @@ runtime/indent/eruby.vim @tpope @dkearns runtime/indent/gitconfig.vim @tpope runtime/indent/haml.vim @tpope runtime/indent/liquid.vim @tpope +runtime/indent/meson.vim @Liambeguin runtime/indent/nsis.vim @k-takata runtime/indent/ps1.vim @heaths runtime/indent/ruby.vim @AndrewRadev @dkearns runtime/indent/sass.vim @tpope runtime/indent/scss.vim @tpope runtime/indent/sh.vim @chrisbra +runtime/indent/systemverilog.vim @Kocha runtime/indent/teraterm.vim @k-takata runtime/indent/xml.vim @chrisbra runtime/indent/zsh.vim @chrisbra @@ -142,6 +144,7 @@ runtime/syntax/aidl.vim @dpelle runtime/syntax/amiga.vim @cecamp runtime/syntax/asm.vim @dkearns runtime/syntax/asmh8300.vim @dkearns +runtime/syntax/asterisk.vim @jaunis runtime/syntax/awk.vim @dkearns runtime/syntax/basic.vim @dkearns runtime/syntax/bst.vim @tpope @@ -154,8 +157,10 @@ runtime/syntax/cucumber.vim @tpope runtime/syntax/datascript.vim @dpelle runtime/syntax/dcl.vim @cecamp runtime/syntax/desktop.vim @e-kwsm +runtime/syntax/dot.vim @mmottl runtime/syntax/doxygen.vim @frogonwheels runtime/syntax/dtd.vim @chrisbra +runtime/syntax/dts.vim @zonque runtime/syntax/elmfilt.vim @cecamp runtime/syntax/eruby.vim @tpope @dkearns runtime/syntax/exports.vim @cecamp @@ -170,6 +175,7 @@ runtime/syntax/haml.vim @tpope runtime/syntax/haskell.vim @coot runtime/syntax/hgcommit.vim @k-takata runtime/syntax/kconfig.vim @chrisbra +runtime/syntax/less.vim @genoma runtime/syntax/lex.vim @cecamp runtime/syntax/liquid.vim @tpope runtime/syntax/lisp.vim @cecamp @@ -180,17 +186,20 @@ runtime/syntax/mailcap.vim @dkearns runtime/syntax/make.vim @rohieb runtime/syntax/maple.vim @cecamp runtime/syntax/markdown.vim @tpope +runtime/syntax/meson.vim @Liambeguin runtime/syntax/modula3.vim @dkearns runtime/syntax/netrw.vim @cecamp runtime/syntax/nroff.vim @jmarshall runtime/syntax/nsis.vim @k-takata runtime/syntax/pascal.vim @dkearns +runtime/syntax/pbtxt.vim @lakshayg runtime/syntax/pdf.vim @tpope runtime/syntax/php.vim @TysonAndre runtime/syntax/privoxy.vim @dkearns runtime/syntax/prolog.vim @XVilka runtime/syntax/ps1.vim @heaths runtime/syntax/ps1xml.vim @heaths +runtime/syntax/psl.vim @danielkho runtime/syntax/rc.vim @chrisbra runtime/syntax/rpcgen.vim @cecamp runtime/syntax/ruby.vim @dkearns @@ -203,6 +212,7 @@ runtime/syntax/sqloracle.vim @chrisbra runtime/syntax/sshconfig.vim @Jakuje runtime/syntax/sshdconfig.vim @Jakuje runtime/syntax/sudoers.vim @e-kwsm +runtime/syntax/systemverilog.vim @Kocha runtime/syntax/tags.vim @cecamp runtime/syntax/teraterm.vim @k-takata runtime/syntax/tex.vim @cecamp @@ -221,6 +231,8 @@ runtime/tutor/tutor.eo @dpelle runtime/tutor/tutor.eo.utf-8 @dpelle runtime/tutor/tutor.fr @dpelle runtime/tutor/tutor.fr.utf-8 @dpelle +src/iscygpty.* @k-takata +src/libvterm/ @leonerd src/po/de.po @chrisbra src/po/eo.po @dpelle src/po/fr.po @dpelle diff --git a/runtime/doc/cmdline.txt b/runtime/doc/cmdline.txt index 68cb04000e..2cd96d0186 100644 --- a/runtime/doc/cmdline.txt +++ b/runtime/doc/cmdline.txt @@ -1,4 +1,4 @@ -*cmdline.txt* For Vim version 8.2. Last change: 2021 Apr 05 +*cmdline.txt* For Vim version 8.2. Last change: 2021 May 08 VIM REFERENCE MANUAL by Bram Moolenaar @@ -798,18 +798,20 @@ three lines: > 3:d is translated into: .,.+2d < -Visual Mode and Range *v_:* - *:star-visual-range* +Visual Mode and Range + *v_:* {Visual}: Starts a command-line with the Visual selected lines as a range. The code `:'<,'>` is used for this range, which makes it possible to select a similar line from the command-line history for repeating a command on different Visually selected lines. + +:* *:star* *:star-visual-range* When Visual mode was already ended, a short way to use the Visual area for a range is `:*`. This requires that "*" does not appear in 'cpo', see |cpo-star|. Otherwise you will have to type `:'<,'>` - + For when "*" is in 'cpo' see |:star-compatible|. ============================================================================== 5. Ex command-line flags *ex-flags* diff --git a/runtime/doc/eval.txt b/runtime/doc/eval.txt index 920ee10b22..890943810d 100644 --- a/runtime/doc/eval.txt +++ b/runtime/doc/eval.txt @@ -1,4 +1,4 @@ -*eval.txt* For Vim version 8.2. Last change: 2021 Apr 24 +*eval.txt* For Vim version 8.2. Last change: 2021 May 07 VIM REFERENCE MANUAL by Bram Moolenaar @@ -7591,6 +7591,9 @@ matchfuzzy({list}, {str} [, {dict}]) *matchfuzzy()* empty list is returned. If length of {str} is greater than 256, then returns an empty list. + Refer to |fuzzy-match| for more information about fuzzy + matching strings. + Example: > :echo matchfuzzy(["clay", "crow"], "cay") < results in ["clay"]. > @@ -9188,6 +9191,8 @@ searchpair({start}, {middle}, {end} [, {flags} [, {skip} and -1 returned. {skip} can be a string, a lambda, a funcref or a partial. Anything else makes the function fail. + In a `:def` function when the {skip} argument is a string + constant it is compiled into instructions. For {stopline} and {timeout} see |search()|. diff --git a/runtime/doc/map.txt b/runtime/doc/map.txt index 13b2c2efca..970bbc923e 100644 --- a/runtime/doc/map.txt +++ b/runtime/doc/map.txt @@ -1,4 +1,4 @@ -*map.txt* For Vim version 8.2. Last change: 2021 Apr 23 +*map.txt* For Vim version 8.2. Last change: 2021 May 16 VIM REFERENCE MANUAL by Bram Moolenaar @@ -389,6 +389,22 @@ Overview of which map command works in which mode. More details below. :cmap :cnoremap :cunmap Command-line :tmap :tnoremap :tunmap Terminal-Job +Same information in a table: + *map-table* + Mode | Norm | Ins | Cmd | Vis | Sel | Opr | Term | Lang | ~ +Command +------+-----+-----+-----+-----+-----+------+------+ ~ +[nore]map | yes | - | - | yes | yes | yes | - | - | +n[nore]map | yes | - | - | - | - | - | - | - | +[nore]map! | - | yes | yes | - | - | - | - | - | +i[nore]map | - | yes | - | - | - | - | - | - | +c[nore]map | - | - | yes | - | - | - | - | - | +v[nore]map | - | - | - | yes | yes | - | - | - | +x[nore]map | - | - | - | yes | - | - | - | - | +s[nore]map | - | - | - | - | yes | - | - | - | +o[nore]map | - | - | - | - | - | yes | - | - | +t[nore]map | - | - | - | - | - | - | yes | - | +l[nore]map | - | yes | yes | - | - | - | - | yes | + COMMANDS MODES ~ Normal Visual+Select Operator-pending ~ diff --git a/runtime/doc/options.txt b/runtime/doc/options.txt index 9cff98da74..4fbc014d32 100644 --- a/runtime/doc/options.txt +++ b/runtime/doc/options.txt @@ -1,4 +1,4 @@ -*options.txt* For Vim version 8.2. Last change: 2021 Apr 28 +*options.txt* For Vim version 8.2. Last change: 2021 May 15 VIM REFERENCE MANUAL by Bram Moolenaar diff --git a/runtime/doc/pattern.txt b/runtime/doc/pattern.txt index a5b9099e3e..20fed5523c 100644 --- a/runtime/doc/pattern.txt +++ b/runtime/doc/pattern.txt @@ -1,4 +1,4 @@ -*pattern.txt* For Vim version 8.2. Last change: 2021 Feb 16 +*pattern.txt* For Vim version 8.2. Last change: 2021 May 02 VIM REFERENCE MANUAL by Bram Moolenaar @@ -19,6 +19,7 @@ explanations are in chapter 27 |usr_27.txt|. 8. Composing characters |patterns-composing| 9. Compare with Perl patterns |perl-patterns| 10. Highlighting matches |match-highlight| +11. Fuzzy matching |fuzzy-match| ============================================================================== 1. Search commands *search-commands* @@ -1431,5 +1432,38 @@ Finally, these constructs are unique to Perl: are suggested to use ":match" for manual matching and ":2match" for another plugin. +============================================================================== +11. Fuzzy matching *fuzzy-match* + +Fuzzy matching refers to matching strings using a non-exact search string. +Fuzzy matching will match a string, if all the characters in the search string +are present anywhere in the string in the same order. Case is ignored. In a +matched string, other characters can be present between two consecutive +characters in the search string. If the search string has multiple words, then +each word is matched separately. So the words in the search string can be +present in any order in a string. + +Fuzzy matching assigns a score for each matched string based on the following +criteria: + - The number of sequentially matching characters. + - The number of characters (distance) between two consecutive matching + characters. + - Matches at the beginning of a word + - Matches after a camel case character or a path separator or a hyphen. + - The number of unmatched characters in a string. +The matching string with the highest score is returned first. + +For example, when you search for the "get pat" string using fuzzy matching, it +will match the strings "GetPattern", "PatternGet", "getPattern", "patGetter", +"getSomePattern", "MatchpatternGet" etc. + +The functions |matchfuzzy()| and |matchfuzzypos()| can be used to fuzzy search +a string in a List of strings. The matchfuzzy() function returns a List of +matching strings. The matchfuzzypos() functions returns the List of matches, +the matching positions and the fuzzy match scores. + +The "f" flag of `:vimgrep` enables fuzzy matching. + + vim:tw=78:ts=8:noet:ft=help:norl: diff --git a/runtime/doc/quickfix.txt b/runtime/doc/quickfix.txt index fcade001ae..f94da7d2a2 100644 --- a/runtime/doc/quickfix.txt +++ b/runtime/doc/quickfix.txt @@ -1,4 +1,4 @@ -*quickfix.txt* For Vim version 8.2. Last change: 2021 Apr 30 +*quickfix.txt* For Vim version 8.2. Last change: 2021 May 02 VIM REFERENCE MANUAL by Bram Moolenaar @@ -1037,8 +1037,8 @@ commands can be combined to create a NewGrep command: > matching is used to find matching lines. In this case, {pattern} is treated as a literal string instead of a regular expression. See - |matchfuzzy()| for more info about fuzzy - matching. + |fuzzy-match| for more information about fuzzy + matching strings. |QuickFixCmdPre| and |QuickFixCmdPost| are triggered. A file that is opened for matching may use a buffer diff --git a/runtime/doc/repeat.txt b/runtime/doc/repeat.txt index 71b4e10de4..18149fcf8f 100644 --- a/runtime/doc/repeat.txt +++ b/runtime/doc/repeat.txt @@ -1,4 +1,4 @@ -*repeat.txt* For Vim version 8.2. Last change: 2021 Feb 13 +*repeat.txt* For Vim version 8.2. Last change: 2021 May 08 VIM REFERENCE MANUAL by Bram Moolenaar @@ -59,6 +59,11 @@ of area is used, see |visual-repeat|. :[range]v[global]/{pattern}/[cmd] Same as :g!. +Example: > + :g/^Obsolete/d _ +Using the underscore after `:d` avoids clobbering registers or the clipboard. +This also makes it faster. + Instead of the '/' which surrounds the {pattern}, you can use any other single byte character, but not an alphabetic character, '\', '"' or '|'. This is useful if you want to include a '/' in the search pattern or @@ -150,15 +155,12 @@ q Stops recording. (Implementation note: The 'q' that *@@* *E748* @@ Repeat the previous @{0-9a-z":*} [count] times. -:[addr]*{0-9a-z".=+} *:@* *:star* + *:@* :[addr]@{0-9a-z".=*+} Execute the contents of register {0-9a-z".=*+} as an Ex command. First set cursor at line [addr] (default is current line). When the last line in the register does not have a it will be added automatically when the 'e' flag is present in 'cpoptions'. - Note that the ":*" command is only recognized when the - '*' flag is present in 'cpoptions'. This is NOT the - default when 'nocompatible' is used. For ":@=" the last used expression is used. The result of evaluating the expression is executed as an Ex command. @@ -171,6 +173,13 @@ q Stops recording. (Implementation note: The 'q' that Future: Will execute the register for each line in the address range. +:[addr]*{0-9a-z".=+} *:star-compatible* + When '*' is present in 'cpoptions' |cpo-star|, use + ":*" in the same way as ":@". This is NOT the default + when 'nocompatible' is used. When the '*' flag is not + present in 'cpoptions', ":*" is an alias for ":'<,'>", + select the Visual area |:star|. + *:@:* :[addr]@: Repeat last command-line. First set cursor at line [addr] (default is current line). diff --git a/runtime/doc/starting.txt b/runtime/doc/starting.txt index e492c89a4f..469ec0ca5d 100644 --- a/runtime/doc/starting.txt +++ b/runtime/doc/starting.txt @@ -1,4 +1,4 @@ -*starting.txt* For Vim version 8.2. Last change: 2021 Feb 10 +*starting.txt* For Vim version 8.2. Last change: 2021 May 08 VIM REFERENCE MANUAL by Bram Moolenaar @@ -1592,7 +1592,7 @@ VIMINFO FILE NAME *viminfo-file-name* file name given is "NONE" (all uppercase), no viminfo file is ever read or written. Also not for the commands below! - The 'viminfofile' option can be used like the "-i" argument. In fact, the - value form the "-i" argument is stored in the 'viminfofile' option. + value from the "-i" argument is stored in the 'viminfofile' option. - For the commands below, another file name can be given, overriding the default and the name given with 'viminfo' or "-i" (unless it's NONE). diff --git a/runtime/doc/tags b/runtime/doc/tags index cdaa66417a..dd73ba2d3e 100644 --- a/runtime/doc/tags +++ b/runtime/doc/tags @@ -3184,7 +3184,8 @@ $VIM_POSIX vi_diff.txt /*$VIM_POSIX* :st starting.txt /*:st* :sta windows.txt /*:sta* :stag windows.txt /*:stag* -:star repeat.txt /*:star* +:star cmdline.txt /*:star* +:star-compatible repeat.txt /*:star-compatible* :star-visual-range cmdline.txt /*:star-visual-range* :start insert.txt /*:start* :startgreplace insert.txt /*:startgreplace* @@ -6691,6 +6692,7 @@ function-range-example eval.txt /*function-range-example* function-search-undo eval.txt /*function-search-undo* function_key intro.txt /*function_key* functions eval.txt /*functions* +fuzzy-match pattern.txt /*fuzzy-match* fvwm.vim syntax.txt /*fvwm.vim* fvwm2rc syntax.txt /*fvwm2rc* fvwmrc syntax.txt /*fvwmrc* @@ -7790,6 +7792,7 @@ map-return map.txt /*map-return* map-self-destroy tips.txt /*map-self-destroy* map-space_in_lhs map.txt /*map-space_in_lhs* map-space_in_rhs map.txt /*map-space_in_rhs* +map-table map.txt /*map-table* map-typing map.txt /*map-typing* map-which-keys map.txt /*map-which-keys* map.txt map.txt /*map.txt* diff --git a/runtime/doc/todo.txt b/runtime/doc/todo.txt index 955c3f6d9a..1cfb9480ee 100644 --- a/runtime/doc/todo.txt +++ b/runtime/doc/todo.txt @@ -1,4 +1,4 @@ -*todo.txt* For Vim version 8.2. Last change: 2021 Apr 29 +*todo.txt* For Vim version 8.2. Last change: 2021 May 15 VIM REFERENCE MANUAL by Bram Moolenaar @@ -39,13 +39,14 @@ browser use: https://github.com/vim/vim/issues/1234 -------------------- Known bugs and current work ----------------------- Vim9 - Make everything work: -- expandcmd() with `=expr` in filename uses legacy expression. -- eval_expr() in ex_cexpr() -- eval_expr() call in dbg_parsearg() and debuggy_find() -- compile_member() guesses the type, should figure out at runtime. -- compile "skip" argument of searchpair() +- function returning nothing should return void instead of zero - compile "expr" and "call" expression of a channel in channel_exe_cmd()? -- give an error for "echo Func()" if Func() does not return anything. +- Need some solution for dict function. Can we implement part of classes? +- A lambda without {} does not require a return type, using { return x } does. + That's unexpected, since the arguments are not required to have a type. + alt 1: not require a return type, figure it out from the common type of all + the return statements found + alt 2: also require argument types - Using "windo echo expr" does not accept a line break inside "expr" (in a :def function and at script level in a not executed block). #7681 - use CheckLegacyAndVim9Success(lines) in many more places @@ -239,6 +240,10 @@ Memory leak in test_alot with pyeval() (allocating partial) Memory leak in test_alot with expand() Memory leaks in test_channel? (or is it because of fork()) +":set &shellpipe" and ":set &shellredir" should use the logic from +initialization to figure out the default value from 'shell'. Add a test for +this. + test_arglist func Test_all_not_allowed_from_cmdwin() hangs on MS-Windows. Mapping with partial match not executed properly in GTK. (Ingo Karkat, #7082) @@ -249,6 +254,9 @@ Have another look at the implementation. Patch to implement the vimtutor with a plugin: #6414 Was originally written by Felipe Morales. +Request to use "." for the cursor column in search pattern \%<.c and \%<.v. +(#8179) + Adding "10" to 'spellsuggest' causes spell suggestions to become very slow. (#4087) Did patch 8.2.2379 help? Also, z= in German on a long word can take a very long time, but CTRL-C to @@ -276,6 +284,9 @@ Missing filetype test for bashrc, PKGBUILD, etc. Add an option to not fetch terminal codes in xterm, to avoid flicker when t_Co changes. +When using ":bwipe!" also get rid of references to be buffer, e.g. in the +jumplist and alternate file. + Add an option to start_timer() to return from the input loop with K_IGNORE. This is useful e.g. when a popup was created that disables mappings, we need to return from vgetc() to make this happen. #7011 @@ -293,6 +304,9 @@ MS-Windows: when writing undo file the infostreams are copied in mch_copy_file_attribute(), that seems unnecessary. (#7925) Add a flag to only copy attributes? +Make the jumplist behave like a tag stack. (#7738) Should there be a more +time bound navigation, like with undo? + Changing a capturing group to non-capturing changes the result: #7607 :echo matchstr('aaa bbb', '\(.\{-1,}\>\)\|.*') aaa @@ -1215,7 +1229,7 @@ Undo problem: "g-" doesn't go back, gets stuck. (Björn Linse, 2016 Jul 18) Add "unicode true" to NSIS installer. Doesn't work with Windows 95, which we no longer support. -Suppoert sort(l, 'F'), convert strings to float. (#7857) +Support sort(l, 'F'), convert strings to float. (#7857) sort() is not stable when using numeric/float sort (Nikolay Pavlov, 2016 Sep 4#1038) diff --git a/runtime/doc/version7.txt b/runtime/doc/version7.txt index 8d75ed6cad..823d49df32 100644 --- a/runtime/doc/version7.txt +++ b/runtime/doc/version7.txt @@ -1,4 +1,4 @@ -*version7.txt* For Vim version 8.2. Last change: 2020 Oct 25 +*version7.txt* For Vim version 8.2. Last change: 2021 May 13 VIM REFERENCE MANUAL by Bram Moolenaar @@ -9826,7 +9826,7 @@ Solution: Add AC_SYS_LARGEFILE to configure. (James Vega) Files: src/configure.in, src/config.h.in, src/auto/configure Patch 7.2.414 -Problem: CTRK-K does not produce 0xa0 as expected. (Tony +Problem: CTRL-K does not produce 0xa0 as expected. (Tony Mechelynck) Solution: Remove the Unicode range 0xe000 - 0xefff from digraphs, these are not valid characters. diff --git a/runtime/doc/version8.txt b/runtime/doc/version8.txt index ab4b7d8068..313c38827f 100644 --- a/runtime/doc/version8.txt +++ b/runtime/doc/version8.txt @@ -1,4 +1,4 @@ -*version8.txt* For Vim version 8.2. Last change: 2020 Dec 24 +*version8.txt* For Vim version 8.2. Last change: 2021 May 13 VIM REFERENCE MANUAL by Bram Moolenaar @@ -15341,7 +15341,7 @@ Solution: Link winpthread statically. (jmmerz, closes #1255, closes #1256) Files: src/Make_cyg_ming.mak Patch 8.0.0116 -Problem: When reading English help and using CTRl-] the language from +Problem: When reading English help and using CTRL-] the language from 'helplang' is used. Solution: Make help tag jumps keep the language. (Tatsuki, test by Hirohito Higashi, closes #1249) diff --git a/runtime/ftplugin/meson.vim b/runtime/ftplugin/meson.vim index e432ebf196..d48fa1dfd1 100644 --- a/runtime/ftplugin/meson.vim +++ b/runtime/ftplugin/meson.vim @@ -1,6 +1,7 @@ " Vim filetype plugin file " Language: meson " License: VIM License +" Maintainer: Liam Beguin " Original Author: Laurent Pinchart " Last Change: 2018 Nov 27 diff --git a/runtime/ftplugin/systemverilog.vim b/runtime/ftplugin/systemverilog.vim index 4d0f565fcc..e350427022 100644 --- a/runtime/ftplugin/systemverilog.vim +++ b/runtime/ftplugin/systemverilog.vim @@ -1,7 +1,7 @@ " Vim filetype plugin file " Language: SystemVerilog " Maintainer: kocha -" Last Change: 12-Aug-2013. +" Last Change: 07-May-2021 if exists("b:did_ftplugin") finish @@ -9,3 +9,36 @@ endif " Behaves just like Verilog runtime! ftplugin/verilog.vim + +let s:cpo_save = &cpo +set cpo&vim + +" Add SystemVerilog keywords for matchit plugin. +if exists("loaded_matchit") + let b:match_words = + \ '\:\,' . + \ '\\|\\|\:\,' . + \ '\:\,' . + \ '\:`\@,' . + \ '\:\,' . + \ '`ifn\?def\>:`elsif\>:`else\>:`endif\>,' . + \ '\:\,' . + \ '\:\,' . + \ '\:\,' . + \ '\:\,' . + \ '\:\\|\\|\,' . + \ '\:\,' . + \ '\:\,' . + \ '\:\,' . + \ '\:\,' . + \ '\:\,' . + \ '\:\,' . + \ '\:\,' . + \ '\:\,' . + \ '\:\,' . + \ '\:\,' . + \ '\:\' +endif + +let &cpo = s:cpo_save +unlet s:cpo_save diff --git a/runtime/indent/meson.vim b/runtime/indent/meson.vim index f116781f74..549209ca33 100644 --- a/runtime/indent/meson.vim +++ b/runtime/indent/meson.vim @@ -2,6 +2,7 @@ " Language: Meson " License: VIM License " Maintainer: Nirbheek Chauhan +" Liam Beguin " Original Authors: David Bustos " Bram Moolenaar " Last Change: 2019 Oct 18 diff --git a/runtime/pack/dist/opt/termdebug/plugin/termdebug.vim b/runtime/pack/dist/opt/termdebug/plugin/termdebug.vim index 706a94b976..117322da50 100644 --- a/runtime/pack/dist/opt/termdebug/plugin/termdebug.vim +++ b/runtime/pack/dist/opt/termdebug/plugin/termdebug.vim @@ -2,7 +2,7 @@ " " Author: Bram Moolenaar " Copyright: Vim license applies, see ":help license" -" Last Change: 2021 Jan 03 +" Last Change: 2021 May 16 " " WORK IN PROGRESS - Only the basics work " Note: On MS-Windows you need a recent version of gdb. The one included with @@ -228,7 +228,9 @@ func s:StartDebug_term(dict) endif let s:gdbwin = win_getid(winnr()) - " Set arguments to be run + " Set arguments to be run. First wait a bit to make detecting gdb a bit + " more reliable. + sleep 200m if len(proc_args) call term_sendkeys(s:gdbbuf, 'set args ' . join(proc_args) . "\r") endif diff --git a/runtime/syntax/dts.vim b/runtime/syntax/dts.vim index cd4bd776b7..d75b9c178a 100644 --- a/runtime/syntax/dts.vim +++ b/runtime/syntax/dts.vim @@ -1,7 +1,7 @@ " Vim syntax file " Language: dts/dtsi (device tree files) " Maintainer: Daniel Mack -" Last Change: 2013 Oct 20 +" Last Change: 2021 May 15 if exists("b:current_syntax") finish @@ -9,7 +9,7 @@ endif syntax region dtsComment start="/\*" end="\*/" syntax match dtsReference "&[[:alpha:][:digit:]_]\+" -syntax region dtsBinaryProperty start="\[" end="\]" +syntax region dtsBinaryProperty start="\[" end="\]" syntax match dtsStringProperty "\".*\"" syntax match dtsKeyword "/.\{-1,\}/" syntax match dtsLabel "^[[:space:]]*[[:alpha:][:digit:]_]\+:" @@ -18,6 +18,38 @@ syntax region dtsCellProperty start="<" end=">" contains=dtsReference,dtsBinar syntax region dtsCommentInner start="/\*" end="\*/" syntax match dtsCommentLine "//.*$" +" Accept %: for # (C99) +syn region cPreCondit start="^\s*\zs\(%:\|#\)\s*\(if\|ifdef\|ifndef\|elif\)\>" skip="\\$" end="$" keepend contains=cComment,cCommentL,cCppString,cCharacter,cCppParen,cParenError,cNumbers,cCommentError,cSpaceError +syn match cPreConditMatch display "^\s*\zs\(%:\|#\)\s*\(else\|endif\)\>" +if !exists("c_no_if0") + syn cluster cCppOutInGroup contains=cCppInIf,cCppInElse,cCppInElse2,cCppOutIf,cCppOutIf2,cCppOutElse,cCppInSkip,cCppOutSkip + syn region cCppOutWrapper start="^\s*\zs\(%:\|#\)\s*if\s\+0\+\s*\($\|//\|/\*\|&\)" end=".\@=\|$" contains=cCppOutIf,cCppOutElse,@NoSpell fold + syn region cCppOutIf contained start="0\+" matchgroup=cCppOutWrapper end="^\s*\(%:\|#\)\s*endif\>" contains=cCppOutIf2,cCppOutElse + if !exists("c_no_if0_fold") + syn region cCppOutIf2 contained matchgroup=cCppOutWrapper start="0\+" end="^\s*\(%:\|#\)\s*\(else\>\|elif\s\+\(0\+\s*\($\|//\|/\*\|&\)\)\@!\|endif\>\)"me=s-1 contains=cSpaceError,cCppOutSkip,@Spell fold + else + syn region cCppOutIf2 contained matchgroup=cCppOutWrapper start="0\+" end="^\s*\(%:\|#\)\s*\(else\>\|elif\s\+\(0\+\s*\($\|//\|/\*\|&\)\)\@!\|endif\>\)"me=s-1 contains=cSpaceError,cCppOutSkip,@Spell + endif + syn region cCppOutElse contained matchgroup=cCppOutWrapper start="^\s*\(%:\|#\)\s*\(else\|elif\)" end="^\s*\(%:\|#\)\s*endif\>"me=s-1 contains=TOP,cPreCondit + syn region cCppInWrapper start="^\s*\zs\(%:\|#\)\s*if\s\+0*[1-9]\d*\s*\($\|//\|/\*\||\)" end=".\@=\|$" contains=cCppInIf,cCppInElse fold + syn region cCppInIf contained matchgroup=cCppInWrapper start="\d\+" end="^\s*\(%:\|#\)\s*endif\>" contains=TOP,cPreCondit + if !exists("c_no_if0_fold") + syn region cCppInElse contained start="^\s*\(%:\|#\)\s*\(else\>\|elif\s\+\(0*[1-9]\d*\s*\($\|//\|/\*\||\)\)\@!\)" end=".\@=\|$" containedin=cCppInIf contains=cCppInElse2 fold + else + syn region cCppInElse contained start="^\s*\(%:\|#\)\s*\(else\>\|elif\s\+\(0*[1-9]\d*\s*\($\|//\|/\*\||\)\)\@!\)" end=".\@=\|$" containedin=cCppInIf contains=cCppInElse2 + endif + syn region cCppInElse2 contained matchgroup=cCppInWrapper start="^\s*\(%:\|#\)\s*\(else\|elif\)\([^/]\|/[^/*]\)*" end="^\s*\(%:\|#\)\s*endif\>"me=s-1 contains=cSpaceError,cCppOutSkip,@Spell + syn region cCppOutSkip contained start="^\s*\(%:\|#\)\s*\(if\>\|ifdef\>\|ifndef\>\)" skip="\\$" end="^\s*\(%:\|#\)\s*endif\>" contains=cSpaceError,cCppOutSkip + syn region cCppInSkip contained matchgroup=cCppInWrapper start="^\s*\(%:\|#\)\s*\(if\s\+\(\d\+\s*\($\|//\|/\*\||\|&\)\)\@!\|ifdef\>\|ifndef\>\)" skip="\\$" end="^\s*\(%:\|#\)\s*endif\>" containedin=cCppOutElse,cCppInIf,cCppInSkip contains=TOP,cPreProc +endif +syn region cIncluded display contained start=+"+ skip=+\\\\\|\\"+ end=+"+ +syn match cIncluded display contained "<[^>]*>" +syn match cInclude display "^\s*\zs\(%:\|#\)\s*include\>\s*["<]" contains=cIncluded +"syn match cLineSkip "\\$" +syn cluster cPreProcGroup contains=cPreCondit,cIncluded,cInclude,cDefine,cErrInParen,cErrInBracket,cUserLabel,cSpecial,cOctalZero,cCppOutWrapper,cCppInWrapper,@cCppOutInGroup,cFormat,cNumber,cFloat,cOctal,cOctalError,cNumbersCom,cString,cCommentSkip,cCommentString,cComment2String,@cCommentGroup,cCommentStartError,cParen,cBracket,cMulti,cBadBlock +syn region cDefine start="^\s*\zs\(%:\|#\)\s*\(define\|undef\)\>" skip="\\$" end="$" keepend contains=ALLBUT,@cPreProcGroup,@Spell +syn region cPreProc start="^\s*\zs\(%:\|#\)\s*\(pragma\>\|line\>\|warning\>\|warn\>\|error\>\)" skip="\\$" end="$" keepend contains=ALLBUT,@cPreProcGroup,@Spell + hi def link dtsCellProperty Number hi def link dtsBinaryProperty Number hi def link dtsStringProperty String @@ -26,5 +58,21 @@ hi def link dtsLabel Label hi def link dtsNode Structure hi def link dtsReference Macro hi def link dtsComment Comment -hi def link dtsCommentInner Comment +hi def link dtsCommentInner Comment hi def link dtsCommentLine Comment + +hi def link cInclude Include +hi def link cPreProc PreProc +hi def link cDefine Macro +hi def link cIncluded cString +hi def link cString String + +hi def link cCppInWrapper cCppOutWrapper +hi def link cCppOutWrapper cPreCondit +hi def link cPreConditMatch cPreCondit +hi def link cPreCondit PreCondit +hi def link cCppOutSkip cCppOutIf2 + +hi def link cCppInElse2 cCppOutIf2 +hi def link cCppOutIf2 cCppOut +hi def link cCppOut Comment diff --git a/runtime/syntax/meson.vim b/runtime/syntax/meson.vim index 78de2ab89e..7e6b565f19 100644 --- a/runtime/syntax/meson.vim +++ b/runtime/syntax/meson.vim @@ -2,6 +2,7 @@ " Language: Meson " License: VIM License " Maintainer: Nirbheek Chauhan +" Liam Beguin " Last Change: 2019 Oct 18 " Credits: Zvezdan Petkovic " Neil Schemenauer @@ -17,11 +18,7 @@ " let meson_space_error_highlight = 1 " -" For version 5.x: Clear all syntax items. -" For version 6.x: Quit when a syntax file was already loaded. -if version < 600 - syntax clear -elseif exists("b:current_syntax") +if exists("b:current_syntax") finish endif @@ -32,8 +29,9 @@ set cpo&vim " http://mesonbuild.com/Syntax.html syn keyword mesonConditional elif else if endif -syn keyword mesonRepeat foreach endforeach -syn keyword mesonOperator and not or +syn keyword mesonRepeat foreach endforeach +syn keyword mesonOperator and not or in +syn keyword mesonStatement continue break syn match mesonComment "#.*$" contains=mesonTodo,@Spell syn keyword mesonTodo FIXME NOTE NOTES TODO XXX contained @@ -117,10 +115,12 @@ syn keyword mesonBuiltin \ subdir \ subdir_done \ subproject + \ summary \ target_machine \ test \ vcs_tag \ warning + \ range if exists("meson_space_error_highlight") " trailing whitespace @@ -130,31 +130,20 @@ if exists("meson_space_error_highlight") syn match mesonSpaceError display "\t\+ " endif -if version >= 508 || !exists("did_meson_syn_inits") - if version <= 508 - let did_meson_syn_inits = 1 - command -nargs=+ HiLink hi link - else - command -nargs=+ HiLink hi def link - endif - - " The default highlight links. Can be overridden later. - HiLink mesonStatement Statement - HiLink mesonConditional Conditional - HiLink mesonRepeat Repeat - HiLink mesonOperator Operator - HiLink mesonComment Comment - HiLink mesonTodo Todo - HiLink mesonString String - HiLink mesonEscape Special - HiLink mesonNumber Number - HiLink mesonBuiltin Function - HiLink mesonConstant Number - if exists("meson_space_error_highlight") - HiLink mesonSpaceError Error - endif - - delcommand HiLink +" The default highlight links. Can be overridden later. +hi def link mesonStatement Statement +hi def link mesonConditional Conditional +hi def link mesonRepeat Repeat +hi def link mesonOperator Operator +hi def link mesonComment Comment +hi def link mesonTodo Todo +hi def link mesonString String +hi def link mesonEscape Special +hi def link mesonNumber Number +hi def link mesonBuiltin Function +hi def link mesonConstant Number +if exists("meson_space_error_higlight") + hi def link mesonSpaceError Error endif let b:current_syntax = "meson" From ff65288aa89dcd50760ad942d58baff70c6e93e6 Mon Sep 17 00:00:00 2001 From: Bram Moolenaar Date: Sun, 16 May 2021 15:24:49 +0200 Subject: [PATCH 11/26] patch 8.2.2857: Vim9: exception in ISN_INSTR caught at wrong level Problem: Vim9: exception in ISN_INSTR caught at wrong level. Solution: Set the starting trylevel in exec_instructions(). (closes #8214) --- src/globals.h | 2 +- src/testdir/test_vim9_builtin.vim | 14 ++++++++++++++ src/version.c | 2 ++ src/vim9compile.c | 5 +++-- src/vim9execute.c | 4 +++- 5 files changed, 23 insertions(+), 4 deletions(-) diff --git a/src/globals.h b/src/globals.h index 0a6b87a780..74a7c3967f 100644 --- a/src/globals.h +++ b/src/globals.h @@ -1616,7 +1616,7 @@ EXTERN char e_duparg2[] INIT(= N_("E983: Duplicate argument: %s")); EXTERN char e_invargval[] INIT(= N_("E475: Invalid value for argument %s")); EXTERN char e_invargNval[] INIT(= N_("E475: Invalid value for argument %s: %s")); #ifdef FEAT_EVAL -EXTERN char e_invexpr2[] INIT(= N_("E15: Invalid expression: %s")); +EXTERN char e_invexpr2[] INIT(= N_("E15: Invalid expression: \"%s\"")); #endif EXTERN char e_invrange[] INIT(= N_("E16: Invalid range")); #if defined(UNIX) || defined(FEAT_SYN_HL) || defined(FEAT_SPELL) diff --git a/src/testdir/test_vim9_builtin.vim b/src/testdir/test_vim9_builtin.vim index 41063c5444..2e9e0566c1 100644 --- a/src/testdir/test_vim9_builtin.vim +++ b/src/testdir/test_vim9_builtin.vim @@ -1006,6 +1006,20 @@ def Test_searchpair() normal 0f{ assert_equal([0, 0], searchpairpos('{', '', '}', '', 'col(".") > col')) + var lines =<< trim END + vim9script + setline(1, '()') + normal gg + def Fail() + try + searchpairpos('(', '', ')', 'nW', '[0]->map("")') + catch + endtry + enddef + Fail() + END + CheckScriptFailure(lines, 'E15:') + bwipe! enddef diff --git a/src/version.c b/src/version.c index 70e02ed8ed..e45d3be709 100644 --- a/src/version.c +++ b/src/version.c @@ -750,6 +750,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 2857, /**/ 2856, /**/ diff --git a/src/vim9compile.c b/src/vim9compile.c index 39c36dfb24..9aa93de7b2 100644 --- a/src/vim9compile.c +++ b/src/vim9compile.c @@ -3131,7 +3131,8 @@ compile_string(isn_T *isn, cctx_T *cctx) s = skipwhite(s); trailing_error = *s != NUL; - if (expr_res == FAIL || trailing_error) + if (expr_res == FAIL || trailing_error + || ga_grow(&cctx->ctx_instr, 1) == FAIL) { if (trailing_error) semsg(_(e_trailing_arg), s); @@ -3185,7 +3186,7 @@ compile_arguments(char_u **arg, cctx_T *cctx, int *argcount, int is_searchpair) return FAIL; ++*argcount; - if (is_searchpair && *argcount == 5 + if (is_searchpair && *argcount >= 5 && cctx->ctx_instr.ga_len == instr_count + 1) { isn_T *isn = ((isn_T *)cctx->ctx_instr.ga_data) + instr_count; diff --git a/src/vim9execute.c b/src/vim9execute.c index ae4142b0ce..425cdb9bb2 100644 --- a/src/vim9execute.c +++ b/src/vim9execute.c @@ -1295,6 +1295,9 @@ exec_instructions(ectx_T *ectx) // Start execution at the first instruction. ectx->ec_iidx = 0; + // Only catch exceptions in this instruction list. + ectx->ec_trylevel_at_start = trylevel; + for (;;) { isn_T *iptr; @@ -4158,7 +4161,6 @@ call_def_function( ga_init2(&ectx.ec_trystack, sizeof(trycmd_T), 10); ga_init2(&ectx.ec_funcrefs, sizeof(partial_T *), 10); ectx.ec_did_emsg_before = did_emsg_before; - ectx.ec_trylevel_at_start = trylevel; idx = argc - ufunc->uf_args.ga_len; if (idx > 0 && ufunc->uf_va_name == NULL) From 6b02b38ed06879f5e6befe2140aee11a6ad66884 Mon Sep 17 00:00:00 2001 From: Bram Moolenaar Date: Sun, 16 May 2021 16:19:37 +0200 Subject: [PATCH 12/26] patch 8.2.2858: test fails because of changed error message Problem: Test fails because of changed error message. Solution: Adjust the expected error message. --- src/testdir/test_ex_mode.vim | 4 ++-- src/version.c | 2 ++ 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/src/testdir/test_ex_mode.vim b/src/testdir/test_ex_mode.vim index a761cbf8b4..1ca5062328 100644 --- a/src/testdir/test_ex_mode.vim +++ b/src/testdir/test_ex_mode.vim @@ -154,9 +154,9 @@ func Test_Ex_echo_backslash() let bsl = '\\\\' let bsl2 = '\\\' call assert_fails('call feedkeys("Qecho " .. bsl .. "\nvisual\n", "xt")', - \ "E15: Invalid expression: \\\\") + \ 'E15: Invalid expression: "\\"') call assert_fails('call feedkeys("Qecho " .. bsl2 .. "\nm\nvisual\n", "xt")', - \ "E15: Invalid expression: \\\nm") + \ "E15: Invalid expression: \"\\\nm\"") endfunc func Test_ex_mode_errors() diff --git a/src/version.c b/src/version.c index e45d3be709..018e47dc5e 100644 --- a/src/version.c +++ b/src/version.c @@ -750,6 +750,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 2858, /**/ 2857, /**/ From dcfc311198b174468c007ec4b5b22b33c2c11c92 Mon Sep 17 00:00:00 2001 From: Bram Moolenaar Date: Sun, 16 May 2021 20:06:59 +0200 Subject: [PATCH 13/26] patch 8.2.2859: Tcl test fails because of changed error message Problem: Tcl test fails because of changed error message. Solution: Adjust the expected error message. --- src/testdir/test_tcl.vim | 2 +- src/version.c | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/src/testdir/test_tcl.vim b/src/testdir/test_tcl.vim index b851ce8618..a4554bb8fc 100644 --- a/src/testdir/test_tcl.vim +++ b/src/testdir/test_tcl.vim @@ -145,7 +145,7 @@ func Test_vim_expr() call assert_fails('tcl ::vim::expr x y', \ 'wrong # args: should be "::vim::expr vimExpr"') - call assert_fails('tcl ::vim::expr 1-', 'E15: Invalid expression: 1-') + call assert_fails('tcl ::vim::expr 1-', 'E15: Invalid expression: "1-"') endfunc " Test ::vim::command diff --git a/src/version.c b/src/version.c index 018e47dc5e..6a37ad5fff 100644 --- a/src/version.c +++ b/src/version.c @@ -750,6 +750,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 2859, /**/ 2858, /**/ From 1764faa38645a559172e9a31f08447385835de81 Mon Sep 17 00:00:00 2001 From: Bram Moolenaar Date: Sun, 16 May 2021 20:18:57 +0200 Subject: [PATCH 14/26] patch 8.2.2860: adding a text property causes the whole window to be redawn Problem: Adding a text property causes the whole window to be redawn. Solution: Use changed_lines_buf() to only redraw the affected lines. --- src/change.c | 2 +- src/proto/change.pro | 1 + src/textprop.c | 3 ++- src/version.c | 2 ++ 4 files changed, 6 insertions(+), 2 deletions(-) diff --git a/src/change.c b/src/change.c index 50dc105436..248e6d8487 100644 --- a/src/change.c +++ b/src/change.c @@ -758,7 +758,7 @@ deleted_lines_mark(linenr_T lnum, long count) /* * Marks the area to be redrawn after a change. */ - static void + void changed_lines_buf( buf_T *buf, linenr_T lnum, // first line with change diff --git a/src/proto/change.pro b/src/proto/change.pro index 69ba2a6b08..b1aa9d57ec 100644 --- a/src/proto/change.pro +++ b/src/proto/change.pro @@ -14,6 +14,7 @@ void appended_lines(linenr_T lnum, long count); void appended_lines_mark(linenr_T lnum, long count); void deleted_lines(linenr_T lnum, long count); void deleted_lines_mark(linenr_T lnum, long count); +void changed_lines_buf(buf_T *buf, linenr_T lnum, linenr_T lnume, long xtra); void changed_lines(linenr_T lnum, colnr_T col, linenr_T lnume, long xtra); void unchanged(buf_T *buf, int ff, int always_inc_changedtick); void save_file_ff(buf_T *buf); diff --git a/src/textprop.c b/src/textprop.c index b62619368f..f11e1a3941 100644 --- a/src/textprop.c +++ b/src/textprop.c @@ -345,7 +345,8 @@ prop_add_common( } buf->b_has_textprop = TRUE; // this is never reset - redraw_buf_later(buf, NOT_VALID); + changed_lines_buf(buf, start_lnum, end_lnum + 1, 0); + redraw_buf_later(buf, VALID); } /* diff --git a/src/version.c b/src/version.c index 6a37ad5fff..cd42c0a7ea 100644 --- a/src/version.c +++ b/src/version.c @@ -750,6 +750,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 2860, /**/ 2859, /**/ From 3b1373b193ce5fbf25e852277a4ecc98688c7bb8 Mon Sep 17 00:00:00 2001 From: Bram Moolenaar Date: Mon, 17 May 2021 00:01:42 +0200 Subject: [PATCH 15/26] patch 8.2.2861: Vim9: "legacy return" is not recognized as a return statement Problem: Vim9: "legacy return" is not recognized as a return statement. Solution: Specifically check for a return command. (closes #8213) --- src/testdir/test_vim9_expr.vim | 15 +++++++++ src/version.c | 2 ++ src/vim9.h | 1 + src/vim9compile.c | 59 ++++++++++++++++++++++++++++++---- src/vim9execute.c | 25 ++++++++++++++ 5 files changed, 95 insertions(+), 7 deletions(-) diff --git a/src/testdir/test_vim9_expr.vim b/src/testdir/test_vim9_expr.vim index 718db8b70e..fe5de29d0b 100644 --- a/src/testdir/test_vim9_expr.vim +++ b/src/testdir/test_vim9_expr.vim @@ -2777,6 +2777,10 @@ def Test_expr7_negate_add() CheckDefAndScriptFailure(lines, 'E15:') enddef +def LegacyReturn(): string + legacy return #{key: 'ok'}.key +enddef + def Test_expr7_legacy_script() var lines =<< trim END let s:legacy = 'legacy' @@ -2790,6 +2794,17 @@ def Test_expr7_legacy_script() call assert_equal('legacy', GetLocalPrefix()) END CheckScriptSuccess(lines) + + assert_equal('ok', LegacyReturn()) + + lines =<< trim END + vim9script + def GetNumber(): number + legacy return range(3)->map('v:val + 1') + enddef + echo GetNumber() + END + CheckScriptFailure(lines, 'E1012: Type mismatch; expected number but got list') enddef def Echo(arg: any): string diff --git a/src/version.c b/src/version.c index cd42c0a7ea..fca2cd8c4f 100644 --- a/src/version.c +++ b/src/version.c @@ -750,6 +750,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 2861, /**/ 2860, /**/ diff --git a/src/vim9.h b/src/vim9.h index 9f45ea4125..b260bdf1f3 100644 --- a/src/vim9.h +++ b/src/vim9.h @@ -14,6 +14,7 @@ typedef enum { ISN_EXEC, // execute Ex command line isn_arg.string ISN_EXECCONCAT, // execute Ex command from isn_arg.number items on stack + ISN_LEGACY_EVAL, // evaluate expression isn_arg.string with legacy syntax. ISN_ECHO, // echo isn_arg.echo.echo_count items on top of stack ISN_EXECUTE, // execute Ex commands isn_arg.number items on top of stack ISN_ECHOMSG, // echo Ex commands isn_arg.number items on top of stack diff --git a/src/vim9compile.c b/src/vim9compile.c index 9aa93de7b2..160c8e428f 100644 --- a/src/vim9compile.c +++ b/src/vim9compile.c @@ -2173,6 +2173,25 @@ generate_EXEC(cctx_T *cctx, char_u *line) return OK; } + static int +generate_LEGACY_EVAL(cctx_T *cctx, char_u *line) +{ + isn_T *isn; + garray_T *stack = &cctx->ctx_type_stack; + + RETURN_OK_IF_SKIP(cctx); + if ((isn = generate_instr(cctx, ISN_LEGACY_EVAL)) == NULL) + return FAIL; + isn->isn_arg.string = vim_strsave(line); + + if (ga_grow(stack, 1) == FAIL) + return FAIL; + ((type_T **)stack->ga_data)[stack->ga_len] = &t_any; + ++stack->ga_len; + + return OK; +} + static int generate_EXECCONCAT(cctx_T *cctx, int count) { @@ -5321,10 +5340,11 @@ compile_expr0(char_u **arg, cctx_T *cctx) } /* - * compile "return [expr]" + * Compile "return [expr]". + * When "legacy" is TRUE evaluate [expr] with legacy syntax */ static char_u * -compile_return(char_u *arg, int check_return_type, cctx_T *cctx) +compile_return(char_u *arg, int check_return_type, int legacy, cctx_T *cctx) { char_u *p = arg; garray_T *stack = &cctx->ctx_type_stack; @@ -5332,9 +5352,24 @@ compile_return(char_u *arg, int check_return_type, cctx_T *cctx) if (*p != NUL && *p != '|' && *p != '\n') { - // compile return argument into instructions - if (compile_expr0(&p, cctx) == FAIL) - return NULL; + if (legacy) + { + int save_flags = cmdmod.cmod_flags; + + generate_LEGACY_EVAL(cctx, p); + if (need_type(&t_any, cctx->ctx_ufunc->uf_ret_type, -1, + 0, cctx, FALSE, FALSE) == FAIL) + return NULL; + cmdmod.cmod_flags |= CMOD_LEGACY; + (void)skip_expr(&p, NULL); + cmdmod.cmod_flags = save_flags; + } + else + { + // compile return argument into instructions + if (compile_expr0(&p, cctx) == FAIL) + return NULL; + } if (cctx->ctx_skip != SKIP_YES) { @@ -9193,7 +9228,15 @@ compile_def_function( // When using ":legacy cmd" always use compile_exec(). if (local_cmdmod.cmod_flags & CMOD_LEGACY) - ea.cmdidx = CMD_legacy; + { + char_u *start = ea.cmd; + + // ":legacy return expr" needs to be handled differently. + if (checkforcmd(&start, "return", 4)) + ea.cmdidx = CMD_return; + else + ea.cmdidx = CMD_legacy; + } if (p == ea.cmd && ea.cmdidx != CMD_SIZE) { @@ -9254,7 +9297,8 @@ compile_def_function( goto erret; case CMD_return: - line = compile_return(p, check_return_type, &cctx); + line = compile_return(p, check_return_type, + local_cmdmod.cmod_flags & CMOD_LEGACY, &cctx); cctx.ctx_had_return = TRUE; break; @@ -9605,6 +9649,7 @@ delete_instr(isn_T *isn) { case ISN_DEF: case ISN_EXEC: + case ISN_LEGACY_EVAL: case ISN_LOADAUTO: case ISN_LOADB: case ISN_LOADENV: diff --git a/src/vim9execute.c b/src/vim9execute.c index 425cdb9bb2..7f56597b30 100644 --- a/src/vim9execute.c +++ b/src/vim9execute.c @@ -1388,6 +1388,27 @@ exec_instructions(ectx_T *ectx) } break; + // Evaluate an expression with legacy syntax, push it onto the + // stack. + case ISN_LEGACY_EVAL: + { + char_u *arg = iptr->isn_arg.string; + int res; + int save_flags = cmdmod.cmod_flags; + + if (GA_GROW(&ectx->ec_stack, 1) == FAIL) + return FAIL; + tv = STACK_TV_BOT(0); + init_tv(tv); + cmdmod.cmod_flags |= CMOD_LEGACY; + res = eval0(arg, tv, NULL, &EVALARG_EVALUATE); + cmdmod.cmod_flags = save_flags; + if (res == FAIL) + goto on_error; + ++ectx->ec_stack.ga_len; + } + break; + // push typeval VAR_INSTR with instructions to be executed case ISN_INSTR: { @@ -4464,6 +4485,10 @@ list_instructions(char *pfx, isn_T *instr, int instr_count, ufunc_T *ufunc) case ISN_EXEC: smsg("%s%4d EXEC %s", pfx, current, iptr->isn_arg.string); break; + case ISN_LEGACY_EVAL: + smsg("%s%4d EVAL legacy %s", pfx, current, + iptr->isn_arg.string); + break; case ISN_REDIRSTART: smsg("%s%4d REDIR", pfx, current); break; From fc643e6016af80ed5be4570db5c26a6410f52d16 Mon Sep 17 00:00:00 2001 From: Bram Moolenaar Date: Mon, 17 May 2021 00:15:18 +0200 Subject: [PATCH 16/26] patch 8.2.2862: removing a text property causes the whole window to be redawn Problem: Removing a text property causes the whole window to be redawn. Solution: Use changed_lines_buf() to only redraw the affected lines. --- src/textprop.c | 10 +++++++++- src/version.c | 2 ++ 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/src/textprop.c b/src/textprop.c index f11e1a3941..9a9dddce72 100644 --- a/src/textprop.c +++ b/src/textprop.c @@ -933,7 +933,15 @@ f_prop_remove(typval_T *argvars, typval_T *rettv) } } if (rettv->vval.v_number > 0) - redraw_buf_later(buf, NOT_VALID); + { + if (start == 1 && end == buf->b_ml.ml_line_count) + redraw_buf_later(buf, NOT_VALID); + else + { + changed_lines_buf(buf, start, end + 1, 0); + redraw_buf_later(buf, VALID); + } + } } /* diff --git a/src/version.c b/src/version.c index fca2cd8c4f..b5401e6246 100644 --- a/src/version.c +++ b/src/version.c @@ -750,6 +750,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 2862, /**/ 2861, /**/ From 965c04486c9364ded99b49c86f4c41228503df1f Mon Sep 17 00:00:00 2001 From: Bram Moolenaar Date: Mon, 17 May 2021 00:22:06 +0200 Subject: [PATCH 17/26] patch 8.2.2863: removing a text property does not redraw optimally Problem: Removing a text property does not redraw optimally. Solution: Only redraw the lines that mithg actually have been changed. --- src/textprop.c | 16 ++++++++-------- src/version.c | 2 ++ 2 files changed, 10 insertions(+), 8 deletions(-) diff --git a/src/textprop.c b/src/textprop.c index 9a9dddce72..bd9a77cada 100644 --- a/src/textprop.c +++ b/src/textprop.c @@ -815,6 +815,8 @@ f_prop_remove(typval_T *argvars, typval_T *rettv) linenr_T start = 1; linenr_T end = 0; linenr_T lnum; + linenr_T first_changed = 0; + linenr_T last_changed = 0; dict_T *dict; buf_T *buf = curbuf; int do_all; @@ -925,6 +927,9 @@ f_prop_remove(typval_T *argvars, typval_T *rettv) buf->b_ml.ml_line_len -= sizeof(textprop_T); --idx; + if (first_changed == 0) + first_changed = lnum; + last_changed = lnum; ++rettv->vval.v_number; if (!do_all) break; @@ -932,15 +937,10 @@ f_prop_remove(typval_T *argvars, typval_T *rettv) } } } - if (rettv->vval.v_number > 0) + if (first_changed > 0) { - if (start == 1 && end == buf->b_ml.ml_line_count) - redraw_buf_later(buf, NOT_VALID); - else - { - changed_lines_buf(buf, start, end + 1, 0); - redraw_buf_later(buf, VALID); - } + changed_lines_buf(buf, first_changed, last_changed + 1, 0); + redraw_buf_later(buf, VALID); } } diff --git a/src/version.c b/src/version.c index b5401e6246..cf5208ffc8 100644 --- a/src/version.c +++ b/src/version.c @@ -750,6 +750,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 2863, /**/ 2862, /**/ From 074f84c01fbe70554feb6a71c0d9cacf2ef77ca5 Mon Sep 17 00:00:00 2001 From: Bram Moolenaar Date: Tue, 18 May 2021 11:47:44 +0200 Subject: [PATCH 18/26] patch 8.2.2864: Vim9: crash when using inline function Problem: Vim9: crash when using inline function. Solution: Check for NULL pointer. Make using inline function work inside lambda. (closes #8217) --- src/testdir/test_vim9_func.vim | 14 +++++ src/userfunc.c | 93 +++++++++++++++++++++++++++++++--- src/version.c | 2 + 3 files changed, 102 insertions(+), 7 deletions(-) diff --git a/src/testdir/test_vim9_func.vim b/src/testdir/test_vim9_func.vim index 4d57eef71e..7eca70919d 100644 --- a/src/testdir/test_vim9_func.vim +++ b/src/testdir/test_vim9_func.vim @@ -2102,6 +2102,20 @@ def Test_nested_lambda() CheckScriptSuccess(lines) enddef +def Test_nested_inline_lambda() + # TODO: use the "text" argument + var lines =<< trim END + vim9script + def F(text: string): func(string): func(string): string + return (arg: string): func(string): string => ((sep: string): string => { + return sep .. arg + }) + enddef + assert_equal('--there', F('unused')('there')('--')) + END + CheckScriptSuccess(lines) +enddef + def Shadowed(): list var FuncList: list = [() => 42] return FuncList->mapnew((_, Shadowed) => Shadowed()) diff --git a/src/userfunc.c b/src/userfunc.c index 99d4e0334e..b88b512c54 100644 --- a/src/userfunc.c +++ b/src/userfunc.c @@ -606,6 +606,7 @@ is_function_cmd(char_u **cmd) /* * Read the body of a function, put every line in "newlines". + * This stops at "}", "endfunction" or "enddef". * "newlines" must already have been initialized. * "eap->cmdidx" is CMD_function, CMD_def or CMD_block; */ @@ -945,9 +946,8 @@ get_function_body( line_arg = NULL; } - // Don't define the function when skipping commands or when an error was - // detected. - if (!eap->skip && !did_emsg) + // Return OK when no error was detected. + if (!did_emsg) ret = OK; theend: @@ -960,6 +960,7 @@ theend: /* * Handle the body of a lambda. *arg points to the "{", process statements * until the matching "}". + * When not evaluating "newargs" is NULL. * When successful "rettv" is set to a funcref. */ static int @@ -974,6 +975,7 @@ lambda_function_body( char_u *ret_type) { int evaluate = (evalarg->eval_flags & EVAL_EVALUATE); + garray_T *gap = &evalarg->eval_ga; ufunc_T *ufunc = NULL; exarg_T eap; garray_T newlines; @@ -1010,6 +1012,52 @@ lambda_function_body( vim_free(cmdline); goto erret; } + + // When inside a lambda must add the function lines to evalarg.eval_ga. + evalarg->eval_break_count += newlines.ga_len; + if (gap->ga_itemsize > 0) + { + int idx; + char_u *last; + size_t plen; + char_u *pnl; + + for (idx = 0; idx < newlines.ga_len; ++idx) + { + char_u *p = skipwhite(((char_u **)newlines.ga_data)[idx]); + + if (ga_grow(gap, 1) == FAIL) + goto erret; + + // Going to concatenate the lines after parsing. For an empty or + // comment line use an empty string. + // Insert NL characters at the start of each line, the string will + // be split again later in .get_lambda_tv(). + if (*p == NUL || vim9_comment_start(p)) + p = (char_u *)""; + plen = STRLEN(p); + pnl = vim_strnsave((char_u *)"\n", plen + 1); + if (pnl != NULL) + mch_memmove(pnl + 1, p, plen + 1); + ((char_u **)gap->ga_data)[gap->ga_len] = pnl; + ++gap->ga_len; + } + if (ga_grow(gap, 1) == FAIL) + goto erret; + if (cmdline != NULL) + // more is following after the "}", which was skipped + last = cmdline; + else + // nothing is following the "}" + last = (char_u *)"}"; + plen = STRLEN(last); + pnl = vim_strnsave((char_u *)"\n", plen + 1); + if (pnl != NULL) + mch_memmove(pnl + 1, last, plen + 1); + ((char_u **)gap->ga_data)[gap->ga_len] = pnl; + ++gap->ga_len; + } + if (cmdline != NULL) { // Something comes after the "}". @@ -1022,6 +1070,12 @@ lambda_function_body( else *arg = (char_u *)""; + if (!evaluate) + { + ret = OK; + goto erret; + } + name = get_lambda_name(); ufunc = alloc_clear(offsetof(ufunc_T, uf_name) + STRLEN(name) + 1); if (ufunc == NULL) @@ -1078,7 +1132,8 @@ erret: SOURCING_LNUM = lnum_save; vim_free(line_to_free); ga_clear_strings(&newlines); - ga_clear_strings(newargs); + if (newargs != NULL) + ga_clear_strings(newargs); ga_clear_strings(default_args); if (ufunc != NULL) { @@ -1222,6 +1277,7 @@ get_lambda_tv( int len; int flags = 0; char_u *p; + char_u *line_end; char_u *name = get_lambda_name(); fp = alloc_clear(offsetof(ufunc_T, uf_name) + STRLEN(name) + 1); @@ -1236,14 +1292,37 @@ get_lambda_tv( if (ga_grow(&newlines, 1) == FAIL) goto errret; - // Add "return " before the expression. - len = 7 + (int)(end - start) + 1; + // If there are line breaks, we need to split up the string. + line_end = vim_strchr(start, '\n'); + if (line_end == NULL) + line_end = end; + + // Add "return " before the expression (or the first line). + len = 7 + (int)(line_end - start) + 1; p = alloc(len); if (p == NULL) goto errret; ((char_u **)(newlines.ga_data))[newlines.ga_len++] = p; STRCPY(p, "return "); - vim_strncpy(p + 7, start, end - start); + vim_strncpy(p + 7, start, line_end - start); + + if (line_end != end) + { + // Add more lines, split by line breaks. Thus is used when a + // lambda with { cmds } is encountered. + while (*line_end == '\n') + { + if (ga_grow(&newlines, 1) == FAIL) + goto errret; + start = line_end + 1; + line_end = vim_strchr(start, '\n'); + if (line_end == NULL) + line_end = end; + ((char_u **)(newlines.ga_data))[newlines.ga_len++] = + vim_strnsave(start, line_end - start); + } + } + if (strstr((char *)p + 7, "a:") == NULL) // No a: variables are used for sure. flags |= FC_NOARGS; diff --git a/src/version.c b/src/version.c index cf5208ffc8..fb72050651 100644 --- a/src/version.c +++ b/src/version.c @@ -750,6 +750,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 2864, /**/ 2863, /**/ From d87c21a918d8d611750f22d68fc638bf7a79b1d5 Mon Sep 17 00:00:00 2001 From: Bram Moolenaar Date: Tue, 18 May 2021 13:40:33 +0200 Subject: [PATCH 19/26] patch 8.2.2865: skipping over function body fails Problem: Skipping over function body fails. Solution: Do not define the function when skipping. --- src/userfunc.c | 5 ++++- src/version.c | 2 ++ 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/src/userfunc.c b/src/userfunc.c index b88b512c54..bc7d923843 100644 --- a/src/userfunc.c +++ b/src/userfunc.c @@ -4014,7 +4014,10 @@ define_function(exarg_T *eap, char_u *name_arg) // Save the starting line number. sourcing_lnum_top = SOURCING_LNUM; - if (get_function_body(eap, &newlines, line_arg, &line_to_free) == FAIL) + // Do not define the function when getting the body fails and when + // skipping. + if (get_function_body(eap, &newlines, line_arg, &line_to_free) == FAIL + || eap->skip) goto erret; /* diff --git a/src/version.c b/src/version.c index fb72050651..5e2a52c1a6 100644 --- a/src/version.c +++ b/src/version.c @@ -750,6 +750,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 2865, /**/ 2864, /**/ From ecb664501d3b04d124fca69029b275c520401d40 Mon Sep 17 00:00:00 2001 From: Bram Moolenaar Date: Tue, 18 May 2021 15:09:18 +0200 Subject: [PATCH 20/26] patch 8.2.2866: Vim9: memory leak when using inline function Problem: Vim9: memory leak when using inline function. Solution: Remember what strings to free. --- src/eval.c | 12 ++++++++++-- src/structs.h | 2 ++ src/userfunc.c | 13 +++++++------ src/version.c | 2 ++ 4 files changed, 21 insertions(+), 8 deletions(-) diff --git a/src/eval.c b/src/eval.c index 97c5f78dff..b5820b8d32 100644 --- a/src/eval.c +++ b/src/eval.c @@ -416,6 +416,7 @@ skip_expr_concatenate( int res; int vim9script = in_vim9script(); garray_T *gap = evalarg == NULL ? NULL : &evalarg->eval_ga; + garray_T *freegap = evalarg == NULL ? NULL : &evalarg->eval_freega; int save_flags = evalarg == NULL ? 0 : evalarg->eval_flags; int evaluate = evalarg == NULL ? FALSE : (evalarg->eval_flags & EVAL_EVALUATE); @@ -427,6 +428,7 @@ skip_expr_concatenate( // leave room for "start" if (ga_grow(gap, 1) == OK) ++gap->ga_len; + ga_init2(freegap, sizeof(char_u *), 10); } *start = *arg; @@ -444,7 +446,7 @@ skip_expr_concatenate( { if (evalarg->eval_ga.ga_len == 1) { - // just one line, no need to concatenate + // just the one line, no need to concatenate ga_clear(gap); gap->ga_itemsize = 0; } @@ -471,7 +473,13 @@ skip_expr_concatenate( ga_clear_strings(gap); } else + { ga_clear(gap); + + // free lines that were explicitly marked for freeing + ga_clear_strings(freegap); + } + gap->ga_itemsize = 0; if (p == NULL) return FAIL; @@ -3530,7 +3538,7 @@ eval7( /* * nested expression: (expression). - * lambda: (arg) => expr + * or lambda: (arg) => expr */ case '(': ret = NOTDONE; if (in_vim9script()) diff --git a/src/structs.h b/src/structs.h index 9861bb601d..3bb641be84 100644 --- a/src/structs.h +++ b/src/structs.h @@ -1881,7 +1881,9 @@ typedef struct { // Used to collect lines while parsing them, so that they can be // concatenated later. Used when "eval_ga.ga_itemsize" is not zero. // "eval_ga.ga_data" is a list of pointers to lines. + // "eval_freega" list pointers that need to be freed after concatenating. garray_T eval_ga; + garray_T eval_freega; // pointer to the last line obtained with getsourceline() char_u *eval_tofree; diff --git a/src/userfunc.c b/src/userfunc.c index bc7d923843..dd6939c9a3 100644 --- a/src/userfunc.c +++ b/src/userfunc.c @@ -976,6 +976,7 @@ lambda_function_body( { int evaluate = (evalarg->eval_flags & EVAL_EVALUATE); garray_T *gap = &evalarg->eval_ga; + garray_T *freegap = &evalarg->eval_freega; ufunc_T *ufunc = NULL; exarg_T eap; garray_T newlines; @@ -1026,7 +1027,7 @@ lambda_function_body( { char_u *p = skipwhite(((char_u **)newlines.ga_data)[idx]); - if (ga_grow(gap, 1) == FAIL) + if (ga_grow(gap, 1) == FAIL || ga_grow(freegap, 1) == FAIL) goto erret; // Going to concatenate the lines after parsing. For an empty or @@ -1039,10 +1040,10 @@ lambda_function_body( pnl = vim_strnsave((char_u *)"\n", plen + 1); if (pnl != NULL) mch_memmove(pnl + 1, p, plen + 1); - ((char_u **)gap->ga_data)[gap->ga_len] = pnl; - ++gap->ga_len; + ((char_u **)gap->ga_data)[gap->ga_len++] = pnl; + ((char_u **)freegap->ga_data)[freegap->ga_len++] = pnl; } - if (ga_grow(gap, 1) == FAIL) + if (ga_grow(gap, 1) == FAIL || ga_grow(freegap, 1) == FAIL) goto erret; if (cmdline != NULL) // more is following after the "}", which was skipped @@ -1054,8 +1055,8 @@ lambda_function_body( pnl = vim_strnsave((char_u *)"\n", plen + 1); if (pnl != NULL) mch_memmove(pnl + 1, last, plen + 1); - ((char_u **)gap->ga_data)[gap->ga_len] = pnl; - ++gap->ga_len; + ((char_u **)gap->ga_data)[gap->ga_len++] = pnl; + ((char_u **)freegap->ga_data)[freegap->ga_len++] = pnl; } if (cmdline != NULL) diff --git a/src/version.c b/src/version.c index 5e2a52c1a6..88dd5d6d97 100644 --- a/src/version.c +++ b/src/version.c @@ -750,6 +750,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 2866, /**/ 2865, /**/ From 082a3bf961efd3668d06e3137cb1ad27c3998d07 Mon Sep 17 00:00:00 2001 From: Bram Moolenaar Date: Tue, 18 May 2021 15:32:11 +0200 Subject: [PATCH 21/26] patch 8.2.2867: build failure Problem: Build failure. Solution: Add missing part of the change. --- src/globals.h | 2 +- src/version.c | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/src/globals.h b/src/globals.h index 74a7c3967f..77ea169434 100644 --- a/src/globals.h +++ b/src/globals.h @@ -1909,7 +1909,7 @@ EXTERN listitem_T range_list_item; EXTERN evalarg_T EVALARG_EVALUATE # ifdef DO_INIT = {EVAL_EVALUATE, 0, NULL, NULL, NULL, {0, 0, 0, 0, NULL}, - NULL, NULL, NULL} + {0, 0, 0, 0, NULL}, NULL, NULL, NULL} # endif ; #endif diff --git a/src/version.c b/src/version.c index 88dd5d6d97..275b231ce9 100644 --- a/src/version.c +++ b/src/version.c @@ -750,6 +750,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 2867, /**/ 2866, /**/ From cbe178e3dc4ad45d9b2ed5e713e7c4cc88bf8b8b Mon Sep 17 00:00:00 2001 From: Bram Moolenaar Date: Tue, 18 May 2021 17:49:59 +0200 Subject: [PATCH 22/26] patch 8.2.2868: Vim9: when executing compiled expression trylevel is changed Problem: Vim9: When executing a compiled expression the trylevel at start is changed but not restored. (closes #8214) Solution: Restore the trylevel at start. --- src/testdir/test_vim9_builtin.vim | 5 +- src/version.c | 2 + src/vim9execute.c | 117 ++++++++++++++++-------------- 3 files changed, 67 insertions(+), 57 deletions(-) diff --git a/src/testdir/test_vim9_builtin.vim b/src/testdir/test_vim9_builtin.vim index 2e9e0566c1..c6df6fea18 100644 --- a/src/testdir/test_vim9_builtin.vim +++ b/src/testdir/test_vim9_builtin.vim @@ -1014,12 +1014,15 @@ def Test_searchpair() try searchpairpos('(', '', ')', 'nW', '[0]->map("")') catch + g:caught = 'yes' endtry enddef Fail() END - CheckScriptFailure(lines, 'E15:') + CheckScriptSuccess(lines) + assert_equal('yes', g:caught) + unlet g:caught bwipe! enddef diff --git a/src/version.c b/src/version.c index 275b231ce9..48f7554085 100644 --- a/src/version.c +++ b/src/version.c @@ -750,6 +750,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 2868, /**/ 2867, /**/ diff --git a/src/vim9execute.c b/src/vim9execute.c index 7f56597b30..35a106f26f 100644 --- a/src/vim9execute.c +++ b/src/vim9execute.c @@ -1291,6 +1291,8 @@ exec_instructions(ectx_T *ectx) { int breakcheck_count = 0; typval_T *tv; + int ret = FAIL; + int save_trylevel_at_start = ectx->ec_trylevel_at_start; // Start execution at the first instruction. ectx->ec_iidx = 0; @@ -1312,7 +1314,7 @@ exec_instructions(ectx_T *ectx) // Turn CTRL-C into an exception. got_int = FALSE; if (throw_exception("Vim:Interrupt", ET_INTERRUPT, NULL) == FAIL) - return FAIL; + goto theend; did_throw = TRUE; } @@ -1321,7 +1323,7 @@ exec_instructions(ectx_T *ectx) // Turn an error message into an exception. did_emsg = FALSE; if (throw_exception(*msg_list, ET_ERROR, NULL) == FAIL) - return FAIL; + goto theend; did_throw = TRUE; *msg_list = NULL; } @@ -1346,7 +1348,7 @@ exec_instructions(ectx_T *ectx) // Not inside try or need to return from current functions. // Push a dummy return value. if (GA_GROW(&ectx->ec_stack, 1) == FAIL) - return FAIL; + goto theend; tv = STACK_TV_BOT(0); tv->v_type = VAR_NUMBER; tv->vval.v_number = 0; @@ -1356,12 +1358,12 @@ exec_instructions(ectx_T *ectx) // At the toplevel we are done. need_rethrow = TRUE; if (handle_closure_in_use(ectx, FALSE) == FAIL) - return FAIL; + goto theend; goto done; } if (func_return(ectx) == FAIL) - return FAIL; + goto theend; } continue; } @@ -1397,7 +1399,7 @@ exec_instructions(ectx_T *ectx) int save_flags = cmdmod.cmod_flags; if (GA_GROW(&ectx->ec_stack, 1) == FAIL) - return FAIL; + goto theend; tv = STACK_TV_BOT(0); init_tv(tv); cmdmod.cmod_flags |= CMOD_LEGACY; @@ -1413,7 +1415,7 @@ exec_instructions(ectx_T *ectx) case ISN_INSTR: { if (GA_GROW(&ectx->ec_stack, 1) == FAIL) - return FAIL; + goto theend; tv = STACK_TV_BOT(0); tv->vval.v_instr = ALLOC_ONE(instr_T); if (tv->vval.v_instr == NULL) @@ -1480,7 +1482,7 @@ exec_instructions(ectx_T *ectx) if (GA_GROW(&ectx->ec_stack, 1) == FAIL) { vim_free(res); - return FAIL; + goto theend; } tv = STACK_TV_BOT(0); tv->v_type = VAR_STRING; @@ -1545,7 +1547,7 @@ exec_instructions(ectx_T *ectx) { cmd = alloc(len + 1); if (cmd == NULL) - return FAIL; + goto theend; len = 0; } } @@ -1665,7 +1667,7 @@ exec_instructions(ectx_T *ectx) // load local variable or argument case ISN_LOAD: if (GA_GROW(&ectx->ec_stack, 1) == FAIL) - return FAIL; + goto theend; copy_tv(STACK_TV_VAR(iptr->isn_arg.number), STACK_TV_BOT(0)); ++ectx->ec_stack.ga_len; break; @@ -1673,7 +1675,7 @@ exec_instructions(ectx_T *ectx) // load v: variable case ISN_LOADV: if (GA_GROW(&ectx->ec_stack, 1) == FAIL) - return FAIL; + goto theend; copy_tv(get_vim_var_tv(iptr->isn_arg.number), STACK_TV_BOT(0)); ++ectx->ec_stack.ga_len; break; @@ -1686,10 +1688,10 @@ exec_instructions(ectx_T *ectx) sv = get_script_svar(sref, ectx); if (sv == NULL) - return FAIL; + goto theend; allocate_if_null(sv->sv_tv); if (GA_GROW(&ectx->ec_stack, 1) == FAIL) - return FAIL; + goto theend; copy_tv(sv->sv_tv, STACK_TV_BOT(0)); ++ectx->ec_stack.ga_len; } @@ -1712,7 +1714,7 @@ exec_instructions(ectx_T *ectx) else { if (GA_GROW(&ectx->ec_stack, 1) == FAIL) - return FAIL; + goto theend; copy_tv(&di->di_tv, STACK_TV_BOT(0)); ++ectx->ec_stack.ga_len; } @@ -1748,7 +1750,7 @@ exec_instructions(ectx_T *ectx) namespace = 't'; break; default: // Cannot reach here - return FAIL; + goto theend; } di = find_var_in_ht(ht, 0, iptr->isn_arg.string, TRUE); @@ -1762,7 +1764,7 @@ exec_instructions(ectx_T *ectx) else { if (GA_GROW(&ectx->ec_stack, 1) == FAIL) - return FAIL; + goto theend; copy_tv(&di->di_tv, STACK_TV_BOT(0)); ++ectx->ec_stack.ga_len; } @@ -1775,7 +1777,7 @@ exec_instructions(ectx_T *ectx) char_u *name = iptr->isn_arg.string; if (GA_GROW(&ectx->ec_stack, 1) == FAIL) - return FAIL; + goto theend; SOURCING_LNUM = iptr->isn_lnum; if (eval_variable(name, (int)STRLEN(name), STACK_TV_BOT(0), NULL, EVAL_VAR_VERBOSE) == FAIL) @@ -1799,10 +1801,10 @@ exec_instructions(ectx_T *ectx) case ISN_LOADWDICT: d = curwin->w_vars; break; case ISN_LOADTDICT: d = curtab->tp_vars; break; default: // Cannot reach here - return FAIL; + goto theend; } if (GA_GROW(&ectx->ec_stack, 1) == FAIL) - return FAIL; + goto theend; tv = STACK_TV_BOT(0); tv->v_type = VAR_DICT; tv->v_lock = 0; @@ -1821,9 +1823,9 @@ exec_instructions(ectx_T *ectx) // This is not expected to fail, name is checked during // compilation: don't set SOURCING_LNUM. if (GA_GROW(&ectx->ec_stack, 1) == FAIL) - return FAIL; + goto theend; if (eval_option(&name, &optval, TRUE) == FAIL) - return FAIL; + goto theend; *STACK_TV_BOT(0) = optval; ++ectx->ec_stack.ga_len; } @@ -1836,7 +1838,7 @@ exec_instructions(ectx_T *ectx) char_u *name = iptr->isn_arg.string; if (GA_GROW(&ectx->ec_stack, 1) == FAIL) - return FAIL; + goto theend; // name is always valid, checked when compiling (void)eval_env_var(&name, &optval, TRUE); *STACK_TV_BOT(0) = optval; @@ -1847,7 +1849,7 @@ exec_instructions(ectx_T *ectx) // load @register case ISN_LOADREG: if (GA_GROW(&ectx->ec_stack, 1) == FAIL) - return FAIL; + goto theend; tv = STACK_TV_BOT(0); tv->v_type = VAR_STRING; tv->v_lock = 0; @@ -1899,7 +1901,7 @@ exec_instructions(ectx_T *ectx) sv = get_script_svar(sref, ectx); if (sv == NULL) - return FAIL; + goto theend; --ectx->ec_stack.ga_len; // "const" and "final" are checked at compile time, locking @@ -2001,7 +2003,7 @@ exec_instructions(ectx_T *ectx) ht = &curtab->tp_vars->dv_hashtab; break; default: // Cannot reach here - return FAIL; + goto theend; } --ectx->ec_stack.ga_len; @@ -2106,7 +2108,7 @@ exec_instructions(ectx_T *ectx) goto on_error; // append to list, only fails when out of memory if (list_append_tv(list, tv) == FAIL) - return FAIL; + goto theend; clear_tv(tv); } } @@ -2141,7 +2143,7 @@ exec_instructions(ectx_T *ectx) goto on_error; // add to dict, only fails when out of memory if (dict_add_tv(dict, (char *)key, tv) == FAIL) - return FAIL; + goto theend; clear_tv(tv); } } @@ -2274,7 +2276,7 @@ exec_instructions(ectx_T *ectx) { SOURCING_LNUM = iptr->isn_lnum; iemsg("LOADOUTER depth more than scope levels"); - return FAIL; + goto theend; } tv = ((typval_T *)outer->out_stack->ga_data) + outer->out_frame_idx + STACK_FRAME_SIZE @@ -2282,7 +2284,7 @@ exec_instructions(ectx_T *ectx) if (iptr->isn_type == ISN_LOADOUTER) { if (GA_GROW(&ectx->ec_stack, 1) == FAIL) - return FAIL; + goto theend; copy_tv(tv, STACK_TV_BOT(0)); ++ectx->ec_stack.ga_len; } @@ -2444,7 +2446,7 @@ exec_instructions(ectx_T *ectx) case ISN_PUSHCHANNEL: case ISN_PUSHJOB: if (GA_GROW(&ectx->ec_stack, 1) == FAIL) - return FAIL; + goto theend; tv = STACK_TV_BOT(0); tv->v_lock = 0; ++ectx->ec_stack.ga_len; @@ -2520,7 +2522,7 @@ exec_instructions(ectx_T *ectx) // for the list header and the items case ISN_NEWLIST: if (exe_newlist(iptr->isn_arg.number, ectx) == FAIL) - return FAIL; + goto theend; break; // create a dict from items on the stack @@ -2533,7 +2535,7 @@ exec_instructions(ectx_T *ectx) int idx; if (dict == NULL) - return FAIL; + goto theend; for (idx = 0; idx < count; ++idx) { // have already checked key type is VAR_STRING @@ -2554,7 +2556,7 @@ exec_instructions(ectx_T *ectx) if (item == NULL) { dict_unref(dict); - return FAIL; + goto theend; } item->di_tv = *STACK_TV_BOT(2 * (idx - count) + 1); item->di_tv.v_lock = 0; @@ -2562,14 +2564,14 @@ exec_instructions(ectx_T *ectx) { // can this ever happen? dict_unref(dict); - return FAIL; + goto theend; } } if (count > 0) ectx->ec_stack.ga_len -= 2 * count - 1; else if (GA_GROW(&ectx->ec_stack, 1) == FAIL) - return FAIL; + goto theend; else ++ectx->ec_stack.ga_len; tv = STACK_TV_BOT(-1); @@ -2651,7 +2653,7 @@ exec_instructions(ectx_T *ectx) // return from a :def function call case ISN_RETURN_ZERO: if (GA_GROW(&ectx->ec_stack, 1) == FAIL) - return FAIL; + goto theend; tv = STACK_TV_BOT(0); ++ectx->ec_stack.ga_len; tv->v_type = VAR_NUMBER; @@ -2690,15 +2692,15 @@ exec_instructions(ectx_T *ectx) + iptr->isn_arg.funcref.fr_func; if (pt == NULL) - return FAIL; + goto theend; if (GA_GROW(&ectx->ec_stack, 1) == FAIL) { vim_free(pt); - return FAIL; + goto theend; } if (fill_partial_and_closure(pt, pt_dfunc->df_ufunc, ectx) == FAIL) - return FAIL; + goto theend; tv = STACK_TV_BOT(0); ++ectx->ec_stack.ga_len; @@ -2715,7 +2717,7 @@ exec_instructions(ectx_T *ectx) if (copy_func(newfunc->nf_lambda, newfunc->nf_global, ectx) == FAIL) - return FAIL; + goto theend; } break; @@ -2788,7 +2790,7 @@ exec_instructions(ectx_T *ectx) STACK_TV_VAR(iptr->isn_arg.forloop.for_idx); if (GA_GROW(&ectx->ec_stack, 1) == FAIL) - return FAIL; + goto theend; if (ltv->v_type == VAR_LIST) { list_T *list = ltv->vval.v_list; @@ -2884,7 +2886,7 @@ exec_instructions(ectx_T *ectx) { semsg(_(e_for_loop_on_str_not_supported), vartype_name(ltv->v_type)); - return FAIL; + goto theend; } } break; @@ -2895,7 +2897,7 @@ exec_instructions(ectx_T *ectx) trycmd_T *trycmd = NULL; if (GA_GROW(&ectx->ec_trystack, 1) == FAIL) - return FAIL; + goto theend; trycmd = ((trycmd_T *)ectx->ec_trystack.ga_data) + ectx->ec_trystack.ga_len; ++ectx->ec_trystack.ga_len; @@ -2917,10 +2919,10 @@ exec_instructions(ectx_T *ectx) { SOURCING_LNUM = iptr->isn_lnum; iemsg("Evaluating catch while current_exception is NULL"); - return FAIL; + goto theend; } if (GA_GROW(&ectx->ec_stack, 1) == FAIL) - return FAIL; + goto theend; tv = STACK_TV_BOT(0); ++ectx->ec_stack.ga_len; tv->v_type = VAR_STRING; @@ -2958,7 +2960,7 @@ exec_instructions(ectx_T *ectx) { siemsg("TRYCONT: expected %d levels, found %d", trycont->tct_levels, trystack->ga_len); - return FAIL; + goto theend; } // Make :endtry jump to any outer try block and the last // :endtry inside the loop to the loop start. @@ -3049,7 +3051,7 @@ exec_instructions(ectx_T *ectx) vim_free(tv->vval.v_string); SOURCING_LNUM = iptr->isn_lnum; emsg(_(e_throw_with_empty_string)); - return FAIL; + goto theend; } // Inside a "catch" we need to first discard the caught @@ -3072,7 +3074,7 @@ exec_instructions(ectx_T *ectx) == FAIL) { vim_free(tv->vval.v_string); - return FAIL; + goto theend; } did_throw = TRUE; } @@ -3277,7 +3279,7 @@ exec_instructions(ectx_T *ectx) goto on_error; } if (list_append_tv(l, tv2) == FAIL) - return FAIL; + goto theend; clear_tv(tv2); --ectx->ec_stack.ga_len; } @@ -3577,7 +3579,7 @@ exec_instructions(ectx_T *ectx) li = list_find(tv->vval.v_list, index); if (GA_GROW(&ectx->ec_stack, 1) == FAIL) - return FAIL; + goto theend; ++ectx->ec_stack.ga_len; copy_tv(&li->li_tv, STACK_TV_BOT(-1)); @@ -3810,7 +3812,7 @@ exec_instructions(ectx_T *ectx) goto on_error; if (GA_GROW(&ectx->ec_stack, 1) == FAIL) - return FAIL; + goto theend; ++ectx->ec_stack.ga_len; tv = STACK_TV_BOT(-1); tv->v_type = VAR_NUMBER; @@ -3912,7 +3914,7 @@ exec_instructions(ectx_T *ectx) CHECK_LIST_MATERIALIZE(l); if (GA_GROW(&ectx->ec_stack, count - 1) == FAIL) - return FAIL; + goto theend; ectx->ec_stack.ga_len += count - 1; // Variable after semicolon gets a list with the remaining @@ -3923,7 +3925,7 @@ exec_instructions(ectx_T *ectx) list_alloc_with_items(l->lv_len - count + 1); if (rem_list == NULL) - return FAIL; + goto theend; tv = STACK_TV_BOT(-count); tv->vval.v_list = rem_list; ++rem_list->lv_refcount; @@ -4007,7 +4009,7 @@ func_return: if (func_return(ectx) == FAIL) // only fails when out of memory - return FAIL; + goto theend; continue; on_error: @@ -4037,11 +4039,14 @@ on_fatal_error: // Jump here for an error that messes up the stack. // If we are not inside a try-catch started here, abort execution. if (trylevel <= ectx->ec_trylevel_at_start) - return FAIL; + goto theend; } done: - return OK; + ret = OK; +theend: + ectx->ec_trylevel_at_start = save_trylevel_at_start; + return ret; } /* From 485b62710004431a16feb4eb861365d082304a08 Mon Sep 17 00:00:00 2001 From: Bram Moolenaar Date: Tue, 18 May 2021 19:19:03 +0200 Subject: [PATCH 23/26] patch 8.2.2869: using unified diff is not tested Problem: Using unified diff is not tested. Solution: Test all cases also with unified diff. (issue #8197) --- src/testdir/test_diffmode.vim | 28 +++++++++++++++++++++++++--- src/version.c | 2 ++ 2 files changed, 27 insertions(+), 3 deletions(-) diff --git a/src/testdir/test_diffmode.vim b/src/testdir/test_diffmode.vim index d09d741498..4696456a2c 100644 --- a/src/testdir/test_diffmode.vim +++ b/src/testdir/test_diffmode.vim @@ -624,7 +624,7 @@ func Test_diffexpr() CheckExecutable diff func DiffExpr() - " Prepent some text to check diff type detection + " Prepend some text to check diff type detection call writefile(['warning', ' message'], v:fname_out) silent exe '!diff ' . v:fname_in . ' ' . v:fname_new . '>>' . v:fname_out endfunc @@ -789,9 +789,15 @@ func VerifyBoth(buf, dumpfile, extra) for cmd in [":set diffopt=filler" . a:extra . "\:", ":set diffopt+=internal\:"] call term_sendkeys(a:buf, cmd) if VerifyScreenDump(a:buf, a:dumpfile, {}, cmd =~ 'internal' ? 'internal' : 'external') - break " don't let the next iteration overwrite the "failed" file. + " don't let the next iteration overwrite the "failed" file. + return endif endfor + + " also test unified diff + call term_sendkeys(a:buf, ":call SetupUnified()\:") + call VerifyScreenDump(a:buf, a:dumpfile, {}, 'unified') + call term_sendkeys(a:buf, ":call StopUnified()\:") endfunc " Verify a screendump with the internal diff only. @@ -807,13 +813,28 @@ func Test_diff_screen() CheckScreendump CheckFeature menu + let lines =<< trim END + func UnifiedDiffExpr() + " Prepend some text to check diff type detection + call writefile(['warning', ' message'], v:fname_out) + silent exe '!diff -u ' .. v:fname_in .. ' ' .. v:fname_new .. '>>' .. v:fname_out + endfunc + func SetupUnified() + set diffexpr=UnifiedDiffExpr() + endfunc + func StopUnified() + set diffexpr= + endfunc + END + call writefile(lines, 'XdiffSetup') + " clean up already existing swap files, just in case call delete('.Xfile1.swp') call delete('.Xfile2.swp') " Test 1: Add a line in beginning of file 2 call WriteDiffFiles(0, [1, 2, 3, 4, 5, 6, 7, 8, 9, 10], [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10]) - let buf = RunVimInTerminal('-d Xfile1 Xfile2', {}) + let buf = RunVimInTerminal('-d -S XdiffSetup Xfile1 Xfile2', {}) " Set autoread mode, so that Vim won't complain once we re-write the test " files call term_sendkeys(buf, ":set autoread\\w:set autoread\\w") @@ -933,6 +954,7 @@ func Test_diff_screen() call StopVimInTerminal(buf) call delete('Xfile1') call delete('Xfile2') + call delete('XdiffSetup') endfunc func Test_diff_with_cursorline() diff --git a/src/version.c b/src/version.c index 48f7554085..0b17d91af4 100644 --- a/src/version.c +++ b/src/version.c @@ -750,6 +750,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 2869, /**/ 2868, /**/ From 796139ae3ac89e27ee96dce3c7fdb87d8c839f53 Mon Sep 17 00:00:00 2001 From: Bram Moolenaar Date: Tue, 18 May 2021 21:38:45 +0200 Subject: [PATCH 24/26] patch 8.2.2870: CmdlineChange event triggered twice for CTRL-R Problem: CmdlineChange event triggered twice for CTRL-R. Solution: Return CMDLINE_NOT_CHANGED from cmdline_insert_reg(). (closes #8219) --- src/ex_getln.c | 5 ++++- src/testdir/test_cmdline.vim | 6 ++++++ src/version.c | 2 ++ 3 files changed, 12 insertions(+), 1 deletion(-) diff --git a/src/ex_getln.c b/src/ex_getln.c index 4ebc341109..e7d71a510f 100644 --- a/src/ex_getln.c +++ b/src/ex_getln.c @@ -1253,8 +1253,11 @@ cmdline_insert_reg(int *gotesc UNUSED) } #endif } + // remove the double quote redrawcmd(); - return CMDLINE_CHANGED; + + // The text has been stuffed, the command line didn't change yet. + return CMDLINE_NOT_CHANGED; } /* diff --git a/src/testdir/test_cmdline.vim b/src/testdir/test_cmdline.vim index 5ed283f1fa..bba7e725e9 100644 --- a/src/testdir/test_cmdline.vim +++ b/src/testdir/test_cmdline.vim @@ -1810,6 +1810,12 @@ func Test_cmd_map_cmdlineChanged() call feedkeys(":\\", 'xt') call assert_equal(['l', 'ls'], g:log) + let @b = 'b' + cnoremap ab + let g:log = [] + call feedkeys(":\\", 'xt') + call assert_equal(['a', 'ab'], g:log) + unlet g:log cunmap augroup test diff --git a/src/version.c b/src/version.c index 0b17d91af4..edc95e5610 100644 --- a/src/version.c +++ b/src/version.c @@ -750,6 +750,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 2870, /**/ 2869, /**/ From 4781d6fd8670af415c3b78f00d70036af85bd286 Mon Sep 17 00:00:00 2001 From: Dominique Pelle Date: Tue, 18 May 2021 21:46:31 +0200 Subject: [PATCH 25/26] patch 8.2.2871: unnessary VIM_ISDIGIT() calls, badly indented code MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Problem: Unnessary VIM_ISDIGIT() calls, badly indented code. Solution: Call skipdigits() on the next character. Improve indenting. (Dominique Pellé, closes #8227) --- src/charset.c | 6 ++---- src/evalfunc.c | 6 +++--- src/ex_docmd.c | 4 ++-- src/json.c | 2 +- src/ops.c | 9 +++++---- src/tag.c | 2 +- src/version.c | 2 ++ src/vim9compile.c | 10 +++++----- 8 files changed, 21 insertions(+), 20 deletions(-) diff --git a/src/charset.c b/src/charset.c index 10aa2e8e52..fcaeedf757 100644 --- a/src/charset.c +++ b/src/charset.c @@ -169,8 +169,7 @@ buf_init_chartab( } if (VIM_ISDIGIT(*p)) c = getdigits(&p); - else - if (has_mbyte) + else if (has_mbyte) c = mb_ptr2char_adv(&p); else c = *p++; @@ -180,8 +179,7 @@ buf_init_chartab( ++p; if (VIM_ISDIGIT(*p)) c2 = getdigits(&p); - else - if (has_mbyte) + else if (has_mbyte) c2 = mb_ptr2char_adv(&p); else c2 = *p++; diff --git a/src/evalfunc.c b/src/evalfunc.c index e740f91b13..16447aba25 100644 --- a/src/evalfunc.c +++ b/src/evalfunc.c @@ -9674,9 +9674,9 @@ f_synIDattr(typval_T *argvars UNUSED, typval_T *rettv) else #endif if (t_colors > 1) - modec = 'c'; - else - modec = 't'; + modec = 'c'; + else + modec = 't'; } switch (TOLOWER_ASC(what[0])) diff --git a/src/ex_docmd.c b/src/ex_docmd.c index 7811c8f7f3..2738f4f4d1 100644 --- a/src/ex_docmd.c +++ b/src/ex_docmd.c @@ -2384,7 +2384,7 @@ do_one_cmd( * count, it's a buffer name. */ if ((ea.argt & EX_COUNT) && VIM_ISDIGIT(*ea.arg) - && (!(ea.argt & EX_BUFNAME) || *(p = skipdigits(ea.arg)) == NUL + && (!(ea.argt & EX_BUFNAME) || *(p = skipdigits(ea.arg + 1)) == NUL || VIM_ISWHITE(*p))) { n = getdigits(&ea.arg); @@ -3730,7 +3730,7 @@ modifier_len(char_u *cmd) char_u *p = cmd; if (VIM_ISDIGIT(*cmd)) - p = skipwhite(skipdigits(cmd)); + p = skipwhite(skipdigits(cmd + 1)); for (i = 0; i < (int)(sizeof(cmdmods) / sizeof(struct cmdmod)); ++i) { for (j = 0; p[j] != NUL; ++j) diff --git a/src/json.c b/src/json.c index 25349b7551..db25b70cc4 100644 --- a/src/json.c +++ b/src/json.c @@ -607,7 +607,7 @@ json_decode_item(js_read_T *reader, typval_T *res, int options) cur_item = res; init_tv(&item); if (res != NULL) - init_tv(res); + init_tv(res); fill_numbuflen(reader); p = reader->js_buf + reader->js_used; diff --git a/src/ops.c b/src/ops.c index d8e96ff1a4..e4590a1e75 100644 --- a/src/ops.c +++ b/src/ops.c @@ -3985,12 +3985,13 @@ do_pending_operator(cmdarg_T *cap, int old_col, int gui_yank) op_formatexpr(oap); // use expression else #endif + { if (*p_fp != NUL || *curbuf->b_p_fp != NUL) - op_colon(oap); // use external command - else - op_format(oap, FALSE); // use internal function + op_colon(oap); // use external command + else + op_format(oap, FALSE); // use internal function + } break; - case OP_FORMAT2: op_format(oap, TRUE); // use internal function break; diff --git a/src/tag.c b/src/tag.c index 4eb7a4f434..256f885c82 100644 --- a/src/tag.c +++ b/src/tag.c @@ -3824,7 +3824,7 @@ find_extra(char_u **pp) for (;;) { if (VIM_ISDIGIT(*str)) - str = skipdigits(str); + str = skipdigits(str + 1); else if (*str == '/' || *str == '?') { str = skip_regexp(str + 1, *str, FALSE); diff --git a/src/version.c b/src/version.c index edc95e5610..8d73f68c09 100644 --- a/src/version.c +++ b/src/version.c @@ -750,6 +750,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 2871, /**/ 2870, /**/ diff --git a/src/vim9compile.c b/src/vim9compile.c index 160c8e428f..5e912dd881 100644 --- a/src/vim9compile.c +++ b/src/vim9compile.c @@ -8341,11 +8341,11 @@ compile_endtry(char_u *arg, cctx_T *cctx) } #ifdef FEAT_PROFILE - if (cctx->ctx_profiling && ((isn_T *)instr->ga_data)[instr->ga_len - 1] - .isn_type == ISN_PROF_START) - // move the profile start after "endtry" so that it's not counted when - // the exception is rethrown. - --instr->ga_len; + if (cctx->ctx_profiling && ((isn_T *)instr->ga_data)[instr->ga_len - 1] + .isn_type == ISN_PROF_START) + // move the profile start after "endtry" so that it's not counted when + // the exception is rethrown. + --instr->ga_len; #endif // Fill in the "end" label in jumps at the end of the blocks, if not From 56c9fd01076bc62b55c8cb89d8a66f6136e52f3a Mon Sep 17 00:00:00 2001 From: Dominique Pelle Date: Wed, 19 May 2021 00:16:14 +0200 Subject: [PATCH 26/26] patch 8.2.2872: Python tests fail without the channel feature MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Problem: Python tests fail without the channel feature. Solution: Add a feature check. (Dominique Pellé, closes #8226) --- src/testdir/test_python2.vim | 8 ++++++-- src/testdir/test_python3.vim | 8 ++++++-- src/version.c | 2 ++ 3 files changed, 14 insertions(+), 4 deletions(-) diff --git a/src/testdir/test_python2.vim b/src/testdir/test_python2.vim index cf35a50b32..84c917316d 100644 --- a/src/testdir/test_python2.vim +++ b/src/testdir/test_python2.vim @@ -814,8 +814,12 @@ func Test_python_vim_bindeval() call assert_equal(v:none, pyeval("vim.bindeval('v:none')")) " channel/job - call assert_equal(v:none, pyeval("vim.bindeval('test_null_channel()')")) - call assert_equal(v:none, pyeval("vim.bindeval('test_null_job()')")) + if has('channel') + call assert_equal(v:none, pyeval("vim.bindeval('test_null_channel()')")) + endif + if has('job') + call assert_equal(v:none, pyeval("vim.bindeval('test_null_job()')")) + endif endfunc " threading diff --git a/src/testdir/test_python3.vim b/src/testdir/test_python3.vim index 58b6427f3e..1e9ef82b07 100644 --- a/src/testdir/test_python3.vim +++ b/src/testdir/test_python3.vim @@ -1007,8 +1007,12 @@ func Test_python3_vim_bindeval() call assert_equal(v:none, py3eval("vim.bindeval('v:none')")) " channel/job - call assert_equal(v:none, py3eval("vim.bindeval('test_null_channel()')")) - call assert_equal(v:none, py3eval("vim.bindeval('test_null_job()')")) + if has('channel') + call assert_equal(v:none, py3eval("vim.bindeval('test_null_channel()')")) + endif + if has('job') + call assert_equal(v:none, py3eval("vim.bindeval('test_null_job()')")) + endif endfunc " threading diff --git a/src/version.c b/src/version.c index 8d73f68c09..af4046250c 100644 --- a/src/version.c +++ b/src/version.c @@ -750,6 +750,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 2872, /**/ 2871, /**/