From 4da6df40f5a637de42cad8e6939dfe8463b211db Mon Sep 17 00:00:00 2001 From: Bram Moolenaar Date: Mon, 20 Apr 2020 16:12:09 +0200 Subject: [PATCH 001/230] patch 8.2.0608: warning from clang when building message test Problem: Warning from clang when building message test. Solution: Use a void pointer. (Dominique Pelle, closes #5958) --- src/message_test.c | 2 +- src/version.c | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/src/message_test.c b/src/message_test.c index 014d8d9d45..85a29b4712 100644 --- a/src/message_test.c +++ b/src/message_test.c @@ -127,7 +127,7 @@ test_vim_snprintf(void) int n; size_t bsize; int bsize_int; - char *ptr = (char *)0x87654321; + void *ptr = (void *)0x87654321; // Loop on various buffer sizes to make sure that truncation of // vim_snprintf() is correct. diff --git a/src/version.c b/src/version.c index f175ff3d2f..2b1a126092 100644 --- a/src/version.c +++ b/src/version.c @@ -746,6 +746,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 608, /**/ 607, /**/ From ad4dc83389931a0354c3691b42f99a5bb98c766f Mon Sep 17 00:00:00 2001 From: Bram Moolenaar Date: Mon, 20 Apr 2020 16:21:53 +0200 Subject: [PATCH 002/230] patch 8.2.0609: configure does not detect moonjit correctly Problem: Configure does not detect moonjit correctly. Solution: Double the brackets. (Ozaki Kiichi) --- src/auto/configure | 2 +- src/configure.ac | 2 +- src/version.c | 2 ++ 3 files changed, 4 insertions(+), 2 deletions(-) diff --git a/src/auto/configure b/src/auto/configure index b6d4bf975d..bd26a7c590 100755 --- a/src/auto/configure +++ b/src/auto/configure @@ -5485,7 +5485,7 @@ $as_echo "no" >&6; } # https://groups.google.com/forum/#!topic/vim_use/O0vek60WuTk lua_suf=/moonjit-2.3 inc_path="$vi_cv_path_lua_pfx/include" - for dir in "$inc_path"/moonjit-0-9* ; do + for dir in "$inc_path"/moonjit-[0-9]* ; do if test -d "$dir" ; then lua_suf=`basename '$dir'` lua_suf="/$lua_suf" diff --git a/src/configure.ac b/src/configure.ac index ebb79ced64..2037de74fa 100644 --- a/src/configure.ac +++ b/src/configure.ac @@ -630,7 +630,7 @@ if test "$enable_luainterp" = "yes" -o "$enable_luainterp" = "dynamic"; then # https://groups.google.com/forum/#!topic/vim_use/O0vek60WuTk lua_suf=/moonjit-2.3 inc_path="$vi_cv_path_lua_pfx/include" - for dir in "$inc_path"/moonjit-[0-9]* ; do + for dir in "$inc_path"/moonjit-[[0-9]]* ; do if test -d "$dir" ; then lua_suf=`basename '$dir'` lua_suf="/$lua_suf" diff --git a/src/version.c b/src/version.c index 2b1a126092..61f71a0c1d 100644 --- a/src/version.c +++ b/src/version.c @@ -746,6 +746,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 609, /**/ 608, /**/ From 08f4157c5cabc55bcb22f04dd7c717aba40caa34 Mon Sep 17 00:00:00 2001 From: Bram Moolenaar Date: Mon, 20 Apr 2020 16:50:00 +0200 Subject: [PATCH 003/230] patch 8.2.0610: some tests are still old style Problem: Some tests are still old style. Solution: Convert to new style tests. (Yegappan Lakshmanan, closes #5957) --- src/testdir/test_blob.vim | 3 + src/testdir/test_cursor_func.vim | 2 + src/testdir/test_eval.in | 92 ------------------------------- src/testdir/test_eval.ok | Bin 7988 -> 6716 bytes src/testdir/test_eval_func.vim | 10 ---- src/testdir/test_eval_stuff.vim | 12 +++- src/testdir/test_expr.vim | 1 + src/testdir/test_filter_map.vim | 10 +++- src/testdir/test_functions.vim | 19 +++++++ src/testdir/test_listdict.vim | 44 ++++++++++++++- src/testdir/test_sort.vim | 2 +- src/testdir/test_syntax.vim | 4 ++ src/testdir/test_utf8.vim | 3 + src/testdir/test_vimscript.vim | 80 +++++++++++++++++++++++++++ src/version.c | 2 + 15 files changed, 178 insertions(+), 106 deletions(-) delete mode 100644 src/testdir/test_eval_func.vim diff --git a/src/testdir/test_blob.vim b/src/testdir/test_blob.vim index 0170f547fa..e2c332a8a6 100644 --- a/src/testdir/test_blob.vim +++ b/src/testdir/test_blob.vim @@ -307,6 +307,9 @@ func Test_blob_insert() call assert_fails('call insert(b, -1)', 'E475:') call assert_fails('call insert(b, 257)', 'E475:') call assert_fails('call insert(b, 0, [9])', 'E745:') + call assert_fails('call insert(b, 0, -20)', 'E475:') + call assert_fails('call insert(b, 0, 20)', 'E475:') + call assert_fails('call insert(b, [])', 'E745:') endfunc func Test_blob_reverse() diff --git a/src/testdir/test_cursor_func.vim b/src/testdir/test_cursor_func.vim index 0afc45e588..7a17958335 100644 --- a/src/testdir/test_cursor_func.vim +++ b/src/testdir/test_cursor_func.vim @@ -115,3 +115,5 @@ func Test_screenpos_number() close bwipe! endfunc + +" vim: shiftwidth=2 sts=2 expandtab diff --git a/src/testdir/test_eval.in b/src/testdir/test_eval.in index e1f4f6de9f..ebe1874102 100644 --- a/src/testdir/test_eval.in +++ b/src/testdir/test_eval.in @@ -27,14 +27,6 @@ endfun execute "silent normal! Go==\n==\e\"".a:1."P" endif endfun -:fun ErrExe(str) - call append('$', 'Executing '.a:str) - try - execute a:str - catch - $put =v:exception - endtry -endfun :fun Test() $put ='{{{1 Appending NL with setreg()' call setreg('a', 'abcA2', 'c') @@ -109,103 +101,19 @@ else call AppendRegParts('*', 'V', "clipboard contents\n", "['clipboard contents']", "clipboard contents\n", "['clipboard contents']") call AppendRegParts('*', 'V', "something else\n", "['something else']", "something else\n", "['something else']") endif -$put ='{{{1 Errors' -call ErrExe('call setreg()') -call ErrExe('call setreg(1)') -call ErrExe('call setreg(1, 2, 3, 4)') -call ErrExe('call setreg([], 2)') -call ErrExe('call setreg(1, {})') -call ErrExe('call setreg(1, 2, [])') -call ErrExe('call setreg("/", ["1", "2"])') -call ErrExe('call setreg("=", ["1", "2"])') -call ErrExe('call setreg(1, ["", "", [], ""])') endfun :" :call Test() :" :delfunction SetReg :delfunction AppendRegContents -:delfunction ErrExe :delfunction Test :delcommand AR :call garbagecollect(1) :" -:" function name not starting with capital -:try -:func! g:test() -:echo "test" -:endfunc -:catch -:$put =v:exception -:endtry -:" -:" function name includes a colon -:try -:func! b:test() -:echo "test" -:endfunc -:catch -:$put =v:exception -:endtry -:" -:" function name folowed by # -:try -:func! test2() "# -:echo "test2" -:endfunc -:catch -:$put =v:exception -:endtry -:" -:" function name starting with/without "g:", buffer-local funcref. -:function! g:Foo(n) -: $put ='called Foo(' . a:n . ')' -:endfunction -:let b:my_func = function('Foo') -:call b:my_func(1) -:echo g:Foo(2) -:echo Foo(3) -:" -:" script-local function used in Funcref must exist. -:so test_eval_func.vim -:" -:" Using $ instead of '$' must give an error -:try -: call append($, 'foobar') -:catch -:$put =v:exception -:endtry -:" -:$put ='{{{1 getcurpos/setpos' -/^012345678 -6l:let sp = getcurpos() -0:call setpos('.', sp) -jyl:$put -:" -:" substring and variable name -:let str = 'abcdef' -:let n = 3 -:$put =str[n:] -:$put =str[:n] -:$put =str[n:n] -:unlet n -:let nn = 3 -:$put =str[nn:] -:$put =str[:nn] -:$put =str[nn:nn] -:unlet nn -:let b:nn = 4 -:$put =str[b:nn:] -:$put =str[:b:nn] -:$put =str[b:nn:b:nn] -:unlet b:nn -:" :/^start:/+1,$wq! test.out :" vim: et ts=4 isk-=\: fmr=???,??? :call getchar() ENDTEST -012345678 -012345678 - start: diff --git a/src/testdir/test_eval.ok b/src/testdir/test_eval.ok index cb7c85e254424dccda4ff03df0a4d11b3655bbfa..3ae6f6c67184852ca66d7e73d7a9552d12de5bca 100644 GIT binary patch delta 7 OcmdmDx5s3IjT8V4g#zgS delta 1290 zcmc(fL5mYH6vx41K7yx5ytGi*owlrFP!D1k1o7hHrR*U)^Ew-uNrvQ&yGxOLB@Z6= z!}&5)+m5YN5M&NX9?5Usd-?zKIRF0o+smhMy1m;_K z&(0NGIR}ll4+pZ1C#1W)X7(QS`RrUl7gDF*n?RrgX!uB;1IJ39!20Wekuf9okhi99 zoA#XIDJZUVc|D;0ZAS7;G9}842RW7dxICYwJJi0og;o=xx1enac;9*qfv*@?8eBSh z?(73tRz%?}X=8!z9IzG|=MidS@tCgUEBI7f19CYDN*PJ}@Q|?J; zQ`Xt#M*d)RgV1!Wj6m8G+!PRl3`Q%bPuXbke1NS4PEE}a{(V|P|;hMm=HEP}e?W1o@r!I}sP&P6H)ev4<~ zjrPBGWnvZ6w*A=NYjdICo&BO~QywsH@-FDMMO%vg9jlOv&bKa{@!Q3NxDX|-guW?C N!QXbenW1=s;s?oVt+4 \" . v:val')", 'E712:') + call assert_fails("let l = filter('abc', '\"> \" . v:val')", 'E712:') + call assert_fails("let l = filter([1, 2, 3], '{}')", 'E728:') + call assert_fails("let l = filter({'k' : 10}, '{}')", 'E728:') + call assert_equal(0, map(test_null_list(), '"> " .. v:val')) + call assert_equal(0, map(test_null_dict(), '"> " .. v:val')) endfunc func Test_map_and_modify() @@ -103,3 +109,5 @@ func Test_map_and_modify() call assert_fails('call map(d, "remove(d, v:key)[0]")', 'E741:') call assert_fails('echo map(d, {k,v -> remove(d, k)})', 'E741:') endfunc + +" vim: shiftwidth=2 sts=2 expandtab diff --git a/src/testdir/test_functions.vim b/src/testdir/test_functions.vim index 3b9e34c191..f7a438af72 100644 --- a/src/testdir/test_functions.vim +++ b/src/testdir/test_functions.vim @@ -99,9 +99,11 @@ func Test_len() call assert_equal(2, len('ab')) call assert_equal(0, len([])) + call assert_equal(0, len(test_null_list())) call assert_equal(2, len([2, 1])) call assert_equal(0, len({})) + call assert_equal(0, len(test_null_dict())) call assert_equal(2, len({'a': 1, 'b': 2})) call assert_fails('call len(v:none)', 'E701:') @@ -799,6 +801,9 @@ func Test_append() split only undo + + " Using $ instead of '$' must give an error + call assert_fails("call append($, 'foobar')", 'E116:') endfunc func Test_getbufvar() @@ -2043,6 +2048,7 @@ func Test_range() " list2str() call assert_equal('ABC', list2str(range(65, 67))) + call assert_fails('let s = list2str(5)', 'E474:') " lock() let thelist = range(5) @@ -2216,4 +2222,17 @@ func Test_screen_functions() call assert_equal([], screenchars(-1, -1)) endfunc +" Test for getcurpos() and setpos() +func Test_getcurpos_setpos() + new + call setline(1, ['012345678', '012345678']) + normal gg6l + let sp = getcurpos() + normal 0 + call setpos('.', sp) + normal jyl + call assert_equal('6', @") + close! +endfunc + " vim: shiftwidth=2 sts=2 expandtab diff --git a/src/testdir/test_listdict.vim b/src/testdir/test_listdict.vim index 9db103545b..c6d6885ec4 100644 --- a/src/testdir/test_listdict.vim +++ b/src/testdir/test_listdict.vim @@ -32,6 +32,7 @@ func Test_list_slice() call assert_equal([1, 'as''d', [1, 2, function('strlen')], {'a': 1}], l[0:8]) call assert_equal([], l[8:-1]) call assert_equal([], l[0:-10]) + call assert_equal([], test_null_list()[:2]) endfunc " List identity @@ -168,6 +169,19 @@ func Test_dict() call assert_equal({'c': 'ccc', '1': 99, 'b': [1, 2, function('strlen')], '3': 33, '-1': {'a': 1}}, d) call filter(d, 'v:key =~ ''[ac391]''') call assert_equal({'c': 'ccc', '1': 99, '3': 33, '-1': {'a': 1}}, d) + + " duplicate key + call assert_fails("let d = {'k' : 10, 'k' : 20}", 'E721:') + " missing comma + call assert_fails("let d = {'k' : 10 'k' : 20}", 'E722:') + " missing curly brace + call assert_fails("let d = {'k' : 10,", 'E723:') + " invalid key + call assert_fails('let d = #{++ : 10}', 'E15:') + " wrong type for key + call assert_fails('let d={[] : 10}', 'E730:') + " undefined variable as value + call assert_fails("let d={'k' : i}", 'E121:') endfunc " Dictionary identity @@ -262,7 +276,7 @@ func Test_script_local_dict_func() unlet g:dict endfunc -" Test removing items in la dictionary +" Test removing items in a dictionary func Test_dict_func_remove() let d = {1:'a', 2:'b', 3:'c'} call assert_equal('b', remove(d, 2)) @@ -634,6 +648,11 @@ func Test_reverse_sort_uniq() call assert_fails('call reverse("")', 'E899:') call assert_fails('call uniq([1, 2], {x, y -> []})', 'E882:') + call assert_fails("call sort([1, 2], function('min'), 1)", "E715:") + call assert_fails("call sort([1, 2], function('invalid_func'))", "E700:") + call assert_fails("call sort([1, 2], function('min'))", "E702:") + call assert_equal(0, sort(test_null_list())) + call assert_equal(0, uniq(test_null_list())) endfunc " splitting a string to a List using split() @@ -748,6 +767,9 @@ func Test_listdict_extend() call assert_fails("call extend([1, 2], 1)", 'E712:') call assert_fails("call extend([1, 2], {})", 'E712:') + + " Extend g: dictionary with an invalid variable name + call assert_fails("call extend(g:, {'-!' : 10})", 'E461:') endfunc func s:check_scope_dict(x, fixed) @@ -871,6 +893,26 @@ func Test_listdict_index() call assert_fails("let v = range(5)[2:[]]", 'E730:') call assert_fails("let v = range(5)[2:{-> 2}(]", 'E116:') call assert_fails("let v = range(5)[2:3", 'E111:') + call assert_fails("let l = insert([1,2,3], 4, 10)", 'E684:') + call assert_fails("let l = insert([1,2,3], 4, -10)", 'E684:') + call assert_fails("let l = insert([1,2,3], 4, [])", 'E745:') +endfunc + +" Test for a null list +func Test_null_list() + call assert_equal(0, join(test_null_list())) + call assert_fails('let s = join([1, 2], [])', 'E730:') + call assert_equal([], split(test_null_string())) +endfunc + +" Test for a null dict +func Test_null_dict() + call assert_equal(0, items(test_null_dict())) + call assert_equal(0, keys(test_null_dict())) + call assert_equal(0, values(test_null_dict())) + call assert_false(has_key(test_null_dict(), 'k')) + call assert_fails("let l = [] + test_null_list()", 'E15:') + call assert_fails("let l = test_null_list() + []", 'E15:') endfunc " vim: shiftwidth=2 sts=2 expandtab diff --git a/src/testdir/test_sort.vim b/src/testdir/test_sort.vim index 8299db4ef8..92e8f49d48 100644 --- a/src/testdir/test_sort.vim +++ b/src/testdir/test_sort.vim @@ -47,7 +47,7 @@ func Test_sort_default() call assert_equal(['2', 'A', 'AA', 'a', 1, 3.3], sort([3.3, 1, "2", "A", "a", "AA"], '')) call assert_equal(['2', 'A', 'AA', 'a', 1, 3.3], sort([3.3, 1, "2", "A", "a", "AA"], 0)) call assert_equal(['2', 'A', 'a', 'AA', 1, 3.3], sort([3.3, 1, "2", "A", "a", "AA"], 1)) - call assert_fails('call sort([3.3, 1, "2"], 3)', "E474") + call assert_fails('call sort([3.3, 1, "2"], 3)', "E474:") endfunc " Tests for the ":sort" command. diff --git a/src/testdir/test_syntax.vim b/src/testdir/test_syntax.vim index 50e1a59b3c..024ba59a40 100644 --- a/src/testdir/test_syntax.vim +++ b/src/testdir/test_syntax.vim @@ -151,6 +151,10 @@ func Test_syntax_list() let a = execute('syntax list') call assert_equal("\nNo Syntax items defined for this buffer", a) + syntax keyword Type int containedin=g1 skipwhite skipempty skipnl nextgroup=Abc + let exp = "Type xxx containedin=g1 nextgroup=Abc skipnl skipwhite skipempty int" + call assert_equal(exp, split(execute("syntax list"), "\n")[1]) + bd endfunc diff --git a/src/testdir/test_utf8.vim b/src/testdir/test_utf8.vim index fa6f76a610..e83a3d04d3 100644 --- a/src/testdir/test_utf8.vim +++ b/src/testdir/test_utf8.vim @@ -103,6 +103,9 @@ func Test_list2str_str2list_latin1() let sres = list2str(l, 1) call assert_equal([65, 66, 67], str2list("ABC")) + " Try converting a list to a string in latin-1 encoding + call assert_equal([1, 2, 3], str2list(list2str([1, 2, 3]))) + let &encoding = save_encoding call assert_equal(l, lres) call assert_equal(s, sres) diff --git a/src/testdir/test_vimscript.vim b/src/testdir/test_vimscript.vim index cef45050be..7c86836619 100644 --- a/src/testdir/test_vimscript.vim +++ b/src/testdir/test_vimscript.vim @@ -1980,6 +1980,86 @@ func Test_float_conversion_errors() endif endfunc +func Test_invalid_function_names() + " function name not starting with capital + let caught_e128 = 0 + try + func! g:test() + echo "test" + endfunc + catch /E128:/ + let caught_e128 = 1 + endtry + call assert_equal(1, caught_e128) + + " function name includes a colon + let caught_e884 = 0 + try + func! b:test() + echo "test" + endfunc + catch /E884:/ + let caught_e884 = 1 + endtry + call assert_equal(1, caught_e884) + + " function name folowed by # + let caught_e128 = 0 + try + func! test2() "# + echo "test2" + endfunc + catch /E128:/ + let caught_e128 = 1 + endtry + call assert_equal(1, caught_e128) + + " function name starting with/without "g:", buffer-local funcref. + function! g:Foo(n) + return 'called Foo(' . a:n . ')' + endfunction + let b:my_func = function('Foo') + call assert_equal('called Foo(1)', b:my_func(1)) + call assert_equal('called Foo(2)', g:Foo(2)) + call assert_equal('called Foo(3)', Foo(3)) + delfunc g:Foo + + " script-local function used in Funcref must exist. + let lines =<< trim END + func s:Testje() + return "foo" + endfunc + let Bar = function('s:Testje') + call assert_equal(0, exists('s:Testje')) + call assert_equal(1, exists('*s:Testje')) + call assert_equal(1, exists('Bar')) + call assert_equal(1, exists('*Bar')) + END + call writefile(lines, 'Xscript') + source Xscript + call delete('Xscript') +endfunc + +" substring and variable name +func Test_substring_var() + let str = 'abcdef' + let n = 3 + call assert_equal('def', str[n:]) + call assert_equal('abcd', str[:n]) + call assert_equal('d', str[n:n]) + unlet n + let nn = 3 + call assert_equal('def', str[nn:]) + call assert_equal('abcd', str[:nn]) + call assert_equal('d', str[nn:nn]) + unlet nn + let b:nn = 4 + call assert_equal('ef', str[b:nn:]) + call assert_equal('abcde', str[:b:nn]) + call assert_equal('e', str[b:nn:b:nn]) + unlet b:nn +endfunc + "------------------------------------------------------------------------------- " Modelines {{{1 " vim: ts=8 sw=2 sts=2 expandtab tw=80 fdm=marker diff --git a/src/version.c b/src/version.c index 61f71a0c1d..1c5ad56246 100644 --- a/src/version.c +++ b/src/version.c @@ -746,6 +746,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 610, /**/ 609, /**/ From faac410409a8d693a0326ad9db42dca85419a391 Mon Sep 17 00:00:00 2001 From: Bram Moolenaar Date: Mon, 20 Apr 2020 17:46:14 +0200 Subject: [PATCH 004/230] patch 8.2.0611: Vim9: no check for space before #comment Problem: Vim9: no check for space before #comment. Solution: Add space checks. --- src/eval.c | 2 +- src/evalvars.c | 4 +- src/ex_docmd.c | 2 +- src/testdir/test_vim9_script.vim | 63 ++++++++++++++++++++++++++++++++ src/version.c | 2 + 5 files changed, 69 insertions(+), 4 deletions(-) diff --git a/src/eval.c b/src/eval.c index 94ecf936e4..43c20086c2 100644 --- a/src/eval.c +++ b/src/eval.c @@ -1773,7 +1773,7 @@ eval0( p = skipwhite(arg); ret = eval1(&p, rettv, evaluate); - if (ret == FAIL || !ends_excmd(*p)) + if (ret == FAIL || !ends_excmd2(arg, p)) { if (ret != FAIL) clear_tv(rettv); diff --git a/src/evalvars.c b/src/evalvars.c index b5075d59cc..1d0599f5ae 100644 --- a/src/evalvars.c +++ b/src/evalvars.c @@ -737,7 +737,7 @@ ex_let_const(exarg_T *eap, int is_const) emsg(_(e_invarg)); else if (expr[0] == '.') emsg(_("E985: .= is not supported with script version 2")); - else if (!ends_excmd(*arg)) + else if (!ends_excmd2(eap->cmd, arg)) // ":let var1 var2" arg = list_arg_vars(eap, arg, &first); else if (!eap->skip) @@ -1068,7 +1068,7 @@ list_arg_vars(exarg_T *eap, char_u *arg, int *first) char_u *tofree; typval_T tv; - while (!ends_excmd(*arg) && !got_int) + while (!ends_excmd2(eap->cmd, arg) && !got_int) { if (error || eap->skip) { diff --git a/src/ex_docmd.c b/src/ex_docmd.c index e2d771e194..43cd013e2c 100644 --- a/src/ex_docmd.c +++ b/src/ex_docmd.c @@ -7903,7 +7903,7 @@ ex_findpat(exarg_T *eap) p = skipwhite(p); // Check for trailing illegal characters - if (!ends_excmd(*p)) + if (!ends_excmd2(eap->arg, p)) eap->errmsg = e_trailing; else eap->nextcmd = check_nextcmd(p); diff --git a/src/testdir/test_vim9_script.vim b/src/testdir/test_vim9_script.vim index 4b7339961f..70653f0332 100644 --- a/src/testdir/test_vim9_script.vim +++ b/src/testdir/test_vim9_script.vim @@ -1208,6 +1208,69 @@ def Test_vim9_comment_not_compiled() 'let g:var = 123', 'unlet g:var # something', ], 'E488:') + + CheckScriptSuccess([ + 'vim9script', + 'if 1 # comment', + ' echo "yes"', + 'elseif 2 #comment', + ' echo "no"', + 'endif', + ]) + + CheckScriptFailure([ + 'vim9script', + 'if 1# comment', + ' echo "yes"', + 'endif', + ], 'E15:') + + CheckScriptFailure([ + 'vim9script', + 'if 0 # comment', + ' echo "yes"', + 'elseif 2#comment', + ' echo "no"', + 'endif', + ], 'E15:') + + CheckScriptSuccess([ + 'vim9script', + 'let # comment', + ]) + + CheckScriptFailure([ + 'vim9script', + 'let# comment', + ], 'E121:') + + CheckScriptSuccess([ + 'vim9script', + 'let v:version # comment', + ]) + + CheckScriptFailure([ + 'vim9script', + 'let v:version# comment', + ], 'E121:') + + CheckScriptSuccess([ + 'vim9script', + 'new' + 'call setline(1, ["# define pat", "last"])', + '$', + 'dsearch /pat/ #comment', + 'bwipe!', + ]) + + CheckScriptFailure([ + 'vim9script', + 'new' + 'call setline(1, ["# define pat", "last"])', + '$', + 'dsearch /pat/#comment', + 'bwipe!', + ], 'E488:') enddef " Keep this last, it messes up highlighting. diff --git a/src/version.c b/src/version.c index 1c5ad56246..d051d79c8d 100644 --- a/src/version.c +++ b/src/version.c @@ -746,6 +746,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 611, /**/ 610, /**/ From 2c5ed4e3300378ce76c8d9c3818d6f73e5119f68 Mon Sep 17 00:00:00 2001 From: Bram Moolenaar Date: Mon, 20 Apr 2020 19:42:10 +0200 Subject: [PATCH 005/230] patch 8.2.0612: Vim9: no check for space before #comment Problem: Vim9: no check for space before #comment. Solution: Add space checks. --- src/ex_cmds.c | 7 ++-- src/ex_eval.c | 11 +++--- src/gui.c | 4 +-- src/highlight.c | 2 +- src/proto/regexp.pro | 3 +- src/regexp.c | 26 ++++++++++++-- src/testdir/test_sort.vim | 2 +- src/testdir/test_vim9_script.vim | 58 ++++++++++++++++++++++++++++++-- src/version.c | 2 ++ 9 files changed, 96 insertions(+), 19 deletions(-) diff --git a/src/ex_cmds.c b/src/ex_cmds.c index bd114631bb..f38bdacb63 100644 --- a/src/ex_cmds.c +++ b/src/ex_cmds.c @@ -451,12 +451,9 @@ ex_sort(exarg_T *eap) } else if (!ASCII_ISALPHA(*p) && regmatch.regprog == NULL) { - s = skip_regexp(p + 1, *p, TRUE); - if (*s != *p) - { - emsg(_(e_invalpat)); + s = skip_regexp_err(p + 1, *p, TRUE); + if (s == NULL) goto sortend; - } *s = NUL; // Use last search pattern if sort pattern is empty. if (s == p + 1) diff --git a/src/ex_eval.c b/src/ex_eval.c index 7ffc145ae4..4aa2658361 100644 --- a/src/ex_eval.c +++ b/src/ex_eval.c @@ -1021,12 +1021,12 @@ ex_else(exarg_T *eap) if (eap->cmdidx == CMD_elseif) { result = eval_to_bool(eap->arg, &error, &eap->nextcmd, skip); + // When throwing error exceptions, we want to throw always the first // of several errors in a row. This is what actually happens when // a conditional error was detected above and there is another failure // when parsing the expression. Since the skip flag is set in this // case, the parsing error will be ignored by emsg(). - if (!skip && !error) { if (result) @@ -1518,7 +1518,7 @@ ex_catch(exarg_T *eap) &cstack->cs_looplevel); } - if (ends_excmd(*eap->arg)) // no argument, catch all errors + if (ends_excmd2(eap->cmd, eap->arg)) // no argument, catch all errors { pat = (char_u *)".*"; end = NULL; @@ -1527,7 +1527,9 @@ ex_catch(exarg_T *eap) else { pat = eap->arg + 1; - end = skip_regexp(pat, *eap->arg, TRUE); + end = skip_regexp_err(pat, *eap->arg, TRUE); + if (end == NULL) + give_up = TRUE; } if (!give_up) @@ -1548,7 +1550,8 @@ ex_catch(exarg_T *eap) if (!skip && (cstack->cs_flags[idx] & CSF_THROWN) && !(cstack->cs_flags[idx] & CSF_CAUGHT)) { - if (end != NULL && *end != NUL && !ends_excmd(*skipwhite(end + 1))) + if (end != NULL && *end != NUL + && !ends_excmd2(end, skipwhite(end + 1))) { emsg(_(e_trailing)); return; diff --git a/src/gui.c b/src/gui.c index cdfc929e9f..5959043279 100644 --- a/src/gui.c +++ b/src/gui.c @@ -5036,7 +5036,7 @@ ex_gui(exarg_T *eap) // of the argument ending up after the shell prompt. msg_clr_eos_force(); #ifdef GUI_MAY_SPAWN - if (!ends_excmd(*eap->arg)) + if (!ends_excmd2(eap->cmd, eap->arg)) gui_start(eap->arg); else #endif @@ -5045,7 +5045,7 @@ ex_gui(exarg_T *eap) channel_gui_register_all(); #endif } - if (!ends_excmd(*eap->arg)) + if (!ends_excmd2(eap->cmd, eap->arg)) ex_next(eap); } diff --git a/src/highlight.c b/src/highlight.c index ee2e43754d..9476a7ddac 100644 --- a/src/highlight.c +++ b/src/highlight.c @@ -658,7 +658,7 @@ do_highlight( /* * If no argument, list current highlighting. */ - if (ends_excmd(*line)) + if (!init && ends_excmd2(line - 1, line)) { for (i = 1; i <= highlight_ga.ga_len && !got_int; ++i) // TODO: only call when the group has attributes set diff --git a/src/proto/regexp.pro b/src/proto/regexp.pro index 27ba8e59a0..d3a7754151 100644 --- a/src/proto/regexp.pro +++ b/src/proto/regexp.pro @@ -1,6 +1,7 @@ /* regexp.c */ int re_multiline(regprog_T *prog); -char_u *skip_regexp(char_u *startp, int dirc, int magic); +char_u *skip_regexp(char_u *startp, int delim, int magic); +char_u *skip_regexp_err(char_u *startp, int delim, int magic); char_u *skip_regexp_ex(char_u *startp, int dirc, int magic, char_u **newp, int *dropped); reg_extmatch_T *ref_extmatch(reg_extmatch_T *em); void unref_extmatch(reg_extmatch_T *em); diff --git a/src/regexp.c b/src/regexp.c index 3911c90616..c222d9c2ee 100644 --- a/src/regexp.c +++ b/src/regexp.c @@ -534,17 +534,37 @@ skip_anyof(char_u *p) /* * Skip past regular expression. - * Stop at end of "startp" or where "dirc" is found ('/', '?', etc). + * Stop at end of "startp" or where "delim" is found ('/', '?', etc). * Take care of characters with a backslash in front of it. * Skip strings inside [ and ]. */ char_u * skip_regexp( char_u *startp, - int dirc, + int delim, int magic) { - return skip_regexp_ex(startp, dirc, magic, NULL, NULL); + return skip_regexp_ex(startp, delim, magic, NULL, NULL); +} + +/* + * Call skip_regexp() and when the delimiter does not match give an error and + * return NULL. + */ + char_u * +skip_regexp_err( + char_u *startp, + int delim, + int magic) +{ + char_u *p = skip_regexp(startp, delim, magic); + + if (*p != delim) + { + semsg(_("E654: missing delimiter after search pattern: %s"), startp); + return NULL; + } + return p; } /* diff --git a/src/testdir/test_sort.vim b/src/testdir/test_sort.vim index 92e8f49d48..aa74a92d0c 100644 --- a/src/testdir/test_sort.vim +++ b/src/testdir/test_sort.vim @@ -1255,7 +1255,7 @@ func Test_sort_cmd() call setline(1, ['line1', 'line2']) call assert_fails('sort no', 'E474:') call assert_fails('sort c', 'E475:') - call assert_fails('sort #pat%', 'E682:') + call assert_fails('sort #pat%', 'E654:') enew! endfunc diff --git a/src/testdir/test_vim9_script.vim b/src/testdir/test_vim9_script.vim index 70653f0332..a541d8808d 100644 --- a/src/testdir/test_vim9_script.vim +++ b/src/testdir/test_vim9_script.vim @@ -1153,22 +1153,76 @@ def Test_vim9_comment() CheckDefFailure([ 'try# comment', - 'echo "yes"', + ' echo "yes"', 'catch', 'endtry', ], 'E488:') + CheckScriptFailure([ + 'vim9script', + 'try# comment', + 'echo "yes"', + ], 'E488:') CheckDefFailure([ 'try', - 'echo "yes"', + ' echo "yes"', 'catch# comment', 'endtry', ], 'E488:') + CheckScriptFailure([ + 'vim9script', + 'try', + ' echo "yes"', + 'catch# comment', + 'endtry', + ], 'E654:') + CheckDefFailure([ + 'try', + ' echo "yes"', + 'catch /pat/# comment', + 'endtry', + ], 'E488:') + CheckScriptFailure([ + 'vim9script', + 'try', + ' throw "pat"', + 'catch /pat/# comment', + 'endtry', + ], 'E605:') CheckDefFailure([ 'try', 'echo "yes"', 'catch', 'endtry# comment', ], 'E488:') + CheckScriptFailure([ + 'vim9script', + 'try', + ' echo "yes"', + 'catch', + 'endtry# comment', + ], 'E600:') + + CheckScriptSuccess([ + 'vim9script', + 'hi # comment', + ]) + CheckScriptFailure([ + 'vim9script', + 'hi# comment', + ], 'E416:') +enddef + +def Test_vim9_comment_gui() + CheckCanRunGui + + CheckScriptFailure([ + 'vim9script', + 'gui#comment' + ], 'E499:') + CheckScriptFailure([ + 'vim9script', + 'gui -f#comment' + ], 'E499:') enddef def Test_vim9_comment_not_compiled() diff --git a/src/version.c b/src/version.c index d051d79c8d..de9413b8c0 100644 --- a/src/version.c +++ b/src/version.c @@ -746,6 +746,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 612, /**/ 611, /**/ From 2c7f8c574f1f8723d59adca3fec8fb89c41cf8c9 Mon Sep 17 00:00:00 2001 From: Bram Moolenaar Date: Mon, 20 Apr 2020 19:52:53 +0200 Subject: [PATCH 006/230] Update runtime files --- runtime/doc/change.txt | 4 ++-- runtime/doc/develop.txt | 5 +++-- runtime/doc/eval.txt | 16 +++++++++------- runtime/doc/netbeans.txt | 2 +- runtime/doc/popup.txt | 12 +++++++----- runtime/doc/tags | 2 ++ runtime/doc/tagsrch.txt | 5 ++++- runtime/doc/term.txt | 3 ++- runtime/doc/todo.txt | 35 ++++++++++++++++++++++++---------- runtime/doc/various.txt | 4 ++-- runtime/doc/vim9.txt | 36 ++++++++++++++++++++++++++++++++--- runtime/filetype.vim | 2 +- runtime/ftplugin/fortran.vim | 7 ++++--- runtime/ftplugin/perl.vim | 6 +++--- runtime/ftplugin/perl6.vim | 6 +++--- runtime/ftplugin/systemd.vim | 36 ++++++++++++++++++++++++++++++++++- runtime/indent/fortran.vim | 7 ++++--- runtime/indent/perl.vim | 6 +++--- runtime/indent/perl6.vim | 6 +++--- runtime/macros/life/life.vim | 3 ++- runtime/syntax/fortran.vim | 7 ++++--- runtime/syntax/man.vim | 11 ++++++++--- runtime/syntax/perl.vim | 6 +++--- runtime/syntax/perl6.vim | 6 +++--- runtime/syntax/synload.vim | 8 +++++--- runtime/syntax/vim.vim | 37 ++++++++++++++++++++++-------------- 26 files changed, 194 insertions(+), 84 deletions(-) diff --git a/runtime/doc/change.txt b/runtime/doc/change.txt index 9c52e8d012..cf799a9dec 100644 --- a/runtime/doc/change.txt +++ b/runtime/doc/change.txt @@ -1,4 +1,4 @@ -*change.txt* For Vim version 8.2. Last change: 2020 Feb 09 +*change.txt* For Vim version 8.2. Last change: 2020 Apr 11 VIM REFERENCE MANUAL by Bram Moolenaar @@ -209,7 +209,7 @@ gR Enter Virtual Replace mode: Each character you type start insert (for {Visual} see |Visual-mode|). *v_r* -{Visual}["x]r{char} Replace all selected characters by {char}. +{Visual}r{char} Replace all selected characters by {char}. *v_C* {Visual}["x]C Delete the highlighted lines [into register x] and diff --git a/runtime/doc/develop.txt b/runtime/doc/develop.txt index c1e5a11f29..7ed251a6f6 100644 --- a/runtime/doc/develop.txt +++ b/runtime/doc/develop.txt @@ -1,4 +1,4 @@ -*develop.txt* For Vim version 8.2. Last change: 2019 Nov 22 +*develop.txt* For Vim version 8.2. Last change: 2020 Apr 13 VIM REFERENCE MANUAL by Bram Moolenaar @@ -151,7 +151,8 @@ VIM IS... NOT *design-not* A satirical way to say this: "Unlike Emacs, Vim does not attempt to include everything but the kitchen sink, but some people say that you can clean one with it. ;-)" - To use Vim with gdb see: http://www.agide.org and http://clewn.sf.net. + To use Vim with gdb see |terminal-debugger|. Other (older) tools can be + found at http://www.agide.org and http://clewn.sf.net. - Vim is not a fancy GUI editor that tries to look nice at the cost of being less consistent over all platforms. But functional GUI features are welcomed. diff --git a/runtime/doc/eval.txt b/runtime/doc/eval.txt index 66033764c1..e01aad3fca 100644 --- a/runtime/doc/eval.txt +++ b/runtime/doc/eval.txt @@ -1,4 +1,4 @@ -*eval.txt* For Vim version 8.2. Last change: 2020 Apr 13 +*eval.txt* For Vim version 8.2. Last change: 2020 Apr 19 VIM REFERENCE MANUAL by Bram Moolenaar @@ -1809,10 +1809,12 @@ v:errors Errors found by assert functions, such as |assert_true()|. v:event Dictionary containing information about the current |autocommand|. See the specific event for what it puts in this dictionary. - The dictionary is emptied when the |autocommand| - finishes, please refer to |dict-identity| for how to get an - independent copy of it. - + The dictionary is emptied when the |autocommand| finishes, + please refer to |dict-identity| for how to get an independent + copy of it. Use |deepcopy()| if you want to keep the + information after the event triggers. Example: > + au TextYankPost * let g:foo = deepcopy(v:event) +< *v:exception* *exception-variable* v:exception The value of the exception most recently caught and not finished. See also |v:throwpoint| and |throw-variables|. @@ -2901,13 +2903,13 @@ win_execute({id}, {command} [, {silent}]) String execute {command} in window {id} win_findbuf({bufnr}) List find windows containing {bufnr} win_getid([{win} [, {tab}]]) Number get window ID for {win} in {tab} +win_gettype([{nr}]) String type of window {nr} win_gotoid({expr}) Number go to window with ID {expr} win_id2tabwin({expr}) List get tab and window nr from window ID win_id2win({expr}) Number get window nr from window ID win_screenpos({nr}) List get screen position of window {nr} win_splitmove({nr}, {target} [, {options}]) Number move window {nr} to split of {target} -win_type([{nr}]) String type of window {nr} winbufnr({nr}) Number buffer number of window {nr} wincol() Number window column of the cursor winheight({nr}) Number height of window {nr} @@ -7766,7 +7768,7 @@ range({expr} [, {max} [, {stride}]]) *range()* GetExpr()->range() < -rand([{expr}]) *rand()* +rand([{expr}]) *rand()* *random* Return a pseudo-random Number generated with an xoshiro128** algorithm using seed {expr}. The returned number is 32 bits, also on 64 bits systems, for consistency. diff --git a/runtime/doc/netbeans.txt b/runtime/doc/netbeans.txt index ac85623670..803d388f4d 100644 --- a/runtime/doc/netbeans.txt +++ b/runtime/doc/netbeans.txt @@ -1,4 +1,4 @@ -*netbeans.txt* For Vim version 8.2. Last change: 2019 May 05 +*netbeans.txt* For Vim version 8.2. Last change: 2020 Apr 19 VIM REFERENCE MANUAL by Gordon Prieur et al. diff --git a/runtime/doc/popup.txt b/runtime/doc/popup.txt index 79aab40fe9..26435d1ff0 100644 --- a/runtime/doc/popup.txt +++ b/runtime/doc/popup.txt @@ -1,4 +1,4 @@ -*popup.txt* For Vim version 8.2. Last change: 2020 Mar 21 +*popup.txt* For Vim version 8.2. Last change: 2020 Apr 13 VIM REFERENCE MANUAL by Bram Moolenaar @@ -535,6 +535,8 @@ popup_setoptions({id}, {options}) *popup_setoptions()* wrap zindex The options from |popup_move()| can also be used. + Generally, setting an option to zero or an empty string resets + it to the default value, but there are exceptions. For "hidden" use |popup_hide()| and |popup_show()|. "tabpage" cannot be changed. @@ -579,15 +581,15 @@ The second argument of |popup_create()| is a dictionary with options: line Screen line where to position the popup. Can use a number or "cursor", "cursor+1" or "cursor-1" to use the line of the cursor and add or subtract a number of - lines. If omitted the popup is vertically centered. - The first line is 1. + lines. If omitted or zero the popup is vertically + centered. The first line is 1. When using "textprop" the number is relative to the text property and can be negative. col Screen column where to position the popup. Can use a number or "cursor" to use the column of the cursor, "cursor+9" or "cursor-9" to add or subtract a number - of columns. If omitted the popup is horizontally - centered. The first column is 1. + of columns. If omitted or zero the popup is + horizontally centered. The first column is 1. When using "textprop" the number is relative to the text property and can be negative. pos "topleft", "topright", "botleft" or "botright": diff --git a/runtime/doc/tags b/runtime/doc/tags index 68ac1a9ed1..301336ca4b 100644 --- a/runtime/doc/tags +++ b/runtime/doc/tags @@ -1315,6 +1315,7 @@ $VIM_POSIX vi_diff.txt /*$VIM_POSIX* +iconv various.txt /*+iconv* +iconv/dyn various.txt /*+iconv\/dyn* +insert_expand various.txt /*+insert_expand* ++ipv6 various.txt /*+ipv6* +job various.txt /*+job* +jumplist various.txt /*+jumplist* +keymap various.txt /*+keymap* @@ -8579,6 +8580,7 @@ quote~ change.txt /*quote~* r change.txt /*r* r.vim syntax.txt /*r.vim* rand() eval.txt /*rand()* +random eval.txt /*random* range() eval.txt /*range()* raw-terminal-mode term.txt /*raw-terminal-mode* rcp pi_netrw.txt /*rcp* diff --git a/runtime/doc/tagsrch.txt b/runtime/doc/tagsrch.txt index 0b22deba13..bab1a1c5d7 100644 --- a/runtime/doc/tagsrch.txt +++ b/runtime/doc/tagsrch.txt @@ -1,4 +1,4 @@ -*tagsrch.txt* For Vim version 8.2. Last change: 2020 Apr 03 +*tagsrch.txt* For Vim version 8.2. Last change: 2020 Apr 19 VIM REFERENCE MANUAL by Bram Moolenaar @@ -527,10 +527,13 @@ a tag for each "#defined" macro, typedefs, enums, etc. Some programs that generate tags files: ctags As found on most Unix systems. Only supports C. Only does the basic work. +universal ctags A maintained version of ctags based on exuberant + ctags. See https://ctags.io. *Exuberant_ctags* exuberant ctags This is a very good one. It works for C, C++, Java, Fortran, Eiffel and others. It can generate tags for many items. See http://ctags.sourceforge.net. + No new version since 2009. etags Connected to Emacs. Supports many languages. JTags For Java, in Java. It can be found at http://www.fleiner.com/jtags/. diff --git a/runtime/doc/term.txt b/runtime/doc/term.txt index 4bff36565f..9e0b0bb43b 100644 --- a/runtime/doc/term.txt +++ b/runtime/doc/term.txt @@ -1,4 +1,4 @@ -*term.txt* For Vim version 8.2. Last change: 2019 Dec 07 +*term.txt* For Vim version 8.2. Last change: 2020 Apr 12 VIM REFERENCE MANUAL by Bram Moolenaar @@ -545,6 +545,7 @@ Note about colors: The 't_Co' option tells Vim the number of colors available. When it is non-zero, the 't_AB' and 't_AF' options are used to set the color. If one of these is not available, 't_Sb' and 't_Sf' are used. 't_me' is used to reset to the default colors. Also see 'termguicolors'. +When the GUI is running 't_Co' is set to 16777216. *termcap-cursor-shape* *termcap-cursor-color* When Vim enters Insert mode the 't_SI' escape sequence is sent. When Vim diff --git a/runtime/doc/todo.txt b/runtime/doc/todo.txt index c7269216ed..14756f093d 100644 --- a/runtime/doc/todo.txt +++ b/runtime/doc/todo.txt @@ -1,4 +1,4 @@ -*todo.txt* For Vim version 8.2. Last change: 2020 Apr 10 +*todo.txt* For Vim version 8.2. Last change: 2020 Apr 20 VIM REFERENCE MANUAL by Bram Moolenaar @@ -39,10 +39,10 @@ browser use: https://github.com/vim/vim/issues/1234 -------------------- Known bugs and current work ----------------------- Vim9 script: +more tests for # comments: + check all calls to ends_excmd() and test that space before # is needed. + next: ex_findpat() func and partial types: -- check using func type with default arguments and varargs. - func(type, type?, ...): rettype -- Type checking arguments when calling :def function and test - Calling unknown user function does not give proper error message: assert_equal('123text', RefDef2Arg()) typo for "RetDef2Arg" - "func" inside "vim9script" doesn't work? (Ben Jackson, #5670) @@ -51,15 +51,25 @@ func and partial types: let ref = def(arg: type): rettype body enddef +- Test that a script-local function in Vim9 script cannot be deleted. +- Test that a function defined inside a :def function is local to that + function, g: functions can be defined and script-local functions cannot be + defined. Also: +- When wildcards are expanded, find `=expr` and evaluate it before invoking + the command. For example: :edit `=filename` - "echo Func()" is an error if Func() does not return anything. +- Check all Ex commands, give error if they use an expression and should be + compiled. +- For range: make table of first ASCII character with flag to quickly check if + it can be a Vim9 command. E.g. "+" can, but "." can't. - better implementation for partial and tests for that. - Make "g:imported = Export.exported" work in Vim9 script. - Make Foo.Bar() work to call the dict function. (#5676) -- make "let var: string" work in a vim9script. -- Disallow unlet for local/script/imported vars - Support type for ":let"/":const" at script level for Vim9 script. (Ben Jackson, #5671) + Can we share the code for :let between direct execution and compiling? +- Disallow unlet for local/script/imported vars - Make "++nr" work. - Check that import in legacy script works and puts item in s: - Error in any command in "vim9script" aborts sourcing. @@ -75,8 +85,6 @@ Also: map(list, SomeFunc) - Test: Function declared inside a :def function is local, disappears at the end of the function. Unless g: is used, just like with variables. -- Can we omit \ for line continuation inside (), {}, ? - Requires parsing while reading a function. Like fgetline in do_one_cmd()? - implement :type - import type declaration? - implement class @@ -93,6 +101,7 @@ Popup windows: Is buf->nwindows incorrect? - popup_clear() and popup_close() should close the terminal popup, and make the buffer hidden. #5745 +- Cursor not updated before a redraw, making it jump. (#5943) - With terminal in popup, allow for popup_hide() to temporarily hide it.? - Fire some autocommand event after a new popup window was created and positioned? PopupNew? Could be used to set some options or move it out of @@ -113,6 +122,8 @@ Popup windows: Text properties: - Patch to fix that split / join does not update properties properly (Axel Forsman, #5839) Alternative: #5875. +- :goto does not go to the right place when test properties are present. + (#5930) - "cc" does not call inserted_bytes(). (Axel Forsman, #5763) - Get E685 with a sequence of commands. (#5674) - Combining text property with 'cursorline' does not always work (Billie @@ -152,6 +163,10 @@ Terminal debugger: with another Vim instance. Terminal emulator window: +- When started with ":terminal ++close" and the shell exits but there is a + background process, the window remains open, because the channel still + exists (and output still shows). Perhaps close the window when an explicit + ++close was used? (#5931) - When the job in the terminal doesn't use mouse events, let the scroll wheel scroll the scrollback, like a terminal does at the shell prompt. #2490 And use modeless selection. #2962 @@ -184,7 +199,7 @@ Terminal emulator window: Error numbers available: E453, E454, E460, E489, E491, E565, E578, E610, E611, E653, -E654, E856, E857, E861, E900 +E856, E857, E861, E900 Buffer autocommands are a bit inconsistent. Add a separate set of autocommands for the buffer lifecycle: @@ -198,7 +213,7 @@ The buffer list and windows are locked, no changes possible Patch to fix drawing error with DirectX. (James Grant, #5688) Causes flicker on resizing. -In gvim always set t_Co to 16777216 (#5903) +Patch to support ipv6 for channel. (Ozaki Kiichi, #5893) Patch to explain use of "%" in :!. (David Briscoe, #5591) diff --git a/runtime/doc/various.txt b/runtime/doc/various.txt index a88cc81cc1..384e8e65e1 100644 --- a/runtime/doc/various.txt +++ b/runtime/doc/various.txt @@ -1,4 +1,4 @@ -*various.txt* For Vim version 8.2. Last change: 2020 Mar 19 +*various.txt* For Vim version 8.2. Last change: 2020 Apr 13 VIM REFERENCE MANUAL by Bram Moolenaar @@ -543,7 +543,7 @@ N *+X11* Unix only: can restore window title |X11| locked or the variable type is changed, then further command output messages will cause errors. To get the output of one command the |execute()| - function can be used. + function can be used instead of redirection. :redi[r] =>> {var} Append messages to an existing variable. Only string variables can be used. diff --git a/runtime/doc/vim9.txt b/runtime/doc/vim9.txt index dd2d510565..704e801c26 100644 --- a/runtime/doc/vim9.txt +++ b/runtime/doc/vim9.txt @@ -1,4 +1,4 @@ -*vim9.txt* For Vim version 8.2. Last change: 2020 Apr 09 +*vim9.txt* For Vim version 8.2. Last change: 2020 Apr 19 VIM REFERENCE MANUAL by Bram Moolenaar @@ -66,6 +66,10 @@ comment can also start with #. Normally this is a command to list text with numbers, but you can also use `:number` for that. > let count = 0 # number of occurences of Ni! +To improve readability there must be a space between the command and the # +that starts a comment. Note that #{ is the start of a dictionary, therefore +it cannot start a comment. + Vim9 functions ~ @@ -82,6 +86,29 @@ In the function body: ... +Functions are script-local by default ~ + +When using `:function` or `:def` to specify a new function at the script level +in a Vim9 script, the function is local to the script, as if "s:" was +prefixed. To define a global function the "g:" prefix must be used. + +When using `:function` or `:def` to specify a new function inside a function, +the function is local to the function. It is not possible to define a +script-local function inside a function. To define a global function the "g:" +prefix must be used. + +When referring to a function and no "s:" or "g:" prefix is used, Vim will +search for the function in this order: +- Local to the current function scope. +- Local to the current script file. +- Imported functions, see `:import`. +- Global. + +Global functions can be defined and deleted at nearly any time. In Vim9 +script script-local functions are defined once when the script is sourced and +cannot be deleted. + + Variable declarations with :let and :const ~ Local variables need to be declared with `:let`. Local constants need to be @@ -468,9 +495,12 @@ Then "myvar" will only exist in this file. While without `vim9script` it would be available as `g:myvar` from any other script and function. The variables at the file level are very much like the script-local "s:" -variables in legacy Vim script, but the "s:" is omitted. +variables in legacy Vim script, but the "s:" is omitted. And they cannot be +deleted. -In Vim9 script the global "g:" namespace can still be used as before. +In Vim9 script the global "g:" namespace can still be used as before. And the +"w:", "b:" and "t:" namespaces. These have in common that variables are not +declared and they can be deleted. A side effect of `:vim9script` is that the 'cpoptions' option is set to the Vim default value, like with: > diff --git a/runtime/filetype.vim b/runtime/filetype.vim index be29691532..d5d8115ca1 100644 --- a/runtime/filetype.vim +++ b/runtime/filetype.vim @@ -1,7 +1,7 @@ " Vim support file to detect file types " " Maintainer: Bram Moolenaar -" Last Change: 2020 Apr 12 +" Last Change: 2020 Apr 17 " Listen very carefully, I will say this only once if exists("did_load_filetypes") diff --git a/runtime/ftplugin/fortran.vim b/runtime/ftplugin/fortran.vim index 5d42409fd4..385f1557de 100644 --- a/runtime/ftplugin/fortran.vim +++ b/runtime/ftplugin/fortran.vim @@ -1,7 +1,8 @@ " Vim settings file " Language: Fortran 2008 (and older: Fortran 2003, 95, 90, 77, 66) " Version: 0.50 -" Last Change: 2015 Nov. 30 +" Last Change: 2020 Apr 20 +" Patched By: Eisuke Kawashima " Maintainer: Ajit J. Thakkar ; " Usage: For instructions, do :help fortran-plugin from Vim " Credits: @@ -31,10 +32,10 @@ if !exists("b:fortran_fixed_source") elseif exists("fortran_fixed_source") " User guarantees fixed source form let b:fortran_fixed_source = 1 - elseif expand("%:e") ==? "f\<90\|95\|03\|08\>" + elseif expand("%:e") =~? '^f\%(90\|95\|03\|08\)$' " Free-form file extension defaults as in Intel ifort, gcc(gfortran), NAG, Pathscale, and Cray compilers let b:fortran_fixed_source = 0 - elseif expand("%:e") ==? "f\|f77\|for" + elseif expand("%:e") =~? '^\%(f\|f77\|for\)$' " Fixed-form file extension defaults let b:fortran_fixed_source = 1 else diff --git a/runtime/ftplugin/perl.vim b/runtime/ftplugin/perl.vim index e7acf654f3..603ba49502 100644 --- a/runtime/ftplugin/perl.vim +++ b/runtime/ftplugin/perl.vim @@ -1,9 +1,9 @@ " Vim filetype plugin file " Language: Perl " Maintainer: vim-perl -" Homepage: http://github.com/vim-perl/vim-perl -" Bugs/requests: http://github.com/vim-perl/vim-perl/issues -" Last Change: 2015-02-09 +" Homepage: https://github.com/vim-perl/vim-perl +" Bugs/requests: https://github.com/vim-perl/vim-perl/issues +" Last Change: 2020 Apr 15 if exists("b:did_ftplugin") | finish | endif let b:did_ftplugin = 1 diff --git a/runtime/ftplugin/perl6.vim b/runtime/ftplugin/perl6.vim index 5318df63bc..0467bea0c2 100644 --- a/runtime/ftplugin/perl6.vim +++ b/runtime/ftplugin/perl6.vim @@ -1,9 +1,9 @@ " Vim filetype plugin file " Language: Perl 6 " Maintainer: vim-perl -" Homepage: http://github.com/vim-perl/vim-perl -" Bugs/requests: http://github.com/vim-perl/vim-perl/issues -" Last Change: 2013-07-21 +" Homepage: https://github.com/vim-perl/vim-perl +" Bugs/requests: https://github.com/vim-perl/vim-perl/issues +" Last Change: 2020 Apr 15 " Contributors: Hinrik Örn Sigurðsson " " Based on ftplugin/perl.vim by Dan Sharp diff --git a/runtime/ftplugin/systemd.vim b/runtime/ftplugin/systemd.vim index 60b3fd996d..4c5c9a1dc1 100644 --- a/runtime/ftplugin/systemd.vim +++ b/runtime/ftplugin/systemd.vim @@ -1,7 +1,41 @@ " Vim filetype plugin file -" Language: systemd.unit(5) +" Language: systemd.unit(5) +" Keyword Lookup Support: Enno Nagel if !exists('b:did_ftplugin') " Looks a lot like dosini files. runtime! ftplugin/dosini.vim endif + +if !has('unix') + finish +endif + +if !has('gui_running') + command! -buffer -nargs=1 Sman silent exe '!' . KeywordLookup_systemd() | redraw! +elseif has('terminal') + command! -buffer -nargs=1 Sman silent exe 'term ' . KeywordLookup_systemd() +else + finish +endif + +if !exists('*KeywordLookup_systemd') + function KeywordLookup_systemd(keyword) abort + let matches = matchlist(getline(search('\v^\s*\[\s*.+\s*\]\s*$', 'nbWz')), '\v^\s*\[\s*(\k+).*\]\s*$') + if len(matches) > 1 + let section = matches[1] + return 'LESS= MANPAGER="less --pattern=''(^|,)\s+' . a:keyword . '=$'' --hilite-search" man ' . 'systemd.' . section + else + return 'LESS= MANPAGER="less --pattern=''(^|,)\s+' . a:keyword . '=$'' --hilite-search" man ' . 'systemd' + endif + endfunction +endif + +setlocal iskeyword+=- +setlocal keywordprg=:Sman + +if !exists('b:undo_ftplugin') || empty(b:undo_ftplugin) + let b:undo_ftplugin = 'setlocal keywordprg< iskeyword<' +else + let b:undo_ftplugin .= '| setlocal keywordprg< iskeyword<' +endif diff --git a/runtime/indent/fortran.vim b/runtime/indent/fortran.vim index 2ba69e86df..df55569f89 100644 --- a/runtime/indent/fortran.vim +++ b/runtime/indent/fortran.vim @@ -1,7 +1,8 @@ " Vim indent file " Language: Fortran 2008 (and older: Fortran 2003, 95, 90, and 77) " Version: 47 -" Last Change: 2016 Oct. 29 +" Last Change: 2020 Apr 20 +" Patched By: Eisuke Kawashima " Maintainer: Ajit J. Thakkar ; " Usage: For instructions, do :help fortran-indent from Vim " Credits: @@ -39,10 +40,10 @@ if !exists("b:fortran_fixed_source") elseif exists("fortran_fixed_source") " User guarantees fixed source form let b:fortran_fixed_source = 1 - elseif expand("%:e") ==? "f\<90\|95\|03\|08\>" + elseif expand("%:e") =~? '^f\%(90\|95\|03\|08\)$' " Free-form file extension defaults as in Intel ifort, gcc(gfortran), NAG, Pathscale, and Cray compilers let b:fortran_fixed_source = 0 - elseif expand("%:e") ==? "f\|f77\|for" + elseif expand("%:e") =~? '^\%(f\|f77\|for\)$' " Fixed-form file extension defaults let b:fortran_fixed_source = 1 else diff --git a/runtime/indent/perl.vim b/runtime/indent/perl.vim index 094d1d37ea..5fc8b7008a 100644 --- a/runtime/indent/perl.vim +++ b/runtime/indent/perl.vim @@ -1,9 +1,9 @@ " Vim indent file " Language: Perl 5 " Maintainer: vim-perl -" Homepage: http://github.com/vim-perl/vim-perl -" Bugs/requests: http://github.com/vim-perl/vim-perl/issues -" Last Change: 2017-01-04 +" Homepage: https://github.com/vim-perl/vim-perl +" Bugs/requests: https://github.com/vim-perl/vim-perl/issues +" Last Change: 2020 Apr 15 " Suggestions and improvements by : " Aaron J. Sherman (use syntax for hints) diff --git a/runtime/indent/perl6.vim b/runtime/indent/perl6.vim index 8561c8c58c..51c7923182 100644 --- a/runtime/indent/perl6.vim +++ b/runtime/indent/perl6.vim @@ -1,9 +1,9 @@ " Vim indent file " Language: Perl 6 " Maintainer: vim-perl -" Homepage: http://github.com/vim-perl/vim-perl -" Bugs/requests: http://github.com/vim-perl/vim-perl/issues -" Last Change: 2017 Jun 13 +" Homepage: https://github.com/vim-perl/vim-perl +" Bugs/requests: https://github.com/vim-perl/vim-perl/issues +" Last Change: 2020 Apr 15 " Contributors: Andy Lester " Hinrik Örn Sigurðsson " diff --git a/runtime/macros/life/life.vim b/runtime/macros/life/life.vim index 4c7e5ca46c..29832f0227 100644 --- a/runtime/macros/life/life.vim +++ b/runtime/macros/life/life.vim @@ -108,8 +108,9 @@ map ,o oPut 'X's in the left box, then hit 'C' or 'R' map ,R 03stop " " Write a new line (used by 'I'nitialize board) +" In remembrance of John Conway, 26 December 1937 – 11 April 2020. map )0 o- --....................--....................- -map )1 o- VIM --....................--....................- +map )1 o- JOHN CONWAY --....................--....................- map )2 o- LIVES --....................--....................- " " diff --git a/runtime/syntax/fortran.vim b/runtime/syntax/fortran.vim index 019a0bf2ac..2b62226ed4 100644 --- a/runtime/syntax/fortran.vim +++ b/runtime/syntax/fortran.vim @@ -1,7 +1,8 @@ " Vim syntax file " Language: Fortran 2008 (and older: Fortran 2003, 95, 90, and 77) " Version: 102 -" Last Change: 2019 Dec. 14 +" Last Change: 2020 Apr 20 +" Patched By: Eisuke Kawashima " Maintainer: Ajit J. Thakkar ; " Usage: For instructions, do :help fortran-syntax from Vim " Credits: @@ -53,10 +54,10 @@ if !exists("b:fortran_fixed_source") elseif exists("fortran_fixed_source") " User guarantees fixed source form for all fortran files let b:fortran_fixed_source = 1 - elseif expand("%:e") ==? "f\<90\|95\|03\|08\>" + elseif expand("%:e") =~? '^f\%(90\|95\|03\|08\)$' " Free-form file extension defaults as in Intel ifort, gcc(gfortran), NAG, Pathscale, and Cray compilers let b:fortran_fixed_source = 0 - elseif expand("%:e") ==? "f\|f77\|for" + elseif expand("%:e") =~? '^\%(f\|f77\|for\)$' " Fixed-form file extension defaults let b:fortran_fixed_source = 1 else diff --git a/runtime/syntax/man.vim b/runtime/syntax/man.vim index 77675c5d2f..5bdba86212 100644 --- a/runtime/syntax/man.vim +++ b/runtime/syntax/man.vim @@ -3,7 +3,7 @@ " Maintainer: SungHyun Nam " Previous Maintainer: Gautam H. Mudunuri " Version Info: -" Last Change: 2015 Nov 24 +" Last Change: 2020 Apr 15 " Additional highlighting by Johannes Tanzler : " * manSubHeading @@ -18,8 +18,11 @@ endif runtime! syntax/ctrlh.vim syn case ignore + +syn match manHeader '\%1l.*' +exe 'syn match manFooter ''\%' . line('$') . 'l.*''' + syn match manReference "\f\+([1-9][a-z]\=)" -syn match manTitle "^\f\+([0-9]\+[a-z]\=).*" syn match manSectionHeading "^[a-z][a-z -]*[a-z]$" syn match manSubHeading "^\s\{3\}[a-z][a-z -]*[a-z]$" syn match manOptionDesc "^\s*[+-][a-z0-9]\S*" @@ -36,7 +39,9 @@ endif " Define the default highlighting. " Only when an item doesn't have highlighting yet -hi def link manTitle Title +hi def link manHeader Title +hi def link manFooter PreProc + hi def link manSectionHeading Statement hi def link manOptionDesc Constant hi def link manLongOptionDesc Constant diff --git a/runtime/syntax/perl.vim b/runtime/syntax/perl.vim index 6ac28f6915..f4f9520de5 100644 --- a/runtime/syntax/perl.vim +++ b/runtime/syntax/perl.vim @@ -1,9 +1,9 @@ " Vim syntax file " Language: Perl 5 " Maintainer: vim-perl -" Homepage: http://github.com/vim-perl/vim-perl/tree/master -" Bugs/requests: http://github.com/vim-perl/vim-perl/issues -" Last Change: 2017-09-12 +" Homepage: https://github.com/vim-perl/vim-perl/tree/master +" Bugs/requests: https://github.com/vim-perl/vim-perl/issues +" Last Change: 2020 Apr 15 " Contributors: Andy Lester " Hinrik Örn Sigurðsson " Lukas Mai diff --git a/runtime/syntax/perl6.vim b/runtime/syntax/perl6.vim index 3bcd9ff0e9..62ddc456e2 100644 --- a/runtime/syntax/perl6.vim +++ b/runtime/syntax/perl6.vim @@ -1,9 +1,9 @@ " Vim syntax file " Language: Perl 6 " Maintainer: vim-perl -" Homepage: http://github.com/vim-perl/vim-perl/tree/master -" Bugs/requests: http://github.com/vim-perl/vim-perl/issues -" Last Change: 2013-07-21 +" Homepage: https://github.com/vim-perl/vim-perl/tree/master +" Bugs/requests: https://github.com/vim-perl/vim-perl/issues +" Last Change: 2020 Apr 15 " Contributors: Luke Palmer " Moritz Lenz diff --git a/runtime/syntax/synload.vim b/runtime/syntax/synload.vim index ab918c645b..f373161c7c 100644 --- a/runtime/syntax/synload.vim +++ b/runtime/syntax/synload.vim @@ -1,6 +1,6 @@ " Vim syntax support file " Maintainer: Bram Moolenaar -" Last Change: 2016 Nov 04 +" Last Change: 2020 Apr 13 " This file sets up for syntax highlighting. " It is loaded from "syntax.vim" and "manual.vim". @@ -52,9 +52,11 @@ fun! s:SynSet() if s != "" " Load the syntax file(s). When there are several, separated by dots, - " load each in sequence. + " load each in sequence. Skip empty entries. for name in split(s, '\.') - exe "runtime! syntax/" . name . ".vim syntax/" . name . "/*.vim" + if !empty(name) + exe "runtime! syntax/" . name . ".vim syntax/" . name . "/*.vim" + endif endfor endif endfun diff --git a/runtime/syntax/vim.vim b/runtime/syntax/vim.vim index d99dc12788..22947bff1a 100644 --- a/runtime/syntax/vim.vim +++ b/runtime/syntax/vim.vim @@ -1,8 +1,8 @@ " Vim syntax file " Language: Vim 8.0 script " Maintainer: Charles E. Campbell -" Last Change: March 11, 2020 -" Version: 8.0-30 +" Last Change: Apr 15, 2020 +" Version: 8.0-33 " URL: http://www.drchip.org/astronaut/vim/index.html#SYNTAX_VIM " Automatically generated keyword lists: {{{1 @@ -224,7 +224,7 @@ syn keyword vimAugroupKey contained aug[roup] " Operators: {{{2 " ========= -syn cluster vimOperGroup contains=vimEnvvar,vimFunc,vimFuncVar,vimOper,vimOperParen,vimNumber,vimString,vimRegister,vimContinue +syn cluster vimOperGroup contains=vimEnvvar,vimFunc,vimFuncVar,vimOper,vimOperParen,vimNumber,vimString,vimRegister,vimContinue,vim9Comment syn match vimOper "\%#=1\(==\|!=\|>=\|<=\|=\~\|!\~\|>\|<\|=\)[?#]\{0,2}" skipwhite nextgroup=vimString,vimSpecFile syn match vimOper "\(\" skipwhite nextgroup=vimString,vimSpecFile syn match vimOper "||\|&&\|[-+.!]" skipwhite nextgroup=vimString,vimSpecFile @@ -265,7 +265,7 @@ syn match vimSpecFileMod "\(:[phtre]\)\+" contained " User-Specified Commands: {{{2 " ======================= -syn cluster vimUserCmdList contains=vimAddress,vimSyntax,vimHighlight,vimAutoCmd,vimCmplxRepeat,vimComment,vimCtrlChar,vimEscapeBrace,vimFunc,vimFuncName,vimFunction,vimFunctionError,vimIsCommand,vimMark,vimNotation,vimNumber,vimOper,vimRegion,vimRegister,vimLet,vimSet,vimSetEqual,vimSetString,vimSpecFile,vimString,vimSubst,vimSubstRep,vimSubstRange,vimSynLine +syn cluster vimUserCmdList contains=vimAddress,vimSyntax,vimHighlight,vimAutoCmd,vimCmplxRepeat,vimComment,vim9Comment,vimCtrlChar,vimEscapeBrace,vimFunc,vimFuncName,vimFunction,vimFunctionError,vimIsCommand,vimMark,vimNotation,vimNumber,vimOper,vimRegion,vimRegister,vimLet,vimSet,vimSetEqual,vimSetString,vimSpecFile,vimString,vimSubst,vimSubstRep,vimSubstRange,vimSynLine syn keyword vimUserCommand contained com[mand] syn match vimUserCmd "\.*$" contains=vimUserAttrb,vimUserAttrbError,vimUserCommand,@vimUserCmdList syn match vimUserAttrbError contained "-\a\+\ze\s" @@ -295,6 +295,12 @@ syn match vimComment excludenl +\s"[^\-:.%#=*].*$+lc=1 contains=@vimCommentGroup syn match vimComment +\'lc=1 syn match vimCmplxRepeat '@[0-9a-z".=@:]\ze\($\|[^a-zA-Z]\>\)' " Set command and associated set-options (vimOptions) with comment {{{2 -syn region vimSet matchgroup=vimCommand start="\<\%(setl\%[ocal]\|setg\%[lobal]\|se\%[t]\)\>" skip="\%(\\\\\)*\\." end="$" end="|" matchgroup=vimNotation end="<[cC][rR]>" keepend oneline contains=vimSetEqual,vimOption,vimErrSetting,vimComment,vimSetString,vimSetMod +syn region vimSet matchgroup=vimCommand start="\<\%(setl\%[ocal]\|setg\%[lobal]\|se\%[t]\)\>" skip="\%(\\\\\)*\\." end="$" end="|" matchgroup=vimNotation end="<[cC][rR]>" keepend oneline contains=vimSetEqual,vimOption,vimErrSetting,vimComment,vim9Comment,vimSetString,vimSetMod syn region vimSetEqual contained start="[=:]\|[-+^]=" skip="\\\\\|\\\s" end="[| \t]\|$"me=e-1 contains=vimCtrlChar,vimSetSep,vimNotation,vimEnvvar oneline syn region vimSetString contained start=+="+hs=s+1 skip=+\\\\\|\\"+ end=+"+ contains=vimCtrlChar syn match vimSetSep contained "[,:]" skipwhite nextgroup=vimCommand @@ -381,7 +387,7 @@ syn match vimSetMod contained "&vim\=\|[!&?<]\|all&" " Let: {{{2 " === syn keyword vimLet let unl[et] skipwhite nextgroup=vimVar,vimFuncVar,vimLetHereDoc -VimFoldh syn region vimLetHereDoc matchgroup=vimLetHereDocStart start='=<<\s\+\%(trim\>\)\=\s*\z(\L\S*\)' matchgroup=vimLetHereDocStop end='^\s*\z1\s*$' contains=vimComment +VimFoldh syn region vimLetHereDoc matchgroup=vimLetHereDocStart start='=<<\s\+\%(trim\>\)\=\s*\z(\L\S*\)' matchgroup=vimLetHereDocStop end='^\s*\z1\s*$' contains=vimComment,vim9Comment " Abbreviations: {{{2 " ============= @@ -427,7 +433,7 @@ syn match vimMenuPriority "\d\+\(\.\d\+\)*" contained skipwhite nextgroup=vimMen syn match vimMenuNameMore "\c\\\s\|\|\\\." contained nextgroup=vimMenuName,vimMenuNameMore contains=vimNotation syn match vimMenuMod contained "\c<\(script\|silent\)\+>" skipwhite contains=vimMapModKey,vimMapModErr nextgroup=@vimMenuList syn match vimMenuMap "\s" contained skipwhite nextgroup=vimMenuRhs -syn match vimMenuRhs ".*$" contained contains=vimString,vimComment,vimIsCommand +syn match vimMenuRhs ".*$" contained contains=vimString,vimComment,vim9Comment,vimIsCommand syn match vimMenuBang "!" contained skipwhite nextgroup=@vimMenuList " Angle-Bracket Notation: (tnx to Michael Geddes) {{{2 @@ -477,8 +483,8 @@ syn match vimSynContains contained "\" contains=vimCommand skipwhite nextgroup=vimSynType,vimComment -syn match vimAuSyntax contained "\s+sy\%[ntax]" contains=vimCommand skipwhite nextgroup=vimSynType,vimComment +syn match vimSyntax "\" contains=vimCommand skipwhite nextgroup=vimSynType,vimComment,vim9Comment +syn match vimAuSyntax contained "\s+sy\%[ntax]" contains=vimCommand skipwhite nextgroup=vimSynType,vimComment,vim9Comment syn cluster vimFuncBodyList add=vimSyntax " Syntax: case {{{2 @@ -515,7 +521,7 @@ syn match vimSynKeyOpt contained "\%#=1\<\(conceal\|contained\|transparent\|skip syn cluster vimFuncBodyList add=vimSynType " Syntax: match {{{2 -syn cluster vimSynMtchGroup contains=vimMtchComment,vimSynContains,vimSynError,vimSynMtchOpt,vimSynNextgroup,vimSynRegPat,vimNotation +syn cluster vimSynMtchGroup contains=vimMtchComment,vimSynContains,vimSynError,vimSynMtchOpt,vimSynNextgroup,vimSynRegPat,vimNotation,vim9Comment syn keyword vimSynType contained match skipwhite nextgroup=vimSynMatchRegion syn region vimSynMatchRegion contained keepend matchgroup=vimGroupName start="\h\w*" matchgroup=vimSep end="|\|$" contains=@vimSynMtchGroup syn match vimSynMtchOpt contained "\%#=1\<\(conceal\|transparent\|contained\|excludenl\|keepend\|skipempty\|skipwhite\|display\|extend\|skipnl\|fold\)\>" @@ -569,7 +575,7 @@ syn match vimIsCommand "\s*\a\+" transparent contains=vimCommand,vimNotatio " Highlighting: {{{2 " ============ -syn cluster vimHighlightCluster contains=vimHiLink,vimHiClear,vimHiKeyList,vimComment +syn cluster vimHighlightCluster contains=vimHiLink,vimHiClear,vimHiKeyList,vimComment,vim9Comment if !exists("g:vimsyn_noerror") && !exists("g:vimsyn_novimhictermerror") syn match vimHiCtermError contained "\D\i*" endif @@ -624,6 +630,7 @@ syn match vimCtrlChar "[- -]" " Beginners - Patterns that involve ^ {{{2 " ========= syn match vimLineComment +^[ \t:]*".*$+ contains=@vimCommentGroup,vimCommentString,vimCommentTitle +syn match vim9LineComment +^[ \t:]\+#.*$+ contains=@vimCommentGroup,vimCommentString,vimCommentTitle syn match vimCommentTitle '"\s*\%([sS]:\|\h\w*#\)\=\u\w*\(\s\+\u\w*\)*:'hs=s+1 contained contains=vimCommentTitleLeader,vimTodo,@vimCommentGroup syn match vimContinue "^\s*\\" syn region vimString start="^\s*\\\z(['"]\)" skip='\\\\\|\\\z1' end="\z1" oneline keepend contains=@vimStringGroup,vimContinue @@ -738,10 +745,10 @@ if g:vimsyn_embed =~# 'P' && has("pythonx") && filereadable(s:pythonpath) unlet! b:current_syntax syn cluster vimFuncBodyList add=vimPythonRegion exe "syn include @vimPythonScript ".s:pythonpath - VimFoldP syn region vimPythonRegion matchgroup=vimScriptDelim start=+py\%[thon]3\=\s*<<\s*\z(\S*\)\ze\(\s*#.*\)\=$+ end=+^\z1\ze\(\s*".*\)\=$+ contains=@vimPythonScript - VimFoldP syn region vimPythonRegion matchgroup=vimScriptDelim start=+py\%[thon]3\=\s*<<\s*$+ end=+\.$+ contains=@vimPythonScript + VimFoldP syn region vimPythonRegion matchgroup=vimScriptDelim start=+py\%[thon][3x]\=\s*<<\s*\z(\S*\)\ze\(\s*#.*\)\=$+ end=+^\z1\ze\(\s*".*\)\=$+ contains=@vimPythonScript + VimFoldP syn region vimPythonRegion matchgroup=vimScriptDelim start=+py\%[thon][3x]\=\s*<<\s*$+ end=+\.$+ contains=@vimPythonScript VimFoldP syn region vimPythonRegion matchgroup=vimScriptDelim start=+Py\%[thon]2or3\s*<<\s*\z(\S*\)\ze\(\s*#.*\)\=$+ end=+^\z1\ze\(\s*".*\)\=$+ contains=@vimPythonScript - VimFoldP syn region vimPythonRegion matchgroup=vimScriptDelim start=+Py\%[thon]2or3\=\s*<<\s*$+ end=+\.$+ contains=@vimPythonScript + VimFoldP syn region vimPythonRegion matchgroup=vimScriptDelim start=+Py\%[thon]2or3\=\s*<<\s*$+ end=+\.$+ contains=@vimPythonScript syn cluster vimFuncBodyList add=vimPythonRegion else syn region vimEmbedError start=+py\%[thon]3\=\s*<<\s*\z(.*\)$+ end=+^\z1$+ @@ -857,6 +864,7 @@ if !exists("skip_vim_syntax_inits") hi def link vimCmplxRepeat SpecialChar hi def link vimCommand Statement hi def link vimComment Comment + hi def link vim9Comment Comment hi def link vimCommentString vimString hi def link vimCommentTitle PreProc hi def link vimCondHL vimCommand @@ -906,6 +914,7 @@ if !exists("skip_vim_syntax_inits") hi def link vimLetHereDocStart Special hi def link vimLetHereDocStop Special hi def link vimLineComment vimComment + hi def link vim9LineComment vimComment hi def link vimMapBang vimCommand hi def link vimMapModKey vimFuncSID hi def link vimMapMod vimBracket From 1966c248814d5195edcd1208ed0e51e664a61283 Mon Sep 17 00:00:00 2001 From: Bram Moolenaar Date: Mon, 20 Apr 2020 22:42:32 +0200 Subject: [PATCH 007/230] patch 8.2.0613: Vim9: no check for space before #comment Problem: Vim9: no check for space before #comment. Solution: Add space checks. --- runtime/lang/menu_de_de.latin1.vim | 2 +- src/highlight.c | 21 ++-- src/menu.c | 6 +- src/syntax.c | 41 +++---- src/testdir/test_vim9_script.vim | 170 +++++++++++++++++++++++++++++ src/version.c | 2 + 6 files changed, 210 insertions(+), 32 deletions(-) diff --git a/runtime/lang/menu_de_de.latin1.vim b/runtime/lang/menu_de_de.latin1.vim index 3079012ff4..d836118ea1 100644 --- a/runtime/lang/menu_de_de.latin1.vim +++ b/runtime/lang/menu_de_de.latin1.vim @@ -188,7 +188,7 @@ menutrans Set\ '&filetype'\ too Auch\ '&filetype'\ setzen menutrans &Off &Aus menutrans &Manual &Manuell menutrans A&utomatic A&utomatisch -menutrans on/off\ for\ &This\ file An/Aus (diese\ &Datei) +menutrans on/off\ for\ &This\ file An/Aus\ (diese\ &Datei) menutrans Co&lor\ test Test\ der\ Farben menutrans &Highlight\ test Test\ der\ Un&terstreichungen menutrans &Convert\ to\ HTML Konvertieren\ nach\ &HTML diff --git a/src/highlight.c b/src/highlight.c index 9476a7ddac..9c9e44599f 100644 --- a/src/highlight.c +++ b/src/highlight.c @@ -694,7 +694,7 @@ do_highlight( /* * ":highlight {group-name}": list highlighting for one group. */ - if (!doclear && !dolink && ends_excmd(*linep)) + if (!doclear && !dolink && ends_excmd2(line, linep)) { id = syn_namen2id(line, (int)(name_end - line)); if (id == 0) @@ -720,14 +720,14 @@ do_highlight( to_start = skipwhite(from_end); to_end = skiptowhite(to_start); - if (ends_excmd(*from_start) || ends_excmd(*to_start)) + if (ends_excmd2(line, from_start) || ends_excmd2(line, to_start)) { semsg(_("E412: Not enough arguments: \":highlight link %s\""), from_start); return; } - if (!ends_excmd(*skipwhite(to_end))) + if (!ends_excmd2(line, skipwhite(to_end))) { semsg(_("E413: Too many arguments: \":highlight link %s\""), from_start); return; @@ -781,8 +781,7 @@ do_highlight( /* * ":highlight clear [group]" command. */ - line = linep; - if (ends_excmd(*line)) + if (ends_excmd2(line, linep)) { #ifdef FEAT_GUI // First, we do not destroy the old values, but allocate the new @@ -826,7 +825,7 @@ do_highlight( // It is now Ok to clear out the old data. #endif #ifdef FEAT_EVAL - do_unlet((char_u *)"colors_name", TRUE); + do_unlet((char_u *)"g:colors_name", TRUE); #endif restore_cterm_colors(); @@ -845,6 +844,7 @@ do_highlight( redraw_later_clear(); return; } + line = linep; name_end = skiptowhite(line); linep = skipwhite(name_end); } @@ -888,7 +888,7 @@ do_highlight( } if (!doclear) - while (!ends_excmd(*linep)) + while (!ends_excmd2(line, linep)) { key_start = linep; if (*linep == '=') @@ -4946,10 +4946,11 @@ ex_match(exarg_T *eap) if (!eap->skip) match_delete(curwin, id, FALSE); - if (ends_excmd(*eap->arg)) + if (ends_excmd2(eap->cmd, eap->arg)) end = eap->arg; else if ((STRNICMP(eap->arg, "none", 4) == 0 - && (VIM_ISWHITE(eap->arg[4]) || ends_excmd(eap->arg[4])))) + && (VIM_ISWHITE(eap->arg[4]) + || ends_excmd2(eap->arg, eap->arg + 4)))) end = eap->arg + 4; else { @@ -4967,7 +4968,7 @@ ex_match(exarg_T *eap) end = skip_regexp(p + 1, *p, TRUE); if (!eap->skip) { - if (*end != NUL && !ends_excmd(*skipwhite(end + 1))) + if (*end != NUL && !ends_excmd2(end, skipwhite(end + 1))) { vim_free(g); eap->errmsg = e_trailing; diff --git a/src/menu.c b/src/menu.c index 38b4fd8af2..b01792594b 100644 --- a/src/menu.c +++ b/src/menu.c @@ -2680,7 +2680,7 @@ ex_menutranslate(exarg_T *eap UNUSED) /* * ":menutrans clear": clear all translations. */ - if (STRNCMP(arg, "clear", 5) == 0 && ends_excmd(*skipwhite(arg + 5))) + if (STRNCMP(arg, "clear", 5) == 0 && ends_excmd2(arg, skipwhite(arg + 5))) { tp = (menutrans_T *)menutrans_ga.ga_data; for (i = 0; i < menutrans_ga.ga_len; ++i) @@ -2703,7 +2703,9 @@ ex_menutranslate(exarg_T *eap UNUSED) to = skipwhite(arg); *arg = NUL; arg = menu_skip_part(to); - if (arg == to) + if (arg == to || ends_excmd2(eap->arg, from) + || ends_excmd2(eap->arg, to) + || !ends_excmd2(eap->arg, skipwhite(arg))) emsg(_(e_invarg)); else { diff --git a/src/syntax.c b/src/syntax.c index da5dfa1502..cda1f953b9 100644 --- a/src/syntax.c +++ b/src/syntax.c @@ -3632,7 +3632,7 @@ syn_cmd_clear(exarg_T *eap, int syncing) if (curwin->w_s->b_syn_topgrp != 0) return; - if (ends_excmd(*arg)) + if (ends_excmd2(eap->cmd, arg)) { /* * No argument: Clear all syntax items. @@ -3652,7 +3652,7 @@ syn_cmd_clear(exarg_T *eap, int syncing) /* * Clear the group IDs that are in the argument. */ - while (!ends_excmd(*arg)) + while (!ends_excmd2(eap->cmd, arg)) { arg_end = skiptowhite(arg); if (*arg == '@') @@ -3843,7 +3843,7 @@ syn_cmd_list( } else msg_puts_title(_("\n--- Syntax items ---")); - if (ends_excmd(*arg)) + if (ends_excmd2(eap->cmd, arg)) { /* * No argument: List all group IDs and all syntax clusters. @@ -3858,7 +3858,7 @@ syn_cmd_list( /* * List the group IDs and syntax clusters that are in the argument. */ - while (!ends_excmd(*arg) && !got_int) + while (!ends_excmd2(eap->cmd, arg) && !got_int) { arg_end = skiptowhite(arg); if (*arg == '@') @@ -4463,11 +4463,12 @@ get_group_name( */ static char_u * get_syn_options( - char_u *arg, // next argument to be checked + char_u *start, // next argument to be checked syn_opt_arg_T *opt, // various things int *conceal_char UNUSED, int skip) // TRUE if skipping over command { + char_u *arg = start; char_u *gname_start, *gname; int syn_id; int len; @@ -4528,7 +4529,7 @@ get_syn_options( if (p[i] == NUL && (VIM_ISWHITE(arg[len]) || (flagtab[fidx].argtype > 0 ? arg[len] == '=' - : ends_excmd(arg[len])))) + : ends_excmd2(start, arg + len)))) { if (opt->keyword && (flagtab[fidx].flags == HL_DISPLAY @@ -4790,11 +4791,12 @@ syn_cmd_keyword(exarg_T *eap, int syncing UNUSED) */ cnt = 0; p = keyword_copy; - for ( ; rest != NULL && !ends_excmd(*rest); rest = skipwhite(rest)) + for ( ; rest != NULL && !ends_excmd2(eap->arg, rest); + rest = skipwhite(rest)) { rest = get_syn_options(rest, &syn_opt_arg, &conceal_char, eap->skip); - if (rest == NULL || ends_excmd(*rest)) + if (rest == NULL || ends_excmd2(eap->arg, rest)) break; // Copy the keyword, removing backslashes, and add a NUL. while (*rest != NUL && !VIM_ISWHITE(*rest)) @@ -4892,6 +4894,7 @@ syn_cmd_match( syn_opt_arg_T syn_opt_arg; int sync_idx = 0; int conceal_char = NUL; + int orig_called_emsg = called_emsg; // Isolate the group name, check for validity rest = get_group_name(arg, &group_name_end); @@ -4922,7 +4925,7 @@ syn_cmd_match( * Check for trailing command and illegal trailing arguments. */ eap->nextcmd = check_nextcmd(rest); - if (!ends_excmd(*rest) || eap->skip) + if (!ends_excmd2(eap->cmd, rest) || eap->skip) rest = NULL; else if (ga_grow(&curwin->w_s->b_syn_patterns, 1) != FAIL && (syn_id = syn_check_group(arg, @@ -4974,7 +4977,7 @@ syn_cmd_match( vim_free(syn_opt_arg.cont_in_list); vim_free(syn_opt_arg.next_list); - if (rest == NULL) + if (rest == NULL && called_emsg == orig_called_emsg) semsg(_(e_invarg2), arg); } @@ -5037,11 +5040,11 @@ syn_cmd_region( /* * get the options, patterns and matchgroup. */ - while (rest != NULL && !ends_excmd(*rest)) + while (rest != NULL && !ends_excmd2(eap->cmd, rest)) { // Check for option arguments rest = get_syn_options(rest, &syn_opt_arg, &conceal_char, eap->skip); - if (rest == NULL || ends_excmd(*rest)) + if (rest == NULL || ends_excmd2(eap->cmd, rest)) break; // must be a pattern or matchgroup then @@ -5570,7 +5573,7 @@ syn_cmd_cluster(exarg_T *eap, int syncing UNUSED) if (!got_clstr) emsg(_("E400: No cluster specified")); - if (rest == NULL || !ends_excmd(*rest)) + if (rest == NULL || !ends_excmd2(eap->cmd, rest)) semsg(_(e_invarg2), arg); } @@ -5680,7 +5683,7 @@ get_syn_pattern(char_u *arg, synpat_T *ci) } } while (idx >= 0); - if (!ends_excmd(*end) && !VIM_ISWHITE(*end)) + if (!ends_excmd2(arg, end) && !VIM_ISWHITE(*end)) { semsg(_("E402: Garbage after pattern: %s"), arg); return NULL; @@ -5703,13 +5706,13 @@ syn_cmd_sync(exarg_T *eap, int syncing UNUSED) long n; char_u *cpo_save; - if (ends_excmd(*arg_start)) + if (ends_excmd2(eap->cmd, arg_start)) { syn_cmd_list(eap, TRUE); return; } - while (!ends_excmd(*arg_start)) + while (!ends_excmd2(eap->cmd, arg_start)) { arg_end = skiptowhite(arg_start); next_arg = skipwhite(arg_end); @@ -5719,7 +5722,7 @@ syn_cmd_sync(exarg_T *eap, int syncing UNUSED) { if (!eap->skip) curwin->w_s->b_syn_sync_flags |= SF_CCOMMENT; - if (!ends_excmd(*next_arg)) + if (!ends_excmd2(eap->cmd, next_arg)) { arg_end = skiptowhite(next_arg); if (!eap->skip) @@ -5888,7 +5891,7 @@ get_id_list( break; } p = skipwhite(p + 1); - if (ends_excmd(*p)) + if (ends_excmd2(*arg, p)) { semsg(_("E406: Empty argument: %s"), *arg); break; @@ -5898,7 +5901,7 @@ get_id_list( * parse the arguments after "contains" */ count = 0; - while (!ends_excmd(*p)) + while (!ends_excmd2(*arg, p)) { for (end = p; *end && !VIM_ISWHITE(*end) && *end != ','; ++end) ; diff --git a/src/testdir/test_vim9_script.vim b/src/testdir/test_vim9_script.vim index a541d8808d..219a86f270 100644 --- a/src/testdir/test_vim9_script.vim +++ b/src/testdir/test_vim9_script.vim @@ -1210,6 +1210,176 @@ def Test_vim9_comment() 'vim9script', 'hi# comment', ], 'E416:') + CheckScriptSuccess([ + 'vim9script', + 'hi Search # comment', + ]) + CheckScriptFailure([ + 'vim9script', + 'hi Search# comment', + ], 'E416:') + CheckScriptSuccess([ + 'vim9script', + 'hi link This Search # comment', + ]) + CheckScriptFailure([ + 'vim9script', + 'hi link This That# comment', + ], 'E413:') + CheckScriptSuccess([ + 'vim9script', + 'hi clear This # comment', + 'hi clear # comment', + ]) + " not tested, because it doesn't give an error but a warning: + " hi clear This# comment', + CheckScriptFailure([ + 'vim9script', + 'hi clear# comment', + ], 'E416:') + + CheckScriptSuccess([ + 'vim9script', + 'hi Group term=bold', + 'match Group /todo/ # comment', + ]) + CheckScriptFailure([ + 'vim9script', + 'hi Group term=bold', + 'match Group /todo/# comment', + ], 'E488:') + CheckScriptSuccess([ + 'vim9script', + 'match # comment', + ]) + CheckScriptFailure([ + 'vim9script', + 'match# comment', + ], 'E475:') + CheckScriptSuccess([ + 'vim9script', + 'match none # comment', + ]) + CheckScriptFailure([ + 'vim9script', + 'match none# comment', + ], 'E475:') + + CheckScriptSuccess([ + 'vim9script', + 'menutrans clear # comment', + ]) + CheckScriptFailure([ + 'vim9script', + 'menutrans clear# comment text', + ], 'E474:') + + CheckScriptSuccess([ + 'vim9script', + 'syntax clear # comment', + ]) + CheckScriptFailure([ + 'vim9script', + 'syntax clear# comment text', + ], 'E28:') + CheckScriptSuccess([ + 'vim9script', + 'syntax keyword Word some', + 'syntax clear Word # comment', + ]) + CheckScriptFailure([ + 'vim9script', + 'syntax keyword Word some', + 'syntax clear Word# comment text', + ], 'E28:') + + CheckScriptSuccess([ + 'vim9script', + 'syntax list # comment', + ]) + CheckScriptFailure([ + 'vim9script', + 'syntax list# comment text', + ], 'E28:') + + CheckScriptSuccess([ + 'vim9script', + 'syntax match Word /pat/ oneline # comment', + ]) + CheckScriptFailure([ + 'vim9script', + 'syntax match Word /pat/ oneline# comment', + ], 'E475:') + + CheckScriptSuccess([ + 'vim9script', + 'syntax keyword Word word # comm[ent', + ]) + CheckScriptFailure([ + 'vim9script', + 'syntax keyword Word word# comm[ent', + ], 'E789:') + + CheckScriptSuccess([ + 'vim9script', + 'syntax match Word /pat/ # comment', + ]) + CheckScriptFailure([ + 'vim9script', + 'syntax match Word /pat/# comment', + ], 'E402:') + + CheckScriptSuccess([ + 'vim9script', + 'syntax match Word /pat/ contains=Something # comment', + ]) + CheckScriptFailure([ + 'vim9script', + 'syntax match Word /pat/ contains=Something# comment', + ], 'E475:') + CheckScriptFailure([ + 'vim9script', + 'syntax match Word /pat/ contains= # comment', + ], 'E406:') + CheckScriptFailure([ + 'vim9script', + 'syntax match Word /pat/ contains=# comment', + ], 'E475:') + + CheckScriptSuccess([ + 'vim9script', + 'syntax region Word start=/pat/ end=/pat/ # comment', + ]) + CheckScriptFailure([ + 'vim9script', + 'syntax region Word start=/pat/ end=/pat/# comment', + ], 'E475:') + + CheckScriptSuccess([ + 'vim9script', + 'syntax sync # comment', + ]) + CheckScriptFailure([ + 'vim9script', + 'syntax sync# comment', + ], 'E404:') + CheckScriptSuccess([ + 'vim9script', + 'syntax sync ccomment # comment', + ]) + CheckScriptFailure([ + 'vim9script', + 'syntax sync ccomment# comment', + ], 'E404:') + + CheckScriptSuccess([ + 'vim9script', + 'syntax cluster Some contains=Word # comment', + ]) + CheckScriptFailure([ + 'vim9script', + 'syntax cluster Some contains=Word# comment', + ], 'E475:') enddef def Test_vim9_comment_gui() diff --git a/src/version.c b/src/version.c index de9413b8c0..9b00c49d9a 100644 --- a/src/version.c +++ b/src/version.c @@ -746,6 +746,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 613, /**/ 612, /**/ From ff06f283e3e4b3ec43012dd3b83f8454c98f6639 Mon Sep 17 00:00:00 2001 From: Bram Moolenaar Date: Tue, 21 Apr 2020 22:01:14 +0200 Subject: [PATCH 008/230] patch 8.2.0614: get ml_get error when deleting a line in 'completefunc' Problem: Get ml_get error when deleting a line in 'completefunc'. (Yegappan Lakshmanan) Solution: Lock the text while evaluating 'completefunc'. --- runtime/doc/insert.txt | 6 ++++-- src/edit.c | 10 ++-------- src/ex_getln.c | 2 +- src/globals.h | 5 +++-- src/insexpand.c | 22 ++++++++++++++-------- src/testdir/test_edit.vim | 21 +++++++++++++++++++-- src/testdir/test_ex_mode.vim | 8 ++++---- src/testdir/test_excmd.vim | 8 ++++---- src/testdir/test_gf.vim | 8 ++++---- src/testdir/test_popup.vim | 10 ++++------ src/undo.c | 2 +- src/version.c | 2 ++ 12 files changed, 62 insertions(+), 42 deletions(-) diff --git a/runtime/doc/insert.txt b/runtime/doc/insert.txt index 99c2d40e7d..ff74d625f4 100644 --- a/runtime/doc/insert.txt +++ b/runtime/doc/insert.txt @@ -666,8 +666,10 @@ Note: The keys that are valid in CTRL-X mode are not mapped. This allows for ends CTRL-X mode (any key that is not a valid CTRL-X mode command) is mapped. Also, when doing completion with 'complete' mappings apply as usual. -Note: While completion is active Insert mode can't be used recursively. -Mappings that somehow invoke ":normal i.." will generate an E523 error. + *E565* +Note: While completion is active Insert mode can't be used recursively and +buffer text cannot be changed. Mappings that somehow invoke ":normal i.." +will generate an E565 error. The following mappings are suggested to make typing the completion commands a bit easier (although they will hide other commands): > diff --git a/src/edit.c b/src/edit.c index 3f0803f685..05518ceab8 100644 --- a/src/edit.c +++ b/src/edit.c @@ -175,16 +175,10 @@ edit( #endif // Don't allow changes in the buffer while editing the cmdline. The // caller of getcmdline() may get confused. - if (textlock != 0) - { - emsg(_(e_secure)); - return FALSE; - } - // Don't allow recursive insert mode when busy with completion. - if (ins_compl_active() || compl_busy || pum_visible()) + if (textlock != 0 || ins_compl_active() || compl_busy || pum_visible()) { - emsg(_(e_secure)); + emsg(_(e_textlock)); return FALSE; } ins_compl_clear(); // clear stuff for CTRL-X mode diff --git a/src/ex_getln.c b/src/ex_getln.c index 9b959fbad5..18da926560 100644 --- a/src/ex_getln.c +++ b/src/ex_getln.c @@ -2576,7 +2576,7 @@ get_text_locked_msg(void) if (cmdwin_type != 0) return e_cmdwin; #endif - return e_secure; + return e_textlock; } /* diff --git a/src/globals.h b/src/globals.h index 4822bf3735..f6c9d60e2b 100644 --- a/src/globals.h +++ b/src/globals.h @@ -1678,9 +1678,10 @@ EXTERN char e_letunexp[] INIT(= N_("E18: Unexpected characters in :let")); EXTERN char e_readerrf[] INIT(= N_("E47: Error while reading errorfile")); #endif #ifdef HAVE_SANDBOX -EXTERN char e_sandbox[] INIT(= N_("E48: Not allowed in sandbox")); +EXTERN char e_sandbox[] INIT(= N_("E48: Not allowed in sandbox")); #endif -EXTERN char e_secure[] INIT(= N_("E523: Not allowed here")); +EXTERN char e_secure[] INIT(= N_("E523: Not allowed here")); +EXTERN char e_textlock[] INIT(= N_("E565: Not allowed to change text here")); #if defined(AMIGA) || defined(MACOS_X) || defined(MSWIN) \ || defined(UNIX) || defined(VMS) EXTERN char e_screenmode[] INIT(= N_("E359: Screen mode setting not supported")); diff --git a/src/insexpand.c b/src/insexpand.c index 0278522684..48ab260a70 100644 --- a/src/insexpand.c +++ b/src/insexpand.c @@ -2217,6 +2217,8 @@ expand_by_function( pos = curwin->w_cursor; curwin_save = curwin; curbuf_save = curbuf; + // Lock the text to avoid weird things from happening. + ++textlock; // Call a function, which returns a list or dict. if (call_vim_function(funcname, 2, args, &rettv) == OK) @@ -2239,6 +2241,7 @@ expand_by_function( break; } } + --textlock; if (curwin_save != curwin || curbuf_save != curbuf) { @@ -2431,6 +2434,7 @@ set_completion(colnr_T startcol, list_T *list) f_complete(typval_T *argvars, typval_T *rettv UNUSED) { int startcol; + int save_textlock = textlock; if ((State & INSERT) == 0) { @@ -2438,22 +2442,24 @@ f_complete(typval_T *argvars, typval_T *rettv UNUSED) return; } + // "textlock" is set when evaluating 'completefunc' but we can change text + // here. + textlock = 0; + // Check for undo allowed here, because if something was already inserted // the line was already saved for undo and this check isn't done. if (!undo_allowed()) return; if (argvars[1].v_type != VAR_LIST || argvars[1].vval.v_list == NULL) - { emsg(_(e_invarg)); - return; + else + { + startcol = (int)tv_get_number_chk(&argvars[0], NULL); + if (startcol > 0) + set_completion(startcol - 1, argvars[1].vval.v_list); } - - startcol = (int)tv_get_number_chk(&argvars[0], NULL); - if (startcol <= 0) - return; - - set_completion(startcol - 1, argvars[1].vval.v_list); + textlock = save_textlock; } /* diff --git a/src/testdir/test_edit.vim b/src/testdir/test_edit.vim index 9096fcdeb1..ce55f6be0b 100644 --- a/src/testdir/test_edit.vim +++ b/src/testdir/test_edit.vim @@ -915,6 +915,23 @@ func Test_edit_CTRL_U() bw! endfunc +func Test_edit_completefunc_delete() + func CompleteFunc(findstart, base) + if a:findstart == 1 + return col('.') - 1 + endif + normal dd + return ['a', 'b'] + endfunc + new + set completefunc=CompleteFunc + call setline(1, ['', 'abcd', '']) + 2d + call assert_fails("normal 2G$a\\", 'E565:') + bwipe! +endfunc + + func Test_edit_CTRL_Z() " Ctrl-Z when insertmode is not set inserts it literally new @@ -1240,7 +1257,7 @@ func Test_edit_forbidden() try call feedkeys("ix\", 'tnix') call assert_fails(1, 'textlock') - catch /^Vim\%((\a\+)\)\=:E523/ " catch E523: not allowed here + catch /^Vim\%((\a\+)\)\=:E565/ " catch E565: not allowed here endtry " TODO: Might be a bug: should x really be inserted here call assert_equal(['xa'], getline(1, '$')) @@ -1264,7 +1281,7 @@ func Test_edit_forbidden() try call feedkeys("i\\\", 'tnix') call assert_fails(1, 'change in complete function') - catch /^Vim\%((\a\+)\)\=:E523/ " catch E523 + catch /^Vim\%((\a\+)\)\=:E565/ " catch E565 endtry delfu Complete set completefunc= diff --git a/src/testdir/test_ex_mode.vim b/src/testdir/test_ex_mode.vim index 9f66e3f012..d23e0ad931 100644 --- a/src/testdir/test_ex_mode.vim +++ b/src/testdir/test_ex_mode.vim @@ -158,13 +158,13 @@ endfunc func Test_ex_mode_errors() " Not allowed to enter ex mode when text is locked au InsertCharPre normal! gQ - let caught_e523 = 0 + let caught_e565 = 0 try call feedkeys("ix\", 'xt') - catch /^Vim\%((\a\+)\)\=:E523/ " catch E523 - let caught_e523 = 1 + catch /^Vim\%((\a\+)\)\=:E565/ " catch E565 + let caught_e565 = 1 endtry - call assert_equal(1, caught_e523) + call assert_equal(1, caught_e565) au! InsertCharPre endfunc diff --git a/src/testdir/test_excmd.vim b/src/testdir/test_excmd.vim index 9369c1b90b..868ac6fc40 100644 --- a/src/testdir/test_excmd.vim +++ b/src/testdir/test_excmd.vim @@ -354,15 +354,15 @@ endfunc func Test_run_excmd_with_text_locked() " :quit let cmd = ":\eexecute('quit')\\" - call assert_fails("call feedkeys(cmd, 'xt')", 'E523:') + call assert_fails("call feedkeys(cmd, 'xt')", 'E565:') " :qall let cmd = ":\eexecute('qall')\\" - call assert_fails("call feedkeys(cmd, 'xt')", 'E523:') + call assert_fails("call feedkeys(cmd, 'xt')", 'E565:') " :exit let cmd = ":\eexecute('exit')\\" - call assert_fails("call feedkeys(cmd, 'xt')", 'E523:') + call assert_fails("call feedkeys(cmd, 'xt')", 'E565:') " :close - should be ignored new @@ -370,7 +370,7 @@ func Test_run_excmd_with_text_locked() call assert_equal(2, winnr('$')) close - call assert_fails("call feedkeys(\":\=execute('bnext')\\", 'xt')", 'E523:') + call assert_fails("call feedkeys(\":\=execute('bnext')\\", 'xt')", 'E565:') endfunc " Test for the :verbose command diff --git a/src/testdir/test_gf.vim b/src/testdir/test_gf.vim index 829b7c2992..736a315790 100644 --- a/src/testdir/test_gf.vim +++ b/src/testdir/test_gf.vim @@ -134,13 +134,13 @@ func Test_gf_error() " gf is not allowed when text is locked au InsertCharPre normal! gF - let caught_e523 = 0 + let caught_e565 = 0 try call feedkeys("ix\", 'xt') - catch /^Vim\%((\a\+)\)\=:E523/ " catch E523 - let caught_e523 = 1 + catch /^Vim\%((\a\+)\)\=:E565/ " catch E565 + let caught_e565 = 1 endtry - call assert_equal(1, caught_e523) + call assert_equal(1, caught_e565) au! InsertCharPre bwipe! diff --git a/src/testdir/test_popup.vim b/src/testdir/test_popup.vim index e96d5fda50..9890377ea7 100644 --- a/src/testdir/test_popup.vim +++ b/src/testdir/test_popup.vim @@ -334,19 +334,17 @@ func DummyCompleteOne(findstart, base) endif endfunc -" Test that nothing happens if the 'completefunc' opens -" a new window (no completion, no crash) +" Test that nothing happens if the 'completefunc' tries to open +" a new window (fails to open window, continues) func Test_completefunc_opens_new_window_one() new let winid = win_getid() setlocal completefunc=DummyCompleteOne call setline(1, 'one') /^one - call assert_fails('call feedkeys("A\\\\", "x")', 'E839:') - call assert_notequal(winid, win_getid()) - q! + call assert_fails('call feedkeys("A\\\\", "x")', 'E565:') call assert_equal(winid, win_getid()) - call assert_equal('', getline(1)) + call assert_equal('oneDEF', getline(1)) q! endfunc diff --git a/src/undo.c b/src/undo.c index c5ce306cab..c11b048a2c 100644 --- a/src/undo.c +++ b/src/undo.c @@ -333,7 +333,7 @@ undo_allowed(void) // caller of getcmdline() may get confused. if (textlock != 0) { - emsg(_(e_secure)); + emsg(_(e_textlock)); return FALSE; } diff --git a/src/version.c b/src/version.c index 9b00c49d9a..cb846f08d6 100644 --- a/src/version.c +++ b/src/version.c @@ -746,6 +746,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 614, /**/ 613, /**/ From ad48e6c1590842ab6d48e6caba3e9250734dae27 Mon Sep 17 00:00:00 2001 From: Bram Moolenaar Date: Tue, 21 Apr 2020 22:19:45 +0200 Subject: [PATCH 009/230] patch 8.2.0615: regexp benchmark stest is old style Problem: Regexp benchmark stest is old style. Solution: Make it a new style test. Fix using a NULL list. Add more tests. (Yegappan Lakshmanan, closes #5963) --- src/evalbuffer.c | 8 ++++++++ src/testdir/Make_dos.mak | 9 +++++---- src/testdir/Make_ming.mak | 8 +++++--- src/testdir/Makefile | 20 +++++++++---------- src/testdir/bench_re_freeze.in | 13 ------------- src/testdir/bench_re_freeze.vim | 13 ------------- src/testdir/test_autocmd.vim | 2 ++ src/testdir/test_bench_regexp.vim | 24 +++++++++++++++++++++++ src/testdir/test_blob.vim | 1 + src/testdir/test_bufline.vim | 31 ++++++++++++++++++++++++++++++ src/testdir/test_channel.vim | 4 ++++ src/testdir/test_cmdline.vim | 3 +++ src/testdir/test_functions.vim | 26 ++++++++++++++++++++++++- src/testdir/test_ins_complete.vim | 31 ++++++++++++++++++++++++++++++ src/testdir/test_popupwin.vim | 14 ++++++++++++++ src/testdir/test_prompt_buffer.vim | 1 + src/testdir/test_tagjump.vim | 1 + src/testdir/test_window_cmd.vim | 12 ++++++++++++ src/version.c | 2 ++ 19 files changed, 179 insertions(+), 44 deletions(-) delete mode 100644 src/testdir/bench_re_freeze.in delete mode 100644 src/testdir/bench_re_freeze.vim create mode 100644 src/testdir/test_bench_regexp.vim diff --git a/src/evalbuffer.c b/src/evalbuffer.c index 2c20939bd4..f11727c787 100644 --- a/src/evalbuffer.c +++ b/src/evalbuffer.c @@ -176,6 +176,13 @@ set_buffer_lines( if (lines->v_type == VAR_LIST) { l = lines->vval.v_list; + if (l == NULL || list_len(l) == 0) + { + // set proper return code + if (lnum > curbuf->b_ml.ml_line_count) + rettv->vval.v_number = 1; // FAIL + goto done; + } range_list_materialize(l); li = l->lv_first; } @@ -251,6 +258,7 @@ set_buffer_lines( update_topline(); } +done: if (!is_curbuf) { curbuf = curbuf_save; diff --git a/src/testdir/Make_dos.mak b/src/testdir/Make_dos.mak index 66839d63bf..0e07ed5c5f 100644 --- a/src/testdir/Make_dos.mak +++ b/src/testdir/Make_dos.mak @@ -107,12 +107,13 @@ nolog: -if exist test_result.log del test_result.log -if exist messages del messages -benchmark: - bench_re_freeze.out +benchmark: test_bench_regexp.res -bench_re_freeze.out: bench_re_freeze.vim +test_bench_regexp.res: test_bench_regexp.vim -if exist benchmark.out del benchmark.out - $(VIMPROG) -u dos.vim $(NO_INITS) $*.in + @echo $(VIMPROG) > vimcmd + $(VIMPROG) -u NONE $(NO_INITS) -S runtest.vim $*.vim + @del vimcmd @IF EXIST benchmark.out ( type benchmark.out ) # New style of tests uses Vim script with assert calls. These are easier diff --git a/src/testdir/Make_ming.mak b/src/testdir/Make_ming.mak index 671caa24f3..f95f70c88c 100644 --- a/src/testdir/Make_ming.mak +++ b/src/testdir/Make_ming.mak @@ -35,7 +35,7 @@ include Make_all.mak SCRIPTS = $(SCRIPTS_ALL) $(SCRIPTS_MORE1) $(SCRIPTS_MORE4) $(SCRIPTS_WIN32) -SCRIPTS_BENCH = bench_re_freeze.out +SCRIPTS_BENCH = test_bench_regexp.res # Must run test1 first to create small.vim. $(SCRIPTS) $(SCRIPTS_GUI) $(SCRIPTS_WIN32) $(NEW_TESTS_RES): $(SCRIPTS_FIRST) @@ -110,9 +110,11 @@ nolog: -@if exist test.log $(DEL) test.log -@if exist messages $(DEL) messages -bench_re_freeze.out: bench_re_freeze.vim +test_bench_regexp.res: test_bench_regexp.vim -$(DEL) benchmark.out - $(VIMPROG) -u dos.vim $(NO_INITS) $*.in + @echo $(VIMPROG) > vimcmd + $(VIMPROG) -u NONE $(NO_INITS) -S runtest.vim $*.vim + @$(DEL) vimcmd $(CAT) benchmark.out # New style of tests uses Vim script with assert calls. These are easier diff --git a/src/testdir/Makefile b/src/testdir/Makefile index b2eaecbf40..92506e6f41 100644 --- a/src/testdir/Makefile +++ b/src/testdir/Makefile @@ -38,7 +38,7 @@ test49.out: test49.vim test_options.res test_alot.res: opt_test.vim -SCRIPTS_BENCH = bench_re_freeze.out +SCRIPTS_BENCH = test_bench_regexp.res .SUFFIXES: .in .out .res .vim @@ -146,15 +146,6 @@ test1.out: test1.in fi" -rm -rf X* test.ok viminfo -bench_re_freeze.out: bench_re_freeze.vim - -rm -rf benchmark.out $(RM_ON_RUN) - # Sleep a moment to avoid that the xterm title is messed up. - # 200 msec is sufficient, but only modern sleep supports a fraction of - # a second, fall back to a second if it fails. - @-/bin/sh -c "sleep .2 > /dev/null 2>&1 || sleep 1" - $(RUN_VIM) $*.in $(REDIR_TEST_TO_NULL) - @/bin/sh -c "if test -f benchmark.out; then cat benchmark.out; fi" - nolog: -rm -f test.log messages @@ -193,3 +184,12 @@ opt_test.vim: ../optiondefs.h gen_opt_test.vim test_xxd.res: XXD=$(XXDPROG); export XXD; $(RUN_VIMTEST) $(NO_INITS) -S runtest.vim test_xxd.vim + +test_bench_regexp.res: test_bench_regexp.vim + -rm -rf benchmark.out $(RM_ON_RUN) + # Sleep a moment to avoid that the xterm title is messed up. + # 200 msec is sufficient, but only modern sleep supports a fraction of + # a second, fall back to a second if it fails. + @-/bin/sh -c "sleep .2 > /dev/null 2>&1 || sleep 1" + $(RUN_VIMTEST) $(NO_INITS) -S runtest.vim $*.vim $(REDIR_TEST_TO_NULL) + @/bin/sh -c "if test -f benchmark.out; then cat benchmark.out; fi" diff --git a/src/testdir/bench_re_freeze.in b/src/testdir/bench_re_freeze.in deleted file mode 100644 index 7b1bfa3459..0000000000 --- a/src/testdir/bench_re_freeze.in +++ /dev/null @@ -1,13 +0,0 @@ -Test for Benchmarking RE engine - -STARTTEST -:so small.vim -:if !has("reltime") | qa! | endif -:set nocp cpo&vim -:so bench_re_freeze.vim -:call Measure('samples/re.freeze.txt', '\s\+\%#\@setbufline(bufnr('$') + 1, 1)) call assert_equal(1, ['x']->setbufline(bufnr('$') + 1, 1)) + call assert_equal(1, []->setbufline(bufnr('$') + 1, 1)) + call assert_equal(1, test_null_list()->setbufline(bufnr('$') + 1, 1)) + + call assert_equal(['a', 'b', 'c'], getbufline(b, 1, '$')) + call assert_equal(0, setbufline(b, 4, ['d', 'e'])) call assert_equal(['c'], b->getbufline(3)) call assert_equal(['d'], getbufline(b, 4)) @@ -83,9 +94,29 @@ func Test_appendbufline() call setline(1, ['a', 'b', 'c']) let b = bufnr('%') wincmd w + + call assert_equal(1, appendbufline(b, -1, 'x')) call assert_equal(1, appendbufline(b, -1, ['x'])) + call assert_equal(1, appendbufline(b, -1, [])) + call assert_equal(1, appendbufline(b, -1, test_null_list())) + + call assert_equal(1, appendbufline(b, 4, 'x')) call assert_equal(1, appendbufline(b, 4, ['x'])) + call assert_equal(1, appendbufline(b, 4, [])) + call assert_equal(1, appendbufline(b, 4, test_null_list())) + + call assert_equal(1, appendbufline(1234, 1, 'x')) call assert_equal(1, appendbufline(1234, 1, ['x'])) + call assert_equal(1, appendbufline(1234, 1, [])) + call assert_equal(1, appendbufline(1234, 1, test_null_list())) + + call assert_equal(0, appendbufline(b, 1, [])) + call assert_equal(0, appendbufline(b, 1, test_null_list())) + call assert_equal(1, appendbufline(b, 3, [])) + call assert_equal(1, appendbufline(b, 3, test_null_list())) + + call assert_equal(['a', 'b', 'c'], getbufline(b, 1, '$')) + call assert_equal(0, appendbufline(b, 3, ['d', 'e'])) call assert_equal(['c'], getbufline(b, 3)) call assert_equal(['d'], getbufline(b, 4)) diff --git a/src/testdir/test_channel.vim b/src/testdir/test_channel.vim index af809eceb4..cf51a536b5 100644 --- a/src/testdir/test_channel.vim +++ b/src/testdir/test_channel.vim @@ -167,6 +167,8 @@ func Ch_communicate(port) call ch_setoptions(handle, {'drop': 'never'}) call ch_setoptions(handle, {'drop': 'auto'}) call assert_fails("call ch_setoptions(handle, {'drop': 'bad'})", "E475") + call assert_equal(0, ch_setoptions(handle, test_null_dict())) + call assert_equal(0, ch_setoptions(test_null_channel(), {'drop' : 'never'})) " Send an eval request that works. call assert_equal('ok', ch_evalexpr(handle, 'eval-works')) @@ -1682,6 +1684,7 @@ func Test_job_start_fails() call assert_fails('let job = job_start("")', 'E474:') call assert_fails('let job = job_start(" ")', 'E474:') call assert_fails('let job = job_start(["ls", []])', 'E730:') + call assert_fails('call job_setoptions(test_null_job(), {})', 'E916:') %bw! endfunc @@ -2267,6 +2270,7 @@ func Test_invalid_job_chan_options() for opt in invalid_opts call assert_fails("let x = ch_status(ch, opt)", 'E475:') endfor + call assert_equal('fail', ch_status(ch, test_null_dict())) endfunc " Test for passing the command and the arguments as List on MS-Windows diff --git a/src/testdir/test_cmdline.vim b/src/testdir/test_cmdline.vim index 8aabaa859d..7d3c0c87d0 100644 --- a/src/testdir/test_cmdline.vim +++ b/src/testdir/test_cmdline.vim @@ -934,6 +934,9 @@ func Test_verbosefile() let log = readfile('Xlog') call assert_match("foo\nbar", join(log, "\n")) call delete('Xlog') + call mkdir('Xdir') + call assert_fails('set verbosefile=Xdir', 'E474:') + call delete('Xdir', 'd') endfunc func Test_verbose_option() diff --git a/src/testdir/test_functions.vim b/src/testdir/test_functions.vim index f7a438af72..dbd08041f3 100644 --- a/src/testdir/test_functions.vim +++ b/src/testdir/test_functions.vim @@ -794,18 +794,41 @@ func Test_mode() set complete& endfunc +" Test for append() func Test_append() enew! split call append(0, ["foo"]) + call append(1, []) + call append(1, test_null_list()) + call assert_equal(['foo', ''], getline(1, '$')) split only undo + undo " Using $ instead of '$' must give an error call assert_fails("call append($, 'foobar')", 'E116:') endfunc +" Test for setline() +func Test_setline() + new + call setline(0, ["foo"]) + call setline(0, []) + call setline(0, test_null_list()) + call setline(1, ["bar"]) + call setline(1, []) + call setline(1, test_null_list()) + call setline(2, []) + call setline(2, test_null_list()) + call setline(3, []) + call setline(3, test_null_list()) + call setline(2, ["baz"]) + call assert_equal(['bar', 'baz'], getline(1, '$')) + close! +endfunc + func Test_getbufvar() let bnr = bufnr('%') let b:var_num = '1234' @@ -913,6 +936,7 @@ func Test_match_func() call assert_equal(-1, match(['a', 'b', 'c', 'a'], 'a', 5)) call assert_equal(4, match('testing', 'ing', -1)) call assert_fails("let x=match('testing', 'ing', 0, [])", 'E745:') + call assert_equal(-1, match(test_null_list(), 2)) endfunc func Test_matchend() @@ -1796,6 +1820,7 @@ func Test_call() call assert_equal(3, 'len'->call([123])) call assert_fails("call call('len', 123)", 'E714:') call assert_equal(0, call('', [])) + call assert_equal(0, call('len', test_null_list())) function Mylen() dict return len(self.data) @@ -1962,7 +1987,6 @@ func Test_range() execute "normal! a\=[complete(col('.'), range(10)), ''][1]\" " complete_info() execute "normal! a\=[complete(col('.'), range(10)), ''][1]\\=[complete_info(range(5)), ''][1]\" - call assert_fails('call complete(1, ["a"])', 'E785:') " copy() call assert_equal([1, 2, 3], copy(range(1, 3))) diff --git a/src/testdir/test_ins_complete.vim b/src/testdir/test_ins_complete.vim index a1c7b98f18..7ae263909c 100644 --- a/src/testdir/test_ins_complete.vim +++ b/src/testdir/test_ins_complete.vim @@ -469,6 +469,7 @@ endfunc " Test for 'completefunc' deleting text func Test_completefunc_error() new + " delete text when called for the first time func CompleteFunc(findstart, base) if a:findstart == 1 normal dd @@ -479,9 +480,39 @@ func Test_completefunc_error() set completefunc=CompleteFunc call setline(1, ['', 'abcd', '']) call assert_fails('exe "normal 2G$a\\"', 'E840:') + + " delete text when called for the second time + func CompleteFunc2(findstart, base) + if a:findstart == 1 + return col('.') - 1 + endif + normal dd + return ['a', 'b'] + endfunc + set completefunc=CompleteFunc2 + call setline(1, ['', 'abcd', '']) + call assert_fails('exe "normal 2G$a\\"', 'E565:') + set completefunc& delfunc CompleteFunc + delfunc CompleteFunc2 close! endfunc +" Test for errors in using complete() function +func Test_complete_func_error() + call assert_fails('call complete(1, ["a"])', 'E785:') + func ListColors() + call complete(col('.'), "blue") + endfunc + call assert_fails('exe "normal i\=ListColors()\"', 'E474:') + func ListMonths() + call complete(col('.'), test_null_list()) + endfunc + call assert_fails('exe "normal i\=ListMonths()\"', 'E474:') + delfunc ListColors + delfunc ListMonths + call assert_fails('call complete_info({})', 'E714:') +endfunc + " vim: shiftwidth=2 sts=2 expandtab diff --git a/src/testdir/test_popupwin.vim b/src/testdir/test_popupwin.vim index 03285f935c..99b4458250 100644 --- a/src/testdir/test_popupwin.vim +++ b/src/testdir/test_popupwin.vim @@ -853,6 +853,9 @@ func Test_popup_invalid_arguments() call popup_clear() call assert_fails('call popup_create("text", "none")', 'E715:') call popup_clear() + call assert_fails('call popup_create(test_null_string(), {})', 'E450:') + call assert_fails('call popup_create(test_null_list(), {})', 'E450:') + call popup_clear() call assert_fails('call popup_create("text", #{col: "xxx"})', 'E475:') call popup_clear() @@ -902,6 +905,8 @@ func Test_popup_invalid_arguments() call assert_fails('call popup_create("text", #{mask: test_null_list()})', 'E475:') call assert_fails('call popup_create("text", #{mapping: []})', 'E745:') call popup_clear() + call assert_fails('call popup_create("text", #{tabpage : 4})', 'E997:') + call popup_clear() endfunc func Test_win_execute_closing_curwin() @@ -1113,8 +1118,13 @@ func Test_popup_move() let line = join(map(range(1, 6), 'screenstring(1, v:val)'), '') call assert_equal('hworld', line) + call assert_fails('call popup_move(winid, [])', 'E715:') + call assert_fails('call popup_move(winid, test_null_dict())', 'E715:') + call popup_close(winid) + call assert_equal(0, popup_move(-1, {})) + bwipe! endfunc @@ -2176,7 +2186,11 @@ func Test_set_get_options() call assert_equal(1, options.drag) call assert_equal('Another', options.highlight) + call assert_fails('call popup_setoptions(winid, [])', 'E715:') + call assert_fails('call popup_setoptions(winid, test_null_dict())', 'E715:') + call popup_close(winid) + call assert_equal(0, popup_setoptions(winid, options.wrap)) endfunc func Test_popupwin_garbage_collect() diff --git a/src/testdir/test_prompt_buffer.vim b/src/testdir/test_prompt_buffer.vim index 39cce247de..760e1d9798 100644 --- a/src/testdir/test_prompt_buffer.vim +++ b/src/testdir/test_prompt_buffer.vim @@ -148,6 +148,7 @@ func Test_prompt_buffer_edit() call assert_beeps("normal! \") call assert_beeps("normal! \") close! + call assert_equal(0, prompt_setprompt([], '')) endfunc " vim: shiftwidth=2 sts=2 expandtab diff --git a/src/testdir/test_tagjump.vim b/src/testdir/test_tagjump.vim index 99526005e6..fa825c7dc0 100644 --- a/src/testdir/test_tagjump.vim +++ b/src/testdir/test_tagjump.vim @@ -285,6 +285,7 @@ func Test_getsettagstack() call assert_fails("call settagstack(1, {'items' : 10})", 'E714') call assert_fails("call settagstack(1, {'items' : []}, 10)", 'E928') call assert_fails("call settagstack(1, {'items' : []}, 'b')", 'E962') + call assert_equal(-1, settagstack(0, test_null_dict())) set tags=Xtags call writefile(["!_TAG_FILE_ENCODING\tutf-8\t//", diff --git a/src/testdir/test_window_cmd.vim b/src/testdir/test_window_cmd.vim index a28c00a4bd..4927842454 100644 --- a/src/testdir/test_window_cmd.vim +++ b/src/testdir/test_window_cmd.vim @@ -1079,4 +1079,16 @@ func Test_split_cmds_with_no_room() call Run_noroom_for_newwindow_test('v') endfunc +" Test for various wincmd failures +func Test_wincmd_fails() + only! + call assert_beeps("normal \w") + call assert_beeps("normal \p") + call assert_beeps("normal \gk") + call assert_beeps("normal \r") + call assert_beeps("normal \K") + call assert_beeps("normal \H") + call assert_beeps("normal \2gt") +endfunc + " vim: shiftwidth=2 sts=2 expandtab diff --git a/src/version.c b/src/version.c index cb846f08d6..4662de6106 100644 --- a/src/version.c +++ b/src/version.c @@ -746,6 +746,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 615, /**/ 614, /**/ From e770598f31ad88fc98e40ead4b228ebc04afaa5d Mon Sep 17 00:00:00 2001 From: Bram Moolenaar Date: Tue, 21 Apr 2020 22:23:15 +0200 Subject: [PATCH 010/230] patch 8.2.0616: build error when disabling the diff feature Problem: Build error when disabling the diff feature. Solution: Move parenthesis outside of #ifdef. (Tom Ryder) --- src/drawline.c | 4 ++-- src/version.c | 2 ++ 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/src/drawline.c b/src/drawline.c index 1544dae284..8de307aa6e 100644 --- a/src/drawline.c +++ b/src/drawline.c @@ -3095,9 +3095,9 @@ win_line( #ifdef FEAT_SYN_HL if (!(cul_screenline # ifdef FEAT_DIFF - && diff_hlf == (hlf_T)0) + && diff_hlf == (hlf_T)0 # endif - ) + )) saved_char_attr = char_attr; else #endif diff --git a/src/version.c b/src/version.c index 4662de6106..f8eccbfb43 100644 --- a/src/version.c +++ b/src/version.c @@ -746,6 +746,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 616, /**/ 615, /**/ From d2662ad2de40e68999198150024531c91fece16c Mon Sep 17 00:00:00 2001 From: Bram Moolenaar Date: Wed, 22 Apr 2020 14:30:31 +0200 Subject: [PATCH 011/230] patch 8.2.0617: new error check triggers in Swedish menu Problem: New error check triggers in Swedish menu. Solution: Insert backslash. (Mats Tegner, closes #5966) --- runtime/lang/menu_sv_se.latin1.vim | 4 ++-- src/version.c | 2 ++ 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/runtime/lang/menu_sv_se.latin1.vim b/runtime/lang/menu_sv_se.latin1.vim index 2e37485306..53e1f40790 100644 --- a/runtime/lang/menu_sv_se.latin1.vim +++ b/runtime/lang/menu_sv_se.latin1.vim @@ -1,6 +1,6 @@ " Menu Translations: Swedish " Maintainer: Johan Svedberg -" Last Change: 2012 May 01 +" Last Change: 2020 Apr 22 " Quit when menu translations have already been done. if exists("did_menu_trans") @@ -51,7 +51,7 @@ menutrans &Redo^R &G menutrans Rep&eat\. &Repetera\. menutrans Cu&t"+x Klipp\ &ut"+x menutrans &Copy"+y &Kopiera"+y -menutrans &Paste"+gP Klistra &in"+gP +menutrans &Paste"+gP Klistra\ &in"+gP menutrans Put\ &Before[p Stt\ in\ &fre[p menutrans Put\ &After]p Stt\ in\ &efter]p menutrans &Select\ AllggVG &Markera\ alltggVG diff --git a/src/version.c b/src/version.c index f8eccbfb43..b7958da9bc 100644 --- a/src/version.c +++ b/src/version.c @@ -746,6 +746,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 617, /**/ 616, /**/ From db950e4c0318c084c31bc7b50665284f4a47c285 Mon Sep 17 00:00:00 2001 From: Bram Moolenaar Date: Wed, 22 Apr 2020 19:13:19 +0200 Subject: [PATCH 012/230] patch 8.2.0618: echoing a null list results in no output Problem: Echoing a null list results in no output. (Yegappan Lakshmanan) Solution: Return "[]" instead of NULL in echo_string_core(). --- src/eval.c | 3 ++- src/testdir/test_messages.vim | 1 + src/version.c | 2 ++ 3 files changed, 5 insertions(+), 1 deletion(-) diff --git a/src/eval.c b/src/eval.c index 43c20086c2..7130620c94 100644 --- a/src/eval.c +++ b/src/eval.c @@ -4528,8 +4528,9 @@ echo_string_core( case VAR_LIST: if (tv->vval.v_list == NULL) { + // NULL list is equivalent to empty list. *tofree = NULL; - r = NULL; + r = (char_u *)"[]"; } else if (copyID != 0 && tv->vval.v_list->lv_copyID == copyID && tv->vval.v_list->lv_len > 0) diff --git a/src/testdir/test_messages.vim b/src/testdir/test_messages.vim index 32ffb48a8d..ac91aa097b 100644 --- a/src/testdir/test_messages.vim +++ b/src/testdir/test_messages.vim @@ -76,6 +76,7 @@ func Test_echomsg() call assert_equal("\n12345", execute(':echomsg 12345')) call assert_equal("\n[]", execute(':echomsg []')) call assert_equal("\n[1, 2, 3]", execute(':echomsg [1, 2, 3]')) + call assert_equal("\n[1, 2, []]", execute(':echomsg [1, 2, test_null_list()]')) call assert_equal("\n{}", execute(':echomsg {}')) call assert_equal("\n{'a': 1, 'b': 2}", execute(':echomsg {"a": 1, "b": 2}')) if has('float') diff --git a/src/version.c b/src/version.c index b7958da9bc..c08008434c 100644 --- a/src/version.c +++ b/src/version.c @@ -746,6 +746,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 618, /**/ 617, /**/ From ea04a6e8baff2f27da7cdd54bf70a5525994f76d Mon Sep 17 00:00:00 2001 From: Bram Moolenaar Date: Thu, 23 Apr 2020 13:38:02 +0200 Subject: [PATCH 013/230] patch 8.2.0619: null dict is not handled like an empty dict Problem: Null dict is not handled like an empty dict. Solution: Fix the code and add tests. (Yegappan Lakshmanan, closes #5968) --- src/dict.c | 9 +++-- src/eval.c | 7 +++- src/testdir/test_blob.vim | 1 + src/testdir/test_expr.vim | 7 ---- src/testdir/test_filter_map.vim | 1 + src/testdir/test_let.vim | 3 ++ src/testdir/test_listdict.vim | 66 ++++++++++++++++++++++++++----- src/testdir/test_search.vim | 31 +++++++++++++++ src/testdir/test_unlet.vim | 1 + src/testdir/test_usercommands.vim | 10 ++--- src/testdir/test_vimscript.vim | 17 ++++++++ src/version.c | 2 + 12 files changed, 128 insertions(+), 27 deletions(-) diff --git a/src/dict.c b/src/dict.c index 1a928a35f2..88bd0e21c6 100644 --- a/src/dict.c +++ b/src/dict.c @@ -977,14 +977,15 @@ dict_equal( dictitem_T *item2; int todo; - if (d1 == NULL && d2 == NULL) - return TRUE; - if (d1 == NULL || d2 == NULL) - return FALSE; if (d1 == d2) return TRUE; if (dict_len(d1) != dict_len(d2)) return FALSE; + if (dict_len(d1) == 0) + // empty and NULL dicts are considered equal + return TRUE; + if (d1 == NULL || d2 == NULL) + return FALSE; todo = (int)d1->dv_hashtab.ht_used; for (hi = d1->dv_hashtab.ht_array; todo > 0; ++hi) diff --git a/src/eval.c b/src/eval.c index 7130620c94..c3f0de8e32 100644 --- a/src/eval.c +++ b/src/eval.c @@ -871,7 +871,10 @@ get_lval( if (len != -1) key[len] = prevval; if (wrong) + { + clear_tv(&var1); return NULL; + } } if (lp->ll_di == NULL) @@ -4553,8 +4556,9 @@ echo_string_core( case VAR_DICT: if (tv->vval.v_dict == NULL) { + // NULL dict is equivalent to empty dict. *tofree = NULL; - r = NULL; + r = (char_u *)"{}"; } else if (copyID != 0 && tv->vval.v_dict->dv_copyID == copyID && tv->vval.v_dict->dv_hashtab.ht_used != 0) @@ -4565,6 +4569,7 @@ echo_string_core( else { int old_copyID = tv->vval.v_dict->dv_copyID; + tv->vval.v_dict->dv_copyID = copyID; *tofree = dict2string(tv, copyID, restore_copyID); if (restore_copyID) diff --git a/src/testdir/test_blob.vim b/src/testdir/test_blob.vim index a29e2e61d9..4b6774fc9d 100644 --- a/src/testdir/test_blob.vim +++ b/src/testdir/test_blob.vim @@ -207,6 +207,7 @@ func Test_blob_add() call assert_equal(0z001122, b) call add(b, '51') call assert_equal(0z00112233, b) + call assert_equal(1, add(test_null_blob(), 0x22)) call assert_fails('call add(b, [9])', 'E745:') call assert_fails('call add("", 0x01)', 'E897:') diff --git a/src/testdir/test_expr.vim b/src/testdir/test_expr.vim index 11cd7aa524..ce16793810 100644 --- a/src/testdir/test_expr.vim +++ b/src/testdir/test_expr.vim @@ -96,13 +96,6 @@ func Test_loop_over_null_list() endfor endfunc -func Test_compare_null_dict() - call assert_fails('let x = test_null_dict()[10]') - call assert_equal({}, {}) - call assert_equal(test_null_dict(), test_null_dict()) - call assert_notequal({}, test_null_dict()) -endfunc - func Test_set_reg_null_list() call setreg('x', test_null_list()) endfunc diff --git a/src/testdir/test_filter_map.vim b/src/testdir/test_filter_map.vim index 63102cd9d4..fc9c741bb3 100644 --- a/src/testdir/test_filter_map.vim +++ b/src/testdir/test_filter_map.vim @@ -96,6 +96,7 @@ func Test_map_filter_fails() call assert_fails("let l = filter('abc', '\"> \" . v:val')", 'E712:') call assert_fails("let l = filter([1, 2, 3], '{}')", 'E728:') call assert_fails("let l = filter({'k' : 10}, '{}')", 'E728:') + call assert_fails("let l = filter([1, 2], {})", 'E731:') call assert_equal(0, map(test_null_list(), '"> " .. v:val')) call assert_equal(0, map(test_null_dict(), '"> " .. v:val')) endfunc diff --git a/src/testdir/test_let.vim b/src/testdir/test_let.vim index cfe095cfef..e0d543c6ce 100644 --- a/src/testdir/test_let.vim +++ b/src/testdir/test_let.vim @@ -274,6 +274,7 @@ func Test_let_errors() call assert_fails('let &buftype[1] = "nofile"', 'E18:') let s = "var" let var = 1 + call assert_fails('let var += [1,2]', 'E734:') call assert_fails('let {s}.1 = 2', 'E18:') call assert_fails('let a[1] = 5', 'E121:') let l = [[1,2]] @@ -286,6 +287,8 @@ func Test_let_errors() call assert_fails('let l[0:1] = [1, 2, 3]', 'E710:') call assert_fails('let l[-2:-3] = [3, 4]', 'E684:') call assert_fails('let l[0:4] = [5, 6]', 'E711:') + call assert_fails('let g:["a;b"] = 10', 'E461:') + call assert_fails('let g:.min = function("max")', 'E704:') " This test works only when the language is English if v:lang == "C" || v:lang =~ '^[Ee]n' diff --git a/src/testdir/test_listdict.vim b/src/testdir/test_listdict.vim index c6d6885ec4..2087f77ec9 100644 --- a/src/testdir/test_listdict.vim +++ b/src/testdir/test_listdict.vim @@ -32,7 +32,11 @@ func Test_list_slice() call assert_equal([1, 'as''d', [1, 2, function('strlen')], {'a': 1}], l[0:8]) call assert_equal([], l[8:-1]) call assert_equal([], l[0:-10]) - call assert_equal([], test_null_list()[:2]) + " perform an operation on a list slice + let l = [1, 2, 3] + let l[:1] += [1, 2] + let l[2:] -= [1] + call assert_equal([2, 4, 2], l) endfunc " List identity @@ -147,6 +151,20 @@ func Test_list_func_remove() call assert_fails("call remove(l, l)", 'E745:') endfunc +" List add() function +func Test_list_add() + let l = [] + call add(l, 1) + call add(l, [2, 3]) + call add(l, []) + call add(l, test_null_list()) + call add(l, {'k' : 3}) + call add(l, {}) + call add(l, test_null_dict()) + call assert_equal([1, [2, 3], [], [], {'k' : 3}, {}, {}], l) + call assert_equal(1, add(test_null_list(), 4)) +endfunc + " Tests for Dictionary type func Test_dict() @@ -529,6 +547,15 @@ func Test_dict_lock_extend() call assert_equal({'a': 99, 'b': 100}, d) endfunc +" Cannot use += with a locked dick +func Test_dict_lock_operator() + unlet! d + let d = {} + lockvar d + call assert_fails("let d += {'k' : 10}", 'E741:') + unlockvar d +endfunc + " No remove() of write-protected scope-level variable func Tfunc1(this_is_a_long_parameter_name) call assert_fails("call remove(a:, 'this_is_a_long_parameter_name')", 'E742') @@ -651,8 +678,6 @@ func Test_reverse_sort_uniq() call assert_fails("call sort([1, 2], function('min'), 1)", "E715:") call assert_fails("call sort([1, 2], function('invalid_func'))", "E700:") call assert_fails("call sort([1, 2], function('min'))", "E702:") - call assert_equal(0, sort(test_null_list())) - call assert_equal(0, uniq(test_null_list())) endfunc " splitting a string to a List using split() @@ -896,23 +921,44 @@ func Test_listdict_index() call assert_fails("let l = insert([1,2,3], 4, 10)", 'E684:') call assert_fails("let l = insert([1,2,3], 4, -10)", 'E684:') call assert_fails("let l = insert([1,2,3], 4, [])", 'E745:') + let l = [1, 2, 3] + call assert_fails("let l[i] = 3", 'E121:') + call assert_fails("let l[1.1] = 4", 'E806:') + call assert_fails("let l[:i] = [4, 5]", 'E121:') + call assert_fails("let l[:3.2] = [4, 5]", 'E806:') endfunc " Test for a null list func Test_null_list() - call assert_equal(0, join(test_null_list())) + let l = test_null_list() + call assert_equal(0, join(l)) + call assert_equal(0, len(l)) + call assert_equal(1, empty(l)) call assert_fails('let s = join([1, 2], [])', 'E730:') call assert_equal([], split(test_null_string())) + call assert_equal([], l[:2]) + call assert_true([] == l) + call assert_equal('[]', string(l)) + call assert_equal(0, sort(l)) + call assert_equal(0, uniq(l)) + call assert_fails("let k = [] + l", 'E15:') + call assert_fails("let k = l + []", 'E15:') endfunc " Test for a null dict func Test_null_dict() - call assert_equal(0, items(test_null_dict())) - call assert_equal(0, keys(test_null_dict())) - call assert_equal(0, values(test_null_dict())) - call assert_false(has_key(test_null_dict(), 'k')) - call assert_fails("let l = [] + test_null_list()", 'E15:') - call assert_fails("let l = test_null_list() + []", 'E15:') + call assert_equal(test_null_dict(), test_null_dict()) + let d = test_null_dict() + call assert_equal({}, d) + call assert_equal(0, len(d)) + call assert_equal(1, empty(d)) + call assert_equal(0, items(d)) + call assert_equal(0, keys(d)) + call assert_equal(0, values(d)) + call assert_false(has_key(d, 'k')) + call assert_equal('{}', string(d)) + call assert_fails('let x = test_null_dict()[10]') + call assert_equal({}, {}) endfunc " vim: shiftwidth=2 sts=2 expandtab diff --git a/src/testdir/test_search.vim b/src/testdir/test_search.vim index b7e751fa04..aaa42352ce 100644 --- a/src/testdir/test_search.vim +++ b/src/testdir/test_search.vim @@ -1617,4 +1617,35 @@ func Test_search_in_visual_area() close! endfunc +" Test for searching with 'smartcase' and 'ignorecase' +func Test_search_smartcase() + new + call setline(1, ['', 'Hello']) + set noignorecase nosmartcase + call assert_fails('exe "normal /\\a\\_.\\(.*\\)O\"', 'E486:') + + set ignorecase nosmartcase + exe "normal /\\a\\_.\\(.*\\)O\" + call assert_equal([2, 1], [line('.'), col('.')]) + + call cursor(1, 1) + set ignorecase smartcase + call assert_fails('exe "normal /\\a\\_.\\(.*\\)O\"', 'E486:') + + exe "normal /\\a\\_.\\(.*\\)o\" + call assert_equal([2, 1], [line('.'), col('.')]) + + set ignorecase& smartcase& + close! +endfunc + +" Test searching past the end of a file +func Test_search_past_eof() + new + call setline(1, ['Line']) + exe "normal /\\n\\zs\" + call assert_equal([1, 4], [line('.'), col('.')]) + close! +endfunc + " vim: shiftwidth=2 sts=2 expandtab diff --git a/src/testdir/test_unlet.vim b/src/testdir/test_unlet.vim index dad0953a66..6be963370a 100644 --- a/src/testdir/test_unlet.vim +++ b/src/testdir/test_unlet.vim @@ -27,6 +27,7 @@ func Test_unlet_fails() call assert_fails("unlet l['k'", 'E111:') let d = {'k' : 1} call assert_fails("unlet d.k2", 'E716:') + call assert_fails("unlet {a};", 'E488:') endfunc func Test_unlet_env() diff --git a/src/testdir/test_usercommands.vim b/src/testdir/test_usercommands.vim index 0f0049569b..7f87e27aee 100644 --- a/src/testdir/test_usercommands.vim +++ b/src/testdir/test_usercommands.vim @@ -587,17 +587,17 @@ func Test_usercmd_custom() return "a\nb\n" endfunc command -nargs=* -complete=customlist,T1 TCmd1 - call feedkeys(":T1 \\\"\", 'xt') - call assert_equal('"T1 ', @:) + call feedkeys(":TCmd1 \\\"\", 'xt') + call assert_equal('"TCmd1 ', @:) delcommand TCmd1 delfunc T1 func T2(a, c, p) - return ['a', 'b', 'c'] + return {} endfunc command -nargs=* -complete=customlist,T2 TCmd2 - call feedkeys(":T2 \\\"\", 'xt') - call assert_equal('"T2 ', @:) + call feedkeys(":TCmd2 \\\"\", 'xt') + call assert_equal('"TCmd2 ', @:) delcommand TCmd2 delfunc T2 endfunc diff --git a/src/testdir/test_vimscript.vim b/src/testdir/test_vimscript.vim index 7c86836619..439114d19b 100644 --- a/src/testdir/test_vimscript.vim +++ b/src/testdir/test_vimscript.vim @@ -1671,6 +1671,20 @@ func Test_compound_assignment_operators() call assert_fails('let x .= "f"', 'E734') let x = !3.14 call assert_equal(0.0, x) + + " integer and float operations + let x = 1 + let x *= 2.1 + call assert_equal(2.1, x) + let x = 1 + let x /= 0.25 + call assert_equal(4.0, x) + let x = 1 + call assert_fails('let x %= 0.25', 'E734:') + let x = 1 + call assert_fails('let x .= 0.25', 'E734:') + let x = 1.0 + call assert_fails('let x += [1.1]', 'E734:') endif " Test for environment variable @@ -1871,6 +1885,9 @@ func Test_missing_end() " Missing 'in' in a :for statement call assert_fails('for i range(1) | endfor', 'E690:') + + " Incorrect number of variables in for + call assert_fails('for [i,] in range(3) | endfor', 'E475:') endfunc " Test for deep nesting of if/for/while/try statements {{{1 diff --git a/src/version.c b/src/version.c index c08008434c..ad34a91c0f 100644 --- a/src/version.c +++ b/src/version.c @@ -746,6 +746,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 619, /**/ 618, /**/ From 0d6fe631f75effbfca92a4f61bbc2fab7385af09 Mon Sep 17 00:00:00 2001 From: Bram Moolenaar Date: Thu, 23 Apr 2020 13:58:12 +0200 Subject: [PATCH 014/230] patch 8.2.0620: error in menu translations Problem: Error in menu translations. Solution: Insert a backslash before a space. --- runtime/lang/menu_chinese_gb.936.vim | 8 ++++---- runtime/lang/menu_it_it.latin1.vim | 10 +++++----- src/version.c | 2 ++ 3 files changed, 11 insertions(+), 9 deletions(-) diff --git a/runtime/lang/menu_chinese_gb.936.vim b/runtime/lang/menu_chinese_gb.936.vim index d96ab37802..f20989f4c8 100644 --- a/runtime/lang/menu_chinese_gb.936.vim +++ b/runtime/lang/menu_chinese_gb.936.vim @@ -1,7 +1,7 @@ " Menu Translations: Simplified Chinese " Maintainer: Shun Bai " Previous Maintainer: Yuheng Xie -" Last Change: 2019-09-10 +" Last Change: 2020 Apr 23 " Quit when menu translations have already been done. if exists("did_menu_trans") @@ -122,7 +122,7 @@ menutrans Toggle\ &C-Style\ Indenting:set\ cin! " other options menutrans &Shiftwidth (&S) -menutrans Soft\ &Tabstop Ʊλ(Soft Tabstop)(&T) +menutrans Soft\ &Tabstop Ʊλ(Soft\ Tabstop)(&T) menutrans Te&xt\ Width\.\.\. ı(&X)\.\.\. menutrans &File\ Format\.\.\. ļʽ(&F)\.\.\. @@ -435,8 +435,8 @@ menutrans Set\ '&filetype'\ Too Ҳ menutrans Sorting\ Method ʽ " Netrw.Style.Sorting Method menuitems {{{3 menutrans Names ļs - menutrans Times ޸ʱs - menutrans Sizes Сs + menutrans Times ޸ʱs + menutrans Sizes Сs menutrans Extens չs " }}} " }}} diff --git a/runtime/lang/menu_it_it.latin1.vim b/runtime/lang/menu_it_it.latin1.vim index 8dec38bb14..927c3c9e67 100644 --- a/runtime/lang/menu_it_it.latin1.vim +++ b/runtime/lang/menu_it_it.latin1.vim @@ -2,7 +2,7 @@ " Maintainer: Antonio Colombo " Vlad Sandrini " Luciano Montanaro -" Last Change: 2018 May 16 +" Last Change: 2020 Apr 23 " Quit when menu translations have already been done. if exists("did_menu_trans") @@ -116,8 +116,8 @@ menut Toggle\ &List\ Mode:set\ list! Modo\ &List\ S menut Toggle\ Line\ &Wrapping:set\ wrap! Linee\ &Continuate\ S/No:set\ wrap! menut Toggle\ W&rapping\ at\ word:set\ lbr! A\ capo\ alla\ &Parola\ S/No:set\ lbr! menut Toggle\ Tab\ &expanding:set\ et! &Espandi\ Tabulazione\ S/No:set\ et! -menut Toggle\ &Auto\ Indenting:set\ ai! Indentazione\ &Automatica\ S/No:set ai! -menut Toggle\ &C-Style\ Indenting:set\ cin! Indentazione\ stile\ &C\ S/No:set cin! +menut Toggle\ &Auto\ Indenting:set\ ai! Indentazione\ &Automatica\ S/No:set\ ai! +menut Toggle\ &C-Style\ Indenting:set\ cin! Indentazione\ stile\ &C\ S/No:set\ cin! " -SEP2- menut &Shiftwidth &Spazi\ rientranza "menut &Shiftwidth.2:set\ sw=2\ sw? &Spazi\ rientranza.2:set\ sw=2\ sw? @@ -360,8 +360,8 @@ menut Copy Copia menut Paste Incolla " -sep3- menut Find Cerca -menut FindNext Cerca Successivo -menut FindPrev Cerca Precedente +menut FindNext Cerca\ Successivo +menut FindPrev Cerca\ Precedente menut Replace Sostituisci " -sep4- menut New Nuova\ finestra diff --git a/src/version.c b/src/version.c index ad34a91c0f..a46ffb46fa 100644 --- a/src/version.c +++ b/src/version.c @@ -746,6 +746,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 620, /**/ 619, /**/ From 95a467e7eeab664a71446e320d328d1d7c52a35a Mon Sep 17 00:00:00 2001 From: Bram Moolenaar Date: Thu, 23 Apr 2020 14:41:46 +0200 Subject: [PATCH 015/230] patch 8.2.0621: after running tests asan files may remain Problem: After running tests asan files may remain. Solution: Clean up asan files with "make testclean". --- src/Makefile | 3 ++- src/testdir/Makefile | 1 + src/version.c | 2 ++ 3 files changed, 5 insertions(+), 1 deletion(-) diff --git a/src/Makefile b/src/Makefile index c32ea0840b..b110f91135 100644 --- a/src/Makefile +++ b/src/Makefile @@ -696,7 +696,8 @@ LINT_OPTIONS = -beprxzF # More at: https://code.google.com/p/address-sanitizer/ # Useful environment variables: # $ export ASAN_OPTIONS="print_stacktrace=1 log_path=asan" -# $ export LSAN_OPTIONS="suppressions=$cwd/testdir/lsan-suppress.txt" +# $ export LSAN_OPTIONS="suppressions=`pwd`/testdir/lsan-suppress.txt" +# When running tests output can be found in testdir/asan.* #SANITIZER_CFLAGS = -g -O0 -fsanitize=address -fno-omit-frame-pointer #SANITIZER_CFLAGS = -g -O0 -fsanitize=undefined -fno-omit-frame-pointer SANITIZER_LIBS = $(SANITIZER_CFLAGS) diff --git a/src/testdir/Makefile b/src/testdir/Makefile index 92506e6f41..7f9ef04342 100644 --- a/src/testdir/Makefile +++ b/src/testdir/Makefile @@ -100,6 +100,7 @@ clean: -rm -f opt_test.vim test.log test_result.log messages -rm -f $(RM_ON_RUN) $(RM_ON_START) -rm -f valgrind.* + -rm -f asan.* test1.out: test1.in -rm -rf $*.failed $(RM_ON_RUN) $(RM_ON_START) wrongtermsize diff --git a/src/version.c b/src/version.c index a46ffb46fa..e446e6bfa9 100644 --- a/src/version.c +++ b/src/version.c @@ -746,6 +746,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 621, /**/ 620, /**/ From beae4084fd34c56d43787be73588070ddc474251 Mon Sep 17 00:00:00 2001 From: Bram Moolenaar Date: Thu, 23 Apr 2020 15:41:49 +0200 Subject: [PATCH 016/230] patch 8.2.0622: Haiku: GUI does not compile Problem: Haiku: GUI does not compile. Solution: Various fixes. (Emir Sari, closes #5961) --- Filelist | 1 + README.md | 5 +++-- READMEdir/README_haiku.txt | 13 +++++++++++++ src/Makefile | 4 ++-- src/beval.h | 4 ++++ src/gui_haiku.cc | 12 +++++++----- src/proto/gui_haiku.pro | 2 +- src/version.c | 2 ++ 8 files changed, 33 insertions(+), 10 deletions(-) create mode 100644 READMEdir/README_haiku.txt diff --git a/Filelist b/Filelist index 422a0d0bad..581a72d1aa 100644 --- a/Filelist +++ b/Filelist @@ -607,6 +607,7 @@ SRC_AMI = \ # source files for Haiku (also in the extra archive) SRC_HAIKU = \ + README_haiku.txt \ src/os_haiku.h \ src/os_haiku.rdef \ src/gui_haiku.cc \ diff --git a/README.md b/README.md index 4e3d8433c3..d42680c6ba 100644 --- a/README.md +++ b/README.md @@ -26,8 +26,8 @@ All commands are given with normal keyboard characters, so those who can type with ten fingers can work very fast. Additionally, function keys can be mapped to commands by the user, and the mouse can be used. -Vim runs under MS-Windows (XP, Vista, 7, 8, 10), macOS, VMS and almost all -flavours of UNIX. Porting to other systems should not be very difficult. +Vim runs under MS-Windows (XP, Vista, 7, 8, 10), macOS, Haiku, VMS and almost +all flavours of UNIX. Porting to other systems should not be very difficult. Older versions of Vim run on MS-DOS, MS-Windows 95/98/Me/NT/2000, Amiga DOS, Atari MiNT, BeOS, RISC OS and OS/2. These are no longer maintained. @@ -72,6 +72,7 @@ archive): README_unix.txt Unix README_dos.txt MS-DOS and MS-Windows README_mac.txt Macintosh + README_haiku.txt Haiku README_vms.txt VMS There are other `README_*.txt` files, depending on the distribution you used. diff --git a/READMEdir/README_haiku.txt b/READMEdir/README_haiku.txt new file mode 100644 index 0000000000..7eeb0bbf37 --- /dev/null +++ b/READMEdir/README_haiku.txt @@ -0,0 +1,13 @@ +README_haiku.txt for version 8.2 of Vim: Vi IMproved. + +This file explains the installation of Vim on Haiku operating system. +See "README.txt" for general information about Vim. + +Preferred (and easy) way to get Vim on Haiku is to use default Haiku +software repository HaikuPorts. To get Vim: + +- Open HaikuDepot application and search for "vim" package, then install, +- Open a Terminal and type "pkgman install vim", then follow instructions. + +If you prefer to install Vim from source, follow the instructions on +"runtime/doc/os_haiku.txt", "Compiling Haiku" section. diff --git a/src/Makefile b/src/Makefile index b110f91135..19453c7421 100644 --- a/src/Makefile +++ b/src/Makefile @@ -1404,8 +1404,8 @@ HAIKUGUI_TESTTARGET = gui HAIKUGUI_BUNDLE = # All GUI files -ALL_GUI_SRC = gui.c gui_gtk.c gui_gtk_f.c gui_motif.c gui_xmdlg.c gui_xmebw.c gui_athena.c gui_gtk_x11.c gui_x11.c gui_at_sb.c gui_at_fs.c -ALL_GUI_PRO = gui.pro gui_gtk.pro gui_motif.pro gui_xmdlg.pro gui_athena.pro gui_gtk_x11.pro gui_x11.pro gui_w32.pro gui_photon.pro +ALL_GUI_SRC = gui.c gui_gtk.c gui_gtk_f.c gui_motif.c gui_xmdlg.c gui_xmebw.c gui_athena.c gui_gtk_x11.c gui_x11.c gui_at_sb.c gui_at_fs.c gui_haiku.cc +ALL_GUI_PRO = gui.pro gui_gtk.pro gui_motif.pro gui_xmdlg.pro gui_athena.pro gui_gtk_x11.pro gui_x11.pro gui_w32.pro gui_photon.pro gui_haiku.pro # }}} diff --git a/src/beval.h b/src/beval.h index f44620038d..4332389642 100644 --- a/src/beval.h +++ b/src/beval.h @@ -79,6 +79,10 @@ typedef struct BalloonEvalStruct #ifdef FEAT_GUI_MSWIN void *tofree; #endif +#ifdef FEAT_GUI_HAIKU + int x; + int y; +#endif } BalloonEval; #define EVAL_OFFSET_X 15 // displacement of beval topleft corner from pointer diff --git a/src/gui_haiku.cc b/src/gui_haiku.cc index b7ecf64402..f26e9035a5 100644 --- a/src/gui_haiku.cc +++ b/src/gui_haiku.cc @@ -2916,6 +2916,7 @@ VimToolbar::RemoveButton(vimmenu_T *menu) menu->button = NULL; } } + return true; } bool @@ -2926,6 +2927,7 @@ VimToolbar::GrayButton(vimmenu_T *menu, int grey) if(index >= 0) menu->button->SetEnabled(grey ? false : true); } + return true; } void @@ -3563,7 +3565,7 @@ gui_mch_set_text_area_pos( gui.vimTextArea->MoveTo(x, y); gui.vimTextArea->ResizeTo(w - PEN_WIDTH, h - PEN_WIDTH); -/*#ifdef FEAT_GUI_TABLINE +#ifdef FEAT_GUI_TABLINE if(gui.vimForm->TabLine() != NULL) { gui.vimForm->TabLine()->ResizeTo(w, gui.vimForm->TablineHeight()); } @@ -3679,7 +3681,7 @@ gui_mch_create_scrollbar( } } -#if defined(FEAT_WINDOWS) || defined(PROTO) +#if defined(FEAT_WINDOWS) || defined(FEAT_GUI_HAIKU) || defined(PROTO) void gui_mch_destroy_scrollbar( scrollbar_T *sb) @@ -3736,7 +3738,7 @@ gui_mch_set_blinking( * Stop the cursor blinking. Show the cursor if it wasn't shown. */ void -gui_mch_stop_blink() +gui_mch_stop_blink(int may_call_gui_update_cursor) { // TODO if (blink_timer != 0) @@ -3870,7 +3872,7 @@ gui_mch_get_font( hl_set_font_name((char_u*)font_name); // Set guifont to the name of the selected font. - char_u* new_p_guifont = alloc(STRLEN(font_name) + 1); + char_u* new_p_guifont = (char_u*)alloc(STRLEN(font_name) + 1); if (new_p_guifont != NULL) { STRCPY(new_p_guifont, font_name); vim_free(p_guifont); @@ -4488,7 +4490,7 @@ gui_mch_wait_for_chars( if (gui.in_focus) gui_mch_start_blink(); else - gui_mch_stop_blink(); + gui_mch_stop_blink(TRUE); focus = gui.in_focus; } diff --git a/src/proto/gui_haiku.pro b/src/proto/gui_haiku.pro index 4d4c7d30de..f392233311 100644 --- a/src/proto/gui_haiku.pro +++ b/src/proto/gui_haiku.pro @@ -6,7 +6,7 @@ int gui_mch_open(void); void gui_mch_exit(int vim_exitcode); int gui_mch_init_check(void); void gui_mch_flush(void); - +int gui_mch_is_blink_off(void); void gui_mch_new_colors(void); void gui_mch_set_bg_color(guicolor_T color); void gui_mch_set_fg_color(guicolor_T color); diff --git a/src/version.c b/src/version.c index e446e6bfa9..7bfe8b050e 100644 --- a/src/version.c +++ b/src/version.c @@ -746,6 +746,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 622, /**/ 621, /**/ From f7b398c6a9476a2004a42555b731ebf47b866408 Mon Sep 17 00:00:00 2001 From: Bram Moolenaar Date: Thu, 23 Apr 2020 15:46:35 +0200 Subject: [PATCH 017/230] patch 8.2.0623: typo in test comment Problem: Typo in test comment. (Christ van Willegen) Solution: Avoid mixing up a data structure with a body part. --- src/testdir/test_listdict.vim | 2 +- src/version.c | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/src/testdir/test_listdict.vim b/src/testdir/test_listdict.vim index 2087f77ec9..a2cc6b5a2d 100644 --- a/src/testdir/test_listdict.vim +++ b/src/testdir/test_listdict.vim @@ -547,7 +547,7 @@ func Test_dict_lock_extend() call assert_equal({'a': 99, 'b': 100}, d) endfunc -" Cannot use += with a locked dick +" Cannot use += with a locked dict func Test_dict_lock_operator() unlet! d let d = {} diff --git a/src/version.c b/src/version.c index 7bfe8b050e..b2268736f1 100644 --- a/src/version.c +++ b/src/version.c @@ -746,6 +746,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 623, /**/ 622, /**/ From a72cfb80cd7aa589ad2a4fb8766ed6d30ea8ae33 Mon Sep 17 00:00:00 2001 From: Bram Moolenaar Date: Thu, 23 Apr 2020 17:07:30 +0200 Subject: [PATCH 018/230] patch 8.2.0624: Vim9: no check for space before #comment Problem: Vim9: no check for space before #comment. Solution: Add space checks. Fix :throw with double quoted string. --- src/testdir/test_vim9_script.vim | 92 ++++++++++++++++++++++++++++++-- src/usercmd.c | 4 +- src/userfunc.c | 4 +- src/version.c | 2 + src/vim9compile.c | 5 -- 5 files changed, 94 insertions(+), 13 deletions(-) diff --git a/src/testdir/test_vim9_script.vim b/src/testdir/test_vim9_script.vim index 219a86f270..5eda50b733 100644 --- a/src/testdir/test_vim9_script.vim +++ b/src/testdir/test_vim9_script.vim @@ -361,7 +361,7 @@ def Test_try_catch() enddef def ThrowFromDef() - throw 'getout' + throw "getout" # comment enddef func CatchInFunc() @@ -430,7 +430,7 @@ def Test_try_catch_fails() call CheckDefFailure(['if 2', 'endtry'], 'E171:') call CheckDefFailure(['try', 'echo 1', 'endtry'], 'E1032:') - call CheckDefFailure(['throw'], 'E471:') + call CheckDefFailure(['throw'], 'E1015:') call CheckDefFailure(['throw xxx'], 'E1001:') enddef @@ -937,12 +937,18 @@ def Test_execute_cmd() setline(1, 'default') execute 'call setline(1, "execute-string")' assert_equal('execute-string', getline(1)) + + execute "call setline(1, 'execute-string')" + assert_equal('execute-string', getline(1)) + let cmd1 = 'call setline(1,' let cmd2 = '"execute-var")' - execute cmd1 cmd2 + execute cmd1 cmd2 # comment assert_equal('execute-var', getline(1)) + execute cmd1 cmd2 '|call setline(1, "execute-var-string")' assert_equal('execute-var-string', getline(1)) + let cmd_first = 'call ' let cmd_last = 'setline(1, "execute-var-var")' execute cmd_first .. cmd_last @@ -950,17 +956,24 @@ def Test_execute_cmd() bwipe! call CheckDefFailure(['execute xxx'], 'E1001:') + call CheckDefFailure(['execute "cmd"# comment'], 'E488:') enddef def Test_echo_cmd() - echo 'some' + echo 'some' # comment echon 'thing' assert_match('^something$', Screenline(&lines)) + echo "some" # comment + echon "thing" + assert_match('^something$', Screenline(&lines)) + let str1 = 'some' let str2 = 'more' echo str1 str2 assert_match('^some more$', Screenline(&lines)) + + call CheckDefFailure(['echo "xxx"# comment'], 'E488:') enddef def Test_for_outside_of_function() @@ -1162,6 +1175,18 @@ def Test_vim9_comment() 'try# comment', 'echo "yes"', ], 'E488:') + CheckDefFailure([ + 'try', + ' throw#comment', + 'catch', + 'endtry', + ], 'E1015:') + CheckDefFailure([ + 'try', + ' throw "yes"#comment', + 'catch', + 'endtry', + ], 'E488:') CheckDefFailure([ 'try', ' echo "yes"', @@ -1380,6 +1405,65 @@ def Test_vim9_comment() 'vim9script', 'syntax cluster Some contains=Word# comment', ], 'E475:') + + CheckScriptSuccess([ + 'vim9script', + 'command Echo echo # comment', + 'command Echo # comment', + ]) + CheckScriptFailure([ + 'vim9script', + 'command Echo echo# comment', + 'Echo', + ], 'E121:') + CheckScriptFailure([ + 'vim9script', + 'command Echo# comment', + ], 'E182:') + CheckScriptFailure([ + 'vim9script', + 'command Echo echo', + 'command Echo# comment', + ], 'E182:') + + CheckScriptSuccess([ + 'vim9script', + 'function # comment', + ]) + CheckScriptFailure([ + 'vim9script', + 'function# comment', + ], 'E129:') + CheckScriptSuccess([ + 'vim9script', + 'function CheckScriptSuccess # comment', + ]) + CheckScriptFailure([ + 'vim9script', + 'function CheckScriptSuccess# comment', + ], 'E488:') + + CheckScriptSuccess([ + 'vim9script', + 'func DeleteMe()', + 'endfunc', + 'delfunction DeleteMe # comment', + ]) + CheckScriptFailure([ + 'vim9script', + 'func DeleteMe()', + 'endfunc', + 'delfunction DeleteMe# comment', + ], 'E488:') + + CheckScriptSuccess([ + 'vim9script', + 'call execute("ls") # comment', + ]) + CheckScriptFailure([ + 'vim9script', + 'call execute("ls")# comment', + ], 'E488:') enddef def Test_vim9_comment_gui() diff --git a/src/usercmd.c b/src/usercmd.c index fc14430b64..cdc46a10b9 100644 --- a/src/usercmd.c +++ b/src/usercmd.c @@ -1007,7 +1007,7 @@ ex_command(exarg_T *eap) if (ASCII_ISALPHA(*p)) while (ASCII_ISALNUM(*p)) ++p; - if (!ends_excmd(*p) && !VIM_ISWHITE(*p)) + if (!ends_excmd2(eap->arg, p) && !VIM_ISWHITE(*p)) { emsg(_("E182: Invalid command name")); return; @@ -1018,7 +1018,7 @@ ex_command(exarg_T *eap) // If there is nothing after the name, and no attributes were specified, // we are listing commands p = skipwhite(end); - if (!has_attr && ends_excmd(*p)) + if (!has_attr && ends_excmd2(eap->arg, p)) { uc_list(name, end - name); } diff --git a/src/userfunc.c b/src/userfunc.c index dfda733a1c..698c1b1e3d 100644 --- a/src/userfunc.c +++ b/src/userfunc.c @@ -2373,7 +2373,7 @@ ex_function(exarg_T *eap) /* * ":function" without argument: list functions. */ - if (ends_excmd(*eap->arg)) + if (ends_excmd2(eap->cmd, eap->arg)) { if (!eap->skip) { @@ -3711,7 +3711,7 @@ ex_call(exarg_T *eap) if (!failed || eap->cstack->cs_trylevel > 0) { // Check for trailing illegal characters and a following command. - if (!ends_excmd(*arg)) + if (!ends_excmd2(eap->arg, arg)) { if (!failed) { diff --git a/src/version.c b/src/version.c index b2268736f1..86cfce0957 100644 --- a/src/version.c +++ b/src/version.c @@ -746,6 +746,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 624, /**/ 623, /**/ diff --git a/src/vim9compile.c b/src/vim9compile.c index daa1cbea41..393d2b824c 100644 --- a/src/vim9compile.c +++ b/src/vim9compile.c @@ -5752,11 +5752,6 @@ compile_throw(char_u *arg, cctx_T *cctx UNUSED) { char_u *p = skipwhite(arg); - if (ends_excmd(*p)) - { - emsg(_(e_argreq)); - return NULL; - } if (compile_expr1(&p, cctx) == FAIL) return NULL; if (may_generate_2STRING(-1, cctx) == FAIL) From 1df8b3fb04ce8732a0be680273c95eb4e9f5e85d Mon Sep 17 00:00:00 2001 From: Bram Moolenaar Date: Thu, 23 Apr 2020 18:13:23 +0200 Subject: [PATCH 019/230] patch 8.2.0625: Vim9: confusing error when calling unknown function Problem: Vim9: confusing error when calling unknown function. Solution: Give error while compiling. --- src/testdir/test_vim9_func.vim | 27 ++++++++++++++++++--------- src/version.c | 2 ++ src/vim9compile.c | 8 ++++++-- src/vim9execute.c | 21 ++++++++++++++------- 4 files changed, 40 insertions(+), 18 deletions(-) diff --git a/src/testdir/test_vim9_func.vim b/src/testdir/test_vim9_func.vim index 8a6c3d607a..d36467996f 100644 --- a/src/testdir/test_vim9_func.vim +++ b/src/testdir/test_vim9_func.vim @@ -193,10 +193,23 @@ def Test_using_var_as_arg() enddef def Test_call_func_defined_later() - call assert_equal('one', DefinedLater('one')) + call assert_equal('one', g:DefinedLater('one')) call assert_fails('call NotDefined("one")', 'E117:') enddef +func DefinedLater(arg) + return a:arg +endfunc + +def Test_call_funcref() + assert_equal(3, g:SomeFunc('abc')) + assert_fails('NotAFunc()', 'E117:') + assert_fails('g:NotAFunc()', 'E117:') +enddef + +let SomeFunc = function('len') +let NotAFunc = 'text' + def CombineFuncrefTypes() " same arguments, different return type let Ref1: func(bool): string @@ -217,12 +230,8 @@ def CombineFuncrefTypes() Refb3 = g:cond ? Refb1 : Refb2 enddef -func DefinedLater(arg) - return a:arg -endfunc - def FuncWithForwardCall() - return DefinedEvenLater("yes") + return g:DefinedEvenLater("yes") enddef def DefinedEvenLater(arg: string): string @@ -372,9 +381,9 @@ def Test_redef_failure() so Xdef call delete('Xdef') - call assert_equal(0, Func0()) - call assert_equal('Func1', Func1()) - call assert_equal('Func2', Func2()) + call assert_equal(0, g:Func0()) + call assert_equal('Func1', g:Func1()) + call assert_equal('Func2', g:Func2()) delfunc! Func0 delfunc! Func1 diff --git a/src/version.c b/src/version.c index 86cfce0957..da1c24326a 100644 --- a/src/version.c +++ b/src/version.c @@ -746,6 +746,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 625, /**/ 624, /**/ diff --git a/src/vim9compile.c b/src/vim9compile.c index 393d2b824c..7e1c22e8b5 100644 --- a/src/vim9compile.c +++ b/src/vim9compile.c @@ -2463,8 +2463,12 @@ compile_call(char_u **arg, size_t varlen, cctx_T *cctx, int argcount_init) goto theend; } - // The function may be defined only later. Need to figure out at runtime. - res = generate_UCALL(cctx, name, argcount); + // A global function may be defined only later. Need to figure out at + // runtime. + if (STRNCMP(namebuf, "g:", 2) == 0) + res = generate_UCALL(cctx, name, argcount); + else + semsg(_(e_unknownfunc), namebuf); theend: vim_free(tofree); diff --git a/src/vim9execute.c b/src/vim9execute.c index 6c8b8c86ea..a98e7e3265 100644 --- a/src/vim9execute.c +++ b/src/vim9execute.c @@ -460,13 +460,20 @@ call_eval_func(char_u *name, int argcount, ectx_T *ectx, isn_T *iptr) if (call_by_name(name, argcount, ectx, iptr) == FAIL && called_emsg == called_emsg_before) { - // "name" may be a variable that is a funcref or partial - // if find variable - // call_partial() - // else - // semsg(_(e_unknownfunc), name); - emsg("call_eval_func(partial) not implemented yet"); - return FAIL; + dictitem_T *v; + + v = find_var(name, NULL, FALSE); + if (v == NULL) + { + semsg(_(e_unknownfunc), name); + return FAIL; + } + if (v->di_tv.v_type != VAR_PARTIAL && v->di_tv.v_type != VAR_FUNC) + { + semsg(_(e_unknownfunc), name); + return FAIL; + } + return call_partial(&v->di_tv, argcount, ectx); } return OK; } From f93c7fea084a99848d512ff2732041d4b41d93c8 Mon Sep 17 00:00:00 2001 From: Bram Moolenaar Date: Thu, 23 Apr 2020 22:16:53 +0200 Subject: [PATCH 020/230] patch 8.2.0626: Vim9: wrong syntax of function in Vim9 script Problem: Vim9: wrong syntax of function in Vim9 script. Solution: Give error for missing space. Implement :echomsg and :echoerr. (closes #5670) --- src/eval.c | 6 +-- src/globals.h | 6 +++ src/testdir/test_vim9_disassemble.vim | 22 +++++++++ src/testdir/test_vim9_func.vim | 15 ++++++ src/testdir/test_vim9_script.vim | 18 +++++++ src/userfunc.c | 8 ++- src/version.c | 2 + src/vim9.h | 2 + src/vim9compile.c | 71 +++++++++++---------------- src/vim9execute.c | 39 ++++++++++++++- 10 files changed, 141 insertions(+), 48 deletions(-) diff --git a/src/eval.c b/src/eval.c index c3f0de8e32..260ce96f12 100644 --- a/src/eval.c +++ b/src/eval.c @@ -34,8 +34,6 @@ static char *e_float_as_string = N_("E806: using Float as a String"); */ static int current_copyID = 0; -static int echo_attr = 0; // attributes used for ":echo" - /* * Info used by a ":for" loop. */ @@ -6145,7 +6143,6 @@ ex_execute(exarg_T *eap) char_u *p; garray_T ga; int len; - int save_did_emsg; ga_init2(&ga, 1, 80); @@ -6213,8 +6210,9 @@ ex_execute(exarg_T *eap) } else if (eap->cmdidx == CMD_echoerr) { + int save_did_emsg = did_emsg; + // We don't want to abort following commands, restore did_emsg. - save_did_emsg = did_emsg; emsg(ga.ga_data); if (!force_abort) did_emsg = save_did_emsg; diff --git a/src/globals.h b/src/globals.h index f6c9d60e2b..725493b320 100644 --- a/src/globals.h +++ b/src/globals.h @@ -1750,6 +1750,10 @@ EXTERN char e_endif_without_if[] INIT(= N_("E580: :endif without :if")); EXTERN char e_continue[] INIT(= N_("E586: :continue without :while or :for")); EXTERN char e_break[] INIT(= N_("E587: :break without :while or :for")); EXTERN char e_nowhitespace[] INIT(= N_("E274: No white space allowed before parenthesis")); +EXTERN char e_white_both[] INIT(= N_("E1004: white space required before and after '%s'")); +EXTERN char e_white_after[] INIT(= N_("E1069: white space required after '%s'")); +EXTERN char e_no_white_before[] INIT(= N_("E1068: No white space allowed before '%s'")); + EXTERN char e_lock_unlock[] INIT(= N_("E940: Cannot lock or unlock variable %s")); #endif @@ -1819,6 +1823,8 @@ EXTERN proftime_T bevalexpr_due; #ifdef FEAT_EVAL EXTERN time_T time_for_testing INIT(= 0); +EXTERN int echo_attr INIT(= 0); // attributes used for ":echo" + // Abort conversion to string after a recursion error. EXTERN int did_echo_string_emsg INIT(= FALSE); diff --git a/src/testdir/test_vim9_disassemble.vim b/src/testdir/test_vim9_disassemble.vim index 7814952789..89ca66f11b 100644 --- a/src/testdir/test_vim9_disassemble.vim +++ b/src/testdir/test_vim9_disassemble.vim @@ -919,6 +919,28 @@ def Test_disassemble_execute() res) enddef +def s:Echomsg() + echomsg 'some' 'message' + echoerr 'went' .. 'wrong' +enddef + +def Test_disassemble_echomsg() + let res = execute('disass s:Echomsg') + assert_match('\\d*_Echomsg.*' .. + "echomsg 'some' 'message'.*" .. + '\d PUSHS "some".*' .. + '\d PUSHS "message".*' .. + '\d ECHOMSG 2.*' .. + "echoerr 'went' .. 'wrong'.*" .. + '\d PUSHS "went".*' .. + '\d PUSHS "wrong".*' .. + '\d CONCAT.*' .. + '\d ECHOERR 1.*' .. + '\d PUSHNR 0.*' .. + '\d RETURN', + res) +enddef + def SomeStringArg(arg: string) echo arg enddef diff --git a/src/testdir/test_vim9_func.vim b/src/testdir/test_vim9_func.vim index d36467996f..f3721ba9f9 100644 --- a/src/testdir/test_vim9_func.vim +++ b/src/testdir/test_vim9_func.vim @@ -259,6 +259,7 @@ enddef def Test_arg_type_wrong() CheckScriptFailure(['def Func3(items: list)', 'echo "a"', 'enddef'], 'E1008: Missing ') CheckScriptFailure(['def Func4(...)', 'echo "a"', 'enddef'], 'E1055: Missing name after ...') + CheckScriptFailure(['def Func5(items:string)', 'echo "a"'], 'E1069:') CheckScriptFailure(['def Func5(items)', 'echo "a"'], 'E1077:') enddef @@ -390,6 +391,20 @@ def Test_redef_failure() delfunc! Func2 enddef +def Test_vim9script_func() + let lines =<< trim END + vim9script + func Func(arg) + echo a:arg + endfunc + Func('text') + END + writefile(lines, 'XVim9Func') + so XVim9Func + + delete('XVim9Func') +enddef + " Test for internal functions returning different types func Test_InternalFuncRetType() let lines =<< trim END diff --git a/src/testdir/test_vim9_script.vim b/src/testdir/test_vim9_script.vim index 5eda50b733..f06bb734c4 100644 --- a/src/testdir/test_vim9_script.vim +++ b/src/testdir/test_vim9_script.vim @@ -54,6 +54,10 @@ def Test_assignment() let dict4: dict = #{one: 1, two: '2'} let dict5: dict = #{one: 0z01, tw: 0z02} + call CheckDefFailure(['let x:string'], 'E1069:') + call CheckDefFailure(['let x:string = "x"'], 'E1069:') + call CheckDefFailure(['let a:string = "x"'], 'E1082:') + let a: number = 6 assert_equal(6, a) @@ -976,6 +980,20 @@ def Test_echo_cmd() call CheckDefFailure(['echo "xxx"# comment'], 'E488:') enddef +def Test_echomsg_cmd() + echomsg 'some' 'more' # comment + assert_match('^some more$', Screenline(&lines)) + echo 'clear' + 1messages + assert_match('^some more$', Screenline(&lines)) + + call CheckDefFailure(['echomsg "xxx"# comment'], 'E488:') +enddef + +def Test_echoerr_cmd() + # TODO: write this test +enddef + def Test_for_outside_of_function() let lines =<< trim END vim9script diff --git a/src/userfunc.c b/src/userfunc.c index 698c1b1e3d..fa729bbe70 100644 --- a/src/userfunc.c +++ b/src/userfunc.c @@ -128,7 +128,13 @@ one_function_arg(char_u *arg, garray_T *newargs, garray_T *argtypes, int skip) } if (*p == ':') { - type = skipwhite(p + 1); + ++p; + if (!VIM_ISWHITE(*p)) + { + semsg(_(e_white_after), ":"); + return arg; + } + type = skipwhite(p); p = skip_type(type); type = vim_strnsave(type, p - type); } diff --git a/src/version.c b/src/version.c index da1c24326a..181cfc05f7 100644 --- a/src/version.c +++ b/src/version.c @@ -746,6 +746,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 626, /**/ 625, /**/ diff --git a/src/vim9.h b/src/vim9.h index a75e1752cd..f1da323188 100644 --- a/src/vim9.h +++ b/src/vim9.h @@ -15,6 +15,8 @@ typedef enum { ISN_EXEC, // execute Ex command line isn_arg.string 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 + ISN_ECHOERR, // echo Ex commands isn_arg.number items on top of stack // get and set variables ISN_LOAD, // push local variable isn_arg.number diff --git a/src/vim9compile.c b/src/vim9compile.c index 7e1c22e8b5..4d1e3acc64 100644 --- a/src/vim9compile.c +++ b/src/vim9compile.c @@ -1401,14 +1401,14 @@ generate_ECHO(cctx_T *cctx, int with_white, int count) } /* - * Generate an ISN_EXECUTE instruction. + * Generate an ISN_EXECUTE/ISN_ECHOMSG/ISN_ECHOERR instruction. */ static int -generate_EXECUTE(cctx_T *cctx, int count) +generate_MULT_EXPR(cctx_T *cctx, isntype_T isn_type, int count) { isn_T *isn; - if ((isn = generate_instr_drop(cctx, ISN_EXECUTE, count)) == NULL) + if ((isn = generate_instr_drop(cctx, isn_type, count)) == NULL) return FAIL; isn->isn_arg.number = count; @@ -1427,11 +1427,6 @@ generate_EXEC(cctx_T *cctx, char_u *line) return OK; } -static char e_white_both[] = - N_("E1004: white space required before and after '%s'"); -static char e_white_after[] = N_("E1069: white space required after '%s'"); -static char e_no_white_before[] = N_("E1068: No white space allowed before '%s'"); - /* * Reserve space for a local variable. * Return the index or -1 if it failed. @@ -4203,6 +4198,11 @@ compile_assignment(char_u *arg, exarg_T *eap, cmdidx_T cmdidx, cctx_T *cctx) goto theend; } } + else if (name[1] == ':' && name[2] != NUL) + { + semsg(_("E1082: Cannot use a namespaced variable: %s"), name); + goto theend; + } } } @@ -4211,6 +4211,11 @@ compile_assignment(char_u *arg, exarg_T *eap, cmdidx_T cmdidx, cctx_T *cctx) if (is_decl && *p == ':') { // parse optional type: "let var: type = expr" + if (!VIM_ISWHITE(p[1])) + { + semsg(_(e_white_after), ":"); + goto theend; + } p = skipwhite(p + 1); type = parse_type(&p, cctx->ctx_type_list); has_type = TRUE; @@ -5768,32 +5773,12 @@ compile_throw(char_u *arg, cctx_T *cctx UNUSED) /* * compile "echo expr" - */ - static char_u * -compile_echo(char_u *arg, int with_white, cctx_T *cctx) -{ - char_u *p = arg; - int count = 0; - - for (;;) - { - if (compile_expr1(&p, cctx) == FAIL) - return NULL; - ++count; - p = skipwhite(p); - if (ends_excmd(*p)) - break; - } - - generate_ECHO(cctx, with_white, count); - return p; -} - -/* + * compile "echomsg expr" + * compile "echoerr expr" * compile "execute expr" */ static char_u * -compile_execute(char_u *arg, cctx_T *cctx) +compile_mult_expr(char_u *arg, int cmdidx, cctx_T *cctx) { char_u *p = arg; int count = 0; @@ -5808,8 +5793,14 @@ compile_execute(char_u *arg, cctx_T *cctx) break; } - generate_EXECUTE(cctx, count); - + if (cmdidx == CMD_echo || cmdidx == CMD_echon) + generate_ECHO(cctx, cmdidx == CMD_echo, count); + else if (cmdidx == CMD_execute) + generate_MULT_EXPR(cctx, ISN_EXECUTE, count); + else if (cmdidx == CMD_echomsg) + generate_MULT_EXPR(cctx, ISN_ECHOMSG, count); + else + generate_MULT_EXPR(cctx, ISN_ECHOERR, count); return p; } @@ -6184,20 +6175,16 @@ compile_def_function(ufunc_T *ufunc, int set_return_type) break; case CMD_echo: - line = compile_echo(p, TRUE, &cctx); - break; case CMD_echon: - line = compile_echo(p, FALSE, &cctx); - break; case CMD_execute: - line = compile_execute(p, &cctx); + case CMD_echomsg: + case CMD_echoerr: + line = compile_mult_expr(p, ea.cmdidx, &cctx); break; default: // Not recognized, execute with do_cmdline_cmd(). - // TODO: - // CMD_echomsg - // etc. + // TODO: other commands with an expression argument generate_EXEC(&cctx, line); line = (char_u *)""; break; @@ -6415,6 +6402,8 @@ delete_instr(isn_T *isn) case ISN_DROP: case ISN_ECHO: case ISN_EXECUTE: + case ISN_ECHOMSG: + case ISN_ECHOERR: case ISN_ENDTRY: case ISN_FOR: case ISN_FUNCREF: diff --git a/src/vim9execute.c b/src/vim9execute.c index a98e7e3265..8c136967f7 100644 --- a/src/vim9execute.c +++ b/src/vim9execute.c @@ -668,8 +668,12 @@ call_def_function( } break; - // execute :execute {string} ... + // :execute {string} ... + // :echomsg {string} ... + // :echoerr {string} ... case ISN_EXECUTE: + case ISN_ECHOMSG: + case ISN_ECHOERR: { int count = iptr->isn_arg.number; garray_T ga; @@ -705,7 +709,30 @@ call_def_function( ectx.ec_stack.ga_len -= count; if (!failed && ga.ga_data != NULL) - do_cmdline_cmd((char_u *)ga.ga_data); + { + if (iptr->isn_type == ISN_EXECUTE) + do_cmdline_cmd((char_u *)ga.ga_data); + else + { + msg_sb_eol(); + if (iptr->isn_type == ISN_ECHOMSG) + { + msg_attr(ga.ga_data, echo_attr); + out_flush(); + } + else + { + int save_did_emsg = did_emsg; + + SOURCING_LNUM = iptr->isn_lnum; + emsg(ga.ga_data); + if (!force_abort) + // We don't want to abort following + // commands, restore did_emsg. + did_emsg = save_did_emsg; + } + } + } ga_clear(&ga); } break; @@ -1947,6 +1974,14 @@ ex_disassemble(exarg_T *eap) smsg("%4d EXECUTE %lld", current, (long long)(iptr->isn_arg.number)); break; + case ISN_ECHOMSG: + smsg("%4d ECHOMSG %lld", current, + (long long)(iptr->isn_arg.number)); + break; + case ISN_ECHOERR: + smsg("%4d ECHOERR %lld", current, + (long long)(iptr->isn_arg.number)); + break; case ISN_LOAD: if (iptr->isn_arg.number < 0) smsg("%4d LOAD arg[%lld]", current, From b8ce6b0005573139fd101dc703ed30360940401b Mon Sep 17 00:00:00 2001 From: Bram Moolenaar Date: Thu, 23 Apr 2020 22:23:14 +0200 Subject: [PATCH 021/230] patch 8.2.0627: Vim9: error message does not work Problem: Vim9: error message does not work. (Yegappan Lakshmanan) Solution: Swap lines. --- src/userfunc.c | 2 +- src/version.c | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/src/userfunc.c b/src/userfunc.c index fa729bbe70..6005af1f59 100644 --- a/src/userfunc.c +++ b/src/userfunc.c @@ -2614,8 +2614,8 @@ ex_function(exarg_T *eap) } else { - ret_type = NULL; semsg(_("E1056: expected a type: %s"), ret_type); + ret_type = NULL; } } } diff --git a/src/version.c b/src/version.c index 181cfc05f7..6285766be1 100644 --- a/src/version.c +++ b/src/version.c @@ -746,6 +746,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 627, /**/ 626, /**/ From e71ebb46a252cd1cdfb075e6014c2b13c580bf3f Mon Sep 17 00:00:00 2001 From: Bram Moolenaar Date: Thu, 23 Apr 2020 23:54:04 +0200 Subject: [PATCH 022/230] patch 8.2.0628: error in menu translations Problem: Error in menu translations. Solution: Insert a backslash before a space in one more file. (Shun Bai, Emir Sari) --- runtime/lang/menu_ca_es.latin1.vim | 2 +- runtime/lang/menu_cs_cz.iso_8859-2.vim | 2 +- runtime/lang/menu_cs_cz.utf-8.vim | 2 +- .../lang/menu_czech_czech_republic.1250.vim | 2 +- .../lang/menu_czech_czech_republic.ascii.vim | 2 +- runtime/lang/menu_da.utf-8.vim | 12 +-- runtime/lang/menu_fi_fi.latin1.vim | 8 +- runtime/lang/menu_hu_hu.iso_8859-2.vim | 4 +- runtime/lang/menu_hu_hu.utf-8.vim | 4 +- runtime/lang/menu_is_is.latin1.vim | 6 +- runtime/lang/menu_no_no.latin1.vim | 4 +- runtime/lang/menu_pt_br.vim | 20 ++--- runtime/lang/menu_pt_pt.vim | 4 +- runtime/lang/menu_sk_sk.iso_8859-2.vim | 16 ++-- runtime/lang/menu_sl_si.latin2.vim | 6 +- .../lang/menu_slovak_slovak_republic.1250.vim | 16 ++-- runtime/lang/menu_tr_tr.cp1254.vim | 74 +++++++++--------- runtime/lang/menu_tr_tr.iso_8859-9.vim | 74 +++++++++--------- runtime/lang/menu_tr_tr.utf-8.vim | 76 +++++++++---------- runtime/lang/menu_vi_vn.vim | 6 +- runtime/lang/menu_zh_cn.utf-8.vim | 4 +- src/version.c | 2 + 22 files changed, 174 insertions(+), 172 deletions(-) diff --git a/runtime/lang/menu_ca_es.latin1.vim b/runtime/lang/menu_ca_es.latin1.vim index 8c0a9e9a61..6e30eef9df 100644 --- a/runtime/lang/menu_ca_es.latin1.vim +++ b/runtime/lang/menu_ca_es.latin1.vim @@ -79,7 +79,7 @@ menutrans &Global\ Settings Opcions\ &globals menutrans Never &Mai menutrans Block\ Selection &Selecci\ de\ blocs menutrans Insert\ mode Mode\ d'&inserci - menutrans Block\ and\ Insert &Blocs i inserci + menutrans Block\ and\ Insert &Blocs\ i\ inserci menutrans Always S&empre menutrans Toggle\ Insert\ &Mode:set\ im! Mode\ d'&inserci:set\ im! menutrans Toggle\ Vi\ C&ompatible:set\ cp! Co&mpatible\ amb\ Vi:set\ cp! diff --git a/runtime/lang/menu_cs_cz.iso_8859-2.vim b/runtime/lang/menu_cs_cz.iso_8859-2.vim index 410d548ee1..1abf0c35e2 100644 --- a/runtime/lang/menu_cs_cz.iso_8859-2.vim +++ b/runtime/lang/menu_cs_cz.iso_8859-2.vim @@ -110,7 +110,7 @@ menutrans Build\ &Tags\ File &Vytvo if has("spell") menutrans &Spelling &Kontrola\ pravopisu menutrans &Spell\ Check\ On &Zapnout\ kontrolu\ pravopisu - menutrans Spell\ Check\ &Off &Vypnout \kontrolu\ pravopisu + menutrans Spell\ Check\ &Off &Vypnout\ kontrolu\ pravopisu menutrans To\ &Next\ error]s &Dal\ chyba]s menutrans To\ &Previous\ error[s &Pedchoz\ chyba[s menutrans Suggest\ &Correctionsz= &Navrhnout\ opravyz= diff --git a/runtime/lang/menu_cs_cz.utf-8.vim b/runtime/lang/menu_cs_cz.utf-8.vim index 91a8eccd46..a7be2c8b39 100644 --- a/runtime/lang/menu_cs_cz.utf-8.vim +++ b/runtime/lang/menu_cs_cz.utf-8.vim @@ -110,7 +110,7 @@ menutrans Build\ &Tags\ File &Vytvořit\ soubor\ tagů if has("spell") menutrans &Spelling &Kontrola\ pravopisu menutrans &Spell\ Check\ On &Zapnout\ kontrolu\ pravopisu - menutrans Spell\ Check\ &Off &Vypnout \kontrolu\ pravopisu + menutrans Spell\ Check\ &Off &Vypnout\ kontrolu\ pravopisu menutrans To\ &Next\ error]s &Další\ chyba]s menutrans To\ &Previous\ error[s &Předchozí\ chyba[s menutrans Suggest\ &Correctionsz= &Navrhnout\ opravyz= diff --git a/runtime/lang/menu_czech_czech_republic.1250.vim b/runtime/lang/menu_czech_czech_republic.1250.vim index f9c85d038a..9502288ed2 100644 --- a/runtime/lang/menu_czech_czech_republic.1250.vim +++ b/runtime/lang/menu_czech_czech_republic.1250.vim @@ -110,7 +110,7 @@ menutrans Build\ &Tags\ File &Vytvo if has("spell") menutrans &Spelling &Kontrola\ pravopisu menutrans &Spell\ Check\ On &Zapnout\ kontrolu\ pravopisu - menutrans Spell\ Check\ &Off &Vypnout \kontrolu\ pravopisu + menutrans Spell\ Check\ &Off &Vypnout\ kontrolu\ pravopisu menutrans To\ &Next\ error]s &Dal\ chyba]s menutrans To\ &Previous\ error[s &Pedchoz\ chyba[s menutrans Suggest\ &Correctionsz= &Navrhnout\ opravyz= diff --git a/runtime/lang/menu_czech_czech_republic.ascii.vim b/runtime/lang/menu_czech_czech_republic.ascii.vim index 1c4fb3ed8f..e7c2c43a4b 100644 --- a/runtime/lang/menu_czech_czech_republic.ascii.vim +++ b/runtime/lang/menu_czech_czech_republic.ascii.vim @@ -110,7 +110,7 @@ menutrans Build\ &Tags\ File &Vytvorit\ soubor\ tagu if has("spell") menutrans &Spelling &Kontrola\ pravopisu menutrans &Spell\ Check\ On &Zapnout\ kontrolu\ pravopisu - menutrans Spell\ Check\ &Off &Vypnout \kontrolu\ pravopisu + menutrans Spell\ Check\ &Off &Vypnout\ kontrolu\ pravopisu menutrans To\ &Next\ error]s &Dalsi\ chyba]s menutrans To\ &Previous\ error[s &Predchozi\ chyba[s menutrans Suggest\ &Correctionsz= &Navrhnout\ opravyz= diff --git a/runtime/lang/menu_da.utf-8.vim b/runtime/lang/menu_da.utf-8.vim index 751dad0947..a11213c05c 100644 --- a/runtime/lang/menu_da.utf-8.vim +++ b/runtime/lang/menu_da.utf-8.vim @@ -1,6 +1,6 @@ " Menu Translations: Danish " Maintainer: scootergrisen -" Last Change: 2018 Aug 17 +" Last Change: 2020 Apr 23 " Quit when menu translations have already been done. if exists("did_menu_trans") @@ -390,7 +390,7 @@ menut Previewp Forhåndsvisp menut Edit\ File\ Hiding\ List Rediger\ liste\ til\ filskjulning menut Edit\ Sorting\ SequenceS Rediger\ sorteringssekvensS menut Quick\ Hide/Unhide\ Dot\ Filesgh Hurtig\ skjul/vis\ punktum-filergh -menut Refresh\ Listing Genopfrisk\ oplistning\ ikke sikker det med \ er korrekt +menut Refresh\ Listing Genopfrisk\ oplistning\\ ikke\ sikker\ det\ med\ er\ korrekt menut Settings/Options:NetrwSettings Indstillinger/valgmuligheder menut Delete\ File/DirectoryD Slet\ fil/mappeD @@ -406,10 +406,10 @@ menut In\ New\ Vertical\ Windowv I\ nyt\ lodret\ vinduev menut Explore Gennemse menut Directory\ Name Mappenavn:Explore -menut Filenames\ Matching\ Pattern\ (curdir\ only):Explore\ */ test29:Explore */ -menut Filenames\ Matching\ Pattern\ (+subdirs):Explore\ **/ test30:Explore **/ -menut Files\ Containing\ String\ Pattern\ (curdir\ only):Explore\ *// test31:Explore *// -menut Files\ Containing\ String\ Pattern\ (+subdirs):Explore\ **// test32:Explore **// +menut Filenames\ Matching\ Pattern\ (curdir\ only):Explore\ */ test29:Explore\ */ +menut Filenames\ Matching\ Pattern\ (+subdirs):Explore\ **/ test30:Explore\ **/ +menut Files\ Containing\ String\ Pattern\ (curdir\ only):Explore\ *// test31:Explore\ *// +menut Files\ Containing\ String\ Pattern\ (+subdirs):Explore\ **// test32:Explore\ **// menut Next\ Match:Nexplore Næste\ match:Nexplore menut Prev\ Match:Pexplore Forrige\ match:Pexplore diff --git a/runtime/lang/menu_fi_fi.latin1.vim b/runtime/lang/menu_fi_fi.latin1.vim index 6a2c1e9053..c68f232eec 100644 --- a/runtime/lang/menu_fi_fi.latin1.vim +++ b/runtime/lang/menu_fi_fi.latin1.vim @@ -1,6 +1,6 @@ " Menu Translations: Finnish " Maintainer: Flammie Pirinen -" Last Change: 2012 May 01 +" Last Change: 2020 Apr 23 " Quit when menu translations have already been done. if exists("did_menu_trans") @@ -70,7 +70,7 @@ menutrans &Context\ lines &Huomioitavat\ kontekstirivit " Subsubmenu: " Accels: ELSOA menutrans &Virtual\ Edit &Virtuaalimuokkaus -menutrans Never &Ei koskaan +menutrans Never &Ei\ koskaan menutrans Block\ Selection &Lohkovalinta menutrans Insert\ mode &Sytttila menutrans Block\ and\ Insert L&ohkosytttila @@ -95,7 +95,7 @@ menutrans F&ile\ Settings Tiedostoasetu&kset menutrans Toggle\ Line\ &Numbering:set\ nu! Rivi&numerointi:set\ nu! menutrans Toggle\ &List\ Mode:set\ list! &Listaustila:set\ list! menutrans Toggle\ Line\ &Wrap:set\ wrap! &Rivitys:set\ wrap! -menutrans Toggle\ W&rap\ at\ word:set\ lbr! &Sanoittainen rivitys:set\ lbr! +menutrans Toggle\ W&rap\ at\ word:set\ lbr! &Sanoittainen\ rivitys:set\ lbr! menutrans Toggle\ &expand-tab:set\ et! Muuta\ &tabit\ vleiksi:set\ et! menutrans Toggle\ &auto-indent:set\ ai! &Automaattinen\ sisennys:set\ ai! menutrans Toggle\ &C-indenting:set\ cin! &C-kielen\ sisennys:set\ cin! @@ -111,7 +111,7 @@ let g:menutrans_fileformat_choices = " &Unix \n &Dos \n &Mac \n &Peru " menutrans C&olor\ Scheme &Vriteema menutrans &Keymap &Nppinkartta -menutrans None Ei mikn +menutrans None Ei\ mikn menutrans Select\ Fo&nt\.\.\. Valitse\ &fontti\.\.\. diff --git a/runtime/lang/menu_hu_hu.iso_8859-2.vim b/runtime/lang/menu_hu_hu.iso_8859-2.vim index c7821d2b32..27c460f3bf 100644 --- a/runtime/lang/menu_hu_hu.iso_8859-2.vim +++ b/runtime/lang/menu_hu_hu.iso_8859-2.vim @@ -1,7 +1,7 @@ " Menu Translations: Hungarian (Magyar) " Original Translation: Zoltn rpdffy " Maintained By: Kontra Gergely -" Last Change: 2012 May 01 +" Last Change: 2020 Apr 23 " I'm working on defining (unaccented) hotkeys for everything. " I want to remove y and z hotkeys, because on the hungarian keymap they're at " a differrent place. @@ -68,7 +68,7 @@ menutrans &Paste"+gP &Beilleszt menutrans Put\ &Before[p Beraks\ e&l[p menutrans Put\ &After]p Beraks\ &mg]p menutrans &Deletex &Trlsx -menutrans &Select\ allggVG A&z\ sszes kijellseggvG +menutrans &Select\ allggVG A&z\ sszes\ kijellseggvG menutrans &Find\.\.\. Ke&ress\.\.\. menutrans Find\ and\ Rep&lace\.\.\. Keress\ s\ c&sere\.\.\. menutrans Find\ and\ Rep&lace:%s Keress\ s\ c&sere:%s diff --git a/runtime/lang/menu_hu_hu.utf-8.vim b/runtime/lang/menu_hu_hu.utf-8.vim index f3adf91882..092abc0857 100644 --- a/runtime/lang/menu_hu_hu.utf-8.vim +++ b/runtime/lang/menu_hu_hu.utf-8.vim @@ -1,7 +1,7 @@ " Menu Translations: Hungarian (Magyar) " Original Translation: Zoltán Árpádffy " Maintained By: Kontra Gergely -" Last Change: 2012 May 01 +" Last Change: 2020 Apr 23 " " This file was converted from menu_hu_hu.iso_8859-2.vim. See there for " remarks. @@ -52,7 +52,7 @@ menutrans &Paste"+gP &Beillesztés"+gP menutrans Put\ &Before[p Berakás\ e&lé[p menutrans Put\ &After]p Berakás\ &mögé]p menutrans &Deletex &Törlésx -menutrans &Select\ allggVG A&z\ összes kijelöléseggvG +menutrans &Select\ allggVG A&z\ összes\ kijelöléseggvG menutrans &Find\.\.\. Ke&resés\.\.\. menutrans Find\ and\ Rep&lace\.\.\. Keresés\ és\ c&sere\.\.\. menutrans Find\ and\ Rep&lace:%s Keresés\ és\ c&sere:%s diff --git a/runtime/lang/menu_is_is.latin1.vim b/runtime/lang/menu_is_is.latin1.vim index 28394e07c9..9616c6cfb4 100644 --- a/runtime/lang/menu_is_is.latin1.vim +++ b/runtime/lang/menu_is_is.latin1.vim @@ -59,7 +59,7 @@ menutrans Startup\ &Settings R menutrans Toggle\ Pattern\ &Highlight:set\ hls! Munsturaukenning\ \/af:set\ hls! menutrans Toggle\ &Ignoring\ Case:set\ ic! Hunsa\ h-lgstafi\ \/af:set\ ic! -menutrans Toggle\ &Showing\ Matched\ Pairs:set\ sm! Sna\ Prun \/af:set\ sm! +menutrans Toggle\ &Showing\ Matched\ Pairs:set\ sm! Sna\ Prun\ \/af:set\ sm! menutrans &Context\ lines Samhengislnur @@ -70,7 +70,7 @@ menutrans Insert\ mode Innskotshamur menutrans Block\ and\ Insert Blkval\ og\ Innskotshamur menutrans Always Alltaf menutrans Toggle\ Insert\ &Mode:set\ im! Innskotshamur\ \/af:set\ im! -menutrans Toggle\ Vi\ C&ompatibility:set\ cp! Vi\ Samhfanleiki \/af:set\ cp! +menutrans Toggle\ Vi\ C&ompatibility:set\ cp! Vi\ Samhfanleiki\ \/af:set\ cp! menutrans Search\ &Path\.\.\. Leita\ \ Sl\.\.\. menutrans Ta&g\ Files\.\.\. Merkja\ Skrr\.\.\. @@ -90,7 +90,7 @@ menutrans Toggle\ &List\ Mode:set\ list! Listahamur\ menutrans Toggle\ Line\ &Wrapping:set\ wrap! Lnuhlaup\ \/af:set\ wrap! menutrans Toggle\ W&rapping\ at\ word:set\ lbr! Lnuhlaup\ \ ori\ \/af:set\ lbr! menutrans Toggle\ Tab\ &Expanding:set\ et! Tab-vkkun\ \/af:set\ et! -menutrans Toggle\ &Auto Indenting:set\ ai! Sjlfvirkur\ Inndrttur\ \/af:set\ ai! +menutrans Toggle\ &Auto\ Indenting:set\ ai! Sjlfvirkur\ Inndrttur\ \/af:set\ ai! menutrans Toggle\ &C-Style\ Indenting:set\ cin! C-Inndrttur\ \/af:set\ cin! " other options diff --git a/runtime/lang/menu_no_no.latin1.vim b/runtime/lang/menu_no_no.latin1.vim index a64e343445..1a5bb4011a 100644 --- a/runtime/lang/menu_no_no.latin1.vim +++ b/runtime/lang/menu_no_no.latin1.vim @@ -1,6 +1,6 @@ " Menu Translations: Norwegian / Norsk (Bokml) " Maintainer: yvind A. Holm -" Last Change: 2012 May 01 +" Last Change: 2020 Apr 23 " menu_no_no.latin1.vim 289 2004-05-16 18:00:52Z sunny " Quit when menu translations have already been done. @@ -46,7 +46,7 @@ menutrans &Edit &Rediger menutrans Settings\ &Window &Innstillinger menutrans &Global\ Settings Glo&bale\ innstillinger menutrans Toggle\ Pattern\ &Highlight:set\ hls! &Utheving\ av\ sketekst\ av/p:set\ hls! - menutrans Toggle\ &Ignore-case:set\ ic! &Forskjell\ mellom\ store/sm bokstaver\ av/p:set\ ic! + menutrans Toggle\ &Ignore-case:set\ ic! &Forskjell\ mellom\ store/sm\ bokstaver\ av/p:set\ ic! menutrans Toggle\ &Showmatch:set\ sm! &Indikering\ av\ samsvarende\ parentes\ av/p:set\ sm! menutrans &Context\ lines &Kontekstlinjer menutrans &Virtual\ Edit Vi&rtuell\ redigering diff --git a/runtime/lang/menu_pt_br.vim b/runtime/lang/menu_pt_br.vim index f4980ef5ac..1e425008de 100644 --- a/runtime/lang/menu_pt_br.vim +++ b/runtime/lang/menu_pt_br.vim @@ -1,6 +1,6 @@ " Menu Translations: Portugus do Brasil " Maintainer: Jos de Paula -" Last Change: 2012 May 01 +" Last Change: 2020 Apr 23 " " Quit when menu translations have already been done. @@ -101,9 +101,9 @@ menutrans Toggle\ Line\ &Numbering:set\ nu! Ativar/Desativar\ &numera menutrans Toggle\ &List\ Mode:set\ list! Ativar/Desativar\ modo\ &list:set\ list! menutrans Toggle\ Line\ &Wrap:set\ wrap! Ativar/Desativar\ &quebra\ de\ linhas:set\ wrap! menutrans Toggle\ W&rap\ at\ word:set\ lbr! Ativar/Desativar\ quebra\ na\ &palavra:set\ lbr! -menutrans Toggle\ &expand-tab:set\ et! Ativar/Desativar\ expanso de tabs:set\ et! +menutrans Toggle\ &expand-tab:set\ et! Ativar/Desativar\ expanso\ de\ tabs:set\ et! menutrans Toggle\ &auto-indent:set\ ai! Ativar/Desativar\ &auto-indentao:set\ ai! -menutrans Toggle\ &C-indenting:set\ cin! Ativar/Desativar\ indentao estilo &C:set\ cin! +menutrans Toggle\ &C-indenting:set\ cin! Ativar/Desativar\ indentao\ estilo\ &C:set\ cin! " other options menutrans &Shiftwidth Largura\ da\ &indentao @@ -144,12 +144,12 @@ menutrans &Convert\ to\ HEX:%!xxd Converter\ para\ hexadecimal:%!xxd menutrans Conve&rt\ back:%!xxd\ -r Conver&ter\ de\ volta:%!xxd\ -r " Tools.Spelling menu -menutrans &Spell Check On &Ativar Correo Ortogrfica -menutrans &Spell Check Off &Desativar Correo Ortogrfica -menutrans To &Next error]s &Prximo Erro]s -menutrans To &Previous Error[s Erro A&nterior[s -menutrans Suggest &Correctionsz= &Sugerir Correesz= -menutrans &Repeat correction:spellrepall &Repetir Correo:spellrepall +menutrans &Spell\ Check\ On &Ativar\ Correo\ Ortogrfica +menutrans &Spell\ Check\ Off &Desativar\ Correo\ Ortogrfica +menutrans To\ &Next\ error]s &Prximo\ Erro]s +menutrans To\ &Previous\ Error[s Erro\ A&nterior[s +menutrans Suggest\ &Correctionsz= &Sugerir\ Correesz= +menutrans &Repeat\ correction:spellrepall &Repetir\ Correo:spellrepall menutrans Set\ language\ to\ "en" Ingls menutrans Set\ language\ to\ "en_au" Ingls\ (en_au) @@ -158,7 +158,7 @@ menutrans Set\ language\ to\ "en_gb" Ingl menutrans Set\ language\ to\ "en_nz" Ingls\ (en_nz) menutrans Set\ language\ to\ "en_us" Ingls\ (en_us) -menutrans &Find\ More\ Languages &Buscar mais idiomas +menutrans &Find\ More\ Languages &Buscar\ mais\ idiomas " Tools.Fold Menu menutrans &Enable/Disable\ foldszi &Ativar/Desativar\ dobraszi diff --git a/runtime/lang/menu_pt_pt.vim b/runtime/lang/menu_pt_pt.vim index 783be0b926..c3265c0064 100644 --- a/runtime/lang/menu_pt_pt.vim +++ b/runtime/lang/menu_pt_pt.vim @@ -98,9 +98,9 @@ menutrans Toggle\ Line\ &Numbering:set\ nu! Activar/Desactivar\ &numera menutrans Toggle\ &List\ Mode:set\ list! Activar/Desactivar\ modo\ &list:set\ list! menutrans Toggle\ Line\ &Wrap:set\ wrap! Activar/Desactivar\ &quebra\ de\ linhas:set\ wrap! menutrans Toggle\ W&rap\ at\ word:set\ lbr! Activar/Desactivar\ quebra\ na\ &palavra:set\ lbr! -menutrans Toggle\ &expand-tab:set\ et! Activar/Desactivar\ expanso de tabs:set\ et! +menutrans Toggle\ &expand-tab:set\ et! Activar/Desactivar\ expanso\ de\ tabs:set\ et! menutrans Toggle\ &auto-indent:set\ ai! Activar/Desactivar\ &auto-indentao:set\ ai! -menutrans Toggle\ &C-indenting:set\ cin! Activar/Desactivar\ indentao estilo &C:set\ cin! +menutrans Toggle\ &C-indenting:set\ cin! Activar/Desactivar\ indentao\ estilo\ &C:set\ cin! " other options menutrans &Shiftwidth Largura\ da\ &indentao diff --git a/runtime/lang/menu_sk_sk.iso_8859-2.vim b/runtime/lang/menu_sk_sk.iso_8859-2.vim index 69de4e7b04..02b3f0e152 100644 --- a/runtime/lang/menu_sk_sk.iso_8859-2.vim +++ b/runtime/lang/menu_sk_sk.iso_8859-2.vim @@ -1,6 +1,6 @@ " Menu Translations: Slovak " Translated By: Martin Lacko -" Last Change: 2012 May 01 +" Last Change: 2020 Apr 23 " Quit when menu translations have already been done. if exists("did_menu_trans") @@ -53,12 +53,12 @@ menutrans &Deletex Vy&maza menutrans &Find\.\.\. &Njs\.\.\. menutrans Find\ and\ Rep&lace\.\.\. N&ahradi\.\.\. menutrans Settings\ &Window Mo&nosti -menutrans &Global\ Settings &Globlne monosti +menutrans &Global\ Settings &Globlne\ monosti menutrans Toggle\ Pattern\ &Highlight:set\ hls! Prepn\ paletu\ zvrazovania:set\ hls! -menutrans Toggle\ &Ignore-case:set\ ic! Prepn\ &ignorovanie vekosti:set\ ic! +menutrans Toggle\ &Ignore-case:set\ ic! Prepn\ &ignorovanie\ vekosti:set\ ic! menutrans Toggle\ &Showmatch:set\ sm! Prepn\ &ukza\ zhodu:set\ sm! menutrans &Context\ lines &Kontextov\ riadky -menutrans &Virtual\ Edit &Virtulne pravy +menutrans &Virtual\ Edit &Virtulne\ pravy menutrans Never Nikdy menutrans Block\ Selection Blokov\ vber menutrans Insert\ mode Reim\ vkladania @@ -67,7 +67,7 @@ menutrans Always V menutrans Toggle\ Insert\ &Mode:set\ im! Prepn\ rei&m\ vkladania:set\ im! menutrans Toggle\ Vi\ C&ompatible:set\ cp! Prepn\ vi\ kompatibilitu:set\ cp! menutrans Search\ &Path\.\.\. Cesta\ &hadania\.\.\. -menutrans Ta&g\ Files\.\.\. Ta&gov sbory\.\.\. +menutrans Ta&g\ Files\.\.\. Ta&gov\ sbory\.\.\. menutrans Toggle\ &Toolbar Prepn\ &panel menutrans Toggle\ &Bottom\ Scrollbar Prepn\ spodn\ posuvnk menutrans Toggle\ &Left\ Scrollbar Prepn\ av\ posuvnk @@ -95,7 +95,7 @@ menutrans &Folding &Vn menutrans &Enable/Disable\ foldszi Zapn/Vypn\ vnrani&ezi menutrans &View\ Cursor\ Linezv Zobrazi\ kurzoro&v\ riadokzv menutrans Vie&w\ Cursor\ Line\ onlyzMzx Zobrazi\ iba\ kurzorov\ riadokzMzx -menutrans C&lose\ more\ foldszm Zatvori\ viac \vnorenzm +menutrans C&lose\ more\ foldszm Zatvori\ viac\ vnorenzm menutrans &Close\ all\ foldszM Zatvor&i\ vetky\ vnoreniazM menutrans O&pen\ more\ foldszr O&tvori\ viac\ vnorenzr menutrans &Open\ all\ foldszR &Otvori\ vetky\ vnoreniazR @@ -139,7 +139,7 @@ menutrans &Delete Vymaza menutrans &Alternate Zmeni menutrans &Next &alia menutrans &Previous &Predchdzajca -menutrans [No File] [iadny\ sbor] +menutrans [No\ File] [iadny\ sbor] " Window menu menutrans &Window &Okn @@ -161,7 +161,7 @@ menutrans &Equal\ Size^W= Rovnak menutrans &Max\ Height^W_ &Maximlna\ vka^W_ menutrans M&in\ Height^W1_ Minimlna\ v&ka^W1_ menutrans Max\ &Width^W\| Maximlna\ rka^W\| -menutrans Min\ Widt&h^W1\| Minimlna irka^W1\| +menutrans Min\ Widt&h^W1\| Minimlna\ irka^W1\| menutrans Rotate\ &Up^WR Rotova&\ nahor^WR menutrans Rotate\ &Down^Wr Rotova\ na&dol^Wr menutrans Select\ Fo&nt\.\.\. Vy&bra\ psmo\.\.\. diff --git a/runtime/lang/menu_sl_si.latin2.vim b/runtime/lang/menu_sl_si.latin2.vim index a810a2a126..cf4b10ba74 100644 --- a/runtime/lang/menu_sl_si.latin2.vim +++ b/runtime/lang/menu_sl_si.latin2.vim @@ -1,7 +1,7 @@ " Menu Translations: Slovenian / Slovensko " Maintainer: Mojca Miklavec " Originally By: Mojca Miklavec -" Last Change: 2016 Oct 17 +" Last Change: 2020 Apr 23 " vim:set foldmethod=marker tabstop=8: " TODO: add/check all '&'s @@ -52,7 +52,7 @@ menutrans Find\ and\ Rep&lace\.\.\. Poi " [-- SETTINGS --] menutrans Settings\ &Window Nastavitve\ \.\.\. -menutrans Startup\ &Settings Zaetne nastavitve +menutrans Startup\ &Settings Zaetne\ nastavitve menutrans &Global\ Settings &Globalne\ nastavitve menutrans Toggle\ Pattern\ &Highlight:set\ hls! Vkljui/izkljui\ poudarjanje\ iskanega\ niza:set\ hls! @@ -92,7 +92,7 @@ menutrans Toggle\ &C-indenting:set\ cin! Vklju " other options menutrans &Shiftwidth irina\ zamika\ vrstic -menutrans Soft\ &Tabstop irina &tabulatorja +menutrans Soft\ &Tabstop irina\ &tabulatorja menutrans Te&xt\ Width\.\.\. irina\ besedila\ \.\.\. menutrans &File\ Format\.\.\. Format\ &datoteke\ \.\.\. menutrans C&olor\ Scheme &Barvna\ shema\ \.\.\. diff --git a/runtime/lang/menu_slovak_slovak_republic.1250.vim b/runtime/lang/menu_slovak_slovak_republic.1250.vim index cfc607865c..ce5e15cb32 100644 --- a/runtime/lang/menu_slovak_slovak_republic.1250.vim +++ b/runtime/lang/menu_slovak_slovak_republic.1250.vim @@ -1,6 +1,6 @@ " Menu Translations: Slovak " Translated By: Martin Lacko -" Last Change: 2012 May 01 +" Last Change: 2020 Apr 23 " Quit when menu translations have already been done. if exists("did_menu_trans") @@ -53,12 +53,12 @@ menutrans &Deletex Vy&maza menutrans &Find\.\.\. &Njs\.\.\. menutrans Find\ and\ Rep&lace\.\.\. N&ahradi\.\.\. menutrans Settings\ &Window Mo&nosti -menutrans &Global\ Settings &Globlne monosti +menutrans &Global\ Settings &Globlne\ monosti menutrans Toggle\ Pattern\ &Highlight:set\ hls! Prepn\ paletu\ zvrazovania:set\ hls! -menutrans Toggle\ &Ignore-case:set\ ic! Prepn\ &ignorovanie vekosti:set\ ic! +menutrans Toggle\ &Ignore-case:set\ ic! Prepn\ &ignorovanie\ vekosti:set\ ic! menutrans Toggle\ &Showmatch:set\ sm! Prepn\ &ukza\ zhodu:set\ sm! menutrans &Context\ lines &Kontextov\ riadky -menutrans &Virtual\ Edit &Virtulne pravy +menutrans &Virtual\ Edit &Virtulne\ pravy menutrans Never Nikdy menutrans Block\ Selection Blokov\ vber menutrans Insert\ mode Reim\ vkladania @@ -67,7 +67,7 @@ menutrans Always V menutrans Toggle\ Insert\ &Mode:set\ im! Prepn\ rei&m\ vkladania:set\ im! menutrans Toggle\ Vi\ C&ompatible:set\ cp! Prepn\ vi\ kompatibilitu:set\ cp! menutrans Search\ &Path\.\.\. Cesta\ &hadania\.\.\. -menutrans Ta&g\ Files\.\.\. Ta&gov sbory\.\.\. +menutrans Ta&g\ Files\.\.\. Ta&gov\ sbory\.\.\. menutrans Toggle\ &Toolbar Prepn\ &panel menutrans Toggle\ &Bottom\ Scrollbar Prepn\ spodn\ posuvnk menutrans Toggle\ &Left\ Scrollbar Prepn\ av\ posuvnk @@ -95,7 +95,7 @@ menutrans &Folding &Vn menutrans &Enable/Disable\ foldszi Zapn/Vypn\ vnrani&ezi menutrans &View\ Cursor\ Linezv Zobrazi\ kurzoro&v\ riadokzv menutrans Vie&w\ Cursor\ Line\ onlyzMzx Zobrazi\ iba\ kurzorov\ riadokzMzx -menutrans C&lose\ more\ foldszm Zatvori\ viac \vnorenzm +menutrans C&lose\ more\ foldszm Zatvori\ viac\ vnorenzm menutrans &Close\ all\ foldszM Zatvor&i\ vetky\ vnoreniazM menutrans O&pen\ more\ foldszr O&tvori\ viac\ vnorenzr menutrans &Open\ all\ foldszR &Otvori\ vetky\ vnoreniazR @@ -139,7 +139,7 @@ menutrans &Delete Vymaza menutrans &Alternate Zmeni menutrans &Next &alia menutrans &Previous &Predchdzajca -menutrans [No File] [iadny\ sbor] +menutrans [No\ File] [iadny\ sbor] " Window menu menutrans &Window &Okn @@ -161,7 +161,7 @@ menutrans &Equal\ Size^W= Rovnak menutrans &Max\ Height^W_ &Maximlna\ vka^W_ menutrans M&in\ Height^W1_ Minimlna\ v&ka^W1_ menutrans Max\ &Width^W\| Maximlna\ rka^W\| -menutrans Min\ Widt&h^W1\| Minimlna irka^W1\| +menutrans Min\ Widt&h^W1\| Minimlna\ irka^W1\| menutrans Rotate\ &Up^WR Rotova&\ nahor^WR menutrans Rotate\ &Down^Wr Rotova\ na&dol^Wr menutrans Select\ Fo&nt\.\.\. Vy&bra\ psmo\.\.\. diff --git a/runtime/lang/menu_tr_tr.cp1254.vim b/runtime/lang/menu_tr_tr.cp1254.vim index 687e2ac257..d1c3d973fd 100644 --- a/runtime/lang/menu_tr_tr.cp1254.vim +++ b/runtime/lang/menu_tr_tr.cp1254.vim @@ -11,19 +11,19 @@ set cpo&vim scriptencoding cp1254 " Top -menutrans &File &Dosya -menutrans &Edit D&zen +menutrans &File &Dosya +menutrans &Edit D&zen menutrans &Tools &Aralar menutrans &Syntax &Szdizim menutrans &Buffers A&rabellekler menutrans &Window &Pencere -menutrans &Help &Yardm +menutrans &Help &Yardm " Help menu menutrans &Overview &Genel\ Bak -menutrans &User\ Manual &Kullanm\ Klavuzu +menutrans &User\ Manual &Kullanm\ Klavuzu menutrans &How-To\ Links &Nasl\ Yaplr? -menutrans &Find\.\.\. &Bul\.\.\. +menutrans &Find\.\.\. &Bul\.\.\. "-------------------- menutrans &Credits &Teekkrler menutrans Co&pying &Datm @@ -37,38 +37,38 @@ menutrans &About &Hakk menutrans &Open\.\.\.:e &A\.\.\.:e menutrans Sp&lit-Open\.\.\.:sp &Yeni\ Blmde\ A\.\.\.:sp menutrans Open\ Tab\.\.\.:tabnew S&ekme\ A\.\.\.:tabnew -menutrans &New:enew Yeni\ &Sekme:enew +menutrans &New:enew Yeni\ &Sekme:enew menutrans &Close:close Ka&pat:close "-------------------- menutrans &Save:w Kayde&t:w -menutrans Save\ &As\.\.\.:sav &Farkl Kaydet\.\.\.:sav +menutrans Save\ &As\.\.\.:sav &Farkl\ Kaydet\.\.\.:sav "-------------------- menutrans Split\ &Diff\ With\.\.\. Ka&rlatr\.\.\. -menutrans Split\ Patched\ &By\.\.\. Ya&malar\ Dahil\ Karlatr\.\.\. +menutrans Split\ Patched\ &By\.\.\. Ya&ma\ le\ Karlatr\.\.\. "-------------------- menutrans &Print Ya&zdr -menutrans Sa&ve-Exit:wqa Kaydet\ &ve k:wqa +menutrans Sa&ve-Exit:wqa Kaydet\ &ve\ k:wqa menutrans E&xit:qa &k:qa " Edit menu -menutrans &Undou &Geri\ Alu -menutrans &Redo^R &Yinele^R -menutrans Rep&eat\. Son\ Komutu\ Y&inele\. +menutrans &Undou &Geri\ Alu +menutrans &Redo^R &Yinele^R +menutrans Rep&eat\. Son\ Komutu\ Y&inele\. "-------------------- -menutrans Cu&t"+x &Kes"+x -menutrans &Copy"+y K&opyala"+y -menutrans &Paste"+gP Ya&ptr"+gP -menutrans Put\ &Before[p &nne Koy[p -menutrans Put\ &After]p A&rkasna Koy]p -menutrans &Deletex Si&lx +menutrans Cu&t"+x &Kes"+x +menutrans &Copy"+y K&opyala"+y +menutrans &Paste"+gP Ya&ptr"+gP +menutrans Put\ &Before[p &nne\ Koy[p +menutrans Put\ &After]p A&rkasna\ Koy]p +menutrans &Deletex Si&lx menutrans &Select\ AllggVG T&mn\ SeggVG "-------------------- " Athena GUI only -menutrans &Find/ &Bul/ -menutrans Find\ and\ Rep&lace:%s Bul\ &ve\ Deitir:%s +menutrans &Find/ &Bul/ +menutrans Find\ and\ Rep&lace:%s Bul\ &ve\ Deitir:%s " End Athena GUI only -menutrans &Find\.\.\./ &Bul\.\.\./ -menutrans Find\ and\ Rep&lace\.\.\. Bul\ ve\ &Deitir\.\.\. +menutrans &Find\.\.\./ &Bul\.\.\./ +menutrans Find\ and\ Rep&lace\.\.\. Bul\ ve\ &Deitir\.\.\. menutrans Find\ and\ Rep&lace\.\.\.:%s Bul\ ve\ &Deitir\.\.\.:%s menutrans Find\ and\ Rep&lace\.\.\.:s Bul\ ve\ &Deitir\.\.\.:s "-------------------- @@ -78,11 +78,11 @@ menutrans &Global\ Settings Ge&nel\ Ayarlar menutrans F&ile\ Settings &Dosya\ Ayarlar menutrans C&olor\ Scheme &Renk\ Dzeni menutrans &Keymap Dme\ &Elem -menutrans Select\ Fo&nt\.\.\. Ya&ztipi Se\.\.\. +menutrans Select\ Fo&nt\.\.\. Ya&ztipi\ Se\.\.\. ">>>----------------- Edit/Global settings -menutrans Toggle\ Pattern\ &Highlight:set\ hls! Dizgi\ &Vurgulamasn\ A/Kapat:set\ hls! -menutrans Toggle\ &Ignoring\ Case:set\ ic! BYK/kk\ Harf\ &Duyarl\ A/Kapat:set\ ic! +menutrans Toggle\ Pattern\ &Highlight:set\ hls! Dizgi\ &Vurgulamasn\ A/Kapat:set\ hls! +menutrans Toggle\ &Ignoring\ Case:set\ ic! BYK/kk\ Harf\ &Duyarl\ A/Kapat:set\ ic! menutrans Toggle\ &Showing\ Matched\ Pairs:set\ sm! E&leen\ kilileri\ A/Kapat:set\ sm! menutrans &Context\ Lines &mlele\ Oynayan\ Satrlar menutrans &Virtual\ Edit &Sanal\ Dzenleme @@ -97,11 +97,11 @@ menutrans Toggle\ &Left\ Scrollbar &Sol\ Kayd menutrans Toggle\ &Right\ Scrollbar S&a\ Kaydrma\ ubuunu\ A/Kapat ">>>->>>------------- Edit/Global settings/Virtual edit -menutrans Never Kapal +menutrans Never Kapal menutrans Block\ Selection Blok\ Seimi menutrans Insert\ Mode Ekleme\ Kipi menutrans Block\ and\ Insert Blok\ Seiminde\ ve\ Ekleme\ Kipinde -menutrans Always Her\ Zaman\ Ak +menutrans Always Her\ Zaman\ Ak ">>>----------------- Edit/File settings menutrans Toggle\ Line\ &Numbering:set\ nu! &Satr\ Numaralandrmay\ A/Kapat:set\ nu! menutrans Toggle\ Relati&ve\ Line\ Numbering:set\ rnu! &Greceli\ Satr\ Numaralandrmay\ A/Kapat:set\ nru! @@ -124,10 +124,10 @@ menutrans Build\ &Tags\ File &Etiket\ Dosyas "------------------- menutrans &Folding &Kvrmalar menutrans &Spelling &Yazm\ Denetimi -menutrans &Diff &Ayrmlar\ (diff) +menutrans &Diff K&arlatrma\ (diff) "------------------- menutrans &Make:make &Derle:make -menutrans &List\ Errors:cl &Hatalar\ Listele:cl +menutrans &List\ Errors:cl &Hatalar\ Listele:cl menutrans L&ist\ Messages:cl! &letileri\ Listele:cl! menutrans &Next\ Error:cn Bir\ &Sonraki\ Hata:cn menutrans &Previous\ Error:cp Bir\ &nceki\ Hata:cp @@ -137,8 +137,8 @@ menutrans Error\ &Window Hatalar\ &Penceresi menutrans Se&t\ Compiler De&rleyici\ Se menutrans Show\ Compiler\ Se&ttings\ in\ Menu Derleyici\ Ayarlarn\ Mende\ &Gster "------------------- -menutrans &Convert\ to\ HEX:%!xxd HEX'e\ D&ntr:%!xxd -menutrans Conve&rt\ Back:%!xxd\ -r HEX'&ten\ Dntr:%!xxd\ -r +menutrans &Convert\ to\ HEX:%!xxd HEX'e\ D&ntr:%!xxd +menutrans Conve&rt\ Back:%!xxd\ -r HEX'&ten\ Dntr:%!xxd\ -r ">>>---------------- Tools/Spelling menutrans &Spell\ Check\ On Yazm\ Denetimini\ &A menutrans Spell\ Check\ &Off Yazm\ Denetimini\ &Kapat @@ -191,7 +191,7 @@ menutrans &Open:copen &A " Syntax menu menutrans &Show\ File\ Types\ in\ Menu Dosya\ Trlerini\ Mende\ &Gster menutrans Set\ '&syntax'\ only Yalnzca\ 'syntax'\ &Ayarla -menutrans Set\ '&filetype'\ too 'filetype'\ in\ &de\ Ayarla +menutrans Set\ '&filetype'\ too 'filetype'\ in\ &de\ Ayarla menutrans &Off &Kapat menutrans &Manual &El\ le menutrans A&utomatic &Otomatik @@ -204,7 +204,7 @@ menutrans &Convert\ to\ HTML &HTML'ye\ D menutrans &Refresh\ menu &Meny\ Gncelle menutrans Delete &Sil menutrans &Alternate &teki -menutrans &Next So&nraki +menutrans &Next So&nraki menutrans &Previous n&ceki menutrans [No\ File] [Dosya\ Yok] @@ -235,16 +235,16 @@ menutrans &Left\ Side^WH So&la^WH menutrans &Right\ Side^WL &Saa^WL " The popup menu -menutrans &Undo &Geri\ Al +menutrans &Undo &Geri\ Al menutrans Cu&t &Kes -menutrans &Copy K&opyala +menutrans &Copy K&opyala menutrans &Paste &Yaptr menutrans &Delete &Sil menutrans Select\ Blockwise &Blok\ Biiminde\ Se -menutrans Select\ &Word S&zck\ Se +menutrans Select\ &Word S&zck\ Se menutrans Select\ &Sentence &Tmce\ Se menutrans Select\ Pa&ragraph &Paragraf\ Se -menutrans Select\ &Line S&atr\ Se +menutrans Select\ &Line S&atr\ Se menutrans Select\ &Block Bl&ok\ Se menutrans Select\ &All Tm&n\ Se diff --git a/runtime/lang/menu_tr_tr.iso_8859-9.vim b/runtime/lang/menu_tr_tr.iso_8859-9.vim index 3e01c0c8aa..0065bc5236 100644 --- a/runtime/lang/menu_tr_tr.iso_8859-9.vim +++ b/runtime/lang/menu_tr_tr.iso_8859-9.vim @@ -11,19 +11,19 @@ set cpo&vim scriptencoding iso-8859-9 " Top -menutrans &File &Dosya -menutrans &Edit D&zen +menutrans &File &Dosya +menutrans &Edit D&zen menutrans &Tools &Aralar menutrans &Syntax &Szdizim menutrans &Buffers A&rabellekler menutrans &Window &Pencere -menutrans &Help &Yardm +menutrans &Help &Yardm " Help menu menutrans &Overview &Genel\ Bak -menutrans &User\ Manual &Kullanm\ Klavuzu +menutrans &User\ Manual &Kullanm\ Klavuzu menutrans &How-To\ Links &Nasl\ Yaplr? -menutrans &Find\.\.\. &Bul\.\.\. +menutrans &Find\.\.\. &Bul\.\.\. "-------------------- menutrans &Credits &Teekkrler menutrans Co&pying &Datm @@ -37,38 +37,38 @@ menutrans &About &Hakk menutrans &Open\.\.\.:e &A\.\.\.:e menutrans Sp&lit-Open\.\.\.:sp &Yeni\ Blmde\ A\.\.\.:sp menutrans Open\ Tab\.\.\.:tabnew S&ekme\ A\.\.\.:tabnew -menutrans &New:enew Yeni\ &Sekme:enew +menutrans &New:enew Yeni\ &Sekme:enew menutrans &Close:close Ka&pat:close "-------------------- menutrans &Save:w Kayde&t:w -menutrans Save\ &As\.\.\.:sav &Farkl Kaydet\.\.\.:sav +menutrans Save\ &As\.\.\.:sav &Farkl\ Kaydet\.\.\.:sav "-------------------- menutrans Split\ &Diff\ With\.\.\. Ka&rlatr\.\.\. -menutrans Split\ Patched\ &By\.\.\. Ya&malar\ Dahil\ Karlatr\.\.\. +menutrans Split\ Patched\ &By\.\.\. Ya&ma\ le\ Karlatr\.\.\. "-------------------- menutrans &Print Ya&zdr -menutrans Sa&ve-Exit:wqa Kaydet\ &ve k:wqa +menutrans Sa&ve-Exit:wqa Kaydet\ &ve\ k:wqa menutrans E&xit:qa &k:qa " Edit menu -menutrans &Undou &Geri\ Alu -menutrans &Redo^R &Yinele^R -menutrans Rep&eat\. Son\ Komutu\ Y&inele\. +menutrans &Undou &Geri\ Alu +menutrans &Redo^R &Yinele^R +menutrans Rep&eat\. Son\ Komutu\ Y&inele\. "-------------------- -menutrans Cu&t"+x &Kes"+x -menutrans &Copy"+y K&opyala"+y -menutrans &Paste"+gP Ya&ptr"+gP -menutrans Put\ &Before[p &nne Koy[p -menutrans Put\ &After]p A&rkasna Koy]p -menutrans &Deletex Si&lx +menutrans Cu&t"+x &Kes"+x +menutrans &Copy"+y K&opyala"+y +menutrans &Paste"+gP Ya&ptr"+gP +menutrans Put\ &Before[p &nne\ Koy[p +menutrans Put\ &After]p A&rkasna\ Koy]p +menutrans &Deletex Si&lx menutrans &Select\ AllggVG T&mn\ SeggVG "-------------------- " Athena GUI only -menutrans &Find/ &Bul/ -menutrans Find\ and\ Rep&lace:%s Bul\ &ve\ Deitir:%s +menutrans &Find/ &Bul/ +menutrans Find\ and\ Rep&lace:%s Bul\ &ve\ Deitir:%s " End Athena GUI only -menutrans &Find\.\.\./ &Bul\.\.\./ -menutrans Find\ and\ Rep&lace\.\.\. Bul\ ve\ &Deitir\.\.\. +menutrans &Find\.\.\./ &Bul\.\.\./ +menutrans Find\ and\ Rep&lace\.\.\. Bul\ ve\ &Deitir\.\.\. menutrans Find\ and\ Rep&lace\.\.\.:%s Bul\ ve\ &Deitir\.\.\.:%s menutrans Find\ and\ Rep&lace\.\.\.:s Bul\ ve\ &Deitir\.\.\.:s "-------------------- @@ -78,11 +78,11 @@ menutrans &Global\ Settings Ge&nel\ Ayarlar menutrans F&ile\ Settings &Dosya\ Ayarlar menutrans C&olor\ Scheme &Renk\ Dzeni menutrans &Keymap Dme\ &Elem -menutrans Select\ Fo&nt\.\.\. Ya&ztipi Se\.\.\. +menutrans Select\ Fo&nt\.\.\. Ya&ztipi\ Se\.\.\. ">>>----------------- Edit/Global settings -menutrans Toggle\ Pattern\ &Highlight:set\ hls! Dizgi\ &Vurgulamasn\ A/Kapat:set\ hls! -menutrans Toggle\ &Ignoring\ Case:set\ ic! BYK/kk\ Harf\ &Duyarl\ A/Kapat:set\ ic! +menutrans Toggle\ Pattern\ &Highlight:set\ hls! Dizgi\ &Vurgulamasn\ A/Kapat:set\ hls! +menutrans Toggle\ &Ignoring\ Case:set\ ic! BYK/kk\ Harf\ &Duyarl\ A/Kapat:set\ ic! menutrans Toggle\ &Showing\ Matched\ Pairs:set\ sm! E&leen\ kilileri\ A/Kapat:set\ sm! menutrans &Context\ Lines &mlele\ Oynayan\ Satrlar menutrans &Virtual\ Edit &Sanal\ Dzenleme @@ -97,11 +97,11 @@ menutrans Toggle\ &Left\ Scrollbar &Sol\ Kayd menutrans Toggle\ &Right\ Scrollbar S&a\ Kaydrma\ ubuunu\ A/Kapat ">>>->>>------------- Edit/Global settings/Virtual edit -menutrans Never Kapal +menutrans Never Kapal menutrans Block\ Selection Blok\ Seimi menutrans Insert\ Mode Ekleme\ Kipi menutrans Block\ and\ Insert Blok\ Seiminde\ ve\ Ekleme\ Kipinde -menutrans Always Her\ Zaman\ Ak +menutrans Always Her\ Zaman\ Ak ">>>----------------- Edit/File settings menutrans Toggle\ Line\ &Numbering:set\ nu! &Satr\ Numaralandrmay\ A/Kapat:set\ nu! menutrans Toggle\ Relati&ve\ Line\ Numbering:set\ rnu! &Greceli\ Satr\ Numaralandrmay\ A/Kapat:set\ nru! @@ -124,10 +124,10 @@ menutrans Build\ &Tags\ File &Etiket\ Dosyas "------------------- menutrans &Folding &Kvrmalar menutrans &Spelling &Yazm\ Denetimi -menutrans &Diff &Ayrmlar\ (diff) +menutrans &Diff K&arlatrma\ (diff) "------------------- menutrans &Make:make &Derle:make -menutrans &List\ Errors:cl &Hatalar\ Listele:cl +menutrans &List\ Errors:cl &Hatalar\ Listele:cl menutrans L&ist\ Messages:cl! &letileri\ Listele:cl! menutrans &Next\ Error:cn Bir\ &Sonraki\ Hata:cn menutrans &Previous\ Error:cp Bir\ &nceki\ Hata:cp @@ -137,8 +137,8 @@ menutrans Error\ &Window Hatalar\ &Penceresi menutrans Se&t\ Compiler De&rleyici\ Se menutrans Show\ Compiler\ Se&ttings\ in\ Menu Derleyici\ Ayarlarn\ Mende\ &Gster "------------------- -menutrans &Convert\ to\ HEX:%!xxd HEX'e\ D&ntr:%!xxd -menutrans Conve&rt\ Back:%!xxd\ -r HEX'&ten\ Dntr:%!xxd\ -r +menutrans &Convert\ to\ HEX:%!xxd HEX'e\ D&ntr:%!xxd +menutrans Conve&rt\ Back:%!xxd\ -r HEX'&ten\ Dntr:%!xxd\ -r ">>>---------------- Tools/Spelling menutrans &Spell\ Check\ On Yazm\ Denetimini\ &A menutrans Spell\ Check\ &Off Yazm\ Denetimini\ &Kapat @@ -191,7 +191,7 @@ menutrans &Open:copen &A " Syntax menu menutrans &Show\ File\ Types\ in\ Menu Dosya\ Trlerini\ Mende\ &Gster menutrans Set\ '&syntax'\ only Yalnzca\ 'syntax'\ &Ayarla -menutrans Set\ '&filetype'\ too 'filetype'\ in\ &de\ Ayarla +menutrans Set\ '&filetype'\ too 'filetype'\ in\ &de\ Ayarla menutrans &Off &Kapat menutrans &Manual &El\ le menutrans A&utomatic &Otomatik @@ -204,7 +204,7 @@ menutrans &Convert\ to\ HTML &HTML'ye\ D menutrans &Refresh\ menu &Meny\ Gncelle menutrans Delete &Sil menutrans &Alternate &teki -menutrans &Next So&nraki +menutrans &Next So&nraki menutrans &Previous n&ceki menutrans [No\ File] [Dosya\ Yok] @@ -235,16 +235,16 @@ menutrans &Left\ Side^WH So&la^WH menutrans &Right\ Side^WL &Saa^WL " The popup menu -menutrans &Undo &Geri\ Al +menutrans &Undo &Geri\ Al menutrans Cu&t &Kes -menutrans &Copy K&opyala +menutrans &Copy K&opyala menutrans &Paste &Yaptr menutrans &Delete &Sil menutrans Select\ Blockwise &Blok\ Biiminde\ Se -menutrans Select\ &Word S&zck\ Se +menutrans Select\ &Word S&zck\ Se menutrans Select\ &Sentence &Tmce\ Se menutrans Select\ Pa&ragraph &Paragraf\ Se -menutrans Select\ &Line S&atr\ Se +menutrans Select\ &Line S&atr\ Se menutrans Select\ &Block Bl&ok\ Se menutrans Select\ &All Tm&n\ Se diff --git a/runtime/lang/menu_tr_tr.utf-8.vim b/runtime/lang/menu_tr_tr.utf-8.vim index a828acfc4f..02a095643c 100644 --- a/runtime/lang/menu_tr_tr.utf-8.vim +++ b/runtime/lang/menu_tr_tr.utf-8.vim @@ -11,19 +11,19 @@ set cpo&vim scriptencoding utf-8 " Top -menutrans &File &Dosya -menutrans &Edit Dü&zen +menutrans &File &Dosya +menutrans &Edit Dü&zen menutrans &Tools &Araçlar menutrans &Syntax &Sözdizim menutrans &Buffers A&rabellekler menutrans &Window &Pencere -menutrans &Help &Yardım +menutrans &Help &Yardım " Help menu menutrans &Overview &Genel\ Bakış -menutrans &User\ Manual &Kullanım\ Kılavuzu +menutrans &User\ Manual &Kullanım\ Kılavuzu menutrans &How-To\ Links &Nasıl\ Yapılır? -menutrans &Find\.\.\. &Bul\.\.\. +menutrans &Find\.\.\. &Bul\.\.\. "-------------------- menutrans &Credits &Teşekkürler menutrans Co&pying &Dağıtım @@ -37,38 +37,38 @@ menutrans &About &Hakkında menutrans &Open\.\.\.:e &Aç\.\.\.:e menutrans Sp&lit-Open\.\.\.:sp &Yeni\ Bölümde\ Aç\.\.\.:sp menutrans Open\ Tab\.\.\.:tabnew S&ekme\ Aç\.\.\.:tabnew -menutrans &New:enew Yeni\ &Sekme:enew +menutrans &New:enew Yeni\ &Sekme:enew menutrans &Close:close Ka&pat:close "-------------------- menutrans &Save:w Kayde&t:w -menutrans Save\ &As\.\.\.:sav &Farklı Kaydet\.\.\.:sav +menutrans Save\ &As\.\.\.:sav &Farklı\ Kaydet\.\.\.:sav "-------------------- menutrans Split\ &Diff\ With\.\.\. Ka&rşılaştır\.\.\. -menutrans Split\ Patched\ &By\.\.\. Ya&malar\ Dahil\ Karşılaştır\.\.\. +menutrans Split\ Patched\ &By\.\.\. Ya&ma\ İle\ Karşılaştır\.\.\. "-------------------- menutrans &Print Ya&zdır -menutrans Sa&ve-Exit:wqa Kaydet\ &ve Çık:wqa +menutrans Sa&ve-Exit:wqa Kaydet\ &ve\ Çık:wqa menutrans E&xit:qa Çı&k:qa " Edit menu -menutrans &Undou &Geri\ Alu -menutrans &Redo^R &Yinele^R -menutrans Rep&eat\. Son\ Komutu\ Y&inele\. +menutrans &Undou &Geri\ Alu +menutrans &Redo^R &Yinele^R +menutrans Rep&eat\. Son\ Komutu\ Y&inele\. "-------------------- -menutrans Cu&t"+x &Kes"+x -menutrans &Copy"+y K&opyala"+y -menutrans &Paste"+gP Ya&pıştır"+gP -menutrans Put\ &Before[p Ö&nüne Koy[p -menutrans Put\ &After]p A&rkasına Koy]p -menutrans &Deletex Si&lx +menutrans Cu&t"+x &Kes"+x +menutrans &Copy"+y K&opyala"+y +menutrans &Paste"+gP Ya&pıştır"+gP +menutrans Put\ &Before[p Ö&nüne\ Koy[p +menutrans Put\ &After]p A&rkasına\ Koy]p +menutrans &Deletex Si&lx menutrans &Select\ AllggVG Tü&münü\ SeçggVG "-------------------- " Athena GUI only -menutrans &Find/ &Bul/ -menutrans Find\ and\ Rep&lace:%s Bul\ &ve\ Değiştir:%s +menutrans &Find/ &Bul/ +menutrans Find\ and\ Rep&lace:%s Bul\ &ve\ Değiştir:%s " End Athena GUI only -menutrans &Find\.\.\./ &Bul\.\.\./ -menutrans Find\ and\ Rep&lace\.\.\. Bul\ ve\ &Değiştir\.\.\. +menutrans &Find\.\.\./ &Bul\.\.\./ +menutrans Find\ and\ Rep&lace\.\.\. Bul\ ve\ &Değiştir\.\.\. menutrans Find\ and\ Rep&lace\.\.\.:%s Bul\ ve\ &Değiştir\.\.\.:%s menutrans Find\ and\ Rep&lace\.\.\.:s Bul\ ve\ &Değiştir\.\.\.:s "-------------------- @@ -78,11 +78,11 @@ menutrans &Global\ Settings Ge&nel\ Ayarlar menutrans F&ile\ Settings &Dosya\ Ayarları menutrans C&olor\ Scheme &Renk\ Düzeni menutrans &Keymap Düğme\ &Eşlem -menutrans Select\ Fo&nt\.\.\. Ya&zıtipi Seç\.\.\. +menutrans Select\ Fo&nt\.\.\. Ya&zıtipi\ Seç\.\.\. ">>>----------------- Edit/Global settings -menutrans Toggle\ Pattern\ &Highlight:set\ hls! Dizgi\ &Vurgulamasını\ Aç/Kapat:set\ hls! -menutrans Toggle\ &Ignoring\ Case:set\ ic! BÜYÜK/küçük\ Harf\ &Duyarlı\ Aç/Kapat:set\ ic! +menutrans Toggle\ Pattern\ &Highlight:set\ hls! Dizgi\ &Vurgulamasını\ Aç/Kapat:set\ hls! +menutrans Toggle\ &Ignoring\ Case:set\ ic! BÜYÜK/küçük\ Harf\ &Duyarlı\ Aç/Kapat:set\ ic! menutrans Toggle\ &Showing\ Matched\ Pairs:set\ sm! Eş&leşen\ İkilileri\ Aç/Kapat:set\ sm! menutrans &Context\ Lines İ&mleçle\ Oynayan\ Satırlar menutrans &Virtual\ Edit &Sanal\ Düzenleme @@ -97,11 +97,11 @@ menutrans Toggle\ &Left\ Scrollbar &Sol\ Kaydırma\ Çubuğunu\ Aç/Kapat menutrans Toggle\ &Right\ Scrollbar S&ağ\ Kaydırma\ Çubuğunu\ Aç/Kapat ">>>->>>------------- Edit/Global settings/Virtual edit -menutrans Never Kapalı +menutrans Never Kapalı menutrans Block\ Selection Blok\ Seçimi menutrans Insert\ Mode Ekleme\ Kipi menutrans Block\ and\ Insert Blok\ Seçiminde\ ve\ Ekleme\ Kipinde -menutrans Always Her\ Zaman\ Açık +menutrans Always Her\ Zaman\ Açık ">>>----------------- Edit/File settings menutrans Toggle\ Line\ &Numbering:set\ nu! &Satır\ Numaralandırmayı\ Aç/Kapat:set\ nu! menutrans Toggle\ Relati&ve\ Line\ Numbering:set\ rnu! &Göreceli\ Satır\ Numaralandırmayı\ Aç/Kapat:set\ nru! @@ -124,10 +124,10 @@ menutrans Build\ &Tags\ File &Etiket\ Dosyası\ Oluştur "------------------- menutrans &Folding &Kıvırmalar menutrans &Spelling &Yazım\ Denetimi -menutrans &Diff &Ayrımlar\ (diff) +menutrans &Diff K&arşılaştırma\ (diff) "------------------- menutrans &Make:make &Derle:make -menutrans &List\ Errors:cl &Hataları\ Listele:cl +menutrans &List\ Errors:cl &Hataları\ Listele:cl menutrans L&ist\ Messages:cl! İ&letileri\ Listele:cl! menutrans &Next\ Error:cn Bir\ &Sonraki\ Hata:cn menutrans &Previous\ Error:cp Bir\ Ö&nceki\ Hata:cp @@ -137,8 +137,8 @@ menutrans Error\ &Window Hatalar\ &Penceresi menutrans Se&t\ Compiler De&rleyici\ Seç menutrans Show\ Compiler\ Se&ttings\ in\ Menu Derleyici\ Ayarlarını\ Menüde\ &Göster "------------------- -menutrans &Convert\ to\ HEX:%!xxd HEX'e\ Dö&nüştür:%!xxd -menutrans Conve&rt\ Back:%!xxd\ -r HEX'&ten\ Dönüştür:%!xxd\ -r +menutrans &Convert\ to\ HEX:%!xxd HEX'e\ Dö&nüştür:%!xxd +menutrans Conve&rt\ Back:%!xxd\ -r HEX'&ten\ Dönüştür:%!xxd\ -r ">>>---------------- Tools/Spelling menutrans &Spell\ Check\ On Yazım\ Denetimini\ &Aç menutrans Spell\ Check\ &Off Yazım\ Denetimini\ &Kapat @@ -191,7 +191,7 @@ menutrans &Open:copen &Aç:copen " Syntax menu menutrans &Show\ File\ Types\ in\ Menu Dosya\ Türlerini\ Menüde\ &Göster menutrans Set\ '&syntax'\ only Yalnızca\ 'syntax'\ &Ayarla -menutrans Set\ '&filetype'\ too 'filetype'\ İçin\ &de\ Ayarla +menutrans Set\ '&filetype'\ too 'filetype'\ İçin\ &de\ Ayarla menutrans &Off &Kapat menutrans &Manual &El\ İle menutrans A&utomatic &Otomatik @@ -204,7 +204,7 @@ menutrans &Convert\ to\ HTML &HTML'ye\ Dönüştür menutrans &Refresh\ menu &Menüyü\ Güncelle menutrans Delete &Sil menutrans &Alternate Ö&teki -menutrans &Next So&nraki +menutrans &Next So&nraki menutrans &Previous Ön&ceki menutrans [No\ File] [Dosya\ Yok] @@ -235,16 +235,16 @@ menutrans &Left\ Side^WH So&la^WH menutrans &Right\ Side^WL &Sağa^WL " The popup menu -menutrans &Undo &Geri\ Al +menutrans &Undo &Geri\ Al menutrans Cu&t &Kes -menutrans &Copy K&opyala +menutrans &Copy K&opyala menutrans &Paste &Yapıştır menutrans &Delete &Sil menutrans Select\ Blockwise &Blok\ Biçiminde\ Seç -menutrans Select\ &Word Sö&zcük\ Seç +menutrans Select\ &Word Sö&zcük\ Seç menutrans Select\ &Sentence &Tümce\ Seç menutrans Select\ Pa&ragraph &Paragraf\ Seç -menutrans Select\ &Line S&atır\ Seç +menutrans Select\ &Line S&atır\ Seç menutrans Select\ &Block Bl&ok\ Seç menutrans Select\ &All Tümü&nü\ Seç @@ -305,4 +305,4 @@ let g:menutrans_fileformat_dialog = "Dosya biçimi seçin" let g:menutrans_fileformat_choices = "&Unix\n&Dos\n&Mac\nİ&ptal" let menutrans_no_file = "[Dosya Yok]" let &cpo = s:keepcpo -unlet s:keepcpo \ No newline at end of file +unlet s:keepcpo diff --git a/runtime/lang/menu_vi_vn.vim b/runtime/lang/menu_vi_vn.vim index 9fbd2c6d5c..563ffa2485 100644 --- a/runtime/lang/menu_vi_vn.vim +++ b/runtime/lang/menu_vi_vn.vim @@ -58,7 +58,7 @@ menutrans Split\ &Diff\ with\.\.\. &So\ sánh\ với\.\.\. menutrans Split\ Patched\ &By\.\.\. So\ sánh\ đã\ vá\ lỗi\ &bởi\.\.\. "-------------------- menutrans &Print In\ &ra -menutrans Sa&ve-Exit:wqa Ghi\ nhớ\ rồi\ th&oát :wqa +menutrans Sa&ve-Exit:wqa Ghi\ nhớ\ rồi\ th&oát\ :wqa menutrans E&xit:qa &Thoát:qa " " @@ -87,7 +87,7 @@ menutrans C&olor\ Scheme Phối\ hợp\ màu\ &sắc menutrans &Keymap Sơ\ đồ\ &bàn\ phím menutrans Select\ Fo&nt\.\.\. Chọn\ &phông\ chữ\.\.\. ">>>----------------- Edit/Global settings -menutrans Toggle\ Pattern\ &Highlight:set\ hls! &Chiếu\ sáng\ từ\ tìm\ thấy :set\ hls! +menutrans Toggle\ Pattern\ &Highlight:set\ hls! &Chiếu\ sáng\ từ\ tìm\ thấy\ :set\ hls! menutrans Toggle\ &Ignore-case:set\ ic! &Không\ tính\ đến\ kiểu\ chữ:set\ ic! menutrans Toggle\ &Showmatch:set\ sm! Cho\ &biết\ phần\ tử\ có\ cặp:set\ sm! menutrans &Context\ lines Số\ &dòng\ quanh\ con\ trỏ @@ -149,7 +149,7 @@ menutrans Jump\ &back^T &Quay\ lại^T menutrans Build\ &Tags\ File &Tạo\ tập\ tin\ thẻ\ ghi "------------------- menutrans &Folding Nếp\ &gấp -menutrans &Diff &Khác\ biệt (diff) +menutrans &Diff &Khác\ biệt\ (diff) "------------------- menutrans &Make:make &Biên\ dịch:make menutrans &List\ Errors:cl &Danh\ sách\ lỗi:cl diff --git a/runtime/lang/menu_zh_cn.utf-8.vim b/runtime/lang/menu_zh_cn.utf-8.vim index c8e2eb3828..f7b086d27d 100644 --- a/runtime/lang/menu_zh_cn.utf-8.vim +++ b/runtime/lang/menu_zh_cn.utf-8.vim @@ -1,7 +1,7 @@ " Menu Translations: Simplified Chinese " Maintainer: Shun Bai " Previous Maintainer: Yuheng Xie -" Last Change: 2019 Sep 11 +" Last Change: 2020 Apr 23 " Quit when menu translations have already been done. if exists("did_menu_trans") @@ -122,7 +122,7 @@ menutrans Toggle\ &C-Style\ Indenting:set\ cin! 开/关\ C\ 语言式缩 " other options menutrans &Shiftwidth 缩进宽度(&S) -menutrans Soft\ &Tabstop 软制表位宽度(Soft Tabstop)(&T) +menutrans Soft\ &Tabstop 软制表位宽度(Soft\ Tabstop)(&T) menutrans Te&xt\ Width\.\.\. 文本宽度(&X)\.\.\. menutrans &File\ Format\.\.\. 文件格式(&F)\.\.\. diff --git a/src/version.c b/src/version.c index 6285766be1..8782b37a73 100644 --- a/src/version.c +++ b/src/version.c @@ -746,6 +746,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 628, /**/ 627, /**/ From 65d032c779a43b767497e15e6a32d04a6a8fa65d Mon Sep 17 00:00:00 2001 From: Bram Moolenaar Date: Fri, 24 Apr 2020 20:57:01 +0200 Subject: [PATCH 023/230] patch 8.2.0629: setting a boolean option to v:false does not work Problem: Setting a boolean option to v:false does not work. Solution: Do not use the string representation of the value. (Christian Brabandt, closes #5974) --- src/evalvars.c | 9 ++++++--- src/testdir/test_options.vim | 14 ++++++++++++++ src/version.c | 2 ++ 3 files changed, 22 insertions(+), 3 deletions(-) diff --git a/src/evalvars.c b/src/evalvars.c index 1d0599f5ae..7c8b9f7acc 100644 --- a/src/evalvars.c +++ b/src/evalvars.c @@ -1251,13 +1251,15 @@ ex_let_one( int opt_type; long numval; char_u *stringval = NULL; - char_u *s; + char_u *s = NULL; c1 = *p; *p = NUL; n = (long)tv_get_number(tv); - s = tv_get_string_chk(tv); // != NULL if number or string + // avoid setting a string option to the text "v:false" or similar. + if (tv->v_type != VAR_BOOL && tv->v_type != VAR_SPECIAL) + s = tv_get_string_chk(tv); // != NULL if number or string if (s != NULL && op != NULL && *op != '=') { opt_type = get_option_value(arg, &numval, @@ -1289,7 +1291,8 @@ ex_let_one( } } } - if (s != NULL) + if (s != NULL || tv->v_type == VAR_BOOL + || tv->v_type == VAR_SPECIAL) { set_option_value(arg, n, s, opt_flags); arg_end = p; diff --git a/src/testdir/test_options.vim b/src/testdir/test_options.vim index e03d7e99cc..dec82885f6 100644 --- a/src/testdir/test_options.vim +++ b/src/testdir/test_options.vim @@ -899,4 +899,18 @@ func Test_opt_num_op() set shiftwidth& endfunc +" Test for setting option values using v:false and v:true +func Test_opt_boolean() + set number& + set number + call assert_equal(1, &nu) + set nonu + call assert_equal(0, &nu) + let &nu = v:true + call assert_equal(1, &nu) + let &nu = v:false + call assert_equal(0, &nu) + set number& +endfunc + " vim: shiftwidth=2 sts=2 expandtab diff --git a/src/version.c b/src/version.c index 8782b37a73..d22750016f 100644 --- a/src/version.c +++ b/src/version.c @@ -746,6 +746,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 629, /**/ 628, /**/ From 7714d7b31f0fc7c717c97abd4a8b5cbb13a3ad31 Mon Sep 17 00:00:00 2001 From: Bram Moolenaar Date: Fri, 24 Apr 2020 21:21:06 +0200 Subject: [PATCH 024/230] patch 8.2.0630: "make tags" does not cover Haiku GUI file Problem: "make tags" does not cover Haiku GUI file. Solution: Add *.cc files. --- src/Make_all.mak | 1 + src/version.c | 2 ++ 2 files changed, 3 insertions(+) diff --git a/src/Make_all.mak b/src/Make_all.mak index 591350f413..6a6d2fe14e 100644 --- a/src/Make_all.mak +++ b/src/Make_all.mak @@ -5,6 +5,7 @@ # Argument for running ctags. TAGS_FILES = \ *.c \ + *.cc \ *.cpp \ *.h \ auto/*.c \ diff --git a/src/version.c b/src/version.c index d22750016f..d2e7451c13 100644 --- a/src/version.c +++ b/src/version.c @@ -746,6 +746,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 630, /**/ 629, /**/ From b52575f9cfcb5c9715ed08ccd552a55e0052370e Mon Sep 17 00:00:00 2001 From: Bram Moolenaar Date: Fri, 24 Apr 2020 22:16:13 +0200 Subject: [PATCH 025/230] patch 8.2.0631: Haiku file formatted with wrong tabstop Problem: Haiku file formatted with wrong tabstop. Solution: Use normal tabstop. Fix white space. --- src/gui_haiku.cc | 6698 +++++++++++++++++++++++----------------------- src/version.c | 2 + 2 files changed, 3351 insertions(+), 3349 deletions(-) diff --git a/src/gui_haiku.cc b/src/gui_haiku.cc index f26e9035a5..2dbd852f27 100644 --- a/src/gui_haiku.cc +++ b/src/gui_haiku.cc @@ -2,7 +2,7 @@ * * VIM - Vi IMproved by Bram Moolenaar * BeBox GUI support Copyright 1998 by Olaf Seibert. - * All Rights Reserved. + * All Rights Reserved. * * Do ":help uganda" in Vim to read copying and usage conditions. * Do ":help credits" in Vim to see a list of people who contributed. @@ -79,7 +79,7 @@ extern "C" { #include "proto.h" #include "version.h" -} // extern "C" +} // extern "C" // ---------------- start of header part ---------------- @@ -143,165 +143,165 @@ extern int main(int argc, char **argv); // VimApp seems comparable to the X "vimShell" class VimApp: public BApplication { - typedef BApplication Inherited; - public: - VimApp(const char *appsig); - ~VimApp(); + typedef BApplication Inherited; + public: + VimApp(const char *appsig); + ~VimApp(); - // callbacks: + // callbacks: #if 0 - virtual void DispatchMessage(BMessage *m, BHandler *h) - { - m->PrintToStream(); - Inherited::DispatchMessage(m, h); - } + virtual void DispatchMessage(BMessage *m, BHandler *h) + { + m->PrintToStream(); + Inherited::DispatchMessage(m, h); + } #endif - virtual void ReadyToRun(); - virtual void ArgvReceived(int32 argc, char **argv); - virtual void RefsReceived(BMessage *m); - virtual bool QuitRequested(); - virtual void MessageReceived(BMessage *m); + virtual void ReadyToRun(); + virtual void ArgvReceived(int32 argc, char **argv); + virtual void RefsReceived(BMessage *m); + virtual bool QuitRequested(); + virtual void MessageReceived(BMessage *m); - static void SendRefs(BMessage *m, bool changedir); + static void SendRefs(BMessage *m, bool changedir); - sem_id fFilePanelSem; - BFilePanel* fFilePanel; - BPath fBrowsedPath; - private: + sem_id fFilePanelSem; + BFilePanel* fFilePanel; + BPath fBrowsedPath; + private: }; class VimWindow: public BWindow { - typedef BWindow Inherited; - public: - VimWindow(); - ~VimWindow(); + typedef BWindow Inherited; + public: + VimWindow(); + ~VimWindow(); - // virtual void DispatchMessage(BMessage *m, BHandler *h); - virtual void WindowActivated(bool active); - virtual bool QuitRequested(); + // virtual void DispatchMessage(BMessage *m, BHandler *h); + virtual void WindowActivated(bool active); + virtual bool QuitRequested(); - VimFormView *formView; + VimFormView *formView; - private: - void init(); + private: + void init(); }; class VimFormView: public BView { - typedef BView Inherited; - public: - VimFormView(BRect frame); - ~VimFormView(); + typedef BView Inherited; + public: + VimFormView(BRect frame); + ~VimFormView(); - // callbacks: - virtual void AllAttached(); - virtual void FrameResized(float new_width, float new_height); + // callbacks: + virtual void AllAttached(); + virtual void FrameResized(float new_width, float new_height); #define MENUBAR_MARGIN 1 - float MenuHeight() const - { return menuBar ? menuBar->Frame().Height() + MENUBAR_MARGIN: 0; } - BMenuBar *MenuBar() const - { return menuBar; } + float MenuHeight() const + { return menuBar ? menuBar->Frame().Height() + MENUBAR_MARGIN: 0; } + BMenuBar *MenuBar() const + { return menuBar; } - private: - void init(BRect); + private: + void init(BRect); - BMenuBar *menuBar; - VimTextAreaView *textArea; + BMenuBar *menuBar; + VimTextAreaView *textArea; #ifdef FEAT_TOOLBAR - public: - float ToolbarHeight() const; - VimToolbar *ToolBar() const - { return toolBar; } - private: - VimToolbar *toolBar; + public: + float ToolbarHeight() const; + VimToolbar *ToolBar() const + { return toolBar; } + private: + VimToolbar *toolBar; #endif #ifdef FEAT_GUI_TABLINE - public: - VimTabLine *TabLine() const { return tabLine; } - bool IsShowingTabLine() const { return showingTabLine; } - void SetShowingTabLine(bool showing) { showingTabLine = showing; } - float TablineHeight() const; - private: - VimTabLine *tabLine; - int showingTabLine; + public: + VimTabLine *TabLine() const { return tabLine; } + bool IsShowingTabLine() const { return showingTabLine; } + void SetShowingTabLine(bool showing) { showingTabLine = showing; } + float TablineHeight() const; + private: + VimTabLine *tabLine; + int showingTabLine; #endif }; class VimTextAreaView: public BView { - typedef BView Inherited; - public: - VimTextAreaView(BRect frame); - ~VimTextAreaView(); + typedef BView Inherited; + public: + VimTextAreaView(BRect frame); + ~VimTextAreaView(); - // callbacks: - virtual void Draw(BRect updateRect); - virtual void KeyDown(const char *bytes, int32 numBytes); - virtual void MouseDown(BPoint point); - virtual void MouseUp(BPoint point); - virtual void MouseMoved(BPoint point, uint32 transit, const BMessage *message); - virtual void MessageReceived(BMessage *m); + // callbacks: + virtual void Draw(BRect updateRect); + virtual void KeyDown(const char *bytes, int32 numBytes); + virtual void MouseDown(BPoint point); + virtual void MouseUp(BPoint point); + virtual void MouseMoved(BPoint point, uint32 transit, const BMessage *message); + virtual void MessageReceived(BMessage *m); - // own functions: - int mchInitFont(char_u *name); - void mchDrawString(int row, int col, char_u *s, int len, int flags); - void mchClearBlock(int row1, int col1, int row2, int col2); - void mchClearAll(); - void mchDeleteLines(int row, int num_lines); - void mchInsertLines(int row, int num_lines); + // own functions: + int mchInitFont(char_u *name); + void mchDrawString(int row, int col, char_u *s, int len, int flags); + void mchClearBlock(int row1, int col1, int row2, int col2); + void mchClearAll(); + void mchDeleteLines(int row, int num_lines); + void mchInsertLines(int row, int num_lines); - static void guiSendMouseEvent(int button, int x, int y, int repeated_click, int_u modifiers); - static void guiMouseMoved(int x, int y); - static void guiBlankMouse(bool should_hide); - static int_u mouseModifiersToVim(int32 beModifiers); + static void guiSendMouseEvent(int button, int x, int y, int repeated_click, int_u modifiers); + static void guiMouseMoved(int x, int y); + static void guiBlankMouse(bool should_hide); + static int_u mouseModifiersToVim(int32 beModifiers); - int32 mouseDragEventCount; + int32 mouseDragEventCount; #ifdef FEAT_MBYTE_IME - void DrawIMString(void); + void DrawIMString(void); #endif - private: - void init(BRect); + private: + void init(BRect); - int_u vimMouseButton; - int_u vimMouseModifiers; + int_u vimMouseButton; + int_u vimMouseModifiers; #ifdef FEAT_MBYTE_IME - struct { - BMessenger* messenger; - BMessage* message; - BPoint location; - int row; - int col; - int count; - } IMData; + struct { + BMessenger* messenger; + BMessage* message; + BPoint location; + int row; + int col; + int count; + } IMData; #endif }; class VimScrollBar: public BScrollBar { - typedef BScrollBar Inherited; - public: - VimScrollBar(scrollbar_T *gsb, orientation posture); - ~VimScrollBar(); + typedef BScrollBar Inherited; + public: + VimScrollBar(scrollbar_T *gsb, orientation posture); + ~VimScrollBar(); - virtual void ValueChanged(float newValue); - virtual void MouseUp(BPoint where); - void SetValue(float newval); - scrollbar_T *getGsb() - { return gsb; } + virtual void ValueChanged(float newValue); + virtual void MouseUp(BPoint where); + void SetValue(float newval); + scrollbar_T *getGsb() + { return gsb; } - int32 scrollEventCount; + int32 scrollEventCount; - private: - scrollbar_T *gsb; - float ignoreValue; + private: + scrollbar_T *gsb; + float ignoreValue; }; @@ -309,28 +309,28 @@ class VimScrollBar: public BScrollBar class VimToolbar : public BBox { - static BBitmap *normalButtonsBitmap; - static BBitmap *grayedButtonsBitmap; + static BBitmap *normalButtonsBitmap; + static BBitmap *grayedButtonsBitmap; - BBitmap *LoadVimBitmap(const char* fileName); - bool GetPictureFromBitmap(BPicture *pictureTo, int32 index, BBitmap *bitmapFrom, bool pressed); - bool ModifyBitmapToGrayed(BBitmap *bitmap); + BBitmap *LoadVimBitmap(const char* fileName); + bool GetPictureFromBitmap(BPicture *pictureTo, int32 index, BBitmap *bitmapFrom, bool pressed); + bool ModifyBitmapToGrayed(BBitmap *bitmap); - BList fButtonsList; - void InvalidateLayout(); + BList fButtonsList; + void InvalidateLayout(); - public: - VimToolbar(BRect frame, const char * name); - ~VimToolbar(); + public: + VimToolbar(BRect frame, const char * name); + ~VimToolbar(); - bool PrepareButtonBitmaps(); + bool PrepareButtonBitmaps(); - bool AddButton(int32 index, vimmenu_T *menu); - bool RemoveButton(vimmenu_T *menu); - bool GrayButton(vimmenu_T *menu, int grey); + bool AddButton(int32 index, vimmenu_T *menu); + bool RemoveButton(vimmenu_T *menu); + bool GrayButton(vimmenu_T *menu, int grey); - float ToolbarHeight() const; - virtual void AttachedToWindow(); + float ToolbarHeight() const; + virtual void AttachedToWindow(); }; BBitmap *VimToolbar::normalButtonsBitmap = NULL; @@ -345,19 +345,19 @@ const float ButtonMargin = 3.; class VimTabLine : public BTabView { - public: - class VimTab : public BTab { - public: - VimTab() : BTab(new BView(BRect(), "-Empty-", 0, 0)) {} + public: + class VimTab : public BTab { + public: + VimTab() : BTab(new BView(BRect(), "-Empty-", 0, 0)) {} - virtual void Select(BView* owner); - }; + virtual void Select(BView* owner); + }; - VimTabLine(BRect r) : BTabView(r, "vimTabLine", B_WIDTH_FROM_LABEL, - B_FOLLOW_LEFT | B_FOLLOW_TOP | B_FOLLOW_RIGHT, B_WILL_DRAW | B_FRAME_EVENTS) {} + VimTabLine(BRect r) : BTabView(r, "vimTabLine", B_WIDTH_FROM_LABEL, + B_FOLLOW_LEFT | B_FOLLOW_TOP | B_FOLLOW_RIGHT, B_WILL_DRAW | B_FRAME_EVENTS) {} - float TablineHeight() const; - virtual void MouseDown(BPoint point); + float TablineHeight() const; + virtual void MouseDown(BPoint point); }; #endif //FEAT_GUI_TABLINE @@ -367,97 +367,97 @@ class VimTabLine : public BTabView // Vim seems rather sloppy in this regard. class VimFont: public BFont { - typedef BFont Inherited; - public: - VimFont(); - VimFont(const VimFont *rhs); - VimFont(const BFont *rhs); - VimFont(const VimFont &rhs); - ~VimFont(); + typedef BFont Inherited; + public: + VimFont(); + VimFont(const VimFont *rhs); + VimFont(const BFont *rhs); + VimFont(const VimFont &rhs); + ~VimFont(); - VimFont *next; - int refcount; - char_u *name; + VimFont *next; + int refcount; + char_u *name; - private: - void init(); + private: + void init(); }; #if defined(FEAT_GUI_DIALOG) class VimDialog : public BWindow { - typedef BWindow Inherited; + typedef BWindow Inherited; - BButton* _CreateButton(int32 which, const char* label); + BButton* _CreateButton(int32 which, const char* label); + + public: + + class View : public BView { + typedef BView Inherited; public: + View(BRect frame); + ~View(); - class View : public BView { - typedef BView Inherited; - - public: - View(BRect frame); - ~View(); - - virtual void Draw(BRect updateRect); - void InitIcon(int32 type); - - private: - BBitmap* fIconBitmap; - }; - - VimDialog(int type, const char *title, const char *message, - const char *buttons, int dfltbutton, const char *textfield, - int ex_cmd); - ~VimDialog(); - - int Go(); - - virtual void MessageReceived(BMessage *msg); + virtual void Draw(BRect updateRect); + void InitIcon(int32 type); private: - sem_id fDialogSem; - int fDialogValue; - BList fButtonsList; - BTextView* fMessageView; - BTextControl* fInputControl; - const char* fInputValue; + BBitmap* fIconBitmap; + }; + + VimDialog(int type, const char *title, const char *message, + const char *buttons, int dfltbutton, const char *textfield, + int ex_cmd); + ~VimDialog(); + + int Go(); + + virtual void MessageReceived(BMessage *msg); + + private: + sem_id fDialogSem; + int fDialogValue; + BList fButtonsList; + BTextView* fMessageView; + BTextControl* fInputControl; + const char* fInputValue; }; class VimSelectFontDialog : public BWindow { - typedef BWindow Inherited; + typedef BWindow Inherited; - void _CleanList(BListView* list); - void _UpdateFontStyles(); - void _UpdateSizeInputPreview(); - void _UpdateFontPreview(); - bool _UpdateFromListItem(BListView* list, char* text, int textSize); - public: + void _CleanList(BListView* list); + void _UpdateFontStyles(); + void _UpdateSizeInputPreview(); + void _UpdateFontPreview(); + bool _UpdateFromListItem(BListView* list, char* text, int textSize); + public: - VimSelectFontDialog(font_family* family, font_style* style, float* size); - ~VimSelectFontDialog(); + VimSelectFontDialog(font_family* family, font_style* style, float* size); + ~VimSelectFontDialog(); - bool Go(); + bool Go(); - virtual void MessageReceived(BMessage *msg); + virtual void MessageReceived(BMessage *msg); - private: - status_t fStatus; - sem_id fDialogSem; - bool fDialogValue; - font_family* fFamily; - font_style* fStyle; - float* fSize; - font_family fFontFamily; - font_style fFontStyle; - float fFontSize; - BStringView* fPreview; - BListView* fFamiliesList; - BListView* fStylesList; - BListView* fSizesList; - BTextControl* fSizesInput; + private: + status_t fStatus; + sem_id fDialogSem; + bool fDialogValue; + font_family* fFamily; + font_style* fStyle; + float* fSize; + font_family fFontFamily; + font_style fFontStyle; + float fFontSize; + BStringView* fPreview; + BListView* fFamiliesList; + BListView* fStylesList; + BListView* fSizesList; + BTextControl* fSizesInput; }; #endif // FEAT_GUI_DIALOG @@ -465,8 +465,8 @@ class VimSelectFontDialog : public BWindow // ---------------- end of GUI classes ---------------- struct MainArgs { - int argc; - char **argv; + int argc; + char **argv; }; // These messages are copied through the VDCMP. @@ -480,74 +480,74 @@ struct MainArgs { #endif struct VimKeyMsg { - char_u length; - char_u chars[KEY_MSG_BUFSIZ]; // contains Vim encoding - bool csi_escape; + char_u length; + char_u chars[KEY_MSG_BUFSIZ]; // contains Vim encoding + bool csi_escape; }; struct VimResizeMsg { - int width; - int height; + int width; + int height; }; struct VimScrollBarMsg { - VimScrollBar *sb; - long value; - int stillDragging; + VimScrollBar *sb; + long value; + int stillDragging; }; struct VimMenuMsg { - vimmenu_T *guiMenu; + vimmenu_T *guiMenu; }; struct VimMouseMsg { - int button; - int x; - int y; - int repeated_click; - int_u modifiers; + int button; + int x; + int y; + int repeated_click; + int_u modifiers; }; struct VimMouseMovedMsg { - int x; - int y; + int x; + int y; }; struct VimFocusMsg { - bool active; + bool active; }; struct VimRefsMsg { - BMessage *message; - bool changedir; + BMessage *message; + bool changedir; }; struct VimTablineMsg { - int index; + int index; }; struct VimTablineMenuMsg { - int index; - int event; + int index; + int event; }; struct VimMsg { - enum VimMsgType { - Key, Resize, ScrollBar, Menu, Mouse, MouseMoved, Focus, Refs, Tabline, TablineMenu - }; + enum VimMsgType { + Key, Resize, ScrollBar, Menu, Mouse, MouseMoved, Focus, Refs, Tabline, TablineMenu + }; - union { - struct VimKeyMsg Key; - struct VimResizeMsg NewSize; - struct VimScrollBarMsg Scroll; - struct VimMenuMsg Menu; - struct VimMouseMsg Mouse; - struct VimMouseMovedMsg MouseMoved; - struct VimFocusMsg Focus; - struct VimRefsMsg Refs; - struct VimTablineMsg Tabline; - struct VimTablineMenuMsg TablineMenu; - } u; + union { + struct VimKeyMsg Key; + struct VimResizeMsg NewSize; + struct VimScrollBarMsg Scroll; + struct VimMenuMsg Menu; + struct VimMouseMsg Mouse; + struct VimMouseMovedMsg MouseMoved; + struct VimFocusMsg Focus; + struct VimRefsMsg Refs; + struct VimTablineMsg Tabline; + struct VimTablineMenuMsg TablineMenu; + } u; }; #define RGB(r, g, b) ((char_u)(r) << 16 | (char_u)(g) << 8 | (char_u)(b) << 0) @@ -557,100 +557,100 @@ struct VimMsg { static struct specialkey { - uint16 BeKeys; -#define KEY(a,b) ((a)<<8|(b)) -#define K(a) KEY(0,a) // for ASCII codes -#define F(b) KEY(1,b) // for scancodes - char_u vim_code0; - char_u vim_code1; + uint16 BeKeys; +#define KEY(a,b) ((a)<<8|(b)) +#define K(a) KEY(0,a) // for ASCII codes +#define F(b) KEY(1,b) // for scancodes + char_u vim_code0; + char_u vim_code1; } special_keys[] = { - {K(B_UP_ARROW), 'k', 'u'}, - {K(B_DOWN_ARROW), 'k', 'd'}, - {K(B_LEFT_ARROW), 'k', 'l'}, - {K(B_RIGHT_ARROW), 'k', 'r'}, - {K(B_BACKSPACE), 'k', 'b'}, - {K(B_INSERT), 'k', 'I'}, - {K(B_DELETE), 'k', 'D'}, - {K(B_HOME), 'k', 'h'}, - {K(B_END), '@', '7'}, - {K(B_PAGE_UP), 'k', 'P'}, // XK_Prior - {K(B_PAGE_DOWN), 'k', 'N'}, // XK_Next, + {K(B_UP_ARROW), 'k', 'u'}, + {K(B_DOWN_ARROW), 'k', 'd'}, + {K(B_LEFT_ARROW), 'k', 'l'}, + {K(B_RIGHT_ARROW), 'k', 'r'}, + {K(B_BACKSPACE), 'k', 'b'}, + {K(B_INSERT), 'k', 'I'}, + {K(B_DELETE), 'k', 'D'}, + {K(B_HOME), 'k', 'h'}, + {K(B_END), '@', '7'}, + {K(B_PAGE_UP), 'k', 'P'}, // XK_Prior + {K(B_PAGE_DOWN), 'k', 'N'}, // XK_Next, #define FIRST_FUNCTION_KEY 11 - {F(B_F1_KEY), 'k', '1'}, - {F(B_F2_KEY), 'k', '2'}, - {F(B_F3_KEY), 'k', '3'}, - {F(B_F4_KEY), 'k', '4'}, - {F(B_F5_KEY), 'k', '5'}, - {F(B_F6_KEY), 'k', '6'}, - {F(B_F7_KEY), 'k', '7'}, - {F(B_F8_KEY), 'k', '8'}, - {F(B_F9_KEY), 'k', '9'}, - {F(B_F10_KEY), 'k', ';'}, + {F(B_F1_KEY), 'k', '1'}, + {F(B_F2_KEY), 'k', '2'}, + {F(B_F3_KEY), 'k', '3'}, + {F(B_F4_KEY), 'k', '4'}, + {F(B_F5_KEY), 'k', '5'}, + {F(B_F6_KEY), 'k', '6'}, + {F(B_F7_KEY), 'k', '7'}, + {F(B_F8_KEY), 'k', '8'}, + {F(B_F9_KEY), 'k', '9'}, + {F(B_F10_KEY), 'k', ';'}, - {F(B_F11_KEY), 'F', '1'}, - {F(B_F12_KEY), 'F', '2'}, - // {XK_F13, 'F', '3'}, // would be print screen - // sysreq - {F(0x0F), 'F', '4'}, // scroll lock - {F(0x10), 'F', '5'}, // pause/break - // {XK_F16, 'F', '6'}, - // {XK_F17, 'F', '7'}, - // {XK_F18, 'F', '8'}, - // {XK_F19, 'F', '9'}, - // {XK_F20, 'F', 'A'}, - // {XK_F21, 'F', 'B'}, - // {XK_F22, 'F', 'C'}, - // {XK_F23, 'F', 'D'}, - // {XK_F24, 'F', 'E'}, - // {XK_F25, 'F', 'F'}, - // {XK_F26, 'F', 'G'}, - // {XK_F27, 'F', 'H'}, - // {XK_F28, 'F', 'I'}, - // {XK_F29, 'F', 'J'}, - // {XK_F30, 'F', 'K'}, - // {XK_F31, 'F', 'L'}, - // {XK_F32, 'F', 'M'}, - // {XK_F33, 'F', 'N'}, - // {XK_F34, 'F', 'O'}, - // {XK_F35, 'F', 'P'}, // keysymdef.h defines up to F35 + {F(B_F11_KEY), 'F', '1'}, + {F(B_F12_KEY), 'F', '2'}, + // {XK_F13, 'F', '3'}, // would be print screen + // sysreq + {F(0x0F), 'F', '4'}, // scroll lock + {F(0x10), 'F', '5'}, // pause/break + // {XK_F16, 'F', '6'}, + // {XK_F17, 'F', '7'}, + // {XK_F18, 'F', '8'}, + // {XK_F19, 'F', '9'}, + // {XK_F20, 'F', 'A'}, + // {XK_F21, 'F', 'B'}, + // {XK_F22, 'F', 'C'}, + // {XK_F23, 'F', 'D'}, + // {XK_F24, 'F', 'E'}, + // {XK_F25, 'F', 'F'}, + // {XK_F26, 'F', 'G'}, + // {XK_F27, 'F', 'H'}, + // {XK_F28, 'F', 'I'}, + // {XK_F29, 'F', 'J'}, + // {XK_F30, 'F', 'K'}, + // {XK_F31, 'F', 'L'}, + // {XK_F32, 'F', 'M'}, + // {XK_F33, 'F', 'N'}, + // {XK_F34, 'F', 'O'}, + // {XK_F35, 'F', 'P'}, // keysymdef.h defines up to F35 - // {XK_Help, '%', '1'}, // XK_Help - {F(B_PRINT_KEY), '%', '9'}, + // {XK_Help, '%', '1'}, // XK_Help + {F(B_PRINT_KEY), '%', '9'}, #if 0 - // Keypad keys: - {F(0x48), 'k', 'l'}, // XK_KP_Left - {F(0x4A), 'k', 'r'}, // XK_KP_Right - {F(0x38), 'k', 'u'}, // XK_KP_Up - {F(0x59), 'k', 'd'}, // XK_KP_Down - {F(0x64), 'k', 'I'}, // XK_KP_Insert - {F(0x65), 'k', 'D'}, // XK_KP_Delete - {F(0x37), 'k', 'h'}, // XK_KP_Home - {F(0x58), '@', '7'}, // XK_KP_End - {F(0x39), 'k', 'P'}, // XK_KP_Prior - {F(0x60), 'k', 'N'}, // XK_KP_Next - {F(0x49), '&', '8'}, // XK_Undo, keypad 5 + // Keypad keys: + {F(0x48), 'k', 'l'}, // XK_KP_Left + {F(0x4A), 'k', 'r'}, // XK_KP_Right + {F(0x38), 'k', 'u'}, // XK_KP_Up + {F(0x59), 'k', 'd'}, // XK_KP_Down + {F(0x64), 'k', 'I'}, // XK_KP_Insert + {F(0x65), 'k', 'D'}, // XK_KP_Delete + {F(0x37), 'k', 'h'}, // XK_KP_Home + {F(0x58), '@', '7'}, // XK_KP_End + {F(0x39), 'k', 'P'}, // XK_KP_Prior + {F(0x60), 'k', 'N'}, // XK_KP_Next + {F(0x49), '&', '8'}, // XK_Undo, keypad 5 #endif - // End of list marker: - {0, 0, 0} + // End of list marker: + {0, 0, 0} }; #define NUM_SPECIAL_KEYS (sizeof(special_keys)/sizeof(special_keys[0])) // ---------------- VimApp ---------------- - static void + static void docd(BPath &path) { - mch_chdir((char *)path.Path()); - // Do this to get the side effects of a :cd command - do_cmdline_cmd((char_u *)"cd ."); + mch_chdir((char *)path.Path()); + // Do this to get the side effects of a :cd command + do_cmdline_cmd((char_u *)"cd ."); } - static void + static void drop_callback(void *cookie) { // TODO here we could handle going to a specific position in the dropped @@ -660,119 +660,119 @@ drop_callback(void *cookie) } // Really handle dropped files and folders. - static void + static void RefsReceived(BMessage *m, bool changedir) { - uint32 type; - int32 count; + uint32 type; + int32 count; - m->PrintToStream(); - switch (m->what) { - case B_REFS_RECEIVED: - case B_SIMPLE_DATA: - m->GetInfo("refs", &type, &count); - if (type != B_REF_TYPE) - goto bad; - break; - case B_ARGV_RECEIVED: - m->GetInfo("argv", &type, &count); - if (type != B_STRING_TYPE) - goto bad; - if (changedir) { - char *dirname; - if (m->FindString("cwd", (const char **) &dirname) == B_OK) { - chdir(dirname); - do_cmdline_cmd((char_u *)"cd ."); - } - } - break; - default: + m->PrintToStream(); + switch (m->what) { + case B_REFS_RECEIVED: + case B_SIMPLE_DATA: + m->GetInfo("refs", &type, &count); + if (type != B_REF_TYPE) + goto bad; + break; + case B_ARGV_RECEIVED: + m->GetInfo("argv", &type, &count); + if (type != B_STRING_TYPE) + goto bad; + if (changedir) { + char *dirname; + if (m->FindString("cwd", (const char **) &dirname) == B_OK) { + chdir(dirname); + do_cmdline_cmd((char_u *)"cd ."); + } + } + break; + default: bad: - /*fprintf(stderr, "bad!\n"); */ - delete m; - return; - } + /*fprintf(stderr, "bad!\n"); */ + delete m; + return; + } #ifdef FEAT_VISUAL - reset_VIsual(); + reset_VIsual(); #endif - char_u **fnames; - fnames = (char_u **) alloc(count * sizeof(char_u *)); - int fname_index = 0; + char_u **fnames; + fnames = (char_u **) alloc(count * sizeof(char_u *)); + int fname_index = 0; - switch (m->what) { - case B_REFS_RECEIVED: - case B_SIMPLE_DATA: - // fprintf(stderr, "case B_REFS_RECEIVED\n"); - for (int i = 0; i < count; ++i) - { - entry_ref ref; - if (m->FindRef("refs", i, &ref) == B_OK) { - BEntry entry(&ref, false); - BPath path; - entry.GetPath(&path); + switch (m->what) { + case B_REFS_RECEIVED: + case B_SIMPLE_DATA: + // fprintf(stderr, "case B_REFS_RECEIVED\n"); + for (int i = 0; i < count; ++i) + { + entry_ref ref; + if (m->FindRef("refs", i, &ref) == B_OK) { + BEntry entry(&ref, false); + BPath path; + entry.GetPath(&path); - // Change to parent directory? - if (changedir) { - BPath parentpath; - path.GetParent(&parentpath); - docd(parentpath); - } + // Change to parent directory? + if (changedir) { + BPath parentpath; + path.GetParent(&parentpath); + docd(parentpath); + } - // Is it a directory? If so, cd into it. - BDirectory bdir(&ref); - if (bdir.InitCheck() == B_OK) { - // don't cd if we already did it - if (!changedir) - docd(path); - } else { - mch_dirname(IObuff, IOSIZE); - char_u *fname = shorten_fname((char_u *)path.Path(), IObuff); - if (fname == NULL) - fname = (char_u *)path.Path(); - fnames[fname_index++] = vim_strsave(fname); - // fprintf(stderr, "%s\n", fname); - } + // Is it a directory? If so, cd into it. + BDirectory bdir(&ref); + if (bdir.InitCheck() == B_OK) { + // don't cd if we already did it + if (!changedir) + docd(path); + } else { + mch_dirname(IObuff, IOSIZE); + char_u *fname = shorten_fname((char_u *)path.Path(), IObuff); + if (fname == NULL) + fname = (char_u *)path.Path(); + fnames[fname_index++] = vim_strsave(fname); + // fprintf(stderr, "%s\n", fname); + } - // Only do it for the first file/dir - changedir = false; - } - } - break; - case B_ARGV_RECEIVED: - // fprintf(stderr, "case B_ARGV_RECEIVED\n"); - for (int i = 1; i < count; ++i) - { - char *fname; + // Only do it for the first file/dir + changedir = false; + } + } + break; + case B_ARGV_RECEIVED: + // fprintf(stderr, "case B_ARGV_RECEIVED\n"); + for (int i = 1; i < count; ++i) + { + char *fname; - if (m->FindString("argv", i, (const char **) &fname) == B_OK) { - fnames[fname_index++] = vim_strsave((char_u *)fname); - } - } - break; - default: - // fprintf(stderr, "case default\n"); - break; - } + if (m->FindString("argv", i, (const char **) &fname) == B_OK) { + fnames[fname_index++] = vim_strsave((char_u *)fname); + } + } + break; + default: + // fprintf(stderr, "case default\n"); + break; + } - delete m; + delete m; - // Handle the drop, :edit to get to the file - if (fname_index > 0) { - handle_drop(fname_index, fnames, FALSE, drop_callback, NULL); + // Handle the drop, :edit to get to the file + if (fname_index > 0) { + handle_drop(fname_index, fnames, FALSE, drop_callback, NULL); - setcursor(); - out_flush(); - } else { - vim_free(fnames); - } + setcursor(); + out_flush(); + } else { + vim_free(fnames); + } } VimApp::VimApp(const char *appsig): - BApplication(appsig), - fFilePanelSem(-1), - fFilePanel(NULL) + BApplication(appsig), + fFilePanelSem(-1), + fFilePanel(NULL) { } @@ -780,1073 +780,1073 @@ VimApp::~VimApp() { } - void + void VimApp::ReadyToRun() { - /* - * Apparently signals are inherited by the created thread - - * disable the most annoying ones. - */ - signal(SIGINT, SIG_IGN); - signal(SIGQUIT, SIG_IGN); + /* + * Apparently signals are inherited by the created thread - + * disable the most annoying ones. + */ + signal(SIGINT, SIG_IGN); + signal(SIGQUIT, SIG_IGN); } - void + void VimApp::ArgvReceived(int32 arg_argc, char **arg_argv) { - if (!IsLaunching()) { - /* - * This can happen if we are set to Single or Exclusive - * Launch. Be nice and open the file(s). - */ - if (gui.vimWindow) - gui.vimWindow->Minimize(false); - BMessage *m = CurrentMessage(); - DetachCurrentMessage(); - SendRefs(m, true); - } -} - - void -VimApp::RefsReceived(BMessage *m) -{ - // Horrible hack!!! XXX XXX XXX - // The real problem is that b_start_ffc is set too late for - // the initial empty buffer. As a result the window will be - // split instead of abandoned. - int limit = 15; - while (--limit >= 0 && (curbuf == NULL || curbuf->b_start_ffc == 0)) - snooze(100000); // 0.1 s + if (!IsLaunching()) { + /* + * This can happen if we are set to Single or Exclusive + * Launch. Be nice and open the file(s). + */ if (gui.vimWindow) - gui.vimWindow->Minimize(false); + gui.vimWindow->Minimize(false); + BMessage *m = CurrentMessage(); DetachCurrentMessage(); SendRefs(m, true); + } +} + + void +VimApp::RefsReceived(BMessage *m) +{ + // Horrible hack!!! XXX XXX XXX + // The real problem is that b_start_ffc is set too late for + // the initial empty buffer. As a result the window will be + // split instead of abandoned. + int limit = 15; + while (--limit >= 0 && (curbuf == NULL || curbuf->b_start_ffc == 0)) + snooze(100000); // 0.1 s + if (gui.vimWindow) + gui.vimWindow->Minimize(false); + DetachCurrentMessage(); + SendRefs(m, true); } /* * Pass a BMessage on to the main() thread. * Caller must have detached the message. */ - void + void VimApp::SendRefs(BMessage *m, bool changedir) { - VimRefsMsg rm; - rm.message = m; - rm.changedir = changedir; + VimRefsMsg rm; + rm.message = m; + rm.changedir = changedir; - write_port(gui.vdcmp, VimMsg::Refs, &rm, sizeof(rm)); - // calls ::RefsReceived + write_port(gui.vdcmp, VimMsg::Refs, &rm, sizeof(rm)); + // calls ::RefsReceived } - void + void VimApp::MessageReceived(BMessage *m) { - switch (m->what) { - case 'save': - { - entry_ref refDirectory; - m->FindRef("directory", &refDirectory); - fBrowsedPath.SetTo(&refDirectory); - BString strName; - m->FindString("name", &strName); - fBrowsedPath.Append(strName.String()); - } - break; - case 'open': - { - entry_ref ref; - m->FindRef("refs", &ref); - fBrowsedPath.SetTo(&ref); - } - break; - case B_CANCEL: - { - BFilePanel *panel; - m->FindPointer("source", (void**)&panel); - if(fFilePanelSem != -1 && panel == fFilePanel) - { - delete_sem(fFilePanelSem); - fFilePanelSem = -1; - } + switch (m->what) { + case 'save': + { + entry_ref refDirectory; + m->FindRef("directory", &refDirectory); + fBrowsedPath.SetTo(&refDirectory); + BString strName; + m->FindString("name", &strName); + fBrowsedPath.Append(strName.String()); + } + break; + case 'open': + { + entry_ref ref; + m->FindRef("refs", &ref); + fBrowsedPath.SetTo(&ref); + } + break; + case B_CANCEL: + { + BFilePanel *panel; + m->FindPointer("source", (void**)&panel); + if (fFilePanelSem != -1 && panel == fFilePanel) + { + delete_sem(fFilePanelSem); + fFilePanelSem = -1; + } - } - break; - default: - Inherited::MessageReceived(m); - break; - } + } + break; + default: + Inherited::MessageReceived(m); + break; + } } - bool + bool VimApp::QuitRequested() { - (void)Inherited::QuitRequested(); - return false; + (void)Inherited::QuitRequested(); + return false; } // ---------------- VimWindow ---------------- VimWindow::VimWindow(): - BWindow(BRect(40, 40, 150, 150), - "Vim", - B_TITLED_WINDOW, - 0, - B_CURRENT_WORKSPACE) + BWindow(BRect(40, 40, 150, 150), + "Vim", + B_TITLED_WINDOW, + 0, + B_CURRENT_WORKSPACE) { - init(); + init(); } VimWindow::~VimWindow() { - if (formView) { - RemoveChild(formView); - delete formView; - } - gui.vimWindow = NULL; + if (formView) { + RemoveChild(formView); + delete formView; + } + gui.vimWindow = NULL; } - void + void VimWindow::init() { - // Attach the VimFormView - formView = new VimFormView(Bounds()); - if (formView != NULL) { - AddChild(formView); - } + // Attach the VimFormView + formView = new VimFormView(Bounds()); + if (formView != NULL) { + AddChild(formView); + } } #if 0 // disabled in zeta patch - void + void VimWindow::DispatchMessage(BMessage *m, BHandler *h) { - /* - * Route B_MOUSE_UP messages to MouseUp(), in - * a manner that should be compatible with the - * intended future system behaviour. - */ - switch (m->what) { - case B_MOUSE_UP: - // if (!h) h = PreferredHandler(); - // gcc isn't happy without this extra set of braces, complains about - // jump to case label crosses init of 'class BView * v' - // richard@whitequeen.com jul 99 - { - BView *v = dynamic_cast(h); - if (v) { - // m->PrintToStream(); - BPoint where; - m->FindPoint("where", &where); - v->MouseUp(where); - } else { - Inherited::DispatchMessage(m, h); - } - } - break; - default: - Inherited::DispatchMessage(m, h); - } + /* + * Route B_MOUSE_UP messages to MouseUp(), in + * a manner that should be compatible with the + * intended future system behaviour. + */ + switch (m->what) { + case B_MOUSE_UP: + // if (!h) h = PreferredHandler(); + // gcc isn't happy without this extra set of braces, complains about + // jump to case label crosses init of 'class BView * v' + // richard@whitequeen.com jul 99 + { + BView *v = dynamic_cast(h); + if (v) { + // m->PrintToStream(); + BPoint where; + m->FindPoint("where", &where); + v->MouseUp(where); + } else { + Inherited::DispatchMessage(m, h); + } + } + break; + default: + Inherited::DispatchMessage(m, h); + } } #endif - void + void VimWindow::WindowActivated(bool active) { - Inherited::WindowActivated(active); - // the textArea gets the keyboard action - if (active && gui.vimTextArea) - gui.vimTextArea->MakeFocus(true); + Inherited::WindowActivated(active); + // the textArea gets the keyboard action + if (active && gui.vimTextArea) + gui.vimTextArea->MakeFocus(true); - struct VimFocusMsg fm; - fm.active = active; + struct VimFocusMsg fm; + fm.active = active; - write_port(gui.vdcmp, VimMsg::Focus, &fm, sizeof(fm)); + write_port(gui.vdcmp, VimMsg::Focus, &fm, sizeof(fm)); } - bool + bool VimWindow::QuitRequested() { - struct VimKeyMsg km; - km.length = 5; - memcpy((char *)km.chars, "\033:qa\r", km.length); - km.csi_escape = false; - write_port(gui.vdcmp, VimMsg::Key, &km, sizeof(km)); - return false; + struct VimKeyMsg km; + km.length = 5; + memcpy((char *)km.chars, "\033:qa\r", km.length); + km.csi_escape = false; + write_port(gui.vdcmp, VimMsg::Key, &km, sizeof(km)); + return false; } // ---------------- VimFormView ---------------- VimFormView::VimFormView(BRect frame): - BView(frame, "VimFormView", B_FOLLOW_ALL_SIDES, - B_WILL_DRAW | B_FRAME_EVENTS), - menuBar(NULL), + BView(frame, "VimFormView", B_FOLLOW_ALL_SIDES, + B_WILL_DRAW | B_FRAME_EVENTS), + menuBar(NULL), #ifdef FEAT_TOOLBAR - toolBar(NULL), + toolBar(NULL), #endif #ifdef FEAT_GUI_TABLINE -// showingTabLine(false), - tabLine(NULL), +// showingTabLine(false), + tabLine(NULL), #endif - textArea(NULL) + textArea(NULL) { - init(frame); + init(frame); } VimFormView::~VimFormView() { - if (menuBar) { - RemoveChild(menuBar); + if (menuBar) { + RemoveChild(menuBar); #ifdef never - // deleting the menuBar leads to SEGV on exit - // richard@whitequeen.com Jul 99 - delete menuBar; + // deleting the menuBar leads to SEGV on exit + // richard@whitequeen.com Jul 99 + delete menuBar; #endif - } + } #ifdef FEAT_TOOLBAR - delete toolBar; + delete toolBar; #endif #ifdef FEAT_GUI_TABLINE - delete tabLine; + delete tabLine; #endif - if (textArea) { - RemoveChild(textArea); - delete textArea; - } - gui.vimForm = NULL; + if (textArea) { + RemoveChild(textArea); + delete textArea; + } + gui.vimForm = NULL; } - void + void VimFormView::init(BRect frame) { - menuBar = new BMenuBar(BRect(0,0,-MENUBAR_MARGIN,-MENUBAR_MARGIN), - "VimMenuBar"); + menuBar = new BMenuBar(BRect(0,0,-MENUBAR_MARGIN,-MENUBAR_MARGIN), + "VimMenuBar"); - AddChild(menuBar); + AddChild(menuBar); #ifdef FEAT_TOOLBAR - toolBar = new VimToolbar(BRect(0,0,0,0), "VimToolBar"); - toolBar->PrepareButtonBitmaps(); - AddChild(toolBar); + toolBar = new VimToolbar(BRect(0,0,0,0), "VimToolBar"); + toolBar->PrepareButtonBitmaps(); + AddChild(toolBar); #endif #ifdef FEAT_GUI_TABLINE - tabLine = new VimTabLine(BRect(0,0,0,0)); -// tabLine->PrepareButtonBitmaps(); - AddChild(tabLine); + tabLine = new VimTabLine(BRect(0,0,0,0)); +// tabLine->PrepareButtonBitmaps(); + AddChild(tabLine); #endif - BRect remaining = frame; - textArea = new VimTextAreaView(remaining); - AddChild(textArea); - // The textArea will be resized later when menus are added + BRect remaining = frame; + textArea = new VimTextAreaView(remaining); + AddChild(textArea); + // The textArea will be resized later when menus are added - gui.vimForm = this; + gui.vimForm = this; } #ifdef FEAT_TOOLBAR - float + float VimFormView::ToolbarHeight() const { - return toolBar ? toolBar->ToolbarHeight() : 0.; + return toolBar ? toolBar->ToolbarHeight() : 0.; } #endif #ifdef FEAT_GUI_TABLINE - float + float VimFormView::TablineHeight() const { - return (tabLine && IsShowingTabLine()) ? tabLine->TablineHeight() : 0.; + return (tabLine && IsShowingTabLine()) ? tabLine->TablineHeight() : 0.; } #endif - void + void VimFormView::AllAttached() { - /* - * Apparently signals are inherited by the created thread - - * disable the most annoying ones. - */ - signal(SIGINT, SIG_IGN); - signal(SIGQUIT, SIG_IGN); + /* + * Apparently signals are inherited by the created thread - + * disable the most annoying ones. + */ + signal(SIGINT, SIG_IGN); + signal(SIGQUIT, SIG_IGN); - if (menuBar && textArea) { - /* - * Resize the textArea to fill the space left over by the menu. - * This is somewhat futile since it will be done again once - * menus are added to the menu bar. - */ - BRect remaining = Bounds(); + if (menuBar && textArea) { + /* + * Resize the textArea to fill the space left over by the menu. + * This is somewhat futile since it will be done again once + * menus are added to the menu bar. + */ + BRect remaining = Bounds(); #ifdef FEAT_MENU - remaining.top += MenuHeight(); - menuBar->ResizeTo(remaining.right, remaining.top); - gui.menu_height = (int) MenuHeight(); + remaining.top += MenuHeight(); + menuBar->ResizeTo(remaining.right, remaining.top); + gui.menu_height = (int) MenuHeight(); #endif #ifdef FEAT_TOOLBAR - toolBar->MoveTo(remaining.left, remaining.top); - toolBar->ResizeTo(remaining.right, ToolbarHeight()); - remaining.top += ToolbarHeight(); - gui.toolbar_height = ToolbarHeight(); + toolBar->MoveTo(remaining.left, remaining.top); + toolBar->ResizeTo(remaining.right, ToolbarHeight()); + remaining.top += ToolbarHeight(); + gui.toolbar_height = ToolbarHeight(); #endif #ifdef FEAT_GUI_TABLINE - tabLine->MoveTo(remaining.left, remaining.top); - tabLine->ResizeTo(remaining.right + 1, TablineHeight()); - remaining.top += TablineHeight(); - gui.tabline_height = TablineHeight(); + tabLine->MoveTo(remaining.left, remaining.top); + tabLine->ResizeTo(remaining.right + 1, TablineHeight()); + remaining.top += TablineHeight(); + gui.tabline_height = TablineHeight(); #endif - textArea->ResizeTo(remaining.Width(), remaining.Height()); - textArea->MoveTo(remaining.left, remaining.top); - } + textArea->ResizeTo(remaining.Width(), remaining.Height()); + textArea->MoveTo(remaining.left, remaining.top); + } - Inherited::AllAttached(); + Inherited::AllAttached(); } - void + void VimFormView::FrameResized(float new_width, float new_height) { - struct VimResizeMsg sm; - int adjust_h, adjust_w; + struct VimResizeMsg sm; + int adjust_h, adjust_w; - new_width += 1; // adjust from width to number of pixels occupied - new_height += 1; + new_width += 1; // adjust from width to number of pixels occupied + new_height += 1; - sm.width = (int) new_width; - sm.height = (int) new_height; - adjust_w = ((int)new_width - gui_get_base_width()) % gui.char_width; - adjust_h = ((int)new_height - gui_get_base_height()) % gui.char_height; + sm.width = (int) new_width; + sm.height = (int) new_height; + adjust_w = ((int)new_width - gui_get_base_width()) % gui.char_width; + adjust_h = ((int)new_height - gui_get_base_height()) % gui.char_height; - if (adjust_w > 0 || adjust_h > 0) { - sm.width -= adjust_w; - sm.height -= adjust_h; - } + if (adjust_w > 0 || adjust_h > 0) { + sm.width -= adjust_w; + sm.height -= adjust_h; + } - write_port(gui.vdcmp, VimMsg::Resize, &sm, sizeof(sm)); - // calls gui_resize_shell(new_width, new_height); + write_port(gui.vdcmp, VimMsg::Resize, &sm, sizeof(sm)); + // calls gui_resize_shell(new_width, new_height); - return; + return; - /* - * The area below the vertical scrollbar is erased to the colour - * set with SetViewColor() automatically, because we had set - * B_WILL_DRAW. Resizing the window tight around the vertical - * scroll bar also helps to avoid debris. - */ + /* + * The area below the vertical scrollbar is erased to the colour + * set with SetViewColor() automatically, because we had set + * B_WILL_DRAW. Resizing the window tight around the vertical + * scroll bar also helps to avoid debris. + */ } // ---------------- VimTextAreaView ---------------- VimTextAreaView::VimTextAreaView(BRect frame): - BView(frame, "VimTextAreaView", B_FOLLOW_ALL_SIDES, + BView(frame, "VimTextAreaView", B_FOLLOW_ALL_SIDES, #ifdef FEAT_MBYTE_IME - B_WILL_DRAW | B_FULL_UPDATE_ON_RESIZE | B_INPUT_METHOD_AWARE), + B_WILL_DRAW | B_FULL_UPDATE_ON_RESIZE | B_INPUT_METHOD_AWARE), #else - B_WILL_DRAW | B_FULL_UPDATE_ON_RESIZE), + B_WILL_DRAW | B_FULL_UPDATE_ON_RESIZE), #endif - mouseDragEventCount(0) + mouseDragEventCount(0) { #ifdef FEAT_MBYTE_IME - IMData.messenger = NULL; - IMData.message = NULL; + IMData.messenger = NULL; + IMData.message = NULL; #endif - init(frame); + init(frame); } VimTextAreaView::~VimTextAreaView() { - gui.vimTextArea = NULL; + gui.vimTextArea = NULL; } - void + void VimTextAreaView::init(BRect frame) { - // set up global var for fast access - gui.vimTextArea = this; + // set up global var for fast access + gui.vimTextArea = this; - /* - * Tell the app server not to erase the view: we will - * fill it in completely by ourselves. - * (Does this really work? Even if not, it won't harm either.) - */ - SetViewColor(B_TRANSPARENT_32_BIT); + /* + * Tell the app server not to erase the view: we will + * fill it in completely by ourselves. + * (Does this really work? Even if not, it won't harm either.) + */ + SetViewColor(B_TRANSPARENT_32_BIT); #define PEN_WIDTH 1 - SetPenSize(PEN_WIDTH); + SetPenSize(PEN_WIDTH); #define W_WIDTH(curwin) 0 } - void + void VimTextAreaView::Draw(BRect updateRect) { - /* - * XXX Other ports call here: - * out_flush(); * make sure all output has been processed * - * but we can't do that, since it involves too much information - * that is owned by other threads... - */ + /* + * XXX Other ports call here: + * out_flush(); * make sure all output has been processed * + * but we can't do that, since it involves too much information + * that is owned by other threads... + */ - /* - * No need to use gui.vimWindow->Lock(): we are locked already. - * However, it would not hurt. - */ - rgb_color rgb = GUI_TO_RGB(gui.back_pixel); - SetLowColor(rgb); - FillRect(updateRect, B_SOLID_LOW); - gui_redraw((int) updateRect.left, (int) updateRect.top, - (int) (updateRect.Width() + PEN_WIDTH), (int) (updateRect.Height() + PEN_WIDTH)); + /* + * No need to use gui.vimWindow->Lock(): we are locked already. + * However, it would not hurt. + */ + rgb_color rgb = GUI_TO_RGB(gui.back_pixel); + SetLowColor(rgb); + FillRect(updateRect, B_SOLID_LOW); + gui_redraw((int) updateRect.left, (int) updateRect.top, + (int) (updateRect.Width() + PEN_WIDTH), (int) (updateRect.Height() + PEN_WIDTH)); - // Clear the border areas if needed - SetLowColor(rgb); + // Clear the border areas if needed + SetLowColor(rgb); - if (updateRect.left < FILL_X(0)) // left border - FillRect(BRect(updateRect.left, updateRect.top, - FILL_X(0)-PEN_WIDTH, updateRect.bottom), B_SOLID_LOW); - if (updateRect.top < FILL_Y(0)) // top border - FillRect(BRect(updateRect.left, updateRect.top, - updateRect.right, FILL_Y(0)-PEN_WIDTH), B_SOLID_LOW); - if (updateRect.right >= FILL_X(Columns)) // right border - FillRect(BRect(FILL_X((int)Columns), updateRect.top, - updateRect.right, updateRect.bottom), B_SOLID_LOW); - if (updateRect.bottom >= FILL_Y(Rows)) // bottom border - FillRect(BRect(updateRect.left, FILL_Y((int)Rows), - updateRect.right, updateRect.bottom), B_SOLID_LOW); + if (updateRect.left < FILL_X(0)) // left border + FillRect(BRect(updateRect.left, updateRect.top, + FILL_X(0)-PEN_WIDTH, updateRect.bottom), B_SOLID_LOW); + if (updateRect.top < FILL_Y(0)) // top border + FillRect(BRect(updateRect.left, updateRect.top, + updateRect.right, FILL_Y(0)-PEN_WIDTH), B_SOLID_LOW); + if (updateRect.right >= FILL_X(Columns)) // right border + FillRect(BRect(FILL_X((int)Columns), updateRect.top, + updateRect.right, updateRect.bottom), B_SOLID_LOW); + if (updateRect.bottom >= FILL_Y(Rows)) // bottom border + FillRect(BRect(updateRect.left, FILL_Y((int)Rows), + updateRect.right, updateRect.bottom), B_SOLID_LOW); #ifdef FEAT_MBYTE_IME - DrawIMString(); + DrawIMString(); #endif } - void + void VimTextAreaView::KeyDown(const char *bytes, int32 numBytes) { - struct VimKeyMsg km; - char_u *dest = km.chars; + struct VimKeyMsg km; + char_u *dest = km.chars; - bool canHaveVimModifiers = false; + bool canHaveVimModifiers = false; - BMessage *msg = Window()->CurrentMessage(); - assert(msg); - // msg->PrintToStream(); + BMessage *msg = Window()->CurrentMessage(); + assert(msg); + // msg->PrintToStream(); + + /* + * Convert special keys to Vim codes. + * I think it is better to do it in the window thread + * so we use at least a little bit of the potential + * of our 2 CPUs. Besides, due to the fantastic mapping + * of special keys to UTF-8, we have quite some work to + * do... + * TODO: I'm not quite happy with detection of special + * keys. Perhaps I should use scan codes after all... + */ + if (numBytes > 1) { + // This cannot be a special key + if (numBytes > KEY_MSG_BUFSIZ) + numBytes = KEY_MSG_BUFSIZ; // should never happen... ??? + km.length = numBytes; + memcpy((char *)dest, bytes, numBytes); + km.csi_escape = true; + } else { + int32 scancode = 0; + msg->FindInt32("key", &scancode); + + int32 beModifiers = 0; + msg->FindInt32("modifiers", &beModifiers); + + char_u string[3]; + int len = 0; + km.length = 0; /* - * Convert special keys to Vim codes. - * I think it is better to do it in the window thread - * so we use at least a little bit of the potential - * of our 2 CPUs. Besides, due to the fantastic mapping - * of special keys to UTF-8, we have quite some work to - * do... - * TODO: I'm not quite happy with detection of special - * keys. Perhaps I should use scan codes after all... + * For normal, printable ASCII characters, don't look them up + * to check if they might be a special key. They aren't. */ - if (numBytes > 1) { - // This cannot be a special key - if (numBytes > KEY_MSG_BUFSIZ) - numBytes = KEY_MSG_BUFSIZ; // should never happen... ??? - km.length = numBytes; - memcpy((char *)dest, bytes, numBytes); - km.csi_escape = true; - } else { - int32 scancode = 0; - msg->FindInt32("key", &scancode); - - int32 beModifiers = 0; - msg->FindInt32("modifiers", &beModifiers); - - char_u string[3]; - int len = 0; - km.length = 0; + assert(B_BACKSPACE <= 0x20); + assert(B_DELETE == 0x7F); + if (((char_u)bytes[0] <= 0x20 || (char_u)bytes[0] == 0x7F) && + numBytes == 1) { + /* + * Due to the great nature of Be's mapping of special keys, + * viz. into the range of the control characters, + * we can only be sure it is *really* a special key if + * if it is special without using ctrl. So, only if ctrl is + * used, we need to check it unmodified. + */ + if (beModifiers & B_CONTROL_KEY) { + int index = keyMap->normal_map[scancode]; + int newNumBytes = keyMapChars[index]; + char_u *newBytes = (char_u *)&keyMapChars[index + 1]; /* - * For normal, printable ASCII characters, don't look them up - * to check if they might be a special key. They aren't. + * Check if still special without the control key. + * This is needed for BACKSPACE: that key does produce + * different values with modifiers (DEL). + * Otherwise we could simply have checked for equality. */ - assert(B_BACKSPACE <= 0x20); - assert(B_DELETE == 0x7F); - if (((char_u)bytes[0] <= 0x20 || (char_u)bytes[0] == 0x7F) && - numBytes == 1) { - /* - * Due to the great nature of Be's mapping of special keys, - * viz. into the range of the control characters, - * we can only be sure it is *really* a special key if - * if it is special without using ctrl. So, only if ctrl is - * used, we need to check it unmodified. - */ - if (beModifiers & B_CONTROL_KEY) { - int index = keyMap->normal_map[scancode]; - int newNumBytes = keyMapChars[index]; - char_u *newBytes = (char_u *)&keyMapChars[index + 1]; - - /* - * Check if still special without the control key. - * This is needed for BACKSPACE: that key does produce - * different values with modifiers (DEL). - * Otherwise we could simply have checked for equality. - */ - if (newNumBytes != 1 || (*newBytes > 0x20 && - *newBytes != 0x7F )) { - goto notspecial; - } - bytes = (char *)newBytes; - } - canHaveVimModifiers = true; - - uint16 beoskey; - int first, last; - - /* - * If numBytes == 0 that probably always indicates a special key. - * (does not happen yet) - */ - if (numBytes == 0 || bytes[0] == B_FUNCTION_KEY) { - beoskey = F(scancode); - first = FIRST_FUNCTION_KEY; - last = NUM_SPECIAL_KEYS; - } else if (*bytes == '\n' && scancode == 0x47) { - // remap the (non-keypad) ENTER key from \n to \r. - string[0] = '\r'; - len = 1; - first = last = 0; - } else { - beoskey = K(bytes[0]); - first = 0; - last = FIRST_FUNCTION_KEY; - } - - for (int i = first; i < last; i++) { - if (special_keys[i].BeKeys == beoskey) { - string[0] = CSI; - string[1] = special_keys[i].vim_code0; - string[2] = special_keys[i].vim_code1; - len = 3; - } - } + if (newNumBytes != 1 || (*newBytes > 0x20 && + *newBytes != 0x7F )) { + goto notspecial; } + bytes = (char *)newBytes; + } + canHaveVimModifiers = true; + + uint16 beoskey; + int first, last; + + /* + * If numBytes == 0 that probably always indicates a special key. + * (does not happen yet) + */ + if (numBytes == 0 || bytes[0] == B_FUNCTION_KEY) { + beoskey = F(scancode); + first = FIRST_FUNCTION_KEY; + last = NUM_SPECIAL_KEYS; + } else if (*bytes == '\n' && scancode == 0x47) { + // remap the (non-keypad) ENTER key from \n to \r. + string[0] = '\r'; + len = 1; + first = last = 0; + } else { + beoskey = K(bytes[0]); + first = 0; + last = FIRST_FUNCTION_KEY; + } + + for (int i = first; i < last; i++) { + if (special_keys[i].BeKeys == beoskey) { + string[0] = CSI; + string[1] = special_keys[i].vim_code0; + string[2] = special_keys[i].vim_code1; + len = 3; + } + } + } notspecial: - if (len == 0) { - string[0] = bytes[0]; - len = 1; + if (len == 0) { + string[0] = bytes[0]; + len = 1; + } + + // Special keys (and a few others) may have modifiers +#if 0 + if (len == 3 || + bytes[0] == B_SPACE || bytes[0] == B_TAB || + bytes[0] == B_RETURN || bytes[0] == '\r' || + bytes[0] == B_ESCAPE) +#else + if (canHaveVimModifiers) +#endif + { + int modifiers; + modifiers = 0; + if (beModifiers & B_SHIFT_KEY) + modifiers |= MOD_MASK_SHIFT; + if (beModifiers & B_CONTROL_KEY) + modifiers |= MOD_MASK_CTRL; + if (beModifiers & B_OPTION_KEY) + modifiers |= MOD_MASK_ALT; + + /* + * For some keys a shift modifier is translated into another key + * code. Do we need to handle the case where len != 1 and + * string[0] != CSI? (Not for BeOS, since len == 3 implies + * string[0] == CSI...) + */ + int key; + if (string[0] == CSI && len == 3) + key = TO_SPECIAL(string[1], string[2]); + else + key = string[0]; + key = simplify_key(key, &modifiers); + if (IS_SPECIAL(key)) + { + string[0] = CSI; + string[1] = K_SECOND(key); + string[2] = K_THIRD(key); + len = 3; + } + else + { + string[0] = key; + len = 1; } - // Special keys (and a few others) may have modifiers -#if 0 - if (len == 3 || - bytes[0] == B_SPACE || bytes[0] == B_TAB || - bytes[0] == B_RETURN || bytes[0] == '\r' || - bytes[0] == B_ESCAPE) -#else - if (canHaveVimModifiers) -#endif - { - int modifiers; - modifiers = 0; - if (beModifiers & B_SHIFT_KEY) - modifiers |= MOD_MASK_SHIFT; - if (beModifiers & B_CONTROL_KEY) - modifiers |= MOD_MASK_CTRL; - if (beModifiers & B_OPTION_KEY) - modifiers |= MOD_MASK_ALT; + if (modifiers) + { + *dest++ = CSI; + *dest++ = KS_MODIFIER; + *dest++ = modifiers; + km.length = 3; + } + } + memcpy((char *)dest, string, len); + km.length += len; + km.csi_escape = false; + } - /* - * For some keys a shift modifier is translated into another key - * code. Do we need to handle the case where len != 1 and - * string[0] != CSI? (Not for BeOS, since len == 3 implies - * string[0] == CSI...) - */ - int key; - if (string[0] == CSI && len == 3) - key = TO_SPECIAL(string[1], string[2]); - else - key = string[0]; - key = simplify_key(key, &modifiers); - if (IS_SPECIAL(key)) - { - string[0] = CSI; - string[1] = K_SECOND(key); - string[2] = K_THIRD(key); - len = 3; - } - else - { - string[0] = key; - len = 1; - } + write_port(gui.vdcmp, VimMsg::Key, &km, sizeof(km)); - if (modifiers) - { - *dest++ = CSI; - *dest++ = KS_MODIFIER; - *dest++ = modifiers; - km.length = 3; - } - } - memcpy((char *)dest, string, len); - km.length += len; - km.csi_escape = false; - } - - write_port(gui.vdcmp, VimMsg::Key, &km, sizeof(km)); - - /* - * blank out the pointer if necessary - */ - if (p_mh && !gui.pointer_hidden) - { - guiBlankMouse(true); - gui.pointer_hidden = TRUE; - } + /* + * blank out the pointer if necessary + */ + if (p_mh && !gui.pointer_hidden) + { + guiBlankMouse(true); + gui.pointer_hidden = TRUE; + } } void VimTextAreaView::guiSendMouseEvent( - int button, - int x, - int y, - int repeated_click, - int_u modifiers) + int button, + int x, + int y, + int repeated_click, + int_u modifiers) { - VimMouseMsg mm; + VimMouseMsg mm; - mm.button = button; - mm.x = x; - mm.y = y; - mm.repeated_click = repeated_click; - mm.modifiers = modifiers; + mm.button = button; + mm.x = x; + mm.y = y; + mm.repeated_click = repeated_click; + mm.modifiers = modifiers; - write_port(gui.vdcmp, VimMsg::Mouse, &mm, sizeof(mm)); - // calls gui_send_mouse_event() + write_port(gui.vdcmp, VimMsg::Mouse, &mm, sizeof(mm)); + // calls gui_send_mouse_event() - /* - * if our pointer is currently hidden, then we should show it. - */ - if (gui.pointer_hidden) - { - guiBlankMouse(false); - gui.pointer_hidden = FALSE; - } + /* + * if our pointer is currently hidden, then we should show it. + */ + if (gui.pointer_hidden) + { + guiBlankMouse(false); + gui.pointer_hidden = FALSE; + } } void VimTextAreaView::guiMouseMoved( - int x, - int y) + int x, + int y) { - VimMouseMovedMsg mm; + VimMouseMovedMsg mm; - mm.x = x; - mm.y = y; + mm.x = x; + mm.y = y; - write_port(gui.vdcmp, VimMsg::MouseMoved, &mm, sizeof(mm)); + write_port(gui.vdcmp, VimMsg::MouseMoved, &mm, sizeof(mm)); - if (gui.pointer_hidden) - { - guiBlankMouse(false); - gui.pointer_hidden = FALSE; - } + if (gui.pointer_hidden) + { + guiBlankMouse(false); + gui.pointer_hidden = FALSE; + } } - void + void VimTextAreaView::guiBlankMouse(bool should_hide) { - if (should_hide) { - // gui.vimApp->HideCursor(); - gui.vimApp->ObscureCursor(); - /* - * ObscureCursor() would even be easier, but then - * Vim's idea of mouse visibility does not necessarily - * correspond to reality. - */ - } else { - // gui.vimApp->ShowCursor(); - } + if (should_hide) { + // gui.vimApp->HideCursor(); + gui.vimApp->ObscureCursor(); + /* + * ObscureCursor() would even be easier, but then + * Vim's idea of mouse visibility does not necessarily + * correspond to reality. + */ + } else { + // gui.vimApp->ShowCursor(); + } } - int_u + int_u VimTextAreaView::mouseModifiersToVim(int32 beModifiers) { - int_u vim_modifiers = 0x0; + int_u vim_modifiers = 0x0; - if (beModifiers & B_SHIFT_KEY) - vim_modifiers |= MOUSE_SHIFT; - if (beModifiers & B_CONTROL_KEY) - vim_modifiers |= MOUSE_CTRL; - if (beModifiers & B_OPTION_KEY) // Alt or Meta key - vim_modifiers |= MOUSE_ALT; + if (beModifiers & B_SHIFT_KEY) + vim_modifiers |= MOUSE_SHIFT; + if (beModifiers & B_CONTROL_KEY) + vim_modifiers |= MOUSE_CTRL; + if (beModifiers & B_OPTION_KEY) // Alt or Meta key + vim_modifiers |= MOUSE_ALT; - return vim_modifiers; + return vim_modifiers; } - void + void VimTextAreaView::MouseDown(BPoint point) { - BMessage *m = Window()->CurrentMessage(); - assert(m); + BMessage *m = Window()->CurrentMessage(); + assert(m); - int32 buttons = 0; - m->FindInt32("buttons", &buttons); + int32 buttons = 0; + m->FindInt32("buttons", &buttons); - int vimButton; + int vimButton; - if (buttons & B_PRIMARY_MOUSE_BUTTON) - vimButton = MOUSE_LEFT; - else if (buttons & B_SECONDARY_MOUSE_BUTTON) - vimButton = MOUSE_RIGHT; - else if (buttons & B_TERTIARY_MOUSE_BUTTON) - vimButton = MOUSE_MIDDLE; - else - return; // Unknown button + if (buttons & B_PRIMARY_MOUSE_BUTTON) + vimButton = MOUSE_LEFT; + else if (buttons & B_SECONDARY_MOUSE_BUTTON) + vimButton = MOUSE_RIGHT; + else if (buttons & B_TERTIARY_MOUSE_BUTTON) + vimButton = MOUSE_MIDDLE; + else + return; // Unknown button - vimMouseButton = 1; // don't care which one + vimMouseButton = 1; // don't care which one - // Handle multiple clicks - int32 clicks = 0; - m->FindInt32("clicks", &clicks); + // Handle multiple clicks + int32 clicks = 0; + m->FindInt32("clicks", &clicks); - int32 modifiers = 0; - m->FindInt32("modifiers", &modifiers); + int32 modifiers = 0; + m->FindInt32("modifiers", &modifiers); - vimMouseModifiers = mouseModifiersToVim(modifiers); + vimMouseModifiers = mouseModifiersToVim(modifiers); - guiSendMouseEvent(vimButton, point.x, point.y, - clicks > 1 /* = repeated_click*/, vimMouseModifiers); + guiSendMouseEvent(vimButton, point.x, point.y, + clicks > 1 /* = repeated_click*/, vimMouseModifiers); } - void + void VimTextAreaView::MouseUp(BPoint point) { - vimMouseButton = 0; + vimMouseButton = 0; - BMessage *m = Window()->CurrentMessage(); - assert(m); - // m->PrintToStream(); + BMessage *m = Window()->CurrentMessage(); + assert(m); + // m->PrintToStream(); - int32 modifiers = 0; - m->FindInt32("modifiers", &modifiers); + int32 modifiers = 0; + m->FindInt32("modifiers", &modifiers); - vimMouseModifiers = mouseModifiersToVim(modifiers); + vimMouseModifiers = mouseModifiersToVim(modifiers); - guiSendMouseEvent(MOUSE_RELEASE, point.x, point.y, - 0 /* = repeated_click*/, vimMouseModifiers); + guiSendMouseEvent(MOUSE_RELEASE, point.x, point.y, + 0 /* = repeated_click*/, vimMouseModifiers); - Inherited::MouseUp(point); + Inherited::MouseUp(point); } - void + void VimTextAreaView::MouseMoved(BPoint point, uint32 transit, const BMessage *message) { - /* - * if our pointer is currently hidden, then we should show it. - */ - if (gui.pointer_hidden) - { - guiBlankMouse(false); - gui.pointer_hidden = FALSE; - } + /* + * if our pointer is currently hidden, then we should show it. + */ + if (gui.pointer_hidden) + { + guiBlankMouse(false); + gui.pointer_hidden = FALSE; + } - if (!vimMouseButton) { // could also check m->"buttons" - guiMouseMoved(point.x, point.y); - return; - } + if (!vimMouseButton) { // could also check m->"buttons" + guiMouseMoved(point.x, point.y); + return; + } - atomic_add(&mouseDragEventCount, 1); + atomic_add(&mouseDragEventCount, 1); - // Don't care much about "transit" - guiSendMouseEvent(MOUSE_DRAG, point.x, point.y, 0, vimMouseModifiers); + // Don't care much about "transit" + guiSendMouseEvent(MOUSE_DRAG, point.x, point.y, 0, vimMouseModifiers); } - void + void VimTextAreaView::MessageReceived(BMessage *m) { - switch (m->what) { - case 'menu': - { - VimMenuMsg mm; - mm.guiMenu = NULL; // in case no pointer in msg - m->FindPointer("VimMenu", (void **)&mm.guiMenu); - write_port(gui.vdcmp, VimMsg::Menu, &mm, sizeof(mm)); - } - break; - case B_MOUSE_WHEEL_CHANGED: - { - VimScrollBar* scb = curwin->w_scrollbars[1].id; - float small=0, big=0, dy=0; - m->FindFloat("be:wheel_delta_y", &dy); - scb->GetSteps(&small, &big); - scb->SetValue(scb->Value()+small*dy*3); - scb->ValueChanged(scb->Value()); + switch (m->what) { + case 'menu': + { + VimMenuMsg mm; + mm.guiMenu = NULL; // in case no pointer in msg + m->FindPointer("VimMenu", (void **)&mm.guiMenu); + write_port(gui.vdcmp, VimMsg::Menu, &mm, sizeof(mm)); + } + break; + case B_MOUSE_WHEEL_CHANGED: + { + VimScrollBar* scb = curwin->w_scrollbars[1].id; + float small=0, big=0, dy=0; + m->FindFloat("be:wheel_delta_y", &dy); + scb->GetSteps(&small, &big); + scb->SetValue(scb->Value()+small*dy*3); + scb->ValueChanged(scb->Value()); #if 0 - scb = curwin->w_scrollbars[0].id; - scb->GetSteps(&small, &big); - scb->SetValue(scb->Value()+small*dy); - scb->ValueChanged(scb->Value()); + scb = curwin->w_scrollbars[0].id; + scb->GetSteps(&small, &big); + scb->SetValue(scb->Value()+small*dy); + scb->ValueChanged(scb->Value()); #endif - } - break; + } + break; #ifdef FEAT_MBYTE_IME - case B_INPUT_METHOD_EVENT: + case B_INPUT_METHOD_EVENT: + { + int32 opcode; + m->FindInt32("be:opcode", &opcode); + switch(opcode) + { + case B_INPUT_METHOD_STARTED: + if (!IMData.messenger) delete IMData.messenger; + IMData.messenger = new BMessenger(); + m->FindMessenger("be:reply_to", IMData.messenger); + break; + case B_INPUT_METHOD_CHANGED: { - int32 opcode; - m->FindInt32("be:opcode", &opcode); - switch(opcode) + BString str; + bool confirmed; + if (IMData.message) *(IMData.message) = *m; + else IMData.message = new BMessage(*m); + DrawIMString(); + m->FindBool("be:confirmed", &confirmed); + if (confirmed) + { + m->FindString("be:string", &str); + char_u *chars = (char_u*)str.String(); + struct VimKeyMsg km; + km.csi_escape = true; + int clen; + int i = 0; + while (i < str.Length()) { - case B_INPUT_METHOD_STARTED: - if(!IMData.messenger) delete IMData.messenger; - IMData.messenger = new BMessenger(); - m->FindMessenger("be:reply_to", IMData.messenger); - break; - case B_INPUT_METHOD_CHANGED: - { - BString str; - bool confirmed; - if(IMData.message) *(IMData.message) = *m; - else IMData.message = new BMessage(*m); - DrawIMString(); - m->FindBool("be:confirmed", &confirmed); - if (confirmed) - { - m->FindString("be:string", &str); - char_u *chars = (char_u*)str.String(); - struct VimKeyMsg km; - km.csi_escape = true; - int clen; - int i = 0; - while (i < str.Length()) - { - clen = utf_ptr2len(chars+i); - memcpy(km.chars, chars+i, clen); - km.length = clen; - write_port(gui.vdcmp, VimMsg::Key, &km, sizeof(km)); - i += clen; - } - } - } - break; - case B_INPUT_METHOD_LOCATION_REQUEST: - { - BMessage msg(B_INPUT_METHOD_EVENT); - msg.AddInt32("be:opcode", B_INPUT_METHOD_LOCATION_REQUEST); - msg.AddPoint("be:location_reply", IMData.location); - msg.AddFloat("be:height_reply", FILL_Y(1)); - IMData.messenger->SendMessage(&msg); - } - break; - case B_INPUT_METHOD_STOPPED: - delete IMData.messenger; - delete IMData.message; - IMData.messenger = NULL; - IMData.message = NULL; - break; + clen = utf_ptr2len(chars+i); + memcpy(km.chars, chars+i, clen); + km.length = clen; + write_port(gui.vdcmp, VimMsg::Key, &km, sizeof(km)); + i += clen; } - } - // TODO: sz: break here??? -#endif - default: - if (m->WasDropped()) { - BWindow *w = Window(); - w->DetachCurrentMessage(); - w->Minimize(false); - VimApp::SendRefs(m, (modifiers() & B_SHIFT_KEY) != 0); - } else { - Inherited::MessageReceived(m); + } } break; - } + case B_INPUT_METHOD_LOCATION_REQUEST: + { + BMessage msg(B_INPUT_METHOD_EVENT); + msg.AddInt32("be:opcode", B_INPUT_METHOD_LOCATION_REQUEST); + msg.AddPoint("be:location_reply", IMData.location); + msg.AddFloat("be:height_reply", FILL_Y(1)); + IMData.messenger->SendMessage(&msg); + } + break; + case B_INPUT_METHOD_STOPPED: + delete IMData.messenger; + delete IMData.message; + IMData.messenger = NULL; + IMData.message = NULL; + break; + } + } + // TODO: sz: break here??? +#endif + default: + if (m->WasDropped()) { + BWindow *w = Window(); + w->DetachCurrentMessage(); + w->Minimize(false); + VimApp::SendRefs(m, (modifiers() & B_SHIFT_KEY) != 0); + } else { + Inherited::MessageReceived(m); + } + break; + } } - int + int VimTextAreaView::mchInitFont(char_u *name) { - VimFont *newFont = (VimFont *)gui_mch_get_font(name, 1); - if(newFont != NOFONT) { - gui.norm_font = (GuiFont)newFont; - gui_mch_set_font((GuiFont)newFont); - if (name && STRCMP(name, "*") != 0) - hl_set_font_name(name); + VimFont *newFont = (VimFont *)gui_mch_get_font(name, 1); + if (newFont != NOFONT) { + gui.norm_font = (GuiFont)newFont; + gui_mch_set_font((GuiFont)newFont); + if (name && STRCMP(name, "*") != 0) + hl_set_font_name(name); - SetDrawingMode(B_OP_COPY); + SetDrawingMode(B_OP_COPY); - /* - * Try to load other fonts for bold, italic, and bold-italic. - * We should also try to work out what font to use for these when they are - * not specified by X resources, but we don't yet. - */ - return OK; - } - return FAIL; + /* + * Try to load other fonts for bold, italic, and bold-italic. + * We should also try to work out what font to use for these when they are + * not specified by X resources, but we don't yet. + */ + return OK; + } + return FAIL; } - void + void VimTextAreaView::mchDrawString(int row, int col, char_u *s, int len, int flags) { - /* - * First we must erase the area, because DrawString won't do - * that for us. XXX Most of the time this is a waste of effort - * since the bachground has been erased already... DRAW_TRANSP - * should be set when appropriate!!! - * (Rectangles include the bottom and right edge) - */ - if (!(flags & DRAW_TRANSP)) { - int cells; - cells = 0; - for(int i=0; iGetFont(&font); - if(!font.IsFixed()) - { - char* p = (char*)s; - int32 clen, lastpos = 0; - BPoint where; - int cells; - while((p - (char*)s) < len) { - clen = utf_ptr2len((u_char*)p); - where.Set(TEXT_X(col+lastpos), TEXT_Y(row)); - DrawString(p, clen, where); - if (flags & DRAW_BOLD) { - where.x += 1.0; - SetDrawingMode(B_OP_BLEND); - DrawString(p, clen, where); - SetDrawingMode(B_OP_COPY); - } - cells = utf_ptr2cells((char_u *)p); - if(cells<4) lastpos += cells; - else lastpos++; - p += clen; - } + BRect r(FILL_X(col), FILL_Y(row), + FILL_X(col + cells) - PEN_WIDTH, FILL_Y(row + 1) - PEN_WIDTH); + FillRect(r, B_SOLID_LOW); + } + + BFont font; + this->GetFont(&font); + if (!font.IsFixed()) + { + char* p = (char*)s; + int32 clen, lastpos = 0; + BPoint where; + int cells; + while ((p - (char*)s) < len) { + clen = utf_ptr2len((u_char*)p); + where.Set(TEXT_X(col+lastpos), TEXT_Y(row)); + DrawString(p, clen, where); + if (flags & DRAW_BOLD) { + where.x += 1.0; + SetDrawingMode(B_OP_BLEND); + DrawString(p, clen, where); + SetDrawingMode(B_OP_COPY); + } + cells = utf_ptr2cells((char_u *)p); + if (cells<4) lastpos += cells; + else lastpos++; + p += clen; } - else - { - BPoint where(TEXT_X(col), TEXT_Y(row)); - DrawString((char*)s, len, where); - if (flags & DRAW_BOLD) { - where.x += 1.0; - SetDrawingMode(B_OP_BLEND); - DrawString((char*)s, len, where); - SetDrawingMode(B_OP_COPY); - } + } + else + { + BPoint where(TEXT_X(col), TEXT_Y(row)); + DrawString((char*)s, len, where); + if (flags & DRAW_BOLD) { + where.x += 1.0; + SetDrawingMode(B_OP_BLEND); + DrawString((char*)s, len, where); + SetDrawingMode(B_OP_COPY); + } + } + + if (flags & DRAW_UNDERL) { + int cells; + cells = 0; + for (int i=0; iLock()) { - // Clear one column more for when bold has spilled over - CopyBits(source, dest); - gui_clear_block(gui.scroll_region_bot - num_lines + 1, - gui.scroll_region_left, - gui.scroll_region_bot, gui.scroll_region_right); + if (gui.vimWindow->Lock()) { + // Clear one column more for when bold has spilled over + CopyBits(source, dest); + gui_clear_block(gui.scroll_region_bot - num_lines + 1, + gui.scroll_region_left, + gui.scroll_region_bot, gui.scroll_region_right); - gui.vimWindow->Unlock(); - /* - * The Draw() callback will be called now if some of the source - * bits were not in the visible region. - */ - } - // gui_x11_check_copy_area(); - // } + gui.vimWindow->Unlock(); + /* + * The Draw() callback will be called now if some of the source + * bits were not in the visible region. + */ + } + // gui_x11_check_copy_area(); + // } } /* * mchInsertLines() Lock()s the window by itself. */ - void + void VimTextAreaView::mchInsertLines(int row, int num_lines) { - BRect source, dest; + BRect source, dest; - // XXX Attempt at a hack: - gui.vimWindow->UpdateIfNeeded(); - source.left = FILL_X(gui.scroll_region_left); - source.top = FILL_Y(row); - source.right = FILL_X(gui.scroll_region_right + 1) - PEN_WIDTH; - source.bottom = FILL_Y(gui.scroll_region_bot - num_lines + 1) - PEN_WIDTH; + // XXX Attempt at a hack: + gui.vimWindow->UpdateIfNeeded(); + source.left = FILL_X(gui.scroll_region_left); + source.top = FILL_Y(row); + source.right = FILL_X(gui.scroll_region_right + 1) - PEN_WIDTH; + source.bottom = FILL_Y(gui.scroll_region_bot - num_lines + 1) - PEN_WIDTH; - dest.left = FILL_X(gui.scroll_region_left); - dest.top = FILL_Y(row + num_lines); - dest.right = FILL_X(gui.scroll_region_right + 1) - PEN_WIDTH; - dest.bottom = FILL_Y(gui.scroll_region_bot + 1) - PEN_WIDTH; + dest.left = FILL_X(gui.scroll_region_left); + dest.top = FILL_Y(row + num_lines); + dest.right = FILL_X(gui.scroll_region_right + 1) - PEN_WIDTH; + dest.bottom = FILL_Y(gui.scroll_region_bot + 1) - PEN_WIDTH; - if (gui.vimWindow->Lock()) { - // Clear one column more for when bold has spilled over - CopyBits(source, dest); - gui_clear_block(row, gui.scroll_region_left, - row + num_lines - 1, gui.scroll_region_right); + if (gui.vimWindow->Lock()) { + // Clear one column more for when bold has spilled over + CopyBits(source, dest); + gui_clear_block(row, gui.scroll_region_left, + row + num_lines - 1, gui.scroll_region_right); - gui.vimWindow->Unlock(); - /* - * The Draw() callback will be called now if some of the source - * bits were not in the visible region. - * However, if we scroll too fast it can't keep up and the - * update region gets messed up. This seems to be because copying - * un-Draw()n bits does not generate Draw() calls for the copy... - * I moved the hack to before the CopyBits() to reduce the - * amount of additional waiting needed. - */ + gui.vimWindow->Unlock(); + /* + * The Draw() callback will be called now if some of the source + * bits were not in the visible region. + * However, if we scroll too fast it can't keep up and the + * update region gets messed up. This seems to be because copying + * un-Draw()n bits does not generate Draw() calls for the copy... + * I moved the hack to before the CopyBits() to reduce the + * amount of additional waiting needed. + */ - // gui_x11_check_copy_area(); + // gui_x11_check_copy_area(); - } + } } #ifdef FEAT_MBYTE_IME @@ -1855,67 +1855,67 @@ VimTextAreaView::mchInsertLines(int row, int num_lines) */ void VimTextAreaView::DrawIMString(void) { - static const rgb_color r_highlight = {255, 152, 152, 255}, - b_highlight = {152, 203, 255, 255}; - BString str; - const char* s; - int len; - BMessage* msg = IMData.message; - if (!msg) - return; - gui_redraw_block(IMData.row, 0, - IMData.row + IMData.count, W_WIDTH(curwin), GUI_MON_NOCLEAR); - bool confirmed = false; - msg->FindBool("be:confirmed", &confirmed); - if (confirmed) - return; - rgb_color hcolor = HighColor(), lcolor = LowColor(); - msg->FindString("be:string", &str); - s = str.String(); - len = str.Length(); - SetHighColor(0, 0, 0); - IMData.row = gui.row; - IMData.col = gui.col; - int32 sel_start = 0, sel_end = 0; - msg->FindInt32("be:selection", 0, &sel_start); - msg->FindInt32("be:selection", 1, &sel_end); - int clen, cn; - BPoint pos(IMData.col, 0); - BRect r; - BPoint where; - IMData.location = ConvertToScreen( - BPoint(FILL_X(pos.x), FILL_Y(IMData.row + pos.y))); - for (int i=0; iFindBool("be:confirmed", &confirmed); + if (confirmed) + return; + rgb_color hcolor = HighColor(), lcolor = LowColor(); + msg->FindString("be:string", &str); + s = str.String(); + len = str.Length(); + SetHighColor(0, 0, 0); + IMData.row = gui.row; + IMData.col = gui.col; + int32 sel_start = 0, sel_end = 0; + msg->FindInt32("be:selection", 0, &sel_start); + msg->FindInt32("be:selection", 1, &sel_end); + int clen, cn; + BPoint pos(IMData.col, 0); + BRect r; + BPoint where; + IMData.location = ConvertToScreen( + BPoint(FILL_X(pos.x), FILL_Y(IMData.row + pos.y))); + for (int i=0; i W_WIDTH(curwin)) { - cn = utf_ptr2cells((char_u *)(s+i)); - clen = utf_ptr2len((char_u *)(s+i)); - if (pos.x + cn > W_WIDTH(curwin)) - { - pos.y++; - pos.x = 0; - } - if (sel_start<=i && i= 0.0 && newValue == ignoreValue) { - ignoreValue = -1; - return; - } + if (ignoreValue >= 0.0 && newValue == ignoreValue) { ignoreValue = -1; - /* - * We want to throttle the amount of scroll messages generated. - * Normally I presume you won't get a new message before we've - * handled the previous one, but because we're passing them on this - * happens very quickly. So instead we keep a counter of how many - * scroll events there are (or will be) in the VDCMP, and the - * throttling happens at the receiving end. - */ - atomic_add(&scrollEventCount, 1); + return; + } + ignoreValue = -1; + /* + * We want to throttle the amount of scroll messages generated. + * Normally I presume you won't get a new message before we've + * handled the previous one, but because we're passing them on this + * happens very quickly. So instead we keep a counter of how many + * scroll events there are (or will be) in the VDCMP, and the + * throttling happens at the receiving end. + */ + atomic_add(&scrollEventCount, 1); - struct VimScrollBarMsg sm; + struct VimScrollBarMsg sm; - sm.sb = this; - sm.value = (long) newValue; - sm.stillDragging = TRUE; + sm.sb = this; + sm.value = (long) newValue; + sm.stillDragging = TRUE; - write_port(gui.vdcmp, VimMsg::ScrollBar, &sm, sizeof(sm)); + write_port(gui.vdcmp, VimMsg::ScrollBar, &sm, sizeof(sm)); - // calls gui_drag_scrollbar(sb, newValue, TRUE); + // calls gui_drag_scrollbar(sb, newValue, TRUE); } /* @@ -1980,733 +1980,733 @@ VimScrollBar::ValueChanged(float newValue) * is outside... This has some funny effects... XXX * So we do special processing when the window de/activates. */ - void + void VimScrollBar::MouseUp(BPoint where) { - // BMessage *m = Window()->CurrentMessage(); - // m->PrintToStream(); + // BMessage *m = Window()->CurrentMessage(); + // m->PrintToStream(); - atomic_add(&scrollEventCount, 1); + atomic_add(&scrollEventCount, 1); - struct VimScrollBarMsg sm; + struct VimScrollBarMsg sm; - sm.sb = this; - sm.value = (long) Value(); - sm.stillDragging = FALSE; + sm.sb = this; + sm.value = (long) Value(); + sm.stillDragging = FALSE; - write_port(gui.vdcmp, VimMsg::ScrollBar, &sm, sizeof(sm)); + write_port(gui.vdcmp, VimMsg::ScrollBar, &sm, sizeof(sm)); - // calls gui_drag_scrollbar(sb, newValue, FALSE); + // calls gui_drag_scrollbar(sb, newValue, FALSE); - Inherited::MouseUp(where); + Inherited::MouseUp(where); } - void + void VimScrollBar::SetValue(float newValue) { - if (newValue == Value()) - return; + if (newValue == Value()) + return; - ignoreValue = newValue; - Inherited::SetValue(newValue); + ignoreValue = newValue; + Inherited::SetValue(newValue); } // ---------------- VimFont ---------------- VimFont::VimFont(): BFont() { - init(); + init(); } VimFont::VimFont(const VimFont *rhs): BFont(rhs) { - init(); + init(); } VimFont::VimFont(const BFont *rhs): BFont(rhs) { - init(); + init(); } VimFont::VimFont(const VimFont &rhs): BFont(rhs) { - init(); + init(); } VimFont::~VimFont() { } - void + void VimFont::init() { - next = NULL; - refcount = 1; - name = NULL; + next = NULL; + refcount = 1; + name = NULL; } // ---------------- VimDialog ---------------- #if defined(FEAT_GUI_DIALOG) -const unsigned int kVimDialogButtonMsg = 'VMDB'; -const unsigned int kVimDialogIconStripeWidth = 30; -const unsigned int kVimDialogButtonsSpacingX = 9; -const unsigned int kVimDialogButtonsSpacingY = 4; -const unsigned int kVimDialogSpacingX = 6; -const unsigned int kVimDialogSpacingY = 10; -const unsigned int kVimDialogMinimalWidth = 310; -const unsigned int kVimDialogMinimalHeight = 75; -const BRect kDefaultRect = +const unsigned int kVimDialogButtonMsg = 'VMDB'; +const unsigned int kVimDialogIconStripeWidth = 30; +const unsigned int kVimDialogButtonsSpacingX = 9; +const unsigned int kVimDialogButtonsSpacingY = 4; +const unsigned int kVimDialogSpacingX = 6; +const unsigned int kVimDialogSpacingY = 10; +const unsigned int kVimDialogMinimalWidth = 310; +const unsigned int kVimDialogMinimalHeight = 75; +const BRect kDefaultRect = BRect(0, 0, kVimDialogMinimalWidth, kVimDialogMinimalHeight); VimDialog::VimDialog(int type, const char *title, const char *message, - const char *buttons, int dfltbutton, const char *textfield, int ex_cmd) + const char *buttons, int dfltbutton, const char *textfield, int ex_cmd) : BWindow(kDefaultRect, title, B_TITLED_WINDOW_LOOK, B_MODAL_APP_WINDOW_FEEL, - B_NOT_CLOSABLE | B_NOT_RESIZABLE | - B_NOT_ZOOMABLE | B_NOT_MINIMIZABLE | B_ASYNCHRONOUS_CONTROLS) - , fDialogSem(-1) - , fDialogValue(dfltbutton) - , fMessageView(NULL) - , fInputControl(NULL) - , fInputValue(textfield) + B_NOT_CLOSABLE | B_NOT_RESIZABLE | + B_NOT_ZOOMABLE | B_NOT_MINIMIZABLE | B_ASYNCHRONOUS_CONTROLS) + , fDialogSem(-1) + , fDialogValue(dfltbutton) + , fMessageView(NULL) + , fInputControl(NULL) + , fInputValue(textfield) { - // master view - VimDialog::View* view = new VimDialog::View(Bounds()); - if(view == NULL) - return; + // master view + VimDialog::View* view = new VimDialog::View(Bounds()); + if (view == NULL) + return; - if(title == NULL) - SetTitle("Vim " VIM_VERSION_MEDIUM); + if (title == NULL) + SetTitle("Vim " VIM_VERSION_MEDIUM); - AddChild(view); + AddChild(view); - // icon - view->InitIcon(type); + // icon + view->InitIcon(type); - // buttons - int32 which = 1; - float maxButtonWidth = 0; - float maxButtonHeight = 0; - float buttonsWidth = 0; - float buttonsHeight = 0; - BString strButtons(buttons); - strButtons.RemoveAll("&"); - do { - int32 end = strButtons.FindFirst('\n'); - if(end != B_ERROR) - strButtons.SetByteAt(end, '\0'); + // buttons + int32 which = 1; + float maxButtonWidth = 0; + float maxButtonHeight = 0; + float buttonsWidth = 0; + float buttonsHeight = 0; + BString strButtons(buttons); + strButtons.RemoveAll("&"); + do { + int32 end = strButtons.FindFirst('\n'); + if (end != B_ERROR) + strButtons.SetByteAt(end, '\0'); - BButton *button = _CreateButton(which++, strButtons.String()); - view->AddChild(button); - fButtonsList.AddItem(button); + BButton *button = _CreateButton(which++, strButtons.String()); + view->AddChild(button); + fButtonsList.AddItem(button); - maxButtonWidth = max_c(maxButtonWidth, button->Bounds().Width()); - maxButtonHeight = max_c(maxButtonHeight, button->Bounds().Height()); - buttonsWidth += button->Bounds().Width(); - buttonsHeight += button->Bounds().Height(); + maxButtonWidth = max_c(maxButtonWidth, button->Bounds().Width()); + maxButtonHeight = max_c(maxButtonHeight, button->Bounds().Height()); + buttonsWidth += button->Bounds().Width(); + buttonsHeight += button->Bounds().Height(); - if(end == B_ERROR) - break; + if (end == B_ERROR) + break; - strButtons.Remove(0, end + 1); - } while(true); + strButtons.Remove(0, end + 1); + } while (true); - int32 buttonsCount = fButtonsList.CountItems(); - buttonsWidth += kVimDialogButtonsSpacingX * (buttonsCount - 1); - buttonsHeight += kVimDialogButtonsSpacingY * (buttonsCount - 1); - float dialogWidth = buttonsWidth + kVimDialogIconStripeWidth + - kVimDialogSpacingX * 2; - float dialogHeight = maxButtonHeight + kVimDialogSpacingY * 3; + int32 buttonsCount = fButtonsList.CountItems(); + buttonsWidth += kVimDialogButtonsSpacingX * (buttonsCount - 1); + buttonsHeight += kVimDialogButtonsSpacingY * (buttonsCount - 1); + float dialogWidth = buttonsWidth + kVimDialogIconStripeWidth + + kVimDialogSpacingX * 2; + float dialogHeight = maxButtonHeight + kVimDialogSpacingY * 3; - // Check 'v' flag in 'guioptions': vertical button placement. - bool vertical = (vim_strchr(p_go, GO_VERTICAL) != NULL) || - dialogWidth >= gui.vimWindow->Bounds().Width(); - if(vertical) { - dialogWidth -= buttonsWidth; - dialogWidth += maxButtonWidth; - dialogHeight -= maxButtonHeight; - dialogHeight += buttonsHeight; - } - - dialogWidth = max_c(dialogWidth, kVimDialogMinimalWidth); - - // message view - BRect rect(0, 0, dialogWidth, 0); - rect.left += kVimDialogIconStripeWidth + 16 + kVimDialogSpacingX; - rect.top += kVimDialogSpacingY; - rect.right -= kVimDialogSpacingX; - rect.bottom = rect.top; - fMessageView = new BTextView(rect, "_tv_", rect.OffsetByCopy(B_ORIGIN), - B_FOLLOW_LEFT | B_FOLLOW_TOP, B_WILL_DRAW); - - fMessageView->SetViewColor(ui_color(B_PANEL_BACKGROUND_COLOR)); - rgb_color textColor = ui_color(B_PANEL_TEXT_COLOR); - fMessageView->SetFontAndColor(be_plain_font, B_FONT_ALL, &textColor); - fMessageView->SetText(message); - fMessageView->MakeEditable(false); - fMessageView->MakeSelectable(false); - fMessageView->SetWordWrap(true); - AddChild(fMessageView); - - float messageHeight = fMessageView->TextHeight(0, fMessageView->CountLines()); - fMessageView->ResizeBy(0, messageHeight); - fMessageView->SetTextRect(BRect(0, 0, rect.Width(), messageHeight)); - - dialogHeight += messageHeight; - - // input view - if(fInputValue != NULL) { - rect.top = - rect.bottom += messageHeight + kVimDialogSpacingY; - fInputControl = new BTextControl(rect, "_iv_", NULL, fInputValue, NULL, - B_FOLLOW_LEFT | B_FOLLOW_TOP, B_WILL_DRAW | B_NAVIGABLE | B_PULSE_NEEDED); - fInputControl->TextView()->SetText(fInputValue); - fInputControl->TextView()->SetWordWrap(false); - AddChild(fInputControl); - - float width = 0.f, height = 0.f; - fInputControl->GetPreferredSize(&width, &height); - fInputControl->MakeFocus(true); - - dialogHeight += height + kVimDialogSpacingY * 1.5; - } - - dialogHeight = max_c(dialogHeight, kVimDialogMinimalHeight); - - ResizeTo(dialogWidth, dialogHeight); - MoveTo((gui.vimWindow->Bounds().Width() - dialogWidth) / 2, - (gui.vimWindow->Bounds().Height() - dialogHeight) / 2); - - // adjust layout of buttons - float buttonWidth = max_c(maxButtonWidth, rect.Width() * 0.66); - BPoint origin(dialogWidth, dialogHeight); - origin.x -= kVimDialogSpacingX + (vertical ? buttonWidth : buttonsWidth); - origin.y -= kVimDialogSpacingY + (vertical ? buttonsHeight : maxButtonHeight); - - for(int32 i = 0 ; i < buttonsCount; i++) { - BButton *button = (BButton*)fButtonsList.ItemAt(i); - button->MoveTo(origin); - if(vertical) { - origin.y += button->Frame().Height() + kVimDialogButtonsSpacingY; - button->ResizeTo(buttonWidth, button->Frame().Height()); - } else - origin.x += button->Frame().Width() + kVimDialogButtonsSpacingX; - - if(dfltbutton == i + 1) { - button->MakeDefault(true); - button->MakeFocus(fInputControl == NULL); - } + // Check 'v' flag in 'guioptions': vertical button placement. + bool vertical = (vim_strchr(p_go, GO_VERTICAL) != NULL) || + dialogWidth >= gui.vimWindow->Bounds().Width(); + if (vertical) { + dialogWidth -= buttonsWidth; + dialogWidth += maxButtonWidth; + dialogHeight -= maxButtonHeight; + dialogHeight += buttonsHeight; + } + + dialogWidth = max_c(dialogWidth, kVimDialogMinimalWidth); + + // message view + BRect rect(0, 0, dialogWidth, 0); + rect.left += kVimDialogIconStripeWidth + 16 + kVimDialogSpacingX; + rect.top += kVimDialogSpacingY; + rect.right -= kVimDialogSpacingX; + rect.bottom = rect.top; + fMessageView = new BTextView(rect, "_tv_", rect.OffsetByCopy(B_ORIGIN), + B_FOLLOW_LEFT | B_FOLLOW_TOP, B_WILL_DRAW); + + fMessageView->SetViewColor(ui_color(B_PANEL_BACKGROUND_COLOR)); + rgb_color textColor = ui_color(B_PANEL_TEXT_COLOR); + fMessageView->SetFontAndColor(be_plain_font, B_FONT_ALL, &textColor); + fMessageView->SetText(message); + fMessageView->MakeEditable(false); + fMessageView->MakeSelectable(false); + fMessageView->SetWordWrap(true); + AddChild(fMessageView); + + float messageHeight = fMessageView->TextHeight(0, fMessageView->CountLines()); + fMessageView->ResizeBy(0, messageHeight); + fMessageView->SetTextRect(BRect(0, 0, rect.Width(), messageHeight)); + + dialogHeight += messageHeight; + + // input view + if (fInputValue != NULL) { + rect.top = + rect.bottom += messageHeight + kVimDialogSpacingY; + fInputControl = new BTextControl(rect, "_iv_", NULL, fInputValue, NULL, + B_FOLLOW_LEFT | B_FOLLOW_TOP, B_WILL_DRAW | B_NAVIGABLE | B_PULSE_NEEDED); + fInputControl->TextView()->SetText(fInputValue); + fInputControl->TextView()->SetWordWrap(false); + AddChild(fInputControl); + + float width = 0.f, height = 0.f; + fInputControl->GetPreferredSize(&width, &height); + fInputControl->MakeFocus(true); + + dialogHeight += height + kVimDialogSpacingY * 1.5; + } + + dialogHeight = max_c(dialogHeight, kVimDialogMinimalHeight); + + ResizeTo(dialogWidth, dialogHeight); + MoveTo((gui.vimWindow->Bounds().Width() - dialogWidth) / 2, + (gui.vimWindow->Bounds().Height() - dialogHeight) / 2); + + // adjust layout of buttons + float buttonWidth = max_c(maxButtonWidth, rect.Width() * 0.66); + BPoint origin(dialogWidth, dialogHeight); + origin.x -= kVimDialogSpacingX + (vertical ? buttonWidth : buttonsWidth); + origin.y -= kVimDialogSpacingY + (vertical ? buttonsHeight : maxButtonHeight); + + for (int32 i = 0 ; i < buttonsCount; i++) { + BButton *button = (BButton*)fButtonsList.ItemAt(i); + button->MoveTo(origin); + if (vertical) { + origin.y += button->Frame().Height() + kVimDialogButtonsSpacingY; + button->ResizeTo(buttonWidth, button->Frame().Height()); + } else + origin.x += button->Frame().Width() + kVimDialogButtonsSpacingX; + + if (dfltbutton == i + 1) { + button->MakeDefault(true); + button->MakeFocus(fInputControl == NULL); } + } } VimDialog::~VimDialog() { - if(fDialogSem > B_OK) - delete_sem(fDialogSem); + if (fDialogSem > B_OK) + delete_sem(fDialogSem); } - int + int VimDialog::Go() { - fDialogSem = create_sem(0, "VimDialogSem"); - if(fDialogSem < B_OK) { - Quit(); - return fDialogValue; - } + fDialogSem = create_sem(0, "VimDialogSem"); + if (fDialogSem < B_OK) { + Quit(); + return fDialogValue; + } - Show(); + Show(); - while(acquire_sem(fDialogSem) == B_INTERRUPTED); + while (acquire_sem(fDialogSem) == B_INTERRUPTED); - int retValue = fDialogValue; - if(fInputValue != NULL) - vim_strncpy((char_u*)fInputValue, (char_u*)fInputControl->Text(), IOSIZE - 1); + int retValue = fDialogValue; + if (fInputValue != NULL) + vim_strncpy((char_u*)fInputValue, (char_u*)fInputControl->Text(), IOSIZE - 1); - if(Lock()) - Quit(); + if (Lock()) + Quit(); - return retValue; + return retValue; } void VimDialog::MessageReceived(BMessage *msg) { - int32 which = 0; - if(msg->what != kVimDialogButtonMsg || - msg->FindInt32("which", &which) != B_OK) - return BWindow::MessageReceived(msg); + int32 which = 0; + if (msg->what != kVimDialogButtonMsg || + msg->FindInt32("which", &which) != B_OK) + return BWindow::MessageReceived(msg); - fDialogValue = which; - delete_sem(fDialogSem); - fDialogSem = -1; + fDialogValue = which; + delete_sem(fDialogSem); + fDialogSem = -1; } BButton* VimDialog::_CreateButton(int32 which, const char* label) { - BMessage *message = new BMessage(kVimDialogButtonMsg); - message->AddInt32("which", which); + BMessage *message = new BMessage(kVimDialogButtonMsg); + message->AddInt32("which", which); - BRect rect(0, 0, 0, 0); - BString name; - name << "_b" << which << "_"; + BRect rect(0, 0, 0, 0); + BString name; + name << "_b" << which << "_"; - BButton* button = new BButton(rect, name.String(), label, message, - B_FOLLOW_RIGHT | B_FOLLOW_BOTTOM); + BButton* button = new BButton(rect, name.String(), label, message, + B_FOLLOW_RIGHT | B_FOLLOW_BOTTOM); - float width = 0.f, height = 0.f; - button->GetPreferredSize(&width, &height); - button->ResizeTo(width, height); + float width = 0.f, height = 0.f; + button->GetPreferredSize(&width, &height); + button->ResizeTo(width, height); - return button; + return button; } VimDialog::View::View(BRect frame) - : BView(frame, "VimDialogView", B_FOLLOW_ALL_SIDES, B_WILL_DRAW), - fIconBitmap(NULL) + : BView(frame, "VimDialogView", B_FOLLOW_ALL_SIDES, B_WILL_DRAW), + fIconBitmap(NULL) { - SetViewColor(ui_color(B_PANEL_BACKGROUND_COLOR)); + SetViewColor(ui_color(B_PANEL_BACKGROUND_COLOR)); } VimDialog::View::~View() { - delete fIconBitmap; + delete fIconBitmap; } void VimDialog::View::Draw(BRect updateRect) { - BRect stripeRect = Bounds(); - stripeRect.right = kVimDialogIconStripeWidth; - SetHighColor(tint_color(ViewColor(), B_DARKEN_1_TINT)); - FillRect(stripeRect); + BRect stripeRect = Bounds(); + stripeRect.right = kVimDialogIconStripeWidth; + SetHighColor(tint_color(ViewColor(), B_DARKEN_1_TINT)); + FillRect(stripeRect); - if(fIconBitmap == NULL) - return; + if (fIconBitmap == NULL) + return; - SetDrawingMode(B_OP_ALPHA); - SetBlendingMode(B_PIXEL_ALPHA, B_ALPHA_OVERLAY); - DrawBitmapAsync(fIconBitmap, BPoint(18, 6)); + SetDrawingMode(B_OP_ALPHA); + SetBlendingMode(B_PIXEL_ALPHA, B_ALPHA_OVERLAY); + DrawBitmapAsync(fIconBitmap, BPoint(18, 6)); } void VimDialog::View::InitIcon(int32 type) { - if(type == VIM_GENERIC) - return; + if (type == VIM_GENERIC) + return; - BPath path; - status_t status = find_directory(B_BEOS_SERVERS_DIRECTORY, &path); - if(status != B_OK) { - fprintf(stderr, "Cannot retrieve app info:%s\n", strerror(status)); - return; - } + BPath path; + status_t status = find_directory(B_BEOS_SERVERS_DIRECTORY, &path); + if (status != B_OK) { + fprintf(stderr, "Cannot retrieve app info:%s\n", strerror(status)); + return; + } - path.Append("app_server"); + path.Append("app_server"); - BFile file(path.Path(), O_RDONLY); - if(file.InitCheck() != B_OK) { - fprintf(stderr, "App file assignment failed:%s\n", - strerror(file.InitCheck())); - return; - } + BFile file(path.Path(), O_RDONLY); + if (file.InitCheck() != B_OK) { + fprintf(stderr, "App file assignment failed:%s\n", + strerror(file.InitCheck())); + return; + } - BResources resources(&file); - if(resources.InitCheck() != B_OK) { - fprintf(stderr, "App server resources assignment failed:%s\n", - strerror(resources.InitCheck())); - return; - } + BResources resources(&file); + if (resources.InitCheck() != B_OK) { + fprintf(stderr, "App server resources assignment failed:%s\n", + strerror(resources.InitCheck())); + return; + } - const char *name = ""; - switch(type) { - case VIM_ERROR: name = "stop"; break; - case VIM_WARNING: name = "warn"; break; - case VIM_INFO: name = "info"; break; - case VIM_QUESTION: name = "idea"; break; - default: return; - } + const char *name = ""; + switch(type) { + case VIM_ERROR: name = "stop"; break; + case VIM_WARNING: name = "warn"; break; + case VIM_INFO: name = "info"; break; + case VIM_QUESTION: name = "idea"; break; + default: return; + } - int32 iconSize = 32; - fIconBitmap = new BBitmap(BRect(0, 0, iconSize - 1, iconSize - 1), 0, B_RGBA32); - if(fIconBitmap == NULL || fIconBitmap->InitCheck() != B_OK) { - fprintf(stderr, "Icon bitmap allocation failed:%s\n", - (fIconBitmap == NULL) ? "null" : strerror(fIconBitmap->InitCheck())); - return; - } + int32 iconSize = 32; + fIconBitmap = new BBitmap(BRect(0, 0, iconSize - 1, iconSize - 1), 0, B_RGBA32); + if (fIconBitmap == NULL || fIconBitmap->InitCheck() != B_OK) { + fprintf(stderr, "Icon bitmap allocation failed:%s\n", + (fIconBitmap == NULL) ? "null" : strerror(fIconBitmap->InitCheck())); + return; + } - size_t size = 0; - const uint8* iconData = NULL; - // try vector icon first? - iconData = (const uint8*)resources.LoadResource(B_VECTOR_ICON_TYPE, name, &size); - if(iconData != NULL && BIconUtils::GetVectorIcon(iconData, size, fIconBitmap) == B_OK) - return; + size_t size = 0; + const uint8* iconData = NULL; + // try vector icon first? + iconData = (const uint8*)resources.LoadResource(B_VECTOR_ICON_TYPE, name, &size); + if (iconData != NULL && BIconUtils::GetVectorIcon(iconData, size, fIconBitmap) == B_OK) + return; - // try bitmap icon now - iconData = (const uint8*)resources.LoadResource(B_LARGE_ICON_TYPE, name, &size); - if(iconData == NULL) { - fprintf(stderr, "Bitmap icon resource not found\n"); - delete fIconBitmap; - fIconBitmap = NULL; - return; - } + // try bitmap icon now + iconData = (const uint8*)resources.LoadResource(B_LARGE_ICON_TYPE, name, &size); + if (iconData == NULL) { + fprintf(stderr, "Bitmap icon resource not found\n"); + delete fIconBitmap; + fIconBitmap = NULL; + return; + } - if(fIconBitmap->ColorSpace() != B_CMAP8) - BIconUtils::ConvertFromCMAP8(iconData, iconSize, iconSize, iconSize, fIconBitmap); + if (fIconBitmap->ColorSpace() != B_CMAP8) + BIconUtils::ConvertFromCMAP8(iconData, iconSize, iconSize, iconSize, fIconBitmap); } -const unsigned int kVimDialogOKButtonMsg = 'FDOK'; -const unsigned int kVimDialogCancelButtonMsg = 'FDCN'; -const unsigned int kVimDialogSizeInputMsg = 'SICH'; -const unsigned int kVimDialogFamilySelectMsg = 'MSFM'; -const unsigned int kVimDialogStyleSelectMsg = 'MSST'; -const unsigned int kVimDialogSizeSelectMsg = 'MSSZ'; +const unsigned int kVimDialogOKButtonMsg = 'FDOK'; +const unsigned int kVimDialogCancelButtonMsg = 'FDCN'; +const unsigned int kVimDialogSizeInputMsg = 'SICH'; +const unsigned int kVimDialogFamilySelectMsg = 'MSFM'; +const unsigned int kVimDialogStyleSelectMsg = 'MSST'; +const unsigned int kVimDialogSizeSelectMsg = 'MSSZ'; VimSelectFontDialog::VimSelectFontDialog(font_family* family, font_style* style, float* size) : BWindow(kDefaultRect, "Font Selection", B_TITLED_WINDOW_LOOK, B_MODAL_APP_WINDOW_FEEL, - B_NOT_CLOSABLE | B_NOT_RESIZABLE | - B_NOT_ZOOMABLE | B_NOT_MINIMIZABLE | B_ASYNCHRONOUS_CONTROLS) - , fStatus(B_NO_INIT) - , fDialogSem(-1) - , fDialogValue(false) - , fFamily(family) - , fStyle(style) - , fSize(size) - , fFontSize(*size) - , fPreview(0) - , fFamiliesList(0) - , fStylesList(0) - , fSizesList(0) - , fSizesInput(0) + B_NOT_CLOSABLE | B_NOT_RESIZABLE | + B_NOT_ZOOMABLE | B_NOT_MINIMIZABLE | B_ASYNCHRONOUS_CONTROLS) + , fStatus(B_NO_INIT) + , fDialogSem(-1) + , fDialogValue(false) + , fFamily(family) + , fStyle(style) + , fSize(size) + , fFontSize(*size) + , fPreview(0) + , fFamiliesList(0) + , fStylesList(0) + , fSizesList(0) + , fSizesInput(0) { - strncpy(fFontFamily, *family, B_FONT_FAMILY_LENGTH); - strncpy(fFontStyle, *style, B_FONT_STYLE_LENGTH); + strncpy(fFontFamily, *family, B_FONT_FAMILY_LENGTH); + strncpy(fFontStyle, *style, B_FONT_STYLE_LENGTH); - // "client" area view - BBox *clientBox = new BBox(Bounds(), B_EMPTY_STRING, B_FOLLOW_ALL_SIDES, - B_WILL_DRAW | B_FRAME_EVENTS | B_NAVIGABLE_JUMP | B_PULSE_NEEDED, - B_PLAIN_BORDER); - AddChild(clientBox); + // "client" area view + BBox *clientBox = new BBox(Bounds(), B_EMPTY_STRING, B_FOLLOW_ALL_SIDES, + B_WILL_DRAW | B_FRAME_EVENTS | B_NAVIGABLE_JUMP | B_PULSE_NEEDED, + B_PLAIN_BORDER); + AddChild(clientBox); - // client view - BRect RC = clientBox->Bounds(); - RC.InsetBy(kVimDialogSpacingX, kVimDialogSpacingY); - BRect rc(RC.LeftTop(), RC.LeftTop()); + // client view + BRect RC = clientBox->Bounds(); + RC.InsetBy(kVimDialogSpacingX, kVimDialogSpacingY); + BRect rc(RC.LeftTop(), RC.LeftTop()); - // at first create all controls - fPreview = new BStringView(rc, "preview", "DejaVu Sans Mono"); - clientBox->AddChild(fPreview); + // at first create all controls + fPreview = new BStringView(rc, "preview", "DejaVu Sans Mono"); + clientBox->AddChild(fPreview); - BBox* boxDivider = new BBox(rc, B_EMPTY_STRING, - B_FOLLOW_NONE, B_WILL_DRAW, B_FANCY_BORDER); - clientBox->AddChild(boxDivider); + BBox* boxDivider = new BBox(rc, B_EMPTY_STRING, + B_FOLLOW_NONE, B_WILL_DRAW, B_FANCY_BORDER); + clientBox->AddChild(boxDivider); - BStringView *labelFamily = new BStringView(rc, "labelFamily", "Family:"); - clientBox->AddChild(labelFamily); - labelFamily->ResizeToPreferred(); + BStringView *labelFamily = new BStringView(rc, "labelFamily", "Family:"); + clientBox->AddChild(labelFamily); + labelFamily->ResizeToPreferred(); - BStringView *labelStyle = new BStringView(rc, "labelStyle", "Style:"); - clientBox->AddChild(labelStyle); - labelStyle->ResizeToPreferred(); + BStringView *labelStyle = new BStringView(rc, "labelStyle", "Style:"); + clientBox->AddChild(labelStyle); + labelStyle->ResizeToPreferred(); - BStringView *labelSize = new BStringView(rc, "labelSize", "Size:"); - clientBox->AddChild(labelSize); - labelSize->ResizeToPreferred(); + BStringView *labelSize = new BStringView(rc, "labelSize", "Size:"); + clientBox->AddChild(labelSize); + labelSize->ResizeToPreferred(); - fFamiliesList = new BListView(rc, "listFamily", - B_SINGLE_SELECTION_LIST, B_FOLLOW_ALL_SIDES); - BScrollView *scrollFamilies = new BScrollView("scrollFamily", - fFamiliesList, B_FOLLOW_LEFT_RIGHT, 0, false, true); - clientBox->AddChild(scrollFamilies); + fFamiliesList = new BListView(rc, "listFamily", + B_SINGLE_SELECTION_LIST, B_FOLLOW_ALL_SIDES); + BScrollView *scrollFamilies = new BScrollView("scrollFamily", + fFamiliesList, B_FOLLOW_LEFT_RIGHT, 0, false, true); + clientBox->AddChild(scrollFamilies); - fStylesList= new BListView(rc, "listStyles", - B_SINGLE_SELECTION_LIST, B_FOLLOW_ALL_SIDES); - BScrollView *scrollStyles = new BScrollView("scrollStyle", - fStylesList, B_FOLLOW_LEFT_RIGHT, 0, false, true); - clientBox->AddChild(scrollStyles); + fStylesList= new BListView(rc, "listStyles", + B_SINGLE_SELECTION_LIST, B_FOLLOW_ALL_SIDES); + BScrollView *scrollStyles = new BScrollView("scrollStyle", + fStylesList, B_FOLLOW_LEFT_RIGHT, 0, false, true); + clientBox->AddChild(scrollStyles); - fSizesInput = new BTextControl(rc, "inputSize", NULL, "???", - new BMessage(kVimDialogSizeInputMsg)); - clientBox->AddChild(fSizesInput); - fSizesInput->ResizeToPreferred(); + fSizesInput = new BTextControl(rc, "inputSize", NULL, "???", + new BMessage(kVimDialogSizeInputMsg)); + clientBox->AddChild(fSizesInput); + fSizesInput->ResizeToPreferred(); - fSizesList = new BListView(rc, "listSizes", - B_SINGLE_SELECTION_LIST, B_FOLLOW_ALL_SIDES); - BScrollView *scrollSizes = new BScrollView("scrollSize", - fSizesList, B_FOLLOW_LEFT_RIGHT, 0, false, true); - clientBox->AddChild(scrollSizes); + fSizesList = new BListView(rc, "listSizes", + B_SINGLE_SELECTION_LIST, B_FOLLOW_ALL_SIDES); + BScrollView *scrollSizes = new BScrollView("scrollSize", + fSizesList, B_FOLLOW_LEFT_RIGHT, 0, false, true); + clientBox->AddChild(scrollSizes); - BButton *buttonOK = new BButton(rc, "buttonOK", "OK", - new BMessage(kVimDialogOKButtonMsg)); - clientBox->AddChild(buttonOK); - buttonOK->ResizeToPreferred(); + BButton *buttonOK = new BButton(rc, "buttonOK", "OK", + new BMessage(kVimDialogOKButtonMsg)); + clientBox->AddChild(buttonOK); + buttonOK->ResizeToPreferred(); - BButton *buttonCancel = new BButton(rc, "buttonCancel", "Cancel", - new BMessage(kVimDialogCancelButtonMsg)); - clientBox->AddChild(buttonCancel); - buttonCancel->ResizeToPreferred(); + BButton *buttonCancel = new BButton(rc, "buttonCancel", "Cancel", + new BMessage(kVimDialogCancelButtonMsg)); + clientBox->AddChild(buttonCancel); + buttonCancel->ResizeToPreferred(); - // layout controls - float lineHeight = labelFamily->Bounds().Height(); - float previewHeight = lineHeight * 3; - float offsetYLabels = previewHeight + kVimDialogSpacingY; - float offsetYLists = offsetYLabels + lineHeight + kVimDialogSpacingY / 2; - float offsetYSizes = offsetYLists + fSizesInput->Bounds().Height() + kVimDialogSpacingY / 2; - float listsHeight = lineHeight * 9; - float offsetYButtons = offsetYLists + listsHeight + kVimDialogSpacingY; - float maxControlsHeight = offsetYButtons + buttonOK->Bounds().Height(); - float familiesWidth = labelFamily->Bounds().Width() * 5; - float offsetXStyles = familiesWidth + kVimDialogSpacingX; - float stylesWidth = labelStyle->Bounds().Width() * 4; - float offsetXSizes = offsetXStyles + stylesWidth + kVimDialogSpacingX; - float sizesWidth = labelSize->Bounds().Width() * 2; - float maxControlsWidth = offsetXSizes + sizesWidth; + // layout controls + float lineHeight = labelFamily->Bounds().Height(); + float previewHeight = lineHeight * 3; + float offsetYLabels = previewHeight + kVimDialogSpacingY; + float offsetYLists = offsetYLabels + lineHeight + kVimDialogSpacingY / 2; + float offsetYSizes = offsetYLists + fSizesInput->Bounds().Height() + kVimDialogSpacingY / 2; + float listsHeight = lineHeight * 9; + float offsetYButtons = offsetYLists + listsHeight + kVimDialogSpacingY; + float maxControlsHeight = offsetYButtons + buttonOK->Bounds().Height(); + float familiesWidth = labelFamily->Bounds().Width() * 5; + float offsetXStyles = familiesWidth + kVimDialogSpacingX; + float stylesWidth = labelStyle->Bounds().Width() * 4; + float offsetXSizes = offsetXStyles + stylesWidth + kVimDialogSpacingX; + float sizesWidth = labelSize->Bounds().Width() * 2; + float maxControlsWidth = offsetXSizes + sizesWidth; - ResizeTo(maxControlsWidth + kVimDialogSpacingX * 2, - maxControlsHeight + kVimDialogSpacingY * 2); + ResizeTo(maxControlsWidth + kVimDialogSpacingX * 2, + maxControlsHeight + kVimDialogSpacingY * 2); - BRect rcVim = gui.vimWindow->Frame(); - MoveTo(rcVim.left + (rcVim.Width() - Frame().Width()) / 2, - rcVim.top + (rcVim.Height() - Frame().Height()) / 2); + BRect rcVim = gui.vimWindow->Frame(); + MoveTo(rcVim.left + (rcVim.Width() - Frame().Width()) / 2, + rcVim.top + (rcVim.Height() - Frame().Height()) / 2); - fPreview->ResizeTo(maxControlsWidth, previewHeight); - fPreview->SetAlignment(B_ALIGN_CENTER); + fPreview->ResizeTo(maxControlsWidth, previewHeight); + fPreview->SetAlignment(B_ALIGN_CENTER); - boxDivider->MoveBy(0.f, previewHeight + kVimDialogSpacingY / 2); - boxDivider->ResizeTo(maxControlsWidth, 1.f); + boxDivider->MoveBy(0.f, previewHeight + kVimDialogSpacingY / 2); + boxDivider->ResizeTo(maxControlsWidth, 1.f); - labelFamily->MoveBy(0.f, offsetYLabels); - labelStyle->MoveBy(offsetXStyles, offsetYLabels); - labelSize->MoveBy(offsetXSizes, offsetYLabels); + labelFamily->MoveBy(0.f, offsetYLabels); + labelStyle->MoveBy(offsetXStyles, offsetYLabels); + labelSize->MoveBy(offsetXSizes, offsetYLabels); - // text control alignment issues - float insetX = fSizesInput->TextView()->Bounds().Width() - fSizesInput->Bounds().Width(); - float insetY = fSizesInput->TextView()->Bounds().Width() - fSizesInput->Bounds().Width(); + // text control alignment issues + float insetX = fSizesInput->TextView()->Bounds().Width() - fSizesInput->Bounds().Width(); + float insetY = fSizesInput->TextView()->Bounds().Width() - fSizesInput->Bounds().Width(); - scrollFamilies->MoveBy(0.f, offsetYLists); - scrollStyles->MoveBy(offsetXStyles, offsetYLists); - fSizesInput->MoveBy(offsetXSizes + insetX / 2, offsetYLists + insetY / 2); - scrollSizes->MoveBy(offsetXSizes, offsetYSizes); + scrollFamilies->MoveBy(0.f, offsetYLists); + scrollStyles->MoveBy(offsetXStyles, offsetYLists); + fSizesInput->MoveBy(offsetXSizes + insetX / 2, offsetYLists + insetY / 2); + scrollSizes->MoveBy(offsetXSizes, offsetYSizes); - fSizesInput->SetAlignment(B_ALIGN_CENTER, B_ALIGN_CENTER); + fSizesInput->SetAlignment(B_ALIGN_CENTER, B_ALIGN_CENTER); - scrollFamilies->ResizeTo(familiesWidth, listsHeight); - scrollStyles->ResizeTo(stylesWidth, listsHeight); - fSizesInput->ResizeTo(sizesWidth, fSizesInput->Bounds().Height()); - scrollSizes->ResizeTo(sizesWidth, - listsHeight - (offsetYSizes - offsetYLists)); + scrollFamilies->ResizeTo(familiesWidth, listsHeight); + scrollStyles->ResizeTo(stylesWidth, listsHeight); + fSizesInput->ResizeTo(sizesWidth, fSizesInput->Bounds().Height()); + scrollSizes->ResizeTo(sizesWidth, + listsHeight - (offsetYSizes - offsetYLists)); - buttonOK->MoveBy(maxControlsWidth - buttonOK->Bounds().Width(), offsetYButtons); - buttonCancel->MoveBy(maxControlsWidth - buttonOK->Bounds().Width() - - buttonCancel->Bounds().Width() - kVimDialogSpacingX, offsetYButtons); + buttonOK->MoveBy(maxControlsWidth - buttonOK->Bounds().Width(), offsetYButtons); + buttonCancel->MoveBy(maxControlsWidth - buttonOK->Bounds().Width() + - buttonCancel->Bounds().Width() - kVimDialogSpacingX, offsetYButtons); - // fill lists - int selIndex = -1; - int count = count_font_families(); - for (int i = 0; i < count; i++) { - font_family family; - if (get_font_family(i, &family ) == B_OK) { - fFamiliesList->AddItem(new BStringItem((const char*)family)); - if (strncmp(family, fFontFamily, B_FONT_FAMILY_LENGTH) == 0) - selIndex = i; - } + // fill lists + int selIndex = -1; + int count = count_font_families(); + for (int i = 0; i < count; i++) { + font_family family; + if (get_font_family(i, &family ) == B_OK) { + fFamiliesList->AddItem(new BStringItem((const char*)family)); + if (strncmp(family, fFontFamily, B_FONT_FAMILY_LENGTH) == 0) + selIndex = i; } + } - if (selIndex >= 0) { - fFamiliesList->Select(selIndex); - fFamiliesList->ScrollToSelection(); - } + if (selIndex >= 0) { + fFamiliesList->Select(selIndex); + fFamiliesList->ScrollToSelection(); + } - _UpdateFontStyles(); + _UpdateFontStyles(); - selIndex = -1; - for (int size = 8, index = 0; size <= 18; size++, index++) { - BString str; - str << size; - fSizesList->AddItem(new BStringItem(str)); - if (size == fFontSize) - selIndex = index; + selIndex = -1; + for (int size = 8, index = 0; size <= 18; size++, index++) { + BString str; + str << size; + fSizesList->AddItem(new BStringItem(str)); + if (size == fFontSize) + selIndex = index; - } + } - if (selIndex >= 0) { - fSizesList->Select(selIndex); - fSizesList->ScrollToSelection(); - } + if (selIndex >= 0) { + fSizesList->Select(selIndex); + fSizesList->ScrollToSelection(); + } - fFamiliesList->SetSelectionMessage(new BMessage(kVimDialogFamilySelectMsg)); - fStylesList->SetSelectionMessage(new BMessage(kVimDialogStyleSelectMsg)); - fSizesList->SetSelectionMessage(new BMessage(kVimDialogSizeSelectMsg)); - fSizesInput->SetModificationMessage(new BMessage(kVimDialogSizeInputMsg)); + fFamiliesList->SetSelectionMessage(new BMessage(kVimDialogFamilySelectMsg)); + fStylesList->SetSelectionMessage(new BMessage(kVimDialogStyleSelectMsg)); + fSizesList->SetSelectionMessage(new BMessage(kVimDialogSizeSelectMsg)); + fSizesInput->SetModificationMessage(new BMessage(kVimDialogSizeInputMsg)); - _UpdateSizeInputPreview(); - _UpdateFontPreview(); + _UpdateSizeInputPreview(); + _UpdateFontPreview(); - fStatus = B_OK; + fStatus = B_OK; } VimSelectFontDialog::~VimSelectFontDialog() { - _CleanList(fFamiliesList); - _CleanList(fStylesList); - _CleanList(fSizesList); + _CleanList(fFamiliesList); + _CleanList(fStylesList); + _CleanList(fSizesList); - if (fDialogSem > B_OK) - delete_sem(fDialogSem); + if (fDialogSem > B_OK) + delete_sem(fDialogSem); } - void + void VimSelectFontDialog::_CleanList(BListView* list) { - while(0 < list->CountItems()) - delete (dynamic_cast(list->RemoveItem((int32)0))); + while (0 < list->CountItems()) + delete (dynamic_cast(list->RemoveItem((int32)0))); } - bool + bool VimSelectFontDialog::Go() { - if (fStatus != B_OK) { - Quit(); - return NOFONT; - } + if (fStatus != B_OK) { + Quit(); + return NOFONT; + } - fDialogSem = create_sem(0, "VimFontSelectDialogSem"); - if(fDialogSem < B_OK) { - Quit(); - return fDialogValue; - } + fDialogSem = create_sem(0, "VimFontSelectDialogSem"); + if (fDialogSem < B_OK) { + Quit(); + return fDialogValue; + } - Show(); + Show(); - while(acquire_sem(fDialogSem) == B_INTERRUPTED); + while (acquire_sem(fDialogSem) == B_INTERRUPTED); - bool retValue = fDialogValue; + bool retValue = fDialogValue; - if(Lock()) - Quit(); + if (Lock()) + Quit(); - return retValue; + return retValue; } void VimSelectFontDialog::_UpdateFontStyles() { - _CleanList(fStylesList); + _CleanList(fStylesList); - int32 selIndex = -1; - int32 count = count_font_styles(fFontFamily); - for (int32 i = 0; i < count; i++) { - font_style style; - uint32 flags = 0; - if (get_font_style(fFontFamily, i, &style, &flags) == B_OK) { - fStylesList->AddItem(new BStringItem((const char*)style)); - if (strncmp(style, fFontStyle, B_FONT_STYLE_LENGTH) == 0) - selIndex = i; - } + int32 selIndex = -1; + int32 count = count_font_styles(fFontFamily); + for (int32 i = 0; i < count; i++) { + font_style style; + uint32 flags = 0; + if (get_font_style(fFontFamily, i, &style, &flags) == B_OK) { + fStylesList->AddItem(new BStringItem((const char*)style)); + if (strncmp(style, fFontStyle, B_FONT_STYLE_LENGTH) == 0) + selIndex = i; } + } - if (selIndex >= 0) { - fStylesList->Select(selIndex); - fStylesList->ScrollToSelection(); - } else - fStylesList->Select(0); + if (selIndex >= 0) { + fStylesList->Select(selIndex); + fStylesList->ScrollToSelection(); + } else + fStylesList->Select(0); } void VimSelectFontDialog::_UpdateSizeInputPreview() { - char buf[10] = {0}; - vim_snprintf(buf, sizeof(buf), (char*)"%.0f", fFontSize); - fSizesInput->SetText(buf); + char buf[10] = {0}; + vim_snprintf(buf, sizeof(buf), (char*)"%.0f", fFontSize); + fSizesInput->SetText(buf); } void VimSelectFontDialog::_UpdateFontPreview() { - BFont font; - fPreview->GetFont(&font); - font.SetSize(fFontSize); - font.SetFamilyAndStyle(fFontFamily, fFontStyle); - fPreview->SetFont(&font, B_FONT_FAMILY_AND_STYLE | B_FONT_SIZE); + BFont font; + fPreview->GetFont(&font); + font.SetSize(fFontSize); + font.SetFamilyAndStyle(fFontFamily, fFontStyle); + fPreview->SetFont(&font, B_FONT_FAMILY_AND_STYLE | B_FONT_SIZE); - BString str; - str << fFontFamily << " " << fFontStyle << ", " << (int)fFontSize << " pt."; - fPreview->SetText(str); + BString str; + str << fFontFamily << " " << fFontStyle << ", " << (int)fFontSize << " pt."; + fPreview->SetText(str); } - bool + bool VimSelectFontDialog::_UpdateFromListItem(BListView* list, char* text, int textSize) { - int32 index = list->CurrentSelection(); - if (index < 0) - return false; - BStringItem* item = (BStringItem*)list->ItemAt(index); - if (item == NULL) - return false; - strncpy(text, item->Text(), textSize); - return true; + int32 index = list->CurrentSelection(); + if (index < 0) + return false; + BStringItem* item = (BStringItem*)list->ItemAt(index); + if (item == NULL) + return false; + strncpy(text, item->Text(), textSize); + return true; } void VimSelectFontDialog::MessageReceived(BMessage *msg) { - switch (msg->what) { - case kVimDialogOKButtonMsg: - strncpy(*fFamily, fFontFamily, B_FONT_FAMILY_LENGTH); - strncpy(*fStyle, fFontStyle, B_FONT_STYLE_LENGTH); - *fSize = fFontSize; - fDialogValue = true; - case kVimDialogCancelButtonMsg: - delete_sem(fDialogSem); - fDialogSem = -1; - return; - case B_KEY_UP: - { - int32 key = 0; - if (msg->FindInt32("raw_char", &key) == B_OK - && key == B_ESCAPE) { - delete_sem(fDialogSem); - fDialogSem = -1; - } - } - break; + switch (msg->what) { + case kVimDialogOKButtonMsg: + strncpy(*fFamily, fFontFamily, B_FONT_FAMILY_LENGTH); + strncpy(*fStyle, fFontStyle, B_FONT_STYLE_LENGTH); + *fSize = fFontSize; + fDialogValue = true; + case kVimDialogCancelButtonMsg: + delete_sem(fDialogSem); + fDialogSem = -1; + return; + case B_KEY_UP: + { + int32 key = 0; + if (msg->FindInt32("raw_char", &key) == B_OK + && key == B_ESCAPE) { + delete_sem(fDialogSem); + fDialogSem = -1; + } + } + break; - case kVimDialogFamilySelectMsg: - if (_UpdateFromListItem(fFamiliesList, - fFontFamily, B_FONT_FAMILY_LENGTH)) { - _UpdateFontStyles(); - _UpdateFontPreview(); - } - break; - case kVimDialogStyleSelectMsg: - if (_UpdateFromListItem(fStylesList, - fFontStyle, B_FONT_STYLE_LENGTH)) - _UpdateFontPreview(); - break; - case kVimDialogSizeSelectMsg: - { - char buf[10] = {0}; - if (_UpdateFromListItem(fSizesList, buf, sizeof(buf))) { - float size = atof(buf); - if (size > 0.f) { - fFontSize = size; - _UpdateSizeInputPreview(); - _UpdateFontPreview(); - } - } - } - break; - case kVimDialogSizeInputMsg: - { - float size = atof(fSizesInput->Text()); - if (size > 0.f) { - fFontSize = size; - _UpdateFontPreview(); - } - } - break; - default: - break; - } - return BWindow::MessageReceived(msg); + case kVimDialogFamilySelectMsg: + if (_UpdateFromListItem(fFamiliesList, + fFontFamily, B_FONT_FAMILY_LENGTH)) { + _UpdateFontStyles(); + _UpdateFontPreview(); + } + break; + case kVimDialogStyleSelectMsg: + if (_UpdateFromListItem(fStylesList, + fFontStyle, B_FONT_STYLE_LENGTH)) + _UpdateFontPreview(); + break; + case kVimDialogSizeSelectMsg: + { + char buf[10] = {0}; + if (_UpdateFromListItem(fSizesList, buf, sizeof(buf))) { + float size = atof(buf); + if (size > 0.f) { + fFontSize = size; + _UpdateSizeInputPreview(); + _UpdateFontPreview(); + } + } + } + break; + case kVimDialogSizeInputMsg: + { + float size = atof(fSizesInput->Text()); + if (size > 0.f) { + fFontSize = size; + _UpdateFontPreview(); + } + } + break; + default: + break; + } + return BWindow::MessageReceived(msg); } #endif // FEAT_GUI_DIALOG @@ -2717,330 +2717,330 @@ void VimSelectFontDialog::MessageReceived(BMessage *msg) static BMessage * MenuMessage(vimmenu_T *menu); VimToolbar::VimToolbar(BRect frame, const char *name) : - BBox(frame, name, B_FOLLOW_LEFT | B_FOLLOW_TOP, B_WILL_DRAW | B_FRAME_EVENTS, B_PLAIN_BORDER) + BBox(frame, name, B_FOLLOW_LEFT | B_FOLLOW_TOP, B_WILL_DRAW | B_FRAME_EVENTS, B_PLAIN_BORDER) { } VimToolbar::~VimToolbar() { - int32 count = fButtonsList.CountItems(); - for(int32 i = 0; i < count; i++) - delete (BPictureButton*)fButtonsList.ItemAt(i); - fButtonsList.MakeEmpty(); + int32 count = fButtonsList.CountItems(); + for (int32 i = 0; i < count; i++) + delete (BPictureButton*)fButtonsList.ItemAt(i); + fButtonsList.MakeEmpty(); - delete normalButtonsBitmap; - delete grayedButtonsBitmap; - normalButtonsBitmap = NULL; - grayedButtonsBitmap = NULL; + delete normalButtonsBitmap; + delete grayedButtonsBitmap; + normalButtonsBitmap = NULL; + grayedButtonsBitmap = NULL; } - void + void VimToolbar::AttachedToWindow() { - BBox::AttachedToWindow(); + BBox::AttachedToWindow(); - SetViewColor(ui_color(B_PANEL_BACKGROUND_COLOR)); + SetViewColor(ui_color(B_PANEL_BACKGROUND_COLOR)); } - float + float VimToolbar::ToolbarHeight() const { - float size = NULL == normalButtonsBitmap ? 18. : normalButtonsBitmap->Bounds().Height(); - return size + ToolbarMargin * 2 + ButtonMargin * 2 + 1; + float size = NULL == normalButtonsBitmap ? 18. : normalButtonsBitmap->Bounds().Height(); + return size + ToolbarMargin * 2 + ButtonMargin * 2 + 1; } - bool + bool VimToolbar::ModifyBitmapToGrayed(BBitmap *bitmap) { - float height = bitmap->Bounds().Height(); - float width = bitmap->Bounds().Width(); + float height = bitmap->Bounds().Height(); + float width = bitmap->Bounds().Width(); - rgb_color *bits = (rgb_color*)bitmap->Bits(); - int32 pixels = bitmap->BitsLength() / 4; - for(int32 i = 0; i < pixels; i++) { - bits[i].red = bits[i].green = - bits[i].blue = ((uint32)bits[i].red + bits[i].green + bits[i].blue) / 3; - bits[i].alpha /= 4; - } + rgb_color *bits = (rgb_color*)bitmap->Bits(); + int32 pixels = bitmap->BitsLength() / 4; + for (int32 i = 0; i < pixels; i++) { + bits[i].red = bits[i].green = + bits[i].blue = ((uint32)bits[i].red + bits[i].green + bits[i].blue) / 3; + bits[i].alpha /= 4; + } - return true; + return true; } - bool + bool VimToolbar::PrepareButtonBitmaps() { - // first try to load potentially customized $VIRUNTIME/bitmaps/builtin-tools.png - normalButtonsBitmap = LoadVimBitmap("builtin-tools.png"); - if(normalButtonsBitmap == NULL) - // customized not found? dig application resources for "builtin-tools" one - normalButtonsBitmap = BTranslationUtils::GetBitmap(B_PNG_FORMAT, "builtin-tools"); + // first try to load potentially customized $VIRUNTIME/bitmaps/builtin-tools.png + normalButtonsBitmap = LoadVimBitmap("builtin-tools.png"); + if (normalButtonsBitmap == NULL) + // customized not found? dig application resources for "builtin-tools" one + normalButtonsBitmap = BTranslationUtils::GetBitmap(B_PNG_FORMAT, "builtin-tools"); - if(normalButtonsBitmap == NULL) - return false; + if (normalButtonsBitmap == NULL) + return false; - BMessage archive; - normalButtonsBitmap->Archive(&archive); + BMessage archive; + normalButtonsBitmap->Archive(&archive); - grayedButtonsBitmap = new BBitmap(&archive); - if(grayedButtonsBitmap == NULL) - return false; + grayedButtonsBitmap = new BBitmap(&archive); + if (grayedButtonsBitmap == NULL) + return false; - // modify grayed bitmap - ModifyBitmapToGrayed(grayedButtonsBitmap); + // modify grayed bitmap + ModifyBitmapToGrayed(grayedButtonsBitmap); - return true; + return true; } BBitmap *VimToolbar::LoadVimBitmap(const char* fileName) { - BBitmap *bitmap = NULL; + BBitmap *bitmap = NULL; - int mustfree = 0; - char_u* runtimePath = vim_getenv((char_u*)"VIMRUNTIME", &mustfree); - if(runtimePath != NULL && fileName != NULL) { - BString strPath((char*)runtimePath); - strPath << "/bitmaps/" << fileName; - bitmap = BTranslationUtils::GetBitmap(strPath.String()); - } + int mustfree = 0; + char_u* runtimePath = vim_getenv((char_u*)"VIMRUNTIME", &mustfree); + if (runtimePath != NULL && fileName != NULL) { + BString strPath((char*)runtimePath); + strPath << "/bitmaps/" << fileName; + bitmap = BTranslationUtils::GetBitmap(strPath.String()); + } - if(mustfree) - vim_free(runtimePath); + if (mustfree) + vim_free(runtimePath); - return bitmap; + return bitmap; } - bool + bool VimToolbar::GetPictureFromBitmap(BPicture *pictureTo, int32 index, BBitmap *bitmapFrom, bool pressed) { - float size = bitmapFrom->Bounds().Height() + 1.; + float size = bitmapFrom->Bounds().Height() + 1.; - BView view(BRect(0, 0, size, size), "", 0, 0); + BView view(BRect(0, 0, size, size), "", 0, 0); - AddChild(&view); - view.BeginPicture(pictureTo); + AddChild(&view); + view.BeginPicture(pictureTo); - view.SetHighColor(ui_color(B_PANEL_BACKGROUND_COLOR)); - view.FillRect(view.Bounds()); - view.SetDrawingMode(B_OP_OVER); + view.SetHighColor(ui_color(B_PANEL_BACKGROUND_COLOR)); + view.FillRect(view.Bounds()); + view.SetDrawingMode(B_OP_OVER); - BRect source(0, 0, size - 1, size - 1); - BRect destination(source); + BRect source(0, 0, size - 1, size - 1); + BRect destination(source); - source.OffsetBy(size * index, 0); - destination.OffsetBy(ButtonMargin, ButtonMargin); + source.OffsetBy(size * index, 0); + destination.OffsetBy(ButtonMargin, ButtonMargin); - view.DrawBitmap(bitmapFrom, source, destination); + view.DrawBitmap(bitmapFrom, source, destination); - if(pressed) { - rgb_color shineColor = ui_color(B_SHINE_COLOR); - rgb_color shadowColor = ui_color(B_SHADOW_COLOR); - size += ButtonMargin * 2 - 1; - view.BeginLineArray(4); - view.AddLine(BPoint(0, 0), BPoint(size, 0), shadowColor); - view.AddLine(BPoint(size, 0), BPoint(size, size), shineColor); - view.AddLine(BPoint(size, size), BPoint(0, size), shineColor); - view.AddLine(BPoint(0, size), BPoint(0, 0), shadowColor); - view.EndLineArray(); - } + if (pressed) { + rgb_color shineColor = ui_color(B_SHINE_COLOR); + rgb_color shadowColor = ui_color(B_SHADOW_COLOR); + size += ButtonMargin * 2 - 1; + view.BeginLineArray(4); + view.AddLine(BPoint(0, 0), BPoint(size, 0), shadowColor); + view.AddLine(BPoint(size, 0), BPoint(size, size), shineColor); + view.AddLine(BPoint(size, size), BPoint(0, size), shineColor); + view.AddLine(BPoint(0, size), BPoint(0, 0), shadowColor); + view.EndLineArray(); + } - view.EndPicture(); - RemoveChild(&view); + view.EndPicture(); + RemoveChild(&view); - return true; + return true; } - bool + bool VimToolbar::AddButton(int32 index, vimmenu_T *menu) { - BPictureButton *button = NULL; - if(!menu_is_separator(menu->name)) { - float size = normalButtonsBitmap ? - normalButtonsBitmap->Bounds().Height() + 1. + ButtonMargin * 2 : 18.; - BRect frame(0, 0, size, size); - BPicture pictureOn; - BPicture pictureOff; - BPicture pictureGray; + BPictureButton *button = NULL; + if (!menu_is_separator(menu->name)) { + float size = normalButtonsBitmap ? + normalButtonsBitmap->Bounds().Height() + 1. + ButtonMargin * 2 : 18.; + BRect frame(0, 0, size, size); + BPicture pictureOn; + BPicture pictureOff; + BPicture pictureGray; - if(menu->iconfile == NULL && menu->iconidx >= 0 && normalButtonsBitmap) { - GetPictureFromBitmap(&pictureOn, menu->iconidx, normalButtonsBitmap, true); - GetPictureFromBitmap(&pictureOff, menu->iconidx, normalButtonsBitmap, false); - GetPictureFromBitmap(&pictureGray, menu->iconidx, grayedButtonsBitmap, false); - } else { + if (menu->iconfile == NULL && menu->iconidx >= 0 && normalButtonsBitmap) { + GetPictureFromBitmap(&pictureOn, menu->iconidx, normalButtonsBitmap, true); + GetPictureFromBitmap(&pictureOff, menu->iconidx, normalButtonsBitmap, false); + GetPictureFromBitmap(&pictureGray, menu->iconidx, grayedButtonsBitmap, false); + } else { - char_u buffer[MAXPATHL] = {0}; - BBitmap *bitmap = NULL; + char_u buffer[MAXPATHL] = {0}; + BBitmap *bitmap = NULL; - if(menu->iconfile) { - gui_find_iconfile(menu->iconfile, buffer, (char*)"png"); - bitmap = BTranslationUtils::GetBitmap((char*)buffer); - } + if (menu->iconfile) { + gui_find_iconfile(menu->iconfile, buffer, (char*)"png"); + bitmap = BTranslationUtils::GetBitmap((char*)buffer); + } - if(bitmap == NULL && gui_find_bitmap(menu->name, buffer, (char*)"png") == OK) - bitmap = BTranslationUtils::GetBitmap((char*)buffer); + if (bitmap == NULL && gui_find_bitmap(menu->name, buffer, (char*)"png") == OK) + bitmap = BTranslationUtils::GetBitmap((char*)buffer); - if(bitmap == NULL) - bitmap = new BBitmap(BRect(0, 0, size, size), B_RGB32); + if (bitmap == NULL) + bitmap = new BBitmap(BRect(0, 0, size, size), B_RGB32); - GetPictureFromBitmap(&pictureOn, 0, bitmap, true); - GetPictureFromBitmap(&pictureOff, 0, bitmap, false); - ModifyBitmapToGrayed(bitmap); - GetPictureFromBitmap(&pictureGray, 0, bitmap, false); + GetPictureFromBitmap(&pictureOn, 0, bitmap, true); + GetPictureFromBitmap(&pictureOff, 0, bitmap, false); + ModifyBitmapToGrayed(bitmap); + GetPictureFromBitmap(&pictureGray, 0, bitmap, false); - delete bitmap; - } - - button = new BPictureButton(frame, (char*)menu->name, - &pictureOff, &pictureOn, MenuMessage(menu)); - - button->SetDisabledOn(&pictureGray); - button->SetDisabledOff(&pictureGray); - - button->SetTarget(gui.vimTextArea); - - AddChild(button); - - menu->button = button; + delete bitmap; } - bool result = fButtonsList.AddItem(button, index); - InvalidateLayout(); - return result; + button = new BPictureButton(frame, (char*)menu->name, + &pictureOff, &pictureOn, MenuMessage(menu)); + + button->SetDisabledOn(&pictureGray); + button->SetDisabledOff(&pictureGray); + + button->SetTarget(gui.vimTextArea); + + AddChild(button); + + menu->button = button; + } + + bool result = fButtonsList.AddItem(button, index); + InvalidateLayout(); + return result; } - bool + bool VimToolbar::RemoveButton(vimmenu_T *menu) { - if(menu->button) { - if(fButtonsList.RemoveItem(menu->button)) { - delete menu->button; - menu->button = NULL; - } + if (menu->button) { + if (fButtonsList.RemoveItem(menu->button)) { + delete menu->button; + menu->button = NULL; } - return true; + } + return true; } - bool + bool VimToolbar::GrayButton(vimmenu_T *menu, int grey) { - if(menu->button) { - int32 index = fButtonsList.IndexOf(menu->button); - if(index >= 0) - menu->button->SetEnabled(grey ? false : true); - } - return true; + if (menu->button) { + int32 index = fButtonsList.IndexOf(menu->button); + if (index >= 0) + menu->button->SetEnabled(grey ? false : true); + } + return true; } - void + void VimToolbar::InvalidateLayout() { - int32 offset = ToolbarMargin; - int32 count = fButtonsList.CountItems(); - for(int32 i = 0; i < count; i++) { - BPictureButton *button = (BPictureButton *)fButtonsList.ItemAt(i); - if(button) { - button->MoveTo(offset, ToolbarMargin); - offset += button->Bounds().Width() + ToolbarMargin; - } else - offset += ToolbarMargin * 3; - } + int32 offset = ToolbarMargin; + int32 count = fButtonsList.CountItems(); + for (int32 i = 0; i < count; i++) { + BPictureButton *button = (BPictureButton *)fButtonsList.ItemAt(i); + if (button) { + button->MoveTo(offset, ToolbarMargin); + offset += button->Bounds().Width() + ToolbarMargin; + } else + offset += ToolbarMargin * 3; + } } #endif /*FEAT_TOOLBAR*/ #if defined(FEAT_GUI_TABLINE) - float + float VimTabLine::TablineHeight() const { -// float size = NULL == normalButtonsBitmap ? 18. : normalButtonsBitmap->Bounds().Height(); -// return size + ToolbarMargin * 2 + ButtonMargin * 2 + 1; - return TabHeight(); // + ToolbarMargin; +// float size = NULL == normalButtonsBitmap ? 18. : normalButtonsBitmap->Bounds().Height(); +// return size + ToolbarMargin * 2 + ButtonMargin * 2 + 1; + return TabHeight(); // + ToolbarMargin; } void VimTabLine::MouseDown(BPoint point) { - if(!gui_mch_showing_tabline()) - return; + if (!gui_mch_showing_tabline()) + return; - BMessage *m = Window()->CurrentMessage(); - assert(m); + BMessage *m = Window()->CurrentMessage(); + assert(m); - int32 buttons = 0; - m->FindInt32("buttons", &buttons); + int32 buttons = 0; + m->FindInt32("buttons", &buttons); - int32 clicks = 0; - m->FindInt32("clicks", &clicks); + int32 clicks = 0; + m->FindInt32("clicks", &clicks); - int index = 0; // 0 means here - no tab found - for (int i = 0; i < CountTabs(); i++) { - if(TabFrame(i).Contains(point)) { - index = i + 1; // indexes are 1-based - break; - } + int index = 0; // 0 means here - no tab found + for (int i = 0; i < CountTabs(); i++) { + if (TabFrame(i).Contains(point)) { + index = i + 1; // indexes are 1-based + break; + } + } + + int event = -1; + + if ((buttons & B_PRIMARY_MOUSE_BUTTON) && clicks > 1) + // left button double click on - create new tab + event = TABLINE_MENU_NEW; + + else if (buttons & B_TERTIARY_MOUSE_BUTTON) + // middle button click - close the pointed tab + // or create new one in case empty space + event = index > 0 ? TABLINE_MENU_CLOSE : TABLINE_MENU_NEW; + + else if (buttons & B_SECONDARY_MOUSE_BUTTON) { + // right button click - show context menu + BPopUpMenu* popUpMenu = new BPopUpMenu("tabLineContextMenu", false, false); + popUpMenu->AddItem(new BMenuItem(_("Close tabi R"), new BMessage(TABLINE_MENU_CLOSE))); + popUpMenu->AddItem(new BMenuItem(_("New tab T"), new BMessage(TABLINE_MENU_NEW))); + popUpMenu->AddItem(new BMenuItem(_("Open tab..."), new BMessage(TABLINE_MENU_OPEN))); + + ConvertToScreen(&point); + BMenuItem* item = popUpMenu->Go(point); + if (item != NULL) { + event = item->Command(); } - int event = -1; + delete popUpMenu; - if ((buttons & B_PRIMARY_MOUSE_BUTTON) && clicks > 1) - // left button double click on - create new tab - event = TABLINE_MENU_NEW; + } else { + // default processing + BTabView::MouseDown(point); + return; + } - else if (buttons & B_TERTIARY_MOUSE_BUTTON) - // middle button click - close the pointed tab - // or create new one in case empty space - event = index > 0 ? TABLINE_MENU_CLOSE : TABLINE_MENU_NEW; + if (event < 0) + return; - else if (buttons & B_SECONDARY_MOUSE_BUTTON) { - // right button click - show context menu - BPopUpMenu* popUpMenu = new BPopUpMenu("tabLineContextMenu", false, false); - popUpMenu->AddItem(new BMenuItem(_("Close tabi R"), new BMessage(TABLINE_MENU_CLOSE))); - popUpMenu->AddItem(new BMenuItem(_("New tab T"), new BMessage(TABLINE_MENU_NEW))); - popUpMenu->AddItem(new BMenuItem(_("Open tab..."), new BMessage(TABLINE_MENU_OPEN))); - - ConvertToScreen(&point); - BMenuItem* item = popUpMenu->Go(point); - if (item != NULL) { - event = item->Command(); - } - - delete popUpMenu; - - } else { - // default processing - BTabView::MouseDown(point); - return; - } - - if (event < 0) - return; - - VimTablineMenuMsg tmm; - tmm.index = index; - tmm.event = event; - write_port(gui.vdcmp, VimMsg::TablineMenu, &tmm, sizeof(tmm)); + VimTablineMenuMsg tmm; + tmm.index = index; + tmm.event = event; + write_port(gui.vdcmp, VimMsg::TablineMenu, &tmm, sizeof(tmm)); } void VimTabLine::VimTab::Select(BView* owner) { - BTab::Select(owner); + BTab::Select(owner); - VimTabLine *tabLine = gui.vimForm->TabLine(); - if(tabLine != NULL) { + VimTabLine *tabLine = gui.vimForm->TabLine(); + if (tabLine != NULL) { - int32 i = 0; - for (; i < tabLine->CountTabs(); i++) - if(this == tabLine->TabAt(i)) - break; + int32 i = 0; + for (; i < tabLine->CountTabs(); i++) + if (this == tabLine->TabAt(i)) + break; -// printf("%d:%d:%s\n", i, tabLine->CountTabs(), tabLine->TabAt(i)->Label()); - if(i < tabLine->CountTabs()) { - VimTablineMsg tm; - tm.index = i + 1; - write_port(gui.vdcmp, VimMsg::Tabline, &tm, sizeof(tm)); - } +// printf("%d:%d:%s\n", i, tabLine->CountTabs(), tabLine->TabAt(i)->Label()); + if (i < tabLine->CountTabs()) { + VimTablineMsg tm; + tm.index = i + 1; + write_port(gui.vdcmp, VimMsg::Tabline, &tm, sizeof(tm)); } + } } #endif // defined(FEAT_GUI_TABLINE) @@ -3053,123 +3053,123 @@ key_map *keyMap; char *keyMapChars; int main_exitcode = 127; - status_t + status_t gui_haiku_process_event(bigtime_t timeout) { - struct VimMsg vm; - int32 what; - ssize_t size; + struct VimMsg vm; + int32 what; + ssize_t size; - size = read_port_etc(gui.vdcmp, &what, &vm, sizeof(vm), - B_TIMEOUT, timeout); + size = read_port_etc(gui.vdcmp, &what, &vm, sizeof(vm), + B_TIMEOUT, timeout); - if (size >= 0) { - switch (what) { - case VimMsg::Key: - { - char_u *string = vm.u.Key.chars; - int len = vm.u.Key.length; - if (len == 1 && string[0] == Ctrl_chr('C')) { - trash_input_buf(); - got_int = TRUE; - } + if (size >= 0) { + switch (what) { + case VimMsg::Key: + { + char_u *string = vm.u.Key.chars; + int len = vm.u.Key.length; + if (len == 1 && string[0] == Ctrl_chr('C')) { + trash_input_buf(); + got_int = TRUE; + } - if (vm.u.Key.csi_escape) + if (vm.u.Key.csi_escape) #ifndef FEAT_MBYTE_IME - { - int i; - char_u buf[2]; + { + int i; + char_u buf[2]; - for (i = 0; i < len; ++i) - { - add_to_input_buf(string + i, 1); - if (string[i] == CSI) - { - // Turn CSI into K_CSI. - buf[0] = KS_EXTRA; - buf[1] = (int)KE_CSI; - add_to_input_buf(buf, 2); - } - } - } + for (i = 0; i < len; ++i) + { + add_to_input_buf(string + i, 1); + if (string[i] == CSI) + { + // Turn CSI into K_CSI. + buf[0] = KS_EXTRA; + buf[1] = (int)KE_CSI; + add_to_input_buf(buf, 2); + } + } + } #else - add_to_input_buf_csi(string, len); + add_to_input_buf_csi(string, len); #endif - else - add_to_input_buf(string, len); - } - break; - case VimMsg::Resize: - gui_resize_shell(vm.u.NewSize.width, vm.u.NewSize.height); - break; - case VimMsg::ScrollBar: - { - /* - * If loads of scroll messages queue up, use only the last - * one. Always report when the scrollbar stops dragging. - * This is not perfect yet anyway: these events are queued - * yet again, this time in the keyboard input buffer. - */ - int32 oldCount = - atomic_add(&vm.u.Scroll.sb->scrollEventCount, -1); - if (oldCount <= 1 || !vm.u.Scroll.stillDragging) - gui_drag_scrollbar(vm.u.Scroll.sb->getGsb(), - vm.u.Scroll.value, vm.u.Scroll.stillDragging); - } - break; -#if defined(FEAT_MENU) - case VimMsg::Menu: - gui_menu_cb(vm.u.Menu.guiMenu); - break; -#endif - case VimMsg::Mouse: - { - int32 oldCount; - if (vm.u.Mouse.button == MOUSE_DRAG) - oldCount = - atomic_add(&gui.vimTextArea->mouseDragEventCount, -1); - else - oldCount = 0; - if (oldCount <= 1) - gui_send_mouse_event(vm.u.Mouse.button, vm.u.Mouse.x, - vm.u.Mouse.y, vm.u.Mouse.repeated_click, - vm.u.Mouse.modifiers); - } - break; - case VimMsg::MouseMoved: - { - gui_mouse_moved(vm.u.MouseMoved.x, vm.u.MouseMoved.y); - } - break; - case VimMsg::Focus: - gui.in_focus = vm.u.Focus.active; - // XXX Signal that scrollbar dragging has stopped? - // This is needed because we don't get a MouseUp if - // that happens while outside the window... :-( - if (gui.dragged_sb) { - gui.dragged_sb = SBAR_NONE; - } - // gui_update_cursor(TRUE, FALSE); - break; - case VimMsg::Refs: - ::RefsReceived(vm.u.Refs.message, vm.u.Refs.changedir); - break; - case VimMsg::Tabline: - send_tabline_event(vm.u.Tabline.index); - break; - case VimMsg::TablineMenu: - send_tabline_menu_event(vm.u.TablineMenu.index, vm.u.TablineMenu.event); - break; - default: - // unrecognised message, ignore it - break; + else + add_to_input_buf(string, len); } + break; + case VimMsg::Resize: + gui_resize_shell(vm.u.NewSize.width, vm.u.NewSize.height); + break; + case VimMsg::ScrollBar: + { + /* + * If loads of scroll messages queue up, use only the last + * one. Always report when the scrollbar stops dragging. + * This is not perfect yet anyway: these events are queued + * yet again, this time in the keyboard input buffer. + */ + int32 oldCount = + atomic_add(&vm.u.Scroll.sb->scrollEventCount, -1); + if (oldCount <= 1 || !vm.u.Scroll.stillDragging) + gui_drag_scrollbar(vm.u.Scroll.sb->getGsb(), + vm.u.Scroll.value, vm.u.Scroll.stillDragging); + } + break; +#if defined(FEAT_MENU) + case VimMsg::Menu: + gui_menu_cb(vm.u.Menu.guiMenu); + break; +#endif + case VimMsg::Mouse: + { + int32 oldCount; + if (vm.u.Mouse.button == MOUSE_DRAG) + oldCount = + atomic_add(&gui.vimTextArea->mouseDragEventCount, -1); + else + oldCount = 0; + if (oldCount <= 1) + gui_send_mouse_event(vm.u.Mouse.button, vm.u.Mouse.x, + vm.u.Mouse.y, vm.u.Mouse.repeated_click, + vm.u.Mouse.modifiers); + } + break; + case VimMsg::MouseMoved: + { + gui_mouse_moved(vm.u.MouseMoved.x, vm.u.MouseMoved.y); + } + break; + case VimMsg::Focus: + gui.in_focus = vm.u.Focus.active; + // XXX Signal that scrollbar dragging has stopped? + // This is needed because we don't get a MouseUp if + // that happens while outside the window... :-( + if (gui.dragged_sb) { + gui.dragged_sb = SBAR_NONE; + } + // gui_update_cursor(TRUE, FALSE); + break; + case VimMsg::Refs: + ::RefsReceived(vm.u.Refs.message, vm.u.Refs.changedir); + break; + case VimMsg::Tabline: + send_tabline_event(vm.u.Tabline.index); + break; + case VimMsg::TablineMenu: + send_tabline_menu_event(vm.u.TablineMenu.index, vm.u.TablineMenu.event); + break; + default: + // unrecognised message, ignore it + break; } + } - /* - * If size < B_OK, it is an error code. - */ - return size; + /* + * If size < B_OK, it is an error code. + */ + return size; } /* @@ -3185,42 +3185,42 @@ gui_haiku_process_event(bigtime_t timeout) * If there is no window, don't call Lock() but do succeed. */ - int + int vim_lock_screen() { - return !gui.vimWindow || gui.vimWindow->Lock(); + return !gui.vimWindow || gui.vimWindow->Lock(); } - void + void vim_unlock_screen() { - if (gui.vimWindow) - gui.vimWindow->Unlock(); + if (gui.vimWindow) + gui.vimWindow->Unlock(); } #define RUN_BAPPLICATION_IN_NEW_THREAD 0 #if RUN_BAPPLICATION_IN_NEW_THREAD - int32 + int32 run_vimapp(void *args) { - VimApp app(appsig); + VimApp app(appsig); - gui.vimApp = &app; - app.Run(); // Run until Quit() called + gui.vimApp = &app; + app.Run(); // Run until Quit() called - return 0; + return 0; } #else - int32 + int32 call_main(void *args) { - struct MainArgs *ma = (MainArgs *)args; + struct MainArgs *ma = (MainArgs *)args; - return main(ma->argc, ma->argv); + return main(ma->argc, ma->argv); } #endif @@ -3229,251 +3229,251 @@ call_main(void *args) * deleted from argv, and *argc is decremented accordingly. This is called * when vim is started, whether or not the GUI has been started. */ - void + void gui_mch_prepare( - int *argc, - char **argv) + int *argc, + char **argv) { - /* - * We don't have any command line arguments for the BeOS GUI yet, - * but this is an excellent place to create our Application object. - */ - if (!gui.vimApp) { - thread_info tinfo; - get_thread_info(find_thread(NULL), &tinfo); + /* + * We don't have any command line arguments for the BeOS GUI yet, + * but this is an excellent place to create our Application object. + */ + if (!gui.vimApp) { + thread_info tinfo; + get_thread_info(find_thread(NULL), &tinfo); - // May need the port very early on to process RefsReceived() - gui.vdcmp = create_port(B_MAX_PORT_COUNT, "vim VDCMP"); + // May need the port very early on to process RefsReceived() + gui.vdcmp = create_port(B_MAX_PORT_COUNT, "vim VDCMP"); #if RUN_BAPPLICATION_IN_NEW_THREAD - thread_id tid = spawn_thread(run_vimapp, "vim VimApp", - tinfo.priority, NULL); - if (tid >= B_OK) { - resume_thread(tid); - } else { - getout(1); - } + thread_id tid = spawn_thread(run_vimapp, "vim VimApp", + tinfo.priority, NULL); + if (tid >= B_OK) { + resume_thread(tid); + } else { + getout(1); + } #else - MainArgs ma = { *argc, argv }; - thread_id tid = spawn_thread(call_main, "vim main()", - tinfo.priority, &ma); - if (tid >= B_OK) { - VimApp app(appsig); + MainArgs ma = { *argc, argv }; + thread_id tid = spawn_thread(call_main, "vim main()", + tinfo.priority, &ma); + if (tid >= B_OK) { + VimApp app(appsig); - gui.vimApp = &app; - resume_thread(tid); - /* - * This is rather horrible. - * call_main will call main() again... - * There will be no infinite recursion since - * gui.vimApp is set now. - */ - app.Run(); // Run until Quit() called - // fprintf(stderr, "app.Run() returned...\n"); - status_t dummy_exitcode; - (void)wait_for_thread(tid, &dummy_exitcode); + gui.vimApp = &app; + resume_thread(tid); + /* + * This is rather horrible. + * call_main will call main() again... + * There will be no infinite recursion since + * gui.vimApp is set now. + */ + app.Run(); // Run until Quit() called + // fprintf(stderr, "app.Run() returned...\n"); + status_t dummy_exitcode; + (void)wait_for_thread(tid, &dummy_exitcode); - /* - * This path should be the normal one taken to exit Vim. - * The main() thread calls mch_exit() which calls - * gui_mch_exit() which terminates its thread. - */ - exit(main_exitcode); - } + /* + * This path should be the normal one taken to exit Vim. + * The main() thread calls mch_exit() which calls + * gui_mch_exit() which terminates its thread. + */ + exit(main_exitcode); + } #endif - } - // Don't fork() when starting the GUI. Spawned threads are not - // duplicated with a fork(). The result is a mess. - gui.dofork = FALSE; - /* - * XXX Try to determine whether we were started from - * the Tracker or the terminal. - * It would be nice to have this work, because the Tracker - * follows symlinks, so even if you double-click on gvim, - * when it is a link to vim it will still pass a command name - * of vim... - * We try here to see if stdin comes from /dev/null. If so, - * (or if there is an error, which should never happen) start the GUI. - * This does the wrong thing for vim - Run(); // Run() unlocks but does not show + gui.vimWindow->Run(); // Run() unlocks but does not show - // Get the colors from the "Normal" group (set in syntax.c or in a vimrc - // file) - set_normal_colors(); + // Get the colors from the "Normal" group (set in syntax.c or in a vimrc + // file) + set_normal_colors(); - /* - * Check that none of the colors are the same as the background color - */ - gui_check_colors(); + /* + * Check that none of the colors are the same as the background color + */ + gui_check_colors(); - // Get the colors for the highlight groups (gui_check_colors() might have - // changed them) - highlight_gui_started(); // re-init colors and fonts + // Get the colors for the highlight groups (gui_check_colors() might have + // changed them) + highlight_gui_started(); // re-init colors and fonts - gui_mch_new_colors(); // window must exist for this + gui_mch_new_colors(); // window must exist for this - return OK; + return OK; } /* * Called when the foreground or background color has been changed. */ - void + void gui_mch_new_colors() { - rgb_color rgb = GUI_TO_RGB(gui.back_pixel); + rgb_color rgb = GUI_TO_RGB(gui.back_pixel); - if (gui.vimWindow->Lock()) { - gui.vimForm->SetViewColor(rgb); - // Does this not have too much effect for those small rectangles? - gui.vimForm->Invalidate(); - gui.vimWindow->Unlock(); - } + if (gui.vimWindow->Lock()) { + gui.vimForm->SetViewColor(rgb); + // Does this not have too much effect for those small rectangles? + gui.vimForm->Invalidate(); + gui.vimWindow->Unlock(); + } } /* * Open the GUI window which was created by a call to gui_mch_init(). */ - int + int gui_mch_open() { - if (gui_win_x != -1 && gui_win_y != -1) - gui_mch_set_winpos(gui_win_x, gui_win_y); + if (gui_win_x != -1 && gui_win_y != -1) + gui_mch_set_winpos(gui_win_x, gui_win_y); - // Actually open the window - if (gui.vimWindow->Lock()) { - gui.vimWindow->Show(); - gui.vimWindow->Unlock(); - return OK; - } + // Actually open the window + if (gui.vimWindow->Lock()) { + gui.vimWindow->Show(); + gui.vimWindow->Unlock(); + return OK; + } - return FAIL; + return FAIL; } - void + void gui_mch_exit(int vim_exitcode) { - if (gui.vimWindow) { - thread_id tid = gui.vimWindow->Thread(); - gui.vimWindow->Lock(); - gui.vimWindow->Quit(); - // Wait until it is truely gone - int32 exitcode; - wait_for_thread(tid, &exitcode); - } - delete_port(gui.vdcmp); + if (gui.vimWindow) { + thread_id tid = gui.vimWindow->Thread(); + gui.vimWindow->Lock(); + gui.vimWindow->Quit(); + // Wait until it is truely gone + int32 exitcode; + wait_for_thread(tid, &exitcode); + } + delete_port(gui.vdcmp); #if !RUN_BAPPLICATION_IN_NEW_THREAD - /* - * We are in the main() thread - quit the App thread and - * quit ourselves (passing on the exitcode). Use a global since the - * value from exit_thread() is only used if wait_for_thread() is - * called in time (race condition). - */ + /* + * We are in the main() thread - quit the App thread and + * quit ourselves (passing on the exitcode). Use a global since the + * value from exit_thread() is only used if wait_for_thread() is + * called in time (race condition). + */ #endif - if (gui.vimApp) { - VimTextAreaView::guiBlankMouse(false); + if (gui.vimApp) { + VimTextAreaView::guiBlankMouse(false); - main_exitcode = vim_exitcode; + main_exitcode = vim_exitcode; #if RUN_BAPPLICATION_IN_NEW_THREAD - thread_id tid = gui.vimApp->Thread(); - int32 exitcode; - gui.vimApp->Lock(); - gui.vimApp->Quit(); - gui.vimApp->Unlock(); - wait_for_thread(tid, &exitcode); + thread_id tid = gui.vimApp->Thread(); + int32 exitcode; + gui.vimApp->Lock(); + gui.vimApp->Quit(); + gui.vimApp->Unlock(); + wait_for_thread(tid, &exitcode); #else - gui.vimApp->Lock(); - gui.vimApp->Quit(); - gui.vimApp->Unlock(); - // suicide - exit_thread(vim_exitcode); + gui.vimApp->Lock(); + gui.vimApp->Quit(); + gui.vimApp->Unlock(); + // suicide + exit_thread(vim_exitcode); #endif - } - // If we are somehow still here, let mch_exit() handle things. + } + // If we are somehow still here, let mch_exit() handle things. } /* * Get the position of the top left corner of the window. */ - int + int gui_mch_get_winpos(int *x, int *y) { - if (gui.vimWindow->Lock()) { - BRect r; - r = gui.vimWindow->Frame(); - gui.vimWindow->Unlock(); - *x = (int)r.left; - *y = (int)r.top; - return OK; - } - else - return FAIL; + if (gui.vimWindow->Lock()) { + BRect r; + r = gui.vimWindow->Frame(); + gui.vimWindow->Unlock(); + *x = (int)r.left; + *y = (int)r.top; + return OK; + } + else + return FAIL; } /* * Set the position of the top left corner of the window to the given * coordinates. */ - void + void gui_mch_set_winpos(int x, int y) { - if (gui.vimWindow->Lock()) { - gui.vimWindow->MoveTo(x, y); - gui.vimWindow->Unlock(); - } + if (gui.vimWindow->Lock()) { + gui.vimWindow->MoveTo(x, y); + gui.vimWindow->Unlock(); + } } /* @@ -3481,98 +3481,98 @@ gui_mch_set_winpos(int x, int y) */ void gui_mch_set_shellsize( - int width, - int height, - int min_width, - int min_height, - int base_width, - int base_height, - int direction) // TODO: utilize? + int width, + int height, + int min_width, + int min_height, + int base_width, + int base_height, + int direction) // TODO: utilize? { + /* + * We are basically given the size of the VimForm, if I understand + * correctly. Since it fills the window completely, this will also + * be the size of the window. + */ + if (gui.vimWindow->Lock()) { + gui.vimWindow->ResizeTo(width - PEN_WIDTH, height - PEN_WIDTH); + + // set size limits + float minWidth, maxWidth, minHeight, maxHeight; + + gui.vimWindow->GetSizeLimits(&minWidth, &maxWidth, + &minHeight, &maxHeight); + gui.vimWindow->SetSizeLimits(min_width, maxWidth, + min_height, maxHeight); + /* - * We are basically given the size of the VimForm, if I understand - * correctly. Since it fills the window completely, this will also - * be the size of the window. + * Set the resizing alignment depending on font size. */ - if (gui.vimWindow->Lock()) { - gui.vimWindow->ResizeTo(width - PEN_WIDTH, height - PEN_WIDTH); + gui.vimWindow->SetWindowAlignment( + B_PIXEL_ALIGNMENT, // window_alignment mode, + 1, // int32 h, + 0, // int32 hOffset = 0, + gui.char_width, // int32 width = 0, + base_width, // int32 widthOffset = 0, + 1, // int32 v = 0, + 0, // int32 vOffset = 0, + gui.char_height, // int32 height = 0, + base_height // int32 heightOffset = 0 + ); - // set size limits - float minWidth, maxWidth, minHeight, maxHeight; - - gui.vimWindow->GetSizeLimits(&minWidth, &maxWidth, - &minHeight, &maxHeight); - gui.vimWindow->SetSizeLimits(min_width, maxWidth, - min_height, maxHeight); - - /* - * Set the resizing alignment depending on font size. - */ - gui.vimWindow->SetWindowAlignment( - B_PIXEL_ALIGNMENT, // window_alignment mode, - 1, // int32 h, - 0, // int32 hOffset = 0, - gui.char_width, // int32 width = 0, - base_width, // int32 widthOffset = 0, - 1, // int32 v = 0, - 0, // int32 vOffset = 0, - gui.char_height, // int32 height = 0, - base_height // int32 heightOffset = 0 - ); - - gui.vimWindow->Unlock(); - } + gui.vimWindow->Unlock(); + } } void gui_mch_get_screen_dimensions( - int *screen_w, - int *screen_h) + int *screen_w, + int *screen_h) { - BRect frame; + BRect frame; - { - BScreen screen(gui.vimWindow); + { + BScreen screen(gui.vimWindow); - if (screen.IsValid()) { - frame = screen.Frame(); - } else { - frame.right = 640; - frame.bottom = 480; - } + if (screen.IsValid()) { + frame = screen.Frame(); + } else { + frame.right = 640; + frame.bottom = 480; } + } - // XXX approximations... - *screen_w = (int) frame.right - 2 * gui.scrollbar_width - 20; - *screen_h = (int) frame.bottom - gui.scrollbar_height + // XXX approximations... + *screen_w = (int) frame.right - 2 * gui.scrollbar_width - 20; + *screen_h = (int) frame.bottom - gui.scrollbar_height #ifdef FEAT_MENU - - gui.menu_height + - gui.menu_height #endif - - 30; + - 30; } void gui_mch_set_text_area_pos( - int x, - int y, - int w, - int h) + int x, + int y, + int w, + int h) { - if (!gui.vimTextArea) - return; + if (!gui.vimTextArea) + return; - if (gui.vimWindow->Lock()) { - gui.vimTextArea->MoveTo(x, y); - gui.vimTextArea->ResizeTo(w - PEN_WIDTH, h - PEN_WIDTH); + if (gui.vimWindow->Lock()) { + gui.vimTextArea->MoveTo(x, y); + gui.vimTextArea->ResizeTo(w - PEN_WIDTH, h - PEN_WIDTH); #ifdef FEAT_GUI_TABLINE - if(gui.vimForm->TabLine() != NULL) { - gui.vimForm->TabLine()->ResizeTo(w, gui.vimForm->TablineHeight()); - } + if (gui.vimForm->TabLine() != NULL) { + gui.vimForm->TabLine()->ResizeTo(w, gui.vimForm->TablineHeight()); + } #endif // FEAT_GUI_TABLINE - gui.vimWindow->Unlock(); - } + gui.vimWindow->Unlock(); + } } @@ -3582,115 +3582,115 @@ gui_mch_set_text_area_pos( void gui_mch_enable_scrollbar( - scrollbar_T *sb, - int flag) + scrollbar_T *sb, + int flag) { - VimScrollBar *vsb = sb->id; - if (gui.vimWindow->Lock()) { - /* - * This function is supposed to be idempotent, but Show()/Hide() - * is not. Therefore we test if they are needed. - */ - if (flag) { - if (vsb->IsHidden()) { - vsb->Show(); - } - } else { - if (!vsb->IsHidden()) { - vsb->Hide(); - } - } - gui.vimWindow->Unlock(); + VimScrollBar *vsb = sb->id; + if (gui.vimWindow->Lock()) { + /* + * This function is supposed to be idempotent, but Show()/Hide() + * is not. Therefore we test if they are needed. + */ + if (flag) { + if (vsb->IsHidden()) { + vsb->Show(); + } + } else { + if (!vsb->IsHidden()) { + vsb->Hide(); + } } + gui.vimWindow->Unlock(); + } } void gui_mch_set_scrollbar_thumb( - scrollbar_T *sb, - int val, - int size, - int max) + scrollbar_T *sb, + int val, + int size, + int max) { - if (gui.vimWindow->Lock()) { - VimScrollBar *s = sb->id; - if (max == 0) { - s->SetValue(0); - s->SetRange(0.0, 0.0); - } else { - s->SetProportion((float)size / (max + 1.0)); - s->SetSteps(1.0, size > 5 ? size - 2 : size); -#ifndef SCROLL_PAST_END // really only defined in gui.c... - max = max + 1 - size; + if (gui.vimWindow->Lock()) { + VimScrollBar *s = sb->id; + if (max == 0) { + s->SetValue(0); + s->SetRange(0.0, 0.0); + } else { + s->SetProportion((float)size / (max + 1.0)); + s->SetSteps(1.0, size > 5 ? size - 2 : size); +#ifndef SCROLL_PAST_END // really only defined in gui.c... + max = max + 1 - size; #endif - if (max < s->Value()) { - /* - * If the new maximum is lower than the current value, - * setting it would cause the value to be clipped and - * therefore a ValueChanged() call. - * We avoid this by setting the value first, because - * it presumably is <= max. - */ - s->SetValue(val); - s->SetRange(0.0, max); - } else { - /* - * In the other case, set the range first, since the - * new value might be higher than the current max. - */ - s->SetRange(0.0, max); - s->SetValue(val); - } - } - gui.vimWindow->Unlock(); + if (max < s->Value()) { + /* + * If the new maximum is lower than the current value, + * setting it would cause the value to be clipped and + * therefore a ValueChanged() call. + * We avoid this by setting the value first, because + * it presumably is <= max. + */ + s->SetValue(val); + s->SetRange(0.0, max); + } else { + /* + * In the other case, set the range first, since the + * new value might be higher than the current max. + */ + s->SetRange(0.0, max); + s->SetValue(val); + } } + gui.vimWindow->Unlock(); + } } void gui_mch_set_scrollbar_pos( - scrollbar_T *sb, - int x, - int y, - int w, - int h) + scrollbar_T *sb, + int x, + int y, + int w, + int h) { - if (gui.vimWindow->Lock()) { - BRect winb = gui.vimWindow->Bounds(); - float vsbx = x, vsby = y; - VimScrollBar *vsb = sb->id; - vsb->ResizeTo(w - PEN_WIDTH, h - PEN_WIDTH); - if(winb.right-(x+w)MoveTo(vsbx, vsby); - gui.vimWindow->Unlock(); - } + if (gui.vimWindow->Lock()) { + BRect winb = gui.vimWindow->Bounds(); + float vsbx = x, vsby = y; + VimScrollBar *vsb = sb->id; + vsb->ResizeTo(w - PEN_WIDTH, h - PEN_WIDTH); + if (winb.right-(x+w)MoveTo(vsbx, vsby); + gui.vimWindow->Unlock(); + } } void gui_mch_create_scrollbar( - scrollbar_T *sb, - int orient) // SBAR_VERT or SBAR_HORIZ + scrollbar_T *sb, + int orient) // SBAR_VERT or SBAR_HORIZ { - orientation posture = - (orient == SBAR_HORIZ) ? B_HORIZONTAL : B_VERTICAL; + orientation posture = + (orient == SBAR_HORIZ) ? B_HORIZONTAL : B_VERTICAL; - VimScrollBar *vsb = sb->id = new VimScrollBar(sb, posture); - if (gui.vimWindow->Lock()) { - vsb->SetTarget(gui.vimTextArea); - vsb->Hide(); - gui.vimForm->AddChild(vsb); - gui.vimWindow->Unlock(); - } + VimScrollBar *vsb = sb->id = new VimScrollBar(sb, posture); + if (gui.vimWindow->Lock()) { + vsb->SetTarget(gui.vimTextArea); + vsb->Hide(); + gui.vimForm->AddChild(vsb); + gui.vimWindow->Unlock(); + } } #if defined(FEAT_WINDOWS) || defined(FEAT_GUI_HAIKU) || defined(PROTO) void gui_mch_destroy_scrollbar( - scrollbar_T *sb) + scrollbar_T *sb) { - if (gui.vimWindow->Lock()) { - sb->id->RemoveSelf(); - delete sb->id; - gui.vimWindow->Unlock(); - } + if (gui.vimWindow->Lock()) { + sb->id->RemoveSelf(); + delete sb->id; + gui.vimWindow->Unlock(); + } } #endif @@ -3709,65 +3709,65 @@ gui_mch_is_blink_off(void) * This is a simple state machine: * BLINK_NONE not blinking at all * BLINK_OFF blinking, cursor is not shown - * BLINK_ON blinking, cursor is shown + * BLINK_ON blinking, cursor is shown */ #define BLINK_NONE 0 #define BLINK_OFF 1 #define BLINK_ON 2 -static int blink_state = BLINK_NONE; -static long_u blink_waittime = 700; -static long_u blink_ontime = 400; -static long_u blink_offtime = 250; -static int blink_timer = 0; +static int blink_state = BLINK_NONE; +static long_u blink_waittime = 700; +static long_u blink_ontime = 400; +static long_u blink_offtime = 250; +static int blink_timer = 0; void gui_mch_set_blinking( - long waittime, - long on, - long off) + long waittime, + long on, + long off) { - // TODO - blink_waittime = waittime; - blink_ontime = on; - blink_offtime = off; + // TODO + blink_waittime = waittime; + blink_ontime = on; + blink_offtime = off; } /* * Stop the cursor blinking. Show the cursor if it wasn't shown. */ - void + void gui_mch_stop_blink(int may_call_gui_update_cursor) { - // TODO - if (blink_timer != 0) - { - // XtRemoveTimeOut(blink_timer); - blink_timer = 0; - } - if (blink_state == BLINK_OFF) - gui_update_cursor(TRUE, FALSE); - blink_state = BLINK_NONE; + // TODO + if (blink_timer != 0) + { + // XtRemoveTimeOut(blink_timer); + blink_timer = 0; + } + if (blink_state == BLINK_OFF) + gui_update_cursor(TRUE, FALSE); + blink_state = BLINK_NONE; } /* * Start the cursor blinking. If it was already blinking, this restarts the * waiting time and shows the cursor. */ - void + void gui_mch_start_blink() { - // TODO - if (blink_timer != 0) - ;// XtRemoveTimeOut(blink_timer); - // Only switch blinking on if none of the times is zero - if (blink_waittime && blink_ontime && blink_offtime && gui.in_focus) - { - blink_timer = 1; // XtAppAddTimeOut(app_context, blink_waittime, - blink_state = BLINK_ON; - gui_update_cursor(TRUE, FALSE); - } + // TODO + if (blink_timer != 0) + ;// XtRemoveTimeOut(blink_timer); + // Only switch blinking on if none of the times is zero + if (blink_waittime && blink_ontime && blink_offtime && gui.in_focus) + { + blink_timer = 1; // XtAppAddTimeOut(app_context, blink_waittime, + blink_state = BLINK_ON; + gui_update_cursor(TRUE, FALSE); + } } /* @@ -3776,144 +3776,144 @@ gui_mch_start_blink() */ int gui_mch_init_font( - char_u *font_name, - int fontset) + char_u *font_name, + int fontset) { - if (gui.vimWindow->Lock()) - { - int rc = gui.vimTextArea->mchInitFont(font_name); - gui.vimWindow->Unlock(); + if (gui.vimWindow->Lock()) + { + int rc = gui.vimTextArea->mchInitFont(font_name); + gui.vimWindow->Unlock(); - return rc; - } + return rc; + } - return FAIL; + return FAIL; } - int + int gui_mch_adjust_charsize() { - return FAIL; + return FAIL; } - int + int gui_mch_font_dialog(font_family* family, font_style* style, float* size) { #if defined(FEAT_GUI_DIALOG) - // gui.vimWindow->Unlock(); - VimSelectFontDialog *dialog = new VimSelectFontDialog(family, style, size); - return dialog->Go(); + // gui.vimWindow->Unlock(); + VimSelectFontDialog *dialog = new VimSelectFontDialog(family, style, size); + return dialog->Go(); #else - return NOFONT; + return NOFONT; #endif // FEAT_GUI_DIALOG } GuiFont gui_mch_get_font( - char_u *name, - int giveErrorIfMissing) + char_u *name, + int giveErrorIfMissing) { - static VimFont *fontList = NULL; + static VimFont *fontList = NULL; - if (!gui.in_use) // can't do this when GUI not running - return NOFONT; + if (!gui.in_use) // can't do this when GUI not running + return NOFONT; - // storage for locally modified name; - const int buff_size = B_FONT_FAMILY_LENGTH + B_FONT_STYLE_LENGTH + 20; - static char font_name[buff_size] = {0}; - font_family family = {0}; - font_style style = {0}; - float size = 0.f; + // storage for locally modified name; + const int buff_size = B_FONT_FAMILY_LENGTH + B_FONT_STYLE_LENGTH + 20; + static char font_name[buff_size] = {0}; + font_family family = {0}; + font_style style = {0}; + float size = 0.f; - if (name == 0 && be_fixed_font == 0) { - if(giveErrorIfMissing) - semsg(_(e_font), name); - return NOFONT; + if (name == 0 && be_fixed_font == 0) { + if (giveErrorIfMissing) + semsg(_(e_font), name); + return NOFONT; + } + + bool useSelectGUI = false; + if (name != NULL) + if (STRCMP(name, "*") == 0) { + useSelectGUI = true; + STRNCPY(font_name, hl_get_font_name(), buff_size); + } else + STRNCPY(font_name, name, buff_size); + + if (font_name[0] == 0) { + be_fixed_font->GetFamilyAndStyle(&family, &style); + size = be_fixed_font->Size(); + vim_snprintf(font_name, buff_size, + (char*)"%s/%s/%.0f", family, style, size); + } + + // replace underscores with spaces + char* end = 0; + while (end = strchr((char *)font_name, '_')) + *end = ' '; + + // store the name before strtok corrupt the buffer ;-) + static char buff[buff_size] = {0}; + STRNCPY(buff, font_name, buff_size); + STRNCPY(family, strtok(buff, "/\0"), B_FONT_FAMILY_LENGTH); + char* style_s = strtok(0, "/\0"); + if (style_s != 0) + STRNCPY(style, style_s, B_FONT_STYLE_LENGTH); + size = atof((style_s != 0) ? strtok(0, "/\0") : "0"); + + if (useSelectGUI) { + if (gui_mch_font_dialog(&family, &style, &size) == NOFONT) + return FAIL; + // compose for further processing + vim_snprintf(font_name, buff_size, + (char*)"%s/%s/%.0f", family, style, size); + hl_set_font_name((char_u*)font_name); + + // Set guifont to the name of the selected font. + char_u* new_p_guifont = (char_u*)alloc(STRLEN(font_name) + 1); + if (new_p_guifont != NULL) { + STRCPY(new_p_guifont, font_name); + vim_free(p_guifont); + p_guifont = new_p_guifont; + // Replace spaces in the font name with underscores. + for ( ; *new_p_guifont; ++new_p_guifont) + if (*new_p_guifont == ' ') + *new_p_guifont = '_'; } + } - bool useSelectGUI = false; - if (name != NULL) - if (STRCMP(name, "*") == 0) { - useSelectGUI = true; - STRNCPY(font_name, hl_get_font_name(), buff_size); - } else - STRNCPY(font_name, name, buff_size); - - if (font_name[0] == 0) { - be_fixed_font->GetFamilyAndStyle(&family, &style); - size = be_fixed_font->Size(); - vim_snprintf(font_name, buff_size, - (char*)"%s/%s/%.0f", family, style, size); + VimFont *flp; + for (flp = fontList; flp; flp = flp->next) { + if (STRCMP(font_name, flp->name) == 0) { + flp->refcount++; + return (GuiFont)flp; } + } - // replace underscores with spaces - char* end = 0; - while (end = strchr((char *)font_name, '_')) - *end = ' '; + VimFont *font = new VimFont(); + font->name = vim_strsave((char_u*)font_name); - // store the name before strtok corrupt the buffer ;-) - static char buff[buff_size] = {0}; - STRNCPY(buff, font_name, buff_size); - STRNCPY(family, strtok(buff, "/\0"), B_FONT_FAMILY_LENGTH); - char* style_s = strtok(0, "/\0"); - if (style_s != 0) - STRNCPY(style, style_s, B_FONT_STYLE_LENGTH); - size = atof((style_s != 0) ? strtok(0, "/\0") : "0"); + if (count_font_styles(family) <= 0) { + if (giveErrorIfMissing) + semsg(_(e_font), font->name); + delete font; + return NOFONT; + } - if (useSelectGUI) { - if(gui_mch_font_dialog(&family, &style, &size) == NOFONT) - return FAIL; - // compose for further processing - vim_snprintf(font_name, buff_size, - (char*)"%s/%s/%.0f", family, style, size); - hl_set_font_name((char_u*)font_name); + // Remember font in the static list for later use + font->next = fontList; + fontList = font; - // Set guifont to the name of the selected font. - char_u* new_p_guifont = (char_u*)alloc(STRLEN(font_name) + 1); - if (new_p_guifont != NULL) { - STRCPY(new_p_guifont, font_name); - vim_free(p_guifont); - p_guifont = new_p_guifont; - // Replace spaces in the font name with underscores. - for ( ; *new_p_guifont; ++new_p_guifont) - if (*new_p_guifont == ' ') - *new_p_guifont = '_'; - } - } + font->SetFamilyAndStyle(family, style); + if (size > 0.f) + font->SetSize(size); - VimFont *flp; - for (flp = fontList; flp; flp = flp->next) { - if (STRCMP(font_name, flp->name) == 0) { - flp->refcount++; - return (GuiFont)flp; - } - } + font->SetSpacing(B_FIXED_SPACING); + font->SetEncoding(B_UNICODE_UTF8); - VimFont *font = new VimFont(); - font->name = vim_strsave((char_u*)font_name); - - if(count_font_styles(family) <= 0) { - if (giveErrorIfMissing) - semsg(_(e_font), font->name); - delete font; - return NOFONT; - } - - // Remember font in the static list for later use - font->next = fontList; - fontList = font; - - font->SetFamilyAndStyle(family, style); - if(size > 0.f) - font->SetSize(size); - - font->SetSpacing(B_FIXED_SPACING); - font->SetEncoding(B_UNICODE_UTF8); - - return (GuiFont)font; + return (GuiFont)font; } /* @@ -3921,73 +3921,73 @@ gui_mch_get_font( */ void gui_mch_set_font( - GuiFont font) + GuiFont font) { - if (gui.vimWindow->Lock()) { - VimFont *vf = (VimFont *)font; + if (gui.vimWindow->Lock()) { + VimFont *vf = (VimFont *)font; - gui.vimTextArea->SetFont(vf); + gui.vimTextArea->SetFont(vf); - gui.char_width = (int) vf->StringWidth("n"); - font_height fh; - vf->GetHeight(&fh); - gui.char_height = (int)(fh.ascent + 0.9999) - + (int)(fh.descent + 0.9999) + (int)(fh.leading + 0.9999); - gui.char_ascent = (int)(fh.ascent + 0.9999); + gui.char_width = (int) vf->StringWidth("n"); + font_height fh; + vf->GetHeight(&fh); + gui.char_height = (int)(fh.ascent + 0.9999) + + (int)(fh.descent + 0.9999) + (int)(fh.leading + 0.9999); + gui.char_ascent = (int)(fh.ascent + 0.9999); - gui.vimWindow->Unlock(); - } + gui.vimWindow->Unlock(); + } } // XXX TODO This is apparently never called... void gui_mch_free_font( - GuiFont font) + GuiFont font) { - if(font == NOFONT) - return; - VimFont *f = (VimFont *)font; - if (--f->refcount <= 0) { - if (f->refcount < 0) - fprintf(stderr, "VimFont: refcount < 0\n"); - delete f; - } + if (font == NOFONT) + return; + VimFont *f = (VimFont *)font; + if (--f->refcount <= 0) { + if (f->refcount < 0) + fprintf(stderr, "VimFont: refcount < 0\n"); + delete f; + } } - char_u * + char_u * gui_mch_get_fontname(GuiFont font, char_u *name) { - if (name == NULL) - return NULL; - return vim_strsave(name); + if (name == NULL) + return NULL; + return vim_strsave(name); } /* * Adjust gui.char_height (after 'linespace' was changed). */ - int + int gui_mch_adjust_charheight() { - // TODO: linespace support? + // TODO: linespace support? // #ifdef FEAT_XFONTSET -// if (gui.fontset != NOFONTSET) -// { -// gui.char_height = fontset_height((XFontSet)gui.fontset) + p_linespace; -// gui.char_ascent = fontset_ascent((XFontSet)gui.fontset) -// + p_linespace / 2; -// } -// else +// if (gui.fontset != NOFONTSET) +// { +// gui.char_height = fontset_height((XFontSet)gui.fontset) + p_linespace; +// gui.char_ascent = fontset_ascent((XFontSet)gui.fontset) +// + p_linespace / 2; +// } +// else // #endif - { - VimFont *font = (VimFont *)gui.norm_font; - font_height fh = {0}; - font->GetHeight(&fh); - gui.char_height = (int)(fh.ascent + fh.descent + 0.5) + p_linespace; - gui.char_ascent = (int)(fh.ascent + 0.5) + p_linespace / 2; - } - return OK; + { + VimFont *font = (VimFont *)gui.norm_font; + font_height fh = {0}; + font->GetHeight(&fh); + gui.char_height = (int)(fh.ascent + fh.descent + 0.5) + p_linespace; + gui.char_ascent = (int)(fh.ascent + 0.5) + p_linespace / 2; + } + return OK; } /* @@ -3997,68 +3997,68 @@ gui_mch_adjust_charheight() void display_errors(void) { - char *p; - char_u pError[256]; + char *p; + char_u pError[256]; if (error_ga.ga_data == NULL) - return; + return; // avoid putting up a message box with blanks only for (p = (char *)error_ga.ga_data; *p; ++p) - if (!isspace(*p)) - { - if (STRLEN(p) > 255) - pError[0] = 255; - else - pError[0] = STRLEN(p); + if (!isspace(*p)) + { + if (STRLEN(p) > 255) + pError[0] = 255; + else + pError[0] = STRLEN(p); - STRNCPY(&pError[1], p, pError[0]); -// ParamText(pError, nil, nil, nil); -// Alert(128, nil); - break; - // TODO: handled message longer than 256 chars - // use auto-sizeable alert - // or dialog with scrollbars (TextEdit zone) - } + STRNCPY(&pError[1], p, pError[0]); +// ParamText(pError, nil, nil, nil); +// Alert(128, nil); + break; + // TODO: handled message longer than 256 chars + // use auto-sizeable alert + // or dialog with scrollbars (TextEdit zone) + } ga_clear(&error_ga); } #endif - void + void gui_mch_getmouse(int *x, int *y) { - fprintf(stderr, "gui_mch_getmouse"); + fprintf(stderr, "gui_mch_getmouse"); - /*int rootx, rooty, winx, winy; - Window root, child; - unsigned int mask; + /*int rootx, rooty, winx, winy; + Window root, child; + unsigned int mask; - if (gui.wid && XQueryPointer(gui.dpy, gui.wid, &root, &child, - &rootx, &rooty, &winx, &winy, &mask)) { - *x = winx; - *y = winy; - } else*/ { - *x = -1; - *y = -1; - } + if (gui.wid && XQueryPointer(gui.dpy, gui.wid, &root, &child, + &rootx, &rooty, &winx, &winy, &mask)) { + *x = winx; + *y = winy; + } else*/ { + *x = -1; + *y = -1; + } } - void + void gui_mch_mousehide(int hide) { - fprintf(stderr, "gui_mch_getmouse"); - // TODO + fprintf(stderr, "gui_mch_getmouse"); + // TODO } - static int + static int hex_digit(int c) { - if (isdigit(c)) - return c - '0'; - c = TOLOWER_ASC(c); - if (c >= 'a' && c <= 'f') - return c - 'a' + 10; - return -1000; + if (isdigit(c)) + return c - '0'; + c = TOLOWER_ASC(c); + if (c >= 'a' && c <= 'f') + return c - 'a' + 10; + return -1000; } /* @@ -4069,166 +4069,166 @@ hex_digit(int c) */ guicolor_T gui_mch_get_color( - char_u *name) + char_u *name) { - typedef struct GuiColourTable - { - const char *name; - guicolor_T colour; - } GuiColourTable; + typedef struct GuiColourTable + { + const char *name; + guicolor_T colour; + } GuiColourTable; -#define NSTATIC_COLOURS 50 // 32 -#define NDYNAMIC_COLOURS 33 -#define NCOLOURS (NSTATIC_COLOURS + NDYNAMIC_COLOURS) +#define NSTATIC_COLOURS 50 // 32 +#define NDYNAMIC_COLOURS 33 +#define NCOLOURS (NSTATIC_COLOURS + NDYNAMIC_COLOURS) - static GuiColourTable table[NCOLOURS] = - { - {"Black", RGB(0x00, 0x00, 0x00)}, - {"DarkGray", RGB(0x80, 0x80, 0x80)}, - {"DarkGrey", RGB(0x80, 0x80, 0x80)}, - {"Gray", RGB(0xC0, 0xC0, 0xC0)}, - {"Grey", RGB(0xC0, 0xC0, 0xC0)}, - {"LightGray", RGB(0xD3, 0xD3, 0xD3)}, - {"LightGrey", RGB(0xD3, 0xD3, 0xD3)}, - {"Gray10", RGB(0x1A, 0x1A, 0x1A)}, - {"Grey10", RGB(0x1A, 0x1A, 0x1A)}, - {"Gray20", RGB(0x33, 0x33, 0x33)}, - {"Grey20", RGB(0x33, 0x33, 0x33)}, - {"Gray30", RGB(0x4D, 0x4D, 0x4D)}, - {"Grey30", RGB(0x4D, 0x4D, 0x4D)}, - {"Gray40", RGB(0x66, 0x66, 0x66)}, - {"Grey40", RGB(0x66, 0x66, 0x66)}, - {"Gray50", RGB(0x7F, 0x7F, 0x7F)}, - {"Grey50", RGB(0x7F, 0x7F, 0x7F)}, - {"Gray60", RGB(0x99, 0x99, 0x99)}, - {"Grey60", RGB(0x99, 0x99, 0x99)}, - {"Gray70", RGB(0xB3, 0xB3, 0xB3)}, - {"Grey70", RGB(0xB3, 0xB3, 0xB3)}, - {"Gray80", RGB(0xCC, 0xCC, 0xCC)}, - {"Grey80", RGB(0xCC, 0xCC, 0xCC)}, - {"Gray90", RGB(0xE5, 0xE5, 0xE5)}, - {"Grey90", RGB(0xE5, 0xE5, 0xE5)}, - {"White", RGB(0xFF, 0xFF, 0xFF)}, - {"DarkRed", RGB(0x80, 0x00, 0x00)}, - {"Red", RGB(0xFF, 0x00, 0x00)}, - {"LightRed", RGB(0xFF, 0xA0, 0xA0)}, - {"DarkBlue", RGB(0x00, 0x00, 0x80)}, - {"Blue", RGB(0x00, 0x00, 0xFF)}, - {"LightBlue", RGB(0xA0, 0xA0, 0xFF)}, - {"DarkGreen", RGB(0x00, 0x80, 0x00)}, - {"Green", RGB(0x00, 0xFF, 0x00)}, - {"LightGreen", RGB(0xA0, 0xFF, 0xA0)}, - {"DarkCyan", RGB(0x00, 0x80, 0x80)}, - {"Cyan", RGB(0x00, 0xFF, 0xFF)}, - {"LightCyan", RGB(0xA0, 0xFF, 0xFF)}, - {"DarkMagenta", RGB(0x80, 0x00, 0x80)}, - {"Magenta", RGB(0xFF, 0x00, 0xFF)}, - {"LightMagenta", RGB(0xFF, 0xA0, 0xFF)}, - {"Brown", RGB(0x80, 0x40, 0x40)}, - {"Yellow", RGB(0xFF, 0xFF, 0x00)}, - {"LightYellow", RGB(0xFF, 0xFF, 0xA0)}, - {"DarkYellow", RGB(0xBB, 0xBB, 0x00)}, - {"SeaGreen", RGB(0x2E, 0x8B, 0x57)}, - {"Orange", RGB(0xFF, 0xA5, 0x00)}, - {"Purple", RGB(0xA0, 0x20, 0xF0)}, - {"SlateBlue", RGB(0x6A, 0x5A, 0xCD)}, - {"Violet", RGB(0xEE, 0x82, 0xEE)}, - // NOTE: some entries are zero-allocated for NDDYNAMIC_COLORS - // in this table! - }; + static GuiColourTable table[NCOLOURS] = + { + {"Black", RGB(0x00, 0x00, 0x00)}, + {"DarkGray", RGB(0x80, 0x80, 0x80)}, + {"DarkGrey", RGB(0x80, 0x80, 0x80)}, + {"Gray", RGB(0xC0, 0xC0, 0xC0)}, + {"Grey", RGB(0xC0, 0xC0, 0xC0)}, + {"LightGray", RGB(0xD3, 0xD3, 0xD3)}, + {"LightGrey", RGB(0xD3, 0xD3, 0xD3)}, + {"Gray10", RGB(0x1A, 0x1A, 0x1A)}, + {"Grey10", RGB(0x1A, 0x1A, 0x1A)}, + {"Gray20", RGB(0x33, 0x33, 0x33)}, + {"Grey20", RGB(0x33, 0x33, 0x33)}, + {"Gray30", RGB(0x4D, 0x4D, 0x4D)}, + {"Grey30", RGB(0x4D, 0x4D, 0x4D)}, + {"Gray40", RGB(0x66, 0x66, 0x66)}, + {"Grey40", RGB(0x66, 0x66, 0x66)}, + {"Gray50", RGB(0x7F, 0x7F, 0x7F)}, + {"Grey50", RGB(0x7F, 0x7F, 0x7F)}, + {"Gray60", RGB(0x99, 0x99, 0x99)}, + {"Grey60", RGB(0x99, 0x99, 0x99)}, + {"Gray70", RGB(0xB3, 0xB3, 0xB3)}, + {"Grey70", RGB(0xB3, 0xB3, 0xB3)}, + {"Gray80", RGB(0xCC, 0xCC, 0xCC)}, + {"Grey80", RGB(0xCC, 0xCC, 0xCC)}, + {"Gray90", RGB(0xE5, 0xE5, 0xE5)}, + {"Grey90", RGB(0xE5, 0xE5, 0xE5)}, + {"White", RGB(0xFF, 0xFF, 0xFF)}, + {"DarkRed", RGB(0x80, 0x00, 0x00)}, + {"Red", RGB(0xFF, 0x00, 0x00)}, + {"LightRed", RGB(0xFF, 0xA0, 0xA0)}, + {"DarkBlue", RGB(0x00, 0x00, 0x80)}, + {"Blue", RGB(0x00, 0x00, 0xFF)}, + {"LightBlue", RGB(0xA0, 0xA0, 0xFF)}, + {"DarkGreen", RGB(0x00, 0x80, 0x00)}, + {"Green", RGB(0x00, 0xFF, 0x00)}, + {"LightGreen", RGB(0xA0, 0xFF, 0xA0)}, + {"DarkCyan", RGB(0x00, 0x80, 0x80)}, + {"Cyan", RGB(0x00, 0xFF, 0xFF)}, + {"LightCyan", RGB(0xA0, 0xFF, 0xFF)}, + {"DarkMagenta", RGB(0x80, 0x00, 0x80)}, + {"Magenta", RGB(0xFF, 0x00, 0xFF)}, + {"LightMagenta", RGB(0xFF, 0xA0, 0xFF)}, + {"Brown", RGB(0x80, 0x40, 0x40)}, + {"Yellow", RGB(0xFF, 0xFF, 0x00)}, + {"LightYellow", RGB(0xFF, 0xFF, 0xA0)}, + {"DarkYellow", RGB(0xBB, 0xBB, 0x00)}, + {"SeaGreen", RGB(0x2E, 0x8B, 0x57)}, + {"Orange", RGB(0xFF, 0xA5, 0x00)}, + {"Purple", RGB(0xA0, 0x20, 0xF0)}, + {"SlateBlue", RGB(0x6A, 0x5A, 0xCD)}, + {"Violet", RGB(0xEE, 0x82, 0xEE)}, + // NOTE: some entries are zero-allocated for NDDYNAMIC_COLORS + // in this table! + }; - static int endColour = NSTATIC_COLOURS; - static int newColour = NSTATIC_COLOURS; + static int endColour = NSTATIC_COLOURS; + static int newColour = NSTATIC_COLOURS; - int r, g, b; - int i; + int r, g, b; + int i; - if (name[0] == '#' && STRLEN(name) == 7) - { - // Name is in "#rrggbb" format - r = hex_digit(name[1]) * 16 + hex_digit(name[2]); - g = hex_digit(name[3]) * 16 + hex_digit(name[4]); - b = hex_digit(name[5]) * 16 + hex_digit(name[6]); - if (r < 0 || g < 0 || b < 0) - return INVALCOLOR; - return RGB(r, g, b); - } - else - { - // Check if the name is one of the colours we know - for (i = 0; i < endColour; i++) - if (STRICMP(name, table[i].name) == 0) - return table[i].colour; - } + if (name[0] == '#' && STRLEN(name) == 7) + { + // Name is in "#rrggbb" format + r = hex_digit(name[1]) * 16 + hex_digit(name[2]); + g = hex_digit(name[3]) * 16 + hex_digit(name[4]); + b = hex_digit(name[5]) * 16 + hex_digit(name[6]); + if (r < 0 || g < 0 || b < 0) + return INVALCOLOR; + return RGB(r, g, b); + } + else + { + // Check if the name is one of the colours we know + for (i = 0; i < endColour; i++) + if (STRICMP(name, table[i].name) == 0) + return table[i].colour; + } - /* - * Last attempt. Look in the file "$VIMRUNTIME/rgb.txt". - */ - { + /* + * Last attempt. Look in the file "$VIMRUNTIME/rgb.txt". + */ + { #define LINE_LEN 100 - FILE *fd; - char line[LINE_LEN]; - char_u *fname; + FILE *fd; + char line[LINE_LEN]; + char_u *fname; - fname = expand_env_save((char_u *)"$VIMRUNTIME/rgb.txt"); - if (fname == NULL) - return INVALCOLOR; + fname = expand_env_save((char_u *)"$VIMRUNTIME/rgb.txt"); + if (fname == NULL) + return INVALCOLOR; - fd = fopen((char *)fname, "rt"); - vim_free(fname); - if (fd == NULL) - return INVALCOLOR; + fd = fopen((char *)fname, "rt"); + vim_free(fname); + if (fd == NULL) + return INVALCOLOR; - while (!feof(fd)) - { - int len; - int pos; - char *colour; + while (!feof(fd)) + { + int len; + int pos; + char *colour; - fgets(line, LINE_LEN, fd); - len = strlen(line); + fgets(line, LINE_LEN, fd); + len = strlen(line); - if (len <= 1 || line[len-1] != '\n') - continue; + if (len <= 1 || line[len-1] != '\n') + continue; - line[len-1] = '\0'; + line[len-1] = '\0'; - i = sscanf(line, "%d %d %d %n", &r, &g, &b, &pos); - if (i != 3) - continue; + i = sscanf(line, "%d %d %d %n", &r, &g, &b, &pos); + if (i != 3) + continue; - colour = line + pos; - - if (STRICMP(colour, name) == 0) - { - fclose(fd); - /* - * Now remember this colour in the table. - * A LRU scheme might be better but this is simpler. - * Or could use a growing array. - */ - guicolor_T gcolour = RGB(r,g,b); - - // NOTE: see note above in table allocation! We are working here with - // dynamically allocated names, not constant ones! - vim_free((char*)table[newColour].name); - table[newColour].name = (char *)vim_strsave((char_u *)colour); - table[newColour].colour = gcolour; - - newColour++; - if (newColour >= NCOLOURS) - newColour = NSTATIC_COLOURS; - if (endColour < NCOLOURS) - endColour = newColour; - - return gcolour; - } - } + colour = line + pos; + if (STRICMP(colour, name) == 0) + { fclose(fd); + /* + * Now remember this colour in the table. + * A LRU scheme might be better but this is simpler. + * Or could use a growing array. + */ + guicolor_T gcolour = RGB(r,g,b); + + // NOTE: see note above in table allocation! We are working here with + // dynamically allocated names, not constant ones! + vim_free((char*)table[newColour].name); + table[newColour].name = (char *)vim_strsave((char_u *)colour); + table[newColour].colour = gcolour; + + newColour++; + if (newColour >= NCOLOURS) + newColour = NSTATIC_COLOURS; + if (endColour < NCOLOURS) + endColour = newColour; + + return gcolour; + } } - return INVALCOLOR; + fclose(fd); + } + + return INVALCOLOR; } /* @@ -4236,13 +4236,13 @@ gui_mch_get_color( */ void gui_mch_set_fg_color( - guicolor_T color) + guicolor_T color) { - rgb_color rgb = GUI_TO_RGB(color); - if (gui.vimWindow->Lock()) { - gui.vimTextArea->SetHighColor(rgb); - gui.vimWindow->Unlock(); - } + rgb_color rgb = GUI_TO_RGB(color); + if (gui.vimWindow->Lock()) { + gui.vimTextArea->SetHighColor(rgb); + gui.vimWindow->Unlock(); + } } /* @@ -4250,39 +4250,39 @@ gui_mch_set_fg_color( */ void gui_mch_set_bg_color( - guicolor_T color) + guicolor_T color) { - rgb_color rgb = GUI_TO_RGB(color); - if (gui.vimWindow->Lock()) { - gui.vimTextArea->SetLowColor(rgb); - gui.vimWindow->Unlock(); - } + rgb_color rgb = GUI_TO_RGB(color); + if (gui.vimWindow->Lock()) { + gui.vimTextArea->SetLowColor(rgb); + gui.vimWindow->Unlock(); + } } /* * Set the current text special color. */ - void + void gui_mch_set_sp_color(guicolor_T color) { - // prev_sp_color = color; + // prev_sp_color = color; } void gui_mch_draw_string( - int row, - int col, - char_u *s, - int len, - int flags) + int row, + int col, + char_u *s, + int len, + int flags) { - if (gui.vimWindow->Lock()) { - gui.vimTextArea->mchDrawString(row, col, s, len, flags); - gui.vimWindow->Unlock(); - } + if (gui.vimWindow->Lock()) { + gui.vimTextArea->mchDrawString(row, col, s, len, flags); + gui.vimWindow->Unlock(); + } } - guicolor_T + guicolor_T gui_mch_get_rgb_color(int r, int g, int b) { return gui_get_rgb_color_cmn(r, g, b); @@ -4292,40 +4292,40 @@ gui_mch_get_rgb_color(int r, int g, int b) // Return OK if the key with the termcap name "name" is supported. int gui_mch_haskey( - char_u *name) + char_u *name) { - int i; + int i; - for (i = 0; special_keys[i].BeKeys != 0; i++) - if (name[0] == special_keys[i].vim_code0 && - name[1] == special_keys[i].vim_code1) - return OK; - return FAIL; + for (i = 0; special_keys[i].BeKeys != 0; i++) + if (name[0] == special_keys[i].vim_code0 && + name[1] == special_keys[i].vim_code1) + return OK; + return FAIL; } - void + void gui_mch_beep() { - ::beep(); + ::beep(); } - void + void gui_mch_flash(int msec) { - // Do a visual beep by reversing the foreground and background colors + // Do a visual beep by reversing the foreground and background colors - if (gui.vimWindow->Lock()) { - BRect rect = gui.vimTextArea->Bounds(); + if (gui.vimWindow->Lock()) { + BRect rect = gui.vimTextArea->Bounds(); - gui.vimTextArea->SetDrawingMode(B_OP_INVERT); - gui.vimTextArea->FillRect(rect); - gui.vimTextArea->Sync(); - snooze(msec * 1000); // wait for a few msec - gui.vimTextArea->FillRect(rect); - gui.vimTextArea->SetDrawingMode(B_OP_COPY); - gui.vimTextArea->Flush(); - gui.vimWindow->Unlock(); - } + gui.vimTextArea->SetDrawingMode(B_OP_INVERT); + gui.vimTextArea->FillRect(rect); + gui.vimTextArea->Sync(); + snooze(msec * 1000); // wait for a few msec + gui.vimTextArea->FillRect(rect); + gui.vimTextArea->SetDrawingMode(B_OP_COPY); + gui.vimTextArea->Flush(); + gui.vimWindow->Unlock(); + } } /* @@ -4333,45 +4333,45 @@ gui_mch_flash(int msec) */ void gui_mch_invert_rectangle( - int r, - int c, - int nr, - int nc) + int r, + int c, + int nr, + int nc) { - BRect rect; - rect.left = FILL_X(c); - rect.top = FILL_Y(r); - rect.right = rect.left + nc * gui.char_width - PEN_WIDTH; - rect.bottom = rect.top + nr * gui.char_height - PEN_WIDTH; + BRect rect; + rect.left = FILL_X(c); + rect.top = FILL_Y(r); + rect.right = rect.left + nc * gui.char_width - PEN_WIDTH; + rect.bottom = rect.top + nr * gui.char_height - PEN_WIDTH; - if (gui.vimWindow->Lock()) { - gui.vimTextArea->SetDrawingMode(B_OP_INVERT); - gui.vimTextArea->FillRect(rect); - gui.vimTextArea->SetDrawingMode(B_OP_COPY); - gui.vimWindow->Unlock(); - } + if (gui.vimWindow->Lock()) { + gui.vimTextArea->SetDrawingMode(B_OP_INVERT); + gui.vimTextArea->FillRect(rect); + gui.vimTextArea->SetDrawingMode(B_OP_COPY); + gui.vimWindow->Unlock(); + } } /* * Iconify the GUI window. */ - void + void gui_mch_iconify() { - if (gui.vimWindow->Lock()) { - gui.vimWindow->Minimize(true); - gui.vimWindow->Unlock(); - } + if (gui.vimWindow->Lock()) { + gui.vimWindow->Minimize(true); + gui.vimWindow->Unlock(); + } } #if defined(FEAT_EVAL) || defined(PROTO) /* * Bring the Vim window to the foreground. */ - void + void gui_mch_set_foreground(void) { - // TODO + // TODO } #endif @@ -4380,36 +4380,36 @@ gui_mch_set_foreground(void) */ void gui_mch_settitle( - char_u *title, - char_u *icon) + char_u *title, + char_u *icon) { - if (gui.vimWindow->Lock()) { - gui.vimWindow->SetTitle((char *)title); - gui.vimWindow->Unlock(); - } + if (gui.vimWindow->Lock()) { + gui.vimWindow->SetTitle((char *)title); + gui.vimWindow->Unlock(); + } } /* * Draw a cursor without focus. */ - void + void gui_mch_draw_hollow_cursor(guicolor_T color) { - gui_mch_set_fg_color(color); + gui_mch_set_fg_color(color); - BRect r; - r.left = FILL_X(gui.col); - r.top = FILL_Y(gui.row); - int cells = utf_off2cells(LineOffset[gui.row] + gui.col, 100); // TODO-TODO - if(cells>=4) cells = 1; - r.right = r.left + cells*gui.char_width - PEN_WIDTH; - r.bottom = r.top + gui.char_height - PEN_WIDTH; + BRect r; + r.left = FILL_X(gui.col); + r.top = FILL_Y(gui.row); + int cells = utf_off2cells(LineOffset[gui.row] + gui.col, 100); // TODO-TODO + if (cells>=4) cells = 1; + r.right = r.left + cells*gui.char_width - PEN_WIDTH; + r.bottom = r.top + gui.char_height - PEN_WIDTH; - if (gui.vimWindow->Lock()) { - gui.vimTextArea->StrokeRect(r); - gui.vimWindow->Unlock(); - // gui_mch_flush(); - } + if (gui.vimWindow->Lock()) { + gui.vimTextArea->StrokeRect(r); + gui.vimWindow->Unlock(); + // gui_mch_flush(); + } } /* @@ -4417,28 +4417,28 @@ gui_mch_draw_hollow_cursor(guicolor_T color) */ void gui_mch_draw_part_cursor( - int w, - int h, - guicolor_T color) + int w, + int h, + guicolor_T color) { - gui_mch_set_fg_color(color); + gui_mch_set_fg_color(color); - BRect r; - r.left = + BRect r; + r.left = #ifdef FEAT_RIGHTLEFT - // vertical line should be on the right of current point - CURSOR_BAR_RIGHT ? FILL_X(gui.col + 1) - w : + // vertical line should be on the right of current point + CURSOR_BAR_RIGHT ? FILL_X(gui.col + 1) - w : #endif - FILL_X(gui.col); - r.right = r.left + w - PEN_WIDTH; - r.bottom = FILL_Y(gui.row + 1) - PEN_WIDTH; - r.top = r.bottom - h + PEN_WIDTH; + FILL_X(gui.col); + r.right = r.left + w - PEN_WIDTH; + r.bottom = FILL_Y(gui.row + 1) - PEN_WIDTH; + r.top = r.bottom - h + PEN_WIDTH; - if (gui.vimWindow->Lock()) { - gui.vimTextArea->FillRect(r); - gui.vimWindow->Unlock(); - // gui_mch_flush(); - } + if (gui.vimWindow->Lock()) { + gui.vimTextArea->FillRect(r); + gui.vimWindow->Unlock(); + // gui_mch_flush(); + } } /* @@ -4447,78 +4447,78 @@ gui_mch_draw_part_cursor( * nothing in the event queue (& no timers pending), then we return * immediately. */ - void + void gui_mch_update() { - gui_mch_flush(); - while (port_count(gui.vdcmp) > 0 && - !vim_is_input_buf_full() && - gui_haiku_process_event(0) >= B_OK) - /* nothing */ ; + gui_mch_flush(); + while (port_count(gui.vdcmp) > 0 && + !vim_is_input_buf_full() && + gui_haiku_process_event(0) >= B_OK) + /* nothing */ ; } /* * GUI input routine called by gui_wait_for_chars(). Waits for a character * from the keyboard. - * wtime == -1 Wait forever. - * wtime == 0 This should never happen. - * wtime > 0 Wait wtime milliseconds for a character. + * wtime == -1 Wait forever. + * wtime == 0 This should never happen. + * wtime > 0 Wait wtime milliseconds for a character. * Returns OK if a character was found to be available within the given time, * or FAIL otherwise. */ int gui_mch_wait_for_chars( - int wtime) + int wtime) { - int focus; - bigtime_t until, timeout; - status_t st; + int focus; + bigtime_t until, timeout; + status_t st; - if (wtime >= 0) { - timeout = wtime * 1000; - until = system_time() + timeout; - } else { - timeout = B_INFINITE_TIMEOUT; - } + if (wtime >= 0) { + timeout = wtime * 1000; + until = system_time() + timeout; + } else { + timeout = B_INFINITE_TIMEOUT; + } - focus = gui.in_focus; - for (;;) + focus = gui.in_focus; + for (;;) + { + // Stop or start blinking when focus changes + if (gui.in_focus != focus) { - // Stop or start blinking when focus changes - if (gui.in_focus != focus) - { - if (gui.in_focus) - gui_mch_start_blink(); - else - gui_mch_stop_blink(TRUE); - focus = gui.in_focus; - } - - gui_mch_flush(); - /* - * Don't use gui_mch_update() because then we will spin-lock until a - * char arrives, instead we use gui_haiku_process_event() to hang until - * an event arrives. No need to check for input_buf_full because we - * are returning as soon as it contains a single char. - */ - st = gui_haiku_process_event(timeout); - - if (input_available()) - return OK; - if (st < B_OK) // includes B_TIMED_OUT - return FAIL; - - /* - * Calculate how much longer we're willing to wait for the - * next event. - */ - if (wtime >= 0) { - timeout = until - system_time(); - if (timeout < 0) - break; - } + if (gui.in_focus) + gui_mch_start_blink(); + else + gui_mch_stop_blink(TRUE); + focus = gui.in_focus; } - return FAIL; + + gui_mch_flush(); + /* + * Don't use gui_mch_update() because then we will spin-lock until a + * char arrives, instead we use gui_haiku_process_event() to hang until + * an event arrives. No need to check for input_buf_full because we + * are returning as soon as it contains a single char. + */ + st = gui_haiku_process_event(timeout); + + if (input_available()) + return OK; + if (st < B_OK) // includes B_TIMED_OUT + return FAIL; + + /* + * Calculate how much longer we're willing to wait for the + * next event. + */ + if (wtime >= 0) { + timeout = until - system_time(); + if (timeout < 0) + break; + } + } + return FAIL; } @@ -4530,15 +4530,15 @@ gui_mch_wait_for_chars( * Flush any output to the screen. This is typically called before * the app goes to sleep. */ - void + void gui_mch_flush() { - // does this need to lock the window? Apparently not but be safe. - if (gui.vimWindow->Lock()) { - gui.vimWindow->Flush(); - gui.vimWindow->Unlock(); - } - return; + // does this need to lock the window? Apparently not but be safe. + if (gui.vimWindow->Lock()) { + gui.vimWindow->Flush(); + gui.vimWindow->Unlock(); + } + return; } /* @@ -4547,24 +4547,24 @@ gui_mch_flush() */ void gui_mch_clear_block( - int row1, - int col1, - int row2, - int col2) + int row1, + int col1, + int row2, + int col2) { - if (gui.vimWindow->Lock()) { - gui.vimTextArea->mchClearBlock(row1, col1, row2, col2); - gui.vimWindow->Unlock(); - } + if (gui.vimWindow->Lock()) { + gui.vimTextArea->mchClearBlock(row1, col1, row2, col2); + gui.vimWindow->Unlock(); + } } - void + void gui_mch_clear_all() { - if (gui.vimWindow->Lock()) { - gui.vimTextArea->mchClearAll(); - gui.vimWindow->Unlock(); - } + if (gui.vimWindow->Lock()) { + gui.vimTextArea->mchClearAll(); + gui.vimWindow->Unlock(); + } } /* @@ -4573,10 +4573,10 @@ gui_mch_clear_all() */ void gui_mch_delete_lines( - int row, - int num_lines) + int row, + int num_lines) { - gui.vimTextArea->mchDeleteLines(row, num_lines); + gui.vimTextArea->mchDeleteLines(row, num_lines); } /* @@ -4585,10 +4585,10 @@ gui_mch_delete_lines( */ void gui_mch_insert_lines( - int row, - int num_lines) + int row, + int num_lines) { - gui.vimTextArea->mchInsertLines(row, num_lines); + gui.vimTextArea->mchInsertLines(row, num_lines); } #if defined(FEAT_MENU) || defined(PROTO) @@ -4598,24 +4598,24 @@ gui_mch_insert_lines( void gui_mch_enable_menu( - int flag) + int flag) { - if (gui.vimWindow->Lock()) - { - BMenuBar *menubar = gui.vimForm->MenuBar(); - menubar->SetEnabled(flag); - gui.vimWindow->Unlock(); - } + if (gui.vimWindow->Lock()) + { + BMenuBar *menubar = gui.vimForm->MenuBar(); + menubar->SetEnabled(flag); + gui.vimWindow->Unlock(); + } } void gui_mch_set_menu_pos( - int x, - int y, - int w, - int h) + int x, + int y, + int w, + int h) { - // It will be in the right place anyway + // It will be in the right place anyway } /* @@ -4623,72 +4623,72 @@ gui_mch_set_menu_pos( */ void gui_mch_add_menu( - vimmenu_T *menu, - int idx) + vimmenu_T *menu, + int idx) { - vimmenu_T *parent = menu->parent; + vimmenu_T *parent = menu->parent; + + // popup menu - just create it unattached + if (menu_is_popup(menu->name) && parent == NULL) { + BPopUpMenu* popUpMenu = new BPopUpMenu((const char*)menu->name, false, false); + menu->submenu_id = popUpMenu; + menu->id = NULL; + return; + } + + if (!menu_is_menubar(menu->name) + || (parent != NULL && parent->submenu_id == NULL)) + return; + + if (gui.vimWindow->Lock()) + { + // Major re-write of the menu code, it was failing with memory corruption when + // we started loading multiple files (the Buffer menu) + // + // Note we don't use the preference values yet, all are inserted into the + // menubar on a first come-first served basis... + // + // richard@whitequeen.com jul 99 + + BMenu *tmp; + + if ( parent ) + tmp = parent->submenu_id; + else + tmp = gui.vimForm->MenuBar(); + // make sure we don't try and add the same menu twice. The Buffers menu tries to + // do this and Be starts to crash... + + if ( ! tmp->FindItem((const char *) menu->dname)) { + + BMenu *bmenu = new BMenu((char *)menu->dname); + + menu->submenu_id = bmenu; + + // when we add a BMenu to another Menu, it creates the interconnecting BMenuItem + tmp->AddItem(bmenu); + + // Now its safe to query the menu for the associated MenuItem.... + menu->id = tmp->FindItem((const char *) menu->dname); - // popup menu - just create it unattached - if (menu_is_popup(menu->name) && parent == NULL) { - BPopUpMenu* popUpMenu = new BPopUpMenu((const char*)menu->name, false, false); - menu->submenu_id = popUpMenu; - menu->id = NULL; - return; - } - - if (!menu_is_menubar(menu->name) - || (parent != NULL && parent->submenu_id == NULL)) - return; - - if (gui.vimWindow->Lock()) - { - // Major re-write of the menu code, it was failing with memory corruption when - // we started loading multiple files (the Buffer menu) - // - // Note we don't use the preference values yet, all are inserted into the - // menubar on a first come-first served basis... - // - // richard@whitequeen.com jul 99 - - BMenu *tmp; - - if ( parent ) - tmp = parent->submenu_id; - else - tmp = gui.vimForm->MenuBar(); - // make sure we don't try and add the same menu twice. The Buffers menu tries to - // do this and Be starts to crash... - - if ( ! tmp->FindItem((const char *) menu->dname)) { - - BMenu *bmenu = new BMenu((char *)menu->dname); - - menu->submenu_id = bmenu; - - // when we add a BMenu to another Menu, it creates the interconnecting BMenuItem - tmp->AddItem(bmenu); - - // Now its safe to query the menu for the associated MenuItem.... - menu->id = tmp->FindItem((const char *) menu->dname); - - } - gui.vimWindow->Unlock(); } + gui.vimWindow->Unlock(); + } } - void + void gui_mch_toggle_tearoffs(int enable) { - // no tearoff menus + // no tearoff menus } - static BMessage * + static BMessage * MenuMessage(vimmenu_T *menu) { - BMessage *m = new BMessage('menu'); - m->AddPointer("VimMenu", (void *)menu); + BMessage *m = new BMessage('menu'); + m->AddPointer("VimMenu", (void *)menu); - return m; + return m; } /* @@ -4696,48 +4696,48 @@ MenuMessage(vimmenu_T *menu) */ void gui_mch_add_menu_item( - vimmenu_T *menu, - int idx) + vimmenu_T *menu, + int idx) { - int mnemonic = 0; - vimmenu_T *parent = menu->parent; + int mnemonic = 0; + vimmenu_T *parent = menu->parent; - // TODO: use menu->actext - // This is difficult, since on Be, an accelerator must be a single char - // and a lot of Vim ones are the standard VI commands. - // - // Punt for Now... - // richard@whiequeen.com jul 99 - if (gui.vimWindow->Lock()) - { + // TODO: use menu->actext + // This is difficult, since on Be, an accelerator must be a single char + // and a lot of Vim ones are the standard VI commands. + // + // Punt for Now... + // richard@whiequeen.com jul 99 + if (gui.vimWindow->Lock()) + { #ifdef FEAT_TOOLBAR - if(menu_is_toolbar(parent->name)) { - VimToolbar *toolbar = gui.vimForm->ToolBar(); - if(toolbar != NULL) { - toolbar->AddButton(idx, menu); - } - } else + if (menu_is_toolbar(parent->name)) { + VimToolbar *toolbar = gui.vimForm->ToolBar(); + if (toolbar != NULL) { + toolbar->AddButton(idx, menu); + } + } else #endif - if (parent->submenu_id != NULL || menu_is_popup(parent->name)) { - if (menu_is_separator(menu->name)) { - BSeparatorItem *item = new BSeparatorItem(); - parent->submenu_id->AddItem(item); - menu->id = item; - menu->submenu_id = NULL; - } - else { - BMenuItem *item = new BMenuItem((char *)menu->dname, - MenuMessage(menu)); - item->SetTarget(gui.vimTextArea); - item->SetTrigger((char) menu->mnemonic); - parent->submenu_id->AddItem(item); - menu->id = item; - menu->submenu_id = NULL; - } - } - gui.vimWindow->Unlock(); + if (parent->submenu_id != NULL || menu_is_popup(parent->name)) { + if (menu_is_separator(menu->name)) { + BSeparatorItem *item = new BSeparatorItem(); + parent->submenu_id->AddItem(item); + menu->id = item; + menu->submenu_id = NULL; + } + else { + BMenuItem *item = new BMenuItem((char *)menu->dname, + MenuMessage(menu)); + item->SetTarget(gui.vimTextArea); + item->SetTrigger((char) menu->mnemonic); + parent->submenu_id->AddItem(item); + menu->id = item; + menu->submenu_id = NULL; + } } + gui.vimWindow->Unlock(); + } } /* @@ -4745,48 +4745,48 @@ gui_mch_add_menu_item( */ void gui_mch_destroy_menu( - vimmenu_T *menu) + vimmenu_T *menu) { - if (gui.vimWindow->Lock()) - { + if (gui.vimWindow->Lock()) + { #ifdef FEAT_TOOLBAR - if(menu->parent && menu_is_toolbar(menu->parent->name)) { - VimToolbar *toolbar = gui.vimForm->ToolBar(); - if(toolbar != NULL) { - toolbar->RemoveButton(menu); - } - } else + if (menu->parent && menu_is_toolbar(menu->parent->name)) { + VimToolbar *toolbar = gui.vimForm->ToolBar(); + if (toolbar != NULL) { + toolbar->RemoveButton(menu); + } + } else #endif + { + assert(menu->submenu_id == NULL || menu->submenu_id->CountItems() == 0); + /* + * Detach this menu from its parent, so that it is not deleted + * twice once we get to delete that parent. + * Deleting a BMenuItem also deletes the associated BMenu, if any + * (which does not have any items anymore since they were + * removed and deleted before). + */ + BMenu *bmenu = menu->id->Menu(); + if (bmenu) + { + bmenu->RemoveItem(menu->id); + /* + * If we removed the last item from the menu bar, + * resize it out of sight. + */ + if (bmenu == gui.vimForm->MenuBar() && bmenu->CountItems() == 0) { - assert(menu->submenu_id == NULL || menu->submenu_id->CountItems() == 0); - /* - * Detach this menu from its parent, so that it is not deleted - * twice once we get to delete that parent. - * Deleting a BMenuItem also deletes the associated BMenu, if any - * (which does not have any items anymore since they were - * removed and deleted before). - */ - BMenu *bmenu = menu->id->Menu(); - if (bmenu) - { - bmenu->RemoveItem(menu->id); - /* - * If we removed the last item from the menu bar, - * resize it out of sight. - */ - if (bmenu == gui.vimForm->MenuBar() && bmenu->CountItems() == 0) - { - bmenu->ResizeTo(-MENUBAR_MARGIN, -MENUBAR_MARGIN); - } - } - delete menu->id; - menu->id = NULL; - menu->submenu_id = NULL; - - gui.menu_height = (int) gui.vimForm->MenuHeight(); + bmenu->ResizeTo(-MENUBAR_MARGIN, -MENUBAR_MARGIN); } - gui.vimWindow->Unlock(); + } + delete menu->id; + menu->id = NULL; + menu->submenu_id = NULL; + + gui.menu_height = (int) gui.vimForm->MenuHeight(); } + gui.vimWindow->Unlock(); + } } /* @@ -4794,22 +4794,22 @@ gui_mch_destroy_menu( */ void gui_mch_menu_grey( - vimmenu_T *menu, - int grey) + vimmenu_T *menu, + int grey) { #ifdef FEAT_TOOLBAR - if(menu->parent && menu_is_toolbar(menu->parent->name)) { - if (gui.vimWindow->Lock()) { - VimToolbar *toolbar = gui.vimForm->ToolBar(); - if(toolbar != NULL) { - toolbar->GrayButton(menu, grey); - } - gui.vimWindow->Unlock(); - } - } else + if (menu->parent && menu_is_toolbar(menu->parent->name)) { + if (gui.vimWindow->Lock()) { + VimToolbar *toolbar = gui.vimForm->ToolBar(); + if (toolbar != NULL) { + toolbar->GrayButton(menu, grey); + } + gui.vimWindow->Unlock(); + } + } else #endif - if (menu->id != NULL) - menu->id->SetEnabled(!grey); + if (menu->id != NULL) + menu->id->SetEnabled(!grey); } /* @@ -4817,40 +4817,40 @@ gui_mch_menu_grey( */ void gui_mch_menu_hidden( - vimmenu_T *menu, - int hidden) + vimmenu_T *menu, + int hidden) { - if (menu->id != NULL) - menu->id->SetEnabled(!hidden); + if (menu->id != NULL) + menu->id->SetEnabled(!hidden); } /* * This is called after setting all the menus to grey/hidden or not. */ - void + void gui_mch_draw_menubar() { - // Nothing to do in BeOS + // Nothing to do in BeOS } - void + void gui_mch_show_popupmenu(vimmenu_T *menu) { - if (!menu_is_popup(menu->name) || menu->submenu_id == NULL) - return; + if (!menu_is_popup(menu->name) || menu->submenu_id == NULL) + return; - BPopUpMenu* popupMenu = dynamic_cast(menu->submenu_id); - if (popupMenu == NULL) - return; + BPopUpMenu* popupMenu = dynamic_cast(menu->submenu_id); + if (popupMenu == NULL) + return; - BPoint point; - if(gui.vimWindow->Lock()) { - uint32 buttons = 0; - gui.vimTextArea->GetMouse(&point, &buttons); - gui.vimTextArea->ConvertToScreen(&point); - gui.vimWindow->Unlock(); - } - popupMenu->Go(point, true); + BPoint point; + if (gui.vimWindow->Lock()) { + uint32 buttons = 0; + gui.vimTextArea->GetMouse(&point, &buttons); + gui.vimTextArea->ConvertToScreen(&point); + gui.vimWindow->Unlock(); + } + popupMenu->Go(point, true); } #endif // FEAT_MENU @@ -4867,122 +4867,122 @@ char vimselectiontype[] = "application/x-vnd.Rhialto-Vim-selectiontype"; /* * Get the current selection and put it in the clipboard register. */ - void + void clip_mch_request_selection(Clipboard_T *cbd) { - if (be_clipboard->Lock()) + if (be_clipboard->Lock()) + { + BMessage *m = be_clipboard->Data(); + // m->PrintToStream(); + + char_u *string = NULL; + ssize_t stringlen = -1; + + if (m->FindData(textplain, B_MIME_TYPE, + (const void **)&string, &stringlen) == B_OK + || m->FindString("text", (const char **)&string) == B_OK) { - BMessage *m = be_clipboard->Data(); - // m->PrintToStream(); + if (stringlen == -1) + stringlen = STRLEN(string); - char_u *string = NULL; - ssize_t stringlen = -1; + int type; + char *seltype; + ssize_t seltypelen; - if (m->FindData(textplain, B_MIME_TYPE, - (const void **)&string, &stringlen) == B_OK - || m->FindString("text", (const char **)&string) == B_OK) + /* + * Try to get the special vim selection type first + */ + if (m->FindData(vimselectiontype, B_MIME_TYPE, + (const void **)&seltype, &seltypelen) == B_OK) + { + switch (*seltype) { - if (stringlen == -1) - stringlen = STRLEN(string); - - int type; - char *seltype; - ssize_t seltypelen; - - /* - * Try to get the special vim selection type first - */ - if (m->FindData(vimselectiontype, B_MIME_TYPE, - (const void **)&seltype, &seltypelen) == B_OK) - { - switch (*seltype) - { - default: - case 'L': type = MLINE; break; - case 'C': type = MCHAR; break; + default: + case 'L': type = MLINE; break; + case 'C': type = MCHAR; break; #ifdef FEAT_VISUAL - case 'B': type = MBLOCK; break; + case 'B': type = MBLOCK; break; #endif - } - } - else - { - // Otherwise use heuristic as documented - type = memchr(string, stringlen, '\n') ? MLINE : MCHAR; - } - clip_yank_selection(type, string, (long)stringlen, cbd); } - be_clipboard->Unlock(); + } + else + { + // Otherwise use heuristic as documented + type = memchr(string, stringlen, '\n') ? MLINE : MCHAR; + } + clip_yank_selection(type, string, (long)stringlen, cbd); } + be_clipboard->Unlock(); + } } /* * Make vim the owner of the current selection. */ - void + void clip_mch_lose_selection(Clipboard_T *cbd) { - // Nothing needs to be done here + // Nothing needs to be done here } /* * Make vim the owner of the current selection. Return OK upon success. */ - int + int clip_mch_own_selection(Clipboard_T *cbd) { - /* - * Never actually own the clipboard. If another application sets the - * clipboard, we don't want to think that we still own it. - */ - return FAIL; + /* + * Never actually own the clipboard. If another application sets the + * clipboard, we don't want to think that we still own it. + */ + return FAIL; } /* * Send the current selection to the clipboard. */ - void + void clip_mch_set_selection(Clipboard_T *cbd) { - if (be_clipboard->Lock()) + if (be_clipboard->Lock()) + { + be_clipboard->Clear(); + BMessage *m = be_clipboard->Data(); + assert(m); + + // If the '*' register isn't already filled in, fill it in now + cbd->owned = TRUE; + clip_get_selection(cbd); + cbd->owned = FALSE; + + char_u *str = NULL; + long_u count; + int type; + + type = clip_convert_selection(&str, &count, cbd); + + if (type < 0) + return; + + m->AddData(textplain, B_MIME_TYPE, (void *)str, count); + + // Add type of selection + char vtype; + switch (type) { - be_clipboard->Clear(); - BMessage *m = be_clipboard->Data(); - assert(m); - - // If the '*' register isn't already filled in, fill it in now - cbd->owned = TRUE; - clip_get_selection(cbd); - cbd->owned = FALSE; - - char_u *str = NULL; - long_u count; - int type; - - type = clip_convert_selection(&str, &count, cbd); - - if (type < 0) - return; - - m->AddData(textplain, B_MIME_TYPE, (void *)str, count); - - // Add type of selection - char vtype; - switch (type) - { - default: - case MLINE: vtype = 'L'; break; - case MCHAR: vtype = 'C'; break; + default: + case MLINE: vtype = 'L'; break; + case MCHAR: vtype = 'C'; break; #ifdef FEAT_VISUAL - case MBLOCK: vtype = 'B'; break; + case MBLOCK: vtype = 'B'; break; #endif - } - m->AddData(vimselectiontype, B_MIME_TYPE, (void *)&vtype, 1); - - vim_free(str); - - be_clipboard->Commit(); - be_clipboard->Unlock(); } + m->AddData(vimselectiontype, B_MIME_TYPE, (void *)&vtype, 1); + + vim_free(str); + + be_clipboard->Commit(); + be_clipboard->Unlock(); + } } #endif // FEAT_CLIPBOARD @@ -5008,42 +5008,42 @@ clip_mch_set_selection(Clipboard_T *cbd) */ char_u * gui_mch_browse( - int saving, - char_u *title, - char_u *dflt, - char_u *ext, - char_u *initdir, - char_u *filter) + int saving, + char_u *title, + char_u *dflt, + char_u *ext, + char_u *initdir, + char_u *filter) { - gui.vimApp->fFilePanel = new BFilePanel((saving == TRUE) ? B_SAVE_PANEL : B_OPEN_PANEL, - NULL, NULL, 0, false, - new BMessage((saving == TRUE) ? 'save' : 'open'), NULL, true); + gui.vimApp->fFilePanel = new BFilePanel((saving == TRUE) ? B_SAVE_PANEL : B_OPEN_PANEL, + NULL, NULL, 0, false, + new BMessage((saving == TRUE) ? 'save' : 'open'), NULL, true); - gui.vimApp->fBrowsedPath.Unset(); + gui.vimApp->fBrowsedPath.Unset(); - gui.vimApp->fFilePanel->Window()->SetTitle((char*)title); - gui.vimApp->fFilePanel->SetPanelDirectory((const char*)initdir); + gui.vimApp->fFilePanel->Window()->SetTitle((char*)title); + gui.vimApp->fFilePanel->SetPanelDirectory((const char*)initdir); - gui.vimApp->fFilePanel->Show(); + gui.vimApp->fFilePanel->Show(); - gui.vimApp->fFilePanelSem = create_sem(0, "FilePanelSem"); + gui.vimApp->fFilePanelSem = create_sem(0, "FilePanelSem"); - while(acquire_sem(gui.vimApp->fFilePanelSem) == B_INTERRUPTED); + while (acquire_sem(gui.vimApp->fFilePanelSem) == B_INTERRUPTED); - char_u *fileName = NULL; - status_t result = gui.vimApp->fBrowsedPath.InitCheck(); - if(result == B_OK) { - fileName = vim_strsave((char_u*)gui.vimApp->fBrowsedPath.Path()); - } else - if(result != B_NO_INIT) { - fprintf(stderr, "gui_mch_browse: BPath error: %#08x (%s)\n", - result, strerror(result)); - } + char_u *fileName = NULL; + status_t result = gui.vimApp->fBrowsedPath.InitCheck(); + if (result == B_OK) { + fileName = vim_strsave((char_u*)gui.vimApp->fBrowsedPath.Path()); + } else + if (result != B_NO_INIT) { + fprintf(stderr, "gui_mch_browse: BPath error: %#08x (%s)\n", + result, strerror(result)); + } - delete gui.vimApp->fFilePanel; - gui.vimApp->fFilePanel = NULL; + delete gui.vimApp->fFilePanel; + gui.vimApp->fFilePanel = NULL; - return fileName; + return fileName; } #endif // FEAT_BROWSE @@ -5052,34 +5052,34 @@ gui_mch_browse( /* * Create a dialog dynamically from the parameter strings. - * type = type of dialog (question, alert, etc.) - * title = dialog title. may be NULL for default title. - * message = text to display. Dialog sizes to accommodate it. - * buttons = '\n' separated list of button captions, default first. + * type = type of dialog (question, alert, etc.) + * title = dialog title. may be NULL for default title. + * message = text to display. Dialog sizes to accommodate it. + * buttons = '\n' separated list of button captions, default first. * dfltbutton = number of default button. * * This routine returns 1 if the first button is pressed, - * 2 for the second, etc. + * 2 for the second, etc. * - * 0 indicates Esc was pressed. - * -1 for unexpected error + * 0 indicates Esc was pressed. + * -1 for unexpected error * * If stubbing out this fn, return 1. */ int gui_mch_dialog( - int type, - char_u *title, - char_u *message, - char_u *buttons, - int dfltbutton, - char_u *textfield, - int ex_cmd) + int type, + char_u *title, + char_u *message, + char_u *buttons, + int dfltbutton, + char_u *textfield, + int ex_cmd) { - VimDialog *dialog = new VimDialog(type, (char*)title, (char*)message, - (char*)buttons, dfltbutton, (char*)textfield, ex_cmd); - return dialog->Go(); + VimDialog *dialog = new VimDialog(type, (char*)title, (char*)message, + (char*)buttons, dfltbutton, (char*)textfield, ex_cmd); + return dialog->Go(); } #endif // FEAT_GUI_DIALOG @@ -5091,50 +5091,50 @@ gui_mch_dialog( guicolor_T gui_mch_get_rgb(guicolor_T pixel) { - rgb_color rgb = GUI_TO_RGB(pixel); + rgb_color rgb = GUI_TO_RGB(pixel); - return ((rgb.red & 0xff) << 16) + ((rgb.green & 0xff) << 8) - + (rgb.blue & 0xff); + return ((rgb.red & 0xff) << 16) + ((rgb.green & 0xff) << 8) + + (rgb.blue & 0xff); } - void + void gui_mch_setmouse(int x, int y) { - TRACE(); - // TODO + TRACE(); + // TODO } #ifdef FEAT_MBYTE_IME - void + void im_set_position(int row, int col) { - if(gui.vimWindow->Lock()) - { - gui.vimTextArea->DrawIMString(); - gui.vimWindow->Unlock(); - } - return; + if (gui.vimWindow->Lock()) + { + gui.vimTextArea->DrawIMString(); + gui.vimWindow->Unlock(); + } + return; } #endif - void + void gui_mch_show_toolbar(int showit) { - VimToolbar *toolbar = gui.vimForm->ToolBar(); - gui.toolbar_height = (toolbar && showit) ? toolbar->ToolbarHeight() : 0.; + VimToolbar *toolbar = gui.vimForm->ToolBar(); + gui.toolbar_height = (toolbar && showit) ? toolbar->ToolbarHeight() : 0.; } - void + void gui_mch_set_toolbar_pos(int x, int y, int w, int h) { - VimToolbar *toolbar = gui.vimForm->ToolBar(); - if(toolbar != NULL) { - if (gui.vimWindow->Lock()) { - toolbar->MoveTo(x, y); - toolbar->ResizeTo(w - 1, h - 1); - gui.vimWindow->Unlock(); - } + VimToolbar *toolbar = gui.vimForm->ToolBar(); + if (toolbar != NULL) { + if (gui.vimWindow->Lock()) { + toolbar->MoveTo(x, y); + toolbar->ResizeTo(w - 1, h - 1); + gui.vimWindow->Unlock(); } + } } #if defined(FEAT_GUI_TABLINE) || defined(PROTO) @@ -5145,28 +5145,28 @@ gui_mch_set_toolbar_pos(int x, int y, int w, int h) void gui_mch_show_tabline(int showit) { - VimTabLine *tabLine = gui.vimForm->TabLine(); + VimTabLine *tabLine = gui.vimForm->TabLine(); if (tabLine == NULL) - return; + return; if (!showit != !gui.vimForm->IsShowingTabLine()) { - gui.vimForm->SetShowingTabLine(showit != 0); - gui.tabline_height = gui.vimForm->TablineHeight(); + gui.vimForm->SetShowingTabLine(showit != 0); + gui.tabline_height = gui.vimForm->TablineHeight(); } } - void + void gui_mch_set_tabline_pos(int x, int y, int w, int h) { - VimTabLine *tabLine = gui.vimForm->TabLine(); - if(tabLine != NULL) { - if (gui.vimWindow->Lock()) { - tabLine->MoveTo(x, y); - tabLine->ResizeTo(w - 1, h - 1); - gui.vimWindow->Unlock(); - } + VimTabLine *tabLine = gui.vimForm->TabLine(); + if (tabLine != NULL) { + if (gui.vimWindow->Lock()) { + tabLine->MoveTo(x, y); + tabLine->ResizeTo(w - 1, h - 1); + gui.vimWindow->Unlock(); } + } } /* @@ -5175,7 +5175,7 @@ gui_mch_set_tabline_pos(int x, int y, int w, int h) int gui_mch_showing_tabline() { - VimTabLine *tabLine = gui.vimForm->TabLine(); + VimTabLine *tabLine = gui.vimForm->TabLine(); return tabLine != NULL && gui.vimForm->IsShowingTabLine(); } @@ -5186,41 +5186,41 @@ gui_mch_showing_tabline() gui_mch_update_tabline() { tabpage_T *tp; - int nr = 0; - int curtabidx = 0; + int nr = 0; + int curtabidx = 0; - VimTabLine *tabLine = gui.vimForm->TabLine(); + VimTabLine *tabLine = gui.vimForm->TabLine(); if (tabLine == NULL) - return; + return; - gui.vimWindow->Lock(); + gui.vimWindow->Lock(); // Add a label for each tab page. They all contain the same text area. for (tp = first_tabpage; tp != NULL; tp = tp->tp_next, ++nr) { - if (tp == curtab) - curtabidx = nr; + if (tp == curtab) + curtabidx = nr; - BTab* tab = tabLine->TabAt(nr); + BTab* tab = tabLine->TabAt(nr); - if (tab == NULL) { - tab = new VimTabLine::VimTab(); - tabLine->AddTab(NULL, tab); - } + if (tab == NULL) { + tab = new VimTabLine::VimTab(); + tabLine->AddTab(NULL, tab); + } - get_tabline_label(tp, FALSE); - tab->SetLabel((const char*)NameBuff); - tabLine->Invalidate(); + get_tabline_label(tp, FALSE); + tab->SetLabel((const char*)NameBuff); + tabLine->Invalidate(); } // Remove any old labels. - while (nr < tabLine->CountTabs()) - tabLine->RemoveTab(nr); + while (nr < tabLine->CountTabs()) + tabLine->RemoveTab(nr); - if(tabLine->Selection() != curtabidx) - tabLine->Select(curtabidx); + if (tabLine->Selection() != curtabidx) + tabLine->Select(curtabidx); - gui.vimWindow->Unlock(); + gui.vimWindow->Unlock(); } /* @@ -5229,16 +5229,16 @@ gui_mch_update_tabline() void gui_mch_set_curtab(int nr) { - VimTabLine *tabLine = gui.vimForm->TabLine(); - if(tabLine == NULL) - return; + VimTabLine *tabLine = gui.vimForm->TabLine(); + if (tabLine == NULL) + return; - gui.vimWindow->Lock(); + gui.vimWindow->Lock(); - if(tabLine->Selection() != nr -1) - tabLine->Select(nr -1); + if (tabLine->Selection() != nr -1) + tabLine->Select(nr -1); - gui.vimWindow->Unlock(); + gui.vimWindow->Unlock(); } #endif // FEAT_GUI_TABLINE diff --git a/src/version.c b/src/version.c index d2e7451c13..3764629097 100644 --- a/src/version.c +++ b/src/version.c @@ -746,6 +746,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 631, /**/ 630, /**/ From 92c461ef1b3b58c7dd4835bc881769f0f84e8ad0 Mon Sep 17 00:00:00 2001 From: Bram Moolenaar Date: Fri, 24 Apr 2020 22:19:00 +0200 Subject: [PATCH 026/230] patch 8.2.0632: crash when using Haiku Problem: Crash when using Haiku. Solution: Lock the screen. (closes #5975, closes #5973) --- src/screen.c | 4 ++++ src/version.c | 2 ++ 2 files changed, 6 insertions(+) diff --git a/src/screen.c b/src/screen.c index d73e7c6941..845c5b2103 100644 --- a/src/screen.c +++ b/src/screen.c @@ -3881,6 +3881,10 @@ screen_del_lines( clip_scroll_selection(line_count); #endif +#ifdef FEAT_GUI_HAIKU + vim_lock_screen(); +#endif + #ifdef FEAT_GUI // Don't update the GUI cursor here, ScreenLines[] is invalid until the // scrolling is actually carried out. diff --git a/src/version.c b/src/version.c index 3764629097..3483a42bde 100644 --- a/src/version.c +++ b/src/version.c @@ -746,6 +746,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 632, /**/ 631, /**/ From 9d8d0b5c644ea53364d04403740b3f23e57c1497 Mon Sep 17 00:00:00 2001 From: Bram Moolenaar Date: Fri, 24 Apr 2020 22:47:31 +0200 Subject: [PATCH 027/230] patch 8.2.0633: crash when using null partial in filter() Problem: Crash when using null partial in filter(). Solution: Fix crash. Add more tests. (Yegappan Lakshmanan, closes #5976) --- src/eval.c | 8 ++++++-- src/testdir/test_blob.vim | 1 + src/testdir/test_channel.vim | 3 +++ src/testdir/test_eval_stuff.vim | 2 +- src/testdir/test_execute_func.vim | 4 +++- src/testdir/test_expr.vim | 24 ++++++++++++++++++++++++ src/testdir/test_filter_map.vim | 4 ++++ src/testdir/test_fold.vim | 25 +++++++++++++++++++++++++ src/testdir/test_functions.vim | 2 ++ src/testdir/test_let.vim | 25 +++++++++++++++++++++++++ src/testdir/test_listdict.vim | 2 ++ src/testdir/test_partial.vim | 12 ++++++++++++ src/testdir/test_usercommands.vim | 4 ++++ src/version.c | 2 ++ 14 files changed, 114 insertions(+), 4 deletions(-) diff --git a/src/eval.c b/src/eval.c index 260ce96f12..659588f1d7 100644 --- a/src/eval.c +++ b/src/eval.c @@ -241,6 +241,9 @@ eval_expr_typval(typval_T *expr, typval_T *argv, int argc, typval_T *rettv) { partial_T *partial = expr->vval.v_partial; + if (partial == NULL) + return FAIL; + if (partial->pt_func != NULL && partial->pt_func->uf_dfunc_idx >= 0) { if (call_def_function(partial->pt_func, argc, argv, rettv) == FAIL) @@ -6416,8 +6419,9 @@ typval_compare( && typ1->vval.v_partial == NULL) || (typ2->v_type == VAR_PARTIAL && typ2->vval.v_partial == NULL)) - // when a partial is NULL assume not equal - n1 = FALSE; + // When both partials are NULL, then they are equal. + // Otherwise they are not equal. + n1 = (typ1->vval.v_partial == typ2->vval.v_partial); else if (type_is) { if (typ1->v_type == VAR_FUNC && typ2->v_type == VAR_FUNC) diff --git a/src/testdir/test_blob.vim b/src/testdir/test_blob.vim index 4b6774fc9d..3c1510136a 100644 --- a/src/testdir/test_blob.vim +++ b/src/testdir/test_blob.vim @@ -142,6 +142,7 @@ func Test_blob_compare() let b2 = b1[:] call assert_true(b1 == b2) call assert_false(b1 is b2) + call assert_true(b1 isnot b2) call assert_fails('let x = b1 > b2') call assert_fails('let x = b1 < b2') diff --git a/src/testdir/test_channel.vim b/src/testdir/test_channel.vim index cf51a536b5..9c51c640d6 100644 --- a/src/testdir/test_channel.vim +++ b/src/testdir/test_channel.vim @@ -1203,6 +1203,7 @@ func Test_out_cb() \ 'err_cb': dict.errHandler, \ 'err_mode': 'json'}) call assert_equal("run", job_status(job)) + call test_garbagecollect_now() try let g:Ch_outmsg = '' let g:Ch_errmsg = '' @@ -1818,6 +1819,7 @@ func Test_read_nonl_in_close_cb() let g:out = '' let arg = 'import sys;sys.stdout.write("1\n2\n3")' call job_start([s:python, '-c', arg], {'close_cb': function('s:close_cb')}) + call test_garbagecollect_now() call WaitForAssert({-> assert_equal('123', g:out)}) unlet g:out delfunc s:close_cb @@ -1828,6 +1830,7 @@ func Test_read_from_terminated_job() let arg = 'import os,sys;os.close(1);sys.stderr.write("test\n")' call job_start([s:python, '-c', arg], {'callback': {-> execute('let g:linecount += 1')}}) call WaitForAssert({-> assert_equal(1, g:linecount)}) + call test_garbagecollect_now() unlet g:linecount endfunc diff --git a/src/testdir/test_eval_stuff.vim b/src/testdir/test_eval_stuff.vim index 8feeb36738..cd9611c461 100644 --- a/src/testdir/test_eval_stuff.vim +++ b/src/testdir/test_eval_stuff.vim @@ -217,7 +217,7 @@ func Test_scriptversion_fail() call delete('Xversionscript') endfunc -func Test_excute_null() +func Test_execute_cmd_with_null() call assert_fails('execute test_null_list()', 'E730:') call assert_fails('execute test_null_dict()', 'E731:') call assert_fails('execute test_null_blob()', 'E976:') diff --git a/src/testdir/test_execute_func.vim b/src/testdir/test_execute_func.vim index 235107c23b..e02b08eb4b 100644 --- a/src/testdir/test_execute_func.vim +++ b/src/testdir/test_execute_func.vim @@ -132,7 +132,7 @@ func Test_win_execute_other_tab() unlet xyz endfunc -func Test_execute_null() +func Test_execute_func_with_null() call assert_equal("", execute(test_null_string())) call assert_equal("", execute(test_null_list())) call assert_fails('call execute(test_null_dict())', 'E731:') @@ -143,3 +143,5 @@ func Test_execute_null() call assert_fails('call execute(test_null_channel())', 'E908:') endif endfunc + +" vim: shiftwidth=2 sts=2 expandtab diff --git a/src/testdir/test_expr.vim b/src/testdir/test_expr.vim index ce16793810..c8b5464f41 100644 --- a/src/testdir/test_expr.vim +++ b/src/testdir/test_expr.vim @@ -1,5 +1,7 @@ " Tests for expressions. +source check.vim + func Test_equal() let base = {} func base.method() @@ -20,6 +22,8 @@ func Test_equal() call assert_false([base.method] == [instance.other]) call assert_fails('echo base.method > instance.method') + call assert_equal(0, test_null_function() == function('min')) + call assert_equal(1, test_null_function() == test_null_function()) endfunc func Test_version() @@ -583,4 +587,24 @@ func Test_expr_eval_error() call assert_fails("let v = -{}", 'E728:') endfunc +" Test for float value comparison +func Test_float_compare() + CheckFeature float + call assert_true(1.2 == 1.2) + call assert_true(1.0 != 1.2) + call assert_true(1.2 > 1.0) + call assert_true(1.2 >= 1.2) + call assert_true(1.0 < 1.2) + call assert_true(1.2 <= 1.2) + call assert_true(+0.0 == -0.0) + " two NaNs (not a number) are not equal + call assert_true(sqrt(-4.01) != (0.0 / 0.0)) + " two inf (infinity) are equal + call assert_true((1.0 / 0) == (2.0 / 0)) + " two -inf (infinity) are equal + call assert_true(-(1.0 / 0) == -(2.0 / 0)) + " +infinity != -infinity + call assert_true((1.0 / 0) != -(2.0 / 0)) +endfunc + " vim: shiftwidth=2 sts=2 expandtab diff --git a/src/testdir/test_filter_map.vim b/src/testdir/test_filter_map.vim index fc9c741bb3..0e47badc20 100644 --- a/src/testdir/test_filter_map.vim +++ b/src/testdir/test_filter_map.vim @@ -99,6 +99,10 @@ func Test_map_filter_fails() call assert_fails("let l = filter([1, 2], {})", 'E731:') call assert_equal(0, map(test_null_list(), '"> " .. v:val')) call assert_equal(0, map(test_null_dict(), '"> " .. v:val')) + call assert_equal([1, 2, 3], filter([1, 2, 3], test_null_function())) + call assert_fails("let l = filter([1, 2], function('min'))", 'E118:') + call assert_equal([1, 2, 3], filter([1, 2, 3], test_null_partial())) + call assert_fails("let l = filter([1, 2], {a, b, c -> 1})", 'E119:') endfunc func Test_map_and_modify() diff --git a/src/testdir/test_fold.vim b/src/testdir/test_fold.vim index 36de13656c..5a4632a2cc 100644 --- a/src/testdir/test_fold.vim +++ b/src/testdir/test_fold.vim @@ -794,3 +794,28 @@ func Test_fold_delete_first_line() bwipe! set foldmethod& endfunc + +" Test for errors in 'foldexpr' +func Test_fold_expr_error() + new + call setline(1, ['one', 'two', 'three']) + + " Return a list from the expression + set foldexpr=[] + set foldmethod=expr + for i in range(3) + call assert_equal(0, foldlevel(i)) + endfor + + " expression error + set foldexpr=[{] + set foldmethod=expr + for i in range(3) + call assert_equal(0, foldlevel(i)) + endfor + + set foldmethod& foldexpr& + close! +endfunc + +" vim: shiftwidth=2 sts=2 expandtab diff --git a/src/testdir/test_functions.vim b/src/testdir/test_functions.vim index dbd08041f3..029ea5b978 100644 --- a/src/testdir/test_functions.vim +++ b/src/testdir/test_functions.vim @@ -1239,6 +1239,8 @@ func Test_col() call assert_equal(0, col([2, '$'])) call assert_equal(0, col([1, 100])) call assert_equal(0, col([1])) + call assert_equal(0, col(test_null_list())) + call assert_fails('let c = col({})', 'E731:') " test for getting the visual start column func T() diff --git a/src/testdir/test_let.vim b/src/testdir/test_let.vim index e0d543c6ce..f135a2f02d 100644 --- a/src/testdir/test_let.vim +++ b/src/testdir/test_let.vim @@ -81,6 +81,24 @@ func Test_let() let l:Test_Local_Var = {'k' : 5} call assert_match("\nl:Test_Local_Var {'k': 5}", execute('let l:')) call assert_match("v:errors []", execute('let v:')) + + " Test for assigning multiple list items + let l = [1, 2, 3] + let [l[0], l[1]] = [10, 20] + call assert_equal([10, 20, 3], l) + + " Test for errors in conditional expression + call assert_fails('let val = [] ? 1 : 2', 'E745:') + call assert_fails('let val = 1 ? 5+ : 6', 'E121:') + call assert_fails('let val = 1 ? 0 : 5+', 'E15:') + call assert_false(exists('val')) + + " Test for errors in logical operators + let @a = 'if [] || 0 | let val = 2 | endif' + call assert_fails('exe @a', 'E745:') + call assert_fails('call feedkeys(":let val = 0 || []\", "xt")', 'E745:') + call assert_fails('exe "let val = [] && 5"', 'E745:') + call assert_fails('exe "let val = 6 && []"', 'E745:') endfunc func s:set_arg1(a) abort @@ -282,13 +300,20 @@ func Test_let_errors() let d = {'k' : 4} call assert_fails('let d.# = 5', 'E713:') call assert_fails('let d.m += 5', 'E734:') + call assert_fails('let m = d[{]', 'E15:') let l = [1, 2] call assert_fails('let l[2] = 0', 'E684:') call assert_fails('let l[0:1] = [1, 2, 3]', 'E710:') call assert_fails('let l[-2:-3] = [3, 4]', 'E684:') call assert_fails('let l[0:4] = [5, 6]', 'E711:') + call assert_fails('let l -= 2', 'E734:') + call assert_fails('let l += 2', 'E734:') call assert_fails('let g:["a;b"] = 10', 'E461:') call assert_fails('let g:.min = function("max")', 'E704:') + if has('channel') + let ch = test_null_channel() + call assert_fails('let ch += 1', 'E734:') + endif " This test works only when the language is English if v:lang == "C" || v:lang =~ '^[Ee]n' diff --git a/src/testdir/test_listdict.vim b/src/testdir/test_listdict.vim index a2cc6b5a2d..87d7a2c94e 100644 --- a/src/testdir/test_listdict.vim +++ b/src/testdir/test_listdict.vim @@ -943,6 +943,7 @@ func Test_null_list() call assert_equal(0, uniq(l)) call assert_fails("let k = [] + l", 'E15:') call assert_fails("let k = l + []", 'E15:') + call assert_equal(0, len(copy(test_null_list()))) endfunc " Test for a null dict @@ -959,6 +960,7 @@ func Test_null_dict() call assert_equal('{}', string(d)) call assert_fails('let x = test_null_dict()[10]') call assert_equal({}, {}) + call assert_equal(0, len(copy(test_null_dict()))) endfunc " vim: shiftwidth=2 sts=2 expandtab diff --git a/src/testdir/test_partial.vim b/src/testdir/test_partial.vim index 1e682d5229..5b273db230 100644 --- a/src/testdir/test_partial.vim +++ b/src/testdir/test_partial.vim @@ -63,6 +63,7 @@ endfunc func Test_partial_dict() let dict = {'name': 'hello'} let Cb = function('MyDictFunc', ["foo", "bar"], dict) + call test_garbagecollect_now() call assert_equal("hello/foo/bar", Cb()) call assert_fails('Cb("xxx")', 'E492:') @@ -282,6 +283,7 @@ func Test_ref_job_partial_dict() let g:ref_job = job_start('echo') let d = {'a': 'b'} call job_setoptions(g:ref_job, {'exit_cb': function('Ignored2', [], d)}) + call test_garbagecollect_now() endif endfunc @@ -391,6 +393,16 @@ func Test_compare_partials() call assert_true(F1 isnot# F2) " Different functions call assert_true(F1 isnot# F1d1) " Partial /= non-partial call assert_true(d1.f1 isnot# d1.f1) " handle_subscript creates new partial each time + + " compare two null partials + let N1 = test_null_partial() + let N2 = N1 + call assert_true(N1 is N2) + call assert_true(N1 == N2) + + " compare a partial and a null partial + call assert_false(N1 == F1) + call assert_false(F1 is N1) endfunc " vim: shiftwidth=2 sts=2 expandtab diff --git a/src/testdir/test_usercommands.vim b/src/testdir/test_usercommands.vim index 7f87e27aee..c38424f1ee 100644 --- a/src/testdir/test_usercommands.vim +++ b/src/testdir/test_usercommands.vim @@ -364,6 +364,10 @@ func Test_CmdCompletion() com! -complete=custom, DoCmd call assert_beeps("call feedkeys(':DoCmd \t', 'tx')") + " custom completion failure with the wrong function + com! -complete=custom,min DoCmd + call assert_fails("call feedkeys(':DoCmd \t', 'tx')", 'E118:') + delcom DoCmd endfunc diff --git a/src/version.c b/src/version.c index 3483a42bde..81f5a33899 100644 --- a/src/version.c +++ b/src/version.c @@ -746,6 +746,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 633, /**/ 632, /**/ From 92b83ccfda7a1d654ccaaf161a9c8a8e01fbcf76 Mon Sep 17 00:00:00 2001 From: Bram Moolenaar Date: Sat, 25 Apr 2020 15:24:44 +0200 Subject: [PATCH 028/230] patch 8.2.0634: crash with null partial and blob Problem: Crash with null partial and blob. Solution: Check for NULL pointer. Add more tests. (Yegappan Lakshmanan, closes #5984) --- src/eval.c | 4 +++- src/list.c | 3 +++ src/testdir/test_blob.vim | 6 +++++ src/testdir/test_bufwintabinfo.vim | 1 + src/testdir/test_cd.vim | 1 + src/testdir/test_channel.vim | 4 ++++ src/testdir/test_cursor_func.vim | 1 + src/testdir/test_eval_stuff.vim | 4 ++++ src/testdir/test_expr.vim | 3 ++- src/testdir/test_filter_map.vim | 2 ++ src/testdir/test_fnamemodify.vim | 4 ++++ src/testdir/test_functions.vim | 34 ++++++++++++++++++++++++++++ src/testdir/test_getvar.vim | 5 +++++ src/testdir/test_listdict.vim | 36 +++++++++++++++++++++++++++--- src/testdir/test_messages.vim | 3 +++ src/testdir/test_partial.vim | 2 ++ src/testdir/test_quickfix.vim | 12 ++++++++++ src/testdir/test_tabpage.vim | 2 ++ src/testdir/test_vimscript.vim | 12 ++++++++++ src/version.c | 2 ++ 20 files changed, 136 insertions(+), 5 deletions(-) diff --git a/src/eval.c b/src/eval.c index 659588f1d7..4bd45e9ceb 100644 --- a/src/eval.c +++ b/src/eval.c @@ -3682,7 +3682,9 @@ partial_name(partial_T *pt) { if (pt->pt_name != NULL) return pt->pt_name; - return pt->pt_func->uf_name; + if (pt->pt_func != NULL) + return pt->pt_func->uf_name; + return (char_u *)""; } static void diff --git a/src/list.c b/src/list.c index dfd370b544..eb76cc6831 100644 --- a/src/list.c +++ b/src/list.c @@ -2167,6 +2167,9 @@ f_insert(typval_T *argvars, typval_T *rettv) int val, len; char_u *p; + if (argvars[0].vval.v_blob == NULL) + return; + len = blob_len(argvars[0].vval.v_blob); if (argvars[2].v_type != VAR_UNKNOWN) { diff --git a/src/testdir/test_blob.vim b/src/testdir/test_blob.vim index 3c1510136a..46b7b0227f 100644 --- a/src/testdir/test_blob.vim +++ b/src/testdir/test_blob.vim @@ -33,6 +33,7 @@ func Test_blob_create() call assert_fails('let b = 0z.') call assert_fails('let b = 0z001122.') call assert_fails('call get("", 1)', 'E896:') + call assert_equal(0, len(test_null_blob())) endfunc " assignment to a blob @@ -100,6 +101,7 @@ func Test_blob_get() call assert_equal(999, get(b, 5, 999)) call assert_equal(-1, get(b, -8)) call assert_equal(999, get(b, -8, 999)) + call assert_equal(10, get(test_null_blob(), 2, 10)) call assert_equal(0x00, b[0]) call assert_equal(0x22, b[2]) @@ -117,6 +119,7 @@ func Test_blob_to_string() call assert_equal('0z00112233', string(b)) call remove(b, 0, 3) call assert_equal('0z', string(b)) + call assert_equal('0z', string(test_null_blob())) endfunc func Test_blob_compare() @@ -251,6 +254,7 @@ func Test_blob_func_remove() call assert_fails("call remove(b, 3, 2)", 'E979:') call assert_fails("call remove(1, 0)", 'E896:') call assert_fails("call remove(b, b)", 'E974:') + call assert_fails("call remove(test_null_blob(), 1, 2)", 'E979:') endfunc func Test_blob_read_write() @@ -313,6 +317,7 @@ func Test_blob_insert() call assert_fails('call insert(b, 0, -20)', 'E475:') call assert_fails('call insert(b, 0, 20)', 'E475:') call assert_fails('call insert(b, [])', 'E745:') + call assert_equal(0, insert(test_null_blob(), 0x33)) endfunc func Test_blob_reverse() @@ -320,6 +325,7 @@ func Test_blob_reverse() call assert_equal(0zBEADDE, reverse(0zDEADBE)) call assert_equal(0zADDE, reverse(0zDEAD)) call assert_equal(0zDE, reverse(0zDE)) + call assert_equal(0z, reverse(test_null_blob())) endfunc func Test_blob_json_encode() diff --git a/src/testdir/test_bufwintabinfo.vim b/src/testdir/test_bufwintabinfo.vim index d61670b670..43d0473a14 100644 --- a/src/testdir/test_bufwintabinfo.vim +++ b/src/testdir/test_bufwintabinfo.vim @@ -42,6 +42,7 @@ func Test_getbufwintabinfo() sign undefine Mark enew! endif + call assert_notequal([], getbufinfo(test_null_dict())) only let w1_id = win_getid() diff --git a/src/testdir/test_cd.vim b/src/testdir/test_cd.vim index e5c119e22e..da9ef0830f 100644 --- a/src/testdir/test_cd.vim +++ b/src/testdir/test_cd.vim @@ -119,6 +119,7 @@ func Test_chdir_func() call assert_equal("", d) " Should not crash call chdir(d) + call assert_equal('', chdir([])) only | tabonly call chdir(topdir) diff --git a/src/testdir/test_channel.vim b/src/testdir/test_channel.vim index 9c51c640d6..4ba552bdbe 100644 --- a/src/testdir/test_channel.vim +++ b/src/testdir/test_channel.vim @@ -1139,6 +1139,8 @@ func Test_pipe_null() call assert_equal("run", job_status(job)) call assert_equal('channel fail', string(job_getchannel(job))) call assert_equal('fail', ch_status(job)) + call assert_equal('no process', string(test_null_job())) + call assert_equal('channel fail', string(test_null_channel())) call job_stop(job) endfunc @@ -1706,6 +1708,7 @@ func Test_partial_in_channel_cycle() let d.a = function('string', [d]) try let d.b = ch_open('nowhere:123', {'close_cb': d.a}) + call test_garbagecollect_now() catch call assert_exception('E901:') endtry @@ -1893,6 +1896,7 @@ function Ch_test_close_lambda(port) endif let g:Ch_close_ret = '' call ch_setoptions(handle, {'close_cb': {ch -> execute("let g:Ch_close_ret = 'closed'")}}) + call test_garbagecollect_now() call assert_equal('', ch_evalexpr(handle, 'close me')) call WaitForAssert({-> assert_equal('closed', g:Ch_close_ret)}) diff --git a/src/testdir/test_cursor_func.vim b/src/testdir/test_cursor_func.vim index 7a17958335..0ddfcdadfd 100644 --- a/src/testdir/test_cursor_func.vim +++ b/src/testdir/test_cursor_func.vim @@ -2,6 +2,7 @@ func Test_wrong_arguments() call assert_fails('call cursor(1. 3)', 'E474:') + call assert_fails('call cursor(test_null_list())', 'E474:') endfunc func Test_move_cursor() diff --git a/src/testdir/test_eval_stuff.vim b/src/testdir/test_eval_stuff.vim index cd9611c461..28350bb3e2 100644 --- a/src/testdir/test_eval_stuff.vim +++ b/src/testdir/test_eval_stuff.vim @@ -41,6 +41,9 @@ func Test_mkdir_p() call assert_fails('call mkdir("Xfile", "p")', 'E739') call delete('Xfile') call delete('Xmkdir', 'rf') + call assert_equal(0, mkdir(test_null_string())) + call assert_fails('call mkdir([])', 'E730') + call assert_fails('call mkdir("abc", [], [])', 'E745') endfunc func Test_line_continuation() @@ -223,6 +226,7 @@ func Test_execute_cmd_with_null() call assert_fails('execute test_null_blob()', 'E976:') execute test_null_string() call assert_fails('execute test_null_partial()', 'E729:') + call assert_fails('execute test_unknown()', 'E908:') if has('job') call assert_fails('execute test_null_job()', 'E908:') call assert_fails('execute test_null_channel()', 'E908:') diff --git a/src/testdir/test_expr.vim b/src/testdir/test_expr.vim index c8b5464f41..5fc502df81 100644 --- a/src/testdir/test_expr.vim +++ b/src/testdir/test_expr.vim @@ -24,6 +24,7 @@ func Test_equal() call assert_fails('echo base.method > instance.method') call assert_equal(0, test_null_function() == function('min')) call assert_equal(1, test_null_function() == test_null_function()) + call assert_fails('eval 10 == test_unknown()', 'E685:') endfunc func Test_version() @@ -100,7 +101,7 @@ func Test_loop_over_null_list() endfor endfunc -func Test_set_reg_null_list() +func Test_setreg_null_list() call setreg('x', test_null_list()) endfunc diff --git a/src/testdir/test_filter_map.vim b/src/testdir/test_filter_map.vim index 0e47badc20..0f58685c60 100644 --- a/src/testdir/test_filter_map.vim +++ b/src/testdir/test_filter_map.vim @@ -97,6 +97,8 @@ func Test_map_filter_fails() call assert_fails("let l = filter([1, 2, 3], '{}')", 'E728:') call assert_fails("let l = filter({'k' : 10}, '{}')", 'E728:') call assert_fails("let l = filter([1, 2], {})", 'E731:') + call assert_equal(0, filter(test_null_list(), 0)) + call assert_equal(0, filter(test_null_dict(), 0)) call assert_equal(0, map(test_null_list(), '"> " .. v:val')) call assert_equal(0, map(test_null_dict(), '"> " .. v:val')) call assert_equal([1, 2, 3], filter([1, 2, 3], test_null_function())) diff --git a/src/testdir/test_fnamemodify.vim b/src/testdir/test_fnamemodify.vim index b35f153402..b90d232f95 100644 --- a/src/testdir/test_fnamemodify.vim +++ b/src/testdir/test_fnamemodify.vim @@ -86,4 +86,8 @@ func Test_fnamemodify_er() " :e never includes the whole filename, so "a.b":e:e:e --> "b" call assert_equal('b.c', fnamemodify('a.b.c.d.e', ':r:r:e:e:e')) call assert_equal('b.c', fnamemodify('a.b.c.d.e', ':r:r:e:e:e:e')) + + call assert_equal('', fnamemodify(test_null_string(), test_null_string())) endfunc + +" vim: shiftwidth=2 sts=2 expandtab diff --git a/src/testdir/test_functions.vim b/src/testdir/test_functions.vim index 029ea5b978..a0807ade7a 100644 --- a/src/testdir/test_functions.vim +++ b/src/testdir/test_functions.vim @@ -480,6 +480,7 @@ func Test_pathshorten() call assert_equal('~.f/bar', pathshorten('~.foo/bar')) call assert_equal('.~f/bar', pathshorten('.~foo/bar')) call assert_equal('~/f/bar', pathshorten('~/foo/bar')) + call assert_fails('call pathshorten([])', 'E730:') endfunc func Test_strpart() @@ -970,6 +971,7 @@ func Test_matchstrpos() call assert_equal(['', -1, -1], matchstrpos('testing', 'ing', 8)) call assert_equal(['ing', 1, 4, 7], matchstrpos(['vim', 'testing', 'execute'], 'ing')) call assert_equal(['', -1, -1, -1], matchstrpos(['vim', 'testing', 'execute'], 'img')) + call assert_equal(['', -1, -1], matchstrpos(test_null_list(), '\a')) endfunc func Test_nextnonblank_prevnonblank() @@ -1222,6 +1224,7 @@ func Test_hlexists() syntax off endfunc +" Test for the col() function func Test_col() new call setline(1, 'abcdef') @@ -1332,6 +1335,7 @@ func Test_inputlist() call assert_equal(-2, c) call assert_fails('call inputlist("")', 'E686:') + call assert_fails('call inputlist(test_null_list())', 'E686:') endfunc func Test_balloon_show() @@ -2227,6 +2231,16 @@ func Test_echoraw() call delete('XTest_echoraw') endfunc +" Test for echo highlighting +func Test_echohl() + echohl Search + echo 'Vim' + call assert_equal('Vim', Screenline(&lines)) + " TODO: How to check the highlight group used by echohl? + " ScreenAttrs() returns all zeros. + echohl None +endfunc + " Test for the eval() function func Test_eval() call assert_fails("call eval('5 a')", 'E488:') @@ -2258,7 +2272,27 @@ func Test_getcurpos_setpos() call setpos('.', sp) normal jyl call assert_equal('6', @") + call assert_equal(-1, setpos('.', test_null_list())) + call assert_equal(-1, setpos('.', {})) close! endfunc +" Test for glob() +func Test_glob() + call assert_equal('', glob(test_null_string())) + call assert_equal('', globpath(test_null_string(), test_null_string())) +endfunc + +" Test for browse() +func Test_browse() + CheckFeature browse + call assert_fails('call browse([], "open", "x", "a.c")', 'E745:') +endfunc + +" Test for browsedir() +func Test_browsedir() + CheckFeature browse + call assert_fails('call browsedir("open", [])', 'E730:') +endfunc + " vim: shiftwidth=2 sts=2 expandtab diff --git a/src/testdir/test_getvar.vim b/src/testdir/test_getvar.vim index 5da5991361..7ced44d07c 100644 --- a/src/testdir/test_getvar.vim +++ b/src/testdir/test_getvar.vim @@ -142,6 +142,11 @@ func Test_get_func() call assert_equal({'func has': 'no dict'}, get(l:F, 'dict', {'func has': 'no dict'})) call assert_equal(0, get(l:F, 'dict')) call assert_equal([], get(l:F, 'args')) + let NF = test_null_function() + call assert_equal('', get(NF, 'name')) + call assert_equal(NF, get(NF, 'func')) + call assert_equal(0, get(NF, 'dict')) + call assert_equal([], get(NF, 'args')) endfunc " get({partial}, {what} [, {default}]) - in test_partial.vim diff --git a/src/testdir/test_listdict.vim b/src/testdir/test_listdict.vim index 87d7a2c94e..1dea4a88c5 100644 --- a/src/testdir/test_listdict.vim +++ b/src/testdir/test_listdict.vim @@ -724,6 +724,7 @@ func Test_listdict_compare_complex() call assert_true(dict4 == dict4copy) endfunc +" Test for extending lists and dictionaries func Test_listdict_extend() " Test extend() with lists @@ -926,6 +927,8 @@ func Test_listdict_index() call assert_fails("let l[1.1] = 4", 'E806:') call assert_fails("let l[:i] = [4, 5]", 'E121:') call assert_fails("let l[:3.2] = [4, 5]", 'E806:') + let t = test_unknown() + call assert_fails("echo t[0]", 'E685:') endfunc " Test for a null list @@ -943,7 +946,23 @@ func Test_null_list() call assert_equal(0, uniq(l)) call assert_fails("let k = [] + l", 'E15:') call assert_fails("let k = l + []", 'E15:') - call assert_equal(0, len(copy(test_null_list()))) + call assert_equal(0, len(copy(l))) + call assert_equal(0, count(l, 5)) + call assert_equal([], deepcopy(l)) + call assert_equal(5, get(l, 2, 5)) + call assert_equal(-1, index(l, 2, 5)) + call assert_equal(0, insert(l, 2, -1)) + call assert_equal(0, min(l)) + call assert_equal(0, max(l)) + call assert_equal(0, remove(l, 0, 2)) + call assert_equal([], repeat(l, 2)) + call assert_equal(0, reverse(l)) + call assert_equal(0, sort(l)) + call assert_equal('[]', string(l)) + call assert_equal(0, extend(l, l, 0)) + lockvar l + call assert_equal(1, islocked('l')) + unlockvar l endfunc " Test for a null dict @@ -958,9 +977,20 @@ func Test_null_dict() call assert_equal(0, values(d)) call assert_false(has_key(d, 'k')) call assert_equal('{}', string(d)) - call assert_fails('let x = test_null_dict()[10]') + call assert_fails('let x = d[10]') call assert_equal({}, {}) - call assert_equal(0, len(copy(test_null_dict()))) + call assert_equal(0, len(copy(d))) + call assert_equal(0, count(d, 'k')) + call assert_equal({}, deepcopy(d)) + call assert_equal(20, get(d, 'k', 20)) + call assert_equal(0, min(d)) + call assert_equal(0, max(d)) + call assert_equal(0, remove(d, 'k')) + call assert_equal('{}', string(d)) + call assert_equal(0, extend(d, d, 0)) + lockvar d + call assert_equal(1, islocked('d')) + unlockvar d endfunc " vim: shiftwidth=2 sts=2 expandtab diff --git a/src/testdir/test_messages.vim b/src/testdir/test_messages.vim index ac91aa097b..84808efa09 100644 --- a/src/testdir/test_messages.vim +++ b/src/testdir/test_messages.vim @@ -305,9 +305,12 @@ func Test_null() echom test_null_dict() echom test_null_blob() echom test_null_string() + echom test_null_function() echom test_null_partial() if has('job') echom test_null_job() echom test_null_channel() endif endfunc + +" vim: shiftwidth=2 sts=2 expandtab diff --git a/src/testdir/test_partial.vim b/src/testdir/test_partial.vim index 5b273db230..2fad7b2892 100644 --- a/src/testdir/test_partial.vim +++ b/src/testdir/test_partial.vim @@ -194,6 +194,8 @@ func Test_partial_string() call assert_equal("function('MyFunc', {'one': 1})", string(F)) let F = function('MyFunc', ['foo'], d) call assert_equal("function('MyFunc', ['foo'], {'one': 1})", string(F)) + call assert_equal("function('')", string(test_null_function())) + call assert_equal("function('')", string(test_null_partial())) endfunc func Test_func_unref() diff --git a/src/testdir/test_quickfix.vim b/src/testdir/test_quickfix.vim index c1b50631be..cfd9a35b7d 100644 --- a/src/testdir/test_quickfix.vim +++ b/src/testdir/test_quickfix.vim @@ -2158,6 +2158,18 @@ func Xproperty_tests(cchar) call g:Xsetlist([], 'a', {'context':246}) let d = g:Xgetlist({'context':1}) call assert_equal(246, d.context) + " set other Vim data types as context + call g:Xsetlist([], 'a', {'context' : test_null_blob()}) + if has('channel') + call g:Xsetlist([], 'a', {'context' : test_null_channel()}) + endif + if has('job') + call g:Xsetlist([], 'a', {'context' : test_null_job()}) + endif + call g:Xsetlist([], 'a', {'context' : test_null_function()}) + call g:Xsetlist([], 'a', {'context' : test_null_partial()}) + call g:Xsetlist([], 'a', {'context' : ''}) + call test_garbagecollect_now() if a:cchar == 'l' " Test for copying context across two different location lists new | only diff --git a/src/testdir/test_tabpage.vim b/src/testdir/test_tabpage.vim index 35c9fd0eab..80cc8e5591 100644 --- a/src/testdir/test_tabpage.vim +++ b/src/testdir/test_tabpage.vim @@ -130,6 +130,8 @@ function Test_tabpage() 1tabmove call assert_equal(2, tabpagenr()) + call assert_fails('let t = tabpagenr("#")', 'E15:') + call assert_equal(0, tabpagewinnr(-1)) call assert_fails("99tabmove", 'E16:') call assert_fails("+99tabmove", 'E16:') call assert_fails("-99tabmove", 'E16:') diff --git a/src/testdir/test_vimscript.vim b/src/testdir/test_vimscript.vim index 439114d19b..805787a7ab 100644 --- a/src/testdir/test_vimscript.vim +++ b/src/testdir/test_vimscript.vim @@ -1164,6 +1164,18 @@ func Test_type() call assert_equal(v:t_bool, type(v:true)) call assert_equal(v:t_none, type(v:none)) call assert_equal(v:t_none, type(v:null)) + call assert_equal(v:t_string, type(test_null_string())) + call assert_equal(v:t_func, type(test_null_function())) + call assert_equal(v:t_func, type(test_null_partial())) + call assert_equal(v:t_list, type(test_null_list())) + call assert_equal(v:t_dict, type(test_null_dict())) + if has('job') + call assert_equal(v:t_job, type(test_null_job())) + endif + if has('channel') + call assert_equal(v:t_channel, type(test_null_channel())) + endif + call assert_equal(v:t_blob, type(test_null_blob())) call assert_fails("call type(test_void())", 'E685:') call assert_fails("call type(test_unknown())", 'E685:') diff --git a/src/version.c b/src/version.c index 81f5a33899..b05d3d884f 100644 --- a/src/version.c +++ b/src/version.c @@ -746,6 +746,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 634, /**/ 633, /**/ From e93c968f520ee8d6bc29ccc6e18055ac65e832b3 Mon Sep 17 00:00:00 2001 From: Bram Moolenaar Date: Sat, 25 Apr 2020 15:35:32 +0200 Subject: [PATCH 029/230] patch 8.2.0635: when using 256 colors DarkYellow does not show expected color Problem: When using 256 colors DarkYellow does not show expected color. Solution: Use color 3 instead of 130. (Romain Lafourcade, closes #5985) --- src/highlight.c | 2 +- src/version.c | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/src/highlight.c b/src/highlight.c index 9c9e44599f..64f37a4e8d 100644 --- a/src/highlight.c +++ b/src/highlight.c @@ -524,7 +524,7 @@ static int color_numbers_88[28] = {0, 4, 2, 6, 75, 11, 78, 15, -1}; // for xterm with 256 colors... static int color_numbers_256[28] = {0, 4, 2, 6, - 1, 5, 130, 130, + 1, 5, 130, 3, 248, 248, 7, 7, 242, 242, 12, 81, 10, 121, diff --git a/src/version.c b/src/version.c index b05d3d884f..2fcabeba4f 100644 --- a/src/version.c +++ b/src/version.c @@ -746,6 +746,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 635, /**/ 634, /**/ From 41f6918bf4545de6a80c96d8c80f5f509f9a647f Mon Sep 17 00:00:00 2001 From: Bram Moolenaar Date: Sat, 25 Apr 2020 15:45:37 +0200 Subject: [PATCH 030/230] patch 8.2.0636: :messages does not show the maintainer when $LANG is unset Problem: :messages does not show the maintainer when $LANG is unset. Solution: Call get_mess_lang() if available. (closes #5978) --- src/message.c | 4 ++++ src/version.c | 2 ++ 2 files changed, 6 insertions(+) diff --git a/src/message.c b/src/message.c index fbddfadcbb..04dc4014f3 100644 --- a/src/message.c +++ b/src/message.c @@ -1035,7 +1035,11 @@ ex_messages(exarg_T *eap) if (p == first_msg_hist) { +#ifdef FEAT_MULTI_LANG + s = get_mess_lang(); +#else s = mch_getenv((char_u *)"LANG"); +#endif if (s != NULL && *s != NUL) // The next comment is extracted by xgettext and put in po file for // translators to read. diff --git a/src/version.c b/src/version.c index 2fcabeba4f..7c753e22ab 100644 --- a/src/version.c +++ b/src/version.c @@ -746,6 +746,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 636, /**/ 635, /**/ From 333015a46e916f566763ec44ae8669c0378767d9 Mon Sep 17 00:00:00 2001 From: Bram Moolenaar Date: Sat, 25 Apr 2020 15:54:16 +0200 Subject: [PATCH 031/230] patch 8.2.0637: incsearch highlighting does not work for ":sort!" Problem: Incsearch highlighting does not work for ":sort!". Solution: Skip over the exclamation point. (closes #5983) --- src/ex_getln.c | 4 +++- src/testdir/dumps/Test_incsearch_sort_02.dump | 9 +++++++++ src/testdir/test_search.vim | 5 ++++- src/version.c | 2 ++ 4 files changed, 18 insertions(+), 2 deletions(-) create mode 100644 src/testdir/dumps/Test_incsearch_sort_02.dump diff --git a/src/ex_getln.c b/src/ex_getln.c index 18da926560..7e92ec8992 100644 --- a/src/ex_getln.c +++ b/src/ex_getln.c @@ -249,7 +249,9 @@ do_incsearch_highlighting(int firstc, int *search_delim, incsearch_state_T *is_s } else if (STRNCMP(cmd, "sort", MAX(p - cmd, 3)) == 0) { - // skip over flags + // skip over ! and flags + if (*p == '!') + p = skipwhite(p + 1); while (ASCII_ISALPHA(*(p = skipwhite(p)))) ++p; if (*p == NUL) diff --git a/src/testdir/dumps/Test_incsearch_sort_02.dump b/src/testdir/dumps/Test_incsearch_sort_02.dump new file mode 100644 index 0000000000..ee752e178b --- /dev/null +++ b/src/testdir/dumps/Test_incsearch_sort_02.dump @@ -0,0 +1,9 @@ +|a+0&#ffffff0|n|o|t|h|e|r| |o+1&&|n|e+0&&| |2| @56 +|t|h|a|t| |o+0&#ffff4012|n|e+0&#ffffff0| |3| @59 +|t|h|e| |o+0&#ffff4012|n|e+0&#ffffff0| |1| @60 +|~+0#4040ff13&| @68 +|~| @68 +|~| @68 +|~| @68 +|~| @68 +|:+0#0000000&|s|o|r|t|!| |/|o|n> @59 diff --git a/src/testdir/test_search.vim b/src/testdir/test_search.vim index aaa42352ce..7aaf8db52d 100644 --- a/src/testdir/test_search.vim +++ b/src/testdir/test_search.vim @@ -1136,11 +1136,14 @@ func Test_incsearch_sort_dump() " the 'ambiwidth' check. sleep 100m - " Need to send one key at a time to force a redraw. call term_sendkeys(buf, ':sort ni u /on') call VerifyScreenDump(buf, 'Test_incsearch_sort_01', {}) call term_sendkeys(buf, "\") + call term_sendkeys(buf, ':sort! /on') + call VerifyScreenDump(buf, 'Test_incsearch_sort_02', {}) + call term_sendkeys(buf, "\") + call StopVimInTerminal(buf) call delete('Xis_sort_script') endfunc diff --git a/src/version.c b/src/version.c index 7c753e22ab..28d317922a 100644 --- a/src/version.c +++ b/src/version.c @@ -746,6 +746,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 637, /**/ 636, /**/ From 47a1a8baf9c8eb22b24f667e57a1dab579999a74 Mon Sep 17 00:00:00 2001 From: Bram Moolenaar Date: Sat, 25 Apr 2020 16:41:58 +0200 Subject: [PATCH 032/230] patch 8.2.0638: MS-Windows: messages test fails Problem: MS-Windows: messages test fails. Solution: Clear environment variables. --- src/testdir/test_messages.vim | 3 +++ src/version.c | 2 ++ 2 files changed, 5 insertions(+) diff --git a/src/testdir/test_messages.vim b/src/testdir/test_messages.vim index 84808efa09..3d7245dc63 100644 --- a/src/testdir/test_messages.vim +++ b/src/testdir/test_messages.vim @@ -9,6 +9,9 @@ function Test_messages() set nomore " Avoid the "message maintainer" line. let $LANG = '' + let $LC_ALL = '' + let $LC_MESSAGES = '' + let $LC_COLLATE = '' let arr = map(range(10), '"hello" . v:val') for s in arr diff --git a/src/version.c b/src/version.c index 28d317922a..3ba7452899 100644 --- a/src/version.c +++ b/src/version.c @@ -746,6 +746,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 638, /**/ 637, /**/ From 49b2fb36ca94be14b98caf86420863d9bbe81a24 Mon Sep 17 00:00:00 2001 From: Bram Moolenaar Date: Sat, 25 Apr 2020 17:13:56 +0200 Subject: [PATCH 033/230] patch 8.2.0639: MS-Windows: messages test still fails Problem: MS-Windows: messages test still fails. Solution: Filter out the maintainer message. --- src/testdir/test_messages.vim | 33 +++++++++++++++++---------------- src/version.c | 2 ++ 2 files changed, 19 insertions(+), 16 deletions(-) diff --git a/src/testdir/test_messages.vim b/src/testdir/test_messages.vim index 3d7245dc63..5a2c64cb74 100644 --- a/src/testdir/test_messages.vim +++ b/src/testdir/test_messages.vim @@ -3,21 +3,27 @@ source shared.vim source term_util.vim -function Test_messages() +" Get all messages but drop the maintainer entry. +func GetMessages() + redir => result + redraw | messages + redir END + let msg_list = split(result, "\n") + if msg_list->len() > 0 && msg_list[0] =~ 'Messages maintainer:' + return msg_list[1:] + endif + return msg_list +endfunc + +func Test_messages() let oldmore = &more try set nomore - " Avoid the "message maintainer" line. - let $LANG = '' - let $LC_ALL = '' - let $LC_MESSAGES = '' - let $LC_COLLATE = '' let arr = map(range(10), '"hello" . v:val') for s in arr echomsg s | redraw endfor - let result = '' " get last two messages redir => result @@ -28,24 +34,19 @@ function Test_messages() " clear messages without last one 1messages clear - redir => result - redraw | messages - redir END - let msg_list = split(result, "\n") + let msg_list = GetMessages() call assert_equal(['hello9'], msg_list) " clear all messages messages clear - redir => result - redraw | messages - redir END - call assert_equal('', result) + let msg_list = GetMessages() + call assert_equal([], msg_list) finally let &more = oldmore endtry call assert_fails('message 1', 'E474:') -endfunction +endfunc " Patch 7.4.1696 defined the "clearmode()" function for clearing the mode " indicator (e.g., "-- INSERT --") when ":stopinsert" is invoked. Message diff --git a/src/version.c b/src/version.c index 3ba7452899..70af7b0436 100644 --- a/src/version.c +++ b/src/version.c @@ -746,6 +746,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 639, /**/ 638, /**/ From cfe435d7feacf123ac060747b885f7c4328062ea Mon Sep 17 00:00:00 2001 From: Bram Moolenaar Date: Sat, 25 Apr 2020 20:02:55 +0200 Subject: [PATCH 034/230] patch 8.2.0640: Vim9: expanding does not work Problem: Vim9: expanding does not work. Solution: Find wildcards in not compiled commands. Reorganize test files. --- Filelist | 1 + src/testdir/Make_all.mak | 2 + src/testdir/test_vim9_cmd.vim | 23 ++ src/testdir/test_vim9_disassemble.vim | 26 ++ src/testdir/test_vim9_expr.vim | 348 ++++++++++++-------------- src/testdir/test_vim9_script.vim | 20 +- src/testdir/vim9.vim | 28 +++ src/version.c | 2 + src/vim9.h | 1 + src/vim9compile.c | 93 ++++++- src/vim9execute.c | 43 ++++ 11 files changed, 373 insertions(+), 214 deletions(-) create mode 100644 src/testdir/test_vim9_cmd.vim create mode 100644 src/testdir/vim9.vim diff --git a/Filelist b/Filelist index 581a72d1aa..ff5994ba0a 100644 --- a/Filelist +++ b/Filelist @@ -162,6 +162,7 @@ SRC_ALL = \ src/testdir/setup.vim \ src/testdir/setup_gui.vim \ src/testdir/shared.vim \ + src/testdir/vim9.vim \ src/testdir/summarize.vim \ src/testdir/term_util.vim \ src/testdir/view_util.vim \ diff --git a/src/testdir/Make_all.mak b/src/testdir/Make_all.mak index db74f05a3f..772c083347 100644 --- a/src/testdir/Make_all.mak +++ b/src/testdir/Make_all.mak @@ -45,12 +45,14 @@ SCRIPTS_GUI = # Tests for Vim9 script. TEST_VIM9 = \ + test_vim9_cmd \ test_vim9_disassemble \ test_vim9_expr \ test_vim9_func \ test_vim9_script TEST_VIM9_RES = \ + test_vim9_cmd.res \ test_vim9_disassemble.res \ test_vim9_expr.res \ test_vim9_func.res \ diff --git a/src/testdir/test_vim9_cmd.vim b/src/testdir/test_vim9_cmd.vim new file mode 100644 index 0000000000..7ccd1f70cc --- /dev/null +++ b/src/testdir/test_vim9_cmd.vim @@ -0,0 +1,23 @@ +" Test commands that are not compiled in a :def function + +source vim9.vim + +def Test_edit_wildcards() + let filename = 'Xtest' + edit `=filename` + assert_equal('Xtest', bufname()) + + let filenr = 123 + edit Xtest`=filenr` + assert_equal('Xtest123', bufname()) + + filenr = 77 + edit `=filename``=filenr` + assert_equal('Xtest77', bufname()) + + edit X`=filename`xx`=filenr`yy + assert_equal('XXtestxx77yy', bufname()) +enddef + + +" vim: ts=8 sw=2 sts=2 expandtab tw=80 fdm=marker diff --git a/src/testdir/test_vim9_disassemble.vim b/src/testdir/test_vim9_disassemble.vim index 89ca66f11b..4e2caf09f1 100644 --- a/src/testdir/test_vim9_disassemble.vim +++ b/src/testdir/test_vim9_disassemble.vim @@ -53,6 +53,32 @@ def Test_disassemble_load() res) enddef +def s:EditExpand() + let filename = "file" + let filenr = 123 + edit the`=filename``=filenr`.txt +enddef + +def Test_disassemble_exec_expr() + let res = execute('disass s:EditExpand') + assert_match('\d*_EditExpand.*' .. + ' let filename = "file".*' .. + '\d PUSHS "file".*' .. + '\d STORE $0.*' .. + ' let filenr = 123.*' .. + '\d STORE 123 in $1.*' .. + ' edit the`=filename``=filenr`.txt.*' .. + '\d PUSHS "edit the".*' .. + '\d LOAD $0.*' .. + '\d LOAD $1.*' .. + '\d 2STRING stack\[-1\].*' .. + '\d PUSHS ".txt".*' .. + '\d EXECCONCAT 4.*' .. + '\d PUSHNR 0.*' .. + '\d RETURN', + res) +enddef + def s:ScriptFuncPush() let localbool = true let localspec = v:none diff --git a/src/testdir/test_vim9_expr.vim b/src/testdir/test_vim9_expr.vim index fe3752c8cf..42a99261fb 100644 --- a/src/testdir/test_vim9_expr.vim +++ b/src/testdir/test_vim9_expr.vim @@ -1,33 +1,7 @@ " Tests for Vim9 script expressions source check.vim - -" Check that "line" inside ":def" results in an "error" message. -func CheckDefFailure(line, error) - call writefile(['def! Func()', a:line, 'enddef'], 'Xdef') - call assert_fails('so Xdef', a:error, a:line) - call delete('Xdef') -endfunc - -func CheckDefFailureMult(lines, error) - call writefile(['def! Func()'] + a:lines + ['enddef'], 'Xdef') - call assert_fails('so Xdef', a:error, join(a:lines, ' | ')) - call delete('Xdef') -endfunc - -" Check that "line" inside ":def" results in an "error" message when executed. -func CheckDefExecFailure(line, error) - call writefile(['def! Func()', a:line, 'enddef'], 'Xdef') - so Xdef - call assert_fails('call Func()', a:error, a:line) - call delete('Xdef') -endfunc - -func CheckDefFailureList(lines, error) - call writefile(['def! Func()'] + a:lines + ['enddef'], 'Xdef') - call assert_fails('so Xdef', a:error, string(a:lines)) - call delete('Xdef') -endfunc +source vim9.vim " test cond ? expr : expr def Test_expr1() @@ -59,18 +33,18 @@ def Test_expr1() enddef func Test_expr1_fails() - call CheckDefFailure("let x = 1 ? 'one'", "Missing ':' after '?'") - call CheckDefFailure("let x = 1 ? 'one' : xxx", "E1001:") + call CheckDefFailure(["let x = 1 ? 'one'"], "Missing ':' after '?'") + call CheckDefFailure(["let x = 1 ? 'one' : xxx"], "E1001:") let msg = "white space required before and after '?'" - call CheckDefFailure("let x = 1? 'one' : 'two'", msg) - call CheckDefFailure("let x = 1 ?'one' : 'two'", msg) - call CheckDefFailure("let x = 1?'one' : 'two'", msg) + call CheckDefFailure(["let x = 1? 'one' : 'two'"], msg) + call CheckDefFailure(["let x = 1 ?'one' : 'two'"], msg) + call CheckDefFailure(["let x = 1?'one' : 'two'"], msg) let msg = "white space required before and after ':'" - call CheckDefFailure("let x = 1 ? 'one': 'two'", msg) - call CheckDefFailure("let x = 1 ? 'one' :'two'", msg) - call CheckDefFailure("let x = 1 ? 'one':'two'", msg) + call CheckDefFailure(["let x = 1 ? 'one': 'two'"], msg) + call CheckDefFailure(["let x = 1 ? 'one' :'two'"], msg) + call CheckDefFailure(["let x = 1 ? 'one':'two'"], msg) endfunc " TODO: define inside test function @@ -107,11 +81,11 @@ enddef func Test_expr2_fails() let msg = "white space required before and after '||'" - call CheckDefFailure("let x = 1||2", msg) - call CheckDefFailure("let x = 1 ||2", msg) - call CheckDefFailure("let x = 1|| 2", msg) + call CheckDefFailure(["let x = 1||2"], msg) + call CheckDefFailure(["let x = 1 ||2"], msg) + call CheckDefFailure(["let x = 1|| 2"], msg) - call CheckDefFailure("let x = 1 || xxx", 'E1001:') + call CheckDefFailure(["let x = 1 || xxx"], 'E1001:') endfunc " test && @@ -148,9 +122,9 @@ enddef func Test_expr3_fails() let msg = "white space required before and after '&&'" - call CheckDefFailure("let x = 1&&2", msg) - call CheckDefFailure("let x = 1 &&2", msg) - call CheckDefFailure("let x = 1&& 2", msg) + call CheckDefFailure(["let x = 1&&2"], msg) + call CheckDefFailure(["let x = 1 &&2"], msg) + call CheckDefFailure(["let x = 1&& 2"], msg) endfunc let atrue = v:true @@ -212,7 +186,7 @@ def Test_expr4_equal() assert_equal(false, 'abc' ==# 'ABC') set noignorecase - call CheckDefFailure("let x = 'a' == xxx", 'E1001:') + call CheckDefFailure(["let x = 'a' == xxx"], 'E1001:') assert_equal(true, 0z3f == 0z3f) assert_equal(false, 0z3f == 0z4f) @@ -413,71 +387,71 @@ enddef func Test_expr4_fails() let msg = "white space required before and after '>'" - call CheckDefFailure("let x = 1>2", msg) - call CheckDefFailure("let x = 1 >2", msg) - call CheckDefFailure("let x = 1> 2", msg) + call CheckDefFailure(["let x = 1>2"], msg) + call CheckDefFailure(["let x = 1 >2"], msg) + call CheckDefFailure(["let x = 1> 2"], msg) let msg = "white space required before and after '=='" - call CheckDefFailure("let x = 1==2", msg) - call CheckDefFailure("let x = 1 ==2", msg) - call CheckDefFailure("let x = 1== 2", msg) + call CheckDefFailure(["let x = 1==2"], msg) + call CheckDefFailure(["let x = 1 ==2"], msg) + call CheckDefFailure(["let x = 1== 2"], msg) let msg = "white space required before and after 'is'" - call CheckDefFailure("let x = '1'is'2'", msg) - call CheckDefFailure("let x = '1' is'2'", msg) - call CheckDefFailure("let x = '1'is '2'", msg) + call CheckDefFailure(["let x = '1'is'2'"], msg) + call CheckDefFailure(["let x = '1' is'2'"], msg) + call CheckDefFailure(["let x = '1'is '2'"], msg) let msg = "white space required before and after 'isnot'" - call CheckDefFailure("let x = '1'isnot'2'", msg) - call CheckDefFailure("let x = '1' isnot'2'", msg) - call CheckDefFailure("let x = '1'isnot '2'", msg) + call CheckDefFailure(["let x = '1'isnot'2'"], msg) + call CheckDefFailure(["let x = '1' isnot'2'"], msg) + call CheckDefFailure(["let x = '1'isnot '2'"], msg) - call CheckDefFailure("let x = 1 is# 2", 'E15:') - call CheckDefFailure("let x = 1 is? 2", 'E15:') - call CheckDefFailure("let x = 1 isnot# 2", 'E15:') - call CheckDefFailure("let x = 1 isnot? 2", 'E15:') + call CheckDefFailure(["let x = 1 is# 2"], 'E15:') + call CheckDefFailure(["let x = 1 is? 2"], 'E15:') + call CheckDefFailure(["let x = 1 isnot# 2"], 'E15:') + call CheckDefFailure(["let x = 1 isnot? 2"], 'E15:') - call CheckDefFailure("let x = 1 == '2'", 'Cannot compare number with string') - call CheckDefFailure("let x = '1' == 2", 'Cannot compare string with number') - call CheckDefFailure("let x = 1 == RetVoid()", 'Cannot use void value') - call CheckDefFailure("let x = RetVoid() == 1", 'Cannot compare void with number') + call CheckDefFailure(["let x = 1 == '2'"], 'Cannot compare number with string') + call CheckDefFailure(["let x = '1' == 2"], 'Cannot compare string with number') + call CheckDefFailure(["let x = 1 == RetVoid()"], 'Cannot use void value') + call CheckDefFailure(["let x = RetVoid() == 1"], 'Cannot compare void with number') - call CheckDefFailure("let x = true > false", 'Cannot compare bool with bool') - call CheckDefFailure("let x = true >= false", 'Cannot compare bool with bool') - call CheckDefFailure("let x = true < false", 'Cannot compare bool with bool') - call CheckDefFailure("let x = true <= false", 'Cannot compare bool with bool') - call CheckDefFailure("let x = true =~ false", 'Cannot compare bool with bool') - call CheckDefFailure("let x = true !~ false", 'Cannot compare bool with bool') - call CheckDefFailure("let x = true is false", 'Cannot use "is" with bool') - call CheckDefFailure("let x = true isnot false", 'Cannot use "isnot" with bool') + call CheckDefFailure(["let x = true > false"], 'Cannot compare bool with bool') + call CheckDefFailure(["let x = true >= false"], 'Cannot compare bool with bool') + call CheckDefFailure(["let x = true < false"], 'Cannot compare bool with bool') + call CheckDefFailure(["let x = true <= false"], 'Cannot compare bool with bool') + call CheckDefFailure(["let x = true =~ false"], 'Cannot compare bool with bool') + call CheckDefFailure(["let x = true !~ false"], 'Cannot compare bool with bool') + call CheckDefFailure(["let x = true is false"], 'Cannot use "is" with bool') + call CheckDefFailure(["let x = true isnot false"], 'Cannot use "isnot" with bool') - call CheckDefFailure("let x = v:none is v:null", 'Cannot use "is" with special') - call CheckDefFailure("let x = v:none isnot v:null", 'Cannot use "isnot" with special') - call CheckDefFailure("let x = 123 is 123", 'Cannot use "is" with number') - call CheckDefFailure("let x = 123 isnot 123", 'Cannot use "isnot" with number') + call CheckDefFailure(["let x = v:none is v:null"], 'Cannot use "is" with special') + call CheckDefFailure(["let x = v:none isnot v:null"], 'Cannot use "isnot" with special') + call CheckDefFailure(["let x = 123 is 123"], 'Cannot use "is" with number') + call CheckDefFailure(["let x = 123 isnot 123"], 'Cannot use "isnot" with number') if has('float') - call CheckDefFailure("let x = 1.3 is 1.3", 'Cannot use "is" with float') - call CheckDefFailure("let x = 1.3 isnot 1.3", 'Cannot use "isnot" with float') + call CheckDefFailure(["let x = 1.3 is 1.3"], 'Cannot use "is" with float') + call CheckDefFailure(["let x = 1.3 isnot 1.3"], 'Cannot use "isnot" with float') endif - call CheckDefFailure("let x = 0za1 > 0z34", 'Cannot compare blob with blob') - call CheckDefFailure("let x = 0za1 >= 0z34", 'Cannot compare blob with blob') - call CheckDefFailure("let x = 0za1 < 0z34", 'Cannot compare blob with blob') - call CheckDefFailure("let x = 0za1 <= 0z34", 'Cannot compare blob with blob') - call CheckDefFailure("let x = 0za1 =~ 0z34", 'Cannot compare blob with blob') - call CheckDefFailure("let x = 0za1 !~ 0z34", 'Cannot compare blob with blob') + call CheckDefFailure(["let x = 0za1 > 0z34"], 'Cannot compare blob with blob') + call CheckDefFailure(["let x = 0za1 >= 0z34"], 'Cannot compare blob with blob') + call CheckDefFailure(["let x = 0za1 < 0z34"], 'Cannot compare blob with blob') + call CheckDefFailure(["let x = 0za1 <= 0z34"], 'Cannot compare blob with blob') + call CheckDefFailure(["let x = 0za1 =~ 0z34"], 'Cannot compare blob with blob') + call CheckDefFailure(["let x = 0za1 !~ 0z34"], 'Cannot compare blob with blob') - call CheckDefFailure("let x = [13] > [88]", 'Cannot compare list with list') - call CheckDefFailure("let x = [13] >= [88]", 'Cannot compare list with list') - call CheckDefFailure("let x = [13] < [88]", 'Cannot compare list with list') - call CheckDefFailure("let x = [13] <= [88]", 'Cannot compare list with list') - call CheckDefFailure("let x = [13] =~ [88]", 'Cannot compare list with list') - call CheckDefFailure("let x = [13] !~ [88]", 'Cannot compare list with list') + call CheckDefFailure(["let x = [13] > [88]"], 'Cannot compare list with list') + call CheckDefFailure(["let x = [13] >= [88]"], 'Cannot compare list with list') + call CheckDefFailure(["let x = [13] < [88]"], 'Cannot compare list with list') + call CheckDefFailure(["let x = [13] <= [88]"], 'Cannot compare list with list') + call CheckDefFailure(["let x = [13] =~ [88]"], 'Cannot compare list with list') + call CheckDefFailure(["let x = [13] !~ [88]"], 'Cannot compare list with list') - call CheckDefFailureMult(['let j: job', 'let chan: channel', 'let r = j == chan'], 'Cannot compare job with channel') - call CheckDefFailureMult(['let j: job', 'let x: list', 'let r = j == x'], 'Cannot compare job with list') - call CheckDefFailureMult(['let j: job', 'let Xx: func', 'let r = j == Xx'], 'Cannot compare job with func') - call CheckDefFailureMult(['let j: job', 'let Xx: func', 'let r = j == Xx'], 'Cannot compare job with func') + call CheckDefFailure(['let j: job', 'let chan: channel', 'let r = j == chan'], 'Cannot compare job with channel') + call CheckDefFailure(['let j: job', 'let x: list', 'let r = j == x'], 'Cannot compare job with list') + call CheckDefFailure(['let j: job', 'let Xx: func', 'let r = j == Xx'], 'Cannot compare job with func') + call CheckDefFailure(['let j: job', 'let Xx: func', 'let r = j == Xx'], 'Cannot compare job with func') endfunc " test addition, subtraction, concatenation @@ -532,27 +506,27 @@ enddef func Test_expr5_fails() let msg = "white space required before and after '+'" - call CheckDefFailure("let x = 1+2", msg) - call CheckDefFailure("let x = 1 +2", msg) - call CheckDefFailure("let x = 1+ 2", msg) + call CheckDefFailure(["let x = 1+2"], msg) + call CheckDefFailure(["let x = 1 +2"], msg) + call CheckDefFailure(["let x = 1+ 2"], msg) let msg = "white space required before and after '-'" - call CheckDefFailure("let x = 1-2", msg) - call CheckDefFailure("let x = 1 -2", msg) - call CheckDefFailure("let x = 1- 2", msg) + call CheckDefFailure(["let x = 1-2"], msg) + call CheckDefFailure(["let x = 1 -2"], msg) + call CheckDefFailure(["let x = 1- 2"], msg) let msg = "white space required before and after '..'" - call CheckDefFailure("let x = '1'..'2'", msg) - call CheckDefFailure("let x = '1' ..'2'", msg) - call CheckDefFailure("let x = '1'.. '2'", msg) + call CheckDefFailure(["let x = '1'..'2'"], msg) + call CheckDefFailure(["let x = '1' ..'2'"], msg) + call CheckDefFailure(["let x = '1'.. '2'"], msg) - call CheckDefFailure("let x = 0z1122 + 33", 'E1035') - call CheckDefFailure("let x = 0z1122 + [3]", 'E1035') - call CheckDefFailure("let x = 0z1122 + 'asd'", 'E1035') - call CheckDefFailure("let x = 33 + 0z1122", 'E1035') - call CheckDefFailure("let x = [3] + 0z1122", 'E1035') - call CheckDefFailure("let x = 'asdf' + 0z1122", 'E1035') - call CheckDefFailure("let x = 6 + xxx", 'E1001') + call CheckDefFailure(["let x = 0z1122 + 33"], 'E1035') + call CheckDefFailure(["let x = 0z1122 + [3]"], 'E1035') + call CheckDefFailure(["let x = 0z1122 + 'asd'"], 'E1035') + call CheckDefFailure(["let x = 33 + 0z1122"], 'E1035') + call CheckDefFailure(["let x = [3] + 0z1122"], 'E1035') + call CheckDefFailure(["let x = 'asdf' + 0z1122"], 'E1035') + call CheckDefFailure(["let x = 6 + xxx"], 'E1001') endfunc " test multiply, divide, modulo @@ -588,7 +562,7 @@ def Test_expr6() assert_equal(6.0, xf[0] * yf[0]) endif - call CheckDefFailure("let x = 6 * xxx", 'E1001') + call CheckDefFailure(["let x = 6 * xxx"], 'E1001') enddef def Test_expr6_float() @@ -623,45 +597,45 @@ enddef func Test_expr6_fails() let msg = "white space required before and after '*'" - call CheckDefFailure("let x = 1*2", msg) - call CheckDefFailure("let x = 1 *2", msg) - call CheckDefFailure("let x = 1* 2", msg) + call CheckDefFailure(["let x = 1*2"], msg) + call CheckDefFailure(["let x = 1 *2"], msg) + call CheckDefFailure(["let x = 1* 2"], msg) let msg = "white space required before and after '/'" - call CheckDefFailure("let x = 1/2", msg) - call CheckDefFailure("let x = 1 /2", msg) - call CheckDefFailure("let x = 1/ 2", msg) + call CheckDefFailure(["let x = 1/2"], msg) + call CheckDefFailure(["let x = 1 /2"], msg) + call CheckDefFailure(["let x = 1/ 2"], msg) let msg = "white space required before and after '%'" - call CheckDefFailure("let x = 1%2", msg) - call CheckDefFailure("let x = 1 %2", msg) - call CheckDefFailure("let x = 1% 2", msg) + call CheckDefFailure(["let x = 1%2"], msg) + call CheckDefFailure(["let x = 1 %2"], msg) + call CheckDefFailure(["let x = 1% 2"], msg) - call CheckDefFailure("let x = '1' * '2'", 'E1036:') - call CheckDefFailure("let x = '1' / '2'", 'E1036:') - call CheckDefFailure("let x = '1' % '2'", 'E1035:') + call CheckDefFailure(["let x = '1' * '2'"], 'E1036:') + call CheckDefFailure(["let x = '1' / '2'"], 'E1036:') + call CheckDefFailure(["let x = '1' % '2'"], 'E1035:') - call CheckDefFailure("let x = 0z01 * 0z12", 'E1036:') - call CheckDefFailure("let x = 0z01 / 0z12", 'E1036:') - call CheckDefFailure("let x = 0z01 % 0z12", 'E1035:') + call CheckDefFailure(["let x = 0z01 * 0z12"], 'E1036:') + call CheckDefFailure(["let x = 0z01 / 0z12"], 'E1036:') + call CheckDefFailure(["let x = 0z01 % 0z12"], 'E1035:') - call CheckDefFailure("let x = [1] * [2]", 'E1036:') - call CheckDefFailure("let x = [1] / [2]", 'E1036:') - call CheckDefFailure("let x = [1] % [2]", 'E1035:') + call CheckDefFailure(["let x = [1] * [2]"], 'E1036:') + call CheckDefFailure(["let x = [1] / [2]"], 'E1036:') + call CheckDefFailure(["let x = [1] % [2]"], 'E1035:') - call CheckDefFailure("let x = #{one: 1} * #{two: 2}", 'E1036:') - call CheckDefFailure("let x = #{one: 1} / #{two: 2}", 'E1036:') - call CheckDefFailure("let x = #{one: 1} % #{two: 2}", 'E1035:') + call CheckDefFailure(["let x = #{one: 1} * #{two: 2}"], 'E1036:') + call CheckDefFailure(["let x = #{one: 1} / #{two: 2}"], 'E1036:') + call CheckDefFailure(["let x = #{one: 1} % #{two: 2}"], 'E1035:') - call CheckDefFailure("let x = 0xff[1]", 'E714:') + call CheckDefFailure(["let x = 0xff[1]"], 'E714:') if has('float') - call CheckDefFailure("let x = 0.7[1]", 'E714:') + call CheckDefFailure(["let x = 0.7[1]"], 'E714:') endif endfunc func Test_expr6_float_fails() CheckFeature float - call CheckDefFailure("let x = 1.0 % 2", 'E1035:') + call CheckDefFailure(["let x = 1.0 % 2"], 'E1035:') endfunc " define here to use old style parsing @@ -721,7 +695,7 @@ def Test_expr7_blob() assert_equal(g:blob_one, 0z01) assert_equal(g:blob_long, 0z0102.0304) - call CheckDefFailure("let x = 0z123", 'E973:') + call CheckDefFailure(["let x = 0z123"], 'E973:') enddef def Test_expr7_string() @@ -734,16 +708,16 @@ def Test_expr7_string() assert_equal(g:string_long, "abcdefghijklm") assert_equal(g:string_special, "ab\ncd\ref\ekk") - call CheckDefFailure('let x = "abc', 'E114:') - call CheckDefFailure("let x = 'abc", 'E115:') + call CheckDefFailure(['let x = "abc'], 'E114:') + call CheckDefFailure(["let x = 'abc"], 'E115:') enddef def Test_expr7_vimvar() let old: list = v:oldfiles let compl: dict = v:completed_item - call CheckDefFailure("let old: list = v:oldfiles", 'E1013: type mismatch, expected list but got list') - call CheckDefFailure("let old: dict = v:completed_item", 'E1013: type mismatch, expected dict but got dict') + call CheckDefFailure(["let old: list = v:oldfiles"], 'E1013: type mismatch, expected list but got list') + call CheckDefFailure(["let old: dict = v:completed_item"], 'E1013: type mismatch, expected dict but got dict') enddef def Test_expr7_special() @@ -755,11 +729,11 @@ def Test_expr7_special() assert_equal(g:special_null, v:null) assert_equal(g:special_none, v:none) - call CheckDefFailure('v:true = true', 'E46:') - call CheckDefFailure('v:true = false', 'E46:') - call CheckDefFailure('v:false = true', 'E46:') - call CheckDefFailure('v:null = 11', 'E46:') - call CheckDefFailure('v:none = 22', 'E46:') + call CheckDefFailure(['v:true = true'], 'E46:') + call CheckDefFailure(['v:true = false'], 'E46:') + call CheckDefFailure(['v:false = true'], 'E46:') + call CheckDefFailure(['v:null = 11'], 'E46:') + call CheckDefFailure(['v:none = 22'], 'E46:') enddef def Test_expr7_list() @@ -770,9 +744,9 @@ def Test_expr7_list() assert_equal('b', g:list_mixed[1]) call CheckDefExecFailure("let x = g:anint[3]", 'E714:') - call CheckDefFailure("let x = g:list_mixed[xxx]", 'E1001:') + call CheckDefFailure(["let x = g:list_mixed[xxx]"], 'E1001:') call CheckDefExecFailure("let x = g:list_mixed['xx']", 'E39:') - call CheckDefFailure("let x = g:list_mixed[0", 'E111:') + call CheckDefFailure(["let x = g:list_mixed[0"], 'E111:') call CheckDefExecFailure("let x = g:list_empty[3]", 'E684:') enddef @@ -792,16 +766,16 @@ def Test_expr7_dict() let val = 1 assert_equal(g:dict_one, {key: val}) - call CheckDefFailure("let x = #{8: 8}", 'E1014:') - call CheckDefFailure("let x = #{xxx}", 'E720:') - call CheckDefFailureMult(["let x = #{xxx: 1", "let y = 2"], 'E722:') - call CheckDefFailure("let x = #{xxx: 1,", 'E723:') - call CheckDefFailure("let x = {'a': xxx}", 'E1001:') - call CheckDefFailure("let x = {xxx: 8}", 'E1001:') - call CheckDefFailure("let x = #{a: 1, a: 2}", 'E721:') - call CheckDefFailure("let x = #", 'E1015:') - call CheckDefFailure("let x += 1", 'E1020:') - call CheckDefFailure("let x = x + 1", 'E1001:') + call CheckDefFailure(["let x = #{8: 8}"], 'E1014:') + call CheckDefFailure(["let x = #{xxx}"], 'E720:') + call CheckDefFailure(["let x = #{xxx: 1", "let y = 2"], 'E722:') + call CheckDefFailure(["let x = #{xxx: 1,"], 'E723:') + call CheckDefFailure(["let x = {'a': xxx}"], 'E1001:') + call CheckDefFailure(["let x = {xxx: 8}"], 'E1001:') + call CheckDefFailure(["let x = #{a: 1, a: 2}"], 'E721:') + call CheckDefFailure(["let x = #"], 'E1015:') + call CheckDefFailure(["let x += 1"], 'E1020:') + call CheckDefFailure(["let x = x + 1"], 'E1001:') call CheckDefExecFailure("let x = g:anint.member", 'E715:') call CheckDefExecFailure("let x = g:dict_empty.member", 'E716:') enddef @@ -809,7 +783,7 @@ enddef def Test_expr_member() assert_equal(1, g:dict_one.one) - call CheckDefFailure("let x = g:dict_one.#$!", 'E1002:') + call CheckDefFailure(["let x = g:dict_one.#$!"], 'E1002:') enddef def Test_expr7_option() @@ -831,7 +805,7 @@ def Test_expr7_environment() assert_equal('testvar', $TESTVAR) assert_equal('', $ASDF_ASD_XXX) - call CheckDefFailure("let x = $$$", 'E1002:') + call CheckDefFailure(["let x = $$$"], 'E1002:') enddef def Test_expr7_register() @@ -871,7 +845,7 @@ def Test_expr7_call() assert_equal('yes', 'yes'->Echo()) assert_equal('yes', 'yes'->s:EchoArg()) - call CheckDefFailure("let x = 'yes'->Echo", 'E107:') + call CheckDefFailure(["let x = 'yes'->Echo"], 'E107:') enddef @@ -904,39 +878,39 @@ def Test_expr7_not() enddef func Test_expr7_fails() - call CheckDefFailure("let x = (12", "E110:") + call CheckDefFailure(["let x = (12"], "E110:") - call CheckDefFailure("let x = -'xx'", "E1030:") - call CheckDefFailure("let x = +'xx'", "E1030:") - call CheckDefFailure("let x = -0z12", "E974:") + call CheckDefFailure(["let x = -'xx'"], "E1030:") + call CheckDefFailure(["let x = +'xx'"], "E1030:") + call CheckDefFailure(["let x = -0z12"], "E974:") call CheckDefExecFailure("let x = -[8]", "E39:") call CheckDefExecFailure("let x = -{'a': 1}", "E39:") - call CheckDefFailure("let x = @", "E1002:") - call CheckDefFailure("let x = @<", "E354:") + call CheckDefFailure(["let x = @"], "E1002:") + call CheckDefFailure(["let x = @<"], "E354:") - call CheckDefFailure("let x = [1, 2", "E697:") - call CheckDefFailure("let x = [notfound]", "E1001:") + call CheckDefFailure(["let x = [1, 2"], "E697:") + call CheckDefFailure(["let x = [notfound]"], "E1001:") - call CheckDefFailure("let x = { -> 123) }", "E451:") - call CheckDefFailure("let x = 123->{x -> x + 5) }", "E451:") + call CheckDefFailure(["let x = { -> 123) }"], "E451:") + call CheckDefFailure(["let x = 123->{x -> x + 5) }"], "E451:") - call CheckDefFailure("let x = ¬exist", 'E113:') - call CheckDefFailure("&grepprg = [343]", 'E1013:') + call CheckDefFailure(["let x = ¬exist"], 'E113:') + call CheckDefFailure(["&grepprg = [343]"], 'E1013:') call CheckDefExecFailure("echo s:doesnt_exist", 'E121:') call CheckDefExecFailure("echo g:doesnt_exist", 'E121:') - call CheckDefFailure("echo a:somevar", 'E1075:') - call CheckDefFailure("echo l:somevar", 'E1075:') - call CheckDefFailure("echo x:somevar", 'E1075:') + call CheckDefFailure(["echo a:somevar"], 'E1075:') + call CheckDefFailure(["echo l:somevar"], 'E1075:') + call CheckDefFailure(["echo x:somevar"], 'E1075:') call CheckDefExecFailure("let x = +g:astring", 'E1030:') call CheckDefExecFailure("let x = +g:ablob", 'E974:') call CheckDefExecFailure("let x = +g:alist", 'E745:') call CheckDefExecFailure("let x = +g:adict", 'E728:') - call CheckDefFailureMult(["let x = ''", "let y = x.memb"], 'E715:') + call CheckDefFailure(["let x = ''", "let y = x.memb"], 'E715:') call CheckDefExecFailure("[1, 2->len()", 'E492:') call CheckDefExecFailure("#{a: 1->len()", 'E488:') @@ -988,23 +962,23 @@ enddef func Test_expr7_trailing_fails() - call CheckDefFailureList(['let l = [2]', 'l->{l -> add(l, 8)}'], 'E107') - call CheckDefFailureList(['let l = [2]', 'l->{l -> add(l, 8)} ()'], 'E274') + call CheckDefFailure(['let l = [2]', 'l->{l -> add(l, 8)}'], 'E107') + call CheckDefFailure(['let l = [2]', 'l->{l -> add(l, 8)} ()'], 'E274') endfunc func Test_expr_fails() - call CheckDefFailure("let x = '1'is2", 'E488:') - call CheckDefFailure("let x = '1'isnot2", 'E488:') + call CheckDefFailure(["let x = '1'is2"], 'E488:') + call CheckDefFailure(["let x = '1'isnot2"], 'E488:') call CheckDefExecFailure("CallMe ('yes')", 'E492:') - call CheckDefFailure("CallMe2('yes','no')", 'E1069:') - call CheckDefFailure("CallMe2('yes' , 'no')", 'E1068:') + call CheckDefFailure(["CallMe2('yes','no')"], 'E1069:') + call CheckDefFailure(["CallMe2('yes' , 'no')"], 'E1068:') - call CheckDefFailure("v:nosuch += 3", 'E1001:') - call CheckDefFailure("let v:statusmsg = ''", 'E1064:') - call CheckDefFailure("let asdf = v:nosuch", 'E1001:') + call CheckDefFailure(["v:nosuch += 3"], 'E1001:') + call CheckDefFailure(["let v:statusmsg = ''"], 'E1064:') + call CheckDefFailure(["let asdf = v:nosuch"], 'E1001:') - call CheckDefFailure("echo len('asdf'", 'E110:') - call CheckDefFailure("echo Func0123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789()", 'E1011:') - call CheckDefFailure("echo doesnotexist()", 'E117:') + call CheckDefFailure(["echo len('asdf'"], 'E110:') + call CheckDefFailure(["echo Func0123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789()"], 'E1011:') + call CheckDefFailure(["echo doesnotexist()"], 'E117:') endfunc diff --git a/src/testdir/test_vim9_script.vim b/src/testdir/test_vim9_script.vim index f06bb734c4..218ef77402 100644 --- a/src/testdir/test_vim9_script.vim +++ b/src/testdir/test_vim9_script.vim @@ -2,25 +2,7 @@ source check.vim source view_util.vim - -" Check that "lines" inside ":def" results in an "error" message. -func CheckDefFailure(lines, error) - call writefile(['def Func()'] + a:lines + ['enddef'], 'Xdef') - call assert_fails('so Xdef', a:error, a:lines) - call delete('Xdef') -endfunc - -def CheckScriptFailure(lines: list, error: string) - writefile(lines, 'Xdef') - assert_fails('so Xdef', error, lines) - delete('Xdef') -enddef - -def CheckScriptSuccess(lines: list) - writefile(lines, 'Xdef') - so Xdef - delete('Xdef') -enddef +source vim9.vim def Test_syntax() let var = 234 diff --git a/src/testdir/vim9.vim b/src/testdir/vim9.vim new file mode 100644 index 0000000000..0e0cd1e1f7 --- /dev/null +++ b/src/testdir/vim9.vim @@ -0,0 +1,28 @@ +" Utility functions for testing vim9 script + +" Check that "lines" inside ":def" results in an "error" message. +func CheckDefFailure(lines, error) + call writefile(['def Func()'] + a:lines + ['enddef'], 'Xdef') + call assert_fails('so Xdef', a:error, a:lines) + call delete('Xdef') +endfunc + +def CheckScriptFailure(lines: list, error: string) + writefile(lines, 'Xdef') + assert_fails('so Xdef', error, lines) + delete('Xdef') +enddef + +def CheckScriptSuccess(lines: list) + writefile(lines, 'Xdef') + so Xdef + delete('Xdef') +enddef + +" Check that "line" inside ":def" results in an "error" message when executed. +func CheckDefExecFailure(line, error) + call writefile(['def! Func()', a:line, 'enddef'], 'Xdef') + so Xdef + call assert_fails('call Func()', a:error, a:line) + call delete('Xdef') +endfunc diff --git a/src/version.c b/src/version.c index 70af7b0436..233106b246 100644 --- a/src/version.c +++ b/src/version.c @@ -746,6 +746,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 640, /**/ 639, /**/ diff --git a/src/vim9.h b/src/vim9.h index f1da323188..ddc84b1e72 100644 --- a/src/vim9.h +++ b/src/vim9.h @@ -13,6 +13,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_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 4d1e3acc64..092939e08d 100644 --- a/src/vim9compile.c +++ b/src/vim9compile.c @@ -1427,6 +1427,17 @@ generate_EXEC(cctx_T *cctx, char_u *line) return OK; } + static int +generate_EXECCONCAT(cctx_T *cctx, int count) +{ + isn_T *isn; + + if ((isn = generate_instr_drop(cctx, ISN_EXECCONCAT, count)) == NULL) + return FAIL; + isn->isn_arg.number = count; + return OK; +} + /* * Reserve space for a local variable. * Return the index or -1 if it failed. @@ -5804,6 +5815,71 @@ compile_mult_expr(char_u *arg, int cmdidx, cctx_T *cctx) return p; } +/* + * A command that is not compiled, execute with legacy code. + */ + static char_u * +compile_exec(char_u *line, exarg_T *eap, cctx_T *cctx) +{ + char_u *p; + + if (cctx->ctx_skip == TRUE) + goto theend; + + + if ((excmd_get_argt(eap->cmdidx) & EX_XFILE) + && (p = (char_u *)strstr((char *)eap->arg, "`=")) != NULL) + { + int count = 0; + char_u *start = skipwhite(line); + + // :cmd xxx`=expr1`yyy`=expr2`zzz + // PUSHS ":cmd xxx" + // eval expr1 + // PUSHS "yyy" + // eval expr2 + // PUSHS "zzz" + // EXECCONCAT 5 + for (;;) + { + if (p > start) + { + generate_PUSHS(cctx, vim_strnsave(start, (int)(p - start))); + ++count; + } + p += 2; + if (compile_expr1(&p, cctx) == FAIL) + return NULL; + may_generate_2STRING(-1, cctx); + ++count; + p = skipwhite(p); + if (*p != '`') + { + emsg(_("E1083: missing backtick")); + return NULL; + } + start = p + 1; + + p = (char_u *)strstr((char *)start, "`="); + if (p == NULL) + { + if (*skipwhite(start) != NUL) + { + generate_PUSHS(cctx, vim_strsave(start)); + ++count; + } + break; + } + } + generate_EXECCONCAT(cctx, count); + } + else + generate_EXEC(cctx, line); + +theend: + return (char_u *)""; +} + /* * After ex_function() has collected all the function lines: parse and compile * the lines into instructions. @@ -5818,7 +5894,6 @@ compile_def_function(ufunc_T *ufunc, int set_return_type) { char_u *line = NULL; char_u *p; - exarg_T ea; char *errormsg = NULL; // error message int had_return = FALSE; cctx_T cctx; @@ -5917,6 +5992,7 @@ compile_def_function(ufunc_T *ufunc, int set_return_type) */ for (;;) { + exarg_T ea; int is_ex_command = FALSE; // Bail out on the first error to avoid a flood of errors and report @@ -5952,7 +6028,7 @@ compile_def_function(ufunc_T *ufunc, int set_return_type) switch (*ea.cmd) { case '#': - // "#" starts a comment, but not "#{". + // "#" starts a comment, but "#{" does not. if (ea.cmd[1] != '{') { line = (char_u *)""; @@ -6093,7 +6169,7 @@ compile_def_function(ufunc_T *ufunc, int set_return_type) && ea.cmdidx != CMD_else && ea.cmdidx != CMD_endif) { - line += STRLEN(line); + line = (char_u *)""; continue; } @@ -6183,10 +6259,10 @@ compile_def_function(ufunc_T *ufunc, int set_return_type) break; default: - // Not recognized, execute with do_cmdline_cmd(). // TODO: other commands with an expression argument - generate_EXEC(&cctx, line); - line = (char_u *)""; + // Not recognized, execute with do_cmdline_cmd(). + ea.arg = p; + line = compile_exec(line, &ea, &cctx); break; } if (line == NULL) @@ -6401,10 +6477,11 @@ delete_instr(isn_T *isn) case ISN_DCALL: case ISN_DROP: case ISN_ECHO: - case ISN_EXECUTE: - case ISN_ECHOMSG: case ISN_ECHOERR: + case ISN_ECHOMSG: case ISN_ENDTRY: + case ISN_EXECCONCAT: + case ISN_EXECUTE: case ISN_FOR: case ISN_FUNCREF: case ISN_INDEX: diff --git a/src/vim9execute.c b/src/vim9execute.c index 8c136967f7..7172718c29 100644 --- a/src/vim9execute.c +++ b/src/vim9execute.c @@ -648,6 +648,45 @@ call_def_function( do_cmdline_cmd(iptr->isn_arg.string); break; + // execute Ex command from pieces on the stack + case ISN_EXECCONCAT: + { + int count = iptr->isn_arg.number; + int len = 0; + int pass; + int i; + char_u *cmd = NULL; + char_u *str; + + for (pass = 1; pass <= 2; ++pass) + { + for (i = 0; i < count; ++i) + { + tv = STACK_TV_BOT(i - count); + str = tv->vval.v_string; + if (str != NULL && *str != NUL) + { + if (pass == 2) + STRCPY(cmd + len, str); + len += STRLEN(str); + } + if (pass == 2) + clear_tv(tv); + } + if (pass == 1) + { + cmd = alloc(len + 1); + if (cmd == NULL) + goto failed; + len = 0; + } + } + + do_cmdline_cmd(cmd); + vim_free(cmd); + } + break; + // execute :echo {string} ... case ISN_ECHO: { @@ -1961,6 +2000,10 @@ ex_disassemble(exarg_T *eap) case ISN_EXEC: smsg("%4d EXEC %s", current, iptr->isn_arg.string); break; + case ISN_EXECCONCAT: + smsg("%4d EXECCONCAT %lld", current, + (long long)iptr->isn_arg.number); + break; case ISN_ECHO: { echo_T *echo = &iptr->isn_arg.echo; From 6378c4fef37df05c99e8a43616063b4ddb692876 Mon Sep 17 00:00:00 2001 From: Bram Moolenaar Date: Sun, 26 Apr 2020 13:50:41 +0200 Subject: [PATCH 035/230] patch 8.2.0641: Vim9: not expanded in :hardcopy and syn-include Problem: Vim9: not expanded in :hardcopy and "syntax include". Solution: Add the EX_EXPAND flag. Expend "syntax include". --- src/ex_cmds.h | 4 +++- src/testdir/test_vim9_cmd.vim | 25 +++++++++++++++++++++++++ src/version.c | 2 ++ src/vim9compile.c | 15 ++++++++++++--- src/vim9execute.c | 2 ++ 5 files changed, 44 insertions(+), 4 deletions(-) diff --git a/src/ex_cmds.h b/src/ex_cmds.h index 0c158e1bd5..25a0853bda 100644 --- a/src/ex_cmds.h +++ b/src/ex_cmds.h @@ -53,6 +53,8 @@ #define EX_MODIFY 0x100000 // forbidden in non-'modifiable' buffer #define EX_FLAGS 0x200000 // allow flags after count in argument #define EX_RESTRICT 0x400000 // forbidden in restricted mode +#define EX_EXPAND 0x800000 // expands wildcards later + #define EX_FILES (EX_XFILE | EX_EXTRA) // multiple extra files allowed #define EX_FILE1 (EX_FILES | EX_NOSPC) // 1 file, defaults to current file #define EX_WORD1 (EX_EXTRA | EX_NOSPC) // one extra word allowed @@ -653,7 +655,7 @@ EXCMD(CMD_helptags, "helptags", ex_helptags, EX_NEEDARG|EX_FILES|EX_TRLBAR|EX_CMDWIN, ADDR_NONE), EXCMD(CMD_hardcopy, "hardcopy", ex_hardcopy, - EX_RANGE|EX_COUNT|EX_EXTRA|EX_TRLBAR|EX_DFLALL|EX_BANG, + EX_RANGE|EX_COUNT|EX_EXTRA|EX_EXPAND|EX_TRLBAR|EX_DFLALL|EX_BANG, ADDR_LINES), EXCMD(CMD_highlight, "highlight", ex_highlight, EX_BANG|EX_EXTRA|EX_TRLBAR|EX_SBOXOK|EX_CMDWIN, diff --git a/src/testdir/test_vim9_cmd.vim b/src/testdir/test_vim9_cmd.vim index 7ccd1f70cc..70437b901f 100644 --- a/src/testdir/test_vim9_cmd.vim +++ b/src/testdir/test_vim9_cmd.vim @@ -1,5 +1,6 @@ " Test commands that are not compiled in a :def function +source check.vim source vim9.vim def Test_edit_wildcards() @@ -19,5 +20,29 @@ def Test_edit_wildcards() assert_equal('XXtestxx77yy', bufname()) enddef +def Test_hardcopy_wildcards() + CheckUnix + CheckFeature postscript + + let outfile = 'print' + hardcopy > X`=outfile`.ps + assert_true(filereadable('Xprint.ps')) + + delete('Xprint.ps') +enddef + +def Test_syn_include_wildcards() + writefile(['syn keyword Found found'], 'Xthemine.vim') + let save_rtp = &rtp + &rtp = '.' + + let fname = 'mine' + syn include @Group Xthe`=fname`.vim + assert_match('Found.* contained found', execute('syn list Found')) + + &rtp = save_rtp + delete('Xthemine.vim') +enddef + " vim: ts=8 sw=2 sts=2 expandtab tw=80 fdm=marker diff --git a/src/version.c b/src/version.c index 233106b246..3829af5b3f 100644 --- a/src/version.c +++ b/src/version.c @@ -746,6 +746,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 641, /**/ 640, /**/ diff --git a/src/vim9compile.c b/src/vim9compile.c index 092939e08d..ccd73f77fa 100644 --- a/src/vim9compile.c +++ b/src/vim9compile.c @@ -5821,14 +5821,23 @@ compile_mult_expr(char_u *arg, int cmdidx, cctx_T *cctx) static char_u * compile_exec(char_u *line, exarg_T *eap, cctx_T *cctx) { - char_u *p; + char_u *p; + int has_expr; if (cctx->ctx_skip == TRUE) goto theend; + has_expr = (excmd_get_argt(eap->cmdidx) & (EX_XFILE | EX_EXPAND)); + if (eap->cmdidx == CMD_syntax && STRNCMP(eap->arg, "include ", 8) == 0) + { + // expand filename in "syntax include [@group] filename" + has_expr = TRUE; + eap->arg = skipwhite(eap->arg + 7); + if (*eap->arg == '@') + eap->arg = skiptowhite(eap->arg); + } - if ((excmd_get_argt(eap->cmdidx) & EX_XFILE) - && (p = (char_u *)strstr((char *)eap->arg, "`=")) != NULL) + if (has_expr && (p = (char_u *)strstr((char *)eap->arg, "`=")) != NULL) { int count = 0; char_u *start = skipwhite(line); diff --git a/src/vim9execute.c b/src/vim9execute.c index 7172718c29..9ea7dafad3 100644 --- a/src/vim9execute.c +++ b/src/vim9execute.c @@ -645,6 +645,7 @@ call_def_function( { // execute Ex command line case ISN_EXEC: + SOURCING_LNUM = iptr->isn_lnum; do_cmdline_cmd(iptr->isn_arg.string); break; @@ -682,6 +683,7 @@ call_def_function( } } + SOURCING_LNUM = iptr->isn_lnum; do_cmdline_cmd(cmd); vim_free(cmd); } From 7d41aa8874a62eb399e13b94add7f0e5c4dd074b Mon Sep 17 00:00:00 2001 From: Bram Moolenaar Date: Sun, 26 Apr 2020 14:29:56 +0200 Subject: [PATCH 036/230] patch 8.2.0642: Vim9: using invalid index Problem: Vim9: using invalid index. Solution: Check index for being valid. Fix memory leak. --- src/clientserver.c | 1 + src/version.c | 2 ++ src/vim9compile.c | 5 +++-- 3 files changed, 6 insertions(+), 2 deletions(-) diff --git a/src/clientserver.c b/src/clientserver.c index 5245425803..cf35c8149f 100644 --- a/src/clientserver.c +++ b/src/clientserver.c @@ -473,6 +473,7 @@ cmdsrv_main( # ifdef FEAT_GUI_MSWIN Shell_NotifyIcon(NIM_DELETE, &ni); # endif + vim_free(done); } } else if (STRICMP(argv[i], "--remote-expr") == 0) diff --git a/src/version.c b/src/version.c index 3829af5b3f..590c392177 100644 --- a/src/version.c +++ b/src/version.c @@ -746,6 +746,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 642, /**/ 641, /**/ diff --git a/src/vim9compile.c b/src/vim9compile.c index ccd73f77fa..0e9abac0e4 100644 --- a/src/vim9compile.c +++ b/src/vim9compile.c @@ -5822,12 +5822,13 @@ compile_mult_expr(char_u *arg, int cmdidx, cctx_T *cctx) compile_exec(char_u *line, exarg_T *eap, cctx_T *cctx) { char_u *p; - int has_expr; + int has_expr = FALSE; if (cctx->ctx_skip == TRUE) goto theend; - has_expr = (excmd_get_argt(eap->cmdidx) & (EX_XFILE | EX_EXPAND)); + if (eap->cmdidx >= 0 && eap->cmdidx < CMD_SIZE) + has_expr = (excmd_get_argt(eap->cmdidx) & (EX_XFILE | EX_EXPAND)); if (eap->cmdidx == CMD_syntax && STRNCMP(eap->arg, "include ", 8) == 0) { // expand filename in "syntax include [@group] filename" From e297802d6ddbebbf36f9a2d01127c034fab88b3b Mon Sep 17 00:00:00 2001 From: Bram Moolenaar Date: Sun, 26 Apr 2020 14:47:44 +0200 Subject: [PATCH 037/230] patch 8.2.0643: terminal uses brown instead of dark yellow Problem: Terminal uses brown instead of dark yellow. (Romain Lafourcade) Solution: Use color index 3 instead of 130. (closes #5993) --- src/terminal.c | 6 +++--- src/version.c | 2 ++ 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/src/terminal.c b/src/terminal.c index f7b653a685..9d9dd6a6d3 100644 --- a/src/terminal.c +++ b/src/terminal.c @@ -847,7 +847,7 @@ ex_terminal(exarg_T *eap) // default to close when the shell exits if (opt.jo_term_finish == NUL) - opt.jo_term_finish = 'c'; + opt.jo_term_finish = TL_FINISH_CLOSE; } if (eap->addr_count > 0) @@ -1930,7 +1930,7 @@ set_terminal_mode(term_T *term, int normal_mode) } /* - * Called after the job if finished and Terminal mode is not active: + * Called after the job is finished and Terminal mode is not active: * Move the vterm contents into the scrollback buffer and free the vterm. */ static void @@ -2698,7 +2698,7 @@ color2index(VTermColor *color, int fg, int *boldp) case 1: return lookup_color( 0, fg, boldp) + 1; // black case 2: return lookup_color( 4, fg, boldp) + 1; // dark red case 3: return lookup_color( 2, fg, boldp) + 1; // dark green - case 4: return lookup_color( 6, fg, boldp) + 1; // brown + case 4: return lookup_color( 7, fg, boldp) + 1; // dark yellow case 5: return lookup_color( 1, fg, boldp) + 1; // dark blue case 6: return lookup_color( 5, fg, boldp) + 1; // dark magenta case 7: return lookup_color( 3, fg, boldp) + 1; // dark cyan diff --git a/src/version.c b/src/version.c index 590c392177..e78fc73390 100644 --- a/src/version.c +++ b/src/version.c @@ -746,6 +746,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 643, /**/ 642, /**/ From 99fa721944dda9d07c53c907c33466728df5c271 Mon Sep 17 00:00:00 2001 From: Bram Moolenaar Date: Sun, 26 Apr 2020 15:59:55 +0200 Subject: [PATCH 038/230] patch 8.2.0644: insufficient testing for invalid function arguments Problem: Insufficient testing for invalid function arguments. Solution: Add more tests. (Yegappan Lakshmanan, closes #5988) --- runtime/doc/eval.txt | 4 ++-- src/testdir/test_bufline.vim | 1 + src/testdir/test_channel.vim | 7 ++++++- src/testdir/test_clientserver.vim | 1 + src/testdir/test_expr.vim | 1 + src/testdir/test_functions.vim | 21 +++++++++++++++------ src/testdir/test_listener.vim | 5 +++++ src/testdir/test_match.vim | 4 +++- src/testdir/test_menu.vim | 1 + src/testdir/test_quickfix.vim | 1 + src/testdir/test_registers.vim | 2 ++ src/testdir/test_reltime.vim | 5 +++++ src/testdir/test_terminal.vim | 18 ++++++++++++++++++ src/testdir/test_textprop.vim | 25 +++++++++++++++++++++++++ src/testdir/test_window_cmd.vim | 8 ++++++++ src/testdir/test_window_id.vim | 8 ++++++++ src/testdir/test_writefile.vim | 12 ++++++++++++ src/version.c | 2 ++ 18 files changed, 116 insertions(+), 10 deletions(-) diff --git a/runtime/doc/eval.txt b/runtime/doc/eval.txt index e01aad3fca..02ed78b2e1 100644 --- a/runtime/doc/eval.txt +++ b/runtime/doc/eval.txt @@ -8641,8 +8641,8 @@ setloclist({nr}, {list} [, {action} [, {what}]]) *setloclist()* GetLoclist()->setloclist(winnr) setmatches({list} [, {win}]) *setmatches()* - Restores a list of matches saved by |getmatches() for the - current window|. Returns 0 if successful, otherwise -1. All + Restores a list of matches saved by |getmatches()| for the + current window. Returns 0 if successful, otherwise -1. All current matches are cleared before the list is restored. See example for |getmatches()|. If {win} is specified, use the window with this number or diff --git a/src/testdir/test_bufline.vim b/src/testdir/test_bufline.vim index d359f205d5..3326e7d297 100644 --- a/src/testdir/test_bufline.vim +++ b/src/testdir/test_bufline.vim @@ -37,6 +37,7 @@ func Test_setbufline_getbufline() call assert_equal(['d'], getbufline(b, 4)) call assert_equal(['e'], getbufline(b, 5)) call assert_equal([], getbufline(b, 6)) + call assert_equal([], getbufline(b, 2, 1)) exe "bwipe! " . b endfunc diff --git a/src/testdir/test_channel.vim b/src/testdir/test_channel.vim index 4ba552bdbe..4a438ea729 100644 --- a/src/testdir/test_channel.vim +++ b/src/testdir/test_channel.vim @@ -869,8 +869,10 @@ func Test_pipe_both_to_buffer() let job = job_start(s:python . " test_channel_pipe.py", \ {'out_io': 'buffer', 'out_name': 'pipe-err', 'err_io': 'out'}) call assert_equal("run", job_status(job)) + let handle = job_getchannel(job) + call assert_equal(bufnr('pipe-err'), ch_getbufnr(handle, 'out')) + call assert_equal(bufnr('pipe-err'), ch_getbufnr(handle, 'err')) try - let handle = job_getchannel(job) call ch_sendraw(handle, "echo line one\n") call ch_sendraw(handle, "echoerr line two\n") call ch_sendraw(handle, "double this\n") @@ -896,6 +898,9 @@ func Run_test_pipe_from_buffer(use_name) let job = job_start(s:python . " test_channel_pipe.py", options) call assert_equal("run", job_status(job)) + if has('unix') && !a:use_name + call assert_equal(bufnr('%'), ch_getbufnr(job, 'in')) + endif try let handle = job_getchannel(job) call assert_equal('one', ch_read(handle)) diff --git a/src/testdir/test_clientserver.vim b/src/testdir/test_clientserver.vim index 4a48aed91c..152a2e1772 100644 --- a/src/testdir/test_clientserver.vim +++ b/src/testdir/test_clientserver.vim @@ -164,6 +164,7 @@ func Test_client_server() endif endtry + call assert_fails('call remote_startserver([])', 'E730:') call assert_fails("let x = remote_peek([])", 'E730:') call assert_fails("let x = remote_read('vim10')", 'E277:') call assert_fails("call server2client('abc', 'xyz')", 'E258:') diff --git a/src/testdir/test_expr.vim b/src/testdir/test_expr.vim index 5fc502df81..ec73aeaae4 100644 --- a/src/testdir/test_expr.vim +++ b/src/testdir/test_expr.vim @@ -471,6 +471,7 @@ func Test_setmatches() endif eval set->setmatches() call assert_equal(exp, getmatches()) + call assert_fails('let m = setmatches([], [])', 'E957:') endfunc func Test_empty_concatenate() diff --git a/src/testdir/test_functions.vim b/src/testdir/test_functions.vim index a0807ade7a..02b658554b 100644 --- a/src/testdir/test_functions.vim +++ b/src/testdir/test_functions.vim @@ -29,6 +29,8 @@ func Test_has() call assert_equal(0, and(has('ttyout'), 0)) call assert_equal(1, has('multi_byte_encoding')) endif + call assert_equal(1, has('vcon', 1)) + call assert_equal(1, has('mouse_gpm_enabled', 1)) call assert_equal(0, has('nonexistent')) call assert_equal(0, has('nonexistent', 1)) @@ -1304,12 +1306,15 @@ endfunc " Test for the inputdialog() function func Test_inputdialog() - CheckNotGui - - call feedkeys(":let v=inputdialog('Q:', 'xx', 'yy')\\", 'xt') - call assert_equal('xx', v) - call feedkeys(":let v=inputdialog('Q:', 'xx', 'yy')\\", 'xt') - call assert_equal('yy', v) + if has('gui_running') + call assert_fails('let v=inputdialog([], "xx")', 'E730:') + call assert_fails('let v=inputdialog("Q", [])', 'E730:') + else + call feedkeys(":let v=inputdialog('Q:', 'xx', 'yy')\\", 'xt') + call assert_equal('xx', v) + call feedkeys(":let v=inputdialog('Q:', 'xx', 'yy')\\", 'xt') + call assert_equal('yy', v) + endif endfunc " Test for inputlist() @@ -1344,6 +1349,7 @@ func Test_balloon_show() call balloon_show('hi!') if !has('gui_running') call balloon_show(range(3)) + call balloon_show([]) endif endif endfunc @@ -2213,6 +2219,9 @@ func Test_range() call assert_fails('let x=range(2, 8, 0)', 'E726:') call assert_fails('let x=range(3, 1)', 'E727:') call assert_fails('let x=range(1, 3, -2)', 'E727:') + call assert_fails('let x=range([])', 'E745:') + call assert_fails('let x=range(1, [])', 'E745:') + call assert_fails('let x=range(1, 4, [])', 'E745:') endfunc func Test_echoraw() diff --git a/src/testdir/test_listener.vim b/src/testdir/test_listener.vim index 0372420641..c1fa45e7a5 100644 --- a/src/testdir/test_listener.vim +++ b/src/testdir/test_listener.vim @@ -207,6 +207,11 @@ func Test_listener_args() call listener_remove(id) bwipe! + + " Invalid arguments + call assert_fails('call listener_add([])', 'E921:') + call assert_fails('call listener_add("s:StoreListArgs", [])', 'E158:') + call assert_fails('call listener_flush([])', 'E158:') endfunc func s:StoreBufList(buf, start, end, added, list) diff --git a/src/testdir/test_match.vim b/src/testdir/test_match.vim index cd8ae2eb56..fca646d6a7 100644 --- a/src/testdir/test_match.vim +++ b/src/testdir/test_match.vim @@ -163,6 +163,7 @@ func Test_matchadd_error() call assert_fails("call matchadd('Search', 'XXX', 1, 123, 1)", 'E715:') call assert_fails("call matchadd('Error', 'XXX', 1, 3)", 'E798:') call assert_fails("call matchadd('Error', 'XXX', 1, 0)", 'E799:') + call assert_fails("call matchadd('Error', 'XXX', [], 0)", 'E745:') endfunc func Test_matchaddpos() @@ -278,6 +279,8 @@ func Test_matchaddpos_error() call assert_fails("call matchaddpos('Error', [1], 1, 5, {'window':12345})", 'E957:') " Why doesn't the following error have an error code E...? call assert_fails("call matchaddpos('Error', [{}])", 'E290:') + call assert_equal(-1, matchaddpos('Error', test_null_list())) + call assert_fails("call matchaddpos('Error', [1], [], 1)", 'E745:') endfunc func OtherWindowCommon() @@ -334,5 +337,4 @@ func Test_matchadd_other_window() call delete('XscriptMatchCommon') endfunc - " vim: shiftwidth=2 sts=2 expandtab diff --git a/src/testdir/test_menu.vim b/src/testdir/test_menu.vim index 85d54f0833..4fd2828754 100644 --- a/src/testdir/test_menu.vim +++ b/src/testdir/test_menu.vim @@ -255,6 +255,7 @@ func Test_menu_info() nmenu Test.abc call assert_equal('', menu_info('Test.abc').rhs) call assert_fails('call menu_info([])', 'E730:') + call assert_fails('call menu_info("", [])', 'E730:') nunmenu Test " Test for defining menus in different modes diff --git a/src/testdir/test_quickfix.vim b/src/testdir/test_quickfix.vim index cfd9a35b7d..71a0f15ba9 100644 --- a/src/testdir/test_quickfix.vim +++ b/src/testdir/test_quickfix.vim @@ -1488,6 +1488,7 @@ func SetXlistTests(cchar, bnum) \ " {'bufnr':999, 'lnum':5}])", 'E92:') call g:Xsetlist([[1, 2,3]]) call assert_equal(0, len(g:Xgetlist())) + call assert_fails('call g:Xsetlist([], [])', 'E928:') endfunc func Test_setqflist() diff --git a/src/testdir/test_registers.vim b/src/testdir/test_registers.vim index 7e7bc07b22..f774153a91 100644 --- a/src/testdir/test_registers.vim +++ b/src/testdir/test_registers.vim @@ -259,6 +259,8 @@ func Test_get_register() call feedkeys(":\r\", 'xt') call assert_equal("a\rb\r", histget(':', -1)) + call assert_fails('let r = getreg("=", [])', 'E745:') + call assert_fails('let r = getreg("=", 1, [])', 'E745:') enew! endfunc diff --git a/src/testdir/test_reltime.vim b/src/testdir/test_reltime.vim index e25c3cede4..f4ce5de118 100644 --- a/src/testdir/test_reltime.vim +++ b/src/testdir/test_reltime.vim @@ -23,4 +23,9 @@ func Test_reltime() call assert_true(reltimestr(differs) != '0.0') call assert_true(reltimefloat(differs) < 0.1) call assert_true(reltimefloat(differs) > 0.0) + + call assert_equal(0, reltime({})) + call assert_equal(0, reltime({}, {})) endfunc + +" vim: shiftwidth=2 sts=2 expandtab diff --git a/src/testdir/test_terminal.vim b/src/testdir/test_terminal.vim index 549fdd16f7..d682a1975d 100644 --- a/src/testdir/test_terminal.vim +++ b/src/testdir/test_terminal.vim @@ -2634,4 +2634,22 @@ func Test_term_and_startinsert() call delete('XTest_startinsert') endfunc +" Test for passing invalid arguments to terminal functions +func Test_term_func_invalid_arg() + call assert_fails('let b = term_getaltscreen([])', 'E745:') + call assert_fails('let p = term_getansicolors([])', 'E745:') + call assert_fails('let a = term_getattr(1, [])', 'E730:') + call assert_fails('let c = term_getcursor([])', 'E745:') + call assert_fails('let l = term_getline([], 1)', 'E745:') + call assert_fails('let l = term_getscrolled([])', 'E745:') + call assert_fails('let s = term_getsize([])', 'E745:') + call assert_fails('let s = term_getstatus([])', 'E745:') + call assert_fails('let s = term_scrape([], 1)', 'E745:') + call assert_fails('call term_sendkeys([], "a")', 'E745:') + call assert_fails('call term_setansicolors([], [])', 'E745:') + call assert_fails('call term_setapi([], "")', 'E745:') + call assert_fails('call term_setrestore([], "")', 'E745:') + call assert_fails('call term_setkill([], "")', 'E745:') +endfunc + " vim: shiftwidth=2 sts=2 expandtab diff --git a/src/testdir/test_textprop.vim b/src/testdir/test_textprop.vim index 692b0c4bd0..f91597ff51 100644 --- a/src/testdir/test_textprop.vim +++ b/src/testdir/test_textprop.vim @@ -1204,3 +1204,28 @@ func Test_find_zerowidth_prop_sol() bwipe! call prop_type_delete('test') endfunc + +" Test for passing invalid arguments to prop_xxx() functions +func Test_prop_func_invalid_args() + call assert_fails('call prop_clear(1, 2, [])', 'E715:') + call assert_fails('call prop_clear(-1, 2)', 'E16:') + call assert_fails('call prop_find(test_null_dict())', 'E474:') + call assert_fails('call prop_find({"bufnr" : []})', 'E158:') + call assert_fails('call prop_find({})', 'E968:') + call assert_fails('call prop_find({}, "x")', 'E474:') + call assert_fails('call prop_find({"lnum" : -2})', 'E16:') + call assert_fails('call prop_list(1, [])', 'E715:') + call assert_fails('call prop_list(-1 , {})', 'E16:') + call assert_fails('call prop_remove([])', 'E474:') + call assert_fails('call prop_remove({}, -2)', 'E16:') + call assert_fails('call prop_remove({})', 'E968:') + call assert_fails('call prop_type_add([], {})', 'E474:') + call assert_fails("call prop_type_change('long', {'xyz' : 10})", 'E971:') + call assert_fails("call prop_type_delete([])", 'E474:') + call assert_fails("call prop_type_delete('xyz', [])", 'E715:') + call assert_fails("call prop_type_get([])", 'E474:') + call assert_fails("call prop_type_get('', [])", 'E474:') + call assert_fails("call prop_type_list([])", 'E715:') +endfunc + +" vim: shiftwidth=2 sts=2 expandtab diff --git a/src/testdir/test_window_cmd.vim b/src/testdir/test_window_cmd.vim index 4927842454..e20bfa5f9e 100644 --- a/src/testdir/test_window_cmd.vim +++ b/src/testdir/test_window_cmd.vim @@ -445,6 +445,7 @@ func Test_win_screenpos() call assert_equal([1, 32], win_screenpos(2)) call assert_equal([12, 1], win_screenpos(3)) call assert_equal([0, 0], win_screenpos(4)) + call assert_fails('let l = win_screenpos([])', 'E745:') only endfunc @@ -694,6 +695,7 @@ func Test_relative_cursor_position_in_one_line_window() only! bwipe! + call assert_fails('call winrestview(test_null_dict())', 'E474:') endfunc func Test_relative_cursor_position_after_move_and_resize() @@ -870,6 +872,10 @@ func Test_winnr() call assert_fails("echo winnr('ll')", 'E15:') call assert_fails("echo winnr('5')", 'E15:') call assert_equal(4, winnr('0h')) + call assert_fails("let w = winnr([])", 'E730:') + call assert_equal('unknown', win_gettype(-1)) + call assert_equal(-1, winheight(-1)) + call assert_equal(-1, winwidth(-1)) tabnew call assert_equal(8, tabpagewinnr(1, 'j')) @@ -890,6 +896,7 @@ func Test_winrestview() call assert_equal(view, winsaveview()) bwipe! + call assert_fails('call winrestview(test_null_dict())', 'E474:') endfunc func Test_win_splitmove() @@ -920,6 +927,7 @@ func Test_win_splitmove() call assert_equal(bufname(winbufnr(2)), 'b') call assert_equal(bufname(winbufnr(3)), 'a') call assert_equal(bufname(winbufnr(4)), 'd') + call assert_fails('call win_splitmove(winnr(), winnr("k"), test_null_dict())', 'E474:') only | bd call assert_fails('call win_splitmove(winnr(), 123)', 'E957:') diff --git a/src/testdir/test_window_id.vim b/src/testdir/test_window_id.vim index 9c92faeea5..20465ae74b 100644 --- a/src/testdir/test_window_id.vim +++ b/src/testdir/test_window_id.vim @@ -91,6 +91,10 @@ func Test_win_getid() split call assert_equal(sort([id5, win_getid()]), sort(win_findbuf(bufnr5))) + call assert_fails('let w = win_getid([])', 'E745:') + call assert_equal(0, win_getid(-1)) + call assert_equal(-1, win_getid(1, -1)) + only! endfunc @@ -130,4 +134,8 @@ func Test_winlayout() let w2 = win_getid() call assert_equal(['leaf', w2], 2->winlayout()) tabclose + + call assert_equal([], winlayout(-1)) endfunc + +" vim: shiftwidth=2 sts=2 expandtab diff --git a/src/testdir/test_writefile.vim b/src/testdir/test_writefile.vim index 497fa0bc7f..58e438c891 100644 --- a/src/testdir/test_writefile.vim +++ b/src/testdir/test_writefile.vim @@ -207,6 +207,12 @@ func Test_saveas() close! enew | only call delete('Xfile') + + call writefile(test_null_list(), 'Xfile') + call assert_false(filereadable('Xfile')) + call writefile(test_null_blob(), 'Xfile') + call assert_false(filereadable('Xfile')) + call assert_fails('call writefile([], "")', 'E482:') endfunc func Test_write_errors() @@ -245,6 +251,12 @@ func Test_write_errors() close call delete('Xfile') + + call writefile(test_null_list(), 'Xfile') + call assert_false(filereadable('Xfile')) + call writefile(test_null_blob(), 'Xfile') + call assert_false(filereadable('Xfile')) + call assert_fails('call writefile([], "")', 'E482:') endfunc " vim: shiftwidth=2 sts=2 expandtab diff --git a/src/version.c b/src/version.c index e78fc73390..8c4cc71b20 100644 --- a/src/version.c +++ b/src/version.c @@ -746,6 +746,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 644, /**/ 643, /**/ From 07b761a012958ca91fa420f9c86a33675ddca943 Mon Sep 17 00:00:00 2001 From: Bram Moolenaar Date: Sun, 26 Apr 2020 16:06:01 +0200 Subject: [PATCH 039/230] patch 8.2.0645: MS-Windows terminal: CTRL-C does not get to child job Problem: MS-Windows terminal: CTRL-C does not get to child job. Solution: Remove CREATE_NEW_PROCESS_GROUP from CreateProcessW(). (Nobuhiro Takasaki, closes #5987) --- src/terminal.c | 3 +-- src/version.c | 2 ++ 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/src/terminal.c b/src/terminal.c index 9d9dd6a6d3..fa18d70225 100644 --- a/src/terminal.c +++ b/src/terminal.c @@ -6300,8 +6300,7 @@ conpty_term_and_job_init( if (!CreateProcessW(NULL, cmd_wchar_copy, NULL, NULL, FALSE, EXTENDED_STARTUPINFO_PRESENT | CREATE_UNICODE_ENVIRONMENT - | CREATE_SUSPENDED | CREATE_NEW_PROCESS_GROUP - | CREATE_DEFAULT_ERROR_MODE, + | CREATE_SUSPENDED | CREATE_DEFAULT_ERROR_MODE, env_wchar, cwd_wchar, &term->tl_siex.StartupInfo, &proc_info)) goto failed; diff --git a/src/version.c b/src/version.c index 8c4cc71b20..392ac18932 100644 --- a/src/version.c +++ b/src/version.c @@ -746,6 +746,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 645, /**/ 644, /**/ From 759d81549c1340185f0d92524c563bb37697ea88 Mon Sep 17 00:00:00 2001 From: Bram Moolenaar Date: Sun, 26 Apr 2020 16:52:49 +0200 Subject: [PATCH 040/230] patch 8.2.0646: t_Co uses the value of $COLORS in the GUI Problem: t_Co uses the value of $COLORS in the GUI. (Masato Nishihata) Solution: Ignore $COLORS for the GUI. (closes #5992) --- src/os_unix.c | 7 +------ src/term.c | 18 ++++++++++++------ src/version.c | 2 ++ 3 files changed, 15 insertions(+), 12 deletions(-) diff --git a/src/os_unix.c b/src/os_unix.c index c6d386b929..66903e0819 100644 --- a/src/os_unix.c +++ b/src/os_unix.c @@ -4160,11 +4160,6 @@ set_child_environment( static char envbuf_Servername[60]; # endif # endif - long colors = -# ifdef FEAT_GUI - gui.in_use ? 256*256*256 : -# endif - t_colors; # ifdef HAVE_SETENV setenv("TERM", term, 1); @@ -4174,7 +4169,7 @@ set_child_environment( setenv("LINES", (char *)envbuf, 1); sprintf((char *)envbuf, "%ld", columns); setenv("COLUMNS", (char *)envbuf, 1); - sprintf((char *)envbuf, "%ld", colors); + sprintf((char *)envbuf, "%d", t_colors); setenv("COLORS", (char *)envbuf, 1); # ifdef FEAT_TERMINAL if (is_terminal) diff --git a/src/term.c b/src/term.c index ef91b8fac5..f5d5dbc6f7 100644 --- a/src/term.c +++ b/src/term.c @@ -3122,15 +3122,21 @@ ttest(int pairs) } need_gather = TRUE; - // Set t_colors to the value of $COLORS or t_Co. + // Set t_colors to the value of $COLORS or t_Co. Ignore $COLORS in the + // GUI. t_colors = atoi((char *)T_CCO); - env_colors = mch_getenv((char_u *)"COLORS"); - if (env_colors != NULL && isdigit(*env_colors)) +#ifdef FEAT_GUI + if (!gui.in_use) +#endif { - int colors = atoi((char *)env_colors); + env_colors = mch_getenv((char_u *)"COLORS"); + if (env_colors != NULL && isdigit(*env_colors)) + { + int colors = atoi((char *)env_colors); - if (colors != t_colors) - set_color_count(colors); + if (colors != t_colors) + set_color_count(colors); + } } } diff --git a/src/version.c b/src/version.c index 392ac18932..16145f2d67 100644 --- a/src/version.c +++ b/src/version.c @@ -746,6 +746,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 646, /**/ 645, /**/ From bc970da80735bfd49c238cdf4bbc60c04dc12e0f Mon Sep 17 00:00:00 2001 From: Bram Moolenaar Date: Sun, 26 Apr 2020 19:00:07 +0200 Subject: [PATCH 041/230] patch 8.2.0647: MS-Windows: repeat count for events was not used Problem: MS-Windows: repeat count for events was not used. Solution: Check the repeat count. (Nobuhiro Takasaki, closes #5989) --- src/os_win32.c | 14 ++++++++++++++ src/version.c | 2 ++ 2 files changed, 16 insertions(+) diff --git a/src/os_win32.c b/src/os_win32.c index 6b32869756..85efc52663 100644 --- a/src/os_win32.c +++ b/src/os_win32.c @@ -307,6 +307,7 @@ read_console_input( int head; int tail; int i; + static INPUT_RECORD s_irPseudo; if (nLength == -2) return (s_dwMax > 0) ? TRUE : FALSE; @@ -354,6 +355,19 @@ read_console_input( } } + if (s_irCache[s_dwIndex].EventType == KEY_EVENT) + { + if (s_irCache[s_dwIndex].Event.KeyEvent.wRepeatCount > 1) + { + s_irPseudo = s_irCache[s_dwIndex]; + s_irPseudo.Event.KeyEvent.wRepeatCount = 1; + s_irCache[s_dwIndex].Event.KeyEvent.wRepeatCount--; + *lpBuffer = s_irPseudo; + *lpEvents = 1; + return TRUE; + } + } + *lpBuffer = s_irCache[s_dwIndex]; if (!(nLength == -1 || nLength == -2) && ++s_dwIndex >= s_dwMax) s_dwMax = 0; diff --git a/src/version.c b/src/version.c index 16145f2d67..9323b1d09d 100644 --- a/src/version.c +++ b/src/version.c @@ -746,6 +746,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 647, /**/ 646, /**/ From 0e71704b77a9891ccae9f5a9c7429e933078f232 Mon Sep 17 00:00:00 2001 From: Bram Moolenaar Date: Mon, 27 Apr 2020 19:29:01 +0200 Subject: [PATCH 042/230] patch 8.2.0648: semicolon search does not work in first line Problem: Semicolon search does not work in first line. Solution: Allow the cursor to be in line zero. (Christian Brabandt, closes #5996) --- src/ex_docmd.c | 6 ++++-- src/testdir/test_cmdline.vim | 11 +++++++++++ src/version.c | 2 ++ 3 files changed, 17 insertions(+), 2 deletions(-) diff --git a/src/ex_docmd.c b/src/ex_docmd.c index 43cd013e2c..ca69c293d6 100644 --- a/src/ex_docmd.c +++ b/src/ex_docmd.c @@ -3069,8 +3069,10 @@ parse_cmd_address(exarg_T *eap, char **errormsg, int silent) if (!eap->skip) { curwin->w_cursor.lnum = eap->line2; - // don't leave the cursor on an illegal line or column - check_cursor(); + // Don't leave the cursor on an illegal line or column, but do + // accept zero as address, so 0;/PATTERN/ works correctly. + if (eap->line2 > 0) + check_cursor(); } } else if (*eap->cmd != ',') diff --git a/src/testdir/test_cmdline.vim b/src/testdir/test_cmdline.vim index 7d3c0c87d0..a5473267dc 100644 --- a/src/testdir/test_cmdline.vim +++ b/src/testdir/test_cmdline.vim @@ -1471,4 +1471,15 @@ func Test_cmdwin_insert_mode_close() call assert_equal(1, winnr('$')) endfunc +" test that ";" works to find a match at the start of the first line +func Test_zero_line_search() + new + call setline(1, ["1, pattern", "2, ", "3, pattern"]) + call cursor(1,1) + 0;/pattern/d + call assert_equal(["2, ", "3, pattern"], getline(1,'$')) + q! +endfunc + + " vim: shiftwidth=2 sts=2 expandtab diff --git a/src/version.c b/src/version.c index 9323b1d09d..a9a2e293e8 100644 --- a/src/version.c +++ b/src/version.c @@ -746,6 +746,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 648, /**/ 647, /**/ From db93495d276642f63f80471fbcb900b9aa1e9e42 Mon Sep 17 00:00:00 2001 From: Bram Moolenaar Date: Mon, 27 Apr 2020 20:18:31 +0200 Subject: [PATCH 043/230] patch 8.2.0649: undo problem whn an InsertLeave autocommand resets undo Problem: Undo problem whn an InsertLeave autocommand resets undo. (Kutsan Kaplan) Solution: Do not create a new undo block when leaving Insert mode. --- src/edit.c | 3 ++- src/testdir/test_edit.vim | 17 ++++++++++++++++- src/version.c | 2 ++ 3 files changed, 20 insertions(+), 2 deletions(-) diff --git a/src/edit.c b/src/edit.c index 05518ceab8..7f4f765012 100644 --- a/src/edit.c +++ b/src/edit.c @@ -5994,7 +5994,8 @@ ins_apply_autocmds(event_T event) // If u_savesub() was called then we are not prepared to start // a new line. Call u_save() with no contents to fix that. - if (tick != CHANGEDTICK(curbuf)) + // Except when leaving Insert mode. + if (event != EVENT_INSERTLEAVE && tick != CHANGEDTICK(curbuf)) u_save(curwin->w_cursor.lnum, (linenr_T)(curwin->w_cursor.lnum + 1)); return r; diff --git a/src/testdir/test_edit.vim b/src/testdir/test_edit.vim index ce55f6be0b..a9ba31df4c 100644 --- a/src/testdir/test_edit.vim +++ b/src/testdir/test_edit.vim @@ -1444,7 +1444,7 @@ func Test_edit_alt() call delete('XAltFile') endfunc -func Test_leave_insert_autocmd() +func Test_edit_InsertLeave() new au InsertLeave * let g:did_au = 1 let g:did_au = 0 @@ -1474,6 +1474,21 @@ func Test_leave_insert_autocmd() iunmap x endfunc +func Test_edit_InsertLeave_undo() + new XtestUndo + set undofile + au InsertLeave * wall + exe "normal ofoo\" + call assert_equal(2, line('$')) + normal u + call assert_equal(1, line('$')) + + bwipe! + au! InsertLeave + call delete('XtestUndo') + set undofile& +endfunc + " Test for inserting characters using CTRL-V followed by a number. func Test_edit_special_chars() new diff --git a/src/version.c b/src/version.c index a9a2e293e8..fa91a2bc04 100644 --- a/src/version.c +++ b/src/version.c @@ -746,6 +746,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 649, /**/ 648, /**/ From 4c17ad94ecb0a0fb26d6fface2614bc5172dea18 Mon Sep 17 00:00:00 2001 From: Bram Moolenaar Date: Mon, 27 Apr 2020 22:47:51 +0200 Subject: [PATCH 044/230] patch 8.2.0650: Vim9: script function can be deleted Problem: Vim9: script function can be deleted. Solution: Disallow deleting script function. Delete functions when sourcing a script again. --- src/evalfunc.c | 20 ++---- src/proto/userfunc.pro | 7 +- src/scriptfile.c | 5 ++ src/testdir/test_vim9_expr.vim | 34 ++++----- src/testdir/test_vim9_func.vim | 4 +- src/testdir/test_vim9_script.vim | 96 ++++++++++++++++++++++++-- src/testing.c | 2 +- src/userfunc.c | 115 +++++++++++++++++++++++-------- src/version.c | 2 + src/vim9compile.c | 4 +- src/vim9execute.c | 9 +-- src/vim9script.c | 2 +- 12 files changed, 219 insertions(+), 81 deletions(-) diff --git a/src/evalfunc.c b/src/evalfunc.c index 8cd137a4dd..02943c717a 100644 --- a/src/evalfunc.c +++ b/src/evalfunc.c @@ -2679,6 +2679,7 @@ common_function(typval_T *argvars, typval_T *rettv, int is_funcref) int use_string = FALSE; partial_T *arg_pt = NULL; char_u *trans_name = NULL; + int is_global = FALSE; if (argvars[0].v_type == VAR_FUNC) { @@ -2702,21 +2703,10 @@ common_function(typval_T *argvars, typval_T *rettv, int is_funcref) if ((use_string && vim_strchr(s, AUTOLOAD_CHAR) == NULL) || is_funcref) { name = s; - trans_name = trans_function_name(&name, FALSE, + trans_name = trans_function_name(&name, &is_global, FALSE, TFN_INT | TFN_QUIET | TFN_NO_AUTOLOAD | TFN_NO_DEREF, NULL, NULL); if (*name != NUL) s = NULL; - else if (trans_name != NULL - && ASCII_ISUPPER(*s) - && current_sctx.sc_version == SCRIPT_VERSION_VIM9 - && find_func(trans_name, NULL) == NULL) - { - // With Vim9 script "MyFunc" can be script-local to the current - // script or global. The script-local name is not found, assume - // global. - vim_free(trans_name); - trans_name = vim_strsave(s); - } } if (s == NULL || *s == NUL || (use_string && VIM_ISDIGIT(*s)) @@ -2724,8 +2714,8 @@ common_function(typval_T *argvars, typval_T *rettv, int is_funcref) semsg(_(e_invarg2), use_string ? tv_get_string(&argvars[0]) : s); // Don't check an autoload name for existence here. else if (trans_name != NULL && (is_funcref - ? find_func(trans_name, NULL) == NULL - : !translated_function_exists(trans_name))) + ? find_func(trans_name, is_global, NULL) == NULL + : !translated_function_exists(trans_name, is_global))) semsg(_("E700: Unknown function: %s"), s); else { @@ -2862,7 +2852,7 @@ common_function(typval_T *argvars, typval_T *rettv, int is_funcref) } else if (is_funcref) { - pt->pt_func = find_func(trans_name, NULL); + pt->pt_func = find_func(trans_name, is_global, NULL); func_ptr_ref(pt->pt_func); vim_free(name); } diff --git a/src/proto/userfunc.pro b/src/proto/userfunc.pro index 19097fe2ec..81d69386f0 100644 --- a/src/proto/userfunc.pro +++ b/src/proto/userfunc.pro @@ -7,11 +7,12 @@ char_u *deref_func_name(char_u *name, int *lenp, partial_T **partialp, int no_au void emsg_funcname(char *ermsg, char_u *name); int get_func_tv(char_u *name, int len, typval_T *rettv, char_u **arg, funcexe_T *funcexe); char_u *fname_trans_sid(char_u *name, char_u *fname_buf, char_u **tofree, int *error); -ufunc_T *find_func(char_u *name, cctx_T *cctx); +ufunc_T *find_func(char_u *name, int is_global, cctx_T *cctx); int call_user_func_check(ufunc_T *fp, int argcount, typval_T *argvars, typval_T *rettv, funcexe_T *funcexe, dict_T *selfdict); void save_funccal(funccal_entry_T *entry); void restore_funccal(void); funccall_T *get_current_funccal(void); +void delete_script_functions(int sid); void free_all_functions(void); int builtin_function(char_u *name, int len); int func_call(char_u *name, typval_T *args, partial_T *partial, dict_T *selfdict, typval_T *rettv); @@ -19,11 +20,11 @@ int get_callback_depth(void); int call_callback(callback_T *callback, int len, typval_T *rettv, int argcount, typval_T *argvars); void user_func_error(int error, char_u *name); int call_func(char_u *funcname, int len, typval_T *rettv, int argcount_in, typval_T *argvars_in, funcexe_T *funcexe); -char_u *trans_function_name(char_u **pp, int skip, int flags, funcdict_T *fdp, partial_T **partial); +char_u *trans_function_name(char_u **pp, int *is_global, int skip, int flags, funcdict_T *fdp, partial_T **partial); char_u *untrans_function_name(char_u *name); void ex_function(exarg_T *eap); int eval_fname_script(char_u *p); -int translated_function_exists(char_u *name); +int translated_function_exists(char_u *name, int is_global); int has_varargs(ufunc_T *ufunc); int function_exists(char_u *name, int no_deref); char_u *get_expanded_name(char_u *name, int check); diff --git a/src/scriptfile.c b/src/scriptfile.c index 3b7652d1fb..0756116b10 100644 --- a/src/scriptfile.c +++ b/src/scriptfile.c @@ -1275,6 +1275,7 @@ do_source( hashitem_T *hi; dictitem_T *di; int todo; + int is_vim9 = si->sn_version == SCRIPT_VERSION_VIM9; // loading the same script again si->sn_had_command = FALSE; @@ -1293,6 +1294,10 @@ do_source( // old imports are no longer valid free_imports(sid); + + // in Vim9 script functions are marked deleted + if (is_vim9) + delete_script_functions(sid); } else { diff --git a/src/testdir/test_vim9_expr.vim b/src/testdir/test_vim9_expr.vim index 42a99261fb..463227257a 100644 --- a/src/testdir/test_vim9_expr.vim +++ b/src/testdir/test_vim9_expr.vim @@ -207,12 +207,12 @@ def Test_expr4_equal() assert_equal(true, g:adict == #{bbb: 8, aaa: 2}) assert_equal(false, #{ccc: 9, aaa: 2} == g:adict) - assert_equal(true, function('Test_expr4_equal') == function('Test_expr4_equal')) - assert_equal(false, function('Test_expr4_equal') == function('Test_expr4_is')) + assert_equal(true, function('g:Test_expr4_equal') == function('g:Test_expr4_equal')) + assert_equal(false, function('g:Test_expr4_equal') == function('g:Test_expr4_is')) - assert_equal(true, function('Test_expr4_equal', [123]) == function('Test_expr4_equal', [123])) - assert_equal(false, function('Test_expr4_equal', [123]) == function('Test_expr4_is', [123])) - assert_equal(false, function('Test_expr4_equal', [123]) == function('Test_expr4_equal', [999])) + assert_equal(true, function('g:Test_expr4_equal', [123]) == function('g:Test_expr4_equal', [123])) + assert_equal(false, function('g:Test_expr4_equal', [123]) == function('g:Test_expr4_is', [123])) + assert_equal(false, function('g:Test_expr4_equal', [123]) == function('g:Test_expr4_equal', [999])) enddef " test != comperator @@ -274,12 +274,12 @@ def Test_expr4_notequal() assert_equal(false, g:adict != #{bbb: 8, aaa: 2}) assert_equal(true, #{ccc: 9, aaa: 2} != g:adict) - assert_equal(false, function('Test_expr4_equal') != function('Test_expr4_equal')) - assert_equal(true, function('Test_expr4_equal') != function('Test_expr4_is')) + assert_equal(false, function('g:Test_expr4_equal') != function('g:Test_expr4_equal')) + assert_equal(true, function('g:Test_expr4_equal') != function('g:Test_expr4_is')) - assert_equal(false, function('Test_expr4_equal', [123]) != function('Test_expr4_equal', [123])) - assert_equal(true, function('Test_expr4_equal', [123]) != function('Test_expr4_is', [123])) - assert_equal(true, function('Test_expr4_equal', [123]) != function('Test_expr4_equal', [999])) + assert_equal(false, function('g:Test_expr4_equal', [123]) != function('g:Test_expr4_equal', [123])) + assert_equal(true, function('g:Test_expr4_equal', [123]) != function('g:Test_expr4_is', [123])) + assert_equal(true, function('g:Test_expr4_equal', [123]) != function('g:Test_expr4_equal', [999])) enddef " test > comperator @@ -929,15 +929,15 @@ endfunc def Test_expr7_trailing() " user function call - assert_equal(123, CallMe(123)) - assert_equal(123, CallMe( 123)) - assert_equal(123, CallMe(123 )) - assert_equal('yesno', CallMe2('yes', 'no')) - assert_equal('yesno', CallMe2( 'yes', 'no' )) - assert_equal('nothing', CallMe('nothing')) + assert_equal(123, g:CallMe(123)) + assert_equal(123, g:CallMe( 123)) + assert_equal(123, g:CallMe(123 )) + assert_equal('yesno', g:CallMe2('yes', 'no')) + assert_equal('yesno', g:CallMe2( 'yes', 'no' )) + assert_equal('nothing', g:CallMe('nothing')) " partial call - let Part = function('CallMe') + let Part = function('g:CallMe') assert_equal('yes', Part('yes')) " funcref call, using list index diff --git a/src/testdir/test_vim9_func.vim b/src/testdir/test_vim9_func.vim index f3721ba9f9..2ee91f1abd 100644 --- a/src/testdir/test_vim9_func.vim +++ b/src/testdir/test_vim9_func.vim @@ -353,7 +353,7 @@ endfunc def Test_delfunc() let lines =<< trim END vim9script - def GoneSoon() + def g:GoneSoon() echo 'hello' enddef @@ -361,7 +361,7 @@ def Test_delfunc() GoneSoon() enddef - delfunc GoneSoon + delfunc g:GoneSoon CallGoneSoon() END writefile(lines, 'XToDelFunc') diff --git a/src/testdir/test_vim9_script.vim b/src/testdir/test_vim9_script.vim index 218ef77402..0ab170ef12 100644 --- a/src/testdir/test_vim9_script.vim +++ b/src/testdir/test_vim9_script.vim @@ -53,7 +53,7 @@ def Test_assignment() endif let Funky1: func let Funky2: func = function('len') - let Party2: func = funcref('Test_syntax') + let Party2: func = funcref('g:Test_syntax') # type becomes list let somelist = rand() > 0 ? [1, 2, 3] : ['a', 'b', 'c'] @@ -282,6 +282,49 @@ def Test_unlet() assert_equal('', $ENVVAR) enddef +def Test_delfunction() + " Check function is defined in script namespace + CheckScriptSuccess([ + 'vim9script', + 'func CheckMe()', + ' return 123', + 'endfunc', + 'assert_equal(123, s:CheckMe())', + ]) + + " Check function in script namespace cannot be deleted + CheckScriptFailure([ + 'vim9script', + 'func DeleteMe1()', + 'endfunc', + 'delfunction DeleteMe1', + ], 'E1084:') + CheckScriptFailure([ + 'vim9script', + 'func DeleteMe2()', + 'endfunc', + 'def DoThat()', + ' delfunction DeleteMe2', + 'enddef', + 'DoThat()', + ], 'E1084:') + CheckScriptFailure([ + 'vim9script', + 'def DeleteMe3()', + 'enddef', + 'delfunction DeleteMe3', + ], 'E1084:') + CheckScriptFailure([ + 'vim9script', + 'def DeleteMe4()', + 'enddef', + 'def DoThat()', + ' delfunction DeleteMe4', + 'enddef', + 'DoThat()', + ], 'E1084:') +enddef + func Test_wrong_type() call CheckDefFailure(['let var: list'], 'E1010:') call CheckDefFailure(['let var: list>'], 'E1010:') @@ -649,7 +692,7 @@ def Test_vim9script_fails() assert_fails('export something', 'E1043') enddef -def Test_vim9script_reload() +def Test_vim9script_reload_import() let lines =<< trim END vim9script const var = '' @@ -700,6 +743,47 @@ def Test_vim9script_reload() delete('Ximport.vim') enddef +def Test_vim9script_reload_delfunc() + let first_lines =<< trim END + vim9script + def FuncYes(): string + return 'yes' + enddef + END + let middle_lines =<< trim END + def FuncNo(): string + return 'no' + enddef + END + let final_lines =<< trim END + def g:DoCheck(no_exists: bool) + assert_equal('yes', FuncYes()) + if no_exists + assert_equal('no', FuncNo()) + else + assert_fails('call FuncNo()', 'E117:') + endif + enddef + END + + # FuncNo() is defined + writefile(first_lines + middle_lines + final_lines, 'Xreloaded.vim') + source Xreloaded.vim + g:DoCheck(true) + + # FuncNo() is not redefined + writefile(first_lines + final_lines, 'Xreloaded.vim') + source Xreloaded.vim + g:DoCheck(false) + + # FuncNo() is back + writefile(first_lines + middle_lines + final_lines, 'Xreloaded.vim') + source Xreloaded.vim + g:DoCheck(true) + + delete('Xreloaded.vim') +enddef + def Test_import_absolute() let import_lines = [ 'vim9script', @@ -1445,15 +1529,15 @@ def Test_vim9_comment() CheckScriptSuccess([ 'vim9script', - 'func DeleteMe()', + 'func g:DeleteMeA()', 'endfunc', - 'delfunction DeleteMe # comment', + 'delfunction g:DeleteMeA # comment', ]) CheckScriptFailure([ 'vim9script', - 'func DeleteMe()', + 'func g:DeleteMeB()', 'endfunc', - 'delfunction DeleteMe# comment', + 'delfunction g:DeleteMeB# comment', ], 'E488:') CheckScriptSuccess([ diff --git a/src/testing.c b/src/testing.c index 35c268349b..604d39b74c 100644 --- a/src/testing.c +++ b/src/testing.c @@ -789,7 +789,7 @@ f_test_refcount(typval_T *argvars, typval_T *rettv) { ufunc_T *fp; - fp = find_func(argvars[0].vval.v_string, NULL); + fp = find_func(argvars[0].vval.v_string, FALSE, NULL); if (fp != NULL) retval = fp->uf_refcount; } diff --git a/src/userfunc.c b/src/userfunc.c index 6005af1f59..993697e46d 100644 --- a/src/userfunc.c +++ b/src/userfunc.c @@ -25,6 +25,7 @@ #define FC_DEAD 0x80 // function kept only for reference to dfunc #define FC_EXPORT 0x100 // "export def Func()" #define FC_NOARGS 0x200 // no a: variables in lambda +#define FC_VIM9 0x400 // defined in vim9 script file /* * All user-defined functions are found in this hashtable. @@ -710,16 +711,17 @@ find_func_with_sid(char_u *name, int sid) /* * Find a function by name, return pointer to it in ufuncs. + * When "is_global" is true don't find script-local or imported functions. * Return NULL for unknown function. */ static ufunc_T * -find_func_even_dead(char_u *name, cctx_T *cctx) +find_func_even_dead(char_u *name, int is_global, cctx_T *cctx) { hashitem_T *hi; ufunc_T *func; imported_T *imported; - if (in_vim9script()) + if (in_vim9script() && !is_global) { // Find script-local function before global one. func = find_func_with_sid(name, current_sctx.sc_sid); @@ -750,9 +752,9 @@ find_func_even_dead(char_u *name, cctx_T *cctx) * Return NULL for unknown or dead function. */ ufunc_T * -find_func(char_u *name, cctx_T *cctx) +find_func(char_u *name, int is_global, cctx_T *cctx) { - ufunc_T *fp = find_func_even_dead(name, cctx); + ufunc_T *fp = find_func_even_dead(name, is_global, cctx); if (fp != NULL && (fp->uf_flags & FC_DEAD) == 0) return fp; @@ -1575,6 +1577,38 @@ get_current_funccal(void) return current_funccal; } +/* + * Mark all functions of script "sid" as deleted. + */ + void +delete_script_functions(int sid) +{ + hashitem_T *hi; + ufunc_T *fp; + long_u todo; + char buf[30]; + size_t len; + + buf[0] = K_SPECIAL; + buf[1] = KS_EXTRA; + buf[2] = (int)KE_SNR; + sprintf(buf + 3, "%d_", sid); + len = STRLEN(buf); + + todo = func_hashtab.ht_used; + for (hi = func_hashtab.ht_array; todo > 0; ++hi) + if (!HASHITEM_EMPTY(hi)) + { + if (STRNCMP(fp->uf_name, buf, len) == 0) + { + fp = HI2UF(hi); + fp->uf_flags |= FC_DEAD; + func_clear(fp, TRUE); + } + --todo; + } +} + #if defined(EXITFREE) || defined(PROTO) void free_all_functions(void) @@ -1884,22 +1918,22 @@ call_func( * User defined function. */ if (fp == NULL) - fp = find_func(rfname, NULL); + fp = find_func(rfname, FALSE, NULL); // Trigger FuncUndefined event, may load the function. if (fp == NULL && apply_autocmds(EVENT_FUNCUNDEFINED, - rfname, rfname, TRUE, NULL) + rfname, rfname, TRUE, NULL) && !aborting()) { // executed an autocommand, search for the function again - fp = find_func(rfname, NULL); + fp = find_func(rfname, FALSE, NULL); } // Try loading a package. if (fp == NULL && script_autoload(rfname, TRUE) && !aborting()) { // loaded a package, search for the function again - fp = find_func(rfname, NULL); + fp = find_func(rfname, FALSE, NULL); } if (fp == NULL) { @@ -1908,7 +1942,7 @@ call_func( // If using Vim9 script try not local to the script. // TODO: should not do this if the name started with "s:". if (p != NULL) - fp = find_func(p, NULL); + fp = find_func(p, FALSE, NULL); } if (fp != NULL && (fp->uf_flags & FC_DELETED)) @@ -2079,6 +2113,8 @@ list_func_head(ufunc_T *fp, int indent) * Get a function name, translating "" and "". * Also handles a Funcref in a List or Dictionary. * Returns the function name in allocated memory, or NULL for failure. + * Set "*is_global" to TRUE when the function must be global, unless + * "is_global" is NULL. * flags: * TFN_INT: internal function name OK * TFN_QUIET: be quiet @@ -2089,6 +2125,7 @@ list_func_head(ufunc_T *fp, int indent) char_u * trans_function_name( char_u **pp, + int *is_global, int skip, // only find the end, don't evaluate int flags, funcdict_T *fdp, // return: info about dictionary used @@ -2239,7 +2276,11 @@ trans_function_name( { // skip over "s:" and "g:" if (lead == 2 || (lv.ll_name[0] == 'g' && lv.ll_name[1] == ':')) + { + if (is_global != NULL && lv.ll_name[0] == 'g') + *is_global = TRUE; lv.ll_name += 2; + } len = (int)(end - lv.ll_name); } @@ -2347,6 +2388,7 @@ ex_function(exarg_T *eap) int saved_did_emsg; int saved_wait_return = need_wait_return; char_u *name = NULL; + int is_global = FALSE; char_u *p; char_u *arg; char_u *line_arg = NULL; @@ -2463,7 +2505,8 @@ ex_function(exarg_T *eap) * g:func global function name, same as "func" */ p = eap->arg; - name = trans_function_name(&p, eap->skip, TFN_NO_AUTOLOAD, &fudi, NULL); + name = trans_function_name(&p, &is_global, eap->skip, + TFN_NO_AUTOLOAD, &fudi, NULL); paren = (vim_strchr(p, '(') != NULL); if (name == NULL && (fudi.fd_dict == NULL || !paren) && !eap->skip) { @@ -2503,7 +2546,7 @@ ex_function(exarg_T *eap) *p = NUL; if (!eap->skip && !got_int) { - fp = find_func(name, NULL); + fp = find_func(name, is_global, NULL); if (fp == NULL && ASCII_ISUPPER(*eap->arg)) { char_u *up = untrans_function_name(name); @@ -2511,7 +2554,7 @@ ex_function(exarg_T *eap) // With Vim9 script the name was made script-local, if not // found try again with the original name. if (up != NULL) - fp = find_func(up, NULL); + fp = find_func(up, FALSE, NULL); } if (fp != NULL) @@ -2675,7 +2718,7 @@ ex_function(exarg_T *eap) { if (fudi.fd_dict != NULL && fudi.fd_newkey == NULL) emsg(_(e_funcdict)); - else if (name != NULL && find_func(name, NULL) != NULL) + else if (name != NULL && find_func(name, is_global, NULL) != NULL) emsg_funcname(e_funcexts, name); } @@ -2825,7 +2868,7 @@ ex_function(exarg_T *eap) if (*p == '!') p = skipwhite(p + 1); p += eval_fname_script(p); - vim_free(trans_function_name(&p, TRUE, 0, NULL, NULL)); + vim_free(trans_function_name(&p, NULL, TRUE, 0, NULL, NULL)); if (*skipwhite(p) == '(') { if (nesting == MAX_FUNC_NESTING - 1) @@ -2963,7 +3006,7 @@ ex_function(exarg_T *eap) goto erret; } - fp = find_func_even_dead(name, NULL); + fp = find_func_even_dead(name, is_global, NULL); if (fp != NULL) { int dead = fp->uf_flags & FC_DEAD; @@ -3208,6 +3251,8 @@ ex_function(exarg_T *eap) fp->uf_varargs = varargs; if (sandbox) flags |= FC_SANDBOX; + if (in_vim9script() && !ASCII_ISUPPER(*fp->uf_name)) + flags |= FC_VIM9; fp->uf_flags = flags; fp->uf_calls = 0; fp->uf_cleared = FALSE; @@ -3261,11 +3306,11 @@ eval_fname_script(char_u *p) } int -translated_function_exists(char_u *name) +translated_function_exists(char_u *name, int is_global) { if (builtin_function(name, -1)) return has_internal_func(name); - return find_func(name, NULL) != NULL; + return find_func(name, is_global, NULL) != NULL; } /* @@ -3289,17 +3334,18 @@ function_exists(char_u *name, int no_deref) char_u *p; int n = FALSE; int flag; + int is_global = FALSE; flag = TFN_INT | TFN_QUIET | TFN_NO_AUTOLOAD; if (no_deref) flag |= TFN_NO_DEREF; - p = trans_function_name(&nm, FALSE, flag, NULL, NULL); + p = trans_function_name(&nm, &is_global, FALSE, flag, NULL, NULL); nm = skipwhite(nm); // Only accept "funcname", "funcname ", "funcname (..." and // "funcname(...", not "funcname!...". if (p != NULL && (*nm == NUL || *nm == '(')) - n = translated_function_exists(p); + n = translated_function_exists(p, is_global); vim_free(p); return n; } @@ -3310,12 +3356,14 @@ get_expanded_name(char_u *name, int check) { char_u *nm = name; char_u *p; + int is_global = FALSE; - p = trans_function_name(&nm, FALSE, TFN_INT|TFN_QUIET, NULL, NULL); + p = trans_function_name(&nm, &is_global, FALSE, + TFN_INT|TFN_QUIET, NULL, NULL); - if (p != NULL && *nm == NUL) - if (!check || translated_function_exists(p)) - return p; + if (p != NULL && *nm == NUL + && (!check || translated_function_exists(p, is_global))) + return p; vim_free(p); return NULL; @@ -3376,9 +3424,10 @@ ex_delfunction(exarg_T *eap) char_u *p; char_u *name; funcdict_T fudi; + int is_global = FALSE; p = eap->arg; - name = trans_function_name(&p, eap->skip, 0, &fudi, NULL); + name = trans_function_name(&p, &is_global, eap->skip, 0, &fudi, NULL); vim_free(fudi.fd_newkey); if (name == NULL) { @@ -3397,7 +3446,7 @@ ex_delfunction(exarg_T *eap) *p = NUL; if (!eap->skip) - fp = find_func(name, NULL); + fp = find_func(name, is_global, NULL); vim_free(name); if (!eap->skip) @@ -3413,6 +3462,11 @@ ex_delfunction(exarg_T *eap) semsg(_("E131: Cannot delete function %s: It is in use"), eap->arg); return; } + if (fp->uf_flags & FC_VIM9) + { + semsg(_("E1084: Cannot delete Vim9 script function %s"), eap->arg); + return; + } if (fudi.fd_dict != NULL) { @@ -3452,7 +3506,7 @@ func_unref(char_u *name) if (name == NULL || !func_name_refcount(name)) return; - fp = find_func(name, NULL); + fp = find_func(name, FALSE, NULL); if (fp == NULL && isdigit(*name)) { #ifdef EXITFREE @@ -3495,7 +3549,7 @@ func_ref(char_u *name) if (name == NULL || !func_name_refcount(name)) return; - fp = find_func(name, NULL); + fp = find_func(name, FALSE, NULL); if (fp != NULL) ++fp->uf_refcount; else if (isdigit(*name)) @@ -3611,7 +3665,8 @@ ex_call(exarg_T *eap) return; } - tofree = trans_function_name(&arg, eap->skip, TFN_INT, &fudi, &partial); + tofree = trans_function_name(&arg, NULL, eap->skip, + TFN_INT, &fudi, &partial); if (fudi.fd_newkey != NULL) { // Still need to give an error message for missing key. @@ -3969,7 +4024,7 @@ make_partial(dict_T *selfdict_in, typval_T *rettv) : rettv->vval.v_partial->pt_name; // Translate "s:func" to the stored function name. fname = fname_trans_sid(fname, fname_buf, &tofree, &error); - fp = find_func(fname, NULL); + fp = find_func(fname, FALSE, NULL); vim_free(tofree); } @@ -4391,7 +4446,7 @@ set_ref_in_func(char_u *name, ufunc_T *fp_in, int copyID) if (fp_in == NULL) { fname = fname_trans_sid(name, fname_buf, &tofree, &error); - fp = find_func(fname, NULL); + fp = find_func(fname, FALSE, NULL); } if (fp != NULL) { diff --git a/src/version.c b/src/version.c index fa91a2bc04..d58ef8ac05 100644 --- a/src/version.c +++ b/src/version.c @@ -746,6 +746,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 650, /**/ 649, /**/ diff --git a/src/vim9compile.c b/src/vim9compile.c index 0e9abac0e4..89a86779a6 100644 --- a/src/vim9compile.c +++ b/src/vim9compile.c @@ -2210,7 +2210,7 @@ compile_load_scriptvar( static int generate_funcref(cctx_T *cctx, char_u *name) { - ufunc_T *ufunc = find_func(name, cctx); + ufunc_T *ufunc = find_func(name, FALSE, cctx); if (ufunc == NULL) return FAIL; @@ -2452,7 +2452,7 @@ compile_call(char_u **arg, size_t varlen, cctx_T *cctx, int argcount_init) } // If we can find the function by name generate the right call. - ufunc = find_func(name, cctx); + ufunc = find_func(name, FALSE, cctx); if (ufunc != NULL) { res = generate_CALL(cctx, ufunc, argcount); diff --git a/src/vim9execute.c b/src/vim9execute.c index 9ea7dafad3..5251d48486 100644 --- a/src/vim9execute.c +++ b/src/vim9execute.c @@ -400,7 +400,7 @@ call_by_name(char_u *name, int argcount, ectx_T *ectx, isn_T *iptr) return call_bfunc(func_idx, argcount, ectx); } - ufunc = find_func(name, NULL); + ufunc = find_func(name, FALSE, NULL); if (ufunc != NULL) return call_ufunc(ufunc, argcount, ectx, iptr); @@ -1944,8 +1944,9 @@ ex_disassemble(exarg_T *eap) int current; int line_idx = 0; int prev_current = 0; + int is_global = FALSE; - fname = trans_function_name(&arg, FALSE, + fname = trans_function_name(&arg, &is_global, FALSE, TFN_INT | TFN_QUIET | TFN_NO_AUTOLOAD | TFN_NO_DEREF, NULL, NULL); if (fname == NULL) { @@ -1953,14 +1954,14 @@ ex_disassemble(exarg_T *eap) return; } - ufunc = find_func(fname, NULL); + ufunc = find_func(fname, is_global, NULL); if (ufunc == NULL) { char_u *p = untrans_function_name(fname); if (p != NULL) // Try again without making it script-local. - ufunc = find_func(p, NULL); + ufunc = find_func(p, FALSE, NULL); } vim_free(fname); if (ufunc == NULL) diff --git a/src/vim9script.c b/src/vim9script.c index e74a7b9cbb..afd6a4af97 100644 --- a/src/vim9script.c +++ b/src/vim9script.c @@ -217,7 +217,7 @@ find_exported( funcname[1] = KS_EXTRA; funcname[2] = (int)KE_SNR; sprintf((char *)funcname + 3, "%ld_%s", (long)sid, name); - *ufunc = find_func(funcname, NULL); + *ufunc = find_func(funcname, FALSE, NULL); if (funcname != buffer) vim_free(funcname); From 57700ee4acee9b7c7f165360f09c07ec9376d989 Mon Sep 17 00:00:00 2001 From: Bram Moolenaar Date: Mon, 27 Apr 2020 22:51:33 +0200 Subject: [PATCH 045/230] patch 8.2.0651: old style benchmark test still in list of distributed files Problem: Old style benchmark test still in list of distributed files. Solution: Remove the files from the list. --- Filelist | 2 -- src/version.c | 2 ++ 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Filelist b/Filelist index ff5994ba0a..46f6774e76 100644 --- a/Filelist +++ b/Filelist @@ -183,8 +183,6 @@ SRC_ALL = \ src/testdir/python_after/*.py \ src/testdir/python_before/*.py \ src/testdir/pyxfile/*.py \ - src/testdir/bench*.in \ - src/testdir/bench*.vim \ src/testdir/dumps/*.dump \ src/testdir/samples/*.txt \ src/testdir/samples/test000 \ diff --git a/src/version.c b/src/version.c index d58ef8ac05..6542b37aff 100644 --- a/src/version.c +++ b/src/version.c @@ -746,6 +746,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 651, /**/ 650, /**/ From 909ed7e902d97054262fb55b28f5e855428ab7fe Mon Sep 17 00:00:00 2001 From: Bram Moolenaar Date: Mon, 27 Apr 2020 23:16:41 +0200 Subject: [PATCH 046/230] patch 8.2.0652: compiler warning for char conversion Problem: Compiler warning for char conversion. Solution: Use unsigned char buffer. --- src/userfunc.c | 4 ++-- src/version.c | 2 ++ 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/src/userfunc.c b/src/userfunc.c index 993697e46d..86dea795cf 100644 --- a/src/userfunc.c +++ b/src/userfunc.c @@ -1586,13 +1586,13 @@ delete_script_functions(int sid) hashitem_T *hi; ufunc_T *fp; long_u todo; - char buf[30]; + char_u buf[30]; size_t len; buf[0] = K_SPECIAL; buf[1] = KS_EXTRA; buf[2] = (int)KE_SNR; - sprintf(buf + 3, "%d_", sid); + sprintf((char *)buf + 3, "%d_", sid); len = STRLEN(buf); todo = func_hashtab.ht_used; diff --git a/src/version.c b/src/version.c index 6542b37aff..f9951e9366 100644 --- a/src/version.c +++ b/src/version.c @@ -746,6 +746,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 652, /**/ 651, /**/ From 03afdcf1f449d23c9b6bc56d8b61f31dd4e11836 Mon Sep 17 00:00:00 2001 From: Bram Moolenaar Date: Mon, 27 Apr 2020 23:39:30 +0200 Subject: [PATCH 047/230] patch 8.2.0653: using uninitialized pointer Problem: using uninitialized pointer. Solution: Move assignment up. (John Marriott) --- src/testdir/test_vim9_script.vim | 34 +++++++++++++++----------------- src/userfunc.c | 2 +- src/version.c | 2 ++ 3 files changed, 19 insertions(+), 19 deletions(-) diff --git a/src/testdir/test_vim9_script.vim b/src/testdir/test_vim9_script.vim index 0ab170ef12..4c821ec513 100644 --- a/src/testdir/test_vim9_script.vim +++ b/src/testdir/test_vim9_script.vim @@ -707,8 +707,7 @@ def Test_vim9script_reload_import() return valtwo enddef END - writefile(lines + morelines, - 'Xreload.vim') + writefile(lines + morelines, 'Xreload.vim') source Xreload.vim source Xreload.vim source Xreload.vim @@ -724,10 +723,9 @@ def Test_vim9script_reload_import() writefile(testlines, 'Ximport.vim') source Ximport.vim - " test that when not using "morelines" valtwo is still defined - " need to source Xreload.vim again, import doesn't reload a script + " Test that when not using "morelines" GetValtwo() and valtwo are still + " defined, because import doesn't reload a script. writefile(lines, 'Xreload.vim') - source Xreload.vim source Ximport.vim " cannot declare a var twice @@ -750,36 +748,36 @@ def Test_vim9script_reload_delfunc() return 'yes' enddef END - let middle_lines =<< trim END + let withno_lines =<< trim END def FuncNo(): string return 'no' enddef - END - let final_lines =<< trim END def g:DoCheck(no_exists: bool) assert_equal('yes', FuncYes()) - if no_exists - assert_equal('no', FuncNo()) - else - assert_fails('call FuncNo()', 'E117:') - endif + assert_equal('no', FuncNo()) + enddef + END + let nono_lines =<< trim END + def g:DoCheck(no_exists: bool) + assert_equal('yes', FuncYes()) + assert_fails('call FuncNo()', 'E117:') enddef END # FuncNo() is defined - writefile(first_lines + middle_lines + final_lines, 'Xreloaded.vim') + writefile(first_lines + withno_lines, 'Xreloaded.vim') source Xreloaded.vim g:DoCheck(true) # FuncNo() is not redefined - writefile(first_lines + final_lines, 'Xreloaded.vim') + writefile(first_lines + nono_lines, 'Xreloaded.vim') source Xreloaded.vim - g:DoCheck(false) + g:DoCheck() # FuncNo() is back - writefile(first_lines + middle_lines + final_lines, 'Xreloaded.vim') + writefile(first_lines + withno_lines, 'Xreloaded.vim') source Xreloaded.vim - g:DoCheck(true) + g:DoCheck() delete('Xreloaded.vim') enddef diff --git a/src/userfunc.c b/src/userfunc.c index 86dea795cf..708b4523b3 100644 --- a/src/userfunc.c +++ b/src/userfunc.c @@ -1599,9 +1599,9 @@ delete_script_functions(int sid) for (hi = func_hashtab.ht_array; todo > 0; ++hi) if (!HASHITEM_EMPTY(hi)) { + fp = HI2UF(hi); if (STRNCMP(fp->uf_name, buf, len) == 0) { - fp = HI2UF(hi); fp->uf_flags |= FC_DEAD; func_clear(fp, TRUE); } diff --git a/src/version.c b/src/version.c index f9951e9366..9bee5136b1 100644 --- a/src/version.c +++ b/src/version.c @@ -746,6 +746,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 653, /**/ 652, /**/ From a14bb7e1132377af60910402f1a9e4796297f5df Mon Sep 17 00:00:00 2001 From: Bram Moolenaar Date: Tue, 28 Apr 2020 00:02:41 +0200 Subject: [PATCH 048/230] patch 8.2.0654: building with Python fails Problem: Building with Python fails. Solution: Add missing argument. --- src/if_py_both.h | 2 +- src/version.c | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/src/if_py_both.h b/src/if_py_both.h index 5a878bd2bd..d6a5b11a5d 100644 --- a/src/if_py_both.h +++ b/src/if_py_both.h @@ -2934,7 +2934,7 @@ FunctionNew(PyTypeObject *subtype, char_u *name, int argc, typval_T *argv, if (isdigit(*name)) { - if (!translated_function_exists(name)) + if (!translated_function_exists(name, FALSE)) { PyErr_FORMAT(PyExc_ValueError, N_("unnamed function %s does not exist"), name); diff --git a/src/version.c b/src/version.c index 9bee5136b1..b99f9bedda 100644 --- a/src/version.c +++ b/src/version.c @@ -746,6 +746,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 654, /**/ 653, /**/ From 224a5f17c6ec9e98322a4c6792ce4f9bb31a4cce Mon Sep 17 00:00:00 2001 From: Bram Moolenaar Date: Tue, 28 Apr 2020 20:29:07 +0200 Subject: [PATCH 049/230] patch 8.2.0655: search code not sufficiently tested Problem: Search code not sufficiently tested. Solution: Add more tests. (Yegappan Lakshmanan, closes #5999) --- src/testdir/test_charsearch.vim | 23 +++ src/testdir/test_gn.vim | 18 ++- src/testdir/test_goto.vim | 59 +++++-- src/testdir/test_ins_complete.vim | 20 +++ src/testdir/test_normal.vim | 139 +++++++---------- src/testdir/test_search.vim | 93 +++++++++++ src/testdir/test_textformat.vim | 26 +++- src/testdir/test_textobjects.vim | 251 ++++++++++++++++++++++++++++++ src/testdir/test_visual.vim | 23 +++ src/version.c | 2 + 10 files changed, 551 insertions(+), 103 deletions(-) diff --git a/src/testdir/test_charsearch.vim b/src/testdir/test_charsearch.vim index e6301a5c05..0a20eafe0b 100644 --- a/src/testdir/test_charsearch.vim +++ b/src/testdir/test_charsearch.vim @@ -30,6 +30,15 @@ func Test_charsearch() normal! ;;p call assert_equal('ZabcdeZfghijkZZemnokqretkZvwxyz', getline(3)) + " check that repeating a search before and after a line fails + normal 3Gfv + call assert_beeps('normal ;') + call assert_beeps('normal ,') + + " clear the character search + call setcharsearch({'char' : ''}) + call assert_equal('', getcharsearch().char) + call assert_fails("call setcharsearch([])", 'E715:') enew! endfunc @@ -75,4 +84,18 @@ func Test_csearch_virtualedit() close! endfunc +" Test for character search failure in latin1 encoding +func Test_charsearch_latin1() + new + let save_enc = &encoding + set encoding=latin1 + call setline(1, 'abcdefghijk') + call assert_beeps('normal fz') + call assert_beeps('normal tx') + call assert_beeps('normal $Fz') + call assert_beeps('normal $Tx') + let &encoding = save_enc + close! +endfunc + " vim: shiftwidth=2 sts=2 expandtab diff --git a/src/testdir/test_gn.vim b/src/testdir/test_gn.vim index 098fc3db4d..c72da925a3 100644 --- a/src/testdir/test_gn.vim +++ b/src/testdir/test_gn.vim @@ -154,8 +154,24 @@ func Test_gn_command() norm! gg0f2vf7gNd call assert_equal(['1678'], getline(1,'$')) sil! %d _ - set wrapscan&vim + + " Without 'wrapscan', in visual mode, running gn without a match should fail + " but the visual mode should be kept. + set nowrapscan + call setline('.', 'one two') + let @/ = 'one' + call assert_beeps('normal 0wvlgn') + exe "normal y" + call assert_equal('tw', @") + + " with exclusive selection, run gn and gN + set selection=exclusive + normal 0gny + call assert_equal('one', @") + normal 0wgNy + call assert_equal('one', @") + set selection& endfu func Test_gn_multi_line() diff --git a/src/testdir/test_goto.vim b/src/testdir/test_goto.vim index 1248de3f01..aeca0b4361 100644 --- a/src/testdir/test_goto.vim +++ b/src/testdir/test_goto.vim @@ -333,21 +333,24 @@ endfunc func Test_motion_if_elif_else_endif() new - a -/* Test pressing % on #if, #else #elsif and #endif, - * with nested #if - */ -#if FOO -/* ... */ -# if BAR -/* ... */ -# endif -#elif BAR -/* ... */ -#else -/* ... */ -#endif -. + let lines =<< trim END + /* Test pressing % on #if, #else #elsif and #endif, + * with nested #if + */ + #if FOO + /* ... */ + # if BAR + /* ... */ + # endif + #elif BAR + /* ... */ + #else + /* ... */ + #endif + + #define FOO 1 + END + call setline(1, lines) /#if FOO norm % call assert_equal([9, 1], getpos('.')[1:2]) @@ -363,6 +366,30 @@ func Test_motion_if_elif_else_endif() norm $% call assert_equal([6, 1], getpos('.')[1:2]) + " Test for [# and ]# command + call cursor(5, 1) + normal [# + call assert_equal([4, 1], getpos('.')[1:2]) + call cursor(5, 1) + normal ]# + call assert_equal([9, 1], getpos('.')[1:2]) + call cursor(10, 1) + normal [# + call assert_equal([9, 1], getpos('.')[1:2]) + call cursor(10, 1) + normal ]# + call assert_equal([11, 1], getpos('.')[1:2]) + + " Finding a match before the first line or after the last line should fail + normal gg + call assert_beeps('normal [#') + normal G + call assert_beeps('normal ]#') + + " Finding a match for a macro definition (#define) should fail + normal G + call assert_beeps('normal %') + bw! endfunc @@ -392,3 +419,5 @@ func Test_motion_c_comment() bw! endfunc + +" vim: shiftwidth=2 sts=2 expandtab diff --git a/src/testdir/test_ins_complete.vim b/src/testdir/test_ins_complete.vim index 7ae263909c..cec4acf3f2 100644 --- a/src/testdir/test_ins_complete.vim +++ b/src/testdir/test_ins_complete.vim @@ -515,4 +515,24 @@ func Test_complete_func_error() call assert_fails('call complete_info({})', 'E714:') endfunc +" Test for completing words following a completed word in a line +func Test_complete_wrapscan() + " complete words from another buffer + new + call setline(1, ['one two', 'three four']) + new + setlocal complete=w + call feedkeys("itw\\\\\\\", 'xt') + call assert_equal('two three four', getline(1)) + close! + " complete words from the current buffer + setlocal complete=. + %d + call setline(1, ['one two', '']) + call cursor(2, 1) + call feedkeys("ion\\\\\\\", 'xt') + call assert_equal('one two one two', getline(2)) + close! +endfunc + " vim: shiftwidth=2 sts=2 expandtab diff --git a/src/testdir/test_normal.vim b/src/testdir/test_normal.vim index 08c0e07713..e75cb7183b 100644 --- a/src/testdir/test_normal.vim +++ b/src/testdir/test_normal.vim @@ -1451,11 +1451,27 @@ func Test_normal28_parenthesis() norm! $d( call assert_equal(['With some sentences!', '', ' ', '', 'This is a long sentence', ''], getline(1, '$')) + " Move to the next sentence from a paragraph macro + %d + call setline(1, ['.LP', 'blue sky!. blue sky.', 'blue sky. blue sky.']) + call cursor(1, 1) + normal ) + call assert_equal([2, 1], [line('.'), col('.')]) + normal ) + call assert_equal([2, 12], [line('.'), col('.')]) + normal (( + call assert_equal([1, 1], [line('.'), col('.')]) + " It is an error if a next sentence is not found %d call setline(1, '.SH') call assert_beeps('normal )') + " If only dot is present, don't treat that as a sentence + call setline(1, '. This is a sentence.') + normal $(( + call assert_equal(3, col('.')) + " Jumping to a fold should open the fold call setline(1, ['', '', 'one', 'two', 'three']) set foldenable @@ -2334,92 +2350,6 @@ func Test_normal42_halfpage() bw! endfunc -" Tests for text object aw -func Test_normal43_textobject1() - new - call append(0, ['foobar,eins,foobar', 'foo,zwei,foo ']) - " diw - norm! 1gg0diw - call assert_equal([',eins,foobar', 'foo,zwei,foo ', ''], getline(1,'$')) - " daw - norm! 2ggEdaw - call assert_equal([',eins,foobar', 'foo,zwei,', ''], getline(1, '$')) - %d - call append(0, ["foo\teins\tfoobar", "foo\tzwei\tfoo "]) - " diW - norm! 2ggwd2iW - call assert_equal(['foo eins foobar', 'foo foo ', ''], getline(1,'$')) - " daW - norm! 1ggd2aW - call assert_equal(['foobar', 'foo foo ', ''], getline(1,'$')) - - %d - call append(0, ["foo\teins\tfoobar", "foo\tzwei\tfoo "]) - " aw in visual line mode switches to characterwise mode - norm! 2gg$Vawd - call assert_equal(['foo eins foobar', 'foo zwei foo'], getline(1,'$')) - norm! 1gg$Viwd - call assert_equal(['foo eins ', 'foo zwei foo'], getline(1,'$')) - - " clean up - bw! -endfunc - -" Test for is and as text objects -func Test_normal44_textobjects2() - new - call append(0, ['This is a test. With some sentences!', '', 'Even with a question? And one more. And no sentence here']) - " Test for dis - does not remove trailing whitespace - norm! 1gg0dis - call assert_equal([' With some sentences!', '', 'Even with a question? And one more. And no sentence here', ''], getline(1,'$')) - " Test for das - removes leading whitespace - norm! 3ggf?ldas - call assert_equal([' With some sentences!', '', 'Even with a question? And no sentence here', ''], getline(1,'$')) - " when used in visual mode, is made characterwise - norm! 3gg$Visy - call assert_equal('v', visualmode()) - " reset visualmode() - norm! 3ggVy - norm! 3gg$Vasy - call assert_equal('v', visualmode()) - " basic testing for textobjects a< and at - %d - call setline(1, ['', ' ']) - " a< - norm! 1gg0da< - call assert_equal([' ', 'xyz', ' ', ' '], getline(1,'$')) - norm! 1pj - call assert_equal(['
', 'xyz', '
', ' '], getline(1,'$')) - " at - norm! d2at - call assert_equal([' '], getline(1,'$')) - %d - call setline(1, ['
','xyz','
', ' ']) - " i< - norm! 1gg0di< - call assert_equal(['<> ', 'xyz', ' ', ' '], getline(1,'$')) - norm! 1Pj - call assert_equal(['
', 'xyz', '
', ' '], getline(1,'$')) - norm! d2it - call assert_equal(['
',' '], getline(1,'$')) - " basic testing for a[ and i[ text object - %d - call setline(1, [' ', '[', 'one [two]', 'thre', ']']) - norm! 3gg0di[ - call assert_equal([' ', '[', ']'], getline(1,'$')) - call setline(1, [' ', '[', 'one [two]', 'thre', ']']) - norm! 3gg0ftd2a[ - call assert_equal([' '], getline(1,'$')) - %d - " Test for i" when cursor is in front of a quoted object - call append(0, 'foo "bar"') - norm! 1gg0di" - call assert_equal(['foo ""', ''], getline(1,'$')) - - " clean up - bw! -endfunc - func Test_normal45_drop() if !has('dnd') " The ~ register does not exist @@ -3065,4 +2995,41 @@ func Test_empty_region_error() close! endfunc +" Test for 'w' and 'b' commands +func Test_normal_word_move() + new + call setline(1, ['foo bar a', '', 'foo bar b']) + " copy a single character word at the end of a line + normal 1G$yw + call assert_equal('a', @") + " copy a single character word at the end of a file + normal G$yw + call assert_equal('b', @") + " check for a word movement handling an empty line properly + normal 1G$vwy + call assert_equal("a\n\n", @") + + " copy using 'b' command + %d + " non-empty blank line at the start of file + call setline(1, [' ', 'foo bar']) + normal 2Gyb + call assert_equal(" \n", @") + " try to copy backwards from the start of the file + call setline(1, ['one two', 'foo bar']) + call assert_beeps('normal ggyb') + " 'b' command should stop at an empty line + call setline(1, ['one two', '', 'foo bar']) + normal 3Gyb + call assert_equal("\n", @") + normal 3Gy2b + call assert_equal("two\n", @") + " 'b' command should not stop at a non-empty blank line + call setline(1, ['one two', ' ', 'foo bar']) + normal 3Gyb + call assert_equal("two\n ", @") + + close! +endfunc + " vim: shiftwidth=2 sts=2 expandtab diff --git a/src/testdir/test_search.vim b/src/testdir/test_search.vim index 7aaf8db52d..a3b67055ce 100644 --- a/src/testdir/test_search.vim +++ b/src/testdir/test_search.vim @@ -1638,6 +1638,12 @@ func Test_search_smartcase() exe "normal /\\a\\_.\\(.*\\)o\" call assert_equal([2, 1], [line('.'), col('.')]) + " Test for using special atoms with 'smartcase' + call setline(1, ['', ' Hello\ ']) + call cursor(1, 1) + call feedkeys('/\_.\%(\uello\)\' .. "\", 'xt') + call assert_equal([2, 4], [line('.'), col('.')]) + set ignorecase& smartcase& close! endfunc @@ -1651,4 +1657,91 @@ func Test_search_past_eof() close! endfunc +" Test for various search offsets +func Test_search_offset() + " With /e, for a match in the first column of a line, the cursor should be + " placed at the end of the previous line. + new + call setline(1, ['one two', 'three four']) + call search('two\_.', 'e') + call assert_equal([1, 7], [line('.'), col('.')]) + + " with cursor at the beginning of the file, use /s+1 + call cursor(1, 1) + exe "normal /two/s+1\" + call assert_equal([1, 6], [line('.'), col('.')]) + + " with cursor at the end of the file, use /e-1 + call cursor(2, 10) + exe "normal ?three?e-1\" + call assert_equal([2, 4], [line('.'), col('.')]) + + " line offset - after the last line + call cursor(1, 1) + exe "normal /three/+1\" + call assert_equal([2, 1], [line('.'), col('.')]) + + " line offset - before the first line + call cursor(2, 1) + exe "normal ?one?-1\" + call assert_equal([1, 1], [line('.'), col('.')]) + + " character offset - before the first character in the file + call cursor(2, 1) + exe "normal ?one?s-1\" + call assert_equal([1, 1], [line('.'), col('.')]) + call cursor(2, 1) + exe "normal ?one?e-3\" + call assert_equal([1, 1], [line('.'), col('.')]) + + " character offset - after the last character in the file + call cursor(1, 1) + exe "normal /four/s+4\" + call assert_equal([2, 10], [line('.'), col('.')]) + call cursor(1, 1) + exe "normal /four/e+1\" + call assert_equal([2, 10], [line('.'), col('.')]) + + close! +endfunc + +" Test for searching for matching parenthesis using % +func Test_search_match_paren() + new + call setline(1, "abc(def')'ghi'('jk'\\t'lm)no") + " searching for a matching parenthesis should skip single quoted characters + call cursor(1, 4) + normal % + call assert_equal([1, 25], [line('.'), col('.')]) + normal % + call assert_equal([1, 4], [line('.'), col('.')]) + call cursor(1, 5) + normal ]) + call assert_equal([1, 25], [line('.'), col('.')]) + call cursor(1, 24) + normal [( + call assert_equal([1, 4], [line('.'), col('.')]) + + " matching parenthesis in 'virtualedit' mode with cursor after the eol + call setline(1, 'abc(defgh)') + set virtualedit=all + normal 20|% + call assert_equal(4, col('.')) + set virtualedit& + close! +endfunc + +" Test for searching a pattern and stopping before a specified line +func Test_search_stopline() + new + call setline(1, ['', '', '', 'vim']) + call assert_equal(0, search('vim', 'n', 3)) + call assert_equal(4, search('vim', 'n', 4)) + call setline(1, ['vim', '', '', '']) + call cursor(4, 1) + call assert_equal(0, search('vim', 'bn', 2)) + call assert_equal(1, search('vim', 'bn', 1)) + close! +endfunc + " vim: shiftwidth=2 sts=2 expandtab diff --git a/src/testdir/test_textformat.vim b/src/testdir/test_textformat.vim index 90c95aeb26..49c1f06d38 100644 --- a/src/testdir/test_textformat.vim +++ b/src/testdir/test_textformat.vim @@ -882,7 +882,7 @@ func Test_tw_2_fo_tm_replace() endfunc " Test for 'matchpairs' with multibyte chars -func Test_mps() +func Test_mps_multibyte() new let t =<< trim END { @@ -906,6 +906,30 @@ func Test_mps() bwipe! endfunc +" Test for 'matchpairs' in latin1 encoding +func Test_mps_latin1() + new + let save_enc = &encoding + set encoding=latin1 + call setline(1, 'abc(def)ghi') + normal % + call assert_equal(8, col('.')) + normal % + call assert_equal(4, col('.')) + call cursor(1, 6) + normal [( + call assert_equal(4, col('.')) + normal % + call assert_equal(8, col('.')) + call cursor(1, 6) + normal ]) + call assert_equal(8, col('.')) + normal % + call assert_equal(4, col('.')) + let &encoding = save_enc + close! +endfunc + " Test for ra on multi-byte characters func Test_ra_multibyte() new diff --git a/src/testdir/test_textobjects.vim b/src/testdir/test_textobjects.vim index 042c534218..eed84e3853 100644 --- a/src/testdir/test_textobjects.vim +++ b/src/testdir/test_textobjects.vim @@ -151,6 +151,24 @@ func Test_string_html_objects() normal! dit call assert_equal('-', getline('.')) + " copy the tag block from leading indentation before the start tag + let t = " \ntext\n" + $put =t + normal! 2kvaty + call assert_equal("\ntext\n", @") + + " copy the tag block from the end tag + let t = "\nwelcome\n" + $put =t + normal! $vaty + call assert_equal("\nwelcome\n", @") + + " copy the outer tag block from a tag without an end tag + let t = "\nwelcome\n</html>" + $put =t + normal! k$vaty + call assert_equal("<html>\n<title>welcome\n</html>", @") + set quoteescape& enew! endfunc @@ -169,6 +187,10 @@ func Test_empty_html_tag() normal 0f<vitsaaa call assert_equal('aaa', getline(1)) + " selecting a tag block in an non-empty blank line should fail + call setline(1, ' ') + call assert_beeps('normal $vaty') + bwipe! endfunc @@ -291,3 +313,232 @@ func Test_sentence_with_cursor_on_delimiter() %delete _ endfunc + +" Test for the paragraph (ap) text object +func Test_paragraph() + new + call setline(1, ['First line.', 'Second line.', 'Third line.']) + call cursor(2, 1) + normal vapy + call assert_equal("First line.\nSecond line.\nThird line.\n", @") + + call cursor(2, 1) + call assert_beeps('normal vapapy') + + call setline(1, ['First line.', 'Second line.', ' ', '']) + call cursor(1, 1) + normal vapy + call assert_equal("First line.\nSecond line.\n \n\n", @") + + call setline(1, ['', '', '', 'First line.', 'Second line.']) + call cursor(2, 1) + normal yap + call assert_equal("\n\n\nFirst line.\nSecond line.\n", @") + call assert_beeps('normal 3yap') + exe "normal \<C-C>" + + %d + call setline(1, [' ', ' ', ' ']) + call cursor(2, 1) + normal Vipy + call assert_equal(" \n \n \n", @") + call cursor(2, 1) + call assert_beeps("normal Vipip") + exe "normal \<C-C>" + + close! +endfunc + +" Tests for text object aw +func Test_textobj_a_word() + new + call append(0, ['foobar,eins,foobar', 'foo,zwei,foo ']) + " diw + norm! 1gg0diw + call assert_equal([',eins,foobar', 'foo,zwei,foo ', ''], getline(1,'$')) + " daw + norm! 2ggEdaw + call assert_equal([',eins,foobar', 'foo,zwei,', ''], getline(1, '$')) + " daw the last word in a line + call setline(1, ['foo bar', 'foo bar', '']) + call cursor(1, 5) + normal daw + call assert_equal('foo', getline(1)) + " aw in visual mode + call cursor(2, 5) + normal! vawx + call assert_equal('foo', getline(2)) + %d + call append(0, ["foo\teins\tfoobar", "foo\tzwei\tfoo "]) + " diW + norm! 2ggwd2iW + call assert_equal(['foo eins foobar', 'foo foo ', ''], getline(1,'$')) + " daW + norm! 1ggd2aW + call assert_equal(['foobar', 'foo foo ', ''], getline(1,'$')) + + %d + call append(0, ["foo\teins\tfoobar", "foo\tzwei\tfoo "]) + " aw in visual line mode switches to characterwise mode + norm! 2gg$Vawd + call assert_equal(['foo eins foobar', 'foo zwei foo'], getline(1,'$')) + norm! 1gg$Viwd + call assert_equal(['foo eins ', 'foo zwei foo'], getline(1,'$')) + + " visually selecting a tab before a word with 'selection' set to 'exclusive' + set selection=exclusive + normal gg3lvlawy + call assert_equal("\teins", @") + " visually selecting a tab before a word with 'selection' set to 'inclusive' + set selection=inclusive + normal gg3lvlawy + call assert_equal("\teins\t", @") + set selection& + + " selecting a word with no non-space characters in a buffer fails + %d + call setline(1, ' ') + call assert_beeps('normal 3lyaw') + + " visually selecting words backwards with no more words to select + call setline(1, 'one two') + call assert_beeps('normal 2lvh2aw') + exe "normal \<C-C>" + call assert_beeps('normal $vh3aw') + exe "normal \<C-C>" + call setline(1, ['', 'one two']) + call assert_beeps('normal 2G2lvh3aw') + exe "normal \<C-C>" + + " selecting words forward with no more words to select + %d + call setline(1, 'one a') + call assert_beeps('normal 0y3aw') + call setline(1, 'one two ') + call assert_beeps('normal 0y3aw') + call assert_beeps('normal 03ly2aw') + + " clean up + bw! +endfunc + +" Test for is and as text objects +func Test_textobj_sentence() + new + call append(0, ['This is a test. With some sentences!', '', + \ 'Even with a question? And one more. And no sentence here']) + " Test for dis - does not remove trailing whitespace + norm! 1gg0dis + call assert_equal([' With some sentences!', '', + \ 'Even with a question? And one more. And no sentence here', ''], + \ getline(1,'$')) + " Test for das - removes leading whitespace + norm! 3ggf?ldas + call assert_equal([' With some sentences!', '', + \ 'Even with a question? And no sentence here', ''], getline(1,'$')) + " when used in visual mode, is made characterwise + norm! 3gg$Visy + call assert_equal('v', visualmode()) + " reset visualmode() + norm! 3ggVy + norm! 3gg$Vasy + call assert_equal('v', visualmode()) + " basic testing for textobjects a< and at + %d + call setline(1, ['<div> ','<a href="foobar" class="foo">xyz</a>',' </div>', ' ']) + " a< + norm! 1gg0da< + call assert_equal([' ', '<a href="foobar" class="foo">xyz</a>', ' </div>', ' '], getline(1,'$')) + norm! 1pj + call assert_equal([' <div>', '<a href="foobar" class="foo">xyz</a>', ' </div>', ' '], getline(1,'$')) + " at + norm! d2at + call assert_equal([' '], getline(1,'$')) + %d + call setline(1, ['<div> ','<a href="foobar" class="foo">xyz</a>',' </div>', ' ']) + " i< + norm! 1gg0di< + call assert_equal(['<> ', '<a href="foobar" class="foo">xyz</a>', ' </div>', ' '], getline(1,'$')) + norm! 1Pj + call assert_equal(['<div> ', '<a href="foobar" class="foo">xyz</a>', ' </div>', ' '], getline(1,'$')) + norm! d2it + call assert_equal(['<div></div>',' '], getline(1,'$')) + " basic testing for a[ and i[ text object + %d + call setline(1, [' ', '[', 'one [two]', 'thre', ']']) + norm! 3gg0di[ + call assert_equal([' ', '[', ']'], getline(1,'$')) + call setline(1, [' ', '[', 'one [two]', 'thre', ']']) + norm! 3gg0ftd2a[ + call assert_equal([' '], getline(1,'$')) + + " clean up + bw! +endfunc + +" Test for quote (', " and `) textobjects +func Test_textobj_quote() + new + + " Test for i" when cursor is in front of a quoted object + call append(0, 'foo "bar"') + norm! 1gg0di" + call assert_equal(['foo ""', ''], getline(1,'$')) + + " Test for visually selecting an inner quote + %d + " extend visual selection from one quote to the next + call setline(1, 'color "red" color "blue"') + call cursor(1, 7) + normal v4li"y + call assert_equal('"red" color "blue', @") + + " try to extend visual selection from one quote to a non-existing quote + call setline(1, 'color "red" color blue') + call cursor(1, 7) + call feedkeys('v4li"y', 'xt') + call assert_equal('"red"', @") + + " try to extend visual selection from one quote to a next partial quote + call setline(1, 'color "red" color "blue') + call cursor(1, 7) + normal v4li"y + call assert_equal('"red" color ', @") + + " select a quote backwards in visual mode + call cursor(1, 12) + normal vhi"y + call assert_equal('red" ', @") + call assert_equal(8, col('.')) + + " select a quote backwards in visual mode from outside the quote + call cursor(1, 17) + normal v2hi"y + call assert_equal('red', @") + call assert_equal(8, col('.')) + + " visually selecting a quote with 'selection' set to 'exclusive' + call setline(1, 'He said "How are you?"') + set selection=exclusive + normal 012lv2li"y + call assert_equal('How are you?', @") + set selection& + + " try copy a quote object with a single quote in the line + call setline(1, "Smith's car") + call cursor(1, 6) + call assert_beeps("normal yi'") + call assert_beeps("normal 2lyi'") + + " selecting space before and after a quoted string + call setline(1, "some 'special' string") + normal 0ya' + call assert_equal("'special' ", @") + call setline(1, "some 'special'string") + normal 0ya' + call assert_equal(" 'special'", @") + + close! +endfunc + +" vim: shiftwidth=2 sts=2 expandtab diff --git a/src/testdir/test_visual.vim b/src/testdir/test_visual.vim index 143b140bae..87cf2a7ade 100644 --- a/src/testdir/test_visual.vim +++ b/src/testdir/test_visual.vim @@ -890,4 +890,27 @@ func Test_AAA_start_visual_mode_with_count() close! endfunc +" Test for visually selecting an inner block (iB) +func Test_visual_inner_block() + new + call setline(1, ['one', '{', 'two', '{', 'three', '}', 'four', '}', 'five']) + call cursor(5, 1) + " visually select all the lines in the block and then execute iB + call feedkeys("ViB\<C-C>", 'xt') + call assert_equal([0, 5, 1, 0], getpos("'<")) + call assert_equal([0, 5, 6, 0], getpos("'>")) + " visually select two inner blocks + call feedkeys("ViBiB\<C-C>", 'xt') + call assert_equal([0, 3, 1, 0], getpos("'<")) + call assert_equal([0, 7, 5, 0], getpos("'>")) + " try to select non-existing inner block + call cursor(5, 1) + call assert_beeps('normal ViBiBiB') + " try to select a unclosed inner block + 8,9d + call cursor(5, 1) + call assert_beeps('normal ViBiB') + close! +endfunc + " vim: shiftwidth=2 sts=2 expandtab diff --git a/src/version.c b/src/version.c index b99f9bedda..8e08363333 100644 --- a/src/version.c +++ b/src/version.c @@ -746,6 +746,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 655, /**/ 654, /**/ From 7ed8f59ae09278c666f1b43488351f9450097372 Mon Sep 17 00:00:00 2001 From: Bram Moolenaar <Bram@vim.org> Date: Tue, 28 Apr 2020 20:44:42 +0200 Subject: [PATCH 050/230] patch 8.2.0656: MS-Windows: redrawing right screen edge may not be needed Problem: MS-Windows: redrawing right screen edge may not be needed. Solution: Check the build version. (Nobuhiro Takasaki, closes #6002) --- src/drawscreen.c | 3 ++- src/os_win32.c | 16 ++++++++++++++++ src/proto/os_win32.pro | 1 + src/version.c | 2 ++ 4 files changed, 21 insertions(+), 1 deletion(-) diff --git a/src/drawscreen.c b/src/drawscreen.c index be4d6aa7ca..faecaa44bf 100644 --- a/src/drawscreen.c +++ b/src/drawscreen.c @@ -2439,7 +2439,8 @@ win_update(win_T *wp) #ifdef FEAT_VTP // Rewrite the character at the end of the screen line. - if (use_vtp()) + // See the version that was fixed. + if (use_vtp() && get_conpty_fix_type() < 1) { int i; diff --git a/src/os_win32.c b/src/os_win32.c index 85efc52663..e4d8135ca3 100644 --- a/src/os_win32.c +++ b/src/os_win32.c @@ -188,6 +188,7 @@ static int win32_set_archive(char_u *name); static int conpty_working = 0; static int conpty_type = 0; static int conpty_stable = 0; +static int conpty_fix_type = 0; static void vtp_flag_init(); #if !defined(FEAT_GUI_MSWIN) || defined(VIMDLL) @@ -7288,6 +7289,12 @@ mch_setenv(char *var, char *value, int x UNUSED) */ #define CONPTY_1909_BUILD MAKE_VER(10, 0, 18363) +/* + * Stay ahead of the next update, and when it's done, fix this. + * version ? (2020 update, temporarily use the build number of insider preview) + */ +#define CONPTY_NEXT_UPDATE_BUILD MAKE_VER(10, 0, 19587) + /* * Confirm until this version. Also the logic changes. * insider preview. @@ -7334,6 +7341,9 @@ vtp_flag_init(void) conpty_type = 2; if (ver < CONPTY_FIRST_SUPPORT_BUILD) conpty_type = 1; + + if (ver >= CONPTY_NEXT_UPDATE_BUILD) + conpty_fix_type = 1; } #if !defined(FEAT_GUI_MSWIN) || defined(VIMDLL) || defined(PROTO) @@ -7622,6 +7632,12 @@ is_conpty_stable(void) return conpty_stable; } + int +get_conpty_fix_type(void) +{ + return conpty_fix_type; +} + #if !defined(FEAT_GUI_MSWIN) || defined(VIMDLL) || defined(PROTO) void resize_console_buf(void) diff --git a/src/proto/os_win32.pro b/src/proto/os_win32.pro index e60ce92ca1..15c1323157 100644 --- a/src/proto/os_win32.pro +++ b/src/proto/os_win32.pro @@ -79,5 +79,6 @@ int has_vtp_working(void); int has_conpty_working(void); int get_conpty_type(void); int is_conpty_stable(void); +int get_conpty_fix_type(void); void resize_console_buf(void); /* vim: set ft=c : */ diff --git a/src/version.c b/src/version.c index 8e08363333..ebe266eda9 100644 --- a/src/version.c +++ b/src/version.c @@ -746,6 +746,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 656, /**/ 655, /**/ From a0a9f43ab24928a0b01b6d91d084bf50a6dbefc2 Mon Sep 17 00:00:00 2001 From: Bram Moolenaar <Bram@vim.org> Date: Tue, 28 Apr 2020 21:29:34 +0200 Subject: [PATCH 051/230] patch 8.2.0657: Vim9: no check if called variable is a FuncRef Problem: Vim9: no check if called variable is a FuncRef. Solution: Add a type check. --- src/testdir/test_vim9_expr.vim | 6 ++++++ src/testdir/test_vim9_script.vim | 3 +++ src/version.c | 2 ++ src/vim9compile.c | 37 ++++++++++++++++++++++++++------ 4 files changed, 42 insertions(+), 6 deletions(-) diff --git a/src/testdir/test_vim9_expr.vim b/src/testdir/test_vim9_expr.vim index 463227257a..ace3d2f256 100644 --- a/src/testdir/test_vim9_expr.vim +++ b/src/testdir/test_vim9_expr.vim @@ -213,6 +213,12 @@ def Test_expr4_equal() assert_equal(true, function('g:Test_expr4_equal', [123]) == function('g:Test_expr4_equal', [123])) assert_equal(false, function('g:Test_expr4_equal', [123]) == function('g:Test_expr4_is', [123])) assert_equal(false, function('g:Test_expr4_equal', [123]) == function('g:Test_expr4_equal', [999])) + + let OneFunc: func + let TwoFunc: func + OneFunc = function('len') + TwoFunc = function('len') + assert_equal(true, OneFunc('abc') == TwoFunc('123')) enddef " test != comperator diff --git a/src/testdir/test_vim9_script.vim b/src/testdir/test_vim9_script.vim index 4c821ec513..bc1f87377f 100644 --- a/src/testdir/test_vim9_script.vim +++ b/src/testdir/test_vim9_script.vim @@ -345,6 +345,9 @@ func Test_wrong_type() call CheckDefFailure(['let var: pam'], 'E1010:') call CheckDefFailure(['let var: sam'], 'E1010:') call CheckDefFailure(['let var: vim'], 'E1010:') + + call CheckDefFailure(['let Ref: number', 'Ref()'], 'E1085:') + call CheckDefFailure(['let Ref: string', 'let res = Ref()'], 'E1085:') endfunc func Test_const() diff --git a/src/version.c b/src/version.c index ebe266eda9..eac5c9adfa 100644 --- a/src/version.c +++ b/src/version.c @@ -746,6 +746,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 657, /**/ 656, /**/ diff --git a/src/vim9compile.c b/src/vim9compile.c index 89a86779a6..aa3cd07d3d 100644 --- a/src/vim9compile.c +++ b/src/vim9compile.c @@ -1327,15 +1327,32 @@ generate_UCALL(cctx_T *cctx, char_u *name, int argcount) /* * Generate an ISN_PCALL instruction. + * "type" is the type of the FuncRef. */ static int -generate_PCALL(cctx_T *cctx, int argcount, int at_top) +generate_PCALL( + cctx_T *cctx, + int argcount, + char_u *name, + type_T *type, + int at_top) { isn_T *isn; garray_T *stack = &cctx->ctx_type_stack; + type_T *ret_type; RETURN_OK_IF_SKIP(cctx); + if (type->tt_type == VAR_ANY) + ret_type = &t_any; + else if (type->tt_type == VAR_FUNC || type->tt_type == VAR_PARTIAL) + ret_type = type->tt_member; + else + { + semsg(_("E1085: Not a callable type: %s"), name); + return FAIL; + } + if ((isn = generate_instr(cctx, ISN_PCALL)) == NULL) return FAIL; isn->isn_arg.pfunc.cpf_top = at_top; @@ -1344,7 +1361,7 @@ generate_PCALL(cctx_T *cctx, int argcount, int at_top) stack->ga_len -= argcount; // drop the arguments // drop the funcref/partial, get back the return value - ((type_T **)stack->ga_data)[stack->ga_len - 1] = &t_any; + ((type_T **)stack->ga_data)[stack->ga_len - 1] = ret_type; // If partial is above the arguments it must be cleared and replaced with // the return value. @@ -2465,12 +2482,16 @@ compile_call(char_u **arg, size_t varlen, cctx_T *cctx, int argcount_init) if (STRNCMP(namebuf, "g:", 2) != 0 && compile_load(&p, namebuf + varlen, cctx, FALSE) == OK) { - res = generate_PCALL(cctx, argcount, FALSE); + garray_T *stack = &cctx->ctx_type_stack; + type_T *type; + + type = ((type_T **)stack->ga_data)[stack->ga_len - 1]; + res = generate_PCALL(cctx, argcount, namebuf, type, FALSE); goto theend; } // A global function may be defined only later. Need to figure out at - // runtime. + // runtime. Also handles a FuncRef at runtime. if (STRNCMP(namebuf, "g:", 2) == 0) res = generate_UCALL(cctx, name, argcount); else @@ -3120,13 +3141,17 @@ compile_subscript( { if (**arg == '(') { - int argcount = 0; + garray_T *stack = &cctx->ctx_type_stack; + type_T *type; + int argcount = 0; // funcref(arg) + type = ((type_T **)stack->ga_data)[stack->ga_len - 1]; + *arg = skipwhite(*arg + 1); if (compile_arguments(arg, cctx, &argcount) == FAIL) return FAIL; - if (generate_PCALL(cctx, argcount, TRUE) == FAIL) + if (generate_PCALL(cctx, argcount, end_leader, type, TRUE) == FAIL) return FAIL; } else if (**arg == '-' && (*arg)[1] == '>') From affc8fd2cda77fbd47df2594da417a9f9a9bb9b6 Mon Sep 17 00:00:00 2001 From: Bram Moolenaar <Bram@vim.org> Date: Tue, 28 Apr 2020 21:58:29 +0200 Subject: [PATCH 052/230] patch 8.2.0658: HP-UX build fails when setenv() is not defined Problem: HP-UX build fails when setenv() is not defined. Solution: Change "colors" to "t_colors". (John Marriott) --- src/os_unix.c | 2 +- src/version.c | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/src/os_unix.c b/src/os_unix.c index 66903e0819..f8fe2cb64b 100644 --- a/src/os_unix.c +++ b/src/os_unix.c @@ -4196,7 +4196,7 @@ set_child_environment( vim_snprintf(envbuf_Columns, sizeof(envbuf_Columns), "COLUMNS=%ld", columns); putenv(envbuf_Columns); - vim_snprintf(envbuf_Colors, sizeof(envbuf_Colors), "COLORS=%ld", colors); + vim_snprintf(envbuf_Colors, sizeof(envbuf_Colors), "COLORS=%ld", t_colors); putenv(envbuf_Colors); # ifdef FEAT_TERMINAL if (is_terminal) diff --git a/src/version.c b/src/version.c index eac5c9adfa..127f906291 100644 --- a/src/version.c +++ b/src/version.c @@ -746,6 +746,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 658, /**/ 657, /**/ From 939b5db4808770d3a2ec35e3902a9d5165adc0cf Mon Sep 17 00:00:00 2001 From: Bram Moolenaar <Bram@vim.org> Date: Tue, 28 Apr 2020 22:49:08 +0200 Subject: [PATCH 053/230] patch 8.2.0659: Vim9: no test for equal func type Problem: Vim9: no test for equal func type. Solution: Add a test. Improve type check. --- src/testdir/test_vim9_expr.vim | 10 ++++++++++ src/version.c | 2 ++ src/vim9compile.c | 12 +++++++++--- 3 files changed, 21 insertions(+), 3 deletions(-) diff --git a/src/testdir/test_vim9_expr.vim b/src/testdir/test_vim9_expr.vim index ace3d2f256..ef5c00ccd7 100644 --- a/src/testdir/test_vim9_expr.vim +++ b/src/testdir/test_vim9_expr.vim @@ -30,6 +30,16 @@ def Test_expr1() assert_equal('two', {} ? 'one' : 'two') var = 0 assert_equal('two', var ? 'one' : 'two') + + let Some: func = function('len') + let Other: func = function('winnr') + let Res: func = g:atrue ? Some : Other + assert_equal(function('len'), Res) + + let RetOne: func(string): number = function('len') + let RetTwo: func(string): number = function('winnr') + let RetThat: func = g:atrue ? RetOne : RetTwo + assert_equal(function('len'), RetThat) enddef func Test_expr1_fails() diff --git a/src/version.c b/src/version.c index 127f906291..d3a1b0b7fe 100644 --- a/src/version.c +++ b/src/version.c @@ -746,6 +746,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 659, /**/ 658, /**/ diff --git a/src/vim9compile.c b/src/vim9compile.c index aa3cd07d3d..7b433a3b15 100644 --- a/src/vim9compile.c +++ b/src/vim9compile.c @@ -724,7 +724,8 @@ generate_TYPECHECK(cctx_T *cctx, type_T *vartype, int offset) RETURN_OK_IF_SKIP(cctx); if ((isn = generate_instr(cctx, ISN_CHECKTYPE)) == NULL) return FAIL; - isn->isn_arg.type.ct_type = vartype->tt_type; // TODO: whole type + // TODO: whole type, e.g. for a function also arg and return types + isn->isn_arg.type.ct_type = vartype->tt_type; isn->isn_arg.type.ct_off = offset; // type becomes vartype @@ -2594,6 +2595,7 @@ arg_type_mismatch(type_T *expected, type_T *actual, int argidx) /* * Check if the expected and actual types match. + * Does not allow for assigning "any" to a specific type. */ static int check_type(type_T *expected, type_T *actual, int give_msg) @@ -2603,7 +2605,8 @@ check_type(type_T *expected, type_T *actual, int give_msg) // When expected is "unknown" we accept any actual type. // When expected is "any" we accept any actual type except "void". if (expected->tt_type != VAR_UNKNOWN - && (expected->tt_type != VAR_ANY || actual->tt_type == VAR_VOID)) + && !(expected->tt_type == VAR_ANY && actual->tt_type != VAR_VOID)) + { if (expected->tt_type != actual->tt_type) { @@ -2643,7 +2646,10 @@ need_type(type_T *actual, type_T *expected, int offset, cctx_T *cctx) { if (check_type(expected, actual, FALSE) == OK) return OK; - if (actual->tt_type != VAR_ANY && actual->tt_type != VAR_UNKNOWN) + if (actual->tt_type != VAR_ANY + && actual->tt_type != VAR_UNKNOWN + && !(actual->tt_type == VAR_FUNC + && (actual->tt_member == &t_any || actual->tt_argcount < 0))) { type_mismatch(expected, actual); return FAIL; From ed8ce057b7a2fcd89b5f55680ae8f85d62a992a5 Mon Sep 17 00:00:00 2001 From: Bram Moolenaar <Bram@vim.org> Date: Wed, 29 Apr 2020 21:04:15 +0200 Subject: [PATCH 054/230] patch 8.2.0660: the search.c file is a bit big Problem: The search.c file is a bit big. Solution: Split off the text object code to a separate file. (Yegappan Lakshmanan, closes #6007) --- Filelist | 2 + src/Make_cyg_ming.mak | 1 + src/Make_morph.mak | 1 + src/Make_mvc.mak | 4 + src/Make_vms.mms | 5 + src/Makefile | 34 +- src/README.md | 1 + src/proto.h | 1 + src/proto/search.pro | 13 - src/proto/textobject.pro | 16 + src/search.c | 1951 ------------------------------------- src/textobject.c | 1965 ++++++++++++++++++++++++++++++++++++++ src/version.c | 2 + 13 files changed, 2020 insertions(+), 1976 deletions(-) create mode 100644 src/proto/textobject.pro create mode 100644 src/textobject.c diff --git a/Filelist b/Filelist index 46f6774e76..ef65b8da24 100644 --- a/Filelist +++ b/Filelist @@ -128,6 +128,7 @@ SRC_ALL = \ src/term.h \ src/termlib.c \ src/testing.c \ + src/textobject.c \ src/textprop.c \ src/time.c \ src/ui.c \ @@ -279,6 +280,7 @@ SRC_ALL = \ src/proto/terminal.pro \ src/proto/termlib.pro \ src/proto/testing.pro \ + src/proto/textobject.pro \ src/proto/textprop.pro \ src/proto/time.pro \ src/proto/ui.pro \ diff --git a/src/Make_cyg_ming.mak b/src/Make_cyg_ming.mak index 750e940e06..7964b0a1f2 100644 --- a/src/Make_cyg_ming.mak +++ b/src/Make_cyg_ming.mak @@ -787,6 +787,7 @@ OBJ = \ $(OUTDIR)/tag.o \ $(OUTDIR)/term.o \ $(OUTDIR)/testing.o \ + $(OUTDIR)/textobject.o \ $(OUTDIR)/textprop.o \ $(OUTDIR)/time.o \ $(OUTDIR)/ui.o \ diff --git a/src/Make_morph.mak b/src/Make_morph.mak index 1830d85b50..d326174cd2 100644 --- a/src/Make_morph.mak +++ b/src/Make_morph.mak @@ -103,6 +103,7 @@ SRC = arabic.c \ tag.c \ term.c \ testing.c \ + textobject.c \ textprop.c \ time.c \ ui.c \ diff --git a/src/Make_mvc.mak b/src/Make_mvc.mak index ebc059f862..c873ca0840 100644 --- a/src/Make_mvc.mak +++ b/src/Make_mvc.mak @@ -806,6 +806,7 @@ OBJ = \ $(OUTDIR)\tag.obj \ $(OUTDIR)\term.obj \ $(OUTDIR)\testing.obj \ + $(OUTDIR)\textobject.obj \ $(OUTDIR)\textprop.obj \ $(OUTDIR)\time.obj \ $(OUTDIR)\ui.obj \ @@ -1744,6 +1745,8 @@ $(OUTDIR)/term.obj: $(OUTDIR) term.c $(INCL) $(OUTDIR)/term.obj: $(OUTDIR) testing.c $(INCL) +$(OUTDIR)/textobject.obj: $(OUTDIR) textobject.c $(INCL) + $(OUTDIR)/textprop.obj: $(OUTDIR) textprop.c $(INCL) $(OUTDIR)/time.obj: $(OUTDIR) time.c $(INCL) @@ -1942,6 +1945,7 @@ proto.h: \ proto/tag.pro \ proto/term.pro \ proto/testing.pro \ + proto/textobject.pro \ proto/textprop.pro \ proto/time.pro \ proto/ui.pro \ diff --git a/src/Make_vms.mms b/src/Make_vms.mms index fdd7ba7c1e..e04020172a 100644 --- a/src/Make_vms.mms +++ b/src/Make_vms.mms @@ -382,6 +382,7 @@ SRC = \ term.c \ termlib.c \ testing.c \ + textobject.c \ textprop.c \ time.c \ ui.c \ @@ -491,6 +492,7 @@ OBJ = \ term.obj \ termlib.obj \ testing.obj \ + textobject.obj \ textprop.obj \ time.obj \ ui.obj \ @@ -989,6 +991,9 @@ termlib.obj : termlib.c vim.h [.auto]config.h feature.h os_unix.h \ testing.obj : testing.c vim.h [.auto]config.h feature.h os_unix.h \ ascii.h keymap.h term.h macros.h structs.h regexp.h gui.h beval.h \ [.proto]gui_beval.pro option.h ex_cmds.h proto.h globals.h +textobject.obj : textobject.c vim.h [.auto]config.h feature.h os_unix.h \ + ascii.h keymap.h term.h macros.h structs.h regexp.h gui.h beval.h \ + [.proto]gui_beval.pro option.h ex_cmds.h proto.h globals.h textprop.obj : textprop.c vim.h [.auto]config.h feature.h os_unix.h \ ascii.h keymap.h term.h macros.h structs.h regexp.h gui.h beval.h \ [.proto]gui_beval.pro option.h ex_cmds.h proto.h globals.h diff --git a/src/Makefile b/src/Makefile index 19453c7421..c8e0f087fe 100644 --- a/src/Makefile +++ b/src/Makefile @@ -404,7 +404,7 @@ CClink = $(CC) # Use --with-luajit if you want to use LuaJIT instead of Lua. # Set PATH environment variable to find lua or luajit executable. # This requires at least "normal" features, "tiny" and "small" don't work. -#CONF_OPT_LUA = --enable-luainterp +CONF_OPT_LUA = --enable-luainterp #CONF_OPT_LUA = --enable-luainterp=dynamic #CONF_OPT_LUA = --enable-luainterp --with-luajit #CONF_OPT_LUA = --enable-luainterp=dynamic --with-luajit @@ -433,7 +433,7 @@ CClink = $(CC) # When you get an error for a missing "perl.exp" file, try creating an empty # one: "touch perl.exp". # This requires at least "normal" features, "tiny" and "small" don't work. -#CONF_OPT_PERL = --enable-perlinterp +CONF_OPT_PERL = --enable-perlinterp #CONF_OPT_PERL = --enable-perlinterp=dynamic # PYTHON @@ -447,10 +447,10 @@ CClink = $(CC) # dlopen(), dlsym(), dlclose(), i.e. pythonX.Y.so must be available # However, this may still cause problems, such as "import termios" failing. # Build two separate versions of Vim in that case. -#CONF_OPT_PYTHON = --enable-pythoninterp +CONF_OPT_PYTHON = --enable-pythoninterp #CONF_OPT_PYTHON = --enable-pythoninterp --with-python-command=python2.7 #CONF_OPT_PYTHON = --enable-pythoninterp=dynamic -#CONF_OPT_PYTHON3 = --enable-python3interp +CONF_OPT_PYTHON3 = --enable-python3interp #CONF_OPT_PYTHON3 = --enable-python3interp --with-python3-command=python3.6 #CONF_OPT_PYTHON3 = --enable-python3interp=dynamic @@ -460,19 +460,19 @@ CClink = $(CC) # Note: you need the development package (e.g., ruby1.9.1-dev on Ubuntu). # This requires at least "normal" features, "tiny" and "small" don't work. #CONF_OPT_RUBY = --enable-rubyinterp -#CONF_OPT_RUBY = --enable-rubyinterp=dynamic +CONF_OPT_RUBY = --enable-rubyinterp=dynamic #CONF_OPT_RUBY = --enable-rubyinterp --with-ruby-command=ruby1.9.1 # TCL # Uncomment this when you want to include the Tcl interface. # First one is for static linking, second one for dynamic loading. #CONF_OPT_TCL = --enable-tclinterp -#CONF_OPT_TCL = --enable-tclinterp=dynamic +CONF_OPT_TCL = --enable-tclinterp=dynamic #CONF_OPT_TCL = --enable-tclinterp --with-tclsh=tclsh8.4 # CSCOPE # Uncomment this when you want to include the Cscope interface. -#CONF_OPT_CSCOPE = --enable-cscope +CONF_OPT_CSCOPE = --enable-cscope # NETBEANS - NetBeans interface. Only works with Motif, GTK, and gnome. # Motif version must have XPM libraries (see |netbeans-xpm|). @@ -540,7 +540,7 @@ CClink = $(CC) #CONF_OPT_FEAT = --with-features=small #CONF_OPT_FEAT = --with-features=normal #CONF_OPT_FEAT = --with-features=big -#CONF_OPT_FEAT = --with-features=huge +CONF_OPT_FEAT = --with-features=huge # COMPILED BY - For including a specific e-mail address for ":version". #CONF_OPT_COMPBY = "--with-compiledby=John Doe <JohnDoe@yahoo.com>" @@ -614,11 +614,11 @@ CClink = $(CC) # Use this with GCC to check for mistakes, unused arguments, etc. # Note: If you use -Wextra and get warnings in GTK code about function # parameters, you can add -Wno-cast-function-type -#CFLAGS = -g -Wall -Wextra -Wshadow -Wmissing-prototypes -Wunreachable-code -Wno-cast-function-type -Wno-deprecated-declarations -U_FORTIFY_SOURCE -D_FORTIFY_SOURCE=1 +CFLAGS = -g -Wall -Wextra -Wshadow -Wmissing-prototypes -Wunreachable-code -Wno-cast-function-type -Wno-deprecated-declarations -U_FORTIFY_SOURCE -D_FORTIFY_SOURCE=1 # Add -Wpedantic to find // comments and other C99 constructs. # Better disable Perl and Python to avoid a lot of warnings. #CFLAGS = -g -Wall -Wextra -Wshadow -Wmissing-prototypes -Wpedantic -Wunreachable-code -Wunused-result -U_FORTIFY_SOURCE -D_FORTIFY_SOURCE=1 -#CFLAGS = -g -O2 -Wall -Wextra -Wshadow -Wmissing-prototypes -Wpedantic -Wunreachable-code -Wunused-result -U_FORTIFY_SOURCE -D_FORTIFY_SOURCE=1 +#CFLAGS = -g -O2 -Wall -Wextra -Wshadow -Wmissing-prototypes -Wpedantic -Wunreachable-code -Wno-cast-function-type -Wunused-result -Wno-deprecated-declarations -U_FORTIFY_SOURCE -D_FORTIFY_SOURCE=1 #PYTHON_CFLAGS_EXTRA = -Wno-missing-field-initializers #MZSCHEME_CFLAGS_EXTRA = -Wno-unreachable-code -Wno-unused-parameter @@ -707,12 +707,12 @@ SANITIZER_LIBS = $(SANITIZER_CFLAGS) # Configuration is in the .ccmalloc or ~/.ccmalloc file. # Doesn't work very well, since memory linked to from global variables # (in libraries) is also marked as leaked memory. -#LEAK_CFLAGS = -DEXITFREE +LEAK_CFLAGS = -DEXITFREE #LEAK_LIBS = -lccmalloc # Uncomment this line to have Vim call abort() when an internal error is # detected. Useful when using a tool to find errors. -#ABORT_CFLAGS = -DABORT_ON_INTERNAL_ERROR +ABORT_CFLAGS = -DABORT_ON_INTERNAL_ERROR ##################################################### ### Specific systems, check if yours is listed! ### {{{ @@ -1680,6 +1680,7 @@ BASIC_SRC = \ term.c \ terminal.c \ testing.c \ + textobject.c \ textprop.c \ time.c \ ui.c \ @@ -1822,6 +1823,7 @@ OBJ_COMMON = \ objects/term.o \ objects/terminal.o \ objects/testing.o \ + objects/textobject.o \ objects/textprop.o \ objects/time.o \ objects/ui.o \ @@ -1996,6 +1998,7 @@ PRO_AUTO = \ terminal.pro \ termlib.pro \ testing.pro \ + textobject.pro \ textprop.pro \ time.pro \ ui.pro \ @@ -3469,6 +3472,9 @@ objects/terminal.o: terminal.c $(TERM_DEPS) objects/testing.o: testing.c $(CCC) -o $@ testing.c +objects/textobject.o: textobject.c + $(CCC) -o $@ textobject.c + objects/textprop.o: textprop.c $(CCC) -o $@ textprop.c @@ -4060,6 +4066,10 @@ objects/testing.o: testing.c vim.h protodef.h auto/config.h feature.h os_unix.h auto/osdef.h ascii.h keymap.h term.h macros.h option.h beval.h \ proto/gui_beval.pro structs.h regexp.h gui.h alloc.h ex_cmds.h spell.h \ proto.h globals.h +objects/textobject.o: textobject.c vim.h protodef.h auto/config.h feature.h os_unix.h \ + auto/osdef.h ascii.h keymap.h term.h macros.h option.h beval.h \ + proto/gui_beval.pro structs.h regexp.h gui.h alloc.h ex_cmds.h spell.h \ + proto.h globals.h objects/textprop.o: textprop.c vim.h protodef.h auto/config.h feature.h os_unix.h \ auto/osdef.h ascii.h keymap.h term.h macros.h option.h beval.h \ proto/gui_beval.pro structs.h regexp.h gui.h alloc.h ex_cmds.h spell.h \ diff --git a/src/README.md b/src/README.md index 54be08284f..765313da7e 100644 --- a/src/README.md +++ b/src/README.md @@ -80,6 +80,7 @@ syntax.c | syntax and other highlighting tag.c | tags term.c | terminal handling, termcap codes testing.c | testing: assert and test functions +textobject.c | text objects textprop.c | text properties time.c | time and timer functions undo.c | undo and redo diff --git a/src/proto.h b/src/proto.h index 0115c68d19..d54936c751 100644 --- a/src/proto.h +++ b/src/proto.h @@ -223,6 +223,7 @@ void mbyte_im_set_active(int active_arg); # include "textprop.pro" # endif # include "testing.pro" +# include "textobject.pro" # include "time.pro" # include "ui.pro" # include "undo.pro" diff --git a/src/proto/search.pro b/src/proto/search.pro index 018c33a4f2..1e15a8828e 100644 --- a/src/proto/search.pro +++ b/src/proto/search.pro @@ -30,19 +30,6 @@ int searchc(cmdarg_T *cap, int t_cmd); pos_T *findmatch(oparg_T *oap, int initc); pos_T *findmatchlimit(oparg_T *oap, int initc, int flags, int maxtravel); void showmatch(int c); -int findsent(int dir, long count); -int findpar(int *pincl, int dir, long count, int what, int both); -int startPS(linenr_T lnum, int para, int both); -int fwd_word(long count, int bigword, int eol); -int bck_word(long count, int bigword, int stop); -int end_word(long count, int bigword, int stop, int empty); -int bckend_word(long count, int bigword, int eol); -int current_word(oparg_T *oap, long count, int include, int bigword); -int current_sent(oparg_T *oap, long count, int include); -int current_block(oparg_T *oap, long count, int include, int what, int other); -int current_tagblock(oparg_T *oap, long count_arg, int include); -int current_par(oparg_T *oap, long count, int include, int type); -int current_quote(oparg_T *oap, long count, int include, int quotechar); int current_search(long count, int forward); int linewhite(linenr_T lnum); void find_pattern_in_path(char_u *ptr, int dir, int len, int whole, int skip_comments, int type, long count, int action, linenr_T start_lnum, linenr_T end_lnum); diff --git a/src/proto/textobject.pro b/src/proto/textobject.pro new file mode 100644 index 0000000000..7931979140 --- /dev/null +++ b/src/proto/textobject.pro @@ -0,0 +1,16 @@ +/* textobject.c */ +int findsent(int dir, long count); +int findpar(int *pincl, int dir, long count, int what, int both); +int startPS(linenr_T lnum, int para, int both); +int fwd_word(long count, int bigword, int eol); +int bck_word(long count, int bigword, int stop); +int end_word(long count, int bigword, int stop, int empty); +int bckend_word(long count, int bigword, int eol); +int current_word(oparg_T *oap, long count, int include, int bigword); +int current_sent(oparg_T *oap, long count, int include); +int current_block(oparg_T *oap, long count, int include, int what, int other); +int current_tagblock(oparg_T *oap, long count_arg, int include); +int current_par(oparg_T *oap, long count, int include, int type); +int current_quote(oparg_T *oap, long count, int include, int quotechar); +/* vim: set ft=c : */ + diff --git a/src/search.c b/src/search.c index 8c335ffd3a..0bf49629eb 100644 --- a/src/search.c +++ b/src/search.c @@ -17,8 +17,6 @@ static void set_vv_searchforward(void); static int first_submatch(regmmatch_T *rp); #endif static int check_linecomment(char_u *line); -static int cls(void); -static int skip_chars(int, int); #ifdef FEAT_FIND_ID static void show_pat_in_path(char_u *, int, int, int, FILE *, linenr_T *, long); @@ -2837,1955 +2835,6 @@ showmatch( } } -/* - * Find the start of the next sentence, searching in the direction specified - * by the "dir" argument. The cursor is positioned on the start of the next - * sentence when found. If the next sentence is found, return OK. Return FAIL - * otherwise. See ":h sentence" for the precise definition of a "sentence" - * text object. - */ - int -findsent(int dir, long count) -{ - pos_T pos, tpos; - int c; - int (*func)(pos_T *); - int startlnum; - int noskip = FALSE; // do not skip blanks - int cpo_J; - int found_dot; - - pos = curwin->w_cursor; - if (dir == FORWARD) - func = incl; - else - func = decl; - - while (count--) - { - /* - * if on an empty line, skip up to a non-empty line - */ - if (gchar_pos(&pos) == NUL) - { - do - if ((*func)(&pos) == -1) - break; - while (gchar_pos(&pos) == NUL); - if (dir == FORWARD) - goto found; - } - /* - * if on the start of a paragraph or a section and searching forward, - * go to the next line - */ - else if (dir == FORWARD && pos.col == 0 && - startPS(pos.lnum, NUL, FALSE)) - { - if (pos.lnum == curbuf->b_ml.ml_line_count) - return FAIL; - ++pos.lnum; - goto found; - } - else if (dir == BACKWARD) - decl(&pos); - - // go back to the previous non-white non-punctuation character - found_dot = FALSE; - while (c = gchar_pos(&pos), VIM_ISWHITE(c) - || vim_strchr((char_u *)".!?)]\"'", c) != NULL) - { - tpos = pos; - if (decl(&tpos) == -1 || (LINEEMPTY(tpos.lnum) && dir == FORWARD)) - break; - - if (found_dot) - break; - if (vim_strchr((char_u *) ".!?", c) != NULL) - found_dot = TRUE; - - if (vim_strchr((char_u *) ")]\"'", c) != NULL - && vim_strchr((char_u *) ".!?)]\"'", gchar_pos(&tpos)) == NULL) - break; - - decl(&pos); - } - - // remember the line where the search started - startlnum = pos.lnum; - cpo_J = vim_strchr(p_cpo, CPO_ENDOFSENT) != NULL; - - for (;;) // find end of sentence - { - c = gchar_pos(&pos); - if (c == NUL || (pos.col == 0 && startPS(pos.lnum, NUL, FALSE))) - { - if (dir == BACKWARD && pos.lnum != startlnum) - ++pos.lnum; - break; - } - if (c == '.' || c == '!' || c == '?') - { - tpos = pos; - do - if ((c = inc(&tpos)) == -1) - break; - while (vim_strchr((char_u *)")]\"'", c = gchar_pos(&tpos)) - != NULL); - if (c == -1 || (!cpo_J && (c == ' ' || c == '\t')) || c == NUL - || (cpo_J && (c == ' ' && inc(&tpos) >= 0 - && gchar_pos(&tpos) == ' '))) - { - pos = tpos; - if (gchar_pos(&pos) == NUL) // skip NUL at EOL - inc(&pos); - break; - } - } - if ((*func)(&pos) == -1) - { - if (count) - return FAIL; - noskip = TRUE; - break; - } - } -found: - // skip white space - while (!noskip && ((c = gchar_pos(&pos)) == ' ' || c == '\t')) - if (incl(&pos) == -1) - break; - } - - setpcmark(); - curwin->w_cursor = pos; - return OK; -} - -/* - * Find the next paragraph or section in direction 'dir'. - * Paragraphs are currently supposed to be separated by empty lines. - * If 'what' is NUL we go to the next paragraph. - * If 'what' is '{' or '}' we go to the next section. - * If 'both' is TRUE also stop at '}'. - * Return TRUE if the next paragraph or section was found. - */ - int -findpar( - int *pincl, // Return: TRUE if last char is to be included - int dir, - long count, - int what, - int both) -{ - linenr_T curr; - int did_skip; // TRUE after separating lines have been skipped - int first; // TRUE on first line - int posix = (vim_strchr(p_cpo, CPO_PARA) != NULL); -#ifdef FEAT_FOLDING - linenr_T fold_first; // first line of a closed fold - linenr_T fold_last; // last line of a closed fold - int fold_skipped; // TRUE if a closed fold was skipped this - // iteration -#endif - - curr = curwin->w_cursor.lnum; - - while (count--) - { - did_skip = FALSE; - for (first = TRUE; ; first = FALSE) - { - if (*ml_get(curr) != NUL) - did_skip = TRUE; - -#ifdef FEAT_FOLDING - // skip folded lines - fold_skipped = FALSE; - if (first && hasFolding(curr, &fold_first, &fold_last)) - { - curr = ((dir > 0) ? fold_last : fold_first) + dir; - fold_skipped = TRUE; - } -#endif - - // POSIX has its own ideas of what a paragraph boundary is and it - // doesn't match historical Vi: It also stops at a "{" in the - // first column and at an empty line. - if (!first && did_skip && (startPS(curr, what, both) - || (posix && what == NUL && *ml_get(curr) == '{'))) - break; - -#ifdef FEAT_FOLDING - if (fold_skipped) - curr -= dir; -#endif - if ((curr += dir) < 1 || curr > curbuf->b_ml.ml_line_count) - { - if (count) - return FALSE; - curr -= dir; - break; - } - } - } - setpcmark(); - if (both && *ml_get(curr) == '}') // include line with '}' - ++curr; - curwin->w_cursor.lnum = curr; - if (curr == curbuf->b_ml.ml_line_count && what != '}') - { - char_u *line = ml_get(curr); - - // Put the cursor on the last character in the last line and make the - // motion inclusive. - if ((curwin->w_cursor.col = (colnr_T)STRLEN(line)) != 0) - { - --curwin->w_cursor.col; - curwin->w_cursor.col -= - (*mb_head_off)(line, line + curwin->w_cursor.col); - *pincl = TRUE; - } - } - else - curwin->w_cursor.col = 0; - return TRUE; -} - -/* - * check if the string 's' is a nroff macro that is in option 'opt' - */ - static int -inmacro(char_u *opt, char_u *s) -{ - char_u *macro; - - for (macro = opt; macro[0]; ++macro) - { - // Accept two characters in the option being equal to two characters - // in the line. A space in the option matches with a space in the - // line or the line having ended. - if ( (macro[0] == s[0] - || (macro[0] == ' ' - && (s[0] == NUL || s[0] == ' '))) - && (macro[1] == s[1] - || ((macro[1] == NUL || macro[1] == ' ') - && (s[0] == NUL || s[1] == NUL || s[1] == ' ')))) - break; - ++macro; - if (macro[0] == NUL) - break; - } - return (macro[0] != NUL); -} - -/* - * startPS: return TRUE if line 'lnum' is the start of a section or paragraph. - * If 'para' is '{' or '}' only check for sections. - * If 'both' is TRUE also stop at '}' - */ - int -startPS(linenr_T lnum, int para, int both) -{ - char_u *s; - - s = ml_get(lnum); - if (*s == para || *s == '\f' || (both && *s == '}')) - return TRUE; - if (*s == '.' && (inmacro(p_sections, s + 1) || - (!para && inmacro(p_para, s + 1)))) - return TRUE; - return FALSE; -} - -/* - * The following routines do the word searches performed by the 'w', 'W', - * 'b', 'B', 'e', and 'E' commands. - */ - -/* - * To perform these searches, characters are placed into one of three - * classes, and transitions between classes determine word boundaries. - * - * The classes are: - * - * 0 - white space - * 1 - punctuation - * 2 or higher - keyword characters (letters, digits and underscore) - */ - -static int cls_bigword; // TRUE for "W", "B" or "E" - -/* - * cls() - returns the class of character at curwin->w_cursor - * - * If a 'W', 'B', or 'E' motion is being done (cls_bigword == TRUE), chars - * from class 2 and higher are reported as class 1 since only white space - * boundaries are of interest. - */ - static int -cls(void) -{ - int c; - - c = gchar_cursor(); - if (c == ' ' || c == '\t' || c == NUL) - return 0; - if (enc_dbcs != 0 && c > 0xFF) - { - // If cls_bigword, report multi-byte chars as class 1. - if (enc_dbcs == DBCS_KOR && cls_bigword) - return 1; - - // process code leading/trailing bytes - return dbcs_class(((unsigned)c >> 8), (c & 0xFF)); - } - if (enc_utf8) - { - c = utf_class(c); - if (c != 0 && cls_bigword) - return 1; - return c; - } - - // If cls_bigword is TRUE, report all non-blanks as class 1. - if (cls_bigword) - return 1; - - if (vim_iswordc(c)) - return 2; - return 1; -} - - -/* - * fwd_word(count, type, eol) - move forward one word - * - * Returns FAIL if the cursor was already at the end of the file. - * If eol is TRUE, last word stops at end of line (for operators). - */ - int -fwd_word( - long count, - int bigword, // "W", "E" or "B" - int eol) -{ - int sclass; // starting class - int i; - int last_line; - - curwin->w_cursor.coladd = 0; - cls_bigword = bigword; - while (--count >= 0) - { -#ifdef FEAT_FOLDING - // When inside a range of folded lines, move to the last char of the - // last line. - if (hasFolding(curwin->w_cursor.lnum, NULL, &curwin->w_cursor.lnum)) - coladvance((colnr_T)MAXCOL); -#endif - sclass = cls(); - - /* - * We always move at least one character, unless on the last - * character in the buffer. - */ - last_line = (curwin->w_cursor.lnum == curbuf->b_ml.ml_line_count); - i = inc_cursor(); - if (i == -1 || (i >= 1 && last_line)) // started at last char in file - return FAIL; - if (i >= 1 && eol && count == 0) // started at last char in line - return OK; - - /* - * Go one char past end of current word (if any) - */ - if (sclass != 0) - while (cls() == sclass) - { - i = inc_cursor(); - if (i == -1 || (i >= 1 && eol && count == 0)) - return OK; - } - - /* - * go to next non-white - */ - while (cls() == 0) - { - /* - * We'll stop if we land on a blank line - */ - if (curwin->w_cursor.col == 0 && *ml_get_curline() == NUL) - break; - - i = inc_cursor(); - if (i == -1 || (i >= 1 && eol && count == 0)) - return OK; - } - } - return OK; -} - -/* - * bck_word() - move backward 'count' words - * - * If stop is TRUE and we are already on the start of a word, move one less. - * - * Returns FAIL if top of the file was reached. - */ - int -bck_word(long count, int bigword, int stop) -{ - int sclass; // starting class - - curwin->w_cursor.coladd = 0; - cls_bigword = bigword; - while (--count >= 0) - { -#ifdef FEAT_FOLDING - // When inside a range of folded lines, move to the first char of the - // first line. - if (hasFolding(curwin->w_cursor.lnum, &curwin->w_cursor.lnum, NULL)) - curwin->w_cursor.col = 0; -#endif - sclass = cls(); - if (dec_cursor() == -1) // started at start of file - return FAIL; - - if (!stop || sclass == cls() || sclass == 0) - { - /* - * Skip white space before the word. - * Stop on an empty line. - */ - while (cls() == 0) - { - if (curwin->w_cursor.col == 0 - && LINEEMPTY(curwin->w_cursor.lnum)) - goto finished; - if (dec_cursor() == -1) // hit start of file, stop here - return OK; - } - - /* - * Move backward to start of this word. - */ - if (skip_chars(cls(), BACKWARD)) - return OK; - } - - inc_cursor(); // overshot - forward one -finished: - stop = FALSE; - } - return OK; -} - -/* - * end_word() - move to the end of the word - * - * There is an apparent bug in the 'e' motion of the real vi. At least on the - * System V Release 3 version for the 80386. Unlike 'b' and 'w', the 'e' - * motion crosses blank lines. When the real vi crosses a blank line in an - * 'e' motion, the cursor is placed on the FIRST character of the next - * non-blank line. The 'E' command, however, works correctly. Since this - * appears to be a bug, I have not duplicated it here. - * - * Returns FAIL if end of the file was reached. - * - * If stop is TRUE and we are already on the end of a word, move one less. - * If empty is TRUE stop on an empty line. - */ - int -end_word( - long count, - int bigword, - int stop, - int empty) -{ - int sclass; // starting class - - curwin->w_cursor.coladd = 0; - cls_bigword = bigword; - while (--count >= 0) - { -#ifdef FEAT_FOLDING - // When inside a range of folded lines, move to the last char of the - // last line. - if (hasFolding(curwin->w_cursor.lnum, NULL, &curwin->w_cursor.lnum)) - coladvance((colnr_T)MAXCOL); -#endif - sclass = cls(); - if (inc_cursor() == -1) - return FAIL; - - /* - * If we're in the middle of a word, we just have to move to the end - * of it. - */ - if (cls() == sclass && sclass != 0) - { - /* - * Move forward to end of the current word - */ - if (skip_chars(sclass, FORWARD)) - return FAIL; - } - else if (!stop || sclass == 0) - { - /* - * We were at the end of a word. Go to the end of the next word. - * First skip white space, if 'empty' is TRUE, stop at empty line. - */ - while (cls() == 0) - { - if (empty && curwin->w_cursor.col == 0 - && LINEEMPTY(curwin->w_cursor.lnum)) - goto finished; - if (inc_cursor() == -1) // hit end of file, stop here - return FAIL; - } - - /* - * Move forward to the end of this word. - */ - if (skip_chars(cls(), FORWARD)) - return FAIL; - } - dec_cursor(); // overshot - one char backward -finished: - stop = FALSE; // we move only one word less - } - return OK; -} - -/* - * Move back to the end of the word. - * - * Returns FAIL if start of the file was reached. - */ - int -bckend_word( - long count, - int bigword, // TRUE for "B" - int eol) // TRUE: stop at end of line. -{ - int sclass; // starting class - int i; - - curwin->w_cursor.coladd = 0; - cls_bigword = bigword; - while (--count >= 0) - { - sclass = cls(); - if ((i = dec_cursor()) == -1) - return FAIL; - if (eol && i == 1) - return OK; - - /* - * Move backward to before the start of this word. - */ - if (sclass != 0) - { - while (cls() == sclass) - if ((i = dec_cursor()) == -1 || (eol && i == 1)) - return OK; - } - - /* - * Move backward to end of the previous word - */ - while (cls() == 0) - { - if (curwin->w_cursor.col == 0 && LINEEMPTY(curwin->w_cursor.lnum)) - break; - if ((i = dec_cursor()) == -1 || (eol && i == 1)) - return OK; - } - } - return OK; -} - -/* - * Skip a row of characters of the same class. - * Return TRUE when end-of-file reached, FALSE otherwise. - */ - static int -skip_chars(int cclass, int dir) -{ - while (cls() == cclass) - if ((dir == FORWARD ? inc_cursor() : dec_cursor()) == -1) - return TRUE; - return FALSE; -} - -#ifdef FEAT_TEXTOBJ -/* - * Go back to the start of the word or the start of white space - */ - static void -back_in_line(void) -{ - int sclass; // starting class - - sclass = cls(); - for (;;) - { - if (curwin->w_cursor.col == 0) // stop at start of line - break; - dec_cursor(); - if (cls() != sclass) // stop at start of word - { - inc_cursor(); - break; - } - } -} - - static void -find_first_blank(pos_T *posp) -{ - int c; - - while (decl(posp) != -1) - { - c = gchar_pos(posp); - if (!VIM_ISWHITE(c)) - { - incl(posp); - break; - } - } -} - -/* - * Skip count/2 sentences and count/2 separating white spaces. - */ - static void -findsent_forward( - long count, - int at_start_sent) // cursor is at start of sentence -{ - while (count--) - { - findsent(FORWARD, 1L); - if (at_start_sent) - find_first_blank(&curwin->w_cursor); - if (count == 0 || at_start_sent) - decl(&curwin->w_cursor); - at_start_sent = !at_start_sent; - } -} - -/* - * Find word under cursor, cursor at end. - * Used while an operator is pending, and in Visual mode. - */ - int -current_word( - oparg_T *oap, - long count, - int include, // TRUE: include word and white space - int bigword) // FALSE == word, TRUE == WORD -{ - pos_T start_pos; - pos_T pos; - int inclusive = TRUE; - int include_white = FALSE; - - cls_bigword = bigword; - CLEAR_POS(&start_pos); - - // Correct cursor when 'selection' is exclusive - if (VIsual_active && *p_sel == 'e' && LT_POS(VIsual, curwin->w_cursor)) - dec_cursor(); - - /* - * When Visual mode is not active, or when the VIsual area is only one - * character, select the word and/or white space under the cursor. - */ - if (!VIsual_active || EQUAL_POS(curwin->w_cursor, VIsual)) - { - /* - * Go to start of current word or white space. - */ - back_in_line(); - start_pos = curwin->w_cursor; - - /* - * If the start is on white space, and white space should be included - * (" word"), or start is not on white space, and white space should - * not be included ("word"), find end of word. - */ - if ((cls() == 0) == include) - { - if (end_word(1L, bigword, TRUE, TRUE) == FAIL) - return FAIL; - } - else - { - /* - * If the start is not on white space, and white space should be - * included ("word "), or start is on white space and white - * space should not be included (" "), find start of word. - * If we end up in the first column of the next line (single char - * word) back up to end of the line. - */ - fwd_word(1L, bigword, TRUE); - if (curwin->w_cursor.col == 0) - decl(&curwin->w_cursor); - else - oneleft(); - - if (include) - include_white = TRUE; - } - - if (VIsual_active) - { - // should do something when inclusive == FALSE ! - VIsual = start_pos; - redraw_curbuf_later(INVERTED); // update the inversion - } - else - { - oap->start = start_pos; - oap->motion_type = MCHAR; - } - --count; - } - - /* - * When count is still > 0, extend with more objects. - */ - while (count > 0) - { - inclusive = TRUE; - if (VIsual_active && LT_POS(curwin->w_cursor, VIsual)) - { - /* - * In Visual mode, with cursor at start: move cursor back. - */ - if (decl(&curwin->w_cursor) == -1) - return FAIL; - if (include != (cls() != 0)) - { - if (bck_word(1L, bigword, TRUE) == FAIL) - return FAIL; - } - else - { - if (bckend_word(1L, bigword, TRUE) == FAIL) - return FAIL; - (void)incl(&curwin->w_cursor); - } - } - else - { - /* - * Move cursor forward one word and/or white area. - */ - if (incl(&curwin->w_cursor) == -1) - return FAIL; - if (include != (cls() == 0)) - { - if (fwd_word(1L, bigword, TRUE) == FAIL && count > 1) - return FAIL; - /* - * If end is just past a new-line, we don't want to include - * the first character on the line. - * Put cursor on last char of white. - */ - if (oneleft() == FAIL) - inclusive = FALSE; - } - else - { - if (end_word(1L, bigword, TRUE, TRUE) == FAIL) - return FAIL; - } - } - --count; - } - - if (include_white && (cls() != 0 - || (curwin->w_cursor.col == 0 && !inclusive))) - { - /* - * If we don't include white space at the end, move the start - * to include some white space there. This makes "daw" work - * better on the last word in a sentence (and "2daw" on last-but-one - * word). Also when "2daw" deletes "word." at the end of the line - * (cursor is at start of next line). - * But don't delete white space at start of line (indent). - */ - pos = curwin->w_cursor; // save cursor position - curwin->w_cursor = start_pos; - if (oneleft() == OK) - { - back_in_line(); - if (cls() == 0 && curwin->w_cursor.col > 0) - { - if (VIsual_active) - VIsual = curwin->w_cursor; - else - oap->start = curwin->w_cursor; - } - } - curwin->w_cursor = pos; // put cursor back at end - } - - if (VIsual_active) - { - if (*p_sel == 'e' && inclusive && LTOREQ_POS(VIsual, curwin->w_cursor)) - inc_cursor(); - if (VIsual_mode == 'V') - { - VIsual_mode = 'v'; - redraw_cmdline = TRUE; // show mode later - } - } - else - oap->inclusive = inclusive; - - return OK; -} - -/* - * Find sentence(s) under the cursor, cursor at end. - * When Visual active, extend it by one or more sentences. - */ - int -current_sent(oparg_T *oap, long count, int include) -{ - pos_T start_pos; - pos_T pos; - int start_blank; - int c; - int at_start_sent; - long ncount; - - start_pos = curwin->w_cursor; - pos = start_pos; - findsent(FORWARD, 1L); // Find start of next sentence. - - /* - * When the Visual area is bigger than one character: Extend it. - */ - if (VIsual_active && !EQUAL_POS(start_pos, VIsual)) - { -extend: - if (LT_POS(start_pos, VIsual)) - { - /* - * Cursor at start of Visual area. - * Find out where we are: - * - in the white space before a sentence - * - in a sentence or just after it - * - at the start of a sentence - */ - at_start_sent = TRUE; - decl(&pos); - while (LT_POS(pos, curwin->w_cursor)) - { - c = gchar_pos(&pos); - if (!VIM_ISWHITE(c)) - { - at_start_sent = FALSE; - break; - } - incl(&pos); - } - if (!at_start_sent) - { - findsent(BACKWARD, 1L); - if (EQUAL_POS(curwin->w_cursor, start_pos)) - at_start_sent = TRUE; // exactly at start of sentence - else - // inside a sentence, go to its end (start of next) - findsent(FORWARD, 1L); - } - if (include) // "as" gets twice as much as "is" - count *= 2; - while (count--) - { - if (at_start_sent) - find_first_blank(&curwin->w_cursor); - c = gchar_cursor(); - if (!at_start_sent || (!include && !VIM_ISWHITE(c))) - findsent(BACKWARD, 1L); - at_start_sent = !at_start_sent; - } - } - else - { - /* - * Cursor at end of Visual area. - * Find out where we are: - * - just before a sentence - * - just before or in the white space before a sentence - * - in a sentence - */ - incl(&pos); - at_start_sent = TRUE; - // not just before a sentence - if (!EQUAL_POS(pos, curwin->w_cursor)) - { - at_start_sent = FALSE; - while (LT_POS(pos, curwin->w_cursor)) - { - c = gchar_pos(&pos); - if (!VIM_ISWHITE(c)) - { - at_start_sent = TRUE; - break; - } - incl(&pos); - } - if (at_start_sent) // in the sentence - findsent(BACKWARD, 1L); - else // in/before white before a sentence - curwin->w_cursor = start_pos; - } - - if (include) // "as" gets twice as much as "is" - count *= 2; - findsent_forward(count, at_start_sent); - if (*p_sel == 'e') - ++curwin->w_cursor.col; - } - return OK; - } - - /* - * If the cursor started on a blank, check if it is just before the start - * of the next sentence. - */ - while (c = gchar_pos(&pos), VIM_ISWHITE(c)) // VIM_ISWHITE() is a macro - incl(&pos); - if (EQUAL_POS(pos, curwin->w_cursor)) - { - start_blank = TRUE; - find_first_blank(&start_pos); // go back to first blank - } - else - { - start_blank = FALSE; - findsent(BACKWARD, 1L); - start_pos = curwin->w_cursor; - } - if (include) - ncount = count * 2; - else - { - ncount = count; - if (start_blank) - --ncount; - } - if (ncount > 0) - findsent_forward(ncount, TRUE); - else - decl(&curwin->w_cursor); - - if (include) - { - /* - * If the blank in front of the sentence is included, exclude the - * blanks at the end of the sentence, go back to the first blank. - * If there are no trailing blanks, try to include leading blanks. - */ - if (start_blank) - { - find_first_blank(&curwin->w_cursor); - c = gchar_pos(&curwin->w_cursor); // VIM_ISWHITE() is a macro - if (VIM_ISWHITE(c)) - decl(&curwin->w_cursor); - } - else if (c = gchar_cursor(), !VIM_ISWHITE(c)) - find_first_blank(&start_pos); - } - - if (VIsual_active) - { - // Avoid getting stuck with "is" on a single space before a sentence. - if (EQUAL_POS(start_pos, curwin->w_cursor)) - goto extend; - if (*p_sel == 'e') - ++curwin->w_cursor.col; - VIsual = start_pos; - VIsual_mode = 'v'; - redraw_cmdline = TRUE; // show mode later - redraw_curbuf_later(INVERTED); // update the inversion - } - else - { - // include a newline after the sentence, if there is one - if (incl(&curwin->w_cursor) == -1) - oap->inclusive = TRUE; - else - oap->inclusive = FALSE; - oap->start = start_pos; - oap->motion_type = MCHAR; - } - return OK; -} - -/* - * Find block under the cursor, cursor at end. - * "what" and "other" are two matching parenthesis/brace/etc. - */ - int -current_block( - oparg_T *oap, - long count, - int include, // TRUE == include white space - int what, // '(', '{', etc. - int other) // ')', '}', etc. -{ - pos_T old_pos; - pos_T *pos = NULL; - pos_T start_pos; - pos_T *end_pos; - pos_T old_start, old_end; - char_u *save_cpo; - int sol = FALSE; // '{' at start of line - - old_pos = curwin->w_cursor; - old_end = curwin->w_cursor; // remember where we started - old_start = old_end; - - /* - * If we start on '(', '{', ')', '}', etc., use the whole block inclusive. - */ - if (!VIsual_active || EQUAL_POS(VIsual, curwin->w_cursor)) - { - setpcmark(); - if (what == '{') // ignore indent - while (inindent(1)) - if (inc_cursor() != 0) - break; - if (gchar_cursor() == what) - // cursor on '(' or '{', move cursor just after it - ++curwin->w_cursor.col; - } - else if (LT_POS(VIsual, curwin->w_cursor)) - { - old_start = VIsual; - curwin->w_cursor = VIsual; // cursor at low end of Visual - } - else - old_end = VIsual; - - /* - * Search backwards for unclosed '(', '{', etc.. - * Put this position in start_pos. - * Ignore quotes here. Keep the "M" flag in 'cpo', as that is what the - * user wants. - */ - save_cpo = p_cpo; - p_cpo = (char_u *)(vim_strchr(p_cpo, CPO_MATCHBSL) != NULL ? "%M" : "%"); - while (count-- > 0) - { - if ((pos = findmatch(NULL, what)) == NULL) - break; - curwin->w_cursor = *pos; - start_pos = *pos; // the findmatch for end_pos will overwrite *pos - } - p_cpo = save_cpo; - - /* - * Search for matching ')', '}', etc. - * Put this position in curwin->w_cursor. - */ - if (pos == NULL || (end_pos = findmatch(NULL, other)) == NULL) - { - curwin->w_cursor = old_pos; - return FAIL; - } - curwin->w_cursor = *end_pos; - - /* - * Try to exclude the '(', '{', ')', '}', etc. when "include" is FALSE. - * If the ending '}', ')' or ']' is only preceded by indent, skip that - * indent. But only if the resulting area is not smaller than what we - * started with. - */ - while (!include) - { - incl(&start_pos); - sol = (curwin->w_cursor.col == 0); - decl(&curwin->w_cursor); - while (inindent(1)) - { - sol = TRUE; - if (decl(&curwin->w_cursor) != 0) - break; - } - - /* - * In Visual mode, when the resulting area is not bigger than what we - * started with, extend it to the next block, and then exclude again. - */ - if (!LT_POS(start_pos, old_start) && !LT_POS(old_end, curwin->w_cursor) - && VIsual_active) - { - curwin->w_cursor = old_start; - decl(&curwin->w_cursor); - if ((pos = findmatch(NULL, what)) == NULL) - { - curwin->w_cursor = old_pos; - return FAIL; - } - start_pos = *pos; - curwin->w_cursor = *pos; - if ((end_pos = findmatch(NULL, other)) == NULL) - { - curwin->w_cursor = old_pos; - return FAIL; - } - curwin->w_cursor = *end_pos; - } - else - break; - } - - if (VIsual_active) - { - if (*p_sel == 'e') - inc(&curwin->w_cursor); - if (sol && gchar_cursor() != NUL) - inc(&curwin->w_cursor); // include the line break - VIsual = start_pos; - VIsual_mode = 'v'; - redraw_curbuf_later(INVERTED); // update the inversion - showmode(); - } - else - { - oap->start = start_pos; - oap->motion_type = MCHAR; - oap->inclusive = FALSE; - if (sol) - incl(&curwin->w_cursor); - else if (LTOREQ_POS(start_pos, curwin->w_cursor)) - // Include the character under the cursor. - oap->inclusive = TRUE; - else - // End is before the start (no text in between <>, [], etc.): don't - // operate on any text. - curwin->w_cursor = start_pos; - } - - return OK; -} - -/* - * Return TRUE if the cursor is on a "<aaa>" tag. Ignore "<aaa/>". - * When "end_tag" is TRUE return TRUE if the cursor is on "</aaa>". - */ - static int -in_html_tag( - int end_tag) -{ - char_u *line = ml_get_curline(); - char_u *p; - int c; - int lc = NUL; - pos_T pos; - - if (enc_dbcs) - { - char_u *lp = NULL; - - // We search forward until the cursor, because searching backwards is - // very slow for DBCS encodings. - for (p = line; p < line + curwin->w_cursor.col; MB_PTR_ADV(p)) - if (*p == '>' || *p == '<') - { - lc = *p; - lp = p; - } - if (*p != '<') // check for '<' under cursor - { - if (lc != '<') - return FALSE; - p = lp; - } - } - else - { - for (p = line + curwin->w_cursor.col; p > line; ) - { - if (*p == '<') // find '<' under/before cursor - break; - MB_PTR_BACK(line, p); - if (*p == '>') // find '>' before cursor - break; - } - if (*p != '<') - return FALSE; - } - - pos.lnum = curwin->w_cursor.lnum; - pos.col = (colnr_T)(p - line); - - MB_PTR_ADV(p); - if (end_tag) - // check that there is a '/' after the '<' - return *p == '/'; - - // check that there is no '/' after the '<' - if (*p == '/') - return FALSE; - - // check that the matching '>' is not preceded by '/' - for (;;) - { - if (inc(&pos) < 0) - return FALSE; - c = *ml_get_pos(&pos); - if (c == '>') - break; - lc = c; - } - return lc != '/'; -} - -/* - * Find tag block under the cursor, cursor at end. - */ - int -current_tagblock( - oparg_T *oap, - long count_arg, - int include) // TRUE == include white space -{ - long count = count_arg; - long n; - pos_T old_pos; - pos_T start_pos; - pos_T end_pos; - pos_T old_start, old_end; - char_u *spat, *epat; - char_u *p; - char_u *cp; - int len; - int r; - int do_include = include; - int save_p_ws = p_ws; - int retval = FAIL; - int is_inclusive = TRUE; - - p_ws = FALSE; - - old_pos = curwin->w_cursor; - old_end = curwin->w_cursor; // remember where we started - old_start = old_end; - if (!VIsual_active || *p_sel == 'e') - decl(&old_end); // old_end is inclusive - - /* - * If we start on "<aaa>" select that block. - */ - if (!VIsual_active || EQUAL_POS(VIsual, curwin->w_cursor)) - { - setpcmark(); - - // ignore indent - while (inindent(1)) - if (inc_cursor() != 0) - break; - - if (in_html_tag(FALSE)) - { - // cursor on start tag, move to its '>' - while (*ml_get_cursor() != '>') - if (inc_cursor() < 0) - break; - } - else if (in_html_tag(TRUE)) - { - // cursor on end tag, move to just before it - while (*ml_get_cursor() != '<') - if (dec_cursor() < 0) - break; - dec_cursor(); - old_end = curwin->w_cursor; - } - } - else if (LT_POS(VIsual, curwin->w_cursor)) - { - old_start = VIsual; - curwin->w_cursor = VIsual; // cursor at low end of Visual - } - else - old_end = VIsual; - -again: - /* - * Search backwards for unclosed "<aaa>". - * Put this position in start_pos. - */ - for (n = 0; n < count; ++n) - { - if (do_searchpair((char_u *)"<[^ \t>/!]\\+\\%(\\_s\\_[^>]\\{-}[^/]>\\|$\\|\\_s\\=>\\)", - (char_u *)"", - (char_u *)"</[^>]*>", BACKWARD, NULL, 0, - NULL, (linenr_T)0, 0L) <= 0) - { - curwin->w_cursor = old_pos; - goto theend; - } - } - start_pos = curwin->w_cursor; - - /* - * Search for matching "</aaa>". First isolate the "aaa". - */ - inc_cursor(); - p = ml_get_cursor(); - for (cp = p; *cp != NUL && *cp != '>' && !VIM_ISWHITE(*cp); MB_PTR_ADV(cp)) - ; - len = (int)(cp - p); - if (len == 0) - { - curwin->w_cursor = old_pos; - goto theend; - } - spat = alloc(len + 31); - epat = alloc(len + 9); - if (spat == NULL || epat == NULL) - { - vim_free(spat); - vim_free(epat); - curwin->w_cursor = old_pos; - goto theend; - } - sprintf((char *)spat, "<%.*s\\>\\%%(\\s\\_[^>]\\{-}[^/]>\\|>\\)\\c", len, p); - sprintf((char *)epat, "</%.*s>\\c", len, p); - - r = do_searchpair(spat, (char_u *)"", epat, FORWARD, NULL, - 0, NULL, (linenr_T)0, 0L); - - vim_free(spat); - vim_free(epat); - - if (r < 1 || LT_POS(curwin->w_cursor, old_end)) - { - // Can't find other end or it's before the previous end. Could be a - // HTML tag that doesn't have a matching end. Search backwards for - // another starting tag. - count = 1; - curwin->w_cursor = start_pos; - goto again; - } - - if (do_include) - { - // Include up to the '>'. - while (*ml_get_cursor() != '>') - if (inc_cursor() < 0) - break; - } - else - { - char_u *c = ml_get_cursor(); - - // Exclude the '<' of the end tag. - // If the closing tag is on new line, do not decrement cursor, but - // make operation exclusive, so that the linefeed will be selected - if (*c == '<' && !VIsual_active && curwin->w_cursor.col == 0) - // do not decrement cursor - is_inclusive = FALSE; - else if (*c == '<') - dec_cursor(); - } - end_pos = curwin->w_cursor; - - if (!do_include) - { - // Exclude the start tag. - curwin->w_cursor = start_pos; - while (inc_cursor() >= 0) - if (*ml_get_cursor() == '>') - { - inc_cursor(); - start_pos = curwin->w_cursor; - break; - } - curwin->w_cursor = end_pos; - - // If we are in Visual mode and now have the same text as before set - // "do_include" and try again. - if (VIsual_active && EQUAL_POS(start_pos, old_start) - && EQUAL_POS(end_pos, old_end)) - { - do_include = TRUE; - curwin->w_cursor = old_start; - count = count_arg; - goto again; - } - } - - if (VIsual_active) - { - // If the end is before the start there is no text between tags, select - // the char under the cursor. - if (LT_POS(end_pos, start_pos)) - curwin->w_cursor = start_pos; - else if (*p_sel == 'e') - inc_cursor(); - VIsual = start_pos; - VIsual_mode = 'v'; - redraw_curbuf_later(INVERTED); // update the inversion - showmode(); - } - else - { - oap->start = start_pos; - oap->motion_type = MCHAR; - if (LT_POS(end_pos, start_pos)) - { - // End is before the start: there is no text between tags; operate - // on an empty area. - curwin->w_cursor = start_pos; - oap->inclusive = FALSE; - } - else - oap->inclusive = is_inclusive; - } - retval = OK; - -theend: - p_ws = save_p_ws; - return retval; -} - - int -current_par( - oparg_T *oap, - long count, - int include, // TRUE == include white space - int type) // 'p' for paragraph, 'S' for section -{ - linenr_T start_lnum; - linenr_T end_lnum; - int white_in_front; - int dir; - int start_is_white; - int prev_start_is_white; - int retval = OK; - int do_white = FALSE; - int t; - int i; - - if (type == 'S') // not implemented yet - return FAIL; - - start_lnum = curwin->w_cursor.lnum; - - /* - * When visual area is more than one line: extend it. - */ - if (VIsual_active && start_lnum != VIsual.lnum) - { -extend: - if (start_lnum < VIsual.lnum) - dir = BACKWARD; - else - dir = FORWARD; - for (i = count; --i >= 0; ) - { - if (start_lnum == - (dir == BACKWARD ? 1 : curbuf->b_ml.ml_line_count)) - { - retval = FAIL; - break; - } - - prev_start_is_white = -1; - for (t = 0; t < 2; ++t) - { - start_lnum += dir; - start_is_white = linewhite(start_lnum); - if (prev_start_is_white == start_is_white) - { - start_lnum -= dir; - break; - } - for (;;) - { - if (start_lnum == (dir == BACKWARD - ? 1 : curbuf->b_ml.ml_line_count)) - break; - if (start_is_white != linewhite(start_lnum + dir) - || (!start_is_white - && startPS(start_lnum + (dir > 0 - ? 1 : 0), 0, 0))) - break; - start_lnum += dir; - } - if (!include) - break; - if (start_lnum == (dir == BACKWARD - ? 1 : curbuf->b_ml.ml_line_count)) - break; - prev_start_is_white = start_is_white; - } - } - curwin->w_cursor.lnum = start_lnum; - curwin->w_cursor.col = 0; - return retval; - } - - /* - * First move back to the start_lnum of the paragraph or white lines - */ - white_in_front = linewhite(start_lnum); - while (start_lnum > 1) - { - if (white_in_front) // stop at first white line - { - if (!linewhite(start_lnum - 1)) - break; - } - else // stop at first non-white line of start of paragraph - { - if (linewhite(start_lnum - 1) || startPS(start_lnum, 0, 0)) - break; - } - --start_lnum; - } - - /* - * Move past the end of any white lines. - */ - end_lnum = start_lnum; - while (end_lnum <= curbuf->b_ml.ml_line_count && linewhite(end_lnum)) - ++end_lnum; - - --end_lnum; - i = count; - if (!include && white_in_front) - --i; - while (i--) - { - if (end_lnum == curbuf->b_ml.ml_line_count) - return FAIL; - - if (!include) - do_white = linewhite(end_lnum + 1); - - if (include || !do_white) - { - ++end_lnum; - /* - * skip to end of paragraph - */ - while (end_lnum < curbuf->b_ml.ml_line_count - && !linewhite(end_lnum + 1) - && !startPS(end_lnum + 1, 0, 0)) - ++end_lnum; - } - - if (i == 0 && white_in_front && include) - break; - - /* - * skip to end of white lines after paragraph - */ - if (include || do_white) - while (end_lnum < curbuf->b_ml.ml_line_count - && linewhite(end_lnum + 1)) - ++end_lnum; - } - - /* - * If there are no empty lines at the end, try to find some empty lines at - * the start (unless that has been done already). - */ - if (!white_in_front && !linewhite(end_lnum) && include) - while (start_lnum > 1 && linewhite(start_lnum - 1)) - --start_lnum; - - if (VIsual_active) - { - // Problem: when doing "Vipipip" nothing happens in a single white - // line, we get stuck there. Trap this here. - if (VIsual_mode == 'V' && start_lnum == curwin->w_cursor.lnum) - goto extend; - if (VIsual.lnum != start_lnum) - { - VIsual.lnum = start_lnum; - VIsual.col = 0; - } - VIsual_mode = 'V'; - redraw_curbuf_later(INVERTED); // update the inversion - showmode(); - } - else - { - oap->start.lnum = start_lnum; - oap->start.col = 0; - oap->motion_type = MLINE; - } - curwin->w_cursor.lnum = end_lnum; - curwin->w_cursor.col = 0; - - return OK; -} - -/* - * Search quote char from string line[col]. - * Quote character escaped by one of the characters in "escape" is not counted - * as a quote. - * Returns column number of "quotechar" or -1 when not found. - */ - static int -find_next_quote( - char_u *line, - int col, - int quotechar, - char_u *escape) // escape characters, can be NULL -{ - int c; - - for (;;) - { - c = line[col]; - if (c == NUL) - return -1; - else if (escape != NULL && vim_strchr(escape, c)) - ++col; - else if (c == quotechar) - break; - if (has_mbyte) - col += (*mb_ptr2len)(line + col); - else - ++col; - } - return col; -} - -/* - * Search backwards in "line" from column "col_start" to find "quotechar". - * Quote character escaped by one of the characters in "escape" is not counted - * as a quote. - * Return the found column or zero. - */ - static int -find_prev_quote( - char_u *line, - int col_start, - int quotechar, - char_u *escape) // escape characters, can be NULL -{ - int n; - - while (col_start > 0) - { - --col_start; - col_start -= (*mb_head_off)(line, line + col_start); - n = 0; - if (escape != NULL) - while (col_start - n > 0 && vim_strchr(escape, - line[col_start - n - 1]) != NULL) - ++n; - if (n & 1) - col_start -= n; // uneven number of escape chars, skip it - else if (line[col_start] == quotechar) - break; - } - return col_start; -} - -/* - * Find quote under the cursor, cursor at end. - * Returns TRUE if found, else FALSE. - */ - int -current_quote( - oparg_T *oap, - long count, - int include, // TRUE == include quote char - int quotechar) // Quote character -{ - char_u *line = ml_get_curline(); - int col_end; - int col_start = curwin->w_cursor.col; - int inclusive = FALSE; - int vis_empty = TRUE; // Visual selection <= 1 char - int vis_bef_curs = FALSE; // Visual starts before cursor - int did_exclusive_adj = FALSE; // adjusted pos for 'selection' - int inside_quotes = FALSE; // Looks like "i'" done before - int selected_quote = FALSE; // Has quote inside selection - int i; - int restore_vis_bef = FALSE; // restore VIsual on abort - - // When 'selection' is "exclusive" move the cursor to where it would be - // with 'selection' "inclusive", so that the logic is the same for both. - // The cursor then is moved forward after adjusting the area. - if (VIsual_active) - { - // this only works within one line - if (VIsual.lnum != curwin->w_cursor.lnum) - return FALSE; - - vis_bef_curs = LT_POS(VIsual, curwin->w_cursor); - vis_empty = EQUAL_POS(VIsual, curwin->w_cursor); - if (*p_sel == 'e') - { - if (vis_bef_curs) - { - dec_cursor(); - did_exclusive_adj = TRUE; - } - else if (!vis_empty) - { - dec(&VIsual); - did_exclusive_adj = TRUE; - } - vis_empty = EQUAL_POS(VIsual, curwin->w_cursor); - if (!vis_bef_curs && !vis_empty) - { - // VIsual needs to be the start of Visual selection. - pos_T t = curwin->w_cursor; - - curwin->w_cursor = VIsual; - VIsual = t; - vis_bef_curs = TRUE; - restore_vis_bef = TRUE; - } - } - } - - if (!vis_empty) - { - // Check if the existing selection exactly spans the text inside - // quotes. - if (vis_bef_curs) - { - inside_quotes = VIsual.col > 0 - && line[VIsual.col - 1] == quotechar - && line[curwin->w_cursor.col] != NUL - && line[curwin->w_cursor.col + 1] == quotechar; - i = VIsual.col; - col_end = curwin->w_cursor.col; - } - else - { - inside_quotes = curwin->w_cursor.col > 0 - && line[curwin->w_cursor.col - 1] == quotechar - && line[VIsual.col] != NUL - && line[VIsual.col + 1] == quotechar; - i = curwin->w_cursor.col; - col_end = VIsual.col; - } - - // Find out if we have a quote in the selection. - while (i <= col_end) - if (line[i++] == quotechar) - { - selected_quote = TRUE; - break; - } - } - - if (!vis_empty && line[col_start] == quotechar) - { - // Already selecting something and on a quote character. Find the - // next quoted string. - if (vis_bef_curs) - { - // Assume we are on a closing quote: move to after the next - // opening quote. - col_start = find_next_quote(line, col_start + 1, quotechar, NULL); - if (col_start < 0) - goto abort_search; - col_end = find_next_quote(line, col_start + 1, quotechar, - curbuf->b_p_qe); - if (col_end < 0) - { - // We were on a starting quote perhaps? - col_end = col_start; - col_start = curwin->w_cursor.col; - } - } - else - { - col_end = find_prev_quote(line, col_start, quotechar, NULL); - if (line[col_end] != quotechar) - goto abort_search; - col_start = find_prev_quote(line, col_end, quotechar, - curbuf->b_p_qe); - if (line[col_start] != quotechar) - { - // We were on an ending quote perhaps? - col_start = col_end; - col_end = curwin->w_cursor.col; - } - } - } - else - - if (line[col_start] == quotechar || !vis_empty) - { - int first_col = col_start; - - if (!vis_empty) - { - if (vis_bef_curs) - first_col = find_next_quote(line, col_start, quotechar, NULL); - else - first_col = find_prev_quote(line, col_start, quotechar, NULL); - } - - // The cursor is on a quote, we don't know if it's the opening or - // closing quote. Search from the start of the line to find out. - // Also do this when there is a Visual area, a' may leave the cursor - // in between two strings. - col_start = 0; - for (;;) - { - // Find open quote character. - col_start = find_next_quote(line, col_start, quotechar, NULL); - if (col_start < 0 || col_start > first_col) - goto abort_search; - // Find close quote character. - col_end = find_next_quote(line, col_start + 1, quotechar, - curbuf->b_p_qe); - if (col_end < 0) - goto abort_search; - // If is cursor between start and end quote character, it is - // target text object. - if (col_start <= first_col && first_col <= col_end) - break; - col_start = col_end + 1; - } - } - else - { - // Search backward for a starting quote. - col_start = find_prev_quote(line, col_start, quotechar, curbuf->b_p_qe); - if (line[col_start] != quotechar) - { - // No quote before the cursor, look after the cursor. - col_start = find_next_quote(line, col_start, quotechar, NULL); - if (col_start < 0) - goto abort_search; - } - - // Find close quote character. - col_end = find_next_quote(line, col_start + 1, quotechar, - curbuf->b_p_qe); - if (col_end < 0) - goto abort_search; - } - - // When "include" is TRUE, include spaces after closing quote or before - // the starting quote. - if (include) - { - if (VIM_ISWHITE(line[col_end + 1])) - while (VIM_ISWHITE(line[col_end + 1])) - ++col_end; - else - while (col_start > 0 && VIM_ISWHITE(line[col_start - 1])) - --col_start; - } - - // Set start position. After vi" another i" must include the ". - // For v2i" include the quotes. - if (!include && count < 2 && (vis_empty || !inside_quotes)) - ++col_start; - curwin->w_cursor.col = col_start; - if (VIsual_active) - { - // Set the start of the Visual area when the Visual area was empty, we - // were just inside quotes or the Visual area didn't start at a quote - // and didn't include a quote. - if (vis_empty - || (vis_bef_curs - && !selected_quote - && (inside_quotes - || (line[VIsual.col] != quotechar - && (VIsual.col == 0 - || line[VIsual.col - 1] != quotechar))))) - { - VIsual = curwin->w_cursor; - redraw_curbuf_later(INVERTED); - } - } - else - { - oap->start = curwin->w_cursor; - oap->motion_type = MCHAR; - } - - // Set end position. - curwin->w_cursor.col = col_end; - if ((include || count > 1 // After vi" another i" must include the ". - || (!vis_empty && inside_quotes) - ) && inc_cursor() == 2) - inclusive = TRUE; - if (VIsual_active) - { - if (vis_empty || vis_bef_curs) - { - // decrement cursor when 'selection' is not exclusive - if (*p_sel != 'e') - dec_cursor(); - } - else - { - // Cursor is at start of Visual area. Set the end of the Visual - // area when it was just inside quotes or it didn't end at a - // quote. - if (inside_quotes - || (!selected_quote - && line[VIsual.col] != quotechar - && (line[VIsual.col] == NUL - || line[VIsual.col + 1] != quotechar))) - { - dec_cursor(); - VIsual = curwin->w_cursor; - } - curwin->w_cursor.col = col_start; - } - if (VIsual_mode == 'V') - { - VIsual_mode = 'v'; - redraw_cmdline = TRUE; // show mode later - } - } - else - { - // Set inclusive and other oap's flags. - oap->inclusive = inclusive; - } - - return OK; - -abort_search: - if (VIsual_active && *p_sel == 'e') - { - if (did_exclusive_adj) - inc_cursor(); - if (restore_vis_bef) - { - pos_T t = curwin->w_cursor; - - curwin->w_cursor = VIsual; - VIsual = t; - } - } - return FALSE; -} - -#endif // FEAT_TEXTOBJ - /* * Check if the pattern is zero-width. * If move is TRUE, check from the beginning of the buffer, else from position diff --git a/src/textobject.c b/src/textobject.c new file mode 100644 index 0000000000..e876d528d7 --- /dev/null +++ b/src/textobject.c @@ -0,0 +1,1965 @@ +/* vi:set ts=8 sts=4 sw=4 noet: + * + * VIM - Vi IMproved by Bram Moolenaar + * + * Do ":help uganda" in Vim to read copying and usage conditions. + * Do ":help credits" in Vim to see a list of people who contributed. + * See README.txt for an overview of the Vim source code. + */ + +/* + * textobject.c: functions for text objects + */ +#include "vim.h" + +static int cls(void); +static int skip_chars(int, int); + +/* + * Find the start of the next sentence, searching in the direction specified + * by the "dir" argument. The cursor is positioned on the start of the next + * sentence when found. If the next sentence is found, return OK. Return FAIL + * otherwise. See ":h sentence" for the precise definition of a "sentence" + * text object. + */ + int +findsent(int dir, long count) +{ + pos_T pos, tpos; + int c; + int (*func)(pos_T *); + int startlnum; + int noskip = FALSE; // do not skip blanks + int cpo_J; + int found_dot; + + pos = curwin->w_cursor; + if (dir == FORWARD) + func = incl; + else + func = decl; + + while (count--) + { + /* + * if on an empty line, skip up to a non-empty line + */ + if (gchar_pos(&pos) == NUL) + { + do + if ((*func)(&pos) == -1) + break; + while (gchar_pos(&pos) == NUL); + if (dir == FORWARD) + goto found; + } + /* + * if on the start of a paragraph or a section and searching forward, + * go to the next line + */ + else if (dir == FORWARD && pos.col == 0 && + startPS(pos.lnum, NUL, FALSE)) + { + if (pos.lnum == curbuf->b_ml.ml_line_count) + return FAIL; + ++pos.lnum; + goto found; + } + else if (dir == BACKWARD) + decl(&pos); + + // go back to the previous non-white non-punctuation character + found_dot = FALSE; + while (c = gchar_pos(&pos), VIM_ISWHITE(c) + || vim_strchr((char_u *)".!?)]\"'", c) != NULL) + { + tpos = pos; + if (decl(&tpos) == -1 || (LINEEMPTY(tpos.lnum) && dir == FORWARD)) + break; + + if (found_dot) + break; + if (vim_strchr((char_u *) ".!?", c) != NULL) + found_dot = TRUE; + + if (vim_strchr((char_u *) ")]\"'", c) != NULL + && vim_strchr((char_u *) ".!?)]\"'", gchar_pos(&tpos)) == NULL) + break; + + decl(&pos); + } + + // remember the line where the search started + startlnum = pos.lnum; + cpo_J = vim_strchr(p_cpo, CPO_ENDOFSENT) != NULL; + + for (;;) // find end of sentence + { + c = gchar_pos(&pos); + if (c == NUL || (pos.col == 0 && startPS(pos.lnum, NUL, FALSE))) + { + if (dir == BACKWARD && pos.lnum != startlnum) + ++pos.lnum; + break; + } + if (c == '.' || c == '!' || c == '?') + { + tpos = pos; + do + if ((c = inc(&tpos)) == -1) + break; + while (vim_strchr((char_u *)")]\"'", c = gchar_pos(&tpos)) + != NULL); + if (c == -1 || (!cpo_J && (c == ' ' || c == '\t')) || c == NUL + || (cpo_J && (c == ' ' && inc(&tpos) >= 0 + && gchar_pos(&tpos) == ' '))) + { + pos = tpos; + if (gchar_pos(&pos) == NUL) // skip NUL at EOL + inc(&pos); + break; + } + } + if ((*func)(&pos) == -1) + { + if (count) + return FAIL; + noskip = TRUE; + break; + } + } +found: + // skip white space + while (!noskip && ((c = gchar_pos(&pos)) == ' ' || c == '\t')) + if (incl(&pos) == -1) + break; + } + + setpcmark(); + curwin->w_cursor = pos; + return OK; +} + +/* + * Find the next paragraph or section in direction 'dir'. + * Paragraphs are currently supposed to be separated by empty lines. + * If 'what' is NUL we go to the next paragraph. + * If 'what' is '{' or '}' we go to the next section. + * If 'both' is TRUE also stop at '}'. + * Return TRUE if the next paragraph or section was found. + */ + int +findpar( + int *pincl, // Return: TRUE if last char is to be included + int dir, + long count, + int what, + int both) +{ + linenr_T curr; + int did_skip; // TRUE after separating lines have been skipped + int first; // TRUE on first line + int posix = (vim_strchr(p_cpo, CPO_PARA) != NULL); +#ifdef FEAT_FOLDING + linenr_T fold_first; // first line of a closed fold + linenr_T fold_last; // last line of a closed fold + int fold_skipped; // TRUE if a closed fold was skipped this + // iteration +#endif + + curr = curwin->w_cursor.lnum; + + while (count--) + { + did_skip = FALSE; + for (first = TRUE; ; first = FALSE) + { + if (*ml_get(curr) != NUL) + did_skip = TRUE; + +#ifdef FEAT_FOLDING + // skip folded lines + fold_skipped = FALSE; + if (first && hasFolding(curr, &fold_first, &fold_last)) + { + curr = ((dir > 0) ? fold_last : fold_first) + dir; + fold_skipped = TRUE; + } +#endif + + // POSIX has its own ideas of what a paragraph boundary is and it + // doesn't match historical Vi: It also stops at a "{" in the + // first column and at an empty line. + if (!first && did_skip && (startPS(curr, what, both) + || (posix && what == NUL && *ml_get(curr) == '{'))) + break; + +#ifdef FEAT_FOLDING + if (fold_skipped) + curr -= dir; +#endif + if ((curr += dir) < 1 || curr > curbuf->b_ml.ml_line_count) + { + if (count) + return FALSE; + curr -= dir; + break; + } + } + } + setpcmark(); + if (both && *ml_get(curr) == '}') // include line with '}' + ++curr; + curwin->w_cursor.lnum = curr; + if (curr == curbuf->b_ml.ml_line_count && what != '}') + { + char_u *line = ml_get(curr); + + // Put the cursor on the last character in the last line and make the + // motion inclusive. + if ((curwin->w_cursor.col = (colnr_T)STRLEN(line)) != 0) + { + --curwin->w_cursor.col; + curwin->w_cursor.col -= + (*mb_head_off)(line, line + curwin->w_cursor.col); + *pincl = TRUE; + } + } + else + curwin->w_cursor.col = 0; + return TRUE; +} + +/* + * check if the string 's' is a nroff macro that is in option 'opt' + */ + static int +inmacro(char_u *opt, char_u *s) +{ + char_u *macro; + + for (macro = opt; macro[0]; ++macro) + { + // Accept two characters in the option being equal to two characters + // in the line. A space in the option matches with a space in the + // line or the line having ended. + if ( (macro[0] == s[0] + || (macro[0] == ' ' + && (s[0] == NUL || s[0] == ' '))) + && (macro[1] == s[1] + || ((macro[1] == NUL || macro[1] == ' ') + && (s[0] == NUL || s[1] == NUL || s[1] == ' ')))) + break; + ++macro; + if (macro[0] == NUL) + break; + } + return (macro[0] != NUL); +} + +/* + * startPS: return TRUE if line 'lnum' is the start of a section or paragraph. + * If 'para' is '{' or '}' only check for sections. + * If 'both' is TRUE also stop at '}' + */ + int +startPS(linenr_T lnum, int para, int both) +{ + char_u *s; + + s = ml_get(lnum); + if (*s == para || *s == '\f' || (both && *s == '}')) + return TRUE; + if (*s == '.' && (inmacro(p_sections, s + 1) || + (!para && inmacro(p_para, s + 1)))) + return TRUE; + return FALSE; +} + +/* + * The following routines do the word searches performed by the 'w', 'W', + * 'b', 'B', 'e', and 'E' commands. + */ + +/* + * To perform these searches, characters are placed into one of three + * classes, and transitions between classes determine word boundaries. + * + * The classes are: + * + * 0 - white space + * 1 - punctuation + * 2 or higher - keyword characters (letters, digits and underscore) + */ + +static int cls_bigword; // TRUE for "W", "B" or "E" + +/* + * cls() - returns the class of character at curwin->w_cursor + * + * If a 'W', 'B', or 'E' motion is being done (cls_bigword == TRUE), chars + * from class 2 and higher are reported as class 1 since only white space + * boundaries are of interest. + */ + static int +cls(void) +{ + int c; + + c = gchar_cursor(); + if (c == ' ' || c == '\t' || c == NUL) + return 0; + if (enc_dbcs != 0 && c > 0xFF) + { + // If cls_bigword, report multi-byte chars as class 1. + if (enc_dbcs == DBCS_KOR && cls_bigword) + return 1; + + // process code leading/trailing bytes + return dbcs_class(((unsigned)c >> 8), (c & 0xFF)); + } + if (enc_utf8) + { + c = utf_class(c); + if (c != 0 && cls_bigword) + return 1; + return c; + } + + // If cls_bigword is TRUE, report all non-blanks as class 1. + if (cls_bigword) + return 1; + + if (vim_iswordc(c)) + return 2; + return 1; +} + + +/* + * fwd_word(count, type, eol) - move forward one word + * + * Returns FAIL if the cursor was already at the end of the file. + * If eol is TRUE, last word stops at end of line (for operators). + */ + int +fwd_word( + long count, + int bigword, // "W", "E" or "B" + int eol) +{ + int sclass; // starting class + int i; + int last_line; + + curwin->w_cursor.coladd = 0; + cls_bigword = bigword; + while (--count >= 0) + { +#ifdef FEAT_FOLDING + // When inside a range of folded lines, move to the last char of the + // last line. + if (hasFolding(curwin->w_cursor.lnum, NULL, &curwin->w_cursor.lnum)) + coladvance((colnr_T)MAXCOL); +#endif + sclass = cls(); + + /* + * We always move at least one character, unless on the last + * character in the buffer. + */ + last_line = (curwin->w_cursor.lnum == curbuf->b_ml.ml_line_count); + i = inc_cursor(); + if (i == -1 || (i >= 1 && last_line)) // started at last char in file + return FAIL; + if (i >= 1 && eol && count == 0) // started at last char in line + return OK; + + /* + * Go one char past end of current word (if any) + */ + if (sclass != 0) + while (cls() == sclass) + { + i = inc_cursor(); + if (i == -1 || (i >= 1 && eol && count == 0)) + return OK; + } + + /* + * go to next non-white + */ + while (cls() == 0) + { + /* + * We'll stop if we land on a blank line + */ + if (curwin->w_cursor.col == 0 && *ml_get_curline() == NUL) + break; + + i = inc_cursor(); + if (i == -1 || (i >= 1 && eol && count == 0)) + return OK; + } + } + return OK; +} + +/* + * bck_word() - move backward 'count' words + * + * If stop is TRUE and we are already on the start of a word, move one less. + * + * Returns FAIL if top of the file was reached. + */ + int +bck_word(long count, int bigword, int stop) +{ + int sclass; // starting class + + curwin->w_cursor.coladd = 0; + cls_bigword = bigword; + while (--count >= 0) + { +#ifdef FEAT_FOLDING + // When inside a range of folded lines, move to the first char of the + // first line. + if (hasFolding(curwin->w_cursor.lnum, &curwin->w_cursor.lnum, NULL)) + curwin->w_cursor.col = 0; +#endif + sclass = cls(); + if (dec_cursor() == -1) // started at start of file + return FAIL; + + if (!stop || sclass == cls() || sclass == 0) + { + /* + * Skip white space before the word. + * Stop on an empty line. + */ + while (cls() == 0) + { + if (curwin->w_cursor.col == 0 + && LINEEMPTY(curwin->w_cursor.lnum)) + goto finished; + if (dec_cursor() == -1) // hit start of file, stop here + return OK; + } + + /* + * Move backward to start of this word. + */ + if (skip_chars(cls(), BACKWARD)) + return OK; + } + + inc_cursor(); // overshot - forward one +finished: + stop = FALSE; + } + return OK; +} + +/* + * end_word() - move to the end of the word + * + * There is an apparent bug in the 'e' motion of the real vi. At least on the + * System V Release 3 version for the 80386. Unlike 'b' and 'w', the 'e' + * motion crosses blank lines. When the real vi crosses a blank line in an + * 'e' motion, the cursor is placed on the FIRST character of the next + * non-blank line. The 'E' command, however, works correctly. Since this + * appears to be a bug, I have not duplicated it here. + * + * Returns FAIL if end of the file was reached. + * + * If stop is TRUE and we are already on the end of a word, move one less. + * If empty is TRUE stop on an empty line. + */ + int +end_word( + long count, + int bigword, + int stop, + int empty) +{ + int sclass; // starting class + + curwin->w_cursor.coladd = 0; + cls_bigword = bigword; + while (--count >= 0) + { +#ifdef FEAT_FOLDING + // When inside a range of folded lines, move to the last char of the + // last line. + if (hasFolding(curwin->w_cursor.lnum, NULL, &curwin->w_cursor.lnum)) + coladvance((colnr_T)MAXCOL); +#endif + sclass = cls(); + if (inc_cursor() == -1) + return FAIL; + + /* + * If we're in the middle of a word, we just have to move to the end + * of it. + */ + if (cls() == sclass && sclass != 0) + { + /* + * Move forward to end of the current word + */ + if (skip_chars(sclass, FORWARD)) + return FAIL; + } + else if (!stop || sclass == 0) + { + /* + * We were at the end of a word. Go to the end of the next word. + * First skip white space, if 'empty' is TRUE, stop at empty line. + */ + while (cls() == 0) + { + if (empty && curwin->w_cursor.col == 0 + && LINEEMPTY(curwin->w_cursor.lnum)) + goto finished; + if (inc_cursor() == -1) // hit end of file, stop here + return FAIL; + } + + /* + * Move forward to the end of this word. + */ + if (skip_chars(cls(), FORWARD)) + return FAIL; + } + dec_cursor(); // overshot - one char backward +finished: + stop = FALSE; // we move only one word less + } + return OK; +} + +/* + * Move back to the end of the word. + * + * Returns FAIL if start of the file was reached. + */ + int +bckend_word( + long count, + int bigword, // TRUE for "B" + int eol) // TRUE: stop at end of line. +{ + int sclass; // starting class + int i; + + curwin->w_cursor.coladd = 0; + cls_bigword = bigword; + while (--count >= 0) + { + sclass = cls(); + if ((i = dec_cursor()) == -1) + return FAIL; + if (eol && i == 1) + return OK; + + /* + * Move backward to before the start of this word. + */ + if (sclass != 0) + { + while (cls() == sclass) + if ((i = dec_cursor()) == -1 || (eol && i == 1)) + return OK; + } + + /* + * Move backward to end of the previous word + */ + while (cls() == 0) + { + if (curwin->w_cursor.col == 0 && LINEEMPTY(curwin->w_cursor.lnum)) + break; + if ((i = dec_cursor()) == -1 || (eol && i == 1)) + return OK; + } + } + return OK; +} + +/* + * Skip a row of characters of the same class. + * Return TRUE when end-of-file reached, FALSE otherwise. + */ + static int +skip_chars(int cclass, int dir) +{ + while (cls() == cclass) + if ((dir == FORWARD ? inc_cursor() : dec_cursor()) == -1) + return TRUE; + return FALSE; +} + +#if defined(FEAT_TEXTOBJ) || defined(PROTO) +/* + * Go back to the start of the word or the start of white space + */ + static void +back_in_line(void) +{ + int sclass; // starting class + + sclass = cls(); + for (;;) + { + if (curwin->w_cursor.col == 0) // stop at start of line + break; + dec_cursor(); + if (cls() != sclass) // stop at start of word + { + inc_cursor(); + break; + } + } +} + + static void +find_first_blank(pos_T *posp) +{ + int c; + + while (decl(posp) != -1) + { + c = gchar_pos(posp); + if (!VIM_ISWHITE(c)) + { + incl(posp); + break; + } + } +} + +/* + * Skip count/2 sentences and count/2 separating white spaces. + */ + static void +findsent_forward( + long count, + int at_start_sent) // cursor is at start of sentence +{ + while (count--) + { + findsent(FORWARD, 1L); + if (at_start_sent) + find_first_blank(&curwin->w_cursor); + if (count == 0 || at_start_sent) + decl(&curwin->w_cursor); + at_start_sent = !at_start_sent; + } +} + +/* + * Find word under cursor, cursor at end. + * Used while an operator is pending, and in Visual mode. + */ + int +current_word( + oparg_T *oap, + long count, + int include, // TRUE: include word and white space + int bigword) // FALSE == word, TRUE == WORD +{ + pos_T start_pos; + pos_T pos; + int inclusive = TRUE; + int include_white = FALSE; + + cls_bigword = bigword; + CLEAR_POS(&start_pos); + + // Correct cursor when 'selection' is exclusive + if (VIsual_active && *p_sel == 'e' && LT_POS(VIsual, curwin->w_cursor)) + dec_cursor(); + + /* + * When Visual mode is not active, or when the VIsual area is only one + * character, select the word and/or white space under the cursor. + */ + if (!VIsual_active || EQUAL_POS(curwin->w_cursor, VIsual)) + { + /* + * Go to start of current word or white space. + */ + back_in_line(); + start_pos = curwin->w_cursor; + + /* + * If the start is on white space, and white space should be included + * (" word"), or start is not on white space, and white space should + * not be included ("word"), find end of word. + */ + if ((cls() == 0) == include) + { + if (end_word(1L, bigword, TRUE, TRUE) == FAIL) + return FAIL; + } + else + { + /* + * If the start is not on white space, and white space should be + * included ("word "), or start is on white space and white + * space should not be included (" "), find start of word. + * If we end up in the first column of the next line (single char + * word) back up to end of the line. + */ + fwd_word(1L, bigword, TRUE); + if (curwin->w_cursor.col == 0) + decl(&curwin->w_cursor); + else + oneleft(); + + if (include) + include_white = TRUE; + } + + if (VIsual_active) + { + // should do something when inclusive == FALSE ! + VIsual = start_pos; + redraw_curbuf_later(INVERTED); // update the inversion + } + else + { + oap->start = start_pos; + oap->motion_type = MCHAR; + } + --count; + } + + /* + * When count is still > 0, extend with more objects. + */ + while (count > 0) + { + inclusive = TRUE; + if (VIsual_active && LT_POS(curwin->w_cursor, VIsual)) + { + /* + * In Visual mode, with cursor at start: move cursor back. + */ + if (decl(&curwin->w_cursor) == -1) + return FAIL; + if (include != (cls() != 0)) + { + if (bck_word(1L, bigword, TRUE) == FAIL) + return FAIL; + } + else + { + if (bckend_word(1L, bigword, TRUE) == FAIL) + return FAIL; + (void)incl(&curwin->w_cursor); + } + } + else + { + /* + * Move cursor forward one word and/or white area. + */ + if (incl(&curwin->w_cursor) == -1) + return FAIL; + if (include != (cls() == 0)) + { + if (fwd_word(1L, bigword, TRUE) == FAIL && count > 1) + return FAIL; + /* + * If end is just past a new-line, we don't want to include + * the first character on the line. + * Put cursor on last char of white. + */ + if (oneleft() == FAIL) + inclusive = FALSE; + } + else + { + if (end_word(1L, bigword, TRUE, TRUE) == FAIL) + return FAIL; + } + } + --count; + } + + if (include_white && (cls() != 0 + || (curwin->w_cursor.col == 0 && !inclusive))) + { + /* + * If we don't include white space at the end, move the start + * to include some white space there. This makes "daw" work + * better on the last word in a sentence (and "2daw" on last-but-one + * word). Also when "2daw" deletes "word." at the end of the line + * (cursor is at start of next line). + * But don't delete white space at start of line (indent). + */ + pos = curwin->w_cursor; // save cursor position + curwin->w_cursor = start_pos; + if (oneleft() == OK) + { + back_in_line(); + if (cls() == 0 && curwin->w_cursor.col > 0) + { + if (VIsual_active) + VIsual = curwin->w_cursor; + else + oap->start = curwin->w_cursor; + } + } + curwin->w_cursor = pos; // put cursor back at end + } + + if (VIsual_active) + { + if (*p_sel == 'e' && inclusive && LTOREQ_POS(VIsual, curwin->w_cursor)) + inc_cursor(); + if (VIsual_mode == 'V') + { + VIsual_mode = 'v'; + redraw_cmdline = TRUE; // show mode later + } + } + else + oap->inclusive = inclusive; + + return OK; +} + +/* + * Find sentence(s) under the cursor, cursor at end. + * When Visual active, extend it by one or more sentences. + */ + int +current_sent(oparg_T *oap, long count, int include) +{ + pos_T start_pos; + pos_T pos; + int start_blank; + int c; + int at_start_sent; + long ncount; + + start_pos = curwin->w_cursor; + pos = start_pos; + findsent(FORWARD, 1L); // Find start of next sentence. + + /* + * When the Visual area is bigger than one character: Extend it. + */ + if (VIsual_active && !EQUAL_POS(start_pos, VIsual)) + { +extend: + if (LT_POS(start_pos, VIsual)) + { + /* + * Cursor at start of Visual area. + * Find out where we are: + * - in the white space before a sentence + * - in a sentence or just after it + * - at the start of a sentence + */ + at_start_sent = TRUE; + decl(&pos); + while (LT_POS(pos, curwin->w_cursor)) + { + c = gchar_pos(&pos); + if (!VIM_ISWHITE(c)) + { + at_start_sent = FALSE; + break; + } + incl(&pos); + } + if (!at_start_sent) + { + findsent(BACKWARD, 1L); + if (EQUAL_POS(curwin->w_cursor, start_pos)) + at_start_sent = TRUE; // exactly at start of sentence + else + // inside a sentence, go to its end (start of next) + findsent(FORWARD, 1L); + } + if (include) // "as" gets twice as much as "is" + count *= 2; + while (count--) + { + if (at_start_sent) + find_first_blank(&curwin->w_cursor); + c = gchar_cursor(); + if (!at_start_sent || (!include && !VIM_ISWHITE(c))) + findsent(BACKWARD, 1L); + at_start_sent = !at_start_sent; + } + } + else + { + /* + * Cursor at end of Visual area. + * Find out where we are: + * - just before a sentence + * - just before or in the white space before a sentence + * - in a sentence + */ + incl(&pos); + at_start_sent = TRUE; + // not just before a sentence + if (!EQUAL_POS(pos, curwin->w_cursor)) + { + at_start_sent = FALSE; + while (LT_POS(pos, curwin->w_cursor)) + { + c = gchar_pos(&pos); + if (!VIM_ISWHITE(c)) + { + at_start_sent = TRUE; + break; + } + incl(&pos); + } + if (at_start_sent) // in the sentence + findsent(BACKWARD, 1L); + else // in/before white before a sentence + curwin->w_cursor = start_pos; + } + + if (include) // "as" gets twice as much as "is" + count *= 2; + findsent_forward(count, at_start_sent); + if (*p_sel == 'e') + ++curwin->w_cursor.col; + } + return OK; + } + + /* + * If the cursor started on a blank, check if it is just before the start + * of the next sentence. + */ + while (c = gchar_pos(&pos), VIM_ISWHITE(c)) // VIM_ISWHITE() is a macro + incl(&pos); + if (EQUAL_POS(pos, curwin->w_cursor)) + { + start_blank = TRUE; + find_first_blank(&start_pos); // go back to first blank + } + else + { + start_blank = FALSE; + findsent(BACKWARD, 1L); + start_pos = curwin->w_cursor; + } + if (include) + ncount = count * 2; + else + { + ncount = count; + if (start_blank) + --ncount; + } + if (ncount > 0) + findsent_forward(ncount, TRUE); + else + decl(&curwin->w_cursor); + + if (include) + { + /* + * If the blank in front of the sentence is included, exclude the + * blanks at the end of the sentence, go back to the first blank. + * If there are no trailing blanks, try to include leading blanks. + */ + if (start_blank) + { + find_first_blank(&curwin->w_cursor); + c = gchar_pos(&curwin->w_cursor); // VIM_ISWHITE() is a macro + if (VIM_ISWHITE(c)) + decl(&curwin->w_cursor); + } + else if (c = gchar_cursor(), !VIM_ISWHITE(c)) + find_first_blank(&start_pos); + } + + if (VIsual_active) + { + // Avoid getting stuck with "is" on a single space before a sentence. + if (EQUAL_POS(start_pos, curwin->w_cursor)) + goto extend; + if (*p_sel == 'e') + ++curwin->w_cursor.col; + VIsual = start_pos; + VIsual_mode = 'v'; + redraw_cmdline = TRUE; // show mode later + redraw_curbuf_later(INVERTED); // update the inversion + } + else + { + // include a newline after the sentence, if there is one + if (incl(&curwin->w_cursor) == -1) + oap->inclusive = TRUE; + else + oap->inclusive = FALSE; + oap->start = start_pos; + oap->motion_type = MCHAR; + } + return OK; +} + +/* + * Find block under the cursor, cursor at end. + * "what" and "other" are two matching parenthesis/brace/etc. + */ + int +current_block( + oparg_T *oap, + long count, + int include, // TRUE == include white space + int what, // '(', '{', etc. + int other) // ')', '}', etc. +{ + pos_T old_pos; + pos_T *pos = NULL; + pos_T start_pos; + pos_T *end_pos; + pos_T old_start, old_end; + char_u *save_cpo; + int sol = FALSE; // '{' at start of line + + old_pos = curwin->w_cursor; + old_end = curwin->w_cursor; // remember where we started + old_start = old_end; + + /* + * If we start on '(', '{', ')', '}', etc., use the whole block inclusive. + */ + if (!VIsual_active || EQUAL_POS(VIsual, curwin->w_cursor)) + { + setpcmark(); + if (what == '{') // ignore indent + while (inindent(1)) + if (inc_cursor() != 0) + break; + if (gchar_cursor() == what) + // cursor on '(' or '{', move cursor just after it + ++curwin->w_cursor.col; + } + else if (LT_POS(VIsual, curwin->w_cursor)) + { + old_start = VIsual; + curwin->w_cursor = VIsual; // cursor at low end of Visual + } + else + old_end = VIsual; + + /* + * Search backwards for unclosed '(', '{', etc.. + * Put this position in start_pos. + * Ignore quotes here. Keep the "M" flag in 'cpo', as that is what the + * user wants. + */ + save_cpo = p_cpo; + p_cpo = (char_u *)(vim_strchr(p_cpo, CPO_MATCHBSL) != NULL ? "%M" : "%"); + while (count-- > 0) + { + if ((pos = findmatch(NULL, what)) == NULL) + break; + curwin->w_cursor = *pos; + start_pos = *pos; // the findmatch for end_pos will overwrite *pos + } + p_cpo = save_cpo; + + /* + * Search for matching ')', '}', etc. + * Put this position in curwin->w_cursor. + */ + if (pos == NULL || (end_pos = findmatch(NULL, other)) == NULL) + { + curwin->w_cursor = old_pos; + return FAIL; + } + curwin->w_cursor = *end_pos; + + /* + * Try to exclude the '(', '{', ')', '}', etc. when "include" is FALSE. + * If the ending '}', ')' or ']' is only preceded by indent, skip that + * indent. But only if the resulting area is not smaller than what we + * started with. + */ + while (!include) + { + incl(&start_pos); + sol = (curwin->w_cursor.col == 0); + decl(&curwin->w_cursor); + while (inindent(1)) + { + sol = TRUE; + if (decl(&curwin->w_cursor) != 0) + break; + } + + /* + * In Visual mode, when the resulting area is not bigger than what we + * started with, extend it to the next block, and then exclude again. + */ + if (!LT_POS(start_pos, old_start) && !LT_POS(old_end, curwin->w_cursor) + && VIsual_active) + { + curwin->w_cursor = old_start; + decl(&curwin->w_cursor); + if ((pos = findmatch(NULL, what)) == NULL) + { + curwin->w_cursor = old_pos; + return FAIL; + } + start_pos = *pos; + curwin->w_cursor = *pos; + if ((end_pos = findmatch(NULL, other)) == NULL) + { + curwin->w_cursor = old_pos; + return FAIL; + } + curwin->w_cursor = *end_pos; + } + else + break; + } + + if (VIsual_active) + { + if (*p_sel == 'e') + inc(&curwin->w_cursor); + if (sol && gchar_cursor() != NUL) + inc(&curwin->w_cursor); // include the line break + VIsual = start_pos; + VIsual_mode = 'v'; + redraw_curbuf_later(INVERTED); // update the inversion + showmode(); + } + else + { + oap->start = start_pos; + oap->motion_type = MCHAR; + oap->inclusive = FALSE; + if (sol) + incl(&curwin->w_cursor); + else if (LTOREQ_POS(start_pos, curwin->w_cursor)) + // Include the character under the cursor. + oap->inclusive = TRUE; + else + // End is before the start (no text in between <>, [], etc.): don't + // operate on any text. + curwin->w_cursor = start_pos; + } + + return OK; +} + +/* + * Return TRUE if the cursor is on a "<aaa>" tag. Ignore "<aaa/>". + * When "end_tag" is TRUE return TRUE if the cursor is on "</aaa>". + */ + static int +in_html_tag( + int end_tag) +{ + char_u *line = ml_get_curline(); + char_u *p; + int c; + int lc = NUL; + pos_T pos; + + if (enc_dbcs) + { + char_u *lp = NULL; + + // We search forward until the cursor, because searching backwards is + // very slow for DBCS encodings. + for (p = line; p < line + curwin->w_cursor.col; MB_PTR_ADV(p)) + if (*p == '>' || *p == '<') + { + lc = *p; + lp = p; + } + if (*p != '<') // check for '<' under cursor + { + if (lc != '<') + return FALSE; + p = lp; + } + } + else + { + for (p = line + curwin->w_cursor.col; p > line; ) + { + if (*p == '<') // find '<' under/before cursor + break; + MB_PTR_BACK(line, p); + if (*p == '>') // find '>' before cursor + break; + } + if (*p != '<') + return FALSE; + } + + pos.lnum = curwin->w_cursor.lnum; + pos.col = (colnr_T)(p - line); + + MB_PTR_ADV(p); + if (end_tag) + // check that there is a '/' after the '<' + return *p == '/'; + + // check that there is no '/' after the '<' + if (*p == '/') + return FALSE; + + // check that the matching '>' is not preceded by '/' + for (;;) + { + if (inc(&pos) < 0) + return FALSE; + c = *ml_get_pos(&pos); + if (c == '>') + break; + lc = c; + } + return lc != '/'; +} + +/* + * Find tag block under the cursor, cursor at end. + */ + int +current_tagblock( + oparg_T *oap, + long count_arg, + int include) // TRUE == include white space +{ + long count = count_arg; + long n; + pos_T old_pos; + pos_T start_pos; + pos_T end_pos; + pos_T old_start, old_end; + char_u *spat, *epat; + char_u *p; + char_u *cp; + int len; + int r; + int do_include = include; + int save_p_ws = p_ws; + int retval = FAIL; + int is_inclusive = TRUE; + + p_ws = FALSE; + + old_pos = curwin->w_cursor; + old_end = curwin->w_cursor; // remember where we started + old_start = old_end; + if (!VIsual_active || *p_sel == 'e') + decl(&old_end); // old_end is inclusive + + /* + * If we start on "<aaa>" select that block. + */ + if (!VIsual_active || EQUAL_POS(VIsual, curwin->w_cursor)) + { + setpcmark(); + + // ignore indent + while (inindent(1)) + if (inc_cursor() != 0) + break; + + if (in_html_tag(FALSE)) + { + // cursor on start tag, move to its '>' + while (*ml_get_cursor() != '>') + if (inc_cursor() < 0) + break; + } + else if (in_html_tag(TRUE)) + { + // cursor on end tag, move to just before it + while (*ml_get_cursor() != '<') + if (dec_cursor() < 0) + break; + dec_cursor(); + old_end = curwin->w_cursor; + } + } + else if (LT_POS(VIsual, curwin->w_cursor)) + { + old_start = VIsual; + curwin->w_cursor = VIsual; // cursor at low end of Visual + } + else + old_end = VIsual; + +again: + /* + * Search backwards for unclosed "<aaa>". + * Put this position in start_pos. + */ + for (n = 0; n < count; ++n) + { + if (do_searchpair((char_u *)"<[^ \t>/!]\\+\\%(\\_s\\_[^>]\\{-}[^/]>\\|$\\|\\_s\\=>\\)", + (char_u *)"", + (char_u *)"</[^>]*>", BACKWARD, NULL, 0, + NULL, (linenr_T)0, 0L) <= 0) + { + curwin->w_cursor = old_pos; + goto theend; + } + } + start_pos = curwin->w_cursor; + + /* + * Search for matching "</aaa>". First isolate the "aaa". + */ + inc_cursor(); + p = ml_get_cursor(); + for (cp = p; *cp != NUL && *cp != '>' && !VIM_ISWHITE(*cp); MB_PTR_ADV(cp)) + ; + len = (int)(cp - p); + if (len == 0) + { + curwin->w_cursor = old_pos; + goto theend; + } + spat = alloc(len + 31); + epat = alloc(len + 9); + if (spat == NULL || epat == NULL) + { + vim_free(spat); + vim_free(epat); + curwin->w_cursor = old_pos; + goto theend; + } + sprintf((char *)spat, "<%.*s\\>\\%%(\\s\\_[^>]\\{-}[^/]>\\|>\\)\\c", len, p); + sprintf((char *)epat, "</%.*s>\\c", len, p); + + r = do_searchpair(spat, (char_u *)"", epat, FORWARD, NULL, + 0, NULL, (linenr_T)0, 0L); + + vim_free(spat); + vim_free(epat); + + if (r < 1 || LT_POS(curwin->w_cursor, old_end)) + { + // Can't find other end or it's before the previous end. Could be a + // HTML tag that doesn't have a matching end. Search backwards for + // another starting tag. + count = 1; + curwin->w_cursor = start_pos; + goto again; + } + + if (do_include) + { + // Include up to the '>'. + while (*ml_get_cursor() != '>') + if (inc_cursor() < 0) + break; + } + else + { + char_u *c = ml_get_cursor(); + + // Exclude the '<' of the end tag. + // If the closing tag is on new line, do not decrement cursor, but + // make operation exclusive, so that the linefeed will be selected + if (*c == '<' && !VIsual_active && curwin->w_cursor.col == 0) + // do not decrement cursor + is_inclusive = FALSE; + else if (*c == '<') + dec_cursor(); + } + end_pos = curwin->w_cursor; + + if (!do_include) + { + // Exclude the start tag. + curwin->w_cursor = start_pos; + while (inc_cursor() >= 0) + if (*ml_get_cursor() == '>') + { + inc_cursor(); + start_pos = curwin->w_cursor; + break; + } + curwin->w_cursor = end_pos; + + // If we are in Visual mode and now have the same text as before set + // "do_include" and try again. + if (VIsual_active && EQUAL_POS(start_pos, old_start) + && EQUAL_POS(end_pos, old_end)) + { + do_include = TRUE; + curwin->w_cursor = old_start; + count = count_arg; + goto again; + } + } + + if (VIsual_active) + { + // If the end is before the start there is no text between tags, select + // the char under the cursor. + if (LT_POS(end_pos, start_pos)) + curwin->w_cursor = start_pos; + else if (*p_sel == 'e') + inc_cursor(); + VIsual = start_pos; + VIsual_mode = 'v'; + redraw_curbuf_later(INVERTED); // update the inversion + showmode(); + } + else + { + oap->start = start_pos; + oap->motion_type = MCHAR; + if (LT_POS(end_pos, start_pos)) + { + // End is before the start: there is no text between tags; operate + // on an empty area. + curwin->w_cursor = start_pos; + oap->inclusive = FALSE; + } + else + oap->inclusive = is_inclusive; + } + retval = OK; + +theend: + p_ws = save_p_ws; + return retval; +} + + int +current_par( + oparg_T *oap, + long count, + int include, // TRUE == include white space + int type) // 'p' for paragraph, 'S' for section +{ + linenr_T start_lnum; + linenr_T end_lnum; + int white_in_front; + int dir; + int start_is_white; + int prev_start_is_white; + int retval = OK; + int do_white = FALSE; + int t; + int i; + + if (type == 'S') // not implemented yet + return FAIL; + + start_lnum = curwin->w_cursor.lnum; + + /* + * When visual area is more than one line: extend it. + */ + if (VIsual_active && start_lnum != VIsual.lnum) + { +extend: + if (start_lnum < VIsual.lnum) + dir = BACKWARD; + else + dir = FORWARD; + for (i = count; --i >= 0; ) + { + if (start_lnum == + (dir == BACKWARD ? 1 : curbuf->b_ml.ml_line_count)) + { + retval = FAIL; + break; + } + + prev_start_is_white = -1; + for (t = 0; t < 2; ++t) + { + start_lnum += dir; + start_is_white = linewhite(start_lnum); + if (prev_start_is_white == start_is_white) + { + start_lnum -= dir; + break; + } + for (;;) + { + if (start_lnum == (dir == BACKWARD + ? 1 : curbuf->b_ml.ml_line_count)) + break; + if (start_is_white != linewhite(start_lnum + dir) + || (!start_is_white + && startPS(start_lnum + (dir > 0 + ? 1 : 0), 0, 0))) + break; + start_lnum += dir; + } + if (!include) + break; + if (start_lnum == (dir == BACKWARD + ? 1 : curbuf->b_ml.ml_line_count)) + break; + prev_start_is_white = start_is_white; + } + } + curwin->w_cursor.lnum = start_lnum; + curwin->w_cursor.col = 0; + return retval; + } + + /* + * First move back to the start_lnum of the paragraph or white lines + */ + white_in_front = linewhite(start_lnum); + while (start_lnum > 1) + { + if (white_in_front) // stop at first white line + { + if (!linewhite(start_lnum - 1)) + break; + } + else // stop at first non-white line of start of paragraph + { + if (linewhite(start_lnum - 1) || startPS(start_lnum, 0, 0)) + break; + } + --start_lnum; + } + + /* + * Move past the end of any white lines. + */ + end_lnum = start_lnum; + while (end_lnum <= curbuf->b_ml.ml_line_count && linewhite(end_lnum)) + ++end_lnum; + + --end_lnum; + i = count; + if (!include && white_in_front) + --i; + while (i--) + { + if (end_lnum == curbuf->b_ml.ml_line_count) + return FAIL; + + if (!include) + do_white = linewhite(end_lnum + 1); + + if (include || !do_white) + { + ++end_lnum; + /* + * skip to end of paragraph + */ + while (end_lnum < curbuf->b_ml.ml_line_count + && !linewhite(end_lnum + 1) + && !startPS(end_lnum + 1, 0, 0)) + ++end_lnum; + } + + if (i == 0 && white_in_front && include) + break; + + /* + * skip to end of white lines after paragraph + */ + if (include || do_white) + while (end_lnum < curbuf->b_ml.ml_line_count + && linewhite(end_lnum + 1)) + ++end_lnum; + } + + /* + * If there are no empty lines at the end, try to find some empty lines at + * the start (unless that has been done already). + */ + if (!white_in_front && !linewhite(end_lnum) && include) + while (start_lnum > 1 && linewhite(start_lnum - 1)) + --start_lnum; + + if (VIsual_active) + { + // Problem: when doing "Vipipip" nothing happens in a single white + // line, we get stuck there. Trap this here. + if (VIsual_mode == 'V' && start_lnum == curwin->w_cursor.lnum) + goto extend; + if (VIsual.lnum != start_lnum) + { + VIsual.lnum = start_lnum; + VIsual.col = 0; + } + VIsual_mode = 'V'; + redraw_curbuf_later(INVERTED); // update the inversion + showmode(); + } + else + { + oap->start.lnum = start_lnum; + oap->start.col = 0; + oap->motion_type = MLINE; + } + curwin->w_cursor.lnum = end_lnum; + curwin->w_cursor.col = 0; + + return OK; +} + +/* + * Search quote char from string line[col]. + * Quote character escaped by one of the characters in "escape" is not counted + * as a quote. + * Returns column number of "quotechar" or -1 when not found. + */ + static int +find_next_quote( + char_u *line, + int col, + int quotechar, + char_u *escape) // escape characters, can be NULL +{ + int c; + + for (;;) + { + c = line[col]; + if (c == NUL) + return -1; + else if (escape != NULL && vim_strchr(escape, c)) + ++col; + else if (c == quotechar) + break; + if (has_mbyte) + col += (*mb_ptr2len)(line + col); + else + ++col; + } + return col; +} + +/* + * Search backwards in "line" from column "col_start" to find "quotechar". + * Quote character escaped by one of the characters in "escape" is not counted + * as a quote. + * Return the found column or zero. + */ + static int +find_prev_quote( + char_u *line, + int col_start, + int quotechar, + char_u *escape) // escape characters, can be NULL +{ + int n; + + while (col_start > 0) + { + --col_start; + col_start -= (*mb_head_off)(line, line + col_start); + n = 0; + if (escape != NULL) + while (col_start - n > 0 && vim_strchr(escape, + line[col_start - n - 1]) != NULL) + ++n; + if (n & 1) + col_start -= n; // uneven number of escape chars, skip it + else if (line[col_start] == quotechar) + break; + } + return col_start; +} + +/* + * Find quote under the cursor, cursor at end. + * Returns TRUE if found, else FALSE. + */ + int +current_quote( + oparg_T *oap, + long count, + int include, // TRUE == include quote char + int quotechar) // Quote character +{ + char_u *line = ml_get_curline(); + int col_end; + int col_start = curwin->w_cursor.col; + int inclusive = FALSE; + int vis_empty = TRUE; // Visual selection <= 1 char + int vis_bef_curs = FALSE; // Visual starts before cursor + int did_exclusive_adj = FALSE; // adjusted pos for 'selection' + int inside_quotes = FALSE; // Looks like "i'" done before + int selected_quote = FALSE; // Has quote inside selection + int i; + int restore_vis_bef = FALSE; // restore VIsual on abort + + // When 'selection' is "exclusive" move the cursor to where it would be + // with 'selection' "inclusive", so that the logic is the same for both. + // The cursor then is moved forward after adjusting the area. + if (VIsual_active) + { + // this only works within one line + if (VIsual.lnum != curwin->w_cursor.lnum) + return FALSE; + + vis_bef_curs = LT_POS(VIsual, curwin->w_cursor); + vis_empty = EQUAL_POS(VIsual, curwin->w_cursor); + if (*p_sel == 'e') + { + if (vis_bef_curs) + { + dec_cursor(); + did_exclusive_adj = TRUE; + } + else if (!vis_empty) + { + dec(&VIsual); + did_exclusive_adj = TRUE; + } + vis_empty = EQUAL_POS(VIsual, curwin->w_cursor); + if (!vis_bef_curs && !vis_empty) + { + // VIsual needs to be the start of Visual selection. + pos_T t = curwin->w_cursor; + + curwin->w_cursor = VIsual; + VIsual = t; + vis_bef_curs = TRUE; + restore_vis_bef = TRUE; + } + } + } + + if (!vis_empty) + { + // Check if the existing selection exactly spans the text inside + // quotes. + if (vis_bef_curs) + { + inside_quotes = VIsual.col > 0 + && line[VIsual.col - 1] == quotechar + && line[curwin->w_cursor.col] != NUL + && line[curwin->w_cursor.col + 1] == quotechar; + i = VIsual.col; + col_end = curwin->w_cursor.col; + } + else + { + inside_quotes = curwin->w_cursor.col > 0 + && line[curwin->w_cursor.col - 1] == quotechar + && line[VIsual.col] != NUL + && line[VIsual.col + 1] == quotechar; + i = curwin->w_cursor.col; + col_end = VIsual.col; + } + + // Find out if we have a quote in the selection. + while (i <= col_end) + if (line[i++] == quotechar) + { + selected_quote = TRUE; + break; + } + } + + if (!vis_empty && line[col_start] == quotechar) + { + // Already selecting something and on a quote character. Find the + // next quoted string. + if (vis_bef_curs) + { + // Assume we are on a closing quote: move to after the next + // opening quote. + col_start = find_next_quote(line, col_start + 1, quotechar, NULL); + if (col_start < 0) + goto abort_search; + col_end = find_next_quote(line, col_start + 1, quotechar, + curbuf->b_p_qe); + if (col_end < 0) + { + // We were on a starting quote perhaps? + col_end = col_start; + col_start = curwin->w_cursor.col; + } + } + else + { + col_end = find_prev_quote(line, col_start, quotechar, NULL); + if (line[col_end] != quotechar) + goto abort_search; + col_start = find_prev_quote(line, col_end, quotechar, + curbuf->b_p_qe); + if (line[col_start] != quotechar) + { + // We were on an ending quote perhaps? + col_start = col_end; + col_end = curwin->w_cursor.col; + } + } + } + else + + if (line[col_start] == quotechar || !vis_empty) + { + int first_col = col_start; + + if (!vis_empty) + { + if (vis_bef_curs) + first_col = find_next_quote(line, col_start, quotechar, NULL); + else + first_col = find_prev_quote(line, col_start, quotechar, NULL); + } + + // The cursor is on a quote, we don't know if it's the opening or + // closing quote. Search from the start of the line to find out. + // Also do this when there is a Visual area, a' may leave the cursor + // in between two strings. + col_start = 0; + for (;;) + { + // Find open quote character. + col_start = find_next_quote(line, col_start, quotechar, NULL); + if (col_start < 0 || col_start > first_col) + goto abort_search; + // Find close quote character. + col_end = find_next_quote(line, col_start + 1, quotechar, + curbuf->b_p_qe); + if (col_end < 0) + goto abort_search; + // If is cursor between start and end quote character, it is + // target text object. + if (col_start <= first_col && first_col <= col_end) + break; + col_start = col_end + 1; + } + } + else + { + // Search backward for a starting quote. + col_start = find_prev_quote(line, col_start, quotechar, curbuf->b_p_qe); + if (line[col_start] != quotechar) + { + // No quote before the cursor, look after the cursor. + col_start = find_next_quote(line, col_start, quotechar, NULL); + if (col_start < 0) + goto abort_search; + } + + // Find close quote character. + col_end = find_next_quote(line, col_start + 1, quotechar, + curbuf->b_p_qe); + if (col_end < 0) + goto abort_search; + } + + // When "include" is TRUE, include spaces after closing quote or before + // the starting quote. + if (include) + { + if (VIM_ISWHITE(line[col_end + 1])) + while (VIM_ISWHITE(line[col_end + 1])) + ++col_end; + else + while (col_start > 0 && VIM_ISWHITE(line[col_start - 1])) + --col_start; + } + + // Set start position. After vi" another i" must include the ". + // For v2i" include the quotes. + if (!include && count < 2 && (vis_empty || !inside_quotes)) + ++col_start; + curwin->w_cursor.col = col_start; + if (VIsual_active) + { + // Set the start of the Visual area when the Visual area was empty, we + // were just inside quotes or the Visual area didn't start at a quote + // and didn't include a quote. + if (vis_empty + || (vis_bef_curs + && !selected_quote + && (inside_quotes + || (line[VIsual.col] != quotechar + && (VIsual.col == 0 + || line[VIsual.col - 1] != quotechar))))) + { + VIsual = curwin->w_cursor; + redraw_curbuf_later(INVERTED); + } + } + else + { + oap->start = curwin->w_cursor; + oap->motion_type = MCHAR; + } + + // Set end position. + curwin->w_cursor.col = col_end; + if ((include || count > 1 // After vi" another i" must include the ". + || (!vis_empty && inside_quotes) + ) && inc_cursor() == 2) + inclusive = TRUE; + if (VIsual_active) + { + if (vis_empty || vis_bef_curs) + { + // decrement cursor when 'selection' is not exclusive + if (*p_sel != 'e') + dec_cursor(); + } + else + { + // Cursor is at start of Visual area. Set the end of the Visual + // area when it was just inside quotes or it didn't end at a + // quote. + if (inside_quotes + || (!selected_quote + && line[VIsual.col] != quotechar + && (line[VIsual.col] == NUL + || line[VIsual.col + 1] != quotechar))) + { + dec_cursor(); + VIsual = curwin->w_cursor; + } + curwin->w_cursor.col = col_start; + } + if (VIsual_mode == 'V') + { + VIsual_mode = 'v'; + redraw_cmdline = TRUE; // show mode later + } + } + else + { + // Set inclusive and other oap's flags. + oap->inclusive = inclusive; + } + + return OK; + +abort_search: + if (VIsual_active && *p_sel == 'e') + { + if (did_exclusive_adj) + inc_cursor(); + if (restore_vis_bef) + { + pos_T t = curwin->w_cursor; + + curwin->w_cursor = VIsual; + VIsual = t; + } + } + return FALSE; +} + +#endif // FEAT_TEXTOBJ diff --git a/src/version.c b/src/version.c index d3a1b0b7fe..ad2e1c3d76 100644 --- a/src/version.c +++ b/src/version.c @@ -746,6 +746,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 660, /**/ 659, /**/ From 339d60c89bef0315343a6128a1b4826510b0efe4 Mon Sep 17 00:00:00 2001 From: Bram Moolenaar <Bram@vim.org> Date: Wed, 29 Apr 2020 22:01:21 +0200 Subject: [PATCH 055/230] patch 8.2.0661: eval test is still old style Problem: Eval test is still old style. Solution: Change into new style tests. (Yegappan Lakshmanan, closes #6009) --- src/Makefile | 1 - src/testdir/Make_all.mak | 4 +- src/testdir/Make_vms.mms | 5 +- src/testdir/test_eval.in | 119 ----------------------- src/testdir/test_eval.ok | Bin 6716 -> 0 bytes src/testdir/test_eval_stuff.vim | 165 ++++++++++++++++++++++++++++++++ src/version.c | 2 + 7 files changed, 169 insertions(+), 127 deletions(-) delete mode 100644 src/testdir/test_eval.in delete mode 100644 src/testdir/test_eval.ok diff --git a/src/Makefile b/src/Makefile index c8e0f087fe..0e1ac77050 100644 --- a/src/Makefile +++ b/src/Makefile @@ -2291,7 +2291,6 @@ test_libvterm: # Run individual OLD style test. # These do not depend on the executable, compile it when needed. test1 \ - test_eval \ test42 test44 test49 \ test52 test59 \ test70 \ diff --git a/src/testdir/Make_all.mak b/src/testdir/Make_all.mak index 772c083347..7fad24b780 100644 --- a/src/testdir/Make_all.mak +++ b/src/testdir/Make_all.mak @@ -16,9 +16,7 @@ SCRIPTS_ALL = \ test42.out \ test44.out \ test70.out \ - test99.out \ - test_eval.out - + test99.out # Tests that run on most systems, but not on Amiga. SCRIPTS_MORE1 = \ diff --git a/src/testdir/Make_vms.mms b/src/testdir/Make_vms.mms index 5400c158d8..a89bb244fd 100644 --- a/src/testdir/Make_vms.mms +++ b/src/testdir/Make_vms.mms @@ -74,10 +74,7 @@ VIMPROG = <->vim.exe .SUFFIXES : .out .in SCRIPT = test1.out \ - test42.out test44.out test49.out \ - test77a.out \ - test99.out \ - test_eval.out + test42.out test44.out test49.out test77a.out test99.out # Known problems: # diff --git a/src/testdir/test_eval.in b/src/testdir/test_eval.in deleted file mode 100644 index ebe1874102..0000000000 --- a/src/testdir/test_eval.in +++ /dev/null @@ -1,119 +0,0 @@ -Test for various eval features. vim: set ft=vim : - -NOTE: Do not add more here, use new style test test_eval_stuff.vim - -Note: system clipboard is saved, changed and restored. - -clipboard contents -something else - -STARTTEST -:so small.vim -:set encoding=latin1 -:set noswapfile -:lang C -:fun AppendRegContents(reg) - call AppendRegParts(a:reg, getregtype(a:reg), getreg(a:reg), string(getreg(a:reg, 0, 1)), getreg(a:reg, 1), string(getreg(a:reg, 1, 1))) -:endfun -:fun AppendRegParts(reg, type, cont, strcont, cont1, strcont1) - call append('$', printf('%s: type %s; value: %s (%s), expr: %s (%s)', a:reg, a:type, a:cont, a:strcont, a:cont1, a:strcont1)) -endfun -:command -nargs=? AR :call AppendRegContents(<q-args>) -:fun SetReg(...) - call call('setreg', a:000) - call append('$', printf('{{{2 setreg(%s)', string(a:000)[1:-2])) - call AppendRegContents(a:1) - if a:1 isnot# '=' - execute "silent normal! Go==\n==\e\"".a:1."P" - endif -endfun -:fun Test() -$put ='{{{1 Appending NL with setreg()' -call setreg('a', 'abcA2', 'c') -call setreg('b', 'abcB2', 'v') -call setreg('c', 'abcC2', 'l') -call setreg('d', 'abcD2', 'V') -call setreg('e', 'abcE2', 'b') -call setreg('f', 'abcF2', "\<C-v>") -call setreg('g', 'abcG2', 'b10') -call setreg('h', 'abcH2', "\<C-v>10") -call setreg('I', 'abcI2') - -call SetReg('A', "\n") -call SetReg('B', "\n", 'c') -call SetReg('C', "\n") -call SetReg('D', "\n", 'l') -call SetReg('E', "\n") -call SetReg('F', "\n", 'b') - -$put ='{{{1 Setting lists with setreg()' -call SetReg('a', ['abcA3'], 'c') -call SetReg('b', ['abcB3'], 'l') -call SetReg('c', ['abcC3'], 'b') -call SetReg('d', ['abcD3']) -call SetReg('e', [1, 2, 'abc', 3]) -call SetReg('f', [1, 2, 3]) - -$put ='{{{1 Appending lists with setreg()' -call SetReg('A', ['abcA3c'], 'c') -call SetReg('b', ['abcB3l'], 'la') -call SetReg('C', ['abcC3b'], 'lb') -call SetReg('D', ['abcD32']) - -call SetReg('A', ['abcA32']) -call SetReg('B', ['abcB3c'], 'c') -call SetReg('C', ['abcC3l'], 'l') -call SetReg('D', ['abcD3b'], 'b') - -$put ='{{{1 Appending lists with NL with setreg()' -call SetReg('A', ["\n", 'abcA3l2'], 'l') -call SetReg('B', ["\n", 'abcB3c2'], 'c') -call SetReg('C', ["\n", 'abcC3b2'], 'b') -call SetReg('D', ["\n", 'abcD3b50'],'b50') - -$put ='{{{1 Setting lists with NLs with setreg()' -call SetReg('a', ['abcA4-0', "\n", "abcA4-2\n", "\nabcA4-3", "abcA4-4\nabcA4-4-2"]) -call SetReg('b', ['abcB4c-0', "\n", "abcB4c-2\n", "\nabcB4c-3", "abcB4c-4\nabcB4c-4-2"], 'c') -call SetReg('c', ['abcC4l-0', "\n", "abcC4l-2\n", "\nabcC4l-3", "abcC4l-4\nabcC4l-4-2"], 'l') -call SetReg('d', ['abcD4b-0', "\n", "abcD4b-2\n", "\nabcD4b-3", "abcD4b-4\nabcD4b-4-2"], 'b') -call SetReg('e', ['abcE4b10-0', "\n", "abcE4b10-2\n", "\nabcE4b10-3", "abcE4b10-4\nabcE4b10-4-2"], 'b10') - -$put ='{{{1 Search and expressions' -call SetReg('/', ['abc/']) -call SetReg('/', ["abc/\n"]) -call SetReg('=', ['"abc/"']) -call SetReg('=', ["\"abc/\n\""]) -$put ='{{{1 System clipboard' -if has('clipboard') -" Save and restore system clipboard. -" If no connection to X-Server is possible, test should succeed. -let _clipreg = ['*', getreg('*'), getregtype('*')] -let _clipopt = &cb -let &cb='unnamed' -7y -AR * -tabdo :windo :echo "hi" -8y -AR * -let &cb=_clipopt -call call('setreg', _clipreg) -else - call AppendRegParts('*', 'V', "clipboard contents\n", "['clipboard contents']", "clipboard contents\n", "['clipboard contents']") - call AppendRegParts('*', 'V', "something else\n", "['something else']", "something else\n", "['something else']") -endif -endfun -:" -:call Test() -:" -:delfunction SetReg -:delfunction AppendRegContents -:delfunction Test -:delcommand AR -:call garbagecollect(1) -:" -:/^start:/+1,$wq! test.out -:" vim: et ts=4 isk-=\: fmr=???,??? -:call getchar() -ENDTEST - -start: diff --git a/src/testdir/test_eval.ok b/src/testdir/test_eval.ok deleted file mode 100644 index 3ae6f6c67184852ca66d7e73d7a9552d12de5bca..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 6716 zcmc&&OK;mo5ayXbz-Pi2#eof3q}-w@bl^ii1-TT+CCEXdm{<TK8<y%e(4X%-$=T&f zk&VRl#Y^taeDnHdR^0FRlO%t5Xf~_$=4<ldee%zGcb9CN-DC6h%|*Q5?^Asm<)h1F z6pb$8{9Us9{?H^J|4g11?cdG2WU;LCG)mrl8qsR>`QkEZ{(X21?ZmTLOs8<+02B-W zC^euIg7RchiVmen@wAH+*hP>Tz!hoip_S@R8FHsgBlV{YAceNYu`-PZo>iS^EqGRi z0IMFb3IK+-1+WSL&egej2y5PB%>!7WZNZucux>l&mf+m20G?gjyxn$ryA1#ab`cNr zcAL)P1j}TS{MGDsSf%ZHyW1Ws)CCyCm6(k_OEoRTET@|COiLCHIwk9Ds4aQsmC#aw z3I@XDE<*t?GA$-NX_34g33HL*!XZbkSS4d&tZR++jg57w#^Xtg<!-1~rSH{Bkt&pr zS0RV0&LKKv*zWC!L)Fls24N<bNeUT)M8i`CXwXc&-ZF{O2=*gJoWQvel@QB}tdA!g zMSCW3iXA8(+VrKj361#@G{!f?w;;5yunK9r?hor38?V%J-4(PpVXvSuRC!kSb<NR* zS8grj+0m0)9C=2)I;*{EG?m|yN$uiD?SoB4)*1@1QSi<+3dnHus1y^hgOA~}LlW%i z6sa;>vROzIZSZHmximpAI4H3Kwy;?w>+<I4NsSfI3wjmnbj`x{Pi9qFij)cu0CFBq zXq<pqY!FMi90QocM<q@`IzBdtlc^{&NQ>#C4NzAi=zZSXm8)G?R9arB##s1lSuwe* zH!eFE+Fpk7jzFO-u%ZF|@KvEJCNLjPOPZkpv&~q2y7I`;*WqcRXeC`Ty24~R&vsLt zLK;(?PUuUr9SV^PucMArqilTXljzy968e&i2TTk-XdQ&!R56naxuvD-atnq4D8T}y ze@Zc@qS^ckiE1n7xuP2TO4$df#6r-__lEv{YdY<ZuezV$uFE#&SqtS2Yn<<=Q6*x| zv>llbkOq{xC^i%W61`lj<aj`@h<Vl?BAOZp{NWIsOt*-PMY-d|GZA1A8v&n)FITE% z($5a2XiO16<RDqqf1m~X@640mZMz)sjsk#!p#j5{h2%8>U=$mGpQls<08`40sYJM* zL^`?B(CE@I0H<!Qi3<4Nu>Z!n?fV?&w2`pH;y@=bu@ER5jGw7i!vSsMIe$FhZHtk} zk-6M&0>4u}yg%^=%k=8n7DPV1N-6f#PNr8nyWss)Ucm{xQt0m+XN<tHYmPlB;`RYr zR8;>1h~xz&USxos{jZ0rZ4D5a$mD0N(W2(&gbD?m8)JWwoz|}F1-$5kk53wXTvPaI zf$@jB#m1<={hn-Jz(bM+T*6OpG!K`2LGhGnw?rwM36`ZdDvl4bcFnP*`9I*5T!bwh zmRzUIkn5NlTv)@s)ZpckFZ0vZjYSDB`qbc)rUuufk`|I09NYR++2IEslGNZ*QiDsr ze|gH3BqU~Y!@`;yl9$}z+O@~#h7@r<unHa-zZPFOL)e@f#-`lhlJ9|@;RE9IUkRp5 zH#-%)=(B@QnjKtIG-x5&!HKHh7|tetSnA+0$qz0iKe*)krKe733rgAau&kzs#3enr zb`7%W!QIz}SLzV9nM^Qvctqny3QKGvxX$>p>p9{!Ir`Lstztf1POjbH@T)#w{Hz({ zCkl})HER=`|N6D&Y~sv+J}RN(2gw~jQ1(P0`XS3Jy(#gtlS6*>JTq-BMJ1C>l@Z<e z;k8WC{E9tYTGb>@tk^`U<+Ymvy=W{R>$_yJS<%P#X1iVAZ?<mg$583iM8|kb7|RDO zXF!dGH+aH~ar;`W9(ygi*B%{KuWfUTXDooT(LqEW#*92ThcX$TBgpJjA6NvP>xG@! zZ!||oR6Ay>{iHHF@3gZ5P!Hd!zi)TVx1?^@56k<-<0^hT_>9=?CH4Jg*KBrM0vWzG h5gTqEmI**^@4q#>JN$m$wA+S6-B$+6-3XtJ{{x_e)a(EN diff --git a/src/testdir/test_eval_stuff.vim b/src/testdir/test_eval_stuff.vim index 28350bb3e2..325f8e2a49 100644 --- a/src/testdir/test_eval_stuff.vim +++ b/src/testdir/test_eval_stuff.vim @@ -354,6 +354,171 @@ func Test_setreg_basic() call Assert_reg('I', "v", "abcI", "['abcI']", "abcI", "['abcI']") call Assert_regput('I', ['==', '=abcI=']) + " Appending NL with setreg() + call setreg('a', 'abcA2', 'c') + call setreg('b', 'abcB2', 'v') + call setreg('c', 'abcC2', 'l') + call setreg('d', 'abcD2', 'V') + call setreg('e', 'abcE2', 'b') + call setreg('f', 'abcF2', "\<C-v>") + call setreg('g', 'abcG2', 'b10') + call setreg('h', 'abcH2', "\<C-v>10") + call setreg('I', 'abcI2') + + call setreg('A', "\n") + call Assert_reg('A', 'V', "abcA2\n", "['abcA2']", "abcA2\n", "['abcA2']") + call Assert_regput('A', ['==', 'abcA2', '==']) + + call setreg('B', "\n", 'c') + call Assert_reg('B', 'v', "abcB2\n", "['abcB2', '']", "abcB2\n", "['abcB2', '']") + call Assert_regput('B', ['==', '=abcB2', '=']) + + call setreg('C', "\n") + call Assert_reg('C', 'V', "abcC2\n\n", "['abcC2', '']", "abcC2\n\n", "['abcC2', '']") + call Assert_regput('C', ['==', 'abcC2', '', '==']) + + call setreg('D', "\n", 'l') + call Assert_reg('D', 'V', "abcD2\n\n", "['abcD2', '']", "abcD2\n\n", "['abcD2', '']") + call Assert_regput('D', ['==', 'abcD2', '', '==']) + + call setreg('E', "\n") + call Assert_reg('E', 'V', "abcE2\n\n", "['abcE2', '']", "abcE2\n\n", "['abcE2', '']") + call Assert_regput('E', ['==', 'abcE2', '', '==']) + + call setreg('F', "\n", 'b') + call Assert_reg('F', "\<C-V>0", "abcF2\n", "['abcF2', '']", "abcF2\n", "['abcF2', '']") + call Assert_regput('F', ['==', '=abcF2=', ' ']) + + " Setting lists with setreg() + call setreg('a', ['abcA3'], 'c') + call Assert_reg('a', 'v', "abcA3", "['abcA3']", "abcA3", "['abcA3']") + call Assert_regput('a', ['==', '=abcA3=']) + + call setreg('b', ['abcB3'], 'l') + call Assert_reg('b', 'V', "abcB3\n", "['abcB3']", "abcB3\n", "['abcB3']") + call Assert_regput('b', ['==', 'abcB3', '==']) + + call setreg('c', ['abcC3'], 'b') + call Assert_reg('c', "\<C-V>5", "abcC3", "['abcC3']", "abcC3", "['abcC3']") + call Assert_regput('c', ['==', '=abcC3=']) + + call setreg('d', ['abcD3']) + call Assert_reg('d', 'V', "abcD3\n", "['abcD3']", "abcD3\n", "['abcD3']") + call Assert_regput('d', ['==', 'abcD3', '==']) + + call setreg('e', [1, 2, 'abc', 3]) + call Assert_reg('e', 'V', "1\n2\nabc\n3\n", "['1', '2', 'abc', '3']", "1\n2\nabc\n3\n", "['1', '2', 'abc', '3']") + call Assert_regput('e', ['==', '1', '2', 'abc', '3', '==']) + + call setreg('f', [1, 2, 3]) + call Assert_reg('f', 'V', "1\n2\n3\n", "['1', '2', '3']", "1\n2\n3\n", "['1', '2', '3']") + call Assert_regput('f', ['==', '1', '2', '3', '==']) + + " Appending lists with setreg() + call setreg('A', ['abcA3c'], 'c') + call Assert_reg('A', 'v', "abcA3\nabcA3c", "['abcA3', 'abcA3c']", "abcA3\nabcA3c", "['abcA3', 'abcA3c']") + call Assert_regput('A', ['==', '=abcA3', 'abcA3c=']) + + call setreg('b', ['abcB3l'], 'la') + call Assert_reg('b', 'V', "abcB3\nabcB3l\n", "['abcB3', 'abcB3l']", "abcB3\nabcB3l\n", "['abcB3', 'abcB3l']") + call Assert_regput('b', ['==', 'abcB3', 'abcB3l', '==']) + + call setreg('C', ['abcC3b'], 'lb') + call Assert_reg('C', "\<C-V>6", "abcC3\nabcC3b", "['abcC3', 'abcC3b']", "abcC3\nabcC3b", "['abcC3', 'abcC3b']") + call Assert_regput('C', ['==', '=abcC3 =', ' abcC3b']) + + call setreg('D', ['abcD32']) + call Assert_reg('D', 'V', "abcD3\nabcD32\n", "['abcD3', 'abcD32']", "abcD3\nabcD32\n", "['abcD3', 'abcD32']") + call Assert_regput('D', ['==', 'abcD3', 'abcD32', '==']) + + call setreg('A', ['abcA32']) + call Assert_reg('A', 'V', "abcA3\nabcA3c\nabcA32\n", "['abcA3', 'abcA3c', 'abcA32']", "abcA3\nabcA3c\nabcA32\n", "['abcA3', 'abcA3c', 'abcA32']") + call Assert_regput('A', ['==', 'abcA3', 'abcA3c', 'abcA32', '==']) + + call setreg('B', ['abcB3c'], 'c') + call Assert_reg('B', 'v', "abcB3\nabcB3l\nabcB3c", "['abcB3', 'abcB3l', 'abcB3c']", "abcB3\nabcB3l\nabcB3c", "['abcB3', 'abcB3l', 'abcB3c']") + call Assert_regput('B', ['==', '=abcB3', 'abcB3l', 'abcB3c=']) + + call setreg('C', ['abcC3l'], 'l') + call Assert_reg('C', 'V', "abcC3\nabcC3b\nabcC3l\n", "['abcC3', 'abcC3b', 'abcC3l']", "abcC3\nabcC3b\nabcC3l\n", "['abcC3', 'abcC3b', 'abcC3l']") + call Assert_regput('C', ['==', 'abcC3', 'abcC3b', 'abcC3l', '==']) + + call setreg('D', ['abcD3b'], 'b') + call Assert_reg('D', "\<C-V>6", "abcD3\nabcD32\nabcD3b", "['abcD3', 'abcD32', 'abcD3b']", "abcD3\nabcD32\nabcD3b", "['abcD3', 'abcD32', 'abcD3b']") + call Assert_regput('D', ['==', '=abcD3 =', ' abcD32', ' abcD3b']) + + " Appending lists with NL with setreg() + call setreg('A', ["\n", 'abcA3l2'], 'l') + call Assert_reg('A', "V", "abcA3\nabcA3c\nabcA32\n\n\nabcA3l2\n", "['abcA3', 'abcA3c', 'abcA32', '\n', 'abcA3l2']", "abcA3\nabcA3c\nabcA32\n\n\nabcA3l2\n", "['abcA3', 'abcA3c', 'abcA32', '\n', 'abcA3l2']") + call Assert_regput('A', ['==', 'abcA3', 'abcA3c', 'abcA32', "\n", 'abcA3l2', '==']) + + call setreg('B', ["\n", 'abcB3c2'], 'c') + call Assert_reg('B', "v", "abcB3\nabcB3l\nabcB3c\n\n\nabcB3c2", "['abcB3', 'abcB3l', 'abcB3c', '\n', 'abcB3c2']", "abcB3\nabcB3l\nabcB3c\n\n\nabcB3c2", "['abcB3', 'abcB3l', 'abcB3c', '\n', 'abcB3c2']") + call Assert_regput('B', ['==', '=abcB3', 'abcB3l', 'abcB3c', "\n", 'abcB3c2=']) + + call setreg('C', ["\n", 'abcC3b2'], 'b') + call Assert_reg('C', "7", "abcC3\nabcC3b\nabcC3l\n\n\nabcC3b2", "['abcC3', 'abcC3b', 'abcC3l', '\n', 'abcC3b2']", "abcC3\nabcC3b\nabcC3l\n\n\nabcC3b2", "['abcC3', 'abcC3b', 'abcC3l', '\n', 'abcC3b2']") + call Assert_regput('C', ['==', '=abcC3 =', ' abcC3b', ' abcC3l', " \n", ' abcC3b2']) + + call setreg('D', ["\n", 'abcD3b50'],'b50') + call Assert_reg('D', "50", "abcD3\nabcD32\nabcD3b\n\n\nabcD3b50", "['abcD3', 'abcD32', 'abcD3b', '\n', 'abcD3b50']", "abcD3\nabcD32\nabcD3b\n\n\nabcD3b50", "['abcD3', 'abcD32', 'abcD3b', '\n', 'abcD3b50']") + call Assert_regput('D', ['==', '=abcD3 =', ' abcD32', ' abcD3b', " \n", ' abcD3b50']) + + " Setting lists with NLs with setreg() + call setreg('a', ['abcA4-0', "\n", "abcA4-2\n", "\nabcA4-3", "abcA4-4\nabcA4-4-2"]) + call Assert_reg('a', "V", "abcA4-0\n\n\nabcA4-2\n\n\nabcA4-3\nabcA4-4\nabcA4-4-2\n", "['abcA4-0', '\n', 'abcA4-2\n', '\nabcA4-3', 'abcA4-4\nabcA4-4-2']", "abcA4-0\n\n\nabcA4-2\n\n\nabcA4-3\nabcA4-4\nabcA4-4-2\n", "['abcA4-0', '\n', 'abcA4-2\n', '\nabcA4-3', 'abcA4-4\nabcA4-4-2']") + call Assert_regput('a', ['==', 'abcA4-0', "\n", "abcA4-2\n", "\nabcA4-3", "abcA4-4\nabcA4-4-2", '==']) + + call setreg('b', ['abcB4c-0', "\n", "abcB4c-2\n", "\nabcB4c-3", "abcB4c-4\nabcB4c-4-2"], 'c') + call Assert_reg('b', "v", "abcB4c-0\n\n\nabcB4c-2\n\n\nabcB4c-3\nabcB4c-4\nabcB4c-4-2", "['abcB4c-0', '\n', 'abcB4c-2\n', '\nabcB4c-3', 'abcB4c-4\nabcB4c-4-2']", "abcB4c-0\n\n\nabcB4c-2\n\n\nabcB4c-3\nabcB4c-4\nabcB4c-4-2", "['abcB4c-0', '\n', 'abcB4c-2\n', '\nabcB4c-3', 'abcB4c-4\nabcB4c-4-2']") + call Assert_regput('b', ['==', '=abcB4c-0', "\n", "abcB4c-2\n", "\nabcB4c-3", "abcB4c-4\nabcB4c-4-2="]) + + call setreg('c', ['abcC4l-0', "\n", "abcC4l-2\n", "\nabcC4l-3", "abcC4l-4\nabcC4l-4-2"], 'l') + call Assert_reg('c', "V", "abcC4l-0\n\n\nabcC4l-2\n\n\nabcC4l-3\nabcC4l-4\nabcC4l-4-2\n", "['abcC4l-0', '\n', 'abcC4l-2\n', '\nabcC4l-3', 'abcC4l-4\nabcC4l-4-2']", "abcC4l-0\n\n\nabcC4l-2\n\n\nabcC4l-3\nabcC4l-4\nabcC4l-4-2\n", "['abcC4l-0', '\n', 'abcC4l-2\n', '\nabcC4l-3', 'abcC4l-4\nabcC4l-4-2']") + call Assert_regput('c', ['==', 'abcC4l-0', "\n", "abcC4l-2\n", "\nabcC4l-3", "abcC4l-4\nabcC4l-4-2", '==']) + + call setreg('d', ['abcD4b-0', "\n", "abcD4b-2\n", "\nabcD4b-3", "abcD4b-4\nabcD4b-4-2"], 'b') + call Assert_reg('d', "19", "abcD4b-0\n\n\nabcD4b-2\n\n\nabcD4b-3\nabcD4b-4\nabcD4b-4-2", "['abcD4b-0', '\n', 'abcD4b-2\n', '\nabcD4b-3', 'abcD4b-4\nabcD4b-4-2']", "abcD4b-0\n\n\nabcD4b-2\n\n\nabcD4b-3\nabcD4b-4\nabcD4b-4-2", "['abcD4b-0', '\n', 'abcD4b-2\n', '\nabcD4b-3', 'abcD4b-4\nabcD4b-4-2']") + call Assert_regput('d', ['==', '=abcD4b-0 =', " \n", " abcD4b-2\n", " \nabcD4b-3", " abcD4b-4\nabcD4b-4-2"]) + + call setreg('e', ['abcE4b10-0', "\n", "abcE4b10-2\n", "\nabcE4b10-3", "abcE4b10-4\nabcE4b10-4-2"], 'b10') + call Assert_reg('e', "10", "abcE4b10-0\n\n\nabcE4b10-2\n\n\nabcE4b10-3\nabcE4b10-4\nabcE4b10-4-2", "['abcE4b10-0', '\n', 'abcE4b10-2\n', '\nabcE4b10-3', 'abcE4b10-4\nabcE4b10-4-2']", "abcE4b10-0\n\n\nabcE4b10-2\n\n\nabcE4b10-3\nabcE4b10-4\nabcE4b10-4-2", "['abcE4b10-0', '\n', 'abcE4b10-2\n', '\nabcE4b10-3', 'abcE4b10-4\nabcE4b10-4-2']") + call Assert_regput('e', ['==', '=abcE4b10-0=', " \n", " abcE4b10-2\n", " \nabcE4b10-3", " abcE4b10-4\nabcE4b10-4-2"]) + + " Search and expressions + call setreg('/', ['abc/']) + call Assert_reg('/', 'v', "abc/", "['abc/']", "abc/", "['abc/']") + call Assert_regput('/', ['==', '=abc/=']) + + call setreg('/', ["abc/\n"]) + call Assert_reg('/', 'v', "abc/\n", "['abc/\n']", "abc/\n", "['abc/\n']") + call Assert_regput('/', ['==', "=abc/\n="]) + + call setreg('=', ['"abc/"']) + call Assert_reg('=', 'v', "abc/", "['abc/']", '"abc/"', "['\"abc/\"']") + + call setreg('=', ["\"abc/\n\""]) + call Assert_reg('=', 'v', "abc/\n", "['abc/\n']", "\"abc/\n\"", "['\"abc/\n\"']") + + " System clipboard + if has('clipboard') + new | only! + call setline(1, ['clipboard contents', 'something else']) + " Save and restore system clipboard. + " If no connection to X-Server is possible, test should succeed. + let _clipreg = ['*', getreg('*'), getregtype('*')] + let _clipopt = &cb + let &cb='unnamed' + 1y + call Assert_reg('*', 'V', "clipboard contents\n", "['clipboard contents']", "clipboard contents\n", "['clipboard contents']") + tabdo :windo :echo "hi" + 2y + call Assert_reg('*', 'V', "something else\n", "['something else']", "something else\n", "['something else']") + let &cb=_clipopt + call call('setreg', _clipreg) + enew! + endif + " Error cases call assert_fails('call setreg()', 'E119:') call assert_fails('call setreg(1)', 'E119:') diff --git a/src/version.c b/src/version.c index ad2e1c3d76..0946468501 100644 --- a/src/version.c +++ b/src/version.c @@ -746,6 +746,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 661, /**/ 660, /**/ From dfc33a665d3b12689aa971575b8e7de4e5202d83 Mon Sep 17 00:00:00 2001 From: Bram Moolenaar <Bram@vim.org> Date: Wed, 29 Apr 2020 22:30:13 +0200 Subject: [PATCH 056/230] patch 8.2.0662: cannot use input() in a channel callback Problem: Cannot use input() in a channel callback. Solution: Reset vgetc_busy. (closes #6010) --- src/evalfunc.c | 6 +++--- src/ex_getln.c | 8 ++++++++ src/globals.h | 3 +++ src/testdir/test_channel.vim | 17 +++++++++++++++++ src/version.c | 2 ++ 5 files changed, 33 insertions(+), 3 deletions(-) diff --git a/src/evalfunc.c b/src/evalfunc.c index 02943c717a..1493291954 100644 --- a/src/evalfunc.c +++ b/src/evalfunc.c @@ -2149,7 +2149,7 @@ f_eval(typval_T *argvars, typval_T *rettv) static void f_eventhandler(typval_T *argvars UNUSED, typval_T *rettv) { - rettv->vval.v_number = vgetc_busy; + rettv->vval.v_number = vgetc_busy || input_busy; } static garray_T redir_execute_ga; @@ -2566,7 +2566,7 @@ f_feedkeys(typval_T *argvars, typval_T *rettv UNUSED) #ifdef FEAT_TIMERS || timer_busy #endif - ) + || input_busy) typebuf_was_filled = TRUE; } vim_free(keys_esc); @@ -2887,7 +2887,7 @@ f_funcref(typval_T *argvars, typval_T *rettv) } static type_T * -ret_f_function(int argcount, type_T **argtypes UNUSED) +ret_f_function(int argcount, type_T **argtypes) { if (argcount == 1 && argtypes[0]->tt_type == VAR_STRING) return &t_func_any; diff --git a/src/ex_getln.c b/src/ex_getln.c index 7e92ec8992..6376a5fba4 100644 --- a/src/ex_getln.c +++ b/src/ex_getln.c @@ -4468,6 +4468,8 @@ get_user_input( rettv->v_type = VAR_STRING; rettv->vval.v_string = NULL; + if (input_busy) + return; // this doesn't work recursively. #ifdef NO_CONSOLE_INPUT // While starting up, there is no place to enter text. When running tests @@ -4528,12 +4530,18 @@ get_user_input( if (defstr != NULL) { int save_ex_normal_busy = ex_normal_busy; + int save_vgetc_busy = vgetc_busy; + int save_input_busy = input_busy; + input_busy |= vgetc_busy; ex_normal_busy = 0; + vgetc_busy = 0; rettv->vval.v_string = getcmdline_prompt(secret ? NUL : '@', p, get_echo_attr(), xp_type, xp_arg); ex_normal_busy = save_ex_normal_busy; + vgetc_busy = save_vgetc_busy; + input_busy = save_input_busy; } if (inputdialog && rettv->vval.v_string == NULL && argvars[1].v_type != VAR_UNKNOWN diff --git a/src/globals.h b/src/globals.h index 725493b320..2dceab5e23 100644 --- a/src/globals.h +++ b/src/globals.h @@ -1814,6 +1814,9 @@ EXTERN int in_free_unref_items INIT(= FALSE); EXTERN int did_add_timer INIT(= FALSE); EXTERN int timer_busy INIT(= 0); // when timer is inside vgetc() then > 0 #endif +#ifdef FEAT_EVAL +EXTERN int input_busy INIT(= 0); // when inside get_user_input() then > 0 +#endif #ifdef FEAT_BEVAL_TERM EXTERN int bevalexpr_due_set INIT(= FALSE); diff --git a/src/testdir/test_channel.vim b/src/testdir/test_channel.vim index 4a438ea729..019b959251 100644 --- a/src/testdir/test_channel.vim +++ b/src/testdir/test_channel.vim @@ -6,6 +6,7 @@ CheckFeature channel source shared.vim source screendump.vim +source view_util.vim let s:python = PythonProg() if s:python == '' @@ -2297,4 +2298,20 @@ func Test_job_with_list_args() %bw! endfunc +func ExitCb_cb_with_input(job, status) + call feedkeys(":\<C-u>echo input('', 'default')\<CR>\<CR>", 'nx') + call assert_equal('default', Screenline(&lines)) + let g:wait_exit_cb = 0 +endfunc + +func Test_cb_with_input() + let g:wait_exit_cb = 1 + + call job_start('echo "Vim''s test"', + \ {'out_cb': 'ExitCb_cb_with_input'}) + call WaitForAssert({-> assert_equal(0, g:wait_exit_cb)}) + + unlet g:wait_exit_cb +endfunc + " vim: shiftwidth=2 sts=2 expandtab diff --git a/src/version.c b/src/version.c index 0946468501..df2fd1f552 100644 --- a/src/version.c +++ b/src/version.c @@ -746,6 +746,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 662, /**/ 661, /**/ From 512fe833c3988bfe0de22135aef67faf51927a0e Mon Sep 17 00:00:00 2001 From: Bram Moolenaar <Bram@vim.org> Date: Wed, 29 Apr 2020 23:02:40 +0200 Subject: [PATCH 057/230] patch 8.2.0663: not all systemd temp files are recognized Problem: Not all systemd temp files are recognized. Solution: Add two more patterns. (Jamie Macdonald, closes #6003) --- runtime/filetype.vim | 4 +++- src/testdir/test_filetype.vim | 2 +- src/version.c | 2 ++ 3 files changed, 6 insertions(+), 2 deletions(-) diff --git a/runtime/filetype.vim b/runtime/filetype.vim index d5d8115ca1..9fe4ecfe57 100644 --- a/runtime/filetype.vim +++ b/runtime/filetype.vim @@ -1,7 +1,7 @@ " Vim support file to detect file types " " Maintainer: Bram Moolenaar <Bram@vim.org> -" Last Change: 2020 Apr 17 +" Last Change: 2020 Apr 29 " Listen very carefully, I will say this only once if exists("did_load_filetypes") @@ -1650,7 +1650,9 @@ au BufNewFile,BufRead */etc/systemd/system/*.d/*.conf setf systemd au BufNewFile,BufRead */.config/systemd/user/*.d/*.conf setf systemd " Systemd temp files au BufNewFile,BufRead */etc/systemd/system/*.d/.#* setf systemd +au BufNewFile,BufRead */etc/systemd/system/.#* setf systemd au BufNewFile,BufRead */.config/systemd/user/*.d/.#* setf systemd +au BufNewFile,BufRead */.config/systemd/user/.#* setf systemd " Synopsys Design Constraints au BufNewFile,BufRead *.sdc setf sdc diff --git a/src/testdir/test_filetype.vim b/src/testdir/test_filetype.vim index 33fcfd7e72..e71ccd44ef 100644 --- a/src/testdir/test_filetype.vim +++ b/src/testdir/test_filetype.vim @@ -438,7 +438,7 @@ let s:filename_checks = { \ 'swiftgyb': ['file.swift.gyb'], \ 'sil': ['file.sil'], \ 'sysctl': ['/etc/sysctl.conf', '/etc/sysctl.d/file.conf'], - \ 'systemd': ['any/systemd/file.automount', 'any/systemd/file.mount', 'any/systemd/file.path', 'any/systemd/file.service', 'any/systemd/file.socket', 'any/systemd/file.swap', 'any/systemd/file.target', 'any/systemd/file.timer', '/etc/systemd/system/some.d/file.conf', '/etc/systemd/system/some.d/.#file', '/home/user/.config/systemd/user/some.d/mine.conf', '/home/user/.config/systemd/user/some.d/.#file'], + \ 'systemd': ['any/systemd/file.automount', 'any/systemd/file.mount', 'any/systemd/file.path', 'any/systemd/file.service', 'any/systemd/file.socket', 'any/systemd/file.swap', 'any/systemd/file.target', 'any/systemd/file.timer', '/etc/systemd/system/some.d/file.conf', '/etc/systemd/system/some.d/.#file', '/etc/systemd/system/.#otherfile', '/home/user/.config/systemd/user/some.d/mine.conf', '/home/user/.config/systemd/user/some.d/.#file', '/home/user/.config/systemd/user/.#otherfile'], \ 'systemverilog': ['file.sv', 'file.svh'], \ 'tags': ['tags'], \ 'tak': ['file.tak'], diff --git a/src/version.c b/src/version.c index df2fd1f552..e90c88465c 100644 --- a/src/version.c +++ b/src/version.c @@ -746,6 +746,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 663, /**/ 662, /**/ From 8dbafd0790eeaf8743298cccdbc2a13be52517b9 Mon Sep 17 00:00:00 2001 From: Bram Moolenaar <Bram@vim.org> Date: Wed, 29 Apr 2020 23:11:32 +0200 Subject: [PATCH 058/230] patch 8.2.0664: included undesired changes in Makefile Problem: Included undesired changes in Makefile. Solution: Revert the changes. --- src/Makefile | 22 +++++++++++----------- src/version.c | 2 ++ 2 files changed, 13 insertions(+), 11 deletions(-) diff --git a/src/Makefile b/src/Makefile index 0e1ac77050..1f7095d0d4 100644 --- a/src/Makefile +++ b/src/Makefile @@ -404,7 +404,7 @@ CClink = $(CC) # Use --with-luajit if you want to use LuaJIT instead of Lua. # Set PATH environment variable to find lua or luajit executable. # This requires at least "normal" features, "tiny" and "small" don't work. -CONF_OPT_LUA = --enable-luainterp +#CONF_OPT_LUA = --enable-luainterp #CONF_OPT_LUA = --enable-luainterp=dynamic #CONF_OPT_LUA = --enable-luainterp --with-luajit #CONF_OPT_LUA = --enable-luainterp=dynamic --with-luajit @@ -433,7 +433,7 @@ CONF_OPT_LUA = --enable-luainterp # When you get an error for a missing "perl.exp" file, try creating an empty # one: "touch perl.exp". # This requires at least "normal" features, "tiny" and "small" don't work. -CONF_OPT_PERL = --enable-perlinterp +#CONF_OPT_PERL = --enable-perlinterp #CONF_OPT_PERL = --enable-perlinterp=dynamic # PYTHON @@ -447,10 +447,10 @@ CONF_OPT_PERL = --enable-perlinterp # dlopen(), dlsym(), dlclose(), i.e. pythonX.Y.so must be available # However, this may still cause problems, such as "import termios" failing. # Build two separate versions of Vim in that case. -CONF_OPT_PYTHON = --enable-pythoninterp +#CONF_OPT_PYTHON = --enable-pythoninterp #CONF_OPT_PYTHON = --enable-pythoninterp --with-python-command=python2.7 #CONF_OPT_PYTHON = --enable-pythoninterp=dynamic -CONF_OPT_PYTHON3 = --enable-python3interp +#CONF_OPT_PYTHON3 = --enable-python3interp #CONF_OPT_PYTHON3 = --enable-python3interp --with-python3-command=python3.6 #CONF_OPT_PYTHON3 = --enable-python3interp=dynamic @@ -460,19 +460,19 @@ CONF_OPT_PYTHON3 = --enable-python3interp # Note: you need the development package (e.g., ruby1.9.1-dev on Ubuntu). # This requires at least "normal" features, "tiny" and "small" don't work. #CONF_OPT_RUBY = --enable-rubyinterp -CONF_OPT_RUBY = --enable-rubyinterp=dynamic +#CONF_OPT_RUBY = --enable-rubyinterp=dynamic #CONF_OPT_RUBY = --enable-rubyinterp --with-ruby-command=ruby1.9.1 # TCL # Uncomment this when you want to include the Tcl interface. # First one is for static linking, second one for dynamic loading. #CONF_OPT_TCL = --enable-tclinterp -CONF_OPT_TCL = --enable-tclinterp=dynamic +#CONF_OPT_TCL = --enable-tclinterp=dynamic #CONF_OPT_TCL = --enable-tclinterp --with-tclsh=tclsh8.4 # CSCOPE # Uncomment this when you want to include the Cscope interface. -CONF_OPT_CSCOPE = --enable-cscope +#CONF_OPT_CSCOPE = --enable-cscope # NETBEANS - NetBeans interface. Only works with Motif, GTK, and gnome. # Motif version must have XPM libraries (see |netbeans-xpm|). @@ -540,7 +540,7 @@ CONF_OPT_CSCOPE = --enable-cscope #CONF_OPT_FEAT = --with-features=small #CONF_OPT_FEAT = --with-features=normal #CONF_OPT_FEAT = --with-features=big -CONF_OPT_FEAT = --with-features=huge +#CONF_OPT_FEAT = --with-features=huge # COMPILED BY - For including a specific e-mail address for ":version". #CONF_OPT_COMPBY = "--with-compiledby=John Doe <JohnDoe@yahoo.com>" @@ -614,7 +614,7 @@ CONF_OPT_FEAT = --with-features=huge # Use this with GCC to check for mistakes, unused arguments, etc. # Note: If you use -Wextra and get warnings in GTK code about function # parameters, you can add -Wno-cast-function-type -CFLAGS = -g -Wall -Wextra -Wshadow -Wmissing-prototypes -Wunreachable-code -Wno-cast-function-type -Wno-deprecated-declarations -U_FORTIFY_SOURCE -D_FORTIFY_SOURCE=1 +#CFLAGS = -g -Wall -Wextra -Wshadow -Wmissing-prototypes -Wunreachable-code -Wno-cast-function-type -Wno-deprecated-declarations -U_FORTIFY_SOURCE -D_FORTIFY_SOURCE=1 # Add -Wpedantic to find // comments and other C99 constructs. # Better disable Perl and Python to avoid a lot of warnings. #CFLAGS = -g -Wall -Wextra -Wshadow -Wmissing-prototypes -Wpedantic -Wunreachable-code -Wunused-result -U_FORTIFY_SOURCE -D_FORTIFY_SOURCE=1 @@ -707,12 +707,12 @@ SANITIZER_LIBS = $(SANITIZER_CFLAGS) # Configuration is in the .ccmalloc or ~/.ccmalloc file. # Doesn't work very well, since memory linked to from global variables # (in libraries) is also marked as leaked memory. -LEAK_CFLAGS = -DEXITFREE +#LEAK_CFLAGS = -DEXITFREE #LEAK_LIBS = -lccmalloc # Uncomment this line to have Vim call abort() when an internal error is # detected. Useful when using a tool to find errors. -ABORT_CFLAGS = -DABORT_ON_INTERNAL_ERROR +#ABORT_CFLAGS = -DABORT_ON_INTERNAL_ERROR ##################################################### ### Specific systems, check if yours is listed! ### {{{ diff --git a/src/version.c b/src/version.c index e90c88465c..6f838573ab 100644 --- a/src/version.c +++ b/src/version.c @@ -746,6 +746,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 664, /**/ 663, /**/ From a161cb5dddd6d374899e46fde834ce9ba5c80c0b Mon Sep 17 00:00:00 2001 From: Bram Moolenaar <Bram@vim.org> Date: Thu, 30 Apr 2020 19:09:35 +0200 Subject: [PATCH 059/230] patch 8.2.0665: wrongly assuming Python executable is called "python" Problem: Wrongly assuming Python executable is called "python". Solution: Use detected python command. (Ken Takata, closes #6016) Also use CheckFunction if possible. --- src/testdir/check.vim | 8 ++++++++ src/testdir/test_terminal.vim | 28 +++++++++++++--------------- src/version.c | 2 ++ 3 files changed, 23 insertions(+), 15 deletions(-) diff --git a/src/testdir/check.vim b/src/testdir/check.vim index efb273b005..2a4599763f 100644 --- a/src/testdir/check.vim +++ b/src/testdir/check.vim @@ -52,6 +52,14 @@ func CheckExecutable(name) endif endfunc +" Command to check for the presence of python. Argument should have been +" obtained with PythonProg() +func CheckPython(name) + if a:name == '' + throw 'Skipped: python command not available' + endif +endfunc + " Command to check for running on MS-Windows command CheckMSWindows call CheckMSWindows() func CheckMSWindows() diff --git a/src/testdir/test_terminal.vim b/src/testdir/test_terminal.vim index d682a1975d..49bce73755 100644 --- a/src/testdir/test_terminal.vim +++ b/src/testdir/test_terminal.vim @@ -715,10 +715,10 @@ func Test_terminal_write_stdin() endfunc func Test_terminal_eof_arg() - CheckExecutable python + call CheckPython(s:python) call setline(1, ['print("hello")']) - 1term ++eof=exit(123) python + exe '1term ++eof=exit(123) ' .. s:python " MS-Windows echoes the input, Unix doesn't. if has('win32') call WaitFor({-> getline('$') =~ 'exit(123)'}) @@ -733,22 +733,22 @@ endfunc func Test_terminal_eof_arg_win32_ctrl_z() CheckMSWindows - CheckExecutable python + call CheckPython(s:python) call setline(1, ['print("hello")']) - 1term ++eof=<C-Z> python + exe '1term ++eof=<C-Z> ' .. s:python call WaitForAssert({-> assert_match('\^Z', getline(line('$') - 1))}) call assert_match('\^Z', getline(line('$') - 1)) %bwipe! endfunc func Test_terminal_duplicate_eof_arg() - CheckExecutable python + call CheckPython(s:python) " Check the last specified ++eof arg is used and should not memory leak. new call setline(1, ['print("hello")']) - 1term ++eof=<C-Z> ++eof=exit(123) python + exe '1term ++eof=<C-Z> ++eof=exit(123) ' .. s:python " MS-Windows echoes the input, Unix doesn't. if has('win32') call WaitFor({-> getline('$') =~ 'exit(123)'}) @@ -1571,9 +1571,8 @@ func Test_terminal_api_call_fail_delete() endfunc func Test_terminal_ansicolors_default() - if !exists('*term_getansicolors') - throw 'Skipped: term_getansicolors() not supported' - endif + CheckFunction term_getansicolors + let colors = [ \ '#000000', '#e00000', \ '#00e000', '#e0e000', @@ -1606,9 +1605,8 @@ let s:test_colors = [ func Test_terminal_ansicolors_global() CheckFeature termguicolors - if !exists('*term_getansicolors') - throw 'Skipped: term_getansicolors() not supported' - endif + CheckFunction term_getansicolors + let g:terminal_ansi_colors = reverse(copy(s:test_colors)) let buf = Run_shell_in_terminal({}) call assert_equal(g:terminal_ansi_colors, term_getansicolors(buf)) @@ -1621,9 +1619,8 @@ endfunc func Test_terminal_ansicolors_func() CheckFeature termguicolors - if !exists('*term_getansicolors') - throw 'Skipped: term_getansicolors() not supported' - endif + CheckFunction term_getansicolors + let g:terminal_ansi_colors = reverse(copy(s:test_colors)) let buf = Run_shell_in_terminal({'ansi_colors': s:test_colors}) call assert_equal(s:test_colors, term_getansicolors(buf)) @@ -2588,6 +2585,7 @@ func Test_hidden_terminal() endfunc func Test_term_nasty_callback() + CheckExecutable sh func OpenTerms() set hidden let g:buf0 = term_start('sh', #{hidden: 1}) diff --git a/src/version.c b/src/version.c index 6f838573ab..a04f4b3f31 100644 --- a/src/version.c +++ b/src/version.c @@ -746,6 +746,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 665, /**/ 664, /**/ From 88e6cc253903c86d06abb59b35c85e6aef0152f3 Mon Sep 17 00:00:00 2001 From: Bram Moolenaar <Bram@vim.org> Date: Thu, 30 Apr 2020 19:19:29 +0200 Subject: [PATCH 060/230] patch 8.2.0666: Ruby test fails on MS-Windows Problem: Ruby test fails on MS-Windows. Solution: Remove the "maintainer" line. (Ken Takata, closes #6015) --- src/testdir/shared.vim | 12 ++++++++++++ src/testdir/test_messages.vim | 12 ------------ src/testdir/test_ruby.vim | 4 ++-- src/version.c | 2 ++ 4 files changed, 16 insertions(+), 14 deletions(-) diff --git a/src/testdir/shared.vim b/src/testdir/shared.vim index 239051e154..fda4d03e6b 100644 --- a/src/testdir/shared.vim +++ b/src/testdir/shared.vim @@ -338,4 +338,16 @@ func IsRoot() return v:false endfunc +" Get all messages but drop the maintainer entry. +func GetMessages() + redir => result + redraw | messages + redir END + let msg_list = split(result, "\n") + if msg_list->len() > 0 && msg_list[0] =~ 'Messages maintainer:' + return msg_list[1:] + endif + return msg_list +endfunc + " vim: shiftwidth=2 sts=2 expandtab diff --git a/src/testdir/test_messages.vim b/src/testdir/test_messages.vim index 5a2c64cb74..e076241607 100644 --- a/src/testdir/test_messages.vim +++ b/src/testdir/test_messages.vim @@ -3,18 +3,6 @@ source shared.vim source term_util.vim -" Get all messages but drop the maintainer entry. -func GetMessages() - redir => result - redraw | messages - redir END - let msg_list = split(result, "\n") - if msg_list->len() > 0 && msg_list[0] =~ 'Messages maintainer:' - return msg_list[1:] - endif - return msg_list -endfunc - func Test_messages() let oldmore = &more try diff --git a/src/testdir/test_ruby.vim b/src/testdir/test_ruby.vim index c816fad8af..100c9ea0fb 100644 --- a/src/testdir/test_ruby.vim +++ b/src/testdir/test_ruby.vim @@ -378,7 +378,7 @@ endfunc func Test_ruby_p() ruby p 'Just a test' - let messages = split(execute('message'), "\n") + let messages = GetMessages() call assert_equal('"Just a test"', messages[-1]) " Check return values of p method @@ -391,7 +391,7 @@ func Test_ruby_p() messages clear call assert_equal(v:true, rubyeval('p() == nil')) - let messages = split(execute('message'), "\n") + let messages = GetMessages() call assert_equal(0, len(messages)) endfunc diff --git a/src/version.c b/src/version.c index a04f4b3f31..7a563d145b 100644 --- a/src/version.c +++ b/src/version.c @@ -746,6 +746,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 666, /**/ 665, /**/ From 2c5c1638a9fe2ef34f2fd09ed69e10ef2e821f0a Mon Sep 17 00:00:00 2001 From: Bram Moolenaar <Bram@vim.org> Date: Thu, 30 Apr 2020 19:54:38 +0200 Subject: [PATCH 061/230] patch 8.2.0667: cannot install Haiku version from source Problem: Cannot install Haiku version from source. Solution: Update Makefile and rdef file. (Emir Sari, closes #6013) --- Filelist | 2 +- READMEdir/README_haiku.txt | 2 +- runtime/doc/os_haiku.txt | 32 +++++++++++++------------ src/Makefile | 12 ++++++++-- src/{os_haiku.rdef => os_haiku.rdef.in} | 3 +-- src/version.c | 2 ++ 6 files changed, 32 insertions(+), 21 deletions(-) rename src/{os_haiku.rdef => os_haiku.rdef.in} (99%) diff --git a/Filelist b/Filelist index ef65b8da24..7090efc929 100644 --- a/Filelist +++ b/Filelist @@ -610,7 +610,7 @@ SRC_AMI = \ SRC_HAIKU = \ README_haiku.txt \ src/os_haiku.h \ - src/os_haiku.rdef \ + src/os_haiku.rdef.in \ src/gui_haiku.cc \ src/gui_haiku.h \ src/proto/gui_haiku.pro \ diff --git a/READMEdir/README_haiku.txt b/READMEdir/README_haiku.txt index 7eeb0bbf37..860b40b0d7 100644 --- a/READMEdir/README_haiku.txt +++ b/READMEdir/README_haiku.txt @@ -10,4 +10,4 @@ software repository HaikuPorts. To get Vim: - Open a Terminal and type "pkgman install vim", then follow instructions. If you prefer to install Vim from source, follow the instructions on -"runtime/doc/os_haiku.txt", "Compiling Haiku" section. +"runtime/doc/os_haiku.txt", "Compiling Vim" section. diff --git a/runtime/doc/os_haiku.txt b/runtime/doc/os_haiku.txt index 2c02994d50..1ca338441d 100644 --- a/runtime/doc/os_haiku.txt +++ b/runtime/doc/os_haiku.txt @@ -1,4 +1,4 @@ -*os_haiku.txt* For Vim version 8.2. Last change: 2020 Mar 19 +*os_haiku.txt* For Vim version 8.2. Last change: 2020 Apr 30 VIM REFERENCE MANUAL by Bram Moolenaar @@ -46,12 +46,11 @@ features you can enable/disable. Haiku uses "ncurses6" as its terminal library, therefore you need to have "ncurses6_devel" package installed from HaikuDepot in order to configure -the Haiku build. Just append "--with-tlib=ncurses6" to ./configure command -below for the initial build. +the Haiku build. Just append "--with-tlib=ncurses6" to ./configure command Now you should use "make" to compile Vim, then "make install" to install it. For seamless integration into Haiku, the GUI-less vim binary should be -additionally installed over the GUI version. Typical build commands are: > +additionally installed over the GUI version. Typical build commands are: ./configure --prefix=`finddir B_SYSTEM_NONPACKAGED_DIRECTORY` \ --datarootdir=`finddir B_SYSTEM_NONPACKAGED_DATA_DIRECTORY` \ @@ -71,25 +70,28 @@ additionally installed over the GUI version. Typical build commands are: > Normally Vim starts with the GUI if you start it as gvim or vim -g. The vim version with GUI tries to determine if it was started from the Tracker instead -of the Terminal, and if so, uses the GUI anyway. However, the current detection +of the Terminal, and if so, uses the GUI anyway. However, the current detection scheme is fooled if you use the command "vim - </dev/null". Stuff that does not work yet: -- Mouse up events are not generated when outside the window. This may be a bug in - Haiku. You can notice this when selecting text and moving the cursor outside - the window, then letting go of the mouse button. Another way is when you - drag the scrollbar and do the same thing. Because Vim still thinks you are - still playing with the scrollbar it won't change it itself. I provided a - workaround which kicks in when the window is activated or deactivated (so it - works best with focus- follows-mouse turned on). +- Mouse up events are not generated when outside the window. You can notice + this when selecting text and moving the cursor outside the window, then + letting go of the mouse button. Another way is when you drag the scrollbar + and do the same thing. Because Vim still thinks you are still playing with + the scrollbar it won't change it itself. There is a workaround which kicks + in when the window is activated or deactivated (so it works best with focus- + follows-mouse turned on). - The cursor does not flash. +- Built-in terminal is not available in GUI, and does not work reliably on + console version as well; e.g. it is not possible to exit using the 'exit' + command. If you need to use it, enable at your own risk. 4. The $VIM directory *haiku-vimdir* $VIM is the symbolic name for the place where Vim's support files are stored. -The default value for $VIM is set at compile time and can be determined with > +The default value for $VIM is set at compile time and can be determined with: :version @@ -117,7 +119,7 @@ The normal value is /boot/home/config/settings. You can drop files and directories on either the Vim icon (starts a new Vim session, unless you use the File Types application to set Vim to be "Single Launch") or on the Vim window (starts editing the files). Dropping a folder -sets Vim's current working directory. |:cd| |:pwd| If you drop files or +sets Vim's current working directory |:cd| |:pwd|. If you drop files or folders with either SHIFT key pressed, Vim changes directory to the folder that contains the first item dropped. When starting Vim, there is no need to press shift: Vim behaves as if you do. @@ -164,7 +166,7 @@ isn't a dotted-y, then for this font the encoding does not work. If the font you specify is unavailable, you get the system fixed font. -GUI Font Selection Dialog is available at giving the > +GUI Font Selection Dialog is available at giving the: :set guifont=* diff --git a/src/Makefile b/src/Makefile index 1f7095d0d4..12ec23cb26 100644 --- a/src/Makefile +++ b/src/Makefile @@ -2885,7 +2885,7 @@ uninstall_runtime: clean celan: testclean -rm -f *.o core $(VIMTARGET).core $(VIMTARGET) vim xxd/*.o -rm -rf objects - -rm -f $(TOOLS) auto/osdef.h auto/pathdef.c auto/if_perl.c auto/gui_gtk_gresources.c auto/gui_gtk_gresources.h + -rm -f $(TOOLS) auto/osdef.h auto/pathdef.c auto/if_perl.c auto/gui_gtk_gresources.c auto/gui_gtk_gresources.h auto/os_haiku.rdef -rm -f conftest* *~ auto/link.sed -rm -f testdir/opt_test.vim -rm -f $(UNITTEST_TARGETS) @@ -3042,6 +3042,14 @@ auto/if_perl.c: if_perl.xs auto/osdef.h: auto/config.h osdef.sh osdef1.h.in osdef2.h.in CC="$(CC) $(OSDEF_CFLAGS)" srcdir=$(srcdir) sh $(srcdir)/osdef.sh +auto/os_haiku.rdef: os_haiku.rdef.in + @echo creating $@ + @echo '/* This file is automatically created by Makefile */' >> $@ + @echo '/* DO NOT EDIT! Change Makefile only. */' >> $@ + @cat $(srcdir)/os_haiku.rdef.in >> auto/os_haiku.rdef + sed -i "s|@MAJOR@|$(VIMMAJOR)|" auto/os_haiku.rdef + sed -i "s|@MINOR@|$(VIMMINOR)|" auto/os_haiku.rdef + auto/pathdef.c: Makefile auto/config.mk -@echo creating $@ -@echo '/* pathdef.c */' > $@ @@ -3384,7 +3392,7 @@ objects/os_beos.o: os_beos.c objects/os_qnx.o: os_qnx.c $(CCC) -o $@ os_qnx.c -objects/os_haiku.rsrc: os_haiku.rdef +objects/os_haiku.rsrc: auto/os_haiku.rdef cat $< | $(CCC) -E - | grep -v '^#' | rc -o "$@" - objects/os_macosx.o: os_macosx.m diff --git a/src/os_haiku.rdef b/src/os_haiku.rdef.in similarity index 99% rename from src/os_haiku.rdef rename to src/os_haiku.rdef.in index bf55aa9a9b..64ba9f4a10 100644 --- a/src/os_haiku.rdef +++ b/src/os_haiku.rdef.in @@ -1,12 +1,11 @@ /* - * os_haiku.rdef + * os_haiku.rdef.in: Assets and resources file for Haiku */ resource app_signature "application/x-vnd.Haiku-Vim-8"; resource app_version { major = @MAJOR@, - middle = @MIDDLE@, minor = @MINOR@, variety = B_APPV_FINAL, diff --git a/src/version.c b/src/version.c index 7a563d145b..c57ef87155 100644 --- a/src/version.c +++ b/src/version.c @@ -746,6 +746,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 667, /**/ 666, /**/ From 7f6f56f43c48f0b7288a4edd12b59fa7335f01d3 Mon Sep 17 00:00:00 2001 From: Bram Moolenaar <Bram@vim.org> Date: Thu, 30 Apr 2020 20:21:43 +0200 Subject: [PATCH 062/230] patch 8.2.0668: compiler warning for int/size_t usage Problem: Compiler warning for int/size_t usage. Solution: Change "int" to "size_t". (Mike Williams) --- src/version.c | 2 ++ src/vim9execute.c | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/src/version.c b/src/version.c index c57ef87155..7382a3dbdf 100644 --- a/src/version.c +++ b/src/version.c @@ -746,6 +746,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 668, /**/ 667, /**/ diff --git a/src/vim9execute.c b/src/vim9execute.c index 5251d48486..3cb8628c55 100644 --- a/src/vim9execute.c +++ b/src/vim9execute.c @@ -653,7 +653,7 @@ call_def_function( case ISN_EXECCONCAT: { int count = iptr->isn_arg.number; - int len = 0; + size_t len = 0; int pass; int i; char_u *cmd = NULL; From 4e5534fab798ab7c95554da3bc80b08336aedc2b Mon Sep 17 00:00:00 2001 From: Bram Moolenaar <Bram@vim.org> Date: Thu, 30 Apr 2020 20:59:57 +0200 Subject: [PATCH 063/230] patch 8.2.0669: MS-Windows: display in VTP is a bit slow Problem: MS-Windows: display in VTP is a bit slow. Solution: Optimize the code. (Nobuhiro Takasaki, closes #6014) --- src/os_win32.c | 407 ++++++++++++++++++++++++++++++++++++++++++------- src/screen.c | 29 ++++ src/version.c | 2 + 3 files changed, 387 insertions(+), 51 deletions(-) diff --git a/src/os_win32.c b/src/os_win32.c index e4d8135ca3..52bc95de88 100644 --- a/src/os_win32.c +++ b/src/os_win32.c @@ -5579,12 +5579,14 @@ clear_chars( COORD coord, DWORD n) { - DWORD dwDummy; - - FillConsoleOutputCharacter(g_hConOut, ' ', n, coord, &dwDummy); - if (!USE_VTP) - FillConsoleOutputAttribute(g_hConOut, g_attrCurrent, n, coord, &dwDummy); + { + DWORD dwDummy; + + FillConsoleOutputCharacter(g_hConOut, ' ', n, coord, &dwDummy); + FillConsoleOutputAttribute(g_hConOut, g_attrCurrent, n, coord, + &dwDummy); + } else { set_console_color_rgb(); @@ -6036,23 +6038,57 @@ write_chars( { COORD coord = g_coord; DWORD written; - DWORD n, cchwritten, cells; + DWORD n, cchwritten; + static DWORD cells; static WCHAR *unicodebuf = NULL; static int unibuflen = 0; - int length; + static int length; int cp = enc_utf8 ? CP_UTF8 : enc_codepage; + static WCHAR *utf8spbuf = NULL; + static int utf8splength; + static DWORD utf8spcells; + static WCHAR **utf8usingbuf = &unicodebuf; - length = MultiByteToWideChar(cp, 0, (LPCSTR)pchBuf, cbToWrite, 0, 0); - if (unicodebuf == NULL || length > unibuflen) + if (cbToWrite != 1 || *pchBuf != ' ' || !enc_utf8) { - vim_free(unicodebuf); - unicodebuf = LALLOC_MULT(WCHAR, length); - unibuflen = length; + utf8usingbuf = &unicodebuf; + do + { + length = MultiByteToWideChar(cp, 0, (LPCSTR)pchBuf, cbToWrite, + unicodebuf, unibuflen); + if (length && length <= unibuflen) + break; + vim_free(unicodebuf); + unicodebuf = length ? LALLOC_MULT(WCHAR, length) : NULL; + unibuflen = unibuflen ? 0 : length; + } while(1); + cells = mb_string2cells(pchBuf, cbToWrite); + } + else // cbToWrite == 1 && *pchBuf == ' ' && enc_utf8 + { + if (utf8usingbuf != &utf8spbuf) + { + if (utf8spbuf == NULL) + { + cells = mb_string2cells((char_u *)" ", 1); + length = MultiByteToWideChar(CP_UTF8, 0, " ", 1, NULL, 0); + utf8spbuf = LALLOC_MULT(WCHAR, length); + if (utf8spbuf != NULL) + { + MultiByteToWideChar(CP_UTF8, 0, " ", 1, utf8spbuf, length); + utf8usingbuf = &utf8spbuf; + utf8splength = length; + utf8spcells = cells; + } + } + else + { + utf8usingbuf = &utf8spbuf; + length = utf8splength; + cells = utf8spcells; + } + } } - MultiByteToWideChar(cp, 0, (LPCSTR)pchBuf, cbToWrite, - unicodebuf, unibuflen); - - cells = mb_string2cells(pchBuf, cbToWrite); if (!USE_VTP) { @@ -6060,14 +6096,14 @@ write_chars( coord, &written); // When writing fails or didn't write a single character, pretend one // character was written, otherwise we get stuck. - if (WriteConsoleOutputCharacterW(g_hConOut, unicodebuf, length, + if (WriteConsoleOutputCharacterW(g_hConOut, *utf8usingbuf, length, coord, &cchwritten) == 0 || cchwritten == 0 || cchwritten == (DWORD)-1) cchwritten = 1; } else { - if (WriteConsoleW(g_hConOut, unicodebuf, length, &cchwritten, + if (WriteConsoleW(g_hConOut, *utf8usingbuf, length, &cchwritten, NULL) == 0 || cchwritten == 0) cchwritten = 1; } @@ -6093,11 +6129,119 @@ write_chars( g_coord.Y++; } - gotoxy(g_coord.X + 1, g_coord.Y + 1); + // Cursor under VTP is always in the correct position, no need to reset. + if (!USE_VTP) + gotoxy(g_coord.X + 1, g_coord.Y + 1); return written; } + static char_u * +get_seq( + int *args, + int *count, + char_u *head) +{ + int argc; + char_u *p; + + if (head == NULL || *head != '\033') + return NULL; + + argc = 0; + p = head; + ++p; + do + { + ++p; + args[argc] = getdigits(&p); + argc += (argc < 15) ? 1 : 0; + } while (*p == ';'); + *count = argc; + + return p; +} + + static char_u * +get_sgr( + int *args, + int *count, + char_u *head) +{ + char_u *p = get_seq(args, count, head); + + return (p && *p == 'm') ? ++p : NULL; +} + +/* + * Pointer to next if SGR (^[[n;2;*;*;*m), NULL otherwise. + */ + static char_u * +sgrn2( + char_u *head, + int n) +{ + int argc; + int args[16]; + char_u *p = get_sgr(args, &argc, head); + + return p && argc == 5 && args[0] == n && args[1] == 2 ? p : NULL; +} + +/* + * Pointer to next if SGR(^[[nm)<space>ESC, NULL otherwise. + */ + static char_u * +sgrnc( + char_u *head, + int n) +{ + int argc; + int args[16]; + char_u *p = get_sgr(args, &argc, head); + + return p && argc == 1 && args[0] == n && (p = skipwhite(p)) && *p == '\033' + ? p : NULL; +} + + static char_u * +skipblank(char_u *q) +{ + char_u *p = q; + + while (*p == ' ' || *p == '\t' || *p == '\n' || *p == '\r') + ++p; + return p; +} + +/* + * Pointer to the next if any whitespace that may follow SGR is ESC, otherwise + * NULL. + */ + static char_u * +sgrn2c( + char_u *head, + int n) +{ + char_u *p = sgrn2(head, n); + + return p && *p != NUL && (p = skipblank(p)) && *p == '\033' ? p : NULL; +} + +/* + * If there is only a newline between the sequence immediately following it, + * a pointer to the character following the newline is returned. + * Otherwise NULL. + */ + static char_u * +sgrn2cn( + char_u *head, + int n) +{ + char_u *p = sgrn2(head, n); + + return p && p[0] == 0x0a && p[1] == '\033' ? ++p : NULL; +} /* * mch_write(): write the output buffer to the screen, translating ESC @@ -6124,9 +6268,21 @@ mch_write( // translate ESC | sequences into faked bios calls while (len--) { - // optimization: use one single write_chars for runs of text, - // rather than once per character It ain't curses, but it helps. - DWORD prefix = (DWORD)strcspn((char *)s, "\n\r\b\a\033"); + int prefix = -1; + char_u ch; + + // While processing a sequence, on rare occasions it seems that another + // sequence may be inserted asynchronously. + if (len < 0) + { + redraw_all_later(CLEAR); + return; + } + + while((ch = s[++prefix])) + if (ch <= 0x1e && !(ch != '\n' && ch != '\r' && ch != '\b' + && ch != '\a' && ch != '\033')) + break; if (p_wd) { @@ -6213,24 +6369,52 @@ mch_write( # endif char_u *p; int arg1 = 0, arg2 = 0, argc = 0, args[16]; + char_u *sp; switch (s[2]) { case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': - p = s + 1; - do + if (*(p = get_seq(args, &argc, s)) != 'm') + goto notsgr; + + p = s; + + // Handling frequent optional sequences. Output to the screen + // takes too long, so do not output as much as possible. + + // If resetFG,FG,BG,<cr>,BG,FG are connected, the preceding + // resetFG,FG,BG are omitted. + if (sgrn2(sgrn2(sgrn2cn(sgrn2(sgrnc(p, 39), 38), 48), 48), 38)) { - ++p; - args[argc] = getdigits(&p); - argc += (argc < 15) ? 1 : 0; - if (p > s + len) - break; - } while (*p == ';'); - - if (p > s + len) + p = sgrn2(sgrn2(sgrnc(p, 39), 38), 48); + len = len + 1 - (int)(p - s); + s = p; break; + } + // If FG,BG,BG,FG of SGR are connected, the first FG can be + // omitted. + if (sgrn2(sgrn2(sgrn2c((sp = sgrn2(p, 38)), 48), 48), 38)) + p = sp; + + // If FG,BG,FG,BG of SGR are connected, the first FG can be + // omitted. + if (sgrn2(sgrn2(sgrn2c((sp = sgrn2(p, 38)), 48), 38), 48)) + p = sp; + + // If BG,BG of SGR are connected, the first BG can be omitted. + if (sgrn2((sp = sgrn2(p, 48)), 48)) + p = sp; + + // If restoreFG and FG are connected, the restoreFG can be + // omitted. + if (sgrn2((sp = sgrnc(p, 39)), 38)) + p = sp; + + p = get_seq(args, &argc, p); + +notsgr: arg1 = args[0]; arg2 = args[1]; if (*p == 'm') @@ -7406,11 +7590,12 @@ vtp_printf( char_u buf[100]; va_list list; DWORD result; + int len; va_start(list, format); - vim_vsnprintf((char *)buf, 100, (char *)format, list); + len = vim_vsnprintf((char *)buf, 100, (char *)format, list); va_end(list); - WriteConsoleA(g_hConOut, buf, (DWORD)STRLEN(buf), &result, NULL); + WriteConsoleA(g_hConOut, buf, (DWORD)len, &result, NULL); return (int)result; } @@ -7424,30 +7609,150 @@ vtp_sgr_bulk( vtp_sgr_bulks(1, args); } +#define FAST256(x) \ + if ((*p-- = "0123456789"[(n = x % 10)]) \ + && x >= 10 && (*p-- = "0123456789"[((m = x % 100) - n) / 10]) \ + && x >= 100 && (*p-- = "012"[((x & 0xff) - m) / 100])); + +#define FAST256CASE(x) \ + case x: \ + FAST256(newargs[x - 1]); + static void vtp_sgr_bulks( int argc, - int *args -) + int *args) { - // 2('\033[') + 4('255.') * 16 + NUL - char_u buf[2 + (4 * 16) + 1]; - char_u *p; - int i; +#define MAXSGR 16 +#define SGRBUFSIZE 2 + 4 * MAXSGR + 1 // '\033[' + SGR + 'm' + char_u buf[SGRBUFSIZE]; + char_u *p; + int in, out; + int newargs[16]; + static int sgrfgr = -1, sgrfgg, sgrfgb; + static int sgrbgr = -1, sgrbgg, sgrbgb; - p = buf; - *p++ = '\033'; - *p++ = '['; - - for (i = 0; i < argc; ++i) + if (argc == 0) { - p += vim_snprintf((char *)p, 4, "%d", args[i] & 0xff); - *p++ = ';'; + sgrfgr = sgrbgr = -1; + vtp_printf("033[m"); + return; + } + + in = out = 0; + while (in < argc) + { + int s = args[in]; + int copylen = 1; + + if (s == 38) + { + if (argc - in >= 5 && args[in + 1] == 2) + { + if (sgrfgr == args[in + 2] && sgrfgg == args[in + 3] + && sgrfgb == args[in + 4]) + { + in += 5; + copylen = 0; + } + else + { + sgrfgr = args[in + 2]; + sgrfgg = args[in + 3]; + sgrfgb = args[in + 4]; + copylen = 5; + } + } + else if (argc - in >= 3 && args[in + 1] == 5) + { + sgrfgr = -1; + copylen = 3; + } + } + else if (s == 48) + { + if (argc - in >= 5 && args[in + 1] == 2) + { + if (sgrbgr == args[in + 2] && sgrbgg == args[in + 3] + && sgrbgb == args[in + 4]) + { + in += 5; + copylen = 0; + } + else + { + sgrbgr = args[in + 2]; + sgrbgg = args[in + 3]; + sgrbgb = args[in + 4]; + copylen = 5; + } + } + else if (argc - in >= 3 && args[in + 1] == 5) + { + sgrbgr = -1; + copylen = 3; + } + } + else if (30 <= s && s <= 39) + sgrfgr = -1; + else if (90 <= s && s <= 97) + sgrfgr = -1; + else if (40 <= s && s <= 49) + sgrbgr = -1; + else if (100 <= s && s <= 107) + sgrbgr = -1; + else if (s == 0) + sgrfgr = sgrbgr = -1; + + while (copylen--) + newargs[out++] = args[in++]; + } + + p = &buf[sizeof(buf) - 1]; + *p-- = 'm'; + + switch (out) + { + int n, m; + DWORD r; + + FAST256CASE(16); + *p-- = ';'; + FAST256CASE(15); + *p-- = ';'; + FAST256CASE(14); + *p-- = ';'; + FAST256CASE(13); + *p-- = ';'; + FAST256CASE(12); + *p-- = ';'; + FAST256CASE(11); + *p-- = ';'; + FAST256CASE(10); + *p-- = ';'; + FAST256CASE(9); + *p-- = ';'; + FAST256CASE(8); + *p-- = ';'; + FAST256CASE(7); + *p-- = ';'; + FAST256CASE(6); + *p-- = ';'; + FAST256CASE(5); + *p-- = ';'; + FAST256CASE(4); + *p-- = ';'; + FAST256CASE(3); + *p-- = ';'; + FAST256CASE(2); + *p-- = ';'; + FAST256CASE(1); + *p-- = '['; + *p = '\033'; + WriteConsoleA(g_hConOut, p, (DWORD)(&buf[SGRBUFSIZE] - p), &r, NULL); + default: + break; } - p--; - *p++ = 'm'; - *p = NUL; - vtp_printf((char *)buf); } # ifdef FEAT_TERMGUICOLORS diff --git a/src/screen.c b/src/screen.c index 845c5b2103..09aa10f0bc 100644 --- a/src/screen.c +++ b/src/screen.c @@ -1880,6 +1880,9 @@ screen_start_highlight(int attr) screen_stop_highlight(void) { int do_ME = FALSE; // output T_ME code +#if defined(FEAT_VTP) && defined(FEAT_TERMGUICOLORS) + int do_ME_fg, do_ME_bg; +#endif if (screen_attr != 0 #ifdef MSWIN @@ -1913,16 +1916,42 @@ screen_stop_highlight(void) #ifdef FEAT_TERMGUICOLORS p_tgc && aep->ae_u.cterm.fg_rgb != CTERMCOLOR ? aep->ae_u.cterm.fg_rgb != INVALCOLOR +# ifdef FEAT_VTP + ? !(do_ME_fg = TRUE) : (do_ME_fg = FALSE) +# endif : #endif aep->ae_u.cterm.fg_color) || ( #ifdef FEAT_TERMGUICOLORS p_tgc && aep->ae_u.cterm.bg_rgb != CTERMCOLOR ? aep->ae_u.cterm.bg_rgb != INVALCOLOR +# ifdef FEAT_VTP + ? !(do_ME_bg = TRUE) : (do_ME_bg = FALSE) +# endif : #endif aep->ae_u.cterm.bg_color))) do_ME = TRUE; +#if defined(FEAT_VTP) && defined(FEAT_TERMGUICOLORS) + if (use_vtp()) + { + if (do_ME_fg && do_ME_bg) + do_ME = TRUE; + + // FG and BG cannot be separated in T_ME, which is not + // efficient. + if (!do_ME && do_ME_fg) + out_str((char_u *)"\033|39m"); // restore FG + if (!do_ME && do_ME_bg) + out_str((char_u *)"\033|49m"); // restore BG + } + else + { + // Process FG and BG at once. + if (!do_ME) + do_ME = do_ME_fg | do_ME_bg; + } +#endif } else { diff --git a/src/version.c b/src/version.c index 7382a3dbdf..6b3a1596aa 100644 --- a/src/version.c +++ b/src/version.c @@ -746,6 +746,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 669, /**/ 668, /**/ From 6adb9ea0a6ca01414f4b591f379b0f829a8273c0 Mon Sep 17 00:00:00 2001 From: Bram Moolenaar <Bram@vim.org> Date: Thu, 30 Apr 2020 22:31:18 +0200 Subject: [PATCH 064/230] patch 8.2.0670: cannot change window when evaluating 'completefunc' Problem: Cannot change window when evaluating 'completefunc'. Solution: Make a difference between not changing text or buffers and also not changing window. --- src/beval.c | 4 ++-- src/change.c | 4 ++-- src/edit.c | 9 +++++---- src/eval.c | 10 +++++----- src/ex_docmd.c | 2 +- src/ex_getln.c | 30 +++++++++++++++++++++--------- src/globals.h | 13 ++++++++++--- src/indent.c | 4 ++-- src/insexpand.c | 11 ++++++----- src/map.c | 4 ++-- src/proto/ex_getln.pro | 3 ++- src/register.c | 4 ++-- src/testdir/test_edit.vim | 2 +- src/testdir/test_ins_complete.vim | 2 +- src/testdir/test_popup.vim | 2 +- src/undo.c | 2 +- src/version.c | 2 ++ src/window.c | 2 +- 18 files changed, 67 insertions(+), 43 deletions(-) diff --git a/src/beval.c b/src/beval.c index 6b10a654d8..b7d9226e70 100644 --- a/src/beval.c +++ b/src/beval.c @@ -282,7 +282,7 @@ general_beval_cb(BalloonEval *beval, int state UNUSED) curbuf = save_curbuf; if (use_sandbox) ++sandbox; - ++textlock; + ++textwinlock; vim_free(result); result = eval_to_string(bexpr, NULL, TRUE); @@ -299,7 +299,7 @@ general_beval_cb(BalloonEval *beval, int state UNUSED) if (use_sandbox) --sandbox; - --textlock; + --textwinlock; set_vim_var_string(VV_BEVAL_TEXT, NULL, -1); if (result != NULL && result[0] != NUL) diff --git a/src/change.c b/src/change.c index cfba90b3ca..45d67044e6 100644 --- a/src/change.c +++ b/src/change.c @@ -382,7 +382,7 @@ invoke_listeners(buf_T *buf) argv[4].v_type = VAR_LIST; argv[4].vval.v_list = buf->b_recorded_changes; - ++textlock; + ++textwinlock; for (lnr = buf->b_listener; lnr != NULL; lnr = lnr->lr_next) { @@ -390,7 +390,7 @@ invoke_listeners(buf_T *buf) clear_tv(&rettv); } - --textlock; + --textwinlock; list_unref(buf->b_recorded_changes); buf->b_recorded_changes = NULL; diff --git a/src/edit.c b/src/edit.c index 7f4f765012..0ac63ec8fd 100644 --- a/src/edit.c +++ b/src/edit.c @@ -176,9 +176,10 @@ edit( // Don't allow changes in the buffer while editing the cmdline. The // caller of getcmdline() may get confused. // Don't allow recursive insert mode when busy with completion. - if (textlock != 0 || ins_compl_active() || compl_busy || pum_visible()) + if (textwinlock != 0 || textlock != 0 + || ins_compl_active() || compl_busy || pum_visible()) { - emsg(_(e_textlock)); + emsg(_(e_textwinlock)); return FALSE; } ins_compl_clear(); // clear stuff for CTRL-X mode @@ -5944,7 +5945,7 @@ do_insert_char_pre(int c) } // Lock the text to avoid weird things from happening. - ++textlock; + ++textwinlock; set_vim_var_string(VV_CHAR, buf, -1); // set v:char res = NULL; @@ -5958,7 +5959,7 @@ do_insert_char_pre(int c) } set_vim_var_string(VV_CHAR, NULL, -1); // clear v:char - --textlock; + --textwinlock; // Restore the State, it may have been changed. State = save_State; diff --git a/src/eval.c b/src/eval.c index 4bd45e9ceb..31dde2faed 100644 --- a/src/eval.c +++ b/src/eval.c @@ -393,7 +393,7 @@ eval_to_string( /* * Call eval_to_string() without using current local variables and using - * textlock. When "use_sandbox" is TRUE use the sandbox. + * textwinlock. When "use_sandbox" is TRUE use the sandbox. */ char_u * eval_to_string_safe( @@ -407,11 +407,11 @@ eval_to_string_safe( save_funccal(&funccal_entry); if (use_sandbox) ++sandbox; - ++textlock; + ++textwinlock; retval = eval_to_string(arg, nextcmd, FALSE); if (use_sandbox) --sandbox; - --textlock; + --textwinlock; restore_funccal(); return retval; } @@ -576,7 +576,7 @@ eval_foldexpr(char_u *arg, int *cp) ++emsg_off; if (use_sandbox) ++sandbox; - ++textlock; + ++textwinlock; *cp = NUL; if (eval0(arg, &tv, NULL, TRUE) == FAIL) retval = 0; @@ -601,7 +601,7 @@ eval_foldexpr(char_u *arg, int *cp) --emsg_off; if (use_sandbox) --sandbox; - --textlock; + --textwinlock; return (int)retval; } diff --git a/src/ex_docmd.c b/src/ex_docmd.c index ca69c293d6..65ef936e9f 100644 --- a/src/ex_docmd.c +++ b/src/ex_docmd.c @@ -5749,7 +5749,7 @@ handle_drop( handle_any_postponed_drop(void) { if (!drop_busy && drop_filev != NULL - && !text_locked() && !curbuf_locked() && !updating_screen) + && !text_locked() && !curbuf_locked() && !updating_screen) handle_drop_internal(); } #endif diff --git a/src/ex_getln.c b/src/ex_getln.c index 6376a5fba4..48d40cfc76 100644 --- a/src/ex_getln.c +++ b/src/ex_getln.c @@ -1318,12 +1318,12 @@ getcmdline_int( c = get_expr_register(); if (c == '=') { - // Need to save and restore ccline. And set "textlock" + // Need to save and restore ccline. And set "textwinlock" // to avoid nasty things like going to another buffer when // evaluating an expression. - ++textlock; + ++textwinlock; p = get_expr_line(); - --textlock; + --textwinlock; if (p != NULL) { @@ -2548,17 +2548,17 @@ check_opt_wim(void) /* * Return TRUE when the text must not be changed and we can't switch to - * another window or buffer. Used when editing the command line, evaluating + * another window or buffer. TRUE when editing the command line, evaluating * 'balloonexpr', etc. */ int -text_locked(void) +text_and_win_locked(void) { #ifdef FEAT_CMDWIN if (cmdwin_type != 0) return TRUE; #endif - return textlock != 0; + return textwinlock != 0; } /* @@ -2578,9 +2578,21 @@ get_text_locked_msg(void) if (cmdwin_type != 0) return e_cmdwin; #endif + if (textwinlock != 0) + return e_textwinlock; return e_textlock; } +/* + * Return TRUE when the text must not be changed and/or we cannot switch to + * another window. TRUE while evaluating 'completefunc'. + */ + int +text_locked(void) +{ + return text_and_win_locked() || textlock != 0; +} + /* * Check if "curbuf_lock" or "allbuf_lock" is set and return TRUE when it is * and give an error message. @@ -3560,11 +3572,11 @@ cmdline_paste( regname = may_get_selection(regname); #endif - // Need to set "textlock" to avoid nasty things like going to another + // Need to set "textwinlock" to avoid nasty things like going to another // buffer when evaluating an expression. - ++textlock; + ++textwinlock; i = get_spec_reg(regname, &arg, &allocated, TRUE); - --textlock; + --textwinlock; if (i) { diff --git a/src/globals.h b/src/globals.h index 2dceab5e23..9180befcb5 100644 --- a/src/globals.h +++ b/src/globals.h @@ -798,9 +798,15 @@ EXTERN int secure INIT(= FALSE); // allowed, e.g. when sourcing .exrc or .vimrc // in current directory -EXTERN int textlock INIT(= 0); +EXTERN int textwinlock INIT(= 0); // non-zero when changing text and jumping to - // another window or buffer is not allowed + // another window or editing another buffer is + // not allowed + +EXTERN int textlock INIT(= 0); + // non-zero when changing text is not allowed, + // jumping to another window is allowed, + // editing another buffer is not allowed. EXTERN int curbuf_lock INIT(= 0); // non-zero when the current buffer can't be @@ -1681,7 +1687,8 @@ EXTERN char e_readerrf[] INIT(= N_("E47: Error while reading errorfile")); EXTERN char e_sandbox[] INIT(= N_("E48: Not allowed in sandbox")); #endif EXTERN char e_secure[] INIT(= N_("E523: Not allowed here")); -EXTERN char e_textlock[] INIT(= N_("E565: Not allowed to change text here")); +EXTERN char e_textlock[] INIT(= N_("E578: Not allowed to change text here")); +EXTERN char e_textwinlock[] INIT(= N_("E565: Not allowed to change text or change window")); #if defined(AMIGA) || defined(MACOS_X) || defined(MSWIN) \ || defined(UNIX) || defined(VMS) EXTERN char e_screenmode[] INIT(= N_("E359: Screen mode setting not supported")); diff --git a/src/indent.c b/src/indent.c index 10c82d89de..a1d4d3628e 100644 --- a/src/indent.c +++ b/src/indent.c @@ -1760,7 +1760,7 @@ get_expr_indent(void) set_vim_var_nr(VV_LNUM, curwin->w_cursor.lnum); if (use_sandbox) ++sandbox; - ++textlock; + ++textwinlock; // Need to make a copy, the 'indentexpr' option could be changed while // evaluating it. @@ -1773,7 +1773,7 @@ get_expr_indent(void) if (use_sandbox) --sandbox; - --textlock; + --textwinlock; // Restore the cursor position so that 'indentexpr' doesn't need to. // Pretend to be in Insert mode, allow cursor past end of line for "o" diff --git a/src/insexpand.c b/src/insexpand.c index 48ab260a70..bd809b0e6f 100644 --- a/src/insexpand.c +++ b/src/insexpand.c @@ -989,9 +989,9 @@ trigger_complete_changed_event(int cur) dict_set_items_ro(v_event); recursive = TRUE; - textlock++; + textwinlock++; apply_autocmds(EVENT_COMPLETECHANGED, NULL, NULL, FALSE, curbuf); - textlock--; + textwinlock--; recursive = FALSE; dict_free_contents(v_event); @@ -2217,7 +2217,8 @@ expand_by_function( pos = curwin->w_cursor; curwin_save = curwin; curbuf_save = curbuf; - // Lock the text to avoid weird things from happening. + // Lock the text to avoid weird things from happening. Do allow switching + // to another window temporarily. ++textlock; // Call a function, which returns a list or dict. @@ -2442,8 +2443,8 @@ f_complete(typval_T *argvars, typval_T *rettv UNUSED) return; } - // "textlock" is set when evaluating 'completefunc' but we can change text - // here. + // "textlock" is set when evaluating 'completefunc' but we can change + // text here. textlock = 0; // Check for undo allowed here, because if something was already inserted diff --git a/src/map.c b/src/map.c index 85c46a52bb..2e20d401cb 100644 --- a/src/map.c +++ b/src/map.c @@ -1570,14 +1570,14 @@ eval_map_expr( // Forbid changing text or using ":normal" to avoid most of the bad side // effects. Also restore the cursor position. - ++textlock; + ++textwinlock; ++ex_normal_lock; set_vim_var_char(c); // set v:char to the typed character save_cursor = curwin->w_cursor; save_msg_col = msg_col; save_msg_row = msg_row; p = eval_to_string(expr, NULL, FALSE); - --textlock; + --textwinlock; --ex_normal_lock; curwin->w_cursor = save_cursor; msg_col = save_msg_col; diff --git a/src/proto/ex_getln.pro b/src/proto/ex_getln.pro index a8ca7af17b..f64bb1ff5d 100644 --- a/src/proto/ex_getln.pro +++ b/src/proto/ex_getln.pro @@ -3,9 +3,10 @@ void cmdline_init(void); char_u *getcmdline(int firstc, long count, int indent, int do_concat); char_u *getcmdline_prompt(int firstc, char_u *prompt, int attr, int xp_context, char_u *xp_arg); int check_opt_wim(void); -int text_locked(void); +int text_and_win_locked(void); void text_locked_msg(void); char *get_text_locked_msg(void); +int text_locked(void); int curbuf_locked(void); int allbuf_locked(void); char_u *getexline(int c, void *cookie, int indent, int do_concat); diff --git a/src/register.c b/src/register.c index 2ad136bdc6..e56149f392 100644 --- a/src/register.c +++ b/src/register.c @@ -932,9 +932,9 @@ yank_do_autocmd(oparg_T *oap, yankreg_T *reg) dict_set_items_ro(v_event); recursive = TRUE; - textlock++; + textwinlock++; apply_autocmds(EVENT_TEXTYANKPOST, NULL, NULL, FALSE, curbuf); - textlock--; + textwinlock--; recursive = FALSE; // Empty the dictionary, v:event is still valid diff --git a/src/testdir/test_edit.vim b/src/testdir/test_edit.vim index a9ba31df4c..f0bf5cc5f6 100644 --- a/src/testdir/test_edit.vim +++ b/src/testdir/test_edit.vim @@ -927,7 +927,7 @@ func Test_edit_completefunc_delete() set completefunc=CompleteFunc call setline(1, ['', 'abcd', '']) 2d - call assert_fails("normal 2G$a\<C-X>\<C-U>", 'E565:') + call assert_fails("normal 2G$a\<C-X>\<C-U>", 'E578:') bwipe! endfunc diff --git a/src/testdir/test_ins_complete.vim b/src/testdir/test_ins_complete.vim index cec4acf3f2..dbea9013f8 100644 --- a/src/testdir/test_ins_complete.vim +++ b/src/testdir/test_ins_complete.vim @@ -491,7 +491,7 @@ func Test_completefunc_error() endfunc set completefunc=CompleteFunc2 call setline(1, ['', 'abcd', '']) - call assert_fails('exe "normal 2G$a\<C-X>\<C-U>"', 'E565:') + call assert_fails('exe "normal 2G$a\<C-X>\<C-U>"', 'E578:') set completefunc& delfunc CompleteFunc diff --git a/src/testdir/test_popup.vim b/src/testdir/test_popup.vim index 9890377ea7..c7229fc8e7 100644 --- a/src/testdir/test_popup.vim +++ b/src/testdir/test_popup.vim @@ -342,7 +342,7 @@ func Test_completefunc_opens_new_window_one() setlocal completefunc=DummyCompleteOne call setline(1, 'one') /^one - call assert_fails('call feedkeys("A\<C-X>\<C-U>\<C-N>\<Esc>", "x")', 'E565:') + call assert_fails('call feedkeys("A\<C-X>\<C-U>\<C-N>\<Esc>", "x")', 'E578:') call assert_equal(winid, win_getid()) call assert_equal('oneDEF', getline(1)) q! diff --git a/src/undo.c b/src/undo.c index c11b048a2c..4bbc0af0fb 100644 --- a/src/undo.c +++ b/src/undo.c @@ -331,7 +331,7 @@ undo_allowed(void) // Don't allow changes in the buffer while editing the cmdline. The // caller of getcmdline() may get confused. - if (textlock != 0) + if (textwinlock != 0 || textlock != 0) { emsg(_(e_textlock)); return FALSE; diff --git a/src/version.c b/src/version.c index 6b3a1596aa..8b9fec5516 100644 --- a/src/version.c +++ b/src/version.c @@ -746,6 +746,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 670, /**/ 669, /**/ diff --git a/src/window.c b/src/window.c index 7c18c06a7f..532d31431e 100644 --- a/src/window.c +++ b/src/window.c @@ -4370,7 +4370,7 @@ win_goto(win_T *wp) return; } #endif - if (text_locked()) + if (text_and_win_locked()) { beep_flush(); text_locked_msg(); From 9e175141f3437627c314257ebf894c29c71a9ded Mon Sep 17 00:00:00 2001 From: Bram Moolenaar <Bram@vim.org> Date: Thu, 30 Apr 2020 22:51:01 +0200 Subject: [PATCH 065/230] patch 8.2.0671: Haiku: compiler warnings Problem: Haiku: compiler warnings. Solution: Avoid the warnings. Drop display_errors() copy. (Emir Sari, closes #6018) --- .gitignore | 1 + src/gui.c | 3 ++- src/gui_haiku.cc | 36 +----------------------------------- src/version.c | 2 ++ 4 files changed, 6 insertions(+), 36 deletions(-) diff --git a/.gitignore b/.gitignore index 2dc119476c..8623fdebf0 100644 --- a/.gitignore +++ b/.gitignore @@ -5,6 +5,7 @@ src/xxd/xxd src/auto/if_perl.c src/auto/gui_gtk_gresources.c src/auto/gui_gtk_gresources.h +src/auto/os_haiku.rdef src/objects/.dirstamp src/objects src/tags diff --git a/src/gui.c b/src/gui.c index 5959043279..13b65cb03c 100644 --- a/src/gui.c +++ b/src/gui.c @@ -5107,7 +5107,8 @@ gui_find_iconfile(char_u *name, char_u *buffer, char *ext) # endif #endif -#if defined(FEAT_GUI_GTK) || defined(FEAT_GUI_X11) || defined(PROTO) +#if defined(FEAT_GUI_GTK) || defined(FEAT_GUI_X11)|| defined(FEAT_GUI_HAIKU) \ + || defined(PROTO) void display_errors(void) { diff --git a/src/gui_haiku.cc b/src/gui_haiku.cc index 2dbd852f27..ff460adf29 100644 --- a/src/gui_haiku.cc +++ b/src/gui_haiku.cc @@ -551,7 +551,7 @@ struct VimMsg { }; #define RGB(r, g, b) ((char_u)(r) << 16 | (char_u)(g) << 8 | (char_u)(b) << 0) -#define GUI_TO_RGB(g) { (g) >> 16, (g) >> 8, (g) >> 0, 255 } +#define GUI_TO_RGB(g) { (char_u)((g) >> 16), (char_u)((g) >> 8), (char_u)((g) >> 0), 255 } // ---------------- end of header part ---------------- @@ -3990,40 +3990,6 @@ gui_mch_adjust_charheight() return OK; } -/* - * Display the saved error message(s). - */ -#ifdef USE_MCH_ERRMSG - void -display_errors(void) -{ - char *p; - char_u pError[256]; - - if (error_ga.ga_data == NULL) - return; - - // avoid putting up a message box with blanks only - for (p = (char *)error_ga.ga_data; *p; ++p) - if (!isspace(*p)) - { - if (STRLEN(p) > 255) - pError[0] = 255; - else - pError[0] = STRLEN(p); - - STRNCPY(&pError[1], p, pError[0]); -// ParamText(pError, nil, nil, nil); -// Alert(128, nil); - break; - // TODO: handled message longer than 256 chars - // use auto-sizeable alert - // or dialog with scrollbars (TextEdit zone) - } - ga_clear(&error_ga); -} -#endif - void gui_mch_getmouse(int *x, int *y) { diff --git a/src/version.c b/src/version.c index 8b9fec5516..5e35da8a08 100644 --- a/src/version.c +++ b/src/version.c @@ -746,6 +746,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 671, /**/ 670, /**/ From 6ab0953fefe31fef91e40752a675ceb60fc2fe03 Mon Sep 17 00:00:00 2001 From: Bram Moolenaar <Bram@vim.org> Date: Fri, 1 May 2020 14:10:13 +0200 Subject: [PATCH 066/230] patch 8.2.0672: heredoc in scripts does not accept lower case marker Problem: Heredoc in scripts does not accept lower case marker. Solution: Allow lower case only in non-Vim scripts. (Ken Takata, closes #6019) --- src/evalvars.c | 2 +- src/testdir/test_lua.vim | 5 ++++- src/testdir/test_perl.vim | 5 ++++- src/testdir/test_python2.vim | 5 ++++- src/testdir/test_python3.vim | 5 ++++- src/testdir/test_pyx2.vim | 5 ++++- src/testdir/test_pyx3.vim | 5 ++++- src/testdir/test_ruby.vim | 5 ++++- src/version.c | 2 ++ 9 files changed, 31 insertions(+), 8 deletions(-) diff --git a/src/evalvars.c b/src/evalvars.c index 7c8b9f7acc..f6f077983b 100644 --- a/src/evalvars.c +++ b/src/evalvars.c @@ -595,7 +595,7 @@ heredoc_get(exarg_T *eap, char_u *cmd, int script_get) return NULL; } *p = NUL; - if (vim_islower(*marker)) + if (!script_get && vim_islower(*marker)) { emsg(_("E221: Marker cannot start with lower case letter")); return NULL; diff --git a/src/testdir/test_lua.vim b/src/testdir/test_lua.vim index 44aae22f4d..25300b67ee 100644 --- a/src/testdir/test_lua.vim +++ b/src/testdir/test_lua.vim @@ -623,7 +623,10 @@ vim.command('let s ..= "B"') lua << trim vim.command('let s ..= "D"') . - call assert_equal('ABCD', s) + lua << trim eof + vim.command('let s ..= "E"') + eof + call assert_equal('ABCDE', s) endfunc " vim: shiftwidth=2 sts=2 expandtab diff --git a/src/testdir/test_perl.vim b/src/testdir/test_perl.vim index 35cb813a11..1a856d5470 100644 --- a/src/testdir/test_perl.vim +++ b/src/testdir/test_perl.vim @@ -305,7 +305,10 @@ VIM::DoCommand('let s ..= "B"') perl << trim VIM::DoCommand('let s ..= "D"') . - call assert_equal('ABCD', s) + perl << trim eof + VIM::DoCommand('let s ..= "E"') + eof + call assert_equal('ABCDE', s) endfunc " vim: shiftwidth=2 sts=2 expandtab diff --git a/src/testdir/test_python2.vim b/src/testdir/test_python2.vim index 7be5b4028e..ae76fe6e89 100644 --- a/src/testdir/test_python2.vim +++ b/src/testdir/test_python2.vim @@ -182,7 +182,10 @@ s+='B' python << trim s+='D' . - call assert_equal('ABCD', pyxeval('s')) + python << trim eof + s+='E' + eof + call assert_equal('ABCDE', pyxeval('s')) endfunc " vim: shiftwidth=2 sts=2 expandtab diff --git a/src/testdir/test_python3.vim b/src/testdir/test_python3.vim index 2244846118..b4a4a4aa7b 100644 --- a/src/testdir/test_python3.vim +++ b/src/testdir/test_python3.vim @@ -349,7 +349,10 @@ s+='B' python3 << trim s+='D' . - call assert_equal('ABCD', pyxeval('s')) + python3 << trim eof + s+='E' + eof + call assert_equal('ABCDE', pyxeval('s')) endfunc " vim: shiftwidth=2 sts=2 expandtab diff --git a/src/testdir/test_pyx2.vim b/src/testdir/test_pyx2.vim index 93a2b899ea..7432ceba4a 100644 --- a/src/testdir/test_pyx2.vim +++ b/src/testdir/test_pyx2.vim @@ -94,7 +94,10 @@ result+='B' pyx << trim result+='D' . - call assert_equal('ABCD', pyxeval('result')) + pyx << trim eof + result+='E' + eof + call assert_equal('ABCDE', pyxeval('result')) endfunc " vim: shiftwidth=2 sts=2 expandtab diff --git a/src/testdir/test_pyx3.vim b/src/testdir/test_pyx3.vim index 5b983e40c0..5d38420dc2 100644 --- a/src/testdir/test_pyx3.vim +++ b/src/testdir/test_pyx3.vim @@ -94,7 +94,10 @@ result+='B' pyx << trim result+='D' . - call assert_equal('ABCD', pyxeval('result')) + pyx << trim eof + result+='E' + eof + call assert_equal('ABCDE', pyxeval('result')) endfunc " vim: shiftwidth=2 sts=2 expandtab diff --git a/src/testdir/test_ruby.vim b/src/testdir/test_ruby.vim index 100c9ea0fb..eee2831acf 100644 --- a/src/testdir/test_ruby.vim +++ b/src/testdir/test_ruby.vim @@ -409,7 +409,10 @@ Vim.command('let s ..= "B"') ruby << trim Vim.command('let s ..= "D"') . - call assert_equal('ABCD', s) + ruby << trim eof + Vim.command('let s ..= "E"') + eof + call assert_equal('ABCDE', s) endfunc " vim: shiftwidth=2 sts=2 expandtab diff --git a/src/version.c b/src/version.c index 5e35da8a08..140871cdf1 100644 --- a/src/version.c +++ b/src/version.c @@ -746,6 +746,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 672, /**/ 671, /**/ From 4cfde1d273ec5fca68a983805af48ea37d3d94e5 Mon Sep 17 00:00:00 2001 From: Bram Moolenaar <Bram@vim.org> Date: Fri, 1 May 2020 14:14:07 +0200 Subject: [PATCH 067/230] patch 8.2.0673: cannot build Haiku in shadow directory Problem: Cannot build Haiku in shadow directory. Solution: Add symlink. (Ozaki Kiichi, closes #6023) --- src/Makefile | 2 +- src/version.c | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/src/Makefile b/src/Makefile index 12ec23cb26..8a12cb8016 100644 --- a/src/Makefile +++ b/src/Makefile @@ -2918,7 +2918,7 @@ clean celan: testclean # % make SHADOWDIR = shadow -LINKEDFILES = ../*.[chm] ../*.in ../*.sh ../*.xs ../*.xbm ../gui_gtk_res.xml ../toolcheck ../proto ../libvterm ../vimtutor ../gvimtutor ../install-sh ../Make_all.mak +LINKEDFILES = ../*.[chm] ../*.cc ../*.in ../*.sh ../*.xs ../*.xbm ../gui_gtk_res.xml ../toolcheck ../proto ../libvterm ../vimtutor ../gvimtutor ../install-sh ../Make_all.mak shadow: runtime pixmaps $(MKDIR_P) $(SHADOWDIR) diff --git a/src/version.c b/src/version.c index 140871cdf1..7267318623 100644 --- a/src/version.c +++ b/src/version.c @@ -746,6 +746,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 673, /**/ 672, /**/ From 11abd095210fc84e5dcee87b9baed86061caefe4 Mon Sep 17 00:00:00 2001 From: Bram Moolenaar <Bram@vim.org> Date: Fri, 1 May 2020 14:26:37 +0200 Subject: [PATCH 068/230] patch 8.2.0674: some source files are too big Problem: Some source files are too big. Solution: Move text formatting functions to a new file. (Yegappan Lakshmanan, closes #6021) --- Filelist | 2 + src/Make_cyg_ming.mak | 1 + src/Make_morph.mak | 1 + src/Make_mvc.mak | 4 + src/Make_vms.mms | 5 + src/Makefile | 10 + src/README.md | 1 + src/edit.c | 567 -------------------- src/getchar.c | 40 ++ src/ops.c | 590 --------------------- src/option.c | 12 - src/proto.h | 1 + src/proto/edit.pro | 2 - src/proto/getchar.pro | 1 + src/proto/ops.pro | 4 - src/proto/option.pro | 1 - src/proto/textformat.pro | 11 + src/textformat.c | 1088 ++++++++++++++++++++++++++++++++++++++ src/version.c | 2 + 19 files changed, 1167 insertions(+), 1176 deletions(-) create mode 100644 src/proto/textformat.pro create mode 100644 src/textformat.c diff --git a/Filelist b/Filelist index 7090efc929..8c0b260a00 100644 --- a/Filelist +++ b/Filelist @@ -128,6 +128,7 @@ SRC_ALL = \ src/term.h \ src/termlib.c \ src/testing.c \ + src/textformat.c \ src/textobject.c \ src/textprop.c \ src/time.c \ @@ -280,6 +281,7 @@ SRC_ALL = \ src/proto/terminal.pro \ src/proto/termlib.pro \ src/proto/testing.pro \ + src/proto/textformat.pro \ src/proto/textobject.pro \ src/proto/textprop.pro \ src/proto/time.pro \ diff --git a/src/Make_cyg_ming.mak b/src/Make_cyg_ming.mak index 7964b0a1f2..94561e51b2 100644 --- a/src/Make_cyg_ming.mak +++ b/src/Make_cyg_ming.mak @@ -787,6 +787,7 @@ OBJ = \ $(OUTDIR)/tag.o \ $(OUTDIR)/term.o \ $(OUTDIR)/testing.o \ + $(OUTDIR)/textformat.o \ $(OUTDIR)/textobject.o \ $(OUTDIR)/textprop.o \ $(OUTDIR)/time.o \ diff --git a/src/Make_morph.mak b/src/Make_morph.mak index d326174cd2..43414e72cf 100644 --- a/src/Make_morph.mak +++ b/src/Make_morph.mak @@ -103,6 +103,7 @@ SRC = arabic.c \ tag.c \ term.c \ testing.c \ + textformat.c \ textobject.c \ textprop.c \ time.c \ diff --git a/src/Make_mvc.mak b/src/Make_mvc.mak index c873ca0840..ffe6e4914c 100644 --- a/src/Make_mvc.mak +++ b/src/Make_mvc.mak @@ -806,6 +806,7 @@ OBJ = \ $(OUTDIR)\tag.obj \ $(OUTDIR)\term.obj \ $(OUTDIR)\testing.obj \ + $(OUTDIR)\textformat.obj \ $(OUTDIR)\textobject.obj \ $(OUTDIR)\textprop.obj \ $(OUTDIR)\time.obj \ @@ -1745,6 +1746,8 @@ $(OUTDIR)/term.obj: $(OUTDIR) term.c $(INCL) $(OUTDIR)/term.obj: $(OUTDIR) testing.c $(INCL) +$(OUTDIR)/textformat.obj: $(OUTDIR) textformat.c $(INCL) + $(OUTDIR)/textobject.obj: $(OUTDIR) textobject.c $(INCL) $(OUTDIR)/textprop.obj: $(OUTDIR) textprop.c $(INCL) @@ -1945,6 +1948,7 @@ proto.h: \ proto/tag.pro \ proto/term.pro \ proto/testing.pro \ + proto/textformat.pro \ proto/textobject.pro \ proto/textprop.pro \ proto/time.pro \ diff --git a/src/Make_vms.mms b/src/Make_vms.mms index e04020172a..954d50a14f 100644 --- a/src/Make_vms.mms +++ b/src/Make_vms.mms @@ -382,6 +382,7 @@ SRC = \ term.c \ termlib.c \ testing.c \ + textformat.c \ textobject.c \ textprop.c \ time.c \ @@ -492,6 +493,7 @@ OBJ = \ term.obj \ termlib.obj \ testing.obj \ + textformat.obj \ textobject.obj \ textprop.obj \ time.obj \ @@ -991,6 +993,9 @@ termlib.obj : termlib.c vim.h [.auto]config.h feature.h os_unix.h \ testing.obj : testing.c vim.h [.auto]config.h feature.h os_unix.h \ ascii.h keymap.h term.h macros.h structs.h regexp.h gui.h beval.h \ [.proto]gui_beval.pro option.h ex_cmds.h proto.h globals.h +textformat.obj : textformat.c vim.h [.auto]config.h feature.h os_unix.h \ + ascii.h keymap.h term.h macros.h structs.h regexp.h gui.h beval.h \ + [.proto]gui_beval.pro option.h ex_cmds.h proto.h globals.h textobject.obj : textobject.c vim.h [.auto]config.h feature.h os_unix.h \ ascii.h keymap.h term.h macros.h structs.h regexp.h gui.h beval.h \ [.proto]gui_beval.pro option.h ex_cmds.h proto.h globals.h diff --git a/src/Makefile b/src/Makefile index 8a12cb8016..6c7ef85a92 100644 --- a/src/Makefile +++ b/src/Makefile @@ -1680,6 +1680,7 @@ BASIC_SRC = \ term.c \ terminal.c \ testing.c \ + textformat.c \ textobject.c \ textprop.c \ time.c \ @@ -1823,6 +1824,7 @@ OBJ_COMMON = \ objects/term.o \ objects/terminal.o \ objects/testing.o \ + objects/textformat.o \ objects/textobject.o \ objects/textprop.o \ objects/time.o \ @@ -1998,6 +2000,7 @@ PRO_AUTO = \ terminal.pro \ termlib.pro \ testing.pro \ + textformat.pro \ textobject.pro \ textprop.pro \ time.pro \ @@ -3479,6 +3482,9 @@ objects/terminal.o: terminal.c $(TERM_DEPS) objects/testing.o: testing.c $(CCC) -o $@ testing.c +objects/textformat.o: textformat.c + $(CCC) -o $@ textformat.c + objects/textobject.o: textobject.c $(CCC) -o $@ textobject.c @@ -4073,6 +4079,10 @@ objects/testing.o: testing.c vim.h protodef.h auto/config.h feature.h os_unix.h auto/osdef.h ascii.h keymap.h term.h macros.h option.h beval.h \ proto/gui_beval.pro structs.h regexp.h gui.h alloc.h ex_cmds.h spell.h \ proto.h globals.h +objects/textformat.o: textformat.c vim.h protodef.h auto/config.h feature.h os_unix.h \ + auto/osdef.h ascii.h keymap.h term.h macros.h option.h beval.h \ + proto/gui_beval.pro structs.h regexp.h gui.h alloc.h ex_cmds.h spell.h \ + proto.h globals.h objects/textobject.o: textobject.c vim.h protodef.h auto/config.h feature.h os_unix.h \ auto/osdef.h ascii.h keymap.h term.h macros.h option.h beval.h \ proto/gui_beval.pro structs.h regexp.h gui.h alloc.h ex_cmds.h spell.h \ diff --git a/src/README.md b/src/README.md index 765313da7e..624bd6a829 100644 --- a/src/README.md +++ b/src/README.md @@ -80,6 +80,7 @@ syntax.c | syntax and other highlighting tag.c | tags term.c | terminal handling, termcap codes testing.c | testing: assert and test functions +textformat.c | text formatting textobject.c | text objects textprop.c | text properties time.c | time and timer functions diff --git a/src/edit.c b/src/edit.c index 0ac63ec8fd..5252334ce5 100644 --- a/src/edit.c +++ b/src/edit.c @@ -28,8 +28,6 @@ static void ins_ctrl_v(void); static void init_prompt(int cmdchar_todo); #endif static void insert_special(int, int, int); -static void internal_format(int textwidth, int second_indent, int flags, int format_only, int c); -static void check_auto_format(int); static void redo_literal(int c); static void start_arrow_common(pos_T *end_insert_pos, int change); #ifdef FEAT_SPELL @@ -104,8 +102,6 @@ static int ins_need_undo; // call u_save() before inserting a // char. Set when edit() is called. // after that arrow_used is used. -static int did_add_space = FALSE; // auto_format() added an extra space - // under the cursor static int dont_sync_undo = FALSE; // CTRL-G U prevents syncing undo for // the next left/right cursor key @@ -2063,8 +2059,6 @@ insert_special( # define ISSPECIAL(c) ((c) < ' ' || (c) >= DEL || (c) == '0' || (c) == '^') #endif -#define WHITECHAR(cc) (VIM_ISWHITE(cc) && (!enc_utf8 || !utf_iscomposing(utf_ptr2char(ml_get_cursor() + 1)))) - /* * "flags": INSCHAR_FORMAT - force formatting * INSCHAR_CTRLV - char typed just after CTRL-V @@ -2301,567 +2295,6 @@ insertchar( } } -/* - * Format text at the current insert position. - * - * If the INSCHAR_COM_LIST flag is present, then the value of second_indent - * will be the comment leader length sent to open_line(). - */ - static void -internal_format( - int textwidth, - int second_indent, - int flags, - int format_only, - int c) // character to be inserted (can be NUL) -{ - int cc; - int save_char = NUL; - int haveto_redraw = FALSE; - int fo_ins_blank = has_format_option(FO_INS_BLANK); - int fo_multibyte = has_format_option(FO_MBYTE_BREAK); - int fo_white_par = has_format_option(FO_WHITE_PAR); - int first_line = TRUE; - colnr_T leader_len; - int no_leader = FALSE; - int do_comments = (flags & INSCHAR_DO_COM); -#ifdef FEAT_LINEBREAK - int has_lbr = curwin->w_p_lbr; - - // make sure win_lbr_chartabsize() counts correctly - curwin->w_p_lbr = FALSE; -#endif - - /* - * When 'ai' is off we don't want a space under the cursor to be - * deleted. Replace it with an 'x' temporarily. - */ - if (!curbuf->b_p_ai && !(State & VREPLACE_FLAG)) - { - cc = gchar_cursor(); - if (VIM_ISWHITE(cc)) - { - save_char = cc; - pchar_cursor('x'); - } - } - - /* - * Repeat breaking lines, until the current line is not too long. - */ - while (!got_int) - { - int startcol; // Cursor column at entry - int wantcol; // column at textwidth border - int foundcol; // column for start of spaces - int end_foundcol = 0; // column for start of word - colnr_T len; - colnr_T virtcol; - int orig_col = 0; - char_u *saved_text = NULL; - colnr_T col; - colnr_T end_col; - int wcc; // counter for whitespace chars - - virtcol = get_nolist_virtcol() - + char2cells(c != NUL ? c : gchar_cursor()); - if (virtcol <= (colnr_T)textwidth) - break; - - if (no_leader) - do_comments = FALSE; - else if (!(flags & INSCHAR_FORMAT) - && has_format_option(FO_WRAP_COMS)) - do_comments = TRUE; - - // Don't break until after the comment leader - if (do_comments) - leader_len = get_leader_len(ml_get_curline(), NULL, FALSE, TRUE); - else - leader_len = 0; - - // If the line doesn't start with a comment leader, then don't - // start one in a following broken line. Avoids that a %word - // moved to the start of the next line causes all following lines - // to start with %. - if (leader_len == 0) - no_leader = TRUE; - if (!(flags & INSCHAR_FORMAT) - && leader_len == 0 - && !has_format_option(FO_WRAP)) - - break; - if ((startcol = curwin->w_cursor.col) == 0) - break; - - // find column of textwidth border - coladvance((colnr_T)textwidth); - wantcol = curwin->w_cursor.col; - - curwin->w_cursor.col = startcol; - foundcol = 0; - - /* - * Find position to break at. - * Stop at first entered white when 'formatoptions' has 'v' - */ - while ((!fo_ins_blank && !has_format_option(FO_INS_VI)) - || (flags & INSCHAR_FORMAT) - || curwin->w_cursor.lnum != Insstart.lnum - || curwin->w_cursor.col >= Insstart.col) - { - if (curwin->w_cursor.col == startcol && c != NUL) - cc = c; - else - cc = gchar_cursor(); - if (WHITECHAR(cc)) - { - // remember position of blank just before text - end_col = curwin->w_cursor.col; - - // find start of sequence of blanks - wcc = 0; - while (curwin->w_cursor.col > 0 && WHITECHAR(cc)) - { - dec_cursor(); - cc = gchar_cursor(); - - // Increment count of how many whitespace chars in this - // group; we only need to know if it's more than one. - if (wcc < 2) - wcc++; - } - if (curwin->w_cursor.col == 0 && WHITECHAR(cc)) - break; // only spaces in front of text - - // Don't break after a period when 'formatoptions' has 'p' and - // there are less than two spaces. - if (has_format_option(FO_PERIOD_ABBR) && cc == '.' && wcc < 2) - continue; - - // Don't break until after the comment leader - if (curwin->w_cursor.col < leader_len) - break; - if (has_format_option(FO_ONE_LETTER)) - { - // do not break after one-letter words - if (curwin->w_cursor.col == 0) - break; // one-letter word at begin - // do not break "#a b" when 'tw' is 2 - if (curwin->w_cursor.col <= leader_len) - break; - col = curwin->w_cursor.col; - dec_cursor(); - cc = gchar_cursor(); - - if (WHITECHAR(cc)) - continue; // one-letter, continue - curwin->w_cursor.col = col; - } - - inc_cursor(); - - end_foundcol = end_col + 1; - foundcol = curwin->w_cursor.col; - if (curwin->w_cursor.col <= (colnr_T)wantcol) - break; - } - else if (cc >= 0x100 && fo_multibyte) - { - // Break after or before a multi-byte character. - if (curwin->w_cursor.col != startcol) - { - // Don't break until after the comment leader - if (curwin->w_cursor.col < leader_len) - break; - col = curwin->w_cursor.col; - inc_cursor(); - // Don't change end_foundcol if already set. - if (foundcol != curwin->w_cursor.col) - { - foundcol = curwin->w_cursor.col; - end_foundcol = foundcol; - if (curwin->w_cursor.col <= (colnr_T)wantcol) - break; - } - curwin->w_cursor.col = col; - } - - if (curwin->w_cursor.col == 0) - break; - - col = curwin->w_cursor.col; - - dec_cursor(); - cc = gchar_cursor(); - - if (WHITECHAR(cc)) - continue; // break with space - // Don't break until after the comment leader - if (curwin->w_cursor.col < leader_len) - break; - - curwin->w_cursor.col = col; - - foundcol = curwin->w_cursor.col; - end_foundcol = foundcol; - if (curwin->w_cursor.col <= (colnr_T)wantcol) - break; - } - if (curwin->w_cursor.col == 0) - break; - dec_cursor(); - } - - if (foundcol == 0) // no spaces, cannot break line - { - curwin->w_cursor.col = startcol; - break; - } - - // Going to break the line, remove any "$" now. - undisplay_dollar(); - - /* - * Offset between cursor position and line break is used by replace - * stack functions. VREPLACE does not use this, and backspaces - * over the text instead. - */ - if (State & VREPLACE_FLAG) - orig_col = startcol; // Will start backspacing from here - else - replace_offset = startcol - end_foundcol; - - /* - * adjust startcol for spaces that will be deleted and - * characters that will remain on top line - */ - curwin->w_cursor.col = foundcol; - while ((cc = gchar_cursor(), WHITECHAR(cc)) - && (!fo_white_par || curwin->w_cursor.col < startcol)) - inc_cursor(); - startcol -= curwin->w_cursor.col; - if (startcol < 0) - startcol = 0; - - if (State & VREPLACE_FLAG) - { - /* - * In VREPLACE mode, we will backspace over the text to be - * wrapped, so save a copy now to put on the next line. - */ - saved_text = vim_strsave(ml_get_cursor()); - curwin->w_cursor.col = orig_col; - if (saved_text == NULL) - break; // Can't do it, out of memory - saved_text[startcol] = NUL; - - // Backspace over characters that will move to the next line - if (!fo_white_par) - backspace_until_column(foundcol); - } - else - { - // put cursor after pos. to break line - if (!fo_white_par) - curwin->w_cursor.col = foundcol; - } - - /* - * Split the line just before the margin. - * Only insert/delete lines, but don't really redraw the window. - */ - open_line(FORWARD, OPENLINE_DELSPACES + OPENLINE_MARKFIX - + (fo_white_par ? OPENLINE_KEEPTRAIL : 0) - + (do_comments ? OPENLINE_DO_COM : 0) - + ((flags & INSCHAR_COM_LIST) ? OPENLINE_COM_LIST : 0) - , ((flags & INSCHAR_COM_LIST) ? second_indent : old_indent)); - if (!(flags & INSCHAR_COM_LIST)) - old_indent = 0; - - replace_offset = 0; - if (first_line) - { - if (!(flags & INSCHAR_COM_LIST)) - { - /* - * This section is for auto-wrap of numeric lists. When not - * in insert mode (i.e. format_lines()), the INSCHAR_COM_LIST - * flag will be set and open_line() will handle it (as seen - * above). The code here (and in get_number_indent()) will - * recognize comments if needed... - */ - if (second_indent < 0 && has_format_option(FO_Q_NUMBER)) - second_indent = - get_number_indent(curwin->w_cursor.lnum - 1); - if (second_indent >= 0) - { - if (State & VREPLACE_FLAG) - change_indent(INDENT_SET, second_indent, - FALSE, NUL, TRUE); - else - if (leader_len > 0 && second_indent - leader_len > 0) - { - int i; - int padding = second_indent - leader_len; - - // We started at the first_line of a numbered list - // that has a comment. the open_line() function has - // inserted the proper comment leader and positioned - // the cursor at the end of the split line. Now we - // add the additional whitespace needed after the - // comment leader for the numbered list. - for (i = 0; i < padding; i++) - ins_str((char_u *)" "); - } - else - { - (void)set_indent(second_indent, SIN_CHANGED); - } - } - } - first_line = FALSE; - } - - if (State & VREPLACE_FLAG) - { - /* - * In VREPLACE mode we have backspaced over the text to be - * moved, now we re-insert it into the new line. - */ - ins_bytes(saved_text); - vim_free(saved_text); - } - else - { - /* - * Check if cursor is not past the NUL off the line, cindent - * may have added or removed indent. - */ - curwin->w_cursor.col += startcol; - len = (colnr_T)STRLEN(ml_get_curline()); - if (curwin->w_cursor.col > len) - curwin->w_cursor.col = len; - } - - haveto_redraw = TRUE; -#ifdef FEAT_CINDENT - can_cindent = TRUE; -#endif - // moved the cursor, don't autoindent or cindent now - did_ai = FALSE; -#ifdef FEAT_SMARTINDENT - did_si = FALSE; - can_si = FALSE; - can_si_back = FALSE; -#endif - line_breakcheck(); - } - - if (save_char != NUL) // put back space after cursor - pchar_cursor(save_char); - -#ifdef FEAT_LINEBREAK - curwin->w_p_lbr = has_lbr; -#endif - if (!format_only && haveto_redraw) - { - update_topline(); - redraw_curbuf_later(VALID); - } -} - -/* - * Called after inserting or deleting text: When 'formatoptions' includes the - * 'a' flag format from the current line until the end of the paragraph. - * Keep the cursor at the same position relative to the text. - * The caller must have saved the cursor line for undo, following ones will be - * saved here. - */ - void -auto_format( - int trailblank, // when TRUE also format with trailing blank - int prev_line) // may start in previous line -{ - pos_T pos; - colnr_T len; - char_u *old; - char_u *new, *pnew; - int wasatend; - int cc; - - if (!has_format_option(FO_AUTO)) - return; - - pos = curwin->w_cursor; - old = ml_get_curline(); - - // may remove added space - check_auto_format(FALSE); - - // Don't format in Insert mode when the cursor is on a trailing blank, the - // user might insert normal text next. Also skip formatting when "1" is - // in 'formatoptions' and there is a single character before the cursor. - // Otherwise the line would be broken and when typing another non-white - // next they are not joined back together. - wasatend = (pos.col == (colnr_T)STRLEN(old)); - if (*old != NUL && !trailblank && wasatend) - { - dec_cursor(); - cc = gchar_cursor(); - if (!WHITECHAR(cc) && curwin->w_cursor.col > 0 - && has_format_option(FO_ONE_LETTER)) - dec_cursor(); - cc = gchar_cursor(); - if (WHITECHAR(cc)) - { - curwin->w_cursor = pos; - return; - } - curwin->w_cursor = pos; - } - - // With the 'c' flag in 'formatoptions' and 't' missing: only format - // comments. - if (has_format_option(FO_WRAP_COMS) && !has_format_option(FO_WRAP) - && get_leader_len(old, NULL, FALSE, TRUE) == 0) - return; - - /* - * May start formatting in a previous line, so that after "x" a word is - * moved to the previous line if it fits there now. Only when this is not - * the start of a paragraph. - */ - if (prev_line && !paragraph_start(curwin->w_cursor.lnum)) - { - --curwin->w_cursor.lnum; - if (u_save_cursor() == FAIL) - return; - } - - /* - * Do the formatting and restore the cursor position. "saved_cursor" will - * be adjusted for the text formatting. - */ - saved_cursor = pos; - format_lines((linenr_T)-1, FALSE); - curwin->w_cursor = saved_cursor; - saved_cursor.lnum = 0; - - if (curwin->w_cursor.lnum > curbuf->b_ml.ml_line_count) - { - // "cannot happen" - curwin->w_cursor.lnum = curbuf->b_ml.ml_line_count; - coladvance((colnr_T)MAXCOL); - } - else - check_cursor_col(); - - // Insert mode: If the cursor is now after the end of the line while it - // previously wasn't, the line was broken. Because of the rule above we - // need to add a space when 'w' is in 'formatoptions' to keep a paragraph - // formatted. - if (!wasatend && has_format_option(FO_WHITE_PAR)) - { - new = ml_get_curline(); - len = (colnr_T)STRLEN(new); - if (curwin->w_cursor.col == len) - { - pnew = vim_strnsave(new, len + 2); - pnew[len] = ' '; - pnew[len + 1] = NUL; - ml_replace(curwin->w_cursor.lnum, pnew, FALSE); - // remove the space later - did_add_space = TRUE; - } - else - // may remove added space - check_auto_format(FALSE); - } - - check_cursor(); -} - -/* - * When an extra space was added to continue a paragraph for auto-formatting, - * delete it now. The space must be under the cursor, just after the insert - * position. - */ - static void -check_auto_format( - int end_insert) // TRUE when ending Insert mode -{ - int c = ' '; - int cc; - - if (did_add_space) - { - cc = gchar_cursor(); - if (!WHITECHAR(cc)) - // Somehow the space was removed already. - did_add_space = FALSE; - else - { - if (!end_insert) - { - inc_cursor(); - c = gchar_cursor(); - dec_cursor(); - } - if (c != NUL) - { - // The space is no longer at the end of the line, delete it. - del_char(FALSE); - did_add_space = FALSE; - } - } - } -} - -/* - * Find out textwidth to be used for formatting: - * if 'textwidth' option is set, use it - * else if 'wrapmargin' option is set, use curwin->w_width - 'wrapmargin' - * if invalid value, use 0. - * Set default to window width (maximum 79) for "gq" operator. - */ - int -comp_textwidth( - int ff) // force formatting (for "gq" command) -{ - int textwidth; - - textwidth = curbuf->b_p_tw; - if (textwidth == 0 && curbuf->b_p_wm) - { - // The width is the window width minus 'wrapmargin' minus all the - // things that add to the margin. - textwidth = curwin->w_width - curbuf->b_p_wm; -#ifdef FEAT_CMDWIN - if (cmdwin_type != 0) - textwidth -= 1; -#endif -#ifdef FEAT_FOLDING - textwidth -= curwin->w_p_fdc; -#endif -#ifdef FEAT_SIGNS - if (signcolumn_on(curwin)) - textwidth -= 1; -#endif - if (curwin->w_p_nu || curwin->w_p_rnu) - textwidth -= 8; - } - if (textwidth < 0) - textwidth = 0; - if (ff && textwidth == 0) - { - textwidth = curwin->w_width - 1; - if (textwidth > 79) - textwidth = 79; - } - return textwidth; -} - /* * Put a character in the redo buffer, for when just after a CTRL-V. */ diff --git a/src/getchar.c b/src/getchar.c index 7bbdf35834..9d8c0d4bff 100644 --- a/src/getchar.c +++ b/src/getchar.c @@ -684,6 +684,46 @@ stuffnumReadbuff(long n) add_num_buff(&readbuf1, n); } +/* + * Stuff a string into the typeahead buffer, such that edit() will insert it + * literally ("literally" TRUE) or interpret is as typed characters. + */ + void +stuffescaped(char_u *arg, int literally) +{ + int c; + char_u *start; + + while (*arg != NUL) + { + // Stuff a sequence of normal ASCII characters, that's fast. Also + // stuff K_SPECIAL to get the effect of a special key when "literally" + // is TRUE. + start = arg; + while ((*arg >= ' ' +#ifndef EBCDIC + && *arg < DEL // EBCDIC: chars above space are normal +#endif + ) + || (*arg == K_SPECIAL && !literally)) + ++arg; + if (arg > start) + stuffReadbuffLen(start, (long)(arg - start)); + + // stuff a single special character + if (*arg != NUL) + { + if (has_mbyte) + c = mb_cptr2char_adv(&arg); + else + c = *arg++; + if (literally && ((c < ' ' && c != TAB) || c == DEL)) + stuffcharReadbuff(Ctrl_V); + stuffcharReadbuff(c); + } + } +} + /* * Read a character from the redo buffer. Translates K_SPECIAL, CSI and * multibyte characters. diff --git a/src/ops.c b/src/ops.c index 5e9de4d7cc..9ab355596b 100644 --- a/src/ops.c +++ b/src/ops.c @@ -17,8 +17,6 @@ static void shift_block(oparg_T *oap, int amount); static void mb_adjust_opend(oparg_T *oap); static int do_addsub(int op_type, pos_T *pos, int length, linenr_T Prenum1); -static int ends_in_white(linenr_T lnum); -static int fmt_check_par(linenr_T, int *, char_u **, int do_comments); // Flags for third item in "opchars". #define OPF_LINES 1 // operator always works on lines @@ -590,46 +588,6 @@ block_insert( State = oldstate; } -/* - * Stuff a string into the typeahead buffer, such that edit() will insert it - * literally ("literally" TRUE) or interpret is as typed characters. - */ - void -stuffescaped(char_u *arg, int literally) -{ - int c; - char_u *start; - - while (*arg != NUL) - { - // Stuff a sequence of normal ASCII characters, that's fast. Also - // stuff K_SPECIAL to get the effect of a special key when "literally" - // is TRUE. - start = arg; - while ((*arg >= ' ' -#ifndef EBCDIC - && *arg < DEL // EBCDIC: chars above space are normal -#endif - ) - || (*arg == K_SPECIAL && !literally)) - ++arg; - if (arg > start) - stuffReadbuffLen(start, (long)(arg - start)); - - // stuff a single special character - if (*arg != NUL) - { - if (has_mbyte) - c = mb_cptr2char_adv(&arg); - else - c = *arg++; - if (literally && ((c < ' ' && c != TAB) || c == DEL)) - stuffcharReadbuff(Ctrl_V); - stuffcharReadbuff(c); - } - } -} - /* * Handle a delete operation. * @@ -2170,554 +2128,6 @@ theend: return ret; } -/* - * Return TRUE if the two comment leaders given are the same. "lnum" is - * the first line. White-space is ignored. Note that the whole of - * 'leader1' must match 'leader2_len' characters from 'leader2' -- webb - */ - static int -same_leader( - linenr_T lnum, - int leader1_len, - char_u *leader1_flags, - int leader2_len, - char_u *leader2_flags) -{ - int idx1 = 0, idx2 = 0; - char_u *p; - char_u *line1; - char_u *line2; - - if (leader1_len == 0) - return (leader2_len == 0); - - /* - * If first leader has 'f' flag, the lines can be joined only if the - * second line does not have a leader. - * If first leader has 'e' flag, the lines can never be joined. - * If fist leader has 's' flag, the lines can only be joined if there is - * some text after it and the second line has the 'm' flag. - */ - if (leader1_flags != NULL) - { - for (p = leader1_flags; *p && *p != ':'; ++p) - { - if (*p == COM_FIRST) - return (leader2_len == 0); - if (*p == COM_END) - return FALSE; - if (*p == COM_START) - { - if (*(ml_get(lnum) + leader1_len) == NUL) - return FALSE; - if (leader2_flags == NULL || leader2_len == 0) - return FALSE; - for (p = leader2_flags; *p && *p != ':'; ++p) - if (*p == COM_MIDDLE) - return TRUE; - return FALSE; - } - } - } - - /* - * Get current line and next line, compare the leaders. - * The first line has to be saved, only one line can be locked at a time. - */ - line1 = vim_strsave(ml_get(lnum)); - if (line1 != NULL) - { - for (idx1 = 0; VIM_ISWHITE(line1[idx1]); ++idx1) - ; - line2 = ml_get(lnum + 1); - for (idx2 = 0; idx2 < leader2_len; ++idx2) - { - if (!VIM_ISWHITE(line2[idx2])) - { - if (line1[idx1++] != line2[idx2]) - break; - } - else - while (VIM_ISWHITE(line1[idx1])) - ++idx1; - } - vim_free(line1); - } - return (idx2 == leader2_len && idx1 == leader1_len); -} - -/* - * Implementation of the format operator 'gq'. - */ - static void -op_format( - oparg_T *oap, - int keep_cursor) // keep cursor on same text char -{ - long old_line_count = curbuf->b_ml.ml_line_count; - - // Place the cursor where the "gq" or "gw" command was given, so that "u" - // can put it back there. - curwin->w_cursor = oap->cursor_start; - - if (u_save((linenr_T)(oap->start.lnum - 1), - (linenr_T)(oap->end.lnum + 1)) == FAIL) - return; - curwin->w_cursor = oap->start; - - if (oap->is_VIsual) - // When there is no change: need to remove the Visual selection - redraw_curbuf_later(INVERTED); - - if (!cmdmod.lockmarks) - // Set '[ mark at the start of the formatted area - curbuf->b_op_start = oap->start; - - // For "gw" remember the cursor position and put it back below (adjusted - // for joined and split lines). - if (keep_cursor) - saved_cursor = oap->cursor_start; - - format_lines(oap->line_count, keep_cursor); - - /* - * Leave the cursor at the first non-blank of the last formatted line. - * If the cursor was moved one line back (e.g. with "Q}") go to the next - * line, so "." will do the next lines. - */ - if (oap->end_adjusted && curwin->w_cursor.lnum < curbuf->b_ml.ml_line_count) - ++curwin->w_cursor.lnum; - beginline(BL_WHITE | BL_FIX); - old_line_count = curbuf->b_ml.ml_line_count - old_line_count; - msgmore(old_line_count); - - if (!cmdmod.lockmarks) - // put '] mark on the end of the formatted area - curbuf->b_op_end = curwin->w_cursor; - - if (keep_cursor) - { - curwin->w_cursor = saved_cursor; - saved_cursor.lnum = 0; - } - - if (oap->is_VIsual) - { - win_T *wp; - - FOR_ALL_WINDOWS(wp) - { - if (wp->w_old_cursor_lnum != 0) - { - // When lines have been inserted or deleted, adjust the end of - // the Visual area to be redrawn. - if (wp->w_old_cursor_lnum > wp->w_old_visual_lnum) - wp->w_old_cursor_lnum += old_line_count; - else - wp->w_old_visual_lnum += old_line_count; - } - } - } -} - -#if defined(FEAT_EVAL) || defined(PROTO) -/* - * Implementation of the format operator 'gq' for when using 'formatexpr'. - */ - static void -op_formatexpr(oparg_T *oap) -{ - if (oap->is_VIsual) - // When there is no change: need to remove the Visual selection - redraw_curbuf_later(INVERTED); - - if (fex_format(oap->start.lnum, oap->line_count, NUL) != 0) - // As documented: when 'formatexpr' returns non-zero fall back to - // internal formatting. - op_format(oap, FALSE); -} - - int -fex_format( - linenr_T lnum, - long count, - int c) // character to be inserted -{ - int use_sandbox = was_set_insecurely((char_u *)"formatexpr", - OPT_LOCAL); - int r; - char_u *fex; - - /* - * Set v:lnum to the first line number and v:count to the number of lines. - * Set v:char to the character to be inserted (can be NUL). - */ - set_vim_var_nr(VV_LNUM, lnum); - set_vim_var_nr(VV_COUNT, count); - set_vim_var_char(c); - - // Make a copy, the option could be changed while calling it. - fex = vim_strsave(curbuf->b_p_fex); - if (fex == NULL) - return 0; - - /* - * Evaluate the function. - */ - if (use_sandbox) - ++sandbox; - r = (int)eval_to_number(fex); - if (use_sandbox) - --sandbox; - - set_vim_var_string(VV_CHAR, NULL, -1); - vim_free(fex); - - return r; -} -#endif - -/* - * Format "line_count" lines, starting at the cursor position. - * When "line_count" is negative, format until the end of the paragraph. - * Lines after the cursor line are saved for undo, caller must have saved the - * first line. - */ - void -format_lines( - linenr_T line_count, - int avoid_fex) // don't use 'formatexpr' -{ - int max_len; - int is_not_par; // current line not part of parag. - int next_is_not_par; // next line not part of paragraph - int is_end_par; // at end of paragraph - int prev_is_end_par = FALSE;// prev. line not part of parag. - int next_is_start_par = FALSE; - int leader_len = 0; // leader len of current line - int next_leader_len; // leader len of next line - char_u *leader_flags = NULL; // flags for leader of current line - char_u *next_leader_flags; // flags for leader of next line - int do_comments; // format comments - int do_comments_list = 0; // format comments with 'n' or '2' - int advance = TRUE; - int second_indent = -1; // indent for second line (comment - // aware) - int do_second_indent; - int do_number_indent; - int do_trail_white; - int first_par_line = TRUE; - int smd_save; - long count; - int need_set_indent = TRUE; // set indent of next paragraph - int force_format = FALSE; - int old_State = State; - - // length of a line to force formatting: 3 * 'tw' - max_len = comp_textwidth(TRUE) * 3; - - // check for 'q', '2' and '1' in 'formatoptions' - do_comments = has_format_option(FO_Q_COMS); - do_second_indent = has_format_option(FO_Q_SECOND); - do_number_indent = has_format_option(FO_Q_NUMBER); - do_trail_white = has_format_option(FO_WHITE_PAR); - - /* - * Get info about the previous and current line. - */ - if (curwin->w_cursor.lnum > 1) - is_not_par = fmt_check_par(curwin->w_cursor.lnum - 1 - , &leader_len, &leader_flags, do_comments); - else - is_not_par = TRUE; - next_is_not_par = fmt_check_par(curwin->w_cursor.lnum - , &next_leader_len, &next_leader_flags, do_comments); - is_end_par = (is_not_par || next_is_not_par); - if (!is_end_par && do_trail_white) - is_end_par = !ends_in_white(curwin->w_cursor.lnum - 1); - - curwin->w_cursor.lnum--; - for (count = line_count; count != 0 && !got_int; --count) - { - /* - * Advance to next paragraph. - */ - if (advance) - { - curwin->w_cursor.lnum++; - prev_is_end_par = is_end_par; - is_not_par = next_is_not_par; - leader_len = next_leader_len; - leader_flags = next_leader_flags; - } - - /* - * The last line to be formatted. - */ - if (count == 1 || curwin->w_cursor.lnum == curbuf->b_ml.ml_line_count) - { - next_is_not_par = TRUE; - next_leader_len = 0; - next_leader_flags = NULL; - } - else - { - next_is_not_par = fmt_check_par(curwin->w_cursor.lnum + 1 - , &next_leader_len, &next_leader_flags, do_comments); - if (do_number_indent) - next_is_start_par = - (get_number_indent(curwin->w_cursor.lnum + 1) > 0); - } - advance = TRUE; - is_end_par = (is_not_par || next_is_not_par || next_is_start_par); - if (!is_end_par && do_trail_white) - is_end_par = !ends_in_white(curwin->w_cursor.lnum); - - /* - * Skip lines that are not in a paragraph. - */ - if (is_not_par) - { - if (line_count < 0) - break; - } - else - { - /* - * For the first line of a paragraph, check indent of second line. - * Don't do this for comments and empty lines. - */ - if (first_par_line - && (do_second_indent || do_number_indent) - && prev_is_end_par - && curwin->w_cursor.lnum < curbuf->b_ml.ml_line_count) - { - if (do_second_indent && !LINEEMPTY(curwin->w_cursor.lnum + 1)) - { - if (leader_len == 0 && next_leader_len == 0) - { - // no comment found - second_indent = - get_indent_lnum(curwin->w_cursor.lnum + 1); - } - else - { - second_indent = next_leader_len; - do_comments_list = 1; - } - } - else if (do_number_indent) - { - if (leader_len == 0 && next_leader_len == 0) - { - // no comment found - second_indent = - get_number_indent(curwin->w_cursor.lnum); - } - else - { - // get_number_indent() is now "comment aware"... - second_indent = - get_number_indent(curwin->w_cursor.lnum); - do_comments_list = 1; - } - } - } - - /* - * When the comment leader changes, it's the end of the paragraph. - */ - if (curwin->w_cursor.lnum >= curbuf->b_ml.ml_line_count - || !same_leader(curwin->w_cursor.lnum, - leader_len, leader_flags, - next_leader_len, next_leader_flags)) - is_end_par = TRUE; - - /* - * If we have got to the end of a paragraph, or the line is - * getting long, format it. - */ - if (is_end_par || force_format) - { - if (need_set_indent) - // replace indent in first line with minimal number of - // tabs and spaces, according to current options - (void)set_indent(get_indent(), SIN_CHANGED); - - // put cursor on last non-space - State = NORMAL; // don't go past end-of-line - coladvance((colnr_T)MAXCOL); - while (curwin->w_cursor.col && vim_isspace(gchar_cursor())) - dec_cursor(); - - // do the formatting, without 'showmode' - State = INSERT; // for open_line() - smd_save = p_smd; - p_smd = FALSE; - insertchar(NUL, INSCHAR_FORMAT - + (do_comments ? INSCHAR_DO_COM : 0) - + (do_comments && do_comments_list - ? INSCHAR_COM_LIST : 0) - + (avoid_fex ? INSCHAR_NO_FEX : 0), second_indent); - State = old_State; - p_smd = smd_save; - second_indent = -1; - // at end of par.: need to set indent of next par. - need_set_indent = is_end_par; - if (is_end_par) - { - // When called with a negative line count, break at the - // end of the paragraph. - if (line_count < 0) - break; - first_par_line = TRUE; - } - force_format = FALSE; - } - - /* - * When still in same paragraph, join the lines together. But - * first delete the leader from the second line. - */ - if (!is_end_par) - { - advance = FALSE; - curwin->w_cursor.lnum++; - curwin->w_cursor.col = 0; - if (line_count < 0 && u_save_cursor() == FAIL) - break; - if (next_leader_len > 0) - { - (void)del_bytes((long)next_leader_len, FALSE, FALSE); - mark_col_adjust(curwin->w_cursor.lnum, (colnr_T)0, 0L, - (long)-next_leader_len, 0); - } - else if (second_indent > 0) // the "leader" for FO_Q_SECOND - { - int indent = getwhitecols_curline(); - - if (indent > 0) - { - (void)del_bytes(indent, FALSE, FALSE); - mark_col_adjust(curwin->w_cursor.lnum, - (colnr_T)0, 0L, (long)-indent, 0); - } - } - curwin->w_cursor.lnum--; - if (do_join(2, TRUE, FALSE, FALSE, FALSE) == FAIL) - { - beep_flush(); - break; - } - first_par_line = FALSE; - // If the line is getting long, format it next time - if (STRLEN(ml_get_curline()) > (size_t)max_len) - force_format = TRUE; - else - force_format = FALSE; - } - } - line_breakcheck(); - } -} - -/* - * Return TRUE if line "lnum" ends in a white character. - */ - static int -ends_in_white(linenr_T lnum) -{ - char_u *s = ml_get(lnum); - size_t l; - - if (*s == NUL) - return FALSE; - // Don't use STRLEN() inside VIM_ISWHITE(), SAS/C complains: "macro - // invocation may call function multiple times". - l = STRLEN(s) - 1; - return VIM_ISWHITE(s[l]); -} - -/* - * Blank lines, and lines containing only the comment leader, are left - * untouched by the formatting. The function returns TRUE in this - * case. It also returns TRUE when a line starts with the end of a comment - * ('e' in comment flags), so that this line is skipped, and not joined to the - * previous line. A new paragraph starts after a blank line, or when the - * comment leader changes -- webb. - */ - static int -fmt_check_par( - linenr_T lnum, - int *leader_len, - char_u **leader_flags, - int do_comments) -{ - char_u *flags = NULL; // init for GCC - char_u *ptr; - - ptr = ml_get(lnum); - if (do_comments) - *leader_len = get_leader_len(ptr, leader_flags, FALSE, TRUE); - else - *leader_len = 0; - - if (*leader_len > 0) - { - /* - * Search for 'e' flag in comment leader flags. - */ - flags = *leader_flags; - while (*flags && *flags != ':' && *flags != COM_END) - ++flags; - } - - return (*skipwhite(ptr + *leader_len) == NUL - || (*leader_len > 0 && *flags == COM_END) - || startPS(lnum, NUL, FALSE)); -} - -/* - * Return TRUE when a paragraph starts in line "lnum". Return FALSE when the - * previous line is in the same paragraph. Used for auto-formatting. - */ - int -paragraph_start(linenr_T lnum) -{ - char_u *p; - int leader_len = 0; // leader len of current line - char_u *leader_flags = NULL; // flags for leader of current line - int next_leader_len; // leader len of next line - char_u *next_leader_flags; // flags for leader of next line - int do_comments; // format comments - - if (lnum <= 1) - return TRUE; // start of the file - - p = ml_get(lnum - 1); - if (*p == NUL) - return TRUE; // after empty line - - do_comments = has_format_option(FO_Q_COMS); - if (fmt_check_par(lnum - 1, &leader_len, &leader_flags, do_comments)) - return TRUE; // after non-paragraph line - - if (fmt_check_par(lnum, &next_leader_len, &next_leader_flags, do_comments)) - return TRUE; // "lnum" is not a paragraph line - - if (has_format_option(FO_WHITE_PAR) && !ends_in_white(lnum - 1)) - return TRUE; // missing trailing space in previous line. - - if (has_format_option(FO_Q_NUMBER) && (get_number_indent(lnum) > 0)) - return TRUE; // numbered item starts in "lnum". - - if (!same_leader(lnum - 1, leader_len, leader_flags, - next_leader_len, next_leader_flags)) - return TRUE; // change of comment leader. - - return FALSE; -} - /* * prepare a few things for block mode yank/delete/tilde * diff --git a/src/option.c b/src/option.c index 504ddf489d..3f97c3cd15 100644 --- a/src/option.c +++ b/src/option.c @@ -6491,18 +6491,6 @@ wc_use_keyname(char_u *varp, long *wcp) return FALSE; } -/* - * Return TRUE if format option 'x' is in effect. - * Take care of no formatting when 'paste' is set. - */ - int -has_format_option(int x) -{ - if (p_paste) - return FALSE; - return (vim_strchr(curbuf->b_p_fo, x) != NULL); -} - /* * Return TRUE if "x" is present in 'shortmess' option, or * 'shortmess' contains 'a' and "x" is present in SHM_A. diff --git a/src/proto.h b/src/proto.h index d54936c751..f8aabc25cd 100644 --- a/src/proto.h +++ b/src/proto.h @@ -224,6 +224,7 @@ void mbyte_im_set_active(int active_arg); # endif # include "testing.pro" # include "textobject.pro" +# include "textformat.pro" # include "time.pro" # include "ui.pro" # include "undo.pro" diff --git a/src/proto/edit.pro b/src/proto/edit.pro index 49b9f4cff0..6efe537151 100644 --- a/src/proto/edit.pro +++ b/src/proto/edit.pro @@ -13,8 +13,6 @@ void truncate_spaces(char_u *line); void backspace_until_column(int col); int get_literal(void); void insertchar(int c, int flags, int second_indent); -void auto_format(int trailblank, int prev_line); -int comp_textwidth(int ff); void start_arrow(pos_T *end_insert_pos); int stop_arrow(void); void set_last_insert(int c); diff --git a/src/proto/getchar.pro b/src/proto/getchar.pro index 0382122294..9ff6620290 100644 --- a/src/proto/getchar.pro +++ b/src/proto/getchar.pro @@ -19,6 +19,7 @@ void stuffReadbuffLen(char_u *s, long len); void stuffReadbuffSpec(char_u *s); void stuffcharReadbuff(int c); void stuffnumReadbuff(long n); +void stuffescaped(char_u *arg, int literally); int start_redo(long count, int old_redo); int start_redo_ins(void); void stop_redo_ins(void); diff --git a/src/proto/ops.pro b/src/proto/ops.pro index bbb6a5dd9a..cbe49cc548 100644 --- a/src/proto/ops.pro +++ b/src/proto/ops.pro @@ -5,7 +5,6 @@ int get_op_char(int optype); int get_extra_op_char(int optype); void op_shift(oparg_T *oap, int curs_top, int amount); void shift_line(int left, int round, int amount, int call_changed_bytes); -void stuffescaped(char_u *arg, int literally); int op_delete(oparg_T *oap); int op_replace(oparg_T *oap, int c); int swapchar(int op_type, pos_T *pos); @@ -14,9 +13,6 @@ int op_change(oparg_T *oap); void adjust_cursor_eol(void); char_u *skip_comment(char_u *line, int process, int include_space, int *is_comment); int do_join(long count, int insert_space, int save_undo, int use_formatoptions, int setmark); -int fex_format(linenr_T lnum, long count, int c); -void format_lines(linenr_T line_count, int avoid_fex); -int paragraph_start(linenr_T lnum); void block_prep(oparg_T *oap, struct block_def *bdp, linenr_T lnum, int is_del); void op_addsub(oparg_T *oap, linenr_T Prenum1, int g_cmd); void clear_oparg(oparg_T *oap); diff --git a/src/proto/option.pro b/src/proto/option.pro index 7da2cbf982..210c60a229 100644 --- a/src/proto/option.pro +++ b/src/proto/option.pro @@ -62,7 +62,6 @@ void set_imsearch_global(void); void set_context_in_set_cmd(expand_T *xp, char_u *arg, int opt_flags); int ExpandSettings(expand_T *xp, regmatch_T *regmatch, int *num_file, char_u ***file); int ExpandOldSetting(int *num_file, char_u ***file); -int has_format_option(int x); int shortmess(int x); void vimrc_found(char_u *fname, char_u *envname); void change_compatible(int on); diff --git a/src/proto/textformat.pro b/src/proto/textformat.pro new file mode 100644 index 0000000000..7ed9428c9a --- /dev/null +++ b/src/proto/textformat.pro @@ -0,0 +1,11 @@ +/* textformat.c */ +int has_format_option(int x); +void internal_format(int textwidth, int second_indent, int flags, int format_only, int c); +void auto_format(int trailblank, int prev_line); +void check_auto_format(int); +int comp_textwidth(int ff); +void op_format(oparg_T *oap, int keep_cursor); +void op_formatexpr(oparg_T *oap); +int fex_format(linenr_T lnum, long count, int c); +void format_lines(linenr_T line_count, int avoid_fex); +/* vim: set ft=c : */ diff --git a/src/textformat.c b/src/textformat.c new file mode 100644 index 0000000000..c50d70f7c3 --- /dev/null +++ b/src/textformat.c @@ -0,0 +1,1088 @@ +/* vi:set ts=8 sts=4 sw=4 noet: + * + * VIM - Vi IMproved by Bram Moolenaar + * + * Do ":help uganda" in Vim to read copying and usage conditions. + * Do ":help credits" in Vim to see a list of people who contributed. + * See README.txt for an overview of the Vim source code. + */ + +/* + * textformat.c: text formatting functions + */ + +#include "vim.h" + +static int did_add_space = FALSE; // auto_format() added an extra space + // under the cursor + +#define WHITECHAR(cc) (VIM_ISWHITE(cc) && (!enc_utf8 || !utf_iscomposing(utf_ptr2char(ml_get_cursor() + 1)))) + +/* + * Return TRUE if format option 'x' is in effect. + * Take care of no formatting when 'paste' is set. + */ + int +has_format_option(int x) +{ + if (p_paste) + return FALSE; + return (vim_strchr(curbuf->b_p_fo, x) != NULL); +} + +/* + * Format text at the current insert position. + * + * If the INSCHAR_COM_LIST flag is present, then the value of second_indent + * will be the comment leader length sent to open_line(). + */ + void +internal_format( + int textwidth, + int second_indent, + int flags, + int format_only, + int c) // character to be inserted (can be NUL) +{ + int cc; + int save_char = NUL; + int haveto_redraw = FALSE; + int fo_ins_blank = has_format_option(FO_INS_BLANK); + int fo_multibyte = has_format_option(FO_MBYTE_BREAK); + int fo_white_par = has_format_option(FO_WHITE_PAR); + int first_line = TRUE; + colnr_T leader_len; + int no_leader = FALSE; + int do_comments = (flags & INSCHAR_DO_COM); +#ifdef FEAT_LINEBREAK + int has_lbr = curwin->w_p_lbr; + + // make sure win_lbr_chartabsize() counts correctly + curwin->w_p_lbr = FALSE; +#endif + + // When 'ai' is off we don't want a space under the cursor to be + // deleted. Replace it with an 'x' temporarily. + if (!curbuf->b_p_ai && !(State & VREPLACE_FLAG)) + { + cc = gchar_cursor(); + if (VIM_ISWHITE(cc)) + { + save_char = cc; + pchar_cursor('x'); + } + } + + // Repeat breaking lines, until the current line is not too long. + while (!got_int) + { + int startcol; // Cursor column at entry + int wantcol; // column at textwidth border + int foundcol; // column for start of spaces + int end_foundcol = 0; // column for start of word + colnr_T len; + colnr_T virtcol; + int orig_col = 0; + char_u *saved_text = NULL; + colnr_T col; + colnr_T end_col; + int wcc; // counter for whitespace chars + + virtcol = get_nolist_virtcol() + + char2cells(c != NUL ? c : gchar_cursor()); + if (virtcol <= (colnr_T)textwidth) + break; + + if (no_leader) + do_comments = FALSE; + else if (!(flags & INSCHAR_FORMAT) + && has_format_option(FO_WRAP_COMS)) + do_comments = TRUE; + + // Don't break until after the comment leader + if (do_comments) + leader_len = get_leader_len(ml_get_curline(), NULL, FALSE, TRUE); + else + leader_len = 0; + + // If the line doesn't start with a comment leader, then don't + // start one in a following broken line. Avoids that a %word + // moved to the start of the next line causes all following lines + // to start with %. + if (leader_len == 0) + no_leader = TRUE; + if (!(flags & INSCHAR_FORMAT) + && leader_len == 0 + && !has_format_option(FO_WRAP)) + + break; + if ((startcol = curwin->w_cursor.col) == 0) + break; + + // find column of textwidth border + coladvance((colnr_T)textwidth); + wantcol = curwin->w_cursor.col; + + curwin->w_cursor.col = startcol; + foundcol = 0; + + // Find position to break at. + // Stop at first entered white when 'formatoptions' has 'v' + while ((!fo_ins_blank && !has_format_option(FO_INS_VI)) + || (flags & INSCHAR_FORMAT) + || curwin->w_cursor.lnum != Insstart.lnum + || curwin->w_cursor.col >= Insstart.col) + { + if (curwin->w_cursor.col == startcol && c != NUL) + cc = c; + else + cc = gchar_cursor(); + if (WHITECHAR(cc)) + { + // remember position of blank just before text + end_col = curwin->w_cursor.col; + + // find start of sequence of blanks + wcc = 0; + while (curwin->w_cursor.col > 0 && WHITECHAR(cc)) + { + dec_cursor(); + cc = gchar_cursor(); + + // Increment count of how many whitespace chars in this + // group; we only need to know if it's more than one. + if (wcc < 2) + wcc++; + } + if (curwin->w_cursor.col == 0 && WHITECHAR(cc)) + break; // only spaces in front of text + + // Don't break after a period when 'formatoptions' has 'p' and + // there are less than two spaces. + if (has_format_option(FO_PERIOD_ABBR) && cc == '.' && wcc < 2) + continue; + + // Don't break until after the comment leader + if (curwin->w_cursor.col < leader_len) + break; + if (has_format_option(FO_ONE_LETTER)) + { + // do not break after one-letter words + if (curwin->w_cursor.col == 0) + break; // one-letter word at begin + // do not break "#a b" when 'tw' is 2 + if (curwin->w_cursor.col <= leader_len) + break; + col = curwin->w_cursor.col; + dec_cursor(); + cc = gchar_cursor(); + + if (WHITECHAR(cc)) + continue; // one-letter, continue + curwin->w_cursor.col = col; + } + + inc_cursor(); + + end_foundcol = end_col + 1; + foundcol = curwin->w_cursor.col; + if (curwin->w_cursor.col <= (colnr_T)wantcol) + break; + } + else if (cc >= 0x100 && fo_multibyte) + { + // Break after or before a multi-byte character. + if (curwin->w_cursor.col != startcol) + { + // Don't break until after the comment leader + if (curwin->w_cursor.col < leader_len) + break; + col = curwin->w_cursor.col; + inc_cursor(); + // Don't change end_foundcol if already set. + if (foundcol != curwin->w_cursor.col) + { + foundcol = curwin->w_cursor.col; + end_foundcol = foundcol; + if (curwin->w_cursor.col <= (colnr_T)wantcol) + break; + } + curwin->w_cursor.col = col; + } + + if (curwin->w_cursor.col == 0) + break; + + col = curwin->w_cursor.col; + + dec_cursor(); + cc = gchar_cursor(); + + if (WHITECHAR(cc)) + continue; // break with space + // Don't break until after the comment leader + if (curwin->w_cursor.col < leader_len) + break; + + curwin->w_cursor.col = col; + + foundcol = curwin->w_cursor.col; + end_foundcol = foundcol; + if (curwin->w_cursor.col <= (colnr_T)wantcol) + break; + } + if (curwin->w_cursor.col == 0) + break; + dec_cursor(); + } + + if (foundcol == 0) // no spaces, cannot break line + { + curwin->w_cursor.col = startcol; + break; + } + + // Going to break the line, remove any "$" now. + undisplay_dollar(); + + // Offset between cursor position and line break is used by replace + // stack functions. VREPLACE does not use this, and backspaces + // over the text instead. + if (State & VREPLACE_FLAG) + orig_col = startcol; // Will start backspacing from here + else + replace_offset = startcol - end_foundcol; + + // adjust startcol for spaces that will be deleted and + // characters that will remain on top line + curwin->w_cursor.col = foundcol; + while ((cc = gchar_cursor(), WHITECHAR(cc)) + && (!fo_white_par || curwin->w_cursor.col < startcol)) + inc_cursor(); + startcol -= curwin->w_cursor.col; + if (startcol < 0) + startcol = 0; + + if (State & VREPLACE_FLAG) + { + // In VREPLACE mode, we will backspace over the text to be + // wrapped, so save a copy now to put on the next line. + saved_text = vim_strsave(ml_get_cursor()); + curwin->w_cursor.col = orig_col; + if (saved_text == NULL) + break; // Can't do it, out of memory + saved_text[startcol] = NUL; + + // Backspace over characters that will move to the next line + if (!fo_white_par) + backspace_until_column(foundcol); + } + else + { + // put cursor after pos. to break line + if (!fo_white_par) + curwin->w_cursor.col = foundcol; + } + + // Split the line just before the margin. + // Only insert/delete lines, but don't really redraw the window. + open_line(FORWARD, OPENLINE_DELSPACES + OPENLINE_MARKFIX + + (fo_white_par ? OPENLINE_KEEPTRAIL : 0) + + (do_comments ? OPENLINE_DO_COM : 0) + + ((flags & INSCHAR_COM_LIST) ? OPENLINE_COM_LIST : 0) + , ((flags & INSCHAR_COM_LIST) ? second_indent : old_indent)); + if (!(flags & INSCHAR_COM_LIST)) + old_indent = 0; + + replace_offset = 0; + if (first_line) + { + if (!(flags & INSCHAR_COM_LIST)) + { + // This section is for auto-wrap of numeric lists. When not + // in insert mode (i.e. format_lines()), the INSCHAR_COM_LIST + // flag will be set and open_line() will handle it (as seen + // above). The code here (and in get_number_indent()) will + // recognize comments if needed... + if (second_indent < 0 && has_format_option(FO_Q_NUMBER)) + second_indent = + get_number_indent(curwin->w_cursor.lnum - 1); + if (second_indent >= 0) + { + if (State & VREPLACE_FLAG) + change_indent(INDENT_SET, second_indent, + FALSE, NUL, TRUE); + else + if (leader_len > 0 && second_indent - leader_len > 0) + { + int i; + int padding = second_indent - leader_len; + + // We started at the first_line of a numbered list + // that has a comment. the open_line() function has + // inserted the proper comment leader and positioned + // the cursor at the end of the split line. Now we + // add the additional whitespace needed after the + // comment leader for the numbered list. + for (i = 0; i < padding; i++) + ins_str((char_u *)" "); + } + else + { + (void)set_indent(second_indent, SIN_CHANGED); + } + } + } + first_line = FALSE; + } + + if (State & VREPLACE_FLAG) + { + // In VREPLACE mode we have backspaced over the text to be + // moved, now we re-insert it into the new line. + ins_bytes(saved_text); + vim_free(saved_text); + } + else + { + // Check if cursor is not past the NUL off the line, cindent + // may have added or removed indent. + curwin->w_cursor.col += startcol; + len = (colnr_T)STRLEN(ml_get_curline()); + if (curwin->w_cursor.col > len) + curwin->w_cursor.col = len; + } + + haveto_redraw = TRUE; +#ifdef FEAT_CINDENT + set_can_cindent(TRUE); +#endif + // moved the cursor, don't autoindent or cindent now + did_ai = FALSE; +#ifdef FEAT_SMARTINDENT + did_si = FALSE; + can_si = FALSE; + can_si_back = FALSE; +#endif + line_breakcheck(); + } + + if (save_char != NUL) // put back space after cursor + pchar_cursor(save_char); + +#ifdef FEAT_LINEBREAK + curwin->w_p_lbr = has_lbr; +#endif + if (!format_only && haveto_redraw) + { + update_topline(); + redraw_curbuf_later(VALID); + } +} + +/* + * Blank lines, and lines containing only the comment leader, are left + * untouched by the formatting. The function returns TRUE in this + * case. It also returns TRUE when a line starts with the end of a comment + * ('e' in comment flags), so that this line is skipped, and not joined to the + * previous line. A new paragraph starts after a blank line, or when the + * comment leader changes -- webb. + */ + static int +fmt_check_par( + linenr_T lnum, + int *leader_len, + char_u **leader_flags, + int do_comments) +{ + char_u *flags = NULL; // init for GCC + char_u *ptr; + + ptr = ml_get(lnum); + if (do_comments) + *leader_len = get_leader_len(ptr, leader_flags, FALSE, TRUE); + else + *leader_len = 0; + + if (*leader_len > 0) + { + // Search for 'e' flag in comment leader flags. + flags = *leader_flags; + while (*flags && *flags != ':' && *flags != COM_END) + ++flags; + } + + return (*skipwhite(ptr + *leader_len) == NUL + || (*leader_len > 0 && *flags == COM_END) + || startPS(lnum, NUL, FALSE)); +} + +/* + * Return TRUE if line "lnum" ends in a white character. + */ + static int +ends_in_white(linenr_T lnum) +{ + char_u *s = ml_get(lnum); + size_t l; + + if (*s == NUL) + return FALSE; + // Don't use STRLEN() inside VIM_ISWHITE(), SAS/C complains: "macro + // invocation may call function multiple times". + l = STRLEN(s) - 1; + return VIM_ISWHITE(s[l]); +} + +/* + * Return TRUE if the two comment leaders given are the same. "lnum" is + * the first line. White-space is ignored. Note that the whole of + * 'leader1' must match 'leader2_len' characters from 'leader2' -- webb + */ + static int +same_leader( + linenr_T lnum, + int leader1_len, + char_u *leader1_flags, + int leader2_len, + char_u *leader2_flags) +{ + int idx1 = 0, idx2 = 0; + char_u *p; + char_u *line1; + char_u *line2; + + if (leader1_len == 0) + return (leader2_len == 0); + + // If first leader has 'f' flag, the lines can be joined only if the + // second line does not have a leader. + // If first leader has 'e' flag, the lines can never be joined. + // If fist leader has 's' flag, the lines can only be joined if there is + // some text after it and the second line has the 'm' flag. + if (leader1_flags != NULL) + { + for (p = leader1_flags; *p && *p != ':'; ++p) + { + if (*p == COM_FIRST) + return (leader2_len == 0); + if (*p == COM_END) + return FALSE; + if (*p == COM_START) + { + if (*(ml_get(lnum) + leader1_len) == NUL) + return FALSE; + if (leader2_flags == NULL || leader2_len == 0) + return FALSE; + for (p = leader2_flags; *p && *p != ':'; ++p) + if (*p == COM_MIDDLE) + return TRUE; + return FALSE; + } + } + } + + // Get current line and next line, compare the leaders. + // The first line has to be saved, only one line can be locked at a time. + line1 = vim_strsave(ml_get(lnum)); + if (line1 != NULL) + { + for (idx1 = 0; VIM_ISWHITE(line1[idx1]); ++idx1) + ; + line2 = ml_get(lnum + 1); + for (idx2 = 0; idx2 < leader2_len; ++idx2) + { + if (!VIM_ISWHITE(line2[idx2])) + { + if (line1[idx1++] != line2[idx2]) + break; + } + else + while (VIM_ISWHITE(line1[idx1])) + ++idx1; + } + vim_free(line1); + } + return (idx2 == leader2_len && idx1 == leader1_len); +} + +/* + * Return TRUE when a paragraph starts in line "lnum". Return FALSE when the + * previous line is in the same paragraph. Used for auto-formatting. + */ + static int +paragraph_start(linenr_T lnum) +{ + char_u *p; + int leader_len = 0; // leader len of current line + char_u *leader_flags = NULL; // flags for leader of current line + int next_leader_len; // leader len of next line + char_u *next_leader_flags; // flags for leader of next line + int do_comments; // format comments + + if (lnum <= 1) + return TRUE; // start of the file + + p = ml_get(lnum - 1); + if (*p == NUL) + return TRUE; // after empty line + + do_comments = has_format_option(FO_Q_COMS); + if (fmt_check_par(lnum - 1, &leader_len, &leader_flags, do_comments)) + return TRUE; // after non-paragraph line + + if (fmt_check_par(lnum, &next_leader_len, &next_leader_flags, do_comments)) + return TRUE; // "lnum" is not a paragraph line + + if (has_format_option(FO_WHITE_PAR) && !ends_in_white(lnum - 1)) + return TRUE; // missing trailing space in previous line. + + if (has_format_option(FO_Q_NUMBER) && (get_number_indent(lnum) > 0)) + return TRUE; // numbered item starts in "lnum". + + if (!same_leader(lnum - 1, leader_len, leader_flags, + next_leader_len, next_leader_flags)) + return TRUE; // change of comment leader. + + return FALSE; +} + +/* + * Called after inserting or deleting text: When 'formatoptions' includes the + * 'a' flag format from the current line until the end of the paragraph. + * Keep the cursor at the same position relative to the text. + * The caller must have saved the cursor line for undo, following ones will be + * saved here. + */ + void +auto_format( + int trailblank, // when TRUE also format with trailing blank + int prev_line) // may start in previous line +{ + pos_T pos; + colnr_T len; + char_u *old; + char_u *new, *pnew; + int wasatend; + int cc; + + if (!has_format_option(FO_AUTO)) + return; + + pos = curwin->w_cursor; + old = ml_get_curline(); + + // may remove added space + check_auto_format(FALSE); + + // Don't format in Insert mode when the cursor is on a trailing blank, the + // user might insert normal text next. Also skip formatting when "1" is + // in 'formatoptions' and there is a single character before the cursor. + // Otherwise the line would be broken and when typing another non-white + // next they are not joined back together. + wasatend = (pos.col == (colnr_T)STRLEN(old)); + if (*old != NUL && !trailblank && wasatend) + { + dec_cursor(); + cc = gchar_cursor(); + if (!WHITECHAR(cc) && curwin->w_cursor.col > 0 + && has_format_option(FO_ONE_LETTER)) + dec_cursor(); + cc = gchar_cursor(); + if (WHITECHAR(cc)) + { + curwin->w_cursor = pos; + return; + } + curwin->w_cursor = pos; + } + + // With the 'c' flag in 'formatoptions' and 't' missing: only format + // comments. + if (has_format_option(FO_WRAP_COMS) && !has_format_option(FO_WRAP) + && get_leader_len(old, NULL, FALSE, TRUE) == 0) + return; + + // May start formatting in a previous line, so that after "x" a word is + // moved to the previous line if it fits there now. Only when this is not + // the start of a paragraph. + if (prev_line && !paragraph_start(curwin->w_cursor.lnum)) + { + --curwin->w_cursor.lnum; + if (u_save_cursor() == FAIL) + return; + } + + // Do the formatting and restore the cursor position. "saved_cursor" will + // be adjusted for the text formatting. + saved_cursor = pos; + format_lines((linenr_T)-1, FALSE); + curwin->w_cursor = saved_cursor; + saved_cursor.lnum = 0; + + if (curwin->w_cursor.lnum > curbuf->b_ml.ml_line_count) + { + // "cannot happen" + curwin->w_cursor.lnum = curbuf->b_ml.ml_line_count; + coladvance((colnr_T)MAXCOL); + } + else + check_cursor_col(); + + // Insert mode: If the cursor is now after the end of the line while it + // previously wasn't, the line was broken. Because of the rule above we + // need to add a space when 'w' is in 'formatoptions' to keep a paragraph + // formatted. + if (!wasatend && has_format_option(FO_WHITE_PAR)) + { + new = ml_get_curline(); + len = (colnr_T)STRLEN(new); + if (curwin->w_cursor.col == len) + { + pnew = vim_strnsave(new, len + 2); + pnew[len] = ' '; + pnew[len + 1] = NUL; + ml_replace(curwin->w_cursor.lnum, pnew, FALSE); + // remove the space later + did_add_space = TRUE; + } + else + // may remove added space + check_auto_format(FALSE); + } + + check_cursor(); +} + +/* + * When an extra space was added to continue a paragraph for auto-formatting, + * delete it now. The space must be under the cursor, just after the insert + * position. + */ + void +check_auto_format( + int end_insert) // TRUE when ending Insert mode +{ + int c = ' '; + int cc; + + if (did_add_space) + { + cc = gchar_cursor(); + if (!WHITECHAR(cc)) + // Somehow the space was removed already. + did_add_space = FALSE; + else + { + if (!end_insert) + { + inc_cursor(); + c = gchar_cursor(); + dec_cursor(); + } + if (c != NUL) + { + // The space is no longer at the end of the line, delete it. + del_char(FALSE); + did_add_space = FALSE; + } + } + } +} + +/* + * Find out textwidth to be used for formatting: + * if 'textwidth' option is set, use it + * else if 'wrapmargin' option is set, use curwin->w_width - 'wrapmargin' + * if invalid value, use 0. + * Set default to window width (maximum 79) for "gq" operator. + */ + int +comp_textwidth( + int ff) // force formatting (for "gq" command) +{ + int textwidth; + + textwidth = curbuf->b_p_tw; + if (textwidth == 0 && curbuf->b_p_wm) + { + // The width is the window width minus 'wrapmargin' minus all the + // things that add to the margin. + textwidth = curwin->w_width - curbuf->b_p_wm; +#ifdef FEAT_CMDWIN + if (cmdwin_type != 0) + textwidth -= 1; +#endif +#ifdef FEAT_FOLDING + textwidth -= curwin->w_p_fdc; +#endif +#ifdef FEAT_SIGNS + if (signcolumn_on(curwin)) + textwidth -= 1; +#endif + if (curwin->w_p_nu || curwin->w_p_rnu) + textwidth -= 8; + } + if (textwidth < 0) + textwidth = 0; + if (ff && textwidth == 0) + { + textwidth = curwin->w_width - 1; + if (textwidth > 79) + textwidth = 79; + } + return textwidth; +} + +/* + * Implementation of the format operator 'gq'. + */ + void +op_format( + oparg_T *oap, + int keep_cursor) // keep cursor on same text char +{ + long old_line_count = curbuf->b_ml.ml_line_count; + + // Place the cursor where the "gq" or "gw" command was given, so that "u" + // can put it back there. + curwin->w_cursor = oap->cursor_start; + + if (u_save((linenr_T)(oap->start.lnum - 1), + (linenr_T)(oap->end.lnum + 1)) == FAIL) + return; + curwin->w_cursor = oap->start; + + if (oap->is_VIsual) + // When there is no change: need to remove the Visual selection + redraw_curbuf_later(INVERTED); + + if (!cmdmod.lockmarks) + // Set '[ mark at the start of the formatted area + curbuf->b_op_start = oap->start; + + // For "gw" remember the cursor position and put it back below (adjusted + // for joined and split lines). + if (keep_cursor) + saved_cursor = oap->cursor_start; + + format_lines(oap->line_count, keep_cursor); + + // Leave the cursor at the first non-blank of the last formatted line. + // If the cursor was moved one line back (e.g. with "Q}") go to the next + // line, so "." will do the next lines. + if (oap->end_adjusted && curwin->w_cursor.lnum < curbuf->b_ml.ml_line_count) + ++curwin->w_cursor.lnum; + beginline(BL_WHITE | BL_FIX); + old_line_count = curbuf->b_ml.ml_line_count - old_line_count; + msgmore(old_line_count); + + if (!cmdmod.lockmarks) + // put '] mark on the end of the formatted area + curbuf->b_op_end = curwin->w_cursor; + + if (keep_cursor) + { + curwin->w_cursor = saved_cursor; + saved_cursor.lnum = 0; + } + + if (oap->is_VIsual) + { + win_T *wp; + + FOR_ALL_WINDOWS(wp) + { + if (wp->w_old_cursor_lnum != 0) + { + // When lines have been inserted or deleted, adjust the end of + // the Visual area to be redrawn. + if (wp->w_old_cursor_lnum > wp->w_old_visual_lnum) + wp->w_old_cursor_lnum += old_line_count; + else + wp->w_old_visual_lnum += old_line_count; + } + } + } +} + +#if defined(FEAT_EVAL) || defined(PROTO) +/* + * Implementation of the format operator 'gq' for when using 'formatexpr'. + */ + void +op_formatexpr(oparg_T *oap) +{ + if (oap->is_VIsual) + // When there is no change: need to remove the Visual selection + redraw_curbuf_later(INVERTED); + + if (fex_format(oap->start.lnum, oap->line_count, NUL) != 0) + // As documented: when 'formatexpr' returns non-zero fall back to + // internal formatting. + op_format(oap, FALSE); +} + + int +fex_format( + linenr_T lnum, + long count, + int c) // character to be inserted +{ + int use_sandbox = was_set_insecurely((char_u *)"formatexpr", + OPT_LOCAL); + int r; + char_u *fex; + + // Set v:lnum to the first line number and v:count to the number of lines. + // Set v:char to the character to be inserted (can be NUL). + set_vim_var_nr(VV_LNUM, lnum); + set_vim_var_nr(VV_COUNT, count); + set_vim_var_char(c); + + // Make a copy, the option could be changed while calling it. + fex = vim_strsave(curbuf->b_p_fex); + if (fex == NULL) + return 0; + + // Evaluate the function. + if (use_sandbox) + ++sandbox; + r = (int)eval_to_number(fex); + if (use_sandbox) + --sandbox; + + set_vim_var_string(VV_CHAR, NULL, -1); + vim_free(fex); + + return r; +} +#endif + +/* + * Format "line_count" lines, starting at the cursor position. + * When "line_count" is negative, format until the end of the paragraph. + * Lines after the cursor line are saved for undo, caller must have saved the + * first line. + */ + void +format_lines( + linenr_T line_count, + int avoid_fex) // don't use 'formatexpr' +{ + int max_len; + int is_not_par; // current line not part of parag. + int next_is_not_par; // next line not part of paragraph + int is_end_par; // at end of paragraph + int prev_is_end_par = FALSE;// prev. line not part of parag. + int next_is_start_par = FALSE; + int leader_len = 0; // leader len of current line + int next_leader_len; // leader len of next line + char_u *leader_flags = NULL; // flags for leader of current line + char_u *next_leader_flags; // flags for leader of next line + int do_comments; // format comments + int do_comments_list = 0; // format comments with 'n' or '2' + int advance = TRUE; + int second_indent = -1; // indent for second line (comment + // aware) + int do_second_indent; + int do_number_indent; + int do_trail_white; + int first_par_line = TRUE; + int smd_save; + long count; + int need_set_indent = TRUE; // set indent of next paragraph + int force_format = FALSE; + int old_State = State; + + // length of a line to force formatting: 3 * 'tw' + max_len = comp_textwidth(TRUE) * 3; + + // check for 'q', '2' and '1' in 'formatoptions' + do_comments = has_format_option(FO_Q_COMS); + do_second_indent = has_format_option(FO_Q_SECOND); + do_number_indent = has_format_option(FO_Q_NUMBER); + do_trail_white = has_format_option(FO_WHITE_PAR); + + // Get info about the previous and current line. + if (curwin->w_cursor.lnum > 1) + is_not_par = fmt_check_par(curwin->w_cursor.lnum - 1 + , &leader_len, &leader_flags, do_comments); + else + is_not_par = TRUE; + next_is_not_par = fmt_check_par(curwin->w_cursor.lnum + , &next_leader_len, &next_leader_flags, do_comments); + is_end_par = (is_not_par || next_is_not_par); + if (!is_end_par && do_trail_white) + is_end_par = !ends_in_white(curwin->w_cursor.lnum - 1); + + curwin->w_cursor.lnum--; + for (count = line_count; count != 0 && !got_int; --count) + { + // Advance to next paragraph. + if (advance) + { + curwin->w_cursor.lnum++; + prev_is_end_par = is_end_par; + is_not_par = next_is_not_par; + leader_len = next_leader_len; + leader_flags = next_leader_flags; + } + + // The last line to be formatted. + if (count == 1 || curwin->w_cursor.lnum == curbuf->b_ml.ml_line_count) + { + next_is_not_par = TRUE; + next_leader_len = 0; + next_leader_flags = NULL; + } + else + { + next_is_not_par = fmt_check_par(curwin->w_cursor.lnum + 1 + , &next_leader_len, &next_leader_flags, do_comments); + if (do_number_indent) + next_is_start_par = + (get_number_indent(curwin->w_cursor.lnum + 1) > 0); + } + advance = TRUE; + is_end_par = (is_not_par || next_is_not_par || next_is_start_par); + if (!is_end_par && do_trail_white) + is_end_par = !ends_in_white(curwin->w_cursor.lnum); + + // Skip lines that are not in a paragraph. + if (is_not_par) + { + if (line_count < 0) + break; + } + else + { + // For the first line of a paragraph, check indent of second line. + // Don't do this for comments and empty lines. + if (first_par_line + && (do_second_indent || do_number_indent) + && prev_is_end_par + && curwin->w_cursor.lnum < curbuf->b_ml.ml_line_count) + { + if (do_second_indent && !LINEEMPTY(curwin->w_cursor.lnum + 1)) + { + if (leader_len == 0 && next_leader_len == 0) + { + // no comment found + second_indent = + get_indent_lnum(curwin->w_cursor.lnum + 1); + } + else + { + second_indent = next_leader_len; + do_comments_list = 1; + } + } + else if (do_number_indent) + { + if (leader_len == 0 && next_leader_len == 0) + { + // no comment found + second_indent = + get_number_indent(curwin->w_cursor.lnum); + } + else + { + // get_number_indent() is now "comment aware"... + second_indent = + get_number_indent(curwin->w_cursor.lnum); + do_comments_list = 1; + } + } + } + + // When the comment leader changes, it's the end of the paragraph. + if (curwin->w_cursor.lnum >= curbuf->b_ml.ml_line_count + || !same_leader(curwin->w_cursor.lnum, + leader_len, leader_flags, + next_leader_len, next_leader_flags)) + is_end_par = TRUE; + + // If we have got to the end of a paragraph, or the line is + // getting long, format it. + if (is_end_par || force_format) + { + if (need_set_indent) + // replace indent in first line with minimal number of + // tabs and spaces, according to current options + (void)set_indent(get_indent(), SIN_CHANGED); + + // put cursor on last non-space + State = NORMAL; // don't go past end-of-line + coladvance((colnr_T)MAXCOL); + while (curwin->w_cursor.col && vim_isspace(gchar_cursor())) + dec_cursor(); + + // do the formatting, without 'showmode' + State = INSERT; // for open_line() + smd_save = p_smd; + p_smd = FALSE; + insertchar(NUL, INSCHAR_FORMAT + + (do_comments ? INSCHAR_DO_COM : 0) + + (do_comments && do_comments_list + ? INSCHAR_COM_LIST : 0) + + (avoid_fex ? INSCHAR_NO_FEX : 0), second_indent); + State = old_State; + p_smd = smd_save; + second_indent = -1; + // at end of par.: need to set indent of next par. + need_set_indent = is_end_par; + if (is_end_par) + { + // When called with a negative line count, break at the + // end of the paragraph. + if (line_count < 0) + break; + first_par_line = TRUE; + } + force_format = FALSE; + } + + // When still in same paragraph, join the lines together. But + // first delete the leader from the second line. + if (!is_end_par) + { + advance = FALSE; + curwin->w_cursor.lnum++; + curwin->w_cursor.col = 0; + if (line_count < 0 && u_save_cursor() == FAIL) + break; + if (next_leader_len > 0) + { + (void)del_bytes((long)next_leader_len, FALSE, FALSE); + mark_col_adjust(curwin->w_cursor.lnum, (colnr_T)0, 0L, + (long)-next_leader_len, 0); + } + else if (second_indent > 0) // the "leader" for FO_Q_SECOND + { + int indent = getwhitecols_curline(); + + if (indent > 0) + { + (void)del_bytes(indent, FALSE, FALSE); + mark_col_adjust(curwin->w_cursor.lnum, + (colnr_T)0, 0L, (long)-indent, 0); + } + } + curwin->w_cursor.lnum--; + if (do_join(2, TRUE, FALSE, FALSE, FALSE) == FAIL) + { + beep_flush(); + break; + } + first_par_line = FALSE; + // If the line is getting long, format it next time + if (STRLEN(ml_get_curline()) > (size_t)max_len) + force_format = TRUE; + else + force_format = FALSE; + } + } + line_breakcheck(); + } +} diff --git a/src/version.c b/src/version.c index 7267318623..35037f8b2a 100644 --- a/src/version.c +++ b/src/version.c @@ -746,6 +746,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 674, /**/ 673, /**/ From b84a381c75e50ca0e0a24cc3e152d0c70f8c2c7d Mon Sep 17 00:00:00 2001 From: Bram Moolenaar <Bram@vim.org> Date: Fri, 1 May 2020 15:44:29 +0200 Subject: [PATCH 069/230] patch 8.2.0675: Vim9: no support for closures Problem: Vim9: no support for closures. Solution: Do not re-use stack entries. --- src/evalvars.c | 16 +++--- src/ex_docmd.c | 4 +- src/proto/evalvars.pro | 2 +- src/proto/ex_docmd.pro | 4 +- src/version.c | 2 + src/vim9compile.c | 127 +++++++++++++++++++++-------------------- 6 files changed, 81 insertions(+), 74 deletions(-) diff --git a/src/evalvars.c b/src/evalvars.c index f6f077983b..08b2990bcc 100644 --- a/src/evalvars.c +++ b/src/evalvars.c @@ -2495,19 +2495,19 @@ get_script_local_ht(void) /* * Look for "name[len]" in script-local variables. - * Return -1 when not found. + * Return a non-NULL pointer when found, NULL when not found. */ - int + void * lookup_scriptvar(char_u *name, size_t len, cctx_T *dummy UNUSED) { hashtab_T *ht = get_script_local_ht(); char_u buffer[30]; char_u *p; - int res; + void *res; hashitem_T *hi; if (ht == NULL) - return -1; + return NULL; if (len < sizeof(buffer) - 1) { vim_strncpy(buffer, name, len); @@ -2517,15 +2517,15 @@ lookup_scriptvar(char_u *name, size_t len, cctx_T *dummy UNUSED) { p = vim_strnsave(name, (int)len); if (p == NULL) - return -1; + return NULL; } hi = hash_find(ht, p); - res = HASHITEM_EMPTY(hi) ? -1 : 1; + res = HASHITEM_EMPTY(hi) ? NULL : hi; // if not script-local, then perhaps imported - if (res == -1 && find_imported(p, 0, NULL) != NULL) - res = 1; + if (res == NULL && find_imported(p, 0, NULL) != NULL) + res = p; if (p != buffer) vim_free(p); diff --git a/src/ex_docmd.c b/src/ex_docmd.c index 65ef936e9f..94a3367a3a 100644 --- a/src/ex_docmd.c +++ b/src/ex_docmd.c @@ -3157,7 +3157,7 @@ append_command(char_u *cmd) find_ex_command( exarg_T *eap, int *full UNUSED, - int (*lookup)(char_u *, size_t, cctx_T *) UNUSED, + void *(*lookup)(char_u *, size_t, cctx_T *) UNUSED, cctx_T *cctx UNUSED) { int len; @@ -3197,7 +3197,7 @@ find_ex_command( // "g:var = expr" // "var = expr" where "var" is a local var name. if (((p - eap->cmd) > 2 && eap->cmd[1] == ':') - || lookup(eap->cmd, p - eap->cmd, cctx) >= 0) + || lookup(eap->cmd, p - eap->cmd, cctx) != NULL) { eap->cmdidx = CMD_let; return eap->cmd; diff --git a/src/proto/evalvars.pro b/src/proto/evalvars.pro index e4159328dc..58e922113e 100644 --- a/src/proto/evalvars.pro +++ b/src/proto/evalvars.pro @@ -55,7 +55,7 @@ int get_var_tv(char_u *name, int len, typval_T *rettv, dictitem_T **dip, int ver void check_vars(char_u *name, int len); dictitem_T *find_var(char_u *name, hashtab_T **htp, int no_autoload); dictitem_T *find_var_in_ht(hashtab_T *ht, int htname, char_u *varname, int no_autoload); -int lookup_scriptvar(char_u *name, size_t len, cctx_T *dummy); +void *lookup_scriptvar(char_u *name, size_t len, cctx_T *dummy); hashtab_T *find_var_ht(char_u *name, char_u **varname); char_u *get_var_value(char_u *name); void new_script_vars(scid_T id); diff --git a/src/proto/ex_docmd.pro b/src/proto/ex_docmd.pro index eba5ee4973..7f5c691282 100644 --- a/src/proto/ex_docmd.pro +++ b/src/proto/ex_docmd.pro @@ -7,7 +7,7 @@ void *getline_cookie(char_u *(*fgetline)(int, void *, int, int), void *cookie); int parse_command_modifiers(exarg_T *eap, char **errormsg, int skip_only); int parse_cmd_address(exarg_T *eap, char **errormsg, int silent); int checkforcmd(char_u **pp, char *cmd, int len); -char_u *find_ex_command(exarg_T *eap, int *full, int (*lookup)(char_u *, size_t, cctx_T *), cctx_T *cctx); +char_u *find_ex_command(exarg_T *eap, int *full, void *((*lookup)(char_u *, size_t, cctx_T *)), cctx_T *cctx); int modifier_len(char_u *cmd); int cmd_exists(char_u *name); cmdidx_T excmd_get_cmdidx(char_u *cmd, int len); @@ -19,7 +19,7 @@ void separate_nextcmd(exarg_T *eap); char_u *skip_cmd_arg(char_u *p, int rembs); int get_bad_opt(char_u *p, exarg_T *eap); int ends_excmd(int c); -int ends_excmd2(char_u *before, char_u *cmd); +int ends_excmd2(char_u *cmd_start, char_u *cmd); char_u *find_nextcmd(char_u *p); char_u *check_nextcmd(char_u *p); char_u *get_command_name(expand_T *xp, int idx); diff --git a/src/version.c b/src/version.c index 35037f8b2a..9657185516 100644 --- a/src/version.c +++ b/src/version.c @@ -746,6 +746,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 675, /**/ 674, /**/ diff --git a/src/vim9compile.c b/src/vim9compile.c index 7b433a3b15..c3f3bfdfbc 100644 --- a/src/vim9compile.c +++ b/src/vim9compile.c @@ -97,6 +97,7 @@ struct scope_S { typedef struct { char_u *lv_name; type_T *lv_type; + int lv_idx; // index of the variable on the stack int lv_const; // when TRUE cannot be assigned to int lv_arg; // when TRUE this is an argument } lvar_T; @@ -112,7 +113,7 @@ struct cctx_S { garray_T ctx_instr; // generated instructions garray_T ctx_locals; // currently visible local variables - int ctx_max_local; // maximum number of locals at one time + int ctx_locals_count; // total number of local variables garray_T ctx_imports; // imported items @@ -120,6 +121,9 @@ struct cctx_S { // commands after "else" scope_T *ctx_scope; // current scope, NULL at toplevel + cctx_T *ctx_outer; // outer scope for lambda or nested + // function + garray_T ctx_type_stack; // type of each item on the stack garray_T *ctx_type_list; // list of pointers to allocated types }; @@ -135,24 +139,25 @@ static void arg_type_mismatch(type_T *expected, type_T *actual, int argidx); static int check_type(type_T *expected, type_T *actual, int give_msg); /* - * Lookup variable "name" in the local scope and return the index. + * Lookup variable "name" in the local scope and return it. + * Return NULL if not found. */ - static int + static lvar_T * lookup_local(char_u *name, size_t len, cctx_T *cctx) { int idx; if (len == 0) - return -1; + return NULL; for (idx = 0; idx < cctx->ctx_locals.ga_len; ++idx) { lvar_T *lvar = ((lvar_T *)cctx->ctx_locals.ga_data) + idx; if (STRNCMP(name, lvar->lv_name, len) == 0 && STRLEN(lvar->lv_name) == len) - return idx; + return lvar; } - return -1; + return NULL; } /* @@ -217,7 +222,7 @@ check_defined(char_u *p, int len, cctx_T *cctx) { if (lookup_script(p, len) == OK || (cctx != NULL - && (lookup_local(p, len, cctx) >= 0 + && (lookup_local(p, len, cctx) != NULL || find_imported(p, len, cctx) != NULL))) { semsg("E1073: imported name already defined: %s", p); @@ -1458,33 +1463,34 @@ generate_EXECCONCAT(cctx_T *cctx, int count) /* * Reserve space for a local variable. - * Return the index or -1 if it failed. + * Return the variable or NULL if it failed. */ - static int + static lvar_T * reserve_local(cctx_T *cctx, char_u *name, size_t len, int isConst, type_T *type) { - int idx; lvar_T *lvar; if (lookup_arg(name, len, cctx) >= 0 || lookup_vararg(name, len, cctx)) { emsg_namelen(_("E1006: %s is used as an argument"), name, (int)len); - return -1; + return NULL; } if (ga_grow(&cctx->ctx_locals, 1) == FAIL) - return -1; - idx = cctx->ctx_locals.ga_len; - if (cctx->ctx_max_local < idx + 1) - cctx->ctx_max_local = idx + 1; - ++cctx->ctx_locals.ga_len; + return NULL; + lvar = ((lvar_T *)cctx->ctx_locals.ga_data) + cctx->ctx_locals.ga_len++; + + // Every local variable uses the next entry on the stack. We could re-use + // the last ones when leaving a scope, but then variables used in a closure + // might get overwritten. To keep things simple do not re-use stack + // entries. This is less efficient, but memory is cheap these days. + lvar->lv_idx = cctx->ctx_locals_count++; - lvar = ((lvar_T *)cctx->ctx_locals.ga_data) + idx; lvar->lv_name = vim_strnsave(name, (int)(len == 0 ? STRLEN(name) : len)); lvar->lv_const = isConst; lvar->lv_type = type; - return idx; + return lvar; } /* @@ -1511,7 +1517,7 @@ unwind_locals(cctx_T *cctx, int new_top) * Free all local variables. */ static void -free_local(cctx_T *cctx) +free_locals(cctx_T *cctx) { unwind_locals(cctx, 0); ga_clear(&cctx->ctx_locals); @@ -2331,10 +2337,12 @@ compile_load(char_u **arg, char_u *end_arg, cctx_T *cctx, int error) } else { - idx = lookup_local(*arg, len, cctx); - if (idx >= 0) + lvar_T *lvar = lookup_local(*arg, len, cctx); + + if (lvar != NULL) { - type = (((lvar_T *)cctx->ctx_locals.ga_data) + idx)->lv_type; + type = lvar->lv_type; + idx = lvar->lv_idx; gen_load = TRUE; } else @@ -4040,7 +4048,6 @@ compile_assignment(char_u *arg, exarg_T *eap, cmdidx_T cmdidx, cctx_T *cctx) int semicolon = 0; size_t varlen; garray_T *instr = &cctx->ctx_instr; - int idx = -1; int new_local = FALSE; char_u *op; int opt_type; @@ -4050,7 +4057,7 @@ compile_assignment(char_u *arg, exarg_T *eap, cmdidx_T cmdidx, cctx_T *cctx) int oplen = 0; int heredoc = FALSE; type_T *type = &t_any; - lvar_T *lvar; + lvar_T *lvar = NULL; char_u *name; char_u *sp; int has_type = FALSE; @@ -4203,6 +4210,8 @@ compile_assignment(char_u *arg, exarg_T *eap, cmdidx_T cmdidx, cctx_T *cctx) } else { + int idx; + for (idx = 0; reserved[idx] != NULL; ++idx) if (STRCMP(reserved[idx], name) == 0) { @@ -4210,8 +4219,8 @@ compile_assignment(char_u *arg, exarg_T *eap, cmdidx_T cmdidx, cctx_T *cctx) goto theend; } - idx = lookup_local(arg, varlen, cctx); - if (idx >= 0) + lvar = lookup_local(arg, varlen, cctx); + if (lvar != NULL) { if (is_decl) { @@ -4220,10 +4229,10 @@ compile_assignment(char_u *arg, exarg_T *eap, cmdidx_T cmdidx, cctx_T *cctx) } else { - lvar = ((lvar_T *)cctx->ctx_locals.ga_data) + idx; if (lvar->lv_const) { - semsg(_("E1018: Cannot assign to a constant: %s"), name); + semsg(_("E1018: Cannot assign to a constant: %s"), + name); goto theend; } } @@ -4262,11 +4271,8 @@ compile_assignment(char_u *arg, exarg_T *eap, cmdidx_T cmdidx, cctx_T *cctx) type = parse_type(&p, cctx->ctx_type_list); has_type = TRUE; } - else if (idx >= 0) - { - lvar = ((lvar_T *)cctx->ctx_locals.ga_data) + idx; + else if (lvar != NULL) type = lvar->lv_type; - } } sp = p; @@ -4288,7 +4294,7 @@ compile_assignment(char_u *arg, exarg_T *eap, cmdidx_T cmdidx, cctx_T *cctx) goto theend; } - if (idx < 0 && dest == dest_local && cctx->ctx_skip != TRUE) + if (lvar == NULL && dest == dest_local && cctx->ctx_skip != TRUE) { if (oplen > 1 && !heredoc) { @@ -4301,8 +4307,8 @@ compile_assignment(char_u *arg, exarg_T *eap, cmdidx_T cmdidx, cctx_T *cctx) // new local variable if (type->tt_type == VAR_FUNC && var_check_func_name(name, TRUE)) goto theend; - idx = reserve_local(cctx, arg, varlen, cmdidx == CMD_const, type); - if (idx < 0) + lvar = reserve_local(cctx, arg, varlen, cmdidx == CMD_const, type); + if (lvar == NULL) goto theend; new_local = TRUE; } @@ -4370,7 +4376,7 @@ compile_assignment(char_u *arg, exarg_T *eap, cmdidx_T cmdidx, cctx_T *cctx) generate_LOADV(cctx, name + 2, TRUE); break; case dest_local: - generate_LOAD(cctx, ISN_LOAD, idx, NULL, type); + generate_LOAD(cctx, ISN_LOAD, lvar->lv_idx, NULL, type); break; } } @@ -4392,9 +4398,8 @@ compile_assignment(char_u *arg, exarg_T *eap, cmdidx_T cmdidx, cctx_T *cctx) stack = &cctx->ctx_type_stack; stacktype = stack->ga_len == 0 ? &t_void : ((type_T **)stack->ga_data)[stack->ga_len - 1]; - if (idx >= 0 && (is_decl || !has_type)) + if (lvar != NULL && (is_decl || !has_type)) { - lvar = ((lvar_T *)cctx->ctx_locals.ga_data) + idx; if (new_local && !has_type) { if (stacktype->tt_type == VAR_VOID) @@ -4546,6 +4551,7 @@ compile_assignment(char_u *arg, exarg_T *eap, cmdidx_T cmdidx, cctx_T *cctx) char_u *rawname = name + (name[1] == ':' ? 2 : 0); imported_T *import = NULL; int sid = current_sctx.sc_sid; + int idx; if (name[1] != ':') { @@ -4581,6 +4587,7 @@ compile_assignment(char_u *arg, exarg_T *eap, cmdidx_T cmdidx, cctx_T *cctx) } break; case dest_local: + if (lvar != NULL) { isn_T *isn = ((isn_T *)instr->ga_data) + instr->ga_len - 1; @@ -4593,13 +4600,13 @@ compile_assignment(char_u *arg, exarg_T *eap, cmdidx_T cmdidx, cctx_T *cctx) garray_T *stack = &cctx->ctx_type_stack; isn->isn_type = ISN_STORENR; - isn->isn_arg.storenr.stnr_idx = idx; + isn->isn_arg.storenr.stnr_idx = lvar->lv_idx; isn->isn_arg.storenr.stnr_val = val; if (stack->ga_len > 0) --stack->ga_len; } else - generate_STORE(cctx, ISN_STORE, idx, NULL); + generate_STORE(cctx, ISN_STORE, lvar->lv_idx, NULL); } break; } @@ -5283,8 +5290,8 @@ compile_for(char_u *arg, cctx_T *cctx) garray_T *instr = &cctx->ctx_instr; garray_T *stack = &cctx->ctx_type_stack; scope_T *scope; - int loop_idx; // index of loop iteration variable - int var_idx; // index of "var" + lvar_T *loop_lvar; // loop iteration variable + lvar_T *var_lvar; // variable for "var" type_T *vartype; // TODO: list of variables: "for [key, value] in dict" @@ -5292,8 +5299,8 @@ compile_for(char_u *arg, cctx_T *cctx) for (p = arg; eval_isnamec1(*p); ++p) ; varlen = p - arg; - var_idx = lookup_local(arg, varlen, cctx); - if (var_idx >= 0) + var_lvar = lookup_local(arg, varlen, cctx); + if (var_lvar != NULL) { semsg(_("E1023: variable already defined: %s"), arg); return NULL; @@ -5314,23 +5321,24 @@ compile_for(char_u *arg, cctx_T *cctx) return NULL; // Reserve a variable to store the loop iteration counter. - loop_idx = reserve_local(cctx, (char_u *)"", 0, FALSE, &t_number); - if (loop_idx < 0) + loop_lvar = reserve_local(cctx, (char_u *)"", 0, FALSE, &t_number); + if (loop_lvar == NULL) { - // only happens when out of memory + // out of memory drop_scope(cctx); return NULL; } // Reserve a variable to store "var" - var_idx = reserve_local(cctx, arg, varlen, FALSE, &t_any); - if (var_idx < 0) + var_lvar = reserve_local(cctx, arg, varlen, FALSE, &t_any); + if (var_lvar == NULL) { + // out of memory or used as an argument drop_scope(cctx); return NULL; } - generate_STORENR(cctx, loop_idx, -1); + generate_STORENR(cctx, loop_lvar->lv_idx, -1); // compile "expr", it remains on the stack until "endfor" arg = p; @@ -5349,17 +5357,13 @@ compile_for(char_u *arg, cctx_T *cctx) return NULL; } if (vartype->tt_member->tt_type != VAR_ANY) - { - lvar_T *lvar = ((lvar_T *)cctx->ctx_locals.ga_data) + var_idx; - - lvar->lv_type = vartype->tt_member; - } + var_lvar->lv_type = vartype->tt_member; // "for_end" is set when ":endfor" is found scope->se_u.se_for.fs_top_label = instr->ga_len; - generate_FOR(cctx, loop_idx); - generate_STORE(cctx, ISN_STORE, var_idx, NULL); + generate_FOR(cctx, loop_lvar->lv_idx); + generate_STORE(cctx, ISN_STORE, var_lvar->lv_idx, NULL); return arg; } @@ -6158,7 +6162,7 @@ compile_def_function(ufunc_T *ufunc, int set_return_type) || *ea.cmd == '$' || *ea.cmd == '@' || ((p - ea.cmd) > 2 && ea.cmd[1] == ':') - || lookup_local(ea.cmd, p - ea.cmd, &cctx) >= 0 + || lookup_local(ea.cmd, p - ea.cmd, &cctx) != NULL || lookup_script(ea.cmd, p - ea.cmd) == OK || find_imported(ea.cmd, p - ea.cmd, &cctx) != NULL) { @@ -6175,7 +6179,8 @@ compile_def_function(ufunc_T *ufunc, int set_return_type) * COMMAND after range */ ea.cmd = skip_range(ea.cmd, NULL); - p = find_ex_command(&ea, NULL, is_ex_command ? NULL : lookup_local, + p = find_ex_command(&ea, NULL, is_ex_command ? NULL + : (void *(*)(char_u *, size_t, cctx_T *))lookup_local, &cctx); if (p == ea.cmd && ea.cmdidx != CMD_SIZE) @@ -6349,7 +6354,7 @@ compile_def_function(ufunc_T *ufunc, int set_return_type) dfunc->df_deleted = FALSE; dfunc->df_instr = instr->ga_data; dfunc->df_instr_count = instr->ga_len; - dfunc->df_varcount = cctx.ctx_max_local; + dfunc->df_varcount = cctx.ctx_locals_count; } { @@ -6431,7 +6436,7 @@ erret: current_sctx = save_current_sctx; free_imported(&cctx); - free_local(&cctx); + free_locals(&cctx); ga_clear(&cctx.ctx_type_stack); } From 7ceefb35c8110d87ced884275ddbe63d024a014f Mon Sep 17 00:00:00 2001 From: Bram Moolenaar <Bram@vim.org> Date: Fri, 1 May 2020 16:07:38 +0200 Subject: [PATCH 070/230] Update runtime files --- runtime/doc/change.txt | 8 +- runtime/doc/cmdline.txt | 3 +- runtime/doc/eval.txt | 8 +- runtime/doc/help.txt | 2 +- runtime/doc/index.txt | 7 +- runtime/doc/insert.txt | 4 +- runtime/doc/map.txt | 4 +- runtime/doc/os_haiku.txt | 7 +- runtime/doc/os_win32.txt | 2 +- runtime/doc/repeat.txt | 4 +- runtime/doc/tags | 4 + runtime/doc/terminal.txt | 8 +- runtime/doc/textprop.txt | 6 +- runtime/doc/todo.txt | 96 ++++++++++----- runtime/doc/usr_08.txt | 2 +- runtime/doc/usr_10.txt | 2 +- runtime/doc/vim9.txt | 84 ++++++++----- runtime/ftplugin/man.vim | 7 +- runtime/syntax/debchangelog.vim | 4 +- runtime/syntax/debsources.vim | 4 +- runtime/syntax/lex.vim | 201 +++++++++++++++++++------------- runtime/syntax/man.vim | 11 +- 22 files changed, 296 insertions(+), 182 deletions(-) diff --git a/runtime/doc/change.txt b/runtime/doc/change.txt index cf799a9dec..59004af14a 100644 --- a/runtime/doc/change.txt +++ b/runtime/doc/change.txt @@ -1,4 +1,4 @@ -*change.txt* For Vim version 8.2. Last change: 2020 Apr 11 +*change.txt* For Vim version 8.2. Last change: 2020 Apr 26 VIM REFERENCE MANUAL by Bram Moolenaar @@ -996,9 +996,9 @@ inside of strings can change! Also see 'softtabstop' option. > 5. Copying and moving text *copy-move* *quote* -"{a-zA-Z0-9.%#:-"} Use register {a-zA-Z0-9.%#:-"} for next delete, yank - or put (use uppercase character to append with - delete and yank) ({.%#:} only work with put). +"{register} Use {register} for next delete, yank or put. Use + an uppercase character to append with delete and yank. + Registers ".", "%", "#" and ":" only work with put. *:reg* *:registers* :reg[isters] Display the type and contents of all numbered and diff --git a/runtime/doc/cmdline.txt b/runtime/doc/cmdline.txt index a01d4b97f1..ecaa73e894 100644 --- a/runtime/doc/cmdline.txt +++ b/runtime/doc/cmdline.txt @@ -1,4 +1,4 @@ -*cmdline.txt* For Vim version 8.2. Last change: 2020 Feb 29 +*cmdline.txt* For Vim version 8.2. Last change: 2020 Apr 23 VIM REFERENCE MANUAL by Bram Moolenaar @@ -615,6 +615,7 @@ followed by another Vim command: :tcl :tcldo :tclfile + :terminal :vglobal :windo :write ! diff --git a/runtime/doc/eval.txt b/runtime/doc/eval.txt index 02ed78b2e1..8086bd5602 100644 --- a/runtime/doc/eval.txt +++ b/runtime/doc/eval.txt @@ -2646,7 +2646,7 @@ prop_clear({lnum} [, {lnum-end} [, {props}]]) none remove all text properties prop_find({props} [, {direction}]) Dict search for a text property -prop_list({lnum} [, {props}) List text properties in {lnum} +prop_list({lnum} [, {props}]) List text properties in {lnum} prop_remove({props} [, {lnum} [, {lnum-end}]]) Number remove a text property prop_type_add({name}, {props}) none define a new property type @@ -2654,7 +2654,7 @@ prop_type_change({name}, {props}) none change an existing property type prop_type_delete({name} [, {props}]) none delete a property type -prop_type_get([{name} [, {props}]) +prop_type_get([{name} [, {props}]]) Dict get property type values prop_type_list([{props}]) List get list of property types pum_getpos() Dict position and size of pum if visible @@ -3050,7 +3050,7 @@ arglistid([{winnr} [, {tabnr}]]) {winnr} can be the window number or the |window-ID|. *argv()* -argv([{nr} [, {winid}]) +argv([{nr} [, {winid}]]) The result is the {nr}th file in the argument list. See |arglist|. "argv(0)" is the first one. Example: > :let i = 0 @@ -5854,7 +5854,7 @@ has({feature} [, {check}]) Note that to skip code that has a syntax error when the feature is not available, Vim may skip the rest of the line - and miss a following `endif`. Therfore put the `endif` on a + and miss a following `endif`. Therefore put the `endif` on a separate line: > if has('feature') let x = this->breaks->without->the->feature diff --git a/runtime/doc/help.txt b/runtime/doc/help.txt index d858be1db0..7de6fb663d 100644 --- a/runtime/doc/help.txt +++ b/runtime/doc/help.txt @@ -198,13 +198,13 @@ Remarks about specific systems ~ |os_amiga.txt| Amiga |os_beos.txt| BeOS and BeBox |os_dos.txt| MS-DOS and MS-Windows common items +|os_haiku.txt| Haiku |os_mac.txt| Macintosh |os_mint.txt| Atari MiNT |os_msdos.txt| MS-DOS (plain DOS and DOS box under Windows) |os_os2.txt| OS/2 |os_qnx.txt| QNX |os_risc.txt| RISC-OS -|os_haiku.txt| Haiku |os_unix.txt| Unix |os_vms.txt| VMS |os_win32.txt| MS-Windows diff --git a/runtime/doc/index.txt b/runtime/doc/index.txt index e5a3bd6b55..315a5f3326 100644 --- a/runtime/doc/index.txt +++ b/runtime/doc/index.txt @@ -1,4 +1,4 @@ -*index.txt* For Vim version 8.2. Last change: 2020 Mar 27 +*index.txt* For Vim version 8.2. Last change: 2020 Apr 26 VIM REFERENCE MANUAL by Bram Moolenaar @@ -246,8 +246,7 @@ tag char note action in Normal mode ~ 2 filter Nmove text through the {filter} command |!!| !!{filter} 2 filter N lines through the {filter} command -|quote| "{a-zA-Z0-9.%#:-"} use register {a-zA-Z0-9.%#:-"} for next - delete, yank or put (uppercase to append) +|quote| "{register} use {register} for next delete, yank or put ({.%#:} only work with put) |#| # 1 search backward for the Nth occurrence of the ident under the cursor @@ -1115,7 +1114,7 @@ tag char action in Terminal-Job mode ~ |t_CTRL-W_:| CTRL-W : enter an Ex command |t_CTRL-W_.| CTRL-W . type CTRL-W in the terminal CTRL-W CTRL-\ send a CTRL-\ to the job in the terminal -|t_CTRL-W_quote| CTRL-W " {0-9a-z"%#*:=} +|t_CTRL-W_quote| CTRL-W " {register} paste register in the terminal |t_CTRL-W_CTRL-C| CTRL-W CTRL-C forcefully ends the job |t_CTRL-W_CTRL-W| CTRL-W CTRL-W move focus to the next window diff --git a/runtime/doc/insert.txt b/runtime/doc/insert.txt index ff74d625f4..fed81e5db4 100644 --- a/runtime/doc/insert.txt +++ b/runtime/doc/insert.txt @@ -1,4 +1,4 @@ -*insert.txt* For Vim version 8.2. Last change: 2020 Mar 25 +*insert.txt* For Vim version 8.2. Last change: 2020 Apr 30 VIM REFERENCE MANUAL by Bram Moolenaar @@ -666,7 +666,7 @@ Note: The keys that are valid in CTRL-X mode are not mapped. This allows for ends CTRL-X mode (any key that is not a valid CTRL-X mode command) is mapped. Also, when doing completion with 'complete' mappings apply as usual. - *E565* + *E578* *E565* Note: While completion is active Insert mode can't be used recursively and buffer text cannot be changed. Mappings that somehow invoke ":normal i.." will generate an E565 error. diff --git a/runtime/doc/map.txt b/runtime/doc/map.txt index bf643c0ffc..c142f231b5 100644 --- a/runtime/doc/map.txt +++ b/runtime/doc/map.txt @@ -1,4 +1,4 @@ -*map.txt* For Vim version 8.2. Last change: 2019 Dec 19 +*map.txt* For Vim version 8.2. Last change: 2020 Apr 23 VIM REFERENCE MANUAL by Bram Moolenaar @@ -1492,7 +1492,7 @@ The valid escape sequences are <bang> (See the '-bang' attribute) Expands to a ! if the command was executed with a ! modifier, otherwise expands to nothing. - *<mods>* + *<mods>* *:command-modifiers* <mods> The command modifiers, if specified. Otherwise, expands to nothing. Supported modifiers are |:aboveleft|, |:belowright|, |:botright|, |:browse|, |:confirm|, |:hide|, |:keepalt|, diff --git a/runtime/doc/os_haiku.txt b/runtime/doc/os_haiku.txt index 1ca338441d..6eff91c275 100644 --- a/runtime/doc/os_haiku.txt +++ b/runtime/doc/os_haiku.txt @@ -25,8 +25,9 @@ targets personal computing. 9. The meta key modifier |haiku-meta| 10. Mouse key mappings |haiku-mouse| 11. Color names |haiku-colors| -12. Credits |haiku-support-credits| -13. Bugs & to-do |haiku-bugs| +12. GUI Toolbar Images |haiku-toolbar-images| +13. Credits |haiku-support-credits| +14. Bugs & to-do |haiku-bugs| 1. General *haiku-general* @@ -223,7 +224,7 @@ All the changes and patches released under vim-license. Thank you, all! -13. Bugs & to-do *haiku-bugs* +14. Bugs & to-do *haiku-bugs* The port is under development now and far away from the perfect state. For bug reports, patches and wishes, please use the Vim mailing list or Vim Github diff --git a/runtime/doc/os_win32.txt b/runtime/doc/os_win32.txt index 7f378457d7..1017d4d261 100644 --- a/runtime/doc/os_win32.txt +++ b/runtime/doc/os_win32.txt @@ -230,7 +230,7 @@ A. VisionFS can't handle certain dot (.) three letter extension file names. SCO declares this behavior required for backwards compatibility with 16bit DOS/Windows environments. The two commands below demonstrate the behavior: > - echo Hello > file.bat~ + echo Hello > file.bat~ dir > file.bat < The result is that the "dir" command updates the "file.bat~" file, instead diff --git a/runtime/doc/repeat.txt b/runtime/doc/repeat.txt index 04e09d3f52..365f6da1e9 100644 --- a/runtime/doc/repeat.txt +++ b/runtime/doc/repeat.txt @@ -1,4 +1,4 @@ -*repeat.txt* For Vim version 8.2. Last change: 2019 Dec 07 +*repeat.txt* For Vim version 8.2. Last change: 2020 Apr 26 VIM REFERENCE MANUAL by Bram Moolenaar @@ -166,7 +166,7 @@ q Stops recording. (Implementation note: The 'q' that [addr] (default is current line). :[addr]@ *:@@* -:[addr]@@ Repeat the previous :@{0-9a-z"}. First set cursor at +:[addr]@@ Repeat the previous :@{register}. First set cursor at line [addr] (default is current line). ============================================================================== diff --git a/runtime/doc/tags b/runtime/doc/tags index 301336ca4b..e8d7d25a39 100644 --- a/runtime/doc/tags +++ b/runtime/doc/tags @@ -2272,6 +2272,7 @@ $VIM_POSIX vi_diff.txt /*$VIM_POSIX* :command-completion-custom map.txt /*:command-completion-custom* :command-completion-customlist map.txt /*:command-completion-customlist* :command-count map.txt /*:command-count* +:command-modifiers map.txt /*:command-modifiers* :command-nargs map.txt /*:command-nargs* :command-range map.txt /*:command-range* :command-register map.txt /*:command-register* @@ -4363,6 +4364,7 @@ E561 if_cscop.txt /*E561* E562 if_cscop.txt /*E562* E563 if_cscop.txt /*E563* E564 if_cscop.txt /*E564* +E565 insert.txt /*E565* E566 if_cscop.txt /*E566* E567 if_cscop.txt /*E567* E568 if_cscop.txt /*E568* @@ -4374,6 +4376,7 @@ E574 starting.txt /*E574* E575 starting.txt /*E575* E576 starting.txt /*E576* E577 starting.txt /*E577* +E578 insert.txt /*E578* E579 eval.txt /*E579* E580 eval.txt /*E580* E581 eval.txt /*E581* @@ -9959,6 +9962,7 @@ vim-variable eval.txt /*vim-variable* vim.vim syntax.txt /*vim.vim* vim7 version7.txt /*vim7* vim8 version8.txt /*vim8* +vim9 vim9.txt /*vim9* vim9-differences vim9.txt /*vim9-differences* vim9-export vim9.txt /*vim9-export* vim9-import vim9.txt /*vim9-import* diff --git a/runtime/doc/terminal.txt b/runtime/doc/terminal.txt index 8105b072f4..ddc0906a15 100644 --- a/runtime/doc/terminal.txt +++ b/runtime/doc/terminal.txt @@ -1,4 +1,4 @@ -*terminal.txt* For Vim version 8.2. Last change: 2020 Mar 26 +*terminal.txt* For Vim version 8.2. Last change: 2020 Apr 23 VIM REFERENCE MANUAL by Bram Moolenaar @@ -120,7 +120,7 @@ break (cursor keys start with an Esc, so they may break): > You can also create menus similar to terminal mode mappings, but you have to use |:tlmenu| instead of |:tmenu|. -< *options-in-terminal* + *options-in-terminal* After opening the terminal window and setting 'buftype' to "terminal" the TerminalOpen autocommand event is triggered. This makes it possible to set options specifically for the window and buffer. Example: > @@ -183,6 +183,10 @@ Command syntax ~ keep the terminal open in Terminal-Normal mode. This can be changed with the ++close argument. + No Vim command can follow, any | is included in + [command]. Use `:execute` if you must have a Vim + command following in the same line. + A new buffer will be created, using [command] or 'shell' as the name, prefixed with a "!". If a buffer by this name already exists a number is added in diff --git a/runtime/doc/textprop.txt b/runtime/doc/textprop.txt index 5d55952eb5..0793940b6d 100644 --- a/runtime/doc/textprop.txt +++ b/runtime/doc/textprop.txt @@ -101,7 +101,7 @@ Manipulating text property types: prop_type_add({name}, {props}) define a new property type prop_type_change({name}, {props}) change an existing property type prop_type_delete({name} [, {props}]) delete a property type -prop_type_get([{name} [, {props}]) get property type values +prop_type_get([{name} [, {props}]]) get property type values prop_type_list([{props}]) get list of property types @@ -111,7 +111,7 @@ prop_add({lnum}, {col}, {props}) add a text property prop_clear({lnum} [, {lnum-end} [, {bufnr}]]) remove all text properties prop_find({props} [, {direction}]) search for a text property -prop_list({lnum} [, {props}) text properties in {lnum} +prop_list({lnum} [, {props}]) text properties in {lnum} prop_remove({props} [, {lnum} [, {lnum-end}]]) remove a text property @@ -291,7 +291,7 @@ prop_type_delete({name} [, {props}]) *prop_type_delete()* Can also be used as a |method|: > GetPropName()->prop_type_delete() -prop_type_get([{name} [, {props}]) *prop_type_get()* +prop_type_get([{name} [, {props}]]) *prop_type_get()* Returns the properties of property type {name}. This is a dictionary with the same fields as was given to prop_type_add(). diff --git a/runtime/doc/todo.txt b/runtime/doc/todo.txt index 14756f093d..fe41907145 100644 --- a/runtime/doc/todo.txt +++ b/runtime/doc/todo.txt @@ -1,4 +1,4 @@ -*todo.txt* For Vim version 8.2. Last change: 2020 Apr 20 +*todo.txt* For Vim version 8.2. Last change: 2020 Apr 30 VIM REFERENCE MANUAL by Bram Moolenaar @@ -39,38 +39,59 @@ browser use: https://github.com/vim/vim/issues/1234 -------------------- Known bugs and current work ----------------------- Vim9 script: -more tests for # comments: - check all calls to ends_excmd() and test that space before # is needed. - next: ex_findpat() -func and partial types: -- Calling unknown user function does not give proper error message: - assert_equal('123text', RefDef2Arg()) typo for "RetDef2Arg" -- "func" inside "vim9script" doesn't work? (Ben Jackson, #5670) -- :func inside vim9script must still use a:arg -- define function and create funcref in one step: - let ref = def(arg: type): rettype - body - enddef +Big changes, need design: +- Make closures work: + Grab the part of the stack that has the arguments and local vars. + Pass a pointer and offset to the closure where this stack fragment is (frame + pointer). + When a closure disappears at end of the function - nothing to do. + When a closure remains at end of the function: copy frame, attach to closure. +- At the vim9 script level: Allow using a function that is defined later. + Requires compiling functions only when the whole script has been sourced. + Like Javascript "hoisting", but only at the script level: + 1. Discovery phase: Read the file to find all functions, variable + declarations and imports If a variable has a constant expression we get + the type, otherwise it will be "any". Follow imports recursively. + 2. Compilation phase: compile :def function bodies, using declared types + 3. Execution phase: Execute imports when encountered. (skip over functions) +- When sourcing a script again, also delete script-local variables. +Making everything work: - Test that a script-local function in Vim9 script cannot be deleted. - Test that a function defined inside a :def function is local to that function, g: functions can be defined and script-local functions cannot be defined. -Also: -- When wildcards are expanded, find `=expr` and evaluate it before invoking - the command. For example: :edit `=filename` +- Check that when using a user function name without prefix, it does not find + a global function. Prefixing g: is required. +- Compile let [var, var] = expr +- Compile replacement of :s command: s/pat/\=expr/ +- Compile redir to local variable: var_redir_start(). +- Compile builtin functions that access local variables: + islocked() +- Expand `=expr` in :next, :argedit, :argadd, :argdelete, :drop +- Expand `=expr` in :vimgrep, :vimgrepadd, :lvimgrep, :lvimgrepadd +- Expand `=expr` in :mkspell +- Support type for ":let"/":const" at script level for Vim9 script. + (Ben Jackson, #5671) + Can we share the code from ex_let_const() between direct execution and + compiling? +- Disallow unlet for local/script/imported vars +- Make "++nr" work. +- expandcmd() with `=expr` in filename uses legacy expression. +- eval_expr() in ex_cexpr() +- eval_expr() call in dbg_parsearg() and debuggy_find() +New syntax and functionality: +- define function and create funcref in one step: + let ref = def(arg: type): rettype + body + enddef +Improve error checking: - "echo Func()" is an error if Func() does not return anything. -- Check all Ex commands, give error if they use an expression and should be - compiled. +Also: - For range: make table of first ASCII character with flag to quickly check if it can be a Vim9 command. E.g. "+" can, but "." can't. - better implementation for partial and tests for that. - Make "g:imported = Export.exported" work in Vim9 script. - Make Foo.Bar() work to call the dict function. (#5676) -- Support type for ":let"/":const" at script level for Vim9 script. - (Ben Jackson, #5671) - Can we share the code for :let between direct execution and compiling? -- Disallow unlet for local/script/imported vars -- Make "++nr" work. - Check that import in legacy script works and puts item in s: - Error in any command in "vim9script" aborts sourcing. - Find a way to test expressions in legacy and Vim9 script without duplication @@ -93,6 +114,13 @@ Also: - Make accessing varargs faster: arg[expr] EVAL expr LOADVARARG (varags idx) +Further improvements: +- compile options that are an expression, e.g. "expr:" in 'spellsuggest', + 'foldexpr', 'foldtext', 'printexpr', 'diffexpr', 'patchexpr', 'charconvert', + 'balloonexpr', 'includeexpr', 'indentexpr', 'formatexpr'. +- compile get_lambda_tv() in popup_add_timeout() +- compile "skip" argument of searchpair() +- compile "expr" and "call" expression of a channel in channel_exe_cmd()? Popup windows: - With some sequence get get hidden finished terminal buffer. (#5768) @@ -198,7 +226,7 @@ Terminal emulator window: conversions. Error numbers available: -E453, E454, E460, E489, E491, E565, E578, E610, E611, E653, +E453, E454, E460, E489, E491, E610, E611, E653, E856, E857, E861, E900 Buffer autocommands are a bit inconsistent. Add a separate set of @@ -222,8 +250,13 @@ Ready to include. Patch to add "-d" to xxd. (#5616) +Patch for the Haiku port: #5961 + Patch to add Turkish manual. (Emir Sarı, #5641) +Patch to support different color for undercurl in cterm. +(Timur Celik, #6011) + Patch to support cindent option to handle pragmas differently. (Max Rumpf, #5468) @@ -234,6 +267,9 @@ manager. Problem with Motif? Now test_gui crashes in submenu_change(). Athena is OK. Motif: Build on Ubuntu can't enter any text in dialog text fields. +:map output does not clear the reset of the command line. +(#5623, also see #5962) + Patch to properly break CJK lines: Anton Kochkov, #3875 Flag in 'formatoptions' is not used in the tests. @@ -248,7 +284,10 @@ Ready to include? Review the code. When 'lazyredraw' is set sometimes the title is not updated. (Jason Franklin, 2020 Feb 3) Looks like a race condition. -Patch to delete BeOS code. (#5817) +Patch to delete BeOS code. (#5817) Anyone who wants to keep it? + +With bash ":make" does not set v:shell_error. Possible solution: set +'shellpipe' to "2>&1| tee %s; exit ${PIPESTATUS[0]}" #5994 Strange sequence of BufWipeout and BufNew events while doing omni-complete. (Paul Jolly, #5656) @@ -317,6 +356,8 @@ unlisted. (#4478) Patch to include reduce() function. (#5481) +When SIGTSTP is ignored, don't let CTRL-Z suspend Vim? (Kurtis Rader, #5990) + Statusline highlighting error, off by one. (#5599) Enable 'termbidi' if $VTE_VERSION >= 5703 ? @@ -331,11 +372,6 @@ Python 3.8 doesn't work. (Antonios Hadjigeorgalis, #5509) The :syntax cchar value can only be a single character. It would be useful to support combining characters. (Charles Campbell) Also #4687 -Include Haiku port. (Adrien Destugues, Siarzhuk Zharski, 2013 Oct 24) -It can replace the BeOS code, which is likely not used anymore. -Now on github: #1856. Updated Oct 2017 -Got permission to include this under the Vim license. - "--cleanFOO" does not result in an error. (#5537) Add "t" action to settagstack(): truncate and add new entries. (#5405) diff --git a/runtime/doc/usr_08.txt b/runtime/doc/usr_08.txt index a5e21f3919..57287d0f43 100644 --- a/runtime/doc/usr_08.txt +++ b/runtime/doc/usr_08.txt @@ -402,7 +402,7 @@ Another way to start in diff mode can be done from inside Vim. Edit the "main.c" file, then make a split and show the differences: > :edit main.c - :vertical diffsplit main.c~ + :vertical diffsplit main.c~ The ":vertical" command is used to make the window split vertically. If you omit this, you will get a horizontal split. diff --git a/runtime/doc/usr_10.txt b/runtime/doc/usr_10.txt index d5799193f8..7898618b4e 100644 --- a/runtime/doc/usr_10.txt +++ b/runtime/doc/usr_10.txt @@ -687,7 +687,7 @@ with any motion command, with text objects and in Visual mode. lowercase. This can be shortened to "guu". "gUgU" is shortened to "gUU" and "g~g~" to "g~~". Example: > - g~~ + g~~ < Some GIRLS have Fun ----> sOME girls HAVE fUN ~ ============================================================================== diff --git a/runtime/doc/vim9.txt b/runtime/doc/vim9.txt index 704e801c26..525393dacb 100644 --- a/runtime/doc/vim9.txt +++ b/runtime/doc/vim9.txt @@ -1,4 +1,4 @@ -*vim9.txt* For Vim version 8.2. Last change: 2020 Apr 19 +*vim9.txt* For Vim version 8.2. Last change: 2020 Apr 30 VIM REFERENCE MANUAL by Bram Moolenaar @@ -6,7 +6,7 @@ THIS IS STILL UNDER DEVELOPMENT - ANYTHING CAN BREAK - ANYTHING CAN CHANGE -Vim9 script commands and expressions. +Vim9 script commands and expressions. *vim9* Most expression help is in |eval.txt|. This file is about the new syntax and features in Vim9 script. @@ -28,29 +28,32 @@ THIS IS STILL UNDER DEVELOPMENT - ANYTHING CAN BREAK - ANYTHING CAN CHANGE THIS IS STILL UNDER DEVELOPMENT - ANYTHING CAN BREAK - ANYTHING CAN CHANGE -Vim script has been growing over time, while keeping backwards compatibility. -That means bad choices from the past often can't be changed. Execution is -quite slow, every line is parsed every time it is executed. +Vim script has been growing over time, while preserving backwards +compatibility. That means bad choices from the past often can't be changed +and compability with Vi restricts possible solutions. Execution is quite +slow, each line is parsed every time it is executed. -The main goal of Vim9 script is to drastically improve performance. An -increase in execution speed of 10 to 100 times can be expected. A secondary -goal is to avoid Vim-specific constructs and get closer to commonly used -programming languages, such as JavaScript, TypeScript and Java. +The main goal of Vim9 script is to drastically improve performance. This is +accomplished by compiling commands into instructions that can be efficiently +executed. An increase in execution speed of 10 to 100 times can be expected. + +A secondary goal is to avoid Vim-specific constructs and get closer to +commonly used programming languages, such as JavaScript, TypeScript and Java. The performance improvements can only be achieved by not being 100% backwards compatible. For example, in a function the arguments are not available in the -"a:" dictionary, as creating that dictionary adds quite a lot of overhead. -Other differences are more subtle, such as how errors are handled. +"a:" dictionary, because creating that dictionary adds quite a lot of +overhead. Other differences are more subtle, such as how errors are handled. The Vim9 script syntax and semantics are used in: - a function defined with the `:def` command - a script file where the first command is `vim9script` When using `:function` in a Vim9 script file the legacy syntax is used. -However, this is discouraged. +However, this can be confusing and is therefore discouraged. -Vim9 script and legacy Vim script can be mixed. There is no need to rewrite -old scripts, they keep working as before. +Vim9 script and legacy Vim script can be mixed. There is no requirement to +rewrite old scripts, they keep working as before. ============================================================================== @@ -62,9 +65,9 @@ Comments starting with # ~ In Vim script comments normally start with double quote. That can also be the start of a string, thus in many places it cannot be used. In Vim9 script a -comment can also start with #. Normally this is a command to list text with +comment can also start with #. In Vi this is a command to list text with numbers, but you can also use `:number` for that. > - let count = 0 # number of occurences of Ni! + let count = 0 # number of occurences To improve readability there must be a space between the command and the # that starts a comment. Note that #{ is the start of a dictionary, therefore @@ -73,40 +76,59 @@ it cannot start a comment. Vim9 functions ~ +A function defined with `:def` is compiled. Execution is many times faster, +often 10x to 100x times. + +Many errors are already found when compiling, before the function is called. +The syntax is strict, to enforce code that is easy to read and understand. + `:def` has no extra arguments like `:function` does: "range", "abort", "dict" or "closure". A `:def` function always aborts on an error, does not get a range passed and cannot be a "dict" function. -In the function body: -- Arguments are accessed by name, without "a:". -- There is no "a:" dictionary or "a:000" list. Variable arguments are defined - with a name and have a list type: > - def MyFunc(...itemlist: list<type>) +The argument types and return type need to be specified. The "any" type can +be used, type checking will then be done at runtime, like with legacy +functions. + +Arguments are accessed by name, without "a:". There is no "a:" dictionary or +"a:000" list. + +Variable arguments are defined as the last argument, with a name and have a +list type, similar to Typescript. For example, a list of numbers: > + def MyFunc(...itemlist: list<number>) for item in itemlist ... -Functions are script-local by default ~ +Functions and variables are script-local by default ~ When using `:function` or `:def` to specify a new function at the script level in a Vim9 script, the function is local to the script, as if "s:" was -prefixed. To define a global function the "g:" prefix must be used. +prefixed. Using the "s:" prefix is optional. + +To define or use a global function or variable the "g:" prefix must be used. When using `:function` or `:def` to specify a new function inside a function, the function is local to the function. It is not possible to define a -script-local function inside a function. To define a global function the "g:" -prefix must be used. +script-local function inside a function. It is possible to define a global +function, using the "g:" prefix. When referring to a function and no "s:" or "g:" prefix is used, Vim will search for the function in this order: -- Local to the current function scope. +- Local to the current scope and outer scopes up to the function scope. - Local to the current script file. - Imported functions, see `:import`. -- Global. +In all cases the function must be defined before used. To make a call cycle a +global function needs to be used. (TODO: can we fix this?) + +The result is that functions and variables without a namespace can always be +found in the script, either defined there or imported. Global functions and +variables could be defined anywhere (good luck finding where!). Global functions can be defined and deleted at nearly any time. In Vim9 script script-local functions are defined once when the script is sourced and -cannot be deleted. +cannot be deleted. Except that when the same script is sourced again all +existing script-local functions and variables are deleted. Variable declarations with :let and :const ~ @@ -156,12 +178,12 @@ and without `:let`, because there is no rule about where they are declared. Variables cannot shadow previously defined variables. Variables may shadow Ex commands, rename the variable if needed. -Global variables must be prefixed with "g:", also at the script level. -However, global user defined functions are used without "g:". > +Global variables and user defined functions must be prefixed with "g:", also +at the script level. > vim9script let script_local = 'text' let g:global = 'value' - let Funcref = ThatFunction + let Funcref = g:ThatFunction Since "&opt = value" is now assigning a value to option "opt", ":&" cannot be used to repeat a `:substitute` command. diff --git a/runtime/ftplugin/man.vim b/runtime/ftplugin/man.vim index f627035eb2..ec290ab1ee 100644 --- a/runtime/ftplugin/man.vim +++ b/runtime/ftplugin/man.vim @@ -1,7 +1,8 @@ " Vim filetype plugin file " Language: man -" Maintainer: SungHyun Nam <goweol@gmail.com> -" Last Change: 2020 Apr 13 +" Maintainer: Jason Franklin <vim@justemail.net> +" Previous Maintainer: SungHyun Nam <goweol@gmail.com> +" Last Change: 2020 Apr 30 " To make the ":Man" command available before editing a manual page, source " this script from your startup vimrc file. @@ -205,7 +206,7 @@ func <SID>GetPage(cmdmods, ...) endif let env_cmd = s:env_has_u ? 'env -u MANPAGER' : 'env MANPAGER=cat' let env_cmd .= ' GROFF_NO_SGR=1' - let man_cmd = env_cmd . ' man ' . s:GetCmdArg(sect, page) . ' | col -b' + let man_cmd = env_cmd . ' man ' . s:GetCmdArg(sect, page) . ' 2>/dev/null | col -b' silent exec "r !" . man_cmd if unsetwidth diff --git a/runtime/syntax/debchangelog.vim b/runtime/syntax/debchangelog.vim index 8d282da445..7321e90b30 100644 --- a/runtime/syntax/debchangelog.vim +++ b/runtime/syntax/debchangelog.vim @@ -3,7 +3,7 @@ " Maintainer: Debian Vim Maintainers " Former Maintainers: Gerfried Fuchs <alfie@ist.org> " Wichert Akkerman <wakkerma@debian.org> -" Last Change: 2020 Feb 02 +" Last Change: 2020 Apr 27 " URL: https://salsa.debian.org/vim-team/vim-debian/blob/master/syntax/debchangelog.vim " Standard syntax initialization @@ -24,7 +24,7 @@ let s:supported = [ \ 'wheezy', 'jessie', 'stretch', 'buster', 'bullseye', 'bookworm', \ 'sid', 'rc-buggy', \ - \ 'trusty', 'xenial', 'bionic', 'eoan', 'focal', 'devel' + \ 'trusty', 'xenial', 'bionic', 'eoan', 'focal', 'groovy', 'devel' \ ] let s:unsupported = [ \ 'frozen', 'buzz', 'rex', 'bo', 'hamm', 'slink', 'potato', diff --git a/runtime/syntax/debsources.vim b/runtime/syntax/debsources.vim index e97d3274ba..b594443119 100644 --- a/runtime/syntax/debsources.vim +++ b/runtime/syntax/debsources.vim @@ -2,7 +2,7 @@ " Language: Debian sources.list " Maintainer: Debian Vim Maintainers " Former Maintainer: Matthijs Mohlmann <matthijs@cacholong.nl> -" Last Change: 2020 Feb 02 +" Last Change: 2020 Apr 27 " URL: https://salsa.debian.org/vim-team/vim-debian/blob/master/syntax/debsources.vim " Standard syntax initialization @@ -26,7 +26,7 @@ let s:supported = [ \ 'wheezy', 'jessie', 'stretch', 'buster', 'bullseye', 'bookworm', \ 'sid', 'rc-buggy', \ - \ 'trusty', 'xenial', 'bionic', 'eoan', 'focal', 'devel' + \ 'trusty', 'xenial', 'bionic', 'eoan', 'focal', 'groovy', 'devel' \ ] let s:unsupported = [ \ 'buzz', 'rex', 'bo', 'hamm', 'slink', 'potato', diff --git a/runtime/syntax/lex.vim b/runtime/syntax/lex.vim index 9e0b307d68..dff70eb3b7 100644 --- a/runtime/syntax/lex.vim +++ b/runtime/syntax/lex.vim @@ -1,22 +1,19 @@ " Vim syntax file -" Language: Lex +" Language: Lex and Flex " Maintainer: Charles E. Campbell <NcampObell@SdrPchip.AorgM-NOSPAM> -" Last Change: Aug 31, 2016 -" Version: 17 -" URL: http://mysite.verizon.net/astronaut/vim/index.html#SYNTAX_LEX -" -" Option: -" lex_uses_cpp : if this variable exists, then C++ is loaded rather than C +" Contributor: Robert A. van Engelen <engelen@acm.org> +" Last Change: Apr 24, 2020 +" Version: 18 " quit when a syntax file was already loaded if exists("b:current_syntax") finish endif -" Read the C/C++ syntax to start with -let s:Cpath= fnameescape(expand("<sfile>:p:h").(exists("g:lex_uses_cpp")? "/cpp.vim" : "/c.vim")) +" Read the C++ syntax to start with +let s:Cpath= fnameescape(expand("<sfile>:p:h")."/cpp.vim") if !filereadable(s:Cpath) - for s:Cpath in split(globpath(&rtp,(exists("g:lex_uses_cpp")? "syntax/cpp.vim" : "syntax/c.vim")),"\n") + for s:Cpath in split(globpath(&rtp,"syntax/cpp.vim"),"\n") if filereadable(fnameescape(s:Cpath)) let s:Cpath= fnameescape(s:Cpath) break @@ -29,115 +26,163 @@ exe "syn include @lexCcode ".s:Cpath " --- Lex stuff --- " --- ========= --- -" Options Section -syn match lexOptions '^%\s*option\>.*$' contains=lexPatString +" Definitions +" %% +" Rules +" %% +" User Code +" +" --- ======= --- +" --- Example --- +" --- ======= --- +" +" // this is a valid lex file +" // indented initial code block +" #include <stdlib.h> +" %{ +" // initial code block +" #include <stdio.h> +" const char *sep = ""; +" %} +" %option outfile="scanner.c" noyywrap nodefault +" %x COMMENT +" id [A-Za-z_][A-Za-z0-9_]* +" %% +" // indented initial action code block +" printf("BEGIN"); +" {id} printf("%s%s", sep, yytext); sep = ""; +" . | +" \n { sep = "\n"; } +" "/*" { BEGIN COMMENT; } +" "//".* { } +" <COMMENT>{ +" "*/" { BEGIN INITIAL; } +" .|\n +" } +" <*><<EOF>> { // end of file +" printf("\nEND\n"); +" yyterminate(); +" } +" %% +" void scan() +" { +" while (yylex()) +" continue; +" } +" /* main program */ +" int main() +" { +" scan(); +" } -" Abbreviations Section +" Definitions Section with initial code blocks, abbreviations, options, states if has("folding") - syn region lexAbbrvBlock fold start="^\(\h\+\s\|%{\)" end="^\ze%%$" skipnl nextgroup=lexPatBlock contains=lexAbbrv,lexInclude,lexAbbrvComment,lexStartState + syn region lexAbbrvBlock fold start="^\S" end="^\ze%%" skipnl nextgroup=lexPatBlock contains=lexOptions,lexAbbrv,lexInitialCodeBlock,lexInclude,lexAbbrvComment,lexStartState else - syn region lexAbbrvBlock start="^\(\h\+\s\|%{\)" end="^\ze%%$" skipnl nextgroup=lexPatBlock contains=lexAbbrv,lexInclude,lexAbbrvComment,lexStartState + syn region lexAbbrvBlock start="^\S" end="^\ze%%" skipnl nextgroup=lexPatBlock contains=lexOptions,lexAbbrv,lexInitialCodeBlock,lexInclude,lexAbbrvComment,lexStartState endif -syn match lexAbbrv "^\I\i*\s"me=e-1 skipwhite contained nextgroup=lexAbbrvRegExp -syn match lexAbbrv "^%[sx]" contained -syn match lexAbbrvRegExp "\s\S.*$"lc=1 contained nextgroup=lexAbbrv,lexInclude +syn match lexOptions "^%\a\+\(\s.*\|[^{]*\)$" contains=lexOptionsEq,lexPatString,lexSlashQuote,lexBrace,lexSlashBrace +syn match lexOptionsEq "=" skipwhite contained +syn match lexAbbrv "^\I\i*\s"me=e-1 skipwhite contained nextgroup=lexAbbrvPat +syn match lexAbbrvPat "\s\S.*$"lc=1 contained contains=lexPatAbbrv,lexPatString,lexSlashQuote,lexBrace,lexSlashBrace nextgroup=lexAbbrv,lexInclude +syn match lexStartState "^%\(xs\?\|s\)\(t\(a\(t\(e\?\)\?\)\?\)\?\)\?\(\s\+\I\i*\)\+\s*$" contained contains=lexStartStateCmd +syn match lexStartStateCmd '^%\(xs\?\|s\)\(t\(a\(t\(e\?\)\?\)\?\)\?\)\?' contained if has("folding") - syn region lexInclude fold matchgroup=lexSep start="^%{" end="%}" contained contains=@lexCcode - syn region lexAbbrvComment fold start="^\s\+/\*" end="\*/" contains=@Spell - syn region lexAbbrvComment fold start="\%^/\*" end="\*/" contains=@Spell - syn region lexStartState fold matchgroup=lexAbbrv start="^%\a\+" end="$" contained + syn region lexInitialCodeBlock fold start="^\s\+" end="^\S"me=e-1 contains=@lexCcode + syn region lexInclude fold matchgroup=lexSep start="^%\a*{" end="^%\?}" contained contains=@lexCcode,lexCFunctions + syn region lexAbbrvComment fold start="^\s*//" end="$" contains=@Spell + syn region lexAbbrvComment fold start="^\s*/\*" end="\*/" contains=@Spell else - syn region lexInclude matchgroup=lexSep start="^%{" end="%}" contained contains=@lexCcode - syn region lexAbbrvComment start="^\s\+/\*" end="\*/" contains=@Spell - syn region lexAbbrvComment start="\%^/\*" end="\*/" contains=@Spell - syn region lexStartState matchgroup=lexAbbrv start="^%\a\+" end="$" contained + syn region lexInitialCodeBlock start="^\s\+" end="^\S"me=e-1 contains=@lexCcode + syn region lexInclude matchgroup=lexSep start="^%\a*{" end="^%\?}" contained contains=@lexCcode,lexCFunctions + syn region lexAbbrvComment start="^\s*//" end="$" contains=@Spell + syn region lexAbbrvComment start="^\s*/\*" end="\*/" contains=@Spell endif -"%% : Patterns {Actions} +" Rules Section with patterns and actions if has("folding") - syn region lexPatBlock fold matchgroup=Todo start="^%%$" matchgroup=Todo end="^%\ze%$" skipnl skipwhite nextgroup=lexFinalCodeBlock contains=lexPatTag,lexPatTagZone,lexPatComment,lexPat,lexPatInclude - syn region lexPat fold start=+\S+ skip="\\\\\|\\." end="\s"me=e-1 skipwhite contained nextgroup=lexMorePat,lexPatSep,lexPattern contains=lexPatTag,lexPatString,lexSlashQuote,lexBrace - syn region lexPatInclude fold matchgroup=lexSep start="^%{" end="%}" contained contains=lexPatCode - syn region lexBrace fold start="\[" skip=+\\\\\|\\+ end="]" contained - syn region lexPatString fold matchgroup=String start=+"+ skip=+\\\\\|\\"+ matchgroup=String end=+"+ contained + syn region lexPatBlock fold matchgroup=Todo start="^%%" matchgroup=Todo end="^\ze%%" skipnl skipwhite nextgroup=lexFinalCodeBlock contains=lexPatTag,lexPatTagZone,lexPatComment,lexPat,lexPatSep,lexPatInclude + syn region lexPat fold start="\S" skip="\\\\\|\\\s" end="\ze\(\s*$\|\s\+\(\h\|{\W\|{$\|[-+*]\|//\|/\*\)\)" skipwhite contained nextgroup=lexMorePat,lexPatSep,lexPatEnd contains=lexPatTag,lexPatString,lexSlashQuote,lexPatAbbrv,lexBrace,lexSlashBrace + syn region lexPatInclude fold matchgroup=lexSep start="^%{" end="^%}" contained contains=@lexCcode + syn region lexBrace fold matchgroup=Character start="\[" skip="\\.\|\[:\a\+:\]\|\[\.\a\+\.\]\|\[=.=\]" end="\]" contained + syn region lexPatString fold matchgroup=String start=+"+ skip=+\\\\\|\\"+ matchgroup=String end=+"+ contained else - syn region lexPatBlock matchgroup=Todo start="^%%$" matchgroup=Todo end="^%%$" skipnl skipwhite nextgroup=lexFinalCodeBlock contains=lexPatTag,lexPatTagZone,lexPatComment,lexPat,lexPatInclude - syn region lexPat start=+\S+ skip="\\\\\|\\." end="\s"me=e-1 skipwhite contained nextgroup=lexMorePat,lexPatSep,lexPattern contains=lexPatTag,lexPatString,lexSlashQuote,lexBrace - syn region lexPatInclude matchgroup=lexSep start="^%{" end="%}" contained contains=lexPatCode - syn region lexBrace start="\[" skip=+\\\\\|\\+ end="]" contained - syn region lexPatString matchgroup=String start=+"+ skip=+\\\\\|\\"+ matchgroup=String end=+"+ contained + syn region lexPatBlock matchgroup=Todo start="^%%" matchgroup=Todo end="^\ze%%" skipnl skipwhite nextgroup=lexFinalCodeBlock contains=lexPatTag,lexPatTagZone,lexPatComment,lexPat,lexPatSep,lexPatInclude + syn region lexPat start="\S" skip="\\\\\|\\\s" end="\ze\(\s*$\|\s\+\(\h\|{\W\|{$\|[-+*]\|//\|/\*\)\)" skipwhite contained nextgroup=lexMorePat,lexPatSep,lexPatEnd contains=lexPatTag,lexPatString,lexSlashQuote,lexPatAbbrv,lexBrace,lexSlashBrace + syn region lexPatInclude matchgroup=lexSep start="^%{" end="^%}" contained contains=@lexCcode + syn region lexBrace matchgroup=Character start="\[" skip="\\.\|\[:\a\+:\]\|\[\.\a\+\.\]\|\[=.=\]" end="\]" contained + syn region lexPatString matchgroup=String start=+"+ skip=+\\\\\|\\"+ matchgroup=String end=+"+ contained endif -syn match lexPatTag "^<\I\i*\(,\I\i*\)*>" contained nextgroup=lexPat,lexPatTag,lexMorePat,lexPatSep -syn match lexPatTagZone "^<\I\i*\(,\I\i*\)*>\s\+\ze{" contained nextgroup=lexPatTagZoneStart -syn match lexPatTag +^<\I\i*\(,\I\i*\)*>*\(\\\\\)*\\"+ contained nextgroup=lexPat,lexPatTag,lexMorePat,lexPatSep - -" Lex Patterns -syn region lexPattern start='[^ \t{}]' end="$" contained contains=lexPatRange -syn region lexPatRange matchgroup=Delimiter start='\[' skip='\\\\\|\\.' end='\]' contains=lexEscape -syn match lexEscape '\%(\\\\\)*\\.' contained +syn match lexPatAbbrv "{\I\i*}"hs=s+1,he=e-1 contained +syn match lexPatTag "^<\^\?\(\I\i*\|\*\)\(,\^\?\(\I\i*\|\*\)\)*>" contained nextgroup=lexPat,lexMorePat,lexPatSep,lexPatEnd +syn match lexPatTagZone "^<\^\?\(\I\i*\|\*\)\(,\^\?\(\I\i*\|\*\)\)*>\s*{$"me=e-1 contained nextgroup=lexPatTagZoneStart if has("folding") - syn region lexPatTagZoneStart matchgroup=lexPatTag fold start='{' end='}' contained contains=lexPat,lexPatComment - syn region lexPatComment start="\s\+/\*" end="\*/" fold skipnl contained contains=cTodo skipwhite nextgroup=lexPatComment,lexPat,@Spell + syn region lexPatTagZoneStart fold matchgroup=lexPatTag start='{$' end='^}' skipnl skipwhite contained contains=lexPatTag,lexPatTagZone,lexPatComment,lexPat,lexPatSep,lexPatInclude + syn region lexPatComment fold start="//" end="$" skipnl contained contains=cTodo skipwhite nextgroup=lexPatComment,lexPat,@Spell + syn region lexPatComment fold start="/\*" end="\*/" skipnl contained contains=cTodo skipwhite nextgroup=lexPatComment,lexPat,@Spell else - syn region lexPatTagZoneStart matchgroup=lexPatTag start='{' end='}' contained contains=lexPat,lexPatComment - syn region lexPatComment start="\s\+/\*" end="\*/" skipnl contained contains=cTodo skipwhite nextgroup=lexPatComment,lexPat,@Spell + syn region lexPatTagZoneStart matchgroup=lexPatTag start='{' end='^}' skipnl skipwhitecontained contains=lexPatTag,lexPatTagZone,lexPatComment,lexPat,lexPatSep,lexPatInclude + syn region lexPatComment start="//" end="$" skipnl contained contains=cTodo skipwhite nextgroup=lexPatComment,lexPat,@Spell + syn region lexPatComment start="/\*" end="\*/" skipnl contained contains=cTodo skipwhite nextgroup=lexPatComment,lexPat,@Spell endif -syn match lexPatCodeLine "[^{\[].*" contained contains=@lexCcode -syn match lexMorePat "\s*|\s*$" skipnl contained nextgroup=lexPat,lexPatTag,lexPatComment -syn match lexPatSep "\s\+" contained nextgroup=lexMorePat,lexPatCode,lexPatCodeLine +syn match lexPatEnd "\s*$" skipnl contained +syn match lexPatCodeLine "[^{\[].*" contained contains=@lexCcode,lexCFunctions +syn match lexMorePat "\s*|\s*$" skipnl contained nextgroup=lexPat,lexPatTag,lexPatComment +syn match lexPatSep "\s\+" contained nextgroup=lexMorePat,lexPatCode,lexPatCodeLine syn match lexSlashQuote +\(\\\\\)*\\"+ contained +syn match lexSlashBrace +\(\\\\\)*\\\[+ contained if has("folding") - syn region lexPatCode matchgroup=Delimiter start="{" end="}" fold skipnl contained contains=@lexCcode,lexCFunctions + syn region lexPatCode fold matchgroup=Delimiter start="{" end="}" skipnl contained contains=@lexCcode,lexCFunctions else - syn region lexPatCode matchgroup=Delimiter start="{" end="}" skipnl contained contains=@lexCcode,lexCFunctions + syn region lexPatCode matchgroup=Delimiter start="{" end="}" skipnl contained contains=@lexCcode,lexCFunctions endif -" Lex "functions" which may appear in C/C++ code blocks -syn keyword lexCFunctions BEGIN input unput woutput yyleng yylook yytext -syn keyword lexCFunctions ECHO output winput wunput yyless yymore yywrap +" User Code Section with final code block +syn region lexFinalCodeBlock matchgroup=Todo start="^%%" end="\%$" contained contains=@lexCcode -" %% -" lexAbbrevBlock -" %% -" lexPatBlock -" %% -" lexFinalCodeBlock -syn region lexFinalCodeBlock matchgroup=Todo start="%$"me=e-1 end="\%$" contained contains=@lexCcode +" Lex macros which may appear in C/C++ code blocks +syn keyword lexCFunctions BEGIN ECHO REJECT yytext YYText yyleng YYLeng yymore yyless yywrap yylook +syn keyword lexCFunctions yyrestart yyterminate yylineno yycolumno yyin yyout +syn keyword lexCFunctions input unput output winput wunput woutput +syn keyword lexCFunctions yyinput yyunput yyoutput yywinput yywunput yywoutput " <c.vim> includes several ALLBUTs; these have to be treated so as to exclude lex* groups -syn cluster cParenGroup add=lex.* +syn cluster cParenGroup add=lex.* syn cluster cDefineGroup add=lex.* syn cluster cPreProcGroup add=lex.* -syn cluster cMultiGroup add=lex.* +syn cluster cMultiGroup add=lex.* " Synchronization syn sync clear syn sync minlines=500 syn sync match lexSyncPat grouphere lexPatBlock "^%[a-zA-Z]" syn sync match lexSyncPat groupthere lexPatBlock "^<$" -syn sync match lexSyncPat groupthere lexPatBlock "^%%$" +syn sync match lexSyncPat groupthere lexPatBlock "^%%" " The default highlighting. if !exists("skip_lex_syntax_inits") hi def link lexAbbrvComment lexPatComment - hi def link lexAbbrvRegExp Macro - hi def link lexAbbrv SpecialChar - hi def link lexBrace lexPat - hi def link lexCFunctions Function - hi def link lexCstruct cStructure - hi def link lexMorePat SpecialChar - hi def link lexOptions PreProc + hi def link lexAbbrvPat lexPat + hi def link lexAbbrv Special + hi def link lexBrace lexPat + hi def link lexCFunctions PreProc + hi def link lexMorePat Special + hi def link lexOptions PreProc + hi def link lexOptionsEq Operator hi def link lexPatComment Comment hi def link lexPat Function - hi def link lexPatString Function - hi def link lexPatTag Special + hi def link lexPatString lexPat + hi def link lexPatAbbrv Special + hi def link lexPatTag Statement hi def link lexPatTagZone lexPatTag hi def link lexSep Delimiter hi def link lexSlashQuote lexPat - hi def link lexStartState Statement + hi def link lexSlashBrace lexPat + hi def link lexStartState lexPatTag + hi def link lexStartStateCmd Special endif let b:current_syntax = "lex" -" vim:ts=10 +" vim:ts=8 diff --git a/runtime/syntax/man.vim b/runtime/syntax/man.vim index 5bdba86212..56f6d10de2 100644 --- a/runtime/syntax/man.vim +++ b/runtime/syntax/man.vim @@ -1,9 +1,10 @@ " Vim syntax file " Language: Man page -" Maintainer: SungHyun Nam <goweol@gmail.com> +" Maintainer: Jason Franklin <vim@justemail.net> +" Previous Maintainer: SungHyun Nam <goweol@gmail.com> " Previous Maintainer: Gautam H. Mudunuri <gmudunur@informatica.com> " Version Info: -" Last Change: 2020 Apr 15 +" Last Change: 2020 Apr 30 " Additional highlighting by Johannes Tanzler <johannes.tanzler@aon.at>: " * manSubHeading @@ -19,9 +20,6 @@ runtime! syntax/ctrlh.vim syn case ignore -syn match manHeader '\%1l.*' -exe 'syn match manFooter ''\%' . line('$') . 'l.*''' - syn match manReference "\f\+([1-9][a-z]\=)" syn match manSectionHeading "^[a-z][a-z -]*[a-z]$" syn match manSubHeading "^\s\{3\}[a-z][a-z -]*[a-z]$" @@ -29,6 +27,9 @@ syn match manOptionDesc "^\s*[+-][a-z0-9]\S*" syn match manLongOptionDesc "^\s*--[a-z0-9-]\S*" " syn match manHistory "^[a-z].*last change.*$" +syn match manHeader '\%1l.*' +exe 'syn match manFooter ''\%' . line('$') . 'l.*''' + if getline(1) =~ '^[a-zA-Z_]\+([23])' syntax include @cCode <sfile>:p:h/c.vim syn match manCFuncDefinition display "\<\h\w*\>\s*("me=e-1 contained From 37addecc422c3b62a622b371246dc4ef0a2fa157 Mon Sep 17 00:00:00 2001 From: Bram Moolenaar <Bram@vim.org> Date: Fri, 1 May 2020 16:08:11 +0200 Subject: [PATCH 071/230] patch 8.2.0676: pattern in list of distributed files does not match Problem: Pattern in list of distributed files does not match. Solution: Drop "testdir/test_[a-z]*.ok". Add CI sed files. --- Filelist | 2 +- src/version.c | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/Filelist b/Filelist index 8c0b260a00..7564879e9f 100644 --- a/Filelist +++ b/Filelist @@ -13,6 +13,7 @@ SRC_ALL = \ ci/appveyor.bat \ ci/if_ver*.vim \ ci/load-snd-dummy.sh \ + ci/config.mk*.sed \ src/Make_all.mak \ src/README.md \ src/alloc.h \ @@ -170,7 +171,6 @@ SRC_ALL = \ src/testdir/view_util.vim \ src/testdir/test[0-9]*.ok \ src/testdir/test[0-9]*a.ok \ - src/testdir/test_[a-z]*.ok \ src/testdir/test49.vim \ src/testdir/test83-tags? \ src/testdir/test77a.com \ diff --git a/src/version.c b/src/version.c index 9657185516..e23e503c63 100644 --- a/src/version.c +++ b/src/version.c @@ -746,6 +746,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 676, /**/ 675, /**/ From c8cd2b34d1027c93fbca90f3cdc8123fe22dfa25 Mon Sep 17 00:00:00 2001 From: Bram Moolenaar <Bram@vim.org> Date: Fri, 1 May 2020 19:29:08 +0200 Subject: [PATCH 072/230] patch 8.2.0677: Vim9: no support for closures Problem: Vim9: no support for closures. Solution: Find variables in the outer function scope, so long as the scope exists. --- src/proto/vim9compile.pro | 2 +- src/structs.h | 17 +++ src/testdir/test_vim9_func.vim | 9 ++ src/userfunc.c | 15 +- src/version.c | 2 + src/vim9.h | 1 + src/vim9compile.c | 253 +++++++++++++++++++-------------- src/vim9execute.c | 50 ++++++- 8 files changed, 223 insertions(+), 126 deletions(-) diff --git a/src/proto/vim9compile.pro b/src/proto/vim9compile.pro index 76a9c99922..76fca4f95f 100644 --- a/src/proto/vim9compile.pro +++ b/src/proto/vim9compile.pro @@ -9,7 +9,7 @@ imported_T *find_imported(char_u *name, size_t len, cctx_T *cctx); char_u *to_name_const_end(char_u *arg); int assignment_len(char_u *p, int *heredoc); int check_vim9_unlet(char_u *name); -void compile_def_function(ufunc_T *ufunc, int set_return_type); +void compile_def_function(ufunc_T *ufunc, int set_return_type, cctx_T *outer_cctx); void delete_instr(isn_T *isn); void delete_def_function(ufunc_T *ufunc); void free_def_functions(void); diff --git a/src/structs.h b/src/structs.h index 1d3d411172..70b6e3f72a 100644 --- a/src/structs.h +++ b/src/structs.h @@ -1561,7 +1561,11 @@ typedef struct sctx_T uf_script_ctx; // SCTX where function was defined, // used for s: variables int uf_refcount; // reference count, see func_name_refcount() + funccall_T *uf_scoped; // l: local variables for closure + garray_T *uf_ectx_stack; // where compiled closure finds local vars + int uf_ectx_frame; // index of function frame in uf_ectx_stack + char_u *uf_name_exp; // if "uf_name[]" starts with SNR the name with // "<SNR>" as a string, otherwise NULL char_u uf_name[1]; // name of function (actually longer); can @@ -1569,6 +1573,19 @@ typedef struct // KS_EXTRA KE_SNR) } ufunc_T; +// flags used in uf_flags +#define FC_ABORT 0x01 // abort function on error +#define FC_RANGE 0x02 // function accepts range +#define FC_DICT 0x04 // Dict function, uses "self" +#define FC_CLOSURE 0x08 // closure, uses outer scope variables +#define FC_DELETED 0x10 // :delfunction used while uf_refcount > 0 +#define FC_REMOVED 0x20 // function redefined while uf_refcount > 0 +#define FC_SANDBOX 0x40 // function defined in the sandbox +#define FC_DEAD 0x80 // function kept only for reference to dfunc +#define FC_EXPORT 0x100 // "export def Func()" +#define FC_NOARGS 0x200 // no a: variables in lambda +#define FC_VIM9 0x400 // defined in vim9 script file + #define MAX_FUNC_ARGS 20 // maximum number of function arguments #define VAR_SHORT_LEN 20 // short variable name length #define FIXVAR_CNT 12 // number of fixed variables diff --git a/src/testdir/test_vim9_func.vim b/src/testdir/test_vim9_func.vim index 2ee91f1abd..a317d8f58d 100644 --- a/src/testdir/test_vim9_func.vim +++ b/src/testdir/test_vim9_func.vim @@ -641,4 +641,13 @@ func Test_E1056_1059() call assert_equal(1, caught_1059) endfunc +def RefFunc(Ref: func(string): string): string + return Ref('more') +enddef + +def Test_closure_simple() + let local = 'some ' + assert_equal('some more', RefFunc({s -> local .. s})) +enddef + " vim: ts=8 sw=2 sts=2 expandtab tw=80 fdm=marker diff --git a/src/userfunc.c b/src/userfunc.c index 708b4523b3..2493dfea0c 100644 --- a/src/userfunc.c +++ b/src/userfunc.c @@ -14,19 +14,6 @@ #include "vim.h" #if defined(FEAT_EVAL) || defined(PROTO) -// flags used in uf_flags -#define FC_ABORT 0x01 // abort function on error -#define FC_RANGE 0x02 // function accepts range -#define FC_DICT 0x04 // Dict function, uses "self" -#define FC_CLOSURE 0x08 // closure, uses outer scope variables -#define FC_DELETED 0x10 // :delfunction used while uf_refcount > 0 -#define FC_REMOVED 0x20 // function redefined while uf_refcount > 0 -#define FC_SANDBOX 0x40 // function defined in the sandbox -#define FC_DEAD 0x80 // function kept only for reference to dfunc -#define FC_EXPORT 0x100 // "export def Func()" -#define FC_NOARGS 0x200 // no a: variables in lambda -#define FC_VIM9 0x400 // defined in vim9 script file - /* * All user-defined functions are found in this hashtable. */ @@ -3267,7 +3254,7 @@ ex_function(exarg_T *eap) // ":def Func()" needs to be compiled if (eap->cmdidx == CMD_def) - compile_def_function(fp, FALSE); + compile_def_function(fp, FALSE, NULL); goto ret_free; diff --git a/src/version.c b/src/version.c index e23e503c63..8f1539a683 100644 --- a/src/version.c +++ b/src/version.c @@ -746,6 +746,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 677, /**/ 676, /**/ diff --git a/src/vim9.h b/src/vim9.h index ddc84b1e72..9269aa9388 100644 --- a/src/vim9.h +++ b/src/vim9.h @@ -27,6 +27,7 @@ typedef enum { ISN_LOADW, // push w: variable isn_arg.string ISN_LOADT, // push t: variable isn_arg.string ISN_LOADS, // push s: variable isn_arg.loadstore + ISN_LOADOUTER, // push variable from outer scope isn_arg.number ISN_LOADSCRIPT, // push script-local variable isn_arg.script. ISN_LOADOPT, // push option isn_arg.string ISN_LOADENV, // push environment variable isn_arg.string diff --git a/src/vim9compile.c b/src/vim9compile.c index c3f3bfdfbc..2ce85dd314 100644 --- a/src/vim9compile.c +++ b/src/vim9compile.c @@ -97,9 +97,10 @@ struct scope_S { typedef struct { char_u *lv_name; type_T *lv_type; - int lv_idx; // index of the variable on the stack - int lv_const; // when TRUE cannot be assigned to - int lv_arg; // when TRUE this is an argument + int lv_idx; // index of the variable on the stack + int lv_from_outer; // when TRUE using ctx_outer scope + int lv_const; // when TRUE cannot be assigned to + int lv_arg; // when TRUE this is an argument } lvar_T; /* @@ -123,6 +124,7 @@ struct cctx_S { cctx_T *ctx_outer; // outer scope for lambda or nested // function + int ctx_outer_used; // var in ctx_outer was used garray_T ctx_type_stack; // type of each item on the stack garray_T *ctx_type_list; // list of pointers to allocated types @@ -146,17 +148,37 @@ static int check_type(type_T *expected, type_T *actual, int give_msg); lookup_local(char_u *name, size_t len, cctx_T *cctx) { int idx; + lvar_T *lvar; if (len == 0) return NULL; + + // Find local in current function scope. for (idx = 0; idx < cctx->ctx_locals.ga_len; ++idx) { - lvar_T *lvar = ((lvar_T *)cctx->ctx_locals.ga_data) + idx; - + lvar = ((lvar_T *)cctx->ctx_locals.ga_data) + idx; if (STRNCMP(name, lvar->lv_name, len) == 0 && STRLEN(lvar->lv_name) == len) + { + lvar->lv_from_outer = FALSE; return lvar; + } } + + // Find local in outer function scope. + if (cctx->ctx_outer != NULL) + { + lvar = lookup_local(name, len, cctx->ctx_outer); + if (lvar != NULL) + { + // TODO: are there situations we should not mark the outer scope as + // used? + cctx->ctx_outer_used = TRUE; + lvar->lv_from_outer = TRUE; + return lvar; + } + } + return NULL; } @@ -417,6 +439,71 @@ typval2type(typval_T *tv) return &t_any; // not used } + static void +type_mismatch(type_T *expected, type_T *actual) +{ + char *tofree1, *tofree2; + + semsg(_("E1013: type mismatch, expected %s but got %s"), + type_name(expected, &tofree1), type_name(actual, &tofree2)); + vim_free(tofree1); + vim_free(tofree2); +} + + static void +arg_type_mismatch(type_T *expected, type_T *actual, int argidx) +{ + char *tofree1, *tofree2; + + semsg(_("E1013: argument %d: type mismatch, expected %s but got %s"), + argidx, + type_name(expected, &tofree1), type_name(actual, &tofree2)); + vim_free(tofree1); + vim_free(tofree2); +} + +/* + * Check if the expected and actual types match. + * Does not allow for assigning "any" to a specific type. + */ + static int +check_type(type_T *expected, type_T *actual, int give_msg) +{ + int ret = OK; + + // When expected is "unknown" we accept any actual type. + // When expected is "any" we accept any actual type except "void". + if (expected->tt_type != VAR_UNKNOWN + && !(expected->tt_type == VAR_ANY && actual->tt_type != VAR_VOID)) + + { + if (expected->tt_type != actual->tt_type) + { + if (give_msg) + type_mismatch(expected, actual); + return FAIL; + } + if (expected->tt_type == VAR_DICT || expected->tt_type == VAR_LIST) + { + // "unknown" is used for an empty list or dict + if (actual->tt_member != &t_unknown) + ret = check_type(expected->tt_member, actual->tt_member, FALSE); + } + else if (expected->tt_type == VAR_FUNC) + { + if (expected->tt_member != &t_unknown) + ret = check_type(expected->tt_member, actual->tt_member, FALSE); + if (ret == OK && expected->tt_argcount != -1 + && (actual->tt_argcount < expected->tt_min_argcount + || actual->tt_argcount > expected->tt_argcount)) + ret = FAIL; + } + if (ret == FAIL && give_msg) + type_mismatch(expected, actual); + } + return ret; +} + ///////////////////////////////////////////////////////////////////// // Following generate_ functions expect the caller to call ga_grow(). @@ -739,6 +826,29 @@ generate_TYPECHECK(cctx_T *cctx, type_T *vartype, int offset) return OK; } +/* + * Check that + * - "actual" is "expected" type or + * - "actual" is a type that can be "expected" type: add a runtime check; or + * - return FAIL. + */ + static int +need_type(type_T *actual, type_T *expected, int offset, cctx_T *cctx) +{ + if (check_type(expected, actual, FALSE) == OK) + return OK; + if (actual->tt_type != VAR_ANY + && actual->tt_type != VAR_UNKNOWN + && !(actual->tt_type == VAR_FUNC + && (actual->tt_member == &t_any || actual->tt_argcount < 0))) + { + type_mismatch(expected, actual); + return FAIL; + } + generate_TYPECHECK(cctx, expected, offset); + return OK; +} + /* * Generate an ISN_PUSHNR instruction. */ @@ -1272,7 +1382,7 @@ generate_CALL(cctx_T *cctx, ufunc_T *ufunc, int pushed_argcount) else expected = ufunc->uf_va_type->tt_member; actual = ((type_T **)stack->ga_data)[stack->ga_len - argcount + i]; - if (check_type(expected, actual, FALSE) == FAIL) + if (need_type(actual, expected, -argcount + i, cctx) == FAIL) { arg_type_mismatch(expected, actual, i + 1); return FAIL; @@ -1543,6 +1653,20 @@ skip_type(char_u *start) if (*p == '>') ++p; } + else if (*p == '(' && STRNCMP("func", start, 4) == 0) + { + // handle func(args): type + ++p; + while (*p != ')' && *p != NUL) + { + p = skip_type(p); + if (*p == ',') + p = skipwhite(p + 1); + } + if (*p == ')' && p[1] == ':') + p = skip_type(skipwhite(p + 2)); + } + return p; } @@ -2309,6 +2433,7 @@ compile_load(char_u **arg, char_u *end_arg, cctx_T *cctx, int error) size_t len = end - *arg; int idx; int gen_load = FALSE; + int gen_load_outer = FALSE; name = vim_strnsave(*arg, end - *arg); if (name == NULL) @@ -2343,7 +2468,10 @@ compile_load(char_u **arg, char_u *end_arg, cctx_T *cctx, int error) { type = lvar->lv_type; idx = lvar->lv_idx; - gen_load = TRUE; + if (lvar->lv_from_outer) + gen_load_outer = TRUE; + else + gen_load = TRUE; } else { @@ -2370,6 +2498,8 @@ compile_load(char_u **arg, char_u *end_arg, cctx_T *cctx, int error) } if (gen_load) res = generate_LOAD(cctx, ISN_LOAD, idx, NULL, type); + if (gen_load_outer) + res = generate_LOAD(cctx, ISN_LOADOUTER, idx, NULL, type); } *arg = end; @@ -2578,94 +2708,6 @@ to_name_const_end(char_u *arg) return p; } - static void -type_mismatch(type_T *expected, type_T *actual) -{ - char *tofree1, *tofree2; - - semsg(_("E1013: type mismatch, expected %s but got %s"), - type_name(expected, &tofree1), type_name(actual, &tofree2)); - vim_free(tofree1); - vim_free(tofree2); -} - - static void -arg_type_mismatch(type_T *expected, type_T *actual, int argidx) -{ - char *tofree1, *tofree2; - - semsg(_("E1013: argument %d: type mismatch, expected %s but got %s"), - argidx, - type_name(expected, &tofree1), type_name(actual, &tofree2)); - vim_free(tofree1); - vim_free(tofree2); -} - -/* - * Check if the expected and actual types match. - * Does not allow for assigning "any" to a specific type. - */ - static int -check_type(type_T *expected, type_T *actual, int give_msg) -{ - int ret = OK; - - // When expected is "unknown" we accept any actual type. - // When expected is "any" we accept any actual type except "void". - if (expected->tt_type != VAR_UNKNOWN - && !(expected->tt_type == VAR_ANY && actual->tt_type != VAR_VOID)) - - { - if (expected->tt_type != actual->tt_type) - { - if (give_msg) - type_mismatch(expected, actual); - return FAIL; - } - if (expected->tt_type == VAR_DICT || expected->tt_type == VAR_LIST) - { - // "unknown" is used for an empty list or dict - if (actual->tt_member != &t_unknown) - ret = check_type(expected->tt_member, actual->tt_member, FALSE); - } - else if (expected->tt_type == VAR_FUNC) - { - if (expected->tt_member != &t_unknown) - ret = check_type(expected->tt_member, actual->tt_member, FALSE); - if (ret == OK && expected->tt_argcount != -1 - && (actual->tt_argcount < expected->tt_min_argcount - || actual->tt_argcount > expected->tt_argcount)) - ret = FAIL; - } - if (ret == FAIL && give_msg) - type_mismatch(expected, actual); - } - return ret; -} - -/* - * Check that - * - "actual" is "expected" type or - * - "actual" is a type that can be "expected" type: add a runtime check; or - * - return FAIL. - */ - static int -need_type(type_T *actual, type_T *expected, int offset, cctx_T *cctx) -{ - if (check_type(expected, actual, FALSE) == OK) - return OK; - if (actual->tt_type != VAR_ANY - && actual->tt_type != VAR_UNKNOWN - && !(actual->tt_type == VAR_FUNC - && (actual->tt_member == &t_any || actual->tt_argcount < 0))) - { - type_mismatch(expected, actual); - return FAIL; - } - generate_TYPECHECK(cctx, expected, offset); - return OK; -} - /* * parse a list: [expr, expr] * "*arg" points to the '['. @@ -2734,7 +2776,7 @@ compile_lambda(char_u **arg, cctx_T *cctx) // The function will have one line: "return {expr}". // Compile it into instructions. - compile_def_function(ufunc, TRUE); + compile_def_function(ufunc, TRUE, cctx); if (ufunc->uf_dfunc_idx >= 0) { @@ -2779,7 +2821,7 @@ compile_lambda_call(char_u **arg, cctx_T *cctx) // The function will have one line: "return {expr}". // Compile it into instructions. - compile_def_function(ufunc, TRUE); + compile_def_function(ufunc, TRUE, cctx); // compile the arguments *arg = skipwhite(*arg + 1); @@ -4227,14 +4269,10 @@ compile_assignment(char_u *arg, exarg_T *eap, cmdidx_T cmdidx, cctx_T *cctx) semsg(_("E1017: Variable already declared: %s"), name); goto theend; } - else + else if (lvar->lv_const) { - if (lvar->lv_const) - { - semsg(_("E1018: Cannot assign to a constant: %s"), - name); - goto theend; - } + semsg(_("E1018: Cannot assign to a constant: %s"), name); + goto theend; } } else if (STRNCMP(arg, "s:", 2) == 0 @@ -5931,11 +5969,12 @@ theend: * Adds the function to "def_functions". * When "set_return_type" is set then set ufunc->uf_ret_type to the type of the * return statement (used for lambda). + * "outer_cctx" is set for a nested function. * This can be used recursively through compile_lambda(), which may reallocate * "def_functions". */ void -compile_def_function(ufunc_T *ufunc, int set_return_type) +compile_def_function(ufunc_T *ufunc, int set_return_type, cctx_T *outer_cctx) { char_u *line = NULL; char_u *p; @@ -5976,6 +6015,7 @@ compile_def_function(ufunc_T *ufunc, int set_return_type) CLEAR_FIELD(cctx); cctx.ctx_ufunc = ufunc; cctx.ctx_lnum = -1; + cctx.ctx_outer = outer_cctx; ga_init2(&cctx.ctx_locals, sizeof(lvar_T), 10); ga_init2(&cctx.ctx_type_stack, sizeof(type_T *), 50); ga_init2(&cctx.ctx_imports, sizeof(imported_T), 10); @@ -6355,6 +6395,8 @@ compile_def_function(ufunc_T *ufunc, int set_return_type) dfunc->df_instr = instr->ga_data; dfunc->df_instr_count = instr->ga_len; dfunc->df_varcount = cctx.ctx_locals_count; + if (cctx.ctx_outer_used) + ufunc->uf_flags |= FC_CLOSURE; } { @@ -6533,6 +6575,7 @@ delete_instr(isn_T *isn) case ISN_INDEX: case ISN_JUMP: case ISN_LOAD: + case ISN_LOADOUTER: case ISN_LOADSCRIPT: case ISN_LOADREG: case ISN_LOADV: diff --git a/src/vim9execute.c b/src/vim9execute.c index 3cb8628c55..aee1c80a2b 100644 --- a/src/vim9execute.c +++ b/src/vim9execute.c @@ -58,6 +58,9 @@ typedef struct { garray_T ec_stack; // stack of typval_T values int ec_frame; // index in ec_stack: context of ec_dfunc_idx + garray_T *ec_outer_stack; // stack used for closures + int ec_outer_frame; // stack frame in ec_outer_stack + garray_T ec_trystack; // stack of trycmd_T values int ec_in_catch; // when TRUE in catch or finally block @@ -229,6 +232,10 @@ call_dfunc(int cdf_idx, int argcount_arg, ectx_T *ectx) ectx->ec_instr = dfunc->df_instr; estack_push_ufunc(ETYPE_UFUNC, dfunc->df_ufunc, 1); + // used for closures + ectx->ec_outer_stack = ufunc->uf_ectx_stack; + ectx->ec_outer_frame = ufunc->uf_ectx_frame; + // Decide where to start execution, handles optional arguments. init_instr_idx(ufunc, argcount, ectx); @@ -508,6 +515,9 @@ call_def_function( // Get pointer to a local variable on the stack. Negative for arguments. #define STACK_TV_VAR(idx) (((typval_T *)ectx.ec_stack.ga_data) + ectx.ec_frame + STACK_FRAME_SIZE + idx) +// Like STACK_TV_VAR but use the outer scope +#define STACK_OUT_TV_VAR(idx) (((typval_T *)ectx.ec_outer_stack->ga_data) + ectx.ec_outer_frame + STACK_FRAME_SIZE + idx) + CLEAR_FIELD(ectx); ga_init2(&ectx.ec_stack, sizeof(typval_T), 500); if (ga_grow(&ectx.ec_stack, 20) == FAIL) @@ -786,6 +796,15 @@ call_def_function( ++ectx.ec_stack.ga_len; break; + // load variable or argument from outer scope + case ISN_LOADOUTER: + if (ga_grow(&ectx.ec_stack, 1) == FAIL) + goto failed; + copy_tv(STACK_OUT_TV_VAR(iptr->isn_arg.number), + STACK_TV_BOT(0)); + ++ectx.ec_stack.ga_len; + break; + // load v: variable case ISN_LOADV: if (ga_grow(&ectx.ec_stack, 1) == FAIL) @@ -1304,6 +1323,14 @@ call_def_function( pt->pt_refcount = 1; ++dfunc->df_ufunc->uf_refcount; + if (dfunc->df_ufunc->uf_flags & FC_CLOSURE) + { + // Closure needs to find local variables in the current + // stack. + dfunc->df_ufunc->uf_ectx_stack = &ectx.ec_stack; + dfunc->df_ufunc->uf_ectx_frame = ectx.ec_frame; + } + if (ga_grow(&ectx.ec_stack, 1) == FAIL) goto failed; tv = STACK_TV_BOT(0); @@ -1862,7 +1889,12 @@ call_def_function( checktype_T *ct = &iptr->isn_arg.type; tv = STACK_TV_BOT(ct->ct_off); - if (tv->v_type != ct->ct_type) + // TODO: better type comparison + if (tv->v_type != ct->ct_type + && !((tv->v_type == VAR_PARTIAL + && ct->ct_type == VAR_FUNC) + || (tv->v_type == VAR_FUNC + && ct->ct_type == VAR_PARTIAL))) { semsg(_("E1029: Expected %s but got %s"), vartype_name(ct->ct_type), @@ -2029,12 +2061,18 @@ ex_disassemble(exarg_T *eap) (long long)(iptr->isn_arg.number)); break; case ISN_LOAD: - if (iptr->isn_arg.number < 0) - smsg("%4d LOAD arg[%lld]", current, - (long long)(iptr->isn_arg.number + STACK_FRAME_SIZE)); - else - smsg("%4d LOAD $%lld", current, + case ISN_LOADOUTER: + { + char *add = iptr->isn_type == ISN_LOAD ? "" : "OUTER"; + + if (iptr->isn_arg.number < 0) + smsg("%4d LOAD%s arg[%lld]", current, add, + (long long)(iptr->isn_arg.number + + STACK_FRAME_SIZE)); + else + smsg("%4d LOAD%s $%lld", current, add, (long long)(iptr->isn_arg.number)); + } break; case ISN_LOADV: smsg("%4d LOADV v:%s", current, From d58a662f44dc11475f4cf5922a948635da934cc4 Mon Sep 17 00:00:00 2001 From: Bram Moolenaar <Bram@vim.org> Date: Sat, 2 May 2020 14:52:57 +0200 Subject: [PATCH 073/230] patch 8.2.0678: rare crash for popup menu Problem: Rare crash for popup menu. Solution: Check for NULL pointer. (Nobuhiro Takasaki, closes #6027) --- src/popupmenu.c | 9 ++++++--- src/version.c | 2 ++ 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/src/popupmenu.c b/src/popupmenu.c index b267ec54af..d6993dc433 100644 --- a/src/popupmenu.c +++ b/src/popupmenu.c @@ -60,9 +60,12 @@ pum_compute_size(void) pum_extra_width = 0; for (i = 0; i < pum_size; ++i) { - w = vim_strsize(pum_array[i].pum_text); - if (pum_base_width < w) - pum_base_width = w; + if (pum_array[i].pum_text != NULL) + { + w = vim_strsize(pum_array[i].pum_text); + if (pum_base_width < w) + pum_base_width = w; + } if (pum_array[i].pum_kind != NULL) { w = vim_strsize(pum_array[i].pum_kind) + 1; diff --git a/src/version.c b/src/version.c index 8f1539a683..29763f7f5d 100644 --- a/src/version.c +++ b/src/version.c @@ -746,6 +746,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 678, /**/ 677, /**/ From bf67ea1af05cbb30cd8f0b665fb567c0dca79796 Mon Sep 17 00:00:00 2001 From: Bram Moolenaar <Bram@vim.org> Date: Sat, 2 May 2020 17:52:42 +0200 Subject: [PATCH 074/230] patch 8.2.0679: Vim9: incomplete support for closures Problem: Vim9: incomplete support for closures. Solution: At the end of a function copy arguments and local variables if they are still used by a referenced closure. --- src/structs.h | 4 +- src/testdir/test_vim9_func.vim | 12 ++ src/version.c | 2 + src/vim9.h | 33 ++++- src/vim9compile.c | 24 +++- src/vim9execute.c | 252 +++++++++++++++++++++++++-------- 6 files changed, 261 insertions(+), 66 deletions(-) diff --git a/src/structs.h b/src/structs.h index 70b6e3f72a..601194e12f 100644 --- a/src/structs.h +++ b/src/structs.h @@ -1563,8 +1563,6 @@ typedef struct int uf_refcount; // reference count, see func_name_refcount() funccall_T *uf_scoped; // l: local variables for closure - garray_T *uf_ectx_stack; // where compiled closure finds local vars - int uf_ectx_frame; // index of function frame in uf_ectx_stack char_u *uf_name_exp; // if "uf_name[]" starts with SNR the name with // "<SNR>" as a string, otherwise NULL @@ -1591,7 +1589,7 @@ typedef struct #define FIXVAR_CNT 12 // number of fixed variables /* - * structure to hold info for a function that is currently being executed. + * Structure to hold info for a function that is currently being executed. */ struct funccall_S { diff --git a/src/testdir/test_vim9_func.vim b/src/testdir/test_vim9_func.vim index a317d8f58d..0fd28924a3 100644 --- a/src/testdir/test_vim9_func.vim +++ b/src/testdir/test_vim9_func.vim @@ -650,4 +650,16 @@ def Test_closure_simple() assert_equal('some more', RefFunc({s -> local .. s})) enddef +def MakeRef() + let local = 'some ' + g:Ref = {s -> local .. s} +enddef + +def Test_closure_ref_after_return() + MakeRef() + assert_equal('some thing', g:Ref('thing')) + unlet g:Ref +enddef + + " vim: ts=8 sw=2 sts=2 expandtab tw=80 fdm=marker diff --git a/src/version.c b/src/version.c index 29763f7f5d..eb88916292 100644 --- a/src/version.c +++ b/src/version.c @@ -746,6 +746,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 679, /**/ 678, /**/ diff --git a/src/vim9.h b/src/vim9.h index 9269aa9388..befa6a74c8 100644 --- a/src/vim9.h +++ b/src/vim9.h @@ -71,7 +71,7 @@ typedef enum { ISN_PCALL, // call partial, use isn_arg.pfunc ISN_PCALL_END, // cleanup after ISN_PCALL with cpf_top set ISN_RETURN, // return, result is on top of stack - ISN_FUNCREF, // push a function ref to dfunc isn_arg.number + ISN_FUNCREF, // push a function ref to dfunc isn_arg.funcref // expression operations ISN_JUMP, // jump if condition is matched isn_arg.jump @@ -218,6 +218,12 @@ typedef struct { int ul_forceit; // forceit flag } unlet_T; +// arguments to ISN_FUNCREF +typedef struct { + int fr_func; // function index + int fr_var_idx; // variable to store partial +} funcref_T; + /* * Instruction */ @@ -249,9 +255,25 @@ struct isn_S { loadstore_T loadstore; script_T script; unlet_T unlet; + funcref_T funcref; } isn_arg; }; +/* + * Structure to hold the context of a compiled function, used by closures + * defined in that function. + */ +typedef struct funcstack_S +{ + garray_T fs_ga; // contains the stack, with: + // - arguments + // - frame + // - local variables + + int fs_refcount; // nr of closures referencing this funcstack + int fs_copyID; // for garray_T collection +} funcstack_T; + /* * Info about a function defined with :def. Used in "def_functions". */ @@ -264,10 +286,19 @@ struct dfunc_S { isn_T *df_instr; // function body to be executed int df_instr_count; + garray_T *df_ectx_stack; // where compiled closure finds local vars + int df_ectx_frame; // index of function frame in uf_ectx_stack + funcstack_T *df_funcstack; // copy of stack for closure, used after + // closure context function returns + int df_varcount; // number of local variables + int df_closure_count; // number of closures created }; // Number of entries used by stack frame for a function call. +// - function index +// - instruction index +// - previous frame index #define STACK_FRAME_SIZE 3 diff --git a/src/vim9compile.c b/src/vim9compile.c index 2ce85dd314..5644c50358 100644 --- a/src/vim9compile.c +++ b/src/vim9compile.c @@ -116,6 +116,9 @@ struct cctx_S { garray_T ctx_locals; // currently visible local variables int ctx_locals_count; // total number of local variables + int ctx_closure_count; // number of closures created in the + // function + garray_T ctx_imports; // imported items int ctx_skip; // when TRUE skip commands, when FALSE skip @@ -1254,7 +1257,8 @@ generate_FUNCREF(cctx_T *cctx, int dfunc_idx) RETURN_OK_IF_SKIP(cctx); if ((isn = generate_instr(cctx, ISN_FUNCREF)) == NULL) return FAIL; - isn->isn_arg.number = dfunc_idx; + isn->isn_arg.funcref.fr_func = dfunc_idx; + isn->isn_arg.funcref.fr_var_idx = cctx->ctx_closure_count++; if (ga_grow(stack, 1) == FAIL) return FAIL; @@ -6395,6 +6399,7 @@ compile_def_function(ufunc_T *ufunc, int set_return_type, cctx_T *outer_cctx) dfunc->df_instr = instr->ga_data; dfunc->df_instr_count = instr->ga_len; dfunc->df_varcount = cctx.ctx_locals_count; + dfunc->df_closure_count = cctx.ctx_closure_count; if (cctx.ctx_outer_used) ufunc->uf_flags |= FC_CLOSURE; } @@ -6620,6 +6625,23 @@ delete_def_function_contents(dfunc_T *dfunc) delete_instr(dfunc->df_instr + idx); VIM_CLEAR(dfunc->df_instr); } + if (dfunc->df_funcstack != NULL) + { + // Decrease the reference count for the context of a closure. If down + // to zero free it and clear the variables on the stack. + if (--dfunc->df_funcstack->fs_refcount == 0) + { + garray_T *gap = &dfunc->df_funcstack->fs_ga; + typval_T *stack = gap->ga_data; + int i; + + for (i = 0; i < gap->ga_len; ++i) + clear_tv(stack + i); + ga_clear(gap); + vim_free(dfunc->df_funcstack); + } + dfunc->df_funcstack = NULL; + } dfunc->df_deleted = TRUE; } diff --git a/src/vim9execute.c b/src/vim9execute.c index aee1c80a2b..c27bcf0ab2 100644 --- a/src/vim9execute.c +++ b/src/vim9execute.c @@ -24,7 +24,7 @@ // Structure put on ec_trystack when ISN_TRY is encountered. typedef struct { - int tcd_frame; // ec_frame when ISN_TRY was encountered + int tcd_frame_idx; // ec_frame_idx when ISN_TRY was encountered int tcd_catch_idx; // instruction of the first catch int tcd_finally_idx; // instruction of the finally block int tcd_caught; // catch block entered @@ -56,7 +56,7 @@ typedef struct { */ typedef struct { garray_T ec_stack; // stack of typval_T values - int ec_frame; // index in ec_stack: context of ec_dfunc_idx + int ec_frame_idx; // index in ec_stack: context of ec_dfunc_idx garray_T *ec_outer_stack; // stack used for closures int ec_outer_frame; // stack frame in ec_outer_stack @@ -202,7 +202,8 @@ call_dfunc(int cdf_idx, int argcount_arg, ectx_T *ectx) iemsg("Argument count wrong?"); return FAIL; } - if (ga_grow(&ectx->ec_stack, arg_to_add + 3 + dfunc->df_varcount) == FAIL) + if (ga_grow(&ectx->ec_stack, arg_to_add + 3 + + dfunc->df_varcount + dfunc->df_closure_count) == FAIL) return FAIL; // Move the vararg-list to below the missing optional arguments. @@ -215,17 +216,16 @@ call_dfunc(int cdf_idx, int argcount_arg, ectx_T *ectx) ectx->ec_stack.ga_len += arg_to_add; // Store current execution state in stack frame for ISN_RETURN. - // TODO: If the actual number of arguments doesn't match what the called - // function expects things go bad. STACK_TV_BOT(0)->vval.v_number = ectx->ec_dfunc_idx; STACK_TV_BOT(1)->vval.v_number = ectx->ec_iidx; - STACK_TV_BOT(2)->vval.v_number = ectx->ec_frame; - ectx->ec_frame = ectx->ec_stack.ga_len; + STACK_TV_BOT(2)->vval.v_number = ectx->ec_frame_idx; + ectx->ec_frame_idx = ectx->ec_stack.ga_len; // Initialize local variables - for (idx = 0; idx < dfunc->df_varcount; ++idx) + for (idx = 0; idx < dfunc->df_varcount + dfunc->df_closure_count; ++idx) STACK_TV_BOT(STACK_FRAME_SIZE + idx)->v_type = VAR_UNKNOWN; - ectx->ec_stack.ga_len += STACK_FRAME_SIZE + dfunc->df_varcount; + ectx->ec_stack.ga_len += STACK_FRAME_SIZE + + dfunc->df_varcount + dfunc->df_closure_count; // Set execution state to the start of the called function. ectx->ec_dfunc_idx = cdf_idx; @@ -233,8 +233,8 @@ call_dfunc(int cdf_idx, int argcount_arg, ectx_T *ectx) estack_push_ufunc(ETYPE_UFUNC, dfunc->df_ufunc, 1); // used for closures - ectx->ec_outer_stack = ufunc->uf_ectx_stack; - ectx->ec_outer_frame = ufunc->uf_ectx_frame; + ectx->ec_outer_stack = dfunc->df_ectx_stack; + ectx->ec_outer_frame = dfunc->df_ectx_frame; // Decide where to start execution, handles optional arguments. init_instr_idx(ufunc, argcount, ectx); @@ -245,35 +245,123 @@ call_dfunc(int cdf_idx, int argcount_arg, ectx_T *ectx) // Get pointer to item in the stack. #define STACK_TV(idx) (((typval_T *)ectx->ec_stack.ga_data) + idx) +/* + * Used when returning from a function: Check if any closure is still + * referenced. If so then move the arguments and variables to a separate piece + * of stack to be used when the closure is called. + * When "free_arguments" is TRUE the arguments are to be freed. + * Returns FAIL when out of memory. + */ + static int +handle_closure_in_use(ectx_T *ectx, int free_arguments) +{ + dfunc_T *dfunc = ((dfunc_T *)def_functions.ga_data) + + ectx->ec_dfunc_idx; + int argcount = ufunc_argcount(dfunc->df_ufunc); + int top = ectx->ec_frame_idx - argcount; + int idx; + typval_T *tv; + int closure_in_use = FALSE; + + // Check if any created closure is still in use. + for (idx = 0; idx < dfunc->df_closure_count; ++idx) + { + tv = STACK_TV(ectx->ec_frame_idx + STACK_FRAME_SIZE + + dfunc->df_varcount + idx); + if (tv->v_type == VAR_PARTIAL && tv->vval.v_partial->pt_refcount > 1) + closure_in_use = TRUE; + } + + if (closure_in_use) + { + funcstack_T *funcstack = ALLOC_CLEAR_ONE(funcstack_T); + typval_T *stack; + + // A closure is using the arguments and/or local variables. + // Move them to the called function. + if (funcstack == NULL) + return FAIL; + funcstack->fs_ga.ga_len = argcount + STACK_FRAME_SIZE + + dfunc->df_varcount; + stack = ALLOC_CLEAR_MULT(typval_T, funcstack->fs_ga.ga_len); + funcstack->fs_ga.ga_data = stack; + if (stack == NULL) + { + vim_free(funcstack); + return FAIL; + } + + // Move or copy the arguments. + for (idx = 0; idx < argcount; ++idx) + { + tv = STACK_TV(top + idx); + if (free_arguments) + { + *(stack + idx) = *tv; + tv->v_type = VAR_UNKNOWN; + } + else + copy_tv(tv, stack + idx); + } + // Move the local variables. + for (idx = 0; idx < dfunc->df_varcount; ++idx) + { + tv = STACK_TV(ectx->ec_frame_idx + STACK_FRAME_SIZE + idx); + *(stack + argcount + STACK_FRAME_SIZE + idx) = *tv; + tv->v_type = VAR_UNKNOWN; + } + + for (idx = 0; idx < dfunc->df_closure_count; ++idx) + { + tv = STACK_TV(ectx->ec_frame_idx + STACK_FRAME_SIZE + + dfunc->df_varcount + idx); + if (tv->v_type == VAR_PARTIAL + && tv->vval.v_partial->pt_refcount > 1) + { + dfunc_T *pt_dfunc = ((dfunc_T *)def_functions.ga_data) + + tv->vval.v_partial->pt_func->uf_dfunc_idx; + ++funcstack->fs_refcount; + pt_dfunc->df_funcstack = funcstack; + pt_dfunc->df_ectx_stack = &funcstack->fs_ga; + pt_dfunc->df_ectx_frame = ectx->ec_frame_idx - top; + } + } + } + + return OK; +} + /* * Return from the current function. */ - static void + static int func_return(ectx_T *ectx) { int idx; - dfunc_T *dfunc; - int top; + dfunc_T *dfunc = ((dfunc_T *)def_functions.ga_data) + + ectx->ec_dfunc_idx; + int argcount = ufunc_argcount(dfunc->df_ufunc); + int top = ectx->ec_frame_idx - argcount; // execution context goes one level up estack_pop(); - // Clear the local variables and temporary values, but not - // the return value. - for (idx = ectx->ec_frame + STACK_FRAME_SIZE; + if (handle_closure_in_use(ectx, TRUE) == FAIL) + return FAIL; + + // Clear the arguments. + for (idx = top; idx < ectx->ec_frame_idx; ++idx) + clear_tv(STACK_TV(idx)); + + // Clear local variables and temp values, but not the return value. + for (idx = ectx->ec_frame_idx + STACK_FRAME_SIZE; idx < ectx->ec_stack.ga_len - 1; ++idx) clear_tv(STACK_TV(idx)); - // Clear the arguments. - dfunc = ((dfunc_T *)def_functions.ga_data) + ectx->ec_dfunc_idx; - top = ectx->ec_frame - ufunc_argcount(dfunc->df_ufunc); - for (idx = top; idx < ectx->ec_frame; ++idx) - clear_tv(STACK_TV(idx)); - // Restore the previous frame. - ectx->ec_dfunc_idx = STACK_TV(ectx->ec_frame)->vval.v_number; - ectx->ec_iidx = STACK_TV(ectx->ec_frame + 1)->vval.v_number; - ectx->ec_frame = STACK_TV(ectx->ec_frame + 2)->vval.v_number; + ectx->ec_dfunc_idx = STACK_TV(ectx->ec_frame_idx)->vval.v_number; + ectx->ec_iidx = STACK_TV(ectx->ec_frame_idx + 1)->vval.v_number; + ectx->ec_frame_idx = STACK_TV(ectx->ec_frame_idx + 2)->vval.v_number; dfunc = ((dfunc_T *)def_functions.ga_data) + ectx->ec_dfunc_idx; ectx->ec_instr = dfunc->df_instr; @@ -282,6 +370,8 @@ func_return(ectx_T *ectx) idx = ectx->ec_stack.ga_len - 1; ectx->ec_stack.ga_len = top + 1; *STACK_TV_BOT(-1) = *STACK_TV(idx); + + return OK; } #undef STACK_TV @@ -498,7 +588,7 @@ call_def_function( { ectx_T ectx; // execution context int argc = argc_arg; - int initial_frame_ptr; + int initial_frame_idx; typval_T *tv; int idx; int ret = FAIL; @@ -513,7 +603,7 @@ call_def_function( #define STACK_TV_BOT(idx) (((typval_T *)ectx.ec_stack.ga_data) + ectx.ec_stack.ga_len + idx) // Get pointer to a local variable on the stack. Negative for arguments. -#define STACK_TV_VAR(idx) (((typval_T *)ectx.ec_stack.ga_data) + ectx.ec_frame + STACK_FRAME_SIZE + idx) +#define STACK_TV_VAR(idx) (((typval_T *)ectx.ec_stack.ga_data) + ectx.ec_frame_idx + STACK_FRAME_SIZE + idx) // Like STACK_TV_VAR but use the outer scope #define STACK_OUT_TV_VAR(idx) (((typval_T *)ectx.ec_outer_stack->ga_data) + ectx.ec_outer_frame + STACK_FRAME_SIZE + idx) @@ -562,8 +652,8 @@ call_def_function( ++ectx.ec_stack.ga_len; // Frame pointer points to just after arguments. - ectx.ec_frame = ectx.ec_stack.ga_len; - initial_frame_ptr = ectx.ec_frame; + ectx.ec_frame_idx = ectx.ec_stack.ga_len; + initial_frame_idx = ectx.ec_frame_idx; // dummy frame entries for (idx = 0; idx < STACK_FRAME_SIZE; ++idx) @@ -573,13 +663,14 @@ call_def_function( } { - // Reserve space for local variables. + // Reserve space for local variables and closure references. dfunc_T *dfunc = ((dfunc_T *)def_functions.ga_data) + ufunc->uf_dfunc_idx; + int count = dfunc->df_varcount + dfunc->df_closure_count; - for (idx = 0; idx < dfunc->df_varcount; ++idx) + for (idx = 0; idx < count; ++idx) STACK_TV_VAR(idx)->v_type = VAR_UNKNOWN; - ectx.ec_stack.ga_len += dfunc->df_varcount; + ectx.ec_stack.ga_len += count; ectx.ec_instr = dfunc->df_instr; } @@ -623,7 +714,7 @@ call_def_function( // the current function. if (trystack->ga_len > 0) trycmd = ((trycmd_T *)trystack->ga_data) + trystack->ga_len - 1; - if (trycmd != NULL && trycmd->tcd_frame == ectx.ec_frame) + if (trycmd != NULL && trycmd->tcd_frame_idx == ectx.ec_frame_idx) { // jump to ":catch" or ":finally" ectx.ec_in_catch = TRUE; @@ -632,7 +723,7 @@ call_def_function( else { // not inside try or need to return from current functions. - if (ectx.ec_frame == initial_frame_ptr) + if (ectx.ec_frame_idx == initial_frame_idx) { // At the toplevel we are done. Push a dummy return value. if (ga_grow(&ectx.ec_stack, 1) == FAIL) @@ -642,10 +733,13 @@ call_def_function( tv->vval.v_number = 0; ++ectx.ec_stack.ga_len; need_rethrow = TRUE; + if (handle_closure_in_use(&ectx, FALSE) == FAIL) + goto failed; goto done; } - func_return(&ectx); + if (func_return(&ectx) == FAIL) + goto failed; } continue; } @@ -1073,8 +1167,7 @@ call_def_function( } --ectx.ec_stack.ga_len; - di = find_var_in_ht(ht, 0, - iptr->isn_arg.string + 2, TRUE); + di = find_var_in_ht(ht, 0, iptr->isn_arg.string + 2, TRUE); if (di == NULL) store_var(iptr->isn_arg.string, STACK_TV_BOT(0)); else @@ -1289,7 +1382,8 @@ call_def_function( if (trystack->ga_len > 0) trycmd = ((trycmd_T *)trystack->ga_data) + trystack->ga_len - 1; - if (trycmd != NULL && trycmd->tcd_frame == ectx.ec_frame + if (trycmd != NULL + && trycmd->tcd_frame_idx == ectx.ec_frame_idx && trycmd->tcd_finally_idx != 0) { // jump to ":finally" @@ -1300,10 +1394,15 @@ call_def_function( { // Restore previous function. If the frame pointer // is zero then there is none and we are done. - if (ectx.ec_frame == initial_frame_ptr) + if (ectx.ec_frame_idx == initial_frame_idx) + { + if (handle_closure_in_use(&ectx, FALSE) == FAIL) + goto failed; goto done; + } - func_return(&ectx); + if (func_return(&ectx) == FAIL) + goto failed; } } break; @@ -1312,27 +1411,49 @@ call_def_function( case ISN_FUNCREF: { partial_T *pt = NULL; - dfunc_T *dfunc; + dfunc_T *pt_dfunc; pt = ALLOC_CLEAR_ONE(partial_T); if (pt == NULL) goto failed; - dfunc = ((dfunc_T *)def_functions.ga_data) - + iptr->isn_arg.number; - pt->pt_func = dfunc->df_ufunc; - pt->pt_refcount = 1; - ++dfunc->df_ufunc->uf_refcount; - - if (dfunc->df_ufunc->uf_flags & FC_CLOSURE) + if (ga_grow(&ectx.ec_stack, 1) == FAIL) { - // Closure needs to find local variables in the current - // stack. - dfunc->df_ufunc->uf_ectx_stack = &ectx.ec_stack; - dfunc->df_ufunc->uf_ectx_frame = ectx.ec_frame; + vim_free(pt); + goto failed; + } + pt_dfunc = ((dfunc_T *)def_functions.ga_data) + + iptr->isn_arg.funcref.fr_func; + pt->pt_func = pt_dfunc->df_ufunc; + pt->pt_refcount = 1; + ++pt_dfunc->df_ufunc->uf_refcount; + + if (pt_dfunc->df_ufunc->uf_flags & FC_CLOSURE) + { + dfunc_T *dfunc = ((dfunc_T *)def_functions.ga_data) + + ectx.ec_dfunc_idx; + + // The closure needs to find arguments and local + // variables in the current stack. + pt_dfunc->df_ectx_stack = &ectx.ec_stack; + pt_dfunc->df_ectx_frame = ectx.ec_frame_idx; + + // If this function returns and the closure is still + // used, we need to make a copy of the context + // (arguments and local variables). Store a reference + // to the partial so we can handle that. + ++pt->pt_refcount; + tv = STACK_TV_VAR(dfunc->df_varcount + + iptr->isn_arg.funcref.fr_var_idx); + if (tv->v_type == VAR_PARTIAL) + { + // TODO: use a garray_T on ectx. + emsg("Multiple closures not supported yet"); + goto failed; + } + tv->v_type = VAR_PARTIAL; + tv->vval.v_partial = pt; } - if (ga_grow(&ectx.ec_stack, 1) == FAIL) - goto failed; tv = STACK_TV_BOT(0); ++ectx.ec_stack.ga_len; tv->vval.v_partial = pt; @@ -1410,7 +1531,7 @@ call_def_function( + ectx.ec_trystack.ga_len; ++ectx.ec_trystack.ga_len; ++trylevel; - trycmd->tcd_frame = ectx.ec_frame; + trycmd->tcd_frame_idx = ectx.ec_frame_idx; trycmd->tcd_catch_idx = iptr->isn_arg.try.try_catch; trycmd->tcd_finally_idx = iptr->isn_arg.try.try_finally; trycmd->tcd_caught = FALSE; @@ -1472,10 +1593,15 @@ call_def_function( { // Restore previous function. If the frame pointer // is zero then there is none and we are done. - if (ectx.ec_frame == initial_frame_ptr) + if (ectx.ec_frame_idx == initial_frame_idx) + { + if (handle_closure_in_use(&ectx, FALSE) == FAIL) + goto failed; goto done; + } - func_return(&ectx); + if (func_return(&ectx) == FAIL) + goto failed; } } } @@ -1949,12 +2075,15 @@ done: failed: // When failed need to unwind the call stack. - while (ectx.ec_frame != initial_frame_ptr) + while (ectx.ec_frame_idx != initial_frame_idx) func_return(&ectx); failed_early: current_sctx.sc_version = save_sc_version; + + // Free all local variables, but not arguments. for (idx = 0; idx < ectx.ec_stack.ga_len; ++idx) clear_tv(STACK_TV(idx)); + vim_free(ectx.ec_stack.ga_data); vim_free(ectx.ec_trystack.ga_data); return ret; @@ -2309,9 +2438,10 @@ ex_disassemble(exarg_T *eap) case ISN_FUNCREF: { dfunc_T *df = ((dfunc_T *)def_functions.ga_data) - + iptr->isn_arg.number; + + iptr->isn_arg.funcref.fr_func; - smsg("%4d FUNCREF %s", current, df->df_ufunc->uf_name); + smsg("%4d FUNCREF %s $%d", current, df->df_ufunc->uf_name, + iptr->isn_arg.funcref.fr_var_idx + df->df_varcount); } break; From 01f731e97c92bee05927f5008b7cd34ce188632b Mon Sep 17 00:00:00 2001 From: Bram Moolenaar <Bram@vim.org> Date: Sat, 2 May 2020 18:14:37 +0200 Subject: [PATCH 075/230] patch 8.2.0680: PTYGROUP and PTYMODE are unused Problem: PTYGROUP and PTYMODE are unused. Solution: Remove from autoconf. (closes #6024) --- src/auto/configure | 97 ---------------------------------------------- src/config.h.in | 6 --- src/configure.ac | 71 --------------------------------- src/version.c | 2 + 4 files changed, 2 insertions(+), 174 deletions(-) diff --git a/src/auto/configure b/src/auto/configure index bd26a7c590..6087e0e5af 100755 --- a/src/auto/configure +++ b/src/auto/configure @@ -12476,103 +12476,6 @@ else $as_echo "don't know" >&6; } fi -rm -f conftest_grp -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking default tty permissions/group" >&5 -$as_echo_n "checking default tty permissions/group... " >&6; } -if ${vim_cv_tty_group+:} false; then : - $as_echo_n "(cached) " >&6 -else - - if test "$cross_compiling" = yes; then : - - as_fn_error $? "cross-compiling: please set 'vim_cv_tty_group' and 'vim_cv_tty_mode'" "$LINENO" 5 - -else - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -#include "confdefs.h" -#include <sys/types.h> -#if STDC_HEADERS -# include <stdlib.h> -# include <stddef.h> -#endif -#ifdef HAVE_UNISTD_H -#include <unistd.h> -#endif -#include <sys/stat.h> -#include <stdio.h> -main() -{ - struct stat sb; - char *x,*ttyname(); - int om, m; - FILE *fp; - - if (!(x = ttyname(0))) exit(1); - if (stat(x, &sb)) exit(1); - om = sb.st_mode; - if (om & 002) exit(0); - m = system("mesg y"); - if (m == -1 || m == 127) exit(1); - if (stat(x, &sb)) exit(1); - m = sb.st_mode; - if (chmod(x, om)) exit(1); - if (m & 002) exit(0); - if (sb.st_gid == getgid()) exit(1); - if (!(fp=fopen("conftest_grp", "w"))) - exit(1); - fprintf(fp, "%d\n", sb.st_gid); - fclose(fp); - exit(0); -} - -_ACEOF -if ac_fn_c_try_run "$LINENO"; then : - - if test -f conftest_grp; then - vim_cv_tty_group=`cat conftest_grp` - if test "x$vim_cv_tty_mode" = "x" ; then - vim_cv_tty_mode=0620 - fi - { $as_echo "$as_me:${as_lineno-$LINENO}: result: pty mode: $vim_cv_tty_mode, group: $vim_cv_tty_group" >&5 -$as_echo "pty mode: $vim_cv_tty_mode, group: $vim_cv_tty_group" >&6; } - else - vim_cv_tty_group=world - { $as_echo "$as_me:${as_lineno-$LINENO}: result: ptys are world accessible" >&5 -$as_echo "ptys are world accessible" >&6; } - fi - -else - - vim_cv_tty_group=world - { $as_echo "$as_me:${as_lineno-$LINENO}: result: can't determine - assume ptys are world accessible" >&5 -$as_echo "can't determine - assume ptys are world accessible" >&6; } - -fi -rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ - conftest.$ac_objext conftest.beam conftest.$ac_ext -fi - - -fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $vim_cv_tty_group" >&5 -$as_echo "$vim_cv_tty_group" >&6; } -rm -f conftest_grp - -if test "x$vim_cv_tty_group" != "xworld" ; then - cat >>confdefs.h <<_ACEOF -#define PTYGROUP $vim_cv_tty_group -_ACEOF - - if test "x$vim_cv_tty_mode" = "x" ; then - as_fn_error $? "It seems you're cross compiling and have 'vim_cv_tty_group' set, please also set the environment variable 'vim_cv_tty_mode' to the correct mode (probably 0620)" "$LINENO" 5 - else - $as_echo "#define PTYMODE 0620" >>confdefs.h - - fi -fi - { $as_echo "$as_me:${as_lineno-$LINENO}: checking return type of signal handlers" >&5 $as_echo_n "checking return type of signal handlers... " >&6; } diff --git a/src/config.h.in b/src/config.h.in index 83549303f6..de53ffb030 100644 --- a/src/config.h.in +++ b/src/config.h.in @@ -126,12 +126,6 @@ #undef PTYRANGE0 #undef PTYRANGE1 -/* Define mode for pty */ -#undef PTYMODE - -/* Define group for pty */ -#undef PTYGROUP - /* Define as the return type of signal handlers (int or void). */ #undef RETSIGTYPE diff --git a/src/configure.ac b/src/configure.ac index 2037de74fa..687bdf95d2 100644 --- a/src/configure.ac +++ b/src/configure.ac @@ -3673,77 +3673,6 @@ else AC_MSG_RESULT([don't know]) fi -dnl **** pty mode/group handling **** -dnl -dnl support provided by Luke Mewburn <lm@rmit.edu.au>, 931222 -rm -f conftest_grp -AC_CACHE_CHECK([default tty permissions/group], [vim_cv_tty_group], - [ - AC_RUN_IFELSE([AC_LANG_SOURCE([[ -#include "confdefs.h" -#include <sys/types.h> -#if STDC_HEADERS -# include <stdlib.h> -# include <stddef.h> -#endif -#ifdef HAVE_UNISTD_H -#include <unistd.h> -#endif -#include <sys/stat.h> -#include <stdio.h> -main() -{ - struct stat sb; - char *x,*ttyname(); - int om, m; - FILE *fp; - - if (!(x = ttyname(0))) exit(1); - if (stat(x, &sb)) exit(1); - om = sb.st_mode; - if (om & 002) exit(0); - m = system("mesg y"); - if (m == -1 || m == 127) exit(1); - if (stat(x, &sb)) exit(1); - m = sb.st_mode; - if (chmod(x, om)) exit(1); - if (m & 002) exit(0); - if (sb.st_gid == getgid()) exit(1); - if (!(fp=fopen("conftest_grp", "w"))) - exit(1); - fprintf(fp, "%d\n", sb.st_gid); - fclose(fp); - exit(0); -} - ]])],[ - if test -f conftest_grp; then - vim_cv_tty_group=`cat conftest_grp` - if test "x$vim_cv_tty_mode" = "x" ; then - vim_cv_tty_mode=0620 - fi - AC_MSG_RESULT([pty mode: $vim_cv_tty_mode, group: $vim_cv_tty_group]) - else - vim_cv_tty_group=world - AC_MSG_RESULT([ptys are world accessible]) - fi - ],[ - vim_cv_tty_group=world - AC_MSG_RESULT([can't determine - assume ptys are world accessible]) - ],[ - AC_MSG_ERROR(cross-compiling: please set 'vim_cv_tty_group' and 'vim_cv_tty_mode') - ]) - ]) -rm -f conftest_grp - -if test "x$vim_cv_tty_group" != "xworld" ; then - AC_DEFINE_UNQUOTED(PTYGROUP,$vim_cv_tty_group) - if test "x$vim_cv_tty_mode" = "x" ; then - AC_MSG_ERROR([It seems you're cross compiling and have 'vim_cv_tty_group' set, please also set the environment variable 'vim_cv_tty_mode' to the correct mode (probably 0620)]) - else - AC_DEFINE(PTYMODE, 0620) - fi -fi - dnl Checks for library functions. =================================== AC_TYPE_SIGNAL diff --git a/src/version.c b/src/version.c index eb88916292..02f7b6ef6d 100644 --- a/src/version.c +++ b/src/version.c @@ -746,6 +746,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 680, /**/ 679, /**/ From 0b6849e9e302286e906d97e4ba017dd66561a9ce Mon Sep 17 00:00:00 2001 From: Bram Moolenaar <Bram@vim.org> Date: Sat, 2 May 2020 18:33:25 +0200 Subject: [PATCH 076/230] patch 8.2.0681: pattern for 'hlsearch' highlighting may leak Problem: Pattern for 'hlsearch' highlighting may leak. (Dominique Pelle) Solution: Call end_search_hl() to make sure the previous pattern is freed. (closes #6028) --- src/screen.c | 1 + src/version.c | 2 ++ 2 files changed, 3 insertions(+) diff --git a/src/screen.c b/src/screen.c index 09aa10f0bc..e218196fd7 100644 --- a/src/screen.c +++ b/src/screen.c @@ -1718,6 +1718,7 @@ start_search_hl(void) { if (p_hls && !no_hlsearch) { + end_search_hl(); // just in case it wasn't called before last_pat_prog(&screen_search_hl.rm); screen_search_hl.attr = HL_ATTR(HLF_L); # ifdef FEAT_RELTIME diff --git a/src/version.c b/src/version.c index 02f7b6ef6d..982ac1f887 100644 --- a/src/version.c +++ b/src/version.c @@ -746,6 +746,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 681, /**/ 680, /**/ From 1c0d44f8efae36c079cb8be395785827aa0b2737 Mon Sep 17 00:00:00 2001 From: Bram Moolenaar <Bram@vim.org> Date: Sat, 2 May 2020 19:04:58 +0200 Subject: [PATCH 077/230] patch 8.2.0682: Vim9: parsing function argument type can get stuck Problem: Vim9: parsing function argument type can get stuck. Solution: Bail out when not making progress. --- src/testdir/test_vim9_func.vim | 1 + src/version.c | 2 ++ src/vim9compile.c | 4 ++++ 3 files changed, 7 insertions(+) diff --git a/src/testdir/test_vim9_func.vim b/src/testdir/test_vim9_func.vim index 0fd28924a3..e1b3b7ffd6 100644 --- a/src/testdir/test_vim9_func.vim +++ b/src/testdir/test_vim9_func.vim @@ -113,6 +113,7 @@ def Test_call_wrong_args() call CheckDefFailure(['TakesOneArg()'], 'E119:') call CheckDefFailure(['TakesOneArg(11, 22)'], 'E118:') call CheckDefFailure(['bufnr(xxx)'], 'E1001:') + call CheckScriptFailure(['def Func(Ref: func(s: string))'], 'E475:') enddef " Default arg and varargs diff --git a/src/version.c b/src/version.c index 982ac1f887..21cda476a5 100644 --- a/src/version.c +++ b/src/version.c @@ -746,6 +746,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 682, /**/ 681, /**/ diff --git a/src/vim9compile.c b/src/vim9compile.c index 5644c50358..eb84e35909 100644 --- a/src/vim9compile.c +++ b/src/vim9compile.c @@ -1663,7 +1663,11 @@ skip_type(char_u *start) ++p; while (*p != ')' && *p != NUL) { + char_u *sp = p; + p = skip_type(p); + if (p == sp) + return p; // syntax error if (*p == ',') p = skipwhite(p + 1); } From 5adc55cb746893c6ddf7865ff654582902dee2e3 Mon Sep 17 00:00:00 2001 From: Bram Moolenaar <Bram@vim.org> Date: Sat, 2 May 2020 23:12:58 +0200 Subject: [PATCH 078/230] patch 8.2.0683: Vim9: parsing type does not always work Problem: Vim9: parsing type does not always work. Solution: Handle func type without return value. Test more closures. Fix type check offset. Fix garbage collection. --- src/proto/vim9execute.pro | 3 ++- src/testdir/test_vim9_func.vim | 44 ++++++++++++++++++++++++++++++++++ src/userfunc.c | 5 ++++ src/version.c | 2 ++ src/vim9compile.c | 11 ++++++--- src/vim9execute.c | 25 +++++++++++++++++-- 6 files changed, 84 insertions(+), 6 deletions(-) diff --git a/src/proto/vim9execute.pro b/src/proto/vim9execute.pro index 4f7262d741..578fe81e1b 100644 --- a/src/proto/vim9execute.pro +++ b/src/proto/vim9execute.pro @@ -1,6 +1,7 @@ /* vim9execute.c */ -int call_def_function(ufunc_T *ufunc, int argc, typval_T *argv, typval_T *rettv); +int call_def_function(ufunc_T *ufunc, int argc_arg, typval_T *argv, typval_T *rettv); void ex_disassemble(exarg_T *eap); int tv2bool(typval_T *tv); int check_not_string(typval_T *tv); +int set_ref_in_dfunc(ufunc_T *ufunc, int copyID); /* vim: set ft=c : */ diff --git a/src/testdir/test_vim9_func.vim b/src/testdir/test_vim9_func.vim index e1b3b7ffd6..a01e27c729 100644 --- a/src/testdir/test_vim9_func.vim +++ b/src/testdir/test_vim9_func.vim @@ -662,5 +662,49 @@ def Test_closure_ref_after_return() unlet g:Ref enddef +def MakeTwoRefs() + let local = ['some'] + g:Extend = {s -> local->add(s)} + g:Read = {-> local} +enddef + +def Test_closure_two_refs() + MakeTwoRefs() + assert_equal('some', join(g:Read(), ' ')) + g:Extend('more') + assert_equal('some more', join(g:Read(), ' ')) + g:Extend('even') + assert_equal('some more even', join(g:Read(), ' ')) + + unlet g:Extend + unlet g:Read +enddef + +" TODO: fix memory leak when using same function again. +def MakeTwoRefs_2() + let local = ['some'] + g:Extend = {s -> local->add(s)} + g:Read = {-> local} +enddef + +def ReadRef(Ref: func(): list<string>): string + return join(Ref(), ' ') +enddef + +def ExtendRef(Ref: func(string), add: string) + Ref(add) +enddef + +def Test_closure_two_indirect_refs() + MakeTwoRefs_2() + assert_equal('some', ReadRef(g:Read)) + ExtendRef(g:Extend, 'more') + assert_equal('some more', ReadRef(g:Read)) + ExtendRef(g:Extend, 'even') + assert_equal('some more even', ReadRef(g:Read)) + + unlet g:Extend + unlet g:Read +enddef " vim: ts=8 sw=2 sts=2 expandtab tw=80 fdm=marker diff --git a/src/userfunc.c b/src/userfunc.c index 2493dfea0c..6aee377953 100644 --- a/src/userfunc.c +++ b/src/userfunc.c @@ -4392,6 +4392,8 @@ set_ref_in_functions(int copyID) fp = HI2UF(hi); if (!func_name_refcount(fp->uf_name)) abort = abort || set_ref_in_func(NULL, fp, copyID); + else if (fp->uf_dfunc_idx >= 0) + abort = abort || set_ref_in_dfunc(fp, copyID); } } return abort; @@ -4439,7 +4441,10 @@ set_ref_in_func(char_u *name, ufunc_T *fp_in, int copyID) { for (fc = fp->uf_scoped; fc != NULL; fc = fc->func->uf_scoped) abort = abort || set_ref_in_funccal(fc, copyID); + if (fp->uf_dfunc_idx >= 0) + abort = abort || set_ref_in_dfunc(fp, copyID); } + vim_free(tofree); return abort; } diff --git a/src/version.c b/src/version.c index 21cda476a5..ae0855405c 100644 --- a/src/version.c +++ b/src/version.c @@ -746,6 +746,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 683, /**/ 682, /**/ diff --git a/src/vim9compile.c b/src/vim9compile.c index eb84e35909..a4a71de1f3 100644 --- a/src/vim9compile.c +++ b/src/vim9compile.c @@ -824,7 +824,7 @@ generate_TYPECHECK(cctx_T *cctx, type_T *vartype, int offset) isn->isn_arg.type.ct_off = offset; // type becomes vartype - ((type_T **)stack->ga_data)[stack->ga_len - 1] = vartype; + ((type_T **)stack->ga_data)[stack->ga_len + offset] = vartype; return OK; } @@ -1671,8 +1671,13 @@ skip_type(char_u *start) if (*p == ',') p = skipwhite(p + 1); } - if (*p == ')' && p[1] == ':') - p = skip_type(skipwhite(p + 2)); + if (*p == ')') + { + if (p[1] == ':') + p = skip_type(skipwhite(p + 2)); + else + p = skipwhite(p + 1); + } } return p; diff --git a/src/vim9execute.c b/src/vim9execute.c index c27bcf0ab2..2404282f8a 100644 --- a/src/vim9execute.c +++ b/src/vim9execute.c @@ -2437,11 +2437,12 @@ ex_disassemble(exarg_T *eap) break; case ISN_FUNCREF: { + funcref_T *funcref = &iptr->isn_arg.funcref; dfunc_T *df = ((dfunc_T *)def_functions.ga_data) - + iptr->isn_arg.funcref.fr_func; + + funcref->fr_func; smsg("%4d FUNCREF %s $%d", current, df->df_ufunc->uf_name, - iptr->isn_arg.funcref.fr_var_idx + df->df_varcount); + funcref->fr_var_idx + dfunc->df_varcount); } break; @@ -2675,5 +2676,25 @@ check_not_string(typval_T *tv) return OK; } +/* + * Mark items in a def function as used. + */ + int +set_ref_in_dfunc(ufunc_T *ufunc, int copyID) +{ + dfunc_T *dfunc = ((dfunc_T *)def_functions.ga_data) + ufunc->uf_dfunc_idx; + int abort = FALSE; + + if (dfunc->df_funcstack != NULL) + { + typval_T *stack = dfunc->df_funcstack->fs_ga.ga_data; + int idx; + + for (idx = 0; idx < dfunc->df_funcstack->fs_ga.ga_len; ++idx) + abort = abort || set_ref_in_item(stack + idx, copyID, NULL, NULL); + } + return abort; +} + #endif // FEAT_EVAL From f7779c63d4fe531e2483502d4441f24802342768 Mon Sep 17 00:00:00 2001 From: Bram Moolenaar <Bram@vim.org> Date: Sun, 3 May 2020 15:38:16 +0200 Subject: [PATCH 079/230] patch 8.2.0684: Vim9: memory leak when using lambda Problem: Vim9: memory leak when using lambda. Solution: Move the funccal context to the partial. Free the function when exiting. --- src/eval.c | 27 ++++++++++++++++ src/structs.h | 23 +++++++++++++ src/testdir/test_vim9_func.vim | 10 ++---- src/userfunc.c | 13 +++----- src/version.c | 2 ++ src/vim9.h | 20 ------------ src/vim9execute.c | 59 ++++++++++++++-------------------- 7 files changed, 83 insertions(+), 71 deletions(-) diff --git a/src/eval.c b/src/eval.c index 31dde2faed..72cb0897af 100644 --- a/src/eval.c +++ b/src/eval.c @@ -3703,6 +3703,24 @@ partial_free(partial_T *pt) } else func_ptr_unref(pt->pt_func); + + if (pt->pt_funcstack != NULL) + { + // Decrease the reference count for the context of a closure. If down + // to zero free it and clear the variables on the stack. + if (--pt->pt_funcstack->fs_refcount == 0) + { + garray_T *gap = &pt->pt_funcstack->fs_ga; + typval_T *stack = gap->ga_data; + + for (i = 0; i < gap->ga_len; ++i) + clear_tv(stack + i); + ga_clear(gap); + vim_free(pt->pt_funcstack); + } + pt->pt_funcstack = NULL; + } + vim_free(pt); } @@ -4336,6 +4354,15 @@ set_ref_in_item( for (i = 0; i < pt->pt_argc; ++i) abort = abort || set_ref_in_item(&pt->pt_argv[i], copyID, ht_stack, list_stack); + if (pt->pt_funcstack != NULL) + { + typval_T *stack = pt->pt_funcstack->fs_ga.ga_data; + + for (i = 0; i < pt->pt_funcstack->fs_ga.ga_len; ++i) + abort = abort || set_ref_in_item(stack + i, copyID, + ht_stack, list_stack); + } + } } #ifdef FEAT_JOB_CHANNEL diff --git a/src/structs.h b/src/structs.h index 601194e12f..7fd325a825 100644 --- a/src/structs.h +++ b/src/structs.h @@ -1777,6 +1777,21 @@ typedef struct { typval_T *basetv; // base for base->method() } funcexe_T; +/* + * Structure to hold the context of a compiled function, used by closures + * defined in that function. + */ +typedef struct funcstack_S +{ + garray_T fs_ga; // contains the stack, with: + // - arguments + // - frame + // - local variables + + int fs_refcount; // nr of closures referencing this funcstack + int fs_copyID; // for garray_T collection +} funcstack_T; + struct partial_S { int pt_refcount; // reference count @@ -1786,8 +1801,16 @@ struct partial_S // with pt_name int pt_auto; // when TRUE the partial was created for using // dict.member in handle_subscript() + + // For a compiled closure: the arguments and local variables. + garray_T *pt_ectx_stack; // where to find local vars + int pt_ectx_frame; // index of function frame in uf_ectx_stack + funcstack_T *pt_funcstack; // copy of stack, used after context + // function returns + int pt_argc; // number of arguments typval_T *pt_argv; // arguments in allocated array + dict_T *pt_dict; // dict for "self" }; diff --git a/src/testdir/test_vim9_func.vim b/src/testdir/test_vim9_func.vim index a01e27c729..fe47513ee9 100644 --- a/src/testdir/test_vim9_func.vim +++ b/src/testdir/test_vim9_func.vim @@ -680,13 +680,6 @@ def Test_closure_two_refs() unlet g:Read enddef -" TODO: fix memory leak when using same function again. -def MakeTwoRefs_2() - let local = ['some'] - g:Extend = {s -> local->add(s)} - g:Read = {-> local} -enddef - def ReadRef(Ref: func(): list<string>): string return join(Ref(), ' ') enddef @@ -696,7 +689,7 @@ def ExtendRef(Ref: func(string), add: string) enddef def Test_closure_two_indirect_refs() - MakeTwoRefs_2() + MakeTwoRefs() assert_equal('some', ReadRef(g:Read)) ExtendRef(g:Extend, 'more') assert_equal('some more', ReadRef(g:Read)) @@ -707,4 +700,5 @@ def Test_closure_two_indirect_refs() unlet g:Read enddef + " vim: ts=8 sw=2 sts=2 expandtab tw=80 fdm=marker diff --git a/src/userfunc.c b/src/userfunc.c index 6aee377953..4dac28126f 100644 --- a/src/userfunc.c +++ b/src/userfunc.c @@ -1016,16 +1016,17 @@ func_clear(ufunc_T *fp, int force) /* * Free a function and remove it from the list of functions. Does not free * what a function contains, call func_clear() first. + * When "force" is TRUE we are exiting. */ static void -func_free(ufunc_T *fp) +func_free(ufunc_T *fp, int force) { // Only remove it when not done already, otherwise we would remove a newer // version of the function with the same name. if ((fp->uf_flags & (FC_DELETED | FC_REMOVED)) == 0) func_remove(fp); - if ((fp->uf_flags & FC_DEAD) == 0) + if ((fp->uf_flags & FC_DEAD) == 0 || force) vim_free(fp); } @@ -1037,7 +1038,7 @@ func_free(ufunc_T *fp) func_clear_free(ufunc_T *fp, int force) { func_clear(fp, force); - func_free(fp); + func_free(fp, force); } @@ -1664,7 +1665,7 @@ free_all_functions(void) ++skipped; else { - func_free(fp); + func_free(fp, FALSE); skipped = 0; break; } @@ -4392,8 +4393,6 @@ set_ref_in_functions(int copyID) fp = HI2UF(hi); if (!func_name_refcount(fp->uf_name)) abort = abort || set_ref_in_func(NULL, fp, copyID); - else if (fp->uf_dfunc_idx >= 0) - abort = abort || set_ref_in_dfunc(fp, copyID); } } return abort; @@ -4441,8 +4440,6 @@ set_ref_in_func(char_u *name, ufunc_T *fp_in, int copyID) { for (fc = fp->uf_scoped; fc != NULL; fc = fc->func->uf_scoped) abort = abort || set_ref_in_funccal(fc, copyID); - if (fp->uf_dfunc_idx >= 0) - abort = abort || set_ref_in_dfunc(fp, copyID); } vim_free(tofree); diff --git a/src/version.c b/src/version.c index ae0855405c..2bccb328a8 100644 --- a/src/version.c +++ b/src/version.c @@ -746,6 +746,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 684, /**/ 683, /**/ diff --git a/src/vim9.h b/src/vim9.h index befa6a74c8..aac776af1c 100644 --- a/src/vim9.h +++ b/src/vim9.h @@ -259,21 +259,6 @@ struct isn_S { } isn_arg; }; -/* - * Structure to hold the context of a compiled function, used by closures - * defined in that function. - */ -typedef struct funcstack_S -{ - garray_T fs_ga; // contains the stack, with: - // - arguments - // - frame - // - local variables - - int fs_refcount; // nr of closures referencing this funcstack - int fs_copyID; // for garray_T collection -} funcstack_T; - /* * Info about a function defined with :def. Used in "def_functions". */ @@ -286,11 +271,6 @@ struct dfunc_S { isn_T *df_instr; // function body to be executed int df_instr_count; - garray_T *df_ectx_stack; // where compiled closure finds local vars - int df_ectx_frame; // index of function frame in uf_ectx_stack - funcstack_T *df_funcstack; // copy of stack for closure, used after - // closure context function returns - int df_varcount; // number of local variables int df_closure_count; // number of closures created }; diff --git a/src/vim9execute.c b/src/vim9execute.c index 2404282f8a..c74240ff20 100644 --- a/src/vim9execute.c +++ b/src/vim9execute.c @@ -232,10 +232,6 @@ call_dfunc(int cdf_idx, int argcount_arg, ectx_T *ectx) ectx->ec_instr = dfunc->df_instr; estack_push_ufunc(ETYPE_UFUNC, dfunc->df_ufunc, 1); - // used for closures - ectx->ec_outer_stack = dfunc->df_ectx_stack; - ectx->ec_outer_frame = dfunc->df_ectx_frame; - // Decide where to start execution, handles optional arguments. init_instr_idx(ufunc, argcount, ectx); @@ -269,7 +265,10 @@ handle_closure_in_use(ectx_T *ectx, int free_arguments) tv = STACK_TV(ectx->ec_frame_idx + STACK_FRAME_SIZE + dfunc->df_varcount + idx); if (tv->v_type == VAR_PARTIAL && tv->vval.v_partial->pt_refcount > 1) + { closure_in_use = TRUE; + break; + } } if (closure_in_use) @@ -315,15 +314,17 @@ handle_closure_in_use(ectx_T *ectx, int free_arguments) { tv = STACK_TV(ectx->ec_frame_idx + STACK_FRAME_SIZE + dfunc->df_varcount + idx); - if (tv->v_type == VAR_PARTIAL - && tv->vval.v_partial->pt_refcount > 1) + if (tv->v_type == VAR_PARTIAL) { - dfunc_T *pt_dfunc = ((dfunc_T *)def_functions.ga_data) - + tv->vval.v_partial->pt_func->uf_dfunc_idx; - ++funcstack->fs_refcount; - pt_dfunc->df_funcstack = funcstack; - pt_dfunc->df_ectx_stack = &funcstack->fs_ga; - pt_dfunc->df_ectx_frame = ectx->ec_frame_idx - top; + partial_T *partial = tv->vval.v_partial; + + if (partial->pt_refcount > 1) + { + ++funcstack->fs_refcount; + partial->pt_funcstack = funcstack; + partial->pt_ectx_stack = &funcstack->fs_ga; + partial->pt_ectx_frame = ectx->ec_frame_idx - top; + } } } } @@ -515,7 +516,15 @@ call_partial(typval_T *tv, int argcount, ectx_T *ectx) partial_T *pt = tv->vval.v_partial; if (pt->pt_func != NULL) - return call_ufunc(pt->pt_func, argcount, ectx, NULL); + { + int ret = call_ufunc(pt->pt_func, argcount, ectx, NULL); + + // closure may need the function context where it was defined + ectx->ec_outer_stack = pt->pt_ectx_stack; + ectx->ec_outer_frame = pt->pt_ectx_frame; + + return ret; + } name = pt->pt_name; } else if (tv->v_type == VAR_FUNC) @@ -1434,8 +1443,8 @@ call_def_function( // The closure needs to find arguments and local // variables in the current stack. - pt_dfunc->df_ectx_stack = &ectx.ec_stack; - pt_dfunc->df_ectx_frame = ectx.ec_frame_idx; + pt->pt_ectx_stack = &ectx.ec_stack; + pt->pt_ectx_frame = ectx.ec_frame_idx; // If this function returns and the closure is still // used, we need to make a copy of the context @@ -2676,25 +2685,5 @@ check_not_string(typval_T *tv) return OK; } -/* - * Mark items in a def function as used. - */ - int -set_ref_in_dfunc(ufunc_T *ufunc, int copyID) -{ - dfunc_T *dfunc = ((dfunc_T *)def_functions.ga_data) + ufunc->uf_dfunc_idx; - int abort = FALSE; - - if (dfunc->df_funcstack != NULL) - { - typval_T *stack = dfunc->df_funcstack->fs_ga.ga_data; - int idx; - - for (idx = 0; idx < dfunc->df_funcstack->fs_ga.ga_len; ++idx) - abort = abort || set_ref_in_item(stack + idx, copyID, NULL, NULL); - } - return abort; -} - #endif // FEAT_EVAL From 3df02f507f96a246366f96dcce156a0ae7b95611 Mon Sep 17 00:00:00 2001 From: Bram Moolenaar <Bram@vim.org> Date: Sun, 3 May 2020 15:47:33 +0200 Subject: [PATCH 080/230] patch 8.2.0685: Build failure Problem: Build failure. Solution: Include missing changes. --- src/version.c | 2 ++ src/vim9compile.c | 20 +++----------------- 2 files changed, 5 insertions(+), 17 deletions(-) diff --git a/src/version.c b/src/version.c index 2bccb328a8..105df760fb 100644 --- a/src/version.c +++ b/src/version.c @@ -746,6 +746,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 685, /**/ 684, /**/ diff --git a/src/vim9compile.c b/src/vim9compile.c index a4a71de1f3..c18cdc0a8a 100644 --- a/src/vim9compile.c +++ b/src/vim9compile.c @@ -3905,6 +3905,9 @@ compile_expr1(char_u **arg, cctx_T *cctx) { char_u *p; + // TODO: Try parsing as a constant. If that works just one PUSH + // instruction needs to be generated. + // evaluate the first expression if (compile_expr2(arg, cctx) == FAIL) return FAIL; @@ -6634,23 +6637,6 @@ delete_def_function_contents(dfunc_T *dfunc) delete_instr(dfunc->df_instr + idx); VIM_CLEAR(dfunc->df_instr); } - if (dfunc->df_funcstack != NULL) - { - // Decrease the reference count for the context of a closure. If down - // to zero free it and clear the variables on the stack. - if (--dfunc->df_funcstack->fs_refcount == 0) - { - garray_T *gap = &dfunc->df_funcstack->fs_ga; - typval_T *stack = gap->ga_data; - int i; - - for (i = 0; i < gap->ga_len; ++i) - clear_tv(stack + i); - ga_clear(gap); - vim_free(dfunc->df_funcstack); - } - dfunc->df_funcstack = NULL; - } dfunc->df_deleted = TRUE; } From 2eaeaf3c317a5145fb0bc926411561d50883019b Mon Sep 17 00:00:00 2001 From: Bram Moolenaar <Bram@vim.org> Date: Sun, 3 May 2020 16:04:43 +0200 Subject: [PATCH 081/230] patch 8.2.0686: formatoptions not sufficiently tested Problem: Formatoptions not sufficiently tested. Solution: Add a few more tests. (Yegappan Lakshmanan, closes #6031) --- src/testdir/test_normal.vim | 15 +++ src/testdir/test_textformat.vim | 192 ++++++++++++++++++++++++++++++++ src/version.c | 2 + 3 files changed, 209 insertions(+) diff --git a/src/testdir/test_normal.vim b/src/testdir/test_normal.vim index e75cb7183b..2975464d99 100644 --- a/src/testdir/test_normal.vim +++ b/src/testdir/test_normal.vim @@ -204,6 +204,21 @@ func Test_normal05_formatexpr_setopt() set formatexpr= endfunc +" When 'formatexpr' returns non-zero, internal formatting is used. +func Test_normal_formatexpr_returns_nonzero() + new + call setline(1, ['one', 'two']) + func! Format() + return 1 + endfunc + setlocal formatexpr=Format() + normal VGgq + call assert_equal(['one two'], getline(1, '$')) + setlocal formatexpr= + delfunc Format + close! +endfunc + " basic test for formatprg func Test_normal06_formatprg() " only test on non windows platform diff --git a/src/testdir/test_textformat.vim b/src/testdir/test_textformat.vim index 49c1f06d38..f4792b9544 100644 --- a/src/testdir/test_textformat.vim +++ b/src/testdir/test_textformat.vim @@ -1091,6 +1091,17 @@ func Test_fo_a_w() setlocal fo+=aw tw=10 call feedkeys("iabc abc a abc\<Esc>k0weade", 'xt') call assert_equal(['abc abcde ', 'a abc'], getline(1, '$')) + + " Test for 'a', 'w' and '1' options. + setlocal textwidth=0 + setlocal fo=1aw + %d + call setline(1, '. foo') + normal 72ig + call feedkeys('a uu uu uu', 'xt') + call assert_equal('g uu uu ', getline(1)[-8:]) + call assert_equal(['uu. foo'], getline(2, '$')) + %bw! endfunc @@ -1113,4 +1124,185 @@ func Test_fo_j() %bw! endfunc +" Test for formatting lines using gq in visual mode +func Test_visual_gq_format() + new + call setline(1, ['one two three four', 'five six', 'one two']) + setl textwidth=10 + call feedkeys('ggv$jj', 'xt') + redraw! + normal gq + %d + call setline(1, ['one two three four', 'five six', 'one two']) + normal G$ + call feedkeys('v0kk', 'xt') + redraw! + normal gq + setl textwidth& + close! +endfunc + +" Test for 'n' flag in 'formatoptions' to format numbered lists +func Test_fo_n() + new + setlocal autoindent + setlocal textwidth=12 + setlocal fo=n + call setline(1, [' 1) one two three four', ' 2) two']) + normal gggqG + call assert_equal([' 1) one two', ' three', ' four', ' 2) two'], + \ getline(1, '$')) + close! +endfunc + +" Test for 'formatlistpat' option +func Test_formatlistpat() + new + setlocal autoindent + setlocal textwidth=10 + setlocal fo=n + setlocal formatlistpat=^\\s*-\\s* + call setline(1, [' - one two three', ' - two']) + normal gggqG + call assert_equal([' - one', ' two', ' three', ' - two'], + \ getline(1, '$')) + close! +endfunc + +" Test for the 'b' and 'v' flags in 'formatoptions' +" Text should wrap only if a space character is inserted at or before +" 'textwidth' +func Test_fo_b() + new + setlocal textwidth=20 + + setlocal formatoptions=t + call setline(1, 'one two three four') + call feedkeys('Amore', 'xt') + call assert_equal(['one two three', 'fourmore'], getline(1, '$')) + + setlocal formatoptions=bt + %d + call setline(1, 'one two three four') + call feedkeys('Amore five', 'xt') + call assert_equal(['one two three fourmore five'], getline(1, '$')) + + setlocal formatoptions=bt + %d + call setline(1, 'one two three four') + call feedkeys('A five', 'xt') + call assert_equal(['one two three four', 'five'], getline(1, '$')) + + setlocal formatoptions=vt + %d + call setline(1, 'one two three four') + call feedkeys('Amore five', 'xt') + call assert_equal(['one two three fourmore', 'five'], getline(1, '$')) + + close! +endfunc + +" Test for the '1' flag in 'formatoptions'. Don't wrap text after a one letter +" word. +func Test_fo_1() + new + setlocal textwidth=20 + + setlocal formatoptions=t + call setline(1, 'one two three four') + call feedkeys('A a bird', 'xt') + call assert_equal(['one two three four a', 'bird'], getline(1, '$')) + + %d + setlocal formatoptions=t1 + call setline(1, 'one two three four') + call feedkeys('A a bird', 'xt') + call assert_equal(['one two three four', 'a bird'], getline(1, '$')) + + close! +endfunc + +" Test for 'l' flag in 'formatoptions'. When starting insert mode, if a line +" is longer than 'textwidth', then it is not broken. +func Test_fo_l() + new + setlocal textwidth=20 + + setlocal formatoptions=t + call setline(1, 'one two three four five') + call feedkeys('A six', 'xt') + call assert_equal(['one two three four', 'five six'], getline(1, '$')) + + %d + setlocal formatoptions=tl + call setline(1, 'one two three four five') + call feedkeys('A six', 'xt') + call assert_equal(['one two three four five six'], getline(1, '$')) + + close! +endfunc + +" Test for the '2' flag in 'formatoptions' +func Test_fo_2() + new + setlocal autoindent + setlocal formatoptions=t2 + setlocal textwidth=30 + call setline(1, ["\tfirst line of a paragraph.", + \ "second line of the same paragraph.", + \ "third line."]) + normal gggqG + call assert_equal(["\tfirst line of a", + \ "paragraph. second line of the", + \ "same paragraph. third line."], getline(1, '$')) + close! +endfunc + +" Test for formatting lines where only the first line has a comment. +func Test_fo_gq_with_firstline_comment() + new + setlocal formatoptions=tcq + call setline(1, ['- one two', 'three']) + normal gggqG + call assert_equal(['- one two three'], getline(1, '$')) + + %d + call setline(1, ['- one', '- two']) + normal gggqG + call assert_equal(['- one', '- two'], getline(1, '$')) + close! +endfunc + +" Test for trying to join a comment line with a non-comment line +func Test_join_comments() + new + call setline(1, ['one', '/* two */', 'three']) + normal gggqG + call assert_equal(['one', '/* two */', 'three'], getline(1, '$')) + close! +endfunc + +" Test for using 'a' in 'formatoptions' with comments +func Test_autoformat_comments() + new + setlocal formatoptions+=a + call feedkeys("a- one\n- two\n", 'xt') + call assert_equal(['- one', '- two', ''], getline(1, '$')) + + %d + call feedkeys("a\none\n", 'xt') + call assert_equal(['', 'one', ''], getline(1, '$')) + + setlocal formatoptions+=aw + %d + call feedkeys("aone \ntwo\n", 'xt') + call assert_equal(['one two', ''], getline(1, '$')) + + %d + call feedkeys("aone\ntwo\n", 'xt') + call assert_equal(['one', 'two', ''], getline(1, '$')) + + close! +endfunc + " vim: shiftwidth=2 sts=2 expandtab diff --git a/src/version.c b/src/version.c index 105df760fb..d35cbab3a1 100644 --- a/src/version.c +++ b/src/version.c @@ -746,6 +746,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 686, /**/ 685, /**/ From 41d4299f26cc98e253f9c63f8adc9dbb9d49ed5c Mon Sep 17 00:00:00 2001 From: Bram Moolenaar <Bram@vim.org> Date: Sun, 3 May 2020 16:29:50 +0200 Subject: [PATCH 082/230] patch 8.2.0687: some tests do not work on FreeBSD Problem: Some tests do not work on FreeBSD. Solution: Enable modeline. Use WaitFor() in more cases. (Ozaki Kiichi, closes #6036) --- src/testdir/test_quickfix.vim | 2 +- src/testdir/test_terminal.vim | 18 ++++++++++-------- src/version.c | 2 ++ 3 files changed, 13 insertions(+), 9 deletions(-) diff --git a/src/testdir/test_quickfix.vim b/src/testdir/test_quickfix.vim index 71a0f15ba9..11bdfbefa3 100644 --- a/src/testdir/test_quickfix.vim +++ b/src/testdir/test_quickfix.vim @@ -1708,7 +1708,6 @@ func s:create_test_file(filename) endfunc func Test_switchbuf() - CheckNotBSD call s:create_test_file('Xqftestfile1') call s:create_test_file('Xqftestfile2') call s:create_test_file('Xqftestfile3') @@ -1834,6 +1833,7 @@ func Test_switchbuf() " If opening a file changes 'switchbuf', then the new value should be " retained. + set modeline&vim call writefile(["vim: switchbuf=split"], 'Xqftestfile1') enew | only set switchbuf&vim diff --git a/src/testdir/test_terminal.vim b/src/testdir/test_terminal.vim index 49bce73755..f7b12e376a 100644 --- a/src/testdir/test_terminal.vim +++ b/src/testdir/test_terminal.vim @@ -894,7 +894,6 @@ func Test_terminal_wqall() endfunc func Test_terminal_composing_unicode() - CheckNotBSD let save_enc = &encoding set encoding=utf-8 @@ -909,7 +908,7 @@ func Test_terminal_composing_unicode() enew let buf = term_start(cmd, {'curwin': bufnr('')}) let g:job = term_getjob(buf) - call TermWait(buf, 25) + call WaitFor({-> term_getline(buf, 1) !=# ''}, 1000) if has('win32') call assert_equal('cmd', job_info(g:job).cmd[0]) @@ -919,10 +918,11 @@ func Test_terminal_composing_unicode() " ascii + composing let txt = "a\u0308bc" - call term_sendkeys(buf, "echo " . txt . "\r") + call term_sendkeys(buf, "echo " . txt) call TermWait(buf, 25) call assert_match("echo " . txt, term_getline(buf, lnum[0])) - call assert_equal(txt, term_getline(buf, lnum[0] + 1)) + call term_sendkeys(buf, "\<cr>") + call WaitForAssert({-> assert_equal(txt, term_getline(buf, lnum[0] + 1))}, 1000) let l = term_scrape(buf, lnum[0] + 1) call assert_equal("a\u0308", l[0].chars) call assert_equal("b", l[1].chars) @@ -930,10 +930,11 @@ func Test_terminal_composing_unicode() " multibyte + composing let txt = "\u304b\u3099\u304e\u304f\u3099\u3052\u3053\u3099" - call term_sendkeys(buf, "echo " . txt . "\r") + call term_sendkeys(buf, "echo " . txt) call TermWait(buf, 25) call assert_match("echo " . txt, term_getline(buf, lnum[1])) - call assert_equal(txt, term_getline(buf, lnum[1] + 1)) + call term_sendkeys(buf, "\<cr>") + call WaitForAssert({-> assert_equal(txt, term_getline(buf, lnum[1] + 1))}, 1000) let l = term_scrape(buf, lnum[1] + 1) call assert_equal("\u304b\u3099", l[0].chars) call assert_equal("\u304e", l[1].chars) @@ -943,10 +944,11 @@ func Test_terminal_composing_unicode() " \u00a0 + composing let txt = "abc\u00a0\u0308" - call term_sendkeys(buf, "echo " . txt . "\r") + call term_sendkeys(buf, "echo " . txt) call TermWait(buf, 25) call assert_match("echo " . txt, term_getline(buf, lnum[2])) - call assert_equal(txt, term_getline(buf, lnum[2] + 1)) + call term_sendkeys(buf, "\<cr>") + call WaitForAssert({-> assert_equal(txt, term_getline(buf, lnum[2] + 1))}, 1000) let l = term_scrape(buf, lnum[2] + 1) call assert_equal("\u00a0\u0308", l[3].chars) diff --git a/src/version.c b/src/version.c index d35cbab3a1..74fabce675 100644 --- a/src/version.c +++ b/src/version.c @@ -746,6 +746,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 687, /**/ 686, /**/ From 647a530b33d9d767f591159c24c62de48e57dad7 Mon Sep 17 00:00:00 2001 From: Bram Moolenaar <Bram@vim.org> Date: Sun, 3 May 2020 17:01:24 +0200 Subject: [PATCH 083/230] patch 8.2.0688: output clobbered if setting 'verbose' to see shell commands Problem: Output clobbered if setting 'verbose' to see shell commands. Solution: Only output "Searching for" when 'verbose' is 11 or higher. --- runtime/doc/options.txt | 2 ++ src/scriptfile.c | 4 ++-- src/version.c | 2 ++ 3 files changed, 6 insertions(+), 2 deletions(-) diff --git a/runtime/doc/options.txt b/runtime/doc/options.txt index baccd25d23..c29ff5ea40 100644 --- a/runtime/doc/options.txt +++ b/runtime/doc/options.txt @@ -8323,9 +8323,11 @@ A jump table for the options with a short description can be found at |Q_op|. Currently, these messages are given: >= 1 When the viminfo file is read or written. >= 2 When a file is ":source"'ed. + >= 4 Shell commands. >= 5 Every searched tags file and include file. >= 8 Files for which a group of autocommands is executed. >= 9 Every executed autocommand. + >= 11 Finding items in a path >= 12 Every executed function. >= 13 When an exception is thrown, caught, finished, or discarded. >= 14 Anything pending in a ":finally" clause. diff --git a/src/scriptfile.c b/src/scriptfile.c index 0756116b10..155ab14bb7 100644 --- a/src/scriptfile.c +++ b/src/scriptfile.c @@ -228,7 +228,7 @@ do_in_path( buf = alloc(MAXPATHL); if (buf != NULL && rtp_copy != NULL) { - if (p_verbose > 1 && name != NULL) + if (p_verbose > 10 && name != NULL) { verbose_enter(); smsg(_("Searching for \"%s\" in \"%s\""), @@ -276,7 +276,7 @@ do_in_path( copy_option_part(&np, tail, (int)(MAXPATHL - (tail - buf)), "\t "); - if (p_verbose > 2) + if (p_verbose > 10) { verbose_enter(); smsg(_("Searching for \"%s\""), buf); diff --git a/src/version.c b/src/version.c index 74fabce675..fcc897a0f5 100644 --- a/src/version.c +++ b/src/version.c @@ -746,6 +746,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 688, /**/ 687, /**/ From a38b2b737e244eb2e4f199e070b05f86f4d433d4 Mon Sep 17 00:00:00 2001 From: Bram Moolenaar <Bram@vim.org> Date: Sun, 3 May 2020 17:03:29 +0200 Subject: [PATCH 084/230] patch 8.2.0689: when using getaddrinfo() the error message is unclear Problem: When using getaddrinfo() the error message is unclear. Solution: Use gai_strerror() to get the message. (Ozaki Kiichi, closes #6034) --- src/channel.c | 6 ++++-- src/version.c | 2 ++ 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/src/channel.c b/src/channel.c index 9577f3dc46..68ac4bc299 100644 --- a/src/channel.c +++ b/src/channel.c @@ -955,6 +955,7 @@ channel_open( int sd = -1; channel_T *channel = NULL; #ifdef FEAT_IPV6 + int err; struct addrinfo hints; struct addrinfo *res = NULL; struct addrinfo *addr = NULL; @@ -986,10 +987,11 @@ channel_open( // Set port number manually in order to prevent name resolution services // from being invoked in the environment where AI_NUMERICSERV is not // defined. - if (getaddrinfo(hostname, NULL, &hints, &res) != 0) + if ((err = getaddrinfo(hostname, NULL, &hints, &res)) != 0) { ch_error(channel, "in getaddrinfo() in channel_open()"); - PERROR(_("E901: getaddrinfo() in channel_open()")); + semsg(_("E901: getaddrinfo() in channel_open(): %s"), + gai_strerror(err)); channel_free(channel); return NULL; } diff --git a/src/version.c b/src/version.c index fcc897a0f5..c083372006 100644 --- a/src/version.c +++ b/src/version.c @@ -746,6 +746,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 689, /**/ 688, /**/ From 5125874951669944a5f6a4163d6e5d437ae6321e Mon Sep 17 00:00:00 2001 From: Bram Moolenaar <Bram@vim.org> Date: Sun, 3 May 2020 17:19:33 +0200 Subject: [PATCH 085/230] patch 8.2.0690: line number of option set by modeline is wrong Problem: Line number of option set by modeline is wrong. Solution: Do not double the line number. (Ozaki Kiichi, closes #6035) --- src/option.c | 4 ++- src/testdir/test_modeline.vim | 56 +++++++++++++++++++++++++++++++++++ src/version.c | 2 ++ 3 files changed, 61 insertions(+), 1 deletion(-) diff --git a/src/option.c b/src/option.c index 3f97c3cd15..8574f7f7cb 100644 --- a/src/option.c +++ b/src/option.c @@ -2460,7 +2460,9 @@ set_option_sctx_idx(int opt_idx, int opt_flags, sctx_T script_ctx) int indir = (int)options[opt_idx].indir; sctx_T new_script_ctx = script_ctx; - new_script_ctx.sc_lnum += SOURCING_LNUM; + // Modeline already has the line number set. + if (!(opt_flags & OPT_MODELINE)) + new_script_ctx.sc_lnum += SOURCING_LNUM; // Remember where the option was set. For local options need to do that // in the buffer or window structure. diff --git a/src/testdir/test_modeline.vim b/src/testdir/test_modeline.vim index 05a1460198..546c30c668 100644 --- a/src/testdir/test_modeline.vim +++ b/src/testdir/test_modeline.vim @@ -279,3 +279,59 @@ func Test_modeline_fails_modelineexpr() call s:modeline_fails('tabline', 'tabline=Something()', 'E992:') call s:modeline_fails('titlestring', 'titlestring=Something()', 'E992:') endfunc + +func Test_modeline_setoption_verbose() + let modeline = &modeline + set modeline + + let lines =<< trim END + 1 vim:ts=2 + 2 two + 3 three + 4 four + 5 five + 6 six + 7 seven + 8 eight + END + call writefile(lines, 'Xmodeline') + edit Xmodeline + let info = split(execute('verbose set tabstop?'), "\n") + call assert_match('^\s*Last set from modeline line 1$', info[-1]) + bwipe! + + let lines =<< trim END + 1 one + 2 two + 3 three + 4 vim:ts=4 + 5 five + 6 six + 7 seven + 8 eight + END + call writefile(lines, 'Xmodeline') + edit Xmodeline + let info = split(execute('verbose set tabstop?'), "\n") + call assert_match('^\s*Last set from modeline line 4$', info[-1]) + bwipe! + + let lines =<< trim END + 1 one + 2 two + 3 three + 4 four + 5 five + 6 six + 7 seven + 8 vim:ts=8 + END + call writefile(lines, 'Xmodeline') + edit Xmodeline + let info = split(execute('verbose set tabstop?'), "\n") + call assert_match('^\s*Last set from modeline line 8$', info[-1]) + bwipe! + + let &modeline = modeline + call delete('Xmodeline') +endfunc diff --git a/src/version.c b/src/version.c index c083372006..6dc86b9643 100644 --- a/src/version.c +++ b/src/version.c @@ -746,6 +746,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 690, /**/ 689, /**/ From 7779ee30d912e9dd5bd2371f8b27057bd249d53c Mon Sep 17 00:00:00 2001 From: Bram Moolenaar <Bram@vim.org> Date: Sun, 3 May 2020 17:55:32 +0200 Subject: [PATCH 086/230] patch 8.2.0691: startup test fails Problem: Startup test fails. Solution: Adjust expected output from -V2 argument. --- src/testdir/test_startup.vim | 2 +- src/version.c | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/src/testdir/test_startup.vim b/src/testdir/test_startup.vim index 5eff1bdf35..ff3510ef6a 100644 --- a/src/testdir/test_startup.vim +++ b/src/testdir/test_startup.vim @@ -274,7 +274,7 @@ func Test_V_arg() call assert_equal(" verbose=0\n", out) let out = system(GetVimCommand() . ' --clean -es -X -V2 -c "set verbose?" -cq') - call assert_match("sourcing \"$VIMRUNTIME[\\/]defaults\.vim\"\r\nSearching for \"filetype\.vim\".*\n", out) + call assert_match("sourcing \"$VIMRUNTIME[\\/]defaults\.vim\"\r\nline \\d\\+: sourcing \"[\\./]*runtime[\\/]filetype\.vim\".*\n", out) call assert_match(" verbose=2\n", out) let out = system(GetVimCommand() . ' --clean -es -X -V15 -c "set verbose?" -cq') diff --git a/src/version.c b/src/version.c index 6dc86b9643..abfade87d0 100644 --- a/src/version.c +++ b/src/version.c @@ -746,6 +746,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 691, /**/ 690, /**/ From 4515bcdec8f3ba54f9d671cc37b9c9b3e19ea999 Mon Sep 17 00:00:00 2001 From: Bram Moolenaar <Bram@vim.org> Date: Sun, 3 May 2020 18:21:04 +0200 Subject: [PATCH 087/230] patch 8.2.0692: startup test fails on MS-Windows Problem: Startup test fails on MS-Windows. Solution: Allow for any path. --- src/testdir/test_startup.vim | 2 +- src/version.c | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/src/testdir/test_startup.vim b/src/testdir/test_startup.vim index ff3510ef6a..fe93eabc54 100644 --- a/src/testdir/test_startup.vim +++ b/src/testdir/test_startup.vim @@ -274,7 +274,7 @@ func Test_V_arg() call assert_equal(" verbose=0\n", out) let out = system(GetVimCommand() . ' --clean -es -X -V2 -c "set verbose?" -cq') - call assert_match("sourcing \"$VIMRUNTIME[\\/]defaults\.vim\"\r\nline \\d\\+: sourcing \"[\\./]*runtime[\\/]filetype\.vim\".*\n", out) + call assert_match("sourcing \"$VIMRUNTIME[\\/]defaults\.vim\"\r\nline \\d\\+: sourcing \"[^\"]*runtime[\\/]filetype\.vim\".*\n", out) call assert_match(" verbose=2\n", out) let out = system(GetVimCommand() . ' --clean -es -X -V15 -c "set verbose?" -cq') diff --git a/src/version.c b/src/version.c index abfade87d0..f87cc8bda6 100644 --- a/src/version.c +++ b/src/version.c @@ -746,6 +746,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 692, /**/ 691, /**/ From 2fd4cd755c3e87e733b7363ac13e5c0fe0297a80 Mon Sep 17 00:00:00 2001 From: Bram Moolenaar <Bram@vim.org> Date: Sun, 3 May 2020 22:30:49 +0200 Subject: [PATCH 088/230] patch 8.2.0693: closure using argument not tested Problem: Closure using argument not tested. Solution: Add a test, make it work. --- src/testdir/test_vim9_func.vim | 21 ++++++++ src/version.c | 2 + src/vim9compile.c | 97 +++++++++++++++++++++------------- 3 files changed, 82 insertions(+), 38 deletions(-) diff --git a/src/testdir/test_vim9_func.vim b/src/testdir/test_vim9_func.vim index fe47513ee9..c06cc2304b 100644 --- a/src/testdir/test_vim9_func.vim +++ b/src/testdir/test_vim9_func.vim @@ -700,5 +700,26 @@ def Test_closure_two_indirect_refs() unlet g:Read enddef +def MakeArgRefs(theArg: string) + let local = 'loc_val' + g:UseArg = {s -> theArg .. '/' .. local .. '/' .. s} +enddef + +def MakeArgRefsVarargs(theArg: string, ...rest: list<string>) + let local = 'the_loc' + g:UseVararg = {s -> theArg .. '/' .. local .. '/' .. s .. '/' .. join(rest)} +enddef + +def Test_closure_using_argument() + MakeArgRefs('arg_val') + assert_equal('arg_val/loc_val/call_val', g:UseArg('call_val')) + + MakeArgRefsVarargs('arg_val', 'one', 'two') + assert_equal('arg_val/the_loc/call_val/one two', g:UseVararg('call_val')) + + unlet g:UseArg + unlet g:UseVararg +enddef + " vim: ts=8 sw=2 sts=2 expandtab tw=80 fdm=marker diff --git a/src/version.c b/src/version.c index f87cc8bda6..10f4efdf3f 100644 --- a/src/version.c +++ b/src/version.c @@ -746,6 +746,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 693, /**/ 692, /**/ diff --git a/src/vim9compile.c b/src/vim9compile.c index c18cdc0a8a..300adfbec5 100644 --- a/src/vim9compile.c +++ b/src/vim9compile.c @@ -186,37 +186,74 @@ lookup_local(char_u *name, size_t len, cctx_T *cctx) } /* - * Lookup an argument in the current function. - * Returns the argument index or -1 if not found. + * Lookup an argument in the current function and an enclosing function. + * Returns the argument index in "idxp" + * Returns the argument type in "type" + * Sets "gen_load_outer" to TRUE if found in outer scope. + * Returns OK when found, FAIL otherwise. */ static int -lookup_arg(char_u *name, size_t len, cctx_T *cctx) +lookup_arg( + char_u *name, + size_t len, + int *idxp, + type_T **type, + int *gen_load_outer, + cctx_T *cctx) { int idx; + char_u *va_name; if (len == 0) - return -1; + return FAIL; for (idx = 0; idx < cctx->ctx_ufunc->uf_args.ga_len; ++idx) { char_u *arg = FUNCARG(cctx->ctx_ufunc, idx); - if (STRNCMP(name, arg, len) == 0 && STRLEN(arg) == len) - return idx; + if (STRNCMP(name, arg, len) == 0 && arg[len] == NUL) + { + if (idxp != NULL) + { + // Arguments are located above the frame pointer. One further + // if there is a vararg argument + *idxp = idx - (cctx->ctx_ufunc->uf_args.ga_len + + STACK_FRAME_SIZE) + + (cctx->ctx_ufunc->uf_va_name != NULL ? -1 : 0); + + if (cctx->ctx_ufunc->uf_arg_types != NULL) + *type = cctx->ctx_ufunc->uf_arg_types[idx]; + else + *type = &t_any; + } + return OK; + } } - return -1; -} -/* - * Lookup a vararg argument in the current function. - * Returns TRUE if there is a match. - */ - static int -lookup_vararg(char_u *name, size_t len, cctx_T *cctx) -{ - char_u *va_name = cctx->ctx_ufunc->uf_va_name; + va_name = cctx->ctx_ufunc->uf_va_name; + if (va_name != NULL + && STRNCMP(name, va_name, len) == 0 && va_name[len] == NUL) + { + if (idxp != NULL) + { + // varargs is always the last argument + *idxp = -STACK_FRAME_SIZE - 1; + *type = cctx->ctx_ufunc->uf_va_type; + } + return OK; + } - return len > 0 && va_name != NULL - && STRNCMP(name, va_name, len) == 0 && STRLEN(va_name) == len; + if (cctx->ctx_outer != NULL) + { + // Lookup the name for an argument of the outer function. + if (lookup_arg(name, len, idxp, type, gen_load_outer, cctx->ctx_outer) + == OK) + { + *gen_load_outer = TRUE; + return OK; + } + } + + return FAIL; } /* @@ -1584,7 +1621,7 @@ reserve_local(cctx_T *cctx, char_u *name, size_t len, int isConst, type_T *type) { lvar_T *lvar; - if (lookup_arg(name, len, cctx) >= 0 || lookup_vararg(name, len, cctx)) + if (lookup_arg(name, len, NULL, NULL, NULL, cctx) == OK) { emsg_namelen(_("E1006: %s is used as an argument"), name, (int)len); return NULL; @@ -2452,26 +2489,10 @@ compile_load(char_u **arg, char_u *end_arg, cctx_T *cctx, int error) if (name == NULL) return FAIL; - idx = lookup_arg(*arg, len, cctx); - if (idx >= 0) + if (lookup_arg(*arg, len, &idx, &type, &gen_load_outer, cctx) == OK) { - if (cctx->ctx_ufunc->uf_arg_types != NULL) - type = cctx->ctx_ufunc->uf_arg_types[idx]; - else - type = &t_any; - - // Arguments are located above the frame pointer. - idx -= cctx->ctx_ufunc->uf_args.ga_len + STACK_FRAME_SIZE; - if (cctx->ctx_ufunc->uf_va_name != NULL) - --idx; - gen_load = TRUE; - } - else if (lookup_vararg(*arg, len, cctx)) - { - // varargs is always the last argument - idx = -STACK_FRAME_SIZE - 1; - type = cctx->ctx_ufunc->uf_va_type; - gen_load = TRUE; + if (!gen_load_outer) + gen_load = TRUE; } else { From 80a8d3889bf1341c47f1c88c59825f183b2b4753 Mon Sep 17 00:00:00 2001 From: Bram Moolenaar <Bram@vim.org> Date: Sun, 3 May 2020 22:57:32 +0200 Subject: [PATCH 089/230] patch 8.2.0694: Haiku: channel and terminal do not work Problem: Haiku: channel and terminal do not work. Solution: Close files when the job has finished. (Ozaki Kiichi, closes #6039) --- src/channel.c | 32 ++++++++++++++++++++++++++++++-- src/getchar.c | 2 +- src/gui_haiku.cc | 43 ++++++++++++++++++++++++++++++++++--------- src/misc1.c | 26 ++++++++++++++------------ src/version.c | 2 ++ 5 files changed, 81 insertions(+), 24 deletions(-) diff --git a/src/channel.c b/src/channel.c index 68ac4bc299..2234ad5d57 100644 --- a/src/channel.c +++ b/src/channel.c @@ -3940,7 +3940,7 @@ theend: free_job_options(&opt); } -# if defined(MSWIN) || defined(FEAT_GUI) || defined(PROTO) +#if defined(MSWIN) || defined(__HAIKU__) || defined(FEAT_GUI) || defined(PROTO) /* * Check the channels for anything that is ready to be read. * The data is put in the read queue. @@ -3973,9 +3973,23 @@ channel_handle_events(int only_keep_open) "channel_handle_events"); } } + +# ifdef __HAIKU__ + // Workaround for Haiku: Since select/poll cannot detect EOF from tty, + // should close fds when the job has finished if 'channel' connects to + // the pty. + if (channel->ch_job != NULL) + { + job_T *job = channel->ch_job; + + if (job->jv_tty_out != NULL && job->jv_status == JOB_FINISHED) + for (part = PART_SOCK; part < PART_COUNT; ++part) + ch_close_part(channel, part); + } +# endif } } -# endif +#endif # if defined(FEAT_GUI) || defined(PROTO) /* @@ -4541,6 +4555,20 @@ channel_select_check(int ret_in, void *rfds_in, void *wfds_in) channel_write_input(channel); --ret; } + +# ifdef __HAIKU__ + // Workaround for Haiku: Since select/poll cannot detect EOF from tty, + // should close fds when the job has finished if 'channel' connects to + // the pty. + if (channel->ch_job != NULL) + { + job_T *job = channel->ch_job; + + if (job->jv_tty_out != NULL && job->jv_status == JOB_FINISHED) + for (part = PART_SOCK; part < PART_COUNT; ++part) + ch_close_part(channel, part); + } +# endif } return ret; diff --git a/src/getchar.c b/src/getchar.c index 9d8c0d4bff..8b417ecd19 100644 --- a/src/getchar.c +++ b/src/getchar.c @@ -2147,7 +2147,7 @@ parse_queued_messages(void) for (i = 0; i < MAX_REPEAT_PARSE; ++i) { // For Win32 mch_breakcheck() does not check for input, do it here. -# if defined(MSWIN) && defined(FEAT_JOB_CHANNEL) +# if (defined(MSWIN) || defined(__HAIKU__)) && defined(FEAT_JOB_CHANNEL) channel_handle_events(FALSE); # endif diff --git a/src/gui_haiku.cc b/src/gui_haiku.cc index ff460adf29..78ca7b27ad 100644 --- a/src/gui_haiku.cc +++ b/src/gui_haiku.cc @@ -1145,10 +1145,11 @@ VimFormView::FrameResized(float new_width, float new_height) VimTextAreaView::VimTextAreaView(BRect frame): BView(frame, "VimTextAreaView", B_FOLLOW_ALL_SIDES, #ifdef FEAT_MBYTE_IME - B_WILL_DRAW | B_FULL_UPDATE_ON_RESIZE | B_INPUT_METHOD_AWARE), + B_WILL_DRAW | B_FULL_UPDATE_ON_RESIZE | B_INPUT_METHOD_AWARE #else - B_WILL_DRAW | B_FULL_UPDATE_ON_RESIZE), + B_WILL_DRAW | B_FULL_UPDATE_ON_RESIZE #endif + ), mouseDragEventCount(0) { #ifdef FEAT_MBYTE_IME @@ -3093,7 +3094,7 @@ gui_haiku_process_event(bigtime_t timeout) } } #else - add_to_input_buf_csi(string, len); + add_to_input_buf_csi(string, len); #endif else add_to_input_buf(string, len); @@ -4437,15 +4438,16 @@ gui_mch_wait_for_chars( int wtime) { int focus; - bigtime_t until, timeout; - status_t st; + bigtime_t until, timeout; + status_t st; - if (wtime >= 0) { + if (wtime >= 0) + { timeout = wtime * 1000; until = system_time() + timeout; - } else { - timeout = B_INFINITE_TIMEOUT; } + else + timeout = B_INFINITE_TIMEOUT; focus = gui.in_focus; for (;;) @@ -4461,6 +4463,28 @@ gui_mch_wait_for_chars( } gui_mch_flush(); + +#ifdef MESSAGE_QUEUE +# ifdef FEAT_TIMERS + did_add_timer = FALSE; +# endif + parse_queued_messages(); +# ifdef FEAT_TIMERS + if (did_add_timer) + // Need to recompute the waiting time. + break; +# endif +# ifdef FEAT_JOB_CHANNEL + if (has_any_channel()) + { + if (wtime < 0 || timeout > 20000) + timeout = 20000; + } + else if (wtime < 0) + timeout = B_INFINITE_TIMEOUT; +# endif +#endif + /* * Don't use gui_mch_update() because then we will spin-lock until a * char arrives, instead we use gui_haiku_process_event() to hang until @@ -4478,7 +4502,8 @@ gui_mch_wait_for_chars( * Calculate how much longer we're willing to wait for the * next event. */ - if (wtime >= 0) { + if (wtime >= 0) + { timeout = until - system_time(); if (timeout < 0) break; diff --git a/src/misc1.c b/src/misc1.c index 92aa82fc42..6686a35146 100644 --- a/src/misc1.c +++ b/src/misc1.c @@ -1666,23 +1666,25 @@ vim_getenv(char_u *name, int *mustfree) if (p != NULL) return p; + +# ifdef __HAIKU__ + // special handling for user settings directory... + if (STRCMP(name, "BE_USER_SETTINGS") == 0) + { + static char userSettingsPath[MAXPATHL]; + + if (find_directory(B_USER_SETTINGS_DIRECTORY, 0, false, + userSettingsPath, MAXPATHL) == B_OK) + return (char_u *)userSettingsPath; + else + return NULL; + } +# endif #endif // handling $VIMRUNTIME and $VIM is below, bail out if it's another name. vimruntime = (STRCMP(name, "VIMRUNTIME") == 0); if (!vimruntime && STRCMP(name, "VIM") != 0) -#if defined(__HAIKU__) - // special handling for user settings directory... - if (STRCMP(name, "BE_USER_SETTINGS") == 0) - { - static char userSettingsPath[MAXPATHL] = {0}; - - if (B_OK == find_directory(B_USER_SETTINGS_DIRECTORY, 0, - false, userSettingsPath, MAXPATHL)) - return userSettingsPath; - } - else -#endif return NULL; /* diff --git a/src/version.c b/src/version.c index 10f4efdf3f..982170eb8f 100644 --- a/src/version.c +++ b/src/version.c @@ -746,6 +746,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 694, /**/ 693, /**/ From 04b12697838b232b8b17c553ccc74cf1f1bdb81c Mon Sep 17 00:00:00 2001 From: Bram Moolenaar <Bram@vim.org> Date: Mon, 4 May 2020 23:24:44 +0200 Subject: [PATCH 090/230] patch 8.2.0695: Vim9: cannot define a function inside a function Problem: Vim9: cannot define a function inside a function. Solution: Initial support for :def inside :def. --- src/proto/userfunc.pro | 2 + src/testdir/test_vim9_func.vim | 35 ++++++----- src/userfunc.c | 92 +++++++++++++++++++---------- src/version.c | 2 + src/vim9compile.c | 103 ++++++++++++++++++++++++--------- src/vim9execute.c | 5 ++ 6 files changed, 167 insertions(+), 72 deletions(-) diff --git a/src/proto/userfunc.pro b/src/proto/userfunc.pro index 81d69386f0..44ed397ea7 100644 --- a/src/proto/userfunc.pro +++ b/src/proto/userfunc.pro @@ -2,6 +2,7 @@ void func_init(void); hashtab_T *func_tbl_get(void); int get_function_args(char_u **argp, char_u endchar, garray_T *newargs, garray_T *argtypes, int *varargs, garray_T *default_args, int skip, exarg_T *eap, char_u **line_to_free); +char_u *get_lambda_name(void); int get_lambda_tv(char_u **arg, typval_T *rettv, int evaluate); char_u *deref_func_name(char_u *name, int *lenp, partial_T **partialp, int no_autoload); void emsg_funcname(char *ermsg, char_u *name); @@ -22,6 +23,7 @@ void user_func_error(int error, char_u *name); int call_func(char_u *funcname, int len, typval_T *rettv, int argcount_in, typval_T *argvars_in, funcexe_T *funcexe); char_u *trans_function_name(char_u **pp, int *is_global, int skip, int flags, funcdict_T *fdp, partial_T **partial); char_u *untrans_function_name(char_u *name); +ufunc_T *def_function(exarg_T *eap, char_u *name_arg, void *context); void ex_function(exarg_T *eap); int eval_fname_script(char_u *p); int translated_function_exists(char_u *name, int is_global); diff --git a/src/testdir/test_vim9_func.vim b/src/testdir/test_vim9_func.vim index c06cc2304b..7127331498 100644 --- a/src/testdir/test_vim9_func.vim +++ b/src/testdir/test_vim9_func.vim @@ -2,19 +2,7 @@ source check.vim source view_util.vim - -" Check that "lines" inside ":def" results in an "error" message. -func CheckDefFailure(lines, error) - call writefile(['def Func()'] + a:lines + ['enddef'], 'Xdef') - call assert_fails('so Xdef', a:error, a:lines) - call delete('Xdef') -endfunc - -func CheckScriptFailure(lines, error) - call writefile(a:lines, 'Xdef') - call assert_fails('so Xdef', a:error, a:lines) - call delete('Xdef') -endfunc +source vim9.vim func Test_def_basic() def SomeFunc(): string @@ -95,8 +83,17 @@ def Test_call_default_args() assert_equal('one', MyDefaultArgs('one')) assert_fails('call MyDefaultArgs("one", "two")', 'E118:') - call CheckScriptFailure(['def Func(arg: number = asdf)', 'enddef'], 'E1001:') - call CheckScriptFailure(['def Func(arg: number = "text")', 'enddef'], 'E1013: argument 1: type mismatch, expected number but got string') + CheckScriptFailure(['def Func(arg: number = asdf)', 'enddef'], 'E1001:') + CheckScriptFailure(['def Func(arg: number = "text")', 'enddef'], 'E1013: argument 1: type mismatch, expected number but got string') +enddef + +def Test_nested_function() + def Nested(arg: string): string + return 'nested ' .. arg + enddef + assert_equal('nested function', Nested('function')) + + CheckDefFailure(['func Nested()', 'endfunc'], 'E1086:') enddef func Test_call_default_args_from_func() @@ -721,5 +718,13 @@ def Test_closure_using_argument() unlet g:UseVararg enddef +def Test_nested_closure() + let local = 'text' + def Closure(arg: string): string + return local .. arg + enddef + assert_equal('text!!!', Closure('!!!')) +enddef + " vim: ts=8 sw=2 sts=2 expandtab tw=80 fdm=marker diff --git a/src/userfunc.c b/src/userfunc.c index 4dac28126f..1d5f5d5bc1 100644 --- a/src/userfunc.c +++ b/src/userfunc.c @@ -328,6 +328,19 @@ set_ufunc_name(ufunc_T *fp, char_u *name) } } +/* + * Get a name for a lambda. Returned in static memory. + */ + char_u * +get_lambda_name(void) +{ + static char_u name[30]; + static int lambda_no = 0; + + sprintf((char*)name, "<lambda>%d", ++lambda_no); + return name; +} + /* * Parse a lambda expression and get a Funcref from "*arg". * Return OK or FAIL. Returns NOTDONE for dict or {expr}. @@ -344,7 +357,6 @@ get_lambda_tv(char_u **arg, typval_T *rettv, int evaluate) int ret; char_u *start = skipwhite(*arg + 1); char_u *s, *e; - static int lambda_no = 0; int *old_eval_lavars = eval_lavars_used; int eval_lavars = FALSE; @@ -392,9 +404,7 @@ get_lambda_tv(char_u **arg, typval_T *rettv, int evaluate) { int len, flags = 0; char_u *p; - char_u name[20]; - - sprintf((char*)name, "<lambda>%d", ++lambda_no); + char_u *name = get_lambda_name(); fp = alloc_clear(offsetof(ufunc_T, uf_name) + STRLEN(name) + 1); if (fp == NULL) @@ -2364,10 +2374,11 @@ untrans_function_name(char_u *name) } /* - * ":function" + * ":function" also supporting nested ":def". + * Returns a pointer to the function or NULL if no function defined. */ - void -ex_function(exarg_T *eap) + ufunc_T * +def_function(exarg_T *eap, char_u *name_arg, void *context) { char_u *theline; char_u *line_to_free = NULL; @@ -2375,7 +2386,7 @@ ex_function(exarg_T *eap) int c; int saved_did_emsg; int saved_wait_return = need_wait_return; - char_u *name = NULL; + char_u *name = name_arg; int is_global = FALSE; char_u *p; char_u *arg; @@ -2387,7 +2398,7 @@ ex_function(exarg_T *eap) int varargs = FALSE; int flags = 0; char_u *ret_type = NULL; - ufunc_T *fp; + ufunc_T *fp = NULL; int overwrite = FALSE; int indent; int nesting; @@ -2429,7 +2440,7 @@ ex_function(exarg_T *eap) } } eap->nextcmd = check_nextcmd(eap->arg); - return; + return NULL; } /* @@ -2469,7 +2480,7 @@ ex_function(exarg_T *eap) if (*p == '/') ++p; eap->nextcmd = check_nextcmd(p); - return; + return NULL; } ga_init(&newargs); @@ -2493,25 +2504,34 @@ ex_function(exarg_T *eap) * g:func global function name, same as "func" */ p = eap->arg; - name = trans_function_name(&p, &is_global, eap->skip, - TFN_NO_AUTOLOAD, &fudi, NULL); - paren = (vim_strchr(p, '(') != NULL); - if (name == NULL && (fudi.fd_dict == NULL || !paren) && !eap->skip) + if (name_arg != NULL) { - /* - * Return on an invalid expression in braces, unless the expression - * evaluation has been cancelled due to an aborting error, an - * interrupt, or an exception. - */ - if (!aborting()) + // nested function, argument is (args). + paren = TRUE; + CLEAR_FIELD(fudi); + } + else + { + name = trans_function_name(&p, &is_global, eap->skip, + TFN_NO_AUTOLOAD, &fudi, NULL); + paren = (vim_strchr(p, '(') != NULL); + if (name == NULL && (fudi.fd_dict == NULL || !paren) && !eap->skip) { - if (!eap->skip && fudi.fd_newkey != NULL) - semsg(_(e_dictkey), fudi.fd_newkey); - vim_free(fudi.fd_newkey); - return; + /* + * Return on an invalid expression in braces, unless the expression + * evaluation has been cancelled due to an aborting error, an + * interrupt, or an exception. + */ + if (!aborting()) + { + if (!eap->skip && fudi.fd_newkey != NULL) + semsg(_(e_dictkey), fudi.fd_newkey); + vim_free(fudi.fd_newkey); + return NULL; + } + else + eap->skip = TRUE; } - else - eap->skip = TRUE; } // An error in a function call during evaluation of an expression in magic @@ -2596,7 +2616,7 @@ ex_function(exarg_T *eap) ga_init2(&newlines, (int)sizeof(char_u *), 3); - if (!eap->skip) + if (!eap->skip && name_arg == NULL) { // Check the name of the function. Unless it's a dictionary function // (that we are overwriting). @@ -3255,7 +3275,7 @@ ex_function(exarg_T *eap) // ":def Func()" needs to be compiled if (eap->cmdidx == CMD_def) - compile_def_function(fp, FALSE, NULL); + compile_def_function(fp, FALSE, context); goto ret_free; @@ -3269,10 +3289,22 @@ ret_free: vim_free(skip_until); vim_free(line_to_free); vim_free(fudi.fd_newkey); - vim_free(name); + if (name != name_arg) + vim_free(name); vim_free(ret_type); did_emsg |= saved_did_emsg; need_wait_return |= saved_wait_return; + + return fp; +} + +/* + * ":function" + */ + void +ex_function(exarg_T *eap) +{ + def_function(eap, NULL, NULL); } /* diff --git a/src/version.c b/src/version.c index 982170eb8f..da1a20f41f 100644 --- a/src/version.c +++ b/src/version.c @@ -746,6 +746,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 695, /**/ 694, /**/ diff --git a/src/vim9compile.c b/src/vim9compile.c index 300adfbec5..7e700d5637 100644 --- a/src/vim9compile.c +++ b/src/vim9compile.c @@ -101,6 +101,7 @@ typedef struct { int lv_from_outer; // when TRUE using ctx_outer scope int lv_const; // when TRUE cannot be assigned to int lv_arg; // when TRUE this is an argument + int lv_func_idx; // for nested function } lvar_T; /* @@ -2615,6 +2616,7 @@ compile_call(char_u **arg, size_t varlen, cctx_T *cctx, int argcount_init) int error = FCERR_NONE; ufunc_T *ufunc; int res = FAIL; + lvar_T *lvar; if (varlen >= sizeof(namebuf)) { @@ -2641,6 +2643,16 @@ compile_call(char_u **arg, size_t varlen, cctx_T *cctx, int argcount_init) goto theend; } + // Check if the name is a nested function. + lvar = lookup_local(namebuf, varlen, cctx); + if (lvar != NULL && lvar->lv_func_idx > 0) + { + dfunc_T *dfunc = ((dfunc_T *)def_functions.ga_data) + + lvar->lv_func_idx; + res = generate_CALL(cctx, dfunc->df_ufunc, argcount); + goto theend; + } + // If we can find the function by name generate the right call. ufunc = find_func(name, FALSE, cctx); if (ufunc != NULL) @@ -4048,6 +4060,64 @@ compile_return(char_u *arg, int set_return_type, cctx_T *cctx) return skipwhite(p); } +/* + * Get a line from the compilation context, compatible with exarg_T getline(). + * Return a pointer to the line in allocated memory. + * Return NULL for end-of-file or some error. + */ + static char_u * +exarg_getline( + int c UNUSED, + void *cookie, + int indent UNUSED, + int do_concat UNUSED) +{ + cctx_T *cctx = (cctx_T *)cookie; + + if (cctx->ctx_lnum == cctx->ctx_ufunc->uf_lines.ga_len) + { + iemsg("Heredoc got to end"); + return NULL; + } + ++cctx->ctx_lnum; + return vim_strsave(((char_u **)cctx->ctx_ufunc->uf_lines.ga_data) + [cctx->ctx_lnum]); +} + +/* + * Compile a nested :def command. + */ + static char_u * +compile_nested_function(exarg_T *eap, cctx_T *cctx) +{ + char_u *name_start = eap->arg; + char_u *name_end = to_name_end(eap->arg, FALSE); + char_u *name = get_lambda_name(); + lvar_T *lvar; + ufunc_T *ufunc; + + eap->arg = name_end; + eap->getline = exarg_getline; + eap->cookie = cctx; + eap->skip = cctx->ctx_skip == TRUE; + eap->forceit = FALSE; + ufunc = def_function(eap, name, cctx); + + if (ufunc == NULL) + return NULL; + + // Define a local variable for the function, but change the index to -1 to + // mark it as a function name. + lvar = reserve_local(cctx, name_start, name_end - name_start, + TRUE, &t_func_unknown); + lvar->lv_idx = 0; + ++cctx->ctx_locals_count; // doesn't count as a local variable + lvar->lv_func_idx = ufunc->uf_dfunc_idx; + + // TODO: warning for trailing? + return (char_u *)""; +} + /* * Return the length of an assignment operator, or zero if there isn't one. */ @@ -4077,30 +4147,6 @@ static char *reserved[] = { NULL }; -/* - * Get a line for "=<<". - * Return a pointer to the line in allocated memory. - * Return NULL for end-of-file or some error. - */ - static char_u * -heredoc_getline( - int c UNUSED, - void *cookie, - int indent UNUSED, - int do_concat UNUSED) -{ - cctx_T *cctx = (cctx_T *)cookie; - - if (cctx->ctx_lnum == cctx->ctx_ufunc->uf_lines.ga_len) - { - iemsg("Heredoc got to end"); - return NULL; - } - ++cctx->ctx_lnum; - return vim_strsave(((char_u **)cctx->ctx_ufunc->uf_lines.ga_data) - [cctx->ctx_lnum]); -} - typedef enum { dest_local, dest_option, @@ -4394,7 +4440,7 @@ compile_assignment(char_u *arg, exarg_T *eap, cmdidx_T cmdidx, cctx_T *cctx) listitem_T *li; // [let] varname =<< [trim] {end} - eap->getline = heredoc_getline; + eap->getline = exarg_getline; eap->cookie = cctx; l = heredoc_get(eap, op + 3, FALSE); @@ -6299,9 +6345,12 @@ compile_def_function(ufunc_T *ufunc, int set_return_type, cctx_T *outer_cctx) switch (ea.cmdidx) { case CMD_def: + ea.arg = p; + line = compile_nested_function(&ea, &cctx); + break; + case CMD_function: - // TODO: Nested function - emsg("Nested function not implemented yet"); + emsg(_("E1086: Cannot use :function inside :def")); goto erret; case CMD_return: diff --git a/src/vim9execute.c b/src/vim9execute.c index c74240ff20..665c6afd29 100644 --- a/src/vim9execute.c +++ b/src/vim9execute.c @@ -206,6 +206,11 @@ call_dfunc(int cdf_idx, int argcount_arg, ectx_T *ectx) + dfunc->df_varcount + dfunc->df_closure_count) == FAIL) return FAIL; + // Closure may need the function context where it was defined. + // TODO: assuming current context. + ectx->ec_outer_stack = &ectx->ec_stack; + ectx->ec_outer_frame = ectx->ec_frame_idx; + // Move the vararg-list to below the missing optional arguments. if (vararg_count > 0 && arg_to_add > 0) *STACK_TV_BOT(arg_to_add - 1) = *STACK_TV_BOT(-1); From 0e65d3de0aeff00aa42ea899f1afd11f8b22b93e Mon Sep 17 00:00:00 2001 From: Bram Moolenaar <Bram@vim.org> Date: Tue, 5 May 2020 17:53:16 +0200 Subject: [PATCH 091/230] patch 8.2.0696: Vim9: nested function does not work properly Problem: Vim9: nested function does not work properly Solution: Create a function reference. Check argument count. --- src/testdir/test_vim9_func.vim | 3 ++ src/version.c | 2 ++ src/vim9compile.c | 51 +++++++++++++++++----------------- src/vim9execute.c | 5 ---- 4 files changed, 30 insertions(+), 31 deletions(-) diff --git a/src/testdir/test_vim9_func.vim b/src/testdir/test_vim9_func.vim index 7127331498..840c220487 100644 --- a/src/testdir/test_vim9_func.vim +++ b/src/testdir/test_vim9_func.vim @@ -93,6 +93,9 @@ def Test_nested_function() enddef assert_equal('nested function', Nested('function')) + CheckDefFailure(['def Nested()', 'enddef', 'Nested(66)'], 'E118:') + CheckDefFailure(['def Nested(arg: string)', 'enddef', 'Nested()'], 'E119:') + CheckDefFailure(['func Nested()', 'endfunc'], 'E1086:') enddef diff --git a/src/version.c b/src/version.c index da1a20f41f..38755db73f 100644 --- a/src/version.c +++ b/src/version.c @@ -746,6 +746,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 696, /**/ 695, /**/ diff --git a/src/vim9compile.c b/src/vim9compile.c index 7e700d5637..de2fb96b51 100644 --- a/src/vim9compile.c +++ b/src/vim9compile.c @@ -101,7 +101,6 @@ typedef struct { int lv_from_outer; // when TRUE using ctx_outer scope int lv_const; // when TRUE cannot be assigned to int lv_arg; // when TRUE this is an argument - int lv_func_idx; // for nested function } lvar_T; /* @@ -1504,7 +1503,24 @@ generate_PCALL( if (type->tt_type == VAR_ANY) ret_type = &t_any; else if (type->tt_type == VAR_FUNC || type->tt_type == VAR_PARTIAL) + { + if (type->tt_argcount != -1) + { + int varargs = (type->tt_flags & TTFLAG_VARARGS) ? 1 : 0; + + if (argcount < type->tt_min_argcount - varargs) + { + semsg(_(e_toofewarg), "[reference]"); + return FAIL; + } + if (!varargs && argcount > type->tt_argcount) + { + semsg(_(e_toomanyarg), "[reference]"); + return FAIL; + } + } ret_type = type->tt_member; + } else { semsg(_("E1085: Not a callable type: %s"), name); @@ -2616,7 +2632,6 @@ compile_call(char_u **arg, size_t varlen, cctx_T *cctx, int argcount_init) int error = FCERR_NONE; ufunc_T *ufunc; int res = FAIL; - lvar_T *lvar; if (varlen >= sizeof(namebuf)) { @@ -2643,16 +2658,6 @@ compile_call(char_u **arg, size_t varlen, cctx_T *cctx, int argcount_init) goto theend; } - // Check if the name is a nested function. - lvar = lookup_local(namebuf, varlen, cctx); - if (lvar != NULL && lvar->lv_func_idx > 0) - { - dfunc_T *dfunc = ((dfunc_T *)def_functions.ga_data) - + lvar->lv_func_idx; - res = generate_CALL(cctx, dfunc->df_ufunc, argcount); - goto theend; - } - // If we can find the function by name generate the right call. ufunc = find_func(name, FALSE, cctx); if (ufunc != NULL) @@ -2807,7 +2812,6 @@ compile_list(char_u **arg, cctx_T *cctx) static int compile_lambda(char_u **arg, cctx_T *cctx) { - garray_T *instr = &cctx->ctx_instr; typval_T rettv; ufunc_T *ufunc; @@ -2825,12 +2829,7 @@ compile_lambda(char_u **arg, cctx_T *cctx) compile_def_function(ufunc, TRUE, cctx); if (ufunc->uf_dfunc_idx >= 0) - { - if (ga_grow(instr, 1) == FAIL) - return FAIL; - generate_FUNCREF(cctx, ufunc->uf_dfunc_idx); - return OK; - } + return generate_FUNCREF(cctx, ufunc->uf_dfunc_idx); return FAIL; } @@ -4103,16 +4102,16 @@ compile_nested_function(exarg_T *eap, cctx_T *cctx) eap->forceit = FALSE; ufunc = def_function(eap, name, cctx); - if (ufunc == NULL) + if (ufunc == NULL || ufunc->uf_dfunc_idx < 0) return NULL; - // Define a local variable for the function, but change the index to -1 to - // mark it as a function name. + // Define a local variable for the function reference. lvar = reserve_local(cctx, name_start, name_end - name_start, - TRUE, &t_func_unknown); - lvar->lv_idx = 0; - ++cctx->ctx_locals_count; // doesn't count as a local variable - lvar->lv_func_idx = ufunc->uf_dfunc_idx; + TRUE, ufunc->uf_func_type); + + if (generate_FUNCREF(cctx, ufunc->uf_dfunc_idx) == FAIL + || generate_STORE(cctx, ISN_STORE, lvar->lv_idx, NULL) == FAIL) + return NULL; // TODO: warning for trailing? return (char_u *)""; diff --git a/src/vim9execute.c b/src/vim9execute.c index 665c6afd29..c74240ff20 100644 --- a/src/vim9execute.c +++ b/src/vim9execute.c @@ -206,11 +206,6 @@ call_dfunc(int cdf_idx, int argcount_arg, ectx_T *ectx) + dfunc->df_varcount + dfunc->df_closure_count) == FAIL) return FAIL; - // Closure may need the function context where it was defined. - // TODO: assuming current context. - ectx->ec_outer_stack = &ectx->ec_stack; - ectx->ec_outer_frame = ectx->ec_frame_idx; - // Move the vararg-list to below the missing optional arguments. if (vararg_count > 0 && arg_to_add > 0) *STACK_TV_BOT(arg_to_add - 1) = *STACK_TV_BOT(-1); From 221fcc741a6660bfc3fd0d64937d0c15bb71f51d Mon Sep 17 00:00:00 2001 From: Bram Moolenaar <Bram@vim.org> Date: Tue, 5 May 2020 19:46:20 +0200 Subject: [PATCH 092/230] patch 8.2.0697: Vim9: memory leak when using nested function Problem: Vim9: memory leak when using nested function. Solution: Unreference function when deleting instructions. Adjust reference count for local variables. --- src/version.c | 2 ++ src/vim9compile.c | 9 ++++++++- src/vim9execute.c | 23 ++++++++++++++++++++--- 3 files changed, 30 insertions(+), 4 deletions(-) diff --git a/src/version.c b/src/version.c index 38755db73f..edbfa9349b 100644 --- a/src/version.c +++ b/src/version.c @@ -746,6 +746,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 697, /**/ 696, /**/ diff --git a/src/vim9compile.c b/src/vim9compile.c index de2fb96b51..42fc0749ad 100644 --- a/src/vim9compile.c +++ b/src/vim9compile.c @@ -6629,6 +6629,14 @@ delete_instr(isn_T *isn) vim_free(isn->isn_arg.ufunc.cuf_name); break; + case ISN_FUNCREF: + { + dfunc_T *dfunc = ((dfunc_T *)def_functions.ga_data) + + isn->isn_arg.funcref.fr_func; + func_ptr_unref(dfunc->df_ufunc); + } + break; + case ISN_2BOOL: case ISN_2STRING: case ISN_ADDBLOB: @@ -6657,7 +6665,6 @@ delete_instr(isn_T *isn) case ISN_EXECCONCAT: case ISN_EXECUTE: case ISN_FOR: - case ISN_FUNCREF: case ISN_INDEX: case ISN_JUMP: case ISN_LOAD: diff --git a/src/vim9execute.c b/src/vim9execute.c index c74240ff20..386b8491f9 100644 --- a/src/vim9execute.c +++ b/src/vim9execute.c @@ -264,10 +264,27 @@ handle_closure_in_use(ectx_T *ectx, int free_arguments) { tv = STACK_TV(ectx->ec_frame_idx + STACK_FRAME_SIZE + dfunc->df_varcount + idx); - if (tv->v_type == VAR_PARTIAL && tv->vval.v_partial->pt_refcount > 1) + if (tv->v_type == VAR_PARTIAL && tv->vval.v_partial != NULL + && tv->vval.v_partial->pt_refcount > 1) { - closure_in_use = TRUE; - break; + int refcount = tv->vval.v_partial->pt_refcount; + int i; + + // A Reference in a local variables doesn't count, its get + // unreferenced on return. + for (i = 0; i < dfunc->df_varcount; ++i) + { + typval_T *stv = STACK_TV(ectx->ec_frame_idx + + STACK_FRAME_SIZE + i); + if (stv->v_type == VAR_PARTIAL + && tv->vval.v_partial == stv->vval.v_partial) + --refcount; + } + if (refcount > 1) + { + closure_in_use = TRUE; + break; + } } } From f9ab52e155dc13f59b654d754041fe78e17b9074 Mon Sep 17 00:00:00 2001 From: Bram Moolenaar <Bram@vim.org> Date: Tue, 5 May 2020 19:57:18 +0200 Subject: [PATCH 093/230] patch 8.2.0698: insert mode completion not fully tested Problem: Insert mode completion not fully tested. Solution: Add a few more tests. (Yegappan Lakshmanan, closes #6041) --- src/testdir/test_edit.vim | 18 +++--- src/testdir/test_ins_complete.vim | 99 +++++++++++++++++++++++++++++++ src/testdir/test_textformat.vim | 24 ++++++++ src/version.c | 2 + 4 files changed, 134 insertions(+), 9 deletions(-) diff --git a/src/testdir/test_edit.vim b/src/testdir/test_edit.vim index f0bf5cc5f6..dabe8fbdc8 100644 --- a/src/testdir/test_edit.vim +++ b/src/testdir/test_edit.vim @@ -328,8 +328,8 @@ func Test_edit_11_indentexpr() bw! endfunc +" Test changing indent in replace mode func Test_edit_12() - " Test changing indent in replace mode new call setline(1, ["\tabc", "\tdef"]) call cursor(2, 4) @@ -368,15 +368,15 @@ func Test_edit_12() call feedkeys("R\<c-t>\<c-t>", 'tnix') call assert_equal(["\tabc", "\t\t\tdef"], getline(1, '$')) call assert_equal([0, 2, 2, 0], getpos('.')) - set et - set sw& et& + set sw& + + " In replace mode, after hitting enter in a line with tab characters, + " pressing backspace should restore the tab characters. %d - call setline(1, ["\t/*"]) - set formatoptions=croql - call cursor(1, 3) - call feedkeys("A\<cr>\<cr>/", 'tnix') - call assert_equal(["\t/*", " *", " */"], getline(1, '$')) - set formatoptions& + setlocal autoindent backspace=2 + call setline(1, "\tone\t\ttwo") + exe "normal ggRred\<CR>six" .. repeat("\<BS>", 8) + call assert_equal(["\tone\t\ttwo"], getline(1, '$')) bw! endfunc diff --git a/src/testdir/test_ins_complete.vim b/src/testdir/test_ins_complete.vim index dbea9013f8..1abbe920ff 100644 --- a/src/testdir/test_ins_complete.vim +++ b/src/testdir/test_ins_complete.vim @@ -493,12 +493,43 @@ func Test_completefunc_error() call setline(1, ['', 'abcd', '']) call assert_fails('exe "normal 2G$a\<C-X>\<C-U>"', 'E578:') + " Jump to a different window from the complete function + " TODO: The following test causes an ASAN failure. Once this issue is + " addressed, enable the following test. + "func! CompleteFunc(findstart, base) + " if a:findstart == 1 + " return col('.') - 1 + " endif + " wincmd p + " return ['a', 'b'] + "endfunc + "set completefunc=CompleteFunc + "new + "call assert_fails('exe "normal a\<C-X>\<C-U>"', 'E839:') + "close! + set completefunc& delfunc CompleteFunc delfunc CompleteFunc2 close! endfunc +" Test for returning non-string values from 'completefunc' +func Test_completefunc_invalid_data() + new + func! CompleteFunc(findstart, base) + if a:findstart == 1 + return col('.') - 1 + endif + return [{}, '', 'moon'] + endfunc + set completefunc=CompleteFunc + exe "normal i\<C-X>\<C-U>" + call assert_equal('moon', getline(1)) + set completefunc& + close! +endfunc + " Test for errors in using complete() function func Test_complete_func_error() call assert_fails('call complete(1, ["a"])', 'E785:') @@ -513,6 +544,7 @@ func Test_complete_func_error() delfunc ListColors delfunc ListMonths call assert_fails('call complete_info({})', 'E714:') + call assert_equal([], complete_info(['items']).items) endfunc " Test for completing words following a completed word in a line @@ -535,4 +567,71 @@ func Test_complete_wrapscan() close! endfunc +" Test for completing special characters +func Test_complete_special_chars() + new + call setline(1, 'int .*[-\^$ func float') + call feedkeys("oin\<C-X>\<C-P>\<C-X>\<C-P>\<C-X>\<C-P>", 'xt') + call assert_equal('int .*[-\^$ func float', getline(2)) + close! +endfunc + +" Test for completion when text is wrapped across lines. +func Test_complete_across_line() + new + call setline(1, ['red green blue', 'one two three']) + setlocal textwidth=20 + exe "normal 2G$a re\<C-X>\<C-P>\<C-X>\<C-P>\<C-X>\<C-P>\<C-X>\<C-P>" + call assert_equal(['one two three red', 'green blue one'], getline(2, '$')) + close! +endfunc + +" Test for using CTRL-L to add one character when completing matching +func Test_complete_add_onechar() + new + call setline(1, ['wool', 'woodwork']) + call feedkeys("Gowoo\<C-P>\<C-P>\<C-P>\<C-L>f", 'xt') + call assert_equal('woof', getline(3)) + + " use 'ignorecase' and backspace to erase characters from the prefix string + " and then add letters using CTRL-L + %d + set ignorecase backspace=2 + setlocal complete=. + call setline(1, ['workhorse', 'workload']) + normal Go + exe "normal aWOR\<C-P>\<bs>\<bs>\<bs>\<bs>\<bs>\<bs>\<C-L>r\<C-L>\<C-L>" + call assert_equal('workh', getline(3)) + set ignorecase& backspace& + close! +endfunc + +" Test insert completion with 'cindent' (adjust the indent) +func Test_complete_with_cindent() + new + setlocal cindent + call setline(1, ['if (i == 1)', " j = 2;"]) + exe "normal Go{\<CR>i\<C-X>\<C-L>\<C-X>\<C-L>\<CR>}" + call assert_equal(['{', "\tif (i == 1)", "\t\tj = 2;", '}'], getline(3, '$')) + + %d + call setline(1, ['when while', '{', '']) + setlocal cinkeys+==while + exe "normal Giwh\<C-P> " + call assert_equal("\twhile ", getline('$')) + close! +endfunc + +" Test for <CTRL-X> <CTRL-V> completion. Complete commands and functions +func Test_complete_cmdline() + new + exe "normal icaddb\<C-X>\<C-V>" + call assert_equal('caddbuffer', getline(1)) + exe "normal ocall getqf\<C-X>\<C-V>" + call assert_equal('call getqflist(', getline(2)) + exe "normal oabcxyz(\<C-X>\<C-V>" + call assert_equal('abcxyz(', getline(3)) + close! +endfunc + " vim: shiftwidth=2 sts=2 expandtab diff --git a/src/testdir/test_textformat.vim b/src/testdir/test_textformat.vim index f4792b9544..33daaab651 100644 --- a/src/testdir/test_textformat.vim +++ b/src/testdir/test_textformat.vim @@ -975,6 +975,30 @@ func Test_whichwrap_multi_byte() bwipe! endfunc +" Test for automatically adding comment leaders in insert mode +func Test_threepiece_comment() + new + setlocal expandtab + call setline(1, ["\t/*"]) + setlocal formatoptions=croql + call cursor(1, 3) + call feedkeys("A\<cr>\<cr>/", 'tnix') + call assert_equal(["\t/*", " *", " */"], getline(1, '$')) + + " If a comment ends in a single line, then don't add it in the next line + %d + call setline(1, '/* line1 */') + call feedkeys("A\<CR>next line", 'xt') + call assert_equal(['/* line1 */', 'next line'], getline(1, '$')) + + %d + " Copy the trailing indentation from the leader comment to a new line + setlocal autoindent noexpandtab + call feedkeys("a\t/*\tone\ntwo\n/", 'xt') + call assert_equal(["\t/*\tone", "\t *\ttwo", "\t */"], getline(1, '$')) + close! +endfunc + " Test for the 'f' flag in 'comments' (only the first line has the comment " string) func Test_firstline_comment() diff --git a/src/version.c b/src/version.c index edbfa9349b..213a41d283 100644 --- a/src/version.c +++ b/src/version.c @@ -746,6 +746,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 698, /**/ 697, /**/ From 015f4267f4a28627c1872042078a95be7e06c4dc Mon Sep 17 00:00:00 2001 From: Bram Moolenaar <Bram@vim.org> Date: Tue, 5 May 2020 21:25:22 +0200 Subject: [PATCH 094/230] patch 8.2.0699: Vim9: not all errors tested Problem: Vim9: not all errors tested. Solution: Add test for deleted function. Bail out on first error. --- src/testdir/test_vim9_expr.vim | 34 +++++++++++++++++----------------- src/testdir/test_vim9_func.vim | 17 +++++++++++++++++ src/testdir/vim9.vim | 16 ++++++++-------- src/version.c | 2 ++ src/vim9execute.c | 7 ++++++- 5 files changed, 50 insertions(+), 26 deletions(-) diff --git a/src/testdir/test_vim9_expr.vim b/src/testdir/test_vim9_expr.vim index ef5c00ccd7..68eb40d2e4 100644 --- a/src/testdir/test_vim9_expr.vim +++ b/src/testdir/test_vim9_expr.vim @@ -759,11 +759,11 @@ def Test_expr7_list() assert_equal(g:list_mixed, [1, 'b', false]) assert_equal('b', g:list_mixed[1]) - call CheckDefExecFailure("let x = g:anint[3]", 'E714:') + call CheckDefExecFailure(["let x = g:anint[3]"], 'E714:') call CheckDefFailure(["let x = g:list_mixed[xxx]"], 'E1001:') - call CheckDefExecFailure("let x = g:list_mixed['xx']", 'E39:') + call CheckDefExecFailure(["let x = g:list_mixed['xx']"], 'E39:') call CheckDefFailure(["let x = g:list_mixed[0"], 'E111:') - call CheckDefExecFailure("let x = g:list_empty[3]", 'E684:') + call CheckDefExecFailure(["let x = g:list_empty[3]"], 'E684:') enddef def Test_expr7_lambda() @@ -792,8 +792,8 @@ def Test_expr7_dict() call CheckDefFailure(["let x = #"], 'E1015:') call CheckDefFailure(["let x += 1"], 'E1020:') call CheckDefFailure(["let x = x + 1"], 'E1001:') - call CheckDefExecFailure("let x = g:anint.member", 'E715:') - call CheckDefExecFailure("let x = g:dict_empty.member", 'E716:') + call CheckDefExecFailure(["let x = g:anint.member"], 'E715:') + call CheckDefExecFailure(["let x = g:dict_empty.member"], 'E716:') enddef def Test_expr_member() @@ -899,8 +899,8 @@ func Test_expr7_fails() call CheckDefFailure(["let x = -'xx'"], "E1030:") call CheckDefFailure(["let x = +'xx'"], "E1030:") call CheckDefFailure(["let x = -0z12"], "E974:") - call CheckDefExecFailure("let x = -[8]", "E39:") - call CheckDefExecFailure("let x = -{'a': 1}", "E39:") + call CheckDefExecFailure(["let x = -[8]"], "E39:") + call CheckDefExecFailure(["let x = -{'a': 1}"], "E39:") call CheckDefFailure(["let x = @"], "E1002:") call CheckDefFailure(["let x = @<"], "E354:") @@ -914,23 +914,23 @@ func Test_expr7_fails() call CheckDefFailure(["let x = ¬exist"], 'E113:') call CheckDefFailure(["&grepprg = [343]"], 'E1013:') - call CheckDefExecFailure("echo s:doesnt_exist", 'E121:') - call CheckDefExecFailure("echo g:doesnt_exist", 'E121:') + call CheckDefExecFailure(["echo s:doesnt_exist"], 'E121:') + call CheckDefExecFailure(["echo g:doesnt_exist"], 'E121:') call CheckDefFailure(["echo a:somevar"], 'E1075:') call CheckDefFailure(["echo l:somevar"], 'E1075:') call CheckDefFailure(["echo x:somevar"], 'E1075:') - call CheckDefExecFailure("let x = +g:astring", 'E1030:') - call CheckDefExecFailure("let x = +g:ablob", 'E974:') - call CheckDefExecFailure("let x = +g:alist", 'E745:') - call CheckDefExecFailure("let x = +g:adict", 'E728:') + call CheckDefExecFailure(["let x = +g:astring"], 'E1030:') + call CheckDefExecFailure(["let x = +g:ablob"], 'E974:') + call CheckDefExecFailure(["let x = +g:alist"], 'E745:') + call CheckDefExecFailure(["let x = +g:adict"], 'E728:') call CheckDefFailure(["let x = ''", "let y = x.memb"], 'E715:') - call CheckDefExecFailure("[1, 2->len()", 'E492:') - call CheckDefExecFailure("#{a: 1->len()", 'E488:') - call CheckDefExecFailure("{'a': 1->len()", 'E492:') + call CheckDefExecFailure(["[1, 2->len()"], 'E492:') + call CheckDefExecFailure(["#{a: 1->len()"], 'E488:') + call CheckDefExecFailure(["{'a': 1->len()"], 'E492:') endfunc let g:Funcrefs = [function('add')] @@ -986,7 +986,7 @@ func Test_expr_fails() call CheckDefFailure(["let x = '1'is2"], 'E488:') call CheckDefFailure(["let x = '1'isnot2"], 'E488:') - call CheckDefExecFailure("CallMe ('yes')", 'E492:') + call CheckDefExecFailure(["CallMe ('yes')"], 'E492:') call CheckDefFailure(["CallMe2('yes','no')"], 'E1069:') call CheckDefFailure(["CallMe2('yes' , 'no')"], 'E1068:') diff --git a/src/testdir/test_vim9_func.vim b/src/testdir/test_vim9_func.vim index 840c220487..49dc2f2f21 100644 --- a/src/testdir/test_vim9_func.vim +++ b/src/testdir/test_vim9_func.vim @@ -642,6 +642,23 @@ func Test_E1056_1059() call assert_equal(1, caught_1059) endfunc +func DelMe() + echo 'DelMe' +endfunc + +def Test_deleted_function() + CheckDefExecFailure([ + 'let RefMe: func = function("g:DelMe")', + 'delfunc g:DelMe', + 'echo RefMe()'], 'E117:') +enddef + +def Test_unknown_function() + CheckDefExecFailure([ + 'let Ref: func = function("NotExist")', + 'delfunc g:NotExist'], 'E700:') +enddef + def RefFunc(Ref: func(string): string): string return Ref('more') enddef diff --git a/src/testdir/vim9.vim b/src/testdir/vim9.vim index 0e0cd1e1f7..0c16576c69 100644 --- a/src/testdir/vim9.vim +++ b/src/testdir/vim9.vim @@ -7,6 +7,14 @@ func CheckDefFailure(lines, error) call delete('Xdef') endfunc +" Check that "lines" inside ":def" results in an "error" message when executed. +func CheckDefExecFailure(lines, error) + call writefile(['def Func()'] + a:lines + ['enddef'], 'Xdef') + so Xdef + call assert_fails('call Func()', a:error, a:lines) + call delete('Xdef') +endfunc + def CheckScriptFailure(lines: list<string>, error: string) writefile(lines, 'Xdef') assert_fails('so Xdef', error, lines) @@ -18,11 +26,3 @@ def CheckScriptSuccess(lines: list<string>) so Xdef delete('Xdef') enddef - -" Check that "line" inside ":def" results in an "error" message when executed. -func CheckDefExecFailure(line, error) - call writefile(['def! Func()', a:line, 'enddef'], 'Xdef') - so Xdef - call assert_fails('call Func()', a:error, a:line) - call delete('Xdef') -endfunc diff --git a/src/version.c b/src/version.c index 213a41d283..61681882bd 100644 --- a/src/version.c +++ b/src/version.c @@ -746,6 +746,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 699, /**/ 698, /**/ diff --git a/src/vim9execute.c b/src/vim9execute.c index 386b8491f9..27ad04b446 100644 --- a/src/vim9execute.c +++ b/src/vim9execute.c @@ -432,6 +432,7 @@ call_bfunc(int func_idx, int argcount, ectx_T *ectx) { typval_T argvars[MAX_FUNC_ARGS]; int idx; + int called_emsg_before = called_emsg; if (call_prepare(argcount, argvars, ectx) == FAIL) return FAIL; @@ -442,6 +443,9 @@ call_bfunc(int func_idx, int argcount, ectx_T *ectx) // Clear the arguments. for (idx = 0; idx < argcount; ++idx) clear_tv(&argvars[idx]); + + if (called_emsg != called_emsg_before) + return FAIL; return OK; } @@ -549,7 +553,8 @@ call_partial(typval_T *tv, int argcount, ectx_T *ectx) if (name == NULL || call_by_name(name, argcount, ectx, NULL) == FAIL) { if (called_emsg == called_emsg_before) - semsg(_(e_unknownfunc), name); + semsg(_(e_unknownfunc), + name == NULL ? (char_u *)"[unknown]" : name); return FAIL; } return OK; From 40ee466c361b9698c2a452a36ff4d6c6e5382ed0 Mon Sep 17 00:00:00 2001 From: Bram Moolenaar <Bram@vim.org> Date: Tue, 5 May 2020 22:08:26 +0200 Subject: [PATCH 095/230] patch 8.2.0700: Vim9: converting error message to exception not tested Problem: Vim9: converting error message to exception not tested. Solution: Test exception from error. Do not continue after :echoerr. --- src/testdir/test_vim9_script.vim | 20 +++++++++++++++++++- src/version.c | 2 ++ src/vim9execute.c | 6 ------ 3 files changed, 21 insertions(+), 7 deletions(-) diff --git a/src/testdir/test_vim9_script.vim b/src/testdir/test_vim9_script.vim index bc1f87377f..76ce2e5498 100644 --- a/src/testdir/test_vim9_script.vim +++ b/src/testdir/test_vim9_script.vim @@ -466,6 +466,20 @@ def Test_try_catch_fails() call CheckDefFailure(['throw xxx'], 'E1001:') enddef +let someJob = test_null_job() + +def FuncWithError() + echomsg g:someJob +enddef + +func Test_convert_emsg_to_exception() + try + call FuncWithError() + catch + call assert_match('Vim:E908:', v:exception) + endtry +endfunc + let s:export_script_lines =<< trim END vim9script let name: string = 'bob' @@ -1058,7 +1072,11 @@ def Test_echomsg_cmd() enddef def Test_echoerr_cmd() - # TODO: write this test + try + echoerr 'something' 'wrong' # comment + catch + assert_match('something wrong', v:exception) + endtry enddef def Test_for_outside_of_function() diff --git a/src/version.c b/src/version.c index 61681882bd..4c743cbfa1 100644 --- a/src/version.c +++ b/src/version.c @@ -746,6 +746,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 700, /**/ 699, /**/ diff --git a/src/vim9execute.c b/src/vim9execute.c index 27ad04b446..5915ea1dce 100644 --- a/src/vim9execute.c +++ b/src/vim9execute.c @@ -898,14 +898,8 @@ call_def_function( } else { - int save_did_emsg = did_emsg; - SOURCING_LNUM = iptr->isn_lnum; emsg(ga.ga_data); - if (!force_abort) - // We don't want to abort following - // commands, restore did_emsg. - did_emsg = save_did_emsg; } } } From 2a1381c305b32885c644cc300e4f6734292626a2 Mon Sep 17 00:00:00 2001 From: Bram Moolenaar <Bram@vim.org> Date: Tue, 5 May 2020 23:32:58 +0200 Subject: [PATCH 096/230] patch 8.2.0701: Vim9 test fails without job feature Problem: Vim9 test fails without job feature. Solution: Add feature check. --- src/testdir/test_vim9_script.vim | 24 +++++++++++++----------- src/version.c | 2 ++ 2 files changed, 15 insertions(+), 11 deletions(-) diff --git a/src/testdir/test_vim9_script.vim b/src/testdir/test_vim9_script.vim index 76ce2e5498..40aae46a14 100644 --- a/src/testdir/test_vim9_script.vim +++ b/src/testdir/test_vim9_script.vim @@ -466,19 +466,21 @@ def Test_try_catch_fails() call CheckDefFailure(['throw xxx'], 'E1001:') enddef -let someJob = test_null_job() +if has('channel') + let someJob = test_null_job() -def FuncWithError() - echomsg g:someJob -enddef + def FuncWithError() + echomsg g:someJob + enddef -func Test_convert_emsg_to_exception() - try - call FuncWithError() - catch - call assert_match('Vim:E908:', v:exception) - endtry -endfunc + func Test_convert_emsg_to_exception() + try + call FuncWithError() + catch + call assert_match('Vim:E908:', v:exception) + endtry + endfunc +endif let s:export_script_lines =<< trim END vim9script diff --git a/src/version.c b/src/version.c index 4c743cbfa1..0dc91da61a 100644 --- a/src/version.c +++ b/src/version.c @@ -746,6 +746,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 701, /**/ 700, /**/ From 54ed0dff2913f9c973f6ab04b3c96372bdf07406 Mon Sep 17 00:00:00 2001 From: Bram Moolenaar <Bram@vim.org> Date: Wed, 6 May 2020 19:38:30 +0200 Subject: [PATCH 097/230] patch 8.2.0702: running channel tests may leave running process behind Problem: Running channel tests may leave running process behind. Solution: Make Python client exit when running into EOF. (Kurtis Rader, part of #6046) --- src/testdir/test_channel_pipe.py | 2 ++ src/version.c | 2 ++ 2 files changed, 4 insertions(+) diff --git a/src/testdir/test_channel_pipe.py b/src/testdir/test_channel_pipe.py index 5caffcbf9e..5202908e7e 100644 --- a/src/testdir/test_channel_pipe.py +++ b/src/testdir/test_channel_pipe.py @@ -29,6 +29,8 @@ if __name__ == "__main__": while True: typed = sys.stdin.readline() + if typed == "": # EOF -- stop + break if typed.startswith("quit"): print("Goodbye!") sys.stdout.flush() diff --git a/src/version.c b/src/version.c index 0dc91da61a..523791ca0f 100644 --- a/src/version.c +++ b/src/version.c @@ -746,6 +746,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 702, /**/ 701, /**/ From b68b346e6db6d3f848e0a89905fcd7777b73c5d8 Mon Sep 17 00:00:00 2001 From: Bram Moolenaar <Bram@vim.org> Date: Wed, 6 May 2020 21:06:30 +0200 Subject: [PATCH 098/230] patch 8.2.0703: Vim9: closure cannot store value in outer context Problem: Vim9: closure cannot store value in outer context. Solution: Make storing value in outer context work. Make :disassemble accept a function reference. --- src/eval.c | 6 +++-- src/structs.h | 1 + src/testdir/test_vim9_disassemble.vim | 36 +++++++++++++++++++++++++++ src/testdir/test_vim9_func.vim | 26 +++++++++++++++++++ src/version.c | 2 ++ src/vim9.h | 3 ++- src/vim9compile.c | 13 +++++++--- src/vim9execute.c | 19 +++++++++++--- 8 files changed, 97 insertions(+), 9 deletions(-) diff --git a/src/eval.c b/src/eval.c index 72cb0897af..b7003a882c 100644 --- a/src/eval.c +++ b/src/eval.c @@ -4337,9 +4337,11 @@ set_ref_in_item( partial_T *pt = tv->vval.v_partial; int i; - // A partial does not have a copyID, because it cannot contain itself. - if (pt != NULL) + if (pt != NULL && pt->pt_copyID != copyID) { + // Didn't see this partial yet. + pt->pt_copyID = copyID; + abort = set_ref_in_func(pt->pt_name, pt->pt_func, copyID); if (pt->pt_dict != NULL) diff --git a/src/structs.h b/src/structs.h index 7fd325a825..69233a9673 100644 --- a/src/structs.h +++ b/src/structs.h @@ -1812,6 +1812,7 @@ struct partial_S typval_T *pt_argv; // arguments in allocated array dict_T *pt_dict; // dict for "self" + int pt_copyID; // funcstack may contain pointer to partial }; typedef struct AutoPatCmd_S AutoPatCmd; diff --git a/src/testdir/test_vim9_disassemble.vim b/src/testdir/test_vim9_disassemble.vim index 4e2caf09f1..11703416d1 100644 --- a/src/testdir/test_vim9_disassemble.vim +++ b/src/testdir/test_vim9_disassemble.vim @@ -291,6 +291,42 @@ def Test_disassemble_call() res) enddef +def s:CreateRefs() + let local = 'a' + def Append(arg: string) + local ..= arg + enddef + g:Append = Append + def Get(): string + return local + enddef + g:Get = Get +enddef + +def Test_disassemble_closure() + CreateRefs() + let res = execute('disass g:Append') + assert_match('<lambda>\d.*' .. + 'local ..= arg.*' .. + '\d LOADOUTER $0.*' .. + '\d LOAD arg\[-1\].*' .. + '\d CONCAT.*' .. + '\d STOREOUTER $0.*' .. + '\d PUSHNR 0.*' .. + '\d RETURN.*', + res) + + res = execute('disass g:Get') + assert_match('<lambda>\d.*' .. + 'return local.*' .. + '\d LOADOUTER $0.*' .. + '\d RETURN.*', + res) + + unlet g:Append + unlet g:Get +enddef + def EchoArg(arg: string): string return arg diff --git a/src/testdir/test_vim9_func.vim b/src/testdir/test_vim9_func.vim index 49dc2f2f21..83cef67c27 100644 --- a/src/testdir/test_vim9_func.vim +++ b/src/testdir/test_vim9_func.vim @@ -738,6 +738,32 @@ def Test_closure_using_argument() unlet g:UseVararg enddef +def MakeGetAndAppendRefs() + let local = 'a' + + def Append(arg: string) + local ..= arg + enddef + g:Append = Append + + def Get(): string + return local + enddef + g:Get = Get +enddef + +def Test_closure_append_get() + MakeGetAndAppendRefs() + assert_equal('a', g:Get()) + g:Append('-b') + assert_equal('a-b', g:Get()) + g:Append('-c') + assert_equal('a-b-c', g:Get()) + + unlet g:Append + unlet g:Get +enddef + def Test_nested_closure() let local = 'text' def Closure(arg: string): string diff --git a/src/version.c b/src/version.c index 523791ca0f..b507c89b28 100644 --- a/src/version.c +++ b/src/version.c @@ -746,6 +746,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 703, /**/ 702, /**/ diff --git a/src/vim9.h b/src/vim9.h index aac776af1c..709716ee3b 100644 --- a/src/vim9.h +++ b/src/vim9.h @@ -40,8 +40,9 @@ typedef enum { ISN_STOREW, // pop into window-local variable isn_arg.string ISN_STORET, // pop into tab-local variable isn_arg.string ISN_STORES, // pop into script variable isn_arg.loadstore + ISN_STOREOUTER, // pop variable into outer scope isn_arg.number ISN_STORESCRIPT, // pop into script variable isn_arg.script - ISN_STOREOPT, // pop into option isn_arg.string + ISN_STOREOPT, // pop into option isn_arg.string ISN_STOREENV, // pop into environment variable isn_arg.string ISN_STOREREG, // pop into register isn_arg.number // ISN_STOREOTHER, // pop into other script variable isn_arg.other. diff --git a/src/vim9compile.c b/src/vim9compile.c index 42fc0749ad..5e29cc0156 100644 --- a/src/vim9compile.c +++ b/src/vim9compile.c @@ -4496,7 +4496,11 @@ compile_assignment(char_u *arg, exarg_T *eap, cmdidx_T cmdidx, cctx_T *cctx) generate_LOADV(cctx, name + 2, TRUE); break; case dest_local: - generate_LOAD(cctx, ISN_LOAD, lvar->lv_idx, NULL, type); + if (lvar->lv_from_outer) + generate_LOAD(cctx, ISN_LOADOUTER, lvar->lv_idx, + NULL, type); + else + generate_LOAD(cctx, ISN_LOAD, lvar->lv_idx, NULL, type); break; } } @@ -4713,8 +4717,8 @@ compile_assignment(char_u *arg, exarg_T *eap, cmdidx_T cmdidx, cctx_T *cctx) // optimization: turn "var = 123" from ISN_PUSHNR + ISN_STORE // into ISN_STORENR - if (instr->ga_len == instr_count + 1 - && isn->isn_type == ISN_PUSHNR) + if (!lvar->lv_from_outer && instr->ga_len == instr_count + 1 + && isn->isn_type == ISN_PUSHNR) { varnumber_T val = isn->isn_arg.number; garray_T *stack = &cctx->ctx_type_stack; @@ -4725,6 +4729,8 @@ compile_assignment(char_u *arg, exarg_T *eap, cmdidx_T cmdidx, cctx_T *cctx) if (stack->ga_len > 0) --stack->ga_len; } + else if (lvar->lv_from_outer) + generate_STORE(cctx, ISN_STOREOUTER, lvar->lv_idx, NULL); else generate_STORE(cctx, ISN_STORE, lvar->lv_idx, NULL); } @@ -6686,6 +6692,7 @@ delete_instr(isn_T *isn) case ISN_PUSHSPEC: case ISN_RETURN: case ISN_STORE: + case ISN_STOREOUTER: case ISN_STOREV: case ISN_STORENR: case ISN_STOREREG: diff --git a/src/vim9execute.c b/src/vim9execute.c index 5915ea1dce..9651f5e9b2 100644 --- a/src/vim9execute.c +++ b/src/vim9execute.c @@ -1070,6 +1070,14 @@ call_def_function( *tv = *STACK_TV_BOT(0); break; + // store variable or argument in outer scope + case ISN_STOREOUTER: + --ectx.ec_stack.ga_len; + tv = STACK_OUT_TV_VAR(iptr->isn_arg.number); + clear_tv(tv); + *tv = *STACK_TV_BOT(0); + break; + // store s: variable in old script case ISN_STORES: { @@ -2133,7 +2141,7 @@ ex_disassemble(exarg_T *eap) int is_global = FALSE; fname = trans_function_name(&arg, &is_global, FALSE, - TFN_INT | TFN_QUIET | TFN_NO_AUTOLOAD | TFN_NO_DEREF, NULL, NULL); + TFN_INT | TFN_QUIET | TFN_NO_AUTOLOAD, NULL, NULL); if (fname == NULL) { semsg(_(e_invarg2), eap->arg); @@ -2275,12 +2283,17 @@ ex_disassemble(exarg_T *eap) break; case ISN_STORE: + case ISN_STOREOUTER: + { + char *add = iptr->isn_type == ISN_STORE ? "" : "OUTER"; + if (iptr->isn_arg.number < 0) - smsg("%4d STORE arg[%lld]", current, + smsg("%4d STORE%s arg[%lld]", current, add, (long long)(iptr->isn_arg.number + STACK_FRAME_SIZE)); else - smsg("%4d STORE $%lld", current, + smsg("%4d STORE%s $%lld", current, add, (long long)(iptr->isn_arg.number)); + } break; case ISN_STOREV: smsg("%4d STOREV v:%s", current, From f821ddaa0c27230012a6bffbec6fb0ab2f101171 Mon Sep 17 00:00:00 2001 From: Bram Moolenaar <Bram@vim.org> Date: Wed, 6 May 2020 22:18:17 +0200 Subject: [PATCH 099/230] patch 8.2.0704: Vim9: memory leak in disassemble test Problem: Vim9: memory leak in disassemble test. Solution: Decrement refcount when creating funccal. --- src/version.c | 2 ++ src/vim9execute.c | 28 +++++++++++++++++++++++++++- 2 files changed, 29 insertions(+), 1 deletion(-) diff --git a/src/version.c b/src/version.c index b507c89b28..f22b37d4cb 100644 --- a/src/version.c +++ b/src/version.c @@ -746,6 +746,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 704, /**/ 703, /**/ diff --git a/src/vim9execute.c b/src/vim9execute.c index 9651f5e9b2..cc677b0013 100644 --- a/src/vim9execute.c +++ b/src/vim9execute.c @@ -270,7 +270,7 @@ handle_closure_in_use(ectx_T *ectx, int free_arguments) int refcount = tv->vval.v_partial->pt_refcount; int i; - // A Reference in a local variables doesn't count, its get + // A Reference in a local variables doesn't count, it gets // unreferenced on return. for (i = 0; i < dfunc->df_varcount; ++i) { @@ -323,6 +323,32 @@ handle_closure_in_use(ectx_T *ectx, int free_arguments) for (idx = 0; idx < dfunc->df_varcount; ++idx) { tv = STACK_TV(ectx->ec_frame_idx + STACK_FRAME_SIZE + idx); + + // Do not copy a partial created for a local function. + // TODO: this won't work if the closure actually uses it. But when + // keeping it it gets complicated: it will create a reference cycle + // inside the partial, thus needs special handling for garbage + // collection. + if (tv->v_type == VAR_PARTIAL && tv->vval.v_partial != NULL) + { + int i; + typval_T *ctv; + + for (i = 0; i < dfunc->df_closure_count; ++i) + { + ctv = STACK_TV(ectx->ec_frame_idx + STACK_FRAME_SIZE + + dfunc->df_varcount + i); + if (tv->vval.v_partial == ctv->vval.v_partial) + break; + } + if (i < dfunc->df_closure_count) + { + (stack + argcount + STACK_FRAME_SIZE + idx)->v_type = + VAR_UNKNOWN; + continue; + } + } + *(stack + argcount + STACK_FRAME_SIZE + idx) = *tv; tv->v_type = VAR_UNKNOWN; } From 3657686a0e8fd07428a25c2cf9efcc8b5d33f895 Mon Sep 17 00:00:00 2001 From: Bram Moolenaar <Bram@vim.org> Date: Wed, 6 May 2020 22:25:05 +0200 Subject: [PATCH 100/230] patch 8.2.0705: indent tests don't run on CI for FreeBSD Problem: Indent tests don't run on CI for FreeBSD. Solution: Set modeline. (Ozaki Kiichi, closes #6048) --- .cirrus.yml | 3 +-- runtime/indent/testdir/runtest.vim | 1 + src/version.c | 2 ++ 3 files changed, 4 insertions(+), 2 deletions(-) diff --git a/.cirrus.yml b/.cirrus.yml index 907d10eb4e..97fb0f1f6a 100644 --- a/.cirrus.yml +++ b/.cirrus.yml @@ -13,5 +13,4 @@ freebsd_12_task: - make -j${NPROC} - src/vim --version test_script: - # Runtime Indent tests do not work, run only the normal test suite - - cd src && make test + - make test diff --git a/runtime/indent/testdir/runtest.vim b/runtime/indent/testdir/runtest.vim index b234a1ad94..6bbd33cacd 100644 --- a/runtime/indent/testdir/runtest.vim +++ b/runtime/indent/testdir/runtest.vim @@ -10,6 +10,7 @@ filetype indent on syn on set nowrapscan set report=9999 +set modeline au! SwapExists * call HandleSwapExists() func HandleSwapExists() diff --git a/src/version.c b/src/version.c index f22b37d4cb..45f67c951c 100644 --- a/src/version.c +++ b/src/version.c @@ -746,6 +746,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 705, /**/ 704, /**/ From 8a1c1013153a7f08e014facac883a1987985d6db Mon Sep 17 00:00:00 2001 From: Bram Moolenaar <Bram@vim.org> Date: Thu, 7 May 2020 14:07:25 +0200 Subject: [PATCH 101/230] patch 8.2.0706: Vim9: using assert_fails() causes function to finish Problem: Vim9: using assert_fails() causes function to finish. Solution: Check did_emsg instead of called_emsg. --- src/testdir/test_vim9_disassemble.vim | 2 ++ src/testdir/test_vim9_script.vim | 7 ------- src/version.c | 2 ++ src/vim9execute.c | 4 ++-- 4 files changed, 6 insertions(+), 9 deletions(-) diff --git a/src/testdir/test_vim9_disassemble.vim b/src/testdir/test_vim9_disassemble.vim index 11703416d1..5c4ecd2907 100644 --- a/src/testdir/test_vim9_disassemble.vim +++ b/src/testdir/test_vim9_disassemble.vim @@ -17,6 +17,7 @@ def s:ScriptFuncLoad(arg: string) buffers echo arg echo local + echo &lines echo v:version echo s:scriptvar echo g:globalvar @@ -42,6 +43,7 @@ def Test_disassemble_load() ' EXEC \+buffers.*' .. ' LOAD arg\[-1\].*' .. ' LOAD $0.*' .. + ' LOADOPT &lines.*' .. ' LOADV v:version.*' .. ' LOADS s:scriptvar from .*test_vim9_disassemble.vim.*' .. ' LOADG g:globalvar.*' .. diff --git a/src/testdir/test_vim9_script.vim b/src/testdir/test_vim9_script.vim index 40aae46a14..7768eb082b 100644 --- a/src/testdir/test_vim9_script.vim +++ b/src/testdir/test_vim9_script.vim @@ -1311,13 +1311,6 @@ def Test_vim9_comment() 'catch /pat/# comment', 'endtry', ], 'E488:') - CheckScriptFailure([ - 'vim9script', - 'try', - ' throw "pat"', - 'catch /pat/# comment', - 'endtry', - ], 'E605:') CheckDefFailure([ 'try', 'echo "yes"', diff --git a/src/version.c b/src/version.c index 45f67c951c..ea8b2a5c16 100644 --- a/src/version.c +++ b/src/version.c @@ -746,6 +746,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 706, /**/ 705, /**/ diff --git a/src/vim9execute.c b/src/vim9execute.c index cc677b0013..a505647df5 100644 --- a/src/vim9execute.c +++ b/src/vim9execute.c @@ -458,7 +458,7 @@ call_bfunc(int func_idx, int argcount, ectx_T *ectx) { typval_T argvars[MAX_FUNC_ARGS]; int idx; - int called_emsg_before = called_emsg; + int did_emsg_before = did_emsg; if (call_prepare(argcount, argvars, ectx) == FAIL) return FAIL; @@ -470,7 +470,7 @@ call_bfunc(int func_idx, int argcount, ectx_T *ectx) for (idx = 0; idx < argcount; ++idx) clear_tv(&argvars[idx]); - if (called_emsg != called_emsg_before) + if (did_emsg != did_emsg_before) return FAIL; return OK; } From f391586f3f6a304d3bb0160ab75bdd9d758bd2da Mon Sep 17 00:00:00 2001 From: Bram Moolenaar <Bram@vim.org> Date: Thu, 7 May 2020 14:37:19 +0200 Subject: [PATCH 102/230] patch 8.2.0707: Vim9 function test fails Problem: Vim9 function test fails. Solution: Adjust expected error code. --- src/testdir/test_vim9_func.vim | 2 +- src/version.c | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/src/testdir/test_vim9_func.vim b/src/testdir/test_vim9_func.vim index 83cef67c27..ab5f9ecd2d 100644 --- a/src/testdir/test_vim9_func.vim +++ b/src/testdir/test_vim9_func.vim @@ -656,7 +656,7 @@ enddef def Test_unknown_function() CheckDefExecFailure([ 'let Ref: func = function("NotExist")', - 'delfunc g:NotExist'], 'E700:') + 'delfunc g:NotExist'], 'E130:') enddef def RefFunc(Ref: func(string): string): string diff --git a/src/version.c b/src/version.c index ea8b2a5c16..c004e33e56 100644 --- a/src/version.c +++ b/src/version.c @@ -746,6 +746,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 707, /**/ 706, /**/ From 61a89816996a0cad0d711c91e6e7cea9a9101211 Mon Sep 17 00:00:00 2001 From: Bram Moolenaar <Bram@vim.org> Date: Thu, 7 May 2020 16:58:17 +0200 Subject: [PATCH 103/230] patch 8.2.0708: Vim9: constant expressions are not simplified Problem: Vim9: constant expressions are not simplified. Solution: Simplify string concatenation. --- src/testdir/test_vim9_disassemble.vim | 16 +- src/testdir/test_vim9_expr.vim | 6 +- src/version.c | 2 + src/vim9compile.c | 859 +++++++++++++++----------- 4 files changed, 516 insertions(+), 367 deletions(-) diff --git a/src/testdir/test_vim9_disassemble.vim b/src/testdir/test_vim9_disassemble.vim index 5c4ecd2907..5cb7383e94 100644 --- a/src/testdir/test_vim9_disassemble.vim +++ b/src/testdir/test_vim9_disassemble.vim @@ -996,9 +996,7 @@ def Test_disassemble_echomsg() '\d PUSHS "message".*' .. '\d ECHOMSG 2.*' .. "echoerr 'went' .. 'wrong'.*" .. - '\d PUSHS "went".*' .. - '\d PUSHS "wrong".*' .. - '\d CONCAT.*' .. + '\d PUSHS "wentwrong".*' .. '\d ECHOERR 1.*' .. '\d PUSHNR 0.*' .. '\d RETURN', @@ -1037,4 +1035,16 @@ def Test_display_func() res3) enddef +def s:ConcatStrings(): string + return 'one' .. 'two' .. 'three' +enddef + +def Test_simplify_const_expr() + let res = execute('disass s:ConcatStrings') + assert_match('\<SNR>\d*_ConcatStrings.*' .. + '\d PUSHS "onetwothree".*' .. + '\d RETURN', + res) +enddef + " vim: ts=8 sw=2 sts=2 expandtab tw=80 fdm=marker diff --git a/src/testdir/test_vim9_expr.vim b/src/testdir/test_vim9_expr.vim index 68eb40d2e4..df6860c77e 100644 --- a/src/testdir/test_vim9_expr.vim +++ b/src/testdir/test_vim9_expr.vim @@ -485,8 +485,10 @@ def Test_expr5() assert_equal(-6, g:alsoint - g:anint) assert_equal('hello', 'hel' .. 'lo') - assert_equal('hello 123', 'hello ' .. - 123) + " TODO: a line break here doesn't work +" assert_equal('hello 123', 'hello ' .. +" 123) + assert_equal('hello 123', 'hello ' .. 123) assert_equal('123 hello', 123 .. ' hello') assert_equal('123456', 123 .. 456) diff --git a/src/version.c b/src/version.c index c004e33e56..14504da4fe 100644 --- a/src/version.c +++ b/src/version.c @@ -746,6 +746,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 708, /**/ 707, /**/ diff --git a/src/vim9compile.c b/src/vim9compile.c index 5e29cc0156..5f6ce7492b 100644 --- a/src/vim9compile.c +++ b/src/vim9compile.c @@ -1040,6 +1040,43 @@ generate_PUSHFUNC(cctx_T *cctx, char_u *name, type_T *type) return OK; } +/* + * Generate a PUSH instruction for "tv". + */ + static int +generate_tv_PUSH(cctx_T *cctx, typval_T *tv) +{ + switch (tv->v_type) + { + case VAR_BOOL: + generate_PUSHBOOL(cctx, tv->vval.v_number); + break; + case VAR_SPECIAL: + generate_PUSHSPEC(cctx, tv->vval.v_number); + break; + case VAR_NUMBER: + generate_PUSHNR(cctx, tv->vval.v_number); + break; +#ifdef FEAT_FLOAT + case VAR_FLOAT: + generate_PUSHF(cctx, tv->vval.v_float); + break; +#endif + case VAR_BLOB: + generate_PUSHBLOB(cctx, tv->vval.v_blob); + tv->vval.v_blob = NULL; + break; + case VAR_STRING: + generate_PUSHS(cctx, tv->vval.v_string); + tv->vval.v_string = NULL; + break; + default: + iemsg("constant type not supported"); + return FAIL; + } + return OK; +} + /* * Generate an ISN_STORE instruction. */ @@ -3180,6 +3217,452 @@ get_vim_constant(char_u **arg, typval_T *rettv) } } +/* + * Evaluate an expression that is a constant: + * has(arg) + * + * Also handle: + * ! in front logical NOT + * + * Return FAIL if the expression is not a constant. + */ + static int +evaluate_const_expr7(char_u **arg, cctx_T *cctx UNUSED, typval_T *tv) +{ + typval_T argvars[2]; + char_u *start_leader, *end_leader; + int has_call = FALSE; + + /* + * Skip '!' characters. They are handled later. + * TODO: '-' and '+' characters + */ + start_leader = *arg; + while (**arg == '!') + *arg = skipwhite(*arg + 1); + end_leader = *arg; + + /* + * Recognize only a few types of constants for now. + */ + if (STRNCMP("true", *arg, 4) == 0 && !ASCII_ISALNUM((*arg)[4])) + { + tv->v_type = VAR_BOOL; + tv->vval.v_number = VVAL_TRUE; + *arg += 4; + return OK; + } + if (STRNCMP("false", *arg, 5) == 0 && !ASCII_ISALNUM((*arg)[5])) + { + tv->v_type = VAR_BOOL; + tv->vval.v_number = VVAL_FALSE; + *arg += 5; + return OK; + } + + if (STRNCMP("has(", *arg, 4) == 0) + { + has_call = TRUE; + *arg = skipwhite(*arg + 4); + } + + if (**arg == '"') + { + if (get_string_tv(arg, tv, TRUE) == FAIL) + return FAIL; + } + else if (**arg == '\'') + { + if (get_lit_string_tv(arg, tv, TRUE) == FAIL) + return FAIL; + } + else + return FAIL; + + if (has_call) + { + *arg = skipwhite(*arg); + if (**arg != ')') + return FAIL; + *arg = *arg + 1; + + argvars[0] = *tv; + argvars[1].v_type = VAR_UNKNOWN; + tv->v_type = VAR_NUMBER; + tv->vval.v_number = 0; + f_has(argvars, tv); + clear_tv(&argvars[0]); + + while (start_leader < end_leader) + { + if (*start_leader == '!') + tv->vval.v_number = !tv->vval.v_number; + ++start_leader; + } + } + else if (end_leader > start_leader) + { + clear_tv(tv); + return FAIL; + } + + return OK; +} + +/* + * * number multiplication + * / number division + * % number modulo + */ + static int +evaluate_const_expr6(char_u **arg, cctx_T *cctx, typval_T *tv) +{ + char_u *op; + + // get the first variable + if (evaluate_const_expr7(arg, cctx, tv) == FAIL) + return FAIL; + + /* + * Repeat computing, until no "*", "/" or "%" is following. + */ + for (;;) + { + op = skipwhite(*arg); + if (*op != '*' && *op != '/' && *op != '%') + break; + // TODO: not implemented yet. + clear_tv(tv); + return FAIL; + } + return OK; +} + +/* + * + number addition + * - number subtraction + * .. string concatenation + */ + static int +evaluate_const_expr5(char_u **arg, cctx_T *cctx, typval_T *tv) +{ + char_u *op; + int oplen; + + // get the first variable + if (evaluate_const_expr6(arg, cctx, tv) == FAIL) + return FAIL; + + /* + * Repeat computing, until no "+", "-" or ".." is following. + */ + for (;;) + { + op = skipwhite(*arg); + if (*op != '+' && *op != '-' && !(*op == '.' && (*(*arg + 1) == '.'))) + break; + oplen = (*op == '.' ? 2 : 1); + + if (!IS_WHITE_OR_NUL(**arg) || !IS_WHITE_OR_NUL(op[oplen])) + { + clear_tv(tv); + return FAIL; + } + + if (*op == '.' && tv->v_type == VAR_STRING) + { + typval_T tv2; + size_t len1; + char_u *s1, *s2; + + tv2.v_type = VAR_UNKNOWN; + *arg = skipwhite(op + oplen); + + // TODO: what if we fail??? + if (may_get_next_line(op + oplen, arg, cctx) == FAIL) + return FAIL; + + // get the second variable + if (evaluate_const_expr6(arg, cctx, &tv2) == FAIL) + { + clear_tv(tv); + return FAIL; + } + if (tv2.v_type != VAR_STRING) + { + clear_tv(tv); + clear_tv(&tv2); + return FAIL; + } + s1 = tv->vval.v_string; + len1 = STRLEN(s1); + s2 = tv2.vval.v_string; + tv->vval.v_string = alloc((int)(len1 + STRLEN(s2) + 1)); + if (tv->vval.v_string == NULL) + { + vim_free(s1); + vim_free(s2); + return FAIL; + } + mch_memmove(tv->vval.v_string, s1, len1); + STRCPY(tv->vval.v_string + len1, s2); + continue; + } + + // TODO: Not implemented yet. + clear_tv(tv); + return FAIL; + } + return OK; +} + + static exptype_T +get_compare_type(char_u *p, int *len, int *type_is) +{ + exptype_T type = EXPR_UNKNOWN; + int i; + + switch (p[0]) + { + case '=': if (p[1] == '=') + type = EXPR_EQUAL; + else if (p[1] == '~') + type = EXPR_MATCH; + break; + case '!': if (p[1] == '=') + type = EXPR_NEQUAL; + else if (p[1] == '~') + type = EXPR_NOMATCH; + break; + case '>': if (p[1] != '=') + { + type = EXPR_GREATER; + *len = 1; + } + else + type = EXPR_GEQUAL; + break; + case '<': if (p[1] != '=') + { + type = EXPR_SMALLER; + *len = 1; + } + else + type = EXPR_SEQUAL; + break; + case 'i': if (p[1] == 's') + { + // "is" and "isnot"; but not a prefix of a name + if (p[2] == 'n' && p[3] == 'o' && p[4] == 't') + *len = 5; + i = p[*len]; + if (!isalnum(i) && i != '_') + { + type = *len == 2 ? EXPR_IS : EXPR_ISNOT; + *type_is = TRUE; + } + } + break; + } + return type; +} + +/* + * Only comparing strings is supported right now. + * expr5a == expr5b + */ + static int +evaluate_const_expr4(char_u **arg, cctx_T *cctx UNUSED, typval_T *tv) +{ + exptype_T type = EXPR_UNKNOWN; + char_u *p; + int len = 2; + int type_is = FALSE; + + // get the first variable + if (evaluate_const_expr5(arg, cctx, tv) == FAIL) + return FAIL; + + p = skipwhite(*arg); + type = get_compare_type(p, &len, &type_is); + + /* + * If there is a comparative operator, use it. + */ + if (type != EXPR_UNKNOWN) + { + typval_T tv2; + char_u *s1, *s2; + char_u buf1[NUMBUFLEN], buf2[NUMBUFLEN]; + int n; + + // TODO: Only string == string is supported now + if (tv->v_type != VAR_STRING) + return FAIL; + if (type != EXPR_EQUAL) + return FAIL; + + // get the second variable + init_tv(&tv2); + *arg = skipwhite(p + len); + if (evaluate_const_expr5(arg, cctx, &tv2) == FAIL + || tv2.v_type != VAR_STRING) + { + clear_tv(&tv2); + return FAIL; + } + s1 = tv_get_string_buf(tv, buf1); + s2 = tv_get_string_buf(&tv2, buf2); + n = STRCMP(s1, s2); + clear_tv(tv); + clear_tv(&tv2); + tv->v_type = VAR_BOOL; + tv->vval.v_number = n == 0 ? VVAL_TRUE : VVAL_FALSE; + } + + return OK; +} + +static int evaluate_const_expr3(char_u **arg, cctx_T *cctx, typval_T *tv); + +/* + * Compile constant || or &&. + */ + static int +evaluate_const_and_or(char_u **arg, cctx_T *cctx, char *op, typval_T *tv) +{ + char_u *p = skipwhite(*arg); + int opchar = *op; + + if (p[0] == opchar && p[1] == opchar) + { + int val = tv2bool(tv); + + /* + * Repeat until there is no following "||" or "&&" + */ + while (p[0] == opchar && p[1] == opchar) + { + typval_T tv2; + + if (!VIM_ISWHITE(**arg) || !VIM_ISWHITE(p[2])) + return FAIL; + + // eval the next expression + *arg = skipwhite(p + 2); + tv2.v_type = VAR_UNKNOWN; + tv2.v_lock = 0; + if ((opchar == '|' ? evaluate_const_expr3(arg, cctx, &tv2) + : evaluate_const_expr4(arg, cctx, &tv2)) == FAIL) + { + clear_tv(&tv2); + return FAIL; + } + if ((opchar == '&') == val) + { + // false || tv2 or true && tv2: use tv2 + clear_tv(tv); + *tv = tv2; + val = tv2bool(tv); + } + else + clear_tv(&tv2); + p = skipwhite(*arg); + } + } + + return OK; +} + +/* + * Evaluate an expression that is a constant: expr4 && expr4 && expr4 + * Return FAIL if the expression is not a constant. + */ + static int +evaluate_const_expr3(char_u **arg, cctx_T *cctx, typval_T *tv) +{ + // evaluate the first expression + if (evaluate_const_expr4(arg, cctx, tv) == FAIL) + return FAIL; + + // || and && work almost the same + return evaluate_const_and_or(arg, cctx, "&&", tv); +} + +/* + * Evaluate an expression that is a constant: expr3 || expr3 || expr3 + * Return FAIL if the expression is not a constant. + */ + static int +evaluate_const_expr2(char_u **arg, cctx_T *cctx, typval_T *tv) +{ + // evaluate the first expression + if (evaluate_const_expr3(arg, cctx, tv) == FAIL) + return FAIL; + + // || and && work almost the same + return evaluate_const_and_or(arg, cctx, "||", tv); +} + +/* + * Evaluate an expression that is a constant: expr2 ? expr1 : expr1 + * E.g. for "has('feature')". + * This does not produce error messages. "tv" should be cleared afterwards. + * Return FAIL if the expression is not a constant. + */ + static int +evaluate_const_expr1(char_u **arg, cctx_T *cctx, typval_T *tv) +{ + char_u *p; + + // evaluate the first expression + if (evaluate_const_expr2(arg, cctx, tv) == FAIL) + return FAIL; + + p = skipwhite(*arg); + if (*p == '?') + { + int val = tv2bool(tv); + typval_T tv2; + + // require space before and after the ? + if (!VIM_ISWHITE(**arg) || !VIM_ISWHITE(p[1])) + return FAIL; + + // evaluate the second expression; any type is accepted + clear_tv(tv); + *arg = skipwhite(p + 1); + if (evaluate_const_expr1(arg, cctx, tv) == FAIL) + return FAIL; + + // Check for the ":". + p = skipwhite(*arg); + if (*p != ':' || !VIM_ISWHITE(**arg) || !VIM_ISWHITE(p[1])) + return FAIL; + + // evaluate the third expression + *arg = skipwhite(p + 1); + tv2.v_type = VAR_UNKNOWN; + if (evaluate_const_expr1(arg, cctx, &tv2) == FAIL) + { + clear_tv(&tv2); + return FAIL; + } + if (val) + { + // use the expr after "?" + clear_tv(&tv2); + } + else + { + // use the expr after ":" + clear_tv(tv); + *tv = tv2; + } + } + return OK; +} + /* * Compile code to apply '-', '+' and '!'. */ @@ -3525,34 +4008,8 @@ compile_expr7(char_u **arg, cctx_T *cctx) start_leader = end_leader; // don't apply again below // push constant - switch (rettv.v_type) - { - case VAR_BOOL: - generate_PUSHBOOL(cctx, rettv.vval.v_number); - break; - case VAR_SPECIAL: - generate_PUSHSPEC(cctx, rettv.vval.v_number); - break; - case VAR_NUMBER: - generate_PUSHNR(cctx, rettv.vval.v_number); - break; -#ifdef FEAT_FLOAT - case VAR_FLOAT: - generate_PUSHF(cctx, rettv.vval.v_float); - break; -#endif - case VAR_BLOB: - generate_PUSHBLOB(cctx, rettv.vval.v_blob); - rettv.vval.v_blob = NULL; - break; - case VAR_STRING: - generate_PUSHS(cctx, rettv.vval.v_string); - rettv.vval.v_string = NULL; - break; - default: - iemsg("constant type missing"); - return FAIL; - } + if (generate_tv_PUSH(cctx, &rettv) == FAIL) + return FAIL; } else if (ret == NOTDONE) { @@ -3682,57 +4139,6 @@ compile_expr5(char_u **arg, cctx_T *cctx) return OK; } - static exptype_T -get_compare_type(char_u *p, int *len, int *type_is) -{ - exptype_T type = EXPR_UNKNOWN; - int i; - - switch (p[0]) - { - case '=': if (p[1] == '=') - type = EXPR_EQUAL; - else if (p[1] == '~') - type = EXPR_MATCH; - break; - case '!': if (p[1] == '=') - type = EXPR_NEQUAL; - else if (p[1] == '~') - type = EXPR_NOMATCH; - break; - case '>': if (p[1] != '=') - { - type = EXPR_GREATER; - *len = 1; - } - else - type = EXPR_GEQUAL; - break; - case '<': if (p[1] != '=') - { - type = EXPR_SMALLER; - *len = 1; - } - else - type = EXPR_SEQUAL; - break; - case 'i': if (p[1] == 's') - { - // "is" and "isnot"; but not a prefix of a name - if (p[2] == 'n' && p[3] == 'o' && p[4] == 't') - *len = 5; - i = p[*len]; - if (!isalnum(i) && i != '_') - { - type = *len == 2 ? EXPR_IS : EXPR_ISNOT; - *type_is = TRUE; - } - } - break; - } - return type; -} - /* * expr5a == expr5b * expr5a =~ expr5b @@ -3936,12 +4342,19 @@ compile_expr2(char_u **arg, cctx_T *cctx) compile_expr1(char_u **arg, cctx_T *cctx) { char_u *p; + typval_T tv; - // TODO: Try parsing as a constant. If that works just one PUSH + // Evaluate the first expression. + // First try parsing as a constant. If that works just one PUSH // instruction needs to be generated. - - // evaluate the first expression - if (compile_expr2(arg, cctx) == FAIL) + tv.v_type = VAR_UNKNOWN; + p = *arg; + if (evaluate_const_expr2(&p, cctx, &tv) == OK) + { + *arg = p; + generate_tv_PUSH(cctx, &tv); + } + else if (compile_expr2(arg, cctx) == FAIL) return FAIL; p = skipwhite(*arg); @@ -4113,7 +4526,7 @@ compile_nested_function(exarg_T *eap, cctx_T *cctx) || generate_STORE(cctx, ISN_STORE, lvar->lv_idx, NULL) == FAIL) return NULL; - // TODO: warning for trailing? + // TODO: warning for trailing text? return (char_u *)""; } @@ -4925,284 +5338,6 @@ drop_scope(cctx_T *cctx) vim_free(scope); } -/* - * Evaluate an expression that is a constant: - * has(arg) - * - * Also handle: - * ! in front logical NOT - * - * Return FAIL if the expression is not a constant. - */ - static int -evaluate_const_expr7(char_u **arg, cctx_T *cctx UNUSED, typval_T *tv) -{ - typval_T argvars[2]; - char_u *start_leader, *end_leader; - int has_call = FALSE; - - /* - * Skip '!' characters. They are handled later. - */ - start_leader = *arg; - while (**arg == '!') - *arg = skipwhite(*arg + 1); - end_leader = *arg; - - /* - * Recognize only a few types of constants for now. - */ - if (STRNCMP("true", *arg, 4) == 0 && !ASCII_ISALNUM((*arg)[4])) - { - tv->v_type = VAR_SPECIAL; - tv->vval.v_number = VVAL_TRUE; - *arg += 4; - return OK; - } - if (STRNCMP("false", *arg, 5) == 0 && !ASCII_ISALNUM((*arg)[5])) - { - tv->v_type = VAR_SPECIAL; - tv->vval.v_number = VVAL_FALSE; - *arg += 5; - return OK; - } - - if (STRNCMP("has(", *arg, 4) == 0) - { - has_call = TRUE; - *arg = skipwhite(*arg + 4); - } - - if (**arg == '"') - { - if (get_string_tv(arg, tv, TRUE) == FAIL) - return FAIL; - } - else if (**arg == '\'') - { - if (get_lit_string_tv(arg, tv, TRUE) == FAIL) - return FAIL; - } - else - return FAIL; - - if (has_call) - { - *arg = skipwhite(*arg); - if (**arg != ')') - return FAIL; - *arg = *arg + 1; - - argvars[0] = *tv; - argvars[1].v_type = VAR_UNKNOWN; - tv->v_type = VAR_NUMBER; - tv->vval.v_number = 0; - f_has(argvars, tv); - clear_tv(&argvars[0]); - - while (start_leader < end_leader) - { - if (*start_leader == '!') - tv->vval.v_number = !tv->vval.v_number; - ++start_leader; - } - } - - return OK; -} - - static int -evaluate_const_expr4(char_u **arg, cctx_T *cctx UNUSED, typval_T *tv) -{ - exptype_T type = EXPR_UNKNOWN; - char_u *p; - int len = 2; - int type_is = FALSE; - - // get the first variable - if (evaluate_const_expr7(arg, cctx, tv) == FAIL) - return FAIL; - - p = skipwhite(*arg); - type = get_compare_type(p, &len, &type_is); - - /* - * If there is a comparative operator, use it. - */ - if (type != EXPR_UNKNOWN) - { - typval_T tv2; - char_u *s1, *s2; - char_u buf1[NUMBUFLEN], buf2[NUMBUFLEN]; - int n; - - // TODO: Only string == string is supported now - if (tv->v_type != VAR_STRING) - return FAIL; - if (type != EXPR_EQUAL) - return FAIL; - - // get the second variable - init_tv(&tv2); - *arg = skipwhite(p + len); - if (evaluate_const_expr7(arg, cctx, &tv2) == FAIL - || tv2.v_type != VAR_STRING) - { - clear_tv(&tv2); - return FAIL; - } - s1 = tv_get_string_buf(tv, buf1); - s2 = tv_get_string_buf(&tv2, buf2); - n = STRCMP(s1, s2); - clear_tv(tv); - clear_tv(&tv2); - tv->v_type = VAR_BOOL; - tv->vval.v_number = n == 0 ? VVAL_TRUE : VVAL_FALSE; - } - - return OK; -} - -static int evaluate_const_expr3(char_u **arg, cctx_T *cctx, typval_T *tv); - -/* - * Compile constant || or &&. - */ - static int -evaluate_const_and_or(char_u **arg, cctx_T *cctx, char *op, typval_T *tv) -{ - char_u *p = skipwhite(*arg); - int opchar = *op; - - if (p[0] == opchar && p[1] == opchar) - { - int val = tv2bool(tv); - - /* - * Repeat until there is no following "||" or "&&" - */ - while (p[0] == opchar && p[1] == opchar) - { - typval_T tv2; - - if (!VIM_ISWHITE(**arg) || !VIM_ISWHITE(p[2])) - return FAIL; - - // eval the next expression - *arg = skipwhite(p + 2); - tv2.v_type = VAR_UNKNOWN; - tv2.v_lock = 0; - if ((opchar == '|' ? evaluate_const_expr3(arg, cctx, &tv2) - : evaluate_const_expr4(arg, cctx, &tv2)) == FAIL) - { - clear_tv(&tv2); - return FAIL; - } - if ((opchar == '&') == val) - { - // false || tv2 or true && tv2: use tv2 - clear_tv(tv); - *tv = tv2; - val = tv2bool(tv); - } - else - clear_tv(&tv2); - p = skipwhite(*arg); - } - } - - return OK; -} - -/* - * Evaluate an expression that is a constant: expr4 && expr4 && expr4 - * Return FAIL if the expression is not a constant. - */ - static int -evaluate_const_expr3(char_u **arg, cctx_T *cctx, typval_T *tv) -{ - // evaluate the first expression - if (evaluate_const_expr4(arg, cctx, tv) == FAIL) - return FAIL; - - // || and && work almost the same - return evaluate_const_and_or(arg, cctx, "&&", tv); -} - -/* - * Evaluate an expression that is a constant: expr3 || expr3 || expr3 - * Return FAIL if the expression is not a constant. - */ - static int -evaluate_const_expr2(char_u **arg, cctx_T *cctx, typval_T *tv) -{ - // evaluate the first expression - if (evaluate_const_expr3(arg, cctx, tv) == FAIL) - return FAIL; - - // || and && work almost the same - return evaluate_const_and_or(arg, cctx, "||", tv); -} - -/* - * Evaluate an expression that is a constant: expr2 ? expr1 : expr1 - * E.g. for "has('feature')". - * This does not produce error messages. "tv" should be cleared afterwards. - * Return FAIL if the expression is not a constant. - */ - static int -evaluate_const_expr1(char_u **arg, cctx_T *cctx, typval_T *tv) -{ - char_u *p; - - // evaluate the first expression - if (evaluate_const_expr2(arg, cctx, tv) == FAIL) - return FAIL; - - p = skipwhite(*arg); - if (*p == '?') - { - int val = tv2bool(tv); - typval_T tv2; - - // require space before and after the ? - if (!VIM_ISWHITE(**arg) || !VIM_ISWHITE(p[1])) - return FAIL; - - // evaluate the second expression; any type is accepted - clear_tv(tv); - *arg = skipwhite(p + 1); - if (evaluate_const_expr1(arg, cctx, tv) == FAIL) - return FAIL; - - // Check for the ":". - p = skipwhite(*arg); - if (*p != ':' || !VIM_ISWHITE(**arg) || !VIM_ISWHITE(p[1])) - return FAIL; - - // evaluate the third expression - *arg = skipwhite(p + 1); - tv2.v_type = VAR_UNKNOWN; - if (evaluate_const_expr1(arg, cctx, &tv2) == FAIL) - { - clear_tv(&tv2); - return FAIL; - } - if (val) - { - // use the expr after "?" - clear_tv(&tv2); - } - else - { - // use the expr after ":" - clear_tv(tv); - *tv = tv2; - } - } - return OK; -} - /* * compile "if expr" * From ea554ca4faf4a0b96706ea24130c4f485b24b241 Mon Sep 17 00:00:00 2001 From: Bram Moolenaar <Bram@vim.org> Date: Thu, 7 May 2020 17:46:59 +0200 Subject: [PATCH 104/230] patch 8.2.0709: MS-Windows: compiler warning for int vs size_t Problem: MS-Windows: compiler warning for int vs size_t. Solution: Add type cast. (Mike Williams) --- src/channel.c | 2 +- src/version.c | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/src/channel.c b/src/channel.c index 2234ad5d57..0e432f9afa 100644 --- a/src/channel.c +++ b/src/channel.c @@ -1037,7 +1037,7 @@ channel_open( if (waittime == 0) waittime = 1; - sd = channel_connect(channel, addr->ai_addr, addr->ai_addrlen, + sd = channel_connect(channel, addr->ai_addr, (int)addr->ai_addrlen, &waittime); if (sd >= 0) break; diff --git a/src/version.c b/src/version.c index 14504da4fe..c7fc8ee325 100644 --- a/src/version.c +++ b/src/version.c @@ -746,6 +746,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 709, /**/ 708, /**/ From 4a070cc82e00618db279526797564cb2b4e9b060 Mon Sep 17 00:00:00 2001 From: Bram Moolenaar <Bram@vim.org> Date: Thu, 7 May 2020 18:16:35 +0200 Subject: [PATCH 105/230] patch 8.2.0710: Netbeans test sometimes fails Problem: Netbeans test sometimes fails. Solution: Mark any test using an external command as flaky. --- src/testdir/shared.vim | 3 +++ src/version.c | 2 ++ 2 files changed, 5 insertions(+) diff --git a/src/testdir/shared.vim b/src/testdir/shared.vim index fda4d03e6b..3e0929c349 100644 --- a/src/testdir/shared.vim +++ b/src/testdir/shared.vim @@ -36,6 +36,9 @@ endfunc " Run "cmd". Returns the job if using a job. func RunCommand(cmd) + " Running an external command can occasionally be slow or fail. + let g:test_is_flaky = 1 + let job = 0 if has('job') let job = job_start(a:cmd, {"stoponexit": "hup"}) diff --git a/src/version.c b/src/version.c index c7fc8ee325..2004f564d1 100644 --- a/src/version.c +++ b/src/version.c @@ -746,6 +746,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 710, /**/ 709, /**/ From b2d0e51366dea6843f991f31a457f5456d162678 Mon Sep 17 00:00:00 2001 From: Bram Moolenaar <Bram@vim.org> Date: Thu, 7 May 2020 18:37:03 +0200 Subject: [PATCH 106/230] patch 8.2.0711: temp directory might be cleared Problem: With a long running Vim the temp directory might be cleared on some systems. Solution: Lock the temp directory. (closes #6044) --- src/auto/configure | 47 ++++++++++++++++++++++++++++++++++++++++++++++ src/config.h.in | 6 ++++++ src/configure.ac | 15 +++++++++++++++ src/fileio.c | 42 +++++++++++++++++++++++++++++++++++++++++ src/globals.h | 3 +++ src/os_unix.h | 4 ++++ src/version.c | 2 ++ 7 files changed, 119 insertions(+) diff --git a/src/auto/configure b/src/auto/configure index 6087e0e5af..659ef82c91 100755 --- a/src/auto/configure +++ b/src/auto/configure @@ -13823,6 +13823,53 @@ fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for dirfd" >&5 +$as_echo_n "checking for dirfd... " >&6; } +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include <sys/types.h> +#include <dirent.h> +int +main () +{ +DIR * dir=opendir("dirname"); dirfd(dir); + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +$as_echo "yes" >&6; }; $as_echo "#define HAVE_DIRFD 1" >>confdefs.h + +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: not usable" >&5 +$as_echo "not usable" >&6; } +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for flock" >&5 +$as_echo_n "checking for flock... " >&6; } +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include <sys/file.h> +int +main () +{ +flock(10, LOCK_SH); + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +$as_echo "yes" >&6; }; $as_echo "#define HAVE_FLOCK 1" >>confdefs.h + +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: not usable" >&5 +$as_echo "not usable" >&6; } +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for sysctl" >&5 $as_echo_n "checking for sysctl... " >&6; } cat confdefs.h - <<_ACEOF >conftest.$ac_ext diff --git a/src/config.h.in b/src/config.h.in index de53ffb030..5c8c7e5561 100644 --- a/src/config.h.in +++ b/src/config.h.in @@ -484,5 +484,11 @@ /* Define if we have isnan() */ #undef HAVE_ISNAN +/* Define if we have dirfd() */ +#undef HAVE_DIRFD + +/* Define if we have flock() */ +#undef HAVE_FLOCK + /* Define to inline symbol or empty */ #undef inline diff --git a/src/configure.ac b/src/configure.ac index 687bdf95d2..8751b2e63b 100644 --- a/src/configure.ac +++ b/src/configure.ac @@ -4060,6 +4060,21 @@ AC_TRY_LINK([#include <stdio.h>], [rename("this", "that")], AC_MSG_RESULT(yes); AC_DEFINE(HAVE_RENAME), AC_MSG_RESULT(no)) +dnl check for dirfd() +AC_MSG_CHECKING(for dirfd) +AC_TRY_COMPILE( +[#include <sys/types.h> +#include <dirent.h>], +[DIR * dir=opendir("dirname"); dirfd(dir);], +AC_MSG_RESULT(yes); AC_DEFINE(HAVE_DIRFD), AC_MSG_RESULT(not usable)) + +dnl check for flock() +AC_MSG_CHECKING(for flock) +AC_TRY_COMPILE( +[#include <sys/file.h>], +[flock(10, LOCK_SH);], +AC_MSG_RESULT(yes); AC_DEFINE(HAVE_FLOCK), AC_MSG_RESULT(not usable)) + dnl sysctl() may exist but not the arguments we use AC_MSG_CHECKING(for sysctl) AC_TRY_COMPILE( diff --git a/src/fileio.c b/src/fileio.c index f05abe68c9..613f92359d 100644 --- a/src/fileio.c +++ b/src/fileio.c @@ -4620,6 +4620,42 @@ delete_recursive(char_u *name) #if defined(TEMPDIRNAMES) || defined(PROTO) static long temp_count = 0; // Temp filename counter. +# if defined(UNIX) && defined(HAVE_FLOCK) && defined(HAVE_DIRFD) +/* + * Open temporary directory and take file lock to prevent + * to be auto-cleaned. + */ + static void +vim_opentempdir(void) +{ + DIR *dp = NULL; + + if (vim_tempdir_dp != NULL) + return; + + dp = opendir((const char*)vim_tempdir); + + if (dp != NULL) + { + vim_tempdir_dp = dp; + flock(dirfd(vim_tempdir_dp), LOCK_SH); + } +} + +/* + * Close temporary directory - it automatically release file lock. + */ + static void +vim_closetempdir(void) +{ + if (vim_tempdir_dp != NULL) + { + closedir(vim_tempdir_dp); + vim_tempdir_dp = NULL; + } +} +# endif + /* * Delete the temp directory and all files it contains. */ @@ -4628,6 +4664,9 @@ vim_deltempdir(void) { if (vim_tempdir != NULL) { +# if defined(UNIX) && defined(HAVE_FLOCK) && defined(HAVE_DIRFD) + vim_closetempdir(); +# endif // remove the trailing path separator gettail(vim_tempdir)[-1] = NUL; delete_recursive(vim_tempdir); @@ -4652,6 +4691,9 @@ vim_settempdir(char_u *tempdir) STRCPY(buf, tempdir); add_pathsep(buf); vim_tempdir = vim_strsave(buf); +# if defined(UNIX) && defined(HAVE_FLOCK) && defined(HAVE_DIRFD) + vim_opentempdir(); +# endif vim_free(buf); } } diff --git a/src/globals.h b/src/globals.h index 9180befcb5..5dfb6ff3f1 100644 --- a/src/globals.h +++ b/src/globals.h @@ -758,6 +758,9 @@ EXTERN int ru_wid; // 'rulerfmt' width of ruler when non-zero EXTERN int sc_col; // column for shown command #ifdef TEMPDIRNAMES +# if defined(UNIX) && defined(HAVE_FLOCK) && defined(HAVE_DIRFD) +EXTERN DIR *vim_tempdir_dp INIT(= NULL); // File descriptor of temp dir +# endif EXTERN char_u *vim_tempdir INIT(= NULL); // Name of Vim's own temp dir. // Ends in a slash. #endif diff --git a/src/os_unix.h b/src/os_unix.h index 485e057755..9b7337ac19 100644 --- a/src/os_unix.h +++ b/src/os_unix.h @@ -204,6 +204,10 @@ # endif #endif +#ifdef HAVE_FLOCK +# include <sys/file.h> +#endif + #endif // PROTO #ifdef VMS diff --git a/src/version.c b/src/version.c index 2004f564d1..d63cc8b8c9 100644 --- a/src/version.c +++ b/src/version.c @@ -746,6 +746,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 711, /**/ 710, /**/ From 0ff5dedf0f69e56320199db7a2aad46be2a1f9b7 Mon Sep 17 00:00:00 2001 From: Bram Moolenaar <Bram@vim.org> Date: Thu, 7 May 2020 18:43:44 +0200 Subject: [PATCH 107/230] patch 8.2.0712: various code not fully tested Problem: Various code not fully tested. Solution: Add a few more tests. (Yegappan Lakshmanan, closes #6049) --- src/testdir/test_functions.vim | 16 ++++++++++++++ src/testdir/test_options.vim | 1 + src/testdir/test_system.vim | 38 ++++++++++++++++++++++++++++++++++ src/testdir/test_termcodes.vim | 26 +++++++++++++++++++++++ src/version.c | 2 ++ 5 files changed, 83 insertions(+) diff --git a/src/testdir/test_functions.vim b/src/testdir/test_functions.vim index 02b658554b..a8506a8f76 100644 --- a/src/testdir/test_functions.vim +++ b/src/testdir/test_functions.vim @@ -570,6 +570,12 @@ func Test_tolower() " invalid memory. call tolower("\xC0\x80\xC0") call tolower("123\xC0\x80\xC0") + + " Test in latin1 encoding + let save_enc = &encoding + set encoding=latin1 + call assert_equal("abc", tolower("ABC")) + let &encoding = save_enc endfunc func Test_toupper() @@ -641,6 +647,12 @@ func Test_toupper() " invalid memory. call toupper("\xC0\x80\xC0") call toupper("123\xC0\x80\xC0") + + " Test in latin1 encoding + let save_enc = &encoding + set encoding=latin1 + call assert_equal("ABC", toupper("abc")) + let &encoding = save_enc endfunc func Test_tr() @@ -1160,6 +1172,10 @@ func Test_filewritable() call assert_equal(0, filewritable('doesnotexist')) + call mkdir('Xdir') + call assert_equal(2, filewritable('Xdir')) + call delete('Xdir', 'd') + call delete('Xfilewritable') bw! endfunc diff --git a/src/testdir/test_options.vim b/src/testdir/test_options.vim index dec82885f6..ce925d8172 100644 --- a/src/testdir/test_options.vim +++ b/src/testdir/test_options.vim @@ -269,6 +269,7 @@ func Test_set_completion() " Expand terminal options. call feedkeys(":set t_A\<C-A>\<C-B>\"\<CR>", 'tx') call assert_equal('"set t_AB t_AF t_AL', @:) + call assert_fails('call feedkeys(":set <t_afoo>=\<C-A>\<CR>", "xt")', 'E474:') " Expand directories. call feedkeys(":set cdpath=./\<C-A>\<C-B>\"\<CR>", 'tx') diff --git a/src/testdir/test_system.vim b/src/testdir/test_system.vim index e69a045522..d597873895 100644 --- a/src/testdir/test_system.vim +++ b/src/testdir/test_system.vim @@ -143,3 +143,41 @@ func Test_system_with_shell_quote() call delete('Xdir with spaces', 'rf') endtry endfunc + +" Test for 'shellxquote' +func Test_Shellxquote() + CheckUnix + + let save_shell = &shell + let save_sxq = &shellxquote + let save_sxe = &shellxescape + + call writefile(['#!/bin/sh', 'echo "Cmd: [$*]" > Xlog'], 'Xtestshell') + call setfperm('Xtestshell', "r-x------") + set shell=./Xtestshell + + set shellxquote=\\" + call feedkeys(":!pwd\<CR>\<CR>", 'xt') + call assert_equal(['Cmd: [-c "pwd"]'], readfile('Xlog')) + + set shellxquote=( + call feedkeys(":!pwd\<CR>\<CR>", 'xt') + call assert_equal(['Cmd: [-c (pwd)]'], readfile('Xlog')) + + set shellxquote=\\"( + call feedkeys(":!pwd\<CR>\<CR>", 'xt') + call assert_equal(['Cmd: [-c "(pwd)"]'], readfile('Xlog')) + + set shellxescape=\"&<<()@^ + set shellxquote=( + call feedkeys(":!pwd\"&<<{}@^\<CR>\<CR>", 'xt') + call assert_equal(['Cmd: [-c (pwd^"^&^<^<{}^@^^)]'], readfile('Xlog')) + + let &shell = save_shell + let &shellxquote = save_sxq + let &shellxescape = save_sxe + call delete('Xtestshell') + call delete('Xlog') +endfunc + +" vim: shiftwidth=2 sts=2 expandtab diff --git a/src/testdir/test_termcodes.vim b/src/testdir/test_termcodes.vim index 13770c643a..49262f529b 100644 --- a/src/testdir/test_termcodes.vim +++ b/src/testdir/test_termcodes.vim @@ -1371,4 +1371,30 @@ func Test_cmdline_literal() set timeoutlen& endfunc +" Test for translation of special key codes (<xF1>, <xF2>, etc.) +func Test_Keycode_Tranlsation() + let keycodes = [ + \ ["<xUp>", "<Up>"], + \ ["<xDown>", "<Down>"], + \ ["<xLeft>", "<Left>"], + \ ["<xRight>", "<Right>"], + \ ["<xHome>", "<Home>"], + \ ["<xEnd>", "<End>"], + \ ["<zHome>", "<Home>"], + \ ["<zEnd>", "<End>"], + \ ["<xF1>", "<F1>"], + \ ["<xF2>", "<F2>"], + \ ["<xF3>", "<F3>"], + \ ["<xF4>", "<F4>"], + \ ["<S-xF1>", "<S-F1>"], + \ ["<S-xF2>", "<S-F2>"], + \ ["<S-xF3>", "<S-F3>"], + \ ["<S-xF4>", "<S-F4>"]] + for [k1, k2] in keycodes + exe "nnoremap " .. k1 .. " 2wx" + call assert_true(maparg(k1, 'n', 0, 1).lhs == k2) + exe "nunmap " .. k1 + endfor +endfunc + " vim: shiftwidth=2 sts=2 expandtab diff --git a/src/version.c b/src/version.c index d63cc8b8c9..f9ce53b40f 100644 --- a/src/version.c +++ b/src/version.c @@ -746,6 +746,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 712, /**/ 711, /**/ From 611548105394fdb76827cd431230c9fbfed39929 Mon Sep 17 00:00:00 2001 From: Bram Moolenaar <Bram@vim.org> Date: Thu, 7 May 2020 18:51:27 +0200 Subject: [PATCH 108/230] patch 8.2.0713: the pam_environment file is not recognized Problem: The pam_environment file is not recognized. Solution: Add a filetype pattern for pamenv. (closes #6051) --- runtime/filetype.vim | 3 +++ src/testdir/test_filetype.vim | 1 + src/version.c | 2 ++ 3 files changed, 6 insertions(+) diff --git a/runtime/filetype.vim b/runtime/filetype.vim index 9fe4ecfe57..75bf5ac126 100644 --- a/runtime/filetype.vim +++ b/runtime/filetype.vim @@ -1133,6 +1133,9 @@ au BufNewFile,BufRead pf.conf setf pf " Pam conf au BufNewFile,BufRead */etc/pam.conf setf pamconf +" Pam environment +au BufNewFile,BufRead .pam_environment setf pamenv + " PApp au BufNewFile,BufRead *.papp,*.pxml,*.pxsl setf papp diff --git a/src/testdir/test_filetype.vim b/src/testdir/test_filetype.vim index e71ccd44ef..117b520723 100644 --- a/src/testdir/test_filetype.vim +++ b/src/testdir/test_filetype.vim @@ -322,6 +322,7 @@ let s:filename_checks = { \ 'openroad': ['file.or'], \ 'ora': ['file.ora'], \ 'pamconf': ['/etc/pam.conf'], + \ 'pamenv': ['/home/user/.pam_environment'], \ 'papp': ['file.papp', 'file.pxml', 'file.pxsl'], \ 'pascal': ['file.pas', 'file.dpr'], \ 'passwd': ['any/etc/passwd', 'any/etc/passwd-', 'any/etc/passwd.edit', 'any/etc/shadow', 'any/etc/shadow-', 'any/etc/shadow.edit', 'any/var/backups/passwd.bak', 'any/var/backups/shadow.bak'], diff --git a/src/version.c b/src/version.c index f9ce53b40f..2d5931ac54 100644 --- a/src/version.c +++ b/src/version.c @@ -746,6 +746,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 713, /**/ 712, /**/ From 2cfb4a2a7248eeb40112bb482ab5b15f01b20433 Mon Sep 17 00:00:00 2001 From: Bram Moolenaar <Bram@vim.org> Date: Thu, 7 May 2020 18:56:00 +0200 Subject: [PATCH 109/230] Update runtime files --- runtime/doc/options.txt | 2 +- runtime/doc/todo.txt | 31 ++++++++++--------- runtime/doc/vim9.txt | 56 +++++++++++++++++++++++++++++++---- runtime/filetype.vim | 2 +- runtime/ftplugin/dosbatch.vim | 13 ++++++-- runtime/ftplugin/man.vim | 6 ++-- runtime/plugin/gzip.vim | 6 +++- runtime/syntax/asciidoc.vim | 22 +++++++------- runtime/syntax/make.vim | 4 +-- runtime/syntax/masm.vim | 7 +++-- 10 files changed, 106 insertions(+), 43 deletions(-) diff --git a/runtime/doc/options.txt b/runtime/doc/options.txt index c29ff5ea40..cc3f5126bc 100644 --- a/runtime/doc/options.txt +++ b/runtime/doc/options.txt @@ -1,4 +1,4 @@ -*options.txt* For Vim version 8.2. Last change: 2020 Apr 10 +*options.txt* For Vim version 8.2. Last change: 2020 May 03 VIM REFERENCE MANUAL by Bram Moolenaar diff --git a/runtime/doc/todo.txt b/runtime/doc/todo.txt index fe41907145..7bc39456d9 100644 --- a/runtime/doc/todo.txt +++ b/runtime/doc/todo.txt @@ -1,4 +1,4 @@ -*todo.txt* For Vim version 8.2. Last change: 2020 Apr 30 +*todo.txt* For Vim version 8.2. Last change: 2020 May 07 VIM REFERENCE MANUAL by Bram Moolenaar @@ -39,22 +39,22 @@ browser use: https://github.com/vim/vim/issues/1234 -------------------- Known bugs and current work ----------------------- Vim9 script: -Big changes, need design: +Big changes, may need design: - Make closures work: - Grab the part of the stack that has the arguments and local vars. - Pass a pointer and offset to the closure where this stack fragment is (frame - pointer). - When a closure disappears at end of the function - nothing to do. - When a closure remains at end of the function: copy frame, attach to closure. + - call closure from not compiled context + - Create closure in a loop. Need to make a list of them. +- Having constant expr evaluation separate does not scale. + First parse the expression, then simplify, then generate code. - At the vim9 script level: Allow using a function that is defined later. Requires compiling functions only when the whole script has been sourced. Like Javascript "hoisting", but only at the script level: + 0. If script was sourced before, clear all script-local functions and + variables. (variables still to be implemented) 1. Discovery phase: Read the file to find all functions, variable declarations and imports If a variable has a constant expression we get the type, otherwise it will be "any". Follow imports recursively. 2. Compilation phase: compile :def function bodies, using declared types 3. Execution phase: Execute imports when encountered. (skip over functions) -- When sourcing a script again, also delete script-local variables. Making everything work: - Test that a script-local function in Vim9 script cannot be deleted. - Test that a function defined inside a :def function is local to that @@ -80,10 +80,6 @@ Making everything work: - eval_expr() in ex_cexpr() - eval_expr() call in dbg_parsearg() and debuggy_find() New syntax and functionality: -- define function and create funcref in one step: - let ref = def(arg: type): rettype - body - enddef Improve error checking: - "echo Func()" is an error if Func() does not return anything. Also: @@ -118,6 +114,10 @@ Further improvements: - compile options that are an expression, e.g. "expr:" in 'spellsuggest', 'foldexpr', 'foldtext', 'printexpr', 'diffexpr', 'patchexpr', 'charconvert', 'balloonexpr', 'includeexpr', 'indentexpr', 'formatexpr'. +- Make inline function work, to be used as a funcref: + let ref = def(arg: type): rettype + body + enddef - compile get_lambda_tv() in popup_add_timeout() - compile "skip" argument of searchpair() - compile "expr" and "call" expression of a channel in channel_exe_cmd()? @@ -254,9 +254,14 @@ Patch for the Haiku port: #5961 Patch to add Turkish manual. (Emir Sarı, #5641) +Patch to add getmarklist() (Yegappan, #6032) + Patch to support different color for undercurl in cterm. (Timur Celik, #6011) +When SIGTSTP is ignored, don't let CTRL-Z suspend Vim? (Kurtis Rader, #5990) +Fixed by patch #6026. Makes tests fail... + Patch to support cindent option to handle pragmas differently. (Max Rumpf, #5468) @@ -356,8 +361,6 @@ unlisted. (#4478) Patch to include reduce() function. (#5481) -When SIGTSTP is ignored, don't let CTRL-Z suspend Vim? (Kurtis Rader, #5990) - Statusline highlighting error, off by one. (#5599) Enable 'termbidi' if $VTE_VERSION >= 5703 ? diff --git a/runtime/doc/vim9.txt b/runtime/doc/vim9.txt index 525393dacb..cb880c18f5 100644 --- a/runtime/doc/vim9.txt +++ b/runtime/doc/vim9.txt @@ -1,4 +1,4 @@ -*vim9.txt* For Vim version 8.2. Last change: 2020 Apr 30 +*vim9.txt* For Vim version 8.2. Last change: 2020 May 06 VIM REFERENCE MANUAL by Bram Moolenaar @@ -125,10 +125,56 @@ The result is that functions and variables without a namespace can always be found in the script, either defined there or imported. Global functions and variables could be defined anywhere (good luck finding where!). -Global functions can be defined and deleted at nearly any time. In Vim9 -script script-local functions are defined once when the script is sourced and -cannot be deleted. Except that when the same script is sourced again all -existing script-local functions and variables are deleted. +Global functions can be still be defined and deleted at nearly any time. In +Vim9 script script-local functions are defined once when the script is sourced +and cannot be deleted. + + +Four phases when loading a Vim9 script ~ + +In legacy script the functions are created when encountered, but parsed only +when used. This allows for defining functions in any order and having them +call each other: > + func One() + call Two() + endfunc + func Two() + if cond + call One() " recursive call + endif + endfunc + call One() + +In Vim9 script the functions are compiled. If using the same functions as the +above example it is not possible to compile function One without knowing that +function Two exists. Or this would require a runtime check, which is slow and +does not allow for compile time type checking. + +When sourcing a Vim9 script this happens in four phases: +1. Cleanup: If the script was sourced before all script-local variables, + imports and functions are deleted. +2. Discovery: The script is read and encountered functions, imports and + variables are recognized. The type is parsed. Variable initializers that + are a constant are evaluated, this can give the type of the variable. +3. Compilation: Functions are compiled. The script-local functions, imports + and variables from the discovery phase are recognized and types are + checked. +4. Execution: the commands in the script are executed. Functions are skipped + over. Variable initializers are evaluated, unless they are a constant. + +The result is that items defined at the script level can be used anywhere in +the script. This allows for putting the main function at the top: > + def Main() + SubOne() + SubTwo() + enddef + def SubOne() + ... + def SubTwo() + ... + +Note that script-local variables should either have a type defined or have a +constant initializer. Otherwise an error is given for the type being unknown. Variable declarations with :let and :const ~ diff --git a/runtime/filetype.vim b/runtime/filetype.vim index 75bf5ac126..6d26ea098d 100644 --- a/runtime/filetype.vim +++ b/runtime/filetype.vim @@ -1,7 +1,7 @@ " Vim support file to detect file types " " Maintainer: Bram Moolenaar <Bram@vim.org> -" Last Change: 2020 Apr 29 +" Last Change: 2020 May 07 " Listen very carefully, I will say this only once if exists("did_load_filetypes") diff --git a/runtime/ftplugin/dosbatch.vim b/runtime/ftplugin/dosbatch.vim index 070bdc4ba2..0c5cde2503 100644 --- a/runtime/ftplugin/dosbatch.vim +++ b/runtime/ftplugin/dosbatch.vim @@ -1,7 +1,7 @@ " Vim filetype plugin file " Language: MS-DOS .bat files " Maintainer: Mike Williams <mrw@eandem.co.uk> -" Last Change: 14th April 2019 +" Last Change: 7th May 2020 " Only do this when not done yet for this buffer if exists("b:did_ftplugin") @@ -19,12 +19,21 @@ setlocal comments=b:rem,b:@rem,b:REM,b:@REM,::: setlocal commentstring=::\ %s setlocal formatoptions-=t formatoptions+=rol +" Lookup DOS keywords using Windows command help. +if executable('help.exe') + if has('terminal') + setlocal keywordprg=:term\ help.exe + else + setlocal keywordprg=help.exe + endif +endif + " Define patterns for the browse file filter if has("gui_win32") && !exists("b:browsefilter") let b:browsefilter = "DOS Batch Files (*.bat, *.cmd)\t*.bat;*.cmd\nAll Files (*.*)\t*.*\n" endif -let b:undo_ftplugin = "setlocal comments< formatoptions<" +let b:undo_ftplugin = "setlocal comments< formatoptions< keywordprg<" \ . "| unlet! b:browsefiler" let &cpo = s:cpo_save diff --git a/runtime/ftplugin/man.vim b/runtime/ftplugin/man.vim index ec290ab1ee..ab7f33f286 100644 --- a/runtime/ftplugin/man.vim +++ b/runtime/ftplugin/man.vim @@ -1,8 +1,8 @@ " Vim filetype plugin file " Language: man " Maintainer: Jason Franklin <vim@justemail.net> -" Previous Maintainer: SungHyun Nam <goweol@gmail.com> -" Last Change: 2020 Apr 30 +" Maintainer: SungHyun Nam <goweol@gmail.com> +" Last Change: 2020 May 07 " To make the ":Man" command available before editing a manual page, source " this script from your startup vimrc file. @@ -206,7 +206,7 @@ func <SID>GetPage(cmdmods, ...) endif let env_cmd = s:env_has_u ? 'env -u MANPAGER' : 'env MANPAGER=cat' let env_cmd .= ' GROFF_NO_SGR=1' - let man_cmd = env_cmd . ' man ' . s:GetCmdArg(sect, page) . ' 2>/dev/null | col -b' + let man_cmd = env_cmd . ' man ' . s:GetCmdArg(sect, page) . ' | col -b' silent exec "r !" . man_cmd if unsetwidth diff --git a/runtime/plugin/gzip.vim b/runtime/plugin/gzip.vim index 5e13b92d1e..ffc00f6fd6 100644 --- a/runtime/plugin/gzip.vim +++ b/runtime/plugin/gzip.vim @@ -20,7 +20,7 @@ augroup gzip " " Set binary mode before reading the file. " Use "gzip -d", gunzip isn't always available. - autocmd BufReadPre,FileReadPre *.gz,*.bz2,*.Z,*.lzma,*.xz,*.lz,*.zst setlocal bin + autocmd BufReadPre,FileReadPre *.gz,*.bz2,*.Z,*.lzma,*.xz,*.lz,*.zst,*.br setlocal bin autocmd BufReadPost,FileReadPost *.gz call gzip#read("gzip -dn") autocmd BufReadPost,FileReadPost *.bz2 call gzip#read("bzip2 -d") autocmd BufReadPost,FileReadPost *.Z call gzip#read("uncompress") @@ -28,6 +28,7 @@ augroup gzip autocmd BufReadPost,FileReadPost *.xz call gzip#read("xz -d") autocmd BufReadPost,FileReadPost *.lz call gzip#read("lzip -d") autocmd BufReadPost,FileReadPost *.zst call gzip#read("zstd -d --rm") + autocmd BufReadPost,FileReadPost *.br call gzip#read("brotli -d --rm") autocmd BufWritePost,FileWritePost *.gz call gzip#write("gzip") autocmd BufWritePost,FileWritePost *.bz2 call gzip#write("bzip2") autocmd BufWritePost,FileWritePost *.Z call gzip#write("compress -f") @@ -35,6 +36,7 @@ augroup gzip autocmd BufWritePost,FileWritePost *.xz call gzip#write("xz -z") autocmd BufWritePost,FileWritePost *.lz call gzip#write("lzip") autocmd BufWritePost,FileWritePost *.zst call gzip#write("zstd --rm") + autocmd BufWritePost,FileWritePost *.br call gzip#write("brotli --rm") autocmd FileAppendPre *.gz call gzip#appre("gzip -dn") autocmd FileAppendPre *.bz2 call gzip#appre("bzip2 -d") autocmd FileAppendPre *.Z call gzip#appre("uncompress") @@ -42,6 +44,7 @@ augroup gzip autocmd FileAppendPre *.xz call gzip#appre("xz -d") autocmd FileAppendPre *.lz call gzip#appre("lzip -d") autocmd FileAppendPre *.zst call gzip#appre("zstd -d --rm") + autocmd FileAppendPre *.br call gzip#appre("brotli -d --rm") autocmd FileAppendPost *.gz call gzip#write("gzip") autocmd FileAppendPost *.bz2 call gzip#write("bzip2") autocmd FileAppendPost *.Z call gzip#write("compress -f") @@ -49,4 +52,5 @@ augroup gzip autocmd FileAppendPost *.xz call gzip#write("xz -z") autocmd FileAppendPost *.lz call gzip#write("lzip") autocmd FileAppendPost *.zst call gzip#write("zstd --rm") + autocmd FileAppendPost *.br call gzip#write("brotli --rm") augroup END diff --git a/runtime/syntax/asciidoc.vim b/runtime/syntax/asciidoc.vim index ccb079e06b..29451f9eab 100644 --- a/runtime/syntax/asciidoc.vim +++ b/runtime/syntax/asciidoc.vim @@ -1,13 +1,15 @@ " Vim syntax file -" Language: AsciiDoc -" Author: Stuart Rackham <srackham@gmail.com> (inspired by Felix -" Obenhuber's original asciidoc.vim script). -" URL: http://asciidoc.org/ -" Licence: GPL (http://www.gnu.org) -" Remarks: Vim 6 or greater -" Last Update: 2014 Aug 29 (see Issue 240) +" Language: AsciiDoc +" Maintainer: @aerostitch on GitHub (tag me in your issue in the +" github/vim/vim repository and I'll answer when available) +" Original author: Stuart Rackham <srackham@gmail.com> (inspired by Felix +" Obenhuber's original asciidoc.vim script). +" URL: http://asciidoc.org/ +" Licence: GPL (http://www.gnu.org) +" Remarks: Vim 6 or greater +" Last Update: 2020 May 03 (see Issue 240) " Limitations: -" +" " - Nested quoted text formatting is highlighted according to the outer " format. " - If a closing Example Block delimiter may be mistaken for a title @@ -23,9 +25,7 @@ if exists("b:current_syntax") finish endif -syn clear -syn sync fromstart -syn sync linebreaks=100 +" Use the default syntax syncing. " Run :help syn-priority to review syntax matching priority. syn keyword asciidocToDo TODO FIXME CHECK TEST XXX ZZZ DEPRECATED diff --git a/runtime/syntax/make.vim b/runtime/syntax/make.vim index 2a64dcd85c..d0d7f1523b 100644 --- a/runtime/syntax/make.vim +++ b/runtime/syntax/make.vim @@ -3,7 +3,7 @@ " Maintainer: Roland Hieber <rohieb+vim-iR0jGdkV@rohieb.name>, <https://github.com/rohieb> " Previous Maintainer: Claudio Fleiner <claudio@fleiner.com> " URL: https://github.com/vim/vim/blob/master/runtime/syntax/make.vim -" Last Change: 2020 Mar 04 +" Last Change: 2020 May 03 " quit when a syntax file was already loaded if exists("b:current_syntax") @@ -73,7 +73,7 @@ syn match makePreCondit "^ *\(ifn\=\(eq\|def\)\>\|else\(\s\+ifn\=\(eq\|def\)\)\= syn match makeInclude "^ *[-s]\=include\s.*$" syn match makeStatement "^ *vpath" syn match makeExport "^ *\(export\|unexport\)\>" -syn match makeOverride "^ *override" +syn match makeOverride "^ *override\>" " Statements / Functions (GNU make) syn match makeStatement contained "(\(abspath\|addprefix\|addsuffix\|and\|basename\|call\|dir\|error\|eval\|file\|filter-out\|filter\|findstring\|firstword\|flavor\|foreach\|guile\|if\|info\|join\|lastword\|notdir\|or\|origin\|patsubst\|realpath\|shell\|sort\|strip\|subst\|suffix\|value\|warning\|wildcard\|word\|wordlist\|words\)\>"ms=s+1 diff --git a/runtime/syntax/masm.vim b/runtime/syntax/masm.vim index bb3c9681bc..abee78b86d 100644 --- a/runtime/syntax/masm.vim +++ b/runtime/syntax/masm.vim @@ -2,8 +2,7 @@ " Language: Microsoft Macro Assembler (80x86) " Orig Author: Rob Brady <robb@datatone.com> " Maintainer: Wu Yongwei <wuyongwei@gmail.com> -" Last Change: $Date: 2013/11/13 11:49:24 $ -" $Revision: 1.48 $ +" Last Change: 2020-05-07 17:04:10 +0800 " Quit when a syntax file was already loaded if exists("b:current_syntax") @@ -13,10 +12,12 @@ endif let s:cpo_save = &cpo set cpo&vim +setlocal iskeyword=@,48-57,_,36,60,62,63,@-@ + syn case ignore -syn match masmIdentifier "[@a-z_$?][@a-z0-9_$?]*" +syn match masmIdentifier "[@a-z_$?][@a-z0-9_$?<>]*" syn match masmLabel "^\s*[@a-z_$?][@a-z0-9_$?]*:"he=e-1 syn match masmDecimal "[-+]\?\d\+[dt]\?" From f0eefce93bb06037a2d45e7ea8c0ad6f1f714151 Mon Sep 17 00:00:00 2001 From: Bram Moolenaar <Bram@vim.org> Date: Thu, 7 May 2020 22:19:01 +0200 Subject: [PATCH 110/230] patch 8.2.0714: Vim9: handling constant expression does not scale Problem: Vim9: handling constant expression does not scale. Solution: Use another solution, passint typval_T. --- src/testdir/test_vim9_expr.vim | 5 +- src/version.c | 2 + src/vim9compile.c | 219 ++++++++++++++++++++++++--------- 3 files changed, 165 insertions(+), 61 deletions(-) diff --git a/src/testdir/test_vim9_expr.vim b/src/testdir/test_vim9_expr.vim index df6860c77e..3ce8b1ea8b 100644 --- a/src/testdir/test_vim9_expr.vim +++ b/src/testdir/test_vim9_expr.vim @@ -485,9 +485,8 @@ def Test_expr5() assert_equal(-6, g:alsoint - g:anint) assert_equal('hello', 'hel' .. 'lo') - " TODO: a line break here doesn't work -" assert_equal('hello 123', 'hello ' .. -" 123) + assert_equal('hello 123', 'hello ' .. + 123) assert_equal('hello 123', 'hello ' .. 123) assert_equal('123 hello', 123 .. ' hello') assert_equal('123456', 123 .. 456) diff --git a/src/version.c b/src/version.c index 2d5931ac54..fd59afd1b6 100644 --- a/src/version.c +++ b/src/version.c @@ -746,6 +746,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 714, /**/ 713, /**/ diff --git a/src/vim9compile.c b/src/vim9compile.c index 5f6ce7492b..4ebb88062c 100644 --- a/src/vim9compile.c +++ b/src/vim9compile.c @@ -1042,37 +1042,45 @@ generate_PUSHFUNC(cctx_T *cctx, char_u *name, type_T *type) /* * Generate a PUSH instruction for "tv". + * "tv" will be consumed or cleared. "tv" may be NULL; */ static int generate_tv_PUSH(cctx_T *cctx, typval_T *tv) { - switch (tv->v_type) + if (tv != NULL) { - case VAR_BOOL: - generate_PUSHBOOL(cctx, tv->vval.v_number); - break; - case VAR_SPECIAL: - generate_PUSHSPEC(cctx, tv->vval.v_number); - break; - case VAR_NUMBER: - generate_PUSHNR(cctx, tv->vval.v_number); - break; + switch (tv->v_type) + { + case VAR_UNKNOWN: + break; + case VAR_BOOL: + generate_PUSHBOOL(cctx, tv->vval.v_number); + break; + case VAR_SPECIAL: + generate_PUSHSPEC(cctx, tv->vval.v_number); + break; + case VAR_NUMBER: + generate_PUSHNR(cctx, tv->vval.v_number); + break; #ifdef FEAT_FLOAT - case VAR_FLOAT: - generate_PUSHF(cctx, tv->vval.v_float); - break; + case VAR_FLOAT: + generate_PUSHF(cctx, tv->vval.v_float); + break; #endif - case VAR_BLOB: - generate_PUSHBLOB(cctx, tv->vval.v_blob); - tv->vval.v_blob = NULL; - break; - case VAR_STRING: - generate_PUSHS(cctx, tv->vval.v_string); - tv->vval.v_string = NULL; - break; - default: - iemsg("constant type not supported"); - return FAIL; + case VAR_BLOB: + generate_PUSHBLOB(cctx, tv->vval.v_blob); + tv->vval.v_blob = NULL; + break; + case VAR_STRING: + generate_PUSHS(cctx, tv->vval.v_string); + tv->vval.v_string = NULL; + break; + default: + iemsg("constant type not supported"); + clear_tv(tv); + return FAIL; + } + tv->v_type = VAR_UNKNOWN; } return OK; } @@ -3719,7 +3727,10 @@ compile_subscript( char_u **arg, cctx_T *cctx, char_u **start_leader, - char_u *end_leader) + char_u *end_leader, + typval_T *bef1_tv, + typval_T *bef2_tv, + typval_T *new_tv) { for (;;) { @@ -3729,6 +3740,11 @@ compile_subscript( type_T *type; int argcount = 0; + if (generate_tv_PUSH(cctx, bef1_tv) == FAIL + || generate_tv_PUSH(cctx, bef2_tv) == FAIL + || generate_tv_PUSH(cctx, new_tv) == FAIL) + return FAIL; + // funcref(arg) type = ((type_T **)stack->ga_data)[stack->ga_len - 1]; @@ -3742,6 +3758,11 @@ compile_subscript( { char_u *p; + if (generate_tv_PUSH(cctx, bef1_tv) == FAIL + || generate_tv_PUSH(cctx, bef2_tv) == FAIL + || generate_tv_PUSH(cctx, new_tv) == FAIL) + return FAIL; + // something->method() // Apply the '!', '-' and '+' first: // -1.0->func() works like (-1.0)->func() @@ -3779,6 +3800,11 @@ compile_subscript( garray_T *stack; type_T **typep; + if (generate_tv_PUSH(cctx, bef1_tv) == FAIL + || generate_tv_PUSH(cctx, bef2_tv) == FAIL + || generate_tv_PUSH(cctx, new_tv) == FAIL) + return FAIL; + // list index: list[123] // TODO: more arguments // TODO: dict member dict['name'] @@ -3809,6 +3835,11 @@ compile_subscript( { char_u *p; + if (generate_tv_PUSH(cctx, bef1_tv) == FAIL + || generate_tv_PUSH(cctx, bef2_tv) == FAIL + || generate_tv_PUSH(cctx, new_tv) == FAIL) + return FAIL; + ++*arg; p = *arg; // dictionary member: dict.name @@ -3837,10 +3868,13 @@ compile_subscript( } /* - * Compile an expression at "*p" and add instructions to "instr". - * "p" is advanced until after the expression, skipping white space. + * Compile an expression at "*arg" and add instructions to "cctx->ctx_instr". + * "arg" is advanced until after the expression, skipping white space. * - * This is the equivalent of eval1(), eval2(), etc. + * If the value is a constant "new_tv" will be set. + * Before instructions are generated, any "bef_tv" will generated. + * + * This is the compiling equivalent of eval1(), eval2(), etc. */ /* @@ -3868,7 +3902,12 @@ compile_subscript( * trailing ->name() method call */ static int -compile_expr7(char_u **arg, cctx_T *cctx) +compile_expr7( + char_u **arg, + cctx_T *cctx, + typval_T *bef1_tv, + typval_T *bef2_tv, + typval_T *new_tv) { typval_T rettv; char_u *start_leader, *end_leader; @@ -4007,15 +4046,18 @@ compile_expr7(char_u **arg, cctx_T *cctx) } start_leader = end_leader; // don't apply again below - // push constant - if (generate_tv_PUSH(cctx, &rettv) == FAIL) - return FAIL; + // A constant expression can possibly be handled compile time. + *new_tv = rettv; } else if (ret == NOTDONE) { char_u *p; int r; + if (generate_tv_PUSH(cctx, bef1_tv) == FAIL + || generate_tv_PUSH(cctx, bef2_tv) == FAIL) + return FAIL; + if (!eval_isnamec1(**arg)) { semsg(_("E1015: Name expected: %s"), *arg); @@ -4032,7 +4074,8 @@ compile_expr7(char_u **arg, cctx_T *cctx) return FAIL; } - if (compile_subscript(arg, cctx, &start_leader, end_leader) == FAIL) + if (compile_subscript(arg, cctx, &start_leader, end_leader, + bef1_tv, bef2_tv, new_tv) == FAIL) return FAIL; // Now deal with prefixed '-', '+' and '!', if not done already. @@ -4045,12 +4088,16 @@ compile_expr7(char_u **arg, cctx_T *cctx) * % number modulo */ static int -compile_expr6(char_u **arg, cctx_T *cctx) +compile_expr6( + char_u **arg, + cctx_T *cctx, + typval_T *bef_tv, + typval_T *new_tv) { char_u *op; - // get the first variable - if (compile_expr7(arg, cctx) == FAIL) + // get the first expression + if (compile_expr7(arg, cctx, NULL, bef_tv, new_tv) == FAIL) return FAIL; /* @@ -4058,9 +4105,12 @@ compile_expr6(char_u **arg, cctx_T *cctx) */ for (;;) { + typval_T tv2; + op = skipwhite(*arg); if (*op != '*' && *op != '/' && *op != '%') break; + if (!IS_WHITE_OR_NUL(**arg) || !IS_WHITE_OR_NUL(op[1])) { char_u buf[3]; @@ -4073,11 +4123,32 @@ compile_expr6(char_u **arg, cctx_T *cctx) if (may_get_next_line(op + 1, arg, cctx) == FAIL) return FAIL; - // get the second variable - if (compile_expr7(arg, cctx) == FAIL) + // get the second expression + tv2.v_type = VAR_UNKNOWN; + if (compile_expr7(arg, cctx, bef_tv, new_tv, &tv2) == FAIL) return FAIL; + if (new_tv->v_type == VAR_NUMBER && tv2.v_type == VAR_NUMBER) + { + varnumber_T res = 0; - generate_two_op(cctx, op); + // both are numbers: compute the result + switch (*op) + { + case '*': res = new_tv->vval.v_number * tv2.vval.v_number; + break; + case '/': res = new_tv->vval.v_number / tv2.vval.v_number; + break; + case '%': res = new_tv->vval.v_number % tv2.vval.v_number; + break; + } + new_tv->vval.v_number = res; + } + else + { + generate_tv_PUSH(cctx, new_tv); + generate_tv_PUSH(cctx, &tv2); + generate_two_op(cctx, op); + } } return OK; @@ -4091,11 +4162,13 @@ compile_expr6(char_u **arg, cctx_T *cctx) static int compile_expr5(char_u **arg, cctx_T *cctx) { + typval_T tv1; char_u *op; int oplen; // get the first variable - if (compile_expr6(arg, cctx) == FAIL) + tv1.v_type = VAR_UNKNOWN; + if (compile_expr6(arg, cctx, NULL, &tv1) == FAIL) return FAIL; /* @@ -4103,6 +4176,8 @@ compile_expr5(char_u **arg, cctx_T *cctx) */ for (;;) { + typval_T tv2; + op = skipwhite(*arg); if (*op != '+' && *op != '-' && !(*op == '.' && (*(*arg + 1) == '.'))) break; @@ -4121,21 +4196,59 @@ compile_expr5(char_u **arg, cctx_T *cctx) if (may_get_next_line(op + oplen, arg, cctx) == FAIL) return FAIL; - // get the second variable - if (compile_expr6(arg, cctx) == FAIL) + // get the second expression + tv2.v_type = VAR_UNKNOWN; + if (compile_expr6(arg, cctx, &tv1, &tv2) == FAIL) return FAIL; - if (*op == '.') + if (*op == '+' && tv1.v_type == VAR_NUMBER && tv2.v_type == VAR_NUMBER) { - if (may_generate_2STRING(-2, cctx) == FAIL - || may_generate_2STRING(-1, cctx) == FAIL) + // add constant numbers + tv1.vval.v_number = tv1.vval.v_number + tv2.vval.v_number; + } + else if (*op == '-' && tv1.v_type == VAR_NUMBER + && tv2.v_type == VAR_NUMBER) + { + // subtract constant numbers + tv1.vval.v_number = tv1.vval.v_number - tv2.vval.v_number; + } + else if (*op == '.' && tv1.v_type == VAR_STRING + && tv2.v_type == VAR_STRING) + { + // concatenate constant strings + char_u *s1 = tv1.vval.v_string; + char_u *s2 = tv2.vval.v_string; + size_t len1 = STRLEN(s1); + + tv1.vval.v_string = alloc((int)(len1 + STRLEN(s2) + 1)); + if (tv1.vval.v_string == NULL) + { + vim_free(s1); + vim_free(s2); return FAIL; - generate_instr_drop(cctx, ISN_CONCAT, 1); + } + mch_memmove(tv1.vval.v_string, s1, len1); + STRCPY(tv1.vval.v_string + len1, s2); } else - generate_two_op(cctx, op); + { + generate_tv_PUSH(cctx, &tv1); + generate_tv_PUSH(cctx, &tv2); + if (*op == '.') + { + if (may_generate_2STRING(-2, cctx) == FAIL + || may_generate_2STRING(-1, cctx) == FAIL) + return FAIL; + generate_instr_drop(cctx, ISN_CONCAT, 1); + } + else + generate_two_op(cctx, op); + } } + // TODO: move to caller + generate_tv_PUSH(cctx, &tv1); + return OK; } @@ -4342,19 +4455,9 @@ compile_expr2(char_u **arg, cctx_T *cctx) compile_expr1(char_u **arg, cctx_T *cctx) { char_u *p; - typval_T tv; // Evaluate the first expression. - // First try parsing as a constant. If that works just one PUSH - // instruction needs to be generated. - tv.v_type = VAR_UNKNOWN; - p = *arg; - if (evaluate_const_expr2(&p, cctx, &tv) == OK) - { - *arg = p; - generate_tv_PUSH(cctx, &tv); - } - else if (compile_expr2(arg, cctx) == FAIL) + if (compile_expr2(arg, cctx) == FAIL) return FAIL; p = skipwhite(*arg); From cca34aa4bef5327eb4025850045c4c980ef4354b Mon Sep 17 00:00:00 2001 From: Bram Moolenaar <Bram@vim.org> Date: Thu, 7 May 2020 22:23:58 +0200 Subject: [PATCH 111/230] patch 8.2.0715: Vim9: leaking memory Problem: Vim9: leaking memory. Solution: Free strings after concatenating them. --- src/version.c | 2 ++ src/vim9compile.c | 2 ++ 2 files changed, 4 insertions(+) diff --git a/src/version.c b/src/version.c index fd59afd1b6..7434486490 100644 --- a/src/version.c +++ b/src/version.c @@ -746,6 +746,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 715, /**/ 714, /**/ diff --git a/src/vim9compile.c b/src/vim9compile.c index 4ebb88062c..3d3b3c30fc 100644 --- a/src/vim9compile.c +++ b/src/vim9compile.c @@ -4229,6 +4229,8 @@ compile_expr5(char_u **arg, cctx_T *cctx) } mch_memmove(tv1.vval.v_string, s1, len1); STRCPY(tv1.vval.v_string + len1, s2); + vim_free(s1); + vim_free(s2); } else { From 5c2fe644430efabf9dadfb89a9f1e82367eaf28d Mon Sep 17 00:00:00 2001 From: Bram Moolenaar <Bram@vim.org> Date: Thu, 7 May 2020 23:20:21 +0200 Subject: [PATCH 112/230] patch 8.2.0716: Vim9: another memory leak Problem: Vim9: another memory leak. Solution: Clear typval when failing. --- src/version.c | 2 ++ src/vim9compile.c | 19 +++++++++++++++---- 2 files changed, 17 insertions(+), 4 deletions(-) diff --git a/src/version.c b/src/version.c index 7434486490..c8361eba12 100644 --- a/src/version.c +++ b/src/version.c @@ -746,6 +746,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 716, /**/ 715, /**/ diff --git a/src/vim9compile.c b/src/vim9compile.c index 3d3b3c30fc..67ca3de667 100644 --- a/src/vim9compile.c +++ b/src/vim9compile.c @@ -4074,12 +4074,16 @@ compile_expr7( return FAIL; } + // Handle following "[]", ".member", etc. + // Then deal with prefixed '-', '+' and '!', if not done already. if (compile_subscript(arg, cctx, &start_leader, end_leader, - bef1_tv, bef2_tv, new_tv) == FAIL) + bef1_tv, bef2_tv, new_tv) == FAIL + || compile_leader(cctx, start_leader, end_leader) == FAIL) + { + clear_tv(new_tv); return FAIL; - - // Now deal with prefixed '-', '+' and '!', if not done already. - return compile_leader(cctx, start_leader, end_leader); + } + return OK; } /* @@ -4187,6 +4191,7 @@ compile_expr5(char_u **arg, cctx_T *cctx) { char_u buf[3]; + clear_tv(&tv1); vim_strncpy(buf, op, oplen); semsg(_(e_white_both), buf); return FAIL; @@ -4194,12 +4199,18 @@ compile_expr5(char_u **arg, cctx_T *cctx) *arg = skipwhite(op + oplen); if (may_get_next_line(op + oplen, arg, cctx) == FAIL) + { + clear_tv(&tv1); return FAIL; + } // get the second expression tv2.v_type = VAR_UNKNOWN; if (compile_expr6(arg, cctx, &tv1, &tv2) == FAIL) + { + clear_tv(&tv1); return FAIL; + } if (*op == '+' && tv1.v_type == VAR_NUMBER && tv2.v_type == VAR_NUMBER) { From 7d131b071539e73e4f8a1e6ffbb4d7bfc69a57ec Mon Sep 17 00:00:00 2001 From: Bram Moolenaar <Bram@vim.org> Date: Fri, 8 May 2020 19:10:34 +0200 Subject: [PATCH 113/230] patch 8.2.0717: Vim9: postponed constant expressions does not scale Problem: Vim9: postponed constant expressions does not scale. Solution: Add a structure to pass around postponed constants. --- src/testdir/test_vim9_disassemble.vim | 10 + src/version.c | 2 + src/vim9compile.c | 305 ++++++++++++++------------ 3 files changed, 182 insertions(+), 135 deletions(-) diff --git a/src/testdir/test_vim9_disassemble.vim b/src/testdir/test_vim9_disassemble.vim index 5cb7383e94..7f4a7ddfc2 100644 --- a/src/testdir/test_vim9_disassemble.vim +++ b/src/testdir/test_vim9_disassemble.vim @@ -1039,12 +1039,22 @@ def s:ConcatStrings(): string return 'one' .. 'two' .. 'three' enddef +def s:ComputeConst(): number + return 2 + 3 * 4 / 6 + 7 +enddef + def Test_simplify_const_expr() let res = execute('disass s:ConcatStrings') assert_match('\<SNR>\d*_ConcatStrings.*' .. '\d PUSHS "onetwothree".*' .. '\d RETURN', res) + + res = execute('disass s:ComputeConst') + assert_match('\<SNR>\d*_ComputeConst.*' .. + '\d PUSHNR 11.*' .. + '\d RETURN', + res) enddef " vim: ts=8 sw=2 sts=2 expandtab tw=80 fdm=marker diff --git a/src/version.c b/src/version.c index c8361eba12..ba81d68092 100644 --- a/src/version.c +++ b/src/version.c @@ -746,6 +746,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 717, /**/ 716, /**/ diff --git a/src/vim9compile.c b/src/vim9compile.c index 67ca3de667..079d160083 100644 --- a/src/vim9compile.c +++ b/src/vim9compile.c @@ -1040,51 +1040,6 @@ generate_PUSHFUNC(cctx_T *cctx, char_u *name, type_T *type) return OK; } -/* - * Generate a PUSH instruction for "tv". - * "tv" will be consumed or cleared. "tv" may be NULL; - */ - static int -generate_tv_PUSH(cctx_T *cctx, typval_T *tv) -{ - if (tv != NULL) - { - switch (tv->v_type) - { - case VAR_UNKNOWN: - break; - case VAR_BOOL: - generate_PUSHBOOL(cctx, tv->vval.v_number); - break; - case VAR_SPECIAL: - generate_PUSHSPEC(cctx, tv->vval.v_number); - break; - case VAR_NUMBER: - generate_PUSHNR(cctx, tv->vval.v_number); - break; -#ifdef FEAT_FLOAT - case VAR_FLOAT: - generate_PUSHF(cctx, tv->vval.v_float); - break; -#endif - case VAR_BLOB: - generate_PUSHBLOB(cctx, tv->vval.v_blob); - tv->vval.v_blob = NULL; - break; - case VAR_STRING: - generate_PUSHS(cctx, tv->vval.v_string); - tv->vval.v_string = NULL; - break; - default: - iemsg("constant type not supported"); - clear_tv(tv); - return FAIL; - } - tv->v_type = VAR_UNKNOWN; - } - return OK; -} - /* * Generate an ISN_STORE instruction. */ @@ -3671,6 +3626,91 @@ evaluate_const_expr1(char_u **arg, cctx_T *cctx, typval_T *tv) return OK; } +// Structure passed between the compile_expr* functions to keep track of +// constants that have been parsed but for which no code was produced yet. If +// possible expressions on these constants are applied at compile time. If +// that is not possible, the code to push the constants needs to be generated +// before other instructions. +typedef struct { + typval_T pp_tv[10]; // stack of ppconst constants + int pp_used; // active entries in pp_tv[] +} ppconst_T; + +/* + * Generate a PUSH instruction for "tv". + * "tv" will be consumed or cleared. + * Nothing happens if "tv" is NULL or of type VAR_UNKNOWN; + */ + static int +generate_tv_PUSH(cctx_T *cctx, typval_T *tv) +{ + if (tv != NULL) + { + switch (tv->v_type) + { + case VAR_UNKNOWN: + break; + case VAR_BOOL: + generate_PUSHBOOL(cctx, tv->vval.v_number); + break; + case VAR_SPECIAL: + generate_PUSHSPEC(cctx, tv->vval.v_number); + break; + case VAR_NUMBER: + generate_PUSHNR(cctx, tv->vval.v_number); + break; +#ifdef FEAT_FLOAT + case VAR_FLOAT: + generate_PUSHF(cctx, tv->vval.v_float); + break; +#endif + case VAR_BLOB: + generate_PUSHBLOB(cctx, tv->vval.v_blob); + tv->vval.v_blob = NULL; + break; + case VAR_STRING: + generate_PUSHS(cctx, tv->vval.v_string); + tv->vval.v_string = NULL; + break; + default: + iemsg("constant type not supported"); + clear_tv(tv); + return FAIL; + } + tv->v_type = VAR_UNKNOWN; + } + return OK; +} + +/* + * Generate code for any ppconst entries. + */ + static int +generate_ppconst(cctx_T *cctx, ppconst_T *ppconst) +{ + int i; + int ret = OK; + + for (i = 0; i < ppconst->pp_used; ++i) + if (generate_tv_PUSH(cctx, &ppconst->pp_tv[i]) == FAIL) + ret = FAIL; + ppconst->pp_used = 0; + return ret; +} + +/* + * Clear ppconst constants. Used when failing. + */ + static void +clear_ppconst(ppconst_T *ppconst) +{ + int i; + + for (i = 0; i < ppconst->pp_used; ++i) + clear_tv(&ppconst->pp_tv[i]); + ppconst->pp_used = 0; +} + /* * Compile code to apply '-', '+' and '!'. */ @@ -3728,9 +3768,7 @@ compile_subscript( cctx_T *cctx, char_u **start_leader, char_u *end_leader, - typval_T *bef1_tv, - typval_T *bef2_tv, - typval_T *new_tv) + ppconst_T *ppconst) { for (;;) { @@ -3740,9 +3778,7 @@ compile_subscript( type_T *type; int argcount = 0; - if (generate_tv_PUSH(cctx, bef1_tv) == FAIL - || generate_tv_PUSH(cctx, bef2_tv) == FAIL - || generate_tv_PUSH(cctx, new_tv) == FAIL) + if (generate_ppconst(cctx, ppconst) == FAIL) return FAIL; // funcref(arg) @@ -3758,9 +3794,7 @@ compile_subscript( { char_u *p; - if (generate_tv_PUSH(cctx, bef1_tv) == FAIL - || generate_tv_PUSH(cctx, bef2_tv) == FAIL - || generate_tv_PUSH(cctx, new_tv) == FAIL) + if (generate_ppconst(cctx, ppconst) == FAIL) return FAIL; // something->method() @@ -3800,9 +3834,7 @@ compile_subscript( garray_T *stack; type_T **typep; - if (generate_tv_PUSH(cctx, bef1_tv) == FAIL - || generate_tv_PUSH(cctx, bef2_tv) == FAIL - || generate_tv_PUSH(cctx, new_tv) == FAIL) + if (generate_ppconst(cctx, ppconst) == FAIL) return FAIL; // list index: list[123] @@ -3835,9 +3867,7 @@ compile_subscript( { char_u *p; - if (generate_tv_PUSH(cctx, bef1_tv) == FAIL - || generate_tv_PUSH(cctx, bef2_tv) == FAIL - || generate_tv_PUSH(cctx, new_tv) == FAIL) + if (generate_ppconst(cctx, ppconst) == FAIL) return FAIL; ++*arg; @@ -3871,8 +3901,8 @@ compile_subscript( * Compile an expression at "*arg" and add instructions to "cctx->ctx_instr". * "arg" is advanced until after the expression, skipping white space. * - * If the value is a constant "new_tv" will be set. - * Before instructions are generated, any "bef_tv" will generated. + * If the value is a constant "ppconst->pp_ret" will be set. + * Before instructions are generated, any values in "ppconst" will generated. * * This is the compiling equivalent of eval1(), eval2(), etc. */ @@ -3905,13 +3935,11 @@ compile_subscript( compile_expr7( char_u **arg, cctx_T *cctx, - typval_T *bef1_tv, - typval_T *bef2_tv, - typval_T *new_tv) + ppconst_T *ppconst) { - typval_T rettv; char_u *start_leader, *end_leader; int ret = OK; + typval_T *rettv = &ppconst->pp_tv[ppconst->pp_used]; /* * Skip '!', '-' and '+' characters. They are handled later. @@ -3921,7 +3949,7 @@ compile_expr7( *arg = skipwhite(*arg + 1); end_leader = *arg; - rettv.v_type = VAR_UNKNOWN; + rettv->v_type = VAR_UNKNOWN; switch (**arg) { /* @@ -3937,28 +3965,28 @@ compile_expr7( case '7': case '8': case '9': - case '.': if (get_number_tv(arg, &rettv, TRUE, FALSE) == FAIL) + case '.': if (get_number_tv(arg, rettv, TRUE, FALSE) == FAIL) return FAIL; break; /* * String constant: "string". */ - case '"': if (get_string_tv(arg, &rettv, TRUE) == FAIL) + case '"': if (get_string_tv(arg, rettv, TRUE) == FAIL) return FAIL; break; /* * Literal string constant: 'str''ing'. */ - case '\'': if (get_lit_string_tv(arg, &rettv, TRUE) == FAIL) + case '\'': if (get_lit_string_tv(arg, rettv, TRUE) == FAIL) return FAIL; break; /* * Constant Vim variable. */ - case 'v': get_vim_constant(arg, &rettv); + case 'v': get_vim_constant(arg, rettv); ret = NOTDONE; break; @@ -4036,26 +4064,26 @@ compile_expr7( if (ret == FAIL) return FAIL; - if (rettv.v_type != VAR_UNKNOWN) + if (rettv->v_type != VAR_UNKNOWN) { // apply the '!', '-' and '+' before the constant - if (apply_leader(&rettv, start_leader, end_leader) == FAIL) + if (apply_leader(rettv, start_leader, end_leader) == FAIL) { - clear_tv(&rettv); + clear_tv(rettv); return FAIL; } start_leader = end_leader; // don't apply again below - // A constant expression can possibly be handled compile time. - *new_tv = rettv; + // A constant expression can possibly be handled compile time, return + // the value instead of generating code. + ++ppconst->pp_used; } else if (ret == NOTDONE) { char_u *p; int r; - if (generate_tv_PUSH(cctx, bef1_tv) == FAIL - || generate_tv_PUSH(cctx, bef2_tv) == FAIL) + if (generate_ppconst(cctx, ppconst) == FAIL) return FAIL; if (!eval_isnamec1(**arg)) @@ -4077,12 +4105,9 @@ compile_expr7( // Handle following "[]", ".member", etc. // Then deal with prefixed '-', '+' and '!', if not done already. if (compile_subscript(arg, cctx, &start_leader, end_leader, - bef1_tv, bef2_tv, new_tv) == FAIL + ppconst) == FAIL || compile_leader(cctx, start_leader, end_leader) == FAIL) - { - clear_tv(new_tv); return FAIL; - } return OK; } @@ -4093,15 +4118,15 @@ compile_expr7( */ static int compile_expr6( - char_u **arg, - cctx_T *cctx, - typval_T *bef_tv, - typval_T *new_tv) + char_u **arg, + cctx_T *cctx, + ppconst_T *ppconst) { char_u *op; + int ppconst_used = ppconst->pp_used; // get the first expression - if (compile_expr7(arg, cctx, NULL, bef_tv, new_tv) == FAIL) + if (compile_expr7(arg, cctx, ppconst) == FAIL) return FAIL; /* @@ -4109,8 +4134,6 @@ compile_expr6( */ for (;;) { - typval_T tv2; - op = skipwhite(*arg); if (*op != '*' && *op != '/' && *op != '%') break; @@ -4128,29 +4151,33 @@ compile_expr6( return FAIL; // get the second expression - tv2.v_type = VAR_UNKNOWN; - if (compile_expr7(arg, cctx, bef_tv, new_tv, &tv2) == FAIL) + if (compile_expr7(arg, cctx, ppconst) == FAIL) return FAIL; - if (new_tv->v_type == VAR_NUMBER && tv2.v_type == VAR_NUMBER) + + if (ppconst->pp_used == ppconst_used + 2 + && ppconst->pp_tv[ppconst_used].v_type == VAR_NUMBER + && ppconst->pp_tv[ppconst_used + 1].v_type == VAR_NUMBER) { + typval_T *tv1 = &ppconst->pp_tv[ppconst_used]; + typval_T *tv2 = &ppconst->pp_tv[ppconst_used + 1]; varnumber_T res = 0; // both are numbers: compute the result switch (*op) { - case '*': res = new_tv->vval.v_number * tv2.vval.v_number; + case '*': res = tv1->vval.v_number * tv2->vval.v_number; break; - case '/': res = new_tv->vval.v_number / tv2.vval.v_number; + case '/': res = tv1->vval.v_number / tv2->vval.v_number; break; - case '%': res = new_tv->vval.v_number % tv2.vval.v_number; + case '%': res = tv1->vval.v_number % tv2->vval.v_number; break; } - new_tv->vval.v_number = res; + tv1->vval.v_number = res; + --ppconst->pp_used; } else { - generate_tv_PUSH(cctx, new_tv); - generate_tv_PUSH(cctx, &tv2); + generate_ppconst(cctx, ppconst); generate_two_op(cctx, op); } } @@ -4166,22 +4193,25 @@ compile_expr6( static int compile_expr5(char_u **arg, cctx_T *cctx) { - typval_T tv1; char_u *op; int oplen; + ppconst_T ppconst; + int ppconst_used = 0; + + CLEAR_FIELD(ppconst); // get the first variable - tv1.v_type = VAR_UNKNOWN; - if (compile_expr6(arg, cctx, NULL, &tv1) == FAIL) + if (compile_expr6(arg, cctx, &ppconst) == FAIL) + { + clear_ppconst(&ppconst); return FAIL; + } /* * Repeat computing, until no "+", "-" or ".." is following. */ for (;;) { - typval_T tv2; - op = skipwhite(*arg); if (*op != '+' && *op != '-' && !(*op == '.' && (*(*arg + 1) == '.'))) break; @@ -4191,7 +4221,7 @@ compile_expr5(char_u **arg, cctx_T *cctx) { char_u buf[3]; - clear_tv(&tv1); + clear_ppconst(&ppconst); vim_strncpy(buf, op, oplen); semsg(_(e_white_both), buf); return FAIL; @@ -4200,58 +4230,63 @@ compile_expr5(char_u **arg, cctx_T *cctx) *arg = skipwhite(op + oplen); if (may_get_next_line(op + oplen, arg, cctx) == FAIL) { - clear_tv(&tv1); + clear_ppconst(&ppconst); return FAIL; } // get the second expression - tv2.v_type = VAR_UNKNOWN; - if (compile_expr6(arg, cctx, &tv1, &tv2) == FAIL) + if (compile_expr6(arg, cctx, &ppconst) == FAIL) { - clear_tv(&tv1); + clear_ppconst(&ppconst); return FAIL; } - if (*op == '+' && tv1.v_type == VAR_NUMBER && tv2.v_type == VAR_NUMBER) + if (ppconst.pp_used == ppconst_used + 2 + && (*op == '.' + ? (ppconst.pp_tv[ppconst_used].v_type == VAR_STRING + && ppconst.pp_tv[ppconst_used + 1].v_type == VAR_STRING) + : (ppconst.pp_tv[ppconst_used].v_type == VAR_NUMBER + && ppconst.pp_tv[ppconst_used + 1].v_type == VAR_NUMBER))) { - // add constant numbers - tv1.vval.v_number = tv1.vval.v_number + tv2.vval.v_number; - } - else if (*op == '-' && tv1.v_type == VAR_NUMBER - && tv2.v_type == VAR_NUMBER) - { - // subtract constant numbers - tv1.vval.v_number = tv1.vval.v_number - tv2.vval.v_number; - } - else if (*op == '.' && tv1.v_type == VAR_STRING - && tv2.v_type == VAR_STRING) - { - // concatenate constant strings - char_u *s1 = tv1.vval.v_string; - char_u *s2 = tv2.vval.v_string; - size_t len1 = STRLEN(s1); + typval_T *tv1 = &ppconst.pp_tv[ppconst_used]; + typval_T *tv2 = &ppconst.pp_tv[ppconst_used + 1]; - tv1.vval.v_string = alloc((int)(len1 + STRLEN(s2) + 1)); - if (tv1.vval.v_string == NULL) + // concat/subtract/add constant numbers + if (*op == '+') + tv1->vval.v_number = tv1->vval.v_number + tv2->vval.v_number; + else if (*op == '-') + tv1->vval.v_number = tv1->vval.v_number - tv2->vval.v_number; + else { + // concatenate constant strings + char_u *s1 = tv1->vval.v_string; + char_u *s2 = tv2->vval.v_string; + size_t len1 = STRLEN(s1); + + tv1->vval.v_string = alloc((int)(len1 + STRLEN(s2) + 1)); + if (tv1->vval.v_string == NULL) + { + clear_ppconst(&ppconst); + return FAIL; + } + mch_memmove(tv1->vval.v_string, s1, len1); + STRCPY(tv1->vval.v_string + len1, s2); vim_free(s1); vim_free(s2); - return FAIL; } - mch_memmove(tv1.vval.v_string, s1, len1); - STRCPY(tv1.vval.v_string + len1, s2); - vim_free(s1); - vim_free(s2); + --ppconst.pp_used; } else { - generate_tv_PUSH(cctx, &tv1); - generate_tv_PUSH(cctx, &tv2); + generate_ppconst(cctx, &ppconst); if (*op == '.') { if (may_generate_2STRING(-2, cctx) == FAIL || may_generate_2STRING(-1, cctx) == FAIL) + { + clear_ppconst(&ppconst); return FAIL; + } generate_instr_drop(cctx, ISN_CONCAT, 1); } else @@ -4260,7 +4295,7 @@ compile_expr5(char_u **arg, cctx_T *cctx) } // TODO: move to caller - generate_tv_PUSH(cctx, &tv1); + generate_ppconst(cctx, &ppconst); return OK; } From 7d3664df9008bd5f39f8a2555843d1b269946e4d Mon Sep 17 00:00:00 2001 From: Bram Moolenaar <Bram@vim.org> Date: Sat, 9 May 2020 13:06:24 +0200 Subject: [PATCH 114/230] patch 8.2.0718: gcc warning for returning pointer to local variable Problem: Gcc warning for returning pointer to local variable. (John Marriott) Solution: Return another pointer. --- src/evalvars.c | 4 +++- src/version.c | 2 ++ 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/src/evalvars.c b/src/evalvars.c index 08b2990bcc..0935bb3ebc 100644 --- a/src/evalvars.c +++ b/src/evalvars.c @@ -2510,6 +2510,7 @@ lookup_scriptvar(char_u *name, size_t len, cctx_T *dummy UNUSED) return NULL; if (len < sizeof(buffer) - 1) { + // avoid an alloc/free for short names vim_strncpy(buffer, name, len); p = buffer; } @@ -2529,7 +2530,8 @@ lookup_scriptvar(char_u *name, size_t len, cctx_T *dummy UNUSED) if (p != buffer) vim_free(p); - return res; + // Don't return "buffer", gcc complains. + return res == NULL ? NULL : IObuff; } /* diff --git a/src/version.c b/src/version.c index ba81d68092..5c54b428e5 100644 --- a/src/version.c +++ b/src/version.c @@ -746,6 +746,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 718, /**/ 717, /**/ From a5565e4189b7c4d3f03d1f5405fc64d5dc00f717 Mon Sep 17 00:00:00 2001 From: Bram Moolenaar <Bram@vim.org> Date: Sat, 9 May 2020 15:44:01 +0200 Subject: [PATCH 115/230] patch 8.2.0719: Vim9: more expressions can be evaluated at compile time Problem: Vim9: more expressions can be evaluated at compile time Solution: Recognize has('name'). --- src/testdir/test_vim9_disassemble.vim | 96 ++-- src/testdir/test_vim9_expr.vim | 2 +- src/version.c | 2 + src/vim9compile.c | 619 ++++++++++++++++---------- 4 files changed, 445 insertions(+), 274 deletions(-) diff --git a/src/testdir/test_vim9_disassemble.vim b/src/testdir/test_vim9_disassemble.vim index 7f4a7ddfc2..724087d703 100644 --- a/src/testdir/test_vim9_disassemble.vim +++ b/src/testdir/test_vim9_disassemble.vim @@ -814,46 +814,45 @@ def Test_disassemble_invert_bool() enddef def Test_disassemble_compare() - " TODO: COMPAREFUNC let cases = [ - ['true == false', 'COMPAREBOOL =='], - ['true != false', 'COMPAREBOOL !='], - ['v:none == v:null', 'COMPARESPECIAL =='], - ['v:none != v:null', 'COMPARESPECIAL !='], + ['true == isFalse', 'COMPAREBOOL =='], + ['true != isFalse', 'COMPAREBOOL !='], + ['v:none == isNull', 'COMPARESPECIAL =='], + ['v:none != isNull', 'COMPARESPECIAL !='], - ['111 == 222', 'COMPARENR =='], - ['111 != 222', 'COMPARENR !='], - ['111 > 222', 'COMPARENR >'], - ['111 < 222', 'COMPARENR <'], - ['111 >= 222', 'COMPARENR >='], - ['111 <= 222', 'COMPARENR <='], - ['111 =~ 222', 'COMPARENR =\~'], - ['111 !~ 222', 'COMPARENR !\~'], + ['111 == aNumber', 'COMPARENR =='], + ['111 != aNumber', 'COMPARENR !='], + ['111 > aNumber', 'COMPARENR >'], + ['111 < aNumber', 'COMPARENR <'], + ['111 >= aNumber', 'COMPARENR >='], + ['111 <= aNumber', 'COMPARENR <='], + ['111 =~ aNumber', 'COMPARENR =\~'], + ['111 !~ aNumber', 'COMPARENR !\~'], - ['"xx" != "yy"', 'COMPARESTRING !='], - ['"xx" > "yy"', 'COMPARESTRING >'], - ['"xx" < "yy"', 'COMPARESTRING <'], - ['"xx" >= "yy"', 'COMPARESTRING >='], - ['"xx" <= "yy"', 'COMPARESTRING <='], - ['"xx" =~ "yy"', 'COMPARESTRING =\~'], - ['"xx" !~ "yy"', 'COMPARESTRING !\~'], - ['"xx" is "yy"', 'COMPARESTRING is'], - ['"xx" isnot "yy"', 'COMPARESTRING isnot'], + ['"xx" != aString', 'COMPARESTRING !='], + ['"xx" > aString', 'COMPARESTRING >'], + ['"xx" < aString', 'COMPARESTRING <'], + ['"xx" >= aString', 'COMPARESTRING >='], + ['"xx" <= aString', 'COMPARESTRING <='], + ['"xx" =~ aString', 'COMPARESTRING =\~'], + ['"xx" !~ aString', 'COMPARESTRING !\~'], + ['"xx" is aString', 'COMPARESTRING is'], + ['"xx" isnot aString', 'COMPARESTRING isnot'], - ['0z11 == 0z22', 'COMPAREBLOB =='], - ['0z11 != 0z22', 'COMPAREBLOB !='], - ['0z11 is 0z22', 'COMPAREBLOB is'], - ['0z11 isnot 0z22', 'COMPAREBLOB isnot'], + ['0z11 == aBlob', 'COMPAREBLOB =='], + ['0z11 != aBlob', 'COMPAREBLOB !='], + ['0z11 is aBlob', 'COMPAREBLOB is'], + ['0z11 isnot aBlob', 'COMPAREBLOB isnot'], - ['[1,2] == [3,4]', 'COMPARELIST =='], - ['[1,2] != [3,4]', 'COMPARELIST !='], - ['[1,2] is [3,4]', 'COMPARELIST is'], - ['[1,2] isnot [3,4]', 'COMPARELIST isnot'], + ['[1, 2] == aList', 'COMPARELIST =='], + ['[1, 2] != aList', 'COMPARELIST !='], + ['[1, 2] is aList', 'COMPARELIST is'], + ['[1, 2] isnot aList', 'COMPARELIST isnot'], - ['#{a:1} == #{x:2}', 'COMPAREDICT =='], - ['#{a:1} != #{x:2}', 'COMPAREDICT !='], - ['#{a:1} is #{x:2}', 'COMPAREDICT is'], - ['#{a:1} isnot #{x:2}', 'COMPAREDICT isnot'], + ['#{a: 1} == aDict', 'COMPAREDICT =='], + ['#{a: 1} != aDict', 'COMPAREDICT !='], + ['#{a: 1} is aDict', 'COMPAREDICT is'], + ['#{a: 1} isnot aDict', 'COMPAREDICT isnot'], ['{->33} == {->44}', 'COMPAREFUNC =='], ['{->33} != {->44}', 'COMPAREFUNC !='], @@ -871,22 +870,33 @@ def Test_disassemble_compare() ['77 is g:xx', 'COMPAREANY is'], ['77 isnot g:xx', 'COMPAREANY isnot'], ] + let floatDecl = '' if has('float') cases->extend([ - ['1.1 == 2.2', 'COMPAREFLOAT =='], - ['1.1 != 2.2', 'COMPAREFLOAT !='], - ['1.1 > 2.2', 'COMPAREFLOAT >'], - ['1.1 < 2.2', 'COMPAREFLOAT <'], - ['1.1 >= 2.2', 'COMPAREFLOAT >='], - ['1.1 <= 2.2', 'COMPAREFLOAT <='], - ['1.1 =~ 2.2', 'COMPAREFLOAT =\~'], - ['1.1 !~ 2.2', 'COMPAREFLOAT !\~'], + ['1.1 == aFloat', 'COMPAREFLOAT =='], + ['1.1 != aFloat', 'COMPAREFLOAT !='], + ['1.1 > aFloat', 'COMPAREFLOAT >'], + ['1.1 < aFloat', 'COMPAREFLOAT <'], + ['1.1 >= aFloat', 'COMPAREFLOAT >='], + ['1.1 <= aFloat', 'COMPAREFLOAT <='], + ['1.1 =~ aFloat', 'COMPAREFLOAT =\~'], + ['1.1 !~ aFloat', 'COMPAREFLOAT !\~'], ]) + floatDecl = 'let aFloat = 2.2' endif let nr = 1 for case in cases + " declare local variables to get a non-constant with the right type writefile(['def TestCase' .. nr .. '()', + ' let isFalse = false', + ' let isNull = v:null', + ' let aNumber = 222', + ' let aString = "yy"', + ' let aBlob = 0z22', + ' let aList = [3, 4]', + ' let aDict = #{x: 2}', + floatDecl, ' if ' .. case[0], ' echo 42' ' endif', @@ -896,7 +906,7 @@ def Test_disassemble_compare() assert_match('TestCase' .. nr .. '.*' .. 'if ' .. substitute(case[0], '[[~]', '\\\0', 'g') .. '.*' .. '\d \(PUSH\|FUNCREF\).*' .. - '\d \(PUSH\|FUNCREF\|LOADG\).*' .. + '\d \(PUSH\|FUNCREF\|LOAD\).*' .. '\d ' .. case[1] .. '.*' .. '\d JUMP_IF_FALSE -> \d\+.*', instr) diff --git a/src/testdir/test_vim9_expr.vim b/src/testdir/test_vim9_expr.vim index 3ce8b1ea8b..86d1715734 100644 --- a/src/testdir/test_vim9_expr.vim +++ b/src/testdir/test_vim9_expr.vim @@ -429,7 +429,7 @@ func Test_expr4_fails() call CheckDefFailure(["let x = 1 == '2'"], 'Cannot compare number with string') call CheckDefFailure(["let x = '1' == 2"], 'Cannot compare string with number') - call CheckDefFailure(["let x = 1 == RetVoid()"], 'Cannot use void value') + call CheckDefFailure(["let x = 1 == RetVoid()"], 'Cannot compare number with void') call CheckDefFailure(["let x = RetVoid() == 1"], 'Cannot compare void with number') call CheckDefFailure(["let x = true > false"], 'Cannot compare bool with bool') diff --git a/src/version.c b/src/version.c index 5c54b428e5..5903a00e26 100644 --- a/src/version.c +++ b/src/version.c @@ -746,6 +746,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 719, /**/ 718, /**/ diff --git a/src/vim9compile.c b/src/vim9compile.c index 079d160083..944efa197d 100644 --- a/src/vim9compile.c +++ b/src/vim9compile.c @@ -136,9 +136,7 @@ struct cctx_S { static char e_var_notfound[] = N_("E1001: variable not found: %s"); static char e_syntax_at[] = N_("E1002: Syntax error at %s"); -static int compile_expr1(char_u **arg, cctx_T *cctx); -static int compile_expr2(char_u **arg, cctx_T *cctx); -static int compile_expr3(char_u **arg, cctx_T *cctx); +static int compile_expr0(char_u **arg, cctx_T *cctx); static void delete_def_function_contents(dfunc_T *dfunc); static void arg_type_mismatch(type_T *expected, type_T *actual, int argidx); static int check_type(type_T *expected, type_T *actual, int give_msg); @@ -744,24 +742,14 @@ generate_two_op(cctx_T *cctx, char_u *op) } /* - * Generate an ISN_COMPARE* instruction with a boolean result. + * Get the instruction to use for comparing "type1" with "type2" + * Return ISN_DROP when failed. */ - static int -generate_COMPARE(cctx_T *cctx, exptype_T exptype, int ic) + static isntype_T +get_compare_isn(exptype_T exptype, vartype_T type1, vartype_T type2) { isntype_T isntype = ISN_DROP; - isn_T *isn; - garray_T *stack = &cctx->ctx_type_stack; - vartype_T type1; - vartype_T type2; - RETURN_OK_IF_SKIP(cctx); - - // Get the known type of the two items on the stack. If they are matching - // use a type-specific instruction. Otherwise fall back to runtime type - // checking. - type1 = ((type_T **)stack->ga_data)[stack->ga_len - 2]->tt_type; - type2 = ((type_T **)stack->ga_data)[stack->ga_len - 1]->tt_type; if (type1 == VAR_UNKNOWN) type1 = VAR_ANY; if (type2 == VAR_UNKNOWN) @@ -796,7 +784,7 @@ generate_COMPARE(cctx_T *cctx, exptype_T exptype, int ic) { semsg(_("E1037: Cannot use \"%s\" with %s"), exptype == EXPR_IS ? "is" : "isnot" , vartype_name(type1)); - return FAIL; + return ISN_DROP; } if (isntype == ISN_DROP || ((exptype != EXPR_EQUAL && exptype != EXPR_NEQUAL @@ -809,8 +797,33 @@ generate_COMPARE(cctx_T *cctx, exptype_T exptype, int ic) { semsg(_("E1072: Cannot compare %s with %s"), vartype_name(type1), vartype_name(type2)); - return FAIL; + return ISN_DROP; } + return isntype; +} + +/* + * Generate an ISN_COMPARE* instruction with a boolean result. + */ + static int +generate_COMPARE(cctx_T *cctx, exptype_T exptype, int ic) +{ + isntype_T isntype; + isn_T *isn; + garray_T *stack = &cctx->ctx_type_stack; + vartype_T type1; + vartype_T type2; + + RETURN_OK_IF_SKIP(cctx); + + // Get the known type of the two items on the stack. If they are matching + // use a type-specific instruction. Otherwise fall back to runtime type + // checking. + type1 = ((type_T **)stack->ga_data)[stack->ga_len - 2]->tt_type; + type2 = ((type_T **)stack->ga_data)[stack->ga_len - 1]->tt_type; + isntype = get_compare_isn(exptype, type1, type2); + if (isntype == ISN_DROP) + return FAIL; if ((isn = generate_instr(cctx, isntype)) == NULL) return FAIL; @@ -2340,6 +2353,91 @@ may_get_next_line(char_u *whitep, char_u **arg, cctx_T *cctx) return OK; } +// Structure passed between the compile_expr* functions to keep track of +// constants that have been parsed but for which no code was produced yet. If +// possible expressions on these constants are applied at compile time. If +// that is not possible, the code to push the constants needs to be generated +// before other instructions. +typedef struct { + typval_T pp_tv[10]; // stack of ppconst constants + int pp_used; // active entries in pp_tv[] +} ppconst_T; + +/* + * Generate a PUSH instruction for "tv". + * "tv" will be consumed or cleared. + * Nothing happens if "tv" is NULL or of type VAR_UNKNOWN; + */ + static int +generate_tv_PUSH(cctx_T *cctx, typval_T *tv) +{ + if (tv != NULL) + { + switch (tv->v_type) + { + case VAR_UNKNOWN: + break; + case VAR_BOOL: + generate_PUSHBOOL(cctx, tv->vval.v_number); + break; + case VAR_SPECIAL: + generate_PUSHSPEC(cctx, tv->vval.v_number); + break; + case VAR_NUMBER: + generate_PUSHNR(cctx, tv->vval.v_number); + break; +#ifdef FEAT_FLOAT + case VAR_FLOAT: + generate_PUSHF(cctx, tv->vval.v_float); + break; +#endif + case VAR_BLOB: + generate_PUSHBLOB(cctx, tv->vval.v_blob); + tv->vval.v_blob = NULL; + break; + case VAR_STRING: + generate_PUSHS(cctx, tv->vval.v_string); + tv->vval.v_string = NULL; + break; + default: + iemsg("constant type not supported"); + clear_tv(tv); + return FAIL; + } + tv->v_type = VAR_UNKNOWN; + } + return OK; +} + +/* + * Generate code for any ppconst entries. + */ + static int +generate_ppconst(cctx_T *cctx, ppconst_T *ppconst) +{ + int i; + int ret = OK; + + for (i = 0; i < ppconst->pp_used; ++i) + if (generate_tv_PUSH(cctx, &ppconst->pp_tv[i]) == FAIL) + ret = FAIL; + ppconst->pp_used = 0; + return ret; +} + +/* + * Clear ppconst constants. Used when failing. + */ + static void +clear_ppconst(ppconst_T *ppconst) +{ + int i; + + for (i = 0; i < ppconst->pp_used; ++i) + clear_tv(&ppconst->pp_tv[i]); + ppconst->pp_used = 0; +} + /* * Generate an instruction to load script-local variable "name", without the * leading "s:". @@ -2526,25 +2624,18 @@ compile_load(char_u **arg, char_u *end_arg, cctx_T *cctx, int error) } else { - if ((len == 4 && STRNCMP("true", *arg, 4) == 0) - || (len == 5 && STRNCMP("false", *arg, 5) == 0)) - res = generate_PUSHBOOL(cctx, **arg == 't' - ? VVAL_TRUE : VVAL_FALSE); - else - { - // "var" can be script-local even without using "s:" if it - // already exists. - if (SCRIPT_ITEM(current_sctx.sc_sid)->sn_version - == SCRIPT_VERSION_VIM9 - || lookup_script(*arg, len) == OK) - res = compile_load_scriptvar(cctx, name, *arg, &end, - FALSE); + // "var" can be script-local even without using "s:" if it + // already exists. + if (SCRIPT_ITEM(current_sctx.sc_sid)->sn_version + == SCRIPT_VERSION_VIM9 + || lookup_script(*arg, len) == OK) + res = compile_load_scriptvar(cctx, name, *arg, &end, + FALSE); - // When the name starts with an uppercase letter or "x:" it - // can be a user defined function. - if (res == FAIL && (ASCII_ISUPPER(*name) || name[1] == ':')) - res = generate_funcref(cctx, name); - } + // When the name starts with an uppercase letter or "x:" it + // can be a user defined function. + if (res == FAIL && (ASCII_ISUPPER(*name) || name[1] == ':')) + res = generate_funcref(cctx, name); } } if (gen_load) @@ -2588,7 +2679,7 @@ compile_arguments(char_u **arg, cctx_T *cctx, int *argcount) return OK; } - if (compile_expr1(&p, cctx) == FAIL) + if (compile_expr0(&p, cctx) == FAIL) return FAIL; ++*argcount; @@ -2621,7 +2712,12 @@ failret: * BCALL / DCALL / UCALL */ static int -compile_call(char_u **arg, size_t varlen, cctx_T *cctx, int argcount_init) +compile_call( + char_u **arg, + size_t varlen, + cctx_T *cctx, + ppconst_T *ppconst, + int argcount_init) { char_u *name = *arg; char_u *p; @@ -2633,6 +2729,36 @@ compile_call(char_u **arg, size_t varlen, cctx_T *cctx, int argcount_init) ufunc_T *ufunc; int res = FAIL; + // we can evaluate "has('name')" at compile time + if (varlen == 3 && STRNCMP(*arg, "has", 3) == 0) + { + char_u *s = skipwhite(*arg + varlen + 1); + typval_T argvars[2]; + + argvars[0].v_type = VAR_UNKNOWN; + if (*s == '"') + (void)get_string_tv(&s, &argvars[0], TRUE); + else if (*s == '\'') + (void)get_lit_string_tv(&s, &argvars[0], TRUE); + s = skipwhite(s); + if (*s == ')' && argvars[0].v_type == VAR_STRING) + { + typval_T *tv = &ppconst->pp_tv[ppconst->pp_used]; + + *arg = s + 1; + argvars[1].v_type = VAR_UNKNOWN; + tv->v_type = VAR_NUMBER; + tv->vval.v_number = 0; + f_has(argvars, tv); + clear_tv(&argvars[0]); + ++ppconst->pp_used; + return OK; + } + } + + if (generate_ppconst(cctx, ppconst) == FAIL) + return FAIL; + if (varlen >= sizeof(namebuf)) { semsg(_("E1011: name too long: %s"), name); @@ -2791,7 +2917,7 @@ compile_list(char_u **arg, cctx_T *cctx) p += STRLEN(p); break; } - if (compile_expr1(&p, cctx) == FAIL) + if (compile_expr0(&p, cctx) == FAIL) break; ++count; if (*p == ',') @@ -2929,7 +3055,7 @@ compile_dict(char_u **arg, cctx_T *cctx, int literal) { isn_T *isn; - if (compile_expr1(arg, cctx) == FAIL) + if (compile_expr0(arg, cctx) == FAIL) return FAIL; // TODO: check type is string isn = ((isn_T *)instr->ga_data) + instr->ga_len - 1; @@ -2974,7 +3100,7 @@ compile_dict(char_u **arg, cctx_T *cctx, int literal) *arg = skipwhite(*arg); } - if (compile_expr1(arg, cctx) == FAIL) + if (compile_expr0(arg, cctx) == FAIL) return FAIL; ++count; @@ -3626,90 +3752,7 @@ evaluate_const_expr1(char_u **arg, cctx_T *cctx, typval_T *tv) return OK; } -// Structure passed between the compile_expr* functions to keep track of -// constants that have been parsed but for which no code was produced yet. If -// possible expressions on these constants are applied at compile time. If -// that is not possible, the code to push the constants needs to be generated -// before other instructions. -typedef struct { - typval_T pp_tv[10]; // stack of ppconst constants - int pp_used; // active entries in pp_tv[] -} ppconst_T; - -/* - * Generate a PUSH instruction for "tv". - * "tv" will be consumed or cleared. - * Nothing happens if "tv" is NULL or of type VAR_UNKNOWN; - */ - static int -generate_tv_PUSH(cctx_T *cctx, typval_T *tv) -{ - if (tv != NULL) - { - switch (tv->v_type) - { - case VAR_UNKNOWN: - break; - case VAR_BOOL: - generate_PUSHBOOL(cctx, tv->vval.v_number); - break; - case VAR_SPECIAL: - generate_PUSHSPEC(cctx, tv->vval.v_number); - break; - case VAR_NUMBER: - generate_PUSHNR(cctx, tv->vval.v_number); - break; -#ifdef FEAT_FLOAT - case VAR_FLOAT: - generate_PUSHF(cctx, tv->vval.v_float); - break; -#endif - case VAR_BLOB: - generate_PUSHBLOB(cctx, tv->vval.v_blob); - tv->vval.v_blob = NULL; - break; - case VAR_STRING: - generate_PUSHS(cctx, tv->vval.v_string); - tv->vval.v_string = NULL; - break; - default: - iemsg("constant type not supported"); - clear_tv(tv); - return FAIL; - } - tv->v_type = VAR_UNKNOWN; - } - return OK; -} - -/* - * Generate code for any ppconst entries. - */ - static int -generate_ppconst(cctx_T *cctx, ppconst_T *ppconst) -{ - int i; - int ret = OK; - - for (i = 0; i < ppconst->pp_used; ++i) - if (generate_tv_PUSH(cctx, &ppconst->pp_tv[i]) == FAIL) - ret = FAIL; - ppconst->pp_used = 0; - return ret; -} - -/* - * Clear ppconst constants. Used when failing. - */ - static void -clear_ppconst(ppconst_T *ppconst) -{ - int i; - - for (i = 0; i < ppconst->pp_used; ++i) - clear_tv(&ppconst->pp_tv[i]); - ppconst->pp_used = 0; -} +static int compile_expr3(char_u **arg, cctx_T *cctx, ppconst_T *ppconst); /* * Compile code to apply '-', '+' and '!'. @@ -3825,7 +3868,7 @@ compile_subscript( return FAIL; } // TODO: base value may not be the first argument - if (compile_call(arg, p - *arg, cctx, 1) == FAIL) + if (compile_call(arg, p - *arg, cctx, ppconst, 1) == FAIL) return FAIL; } } @@ -3841,7 +3884,7 @@ compile_subscript( // TODO: more arguments // TODO: dict member dict['name'] *arg = skipwhite(*arg + 1); - if (compile_expr1(arg, cctx) == FAIL) + if (compile_expr0(arg, cctx) == FAIL) return FAIL; if (**arg != ']') @@ -3990,6 +4033,34 @@ compile_expr7( ret = NOTDONE; break; + /* + * "true" constant + */ + case 't': if (STRNCMP(*arg, "true", 4) == 0 + && !eval_isnamec((*arg)[4])) + { + *arg += 4; + rettv->v_type = VAR_BOOL; + rettv->vval.v_number = VVAL_TRUE; + } + else + ret = NOTDONE; + break; + + /* + * "false" constant + */ + case 'f': if (STRNCMP(*arg, "false", 5) == 0 + && !eval_isnamec((*arg)[5])) + { + *arg += 5; + rettv->v_type = VAR_BOOL; + rettv->vval.v_number = VVAL_FALSE; + } + else + ret = NOTDONE; + break; + /* * List: [expr, expr] */ @@ -4047,7 +4118,7 @@ compile_expr7( * nested expression: (expression). */ case '(': *arg = skipwhite(*arg + 1); - ret = compile_expr1(arg, cctx); // recursive! + ret = compile_expr0(arg, cctx); // recursive! *arg = skipwhite(*arg); if (**arg == ')') ++*arg; @@ -4074,18 +4145,18 @@ compile_expr7( } start_leader = end_leader; // don't apply again below - // A constant expression can possibly be handled compile time, return - // the value instead of generating code. - ++ppconst->pp_used; + if (cctx->ctx_skip == TRUE) + clear_tv(rettv); + else + // A constant expression can possibly be handled compile time, + // return the value instead of generating code. + ++ppconst->pp_used; } else if (ret == NOTDONE) { char_u *p; int r; - if (generate_ppconst(cctx, ppconst) == FAIL) - return FAIL; - if (!eval_isnamec1(**arg)) { semsg(_("E1015: Name expected: %s"), *arg); @@ -4095,9 +4166,15 @@ compile_expr7( // "name" or "name()" p = to_name_end(*arg, TRUE); if (*p == '(') - r = compile_call(arg, p - *arg, cctx, 0); + { + r = compile_call(arg, p - *arg, cctx, ppconst, 0); + } else + { + if (generate_ppconst(cctx, ppconst) == FAIL) + return FAIL; r = compile_load(arg, p, cctx, TRUE); + } if (r == FAIL) return FAIL; } @@ -4105,8 +4182,17 @@ compile_expr7( // Handle following "[]", ".member", etc. // Then deal with prefixed '-', '+' and '!', if not done already. if (compile_subscript(arg, cctx, &start_leader, end_leader, - ppconst) == FAIL - || compile_leader(cctx, start_leader, end_leader) == FAIL) + ppconst) == FAIL) + return FAIL; + if (ppconst->pp_used > 0) + { + // apply the '!', '-' and '+' before the constant + rettv = &ppconst->pp_tv[ppconst->pp_used - 1]; + if (apply_leader(rettv, start_leader, end_leader) == FAIL) + return FAIL; + return OK; + } + if (compile_leader(cctx, start_leader, end_leader) == FAIL) return FAIL; return OK; } @@ -4117,10 +4203,7 @@ compile_expr7( * % number modulo */ static int -compile_expr6( - char_u **arg, - cctx_T *cctx, - ppconst_T *ppconst) +compile_expr6(char_u **arg, cctx_T *cctx, ppconst_T *ppconst) { char_u *op; int ppconst_used = ppconst->pp_used; @@ -4191,21 +4274,15 @@ compile_expr6( * .. string concatenation */ static int -compile_expr5(char_u **arg, cctx_T *cctx) +compile_expr5(char_u **arg, cctx_T *cctx, ppconst_T *ppconst) { char_u *op; int oplen; - ppconst_T ppconst; - int ppconst_used = 0; - - CLEAR_FIELD(ppconst); + int ppconst_used = ppconst->pp_used; // get the first variable - if (compile_expr6(arg, cctx, &ppconst) == FAIL) - { - clear_ppconst(&ppconst); + if (compile_expr6(arg, cctx, ppconst) == FAIL) return FAIL; - } /* * Repeat computing, until no "+", "-" or ".." is following. @@ -4221,7 +4298,6 @@ compile_expr5(char_u **arg, cctx_T *cctx) { char_u buf[3]; - clear_ppconst(&ppconst); vim_strncpy(buf, op, oplen); semsg(_(e_white_both), buf); return FAIL; @@ -4229,27 +4305,21 @@ compile_expr5(char_u **arg, cctx_T *cctx) *arg = skipwhite(op + oplen); if (may_get_next_line(op + oplen, arg, cctx) == FAIL) - { - clear_ppconst(&ppconst); return FAIL; - } // get the second expression - if (compile_expr6(arg, cctx, &ppconst) == FAIL) - { - clear_ppconst(&ppconst); + if (compile_expr6(arg, cctx, ppconst) == FAIL) return FAIL; - } - if (ppconst.pp_used == ppconst_used + 2 + if (ppconst->pp_used == ppconst_used + 2 && (*op == '.' - ? (ppconst.pp_tv[ppconst_used].v_type == VAR_STRING - && ppconst.pp_tv[ppconst_used + 1].v_type == VAR_STRING) - : (ppconst.pp_tv[ppconst_used].v_type == VAR_NUMBER - && ppconst.pp_tv[ppconst_used + 1].v_type == VAR_NUMBER))) + ? (ppconst->pp_tv[ppconst_used].v_type == VAR_STRING + && ppconst->pp_tv[ppconst_used + 1].v_type == VAR_STRING) + : (ppconst->pp_tv[ppconst_used].v_type == VAR_NUMBER + && ppconst->pp_tv[ppconst_used + 1].v_type == VAR_NUMBER))) { - typval_T *tv1 = &ppconst.pp_tv[ppconst_used]; - typval_T *tv2 = &ppconst.pp_tv[ppconst_used + 1]; + typval_T *tv1 = &ppconst->pp_tv[ppconst_used]; + typval_T *tv2 = &ppconst->pp_tv[ppconst_used + 1]; // concat/subtract/add constant numbers if (*op == '+') @@ -4266,7 +4336,7 @@ compile_expr5(char_u **arg, cctx_T *cctx) tv1->vval.v_string = alloc((int)(len1 + STRLEN(s2) + 1)); if (tv1->vval.v_string == NULL) { - clear_ppconst(&ppconst); + clear_ppconst(ppconst); return FAIL; } mch_memmove(tv1->vval.v_string, s1, len1); @@ -4274,19 +4344,16 @@ compile_expr5(char_u **arg, cctx_T *cctx) vim_free(s1); vim_free(s2); } - --ppconst.pp_used; + --ppconst->pp_used; } else { - generate_ppconst(cctx, &ppconst); + generate_ppconst(cctx, ppconst); if (*op == '.') { if (may_generate_2STRING(-2, cctx) == FAIL || may_generate_2STRING(-1, cctx) == FAIL) - { - clear_ppconst(&ppconst); return FAIL; - } generate_instr_drop(cctx, ISN_CONCAT, 1); } else @@ -4294,9 +4361,6 @@ compile_expr5(char_u **arg, cctx_T *cctx) } } - // TODO: move to caller - generate_ppconst(cctx, &ppconst); - return OK; } @@ -4318,15 +4382,16 @@ compile_expr5(char_u **arg, cctx_T *cctx) * COMPARE one of the compare instructions */ static int -compile_expr4(char_u **arg, cctx_T *cctx) +compile_expr4(char_u **arg, cctx_T *cctx, ppconst_T *ppconst) { exptype_T type = EXPR_UNKNOWN; char_u *p; int len = 2; int type_is = FALSE; + int ppconst_used = ppconst->pp_used; // get the first variable - if (compile_expr5(arg, cctx) == FAIL) + if (compile_expr5(arg, cctx, ppconst) == FAIL) return FAIL; p = skipwhite(*arg); @@ -4369,10 +4434,34 @@ compile_expr4(char_u **arg, cctx_T *cctx) if (may_get_next_line(p + len, arg, cctx) == FAIL) return FAIL; - if (compile_expr5(arg, cctx) == FAIL) + if (compile_expr5(arg, cctx, ppconst) == FAIL) return FAIL; - generate_COMPARE(cctx, type, ic); + if (ppconst->pp_used == ppconst_used + 2) + { + typval_T * tv1 = &ppconst->pp_tv[ppconst->pp_used - 2]; + typval_T *tv2 = &ppconst->pp_tv[ppconst->pp_used - 1]; + int ret; + + // Both sides are a constant, compute the result now. + // First check for a valid combination of types, this is more + // strict than typval_compare(). + if (get_compare_isn(type, tv1->v_type, tv2->v_type) == ISN_DROP) + ret = FAIL; + else + { + ret = typval_compare(tv1, tv2, type, ic); + tv1->v_type = VAR_BOOL; + tv1->vval.v_number = tv1->vval.v_number + ? VVAL_TRUE : VVAL_FALSE; + clear_tv(tv2); + --ppconst->pp_used; + } + return ret; + } + + generate_ppconst(cctx, ppconst); + return generate_COMPARE(cctx, type, ic); } return OK; @@ -4382,7 +4471,12 @@ compile_expr4(char_u **arg, cctx_T *cctx) * Compile || or &&. */ static int -compile_and_or(char_u **arg, cctx_T *cctx, char *op) +compile_and_or( + char_u **arg, + cctx_T *cctx, + char *op, + ppconst_T *ppconst, + int ppconst_used UNUSED) { char_u *p = skipwhite(*arg); int opchar = *op; @@ -4404,6 +4498,9 @@ compile_and_or(char_u **arg, cctx_T *cctx, char *op) return FAIL; } + // TODO: use ppconst if the value is a constant + generate_ppconst(cctx, ppconst); + if (ga_grow(&end_ga, 1) == FAIL) { ga_clear(&end_ga); @@ -4419,14 +4516,15 @@ compile_and_or(char_u **arg, cctx_T *cctx, char *op) if (may_get_next_line(p + 2, arg, cctx) == FAIL) return FAIL; - if ((opchar == '|' ? compile_expr3(arg, cctx) - : compile_expr4(arg, cctx)) == FAIL) + if ((opchar == '|' ? compile_expr3(arg, cctx, ppconst) + : compile_expr4(arg, cctx, ppconst)) == FAIL) { ga_clear(&end_ga); return FAIL; } p = skipwhite(*arg); } + generate_ppconst(cctx, ppconst); // Fill in the end label in all jumps. while (end_ga.ga_len > 0) @@ -4456,14 +4554,16 @@ compile_and_or(char_u **arg, cctx_T *cctx, char *op) * end: */ static int -compile_expr3(char_u **arg, cctx_T *cctx) +compile_expr3(char_u **arg, cctx_T *cctx, ppconst_T *ppconst) { + int ppconst_used = ppconst->pp_used; + // get the first variable - if (compile_expr4(arg, cctx) == FAIL) + if (compile_expr4(arg, cctx, ppconst) == FAIL) return FAIL; // || and && work almost the same - return compile_and_or(arg, cctx, "&&"); + return compile_and_or(arg, cctx, "&&", ppconst, ppconst_used); } /* @@ -4478,14 +4578,16 @@ compile_expr3(char_u **arg, cctx_T *cctx) * end: */ static int -compile_expr2(char_u **arg, cctx_T *cctx) +compile_expr2(char_u **arg, cctx_T *cctx, ppconst_T *ppconst) { + int ppconst_used = ppconst->pp_used; + // eval the first expression - if (compile_expr3(arg, cctx) == FAIL) + if (compile_expr3(arg, cctx, ppconst) == FAIL) return FAIL; // || and && work almost the same - return compile_and_or(arg, cctx, "||"); + return compile_and_or(arg, cctx, "||", ppconst, ppconst_used); } /* @@ -4500,12 +4602,13 @@ compile_expr2(char_u **arg, cctx_T *cctx) * end: */ static int -compile_expr1(char_u **arg, cctx_T *cctx) +compile_expr1(char_u **arg, cctx_T *cctx, ppconst_T *ppconst) { char_u *p; + int ppconst_used = ppconst->pp_used; // Evaluate the first expression. - if (compile_expr2(arg, cctx) == FAIL) + if (compile_expr2(arg, cctx, ppconst) == FAIL) return FAIL; p = skipwhite(*arg); @@ -4518,6 +4621,9 @@ compile_expr1(char_u **arg, cctx_T *cctx) isn_T *isn; type_T *type1; type_T *type2; + int has_const_expr = FALSE; + int const_value = FALSE; + int save_skip = cctx->ctx_skip; if (!IS_WHITE_OR_NUL(**arg) || !IS_WHITE_OR_NUL(p[1])) { @@ -4525,26 +4631,44 @@ compile_expr1(char_u **arg, cctx_T *cctx) return FAIL; } - generate_JUMP(cctx, JUMP_IF_FALSE, 0); + if (ppconst->pp_used == ppconst_used + 1) + { + // the condition is a constant, we know whether the ? or the : + // expression is to be evaluated. + has_const_expr = TRUE; + const_value = tv2bool(&ppconst->pp_tv[ppconst_used]); + clear_tv(&ppconst->pp_tv[ppconst_used]); + --ppconst->pp_used; + cctx->ctx_skip = save_skip == TRUE || !const_value; + } + else + { + generate_ppconst(cctx, ppconst); + generate_JUMP(cctx, JUMP_IF_FALSE, 0); + } // evaluate the second expression; any type is accepted *arg = skipwhite(p + 1); if (may_get_next_line(p + 1, arg, cctx) == FAIL) return FAIL; - - if (compile_expr1(arg, cctx) == FAIL) + if (compile_expr1(arg, cctx, ppconst) == FAIL) return FAIL; - // remember the type and drop it - --stack->ga_len; - type1 = ((type_T **)stack->ga_data)[stack->ga_len]; + if (!has_const_expr) + { + generate_ppconst(cctx, ppconst); - end_idx = instr->ga_len; - generate_JUMP(cctx, JUMP_ALWAYS, 0); + // remember the type and drop it + --stack->ga_len; + type1 = ((type_T **)stack->ga_data)[stack->ga_len]; - // jump here from JUMP_IF_FALSE - isn = ((isn_T *)instr->ga_data) + alt_idx; - isn->isn_arg.jump.jump_where = instr->ga_len; + end_idx = instr->ga_len; + generate_JUMP(cctx, JUMP_ALWAYS, 0); + + // jump here from JUMP_IF_FALSE + isn = ((isn_T *)instr->ga_data) + alt_idx; + isn->isn_arg.jump.jump_where = instr->ga_len; + } // Check for the ":". p = skipwhite(*arg); @@ -4560,24 +4684,51 @@ compile_expr1(char_u **arg, cctx_T *cctx) } // evaluate the third expression + if (has_const_expr) + cctx->ctx_skip = save_skip == TRUE || const_value; *arg = skipwhite(p + 1); if (may_get_next_line(p + 1, arg, cctx) == FAIL) return FAIL; - - if (compile_expr1(arg, cctx) == FAIL) + if (compile_expr1(arg, cctx, ppconst) == FAIL) return FAIL; - // If the types differ, the result has a more generic type. - type2 = ((type_T **)stack->ga_data)[stack->ga_len - 1]; - common_type(type1, type2, &type2, cctx->ctx_type_list); + if (!has_const_expr) + { + generate_ppconst(cctx, ppconst); - // jump here from JUMP_ALWAYS - isn = ((isn_T *)instr->ga_data) + end_idx; - isn->isn_arg.jump.jump_where = instr->ga_len; + // If the types differ, the result has a more generic type. + type2 = ((type_T **)stack->ga_data)[stack->ga_len - 1]; + common_type(type1, type2, &type2, cctx->ctx_type_list); + + // jump here from JUMP_ALWAYS + isn = ((isn_T *)instr->ga_data) + end_idx; + isn->isn_arg.jump.jump_where = instr->ga_len; + } + + cctx->ctx_skip = save_skip; } return OK; } +/* + * Toplevel expression. + */ + static int +compile_expr0(char_u **arg, cctx_T *cctx) +{ + ppconst_T ppconst; + + CLEAR_FIELD(ppconst); + if (compile_expr1(arg, cctx, &ppconst) == FAIL) + { + clear_ppconst(&ppconst); + return FAIL; + } + if (generate_ppconst(cctx, &ppconst) == FAIL) + return FAIL; + return OK; +} + /* * compile "return [expr]" */ @@ -4591,7 +4742,7 @@ compile_return(char_u *arg, int set_return_type, cctx_T *cctx) if (*p != NUL && *p != '|' && *p != '\n') { // compile return argument into instructions - if (compile_expr1(&p, cctx) == FAIL) + if (compile_expr0(&p, cctx) == FAIL) return NULL; stack_type = ((type_T **)stack->ga_data)[stack->ga_len - 1]; @@ -5075,7 +5226,7 @@ compile_assignment(char_u *arg, exarg_T *eap, cmdidx_T cmdidx, cctx_T *cctx) --cctx->ctx_locals.ga_len; instr_count = instr->ga_len; p = skipwhite(p + oplen); - r = compile_expr1(&p, cctx); + r = compile_expr0(&p, cctx); if (new_local) ++cctx->ctx_locals.ga_len; if (r == FAIL) @@ -5526,20 +5677,28 @@ compile_if(char_u *arg, cctx_T *cctx) { char_u *p = arg; garray_T *instr = &cctx->ctx_instr; + int instr_count = instr->ga_len; scope_T *scope; - typval_T tv; + ppconst_T ppconst; - // compile "expr"; if we know it evaluates to FALSE skip the block - tv.v_type = VAR_UNKNOWN; - if (evaluate_const_expr1(&p, cctx, &tv) == OK) - cctx->ctx_skip = tv2bool(&tv) ? FALSE : TRUE; - else - cctx->ctx_skip = MAYBE; - clear_tv(&tv); - if (cctx->ctx_skip == MAYBE) + CLEAR_FIELD(ppconst); + if (compile_expr1(&p, cctx, &ppconst) == FAIL) { - p = arg; - if (compile_expr1(&p, cctx) == FAIL) + clear_ppconst(&ppconst); + return NULL; + } + if (instr->ga_len == instr_count && ppconst.pp_used == 1) + { + // The expression results in a constant. + // TODO: how about nesting? + cctx->ctx_skip = tv2bool(&ppconst.pp_tv[0]) ? FALSE : TRUE; + clear_ppconst(&ppconst); + } + else + { + // Not a constant, generate instructions for the expression. + cctx->ctx_skip = MAYBE; + if (generate_ppconst(cctx, &ppconst) == FAIL) return NULL; } @@ -5595,7 +5754,7 @@ compile_elseif(char_u *arg, cctx_T *cctx) if (cctx->ctx_skip == MAYBE) { p = arg; - if (compile_expr1(&p, cctx) == FAIL) + if (compile_expr0(&p, cctx) == FAIL) return NULL; // "where" is set when ":elseif", "else" or ":endif" is found @@ -5754,7 +5913,7 @@ compile_for(char_u *arg, cctx_T *cctx) // compile "expr", it remains on the stack until "endfor" arg = p; - if (compile_expr1(&arg, cctx) == FAIL) + if (compile_expr0(&arg, cctx) == FAIL) { drop_scope(cctx); return NULL; @@ -5844,7 +6003,7 @@ compile_while(char_u *arg, cctx_T *cctx) scope->se_u.se_while.ws_top_label = instr->ga_len; // compile "expr" - if (compile_expr1(&p, cctx) == FAIL) + if (compile_expr0(&p, cctx) == FAIL) return NULL; // "while_end" is set when ":endwhile" is found @@ -6219,7 +6378,7 @@ compile_throw(char_u *arg, cctx_T *cctx UNUSED) { char_u *p = skipwhite(arg); - if (compile_expr1(&p, cctx) == FAIL) + if (compile_expr0(&p, cctx) == FAIL) return NULL; if (may_generate_2STRING(-1, cctx) == FAIL) return NULL; @@ -6243,7 +6402,7 @@ compile_mult_expr(char_u *arg, int cmdidx, cctx_T *cctx) for (;;) { - if (compile_expr1(&p, cctx) == FAIL) + if (compile_expr0(&p, cctx) == FAIL) return NULL; ++count; p = skipwhite(p); @@ -6305,7 +6464,7 @@ compile_exec(char_u *line, exarg_T *eap, cctx_T *cctx) ++count; } p += 2; - if (compile_expr1(&p, cctx) == FAIL) + if (compile_expr0(&p, cctx) == FAIL) return NULL; may_generate_2STRING(-1, cctx); ++count; @@ -6423,7 +6582,7 @@ compile_def_function(ufunc_T *ufunc, int set_return_type, cctx_T *outer_cctx) ufunc->uf_def_arg_idx[i] = instr->ga_len; arg = ((char_u **)(ufunc->uf_def_args.ga_data))[i]; - if (compile_expr1(&arg, &cctx) == FAIL) + if (compile_expr0(&arg, &cctx) == FAIL) goto erret; // If no type specified use the type of the default value. @@ -6609,7 +6768,7 @@ compile_def_function(ufunc_T *ufunc, int set_return_type, cctx_T *outer_cctx) if (ea.cmdidx == CMD_eval) { p = ea.cmd; - if (compile_expr1(&p, &cctx) == FAIL) + if (compile_expr0(&p, &cctx) == FAIL) goto erret; // drop the return value From b1062eb23e7a7a8b44f3416e79c3b28aa6c6c229 Mon Sep 17 00:00:00 2001 From: Bram Moolenaar <Bram@vim.org> Date: Sat, 9 May 2020 16:11:33 +0200 Subject: [PATCH 116/230] patch 8.2.0720: occasional exit when encountering an X error Problem: Occasional exit when encountering an X error. (Manfred Lotz) Solution: On an X error do not exit, do preserve files. --- src/os_unix.c | 13 +++++++++---- src/version.c | 2 ++ 2 files changed, 11 insertions(+), 4 deletions(-) diff --git a/src/os_unix.c b/src/os_unix.c index f8fe2cb64b..8424b11a3c 100644 --- a/src/os_unix.c +++ b/src/os_unix.c @@ -1544,10 +1544,15 @@ x_error_handler(Display *dpy, XErrorEvent *error_event) XGetErrorText(dpy, error_event->error_code, (char *)IObuff, IOSIZE); STRCAT(IObuff, _("\nVim: Got X error\n")); - // We cannot print a message and continue, because no X calls are allowed - // here (causes my system to hang). Silently continuing might be an - // alternative... - preserve_exit(); // preserve files and exit + // In the GUI we cannot print a message and continue, because no X calls + // are allowed here (causes my system to hang). Silently continuing seems + // like the best alternative. Do preserve files, in case we crash. + ml_sync_all(FALSE, FALSE); + +#ifdef FEAT_GUI + if (!gui.in_use) +#endif + msg((char *)IObuff); return 0; // NOTREACHED } diff --git a/src/version.c b/src/version.c index 5903a00e26..456516f971 100644 --- a/src/version.c +++ b/src/version.c @@ -746,6 +746,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 720, /**/ 719, /**/ From 497f76bfbf9d5fe951221573d23696bb9e512c0b Mon Sep 17 00:00:00 2001 From: Bram Moolenaar <Bram@vim.org> Date: Sat, 9 May 2020 16:44:22 +0200 Subject: [PATCH 117/230] patch 8.2.0721: Vim9: leaking memory when skipping Problem: Vim9: leaking memory when skipping. Solution: Disable skipping in generate_ppconst(). --- src/version.c | 2 ++ src/vim9compile.c | 4 ++++ 2 files changed, 6 insertions(+) diff --git a/src/version.c b/src/version.c index 456516f971..f51f51df91 100644 --- a/src/version.c +++ b/src/version.c @@ -746,6 +746,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 721, /**/ 720, /**/ diff --git a/src/vim9compile.c b/src/vim9compile.c index 944efa197d..a41972520b 100644 --- a/src/vim9compile.c +++ b/src/vim9compile.c @@ -2417,11 +2417,14 @@ generate_ppconst(cctx_T *cctx, ppconst_T *ppconst) { int i; int ret = OK; + int save_skip = cctx->ctx_skip; + cctx->ctx_skip = FALSE; for (i = 0; i < ppconst->pp_used; ++i) if (generate_tv_PUSH(cctx, &ppconst->pp_tv[i]) == FAIL) ret = FAIL; ppconst->pp_used = 0; + cctx->ctx_skip = save_skip; return ret; } @@ -2754,6 +2757,7 @@ compile_call( ++ppconst->pp_used; return OK; } + clear_tv(&argvars[0]); } if (generate_ppconst(cctx, ppconst) == FAIL) From 7f14155f422ffcc997fc5a0b635a20a4bafd2093 Mon Sep 17 00:00:00 2001 From: Bram Moolenaar <Bram@vim.org> Date: Sat, 9 May 2020 17:35:53 +0200 Subject: [PATCH 118/230] patch 8.2.0722: Vim9: not handling constant expression for elseif Problem: Vim9: not handling constant expression for elseif. Solution: Use postponed constants. Delete the code for evaluating a constant expression. --- src/version.c | 2 + src/vim9compile.c | 431 +++------------------------------------------- 2 files changed, 24 insertions(+), 409 deletions(-) diff --git a/src/version.c b/src/version.c index f51f51df91..741e3b3042 100644 --- a/src/version.c +++ b/src/version.c @@ -746,6 +746,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 722, /**/ 721, /**/ diff --git a/src/vim9compile.c b/src/vim9compile.c index a41972520b..1042bb2701 100644 --- a/src/vim9compile.c +++ b/src/vim9compile.c @@ -3310,205 +3310,6 @@ get_vim_constant(char_u **arg, typval_T *rettv) } } -/* - * Evaluate an expression that is a constant: - * has(arg) - * - * Also handle: - * ! in front logical NOT - * - * Return FAIL if the expression is not a constant. - */ - static int -evaluate_const_expr7(char_u **arg, cctx_T *cctx UNUSED, typval_T *tv) -{ - typval_T argvars[2]; - char_u *start_leader, *end_leader; - int has_call = FALSE; - - /* - * Skip '!' characters. They are handled later. - * TODO: '-' and '+' characters - */ - start_leader = *arg; - while (**arg == '!') - *arg = skipwhite(*arg + 1); - end_leader = *arg; - - /* - * Recognize only a few types of constants for now. - */ - if (STRNCMP("true", *arg, 4) == 0 && !ASCII_ISALNUM((*arg)[4])) - { - tv->v_type = VAR_BOOL; - tv->vval.v_number = VVAL_TRUE; - *arg += 4; - return OK; - } - if (STRNCMP("false", *arg, 5) == 0 && !ASCII_ISALNUM((*arg)[5])) - { - tv->v_type = VAR_BOOL; - tv->vval.v_number = VVAL_FALSE; - *arg += 5; - return OK; - } - - if (STRNCMP("has(", *arg, 4) == 0) - { - has_call = TRUE; - *arg = skipwhite(*arg + 4); - } - - if (**arg == '"') - { - if (get_string_tv(arg, tv, TRUE) == FAIL) - return FAIL; - } - else if (**arg == '\'') - { - if (get_lit_string_tv(arg, tv, TRUE) == FAIL) - return FAIL; - } - else - return FAIL; - - if (has_call) - { - *arg = skipwhite(*arg); - if (**arg != ')') - return FAIL; - *arg = *arg + 1; - - argvars[0] = *tv; - argvars[1].v_type = VAR_UNKNOWN; - tv->v_type = VAR_NUMBER; - tv->vval.v_number = 0; - f_has(argvars, tv); - clear_tv(&argvars[0]); - - while (start_leader < end_leader) - { - if (*start_leader == '!') - tv->vval.v_number = !tv->vval.v_number; - ++start_leader; - } - } - else if (end_leader > start_leader) - { - clear_tv(tv); - return FAIL; - } - - return OK; -} - -/* - * * number multiplication - * / number division - * % number modulo - */ - static int -evaluate_const_expr6(char_u **arg, cctx_T *cctx, typval_T *tv) -{ - char_u *op; - - // get the first variable - if (evaluate_const_expr7(arg, cctx, tv) == FAIL) - return FAIL; - - /* - * Repeat computing, until no "*", "/" or "%" is following. - */ - for (;;) - { - op = skipwhite(*arg); - if (*op != '*' && *op != '/' && *op != '%') - break; - // TODO: not implemented yet. - clear_tv(tv); - return FAIL; - } - return OK; -} - -/* - * + number addition - * - number subtraction - * .. string concatenation - */ - static int -evaluate_const_expr5(char_u **arg, cctx_T *cctx, typval_T *tv) -{ - char_u *op; - int oplen; - - // get the first variable - if (evaluate_const_expr6(arg, cctx, tv) == FAIL) - return FAIL; - - /* - * Repeat computing, until no "+", "-" or ".." is following. - */ - for (;;) - { - op = skipwhite(*arg); - if (*op != '+' && *op != '-' && !(*op == '.' && (*(*arg + 1) == '.'))) - break; - oplen = (*op == '.' ? 2 : 1); - - if (!IS_WHITE_OR_NUL(**arg) || !IS_WHITE_OR_NUL(op[oplen])) - { - clear_tv(tv); - return FAIL; - } - - if (*op == '.' && tv->v_type == VAR_STRING) - { - typval_T tv2; - size_t len1; - char_u *s1, *s2; - - tv2.v_type = VAR_UNKNOWN; - *arg = skipwhite(op + oplen); - - // TODO: what if we fail??? - if (may_get_next_line(op + oplen, arg, cctx) == FAIL) - return FAIL; - - // get the second variable - if (evaluate_const_expr6(arg, cctx, &tv2) == FAIL) - { - clear_tv(tv); - return FAIL; - } - if (tv2.v_type != VAR_STRING) - { - clear_tv(tv); - clear_tv(&tv2); - return FAIL; - } - s1 = tv->vval.v_string; - len1 = STRLEN(s1); - s2 = tv2.vval.v_string; - tv->vval.v_string = alloc((int)(len1 + STRLEN(s2) + 1)); - if (tv->vval.v_string == NULL) - { - vim_free(s1); - vim_free(s2); - return FAIL; - } - mch_memmove(tv->vval.v_string, s1, len1); - STRCPY(tv->vval.v_string + len1, s2); - continue; - } - - // TODO: Not implemented yet. - clear_tv(tv); - return FAIL; - } - return OK; -} - static exptype_T get_compare_type(char_u *p, int *len, int *type_is) { @@ -3560,204 +3361,6 @@ get_compare_type(char_u *p, int *len, int *type_is) return type; } -/* - * Only comparing strings is supported right now. - * expr5a == expr5b - */ - static int -evaluate_const_expr4(char_u **arg, cctx_T *cctx UNUSED, typval_T *tv) -{ - exptype_T type = EXPR_UNKNOWN; - char_u *p; - int len = 2; - int type_is = FALSE; - - // get the first variable - if (evaluate_const_expr5(arg, cctx, tv) == FAIL) - return FAIL; - - p = skipwhite(*arg); - type = get_compare_type(p, &len, &type_is); - - /* - * If there is a comparative operator, use it. - */ - if (type != EXPR_UNKNOWN) - { - typval_T tv2; - char_u *s1, *s2; - char_u buf1[NUMBUFLEN], buf2[NUMBUFLEN]; - int n; - - // TODO: Only string == string is supported now - if (tv->v_type != VAR_STRING) - return FAIL; - if (type != EXPR_EQUAL) - return FAIL; - - // get the second variable - init_tv(&tv2); - *arg = skipwhite(p + len); - if (evaluate_const_expr5(arg, cctx, &tv2) == FAIL - || tv2.v_type != VAR_STRING) - { - clear_tv(&tv2); - return FAIL; - } - s1 = tv_get_string_buf(tv, buf1); - s2 = tv_get_string_buf(&tv2, buf2); - n = STRCMP(s1, s2); - clear_tv(tv); - clear_tv(&tv2); - tv->v_type = VAR_BOOL; - tv->vval.v_number = n == 0 ? VVAL_TRUE : VVAL_FALSE; - } - - return OK; -} - -static int evaluate_const_expr3(char_u **arg, cctx_T *cctx, typval_T *tv); - -/* - * Compile constant || or &&. - */ - static int -evaluate_const_and_or(char_u **arg, cctx_T *cctx, char *op, typval_T *tv) -{ - char_u *p = skipwhite(*arg); - int opchar = *op; - - if (p[0] == opchar && p[1] == opchar) - { - int val = tv2bool(tv); - - /* - * Repeat until there is no following "||" or "&&" - */ - while (p[0] == opchar && p[1] == opchar) - { - typval_T tv2; - - if (!VIM_ISWHITE(**arg) || !VIM_ISWHITE(p[2])) - return FAIL; - - // eval the next expression - *arg = skipwhite(p + 2); - tv2.v_type = VAR_UNKNOWN; - tv2.v_lock = 0; - if ((opchar == '|' ? evaluate_const_expr3(arg, cctx, &tv2) - : evaluate_const_expr4(arg, cctx, &tv2)) == FAIL) - { - clear_tv(&tv2); - return FAIL; - } - if ((opchar == '&') == val) - { - // false || tv2 or true && tv2: use tv2 - clear_tv(tv); - *tv = tv2; - val = tv2bool(tv); - } - else - clear_tv(&tv2); - p = skipwhite(*arg); - } - } - - return OK; -} - -/* - * Evaluate an expression that is a constant: expr4 && expr4 && expr4 - * Return FAIL if the expression is not a constant. - */ - static int -evaluate_const_expr3(char_u **arg, cctx_T *cctx, typval_T *tv) -{ - // evaluate the first expression - if (evaluate_const_expr4(arg, cctx, tv) == FAIL) - return FAIL; - - // || and && work almost the same - return evaluate_const_and_or(arg, cctx, "&&", tv); -} - -/* - * Evaluate an expression that is a constant: expr3 || expr3 || expr3 - * Return FAIL if the expression is not a constant. - */ - static int -evaluate_const_expr2(char_u **arg, cctx_T *cctx, typval_T *tv) -{ - // evaluate the first expression - if (evaluate_const_expr3(arg, cctx, tv) == FAIL) - return FAIL; - - // || and && work almost the same - return evaluate_const_and_or(arg, cctx, "||", tv); -} - -/* - * Evaluate an expression that is a constant: expr2 ? expr1 : expr1 - * E.g. for "has('feature')". - * This does not produce error messages. "tv" should be cleared afterwards. - * Return FAIL if the expression is not a constant. - */ - static int -evaluate_const_expr1(char_u **arg, cctx_T *cctx, typval_T *tv) -{ - char_u *p; - - // evaluate the first expression - if (evaluate_const_expr2(arg, cctx, tv) == FAIL) - return FAIL; - - p = skipwhite(*arg); - if (*p == '?') - { - int val = tv2bool(tv); - typval_T tv2; - - // require space before and after the ? - if (!VIM_ISWHITE(**arg) || !VIM_ISWHITE(p[1])) - return FAIL; - - // evaluate the second expression; any type is accepted - clear_tv(tv); - *arg = skipwhite(p + 1); - if (evaluate_const_expr1(arg, cctx, tv) == FAIL) - return FAIL; - - // Check for the ":". - p = skipwhite(*arg); - if (*p != ':' || !VIM_ISWHITE(**arg) || !VIM_ISWHITE(p[1])) - return FAIL; - - // evaluate the third expression - *arg = skipwhite(p + 1); - tv2.v_type = VAR_UNKNOWN; - if (evaluate_const_expr1(arg, cctx, &tv2) == FAIL) - { - clear_tv(&tv2); - return FAIL; - } - if (val) - { - // use the expr after "?" - clear_tv(&tv2); - } - else - { - // use the expr after ":" - clear_tv(tv); - *tv = tv2; - } - } - return OK; -} - -static int compile_expr3(char_u **arg, cctx_T *cctx, ppconst_T *ppconst); - /* * Compile code to apply '-', '+' and '!'. */ @@ -4471,6 +4074,8 @@ compile_expr4(char_u **arg, cctx_T *cctx, ppconst_T *ppconst) return OK; } +static int compile_expr3(char_u **arg, cctx_T *cctx, ppconst_T *ppconst); + /* * Compile || or &&. */ @@ -5727,9 +5332,10 @@ compile_elseif(char_u *arg, cctx_T *cctx) { char_u *p = arg; garray_T *instr = &cctx->ctx_instr; + int instr_count = instr->ga_len; isn_T *isn; scope_T *scope = cctx->ctx_scope; - typval_T tv; + ppconst_T ppconst; if (scope == NULL || scope->se_type != IF_SCOPE) { @@ -5749,24 +5355,31 @@ compile_elseif(char_u *arg, cctx_T *cctx) } // compile "expr"; if we know it evaluates to FALSE skip the block - tv.v_type = VAR_UNKNOWN; - if (evaluate_const_expr1(&p, cctx, &tv) == OK) - cctx->ctx_skip = tv2bool(&tv) ? FALSE : TRUE; - else - cctx->ctx_skip = MAYBE; - clear_tv(&tv); - if (cctx->ctx_skip == MAYBE) + CLEAR_FIELD(ppconst); + if (compile_expr1(&p, cctx, &ppconst) == FAIL) { - p = arg; - if (compile_expr0(&p, cctx) == FAIL) + clear_ppconst(&ppconst); + return NULL; + } + if (instr->ga_len == instr_count && ppconst.pp_used == 1) + { + // The expression results in a constant. + // TODO: how about nesting? + cctx->ctx_skip = tv2bool(&ppconst.pp_tv[0]) ? FALSE : TRUE; + clear_ppconst(&ppconst); + scope->se_u.se_if.is_if_label = -1; + } + else + { + // Not a constant, generate instructions for the expression. + cctx->ctx_skip = MAYBE; + if (generate_ppconst(cctx, &ppconst) == FAIL) return NULL; // "where" is set when ":elseif", "else" or ":endif" is found scope->se_u.se_if.is_if_label = instr->ga_len; generate_JUMP(cctx, JUMP_IF_FALSE, 0); } - else - scope->se_u.se_if.is_if_label = -1; return p; } From 1c74721233dac057778f9aef9ae20f49d934ec22 Mon Sep 17 00:00:00 2001 From: Bram Moolenaar <Bram@vim.org> Date: Sat, 9 May 2020 18:28:34 +0200 Subject: [PATCH 119/230] patch 8.2.0723: Vim9: nested constant expression not evaluated compile time Problem: Vim9: nested constant expression not evaluated compile time. Solution: Use compile_expr1() for parenthesis. --- src/testdir/test_vim9_disassemble.vim | 10 ++++++++++ src/version.c | 2 ++ src/vim9compile.c | 25 +++++++++++++++++++++---- 3 files changed, 33 insertions(+), 4 deletions(-) diff --git a/src/testdir/test_vim9_disassemble.vim b/src/testdir/test_vim9_disassemble.vim index 724087d703..610c565575 100644 --- a/src/testdir/test_vim9_disassemble.vim +++ b/src/testdir/test_vim9_disassemble.vim @@ -1053,6 +1053,10 @@ def s:ComputeConst(): number return 2 + 3 * 4 / 6 + 7 enddef +def s:ComputeConstParen(): number + return ((2 + 4) * (8 / 2)) / (3 + 4) +enddef + def Test_simplify_const_expr() let res = execute('disass s:ConcatStrings') assert_match('\<SNR>\d*_ConcatStrings.*' .. @@ -1065,6 +1069,12 @@ def Test_simplify_const_expr() '\d PUSHNR 11.*' .. '\d RETURN', res) + + res = execute('disass s:ComputeConstParen') + assert_match('\<SNR>\d*_ComputeConstParen.*' .. + '\d PUSHNR 3\>.*' .. + '\d RETURN', + res) enddef " vim: ts=8 sw=2 sts=2 expandtab tw=80 fdm=marker diff --git a/src/version.c b/src/version.c index 741e3b3042..3084d9b7ce 100644 --- a/src/version.c +++ b/src/version.c @@ -746,6 +746,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 723, /**/ 722, /**/ diff --git a/src/vim9compile.c b/src/vim9compile.c index 1042bb2701..5320cafc68 100644 --- a/src/vim9compile.c +++ b/src/vim9compile.c @@ -136,7 +136,6 @@ struct cctx_S { static char e_var_notfound[] = N_("E1001: variable not found: %s"); static char e_syntax_at[] = N_("E1002: Syntax error at %s"); -static int compile_expr0(char_u **arg, cctx_T *cctx); static void delete_def_function_contents(dfunc_T *dfunc); static void arg_type_mismatch(type_T *expected, type_T *actual, int argidx); static int check_type(type_T *expected, type_T *actual, int give_msg); @@ -2358,11 +2357,16 @@ may_get_next_line(char_u *whitep, char_u **arg, cctx_T *cctx) // possible expressions on these constants are applied at compile time. If // that is not possible, the code to push the constants needs to be generated // before other instructions. +// Using 50 should be more than enough of 5 levels of (). +#define PPSIZE 50 typedef struct { - typval_T pp_tv[10]; // stack of ppconst constants + typval_T pp_tv[PPSIZE]; // stack of ppconst constants int pp_used; // active entries in pp_tv[] } ppconst_T; +static int compile_expr0(char_u **arg, cctx_T *cctx); +static int compile_expr1(char_u **arg, cctx_T *cctx, ppconst_T *ppconst); + /* * Generate a PUSH instruction for "tv". * "tv" will be consumed or cleared. @@ -3590,6 +3594,7 @@ compile_expr7( char_u *start_leader, *end_leader; int ret = OK; typval_T *rettv = &ppconst->pp_tv[ppconst->pp_used]; + int used_before = ppconst->pp_used; /* * Skip '!', '-' and '+' characters. They are handled later. @@ -3725,7 +3730,19 @@ compile_expr7( * nested expression: (expression). */ case '(': *arg = skipwhite(*arg + 1); - ret = compile_expr0(arg, cctx); // recursive! + + // recursive! + if (ppconst->pp_used <= PPSIZE - 10) + { + ret = compile_expr1(arg, cctx, ppconst); + } + else + { + // Not enough space in ppconst, flush constants. + if (generate_ppconst(cctx, ppconst) == FAIL) + return FAIL; + ret = compile_expr0(arg, cctx); + } *arg = skipwhite(*arg); if (**arg == ')') ++*arg; @@ -3742,7 +3759,7 @@ compile_expr7( if (ret == FAIL) return FAIL; - if (rettv->v_type != VAR_UNKNOWN) + if (rettv->v_type != VAR_UNKNOWN && used_before == ppconst->pp_used) { // apply the '!', '-' and '+' before the constant if (apply_leader(rettv, start_leader, end_leader) == FAIL) From 396f3138ca83ce844679143861f544070683d479 Mon Sep 17 00:00:00 2001 From: Bram Moolenaar <Bram@vim.org> Date: Sat, 9 May 2020 18:44:56 +0200 Subject: [PATCH 120/230] patch 8.2.0724: Vim9: appending to buffer/window/tab variable not tested Problem: Vim9: appending to buffer/window/tab variable not tested Solution: Add a test. --- src/testdir/test_vim9_script.vim | 6 ++++++ src/version.c | 2 ++ 2 files changed, 8 insertions(+) diff --git a/src/testdir/test_vim9_script.vim b/src/testdir/test_vim9_script.vim index 7768eb082b..564e51d0af 100644 --- a/src/testdir/test_vim9_script.vim +++ b/src/testdir/test_vim9_script.vim @@ -135,18 +135,24 @@ def Test_assignment_local() assert_equal('yes', b:existing) b:existing = 'no' assert_equal('no', b:existing) + b:existing ..= 'NO' + assert_equal('noNO', b:existing) w:newvar = 'new' assert_equal('new', w:newvar) assert_equal('yes', w:existing) w:existing = 'no' assert_equal('no', w:existing) + w:existing ..= 'NO' + assert_equal('noNO', w:existing) t:newvar = 'new' assert_equal('new', t:newvar) assert_equal('yes', t:existing) t:existing = 'no' assert_equal('no', t:existing) + t:existing ..= 'NO' + assert_equal('noNO', t:existing) enddef call Test_assignment_local_internal() END diff --git a/src/version.c b/src/version.c index 3084d9b7ce..38da744e46 100644 --- a/src/version.c +++ b/src/version.c @@ -746,6 +746,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 724, /**/ 723, /**/ From 09689a02840be40fa7bb10b1921fb5bc5b2908f1 Mon Sep 17 00:00:00 2001 From: Bram Moolenaar <Bram@vim.org> Date: Sat, 9 May 2020 22:50:08 +0200 Subject: [PATCH 121/230] patch 8.2.0725: Vim9: cannot call a function declared later in Vim9 script Problem: Vim9: cannot call a function declared later in Vim9 script. Solution: Make two passes through the script file. --- src/evalvars.c | 17 +++-- src/proto/evalvars.pro | 1 + src/proto/scriptfile.pro | 2 + src/proto/userfunc.pro | 2 +- src/proto/vim9compile.pro | 1 + src/scriptfile.c | 51 +++++++++++++++ src/testdir/test_vim9_disassemble.vim | 25 +++++++ src/userfunc.c | 9 +-- src/version.c | 2 + src/vim.h | 1 + src/vim9compile.c | 53 ++++++++------- src/vim9execute.c | 7 ++ src/vim9script.c | 93 ++++++++++++++++++++++++++- 13 files changed, 229 insertions(+), 35 deletions(-) diff --git a/src/evalvars.c b/src/evalvars.c index 0935bb3ebc..01aef1ae69 100644 --- a/src/evalvars.c +++ b/src/evalvars.c @@ -164,7 +164,6 @@ static dict_T vimvardict; // Dictionary with v: variables // for VIM_VERSION_ defines #include "version.h" -static void ex_let_const(exarg_T *eap, int is_const); static char_u *skip_var_one(char_u *arg, int include_type); static void list_glob_vars(int *first); static void list_buf_vars(int *first); @@ -698,11 +697,15 @@ ex_let(exarg_T *eap) void ex_const(exarg_T *eap) { - ex_let_const(eap, TRUE); + ex_let_const(eap, FALSE); } - static void -ex_let_const(exarg_T *eap, int is_const) +/* + * When "redefine" is TRUE the command will be executed again, redefining the + * variable is OK then. + */ + void +ex_let_const(exarg_T *eap, int redefine) { char_u *arg = eap->arg; char_u *expr = NULL; @@ -714,11 +717,13 @@ ex_let_const(exarg_T *eap, int is_const) char_u *argend; int first = TRUE; int concat; - int flags = is_const ? LET_IS_CONST : 0; + int flags = eap->cmdidx == CMD_const ? LET_IS_CONST : 0; // detect Vim9 assignment without ":let" or ":const" if (eap->arg == eap->cmd) flags |= LET_NO_COMMAND; + if (redefine) + flags |= LET_REDEFINE; argend = skip_var_list(arg, TRUE, &var_count, &semicolon); if (argend == NULL) @@ -2976,6 +2981,8 @@ set_var_const( if (flags & LET_IS_CONST) di->di_tv.v_lock |= VAR_LOCKED; + if (flags & LET_REDEFINE) + di->di_flags |= DI_FLAGS_RELOAD; } /* diff --git a/src/proto/evalvars.pro b/src/proto/evalvars.pro index 58e922113e..3d07a6dfeb 100644 --- a/src/proto/evalvars.pro +++ b/src/proto/evalvars.pro @@ -16,6 +16,7 @@ void restore_vimvar(int idx, typval_T *save_tv); list_T *heredoc_get(exarg_T *eap, char_u *cmd, int script_get); void ex_let(exarg_T *eap); void ex_const(exarg_T *eap); +void ex_let_const(exarg_T *eap, int redefine); int ex_let_vars(char_u *arg_start, typval_T *tv, int copy, int semicolon, int var_count, int flags, char_u *op); char_u *skip_var_list(char_u *arg, int include_type, int *var_count, int *semicolon); void list_hashtable_vars(hashtab_T *ht, char *prefix, int empty, int *first); diff --git a/src/proto/scriptfile.pro b/src/proto/scriptfile.pro index 111e855a74..84536ba78e 100644 --- a/src/proto/scriptfile.pro +++ b/src/proto/scriptfile.pro @@ -19,6 +19,8 @@ int ExpandPackAddDir(char_u *pat, int *num_file, char_u ***file); void ex_source(exarg_T *eap); void ex_options(exarg_T *eap); linenr_T *source_breakpoint(void *cookie); +garray_T *source_get_line_ga(void *cookie); +void source_use_line_ga(void *cookie); int *source_dbg_tick(void *cookie); int source_level(void *cookie); int do_source(char_u *fname, int check_other, int is_vimrc, int *ret_sid); diff --git a/src/proto/userfunc.pro b/src/proto/userfunc.pro index 44ed397ea7..4295ce269f 100644 --- a/src/proto/userfunc.pro +++ b/src/proto/userfunc.pro @@ -23,7 +23,7 @@ void user_func_error(int error, char_u *name); int call_func(char_u *funcname, int len, typval_T *rettv, int argcount_in, typval_T *argvars_in, funcexe_T *funcexe); char_u *trans_function_name(char_u **pp, int *is_global, int skip, int flags, funcdict_T *fdp, partial_T **partial); char_u *untrans_function_name(char_u *name); -ufunc_T *def_function(exarg_T *eap, char_u *name_arg, void *context); +ufunc_T *def_function(exarg_T *eap, char_u *name_arg, void *context, int compile); void ex_function(exarg_T *eap); int eval_fname_script(char_u *p); int translated_function_exists(char_u *name, int is_global); diff --git a/src/proto/vim9compile.pro b/src/proto/vim9compile.pro index 76fca4f95f..6a3d9b5b23 100644 --- a/src/proto/vim9compile.pro +++ b/src/proto/vim9compile.pro @@ -9,6 +9,7 @@ imported_T *find_imported(char_u *name, size_t len, cctx_T *cctx); char_u *to_name_const_end(char_u *arg); int assignment_len(char_u *p, int *heredoc); int check_vim9_unlet(char_u *name); +int add_def_function(ufunc_T *ufunc); void compile_def_function(ufunc_T *ufunc, int set_return_type, cctx_T *outer_cctx); void delete_instr(isn_T *isn); void delete_def_function(ufunc_T *ufunc); diff --git a/src/scriptfile.c b/src/scriptfile.c index 155ab14bb7..ba74a8aece 100644 --- a/src/scriptfile.c +++ b/src/scriptfile.c @@ -998,6 +998,8 @@ struct source_cookie int error; // TRUE if LF found after CR-LF #endif #ifdef FEAT_EVAL + garray_T lines_ga; // lines read in previous pass + int use_lines_ga; // next line to get from "lines_ga" linenr_T breakpoint; // next line with breakpoint or zero char_u *fname; // name of sourced file int dbg_tick; // debug_tick when breakpoint was set @@ -1016,6 +1018,24 @@ source_breakpoint(void *cookie) return &((struct source_cookie *)cookie)->breakpoint; } +/* + * Get the grow array to store script lines in. + */ + garray_T * +source_get_line_ga(void *cookie) +{ + return &((struct source_cookie *)cookie)->lines_ga; +} + +/* + * Set the index to start reading from the grow array with script lines. + */ + void +source_use_line_ga(void *cookie) +{ + ((struct source_cookie *)cookie)->use_lines_ga = 0; +} + /* * Return the address holding the debug tick for a source cookie. */ @@ -1235,6 +1255,9 @@ do_source( cookie.finished = FALSE; #ifdef FEAT_EVAL + ga_init2(&cookie.lines_ga, sizeof(char_u *), 200); + cookie.use_lines_ga = -1; + // Check if this script has a breakpoint. cookie.breakpoint = dbg_find_breakpoint(TRUE, fname_exp, (linenr_T)0); cookie.fname = fname_exp; @@ -1447,6 +1470,9 @@ almosttheend: vim_free(cookie.nextline); vim_free(firstline); convert_setup(&cookie.conv, NULL, NULL); +#ifdef FEAT_EVAL + ga_clear_strings(&cookie.lines_ga); +#endif if (trigger_source_post) apply_autocmds(EVENT_SOURCEPOST, fname_exp, fname_exp, FALSE, curbuf); @@ -1702,6 +1728,31 @@ getsourceline(int c UNUSED, void *cookie, int indent UNUSED, int do_concat) // one now. if (sp->finished) line = NULL; +#ifdef FEAT_EVAL + else if (sp->use_lines_ga >= 0) + { + // Get a line that was read in ex_vim9script(). + for (;;) + { + if (sp->use_lines_ga >= sp->lines_ga.ga_len) + { + line = NULL; + break; + } + else + { + line = ((char_u **)(sp->lines_ga.ga_data))[sp->use_lines_ga]; + ((char_u **)(sp->lines_ga.ga_data))[sp->use_lines_ga] = NULL; + ++sp->use_lines_ga; + if (line != NULL) + break; + // Skip NULL lines, they are equivalent to blank lines. + ++sp->sourcing_lnum; + } + } + SOURCING_LNUM = sp->sourcing_lnum + 1; + } +#endif else if (sp->nextline == NULL) line = get_one_sourceline(sp); else diff --git a/src/testdir/test_vim9_disassemble.vim b/src/testdir/test_vim9_disassemble.vim index 610c565575..7213ee4ff7 100644 --- a/src/testdir/test_vim9_disassemble.vim +++ b/src/testdir/test_vim9_disassemble.vim @@ -1045,6 +1045,31 @@ def Test_display_func() res3) enddef +def Test_vim9script_forward_func() + let lines =<< trim END + vim9script + def FuncOne(): string + return FuncTwo() + enddef + def FuncTwo(): string + return 'two' + enddef + let g:res_FuncOne = execute('disass FuncOne') + END + writefile(lines, 'Xdisassemble') + source Xdisassemble + + " check that the first function calls the second with DCALL + assert_match('\<SNR>\d*_FuncOne.*' .. + 'return FuncTwo().*' .. + '\d DCALL <SNR>\d\+_FuncTwo(argc 0).*' .. + '\d RETURN', + g:res_FuncOne) + + delete('Xdisassemble') + unlet g:res_FuncOne +enddef + def s:ConcatStrings(): string return 'one' .. 'two' .. 'three' enddef diff --git a/src/userfunc.c b/src/userfunc.c index 1d5f5d5bc1..b33aee7741 100644 --- a/src/userfunc.c +++ b/src/userfunc.c @@ -2378,7 +2378,7 @@ untrans_function_name(char_u *name) * Returns a pointer to the function or NULL if no function defined. */ ufunc_T * -def_function(exarg_T *eap, char_u *name_arg, void *context) +def_function(exarg_T *eap, char_u *name_arg, void *context, int compile) { char_u *theline; char_u *line_to_free = NULL; @@ -3241,6 +3241,7 @@ def_function(exarg_T *eap, char_u *name_arg, void *context) p = ret_type; fp->uf_ret_type = parse_type(&p, &fp->uf_type_list); } + SOURCING_LNUM = lnum_save; } fp->uf_lines = newlines; @@ -3273,8 +3274,8 @@ def_function(exarg_T *eap, char_u *name_arg, void *context) is_export = FALSE; } - // ":def Func()" needs to be compiled - if (eap->cmdidx == CMD_def) + // ":def Func()" may need to be compiled + if (eap->cmdidx == CMD_def && compile) compile_def_function(fp, FALSE, context); goto ret_free; @@ -3304,7 +3305,7 @@ ret_free: void ex_function(exarg_T *eap) { - def_function(eap, NULL, NULL); + (void)def_function(eap, NULL, NULL, TRUE); } /* diff --git a/src/version.c b/src/version.c index 38da744e46..bc93675ab4 100644 --- a/src/version.c +++ b/src/version.c @@ -746,6 +746,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 725, /**/ 724, /**/ diff --git a/src/vim.h b/src/vim.h index d882e50198..c84d5a596c 100644 --- a/src/vim.h +++ b/src/vim.h @@ -2133,6 +2133,7 @@ typedef enum { // Flags for assignment functions. #define LET_IS_CONST 1 // ":const" #define LET_NO_COMMAND 2 // "var = expr" without ":let" or ":const" +#define LET_REDEFINE 4 // variable can be redefined later #include "ex_cmds.h" // Ex command defines #include "spell.h" // spell checking stuff diff --git a/src/vim9compile.c b/src/vim9compile.c index 5320cafc68..5b016e63c4 100644 --- a/src/vim9compile.c +++ b/src/vim9compile.c @@ -4441,7 +4441,7 @@ compile_nested_function(exarg_T *eap, cctx_T *cctx) eap->cookie = cctx; eap->skip = cctx->ctx_skip == TRUE; eap->forceit = FALSE; - ufunc = def_function(eap, name, cctx); + ufunc = def_function(eap, name, cctx, TRUE); if (ufunc == NULL || ufunc->uf_dfunc_idx < 0) return NULL; @@ -6130,6 +6130,27 @@ theend: return (char_u *)""; } +/* + * Add a function to the list of :def functions. + * This "sets ufunc->uf_dfunc_idx" but the function isn't compiled yet. + */ + int +add_def_function(ufunc_T *ufunc) +{ + dfunc_T *dfunc; + + // Add the function to "def_functions". + if (ga_grow(&def_functions, 1) == FAIL) + return FAIL; + dfunc = ((dfunc_T *)def_functions.ga_data) + def_functions.ga_len; + CLEAR_POINTER(dfunc); + dfunc->df_idx = def_functions.ga_len; + ufunc->uf_dfunc_idx = dfunc->df_idx; + dfunc->df_ufunc = ufunc; + ++def_functions.ga_len; + return OK; +} + /* * After ex_function() has collected all the function lines: parse and compile * the lines into instructions. @@ -6154,30 +6175,16 @@ compile_def_function(ufunc_T *ufunc, int set_return_type, cctx_T *outer_cctx) sctx_T save_current_sctx = current_sctx; int emsg_before = called_emsg; + if (ufunc->uf_dfunc_idx >= 0) { - dfunc_T *dfunc; // may be invalidated by compile_lambda() - - if (ufunc->uf_dfunc_idx >= 0) - { - // Redefining a function that was compiled before. - dfunc = ((dfunc_T *)def_functions.ga_data) + ufunc->uf_dfunc_idx; - - // Free old instructions. - delete_def_function_contents(dfunc); - } - else - { - // Add the function to "def_functions". - if (ga_grow(&def_functions, 1) == FAIL) - return; - dfunc = ((dfunc_T *)def_functions.ga_data) + def_functions.ga_len; - CLEAR_POINTER(dfunc); - dfunc->df_idx = def_functions.ga_len; - ufunc->uf_dfunc_idx = dfunc->df_idx; - dfunc->df_ufunc = ufunc; - ++def_functions.ga_len; - } + // Redefining a function that was compiled before. + dfunc_T *dfunc = ((dfunc_T *)def_functions.ga_data) + + ufunc->uf_dfunc_idx; + // Free old instructions. + delete_def_function_contents(dfunc); } + else if (add_def_function(ufunc) == FAIL) + return; CLEAR_FIELD(cctx); cctx.ctx_ufunc = ufunc; diff --git a/src/vim9execute.c b/src/vim9execute.c index a505647df5..bfa24928a8 100644 --- a/src/vim9execute.c +++ b/src/vim9execute.c @@ -669,6 +669,13 @@ call_def_function( ga_init2(&ectx.ec_stack, sizeof(typval_T), 500); if (ga_grow(&ectx.ec_stack, 20) == FAIL) return FAIL; + { + // Check the function was compiled, it is postponed in ex_vim9script(). + dfunc_T *dfunc = ((dfunc_T *)def_functions.ga_data) + + ufunc->uf_dfunc_idx; + if (dfunc->df_instr == NULL) + return FAIL; + } ectx.ec_dfunc_idx = ufunc->uf_dfunc_idx; ga_init2(&ectx.ec_trystack, sizeof(trycmd_T), 10); diff --git a/src/vim9script.c b/src/vim9script.c index afd6a4af97..8bc1962bfd 100644 --- a/src/vim9script.c +++ b/src/vim9script.c @@ -32,7 +32,11 @@ in_vim9script(void) void ex_vim9script(exarg_T *eap) { - scriptitem_T *si = SCRIPT_ITEM(current_sctx.sc_sid); + scriptitem_T *si = SCRIPT_ITEM(current_sctx.sc_sid); + garray_T *gap; + garray_T func_ga; + int idx; + ufunc_T *ufunc; if (!getline_equal(eap->getline, eap->cookie, getsourceline)) { @@ -47,12 +51,97 @@ ex_vim9script(exarg_T *eap) current_sctx.sc_version = SCRIPT_VERSION_VIM9; si->sn_version = SCRIPT_VERSION_VIM9; si->sn_had_command = TRUE; + ga_init2(&func_ga, sizeof(ufunc_T *), 20); if (STRCMP(p_cpo, CPO_VIM) != 0) { si->sn_save_cpo = p_cpo; p_cpo = vim_strsave((char_u *)CPO_VIM); } + + // Make a pass through the script to find: + // - function declarations + // - variable and constant declarations + // - imports + // The types are recognized, so that they can be used when compiling a + // function. + gap = source_get_line_ga(eap->cookie); + for (;;) + { + char_u *line; + char_u *p; + + if (ga_grow(gap, 1) == FAIL) + return; + line = eap->getline(':', eap->cookie, 0, TRUE); + if (line == NULL) + break; + ((char_u **)(gap->ga_data))[gap->ga_len++] = line; + line = skipwhite(line); + p = line; + if (checkforcmd(&p, "function", 2) || checkforcmd(&p, "def", 3)) + { + int lnum_start = SOURCING_LNUM - 1; + + // Handle :function and :def by calling def_function(). + // It will read upto the matching :endded or :endfunction. + eap->cmdidx = *line == 'f' ? CMD_function : CMD_def; + eap->cmd = line; + eap->arg = p; + eap->forceit = FALSE; + ufunc = def_function(eap, NULL, NULL, FALSE); + + if (ufunc != NULL && *line == 'd' && ga_grow(&func_ga, 1) == OK) + { + // Add the function to the list of :def functions, so that it + // can be referenced by index. It's compiled below. + add_def_function(ufunc); + ((ufunc_T **)(func_ga.ga_data))[func_ga.ga_len++] = ufunc; + } + + // Store empty lines in place of the function, we don't need to + // process it again. + vim_free(((char_u **)(gap->ga_data))[--gap->ga_len]); + if (ga_grow(gap, SOURCING_LNUM - lnum_start) == OK) + while (lnum_start < SOURCING_LNUM) + { + // getsourceline() will skip over NULL lines. + ((char_u **)(gap->ga_data))[gap->ga_len++] = NULL; + ++lnum_start; + } + } + else if (checkforcmd(&p, "let", 3) || checkforcmd(&p, "const", 4)) + { + eap->cmd = line; + eap->arg = p; + eap->forceit = FALSE; + eap->cmdidx = *line == 'l' ? CMD_let: CMD_const; + + // The command will be executed again, it's OK to redefine the + // variable then. + ex_let_const(eap, TRUE); + } + else if (checkforcmd(&p, "import", 3)) + { + eap->arg = p; + ex_import(eap); + + // Store empty line, we don't need to process the command again. + vim_free(((char_u **)(gap->ga_data))[--gap->ga_len]); + ((char_u **)(gap->ga_data))[gap->ga_len++] = NULL; + } + } + + // Compile the :def functions. + for (idx = 0; idx < func_ga.ga_len; ++idx) + { + ufunc = ((ufunc_T **)(func_ga.ga_data))[idx]; + compile_def_function(ufunc, FALSE, NULL); + } + ga_clear(&func_ga); + + // Return to process the commands at the script level. + source_use_line_ga(eap->cookie); } /* @@ -64,7 +153,7 @@ ex_vim9script(exarg_T *eap) * ":export {Name, ...}" */ void -ex_export(exarg_T *eap UNUSED) +ex_export(exarg_T *eap) { if (current_sctx.sc_version != SCRIPT_VERSION_VIM9) { From 3b6a6eb7b4e0ac5b75dd2518bd27bce2b13298a3 Mon Sep 17 00:00:00 2001 From: Bram Moolenaar <Bram@vim.org> Date: Sat, 9 May 2020 23:20:20 +0200 Subject: [PATCH 122/230] patch 8.2.0726: Vim9: leaking memory when calling not compiled :def function Problem: Vim9: leaking memory when calling not compiled :def function. Solution: Check if function is compiled earlier. --- src/version.c | 2 ++ src/vim9execute.c | 10 +++++----- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/src/version.c b/src/version.c index bc93675ab4..ef7dedb980 100644 --- a/src/version.c +++ b/src/version.c @@ -746,6 +746,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 726, /**/ 725, /**/ diff --git a/src/vim9execute.c b/src/vim9execute.c index bfa24928a8..4d4df0ab60 100644 --- a/src/vim9execute.c +++ b/src/vim9execute.c @@ -665,10 +665,6 @@ call_def_function( // Like STACK_TV_VAR but use the outer scope #define STACK_OUT_TV_VAR(idx) (((typval_T *)ectx.ec_outer_stack->ga_data) + ectx.ec_outer_frame + STACK_FRAME_SIZE + idx) - CLEAR_FIELD(ectx); - ga_init2(&ectx.ec_stack, sizeof(typval_T), 500); - if (ga_grow(&ectx.ec_stack, 20) == FAIL) - return FAIL; { // Check the function was compiled, it is postponed in ex_vim9script(). dfunc_T *dfunc = ((dfunc_T *)def_functions.ga_data) @@ -676,8 +672,12 @@ call_def_function( if (dfunc->df_instr == NULL) return FAIL; } - ectx.ec_dfunc_idx = ufunc->uf_dfunc_idx; + CLEAR_FIELD(ectx); + ectx.ec_dfunc_idx = ufunc->uf_dfunc_idx; + ga_init2(&ectx.ec_stack, sizeof(typval_T), 500); + if (ga_grow(&ectx.ec_stack, 20) == FAIL) + return FAIL; ga_init2(&ectx.ec_trystack, sizeof(trycmd_T), 10); // Put arguments on the stack. From d695ba732de915fc227c1069a7a4e1d5049601bd Mon Sep 17 00:00:00 2001 From: Bram Moolenaar <Bram@vim.org> Date: Sun, 10 May 2020 13:42:43 +0200 Subject: [PATCH 123/230] patch 8.2.0727: MS-Windows: new gcc compiler does not support scanf format Problem: MS-Windows: new gcc compiler does not support scanf format. Solution: Use "%ll" instead of "%I". (Ken Takata) --- src/version.c | 2 ++ src/vim.h | 6 +++--- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/src/version.c b/src/version.c index ef7dedb980..55b865409e 100644 --- a/src/version.c +++ b/src/version.c @@ -746,6 +746,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 727, /**/ 726, /**/ diff --git a/src/vim.h b/src/vim.h index c84d5a596c..9e4c61db37 100644 --- a/src/vim.h +++ b/src/vim.h @@ -340,9 +340,9 @@ typedef unsigned int int_u; #ifdef _WIN64 typedef unsigned __int64 long_u; typedef __int64 long_i; -# define SCANF_HEX_LONG_U "%Ix" -# define SCANF_DECIMAL_LONG_U "%Iu" -# define PRINTF_HEX_LONG_U "0x%Ix" +# define SCANF_HEX_LONG_U "%llx" +# define SCANF_DECIMAL_LONG_U "%llu" +# define PRINTF_HEX_LONG_U "0x%llx" #else // Microsoft-specific. The __w64 keyword should be specified on any typedefs // that change size between 32-bit and 64-bit platforms. For any such type, From 69212b11d18d9d8951968f6ca88e6ce046c90675 Mon Sep 17 00:00:00 2001 From: Bram Moolenaar <Bram@vim.org> Date: Sun, 10 May 2020 14:14:03 +0200 Subject: [PATCH 124/230] patch 8.2.0728: messages about a deadly signal are not left aligned Problem: Messages about a deadly signal are not left aligned. Solution: Output a CR before the NL. (Dominique Pelle, #6055) --- src/misc1.c | 4 ++-- src/os_unix.c | 4 ++-- src/version.c | 2 ++ 3 files changed, 6 insertions(+), 4 deletions(-) diff --git a/src/misc1.c b/src/misc1.c index 6686a35146..a370a82f8d 100644 --- a/src/misc1.c +++ b/src/misc1.c @@ -2174,7 +2174,7 @@ preserve_exit(void) { if (buf->b_ml.ml_mfp != NULL && buf->b_ml.ml_mfp->mf_fname != NULL) { - OUT_STR("Vim: preserving files...\n"); + OUT_STR("Vim: preserving files...\r\n"); screen_start(); // don't know where cursor is now out_flush(); ml_sync_all(FALSE, FALSE); // preserve all swap files @@ -2184,7 +2184,7 @@ preserve_exit(void) ml_close_all(FALSE); // close all memfiles, without deleting - OUT_STR("Vim: Finished.\n"); + OUT_STR("Vim: Finished.\r\n"); getout(1); } diff --git a/src/os_unix.c b/src/os_unix.c index 8424b11a3c..596fb0e906 100644 --- a/src/os_unix.c +++ b/src/os_unix.c @@ -1083,10 +1083,10 @@ deathtrap SIGDEFARG(sigarg) // No translation, it may call malloc(). #ifdef SIGHASARG - sprintf((char *)IObuff, "Vim: Caught deadly signal %s\n", + sprintf((char *)IObuff, "Vim: Caught deadly signal %s\r\n", signal_info[i].name); #else - sprintf((char *)IObuff, "Vim: Caught deadly signal\n"); + sprintf((char *)IObuff, "Vim: Caught deadly signal\r\n"); #endif // Preserve files and exit. This sets the really_exiting flag to prevent diff --git a/src/version.c b/src/version.c index 55b865409e..c595e9df45 100644 --- a/src/version.c +++ b/src/version.c @@ -746,6 +746,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 728, /**/ 727, /**/ From 89483d40438830fb9e74a5ec6c92d2470b05e4c2 Mon Sep 17 00:00:00 2001 From: Bram Moolenaar <Bram@vim.org> Date: Sun, 10 May 2020 15:24:44 +0200 Subject: [PATCH 125/230] patch 8.2.0729: Vim9: When reloading a script variables are not cleared Problem: Vim9: When reloading a script variables are not cleared. Solution: When sourcing a script again clear all script-local variables. --- src/dict.c | 21 +++++++++++++++------ src/proto/dict.pro | 1 + src/scriptfile.c | 27 ++++++++++++++++----------- src/testdir/test_vim9_script.vim | 26 +++++++++++++++++++++++--- src/version.c | 2 ++ 5 files changed, 57 insertions(+), 20 deletions(-) diff --git a/src/dict.c b/src/dict.c index 88bd0e21c6..54d3110b02 100644 --- a/src/dict.c +++ b/src/dict.c @@ -104,29 +104,38 @@ rettv_dict_set(typval_T *rettv, dict_T *d) */ void dict_free_contents(dict_T *d) +{ + hashtab_free_contents(&d->dv_hashtab); +} + +/* + * Clear hashtab "ht" and dict items it contains. + */ + void +hashtab_free_contents(hashtab_T *ht) { int todo; hashitem_T *hi; dictitem_T *di; // Lock the hashtab, we don't want it to resize while freeing items. - hash_lock(&d->dv_hashtab); - todo = (int)d->dv_hashtab.ht_used; - for (hi = d->dv_hashtab.ht_array; todo > 0; ++hi) + hash_lock(ht); + todo = (int)ht->ht_used; + for (hi = ht->ht_array; todo > 0; ++hi) { if (!HASHITEM_EMPTY(hi)) { // Remove the item before deleting it, just in case there is // something recursive causing trouble. di = HI2DI(hi); - hash_remove(&d->dv_hashtab, hi); + hash_remove(ht, hi); dictitem_free(di); --todo; } } - // The hashtab is still locked, it has to be re-initialized anyway - hash_clear(&d->dv_hashtab); + // The hashtab is still locked, it has to be re-initialized anyway. + hash_clear(ht); } static void diff --git a/src/proto/dict.pro b/src/proto/dict.pro index d9b35c3091..45bcfbf3a9 100644 --- a/src/proto/dict.pro +++ b/src/proto/dict.pro @@ -5,6 +5,7 @@ dict_T *dict_alloc_lock(int lock); int rettv_dict_alloc(typval_T *rettv); void rettv_dict_set(typval_T *rettv, dict_T *d); void dict_free_contents(dict_T *d); +void hashtab_free_contents(hashtab_T *ht); void dict_unref(dict_T *d); int dict_free_nonref(int copyID); void dict_free_items(int copyID); diff --git a/src/scriptfile.c b/src/scriptfile.c index ba74a8aece..86e8b01105 100644 --- a/src/scriptfile.c +++ b/src/scriptfile.c @@ -1295,9 +1295,6 @@ do_source( if (sid > 0) { hashtab_T *ht; - hashitem_T *hi; - dictitem_T *di; - int todo; int is_vim9 = si->sn_version == SCRIPT_VERSION_VIM9; // loading the same script again @@ -1306,14 +1303,22 @@ do_source( current_sctx.sc_sid = sid; ht = &SCRIPT_VARS(sid); - todo = (int)ht->ht_used; - for (hi = ht->ht_array; todo > 0; ++hi) - if (!HASHITEM_EMPTY(hi)) - { - --todo; - di = HI2DI(hi); - di->di_flags |= DI_FLAGS_RELOAD; - } + if (is_vim9) + hashtab_free_contents(ht); + else + { + int todo = (int)ht->ht_used; + hashitem_T *hi; + dictitem_T *di; + + for (hi = ht->ht_array; todo > 0; ++hi) + if (!HASHITEM_EMPTY(hi)) + { + --todo; + di = HI2DI(hi); + di->di_flags |= DI_FLAGS_RELOAD; + } + } // old imports are no longer valid free_imports(sid); diff --git a/src/testdir/test_vim9_script.vim b/src/testdir/test_vim9_script.vim index 564e51d0af..d1cc1f9de3 100644 --- a/src/testdir/test_vim9_script.vim +++ b/src/testdir/test_vim9_script.vim @@ -610,7 +610,6 @@ def Test_vim9_import_export() let import_star_lines =<< trim END vim9script import * from './Xexport.vim' - g:imported = exported END writefile(import_star_lines, 'Ximport.vim') assert_fails('source Ximport.vim', 'E1045:') @@ -807,6 +806,28 @@ def Test_vim9script_reload_delfunc() delete('Xreloaded.vim') enddef +def Test_vim9script_reload_delvar() + # write the script with a script-local variable + let lines =<< trim END + vim9script + let var = 'string' + END + writefile(lines, 'XreloadVar.vim') + source XreloadVar.vim + + # now write the script using the same variable locally - works + lines =<< trim END + vim9script + def Func() + let var = 'string' + enddef + END + writefile(lines, 'XreloadVar.vim') + source XreloadVar.vim + + delete('XreloadVar.vim') +enddef + def Test_import_absolute() let import_lines = [ 'vim9script', @@ -862,8 +883,7 @@ def Test_import_rtp() unlet g:imported_rtp delete('Ximport_rtp.vim') - delete('import/Xexport_rtp.vim') - delete('import', 'd') + delete('import', 'rf') enddef def Test_fixed_size_list() diff --git a/src/version.c b/src/version.c index c595e9df45..4bf6242645 100644 --- a/src/version.c +++ b/src/version.c @@ -746,6 +746,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 729, /**/ 728, /**/ From 1cc2a94f80ba982f83d1e2d37c4726867e36bd9f Mon Sep 17 00:00:00 2001 From: Bram Moolenaar <Bram@vim.org> Date: Sun, 10 May 2020 19:10:31 +0200 Subject: [PATCH 126/230] patch 8.2.0730: Vim9: Assignment to dict member does not work Problem: Vim9: Assignment to dict member does not work. Solution: Parse dict assignment. Implement getting dict member. --- src/globals.h | 1 + src/testdir/test_vim9_cmd.vim | 22 ++ src/testdir/test_vim9_expr.vim | 4 +- src/testdir/test_vim9_script.vim | 2 +- src/version.c | 2 + src/vim9.h | 5 +- src/vim9compile.c | 481 ++++++++++++++++++++----------- src/vim9execute.c | 117 +++++++- 8 files changed, 465 insertions(+), 169 deletions(-) diff --git a/src/globals.h b/src/globals.h index 5dfb6ff3f1..11e06be7ee 100644 --- a/src/globals.h +++ b/src/globals.h @@ -1673,6 +1673,7 @@ EXTERN char e_toofewarg[] INIT(= N_("E119: Not enough arguments for function: %s EXTERN char e_func_deleted[] INIT(= N_("E933: Function was deleted: %s")); EXTERN char e_dictkey[] INIT(= N_("E716: Key not present in Dictionary: %s")); EXTERN char e_listreq[] INIT(= N_("E714: List required")); +EXTERN char e_listdictblobreq[] INIT(= N_("E1090: List, Dict or Blob required")); EXTERN char e_listblobreq[] INIT(= N_("E897: List or Blob required")); EXTERN char e_list_end[] INIT(= N_("E697: Missing end of List ']': %s")); EXTERN char e_listdictarg[] INIT(= N_("E712: Argument of %s must be a List or Dictionary")); diff --git a/src/testdir/test_vim9_cmd.vim b/src/testdir/test_vim9_cmd.vim index 70437b901f..12260c3558 100644 --- a/src/testdir/test_vim9_cmd.vim +++ b/src/testdir/test_vim9_cmd.vim @@ -44,5 +44,27 @@ def Test_syn_include_wildcards() delete('Xthemine.vim') enddef +def Test_assign_list() + let l: list<string> = [] + l[0] = 'value' + assert_equal('value', l[0]) + + l[1] = 'asdf' + assert_equal('value', l[0]) + assert_equal('asdf', l[1]) + assert_equal('asdf', l[-1]) + assert_equal('value', l[-2]) +enddef + +def Test_assign_dict() + let d: dict<string> = {} + d['key'] = 'value' + assert_equal('value', d['key']) + + d[123] = 'qwerty' + assert_equal('qwerty', d[123]) + assert_equal('qwerty', d['123']) +enddef + " vim: ts=8 sw=2 sts=2 expandtab tw=80 fdm=marker diff --git a/src/testdir/test_vim9_expr.vim b/src/testdir/test_vim9_expr.vim index 86d1715734..6e8278850f 100644 --- a/src/testdir/test_vim9_expr.vim +++ b/src/testdir/test_vim9_expr.vim @@ -644,9 +644,9 @@ func Test_expr6_fails() call CheckDefFailure(["let x = #{one: 1} / #{two: 2}"], 'E1036:') call CheckDefFailure(["let x = #{one: 1} % #{two: 2}"], 'E1035:') - call CheckDefFailure(["let x = 0xff[1]"], 'E714:') + call CheckDefFailure(["let x = 0xff[1]"], 'E1090:') if has('float') - call CheckDefFailure(["let x = 0.7[1]"], 'E714:') + call CheckDefFailure(["let x = 0.7[1]"], 'E1090:') endif endfunc diff --git a/src/testdir/test_vim9_script.vim b/src/testdir/test_vim9_script.vim index d1cc1f9de3..0b99eec5d3 100644 --- a/src/testdir/test_vim9_script.vim +++ b/src/testdir/test_vim9_script.vim @@ -38,7 +38,7 @@ def Test_assignment() call CheckDefFailure(['let x:string'], 'E1069:') call CheckDefFailure(['let x:string = "x"'], 'E1069:') - call CheckDefFailure(['let a:string = "x"'], 'E1082:') + call CheckDefFailure(['let a:string = "x"'], 'E1069:') let a: number = 6 assert_equal(6, a) diff --git a/src/version.c b/src/version.c index 4bf6242645..d89763bfc1 100644 --- a/src/version.c +++ b/src/version.c @@ -746,6 +746,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 730, /**/ 729, /**/ diff --git a/src/vim9.h b/src/vim9.h index 709716ee3b..27914af7e4 100644 --- a/src/vim9.h +++ b/src/vim9.h @@ -48,6 +48,8 @@ typedef enum { // ISN_STOREOTHER, // pop into other script variable isn_arg.other. ISN_STORENR, // store number into local variable isn_arg.storenr.stnr_idx + ISN_STORELIST, // store into list, value/index/varable on stack + ISN_STOREDICT, // store into dictionary, value/index/variable on stack ISN_UNLET, // unlet variable isn_arg.unlet.ul_name ISN_UNLETENV, // unlet environment variable isn_arg.unlet.ul_name @@ -110,7 +112,8 @@ typedef enum { // expression operations ISN_CONCAT, ISN_INDEX, // [expr] list index - ISN_MEMBER, // dict.member using isn_arg.string + ISN_MEMBER, // dict[member] + ISN_STRINGMEMBER, // dict.member using isn_arg.string ISN_2BOOL, // convert value to bool, invert if isn_arg.number != 0 ISN_2STRING, // convert value to string at isn_arg.number on stack ISN_NEGATENR, // apply "-" to number diff --git a/src/vim9compile.c b/src/vim9compile.c index 5b016e63c4..09e71aca35 100644 --- a/src/vim9compile.c +++ b/src/vim9compile.c @@ -1558,17 +1558,17 @@ generate_PCALL( } /* - * Generate an ISN_MEMBER instruction. + * Generate an ISN_STRINGMEMBER instruction. */ static int -generate_MEMBER(cctx_T *cctx, char_u *name, size_t len) +generate_STRINGMEMBER(cctx_T *cctx, char_u *name, size_t len) { isn_T *isn; garray_T *stack = &cctx->ctx_type_stack; type_T *type; RETURN_OK_IF_SKIP(cctx); - if ((isn = generate_instr(cctx, ISN_MEMBER)) == NULL) + if ((isn = generate_instr(cctx, ISN_STRINGMEMBER)) == NULL) return FAIL; isn->isn_arg.string = vim_strnsave(name, (int)len); @@ -3485,15 +3485,17 @@ compile_subscript( } else if (**arg == '[') { - garray_T *stack; + garray_T *stack = &cctx->ctx_type_stack; type_T **typep; + // list index: list[123] + // list member: dict[key] + // TODO: blob index + // TODO: more arguments + // TODO: recognize list or dict at runtime if (generate_ppconst(cctx, ppconst) == FAIL) return FAIL; - // list index: list[123] - // TODO: more arguments - // TODO: dict member dict['name'] *arg = skipwhite(*arg + 1); if (compile_expr0(arg, cctx) == FAIL) return FAIL; @@ -3505,17 +3507,27 @@ compile_subscript( } *arg = *arg + 1; - if (generate_instr_drop(cctx, ISN_INDEX, 1) == FAIL) - return FAIL; - stack = &cctx->ctx_type_stack; - typep = ((type_T **)stack->ga_data) + stack->ga_len - 1; - if ((*typep)->tt_type != VAR_LIST && *typep != &t_any) + typep = ((type_T **)stack->ga_data) + stack->ga_len - 2; + if ((*typep)->tt_type == VAR_LIST || (*typep) == &t_any) { - emsg(_(e_listreq)); + if ((*typep)->tt_type == VAR_LIST) + *typep = (*typep)->tt_member; + if (generate_instr_drop(cctx, ISN_INDEX, 1) == FAIL) + return FAIL; + } + else if ((*typep)->tt_type == VAR_DICT) + { + *typep = (*typep)->tt_member; + if (may_generate_2STRING(-1, cctx) == FAIL) + return FAIL; + if (generate_instr_drop(cctx, ISN_MEMBER, 1) == FAIL) + return FAIL; + } + else + { + emsg(_(e_listdictblobreq)); return FAIL; } - if ((*typep)->tt_type == VAR_LIST) - *typep = (*typep)->tt_member; } else if (**arg == '.' && (*arg)[1] != '.') { @@ -3535,7 +3547,7 @@ compile_subscript( semsg(_(e_syntax_at), *arg); return FAIL; } - if (generate_MEMBER(cctx, *arg, p - *arg) == FAIL) + if (generate_STRINGMEMBER(cctx, *arg, p - *arg) == FAIL) return FAIL; *arg = p; } @@ -4500,6 +4512,59 @@ typedef enum { dest_reg, } assign_dest_T; +/* + * Generate the load instruction for "name". + */ + static void +generate_loadvar( + cctx_T *cctx, + assign_dest_T dest, + char_u *name, + lvar_T *lvar, + type_T *type) +{ + switch (dest) + { + case dest_option: + // TODO: check the option exists + generate_LOAD(cctx, ISN_LOADOPT, 0, name, type); + break; + case dest_global: + generate_LOAD(cctx, ISN_LOADG, 0, name + 2, type); + break; + case dest_buffer: + generate_LOAD(cctx, ISN_LOADB, 0, name + 2, type); + break; + case dest_window: + generate_LOAD(cctx, ISN_LOADW, 0, name + 2, type); + break; + case dest_tab: + generate_LOAD(cctx, ISN_LOADT, 0, name + 2, type); + break; + case dest_script: + compile_load_scriptvar(cctx, + name + (name[1] == ':' ? 2 : 0), NULL, NULL, TRUE); + break; + case dest_env: + // Include $ in the name here + generate_LOAD(cctx, ISN_LOADENV, 0, name, type); + break; + case dest_reg: + generate_LOAD(cctx, ISN_LOADREG, name[1], NULL, &t_string); + break; + case dest_vimvar: + generate_LOADV(cctx, name + 2, TRUE); + break; + case dest_local: + if (lvar->lv_from_outer) + generate_LOAD(cctx, ISN_LOADOUTER, lvar->lv_idx, + NULL, type); + else + generate_LOAD(cctx, ISN_LOAD, lvar->lv_idx, NULL, type); + break; + } +} + /* * compile "let var [= expr]", "const var = expr" and "var = expr" * "arg" points to "var". @@ -4507,12 +4572,15 @@ typedef enum { static char_u * compile_assignment(char_u *arg, exarg_T *eap, cmdidx_T cmdidx, cctx_T *cctx) { + char_u *var_end; char_u *p; + char_u *end = arg; char_u *ret = NULL; int var_count = 0; int semicolon = 0; size_t varlen; garray_T *instr = &cctx->ctx_instr; + garray_T *stack = &cctx->ctx_type_stack; int new_local = FALSE; char_u *op; int opt_type; @@ -4522,15 +4590,17 @@ compile_assignment(char_u *arg, exarg_T *eap, cmdidx_T cmdidx, cctx_T *cctx) int oplen = 0; int heredoc = FALSE; type_T *type = &t_any; + type_T *member_type = &t_any; lvar_T *lvar = NULL; char_u *name; char_u *sp; int has_type = FALSE; + int has_index = FALSE; int is_decl = cmdidx == CMD_let || cmdidx == CMD_const; int instr_count = -1; - p = skip_var_list(arg, FALSE, &var_count, &semicolon); - if (p == NULL) + var_end = skip_var_list(arg, FALSE, &var_count, &semicolon); + if (var_end == NULL) return NULL; if (var_count > 0) { @@ -4539,7 +4609,12 @@ compile_assignment(char_u *arg, exarg_T *eap, cmdidx_T cmdidx, cctx_T *cctx) return NULL; } + p = (*arg == '&' || *arg == '$' || *arg == '@') ? arg + 1 : arg; + p = to_name_end(p, TRUE); + // "a: type" is declaring variable "a" with a type, not "a:". + if (is_decl && var_end == arg + 2 && var_end[-1] == ':') + --var_end; if (is_decl && p == arg + 2 && p[-1] == ':') --p; @@ -4715,9 +4790,18 @@ compile_assignment(char_u *arg, exarg_T *eap, cmdidx_T cmdidx, cctx_T *cctx) semsg(_("E1082: Cannot use a namespaced variable: %s"), name); goto theend; } + else if (!is_decl) + { + semsg(_("E1089: unknown variable: %s"), name); + goto theend; + } } } + // handle "a:name" as a name, not index "name" on "a" + if (varlen > 1 || arg[varlen] != ':') + p = var_end; + if (dest != dest_option) { if (is_decl && *p == ':') @@ -4774,6 +4858,33 @@ compile_assignment(char_u *arg, exarg_T *eap, cmdidx_T cmdidx, cctx_T *cctx) new_local = TRUE; } + member_type = type; + if (var_end > arg + varlen) + { + if (is_decl) + { + emsg(_("E1087: cannot use an index when declaring a variable")); + goto theend; + } + + // Something follows after the variable: "var[idx]". + if (arg[varlen] == '[') + { + has_index = TRUE; + if (type->tt_member == NULL) + { + semsg(_("E1088: cannot use an index on %s"), name); + goto theend; + } + member_type = type->tt_member; + } + else + { + semsg("Not supported yet: %s", arg); + goto theend; + } + } + if (heredoc) { list_T *l; @@ -4792,57 +4903,24 @@ compile_assignment(char_u *arg, exarg_T *eap, cmdidx_T cmdidx, cctx_T *cctx) } generate_NEWLIST(cctx, l->lv_len); type = &t_list_string; + member_type = &t_list_string; list_free(l); p += STRLEN(p); } else if (oplen > 0) { int r; - type_T *stacktype; - garray_T *stack; // for "+=", "*=", "..=" etc. first load the current value if (*op != '=') { - switch (dest) + generate_loadvar(cctx, dest, name, lvar, type); + + if (has_index) { - case dest_option: - // TODO: check the option exists - generate_LOAD(cctx, ISN_LOADOPT, 0, name, type); - break; - case dest_global: - generate_LOAD(cctx, ISN_LOADG, 0, name + 2, type); - break; - case dest_buffer: - generate_LOAD(cctx, ISN_LOADB, 0, name + 2, type); - break; - case dest_window: - generate_LOAD(cctx, ISN_LOADW, 0, name + 2, type); - break; - case dest_tab: - generate_LOAD(cctx, ISN_LOADT, 0, name + 2, type); - break; - case dest_script: - compile_load_scriptvar(cctx, - name + (name[1] == ':' ? 2 : 0), NULL, NULL, TRUE); - break; - case dest_env: - // Include $ in the name here - generate_LOAD(cctx, ISN_LOADENV, 0, name, type); - break; - case dest_reg: - generate_LOAD(cctx, ISN_LOADREG, arg[1], NULL, &t_string); - break; - case dest_vimvar: - generate_LOADV(cctx, name + 2, TRUE); - break; - case dest_local: - if (lvar->lv_from_outer) - generate_LOAD(cctx, ISN_LOADOUTER, lvar->lv_idx, - NULL, type); - else - generate_LOAD(cctx, ISN_LOAD, lvar->lv_idx, NULL, type); - break; + // TODO: get member from list or dict + emsg("Index with operation not supported yet"); + goto theend; } } @@ -4860,7 +4938,8 @@ compile_assignment(char_u *arg, exarg_T *eap, cmdidx_T cmdidx, cctx_T *cctx) if (cctx->ctx_skip != TRUE) { - stack = &cctx->ctx_type_stack; + type_T *stacktype; + stacktype = stack->ga_len == 0 ? &t_void : ((type_T **)stack->ga_data)[stack->ga_len - 1]; if (lvar != NULL && (is_decl || !has_type)) @@ -4884,10 +4963,22 @@ compile_assignment(char_u *arg, exarg_T *eap, cmdidx_T cmdidx, cctx_T *cctx) lvar->lv_type = stacktype; } } - else if (need_type(stacktype, lvar->lv_type, -1, cctx) == FAIL) - goto theend; + else + { + type_T *use_type = lvar->lv_type; + + if (has_index) + { + use_type = use_type->tt_member; + if (use_type == NULL) + use_type = &t_void; + } + if (need_type(stacktype, use_type, -1, cctx) == FAIL) + goto theend; + } } - else if (*p != '=' && check_type(type, stacktype, TRUE) == FAIL) + else if (*p != '=' && check_type(member_type, stacktype, TRUE) + == FAIL) goto theend; } } @@ -4906,7 +4997,7 @@ compile_assignment(char_u *arg, exarg_T *eap, cmdidx_T cmdidx, cctx_T *cctx) // variables are always initialized if (ga_grow(instr, 1) == FAIL) goto theend; - switch (type->tt_type) + switch (member_type->tt_type) { case VAR_BOOL: generate_PUSHBOOL(cctx, VVAL_FALSE); @@ -4947,11 +5038,11 @@ compile_assignment(char_u *arg, exarg_T *eap, cmdidx_T cmdidx, cctx_T *cctx) break; } } + end = p; if (oplen > 0 && *op != '=') { type_T *expected = &t_number; - garray_T *stack = &cctx->ctx_type_stack; type_T *stacktype; // TODO: if type is known use float or any operation @@ -4981,103 +5072,158 @@ compile_assignment(char_u *arg, exarg_T *eap, cmdidx_T cmdidx, cctx_T *cctx) } } - switch (dest) + if (has_index) { - case dest_option: - generate_STOREOPT(cctx, name + 1, opt_flags); - break; - case dest_global: - // include g: with the name, easier to execute that way - generate_STORE(cctx, ISN_STOREG, 0, name); - break; - case dest_buffer: - // include b: with the name, easier to execute that way - generate_STORE(cctx, ISN_STOREB, 0, name); - break; - case dest_window: - // include w: with the name, easier to execute that way - generate_STORE(cctx, ISN_STOREW, 0, name); - break; - case dest_tab: - // include t: with the name, easier to execute that way - generate_STORE(cctx, ISN_STORET, 0, name); - break; - case dest_env: - generate_STORE(cctx, ISN_STOREENV, 0, name + 1); - break; - case dest_reg: - generate_STORE(cctx, ISN_STOREREG, name[1], NULL); - break; - case dest_vimvar: - generate_STORE(cctx, ISN_STOREV, vimvaridx, NULL); - break; - case dest_script: - { - char_u *rawname = name + (name[1] == ':' ? 2 : 0); - imported_T *import = NULL; - int sid = current_sctx.sc_sid; - int idx; + int r; - if (name[1] != ':') + // Compile the "idx" in "var[idx]". + if (new_local) + --cctx->ctx_locals.ga_len; + p = skipwhite(arg + varlen + 1); + r = compile_expr0(&p, cctx); + if (new_local) + ++cctx->ctx_locals.ga_len; + if (r == FAIL) + goto theend; + if (*skipwhite(p) != ']') + { + emsg(_(e_missbrac)); + goto theend; + } + if (type->tt_type == VAR_DICT + && may_generate_2STRING(-1, cctx) == FAIL) + goto theend; + if (type->tt_type == VAR_LIST + && ((type_T **)stack->ga_data)[stack->ga_len - 1]->tt_type + != VAR_NUMBER) + { + emsg(_(e_number_exp)); + goto theend; + } + + // Load the dict or list. On the stack we then have: + // - value + // - index + // - variable + generate_loadvar(cctx, dest, name, lvar, type); + + if (type->tt_type == VAR_LIST) + { + if (generate_instr_drop(cctx, ISN_STORELIST, 3) == FAIL) + return FAIL; + } + else if (type->tt_type == VAR_DICT) + { + if (generate_instr_drop(cctx, ISN_STOREDICT, 3) == FAIL) + return FAIL; + } + else + { + emsg(_(e_listreq)); + goto theend; + } + } + else + { + switch (dest) + { + case dest_option: + generate_STOREOPT(cctx, name + 1, opt_flags); + break; + case dest_global: + // include g: with the name, easier to execute that way + generate_STORE(cctx, ISN_STOREG, 0, name); + break; + case dest_buffer: + // include b: with the name, easier to execute that way + generate_STORE(cctx, ISN_STOREB, 0, name); + break; + case dest_window: + // include w: with the name, easier to execute that way + generate_STORE(cctx, ISN_STOREW, 0, name); + break; + case dest_tab: + // include t: with the name, easier to execute that way + generate_STORE(cctx, ISN_STORET, 0, name); + break; + case dest_env: + generate_STORE(cctx, ISN_STOREENV, 0, name + 1); + break; + case dest_reg: + generate_STORE(cctx, ISN_STOREREG, name[1], NULL); + break; + case dest_vimvar: + generate_STORE(cctx, ISN_STOREV, vimvaridx, NULL); + break; + case dest_script: { - import = find_imported(name, 0, cctx); - if (import != NULL) - sid = import->imp_sid; - } + char_u *rawname = name + (name[1] == ':' ? 2 : 0); + imported_T *import = NULL; + int sid = current_sctx.sc_sid; + int idx; - idx = get_script_item_idx(sid, rawname, TRUE); - // TODO: specific type - if (idx < 0) - { - char_u *name_s = name; - - // Include s: in the name for store_var() if (name[1] != ':') { - int len = (int)STRLEN(name) + 3; - - name_s = alloc(len); - if (name_s == NULL) - name_s = name; - else - vim_snprintf((char *)name_s, len, "s:%s", name); + import = find_imported(name, 0, cctx); + if (import != NULL) + sid = import->imp_sid; } - generate_OLDSCRIPT(cctx, ISN_STORES, name_s, sid, &t_any); - if (name_s != name) - vim_free(name_s); - } - else - generate_VIM9SCRIPT(cctx, ISN_STORESCRIPT, + + idx = get_script_item_idx(sid, rawname, TRUE); + // TODO: specific type + if (idx < 0) + { + char_u *name_s = name; + + // Include s: in the name for store_var() + if (name[1] != ':') + { + int len = (int)STRLEN(name) + 3; + + name_s = alloc(len); + if (name_s == NULL) + name_s = name; + else + vim_snprintf((char *)name_s, len, "s:%s", name); + } + generate_OLDSCRIPT(cctx, ISN_STORES, name_s, sid, + &t_any); + if (name_s != name) + vim_free(name_s); + } + else + generate_VIM9SCRIPT(cctx, ISN_STORESCRIPT, sid, idx, &t_any); - } - break; - case dest_local: - if (lvar != NULL) - { - isn_T *isn = ((isn_T *)instr->ga_data) + instr->ga_len - 1; - - // optimization: turn "var = 123" from ISN_PUSHNR + ISN_STORE - // into ISN_STORENR - if (!lvar->lv_from_outer && instr->ga_len == instr_count + 1 - && isn->isn_type == ISN_PUSHNR) - { - varnumber_T val = isn->isn_arg.number; - garray_T *stack = &cctx->ctx_type_stack; - - isn->isn_type = ISN_STORENR; - isn->isn_arg.storenr.stnr_idx = lvar->lv_idx; - isn->isn_arg.storenr.stnr_val = val; - if (stack->ga_len > 0) - --stack->ga_len; } - else if (lvar->lv_from_outer) - generate_STORE(cctx, ISN_STOREOUTER, lvar->lv_idx, NULL); - else - generate_STORE(cctx, ISN_STORE, lvar->lv_idx, NULL); - } - break; + break; + case dest_local: + if (lvar != NULL) + { + isn_T *isn = ((isn_T *)instr->ga_data) + instr->ga_len - 1; + + // optimization: turn "var = 123" from ISN_PUSHNR + + // ISN_STORE into ISN_STORENR + if (!lvar->lv_from_outer && instr->ga_len == instr_count + 1 + && isn->isn_type == ISN_PUSHNR) + { + varnumber_T val = isn->isn_arg.number; + + isn->isn_type = ISN_STORENR; + isn->isn_arg.storenr.stnr_idx = lvar->lv_idx; + isn->isn_arg.storenr.stnr_val = val; + if (stack->ga_len > 0) + --stack->ga_len; + } + else if (lvar->lv_from_outer) + generate_STORE(cctx, ISN_STOREOUTER, lvar->lv_idx, + NULL); + else + generate_STORE(cctx, ISN_STORE, lvar->lv_idx, NULL); + } + break; + } } - ret = p; + ret = end; theend: vim_free(name); @@ -6252,7 +6398,7 @@ compile_def_function(ufunc_T *ufunc, int set_return_type, cctx_T *outer_cctx) for (;;) { exarg_T ea; - int is_ex_command = FALSE; + int starts_with_colon = FALSE; // Bail out on the first error to avoid a flood of errors and report // the right line number when inside try/catch. @@ -6327,7 +6473,7 @@ compile_def_function(ufunc_T *ufunc, int set_return_type, cctx_T *outer_cctx) break; case ':': - is_ex_command = TRUE; + starts_with_colon = TRUE; break; } @@ -6347,20 +6493,26 @@ compile_def_function(ufunc_T *ufunc, int set_return_type, cctx_T *outer_cctx) if (checkforcmd(&ea.cmd, "call", 3)) ea.cmd = skipwhite(ea.cmd); - if (!is_ex_command) + if (!starts_with_colon) { + char_u *pskip; + // Assuming the command starts with a variable or function name, - // find what follows. Also "&opt = val", "$ENV = val" and "@r = - // val". - p = (*ea.cmd == '&' || *ea.cmd == '$' || *ea.cmd == '@') + // find what follows. + // Skip over "var.member", "var[idx]" and the like. + // Also "&opt = val", "$ENV = val" and "@r = val". + pskip = (*ea.cmd == '&' || *ea.cmd == '$' || *ea.cmd == '@') ? ea.cmd + 1 : ea.cmd; - p = to_name_end(p, TRUE); + p = to_name_end(pskip, TRUE); if (p > ea.cmd && *p != NUL) { - int oplen; - int heredoc; + char_u *var_end; + int oplen; + int heredoc; - oplen = assignment_len(skipwhite(p), &heredoc); + var_end = find_name_end(pskip, NULL, NULL, + FNE_CHECK_START | FNE_INCL_BR); + oplen = assignment_len(skipwhite(var_end), &heredoc); if (oplen > 0) { // Recognize an assignment if we recognize the variable @@ -6393,7 +6545,7 @@ compile_def_function(ufunc_T *ufunc, int set_return_type, cctx_T *outer_cctx) * COMMAND after range */ ea.cmd = skip_range(ea.cmd, NULL); - p = find_ex_command(&ea, NULL, is_ex_command ? NULL + p = find_ex_command(&ea, NULL, starts_with_colon ? NULL : (void *(*)(char_u *, size_t, cctx_T *))lookup_local, &cctx); @@ -6675,7 +6827,7 @@ delete_instr(isn_T *isn) case ISN_LOADW: case ISN_LOADT: case ISN_LOADOPT: - case ISN_MEMBER: + case ISN_STRINGMEMBER: case ISN_PUSHEXC: case ISN_PUSHS: case ISN_STOREENV: @@ -6758,6 +6910,7 @@ delete_instr(isn_T *isn) case ISN_EXECUTE: case ISN_FOR: case ISN_INDEX: + case ISN_MEMBER: case ISN_JUMP: case ISN_LOAD: case ISN_LOADOUTER: @@ -6783,6 +6936,8 @@ delete_instr(isn_T *isn) case ISN_STORENR: case ISN_STOREREG: case ISN_STORESCRIPT: + case ISN_STOREDICT: + case ISN_STORELIST: case ISN_THROW: case ISN_TRY: // nothing allocated diff --git a/src/vim9execute.c b/src/vim9execute.c index 4d4df0ab60..ba4ae47871 100644 --- a/src/vim9execute.c +++ b/src/vim9execute.c @@ -1252,6 +1252,76 @@ call_def_function( tv->vval.v_number = iptr->isn_arg.storenr.stnr_val; break; + // store value in list variable + case ISN_STORELIST: + { + typval_T *tv_idx = STACK_TV_BOT(-2); + varnumber_T lidx = tv_idx->vval.v_number; + typval_T *tv_list = STACK_TV_BOT(-1); + list_T *list = tv_list->vval.v_list; + + if (lidx < 0 && list->lv_len + lidx >= 0) + // negative index is relative to the end + lidx = list->lv_len + lidx; + if (lidx < 0 || lidx > list->lv_len) + { + semsg(_(e_listidx), lidx); + goto failed; + } + tv = STACK_TV_BOT(-3); + if (lidx < list->lv_len) + { + listitem_T *li = list_find(list, lidx); + + // overwrite existing list item + clear_tv(&li->li_tv); + li->li_tv = *tv; + } + else + { + // append to list + if (list_append_tv(list, tv) == FAIL) + goto failed; + clear_tv(tv); + } + clear_tv(tv_idx); + clear_tv(tv_list); + } + break; + + // store value in dict variable + case ISN_STOREDICT: + { + typval_T *tv_key = STACK_TV_BOT(-2); + char_u *key = tv_key->vval.v_string; + typval_T *tv_dict = STACK_TV_BOT(-1); + dict_T *dict = tv_dict->vval.v_dict; + dictitem_T *di; + + if (key == NULL || *key == NUL) + { + emsg(_(e_emptykey)); + goto failed; + } + tv = STACK_TV_BOT(-3); + di = dict_find(dict, key, -1); + if (di != NULL) + { + clear_tv(&di->di_tv); + di->di_tv = *tv; + } + else + { + // add to dict + if (dict_add_tv(dict, (char *)key, tv) == FAIL) + goto failed; + clear_tv(tv); + } + clear_tv(tv_key); + clear_tv(tv_dict); + } + break; + // push constant case ISN_PUSHNR: case ISN_PUSHBOOL: @@ -2019,8 +2089,42 @@ call_def_function( } break; - // dict member with string key case ISN_MEMBER: + { + dict_T *dict; + char_u *key; + dictitem_T *di; + + // dict member: dict is at stack-2, key at stack-1 + tv = STACK_TV_BOT(-2); + if (tv->v_type != VAR_DICT) + { + emsg(_(e_dictreq)); + goto failed; + } + dict = tv->vval.v_dict; + + tv = STACK_TV_BOT(-1); + if (tv->v_type != VAR_STRING) + { + emsg(_(e_stringreq)); + goto failed; + } + key = tv->vval.v_string; + if ((di = dict_find(dict, key, -1)) == NULL) + { + semsg(_(e_dictkey), key); + goto failed; + } + --ectx.ec_stack.ga_len; + clear_tv(tv); + clear_tv(STACK_TV_BOT(-1)); + copy_tv(&di->di_tv, STACK_TV_BOT(-1)); + } + break; + + // dict member with string key + case ISN_STRINGMEMBER: { dict_T *dict; dictitem_T *di; @@ -2380,6 +2484,14 @@ ex_disassemble(exarg_T *eap) iptr->isn_arg.storenr.stnr_idx); break; + case ISN_STORELIST: + smsg("%4d STORELIST", current); + break; + + case ISN_STOREDICT: + smsg("%4d STOREDICT", current); + break; + // constants case ISN_PUSHNR: smsg("%4d PUSHNR %lld", current, @@ -2656,7 +2768,8 @@ ex_disassemble(exarg_T *eap) // expression operations case ISN_CONCAT: smsg("%4d CONCAT", current); break; case ISN_INDEX: smsg("%4d INDEX", current); break; - case ISN_MEMBER: smsg("%4d MEMBER %s", current, + case ISN_MEMBER: smsg("%4d MEMBER", current); break; + case ISN_STRINGMEMBER: smsg("%4d MEMBER %s", current, iptr->isn_arg.string); break; case ISN_NEGATENR: smsg("%4d NEGATENR", current); break; From 7e5bd91dc99e1ecb38c4220eaab1a906a69815c2 Mon Sep 17 00:00:00 2001 From: Bram Moolenaar <Bram@vim.org> Date: Sun, 10 May 2020 21:20:29 +0200 Subject: [PATCH 127/230] patch 8.2.0731: Vim9: parsing declarations continues after :finish Problem: Vim9: parsing declarations continues after :finish. Solution: Bail out when encountering :finish. --- src/testdir/test_vim9_script.vim | 17 +++++++++++++++++ src/version.c | 2 ++ src/vim9script.c | 6 ++++++ 3 files changed, 25 insertions(+) diff --git a/src/testdir/test_vim9_script.vim b/src/testdir/test_vim9_script.vim index 0b99eec5d3..e85da5a800 100644 --- a/src/testdir/test_vim9_script.vim +++ b/src/testdir/test_vim9_script.vim @@ -1705,6 +1705,23 @@ def Test_vim9_comment_not_compiled() ], 'E488:') enddef +def Test_finish() + let lines =<< trim END + vim9script + let g:res = 'one' + if v:false | finish | endif + let g:res = 'two' + finish + let g:res = 'three' + END + writefile(lines, 'Xfinished') + source Xfinished + assert_equal('two', g:res) + + unlet g:res + delete('Xfinished') +enddef + " Keep this last, it messes up highlighting. def Test_substitute_cmd() new diff --git a/src/version.c b/src/version.c index d89763bfc1..efb3c3187c 100644 --- a/src/version.c +++ b/src/version.c @@ -746,6 +746,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 731, /**/ 730, /**/ diff --git a/src/vim9script.c b/src/vim9script.c index 8bc1962bfd..4d7e8ee46f 100644 --- a/src/vim9script.c +++ b/src/vim9script.c @@ -130,6 +130,12 @@ ex_vim9script(exarg_T *eap) vim_free(((char_u **)(gap->ga_data))[--gap->ga_len]); ((char_u **)(gap->ga_data))[gap->ga_len++] = NULL; } + else if (checkforcmd(&p, "finish", 4)) + { + // TODO: this should not happen below "if false". + // Use "if cond | finish | endif as a workaround. + break; + } } // Compile the :def functions. From f163bd5e41e8ea1d32e7977e671598a9d6f7b23c Mon Sep 17 00:00:00 2001 From: Bram Moolenaar <Bram@vim.org> Date: Sun, 10 May 2020 21:47:43 +0200 Subject: [PATCH 128/230] patch 8.2.0732: Vim9: storing value in dict messes up stack Problem: Vim9: storing value in dict messes up stack. Solution: Correct item count of stack. --- src/testdir/test_vim9_cmd.vim | 12 ++++++++++++ src/version.c | 2 ++ src/vim9execute.c | 2 ++ 3 files changed, 16 insertions(+) diff --git a/src/testdir/test_vim9_cmd.vim b/src/testdir/test_vim9_cmd.vim index 12260c3558..55d756a676 100644 --- a/src/testdir/test_vim9_cmd.vim +++ b/src/testdir/test_vim9_cmd.vim @@ -54,6 +54,12 @@ def Test_assign_list() assert_equal('asdf', l[1]) assert_equal('asdf', l[-1]) assert_equal('value', l[-2]) + + let nrl: list<number> = [] + for i in range(5) + nrl[i] = i + endfor + assert_equal([0, 1, 2, 3, 4], nrl) enddef def Test_assign_dict() @@ -64,6 +70,12 @@ def Test_assign_dict() d[123] = 'qwerty' assert_equal('qwerty', d[123]) assert_equal('qwerty', d['123']) + + let nrd: dict<number> = {} + for i in range(3) + nrd[i] = i + endfor + assert_equal({'0': 0, '1': 1, '2': 2}, nrd) enddef diff --git a/src/version.c b/src/version.c index efb3c3187c..6a29592c15 100644 --- a/src/version.c +++ b/src/version.c @@ -746,6 +746,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 732, /**/ 731, /**/ diff --git a/src/vim9execute.c b/src/vim9execute.c index ba4ae47871..4356e2a95a 100644 --- a/src/vim9execute.c +++ b/src/vim9execute.c @@ -1286,6 +1286,7 @@ call_def_function( } clear_tv(tv_idx); clear_tv(tv_list); + ectx.ec_stack.ga_len -= 3; } break; @@ -1319,6 +1320,7 @@ call_def_function( } clear_tv(tv_key); clear_tv(tv_dict); + ectx.ec_stack.ga_len -= 3; } break; From cb2bdb1c6d8b6df4a3d9cfb1ad9e602dace5d310 Mon Sep 17 00:00:00 2001 From: Bram Moolenaar <Bram@vim.org> Date: Sun, 10 May 2020 22:53:56 +0200 Subject: [PATCH 129/230] patch 8.2.0733: Vim9: assigning to dict or list argument does not work Problem: Vim9: assigning to dict or list argument does not work. Solution: Recognize an argument as assignment target. --- src/testdir/test_vim9_func.vim | 20 +++++++++++++++++++ src/version.c | 2 ++ src/vim9compile.c | 36 ++++++++++++++++++++++++++++------ 3 files changed, 52 insertions(+), 6 deletions(-) diff --git a/src/testdir/test_vim9_func.vim b/src/testdir/test_vim9_func.vim index ab5f9ecd2d..c74b4a4510 100644 --- a/src/testdir/test_vim9_func.vim +++ b/src/testdir/test_vim9_func.vim @@ -193,6 +193,26 @@ def Test_using_var_as_arg() call delete('Xdef') enddef +def DictArg(arg: dict<string>) + arg['key'] = 'value' +enddef + +def ListArg(arg: list<string>) + arg[0] = 'value' +enddef + +def Test_assign_to_argument() + " works for dict and list + let d: dict<string> = {} + DictArg(d) + assert_equal('value', d['key']) + let l: list<string> = [] + ListArg(l) + assert_equal('value', l[0]) + + call CheckScriptFailure(['def Func(arg: number)', 'arg = 3', 'enddef'], 'E1090:') +enddef + def Test_call_func_defined_later() call assert_equal('one', g:DefinedLater('one')) call assert_fails('call NotDefined("one")', 'E117:') diff --git a/src/version.c b/src/version.c index 6a29592c15..9dc3c22e53 100644 --- a/src/version.c +++ b/src/version.c @@ -746,6 +746,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 733, /**/ 732, /**/ diff --git a/src/vim9compile.c b/src/vim9compile.c index 09e71aca35..c8c87e737f 100644 --- a/src/vim9compile.c +++ b/src/vim9compile.c @@ -135,6 +135,7 @@ struct cctx_S { static char e_var_notfound[] = N_("E1001: variable not found: %s"); static char e_syntax_at[] = N_("E1002: Syntax error at %s"); +static char e_used_as_arg[] = N_("E1006: %s is used as an argument"); static void delete_def_function_contents(dfunc_T *dfunc); static void arg_type_mismatch(type_T *expected, type_T *actual, int argidx); @@ -1652,7 +1653,7 @@ reserve_local(cctx_T *cctx, char_u *name, size_t len, int isConst, type_T *type) if (lookup_arg(name, len, NULL, NULL, NULL, cctx) == OK) { - emsg_namelen(_("E1006: %s is used as an argument"), name, (int)len); + emsg_namelen(_(e_used_as_arg), name, (int)len); return NULL; } @@ -4592,6 +4593,7 @@ compile_assignment(char_u *arg, exarg_T *eap, cmdidx_T cmdidx, cctx_T *cctx) type_T *type = &t_any; type_T *member_type = &t_any; lvar_T *lvar = NULL; + lvar_T arg_lvar; char_u *name; char_u *sp; int has_type = FALSE; @@ -4760,6 +4762,19 @@ compile_assignment(char_u *arg, exarg_T *eap, cmdidx_T cmdidx, cctx_T *cctx) } lvar = lookup_local(arg, varlen, cctx); + if (lvar == NULL + && lookup_arg(arg, varlen, + &arg_lvar.lv_idx, &arg_lvar.lv_type, + &arg_lvar.lv_from_outer, cctx) == OK) + { + if (is_decl) + { + semsg(_(e_used_as_arg), name); + goto theend; + } + arg_lvar.lv_const = 0; + lvar = &arg_lvar; + } if (lvar != NULL) { if (is_decl) @@ -4861,13 +4876,13 @@ compile_assignment(char_u *arg, exarg_T *eap, cmdidx_T cmdidx, cctx_T *cctx) member_type = type; if (var_end > arg + varlen) { + // Something follows after the variable: "var[idx]". if (is_decl) { emsg(_("E1087: cannot use an index when declaring a variable")); goto theend; } - // Something follows after the variable: "var[idx]". if (arg[varlen] == '[') { has_index = TRUE; @@ -4884,6 +4899,11 @@ compile_assignment(char_u *arg, exarg_T *eap, cmdidx_T cmdidx, cctx_T *cctx) goto theend; } } + else if (lvar == &arg_lvar) + { + semsg(_("E1090: Cannot assign to argument %s"), name); + goto theend; + } if (heredoc) { @@ -6515,6 +6535,8 @@ compile_def_function(ufunc_T *ufunc, int set_return_type, cctx_T *outer_cctx) oplen = assignment_len(skipwhite(var_end), &heredoc); if (oplen > 0) { + size_t len = p - ea.cmd; + // Recognize an assignment if we recognize the variable // name: // "g:var = expr" @@ -6527,10 +6549,12 @@ compile_def_function(ufunc_T *ufunc, int set_return_type, cctx_T *outer_cctx) if (*ea.cmd == '&' || *ea.cmd == '$' || *ea.cmd == '@' - || ((p - ea.cmd) > 2 && ea.cmd[1] == ':') - || lookup_local(ea.cmd, p - ea.cmd, &cctx) != NULL - || lookup_script(ea.cmd, p - ea.cmd) == OK - || find_imported(ea.cmd, p - ea.cmd, &cctx) != NULL) + || ((len) > 2 && ea.cmd[1] == ':') + || lookup_local(ea.cmd, len, &cctx) != NULL + || lookup_arg(ea.cmd, len, NULL, NULL, + NULL, &cctx) == OK + || lookup_script(ea.cmd, len) == OK + || find_imported(ea.cmd, len, &cctx) != NULL) { line = compile_assignment(ea.cmd, &ea, CMD_SIZE, &cctx); if (line == NULL) From 04816717dfea6e2469ff4c9d40f68b59aaf03724 Mon Sep 17 00:00:00 2001 From: Bram Moolenaar <Bram@vim.org> Date: Sun, 10 May 2020 23:11:53 +0200 Subject: [PATCH 130/230] patch 8.2.0734: Vim9: leaking memory when using :finish Problem: Vim9: leaking memory when using :finish. Solution: Do not check for next line in third pass. --- src/scriptfile.c | 6 +++++- src/version.c | 2 ++ 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/src/scriptfile.c b/src/scriptfile.c index 86e8b01105..7a148a7c8a 100644 --- a/src/scriptfile.c +++ b/src/scriptfile.c @@ -1773,7 +1773,11 @@ getsourceline(int c UNUSED, void *cookie, int indent UNUSED, int do_concat) // Only concatenate lines starting with a \ when 'cpoptions' doesn't // contain the 'C' flag. - if (line != NULL && do_concat && vim_strchr(p_cpo, CPO_CONCAT) == NULL) + if (line != NULL && do_concat && vim_strchr(p_cpo, CPO_CONCAT) == NULL +#ifdef FEAT_EVAL + && sp->use_lines_ga < 0 +#endif + ) { // compensate for the one line read-ahead --sp->sourcing_lnum; diff --git a/src/version.c b/src/version.c index 9dc3c22e53..19920dea87 100644 --- a/src/version.c +++ b/src/version.c @@ -746,6 +746,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 734, /**/ 733, /**/ From bc38f25c021dc4314c77d50a608329a328b0d988 Mon Sep 17 00:00:00 2001 From: Bram Moolenaar <Bram@vim.org> Date: Sun, 10 May 2020 23:20:06 +0200 Subject: [PATCH 131/230] patch 8.2.0735: Vim9: using unitialized memory Problem: Vim9: using unitialized memory. Solution: Clear the arg_lvar field. --- src/version.c | 2 ++ src/vim9compile.c | 18 ++++++++++-------- 2 files changed, 12 insertions(+), 8 deletions(-) diff --git a/src/version.c b/src/version.c index 19920dea87..96ca8898ae 100644 --- a/src/version.c +++ b/src/version.c @@ -746,6 +746,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 735, /**/ 734, /**/ diff --git a/src/vim9compile.c b/src/vim9compile.c index c8c87e737f..99246e07df 100644 --- a/src/vim9compile.c +++ b/src/vim9compile.c @@ -4762,18 +4762,20 @@ compile_assignment(char_u *arg, exarg_T *eap, cmdidx_T cmdidx, cctx_T *cctx) } lvar = lookup_local(arg, varlen, cctx); - if (lvar == NULL - && lookup_arg(arg, varlen, + if (lvar == NULL) + { + CLEAR_FIELD(arg_lvar); + if (lookup_arg(arg, varlen, &arg_lvar.lv_idx, &arg_lvar.lv_type, &arg_lvar.lv_from_outer, cctx) == OK) - { - if (is_decl) { - semsg(_(e_used_as_arg), name); - goto theend; + if (is_decl) + { + semsg(_(e_used_as_arg), name); + goto theend; + } + lvar = &arg_lvar; } - arg_lvar.lv_const = 0; - lvar = &arg_lvar; } if (lvar != NULL) { From aacc6afdb8cdeb2558e6942dcd65ca0079bec1ee Mon Sep 17 00:00:00 2001 From: Bram Moolenaar <Bram@vim.org> Date: Mon, 11 May 2020 19:46:36 +0200 Subject: [PATCH 132/230] patch 8.2.0736: some files not recognized as pamenv Problem: Some files not recognized as pamenv. Solution: Add pam_inv.conf. (closes #6065) --- runtime/filetype.vim | 2 +- src/testdir/test_filetype.vim | 2 +- src/version.c | 2 ++ 3 files changed, 4 insertions(+), 2 deletions(-) diff --git a/runtime/filetype.vim b/runtime/filetype.vim index 6d26ea098d..7157f092b6 100644 --- a/runtime/filetype.vim +++ b/runtime/filetype.vim @@ -1134,7 +1134,7 @@ au BufNewFile,BufRead pf.conf setf pf au BufNewFile,BufRead */etc/pam.conf setf pamconf " Pam environment -au BufNewFile,BufRead .pam_environment setf pamenv +au BufNewFile,BufRead pam_env.conf,.pam_environment setf pamenv " PApp au BufNewFile,BufRead *.papp,*.pxml,*.pxsl setf papp diff --git a/src/testdir/test_filetype.vim b/src/testdir/test_filetype.vim index 117b520723..c881fdedce 100644 --- a/src/testdir/test_filetype.vim +++ b/src/testdir/test_filetype.vim @@ -322,7 +322,7 @@ let s:filename_checks = { \ 'openroad': ['file.or'], \ 'ora': ['file.ora'], \ 'pamconf': ['/etc/pam.conf'], - \ 'pamenv': ['/home/user/.pam_environment'], + \ 'pamenv': ['/etc/security/pam_env.conf', '/home/user/.pam_environment'], \ 'papp': ['file.papp', 'file.pxml', 'file.pxsl'], \ 'pascal': ['file.pas', 'file.dpr'], \ 'passwd': ['any/etc/passwd', 'any/etc/passwd-', 'any/etc/passwd.edit', 'any/etc/shadow', 'any/etc/shadow-', 'any/etc/shadow.edit', 'any/var/backups/passwd.bak', 'any/var/backups/shadow.bak'], diff --git a/src/version.c b/src/version.c index 96ca8898ae..7fcef28487 100644 --- a/src/version.c +++ b/src/version.c @@ -746,6 +746,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 736, /**/ 735, /**/ From 5c3128efe6bc48cbd88da23973db389ad3b8ab63 Mon Sep 17 00:00:00 2001 From: Bram Moolenaar <Bram@vim.org> Date: Mon, 11 May 2020 20:54:42 +0200 Subject: [PATCH 133/230] patch 8.2.0737: when shell doesn't support CTRL-Z Vim still handles it Problem: When shell doesn't support CTRL-Z Vim still handles it. Solution: Ignore the STOP signal if it was ignored on startup. (Kurtis Rader, closes #5990, closes #6058) --- src/os_unix.c | 32 ++++++++++++++++++++++++++------ src/version.c | 2 ++ 2 files changed, 28 insertions(+), 6 deletions(-) diff --git a/src/os_unix.c b/src/os_unix.c index 596fb0e906..b5ae9f8687 100644 --- a/src/os_unix.c +++ b/src/os_unix.c @@ -129,6 +129,8 @@ Window x11_window = 0; Display *x11_display = NULL; #endif +static int ignore_sigtstp = FALSE; + #ifdef FEAT_TITLE static int get_x11_title(int); @@ -1237,6 +1239,9 @@ restore_clipboard(void) void mch_suspend(void) { + if (ignore_sigtstp) + return; + // BeOS does have SIGTSTP, but it doesn't work. #if defined(SIGTSTP) && !defined(__BEOS__) in_mch_suspend = TRUE; @@ -1286,6 +1291,14 @@ mch_init(void) Rows = 24; out_flush(); + +#ifdef SIGTSTP + // Check whether we were invoked with SIGTSTP set to be ignored. If it is + // that indicates the shell (or program) that launched us does not support + // tty job control and thus we should ignore that signal. If invoked as a + // restricted editor (e.g., as "rvim") SIGTSTP is always ignored. + ignore_sigtstp = restricted || SIG_IGN == signal(SIGTSTP, SIG_ERR); +#endif set_signals(); #ifdef MACOS_CONVERT @@ -1306,17 +1319,13 @@ set_signals(void) signal(SIGWINCH, (RETSIGTYPE (*)())sig_winch); #endif - /* - * We want the STOP signal to work, to make mch_suspend() work. - * For "rvim" the STOP signal is ignored. - */ #ifdef SIGTSTP - signal(SIGTSTP, restricted ? SIG_IGN : SIG_DFL); + // See mch_init() for the conditions under which we ignore SIGTSTP. + signal(SIGTSTP, ignore_sigtstp ? SIG_IGN : SIG_DFL); #endif #if defined(SIGCONT) signal(SIGCONT, sigcont_handler); #endif - /* * We want to ignore breaking of PIPEs. */ @@ -1386,6 +1395,7 @@ catch_signals( int i; for (i = 0; signal_info[i].sig != -1; i++) + { if (signal_info[i].deadly) { #if defined(HAVE_SIGALTSTACK) && defined(HAVE_SIGACTION) @@ -1420,7 +1430,17 @@ catch_signals( #endif } else if (func_other != SIG_ERR) + { + // Deal with non-deadly signals. +#ifdef SIGTSTP + signal(signal_info[i].sig, + signal_info[i].sig == SIGTSTP && ignore_sigtstp + ? SIG_IGN : func_other); +#else signal(signal_info[i].sig, func_other); +#endif + } + } } #ifdef HAVE_SIGPROCMASK diff --git a/src/version.c b/src/version.c index 7fcef28487..31d83ce872 100644 --- a/src/version.c +++ b/src/version.c @@ -746,6 +746,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 737, /**/ 736, /**/ From 91689ea8ae01acb3daf8ba0ee91acd729af7c84c Mon Sep 17 00:00:00 2001 From: Bram Moolenaar <Bram@vim.org> Date: Mon, 11 May 2020 22:04:53 +0200 Subject: [PATCH 134/230] patch 8.2.0738: mouse handling in a terminal window not well tested Problem: Mouse handling in a terminal window not well tested. Solution: Add tests. (Yegappan Lakshmanan, closes #6052) --- src/testdir/term_util.vim | 3 + src/testdir/test_gui.vim | 18 +++ src/testdir/test_modeless.vim | 44 +++---- src/testdir/test_terminal.vim | 225 ++++++++++++++++++++++++++++++++++ src/version.c | 2 + 5 files changed, 270 insertions(+), 22 deletions(-) diff --git a/src/testdir/term_util.vim b/src/testdir/term_util.vim index 715a4ac760..2d66f38a58 100644 --- a/src/testdir/term_util.vim +++ b/src/testdir/term_util.vim @@ -127,6 +127,9 @@ func StopVimInTerminal(buf) " In Command-line it's inserted, the CTRL-U removes it again. call term_sendkeys(a:buf, "\<C-O>:\<C-U>qa!\<cr>") + " Wait for all the pending updates to terminal to complete + call TermWait(a:buf) + call WaitForAssert({-> assert_equal("finished", term_getstatus(a:buf))}) only! endfunc diff --git a/src/testdir/test_gui.vim b/src/testdir/test_gui.vim index 384209f107..64b24bfc79 100644 --- a/src/testdir/test_gui.vim +++ b/src/testdir/test_gui.vim @@ -838,4 +838,22 @@ func Test_gui_dash_y() call delete('Xtestgui') endfunc +" Test for "!" option in 'guioptions'. Use a terminal for running external +" commands +func Test_gui_run_cmd_in_terminal() + let save_guioptions = &guioptions + set guioptions+=! + if has('win32') + let cmd = 'type' + else + " assume all the other systems have a cat command + let cmd = 'cat' + endif + let cmd = ':silent !' . cmd . " test_gui.vim\<CR>\<CR>" + call feedkeys(cmd, 'xt') + " TODO: how to check that the command ran in a separate terminal? + " Maybe check for $TERM (dumb vs xterm) in the spawned shell? + let &guioptions = save_guioptions +endfunc + " vim: shiftwidth=2 sts=2 expandtab diff --git a/src/testdir/test_modeless.vim b/src/testdir/test_modeless.vim index 11ccc2c2ac..3736f988ea 100644 --- a/src/testdir/test_modeless.vim +++ b/src/testdir/test_modeless.vim @@ -24,7 +24,7 @@ func Test_modeless_characterwise_selection() exe 'set ttymouse=' .. ttymouse_val " select multiple characters within a line - let @* = '' + let @* = 'clean' call MouseRightClick(1, 1) call MouseRightRelease(1, 1) let keys = ":" @@ -36,7 +36,7 @@ func Test_modeless_characterwise_selection() call assert_equal("wo th", @*, msg) " select multiple characters including the end of line - let @* = '' + let @* = 'clean' call MouseRightClick(1, 1) call MouseRightRelease(1, 1) let keys = ":" @@ -48,7 +48,7 @@ func Test_modeless_characterwise_selection() call assert_equal("ree\n", @*, msg) " extend a selection using right mouse click - let @* = '' + let @* = 'clean' call MouseRightClick(1, 1) call MouseRightRelease(1, 1) set mousemodel=extend @@ -64,7 +64,7 @@ func Test_modeless_characterwise_selection() set mousemodel& " extend a selection backwards using right mouse click - let @* = '' + let @* = 'clean' call MouseRightClick(1, 1) call MouseRightRelease(1, 1) set mousemodel=extend @@ -80,7 +80,7 @@ func Test_modeless_characterwise_selection() set mousemodel& " select multiple characters within a line backwards - let @* = '' + let @* = 'clean' call MouseRightClick(1, 1) call MouseRightRelease(1, 1) let keys = ":" @@ -93,7 +93,7 @@ func Test_modeless_characterwise_selection() " select multiple characters across lines with (end row > start row) and " (end column < start column) - let @* = '' + let @* = 'clean' call MouseRightClick(1, 1) call MouseRightRelease(1, 1) let keys = ":" @@ -106,7 +106,7 @@ func Test_modeless_characterwise_selection() " select multiple characters across lines with (end row > start row) and " (end column > start column) - let @* = '' + let @* = 'clean' call MouseRightClick(1, 1) call MouseRightRelease(1, 1) let keys = ":" @@ -119,7 +119,7 @@ func Test_modeless_characterwise_selection() " select multiple characters across lines with (end row < start row) and " (end column < start column) - let @* = '' + let @* = 'clean' call MouseRightClick(1, 1) call MouseRightRelease(1, 1) let keys = ":" @@ -132,7 +132,7 @@ func Test_modeless_characterwise_selection() " select multiple characters across lines with (end row < start row) and " (end column > start column) - let @* = '' + let @* = 'clean' call MouseRightClick(1, 1) call MouseRightRelease(1, 1) let keys = ":" @@ -145,7 +145,7 @@ func Test_modeless_characterwise_selection() " select multiple characters across lines with (end row < start row) and " the end column is greater than the line length - let @* = '' + let @* = 'clean' call MouseRightClick(1, 1) call MouseRightRelease(1, 1) let keys = ":" @@ -158,7 +158,7 @@ func Test_modeless_characterwise_selection() " select multiple characters across lines with start/end row and start/end " column outside the lines in the buffer - let @* = '' + let @* = 'clean' call MouseRightClick(1, 1) call MouseRightRelease(1, 1) let keys = ":" @@ -170,7 +170,7 @@ func Test_modeless_characterwise_selection() call assert_equal("\n~ ", @*, msg) " change selection using right mouse click within the selected text - let @* = '' + let @* = 'clean' call MouseRightClick(1, 1) call MouseRightRelease(1, 1) set mousemodel=extend @@ -188,7 +188,7 @@ func Test_modeless_characterwise_selection() set mousemodel& " select text multiple times at different places - let @* = '' + let @* = 'clean' call MouseRightClick(1, 1) call MouseRightRelease(1, 1) let keys = ":" @@ -205,7 +205,7 @@ func Test_modeless_characterwise_selection() " Test for 'clipboard' set to 'autoselectml' to automatically copy the " modeless selection to the clipboard set clipboard=autoselectml - let @* = '' + let @* = 'clean' let keys = ":" let keys ..= MouseLeftClickCode(2, 5) let keys ..= MouseLeftDragCode(2, 7) @@ -216,7 +216,7 @@ func Test_modeless_characterwise_selection() set clipboard& " quadruple click should start characterwise selectmode - let @* = '' + let @* = 'clean' call MouseRightClick(1, 1) call MouseRightRelease(1, 1) let keys = ":" @@ -259,7 +259,7 @@ func Test_modeless_word_selection() exe 'set ttymouse=' .. ttymouse_val " select multiple words within a line - let @* = '' + let @* = 'clean' call MouseRightClick(1, 1) call MouseRightRelease(1, 1) let keys = ":" @@ -273,7 +273,7 @@ func Test_modeless_word_selection() call assert_equal("two three", @*, msg) " select a single word - let @* = '' + let @* = 'clean' call MouseRightClick(1, 1) call MouseRightRelease(1, 1) let keys = ":" @@ -286,7 +286,7 @@ func Test_modeless_word_selection() call assert_equal("bar", @*, msg) " select multiple words backwards within a line - let @* = '' + let @* = 'clean' call MouseRightClick(1, 1) call MouseRightRelease(1, 1) let keys = ":" @@ -300,7 +300,7 @@ func Test_modeless_word_selection() call assert_equal("bar baz", @*, msg) " select multiple words backwards across lines - let @* = '' + let @* = 'clean' call MouseRightClick(1, 1) call MouseRightRelease(1, 1) let keys = ":" @@ -339,7 +339,7 @@ func Test_modeless_line_selection() exe 'set ttymouse=' .. ttymouse_val " select single line - let @* = '' + let @* = 'clean' call MouseRightClick(1, 1) call MouseRightRelease(1, 1) let keys = ":" @@ -354,7 +354,7 @@ func Test_modeless_line_selection() call assert_equal("foo bar baz\n", @*, msg) " select multiple lines - let @* = '' + let @* = 'clean' call MouseRightClick(1, 1) call MouseRightRelease(1, 1) let keys = ":" @@ -370,7 +370,7 @@ func Test_modeless_line_selection() call assert_equal("one two three\nfoo bar baz\n", @*, msg) " select multiple lines backwards - let @* = '' + let @* = 'clean' call MouseRightClick(1, 1) call MouseRightRelease(1, 1) let keys = ":" diff --git a/src/testdir/test_terminal.vim b/src/testdir/test_terminal.vim index f7b12e376a..b7791c8150 100644 --- a/src/testdir/test_terminal.vim +++ b/src/testdir/test_terminal.vim @@ -5,6 +5,7 @@ CheckFeature terminal source shared.vim source screendump.vim +source mouse.vim let s:python = PythonProg() let $PROMPT_COMMAND='' @@ -1206,6 +1207,26 @@ func Test_terminal_dumpwrite_composing() let &encoding = save_enc endfunc +" Tests for failures in the term_dumpwrite() function +func Test_terminal_dumpwrite_errors() + CheckRunVimInTerminal + call assert_fails("call term_dumpwrite({}, 'Xtest.dump')", 'E728:') + let buf = RunVimInTerminal('', {}) + call term_wait(buf) + call assert_fails("call term_dumpwrite(buf, 'Xtest.dump', '')", 'E715:') + call assert_fails("call term_dumpwrite(buf, [])", 'E730:') + call writefile([], 'Xtest.dump') + call assert_fails("call term_dumpwrite(buf, 'Xtest.dump')", 'E953:') + call delete('Xtest.dump') + call assert_fails("call term_dumpwrite(buf, '')", 'E482:') + call assert_fails("call term_dumpwrite(buf, test_null_string())", 'E482:') + call StopVimInTerminal(buf) + call term_wait(buf) + call assert_fails("call term_dumpwrite(buf, 'Xtest.dump')", 'E958:') + call assert_fails('call term_sendkeys([], ":q\<CR>")', 'E745:') + call assert_equal(0, term_sendkeys(buf, ":q\<CR>")) +endfunc + " just testing basic functionality. func Test_terminal_dumpload() let curbuf = winbufnr('') @@ -1231,6 +1252,8 @@ func Test_terminal_dumpload() let closedbuf = winbufnr('') quit call assert_fails("call term_dumpload('dumps/Test_popup_command_01.dump', {'bufnr': closedbuf})", 'E475:') + call assert_fails('call term_dumpload([])', 'E474:') + call assert_fails('call term_dumpload("xabcy.dump")', 'E485:') quit endfunc @@ -1258,6 +1281,12 @@ func Test_terminal_dumpdiff() call Check_dump01(42) call assert_equal(' bbbbbbbbbbbbbbbbbb ', getline(26)[0:29]) quit + + call assert_fails('call term_dumpdiff("X1.dump", [])', 'E474:') + call assert_fails('call term_dumpdiff("X1.dump", "X2.dump")', 'E485:') + call writefile([], 'X1.dump') + call assert_fails('call term_dumpdiff("X1.dump", "X2.dump")', 'E485:') + call delete('X1.dump') endfunc func Test_terminal_dumpdiff_swap() @@ -2652,4 +2681,200 @@ func Test_term_func_invalid_arg() call assert_fails('call term_setkill([], "")', 'E745:') endfunc +" Test for sending various special keycodes to a terminal +func Test_term_keycode_translation() + CheckRunVimInTerminal + + let buf = RunVimInTerminal('', {}) + call term_sendkeys(buf, ":set nocompatible\<CR>") + + let keys = ["\<F1>", "\<F2>", "\<F3>", "\<F4>", "\<F5>", "\<F6>", "\<F7>", + \ "\<F8>", "\<F9>", "\<F10>", "\<F11>", "\<F12>", "\<Home>", + \ "\<S-Home>", "\<C-Home>", "\<End>", "\<S-End>", "\<C-End>", + \ "\<Ins>", "\<Del>", "\<Left>", "\<S-Left>", "\<C-Left>", "\<Right>", + \ "\<S-Right>", "\<C-Right>", "\<Up>", "\<S-Up>", "\<Down>", + \ "\<S-Down>"] + let output = ['<F1>', '<F2>', '<F3>', '<F4>', '<F5>', '<F6>', '<F7>', + \ '<F8>', '<F9>', '<F10>', '<F11>', '<F12>', '<Home>', '<S-Home>', + \ '<C-Home>', '<End>', '<S-End>', '<C-End>', '<Insert>', '<Del>', + \ '<Left>', '<S-Left>', '<C-Left>', '<Right>', '<S-Right>', + \ '<C-Right>', '<Up>', '<S-Up>', '<Down>', '<S-Down>', + \ '0123456789', "\t\t.+-*/"] + + for k in keys + call term_sendkeys(buf, "i\<C-K>" .. k .. "\<CR>\<C-\>\<C-N>") + endfor + call term_sendkeys(buf, "i\<K0>\<K1>\<K2>\<K3>\<K4>\<K5>\<K6>\<K7>") + call term_sendkeys(buf, "\<K8>\<K9>\<kEnter>\<kPoint>\<kPlus>") + call term_sendkeys(buf, "\<kMinus>\<kMultiply>\<kDivide>\<C-\>\<C-N>") + call term_sendkeys(buf, "\<Home>\<Ins>\<Tab>\<S-Tab>\<C-\>\<C-N>") + + call term_sendkeys(buf, ":write Xkeycodes\<CR>") + call term_wait(buf) + call StopVimInTerminal(buf) + call assert_equal(output, readfile('Xkeycodes')) + call delete('Xkeycodes') +endfunc + +" Test for using the mouse in a terminal +func Test_term_mouse() + CheckNotGui + CheckRunVimInTerminal + + let save_mouse = &mouse + let save_term = &term + let save_ttymouse = &ttymouse + let save_clipboard = &clipboard + call test_override('no_query_mouse', 1) + set mouse=a term=xterm ttymouse=sgr mousetime=200 clipboard= + + let lines =<< trim END + one two three four five + red green yellow red blue + vim emacs sublime nano + END + call writefile(lines, 'Xtest_mouse') + + let buf = RunVimInTerminal('Xtest_mouse -n', {}) + call term_sendkeys(buf, ":set nocompatible\<CR>") + call term_sendkeys(buf, ":set mouse=a term=xterm ttymouse=sgr\<CR>") + call term_sendkeys(buf, ":set clipboard=\<CR>") + call term_sendkeys(buf, ":set mousemodel=extend\<CR>") + call term_wait(buf) + redraw! + + " Test for <LeftMouse> click/release + call test_setmouse(2, 5) + call feedkeys("\<LeftMouse>\<LeftRelease>", 'xt') + call test_setmouse(3, 8) + call term_sendkeys(buf, "\<LeftMouse>\<LeftRelease>") + call term_wait(buf, 50) + call term_sendkeys(buf, ":call writefile([json_encode(getpos('.'))], 'Xbuf')\<CR>") + call term_wait(buf, 50) + let pos = json_decode(readfile('Xbuf')[0]) + call assert_equal([3, 8], pos[1:2]) + + " Test for selecting text using mouse + call delete('Xbuf') + call test_setmouse(2, 11) + call term_sendkeys(buf, "\<LeftMouse>") + call test_setmouse(2, 16) + call term_sendkeys(buf, "\<LeftRelease>y") + call term_wait(buf, 50) + call term_sendkeys(buf, ":call writefile([@\"], 'Xbuf')\<CR>") + call term_wait(buf, 50) + call assert_equal('yellow', readfile('Xbuf')[0]) + + " Test for selecting text using doubleclick + call delete('Xbuf') + call test_setmouse(1, 11) + call term_sendkeys(buf, "\<LeftMouse>\<LeftRelease>\<LeftMouse>") + call test_setmouse(1, 17) + call term_sendkeys(buf, "\<LeftRelease>y") + call term_wait(buf, 50) + call term_sendkeys(buf, ":call writefile([@\"], 'Xbuf')\<CR>") + call term_wait(buf, 50) + call assert_equal('three four', readfile('Xbuf')[0]) + + " Test for selecting a line using triple click + call delete('Xbuf') + call test_setmouse(3, 2) + call term_sendkeys(buf, "\<LeftMouse>\<LeftRelease>\<LeftMouse>\<LeftRelease>\<LeftMouse>\<LeftRelease>y") + call term_wait(buf, 50) + call term_sendkeys(buf, ":call writefile([@\"], 'Xbuf')\<CR>") + call term_wait(buf, 50) + call assert_equal("vim emacs sublime nano\n", readfile('Xbuf')[0]) + + " Test for selecting a block using qudraple click + call delete('Xbuf') + call test_setmouse(1, 11) + call term_sendkeys(buf, "\<LeftMouse>\<LeftRelease>\<LeftMouse>\<LeftRelease>\<LeftMouse>\<LeftRelease>\<LeftMouse>") + call test_setmouse(3, 13) + call term_sendkeys(buf, "\<LeftRelease>y") + call term_wait(buf, 50) + call term_sendkeys(buf, ":call writefile([@\"], 'Xbuf')\<CR>") + call term_wait(buf, 50) + call assert_equal("ree\nyel\nsub", readfile('Xbuf')[0]) + + " Test for extending a selection using right click + call delete('Xbuf') + call test_setmouse(2, 9) + call term_sendkeys(buf, "\<LeftMouse>\<LeftRelease>") + call test_setmouse(2, 16) + call term_sendkeys(buf, "\<RightMouse>\<RightRelease>y") + call term_wait(buf, 50) + call term_sendkeys(buf, ":call writefile([@\"], 'Xbuf')\<CR>") + call term_wait(buf, 50) + call assert_equal("n yellow", readfile('Xbuf')[0]) + + " Test for pasting text using middle click + call delete('Xbuf') + call term_sendkeys(buf, ":let @r='bright '\<CR>") + call test_setmouse(2, 22) + call term_sendkeys(buf, "\"r\<MiddleMouse>\<MiddleRelease>") + call term_wait(buf, 50) + call term_sendkeys(buf, ":call writefile([getline(2)], 'Xbuf')\<CR>") + call term_wait(buf, 50) + call assert_equal("red bright blue", readfile('Xbuf')[0][-15:]) + + " cleanup + call term_wait(buf) + call StopVimInTerminal(buf) + let &mouse = save_mouse + let &term = save_term + let &ttymouse = save_ttymouse + let &clipboard = save_clipboard + set mousetime& + call test_override('no_query_mouse', 0) + call delete('Xtest_mouse') + call delete('Xbuf') +endfunc + +" Test for modeless selection in a terminal +func Test_term_modeless_selection() + CheckUnix + CheckNotGui + CheckRunVimInTerminal + CheckFeature clipboard_working + + let save_mouse = &mouse + let save_term = &term + let save_ttymouse = &ttymouse + call test_override('no_query_mouse', 1) + set mouse=a term=xterm ttymouse=sgr mousetime=200 + set clipboard=autoselectml + + let lines =<< trim END + one two three four five + red green yellow red blue + vim emacs sublime nano + END + call writefile(lines, 'Xtest_modeless') + + let buf = RunVimInTerminal('Xtest_modeless -n', {}) + call term_sendkeys(buf, ":set nocompatible\<CR>") + call term_sendkeys(buf, ":set mouse=\<CR>") + call term_wait(buf) + redraw! + + " Test for copying a modeless selection to clipboard + let @* = 'clean' + " communicating with X server may take a little time + sleep 100m + call feedkeys(MouseLeftClickCode(2, 3), 'x') + call feedkeys(MouseLeftDragCode(2, 11), 'x') + call feedkeys(MouseLeftReleaseCode(2, 11), 'x') + call assert_equal("d green y", @*) + + " cleanup + call term_wait(buf) + call StopVimInTerminal(buf) + let &mouse = save_mouse + let &term = save_term + let &ttymouse = save_ttymouse + set mousetime& clipboard& + call test_override('no_query_mouse', 0) + call delete('Xtest_modeless') +endfunc + " vim: shiftwidth=2 sts=2 expandtab diff --git a/src/version.c b/src/version.c index 31d83ce872..317b34431e 100644 --- a/src/version.c +++ b/src/version.c @@ -746,6 +746,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 738, /**/ 737, /**/ From b415168a9862023462b7193e83da948cb8d11893 Mon Sep 17 00:00:00 2001 From: Bram Moolenaar <Bram@vim.org> Date: Mon, 11 May 2020 22:13:28 +0200 Subject: [PATCH 135/230] patch 8.2.0739: incomplete profiling when exiting because of a dealy signal Problem: Incomplete profiling when exiting because of a dealy signal. Solution: Call __gcov_flush() if available. --- .travis.yml | 4 ++-- src/Makefile | 4 +++- src/os_unix.c | 10 ++++++++++ src/version.c | 2 ++ 4 files changed, 17 insertions(+), 3 deletions(-) diff --git a/.travis.yml b/.travis.yml index 2c5f5ff304..7c1ecbca56 100644 --- a/.travis.yml +++ b/.travis.yml @@ -11,13 +11,13 @@ _anchors: - &normal BUILD=yes TEST=test FEATURES=normal CONFOPT= SHADOWOPT= SRCDIR=./src CHECK_AUTOCONF=no - &linux-huge - BUILD=yes TEST="scripttests test_libvterm" CFLAGS=--coverage LDFLAGS=--coverage FEATURES=huge SHADOWOPT= SRCDIR=./src CHECK_AUTOCONF=no + BUILD=yes TEST="scripttests test_libvterm" CFLAGS="--coverage -DUSE_GCOV_FLUSH" LDFLAGS=--coverage FEATURES=huge SHADOWOPT= SRCDIR=./src CHECK_AUTOCONF=no CONFOPT="--enable-perlinterp --enable-pythoninterp --enable-python3interp --enable-rubyinterp --enable-luainterp --enable-tclinterp" - &osx-huge # macOS build BUILD=yes TEST=test FEATURES=huge SHADOWOPT= SRCDIR=./src CHECK_AUTOCONF=no CONFOPT="--enable-perlinterp --enable-pythoninterp --enable-rubyinterp --enable-luainterp --enable-tclinterp" - &unittests - BUILD=no TEST=unittests CFLAGS=--coverage LDFLAGS=--coverage FEATURES=huge SHADOWOPT= SRCDIR=./src CHECK_AUTOCONF=yes + BUILD=no TEST=unittests CFLAGS="--coverage -DUSE_GCOV_FLUSH" LDFLAGS=--coverage FEATURES=huge SHADOWOPT= SRCDIR=./src CHECK_AUTOCONF=yes - &asan # ASAN build SANITIZER_CFLAGS="-g -O1 -DABORT_ON_INTERNAL_ERROR -DEXITFREE -fsanitize=address -fno-omit-frame-pointer" ASAN_OPTIONS="print_stacktrace=1 log_path=asan" LSAN_OPTIONS="suppressions=$TRAVIS_BUILD_DIR/src/testdir/lsan-suppress.txt" diff --git a/src/Makefile b/src/Makefile index 6c7ef85a92..7c2934aea3 100644 --- a/src/Makefile +++ b/src/Makefile @@ -686,8 +686,10 @@ LINT_OPTIONS = -beprxzF # 7. Open the objects/index.html file in a web browser to view the coverage # information. # -# PROFILE_CFLAGS=-g -O0 -fprofile-arcs -ftest-coverage # LDFLAGS=--coverage +# PROFILE_CFLAGS=-g -O0 -fprofile-arcs -ftest-coverage -DWE_ARE_PROFILING -DUSE_GCOV_FLUSH +# Alternate flags +# PROFILE_CFLAGS=-g -O0 --coverage -DWE_ARE_PROFILING -DUSE_GCOV_FLUSH # Uncomment one of the next two lines to compile Vim with the diff --git a/src/os_unix.c b/src/os_unix.c index b5ae9f8687..aea3d5a9e2 100644 --- a/src/os_unix.c +++ b/src/os_unix.c @@ -3312,6 +3312,10 @@ exit_scroll(void) } } +#ifdef USE_GCOV_FLUSH +extern void __gcov_flush(); +#endif + void mch_exit(int r) { @@ -3358,6 +3362,12 @@ mch_exit(int r) } out_flush(); ml_close_all(TRUE); // remove all memfiles + +#ifdef USE_GCOV_FLUSH + // Flush coverage info before possibly being killed by a deadly signal. + __gcov_flush(); +#endif + may_core_dump(); #ifdef FEAT_GUI if (gui.in_use) diff --git a/src/version.c b/src/version.c index 317b34431e..799e846713 100644 --- a/src/version.c +++ b/src/version.c @@ -746,6 +746,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 739, /**/ 738, /**/ From 86181df9f5501ba735dcb75e0832c35ac1212ca6 Mon Sep 17 00:00:00 2001 From: Bram Moolenaar <Bram@vim.org> Date: Mon, 11 May 2020 23:14:04 +0200 Subject: [PATCH 136/230] patch 8.2.0740: minor message mistakes Problem: Minor message mistakes. Solution: Change vim to Vim and other fixes. --- src/if_py_both.h | 26 +++++++++++++------------- src/if_tcl.c | 2 +- src/main.c | 6 +++--- src/version.c | 2 ++ 4 files changed, 19 insertions(+), 17 deletions(-) diff --git a/src/if_py_both.h b/src/if_py_both.h index d6a5b11a5d..a13a5e345a 100644 --- a/src/if_py_both.h +++ b/src/if_py_both.h @@ -652,7 +652,7 @@ VimTryEnd(void) } else if (!did_throw) return (PyErr_Occurred() ? -1 : 0); - // Python exception is preferred over vim one; unlikely to occur though + // Python exception is preferred over Vim one; unlikely to occur though else if (PyErr_Occurred()) { discard_current_exception(); @@ -1406,7 +1406,7 @@ static struct PyMethodDef VimMethods[] = { // name, function, calling, documentation {"command", VimCommand, METH_O, "Execute a Vim ex-mode command" }, {"eval", VimEval, METH_VARARGS, "Evaluate an expression using Vim evaluator" }, - {"bindeval", VimEvalPy, METH_O, "Like eval(), but returns objects attached to vim ones"}, + {"bindeval", VimEvalPy, METH_O, "Like eval(), but returns objects attached to Vim ones"}, {"strwidth", VimStrwidth, METH_O, "Screen string width, counts <Tab> as having width 1"}, {"chdir", (PyCFunction)VimChdir, METH_VARARGS|METH_KEYWORDS, "Change directory"}, {"fchdir", (PyCFunction)VimFchdir, METH_VARARGS|METH_KEYWORDS, "Change directory"}, @@ -2393,7 +2393,7 @@ ListIndex(ListObject *self, Py_ssize_t index) if (li == NULL) { // No more suitable format specifications in python-2.3 - PyErr_VIM_FORMAT(N_("internal error: failed to get vim list item %d"), + PyErr_VIM_FORMAT(N_("internal error: failed to get Vim list item %d"), (int) index); return NULL; } @@ -2555,7 +2555,7 @@ ListAssSlice(ListObject *self, Py_ssize_t first, li = list_find(l, (long) first); if (li == NULL) { - PyErr_VIM_FORMAT(N_("internal error: no vim list item %d"), + PyErr_VIM_FORMAT(N_("internal error: no Vim list item %d"), (int)first); if (obj != NULL) PyMem_Free(lis); @@ -4267,7 +4267,7 @@ StringToLine(PyObject *obj) /* * Create a copy of the string, with internal nulls replaced by - * newline characters, as is the vim convention. + * newline characters, as is the Vim convention. */ save = alloc(len+1); if (save == NULL) @@ -4614,7 +4614,7 @@ SetBufferLineList( // Now we may need to insert the remaining new old_len. If we do, we // must free the strings as we finish with them (we can't pass the - // responsibility to vim in this case). + // responsibility to Vim in this case). if (!PyErr_Occurred()) { while (i < new_len) @@ -5825,7 +5825,7 @@ run_eval(const char *cmd, typval_T *rettv else { if (ConvertFromPyObject(run_ret, rettv) == -1) - emsg(_("E859: Failed to convert returned python object to vim value")); + emsg(_("E859: Failed to convert returned python object to a Vim value")); Py_DECREF(run_ret); } PyErr_Clear(); @@ -6159,7 +6159,7 @@ ConvertFromPyMapping(PyObject *obj, typval_T *tv) else { PyErr_FORMAT(PyExc_TypeError, - N_("unable to convert %s to vim dictionary"), + N_("unable to convert %s to a Vim dictionary"), Py_TYPE_NAME(obj)); ret = -1; } @@ -6188,7 +6188,7 @@ ConvertFromPySequence(PyObject *obj, typval_T *tv) else { PyErr_FORMAT(PyExc_TypeError, - N_("unable to convert %s to vim list"), + N_("unable to convert %s to a Vim list"), Py_TYPE_NAME(obj)); ret = -1; } @@ -6333,7 +6333,7 @@ _ConvertFromPyObject(PyObject *obj, typval_T *tv, PyObject *lookup_dict) else { PyErr_FORMAT(PyExc_TypeError, - N_("unable to convert %s to vim structure"), + N_("unable to convert %s to a Vim structure"), Py_TYPE_NAME(obj)); return -1; } @@ -6575,7 +6575,7 @@ init_structs(void) DictionaryType.tp_as_sequence = &DictionaryAsSeq; DictionaryType.tp_as_mapping = &DictionaryAsMapping; DictionaryType.tp_flags = Py_TPFLAGS_DEFAULT|Py_TPFLAGS_BASETYPE; - DictionaryType.tp_doc = "dictionary pushing modifications to vim structure"; + DictionaryType.tp_doc = "dictionary pushing modifications to Vim structure"; DictionaryType.tp_methods = DictionaryMethods; DictionaryType.tp_iter = (getiterfunc)DictionaryIter; DictionaryType.tp_new = (newfunc)DictionaryConstructor; @@ -6595,7 +6595,7 @@ init_structs(void) ListType.tp_as_sequence = &ListAsSeq; ListType.tp_as_mapping = &ListAsMapping; ListType.tp_flags = Py_TPFLAGS_DEFAULT|Py_TPFLAGS_BASETYPE; - ListType.tp_doc = "list pushing modifications to vim structure"; + ListType.tp_doc = "list pushing modifications to Vim structure"; ListType.tp_methods = ListMethods; ListType.tp_iter = (getiterfunc)ListIter; ListType.tp_new = (newfunc)ListConstructor; @@ -6614,7 +6614,7 @@ init_structs(void) FunctionType.tp_dealloc = (destructor)FunctionDestructor; FunctionType.tp_call = (ternaryfunc)FunctionCall; FunctionType.tp_flags = Py_TPFLAGS_DEFAULT|Py_TPFLAGS_BASETYPE; - FunctionType.tp_doc = "object that calls vim function"; + FunctionType.tp_doc = "object that calls Vim function"; FunctionType.tp_methods = FunctionMethods; FunctionType.tp_repr = (reprfunc)FunctionRepr; FunctionType.tp_new = (newfunc)FunctionConstructor; diff --git a/src/if_tcl.c b/src/if_tcl.c index 45d880bdad..17e20ee389 100644 --- a/src/if_tcl.c +++ b/src/if_tcl.c @@ -1403,7 +1403,7 @@ vimerror(Tcl_Interp *interp) } else if (did_emsg) { - Tcl_SetResult(interp, _("vim error"), TCL_STATIC); + Tcl_SetResult(interp, _("Vim error"), TCL_STATIC); return TCL_ERROR; } return TCL_OK; diff --git a/src/main.c b/src/main.c index a65392f772..a1e933cc50 100644 --- a/src/main.c +++ b/src/main.c @@ -3562,7 +3562,7 @@ usage(void) #endif #if (defined(UNIX) || defined(VMS)) && defined(FEAT_X11) # if defined(FEAT_GUI_X11) && !defined(FEAT_GUI_GTK) - main_msg(_("-display <display>\tConnect vim to this particular X-server")); + main_msg(_("-display <display>\tConnect Vim to this particular X-server")); # endif main_msg(_("-X\t\t\tDo not connect to X server")); #endif @@ -3599,7 +3599,7 @@ usage(void) # endif # endif # endif - main_msg(_("-display <display>\tRun vim on <display>")); + main_msg(_("-display <display>\tRun Vim on <display>")); main_msg(_("-iconic\t\tStart vim iconified")); main_msg(_("-background <color>\tUse <color> for the background (also: -bg)")); main_msg(_("-foreground <color>\tUse <color> for normal text (also: -fg)")); @@ -3621,7 +3621,7 @@ usage(void) main_msg(_("-font <font>\t\tUse <font> for normal text (also: -fn)")); main_msg(_("-geometry <geom>\tUse <geom> for initial geometry (also: -geom)")); main_msg(_("-reverse\t\tUse reverse video (also: -rv)")); - main_msg(_("-display <display>\tRun vim on <display> (also: --display)")); + main_msg(_("-display <display>\tRun Vim on <display> (also: --display)")); main_msg(_("--role <role>\tSet a unique role to identify the main window")); main_msg(_("--socketid <xid>\tOpen Vim inside another GTK widget")); main_msg(_("--echo-wid\t\tMake gvim echo the Window ID on stdout")); diff --git a/src/version.c b/src/version.c index 799e846713..a31cdabb52 100644 --- a/src/version.c +++ b/src/version.c @@ -746,6 +746,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 740, /**/ 739, /**/ From c3fd98cf8e43d48a322402d08fa83444c2b0a4a6 Mon Sep 17 00:00:00 2001 From: Bram Moolenaar <Bram@vim.org> Date: Tue, 12 May 2020 13:08:07 +0200 Subject: [PATCH 137/230] patch 8.2.0741: Python tests fail because of changed message Problem: Python tests fail because of changed message. Solution: Adjust the expected messages (Dominique Pelle, closes #6066) --- src/testdir/test86.ok | 64 +++++++++++++++++++++---------------------- src/testdir/test87.ok | 54 ++++++++++++++++++------------------ src/version.c | 2 ++ 3 files changed, 61 insertions(+), 59 deletions(-) diff --git a/src/testdir/test86.ok b/src/testdir/test86.ok index 6ad02e3723..4f6d4b3060 100644 --- a/src/testdir/test86.ok +++ b/src/testdir/test86.ok @@ -764,7 +764,7 @@ d["a"] = {"abcF" : Mapping({u"\0" : 1})}:TypeError:('expected string without nul d["a"] = {"abcF" : Mapping({"\0" : 1})}:TypeError:('expected string without null bytes',) <<< Finished >>> Testing *Iter* using d["a"] = {"abcF" : %s} -d["a"] = {"abcF" : FailingIter()}:TypeError:('unable to convert FailingIter to vim structure',) +d["a"] = {"abcF" : FailingIter()}:TypeError:('unable to convert FailingIter to a Vim structure',) d["a"] = {"abcF" : FailingIterNext()}:NotImplementedError:('next',) <<< Finished >>> Testing ConvertFromPyObject using d["a"] = {"abcF" : %s} @@ -791,7 +791,7 @@ d["a"] = Mapping({"abcG" : Mapping({u"\0" : 1})}):TypeError:('expected string wi d["a"] = Mapping({"abcG" : Mapping({"\0" : 1})}):TypeError:('expected string without null bytes',) <<< Finished >>> Testing *Iter* using d["a"] = Mapping({"abcG" : %s}) -d["a"] = Mapping({"abcG" : FailingIter()}):TypeError:('unable to convert FailingIter to vim structure',) +d["a"] = Mapping({"abcG" : FailingIter()}):TypeError:('unable to convert FailingIter to a Vim structure',) d["a"] = Mapping({"abcG" : FailingIterNext()}):NotImplementedError:('next',) <<< Finished >>> Testing ConvertFromPyObject using d["a"] = Mapping({"abcG" : %s}) @@ -803,7 +803,7 @@ d["a"] = Mapping({"abcG" : FailingMappingKey()}):NotImplementedError:('getitem:m d["a"] = Mapping({"abcG" : FailingNumber()}):TypeError:('long() argument must be a string or a number',) <<< Finished >>> Testing *Iter* using d["a"] = %s -d["a"] = FailingIter():TypeError:('unable to convert FailingIter to vim structure',) +d["a"] = FailingIter():TypeError:('unable to convert FailingIter to a Vim structure',) d["a"] = FailingIterNext():NotImplementedError:('next',) <<< Finished >>> Testing ConvertFromPyObject using d["a"] = %s @@ -840,7 +840,7 @@ d.update({"abcF" : Mapping({u"\0" : 1})}):TypeError:('expected string without nu d.update({"abcF" : Mapping({"\0" : 1})}):TypeError:('expected string without null bytes',) <<< Finished >>> Testing *Iter* using d.update({"abcF" : %s}) -d.update({"abcF" : FailingIter()}):TypeError:('unable to convert FailingIter to vim structure',) +d.update({"abcF" : FailingIter()}):TypeError:('unable to convert FailingIter to a Vim structure',) d.update({"abcF" : FailingIterNext()}):NotImplementedError:('next',) <<< Finished >>> Testing ConvertFromPyObject using d.update({"abcF" : %s}) @@ -867,7 +867,7 @@ d.update(Mapping({"abcG" : Mapping({u"\0" : 1})})):TypeError:('expected string w d.update(Mapping({"abcG" : Mapping({"\0" : 1})})):TypeError:('expected string without null bytes',) <<< Finished >>> Testing *Iter* using d.update(Mapping({"abcG" : %s})) -d.update(Mapping({"abcG" : FailingIter()})):TypeError:('unable to convert FailingIter to vim structure',) +d.update(Mapping({"abcG" : FailingIter()})):TypeError:('unable to convert FailingIter to a Vim structure',) d.update(Mapping({"abcG" : FailingIterNext()})):NotImplementedError:('next',) <<< Finished >>> Testing ConvertFromPyObject using d.update(Mapping({"abcG" : %s})) @@ -911,7 +911,7 @@ d.update((("a", {"abcF" : Mapping({u"\0" : 1})}),)):TypeError:('expected string d.update((("a", {"abcF" : Mapping({"\0" : 1})}),)):TypeError:('expected string without null bytes',) <<< Finished >>> Testing *Iter* using d.update((("a", {"abcF" : %s}),)) -d.update((("a", {"abcF" : FailingIter()}),)):TypeError:('unable to convert FailingIter to vim structure',) +d.update((("a", {"abcF" : FailingIter()}),)):TypeError:('unable to convert FailingIter to a Vim structure',) d.update((("a", {"abcF" : FailingIterNext()}),)):NotImplementedError:('next',) <<< Finished >>> Testing ConvertFromPyObject using d.update((("a", {"abcF" : %s}),)) @@ -938,7 +938,7 @@ d.update((("a", Mapping({"abcG" : Mapping({u"\0" : 1})})),)):TypeError:('expecte d.update((("a", Mapping({"abcG" : Mapping({"\0" : 1})})),)):TypeError:('expected string without null bytes',) <<< Finished >>> Testing *Iter* using d.update((("a", Mapping({"abcG" : %s})),)) -d.update((("a", Mapping({"abcG" : FailingIter()})),)):TypeError:('unable to convert FailingIter to vim structure',) +d.update((("a", Mapping({"abcG" : FailingIter()})),)):TypeError:('unable to convert FailingIter to a Vim structure',) d.update((("a", Mapping({"abcG" : FailingIterNext()})),)):NotImplementedError:('next',) <<< Finished >>> Testing ConvertFromPyObject using d.update((("a", Mapping({"abcG" : %s})),)) @@ -950,7 +950,7 @@ d.update((("a", Mapping({"abcG" : FailingMappingKey()})),)):NotImplementedError: d.update((("a", Mapping({"abcG" : FailingNumber()})),)):TypeError:('long() argument must be a string or a number',) <<< Finished >>> Testing *Iter* using d.update((("a", %s),)) -d.update((("a", FailingIter()),)):TypeError:('unable to convert FailingIter to vim structure',) +d.update((("a", FailingIter()),)):TypeError:('unable to convert FailingIter to a Vim structure',) d.update((("a", FailingIterNext()),)):NotImplementedError:('next',) <<< Finished >>> Testing ConvertFromPyObject using d.update((("a", %s),)) @@ -989,7 +989,7 @@ vim.List([{"abcF" : Mapping({u"\0" : 1})}]):TypeError:('expected string without vim.List([{"abcF" : Mapping({"\0" : 1})}]):TypeError:('expected string without null bytes',) <<< Finished >>> Testing *Iter* using vim.List([{"abcF" : %s}]) -vim.List([{"abcF" : FailingIter()}]):TypeError:('unable to convert FailingIter to vim structure',) +vim.List([{"abcF" : FailingIter()}]):TypeError:('unable to convert FailingIter to a Vim structure',) vim.List([{"abcF" : FailingIterNext()}]):NotImplementedError:('next',) <<< Finished >>> Testing ConvertFromPyObject using vim.List([{"abcF" : %s}]) @@ -1016,7 +1016,7 @@ vim.List([Mapping({"abcG" : Mapping({u"\0" : 1})})]):TypeError:('expected string vim.List([Mapping({"abcG" : Mapping({"\0" : 1})})]):TypeError:('expected string without null bytes',) <<< Finished >>> Testing *Iter* using vim.List([Mapping({"abcG" : %s})]) -vim.List([Mapping({"abcG" : FailingIter()})]):TypeError:('unable to convert FailingIter to vim structure',) +vim.List([Mapping({"abcG" : FailingIter()})]):TypeError:('unable to convert FailingIter to a Vim structure',) vim.List([Mapping({"abcG" : FailingIterNext()})]):NotImplementedError:('next',) <<< Finished >>> Testing ConvertFromPyObject using vim.List([Mapping({"abcG" : %s})]) @@ -1028,7 +1028,7 @@ vim.List([Mapping({"abcG" : FailingMappingKey()})]):NotImplementedError:('getite vim.List([Mapping({"abcG" : FailingNumber()})]):TypeError:('long() argument must be a string or a number',) <<< Finished >>> Testing *Iter* using vim.List([%s]) -vim.List([FailingIter()]):TypeError:('unable to convert FailingIter to vim structure',) +vim.List([FailingIter()]):TypeError:('unable to convert FailingIter to a Vim structure',) vim.List([FailingIterNext()]):NotImplementedError:('next',) <<< Finished >>> Testing ConvertFromPyObject using vim.List([%s]) @@ -1074,7 +1074,7 @@ l[:] = [{"abcF" : Mapping({u"\0" : 1})}]:TypeError:('expected string without nul l[:] = [{"abcF" : Mapping({"\0" : 1})}]:TypeError:('expected string without null bytes',) <<< Finished >>> Testing *Iter* using l[:] = [{"abcF" : %s}] -l[:] = [{"abcF" : FailingIter()}]:TypeError:('unable to convert FailingIter to vim structure',) +l[:] = [{"abcF" : FailingIter()}]:TypeError:('unable to convert FailingIter to a Vim structure',) l[:] = [{"abcF" : FailingIterNext()}]:NotImplementedError:('next',) <<< Finished >>> Testing ConvertFromPyObject using l[:] = [{"abcF" : %s}] @@ -1101,7 +1101,7 @@ l[:] = [Mapping({"abcG" : Mapping({u"\0" : 1})})]:TypeError:('expected string wi l[:] = [Mapping({"abcG" : Mapping({"\0" : 1})})]:TypeError:('expected string without null bytes',) <<< Finished >>> Testing *Iter* using l[:] = [Mapping({"abcG" : %s})] -l[:] = [Mapping({"abcG" : FailingIter()})]:TypeError:('unable to convert FailingIter to vim structure',) +l[:] = [Mapping({"abcG" : FailingIter()})]:TypeError:('unable to convert FailingIter to a Vim structure',) l[:] = [Mapping({"abcG" : FailingIterNext()})]:NotImplementedError:('next',) <<< Finished >>> Testing ConvertFromPyObject using l[:] = [Mapping({"abcG" : %s})] @@ -1113,7 +1113,7 @@ l[:] = [Mapping({"abcG" : FailingMappingKey()})]:NotImplementedError:('getitem:m l[:] = [Mapping({"abcG" : FailingNumber()})]:TypeError:('long() argument must be a string or a number',) <<< Finished >>> Testing *Iter* using l[:] = [%s] -l[:] = [FailingIter()]:TypeError:('unable to convert FailingIter to vim structure',) +l[:] = [FailingIter()]:TypeError:('unable to convert FailingIter to a Vim structure',) l[:] = [FailingIterNext()]:NotImplementedError:('next',) <<< Finished >>> Testing ConvertFromPyObject using l[:] = [%s] @@ -1145,7 +1145,7 @@ l.extend([{"abcF" : Mapping({u"\0" : 1})}]):TypeError:('expected string without l.extend([{"abcF" : Mapping({"\0" : 1})}]):TypeError:('expected string without null bytes',) <<< Finished >>> Testing *Iter* using l.extend([{"abcF" : %s}]) -l.extend([{"abcF" : FailingIter()}]):TypeError:('unable to convert FailingIter to vim structure',) +l.extend([{"abcF" : FailingIter()}]):TypeError:('unable to convert FailingIter to a Vim structure',) l.extend([{"abcF" : FailingIterNext()}]):NotImplementedError:('next',) <<< Finished >>> Testing ConvertFromPyObject using l.extend([{"abcF" : %s}]) @@ -1172,7 +1172,7 @@ l.extend([Mapping({"abcG" : Mapping({u"\0" : 1})})]):TypeError:('expected string l.extend([Mapping({"abcG" : Mapping({"\0" : 1})})]):TypeError:('expected string without null bytes',) <<< Finished >>> Testing *Iter* using l.extend([Mapping({"abcG" : %s})]) -l.extend([Mapping({"abcG" : FailingIter()})]):TypeError:('unable to convert FailingIter to vim structure',) +l.extend([Mapping({"abcG" : FailingIter()})]):TypeError:('unable to convert FailingIter to a Vim structure',) l.extend([Mapping({"abcG" : FailingIterNext()})]):NotImplementedError:('next',) <<< Finished >>> Testing ConvertFromPyObject using l.extend([Mapping({"abcG" : %s})]) @@ -1184,7 +1184,7 @@ l.extend([Mapping({"abcG" : FailingMappingKey()})]):NotImplementedError:('getite l.extend([Mapping({"abcG" : FailingNumber()})]):TypeError:('long() argument must be a string or a number',) <<< Finished >>> Testing *Iter* using l.extend([%s]) -l.extend([FailingIter()]):TypeError:('unable to convert FailingIter to vim structure',) +l.extend([FailingIter()]):TypeError:('unable to convert FailingIter to a Vim structure',) l.extend([FailingIterNext()]):NotImplementedError:('next',) <<< Finished >>> Testing ConvertFromPyObject using l.extend([%s]) @@ -1209,11 +1209,11 @@ vim.Function("xxx_non_existent_function_xxx2", args=[]):ValueError:('function xx vim.Function("xxx_non_existent_function_xxx3", self={}):ValueError:('function xxx_non_existent_function_xxx3 does not exist',) vim.Function("xxx_non_existent_function_xxx4", args=[], self={}):ValueError:('function xxx_non_existent_function_xxx4 does not exist',) >>> FunctionNew -vim.Function("tr", self="abcFuncSelf"):TypeError:('unable to convert str to vim dictionary',) -vim.Function("tr", args=427423):TypeError:('unable to convert int to vim list',) -vim.Function("tr", self="abcFuncSelf2", args="abcFuncArgs2"):TypeError:('unable to convert str to vim dictionary',) -vim.Function(self="abcFuncSelf2", args="abcFuncArgs2"):TypeError:('unable to convert str to vim dictionary',) -vim.Function("tr", "", self="abcFuncSelf2", args="abcFuncArgs2"):TypeError:('unable to convert str to vim dictionary',) +vim.Function("tr", self="abcFuncSelf"):TypeError:('unable to convert str to a Vim dictionary',) +vim.Function("tr", args=427423):TypeError:('unable to convert int to a Vim list',) +vim.Function("tr", self="abcFuncSelf2", args="abcFuncArgs2"):TypeError:('unable to convert str to a Vim dictionary',) +vim.Function(self="abcFuncSelf2", args="abcFuncArgs2"):TypeError:('unable to convert str to a Vim dictionary',) +vim.Function("tr", "", self="abcFuncSelf2", args="abcFuncArgs2"):TypeError:('unable to convert str to a Vim dictionary',) vim.Function("tr", ""):TypeError:('function takes exactly 1 argument (2 given)',) >> FunctionCall >>> Testing StringToChars using f({%s : 1}) @@ -1232,7 +1232,7 @@ f({"abcF" : Mapping({u"\0" : 1})}):TypeError:('expected string without null byte f({"abcF" : Mapping({"\0" : 1})}):TypeError:('expected string without null bytes',) <<< Finished >>> Testing *Iter* using f({"abcF" : %s}) -f({"abcF" : FailingIter()}):TypeError:('unable to convert FailingIter to vim structure',) +f({"abcF" : FailingIter()}):TypeError:('unable to convert FailingIter to a Vim structure',) f({"abcF" : FailingIterNext()}):NotImplementedError:('next',) <<< Finished >>> Testing ConvertFromPyObject using f({"abcF" : %s}) @@ -1259,7 +1259,7 @@ f(Mapping({"abcG" : Mapping({u"\0" : 1})})):TypeError:('expected string without f(Mapping({"abcG" : Mapping({"\0" : 1})})):TypeError:('expected string without null bytes',) <<< Finished >>> Testing *Iter* using f(Mapping({"abcG" : %s})) -f(Mapping({"abcG" : FailingIter()})):TypeError:('unable to convert FailingIter to vim structure',) +f(Mapping({"abcG" : FailingIter()})):TypeError:('unable to convert FailingIter to a Vim structure',) f(Mapping({"abcG" : FailingIterNext()})):NotImplementedError:('next',) <<< Finished >>> Testing ConvertFromPyObject using f(Mapping({"abcG" : %s})) @@ -1271,7 +1271,7 @@ f(Mapping({"abcG" : FailingMappingKey()})):NotImplementedError:('getitem:mapping f(Mapping({"abcG" : FailingNumber()})):TypeError:('long() argument must be a string or a number',) <<< Finished >>> Testing *Iter* using f(%s) -f(FailingIter()):TypeError:('unable to convert FailingIter to vim structure',) +f(FailingIter()):TypeError:('unable to convert FailingIter to a Vim structure',) f(FailingIterNext()):NotImplementedError:('next',) <<< Finished >>> Testing ConvertFromPyObject using f(%s) @@ -1298,7 +1298,7 @@ fd(self={"abcF" : Mapping({u"\0" : 1})}):TypeError:('expected string without nul fd(self={"abcF" : Mapping({"\0" : 1})}):TypeError:('expected string without null bytes',) <<< Finished >>> Testing *Iter* using fd(self={"abcF" : %s}) -fd(self={"abcF" : FailingIter()}):TypeError:('unable to convert FailingIter to vim structure',) +fd(self={"abcF" : FailingIter()}):TypeError:('unable to convert FailingIter to a Vim structure',) fd(self={"abcF" : FailingIterNext()}):NotImplementedError:('next',) <<< Finished >>> Testing ConvertFromPyObject using fd(self={"abcF" : %s}) @@ -1325,7 +1325,7 @@ fd(self=Mapping({"abcG" : Mapping({u"\0" : 1})})):TypeError:('expected string wi fd(self=Mapping({"abcG" : Mapping({"\0" : 1})})):TypeError:('expected string without null bytes',) <<< Finished >>> Testing *Iter* using fd(self=Mapping({"abcG" : %s})) -fd(self=Mapping({"abcG" : FailingIter()})):TypeError:('unable to convert FailingIter to vim structure',) +fd(self=Mapping({"abcG" : FailingIter()})):TypeError:('unable to convert FailingIter to a Vim structure',) fd(self=Mapping({"abcG" : FailingIterNext()})):NotImplementedError:('next',) <<< Finished >>> Testing ConvertFromPyObject using fd(self=Mapping({"abcG" : %s})) @@ -1337,19 +1337,19 @@ fd(self=Mapping({"abcG" : FailingMappingKey()})):NotImplementedError:('getitem:m fd(self=Mapping({"abcG" : FailingNumber()})):TypeError:('long() argument must be a string or a number',) <<< Finished >>> Testing *Iter* using fd(self=%s) -fd(self=FailingIter()):TypeError:('unable to convert FailingIter to vim dictionary',) -fd(self=FailingIterNext()):TypeError:('unable to convert FailingIterNext to vim dictionary',) +fd(self=FailingIter()):TypeError:('unable to convert FailingIter to a Vim dictionary',) +fd(self=FailingIterNext()):TypeError:('unable to convert FailingIterNext to a Vim dictionary',) <<< Finished >>> Testing ConvertFromPyObject using fd(self=%s) -fd(self=None):TypeError:('unable to convert NoneType to vim dictionary',) +fd(self=None):TypeError:('unable to convert NoneType to a Vim dictionary',) fd(self={"": 1}):ValueError:('empty keys are not allowed',) fd(self={u"": 1}):ValueError:('empty keys are not allowed',) fd(self=FailingMapping()):NotImplementedError:('keys',) fd(self=FailingMappingKey()):NotImplementedError:('getitem:mappingkey',) -fd(self=FailingNumber()):TypeError:('unable to convert FailingNumber to vim dictionary',) +fd(self=FailingNumber()):TypeError:('unable to convert FailingNumber to a Vim dictionary',) <<< Finished >>> Testing ConvertFromPyMapping using fd(self=%s) -fd(self=[]):TypeError:('unable to convert list to vim dictionary',) +fd(self=[]):TypeError:('unable to convert list to a Vim dictionary',) <<< Finished > TabPage >> TabPageAttr diff --git a/src/testdir/test87.ok b/src/testdir/test87.ok index 7ddea8f26e..c42acdf386 100644 --- a/src/testdir/test87.ok +++ b/src/testdir/test87.ok @@ -764,7 +764,7 @@ d["a"] = {"abcF" : Mapping({b"\0" : 1})}:(<class 'TypeError'>, TypeError('expect d["a"] = {"abcF" : Mapping({"\0" : 1})}:(<class 'TypeError'>, TypeError('expected bytes with no null',)) <<< Finished >>> Testing *Iter* using d["a"] = {"abcF" : %s} -d["a"] = {"abcF" : FailingIter()}:(<class 'TypeError'>, TypeError('unable to convert FailingIter to vim structure',)) +d["a"] = {"abcF" : FailingIter()}:(<class 'TypeError'>, TypeError('unable to convert FailingIter to a Vim structure',)) d["a"] = {"abcF" : FailingIterNext()}:(<class 'NotImplementedError'>, NotImplementedError('next',)) <<< Finished >>> Testing ConvertFromPyObject using d["a"] = {"abcF" : %s} @@ -791,7 +791,7 @@ d["a"] = Mapping({"abcG" : Mapping({b"\0" : 1})}):(<class 'TypeError'>, TypeErro d["a"] = Mapping({"abcG" : Mapping({"\0" : 1})}):(<class 'TypeError'>, TypeError('expected bytes with no null',)) <<< Finished >>> Testing *Iter* using d["a"] = Mapping({"abcG" : %s}) -d["a"] = Mapping({"abcG" : FailingIter()}):(<class 'TypeError'>, TypeError('unable to convert FailingIter to vim structure',)) +d["a"] = Mapping({"abcG" : FailingIter()}):(<class 'TypeError'>, TypeError('unable to convert FailingIter to a Vim structure',)) d["a"] = Mapping({"abcG" : FailingIterNext()}):(<class 'NotImplementedError'>, NotImplementedError('next',)) <<< Finished >>> Testing ConvertFromPyObject using d["a"] = Mapping({"abcG" : %s}) @@ -803,7 +803,7 @@ d["a"] = Mapping({"abcG" : FailingMappingKey()}):(<class 'NotImplementedError'>, d["a"] = Mapping({"abcG" : FailingNumber()}):(<class 'NotImplementedError'>, NotImplementedError('int',)) <<< Finished >>> Testing *Iter* using d["a"] = %s -d["a"] = FailingIter():(<class 'TypeError'>, TypeError('unable to convert FailingIter to vim structure',)) +d["a"] = FailingIter():(<class 'TypeError'>, TypeError('unable to convert FailingIter to a Vim structure',)) d["a"] = FailingIterNext():(<class 'NotImplementedError'>, NotImplementedError('next',)) <<< Finished >>> Testing ConvertFromPyObject using d["a"] = %s @@ -840,7 +840,7 @@ d.update({"abcF" : Mapping({b"\0" : 1})}):(<class 'TypeError'>, TypeError('expec d.update({"abcF" : Mapping({"\0" : 1})}):(<class 'TypeError'>, TypeError('expected bytes with no null',)) <<< Finished >>> Testing *Iter* using d.update({"abcF" : %s}) -d.update({"abcF" : FailingIter()}):(<class 'TypeError'>, TypeError('unable to convert FailingIter to vim structure',)) +d.update({"abcF" : FailingIter()}):(<class 'TypeError'>, TypeError('unable to convert FailingIter to a Vim structure',)) d.update({"abcF" : FailingIterNext()}):(<class 'NotImplementedError'>, NotImplementedError('next',)) <<< Finished >>> Testing ConvertFromPyObject using d.update({"abcF" : %s}) @@ -867,7 +867,7 @@ d.update(Mapping({"abcG" : Mapping({b"\0" : 1})})):(<class 'TypeError'>, TypeErr d.update(Mapping({"abcG" : Mapping({"\0" : 1})})):(<class 'TypeError'>, TypeError('expected bytes with no null',)) <<< Finished >>> Testing *Iter* using d.update(Mapping({"abcG" : %s})) -d.update(Mapping({"abcG" : FailingIter()})):(<class 'TypeError'>, TypeError('unable to convert FailingIter to vim structure',)) +d.update(Mapping({"abcG" : FailingIter()})):(<class 'TypeError'>, TypeError('unable to convert FailingIter to a Vim structure',)) d.update(Mapping({"abcG" : FailingIterNext()})):(<class 'NotImplementedError'>, NotImplementedError('next',)) <<< Finished >>> Testing ConvertFromPyObject using d.update(Mapping({"abcG" : %s})) @@ -911,7 +911,7 @@ d.update((("a", {"abcF" : Mapping({b"\0" : 1})}),)):(<class 'TypeError'>, TypeEr d.update((("a", {"abcF" : Mapping({"\0" : 1})}),)):(<class 'TypeError'>, TypeError('expected bytes with no null',)) <<< Finished >>> Testing *Iter* using d.update((("a", {"abcF" : %s}),)) -d.update((("a", {"abcF" : FailingIter()}),)):(<class 'TypeError'>, TypeError('unable to convert FailingIter to vim structure',)) +d.update((("a", {"abcF" : FailingIter()}),)):(<class 'TypeError'>, TypeError('unable to convert FailingIter to a Vim structure',)) d.update((("a", {"abcF" : FailingIterNext()}),)):(<class 'NotImplementedError'>, NotImplementedError('next',)) <<< Finished >>> Testing ConvertFromPyObject using d.update((("a", {"abcF" : %s}),)) @@ -938,7 +938,7 @@ d.update((("a", Mapping({"abcG" : Mapping({b"\0" : 1})})),)):(<class 'TypeError' d.update((("a", Mapping({"abcG" : Mapping({"\0" : 1})})),)):(<class 'TypeError'>, TypeError('expected bytes with no null',)) <<< Finished >>> Testing *Iter* using d.update((("a", Mapping({"abcG" : %s})),)) -d.update((("a", Mapping({"abcG" : FailingIter()})),)):(<class 'TypeError'>, TypeError('unable to convert FailingIter to vim structure',)) +d.update((("a", Mapping({"abcG" : FailingIter()})),)):(<class 'TypeError'>, TypeError('unable to convert FailingIter to a Vim structure',)) d.update((("a", Mapping({"abcG" : FailingIterNext()})),)):(<class 'NotImplementedError'>, NotImplementedError('next',)) <<< Finished >>> Testing ConvertFromPyObject using d.update((("a", Mapping({"abcG" : %s})),)) @@ -950,7 +950,7 @@ d.update((("a", Mapping({"abcG" : FailingMappingKey()})),)):(<class 'NotImplemen d.update((("a", Mapping({"abcG" : FailingNumber()})),)):(<class 'NotImplementedError'>, NotImplementedError('int',)) <<< Finished >>> Testing *Iter* using d.update((("a", %s),)) -d.update((("a", FailingIter()),)):(<class 'TypeError'>, TypeError('unable to convert FailingIter to vim structure',)) +d.update((("a", FailingIter()),)):(<class 'TypeError'>, TypeError('unable to convert FailingIter to a Vim structure',)) d.update((("a", FailingIterNext()),)):(<class 'NotImplementedError'>, NotImplementedError('next',)) <<< Finished >>> Testing ConvertFromPyObject using d.update((("a", %s),)) @@ -989,7 +989,7 @@ vim.List([{"abcF" : Mapping({b"\0" : 1})}]):(<class 'TypeError'>, TypeError('exp vim.List([{"abcF" : Mapping({"\0" : 1})}]):(<class 'TypeError'>, TypeError('expected bytes with no null',)) <<< Finished >>> Testing *Iter* using vim.List([{"abcF" : %s}]) -vim.List([{"abcF" : FailingIter()}]):(<class 'TypeError'>, TypeError('unable to convert FailingIter to vim structure',)) +vim.List([{"abcF" : FailingIter()}]):(<class 'TypeError'>, TypeError('unable to convert FailingIter to a Vim structure',)) vim.List([{"abcF" : FailingIterNext()}]):(<class 'NotImplementedError'>, NotImplementedError('next',)) <<< Finished >>> Testing ConvertFromPyObject using vim.List([{"abcF" : %s}]) @@ -1016,7 +1016,7 @@ vim.List([Mapping({"abcG" : Mapping({b"\0" : 1})})]):(<class 'TypeError'>, TypeE vim.List([Mapping({"abcG" : Mapping({"\0" : 1})})]):(<class 'TypeError'>, TypeError('expected bytes with no null',)) <<< Finished >>> Testing *Iter* using vim.List([Mapping({"abcG" : %s})]) -vim.List([Mapping({"abcG" : FailingIter()})]):(<class 'TypeError'>, TypeError('unable to convert FailingIter to vim structure',)) +vim.List([Mapping({"abcG" : FailingIter()})]):(<class 'TypeError'>, TypeError('unable to convert FailingIter to a Vim structure',)) vim.List([Mapping({"abcG" : FailingIterNext()})]):(<class 'NotImplementedError'>, NotImplementedError('next',)) <<< Finished >>> Testing ConvertFromPyObject using vim.List([Mapping({"abcG" : %s})]) @@ -1028,7 +1028,7 @@ vim.List([Mapping({"abcG" : FailingMappingKey()})]):(<class 'NotImplementedError vim.List([Mapping({"abcG" : FailingNumber()})]):(<class 'NotImplementedError'>, NotImplementedError('int',)) <<< Finished >>> Testing *Iter* using vim.List([%s]) -vim.List([FailingIter()]):(<class 'TypeError'>, TypeError('unable to convert FailingIter to vim structure',)) +vim.List([FailingIter()]):(<class 'TypeError'>, TypeError('unable to convert FailingIter to a Vim structure',)) vim.List([FailingIterNext()]):(<class 'NotImplementedError'>, NotImplementedError('next',)) <<< Finished >>> Testing ConvertFromPyObject using vim.List([%s]) @@ -1074,7 +1074,7 @@ l[:] = [{"abcF" : Mapping({b"\0" : 1})}]:(<class 'TypeError'>, TypeError('expect l[:] = [{"abcF" : Mapping({"\0" : 1})}]:(<class 'TypeError'>, TypeError('expected bytes with no null',)) <<< Finished >>> Testing *Iter* using l[:] = [{"abcF" : %s}] -l[:] = [{"abcF" : FailingIter()}]:(<class 'TypeError'>, TypeError('unable to convert FailingIter to vim structure',)) +l[:] = [{"abcF" : FailingIter()}]:(<class 'TypeError'>, TypeError('unable to convert FailingIter to a Vim structure',)) l[:] = [{"abcF" : FailingIterNext()}]:(<class 'NotImplementedError'>, NotImplementedError('next',)) <<< Finished >>> Testing ConvertFromPyObject using l[:] = [{"abcF" : %s}] @@ -1101,7 +1101,7 @@ l[:] = [Mapping({"abcG" : Mapping({b"\0" : 1})})]:(<class 'TypeError'>, TypeErro l[:] = [Mapping({"abcG" : Mapping({"\0" : 1})})]:(<class 'TypeError'>, TypeError('expected bytes with no null',)) <<< Finished >>> Testing *Iter* using l[:] = [Mapping({"abcG" : %s})] -l[:] = [Mapping({"abcG" : FailingIter()})]:(<class 'TypeError'>, TypeError('unable to convert FailingIter to vim structure',)) +l[:] = [Mapping({"abcG" : FailingIter()})]:(<class 'TypeError'>, TypeError('unable to convert FailingIter to a Vim structure',)) l[:] = [Mapping({"abcG" : FailingIterNext()})]:(<class 'NotImplementedError'>, NotImplementedError('next',)) <<< Finished >>> Testing ConvertFromPyObject using l[:] = [Mapping({"abcG" : %s})] @@ -1113,7 +1113,7 @@ l[:] = [Mapping({"abcG" : FailingMappingKey()})]:(<class 'NotImplementedError'>, l[:] = [Mapping({"abcG" : FailingNumber()})]:(<class 'NotImplementedError'>, NotImplementedError('int',)) <<< Finished >>> Testing *Iter* using l[:] = [%s] -l[:] = [FailingIter()]:(<class 'TypeError'>, TypeError('unable to convert FailingIter to vim structure',)) +l[:] = [FailingIter()]:(<class 'TypeError'>, TypeError('unable to convert FailingIter to a Vim structure',)) l[:] = [FailingIterNext()]:(<class 'NotImplementedError'>, NotImplementedError('next',)) <<< Finished >>> Testing ConvertFromPyObject using l[:] = [%s] @@ -1145,7 +1145,7 @@ l.extend([{"abcF" : Mapping({b"\0" : 1})}]):(<class 'TypeError'>, TypeError('exp l.extend([{"abcF" : Mapping({"\0" : 1})}]):(<class 'TypeError'>, TypeError('expected bytes with no null',)) <<< Finished >>> Testing *Iter* using l.extend([{"abcF" : %s}]) -l.extend([{"abcF" : FailingIter()}]):(<class 'TypeError'>, TypeError('unable to convert FailingIter to vim structure',)) +l.extend([{"abcF" : FailingIter()}]):(<class 'TypeError'>, TypeError('unable to convert FailingIter to a Vim structure',)) l.extend([{"abcF" : FailingIterNext()}]):(<class 'NotImplementedError'>, NotImplementedError('next',)) <<< Finished >>> Testing ConvertFromPyObject using l.extend([{"abcF" : %s}]) @@ -1172,7 +1172,7 @@ l.extend([Mapping({"abcG" : Mapping({b"\0" : 1})})]):(<class 'TypeError'>, TypeE l.extend([Mapping({"abcG" : Mapping({"\0" : 1})})]):(<class 'TypeError'>, TypeError('expected bytes with no null',)) <<< Finished >>> Testing *Iter* using l.extend([Mapping({"abcG" : %s})]) -l.extend([Mapping({"abcG" : FailingIter()})]):(<class 'TypeError'>, TypeError('unable to convert FailingIter to vim structure',)) +l.extend([Mapping({"abcG" : FailingIter()})]):(<class 'TypeError'>, TypeError('unable to convert FailingIter to a Vim structure',)) l.extend([Mapping({"abcG" : FailingIterNext()})]):(<class 'NotImplementedError'>, NotImplementedError('next',)) <<< Finished >>> Testing ConvertFromPyObject using l.extend([Mapping({"abcG" : %s})]) @@ -1184,7 +1184,7 @@ l.extend([Mapping({"abcG" : FailingMappingKey()})]):(<class 'NotImplementedError l.extend([Mapping({"abcG" : FailingNumber()})]):(<class 'NotImplementedError'>, NotImplementedError('int',)) <<< Finished >>> Testing *Iter* using l.extend([%s]) -l.extend([FailingIter()]):(<class 'TypeError'>, TypeError('unable to convert FailingIter to vim structure',)) +l.extend([FailingIter()]):(<class 'TypeError'>, TypeError('unable to convert FailingIter to a Vim structure',)) l.extend([FailingIterNext()]):(<class 'NotImplementedError'>, NotImplementedError('next',)) <<< Finished >>> Testing ConvertFromPyObject using l.extend([%s]) @@ -1210,7 +1210,7 @@ vim.Function("xxx_non_existent_function_xxx3", self={}):(<class 'ValueError'>, V vim.Function("xxx_non_existent_function_xxx4", args=[], self={}):(<class 'ValueError'>, ValueError('function xxx_non_existent_function_xxx4 does not exist',)) >>> FunctionNew vim.Function("tr", self="abcFuncSelf"):(<class 'AttributeError'>, AttributeError('keys',)) -vim.Function("tr", args=427423):(<class 'TypeError'>, TypeError('unable to convert int to vim list',)) +vim.Function("tr", args=427423):(<class 'TypeError'>, TypeError('unable to convert int to a Vim list',)) vim.Function("tr", self="abcFuncSelf2", args="abcFuncArgs2"):(<class 'AttributeError'>, AttributeError('keys',)) vim.Function(self="abcFuncSelf2", args="abcFuncArgs2"):(<class 'AttributeError'>, AttributeError('keys',)) vim.Function("tr", "", self="abcFuncSelf2", args="abcFuncArgs2"):(<class 'AttributeError'>, AttributeError('keys',)) @@ -1232,7 +1232,7 @@ f({"abcF" : Mapping({b"\0" : 1})}):(<class 'TypeError'>, TypeError('expected byt f({"abcF" : Mapping({"\0" : 1})}):(<class 'TypeError'>, TypeError('expected bytes with no null',)) <<< Finished >>> Testing *Iter* using f({"abcF" : %s}) -f({"abcF" : FailingIter()}):(<class 'TypeError'>, TypeError('unable to convert FailingIter to vim structure',)) +f({"abcF" : FailingIter()}):(<class 'TypeError'>, TypeError('unable to convert FailingIter to a Vim structure',)) f({"abcF" : FailingIterNext()}):(<class 'NotImplementedError'>, NotImplementedError('next',)) <<< Finished >>> Testing ConvertFromPyObject using f({"abcF" : %s}) @@ -1259,7 +1259,7 @@ f(Mapping({"abcG" : Mapping({b"\0" : 1})})):(<class 'TypeError'>, TypeError('exp f(Mapping({"abcG" : Mapping({"\0" : 1})})):(<class 'TypeError'>, TypeError('expected bytes with no null',)) <<< Finished >>> Testing *Iter* using f(Mapping({"abcG" : %s})) -f(Mapping({"abcG" : FailingIter()})):(<class 'TypeError'>, TypeError('unable to convert FailingIter to vim structure',)) +f(Mapping({"abcG" : FailingIter()})):(<class 'TypeError'>, TypeError('unable to convert FailingIter to a Vim structure',)) f(Mapping({"abcG" : FailingIterNext()})):(<class 'NotImplementedError'>, NotImplementedError('next',)) <<< Finished >>> Testing ConvertFromPyObject using f(Mapping({"abcG" : %s})) @@ -1271,7 +1271,7 @@ f(Mapping({"abcG" : FailingMappingKey()})):(<class 'NotImplementedError'>, NotIm f(Mapping({"abcG" : FailingNumber()})):(<class 'NotImplementedError'>, NotImplementedError('int',)) <<< Finished >>> Testing *Iter* using f(%s) -f(FailingIter()):(<class 'TypeError'>, TypeError('unable to convert FailingIter to vim structure',)) +f(FailingIter()):(<class 'TypeError'>, TypeError('unable to convert FailingIter to a Vim structure',)) f(FailingIterNext()):(<class 'NotImplementedError'>, NotImplementedError('next',)) <<< Finished >>> Testing ConvertFromPyObject using f(%s) @@ -1298,7 +1298,7 @@ fd(self={"abcF" : Mapping({b"\0" : 1})}):(<class 'TypeError'>, TypeError('expect fd(self={"abcF" : Mapping({"\0" : 1})}):(<class 'TypeError'>, TypeError('expected bytes with no null',)) <<< Finished >>> Testing *Iter* using fd(self={"abcF" : %s}) -fd(self={"abcF" : FailingIter()}):(<class 'TypeError'>, TypeError('unable to convert FailingIter to vim structure',)) +fd(self={"abcF" : FailingIter()}):(<class 'TypeError'>, TypeError('unable to convert FailingIter to a Vim structure',)) fd(self={"abcF" : FailingIterNext()}):(<class 'NotImplementedError'>, NotImplementedError('next',)) <<< Finished >>> Testing ConvertFromPyObject using fd(self={"abcF" : %s}) @@ -1325,7 +1325,7 @@ fd(self=Mapping({"abcG" : Mapping({b"\0" : 1})})):(<class 'TypeError'>, TypeErro fd(self=Mapping({"abcG" : Mapping({"\0" : 1})})):(<class 'TypeError'>, TypeError('expected bytes with no null',)) <<< Finished >>> Testing *Iter* using fd(self=Mapping({"abcG" : %s})) -fd(self=Mapping({"abcG" : FailingIter()})):(<class 'TypeError'>, TypeError('unable to convert FailingIter to vim structure',)) +fd(self=Mapping({"abcG" : FailingIter()})):(<class 'TypeError'>, TypeError('unable to convert FailingIter to a Vim structure',)) fd(self=Mapping({"abcG" : FailingIterNext()})):(<class 'NotImplementedError'>, NotImplementedError('next',)) <<< Finished >>> Testing ConvertFromPyObject using fd(self=Mapping({"abcG" : %s})) @@ -1337,16 +1337,16 @@ fd(self=Mapping({"abcG" : FailingMappingKey()})):(<class 'NotImplementedError'>, fd(self=Mapping({"abcG" : FailingNumber()})):(<class 'NotImplementedError'>, NotImplementedError('int',)) <<< Finished >>> Testing *Iter* using fd(self=%s) -fd(self=FailingIter()):(<class 'TypeError'>, TypeError('unable to convert FailingIter to vim dictionary',)) -fd(self=FailingIterNext()):(<class 'TypeError'>, TypeError('unable to convert FailingIterNext to vim dictionary',)) +fd(self=FailingIter()):(<class 'TypeError'>, TypeError('unable to convert FailingIter to a Vim dictionary',)) +fd(self=FailingIterNext()):(<class 'TypeError'>, TypeError('unable to convert FailingIterNext to a Vim dictionary',)) <<< Finished >>> Testing ConvertFromPyObject using fd(self=%s) -fd(self=None):(<class 'TypeError'>, TypeError('unable to convert NoneType to vim dictionary',)) +fd(self=None):(<class 'TypeError'>, TypeError('unable to convert NoneType to a Vim dictionary',)) fd(self={b"": 1}):(<class 'ValueError'>, ValueError('empty keys are not allowed',)) fd(self={"": 1}):(<class 'ValueError'>, ValueError('empty keys are not allowed',)) fd(self=FailingMapping()):(<class 'NotImplementedError'>, NotImplementedError('keys',)) fd(self=FailingMappingKey()):(<class 'NotImplementedError'>, NotImplementedError('getitem:mappingkey',)) -fd(self=FailingNumber()):(<class 'TypeError'>, TypeError('unable to convert FailingNumber to vim dictionary',)) +fd(self=FailingNumber()):(<class 'TypeError'>, TypeError('unable to convert FailingNumber to a Vim dictionary',)) <<< Finished >>> Testing ConvertFromPyMapping using fd(self=%s) fd(self=[]):(<class 'AttributeError'>, AttributeError('keys',)) diff --git a/src/version.c b/src/version.c index a31cdabb52..f71d1c4fb3 100644 --- a/src/version.c +++ b/src/version.c @@ -746,6 +746,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 741, /**/ 740, /**/ From 48a687148c4649f6f55b36a1f4111041e7207235 Mon Sep 17 00:00:00 2001 From: Bram Moolenaar <Bram@vim.org> Date: Tue, 12 May 2020 14:42:02 +0200 Subject: [PATCH 138/230] patch 8.2.0742: handling of a TERM signal not tested Problem: Handling of a TERM signal not tested. Solution: Add a test for SIGTERM. (Dominique Pelle, closes #6055) --- src/testdir/test_signals.vim | 46 ++++++++++++++++++++++++++++++++++++ src/version.c | 2 ++ 2 files changed, 48 insertions(+) diff --git a/src/testdir/test_signals.vim b/src/testdir/test_signals.vim index 7a2be899f6..cb84f5e1aa 100644 --- a/src/testdir/test_signals.vim +++ b/src/testdir/test_signals.vim @@ -106,3 +106,49 @@ func Test_signal_INT() call StopVimInTerminal(buf) endfunc + +" Test a deadly signal. +" +" There are several deadly signals: SISEGV, SIBUS, SIGTERM... +" Test uses signal SIGTERM as it does not create a core +" dump file unlike SIGSEGV, SIGBUS, etc. See "man 7 signals. +" +" Vim should exit with a deadly signal and unsaved changes +" should be recoverable from the swap file preserved as a +" result of the deadly signal handler. +func Test_deadly_signal_TERM() + if !HasSignal('TERM') + throw 'Skipped: TERM signal not supported' + endif + if !CanRunVimInTerminal() + throw 'Skipped: cannot run vim in terminal' + endif + let cmd = GetVimCommand() + if cmd =~ 'valgrind' + throw 'Skipped: cannot test signal TERM with valgrind' + endif + + let buf = RunVimInTerminal('Xsig_TERM', {'rows': 6}) + let pid_vim = term_getjob(buf)->job_info().process + + call term_sendkeys(buf, ":call setline(1, 'foo')\n") + call WaitForAssert({-> assert_equal('foo', term_getline(buf, 1))}) + + call assert_false(filereadable('Xsig_TERM')) + exe 'silent !kill -s TERM ' .. pid_vim + call WaitForAssert({-> assert_equal('Vim: Caught deadly signal TERM', term_getline(buf, 1))}) + call WaitForAssert({-> assert_match('Vim: preserving files\.\.\.$', term_getline(buf, 2))}) + call WaitForAssert({-> assert_true(filereadable('.Xsig_TERM.swp'))}) + + " Don't call StopVimInTerminal() as it expects job to be still running. + call WaitForAssert({-> assert_equal("finished", term_getstatus(buf))}) + + new + silent recover .Xsig_TERM.swp + call assert_equal(['foo'], getline(1, '$')) + + %bwipe! + call delete('.Xsig_TERM.swp') +endfunc + +" vim: ts=8 sw=2 sts=2 tw=80 fdm=marker diff --git a/src/version.c b/src/version.c index f71d1c4fb3..41f857f638 100644 --- a/src/version.c +++ b/src/version.c @@ -746,6 +746,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 742, /**/ 741, /**/ From 5aed0ccb965dbad4b60f4c77c9c4455a9379e73c Mon Sep 17 00:00:00 2001 From: Bram Moolenaar <Bram@vim.org> Date: Tue, 12 May 2020 22:02:21 +0200 Subject: [PATCH 139/230] patch 8.2.0743: can move to another buffer from a terminal in popup window Problem: Can move to another buffer from a terminal in popup window. Solution: Do not allow "gf" or editing a file. (closes #6072) --- src/ex_cmds.c | 5 +++++ src/normal.c | 4 ++++ src/testdir/test_popupwin.vim | 8 ++++++++ src/version.c | 2 ++ 4 files changed, 19 insertions(+) diff --git a/src/ex_cmds.c b/src/ex_cmds.c index f38bdacb63..9c55de3adf 100644 --- a/src/ex_cmds.c +++ b/src/ex_cmds.c @@ -2484,6 +2484,11 @@ do_ecmd( int did_inc_redrawing_disabled = FALSE; long *so_ptr = curwin->w_p_so >= 0 ? &curwin->w_p_so : &p_so; +#ifdef FEAT_PROP_POPUP + if (ERROR_IF_TERM_POPUP_WINDOW) + return FAIL; +#endif + if (eap != NULL) command = eap->do_ecmd_cmd; set_bufref(&old_curbuf, curbuf); diff --git a/src/normal.c b/src/normal.c index 7dd74a40bf..690bb00819 100644 --- a/src/normal.c +++ b/src/normal.c @@ -4169,6 +4169,10 @@ nv_gotofile(cmdarg_T *cap) clearop(cap->oap); return; } +#ifdef FEAT_PROP_POPUP + if (ERROR_IF_TERM_POPUP_WINDOW) + return; +#endif ptr = grab_file_name(cap->count1, &lnum); diff --git a/src/testdir/test_popupwin.vim b/src/testdir/test_popupwin.vim index 99b4458250..5eecb193c1 100644 --- a/src/testdir/test_popupwin.vim +++ b/src/testdir/test_popupwin.vim @@ -2425,8 +2425,16 @@ func Test_popupwin_terminal_buffer() call assert_equal(winnr(), winnr('k')) call assert_equal(winnr(), winnr('h')) call assert_equal(winnr(), winnr('l')) + " Cannot quit while job is running call assert_fails('call feedkeys("\<C-W>:quit\<CR>", "xt")', 'E948:') + + " Cannot enter Terminal-Normal mode. + call feedkeys("xxx\<C-W>N", 'xt') + call assert_fails('call feedkeys("gf", "xt")', 'E863:') + call feedkeys("a\<C-U>", 'xt') + + " Exiting shell closes popup window call feedkeys("exit\<CR>", 'xt') " Wait for shell to exit sleep 100m diff --git a/src/version.c b/src/version.c index 41f857f638..1ce64b7627 100644 --- a/src/version.c +++ b/src/version.c @@ -746,6 +746,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 743, /**/ 742, /**/ From 9e6ba8cbef2b2363f1d0a0e2c2a8d21c3b987416 Mon Sep 17 00:00:00 2001 From: Bram Moolenaar <Bram@vim.org> Date: Tue, 12 May 2020 22:21:26 +0200 Subject: [PATCH 140/230] patch 8.2.0744: the name vim is not capatilized in a message Problem: The name vim is not capatilized in a message. Solution: Use "Vim" instead of "vim". --- src/main.c | 2 +- src/version.c | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/src/main.c b/src/main.c index a1e933cc50..b00d7b987f 100644 --- a/src/main.c +++ b/src/main.c @@ -3600,7 +3600,7 @@ usage(void) # endif # endif main_msg(_("-display <display>\tRun Vim on <display>")); - main_msg(_("-iconic\t\tStart vim iconified")); + main_msg(_("-iconic\t\tStart Vim iconified")); main_msg(_("-background <color>\tUse <color> for the background (also: -bg)")); main_msg(_("-foreground <color>\tUse <color> for normal text (also: -fg)")); main_msg(_("-font <font>\t\tUse <font> for normal text (also: -fn)")); diff --git a/src/version.c b/src/version.c index 1ce64b7627..bd5337bca7 100644 --- a/src/version.c +++ b/src/version.c @@ -746,6 +746,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 744, /**/ 743, /**/ From 47e13953ffdbb9f163b901196dec8c2100b72edd Mon Sep 17 00:00:00 2001 From: Bram Moolenaar <Bram@vim.org> Date: Tue, 12 May 2020 22:49:12 +0200 Subject: [PATCH 141/230] Update runtime files --- runtime/doc/editing.txt | 39 +- runtime/doc/index.txt | 8 +- runtime/doc/popup.txt | 3 +- runtime/doc/recover.txt | 14 +- runtime/doc/tags | 1 + runtime/doc/todo.txt | 48 +- runtime/doc/vim9.txt | 29 +- runtime/doc/windows.txt | 19 +- runtime/ftplugin/masm.vim | 19 + runtime/indent/python.vim | 24 +- runtime/plugin/gzip.vim | 6 +- runtime/syntax/gnuplot.vim | 4 +- runtime/syntax/masm.vim | 4 +- runtime/syntax/pamenv.vim | 28 + runtime/syntax/php.vim | 25 +- runtime/syntax/sh.vim | 21 +- src/po/af.po | 16 +- src/po/ca.po | 33 +- src/po/cs.cp1250.po | 18 +- src/po/cs.po | 18 +- src/po/da.po | 31 +- src/po/de.po | 31 +- src/po/eo.po | 27 +- src/po/es.po | 1812 +----------------------------------- src/po/fi.po | 29 +- src/po/fr.po | 23 +- src/po/ga.po | 31 +- src/po/it.po | 33 +- src/po/ja.euc-jp.po | 25 +- src/po/ja.po | 25 +- src/po/ja.sjis.po | 23 +- src/po/ko.UTF-8.po | 23 +- src/po/ko.po | 23 +- src/po/nb.po | 19 +- src/po/nl.po | 3 - src/po/no.po | 19 +- src/po/pl.UTF-8.po | 20 +- src/po/pl.cp1250.po | 20 +- src/po/pl.po | 20 +- src/po/pt_BR.po | 31 +- src/po/ru.cp1251.po | 23 +- src/po/ru.po | 23 +- src/po/sk.cp1250.po | 23 +- src/po/sk.po | 23 +- src/po/sr.po | 31 +- src/po/sv.po | 19 +- src/po/tr.po | 23 +- src/po/uk.cp1251.po | 29 +- src/po/uk.po | 29 +- src/po/vi.po | 18 +- src/po/zh_CN.UTF-8.po | 15 +- src/po/zh_CN.cp936.po | 15 +- src/po/zh_CN.po | 15 +- src/po/zh_TW.UTF-8.po | 12 +- src/po/zh_TW.po | 14 +- 55 files changed, 577 insertions(+), 2380 deletions(-) create mode 100644 runtime/ftplugin/masm.vim create mode 100644 runtime/syntax/pamenv.vim diff --git a/runtime/doc/editing.txt b/runtime/doc/editing.txt index 96bcb9340d..f6e3810d88 100644 --- a/runtime/doc/editing.txt +++ b/runtime/doc/editing.txt @@ -1,4 +1,4 @@ -*editing.txt* For Vim version 8.2. Last change: 2019 Dec 22 +*editing.txt* For Vim version 8.2. Last change: 2020 May 12 VIM REFERENCE MANUAL by Bram Moolenaar @@ -475,6 +475,9 @@ This edits the same file again with 'fileformat' set to "unix". > :w ++enc=latin1 newfile This writes the current buffer to "newfile" in latin1 format. +The message given when writing a file will show "[converted]" when +'fileencoding' or the value specified with ++enc differs from 'encoding'. + There may be several ++opt arguments, separated by white space. They must all appear before any |+cmd| argument. @@ -1079,9 +1082,9 @@ The names can be in upper- or lowercase. *:q* *:quit* :q[uit] Quit the current window. Quit Vim if this is the last - window. This fails when changes have been made and - Vim refuses to |abandon| the current buffer, and when - the last file in the argument list has not been + |edit-window|. This fails when changes have been made + and Vim refuses to |abandon| the current buffer, and + when the last file in the argument list has not been edited. If there are other tab pages and quitting the last window in the current tab page the current tab page is @@ -1107,18 +1110,22 @@ The names can be in upper- or lowercase. |quickfix|). *:wq* -:wq [++opt] Write the current file and quit. Writing fails when - the file is read-only or the buffer does not have a - name. Quitting fails when the last file in the - argument list has not been edited. +:wq [++opt] Write the current file and close the window. If this + was the last |edit-window| Vim quits. + Writing fails when the file is read-only or the buffer + does not have a name. Quitting fails when the last + file in the argument list has not been edited. -:wq! [++opt] Write the current file and quit. Writing fails when - the current buffer does not have a name. +:wq! [++opt] Write the current file and close the window. If this + was the last |edit-window| Vim quits. Writing fails + when the current buffer does not have a name. -:wq [++opt] {file} Write to {file} and quit. Quitting fails when the +:wq [++opt] {file} Write to {file} and close the window. If this was the + last |edit-window| Vim quits. Quitting fails when the last file in the argument list has not been edited. -:wq! [++opt] {file} Write to {file} and quit. +:wq! [++opt] {file} Write to {file} and close the current window. Quit + Vim if this was the last |edit-window|. :[range]wq[!] [++opt] [file] Same as above, but only write the lines in [range]. @@ -1135,10 +1142,10 @@ The names can be in upper- or lowercase. Same as :xit. *ZZ* -ZZ Write current file, if modified, and quit (same as - ":x"). (Note: If there are several windows for the - current file, the file is written if it was modified - and the window is closed). +ZZ Write current file, if modified, and close the current + window (same as ":x"). + If there are several windows for the current file, + only the current window is closed. *ZQ* ZQ Quit without checking for changes (same as ":q!"). diff --git a/runtime/doc/index.txt b/runtime/doc/index.txt index 315a5f3326..78d557f51e 100644 --- a/runtime/doc/index.txt +++ b/runtime/doc/index.txt @@ -1,4 +1,4 @@ -*index.txt* For Vim version 8.2. Last change: 2020 Apr 26 +*index.txt* For Vim version 8.2. Last change: 2020 May 10 VIM REFERENCE MANUAL by Bram Moolenaar @@ -364,8 +364,8 @@ tag char note action in Normal mode ~ register x] |Y| ["x]Y yank N lines [into register x]; synonym for "yy" -|ZZ| ZZ store current file if modified, and exit -|ZQ| ZQ exit current file always +|ZZ| ZZ write if buffer changed and close window +|ZQ| ZQ close window without writing |[| [{char} square bracket command (see |[| below) \ not used |]| ]{char} square bracket command (see |]| below) @@ -1721,7 +1721,7 @@ tag command action ~ |:wqall| :wqa[ll] write all changed buffers and quit Vim |:wundo| :wu[ndo] write undo information to a file |:wviminfo| :wv[iminfo] write to viminfo file -|:xit| :x[it] write if buffer changed and quit window or Vim +|:xit| :x[it] write if buffer changed and close window |:xall| :xa[ll] same as ":wqall" |:xmapclear| :xmapc[lear] remove all mappings for Visual mode |:xmap| :xm[ap] like ":map" but for Visual mode diff --git a/runtime/doc/popup.txt b/runtime/doc/popup.txt index 26435d1ff0..9041f87540 100644 --- a/runtime/doc/popup.txt +++ b/runtime/doc/popup.txt @@ -1,4 +1,4 @@ -*popup.txt* For Vim version 8.2. Last change: 2020 Apr 13 +*popup.txt* For Vim version 8.2. Last change: 2020 May 12 VIM REFERENCE MANUAL by Bram Moolenaar @@ -150,6 +150,7 @@ different: *E863* - When the job ends, the popup window closes. - The popup window can be closed with `popup_close()`, the terminal buffer then becomes hidden. +- It is not possible to enter Terminal-Normal mode. - The default Pmenu color is only used for the border and padding. To change the color of the terminal itself set the Terminal highlight group before creating the terminal. Setting 'wincolor' later can work but requires the diff --git a/runtime/doc/recover.txt b/runtime/doc/recover.txt index 0bab64a295..34f7f18451 100644 --- a/runtime/doc/recover.txt +++ b/runtime/doc/recover.txt @@ -1,4 +1,4 @@ -*recover.txt* For Vim version 8.2. Last change: 2020 Mar 24 +*recover.txt* For Vim version 8.2. Last change: 2020 May 09 VIM REFERENCE MANUAL by Bram Moolenaar @@ -125,12 +125,12 @@ If you want to make sure that your changes are in the swap file use this command: *:pre* *:preserve* *E313* *E314* -:pre[serve] Write all text for all buffers into swap files. The - original file is no longer needed for recovery. - This sets a flag in the current buffer. When the '&' - flag is present in 'cpoptions' the swap file will not - be deleted for this buffer when Vim exits and the - buffer is still loaded |cpo-&|. +:pre[serve] Write all text for the current buffer into its swap + file. The original file is no longer needed for + recovery. This sets a flag in the current buffer. + When the '&' flag is present in 'cpoptions' the swap + file will not be deleted for this buffer when Vim + exits and the buffer is still loaded |cpo-&|. A Vim swap file can be recognized by the first six characters: "b0VIM ". After that comes the version number, e.g., "3.0". diff --git a/runtime/doc/tags b/runtime/doc/tags index e8d7d25a39..18e88f5708 100644 --- a/runtime/doc/tags +++ b/runtime/doc/tags @@ -6127,6 +6127,7 @@ edit-files editing.txt /*edit-files* edit-intro editing.txt /*edit-intro* edit-no-break usr_25.txt /*edit-no-break* edit-paragraph-join usr_25.txt /*edit-paragraph-join* +edit-window windows.txt /*edit-window* editing.txt editing.txt /*editing.txt* efm-%> quickfix.txt /*efm-%>* efm-entries quickfix.txt /*efm-entries* diff --git a/runtime/doc/todo.txt b/runtime/doc/todo.txt index 7bc39456d9..acc55fe337 100644 --- a/runtime/doc/todo.txt +++ b/runtime/doc/todo.txt @@ -1,4 +1,4 @@ -*todo.txt* For Vim version 8.2. Last change: 2020 May 07 +*todo.txt* For Vim version 8.2. Last change: 2020 May 11 VIM REFERENCE MANUAL by Bram Moolenaar @@ -38,23 +38,22 @@ browser use: https://github.com/vim/vim/issues/1234 *known-bugs* -------------------- Known bugs and current work ----------------------- +Patch to test TERM signal. (Dominique, #6055) + +Include src/po/vim.pot + Vim9 script: -Big changes, may need design: -- Make closures work: +Make closures work: - call closure from not compiled context - Create closure in a loop. Need to make a list of them. -- Having constant expr evaluation separate does not scale. - First parse the expression, then simplify, then generate code. -- At the vim9 script level: Allow using a function that is defined later. - Requires compiling functions only when the whole script has been sourced. - Like Javascript "hoisting", but only at the script level: - 0. If script was sourced before, clear all script-local functions and - variables. (variables still to be implemented) - 1. Discovery phase: Read the file to find all functions, variable - declarations and imports If a variable has a constant expression we get - the type, otherwise it will be "any". Follow imports recursively. - 2. Compilation phase: compile :def function bodies, using declared types - 3. Execution phase: Execute imports when encountered. (skip over functions) +Forward declarations: + - Cleanup when sourcing a script again: all script-local variables, imports + and functions are deleted. + - make sure only constants in declarations are executed, no function calls. + - Declare a variable at script level without an assignment. + let var: string + Error without a type or assignment + let var # error! Making everything work: - Test that a script-local function in Vim9 script cannot be deleted. - Test that a function defined inside a :def function is local to that @@ -62,7 +61,13 @@ Making everything work: defined. - Check that when using a user function name without prefix, it does not find a global function. Prefixing g: is required. -- Compile let [var, var] = expr +- Compile: let [var, var] = expr +- Compile: for [key, value] in items(map) +- Assignment to dict doesn't work: + let ret: dict<string> = #{} + ret[i] = string(i) +- Appending to dict item doesn't work: + let d[i] ..= value - Compile replacement of :s command: s/pat/\=expr/ - Compile redir to local variable: var_redir_start(). - Compile builtin functions that access local variables: @@ -79,6 +84,7 @@ Making everything work: - expandcmd() with `=expr` in filename uses legacy expression. - eval_expr() in ex_cexpr() - eval_expr() call in dbg_parsearg() and debuggy_find() +- Make "true" and "false" work in vim9script New syntax and functionality: Improve error checking: - "echo Func()" is an error if Func() does not return anything. @@ -254,14 +260,14 @@ Patch for the Haiku port: #5961 Patch to add Turkish manual. (Emir Sarı, #5641) +Patch to add lua sleep function. (Prabir Shrestha, #6057) +Alternative: use vim.call and vim.fn: #6063 + Patch to add getmarklist() (Yegappan, #6032) Patch to support different color for undercurl in cterm. (Timur Celik, #6011) -When SIGTSTP is ignored, don't let CTRL-Z suspend Vim? (Kurtis Rader, #5990) -Fixed by patch #6026. Makes tests fail... - Patch to support cindent option to handle pragmas differently. (Max Rumpf, #5468) @@ -294,6 +300,10 @@ Patch to delete BeOS code. (#5817) Anyone who wants to keep it? With bash ":make" does not set v:shell_error. Possible solution: set 'shellpipe' to "2>&1| tee %s; exit ${PIPESTATUS[0]}" #5994 +When changing the crypt key the buffer should be considered modified. +Like when changing 'fileformat'. Save the old key in save_file_ff(). +(Ninu-Ciprian Marginean) + Strange sequence of BufWipeout and BufNew events while doing omni-complete. (Paul Jolly, #5656) Get BufDelete without preceding BufNew. (Paul Jolly, #5694) diff --git a/runtime/doc/vim9.txt b/runtime/doc/vim9.txt index cb880c18f5..3eec280364 100644 --- a/runtime/doc/vim9.txt +++ b/runtime/doc/vim9.txt @@ -1,4 +1,4 @@ -*vim9.txt* For Vim version 8.2. Last change: 2020 May 06 +*vim9.txt* For Vim version 8.2. Last change: 2020 May 09 VIM REFERENCE MANUAL by Bram Moolenaar @@ -134,7 +134,7 @@ Four phases when loading a Vim9 script ~ In legacy script the functions are created when encountered, but parsed only when used. This allows for defining functions in any order and having them -call each other: > +call each other, so long as the function is defined when it is called: > func One() call Two() endfunc @@ -145,22 +145,25 @@ call each other: > endfunc call One() -In Vim9 script the functions are compiled. If using the same functions as the -above example it is not possible to compile function One without knowing that -function Two exists. Or this would require a runtime check, which is slow and -does not allow for compile time type checking. +In Vim9 script the functions are compiled. When using the same functions as +the above example it is not possible to compile function One without knowing +that function Two exists. Or this would require a runtime check, which is slow +and does not allow for compile time type checking. When sourcing a Vim9 script this happens in four phases: 1. Cleanup: If the script was sourced before all script-local variables, imports and functions are deleted. -2. Discovery: The script is read and encountered functions, imports and - variables are recognized. The type is parsed. Variable initializers that - are a constant are evaluated, this can give the type of the variable. +2. Discovery: The script is read and declarations of functions, imports and + variables are recognized and the type is parsed. Variable initializers + that are a constant are evaluated, this can also give the type of the + variable. 3. Compilation: Functions are compiled. The script-local functions, imports - and variables from the discovery phase are recognized and types are - checked. -4. Execution: the commands in the script are executed. Functions are skipped - over. Variable initializers are evaluated, unless they are a constant. + and variables from the discovery phase are found and types are checked. +4. Execution: the commands in the script are executed, top to bottom. + Functions are skipped over, they do do not need to be processed again. + Variable initializers are evaluated when encountered. Note that if a + function called earlier has set the value this will be over-written. It is + best to declare variables before where they are used to avoid confusion. The result is that items defined at the script level can be used anywhere in the script. This allows for putting the main function at the top: > diff --git a/runtime/doc/windows.txt b/runtime/doc/windows.txt index 6129b8d13b..2b01fb359d 100644 --- a/runtime/doc/windows.txt +++ b/runtime/doc/windows.txt @@ -1,4 +1,4 @@ -*windows.txt* For Vim version 8.2. Last change: 2020 Mar 19 +*windows.txt* For Vim version 8.2. Last change: 2020 May 10 VIM REFERENCE MANUAL by Bram Moolenaar @@ -291,9 +291,9 @@ CTRL-W q *CTRL-W_q* CTRL-W CTRL-Q *CTRL-W_CTRL-Q* Without {count}: Quit the current window. If {count} is given quit the {count} window. - - When quitting the last window (not counting a help window), - exit Vim. + *edit-window* + When quitting the last edit window (not counting help or + preview windows), exit Vim. When 'hidden' is set, and there is only one window for the current buffer, it becomes hidden. When 'hidden' is not set, @@ -312,8 +312,9 @@ CTRL-W CTRL-Q *CTRL-W_CTRL-Q* :+quit " quit the next window :+2quit " quit the second next window < - When closing a help window, Vim will try to restore the - previous window layout |:helpclose|. + When closing a help window, and this is not the only window, + Vim will try to restore the previous window layout, see + |:helpclose|. :q[uit]! :{count}q[uit]! @@ -335,9 +336,9 @@ CTRL-W c *CTRL-W_c* *:clo* *:close* changed and the [!] is used, the buffer becomes hidden (unless there is another window editing it). - When there is only one window in the current tab page and - there is another tab page, this closes the current tab page. - |tab-page|. + When there is only one |edit-window| in the current tab page + and there is another tab page, this closes the current tab + page. |tab-page|. This command fails when: *E444* - There is only one window on the screen. diff --git a/runtime/ftplugin/masm.vim b/runtime/ftplugin/masm.vim new file mode 100644 index 0000000000..235469ac32 --- /dev/null +++ b/runtime/ftplugin/masm.vim @@ -0,0 +1,19 @@ +" Vim filetype plugin file +" Language: Microsoft Macro Assembler (80x86) +" Maintainer: Wu Yongwei <wuyongwei@gmail.com> +" Last Change: 2020-05-09 23:02:05 +0800 + +if exists("b:did_ftplugin") + finish +endif +let b:did_ftplugin = 1 + +let s:cpo_save = &cpo +set cpo&vim + +let b:undo_ftplugin = "setl iskeyword<" + +setlocal iskeyword=@,48-57,_,36,60,62,63,@-@ + +let &cpo = s:cpo_save +unlet s:cpo_save diff --git a/runtime/indent/python.vim b/runtime/indent/python.vim index e53987a0de..f9236e63c7 100644 --- a/runtime/indent/python.vim +++ b/runtime/indent/python.vim @@ -28,6 +28,11 @@ set cpo&vim let s:maxoff = 50 " maximum number of lines to look backwards for () +" See if the specified line is already user-dedented from the expected value. +function s:Dedented(lnum, expected) + return indent(a:lnum) <= a:expected - shiftwidth() +endfunction + function GetPythonIndent(lnum) " If this line is explicitly joined: If the previous line was also joined, @@ -158,12 +163,12 @@ function GetPythonIndent(lnum) " If the previous line was a stop-execution statement... if getline(plnum) =~ '^\s*\(break\|continue\|raise\|return\|pass\)\>' " See if the user has already dedented - if indent(a:lnum) > indent(plnum) - shiftwidth() - " If not, recommend one dedent - return indent(plnum) - shiftwidth() + if s:Dedented(a:lnum, indent(plnum)) + " If so, trust the user + return -1 endif - " Otherwise, trust the user - return -1 + " If not, recommend one dedent + return indent(plnum) - shiftwidth() endif " If the current line begins with a keyword that lines up with "try" @@ -191,7 +196,7 @@ function GetPythonIndent(lnum) endif " Or the user has already dedented - if indent(a:lnum) <= plindent - shiftwidth() + if s:Dedented(a:lnum, plindent) return -1 endif @@ -203,7 +208,12 @@ function GetPythonIndent(lnum) " + c) " here if parlnum > 0 - return plindent + " ...unless the user has already dedented + if s:Dedented(a:lnum, plindent) + return -1 + else + return plindent + endif endif return -1 diff --git a/runtime/plugin/gzip.vim b/runtime/plugin/gzip.vim index ffc00f6fd6..7214488579 100644 --- a/runtime/plugin/gzip.vim +++ b/runtime/plugin/gzip.vim @@ -20,7 +20,7 @@ augroup gzip " " Set binary mode before reading the file. " Use "gzip -d", gunzip isn't always available. - autocmd BufReadPre,FileReadPre *.gz,*.bz2,*.Z,*.lzma,*.xz,*.lz,*.zst,*.br setlocal bin + autocmd BufReadPre,FileReadPre *.gz,*.bz2,*.Z,*.lzma,*.xz,*.lz,*.zst,*.br,*.lzo setlocal bin autocmd BufReadPost,FileReadPost *.gz call gzip#read("gzip -dn") autocmd BufReadPost,FileReadPost *.bz2 call gzip#read("bzip2 -d") autocmd BufReadPost,FileReadPost *.Z call gzip#read("uncompress") @@ -29,6 +29,7 @@ augroup gzip autocmd BufReadPost,FileReadPost *.lz call gzip#read("lzip -d") autocmd BufReadPost,FileReadPost *.zst call gzip#read("zstd -d --rm") autocmd BufReadPost,FileReadPost *.br call gzip#read("brotli -d --rm") + autocmd BufReadPost,FileReadPost *.lzo call gzip#read("lzop -d -U") autocmd BufWritePost,FileWritePost *.gz call gzip#write("gzip") autocmd BufWritePost,FileWritePost *.bz2 call gzip#write("bzip2") autocmd BufWritePost,FileWritePost *.Z call gzip#write("compress -f") @@ -37,6 +38,7 @@ augroup gzip autocmd BufWritePost,FileWritePost *.lz call gzip#write("lzip") autocmd BufWritePost,FileWritePost *.zst call gzip#write("zstd --rm") autocmd BufWritePost,FileWritePost *.br call gzip#write("brotli --rm") + autocmd BufWritePost,FileWritePost *.lzo call gzip#write("lzop -U") autocmd FileAppendPre *.gz call gzip#appre("gzip -dn") autocmd FileAppendPre *.bz2 call gzip#appre("bzip2 -d") autocmd FileAppendPre *.Z call gzip#appre("uncompress") @@ -45,6 +47,7 @@ augroup gzip autocmd FileAppendPre *.lz call gzip#appre("lzip -d") autocmd FileAppendPre *.zst call gzip#appre("zstd -d --rm") autocmd FileAppendPre *.br call gzip#appre("brotli -d --rm") + autocmd FileAppendPre *.lzo call gzip#appre("lzop -d -U") autocmd FileAppendPost *.gz call gzip#write("gzip") autocmd FileAppendPost *.bz2 call gzip#write("bzip2") autocmd FileAppendPost *.Z call gzip#write("compress -f") @@ -53,4 +56,5 @@ augroup gzip autocmd FileAppendPost *.lz call gzip#write("lzip") autocmd FileAppendPost *.zst call gzip#write("zstd --rm") autocmd FileAppendPost *.br call gzip#write("brotli --rm") + autocmd FileAppendPost *.lzo call gzip#write("lzop -U") augroup END diff --git a/runtime/syntax/gnuplot.vim b/runtime/syntax/gnuplot.vim index 7777cc9e46..9c98e67e58 100644 --- a/runtime/syntax/gnuplot.vim +++ b/runtime/syntax/gnuplot.vim @@ -3,7 +3,7 @@ " Maintainer: Josh Wainwright <wainwright DOT ja AT gmail DOT com> " Last Maintainer: Andrew Rasmussen andyras@users.sourceforge.net " Original Maintainer: John Hoelzel johnh51@users.sourceforge.net -" Last Change: 2015-08-25 +" Last Change: 2020 May 12 " Filenames: *.gnu *.plt *.gpi *.gih *.gp *.gnuplot scripts: #!*gnuplot " URL: http://www.vim.org/scripts/script.php?script_id=4873 " Original URL: http://johnh51.get.to/vim/syntax/gnuplot.vim @@ -479,7 +479,7 @@ syn keyword gnuplotKeyword terminal palette rgb rbg grb gbr brg bgr " ---- Macros ---- " -syn region gnuplotMacro start="@" end=" " +syn match gnuplotMacro "@[a-zA-Z0-9_]*" " ---- Todos ---- " diff --git a/runtime/syntax/masm.vim b/runtime/syntax/masm.vim index abee78b86d..c3b2a9bd63 100644 --- a/runtime/syntax/masm.vim +++ b/runtime/syntax/masm.vim @@ -2,7 +2,7 @@ " Language: Microsoft Macro Assembler (80x86) " Orig Author: Rob Brady <robb@datatone.com> " Maintainer: Wu Yongwei <wuyongwei@gmail.com> -" Last Change: 2020-05-07 17:04:10 +0800 +" Last Change: 2020-05-09 22:55:38 +0800 " Quit when a syntax file was already loaded if exists("b:current_syntax") @@ -12,7 +12,7 @@ endif let s:cpo_save = &cpo set cpo&vim -setlocal iskeyword=@,48-57,_,36,60,62,63,@-@ +syn iskeyword @,48-57,_,36,60,62,63,@-@ syn case ignore diff --git a/runtime/syntax/pamenv.vim b/runtime/syntax/pamenv.vim new file mode 100644 index 0000000000..90359daa61 --- /dev/null +++ b/runtime/syntax/pamenv.vim @@ -0,0 +1,28 @@ +" Vim syntax file +" Language: pam_env.conf(5) configuration file +" Latest Revision: 2020-05-10 + +if exists("b:current_syntax") + finish +endif + +syn keyword pamenvTodo contained TODO FIXME XXX NOTE +syn region pamenvComment start='^#' end='$' display oneline contains=pamenvTodo,@Spells + +syn match pamenvVars '^[A-Z_][A-Z_0-9]*' nextgroup=pamenvKeywords skipwhite + +syn keyword pamenvKeywords contained DEFAULT OVERRIDE nextgroup=pamenvVarEq + +syn match pamenvVarEq contained '=' nextgroup=pamenvValue,pamenvValueWithQuote + +syn match pamenvValue contained '[^ \t]*' skipwhite nextgroup=pamenvKeywords +syn region pamenvValueWithQuote contained start='"' end='"' skipwhite nextgroup=pamenvKeywords + +hi def link pamenvTodo Todo +hi def link pamenvComment Comment +hi def link pamenvKeywords Keyword +hi def link pamenvVars Identifier +hi def link pamenvValue String +hi def link pamenvValueWithQuote String + +let b:current_syntax = "pamenv" diff --git a/runtime/syntax/php.vim b/runtime/syntax/php.vim index 04036fdf39..720d71e646 100644 --- a/runtime/syntax/php.vim +++ b/runtime/syntax/php.vim @@ -1,9 +1,11 @@ " Vim syntax file " Language: php PHP 3/4/5/7 -" Maintainer: Jason Woofenden <jason@jasonwoof.com> -" Last Change: Oct 19, 2019 -" URL: https://jasonwoof.com/gitweb/?p=vim-syntax.git;a=blob;f=php.vim;hb=HEAD -" Former Maintainers: Peter Hodge <toomuchphp-vim@yahoo.com> +" Maintainer: Tyson Andre <tysonandre775@hotmail.com> +" Last Change: May 11, 2020 +" URL: https://github.com/TysonAndre/vim-syntax +" Former Maintainers: +" Jason Woofenden <jason@jasonwoof.com> +" Peter Hodge <toomuchphp-vim@yahoo.com> " Debian VIM Maintainers <pkg-vim-maintainers@lists.alioth.debian.org> " " Note: If you are using a colour terminal with dark background, you will @@ -91,7 +93,7 @@ if exists( "php_htmlInStrings") syn cluster phpAddStrings add=@htmlTop endif -" make sure we can use \ at the begining of the line to do a continuation +" make sure we can use \ at the beginning of the line to do a continuation let s:cpo_save = &cpo set cpo&vim @@ -314,7 +316,7 @@ syn region phpIdentifierComplexP matchgroup=phpParent start="\[" end="]" contain " define a cluster to get all interpolation syntaxes for double-quoted strings syn cluster phpInterpDouble contains=phpInterpSimple,phpInterpSimpleCurly,phpInterpDollarCurly1,phpInterpDollarCurly2,phpInterpBogusDollarCurley,phpInterpComplex -" Methoden +" Methods syn match phpMethodsVar "->\h\w*" contained contains=phpMethods,phpMemberSelector display " Include @@ -328,14 +330,14 @@ syn keyword phpBoolean true false contained " Float " Refer to: https://www.php.net/manual/en/language.types.float.php -syn match phpFloat "\%(\w\|\.\)\@<!\%(\d\|\.\)*\d\%(\d\|\.\)*\%([eE][+-]\=\%(\d\|\.\)\+\)\=\%(\w\|\.\)\@!" contained contains=phpFloatError display -syn match phpFloatError "[eE.].*\." contained display +syn match phpFloat "\%(\w\|\.\)\@<!\%(\d_\?\|\.\)*\d\%(\d\|_\|\.\)*\%([eE][+-]\=\%(\d\|_\|\.\)\+\)\=\%(\w\|\.\)\@!" contained contains=phpFloatError display +syn match phpFloatError "\%([eE.][0-9._+-]*\.\|__\|_\(\>\|[eE]\)\|\(\>\|[eE]\)_\)" contained display " Number -syn match phpNumber "\%(\.\)\@<!\<\%([1-9]\d*\|0\|0[xX]\x\+\)\>\%(\.\)\@!" contained display +syn match phpNumber "\%(\.\)\@<!\<\%([1-9]\d*\|0\|0[xX]\(\x_\?\)*\x\)\>\%(\.\)\@!" contained display syn match phpNumber "\%(\.\)\@<!\<0\d\+\>\%(\.\)\@!" contained contains=phpOctalError display syn match phpBinaryError "[2-9]" contained display -syn match phpNumber "\%(\.\)\@<!\<0[bB]\d\+\>\%(\.\)\@!" contained contains=phpBinaryError display +syn match phpNumber "\%(\.\)\@<!\<0[bB]\(\d_\?\)*\d\>\%(\.\)\@!" contained contains=phpBinaryError display " Backslash escapes syn case match @@ -442,6 +444,7 @@ if exists("php_folding") && php_folding==1 " match one line constructs here and skip them at folding syn keyword phpSCKeyword abstract final private protected public static contained syn keyword phpFCKeyword function contained + syn keyword phpDefine fn contained syn keyword phpStorageClass global contained syn match phpDefine "\(\s\|^\)\(abstract\s\+\|final\s\+\|private\s\+\|protected\s\+\|public\s\+\|static\s\+\)*function\(\s\+.*[;}]\)\@=" contained contains=phpSCKeyword syn match phpStructure "\(\s\|^\)\(abstract\s\+\|final\s\+\)*\(trait\|class\)\(\s\+.*}\)\@=" contained @@ -459,7 +462,7 @@ if exists("php_folding") && php_folding==1 syn region phpFoldCatch matchgroup=Exception start="^\z(\s*\)catch\s\+\([^}]*$\)\@=" matchgroup=Delimiter end="^\z1}" contains=@phpClFunction,phpFoldFunction contained transparent fold extend syn region phpFoldTry matchgroup=Exception start="^\z(\s*\)try\s\+\([^}]*$\)\@=" matchgroup=Delimiter end="^\z1}" contains=@phpClFunction,phpFoldFunction contained transparent fold extend else - syn keyword phpDefine function contained + syn keyword phpDefine function fn contained syn keyword phpStructure abstract class trait interface contained syn keyword phpException catch throw try finally contained syn keyword phpStorageClass final global private protected public static contained diff --git a/runtime/syntax/sh.vim b/runtime/syntax/sh.vim index 0f4406d3e1..3a2a6e7b0e 100644 --- a/runtime/syntax/sh.vim +++ b/runtime/syntax/sh.vim @@ -2,8 +2,8 @@ " Language: shell (sh) Korn shell (ksh) bash (sh) " Maintainer: Charles E. Campbell <NcampObell@SdrPchip.AorgM-NOSPAM> " Previous Maintainer: Lennart Schultz <Lennart.Schultz@ecmwf.int> -" Last Change: Oct 16, 2019 -" Version: 189 +" Last Change: Apr 14, 2020 +" Version: 190 " URL: http://www.drchip.org/astronaut/vim/index.html#SYNTAX_SH " For options and settings, please use: :help ft-sh-syntax " This file includes many ideas from Eric Brunet (eric.brunet@ens.fr) @@ -357,19 +357,18 @@ elseif !exists("g:sh_no_error") syn region shExDoubleQuote matchGroup=Error start=+\$"+ skip=+\\\\\|\\.+ end=+"+ contains=shStringSpecial endif syn region shSingleQuote matchgroup=shQuote start=+'+ end=+'+ contains=@Spell nextgroup=shSpecialStart,shSpecialSQ -syn region shDoubleQuote matchgroup=shQuote start=+\%(\%(\\\\\)*\\\)\@<!"+ skip=+\\"+ end=+"+ contains=@shDblQuoteList,shStringSpecial,@Spell nextgroup=shSpecialStart -syn region shDoubleQuote matchgroup=shQuote start=+"+ skip=+\\"+ end=+"+ contained contains=@shDblQuoteList,shStringSpecial,@Spell nextgroup=shSpecialStart +syn region shDoubleQuote matchgroup=shQuote start=+\%(\%(\\\\\)*\\\)\@<!"+ skip=+\\.+ end=+"+ contains=@shDblQuoteList,shStringSpecial,@Spell nextgroup=shSpecialStart +syn region shDoubleQuote matchgroup=shQuote start=+"+ matchgroup=shSpecial skip=+\\"+ end=+"+ contained contains=@shDblQuoteList,shStringSpecial,@Spell nextgroup=shSpecialStart syn match shStringSpecial "[^[:print:] \t]" contained syn match shStringSpecial "[^\\]\zs\%(\\\\\)*\\[\\"'`$()#]" nextgroup=shComment -syn match shStringSpecial "[^\\]\zs\%(\\\\\)*\\[\\"'`$()#]" syn match shSpecialSQ "[^\\]\zs\%(\\\\\)*\\[\\"'`$()#]" contained nextgroup=shBkslshSnglQuote,@shNoZSList syn match shSpecialDQ "[^\\]\zs\%(\\\\\)*\\[\\"'`$()#]" contained nextgroup=shBkslshDblQuote,@shNoZSList syn match shSpecialStart "\%(\\\\\)*\\[\\"'`$()#]" contained nextgroup=shBkslshSnglQuote,shBkslshDblQuote,@shNoZSList syn match shSpecial "^\%(\\\\\)*\\[\\"'`$()#]" syn match shSpecialNoZS contained "\%(\\\\\)*\\[\\"'`$()#]" syn match shSpecialNxt contained "\\[\\"'`$()#]" -syn region shBkslshSnglQuote contained matchgroup=shQuote start=+'+ end=+'+ contains=@Spell nextgroup=shSpecialStart -syn region shBkslshDblQuote contained matchgroup=shQuote start=+"+ skip=+\\"+ end=+"+ contains=@shDblQuoteList,shStringSpecial,@Spell nextgroup=shSpecialStart +"syn region shBkslshSnglQuote contained matchgroup=shQuote start=+'+ end=+'+ contains=@Spell nextgroup=shSpecialStart +"syn region shBkslshDblQuote contained matchgroup=shQuote start=+"+ skip=+\\"+ end=+"+ contains=@shDblQuoteList,shStringSpecial,@Spell nextgroup=shSpecialStart " Comments: {{{1 "========== @@ -454,13 +453,13 @@ if !exists("g:sh_no_error") syn match shDerefWordError "[^}$[~]" contained endif syn match shDerefSimple "\$\%(\h\w*\|\d\)" nextgroup=@shNoZSList -syn region shDeref matchgroup=PreProc start="\${" end="}" contains=@shDerefList,shDerefVarArray +syn region shDeref matchgroup=PreProc start="\${" end="}" contains=@shDerefList,shDerefVarArray nextgroup=shSpecialStart syn match shDerefSimple "\$[-#*@!?]" nextgroup=@shNoZSList syn match shDerefSimple "\$\$" nextgroup=@shNoZSList -syn match shDerefSimple "\${\d}" nextgroup=@shNoZSList +syn match shDerefSimple "\${\d}" nextgroup=@shNoZSList nextgroup=shSpecialStart if exists("b:is_bash") || exists("b:is_kornshell") || exists("b:is_posix") - syn region shDeref matchgroup=PreProc start="\${##\=" end="}" contains=@shDerefList nextgroup=@shSpecialNoZS - syn region shDeref matchgroup=PreProc start="\${\$\$" end="}" contains=@shDerefList nextgroup=@shSpecialNoZS + syn region shDeref matchgroup=PreProc start="\${##\=" end="}" contains=@shDerefList nextgroup=@shSpecialNoZS,shSpecialStart + syn region shDeref matchgroup=PreProc start="\${\$\$" end="}" contains=@shDerefList nextgroup=@shSpecialNoZS,shSpecialStart endif " ksh: ${!var[*]} array index list syntax: {{{1 diff --git a/src/po/af.po b/src/po/af.po index 0b047fc3ef..e19c2c42df 100644 --- a/src/po/af.po +++ b/src/po/af.po @@ -2151,7 +2151,7 @@ msgstr "onbekende 'vimOption'" msgid "keyboard interrupt" msgstr "sleutelbordonderbreking" -msgid "vim error" +msgid "Vim error" msgstr "vim fout" msgid "cannot create buffer/window command: object is being deleted" @@ -2432,8 +2432,8 @@ msgstr "-W <skripuit>\tSkryf alle getikte bevele na l msgid "-x\t\t\tEdit encrypted files" msgstr "-x\t\t\tBewerk genkripteerde lers" -msgid "-display <display>\tConnect vim to this particular X-server" -msgstr "-display <display>\tKoppel vim aan hierdie X-bediener" +msgid "-display <display>\tConnect Vim to this particular X-server" +msgstr "-display <display>\tKoppel Vim aan hierdie X-bediener" msgid "-X\t\t\tDo not connect to X server" msgstr "-X\t\t\tMoet nie verbinding met X-bediener maak nie" @@ -2498,10 +2498,10 @@ msgstr "" "\n" "Parameters deur gvim herken (Athena weergawe):\n" -msgid "-display <display>\tRun vim on <display>" -msgstr "-display <display>\tVoer vim op <display> uit" +msgid "-display <display>\tRun Vim on <display>" +msgstr "-display <display>\tVoer Vim op <display> uit" -msgid "-iconic\t\tStart vim iconified" +msgid "-iconic\t\tStart Vim iconified" msgstr "-iconic\t\tBegin vim as ikoon" msgid "-name <name>\t\tUse resource as if vim was <name>" @@ -2568,8 +2568,8 @@ msgstr "" "\n" "Parameters wat gvim verstaan (GTK+ weergawe):\n" -msgid "-display <display>\tRun vim on <display> (also: --display)" -msgstr "-display <skerm>\tVoer vim op <skerm> uit: (ook --display)" +msgid "-display <display>\tRun Vim on <display> (also: --display)" +msgstr "-display <skerm>\tVoer Vim op <skerm> uit: (ook --display)" msgid "--role <role>\tSet a unique role to identify the main window" msgstr "--role <rol>\tStel 'n unieke rol om die hoofvenster te identifiseer" diff --git a/src/po/ca.po b/src/po/ca.po index 65be8f6d50..5fb5ede67b 100644 --- a/src/po/ca.po +++ b/src/po/ca.po @@ -2760,9 +2760,6 @@ msgstr "opci msgid "keyboard interrupt" msgstr "interrupci de teclat" -msgid "vim error" -msgstr "error de vim" - msgid "cannot create buffer/window command: object is being deleted" msgstr "no es pot crear l'ordre Tcl: l'objecte est sent eliminant" @@ -3080,7 +3077,7 @@ msgstr "-W <script>\t\tEscriu totes les ordres entrades al fitxer <script>" msgid "-x\t\t\tEdit encrypted files" msgstr "-x\t\t\tEdita fitxers amb xifrat" -msgid "-display <display>\tConnect vim to this particular X-server" +msgid "-display <display>\tConnect Vim to this particular X-server" msgstr "-display <pantalla>\tConnecta el Vim a un servidor X particular" msgid "-X\t\t\tDo not connect to X server" @@ -3151,10 +3148,10 @@ msgstr "" "\n" "Arguments reconeguts pel gvim (versi Athena):\n" -msgid "-display <display>\tRun vim on <display>" -msgstr "-display <pantalla>\tExecuta vim a <pantalla>" +msgid "-display <display>\tRun Vim on <display>" +msgstr "-display <pantalla>\tExecuta Vim a <pantalla>" -msgid "-iconic\t\tStart vim iconified" +msgid "-iconic\t\tStart Vim iconified" msgstr "-iconic\t\tComena iconificat" msgid "-background <color>\tUse <color> for the background (also: -bg)" @@ -3200,14 +3197,14 @@ msgstr "" "\n" "Arguments reconeguts pel gvim (versi GTK+):\n" -msgid "-display <display>\tRun vim on <display> (also: --display)" -msgstr "-display <pantalla>\tExecuta vim a <pantalla> (tamb: --display)" +msgid "-display <display>\tRun Vim on <display> (also: --display)" +msgstr "-display <pantalla>\tExecuta Vim a <pantalla> (tamb: --display)" msgid "--role <role>\tSet a unique role to identify the main window" msgstr "--role <rol>\t\tUsa un nic rol per a identificar la finestra principal" msgid "--socketid <xid>\tOpen Vim inside another GTK widget" -msgstr "--socketid <xid>\tObre el vim dins d'un altre giny GTK" +msgstr "--socketid <xid>\tObre el Vim dins d'un altre giny GTK" msgid "--echo-wid\t\tMake gvim echo the Window ID on stdout" msgstr "--echo-wid\t\tEscriu el Window ID a la sortida estndard" @@ -6774,8 +6771,8 @@ msgid "list index out of range" msgstr "ndex de llista fora de l'interval" #, c-format -msgid "internal error: failed to get vim list item %d" -msgstr "error intern: error en obtenir l'element %d de la llista vim" +msgid "internal error: failed to get Vim list item %d" +msgstr "error intern: error en obtenir l'element %d de la llista Vim" msgid "slice step cannot be zero" msgstr "l'increment de l'interval no pot ser zero" @@ -6785,8 +6782,8 @@ msgid "attempt to assign sequence of size greater than %d to extended slice" msgstr "intent d'assignar una seqncia de ms de %d elements a un interval ests" #, c-format -msgid "internal error: no vim list item %d" -msgstr "error intern: no existeix l'element %d a la llista vim" +msgid "internal error: no Vim list item %d" +msgstr "error intern: no existeix l'element %d a la llista Vim" msgid "internal error: not enough list items" msgstr "error intern: no hi ha prou elements a la llista" @@ -6894,19 +6891,19 @@ msgstr "error en executar el codi" msgid "E858: Eval did not return a valid python object" msgstr "E858: Eval no ha retornat un objecte Python vlid" -msgid "E859: Failed to convert returned python object to vim value" +msgid "E859: Failed to convert returned python object to a Vim value" msgstr "E859: Error en convertir l'objecte Python retornat a un valor Vim" #, c-format -msgid "unable to convert %s to vim dictionary" +msgid "unable to convert %s to a Vim dictionary" msgstr "error en convertir %s en un diccionari Vim" #, c-format -msgid "unable to convert %s to vim list" +msgid "unable to convert %s to a Vim list" msgstr "error en convertir %s en una llista Vim" #, c-format -msgid "unable to convert %s to vim structure" +msgid "unable to convert %s to a Vim structure" msgstr "error en convertir %s en una estructura Vim" msgid "internal error: NULL reference passed" diff --git a/src/po/cs.cp1250.po b/src/po/cs.cp1250.po index 401f60d39c..809ced1143 100644 --- a/src/po/cs.cp1250.po +++ b/src/po/cs.cp1250.po @@ -1962,7 +1962,7 @@ msgstr "nezn msgid "keyboard interrupt" msgstr "peruen z klvesnice" -msgid "vim error" +msgid "Vim error" msgstr "chyba vim" msgid "cannot create buffer/window command: object is being deleted" @@ -2247,8 +2247,8 @@ msgstr "-W <skript>\t\tUlo msgid "-x\t\t\tEdit encrypted files" msgstr "-x\t\t\tEditace zaifrovanch soubor" -msgid "-display <display>\tConnect vim to this particular X-server" -msgstr "-display <display>\tSpust vim na dan X-server" +msgid "-display <display>\tConnect Vim to this particular X-server" +msgstr "-display <display>\tSpust Vim na dan X-server" msgid "-X\t\t\tDo not connect to X server" msgstr "-X\t\t\tNepipoj se k X serveru" @@ -2300,11 +2300,11 @@ msgstr "" "\n" "Pepnae pro gvim (Athena verzi):\n" -msgid "-display <display>\tRun vim on <display>" -msgstr "-display <display>\tSpust vim na <display>" +msgid "-display <display>\tRun Vim on <display>" +msgstr "-display <display>\tSpust Vim na <display>" -msgid "-iconic\t\tStart vim iconified" -msgstr "-iconic\t\tSpust vim minimalizovan" +msgid "-iconic\t\tStart Vim iconified" +msgstr "-iconic\t\tSpust Vim minimalizovan" msgid "-name <name>\t\tUse resource as if vim was <name>" msgstr "-name <nzev>\t\tPouije resource jako by vim ml <nzev>" @@ -2368,8 +2368,8 @@ msgstr "" "\n" "Pepnae pro gvim (GTK+ verzi):\n" -msgid "-display <display>\tRun vim on <display> (also: --display)" -msgstr "-display <display>\tSpust vim na <display> (tak --display)" +msgid "-display <display>\tRun Vim on <display> (also: --display)" +msgstr "-display <display>\tSpust Vim na <display> (tak --display)" msgid "--help\t\tShow Gnome arguments" msgstr "--help\t\tVype Gnome pepnae" diff --git a/src/po/cs.po b/src/po/cs.po index 17d94b3294..6e6cc3bd4d 100644 --- a/src/po/cs.po +++ b/src/po/cs.po @@ -1962,7 +1962,7 @@ msgstr "nezn msgid "keyboard interrupt" msgstr "peruen z klvesnice" -msgid "vim error" +msgid "Vim error" msgstr "chyba vim" msgid "cannot create buffer/window command: object is being deleted" @@ -2247,8 +2247,8 @@ msgstr "-W <skript>\t\tUlo msgid "-x\t\t\tEdit encrypted files" msgstr "-x\t\t\tEditace zaifrovanch soubor" -msgid "-display <display>\tConnect vim to this particular X-server" -msgstr "-display <display>\tSpust vim na dan X-server" +msgid "-display <display>\tConnect Vim to this particular X-server" +msgstr "-display <display>\tSpust Vim na dan X-server" msgid "-X\t\t\tDo not connect to X server" msgstr "-X\t\t\tNepipoj se k X serveru" @@ -2300,11 +2300,11 @@ msgstr "" "\n" "Pepnae pro gvim (Athena verzi):\n" -msgid "-display <display>\tRun vim on <display>" -msgstr "-display <display>\tSpust vim na <display>" +msgid "-display <display>\tRun Vim on <display>" +msgstr "-display <display>\tSpust Vim na <display>" -msgid "-iconic\t\tStart vim iconified" -msgstr "-iconic\t\tSpust vim minimalizovan" +msgid "-iconic\t\tStart Vim iconified" +msgstr "-iconic\t\tSpust Vim minimalizovan" msgid "-name <name>\t\tUse resource as if vim was <name>" msgstr "-name <nzev>\t\tPouije resource jako by vim ml <nzev>" @@ -2368,8 +2368,8 @@ msgstr "" "\n" "Pepnae pro gvim (GTK+ verzi):\n" -msgid "-display <display>\tRun vim on <display> (also: --display)" -msgstr "-display <display>\tSpust vim na <display> (tak --display)" +msgid "-display <display>\tRun Vim on <display> (also: --display)" +msgstr "-display <display>\tSpust Vim na <display> (tak --display)" msgid "--help\t\tShow Gnome arguments" msgstr "--help\t\tVype Gnome pepnae" diff --git a/src/po/da.po b/src/po/da.po index 692b3bf5c2..a5e9c260fc 100644 --- a/src/po/da.po +++ b/src/po/da.po @@ -2807,9 +2807,6 @@ msgstr "ukendt vimOption" msgid "keyboard interrupt" msgstr "tastaturafbryd" -msgid "vim error" -msgstr "fejl ved vim" - msgid "cannot create buffer/window command: object is being deleted" msgstr "kan ikke oprette buffer-/vindue-kommando: objekt slettes" @@ -3136,8 +3133,8 @@ msgstr "-W <scriptud>\tSkriv alle indtastede kommandoer til filen <scriptud>" msgid "-x\t\t\tEdit encrypted files" msgstr "-x\t\t\tRediger krypterede filer" -msgid "-display <display>\tConnect vim to this particular X-server" -msgstr "-display <display>\tForbind vim til denne X-server" +msgid "-display <display>\tConnect Vim to this particular X-server" +msgstr "-display <display>\tForbind Vim til denne X-server" msgid "-X\t\t\tDo not connect to X server" msgstr "-X\t\t\tOpret ikke forbindelse til X-server" @@ -3217,11 +3214,11 @@ msgstr "" "\n" "Argumenter som genkendes af gvim (Athena-version):\n" -msgid "-display <display>\tRun vim on <display>" -msgstr "-display <display>\tKør vim på <display>" +msgid "-display <display>\tRun Vim on <display>" +msgstr "-display <display>\tKør Vim på <display>" -msgid "-iconic\t\tStart vim iconified" -msgstr "-iconic\t\tStart vim som ikon" +msgid "-iconic\t\tStart Vim iconified" +msgstr "-iconic\t\tStart Vim som ikon" msgid "-background <color>\tUse <color> for the background (also: -bg)" msgstr "-background <farve>\tBrug <farve> til baggrunden (også: -bg)" @@ -3267,8 +3264,8 @@ msgstr "" "\n" "Argumenter genkendt af gvim (GTK+-version):\n" -msgid "-display <display>\tRun vim on <display> (also: --display)" -msgstr "-display <display>\tKør vim på <display> (også: --display)" +msgid "-display <display>\tRun Vim on <display> (also: --display)" +msgstr "-display <display>\tKør Vim på <display> (også: --display)" msgid "--role <role>\tSet a unique role to identify the main window" msgstr "--role <rolle>\tSæt en unik rolle til at identificere hovedvinduet" @@ -6891,7 +6888,7 @@ msgid "list index out of range" msgstr "listeindeks udenfor område" #, c-format -msgid "internal error: failed to get vim list item %d" +msgid "internal error: failed to get Vim list item %d" msgstr "intern fejl: kunne ikke hente vim-listepunkt %d" msgid "slice step cannot be zero" @@ -6902,7 +6899,7 @@ msgid "attempt to assign sequence of size greater than %d to extended slice" msgstr "forsøg på at tildele sekvens som er større end %d til udvidet slice" #, c-format -msgid "internal error: no vim list item %d" +msgid "internal error: no Vim list item %d" msgstr "intern fejl: intet vim-listepunkt %d" msgid "internal error: not enough list items" @@ -7013,19 +7010,19 @@ msgstr "kunne ikke køre koden" msgid "E858: Eval did not return a valid python object" msgstr "E858: Eval returnerede ikke et gyldigt python-objekt" -msgid "E859: Failed to convert returned python object to vim value" +msgid "E859: Failed to convert returned python object to a Vim value" msgstr "E859: Kunne ikke konvertere returnerede python-objekt til vim-værdi" #, c-format -msgid "unable to convert %s to vim dictionary" +msgid "unable to convert %s to a Vim dictionary" msgstr "kan ikke konvertere %s til vim-ordbog" #, c-format -msgid "unable to convert %s to vim list" +msgid "unable to convert %s to a Vim list" msgstr "kan ikke konvertere %s til vim-liste" #, c-format -msgid "unable to convert %s to vim structure" +msgid "unable to convert %s to a Vim structure" msgstr "kan ikke konvertere %s til vim-struktur" msgid "internal error: NULL reference passed" diff --git a/src/po/de.po b/src/po/de.po index fe423cbc92..720fcbafca 100644 --- a/src/po/de.po +++ b/src/po/de.po @@ -2564,9 +2564,6 @@ msgstr "unbekannte vimOption" msgid "keyboard interrupt" msgstr "Tastatur-Interrupt" -msgid "vim error" -msgstr "vim Fehler" - msgid "cannot create buffer/window command: object is being deleted" msgstr "" "Puffer/Fenster-Befehl kann nicht ausgefhrt werden: das Objekt wird gelscht" @@ -3042,8 +3039,8 @@ msgstr "" msgid "-x\t\t\tEdit encrypted files" msgstr "-x\t\t\tEditiere verschlsselte Dateien" -msgid "-display <display>\tConnect vim to this particular X-server" -msgstr "-display <display>\tStarte vim <display>" +msgid "-display <display>\tConnect Vim to this particular X-server" +msgstr "-display <display>\tStarte Vim <display>" msgid "-X\t\t\tDo not connect to X server" msgstr "-X\t\t\tStelle keine Verbindung zum X-server her" @@ -3126,11 +3123,11 @@ msgstr "" "\n" "Argumente fr den gvim (Athena Version):\n" -msgid "-display <display>\tRun vim on <display>" -msgstr "-display <display>\tStarte vim auf <display>" +msgid "-display <display>\tRun Vim on <display>" +msgstr "-display <display>\tStarte Vim auf <display>" -msgid "-iconic\t\tStart vim iconified" -msgstr "-iconic\t\tStarte vim als Icon" +msgid "-iconic\t\tStart Vim iconified" +msgstr "-iconic\t\tStarte Vim als Icon" msgid "-background <color>\tUse <color> for the background (also: -bg)" msgstr "" @@ -3185,8 +3182,8 @@ msgstr "" "\n" "Argumente fr gvim GTK+ Version:\n" -msgid "-display <display>\tRun vim on <display> (also: --display)" -msgstr "-display <display>\tStarte vim auf <display> (auch mit: --display)" +msgid "-display <display>\tRun Vim on <display> (also: --display)" +msgstr "-display <display>\tStarte Vim auf <display> (auch mit: --display)" msgid "--role <role>\tSet a unique role to identify the main window" msgstr "" @@ -7563,7 +7560,7 @@ msgid "list index out of range" msgstr "Listen Index auerhalb des gltigen Bereichs" #, c-format -msgid "internal error: failed to get vim list item %d" +msgid "internal error: failed to get Vim list item %d" msgstr "interner Fehler: Zugriff auf Vim Listobjekt %d fehlgeschlagen" msgid "slice step cannot be zero" @@ -7575,7 +7572,7 @@ msgstr "" "Versuch der Zuweisung von Sequenzgre grer als %d zu erweiterten Slice" #, c-format -msgid "internal error: no vim list item %d" +msgid "internal error: no Vim list item %d" msgstr "interner Fehler: Kein Vim Listobjekt %d" msgid "internal error: not enough list items" @@ -7685,21 +7682,21 @@ msgstr "Ausf msgid "E858: Eval did not return a valid python object" msgstr "E858: Eval hat kein gltiges Pythonobjekt zurckgegeben" -msgid "E859: Failed to convert returned python object to vim value" +msgid "E859: Failed to convert returned python object to a Vim value" msgstr "" "E859: Konvertierung von zurckgegebenen Pythonobjekt zu Vim Wert " "fehlgeschlagen" #, c-format -msgid "unable to convert %s to vim dictionary" +msgid "unable to convert %s to a Vim dictionary" msgstr "konnte nicht %s zu Vim Dictionary konvertieren" #, c-format -msgid "unable to convert %s to vim list" +msgid "unable to convert %s to a Vim list" msgstr "konnte %s nicht zu Vim Liste konvertieren" #, c-format -msgid "unable to convert %s to vim structure" +msgid "unable to convert %s to a Vim structure" msgstr "konnte %s nicht zu Vim Struktur konvertieren" msgid "internal error: NULL reference passed" diff --git a/src/po/eo.po b/src/po/eo.po index 01732c3684..521522bb8a 100644 --- a/src/po/eo.po +++ b/src/po/eo.po @@ -2539,9 +2539,6 @@ msgstr "nekonata vimOption" msgid "keyboard interrupt" msgstr "klavara interrompo" -msgid "vim error" -msgstr "eraro de Vim" - msgid "cannot create buffer/window command: object is being deleted" msgstr "ne eblas krei komandon de bufro/fenestro: objekto estas forviŝiĝanta" @@ -3014,7 +3011,7 @@ msgstr "" msgid "-x\t\t\tEdit encrypted files" msgstr "-x\t\t\tRedakti ĉifradan dosieron" -msgid "-display <display>\tConnect vim to this particular X-server" +msgid "-display <display>\tConnect Vim to this particular X-server" msgstr "-display <ekrano>\tKonekti Vim al tiu X-servilo" msgid "-X\t\t\tDo not connect to X server" @@ -3093,11 +3090,11 @@ msgstr "" "\n" "Argumentoj agnoskitaj de gvim (versio Athena):\n" -msgid "-display <display>\tRun vim on <display>" -msgstr "-display <ekrano>\tLanĉi vim sur <ekrano>" +msgid "-display <display>\tRun Vim on <display>" +msgstr "-display <ekrano>\tLanĉi Vim sur <ekrano>" -msgid "-iconic\t\tStart vim iconified" -msgstr "-iconic\t\tLanĉi vim piktograme" +msgid "-iconic\t\tStart Vim iconified" +msgstr "-iconic\t\tLanĉi Vim piktograme" msgid "-background <color>\tUse <color> for the background (also: -bg)" msgstr "-background <koloro>\tUzi <koloro>-n por la fona koloro (ankaŭ: -bg)" @@ -3145,7 +3142,7 @@ msgstr "" "\n" "Argumentoj agnoskitaj de gvim (versio GTK+):\n" -msgid "-display <display>\tRun vim on <display> (also: --display)" +msgid "-display <display>\tRun Vim on <display> (also: --display)" msgstr "-display <ekrano>\tLanĉi Vim sur tiu <ekrano> (ankaŭ: --display)" msgid "--role <role>\tSet a unique role to identify the main window" @@ -7459,7 +7456,7 @@ msgid "list index out of range" msgstr "indekso de listo ekster limoj" #, c-format -msgid "internal error: failed to get vim list item %d" +msgid "internal error: failed to get Vim list item %d" msgstr "interna eraro: obteno de vim-a listero %d malsukcesis" msgid "slice step cannot be zero" @@ -7470,7 +7467,7 @@ msgid "attempt to assign sequence of size greater than %d to extended slice" msgstr "provis valorizi sekvencon kun pli ol %d eroj en etendita sekco" #, c-format -msgid "internal error: no vim list item %d" +msgid "internal error: no Vim list item %d" msgstr "interna eraro: neniu vim-a listero %d" msgid "internal error: not enough list items" @@ -7579,19 +7576,19 @@ msgstr "malsukcesis ruli la kodon" msgid "E858: Eval did not return a valid python object" msgstr "E858: Eval ne revenis kun valida python-objekto" -msgid "E859: Failed to convert returned python object to vim value" +msgid "E859: Failed to convert returned python object to a Vim value" msgstr "E859: Konverto de revena python-objekto al vim-valoro malsukcesis" #, c-format -msgid "unable to convert %s to vim dictionary" +msgid "unable to convert %s to a Vim dictionary" msgstr "ne povis konverti %s al vim-vortaro" #, c-format -msgid "unable to convert %s to vim list" +msgid "unable to convert %s to a Vim list" msgstr "ne povis konverti %s al vim-listo" #, c-format -msgid "unable to convert %s to vim structure" +msgid "unable to convert %s to a Vim structure" msgstr "ne povis konverti %s al vim-strukturo" msgid "internal error: NULL reference passed" diff --git a/src/po/es.po b/src/po/es.po index 8f8935c6a9..6c6d147eae 100644 --- a/src/po/es.po +++ b/src/po/es.po @@ -19,181 +19,139 @@ msgstr "" "Content-Type: text/plain; charset=utf-8\n" "Content-Transfer-Encoding: octect-stream\n" -#: buffer.c:102 msgid "E82: Cannot allocate any buffer, exiting..." msgstr "E82: No se pudo asignar memoria para ningún búfer, saliendo..." -#: buffer.c:105 msgid "E83: Cannot allocate buffer, using other one..." msgstr "E83: No se pudo asignar memoria para el búfer, usando otro..." -#: buffer.c:879 msgid "E515: No buffers were unloaded" msgstr "E515: No se descargó ningún búfer" -#: buffer.c:881 msgid "E516: No buffers were deleted" msgstr "E516: No se borró ningún búfer" -#: buffer.c:883 msgid "E517: No buffers were wiped out" msgstr "E517: No se eliminó ningún búfer" -#: buffer.c:891 msgid "1 buffer unloaded" msgstr "Se descargó un (1) búfer" -#: buffer.c:893 #, c-format msgid "%d buffers unloaded" msgstr "Se descargaron %d búfers" -#: buffer.c:898 msgid "1 buffer deleted" msgstr "Se suprimió un (1) búfer" -#: buffer.c:900 #, c-format msgid "%d buffers deleted" msgstr "Se suprimieron %d búfers" -#: buffer.c:905 msgid "1 buffer wiped out" msgstr "Se eliminó un (1) búfer" -#: buffer.c:907 #, c-format msgid "%d buffers wiped out" msgstr "Se eliminaron %d búfers" -#: buffer.c:965 msgid "E84: No modified buffer found" msgstr "E84: No se encontró ningún búfer modificado" # back where we started, didn't find anything. -#. back where we started, didn't find anything. -#: buffer.c:1004 msgid "E85: There is no listed buffer" msgstr "E85: No hay búfers en la lista" -#: buffer.c:1016 #, c-format msgid "E86: Buffer %ld does not exist" msgstr "E86: El búfer %ld no existe" -#: buffer.c:1019 msgid "E87: Cannot go beyond last buffer" msgstr "E87: No se pudo ir más allá del último búfer" -#: buffer.c:1021 msgid "E88: Cannot go before first buffer" msgstr "E88: No se pudo regresar antes del primer búfer" -#: buffer.c:1063 #, c-format msgid "E89: No write since last change for buffer %ld (add ! to override)" msgstr "" "E89: No se guardó el archivo desde el último cambio del búfer %ld (añada \"!" "\" para forzar)" -#: buffer.c:1080 msgid "E90: Cannot unload last buffer" msgstr "E90: No se pudo descargar el último búfer" -#: buffer.c:1651 msgid "W14: Warning: List of file names overflow" msgstr "W14: Advertencia: La lista de nombres de archivos es muy larga" -#: buffer.c:1850 quickfix.c:3632 #, c-format msgid "E92: Buffer %ld not found" msgstr "E92: No se encontró el búfer %ld" -#: buffer.c:2125 #, c-format msgid "E93: More than one match for %s" msgstr "E93: Hay más de una coincidencia con %s" -#: buffer.c:2127 #, c-format msgid "E94: No matching buffer for %s" msgstr "E94: No hay un búfer que coincida con %s" -#: buffer.c:2579 #, c-format msgid "line %ld" msgstr "línea %ld" -#: buffer.c:2666 msgid "E95: Buffer with this name already exists" msgstr "E95: Ya existe un búfer con este nombre" -#: buffer.c:2993 msgid " [Modified]" msgstr " [Modificado]" -#: buffer.c:2998 msgid "[Not edited]" msgstr "[Sin editar]" -#: buffer.c:3003 msgid "[New file]" msgstr "[Archivo nuevo]" -#: buffer.c:3004 msgid "[Read errors]" msgstr "[Errores de lectura]" -#: buffer.c:3006 fileio.c:2391 netbeans.c:3632 msgid "[readonly]" msgstr "[Sólo lectura]" -#: buffer.c:3029 #, c-format msgid "1 line --%d%%--" msgstr "1 línea --%d%%--" -#: buffer.c:3032 #, c-format msgid "%ld lines --%d%%--" msgstr "%ld líneas --%d%%--" -#: buffer.c:3039 #, c-format msgid "line %ld of %ld --%d%%-- col " msgstr "línea %ld de %ld --%d%%-- col " -#: buffer.c:3160 buffer.c:5126 memline.c:1727 msgid "[No Name]" msgstr "[Sin nombre]" # must be a help buffer -#. must be a help buffer -#: buffer.c:3198 msgid "help" msgstr "ayuda" -#: buffer.c:3826 screen.c:5817 msgid "[Help]" msgstr "[Ayuda]" -#: buffer.c:3860 screen.c:5823 msgid "[Preview]" msgstr "[Vista previa]" -#: buffer.c:4182 msgid "All" msgstr "Todo" -#: buffer.c:4182 msgid "Bot" msgstr "Final" -#: buffer.c:4185 msgid "Top" msgstr "Comienzo" -#: buffer.c:5061 #, c-format msgid "" "\n" @@ -202,19 +160,15 @@ msgstr "" "\n" "# Lista de búfers:\n" -#: buffer.c:5110 msgid "[Location List]" msgstr "[Lista de ubicaciones]" -#: buffer.c:5112 msgid "[Quickfix List]" msgstr "[Lista de cambios rápidos]" -#: buffer.c:5122 msgid "[Scratch]" msgstr "[De cero]" -#: buffer.c:5439 msgid "" "\n" "--- Signs ---" @@ -222,182 +176,139 @@ msgstr "" "\n" "--- Signos ---" -#: buffer.c:5449 #, c-format msgid "Signs for %s:" msgstr "Signos para %s:" -#: buffer.c:5455 #, c-format msgid " line=%ld id=%d name=%s" msgstr " línea=%ld id=%d nombre=%s" -#: diff.c:141 #, c-format msgid "E96: Can not diff more than %ld buffers" msgstr "E96: No se puede usar \"diff\" con más de %ld búfers" -#: diff.c:777 msgid "E810: Cannot read or write temp files" msgstr "E810: No se puede leer o escribir en archivos temporales" -#: diff.c:778 msgid "E97: Cannot create diffs" msgstr "E97: No se pudieron crear las \"diffs\" (diferencias)" -#: diff.c:901 msgid "Patch file" msgstr "Archivo de parches" -#: diff.c:1005 msgid "E816: Cannot read patch output" msgstr "E816: No se pudo leer la salida del parche" -#: diff.c:1227 msgid "E98: Cannot read diff output" msgstr "E98: No se pudo leer la salida de \"diff\"" -#: diff.c:2086 msgid "E99: Current buffer is not in diff mode" msgstr "E99: El búfer actual no está en modo de diferencias" -#: diff.c:2105 msgid "E793: No other buffer in diff mode is modifiable" msgstr "E793: Ningún otro búfer está en modo de diferencias" -#: diff.c:2107 msgid "E100: No other buffer in diff mode" msgstr "E100: Ningún otro búfer está en modo de diferencias" -#: diff.c:2117 msgid "E101: More than two buffers in diff mode, don't know which one to use" msgstr "E101: Más de dos búfers en modo de diferencias, no se cual usar" -#: diff.c:2140 #, c-format msgid "E102: Can't find buffer \"%s\"" msgstr "E102: No se pudo encontrar el búfer %s" -#: diff.c:2148 #, c-format msgid "E103: Buffer \"%s\" is not in diff mode" msgstr "E103: El búfer \"%s\" no está en modo de diferencias" -#: diff.c:2192 msgid "E787: Buffer changed unexpectedly" msgstr "E787: El búfer cambió inesperadamente" -#: digraph.c:2251 msgid "E104: Escape not allowed in digraph" msgstr "E104: El código de escape no se permite en un dígrafo" -#: digraph.c:2444 msgid "E544: Keymap file not found" msgstr "E544: No se encontró el archivo \"keymap\"" -#: digraph.c:2471 msgid "E105: Using :loadkeymap not in a sourced file" msgstr "E105: Usando \":loadkeymap\" en el archivo suministrado" -#: digraph.c:2510 msgid "E791: Empty keymap entry" msgstr "E791: Definición de \"keymap\" vacía" -#: edit.c:42 msgid " Keyword completion (^N^P)" msgstr " Completar palabra clave (^N^P)" # ctrl_x_mode == 0, ^P/^N compl. -#. ctrl_x_mode == 0, ^P/^N compl. -#: edit.c:43 msgid " ^X mode (^]^D^E^F^I^K^L^N^O^Ps^U^V^Y)" msgstr " Modo ^X (^]^D^E^F^I^K^L^N^O^Ps^U^V^Y)" -#: edit.c:45 msgid " Whole line completion (^L^N^P)" msgstr " Completar toda la línea (^L^N^P)" -#: edit.c:46 msgid " File name completion (^F^N^P)" msgstr " Completar nombre de archivo (^F^N^P)" -#: edit.c:47 msgid " Tag completion (^]^N^P)" msgstr " Completar etiquetas (^]^N^P)" -#: edit.c:48 msgid " Path pattern completion (^N^P)" msgstr " Completar patrón de ruta (^N^P)" -#: edit.c:49 msgid " Definition completion (^D^N^P)" msgstr " Completar definición (^D^N^P)" -#: edit.c:51 msgid " Dictionary completion (^K^N^P)" msgstr " Completar diccionario (^K^N^P)" -#: edit.c:52 msgid " Thesaurus completion (^T^N^P)" msgstr " Completar palabras con tesauro (^T^N^P)" -#: edit.c:53 msgid " Command-line completion (^V^N^P)" msgstr " Compleción de línea de órdenes (^V^N^P)" -#: edit.c:54 msgid " User defined completion (^U^N^P)" msgstr " Completar definido por usuario (^U^N^P)" -#: edit.c:55 msgid " Omni completion (^O^N^P)" msgstr " Completar con método Omni (^O^N^P)" -#: edit.c:56 msgid " Spelling suggestion (s^N^P)" msgstr " Sugerencia de ortografía (s^N^P)" # Scroll has its own msgs, in its place there is the msg for local # * ctrl_x_mode = 0 (eg continue_status & CONT_LOCAL) -- Acevedo -#: edit.c:57 msgid " Keyword Local completion (^N^P)" msgstr " Completar palabra clave local (^N^P)" -#: edit.c:60 msgid "Hit end of paragraph" msgstr "Se llegó al final del párrafo" -#: edit.c:2038 msgid "'dictionary' option is empty" msgstr "La opción 'dictionary' está vacía" -#: edit.c:2039 msgid "'thesaurus' option is empty" msgstr "La opción 'thesaurus' (tesauro) está vacía" -#: edit.c:2999 #, c-format msgid "Scanning dictionary: %s" msgstr "Buscando en el diccionario: %s" -#: edit.c:3484 msgid " (insert) Scroll (^E/^Y)" msgstr " (insertar) Desplazamiento (^E/^Y)" -#: edit.c:3486 msgid " (replace) Scroll (^E/^Y)" msgstr " (reemplazar) Desplazamiento (^E/^Y)" -#: edit.c:3963 #, c-format msgid "Scanning: %s" msgstr "Buscando: %s" -#: edit.c:3998 msgid "Scanning tags." msgstr "Buscando etiquetas." -#: edit.c:5010 msgid " Adding" msgstr "Añadiendo" @@ -405,336 +316,255 @@ msgstr "Añadiendo" # * be called before line = ml_get(), or when this address is no # * longer needed. -- Acevedo. # -#. showmode might reset the internal line pointers, so it must -#. * be called before line = ml_get(), or when this address is no -#. * longer needed. -- Acevedo. -#. -#: edit.c:5057 msgid "-- Searching..." msgstr "-- Buscando..." -#: edit.c:5116 msgid "Back at original" msgstr "De vuelta al original" -#: edit.c:5121 msgid "Word from other line" msgstr "Palabra proveniente de otra línea" -#: edit.c:5126 msgid "The only match" msgstr "La única coincidencia" -#: edit.c:5191 #, c-format msgid "match %d of %d" msgstr "coincidencia %d de %d" -#: edit.c:5195 #, c-format msgid "match %d" msgstr "coincidencia %d" -#: eval.c:96 msgid "E18: Unexpected characters in :let" msgstr "E18: Caracteres inesperados en :let" -#: eval.c:97 #, c-format msgid "E684: list index out of range: %ld" msgstr "E684: índice de lista fuera de rango: %ld" -#: eval.c:98 #, c-format msgid "E121: Undefined variable: %s" msgstr "E121: Variable sin definir: %s" -#: eval.c:99 msgid "E111: Missing ']'" msgstr "E111: Falta un \"]\"" -#: eval.c:100 #, c-format msgid "E686: Argument of %s must be a List" msgstr "E686: El argumento de %s debe ser una lista" -#: eval.c:101 #, c-format msgid "E712: Argument of %s must be a List or Dictionary" msgstr "E712: El argumento de %s debe ser una lista o un diccionario" -#: eval.c:102 msgid "E713: Cannot use empty key for Dictionary" msgstr "E713: No se puede usar una llave vacía para el diccionario" -#: eval.c:103 msgid "E714: List required" msgstr "E714: Se requiere una lista" -#: eval.c:104 msgid "E715: Dictionary required" msgstr "E715: Se requiere de un diccionario" -#: eval.c:105 #, c-format msgid "E118: Too many arguments for function: %s" msgstr "E118: Demasiados argumentos para la función: %s" -#: eval.c:106 #, c-format msgid "E716: Key not present in Dictionary: %s" msgstr "E716: No se encuentra la llave en el diccionario. %s" -#: eval.c:107 #, c-format msgid "E122: Function %s already exists, add ! to replace it" msgstr "E122: La función %s ya existe, añada \"!\" para reemplazarla" -#: eval.c:108 msgid "E717: Dictionary entry already exists" msgstr "E717: Esta entrada ya existe en el diccionario" -#: eval.c:109 msgid "E718: Funcref required" msgstr "E718: Se requiere una referencia de función" # if Vim opened a window: Executing a shell may cause crashes -#: eval.c:110 msgid "E719: Cannot use [:] with a Dictionary" msgstr "E719: No puede usar [:] con un diccionario" -#: eval.c:111 #, c-format msgid "E734: Wrong variable type for %s=" msgstr "E734: Tipo de variable incorrecta para %s=" -#: eval.c:112 #, c-format msgid "E130: Unknown function: %s" msgstr "E130: Función desconocida: %s" -#: eval.c:113 #, c-format msgid "E461: Illegal variable name: %s" msgstr "E461: Nombre ilegal para una variable: %s" -#: eval.c:1898 msgid "E687: Less targets than List items" msgstr "E687: Menos blancos que elementos en la lista" -#: eval.c:1903 msgid "E688: More targets than List items" msgstr "E688: Más blancos que elementos en la lista" -#: eval.c:1989 msgid "Double ; in list of variables" msgstr "Duplicado ; en la lista de variables" -#: eval.c:2208 #, c-format msgid "E738: Can't list variables for %s" msgstr "E738: No se pudo enumerar las variables de %s" -#: eval.c:2554 msgid "E689: Can only index a List or Dictionary" msgstr "E689: Solo puedo indexar una lista o un diccionario" -#: eval.c:2560 msgid "E708: [:] must come last" msgstr "E708: [:] debe ir al final" -#: eval.c:2612 msgid "E709: [:] requires a List value" msgstr "E709: [:] requiere un valor de la lista" -#: eval.c:2848 msgid "E710: List value has more items than target" msgstr "E710: La lista de valores tiene más elementos que blancos" -#: eval.c:2852 msgid "E711: List value has not enough items" msgstr "E711: La lista de valores no tiene suficientes elementos" -#: eval.c:3087 msgid "E690: Missing \"in\" after :for" msgstr "E690: Falta \"in\" después de :for" -#: eval.c:3320 #, c-format msgid "E107: Missing parentheses: %s" msgstr "E107: Faltan paréntesis: %s" -#: eval.c:3559 #, c-format msgid "E108: No such variable: \"%s\"" msgstr "E108: No existe la variable: \"%s\"" -#: eval.c:3646 msgid "E743: variable nested too deep for (un)lock" msgstr "E743: La variable está anidada muy profundamente para (des)bloquear" -#: eval.c:3994 msgid "E109: Missing ':' after '?'" msgstr "E109: Falta un \":\" después de \"?\"" -#: eval.c:4296 msgid "E691: Can only compare List with List" msgstr "E691: Solo se puede comparar una lista con otra lista" -#: eval.c:4298 msgid "E692: Invalid operation for List" msgstr "E692: Operación inválida para lista" -#: eval.c:4325 msgid "E735: Can only compare Dictionary with Dictionary" msgstr "E735: Solo se puede comparar un diccionario con otro diccionario" -#: eval.c:4327 msgid "E736: Invalid operation for Dictionary" msgstr "E736: Operación inválida para diccionario" -#: eval.c:4347 msgid "E693: Can only compare Funcref with Funcref" msgstr "E693: Solo se puede comparar un \"Funref\" con otro \"Funcref\"" -#: eval.c:4349 msgid "E694: Invalid operation for Funcrefs" msgstr "E694: Operación inválida para \"Funcrefs\"" # if Vim opened a window: Executing a shell may cause crashes -#: eval.c:4769 msgid "E804: Cannot use '%' with Float" msgstr "E804: No se puede usar '%' con \"Float\"" -#: eval.c:4989 msgid "E110: Missing ')'" msgstr "E110: Falta un \")\"" -#: eval.c:5141 msgid "E695: Cannot index a Funcref" msgstr "E695: No se puede crear un índice de un \"Funcref\"" -#: eval.c:5398 #, c-format msgid "E112: Option name missing: %s" msgstr "E112: Falta el nombre de la opción: %s" -#: eval.c:5416 #, c-format msgid "E113: Unknown option: %s" msgstr "E113: Opción desconocida: %s" -#: eval.c:5482 #, c-format msgid "E114: Missing quote: %s" msgstr "E114: Faltan las comillas: %s" -#: eval.c:5618 #, c-format msgid "E115: Missing quote: %s" msgstr "E115: Faltan las comillas: %s" -#: eval.c:5697 #, c-format msgid "E696: Missing comma in List: %s" msgstr "E696: Falta una coma en la lista: %s" -#: eval.c:5705 #, c-format msgid "E697: Missing end of List ']': %s" msgstr "E697: Falta una marca de final de lista ']': %s" -#: eval.c:7195 #, c-format msgid "E720: Missing colon in Dictionary: %s" msgstr "E720: Falta una marca de dos puntos en el diccionario: %s" -#: eval.c:7224 #, c-format msgid "E721: Duplicate key in Dictionary: \"%s\"" msgstr "E721: Llave duplicada en el diccionario: %s" -#: eval.c:7244 #, c-format msgid "E722: Missing comma in Dictionary: %s" msgstr "E722: Falta una coma en el diccionario: %s" -#: eval.c:7252 #, c-format msgid "E723: Missing end of Dictionary '}': %s" msgstr "E723: Falta una marca de cierre '}' en el diccionario: %s" -#: eval.c:7290 msgid "E724: variable nested too deep for displaying" msgstr "E724: La variable está anidada demasiado profundamente para mostrarla" -#: eval.c:7974 #, c-format msgid "E740: Too many arguments for function %s" msgstr "E740: Demasiados argumentos para la función: %s" -#: eval.c:7976 #, c-format msgid "E116: Invalid arguments for function %s" msgstr "E116: Argumentos inválidos para la función: %s" -#: eval.c:8181 #, c-format msgid "E117: Unknown function: %s" msgstr "E117: Función desconocida: %s" -#: eval.c:8187 #, c-format msgid "E119: Not enough arguments for function: %s" msgstr "E119: No hay suficientes argumentos para la función: %s" -#: eval.c:8191 #, c-format msgid "E120: Using <SID> not in a script context: %s" msgstr "E120: Usando <SID> en un contexto que no es de \"script\": %s" -#: eval.c:8195 #, c-format msgid "E725: Calling dict function without Dictionary: %s" msgstr "E725: Llamando una función \"dict\" sin un diccionario: %s" -#: eval.c:8423 msgid "E808: Number or Float required" msgstr "E808: Se requiere \"Number\" o \"Float\"" -#: eval.c:8808 msgid "E699: Too many arguments" msgstr "E699: Demasiados argumentos" -#: eval.c:8977 msgid "E785: complete() can only be used in Insert mode" msgstr "E785: complete() solo se puede usar en modo \"Insert\"" -#. -#. * Yes this is ugly, I don't particularly like it either. But doing it -#. * this way has the compelling advantage that translations need not to -#. * be touched at all. See below what 'ok' and 'ync' are used for. -#. -#: eval.c:9077 gui.c:4871 gui_gtk.c:2144 os_mswin.c:598 msgid "&Ok" msgstr "&Ok" -#: eval.c:9727 #, c-format msgid "E737: Key already exists: %s" msgstr "E737: Ya existe una llave: %s" -#: eval.c:10301 #, c-format msgid "+-%s%3ld lines: " msgstr "+-%s%3ld líneas: " -#: eval.c:10389 #, c-format msgid "E700: Unknown function: %s" msgstr "E700: Función desconocida: %s" -#: eval.c:12379 msgid "" "&OK\n" "&Cancel" @@ -742,222 +572,174 @@ msgstr "" "&Aceptar\n" "&Cancelar" -#: eval.c:12461 msgid "called inputrestore() more often than inputsave()" msgstr "Se invocó \"inputrestore()\" más veces que \"inputsave()\"" -#: eval.c:12595 msgid "E786: Range not allowed" msgstr "E786: El rango no está permitido" -#: eval.c:12795 msgid "E701: Invalid type for len()" msgstr "E701: No es un tipo válido para len()" -#: eval.c:13788 msgid "E726: Stride is zero" msgstr "E726: El largo es cero" -#: eval.c:13790 msgid "E727: Start past end" msgstr "E727: El inicio está más allá del final" -#: eval.c:13843 eval.c:17576 msgid "<empty>" msgstr "<vacio>" -#: eval.c:14077 msgid "E240: No connection to Vim server" msgstr "E240: No hay conexión al servidor Vim" -#: eval.c:14125 #, c-format msgid "E241: Unable to send to %s" msgstr "E241: Incapaz de enviar a %s" -#: eval.c:14272 msgid "E277: Unable to read a server reply" msgstr "E277: Incapaz de leer una respuesta del servidor" -#: eval.c:14522 msgid "E655: Too many symbolic links (cycle?)" msgstr "E655: Demasiados enlaces simbólicos (¿referencia circular?)" -#: eval.c:15243 msgid "E258: Unable to send to client" msgstr "E258: Incapaz de enviar al cliente" -#: eval.c:15950 msgid "E702: Sort compare function failed" msgstr "E702: Fallo al ordenar funciones comparadas" -#: eval.c:16275 msgid "(Invalid)" msgstr "(No es válido)" -#: eval.c:16760 msgid "E677: Error writing temp file" msgstr "E677: Error al escribir el archivo temporal" -#: eval.c:18602 msgid "E805: Using a Float as a Number" msgstr "E805: Usando \"Float\" como un \"Number\"" -#: eval.c:18606 msgid "E703: Using a Funcref as a Number" msgstr "E703: Usando una función de referencia como \"Number\"" -#: eval.c:18614 msgid "E745: Using a List as a Number" msgstr "E745: Usando una \"Lista\" como \"Number\"" -#: eval.c:18617 msgid "E728: Using a Dictionary as a Number" msgstr "E728: Usando un Diccionario como \"Number\"" -#: eval.c:18720 msgid "E729: using Funcref as a String" msgstr "E729: Usando una Función de referencia como \"String\"" -#: eval.c:18723 msgid "E730: using List as a String" msgstr "E730: Usando una \"List\" como \"String\"" -#: eval.c:18726 msgid "E731: using Dictionary as a String" msgstr "E731: Usando un Diccionario como \"String\"" -#: eval.c:18730 msgid "E806: using Float as a String" msgstr "E806: Usando \"Float\" como \"String\"" -#: eval.c:19090 #, c-format msgid "E704: Funcref variable name must start with a capital: %s" msgstr "" "E704: El nombre de una variable de Función de referencia debe empezar con " "mayúscula: %s" -#: eval.c:19095 #, c-format msgid "E705: Variable name conflicts with existing function: %s" msgstr "E705: Nombre de variable en conflicto con una función existente: %s" -#: eval.c:19128 #, c-format msgid "E706: Variable type mismatch for: %s" msgstr "E706: Tipo de variable no concuerda con : %s" -#: eval.c:19237 #, c-format msgid "E795: Cannot delete variable %s" msgstr "E795: No se pudo borrar la variable %s" -#: eval.c:19254 #, c-format msgid "E741: Value is locked: %s" msgstr "E741: El valor está bloqueado: %s" -#: eval.c:19255 eval.c:19261 message.c:2132 os_mswin.c:2258 msgid "Unknown" msgstr "Desconocido" -#: eval.c:19260 #, c-format msgid "E742: Cannot change value of %s" msgstr "E742: No se pudo cambiar el valor de %s" -#: eval.c:19345 msgid "E698: variable nested too deep for making a copy" msgstr "E698: La variable está anidada muy profundamente para hacer una copia" -#: eval.c:19818 #, c-format msgid "E123: Undefined function: %s" msgstr "E123: Función indefinida: %s" -#: eval.c:19831 #, c-format msgid "E124: Missing '(': %s" msgstr "E124: Falta un \"(\": %s" -#: eval.c:19887 #, c-format msgid "E125: Illegal argument: %s" msgstr "E125: Argumento ilegal: %s" -#: eval.c:19997 msgid "E126: Missing :endfunction" msgstr "E126: Falta un \":endfunction\"" -#: eval.c:20134 #, c-format msgid "E707: Function name conflicts with variable: %s" msgstr "E707: El nombre de la función entran en conflicto con la variable: %s" -#: eval.c:20149 #, c-format msgid "E127: Cannot redefine function %s: It is in use" msgstr "E127: No se puede redefinir la función %s: Está en uso" -#: eval.c:20214 #, c-format msgid "E746: Function name does not match script file name: %s" msgstr "E746: Nombre de función no concuerda con el nombre de archivo: %s" -#: eval.c:20332 msgid "E129: Function name required" msgstr "E129: Se requiere el nombre de la función" -#: eval.c:20452 #, c-format msgid "E128: Function name must start with a capital or contain a colon: %s" msgstr "" "E128: El nombre de una función debe empezar con mayúscula o contener el " "signo de dos puntos: %s" -#: eval.c:20984 #, c-format msgid "E131: Cannot delete function %s: It is in use" msgstr "E131: No se pudo eliminar la función %s: Está en uso" -#: eval.c:21104 msgid "E132: Function call depth is higher than 'maxfuncdepth'" msgstr "" "E132: La recursión de llamada de la función es mayor que \"maxfuncdepth\"" # always scroll up, don't overwrite -#: eval.c:21243 #, c-format msgid "calling %s" msgstr "Invocando %s" -#: eval.c:21335 #, c-format msgid "%s aborted" msgstr "Abortada la ejecución de %s" -#: eval.c:21337 #, c-format msgid "%s returning #%ld" msgstr "%s devuelve #%ld" -#: eval.c:21353 #, c-format msgid "%s returning %s" msgstr "%s devuelve %s" # always scroll up, don't overwrite -#: eval.c:21377 ex_cmds2.c:3145 #, c-format msgid "continuing in %s" msgstr "continuando en %s" -#: eval.c:21496 msgid "E133: :return not inside a function" msgstr "E133: \":return\" no está dentro de una función" -#: eval.c:21909 #, c-format msgid "" "\n" @@ -966,7 +748,6 @@ msgstr "" "\n" "# variables globales:\n" -#: eval.c:22026 msgid "" "\n" "\tLast set from " @@ -974,105 +755,81 @@ msgstr "" "\n" "\tSe definió por última vez en " -#: eval.c:22046 msgid "No old files" msgstr "No hay archivos antiguos" -#: ex_cmds.c:101 #, c-format msgid "<%s>%s%s %d, Hex %02x, Octal %03o" msgstr "<%s>%s%s %d, Hex %02x, Octal %03o" -#: ex_cmds.c:128 #, c-format msgid "> %d, Hex %04x, Octal %o" msgstr "> %d, Hex %04x, Octal %o" -#: ex_cmds.c:129 #, c-format msgid "> %d, Hex %08x, Octal %o" msgstr "> %d, Hex %08x, Octal %o" -#: ex_cmds.c:739 msgid "E134: Move lines into themselves" msgstr "E134: Moviendo líneas sobre sí mismas" -#: ex_cmds.c:808 msgid "1 line moved" msgstr "1 línea movida" -#: ex_cmds.c:810 #, c-format msgid "%ld lines moved" msgstr "%ld líneas movidas" -#: ex_cmds.c:1305 #, c-format msgid "%ld lines filtered" msgstr "%ld líneas filtradas" -#: ex_cmds.c:1329 msgid "E135: *Filter* Autocommands must not change current buffer" msgstr "E135: *Filtro* Las auto-órdenes no deben cambiar el búfer en uso" -#: ex_cmds.c:1414 msgid "[No write since last change]\n" msgstr "[No se ha escrito nada al disco desde el último cambio]\n" -#: ex_cmds.c:1672 #, c-format msgid "%sviminfo: %s in line: " msgstr "%sviminfo: %s en la línea: " -#: ex_cmds.c:1680 msgid "E136: viminfo: Too many errors, skipping rest of file" msgstr "E136: viminfo: Demasiados errores, omitiendo el resto del archivo" -#: ex_cmds.c:1709 #, c-format msgid "Reading viminfo file \"%s\"%s%s%s" msgstr "Leyendo el archivo \"viminfo\" \"%s\"%s%s%s" -#: ex_cmds.c:1711 msgid " info" msgstr " info" -#: ex_cmds.c:1712 msgid " marks" msgstr " marcas" -#: ex_cmds.c:1713 msgid " oldfiles" msgstr " archivos antiguos" -#: ex_cmds.c:1714 msgid " FAILED" msgstr " FALLÓ" -#. avoid a wait_return for this message, it's annoying -#: ex_cmds.c:1810 #, c-format msgid "E137: Viminfo file is not writable: %s" msgstr "E137: No hay permisos de escritura para el archivo \"viminfo\": %s" -#: ex_cmds.c:1963 #, c-format msgid "E138: Can't write viminfo file %s!" msgstr "E138: ¡No se pudo escribir el archivo \"viminfo\" %s!" -#: ex_cmds.c:1973 #, c-format msgid "Writing viminfo file \"%s\"" msgstr "Escribiendo archivo \"viminfo\" \"%s\"" # Write the info: -#. Write the info: -#: ex_cmds.c:2081 #, c-format msgid "# This viminfo file was generated by Vim %s.\n" msgstr "# Vim %s generó este archivo \"viminfo\".\n" -#: ex_cmds.c:2083 #, c-format msgid "" "# You may edit it if you're careful!\n" @@ -1081,55 +838,44 @@ msgstr "" "# Puede editarlo, ¡sólo si tiene cuidado!\n" "\n" -#: ex_cmds.c:2085 #, c-format msgid "# Value of 'encoding' when this file was written\n" msgstr "# Valor de 'encoding' cuando se escribió este archivo\n" -#: ex_cmds.c:2185 msgid "Illegal starting char" msgstr "Carácter de comienzo ilegal" -#: ex_cmds.c:2551 ex_cmds2.c:1407 msgid "Save As" msgstr "Guardar como" -#: ex_cmds.c:2628 msgid "Write partial file?" msgstr "¿Escribir un archivo parcial?" -#: ex_cmds.c:2635 msgid "E140: Use ! to write partial buffer" msgstr "E140: Use \"!\" para escribir un búfer parcial" -#: ex_cmds.c:2777 #, c-format msgid "Overwrite existing file \"%s\"?" msgstr "¿Escribir sobre el archivo existente \"%s\"?" -#: ex_cmds.c:2820 #, c-format msgid "Swap file \"%s\" exists, overwrite anyway?" msgstr "Ya existe un archivo de intercambio \"%s\", desea sobreescribirlo? " -#: ex_cmds.c:2833 #, c-format msgid "E768: Swap file exists: %s (:silent! overrides)" msgstr "" "E768: El archivo de intercambio ya existe: %s (use ! para sobreescribir)" -#: ex_cmds.c:2901 #, c-format msgid "E141: No file name for buffer %ld" msgstr "E141: No existe un nombre de archivo para el búfer %ld" -#: ex_cmds.c:2940 msgid "E142: File not written: Writing is disabled by 'write' option" msgstr "" "E142: No se ha escrito el archivo: escritura desactivada por " "la opción 'write'" -#: ex_cmds.c:2970 #, c-format msgid "" "'readonly' option is set for \"%s\".\n" @@ -1138,7 +884,6 @@ msgstr "" "Se ha activado la opción de solo lectura ('readonly') para %s.\n" "¿Desea escribir de todas formas?" -#: ex_cmds.c:2973 #, c-format msgid "" "File permissions of \"%s\" are read-only.\n" @@ -1149,82 +894,64 @@ msgstr "" "sólo lectura. Cabe la posibilidad de escribir\n" "en él. ¿Desea intentarlo?" -#: ex_cmds.c:2990 #, c-format msgid "E505: \"%s\" is read-only (add ! to override)" msgstr "E505: \"%s\" es de solo lectura (añada ! para sobreescribir)" -#: ex_cmds.c:3177 msgid "Edit File" msgstr "Editar archivo" -#: ex_cmds.c:3847 #, c-format msgid "E143: Autocommands unexpectedly deleted new buffer %s" msgstr "E143: Las auto-órdenes han eliminado al nuevo búfer %s" -#: ex_cmds.c:4063 msgid "E144: non-numeric argument to :z" msgstr "E144: Argumento no numérico para \":z\"" -#: ex_cmds.c:4162 msgid "E145: Shell commands not allowed in rvim" msgstr "E145: No se permiten órdenes de consola en rvim" -#: ex_cmds.c:4261 msgid "E146: Regular expressions can't be delimited by letters" msgstr "E146: Las expresiones regulares no se pueden delimitar con letras" -#: ex_cmds.c:4721 #, c-format msgid "replace with %s (y/n/a/q/l/^E/^Y)?" msgstr "¿Reemplazar con %s (y/n/a/q/l/^E/^Y)?" -#: ex_cmds.c:5166 msgid "(Interrupted) " msgstr "(Interrumpido)" -#: ex_cmds.c:5171 msgid "1 match" msgstr "Una (1) coincidencia" -#: ex_cmds.c:5171 msgid "1 substitution" msgstr "Una (1) sustitución" -#: ex_cmds.c:5174 #, c-format msgid "%ld matches" msgstr "%ld coincidencias" -#: ex_cmds.c:5174 #, c-format msgid "%ld substitutions" msgstr "%ld sustituciones" -#: ex_cmds.c:5179 msgid " on 1 line" msgstr " en una (1) línea" -#: ex_cmds.c:5182 #, c-format msgid " on %ld lines" msgstr " en %ld líneas" -#: ex_cmds.c:5229 msgid "E147: Cannot do :global recursive" msgstr "E147: \":global\" no puede ser recursivo" -#: ex_cmds.c:5264 msgid "E148: Regular expression missing from global" msgstr "E148: Falta una expresión regular en \":global\"" -#: ex_cmds.c:5313 #, c-format msgid "Pattern found in every line: %s" msgstr "Patrón encontrado en cada línea: %s" -#: ex_cmds.c:5398 #, c-format msgid "" "\n" @@ -1235,345 +962,270 @@ msgstr "" "# Última cadena de sustitución:\n" "$" -#: ex_cmds.c:5511 msgid "E478: Don't panic!" msgstr "E478: ¡No entre en pánico!" -#: ex_cmds.c:5557 #, c-format msgid "E661: Sorry, no '%s' help for %s" msgstr "E661: Lo siento, no hay ayuda '%s' para \"%s\"" -#: ex_cmds.c:5560 #, c-format msgid "E149: Sorry, no help for %s" msgstr "E149: Lo siento, no hay ayuda para \"%s\"" -#: ex_cmds.c:5602 #, c-format msgid "Sorry, help file \"%s\" not found" msgstr "Lo siento, no encuentro el archivo de ayuda \"%s\"" -#: ex_cmds.c:6180 #, c-format msgid "E150: Not a directory: %s" msgstr "E150: No es un directorio: %s" -#: ex_cmds.c:6323 #, c-format msgid "E152: Cannot open %s for writing" msgstr "E152: No se pudo abrir %s para escritura" -#: ex_cmds.c:6360 #, c-format msgid "E153: Unable to open %s for reading" msgstr "E153: Incapaz de abrir %s para lectura" -#: ex_cmds.c:6396 #, c-format msgid "E670: Mix of help file encodings within a language: %s" msgstr "" "E670: Mezcla de codificaciones en archivos de ayuda dentro de un lenguaje: %s" -#: ex_cmds.c:6474 #, c-format msgid "E154: Duplicate tag \"%s\" in file %s/%s" msgstr "E154: Etiqueta \"%s\" duplicada en el archivo %s/%s" -#: ex_cmds.c:6610 #, c-format msgid "E160: Unknown sign command: %s" msgstr "E160: Orden de signo desconocida: %s" -#: ex_cmds.c:6627 msgid "E156: Missing sign name" msgstr "E156: Falta el nombre del signo" -#: ex_cmds.c:6673 msgid "E612: Too many signs defined" msgstr "E612: Demasiados signos definidos" -#: ex_cmds.c:6741 #, c-format msgid "E239: Invalid sign text: %s" msgstr "E239: El texto de signo no es válido: %s" -#: ex_cmds.c:6772 ex_cmds.c:6947 #, c-format msgid "E155: Unknown sign: %s" msgstr "E155: Signo desconocido: %s" -#: ex_cmds.c:6805 msgid "E159: Missing sign number" msgstr "E159: Falta el número del signo" -#: ex_cmds.c:6887 #, c-format msgid "E158: Invalid buffer name: %s" msgstr "E158: El nombre del búfer no es válido: %s" -#: ex_cmds.c:6926 #, c-format msgid "E157: Invalid sign ID: %ld" msgstr "E157: La identificación del signo no es válida: %ld" -#: ex_cmds.c:6996 msgid " (NOT FOUND)" msgstr " (NO ENCONTRADO)" -#: ex_cmds.c:6998 msgid " (not supported)" msgstr " (no hay apoyo para la función pedida)" -#: ex_cmds.c:7122 msgid "[Deleted]" msgstr "[Suprimido]" -#: ex_cmds2.c:138 msgid "Entering Debug mode. Type \"cont\" to continue." msgstr "Iniciando modo de depuración. Escriba \"cont\" para continuar." -#: ex_cmds2.c:142 ex_docmd.c:1081 #, c-format msgid "line %ld: %s" msgstr "línea %ld: %s" -#: ex_cmds2.c:144 #, c-format msgid "cmd: %s" msgstr "cmd: %s" -#: ex_cmds2.c:344 #, c-format msgid "Breakpoint in \"%s%s\" line %ld" msgstr "\"Breakpoint\" en \"%s%s\" línea %ld" -#: ex_cmds2.c:656 #, c-format msgid "E161: Breakpoint not found: %s" msgstr "E161: No se ha encontrado el \"breakpoint\": %s" -#: ex_cmds2.c:692 msgid "No breakpoints defined" msgstr "No se han definido \"breakpoints\"" -#: ex_cmds2.c:697 #, c-format msgid "%3d %s %s line %ld" msgstr "%3d %s %s línea %ld" -#: ex_cmds2.c:1095 msgid "E750: First use :profile start <fname>" msgstr "E750: Primero use \":profile start <nombre_de_archivo>\"" -#: ex_cmds2.c:1432 #, c-format msgid "Save changes to \"%s\"?" msgstr "¿Guardar los cambios en \"%s\"?" -#: ex_cmds2.c:1434 ex_docmd.c:10814 msgid "Untitled" msgstr "Sin título" -#: ex_cmds2.c:1563 #, c-format msgid "E162: No write since last change for buffer \"%s\"" msgstr "E162: No se ha grabado nada desde el último cambio en el búfer \"%s\"" -#: ex_cmds2.c:1634 msgid "Warning: Entered other buffer unexpectedly (check autocommands)" msgstr "" "Advertencia: se ha entrado en otro búfer de forma inesperada (verifique las " "auto-órdenes)" -#: ex_cmds2.c:2078 msgid "E163: There is only one file to edit" msgstr "E163: Hay sólo un archivo para editar" -#: ex_cmds2.c:2080 msgid "E164: Cannot go before first file" msgstr "E164: No se pudo regresar antes del primer archivo" -#: ex_cmds2.c:2082 msgid "E165: Cannot go beyond last file" msgstr "E165: No se pudo ir más allá del último archivo" -#: ex_cmds2.c:2511 #, c-format msgid "E666: compiler not supported: %s" msgstr "E666: El compilador no es compatible en esta versión: %s" -#: ex_cmds2.c:2612 #, c-format msgid "Searching for \"%s\" in \"%s\"" msgstr "Buscando \"%s\" en \"%s\"" -#: ex_cmds2.c:2639 #, c-format msgid "Searching for \"%s\"" msgstr "Buscando \"%s\"" -#: ex_cmds2.c:2665 #, c-format msgid "not found in 'runtimepath': \"%s\"" msgstr "No se ha encontrado en 'runtimepath': %s" -#: ex_cmds2.c:2700 msgid "Source Vim script" msgstr "Ejecute archivo de órdenes de Vim" -#: ex_cmds2.c:2875 #, c-format msgid "Cannot source a directory: \"%s\"" msgstr "No se pudo ejecutar un directorio: %s" -#: ex_cmds2.c:2932 #, c-format msgid "could not source \"%s\"" msgstr "No pude ejecutar %s" -#: ex_cmds2.c:2934 #, c-format msgid "line %ld: could not source \"%s\"" msgstr "línea %ld: no se pudo ejecutar %s" -#: ex_cmds2.c:2950 #, c-format msgid "sourcing \"%s\"" msgstr "ejecutando %s" -#: ex_cmds2.c:2952 #, c-format msgid "line %ld: sourcing \"%s\"" msgstr "línea %ld: ejecutando %s" -#: ex_cmds2.c:3143 #, c-format msgid "finished sourcing %s" msgstr "La ejecución de %s ha terminado" -#: ex_cmds2.c:3224 msgid "modeline" msgstr "modeline" -#: ex_cmds2.c:3226 msgid "--cmd argument" msgstr "--cmd [argumentos]" -#: ex_cmds2.c:3228 msgid "-c argument" msgstr "-c [argumentos]" -#: ex_cmds2.c:3230 msgid "environment variable" msgstr "variable de entorno" -#: ex_cmds2.c:3232 msgid "error handler" msgstr "administrador de errores" -#: ex_cmds2.c:3524 msgid "W15: Warning: Wrong line separator, ^M may be missing" msgstr "W15: Advertencia: separador de línea incorrecto, puede que falte ^M" -#: ex_cmds2.c:3657 msgid "E167: :scriptencoding used outside of a sourced file" msgstr "" "E167: Ha usado \":scriptencoding\" fuera de un archivo de instrucciones " "ejecutables" -#: ex_cmds2.c:3690 msgid "E168: :finish used outside of a sourced file" msgstr "" "E168: Ha usado \":finish\" fuera de un archivo de instrucciones ejecutables" -#: ex_cmds2.c:4012 #, c-format msgid "Current %slanguage: \"%s\"" msgstr "Idioma actual %s: \"%s\"" -#: ex_cmds2.c:4029 #, c-format msgid "E197: Cannot set language to \"%s\"" msgstr "E197: No se pudo establecer la opción del idioma a \"%s\"" -#: ex_docmd.c:626 msgid "Entering Ex mode. Type \"visual\" to go to Normal mode." msgstr "Entrando al modo Ex. Escriba \"visual\" para ir al modo Normal" # must be at EOF -#: ex_docmd.c:681 msgid "E501: At end-of-file" msgstr "E501: Estoy al final del archivo" -#: ex_docmd.c:780 msgid "E169: Command too recursive" msgstr "E169: Orden demasiado recursiva" -#: ex_docmd.c:1359 #, c-format msgid "E605: Exception not caught: %s" msgstr "E605: La excepción %s no se atrapó" -#: ex_docmd.c:1447 msgid "End of sourced file" msgstr "Fin del archivo de instrucciones ejecutables" -#: ex_docmd.c:1448 msgid "End of function" msgstr "Fin de la función" -#: ex_docmd.c:2096 msgid "E464: Ambiguous use of user-defined command" msgstr "E464: Uso ambiguo de una orden definida por el usuario" -#: ex_docmd.c:2110 msgid "E492: Not an editor command" msgstr "E492: No es una orden del editor" -#: ex_docmd.c:2242 msgid "E493: Backwards range given" msgstr "E493: Me ha dado un rango invertido" -#: ex_docmd.c:2246 msgid "Backwards range given, OK to swap" msgstr "Se devolvió un rango invertido, ¿puedo intercambiarlo?" -#: ex_docmd.c:2309 msgid "E494: Use w or w>>" msgstr "E494: Use \"w\" o \"w>>\"" -#: ex_docmd.c:4076 msgid "E319: Sorry, the command is not available in this version" msgstr "E319: Lo siento, esa orden no está disponible en esta versión" -#: ex_docmd.c:4425 msgid "E172: Only one file name allowed" msgstr "E172: Solo se permite un nombre de archivo" -#: ex_docmd.c:5036 msgid "1 more file to edit. Quit anyway?" msgstr "Un (1) archivo más para editar. ¿Cerrar de todas formas?" -#: ex_docmd.c:5039 #, c-format msgid "%d more files to edit. Quit anyway?" msgstr "Hay %d archivos más en edición. ¿Cerrar de todas formas?" -#: ex_docmd.c:5046 msgid "E173: 1 more file to edit" msgstr "E173: Un (1) archivo más para editar" -#: ex_docmd.c:5048 #, c-format msgid "E173: %ld more files to edit" msgstr "E173: Hay %ld archivos en edición" -#: ex_docmd.c:5142 msgid "E174: Command already exists: add ! to replace it" msgstr "E174: Ya existe esa orden. Añada \"!\" para reemplazarla" -#: ex_docmd.c:5264 msgid "" "\n" " Name Args Range Complete Definition" @@ -1581,389 +1233,298 @@ msgstr "" "\n" " Nombre Args Rango Completar Definición" -#: ex_docmd.c:5357 msgid "No user-defined commands found" msgstr "No se han encontrado órdenes definidos por el usuario" -#: ex_docmd.c:5389 msgid "E175: No attribute specified" msgstr "E175: No se ha especificado el atributo" -#: ex_docmd.c:5441 msgid "E176: Invalid number of arguments" msgstr "E176: El número de argumentos no es válido" -#: ex_docmd.c:5456 msgid "E177: Count cannot be specified twice" msgstr "E177: El recuento no se puede especificar dos veces" -#: ex_docmd.c:5466 msgid "E178: Invalid default value for count" msgstr "E178: El valor predeterminado para el recuento no es válido" -#: ex_docmd.c:5494 msgid "E179: argument required for -complete" msgstr "E179: se necesita un argumento para \"-complete\"" -#: ex_docmd.c:5506 #, c-format msgid "E181: Invalid attribute: %s" msgstr "E181: El atributo no es válido: %s" -#: ex_docmd.c:5552 msgid "E182: Invalid command name" msgstr "E182: El nombre de la orden no es válido" -#: ex_docmd.c:5567 msgid "E183: User defined commands must start with an uppercase letter" msgstr "" "E183: Las órdenes definidas por el usuario deben comenzar con mayúscula" -#: ex_docmd.c:5635 #, c-format msgid "E184: No such user-defined command: %s" msgstr "E184: No existe esa orden definida por el usuario: %s" -#: ex_docmd.c:6187 #, c-format msgid "E180: Invalid complete value: %s" msgstr "E180: El valor para completar no es válido: %s" -#: ex_docmd.c:6198 msgid "E468: Completion argument only allowed for custom completion" msgstr "" "E468: El argumento de finalización solo se permite en finalizaciones " "definidas por el usuario" -#: ex_docmd.c:6206 msgid "E467: Custom completion requires a function argument" msgstr "" "E467: Las finalizaciones definidas por el usuario requieren de un argumento " "de función" -#: ex_docmd.c:6222 #, c-format msgid "E185: Cannot find color scheme %s" msgstr "E185: No se pudo encontrar el esquema de colores %s" -#: ex_docmd.c:6230 msgid "Greetings, Vim user!" msgstr "¡Saludos, usuario de Vim!" -#: ex_docmd.c:6448 msgid "E784: Cannot close last tab page" msgstr "E784: No se pudo cerrar la última ventana" -#: ex_docmd.c:6490 msgid "Already only one tab page" msgstr "Solo hay una ventana" -#: ex_docmd.c:7177 msgid "Edit File in new window" msgstr "Editar archivo en una ventana nueva" -#: ex_docmd.c:7303 #, c-format msgid "Tab page %d" msgstr "Página %d" -#: ex_docmd.c:7695 msgid "No swap file" msgstr "No hay archivo de intercambio" -#: ex_docmd.c:7800 msgid "Append File" msgstr "Añadir archivo" -#: ex_docmd.c:7899 msgid "E747: Cannot change directory, buffer is modified (add ! to override)" msgstr "" "E747: No se pudo cambiar de directorio, el búfer fue modificado (añada ! " "para forzar la orden)" -#: ex_docmd.c:7908 msgid "E186: No previous directory" msgstr "E186: No hay un directorio previo" -#: ex_docmd.c:7989 msgid "E187: Unknown" msgstr "E187: Desconocido" -#: ex_docmd.c:8084 msgid "E465: :winsize requires two number arguments" msgstr "E465: \":winsize\" requiere de dos argumentos numéricos" -#: ex_docmd.c:8146 #, c-format msgid "Window position: X %d, Y %d" msgstr "Posición de la ventana: X %d, Y %d" -#: ex_docmd.c:8151 msgid "E188: Obtaining window position not implemented for this platform" msgstr "" "E188: Obtener la posición de la ventana no está implementado en esta " "plataforma" -#: ex_docmd.c:8161 msgid "E466: :winpos requires two number arguments" msgstr "E466: \":winpos\" requiere de dos argumentos numéricos" -#: ex_docmd.c:8499 msgid "Save Redirection" msgstr "Guardar redirección" -#: ex_docmd.c:8730 msgid "Save View" msgstr "Guardar vista" -#: ex_docmd.c:8731 msgid "Save Session" msgstr "Guardar sesión" -#: ex_docmd.c:8733 msgid "Save Setup" msgstr "Guardar configuración" -#: ex_docmd.c:8889 #, c-format msgid "E739: Cannot create directory: %s" msgstr "E739: No se pudo crear directorio: %s" -#: ex_docmd.c:8918 #, c-format msgid "E189: \"%s\" exists (add ! to override)" msgstr "E189: \"%s\" ya existe (añada ! para sobreescribir.)" -#: ex_docmd.c:8923 #, c-format msgid "E190: Cannot open \"%s\" for writing" msgstr "E190: No se pudo abrir \"%s\" para escrbir" # set mark -#. set mark -#: ex_docmd.c:8947 msgid "E191: Argument must be a letter or forward/backward quote" msgstr "" "E191: El argumento debe ser una letra o una comilla simple/comilla simple " "invertida" -#: ex_docmd.c:8994 msgid "E192: Recursive use of :normal too deep" msgstr "E192: Excesivo uso recursivo de \":normal\"" -#: ex_docmd.c:9593 msgid "E809: #< is not available without the +eval feature" msgstr "E809: #< no está disponible sin la característica \"+eval\"" -#: ex_docmd.c:9602 msgid "E194: No alternate file name to substitute for '#'" msgstr "E194: No hay un nombre de archivo alterno que sustituya a '#'" -#: ex_docmd.c:9643 msgid "E495: no autocommand file name to substitute for \"<afile>\"" msgstr "" "E495: No se ha dado un nombre de archivo de auto-órdenes para sustituir a " "\"<afile>\"" -#: ex_docmd.c:9652 msgid "E496: no autocommand buffer number to substitute for \"<abuf>\"" msgstr "E496: No existe un búfer de auto-órdenes para sustituir por \"<abuf>\"" -#: ex_docmd.c:9663 msgid "E497: no autocommand match name to substitute for \"<amatch>\"" msgstr "" "E497: Ningún nombre de auto-orden concuerda para sustituir \"<amatch>\"" -#: ex_docmd.c:9673 msgid "E498: no :source file name to substitute for \"<sfile>\"" msgstr "" "E498: No hay un nombre de archivo \":source\" que sustituya a \"<sfile>\"" -#: ex_docmd.c:9715 #, no-c-format msgid "E499: Empty file name for '%' or '#', only works with \":p:h\"" msgstr "" "E499: Un nombre de archivo vacío para \"%\" o \"#\" solo funciona con \":p:h" "\"" -#: ex_docmd.c:9717 msgid "E500: Evaluates to an empty string" msgstr "E500: La expresión evalúa a una cadena vacía" -#: ex_docmd.c:10794 msgid "E195: Cannot open viminfo file for reading" msgstr "E195: No se pudo abrir el archivo \"viminfo\" para lectura" -#: ex_docmd.c:10964 msgid "E196: No digraphs in this version" msgstr "E196: No hay dígrafos en esta versión" -#: ex_eval.c:441 msgid "E608: Cannot :throw exceptions with 'Vim' prefix" msgstr "" "E608: No se pudo lanzar (':throw') excepciones si tienen el prefijo 'Vim'" # always scroll up, don't overwrite -#. always scroll up, don't overwrite -#: ex_eval.c:534 #, c-format msgid "Exception thrown: %s" msgstr "Excepción lanzada: %s" -#: ex_eval.c:588 #, c-format msgid "Exception finished: %s" msgstr "Excepción terminada: %s" -#: ex_eval.c:589 #, c-format msgid "Exception discarded: %s" msgstr "Excepción descartada: %s" -#: ex_eval.c:635 ex_eval.c:687 #, c-format msgid "%s, line %ld" msgstr "%s, en la línea %ld" # always scroll up, don't overwrite -#. always scroll up, don't overwrite -#: ex_eval.c:657 #, c-format msgid "Exception caught: %s" msgstr "Excepción atrapada: %s" -#: ex_eval.c:737 #, c-format msgid "%s made pending" msgstr "%s ha pasado a la lista de pendientes" -#: ex_eval.c:740 #, c-format msgid "%s resumed" msgstr "%s continuado" -#: ex_eval.c:744 #, c-format msgid "%s discarded" msgstr "%s descartado" -#: ex_eval.c:771 msgid "Exception" msgstr "Excepción" -#: ex_eval.c:777 msgid "Error and interrupt" msgstr "Error e interrupción" -#: ex_eval.c:779 gui.c:4870 gui_xmdlg.c:689 gui_xmdlg.c:808 os_mswin.c:597 msgid "Error" msgstr "Error" # if (pending & CSTP_INTERRUPT) -#. if (pending & CSTP_INTERRUPT) -#: ex_eval.c:781 msgid "Interrupt" msgstr "Interrupción" -#: ex_eval.c:873 msgid "E579: :if nesting too deep" msgstr "E579: ¡\":if\" anidado en exceso!" -#: ex_eval.c:910 msgid "E580: :endif without :if" msgstr "E580: ¡\":endif\" sin un \":if\"!" -#: ex_eval.c:955 msgid "E581: :else without :if" msgstr "E581: ¡\":else\" sin un \":if\"!" -#: ex_eval.c:958 msgid "E582: :elseif without :if" msgstr "E582: ¡\":elseif\" sin un \":if\"!" -#: ex_eval.c:965 msgid "E583: multiple :else" msgstr "E583: ¡\":else\" múltiple!" -#: ex_eval.c:968 msgid "E584: :elseif after :else" msgstr "E584: ¡\":elseif\" después de \":else\"!" -#: ex_eval.c:1035 msgid "E585: :while/:for nesting too deep" msgstr "E585: ¡\":while\" anidado en exceso!" -#: ex_eval.c:1133 msgid "E586: :continue without :while or :for" msgstr "E586: ¡\":continue\" sin un \":while\" o \":for\"!" -#: ex_eval.c:1172 msgid "E587: :break without :while or :for" msgstr "E587: ¡\":break\" sin \":while\" o \":for\"!" -#: ex_eval.c:1222 msgid "E732: Using :endfor with :while" msgstr "E732: Usando \":endfor\" con \":while\"" -#: ex_eval.c:1224 msgid "E733: Using :endwhile with :for" msgstr "E733: Usando \":endwhile\" con \":for\"" -#: ex_eval.c:1399 msgid "E601: :try nesting too deep" msgstr "E601: ¡\":try\" anidado en exceso!" -#: ex_eval.c:1479 msgid "E603: :catch without :try" msgstr "E603: ¡\":catch\" sin un \":try\"!" # Give up for a ":catch" after ":finally" and ignore it. # * Just parse. -#. Give up for a ":catch" after ":finally" and ignore it. -#. * Just parse. -#: ex_eval.c:1498 msgid "E604: :catch after :finally" msgstr "E604: ¡\":catch\" después de \":finally\"!" -#: ex_eval.c:1632 msgid "E606: :finally without :try" msgstr "E606: ¡\":finally\" sin un \":try\"!" # Give up for a multiple ":finally" and ignore it. -#. Give up for a multiple ":finally" and ignore it. -#: ex_eval.c:1652 msgid "E607: multiple :finally" msgstr "E607: ¡\":finally\" múltiple!" -#: ex_eval.c:1762 msgid "E602: :endtry without :try" msgstr "E602: ¡\":endtry\" sin un \":try\"!" -#: ex_eval.c:2267 msgid "E193: :endfunction not inside a function" msgstr "E193: ¡\":endfunction\" no está dentro de una función!" -#: ex_getln.c:2010 msgid "E788: Not allowed to edit another buffer now" msgstr "E788: No se permite editar otro búfer en este momento" -#: ex_getln.c:2025 msgid "E811: Not allowed to change buffer information now" msgstr "E811: No se permite cambiar la información del búfer en este momento" -#: ex_getln.c:3924 msgid "tagname" msgstr "Nombre de la etiqueta (\"tagname\")" -#: ex_getln.c:3927 msgid " kind file\n" msgstr " tipo de archivo\n" -#: ex_getln.c:5676 msgid "'history' option is zero" msgstr "La opción 'history' (historia) es cero" -#: ex_getln.c:5947 #, c-format msgid "" "\n" @@ -1972,252 +1533,194 @@ msgstr "" "\n" "# Historia de %s (de lo más nuevo a lo más antiguo):\n" -#: ex_getln.c:5948 msgid "Command Line" msgstr "Línea de órdenes" -#: ex_getln.c:5949 msgid "Search String" msgstr "Cadena de búsqueda" -#: ex_getln.c:5950 msgid "Expression" msgstr "Expresión" -#: ex_getln.c:5951 msgid "Input Line" msgstr "Línea de entrada" -#: ex_getln.c:5989 msgid "E198: cmd_pchar beyond the command length" msgstr "E198: \"cmd_pchar\" más allá de la longitud de la orden" -#: ex_getln.c:6190 msgid "E199: Active window or buffer deleted" msgstr "E199: Se borró la ventana o el búfer activo" -#: fileio.c:153 msgid "E812: Autocommands changed buffer or buffer name" msgstr "E812: *Filtro* Las auto-órdenes no deben cambiar el búfer en uso" -#: fileio.c:408 msgid "Illegal file name" msgstr "Nombre de archivo ilegal" -#: fileio.c:437 fileio.c:591 fileio.c:3320 fileio.c:3371 msgid "is a directory" msgstr "es un directorio" -#: fileio.c:439 msgid "is not a file" msgstr "no es un archivo" -#: fileio.c:452 msgid "is a device (disabled with 'opendevice' option)" msgstr "es un dispositivo (desactivado con la opción 'opendevice')" -#: fileio.c:628 fileio.c:4605 msgid "[New File]" msgstr "[Archivo nuevo]" -#: fileio.c:631 msgid "[New DIRECTORY]" msgstr "[Directorio nuevo]" -#: fileio.c:665 msgid "[File too big]" msgstr "[El archivo es demasiado grande]" -#: fileio.c:667 msgid "[Permission Denied]" msgstr "[Permiso denegado]" -#: fileio.c:800 msgid "E200: *ReadPre autocommands made the file unreadable" msgstr "E200: Las auto-órdenes \"*ReadPre\" hicieron ilegible el archivo" -#: fileio.c:802 msgid "E201: *ReadPre autocommands must not change current buffer" msgstr "E201: Las auto-órdenes \"*ReadPre\" no deben cambiar el búfer en uso" -#: fileio.c:823 msgid "Vim: Reading from stdin...\n" msgstr "Vim: Leyendo la entrada estándar...\n" -#: fileio.c:829 msgid "Reading from stdin..." msgstr "Leyendo la entrada estándar..." # Re-opening the original file failed! -#. Re-opening the original file failed! -#: fileio.c:1128 msgid "E202: Conversion made file unreadable!" msgstr "E202: ¡La conversión ha hecho ilegible el archivo!" -#: fileio.c:2362 msgid "[fifo/socket]" msgstr "[fifo/socket]" -#: fileio.c:2369 msgid "[fifo]" msgstr "[fifo]" -#: fileio.c:2376 msgid "[socket]" msgstr "[socket]" -#: fileio.c:2384 msgid "[character special]" msgstr "[carácter especial]" -#: fileio.c:2391 netbeans.c:3632 msgid "[RO]" msgstr "[RO]" -#: fileio.c:2401 msgid "[CR missing]" msgstr "[Falta un CR]" -#: fileio.c:2406 msgid "[long lines split]" msgstr "[se han dividido las líneas largas]" -#: fileio.c:2412 fileio.c:4589 msgid "[NOT converted]" msgstr "[NO se ha convertido]" -#: fileio.c:2417 fileio.c:4594 msgid "[converted]" msgstr "[convertido]" -#: fileio.c:2424 fileio.c:4619 msgid "[crypted]" msgstr "[cifrado]" -#: fileio.c:2432 #, c-format msgid "[CONVERSION ERROR in line %ld]" msgstr "[ERROR DE CONVERSIÓN en línea %ld]" -#: fileio.c:2438 #, c-format msgid "[ILLEGAL BYTE in line %ld]" msgstr "[BYTE ILEGAL en la línea %ld]" -#: fileio.c:2445 msgid "[READ ERRORS]" msgstr "[ERRORES DE LECTURA]" -#: fileio.c:2723 msgid "Can't find temp file for conversion" msgstr "No se pudo encontrar el archivo temporal para la conversión" -#: fileio.c:2730 msgid "Conversion with 'charconvert' failed" msgstr "Falló la conversión con 'charconvert'" -#: fileio.c:2733 msgid "can't read output of 'charconvert'" msgstr "No se pudo leer el resultado de 'charconvert'" -#: fileio.c:3165 msgid "E676: No matching autocommands for acwrite buffer" msgstr "E676: No coincide ninguna auto-orden para \"acwrite\"en el búfer" -#: fileio.c:3200 msgid "E203: Autocommands deleted or unloaded buffer to be written" msgstr "" "E203: Las auto-órdenes fueron suprimidas o el búfer se descargó para ser " "grabado en disco" -#: fileio.c:3223 msgid "E204: Autocommand changed number of lines in unexpected way" msgstr "" "E204: La auto-orden ha cambiado el número de líneas en forma inesperada" -#: fileio.c:3263 msgid "NetBeans disallows writes of unmodified buffers" msgstr "NetBeans no permite que se escriba sobre búfers sin modificar" -#: fileio.c:3271 msgid "Partial writes disallowed for NetBeans buffers" msgstr "No se permite la escritura parcial de los búfers de NetBeans" -#: fileio.c:3326 fileio.c:3344 msgid "is not a file or writable device" msgstr "no es un archivo o dispositivo en el que se pueda escribir" -#: fileio.c:3355 msgid "writing to device disabled with 'opendevice' option" msgstr "" "se ha desactivado la escritura en dispositivo con la opción 'opendevice'" -#: fileio.c:3397 netbeans.c:3694 msgid "is read-only (add ! to override)" msgstr "es de solo lectura (añada ! para sobreescribir)" -#: fileio.c:3761 msgid "E506: Can't write to backup file (add ! to override)" msgstr "" "E506: No se pudo escribir en el archivo de recuperación " "(añada ! para forzar la orden)" -#: fileio.c:3773 msgid "E507: Close error for backup file (add ! to override)" msgstr "" "E507: Error al cerrar el archivo de la copia de seguridad (añada ! para " "forzar la orden)" -#: fileio.c:3775 msgid "E508: Can't read file for backup (add ! to override)" msgstr "" "E508: No se pudo leer el archivo para crear la copia de seguridad (añada ! " "para forzar la orden)" -#: fileio.c:3794 msgid "E509: Cannot create backup file (add ! to override)" msgstr "" "E509: No se pudo crear el archivo para la copia de seguridad (añada ! para " "forzar la orden)" -#: fileio.c:3896 msgid "E510: Can't make backup file (add ! to override)" msgstr "" "E510: No se pudo hacer un archivo de copia de seguridad (añada ! para forzar " "la orden)" -#: fileio.c:4067 msgid "E214: Can't find temp file for writing" msgstr "E214: No se pudo encontrar el archivo temporal para escribir en él" -#: fileio.c:4085 msgid "E213: Cannot convert (add ! to write without conversion)" msgstr "" "E213: No se pudo convertir (añada \"!\" para escribir el archivo sin " "conversión)" -#: fileio.c:4120 msgid "E166: Can't open linked file for writing" msgstr "E166: No se pudo abrir el archivo enlazado para escribir" -#: fileio.c:4124 msgid "E212: Can't open file for writing" msgstr "E212: No se pudo abrir el archivo para escribir en él" -#: fileio.c:4405 msgid "E667: Fsync failed" msgstr "E667: Falló \"fsync\" (sincronización de archivo)" -#: fileio.c:4444 msgid "E512: Close failed" msgstr "E512: Falló el cierre del archivo" -#: fileio.c:4496 msgid "E513: write error, conversion failed (make 'fenc' empty to override)" msgstr "" "E513: Error de escritura, la conversión falló (vacíe 'fenc' para forzar)." -#: fileio.c:4501 #, c-format msgid "" "E513: write error, conversion failed in line %ld (make 'fenc' empty to " @@ -2226,56 +1729,43 @@ msgstr "" "E513: Error de escritura, la conversión falló en la línea %ld(vacíe 'fenc' " "para forzar)" -#: fileio.c:4510 msgid "E514: write error (file system full?)" msgstr "E514: Error de escritura (¿Sistema de archivos lleno?)" -#: fileio.c:4578 msgid " CONVERSION ERROR" msgstr " ERROR DE CONVERSIÓN" -#: fileio.c:4583 #, c-format msgid " in line %ld;" msgstr "en la línea %ld" -#: fileio.c:4600 msgid "[Device]" msgstr "[Dispositivo]" -#: fileio.c:4605 msgid "[New]" msgstr "[Nuevo]" -#: fileio.c:4627 msgid " [a]" msgstr " [a]" -#: fileio.c:4627 msgid " appended" msgstr " añadido" -#: fileio.c:4629 msgid " [w]" msgstr " [w]" -#: fileio.c:4629 msgid " written" msgstr " escritos" -#: fileio.c:4684 msgid "E205: Patchmode: can't save original file" msgstr "E205: Modo de parcheo: no se puede guardar el archivo original" -#: fileio.c:4707 msgid "E206: patchmode: can't touch empty original file" msgstr "E206: Modo de parcheo: no se puede tocar el archivo original vacío" -#: fileio.c:4722 msgid "E207: Can't delete backup file" msgstr "E207: No se pudo borrar el archivo de respaldo" -#: fileio.c:4788 msgid "" "\n" "WARNING: Original file may be lost or damaged\n" @@ -2283,99 +1773,75 @@ msgstr "" "\n" "ADVERTENCIA: el archivo original puede haberse perdido o dañado\n" -#: fileio.c:4790 msgid "don't quit the editor until the file is successfully written!" msgstr "¡no salga del editor hasta que el archivo se haya escrito!" -#: fileio.c:4932 msgid "[dos]" msgstr "[DOS]" -#: fileio.c:4932 msgid "[dos format]" msgstr "[formato DOS]" -#: fileio.c:4939 msgid "[mac]" msgstr "[Mac]" -#: fileio.c:4939 msgid "[mac format]" msgstr "[formato Mac]" -#: fileio.c:4946 msgid "[unix]" msgstr "[UNIX]" -#: fileio.c:4946 msgid "[unix format]" msgstr "[formato UNIX]" -#: fileio.c:4973 msgid "1 line, " msgstr "1 línea, " -#: fileio.c:4975 #, c-format msgid "%ld lines, " msgstr "%ld líneas, " -#: fileio.c:4978 msgid "1 character" msgstr "1 carácter" -#: fileio.c:4980 #, c-format msgid "%ld characters" msgstr "%ld caracteres" -#: fileio.c:4990 netbeans.c:3637 msgid "[noeol]" msgstr "[no hay fin de línea]" -#: fileio.c:4990 netbeans.c:3637 msgid "[Incomplete last line]" msgstr "[Última línea incompleta]" # don't overwrite messages here # must give this prompt # don't use emsg() here, don't want to flush the buffers -#. don't overwrite messages here -#. must give this prompt -#. don't use emsg() here, don't want to flush the buffers -#: fileio.c:5009 msgid "WARNING: The file has been changed since reading it!!!" msgstr "ADVERTENCIA: ¡¡¡El archivo ha cambiado desde que se leyó!!!" -#: fileio.c:5011 msgid "Do you really want to write to it" msgstr "¿Desea realmente escribir al archivo?" -#: fileio.c:6375 #, c-format msgid "E208: Error writing to \"%s\"" msgstr "E208: Error al escribir a \"%s\"" -#: fileio.c:6382 #, c-format msgid "E209: Error closing \"%s\"" msgstr "E209: Error al cerrar \"%s\"" -#: fileio.c:6385 #, c-format msgid "E210: Error reading \"%s\"" msgstr "E210: Error al leer \"%s\"" -#: fileio.c:6647 msgid "E246: FileChangedShell autocommand deleted buffer" msgstr "E246: La auto-orden \"FileChangedShell\" ha borrado el búfer" -#: fileio.c:6662 #, c-format msgid "E211: File \"%s\" no longer available" msgstr "E211: El archivo \"%s\" ya no está disponible" -#: fileio.c:6677 #, c-format msgid "" "W12: Warning: File \"%s\" has changed and the buffer was changed in Vim as " @@ -2384,43 +1850,35 @@ msgstr "" "W12: Advertencia: el archivo \"%s\" ha cambiado y el búfer se modificó " "también en Vim" -#: fileio.c:6678 msgid "See \":help W12\" for more info." msgstr "Véase \":help W12\" para más información" -#: fileio.c:6682 #, c-format msgid "W11: Warning: File \"%s\" has changed since editing started" msgstr "" "W11: Advertencia: el archivo \"%s\" ha cambiado desde que comenzó la edición" -#: fileio.c:6683 msgid "See \":help W11\" for more info." msgstr "Véase \":help W11\" para más información." -#: fileio.c:6687 #, c-format msgid "W16: Warning: Mode of file \"%s\" has changed since editing started" msgstr "" "W16: Advertencia: el modo del archivo \"%s\" ha cambiado desde que comenzó " "la edición" -#: fileio.c:6688 msgid "See \":help W16\" for more info." msgstr "Véase \":help W16\" para más información." -#: fileio.c:6703 #, c-format msgid "W13: Warning: File \"%s\" has been created after editing started" msgstr "" "W13: Advertencia: la creación del archivo \"%s\" es posterior al inicio de " "la edición" -#: fileio.c:6733 msgid "Warning" msgstr "Advertencia" -#: fileio.c:6734 msgid "" "&OK\n" "&Load File" @@ -2428,50 +1886,39 @@ msgstr "" "&OK\n" "&Cargar archivo" -#: fileio.c:6857 #, c-format msgid "E462: Could not prepare for reloading \"%s\"" msgstr "E462: No pude prepararme para recargar \"%s\"" -#: fileio.c:6876 #, c-format msgid "E321: Could not reload \"%s\"" msgstr "E321: No pude recargar \"%s\"" -#: fileio.c:7490 msgid "--Deleted--" msgstr "--Suprimido--" -#: fileio.c:7643 #, c-format msgid "auto-removing autocommand: %s <buffer=%d>" msgstr "Auto-removiendo autocomando: %s <búfer=%d>" # the group doesn't exist -#. the group doesn't exist -#: fileio.c:7689 #, c-format msgid "E367: No such group: \"%s\"" msgstr "E367: No existe el grupo: %s" -#: fileio.c:7836 #, c-format msgid "E215: Illegal character after *: %s" msgstr "E215: Carácter ilegal después de *: %s" -#: fileio.c:7848 #, c-format msgid "E216: No such event: %s" msgstr "E216: No existe tal evento: %s" -#: fileio.c:7850 #, c-format msgid "E216: No such group or event: %s" msgstr "E216: No existe tal grupo o evento: %s" # Highlight title -#. Highlight title -#: fileio.c:8058 msgid "" "\n" "--- Autocommands ---" @@ -2479,188 +1926,147 @@ msgstr "" "\n" "--- Auto-órdenes ---" -#: fileio.c:8294 #, c-format msgid "E680: <buffer=%d>: invalid buffer number " msgstr "E680: número de <búfer=%d> no válido" -#: fileio.c:8391 msgid "E217: Can't execute autocommands for ALL events" msgstr "E217: No se pueden ejecutar las auto-órdenes para TODOS los eventos" -#: fileio.c:8414 msgid "No matching autocommands" msgstr "No coincide ninguna auto-orden" -#: fileio.c:8862 msgid "E218: autocommand nesting too deep" msgstr "E218: La auto-orden se anida en exceso" -#: fileio.c:9215 #, c-format msgid "%s Autocommands for \"%s\"" msgstr "%s Auto-órdenes para \"%s\"" -#: fileio.c:9225 #, c-format msgid "Executing %s" msgstr "Ejecutando %s" # always scroll up, don't overwrite -#: fileio.c:9294 #, c-format msgid "autocommand %s" msgstr "auto-orden %s" -#: fileio.c:9977 msgid "E219: Missing {." msgstr "E219: Falta un {." -#: fileio.c:9979 msgid "E220: Missing }." msgstr "E220: Falta un }." -#: fold.c:68 msgid "E490: No fold found" msgstr "E490: No se encontró ningún pliegue" -#: fold.c:593 msgid "E350: Cannot create fold with current 'foldmethod'" msgstr "E350: No se puede crear el pliegue con el 'foldmethod' actual activo" -#: fold.c:595 msgid "E351: Cannot delete fold with current 'foldmethod'" msgstr "E351: No se puede borrar el pliegue con el 'foldmethod' activo" -#: fold.c:1999 #, c-format msgid "+--%3ld lines folded " msgstr "+--%3ld líneas plegadas" -#: getchar.c:252 msgid "E222: Add to read buffer" msgstr "E222: Añadir al búfer de lectura" -#: getchar.c:2407 msgid "E223: recursive mapping" msgstr "E223: Asociación recursiva" -#: getchar.c:3366 #, c-format msgid "E224: global abbreviation already exists for %s" msgstr "E224: Ya existe una abreviatura global para %s" -#: getchar.c:3369 #, c-format msgid "E225: global mapping already exists for %s" msgstr "E225: Ya existe una asociación global para %s" -#: getchar.c:3501 #, c-format msgid "E226: abbreviation already exists for %s" msgstr "E226: Ya existe una abreviatura para %s" -#: getchar.c:3504 #, c-format msgid "E227: mapping already exists for %s" msgstr "E227: Ya existe una asociación para %s" -#: getchar.c:3572 msgid "No abbreviation found" msgstr "No se encontró ninguna abreviatura" -#: getchar.c:3574 msgid "No mapping found" msgstr "No se encontró ninguna asociación de teclado" -#: getchar.c:4687 msgid "E228: makemap: Illegal mode" msgstr "E228: \"makemap\": modo ilegal" -#: gui.c:226 msgid "E229: Cannot start the GUI" msgstr "E229: No se pudo iniciar la interfaz gráfica" -#: gui.c:361 #, c-format msgid "E230: Cannot read from \"%s\"" msgstr "E230: No se pudo leer desde \"%s\"" -#: gui.c:487 msgid "E665: Cannot start GUI, no valid font found" msgstr "" "E665: No se pudo iniciar la interfaz gráfica (GUI), no se encontró ninguna " "tipografía de impresión válida" -#: gui.c:492 msgid "E231: 'guifontwide' invalid" msgstr "E231: El valor de 'guifontwide' no es válido" -#: gui.c:603 msgid "E599: Value of 'imactivatekey' is invalid" msgstr "E599: El valor de 'imactivatekey' no es válido" -#: gui.c:4526 #, c-format msgid "E254: Cannot allocate color %s" msgstr "E254: No se pudo asignar el color %s" -#: gui.c:5107 msgid "No match at cursor, finding next" msgstr "" "No hay correspondencia en la posición del cursor, buscando la siguiente" -#: gui_at_fs.c:300 msgid "<cannot open> " msgstr "<no se puede abrir> " -#: gui_at_fs.c:1133 #, c-format msgid "E616: vim_SelFile: can't get font %s" msgstr "" "E616: \"vim_SelFile\": No se puede hallar la tipografía de impresión %s" -#: gui_at_fs.c:2764 msgid "E614: vim_SelFile: can't return to current directory" msgstr "E614: \"vim_SelFile\": no puedo regresar al directorio actual" -#: gui_at_fs.c:2784 msgid "Pathname:" msgstr "Nombre de la ruta:" -#: gui_at_fs.c:2790 msgid "E615: vim_SelFile: can't get current directory" msgstr "" "E615: \"vim_SelFile\": No se pudo obtener la ubicación del directorio actual" -#: gui_at_fs.c:2798 gui_xmdlg.c:931 msgid "OK" msgstr "OK" -#: gui_at_fs.c:2798 gui_gtk.c:2831 gui_xmdlg.c:940 msgid "Cancel" msgstr "Cancelar" -#: gui_at_sb.c:490 msgid "Scrollbar Widget: Could not get geometry of thumb pixmap." msgstr "" "Scrollbar Widget: No pude obtener la geometría de la miniatura \"pixmap\"" -#: gui_athena.c:2160 gui_motif.c:2588 msgid "Vim dialog" msgstr "Diálogo de Vim" -#: gui_beval.c:200 gui_w32.c:4728 msgid "E232: Cannot create BalloonEval with both message and callback" msgstr "" "E232: No se pudo crear un \"BalloonEval\" que contenga tanto el mensaje como " "la llamada de retorno" -#: gui_gtk.c:1694 msgid "Vim dialog..." msgstr "Diálogo de Vim..." -#: gui_gtk.c:2145 message.c:3654 msgid "" "&Yes\n" "&No\n" @@ -2670,227 +2076,172 @@ msgstr "" "&No\n" "&Cancelar" -#: gui_gtk.c:2356 msgid "Input _Methods" msgstr "Métodos de Entrada (\"Input Methods\")" -#: gui_gtk.c:2634 gui_motif.c:3760 msgid "VIM - Search and Replace..." msgstr "VIM - Buscar y reemplazar..." -#: gui_gtk.c:2642 gui_motif.c:3762 msgid "VIM - Search..." msgstr "VIM - Buscar..." -#: gui_gtk.c:2674 gui_motif.c:3871 msgid "Find what:" msgstr "¿Encontrar qué?:" -#: gui_gtk.c:2692 gui_motif.c:3904 msgid "Replace with:" msgstr "Reemplazar con:" # whole word only button -#. whole word only button -#: gui_gtk.c:2724 gui_motif.c:4025 msgid "Match whole word only" msgstr "Encontrar solo palabras completas" # match case button -#. match case button -#: gui_gtk.c:2735 gui_motif.c:4037 msgid "Match case" msgstr "La única coincidencia" -#: gui_gtk.c:2745 gui_motif.c:3976 msgid "Direction" msgstr "Dirección" # 'Up' and 'Down' buttons -#. 'Up' and 'Down' buttons -#: gui_gtk.c:2757 gui_motif.c:3989 msgid "Up" msgstr "Hacia arriba" -#: gui_gtk.c:2761 gui_motif.c:3998 msgid "Down" msgstr "Hacia abajo" -#: gui_gtk.c:2783 gui_gtk.c:2785 msgid "Find Next" msgstr "Encontrar siguiente" -#: gui_gtk.c:2802 gui_gtk.c:2804 msgid "Replace" msgstr "Reemplazar" -#: gui_gtk.c:2815 gui_gtk.c:2817 msgid "Replace All" msgstr "Reemplazar todos" -#: gui_gtk_x11.c:2417 msgid "Vim: Received \"die\" request from session manager\n" msgstr "Vim: Recibí una solicitud \"die\" del administrador de sesiones.\n" -#: gui_gtk_x11.c:3244 msgid "Close" msgstr "Cerrar" -#: gui_gtk_x11.c:3245 gui_w48.c:2375 msgid "New tab" msgstr "Pestaña nueva" -#: gui_gtk_x11.c:3246 msgid "Open Tab..." msgstr "Abrir pestaña..." -#: gui_gtk_x11.c:4025 msgid "Vim: Main window unexpectedly destroyed\n" msgstr "Vim: La ventana principal fue destruida inesperadamente.\n" -#: gui_gtk_x11.c:4746 msgid "Font Selection" msgstr "Selección de tipos de letra" -#: gui_motif.c:2355 msgid "&Filter" msgstr "&Filtro" -#: gui_motif.c:2356 gui_motif.c:3839 msgid "&Cancel" msgstr "&Cancelar" -#: gui_motif.c:2357 msgid "Directories" msgstr "Directorios" -#: gui_motif.c:2358 msgid "Filter" msgstr "Filtro" -#: gui_motif.c:2359 msgid "&Help" msgstr "&Ayuda" -#: gui_motif.c:2360 msgid "Files" msgstr "Archivos" -#: gui_motif.c:2361 msgid "&OK" msgstr "&OK" -#: gui_motif.c:2362 msgid "Selection" msgstr "Selección" -#: gui_motif.c:3791 msgid "Find &Next" msgstr "Encontrar &Siguiente" -#: gui_motif.c:3806 msgid "&Replace" msgstr "&Reemplazar" -#: gui_motif.c:3817 msgid "Replace &All" msgstr "Reemplazar &Todos" -#: gui_motif.c:3828 msgid "&Undo" msgstr "&Deshacer" -#: gui_w32.c:1177 #, c-format msgid "E671: Cannot find window title \"%s\"" msgstr "E671: No se pudo encontrar el título de la ventana \"%s\"" -#: gui_w32.c:1190 #, c-format msgid "E243: Argument not supported: \"-%s\"; Use the OLE version." msgstr "E243: Argumento no admitido: \"-%s\"; use la versión OLE." -#: gui_w32.c:1442 msgid "E672: Unable to open window inside MDI application" msgstr "E672: Incapaz de abrir ventana dentro de la aplicación MDI" -#: gui_w48.c:2374 msgid "Close tab" msgstr "Cerrar Ventana" -#: gui_w48.c:2377 msgid "Open tab..." msgstr "Abrir pestaña..." -#: gui_w48.c:2633 msgid "Find string (use '\\\\' to find a '\\')" msgstr "Buscar cadena (use '\\\\' para encontrar un '\\')" -#: gui_w48.c:2669 msgid "Find & Replace (use '\\\\' to find a '\\')" msgstr "Buscar y reemplazar (use '\\\\' para encontrar un '\\')" -#. We fake this: Use a filter that doesn't select anything and a default -#. * file name that won't be used. -#: gui_w48.c:3463 msgid "Not Used" msgstr "Sin usar" -#: gui_w48.c:3464 msgid "Directory\t*.nothing\n" msgstr "Directorio\t*.nada\n" -#: gui_x11.c:1546 msgid "Vim E458: Cannot allocate colormap entry, some colors may be incorrect" msgstr "" "Vim E458: no se puede asignar una entrada al mapa de colores; algunos " "colores tal vez no sean correctos" -#: gui_x11.c:2138 #, c-format msgid "E250: Fonts for the following charsets are missing in fontset %s:" msgstr "" "E250: Faltan los tipos de letras para los siguientes conjuntos de caracteres " "en el conjunto de fuentes %s:" -#: gui_x11.c:2181 #, c-format msgid "E252: Fontset name: %s" msgstr "E252: Nombre del conjunto de tipos de letra: %s" -#: gui_x11.c:2182 #, c-format msgid "Font '%s' is not fixed-width" msgstr "La tipografía de impresión '%s' no es de ancho fijo" -#: gui_x11.c:2201 #, c-format msgid "E253: Fontset name: %s\n" msgstr "E253: Nombre del conjunto de tipografías de impresión: %s\n" -#: gui_x11.c:2202 #, c-format msgid "Font0: %s\n" msgstr "Tipo de letra de impresión 0: %s\n" -#: gui_x11.c:2203 #, c-format msgid "Font1: %s\n" msgstr "Tipo de letra de impresión 1: %s\n" -#: gui_x11.c:2204 #, c-format msgid "Font%ld width is not twice that of font0\n" msgstr "" "La anchura del tipo de letra de impresión %ld no es el doble de la " "de la tipografía de impresión 0\n" -#: gui_x11.c:2205 #, c-format msgid "Font0 width: %ld\n" msgstr "Anchura del tipo de letra de impresión 0: %ld\n" -#: gui_x11.c:2206 #, c-format msgid "" "Font1 width: %ld\n" @@ -2899,293 +2250,226 @@ msgstr "" "Anchura del tipo de letra de impresión 1: %ld\n" "\n" -#: gui_xmdlg.c:690 gui_xmdlg.c:809 msgid "Invalid font specification" msgstr "La especificación de tipo de letra no es válida" -#: gui_xmdlg.c:691 gui_xmdlg.c:810 msgid "&Dismiss" msgstr "&Cerrar" -#: gui_xmdlg.c:700 msgid "no specific match" msgstr "no hay una coincidencia especifica" -#: gui_xmdlg.c:909 msgid "Vim - Font Selector" msgstr "Vim - Selector de tipos de letra" -#: gui_xmdlg.c:978 msgid "Name:" msgstr "Nombre:" -#. create toggle button -#: gui_xmdlg.c:1018 msgid "Show size in Points" msgstr "Mostrar tamaño en puntos" -#: gui_xmdlg.c:1037 msgid "Encoding:" msgstr "Codificando:" -#: gui_xmdlg.c:1083 msgid "Font:" msgstr "Tipo de letra:" -#: gui_xmdlg.c:1116 msgid "Style:" msgstr "Estilo:" -#: gui_xmdlg.c:1148 msgid "Size:" msgstr "Tamaño:" -#: hangulin.c:610 msgid "E256: Hangul automata ERROR" msgstr "E256: ERROR del autómata Hangul" -#: hardcopy.c:210 msgid "E550: Missing colon" msgstr "E550: Falta un símbolo de dos puntos" -#: hardcopy.c:222 msgid "E551: Illegal component" msgstr "E551: Componente ilegal" -#: hardcopy.c:230 msgid "E552: digit expected" msgstr "E552: Se esperaba un dígito" -#: hardcopy.c:501 #, c-format msgid "Page %d" msgstr "Página %d" -#: hardcopy.c:658 msgid "No text to be printed" msgstr "No hay texto que imprimir" -#: hardcopy.c:736 #, c-format msgid "Printing page %d (%d%%)" msgstr "Imprimiendo la página %d (%d%%)" -#: hardcopy.c:748 #, c-format msgid " Copy %d of %d" msgstr "Copia %d de %d" -#: hardcopy.c:806 #, c-format msgid "Printed: %s" msgstr "Impreso: %s" -#: hardcopy.c:814 msgid "Printing aborted" msgstr "Impresión interrumpida" -#: hardcopy.c:1469 msgid "E455: Error writing to PostScript output file" msgstr "E455: Error escribiendo al archivo PostScript de salida" -#: hardcopy.c:1931 #, c-format msgid "E624: Can't open file \"%s\"" msgstr "E624: No se pudo abrir el archivo \"%s\"" -#: hardcopy.c:1941 hardcopy.c:2822 #, c-format msgid "E457: Can't read PostScript resource file \"%s\"" msgstr "E457: No se pudo leer el archivo de recursos de PostScript \"%s\"" -#: hardcopy.c:1957 #, c-format msgid "E618: file \"%s\" is not a PostScript resource file" msgstr "E618: El archivo \"%s\" no es un archivo de recursos PostScript" -#: hardcopy.c:1975 hardcopy.c:1994 hardcopy.c:2037 #, c-format msgid "E619: file \"%s\" is not a supported PostScript resource file" msgstr "E619: El archivo \"%s\" no es un recurso PostScript que pueda usar" -#: hardcopy.c:2056 #, c-format msgid "E621: \"%s\" resource file has wrong version" msgstr "E621: La versión del archivo de recursos \"%s\" es incorrecta" -#: hardcopy.c:2543 msgid "E673: Incompatible multi-byte encoding and character set." msgstr "E673: Codificación y set de caracteres multi-byte incompatibles" -#: hardcopy.c:2560 msgid "E674: printmbcharset cannot be empty with multi-byte encoding." msgstr "" "E674: \"printmbcharset\" no puede estar vacío en una codificación multi-byte" -#: hardcopy.c:2578 msgid "E675: No default font specified for multi-byte printing." msgstr "" "E675: No se ha definido un tipo de letra predeterminado para impresión " "multi-byte" -#: hardcopy.c:2771 msgid "E324: Can't open PostScript output file" msgstr "E324: No se pudo abrir el archivo PostScript de salida" -#: hardcopy.c:2808 #, c-format msgid "E456: Can't open file \"%s\"" msgstr "E456: No se pudo abrir el archivo %s" -#: hardcopy.c:2942 msgid "E456: Can't find PostScript resource file \"prolog.ps\"" msgstr "E456: No se encontró el archivo de recursos PostScript \"prolog.ps\"" -#: hardcopy.c:2955 msgid "E456: Can't find PostScript resource file \"cidfont.ps\"" msgstr "E456: No se encontró el archivo de recursos PostScript \"cidfont.ps\"" -#: hardcopy.c:2993 hardcopy.c:3015 hardcopy.c:3044 #, c-format msgid "E456: Can't find PostScript resource file \"%s.ps\"" msgstr "E456: No se encontró el archivo de recursos PostScript \"%s.ps\"" -#: hardcopy.c:3031 #, c-format msgid "E620: Unable to convert to print encoding \"%s\"" msgstr "E620: No se pudo convertir a la codificación de impresión \"%s\"" -#: hardcopy.c:3285 msgid "Sending to printer..." msgstr "Enviando a la impresora..." -#: hardcopy.c:3289 msgid "E365: Failed to print PostScript file" msgstr "E365: Falló la impresión del archivo PostScript" -#: hardcopy.c:3291 msgid "Print job sent." msgstr "Se ha enviado la tarea de impresión." -#: if_cscope.c:77 msgid "Add a new database" msgstr "Añadir una nueva base de datos" -#: if_cscope.c:79 msgid "Query for a pattern" msgstr "Petición de un patrón" -#: if_cscope.c:81 msgid "Show this message" msgstr "Mostrar este mensaje" -#: if_cscope.c:83 msgid "Kill a connection" msgstr "Matar una conexión" -#: if_cscope.c:85 msgid "Reinit all connections" msgstr "Reiniciar todas las conexiones" -#: if_cscope.c:87 msgid "Show connections" msgstr "Mostrar las conexiones" -#: if_cscope.c:95 #, c-format msgid "E560: Usage: cs[cope] %s" msgstr "E560: Forma de uso: cs[cope] %s" -#: if_cscope.c:236 msgid "This cscope command does not support splitting the window.\n" msgstr "Esta orden \"cscope\" no admite la división de la ventana.\n" -#: if_cscope.c:287 msgid "E562: Usage: cstag <ident>" msgstr "E562: Forma de uso: cstag <identificador>" -#: if_cscope.c:345 msgid "E257: cstag: tag not found" msgstr "E257: cstag: no se encontró la etiqueta" -#: if_cscope.c:515 #, c-format msgid "E563: stat(%s) error: %d" msgstr "E563: Error en stat(%s): %d" -#: if_cscope.c:525 msgid "E563: stat error" msgstr "E563: error en la función \"stat\"" -#: if_cscope.c:622 #, c-format msgid "E564: %s is not a directory or a valid cscope database" msgstr "E564: \"%s\" no es un directorio ni una base de datos válida de cscope" -#: if_cscope.c:640 #, c-format msgid "Added cscope database %s" msgstr "Se ha añadido la base de datos \"cscope\" %s" -#: if_cscope.c:695 #, c-format msgid "E262: error reading cscope connection %ld" msgstr "E262: Error al leer la conexión %ld con \"cscope\"" -#: if_cscope.c:802 msgid "E561: unknown cscope search type" msgstr "E561: Tipo de búsqueda desconocido para \"cscope\"" -#: if_cscope.c:866 if_cscope.c:905 msgid "E566: Could not create cscope pipes" msgstr "E566: Falló la conexión \"pipe\" para comunicarse con \"cscope\"" -#: if_cscope.c:882 msgid "E622: Could not fork for cscope" msgstr "" "E622: No se pudo crear un nuevo proceso (\"fork\") para usar \"cscope\"" -#: if_cscope.c:992 if_cscope.c:1029 msgid "cs_create_connection exec failed" msgstr "Falló la ejecución de \"cs_create_connection\"" -#: if_cscope.c:1002 if_cscope.c:1042 msgid "cs_create_connection: fdopen for to_fp failed" msgstr "\"cs_create_connection\": Falló \"fdopen\" para \"to_fp\"" -#: if_cscope.c:1004 if_cscope.c:1046 msgid "cs_create_connection: fdopen for fr_fp failed" msgstr "\"cs_create_connection\": Falló \"fdopen\" para \"fr_fp\"" -#: if_cscope.c:1030 msgid "E623: Could not spawn cscope process" msgstr "E623: No se pudo crear un nuevo proceso (\"spawn\") de \"cscope\"" -#: if_cscope.c:1074 msgid "E567: no cscope connections" msgstr "E567: No hay conexiones con \"cscope\"" -#: if_cscope.c:1154 #, c-format msgid "E259: no matches found for cscope query %s of %s" msgstr "" "E259: No se encontraron coincidencias para la búsqueda \"cscope\" %s de %s" -#: if_cscope.c:1215 #, c-format msgid "E469: invalid cscopequickfix flag %c for %c" msgstr "E469: La marca \"cscopequickfix\" %c para %c no es válida" -#: if_cscope.c:1307 msgid "cscope commands:\n" msgstr "órdenes de \"cscope\":\n" -#: if_cscope.c:1316 #, c-format msgid "%-5s: %s%*s (Usage: %s)" msgstr "%-5s: %s%*s (Modo de uso: %s)" -#: if_cscope.c:1321 msgid "" "\n" " c: Find functions calling this function\n" @@ -3207,42 +2491,33 @@ msgstr "" " s: Encontrar este símbolo de C\n" " t: Encontrar asignaciones a\n" -#: if_cscope.c:1409 #, c-format msgid "E625: cannot open cscope database: %s" msgstr "E625: No se pudo abrir la base de datos \"cscope\": %s" -#: if_cscope.c:1427 msgid "E626: cannot get cscope database information" msgstr "" "E626: No se pudo obtener información acerca de la base de datos \"cscope\"" -#: if_cscope.c:1452 msgid "E568: duplicate cscope database not added" msgstr "E568: Intentó añadir una base de datos de \"cscope\" duplicada" -#: if_cscope.c:1597 #, c-format msgid "E261: cscope connection %s not found" msgstr "E261: No se ha encontrado la conexión \"cscope\" %s" -#: if_cscope.c:1631 #, c-format msgid "cscope connection %s closed" msgstr "Conexión \"cscope\" %s cerrada" # should not reach here -#. should not reach here -#: if_cscope.c:1771 msgid "E570: fatal error in cs_manage_matches" msgstr "E570: Error fatal en \"cs_manage_matches\"" -#: if_cscope.c:2033 #, c-format msgid "Cscope tag: %s" msgstr "Etiqueta de \"cscope\": %s" -#: if_cscope.c:2055 msgid "" "\n" " # line" @@ -3250,28 +2525,22 @@ msgstr "" "\n" " # línea" -#: if_cscope.c:2057 msgid "filename / context / line\n" msgstr "nombre del archivo / contexto / línea\n" -#: if_cscope.c:2169 #, c-format msgid "E609: Cscope error: %s" msgstr "E609: Error de \"cscope\": %s" -#: if_cscope.c:2438 msgid "All cscope databases reset" msgstr "Se han vaciado todas las bases de datos de \"cscope\"" -#: if_cscope.c:2505 msgid "no cscope connections\n" msgstr "no hay conexiones \"cscope\"\n" -#: if_cscope.c:2509 msgid " # pid database name prepend path\n" msgstr " nº pid base de datos prefijo ruta\n" -#: if_mzsch.c:1045 msgid "" "E815: Sorry, this command is disabled, the MzScheme libraries could not be " "loaded." @@ -3279,81 +2548,57 @@ msgstr "" "E815: Lo siento, esta orden está desactivada, no se pudo cargar las " "bibliotecas de MzScheme" -#: if_mzsch.c:1469 if_python.c:1271 if_tcl.c:1404 msgid "invalid expression" msgstr "expresión no válida" -#: if_mzsch.c:1477 if_python.c:1290 if_tcl.c:1409 msgid "expressions disabled at compile time" msgstr "expresiones desactivadas al compilar" -#: if_mzsch.c:1566 msgid "hidden option" msgstr "opción oculta" -#: if_mzsch.c:1568 if_tcl.c:501 msgid "unknown option" msgstr "opción desconocida" -#: if_mzsch.c:1727 msgid "window index is out of range" msgstr "indice de ventana fuera del rango" -#: if_mzsch.c:1887 msgid "couldn't open buffer" msgstr "No se pudo abrir el búfer" -#: if_mzsch.c:2167 if_mzsch.c:2197 if_mzsch.c:2294 if_mzsch.c:2358 -#: if_mzsch.c:2479 if_mzsch.c:2536 if_python.c:2508 if_python.c:2542 -#: if_python.c:2601 if_python.c:2668 if_python.c:2790 if_python.c:2842 -#: if_tcl.c:684 if_tcl.c:729 if_tcl.c:803 if_tcl.c:875 if_tcl.c:2017 msgid "cannot save undo information" msgstr "No se pudo guardar la información para deshacer" -#: if_mzsch.c:2172 if_mzsch.c:2302 if_mzsch.c:2372 if_python.c:2510 -#: if_python.c:2608 if_python.c:2679 msgid "cannot delete line" msgstr "no puedo suprimir la línea" -#: if_mzsch.c:2203 if_mzsch.c:2387 if_python.c:2547 if_python.c:2695 -#: if_tcl.c:690 if_tcl.c:2039 msgid "cannot replace line" msgstr "no se pudo reemplazar la línea" -#: if_mzsch.c:2402 if_mzsch.c:2485 if_mzsch.c:2546 if_python.c:2713 -#: if_python.c:2792 if_python.c:2850 msgid "cannot insert line" msgstr "no se pudo insertar la línea" -#: if_mzsch.c:2637 if_python.c:2962 msgid "string cannot contain newlines" msgstr "La cadena no puede contener quiebres de línea" -#: if_mzsch.c:2859 msgid "Vim error: ~a" msgstr "Error de Vim: ~a" -#: if_mzsch.c:2892 msgid "Vim error" msgstr "Error de Vim" -#: if_mzsch.c:2958 msgid "buffer is invalid" msgstr "El búfer no es valido" -#: if_mzsch.c:2967 msgid "window is invalid" msgstr "La ventana no es válida" -#: if_mzsch.c:2987 msgid "linenr out of range" msgstr "El número de la línea está fuera del rango" -#: if_mzsch.c:3138 if_mzsch.c:3180 msgid "not allowed in the Vim sandbox" msgstr "No permitido en la \"sandbox\" de vim" -#: if_python.c:517 msgid "" "E263: Sorry, this command is disabled, the Python library could not be " "loaded." @@ -3361,171 +2606,128 @@ msgstr "" "E263: Lo siento, esta orden está desactivada, no se pudo cargar la " "biblioteca de Python" -#: if_python.c:583 msgid "E659: Cannot invoke Python recursively" msgstr "E659: No se pudo invocar a Python recursivamente" -#: if_python.c:776 msgid "can't delete OutputObject attributes" msgstr "No se pueden borrar los atributos de \"OutputObject\"" -#: if_python.c:783 msgid "softspace must be an integer" msgstr "\"softspace\" debe ser un entero" -#: if_python.c:791 msgid "invalid attribute" msgstr "Atributo no válido" -#: if_python.c:830 if_python.c:844 msgid "writelines() requires list of strings" msgstr "\"writelines()\" requiere una lista de cadenas" -#: if_python.c:970 msgid "E264: Python: Error initialising I/O objects" msgstr "E264: Python: error de iniciación de los objetos de I/O" -#: if_python.c:1303 msgid "attempt to refer to deleted buffer" msgstr "Intento de referirse a un búfer suprimido" -#: if_python.c:1318 if_python.c:1359 if_python.c:1423 if_tcl.c:1216 msgid "line number out of range" msgstr "El número de la línea está fuera del rango" -#: if_python.c:1558 #, c-format msgid "<buffer object (deleted) at %p>" msgstr "<objeto de búfer (suprimido) en %p>" -#: if_python.c:1649 if_tcl.c:836 msgid "invalid mark name" msgstr "Nombre de marca no válido" -#: if_python.c:1927 msgid "no such buffer" msgstr "No existe tal búfer" -#: if_python.c:2015 msgid "attempt to refer to deleted window" msgstr "Intento de referirse a una ventana suprimida" -#: if_python.c:2060 msgid "readonly attribute" msgstr "Atributo de solo lectura" -#: if_python.c:2074 msgid "cursor position outside buffer" msgstr "Posición del cursor fuera del búfer" -#: if_python.c:2157 #, c-format msgid "<window object (deleted) at %p>" msgstr "<objeto ventana (suprimido) en %p>" -#: if_python.c:2169 #, c-format msgid "<window object (unknown) at %p>" msgstr "<objeto ventana (desconocido) en %p>" -#: if_python.c:2172 #, c-format msgid "<window %d>" msgstr "<ventana %d>" -#: if_python.c:2246 msgid "no such window" msgstr "No existe tal ventana" -#: if_ruby.c:365 msgid "E265: $_ must be an instance of String" msgstr "E265: $_ debe ser una instancia de \"String\"" -#: if_ruby.c:426 msgid "" "E266: Sorry, this command is disabled, the Ruby library could not be loaded." msgstr "" "E266: Lo siento, esta orden está desactivada, no se pudo cargar " "la biblioteca de Ruby" -#: if_ruby.c:455 msgid "E267: unexpected return" msgstr "E267: \"return\" inesperado" -#: if_ruby.c:458 msgid "E268: unexpected next" msgstr "E268: \"next\" inesperado" -#: if_ruby.c:461 msgid "E269: unexpected break" msgstr "E269: \"break\" inesperado" -#: if_ruby.c:464 msgid "E270: unexpected redo" msgstr "E270: \"redo\" inesperado" -#: if_ruby.c:467 msgid "E271: retry outside of rescue clause" msgstr "E271: \"retry\" fuera de una cláusula \"rescue\"" -#: if_ruby.c:474 msgid "E272: unhandled exception" msgstr "E272: excepción sin manejar" -#: if_ruby.c:489 #, c-format msgid "E273: unknown longjmp status %d" msgstr "E273: El estado %d de \"longjmp\" es desconocido" -#: if_tcl.c:419 msgid "invalid buffer number" msgstr "Número de búfer no válido" -#: if_tcl.c:465 if_tcl.c:935 if_tcl.c:1115 msgid "not implemented yet" msgstr "Aún no implementado" # ??? -#. ??? -#: if_tcl.c:774 msgid "cannot set line(s)" msgstr "No se puede(n) definir la/s línea/s" -#: if_tcl.c:845 msgid "mark not set" msgstr "Marca sin definir" -#: if_tcl.c:852 if_tcl.c:1071 #, c-format msgid "row %d column %d" msgstr "fila %d columna %d" -#: if_tcl.c:884 msgid "cannot insert/append line" msgstr "No se puede insertar/añadir línea" -#: if_tcl.c:1270 msgid "unknown flag: " msgstr "Indicador desconocido: " -#: if_tcl.c:1340 msgid "unknown vimOption" msgstr "\"vimOption\" desconocida" -#: if_tcl.c:1425 msgid "keyboard interrupt" msgstr "Interrupción desde el teclado" -#: if_tcl.c:1430 -msgid "vim error" -msgstr "Error de Vim" - -#: if_tcl.c:1474 msgid "cannot create buffer/window command: object is being deleted" msgstr "No se pudo crear la orden de búfer/ventana: el objeto se suprimirá" -#: if_tcl.c:1550 msgid "" "cannot register callback command: buffer/window is already being deleted" msgstr "" @@ -3533,8 +2735,6 @@ msgstr "" "eliminó" # This should never happen. Famous last word? -#. This should never happen. Famous last word? -#: if_tcl.c:1569 msgid "" "E280: TCL FATAL ERROR: reflist corrupt!? Please report this to vim-dev@vim." "org" @@ -3542,127 +2742,99 @@ msgstr "" "E280: ERROR FATAL DE TCL: ¿¡\"reflist\" dañada!? Por favor, informe de " "esto a vim-dev@vim.org" -#: if_tcl.c:1570 msgid "cannot register callback command: buffer/window reference not found" msgstr "" "No se pudo registrar la orden de retorno de llamada: No se pudo encontrar " "la referencia al búfer o la ventana" -#: if_tcl.c:1742 msgid "" "E571: Sorry, this command is disabled: the Tcl library could not be loaded." msgstr "" "E571: Lo siento, esta orden está desactivada pues no se pudo " "cargar la biblioteca de Tcl" -#: if_tcl.c:1904 msgid "" "E281: TCL ERROR: exit code is not int!? Please report this to vim-dev@vim.org" msgstr "" "E281: ERROR DE TCL: ¿¡el código de salida no es \"int\"!? Por favor " "informe a vim-dev@vim.org" -#: if_tcl.c:1909 #, c-format msgid "E572: exit code %d" msgstr "E572: código de salida %d" -#: if_tcl.c:2025 msgid "cannot get line" msgstr "No puedo obtener la línea" -#: if_xcmdsrv.c:233 msgid "Unable to register a command server name" msgstr "Incapaz de registrar un nombre de servidor de órdenes" -#: if_xcmdsrv.c:492 msgid "E248: Failed to send command to the destination program" msgstr "E248: No pude enviar la orden al programa de destino" -#: if_xcmdsrv.c:765 #, c-format msgid "E573: Invalid server id used: %s" msgstr "E573: El ID de usuario no es válido en el servidor: %s" -#: if_xcmdsrv.c:1146 msgid "E251: VIM instance registry property is badly formed. Deleted!" msgstr "E251: La propiedad de registro de VIM es incorrecta. ¡Eliminada!" -#: main.c:138 msgid "Unknown option argument" msgstr "Opción de argumento desconocida" -#: main.c:140 msgid "Too many edit arguments" msgstr "Demasiados argumentos de edición" -#: main.c:142 msgid "Argument missing after" msgstr "Falta el argumento después de" -#: main.c:144 msgid "Garbage after option argument" msgstr "Basura después de la opción" -#: main.c:146 msgid "Too many \"+command\", \"-c command\" or \"--cmd command\" arguments" msgstr "" "Demasiados argumentos tales como: \"+orden\", \"-c orden\" " "o \"--cmd orden\"" -#: main.c:148 msgid "Invalid argument for" msgstr "Argumento no válido para" -#: main.c:514 #, c-format msgid "%d files to edit\n" msgstr "%d archivos que editar\n" -#: main.c:1510 msgid "This Vim was not compiled with the diff feature." msgstr "Este Vim no se ha compilado con la opción \"diff\"" -#: main.c:1612 msgid "'-nb' cannot be used: not enabled at compile time\n" msgstr "'-nb' no se puede usar: no se ha activado al compilar\n" -#: main.c:2135 msgid "Attempt to open script file again: \"" msgstr "Intento de abrir de nuevo el archivo de órdenes: \"" -#: main.c:2144 msgid "Cannot open for reading: \"" msgstr "No se pudo abrir para leer: \"" -#: main.c:2198 msgid "Cannot open for script output: \"" msgstr "No se pudo abrir para escribir la salida del archivo de órdenes: \"" -#: main.c:2364 msgid "Vim: Error: Failure to start gvim from NetBeans\n" msgstr "Vim: Error: Imposible iniciar gvim para NetBeans\n" -#: main.c:2369 msgid "Vim: Warning: Output is not to a terminal\n" msgstr "Vim: Advertencia: la salida no es un terminal\n" -#: main.c:2371 msgid "Vim: Warning: Input is not from a terminal\n" msgstr "Vim: Advertencia: la entrada no es desde un terminal\n" # just in case.. -#. just in case.. -#: main.c:2688 msgid "pre-vimrc command line" msgstr "Línea de órdenes previa a \"vimrc\"" -#: main.c:2785 #, c-format msgid "E282: Cannot read from \"%s\"" msgstr "E282: No se pudo leer desde \"%s\"" -#: main.c:3002 msgid "" "\n" "More info with: \"vim -h\"\n" @@ -3670,23 +2842,18 @@ msgstr "" "\n" "Más información con: \"vim -h\"\n" -#: main.c:3035 msgid "[file ..] edit specified file(s)" msgstr "[archivo ..] Editar el/los archivos/s especificado/s" -#: main.c:3036 msgid "- read text from stdin" msgstr "- Leer texto de la entrada estándar" -#: main.c:3037 msgid "-t tag edit file where tag is defined" msgstr "-t etiqueta Editar el archivo donde está definida la etiqueta" -#: main.c:3039 msgid "-q [errorfile] edit file with first error" msgstr "-q [fich. err.] Editar el archivo con el primer error" -#: main.c:3048 msgid "" "\n" "\n" @@ -3696,11 +2863,9 @@ msgstr "" "\n" "Uso:" -#: main.c:3051 msgid " vim [arguments] " msgstr " vim [argumentos]" -#: main.c:3055 msgid "" "\n" " or:" @@ -3708,7 +2873,6 @@ msgstr "" "\n" " o:" -#: main.c:3058 msgid "" "\n" "Where case is ignored prepend / to make flag upper case" @@ -3717,7 +2881,6 @@ msgstr "" "Cuando mayúscula y minúscula son ignoradas añada \"/\" para " "cambiar la marca (\"flag\") a mayúscula" -#: main.c:3061 msgid "" "\n" "\n" @@ -3727,280 +2890,218 @@ msgstr "" "\n" "Argumentos:\n" -#: main.c:3062 msgid "--\t\t\tOnly file names after this" msgstr "--\t\t\tSolo nombres de archivos a partir de aquí" -#: main.c:3064 msgid "--literal\t\tDon't expand wildcards" msgstr "--literal\t\tNo expandir comodines" -#: main.c:3067 msgid "-register\t\tRegister this gvim for OLE" msgstr "-register\t\tRegistrar este \"gvim\" para \"OLE\"" -#: main.c:3068 msgid "-unregister\t\tUnregister gvim for OLE" msgstr "-unregister\t\tSuprimir el registro de \"gvim\" para \"OLE\"" -#: main.c:3071 msgid "-g\t\t\tRun using GUI (like \"gvim\")" msgstr "-g\t\t\tEjecutar usando el GUI (como \"gvim\")" -#: main.c:3072 msgid "-f or --nofork\tForeground: Don't fork when starting GUI" msgstr "" "-f o --nofork\tPrimer plano: No separarse (\"fork\") cuando se " "inicia la interfaz gráfica (GUI)" -#: main.c:3074 msgid "-v\t\t\tVi mode (like \"vi\")" msgstr "-v\t\t\tModo vi" -#: main.c:3075 msgid "-e\t\t\tEx mode (like \"ex\")" msgstr "-e\t\t\tModo ex" -#: main.c:3076 msgid "-s\t\t\tSilent (batch) mode (only for \"ex\")" msgstr "-s\t\t\tModo silencioso de ejecución por lotes (\"ex\")" -#: main.c:3078 msgid "-d\t\t\tDiff mode (like \"vimdiff\")" msgstr "-d\t\t\tModo de diferencias (como \"vimdiff\")" -#: main.c:3080 msgid "-y\t\t\tEasy mode (like \"evim\", modeless)" msgstr "-y\t\t\tModo fácil (como \"evim\", sin modo)" -#: main.c:3081 msgid "-R\t\t\tReadonly mode (like \"view\")" msgstr "-R\t\t\tModo de solo lectura (como \"view\")" -#: main.c:3082 msgid "-Z\t\t\tRestricted mode (like \"rvim\")" msgstr "-Z\t\t\tModo restringido (como \"rvim\")" -#: main.c:3083 msgid "-m\t\t\tModifications (writing files) not allowed" msgstr "-m\t\t\tModificación de archivos desactivada" -#: main.c:3084 msgid "-M\t\t\tModifications in text not allowed" msgstr "-M\t\t\tModificación de texto desactivada" -#: main.c:3085 msgid "-b\t\t\tBinary mode" msgstr "-b\t\t\tModo binario" -#: main.c:3087 msgid "-l\t\t\tLisp mode" msgstr "-l\t\t\tModo LISP" -#: main.c:3089 msgid "-C\t\t\tCompatible with Vi: 'compatible'" msgstr "-C\t\t\tCompatible con vi: \"compatible\"" -#: main.c:3090 msgid "-N\t\t\tNot fully Vi compatible: 'nocompatible'" msgstr "-N\t\t\tParcialmente compatible con vi: \"nocompatible\"" -#: main.c:3091 msgid "-V[N][fname]\t\tBe verbose [level N] [log messages to fname]" msgstr "" "-V[N][nombre_archivo]\t\tCon verbosidad [nivel N] [guardar mensajes en " "nombre_archivo]" -#: main.c:3093 msgid "-D\t\t\tDebugging mode" msgstr "-D\t\t\tModo de depuración" -#: main.c:3095 msgid "-n\t\t\tNo swap file, use memory only" msgstr "-n\t\t\tSin archivo de intercambio, solo usa RAM" -#: main.c:3096 msgid "-r\t\t\tList swap files and exit" msgstr "-r\t\t\tDar una lista de los archivo de intercambio y salir" -#: main.c:3097 msgid "-r (with file name)\tRecover crashed session" msgstr "-r \"archivo\"\tRecuperar sesión fallida" -#: main.c:3098 msgid "-L\t\t\tSame as -r" msgstr "-L\t\t\tIgual que \"-r\"" -#: main.c:3100 msgid "-f\t\t\tDon't use newcli to open window" msgstr "-f\t\t\tNo usar \"newcli\" para abrir ventanas" -#: main.c:3101 msgid "-dev <device>\t\tUse <device> for I/O" msgstr "-dev <dispositivo>\t\tUsar <dispositivo> para I/O" -#: main.c:3104 msgid "-A\t\t\tStart in Arabic mode" msgstr "-A\t\t\tIniciar en modo árabe" -#: main.c:3107 msgid "-H\t\t\tStart in Hebrew mode" msgstr "-H\t\t\tIniciar en modo hebreo" -#: main.c:3110 msgid "-F\t\t\tStart in Farsi mode" msgstr "-F\t\t\tIniciar en modo persa (farsi)" -#: main.c:3112 msgid "-T <terminal>\tSet terminal type to <terminal>" msgstr "-T <terminal>\tEstablecer el tipo de salida visual a <terminal>" -#: main.c:3113 msgid "-u <vimrc>\t\tUse <vimrc> instead of any .vimrc" msgstr "-u <vimrc>\t\tUsar <vimrc> en lugar de cualquier \".vimrc\"" -#: main.c:3115 msgid "-U <gvimrc>\t\tUse <gvimrc> instead of any .gvimrc" msgstr "-U <gvimrc>\t\tUsar <gvimrc> en lugar de otro \".gvimrc\"" -#: main.c:3117 msgid "--noplugin\t\tDon't load plugin scripts" msgstr "--noplugin\t\tNo cargar los módulos de expansión" -#: main.c:3119 msgid "-p[N]\t\tOpen N tab pages (default: one for each file)" msgstr "-p[N]\t\tAbrir N ventanas (valor predeterminado: una por archivo)" -#: main.c:3120 msgid "-o[N]\t\tOpen N windows (default: one for each file)" msgstr "-o[N]\t\tAbrir N ventanas (valor predeterminado: una por archivo)" -#: main.c:3121 msgid "-O[N]\t\tLike -o but split vertically" msgstr "-O[N]\t\tComo \"-o\" pero divide las ventanas verticalmente" -#: main.c:3123 msgid "+\t\t\tStart at end of file" msgstr "+\t\t\tComenzar al final del archivo" -#: main.c:3124 msgid "+<lnum>\t\tStart at line <lnum>" msgstr "+<número_de_línea>\tComienza en la línea <número_de_línea>" -#: main.c:3125 msgid "--cmd <command>\tExecute <command> before loading any vimrc file" msgstr "--cmd <orden>\tEjecutar la <orden> antes de cargar algún archivo vimrc" -#: main.c:3126 msgid "-c <command>\t\tExecute <command> after loading the first file" msgstr "-c <orden>\t\tEjecutar <orden> después de cargar el primer archivo" -#: main.c:3127 msgid "-S <session>\t\tSource file <session> after loading the first file" msgstr "" "-S <sesión>\t\tEjecutar las órdenes del archivo <sesión> después " "de cargar el primer archivo" -#: main.c:3128 msgid "-s <scriptin>\tRead Normal mode commands from file <scriptin>" msgstr "" "-s <scriptin>\tLeer las órdenes en modo Normal del archivo " "\"módulo de expansión\" de entrada>" -#: main.c:3129 msgid "-w <scriptout>\tAppend all typed commands to file <scriptout>" msgstr "" "-w <scriptout>\tAñadir todas las órdenes escritas al archivo " "\"módulo de expansión\" de salida" -#: main.c:3130 msgid "-W <scriptout>\tWrite all typed commands to file <scriptout>" msgstr "" "-W <scriptout>\tGrabar todas las órdenes escritas al archivo " "\"módulo de expansión\" de salida" -#: main.c:3132 msgid "-x\t\t\tEdit encrypted files" msgstr "-x\t\t\tEditar archivos cifrados" -#: main.c:3136 -msgid "-display <display>\tConnect vim to this particular X-server" -msgstr "-display <pantalla>\tConectar vim a este servidor X en particular" +msgid "-display <display>\tConnect Vim to this particular X-server" +msgstr "-display <pantalla>\tConectar Vim a este servidor X en particular" -#: main.c:3138 msgid "-X\t\t\tDo not connect to X server" msgstr "-X\t\t\tEvitar la conexión al servidor X" -#: main.c:3141 msgid "--remote <files>\tEdit <files> in a Vim server if possible" msgstr "" "--remote <archivos>\tEditar <archivos> en un servidor Vim si es posible" -#: main.c:3142 msgid "--remote-silent <files> Same, don't complain if there is no server" msgstr "" "--remote-silent \"archivos\"\tLo mismo pero no se queja si no existe un " "servidor disponible" -#: main.c:3143 msgid "" "--remote-wait <files> As --remote but wait for files to have been edited" msgstr "" "--remote-wait \"archivos\"\tComo --remote pero espera a que los archivos " "terminen de editarse" -#: main.c:3144 msgid "" "--remote-wait-silent <files> Same, don't complain if there is no server" msgstr "" "--remote-wait-silent \"archivos\"\tLo mismo pero no se queja si no hay un " "servidor disponible" -#: main.c:3146 msgid "" "--remote-tab[-wait][-silent] <files> As --remote but use tab page per file" msgstr "" "--remote-tab[-wait][-silent] <archivos> Como \"--remote\" pero usa una " "pestaña por página" -#: main.c:3148 msgid "--remote-send <keys>\tSend <keys> to a Vim server and exit" msgstr "--remote-send <teclas>\tEnvíar <teclas> a un servidor Vim y cerrar" -#: main.c:3149 msgid "--remote-expr <expr>\tEvaluate <expr> in a Vim server and print result" msgstr "" "--remote-expr <expr>\tEvaluar <expr> en un servidor Vim e imprimir el " "resultado" -#: main.c:3150 msgid "--serverlist\t\tList available Vim server names and exit" msgstr "" "--serverlist\t\tEmitir una lista de los servidores Vim disponibles y cerrar" -#: main.c:3151 msgid "--servername <name>\tSend to/become the Vim server <name>" msgstr "" "--servername \"nombre\"\tEnvíar a/se convierte en el servidor Vim con <nombre>" -#: main.c:3154 msgid "--startuptime <file>\tWrite startup timing messages to <file>" msgstr "-- startuptime <archivo>\tGuardar los mensajes de tiempo de inicio " "a <archivo>." -#: main.c:3157 msgid "-i <viminfo>\t\tUse <viminfo> instead of .viminfo" msgstr "-i <viminfo>\t\tUsar <viminfo> en lugar de \".viminfo\"" -#: main.c:3159 msgid "-h or --help\tPrint Help (this message) and exit" msgstr "-h or --help\tImpresión de la ayuda (este mensaje) y cerrar" -#: main.c:3160 msgid "--version\t\tPrint version information and exit" msgstr "--version\t\tImpresión de la información de versión y cerrar" -#: main.c:3164 msgid "" "\n" "Arguments recognised by gvim (Motif version):\n" @@ -4008,7 +3109,6 @@ msgstr "" "\n" "Argumentos reconocidos por gvim (versión Motif):\n" -#: main.c:3168 msgid "" "\n" "Arguments recognised by gvim (neXtaw version):\n" @@ -4016,7 +3116,6 @@ msgstr "" "\n" "Argumentos reconocidos por gvim (versión neXtaw):\n" -#: main.c:3170 msgid "" "\n" "Arguments recognised by gvim (Athena version):\n" @@ -4024,81 +3123,64 @@ msgstr "" "\n" "Argumentos reconocidos por gvim (versión Athena):\n" -#: main.c:3174 -msgid "-display <display>\tRun vim on <display>" -msgstr "-display <pantalla>\tEjecuta vim en <pantalla>" +msgid "-display <display>\tRun Vim on <display>" +msgstr "-display <pantalla>\tEjecuta Vim en <pantalla>" -#: main.c:3175 -msgid "-iconic\t\tStart vim iconified" -msgstr "-iconic\t\tArranca vim \"iconizado\"" +msgid "-iconic\t\tStart Vim iconified" +msgstr "-iconic\t\tArranca Vim \"iconizado\"" -#: main.c:3177 msgid "-name <name>\t\tUse resource as if vim was <name>" msgstr "-name <nombre>\t\tUsa un recurso como si vim fuese <nombre>" -#: main.c:3178 msgid "\t\t\t (Unimplemented)\n" msgstr "\t\t\t (Sin implementar)\n" -#: main.c:3180 msgid "-background <color>\tUse <color> for the background (also: -bg)" msgstr "-background <color>\tUsa <color> para el fondo (también: -bg)" -#: main.c:3181 msgid "-foreground <color>\tUse <color> for normal text (also: -fg)" msgstr "-foreground <color>\tUsa <color> para el texto normal (también: -fg)" -#: main.c:3182 main.c:3202 msgid "-font <font>\t\tUse <font> for normal text (also: -fn)" msgstr "" "-font <tipo>\t\tUse <tipo de letra de impresión> para el texto normal " "(también: -fn)" -#: main.c:3183 msgid "-boldfont <font>\tUse <font> for bold text" msgstr "" "-boldfont <tipo>\tUsa <tipo de letra de impresión> para texto en " "negrita" -#: main.c:3184 msgid "-italicfont <font>\tUse <font> for italic text" msgstr "" "-italicfont <tipo>\tUse <tipo de letra de impresión> para texto " "en cursiva" -#: main.c:3185 main.c:3203 msgid "-geometry <geom>\tUse <geom> for initial geometry (also: -geom)" msgstr "" "-geometry <geom>\tUse <geom> para la geometría inicial (también: -geom)" -#: main.c:3186 msgid "-borderwidth <width>\tUse a border width of <width> (also: -bw)" msgstr "-borderwidth <ancho>\tUsa un ancho de borde de <ancho> (también: -bw)" -#: main.c:3187 msgid "-scrollbarwidth <width> Use a scrollbar width of <width> (also: -sw)" msgstr "" "-scrollbarwidth <ancho>\tUsa una barra de desplazamiento de ancho <ancho> " "(también: -sw)" -#: main.c:3189 msgid "-menuheight <height>\tUse a menu bar height of <height> (also: -mh)" msgstr "" "-menuheight <alt>\tUsa una barra de menú de altura <alt> (también: -mh)" -#: main.c:3191 main.c:3204 msgid "-reverse\t\tUse reverse video (also: -rv)" msgstr "-reverse\t\tUsar vídeo inverso (también: -rv)" -#: main.c:3192 msgid "+reverse\t\tDon't use reverse video (also: +rv)" msgstr "+reverse\t\tNo usar vídeo inverso (también: +rv)" -#: main.c:3193 msgid "-xrm <resource>\tSet the specified resource" msgstr "-xrm <recurso>\tEstablece el recurso especificado" -#: main.c:3196 msgid "" "\n" "Arguments recognised by gvim (RISC OS version):\n" @@ -4106,15 +3188,12 @@ msgstr "" "\n" "Argumentos reconocidos por gvim (versión para RISC OS):\n" -#: main.c:3197 msgid "--columns <number>\tInitial width of window in columns" msgstr "--columns <número>\tAnchura inicial de la ventana, en columnas" -#: main.c:3198 msgid "--rows <number>\tInitial height of window in rows" msgstr "--rows <número>\tAltura inicial de la ventana, en filas" -#: main.c:3201 msgid "" "\n" "Arguments recognised by gvim (GTK+ version):\n" @@ -4122,70 +3201,53 @@ msgstr "" "\n" "Argumentos reconocidos por gvim (versión GTK+):\n" -#: main.c:3205 -msgid "-display <display>\tRun vim on <display> (also: --display)" -msgstr "-display <pantalla>\tEjecuta vim en <pantalla> (también: --display)" +msgid "-display <display>\tRun Vim on <display> (also: --display)" +msgstr "-display <pantalla>\tEjecuta Vim en <pantalla> (también: --display)" -#: main.c:3207 msgid "--role <role>\tSet a unique role to identify the main window" msgstr "" "--role <role>\tDefine un rol único para identificar la ventana principal" -#: main.c:3209 msgid "--socketid <xid>\tOpen Vim inside another GTK widget" msgstr "--socketid <xid>\tAbre a Vim dentro de otro \"widget\" GTK" -#: main.c:3212 msgid "-P <parent title>\tOpen Vim inside parent application" msgstr "-P <título ventana padre>\tAbrir a Vim dentro de la aplicación padre" -#: main.c:3213 msgid "--windowid <HWND>\tOpen Vim inside another win32 widget" msgstr "--windowid <HWND>\tAbrir Vim dentro de otro objeto de win32" -#: main.c:3557 msgid "No display" msgstr "No hay una ventana" # Failed to send, abort. -#. Failed to send, abort. -#: main.c:3572 msgid ": Send failed.\n" msgstr ": Falló el envío.\n" # Let vim start normally. -#. Let vim start normally. -#: main.c:3578 msgid ": Send failed. Trying to execute locally\n" msgstr "" ": Falló el inicio de sesión remota (\"send\"). Intentado una " "ejecución local\n" -#: main.c:3616 main.c:3637 #, c-format msgid "%d of %d edited" msgstr "%d de %d editados" -#: main.c:3659 msgid "No display: Send expression failed.\n" msgstr "No hay una ventana en el destino: El envío de la expresión falló.\n" -#: main.c:3671 msgid ": Send expression failed.\n" msgstr ": Falló el envío de la expresión.\n" -#: mark.c:761 msgid "No marks set" msgstr "No se han fijado marcas" -#: mark.c:763 #, c-format msgid "E283: No marks matching \"%s\"" msgstr "E283: No hay marcas que coincidan con %s" # Highlight title -#. Highlight title -#: mark.c:774 msgid "" "\n" "mark line col file/text" @@ -4194,8 +3256,6 @@ msgstr "" "marca línea col archivo/texto" # Highlight title -#. Highlight title -#: mark.c:896 msgid "" "\n" " jump line col file/text" @@ -4204,8 +3264,6 @@ msgstr "" " salto línea col archivo/texto" # Highlight title -#. Highlight title -#: mark.c:943 msgid "" "\n" "change line col text" @@ -4213,7 +3271,6 @@ msgstr "" "\n" "cambio línea col archivo/texto" -#: mark.c:1437 #, c-format msgid "" "\n" @@ -4223,8 +3280,6 @@ msgstr "" "# Marcas en el archivo:\n" # Write the jumplist with -' -#. Write the jumplist with -' -#: mark.c:1472 #, c-format msgid "" "\n" @@ -4233,7 +3288,6 @@ msgstr "" "\n" "# Lista de saltos (el más reciente va primero):\n" -#: mark.c:1573 #, c-format msgid "" "\n" @@ -4243,124 +3297,96 @@ msgstr "" "# Historia de las marcas en los archivos (de la más reciente a la más " "antigua):\n" -#: mark.c:1677 msgid "Missing '>'" msgstr "Falta \">\"" -#: mbyte.c:532 msgid "E543: Not a valid codepage" msgstr "E543: No es una página de código válida" -#: mbyte.c:4852 msgid "E284: Cannot set IC values" msgstr "E284: No se pudo fijar los valores IC" -#: mbyte.c:5004 msgid "E285: Failed to create input context" msgstr "E285: Falló la creación del contexto de entrada" -#: mbyte.c:5162 msgid "E286: Failed to open input method" msgstr "E286: Falló la apertura del método de entrada" -#: mbyte.c:5175 msgid "E287: Warning: Could not set destroy callback to IM" msgstr "" "E287: Advertencia: No pude crear una llamada de retorno " "de destrucción al IM" -#: mbyte.c:5181 msgid "E288: input method doesn't support any style" msgstr "E288: el método de entrada no admite ningún estilo" -#: mbyte.c:5240 msgid "E289: input method doesn't support my preedit type" msgstr "E289: El método de entrada no soporta mi tipo de pre-edición" -#: mbyte.c:5352 msgid "E291: Your GTK+ is older than 1.2.3. Status area disabled" msgstr "" "E291: Su versión de GTK+ es anterior a 1.2.3. Área de estado " "desactivada" -#: memfile.c:501 msgid "E293: block was not locked" msgstr "E293: El bloque no estaba asegurado" -#: memfile.c:1044 msgid "E294: Seek error in swap file read" msgstr "E294: Error de búsqueda al leer el archivo de intercambio" -#: memfile.c:1049 msgid "E295: Read error in swap file" msgstr "E295: Error de lectura en el archivo de intercambio" -#: memfile.c:1101 msgid "E296: Seek error in swap file write" msgstr "E296: Error de búsqueda al escribir en el archivo de intercambio" -#: memfile.c:1119 msgid "E297: Write error in swap file" msgstr "E297: Error de escritura en el archivo de intercambio" -#: memfile.c:1316 msgid "E300: Swap file already exists (symlink attack?)" msgstr "" "E300: Ya existe un archivo de intercambio (¿ataque de enlace simbólico?)" -#: memline.c:312 msgid "E298: Didn't get block nr 0?" msgstr "E298: ¿No se obtuvo el bloque Nº 0?" -#: memline.c:359 msgid "E298: Didn't get block nr 1?" msgstr "E298: ¿No se obtuvo el bloque Nº 1?" -#: memline.c:377 msgid "E298: Didn't get block nr 2?" msgstr "E298: ¿No se obtuvo el bloque Nº 2?" # could not (re)open the swap file, what can we do???? -#. could not (re)open the swap file, what can we do???? -#: memline.c:490 msgid "E301: Oops, lost the swap file!!!" msgstr "E301: ¡¡¡Perdí el archivo de intercambio!!!" -#: memline.c:502 msgid "E302: Could not rename swap file" msgstr "E302: No pude cambiar el nombre del archivo de intercambio" -#: memline.c:592 #, c-format msgid "E303: Unable to open swap file for \"%s\", recovery impossible" msgstr "" "E303: Incapaz de abrir el archivo de intercambio para %s, " "recuperación imposible" -#: memline.c:703 msgid "E304: ml_upd_block0(): Didn't get block 0??" msgstr "E304: \"ml_upd_block0()\": ¿No se obtuvo el bloque 0?" -#: memline.c:904 #, c-format msgid "E305: No swap file found for %s" msgstr "E305: No se encontró el archivo de intercambio para %s" -#: memline.c:914 msgid "Enter number of swap file to use (0 to quit): " msgstr "" "Introduzca el número del archivo de intercambio a usar (0 para salir): " -#: memline.c:959 #, c-format msgid "E306: Cannot open %s" msgstr "E306: No se pudo abrir %s" -#: memline.c:981 msgid "Unable to read block 0 from " msgstr "Incapaz de leer el bloque 0 de " -#: memline.c:984 msgid "" "\n" "Maybe no changes were made or Vim did not update the swap file." @@ -4368,28 +3394,22 @@ msgstr "" "\n" "Tal vez no hay cambios o Vim no actualizó el archivo de intercambio." -#: memline.c:994 memline.c:1011 msgid " cannot be used with this version of Vim.\n" msgstr " no puede usarse con esta versión de Vim.\n" -#: memline.c:996 msgid "Use Vim version 3.0.\n" msgstr "Use la versión 3.0 de Vim.\n" -#: memline.c:1002 #, c-format msgid "E307: %s does not look like a Vim swap file" msgstr "E307: %s no parece un archivo de intercambio de Vim" -#: memline.c:1015 msgid " cannot be used on this computer.\n" msgstr "no puede usarse en este ordenador.\n" -#: memline.c:1017 msgid "The file was created on " msgstr "El archivo se creó el " -#: memline.c:1021 msgid "" ",\n" "or the file has been damaged." @@ -4397,88 +3417,69 @@ msgstr "" ",\n" "o el archivo se ha dañado" -#: memline.c:1039 msgid " has been damaged (page size is smaller than minimum value).\n" msgstr " se ha dañado (el tamaño de la página es menor al valor minimo).\n" -#: memline.c:1071 #, c-format msgid "Using swap file \"%s\"" msgstr "Usando el archivo de intercambio \"%s\"" -#: memline.c:1077 #, c-format msgid "Original file \"%s\"" msgstr "Archivo original %s" -#: memline.c:1090 msgid "E308: Warning: Original file may have been changed" msgstr "E308: Advertencia: el archivo original puede haber cambiado" -#: memline.c:1164 #, c-format msgid "E309: Unable to read block 1 from %s" msgstr "E309: Incapaz de leer el bloque 1 de %s" -#: memline.c:1168 msgid "???MANY LINES MISSING" msgstr "???FALTAN MUCHAS LÍNEAS" -#: memline.c:1184 msgid "???LINE COUNT WRONG" msgstr "???RECUENTO DE LÍNEAS EQUIVOCADO" -#: memline.c:1191 msgid "???EMPTY BLOCK" msgstr "???BLOQUE VACÍO" -#: memline.c:1217 msgid "???LINES MISSING" msgstr "???FALTAN LÍNEAS" -#: memline.c:1249 #, c-format msgid "E310: Block 1 ID wrong (%s not a .swp file?)" msgstr "E310: El ID del bloque 1 es incorrecto (¿No es %s un archivo .swp?)" -#: memline.c:1254 msgid "???BLOCK MISSING" msgstr "???FALTA UN BLOQUE" -#: memline.c:1270 msgid "??? from here until ???END lines may be messed up" msgstr "??? desde aquí hasta ???FIN las líneas pueden estar desordenadas" -#: memline.c:1286 msgid "??? from here until ???END lines may have been inserted/deleted" msgstr "" "??? desde aquí hasta ???FIN las líneas pueden haber sido " "insertadas/borradas" -#: memline.c:1306 msgid "???END" msgstr "???FIN" -#: memline.c:1333 msgid "E311: Recovery Interrupted" msgstr "E311: Recuperación interrumpida" -#: memline.c:1338 msgid "" "E312: Errors detected while recovering; look for lines starting with ???" msgstr "" "E312: Se han detectado errores al recuperar; busque líneas que " "empiecen con ???" -#: memline.c:1340 msgid "See \":help E312\" for more information." msgstr "Vea \":help E312\" para más información." -#: memline.c:1345 msgid "Recovery completed. You should check if everything is OK." msgstr "Recuperación completa. Ud. debería comprobar que todo está bien" -#: memline.c:1346 msgid "" "\n" "(You might want to write out this file under another name\n" @@ -4486,12 +3487,10 @@ msgstr "" "\n" "(Podría querer guardar este archivo con otro nombre\n" -#: memline.c:1347 msgid "and run diff with the original file to check for changes)\n" msgstr "" "y ejecutar \"diff\" con el archivo original para comprobar los cambios)\n" -#: memline.c:1348 msgid "" "Delete the .swp file afterwards.\n" "\n" @@ -4500,52 +3499,39 @@ msgstr "" "\n" # use msg() to start the scrolling properly -#. use msg() to start the scrolling properly -#: memline.c:1408 msgid "Swap files found:" msgstr "Se han encontrado los siguientes archivos de intercambio:" -#: memline.c:1593 msgid " In current directory:\n" msgstr " En el directorio actual:\n" -#: memline.c:1595 msgid " Using specified name:\n" msgstr " Usando el nombre especificado:\n" -#: memline.c:1599 msgid " In directory " msgstr " En el directorio " -#: memline.c:1617 msgid " -- none --\n" msgstr " -- ninguno --\n" -#: memline.c:1692 msgid " owned by: " msgstr " propiedad de: " -#: memline.c:1694 msgid " dated: " msgstr " de fecha: " -#: memline.c:1698 memline.c:3736 msgid " dated: " msgstr " de fecha: " -#: memline.c:1717 msgid " [from Vim version 3.0]" msgstr " [desde la versión 3.0 de Vim]" -#: memline.c:1721 msgid " [does not look like a Vim swap file]" msgstr " [no parece un archivo de intercambio de Vim]" -#: memline.c:1725 msgid " file name: " msgstr " nombre del archivo: " -#: memline.c:1731 msgid "" "\n" " modified: " @@ -4553,15 +3539,12 @@ msgstr "" "\n" " modificado: " -#: memline.c:1732 msgid "YES" msgstr "SI" -#: memline.c:1732 msgid "no" msgstr "no" -#: memline.c:1736 msgid "" "\n" " user name: " @@ -4569,11 +3552,9 @@ msgstr "" "\n" " nombre del usuario: " -#: memline.c:1743 msgid " host name: " msgstr " nombre del servidor: " -#: memline.c:1745 msgid "" "\n" " host name: " @@ -4581,7 +3562,6 @@ msgstr "" "\n" " nombre del servidor: " -#: memline.c:1751 msgid "" "\n" " process ID: " @@ -4589,11 +3569,9 @@ msgstr "" "\n" " ID del proceso: " -#: memline.c:1757 msgid " (still running)" msgstr " (aún en ejecución)" -#: memline.c:1769 msgid "" "\n" " [not usable with this version of Vim]" @@ -4601,7 +3579,6 @@ msgstr "" "\n" " [no se puede usar con esta versión de Vim]" -#: memline.c:1772 msgid "" "\n" " [not usable on this computer]" @@ -4609,97 +3586,75 @@ msgstr "" "\n" " [no se puede usar en este ordenador]" -#: memline.c:1777 msgid " [cannot be read]" msgstr " [no se puede leer]" -#: memline.c:1781 msgid " [cannot be opened]" msgstr " [no se puede abrir]" -#: memline.c:1971 msgid "E313: Cannot preserve, there is no swap file" msgstr "E313: No se pudo preservar, no existe un archivo de intercambio" -#: memline.c:2024 msgid "File preserved" msgstr "Archivo preservado" -#: memline.c:2026 msgid "E314: Preserve failed" msgstr "E314: Falló la preservación del archivo" -#: memline.c:2103 #, c-format msgid "E315: ml_get: invalid lnum: %ld" msgstr "E315: \"ml_get\": número de línea no válido: %ld" -#: memline.c:2138 #, c-format msgid "E316: ml_get: cannot find line %ld" msgstr "E316: \"ml_get\": no se pudo encontrar la línea %ld" -#: memline.c:2552 msgid "E317: pointer block id wrong 3" msgstr "E317: El id del bloque de punteros es incorrecto. 3" -#: memline.c:2632 msgid "stack_idx should be 0" msgstr "\"stack_idx\" debería ser 0" -#: memline.c:2694 msgid "E318: Updated too many blocks?" msgstr "E318: ¿Demasiados bloques actualizados?" -#: memline.c:2874 msgid "E317: pointer block id wrong 4" msgstr "E317: El id del bloque de punteros es incorrecto. 4" -#: memline.c:2901 msgid "deleted block 1?" msgstr "¿bloque 1 suprimido?" -#: memline.c:3101 #, c-format msgid "E320: Cannot find line %ld" msgstr "E320: No se pudo encontrar la línea %ld" -#: memline.c:3347 msgid "E317: pointer block id wrong" msgstr "E317: El id del bloque de punteros es incorrecto" -#: memline.c:3363 msgid "pe_line_count is zero" msgstr "\"pe_line_count\" es cero" -#: memline.c:3392 #, c-format msgid "E322: line number out of range: %ld past the end" msgstr "E322: número de línea fuera de rango: %ld más allá del final" -#: memline.c:3396 #, c-format msgid "E323: line count wrong in block %ld" msgstr "E323: recuento de líneas erróneo en el bloque %ld" -#: memline.c:3445 msgid "Stack size increases" msgstr "El tamaño de la pila aumenta" -#: memline.c:3492 msgid "E317: pointer block id wrong 2" msgstr "E317: El id del bloque de punteros es incorrecto. 2" -#: memline.c:3531 #, c-format msgid "E773: Symlink loop for \"%s\"" msgstr "E773: Bucle de symlinks para \"%s\"" -#: memline.c:3726 msgid "E325: ATTENTION" msgstr "E325: ATENCIÓN" -#: memline.c:3727 msgid "" "\n" "Found a swap file by the name \"" @@ -4707,19 +3662,14 @@ msgstr "" "\n" "Se ha encontrado un archivo de intercambio con el nombre \"" -#: memline.c:3731 msgid "While opening file \"" msgstr "al abrir el archivo \"" -#: memline.c:3744 msgid " NEWER than swap file!\n" msgstr " MÁS NUEVO que el archivo de intercambio!\n" # Some of these messages are long to allow translation to # * other languages. -#. Some of these messages are long to allow translation to -#. * other languages. -#: memline.c:3748 msgid "" "\n" "(1) Another program may be editing the same file.\n" @@ -4731,11 +3681,9 @@ msgstr "" " De ser así, tenga cuidado de no acabar con dos\n" " ejemplares diferentes del mismo archivo al hacer cambios.\n" -#: memline.c:3749 msgid " Quit, or continue with caution.\n" msgstr " Salga del programa o continúe con precaución.\n" -#: memline.c:3750 msgid "" "\n" "(2) An edit session for this file crashed.\n" @@ -4743,11 +3691,9 @@ msgstr "" "\n" "(2) Falló una sesión de edición de este archivo.\n" -#: memline.c:3751 msgid " If this is the case, use \":recover\" or \"vim -r " msgstr " Si es así, use \":recover\" o \"vim -r " -#: memline.c:3753 msgid "" "\"\n" " to recover the changes (see \":help recovery\").\n" @@ -4755,11 +3701,9 @@ msgstr "" "\"\n" " para recuperar los cambios (véa \":help recovery\").\n" -#: memline.c:3754 msgid " If you did this already, delete the swap file \"" msgstr " Si Ud. ya ha hecho esto, borre el archivo de intercambio \"" -#: memline.c:3756 msgid "" "\"\n" " to avoid this message.\n" @@ -4767,23 +3711,18 @@ msgstr "" "\"\n" " para evitar este mensaje.\n" -#: memline.c:4175 memline.c:4179 msgid "Swap file \"" msgstr "¡El archivo de intercambio \"" -#: memline.c:4176 memline.c:4182 msgid "\" already exists!" msgstr "\" ya existe!" -#: memline.c:4185 msgid "VIM - ATTENTION" msgstr "VIM - ATENCIÓN" -#: memline.c:4187 msgid "Swap file already exists!" msgstr "¡Ya existe un archivo de intercambio!" -#: memline.c:4191 msgid "" "&Open Read-Only\n" "&Edit anyway\n" @@ -4797,7 +3736,6 @@ msgstr "" "&Salir\n" "A&bortar" -#: memline.c:4193 msgid "" "&Open Read-Only\n" "&Edit anyway\n" @@ -4813,46 +3751,34 @@ msgstr "" "&Salir\n" "&Abortar" -#: memline.c:4264 msgid "E326: Too many swap files found" msgstr "E326: Se han encontrado demasiados archivos de intercambio" -#: menu.c:64 msgid "E327: Part of menu-item path is not sub-menu" msgstr "E327: Parte de la ruta del item del menú no es un sub-menú" -#: menu.c:65 msgid "E328: Menu only exists in another mode" msgstr "E328: El menú solo existe en otro modo de operación" -#: menu.c:66 #, c-format msgid "E329: No menu \"%s\"" msgstr "E329: No existe el menú \"%s\"" -#. Only a mnemonic or accelerator is not valid. -#: menu.c:519 msgid "E792: Empty menu name" msgstr "E792: Nombre de menú vacío" -#: menu.c:537 msgid "E330: Menu path must not lead to a sub-menu" msgstr "E330: La ruta del menú no debe conducir a un sub-menú" -#: menu.c:576 msgid "E331: Must not add menu items directly to menu bar" msgstr "" "E331: No se deben añadir elementos del menú directamente a la barra del menú" -#: menu.c:582 msgid "E332: Separator cannot be part of a menu path" msgstr "E332: El separador no puede ser parte de una ruta de menú" # Now we have found the matching menu, and we list the mappings # Highlight title -#. Now we have found the matching menu, and we list the mappings -#. Highlight title -#: menu.c:1127 msgid "" "\n" "--- Menus ---" @@ -4860,78 +3786,61 @@ msgstr "" "\n" "--- Menús ---" -#: menu.c:2090 msgid "Tear off this menu" msgstr "Desprender y flotar este menú" -#: menu.c:2155 msgid "E333: Menu path must lead to a menu item" msgstr "E333: La ruta del menú debe conducir a un item del menú" -#: menu.c:2175 #, c-format msgid "E334: Menu not found: %s" msgstr "E334: No se ha encontrado el menú: %s" -#: menu.c:2257 #, c-format msgid "E335: Menu not defined for %s mode" msgstr "E335: El menú no está definido para el modo %s" -#: menu.c:2295 msgid "E336: Menu path must lead to a sub-menu" msgstr "E336: La ruta del menú debe conducir a un sub-menú" -#: menu.c:2316 msgid "E337: Menu not found - check menu names" msgstr "E337: No se ha encontrado el menú - verifique los nombres de los menús" -#: message.c:462 #, c-format msgid "Error detected while processing %s:" msgstr "Se ha detectado un error al procesar %s:" -#: message.c:487 #, c-format msgid "line %4ld:" msgstr "línea %4ld" -#: message.c:685 #, c-format msgid "E354: Invalid register name: '%s'" msgstr "E354: Nombre de registro no válido: '%s'" -#: message.c:833 msgid "Messages maintainer: Bram Moolenaar <Bram@vim.org>" msgstr "" "Traducción: Proyecto vim-doc-es <http://www.assembla.com/wiki/show/vim-doc-es>" -#: message.c:1090 msgid "Interrupt: " msgstr "Interrupción: " -#: message.c:1092 msgid "Press ENTER or type command to continue" msgstr "Pulse INTRO o escriba una orden para continuar" -#: message.c:2139 #, c-format msgid "%s line %ld" msgstr "%s, en la línea %ld" -#: message.c:2839 msgid "-- More --" msgstr "-- Más --" -#: message.c:2845 msgid " SPACE/d/j: screen/page/line down, b/u/k: up, q: quit " msgstr " ESPACIO/d/j: pantalla/página/línea abajo, b/u/k: arriba, q: salir " -#: message.c:3637 message.c:3652 msgid "Question" msgstr "Pregunta" -#: message.c:3639 msgid "" "&Yes\n" "&No" @@ -4939,7 +3848,6 @@ msgstr "" "&Si\n" "&No" -#: message.c:3672 msgid "" "&Yes\n" "&No\n" @@ -4953,90 +3861,68 @@ msgstr "" "&Descartar todo\n" "&Cancelar" -#: message.c:3713 msgid "Select Directory dialog" msgstr "Diálogo: Selección de directorio" -#: message.c:3715 msgid "Save File dialog" msgstr "Diálogo: Guardar Archivos" -#: message.c:3717 msgid "Open File dialog" msgstr "Diálogo: Abrir Archivos" # TODO: non-GUI file selector here -#. TODO: non-GUI file selector here -#: message.c:3817 msgid "E338: Sorry, no file browser in console mode" msgstr "E338: Lo siento, no hay navegador de archivos en el modo de consola" -#: message.c:3848 msgid "E766: Insufficient arguments for printf()" msgstr "E766: Argumentos insuficientes para printf()" -#: message.c:3924 msgid "E807: Expected Float argument for printf()" msgstr "E807: Se esperaba un argumento \"Float\" para printf()" -#: message.c:4812 msgid "E767: Too many arguments to printf()" msgstr "E767: Demasiados argumentos para printf()" -#: misc1.c:2975 msgid "W10: Warning: Changing a readonly file" msgstr "W10: Advertencia: cambiando un archivo de sólo lectura" -#: misc1.c:3269 msgid "Type number and <Enter> or click with mouse (empty cancels): " msgstr "Escriba un número e <Intro> o pulse con el ratón (la omisión cancela) " -#: misc1.c:3271 msgid "Type number and <Enter> (empty cancels): " msgstr "Escoja un número e <Intro> (la omisión cancela la acción): " -#: misc1.c:3323 msgid "1 more line" msgstr "1 línea más" -#: misc1.c:3325 msgid "1 line less" msgstr "1 línea menos" -#: misc1.c:3330 #, c-format msgid "%ld more lines" msgstr "%ld líneas más" -#: misc1.c:3332 #, c-format msgid "%ld fewer lines" msgstr "%ld líneas menos" -#: misc1.c:3335 msgid " (Interrupted)" msgstr " (Interrumpido)" -#: misc1.c:3400 msgid "Beep!" msgstr "¡Bip!" -#: misc1.c:8380 msgid "Vim: preserving files...\n" msgstr "Vim: preservando archivos...\n" # close all memfiles, without deleting -#. close all memfiles, without deleting -#: misc1.c:8390 msgid "Vim: Finished.\n" msgstr "Vim: Finalizado.\n" -#: misc2.c:718 misc2.c:734 #, c-format msgid "ERROR: " msgstr "ERROR: " -#: misc2.c:738 #, c-format msgid "" "\n" @@ -5045,7 +3931,6 @@ msgstr "" "\n" "[bytes] total liberados por alloc: %lu-%lu, en uso: %lu, uso máximo: %lu\n" -#: misc2.c:740 #, c-format msgid "" "[calls] total re/malloc()'s %lu, total free()'s %lu\n" @@ -5054,58 +3939,45 @@ msgstr "" "[llamadas] total re/malloc(): %lu, total free(): %lu\n" "\n" -#: misc2.c:795 msgid "E340: Line is becoming too long" msgstr "E340: La línea se está haciendo demasiado larga" -#: misc2.c:839 #, c-format msgid "E341: Internal error: lalloc(%ld, )" msgstr "E341: Error interno: lalloc(%ld, )" -#: misc2.c:953 #, c-format msgid "E342: Out of memory! (allocating %lu bytes)" msgstr "E342: ¡Memoria agotada! (al asignar %lu bytes)" -#: misc2.c:3033 #, c-format msgid "Calling shell to execute: \"%s\"" msgstr "Invocando al intérprete de órdenes para ejecutar: %s" -#: misc2.c:3302 msgid "E545: Missing colon" msgstr "E545: Falta un símbolo de dos puntos" -#: misc2.c:3304 misc2.c:3331 msgid "E546: Illegal mode" msgstr "E546: Modo de operación ilegal" -#: misc2.c:3370 msgid "E547: Illegal mouseshape" msgstr "E547: El \"mouseshape\" no es válido" -#: misc2.c:3410 msgid "E548: digit expected" msgstr "E548: Se esperaba un dígito" -#: misc2.c:3415 msgid "E549: Illegal percentage" msgstr "E549: Porcentaje ilegal" -#: misc2.c:3737 msgid "Enter encryption key: " msgstr "Introduzca la clave de cifrado: " -#: misc2.c:3738 msgid "Enter same key again: " msgstr "Introduzca la misma clave de cifrado otra vez: " -#: misc2.c:3749 msgid "Keys don't match!" msgstr "¡Las claves de cifrado no coinciden!" -#: misc2.c:4290 #, c-format msgid "" "E343: Invalid path: '**[number]' must be at the end of the path or be " @@ -5114,178 +3986,138 @@ msgstr "" "E343: Ruta no válida: '**[número]' debe estar al final de la ruta " "o seguido de %s." -#: misc2.c:5585 #, c-format msgid "E344: Can't find directory \"%s\" in cdpath" msgstr "E344: No se pudo encontrar el directorio \"%s\" en \"cdpath\"" -#: misc2.c:5588 #, c-format msgid "E345: Can't find file \"%s\" in path" msgstr "E345: No se pudo encontrar el archivo %s en la ruta" -#: misc2.c:5594 #, c-format msgid "E346: No more directory \"%s\" found in cdpath" msgstr "E346: No se han encontrado mas directorios \"%s\" en \"cdpath\"" -#: misc2.c:5597 #, c-format msgid "E347: No more file \"%s\" found in path" msgstr "E347: No se han encontrado mas archivos \"%s\" en la ruta" # Get here when the server can't be found. -#: netbeans.c:406 msgid "Cannot connect to Netbeans #2" msgstr "No se pudo conectar a NetBeans #2" -#: netbeans.c:415 msgid "Cannot connect to Netbeans" msgstr "No se pudo conectar a NetBeans" # c-format -#: netbeans.c:461 #, c-format msgid "E668: Wrong access mode for NetBeans connection info file: \"%s\"" msgstr "E668: El dueño/a del archivo de conexión NetBeans no es válido: %s" -#: netbeans.c:770 msgid "read from Netbeans socket" msgstr "leído del socket NetBeans" -#: netbeans.c:1872 #, c-format msgid "E658: NetBeans connection lost for buffer %ld" msgstr "E658: Se perdió la conexión NetBeans para el búfer %ld" -#: netbeans.c:3692 msgid "E505: " msgstr "E505: " -#: normal.c:186 msgid "E349: No identifier under cursor" msgstr "E349: No hay ningún identificador bajo el cursor" -#: normal.c:2198 msgid "E774: 'operatorfunc' is empty" msgstr "E774: 'operatorfunc' está vacío" -#: normal.c:2217 msgid "E775: Eval feature not available" msgstr "E775: La característica \"eval\" no está disponible" -#: normal.c:3221 msgid "Warning: terminal cannot highlight" msgstr "Advertencia: la terminal no puede resaltar el texto" -#: normal.c:3516 msgid "E348: No string under cursor" msgstr "E348: No hay ninguna cadena bajo el cursor" -#: normal.c:4868 msgid "E352: Cannot erase folds with current 'foldmethod'" msgstr "E352: No se pudo borrar pliegues con el 'folmethod' actual" -#: normal.c:7365 msgid "E664: changelist is empty" msgstr "E664: La lista de cambios está vacía" -#: normal.c:7367 msgid "E662: At start of changelist" msgstr "E662: Al comienzo de la lista de cambios" -#: normal.c:7369 msgid "E663: At end of changelist" msgstr "E663: Al final de la lista de cambios" -#: normal.c:8734 msgid "Type :quit<Enter> to exit Vim" msgstr "Escriba \":quit<intro>\" para salir de Vim" -#: ops.c:293 #, c-format msgid "1 line %sed 1 time" msgstr "1 línea %sed 1 vez" -#: ops.c:295 #, c-format msgid "1 line %sed %d times" msgstr "1 línea %sed %d veces" -#: ops.c:300 #, c-format msgid "%ld lines %sed 1 time" msgstr "%ld líneas %sed 1 vez" -#: ops.c:303 #, c-format msgid "%ld lines %sed %d times" msgstr "%ld líneas %sed %d veces" -#: ops.c:691 #, c-format msgid "%ld lines to indent... " msgstr "%ld líneas por sangrar..." -#: ops.c:742 msgid "1 line indented " msgstr "1 línea sangrada" -#: ops.c:744 #, c-format msgid "%ld lines indented " msgstr "%ld líneas sangradas" -#: ops.c:1170 msgid "E748: No previously used register" msgstr "E748: No hay registro previamente en uso" # must display the prompt -#. must display the prompt -#: ops.c:1734 msgid "cannot yank; delete anyway" msgstr "No se pudo copiar \"yank\"; ¿Lo borro de todas formas?" -#: ops.c:2331 msgid "1 line changed" msgstr "1 línea cambiada" -#: ops.c:2333 #, c-format msgid "%ld lines changed" msgstr "%ld líneas cambiadas" -#: ops.c:2788 #, c-format msgid "freeing %ld lines" msgstr "liberando %ld líneas" -#: ops.c:3073 msgid "block of 1 line yanked" msgstr "bloque de 1 línea copiada" -#: ops.c:3076 msgid "1 line yanked" msgstr "1 línea copiada" -#: ops.c:3080 #, c-format msgid "block of %ld lines yanked" msgstr "bloque de %ld líneas copiadas" -#: ops.c:3083 #, c-format msgid "%ld lines yanked" msgstr "%ld líneas copiadas" -#: ops.c:3378 #, c-format msgid "E353: Nothing in register %s" msgstr "E353: No hay nada en el registro %s" # Highlight title -#. Highlight title -#: ops.c:3970 msgid "" "\n" "--- Registers ---" @@ -5293,11 +4125,9 @@ msgstr "" "\n" "--- Registros ---" -#: ops.c:5344 msgid "Illegal register name" msgstr "Nombre de registro ilegal" -#: ops.c:5440 #, c-format msgid "" "\n" @@ -5306,23 +4136,19 @@ msgstr "" "\n" "# Registros:\n" -#: ops.c:5497 #, c-format msgid "E574: Unknown register type %d" msgstr "E574: Registro desconocido de tipo %d" -#: ops.c:6435 #, c-format msgid "%ld Cols; " msgstr "%ld Cols; " -#: ops.c:6444 #, c-format msgid "Selected %s%ld of %ld Lines; %ld of %ld Words; %ld of %ld Bytes" msgstr "" "Selección %s%ld de %ld Líneas; %ld de %ld Palabras; %ld de %ld Caracteres" -#: ops.c:6451 #, c-format msgid "" "Selected %s%ld of %ld Lines; %ld of %ld Words; %ld of %ld Chars; %ld of %ld " @@ -5331,12 +4157,10 @@ msgstr "" "Selección %s%ld de %ld Líneas; %ld de %ld Palabras; %ld de %ld Caracteres; %" "ld de %ld Bytes" -#: ops.c:6470 #, c-format msgid "Col %s of %s; Line %ld of %ld; Word %ld of %ld; Byte %ld of %ld" msgstr "Col %s de %s; Línea %ld de %ld; Palabra %ld de %ld; Byte %ld de %ld" -#: ops.c:6478 #, c-format msgid "" "Col %s of %s; Line %ld of %ld; Word %ld of %ld; Char %ld of %ld; Byte %ld of " @@ -5345,173 +4169,131 @@ msgstr "" "Col %s de %s; Línea %ld de %ld; Palabra %ld de %ld; Carácter %ld de %ld Byte " "%ld de %ld" -#: ops.c:6490 #, c-format msgid "(+%ld for BOM)" msgstr "(+%ld para BOM)" -#: option.c:1953 msgid "%<%f%h%m%=Page %N" msgstr "%<%f%h%m%=Página %N" -#: option.c:2524 msgid "Thanks for flying Vim" msgstr "Gracias por volar con Vim" -#: option.c:4099 option.c:4242 msgid "E518: Unknown option" msgstr "E518: Opción desconocida" -#: option.c:4112 msgid "E519: Option not supported" msgstr "E519: Opción no admitida" -#: option.c:4150 msgid "E520: Not allowed in a modeline" msgstr "E520: No permitido en una \"modeline\"" -#: option.c:4368 msgid "E521: Number required after =" msgstr "E521: Debe introducir un número después de \"=\"" -#: option.c:4693 option.c:5499 msgid "E522: Not found in termcap" msgstr "E522: No lo encontré en el \"termcap\"" -#: option.c:4810 #, c-format msgid "E539: Illegal character <%s>" msgstr "E539: Carácter ilegal <%s>" -#: option.c:5491 msgid "E529: Cannot set 'term' to empty string" msgstr "E529: No se pudo definir \"term\" como una cadena de caracteres vacía" -#: option.c:5494 msgid "E530: Cannot change term in GUI" msgstr "E530: No se pudo cambiar \"term\" en la interfaz gráfica" -#: option.c:5496 msgid "E531: Use \":gui\" to start the GUI" msgstr "E531: Use \":gui\" para iniciar la interfaz gráfica" -#: option.c:5525 msgid "E589: 'backupext' and 'patchmode' are equal" msgstr "E589: \"backupext\" y \"patchmode\" son iguales" -#: option.c:5753 msgid "E617: Cannot be changed in the GTK+ 2 GUI" msgstr "E617: No puede cambiarse en la interfaz gráfica de GTK+ 2" -#: option.c:5931 msgid "E524: Missing colon" msgstr "E524: Falta un símbolo de dos puntos" -#: option.c:5933 msgid "E525: Zero length string" msgstr "E525: Cadena de caracteres de largo cero" -#: option.c:6016 #, c-format msgid "E526: Missing number after <%s>" msgstr "E526: Falta el número después de <%s>" -#: option.c:6030 msgid "E527: Missing comma" msgstr "E527: Falta una coma" -#: option.c:6037 msgid "E528: Must specify a ' value" msgstr "E528: Debe especificar un valor " -#: option.c:6086 msgid "E595: contains unprintable or wide character" msgstr "E595: Contiene un carácter no imprimible o de más de un byte" -#: option.c:6130 msgid "E596: Invalid font(s)" msgstr "E596: Las fuente/s de impresión no son válidas" -#: option.c:6139 msgid "E597: can't select fontset" msgstr "E597: No se pudo seleccionar ese \"fontset\"" -#: option.c:6141 msgid "E598: Invalid fontset" msgstr "E598: El conjunto de tipos de letra de impresión no es válido" -#: option.c:6149 msgid "E533: can't select wide font" msgstr "" "E533: No se pudo seleccionar el tipo de letra de impresión \"ancho\" (de " "\"byte\" doble)" -#: option.c:6151 msgid "E534: Invalid wide font" msgstr "E534: Tipo de letra de impresión \"ancho\" inválida" -#: option.c:6477 #, c-format msgid "E535: Illegal character after <%c>" msgstr "E535: Carácter ilegal después de <%c>" -#: option.c:6597 msgid "E536: comma required" msgstr "E536: necesita una coma" -#: option.c:6607 #, c-format msgid "E537: 'commentstring' must be empty or contain %s" msgstr "E537: 'commentstring' debe estar vacío o contener %s" -#: option.c:6688 msgid "E538: No mouse support" msgstr "E538: No hay soporte para el ratón" -#: option.c:7007 msgid "E540: Unclosed expression sequence" msgstr "E540: Secuencia de expresión sin cerrar" -#: option.c:7011 msgid "E541: too many items" msgstr "E541: Demasiados elementos" -#: option.c:7013 msgid "E542: unbalanced groups" msgstr "E542: Grupos sin equilibrar" -#: option.c:7349 msgid "E590: A preview window already exists" msgstr "E590: Ya existe una ventana de visualización previa" -#: option.c:7605 msgid "W17: Arabic requires UTF-8, do ':set encoding=utf-8'" msgstr "W17: La opción árabe necesita de UTF-8, use \":set encoding=utf-8\"" -#: option.c:8028 #, c-format msgid "E593: Need at least %d lines" msgstr "E593: Necesita al menos %d líneas" -#: option.c:8038 #, c-format msgid "E594: Need at least %d columns" msgstr "E594: Necesita al menos %d columnas" -#: option.c:8357 #, c-format msgid "E355: Unknown option: %s" msgstr "E355: Opción desconocida: %s" -#. There's another character after zeros or the string -#. * is empty. In both cases, we are trying to set a -#. * num option using a string. -#: option.c:8389 #, c-format msgid "E521: Number required: &%s = '%s'" msgstr "E521: Debe introducir un número: &%s = '%s'" -#: option.c:8513 msgid "" "\n" "--- Terminal codes ---" @@ -5519,7 +4301,6 @@ msgstr "" "\n" "--- Códigos de terminal ---" -#: option.c:8515 msgid "" "\n" "--- Global option values ---" @@ -5527,7 +4308,6 @@ msgstr "" "\n" "--- Valores de las opciones globales ---" -#: option.c:8517 msgid "" "\n" "--- Local option values ---" @@ -5535,7 +4315,6 @@ msgstr "" "\n" "--- Valores de las opciones locales ---" -#: option.c:8519 msgid "" "\n" "--- Options ---" @@ -5543,150 +4322,117 @@ msgstr "" "\n" "--- Opciones ---" -#: option.c:9332 msgid "E356: get_varp ERROR" msgstr "E356: ERROR en \"get_varp\"" -#: option.c:10431 #, c-format msgid "E357: 'langmap': Matching character missing for %s" msgstr "E357: \"langmap\": falta carácter coincidente para %s" -#: option.c:10463 #, c-format msgid "E358: 'langmap': Extra characters after semicolon: %s" msgstr "E358: \"langmap\": caracteres extra después del punto y coma: %s" -#: os_amiga.c:278 msgid "cannot open " msgstr "No se pudo abrir" -#: os_amiga.c:313 msgid "VIM: Can't open window!\n" msgstr "VIM: ¡No se pudo abrir la ventana!\n" -#: os_amiga.c:340 msgid "Need Amigados version 2.04 or later\n" msgstr "Necesito Amigados 2.04 o una versión posterior\n" -#: os_amiga.c:346 #, c-format msgid "Need %s version %ld\n" msgstr "Necesito %s versión %ld\n" -#: os_amiga.c:419 msgid "Cannot open NIL:\n" msgstr "No se pudo abrir NIL:\n" -#: os_amiga.c:437 msgid "Cannot create " msgstr "No se pudo crear " -#: os_amiga.c:943 #, c-format msgid "Vim exiting with %d\n" msgstr "Saliendo de Vim con %d\n" -#: os_amiga.c:979 msgid "cannot change console mode ?!\n" msgstr "¡¿No se pudo cambiar el modo de la consola?!\n" -#: os_amiga.c:1057 msgid "mch_get_shellsize: not a console??\n" msgstr "\"mch_get_shellsize\": ¿No es una consola?\n" # if Vim opened a window: Executing a shell may cause crashes -#. if Vim opened a window: Executing a shell may cause crashes -#: os_amiga.c:1212 msgid "E360: Cannot execute shell with -f option" msgstr "E360: No se pudo ejecutar el intérprete de órdenes con la opción -f" -#: os_amiga.c:1253 os_amiga.c:1343 msgid "Cannot execute " msgstr "No se puede ejecutar " -#: os_amiga.c:1256 os_amiga.c:1353 msgid "shell " msgstr "shell " -#: os_amiga.c:1276 os_amiga.c:1378 msgid " returned\n" msgstr " devolvió\n" -#: os_amiga.c:1540 msgid "ANCHOR_BUF_SIZE too small." msgstr "\"ANCHOR_BUF_SIZE\" demasiado pequeño." -#: os_amiga.c:1544 msgid "I/O ERROR" msgstr "ERROR I/O" -#: os_mswin.c:595 msgid "Message" msgstr "Mensaje" -#: os_mswin.c:710 msgid "'columns' is not 80, cannot execute external commands" msgstr "\"columns\" no es 80, no puede ejecutar órdenes externas" -#: os_mswin.c:2143 msgid "E237: Printer selection failed" msgstr "E237: Falló la selección de impresora" -#: os_mswin.c:2183 #, c-format msgid "to %s on %s" msgstr "para %s en %s" -#: os_mswin.c:2198 #, c-format msgid "E613: Unknown printer font: %s" msgstr "E613: Tipo de letra de impresión desconocida en la impresora: %s" -#: os_mswin.c:2247 os_mswin.c:2257 #, c-format msgid "E238: Print error: %s" msgstr "E238: Error de impresión: %s" -#: os_mswin.c:2285 #, c-format msgid "Printing '%s'" msgstr "Imprimiendo %s" -#: os_mswin.c:3461 #, c-format msgid "E244: Illegal charset name \"%s\" in font name \"%s\"" msgstr "" "E244: El nombre del conjunto de caracteres \"%s\" no es válido en el " "nombre del tipo de letra de impresión \"%s\"" -#: os_mswin.c:3471 #, c-format msgid "E245: Illegal char '%c' in font name \"%s\"" msgstr "" "E245: Carácter '%c' ilegal en el nombre del tipo de letra de " "impresión %s" -#: os_unix.c:1065 msgid "Vim: Double signal, exiting\n" msgstr "Vim: Señal doble, saliendo\n" -#: os_unix.c:1071 #, c-format msgid "Vim: Caught deadly signal %s\n" msgstr "Vim: Capté una señal mortal %s\n" -#: os_unix.c:1074 #, c-format msgid "Vim: Caught deadly signal\n" msgstr "Vim: Capté una señal mortal\n" -#: os_unix.c:1412 #, c-format msgid "Opening the X display took %ld msec" msgstr "Abrir la pantalla X tomó %ld mseg" -#: os_unix.c:1439 msgid "" "\n" "Vim: Got X error\n" @@ -5694,15 +4440,12 @@ msgstr "" "\n" "Vim: Hay un error de X\n" -#: os_unix.c:1544 msgid "Testing the X display failed" msgstr "Falló la prueba del sistema X" -#: os_unix.c:1684 msgid "Opening the X display timed out" msgstr "El \"display\" de X tardó demasiado en abrirse" -#: os_unix.c:2658 os_unix.c:2665 msgid "" "\n" "Could not get security context for " @@ -5710,7 +4453,6 @@ msgstr "" "\n" "No se pudo obtener el contexto de seguridad para " -#: os_unix.c:2675 msgid "" "\n" "Could not set security context for " @@ -5718,7 +4460,6 @@ msgstr "" "\n" "No se pudo definir el contexto de seguridad para " -#: os_unix.c:3695 os_unix.c:4620 msgid "" "\n" "Cannot execute shell " @@ -5726,7 +4467,6 @@ msgstr "" "\n" "No se pudo ejecutar el intérprete de órdenes " -#: os_unix.c:3743 msgid "" "\n" "Cannot execute shell sh\n" @@ -5734,7 +4474,6 @@ msgstr "" "\n" "No se pudo ejecutar el intérprete de órdenes \"sh\"\n" -#: os_unix.c:3747 os_unix.c:4626 msgid "" "\n" "shell returned " @@ -5742,7 +4481,6 @@ msgstr "" "\n" "El intérprete de órdenes devolvió " -#: os_unix.c:3891 msgid "" "\n" "Cannot create pipes\n" @@ -5750,7 +4488,6 @@ msgstr "" "\n" "No se pudo crear \"pipes\"\n" -#: os_unix.c:3905 os_unix.c:4169 msgid "" "\n" "Cannot fork\n" @@ -5758,7 +4495,6 @@ msgstr "" "\n" "No se pudo crear proceso secundario \"fork\"\n" -#: os_unix.c:4633 msgid "" "\n" "Command terminated\n" @@ -5766,79 +4502,61 @@ msgstr "" "\n" "La orden fue terminada\n" -#: os_unix.c:4919 os_unix.c:5069 os_unix.c:6792 msgid "XSMP lost ICE connection" msgstr "XSMP perdió la conexión ICE" -#: os_unix.c:6192 os_unix.c:6295 #, c-format msgid "dlerror = \"%s\"" msgstr "dlerror = \"%s\"" -#: os_unix.c:6377 msgid "Opening the X display failed" msgstr "Falló la apertura de la pantalla de X" -#: os_unix.c:6701 msgid "XSMP handling save-yourself request" msgstr "XSMP está manejando una solicitud de \"guardelo usted mismo\"" -#: os_unix.c:6815 msgid "XSMP opening connection" msgstr "XSMP está abriendo una conexión" -#: os_unix.c:6834 msgid "XSMP ICE connection watch failed" msgstr "XSMP Falló el supervisión de la conexión ICE" -#: os_unix.c:6858 #, c-format msgid "XSMP SmcOpenConnection failed: %s" msgstr "XSMP SmcOpenConnection falló: %s" -#: os_vms_mms.c:60 msgid "At line" msgstr "En la línea" -#: os_w32exe.c:89 msgid "Could not load vim32.dll!" msgstr "¡No se pudo cargar \"vim32.dll\"!" -#: os_w32exe.c:89 os_w32exe.c:100 msgid "VIM Error" msgstr "Error de Vim" -#: os_w32exe.c:99 msgid "Could not fix up function pointers to the DLL!" msgstr "¡No se pudo conectar los punteros de la función a la DLL!" -#: os_win16.c:342 os_win32.c:3399 #, c-format msgid "shell returned %d" msgstr "El intérprete de órdenes ha devuelto %d" -#: os_win32.c:2856 #, c-format msgid "Vim: Caught %s event\n" msgstr "Vim: Capté el evento %s\n" -#: os_win32.c:2858 msgid "close" msgstr "cerrar" -#: os_win32.c:2860 msgid "logoff" msgstr "cerrar la sesión" -#: os_win32.c:2861 msgid "shutdown" msgstr "apagar" -#: os_win32.c:3351 msgid "E371: Command not found" msgstr "E371: No se encontró la orden" -#: os_win32.c:3364 msgid "" "VIMRUN.EXE not found in your $PATH.\n" "External commands will not pause after completion.\n" @@ -5848,363 +4566,280 @@ msgstr "" "Las órdenes externas no harán una pausa al finalizar.\n" "Véase \":help win32-vimrun\" para más información" -#: os_win32.c:3367 msgid "Vim Warning" msgstr "Advertencia de Vim" -#: quickfix.c:330 #, c-format msgid "E372: Too many %%%c in format string" msgstr "E372: Demasiados %%%c en la cadena de formato" -#: quickfix.c:343 #, c-format msgid "E373: Unexpected %%%c in format string" msgstr "E373: %%%c inesperado en la cadena de formato" -#: quickfix.c:405 msgid "E374: Missing ] in format string" msgstr "E374: Falta ] en la cadena de formato" -#: quickfix.c:419 #, c-format msgid "E375: Unsupported %%%c in format string" msgstr "E375: %%%c no admitido en cadena de formato" -#: quickfix.c:439 #, c-format msgid "E376: Invalid %%%c in format string prefix" msgstr "E376: %%%c no es válido en el prefijo de una cadena de formato" -#: quickfix.c:447 #, c-format msgid "E377: Invalid %%%c in format string" msgstr "E377: %%%c no es válido en una cadena de formato" -#: quickfix.c:473 msgid "E378: 'errorformat' contains no pattern" msgstr "E378: 'errorformat' no contiene un patrón" -#: quickfix.c:706 msgid "E379: Missing or empty directory name" msgstr "E379: Hace falta el nombre del directorio" -#: quickfix.c:1408 msgid "E553: No more items" msgstr "E553: No hay más elementos" -#: quickfix.c:1830 #, c-format msgid "(%d of %d)%s%s: " msgstr "(%d de %d)%s%s: " -#: quickfix.c:1832 msgid " (line deleted)" msgstr " (línea borrada)" -#: quickfix.c:2061 msgid "E380: At bottom of quickfix stack" msgstr "E380: Al final de la pila de corrección rápida" -#: quickfix.c:2070 msgid "E381: At top of quickfix stack" msgstr "E381: Al principio de la pila de corrección rápida" -#: quickfix.c:2084 #, c-format msgid "error list %d of %d; %d errors" msgstr "lista de errores %d de %d: %d errores" -#: quickfix.c:2670 msgid "E382: Cannot write, 'buftype' option is set" msgstr "E382: No se pudo escribir, la opción \"buftype\" está activa" -#: quickfix.c:3074 msgid "E683: File name missing or invalid pattern" msgstr "E683: Falta el nombre del archivo o el patrón no es válido" -#: quickfix.c:3172 #, c-format msgid "Cannot open file \"%s\"" msgstr "No se pudo abrir el archivo %s" -#: quickfix.c:3705 msgid "E681: Buffer is not loaded" msgstr "E681: El búfer no está cargado" -#: quickfix.c:3766 msgid "E777: String or List expected" msgstr "E777: Se esperaba una lista o una cadena de caracteres" -#: regexp.c:331 #, c-format msgid "E369: invalid item in %s%%[]" msgstr "E369: El elemento en %s%%[] no es válido" -#: regexp.c:1017 msgid "E339: Pattern too long" msgstr "E339: Patrón demasiado largo" -#: regexp.c:1189 msgid "E50: Too many \\z(" msgstr "E50: Demasiados \\z(" -#: regexp.c:1200 #, c-format msgid "E51: Too many %s(" msgstr "E51: Hay demasiados %s(" -#: regexp.c:1257 msgid "E52: Unmatched \\z(" msgstr "E52: \\z( sin complemento" -#: regexp.c:1261 #, c-format msgid "E53: Unmatched %s%%(" msgstr "E53: %s%%( sin complemento" -#: regexp.c:1263 #, c-format msgid "E54: Unmatched %s(" msgstr "E54: %s( sin complemento" -#: regexp.c:1268 #, c-format msgid "E55: Unmatched %s)" msgstr "E55: %s) sin complemento" -#: regexp.c:1484 #, c-format msgid "E59: invalid character after %s@" msgstr "E59: Carácter inválido después de %s@" -#: regexp.c:1518 #, c-format msgid "E60: Too many complex %s{...}s" msgstr "E60: Hay demasiados %s{...}s complejos" -#: regexp.c:1534 #, c-format msgid "E61: Nested %s*" msgstr "E61: Anidado %s*" -#: regexp.c:1537 #, c-format msgid "E62: Nested %s%c" msgstr "E62: Anidado %s%c" -#: regexp.c:1657 msgid "E63: invalid use of \\_" msgstr "E63: Uso inválido de \\_" -#: regexp.c:1713 #, c-format msgid "E64: %s%c follows nothing" msgstr "E64: %s%c no sigue a nada" -#: regexp.c:1769 msgid "E65: Illegal back reference" msgstr "E65: Referencia inversa ilegal" -#: regexp.c:1782 msgid "E66: \\z( not allowed here" msgstr "E66: No se permite \\z( aquí" -#: regexp.c:1801 msgid "E67: \\z1 - \\z9 not allowed here" msgstr "E67: \\z1 - \\z9 no se permiten aquí" # Es preferible traducir "invalid" por "no [es] válido" pues "inválido" no es lo suficientemente claro. Además, no es políticamente correcto :-) ALV -#: regexp.c:1813 msgid "E68: Invalid character after \\z" msgstr "E68: Hay un carácter no válido después de \\z" -#: regexp.c:1865 #, c-format msgid "E69: Missing ] after %s%%[" msgstr "E69: Falta ] después de %s%%[" -#: regexp.c:1881 #, c-format msgid "E70: Empty %s%%[]" msgstr "E70: %s%%[] vacío" -#: regexp.c:1926 #, c-format msgid "E678: Invalid character after %s%%[dxouU]" msgstr "E678: Carácter no válido después de %s%%[dxouU]" -#: regexp.c:1997 #, c-format msgid "E71: Invalid character after %s%%" msgstr "E71: Carácter ilegal después de %s%%" -#: regexp.c:2290 #, c-format msgid "E769: Missing ] after %s[" msgstr "E769: Falta ] después de %s[" -#: regexp.c:2978 #, c-format msgid "E554: Syntax error in %s{...}" msgstr "E554: Error de sintaxis en %s{...}" -#: regexp.c:3821 msgid "External submatches:\n" msgstr "Sub-coincidencias externas:\n" -#: screen.c:9072 msgid " VREPLACE" msgstr " REEMPLAZO VIRTUAL" -#: screen.c:9076 msgid " REPLACE" msgstr " REEMPLAZAR" -#: screen.c:9081 msgid " REVERSE" msgstr " INVERTIR" -#: screen.c:9083 msgid " INSERT" msgstr " INSERTAR" -#: screen.c:9086 msgid " (insert)" msgstr " (insertar)" -#: screen.c:9088 msgid " (replace)" msgstr " (reemplazar)" -#: screen.c:9090 msgid " (vreplace)" msgstr " (reemplazo virtual)" -#: screen.c:9093 msgid " Hebrew" msgstr " hebreo" -#: screen.c:9104 msgid " Arabic" msgstr " árabe" -#: screen.c:9107 msgid " (lang)" msgstr " (idioma)" -#: screen.c:9111 msgid " (paste)" msgstr " (pegar)" -#: screen.c:9124 msgid " VISUAL" msgstr " VISUAL" -#: screen.c:9125 msgid " VISUAL LINE" msgstr " LÍNEA VISUAL" -#: screen.c:9126 msgid " VISUAL BLOCK" msgstr " BLOQUE VISUAL" -#: screen.c:9127 msgid " SELECT" msgstr " SELECCIONAR" -#: screen.c:9128 msgid " SELECT LINE" msgstr " SELECCIONAR LÍNEA" -#: screen.c:9129 msgid " SELECT BLOCK" msgstr " SELECCIONAR BLOQUE" -#: screen.c:9145 screen.c:9211 msgid "recording" msgstr "grabando" -#: search.c:562 #, c-format msgid "E383: Invalid search string: %s" msgstr "E383: La cadena de búsqueda no es válida: %s" -#: search.c:983 #, c-format msgid "E384: search hit TOP without match for: %s" msgstr "E384: La búsqueda ha llegado al PRINCIPIO sin coincidir con: %s" -#: search.c:986 #, c-format msgid "E385: search hit BOTTOM without match for: %s" msgstr "E385: La búsqueda ha llegado al FINAL sin coincidir con: %s" -#: search.c:1415 msgid "E386: Expected '?' or '/' after ';'" msgstr "E386: Esperaba \"?\" o \"/\" después de \";\"" -#: search.c:4681 msgid " (includes previously listed match)" msgstr " (incluye la coincidencia mostrada previamente)" # cursor at status line -#. cursor at status line -#: search.c:4701 msgid "--- Included files " msgstr "--- Archivos incluidos " -#: search.c:4703 msgid "not found " msgstr "no se encontrṕ" -#: search.c:4704 msgid "in path ---\n" msgstr "en la ruta ---\n" -#: search.c:4761 msgid " (Already listed)" msgstr " (Ya está listado)" -#: search.c:4763 msgid " NOT FOUND" msgstr " NO SE ENCONTRÓ" -#: search.c:4817 #, c-format msgid "Scanning included file: %s" msgstr "Explorando el archivo incluido: %s" -#: search.c:4826 #, c-format msgid "Searching included file %s" msgstr "Buscando en el archivo incluido: %s" -#: search.c:5049 msgid "E387: Match is on current line" msgstr "E387: La coincidencia está en la línea bajo el cursor" -#: search.c:5193 msgid "All included files were found" msgstr "Se han encontrado todos los archivos incluidos" -#: search.c:5195 msgid "No included files" msgstr "No hay archivos incluidos" -#: search.c:5211 msgid "E388: Couldn't find definition" msgstr "E388: La definición no se encontró" -#: search.c:5213 msgid "E389: Couldn't find pattern" msgstr "E389: El patrón no se encontró" -#: search.c:5391 msgid "Substitute " msgstr "Sustitución" -#: search.c:5404 #, c-format msgid "" "\n" @@ -6215,104 +4850,82 @@ msgstr "" "# Último %sPatrón de búsqueda:\n" "~" -#: spell.c:989 msgid "E759: Format error in spell file" msgstr "E759: Error de formato en el archivo de ortografía" -#: spell.c:990 msgid "E758: Truncated spell file" msgstr "E758: Archivo de ortografía truncado" -#: spell.c:991 #, c-format msgid "Trailing text in %s line %d: %s" msgstr "Texto sobrante en %s línea %d: %s" -#: spell.c:992 #, c-format msgid "Affix name too long in %s line %d: %s" msgstr "Nombre de afijo demasiado largo en %s línea %d: %s" -#: spell.c:993 msgid "E761: Format error in affix file FOL, LOW or UPP" msgstr "E761: Error de formato en el archivo de afijos FOL, LOW o UPP" -#: spell.c:994 msgid "E762: Character in FOL, LOW or UPP is out of range" msgstr "E762: El carácter en FOL, LOW o UPP está fuera de rango" -#: spell.c:995 msgid "Compressing word tree..." msgstr "Comprimiendo el árbol de palabras..." -#: spell.c:2149 msgid "E756: Spell checking is not enabled" msgstr "E756: La corrección ortográfica está desactivada" -#: spell.c:2502 #, c-format msgid "Warning: Cannot find word list \"%s.%s.spl\" or \"%s.ascii.spl\"" msgstr "" "Advertencia: No se pudo hallar la lista de palabras \"%s.%s.spl\" " "or \"%s.ascii.spl\"" -#: spell.c:2776 #, c-format msgid "Reading spell file \"%s\"" msgstr "Leyendo archivo de ortografía \"%s\"" -#: spell.c:2808 msgid "E757: This does not look like a spell file" msgstr "E757: Esto no parece un archivo de ortografía" -#: spell.c:2814 msgid "E771: Old spell file, needs to be updated" msgstr "E771: Archivo de ortografía obsoleto, debe actualizarlo" -#: spell.c:2819 msgid "E772: Spell file is for newer version of Vim" msgstr "E772: El archivo de ortografía es para una versión de Vim más reciente" -#: spell.c:2922 msgid "E770: Unsupported section in spell file" msgstr "E770: Sección no compatible en el archivo de ortografía" -#: spell.c:4417 #, c-format msgid "Warning: region %s not supported" msgstr "Advertencia: la región %s no es compatible" -#: spell.c:5307 #, c-format msgid "Reading affix file %s..." msgstr "Leyendo el archivo de afijos \"%s\"..." -#: spell.c:5355 spell.c:6699 spell.c:7278 #, c-format msgid "Conversion failure for word in %s line %d: %s" msgstr "La conversión falló para la palabra en %s línea %d: %s" -#: spell.c:5403 spell.c:7313 #, c-format msgid "Conversion in %s not supported: from %s to %s" msgstr "La conversión en %s no es posible: de %s a %s" -#: spell.c:5407 spell.c:7318 #, c-format msgid "Conversion in %s not supported" msgstr "La conversión a %s no es posible en esta versión" -#: spell.c:5420 #, c-format msgid "Invalid value for FLAG in %s line %d: %s" msgstr "El valor para \"FLAG\" no es válido en la %s línea %d: %s" -#: spell.c:5433 #, c-format msgid "FLAG after using flags in %s line %d: %s" msgstr "\"FLAG\" después de usar parámetros en %s línea %d: %s" -#: spell.c:5524 #, c-format msgid "" "Defining COMPOUNDFORBIDFLAG after PFX item may give wrong results in %s line " @@ -6321,7 +4934,6 @@ msgstr "" "Definir COMPOUNDFORBIDFLAG después de un elemento PFX puede dar resultados " "erróneos en %s línea %d" -#: spell.c:5533 #, c-format msgid "" "Defining COMPOUNDPERMITFLAG after PFX item may give wrong results in %s line " @@ -6330,44 +4942,36 @@ msgstr "" "Definir COMPOUNDPERMITFLAG después de un ítem PFX puede dar resultados " "erróneos en %s línea %d" -#: spell.c:5554 #, c-format msgid "Wrong COMPOUNDRULES value in %s line %d: %s" msgstr "Valor equivocado de COMPOUNDRULES %s línea %d: %s" -#: spell.c:5581 #, c-format msgid "Wrong COMPOUNDWORDMAX value in %s line %d: %s" msgstr "Valor equivocado de COMPOUNDWORDMAX en %s línea %d: %s" -#: spell.c:5589 #, c-format msgid "Wrong COMPOUNDMIN value in %s line %d: %s" msgstr "Valor equivocado de COMPOUNDMIN en %s línea %d: %s" -#: spell.c:5597 #, c-format msgid "Wrong COMPOUNDSYLMAX value in %s line %d: %s" msgstr "Valor equivocado de COMPOUNDSYLMAX en %s línea %d: %s" -#: spell.c:5619 #, c-format msgid "Wrong CHECKCOMPOUNDPATTERN value in %s line %d: %s" msgstr "Valor equivocado de CHECKCOMPOUNDPATTERN en %s línea %d: %s" -#: spell.c:5685 #, c-format msgid "Different combining flag in continued affix block in %s line %d: %s" msgstr "" "Marca de combinación diferente en el bloque de afijos continuo " "en %s línea %d: %s" -#: spell.c:5688 #, c-format msgid "Duplicate affix in %s line %d: %s" msgstr "Afijo duplicado en %s línea %d: %s" -#: spell.c:5710 #, c-format msgid "" "Affix also used for BAD/RARE/KEEPCASE/NEEDAFFIX/NEEDCOMPOUND/NOSUGGEST in %s " @@ -6376,338 +4980,261 @@ msgstr "" "Afijo usado también para BAD/RARE/KEEPCASE/NEEDAFFIX/NEEDCOMPOUND/NOSUGGEST " "en %s línea %d: %s" -#: spell.c:5734 #, c-format msgid "Expected Y or N in %s line %d: %s" msgstr "Esperaba Y o N en %s línea %d: %s" -#: spell.c:5818 #, c-format msgid "Broken condition in %s line %d: %s" msgstr "Condición inválida en %s línea %d: %s" -#: spell.c:5966 #, c-format msgid "Expected REP(SAL) count in %s line %d" msgstr "Esperaba conteo REP(SAL) en %s línea %d" -#: spell.c:6001 #, c-format msgid "Expected MAP count in %s line %d" msgstr "Esperaba conteo MAP en %s línea %d" -#: spell.c:6020 #, c-format msgid "Duplicate character in MAP in %s line %d" msgstr "Carácter duplicado en MAP en %s línea %d" -#: spell.c:6077 #, c-format msgid "Unrecognized or duplicate item in %s line %d: %s" msgstr "Elemento no reconocido o duplicado en %s línea %d: %s" -#: spell.c:6105 #, c-format msgid "Missing FOL/LOW/UPP line in %s" msgstr "Falta una línea FOL/LOW/UPP en %s" -#: spell.c:6131 msgid "COMPOUNDSYLMAX used without SYLLABLE" msgstr "COMPOUNDSYLMAX usado sin SYLLABLE" -#: spell.c:6149 msgid "Too many postponed prefixes" msgstr "Hay demasiados prefijos postpuestos" -#: spell.c:6151 msgid "Too many compound flags" msgstr "Demasiados parámetros compuestos" -#: spell.c:6153 msgid "Too many postponed prefixes and/or compound flags" msgstr "Demasiados prefijos postpuestos y/o \"flags\" compuestos" -#: spell.c:6165 #, c-format msgid "Missing SOFO%s line in %s" msgstr "Falta una línea SOFO%s en %s" -#: spell.c:6168 #, c-format msgid "Both SAL and SOFO lines in %s" msgstr "Líneas SAL y SOFO en %s" -#: spell.c:6275 #, c-format msgid "Flag is not a number in %s line %d: %s" msgstr "La marca no es un número en %s línea %d: %s" -#: spell.c:6278 #, c-format msgid "Illegal flag in %s line %d: %s" msgstr "Marca ilegal en %s line %d: %s" -#: spell.c:6495 spell.c:6508 #, c-format msgid "%s value differs from what is used in another .aff file" msgstr "El valor %s difiere de los que se usa en otro archivo .aff" -#: spell.c:6660 #, c-format msgid "Reading dictionary file %s..." msgstr "Leyendo el archivo de diccionario %s..." -#: spell.c:6669 #, c-format msgid "E760: No word count in %s" msgstr "E760: No hay cuenta de palabras en %s" -#: spell.c:6740 #, c-format msgid "line %6d, word %6d - %s" msgstr "línea %6d, palabra %6d - %s" -#: spell.c:6764 #, c-format msgid "Duplicate word in %s line %d: %s" msgstr "Palabra duplicada en %s línea %d: %s" -#: spell.c:6767 #, c-format msgid "First duplicate word in %s line %d: %s" msgstr "Primera palabra duplicada en %s line %d: %s" -#: spell.c:6822 #, c-format msgid "%d duplicate word(s) in %s" msgstr "%d palabra(s) duplicada(s) en %s" -#: spell.c:6824 #, c-format msgid "Ignored %d word(s) with non-ASCII characters in %s" msgstr "Ignorando %d palabra(s) con caracteres no-ASCII en %s" -#: spell.c:7247 #, c-format msgid "Reading word file %s..." msgstr "Leyendo archivo de palabras \"%s\"..." -#: spell.c:7297 #, c-format msgid "Duplicate /encoding= line ignored in %s line %d: %s" msgstr "Ignorando línea /encoding= duplicada en %s line %d: %s" -#: spell.c:7300 #, c-format msgid "/encoding= line after word ignored in %s line %d: %s" msgstr "Ignorando línea /encoding= después de palabra en %s línea %d: %s" -#: spell.c:7327 #, c-format msgid "Duplicate /regions= line ignored in %s line %d: %s" msgstr "Ignorando línea /regions= en %s línea %d: %s" -#: spell.c:7333 #, c-format msgid "Too many regions in %s line %d: %s" msgstr "Demasiadas regiones en %s línea %d: %s" -#: spell.c:7347 #, c-format msgid "/ line ignored in %s line %d: %s" msgstr "Ignorando línea / en %s línea %d: %s" -#: spell.c:7377 #, c-format msgid "Invalid region nr in %s line %d: %s" msgstr "Región nr no válida en %s línea %d: %s" -#: spell.c:7385 #, c-format msgid "Unrecognized flags in %s line %d: %s" msgstr "Parámetros no reconocidos en %s línea %d: %s" -#: spell.c:7415 #, c-format msgid "Ignored %d words with non-ASCII characters" msgstr "Ignorando %d palabras con caracteres no-ASCII" -#: spell.c:7876 #, c-format msgid "Compressed %d of %d nodes; %d (%d%%) remaining" msgstr "Comprimiendo %d de %d nodos; faltan %d (%d%%)" -#: spell.c:8720 msgid "Reading back spell file..." msgstr "Releyendo el archivo de ortografía ..." -#. -#. * Go through the trie of good words, soundfold each word and add it to -#. * the soundfold trie. -#. -#: spell.c:8741 msgid "Performing soundfolding..." msgstr "Ejecutando compresión fonética" -#: spell.c:8754 #, c-format msgid "Number of words after soundfolding: %ld" msgstr "Número de palabras después de la compresión fonética: %ld" -#: spell.c:8879 #, c-format msgid "Total number of words: %d" msgstr "Número total de palabras: %d" -#: spell.c:9096 #, c-format msgid "Writing suggestion file %s..." msgstr "Escribiendo el archivo de sugerencias %s..." -#: spell.c:9157 spell.c:9418 #, c-format msgid "Estimated runtime memory use: %d bytes" msgstr "Uso de memoria estimado al usar: %d bytes" -#: spell.c:9289 msgid "E751: Output file name must not have region name" msgstr "" "E751: El nombre del archivo de salida no debe contener un nombre de región" -#: spell.c:9291 msgid "E754: Only up to 8 regions supported" msgstr "E754: Solo se pueden usar hasta 8 regiones" -#: spell.c:9321 #, c-format msgid "E755: Invalid region in %s" msgstr "E755: Región no válida en %s" -#: spell.c:9392 msgid "Warning: both compounding and NOBREAK specified" msgstr "Advertencia: Se especificó \"compounding\" y NOBREAK" -#: spell.c:9411 #, c-format msgid "Writing spell file %s..." msgstr "Escribiendo archivo de ortografía \"%s\"..." -#: spell.c:9416 msgid "Done!" msgstr "¡Listo!" -#: spell.c:9543 #, c-format msgid "E765: 'spellfile' does not have %ld entries" msgstr "E765: 'spellfile' no tiene entradas %ld" -#: spell.c:9588 #, c-format msgid "Word removed from %s" msgstr "Eliminando palabra de %s" -#: spell.c:9633 #, c-format msgid "Word added to %s" msgstr "Añadiendo palabra en \"%s\"" -#: spell.c:9946 msgid "E763: Word characters differ between spell files" msgstr "" "E763: Los caracteres de la palabra difieren entre archivos de ortografía" -#: spell.c:10321 msgid "Sorry, no suggestions" msgstr "Lo siento, no hay sugerencias" -#: spell.c:10325 #, c-format msgid "Sorry, only %ld suggestions" msgstr "Lo siento, solo hay %ld sugerencias" -#. for when 'cmdheight' > 1 -#. avoid more prompt -#: spell.c:10346 #, c-format msgid "Change \"%.*s\" to:" msgstr "\"%.*s\" cambió a:" -#: spell.c:10386 #, c-format msgid " < \"%.*s\"" msgstr " < \"%.*s\"" -#: spell.c:10562 msgid "E752: No previous spell replacement" msgstr "E752: No hay un reemplazo de ortografía previo" -#: spell.c:10612 #, c-format msgid "E753: Not found: %s" msgstr "E753: No se encontró: %s" -#: spell.c:11032 #, c-format msgid "E778: This does not look like a .sug file: %s" msgstr "E778: Esto no se parece a un archivo .sug: %s" -#: spell.c:11039 #, c-format msgid "E779: Old .sug file, needs to be updated: %s" msgstr "E779: Archivo .sug obsoleto, necesita una actualización: %s" -#: spell.c:11045 #, c-format msgid "E780: .sug file is for newer version of Vim: %s" msgstr "E780: El archivo .sug es para una versión más reciente de Vim: %s" -#: spell.c:11055 #, c-format msgid "E781: .sug file doesn't match .spl file: %s" msgstr "E781: El archivo .sug no corresponde al archivo .spl: %s" -#: spell.c:11068 #, c-format msgid "E782: error while reading .sug file: %s" msgstr "E782: Error al leer archivo .sig: %s" -#. This should have been checked when generating the .spl -#. * file. -#: spell.c:13765 msgid "E783: duplicate char in MAP entry" msgstr "E783: carácter duplicado en entrada MAP" -#: syntax.c:3245 syntax.c:3271 #, c-format msgid "E390: Illegal argument: %s" msgstr "E390: Argumento ilegal: %s" -#: syntax.c:3453 #, c-format msgid "E391: No such syntax cluster: %s" msgstr "E391: No existe tal agrupamiento sintáctico: %s" -#: syntax.c:3612 msgid "No Syntax items defined for this buffer" msgstr "No hay elementos sintácticos definidos para este búfer" -#: syntax.c:3620 msgid "syncing on C-style comments" msgstr "Sincronizando con los comentarios de estilo \"C\"" -#: syntax.c:3628 msgid "no syncing" msgstr "no hay sincronización" -#: syntax.c:3631 msgid "syncing starts " msgstr "Comenzando sincronización" -#: syntax.c:3633 syntax.c:3708 msgid " lines before top line" msgstr " líneas antes de la línea superior" -#: syntax.c:3638 msgid "" "\n" "--- Syntax sync items ---" @@ -6715,7 +5242,6 @@ msgstr "" "\n" "--- Elementos de sincronización de sintaxis ---" -#: syntax.c:3643 msgid "" "\n" "syncing on items" @@ -6723,7 +5249,6 @@ msgstr "" "\n" "sincronizando con los elementos" -#: syntax.c:3649 msgid "" "\n" "--- Syntax items ---" @@ -6731,260 +5256,203 @@ msgstr "" "\n" "--- Elementos sintácticos ---" -#: syntax.c:3672 #, c-format msgid "E392: No such syntax cluster: %s" msgstr "E392: No existe tal agrupamiento sintáctico: %s" -#: syntax.c:3698 msgid "minimal " msgstr "mínimo" -#: syntax.c:3705 msgid "maximal " msgstr "máximo" -#: syntax.c:3717 msgid "; match " msgstr "; coincide" -#: syntax.c:3719 msgid " line breaks" msgstr " líneas de quiebre" -#: syntax.c:4347 msgid "E395: contains argument not accepted here" msgstr "E395: el contenido del argumento no se acepta aquí" -#: syntax.c:4358 msgid "E396: containedin argument not accepted here" msgstr "E396: el argumento \"containedin\" no se acepta aquí" -#: syntax.c:4380 msgid "E393: group[t]here not accepted here" msgstr "E393: \"grouphere\" y \"groupthere\" no son válidos aquí" -#: syntax.c:4404 #, c-format msgid "E394: Didn't find region item for %s" msgstr "E394: No se encuentra el elemento de la región para %s" -#: syntax.c:4481 msgid "E397: Filename required" msgstr "E397: Debe proporcionar un nombre de archivo" -#: syntax.c:4603 #, c-format msgid "E789: Missing ']': %s" msgstr "E789: Falta un ']': %s" -#: syntax.c:4843 #, c-format msgid "E398: Missing '=': %s" msgstr "E398: Falta un '=': %s" -#: syntax.c:5002 #, c-format msgid "E399: Not enough arguments: syntax region %s" msgstr "E399: Argumentos insuficientes: región de sintaxis %s" -#: syntax.c:5336 msgid "E400: No cluster specified" msgstr "E400: No se ha especificado una agrupación" -#: syntax.c:5373 #, c-format msgid "E401: Pattern delimiter not found: %s" msgstr "E401: No hay un delimitador de patrón: %s" -#: syntax.c:5448 #, c-format msgid "E402: Garbage after pattern: %s" msgstr "E402: Basura después del patrón: %s" -#: syntax.c:5537 msgid "E403: syntax sync: line continuations pattern specified twice" msgstr "" "E403: Sincronización de sintaxis: Se especificó dos veces un " "patrón de continuación de línea" -#: syntax.c:5594 #, c-format msgid "E404: Illegal arguments: %s" msgstr "E404: Argumentos ilegales: %s" -#: syntax.c:5644 #, c-format msgid "E405: Missing equal sign: %s" msgstr "E405: Falta el signo igual: %s" -#: syntax.c:5650 #, c-format msgid "E406: Empty argument: %s" msgstr "E406: Argumento vacío: %s" -#: syntax.c:5676 #, c-format msgid "E407: %s not allowed here" msgstr "E407: %s no se permite aquí" -#: syntax.c:5683 #, c-format msgid "E408: %s must be first in contains list" msgstr "E408: %s debe ser el primero en la lista de contenido" -#: syntax.c:5753 #, c-format msgid "E409: Unknown group name: %s" msgstr "E409: Nombre de grupo desconocido: %s" -#: syntax.c:5988 #, c-format msgid "E410: Invalid :syntax subcommand: %s" msgstr "E410: Suborden \":syntax\" no válido: %s" -#: syntax.c:6475 msgid "E679: recursive loop loading syncolor.vim" msgstr "E679: bucle recursivo al cargar \"syncolor.vim\"" -#: syntax.c:6602 #, c-format msgid "E411: highlight group not found: %s" msgstr "E411: grupo de resaltado no encontrado: %s" -#: syntax.c:6626 #, c-format msgid "E412: Not enough arguments: \":highlight link %s\"" msgstr "E412: Argumentos insuficientes: \":highlight link %s\"" -#: syntax.c:6633 #, c-format msgid "E413: Too many arguments: \":highlight link %s\"" msgstr "E413: Demasiados argumentos: \":highlight link %s\"" -#: syntax.c:6653 msgid "E414: group has settings, highlight link ignored" msgstr "E414: Esta grupo está configurado, se ignora el enlace resaltado" -#: syntax.c:6785 #, c-format msgid "E415: unexpected equal sign: %s" msgstr "E415: Signo \"=\" inesperado: %s" -#: syntax.c:6821 #, c-format msgid "E416: missing equal sign: %s" msgstr "E416: Falta el signo \"=\": %s" -#: syntax.c:6849 #, c-format msgid "E417: missing argument: %s" msgstr "E417: Falta el argumento: %s" -#: syntax.c:6886 #, c-format msgid "E418: Illegal value: %s" msgstr "E418: Valor ilegal: %s" -#: syntax.c:7005 msgid "E419: FG color unknown" msgstr "E419: Color en primer plano desconocido" -#: syntax.c:7016 msgid "E420: BG color unknown" msgstr "E420: Color de fondo desconocido" -#: syntax.c:7077 #, c-format msgid "E421: Color name or number not recognized: %s" msgstr "E421: Nombre o número de color desconocido: %s" -#: syntax.c:7304 #, c-format msgid "E422: terminal code too long: %s" msgstr "E422: Código de terminal demasiado largo: %s" -#: syntax.c:7351 #, c-format msgid "E423: Illegal argument: %s" msgstr "E423: Argumento ilegal: %s" -#: syntax.c:7912 msgid "E424: Too many different highlighting attributes in use" msgstr "E424: Hay demasiados atributos de resaltado sintáctico en uso" -#: syntax.c:8649 msgid "E669: Unprintable character in group name" msgstr "E669: Carácter no imprimible en el nombre del grupo" # This is an error, but since there previously was no check only # * give a warning. -#: syntax.c:8657 msgid "W18: Invalid character in group name" msgstr "W18: Hay un carácter no válido en el nombre del grupo" -#: tag.c:85 msgid "E555: at bottom of tag stack" msgstr "E555: En el final de la pila de etiquetas" -#: tag.c:86 msgid "E556: at top of tag stack" msgstr "E556: En el principio de la pila de etiquetas" -#: tag.c:434 msgid "E425: Cannot go before first matching tag" msgstr "E425: No se pudo ir antes de la primer etiqueta coincidente" -#: tag.c:583 #, c-format msgid "E426: tag not found: %s" msgstr "E426: No se encontró la etiqueta: %s" -#: tag.c:616 msgid " # pri kind tag" msgstr " # etiqueta tipo \"pri\"" -#: tag.c:619 msgid "file\n" msgstr "archivo\n" -#: tag.c:953 msgid "E427: There is only one matching tag" msgstr "E427: Sólo coincide una etiqueta" -#: tag.c:955 msgid "E428: Cannot go beyond last matching tag" msgstr "E428: No se pudo ir más allá de la última etiqueta coincidente" -#: tag.c:979 #, c-format msgid "File \"%s\" does not exist" msgstr "No existe el archivo \"%s\"" # Give an indication of the number of matching tags -#. Give an indication of the number of matching tags -#: tag.c:991 #, c-format msgid "tag %d of %d%s" msgstr "etiqueta %d de %d%s" -#: tag.c:994 msgid " or more" msgstr " o más" -#: tag.c:996 msgid " Using tag with different case!" msgstr "" " ¡Está usando una etiqueta con mayúsculas y minúsculas que no coinciden!" -#: tag.c:1051 #, c-format msgid "E429: File \"%s\" does not exist" msgstr "E429: El archivo \"%s\" no existe" # Highlight title -#. Highlight title -#: tag.c:1119 msgid "" "\n" " # TO tag FROM line in file/text" @@ -6992,81 +5460,62 @@ msgstr "" "\n" " # A etiqueta DESDE la línea en el archivo/texto" -#: tag.c:1546 #, c-format msgid "Searching tags file %s" msgstr "Buscando el archivo de etiquetas %s" -#: tag.c:1737 #, c-format msgid "E430: Tag file path truncated for %s\n" msgstr "E430: La ruta del archivo de etiquetas %s está truncada\n" -#: tag.c:2388 #, c-format msgid "E431: Format error in tags file \"%s\"" msgstr "E431: Error de formato en el archivo de etiquetas \"%s\"" -#: tag.c:2392 #, c-format msgid "Before byte %ld" msgstr "Adelante del byte %ld" -#: tag.c:2425 #, c-format msgid "E432: Tags file not sorted: %s" msgstr "E432: Archivo de etiquetas sin ordenar: %s" # never opened any tags file -#. never opened any tags file -#: tag.c:2469 msgid "E433: No tags file" msgstr "E433: No hay archivo de etiquetas" -#: tag.c:2748 msgid "Ignoring long line in tags file" msgstr "Ignorando la línea larga en el archivo de etiquetas" -#: tag.c:3257 msgid "E434: Can't find tag pattern" msgstr "E434: No se pudo encontrar el patrón de la etiqueta" -#: tag.c:3268 msgid "E435: Couldn't find tag, just guessing!" msgstr "E435: No se pudo encontrar la etiqueta. ¡Estoy adivinando!" -#: term.c:1793 msgid "' not known. Available builtin terminals are:" msgstr "' desconocido. Los terminales incorporados disponibles son:" -#: term.c:1817 msgid "defaulting to '" msgstr "Usando ' por defecto" -#: term.c:2172 msgid "E557: Cannot open termcap file" msgstr "E557: No se pudo abrir el archivo \"termcap\"" -#: term.c:2176 msgid "E558: Terminal entry not found in terminfo" msgstr "E558: No he encontrado la definición del terminal en \"terminfo\"" -#: term.c:2178 msgid "E559: Terminal entry not found in termcap" msgstr "E559: No he encontrado la definición del terminal en \"termcap\"" -#: term.c:2337 #, c-format msgid "E436: No \"%s\" entry in termcap" msgstr "E436: la entrada %s no existe en el archivo \"termcap\"" -#: term.c:2811 msgid "E437: terminal capability \"cm\" required" msgstr "E437: Se necesita la capacidad \"cm\" en el terminal" # Highlight title -#. Highlight title -#: term.c:5280 msgid "" "\n" "--- Terminal keys ---" @@ -7074,106 +5523,80 @@ msgstr "" "\n" "--- Teclas de la terminal ---" -#: ui.c:284 msgid "new shell started\n" msgstr "Iniciado nuevo intérprete de órdenes\n" -#: ui.c:1886 msgid "Vim: Error reading input, exiting...\n" msgstr "Vim: error al leer la entrada, saliendo...\n" -#: ui.c:2409 msgid "Used CUT_BUFFER0 instead of empty selection" msgstr "Se ha usado \"CUT_BUFFER0\" en vez de una selección vacía" # must display the prompt -#. must display the prompt -#: undo.c:645 msgid "No undo possible; continue anyway" msgstr "No es posible deshacer; continuando de todos modos" -#: undo.c:727 undo.c:937 msgid "Already at oldest change" msgstr "Este es el cambio más antiguo" -#: undo.c:742 undo.c:939 msgid "Already at newest change" msgstr "Este es el cambio más nuevo" -#: undo.c:930 #, c-format msgid "Undo number %ld not found" msgstr "No se encontró el número de \"deshacer\" %ld" -#: undo.c:1100 msgid "E438: u_undo: line numbers wrong" msgstr "E438: \"u_undo\": números de línea erróneos" -#: undo.c:1338 msgid "more line" msgstr "Una línea más" -#: undo.c:1340 msgid "more lines" msgstr "líneas más" -#: undo.c:1342 msgid "line less" msgstr "una línea menos" -#: undo.c:1344 msgid "fewer lines" msgstr "líneas menos" -#: undo.c:1349 msgid "change" msgstr "cambio" -#: undo.c:1351 msgid "changes" msgstr "cambios" -#: undo.c:1375 #, c-format msgid "%ld %s; %s #%ld %s" msgstr "%ld %s; %s #%ld %s" -#: undo.c:1378 msgid "before" msgstr "antes" -#: undo.c:1378 msgid "after" msgstr "después" -#: undo.c:1486 msgid "Nothing to undo" msgstr "Nada que hacer" -#: undo.c:1492 msgid "number changes time" msgstr "el número modifica el tiempo" -#: undo.c:1525 #, c-format msgid "%ld seconds ago" msgstr "hace %ld segundos" -#: undo.c:1541 msgid "E790: undojoin is not allowed after undo" msgstr "E790: \"undojoin\" no está permitido después de \"undo\"" -#: undo.c:1591 msgid "E439: undo list corrupt" msgstr "E439: la lista de deshacer se ha dañado" -#: undo.c:1623 msgid "E440: undo line missing" msgstr "E440: falta la línea deshacer" # Only MS VC 4.1 and earlier can do Win32s -#. Only MS VC 4.1 and earlier can do Win32s -#: version.c:1366 msgid "" "\n" "MS-Windows 16/32-bit GUI version" @@ -7181,7 +5604,6 @@ msgstr "" "\n" "Versión de interfaz gráfica de 16/32 bits para MS-Windows" -#: version.c:1369 msgid "" "\n" "MS-Windows 64-bit GUI version" @@ -7189,7 +5611,6 @@ msgstr "" "\n" "Versión de interfaz gráfica de 64 bits para MS-Windows" -#: version.c:1371 msgid "" "\n" "MS-Windows 32-bit GUI version" @@ -7197,15 +5618,12 @@ msgstr "" "\n" "Versión de interfaz gráfica de 32 bits para MS-Windows" -#: version.c:1375 msgid " in Win32s mode" msgstr " en modo Win32s" -#: version.c:1377 msgid " with OLE support" msgstr " con compatibilidad con OLE" -#: version.c:1381 msgid "" "\n" "MS-Windows 64-bit console version" @@ -7213,7 +5631,6 @@ msgstr "" "\n" "Versión de 64 bits para consola de MS-Windows" -#: version.c:1383 msgid "" "\n" "MS-Windows 32-bit console version" @@ -7221,7 +5638,6 @@ msgstr "" "\n" "Versión de 32 bits para consola de MS-Windows" -#: version.c:1388 msgid "" "\n" "MS-Windows 16-bit version" @@ -7229,7 +5645,6 @@ msgstr "" "\n" "Versión de 16 bits para MS-Windows" -#: version.c:1392 msgid "" "\n" "32-bit MS-DOS version" @@ -7237,7 +5652,6 @@ msgstr "" "\n" "Versión de 32 bits para MS-DOS" -#: version.c:1394 msgid "" "\n" "16-bit MS-DOS version" @@ -7245,7 +5659,6 @@ msgstr "" "\n" "Versión de 16 bits para MS-DOS" -#: version.c:1400 msgid "" "\n" "MacOS X (unix) version" @@ -7253,7 +5666,6 @@ msgstr "" "\n" "Versión para X (Unix) para MacOS" -#: version.c:1402 msgid "" "\n" "MacOS X version" @@ -7261,7 +5673,6 @@ msgstr "" "\n" "Versión para MacOS X" -#: version.c:1405 msgid "" "\n" "MacOS version" @@ -7269,7 +5680,6 @@ msgstr "" "\n" "Versión para MacOS" -#: version.c:1410 msgid "" "\n" "RISC OS version" @@ -7277,7 +5687,6 @@ msgstr "" "\n" "Versión para RISC OS" -#: version.c:1413 msgid "" "\n" "OpenVMS version" @@ -7285,7 +5694,6 @@ msgstr "" "\n" "Versión para OpenVMS" -#: version.c:1428 msgid "" "\n" "Included patches: " @@ -7293,7 +5701,6 @@ msgstr "" "\n" "Parches incluidos: " -#: version.c:1455 msgid "" "\n" "Extra patches: " @@ -7301,11 +5708,9 @@ msgstr "" "\n" "Parches adicionales: " -#: version.c:1467 version.c:1831 msgid "Modified by " msgstr "Modificado por " -#: version.c:1474 msgid "" "\n" "Compiled " @@ -7313,11 +5718,9 @@ msgstr "" "\n" "Compilado " -#: version.c:1477 msgid "by " msgstr "por " -#: version.c:1489 msgid "" "\n" "Huge version " @@ -7325,7 +5728,6 @@ msgstr "" "\n" "Versión \"enorme\" " -#: version.c:1492 msgid "" "\n" "Big version " @@ -7333,7 +5735,6 @@ msgstr "" "\n" "Versión \"grande\" " -#: version.c:1495 msgid "" "\n" "Normal version " @@ -7341,7 +5742,6 @@ msgstr "" "\n" "Versión \"normal\" " -#: version.c:1498 msgid "" "\n" "Small version " @@ -7349,7 +5749,6 @@ msgstr "" "\n" "Versión \"pequeña\" " -#: version.c:1500 msgid "" "\n" "Tiny version " @@ -7357,330 +5756,250 @@ msgstr "" "\n" "Versión \"diminuta\" " -#: version.c:1506 msgid "without GUI." msgstr "sin interfaz gráfica (GUI)." -#: version.c:1511 msgid "with GTK2-GNOME GUI." msgstr "con interfaz gráfica para GTK2-GNOME." -#: version.c:1513 msgid "with GTK-GNOME GUI." msgstr "con interfaz gráfica para GTK-GNOME." -#: version.c:1517 msgid "with GTK2 GUI." msgstr "con interfaz gráfica de GTK2." -#: version.c:1519 msgid "with GTK GUI." msgstr "con interfaz gráfica de GTK." -#: version.c:1524 msgid "with X11-Motif GUI." msgstr "con interfaz gráfica para X11-Motif." -#: version.c:1528 msgid "with X11-neXtaw GUI." msgstr "con interfaz gráfica de X11-neXtaw." -#: version.c:1530 msgid "with X11-Athena GUI." msgstr "con interfaz gráfica de X11-Athena." -#: version.c:1534 msgid "with Photon GUI." msgstr "con interfaz gráfica para Photon." -#: version.c:1537 msgid "with GUI." msgstr "con interfaz gráfica de usuario." -#: version.c:1540 msgid "with Carbon GUI." msgstr "con GUI Carbon." -#: version.c:1543 msgid "with Cocoa GUI." msgstr "con interfaz gráfica para Cocoa." -#: version.c:1546 msgid "with (classic) GUI." msgstr "con interfaz gráfica (clásica)." -#: version.c:1556 msgid " Features included (+) or not (-):\n" msgstr " Aspectos incluidos (+) o no (-):\n" -#: version.c:1568 msgid " system vimrc file: \"" msgstr " archivo \"vimrc\" del sistema: \"" -#: version.c:1573 msgid " user vimrc file: \"" msgstr " archivo \"vimrc\" del usuario: \"" -#: version.c:1578 msgid " 2nd user vimrc file: \"" msgstr " 2º archivo \"vimrc\" del usuario: \"" -#: version.c:1583 msgid " 3rd user vimrc file: \"" msgstr " 3er archivo \"vimrc\" del usuario: \"" -#: version.c:1588 msgid " user exrc file: \"" msgstr " archivo \"exrc\" del usuario: \"" -#: version.c:1593 msgid " 2nd user exrc file: \"" msgstr " 2º archivo \"exrc\" del usuario: \"" -#: version.c:1599 msgid " system gvimrc file: \"" msgstr " archivo \"gvimrc\" del sistema: \"" -#: version.c:1603 msgid " user gvimrc file: \"" msgstr " archivo \"gvimrc\" del usuario: \"" -#: version.c:1607 msgid "2nd user gvimrc file: \"" msgstr " 2º archivo \"gvimrc\" del usuario: \"" -#: version.c:1612 msgid "3rd user gvimrc file: \"" msgstr "3er archivo \"gvimrc\" del usuario: \"" -#: version.c:1619 msgid " system menu file: \"" msgstr " archivo de menú del sistema: \"" -#: version.c:1627 msgid " fall-back for $VIM: \"" msgstr " predefinido para $VIM: \"" -#: version.c:1633 msgid " f-b for $VIMRUNTIME: \"" msgstr " predefinido para $VIMRUNTIME: \"" -#: version.c:1637 msgid "Compilation: " msgstr "Compilación: " -#: version.c:1643 msgid "Compiler: " msgstr "Compilador: " -#: version.c:1648 msgid "Linking: " msgstr "Enlazado: " -#: version.c:1653 msgid " DEBUG BUILD" msgstr " COMPILACIÓN CON SÍMBOLOS DE DEPURACIÓN" -#: version.c:1692 msgid "VIM - Vi IMproved" msgstr "VIM - VI Mejorado" -#: version.c:1694 msgid "version " msgstr "versión " -#: version.c:1695 msgid "by Bram Moolenaar et al." msgstr "por Bram Moolenaar et al." -#: version.c:1699 msgid "Vim is open source and freely distributable" msgstr "Vim es código abierto y se puede distribuir libremente" -#: version.c:1701 msgid "Help poor children in Uganda!" msgstr "¡Ayude a los niños pobres de Uganda!" -#: version.c:1702 msgid "type :help iccf<Enter> for information " msgstr "escriba «:help iccf<Intro>» para más información " -#: version.c:1704 msgid "type :q<Enter> to exit " msgstr "escriba «:q<Intro>» para salir " -#: version.c:1705 msgid "type :help<Enter> or <F1> for on-line help" msgstr "escriba «:help<Intro>» o <F1> para obtener ayuda " -#: version.c:1706 msgid "type :help version8<Enter> for version info" msgstr "escriba «:help version8<Intro>» para información de la versión" -#: version.c:1709 msgid "Running in Vi compatible mode" msgstr "Ejecutando en modo compatible con Vi" -#: version.c:1710 msgid "type :set nocp<Enter> for Vim defaults" msgstr "escriba «:set nocp<Intro>» para los valores predefinidos de Vim" -#: version.c:1711 msgid "type :help cp-default<Enter> for info on this" msgstr "escriba «:help cp-default<Intro>» para más información" -#: version.c:1726 msgid "menu Help->Orphans for information " msgstr "menú Ayuda->Ayude a los niños huérfanos para más información " -#: version.c:1728 msgid "Running modeless, typed text is inserted" msgstr "Ejecución no modal, el texto escrito se inserta directamente" -#: version.c:1729 msgid "menu Edit->Global Settings->Toggle Insert Mode " msgstr "menú Editar->Opciones globales->Activar/Desactivar modo de inserción" -#: version.c:1730 msgid " for two modes " msgstr " para dos modos " -#: version.c:1734 msgid "menu Edit->Global Settings->Toggle Vi Compatible" msgstr "" "menú Editar->Opciones globales->Activar/Desactivar compatibilidad con Vi" -#: version.c:1735 msgid " for Vim defaults " msgstr "" " para los valores predeterminados de Vim" -#: version.c:1782 msgid "Sponsor Vim development!" msgstr "¡Patrocine el desarrollo de Vim!" -#: version.c:1783 msgid "Become a registered Vim user!" msgstr "¡Conviértase en un usuario registrado de Vim!" -#: version.c:1786 msgid "type :help sponsor<Enter> for information " msgstr "escriba «:help sponsor<Intro>» para más información " -#: version.c:1787 msgid "type :help register<Enter> for information " msgstr "escriba «:help register<Intro>» para más información " -#: version.c:1789 msgid "menu Help->Sponsor/Register for information " msgstr "menú Ayuda->Benefactor/Regístrese para más información" -#: version.c:1799 msgid "WARNING: Windows 95/98/ME detected" msgstr "ADVERTENCIA: se ha detectado Windows 95/98/ME" -#: version.c:1802 msgid "type :help windows95<Enter> for info on this" msgstr "escriba «:help windows95<Intro>» para más información" -#: window.c:88 msgid "Already only one window" msgstr "Solo hay una ventana" -#: window.c:237 msgid "E441: There is no preview window" msgstr "E441: No hay una ventana de vista previa" -#: window.c:672 msgid "E442: Can't split topleft and botright at the same time" msgstr "E442: No se puede dividir arriba izq. y abajo der. al mismo tiempo" -#: window.c:1484 msgid "E443: Cannot rotate when another window is split" msgstr "E443: No se puede rotar cuando otra ventana está dividida" -#: window.c:2113 msgid "E444: Cannot close last window" msgstr "E444: No se puede cerrar la última ventana" -#: window.c:2120 msgid "E813: Cannot close autocmd window" msgstr "E813: No se puede cerrar la ventana de autocmd" -#: window.c:2125 msgid "E814: Cannot close window, only autocmd window would remain" msgstr "" "E814: No se pudo cerrar la última ventana, solo quedará " "la ventana de autocmd" -#: window.c:3188 msgid "E445: Other window contains changes" msgstr "E445: Otra ventana contiene cambios" -#: window.c:5868 msgid "E446: No file name under cursor" msgstr "E446: No hay un nombre de archivo bajo el cursor" -#: window.c:6005 #, c-format msgid "E447: Can't find file \"%s\" in path" msgstr "E447: No se pudo encontrar el archivo \"%s\" en la ruta" -#: if_perl.xs:420 globals.h:1420 #, c-format msgid "E370: Could not load library %s" msgstr "E370: No se pudo cargar la biblioteca dinámica %s" -#: if_perl.xs:671 msgid "Sorry, this command is disabled: the Perl library could not be loaded." msgstr "Esta orden está desactivada, no se pudo cargar la biblioteca de Perl" -#: if_perl.xs:726 msgid "E299: Perl evaluation forbidden in sandbox without the Safe module" msgstr "" "E299: No se permite la evaluación de código Perl en la caja de " "arena sin el uso del módulo \"Safe\"" -#: GvimExt/gvimext.cpp:587 msgid "Edit with &multiple Vims" msgstr "Editar con &múltiples Vims" -#: GvimExt/gvimext.cpp:593 msgid "Edit with single &Vim" msgstr "Editar con un solo &Vim" -#: GvimExt/gvimext.cpp:602 msgid "Diff with Vim" msgstr "Diff con Vim" -#: GvimExt/gvimext.cpp:615 msgid "Edit with &Vim" msgstr "Editar con &Vim" # Now concatenate -#. Now concatenate -#: GvimExt/gvimext.cpp:637 msgid "Edit with existing Vim - " msgstr "Editar con un Vim en ejecución -" -#: GvimExt/gvimext.cpp:752 msgid "Edits the selected file(s) with Vim" msgstr "Editar el(los) archivos seleccionado/s con Vim" -#: GvimExt/gvimext.cpp:891 GvimExt/gvimext.cpp:972 msgid "Error creating process: Check if gvim is in your path!" msgstr "" "Error al crear el proceso: ¡Asegúrese de que gvim esta en su ruta de acceso!" -#: GvimExt/gvimext.cpp:892 GvimExt/gvimext.cpp:906 GvimExt/gvimext.cpp:973 msgid "gvimext.dll error" msgstr "error de \"gvimext.dll\"" -#: GvimExt/gvimext.cpp:905 msgid "Path length too long!" msgstr "¡La ruta de acceso es demasiado larga!" -#: globals.h:1174 msgid "--No lines in buffer--" msgstr "--No hay líneas en el búfer--" @@ -7688,460 +6007,345 @@ msgstr "--No hay líneas en el búfer--" # * The error messages that can be shared are included here. # * Excluded are errors that are only used once and debugging messages. # -#. -#. * The error messages that can be shared are included here. -#. * Excluded are errors that are only used once and debugging messages. -#. -#: globals.h:1374 msgid "E470: Command aborted" msgstr "E470: La orden se ha interrumpido" -#: globals.h:1375 msgid "E471: Argument required" msgstr "E471: Es necesario un argumento" -#: globals.h:1376 msgid "E10: \\ should be followed by /, ? or &" msgstr "E10: \\ debería ir seguido de \"/\", \"?\" o \"&\"" -#: globals.h:1378 msgid "E11: Invalid in command-line window; <CR> executes, CTRL-C quits" msgstr "" "E11: Inválido en la ventana de la línea de órdenes: <CR> ejecuta, CTRL-C " "cierra" -#: globals.h:1380 msgid "E12: Command not allowed from exrc/vimrc in current dir or tag search" msgstr "" "E12: Orden no permitida desde exrc/vimrc en el directorio " "en uso o al buscar etiquetas" -#: globals.h:1382 msgid "E171: Missing :endif" msgstr "E171: Falta \":endif\"" -#: globals.h:1383 msgid "E600: Missing :endtry" msgstr "E600: Falta \":endtry\"" -#: globals.h:1384 msgid "E170: Missing :endwhile" msgstr "E170: Falta \":endwhile\"" -#: globals.h:1385 msgid "E170: Missing :endfor" msgstr "E170: Falta \":endfor\"" -#: globals.h:1386 msgid "E588: :endwhile without :while" msgstr "E588: \":endwhile\" sin \":while\"" -#: globals.h:1387 msgid "E588: :endfor without :for" msgstr "E588: \":endfor\" sin un \":for\"" -#: globals.h:1389 msgid "E13: File exists (add ! to override)" msgstr "E13: El archivo ya existe (use \"!\" para sobreescribir)" -#: globals.h:1390 msgid "E472: Command failed" msgstr "E472: La orden falló" -#: globals.h:1392 #, c-format msgid "E234: Unknown fontset: %s" msgstr "E234: Conjunto de tipos de letra de impresión desconocido: %s" -#: globals.h:1396 #, c-format msgid "E235: Unknown font: %s" msgstr "E235: Tipo de letra de impresión desconocida: %s" -#: globals.h:1399 #, c-format msgid "E236: Font \"%s\" is not fixed-width" msgstr "E236: El tipo de letra de impresión \"%s\" no es de ancho fijo" -#: globals.h:1401 msgid "E473: Internal error" msgstr "E473: Error interno" -#: globals.h:1402 msgid "Interrupted" msgstr "Interrumpido" -#: globals.h:1403 msgid "E14: Invalid address" msgstr "E14: La dirección no es válida" -#: globals.h:1404 msgid "E474: Invalid argument" msgstr "E474: El argumento no es válido" -#: globals.h:1405 #, c-format msgid "E475: Invalid argument: %s" msgstr "E475: El argumento no es válido: %s" -#: globals.h:1407 #, c-format msgid "E15: Invalid expression: %s" msgstr "E15: La expresión no es válida: %s" -#: globals.h:1409 msgid "E16: Invalid range" msgstr "E16: El rango no es válido" -#: globals.h:1410 msgid "E476: Invalid command" msgstr "E476: La orden no es válida" -#: globals.h:1412 #, c-format msgid "E17: \"%s\" is a directory" msgstr "E17: \"%s\" es un directorio" -#: globals.h:1415 #, c-format msgid "E364: Library call failed for \"%s()\"" msgstr "E364: Falló la llamada a la biblioteca para \"%s()\"" -#: globals.h:1421 #, c-format msgid "E448: Could not load library function %s" msgstr "E448: No pude cargar la biblioteca de funciones %s" -#: globals.h:1423 msgid "E19: Mark has invalid line number" msgstr "E19: El número de línea de la marca no es válido" -#: globals.h:1424 msgid "E20: Mark not set" msgstr "E20: No se ha colocado una marca" -#: globals.h:1425 msgid "E21: Cannot make changes, 'modifiable' is off" msgstr "E21: No se pudo modificar, 'modifiable' está desactivado" -#: globals.h:1426 msgid "E22: Scripts nested too deep" msgstr "E22: Demasiados archivos de órdenes anidados" -#: globals.h:1427 msgid "E23: No alternate file" msgstr "E23: No hay un archivo alterno" -#: globals.h:1428 msgid "E24: No such abbreviation" msgstr "E24: No existe esa abreviatura" -#: globals.h:1429 msgid "E477: No ! allowed" msgstr "E477: \"!\" no está permitido" -#: globals.h:1431 msgid "E25: GUI cannot be used: Not enabled at compile time" msgstr "" "E25: No se puede usar la interfaz gráfica de usuario: No se activó al " "compilar" -#: globals.h:1434 msgid "E26: Hebrew cannot be used: Not enabled at compile time\n" msgstr "E26: No se pudo usar el hebreo: no se activó al compilar\n" -#: globals.h:1437 msgid "E27: Farsi cannot be used: Not enabled at compile time\n" msgstr "E27: No se pudo usar el persa (farsi): no se activó al compilar\n" -#: globals.h:1440 msgid "E800: Arabic cannot be used: Not enabled at compile time\n" msgstr "E800: No se pudo usar el árabe: no se activó al compilar\n" -#: globals.h:1443 #, c-format msgid "E28: No such highlight group name: %s" msgstr "E28: No existe un grupo de resaltado de nombre: %s" -#: globals.h:1445 msgid "E29: No inserted text yet" msgstr "E29: Aún no ha insertado texto" -#: globals.h:1446 msgid "E30: No previous command line" msgstr "E30: No hay una línea de órdenes previa" -#: globals.h:1447 msgid "E31: No such mapping" msgstr "E31: No existe tal asociación" -#: globals.h:1448 msgid "E479: No match" msgstr "E479: No hay coincidencia" -#: globals.h:1449 #, c-format msgid "E480: No match: %s" msgstr "E480: No coincide: %s" -#: globals.h:1450 msgid "E32: No file name" msgstr "E32: No hay un nombre de archivo" -#: globals.h:1451 msgid "E33: No previous substitute regular expression" msgstr "E33: No existe una expresión regular de sustitución previa" -#: globals.h:1452 msgid "E34: No previous command" msgstr "E34: No existe una orden previa" -#: globals.h:1453 msgid "E35: No previous regular expression" msgstr "E35: No existe una expresión regular previa" -#: globals.h:1454 msgid "E481: No range allowed" msgstr "E481: El rango no está permitido" -#: globals.h:1456 msgid "E36: Not enough room" msgstr "E36: No hay espacio suficiente" -#: globals.h:1459 #, c-format msgid "E247: no registered server named \"%s\"" msgstr "E247: El servidor llamado \"%s\" no está registrado" -#: globals.h:1461 #, c-format msgid "E482: Can't create file %s" msgstr "E482: No se pudo crear el archivo \"%s\"" -#: globals.h:1462 msgid "E483: Can't get temp file name" msgstr "E483: No se pudo obtener el nombre del archivo temporal" -#: globals.h:1463 #, c-format msgid "E484: Can't open file %s" msgstr "E484: No se pudo abrir el archivo \"%s\"" -#: globals.h:1464 #, c-format msgid "E485: Can't read file %s" msgstr "E485: No se pudo leer el archivo \"%s\"" -#: globals.h:1465 msgid "E37: No write since last change (add ! to override)" msgstr "" "E37: No guardó el archivo desde el último cambio (añada \"!\" para forzar)" -#: globals.h:1466 msgid "E38: Null argument" msgstr "E38: Argumento nulo" -#: globals.h:1468 msgid "E39: Number expected" msgstr "E39: Se esperaba un número" -#: globals.h:1471 #, c-format msgid "E40: Can't open errorfile %s" msgstr "E40: No se pudo abrir el archivo de errores \"%s\"" -#: globals.h:1474 msgid "E233: cannot open display" msgstr "E233: No se pudo abrir la pantalla" -#: globals.h:1476 msgid "E41: Out of memory!" msgstr "E41: ¡Memoria agotada!" -#: globals.h:1478 msgid "Pattern not found" msgstr "No se encontró el patrón de búsqueda" -#: globals.h:1480 #, c-format msgid "E486: Pattern not found: %s" msgstr "E486: No se encontró el patrón de búsqueda: %s" -#: globals.h:1481 msgid "E487: Argument must be positive" msgstr "E487: El argumento debe ser positivo" -#: globals.h:1483 msgid "E459: Cannot go back to previous directory" msgstr "E459: No se pudo regresar al directorio previo" -#: globals.h:1487 msgid "E42: No Errors" msgstr "E42: No hay errores" -#: globals.h:1488 msgid "E776: No location list" msgstr "E776: No hay una lista de posiciones" -#: globals.h:1490 msgid "E43: Damaged match string" msgstr "E43: Cadena de coincidencia dañada" -#: globals.h:1491 msgid "E44: Corrupted regexp program" msgstr "E44: El programa \"regexp\" está corrupto" -#: globals.h:1492 msgid "E45: 'readonly' option is set (add ! to override)" msgstr "E45: La opción 'readonly' está activada (añada \"!\" para forzar)" -#: globals.h:1494 #, c-format msgid "E46: Cannot change read-only variable \"%s\"" msgstr "E46: No puede cambiar la variable de solo lectura \"%s\"" -#: globals.h:1495 #, c-format msgid "E794: Cannot set variable in the sandbox: \"%s\"" msgstr "E794: No se puede definir la variable en el \"sandbox\": \"%s\"" -#: globals.h:1498 msgid "E47: Error while reading errorfile" msgstr "E47: Error al leer el archivo de errores" -#: globals.h:1501 msgid "E48: Not allowed in sandbox" msgstr "E48: No se permite en el ambiente protegido" -#: globals.h:1503 msgid "E523: Not allowed here" msgstr "E523: No se permite aquí" -#: globals.h:1506 msgid "E359: Screen mode setting not supported" msgstr "E359: La configuración de la pantalla no es válida" -#: globals.h:1508 msgid "E49: Invalid scroll size" msgstr "E49: La longitud de desplazamiento no es válida" -#: globals.h:1509 msgid "E91: 'shell' option is empty" msgstr "E91: La opción 'shell' (intérprete de órdenes) está vacía" -#: globals.h:1511 msgid "E255: Couldn't read in sign data!" msgstr "E255: ¡No se pudo cargar los signos!" -#: globals.h:1513 msgid "E72: Close error on swap file" msgstr "E72: Error de cierre en el archivo de intercambio" -#: globals.h:1514 msgid "E73: tag stack empty" msgstr "E73: La pila de etiquetas ('tagstack') está vacía" -#: globals.h:1515 msgid "E74: Command too complex" msgstr "E74: La orden es demasiado compleja" -#: globals.h:1516 msgid "E75: Name too long" msgstr "E75: El nombre es demasiado largo" -#: globals.h:1517 msgid "E76: Too many [" msgstr "E76: Hay demasiados [" -#: globals.h:1518 msgid "E77: Too many file names" msgstr "E77: Hay demasiados nombres de archivos" -#: globals.h:1519 msgid "E488: Trailing characters" msgstr "E488: Caracteres en exceso al final de la línea" -#: globals.h:1520 msgid "E78: Unknown mark" msgstr "E78: Marca desconocida" -#: globals.h:1521 msgid "E79: Cannot expand wildcards" msgstr "E79: No se pudo expandir los comodines" -#: globals.h:1523 msgid "E591: 'winheight' cannot be smaller than 'winminheight'" msgstr "E591: \"winheight\" no puede ser más pequeño que \"winminheight\"" -#: globals.h:1525 msgid "E592: 'winwidth' cannot be smaller than 'winminwidth'" msgstr "E592: \"winwidth\" no puede ser más pequeño que \"winminwidth\"" -#: globals.h:1528 msgid "E80: Error while writing" msgstr "E80: Error al escribir el archivo" -#: globals.h:1529 msgid "Zero count" msgstr "El recuento es cero" -#: globals.h:1531 msgid "E81: Using <SID> not in a script context" msgstr "E81: Usando <SID> en un contexto que no es de archivo de órdenes" -#: globals.h:1534 msgid "E449: Invalid expression received" msgstr "E449: Se recibió una expresión inválida" -#: globals.h:1537 msgid "E463: Region is guarded, cannot modify" msgstr "E463: La región está protegida, no se puede modificar" -#: globals.h:1538 msgid "E744: NetBeans does not allow changes in read-only files" msgstr "E744: NetBeans no permite cambios a archivos de sólo lectura" -#: globals.h:1540 #, c-format msgid "E685: Internal error: %s" msgstr "E685: Error interno: %s" -#: globals.h:1541 msgid "E363: pattern uses more memory than 'maxmempattern'" msgstr "E363: El patrón usa más memoria que 'maxmempattern'" -#: globals.h:1542 msgid "E749: empty buffer" msgstr "E749: Búfer vacío" -#: globals.h:1545 msgid "E682: Invalid search pattern or delimiter" msgstr "E682: Patrón de búsqueda o delimitador no válido" # Overwriting a file that is loaded in another buffer is not a # * good idea. -#: globals.h:1547 msgid "E139: File is loaded in another buffer" msgstr "E139: El archivo ya se ha cargado en otro búfer" -#: globals.h:1550 #, c-format msgid "E764: Option '%s' is not set" msgstr "E764: No se ha definido la opción '%s'" -#: globals.h:1557 msgid "search hit TOP, continuing at BOTTOM" msgstr "La búsqueda ha llegado al PRINCIPIO, continuando desde el FINAL" -#: globals.h:1558 msgid "search hit BOTTOM, continuing at TOP" msgstr "La búsqueda ha llegado al FINAL, continuando desde el PRINCIPIO" -#~ msgid "[NL found]" -#~ msgstr "[NL encontrado]" -#~ msgid "E569: maximum number of cscope connections reached" -#~ msgstr "E569: Se ha alcanzado el número máximo de conexiones con \"cscope\"" - -#~ msgid "-V[N]\t\tVerbose level" -#~ msgstr "-V[N]\t\tNivel de verbosidad (traza de ejecución)" diff --git a/src/po/fi.po b/src/po/fi.po index 684c67661b..166472c482 100644 --- a/src/po/fi.po +++ b/src/po/fi.po @@ -2774,9 +2774,6 @@ msgstr "tuntematon vimOption" msgid "keyboard interrupt" msgstr "näppäimistökeskeytys" -msgid "vim error" -msgstr "vim-virhe" - msgid "cannot create buffer/window command: object is being deleted" msgstr "ei voi luoda puskuri- tai ikkunakomentoa, olio on poistumassa" @@ -3093,8 +3090,8 @@ msgstr "-W <skripti>\tKirjoita komennot <skripti>-tiedostoon" msgid "-x\t\t\tEdit encrypted files" msgstr "-x\t\t\tMuokkaa salattua tiedostoa" -msgid "-display <display>\tConnect vim to this particular X-server" -msgstr "-display <näyttö>\tYhdistä vim tiettyyn X-palvelimeen" +msgid "-display <display>\tConnect Vim to this particular X-server" +msgstr "-display <näyttö>\tYhdistä Vim tiettyyn X-palvelimeen" msgid "-X\t\t\tDo not connect to X server" msgstr "-X\t\t\tÄlä yhdistä X-palvelimeen" @@ -3177,10 +3174,10 @@ msgstr "" "\n" "Gvimin (Athena-version) tuntemat argumentit:\n" -msgid "-display <display>\tRun vim on <display>" -msgstr "-display <näyttö>\tSuorita vim <näytössä>" +msgid "-display <display>\tRun Vim on <display>" +msgstr "-display <näyttö>\tSuorita Vim <näytössä>" -msgid "-iconic\t\tStart vim iconified" +msgid "-iconic\t\tStart Vim iconified" msgstr "-iconic\t\tKäynnistä pienennettynä" msgid "-background <color>\tUse <color> for the background (also: -bg)" @@ -3228,8 +3225,8 @@ msgstr "" "\n" "Gvimin (GTK+-version) tuntemat argumentit:\n" -msgid "-display <display>\tRun vim on <display> (also: --display)" -msgstr "-display <näyttö>\tSuorita vim näytöllä <näyttö> (myös: --display)" +msgid "-display <display>\tRun Vim on <display> (also: --display)" +msgstr "-display <näyttö>\tSuorita Vim näytöllä <näyttö> (myös: --display)" # X-ikkunointijärjestelmässä saman sovelluksen saman luokan ikkunat # tunnistetaan rooliresursseista @@ -6828,7 +6825,7 @@ msgid "list index out of range" msgstr "listaindeksi arvoalueen ulkopuolelta" #, c-format -msgid "internal error: failed to get vim list item %d" +msgid "internal error: failed to get Vim list item %d" msgstr "sisäinen virhe: ei pystytty hakea vimin listan indeksiä %d" msgid "slice step cannot be zero" @@ -6839,7 +6836,7 @@ msgid "attempt to assign sequence of size greater than %d to extended slice" msgstr "yritettiin sijoittaa sekvenssiä jonka koko on enemmän kuin %d sliceen" #, c-format -msgid "internal error: no vim list item %d" +msgid "internal error: no Vim list item %d" msgstr "sisäinen virhe: ei vim-listan indeksiä %d" msgid "internal error: not enough list items" @@ -6949,19 +6946,19 @@ msgstr "ei voitu suorittaa koodia" msgid "E858: Eval did not return a valid python object" msgstr "E858: Eval ei palauttanut python-oliota" -msgid "E859: Failed to convert returned python object to vim value" +msgid "E859: Failed to convert returned python object to a Vim value" msgstr "E859: Ei voitu konvertoida python-oliota vim-arvoksi" #, c-format -msgid "unable to convert %s to vim dictionary" +msgid "unable to convert %s to a Vim dictionary" msgstr "ei voitu konvertoida oliota %s vim-sanakirjaksi" #, c-format -msgid "unable to convert %s to vim list" +msgid "unable to convert %s to a Vim list" msgstr "ei voitu konvertoida tyypistä %s vim-listaksi" #, c-format -msgid "unable to convert %s to vim structure" +msgid "unable to convert %s to a Vim structure" msgstr "ei voi konvertoida oliota %s vim-tietorakenteeksi" msgid "internal error: NULL reference passed" diff --git a/src/po/fr.po b/src/po/fr.po index e902f63a08..bb69493614 100644 --- a/src/po/fr.po +++ b/src/po/fr.po @@ -2751,9 +2751,6 @@ msgstr "vimOption inconnue" msgid "keyboard interrupt" msgstr "interruption clavier" -msgid "vim error" -msgstr "erreur Vim" - msgid "cannot create buffer/window command: object is being deleted" msgstr "" "Impossible de crer commande de tampon/fentre : objet en cours d'effacement" @@ -3253,7 +3250,7 @@ msgstr "-W <dest>\t msgid "-x\t\t\tEdit encrypted files" msgstr "-x\t\t\tditer des fichiers chiffrs" -msgid "-display <display>\tConnect vim to this particular X-server" +msgid "-display <display>\tConnect Vim to this particular X-server" msgstr "-display <display>\tConnecter Vim au serveur X spcifi" msgid "-X\t\t\tDo not connect to X server" @@ -3336,10 +3333,10 @@ msgstr "" "\n" "Arguments reconnus par gvim (version Athena) :\n" -msgid "-display <display>\tRun vim on <display>" +msgid "-display <display>\tRun Vim on <display>" msgstr "-display <cran>\tLancer Vim sur ce <display>" -msgid "-iconic\t\tStart vim iconified" +msgid "-iconic\t\tStart Vim iconified" msgstr "-iconic\t\tIconifier Vim au dmarrage" msgid "-background <color>\tUse <color> for the background (also: -bg)" @@ -3389,7 +3386,7 @@ msgstr "" "\n" "Arguments reconnus par gvim (version GTK+) :\n" -msgid "-display <display>\tRun vim on <display> (also: --display)" +msgid "-display <display>\tRun Vim on <display> (also: --display)" msgstr "" "-display <display>\tLancer Vim sur ce <display>\t(galement : --display)" @@ -7489,7 +7486,7 @@ msgid "list index out of range" msgstr "index de liste hors limites" #, c-format -msgid "internal error: failed to get vim list item %d" +msgid "internal error: failed to get Vim list item %d" msgstr "erreur interne : accs un lment %d de liste a chou" msgid "slice step cannot be zero" @@ -7502,7 +7499,7 @@ msgstr "" "dcoupage en tranche tendu " #, c-format -msgid "internal error: no vim list item %d" +msgid "internal error: no Vim list item %d" msgstr "erreur interne : pas d'lment %d de liste vim" msgid "internal error: not enough list items" @@ -7613,19 +7610,19 @@ msgstr "ex msgid "E858: Eval did not return a valid python object" msgstr "E858: Eval n'a pas retourn un objet python valide" -msgid "E859: Failed to convert returned python object to vim value" +msgid "E859: Failed to convert returned python object to a Vim value" msgstr "E859: Conversion d'objet python une valeur de vim a chou" #, c-format -msgid "unable to convert %s to vim dictionary" +msgid "unable to convert %s to a Vim dictionary" msgstr "impossible de convertir %s un dictionnaire vim" #, c-format -msgid "unable to convert %s to vim list" +msgid "unable to convert %s to a Vim list" msgstr "impossible de convertir %s une liste de vim" #, c-format -msgid "unable to convert %s to vim structure" +msgid "unable to convert %s to a Vim structure" msgstr "impossible de convertir %s une structure de vim" msgid "internal error: NULL reference passed" diff --git a/src/po/ga.po b/src/po/ga.po index 2933ff35d2..3ef02b411b 100644 --- a/src/po/ga.po +++ b/src/po/ga.po @@ -2806,9 +2806,6 @@ msgstr "vimOption anaithnid" msgid "keyboard interrupt" msgstr "idirbhriseadh marchlir" -msgid "vim error" -msgstr "earrid vim" - msgid "cannot create buffer/window command: object is being deleted" msgstr "n fidir ord maolin/fuinneoige a chruth: rad scriosadh" @@ -3135,8 +3132,8 @@ msgstr "-W <aschur>\tScr msgid "-x\t\t\tEdit encrypted files" msgstr "-x\t\t\tCuir comhaid chriptithe in eagar" -msgid "-display <display>\tConnect vim to this particular X-server" -msgstr "-display <freastala>\tNasc vim leis an bhfreastala-X seo" +msgid "-display <display>\tConnect Vim to this particular X-server" +msgstr "-display <freastala>\tNasc Vim leis an bhfreastala-X seo" msgid "-X\t\t\tDo not connect to X server" msgstr "-X\t\t\tN naisc leis an bhfreastala X" @@ -3218,11 +3215,11 @@ msgstr "" "\n" "Argint ar eolas do gvim (leagan Athena):\n" -msgid "-display <display>\tRun vim on <display>" -msgstr "-display <scilen>\tRith vim ar <scilen>" +msgid "-display <display>\tRun Vim on <display>" +msgstr "-display <scilen>\tRith Vim ar <scilen>" -msgid "-iconic\t\tStart vim iconified" -msgstr "-iconic\t\tTosaigh vim sa mhd oslaghdaithe" +msgid "-iconic\t\tStart Vim iconified" +msgstr "-iconic\t\tTosaigh Vim sa mhd oslaghdaithe" msgid "-background <color>\tUse <color> for the background (also: -bg)" msgstr "-background <dath>\tBain sid as <dath> don chlra (-bg fosta)" @@ -3273,8 +3270,8 @@ msgstr "" "\n" "Argint ar eolas do gvim (leagan GTK+):\n" -msgid "-display <display>\tRun vim on <display> (also: --display)" -msgstr "-display <scilen>\tRith vim ar <scilen> (fosta: --display)" +msgid "-display <display>\tRun Vim on <display> (also: --display)" +msgstr "-display <scilen>\tRith Vim ar <scilen> (fosta: --display)" msgid "--role <role>\tSet a unique role to identify the main window" msgstr "--role <rl>\tSocraigh rl sainiil chun an phromhfhuinneog a aithint" @@ -6955,7 +6952,7 @@ msgstr "inn #. No more suitable format specifications in python-2.3 #, c-format -msgid "internal error: failed to get vim list item %d" +msgid "internal error: failed to get Vim list item %d" msgstr "earrid inmhenach: nl aon fhil ar mhr %d sa liosta vim" msgid "slice step cannot be zero" @@ -6966,7 +6963,7 @@ msgid "attempt to assign sequence of size greater than %d to extended slice" msgstr "iarracht ar sheicheamh nos m n %d a shannadh do shlisne fadaithe" #, c-format -msgid "internal error: no vim list item %d" +msgid "internal error: no Vim list item %d" msgstr "earrid inmhenach: nl aon mhr %d sa liosta vim" msgid "internal error: not enough list items" @@ -7075,19 +7072,19 @@ msgstr "n msgid "E858: Eval did not return a valid python object" msgstr "E858: N bhfuarthas rad bail python ar ais Eval" -msgid "E859: Failed to convert returned python object to vim value" +msgid "E859: Failed to convert returned python object to a Vim value" msgstr "E859: Norbh fhidir luach vim a dhanamh as an rad python" #, c-format -msgid "unable to convert %s to vim dictionary" +msgid "unable to convert %s to a Vim dictionary" msgstr "n fidir foclir vim a dhanamh as %s" #, c-format -msgid "unable to convert %s to vim list" +msgid "unable to convert %s to a Vim list" msgstr "n fidir liosta vim a dhanamh as %s" #, c-format -msgid "unable to convert %s to vim structure" +msgid "unable to convert %s to a Vim structure" msgstr "n fidir struchtr vim a dhanamh as %s" msgid "internal error: NULL reference passed" diff --git a/src/po/it.po b/src/po/it.po index d9fc3c92a5..77e4ef06b7 100644 --- a/src/po/it.po +++ b/src/po/it.po @@ -2607,9 +2607,6 @@ msgstr "'vimOption' inesistente" msgid "keyboard interrupt" msgstr "interruzione dalla tastiera" -msgid "vim error" -msgstr "errore vim" - msgid "cannot create buffer/window command: object is being deleted" msgstr "" "non riesco a creare comando buffer/finestra: oggetto in via di cancellazione" @@ -3018,8 +3015,8 @@ msgstr "-W <scriptout>\tScrivi tutti i comandi immessi in file <scriptout>" msgid "-x\t\t\tEdit encrypted files" msgstr "-x\t\t\tApri un file cifrato" -msgid "-display <display>\tConnect vim to this particular X-server" -msgstr "-display <schermo>\tEsegui vim a questo particolare server X" +msgid "-display <display>\tConnect Vim to this particular X-server" +msgstr "-display <schermo>\tEsegui Vim a questo particolare server X" msgid "-X\t\t\tDo not connect to X server" msgstr "-X\t\t\tNon connetterti a server X" @@ -3096,11 +3093,11 @@ msgstr "" "\n" "Opzioni accettate da gvim (versione Athena):\n" -msgid "-display <display>\tRun vim on <display>" -msgstr "-display <schermo>\tEsegui vim su <schermo>" +msgid "-display <display>\tRun Vim on <display>" +msgstr "-display <schermo>\tEsegui Vim su <schermo>" -msgid "-iconic\t\tStart vim iconified" -msgstr "-iconic\t\tInizia vim riducendolo ad icona" +msgid "-iconic\t\tStart Vim iconified" +msgstr "-iconic\t\tInizia Vim riducendolo ad icona" msgid "-background <color>\tUse <color> for the background (also: -bg)" msgstr "-background <colore>\tUsa <colore> come sfondo (anche: -bg)" @@ -3146,8 +3143,8 @@ msgstr "" "\n" "Argomenti accettati da gvim (versione GTK+):\n" -msgid "-display <display>\tRun vim on <display> (also: --display)" -msgstr "-display <schermo>\tEsegui vim su <schermo> (anche: --display)" +msgid "-display <display>\tRun Vim on <display> (also: --display)" +msgstr "-display <schermo>\tEsegui Vim su <schermo> (anche: --display)" msgid "--role <role>\tSet a unique role to identify the main window" msgstr "" @@ -6530,8 +6527,8 @@ msgstr "il costruttore di lista non accetta parole chiave come argomenti" msgid "list index out of range" msgstr "Indice di Lista fuori intervallo" -msgid "internal error: failed to get vim list item %d" -msgstr "errore interno: non ho potuto ottenere l'elemento di vim list %d" +msgid "internal error: failed to get Vim list item %d" +msgstr "errore interno: non ho potuto ottenere l'elemento di Vim list %d" msgid "slice step cannot be zero" msgstr "il passo scorrendo un intervallo non pu essere zero" @@ -6540,7 +6537,7 @@ msgid "attempt to assign sequence of size greater than %d to extended slice" msgstr "" "tentativo di assegnare una sequenza maggiore di %d a un intervallo esteso" -msgid "internal error: no vim list item %d" +msgid "internal error: no Vim list item %d" msgstr "errore interno: non c' un elemento di vim list %d" msgid "internal error: not enough list items" @@ -6642,17 +6639,17 @@ msgstr "esecuzione del codice non riuscita" msgid "E858: Eval did not return a valid python object" msgstr "E858: Eval non ha restituito un oggetto python valido" -msgid "E859: Failed to convert returned python object to vim value" +msgid "E859: Failed to convert returned python object to a Vim value" msgstr "" "E859: Conversione non riuscita dell'oggetto python risultato a un valore vim" -msgid "unable to convert %s to vim dictionary" +msgid "unable to convert %s to a Vim dictionary" msgstr "impossibile convertire %s a dizionario vim" -msgid "unable to convert %s to vim list" +msgid "unable to convert %s to a Vim list" msgstr "impossibile convertire %s a Lista vim" -msgid "unable to convert %s to vim structure" +msgid "unable to convert %s to a Vim structure" msgstr "impossibile convertire %s a struttura vim" msgid "internal error: NULL reference passed" diff --git a/src/po/ja.euc-jp.po b/src/po/ja.euc-jp.po index 71a46d81f4..935874b477 100644 --- a/src/po/ja.euc-jp.po +++ b/src/po/ja.euc-jp.po @@ -2590,9 +2590,6 @@ msgstr "̤ msgid "keyboard interrupt" msgstr "ܡɳ" -msgid "vim error" -msgstr "vim 顼" - msgid "cannot create buffer/window command: object is being deleted" msgstr "" "Хåե/ɥޥɤǤޤ: ֥ȤõƤ" @@ -3055,7 +3052,7 @@ msgstr "-W <scriptout>\t msgid "-x\t\t\tEdit encrypted files" msgstr "-x\t\t\tŹ沽줿եԽ" -msgid "-display <display>\tConnect vim to this particular X-server" +msgid "-display <display>\tConnect Vim to this particular X-server" msgstr "-display <display>\tvimꤷ X С³" msgid "-X\t\t\tDo not connect to X server" @@ -3130,10 +3127,10 @@ msgstr "" "\n" "gvimˤäƲᤵ(AthenaС):\n" -msgid "-display <display>\tRun vim on <display>" +msgid "-display <display>\tRun Vim on <display>" msgstr "-display <display>\t<display> vim¹Ԥ" -msgid "-iconic\t\tStart vim iconified" +msgid "-iconic\t\tStart Vim iconified" msgstr "-iconic\t\tǾ֤vimư" msgid "-background <color>\tUse <color> for the background (also: -bg)" @@ -3180,8 +3177,8 @@ msgstr "" "\n" "gvimˤäƲᤵ(GTK+С):\n" -msgid "-display <display>\tRun vim on <display> (also: --display)" -msgstr "-display <display>\t<display> vim¹Ԥ(Ʊ: --display)" +msgid "-display <display>\tRun Vim on <display> (also: --display)" +msgstr "-display <display>\t<display> Vim¹Ԥ(Ʊ: --display)" msgid "--role <role>\tSet a unique role to identify the main window" msgstr "--role <role>\tᥤ󥦥ɥ̤դ(role)ꤹ" @@ -7135,7 +7132,7 @@ msgid "list index out of range" msgstr "ꥹϰϳΥǥåǤ" #, c-format -msgid "internal error: failed to get vim list item %d" +msgid "internal error: failed to get Vim list item %d" msgstr "顼: vimΥꥹ %d μ˼Ԥޤ" msgid "slice step cannot be zero" @@ -7146,7 +7143,7 @@ msgid "attempt to assign sequence of size greater than %d to extended slice" msgstr "Ĺ %d γĥ饤ˡĹ饤Ƥ褦Ȥޤ" #, c-format -msgid "internal error: no vim list item %d" +msgid "internal error: no Vim list item %d" msgstr "顼: vimΥꥹ %d Ϥޤ" msgid "internal error: not enough list items" @@ -7255,19 +7252,19 @@ msgstr " msgid "E858: Eval did not return a valid python object" msgstr "E858: ɾͭpython֥Ȥ֤ޤǤ" -msgid "E859: Failed to convert returned python object to vim value" +msgid "E859: Failed to convert returned python object to a Vim value" msgstr "E859: ֤줿python֥ȤvimͤѴǤޤǤ" #, c-format -msgid "unable to convert %s to vim dictionary" +msgid "unable to convert %s to a Vim dictionary" msgstr "%s vimμ񷿤ѴǤޤ" #, c-format -msgid "unable to convert %s to vim list" +msgid "unable to convert %s to a Vim list" msgstr "%s vimΥꥹȤѴǤޤ" #, c-format -msgid "unable to convert %s to vim structure" +msgid "unable to convert %s to a Vim structure" msgstr "%s vimι¤ΤѴǤޤ" msgid "internal error: NULL reference passed" diff --git a/src/po/ja.po b/src/po/ja.po index 2826c35dd7..acc152e75c 100644 --- a/src/po/ja.po +++ b/src/po/ja.po @@ -2590,9 +2590,6 @@ msgstr "未知の vimOption です" msgid "keyboard interrupt" msgstr "キーボード割込み" -msgid "vim error" -msgstr "vim エラー" - msgid "cannot create buffer/window command: object is being deleted" msgstr "" "バッファ/ウィンドウ作成コマンドを作成できません: オブジェクトが消去されていま" @@ -3055,7 +3052,7 @@ msgstr "-W <scriptout>\t入力した全コマンドをファイル <scriptout> msgid "-x\t\t\tEdit encrypted files" msgstr "-x\t\t\t暗号化されたファイルを編集する" -msgid "-display <display>\tConnect vim to this particular X-server" +msgid "-display <display>\tConnect Vim to this particular X-server" msgstr "-display <display>\tvimを指定した X サーバーに接続する" msgid "-X\t\t\tDo not connect to X server" @@ -3130,10 +3127,10 @@ msgstr "" "\n" "gvimによって解釈される引数(Athenaバージョン):\n" -msgid "-display <display>\tRun vim on <display>" +msgid "-display <display>\tRun Vim on <display>" msgstr "-display <display>\t<display> でvimを実行する" -msgid "-iconic\t\tStart vim iconified" +msgid "-iconic\t\tStart Vim iconified" msgstr "-iconic\t\t最小化した状態でvimを起動する" msgid "-background <color>\tUse <color> for the background (also: -bg)" @@ -3180,8 +3177,8 @@ msgstr "" "\n" "gvimによって解釈される引数(GTK+バージョン):\n" -msgid "-display <display>\tRun vim on <display> (also: --display)" -msgstr "-display <display>\t<display> でvimを実行する(同義: --display)" +msgid "-display <display>\tRun Vim on <display> (also: --display)" +msgstr "-display <display>\t<display> でVimを実行する(同義: --display)" msgid "--role <role>\tSet a unique role to identify the main window" msgstr "--role <role>\tメインウィンドウを識別する一意な役割(role)を設定する" @@ -7135,7 +7132,7 @@ msgid "list index out of range" msgstr "リスト範囲外のインデックスです" #, c-format -msgid "internal error: failed to get vim list item %d" +msgid "internal error: failed to get Vim list item %d" msgstr "内部エラー: vimのリスト要素 %d の取得に失敗しました" msgid "slice step cannot be zero" @@ -7146,7 +7143,7 @@ msgid "attempt to assign sequence of size greater than %d to extended slice" msgstr "長さ %d の拡張スライスに、より長いスライスを割り当てようとしました" #, c-format -msgid "internal error: no vim list item %d" +msgid "internal error: no Vim list item %d" msgstr "内部エラー: vimのリスト要素 %d はありません" msgid "internal error: not enough list items" @@ -7255,19 +7252,19 @@ msgstr "コードの実行に失敗しました" msgid "E858: Eval did not return a valid python object" msgstr "E858: 式評価は有効なpythonオブジェクトを返しませんでした" -msgid "E859: Failed to convert returned python object to vim value" +msgid "E859: Failed to convert returned python object to a Vim value" msgstr "E859: 返されたpythonオブジェクトをvimの値に変換できませんでした" #, c-format -msgid "unable to convert %s to vim dictionary" +msgid "unable to convert %s to a Vim dictionary" msgstr "%s vimの辞書型に変換できません" #, c-format -msgid "unable to convert %s to vim list" +msgid "unable to convert %s to a Vim list" msgstr "%s をvimのリストに変換できません" #, c-format -msgid "unable to convert %s to vim structure" +msgid "unable to convert %s to a Vim structure" msgstr "%s をvimの構造体に変換できません" msgid "internal error: NULL reference passed" diff --git a/src/po/ja.sjis.po b/src/po/ja.sjis.po index 9676475a5c..927f4f4f73 100644 --- a/src/po/ja.sjis.po +++ b/src/po/ja.sjis.po @@ -2590,9 +2590,6 @@ msgstr " msgid "keyboard interrupt" msgstr "L[{[h" -msgid "vim error" -msgstr "vim G[" - msgid "cannot create buffer/window command: object is being deleted" msgstr "" "obt@/EBhE쐬R}h쐬ł܂: IuWFNgĂ" @@ -3055,7 +3052,7 @@ msgstr "-W <scriptout>\t msgid "-x\t\t\tEdit encrypted files" msgstr "-x\t\t\tÍꂽt@CҏW" -msgid "-display <display>\tConnect vim to this particular X-server" +msgid "-display <display>\tConnect Vim to this particular X-server" msgstr "-display <display>\tvimw肵 X T[o[ɐڑ" msgid "-X\t\t\tDo not connect to X server" @@ -3130,10 +3127,10 @@ msgstr "" "\n" "gvimɂĉ߂(Athenao[W):\n" -msgid "-display <display>\tRun vim on <display>" +msgid "-display <display>\tRun Vim on <display>" msgstr "-display <display>\t<display> vims" -msgid "-iconic\t\tStart vim iconified" +msgid "-iconic\t\tStart Vim iconified" msgstr "-iconic\t\tŏԂvimN" msgid "-background <color>\tUse <color> for the background (also: -bg)" @@ -3180,7 +3177,7 @@ msgstr "" "\n" "gvimɂĉ߂(GTK+o[W):\n" -msgid "-display <display>\tRun vim on <display> (also: --display)" +msgid "-display <display>\tRun Vim on <display> (also: --display)" msgstr "-display <display>\t<display> vims(`: --display)" msgid "--role <role>\tSet a unique role to identify the main window" @@ -7135,7 +7132,7 @@ msgid "list index out of range" msgstr "Xg͈͊ÕCfbNXł" #, c-format -msgid "internal error: failed to get vim list item %d" +msgid "internal error: failed to get Vim list item %d" msgstr "G[: vim̃Xgvf %d ̎擾Ɏs܂" msgid "slice step cannot be zero" @@ -7146,7 +7143,7 @@ msgid "attempt to assign sequence of size greater than %d to extended slice" msgstr " %d ̊gXCXɁA蒷XCX蓖Ă悤Ƃ܂" #, c-format -msgid "internal error: no vim list item %d" +msgid "internal error: no Vim list item %d" msgstr "G[: vim̃Xgvf %d ͂܂" msgid "internal error: not enough list items" @@ -7255,19 +7252,19 @@ msgstr " msgid "E858: Eval did not return a valid python object" msgstr "E858: ]͗LpythonIuWFNgԂ܂ł" -msgid "E859: Failed to convert returned python object to vim value" +msgid "E859: Failed to convert returned python object to a Vim value" msgstr "E859: ԂꂽpythonIuWFNgvim̒lɕϊł܂ł" #, c-format -msgid "unable to convert %s to vim dictionary" +msgid "unable to convert %s to a Vim dictionary" msgstr "%s vim̎^ɕϊł܂" #, c-format -msgid "unable to convert %s to vim list" +msgid "unable to convert %s to a Vim list" msgstr "%s vim̃Xgɕϊł܂" #, c-format -msgid "unable to convert %s to vim structure" +msgid "unable to convert %s to a Vim structure" msgstr "%s vim̍\\̂ɕϊł܂" msgid "internal error: NULL reference passed" diff --git a/src/po/ko.UTF-8.po b/src/po/ko.UTF-8.po index 8acbcc9322..a4864e7311 100644 --- a/src/po/ko.UTF-8.po +++ b/src/po/ko.UTF-8.po @@ -2780,9 +2780,6 @@ msgstr "모르는 빔 옵션" msgid "keyboard interrupt" msgstr "키보드 인터럽트" -msgid "vim error" -msgstr "빔 에러" - msgid "cannot create buffer/window command: object is being deleted" msgstr "버퍼/창 명령을 만들 수 없습니다: 객체가 지워집니다" @@ -3096,7 +3093,7 @@ msgstr "-W <scriptout>\t모든 입력된 명령을 <scriptout> 파일에 저장" msgid "-x\t\t\tEdit encrypted files" msgstr "-x\t\t\t암호화된 파일 고치기" -msgid "-display <display>\tConnect vim to this particular X-server" +msgid "-display <display>\tConnect Vim to this particular X-server" msgstr "-display <display>\t빔을 특정 X-서버와 연결" msgid "-X\t\t\tDo not connect to X server" @@ -3170,10 +3167,10 @@ msgstr "" "\n" "gvim이 알고 있는 인자 (아테나 판):\n" -msgid "-display <display>\tRun vim on <display>" +msgid "-display <display>\tRun Vim on <display>" msgstr "-display <display>\t빔을 <display>에서 실행" -msgid "-iconic\t\tStart vim iconified" +msgid "-iconic\t\tStart Vim iconified" msgstr "-iconic\t\t아이콘 상태로 빔 시작" msgid "-background <color>\tUse <color> for the background (also: -bg)" @@ -3219,7 +3216,7 @@ msgstr "" "\n" "gvim이 알고있는 인자 (GTK+ 판):\n" -msgid "-display <display>\tRun vim on <display> (also: --display)" +msgid "-display <display>\tRun Vim on <display> (also: --display)" msgstr "-display <display>\t빔을 <display>에서 실행 (also: --display)" msgid "--role <role>\tSet a unique role to identify the main window" @@ -6811,7 +6808,7 @@ msgid "list index out of range" msgstr "list 색인이 범위를 벗어났습니다" #, c-format -#~ msgid "internal error: failed to get vim list item %d" +#~ msgid "internal error: failed to get Vim list item %d" #~ msgstr "" #~ msgid "slice step cannot be zero" @@ -6822,7 +6819,7 @@ msgstr "list 색인이 범위를 벗어났습니다" #~ msgstr "" #, c-format -#~ msgid "internal error: no vim list item %d" +#~ msgid "internal error: no Vim list item %d" #~ msgstr "" #~ msgid "internal error: not enough list items" @@ -6931,19 +6928,19 @@ msgstr "버퍼 이름을 변경할 수 없습니다" #~ msgid "E858: Eval did not return a valid python object" #~ msgstr "" -#~ msgid "E859: Failed to convert returned python object to vim value" +#~ msgid "E859: Failed to convert returned python object to a Vim value" #~ msgstr "" #, c-format -#~ msgid "unable to convert %s to vim dictionary" +#~ msgid "unable to convert %s to a Vim dictionary" #~ msgstr "" #, c-format -msgid "unable to convert %s to vim list" +msgid "unable to convert %s to a Vim list" msgstr "%s을(를) vim list로 변경할 수 없습니다" #, c-format -#~ msgid "unable to convert %s to vim structure" +#~ msgid "unable to convert %s to a Vim structure" #~ msgstr "" #~ msgid "internal error: NULL reference passed" diff --git a/src/po/ko.po b/src/po/ko.po index c6b0997a69..9f2ff70339 100644 --- a/src/po/ko.po +++ b/src/po/ko.po @@ -2780,9 +2780,6 @@ msgstr " msgid "keyboard interrupt" msgstr "Ű ͷƮ" -msgid "vim error" -msgstr " " - msgid "cannot create buffer/window command: object is being deleted" msgstr "/â ϴ: ü ϴ" @@ -3096,7 +3093,7 @@ msgstr "-W <scriptout>\t msgid "-x\t\t\tEdit encrypted files" msgstr "-x\t\t\tȣȭ ġ" -msgid "-display <display>\tConnect vim to this particular X-server" +msgid "-display <display>\tConnect Vim to this particular X-server" msgstr "-display <display>\t Ư X- " msgid "-X\t\t\tDo not connect to X server" @@ -3170,10 +3167,10 @@ msgstr "" "\n" "gvim ˰ ִ (׳ ):\n" -msgid "-display <display>\tRun vim on <display>" +msgid "-display <display>\tRun Vim on <display>" msgstr "-display <display>\t <display> " -msgid "-iconic\t\tStart vim iconified" +msgid "-iconic\t\tStart Vim iconified" msgstr "-iconic\t\t · " msgid "-background <color>\tUse <color> for the background (also: -bg)" @@ -3219,7 +3216,7 @@ msgstr "" "\n" "gvim ˰ִ (GTK+ ):\n" -msgid "-display <display>\tRun vim on <display> (also: --display)" +msgid "-display <display>\tRun Vim on <display> (also: --display)" msgstr "-display <display>\t <display> (also: --display)" msgid "--role <role>\tSet a unique role to identify the main window" @@ -6811,7 +6808,7 @@ msgid "list index out of range" msgstr "list ϴ" #, c-format -#~ msgid "internal error: failed to get vim list item %d" +#~ msgid "internal error: failed to get Vim list item %d" #~ msgstr "" #~ msgid "slice step cannot be zero" @@ -6822,7 +6819,7 @@ msgstr "list #~ msgstr "" #, c-format -#~ msgid "internal error: no vim list item %d" +#~ msgid "internal error: no Vim list item %d" #~ msgstr "" #~ msgid "internal error: not enough list items" @@ -6931,19 +6928,19 @@ msgstr " #~ msgid "E858: Eval did not return a valid python object" #~ msgstr "" -#~ msgid "E859: Failed to convert returned python object to vim value" +#~ msgid "E859: Failed to convert returned python object to a Vim value" #~ msgstr "" #, c-format -#~ msgid "unable to convert %s to vim dictionary" +#~ msgid "unable to convert %s to a Vim dictionary" #~ msgstr "" #, c-format -msgid "unable to convert %s to vim list" +msgid "unable to convert %s to a Vim list" msgstr "%s() vim list ϴ" #, c-format -#~ msgid "unable to convert %s to vim structure" +#~ msgid "unable to convert %s to a Vim structure" #~ msgstr "" #~ msgid "internal error: NULL reference passed" diff --git a/src/po/nb.po b/src/po/nb.po index a5824eb483..7e99deb248 100644 --- a/src/po/nb.po +++ b/src/po/nb.po @@ -2648,9 +2648,6 @@ msgstr "ukjent vimOption" msgid "keyboard interrupt" msgstr "tastaturavbrudd" -msgid "vim error" -msgstr "vim-feil" - msgid "cannot create buffer/window command: object is being deleted" msgstr "kan ikke opprette buffer/vindukommando: Objektet slettes" @@ -2946,8 +2943,8 @@ msgstr "-W <utskript>\tSkriv alle skrevne kommandoer til filen <utskript>" msgid "-x\t\t\tEdit encrypted files" msgstr "-x\t\t\tRediger krypterte filer" -msgid "-display <display>\tConnect vim to this particular X-server" -msgstr "-display <display>\tKoble vim til denne spesielle X-tjeneren" +msgid "-display <display>\tConnect Vim to this particular X-server" +msgstr "-display <display>\tKoble Vim til denne spesielle X-tjeneren" msgid "-X\t\t\tDo not connect to X server" msgstr "-X\t\t\tUnng oppkobling til X-tjener" @@ -3016,11 +3013,11 @@ msgstr "" "\n" "Parametere gjenkjent av gvim (Athena-versjon):\n" -msgid "-display <display>\tRun vim on <display>" -msgstr "-display <display>\tKjr vim p <display>" +msgid "-display <display>\tRun Vim on <display>" +msgstr "-display <display>\tKjr Vim p <display>" -msgid "-iconic\t\tStart vim iconified" -msgstr "-iconic\t\tStart vim som ikon" +msgid "-iconic\t\tStart Vim iconified" +msgstr "-iconic\t\tStart Vim som ikon" msgid "-name <name>\t\tUse resource as if vim was <name>" msgstr "-name <navn>\t\tBruk ressurs som om Vim var <navn>" @@ -3089,8 +3086,8 @@ msgstr "" "\n" "Parametere gjenkjent av gvim (GTK+-versjon):\n" -msgid "-display <display>\tRun vim on <display> (also: --display)" -msgstr "-display <display>\tKjr vim p <display> (ogs: --display)" +msgid "-display <display>\tRun Vim on <display> (also: --display)" +msgstr "-display <display>\tKjr Vim p <display> (ogs: --display)" msgid "--role <role>\tSet a unique role to identify the main window" msgstr "--role <role>\tSett en unik \"role\" for identifisere hovedvinduet" diff --git a/src/po/nl.po b/src/po/nl.po index e5eb9f444d..b4d0a444c0 100644 --- a/src/po/nl.po +++ b/src/po/nl.po @@ -2720,9 +2720,6 @@ msgstr "onbekende vim-optie" msgid "keyboard interrupt" msgstr "toetsenbord-interrupt" -msgid "vim error" -msgstr "vim-fout" - msgid "cannot create buffer/window command: object is being deleted" msgstr "aanmaken buffer-/vensteropdracht is mislukt: object wordt verwijderd" diff --git a/src/po/no.po b/src/po/no.po index a5824eb483..7e99deb248 100644 --- a/src/po/no.po +++ b/src/po/no.po @@ -2648,9 +2648,6 @@ msgstr "ukjent vimOption" msgid "keyboard interrupt" msgstr "tastaturavbrudd" -msgid "vim error" -msgstr "vim-feil" - msgid "cannot create buffer/window command: object is being deleted" msgstr "kan ikke opprette buffer/vindukommando: Objektet slettes" @@ -2946,8 +2943,8 @@ msgstr "-W <utskript>\tSkriv alle skrevne kommandoer til filen <utskript>" msgid "-x\t\t\tEdit encrypted files" msgstr "-x\t\t\tRediger krypterte filer" -msgid "-display <display>\tConnect vim to this particular X-server" -msgstr "-display <display>\tKoble vim til denne spesielle X-tjeneren" +msgid "-display <display>\tConnect Vim to this particular X-server" +msgstr "-display <display>\tKoble Vim til denne spesielle X-tjeneren" msgid "-X\t\t\tDo not connect to X server" msgstr "-X\t\t\tUnng oppkobling til X-tjener" @@ -3016,11 +3013,11 @@ msgstr "" "\n" "Parametere gjenkjent av gvim (Athena-versjon):\n" -msgid "-display <display>\tRun vim on <display>" -msgstr "-display <display>\tKjr vim p <display>" +msgid "-display <display>\tRun Vim on <display>" +msgstr "-display <display>\tKjr Vim p <display>" -msgid "-iconic\t\tStart vim iconified" -msgstr "-iconic\t\tStart vim som ikon" +msgid "-iconic\t\tStart Vim iconified" +msgstr "-iconic\t\tStart Vim som ikon" msgid "-name <name>\t\tUse resource as if vim was <name>" msgstr "-name <navn>\t\tBruk ressurs som om Vim var <navn>" @@ -3089,8 +3086,8 @@ msgstr "" "\n" "Parametere gjenkjent av gvim (GTK+-versjon):\n" -msgid "-display <display>\tRun vim on <display> (also: --display)" -msgstr "-display <display>\tKjr vim p <display> (ogs: --display)" +msgid "-display <display>\tRun Vim on <display> (also: --display)" +msgstr "-display <display>\tKjr Vim p <display> (ogs: --display)" msgid "--role <role>\tSet a unique role to identify the main window" msgstr "--role <role>\tSett en unik \"role\" for identifisere hovedvinduet" diff --git a/src/po/pl.UTF-8.po b/src/po/pl.UTF-8.po index 0d173f6faa..886d43af30 100644 --- a/src/po/pl.UTF-8.po +++ b/src/po/pl.UTF-8.po @@ -2767,8 +2767,6 @@ msgstr "nieznane vimOption" msgid "keyboard interrupt" msgstr "przerwanie klawiatury" -msgid "vim error" -msgstr "błąd vima" msgid "cannot create buffer/window command: object is being deleted" msgstr "nie mogę stworzyć bufora/okna komendy: obiekt jest kasowany" @@ -3078,7 +3076,7 @@ msgstr "" msgid "-x\t\t\tEdit encrypted files" msgstr "-x\t\t\tEdytuj zakodowane pliki" -msgid "-display <display>\tConnect vim to this particular X-server" +msgid "-display <display>\tConnect Vim to this particular X-server" msgstr "-display <display>\tPodłącz vima to danego X-serwera" msgid "-X\t\t\tDo not connect to X server" @@ -3153,10 +3151,10 @@ msgstr "" "\n" "Argumenty rozpoznawane przez gvim (wersja Athena):\n" -msgid "-display <display>\tRun vim on <display>" -msgstr "-display <display>\tZaładuj vim na <display>" +msgid "-display <display>\tRun Vim on <display>" +msgstr "-display <display>\tZaładuj Vim na <display>" -msgid "-iconic\t\tStart vim iconified" +msgid "-iconic\t\tStart Vim iconified" msgstr "-iconic\t\tZacznij Vim jako ikonę" msgid "-background <color>\tUse <color> for the background (also: -bg)" @@ -3206,8 +3204,8 @@ msgstr "" "\n" "Argumenty rozpoznawane przez gvim (wersja GTK+):\n" -msgid "-display <display>\tRun vim on <display> (also: --display)" -msgstr "-display <display>\tZastartuj vim na <display> (również: --display)" +msgid "-display <display>\tRun Vim on <display> (also: --display)" +msgstr "-display <display>\tZastartuj Vim na <display> (również: --display)" msgid "--role <role>\tSet a unique role to identify the main window" msgstr "--role <role>\tUstaw unikatową rolę do identyfikacji głównego okna" @@ -6643,14 +6641,14 @@ msgstr "indeks listy poza zakresem" #. No more suitable format specifications in python-2.3 #, c-format -msgid "internal error: failed to get vim list item %d" +msgid "internal error: failed to get Vim list item %d" msgstr "błąd wewnętrzny: nie powiodło się pobranie z listy Vima elementu %d" msgid "failed to add item to list" msgstr "nie powiodło się dodanie elementu do listy" #, c-format -msgid "internal error: no vim list item %d" +msgid "internal error: no Vim list item %d" msgstr "błąd wewnętrzny: w liście Vima brak elementu %d" msgid "internal error: failed to add item to list" @@ -6752,7 +6750,7 @@ msgstr "uruchomienie kodu się nie powiodło" msgid "E858: Eval did not return a valid python object" msgstr "E858: eval nie zwróciło odpowiedniego obiektu pythona" -msgid "E859: Failed to convert returned python object to vim value" +msgid "E859: Failed to convert returned python object to a Vim value" msgstr "E859: Nie powiodła się konwersja obiektu pythona do wartości Vima" #, c-format diff --git a/src/po/pl.cp1250.po b/src/po/pl.cp1250.po index a1e5a45d61..007c8d34fa 100644 --- a/src/po/pl.cp1250.po +++ b/src/po/pl.cp1250.po @@ -2767,8 +2767,6 @@ msgstr "nieznane vimOption" msgid "keyboard interrupt" msgstr "przerwanie klawiatury" -msgid "vim error" -msgstr "bd vima" msgid "cannot create buffer/window command: object is being deleted" msgstr "nie mog stworzy bufora/okna komendy: obiekt jest kasowany" @@ -3078,7 +3076,7 @@ msgstr "" msgid "-x\t\t\tEdit encrypted files" msgstr "-x\t\t\tEdytuj zakodowane pliki" -msgid "-display <display>\tConnect vim to this particular X-server" +msgid "-display <display>\tConnect Vim to this particular X-server" msgstr "-display <display>\tPodcz vima to danego X-serwera" msgid "-X\t\t\tDo not connect to X server" @@ -3153,10 +3151,10 @@ msgstr "" "\n" "Argumenty rozpoznawane przez gvim (wersja Athena):\n" -msgid "-display <display>\tRun vim on <display>" -msgstr "-display <display>\tZaaduj vim na <display>" +msgid "-display <display>\tRun Vim on <display>" +msgstr "-display <display>\tZaaduj Vim na <display>" -msgid "-iconic\t\tStart vim iconified" +msgid "-iconic\t\tStart Vim iconified" msgstr "-iconic\t\tZacznij Vim jako ikon" msgid "-background <color>\tUse <color> for the background (also: -bg)" @@ -3206,8 +3204,8 @@ msgstr "" "\n" "Argumenty rozpoznawane przez gvim (wersja GTK+):\n" -msgid "-display <display>\tRun vim on <display> (also: --display)" -msgstr "-display <display>\tZastartuj vim na <display> (rwnie: --display)" +msgid "-display <display>\tRun Vim on <display> (also: --display)" +msgstr "-display <display>\tZastartuj Vim na <display> (rwnie: --display)" msgid "--role <role>\tSet a unique role to identify the main window" msgstr "--role <role>\tUstaw unikatow rol do identyfikacji gwnego okna" @@ -6643,14 +6641,14 @@ msgstr "indeks listy poza zakresem" #. No more suitable format specifications in python-2.3 #, c-format -msgid "internal error: failed to get vim list item %d" +msgid "internal error: failed to get Vim list item %d" msgstr "bd wewntrzny: nie powiodo si pobranie z listy Vima elementu %d" msgid "failed to add item to list" msgstr "nie powiodo si dodanie elementu do listy" #, c-format -msgid "internal error: no vim list item %d" +msgid "internal error: no Vim list item %d" msgstr "bd wewntrzny: w licie Vima brak elementu %d" msgid "internal error: failed to add item to list" @@ -6752,7 +6750,7 @@ msgstr "uruchomienie kodu si msgid "E858: Eval did not return a valid python object" msgstr "E858: eval nie zwrcio odpowiedniego obiektu pythona" -msgid "E859: Failed to convert returned python object to vim value" +msgid "E859: Failed to convert returned python object to a Vim value" msgstr "E859: Nie powioda si konwersja obiektu pythona do wartoci Vima" #, c-format diff --git a/src/po/pl.po b/src/po/pl.po index 0d2ba3424d..eb95bd5e39 100644 --- a/src/po/pl.po +++ b/src/po/pl.po @@ -2767,8 +2767,6 @@ msgstr "nieznane vimOption" msgid "keyboard interrupt" msgstr "przerwanie klawiatury" -msgid "vim error" -msgstr "bd vima" msgid "cannot create buffer/window command: object is being deleted" msgstr "nie mog stworzy bufora/okna komendy: obiekt jest kasowany" @@ -3078,7 +3076,7 @@ msgstr "" msgid "-x\t\t\tEdit encrypted files" msgstr "-x\t\t\tEdytuj zakodowane pliki" -msgid "-display <display>\tConnect vim to this particular X-server" +msgid "-display <display>\tConnect Vim to this particular X-server" msgstr "-display <display>\tPodcz vima to danego X-serwera" msgid "-X\t\t\tDo not connect to X server" @@ -3153,10 +3151,10 @@ msgstr "" "\n" "Argumenty rozpoznawane przez gvim (wersja Athena):\n" -msgid "-display <display>\tRun vim on <display>" -msgstr "-display <display>\tZaaduj vim na <display>" +msgid "-display <display>\tRun Vim on <display>" +msgstr "-display <display>\tZaaduj Vim na <display>" -msgid "-iconic\t\tStart vim iconified" +msgid "-iconic\t\tStart Vim iconified" msgstr "-iconic\t\tZacznij Vim jako ikon" msgid "-background <color>\tUse <color> for the background (also: -bg)" @@ -3206,8 +3204,8 @@ msgstr "" "\n" "Argumenty rozpoznawane przez gvim (wersja GTK+):\n" -msgid "-display <display>\tRun vim on <display> (also: --display)" -msgstr "-display <display>\tZastartuj vim na <display> (rwnie: --display)" +msgid "-display <display>\tRun Vim on <display> (also: --display)" +msgstr "-display <display>\tZastartuj Vim na <display> (rwnie: --display)" msgid "--role <role>\tSet a unique role to identify the main window" msgstr "--role <role>\tUstaw unikatow rol do identyfikacji gwnego okna" @@ -6643,14 +6641,14 @@ msgstr "indeks listy poza zakresem" #. No more suitable format specifications in python-2.3 #, c-format -msgid "internal error: failed to get vim list item %d" +msgid "internal error: failed to get Vim list item %d" msgstr "bd wewntrzny: nie powiodo si pobranie z listy Vima elementu %d" msgid "failed to add item to list" msgstr "nie powiodo si dodanie elementu do listy" #, c-format -msgid "internal error: no vim list item %d" +msgid "internal error: no Vim list item %d" msgstr "bd wewntrzny: w licie Vima brak elementu %d" msgid "internal error: failed to add item to list" @@ -6752,7 +6750,7 @@ msgstr "uruchomienie kodu si msgid "E858: Eval did not return a valid python object" msgstr "E858: eval nie zwrcio odpowiedniego obiektu pythona" -msgid "E859: Failed to convert returned python object to vim value" +msgid "E859: Failed to convert returned python object to a Vim value" msgstr "E859: Nie powioda si konwersja obiektu pythona do wartoci Vima" #, c-format diff --git a/src/po/pt_BR.po b/src/po/pt_BR.po index 8acef0e82d..65dcf37883 100644 --- a/src/po/pt_BR.po +++ b/src/po/pt_BR.po @@ -2765,9 +2765,6 @@ msgstr "opção do Vim desconhecida" msgid "keyboard interrupt" msgstr "interrompido pelo teclado" -msgid "vim error" -msgstr "erro do vim" - msgid "cannot create buffer/window command: object is being deleted" msgstr "" "impossível criar comando de buffer/janela: o objeto está sendo excluído" @@ -3096,8 +3093,8 @@ msgstr "-W <script>\t\tGravar todos os comandos digitados no arquivo <script>" msgid "-x\t\t\tEdit encrypted files" msgstr "-x\t\t\tEditar arquivos criptografados" -msgid "-display <display>\tConnect vim to this particular X-server" -msgstr "-display <display>\tConectar o vim a este servidor X específico" +msgid "-display <display>\tConnect Vim to this particular X-server" +msgstr "-display <display>\tConectar o Vim a este servidor X específico" msgid "-X\t\t\tDo not connect to X server" msgstr "-X\t\t\tNão conectar ao servidor X" @@ -3175,11 +3172,11 @@ msgstr "" "\n" "Argumentos reconhecidos pelo gvim (versão Athena):\n" -msgid "-display <display>\tRun vim on <display>" -msgstr "-display <display>\tExecutar vim em <display>" +msgid "-display <display>\tRun Vim on <display>" +msgstr "-display <display>\tExecutar Vim em <display>" -msgid "-iconic\t\tStart vim iconified" -msgstr "-iconic\t\tIniciar vim iconizado" +msgid "-iconic\t\tStart Vim iconified" +msgstr "-iconic\t\tIniciar Vim iconizado" msgid "-background <color>\tUse <color> for the background (also: -bg)" msgstr "-background <cor>\tUsar <cor> para o fundo (abrev.: -bg)" @@ -3227,8 +3224,8 @@ msgstr "" "\n" "Argumentos reconhecidos pelo gvim (versão GTK+):\n" -msgid "-display <display>\tRun vim on <display> (also: --display)" -msgstr "-display <display>\tExecutar vim no <display> (alt.: --display)" +msgid "-display <display>\tRun Vim on <display> (also: --display)" +msgstr "-display <display>\tExecutar Vim no <display> (alt.: --display)" msgid "--role <role>\tSet a unique role to identify the main window" msgstr "" @@ -6849,7 +6846,7 @@ msgid "list index out of range" msgstr "índice de lista fora dos limites" #, c-format -msgid "internal error: failed to get vim list item %d" +msgid "internal error: failed to get Vim list item %d" msgstr "erro interno: não consegui obter item %d de lista do Vim" msgid "slice step cannot be zero" @@ -6861,7 +6858,7 @@ msgstr "" "tentativa de atribuir sequência de tamanho maior que %d a slice estendida" #, c-format -msgid "internal error: no vim list item %d" +msgid "internal error: no Vim list item %d" msgstr "erro interno: não existe o item %d na lista do vim" msgid "internal error: not enough list items" @@ -6971,20 +6968,20 @@ msgstr "falha ao executar o código" msgid "E858: Eval did not return a valid python object" msgstr "E858: Eval não devolveu um objeto python válido" -msgid "E859: Failed to convert returned python object to vim value" +msgid "E859: Failed to convert returned python object to a Vim value" msgstr "" "E859: Falha ao converter o objeto devolvido pelo python para um valor do vim" #, c-format -msgid "unable to convert %s to vim dictionary" +msgid "unable to convert %s to a Vim dictionary" msgstr "impossível converter %s para dicionário do vim" #, c-format -msgid "unable to convert %s to vim list" +msgid "unable to convert %s to a Vim list" msgstr "impossível converter %s para lista do vim" #, c-format -msgid "unable to convert %s to vim structure" +msgid "unable to convert %s to a Vim structure" msgstr "impossível converter %s para estrutura do vim" msgid "internal error: NULL reference passed" diff --git a/src/po/ru.cp1251.po b/src/po/ru.cp1251.po index 50c1da2121..bd9c9dc725 100644 --- a/src/po/ru.cp1251.po +++ b/src/po/ru.cp1251.po @@ -2642,9 +2642,6 @@ msgstr " msgid "keyboard interrupt" msgstr " " -msgid "vim error" -msgstr " VIM" - msgid "cannot create buffer/window command: object is being deleted" msgstr " : " @@ -3132,7 +3129,7 @@ msgstr "-W < msgid "-x\t\t\tEdit encrypted files" msgstr "-x\t\t\t " -msgid "-display <display>\tConnect vim to this particular X-server" +msgid "-display <display>\tConnect Vim to this particular X-server" msgstr "-display <>\t Vim X-" msgid "-X\t\t\tDo not connect to X server" @@ -3210,10 +3207,10 @@ msgstr "" "\n" " gvim ( Athena):\n" -msgid "-display <display>\tRun vim on <display>" +msgid "-display <display>\tRun Vim on <display>" msgstr "-display <>\t Vim <>" -msgid "-iconic\t\tStart vim iconified" +msgid "-iconic\t\tStart Vim iconified" msgstr "-iconic\t\t Vim " msgid "-background <color>\tUse <color> for the background (also: -bg)" @@ -3260,7 +3257,7 @@ msgstr "" "\n" " gvim ( GTK+):\n" -msgid "-display <display>\tRun vim on <display> (also: --display)" +msgid "-display <display>\tRun Vim on <display> (also: --display)" msgstr "" "-display <>\t Vim <> ( --display)" @@ -7262,7 +7259,7 @@ msgid "list index out of range" msgstr " " #, c-format -msgid "internal error: failed to get vim list item %d" +msgid "internal error: failed to get Vim list item %d" msgstr " : VIM- %d" msgid "slice step cannot be zero" @@ -7275,7 +7272,7 @@ msgstr "" "" #, c-format -msgid "internal error: no vim list item %d" +msgid "internal error: no Vim list item %d" msgstr " : VIM- %d" msgid "internal error: not enough list items" @@ -7386,20 +7383,20 @@ msgstr " msgid "E858: Eval did not return a valid python object" msgstr "E858: Eval Python" -msgid "E859: Failed to convert returned python object to vim value" +msgid "E859: Failed to convert returned python object to a Vim value" msgstr "" "E859: Python VIM" #, c-format -msgid "unable to convert %s to vim dictionary" +msgid "unable to convert %s to a Vim dictionary" msgstr " %s VIM" #, c-format -msgid "unable to convert %s to vim list" +msgid "unable to convert %s to a Vim list" msgstr " %s VIM" #, c-format -msgid "unable to convert %s to vim structure" +msgid "unable to convert %s to a Vim structure" msgstr " %s VIM" msgid "internal error: NULL reference passed" diff --git a/src/po/ru.po b/src/po/ru.po index 9c2c7881a5..d2b70a3e80 100644 --- a/src/po/ru.po +++ b/src/po/ru.po @@ -2642,9 +2642,6 @@ msgstr "неизвестная vimOption" msgid "keyboard interrupt" msgstr "клавиатурное прерывание" -msgid "vim error" -msgstr "ошибка VIM" - msgid "cannot create buffer/window command: object is being deleted" msgstr "невозможно создать команду буфера или окна: объект в процессе удаления" @@ -3132,7 +3129,7 @@ msgstr "-W <сценарий>\tЗаписать все введённые ком msgid "-x\t\t\tEdit encrypted files" msgstr "-x\t\t\tРедактирование зашифрованных файлов" -msgid "-display <display>\tConnect vim to this particular X-server" +msgid "-display <display>\tConnect Vim to this particular X-server" msgstr "-display <экран>\tПодсоединить Vim к указанному X-серверу" msgid "-X\t\t\tDo not connect to X server" @@ -3210,10 +3207,10 @@ msgstr "" "\n" "Параметры для gvim (версия Athena):\n" -msgid "-display <display>\tRun vim on <display>" +msgid "-display <display>\tRun Vim on <display>" msgstr "-display <дисплей>\tЗапустить Vim на указанном <дисплее>" -msgid "-iconic\t\tStart vim iconified" +msgid "-iconic\t\tStart Vim iconified" msgstr "-iconic\t\tЗапустить Vim в свёрнутом виде" msgid "-background <color>\tUse <color> for the background (also: -bg)" @@ -3260,7 +3257,7 @@ msgstr "" "\n" "Параметры для gvim (версия GTK+):\n" -msgid "-display <display>\tRun vim on <display> (also: --display)" +msgid "-display <display>\tRun Vim on <display> (also: --display)" msgstr "" "-display <дисплей>\tЗапустить Vim на указанном <дисплее> (или --display)" @@ -7262,7 +7259,7 @@ msgid "list index out of range" msgstr "Индекс списка за пределами диапазона" #, c-format -msgid "internal error: failed to get vim list item %d" +msgid "internal error: failed to get Vim list item %d" msgstr "Внутренняя ошибка: не удалось получить элемент VIM-списка %d" msgid "slice step cannot be zero" @@ -7275,7 +7272,7 @@ msgstr "" "выборке" #, c-format -msgid "internal error: no vim list item %d" +msgid "internal error: no Vim list item %d" msgstr "Внутренняя ошибка: нет элемента VIM-списка %d" msgid "internal error: not enough list items" @@ -7386,20 +7383,20 @@ msgstr "Невозможно выполнить код" msgid "E858: Eval did not return a valid python object" msgstr "E858: Eval не возвратил допустимого объекта Python" -msgid "E859: Failed to convert returned python object to vim value" +msgid "E859: Failed to convert returned python object to a Vim value" msgstr "" "E859: Не удалось преобразовать возвращённый объект Python в значение VIM" #, c-format -msgid "unable to convert %s to vim dictionary" +msgid "unable to convert %s to a Vim dictionary" msgstr "Невозможно преобразовать %s в словарь VIM" #, c-format -msgid "unable to convert %s to vim list" +msgid "unable to convert %s to a Vim list" msgstr "Невозможно преобразовать %s в список VIM" #, c-format -msgid "unable to convert %s to vim structure" +msgid "unable to convert %s to a Vim structure" msgstr "Невозможно преобразовать %s в структуру VIM" msgid "internal error: NULL reference passed" diff --git a/src/po/sk.cp1250.po b/src/po/sk.cp1250.po index af413e9ea2..c492f2aab8 100644 --- a/src/po/sk.cp1250.po +++ b/src/po/sk.cp1250.po @@ -2448,9 +2448,6 @@ msgstr "nezn msgid "keyboard interrupt" msgstr "preruenie z klvesnice" -msgid "vim error" -msgstr "chyba Vim" - msgid "cannot create buffer/window command: object is being deleted" msgstr "ned sa vytvori prkaz bufferu/okna: objekt bude vymazan" @@ -2740,8 +2737,8 @@ msgstr "-W <skript>\t\tUlo msgid "-x\t\t\tEdit encrypted files" msgstr "-x\t\t\tprava zaifrovanch sborov" -msgid "-display <display>\tConnect vim to this particular X-server" -msgstr "-display <displej>\tPripoj vim na prslun X-server" +msgid "-display <display>\tConnect Vim to this particular X-server" +msgstr "-display <displej>\tPripoj Vim na prslun X-server" msgid "-X\t\t\tDo not connect to X server" msgstr "-X\t\t\tNepripoj sa k X serveru" @@ -2803,11 +2800,11 @@ msgstr "" "\n" "Argumenty dostupn pre gvim (Athena verzia):\n" -msgid "-display <display>\tRun vim on <display>" -msgstr "-display <displej>\tSpust vim na <displej>" +msgid "-display <display>\tRun Vim on <display>" +msgstr "-display <displej>\tSpust Vim na <displej>" -msgid "-iconic\t\tStart vim iconified" -msgstr "-iconic\t\tSpust vim minimalizovan" +msgid "-iconic\t\tStart Vim iconified" +msgstr "-iconic\t\tSpust Vim minimalizovan" msgid "-name <name>\t\tUse resource as if vim was <name>" msgstr "-name <nzov>\t\tPouije resource ako by vim mal <nzov>" @@ -2872,8 +2869,8 @@ msgstr "" "\n" "Argumenty dostupn pre gvim (GTK+ verzia):\n" -msgid "-display <display>\tRun vim on <display> (also: --display)" -msgstr "-display <displej>\tSpust vim na <displej> (tie --display)" +msgid "-display <display>\tRun Vim on <display> (also: --display)" +msgstr "-display <displej>\tSpust Vim na <displej> (tie --display)" msgid "--role <role>\tSet a unique role to identify the main window" msgstr "-role <rola>\tNastav uniktnu rolu pre identifikciu hlavnho okna" @@ -2897,8 +2894,8 @@ msgstr "-tip\t\t\tZobraz tip pri msgid "-notip\t\tDisable the tip dialog" msgstr "-notip\t\tNezobrazuj tip pri tarte" -msgid "--display <display>\tRun vim on <display>" -msgstr "-display <displej>\tSpust vim na <displej>" +msgid "--display <display>\tRun Vim on <display>" +msgstr "-display <displej>\tSpust Vim na <displej>" msgid "-P <parent title>\tOpen Vim inside parent application" msgstr "-P <titulok rodia>\tOtvor Vim vntri materskej aplikcie" diff --git a/src/po/sk.po b/src/po/sk.po index ab132777b4..380a929e3b 100644 --- a/src/po/sk.po +++ b/src/po/sk.po @@ -2448,9 +2448,6 @@ msgstr "nezn msgid "keyboard interrupt" msgstr "preruenie z klvesnice" -msgid "vim error" -msgstr "chyba Vim" - msgid "cannot create buffer/window command: object is being deleted" msgstr "ned sa vytvori prkaz bufferu/okna: objekt bude vymazan" @@ -2740,8 +2737,8 @@ msgstr "-W <skript>\t\tUlo msgid "-x\t\t\tEdit encrypted files" msgstr "-x\t\t\tprava zaifrovanch sborov" -msgid "-display <display>\tConnect vim to this particular X-server" -msgstr "-display <displej>\tPripoj vim na prslun X-server" +msgid "-display <display>\tConnect Vim to this particular X-server" +msgstr "-display <displej>\tPripoj Vim na prslun X-server" msgid "-X\t\t\tDo not connect to X server" msgstr "-X\t\t\tNepripoj sa k X serveru" @@ -2803,11 +2800,11 @@ msgstr "" "\n" "Argumenty dostupn pre gvim (Athena verzia):\n" -msgid "-display <display>\tRun vim on <display>" -msgstr "-display <displej>\tSpust vim na <displej>" +msgid "-display <display>\tRun Vim on <display>" +msgstr "-display <displej>\tSpust Vim na <displej>" -msgid "-iconic\t\tStart vim iconified" -msgstr "-iconic\t\tSpust vim minimalizovan" +msgid "-iconic\t\tStart Vim iconified" +msgstr "-iconic\t\tSpust Vim minimalizovan" msgid "-name <name>\t\tUse resource as if vim was <name>" msgstr "-name <nzov>\t\tPouije resource ako by vim mal <nzov>" @@ -2872,8 +2869,8 @@ msgstr "" "\n" "Argumenty dostupn pre gvim (GTK+ verzia):\n" -msgid "-display <display>\tRun vim on <display> (also: --display)" -msgstr "-display <displej>\tSpust vim na <displej> (tie --display)" +msgid "-display <display>\tRun Vim on <display> (also: --display)" +msgstr "-display <displej>\tSpust Vim na <displej> (tie --display)" msgid "--role <role>\tSet a unique role to identify the main window" msgstr "-role <rola>\tNastav uniktnu rolu pre identifikciu hlavnho okna" @@ -2897,8 +2894,8 @@ msgstr "-tip\t\t\tZobraz tip pri msgid "-notip\t\tDisable the tip dialog" msgstr "-notip\t\tNezobrazuj tip pri tarte" -msgid "--display <display>\tRun vim on <display>" -msgstr "-display <displej>\tSpust vim na <displej>" +msgid "--display <display>\tRun Vim on <display>" +msgstr "-display <displej>\tSpust Vim na <displej>" msgid "-P <parent title>\tOpen Vim inside parent application" msgstr "-P <titulok rodia>\tOtvor Vim vntri materskej aplikcie" diff --git a/src/po/sr.po b/src/po/sr.po index 02d697cea1..87ec416dfe 100644 --- a/src/po/sr.po +++ b/src/po/sr.po @@ -2630,9 +2630,6 @@ msgstr "непозната vimОпција" msgid "keyboard interrupt" msgstr "прекид тастатуре" -msgid "vim error" -msgstr "vim грешка" - msgid "cannot create buffer/window command: object is being deleted" msgstr "бафер/прозор команда не може да се креира: објекат се брише" @@ -3100,8 +3097,8 @@ msgstr "-W <скриптизлаз>\tУписуј све откуцане ком msgid "-x\t\t\tEdit encrypted files" msgstr "-x\t\t\tУређуј шифроване фајлове" -msgid "-display <display>\tConnect vim to this particular X-server" -msgstr "-display <дисплеј>\tПовежи vim на овај X-сервер" +msgid "-display <display>\tConnect Vim to this particular X-server" +msgstr "-display <дисплеј>\tПовежи Vim на овај X-сервер" msgid "-X\t\t\tDo not connect to X server" msgstr "-X\t\t\tНе повезуј се на X сервер" @@ -3178,11 +3175,11 @@ msgstr "" "\n" "Аргументи које препознаје gvim (Athena верзија):\n" -msgid "-display <display>\tRun vim on <display>" -msgstr "-display <дисплеј>\tПокрени vim на <дисплеј>" +msgid "-display <display>\tRun Vim on <display>" +msgstr "-display <дисплеј>\tПокрени Vim на <дисплеј>" -msgid "-iconic\t\tStart vim iconified" -msgstr "-iconic\t\tПокрени vim као икону" +msgid "-iconic\t\tStart Vim iconified" +msgstr "-iconic\t\tПокрени Vim као икону" msgid "-background <color>\tUse <color> for the background (also: -bg)" msgstr "-background <боја>\tКористи <боја> за позадину (такође: -bg)" @@ -3230,8 +3227,8 @@ msgstr "" "\n" "Аргументи које препознаје gvim (GTK+ верзија):\n" -msgid "-display <display>\tRun vim on <display> (also: --display)" -msgstr "-display <дисплеј>\tПокрени vim на <дисплеј> (такође: --display)" +msgid "-display <display>\tRun Vim on <display> (also: --display)" +msgstr "-display <дисплеј>\tПокрени Vim на <дисплеј> (такође: --display)" msgid "--role <role>\tSet a unique role to identify the main window" msgstr "" @@ -7210,7 +7207,7 @@ msgid "list index out of range" msgstr "индекс листе је ван опсега" #, c-format -msgid "internal error: failed to get vim list item %d" +msgid "internal error: failed to get Vim list item %d" msgstr "интерна грешка: ставка %d vim листе није могла да се добије" msgid "slice step cannot be zero" @@ -7221,7 +7218,7 @@ msgid "attempt to assign sequence of size greater than %d to extended slice" msgstr "покушај доделе секвенце величине веће од %d како би се продужио slice" #, c-format -msgid "internal error: no vim list item %d" +msgid "internal error: no Vim list item %d" msgstr "интерна грешка: нема ставке %d у vim листи" msgid "internal error: not enough list items" @@ -7331,19 +7328,19 @@ msgstr "кôд није могао да се покрене" msgid "E858: Eval did not return a valid python object" msgstr "E858: Eval није вратио важећи python објекат" -msgid "E859: Failed to convert returned python object to vim value" +msgid "E859: Failed to convert returned python object to a Vim value" msgstr "E859: Конверзија враћеног python објекта у vim вредност није успела" #, c-format -msgid "unable to convert %s to vim dictionary" +msgid "unable to convert %s to a Vim dictionary" msgstr "%s не може да се конвертује у vim речник" #, c-format -msgid "unable to convert %s to vim list" +msgid "unable to convert %s to a Vim list" msgstr "%s не може да се конвертује у vim листу" #, c-format -msgid "unable to convert %s to vim structure" +msgid "unable to convert %s to a Vim structure" msgstr "%s не може да се конвертује у vim структуру" msgid "internal error: NULL reference passed" diff --git a/src/po/sv.po b/src/po/sv.po index 8beae82355..35b9a620b2 100644 --- a/src/po/sv.po +++ b/src/po/sv.po @@ -2621,9 +2621,6 @@ msgstr "ok msgid "keyboard interrupt" msgstr "tangentbordsavbrott" -msgid "vim error" -msgstr "vim-fel" - msgid "cannot create buffer/window command: object is being deleted" msgstr "kan inte skapa buffert/fnster-kommando: objekt hller p att tas bort" @@ -2922,8 +2919,8 @@ msgstr "-W <utskript>\tSkriv alla skrivna kommandon till fil <utskript>" msgid "-x\t\t\tEdit encrypted files" msgstr "-x\t\t\tRedigera krypterade filer" -msgid "-display <display>\tConnect vim to this particular X-server" -msgstr "-display <display>\tAnslut vim till just denna X-server" +msgid "-display <display>\tConnect Vim to this particular X-server" +msgstr "-display <display>\tAnslut Vim till just denna X-server" msgid "-X\t\t\tDo not connect to X server" msgstr "-X\t\t\tAnslut inte till X server" @@ -2995,11 +2992,11 @@ msgstr "" "\n" "Argument som stds av gvim (Athena-version):\n" -msgid "-display <display>\tRun vim on <display>" -msgstr "-display <display>\tKr vim p <display>" +msgid "-display <display>\tRun Vim on <display>" +msgstr "-display <display>\tKr Vim p <display>" -msgid "-iconic\t\tStart vim iconified" -msgstr "-iconic\t\tStarta vim som ikon" +msgid "-iconic\t\tStart Vim iconified" +msgstr "-iconic\t\tStarta Vim som ikon" msgid "-name <name>\t\tUse resource as if vim was <name>" msgstr "-name <namn>\t\tAnvnd resurs som om vim var <namn>" @@ -3065,8 +3062,8 @@ msgstr "" "\n" "Argument igenknda av gvim (GTK+-version):\n" -msgid "-display <display>\tRun vim on <display> (also: --display)" -msgstr "-display <display>\tKr vim p <display> (ven: --display)" +msgid "-display <display>\tRun Vim on <display> (also: --display)" +msgstr "-display <display>\tKr Vim p <display> (ven: --display)" msgid "--role <role>\tSet a unique role to identify the main window" msgstr "--role <roll>\tStll in en unik roll fr att identifiera huvudfnstret" diff --git a/src/po/tr.po b/src/po/tr.po index 3f988b1ddb..04422fbd9c 100644 --- a/src/po/tr.po +++ b/src/po/tr.po @@ -2529,9 +2529,6 @@ msgstr "geçersiz vimOption" msgid "keyboard interrupt" msgstr "klavye araya girdi" -msgid "vim error" -msgstr "vim hatası" - msgid "cannot create buffer/window command: object is being deleted" msgstr "arabellek/pencere komutu oluşturulamadı: öge şu anda siliniyor" @@ -2991,7 +2988,7 @@ msgstr "-W <betikçık>\tGirilen tüm komutları <betikçık> dosyasına yaz" msgid "-x\t\t\tEdit encrypted files" msgstr "-x\t\t\tŞifrelenmiş dosyaları düzenle" -msgid "-display <display>\tConnect vim to this particular X-server" +msgid "-display <display>\tConnect Vim to this particular X-server" msgstr "-display <ekran>\tVim'i bu belirtilen X sunucusuna bağla" msgid "-X\t\t\tDo not connect to X server" @@ -3069,10 +3066,10 @@ msgstr "" "\n" "gvim tarafından tanınan değişkenler (Athena sürümü):\n" -msgid "-display <display>\tRun vim on <display>" +msgid "-display <display>\tRun Vim on <display>" msgstr "-display <ekran>\tVim'i <ekran>'da çalıştır" -msgid "-iconic\t\tStart vim iconified" +msgid "-iconic\t\tStart Vim iconified" msgstr "-iconic\t\tVim'i simge durumunda başlat" msgid "-background <color>\tUse <color> for the background (also: -bg)" @@ -3120,7 +3117,7 @@ msgstr "" "\n" "gvim tarafından tanınan değişkenler (GTK+ sürümü):\n" -msgid "-display <display>\tRun vim on <display> (also: --display)" +msgid "-display <display>\tRun Vim on <display> (also: --display)" msgstr "-display <ekran>\tVim'i <ekran>'da çalıştır (veya: --display)" msgid "--role <role>\tSet a unique role to identify the main window" @@ -7437,7 +7434,7 @@ msgid "list index out of range" msgstr "liste dizini erimin dışında" #, c-format -msgid "internal error: failed to get vim list item %d" +msgid "internal error: failed to get Vim list item %d" msgstr "iç hata: %d vim liste ögesi alınamadı" msgid "slice step cannot be zero" @@ -7448,7 +7445,7 @@ msgid "attempt to assign sequence of size greater than %d to extended slice" msgstr "genişletilmiş dilime %d boyuttan büyük bir sıralamayı atama denemesi" #, c-format -msgid "internal error: no vim list item %d" +msgid "internal error: no Vim list item %d" msgstr "iç hata: %d vim liste ögesi yok" msgid "internal error: not enough list items" @@ -7557,19 +7554,19 @@ msgstr "kod çalıştırılamadı" msgid "E858: Eval did not return a valid python object" msgstr "E858: Eval geçerli bir python nesnesi döndürmedi" -msgid "E859: Failed to convert returned python object to vim value" +msgid "E859: Failed to convert returned python object to a Vim value" msgstr "E859: Döndürülen python nesnesi vim değerine dönüştürülemedi" #, c-format -msgid "unable to convert %s to vim dictionary" +msgid "unable to convert %s to a Vim dictionary" msgstr "%s vim sözlüğüne dönüştürülemedi" #, c-format -msgid "unable to convert %s to vim list" +msgid "unable to convert %s to a Vim list" msgstr "%s vim listesine dönüştürülemedi" #, c-format -msgid "unable to convert %s to vim structure" +msgid "unable to convert %s to a Vim structure" msgstr "%s vim yapısına dönüştürülemedi" msgid "internal error: NULL reference passed" diff --git a/src/po/uk.cp1251.po b/src/po/uk.cp1251.po index 9b7de40727..78593aa23e 100644 --- a/src/po/uk.cp1251.po +++ b/src/po/uk.cp1251.po @@ -2879,9 +2879,6 @@ msgstr " msgid "keyboard interrupt" msgstr " " -msgid "vim error" -msgstr " Vim" - msgid "cannot create buffer/window command: object is being deleted" msgstr " /: ' " @@ -3201,8 +3198,8 @@ msgstr "-w < msgid "-x\t\t\tEdit encrypted files" msgstr "-x\t\t\t " -msgid "-display <display>\tConnect vim to this particular X-server" -msgstr "-display <>\tϳ' vim X" +msgid "-display <display>\tConnect Vim to this particular X-server" +msgstr "-display <>\tϳ' Vim X" msgid "-X\t\t\tDo not connect to X server" msgstr "-X\t\t\t ' X " @@ -3283,10 +3280,10 @@ msgstr "" "\n" " gvim ( Athena)\n" -msgid "-display <display>\tRun vim on <display>" -msgstr "-display <>\t vim <>" +msgid "-display <display>\tRun Vim on <display>" +msgstr "-display <>\t Vim <>" -msgid "-iconic\t\tStart vim iconified" +msgid "-iconic\t\tStart Vim iconified" msgstr "-iconic\t\t Vim " msgid "-background <color>\tUse <color> for the background (also: -bg)" @@ -3333,8 +3330,8 @@ msgstr "" "\n" " gvim ( GTK+)\n" -msgid "-display <display>\tRun vim on <display> (also: --display)" -msgstr "-display <>\t vim <> (: --display)" +msgid "-display <display>\tRun Vim on <display> (also: --display)" +msgstr "-display <>\t Vim <> (: --display)" msgid "--role <role>\tSet a unique role to identify the main window" msgstr "" @@ -7123,7 +7120,7 @@ msgid "list index out of range" msgstr " " #, c-format -msgid "internal error: failed to get vim list item %d" +msgid "internal error: failed to get Vim list item %d" msgstr " : vim %d" msgid "slice step cannot be zero" @@ -7135,7 +7132,7 @@ msgstr "" " , %d, " #, c-format -msgid "internal error: no vim list item %d" +msgid "internal error: no Vim list item %d" msgstr " : vim %d" msgid "internal error: not enough list items" @@ -7247,19 +7244,19 @@ msgstr " msgid "E858: Eval did not return a valid python object" msgstr "E858: Eval ᒺ python" -msgid "E859: Failed to convert returned python object to vim value" +msgid "E859: Failed to convert returned python object to a Vim value" msgstr "E859: ᒺ python vim" #, c-format -msgid "unable to convert %s to vim dictionary" +msgid "unable to convert %s to a Vim dictionary" msgstr " %s vim" #, c-format -msgid "unable to convert %s to vim list" +msgid "unable to convert %s to a Vim list" msgstr " %s vim" #, c-format -msgid "unable to convert %s to vim structure" +msgid "unable to convert %s to a Vim structure" msgstr " %s vim" msgid "internal error: NULL reference passed" diff --git a/src/po/uk.po b/src/po/uk.po index 8ec2cde440..bb020af956 100644 --- a/src/po/uk.po +++ b/src/po/uk.po @@ -2879,9 +2879,6 @@ msgstr "Невідома vimOption" msgid "keyboard interrupt" msgstr "перервано з клавіатури" -msgid "vim error" -msgstr "помилка Vim" - msgid "cannot create buffer/window command: object is being deleted" msgstr "не вдалося створити команду вікна/буфера: об'єкт знищується" @@ -3201,8 +3198,8 @@ msgstr "-w <скрипт>\t\tЗаписати усі набрані команд msgid "-x\t\t\tEdit encrypted files" msgstr "-x\t\t\tРедагувати зашифровані файли" -msgid "-display <display>\tConnect vim to this particular X-server" -msgstr "-display <дисплей>\tПід'єднати vim до заданого дисплею сервера X" +msgid "-display <display>\tConnect Vim to this particular X-server" +msgstr "-display <дисплей>\tПід'єднати Vim до заданого дисплею сервера X" msgid "-X\t\t\tDo not connect to X server" msgstr "-X\t\t\tНе з'єднуватися з X сервером" @@ -3283,10 +3280,10 @@ msgstr "" "\n" "Аргументи для gvim (версія Athena)\n" -msgid "-display <display>\tRun vim on <display>" -msgstr "-display <дисплей>\tВиконати vim на заданому <дисплеї>" +msgid "-display <display>\tRun Vim on <display>" +msgstr "-display <дисплей>\tВиконати Vim на заданому <дисплеї>" -msgid "-iconic\t\tStart vim iconified" +msgid "-iconic\t\tStart Vim iconified" msgstr "-iconic\t\tЗапустити Vim і згорнути його вікно" msgid "-background <color>\tUse <color> for the background (also: -bg)" @@ -3333,8 +3330,8 @@ msgstr "" "\n" "Аргументи gvim (версія GTK+)\n" -msgid "-display <display>\tRun vim on <display> (also: --display)" -msgstr "-display <дисплей>\tВиконати vim на <дисплеї> (також: --display)" +msgid "-display <display>\tRun Vim on <display> (also: --display)" +msgstr "-display <дисплей>\tВиконати Vim на <дисплеї> (також: --display)" msgid "--role <role>\tSet a unique role to identify the main window" msgstr "" @@ -7123,7 +7120,7 @@ msgid "list index out of range" msgstr "індекс списку за межами" #, c-format -msgid "internal error: failed to get vim list item %d" +msgid "internal error: failed to get Vim list item %d" msgstr "внутрішня помилка: не вдалося отримати елемент списку vim %d" msgid "slice step cannot be zero" @@ -7135,7 +7132,7 @@ msgstr "" "спроба призначити послідовність розміру більше, ніж %d, у розширений зріз" #, c-format -msgid "internal error: no vim list item %d" +msgid "internal error: no Vim list item %d" msgstr "внутрішня помилка: немає елемента списку vim %d" msgid "internal error: not enough list items" @@ -7247,19 +7244,19 @@ msgstr "не вдалося виконати код" msgid "E858: Eval did not return a valid python object" msgstr "E858: Eval не повернув дійсний об’єкт python" -msgid "E859: Failed to convert returned python object to vim value" +msgid "E859: Failed to convert returned python object to a Vim value" msgstr "E859: Не вдалося перетворити об’єкт python у значення vim" #, c-format -msgid "unable to convert %s to vim dictionary" +msgid "unable to convert %s to a Vim dictionary" msgstr "не вдалося перетворити %s у словник vim" #, c-format -msgid "unable to convert %s to vim list" +msgid "unable to convert %s to a Vim list" msgstr "не вдалося перетворити %s у список vim" #, c-format -msgid "unable to convert %s to vim structure" +msgid "unable to convert %s to a Vim structure" msgstr "не вдалося перетворити %s у структуру vim" msgid "internal error: NULL reference passed" diff --git a/src/po/vi.po b/src/po/vi.po index 91e55622b0..24b7001aa8 100644 --- a/src/po/vi.po +++ b/src/po/vi.po @@ -2176,7 +2176,7 @@ msgstr "không rõ tùy chọn vimOption" msgid "keyboard interrupt" msgstr "sự gián đoạn của bàn phím" -msgid "vim error" +msgid "Vim error" msgstr "lỗi của vim" msgid "cannot create buffer/window command: object is being deleted" @@ -2460,8 +2460,8 @@ msgstr "-W <scriptout>\tGhi nhớ tất cả các lệnh đã gõ vào tập tin msgid "-x\t\t\tEdit encrypted files" msgstr "-x\t\t\tSoạn thảo tập tin đã mã hóa" -msgid "-display <display>\tConnect vim to this particular X-server" -msgstr "-display <màn hình>\tKết nối vim tới máy chủ X đã chỉ ra" +msgid "-display <display>\tConnect Vim to this particular X-server" +msgstr "-display <màn hình>\tKết nối Vim tới máy chủ X đã chỉ ra" msgid "-X\t\t\tDo not connect to X server" msgstr "-X\t\t\tKhông thực hiện việc kết nối tới máy chủ X" @@ -2526,11 +2526,11 @@ msgstr "" "\n" "Tham số cho gvim (phiên bản Athena):\n" -msgid "-display <display>\tRun vim on <display>" -msgstr "-display <màn hình>\tChạy vim trong <màn hình> đã chỉ ra" +msgid "-display <display>\tRun Vim on <display>" +msgstr "-display <màn hình>\tChạy Vim trong <màn hình> đã chỉ ra" -msgid "-iconic\t\tStart vim iconified" -msgstr "-iconic\t\tChạy vim ở dạng thu nhỏ" +msgid "-iconic\t\tStart Vim iconified" +msgstr "-iconic\t\tChạy Vim ở dạng thu nhỏ" msgid "-name <name>\t\tUse resource as if vim was <name>" msgstr "-name <tên>\t\tSử dụng tài nguyên giống như khi vim có <tên>" @@ -2599,9 +2599,9 @@ msgstr "" "\n" "Tham số cho gvim (phiên bản GTK+):\n" -msgid "-display <display>\tRun vim on <display> (also: --display)" +msgid "-display <display>\tRun Vim on <display> (also: --display)" msgstr "" -"-display <màn hình>\tChạy vim trên <màn hình> chỉ ra (cũng như: --display)" +"-display <màn hình>\tChạy Vim trên <màn hình> chỉ ra (cũng như: --display)" msgid "--role <role>\tSet a unique role to identify the main window" msgstr "--role <vai trò>\tĐặt <vai trò> duy nhất để nhận diện cửa sổ chính" diff --git a/src/po/zh_CN.UTF-8.po b/src/po/zh_CN.UTF-8.po index bb88cc9cde..83ed01e68a 100644 --- a/src/po/zh_CN.UTF-8.po +++ b/src/po/zh_CN.UTF-8.po @@ -2569,9 +2569,6 @@ msgstr "未知的 vim 选项" msgid "keyboard interrupt" msgstr "键盘中断" -msgid "vim error" -msgstr "vim 错误" - msgid "cannot create buffer/window command: object is being deleted" msgstr "无法创建缓冲区/窗口命令: 对象将被删除" @@ -2855,8 +2852,8 @@ msgstr "-W <scriptout>\t将所有输入的命令写入到文件 <scriptout>" msgid "-x\t\t\tEdit encrypted files" msgstr "-x\t\t\t编辑加密的文件" -msgid "-display <display>\tConnect vim to this particular X-server" -msgstr "-display <display>\t将 vim 与指定的 X-server 连接" +msgid "-display <display>\tConnect Vim to this particular X-server" +msgstr "-display <display>\t将 Vim 与指定的 X-server 连接" msgid "-X\t\t\tDo not connect to X server" msgstr "-X\t\t\t不连接到 X Server" @@ -2921,10 +2918,10 @@ msgstr "" "\n" "gvim (Athena 版本) 可识别的参数:\n" -msgid "-display <display>\tRun vim on <display>" +msgid "-display <display>\tRun Vim on <display>" msgstr "-display <display>\t在 <display> 上运行 vim" -msgid "-iconic\t\tStart vim iconified" +msgid "-iconic\t\tStart Vim iconified" msgstr "-iconic\t\t启动后最小化" msgid "-name <name>\t\tUse resource as if vim was <name>" @@ -2989,8 +2986,8 @@ msgstr "" "\n" "gvim (GTK+ 版本) 可识别的参数:\n" -msgid "-display <display>\tRun vim on <display> (also: --display)" -msgstr "-display <display>\t在 <display> 上运行 vim (也可用 --display)" +msgid "-display <display>\tRun Vim on <display> (also: --display)" +msgstr "-display <display>\t在 <display> 上运行 Vim (也可用 --display)" msgid "--role <role>\tSet a unique role to identify the main window" msgstr "--role <role>\t设置用于区分主窗口的窗口角色名" diff --git a/src/po/zh_CN.cp936.po b/src/po/zh_CN.cp936.po index b6e2bd9406..3feed9de31 100644 --- a/src/po/zh_CN.cp936.po +++ b/src/po/zh_CN.cp936.po @@ -2569,9 +2569,6 @@ msgstr "δ֪ msgid "keyboard interrupt" msgstr "ж" -msgid "vim error" -msgstr "vim " - msgid "cannot create buffer/window command: object is being deleted" msgstr "޷/: 󽫱ɾ" @@ -2855,8 +2852,8 @@ msgstr "-W <scriptout>\t msgid "-x\t\t\tEdit encrypted files" msgstr "-x\t\t\t༭ܵļ" -msgid "-display <display>\tConnect vim to this particular X-server" -msgstr "-display <display>\t vim ָ X-server " +msgid "-display <display>\tConnect Vim to this particular X-server" +msgstr "-display <display>\t Vim ָ X-server " msgid "-X\t\t\tDo not connect to X server" msgstr "-X\t\t\tӵ X Server" @@ -2921,10 +2918,10 @@ msgstr "" "\n" "gvim (Athena 汾) ʶIJ:\n" -msgid "-display <display>\tRun vim on <display>" +msgid "-display <display>\tRun Vim on <display>" msgstr "-display <display>\t <display> vim" -msgid "-iconic\t\tStart vim iconified" +msgid "-iconic\t\tStart Vim iconified" msgstr "-iconic\t\tС" msgid "-name <name>\t\tUse resource as if vim was <name>" @@ -2989,8 +2986,8 @@ msgstr "" "\n" "gvim (GTK+ 汾) ʶIJ:\n" -msgid "-display <display>\tRun vim on <display> (also: --display)" -msgstr "-display <display>\t <display> vim (Ҳ --display)" +msgid "-display <display>\tRun Vim on <display> (also: --display)" +msgstr "-display <display>\t <display> Vim (Ҳ --display)" msgid "--role <role>\tSet a unique role to identify the main window" msgstr "--role <role>\tڵĴڽɫ" diff --git a/src/po/zh_CN.po b/src/po/zh_CN.po index bddad0daf4..606b75c498 100644 --- a/src/po/zh_CN.po +++ b/src/po/zh_CN.po @@ -2570,9 +2570,6 @@ msgstr "δ֪ msgid "keyboard interrupt" msgstr "ж" -msgid "vim error" -msgstr "vim " - msgid "cannot create buffer/window command: object is being deleted" msgstr "޷/: 󽫱ɾ" @@ -2856,8 +2853,8 @@ msgstr "-W <scriptout>\t msgid "-x\t\t\tEdit encrypted files" msgstr "-x\t\t\t༭ܵļ" -msgid "-display <display>\tConnect vim to this particular X-server" -msgstr "-display <display>\t vim ָ X-server " +msgid "-display <display>\tConnect Vim to this particular X-server" +msgstr "-display <display>\t Vim ָ X-server " msgid "-X\t\t\tDo not connect to X server" msgstr "-X\t\t\tӵ X Server" @@ -2921,10 +2918,10 @@ msgstr "" "\n" "gvim (Athena 汾) ʶIJ:\n" -msgid "-display <display>\tRun vim on <display>" +msgid "-display <display>\tRun Vim on <display>" msgstr "-display <display>\t <display> vim" -msgid "-iconic\t\tStart vim iconified" +msgid "-iconic\t\tStart Vim iconified" msgstr "-iconic\t\tС" msgid "-name <name>\t\tUse resource as if vim was <name>" @@ -2989,8 +2986,8 @@ msgstr "" "\n" "gvim (GTK+ 汾) ʶIJ:\n" -msgid "-display <display>\tRun vim on <display> (also: --display)" -msgstr "-display <display>\t <display> vim (Ҳ --display)" +msgid "-display <display>\tRun Vim on <display> (also: --display)" +msgstr "-display <display>\t <display> Vim (Ҳ --display)" msgid "--role <role>\tSet a unique role to identify the main window" msgstr "--role <role>\tڵĴڽɫ" diff --git a/src/po/zh_TW.UTF-8.po b/src/po/zh_TW.UTF-8.po index 86e2ce1a75..e991b7a3ff 100644 --- a/src/po/zh_TW.UTF-8.po +++ b/src/po/zh_TW.UTF-8.po @@ -2190,7 +2190,7 @@ msgstr "不正確的 VIM 選項" msgid "keyboard interrupt" msgstr "鍵盤中斷" -msgid "vim error" +msgid "Vim error" msgstr "vim 錯誤" msgid "cannot create buffer/window command: object is being deleted" @@ -2463,8 +2463,8 @@ msgstr "-W <scriptout>\t對檔案 <scriptout> 寫入所有輸入的命令" msgid "-x\t\t\tEdit encrypted files" msgstr "-x\t\t\t編輯編碼過的檔案" -msgid "-display <display>\tConnect vim to this particular X-server" -msgstr "-display <display>\t將 vim 與指定的 X-server 連線" +msgid "-display <display>\tConnect Vim to this particular X-server" +msgstr "-display <display>\t將 Vim 與指定的 X-server 連線" msgid "-X\t\t\tDo not connect to X server" msgstr "-X\t\t\t不要連線到 X Server" @@ -2525,10 +2525,10 @@ msgstr "" "\n" "gvim 認得的參數 (Athena 版):\n" -msgid "-display <display>\tRun vim on <display>" +msgid "-display <display>\tRun Vim on <display>" msgstr "-display <display>\t在視窗 <display> 執行 vim" -msgid "-iconic\t\tStart vim iconified" +msgid "-iconic\t\tStart Vim iconified" msgstr "-iconic\t\t啟動後圖示化(iconified)" msgid "-name <name>\t\tUse resource as if vim was <name>" @@ -2593,7 +2593,7 @@ msgstr "" "\n" "gvim 認得的參數 (GTK+ 版):\n" -msgid "-display <display>\tRun vim on <display> (also: --display)" +msgid "-display <display>\tRun Vim on <display> (also: --display)" msgstr "-display <display>\t在 <display> 執行 vim (也可用 --display)" msgid "--role <role>\tSet a unique role to identify the main window" diff --git a/src/po/zh_TW.po b/src/po/zh_TW.po index 70e046c89a..657d604118 100644 --- a/src/po/zh_TW.po +++ b/src/po/zh_TW.po @@ -2183,7 +2183,7 @@ msgstr " msgid "keyboard interrupt" msgstr "L_" -msgid "vim error" +msgid "Vim error" msgstr "vim ~" msgid "cannot create buffer/window command: object is being deleted" @@ -2456,8 +2456,8 @@ msgstr "-W <scriptout>\t msgid "-x\t\t\tEdit encrypted files" msgstr "-x\t\t\tssXLɮ" -msgid "-display <display>\tConnect vim to this particular X-server" -msgstr "-display <display>\tN vim Pw X-server su" +msgid "-display <display>\tConnect Vim to this particular X-server" +msgstr "-display <display>\tN Vim Pw X-server su" msgid "-X\t\t\tDo not connect to X server" msgstr "-X\t\t\tnsu X Server" @@ -2518,10 +2518,10 @@ msgstr "" "\n" "gvim {oѼ (Athena ):\n" -msgid "-display <display>\tRun vim on <display>" +msgid "-display <display>\tRun Vim on <display>" msgstr "-display <display>\tb <display> vim" -msgid "-iconic\t\tStart vim iconified" +msgid "-iconic\t\tStart Vim iconified" msgstr "-iconic\t\tҰʫϥܤ(iconified)" msgid "-name <name>\t\tUse resource as if vim was <name>" @@ -2586,8 +2586,8 @@ msgstr "" "\n" "gvim {oѼ (GTK+ ):\n" -msgid "-display <display>\tRun vim on <display> (also: --display)" -msgstr "-display <display>\tb <display> vim (]i --display)" +msgid "-display <display>\tRun Vim on <display> (also: --display)" +msgstr "-display <display>\tb <display> Vim (]i --display)" msgid "--role <role>\tSet a unique role to identify the main window" msgstr "--role <role>\t]wWS(role)HϤD" From 06f0853cb0b10364b22e5607fdecd35b3936e9ea Mon Sep 17 00:00:00 2001 From: Bram Moolenaar <Bram@vim.org> Date: Tue, 12 May 2020 23:45:16 +0200 Subject: [PATCH 142/230] patch 8.2.0745: crash on exit when not all popups are closed Problem: Crash on exit when not all popups are closed. Solution: Close popups when freeing all memory. Disable checking for popup when editing a file for now. --- src/ex_cmds.c | 5 ----- src/misc2.c | 11 +++++++++-- src/version.c | 2 ++ 3 files changed, 11 insertions(+), 7 deletions(-) diff --git a/src/ex_cmds.c b/src/ex_cmds.c index 9c55de3adf..f38bdacb63 100644 --- a/src/ex_cmds.c +++ b/src/ex_cmds.c @@ -2484,11 +2484,6 @@ do_ecmd( int did_inc_redrawing_disabled = FALSE; long *so_ptr = curwin->w_p_so >= 0 ? &curwin->w_p_so : &p_so; -#ifdef FEAT_PROP_POPUP - if (ERROR_IF_TERM_POPUP_WINDOW) - return FAIL; -#endif - if (eap != NULL) command = eap->do_ecmd_cmd; set_bufref(&old_curbuf, curbuf); diff --git a/src/misc2.c b/src/misc2.c index db03b5b1f9..0ab6caffaf 100644 --- a/src/misc2.c +++ b/src/misc2.c @@ -1069,6 +1069,14 @@ free_all_mem(void) # if defined(FEAT_BEVAL_TERM) ui_remove_balloon(); # endif +# if defined(FEAT_PROP_POPUP) + if (curwin != NULL) + { + while (popup_is_popup(curwin)) + popup_close_with_retval(curwin, 0); + close_all_popups(); + } +# endif // Clear user commands (before deleting buffers). ex_comclear(NULL); @@ -3144,8 +3152,7 @@ call_shell(char_u *cmd, int opt) if (p_verbose > 3) { verbose_enter(); - smsg(_("Calling shell to execute: \"%s\""), - cmd == NULL ? p_sh : cmd); + smsg(_("Calling shell to execute: \"%s\""), cmd == NULL ? p_sh : cmd); out_char('\n'); cursor_on(); verbose_leave(); diff --git a/src/version.c b/src/version.c index bd5337bca7..aa88847e7b 100644 --- a/src/version.c +++ b/src/version.c @@ -746,6 +746,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 745, /**/ 744, /**/ From d502aa4c10771ec8eb570345ec5e124c4a4b7cd0 Mon Sep 17 00:00:00 2001 From: Bram Moolenaar <Bram@vim.org> Date: Wed, 13 May 2020 01:04:32 +0200 Subject: [PATCH 143/230] patch 8.2.0746: popup_clear() hangs when a popup can't be closed Problem: popup_clear() hangs when a popup can't be closed. Solution: Bail out when a popup can't be closed. --- src/popupwin.c | 24 +++++++++++++++--------- src/proto/popupwin.pro | 4 ++-- src/version.c | 2 ++ 3 files changed, 19 insertions(+), 11 deletions(-) diff --git a/src/popupwin.c b/src/popupwin.c index 863439e83a..5b346ac5bc 100644 --- a/src/popupwin.c +++ b/src/popupwin.c @@ -2531,8 +2531,9 @@ error_if_popup_window(int also_with_term UNUSED) /* * Close a popup window by Window-id. * Does not invoke the callback. + * Return OK if the popup was closed, FAIL otherwise. */ - void + int popup_close(int id) { win_T *wp; @@ -2546,25 +2547,27 @@ popup_close(int id) if (wp == curwin) { error_for_popup_window(); - return; + return FAIL; } if (prev == NULL) first_popupwin = wp->w_next; else prev->w_next = wp->w_next; popup_free(wp); - return; + return OK; } // go through tab-local popups FOR_ALL_TABPAGES(tp) - popup_close_tabpage(tp, id); + if (popup_close_tabpage(tp, id) == OK) + return OK; + return FAIL; } /* * Close a popup window with Window-id "id" in tabpage "tp". */ - void + int popup_close_tabpage(tabpage_T *tp, int id) { win_T *wp; @@ -2577,15 +2580,16 @@ popup_close_tabpage(tabpage_T *tp, int id) if (wp == curwin) { error_for_popup_window(); - return; + return FAIL; } if (prev == NULL) *root = wp->w_next; else prev->w_next = wp->w_next; popup_free(wp); - return; + return OK; } + return FAIL; } void @@ -2594,9 +2598,11 @@ close_all_popups(void) if (ERROR_IF_ANY_POPUP_WINDOW) return; while (first_popupwin != NULL) - popup_close(first_popupwin->w_id); + if (popup_close(first_popupwin->w_id) == FAIL) + return; while (curtab->tp_first_popupwin != NULL) - popup_close(curtab->tp_first_popupwin->w_id); + if (popup_close(curtab->tp_first_popupwin->w_id) == FAIL) + return; } /* diff --git a/src/proto/popupwin.pro b/src/proto/popupwin.pro index 96b21b643e..0147e68052 100644 --- a/src/proto/popupwin.pro +++ b/src/proto/popupwin.pro @@ -34,8 +34,8 @@ void popup_show(win_T *wp); void f_popup_show(typval_T *argvars, typval_T *rettv); void f_popup_settext(typval_T *argvars, typval_T *rettv); int error_if_popup_window(int also_with_term); -void popup_close(int id); -void popup_close_tabpage(tabpage_T *tp, int id); +int popup_close(int id); +int popup_close_tabpage(tabpage_T *tp, int id); void close_all_popups(void); void f_popup_move(typval_T *argvars, typval_T *rettv); void f_popup_setoptions(typval_T *argvars, typval_T *rettv); diff --git a/src/version.c b/src/version.c index aa88847e7b..37548b2baa 100644 --- a/src/version.c +++ b/src/version.c @@ -746,6 +746,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 746, /**/ 745, /**/ From 03a9f848175b182372fb33403998059724a8bf31 Mon Sep 17 00:00:00 2001 From: Bram Moolenaar <Bram@vim.org> Date: Wed, 13 May 2020 13:40:16 +0200 Subject: [PATCH 144/230] patch 8.2.0747: cannot forcefully close all popups Problem: Cannot forcefully close all popups. Solution: Add the "force" argument to popup_clear(). Use it after running a test. Put back the check for a popup when editing a file. --- runtime/doc/popup.txt | 9 ++++++- src/channel.c | 4 ++-- src/evalfunc.c | 2 +- src/ex_cmds.c | 5 ++++ src/misc2.c | 8 ++----- src/popupwin.c | 44 ++++++++++++++++++++++------------- src/proto/popupwin.pro | 6 ++--- src/tag.c | 2 +- src/testdir/runtest.vim | 4 ++-- src/testdir/test_terminal.vim | 28 +++++++--------------- src/version.c | 2 ++ src/window.c | 5 +--- 12 files changed, 63 insertions(+), 56 deletions(-) diff --git a/runtime/doc/popup.txt b/runtime/doc/popup.txt index 9041f87540..d0bf2c4f28 100644 --- a/runtime/doc/popup.txt +++ b/runtime/doc/popup.txt @@ -236,8 +236,15 @@ popup_beval({what}, {options}) *popup_beval()* GetText()->popup_beval({}) < *popup_clear()* -popup_clear() Emergency solution to a misbehaving plugin: close all popup +popup_clear([{force}]) + Emergency solution to a misbehaving plugin: close all popup windows for the current tab and global popups. + Close callbacks are not invoked. + When {force} is not present this will fail if the current + window is a popup. + When {force} is present and |TRUE| the popup is also closed + when it is the current window. If a terminal is running in a + popup it is killed. popup_close({id} [, {result}]) *popup_close()* diff --git a/src/channel.c b/src/channel.c index 0e432f9afa..1fcb8451cb 100644 --- a/src/channel.c +++ b/src/channel.c @@ -156,9 +156,9 @@ ch_logfile(char_u *fname, char_u *opt) if (log_fd != NULL) { if (*fname != NUL) - ch_log(NULL, "closing, opening %s", fname); + ch_log(NULL, "closing this logfile, opening %s", fname); else - ch_log(NULL, "closing"); + ch_log(NULL, "closing logfile"); fclose(log_fd); } diff --git a/src/evalfunc.c b/src/evalfunc.c index 1493291954..c0101162b1 100644 --- a/src/evalfunc.c +++ b/src/evalfunc.c @@ -704,7 +704,7 @@ static funcentry_T global_functions[] = }, {"popup_atcursor", 2, 2, FEARG_1, ret_number, PROP_FUNC(f_popup_atcursor)}, {"popup_beval", 2, 2, FEARG_1, ret_number, PROP_FUNC(f_popup_beval)}, - {"popup_clear", 0, 0, 0, ret_void, PROP_FUNC(f_popup_clear)}, + {"popup_clear", 0, 1, 0, ret_void, PROP_FUNC(f_popup_clear)}, {"popup_close", 1, 2, FEARG_1, ret_void, PROP_FUNC(f_popup_close)}, {"popup_create", 2, 2, FEARG_1, ret_number, PROP_FUNC(f_popup_create)}, {"popup_dialog", 2, 2, FEARG_1, ret_number, PROP_FUNC(f_popup_dialog)}, diff --git a/src/ex_cmds.c b/src/ex_cmds.c index f38bdacb63..9c55de3adf 100644 --- a/src/ex_cmds.c +++ b/src/ex_cmds.c @@ -2484,6 +2484,11 @@ do_ecmd( int did_inc_redrawing_disabled = FALSE; long *so_ptr = curwin->w_p_so >= 0 ? &curwin->w_p_so : &p_so; +#ifdef FEAT_PROP_POPUP + if (ERROR_IF_TERM_POPUP_WINDOW) + return FAIL; +#endif + if (eap != NULL) command = eap->do_ecmd_cmd; set_bufref(&old_curbuf, curbuf); diff --git a/src/misc2.c b/src/misc2.c index 0ab6caffaf..50efde7f7b 100644 --- a/src/misc2.c +++ b/src/misc2.c @@ -1069,13 +1069,9 @@ free_all_mem(void) # if defined(FEAT_BEVAL_TERM) ui_remove_balloon(); # endif -# if defined(FEAT_PROP_POPUP) +# ifdef FEAT_PROP_POPUP if (curwin != NULL) - { - while (popup_is_popup(curwin)) - popup_close_with_retval(curwin, 0); - close_all_popups(); - } + close_all_popups(TRUE); # endif // Clear user commands (before deleting buffers). diff --git a/src/popupwin.c b/src/popupwin.c index 5b346ac5bc..f1f9f6008a 100644 --- a/src/popupwin.c +++ b/src/popupwin.c @@ -2054,9 +2054,13 @@ popup_create(typval_T *argvars, typval_T *rettv, create_type_T type) * popup_clear() */ void -f_popup_clear(typval_T *argvars UNUSED, typval_T *rettv UNUSED) +f_popup_clear(typval_T *argvars, typval_T *rettv UNUSED) { - close_all_popups(); + int force = FALSE; + + if (argvars[0].v_type != VAR_UNKNOWN) + force = (int)tv_get_number(&argvars[0]); + close_all_popups(force); } /* @@ -2163,7 +2167,7 @@ popup_close_and_callback(win_T *wp, typval_T *arg) // Careful: This may make "wp" invalid. invoke_popup_callback(wp, arg); - popup_close(id); + popup_close(id, FALSE); CHECK_CURBUF; } @@ -2250,7 +2254,7 @@ filter_handle_drag(win_T *wp, int c, typval_T *rettv) } /* - * popup_filter_menu({text}, {options}) + * popup_filter_menu({id}, {key}) */ void f_popup_filter_menu(typval_T *argvars, typval_T *rettv) @@ -2305,7 +2309,7 @@ f_popup_filter_menu(typval_T *argvars, typval_T *rettv) } /* - * popup_filter_yesno({text}, {options}) + * popup_filter_yesno({id}, {key}) */ void f_popup_filter_yesno(typval_T *argvars, typval_T *rettv) @@ -2534,7 +2538,7 @@ error_if_popup_window(int also_with_term UNUSED) * Return OK if the popup was closed, FAIL otherwise. */ int -popup_close(int id) +popup_close(int id, int force) { win_T *wp; tabpage_T *tp; @@ -2546,8 +2550,12 @@ popup_close(int id) { if (wp == curwin) { - error_for_popup_window(); - return FAIL; + if (!force) + { + error_for_popup_window(); + return FAIL; + } + win_enter(firstwin, FALSE); } if (prev == NULL) first_popupwin = wp->w_next; @@ -2559,7 +2567,7 @@ popup_close(int id) // go through tab-local popups FOR_ALL_TABPAGES(tp) - if (popup_close_tabpage(tp, id) == OK) + if (popup_close_tabpage(tp, id, force) == OK) return OK; return FAIL; } @@ -2568,7 +2576,7 @@ popup_close(int id) * Close a popup window with Window-id "id" in tabpage "tp". */ int -popup_close_tabpage(tabpage_T *tp, int id) +popup_close_tabpage(tabpage_T *tp, int id, int force) { win_T *wp; win_T **root = &tp->tp_first_popupwin; @@ -2579,8 +2587,12 @@ popup_close_tabpage(tabpage_T *tp, int id) { if (wp == curwin) { - error_for_popup_window(); - return FAIL; + if (!force) + { + error_for_popup_window(); + return FAIL; + } + win_enter(firstwin, FALSE); } if (prev == NULL) *root = wp->w_next; @@ -2593,15 +2605,15 @@ popup_close_tabpage(tabpage_T *tp, int id) } void -close_all_popups(void) +close_all_popups(int force) { - if (ERROR_IF_ANY_POPUP_WINDOW) + if (!force && ERROR_IF_ANY_POPUP_WINDOW) return; while (first_popupwin != NULL) - if (popup_close(first_popupwin->w_id) == FAIL) + if (popup_close(first_popupwin->w_id, force) == FAIL) return; while (curtab->tp_first_popupwin != NULL) - if (popup_close(curtab->tp_first_popupwin->w_id) == FAIL) + if (popup_close(curtab->tp_first_popupwin->w_id, force) == FAIL) return; } diff --git a/src/proto/popupwin.pro b/src/proto/popupwin.pro index 0147e68052..4fa3013f45 100644 --- a/src/proto/popupwin.pro +++ b/src/proto/popupwin.pro @@ -34,9 +34,9 @@ void popup_show(win_T *wp); void f_popup_show(typval_T *argvars, typval_T *rettv); void f_popup_settext(typval_T *argvars, typval_T *rettv); int error_if_popup_window(int also_with_term); -int popup_close(int id); -int popup_close_tabpage(tabpage_T *tp, int id); -void close_all_popups(void); +int popup_close(int id, int force); +int popup_close_tabpage(tabpage_T *tp, int id, int force); +void close_all_popups(int force); void f_popup_move(typval_T *argvars, typval_T *rettv); void f_popup_setoptions(typval_T *argvars, typval_T *rettv); void f_popup_getpos(typval_T *argvars, typval_T *rettv); diff --git a/src/tag.c b/src/tag.c index 40304e6696..a22a259962 100644 --- a/src/tag.c +++ b/src/tag.c @@ -3684,7 +3684,7 @@ jumpto_tag( if (win_valid(curwin_save)) win_enter(curwin_save, TRUE); - popup_close(wp->w_id); + popup_close(wp->w_id, FALSE); } #endif } diff --git a/src/testdir/runtest.vim b/src/testdir/runtest.vim index 13d4784e4a..b9d85f4bb1 100644 --- a/src/testdir/runtest.vim +++ b/src/testdir/runtest.vim @@ -188,9 +188,9 @@ func RunTheTest(test) au! au SwapExists * call HandleSwapExists() - " Close any stray popup windows + " Close any stray popup windows. if has('popupwin') - call popup_clear() + call popup_clear(1) endif " Close any extra tab pages and windows and make the current one not modified. diff --git a/src/testdir/test_terminal.vim b/src/testdir/test_terminal.vim index b7791c8150..33ff52fa48 100644 --- a/src/testdir/test_terminal.vim +++ b/src/testdir/test_terminal.vim @@ -2617,27 +2617,15 @@ endfunc func Test_term_nasty_callback() CheckExecutable sh - func OpenTerms() - set hidden - let g:buf0 = term_start('sh', #{hidden: 1}) - call popup_create(g:buf0, {}) - let g:buf1 = term_start('sh', #{hidden: 1, term_finish: 'close'}) - call popup_create(g:buf1, {}) - let g:buf2 = term_start(['sh', '-c'], #{curwin: 1, exit_cb: function('TermExit')}) - call TermWait(g:buf2, 50) - call popup_close(win_getid()) - endfunc - func TermExit(...) - let altbuf = bufnr('#') - call term_sendkeys(altbuf, "exit\<CR>") - call TermWait(altbuf) - call popup_close(win_getid()) - endfunc - call OpenTerms() - call term_sendkeys(g:buf0, "exit\<CR>") - call TermWait(g:buf0, 50) - exe g:buf0 .. 'bwipe!' + set hidden + let g:buf0 = term_start('sh', #{hidden: 1}) + call popup_create(g:buf0, {}) + let g:buf1 = term_start('sh', #{hidden: 1, term_finish: 'close'}) + call popup_create(g:buf1, {}) + call assert_fails("call term_start(['sh', '-c'], #{curwin: 1})", 'E863:') + + call popup_clear(1) set hidden& endfunc diff --git a/src/version.c b/src/version.c index 37548b2baa..15956bbeb3 100644 --- a/src/version.c +++ b/src/version.c @@ -746,6 +746,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 747, /**/ 746, /**/ diff --git a/src/window.c b/src/window.c index 532d31431e..ede2c6f281 100644 --- a/src/window.c +++ b/src/window.c @@ -2766,9 +2766,6 @@ win_free_all(void) (void)win_free_mem(aucmd_win, &dummy, NULL); aucmd_win = NULL; } -# ifdef FEAT_PROP_POPUP - close_all_popups(); -# endif while (firstwin != NULL) (void)win_free_mem(firstwin, &dummy, NULL); @@ -3801,7 +3798,7 @@ free_tabpage(tabpage_T *tp) # endif # ifdef FEAT_PROP_POPUP while (tp->tp_first_popupwin != NULL) - popup_close_tabpage(tp, tp->tp_first_popupwin->w_id); + popup_close_tabpage(tp, tp->tp_first_popupwin->w_id, TRUE); #endif for (idx = 0; idx < SNAP_COUNT; ++idx) clear_snapshot(tp, idx); From ef6b979bfae82f64781d8b0ce0194c57111243d4 Mon Sep 17 00:00:00 2001 From: Bram Moolenaar <Bram@vim.org> Date: Wed, 13 May 2020 16:34:15 +0200 Subject: [PATCH 145/230] patch 8.2.0748: cannot get a list of all popups Problem: Cannot get a list of all popups. Solution: Add popup_list(). Use it in the test runner. --- runtime/doc/eval.txt | 2 ++ runtime/doc/popup.txt | 5 +++++ src/evalfunc.c | 1 + src/popupwin.c | 19 +++++++++++++++++++ src/proto/popupwin.pro | 1 + src/testdir/runtest.vim | 3 ++- src/testdir/test_popupwin.vim | 13 +++++++++++-- src/version.c | 2 ++ 8 files changed, 43 insertions(+), 3 deletions(-) diff --git a/runtime/doc/eval.txt b/runtime/doc/eval.txt index 8086bd5602..8259e9920b 100644 --- a/runtime/doc/eval.txt +++ b/runtime/doc/eval.txt @@ -2627,6 +2627,8 @@ popup_findpreview() Number get window ID of preview popup window popup_getoptions({id}) Dict get options of popup window {id} popup_getpos({id}) Dict get position of popup window {id} popup_hide({id}) none hide popup menu {id} +popup_list() List get a list of window IDs of al popups +popup_locate({row}, {col}) Number get window ID of popup at position popup_menu({what}, {options}) Number create a popup window used as a menu popup_move({id}, {options}) none set position of popup window {id} popup_notification({what}, {options}) diff --git a/runtime/doc/popup.txt b/runtime/doc/popup.txt index d0bf2c4f28..5950c4753d 100644 --- a/runtime/doc/popup.txt +++ b/runtime/doc/popup.txt @@ -198,6 +198,7 @@ Other: |popup_getoptions()| get current options for a popup |popup_getpos()| get actual position and size of a popup |popup_locate()| find popup window at a screen position + |popup_list()| get list of all popups DETAILS *popup-function-details* @@ -423,6 +424,10 @@ popup_hide({id}) *popup_hide()* Can also be used as a |method|: > GetPopup()->popup_hide() +popup_list() *popup_list()* + Return a List with the |window-ID| of all existing popups. + + popup_locate({row}, {col}) *popup_locate()* Return the |window-ID| of the popup at screen position {row} and {col}. If there are multiple popups the one with the diff --git a/src/evalfunc.c b/src/evalfunc.c index c0101162b1..c499890d9b 100644 --- a/src/evalfunc.c +++ b/src/evalfunc.c @@ -715,6 +715,7 @@ static funcentry_T global_functions[] = {"popup_getoptions", 1, 1, FEARG_1, ret_dict_any, PROP_FUNC(f_popup_getoptions)}, {"popup_getpos", 1, 1, FEARG_1, ret_dict_any, PROP_FUNC(f_popup_getpos)}, {"popup_hide", 1, 1, FEARG_1, ret_void, PROP_FUNC(f_popup_hide)}, + {"popup_list", 0, 0, 0, ret_list_number, PROP_FUNC(f_popup_list)}, {"popup_locate", 2, 2, 0, ret_number, PROP_FUNC(f_popup_locate)}, {"popup_menu", 2, 2, FEARG_1, ret_number, PROP_FUNC(f_popup_menu)}, {"popup_move", 2, 2, FEARG_1, ret_void, PROP_FUNC(f_popup_move)}, diff --git a/src/popupwin.c b/src/popupwin.c index f1f9f6008a..a244c32368 100644 --- a/src/popupwin.c +++ b/src/popupwin.c @@ -2720,6 +2720,25 @@ f_popup_getpos(typval_T *argvars, typval_T *rettv) hash_unlock(&dict->dv_hashtab); } } + +/* + * popup_list() + */ + void +f_popup_list(typval_T *argvars UNUSED, typval_T *rettv) +{ + win_T *wp; + tabpage_T *tp; + + if (rettv_list_alloc(rettv) != OK) + return; + FOR_ALL_POPUPWINS(wp) + list_append_number(rettv->vval.v_list, wp->w_id); + FOR_ALL_TABPAGES(tp) + FOR_ALL_POPUPWINS_IN_TAB(tp, wp) + list_append_number(rettv->vval.v_list, wp->w_id); +} + /* * popup_locate({row}, {col}) */ diff --git a/src/proto/popupwin.pro b/src/proto/popupwin.pro index 4fa3013f45..02cdce33ab 100644 --- a/src/proto/popupwin.pro +++ b/src/proto/popupwin.pro @@ -40,6 +40,7 @@ void close_all_popups(int force); void f_popup_move(typval_T *argvars, typval_T *rettv); void f_popup_setoptions(typval_T *argvars, typval_T *rettv); void f_popup_getpos(typval_T *argvars, typval_T *rettv); +void f_popup_list(typval_T *argvars, typval_T *rettv); void f_popup_locate(typval_T *argvars, typval_T *rettv); void f_popup_getoptions(typval_T *argvars, typval_T *rettv); int error_if_term_popup_window(void); diff --git a/src/testdir/runtest.vim b/src/testdir/runtest.vim index b9d85f4bb1..b1e05288b1 100644 --- a/src/testdir/runtest.vim +++ b/src/testdir/runtest.vim @@ -188,8 +188,9 @@ func RunTheTest(test) au! au SwapExists * call HandleSwapExists() - " Close any stray popup windows. + " Check for and close any stray popup windows. if has('popupwin') + call assert_equal([], popup_list()) call popup_clear(1) endif diff --git a/src/testdir/test_popupwin.vim b/src/testdir/test_popupwin.vim index 5eecb193c1..a664346df5 100644 --- a/src/testdir/test_popupwin.vim +++ b/src/testdir/test_popupwin.vim @@ -428,7 +428,7 @@ func Test_popup_nospace() call delete('XtestPopupNospace') endfunc -func Test_popup_firstline() +func Test_popup_firstline_dump() CheckScreendump let lines =<< trim END @@ -449,7 +449,9 @@ func Test_popup_firstline() " clean up call StopVimInTerminal(buf) call delete('XtestPopupFirstline') +endfunc +func Test_popup_firstline() let winid = popup_create(['1111', '222222', '33333', '44444'], #{ \ maxheight: 2, \ firstline: 3, @@ -491,6 +493,7 @@ func Test_popup_firstline() call popup_setoptions(winid, #{line: 3}) call assert_equal(0, popup_getoptions(winid).firstline) call assert_equal(10, popup_getpos(winid).firstline) + call popup_close(winid) " CTRL-D scrolls down half a page let winid = popup_create(['xxx']->repeat(50), #{ @@ -826,10 +829,13 @@ func Test_popup_in_tab() endfunc func Test_popup_valid_arguments() + call assert_equal(0, len(popup_list())) + " Zero value is like the property wasn't there let winid = popup_create("text", #{col: 0}) let pos = popup_getpos(winid) call assert_inrange(&columns / 2 - 1, &columns / 2 + 1, pos.col) + call assert_equal([winid], popup_list()) call popup_clear() " using cursor column has minimum value of 1 @@ -1619,12 +1625,14 @@ func Test_popup_empty() let pos = popup_getpos(winid) call assert_equal(5, pos.width) call assert_equal(5, pos.height) + call popup_close(winid) let winid = popup_create([], #{border: []}) redraw let pos = popup_getpos(winid) call assert_equal(3, pos.width) call assert_equal(3, pos.height) + call popup_close(winid) endfunc func Test_popup_never_behind() @@ -3323,8 +3331,9 @@ func Test_popupwin_atcursor_far_right() set signcolumn=yes call setline(1, repeat('=', &columns)) normal! ggg$ - call popup_atcursor(repeat('x', 500), #{moved: 'any', border: []}) + let winid = popup_atcursor(repeat('x', 500), #{moved: 'any', border: []}) + call popup_close(winid) bwipe! set signcolumn& endfunc diff --git a/src/version.c b/src/version.c index 15956bbeb3..7881e3211e 100644 --- a/src/version.c +++ b/src/version.c @@ -746,6 +746,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 748, /**/ 747, /**/ From 55ba4b844f1b0e44f0f2e1bd14d26e7ad2df9ffc Mon Sep 17 00:00:00 2001 From: Bram Moolenaar <Bram@vim.org> Date: Wed, 13 May 2020 16:53:49 +0200 Subject: [PATCH 146/230] patch 8.2.0749: TERM signal test fails on FreeBSD Problem: TERM signal test fails on FreeBSD. Solution: Do not check the messages, the may appear anywhere. (Dominique Pelle, closes #6075) --- src/testdir/test_signals.vim | 2 -- src/version.c | 2 ++ 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/testdir/test_signals.vim b/src/testdir/test_signals.vim index cb84f5e1aa..0008e31fb7 100644 --- a/src/testdir/test_signals.vim +++ b/src/testdir/test_signals.vim @@ -136,8 +136,6 @@ func Test_deadly_signal_TERM() call assert_false(filereadable('Xsig_TERM')) exe 'silent !kill -s TERM ' .. pid_vim - call WaitForAssert({-> assert_equal('Vim: Caught deadly signal TERM', term_getline(buf, 1))}) - call WaitForAssert({-> assert_match('Vim: preserving files\.\.\.$', term_getline(buf, 2))}) call WaitForAssert({-> assert_true(filereadable('.Xsig_TERM.swp'))}) " Don't call StopVimInTerminal() as it expects job to be still running. diff --git a/src/version.c b/src/version.c index 7881e3211e..dae9357179 100644 --- a/src/version.c +++ b/src/version.c @@ -746,6 +746,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 749, /**/ 748, /**/ From 37d1b4f9416973abe9f5a7c6b81540ca88fa8489 Mon Sep 17 00:00:00 2001 From: Bram Moolenaar <Bram@vim.org> Date: Wed, 13 May 2020 17:16:04 +0200 Subject: [PATCH 147/230] patch 8.2.0750: netbeans test is a bit flaky Problem: Netbeans test is a bit flaky. Solution: Allow for standard sign to be defined. Use WaitForAssert(). --- src/testdir/test_netbeans.vim | 9 ++++----- src/version.c | 2 ++ 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/src/testdir/test_netbeans.vim b/src/testdir/test_netbeans.vim index a0606fcf06..7f1dab46dd 100644 --- a/src/testdir/test_netbeans.vim +++ b/src/testdir/test_netbeans.vim @@ -339,8 +339,8 @@ func Nb_basic(port) let l = readfile('Xnetbeans') call assert_equal('send: 2:defineAnnoType!60 1 "s1" "x" "=>" blue none', l[-1]) sleep 1m - call assert_equal([{'name': '1', 'texthl': 'NB_s1', 'text': '=>'}], - \ sign_getdefined()) + call assert_equal({'name': '1', 'texthl': 'NB_s1', 'text': '=>'}, + \ sign_getdefined()[0]) let g:last += 3 " defineAnnoType with a long color name @@ -610,10 +610,9 @@ func Nb_basic(port) " detach call appendbufline(cmdbufnr, '$', 'detach_Test') call WaitFor('len(readfile("Xnetbeans")) >= (g:last + 6)') - let l = readfile('Xnetbeans') - call assert_equal('0:disconnect=91', l[-1]) + call WaitForAssert({-> assert_equal('0:disconnect=91', readfile("Xnetbeans")[-1])}) - " close the connection + " the connection was closed call assert_false(has("netbeans_enabled")) call delete("Xnetbeans") diff --git a/src/version.c b/src/version.c index dae9357179..e78145ea7b 100644 --- a/src/version.c +++ b/src/version.c @@ -746,6 +746,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 750, /**/ 749, /**/ From 7e9f351b2e69b498c4ee5004d7459844e1ba191a Mon Sep 17 00:00:00 2001 From: Bram Moolenaar <Bram@vim.org> Date: Wed, 13 May 2020 22:44:22 +0200 Subject: [PATCH 148/230] patch 8.2.0751: Vim9: performance can be improved Problem: Vim9: performance can be improved. Solution: Don't call break. Inline check for list materialize. Make an inline version of ga_grow(). --- src/channel.c | 6 +++--- src/eval.c | 2 +- src/evalbuffer.c | 2 +- src/evalfunc.c | 42 ++++++++++++++++++++---------------------- src/evalvars.c | 2 +- src/filepath.c | 2 +- src/highlight.c | 2 +- src/if_py_both.h | 8 ++++---- src/insexpand.c | 4 ++-- src/json.c | 2 +- src/list.c | 34 +++++++++++++++++----------------- src/macros.h | 6 ++++++ src/misc2.c | 41 +++++++++++++++++++++++------------------ src/popupmenu.c | 2 +- src/popupwin.c | 10 +++++----- src/proto/misc2.pro | 1 + src/userfunc.c | 2 +- 17 files changed, 89 insertions(+), 79 deletions(-) diff --git a/src/channel.c b/src/channel.c index 1fcb8451cb..68adbc3782 100644 --- a/src/channel.c +++ b/src/channel.c @@ -2399,7 +2399,7 @@ channel_get_json( list_T *l = item->jq_value->vval.v_list; typval_T *tv; - range_list_materialize(l); + CHECK_LIST_MATERIALIZE(l); tv = &l->lv_first->li_tv; if ((without_callback || !item->jq_no_callback) @@ -5302,7 +5302,7 @@ get_job_options(typval_T *tv, jobopt_T *opt, int supported, int supported2) return FAIL; } - range_list_materialize(item->vval.v_list); + CHECK_LIST_MATERIALIZE(item->vval.v_list); li = item->vval.v_list->lv_first; for (; li != NULL && n < 16; li = li->li_next, n++) { @@ -5729,7 +5729,7 @@ win32_build_cmd(list_T *l, garray_T *gap) listitem_T *li; char_u *s; - range_list_materialize(l); + CHECK_LIST_MATERIALIZE(l); FOR_ALL_LIST_ITEMS(l, li) { s = tv_get_string_chk(&li->li_tv); diff --git a/src/eval.c b/src/eval.c index b7003a882c..2100d8039f 100644 --- a/src/eval.c +++ b/src/eval.c @@ -1449,7 +1449,7 @@ eval_for_line( else { // Need a real list here. - range_list_materialize(l); + CHECK_LIST_MATERIALIZE(l); // No need to increment the refcount, it's already set for // the list being used in "tv". diff --git a/src/evalbuffer.c b/src/evalbuffer.c index f11727c787..adbbca3f7b 100644 --- a/src/evalbuffer.c +++ b/src/evalbuffer.c @@ -183,7 +183,7 @@ set_buffer_lines( rettv->vval.v_number = 1; // FAIL goto done; } - range_list_materialize(l); + CHECK_LIST_MATERIALIZE(l); li = l->lv_first; } else diff --git a/src/evalfunc.c b/src/evalfunc.c index c499890d9b..7579208359 100644 --- a/src/evalfunc.c +++ b/src/evalfunc.c @@ -2275,7 +2275,7 @@ execute_common(typval_T *argvars, typval_T *rettv, int arg_off) { listitem_T *item; - range_list_materialize(list); + CHECK_LIST_MATERIALIZE(list); item = list->lv_first; do_cmdline(NULL, get_list_line, (void *)&item, DOCMD_NOWAIT|DOCMD_VERBOSE|DOCMD_REPEAT|DOCMD_KEYTYPED); @@ -2820,7 +2820,7 @@ common_function(typval_T *argvars, typval_T *rettv, int is_funcref) copy_tv(&arg_pt->pt_argv[i], &pt->pt_argv[i]); if (lv_len > 0) { - range_list_materialize(list); + CHECK_LIST_MATERIALIZE(list); FOR_ALL_LIST_ITEMS(list, li) copy_tv(&li->li_tv, &pt->pt_argv[i++]); } @@ -4912,7 +4912,7 @@ f_index(typval_T *argvars, typval_T *rettv) l = argvars[0].vval.v_list; if (l != NULL) { - range_list_materialize(l); + CHECK_LIST_MATERIALIZE(l); item = l->lv_first; if (argvars[2].v_type != VAR_UNKNOWN) { @@ -5018,7 +5018,7 @@ f_inputlist(typval_T *argvars, typval_T *rettv) msg_clr_eos(); l = argvars[0].vval.v_list; - range_list_materialize(l); + CHECK_LIST_MATERIALIZE(l); FOR_ALL_LIST_ITEMS(l, li) { msg_puts((char *)tv_get_string(&li->li_tv)); @@ -5494,7 +5494,7 @@ find_some_match(typval_T *argvars, typval_T *rettv, matchtype_T type) { if ((l = argvars[0].vval.v_list) == NULL) goto theend; - range_list_materialize(l); + CHECK_LIST_MATERIALIZE(l); li = l->lv_first; } else @@ -6279,7 +6279,7 @@ f_range(typval_T *argvars, typval_T *rettv) list_T *list = rettv->vval.v_list; // Create a non-materialized list. This is much more efficient and - // works with ":for". If used otherwise range_list_materialize() must + // works with ":for". If used otherwise CHECK_LIST_MATERIALIZE() must // be called. list->lv_first = &range_list_item; list->lv_u.nonmat.lv_start = start; @@ -6290,26 +6290,24 @@ f_range(typval_T *argvars, typval_T *rettv) } /* - * If "list" is a non-materialized list then materialize it now. + * Materialize "list". + * Do not call directly, use CHECK_LIST_MATERIALIZE() */ void range_list_materialize(list_T *list) { - if (list->lv_first == &range_list_item) - { - varnumber_T start = list->lv_u.nonmat.lv_start; - varnumber_T end = list->lv_u.nonmat.lv_end; - int stride = list->lv_u.nonmat.lv_stride; - varnumber_T i; + varnumber_T start = list->lv_u.nonmat.lv_start; + varnumber_T end = list->lv_u.nonmat.lv_end; + int stride = list->lv_u.nonmat.lv_stride; + varnumber_T i; - list->lv_first = NULL; - list->lv_u.mat.lv_last = NULL; - list->lv_len = 0; - list->lv_u.mat.lv_idx_item = NULL; - for (i = start; stride > 0 ? i <= end : i >= end; i += stride) - if (list_append_number(list, (varnumber_T)i) == FAIL) - break; - } + list->lv_first = NULL; + list->lv_u.mat.lv_last = NULL; + list->lv_len = 0; + list->lv_u.mat.lv_idx_item = NULL; + for (i = start; stride > 0 ? i <= end : i >= end; i += stride) + if (list_append_number(list, (varnumber_T)i) == FAIL) + break; } static void @@ -7327,7 +7325,7 @@ f_setreg(typval_T *argvars, typval_T *rettv) if (ll != NULL) { - range_list_materialize(ll); + CHECK_LIST_MATERIALIZE(ll); FOR_ALL_LIST_ITEMS(ll, li) { strval = tv_get_string_buf_chk(&li->li_tv, buf); diff --git a/src/evalvars.c b/src/evalvars.c index 01aef1ae69..e747230033 100644 --- a/src/evalvars.c +++ b/src/evalvars.c @@ -863,7 +863,7 @@ ex_let_vars( return FAIL; } - range_list_materialize(l); + CHECK_LIST_MATERIALIZE(l); item = l->lv_first; while (*arg != ']') { diff --git a/src/filepath.c b/src/filepath.c index 81f90c3392..27a26e5edc 100644 --- a/src/filepath.c +++ b/src/filepath.c @@ -1917,7 +1917,7 @@ f_writefile(typval_T *argvars, typval_T *rettv) list = argvars[0].vval.v_list; if (list == NULL) return; - range_list_materialize(list); + CHECK_LIST_MATERIALIZE(list); FOR_ALL_LIST_ITEMS(list, li) if (tv_get_string_chk(&li->li_tv) == NULL) return; diff --git a/src/highlight.c b/src/highlight.c index 64f37a4e8d..7a7e537f38 100644 --- a/src/highlight.c +++ b/src/highlight.c @@ -3743,7 +3743,7 @@ match_add( listitem_T *li; int i; - range_list_materialize(pos_list); + CHECK_LIST_MATERIALIZE(pos_list); for (i = 0, li = pos_list->lv_first; li != NULL && i < MAXPOSMATCH; i++, li = li->li_next) { diff --git a/src/if_py_both.h b/src/if_py_both.h index a13a5e345a..9f563f0afd 100644 --- a/src/if_py_both.h +++ b/src/if_py_both.h @@ -785,7 +785,7 @@ VimToPython(typval_T *our_tv, int depth, PyObject *lookup_dict) return NULL; } - range_list_materialize(list); + CHECK_LIST_MATERIALIZE(list); FOR_ALL_LIST_ITEMS(list, curr) { if (!(newObj = VimToPython(&curr->li_tv, depth + 1, lookup_dict))) @@ -2256,7 +2256,7 @@ ListNew(PyTypeObject *subtype, list_T *list) return NULL; self->list = list; ++list->lv_refcount; - range_list_materialize(list); + CHECK_LIST_MATERIALIZE(list); pyll_add((PyObject *)(self), &self->ref, &lastlist); @@ -2824,7 +2824,7 @@ ListIter(ListObject *self) return NULL; } - range_list_materialize(l); + CHECK_LIST_MATERIALIZE(l); list_add_watch(l, &lii->lw); lii->lw.lw_item = l->lv_first; lii->list = l; @@ -3021,7 +3021,7 @@ FunctionConstructor(PyTypeObject *subtype, PyObject *args, PyObject *kwargs) return NULL; } argslist = argstv.vval.v_list; - range_list_materialize(argslist); + CHECK_LIST_MATERIALIZE(argslist); argc = argslist->lv_len; if (argc != 0) diff --git a/src/insexpand.c b/src/insexpand.c index bd809b0e6f..6963baf987 100644 --- a/src/insexpand.c +++ b/src/insexpand.c @@ -2334,7 +2334,7 @@ ins_compl_add_list(list_T *list) int dir = compl_direction; // Go through the List with matches and add each of them. - range_list_materialize(list); + CHECK_LIST_MATERIALIZE(list); FOR_ALL_LIST_ITEMS(list, li) { if (ins_compl_add_tv(&li->li_tv, dir) == OK) @@ -2519,7 +2519,7 @@ get_complete_info(list_T *what_list, dict_T *retdict) else { what_flag = 0; - range_list_materialize(what_list); + CHECK_LIST_MATERIALIZE(what_list); FOR_ALL_LIST_ITEMS(what_list, item) { char_u *what = tv_get_string(&item->li_tv); diff --git a/src/json.c b/src/json.c index c1c6e85638..ec3355e714 100644 --- a/src/json.c +++ b/src/json.c @@ -265,7 +265,7 @@ json_encode_item(garray_T *gap, typval_T *val, int copyID, int options) l->lv_copyID = copyID; ga_append(gap, '['); - range_list_materialize(l); + CHECK_LIST_MATERIALIZE(l); for (li = l->lv_first; li != NULL && !got_int; ) { if (json_encode_item(gap, &li->li_tv, copyID, diff --git a/src/list.c b/src/list.c index eb76cc6831..6242e52438 100644 --- a/src/list.c +++ b/src/list.c @@ -378,8 +378,8 @@ list_equal( if (l1 == NULL || l2 == NULL) return FALSE; - range_list_materialize(l1); - range_list_materialize(l2); + CHECK_LIST_MATERIALIZE(l1); + CHECK_LIST_MATERIALIZE(l2); for (item1 = l1->lv_first, item2 = l2->lv_first; item1 != NULL && item2 != NULL; @@ -411,7 +411,7 @@ list_find(list_T *l, long n) if (n < 0 || n >= l->lv_len) return NULL; - range_list_materialize(l); + CHECK_LIST_MATERIALIZE(l); // When there is a cached index may start search from there. if (l->lv_u.mat.lv_idx_item != NULL) @@ -541,7 +541,7 @@ list_idx_of_item(list_T *l, listitem_T *item) if (l == NULL) return -1; - range_list_materialize(l); + CHECK_LIST_MATERIALIZE(l); idx = 0; for (li = l->lv_first; li != NULL && li != item; li = li->li_next) ++idx; @@ -556,7 +556,7 @@ list_idx_of_item(list_T *l, listitem_T *item) void list_append(list_T *l, listitem_T *item) { - range_list_materialize(l); + CHECK_LIST_MATERIALIZE(l); if (l->lv_u.mat.lv_last == NULL) { // empty list @@ -706,7 +706,7 @@ list_insert_tv(list_T *l, typval_T *tv, listitem_T *item) void list_insert(list_T *l, listitem_T *ni, listitem_T *item) { - range_list_materialize(l); + CHECK_LIST_MATERIALIZE(l); if (item == NULL) // Append new item at end of list. list_append(l, ni); @@ -741,8 +741,8 @@ list_extend(list_T *l1, list_T *l2, listitem_T *bef) listitem_T *item; int todo = l2->lv_len; - range_list_materialize(l1); - range_list_materialize(l2); + CHECK_LIST_MATERIALIZE(l1); + CHECK_LIST_MATERIALIZE(l2); // We also quit the loop when we have inserted the original item count of // the list, avoid a hang when we extend a list with itself. @@ -801,7 +801,7 @@ list_copy(list_T *orig, int deep, int copyID) orig->lv_copyID = copyID; orig->lv_copylist = copy; } - range_list_materialize(orig); + CHECK_LIST_MATERIALIZE(orig); for (item = orig->lv_first; item != NULL && !got_int; item = item->li_next) { @@ -842,7 +842,7 @@ vimlist_remove(list_T *l, listitem_T *item, listitem_T *item2) { listitem_T *ip; - range_list_materialize(l); + CHECK_LIST_MATERIALIZE(l); // notify watchers for (ip = item; ip != NULL; ip = ip->li_next) @@ -877,7 +877,7 @@ list2string(typval_T *tv, int copyID, int restore_copyID) return NULL; ga_init2(&ga, (int)sizeof(char), 80); ga_append(&ga, '['); - range_list_materialize(tv->vval.v_list); + CHECK_LIST_MATERIALIZE(tv->vval.v_list); if (list_join(&ga, tv->vval.v_list, (char_u *)", ", FALSE, restore_copyID, copyID) == FAIL) { @@ -915,7 +915,7 @@ list_join_inner( char_u *s; // Stringify each item in the list. - range_list_materialize(l); + CHECK_LIST_MATERIALIZE(l); for (item = l->lv_first; item != NULL && !got_int; item = item->li_next) { s = echo_string_core(&item->li_tv, &tofree, numbuf, copyID, @@ -1116,7 +1116,7 @@ write_list(FILE *fd, list_T *list, int binary) int ret = OK; char_u *s; - range_list_materialize(list); + CHECK_LIST_MATERIALIZE(list); FOR_ALL_LIST_ITEMS(list, li) { for (s = tv_get_string(&li->li_tv); *s != NUL; ++s) @@ -1203,7 +1203,7 @@ f_list2str(typval_T *argvars, typval_T *rettv) if (argvars[1].v_type != VAR_UNKNOWN) utf8 = (int)tv_get_number_chk(&argvars[1], NULL); - range_list_materialize(l); + CHECK_LIST_MATERIALIZE(l); ga_init2(&ga, 1, 80); if (has_mbyte || utf8) { @@ -1496,7 +1496,7 @@ do_sort_uniq(typval_T *argvars, typval_T *rettv, int sort) TRUE)) goto theend; rettv_list_set(rettv, l); - range_list_materialize(l); + CHECK_LIST_MATERIALIZE(l); len = list_len(l); if (len <= 1) @@ -1873,7 +1873,7 @@ filter_map(typval_T *argvars, typval_T *rettv, int map) // set_vim_var_nr() doesn't set the type set_vim_var_type(VV_KEY, VAR_NUMBER); - range_list_materialize(l); + CHECK_LIST_MATERIALIZE(l); if (map && l->lv_lock == 0) l->lv_lock = VAR_LOCKED; for (li = l->lv_first; li != NULL; li = nli) @@ -2011,7 +2011,7 @@ f_count(typval_T *argvars, typval_T *rettv) if ((l = argvars[0].vval.v_list) != NULL) { - range_list_materialize(l); + CHECK_LIST_MATERIALIZE(l); li = l->lv_first; if (argvars[2].v_type != VAR_UNKNOWN) { diff --git a/src/macros.h b/src/macros.h index 9a3d4e13cf..2ac705d4a1 100644 --- a/src/macros.h +++ b/src/macros.h @@ -373,3 +373,9 @@ # define ESTACK_CHECK_NOW # define CHECK_CURBUF #endif + +// Inline the condition for performance. +#define CHECK_LIST_MATERIALIZE(l) if ((l)->lv_first == &range_list_item) range_list_materialize(l) + +// Inlined version of ga_grow(). Especially useful if "n" is a constant. +#define GA_GROW(gap, n) (((gap)->ga_maxlen - (gap)->ga_len < n) ? ga_grow_inner((gap), (n)) : OK) diff --git a/src/misc2.c b/src/misc2.c index 50efde7f7b..678b73c009 100644 --- a/src/misc2.c +++ b/src/misc2.c @@ -2053,31 +2053,36 @@ ga_init2(garray_T *gap, int itemsize, int growsize) */ int ga_grow(garray_T *gap, int n) +{ + if (gap->ga_maxlen - gap->ga_len < n) + return ga_grow_inner(gap, n); + return OK; +} + + int +ga_grow_inner(garray_T *gap, int n) { size_t old_len; size_t new_len; char_u *pp; - if (gap->ga_maxlen - gap->ga_len < n) - { - if (n < gap->ga_growsize) - n = gap->ga_growsize; + if (n < gap->ga_growsize) + n = gap->ga_growsize; - // A linear growth is very inefficient when the array grows big. This - // is a compromise between allocating memory that won't be used and too - // many copy operations. A factor of 1.5 seems reasonable. - if (n < gap->ga_len / 2) - n = gap->ga_len / 2; + // A linear growth is very inefficient when the array grows big. This + // is a compromise between allocating memory that won't be used and too + // many copy operations. A factor of 1.5 seems reasonable. + if (n < gap->ga_len / 2) + n = gap->ga_len / 2; - new_len = gap->ga_itemsize * (gap->ga_len + n); - pp = vim_realloc(gap->ga_data, new_len); - if (pp == NULL) - return FAIL; - old_len = gap->ga_itemsize * gap->ga_maxlen; - vim_memset(pp + old_len, 0, new_len - old_len); - gap->ga_maxlen = gap->ga_len + n; - gap->ga_data = pp; - } + new_len = gap->ga_itemsize * (gap->ga_len + n); + pp = vim_realloc(gap->ga_data, new_len); + if (pp == NULL) + return FAIL; + old_len = gap->ga_itemsize * gap->ga_maxlen; + vim_memset(pp + old_len, 0, new_len - old_len); + gap->ga_maxlen = gap->ga_len + n; + gap->ga_data = pp; return OK; } diff --git a/src/popupmenu.c b/src/popupmenu.c index d6993dc433..2fe4cff402 100644 --- a/src/popupmenu.c +++ b/src/popupmenu.c @@ -1318,7 +1318,7 @@ ui_post_balloon(char_u *mesg, list_T *list) balloon_array = ALLOC_CLEAR_MULT(pumitem_T, list->lv_len); if (balloon_array == NULL) return; - range_list_materialize(list); + CHECK_LIST_MATERIALIZE(list); for (idx = 0, li = list->lv_first; li != NULL; li = li->li_next, ++idx) { char_u *text = tv_get_string_chk(&li->li_tv); diff --git a/src/popupwin.c b/src/popupwin.c index a244c32368..4ee097a066 100644 --- a/src/popupwin.c +++ b/src/popupwin.c @@ -98,7 +98,7 @@ set_padding_border(dict_T *dict, int *array, char *name, int max_val) array[i] = 1; if (list != NULL) { - range_list_materialize(list); + CHECK_LIST_MATERIALIZE(list); for (i = 0, li = list->lv_first; i < 4 && i < list->lv_len; ++i, li = li->li_next) { @@ -516,7 +516,7 @@ handle_moved_argument(win_T *wp, dictitem_T *di, int mousemoved) int mincol; int maxcol; - range_list_materialize(l); + CHECK_LIST_MATERIALIZE(l); li = l->lv_first; if (l->lv_len == 3) { @@ -756,7 +756,7 @@ apply_general_options(win_T *wp, dict_T *dict) listitem_T *li; int i; - range_list_materialize(list); + CHECK_LIST_MATERIALIZE(list); for (i = 0, li = list->lv_first; i < 4 && i < list->lv_len; ++i, li = li->li_next) { @@ -790,7 +790,7 @@ apply_general_options(win_T *wp, dict_T *dict) if (list != NULL) { - range_list_materialize(list); + CHECK_LIST_MATERIALIZE(list); for (i = 0, li = list->lv_first; i < 8 && i < list->lv_len; ++i, li = li->li_next) { @@ -845,7 +845,7 @@ apply_general_options(win_T *wp, dict_T *dict) break; } else - range_list_materialize(li->li_tv.vval.v_list); + CHECK_LIST_MATERIALIZE(li->li_tv.vval.v_list); } } if (ok) diff --git a/src/proto/misc2.pro b/src/proto/misc2.pro index 6c047f332d..592c7d19fd 100644 --- a/src/proto/misc2.pro +++ b/src/proto/misc2.pro @@ -59,6 +59,7 @@ void ga_clear_strings(garray_T *gap); void ga_init(garray_T *gap); void ga_init2(garray_T *gap, int itemsize, int growsize); int ga_grow(garray_T *gap, int n); +int ga_grow_inner(garray_T *gap, int n); char_u *ga_concat_strings(garray_T *gap, char *sep); void ga_add_string(garray_T *gap, char_u *p); void ga_concat(garray_T *gap, char_u *s); diff --git a/src/userfunc.c b/src/userfunc.c index b33aee7741..5a64ccb75f 100644 --- a/src/userfunc.c +++ b/src/userfunc.c @@ -1718,7 +1718,7 @@ func_call( int argc = 0; int r = 0; - range_list_materialize(l); + CHECK_LIST_MATERIALIZE(l); FOR_ALL_LIST_ITEMS(l, item) { if (argc == MAX_FUNC_ARGS - (partial == NULL ? 0 : partial->pt_argc)) From 2b72821924ff514727b60fb0b647d5caae8336f7 Mon Sep 17 00:00:00 2001 From: Bram Moolenaar <Bram@vim.org> Date: Wed, 13 May 2020 23:21:55 +0200 Subject: [PATCH 149/230] Update version.c for missing patch number --- src/version.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/version.c b/src/version.c index e78145ea7b..0d0af788ff 100644 --- a/src/version.c +++ b/src/version.c @@ -746,6 +746,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 751, /**/ 750, /**/ From e06a28f5e30f439545ac125d54ffc4e6bd6daada Mon Sep 17 00:00:00 2001 From: Bram Moolenaar <Bram@vim.org> Date: Wed, 13 May 2020 23:24:12 +0200 Subject: [PATCH 150/230] patch 8.2.0752: terminal in popup window test is a bit flaky Problem: Terminal in popup window test is a bit flaky. Solution: Wait for shell job status to be "run". Mark as flaky test. --- src/testdir/test_popupwin.vim | 5 ++++- src/version.c | 2 ++ 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/src/testdir/test_popupwin.vim b/src/testdir/test_popupwin.vim index a664346df5..feaa5e4c0d 100644 --- a/src/testdir/test_popupwin.vim +++ b/src/testdir/test_popupwin.vim @@ -2422,12 +2422,15 @@ endfunc func Test_popupwin_terminal_buffer() CheckFeature terminal CheckUnix + " Starting a terminal to run a shell in is considered flaky. + let g:test_is_flaky = 1 let origwin = win_getid() let ptybuf = term_start(&shell, #{hidden: 1}) let winid = popup_create(ptybuf, #{minwidth: 40, minheight: 10}) " Wait for shell to start - sleep 200m + call WaitForAssert({-> assert_equal("run", job_status(term_getjob(ptybuf)))}) + sleep 100m " Check this doesn't crash call assert_equal(winnr(), winnr('j')) call assert_equal(winnr(), winnr('k')) diff --git a/src/version.c b/src/version.c index 0d0af788ff..3f67db4511 100644 --- a/src/version.c +++ b/src/version.c @@ -746,6 +746,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 752, /**/ 751, /**/ From 32e351179eacfc84f64cd5029e221582d400bb38 Mon Sep 17 00:00:00 2001 From: Bram Moolenaar <Bram@vim.org> Date: Thu, 14 May 2020 22:41:15 +0200 Subject: [PATCH 151/230] patch 8.2.0753: Vim9: expressions are evaluated in the discovery phase Problem: Vim9: expressions are evaluated in the discovery phase. Solution: Bail out if an expression is not a constant. Require a type for declared constants. --- src/dict.c | 12 ++- src/eval.c | 145 ++++++++++++++------------ src/evalfunc.c | 2 +- src/evalvars.c | 84 +++++++++------ src/ex_eval.c | 3 +- src/list.c | 5 +- src/testdir/test_vim9_disassemble.vim | 2 +- src/testdir/test_vim9_script.vim | 60 ++++++++--- src/userfunc.c | 18 ++-- src/version.c | 2 + src/vim.h | 6 +- src/vim9compile.c | 6 +- 12 files changed, 214 insertions(+), 131 deletions(-) diff --git a/src/dict.c b/src/dict.c index 54d3110b02..3824f407cb 100644 --- a/src/dict.c +++ b/src/dict.c @@ -791,8 +791,9 @@ get_literal_key(char_u **arg, typval_T *tv) * Return OK or FAIL. Returns NOTDONE for {expr}. */ int -eval_dict(char_u **arg, typval_T *rettv, int evaluate, int literal) +eval_dict(char_u **arg, typval_T *rettv, int flags, int literal) { + int evaluate = flags & EVAL_EVALUATE; dict_T *d = NULL; typval_T tvkey; typval_T tv; @@ -800,6 +801,7 @@ eval_dict(char_u **arg, typval_T *rettv, int evaluate, int literal) dictitem_T *item; char_u *start = skipwhite(*arg + 1); char_u buf[NUMBUFLEN]; + int vim9script = current_sctx.sc_version == SCRIPT_VERSION_VIM9; /* * First check if it's not a curly-braces thing: {expr}. @@ -808,9 +810,9 @@ eval_dict(char_u **arg, typval_T *rettv, int evaluate, int literal) * first item. * But {} is an empty Dictionary. */ - if (*start != '}') + if (!vim9script && *start != '}') { - if (eval1(&start, &tv, FALSE) == FAIL) // recursive! + if (eval1(&start, &tv, 0) == FAIL) // recursive! return FAIL; if (*start == '}') return NOTDONE; @@ -830,7 +832,7 @@ eval_dict(char_u **arg, typval_T *rettv, int evaluate, int literal) { if ((literal ? get_literal_key(arg, &tvkey) - : eval1(arg, &tvkey, evaluate)) == FAIL) // recursive! + : eval1(arg, &tvkey, flags)) == FAIL) // recursive! goto failret; if (**arg != ':') @@ -852,7 +854,7 @@ eval_dict(char_u **arg, typval_T *rettv, int evaluate, int literal) } *arg = skipwhite(*arg + 1); - if (eval1(arg, &tv, evaluate) == FAIL) // recursive! + if (eval1(arg, &tv, flags) == FAIL) // recursive! { if (evaluate) clear_tv(&tvkey); diff --git a/src/eval.c b/src/eval.c index 2100d8039f..b3fe650ee8 100644 --- a/src/eval.c +++ b/src/eval.c @@ -48,12 +48,12 @@ typedef struct } forinfo_T; static int tv_op(typval_T *tv1, typval_T *tv2, char_u *op); -static int eval2(char_u **arg, typval_T *rettv, int evaluate); -static int eval3(char_u **arg, typval_T *rettv, int evaluate); -static int eval4(char_u **arg, typval_T *rettv, int evaluate); -static int eval5(char_u **arg, typval_T *rettv, int evaluate); -static int eval6(char_u **arg, typval_T *rettv, int evaluate, int want_string); -static int eval7(char_u **arg, typval_T *rettv, int evaluate, int want_string); +static int eval2(char_u **arg, typval_T *rettv, int flags); +static int eval3(char_u **arg, typval_T *rettv, int flags); +static int eval4(char_u **arg, typval_T *rettv, int flags); +static int eval5(char_u **arg, typval_T *rettv, int flags); +static int eval6(char_u **arg, typval_T *rettv, int flags, int want_string); +static int eval7(char_u **arg, typval_T *rettv, int flags, int want_string); static int eval7_leader(typval_T *rettv, char_u *start_leader, char_u **end_leaderp); static int free_unref_items(int copyID); @@ -173,7 +173,7 @@ eval_to_bool( if (skip) ++emsg_skip; - if (eval0(arg, &tv, nextcmd, !skip) == FAIL) + if (eval0(arg, &tv, nextcmd, skip ? 0 : EVAL_EVALUATE) == FAIL) *error = TRUE; else { @@ -201,7 +201,7 @@ eval1_emsg(char_u **arg, typval_T *rettv, int evaluate) int did_emsg_before = did_emsg; int called_emsg_before = called_emsg; - ret = eval1(arg, rettv, evaluate); + ret = eval1(arg, rettv, evaluate ? EVAL_EVALUATE : 0); if (ret == FAIL) { // Report the invalid expression unless the expression evaluation has @@ -315,7 +315,7 @@ eval_to_string_skip( if (skip) ++emsg_skip; - if (eval0(arg, &tv, nextcmd, !skip) == FAIL || skip) + if (eval0(arg, &tv, nextcmd, skip ? 0 : EVAL_EVALUATE) == FAIL || skip) retval = NULL; else { @@ -338,7 +338,7 @@ skip_expr(char_u **pp) typval_T rettv; *pp = skipwhite(*pp); - return eval1(pp, &rettv, FALSE); + return eval1(pp, &rettv, 0); } /* @@ -360,7 +360,7 @@ eval_to_string( char_u numbuf[NUMBUFLEN]; #endif - if (eval0(arg, &tv, nextcmd, TRUE) == FAIL) + if (eval0(arg, &tv, nextcmd, EVAL_EVALUATE) == FAIL) retval = NULL; else { @@ -430,7 +430,7 @@ eval_to_number(char_u *expr) ++emsg_off; - if (eval1(&p, &rettv, TRUE) == FAIL) + if (eval1(&p, &rettv, EVAL_EVALUATE) == FAIL) retval = -1; else { @@ -453,7 +453,7 @@ eval_expr(char_u *arg, char_u **nextcmd) typval_T *tv; tv = ALLOC_ONE(typval_T); - if (tv != NULL && eval0(arg, tv, nextcmd, TRUE) == FAIL) + if (tv != NULL && eval0(arg, tv, nextcmd, EVAL_EVALUATE) == FAIL) VIM_CLEAR(tv); return tv; @@ -578,7 +578,7 @@ eval_foldexpr(char_u *arg, int *cp) ++sandbox; ++textwinlock; *cp = NUL; - if (eval0(arg, &tv, NULL, TRUE) == FAIL) + if (eval0(arg, &tv, NULL, EVAL_EVALUATE) == FAIL) retval = 0; else { @@ -766,7 +766,7 @@ get_lval( else { empty1 = FALSE; - if (eval1(&p, &var1, TRUE) == FAIL) // recursive! + if (eval1(&p, &var1, EVAL_EVALUATE) == FAIL) // recursive! return NULL; if (tv_get_string_chk(&var1) == NULL) { @@ -803,7 +803,8 @@ get_lval( else { lp->ll_empty2 = FALSE; - if (eval1(&p, &var2, TRUE) == FAIL) // recursive! + // recursive! + if (eval1(&p, &var2, EVAL_EVALUATE) == FAIL) { clear_tv(&var1); return NULL; @@ -1433,7 +1434,8 @@ eval_for_line( if (skip) ++emsg_skip; - if (eval0(skipwhite(expr + 2), &tv, nextcmdp, !skip) == OK) + if (eval0(skipwhite(expr + 2), &tv, nextcmdp, skip ? 0 : EVAL_EVALUATE) + == OK) { *errp = FALSE; if (!skip) @@ -1694,9 +1696,10 @@ eval_func( char_u *name, int name_len, typval_T *rettv, - int evaluate, + int flags, typval_T *basetv) // "expr" for "expr->name(arg)" { + int evaluate = flags & EVAL_EVALUATE; char_u *s = name; int len = name_len; partial_T *partial; @@ -1712,7 +1715,7 @@ eval_func( // Need to make a copy, in case evaluating the arguments makes // the name invalid. s = vim_strsave(s); - if (s == NULL) + if (s == NULL || (flags & EVAL_CONSTANT)) ret = FAIL; else { @@ -1761,6 +1764,7 @@ eval_func( * This calls eval1() and handles error message and nextcmd. * Put the result in "rettv" when returning OK and "evaluate" is TRUE. * Note: "rettv.v_lock" is not set. + * "flags" has EVAL_EVALUATE and similar flags. * Return OK or FAIL. */ int @@ -1768,7 +1772,7 @@ eval0( char_u *arg, typval_T *rettv, char_u **nextcmd, - int evaluate) + int flags) { int ret; char_u *p; @@ -1776,7 +1780,7 @@ eval0( int called_emsg_before = called_emsg; p = skipwhite(arg); - ret = eval1(&p, rettv, evaluate); + ret = eval1(&p, rettv, flags); if (ret == FAIL || !ends_excmd2(arg, p)) { if (ret != FAIL) @@ -1787,8 +1791,10 @@ eval0( * exception, or we already gave a more specific error. * Also check called_emsg for when using assert_fails(). */ - if (!aborting() && did_emsg == did_emsg_before - && called_emsg == called_emsg_before) + if (!aborting() + && did_emsg == did_emsg_before + && called_emsg == called_emsg_before + && (flags & EVAL_CONSTANT) == 0) semsg(_(e_invexpr2), arg); ret = FAIL; } @@ -1810,7 +1816,7 @@ eval0( * Return OK or FAIL. */ int -eval1(char_u **arg, typval_T *rettv, int evaluate) +eval1(char_u **arg, typval_T *rettv, int flags) { int result; typval_T var2; @@ -1818,13 +1824,15 @@ eval1(char_u **arg, typval_T *rettv, int evaluate) /* * Get the first variable. */ - if (eval2(arg, rettv, evaluate) == FAIL) + if (eval2(arg, rettv, flags) == FAIL) return FAIL; if ((*arg)[0] == '?') { + int evaluate = flags & EVAL_EVALUATE; + result = FALSE; - if (evaluate) + if (flags & EVAL_EVALUATE) { int error = FALSE; @@ -1836,10 +1844,10 @@ eval1(char_u **arg, typval_T *rettv, int evaluate) } /* - * Get the second variable. + * Get the second variable. Recursive! */ *arg = skipwhite(*arg + 1); - if (eval1(arg, rettv, evaluate && result) == FAIL) // recursive! + if (eval1(arg, rettv, result ? flags : flags & ~EVAL_EVALUATE) == FAIL) return FAIL; /* @@ -1854,10 +1862,10 @@ eval1(char_u **arg, typval_T *rettv, int evaluate) } /* - * Get the third variable. + * Get the third variable. Recursive! */ *arg = skipwhite(*arg + 1); - if (eval1(arg, &var2, evaluate && !result) == FAIL) // recursive! + if (eval1(arg, &var2, !result ? flags : flags & ~EVAL_EVALUATE) == FAIL) { if (evaluate && result) clear_tv(rettv); @@ -1880,7 +1888,7 @@ eval1(char_u **arg, typval_T *rettv, int evaluate) * Return OK or FAIL. */ static int -eval2(char_u **arg, typval_T *rettv, int evaluate) +eval2(char_u **arg, typval_T *rettv, int flags) { typval_T var2; long result; @@ -1890,7 +1898,7 @@ eval2(char_u **arg, typval_T *rettv, int evaluate) /* * Get the first variable. */ - if (eval3(arg, rettv, evaluate) == FAIL) + if (eval3(arg, rettv, flags) == FAIL) return FAIL; /* @@ -1900,6 +1908,8 @@ eval2(char_u **arg, typval_T *rettv, int evaluate) result = FALSE; while ((*arg)[0] == '|' && (*arg)[1] == '|') { + int evaluate = flags & EVAL_EVALUATE; + if (evaluate && first) { if (tv_get_number_chk(rettv, &error) != 0) @@ -1914,7 +1924,8 @@ eval2(char_u **arg, typval_T *rettv, int evaluate) * Get the second variable. */ *arg = skipwhite(*arg + 2); - if (eval3(arg, &var2, evaluate && !result) == FAIL) + if (eval3(arg, &var2, !result ? flags : flags & ~EVAL_EVALUATE) + == FAIL) return FAIL; /* @@ -1948,7 +1959,7 @@ eval2(char_u **arg, typval_T *rettv, int evaluate) * Return OK or FAIL. */ static int -eval3(char_u **arg, typval_T *rettv, int evaluate) +eval3(char_u **arg, typval_T *rettv, int flags) { typval_T var2; long result; @@ -1958,7 +1969,7 @@ eval3(char_u **arg, typval_T *rettv, int evaluate) /* * Get the first variable. */ - if (eval4(arg, rettv, evaluate) == FAIL) + if (eval4(arg, rettv, flags) == FAIL) return FAIL; /* @@ -1968,6 +1979,8 @@ eval3(char_u **arg, typval_T *rettv, int evaluate) result = TRUE; while ((*arg)[0] == '&' && (*arg)[1] == '&') { + int evaluate = flags & EVAL_EVALUATE; + if (evaluate && first) { if (tv_get_number_chk(rettv, &error) == 0) @@ -1982,7 +1995,7 @@ eval3(char_u **arg, typval_T *rettv, int evaluate) * Get the second variable. */ *arg = skipwhite(*arg + 2); - if (eval4(arg, &var2, evaluate && result) == FAIL) + if (eval4(arg, &var2, result ? flags : flags & ~EVAL_EVALUATE) == FAIL) return FAIL; /* @@ -2025,7 +2038,7 @@ eval3(char_u **arg, typval_T *rettv, int evaluate) * Return OK or FAIL. */ static int -eval4(char_u **arg, typval_T *rettv, int evaluate) +eval4(char_u **arg, typval_T *rettv, int flags) { typval_T var2; char_u *p; @@ -2037,7 +2050,7 @@ eval4(char_u **arg, typval_T *rettv, int evaluate) /* * Get the first variable. */ - if (eval5(arg, rettv, evaluate) == FAIL) + if (eval5(arg, rettv, flags) == FAIL) return FAIL; p = *arg; @@ -2105,12 +2118,12 @@ eval4(char_u **arg, typval_T *rettv, int evaluate) * Get the second variable. */ *arg = skipwhite(p + len); - if (eval5(arg, &var2, evaluate) == FAIL) + if (eval5(arg, &var2, flags) == FAIL) { clear_tv(rettv); return FAIL; } - if (evaluate) + if (flags & EVAL_EVALUATE) { int ret = typval_compare(rettv, &var2, type, ic); @@ -2172,7 +2185,7 @@ eval_addlist(typval_T *tv1, typval_T *tv2) * Return OK or FAIL. */ static int -eval5(char_u **arg, typval_T *rettv, int evaluate) +eval5(char_u **arg, typval_T *rettv, int flags) { typval_T var2; int op; @@ -2188,7 +2201,7 @@ eval5(char_u **arg, typval_T *rettv, int evaluate) /* * Get the first variable. */ - if (eval6(arg, rettv, evaluate, FALSE) == FAIL) + if (eval6(arg, rettv, flags, FALSE) == FAIL) return FAIL; /* @@ -2217,7 +2230,7 @@ eval5(char_u **arg, typval_T *rettv, int evaluate) // we know that the first operand needs to be a string or number // without evaluating the 2nd operand. So check before to avoid // side effects after an error. - if (evaluate && tv_get_string_chk(rettv) == NULL) + if ((flags & EVAL_EVALUATE) && tv_get_string_chk(rettv) == NULL) { clear_tv(rettv); return FAIL; @@ -2230,13 +2243,13 @@ eval5(char_u **arg, typval_T *rettv, int evaluate) if (op == '.' && *(*arg + 1) == '.') // .. string concatenation ++*arg; *arg = skipwhite(*arg + 1); - if (eval6(arg, &var2, evaluate, op == '.') == FAIL) + if (eval6(arg, &var2, flags, op == '.') == FAIL) { clear_tv(rettv); return FAIL; } - if (evaluate) + if (flags & EVAL_EVALUATE) { /* * Compute the result. @@ -2358,7 +2371,7 @@ eval5(char_u **arg, typval_T *rettv, int evaluate) eval6( char_u **arg, typval_T *rettv, - int evaluate, + int flags, int want_string) // after "." operator { typval_T var2; @@ -2373,7 +2386,7 @@ eval6( /* * Get the first variable. */ - if (eval7(arg, rettv, evaluate, want_string) == FAIL) + if (eval7(arg, rettv, flags, want_string) == FAIL) return FAIL; /* @@ -2385,7 +2398,7 @@ eval6( if (op != '*' && op != '/' && op != '%') break; - if (evaluate) + if (flags & EVAL_EVALUATE) { #ifdef FEAT_FLOAT if (rettv->v_type == VAR_FLOAT) @@ -2408,10 +2421,10 @@ eval6( * Get the second variable. */ *arg = skipwhite(*arg + 1); - if (eval7(arg, &var2, evaluate, FALSE) == FAIL) + if (eval7(arg, &var2, flags, FALSE) == FAIL) return FAIL; - if (evaluate) + if (flags & EVAL_EVALUATE) { #ifdef FEAT_FLOAT if (var2.v_type == VAR_FLOAT) @@ -2528,9 +2541,10 @@ eval6( eval7( char_u **arg, typval_T *rettv, - int evaluate, + int flags, int want_string) // after "." operator { + int evaluate = flags & EVAL_EVALUATE; int len; char_u *s; char_u *start_leader, *end_leader; @@ -2595,7 +2609,7 @@ eval7( /* * List: [expr, expr] */ - case '[': ret = get_list_tv(arg, rettv, evaluate, TRUE); + case '[': ret = get_list_tv(arg, rettv, flags, TRUE); break; /* @@ -2604,7 +2618,7 @@ eval7( case '#': if ((*arg)[1] == '{') { ++*arg; - ret = eval_dict(arg, rettv, evaluate, TRUE); + ret = eval_dict(arg, rettv, flags, TRUE); } else ret = NOTDONE; @@ -2616,7 +2630,7 @@ eval7( */ case '{': ret = get_lambda_tv(arg, rettv, evaluate); if (ret == NOTDONE) - ret = eval_dict(arg, rettv, evaluate, FALSE); + ret = eval_dict(arg, rettv, flags, FALSE); break; /* @@ -2649,7 +2663,7 @@ eval7( * nested expression: (expression). */ case '(': *arg = skipwhite(*arg + 1); - ret = eval1(arg, rettv, evaluate); // recursive! + ret = eval1(arg, rettv, flags); // recursive! if (**arg == ')') ++*arg; else if (ret == OK) @@ -2680,7 +2694,7 @@ eval7( else { if (**arg == '(') // recursive! - ret = eval_func(arg, s, len, rettv, evaluate, NULL); + ret = eval_func(arg, s, len, rettv, flags, NULL); else if (evaluate) ret = get_var_tv(s, len, rettv, NULL, TRUE, FALSE); else @@ -2697,7 +2711,7 @@ eval7( // Handle following '[', '(' and '.' for expr[expr], expr.name, // expr(expr), expr->name(expr) if (ret == OK) - ret = handle_subscript(arg, rettv, evaluate, TRUE, + ret = handle_subscript(arg, rettv, flags, TRUE, start_leader, &end_leader); /* @@ -2919,7 +2933,8 @@ eval_method( ret = FAIL; } else - ret = eval_func(arg, name, len, rettv, evaluate, &base); + ret = eval_func(arg, name, len, rettv, + evaluate ? EVAL_EVALUATE : 0, &base); } // Clear the funcref afterwards, so that deleting it while @@ -2939,9 +2954,10 @@ eval_method( eval_index( char_u **arg, typval_T *rettv, - int evaluate, + int flags, int verbose) // give error messages { + int evaluate = flags & EVAL_EVALUATE; int empty1 = FALSE, empty2 = FALSE; typval_T var1, var2; long i; @@ -3010,7 +3026,7 @@ eval_index( *arg = skipwhite(*arg + 1); if (**arg == ':') empty1 = TRUE; - else if (eval1(arg, &var1, evaluate) == FAIL) // recursive! + else if (eval1(arg, &var1, flags) == FAIL) // recursive! return FAIL; else if (evaluate && tv_get_string_chk(&var1) == NULL) { @@ -3028,7 +3044,7 @@ eval_index( *arg = skipwhite(*arg + 1); if (**arg == ']') empty2 = TRUE; - else if (eval1(arg, &var2, evaluate) == FAIL) // recursive! + else if (eval1(arg, &var2, flags) == FAIL) // recursive! { if (!empty1) clear_tv(&var1); @@ -5310,11 +5326,12 @@ eval_isnamec1(int c) handle_subscript( char_u **arg, typval_T *rettv, - int evaluate, // do more than finding the end + int flags, // do more than finding the end int verbose, // give error messages char_u *start_leader, // start of '!' and '-' prefixes char_u **end_leaderp) // end of '!' and '-' prefixes { + int evaluate = flags & EVAL_EVALUATE; int ret = OK; dict_T *selfdict = NULL; @@ -5374,7 +5391,7 @@ handle_subscript( } else selfdict = NULL; - if (eval_index(arg, rettv, evaluate, verbose) == FAIL) + if (eval_index(arg, rettv, flags, verbose) == FAIL) { clear_tv(rettv); ret = FAIL; @@ -6108,7 +6125,7 @@ ex_echo(exarg_T *eap) need_clr_eos = needclr; p = arg; - if (eval1(&arg, &rettv, !eap->skip) == FAIL) + if (eval1(&arg, &rettv, eap->skip ? 0 : EVAL_EVALUATE) == FAIL) { /* * Report the invalid expression unless the expression evaluation diff --git a/src/evalfunc.c b/src/evalfunc.c index 7579208359..297961184a 100644 --- a/src/evalfunc.c +++ b/src/evalfunc.c @@ -2132,7 +2132,7 @@ f_eval(typval_T *argvars, typval_T *rettv) s = skipwhite(s); p = s; - if (s == NULL || eval1(&s, rettv, TRUE) == FAIL) + if (s == NULL || eval1(&s, rettv, EVAL_EVALUATE) == FAIL) { if (p != NULL && !aborting()) semsg(_(e_invexpr2), p); diff --git a/src/evalvars.c b/src/evalvars.c index e747230033..fd652ae109 100644 --- a/src/evalvars.c +++ b/src/evalvars.c @@ -433,7 +433,7 @@ eval_spell_expr(char_u *badword, char_u *expr) if (p_verbose == 0) ++emsg_off; - if (eval1(&p, &rettv, TRUE) == OK) + if (eval1(&p, &rettv, EVAL_EVALUATE) == OK) { if (rettv.v_type != VAR_LIST) clear_tv(&rettv); @@ -701,11 +701,14 @@ ex_const(exarg_T *eap) } /* - * When "redefine" is TRUE the command will be executed again, redefining the - * variable is OK then. + * When "discovery" is TRUE the ":let" or ":const" is encountered during the + * discovery phase of vim9script: + * - The command will be executed again, redefining the variable is OK then. + * - The expresion argument must be a constant. + * - If no constant expression a type must be specified. */ void -ex_let_const(exarg_T *eap, int redefine) +ex_let_const(exarg_T *eap, int discovery) { char_u *arg = eap->arg; char_u *expr = NULL; @@ -717,13 +720,14 @@ ex_let_const(exarg_T *eap, int redefine) char_u *argend; int first = TRUE; int concat; + int has_assign; int flags = eap->cmdidx == CMD_const ? LET_IS_CONST : 0; // detect Vim9 assignment without ":let" or ":const" if (eap->arg == eap->cmd) flags |= LET_NO_COMMAND; - if (redefine) - flags |= LET_REDEFINE; + if (discovery) + flags |= LET_DISCOVERY; argend = skip_var_list(arg, TRUE, &var_count, &semicolon); if (argend == NULL) @@ -734,8 +738,9 @@ ex_let_const(exarg_T *eap, int redefine) concat = expr[0] == '.' && ((expr[1] == '=' && current_sctx.sc_version < 2) || (expr[1] == '.' && expr[2] == '=')); - if (*expr != '=' && !((vim_strchr((char_u *)"+-*/%", *expr) != NULL - && expr[1] == '=') || concat)) + has_assign = *expr == '=' || (vim_strchr((char_u *)"+-*/%", *expr) != NULL + && expr[1] == '='); + if (!has_assign && !concat && !discovery) { // ":let" without "=": list variables if (*arg == '[') @@ -779,32 +784,45 @@ ex_let_const(exarg_T *eap, int redefine) } else { - op[0] = '='; - op[1] = NUL; - if (*expr != '=') - { - if (vim_strchr((char_u *)"+-*/%.", *expr) != NULL) - { - op[0] = *expr; // +=, -=, *=, /=, %= or .= - if (expr[0] == '.' && expr[1] == '.') // ..= - ++expr; - } - expr = skipwhite(expr + 2); - } - else - expr = skipwhite(expr + 1); + int eval_flags; + int save_called_emsg = called_emsg; - if (eap->skip) - ++emsg_skip; - i = eval0(expr, &rettv, &eap->nextcmd, !eap->skip); + rettv.v_type = VAR_UNKNOWN; + i = FAIL; + if (has_assign || concat) + { + op[0] = '='; + op[1] = NUL; + if (*expr != '=') + { + if (vim_strchr((char_u *)"+-*/%.", *expr) != NULL) + { + op[0] = *expr; // +=, -=, *=, /=, %= or .= + if (expr[0] == '.' && expr[1] == '.') // ..= + ++expr; + } + expr = skipwhite(expr + 2); + } + else + expr = skipwhite(expr + 1); + + if (eap->skip) + ++emsg_skip; + eval_flags = eap->skip ? 0 : EVAL_EVALUATE; + if (discovery) + eval_flags |= EVAL_CONSTANT; + i = eval0(expr, &rettv, &eap->nextcmd, eval_flags); + } if (eap->skip) { if (i != FAIL) clear_tv(&rettv); --emsg_skip; } - else if (i != FAIL) + else if (i != FAIL || (discovery && save_called_emsg == called_emsg)) { + // In Vim9 script discovery "let v: bool = Func()" fails but is + // still a valid declaration. (void)ex_let_vars(eap->arg, &rettv, FALSE, semicolon, var_count, flags, op); clear_tv(&rettv); @@ -1112,7 +1130,7 @@ list_arg_vars(exarg_T *eap, char_u *arg, int *first) { // handle d.key, l[idx], f(expr) arg_subsc = arg; - if (handle_subscript(&arg, &tv, TRUE, TRUE, + if (handle_subscript(&arg, &tv, EVAL_EVALUATE, TRUE, name, &name) == FAIL) error = TRUE; else @@ -1353,7 +1371,12 @@ ex_let_one( lval_T lv; p = get_lval(arg, tv, &lv, FALSE, FALSE, 0, FNE_CHECK_START); - if (p != NULL && lv.ll_name != NULL) + if ((flags & LET_DISCOVERY) && tv->v_type == VAR_UNKNOWN + && lv.ll_type == NULL) + { + semsg(_("E1091: type missing for %s"), arg); + } + else if (p != NULL && lv.ll_name != NULL) { if (endchars != NULL && vim_strchr(endchars, *skipwhite(lv.ll_name_end)) == NULL) @@ -2981,7 +3004,7 @@ set_var_const( if (flags & LET_IS_CONST) di->di_tv.v_lock |= VAR_LOCKED; - if (flags & LET_REDEFINE) + if (flags & LET_DISCOVERY) di->di_flags |= DI_FLAGS_RELOAD; } @@ -3288,7 +3311,8 @@ var_exists(char_u *var) if (n) { // handle d.key, l[idx], f(expr) - n = (handle_subscript(&var, &tv, TRUE, FALSE, name, &name) == OK); + n = (handle_subscript(&var, &tv, EVAL_EVALUATE, + FALSE, name, &name) == OK); if (n) clear_tv(&tv); } diff --git a/src/ex_eval.c b/src/ex_eval.c index 4aa2658361..f7253438d7 100644 --- a/src/ex_eval.c +++ b/src/ex_eval.c @@ -879,7 +879,8 @@ ex_eval(exarg_T *eap) { typval_T tv; - if (eval0(eap->arg, &tv, &eap->nextcmd, !eap->skip) == OK) + if (eval0(eap->arg, &tv, &eap->nextcmd, eap->skip ? 0 : EVAL_EVALUATE) + == OK) clear_tv(&tv); } diff --git a/src/list.c b/src/list.c index 6242e52438..b9e7e340d7 100644 --- a/src/list.c +++ b/src/list.c @@ -1046,8 +1046,9 @@ f_join(typval_T *argvars, typval_T *rettv) * Return OK or FAIL. */ int -get_list_tv(char_u **arg, typval_T *rettv, int evaluate, int do_error) +get_list_tv(char_u **arg, typval_T *rettv, int flags, int do_error) { + int evaluate = flags & EVAL_EVALUATE; list_T *l = NULL; typval_T tv; listitem_T *item; @@ -1062,7 +1063,7 @@ get_list_tv(char_u **arg, typval_T *rettv, int evaluate, int do_error) *arg = skipwhite(*arg + 1); while (**arg != ']' && **arg != NUL) { - if (eval1(arg, &tv, evaluate) == FAIL) // recursive! + if (eval1(arg, &tv, flags) == FAIL) // recursive! goto failret; if (evaluate) { diff --git a/src/testdir/test_vim9_disassemble.vim b/src/testdir/test_vim9_disassemble.vim index 7213ee4ff7..2df28e220f 100644 --- a/src/testdir/test_vim9_disassemble.vim +++ b/src/testdir/test_vim9_disassemble.vim @@ -1054,7 +1054,7 @@ def Test_vim9script_forward_func() def FuncTwo(): string return 'two' enddef - let g:res_FuncOne = execute('disass FuncOne') + let g:res_FuncOne: string = execute('disass FuncOne') END writefile(lines, 'Xdisassemble') source Xdisassemble diff --git a/src/testdir/test_vim9_script.vim b/src/testdir/test_vim9_script.vim index e85da5a800..c528b8009b 100644 --- a/src/testdir/test_vim9_script.vim +++ b/src/testdir/test_vim9_script.vim @@ -494,7 +494,7 @@ let s:export_script_lines =<< trim END def Concat(arg: string): string return name .. arg enddef - let g:result = Concat('bie') + let g:result: string = Concat('bie') let g:localname = name export const CONST = 1234 @@ -1633,7 +1633,7 @@ def Test_vim9_comment_not_compiled() CheckScriptFailure([ 'vim9script', 'let g:var = 123', - 'unlet g:var# comment', + 'unlet g:var# comment1', ], 'E108:') CheckScriptFailure([ @@ -1643,7 +1643,7 @@ def Test_vim9_comment_not_compiled() CheckScriptSuccess([ 'vim9script', - 'if 1 # comment', + 'if 1 # comment2', ' echo "yes"', 'elseif 2 #comment', ' echo "no"', @@ -1652,14 +1652,14 @@ def Test_vim9_comment_not_compiled() CheckScriptFailure([ 'vim9script', - 'if 1# comment', + 'if 1# comment3', ' echo "yes"', 'endif', ], 'E15:') CheckScriptFailure([ 'vim9script', - 'if 0 # comment', + 'if 0 # comment4', ' echo "yes"', 'elseif 2#comment', ' echo "no"', @@ -1668,23 +1668,18 @@ def Test_vim9_comment_not_compiled() CheckScriptSuccess([ 'vim9script', - 'let # comment', + 'let v = 1 # comment5', ]) CheckScriptFailure([ 'vim9script', - 'let# comment', - ], 'E121:') - - CheckScriptSuccess([ - 'vim9script', - 'let v:version # comment', - ]) + 'let v = 1# comment6', + ], 'E15:') CheckScriptFailure([ 'vim9script', - 'let v:version# comment', - ], 'E121:') + 'let v:version', + ], 'E1091:') CheckScriptSuccess([ 'vim9script', @@ -1722,6 +1717,41 @@ def Test_finish() delete('Xfinished') enddef +def Test_let_func_call() + let lines =<< trim END + vim9script + func GetValue() + if exists('g:count') + let g:count += 1 + else + let g:count = 1 + endif + return 'this' + endfunc + let val: string = GetValue() + END + writefile(lines, 'Xfinished') + source Xfinished + assert_equal(1, g:count) + + unlet g:count + delete('Xfinished') +enddef + +def Test_let_missing_type() + let lines =<< trim END + vim9script + func GetValue() + return 'this' + endfunc + let val = GetValue() + END + writefile(lines, 'Xfinished') + assert_fails('source Xfinished', 'E1091:') + + delete('Xfinished') +enddef + " Keep this last, it messes up highlighting. def Test_substitute_cmd() new diff --git a/src/userfunc.c b/src/userfunc.c index 5a64ccb75f..b3c4f900a1 100644 --- a/src/userfunc.c +++ b/src/userfunc.c @@ -239,7 +239,7 @@ get_function_args( whitep = p; p = skipwhite(p); expr = p; - if (eval1(&p, &rettv, FALSE) != FAIL) + if (eval1(&p, &rettv, 0) != FAIL) { if (ga_grow(default_args, 1) == FAIL) goto err_ret; @@ -572,7 +572,8 @@ get_func_tv( argp = skipwhite(argp + 1); // skip the '(' or ',' if (*argp == ')' || *argp == ',' || *argp == NUL) break; - if (eval1(&argp, &argvars[argcount], funcexe->evaluate) == FAIL) + if (eval1(&argp, &argvars[argcount], + funcexe->evaluate ? EVAL_EVALUATE : 0) == FAIL) { ret = FAIL; break; @@ -1223,7 +1224,7 @@ call_user_func( default_expr = ((char_u **)(fp->uf_def_args.ga_data)) [ai + fp->uf_def_args.ga_len]; - if (eval1(&default_expr, &def_rettv, TRUE) == FAIL) + if (eval1(&default_expr, &def_rettv, EVAL_EVALUATE) == FAIL) { default_arg_err = 1; break; @@ -1368,7 +1369,7 @@ call_user_func( // A Lambda always has the command "return {expr}". It is much faster // to evaluate {expr} directly. ++ex_nesting_level; - (void)eval1(&p, rettv, TRUE); + (void)eval1(&p, rettv, EVAL_EVALUATE); --ex_nesting_level; } else @@ -3623,7 +3624,8 @@ ex_return(exarg_T *eap) eap->nextcmd = NULL; if ((*arg != NUL && *arg != '|' && *arg != '\n') - && eval0(arg, &rettv, &eap->nextcmd, !eap->skip) != FAIL) + && eval0(arg, &rettv, &eap->nextcmd, eap->skip ? 0 : EVAL_EVALUATE) + != FAIL) { if (!eap->skip) returning = do_return(eap, FALSE, TRUE, &rettv); @@ -3680,7 +3682,7 @@ ex_call(exarg_T *eap) // instead to skip to any following command, e.g. for: // :if 0 | call dict.foo().bar() | endif ++emsg_skip; - if (eval0(eap->arg, &rettv, &eap->nextcmd, FALSE) != FAIL) + if (eval0(eap->arg, &rettv, &eap->nextcmd, 0) != FAIL) clear_tv(&rettv); --emsg_skip; return; @@ -3768,8 +3770,8 @@ ex_call(exarg_T *eap) dbg_check_breakpoint(eap); // Handle a function returning a Funcref, Dictionary or List. - if (handle_subscript(&arg, &rettv, !eap->skip, TRUE, - name, &name) == FAIL) + if (handle_subscript(&arg, &rettv, eap->skip ? 0 : EVAL_EVALUATE, + TRUE, name, &name) == FAIL) { failed = TRUE; break; diff --git a/src/version.c b/src/version.c index 3f67db4511..ad56b7af19 100644 --- a/src/version.c +++ b/src/version.c @@ -746,6 +746,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 753, /**/ 752, /**/ diff --git a/src/vim.h b/src/vim.h index 9e4c61db37..667e290299 100644 --- a/src/vim.h +++ b/src/vim.h @@ -2133,7 +2133,7 @@ typedef enum { // Flags for assignment functions. #define LET_IS_CONST 1 // ":const" #define LET_NO_COMMAND 2 // "var = expr" without ":let" or ":const" -#define LET_REDEFINE 4 // variable can be redefined later +#define LET_DISCOVERY 4 // discovery phase: variable can be redefined later #include "ex_cmds.h" // Ex command defines #include "spell.h" // spell checking stuff @@ -2662,4 +2662,8 @@ long elapsed(DWORD start_tick); #define REPTERM_SPECIAL 4 #define REPTERM_NO_SIMPLIFY 8 +// Flags for expression evaluation. +#define EVAL_EVALUATE 1 // when missing don't actually evaluate +#define EVAL_CONSTANT 2 // when not a constant return FAIL + #endif // VIM__H diff --git a/src/vim9compile.c b/src/vim9compile.c index 99246e07df..4b294df298 100644 --- a/src/vim9compile.c +++ b/src/vim9compile.c @@ -2869,14 +2869,14 @@ to_name_const_end(char_u *arg) { // Can be "[1, 2, 3]->Func()". - if (get_list_tv(&p, &rettv, FALSE, FALSE) == FAIL) + if (get_list_tv(&p, &rettv, 0, FALSE) == FAIL) p = arg; } else if (p == arg && *arg == '#' && arg[1] == '{') { // Can be "#{a: 1}->Func()". ++p; - if (eval_dict(&p, &rettv, FALSE, TRUE) == FAIL) + if (eval_dict(&p, &rettv, 0, TRUE) == FAIL) p = arg; } else if (p == arg && *arg == '{') @@ -2886,7 +2886,7 @@ to_name_const_end(char_u *arg) // Can be "{x -> ret}()". // Can be "{'a': 1}->Func()". if (ret == NOTDONE) - ret = eval_dict(&p, &rettv, FALSE, FALSE); + ret = eval_dict(&p, &rettv, 0, FALSE); if (ret != OK) p = arg; } From a5d0077efbced85fcc63f203937b13efd55d036f Mon Sep 17 00:00:00 2001 From: Bram Moolenaar <Bram@vim.org> Date: Thu, 14 May 2020 23:20:55 +0200 Subject: [PATCH 152/230] patch 8.2.0754: Vim9: No test for forward declaration Problem: Vim9: No test for forward declaration. Solution: Add a test. --- src/testdir/test_vim9_script.vim | 23 +++++++++++++++++++++++ src/version.c | 2 ++ 2 files changed, 25 insertions(+) diff --git a/src/testdir/test_vim9_script.vim b/src/testdir/test_vim9_script.vim index c528b8009b..6b6228e5ed 100644 --- a/src/testdir/test_vim9_script.vim +++ b/src/testdir/test_vim9_script.vim @@ -1732,6 +1732,7 @@ def Test_let_func_call() END writefile(lines, 'Xfinished') source Xfinished + " GetValue() is not called during discovery phase assert_equal(1, g:count) unlet g:count @@ -1752,6 +1753,28 @@ def Test_let_missing_type() delete('Xfinished') enddef +def Test_forward_declaration() + let lines =<< trim END + vim9script + g:initVal = GetValue() + def GetValue(): string + return theVal + enddef + let theVal = 'something' + theVal = 'else' + g:laterVal = GetValue() + END + writefile(lines, 'Xforward') + source Xforward + assert_equal('something', g:initVal) + assert_equal('else', g:laterVal) + + unlet g:initVal + unlet g:laterVal + delete('Xforward') +enddef + + " Keep this last, it messes up highlighting. def Test_substitute_cmd() new diff --git a/src/version.c b/src/version.c index ad56b7af19..8ff5161e72 100644 --- a/src/version.c +++ b/src/version.c @@ -746,6 +746,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 754, /**/ 753, /**/ From 227a69de1e0f9457a9fc9e098d999304faff55f8 Mon Sep 17 00:00:00 2001 From: Bram Moolenaar <Bram@vim.org> Date: Fri, 15 May 2020 18:17:28 +0200 Subject: [PATCH 153/230] patch 8.2.0755: Vim9: No error when variable initializer is not a constant Problem: Vim9: No error when variable initializer is not a constant. Solution: Return FAIL when trying to get a variable value. Do not execute a script when an error is deteted in the first or second phase. --- src/eval.c | 2 ++ src/testdir/test_vim9_script.vim | 34 +++++++++++++++++++++++++++----- src/version.c | 2 ++ src/vim9script.c | 20 +++++++++++++------ 4 files changed, 47 insertions(+), 11 deletions(-) diff --git a/src/eval.c b/src/eval.c index b3fe650ee8..77359dccaa 100644 --- a/src/eval.c +++ b/src/eval.c @@ -2695,6 +2695,8 @@ eval7( { if (**arg == '(') // recursive! ret = eval_func(arg, s, len, rettv, flags, NULL); + else if (flags & EVAL_CONSTANT) + ret = FAIL; else if (evaluate) ret = get_var_tv(s, len, rettv, NULL, TRUE, FALSE); else diff --git a/src/testdir/test_vim9_script.vim b/src/testdir/test_vim9_script.vim index 6b6228e5ed..fd1dbc8c2f 100644 --- a/src/testdir/test_vim9_script.vim +++ b/src/testdir/test_vim9_script.vim @@ -494,8 +494,8 @@ let s:export_script_lines =<< trim END def Concat(arg: string): string return name .. arg enddef - let g:result: string = Concat('bie') - let g:localname = name + g:result = Concat('bie') + g:localname = name export const CONST = 1234 export let exported = 9876 @@ -1747,10 +1747,34 @@ def Test_let_missing_type() endfunc let val = GetValue() END - writefile(lines, 'Xfinished') - assert_fails('source Xfinished', 'E1091:') + CheckScriptFailure(lines, 'E1091:') - delete('Xfinished') + lines =<< trim END + vim9script + let var = g:unkown + END + CheckScriptFailure(lines, 'E1091:') + + " TODO: eventually this would work + lines =<< trim END + vim9script + let var = has('eval') + END + CheckScriptFailure(lines, 'E1091:') + + " TODO: eventually this would work + lines =<< trim END + vim9script + let var = len('string') + END + CheckScriptFailure(lines, 'E1091:') + + lines =<< trim END + vim9script + let nr: number = 123 + let var = nr + END + CheckScriptFailure(lines, 'E1091:') enddef def Test_forward_declaration() diff --git a/src/version.c b/src/version.c index 8ff5161e72..1f77ddc3f7 100644 --- a/src/version.c +++ b/src/version.c @@ -746,6 +746,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 755, /**/ 754, /**/ diff --git a/src/vim9script.c b/src/vim9script.c index 4d7e8ee46f..e213d61f1d 100644 --- a/src/vim9script.c +++ b/src/vim9script.c @@ -37,6 +37,7 @@ ex_vim9script(exarg_T *eap) garray_T func_ga; int idx; ufunc_T *ufunc; + int start_called_emsg = called_emsg; if (!getline_equal(eap->getline, eap->cookie, getsourceline)) { @@ -66,7 +67,7 @@ ex_vim9script(exarg_T *eap) // The types are recognized, so that they can be used when compiling a // function. gap = source_get_line_ga(eap->cookie); - for (;;) + while (called_emsg == start_called_emsg) { char_u *line; char_u *p; @@ -132,22 +133,29 @@ ex_vim9script(exarg_T *eap) } else if (checkforcmd(&p, "finish", 4)) { - // TODO: this should not happen below "if false". - // Use "if cond | finish | endif as a workaround. break; } } // Compile the :def functions. - for (idx = 0; idx < func_ga.ga_len; ++idx) + for (idx = 0; idx < func_ga.ga_len && called_emsg == start_called_emsg; ++idx) { ufunc = ((ufunc_T **)(func_ga.ga_data))[idx]; compile_def_function(ufunc, FALSE, NULL); } ga_clear(&func_ga); - // Return to process the commands at the script level. - source_use_line_ga(eap->cookie); + if (called_emsg == start_called_emsg) + { + // Return to process the commands at the script level. + source_use_line_ga(eap->cookie); + } + else + { + // If there was an error in the first or second phase then don't + // execute the script lines. + do_finish(eap, FALSE); + } } /* From 7e6f3fcc3ce89fc8ade85be39aa475e606c0b26c Mon Sep 17 00:00:00 2001 From: Bram Moolenaar <Bram@vim.org> Date: Fri, 15 May 2020 18:21:51 +0200 Subject: [PATCH 154/230] patch 8.2.0756: MS-Windows: still a compiler warning Problem: MS-Windows: still a compiler warning. Solution: Move flag to another place in the Makefile. (Ken Takata, closes #6083) --- src/Make_mvc.mak | 7 ++++--- src/version.c | 2 ++ 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/src/Make_mvc.mak b/src/Make_mvc.mak index ffe6e4914c..c93517b980 100644 --- a/src/Make_mvc.mak +++ b/src/Make_mvc.mak @@ -675,9 +675,6 @@ CFLAGS = $(CFLAGS) $(WP64CHECK) CFLAGS = $(CFLAGS) $(OPTFLAG) -DNDEBUG $(CPUARG) RCFLAGS = $(rcflags) $(rcvars) -DNDEBUG -! if "$(CL)" == "/D_USING_V110_SDK71_" -RCFLAGS = $(RCFLAGS) /D_USING_V110_SDK71_ -! endif ! ifdef USE_MSVCRT CFLAGS = $(CFLAGS) /MD LIBC = msvcrt.lib @@ -707,6 +704,10 @@ CFLAGS = $(CFLAGS) /Zl /MTd ! endif !endif # DEBUG +!if "$(CL)" == "/D_USING_V110_SDK71_" +RCFLAGS = $(RCFLAGS) /D_USING_V110_SDK71_ +!endif + !if $(MSVC_MAJOR) >= 8 # Visual Studio 2005 has 'deprecated' many of the standard CRT functions CFLAGS_DEPR = /D_CRT_SECURE_NO_DEPRECATE /D_CRT_NONSTDC_NO_DEPRECATE diff --git a/src/version.c b/src/version.c index 1f77ddc3f7..44f816aef3 100644 --- a/src/version.c +++ b/src/version.c @@ -746,6 +746,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 756, /**/ 755, /**/ From 4902ab16cbb6e00f4fee8bbdf16f1383fd8ba42f Mon Sep 17 00:00:00 2001 From: Bram Moolenaar <Bram@vim.org> Date: Fri, 15 May 2020 19:21:31 +0200 Subject: [PATCH 155/230] patch 8.2.0757: Vim9: no test for MEMBER instruction Problem: Vim9: no test for MEMBER instruction. Solution: Add a test. Make matches stricter. --- src/testdir/test_vim9_disassemble.vim | 193 ++++++++++++++------------ src/version.c | 2 + 2 files changed, 103 insertions(+), 92 deletions(-) diff --git a/src/testdir/test_vim9_disassemble.vim b/src/testdir/test_vim9_disassemble.vim index 2df28e220f..90bd67dbac 100644 --- a/src/testdir/test_vim9_disassemble.vim +++ b/src/testdir/test_vim9_disassemble.vim @@ -726,18 +726,18 @@ enddef def Test_disassemble_list_index() let instr = execute('disassemble ListIndex') - assert_match('ListIndex.*' .. - 'let l = \[1, 2, 3].*' .. - '\d PUSHNR 1.*' .. - '\d PUSHNR 2.*' .. - '\d PUSHNR 3.*' .. - '\d NEWLIST size 3.*' .. - '\d STORE $0.*' .. - 'let res = l\[1].*' .. - '\d LOAD $0.*' .. - '\d PUSHNR 1.*' .. - '\d INDEX.*' .. - '\d STORE $1.*', + assert_match('ListIndex\_s*' .. + 'let l = \[1, 2, 3]\_s*' .. + '\d PUSHNR 1\_s*' .. + '\d PUSHNR 2\_s*' .. + '\d PUSHNR 3\_s*' .. + '\d NEWLIST size 3\_s*' .. + '\d STORE $0\_s*' .. + 'let res = l\[1]\_s*' .. + '\d LOAD $0\_s*' .. + '\d PUSHNR 1\_s*' .. + '\d INDEX\_s*' .. + '\d STORE $1\_s*', instr) assert_equal(2, ListIndex()) enddef @@ -745,21 +745,27 @@ enddef def DictMember(): number let d = #{item: 1} let res = d.item + res = d["item"] return res enddef def Test_disassemble_dict_member() let instr = execute('disassemble DictMember') - assert_match('DictMember.*' .. - 'let d = #{item: 1}.*' .. - '\d PUSHS "item".*' .. - '\d PUSHNR 1.*' .. - '\d NEWDICT size 1.*' .. - '\d STORE $0.*' .. - 'let res = d.item.*' .. - '\d LOAD $0.*' .. - '\d MEMBER item.*' .. - '\d STORE $1.*', + assert_match('DictMember\_s*' .. + 'let d = #{item: 1}\_s*' .. + '\d PUSHS "item"\_s*' .. + '\d PUSHNR 1\_s*' .. + '\d NEWDICT size 1\_s*' .. + '\d STORE $0\_s*' .. + 'let res = d.item\_s*' .. + '\d\+ LOAD $0\_s*' .. + '\d\+ MEMBER item\_s*' .. + '\d\+ STORE $1\_s*' .. + 'res = d\["item"\]\_s*' .. + '\d\+ LOAD $0\_s*' .. + '\d\+ PUSHS "item"\_s*' .. + '\d\+ MEMBER\_s*' .. + '\d\+ STORE $1\_s*', instr) call assert_equal(1, DictMember()) enddef @@ -773,17 +779,17 @@ enddef def Test_disassemble_negate_number() let instr = execute('disassemble NegateNumber') - assert_match('NegateNumber.*' .. - 'let nr = 9.*' .. - '\d STORE 9 in $0.*' .. - 'let plus = +nr.*' .. - '\d LOAD $0.*' .. - '\d CHECKNR.*' .. - '\d STORE $1.*' .. - 'let res = -nr.*' .. - '\d LOAD $0.*' .. - '\d NEGATENR.*' .. - '\d STORE $2.*', + assert_match('NegateNumber\_s*' .. + 'let nr = 9\_s*' .. + '\d STORE 9 in $0\_s*' .. + 'let plus = +nr\_s*' .. + '\d LOAD $0\_s*' .. + '\d CHECKNR\_s*' .. + '\d STORE $1\_s*' .. + 'let res = -nr\_s*' .. + '\d LOAD $0\_s*' .. + '\d NEGATENR\_s*' .. + '\d STORE $2\_s*', instr) call assert_equal(-9, NegateNumber()) enddef @@ -797,18 +803,18 @@ enddef def Test_disassemble_invert_bool() let instr = execute('disassemble InvertBool') - assert_match('InvertBool.*' .. - 'let flag = true.*' .. - '\d PUSH v:true.*' .. - '\d STORE $0.*' .. - 'let invert = !flag.*' .. - '\d LOAD $0.*' .. - '\d INVERT (!val).*' .. - '\d STORE $1.*' .. - 'let res = !!flag.*' .. - '\d LOAD $0.*' .. - '\d 2BOOL (!!val).*' .. - '\d STORE $2.*', + assert_match('InvertBool\_s*' .. + 'let flag = true\_s*' .. + '\d PUSH v:true\_s*' .. + '\d STORE $0\_s*' .. + 'let invert = !flag\_s*' .. + '\d LOAD $0\_s*' .. + '\d INVERT (!val)\_s*' .. + '\d STORE $1\_s*' .. + 'let res = !!flag\_s*' .. + '\d LOAD $0\_s*' .. + '\d 2BOOL (!!val)\_s*' .. + '\d STORE $2\_s*', instr) call assert_equal(true, InvertBool()) enddef @@ -970,26 +976,26 @@ enddef def Test_disassemble_execute() let res = execute('disass s:Execute') - assert_match('\<SNR>\d*_Execute.*' .. - "execute 'help vim9.txt'.*" .. - '\d PUSHS "help vim9.txt".*' .. - '\d EXECUTE 1.*' .. - "let cmd = 'help vim9.txt'.*" .. - '\d PUSHS "help vim9.txt".*' .. - '\d STORE $0.*' .. - 'execute cmd.*' .. - '\d LOAD $0.*' .. - '\d EXECUTE 1.*' .. - "let tag = 'vim9.txt'.*" .. - '\d PUSHS "vim9.txt".*' .. - '\d STORE $1.*' .. - "execute 'help ' .. tag.*" .. - '\d PUSHS "help ".*' .. - '\d LOAD $1.*' .. - '\d CONCAT.*' .. - '\d EXECUTE 1.*' .. - '\d PUSHNR 0.*' .. - '\d RETURN', + assert_match('\<SNR>\d*_Execute\_s*' .. + "execute 'help vim9.txt'\\_s*" .. + '\d PUSHS "help vim9.txt"\_s*' .. + '\d EXECUTE 1\_s*' .. + "let cmd = 'help vim9.txt'\\_s*" .. + '\d PUSHS "help vim9.txt"\_s*' .. + '\d STORE $0\_s*' .. + 'execute cmd\_s*' .. + '\d LOAD $0\_s*' .. + '\d EXECUTE 1\_s*' .. + "let tag = 'vim9.txt'\\_s*" .. + '\d PUSHS "vim9.txt"\_s*' .. + '\d STORE $1\_s*' .. + "execute 'help ' .. tag\\_s*" .. + '\d\+ PUSHS "help "\_s*' .. + '\d\+ LOAD $1\_s*' .. + '\d\+ CONCAT\_s*' .. + '\d\+ EXECUTE 1\_s*' .. + '\d\+ PUSHNR 0\_s*' .. + '\d\+ RETURN', res) enddef @@ -1000,15 +1006,15 @@ enddef def Test_disassemble_echomsg() let res = execute('disass s:Echomsg') - assert_match('\<SNR>\d*_Echomsg.*' .. - "echomsg 'some' 'message'.*" .. - '\d PUSHS "some".*' .. - '\d PUSHS "message".*' .. - '\d ECHOMSG 2.*' .. - "echoerr 'went' .. 'wrong'.*" .. - '\d PUSHS "wentwrong".*' .. - '\d ECHOERR 1.*' .. - '\d PUSHNR 0.*' .. + assert_match('\<SNR>\d*_Echomsg\_s*' .. + "echomsg 'some' 'message'\\_s*" .. + '\d PUSHS "some"\_s*' .. + '\d PUSHS "message"\_s*' .. + '\d ECHOMSG 2\_s*' .. + "echoerr 'went' .. 'wrong'\\_s*" .. + '\d PUSHS "wentwrong"\_s*' .. + '\d ECHOERR 1\_s*' .. + '\d PUSHNR 0\_s*' .. '\d RETURN', res) enddef @@ -1027,21 +1033,21 @@ enddef def Test_display_func() let res1 = execute('function SomeStringArg') - assert_match('.* def SomeStringArg(arg: string).*' .. - ' echo arg.*' .. - ' enddef', + assert_match('.* def SomeStringArg(arg: string)\_s*' .. + '\d *echo arg.*' .. + ' *enddef', res1) let res2 = execute('function SomeAnyArg') - assert_match('.* def SomeAnyArg(arg: any).*' .. - ' echo arg.*' .. - ' enddef', + assert_match('.* def SomeAnyArg(arg: any)\_s*' .. + '\d *echo arg\_s*' .. + ' *enddef', res2) let res3 = execute('function SomeStringArgAndReturn') - assert_match('.* def SomeStringArgAndReturn(arg: string): string.*' .. - ' return arg.*' .. - ' enddef', + assert_match('.* def SomeStringArgAndReturn(arg: string): string\_s*' .. + '\d *return arg\_s*' .. + ' *enddef', res3) enddef @@ -1060,9 +1066,9 @@ def Test_vim9script_forward_func() source Xdisassemble " check that the first function calls the second with DCALL - assert_match('\<SNR>\d*_FuncOne.*' .. - 'return FuncTwo().*' .. - '\d DCALL <SNR>\d\+_FuncTwo(argc 0).*' .. + assert_match('\<SNR>\d*_FuncOne\_s*' .. + 'return FuncTwo()\_s*' .. + '\d DCALL <SNR>\d\+_FuncTwo(argc 0)\_s*' .. '\d RETURN', g:res_FuncOne) @@ -1084,20 +1090,23 @@ enddef def Test_simplify_const_expr() let res = execute('disass s:ConcatStrings') - assert_match('\<SNR>\d*_ConcatStrings.*' .. - '\d PUSHS "onetwothree".*' .. + assert_match('<SNR>\d*_ConcatStrings\_s*' .. + "return 'one' .. 'two' .. 'three'\\_s*" .. + '\d PUSHS "onetwothree"\_s*' .. '\d RETURN', res) res = execute('disass s:ComputeConst') - assert_match('\<SNR>\d*_ComputeConst.*' .. - '\d PUSHNR 11.*' .. + assert_match('<SNR>\d*_ComputeConst\_s*' .. + 'return 2 + 3 \* 4 / 6 + 7\_s*' .. + '\d PUSHNR 11\_s*' .. '\d RETURN', res) res = execute('disass s:ComputeConstParen') - assert_match('\<SNR>\d*_ComputeConstParen.*' .. - '\d PUSHNR 3\>.*' .. + assert_match('<SNR>\d*_ComputeConstParen\_s*' .. + 'return ((2 + 4) \* (8 / 2)) / (3 + 4)\_s*' .. + '\d PUSHNR 3\>\_s*' .. '\d RETURN', res) enddef diff --git a/src/version.c b/src/version.c index 44f816aef3..061844786f 100644 --- a/src/version.c +++ b/src/version.c @@ -746,6 +746,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 757, /**/ 756, /**/ From cb7904016eb817e80760c394044740df8273c774 Mon Sep 17 00:00:00 2001 From: Bram Moolenaar <Bram@vim.org> Date: Fri, 15 May 2020 20:53:00 +0200 Subject: [PATCH 156/230] patch 8.2.0758: Vim9: no test for STORELIST and STOREDICT Problem: Vim9: no test for STORELIST and STOREDICT. Solution: Add a test. Make matches stricter. --- src/testdir/test_vim9_disassemble.vim | 450 +++++++++++++++----------- src/version.c | 2 + 2 files changed, 263 insertions(+), 189 deletions(-) diff --git a/src/testdir/test_vim9_disassemble.vim b/src/testdir/test_vim9_disassemble.vim index 90bd67dbac..74804b4cf2 100644 --- a/src/testdir/test_vim9_disassemble.vim +++ b/src/testdir/test_vim9_disassemble.vim @@ -154,6 +154,37 @@ def Test_disassemble_store() res) enddef +def s:ScriptFuncStoreMember() + let locallist: list<number> = [] + locallist[0] = 123 + let localdict: dict<number> = {} + localdict["a"] = 456 +enddef + +def Test_disassemble_store_member() + let res = execute('disass s:ScriptFuncStoreMember') + assert_match('<SNR>\d*_ScriptFuncStoreMember\_s*' .. + 'let locallist: list<number> = []\_s*' .. + '\d NEWLIST size 0\_s*' .. + '\d STORE $0\_s*' .. + 'locallist\[0\] = 123\_s*' .. + '\d PUSHNR 123\_s*' .. + '\d PUSHNR 0\_s*' .. + '\d LOAD $0\_s*' .. + '\d STORELIST\_s*' .. + 'let localdict: dict<number> = {}\_s*' .. + '\d NEWDICT size 0\_s*' .. + '\d STORE $1\_s*' .. + 'localdict\["a"\] = 456\_s*' .. + '\d\+ PUSHNR 456\_s*' .. + '\d\+ PUSHS "a"\_s*' .. + '\d\+ LOAD $1\_s*' .. + '\d\+ STOREDICT\_s*' .. + '\d\+ PUSHNR 0\_s*' .. + '\d\+ RETURN', + res) +enddef + def s:ScriptFuncUnlet() g:somevar = "value" unlet g:somevar @@ -163,46 +194,53 @@ enddef def Test_disassemble_unlet() let res = execute('disass s:ScriptFuncUnlet') - assert_match('<SNR>\d*_ScriptFuncUnlet.*' .. - 'g:somevar = "value".*' .. - '\d PUSHS "value".*' .. - '\d STOREG g:somevar.*' .. - 'unlet g:somevar.*' .. - '\d UNLET g:somevar.*' .. - 'unlet! g:somevar.*' .. - '\d UNLET! g:somevar.*' .. - 'unlet $SOMEVAR.*' .. - '\d UNLETENV $SOMEVAR.*', + assert_match('<SNR>\d*_ScriptFuncUnlet\_s*' .. + 'g:somevar = "value"\_s*' .. + '\d PUSHS "value"\_s*' .. + '\d STOREG g:somevar\_s*' .. + 'unlet g:somevar\_s*' .. + '\d UNLET g:somevar\_s*' .. + 'unlet! g:somevar\_s*' .. + '\d UNLET! g:somevar\_s*' .. + 'unlet $SOMEVAR\_s*' .. + '\d UNLETENV $SOMEVAR\_s*', res) enddef def s:ScriptFuncTry() try - echo 'yes' + echo "yes" catch /fail/ - echo 'no' + echo "no" finally - throw 'end' + throw "end" endtry enddef def Test_disassemble_try() let res = execute('disass s:ScriptFuncTry') - assert_match('<SNR>\d*_ScriptFuncTry.*' .. - 'try.*' .. - 'TRY catch -> \d\+, finally -> \d\+.*' .. - 'catch /fail/.*' .. - ' JUMP -> \d\+.*' .. - ' PUSH v:exception.*' .. - ' PUSHS "fail".*' .. - ' COMPARESTRING =\~.*' .. - ' JUMP_IF_FALSE -> \d\+.*' .. - ' CATCH.*' .. - 'finally.*' .. - ' PUSHS "end".*' .. - ' THROW.*' .. - 'endtry.*' .. - ' ENDTRY.*', + assert_match('<SNR>\d*_ScriptFuncTry\_s*' .. + 'try\_s*' .. + '\d TRY catch -> \d\+, finally -> \d\+\_s*' .. + 'echo "yes"\_s*' .. + '\d PUSHS "yes"\_s*' .. + '\d ECHO 1\_s*' .. + 'catch /fail/\_s*' .. + '\d JUMP -> \d\+\_s*' .. + '\d PUSH v:exception\_s*' .. + '\d PUSHS "fail"\_s*' .. + '\d COMPARESTRING =\~\_s*' .. + '\d JUMP_IF_FALSE -> \d\+\_s*' .. + '\d CATCH\_s*' .. + 'echo "no"\_s*' .. + '\d\+ PUSHS "no"\_s*' .. + '\d\+ ECHO 1\_s*' .. + 'finally\_s*' .. + 'throw "end"\_s*' .. + '\d\+ PUSHS "end"\_s*' .. + '\d\+ THROW\_s*' .. + 'endtry\_s*' .. + '\d\+ ENDTRY', res) enddef @@ -213,18 +251,19 @@ enddef def Test_disassemble_new() let res = execute('disass s:ScriptFuncNew') - assert_match('<SNR>\d*_ScriptFuncNew.*' .. - 'let ll = \[1, "two", 333].*' .. - 'PUSHNR 1.*' .. - 'PUSHS "two".*' .. - 'PUSHNR 333.*' .. - 'NEWLIST size 3.*' .. - 'let dd = #{one: 1, two: "val"}.*' .. - 'PUSHS "one".*' .. - 'PUSHNR 1.*' .. - 'PUSHS "two".*' .. - 'PUSHS "val".*' .. - 'NEWDICT size 2.*', + assert_match('<SNR>\d*_ScriptFuncNew\_s*' .. + 'let ll = \[1, "two", 333\]\_s*' .. + '\d PUSHNR 1\_s*' .. + '\d PUSHS "two"\_s*' .. + '\d PUSHNR 333\_s*' .. + '\d NEWLIST size 3\_s*' .. + '\d STORE $0\_s*' .. + 'let dd = #{one: 1, two: "val"}\_s*' .. + '\d PUSHS "one"\_s*' .. + '\d PUSHNR 1\_s*' .. + '\d PUSHS "two"\_s*' .. + '\d PUSHS "val"\_s*' .. + '\d NEWDICT size 2\_s*', res) enddef @@ -258,38 +297,54 @@ enddef def Test_disassemble_call() let res = execute('disass s:ScriptFuncCall') - assert_match('<SNR>\d\+_ScriptFuncCall.*' .. - 'changenr().*' .. - ' BCALL changenr(argc 0).*' .. - 'char2nr("abc").*' .. - ' PUSHS "abc".*' .. - ' BCALL char2nr(argc 1).*' .. - 'Test_disassemble_new().*' .. - ' DCALL Test_disassemble_new(argc 0).*' .. - 'FuncWithArg(343).*' .. - ' PUSHNR 343.*' .. - ' DCALL FuncWithArg(argc 1).*' .. - 'ScriptFuncNew().*' .. - ' DCALL <SNR>\d\+_ScriptFuncNew(argc 0).*' .. - 's:ScriptFuncNew().*' .. - ' DCALL <SNR>\d\+_ScriptFuncNew(argc 0).*' .. - 'UserFunc().*' .. - ' UCALL UserFunc(argc 0).*' .. - 'UserFuncWithArg("foo").*' .. - ' PUSHS "foo".*' .. - ' UCALL UserFuncWithArg(argc 1).*' .. - 'let FuncRef = function("UserFunc").*' .. - 'FuncRef().*' .. - ' LOAD $\d.*' .. - ' PCALL (argc 0).*' .. - 'let FuncRefWithArg = function("UserFuncWithArg").*' .. - 'FuncRefWithArg("bar").*' .. - ' PUSHS "bar".*' .. - ' LOAD $\d.*' .. - ' PCALL (argc 1).*' .. - 'return "yes".*' .. - ' PUSHS "yes".*' .. - ' RETURN.*', + assert_match('<SNR>\d\+_ScriptFuncCall\_s*' .. + 'changenr()\_s*' .. + '\d BCALL changenr(argc 0)\_s*' .. + '\d DROP\_s*' .. + 'char2nr("abc")\_s*' .. + '\d PUSHS "abc"\_s*' .. + '\d BCALL char2nr(argc 1)\_s*' .. + '\d DROP\_s*' .. + 'Test_disassemble_new()\_s*' .. + '\d DCALL Test_disassemble_new(argc 0)\_s*' .. + '\d DROP\_s*' .. + 'FuncWithArg(343)\_s*' .. + '\d\+ PUSHNR 343\_s*' .. + '\d\+ DCALL FuncWithArg(argc 1)\_s*' .. + '\d\+ DROP\_s*' .. + 'ScriptFuncNew()\_s*' .. + '\d\+ DCALL <SNR>\d\+_ScriptFuncNew(argc 0)\_s*' .. + '\d\+ DROP\_s*' .. + 's:ScriptFuncNew()\_s*' .. + '\d\+ DCALL <SNR>\d\+_ScriptFuncNew(argc 0)\_s*' .. + '\d\+ DROP\_s*' .. + 'UserFunc()\_s*' .. + '\d\+ UCALL UserFunc(argc 0)\_s*' .. + '\d\+ DROP\_s*' .. + 'UserFuncWithArg("foo")\_s*' .. + '\d\+ PUSHS "foo"\_s*' .. + '\d\+ UCALL UserFuncWithArg(argc 1)\_s*' .. + '\d\+ DROP\_s*' .. + 'let FuncRef = function("UserFunc")\_s*' .. + '\d\+ PUSHS "UserFunc"\_s*' .. + '\d\+ BCALL function(argc 1)\_s*' .. + '\d\+ STORE $0\_s*' .. + 'FuncRef()\_s*' .. + '\d\+ LOAD $\d\_s*' .. + '\d\+ PCALL (argc 0)\_s*' .. + '\d\+ DROP\_s*' .. + 'let FuncRefWithArg = function("UserFuncWithArg")\_s*' .. + '\d\+ PUSHS "UserFuncWithArg"\_s*' .. + '\d\+ BCALL function(argc 1)\_s*' .. + '\d\+ STORE $1\_s*' .. + 'FuncRefWithArg("bar")\_s*' .. + '\d\+ PUSHS "bar"\_s*' .. + '\d\+ LOAD $\d\_s*' .. + '\d\+ PCALL (argc 1)\_s*' .. + '\d\+ DROP\_s*' .. + 'return "yes"\_s*' .. + '\d\+ PUSHS "yes"\_s*' .. + '\d\+ RETURN', res) enddef @@ -308,21 +363,21 @@ enddef def Test_disassemble_closure() CreateRefs() let res = execute('disass g:Append') - assert_match('<lambda>\d.*' .. - 'local ..= arg.*' .. - '\d LOADOUTER $0.*' .. - '\d LOAD arg\[-1\].*' .. - '\d CONCAT.*' .. - '\d STOREOUTER $0.*' .. - '\d PUSHNR 0.*' .. - '\d RETURN.*', + assert_match('<lambda>\d\_s*' .. + 'local ..= arg\_s*' .. + '\d LOADOUTER $0\_s*' .. + '\d LOAD arg\[-1\]\_s*' .. + '\d CONCAT\_s*' .. + '\d STOREOUTER $0\_s*' .. + '\d PUSHNR 0\_s*' .. + '\d RETURN', res) res = execute('disass g:Get') - assert_match('<lambda>\d.*' .. - 'return local.*' .. - '\d LOADOUTER $0.*' .. - '\d RETURN.*', + assert_match('<lambda>\d\_s*' .. + 'return local\_s*' .. + '\d LOADOUTER $0\_s*' .. + '\d RETURN', res) unlet g:Append @@ -342,15 +397,15 @@ enddef def Test_disassemble_pcall() let res = execute('disass s:ScriptPCall') - assert_match('<SNR>\d\+_ScriptPCall.*' .. - 'RefThis()("text").*' .. - '\d DCALL RefThis(argc 0).*' .. - '\d PUSHS "text".*' .. - '\d PCALL top (argc 1).*' .. - '\d PCALL end.*' .. - '\d DROP.*' .. - '\d PUSHNR 0.*' .. - '\d RETURN.*', + assert_match('<SNR>\d\+_ScriptPCall\_s*' .. + 'RefThis()("text")\_s*' .. + '\d DCALL RefThis(argc 0)\_s*' .. + '\d PUSHS "text"\_s*' .. + '\d PCALL top (argc 1)\_s*' .. + '\d PCALL end\_s*' .. + '\d DROP\_s*' .. + '\d PUSHNR 0\_s*' .. + '\d RETURN', res) enddef @@ -365,24 +420,24 @@ enddef def Test_disassemble_update_instr() let res = execute('disass s:FuncWithForwardCall') - assert_match('FuncWithForwardCall.*' .. - 'return g:DefinedLater("yes").*' .. - '\d PUSHS "yes".*' .. - '\d UCALL g:DefinedLater(argc 1).*' .. - '\d CHECKTYPE string stack\[-1].*' .. - '\d RETURN.*', + assert_match('FuncWithForwardCall\_s*' .. + 'return g:DefinedLater("yes")\_s*' .. + '\d PUSHS "yes"\_s*' .. + '\d UCALL g:DefinedLater(argc 1)\_s*' .. + '\d CHECKTYPE string stack\[-1]\_s*' .. + '\d RETURN', res) " Calling the function will change UCALL into the faster DCALL assert_equal('yes', FuncWithForwardCall()) res = execute('disass s:FuncWithForwardCall') - assert_match('FuncWithForwardCall.*' .. - 'return g:DefinedLater("yes").*' .. - '\d PUSHS "yes".*' .. - '\d DCALL DefinedLater(argc 1).*' .. - '\d CHECKTYPE string stack\[-1].*' .. - '\d RETURN.*', + assert_match('FuncWithForwardCall\_s*' .. + 'return g:DefinedLater("yes")\_s*' .. + '\d PUSHS "yes"\_s*' .. + '\d DCALL DefinedLater(argc 1)\_s*' .. + '\d CHECKTYPE string stack\[-1]\_s*' .. + '\d RETURN', res) enddef @@ -393,12 +448,12 @@ enddef def Test_disassemble_call_default() let res = execute('disass FuncWithDefault') - assert_match('FuncWithDefault.*' .. - '\d PUSHS "default".*' .. - '\d STORE arg\[-1].*' .. - 'return arg.*' .. - '\d LOAD arg\[-1].*' .. - '\d RETURN.*', + assert_match('FuncWithDefault\_s*' .. + '\d PUSHS "default"\_s*' .. + '\d STORE arg\[-1]\_s*' .. + 'return arg\_s*' .. + '\d LOAD arg\[-1]\_s*' .. + '\d RETURN', res) enddef @@ -434,18 +489,27 @@ enddef def Test_disassemble_const_expr() assert_equal("\nyes", execute('call HasEval()')) let instr = execute('disassemble HasEval') - assert_match('HasEval.*' .. - 'if has("eval").*' .. - ' PUSHS "yes".*', + assert_match('HasEval\_s*' .. + 'if has("eval")\_s*' .. + 'echo "yes"\_s*' .. + '\d PUSHS "yes"\_s*' .. + '\d ECHO 1\_s*' .. + 'else\_s*' .. + 'echo "no"\_s*' .. + 'endif\_s*', instr) assert_notmatch('JUMP', instr) assert_equal("\nno", execute('call HasNothing()')) instr = execute('disassemble HasNothing') - assert_match('HasNothing.*' .. - 'if has("nothing").*' .. - 'else.*' .. - ' PUSHS "no".*', + assert_match('HasNothing\_s*' .. + 'if has("nothing")\_s*' .. + 'echo "yes"\_s*' .. + 'else\_s*' .. + 'echo "no"\_s*' .. + '\d PUSHS "no"\_s*' .. + '\d ECHO 1\_s*' .. + 'endif', instr) assert_notmatch('PUSHS "yes"', instr) assert_notmatch('JUMP', instr) @@ -453,11 +517,17 @@ def Test_disassemble_const_expr() assert_equal("\neval", execute('call HasSomething()')) instr = execute('disassemble HasSomething') assert_match('HasSomething.*' .. - 'if has("nothing").*' .. - 'elseif has("something").*' .. - 'elseif has("eval").*' .. - ' PUSHS "eval".*' .. - 'elseif has("less").*', + 'if has("nothing")\_s*' .. + 'echo "nothing"\_s*' .. + 'elseif has("something")\_s*' .. + 'echo "something"\_s*' .. + 'elseif has("eval")\_s*' .. + 'echo "eval"\_s*' .. + '\d PUSHS "eval"\_s*' .. + '\d ECHO 1\_s*' .. + 'elseif has("less").*' .. + 'echo "less"\_s*' .. + 'endif', instr) assert_notmatch('PUSHS "nothing"', instr) assert_notmatch('PUSHS "something"', instr) @@ -473,20 +543,20 @@ enddef def Test_disassemble_function() let instr = execute('disassemble WithFunc') - assert_match('WithFunc.*' .. - 'let Funky1: func.*' .. - '0 PUSHFUNC "\[none]".*' .. - '1 STORE $0.*' .. - 'let Funky2: func = function("len").*' .. - '2 PUSHS "len".*' .. - '3 BCALL function(argc 1).*' .. - '4 STORE $1.*' .. - 'let Party2: func = funcref("UserFunc").*' .. - '\d PUSHS "UserFunc".*' .. - '\d BCALL funcref(argc 1).*' .. - '\d STORE $2.*' .. - '\d PUSHNR 0.*' .. - '\d RETURN.*', + assert_match('WithFunc\_s*' .. + 'let Funky1: func\_s*' .. + '0 PUSHFUNC "\[none]"\_s*' .. + '1 STORE $0\_s*' .. + 'let Funky2: func = function("len")\_s*' .. + '2 PUSHS "len"\_s*' .. + '3 BCALL function(argc 1)\_s*' .. + '4 STORE $1\_s*' .. + 'let Party2: func = funcref("UserFunc")\_s*' .. + '\d PUSHS "UserFunc"\_s*' .. + '\d BCALL funcref(argc 1)\_s*' .. + '\d STORE $2\_s*' .. + '\d PUSHNR 0\_s*' .. + '\d RETURN', instr) enddef @@ -502,19 +572,19 @@ def Test_disassemble_channel() CheckFeature channel let instr = execute('disassemble WithChannel') - assert_match('WithChannel.*' .. - 'let job1: job.*' .. - '\d PUSHJOB "no process".*' .. - '\d STORE $0.*' .. - 'let job2: job = job_start("donothing").*' .. - '\d PUSHS "donothing".*' .. - '\d BCALL job_start(argc 1).*' .. - '\d STORE $1.*' .. - 'let chan1: channel.*' .. - '\d PUSHCHANNEL 0.*' .. - '\d STORE $2.*' .. - '\d PUSHNR 0.*' .. - '\d RETURN.*', + assert_match('WithChannel\_s*' .. + 'let job1: job\_s*' .. + '\d PUSHJOB "no process"\_s*' .. + '\d STORE $0\_s*' .. + 'let job2: job = job_start("donothing")\_s*' .. + '\d PUSHS "donothing"\_s*' .. + '\d BCALL job_start(argc 1)\_s*' .. + '\d STORE $1\_s*' .. + 'let chan1: channel\_s*' .. + '\d PUSHCHANNEL 0\_s*' .. + '\d STORE $2\_s*' .. + '\d PUSHNR 0\_s*' .. + '\d RETURN', instr) enddef @@ -526,13 +596,15 @@ enddef def Test_disassemble_lambda() assert_equal("XxX", WithLambda()) let instr = execute('disassemble WithLambda') - assert_match('WithLambda.*' .. - 'let F = {a -> "X" .. a .. "X"}.*' .. - ' FUNCREF <lambda>\d\+.*' .. - 'PUSHS "x".*' .. - ' LOAD $0.*' .. - ' PCALL (argc 1).*' .. - ' CHECKTYPE string stack\[-1].*', + assert_match('WithLambda\_s*' .. + 'let F = {a -> "X" .. a .. "X"}\_s*' .. + '\d FUNCREF <lambda>\d\+ $1\_s*' .. + '\d STORE $0\_s*' .. + 'return F("x")\_s*' .. + '\d PUSHS "x"\_s*' .. + '\d LOAD $0\_s*' .. + '\d PCALL (argc 1)\_s*' .. + '\d CHECKTYPE string stack\[-1]', instr) enddef @@ -548,20 +620,20 @@ def Test_disassemble_and_or() assert_equal("no", AndOr(2)) assert_equal("yes", AndOr(4)) let instr = execute('disassemble AndOr') - assert_match('AndOr.*' .. - 'if arg == 1 && arg != 2 || arg == 4.*' .. - '\d LOAD arg\[-1].*' .. - '\d PUSHNR 1.*' .. - '\d COMPAREANY ==.*' .. - '\d JUMP_AND_KEEP_IF_FALSE -> \d\+.*' .. - '\d LOAD arg\[-1].*' .. - '\d PUSHNR 2.*' .. - '\d COMPAREANY !=.*' .. - '\d JUMP_AND_KEEP_IF_TRUE -> \d\+.*' .. - '\d LOAD arg\[-1].*' .. - '\d PUSHNR 4.*' .. - '\d COMPAREANY ==.*' .. - '\d JUMP_IF_FALSE -> \d\+.*', + assert_match('AndOr\_s*' .. + 'if arg == 1 && arg != 2 || arg == 4\_s*' .. + '\d LOAD arg\[-1]\_s*' .. + '\d PUSHNR 1\_s*' .. + '\d COMPAREANY ==\_s*' .. + '\d JUMP_AND_KEEP_IF_FALSE -> \d\+\_s*' .. + '\d LOAD arg\[-1]\_s*' .. + '\d PUSHNR 2\_s*' .. + '\d COMPAREANY !=\_s*' .. + '\d JUMP_AND_KEEP_IF_TRUE -> \d\+\_s*' .. + '\d LOAD arg\[-1]\_s*' .. + '\d\+ PUSHNR 4\_s*' .. + '\d\+ COMPAREANY ==\_s*' .. + '\d\+ JUMP_IF_FALSE -> \d\+', instr) enddef @@ -576,24 +648,24 @@ enddef def Test_disassemble_for_loop() assert_equal([0, 1, 2], ForLoop()) let instr = execute('disassemble ForLoop') - assert_match('ForLoop.*' .. - 'let res: list<number>.*' .. - ' NEWLIST size 0.*' .. - '\d STORE $0.*' .. - 'for i in range(3).*' .. - '\d STORE -1 in $1.*' .. - '\d PUSHNR 3.*' .. - '\d BCALL range(argc 1).*' .. - '\d FOR $1 -> \d\+.*' .. - '\d STORE $2.*' .. - 'res->add(i).*' .. - '\d LOAD $0.*' .. - '\d LOAD $2.*' .. - '\d BCALL add(argc 2).*' .. - '\d DROP.*' .. - 'endfor.*' .. - '\d JUMP -> \d\+.*' .. - '\d DROP.*', + assert_match('ForLoop\_s*' .. + 'let res: list<number>\_s*' .. + '\d NEWLIST size 0\_s*' .. + '\d STORE $0\_s*' .. + 'for i in range(3)\_s*' .. + '\d STORE -1 in $1\_s*' .. + '\d PUSHNR 3\_s*' .. + '\d BCALL range(argc 1)\_s*' .. + '\d FOR $1 -> \d\+\_s*' .. + '\d STORE $2\_s*' .. + 'res->add(i)\_s*' .. + '\d LOAD $0\_s*' .. + '\d LOAD $2\_s*' .. + '\d\+ BCALL add(argc 2)\_s*' .. + '\d\+ DROP\_s*' .. + 'endfor\_s*' .. + '\d\+ JUMP -> \d\+\_s*' .. + '\d\+ DROP', instr) enddef diff --git a/src/version.c b/src/version.c index 061844786f..47b276b580 100644 --- a/src/version.c +++ b/src/version.c @@ -746,6 +746,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 758, /**/ 757, /**/ From 270d0388d284c130b322b185497e437cfbbae412 Mon Sep 17 00:00:00 2001 From: Bram Moolenaar <Bram@vim.org> Date: Fri, 15 May 2020 21:42:53 +0200 Subject: [PATCH 157/230] patch 8.2.0759: Vim9: missing changes for performance improvements Problem: Vim9: missing changes for performance improvements Solution: Use GA_GROW(). Don't call breakcheck so often. --- src/version.c | 2 ++ src/vim9execute.c | 43 ++++++++++++++++++++++++------------------- 2 files changed, 26 insertions(+), 19 deletions(-) diff --git a/src/version.c b/src/version.c index 47b276b580..1eb94bdd25 100644 --- a/src/version.c +++ b/src/version.c @@ -746,6 +746,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 759, /**/ 758, /**/ diff --git a/src/vim9execute.c b/src/vim9execute.c index 4356e2a95a..dcc982805e 100644 --- a/src/vim9execute.c +++ b/src/vim9execute.c @@ -128,7 +128,7 @@ exe_newlist(int count, ectx_T *ectx) if (count > 0) ectx->ec_stack.ga_len -= count - 1; - else if (ga_grow(&ectx->ec_stack, 1) == FAIL) + else if (GA_GROW(&ectx->ec_stack, 1) == FAIL) return FAIL; else ++ectx->ec_stack.ga_len; @@ -437,7 +437,7 @@ call_prepare(int argcount, typval_T *argvars, ectx_T *ectx) // Result replaces the arguments on the stack. if (argcount > 0) ectx->ec_stack.ga_len -= argcount - 1; - else if (ga_grow(&ectx->ec_stack, 1) == FAIL) + else if (GA_GROW(&ectx->ec_stack, 1) == FAIL) return FAIL; else ++ectx->ec_stack.ga_len; @@ -651,6 +651,7 @@ call_def_function( int ret = FAIL; int defcount = ufunc->uf_args.ga_len - argc; int save_sc_version = current_sctx.sc_version; + int breakcheck_count = 0; // Get pointer to item in the stack. #define STACK_TV(idx) (((typval_T *)ectx.ec_stack.ga_data) + idx) @@ -749,7 +750,11 @@ call_def_function( { isn_T *iptr; - veryfast_breakcheck(); + if (++breakcheck_count >= 100) + { + line_breakcheck(); + breakcheck_count = 0; + } if (got_int) { // Turn CTRL-C into an exception. @@ -790,7 +795,7 @@ call_def_function( if (ectx.ec_frame_idx == initial_frame_idx) { // At the toplevel we are done. Push a dummy return value. - if (ga_grow(&ectx.ec_stack, 1) == FAIL) + if (GA_GROW(&ectx.ec_stack, 1) == FAIL) goto failed; tv = STACK_TV_BOT(0); tv->v_type = VAR_NUMBER; @@ -942,7 +947,7 @@ call_def_function( // load local variable or argument case ISN_LOAD: - if (ga_grow(&ectx.ec_stack, 1) == FAIL) + if (GA_GROW(&ectx.ec_stack, 1) == FAIL) goto failed; copy_tv(STACK_TV_VAR(iptr->isn_arg.number), STACK_TV_BOT(0)); ++ectx.ec_stack.ga_len; @@ -950,7 +955,7 @@ call_def_function( // load variable or argument from outer scope case ISN_LOADOUTER: - if (ga_grow(&ectx.ec_stack, 1) == FAIL) + if (GA_GROW(&ectx.ec_stack, 1) == FAIL) goto failed; copy_tv(STACK_OUT_TV_VAR(iptr->isn_arg.number), STACK_TV_BOT(0)); @@ -959,7 +964,7 @@ call_def_function( // load v: variable case ISN_LOADV: - if (ga_grow(&ectx.ec_stack, 1) == FAIL) + if (GA_GROW(&ectx.ec_stack, 1) == FAIL) goto failed; copy_tv(get_vim_var_tv(iptr->isn_arg.number), STACK_TV_BOT(0)); ++ectx.ec_stack.ga_len; @@ -974,7 +979,7 @@ call_def_function( sv = ((svar_T *)si->sn_var_vals.ga_data) + iptr->isn_arg.script.script_idx; - if (ga_grow(&ectx.ec_stack, 1) == FAIL) + if (GA_GROW(&ectx.ec_stack, 1) == FAIL) goto failed; copy_tv(sv->sv_tv, STACK_TV_BOT(0)); ++ectx.ec_stack.ga_len; @@ -996,7 +1001,7 @@ call_def_function( } else { - if (ga_grow(&ectx.ec_stack, 1) == FAIL) + if (GA_GROW(&ectx.ec_stack, 1) == FAIL) goto failed; copy_tv(&di->di_tv, STACK_TV_BOT(0)); ++ectx.ec_stack.ga_len; @@ -1044,7 +1049,7 @@ call_def_function( } else { - if (ga_grow(&ectx.ec_stack, 1) == FAIL) + if (GA_GROW(&ectx.ec_stack, 1) == FAIL) goto failed; copy_tv(&di->di_tv, STACK_TV_BOT(0)); ++ectx.ec_stack.ga_len; @@ -1060,7 +1065,7 @@ call_def_function( // This is not expected to fail, name is checked during // compilation: don't set SOURCING_LNUM. - if (ga_grow(&ectx.ec_stack, 1) == FAIL) + if (GA_GROW(&ectx.ec_stack, 1) == FAIL) goto failed; if (get_option_tv(&name, &optval, TRUE) == FAIL) goto failed; @@ -1075,7 +1080,7 @@ call_def_function( typval_T optval; char_u *name = iptr->isn_arg.string; - if (ga_grow(&ectx.ec_stack, 1) == FAIL) + if (GA_GROW(&ectx.ec_stack, 1) == FAIL) goto failed; // name is always valid, checked when compiling (void)get_env_tv(&name, &optval, TRUE); @@ -1086,7 +1091,7 @@ call_def_function( // load @register case ISN_LOADREG: - if (ga_grow(&ectx.ec_stack, 1) == FAIL) + if (GA_GROW(&ectx.ec_stack, 1) == FAIL) goto failed; tv = STACK_TV_BOT(0); tv->v_type = VAR_STRING; @@ -1334,7 +1339,7 @@ call_def_function( case ISN_PUSHFUNC: case ISN_PUSHCHANNEL: case ISN_PUSHJOB: - if (ga_grow(&ectx.ec_stack, 1) == FAIL) + if (GA_GROW(&ectx.ec_stack, 1) == FAIL) goto failed; tv = STACK_TV_BOT(0); ++ectx.ec_stack.ga_len; @@ -1434,7 +1439,7 @@ call_def_function( if (count > 0) ectx.ec_stack.ga_len -= 2 * count - 1; - else if (ga_grow(&ectx.ec_stack, 1) == FAIL) + else if (GA_GROW(&ectx.ec_stack, 1) == FAIL) goto failed; else ++ectx.ec_stack.ga_len; @@ -1554,7 +1559,7 @@ call_def_function( pt = ALLOC_CLEAR_ONE(partial_T); if (pt == NULL) goto failed; - if (ga_grow(&ectx.ec_stack, 1) == FAIL) + if (GA_GROW(&ectx.ec_stack, 1) == FAIL) { vim_free(pt); goto failed; @@ -1632,7 +1637,7 @@ call_def_function( STACK_TV_VAR(iptr->isn_arg.forloop.for_idx); // push the next item from the list - if (ga_grow(&ectx.ec_stack, 1) == FAIL) + if (GA_GROW(&ectx.ec_stack, 1) == FAIL) goto failed; if (++idxtv->vval.v_number >= list->lv_len) // past the end of the list, jump to "endfor" @@ -1663,7 +1668,7 @@ call_def_function( { trycmd_T *trycmd = NULL; - if (ga_grow(&ectx.ec_trystack, 1) == FAIL) + if (GA_GROW(&ectx.ec_trystack, 1) == FAIL) goto failed; trycmd = ((trycmd_T *)ectx.ec_trystack.ga_data) + ectx.ec_trystack.ga_len; @@ -1682,7 +1687,7 @@ call_def_function( iemsg("Evaluating catch while current_exception is NULL"); goto failed; } - if (ga_grow(&ectx.ec_stack, 1) == FAIL) + if (GA_GROW(&ectx.ec_stack, 1) == FAIL) goto failed; tv = STACK_TV_BOT(0); ++ectx.ec_stack.ga_len; From 4dac32caf38f7c35b707b7df104df03591bf6b14 Mon Sep 17 00:00:00 2001 From: Bram Moolenaar <Bram@vim.org> Date: Fri, 15 May 2020 21:44:19 +0200 Subject: [PATCH 158/230] patch 8.2.0760: Vim9: dict member errors not tested Problem: Vim9: dict member errors not tested. Solution: Delete unreachable error. Add tests. --- src/testdir/test_vim9_expr.vim | 4 ++++ src/version.c | 2 ++ src/vim9execute.c | 13 +++---------- 3 files changed, 9 insertions(+), 10 deletions(-) diff --git a/src/testdir/test_vim9_expr.vim b/src/testdir/test_vim9_expr.vim index 6e8278850f..8b937dc722 100644 --- a/src/testdir/test_vim9_expr.vim +++ b/src/testdir/test_vim9_expr.vim @@ -799,8 +799,12 @@ enddef def Test_expr_member() assert_equal(1, g:dict_one.one) + let d: dict<number> = g:dict_one + assert_equal(1, d['one']) call CheckDefFailure(["let x = g:dict_one.#$!"], 'E1002:') + call CheckDefExecFailure(["let d: dict<any>", "echo d['a']"], 'E716:') + call CheckDefExecFailure(["let d: dict<number>", "d = g:list_empty"], 'E1029: Expected dict but got list') enddef def Test_expr7_option() diff --git a/src/version.c b/src/version.c index 1eb94bdd25..d447c4b280 100644 --- a/src/version.c +++ b/src/version.c @@ -746,6 +746,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 760, /**/ 759, /**/ diff --git a/src/vim9execute.c b/src/vim9execute.c index dcc982805e..f50f8c6e10 100644 --- a/src/vim9execute.c +++ b/src/vim9execute.c @@ -2104,20 +2104,13 @@ call_def_function( // dict member: dict is at stack-2, key at stack-1 tv = STACK_TV_BOT(-2); - if (tv->v_type != VAR_DICT) - { - emsg(_(e_dictreq)); - goto failed; - } + // no need to check for VAR_DICT, CHECKTYPE will check. dict = tv->vval.v_dict; tv = STACK_TV_BOT(-1); - if (tv->v_type != VAR_STRING) - { - emsg(_(e_stringreq)); - goto failed; - } + // no need to check for VAR_STRING, 2STRING will check. key = tv->vval.v_string; + if ((di = dict_find(dict, key, -1)) == NULL) { semsg(_(e_dictkey), key); From 4aeeb6393824e375afad4d7291e8552917ad28b8 Mon Sep 17 00:00:00 2001 From: Bram Moolenaar <Bram@vim.org> Date: Fri, 15 May 2020 22:01:57 +0200 Subject: [PATCH 159/230] patch 8.2.0761: Vim9: instructions not tested Problem: Vim9: instructions not tested Solution: Use a variable instead of a constant. --- src/testdir/test_vim9_expr.vim | 72 ++++++++++++++++++++-------------- src/version.c | 2 + 2 files changed, 44 insertions(+), 30 deletions(-) diff --git a/src/testdir/test_vim9_expr.vim b/src/testdir/test_vim9_expr.vim index 8b937dc722..6fabf0c9f7 100644 --- a/src/testdir/test_vim9_expr.vim +++ b/src/testdir/test_vim9_expr.vim @@ -170,15 +170,18 @@ def Test_expr4_equal() assert_equal(false, 61 == g:anint) if has('float') - assert_equal(true, 0.3 == 0.3) - assert_equal(false, 0.4 == 0.3) + let ff = 0.3 + assert_equal(true, ff == 0.3) + assert_equal(false, 0.4 == ff) assert_equal(true, 0.1 == g:afloat) assert_equal(false, g:afloat == 0.3) - assert_equal(true, 3.0 == 3) - assert_equal(true, 3 == 3.0) - assert_equal(false, 3.1 == 3) - assert_equal(false, 3 == 3.1) + ff = 3.0 + assert_equal(true, ff == 3) + assert_equal(true, 3 == ff) + ff = 3.1 + assert_equal(false, ff == 3) + assert_equal(false, 3 == ff) endif assert_equal(true, 'abc' == 'abc') @@ -198,8 +201,9 @@ def Test_expr4_equal() call CheckDefFailure(["let x = 'a' == xxx"], 'E1001:') - assert_equal(true, 0z3f == 0z3f) - assert_equal(false, 0z3f == 0z4f) + let bb = 0z3f + assert_equal(true, 0z3f == bb) + assert_equal(false, bb == 0z4f) assert_equal(true, g:ablob == 0z01ab) assert_equal(false, 0z3f == g:ablob) @@ -250,15 +254,18 @@ def Test_expr4_notequal() assert_equal(true, 61 != g:anint) if has('float') - assert_equal(false, 0.3 != 0.3) - assert_equal(true, 0.4 != 0.3) + let ff = 0.3 + assert_equal(false, 0.3 != ff) + assert_equal(true, 0.4 != ff) assert_equal(false, 0.1 != g:afloat) assert_equal(true, g:afloat != 0.3) - assert_equal(false, 3.0 != 3) - assert_equal(false, 3 != 3.0) - assert_equal(true, 3.1 != 3) - assert_equal(true, 3 != 3.1) + ff = 3.0 + assert_equal(false, ff != 3) + assert_equal(false, 3 != ff) + ff = 3.1 + assert_equal(true, ff != 3) + assert_equal(true, 3 != ff) endif assert_equal(false, 'abc' != 'abc') @@ -271,8 +278,9 @@ def Test_expr4_notequal() assert_equal(true, 'abc' != 'ABC') set noignorecase - assert_equal(false, 0z3f != 0z3f) - assert_equal(true, 0z3f != 0z4f) + let bb = 0z3f + assert_equal(false, 0z3f != bb) + assert_equal(true, bb != 0z4f) assert_equal(false, g:ablob != 0z01ab) assert_equal(true, 0z3f != g:ablob) @@ -306,10 +314,11 @@ def Test_expr4_greater() assert_false(2 > 2) assert_false(2 > 3) if has('float') - assert_true(2.0 > 0.0) - assert_true(2.0 > 1.0) - assert_false(2.0 > 2.0) - assert_false(2.0 > 3.0) + let ff = 2.0 + assert_true(ff > 0.0) + assert_true(ff > 1.0) + assert_false(ff > 2.0) + assert_false(ff > 3.0) endif enddef @@ -320,9 +329,10 @@ def Test_expr4_greaterequal() 2) assert_false(2 >= 3) if has('float') - assert_true(2.0 >= 0.0) - assert_true(2.0 >= 2.0) - assert_false(2.0 >= 3.0) + let ff = 2.0 + assert_true(ff >= 0.0) + assert_true(ff >= 2.0) + assert_false(ff >= 3.0) endif enddef @@ -333,9 +343,10 @@ def Test_expr4_smaller() 2) assert_true(2 < 3) if has('float') - assert_false(2.0 < 0.0) - assert_false(2.0 < 2.0) - assert_true(2.0 < 3.0) + let ff = 2.0 + assert_false(ff < 0.0) + assert_false(ff < 2.0) + assert_true(ff < 3.0) endif enddef @@ -347,10 +358,11 @@ def Test_expr4_smallerequal() assert_true(2 <= 2) assert_true(2 <= 3) if has('float') - assert_false(2.0 <= 0.0) - assert_false(2.0 <= 1.0) - assert_true(2.0 <= 2.0) - assert_true(2.0 <= 3.0) + let ff = 2.0 + assert_false(ff <= 0.0) + assert_false(ff <= 1.0) + assert_true(ff <= 2.0) + assert_true(ff <= 3.0) endif enddef diff --git a/src/version.c b/src/version.c index d447c4b280..c631d54fec 100644 --- a/src/version.c +++ b/src/version.c @@ -746,6 +746,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 761, /**/ 760, /**/ From 76cb68309794def0fa7d1f2f72dd694b822186a5 Mon Sep 17 00:00:00 2001 From: Bram Moolenaar <Bram@vim.org> Date: Fri, 15 May 2020 22:30:38 +0200 Subject: [PATCH 160/230] patch 8.2.0762: buffer is not considered modified after setting crypt key Problem: Buffer is not considered modified after setting crypt key. Solution: Set the modified flag. (Christian Brabandt, closes #6082) --- src/optionstr.c | 3 +++ src/testdir/test_crypt.vim | 26 ++++++++++++++++++++++++++ src/version.c | 2 ++ 3 files changed, 31 insertions(+) diff --git a/src/optionstr.c b/src/optionstr.c index 17613a6567..ff0186f429 100644 --- a/src/optionstr.c +++ b/src/optionstr.c @@ -1157,8 +1157,11 @@ did_set_string_option( if (STRCMP(curbuf->b_p_key, oldval) != 0) // Need to update the swapfile. + { ml_set_crypt_key(curbuf, oldval, *curbuf->b_p_cm == NUL ? p_cm : curbuf->b_p_cm); + changed_internal(); + } } else if (gvarp == &p_cm) diff --git a/src/testdir/test_crypt.vim b/src/testdir/test_crypt.vim index ab62d84708..fa26ba5501 100644 --- a/src/testdir/test_crypt.vim +++ b/src/testdir/test_crypt.vim @@ -110,3 +110,29 @@ func Test_crypt_key_mismatch() bwipe! endfunc +func Test_crypt_set_key_changes_buffer() + + new Xtest1.txt + call setline(1, 'nothing') + set cryptmethod=blowfish2 + call feedkeys(":X\<CR>foobar\<CR>foobar\<CR>", 'xt') + call assert_fails(":q", "E37:") + w + set key=anotherkey + call assert_fails(":bw") + w + call feedkeys(":X\<CR>foobar\<CR>foobar\<CR>", 'xt') + call assert_fails(":bw") + w + let winnr = winnr() + wincmd p + call setwinvar(winnr, '&key', 'yetanotherkey') + wincmd p + call assert_fails(":bw") + w + + set cryptmethod& + set key= + bwipe! + call delete('Xtest1.txt') +endfunc diff --git a/src/version.c b/src/version.c index c631d54fec..90773d3f9a 100644 --- a/src/version.c +++ b/src/version.c @@ -746,6 +746,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 762, /**/ 761, /**/ From 4457e1d98f78152311495b1aff6169383d330a75 Mon Sep 17 00:00:00 2001 From: Bram Moolenaar <Bram@vim.org> Date: Fri, 15 May 2020 22:46:44 +0200 Subject: [PATCH 161/230] patch 8.2.0763: GUI test fails without the terminal feature Problem: GUI test fails without the terminal feature. Solution: Check the terminal feature is supported. (Ken Takata, closes #6084) --- src/testdir/test_gui.vim | 1 + src/version.c | 2 ++ 2 files changed, 3 insertions(+) diff --git a/src/testdir/test_gui.vim b/src/testdir/test_gui.vim index 64b24bfc79..28782f00c0 100644 --- a/src/testdir/test_gui.vim +++ b/src/testdir/test_gui.vim @@ -841,6 +841,7 @@ endfunc " Test for "!" option in 'guioptions'. Use a terminal for running external " commands func Test_gui_run_cmd_in_terminal() + CheckFeature terminal let save_guioptions = &guioptions set guioptions+=! if has('win32') diff --git a/src/version.c b/src/version.c index 90773d3f9a..94db9b888d 100644 --- a/src/version.c +++ b/src/version.c @@ -746,6 +746,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 763, /**/ 762, /**/ From a6e67e4f41386c3e6eab7e047671c6d32f6cb0dc Mon Sep 17 00:00:00 2001 From: Bram Moolenaar <Bram@vim.org> Date: Fri, 15 May 2020 23:36:40 +0200 Subject: [PATCH 162/230] patch 8.2.0764: Vim9: assigning to option not fully tested Problem: Vim9: assigning to option not fully tested. Solution: Add more test cases. Allow using any type for assignment. --- src/testdir/test_vim9_script.vim | 7 +++++++ src/version.c | 2 ++ src/vim9compile.c | 6 +++--- src/vim9execute.c | 8 ++------ 4 files changed, 14 insertions(+), 9 deletions(-) diff --git a/src/testdir/test_vim9_script.vim b/src/testdir/test_vim9_script.vim index fd1dbc8c2f..4284aada24 100644 --- a/src/testdir/test_vim9_script.vim +++ b/src/testdir/test_vim9_script.vim @@ -14,6 +14,8 @@ let s:addToMe = 111 let g:existing = 'yes' let g:inc_counter = 1 let $SOME_ENV_VAR = 'some' +let g:alist = [7] +let g:astring = 'text' def Test_assignment() let bool1: bool = true @@ -95,7 +97,12 @@ def Test_assignment() assert_equal(2, &ts) call CheckDefFailure(['¬ex += 3'], 'E113:') call CheckDefFailure(['&ts ..= "xxx"'], 'E1019:') + call CheckDefFailure(['&ts = [7]'], 'E1013:') + call CheckDefExecFailure(['&ts = g:alist'], 'E1029: Expected number but got list') + call CheckDefFailure(['&ts = "xx"'], 'E1013:') + call CheckDefExecFailure(['&ts = g:astring'], 'E1029: Expected number but got string') call CheckDefFailure(['&path += 3'], 'E1013:') + call CheckDefExecFailure(['&bs = "asdf"'], 'E474:') # test freeing ISN_STOREOPT call CheckDefFailure(['&ts = 3', 'let asdf'], 'E1022:') &ts = 8 diff --git a/src/version.c b/src/version.c index 94db9b888d..b361dedf08 100644 --- a/src/version.c +++ b/src/version.c @@ -746,6 +746,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 764, /**/ 763, /**/ diff --git a/src/vim9compile.c b/src/vim9compile.c index 4b294df298..416198a0c4 100644 --- a/src/vim9compile.c +++ b/src/vim9compile.c @@ -3490,7 +3490,7 @@ compile_subscript( type_T **typep; // list index: list[123] - // list member: dict[key] + // dict member: dict[key] // TODO: blob index // TODO: more arguments // TODO: recognize list or dict at runtime @@ -4999,8 +4999,8 @@ compile_assignment(char_u *arg, exarg_T *eap, cmdidx_T cmdidx, cctx_T *cctx) goto theend; } } - else if (*p != '=' && check_type(member_type, stacktype, TRUE) - == FAIL) + else if (*p != '=' && need_type(stacktype, member_type, -1, + cctx) == FAIL) goto theend; } } diff --git a/src/vim9execute.c b/src/vim9execute.c index f50f8c6e10..398c94c42a 100644 --- a/src/vim9execute.c +++ b/src/vim9execute.c @@ -1164,13 +1164,9 @@ call_def_function( if (s == NULL) s = (char_u *)""; } - else if (tv->v_type == VAR_NUMBER) - n = tv->vval.v_number; else - { - emsg(_("E1051: Expected string or number")); - goto failed; - } + // must be VAR_NUMBER, CHECKTYPE makes sure + n = tv->vval.v_number; msg = set_option_value(iptr->isn_arg.storeopt.so_name, n, s, iptr->isn_arg.storeopt.so_flags); if (msg != NULL) From fd615a3c901f59abddca27c6a09940be552c0f4d Mon Sep 17 00:00:00 2001 From: Bram Moolenaar <Bram@vim.org> Date: Sat, 16 May 2020 14:01:51 +0200 Subject: [PATCH 163/230] patch 8.2.0765: In the GUI can't use all the modifiers. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Problem: In the GUI can't use all the modifiers. (Andri Möll) Solution: Do not apply Alt/Meta early, do it later like with the terminal. Avoid the Motif test from crashing. --- src/gui_gtk_x11.c | 109 +++++++++++------------------------ src/gui_mac.c | 4 +- src/gui_motif.c | 3 + src/gui_w32.c | 4 +- src/gui_x11.c | 143 ++++++++++++++-------------------------------- src/version.c | 2 + 6 files changed, 85 insertions(+), 180 deletions(-) diff --git a/src/gui_gtk_x11.c b/src/gui_gtk_x11.c index ea43c93850..02526b2726 100644 --- a/src/gui_gtk_x11.c +++ b/src/gui_gtk_x11.c @@ -1212,39 +1212,9 @@ key_press_event(GtkWidget *widget UNUSED, return FALSE; #endif - // Check for Alt/Meta key (Mod1Mask), but not for a BS, DEL or character - // that already has the 8th bit set. - // Don't do this for <S-M-Tab>, that should become K_S_TAB with ALT. - // Don't do this for double-byte encodings, it turns the char into a lead - // byte. - if (len == 1 - && ((state & GDK_MOD1_MASK) -#if GTK_CHECK_VERSION(2,10,0) - || (state & GDK_SUPER_MASK) -#endif - ) - && !(key_sym == GDK_BackSpace || key_sym == GDK_Delete) - && (string[0] & 0x80) == 0 - && !(key_sym == GDK_Tab && (state & GDK_SHIFT_MASK)) - && !enc_dbcs - ) - { - string[0] |= 0x80; - state &= ~GDK_MOD1_MASK; // don't use it again - if (enc_utf8) // convert to utf-8 - { - string[1] = string[0] & 0xbf; - string[0] = ((unsigned)string[0] >> 6) + 0xc0; - if (string[1] == CSI) - { - string[2] = KS_EXTRA; - string[3] = (int)KE_CSI; - len = 4; - } - else - len = 2; - } - } + // We used to apply Alt/Meta to the key here (Mod1Mask), but that is now + // done later, the same as it happens for the terminal. Hopefully that + // works for everybody... // Check for special keys. Also do this when len == 1 (key has an ASCII // value) to detect backspace, delete and keypad keys. @@ -1266,52 +1236,37 @@ key_press_event(GtkWidget *widget UNUSED, if (len == 0) // Unrecognized key return TRUE; - // Special keys (and a few others) may have modifiers. Also when using a - // double-byte encoding (can't set the 8th bit). - if (len == -3 || key_sym == GDK_space || key_sym == GDK_Tab - || key_sym == GDK_Return || key_sym == GDK_Linefeed - || key_sym == GDK_Escape || key_sym == GDK_KP_Tab - || key_sym == GDK_ISO_Enter || key_sym == GDK_3270_Enter - || (enc_dbcs && len == 1 && ((state & GDK_MOD1_MASK) -#if GTK_CHECK_VERSION(2,10,0) - || (state & GDK_SUPER_MASK) -#endif - ))) + // Handle modifiers. + modifiers = modifiers_gdk2vim(state); + + // For some keys a shift modifier is translated into another key code. + if (len == -3) + key = TO_SPECIAL(string[1], string[2]); + else + key = string[0]; + + key = simplify_key(key, &modifiers); + if (key == CSI) + key = K_CSI; + if (IS_SPECIAL(key)) { - modifiers = modifiers_gdk2vim(state); + string[0] = CSI; + string[1] = K_SECOND(key); + string[2] = K_THIRD(key); + len = 3; + } + else + { + string[0] = key; + len = 1; + } - /* - * For some keys a shift modifier is translated into another key - * code. - */ - if (len == -3) - key = TO_SPECIAL(string[1], string[2]); - else - key = string[0]; - - key = simplify_key(key, &modifiers); - if (key == CSI) - key = K_CSI; - if (IS_SPECIAL(key)) - { - string[0] = CSI; - string[1] = K_SECOND(key); - string[2] = K_THIRD(key); - len = 3; - } - else - { - string[0] = key; - len = 1; - } - - if (modifiers != 0) - { - string2[0] = CSI; - string2[1] = KS_MODIFIER; - string2[2] = modifiers; - add_to_input_buf(string2, 3); - } + if (modifiers != 0) + { + string2[0] = CSI; + string2[1] = KS_MODIFIER; + string2[2] = modifiers; + add_to_input_buf(string2, 3); } if (len == 1 && ((string[0] == Ctrl_C && ctrl_c_interrupts) diff --git a/src/gui_mac.c b/src/gui_mac.c index b37d3f5a03..b048375442 100644 --- a/src/gui_mac.c +++ b/src/gui_mac.c @@ -2168,9 +2168,9 @@ gui_mac_unicode_key_event( // taken liberally from gui_w48.c key_char = simplify_key(key_char, (int *)&vimModifiers); - // Interpret META, include SHIFT, etc. + // Unify modifiers somewhat. No longer use ALT to set the 8th bit. key_char = extract_modifiers(key_char, (int *)&vimModifiers, - TRUE, NULL); + FALSE, NULL); if (key_char == CSI) key_char = K_CSI; diff --git a/src/gui_motif.c b/src/gui_motif.c index 022626bcb0..90c5df98d6 100644 --- a/src/gui_motif.c +++ b/src/gui_motif.c @@ -1238,8 +1238,11 @@ add_pixmap_args(vimmenu_T *menu, Arg *args, int n) } else { +# if 0 // DISABLED - this causes a crash when running "make test_gui" in + // Test_colorscheme() if (menu->xpm_fname != NULL) XtSetArg(args[n], XmNpixmapFile, menu->xpm_fname); n++; +# endif XtSetArg(args[n], XmNpixmapData, menu->xpm); n++; XtSetArg(args[n], XmNlabelLocation, XmBOTTOM); n++; } diff --git a/src/gui_w32.c b/src/gui_w32.c index 2409ee68e4..6527b42309 100644 --- a/src/gui_w32.c +++ b/src/gui_w32.c @@ -847,8 +847,8 @@ _OnSysChar( if (ch < 0x100 && !isalpha(ch) && isprint(ch)) modifiers &= ~MOD_MASK_SHIFT; - // Interpret the ALT key as making the key META, include SHIFT, etc. - ch = extract_modifiers(ch, &modifiers, TRUE, NULL); + // Unify modifiers somewhat. No longer use ALT to set the 8th bit. + ch = extract_modifiers(ch, &modifiers, FALSE, NULL); if (ch == CSI) ch = K_CSI; diff --git a/src/gui_x11.c b/src/gui_x11.c index f05de7bac8..c03b210443 100644 --- a/src/gui_x11.c +++ b/src/gui_x11.c @@ -771,8 +771,8 @@ gui_x11_key_hit_cb( #else char_u string[4], string2[3]; #endif - KeySym key_sym, key_sym2; - int len, len2; + KeySym key_sym; + int len; int i; int modifiers; int key; @@ -883,57 +883,9 @@ gui_x11_key_hit_cb( } #endif - // Check for Alt/Meta key (Mod1Mask), but not for a BS, DEL or character - // that already has the 8th bit set. And not when using a double-byte - // encoding, setting the 8th bit may make it the lead byte of a - // double-byte character. - if (len == 1 - && (ev_press->state & Mod1Mask) - && !(key_sym == XK_BackSpace || key_sym == XK_Delete) - && (string[0] & 0x80) == 0 - && !enc_dbcs) - { -#if defined(FEAT_MENU) && defined(FEAT_GUI_MOTIF) - // Ignore ALT keys when they are used for the menu only - if (gui.menu_is_active - && (p_wak[0] == 'y' - || (p_wak[0] == 'm' && gui_is_menu_shortcut(string[0])))) - goto theend; -#endif - /* - * Before we set the 8th bit, check to make sure the user doesn't - * already have a mapping defined for this sequence. We determine this - * by checking to see if the input would be the same without the - * Alt/Meta key. - * Don't do this for <S-M-Tab>, that should become K_S_TAB with ALT. - */ - ev_press->state &= ~Mod1Mask; - len2 = XLookupString(ev_press, (char *)string2, sizeof(string2), - &key_sym2, NULL); - if (key_sym2 == XK_space) - string2[0] = ' '; // Otherwise Meta-Ctrl-Space doesn't work - if ( len2 == 1 - && string[0] == string2[0] - && !(key_sym == XK_Tab && (ev_press->state & ShiftMask))) - { - string[0] |= 0x80; - if (enc_utf8) // convert to utf-8 - { - string[1] = string[0] & 0xbf; - string[0] = ((unsigned)string[0] >> 6) + 0xc0; - if (string[1] == CSI) - { - string[2] = KS_EXTRA; - string[3] = (int)KE_CSI; - len = 4; - } - else - len = 2; - } - } - else - ev_press->state |= Mod1Mask; - } + // We used to apply Alt/Meta to the key here (Mod1Mask), but that is now + // done later, the same as it happens for the terminal. Hopefully that + // works for everybody... if (len == 1 && string[0] == CSI) { @@ -963,54 +915,47 @@ gui_x11_key_hit_cb( if (len == 0) goto theend; - // Special keys (and a few others) may have modifiers. Also when using a - // double-byte encoding (can't set the 8th bit). - if (len == -3 || key_sym == XK_space || key_sym == XK_Tab - || key_sym == XK_Return || key_sym == XK_Linefeed - || key_sym == XK_Escape - || (enc_dbcs && len == 1 && (ev_press->state & Mod1Mask))) + // Handle modifiers. + modifiers = 0; + if (ev_press->state & ShiftMask) + modifiers |= MOD_MASK_SHIFT; + if (ev_press->state & ControlMask) + modifiers |= MOD_MASK_CTRL; + if (ev_press->state & Mod1Mask) + modifiers |= MOD_MASK_ALT; + if (ev_press->state & Mod4Mask) + modifiers |= MOD_MASK_META; + + /* + * For some keys a shift modifier is translated into another key + * code. + */ + if (len == -3) + key = TO_SPECIAL(string[1], string[2]); + else + key = string[0]; + key = simplify_key(key, &modifiers); + if (key == CSI) + key = K_CSI; + if (IS_SPECIAL(key)) { - modifiers = 0; - if (ev_press->state & ShiftMask) - modifiers |= MOD_MASK_SHIFT; - if (ev_press->state & ControlMask) - modifiers |= MOD_MASK_CTRL; - if (ev_press->state & Mod1Mask) - modifiers |= MOD_MASK_ALT; - if (ev_press->state & Mod4Mask) - modifiers |= MOD_MASK_META; + string[0] = CSI; + string[1] = K_SECOND(key); + string[2] = K_THIRD(key); + len = 3; + } + else + { + string[0] = key; + len = 1; + } - /* - * For some keys a shift modifier is translated into another key - * code. - */ - if (len == -3) - key = TO_SPECIAL(string[1], string[2]); - else - key = string[0]; - key = simplify_key(key, &modifiers); - if (key == CSI) - key = K_CSI; - if (IS_SPECIAL(key)) - { - string[0] = CSI; - string[1] = K_SECOND(key); - string[2] = K_THIRD(key); - len = 3; - } - else - { - string[0] = key; - len = 1; - } - - if (modifiers != 0) - { - string2[0] = CSI; - string2[1] = KS_MODIFIER; - string2[2] = modifiers; - add_to_input_buf(string2, 3); - } + if (modifiers != 0) + { + string2[0] = CSI; + string2[1] = KS_MODIFIER; + string2[2] = modifiers; + add_to_input_buf(string2, 3); } if (len == 1 && ((string[0] == Ctrl_C && ctrl_c_interrupts) diff --git a/src/version.c b/src/version.c index b361dedf08..a65aaf2c6f 100644 --- a/src/version.c +++ b/src/version.c @@ -746,6 +746,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 765, /**/ 764, /**/ From e882f7a73c8fa48707de71035eb0a7ccc6ac8548 Mon Sep 17 00:00:00 2001 From: Bram Moolenaar <Bram@vim.org> Date: Sat, 16 May 2020 14:07:39 +0200 Subject: [PATCH 164/230] patch 8.2.0766: display error when using 'number' and 'breakindent' Problem: Display error when using 'number' and 'breakindent'. Solution: Adjust extra spaces in the first row. (Ken Takata, closes #6089, closes #5986) --- src/drawline.c | 6 ++++ src/testdir/test_breakindent.vim | 47 ++++++++++++++++++++++++++++++++ src/version.c | 2 ++ 3 files changed, 55 insertions(+) diff --git a/src/drawline.c b/src/drawline.c index 8de307aa6e..0a5a4bd502 100644 --- a/src/drawline.c +++ b/src/drawline.c @@ -1177,6 +1177,12 @@ win_line( c_final = NUL; n_extra = get_breakindent_win(wp, ml_get_buf(wp->w_buffer, lnum, FALSE)); + if (row == startrow) + { + n_extra -= win_col_off2(wp); + if (n_extra < 0) + n_extra = 0; + } if (wp->w_skipcol > 0 && wp->w_p_wrap && wp->w_briopt_sbr) need_showbreak = FALSE; // Correct end of highlighted area for 'breakindent', diff --git a/src/testdir/test_breakindent.vim b/src/testdir/test_breakindent.vim index aea0572c30..30c44f4dd6 100644 --- a/src/testdir/test_breakindent.vim +++ b/src/testdir/test_breakindent.vim @@ -696,4 +696,51 @@ func Test_breakindent19_sbr_nextpage() call s:close_windows('set breakindent& briopt& sbr&') endfunc +func Test_breakindent20_cpo_n_nextpage() + let s:input = "" + call s:test_windows('setl breakindent briopt=min:14 cpo+=n number') + call setline(1, repeat('a', 200)) + norm! 1gg + redraw! + let lines = s:screen_lines(1, 20) + let expect = [ + \ " 1 aaaaaaaaaaaaaaaa", + \ " aaaaaaaaaaaaaaaa", + \ " aaaaaaaaaaaaaaaa", + \ ] + call s:compare_lines(expect, lines) + " Scroll down one screen line + setl scrolloff=5 + norm! 5gj + redraw! + let lines = s:screen_lines(1, 20) + let expect = [ + \ "--1 aaaaaaaaaaaaaaaa", + \ " aaaaaaaaaaaaaaaa", + \ " aaaaaaaaaaaaaaaa", + \ ] + call s:compare_lines(expect, lines) + + setl briopt+=shift:2 + norm! 1gg + let lines = s:screen_lines(1, 20) + let expect = [ + \ " 1 aaaaaaaaaaaaaaaa", + \ " aaaaaaaaaaaaaa", + \ " aaaaaaaaaaaaaa", + \ ] + call s:compare_lines(expect, lines) + " Scroll down one screen line + norm! 5gj + let lines = s:screen_lines(1, 20) + let expect = [ + \ "--1 aaaaaaaaaaaaaa", + \ " aaaaaaaaaaaaaa", + \ " aaaaaaaaaaaaaa", + \ ] + call s:compare_lines(expect, lines) + + call s:close_windows('set breakindent& briopt& cpo& number&') +endfunc + " vim: shiftwidth=2 sts=2 expandtab diff --git a/src/version.c b/src/version.c index a65aaf2c6f..f0b0bec19c 100644 --- a/src/version.c +++ b/src/version.c @@ -746,6 +746,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 766, /**/ 765, /**/ From 645e3fe3fe2cfaf0615428207bbacc2963852eba Mon Sep 17 00:00:00 2001 From: Bram Moolenaar <Bram@vim.org> Date: Sat, 16 May 2020 15:05:04 +0200 Subject: [PATCH 165/230] patch 8.2.0767: modifyOtherKeys active when using a shell command in autocmd Problem: ModifyOtherKeys active when using a shell command in autocmd. Solution: Output T_CTE when going to cooked mode. (closes 5617) --- src/term.c | 6 ++++++ src/version.c | 2 ++ 2 files changed, 8 insertions(+) diff --git a/src/term.c b/src/term.c index f5d5dbc6f7..9803a1bb94 100644 --- a/src/term.c +++ b/src/term.c @@ -3474,10 +3474,16 @@ settmode(int tmode) if (termcap_active) { if (tmode != TMODE_RAW) + { out_str(T_BD); // disable bracketed paste mode + out_str(T_CTE); // possibly disables modifyOtherKeys + } else + { out_str(T_BE); // enable bracketed paste mode (should // be before mch_settmode(). + out_str(T_CTI); // possibly enables modifyOtherKeys + } } out_flush(); mch_settmode(tmode); // machine specific function diff --git a/src/version.c b/src/version.c index f0b0bec19c..7d351a06b5 100644 --- a/src/version.c +++ b/src/version.c @@ -746,6 +746,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 767, /**/ 766, /**/ From e75ba268b35a9b3a1f8b47668e657259555fc5fa Mon Sep 17 00:00:00 2001 From: Bram Moolenaar <Bram@vim.org> Date: Sat, 16 May 2020 15:43:31 +0200 Subject: [PATCH 166/230] patch 8.2.0768: Vim9: memory leak in script test Problem: Vim9: memory leak in script test. Solution: Clear typval before giving an error message. --- src/version.c | 2 ++ src/vim9execute.c | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/src/version.c b/src/version.c index 7d351a06b5..8c89761bb9 100644 --- a/src/version.c +++ b/src/version.c @@ -746,6 +746,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 768, /**/ 767, /**/ diff --git a/src/vim9execute.c b/src/vim9execute.c index 398c94c42a..c910dbc96b 100644 --- a/src/vim9execute.c +++ b/src/vim9execute.c @@ -1169,12 +1169,12 @@ call_def_function( n = tv->vval.v_number; msg = set_option_value(iptr->isn_arg.storeopt.so_name, n, s, iptr->isn_arg.storeopt.so_flags); + clear_tv(tv); if (msg != NULL) { emsg(_(msg)); goto failed; } - clear_tv(tv); } break; From 129d6bf6b3d120b0a4c69e18b5e8602a84e352bf Mon Sep 17 00:00:00 2001 From: Bram Moolenaar <Bram@vim.org> Date: Sat, 16 May 2020 16:08:35 +0200 Subject: [PATCH 167/230] patch 8.2.0769: VimLeavePre not triggered when Vim is terminated Problem: VimLeavePre not triggered when Vim is terminated. Solution: Unblock autocommands. --- src/main.c | 11 +++++++++++ src/testdir/test_signals.vim | 13 ++++++++++++- src/version.c | 2 ++ 3 files changed, 25 insertions(+), 1 deletion(-) diff --git a/src/main.c b/src/main.c index b00d7b987f..201ed37211 100644 --- a/src/main.c +++ b/src/main.c @@ -1576,6 +1576,7 @@ getout(int exitval) tabpage_T *next_tp; buf_T *buf; win_T *wp; + int unblock = 0; // Trigger BufWinLeave for all windows, but only once per buffer. for (tp = first_tabpage; tp != NULL; tp = next_tp) @@ -1617,7 +1618,17 @@ getout(int exitval) // autocmd deleted the buffer break; } + + // deathtrap() blocks autocommands, but we do want to trigger + // VimLeavePre. + if (is_autocmd_blocked()) + { + unblock_autocmds(); + ++unblock; + } apply_autocmds(EVENT_VIMLEAVEPRE, NULL, NULL, FALSE, curbuf); + if (unblock) + block_autocmds(); } #ifdef FEAT_VIMINFO diff --git a/src/testdir/test_signals.vim b/src/testdir/test_signals.vim index 0008e31fb7..48e3a3e0e4 100644 --- a/src/testdir/test_signals.vim +++ b/src/testdir/test_signals.vim @@ -127,8 +127,13 @@ func Test_deadly_signal_TERM() if cmd =~ 'valgrind' throw 'Skipped: cannot test signal TERM with valgrind' endif + let lines =<< trim END + au VimLeave * call writefile(["VimLeave triggered"], "XautoOut", "a") + au VimLeavePre * call writefile(["VimLeavePre triggered"], "XautoOut", "a") + END + call writefile(lines, 'XsetupAucmd') - let buf = RunVimInTerminal('Xsig_TERM', {'rows': 6}) + let buf = RunVimInTerminal('-S XsetupAucmd Xsig_TERM', {'rows': 6}) let pid_vim = term_getjob(buf)->job_info().process call term_sendkeys(buf, ":call setline(1, 'foo')\n") @@ -145,8 +150,14 @@ func Test_deadly_signal_TERM() silent recover .Xsig_TERM.swp call assert_equal(['foo'], getline(1, '$')) + let result = readfile('XautoOut') + call assert_match('VimLeavePre triggered', result[0]) + call assert_match('VimLeave triggered', result[1]) + %bwipe! call delete('.Xsig_TERM.swp') + call delete('XsetupAucmd') + call delete('XautoOut') endfunc " vim: ts=8 sw=2 sts=2 tw=80 fdm=marker diff --git a/src/version.c b/src/version.c index 8c89761bb9..a1b038f157 100644 --- a/src/version.c +++ b/src/version.c @@ -746,6 +746,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 769, /**/ 768, /**/ From aa5fc4ec51b00e91f174ac83c8ff68becf5f42bb Mon Sep 17 00:00:00 2001 From: Bram Moolenaar <Bram@vim.org> Date: Sat, 16 May 2020 18:57:53 +0200 Subject: [PATCH 168/230] patch 8.2.0770: cannot map CTRL-B when using the GUI Problem: Cannot map CTRL-B when using the GUI. Solution: Reset the CTRL modifier when used. (closes #6092) --- src/gui_gtk_x11.c | 12 ++++++++---- src/version.c | 2 ++ 2 files changed, 10 insertions(+), 4 deletions(-) diff --git a/src/gui_gtk_x11.c b/src/gui_gtk_x11.c index 02526b2726..8e272970d2 100644 --- a/src/gui_gtk_x11.c +++ b/src/gui_gtk_x11.c @@ -1023,7 +1023,7 @@ focus_out_event(GtkWidget *widget UNUSED, * http://developer.gnome.org/doc/API/2.0/gdk/gdk-Event-Structures.html#GdkEventKey */ static int -keyval_to_string(unsigned int keyval, unsigned int state, char_u *string) +keyval_to_string(unsigned int keyval, unsigned int *state, char_u *string) { int len; guint32 uc; @@ -1031,8 +1031,8 @@ keyval_to_string(unsigned int keyval, unsigned int state, char_u *string) uc = gdk_keyval_to_unicode(keyval); if (uc != 0) { - // Check for CTRL-foo - if ((state & GDK_CONTROL_MASK) && uc >= 0x20 && uc < 0x80) + // Check for CTRL-char + if ((*state & GDK_CONTROL_MASK) && uc >= 0x20 && uc < 0x80) { // These mappings look arbitrary at the first glance, but in fact // resemble quite exactly the behaviour of the GTK+ 1.2 GUI on my @@ -1051,6 +1051,10 @@ keyval_to_string(unsigned int keyval, unsigned int state, char_u *string) else string[0] = uc; len = 1; + + if (string[0] != uc) + // The modifier was used, remove it. + *state = *state & ~GDK_CONTROL_MASK; } else { @@ -1169,7 +1173,7 @@ key_press_event(GtkWidget *widget UNUSED, else #endif { - len = keyval_to_string(key_sym, state, string2); + len = keyval_to_string(key_sym, &state, string2); // Careful: convert_input() doesn't handle the NUL character. // No need to convert pure ASCII anyway, thus the len > 1 check. diff --git a/src/version.c b/src/version.c index a1b038f157..277650488c 100644 --- a/src/version.c +++ b/src/version.c @@ -746,6 +746,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 770, /**/ 769, /**/ From 6f5b6dfb16228c0ce1e4379b7bafed02eaddbab2 Mon Sep 17 00:00:00 2001 From: Bram Moolenaar <Bram@vim.org> Date: Sat, 16 May 2020 21:20:12 +0200 Subject: [PATCH 169/230] patch 8.2.0771: Vim9: cannot call a compiled closure from not compiled code Problem: Vim9: cannot call a compiled closure from not compiled code. Solution: Pass funcexe to call_user_func(). --- src/eval.c | 3 ++- src/proto/vim9execute.pro | 3 +-- src/testdir/test_vim9_func.vim | 10 ++++++++++ src/userfunc.c | 16 +++++++--------- src/version.c | 2 ++ src/vim9execute.c | 17 ++++++++++++----- 6 files changed, 34 insertions(+), 17 deletions(-) diff --git a/src/eval.c b/src/eval.c index 77359dccaa..dbc10c1b69 100644 --- a/src/eval.c +++ b/src/eval.c @@ -246,7 +246,8 @@ eval_expr_typval(typval_T *expr, typval_T *argv, int argc, typval_T *rettv) if (partial->pt_func != NULL && partial->pt_func->uf_dfunc_idx >= 0) { - if (call_def_function(partial->pt_func, argc, argv, rettv) == FAIL) + if (call_def_function(partial->pt_func, argc, argv, + partial, rettv) == FAIL) return FAIL; } else diff --git a/src/proto/vim9execute.pro b/src/proto/vim9execute.pro index 578fe81e1b..eac8979afc 100644 --- a/src/proto/vim9execute.pro +++ b/src/proto/vim9execute.pro @@ -1,7 +1,6 @@ /* vim9execute.c */ -int call_def_function(ufunc_T *ufunc, int argc_arg, typval_T *argv, typval_T *rettv); +int call_def_function(ufunc_T *ufunc, int argc_arg, typval_T *argv, partial_T *partial, typval_T *rettv); void ex_disassemble(exarg_T *eap); int tv2bool(typval_T *tv); int check_not_string(typval_T *tv); -int set_ref_in_dfunc(ufunc_T *ufunc, int copyID); /* vim: set ft=c : */ diff --git a/src/testdir/test_vim9_func.vim b/src/testdir/test_vim9_func.vim index c74b4a4510..100d86aa66 100644 --- a/src/testdir/test_vim9_func.vim +++ b/src/testdir/test_vim9_func.vim @@ -792,5 +792,15 @@ def Test_nested_closure() assert_equal('text!!!', Closure('!!!')) enddef +func GetResult(Ref) + return a:Ref('some') +endfunc + +def Test_call_closure_not_compiled() + let text = 'text' + g:Ref = {s -> s .. text} + assert_equal('sometext', GetResult(g:Ref)) +enddef + " vim: ts=8 sw=2 sts=2 expandtab tw=80 fdm=marker diff --git a/src/userfunc.c b/src/userfunc.c index b3c4f900a1..99c45b3e76 100644 --- a/src/userfunc.c +++ b/src/userfunc.c @@ -1062,8 +1062,7 @@ call_user_func( int argcount, // nr of args typval_T *argvars, // arguments typval_T *rettv, // return value - linenr_T firstline, // first line of range - linenr_T lastline, // last line of range + funcexe_T *funcexe, // context dict_T *selfdict) // Dictionary for "self" { sctx_T save_current_sctx; @@ -1120,7 +1119,7 @@ call_user_func( current_sctx = fp->uf_script_ctx; // Execute the compiled function. - call_def_function(fp, argcount, argvars, rettv); + call_def_function(fp, argcount, argvars, funcexe->partial, rettv); --depth; current_funccal = fc->caller; @@ -1194,9 +1193,9 @@ call_user_func( if ((fp->uf_flags & FC_NOARGS) == 0) { add_nr_var(&fc->l_avars, &fc->fixvar[fixvar_idx++].var, "firstline", - (varnumber_T)firstline); + (varnumber_T)funcexe->firstline); add_nr_var(&fc->l_avars, &fc->fixvar[fixvar_idx++].var, "lastline", - (varnumber_T)lastline); + (varnumber_T)funcexe->lastline); } for (i = 0; i < argcount || i < fp->uf_args.ga_len; ++i) { @@ -1515,9 +1514,8 @@ call_user_func_check( did_save_redo = TRUE; } ++fp->uf_calls; - call_user_func(fp, argcount, argvars, rettv, - funcexe->firstline, funcexe->lastline, - (fp->uf_flags & FC_DICT) ? selfdict : NULL); + call_user_func(fp, argcount, argvars, rettv, funcexe, + (fp->uf_flags & FC_DICT) ? selfdict : NULL); if (--fp->uf_calls <= 0 && fp->uf_refcount <= 0) // Function was unreferenced while being used, free it now. func_clear_free(fp, FALSE); @@ -4293,7 +4291,7 @@ find_hi_in_scoped_ht(char_u *name, hashtab_T **pht) if (current_funccal == NULL || current_funccal->func->uf_scoped == NULL) return NULL; - // Search in parent scope which is possible to reference from lambda + // Search in parent scope, which can be referenced from a lambda. current_funccal = current_funccal->func->uf_scoped; while (current_funccal != NULL) { diff --git a/src/version.c b/src/version.c index 277650488c..c369a71606 100644 --- a/src/version.c +++ b/src/version.c @@ -746,6 +746,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 771, /**/ 770, /**/ diff --git a/src/vim9execute.c b/src/vim9execute.c index c910dbc96b..fe6adda601 100644 --- a/src/vim9execute.c +++ b/src/vim9execute.c @@ -641,6 +641,7 @@ call_def_function( ufunc_T *ufunc, int argc_arg, // nr of arguments typval_T *argv, // arguments + partial_T *partial, // optional partial for context typval_T *rettv) // return value { ectx_T ectx; // execution context @@ -720,6 +721,12 @@ call_def_function( ectx.ec_frame_idx = ectx.ec_stack.ga_len; initial_frame_idx = ectx.ec_frame_idx; + if (partial != NULL) + { + ectx.ec_outer_stack = partial->pt_ectx_stack; + ectx.ec_outer_frame = partial->pt_ectx_frame; + } + // dummy frame entries for (idx = 0; idx < STACK_FRAME_SIZE; ++idx) { @@ -1468,7 +1475,7 @@ call_def_function( { cpfunc_T *pfunc = &iptr->isn_arg.pfunc; int r; - typval_T partial; + typval_T partial_tv; SOURCING_LNUM = iptr->isn_lnum; if (pfunc->cpf_top) @@ -1480,12 +1487,12 @@ call_def_function( { // Get the funcref from the stack. --ectx.ec_stack.ga_len; - partial = *STACK_TV_BOT(0); - tv = &partial; + partial_tv = *STACK_TV_BOT(0); + tv = &partial_tv; } r = call_partial(tv, pfunc->cpf_argcount, &ectx); - if (tv == &partial) - clear_tv(&partial); + if (tv == &partial_tv) + clear_tv(&partial_tv); if (r == FAIL) goto failed; } From df671b4629a0c6451c067cafd2534b7261f41277 Mon Sep 17 00:00:00 2001 From: Bram Moolenaar <Bram@vim.org> Date: Sat, 16 May 2020 22:33:33 +0200 Subject: [PATCH 170/230] patch 8.2.0772: Vim9: some variable initializations not tested Problem: Vim9: some variable initializations not tested. Solution: Add a few more tests --- src/testdir/test_vim9_script.vim | 33 ++++++++++++++++++++++++++++++-- src/version.c | 2 ++ 2 files changed, 33 insertions(+), 2 deletions(-) diff --git a/src/testdir/test_vim9_script.vim b/src/testdir/test_vim9_script.vim index 4284aada24..f5391847c2 100644 --- a/src/testdir/test_vim9_script.vim +++ b/src/testdir/test_vim9_script.vim @@ -1736,6 +1736,8 @@ def Test_let_func_call() return 'this' endfunc let val: string = GetValue() + " env var is always a string + let env = $TERM END writefile(lines, 'Xfinished') source Xfinished @@ -1752,13 +1754,40 @@ def Test_let_missing_type() func GetValue() return 'this' endfunc - let val = GetValue() + let val = GetValue() END CheckScriptFailure(lines, 'E1091:') lines =<< trim END vim9script - let var = g:unkown + func GetValue() + return 'this' + endfunc + let val = [GetValue()] + END + CheckScriptFailure(lines, 'E1091:') + + lines =<< trim END + vim9script + func GetValue() + return 'this' + endfunc + let val = {GetValue(): 123} + END + CheckScriptFailure(lines, 'E1091:') + + lines =<< trim END + vim9script + func GetValue() + return 'this' + endfunc + let val = {'a': GetValue()} + END + CheckScriptFailure(lines, 'E1091:') + + lines =<< trim END + vim9script + let var = g:unknown END CheckScriptFailure(lines, 'E1091:') diff --git a/src/version.c b/src/version.c index c369a71606..fa8ba91ce4 100644 --- a/src/version.c +++ b/src/version.c @@ -746,6 +746,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 772, /**/ 771, /**/ From 3b1f18f785f67c6cd110498c366e4d0c0fe11f27 Mon Sep 17 00:00:00 2001 From: Bram Moolenaar <Bram@vim.org> Date: Sat, 16 May 2020 23:15:08 +0200 Subject: [PATCH 171/230] patch 8.2.0773: switching to raw mode every time ":" is used Problem: Switching to raw mode every time ":" is used. Solution: When executing a shell set cur_tmode to TMODE_UNKNOWN, so that the next time TMODE_RAW is used it is set, but not every time. --- src/os_amiga.c | 4 ++++ src/os_unix.c | 7 +++++++ src/os_win32.c | 4 ++++ src/term.c | 10 +++++----- src/term.h | 7 ++++--- src/version.c | 2 ++ 6 files changed, 26 insertions(+), 8 deletions(-) diff --git a/src/os_amiga.c b/src/os_amiga.c index 1e3fd4b201..58e462d5cb 100644 --- a/src/os_amiga.c +++ b/src/os_amiga.c @@ -1387,7 +1387,11 @@ mch_call_shell( if ((mydir = CurrentDir(mydir)) != 0) // make sure we stay in the same directory UnLock(mydir); if (tmode == TMODE_RAW) + { + // The shell may have messed with the mode, always set it. + cur_tmode = TMODE_UNKNOWN; settmode(TMODE_RAW); // set to raw mode + } #ifdef FEAT_TITLE resettitle(); #endif diff --git a/src/os_unix.c b/src/os_unix.c index aea3d5a9e2..9162f5bf8a 100644 --- a/src/os_unix.c +++ b/src/os_unix.c @@ -4521,7 +4521,11 @@ mch_call_shell_system( } if (tmode == TMODE_RAW) + { + // The shell may have messed with the mode, always set it. + cur_tmode = TMODE_UNKNOWN; settmode(TMODE_RAW); // set to raw mode + } # ifdef FEAT_TITLE resettitle(); # endif @@ -4571,6 +4575,9 @@ mch_call_shell_fork( out_flush(); if (options & SHELL_COOKED) settmode(TMODE_COOK); // set to normal mode + if (tmode == TMODE_RAW) + // The shell may have messed with the mode, always set it later. + cur_tmode = TMODE_UNKNOWN; if (unix_build_argv(cmd, &argv, &tofree1, &tofree2) == FAIL) goto error; diff --git a/src/os_win32.c b/src/os_win32.c index 52bc95de88..d77e216916 100644 --- a/src/os_win32.c +++ b/src/os_win32.c @@ -4899,7 +4899,11 @@ mch_call_shell( } if (tmode == TMODE_RAW) + { + // The shell may have messed with the mode, always set it. + cur_tmode = TMODE_UNKNOWN; settmode(TMODE_RAW); // set to raw mode + } // Print the return value, unless "vimrun" was used. if (x != 0 && !(options & SHELL_SILENT) && !emsg_silent diff --git a/src/term.c b/src/term.c index 9803a1bb94..1260c9a37d 100644 --- a/src/term.c +++ b/src/term.c @@ -2862,7 +2862,7 @@ term_color(char_u *s, int n) #if defined(FEAT_VTP) && defined(FEAT_TERMGUICOLORS) || (s[0] == ESC && s[1] == '|') #endif - || (s[0] == CSI && (i = 1) == 1)) + || (s[0] == CSI && (i = 1) == 1)) && s[i] != NUL && (STRCMP(s + i + 1, "%p1%dm") == 0 || STRCMP(s + i + 1, "%dm") == 0) @@ -3447,14 +3447,14 @@ settmode(int tmode) if (full_screen) { /* - * When returning after calling a shell we want to really set the - * terminal to raw mode, even though we think it already is, because - * the shell program may have reset the terminal mode. + * When returning after calling a shell cur_tmode is TMODE_UNKNOWN, + * set the terminal to raw mode, even though we think it already is, + * because the shell program may have reset the terminal mode. * When we think the terminal is normal, don't try to set it to * normal again, because that causes problems (logout!) on some * machines. */ - if (tmode != TMODE_COOK || cur_tmode != TMODE_COOK) + if (tmode != cur_tmode) { #ifdef FEAT_TERMRESPONSE # ifdef FEAT_GUI diff --git a/src/term.h b/src/term.h index f1c3df5344..b9535ee1de 100644 --- a/src/term.h +++ b/src/term.h @@ -209,6 +209,7 @@ extern char_u *(term_strings[]); // current terminal strings #define T_SSI (TERM_STR(KS_SSI)) // save icon text #define T_SRI (TERM_STR(KS_SRI)) // restore icon text -#define TMODE_COOK 0 // terminal mode for external cmds and Ex mode -#define TMODE_SLEEP 1 // terminal mode for sleeping (cooked but no echo) -#define TMODE_RAW 2 // terminal mode for Normal and Insert mode +#define TMODE_COOK 0 // terminal mode for external cmds and Ex mode +#define TMODE_SLEEP 1 // terminal mode for sleeping (cooked but no echo) +#define TMODE_RAW 2 // terminal mode for Normal and Insert mode +#define TMODE_UNKNOWN 9 // after executing a shell diff --git a/src/version.c b/src/version.c index fa8ba91ce4..6a28ae35f8 100644 --- a/src/version.c +++ b/src/version.c @@ -746,6 +746,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 773, /**/ 772, /**/ From 26e86445bf06ab7e7587dfdf75f33f7c70632b46 Mon Sep 17 00:00:00 2001 From: Bram Moolenaar <Bram@vim.org> Date: Sun, 17 May 2020 14:06:16 +0200 Subject: [PATCH 172/230] patch 8.2.0774: t_TI and t_TE are output when using 'visualbell' Problem: t_TI and t_TE are output when using 'visualbell'. (Dominique Pelle) Solution: Do not change the terminal mode for a short sleep. Do not output t_TI and t_TE when switching to/from TMODE_SLEEP. Make tmode an enum. --- src/globals.h | 2 +- src/os_amiga.c | 2 +- src/os_mswin.c | 2 +- src/os_unix.c | 23 +++++++++++++---------- src/os_vms.c | 2 +- src/os_win32.c | 2 +- src/proto/os_amiga.pro | 2 +- src/proto/os_mswin.pro | 2 +- src/proto/os_unix.pro | 2 +- src/proto/os_vms.pro | 2 +- src/proto/os_win32.pro | 2 +- src/term.c | 7 ++++++- src/term.h | 10 ++++++---- src/version.c | 2 ++ 14 files changed, 37 insertions(+), 25 deletions(-) diff --git a/src/globals.h b/src/globals.h index 11e06be7ee..60c3c668b8 100644 --- a/src/globals.h +++ b/src/globals.h @@ -1171,7 +1171,7 @@ EXTERN volatile sig_atomic_t got_int INIT(= FALSE); // set to TRUE when interrup EXTERN int term_console INIT(= FALSE); // set to TRUE when console used #endif EXTERN int termcap_active INIT(= FALSE); // set by starttermcap() -EXTERN int cur_tmode INIT(= TMODE_COOK); // input terminal mode +EXTERN tmode_T cur_tmode INIT(= TMODE_COOK); // input terminal mode EXTERN int bangredo INIT(= FALSE); // set to TRUE with ! command EXTERN int searchcmdlen; // length of previous search cmd #ifdef FEAT_SYN_HL diff --git a/src/os_amiga.c b/src/os_amiga.c index 58e462d5cb..850c26acda 100644 --- a/src/os_amiga.c +++ b/src/os_amiga.c @@ -977,7 +977,7 @@ mch_exit(int r) * it sends a 0 to the console to make it back into a CON: from a RAW: */ void -mch_settmode(int tmode) +mch_settmode(tmode_T tmode) { #if defined(__AROS__) || defined(__amigaos4__) if (!SetMode(raw_in, tmode == TMODE_RAW ? 1 : 0)) diff --git a/src/os_mswin.c b/src/os_mswin.c index 1c987c2d62..80009533c6 100644 --- a/src/os_mswin.c +++ b/src/os_mswin.c @@ -553,7 +553,7 @@ vim_stat(const char *name, stat_T *stp) #if (defined(FEAT_GUI_MSWIN) && !defined(VIMDLL)) || defined(PROTO) void -mch_settmode(int tmode UNUSED) +mch_settmode(tmode_T tmode UNUSED) { // nothing to do } diff --git a/src/os_unix.c b/src/os_unix.c index 9162f5bf8a..6c308affbe 100644 --- a/src/os_unix.c +++ b/src/os_unix.c @@ -215,7 +215,8 @@ static volatile sig_atomic_t in_mch_delay = FALSE; // sleeping in mch_delay() static int dont_check_job_ended = 0; #endif -static int curr_tmode = TMODE_COOK; // contains current terminal mode +// Current terminal mode from mch_settmode(). Can differ from cur_tmode. +static tmode_T mch_cur_tmode = TMODE_COOK; #ifdef USE_XSMP typedef struct @@ -581,7 +582,7 @@ mch_total_mem(int special UNUSED) void mch_delay(long msec, int ignoreinput) { - int old_tmode; + tmode_T old_tmode; #ifdef FEAT_MZSCHEME long total = msec; // remember original value #endif @@ -591,9 +592,10 @@ mch_delay(long msec, int ignoreinput) // Go to cooked mode without echo, to allow SIGINT interrupting us // here. But we don't want QUIT to kill us (CTRL-\ used in a // shell may produce SIGQUIT). + // Only do this if sleeping for more than half a second. in_mch_delay = TRUE; - old_tmode = curr_tmode; - if (curr_tmode == TMODE_RAW) + old_tmode = mch_cur_tmode; + if (mch_cur_tmode == TMODE_RAW && msec > 500) settmode(TMODE_SLEEP); /* @@ -650,7 +652,8 @@ mch_delay(long msec, int ignoreinput) while (total > 0); #endif - settmode(old_tmode); + if (msec > 500) + settmode(old_tmode); in_mch_delay = FALSE; } else @@ -3461,7 +3464,7 @@ mch_tcgetattr(int fd, void *term) } void -mch_settmode(int tmode) +mch_settmode(tmode_T tmode) { static int first = TRUE; @@ -3558,7 +3561,7 @@ mch_settmode(int tmode) ttybnew.sg_flags &= ~(ECHO); ioctl(read_cmd_fd, TIOCSETN, &ttybnew); #endif - curr_tmode = tmode; + mch_cur_tmode = tmode; } /* @@ -4455,7 +4458,7 @@ mch_call_shell_system( char *ifn = NULL; char *ofn = NULL; #endif - int tmode = cur_tmode; + tmode_T tmode = cur_tmode; char_u *newcmd; // only needed for unix int x; @@ -4549,7 +4552,7 @@ mch_call_shell_fork( char_u *cmd, int options) // SHELL_*, see vim.h { - int tmode = cur_tmode; + tmode_T tmode = cur_tmode; pid_t pid; pid_t wpid = 0; pid_t wait_pid = 0; @@ -5939,7 +5942,7 @@ mch_create_pty_channel(job_T *job, jobopt_T *options) void mch_breakcheck(int force) { - if ((curr_tmode == TMODE_RAW || force) + if ((mch_cur_tmode == TMODE_RAW || force) && RealWaitForChar(read_cmd_fd, 0L, NULL, NULL)) fill_input_buf(FALSE); } diff --git a/src/os_vms.c b/src/os_vms.c index 96fbc172f9..b8ad788987 100644 --- a/src/os_vms.c +++ b/src/os_vms.c @@ -112,7 +112,7 @@ vul_item(ITEM *itm, short len, short cod, char *adr, int *ret) } void -mch_settmode(int tmode) +mch_settmode(tmode_T tmode) { int status; diff --git a/src/os_win32.c b/src/os_win32.c index d77e216916..edd5cdac4e 100644 --- a/src/os_win32.c +++ b/src/os_win32.c @@ -3600,7 +3600,7 @@ handler_routine( * set the tty in (raw) ? "raw" : "cooked" mode */ void -mch_settmode(int tmode) +mch_settmode(tmode_T tmode) { DWORD cmodein; DWORD cmodeout; diff --git a/src/proto/os_amiga.pro b/src/proto/os_amiga.pro index 8e12f4da28..b2ad9c3b55 100644 --- a/src/proto/os_amiga.pro +++ b/src/proto/os_amiga.pro @@ -31,7 +31,7 @@ int mch_can_exe(char_u *name, char_u **path, int use_path); int mch_nodetype(char_u *name); void mch_early_init(void); void mch_exit(int r); -void mch_settmode(int tmode); +void mch_settmode(tmode_T tmode); int mch_get_shellsize(void); void mch_set_shellsize(void); void mch_new_shellsize(void); diff --git a/src/proto/os_mswin.pro b/src/proto/os_mswin.pro index ade7cc2556..e8a6cb9f15 100644 --- a/src/proto/os_mswin.pro +++ b/src/proto/os_mswin.pro @@ -10,7 +10,7 @@ int mch_FullName(char_u *fname, char_u *buf, int len, int force); int mch_isFullName(char_u *fname); void slash_adjust(char_u *p); int vim_stat(const char *name, stat_T *stp); -void mch_settmode(int tmode); +void mch_settmode(tmode_T tmode); int mch_get_shellsize(void); void mch_set_shellsize(void); void mch_new_shellsize(void); diff --git a/src/proto/os_unix.pro b/src/proto/os_unix.pro index b9db0fc56f..cb84994429 100644 --- a/src/proto/os_unix.pro +++ b/src/proto/os_unix.pro @@ -48,7 +48,7 @@ int mch_nodetype(char_u *name); void mch_early_init(void); void mch_free_mem(void); void mch_exit(int r); -void mch_settmode(int tmode); +void mch_settmode(tmode_T tmode); void get_stty(void); int get_tty_info(int fd, ttyinfo_T *info); void mch_setmouse(int on); diff --git a/src/proto/os_vms.pro b/src/proto/os_vms.pro index c1cfd4442a..b58118d88e 100644 --- a/src/proto/os_vms.pro +++ b/src/proto/os_vms.pro @@ -1,5 +1,5 @@ /* os_vms.c */ -void mch_settmode(int tmode); +void mch_settmode(tmode_T tmode); int mch_get_shellsize(void); void mch_set_shellsize(void); char_u *mch_getenv(char_u *lognam); diff --git a/src/proto/os_win32.pro b/src/proto/os_win32.pro index 15c1323157..d8f9ac36b2 100644 --- a/src/proto/os_win32.pro +++ b/src/proto/os_win32.pro @@ -39,7 +39,7 @@ int mch_nodetype(char_u *name); vim_acl_T mch_get_acl(char_u *fname); void mch_set_acl(char_u *fname, vim_acl_T acl); void mch_free_acl(vim_acl_T acl); -void mch_settmode(int tmode); +void mch_settmode(tmode_T tmode); int mch_get_shellsize(void); void mch_set_shellsize(void); void mch_new_shellsize(void); diff --git a/src/term.c b/src/term.c index 1260c9a37d..a575227072 100644 --- a/src/term.c +++ b/src/term.c @@ -3471,7 +3471,12 @@ settmode(int tmode) #endif if (tmode != TMODE_RAW) mch_setmouse(FALSE); // switch mouse off - if (termcap_active) + + // Disable bracketed paste and modifyOtherKeys in cooked mode. + // Avoid doing this too often, on some terminals the codes are not + // handled properly. + if (termcap_active && tmode != TMODE_SLEEP + && cur_tmode != TMODE_SLEEP) { if (tmode != TMODE_RAW) { diff --git a/src/term.h b/src/term.h index b9535ee1de..dca48d1ad5 100644 --- a/src/term.h +++ b/src/term.h @@ -209,7 +209,9 @@ extern char_u *(term_strings[]); // current terminal strings #define T_SSI (TERM_STR(KS_SSI)) // save icon text #define T_SRI (TERM_STR(KS_SRI)) // restore icon text -#define TMODE_COOK 0 // terminal mode for external cmds and Ex mode -#define TMODE_SLEEP 1 // terminal mode for sleeping (cooked but no echo) -#define TMODE_RAW 2 // terminal mode for Normal and Insert mode -#define TMODE_UNKNOWN 9 // after executing a shell +typedef enum { + TMODE_COOK, // terminal mode for external cmds and Ex mode + TMODE_SLEEP, // terminal mode for sleeping (cooked but no echo) + TMODE_RAW, // terminal mode for Normal and Insert mode + TMODE_UNKNOWN // after executing a shell +} tmode_T; diff --git a/src/version.c b/src/version.c index 6a28ae35f8..951137912b 100644 --- a/src/version.c +++ b/src/version.c @@ -746,6 +746,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 774, /**/ 773, /**/ From eb04f0893afe01faff272ef84c70d8cc16d8e80a Mon Sep 17 00:00:00 2001 From: Bram Moolenaar <Bram@vim.org> Date: Sun, 17 May 2020 14:32:35 +0200 Subject: [PATCH 173/230] patch 8.2.0775: not easy to call a Vim function from Lua Problem: Not easy to call a Vim function from Lua. Solution: Add vim.call() and vim.fn(). (Prabir Shrestha, closes #6063) --- runtime/doc/if_lua.txt | 9 +++++ src/if_lua.c | 77 ++++++++++++++++++++++++++++++++++++++-- src/testdir/test_lua.vim | 52 ++++++++++++++++----------- src/version.c | 2 ++ 4 files changed, 118 insertions(+), 22 deletions(-) diff --git a/runtime/doc/if_lua.txt b/runtime/doc/if_lua.txt index 75bb963a9f..ff108eebb6 100644 --- a/runtime/doc/if_lua.txt +++ b/runtime/doc/if_lua.txt @@ -199,6 +199,15 @@ Vim evaluation and command execution, and others. returns it. Note that the buffer is not set as current. + vim.call({name} [,{args}]) + Proxy to call Vim function named {name} with + arguments {args}. Example: > + :lua print(vim.call('has', 'timers')) +< + vim.fn Proxy to call Vim functions. Proxy methods are + created on demand. Example: > + :lua print(vim.fn.has('timers')) +< ============================================================================== 3. List userdata *lua-list* diff --git a/src/if_lua.c b/src/if_lua.c index 19842912fb..d4cc21f3d0 100644 --- a/src/if_lua.c +++ b/src/if_lua.c @@ -568,8 +568,21 @@ luaV_totypval(lua_State *L, int pos, typval_T *tv) break; case LUA_TNUMBER: #ifdef FEAT_FLOAT - tv->v_type = VAR_FLOAT; - tv->vval.v_float = (float_T) lua_tonumber(L, pos); + { + const lua_Number n = lua_tonumber(L, pos); + + if (n > (lua_Number)INT64_MAX || n < (lua_Number)INT64_MIN + || ((lua_Number)((varnumber_T)n)) != n) + { + tv->v_type = VAR_FLOAT; + tv->vval.v_float = (float_T)n; + } + else + { + tv->v_type = VAR_NUMBER; + tv->vval.v_number = (varnumber_T)n; + } + } #else tv->v_type = VAR_NUMBER; tv->vval.v_number = (varnumber_T) lua_tointeger(L, pos); @@ -1903,6 +1916,52 @@ luaV_type(lua_State *L) return 1; } + static int +luaV_call(lua_State *L) +{ + int argc = lua_gettop(L) - 1; + size_t funcname_len; + char_u *funcname; + char *error = NULL; + typval_T rettv; + typval_T argv[MAX_FUNC_ARGS + 1]; + int i = 0; + + if (argc > MAX_FUNC_ARGS) + return luaL_error(L, "Function called with too many arguments"); + + funcname = (char_u *)luaL_checklstring(L, 1, &funcname_len); + + for (; i < argc; i++) + { + if (luaV_totypval(L, i + 2, &argv[i]) == FAIL) + { + error = "lua: cannot convert value"; + goto free_vim_args; + } + } + + argv[argc].v_type = VAR_UNKNOWN; + + if (call_vim_function(funcname, argc, argv, &rettv) == FAIL) + { + error = "lua: call_vim_function failed"; + goto free_vim_args; + } + + luaV_pushtypval(L, &rettv); + clear_tv(&rettv); + +free_vim_args: + while (i > 0) + clear_tv(&argv[--i]); + + if (error == NULL) + return 1; + else + return luaL_error(L, error); +} + static const luaL_Reg luaV_module[] = { {"command", luaV_command}, {"eval", luaV_eval}, @@ -1916,6 +1975,7 @@ static const luaL_Reg luaV_module[] = { {"window", luaV_window}, {"open", luaV_open}, {"type", luaV_type}, + {"call", luaV_call}, {NULL, NULL} }; @@ -1997,6 +2057,17 @@ luaV_setref(lua_State *L) return 1; } +#define LUA_VIM_FN_CODE \ + "vim.fn = setmetatable({}, {"\ + " __index = function (t, key)"\ + " local function _fn(...)"\ + " return vim.call(key, ...)"\ + " end"\ + " t[key] = _fn"\ + " return _fn"\ + " end"\ + "})" + static int luaopen_vim(lua_State *L) { @@ -2052,6 +2123,8 @@ luaopen_vim(lua_State *L) lua_pushvalue(L, 1); // cache table luaV_openlib(L, luaV_module, 1); lua_setglobal(L, LUAVIM_NAME); + // custom code + luaL_dostring(L, LUA_VIM_FN_CODE); return 0; } diff --git a/src/testdir/test_lua.vim b/src/testdir/test_lua.vim index 25300b67ee..f92208c209 100644 --- a/src/testdir/test_lua.vim +++ b/src/testdir/test_lua.vim @@ -33,7 +33,7 @@ func Test_lua_eval() " lua.eval with a number lua v = vim.eval('123') call assert_equal('number', luaeval('vim.type(v)')) - call assert_equal(123.0, luaeval('v')) + call assert_equal(123, luaeval('v')) " lua.eval with a string lua v = vim.eval('"abc"') @@ -121,6 +121,18 @@ func Test_lua_window_line_col() bwipe! endfunc +" Test vim.call +func Test_lua_call() + call assert_equal(has('lua'), luaeval('vim.call("has", "lua")')) + call assert_equal(printf("Hello %s", "vim"), luaeval('vim.call("printf", "Hello %s", "vim")')) +endfunc + +" Test vim.fn.* +func Test_lua_fn() + call assert_equal(has('lua'), luaeval('vim.fn.has("lua")')) + call assert_equal(printf("Hello %s", "vim"), luaeval('vim.fn.printf("Hello %s", "vim")')) +endfunc + " Test setting the current window func Test_lua_window_set_current() new Xfoo1 @@ -252,7 +264,7 @@ endfunc func Test_lua_buffer_number_lines() new call setline(1, ['a', 'b', 'c']) - call assert_equal(3.0, luaeval('#vim.buffer()')) + call assert_equal(3, luaeval('#vim.buffer()')) bwipe! endfunc @@ -311,15 +323,15 @@ func Test_lua_list() lua l:add(nil) lua l:add(vim.eval("[1, 2, 3]")) lua l:add(vim.eval("{'a':1, 'b':2, 'c':3}")) - call assert_equal([123.0, 'abc', v:true, v:false, v:null, [1, 2, 3], {'a': 1, 'b': 2, 'c': 3}], l) - call assert_equal(7.0, luaeval('#l')) + call assert_equal([123, 'abc', v:true, v:false, v:null, [1, 2, 3], {'a': 1, 'b': 2, 'c': 3}], l) + call assert_equal(7, luaeval('#l')) call assert_match('^list: \%(0x\)\?\x\+$', luaeval('tostring(l)')) lua l[0] = 124 lua l[5] = nil lua l:insert('first') lua l:insert('xx', 3) - call assert_equal(['first', 124.0, 'abc', 'xx', v:true, v:false, v:null, {'a': 1, 'b': 2, 'c': 3}], l) + call assert_equal(['first', 124, 'abc', 'xx', v:true, v:false, v:null, {'a': 1, 'b': 2, 'c': 3}], l) lockvar 1 l call assert_fails('lua l:add("x")', '[string "vim chunk"]:1: list is locked') @@ -355,16 +367,16 @@ func Test_lua_recursive_list() lua l = vim.list():add(1):add(2) lua l = l:add(l) - call assert_equal(1.0, luaeval('l[0]')) - call assert_equal(2.0, luaeval('l[1]')) + call assert_equal(1, luaeval('l[0]')) + call assert_equal(2, luaeval('l[1]')) - call assert_equal(1.0, luaeval('l[2][0]')) - call assert_equal(2.0, luaeval('l[2][1]')) + call assert_equal(1, luaeval('l[2][0]')) + call assert_equal(2, luaeval('l[2][1]')) - call assert_equal(1.0, luaeval('l[2][2][0]')) - call assert_equal(2.0, luaeval('l[2][2][1]')) + call assert_equal(1, luaeval('l[2][2][0]')) + call assert_equal(2, luaeval('l[2][2][1]')) - call assert_equal('[1.0, 2.0, [...]]', string(luaeval('l'))) + call assert_equal('[1, 2, [...]]', string(luaeval('l'))) call assert_match('^list: \%(0x\)\?\x\+$', luaeval('tostring(l)')) call assert_equal(luaeval('tostring(l)'), luaeval('tostring(l[2])')) @@ -386,15 +398,15 @@ func Test_lua_dict() lua d[3] = false lua d[4] = vim.eval("[1, 2, 3]") lua d[5] = vim.eval("{'a':1, 'b':2, 'c':3}") - call assert_equal({'0':123.0, '1':'abc', '2':v:true, '3':v:false, '4': [1, 2, 3], '5': {'a':1, 'b':2, 'c':3}}, d) - call assert_equal(6.0, luaeval('#d')) + call assert_equal({'0':123, '1':'abc', '2':v:true, '3':v:false, '4': [1, 2, 3], '5': {'a':1, 'b':2, 'c':3}}, d) + call assert_equal(6, luaeval('#d')) call assert_match('^dict: \%(0x\)\?\x\+$', luaeval('tostring(d)')) call assert_equal('abc', luaeval('d[1]')) lua d[0] = 124 lua d[4] = nil - call assert_equal({'0':124.0, '1':'abc', '2':v:true, '3':v:false, '5': {'a':1, 'b':2, 'c':3}}, d) + call assert_equal({'0':124, '1':'abc', '2':v:true, '3':v:false, '5': {'a':1, 'b':2, 'c':3}}, d) lockvar 1 d call assert_fails('lua d[6] = 1', '[string "vim chunk"]:1: dict is locked') @@ -441,16 +453,16 @@ func Test_lua_blob() lua b = vim.blob("\x00\x00\x00\x00") call assert_equal(0z00000000, luaeval('b')) - call assert_equal(4.0, luaeval('#b')) + call assert_equal(4, luaeval('#b')) lua b[0], b[1], b[2], b[3] = 1, 32, 256, 0xff call assert_equal(0z012000ff, luaeval('b')) lua b[4] = string.byte("z", 1) call assert_equal(0z012000ff.7a, luaeval('b')) - call assert_equal(5.0, luaeval('#b')) + call assert_equal(5, luaeval('#b')) call assert_fails('lua b[#b+1] = 0x80', '[string "vim chunk"]:1: index out of range') lua b:add("12ab") call assert_equal(0z012000ff.7a313261.62, luaeval('b')) - call assert_equal(9.0, luaeval('#b')) + call assert_equal(9, luaeval('#b')) call assert_fails('lua b:add(nil)', '[string "vim chunk"]:1: string expected, got nil') call assert_fails('lua b:add(true)', '[string "vim chunk"]:1: string expected, got boolean') call assert_fails('lua b:add({})', '[string "vim chunk"]:1: string expected, got table') @@ -552,12 +564,12 @@ endfunc " Test :luafile foo.lua func Test_luafile() call delete('Xlua_file') - call writefile(["str = 'hello'", "num = 123.0" ], 'Xlua_file') + call writefile(["str = 'hello'", "num = 123" ], 'Xlua_file') call setfperm('Xlua_file', 'r-xr-xr-x') luafile Xlua_file call assert_equal('hello', luaeval('str')) - call assert_equal(123.0, luaeval('num')) + call assert_equal(123, luaeval('num')) lua str, num = nil call delete('Xlua_file') diff --git a/src/version.c b/src/version.c index 951137912b..cc092c29fb 100644 --- a/src/version.c +++ b/src/version.c @@ -746,6 +746,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 775, /**/ 774, /**/ From e178ba36546ec7805020280910306331f1ef4ed0 Mon Sep 17 00:00:00 2001 From: Bram Moolenaar <Bram@vim.org> Date: Sun, 17 May 2020 14:59:47 +0200 Subject: [PATCH 174/230] patch 8.2.0776: libvterm code lags behind the upstream version Problem: Libvterm code lags behind the upstream version. Solution: Include revision 719. --- Filelist | 2 + src/libvterm/Makefile | 3 + src/libvterm/README | 3 + src/libvterm/find-wide-chars.pl | 34 +++++++++++ src/libvterm/src/fullwidth.inc | 104 ++++++++++++++++++++++++++++++++ src/libvterm/src/unicode.c | 7 +++ src/version.c | 2 + 7 files changed, 155 insertions(+) create mode 100644 src/libvterm/find-wide-chars.pl create mode 100644 src/libvterm/src/fullwidth.inc diff --git a/Filelist b/Filelist index 7564879e9f..be1b36eacc 100644 --- a/Filelist +++ b/Filelist @@ -305,6 +305,7 @@ SRC_ALL = \ src/libvterm/vterm.pc.in \ src/libvterm/doc/URLs \ src/libvterm/doc/seqs.txt \ + src/libvterm/find-wide-chars.pl \ src/libvterm/include/vterm.h \ src/libvterm/include/vterm_keycodes.h \ src/libvterm/src/encoding.c \ @@ -312,6 +313,7 @@ SRC_ALL = \ src/libvterm/src/encoding/DECdrawing.tbl \ src/libvterm/src/encoding/uk.inc \ src/libvterm/src/encoding/uk.tbl \ + src/libvterm/src/fullwidth.inc \ src/libvterm/src/keyboard.c \ src/libvterm/src/mouse.c \ src/libvterm/src/parser.c \ diff --git a/src/libvterm/Makefile b/src/libvterm/Makefile index 2fca6ad185..e56c10adf3 100644 --- a/src/libvterm/Makefile +++ b/src/libvterm/Makefile @@ -66,6 +66,9 @@ src/%.lo: src/%.c $(HFILES_INT) src/encoding/%.inc: src/encoding/%.tbl perl -CSD tbl2inc_c.pl $< >$@ +src/fullwidth.inc: + @perl find-wide-chars.pl >$@ + src/encoding.lo: $(INCFILES) bin/%: bin/%.c $(LIBRARY) diff --git a/src/libvterm/README b/src/libvterm/README index 208066bdeb..3e1ff30a87 100644 --- a/src/libvterm/README +++ b/src/libvterm/README @@ -11,6 +11,9 @@ Modifications: - Convert from C99 to C90. - Other changes to support embedding in Vim. +To find the diff of a libvterm patch edit this URL, changing "999" to the patch +number: + https://bazaar.launchpad.net/~libvterm/libvterm/trunk/diff/999?context=3 To merge in changes from Github, do this: - Commit any pending changes. diff --git a/src/libvterm/find-wide-chars.pl b/src/libvterm/find-wide-chars.pl new file mode 100644 index 0000000000..fc4a23444c --- /dev/null +++ b/src/libvterm/find-wide-chars.pl @@ -0,0 +1,34 @@ +#!/usr/bin/perl + +use strict; +use warnings; + +use Unicode::UCD qw( charprop ); + +STDOUT->autoflush(1); + +sub iswide +{ + my ( $cp ) = @_; + + my $width = charprop( $cp, "East_Asian_Width" ) or return; + return $width eq "Wide" || $width eq "Fullwidth"; +} + +my ( $start, $end ); +foreach my $cp ( 0 .. 0x1FFFF ) { + iswide($cp) or next; + + if( defined $end and $end == $cp-1 ) { + # extend the range + $end = $cp; + next; + } + + # start a new range + printf " { %#04x, %#04x },\n", $start, $end if defined $start; + + $start = $end = $cp; +} + +printf " { %#04x, %#04x },\n", $start, $end if defined $start; diff --git a/src/libvterm/src/fullwidth.inc b/src/libvterm/src/fullwidth.inc new file mode 100644 index 0000000000..7ff142f77c --- /dev/null +++ b/src/libvterm/src/fullwidth.inc @@ -0,0 +1,104 @@ + { 0x1100, 0x115f }, + { 0x231a, 0x231b }, + { 0x2329, 0x232a }, + { 0x23e9, 0x23ec }, + { 0x23f0, 0x23f0 }, + { 0x23f3, 0x23f3 }, + { 0x25fd, 0x25fe }, + { 0x2614, 0x2615 }, + { 0x2648, 0x2653 }, + { 0x267f, 0x267f }, + { 0x2693, 0x2693 }, + { 0x26a1, 0x26a1 }, + { 0x26aa, 0x26ab }, + { 0x26bd, 0x26be }, + { 0x26c4, 0x26c5 }, + { 0x26ce, 0x26ce }, + { 0x26d4, 0x26d4 }, + { 0x26ea, 0x26ea }, + { 0x26f2, 0x26f3 }, + { 0x26f5, 0x26f5 }, + { 0x26fa, 0x26fa }, + { 0x26fd, 0x26fd }, + { 0x2705, 0x2705 }, + { 0x270a, 0x270b }, + { 0x2728, 0x2728 }, + { 0x274c, 0x274c }, + { 0x274e, 0x274e }, + { 0x2753, 0x2755 }, + { 0x2757, 0x2757 }, + { 0x2795, 0x2797 }, + { 0x27b0, 0x27b0 }, + { 0x27bf, 0x27bf }, + { 0x2b1b, 0x2b1c }, + { 0x2b50, 0x2b50 }, + { 0x2b55, 0x2b55 }, + { 0x2e80, 0x2e99 }, + { 0x2e9b, 0x2ef3 }, + { 0x2f00, 0x2fd5 }, + { 0x2ff0, 0x2ffb }, + { 0x3000, 0x303e }, + { 0x3041, 0x3096 }, + { 0x3099, 0x30ff }, + { 0x3105, 0x312d }, + { 0x3131, 0x318e }, + { 0x3190, 0x31ba }, + { 0x31c0, 0x31e3 }, + { 0x31f0, 0x321e }, + { 0x3220, 0x3247 }, + { 0x3250, 0x32fe }, + { 0x3300, 0x4dbf }, + { 0x4e00, 0xa48c }, + { 0xa490, 0xa4c6 }, + { 0xa960, 0xa97c }, + { 0xac00, 0xd7a3 }, + { 0xf900, 0xfaff }, + { 0xfe10, 0xfe19 }, + { 0xfe30, 0xfe52 }, + { 0xfe54, 0xfe66 }, + { 0xfe68, 0xfe6b }, + { 0xff01, 0xff60 }, + { 0xffe0, 0xffe6 }, + { 0x16fe0, 0x16fe0 }, + { 0x17000, 0x187ec }, + { 0x18800, 0x18af2 }, + { 0x1b000, 0x1b001 }, + { 0x1f004, 0x1f004 }, + { 0x1f0cf, 0x1f0cf }, + { 0x1f18e, 0x1f18e }, + { 0x1f191, 0x1f19a }, + { 0x1f200, 0x1f202 }, + { 0x1f210, 0x1f23b }, + { 0x1f240, 0x1f248 }, + { 0x1f250, 0x1f251 }, + { 0x1f300, 0x1f320 }, + { 0x1f32d, 0x1f335 }, + { 0x1f337, 0x1f37c }, + { 0x1f37e, 0x1f393 }, + { 0x1f3a0, 0x1f3ca }, + { 0x1f3cf, 0x1f3d3 }, + { 0x1f3e0, 0x1f3f0 }, + { 0x1f3f4, 0x1f3f4 }, + { 0x1f3f8, 0x1f43e }, + { 0x1f440, 0x1f440 }, + { 0x1f442, 0x1f4fc }, + { 0x1f4ff, 0x1f53d }, + { 0x1f54b, 0x1f54e }, + { 0x1f550, 0x1f567 }, + { 0x1f57a, 0x1f57a }, + { 0x1f595, 0x1f596 }, + { 0x1f5a4, 0x1f5a4 }, + { 0x1f5fb, 0x1f64f }, + { 0x1f680, 0x1f6c5 }, + { 0x1f6cc, 0x1f6cc }, + { 0x1f6d0, 0x1f6d2 }, + { 0x1f6eb, 0x1f6ec }, + { 0x1f6f4, 0x1f6f6 }, + { 0x1f910, 0x1f91e }, + { 0x1f920, 0x1f927 }, + { 0x1f930, 0x1f930 }, + { 0x1f933, 0x1f93e }, + { 0x1f940, 0x1f94b }, + { 0x1f950, 0x1f95e }, + { 0x1f980, 0x1f991 }, + { 0x1f9c0, 0x1f9c0 }, diff --git a/src/libvterm/src/unicode.c b/src/libvterm/src/unicode.c index 424b3e206e..1c0b2db3a1 100644 --- a/src/libvterm/src/unicode.c +++ b/src/libvterm/src/unicode.c @@ -591,8 +591,15 @@ vterm_get_special_pty_type_placeholder(void) // ################################ // ### The rest added by Paul Evans +static const struct interval fullwidth[] = { +#include "fullwidth.inc" +}; + INTERNAL int vterm_unicode_width(uint32_t codepoint) { + if(bisearch(codepoint, fullwidth, sizeof(fullwidth) / sizeof(fullwidth[0]) - 1)) + return 2; + return WCWIDTH_FUNCTION(codepoint); } diff --git a/src/version.c b/src/version.c index cc092c29fb..ccd564475c 100644 --- a/src/version.c +++ b/src/version.c @@ -746,6 +746,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 776, /**/ 775, /**/ From 79ea680e6b1dd02035fdf8a5521927cf1f98c2ed Mon Sep 17 00:00:00 2001 From: Bram Moolenaar <Bram@vim.org> Date: Sun, 17 May 2020 15:09:27 +0200 Subject: [PATCH 175/230] patch 8.2.0777: terminal test fails Problem: Terminal test fails. Solution: Adjust character position for double-wide characters. --- src/testdir/test_terminal.vim | 8 ++++---- src/version.c | 2 ++ 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/src/testdir/test_terminal.vim b/src/testdir/test_terminal.vim index 33ff52fa48..ab1961aa37 100644 --- a/src/testdir/test_terminal.vim +++ b/src/testdir/test_terminal.vim @@ -938,10 +938,10 @@ func Test_terminal_composing_unicode() call WaitForAssert({-> assert_equal(txt, term_getline(buf, lnum[1] + 1))}, 1000) let l = term_scrape(buf, lnum[1] + 1) call assert_equal("\u304b\u3099", l[0].chars) - call assert_equal("\u304e", l[1].chars) - call assert_equal("\u304f\u3099", l[2].chars) - call assert_equal("\u3052", l[3].chars) - call assert_equal("\u3053\u3099", l[4].chars) + call assert_equal("\u304e", l[2].chars) + call assert_equal("\u304f\u3099", l[3].chars) + call assert_equal("\u3052", l[5].chars) + call assert_equal("\u3053\u3099", l[6].chars) " \u00a0 + composing let txt = "abc\u00a0\u0308" diff --git a/src/version.c b/src/version.c index ccd564475c..b7e6d5caf8 100644 --- a/src/version.c +++ b/src/version.c @@ -746,6 +746,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 777, /**/ 776, /**/ From ed37d9b3241abe7c302c7ac606df80037aecdb46 Mon Sep 17 00:00:00 2001 From: Bram Moolenaar <bram@moolenaar.net> Date: Sun, 17 May 2020 15:17:26 +0200 Subject: [PATCH 176/230] Update feature_request.md --- .github/ISSUE_TEMPLATE/feature_request.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/ISSUE_TEMPLATE/feature_request.md b/.github/ISSUE_TEMPLATE/feature_request.md index f78a84b567..8fa535d540 100644 --- a/.github/ISSUE_TEMPLATE/feature_request.md +++ b/.github/ISSUE_TEMPLATE/feature_request.md @@ -8,7 +8,7 @@ labels: enhancement _Instructions: Replace the template text and remove irrelevant text (including this line)_ -**Is your feature request related something that is currently hard to do? Please describe.** +**Is your feature request about something that is currently impossible or hard to do? Please describe the problem.** A clear and concise description of what is hard to do. Ex. It is difficult to [...] when [...] (If it is related to runtime files, please check their header for where to discuss enhancements.) From d4a5f40c0cc45fdfac01df0e408d557006eb0206 Mon Sep 17 00:00:00 2001 From: Bram Moolenaar <Bram@vim.org> Date: Sun, 17 May 2020 16:04:44 +0200 Subject: [PATCH 177/230] patch 8.2.0778: libvterm code lags behind the upstream version Problem: Libvterm code lags behind the upstream version. Solution: Include revisions 720 - 723. --- src/libvterm/Makefile | 2 +- src/libvterm/src/state.c | 21 ++++- src/libvterm/t/10state_putglyph.test | 7 ++ src/libvterm/t/92lp1805050.test | 128 +++++++++++++++++++++++++++ src/libvterm/t/run-test.pl | 4 +- src/version.c | 2 + 6 files changed, 161 insertions(+), 3 deletions(-) create mode 100644 src/libvterm/t/92lp1805050.test diff --git a/src/libvterm/Makefile b/src/libvterm/Makefile index e56c10adf3..f231dd3b52 100644 --- a/src/libvterm/Makefile +++ b/src/libvterm/Makefile @@ -118,7 +118,7 @@ distdir: $(INCFILES) mkdir __distdir cp LICENSE __distdir mkdir __distdir/src - cp src/*.c src/*.h __distdir/src + cp src/*.c src/*.h src/*.inc __distdir/src mkdir __distdir/src/encoding cp src/encoding/*.inc __distdir/src/encoding mkdir __distdir/include diff --git a/src/libvterm/src/state.c b/src/libvterm/src/state.c index 6b2583af99..89803016ff 100644 --- a/src/libvterm/src/state.c +++ b/src/libvterm/src/state.c @@ -922,6 +922,7 @@ static int on_csi(const char *leader, const long args[], int argcount, const cha VTermState *state = user; int leader_byte = 0; int intermed_byte = 0; + int cancel_phantom = 1; VTermPos oldpos = state->pos; int handled = 1; @@ -1237,6 +1238,24 @@ static int on_csi(const char *leader, const long args[], int argcount, const cha state->at_phantom = 0; break; + case 0x62: { // REP - ECMA-48 8.3.103 + const int row_width = THISROWWIDTH(state); + count = CSI_ARG_COUNT(args[0]); + col = state->pos.col + count; + UBOUND(col, row_width); + while (state->pos.col < col) { + putglyph(state, state->combine_chars, state->combine_width, state->pos); + state->pos.col += state->combine_width; + } + if (state->pos.col + state->combine_width >= row_width) { + if (state->mode.autowrap) { + state->at_phantom = 1; + cancel_phantom = 0; + } + } + break; + } + case 0x63: // DA - ECMA-48 8.3.24 val = CSI_ARG_OR(args[0], 0); if(val == 0) @@ -1523,7 +1542,7 @@ static int on_csi(const char *leader, const long args[], int argcount, const cha UBOUND(state->pos.col, THISROWWIDTH(state)-1); } - updatecursor(state, &oldpos, 1); + updatecursor(state, &oldpos, cancel_phantom); #ifdef DEBUG if(state->pos.row < 0 || state->pos.row >= state->rows || diff --git a/src/libvterm/t/10state_putglyph.test b/src/libvterm/t/10state_putglyph.test index 6d5d56a38d..bae0423b17 100644 --- a/src/libvterm/t/10state_putglyph.test +++ b/src/libvterm/t/10state_putglyph.test @@ -30,6 +30,13 @@ PUSH "\xEF\xBC\x90 " putglyph 0xff10 2 0,0 putglyph 0x20 1 0,2 +!UTF-8 emoji wide char +# U+1F600 = 0xF0 0x9F 0x98 0x80 name: GRINNING FACE +RESET +PUSH "\xF0\x9F\x98\x80 " + putglyph 0x1f600 2 0,0 + putglyph 0x20 1 0,2 + !UTF-8 combining chars # U+0301 = 0xCC 0x81 name: COMBINING ACUTE RESET diff --git a/src/libvterm/t/92lp1805050.test b/src/libvterm/t/92lp1805050.test new file mode 100644 index 0000000000..f820e675cf --- /dev/null +++ b/src/libvterm/t/92lp1805050.test @@ -0,0 +1,128 @@ +INIT +UTF8 1 +WANTSTATE g + +!REP no argument +RESET +PUSH "a\e[b" + putglyph 0x61 1 0,0 + putglyph 0x61 1 0,1 + +!REP zero (zero should be interpreted as one) +RESET +PUSH "a\e[0b" + putglyph 0x61 1 0,0 + putglyph 0x61 1 0,1 + +!REP lowercase a times two +RESET +PUSH "a\e[2b" + putglyph 0x61 1 0,0 + putglyph 0x61 1 0,1 + putglyph 0x61 1 0,2 + +!REP with UTF-8 1 char +# U+00E9 = 0xC3 0xA9 name: LATIN SMALL LETTER E WITH ACUTE +RESET +PUSH "\xC3\xA9\e[b" + putglyph 0xe9 1 0,0 + putglyph 0xe9 1 0,1 + +!REP with UTF-8 wide char +# U+00E9 = 0xC3 0xA9 name: LATIN SMALL LETTER E WITH ACUTE +RESET +PUSH "\xEF\xBC\x90\e[b" + putglyph 0xff10 2 0,0 + putglyph 0xff10 2 0,2 + +!REP with UTF-8 combining character +RESET +PUSH "e\xCC\x81\e[b" + putglyph 0x65,0x301 1 0,0 + putglyph 0x65,0x301 1 0,1 + +!REP till end of line +RESET +PUSH "a\e[1000bb" + putglyph 0x61 1 0,0 + putglyph 0x61 1 0,1 + putglyph 0x61 1 0,2 + putglyph 0x61 1 0,3 + putglyph 0x61 1 0,4 + putglyph 0x61 1 0,5 + putglyph 0x61 1 0,6 + putglyph 0x61 1 0,7 + putglyph 0x61 1 0,8 + putglyph 0x61 1 0,9 + putglyph 0x61 1 0,10 + putglyph 0x61 1 0,11 + putglyph 0x61 1 0,12 + putglyph 0x61 1 0,13 + putglyph 0x61 1 0,14 + putglyph 0x61 1 0,15 + putglyph 0x61 1 0,16 + putglyph 0x61 1 0,17 + putglyph 0x61 1 0,18 + putglyph 0x61 1 0,19 + putglyph 0x61 1 0,20 + putglyph 0x61 1 0,21 + putglyph 0x61 1 0,22 + putglyph 0x61 1 0,23 + putglyph 0x61 1 0,24 + putglyph 0x61 1 0,25 + putglyph 0x61 1 0,26 + putglyph 0x61 1 0,27 + putglyph 0x61 1 0,28 + putglyph 0x61 1 0,29 + putglyph 0x61 1 0,30 + putglyph 0x61 1 0,31 + putglyph 0x61 1 0,32 + putglyph 0x61 1 0,33 + putglyph 0x61 1 0,34 + putglyph 0x61 1 0,35 + putglyph 0x61 1 0,36 + putglyph 0x61 1 0,37 + putglyph 0x61 1 0,38 + putglyph 0x61 1 0,39 + putglyph 0x61 1 0,40 + putglyph 0x61 1 0,41 + putglyph 0x61 1 0,42 + putglyph 0x61 1 0,43 + putglyph 0x61 1 0,44 + putglyph 0x61 1 0,45 + putglyph 0x61 1 0,46 + putglyph 0x61 1 0,47 + putglyph 0x61 1 0,48 + putglyph 0x61 1 0,49 + putglyph 0x61 1 0,50 + putglyph 0x61 1 0,51 + putglyph 0x61 1 0,52 + putglyph 0x61 1 0,53 + putglyph 0x61 1 0,54 + putglyph 0x61 1 0,55 + putglyph 0x61 1 0,56 + putglyph 0x61 1 0,57 + putglyph 0x61 1 0,58 + putglyph 0x61 1 0,59 + putglyph 0x61 1 0,60 + putglyph 0x61 1 0,61 + putglyph 0x61 1 0,62 + putglyph 0x61 1 0,63 + putglyph 0x61 1 0,64 + putglyph 0x61 1 0,65 + putglyph 0x61 1 0,66 + putglyph 0x61 1 0,67 + putglyph 0x61 1 0,68 + putglyph 0x61 1 0,69 + putglyph 0x61 1 0,70 + putglyph 0x61 1 0,71 + putglyph 0x61 1 0,72 + putglyph 0x61 1 0,73 + putglyph 0x61 1 0,74 + putglyph 0x61 1 0,75 + putglyph 0x61 1 0,76 + putglyph 0x61 1 0,77 + putglyph 0x61 1 0,78 + putglyph 0x61 1 0,79 + putglyph 0x62 1 1,0 + diff --git a/src/libvterm/t/run-test.pl b/src/libvterm/t/run-test.pl index 12e11801b6..1b2144a9e4 100644 --- a/src/libvterm/t/run-test.pl +++ b/src/libvterm/t/run-test.pl @@ -8,14 +8,16 @@ use IPC::Open2 qw( open2 ); use POSIX qw( WIFEXITED WEXITSTATUS WIFSIGNALED WTERMSIG ); my $VALGRIND = 0; +my $EXECUTABLE = "t/.libs/harness"; GetOptions( 'valgrind|v+' => \$VALGRIND, + 'executable|e=s' => \$EXECUTABLE ) or exit 1; my ( $hin, $hout, $hpid ); { local $ENV{LD_LIBRARY_PATH} = ".libs"; - my @command = "t/.libs/harness"; + my @command = $EXECUTABLE; unshift @command, "valgrind", "--tool=memcheck", "--leak-check=yes", "--num-callers=25", "--log-file=valgrind.out", "--error-exitcode=126" if $VALGRIND; $hpid = open2 $hout, $hin, @command or die "Cannot open2 harness - $!"; diff --git a/src/version.c b/src/version.c index b7e6d5caf8..fa05a76cd7 100644 --- a/src/version.c +++ b/src/version.c @@ -746,6 +746,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 778, /**/ 777, /**/ From f4e16ae041962555316a6953df30a45f4c45be6a Mon Sep 17 00:00:00 2001 From: Bram Moolenaar <Bram@vim.org> Date: Sun, 17 May 2020 16:10:11 +0200 Subject: [PATCH 178/230] patch 8.2.0779: tmode_T not used everywhere Problem: Tmode_T not used everywhere. Solution: Also use tmode_T for settmode(). --- src/proto/term.pro | 2 +- src/term.c | 2 +- src/version.c | 2 ++ 3 files changed, 4 insertions(+), 2 deletions(-) diff --git a/src/proto/term.pro b/src/proto/term.pro index 4ac2858ab2..fa7c69d9f3 100644 --- a/src/proto/term.pro +++ b/src/proto/term.pro @@ -41,7 +41,7 @@ void win_new_shellsize(void); void shell_resized(void); void shell_resized_check(void); void set_shellsize(int width, int height, int mustset); -void settmode(int tmode); +void settmode(tmode_T tmode); void starttermcap(void); void stoptermcap(void); void may_req_termresponse(void); diff --git a/src/term.c b/src/term.c index a575227072..11972a15b0 100644 --- a/src/term.c +++ b/src/term.c @@ -3436,7 +3436,7 @@ set_shellsize(int width, int height, int mustset) * commands and Ex mode). */ void -settmode(int tmode) +settmode(tmode_T tmode) { #ifdef FEAT_GUI // don't set the term where gvim was started to any mode diff --git a/src/version.c b/src/version.c index fa05a76cd7..8e91aea327 100644 --- a/src/version.c +++ b/src/version.c @@ -746,6 +746,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 779, /**/ 778, /**/ From 2d2970ea599e83acabee56be548a54a8e6b21007 Mon Sep 17 00:00:00 2001 From: Bram Moolenaar <Bram@vim.org> Date: Sun, 17 May 2020 16:29:47 +0200 Subject: [PATCH 179/230] patch 8.2.0780: libvterm code lags behind the upstream version Problem: Libvterm code lags behind the upstream version. Solution: Include revisions 724 - 726. --- Filelist | 21 ++++++++++--------- src/libvterm/doc/seqs.txt | 1 + .../t/{30pen.test => 30state_pen.test} | 0 .../t/{92lp1805050.test => 31state_rep.test} | 0 ...0screen_ascii.test => 60screen_ascii.test} | 0 ...een_unicode.test => 61screen_unicode.test} | 0 ...creen_damage.test => 62screen_damage.test} | 0 ...creen_resize.test => 63screen_resize.test} | 0 .../{44screen_pen.test => 64screen_pen.test} | 0 ...een_protect.test => 65screen_protect.test} | 0 ...creen_extent.test => 66screen_extent.test} | 0 ...creen_dbl_wh.test => 67screen_dbl_wh.test} | 0 ...termprops.test => 68screen_termprops.test} | 0 src/version.c | 2 ++ 14 files changed, 14 insertions(+), 10 deletions(-) rename src/libvterm/t/{30pen.test => 30state_pen.test} (100%) rename src/libvterm/t/{92lp1805050.test => 31state_rep.test} (100%) rename src/libvterm/t/{40screen_ascii.test => 60screen_ascii.test} (100%) rename src/libvterm/t/{41screen_unicode.test => 61screen_unicode.test} (100%) rename src/libvterm/t/{42screen_damage.test => 62screen_damage.test} (100%) rename src/libvterm/t/{43screen_resize.test => 63screen_resize.test} (100%) rename src/libvterm/t/{44screen_pen.test => 64screen_pen.test} (100%) rename src/libvterm/t/{45screen_protect.test => 65screen_protect.test} (100%) rename src/libvterm/t/{46screen_extent.test => 66screen_extent.test} (100%) rename src/libvterm/t/{47screen_dbl_wh.test => 67screen_dbl_wh.test} (100%) rename src/libvterm/t/{48screen_termprops.test => 68screen_termprops.test} (100%) diff --git a/Filelist b/Filelist index be1b36eacc..21ec37d7a4 100644 --- a/Filelist +++ b/Filelist @@ -344,16 +344,17 @@ SRC_ALL = \ src/libvterm/t/27state_reset.test \ src/libvterm/t/28state_dbl_wh.test \ src/libvterm/t/29state_fallback.test \ - src/libvterm/t/30pen.test \ - src/libvterm/t/40screen_ascii.test \ - src/libvterm/t/41screen_unicode.test \ - src/libvterm/t/42screen_damage.test \ - src/libvterm/t/43screen_resize.test \ - src/libvterm/t/44screen_pen.test \ - src/libvterm/t/45screen_protect.test \ - src/libvterm/t/46screen_extent.test \ - src/libvterm/t/47screen_dbl_wh.test \ - src/libvterm/t/48screen_termprops.test \ + src/libvterm/t/30state_pen.test \ + src/libvterm/t/31state_rep.test \ + src/libvterm/t/60screen_ascii.test \ + src/libvterm/t/61screen_unicode.test \ + src/libvterm/t/62screen_damage.test \ + src/libvterm/t/63screen_resize.test \ + src/libvterm/t/64screen_pen.test \ + src/libvterm/t/65screen_protect.test \ + src/libvterm/t/66screen_extent.test \ + src/libvterm/t/67screen_dbl_wh.test \ + src/libvterm/t/68screen_termprops.test \ src/libvterm/t/90vttest_01-movement-1.test \ src/libvterm/t/90vttest_01-movement-2.test \ src/libvterm/t/90vttest_01-movement-3.test \ diff --git a/src/libvterm/doc/seqs.txt b/src/libvterm/doc/seqs.txt index c26dc44990..164120cee8 100644 --- a/src/libvterm/doc/seqs.txt +++ b/src/libvterm/doc/seqs.txt @@ -97,6 +97,7 @@ between states. CSI Z = CBT CSI ` = HPA CSI a = HPR + CSI b = REP 123 CSI c = DA, device attributes 123 0 = DA 23 CSI > c = DECSDA diff --git a/src/libvterm/t/30pen.test b/src/libvterm/t/30state_pen.test similarity index 100% rename from src/libvterm/t/30pen.test rename to src/libvterm/t/30state_pen.test diff --git a/src/libvterm/t/92lp1805050.test b/src/libvterm/t/31state_rep.test similarity index 100% rename from src/libvterm/t/92lp1805050.test rename to src/libvterm/t/31state_rep.test diff --git a/src/libvterm/t/40screen_ascii.test b/src/libvterm/t/60screen_ascii.test similarity index 100% rename from src/libvterm/t/40screen_ascii.test rename to src/libvterm/t/60screen_ascii.test diff --git a/src/libvterm/t/41screen_unicode.test b/src/libvterm/t/61screen_unicode.test similarity index 100% rename from src/libvterm/t/41screen_unicode.test rename to src/libvterm/t/61screen_unicode.test diff --git a/src/libvterm/t/42screen_damage.test b/src/libvterm/t/62screen_damage.test similarity index 100% rename from src/libvterm/t/42screen_damage.test rename to src/libvterm/t/62screen_damage.test diff --git a/src/libvterm/t/43screen_resize.test b/src/libvterm/t/63screen_resize.test similarity index 100% rename from src/libvterm/t/43screen_resize.test rename to src/libvterm/t/63screen_resize.test diff --git a/src/libvterm/t/44screen_pen.test b/src/libvterm/t/64screen_pen.test similarity index 100% rename from src/libvterm/t/44screen_pen.test rename to src/libvterm/t/64screen_pen.test diff --git a/src/libvterm/t/45screen_protect.test b/src/libvterm/t/65screen_protect.test similarity index 100% rename from src/libvterm/t/45screen_protect.test rename to src/libvterm/t/65screen_protect.test diff --git a/src/libvterm/t/46screen_extent.test b/src/libvterm/t/66screen_extent.test similarity index 100% rename from src/libvterm/t/46screen_extent.test rename to src/libvterm/t/66screen_extent.test diff --git a/src/libvterm/t/47screen_dbl_wh.test b/src/libvterm/t/67screen_dbl_wh.test similarity index 100% rename from src/libvterm/t/47screen_dbl_wh.test rename to src/libvterm/t/67screen_dbl_wh.test diff --git a/src/libvterm/t/48screen_termprops.test b/src/libvterm/t/68screen_termprops.test similarity index 100% rename from src/libvterm/t/48screen_termprops.test rename to src/libvterm/t/68screen_termprops.test diff --git a/src/version.c b/src/version.c index 8e91aea327..5946964e51 100644 --- a/src/version.c +++ b/src/version.c @@ -746,6 +746,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 780, /**/ 779, /**/ From 9309eb2f28e6ee346c2a5deaa6f9c2b36578522e Mon Sep 17 00:00:00 2001 From: Bram Moolenaar <Bram@vim.org> Date: Sun, 17 May 2020 16:53:56 +0200 Subject: [PATCH 180/230] patch 8.2.0781: compiler warning for not using value in Lua Problem: Compiler warning for not using value in Lua. Solution: Add "(void)". --- src/if_lua.c | 2 +- src/version.c | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/src/if_lua.c b/src/if_lua.c index d4cc21f3d0..060cb38cd6 100644 --- a/src/if_lua.c +++ b/src/if_lua.c @@ -2124,7 +2124,7 @@ luaopen_vim(lua_State *L) luaV_openlib(L, luaV_module, 1); lua_setglobal(L, LUAVIM_NAME); // custom code - luaL_dostring(L, LUA_VIM_FN_CODE); + (void)luaL_dostring(L, LUA_VIM_FN_CODE); return 0; } diff --git a/src/version.c b/src/version.c index 5946964e51..641aa88165 100644 --- a/src/version.c +++ b/src/version.c @@ -746,6 +746,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 781, /**/ 780, /**/ From df1643a6a7886b9363c2a98438e61cbe1c803d41 Mon Sep 17 00:00:00 2001 From: Bram Moolenaar <Bram@vim.org> Date: Sun, 17 May 2020 18:53:27 +0200 Subject: [PATCH 181/230] patch 8.2.0782: cannot build with Lua on MS-Windows Problem: Cannot build with Lua on MS-Windows. Solution: Add DLL symbol for luaL_Loadstring. (Ken Takata) --- src/if_lua.c | 3 +++ src/version.c | 2 ++ 2 files changed, 5 insertions(+) diff --git a/src/if_lua.c b/src/if_lua.c index 060cb38cd6..9a3081bb4f 100644 --- a/src/if_lua.c +++ b/src/if_lua.c @@ -119,6 +119,7 @@ static luaV_Funcref *luaV_pushfuncref(lua_State *L, char_u *name); #define luaL_buffinit dll_luaL_buffinit #define luaL_addlstring dll_luaL_addlstring #define luaL_pushresult dll_luaL_pushresult +#define luaL_loadstring dll_luaL_loadstring // lua #if LUA_VERSION_NUM <= 501 #define lua_tonumber dll_lua_tonumber @@ -213,6 +214,7 @@ lua_State *(*dll_luaL_newstate) (void); void (*dll_luaL_buffinit) (lua_State *L, luaL_Buffer *B); void (*dll_luaL_addlstring) (luaL_Buffer *B, const char *s, size_t l); void (*dll_luaL_pushresult) (luaL_Buffer *B); +int (*dll_luaL_loadstring) (lua_State *L, const char *s); // lua #if LUA_VERSION_NUM <= 501 lua_Number (*dll_lua_tonumber) (lua_State *L, int idx); @@ -325,6 +327,7 @@ static const luaV_Reg luaV_dll[] = { {"luaL_buffinit", (luaV_function) &dll_luaL_buffinit}, {"luaL_addlstring", (luaV_function) &dll_luaL_addlstring}, {"luaL_pushresult", (luaV_function) &dll_luaL_pushresult}, + {"luaL_loadstring", (luaV_function) &dll_luaL_loadstring}, // lua #if LUA_VERSION_NUM <= 501 {"lua_tonumber", (luaV_function) &dll_lua_tonumber}, diff --git a/src/version.c b/src/version.c index 641aa88165..f047bde574 100644 --- a/src/version.c +++ b/src/version.c @@ -746,6 +746,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 782, /**/ 781, /**/ From c4c9f7e43e7229c78919a5618003ce8aac3e1785 Mon Sep 17 00:00:00 2001 From: Bram Moolenaar <Bram@vim.org> Date: Sun, 17 May 2020 20:52:45 +0200 Subject: [PATCH 182/230] patch 8.2.0783: libvterm code lags behind the upstream version Problem: Libvterm code lags behind the upstream version. Solution: Include revisions 728 - 729. --- src/Make_cyg_ming.mak | 1 + src/Make_mvc.mak | 1 + src/Makefile | 1 + src/libvterm/src/keyboard.c | 8 +-- src/libvterm/src/vterm.c | 88 ++++++++++++++----------------- src/libvterm/src/vterm_internal.h | 3 ++ src/libvterm/t/25state_input.test | 12 +++++ src/libvterm/t/26state_query.test | 2 +- src/libvterm/t/harness.c | 1 + src/version.c | 2 + 10 files changed, 67 insertions(+), 52 deletions(-) diff --git a/src/Make_cyg_ming.mak b/src/Make_cyg_ming.mak index 94561e51b2..517ed2bfbc 100644 --- a/src/Make_cyg_ming.mak +++ b/src/Make_cyg_ming.mak @@ -1246,6 +1246,7 @@ $(OUTDIR)/pathdef.o: $(PATHDEF_SRC) $(INCL) CCCTERM = $(CC) -c $(CFLAGS) -Ilibvterm/include -DINLINE="" \ -DVSNPRINTF=vim_vsnprintf \ + -DSNPRINTF=vim_snprintf \ -DIS_COMBINING_FUNCTION=utf_iscomposing_uint \ -DWCWIDTH_FUNCTION=utf_uint2cells \ -DGET_SPECIAL_PTY_TYPE_FUNCTION=get_special_pty_type diff --git a/src/Make_mvc.mak b/src/Make_mvc.mak index c93517b980..8240f50568 100644 --- a/src/Make_mvc.mak +++ b/src/Make_mvc.mak @@ -1812,6 +1812,7 @@ $(OUTDIR)/glbl_ime.obj: $(OUTDIR) glbl_ime.cpp dimm.h $(INCL) CCCTERM = $(CC) $(CFLAGS) -Ilibvterm/include -DINLINE="" \ -DVSNPRINTF=vim_vsnprintf \ + -DSNPRINTF=vim_snprintf \ -DIS_COMBINING_FUNCTION=utf_iscomposing_uint \ -DWCWIDTH_FUNCTION=utf_uint2cells \ -DGET_SPECIAL_PTY_TYPE_FUNCTION=get_special_pty_type \ diff --git a/src/Makefile b/src/Makefile index 7c2934aea3..ad8f241de7 100644 --- a/src/Makefile +++ b/src/Makefile @@ -3537,6 +3537,7 @@ Makefile: # prefix vterm_ to avoid name clashes. CCCTERM = $(CCC_NF) $(VTERM_CFLAGS) $(ALL_CFLAGS) -DINLINE="" \ -DVSNPRINTF=vim_vsnprintf \ + -DSNPRINTF=vim_snprintf \ -DIS_COMBINING_FUNCTION=utf_iscomposing_uint \ -DWCWIDTH_FUNCTION=utf_uint2cells diff --git a/src/libvterm/src/keyboard.c b/src/libvterm/src/keyboard.c index 95b962ed64..9c2a53d7b1 100644 --- a/src/libvterm/src/keyboard.c +++ b/src/libvterm/src/keyboard.c @@ -102,10 +102,10 @@ static keycodes_s keycodes[] = { static keycodes_s keycodes_fn[] = { { KEYCODE_NONE, 0, 0 }, // F0 - shouldn't happen - { KEYCODE_CSI_CURSOR, 'P', 0 }, // F1 - { KEYCODE_CSI_CURSOR, 'Q', 0 }, // F2 - { KEYCODE_CSI_CURSOR, 'R', 0 }, // F3 - { KEYCODE_CSI_CURSOR, 'S', 0 }, // F4 + { KEYCODE_SS3, 'P', 0 }, // F1 + { KEYCODE_SS3, 'Q', 0 }, // F2 + { KEYCODE_SS3, 'R', 0 }, // F3 + { KEYCODE_SS3, 'S', 0 }, // F4 { KEYCODE_CSINUM, '~', 15 }, // F5 { KEYCODE_CSINUM, '~', 17 }, // F6 { KEYCODE_CSINUM, '~', 18 }, // F7 diff --git a/src/libvterm/src/vterm.c b/src/libvterm/src/vterm.c index 1d6a977f1b..56c4e28d99 100644 --- a/src/libvterm/src/vterm.c +++ b/src/libvterm/src/vterm.c @@ -74,6 +74,9 @@ VTerm *vterm_new_with_allocator(int rows, int cols, VTermAllocatorFunctions *fun return NULL; } + vt->tmpbuffer_len = 64; + vt->tmpbuffer = vterm_allocator_malloc(vt, vt->tmpbuffer_len); + return vt; } @@ -135,67 +138,46 @@ void vterm_set_utf8(VTerm *vt, int is_utf8) INTERNAL void vterm_push_output_bytes(VTerm *vt, const char *bytes, size_t len) { if(len > vt->outbuffer_len - vt->outbuffer_cur) { - DEBUG_LOG("vterm_push_output(): buffer overflow; truncating output\n"); - len = vt->outbuffer_len - vt->outbuffer_cur; + DEBUG_LOG("vterm_push_output_bytes(): buffer overflow; dropping output\n"); + return; } memcpy(vt->outbuffer + vt->outbuffer_cur, bytes, len); vt->outbuffer_cur += len; } -static int outbuffer_is_full(VTerm *vt) -{ - return vt->outbuffer_cur >= vt->outbuffer_len - 1; -} - #if (defined(_XOPEN_SOURCE) && _XOPEN_SOURCE >= 500) \ || defined(_ISOC99_SOURCE) || defined(_BSD_SOURCE) # undef VSNPRINTF # define VSNPRINTF vsnprintf +# undef SNPRINTF +# define SNPRINTF snprintf #else # ifdef VSNPRINTF // Use a provided vsnprintf() function. int VSNPRINTF(char *str, size_t str_m, const char *fmt, va_list ap); # endif +# ifdef SNPRINTF +// Use a provided snprintf() function. +int SNPRINTF(char *str, size_t str_m, const char *fmt, ...); +# endif #endif INTERNAL void vterm_push_output_vsprintf(VTerm *vt, const char *format, va_list args) { - int written; + size_t len; #ifndef VSNPRINTF // When vsnprintf() is not available (C90) fall back to vsprintf(). char buffer[1024]; // 1Kbyte is enough for everybody, right? #endif - if(outbuffer_is_full(vt)) { - DEBUG_LOG("vterm_push_output(): buffer overflow; truncating output\n"); - return; - } - #ifdef VSNPRINTF - written = VSNPRINTF(vt->outbuffer + vt->outbuffer_cur, - vt->outbuffer_len - vt->outbuffer_cur, - format, args); - - if(written == (int)(vt->outbuffer_len - vt->outbuffer_cur)) { - // output was truncated - vt->outbuffer_cur = vt->outbuffer_len - 1; - } - else - vt->outbuffer_cur += written; + len = VSNPRINTF(vt->tmpbuffer, vt->tmpbuffer_len, format, args); + vterm_push_output_bytes(vt, vt->tmpbuffer, len); #else - written = vsprintf(buffer, format, args); - - if(written >= (int)(vt->outbuffer_len - vt->outbuffer_cur - 1)) { - // output was truncated - written = vt->outbuffer_len - vt->outbuffer_cur - 1; - } - if (written > 0) - { - strncpy(vt->outbuffer + vt->outbuffer_cur, buffer, written + 1); - vt->outbuffer_cur += written; - } + len = vsprintf(buffer, format, args); + vterm_push_output_bytes(vt, buffer, len); #endif } @@ -209,40 +191,52 @@ INTERNAL void vterm_push_output_sprintf(VTerm *vt, const char *format, ...) INTERNAL void vterm_push_output_sprintf_ctrl(VTerm *vt, unsigned char ctrl, const char *fmt, ...) { - size_t orig_cur = vt->outbuffer_cur; + size_t cur; va_list args; if(ctrl >= 0x80 && !vt->mode.ctrl8bit) - vterm_push_output_sprintf(vt, ESC_S "%c", ctrl - 0x40); + cur = SNPRINTF(vt->tmpbuffer, vt->tmpbuffer_len, + ESC_S "%c", ctrl - 0x40); else - vterm_push_output_sprintf(vt, "%c", ctrl); + cur = SNPRINTF(vt->tmpbuffer, vt->tmpbuffer_len, + "%c", ctrl); + if(cur >= vt->tmpbuffer_len) + return; + vterm_push_output_bytes(vt, vt->tmpbuffer, cur); va_start(args, fmt); vterm_push_output_vsprintf(vt, fmt, args); va_end(args); - - if(outbuffer_is_full(vt)) - vt->outbuffer_cur = orig_cur; } INTERNAL void vterm_push_output_sprintf_dcs(VTerm *vt, const char *fmt, ...) { - size_t orig_cur = vt->outbuffer_cur; + size_t cur; va_list args; if(!vt->mode.ctrl8bit) - vterm_push_output_sprintf(vt, ESC_S "%c", C1_DCS - 0x40); + cur = SNPRINTF(vt->tmpbuffer, vt->tmpbuffer_len, + ESC_S "%c", C1_DCS - 0x40); else - vterm_push_output_sprintf(vt, "%c", C1_DCS); + cur = SNPRINTF(vt->tmpbuffer, vt->tmpbuffer_len, + "%c", C1_DCS); + if(cur >= vt->tmpbuffer_len) + return; + vterm_push_output_bytes(vt, vt->tmpbuffer, cur); va_start(args, fmt); vterm_push_output_vsprintf(vt, fmt, args); va_end(args); - vterm_push_output_sprintf_ctrl(vt, C1_ST, ""); - - if(outbuffer_is_full(vt)) - vt->outbuffer_cur = orig_cur; + if(!vt->mode.ctrl8bit) + cur = SNPRINTF(vt->tmpbuffer, vt->tmpbuffer_len, + ESC_S "%c", C1_ST - 0x40); + else + cur = SNPRINTF(vt->tmpbuffer, vt->tmpbuffer_len, + "%c", C1_ST); + if(cur >= vt->tmpbuffer_len) + return; + vterm_push_output_bytes(vt, vt->tmpbuffer, cur); } size_t vterm_output_get_buffer_size(const VTerm *vt) diff --git a/src/libvterm/src/vterm_internal.h b/src/libvterm/src/vterm_internal.h index e2b8b159be..6aa1e9cc48 100644 --- a/src/libvterm/src/vterm_internal.h +++ b/src/libvterm/src/vterm_internal.h @@ -211,6 +211,9 @@ struct VTerm size_t outbuffer_len; size_t outbuffer_cur; + char *tmpbuffer; + size_t tmpbuffer_len; + VTermState *state; VTermScreen *screen; diff --git a/src/libvterm/t/25state_input.test b/src/libvterm/t/25state_input.test index a5119fbd87..4eb4c6abdf 100644 --- a/src/libvterm/t/25state_input.test +++ b/src/libvterm/t/25state_input.test @@ -111,6 +111,18 @@ PUSH "\e[20h" INKEY 0 Enter output "\x0d\x0a" +!Unmodified F1 is SS3 P +INKEY 0 F1 + output "\eOP" + +!Modified F1 is CSI P +INKEY S F1 + output "\e[1;2P" +INKEY A F1 + output "\e[1;3P" +INKEY C F1 + output "\e[1;5P" + !Keypad in DECKPNM INKEY 0 KP0 output "0" diff --git a/src/libvterm/t/26state_query.test b/src/libvterm/t/26state_query.test index 3ace2d5323..c6be90b619 100644 --- a/src/libvterm/t/26state_query.test +++ b/src/libvterm/t/26state_query.test @@ -59,4 +59,4 @@ PUSH "\e F" !Truncation on attempted buffer overflow PUSH "\e[6n" x 30 - output "\e[10;10R" x 24 + output "\e[10;10R" x 25 diff --git a/src/libvterm/t/harness.c b/src/libvterm/t/harness.c index 75869d756c..e28bb7d308 100644 --- a/src/libvterm/t/harness.c +++ b/src/libvterm/t/harness.c @@ -47,6 +47,7 @@ static VTermKey strp_key(char *str) { "Tab", VTERM_KEY_TAB }, { "Enter", VTERM_KEY_ENTER }, { "KP0", VTERM_KEY_KP_0 }, + { "F1", VTERM_KEY_FUNCTION(1) }, { NULL, VTERM_KEY_NONE }, }; int i; diff --git a/src/version.c b/src/version.c index f047bde574..ee9a393583 100644 --- a/src/version.c +++ b/src/version.c @@ -746,6 +746,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 783, /**/ 782, /**/ From 94d729cbe8f0f788d9d7539f733cff395e73b228 Mon Sep 17 00:00:00 2001 From: Bram Moolenaar <Bram@vim.org> Date: Sun, 17 May 2020 21:50:16 +0200 Subject: [PATCH 183/230] patch 8.2.0784: libvterm code lags behind the upstream version Problem: Libvterm code lags behind the upstream version. Solution: Include revisions 730 - 733. --- src/libvterm/include/vterm.h | 7 +++++ src/libvterm/src/state.c | 43 +++++++++++++++++++-------- src/libvterm/src/vterm.c | 49 ++++++++++++------------------- src/libvterm/src/vterm_internal.h | 23 +++++++++++++++ src/libvterm/t/harness.c | 3 ++ src/version.c | 2 ++ 6 files changed, 84 insertions(+), 43 deletions(-) diff --git a/src/libvterm/include/vterm.h b/src/libvterm/include/vterm.h index 0238226fbf..b06952195e 100644 --- a/src/libvterm/include/vterm.h +++ b/src/libvterm/include/vterm.h @@ -194,10 +194,17 @@ void vterm_set_utf8(VTerm *vt, int is_utf8); size_t vterm_input_write(VTerm *vt, const char *bytes, size_t len); +/* Setting output callback will override the buffer logic */ +typedef void VTermOutputCallback(const char *s, size_t len, void *user); +void vterm_output_set_callback(VTerm *vt, VTermOutputCallback *func, void *user); + +/* These buffer functions only work if output callback is NOT set + * These are deprecated and will be removed in a later version */ size_t vterm_output_get_buffer_size(const VTerm *vt); size_t vterm_output_get_buffer_current(const VTerm *vt); size_t vterm_output_get_buffer_remaining(const VTerm *vt); +/* This too */ size_t vterm_output_read(VTerm *vt, char *buffer, size_t len); int vterm_is_modify_other_keys(VTerm *vt); diff --git a/src/libvterm/src/state.c b/src/libvterm/src/state.c index 89803016ff..add75ac4e8 100644 --- a/src/libvterm/src/state.c +++ b/src/libvterm/src/state.c @@ -1617,6 +1617,8 @@ static int on_osc(const char *command, size_t cmdlen, void *user) static void request_status_string(VTermState *state, const char *command, size_t cmdlen) { + VTerm *vt = state->vt; + if(cmdlen == 1) switch(command[0]) { case 'm': // Query SGR @@ -1624,22 +1626,37 @@ static void request_status_string(VTermState *state, const char *command, size_t long args[20]; int argc = vterm_state_getpen(state, args, sizeof(args)/sizeof(args[0])); int argi; - vterm_push_output_sprintf_ctrl(state->vt, C1_DCS, "1$r"); - for(argi = 0; argi < argc; argi++) - vterm_push_output_sprintf(state->vt, - argi == argc - 1 ? "%d" : - CSI_ARG_HAS_MORE(args[argi]) ? "%d:" : - "%d;", - CSI_ARG(args[argi])); - vterm_push_output_sprintf(state->vt, "m"); - vterm_push_output_sprintf_ctrl(state->vt, C1_ST, ""); + size_t cur = 0; + + cur += SNPRINTF(vt->tmpbuffer + cur, vt->tmpbuffer_len - cur, + vt->mode.ctrl8bit ? "\x90" "1$r" : ESC_S "P" "1$r"); // DCS 1$r ... + if(cur >= vt->tmpbuffer_len) + return; + + for(argi = 0; argi < argc; argi++) { + cur += SNPRINTF(vt->tmpbuffer + cur, vt->tmpbuffer_len - cur, + argi == argc - 1 ? "%ld" : + CSI_ARG_HAS_MORE(args[argi]) ? "%ld:" : + "%ld;", + CSI_ARG(args[argi])); + + if(cur >= vt->tmpbuffer_len) + return; + } + + cur += SNPRINTF(vt->tmpbuffer + cur, vt->tmpbuffer_len - cur, + vt->mode.ctrl8bit ? "m" "\x9C" : "m" ESC_S "\\"); // ... m ST + if(cur >= vt->tmpbuffer_len) + return; + + vterm_push_output_bytes(vt, vt->tmpbuffer, cur); } return; case 'r': // Query DECSTBM - vterm_push_output_sprintf_dcs(state->vt, "1$r%d;%dr", state->scrollregion_top+1, SCROLLREGION_BOTTOM(state)); + vterm_push_output_sprintf_dcs(vt, "1$r%d;%dr", state->scrollregion_top+1, SCROLLREGION_BOTTOM(state)); return; case 's': // Query DECSLRM - vterm_push_output_sprintf_dcs(state->vt, "1$r%d;%ds", SCROLLREGION_LEFT(state)+1, SCROLLREGION_RIGHT(state)); + vterm_push_output_sprintf_dcs(vt, "1$r%d;%ds", SCROLLREGION_LEFT(state)+1, SCROLLREGION_RIGHT(state)); return; } @@ -1653,11 +1670,11 @@ static void request_status_string(VTermState *state, const char *command, size_t } if(state->mode.cursor_blink) reply--; - vterm_push_output_sprintf_dcs(state->vt, "1$r%d q", reply); + vterm_push_output_sprintf_dcs(vt, "1$r%d q", reply); return; } else if(strneq(command, "\"q", 2)) { - vterm_push_output_sprintf_dcs(state->vt, "1$r%d\"q", state->protected_cell ? 1 : 2); + vterm_push_output_sprintf_dcs(vt, "1$r%d\"q", state->protected_cell ? 1 : 2); return; } } diff --git a/src/libvterm/src/vterm.c b/src/libvterm/src/vterm.c index 56c4e28d99..c5b6652d08 100644 --- a/src/libvterm/src/vterm.c +++ b/src/libvterm/src/vterm.c @@ -64,6 +64,9 @@ VTerm *vterm_new_with_allocator(int rows, int cols, VTermAllocatorFunctions *fun return NULL; } + vt->outfunc = NULL; + vt->outdata = NULL; + vt->outbuffer_len = 200; vt->outbuffer_cur = 0; vt->outbuffer = vterm_allocator_malloc(vt, vt->outbuffer_len); @@ -135,8 +138,19 @@ void vterm_set_utf8(VTerm *vt, int is_utf8) vt->mode.utf8 = is_utf8; } +void vterm_output_set_callback(VTerm *vt, VTermOutputCallback *func, void *user) +{ + vt->outfunc = func; + vt->outdata = user; +} + INTERNAL void vterm_push_output_bytes(VTerm *vt, const char *bytes, size_t len) { + if(vt->outfunc) { + (vt->outfunc)(bytes, len, vt->outdata); + return; + } + if(len > vt->outbuffer_len - vt->outbuffer_cur) { DEBUG_LOG("vterm_push_output_bytes(): buffer overflow; dropping output\n"); return; @@ -146,24 +160,6 @@ INTERNAL void vterm_push_output_bytes(VTerm *vt, const char *bytes, size_t len) vt->outbuffer_cur += len; } -#if (defined(_XOPEN_SOURCE) && _XOPEN_SOURCE >= 500) \ - || defined(_ISOC99_SOURCE) || defined(_BSD_SOURCE) -# undef VSNPRINTF -# define VSNPRINTF vsnprintf -# undef SNPRINTF -# define SNPRINTF snprintf -#else -# ifdef VSNPRINTF -// Use a provided vsnprintf() function. -int VSNPRINTF(char *str, size_t str_m, const char *fmt, va_list ap); -# endif -# ifdef SNPRINTF -// Use a provided snprintf() function. -int SNPRINTF(char *str, size_t str_m, const char *fmt, ...); -# endif -#endif - - INTERNAL void vterm_push_output_vsprintf(VTerm *vt, const char *format, va_list args) { size_t len; @@ -214,12 +210,9 @@ INTERNAL void vterm_push_output_sprintf_dcs(VTerm *vt, const char *fmt, ...) size_t cur; va_list args; - if(!vt->mode.ctrl8bit) - cur = SNPRINTF(vt->tmpbuffer, vt->tmpbuffer_len, - ESC_S "%c", C1_DCS - 0x40); - else - cur = SNPRINTF(vt->tmpbuffer, vt->tmpbuffer_len, - "%c", C1_DCS); + cur = SNPRINTF(vt->tmpbuffer, vt->tmpbuffer_len, + vt->mode.ctrl8bit ? "\x90" : ESC_S "P"); // DCS + if(cur >= vt->tmpbuffer_len) return; vterm_push_output_bytes(vt, vt->tmpbuffer, cur); @@ -228,12 +221,8 @@ INTERNAL void vterm_push_output_sprintf_dcs(VTerm *vt, const char *fmt, ...) vterm_push_output_vsprintf(vt, fmt, args); va_end(args); - if(!vt->mode.ctrl8bit) - cur = SNPRINTF(vt->tmpbuffer, vt->tmpbuffer_len, - ESC_S "%c", C1_ST - 0x40); - else - cur = SNPRINTF(vt->tmpbuffer, vt->tmpbuffer_len, - "%c", C1_ST); + cur = SNPRINTF(vt->tmpbuffer, vt->tmpbuffer_len, + vt->mode.ctrl8bit ? "\x9C" : ESC_S "\\"); // ST if(cur >= vt->tmpbuffer_len) return; vterm_push_output_bytes(vt, vt->tmpbuffer, cur); diff --git a/src/libvterm/src/vterm_internal.h b/src/libvterm/src/vterm_internal.h index 6aa1e9cc48..38e4235407 100644 --- a/src/libvterm/src/vterm_internal.h +++ b/src/libvterm/src/vterm_internal.h @@ -207,6 +207,9 @@ struct VTerm // len == malloc()ed size; cur == number of valid bytes + VTermOutputCallback *outfunc; + void *outdata; + char *outbuffer; size_t outbuffer_len; size_t outbuffer_cur; @@ -268,4 +271,24 @@ int vterm_unicode_is_combining(uint32_t codepoint); int vterm_unicode_is_ambiguous(uint32_t codepoint); int vterm_get_special_pty_type(void); +#if (defined(_XOPEN_SOURCE) && _XOPEN_SOURCE >= 500) \ + || defined(_ISOC99_SOURCE) || defined(_BSD_SOURCE) +# undef VSNPRINTF +# define VSNPRINTF vsnprintf +# undef SNPRINTF +#else +# ifdef VSNPRINTF +// Use a provided vsnprintf() function. +int VSNPRINTF(char *str, size_t str_m, const char *fmt, va_list ap); +# endif +# ifdef SNPRINTF +// Use a provided snprintf() function. +int SNPRINTF(char *str, size_t str_m, const char *fmt, ...); +# endif +#endif +#ifndef SNPRINTF +# define SNPRINTF snprintf +#endif + + #endif diff --git a/src/libvterm/t/harness.c b/src/libvterm/t/harness.c index e28bb7d308..8bbd8cfaed 100644 --- a/src/libvterm/t/harness.c +++ b/src/libvterm/t/harness.c @@ -483,6 +483,9 @@ int main(int argc UNUSED, char **argv UNUSED) if(streq(line, "INIT")) { if(!vt) vt = vterm_new(25, 80); + + // Somehow this makes tests fail + // vterm_output_set_callback(vt, term_output, NULL); } else if(streq(line, "WANTPARSER")) { diff --git a/src/version.c b/src/version.c index ee9a393583..f3f4d14879 100644 --- a/src/version.c +++ b/src/version.c @@ -746,6 +746,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 784, /**/ 783, /**/ From 6fc3b59ee914a0d1710c8b037a0c592e0a7c34d4 Mon Sep 17 00:00:00 2001 From: Bram Moolenaar <Bram@vim.org> Date: Sun, 17 May 2020 22:27:55 +0200 Subject: [PATCH 184/230] patch 8.2.0785: libvterm code lags behind the upstream version Problem: Libvterm code lags behind the upstream version. Solution: Include revisions 734 - 740. --- src/libvterm/CONTRIBUTING | 22 ++++++++++++++++++++++ src/libvterm/Makefile | 8 +++----- src/libvterm/doc/seqs.txt | 1 + src/libvterm/include/vterm.h | 15 +++++++++++++++ src/libvterm/src/pen.c | 33 ++++++++++++++++++++++++++------- src/libvterm/src/vterm.c | 17 +++++++++++++++++ src/libvterm/t/30state_pen.test | 8 ++++++++ src/libvterm/t/run-test.pl | 6 ++++-- src/version.c | 2 ++ 9 files changed, 98 insertions(+), 14 deletions(-) create mode 100644 src/libvterm/CONTRIBUTING diff --git a/src/libvterm/CONTRIBUTING b/src/libvterm/CONTRIBUTING new file mode 100644 index 0000000000..2100d1e510 --- /dev/null +++ b/src/libvterm/CONTRIBUTING @@ -0,0 +1,22 @@ +How to Contribute +----------------- + +The main resources for this library are: + + Launchpad + https://launchpad.net/libvterm + + Freenode: + ##tty or #tickit on irc.freenode.net + + Email: + Paul "LeoNerd" Evans <leonerd@leonerd.org.uk> + + +Bug reports and feature requests can be sent to any of the above resources. + +New features, bug patches, etc.. should in the first instance be discussed via +any of the resources listed above, before starting work on the actual code. +There may be future plans or development already in-progress that could be +affected so it is better to discuss the ideas first before starting work +actually writing any code. diff --git a/src/libvterm/Makefile b/src/libvterm/Makefile index f231dd3b52..852c97fbe8 100644 --- a/src/libvterm/Makefile +++ b/src/libvterm/Makefile @@ -37,13 +37,13 @@ INCFILES=$(TBLFILES:.tbl=.inc) HFILES_INT=$(sort $(wildcard src/*.h)) $(HFILES) VERSION_MAJOR=0 -VERSION_MINOR=0 +VERSION_MINOR=1 VERSION_CURRENT=0 VERSION_REVISION=0 VERSION_AGE=0 -VERSION=0 +VERSION=$(VERSION_MAJOR).$(VERSION_MINOR) PREFIX=/usr/local BINDIR=$(PREFIX)/bin @@ -110,13 +110,11 @@ install-bin: $(BINFILES) # DIST CUT -VERSION=$(VERSION_MAJOR).$(VERSION_MINOR) - DISTDIR=libvterm-$(VERSION) distdir: $(INCFILES) mkdir __distdir - cp LICENSE __distdir + cp LICENSE CONTRIBUTING __distdir mkdir __distdir/src cp src/*.c src/*.h src/*.inc __distdir/src mkdir __distdir/src/encoding diff --git a/src/libvterm/doc/seqs.txt b/src/libvterm/doc/seqs.txt index 164120cee8..c03fa51d7f 100644 --- a/src/libvterm/doc/seqs.txt +++ b/src/libvterm/doc/seqs.txt @@ -167,6 +167,7 @@ between states. 123 SGR 1 = Bold on SGR 3 = Italic on 123 SGR 4 = Underline single + SGR 4:x = Underline style 123 SGR 5 = Blink on 123 SGR 7 = Reverse on SGR 9 = Strikethrough on diff --git a/src/libvterm/include/vterm.h b/src/libvterm/include/vterm.h index b06952195e..0d641668a6 100644 --- a/src/libvterm/include/vterm.h +++ b/src/libvterm/include/vterm.h @@ -19,6 +19,12 @@ extern "C" { typedef unsigned char uint8_t; typedef unsigned int uint32_t; +#define VTERM_VERSION_MAJOR 0 +#define VTERM_VERSION_MINOR 1 + +#define VTERM_CHECK_VERSION \ + vterm_check_version(VTERM_VERSION_MAJOR, VTERM_VERSION_MINOR) + typedef struct VTerm VTerm; typedef struct VTermState VTermState; typedef struct VTermScreen VTermScreen; @@ -175,6 +181,8 @@ typedef struct { void (*free)(void *ptr, void *allocdata); } VTermAllocatorFunctions; +void vterm_check_version(int major, int minor); + // Allocate and initialize a new terminal with default allocators. VTerm *vterm_new(int rows, int cols); @@ -330,6 +338,13 @@ typedef struct { unsigned int dhl : 2; // On a DECDHL line (1=top 2=bottom) } VTermScreenCellAttrs; +enum { + VTERM_UNDERLINE_OFF, + VTERM_UNDERLINE_SINGLE, + VTERM_UNDERLINE_DOUBLE, + VTERM_UNDERLINE_CURLY, +}; + typedef struct { #define VTERM_MAX_CHARS_PER_CELL 6 uint32_t chars[VTERM_MAX_CHARS_PER_CELL]; diff --git a/src/libvterm/src/pen.c b/src/libvterm/src/pen.c index d34599da11..5619f276d6 100644 --- a/src/libvterm/src/pen.c +++ b/src/libvterm/src/pen.c @@ -261,9 +261,26 @@ INTERNAL void vterm_state_setpen(VTermState *state, const long args[], int argco setpenattr_bool(state, VTERM_ATTR_ITALIC, 1); break; - case 4: // Underline single - state->pen.underline = 1; - setpenattr_int(state, VTERM_ATTR_UNDERLINE, 1); + case 4: // Underline + state->pen.underline = VTERM_UNDERLINE_SINGLE; + if(CSI_ARG_HAS_MORE(args[argi])) { + argi++; + switch(CSI_ARG(args[argi])) { + case 0: + state->pen.underline = 0; + break; + case 1: + state->pen.underline = VTERM_UNDERLINE_SINGLE; + break; + case 2: + state->pen.underline = VTERM_UNDERLINE_DOUBLE; + break; + case 3: + state->pen.underline = VTERM_UNDERLINE_CURLY; + break; + } + } + setpenattr_int(state, VTERM_ATTR_UNDERLINE, state->pen.underline); break; case 5: // Blink @@ -288,8 +305,8 @@ INTERNAL void vterm_state_setpen(VTermState *state, const long args[], int argco break; case 21: // Underline double - state->pen.underline = 2; - setpenattr_int(state, VTERM_ATTR_UNDERLINE, 2); + state->pen.underline = VTERM_UNDERLINE_DOUBLE; + setpenattr_int(state, VTERM_ATTR_UNDERLINE, state->pen.underline); break; case 22: // Bold off @@ -405,8 +422,10 @@ INTERNAL int vterm_state_getpen(VTermState *state, long args[], int argcount UNU if(state->pen.italic) args[argi++] = 3; - if(state->pen.underline == 1) + if(state->pen.underline == VTERM_UNDERLINE_SINGLE) args[argi++] = 4; + if(state->pen.underline == VTERM_UNDERLINE_CURLY) + args[argi++] = 4 | CSI_ARG_FLAG_MORE, args[argi++] = 3; if(state->pen.blink) args[argi++] = 5; @@ -420,7 +439,7 @@ INTERNAL int vterm_state_getpen(VTermState *state, long args[], int argcount UNU if(state->pen.font) args[argi++] = 10 + state->pen.font; - if(state->pen.underline == 2) + if(state->pen.underline == VTERM_UNDERLINE_DOUBLE) args[argi++] = 21; if(state->fg_index >= 0 && state->fg_index < 8) diff --git a/src/libvterm/src/vterm.c b/src/libvterm/src/vterm.c index c5b6652d08..7b06c04bbc 100644 --- a/src/libvterm/src/vterm.c +++ b/src/libvterm/src/vterm.c @@ -406,3 +406,20 @@ void vterm_copy_cells(VTermRect dest, (*copycell)(pos, srcpos, user); } } + +void vterm_check_version(int major, int minor) +{ + if(major != VTERM_VERSION_MAJOR) { + fprintf(stderr, "libvterm major version mismatch; %d (wants) != %d (library)\n", + major, VTERM_VERSION_MAJOR); + exit(1); + } + + if(minor > VTERM_VERSION_MINOR) { + fprintf(stderr, "libvterm minor version mismatch; %d (wants) > %d (library)\n", + minor, VTERM_VERSION_MINOR); + exit(1); + } + + // Happy +} diff --git a/src/libvterm/t/30state_pen.test b/src/libvterm/t/30state_pen.test index 7a671e7530..d1e0d14700 100644 --- a/src/libvterm/t/30state_pen.test +++ b/src/libvterm/t/30state_pen.test @@ -28,6 +28,14 @@ PUSH "\e[21m" ?pen underline = 2 PUSH "\e[24m" ?pen underline = 0 +PUSH "\e[4m\e[4:0m" + ?pen underline = 0 +PUSH "\e[4:1m" + ?pen underline = 1 +PUSH "\e[4:2m" + ?pen underline = 2 +PUSH "\e[4:3m" + ?pen underline = 3 PUSH "\e[4m\e[m" ?pen underline = 0 diff --git a/src/libvterm/t/run-test.pl b/src/libvterm/t/run-test.pl index 1b2144a9e4..d8fbe09ed1 100644 --- a/src/libvterm/t/run-test.pl +++ b/src/libvterm/t/run-test.pl @@ -177,9 +177,11 @@ open my $test, "<", $ARGV[0] or die "Cannot open test script $ARGV[0] - $!"; while( my $line = <$test> ) { $line =~ s/^\s+//; - next if $line =~ m/^(?:#|$)/; - chomp $line; + + next if $line =~ m/^(?:#|$)/; + last if $line eq "__END__"; + do_line( $line ); } diff --git a/src/version.c b/src/version.c index f3f4d14879..232fbb09c0 100644 --- a/src/version.c +++ b/src/version.c @@ -746,6 +746,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 785, /**/ 784, /**/ From 0b39ec3c7dd41852fa6f0430b3f963c59d0b50d8 Mon Sep 17 00:00:00 2001 From: Bram Moolenaar <Bram@vim.org> Date: Sun, 17 May 2020 22:33:53 +0200 Subject: [PATCH 185/230] patch 8.2.0786: channel test is flaky on FreeBSD Problem: Channel test is flaky on FreeBSD. Solution: Set the sockiet TCP_NODELAY option. Adjust expected line count in netbeans test. (Ozaki Kiichi, closes #6097) --- src/testdir/test_channel.py | 3 +++ src/testdir/test_netbeans.vim | 2 +- src/version.c | 2 ++ 3 files changed, 6 insertions(+), 1 deletion(-) diff --git a/src/testdir/test_channel.py b/src/testdir/test_channel.py index 6b2947d904..8dba3ba4ca 100644 --- a/src/testdir/test_channel.py +++ b/src/testdir/test_channel.py @@ -21,6 +21,9 @@ except ImportError: class ThreadedTCPRequestHandler(socketserver.BaseRequestHandler): + def setup(self): + self.request.setsockopt(socket.IPPROTO_TCP, socket.TCP_NODELAY, 1) + def handle(self): print("=== socket opened ===") while True: diff --git a/src/testdir/test_netbeans.vim b/src/testdir/test_netbeans.vim index 7f1dab46dd..781f179c38 100644 --- a/src/testdir/test_netbeans.vim +++ b/src/testdir/test_netbeans.vim @@ -609,7 +609,7 @@ func Nb_basic(port) " detach call appendbufline(cmdbufnr, '$', 'detach_Test') - call WaitFor('len(readfile("Xnetbeans")) >= (g:last + 6)') + call WaitFor('len(readfile("Xnetbeans")) >= (g:last + 8)') call WaitForAssert({-> assert_equal('0:disconnect=91', readfile("Xnetbeans")[-1])}) " the connection was closed diff --git a/src/version.c b/src/version.c index 232fbb09c0..d04f529d9b 100644 --- a/src/version.c +++ b/src/version.c @@ -746,6 +746,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 786, /**/ 785, /**/ From a2e408f5981b4da64426c3bda98d837ea36469bf Mon Sep 17 00:00:00 2001 From: Bram Moolenaar <Bram@vim.org> Date: Sun, 17 May 2020 23:00:52 +0200 Subject: [PATCH 186/230] patch 8.2.0787: libvterm code lags behind the upstream version Problem: Libvterm code lags behind the upstream version. Solution: Include revisions 741 - 742. --- Filelist | 1 + src/libvterm/src/screen.c | 311 ++++++++++++++++++++------------------ src/version.c | 2 + 3 files changed, 171 insertions(+), 143 deletions(-) diff --git a/Filelist b/Filelist index 21ec37d7a4..422f18dd28 100644 --- a/Filelist +++ b/Filelist @@ -301,6 +301,7 @@ SRC_ALL = \ src/libvterm/LICENSE \ src/libvterm/Makefile \ src/libvterm/README \ + src/libvterm/CONTRIBUTING \ src/libvterm/tbl2inc_c.pl \ src/libvterm/vterm.pc.in \ src/libvterm/doc/URLs \ diff --git a/src/libvterm/src/screen.c b/src/libvterm/src/screen.c index bf2383a1c6..044c262214 100644 --- a/src/libvterm/src/screen.c +++ b/src/libvterm/src/screen.c @@ -37,8 +37,6 @@ typedef struct ScreenPen pen; } ScreenCell; -static int vterm_screen_set_cell(VTermScreen *screen, VTermPos pos, const VTermScreenCell *cell); - struct VTermScreen { VTerm *vt; @@ -58,6 +56,8 @@ struct VTermScreen int global_reverse; // Primary and Altscreen. buffers[1] is lazily allocated as needed +#define BUFIDX_PRIMARY 0 +#define BUFIDX_ALTSCREEN 1 ScreenCell *buffers[2]; // buffer will == buffers[0] or buffers[1], depending on altscreen @@ -69,6 +69,12 @@ struct VTermScreen ScreenPen pen; }; +static void clearcell(const VTermScreen *screen, ScreenCell *cell) +{ + cell->chars[0] = 0; + cell->pen = screen->pen; +} + static ScreenCell *getcell(const VTermScreen *screen, int row, int col) { if(row < 0 || row >= screen->rows) @@ -80,28 +86,18 @@ static ScreenCell *getcell(const VTermScreen *screen, int row, int col) return screen->buffer + (screen->cols * row) + col; } -static ScreenCell *realloc_buffer(VTermScreen *screen, ScreenCell *buffer, int new_rows, int new_cols) +static ScreenCell *alloc_buffer(VTermScreen *screen, int rows, int cols) { - ScreenCell *new_buffer = vterm_allocator_malloc(screen->vt, sizeof(ScreenCell) * new_rows * new_cols); - int row, col; + ScreenCell *new_buffer = vterm_allocator_malloc(screen->vt, sizeof(ScreenCell) * rows * cols); + int row; + int col; - if (new_buffer == NULL) - return NULL; - for(row = 0; row < new_rows; row++) { - for(col = 0; col < new_cols; col++) { - ScreenCell *new_cell = new_buffer + row*new_cols + col; - - if(buffer && row < screen->rows && col < screen->cols) - *new_cell = buffer[row * screen->cols + col]; - else { - new_cell->chars[0] = 0; - new_cell->pen = screen->pen; - } + for(row = 0; row < rows; row++) { + for(col = 0; col < cols; col++) { + clearcell(screen, &new_buffer[row * cols + col]); } } - vterm_allocator_free(screen->vt, buffer); - return new_buffer; } @@ -207,21 +203,27 @@ static int putglyph(VTermGlyphInfo *info, VTermPos pos, void *user) return 1; } +static void sb_pushline_from_row(VTermScreen *screen, int row) +{ + VTermPos pos; + pos.row = row; + for(pos.col = 0; pos.col < screen->cols; pos.col++) + vterm_screen_get_cell(screen, pos, screen->sb_buffer + pos.col); + + (screen->callbacks->sb_pushline)(screen->cols, screen->sb_buffer, screen->cbdata); +} + static int moverect_internal(VTermRect dest, VTermRect src, void *user) { VTermScreen *screen = user; if(screen->callbacks && screen->callbacks->sb_pushline && - dest.start_row == 0 && dest.start_col == 0 && // starts top-left corner - dest.end_col == screen->cols && // full width - screen->buffer == screen->buffers[0]) { // not altscreen - VTermPos pos; - for(pos.row = 0; pos.row < src.start_row; pos.row++) { - for(pos.col = 0; pos.col < screen->cols; pos.col++) - (void)vterm_screen_get_cell(screen, pos, screen->sb_buffer + pos.col); - - (screen->callbacks->sb_pushline)(screen->cols, screen->sb_buffer, screen->cbdata); - } + dest.start_row == 0 && dest.start_col == 0 && // starts top-left corner + dest.end_col == screen->cols && // full width + screen->buffer == screen->buffers[BUFIDX_PRIMARY]) { // not altscreen + int row; + for(row = 0; row < src.start_row; row++) + sb_pushline_from_row(screen, row); } { @@ -446,10 +448,10 @@ static int settermprop(VTermProp prop, VTermValue *val, void *user) switch(prop) { case VTERM_PROP_ALTSCREEN: - if(val->boolean && !screen->buffers[1]) + if(val->boolean && !screen->buffers[BUFIDX_ALTSCREEN]) return 0; - screen->buffer = val->boolean ? screen->buffers[1] : screen->buffers[0]; + screen->buffer = val->boolean ? screen->buffers[BUFIDX_ALTSCREEN] : screen->buffers[BUFIDX_PRIMARY]; // only send a damage event on disable; because during enable there's an // erase that sends a damage anyway if(!val->boolean) @@ -479,95 +481,149 @@ static int bell(void *user) return 0; } +static void resize_buffer(VTermScreen *screen, int bufidx, int new_rows, int new_cols, int active, VTermPos *delta) +{ + int old_rows = screen->rows; + int old_cols = screen->cols; + + ScreenCell *old_buffer = screen->buffers[bufidx]; + ScreenCell *new_buffer = vterm_allocator_malloc(screen->vt, sizeof(ScreenCell) * new_rows * new_cols); + + /* Find the final row of old buffer content */ + int old_row; + int col; + int new_row; + + for(old_row = old_rows - 1; old_row > 0; old_row--) { + if(active && (old_row == screen->state->pos.row)) + /* The line with the active cursor is never "blank" */ + goto found_oldrow; + for(col = 0; col < old_cols; col++) + if(old_buffer[old_row * old_cols + col].chars[0]) + /* This row is not blank */ + goto found_oldrow; + } + old_row = 0; +found_oldrow: + ; + + new_row = new_rows - 1; + + while(new_row >= 0 && old_row >= 0) { + for(col = 0; col < old_cols && col < new_cols; col++) + new_buffer[new_row * new_cols + col] = old_buffer[old_row * old_cols + col]; + for( ; col < new_cols; col++) + clearcell(screen, &new_buffer[new_row * new_cols + col]); + + old_row--; + new_row--; + } + + if(old_row >= 0 && bufidx == BUFIDX_PRIMARY) { + /* Push spare lines to scrollback buffer */ + int row; + for(row = 0; row <= old_row; row++) + sb_pushline_from_row(screen, row); + if(delta) + delta->row -= (old_row + 1); + } + if(new_row >= 0 && bufidx == BUFIDX_PRIMARY && + screen->callbacks && screen->callbacks->sb_popline) { + /* Try to backfill rows by popping scrollback buffer */ + while(new_row >= 0) { + VTermPos pos; + if(!(screen->callbacks->sb_popline(old_cols, screen->sb_buffer, screen->cbdata))) + break; + + pos.row = new_row; + for(pos.col = 0; pos.col < old_cols && pos.col < new_cols; pos.col += screen->sb_buffer[pos.col].width) { + VTermScreenCell *src = &screen->sb_buffer[pos.col]; + ScreenCell *dst = &new_buffer[pos.row * new_cols + pos.col]; + int i; + + for(i = 0; ; i++) { + dst->chars[i] = src->chars[i]; + if(!src->chars[i]) + break; + } + + dst->pen.bold = src->attrs.bold; + dst->pen.underline = src->attrs.underline; + dst->pen.italic = src->attrs.italic; + dst->pen.blink = src->attrs.blink; + dst->pen.reverse = src->attrs.reverse ^ screen->global_reverse; + dst->pen.strike = src->attrs.strike; + dst->pen.font = src->attrs.font; + + dst->pen.fg = src->fg; + dst->pen.bg = src->bg; + + if(src->width == 2 && pos.col < (new_cols-1)) + (dst + 1)->chars[0] = (uint32_t) -1; + } + new_row--; + + if(delta) + delta->row++; + } + } + + if(new_row >= 0) { + /* Scroll new rows back up to the top and fill in blanks at the bottom */ + int moverows = new_rows - new_row - 1; + memmove(&new_buffer[0], &new_buffer[(new_row + 1) * new_cols], moverows * new_cols * sizeof(ScreenCell)); + + for(new_row = moverows; new_row < new_rows; new_row++) + { + for(col = 0; col < new_cols; col++) + clearcell(screen, &new_buffer[new_row * new_cols + col]); + } + } + + vterm_allocator_free(screen->vt, old_buffer); + screen->buffers[bufidx] = new_buffer; + + return; + + /* REFLOW TODO: + * Handle delta. Probably needs to be a full cursorpos that we edit + */ +} + static int resize(int new_rows, int new_cols, VTermPos *delta, void *user) { VTermScreen *screen = user; - int is_altscreen = (screen->buffers[1] && screen->buffer == screen->buffers[1]); + int altscreen_active = (screen->buffers[BUFIDX_ALTSCREEN] && screen->buffer == screen->buffers[BUFIDX_ALTSCREEN]); - int old_rows = screen->rows; int old_cols = screen->cols; - int first_blank_row; - if(!is_altscreen && new_rows < old_rows) { - // Fewer rows - determine if we're going to scroll at all, and if so, push - // those lines to scrollback - VTermPos pos = { 0, 0 }; - VTermPos cursor = screen->state->pos; - // Find the first blank row after the cursor. - for(pos.row = old_rows - 1; pos.row >= new_rows; pos.row--) - if(!vterm_screen_is_eol(screen, pos) || cursor.row == pos.row) - break; + if(new_cols > old_cols) { + /* Ensure that ->sb_buffer is large enough for a new or and old row */ + if(screen->sb_buffer) + vterm_allocator_free(screen->vt, screen->sb_buffer); - first_blank_row = pos.row + 1; - if(first_blank_row > new_rows) { - VTermRect rect = {0,0,0,0}; - rect.end_row = old_rows; - rect.end_col = old_cols; - scrollrect(rect, first_blank_row - new_rows, 0, user); - vterm_screen_flush_damage(screen); - - delta->row -= first_blank_row - new_rows; - } + screen->sb_buffer = vterm_allocator_malloc(screen->vt, sizeof(VTermScreenCell) * new_cols); } - screen->buffers[0] = realloc_buffer(screen, screen->buffers[0], new_rows, new_cols); - if(screen->buffers[1]) - screen->buffers[1] = realloc_buffer(screen, screen->buffers[1], new_rows, new_cols); + resize_buffer(screen, 0, new_rows, new_cols, !altscreen_active, altscreen_active ? NULL : delta); + if(screen->buffers[BUFIDX_ALTSCREEN]) + resize_buffer(screen, 1, new_rows, new_cols, altscreen_active, altscreen_active ? delta : NULL); - screen->buffer = is_altscreen ? screen->buffers[1] : screen->buffers[0]; + screen->buffer = altscreen_active ? screen->buffers[BUFIDX_ALTSCREEN] : screen->buffers[BUFIDX_PRIMARY]; screen->rows = new_rows; screen->cols = new_cols; - vterm_allocator_free(screen->vt, screen->sb_buffer); + if(new_cols <= old_cols) { + if(screen->sb_buffer) + vterm_allocator_free(screen->vt, screen->sb_buffer); - screen->sb_buffer = vterm_allocator_malloc(screen->vt, sizeof(VTermScreenCell) * new_cols); - - if(new_cols > old_cols) { - VTermRect rect; - rect.start_row = 0; - rect.end_row = old_rows; - rect.start_col = old_cols; - rect.end_col = new_cols; - damagerect(screen, rect); + screen->sb_buffer = vterm_allocator_malloc(screen->vt, sizeof(VTermScreenCell) * new_cols); } - if(new_rows > old_rows) { - if(!is_altscreen && screen->callbacks && screen->callbacks->sb_popline) { - int rows = new_rows - old_rows; - while(rows) { - VTermRect rect = {0,0,0,0}; - VTermPos pos = { 0, 0 }; - if(!(screen->callbacks->sb_popline(screen->cols, screen->sb_buffer, screen->cbdata))) - break; - - rect.end_row = screen->rows; - rect.end_col = screen->cols; - scrollrect(rect, -1, 0, user); - - for(pos.col = 0; pos.col < screen->cols; pos.col += screen->sb_buffer[pos.col].width) - vterm_screen_set_cell(screen, pos, screen->sb_buffer + pos.col); - - rect.end_row = 1; - damagerect(screen, rect); - - vterm_screen_flush_damage(screen); - - rows--; - delta->row++; - } - } - - { - VTermRect rect; - rect.start_row = old_rows; - rect.end_row = new_rows; - rect.start_col = 0; - rect.end_col = new_cols; - damagerect(screen, rect); - } - } + /* TODO: Maaaaybe we can optimise this if there's no reflow happening */ + damagescreen(screen); if(screen->callbacks && screen->callbacks->resize) return (*screen->callbacks->resize)(new_rows, new_cols, screen->cbdata); @@ -651,8 +707,10 @@ static VTermScreen *screen_new(VTerm *vt) screen->callbacks = NULL; screen->cbdata = NULL; - screen->buffers[0] = realloc_buffer(screen, NULL, rows, cols); - screen->buffer = screen->buffers[0]; + screen->buffers[BUFIDX_PRIMARY] = alloc_buffer(screen, rows, cols); + + screen->buffer = screen->buffers[BUFIDX_PRIMARY]; + screen->sb_buffer = vterm_allocator_malloc(screen->vt, sizeof(VTermScreenCell) * cols); if (screen->buffer == NULL || screen->sb_buffer == NULL) { @@ -667,8 +725,10 @@ static VTermScreen *screen_new(VTerm *vt) INTERNAL void vterm_screen_free(VTermScreen *screen) { - vterm_allocator_free(screen->vt, screen->buffers[0]); - vterm_allocator_free(screen->vt, screen->buffers[1]); + vterm_allocator_free(screen->vt, screen->buffers[BUFIDX_PRIMARY]); + if(screen->buffers[BUFIDX_ALTSCREEN]) + vterm_allocator_free(screen->vt, screen->buffers[BUFIDX_ALTSCREEN]); + vterm_allocator_free(screen->vt, screen->sb_buffer); vterm_allocator_free(screen->vt, screen); } @@ -798,41 +858,6 @@ int vterm_screen_get_cell(const VTermScreen *screen, VTermPos pos, VTermScreenCe return 1; } -/* - * Copy external to internal representation of a screen cell - * static because it's only used internally for sb_popline during resize - */ -static int vterm_screen_set_cell(VTermScreen *screen, VTermPos pos, const VTermScreenCell *cell) -{ - ScreenCell *intcell = getcell(screen, pos.row, pos.col); - int i; - - if(!intcell) - return 0; - - for(i = 0; ; i++) { - intcell->chars[i] = cell->chars[i]; - if(!cell->chars[i]) - break; - } - - intcell->pen.bold = cell->attrs.bold; - intcell->pen.underline = cell->attrs.underline; - intcell->pen.italic = cell->attrs.italic; - intcell->pen.blink = cell->attrs.blink; - intcell->pen.reverse = cell->attrs.reverse ^ screen->global_reverse; - intcell->pen.strike = cell->attrs.strike; - intcell->pen.font = cell->attrs.font; - - intcell->pen.fg = cell->fg; - intcell->pen.bg = cell->bg; - - if(cell->width == 2) - getcell(screen, pos.row, pos.col + 1)->chars[0] = (uint32_t)-1; - - return 1; -} - int vterm_screen_is_eol(const VTermScreen *screen, VTermPos pos) { // This cell is EOL if this and every cell to the right is black @@ -855,11 +880,11 @@ VTermScreen *vterm_obtain_screen(VTerm *vt) void vterm_screen_enable_altscreen(VTermScreen *screen, int altscreen) { - if(!screen->buffers[1] && altscreen) { + if(!screen->buffers[BUFIDX_ALTSCREEN] && altscreen) { int rows, cols; vterm_get_size(screen->vt, &rows, &cols); - screen->buffers[1] = realloc_buffer(screen, NULL, rows, cols); + screen->buffers[BUFIDX_ALTSCREEN] = alloc_buffer(screen, rows, cols); } } diff --git a/src/version.c b/src/version.c index d04f529d9b..abdb68a732 100644 --- a/src/version.c +++ b/src/version.c @@ -746,6 +746,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 787, /**/ 786, /**/ From deb17451edd65e2af1d155bce0886e856a716591 Mon Sep 17 00:00:00 2001 From: Bram Moolenaar <Bram@vim.org> Date: Sun, 17 May 2020 23:34:42 +0200 Subject: [PATCH 187/230] patch 8.2.0788: memory leak in libvterm Problem: Memory leak in libvterm. Solution: free tmpbuffer. --- src/libvterm/src/vterm.c | 8 ++++++++ src/version.c | 2 ++ 2 files changed, 10 insertions(+) diff --git a/src/libvterm/src/vterm.c b/src/libvterm/src/vterm.c index 7b06c04bbc..991286ee90 100644 --- a/src/libvterm/src/vterm.c +++ b/src/libvterm/src/vterm.c @@ -79,6 +79,13 @@ VTerm *vterm_new_with_allocator(int rows, int cols, VTermAllocatorFunctions *fun vt->tmpbuffer_len = 64; vt->tmpbuffer = vterm_allocator_malloc(vt, vt->tmpbuffer_len); + if (vt->tmpbuffer == NULL) + { + vterm_allocator_free(vt, vt->parser.strbuffer); + vterm_allocator_free(vt, vt); + vterm_allocator_free(vt, vt->outbuffer); + return NULL; + } return vt; } @@ -93,6 +100,7 @@ void vterm_free(VTerm *vt) vterm_allocator_free(vt, vt->parser.strbuffer); vterm_allocator_free(vt, vt->outbuffer); + vterm_allocator_free(vt, vt->tmpbuffer); vterm_allocator_free(vt, vt); } diff --git a/src/version.c b/src/version.c index abdb68a732..4dcae55f02 100644 --- a/src/version.c +++ b/src/version.c @@ -746,6 +746,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 788, /**/ 787, /**/ From 66b3101672f7da32df2fd3962d7f14300e7a65f3 Mon Sep 17 00:00:00 2001 From: Bram Moolenaar <Bram@vim.org> Date: Mon, 18 May 2020 13:38:02 +0200 Subject: [PATCH 188/230] patch 8.2.0789: Vim9: expression testing lost coverage using constants Problem: Vim9: expression testing lost coverage using constants. Solution: Use a few variables instead of constants. --- src/testdir/test_vim9_expr.vim | 35 ++++++++++++++++++++++++++++++++++ src/version.c | 2 ++ 2 files changed, 37 insertions(+) diff --git a/src/testdir/test_vim9_expr.vim b/src/testdir/test_vim9_expr.vim index 6fabf0c9f7..e0776b5313 100644 --- a/src/testdir/test_vim9_expr.vim +++ b/src/testdir/test_vim9_expr.vim @@ -153,9 +153,13 @@ let adict = #{aaa: 2, bbb: 8} " test == comperator def Test_expr4_equal() + let trueVar = true + let falseVar = false assert_equal(true, true == true) assert_equal(false, true == false) + assert_equal(true, true == trueVar) + assert_equal(false, true == falseVar) assert_equal(true, true == g:atrue) assert_equal(false, g:atrue == false) @@ -164,8 +168,12 @@ def Test_expr4_equal() assert_equal(true, g:anone == v:none) assert_equal(false, v:none == g:anull) + let nr0 = 0 + let nr61 = 61 assert_equal(false, 2 == 0) + assert_equal(false, 2 == nr0) assert_equal(true, 61 == 61) + assert_equal(true, 61 == nr61) assert_equal(true, g:anint == 10) assert_equal(false, 61 == g:anint) @@ -237,9 +245,13 @@ enddef " test != comperator def Test_expr4_notequal() + let trueVar = true + let falseVar = false assert_equal(false, true != true) assert_equal(true, true != false) + assert_equal(false, true != trueVar) + assert_equal(true, true != falseVar) assert_equal(false, true != g:atrue) assert_equal(true, g:atrue != false) @@ -248,8 +260,12 @@ def Test_expr4_notequal() assert_equal(false, g:anone != v:none) assert_equal(true, v:none != g:anull) + let nr55 = 55 + let nr0 = 55 assert_equal(true, 2 != 0) + assert_equal(true, 2 != nr0) assert_equal(false, 55 != 55) + assert_equal(false, 55 != nr55) assert_equal(false, g:anint != 10) assert_equal(true, 61 != g:anint) @@ -313,6 +329,12 @@ def Test_expr4_greater() 1) assert_false(2 > 2) assert_false(2 > 3) + let nr2 = 2 + assert_true(nr2 > 0) + assert_true(nr2 > + 1) + assert_false(nr2 > 2) + assert_false(nr2 > 3) if has('float') let ff = 2.0 assert_true(ff > 0.0) @@ -328,6 +350,10 @@ def Test_expr4_greaterequal() assert_true(2 >= 2) assert_false(2 >= 3) + let nr2 = 2 + assert_true(nr2 >= 0) + assert_true(nr2 >= 2) + assert_false(nr2 >= 3) if has('float') let ff = 2.0 assert_true(ff >= 0.0) @@ -342,6 +368,10 @@ def Test_expr4_smaller() assert_false(2 < 2) assert_true(2 < 3) + let nr2 = 2 + assert_false(nr2 < 0) + assert_false(nr2 < 2) + assert_true(nr2 < 3) if has('float') let ff = 2.0 assert_false(ff < 0.0) @@ -357,6 +387,11 @@ def Test_expr4_smallerequal() 1) assert_true(2 <= 2) assert_true(2 <= 3) + let nr2 = 2 + assert_false(nr2 <= 0) + assert_false(nr2 <= 1) + assert_true(nr2 <= 2) + assert_true(nr2 <= 3) if has('float') let ff = 2.0 assert_false(ff <= 0.0) diff --git a/src/version.c b/src/version.c index 4dcae55f02..53d69d54be 100644 --- a/src/version.c +++ b/src/version.c @@ -746,6 +746,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 789, /**/ 788, /**/ From 843700875e50c03c94245bef1b2de147b9b3b585 Mon Sep 17 00:00:00 2001 From: Bram Moolenaar <Bram@vim.org> Date: Mon, 18 May 2020 14:20:36 +0200 Subject: [PATCH 189/230] patch 8.2.0790: Vim9: list index not well tested Problem: Vim9: list index not well tested. Solution: Add a few more tests. --- src/testdir/test_vim9_script.vim | 56 ++++++++++++++++++++------------ src/version.c | 2 ++ 2 files changed, 38 insertions(+), 20 deletions(-) diff --git a/src/testdir/test_vim9_script.vim b/src/testdir/test_vim9_script.vim index f5391847c2..22166fcb90 100644 --- a/src/testdir/test_vim9_script.vim +++ b/src/testdir/test_vim9_script.vim @@ -23,21 +23,6 @@ def Test_assignment() let bool2: bool = false assert_equal(v:false, bool2) - let list1: list<bool> = [false, true, false] - let list2: list<number> = [1, 2, 3] - let list3: list<string> = ['sdf', 'asdf'] - let list4: list<any> = ['yes', true, 1234] - let list5: list<blob> = [0z01, 0z02] - - let listS: list<string> = [] - let listN: list<number> = [] - - let dict1: dict<bool> = #{one: false, two: true} - let dict2: dict<number> = #{one: 1, two: 2} - let dict3: dict<string> = #{key: 'value'} - let dict4: dict<any> = #{one: 1, two: '2'} - let dict5: dict<blob> = #{one: 0z01, tw: 0z02} - call CheckDefFailure(['let x:string'], 'E1069:') call CheckDefFailure(['let x:string = "x"'], 'E1069:') call CheckDefFailure(['let a:string = "x"'], 'E1069:') @@ -57,11 +42,6 @@ def Test_assignment() let Funky2: func = function('len') let Party2: func = funcref('g:Test_syntax') - # type becomes list<any> - let somelist = rand() > 0 ? [1, 2, 3] : ['a', 'b', 'c'] - # type becomes dict<any> - let somedict = rand() > 0 ? #{a: 1, b: 2} : #{a: 'a', b: 'b'} - g:newvar = 'new' assert_equal('new', g:newvar) @@ -128,6 +108,42 @@ def Test_assignment() call CheckDefFailure(['v:errmsg += 123'], 'E1013:') enddef +def Test_assignment_list() + let list1: list<bool> = [false, true, false] + let list2: list<number> = [1, 2, 3] + let list3: list<string> = ['sdf', 'asdf'] + let list4: list<any> = ['yes', true, 1234] + let list5: list<blob> = [0z01, 0z02] + + let listS: list<string> = [] + let listN: list<number> = [] + + assert_equal([1, 2, 3], list2) + list2[-1] = 99 + assert_equal([1, 2, 99], list2) + list2[-2] = 88 + assert_equal([1, 88, 99], list2) + list2[-3] = 77 + assert_equal([77, 88, 99], list2) + call CheckDefExecFailure(['let ll = [1, 2, 3]', 'll[-4] = 6'], 'E684:') + + # type becomes list<any> + let somelist = rand() > 0 ? [1, 2, 3] : ['a', 'b', 'c'] +enddef + +def Test_assignment_dict() + let dict1: dict<bool> = #{one: false, two: true} + let dict2: dict<number> = #{one: 1, two: 2} + let dict3: dict<string> = #{key: 'value'} + let dict4: dict<any> = #{one: 1, two: '2'} + let dict5: dict<blob> = #{one: 0z01, tw: 0z02} + + call CheckDefExecFailure(['let dd = {}', 'dd[""] = 6'], 'E713:') + + # type becomes dict<any> + let somedict = rand() > 0 ? #{a: 1, b: 2} : #{a: 'a', b: 'b'} +enddef + def Test_assignment_local() " Test in a separated file in order not to the current buffer/window/tab is " changed. diff --git a/src/version.c b/src/version.c index 53d69d54be..aa03f906cd 100644 --- a/src/version.c +++ b/src/version.c @@ -746,6 +746,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 790, /**/ 789, /**/ From b5383b174b2436b556f76f14badb1c1f55d6d8f6 Mon Sep 17 00:00:00 2001 From: Bram Moolenaar <Bram@vim.org> Date: Mon, 18 May 2020 19:46:48 +0200 Subject: [PATCH 190/230] patch 8.2.0791: a second popup window with terminal causes trouble Problem: A second popup window with terminal causes trouble. Solution: Disallow opening a second terminal-popup window. (closes #6101, closes #6103) Avoid defaulting to an invalid line number. --- runtime/doc/popup.txt | 2 +- src/ex_docmd.c | 8 ++++++-- src/popupwin.c | 26 ++++++++++++++++++++++++++ src/testdir/test_popupwin.vim | 13 +++++++++---- src/testdir/test_terminal.vim | 7 ++----- src/version.c | 2 ++ 6 files changed, 46 insertions(+), 12 deletions(-) diff --git a/runtime/doc/popup.txt b/runtime/doc/popup.txt index 5950c4753d..fdf28a5e7a 100644 --- a/runtime/doc/popup.txt +++ b/runtime/doc/popup.txt @@ -150,7 +150,7 @@ different: *E863* - When the job ends, the popup window closes. - The popup window can be closed with `popup_close()`, the terminal buffer then becomes hidden. -- It is not possible to enter Terminal-Normal mode. +- It is not possible to open a second popup window with a terminal. *E861* - The default Pmenu color is only used for the border and padding. To change the color of the terminal itself set the Terminal highlight group before creating the terminal. Setting 'wincolor' later can work but requires the diff --git a/src/ex_docmd.c b/src/ex_docmd.c index 94a3367a3a..5447b74195 100644 --- a/src/ex_docmd.c +++ b/src/ex_docmd.c @@ -2918,8 +2918,12 @@ parse_cmd_address(exarg_T *eap, char **errormsg, int silent) { case ADDR_LINES: case ADDR_OTHER: - // default is current line number - eap->line2 = curwin->w_cursor.lnum; + // Default is the cursor line number. Avoid using an invalid + // line number though. + if (curwin->w_cursor.lnum > curbuf->b_ml.ml_line_count) + eap->line2 = curbuf->b_ml.ml_line_count; + else + eap->line2 = curwin->w_cursor.lnum; break; case ADDR_WINDOWS: eap->line2 = CURRENT_WIN_NR; diff --git a/src/popupwin.c b/src/popupwin.c index 4ee097a066..79021c38c9 100644 --- a/src/popupwin.c +++ b/src/popupwin.c @@ -1757,6 +1757,25 @@ add_border_left_right_padding(win_T *wp) } } +/* + * Return TRUE if there is any popup window with a terminal buffer. + */ + static int +popup_terminal_exists(void) +{ + win_T *wp; + tabpage_T *tp; + + FOR_ALL_POPUPWINS(wp) + if (wp->w_buffer->b_term != NULL) + return TRUE; + FOR_ALL_TABPAGES(tp) + FOR_ALL_POPUPWINS_IN_TAB(tp, wp) + if (wp->w_buffer->b_term != NULL) + return TRUE; + return FALSE; +} + /* * popup_create({text}, {options}) * popup_atcursor({text}, {options}) @@ -1786,6 +1805,13 @@ popup_create(typval_T *argvars, typval_T *rettv, create_type_T type) semsg(_(e_nobufnr), argvars[0].vval.v_number); return NULL; } +#ifdef FEAT_TERMINAL + if (buf->b_term != NULL && popup_terminal_exists()) + { + emsg(_("E861: Cannot open a second popup with a terminal")); + return NULL; + } +#endif } else if (!(argvars[0].v_type == VAR_STRING && argvars[0].vval.v_string != NULL) diff --git a/src/testdir/test_popupwin.vim b/src/testdir/test_popupwin.vim index feaa5e4c0d..8c917bc8e3 100644 --- a/src/testdir/test_popupwin.vim +++ b/src/testdir/test_popupwin.vim @@ -2426,10 +2426,10 @@ func Test_popupwin_terminal_buffer() let g:test_is_flaky = 1 let origwin = win_getid() - let ptybuf = term_start(&shell, #{hidden: 1}) - let winid = popup_create(ptybuf, #{minwidth: 40, minheight: 10}) + let termbuf = term_start(&shell, #{hidden: 1}) + let winid = popup_create(termbuf, #{minwidth: 40, minheight: 10}) " Wait for shell to start - call WaitForAssert({-> assert_equal("run", job_status(term_getjob(ptybuf)))}) + call WaitForAssert({-> assert_equal("run", job_status(term_getjob(termbuf)))}) sleep 100m " Check this doesn't crash call assert_equal(winnr(), winnr('j')) @@ -2440,11 +2440,16 @@ func Test_popupwin_terminal_buffer() " Cannot quit while job is running call assert_fails('call feedkeys("\<C-W>:quit\<CR>", "xt")', 'E948:') - " Cannot enter Terminal-Normal mode. + " Cannot enter Terminal-Normal mode. (TODO: but it works...) call feedkeys("xxx\<C-W>N", 'xt') call assert_fails('call feedkeys("gf", "xt")', 'E863:') call feedkeys("a\<C-U>", 'xt') + " Cannot open a second one. + let termbuf2 = term_start(&shell, #{hidden: 1}) + call assert_fails('call popup_create(termbuf2, #{})', 'E861:') + call term_sendkeys(termbuf2, "exit\<CR>") + " Exiting shell closes popup window call feedkeys("exit\<CR>", 'xt') " Wait for shell to exit diff --git a/src/testdir/test_terminal.vim b/src/testdir/test_terminal.vim index ab1961aa37..7f85f6cf10 100644 --- a/src/testdir/test_terminal.vim +++ b/src/testdir/test_terminal.vim @@ -2587,9 +2587,8 @@ func Test_double_popup_terminal() let buf1 = term_start(&shell, #{hidden: 1}) let win1 = popup_create(buf1, {}) let buf2 = term_start(&shell, #{hidden: 1}) - let win2 = popup_create(buf2, {}) + call assert_fails('call popup_create(buf2, {})', 'E861:') call popup_close(win1) - call popup_close(win2) exe buf1 .. 'bwipe!' exe buf2 .. 'bwipe!' endfunc @@ -2619,10 +2618,8 @@ func Test_term_nasty_callback() CheckExecutable sh set hidden - let g:buf0 = term_start('sh', #{hidden: 1}) + let g:buf0 = term_start('sh', #{hidden: 1, term_finish: 'close'}) call popup_create(g:buf0, {}) - let g:buf1 = term_start('sh', #{hidden: 1, term_finish: 'close'}) - call popup_create(g:buf1, {}) call assert_fails("call term_start(['sh', '-c'], #{curwin: 1})", 'E863:') call popup_clear(1) diff --git a/src/version.c b/src/version.c index aa03f906cd..92f5660e53 100644 --- a/src/version.c +++ b/src/version.c @@ -746,6 +746,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 791, /**/ 790, /**/ From c33b3216c8ceac84130d627b20cb7034e5f831e6 Mon Sep 17 00:00:00 2001 From: Bram Moolenaar <Bram@vim.org> Date: Mon, 18 May 2020 20:12:09 +0200 Subject: [PATCH 191/230] patch 8.2.0792: build failure with small features Problem: Build failure with small features. Solution: Add #ifdef. --- src/popupwin.c | 2 ++ src/version.c | 2 ++ 2 files changed, 4 insertions(+) diff --git a/src/popupwin.c b/src/popupwin.c index 79021c38c9..cee848a13c 100644 --- a/src/popupwin.c +++ b/src/popupwin.c @@ -1757,6 +1757,7 @@ add_border_left_right_padding(win_T *wp) } } +#ifdef FEAT_TERMINAL /* * Return TRUE if there is any popup window with a terminal buffer. */ @@ -1775,6 +1776,7 @@ popup_terminal_exists(void) return TRUE; return FALSE; } +#endif /* * popup_create({text}, {options}) diff --git a/src/version.c b/src/version.c index 92f5660e53..14eca5f6a2 100644 --- a/src/version.c +++ b/src/version.c @@ -746,6 +746,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 792, /**/ 791, /**/ From 1e1d2e89fa460328883bb09fb13a24e26ef1ab31 Mon Sep 17 00:00:00 2001 From: Bram Moolenaar <Bram@vim.org> Date: Mon, 18 May 2020 20:17:02 +0200 Subject: [PATCH 192/230] patch 8.2.0793: MS-Windows: cannot build GUI with small features Problem: MS-Windows: cannot build GUI with small features. (Michael Soyka) Solution: Add #ifdef around use of windowsVersion. (Ken Takata) --- src/os_win32.c | 5 +++-- src/version.c | 2 ++ 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/src/os_win32.c b/src/os_win32.c index edd5cdac4e..89c7c5e3aa 100644 --- a/src/os_win32.c +++ b/src/os_win32.c @@ -822,7 +822,7 @@ win32_enable_privilege(LPTSTR lpszPrivilege, BOOL bEnable) #endif /* - * Set "win8_or_later" and fill in "windowsVersion". + * Set "win8_or_later" and fill in "windowsVersion" if possible. */ void PlatformId(void) @@ -836,9 +836,10 @@ PlatformId(void) ovi.dwOSVersionInfoSize = sizeof(ovi); GetVersionEx(&ovi); +#ifdef FEAT_EVAL vim_snprintf(windowsVersion, sizeof(windowsVersion), "%d.%d", (int)ovi.dwMajorVersion, (int)ovi.dwMinorVersion); - +#endif if ((ovi.dwMajorVersion == 6 && ovi.dwMinorVersion >= 2) || ovi.dwMajorVersion > 6) win8_or_later = TRUE; diff --git a/src/version.c b/src/version.c index 14eca5f6a2..055a4180ed 100644 --- a/src/version.c +++ b/src/version.c @@ -746,6 +746,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 793, /**/ 792, /**/ From d098b824c10cc20dc55e18c22c4991f61826006e Mon Sep 17 00:00:00 2001 From: Bram Moolenaar <Bram@vim.org> Date: Mon, 18 May 2020 21:12:59 +0200 Subject: [PATCH 193/230] patch 8.2.0794: libvterm code lags behind the upstream version Problem: Libvterm code lags behind the upstream version. Solution: Include revisions 743 - 747. --- src/libvterm/include/vterm.h | 11 +++- src/libvterm/src/screen.c | 18 +++--- src/libvterm/src/state.c | 85 ++++++++++++++++++----------- src/libvterm/src/vterm_internal.h | 7 +++ src/libvterm/t/67screen_dbl_wh.test | 6 ++ src/libvterm/t/run-test.pl | 4 +- src/version.c | 2 + 7 files changed, 88 insertions(+), 45 deletions(-) diff --git a/src/libvterm/include/vterm.h b/src/libvterm/include/vterm.h index 0d641668a6..1002fc3ad3 100644 --- a/src/libvterm/include/vterm.h +++ b/src/libvterm/include/vterm.h @@ -268,6 +268,15 @@ void *vterm_parser_get_cbdata(VTerm *vt); // State layer // ----------- +/* Copies of VTermState fields that the 'resize' callback might have reason to + * edit. 'resize' callback gets total control of these fields and may + * free-and-reallocate them if required. They will be copied back from the + * struct after the callback has returned. + */ +typedef struct { + VTermPos pos; /* current cursor position */ +} VTermStateFields; + typedef struct { int (*putglyph)(VTermGlyphInfo *info, VTermPos pos, void *user); int (*movecursor)(VTermPos pos, VTermPos oldpos, int visible, void *user); @@ -280,7 +289,7 @@ typedef struct { // was accepted, 0 otherwise. int (*settermprop)(VTermProp prop, VTermValue *val, void *user); int (*bell)(void *user); - int (*resize)(int rows, int cols, VTermPos *delta, void *user); + int (*resize)(int rows, int cols, VTermStateFields *fields, void *user); int (*setlineinfo)(int row, const VTermLineInfo *newinfo, const VTermLineInfo *oldinfo, void *user); } VTermStateCallbacks; diff --git a/src/libvterm/src/screen.c b/src/libvterm/src/screen.c index 044c262214..081bf408b3 100644 --- a/src/libvterm/src/screen.c +++ b/src/libvterm/src/screen.c @@ -56,8 +56,6 @@ struct VTermScreen int global_reverse; // Primary and Altscreen. buffers[1] is lazily allocated as needed -#define BUFIDX_PRIMARY 0 -#define BUFIDX_ALTSCREEN 1 ScreenCell *buffers[2]; // buffer will == buffers[0] or buffers[1], depending on altscreen @@ -481,7 +479,7 @@ static int bell(void *user) return 0; } -static void resize_buffer(VTermScreen *screen, int bufidx, int new_rows, int new_cols, int active, VTermPos *delta) +static void resize_buffer(VTermScreen *screen, int bufidx, int new_rows, int new_cols, int active, VTermStateFields *statefields) { int old_rows = screen->rows; int old_cols = screen->cols; @@ -524,8 +522,8 @@ found_oldrow: int row; for(row = 0; row <= old_row; row++) sb_pushline_from_row(screen, row); - if(delta) - delta->row -= (old_row + 1); + if(active) + statefields->pos.row -= (old_row + 1); } if(new_row >= 0 && bufidx == BUFIDX_PRIMARY && screen->callbacks && screen->callbacks->sb_popline) { @@ -563,8 +561,8 @@ found_oldrow: } new_row--; - if(delta) - delta->row++; + if(active) + statefields->pos.row++; } } @@ -590,7 +588,7 @@ found_oldrow: */ } -static int resize(int new_rows, int new_cols, VTermPos *delta, void *user) +static int resize(int new_rows, int new_cols, VTermStateFields *fields, void *user) { VTermScreen *screen = user; @@ -606,9 +604,9 @@ static int resize(int new_rows, int new_cols, VTermPos *delta, void *user) screen->sb_buffer = vterm_allocator_malloc(screen->vt, sizeof(VTermScreenCell) * new_cols); } - resize_buffer(screen, 0, new_rows, new_cols, !altscreen_active, altscreen_active ? NULL : delta); + resize_buffer(screen, 0, new_rows, new_cols, !altscreen_active, fields); if(screen->buffers[BUFIDX_ALTSCREEN]) - resize_buffer(screen, 1, new_rows, new_cols, altscreen_active, altscreen_active ? delta : NULL); + resize_buffer(screen, 1, new_rows, new_cols, altscreen_active, fields); screen->buffer = altscreen_active ? screen->buffers[BUFIDX_ALTSCREEN] : screen->buffers[BUFIDX_PRIMARY]; diff --git a/src/libvterm/src/state.c b/src/libvterm/src/state.c index add75ac4e8..38702bd5ed 100644 --- a/src/libvterm/src/state.c +++ b/src/libvterm/src/state.c @@ -73,13 +73,27 @@ static VTermState *vterm_state_new(VTerm *vt) state->bold_is_highbright = 0; + state->combine_chars_size = 16; + state->combine_chars = vterm_allocator_malloc(state->vt, state->combine_chars_size * sizeof(state->combine_chars[0])); + + state->tabstops = vterm_allocator_malloc(state->vt, (state->cols + 7) / 8); + + state->lineinfos[BUFIDX_PRIMARY] = vterm_allocator_malloc(state->vt, state->rows * sizeof(VTermLineInfo)); + state->lineinfo = state->lineinfos[BUFIDX_PRIMARY]; + + state->encoding_utf8.enc = vterm_lookup_encoding(ENC_UTF8, 'u'); + if(*state->encoding_utf8.enc->init) + (*state->encoding_utf8.enc->init)(state->encoding_utf8.enc, state->encoding_utf8.data); + return state; } INTERNAL void vterm_state_free(VTermState *state) { vterm_allocator_free(state->vt, state->tabstops); - vterm_allocator_free(state->vt, state->lineinfo); + vterm_allocator_free(state->vt, state->lineinfos[BUFIDX_PRIMARY]); + if(state->lineinfos[BUFIDX_ALTSCREEN]) + vterm_allocator_free(state->vt, state->lineinfos[BUFIDX_ALTSCREEN]); vterm_allocator_free(state->vt, state->combine_chars); vterm_allocator_free(state->vt, state); } @@ -106,15 +120,22 @@ static void scroll(VTermState *state, VTermRect rect, int downward, int rightwar // Update lineinfo if full line if(rect.start_col == 0 && rect.end_col == state->cols && rightward == 0) { int height = rect.end_row - rect.start_row - abs(downward); + int row; - if(downward > 0) + if(downward > 0) { memmove(state->lineinfo + rect.start_row, state->lineinfo + rect.start_row + downward, height * sizeof(state->lineinfo[0])); - else + for(row = rect.end_row - downward; row < rect.end_row; row++) + state->lineinfo[row] = (VTermLineInfo){ 0 }; + } + else { memmove(state->lineinfo + rect.start_row - downward, state->lineinfo + rect.start_row, height * sizeof(state->lineinfo[0])); + for(row = rect.start_row; row < rect.start_row - downward; row++) + state->lineinfo[row] = (VTermLineInfo){ 0 }; + } } if(state->callbacks && state->callbacks->scrollrect) @@ -1701,7 +1722,7 @@ static int on_resize(int rows, int cols, void *user) { VTermState *state = user; VTermPos oldpos = state->pos; - VTermPos delta = { 0, 0 }; + VTermStateFields fields; if(cols != state->cols) { int col; @@ -1731,22 +1752,29 @@ static int on_resize(int rows, int cols, void *user) } if(rows != state->rows) { - int row; - VTermLineInfo *newlineinfo = vterm_allocator_malloc(state->vt, rows * sizeof(VTermLineInfo)); - if (newlineinfo == NULL) - return 0; + for(int bufidx = BUFIDX_PRIMARY; bufidx <= BUFIDX_ALTSCREEN; bufidx++) { + int row; + VTermLineInfo *oldlineinfo = state->lineinfos[bufidx]; + if(!oldlineinfo) + continue; - for(row = 0; row < state->rows && row < rows; row++) { - newlineinfo[row] = state->lineinfo[row]; + VTermLineInfo *newlineinfo = vterm_allocator_malloc(state->vt, rows * sizeof(VTermLineInfo)); + + for(row = 0; row < state->rows && row < rows; row++) { + newlineinfo[row] = oldlineinfo[row]; + } + + for( ; row < rows; row++) { + newlineinfo[row] = (VTermLineInfo){ + .doublewidth = 0, + }; + } + + vterm_allocator_free(state->vt, state->lineinfos[bufidx]); + state->lineinfos[bufidx] = newlineinfo; } - for( ; row < rows; row++) { - newlineinfo[row].doublewidth = 0; - newlineinfo[row].doubleheight = 0; - } - - vterm_allocator_free(state->vt, state->lineinfo); - state->lineinfo = newlineinfo; + state->lineinfo = state->lineinfos[state->mode.alt_screen ? BUFIDX_ALTSCREEN : BUFIDX_PRIMARY]; } state->rows = rows; @@ -1757,17 +1785,18 @@ static int on_resize(int rows, int cols, void *user) if(state->scrollregion_right > -1) UBOUND(state->scrollregion_right, state->cols); + fields.pos = state->pos; + if(state->callbacks && state->callbacks->resize) - (*state->callbacks->resize)(rows, cols, &delta, state->cbdata); + (*state->callbacks->resize)(rows, cols, &fields, state->cbdata); + + state->pos = fields.pos; if(state->at_phantom && state->pos.col < cols-1) { state->at_phantom = 0; state->pos.col++; } - state->pos.row += delta.row; - state->pos.col += delta.col; - if(state->pos.row >= rows) state->pos.row = rows - 1; if(state->pos.col >= cols) @@ -1803,17 +1832,6 @@ VTermState *vterm_obtain_state(VTerm *vt) return NULL; vt->state = state; - state->combine_chars_size = 16; - state->combine_chars = vterm_allocator_malloc(state->vt, state->combine_chars_size * sizeof(state->combine_chars[0])); - - state->tabstops = vterm_allocator_malloc(state->vt, (state->cols + 7) / 8); - - state->lineinfo = vterm_allocator_malloc(state->vt, state->rows * sizeof(VTermLineInfo)); - - state->encoding_utf8.enc = vterm_lookup_encoding(ENC_UTF8, 'u'); - if(*state->encoding_utf8.enc->init != NULL) - (*state->encoding_utf8.enc->init)(state->encoding_utf8.enc, state->encoding_utf8.data); - vterm_parser_set_callbacks(vt, &parser_callbacks, state); return state; @@ -1976,6 +1994,9 @@ int vterm_state_set_termprop(VTermState *state, VTermProp prop, VTermValue *val) return 1; case VTERM_PROP_ALTSCREEN: state->mode.alt_screen = val->boolean; + if(state->mode.alt_screen && !state->lineinfos[BUFIDX_ALTSCREEN]) + state->lineinfos[BUFIDX_ALTSCREEN] = vterm_allocator_malloc(state->vt, state->rows * sizeof(VTermLineInfo)); + state->lineinfo = state->lineinfos[state->mode.alt_screen ? BUFIDX_ALTSCREEN : BUFIDX_PRIMARY]; if(state->mode.alt_screen) { VTermRect rect = {0, 0, 0, 0}; rect.end_row = state->rows; diff --git a/src/libvterm/src/vterm_internal.h b/src/libvterm/src/vterm_internal.h index 38e4235407..19b00c96ce 100644 --- a/src/libvterm/src/vterm_internal.h +++ b/src/libvterm/src/vterm_internal.h @@ -32,6 +32,9 @@ #define CSI_ARGS_MAX 16 #define CSI_LEADER_MAX 16 +#define BUFIDX_PRIMARY 0 +#define BUFIDX_ALTSCREEN 1 + typedef struct VTermEncoding VTermEncoding; typedef struct { @@ -92,6 +95,10 @@ struct VTermState // Bitvector of tab stops unsigned char *tabstops; + /* Primary and Altscreen; lineinfos[1] is lazily allocated as needed */ + VTermLineInfo *lineinfos[2]; + + /* lineinfo will == lineinfos[0] or lineinfos[1], depending on altscreen */ VTermLineInfo *lineinfo; #define ROWWIDTH(state,row) ((state)->lineinfo[(row)].doublewidth ? ((state)->cols / 2) : (state)->cols) #define THISROWWIDTH(state) ROWWIDTH(state, (state)->pos.row) diff --git a/src/libvterm/t/67screen_dbl_wh.test b/src/libvterm/t/67screen_dbl_wh.test index 7d17d9a8c3..9c81e83b86 100644 --- a/src/libvterm/t/67screen_dbl_wh.test +++ b/src/libvterm/t/67screen_dbl_wh.test @@ -30,3 +30,9 @@ PUSH "abcde" ?screen_cell 0,0 = {0x61} width=1 attrs={} fg=rgb(240,240,240) bg=rgb(0,0,0) PUSH "\e#6" ?screen_cell 0,0 = {0x61} width=1 attrs={} dwl fg=rgb(240,240,240) bg=rgb(0,0,0) + +!DWL doesn't spill over on scroll +RESET +PUSH "\e[25H\e#6Final\r\n" + ?screen_cell 23,0 = {0x46} width=1 attrs={} dwl fg=rgb(240,240,240) bg=rgb(0,0,0) + ?screen_cell 24,0 = {} width=1 attrs={} fg=rgb(240,240,240) bg=rgb(0,0,0) diff --git a/src/libvterm/t/run-test.pl b/src/libvterm/t/run-test.pl index d8fbe09ed1..a6de7a27d3 100644 --- a/src/libvterm/t/run-test.pl +++ b/src/libvterm/t/run-test.pl @@ -140,14 +140,14 @@ sub do_line } } # Assertions start with '?' - elsif( $line =~ s/^\?([a-z]+.*?=)\s+// ) { + elsif( $line =~ s/^\?([a-z]+.*?=)\s*// ) { do_onetest if defined $command; my ( $assertion ) = $1 =~ m/^(.*)\s+=/; $hin->print( "\?$assertion\n" ); my $response = <$hout>; defined $response or wait, die "Test harness failed - $?\n"; - chomp $response; + chomp $response; $response =~ s/^\s+|\s+$//g; if( $response ne $line ) { print "# Assert $assertion failed:\n" . diff --git a/src/version.c b/src/version.c index 055a4180ed..c4a197677b 100644 --- a/src/version.c +++ b/src/version.c @@ -746,6 +746,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 794, /**/ 793, /**/ From 88d68de95da70d0f89a5246f58355d72e9c17db4 Mon Sep 17 00:00:00 2001 From: Bram Moolenaar <Bram@vim.org> Date: Mon, 18 May 2020 21:51:01 +0200 Subject: [PATCH 194/230] patch 8.2.0795: libvterm code lags behind the upstream version Problem: Libvterm code lags behind the upstream version. Solution: Include revisions 748 - 754. --- src/libvterm/include/vterm.h | 5 ++- src/libvterm/src/screen.c | 29 ++++++--------- src/libvterm/src/state.c | 29 +++++++++++---- src/libvterm/t/32state_flow.test | 28 ++++++++++++++ src/libvterm/t/60screen_ascii.test | 28 +++++++------- src/libvterm/t/62screen_damage.test | 4 +- src/libvterm/t/63screen_resize.test | 57 +++++++++++++++++------------ src/libvterm/t/harness.c | 23 +++++++++++- src/libvterm/t/run-test.pl | 23 ++++++++---- src/version.c | 2 + 10 files changed, 153 insertions(+), 75 deletions(-) create mode 100644 src/libvterm/t/32state_flow.test diff --git a/src/libvterm/include/vterm.h b/src/libvterm/include/vterm.h index 1002fc3ad3..ea8f8cd106 100644 --- a/src/libvterm/include/vterm.h +++ b/src/libvterm/include/vterm.h @@ -170,8 +170,9 @@ typedef struct { } VTermGlyphInfo; typedef struct { - unsigned int doublewidth:1; // DECDWL or DECDHL line - unsigned int doubleheight:2; // DECDHL line (1=top 2=bottom) + unsigned int doublewidth:1; /* DECDWL or DECDHL line */ + unsigned int doubleheight:2; /* DECDHL line (1=top 2=bottom) */ + unsigned int continuation:1; /* Line is a flow continuation of the previous */ } VTermLineInfo; typedef struct { diff --git a/src/libvterm/src/screen.c b/src/libvterm/src/screen.c index 081bf408b3..1da2b72ae7 100644 --- a/src/libvterm/src/screen.c +++ b/src/libvterm/src/screen.c @@ -488,24 +488,9 @@ static void resize_buffer(VTermScreen *screen, int bufidx, int new_rows, int new ScreenCell *new_buffer = vterm_allocator_malloc(screen->vt, sizeof(ScreenCell) * new_rows * new_cols); /* Find the final row of old buffer content */ - int old_row; + int old_row = old_rows - 1; + int new_row = new_rows - 1; int col; - int new_row; - - for(old_row = old_rows - 1; old_row > 0; old_row--) { - if(active && (old_row == screen->state->pos.row)) - /* The line with the active cursor is never "blank" */ - goto found_oldrow; - for(col = 0; col < old_cols; col++) - if(old_buffer[old_row * old_cols + col].chars[0]) - /* This row is not blank */ - goto found_oldrow; - } - old_row = 0; -found_oldrow: - ; - - new_row = new_rows - 1; while(new_row >= 0 && old_row >= 0) { for(col = 0; col < old_cols && col < new_cols; col++) @@ -515,6 +500,15 @@ found_oldrow: old_row--; new_row--; + + if(new_row < 0 && old_row >= 0 && + new_buffer[(new_rows - 1) * new_cols].chars[0] == 0 && + (!active || statefields->pos.row < (new_rows - 1))) { + int moverows = new_rows - 1; + memmove(&new_buffer[1 * new_cols], &new_buffer[0], moverows * new_cols * sizeof(ScreenCell)); + + new_row++; + } } if(old_row >= 0 && bufidx == BUFIDX_PRIMARY) { @@ -877,7 +871,6 @@ VTermScreen *vterm_obtain_screen(VTerm *vt) void vterm_screen_enable_altscreen(VTermScreen *screen, int altscreen) { - if(!screen->buffers[BUFIDX_ALTSCREEN] && altscreen) { int rows, cols; vterm_get_size(screen->vt, &rows, &cols); diff --git a/src/libvterm/src/state.c b/src/libvterm/src/state.c index 38702bd5ed..16bd790ae6 100644 --- a/src/libvterm/src/state.c +++ b/src/libvterm/src/state.c @@ -44,6 +44,15 @@ static void updatecursor(VTermState *state, VTermPos *oldpos, int cancel_phantom static void erase(VTermState *state, VTermRect rect, int selective) { + if(rect.end_col == state->cols) { + int row; + /* If we're erasing the final cells of any lines, cancel the continuation + * marker on the subsequent line + */ + for(row = rect.start_row + 1; row < rect.end_row + 1 && row < state->rows; row++) + state->lineinfo[row].continuation = 0; + } + if(state->callbacks && state->callbacks->erase) if((*state->callbacks->erase)(rect, selective, state->cbdata)) return; @@ -78,11 +87,13 @@ static VTermState *vterm_state_new(VTerm *vt) state->tabstops = vterm_allocator_malloc(state->vt, (state->cols + 7) / 8); - state->lineinfos[BUFIDX_PRIMARY] = vterm_allocator_malloc(state->vt, state->rows * sizeof(VTermLineInfo)); + state->lineinfos[BUFIDX_PRIMARY] = vterm_allocator_malloc(state->vt, state->rows * sizeof(VTermLineInfo)); + /* TODO: Make an 'enable' function */ + state->lineinfos[BUFIDX_ALTSCREEN] = vterm_allocator_malloc(state->vt, state->rows * sizeof(VTermLineInfo)); state->lineinfo = state->lineinfos[BUFIDX_PRIMARY]; state->encoding_utf8.enc = vterm_lookup_encoding(ENC_UTF8, 'u'); - if(*state->encoding_utf8.enc->init) + if(state->encoding_utf8.enc->init) (*state->encoding_utf8.enc->init)(state->encoding_utf8.enc, state->encoding_utf8.data); return state; @@ -121,20 +132,21 @@ static void scroll(VTermState *state, VTermRect rect, int downward, int rightwar if(rect.start_col == 0 && rect.end_col == state->cols && rightward == 0) { int height = rect.end_row - rect.start_row - abs(downward); int row; + VTermLineInfo zeroLineInfo = { 0 }; if(downward > 0) { memmove(state->lineinfo + rect.start_row, state->lineinfo + rect.start_row + downward, height * sizeof(state->lineinfo[0])); for(row = rect.end_row - downward; row < rect.end_row; row++) - state->lineinfo[row] = (VTermLineInfo){ 0 }; + state->lineinfo[row] = zeroLineInfo; } else { memmove(state->lineinfo + rect.start_row - downward, state->lineinfo + rect.start_row, height * sizeof(state->lineinfo[0])); for(row = rect.start_row; row < rect.start_row - downward; row++) - state->lineinfo[row] = (VTermLineInfo){ 0 }; + state->lineinfo[row] = zeroLineInfo; } } @@ -388,6 +400,7 @@ static int on_text(const char bytes[], size_t len, void *user) linefeed(state); state->pos.col = 0; state->at_phantom = 0; + state->lineinfo[state->pos.row].continuation = 1; } if(state->mode.insert) { @@ -1752,13 +1765,15 @@ static int on_resize(int rows, int cols, void *user) } if(rows != state->rows) { - for(int bufidx = BUFIDX_PRIMARY; bufidx <= BUFIDX_ALTSCREEN; bufidx++) { + int bufidx; + for(bufidx = BUFIDX_PRIMARY; bufidx <= BUFIDX_ALTSCREEN; bufidx++) { int row; VTermLineInfo *oldlineinfo = state->lineinfos[bufidx]; + VTermLineInfo *newlineinfo; if(!oldlineinfo) continue; - VTermLineInfo *newlineinfo = vterm_allocator_malloc(state->vt, rows * sizeof(VTermLineInfo)); + newlineinfo = vterm_allocator_malloc(state->vt, rows * sizeof(VTermLineInfo)); for(row = 0; row < state->rows && row < rows; row++) { newlineinfo[row] = oldlineinfo[row]; @@ -1994,8 +2009,6 @@ int vterm_state_set_termprop(VTermState *state, VTermProp prop, VTermValue *val) return 1; case VTERM_PROP_ALTSCREEN: state->mode.alt_screen = val->boolean; - if(state->mode.alt_screen && !state->lineinfos[BUFIDX_ALTSCREEN]) - state->lineinfos[BUFIDX_ALTSCREEN] = vterm_allocator_malloc(state->vt, state->rows * sizeof(VTermLineInfo)); state->lineinfo = state->lineinfos[state->mode.alt_screen ? BUFIDX_ALTSCREEN : BUFIDX_PRIMARY]; if(state->mode.alt_screen) { VTermRect rect = {0, 0, 0, 0}; diff --git a/src/libvterm/t/32state_flow.test b/src/libvterm/t/32state_flow.test new file mode 100644 index 0000000000..84a13df18b --- /dev/null +++ b/src/libvterm/t/32state_flow.test @@ -0,0 +1,28 @@ +INIT +WANTSTATE + +# Many of these test cases inspired by +# https://blueprints.launchpad.net/libvterm/+spec/reflow-cases + +!Spillover text marks continuation on second line +RESET +PUSH "A"x100 +PUSH "\r\n" + ?lineinfo 0 = + ?lineinfo 1 = cont + +!CRLF in column 80 does not mark continuation +RESET +PUSH "B"x80 +PUSH "\r\n" +PUSH "B"x20 +PUSH "\r\n" + ?lineinfo 0 = + ?lineinfo 1 = + +!EL cancels continuation of following line +RESET +PUSH "D"x100 + ?lineinfo 1 = cont +PUSH "\eM\e[79G\e[K" + ?lineinfo 1 = diff --git a/src/libvterm/t/60screen_ascii.test b/src/libvterm/t/60screen_ascii.test index c2f48fabf3..e679b98af4 100644 --- a/src/libvterm/t/60screen_ascii.test +++ b/src/libvterm/t/60screen_ascii.test @@ -1,12 +1,12 @@ INIT -WANTSCREEN c +WANTSCREEN ac !Get RESET PUSH "ABC" movecursor 0,3 - ?screen_chars 0,0,1,3 = 0x41,0x42,0x43 - ?screen_chars 0,0,1,80 = 0x41,0x42,0x43 + ?screen_chars 0,0,1,3 = "ABC" + ?screen_chars 0,0,1,80 = "ABC" ?screen_text 0,0,1,3 = 0x41,0x42,0x43 ?screen_text 0,0,1,80 = 0x41,0x42,0x43 ?screen_cell 0,0 = {0x41} width=1 attrs={} fg=rgb(240,240,240) bg=rgb(0,0,0) @@ -18,11 +18,11 @@ PUSH "ABC" ?screen_eol 0,3 = 1 PUSH "\e[H" movecursor 0,0 - ?screen_chars 0,0,1,80 = 0x41,0x42,0x43 + ?screen_chars 0,0,1,80 = "ABC" ?screen_text 0,0,1,80 = 0x41,0x42,0x43 PUSH "E" movecursor 0,1 - ?screen_chars 0,0,1,80 = 0x45,0x42,0x43 + ?screen_chars 0,0,1,80 = "EBC" ?screen_text 0,0,1,80 = 0x45,0x42,0x43 WANTSCREEN -c @@ -37,33 +37,33 @@ PUSH "ABCDE\e[H\e[K" RESET PUSH "ABC\e[H\e[@" PUSH "1" - ?screen_chars 0,0,1,80 = 0x31,0x41,0x42,0x43 + ?screen_chars 0,0,1,80 = "1ABC" RESET PUSH "ABC\e[H\e[P" - ?screen_chars 0,0,1,1 = 0x42 - ?screen_chars 0,1,1,2 = 0x43 - ?screen_chars 0,0,1,80 = 0x42,0x43 + ?screen_chars 0,0,1,1 = "B" + ?screen_chars 0,1,1,2 = "C" + ?screen_chars 0,0,1,80 = "BC" !Space padding RESET PUSH "Hello\e[CWorld" - ?screen_chars 0,0,1,80 = 0x48,0x65,0x6c,0x6c,0x6f,0x20,0x57,0x6f,0x72,0x6c,0x64 + ?screen_chars 0,0,1,80 = "Hello World" ?screen_text 0,0,1,80 = 0x48,0x65,0x6c,0x6c,0x6f,0x20,0x57,0x6f,0x72,0x6c,0x64 !Linefeed padding RESET PUSH "Hello\r\nWorld" - ?screen_chars 0,0,2,80 = 0x48,0x65,0x6c,0x6c,0x6f,0x0a,0x57,0x6f,0x72,0x6c,0x64 + ?screen_chars 0,0,2,80 = "Hello\nWorld" ?screen_text 0,0,2,80 = 0x48,0x65,0x6c,0x6c,0x6f,0x0a,0x57,0x6f,0x72,0x6c,0x64 !Altscreen RESET PUSH "P" - ?screen_chars 0,0,1,80 = 0x50 + ?screen_chars 0,0,1,80 = "P" PUSH "\e[?1049h" ?screen_chars 0,0,1,80 = PUSH "\e[2K\e[HA" - ?screen_chars 0,0,1,80 = 0x41 + ?screen_chars 0,0,1,80 = "A" PUSH "\e[?1049l" - ?screen_chars 0,0,1,80 = 0x50 + ?screen_chars 0,0,1,80 = "P" diff --git a/src/libvterm/t/62screen_damage.test b/src/libvterm/t/62screen_damage.test index 791a96cdb9..32cac2d0a1 100644 --- a/src/libvterm/t/62screen_damage.test +++ b/src/libvterm/t/62screen_damage.test @@ -1,5 +1,5 @@ INIT -WANTSCREEN Db +WANTSCREEN aDb !Putglyph RESET @@ -152,4 +152,4 @@ PUSH "\e[25H\r\nABCDE\b\b\b\e[2P\r\n" DAMAGEFLUSH moverect 1..25,0..80 -> 0..24,0..80 damage 24..25,0..80 - ?screen_chars 23,0,24,5 = 0x41,0x42,0x45 + ?screen_chars 23,0,24,5 = "ABE" diff --git a/src/libvterm/t/63screen_resize.test b/src/libvterm/t/63screen_resize.test index 9e5e5b206a..87932f66d4 100644 --- a/src/libvterm/t/63screen_resize.test +++ b/src/libvterm/t/63screen_resize.test @@ -6,42 +6,42 @@ WANTSCREEN RESET RESIZE 25,80 PUSH "AB\r\nCD" - ?screen_chars 0,0,1,80 = 0x41,0x42 - ?screen_chars 1,0,2,80 = 0x43,0x44 + ?screen_chars 0,0,1,80 = "AB" + ?screen_chars 1,0,2,80 = "CD" RESIZE 25,100 - ?screen_chars 0,0,1,100 = 0x41,0x42 - ?screen_chars 1,0,2,100 = 0x43,0x44 + ?screen_chars 0,0,1,100 = "AB" + ?screen_chars 1,0,2,100 = "CD" !Resize wider allows print in new area RESET RESIZE 25,80 PUSH "AB\e[79GCD" - ?screen_chars 0,0,1,2 = 0x41,0x42 - ?screen_chars 0,78,1,80 = 0x43,0x44 + ?screen_chars 0,0,1,2 = "AB" + ?screen_chars 0,78,1,80 = "CD" RESIZE 25,100 - ?screen_chars 0,0,1,2 = 0x41,0x42 - ?screen_chars 0,78,1,80 = 0x43,0x44 + ?screen_chars 0,0,1,2 = "AB" + ?screen_chars 0,78,1,80 = "CD" PUSH "E" - ?screen_chars 0,78,1,81 = 0x43,0x44,0x45 + ?screen_chars 0,78,1,81 = "CDE" !Resize shorter with blanks just truncates RESET RESIZE 25,80 PUSH "Top\e[10HLine 10" - ?screen_chars 0,0,1,80 = 0x54,0x6f,0x70 - ?screen_chars 9,0,10,80 = 0x4c,0x69,0x6e,0x65,0x20,0x31,0x30 + ?screen_chars 0,0,1,80 = "Top" + ?screen_chars 9,0,10,80 = "Line 10" ?cursor = 9,7 RESIZE 20,80 - ?screen_chars 0,0,1,80 = 0x54,0x6f,0x70 - ?screen_chars 9,0,10,80 = 0x4c,0x69,0x6e,0x65,0x20,0x31,0x30 + ?screen_chars 0,0,1,80 = "Top" + ?screen_chars 9,0,10,80 = "Line 10" ?cursor = 9,7 !Resize shorter with content must scroll RESET RESIZE 25,80 PUSH "Top\e[25HLine 25\e[15H" - ?screen_chars 0,0,1,80 = 0x54,0x6f,0x70 - ?screen_chars 24,0,25,80 = 0x4c,0x69,0x6e,0x65,0x20,0x32,0x35 + ?screen_chars 0,0,1,80 = "Top" + ?screen_chars 24,0,25,80 = "Line 25" ?cursor = 14,0 WANTSCREEN b RESIZE 20,80 @@ -51,7 +51,7 @@ RESIZE 20,80 sb_pushline 80 = sb_pushline 80 = ?screen_chars 0,0,1,80 = - ?screen_chars 19,0,20,80 = 0x4c,0x69,0x6e,0x65,0x20,0x32,0x35 + ?screen_chars 19,0,20,80 = "Line 25" ?cursor = 9,0 !Resize shorter does not lose line with cursor @@ -62,11 +62,11 @@ RESIZE 25,80 WANTSCREEN b PUSH "\e[24HLine 24\r\nLine 25\r\n" sb_pushline 80 = - ?screen_chars 23,0,24,10 = 0x4c,0x69,0x6e,0x65,0x20,0x32,0x35 + ?screen_chars 23,0,24,10 = "Line 25" ?cursor = 24,0 RESIZE 24,80 sb_pushline 80 = - ?screen_chars 22,0,23,10 = 0x4c,0x69,0x6e,0x65,0x20,0x32,0x35 + ?screen_chars 22,0,23,10 = "Line 25" ?cursor = 23,0 !Resize taller attempts to pop scrollback @@ -74,8 +74,8 @@ RESET WANTSCREEN -b RESIZE 25,80 PUSH "Line 1\e[25HBottom\e[15H" - ?screen_chars 0,0,1,80 = 0x4c,0x69,0x6e,0x65,0x20,0x31 - ?screen_chars 24,0,25,80 = 0x42,0x6f,0x74,0x74,0x6f,0x6d + ?screen_chars 0,0,1,80 = "Line 1" + ?screen_chars 24,0,25,80 = "Bottom" ?cursor = 14,0 WANTSCREEN b RESIZE 30,80 @@ -84,7 +84,18 @@ RESIZE 30,80 sb_popline 80 sb_popline 80 sb_popline 80 - ?screen_chars 0,0,1,80 = 0x41,0x42,0x43,0x44,0x45 - ?screen_chars 5,0,6,80 = 0x4c,0x69,0x6e,0x65,0x20,0x31 - ?screen_chars 29,0,30,80 = 0x42,0x6f,0x74,0x74,0x6f,0x6d + ?screen_chars 0,0,1,80 = "ABCDE" + ?screen_chars 5,0,6,80 = "Line 1" + ?screen_chars 29,0,30,80 = "Bottom" ?cursor = 19,0 +WANTSCREEN -b + +!Resize can operate on altscreen +RESET +WANTSCREEN a +RESIZE 25,80 +PUSH "Main screen\e[?1049h\e[HAlt screen" +RESIZE 30,80 + ?screen_chars 0,0,1,3 = "Alt" +PUSH "\e[?1049l" + ?screen_chars 0,0,1,3 = "Mai" diff --git a/src/libvterm/t/harness.c b/src/libvterm/t/harness.c index 8bbd8cfaed..289d829281 100644 --- a/src/libvterm/t/harness.c +++ b/src/libvterm/t/harness.c @@ -540,7 +540,6 @@ int main(int argc UNUSED, char **argv UNUSED) int sense = 1; if(!screen) screen = vterm_obtain_screen(vt); - vterm_screen_enable_altscreen(screen, 1); vterm_screen_set_callbacks(screen, &screen_cbs, NULL); while(line[i] == ' ') @@ -550,6 +549,9 @@ int main(int argc UNUSED, char **argv UNUSED) case '-': sense = 0; break; + case 'a': + vterm_screen_enable_altscreen(screen, 1); + break; case 'd': want_screen_damage = sense; break; @@ -805,6 +807,25 @@ int main(int argc UNUSED, char **argv UNUSED) else printf("?\n"); } + else if(strstartswith(line, "?lineinfo ")) { + char *linep = line + 10; + int row; + const VTermLineInfo *info; + while(linep[0] == ' ') + linep++; + if(sscanf(linep, "%d", &row) < 1) { + printf("! lineinfo unrecognised input\n"); + goto abort_line; + } + info = vterm_state_get_lineinfo(state, row); + if(info->doublewidth) + printf("dwl "); + if(info->doubleheight) + printf("dhl "); + if(info->continuation) + printf("cont "); + printf("\n"); + } else if(strstartswith(line, "?screen_chars ")) { char *linep = line + 13; VTermRect rect; diff --git a/src/libvterm/t/run-test.pl b/src/libvterm/t/run-test.pl index a6de7a27d3..5f3c78d70f 100644 --- a/src/libvterm/t/run-test.pl +++ b/src/libvterm/t/run-test.pl @@ -28,6 +28,8 @@ my $exitcode = 0; my $command; my @expect; +my $linenum = 0; + sub do_onetest { $hin->print( "$command\n" ); @@ -41,7 +43,7 @@ sub do_onetest chomp $outline; if( !@expect ) { - print "# Test failed\n" unless $fail_printed++; + print "# line $linenum: Test failed\n" unless $fail_printed++; print "# expected nothing more\n" . "# Actual: $outline\n"; next; @@ -51,13 +53,13 @@ sub do_onetest next if $expectation eq $outline; - print "# Test failed\n" unless $fail_printed++; + print "# line $linenum: Test failed\n" unless $fail_printed++; print "# Expected: $expectation\n" . "# Actual: $outline\n"; } if( @expect ) { - print "# Test failed\n" unless $fail_printed++; + print "# line $linenum: Test failed\n" unless $fail_printed++; print "# Expected: $_\n" . "# didn't happen\n" for @expect; } @@ -133,7 +135,7 @@ sub do_line $response = pack "C*", map hex, split m/,/, $response; if( $response ne $want ) { - print "# Assert ?screen_row $row failed:\n" . + print "# line $linenum: Assert ?screen_row $row failed:\n" . "# Expected: $want\n" . "# Actual: $response\n"; $exitcode = 1; @@ -144,14 +146,20 @@ sub do_line do_onetest if defined $command; my ( $assertion ) = $1 =~ m/^(.*)\s+=/; + my $expectation = $line; $hin->print( "\?$assertion\n" ); my $response = <$hout>; defined $response or wait, die "Test harness failed - $?\n"; chomp $response; $response =~ s/^\s+|\s+$//g; - if( $response ne $line ) { - print "# Assert $assertion failed:\n" . - "# Expected: $line\n" . + # Some convenience formatting + if( $assertion =~ m/^screen_chars/ and $expectation =~ m/^"/ ) { + $expectation = join ",", map sprintf("0x%02x", ord $_), split m//, eval($expectation); + } + + if( $response ne $expectation ) { + print "# line $linenum: Assert $assertion failed:\n" . + "# Expected: $expectation\n" . "# Actual: $response\n"; $exitcode = 1; } @@ -176,6 +184,7 @@ sub do_line open my $test, "<", $ARGV[0] or die "Cannot open test script $ARGV[0] - $!"; while( my $line = <$test> ) { + $linenum++; $line =~ s/^\s+//; chomp $line; diff --git a/src/version.c b/src/version.c index c4a197677b..3598f47d61 100644 --- a/src/version.c +++ b/src/version.c @@ -746,6 +746,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 795, /**/ 794, /**/ From 37ebd42f16734838ab68be91da291c4ec8610f47 Mon Sep 17 00:00:00 2001 From: Bram Moolenaar <Bram@vim.org> Date: Mon, 18 May 2020 23:27:50 +0200 Subject: [PATCH 195/230] patch 8.2.0796: MS-Windows: compiler can't handle C99 construct in libvterm Problem: MS-Windows: compiler can't handle C99 construct in libvterm. Solution: Change to C90 construct. --- src/libvterm/src/state.c | 6 +++--- src/version.c | 2 ++ 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/src/libvterm/src/state.c b/src/libvterm/src/state.c index 16bd790ae6..fe8e7b455b 100644 --- a/src/libvterm/src/state.c +++ b/src/libvterm/src/state.c @@ -1780,9 +1780,9 @@ static int on_resize(int rows, int cols, void *user) } for( ; row < rows; row++) { - newlineinfo[row] = (VTermLineInfo){ - .doublewidth = 0, - }; + VTermLineInfo lineInfo = (VTermLineInfo){0}; + lineInfo.doublewidth = 0; + newlineinfo[row] = lineInfo; } vterm_allocator_free(state->vt, state->lineinfos[bufidx]); diff --git a/src/version.c b/src/version.c index 3598f47d61..fc9a1a02d5 100644 --- a/src/version.c +++ b/src/version.c @@ -746,6 +746,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 796, /**/ 795, /**/ From 904e48a22be7e227a73c70e520cf9d8bc50fc1b2 Mon Sep 17 00:00:00 2001 From: Bram Moolenaar <Bram@vim.org> Date: Tue, 19 May 2020 10:33:02 +0200 Subject: [PATCH 196/230] patch 8.2.0797: MS-Windows: compiler still can't handle C99 construct Problem: MS-Windows: compiler still can't handle C99 construct. Solution: Change to C90 construct. (Dominique Pelle, closes #6106) --- src/libvterm/src/state.c | 3 +-- src/version.c | 2 ++ 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/src/libvterm/src/state.c b/src/libvterm/src/state.c index fe8e7b455b..1be1dae85b 100644 --- a/src/libvterm/src/state.c +++ b/src/libvterm/src/state.c @@ -1780,8 +1780,7 @@ static int on_resize(int rows, int cols, void *user) } for( ; row < rows; row++) { - VTermLineInfo lineInfo = (VTermLineInfo){0}; - lineInfo.doublewidth = 0; + VTermLineInfo lineInfo = {0}; newlineinfo[row] = lineInfo; } diff --git a/src/version.c b/src/version.c index fc9a1a02d5..9c1f6f180f 100644 --- a/src/version.c +++ b/src/version.c @@ -746,6 +746,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 797, /**/ 796, /**/ From be593bf135f6967335b14ba188bd5f8f32175c75 Mon Sep 17 00:00:00 2001 From: Bram Moolenaar <Bram@vim.org> Date: Tue, 19 May 2020 21:20:04 +0200 Subject: [PATCH 197/230] patch 8.2.0798: libvterm code lags behind the upstream version Problem: Libvterm code lags behind the upstream version. Solution: Include revisions 755 - 758. --- src/libvterm/include/vterm.h | 13 +- src/libvterm/src/parser.c | 290 ++++++++++++------------- src/libvterm/src/screen.c | 4 +- src/libvterm/src/state.c | 198 +++++++++-------- src/libvterm/src/vterm.c | 25 +-- src/libvterm/src/vterm_internal.h | 45 ++-- src/libvterm/t/02parser.test | 26 ++- src/libvterm/t/18state_termprops.test | 8 +- src/libvterm/t/29state_fallback.test | 4 +- src/libvterm/t/68screen_termprops.test | 2 +- src/libvterm/t/harness.c | 38 +++- src/libvterm/t/run-test.pl | 17 +- src/terminal.c | 36 ++- src/version.c | 2 + 14 files changed, 396 insertions(+), 312 deletions(-) diff --git a/src/libvterm/include/vterm.h b/src/libvterm/include/vterm.h index ea8f8cd106..8b6a64d96a 100644 --- a/src/libvterm/include/vterm.h +++ b/src/libvterm/include/vterm.h @@ -107,10 +107,17 @@ typedef enum { VTERM_N_VALUETYPES } VTermValueType; +typedef struct { + const char *str; + size_t len : 30; + unsigned int initial : 1; + unsigned int final : 1; +} VTermStringFragment; + typedef union { int boolean; int number; - char *string; + VTermStringFragment string; VTermColor color; } VTermValue; @@ -257,8 +264,8 @@ typedef struct { int (*control)(unsigned char control, void *user); int (*escape)(const char *bytes, size_t len, void *user); int (*csi)(const char *leader, const long args[], int argcount, const char *intermed, char command, void *user); - int (*osc)(const char *command, size_t cmdlen, void *user); - int (*dcs)(const char *command, size_t cmdlen, void *user); + int (*osc)(int command, VTermStringFragment frag, void *user); + int (*dcs)(const char *command, size_t commandlen, VTermStringFragment frag, void *user); int (*resize)(int rows, int cols, void *user); } VTermParserCallbacks; diff --git a/src/libvterm/src/parser.c b/src/libvterm/src/parser.c index 8a06c427b0..520ec2cdc6 100644 --- a/src/libvterm/src/parser.c +++ b/src/libvterm/src/parser.c @@ -23,10 +23,10 @@ static void do_csi(VTerm *vt, char command) { #ifdef DEBUG_PARSER printf("Parsed CSI args as:\n", arglen, args); - printf(" leader: %s\n", vt->parser.csi_leader); - for(int argi = 0; argi < vt->parser.csi_argi; argi++) { - printf(" %lu", CSI_ARG(vt->parser.csi_args[argi])); - if(!CSI_ARG_HAS_MORE(vt->parser.csi_args[argi])) + printf(" leader: %s\n", vt->parser.v.csi.leader); + for(int argi = 0; argi < vt->parser.v.csi.argi; argi++) { + printf(" %lu", CSI_ARG(vt->parser.v.csi.args[argi])); + if(!CSI_ARG_HAS_MORE(vt->parser.v.csi.args[argi])) printf("\n"); printf(" intermed: %s\n", vt->parser.intermed); } @@ -34,9 +34,9 @@ static void do_csi(VTerm *vt, char command) if(vt->parser.callbacks && vt->parser.callbacks->csi) if((*vt->parser.callbacks->csi)( - vt->parser.csi_leaderlen ? vt->parser.csi_leader : NULL, - vt->parser.csi_args, - vt->parser.csi_argi, + vt->parser.v.csi.leaderlen ? vt->parser.v.csi.leader : NULL, + vt->parser.v.csi.args, + vt->parser.v.csi.argi, vt->parser.intermedlen ? vt->parser.intermed : NULL, command, vt->parser.cbdata)) @@ -61,65 +61,36 @@ static void do_escape(VTerm *vt, char command) DEBUG_LOG1("libvterm: Unhandled escape ESC 0x%02x\n", command); } -static void append_strbuffer(VTerm *vt, const char *str, size_t len) +static void string_fragment(VTerm *vt, const char *str, size_t len, int final) { - if(len > vt->parser.strbuffer_len - vt->parser.strbuffer_cur) { - len = vt->parser.strbuffer_len - vt->parser.strbuffer_cur; - DEBUG_LOG1("Truncating strbuffer preserve to %zu bytes\n", len); + VTermStringFragment frag; + + frag.str = str; + frag.len = len; + frag.initial = vt->parser.string_initial; + frag.final = final; + + switch(vt->parser.state) { + case OSC: + if(vt->parser.callbacks && vt->parser.callbacks->osc) + (*vt->parser.callbacks->osc)(vt->parser.v.osc.command, frag, vt->parser.cbdata); + break; + + case DCS: + if(len && vt->parser.callbacks && vt->parser.callbacks->dcs) + (*vt->parser.callbacks->dcs)(vt->parser.v.dcs.command, vt->parser.v.dcs.commandlen, frag, vt->parser.cbdata); + break; + + case NORMAL: + case CSI_LEADER: + case CSI_ARGS: + case CSI_INTERMED: + case OSC_COMMAND: + case DCS_COMMAND: + break; } - if(len > 0) { - strncpy(vt->parser.strbuffer + vt->parser.strbuffer_cur, str, len); - vt->parser.strbuffer_cur += len; - } -} - -static void start_string(VTerm *vt, VTermParserStringType type) -{ - vt->parser.stringtype = type; - - vt->parser.strbuffer_cur = 0; -} - -static void more_string(VTerm *vt, const char *str, size_t len) -{ - append_strbuffer(vt, str, len); -} - -static void done_string(VTerm *vt, const char *str, size_t len) -{ - if(vt->parser.strbuffer_cur) { - if(str) - append_strbuffer(vt, str, len); - - str = vt->parser.strbuffer; - len = vt->parser.strbuffer_cur; - } - else if(!str) { - DEBUG_LOG("parser.c: TODO: No strbuffer _and_ no final fragment???\n"); - len = 0; - } - - switch(vt->parser.stringtype) { - case VTERM_PARSER_OSC: - if(vt->parser.callbacks && vt->parser.callbacks->osc) - if((*vt->parser.callbacks->osc)(str, len, vt->parser.cbdata)) - return; - - DEBUG_LOG2("libvterm: Unhandled OSC %.*s\n", (int)len, str); - return; - - case VTERM_PARSER_DCS: - if(vt->parser.callbacks && vt->parser.callbacks->dcs) - if((*vt->parser.callbacks->dcs)(str, len, vt->parser.cbdata)) - return; - - DEBUG_LOG2("libvterm: Unhandled DCS %.*s\n", (int)len, str); - return; - - case VTERM_N_PARSER_TYPES: - return; - } + vt->parser.string_initial = FALSE; } size_t vterm_input_write(VTerm *vt, const char *bytes, size_t len) @@ -135,43 +106,45 @@ size_t vterm_input_write(VTerm *vt, const char *bytes, size_t len) case CSI_LEADER: case CSI_ARGS: case CSI_INTERMED: - case ESC: + case OSC_COMMAND: + case DCS_COMMAND: string_start = NULL; break; - case STRING: - case ESC_IN_STRING: + case OSC: + case DCS: string_start = bytes; break; } -#define ENTER_STRING_STATE() do { vt->parser.state = STRING; string_start = bytes + pos + 1; } while(0) #define ENTER_STATE(st) do { vt->parser.state = st; string_start = NULL; } while(0) #define ENTER_NORMAL_STATE() ENTER_STATE(NORMAL) for( ; pos < len; pos++) { unsigned char c = bytes[pos]; + int c1_allowed = !vt->mode.utf8; + size_t string_len; if(c == 0x00 || c == 0x7f) { // NUL, DEL - if(vt->parser.state >= STRING) { - more_string(vt, string_start, bytes + pos - string_start); + if(vt->parser.state >= OSC) { + string_fragment(vt, string_start, bytes + pos - string_start, FALSE); string_start = bytes + pos + 1; } continue; } if(c == 0x18 || c == 0x1a) { // CAN, SUB + vt->parser.in_esc = FALSE; ENTER_NORMAL_STATE(); continue; } else if(c == 0x1b) { // ESC vt->parser.intermedlen = 0; - if(vt->parser.state == STRING) - vt->parser.state = ESC_IN_STRING; - else - ENTER_STATE(ESC); + if(vt->parser.state < OSC) + vt->parser.state = NORMAL; + vt->parser.in_esc = TRUE; continue; } else if(c == 0x07 && // BEL, can stand for ST in OSC or DCS state - vt->parser.state == STRING) { + vt->parser.state >= OSC) { // fallthrough } else if(c < 0x20) { // other C0 @@ -182,96 +155,72 @@ size_t vterm_input_write(VTerm *vt, const char *bytes, size_t len) if(pos + 2 < len && bytes[pos + 1] == 0x20 && bytes[pos + 2] == 0x08) vt->in_backspace = 2; // Trigger when count down to 1 } - if(vt->parser.state >= STRING) - more_string(vt, string_start, bytes + pos - string_start); + if(vt->parser.state >= OSC) + string_fragment(vt, string_start, bytes + pos - string_start, FALSE); do_control(vt, c); - if(vt->parser.state >= STRING) + if(vt->parser.state >= OSC) string_start = bytes + pos + 1; continue; } // else fallthrough + string_len = bytes + pos - string_start; + + if(vt->parser.in_esc) { + // Hoist an ESC letter into a C1 if we're not in a string mode + // Always accept ESC \ == ST even in string mode + if(!vt->parser.intermedlen && + c >= 0x40 && c < 0x60 && + ((vt->parser.state < OSC || c == 0x5c))) { + c += 0x40; + c1_allowed = TRUE; + string_len -= 1; + vt->parser.in_esc = FALSE; + } + else { + string_start = NULL; + vt->parser.state = NORMAL; + } + } + switch(vt->parser.state) { - case ESC_IN_STRING: - if(c == 0x5c) { // ST - vt->parser.state = STRING; - done_string(vt, string_start, bytes + pos - string_start - 1); - ENTER_NORMAL_STATE(); - break; - } - vt->parser.state = ESC; - // else fallthrough - - case ESC: - switch(c) { - case 0x50: // DCS - start_string(vt, VTERM_PARSER_DCS); - ENTER_STRING_STATE(); - break; - case 0x5b: // CSI - vt->parser.csi_leaderlen = 0; - ENTER_STATE(CSI_LEADER); - break; - case 0x5d: // OSC - start_string(vt, VTERM_PARSER_OSC); - ENTER_STRING_STATE(); - break; - default: - if(is_intermed(c)) { - if(vt->parser.intermedlen < INTERMED_MAX-1) - vt->parser.intermed[vt->parser.intermedlen++] = c; - } - else if(!vt->parser.intermedlen && c >= 0x40 && c < 0x60) { - do_control(vt, c + 0x40); - ENTER_NORMAL_STATE(); - } - else if(c >= 0x30 && c < 0x7f) { - do_escape(vt, c); - ENTER_NORMAL_STATE(); - } - else { - DEBUG_LOG1("TODO: Unhandled byte %02x in Escape\n", c); - } - } - break; - case CSI_LEADER: // Extract leader bytes 0x3c to 0x3f if(c >= 0x3c && c <= 0x3f) { - if(vt->parser.csi_leaderlen < CSI_LEADER_MAX-1) - vt->parser.csi_leader[vt->parser.csi_leaderlen++] = c; + if(vt->parser.v.csi.leaderlen < CSI_LEADER_MAX-1) + vt->parser.v.csi.leader[vt->parser.v.csi.leaderlen++] = c; break; } // else fallthrough - vt->parser.csi_leader[vt->parser.csi_leaderlen] = 0; + vt->parser.v.csi.leader[vt->parser.v.csi.leaderlen] = 0; - vt->parser.csi_argi = 0; - vt->parser.csi_args[0] = CSI_ARG_MISSING; + vt->parser.v.csi.argi = 0; + vt->parser.v.csi.args[0] = CSI_ARG_MISSING; vt->parser.state = CSI_ARGS; // fallthrough case CSI_ARGS: // Numerical value of argument if(c >= '0' && c <= '9') { - if(vt->parser.csi_args[vt->parser.csi_argi] == CSI_ARG_MISSING) - vt->parser.csi_args[vt->parser.csi_argi] = 0; - vt->parser.csi_args[vt->parser.csi_argi] *= 10; - vt->parser.csi_args[vt->parser.csi_argi] += c - '0'; + if(vt->parser.v.csi.args[vt->parser.v.csi.argi] == CSI_ARG_MISSING) + vt->parser.v.csi.args[vt->parser.v.csi.argi] = 0; + vt->parser.v.csi.args[vt->parser.v.csi.argi] *= 10; + vt->parser.v.csi.args[vt->parser.v.csi.argi] += c - '0'; break; } if(c == ':') { - vt->parser.csi_args[vt->parser.csi_argi] |= CSI_ARG_FLAG_MORE; + vt->parser.v.csi.args[vt->parser.v.csi.argi] |= CSI_ARG_FLAG_MORE; c = ';'; } if(c == ';') { - vt->parser.csi_argi++; - vt->parser.csi_args[vt->parser.csi_argi] = CSI_ARG_MISSING; + vt->parser.v.csi.argi++; + vt->parser.v.csi.args[vt->parser.v.csi.argi] = CSI_ARG_MISSING; break; } // else fallthrough - vt->parser.csi_argi++; + vt->parser.v.csi.argi++; vt->parser.intermedlen = 0; vt->parser.state = CSI_INTERMED; // fallthrough @@ -293,31 +242,77 @@ size_t vterm_input_write(VTerm *vt, const char *bytes, size_t len) ENTER_NORMAL_STATE(); break; - case STRING: - if(c == 0x07 || (c == 0x9c && !vt->mode.utf8)) { - done_string(vt, string_start, bytes + pos - string_start); - ENTER_NORMAL_STATE(); + case OSC_COMMAND: + /* Numerical value of command */ + if(c >= '0' && c <= '9') { + if(vt->parser.v.osc.command == -1) + vt->parser.v.osc.command = 0; + else + vt->parser.v.osc.command *= 10; + vt->parser.v.osc.command += c - '0'; + break; } - else if (pos + 1 == len) { - // end of input but OSC string isn't finished yet, copy it to - // vt->parser.strbuffer to continue it later - more_string(vt, string_start, bytes + pos + 1 - string_start); + if(c == ';') { + vt->parser.state = OSC; + string_start = bytes + pos + 1; + break; + } + + /* else fallthrough */ + string_start = bytes + pos; + vt->parser.state = OSC; + goto string_state; + + case DCS_COMMAND: + if(vt->parser.v.dcs.commandlen < CSI_LEADER_MAX) + vt->parser.v.dcs.command[vt->parser.v.dcs.commandlen++] = c; + + if(c >= 0x40 && c<= 0x7e) { + string_start = bytes + pos + 1; + vt->parser.state = DCS; + } + break; + +string_state: + case OSC: + case DCS: + if(c == 0x07 || (c1_allowed && c == 0x9c)) { + string_fragment(vt, string_start, string_len, TRUE); + ENTER_NORMAL_STATE(); } break; case NORMAL: - if(c >= 0x80 && c < 0xa0 && !vt->mode.utf8) { + if(vt->parser.in_esc) { + if(is_intermed(c)) { + if(vt->parser.intermedlen < INTERMED_MAX-1) + vt->parser.intermed[vt->parser.intermedlen++] = c; + } + else if(c >= 0x30 && c < 0x7f) { + do_escape(vt, c); + vt->parser.in_esc = 0; + ENTER_NORMAL_STATE(); + } + else { + DEBUG_LOG1("TODO: Unhandled byte %02x in Escape\n", c); + } + break; + } + if(c1_allowed && c >= 0x80 && c < 0xa0) { switch(c) { case 0x90: // DCS - start_string(vt, VTERM_PARSER_DCS); - ENTER_STRING_STATE(); + vt->parser.string_initial = TRUE; + vt->parser.v.dcs.commandlen = 0; + ENTER_STATE(DCS_COMMAND); break; case 0x9b: // CSI + vt->parser.v.csi.leaderlen = 0; ENTER_STATE(CSI_LEADER); break; case 0x9d: // OSC - start_string(vt, VTERM_PARSER_OSC); - ENTER_STRING_STATE(); + vt->parser.v.osc.command = -1; + vt->parser.string_initial = TRUE; + ENTER_STATE(OSC_COMMAND); break; default: do_control(vt, c); @@ -341,6 +336,9 @@ size_t vterm_input_write(VTerm *vt, const char *bytes, size_t len) } } + if(string_start) + string_fragment(vt, string_start, bytes + pos - string_start, FALSE); + return len; } diff --git a/src/libvterm/src/screen.c b/src/libvterm/src/screen.c index 1da2b72ae7..0dd6276a1c 100644 --- a/src/libvterm/src/screen.c +++ b/src/libvterm/src/screen.c @@ -533,7 +533,7 @@ static void resize_buffer(VTermScreen *screen, int bufidx, int new_rows, int new ScreenCell *dst = &new_buffer[pos.row * new_cols + pos.col]; int i; - for(i = 0; ; i++) { + for(i = 0; i < VTERM_MAX_CHARS_PER_CELL; i++) { dst->chars[i] = src->chars[i]; if(!src->chars[i]) break; @@ -804,7 +804,7 @@ int vterm_screen_get_cell(const VTermScreen *screen, VTermPos pos, VTermScreenCe if(!intcell) return 0; - for(i = 0; ; i++) { + for(i = 0; i < VTERM_MAX_CHARS_PER_CELL; i++) { cell->chars[i] = intcell->chars[i]; if(!intcell->chars[i]) break; diff --git a/src/libvterm/src/state.c b/src/libvterm/src/state.c index 1be1dae85b..6a5c265abc 100644 --- a/src/libvterm/src/state.c +++ b/src/libvterm/src/state.c @@ -582,19 +582,12 @@ static int settermprop_int(VTermState *state, VTermProp prop, int v) return vterm_state_set_termprop(state, prop, &val); } -static int settermprop_string(VTermState *state, VTermProp prop, const char *str, size_t len) +static int settermprop_string(VTermState *state, VTermProp prop, VTermStringFragment frag) { - char *strvalue; - int r; VTermValue val; - strvalue = vterm_allocator_malloc(state->vt, (len+1) * sizeof(char)); - strncpy(strvalue, str, len); - strvalue[len] = 0; - val.string = strvalue; - r = vterm_state_set_termprop(state, prop, &val); - vterm_allocator_free(state->vt, strvalue); - return r; + val.string = frag; + return vterm_state_set_termprop(state, prop, &val); } static void savecursor(VTermState *state, int save) @@ -1602,100 +1595,121 @@ static int on_csi(const char *leader, const long args[], int argcount, const cha return 1; } -static int on_osc(const char *command, size_t cmdlen, void *user) +static int on_osc(int command, VTermStringFragment frag, void *user) { VTermState *state = user; - if(cmdlen < 2) - return 0; - - if(strneq(command, "0;", 2)) { - settermprop_string(state, VTERM_PROP_ICONNAME, command + 2, cmdlen - 2); - settermprop_string(state, VTERM_PROP_TITLE, command + 2, cmdlen - 2); - return 1; - } - else if(strneq(command, "1;", 2)) { - settermprop_string(state, VTERM_PROP_ICONNAME, command + 2, cmdlen - 2); - return 1; - } - else if(strneq(command, "2;", 2)) { - settermprop_string(state, VTERM_PROP_TITLE, command + 2, cmdlen - 2); - return 1; - } - else if(strneq(command, "10;", 3)) { - // request foreground color: <Esc>]10;?<0x07> - int red = state->default_fg.red; - int blue = state->default_fg.blue; - int green = state->default_fg.green; - vterm_push_output_sprintf_ctrl(state->vt, C1_OSC, "10;rgb:%02x%02x/%02x%02x/%02x%02x\x07", red, red, green, green, blue, blue); - return 1; - } - else if(strneq(command, "11;", 3)) { - // request background color: <Esc>]11;?<0x07> - int red = state->default_bg.red; - int blue = state->default_bg.blue; - int green = state->default_bg.green; - vterm_push_output_sprintf_ctrl(state->vt, C1_OSC, "11;rgb:%02x%02x/%02x%02x/%02x%02x\x07", red, red, green, green, blue, blue); - return 1; - } - else if(strneq(command, "12;", 3)) { - settermprop_string(state, VTERM_PROP_CURSORCOLOR, command + 3, cmdlen - 3); - return 1; - } - else if(state->fallbacks && state->fallbacks->osc) - if((*state->fallbacks->osc)(command, cmdlen, state->fbdata)) + switch(command) { + case 0: + settermprop_string(state, VTERM_PROP_ICONNAME, frag); + settermprop_string(state, VTERM_PROP_TITLE, frag); return 1; + case 1: + settermprop_string(state, VTERM_PROP_ICONNAME, frag); + return 1; + + case 2: + settermprop_string(state, VTERM_PROP_TITLE, frag); + return 1; + + case 10: + { + // request foreground color: <Esc>]10;?<0x07> + int red = state->default_fg.red; + int blue = state->default_fg.blue; + int green = state->default_fg.green; + vterm_push_output_sprintf_ctrl(state->vt, C1_OSC, "10;rgb:%02x%02x/%02x%02x/%02x%02x\x07", red, red, green, green, blue, blue); + return 1; + } + + case 11: + { + // request background color: <Esc>]11;?<0x07> + int red = state->default_bg.red; + int blue = state->default_bg.blue; + int green = state->default_bg.green; + vterm_push_output_sprintf_ctrl(state->vt, C1_OSC, "11;rgb:%02x%02x/%02x%02x/%02x%02x\x07", red, red, green, green, blue, blue); + return 1; + } + case 12: + settermprop_string(state, VTERM_PROP_CURSORCOLOR, frag); + return 1; + + default: + if(state->fallbacks && state->fallbacks->osc) + if((*state->fallbacks->osc)(command, frag, state->fbdata)) + return 1; + } + return 0; } -static void request_status_string(VTermState *state, const char *command, size_t cmdlen) +static void request_status_string(VTermState *state, VTermStringFragment frag) { VTerm *vt = state->vt; - if(cmdlen == 1) - switch(command[0]) { - case 'm': // Query SGR - { - long args[20]; - int argc = vterm_state_getpen(state, args, sizeof(args)/sizeof(args[0])); - int argi; - size_t cur = 0; + char *tmp = state->tmp.decrqss; + size_t i = 0; - cur += SNPRINTF(vt->tmpbuffer + cur, vt->tmpbuffer_len - cur, - vt->mode.ctrl8bit ? "\x90" "1$r" : ESC_S "P" "1$r"); // DCS 1$r ... - if(cur >= vt->tmpbuffer_len) - return; + if(frag.initial) + tmp[0] = tmp[1] = tmp[2] = tmp[3] = 0; - for(argi = 0; argi < argc; argi++) { - cur += SNPRINTF(vt->tmpbuffer + cur, vt->tmpbuffer_len - cur, - argi == argc - 1 ? "%ld" : - CSI_ARG_HAS_MORE(args[argi]) ? "%ld:" : - "%ld;", - CSI_ARG(args[argi])); + while(i < sizeof(state->tmp.decrqss)-1 && tmp[i]) + i++; + while(i < sizeof(state->tmp.decrqss)-1 && frag.len--) + tmp[i++] = (frag.str++)[0]; + tmp[i] = 0; - if(cur >= vt->tmpbuffer_len) - return; - } + if(!frag.final) + return; - cur += SNPRINTF(vt->tmpbuffer + cur, vt->tmpbuffer_len - cur, - vt->mode.ctrl8bit ? "m" "\x9C" : "m" ESC_S "\\"); // ... m ST - if(cur >= vt->tmpbuffer_len) - return; + fprintf(stderr, "DECRQSS on <%s>\n", tmp); - vterm_push_output_bytes(vt, vt->tmpbuffer, cur); - } + switch(tmp[0] | tmp[1]<<8 | tmp[2]<<16) { + case 'm': { + // Query SGR + long args[20]; + int argc = vterm_state_getpen(state, args, sizeof(args)/sizeof(args[0])); + size_t cur = 0; + int argi; + + cur += snprintf(vt->tmpbuffer + cur, vt->tmpbuffer_len - cur, + vt->mode.ctrl8bit ? "\x90" "1$r" : ESC_S "P" "1$r"); // DCS 1$r ... + if(cur >= vt->tmpbuffer_len) return; - case 'r': // Query DECSTBM - vterm_push_output_sprintf_dcs(vt, "1$r%d;%dr", state->scrollregion_top+1, SCROLLREGION_BOTTOM(state)); - return; - case 's': // Query DECSLRM - vterm_push_output_sprintf_dcs(vt, "1$r%d;%ds", SCROLLREGION_LEFT(state)+1, SCROLLREGION_RIGHT(state)); + + for(argi = 0; argi < argc; argi++) { + cur += snprintf(vt->tmpbuffer + cur, vt->tmpbuffer_len - cur, + argi == argc - 1 ? "%ld" : + CSI_ARG_HAS_MORE(args[argi]) ? "%ld:" : + "%ld;", + CSI_ARG(args[argi])); + if(cur >= vt->tmpbuffer_len) + return; + } + + cur += snprintf(vt->tmpbuffer + cur, vt->tmpbuffer_len - cur, + vt->mode.ctrl8bit ? "m" "\x9C" : "m" ESC_S "\\"); // ... m ST + if(cur >= vt->tmpbuffer_len) return; + + vterm_push_output_bytes(vt, vt->tmpbuffer, cur); + return; } - if(cmdlen == 2) { - if(strneq(command, " q", 2)) { + case 'r': + // Query DECSTBM + vterm_push_output_sprintf_dcs(vt, "1$r%d;%dr", state->scrollregion_top+1, SCROLLREGION_BOTTOM(state)); + return; + + case 's': + // Query DECSLRM + vterm_push_output_sprintf_dcs(vt, "1$r%d;%ds", SCROLLREGION_LEFT(state)+1, SCROLLREGION_RIGHT(state)); + return; + + case ' '|('q'<<8): { + // Query DECSCUSR int reply; switch(state->mode.cursor_shape) { case VTERM_PROP_CURSORSHAPE_BLOCK: reply = 2; break; @@ -1707,27 +1721,29 @@ static void request_status_string(VTermState *state, const char *command, size_t vterm_push_output_sprintf_dcs(vt, "1$r%d q", reply); return; } - else if(strneq(command, "\"q", 2)) { + + case '\"'|('q'<<8): + // Query DECSCA vterm_push_output_sprintf_dcs(vt, "1$r%d\"q", state->protected_cell ? 1 : 2); return; - } } - vterm_push_output_sprintf_dcs(state->vt, "0$r%.s", (int)cmdlen, command); + vterm_push_output_sprintf_dcs(state->vt, "0$r%s", tmp); } -static int on_dcs(const char *command, size_t cmdlen, void *user) +static int on_dcs(const char *command, size_t commandlen, VTermStringFragment frag, void *user) { VTermState *state = user; - if(cmdlen >= 2 && strneq(command, "$q", 2)) { - request_status_string(state, command+2, cmdlen-2); + if(commandlen == 2 && strneq(command, "$q", 2)) { + request_status_string(state, frag); return 1; } else if(state->fallbacks && state->fallbacks->dcs) - if((*state->fallbacks->dcs)(command, cmdlen, state->fbdata)) + if((*state->fallbacks->dcs)(command, commandlen, frag, state->fbdata)) return 1; + DEBUG_LOG2("libvterm: Unhandled DCS %.*s\n", (int)commandlen, command); return 0; } diff --git a/src/libvterm/src/vterm.c b/src/libvterm/src/vterm.c index 991286ee90..d03b7b4d70 100644 --- a/src/libvterm/src/vterm.c +++ b/src/libvterm/src/vterm.c @@ -55,35 +55,23 @@ VTerm *vterm_new_with_allocator(int rows, int cols, VTermAllocatorFunctions *fun vt->parser.callbacks = NULL; vt->parser.cbdata = NULL; - vt->parser.strbuffer_len = 500; // should be able to hold an OSC string - vt->parser.strbuffer_cur = 0; - vt->parser.strbuffer = vterm_allocator_malloc(vt, vt->parser.strbuffer_len); - if (vt->parser.strbuffer == NULL) - { - vterm_allocator_free(vt, vt); - return NULL; - } - vt->outfunc = NULL; vt->outdata = NULL; vt->outbuffer_len = 200; vt->outbuffer_cur = 0; vt->outbuffer = vterm_allocator_malloc(vt, vt->outbuffer_len); - if (vt->outbuffer == NULL) - { - vterm_allocator_free(vt, vt->parser.strbuffer); - vterm_allocator_free(vt, vt); - return NULL; - } vt->tmpbuffer_len = 64; vt->tmpbuffer = vterm_allocator_malloc(vt, vt->tmpbuffer_len); - if (vt->tmpbuffer == NULL) + + if (vt->tmpbuffer == NULL + || vt->outbuffer == NULL + || vt->tmpbuffer == NULL) { - vterm_allocator_free(vt, vt->parser.strbuffer); - vterm_allocator_free(vt, vt); vterm_allocator_free(vt, vt->outbuffer); + vterm_allocator_free(vt, vt->tmpbuffer); + vterm_allocator_free(vt, vt); return NULL; } @@ -98,7 +86,6 @@ void vterm_free(VTerm *vt) if(vt->state) vterm_state_free(vt->state); - vterm_allocator_free(vt, vt->parser.strbuffer); vterm_allocator_free(vt, vt->outbuffer); vterm_allocator_free(vt, vt->tmpbuffer); diff --git a/src/libvterm/src/vterm_internal.h b/src/libvterm/src/vterm_internal.h index 19b00c96ce..7321d0d856 100644 --- a/src/libvterm/src/vterm_internal.h +++ b/src/libvterm/src/vterm_internal.h @@ -160,15 +160,13 @@ struct VTermState unsigned int cursor_shape:2; } mode; } saved; + + /* Temporary state for DECRQSS parsing */ + union { + char decrqss[4]; + } tmp; }; -typedef enum { - VTERM_PARSER_OSC, - VTERM_PARSER_DCS, - - VTERM_N_PARSER_TYPES -} VTermParserStringType; - struct VTerm { VTermAllocatorFunctions *allocator; @@ -188,28 +186,39 @@ struct VTerm CSI_LEADER, CSI_ARGS, CSI_INTERMED, - ESC, + OSC_COMMAND, + DCS_COMMAND, // below here are the "string states" - STRING, - ESC_IN_STRING, + OSC, + DCS, } state; + unsigned int in_esc : 1; + int intermedlen; char intermed[INTERMED_MAX]; - int csi_leaderlen; - char csi_leader[CSI_LEADER_MAX]; + union { + struct { + int leaderlen; + char leader[CSI_LEADER_MAX]; - int csi_argi; - long csi_args[CSI_ARGS_MAX]; + int argi; + long args[CSI_ARGS_MAX]; + } csi; + struct { + int command; + } osc; + struct { + int commandlen; + char command[CSI_LEADER_MAX]; + } dcs; + } v; const VTermParserCallbacks *callbacks; void *cbdata; - VTermParserStringType stringtype; - char *strbuffer; - size_t strbuffer_len; - size_t strbuffer_cur; + int string_initial; } parser; // len == malloc()ed size; cur == number of valid bytes diff --git a/src/libvterm/t/02parser.test b/src/libvterm/t/02parser.test index 66d487dad9..4a4a65bca0 100644 --- a/src/libvterm/t/02parser.test +++ b/src/libvterm/t/02parser.test @@ -132,15 +132,23 @@ PUSH "\e[12\n;3X" !OSC BEL PUSH "\e]1;Hello\x07" - osc "1;Hello" + osc [1 "Hello"] !OSC ST (7bit) PUSH "\e]1;Hello\e\\" - osc "1;Hello" + osc [1 "Hello"] !OSC ST (8bit) PUSH "\x{9d}1;Hello\x9c" - osc "1;Hello" + osc [1 "Hello"] + +!OSC in parts +PUSH "\e]52;abc" + osc [52 "abc" +PUSH "def" + osc "def" +PUSH "ghi\e\\" + osc "ghi"] !Escape cancels OSC, starts Escape PUSH "\e]Something\e9" @@ -152,20 +160,21 @@ PUSH "\e]12\x{18}AB" !C0 in OSC interrupts and continues PUSH "\e]2;\nBye\x07" + osc [2 "" control 10 - osc "2;Bye" + osc "Bye"] !DCS BEL PUSH "\ePHello\x07" - dcs "Hello" + dcs ["Hello"] !DCS ST (7bit) PUSH "\ePHello\e\\" - dcs "Hello" + dcs ["Hello"] !DCS ST (8bit) PUSH "\x{90}Hello\x9c" - dcs "Hello" + dcs ["Hello"] !Escape cancels DCS, starts Escape PUSH "\ePSomething\e9" @@ -177,8 +186,9 @@ PUSH "\eP12\x{18}AB" !C0 in OSC interrupts and continues PUSH "\ePBy\ne\x07" + dcs ["By" control 10 - dcs "Bye" + dcs "e"] !NUL ignored PUSH "\x{00}" diff --git a/src/libvterm/t/18state_termprops.test b/src/libvterm/t/18state_termprops.test index 9e6928a21e..83c333f3fd 100644 --- a/src/libvterm/t/18state_termprops.test +++ b/src/libvterm/t/18state_termprops.test @@ -33,4 +33,10 @@ PUSH "\e[3 q" !Title PUSH "\e]2;Here is my title\a" - settermprop 4 "Here is my title" + settermprop 4 ["Here is my title"] + +!Title split write +PUSH "\e]2;Here is" + settermprop 4 ["Here is" +PUSH " another title\a" + settermprop 4 " another title"] diff --git a/src/libvterm/t/29state_fallback.test b/src/libvterm/t/29state_fallback.test index adf1c233ab..7995dd1b6a 100644 --- a/src/libvterm/t/29state_fallback.test +++ b/src/libvterm/t/29state_fallback.test @@ -12,8 +12,8 @@ PUSH "\e[?15;2z" !Unrecognised OSC PUSH "\e]27;Something\e\\" - osc "27;Something" + osc [27 "Something"] !Unrecognised DCS PUSH "\ePz123\e\\" - dcs "z123" + dcs ["z123"] diff --git a/src/libvterm/t/68screen_termprops.test b/src/libvterm/t/68screen_termprops.test index adf7ec2f74..bba6660e30 100644 --- a/src/libvterm/t/68screen_termprops.test +++ b/src/libvterm/t/68screen_termprops.test @@ -14,4 +14,4 @@ PUSH "\e[?25l" !Title PUSH "\e]2;Here is my title\a" - settermprop 4 "Here is my title" + settermprop 4 ["Here is my title"] diff --git a/src/libvterm/t/harness.c b/src/libvterm/t/harness.c index 289d829281..92882fdfd9 100644 --- a/src/libvterm/t/harness.c +++ b/src/libvterm/t/harness.c @@ -153,21 +153,44 @@ static int parser_csi(const char *leader, const long args[], int argcount, const return 1; } -static int parser_osc(const char *command, size_t cmdlen, void *user UNUSED) +static int parser_osc(int command, VTermStringFragment frag, void *user UNUSED) { printf("osc "); - printhex(command, cmdlen); + + if(frag.initial) { + if(command == -1) + printf("["); + else + printf("[%d;", command); + } + + printhex(frag.str, frag.len); + + if(frag.final) + printf("]"); + printf("\n"); return 1; } -static int parser_dcs(const char *command, size_t cmdlen, void *user UNUSED) +static int parser_dcs(const char *command, size_t commandlen, VTermStringFragment frag, void *user UNUSED) { - printf("dcs "); - printhex(command, cmdlen); + + if(frag.initial) { + size_t i; + printf("["); + for(i = 0; i < commandlen; i++) + printf("%02x", command[i]); + } + + printhex(frag.str, frag.len); + + if(frag.final) + printf("]"); + printf("\n"); return 1; @@ -239,7 +262,8 @@ static int settermprop(VTermProp prop, VTermValue *val, void *user UNUSED) printf("settermprop %d %d\n", prop, val->number); return 1; case VTERM_VALUETYPE_STRING: - printf("settermprop %d \"%s\"\n", prop, val->string); + printf("settermprop %d %s\"%.*s\"%s\n", prop, + val->string.initial ? "[" : "", val->string.len, val->string.str, val->string.final ? "]" : ""); return 1; case VTERM_VALUETYPE_COLOR: printf("settermprop %d rgb(%d,%d,%d)\n", prop, val->color.red, val->color.green, val->color.blue); @@ -262,7 +286,7 @@ static int state_putglyph(VTermGlyphInfo *info, VTermPos pos, void *user UNUSED) return 1; printf("putglyph "); - for(i = 0; info->chars[i]; i++) + for(i = 0; i < VTERM_MAX_CHARS_PER_CELL && info->chars[i]; i++) printf(i ? ",%x" : "%x", info->chars[i]); printf(" %d %d,%d", info->width, pos.row, pos.col); if(info->protected_cell) diff --git a/src/libvterm/t/run-test.pl b/src/libvterm/t/run-test.pl index 5f3c78d70f..9f48c5cade 100644 --- a/src/libvterm/t/run-test.pl +++ b/src/libvterm/t/run-test.pl @@ -11,7 +11,8 @@ my $VALGRIND = 0; my $EXECUTABLE = "t/.libs/harness"; GetOptions( 'valgrind|v+' => \$VALGRIND, - 'executable|e=s' => \$EXECUTABLE + 'executable|e=s' => \$EXECUTABLE, + 'fail-early|F' => \(my $FAIL_EARLY), ) or exit 1; my ( $hin, $hout, $hpid ); @@ -65,6 +66,7 @@ sub do_onetest } $exitcode = 1 if $fail_printed; + exit $exitcode if $exitcode and $FAIL_EARLY; } sub do_line @@ -105,8 +107,15 @@ sub do_line elsif( $line =~ m/^csi (\S+) (.*)$/ ) { $line = sprintf "csi %02x %s", eval($1), $2; # TODO } - elsif( $line =~ m/^(escape|osc|dcs) (.*)$/ ) { - $line = "$1 " . join "", map sprintf("%02x", $_), unpack "C*", eval($2); + elsif( $line =~ m/^(osc) (\[\d+)? *(.*?)(\]?)$/ ) { + my ( $cmd, $initial, $data, $final ) = ( $1, $2, $3, $4 ); + $initial //= ""; + $initial .= ";" if $initial =~ m/\d+/; + + $line = "$cmd $initial" . join( "", map sprintf("%02x", $_), unpack "C*", eval($data) ) . "$final"; + } + elsif( $line =~ m/^(escape|dcs) (\[?)(.*?)(\]?)$/ ) { + $line = "$1 $2" . join( "", map sprintf("%02x", $_), unpack "C*", eval($3) ) . "$4"; } elsif( $line =~ m/^putglyph (\S+) (.*)$/ ) { $line = "putglyph " . join( ",", map sprintf("%x", $_), eval($1) ) . " $2"; @@ -139,6 +148,7 @@ sub do_line "# Expected: $want\n" . "# Actual: $response\n"; $exitcode = 1; + exit $exitcode if $exitcode and $FAIL_EARLY; } } # Assertions start with '?' @@ -162,6 +172,7 @@ sub do_line "# Expected: $expectation\n" . "# Actual: $response\n"; $exitcode = 1; + exit $exitcode if $exitcode and $FAIL_EARLY; } } # Test controls start with '$' diff --git a/src/terminal.c b/src/terminal.c index fa18d70225..5774dba9a2 100644 --- a/src/terminal.c +++ b/src/terminal.c @@ -2998,22 +2998,27 @@ handle_settermprop( void *user) { term_T *term = (term_T *)user; + char_u *strval = NULL; switch (prop) { case VTERM_PROP_TITLE: + strval = vim_strnsave((char_u *)value->string.str, + (int)value->string.len); + if (strval == NULL) + break; vim_free(term->tl_title); // a blank title isn't useful, make it empty, so that "running" is // displayed - if (*skipwhite((char_u *)value->string) == NUL) + if (*skipwhite(strval) == NUL) term->tl_title = NULL; // Same as blank else if (term->tl_arg0_cmd != NULL - && STRNCMP(term->tl_arg0_cmd, (char_u *)value->string, + && STRNCMP(term->tl_arg0_cmd, strval, (int)STRLEN(term->tl_arg0_cmd)) == 0) term->tl_title = NULL; // Empty corrupted data of winpty - else if (STRNCMP(" - ", (char_u *)value->string, 4) == 0) + else if (STRNCMP(" - ", strval, 4) == 0) term->tl_title = NULL; #ifdef MSWIN else if (!enc_utf8 && enc_codepage > 0) @@ -3022,8 +3027,8 @@ handle_settermprop( int length = 0; MultiByteToWideChar_alloc(CP_UTF8, 0, - (char*)value->string, (int)STRLEN(value->string), - &ret, &length); + (char*)value->string.str, + (int)value->string.len, &ret, &length); if (ret != NULL) { WideCharToMultiByte_alloc(enc_codepage, 0, @@ -3034,7 +3039,10 @@ handle_settermprop( } #endif else - term->tl_title = vim_strsave((char_u *)value->string); + { + term->tl_title = vim_strsave(strval); + strval = NULL; + } VIM_CLEAR(term->tl_status_text); if (term == curbuf->b_term) maketitle(); @@ -3057,7 +3065,11 @@ handle_settermprop( break; case VTERM_PROP_CURSORCOLOR: - cursor_color_copy(&term->tl_cursor_color, (char_u*)value->string); + strval = vim_strnsave((char_u *)value->string.str, + (int)value->string.len); + if (strval == NULL) + break; + cursor_color_copy(&term->tl_cursor_color, strval); may_set_cursor_props(term); break; @@ -3069,6 +3081,8 @@ handle_settermprop( default: break; } + vim_free(strval); + // Always return 1, otherwise vterm doesn't store the value internally. return 1; } @@ -4181,7 +4195,7 @@ handle_call_command(term_T *term, channel_T *channel, listitem_T *item) * We recognize a terminal API command. */ static int -parse_osc(const char *command, size_t cmdlen, void *user) +parse_osc(int command, VTermStringFragment frag, void *user) { term_T *term = (term_T *)user; js_read_T reader; @@ -4190,10 +4204,10 @@ parse_osc(const char *command, size_t cmdlen, void *user) : term->tl_job->jv_channel; // We recognize only OSC 5 1 ; {command} - if (cmdlen < 3 || STRNCMP(command, "51;", 3) != 0) - return 0; // not handled + if (command != 51) + return 0; - reader.js_buf = vim_strnsave((char_u *)command + 3, (int)(cmdlen - 3)); + reader.js_buf = vim_strnsave((char_u *)frag.str, (int)(frag.len)); if (reader.js_buf == NULL) return 1; reader.js_fill = NULL; diff --git a/src/version.c b/src/version.c index 9c1f6f180f..4c3cab753d 100644 --- a/src/version.c +++ b/src/version.c @@ -746,6 +746,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 798, /**/ 797, /**/ From 74c69636563310d1e941fec695ff2d74518fe743 Mon Sep 17 00:00:00 2001 From: Bram Moolenaar <Bram@vim.org> Date: Tue, 19 May 2020 21:43:47 +0200 Subject: [PATCH 198/230] patch 8.2.0799: build fails if snprintf is not available Problem: Build fails if snprintf is not available. Solution: Use vim_snprintf(). --- src/libvterm/src/state.c | 6 +++--- src/version.c | 2 ++ 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/src/libvterm/src/state.c b/src/libvterm/src/state.c index 6a5c265abc..42f61f256d 100644 --- a/src/libvterm/src/state.c +++ b/src/libvterm/src/state.c @@ -1674,13 +1674,13 @@ static void request_status_string(VTermState *state, VTermStringFragment frag) size_t cur = 0; int argi; - cur += snprintf(vt->tmpbuffer + cur, vt->tmpbuffer_len - cur, + cur += SNPRINTF(vt->tmpbuffer + cur, vt->tmpbuffer_len - cur, vt->mode.ctrl8bit ? "\x90" "1$r" : ESC_S "P" "1$r"); // DCS 1$r ... if(cur >= vt->tmpbuffer_len) return; for(argi = 0; argi < argc; argi++) { - cur += snprintf(vt->tmpbuffer + cur, vt->tmpbuffer_len - cur, + cur += SNPRINTF(vt->tmpbuffer + cur, vt->tmpbuffer_len - cur, argi == argc - 1 ? "%ld" : CSI_ARG_HAS_MORE(args[argi]) ? "%ld:" : "%ld;", @@ -1689,7 +1689,7 @@ static void request_status_string(VTermState *state, VTermStringFragment frag) return; } - cur += snprintf(vt->tmpbuffer + cur, vt->tmpbuffer_len - cur, + cur += SNPRINTF(vt->tmpbuffer + cur, vt->tmpbuffer_len - cur, vt->mode.ctrl8bit ? "m" "\x9C" : "m" ESC_S "\\"); // ... m ST if(cur >= vt->tmpbuffer_len) return; diff --git a/src/version.c b/src/version.c index 4c3cab753d..f79ad7545c 100644 --- a/src/version.c +++ b/src/version.c @@ -746,6 +746,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 799, /**/ 798, /**/ From a09195f29ee8cd88411152cf311f4e4ab2f3b4b3 Mon Sep 17 00:00:00 2001 From: Bram Moolenaar <Bram@vim.org> Date: Tue, 19 May 2020 22:38:59 +0200 Subject: [PATCH 199/230] patch 8.2.0800: errors from failing test are unclear Problem: Errors from failing test are unclear. Solution: Include text where parsing failed. --- src/json.c | 20 ++++++++++-------- src/testdir/test_json.vim | 44 +++++++++++++++++++-------------------- src/version.c | 2 ++ 3 files changed, 35 insertions(+), 31 deletions(-) diff --git a/src/json.c b/src/json.c index ec3355e714..2720abfca4 100644 --- a/src/json.c +++ b/src/json.c @@ -20,6 +20,8 @@ static int json_encode_item(garray_T *gap, typval_T *val, int copyID, int options); +static char e_json_error[] = N_("E491: json decode error at '%s'"); + /* * Encode "val" into a JSON format string. * The result is added to "gap" @@ -740,7 +742,7 @@ json_decode_item(js_read_T *reader, typval_T *res, int options) retval = json_decode_string(reader, cur_item, *p); else { - emsg(_(e_invarg)); + semsg(_(e_json_error), p); retval = FAIL; } break; @@ -748,7 +750,7 @@ json_decode_item(js_read_T *reader, typval_T *res, int options) case ',': // comma: empty item if ((options & JSON_JS) == 0) { - emsg(_(e_invarg)); + semsg(_(e_json_error), p); retval = FAIL; break; } @@ -778,7 +780,7 @@ json_decode_item(js_read_T *reader, typval_T *res, int options) } if (!VIM_ISDIGIT(*sp)) { - emsg(_(e_invarg)); + semsg(_(e_json_error), p); retval = FAIL; break; } @@ -809,7 +811,7 @@ json_decode_item(js_read_T *reader, typval_T *res, int options) &nr, NULL, 0, TRUE); if (len == 0) { - emsg(_(e_invarg)); + semsg(_(e_json_error), p); retval = FAIL; goto theend; } @@ -962,7 +964,7 @@ item_end: retval = MAYBE; else { - emsg(_(e_invarg)); + semsg(_(e_json_error), p); retval = FAIL; } goto theend; @@ -980,7 +982,7 @@ item_end: retval = MAYBE; else { - emsg(_(e_invarg)); + semsg(_(e_json_error), p); retval = FAIL; } goto theend; @@ -1036,7 +1038,7 @@ item_end: retval = MAYBE; else { - emsg(_(e_invarg)); + semsg(_(e_json_error), p); retval = FAIL; } goto theend; @@ -1055,7 +1057,7 @@ item_end: res->v_type = VAR_SPECIAL; res->vval.v_number = VVAL_NONE; } - emsg(_(e_invarg)); + semsg(_(e_json_error), p); theend: ga_clear(&stack); @@ -1079,7 +1081,7 @@ json_decode_all(js_read_T *reader, typval_T *res, int options) if (ret != OK) { if (ret == MAYBE) - emsg(_(e_invarg)); + semsg(_(e_json_error), reader->js_buf); return FAIL; } json_skip_white(reader); diff --git a/src/testdir/test_json.vim b/src/testdir/test_json.vim index 94481d9305..6c11ace187 100644 --- a/src/testdir/test_json.vim +++ b/src/testdir/test_json.vim @@ -148,36 +148,36 @@ func Test_json_decode() call assert_fails("call json_decode('{\"\": \"ok\", \"\": \"bad\"}')", 'E938:') call assert_equal({'n': 1}, json_decode('{"n":1,}')) - call assert_fails("call json_decode(\"{'n':'1',}\")", 'E474:') - call assert_fails("call json_decode(\"'n'\")", 'E474:') + call assert_fails("call json_decode(\"{'n':'1',}\")", 'E491:') + call assert_fails("call json_decode(\"'n'\")", 'E491:') - call assert_fails('call json_decode("\"")', "E474:") - call assert_fails('call json_decode("blah")', "E474:") + call assert_fails('call json_decode("\"")', "E491:") + call assert_fails('call json_decode("blah")', "E491:") call assert_fails('call json_decode("true blah")', "E488:") - call assert_fails('call json_decode("<foobar>")', "E474:") + call assert_fails('call json_decode("<foobar>")', "E491:") call assert_fails('call json_decode("{\"a\":1,\"a\":2}")', "E938:") - call assert_fails('call json_decode("{")', "E474:") - call assert_fails('call json_decode("{foobar}")', "E474:") - call assert_fails('call json_decode("{\"n\",")', "E474:") - call assert_fails('call json_decode("{\"n\":")', "E474:") - call assert_fails('call json_decode("{\"n\":1")', "E474:") - call assert_fails('call json_decode("{\"n\":1,")', "E474:") - call assert_fails('call json_decode("{\"n\",1}")', "E474:") - call assert_fails('call json_decode("{-}")', "E474:") + call assert_fails('call json_decode("{")', "E491:") + call assert_fails('call json_decode("{foobar}")', "E491:") + call assert_fails('call json_decode("{\"n\",")', "E491:") + call assert_fails('call json_decode("{\"n\":")', "E491:") + call assert_fails('call json_decode("{\"n\":1")', "E491:") + call assert_fails('call json_decode("{\"n\":1,")', "E491:") + call assert_fails('call json_decode("{\"n\",1}")', "E491:") + call assert_fails('call json_decode("{-}")', "E491:") - call assert_fails('call json_decode("[foobar]")', "E474:") - call assert_fails('call json_decode("[")', "E474:") - call assert_fails('call json_decode("[1")', "E474:") - call assert_fails('call json_decode("[1,")', "E474:") - call assert_fails('call json_decode("[1 2]")', "E474:") + call assert_fails('call json_decode("[foobar]")', "E491:") + call assert_fails('call json_decode("[")', "E491:") + call assert_fails('call json_decode("[1")', "E491:") + call assert_fails('call json_decode("[1,")', "E491:") + call assert_fails('call json_decode("[1 2]")', "E491:") - call assert_fails('call json_decode("[1,,2]")', "E474:") + call assert_fails('call json_decode("[1,,2]")', "E491:") - call assert_fails('call json_decode("{{}:42}")', "E474:") - call assert_fails('call json_decode("{[]:42}")', "E474:") + call assert_fails('call json_decode("{{}:42}")', "E491:") + call assert_fails('call json_decode("{[]:42}")', "E491:") - call assert_fails('call json_decode("\"\\u111Z\"")', 'E474:') + call assert_fails('call json_decode("\"\\u111Z\"")', 'E491:') call assert_equal('[😂]', json_decode('"[\uD83D\uDE02]"')) call assert_equal('a😂b', json_decode('"a\uD83D\uDE02b"')) endfunc diff --git a/src/version.c b/src/version.c index f79ad7545c..ede8ad10bc 100644 --- a/src/version.c +++ b/src/version.c @@ -746,6 +746,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 800, /**/ 799, /**/ From eaa3e0dae53acc9a345f430ef014d65c105192c3 Mon Sep 17 00:00:00 2001 From: Bram Moolenaar <Bram@vim.org> Date: Tue, 19 May 2020 23:11:00 +0200 Subject: [PATCH 200/230] patch 8.2.0801: terminal test fails on Mac Problem: Terminal test fails on Mac. Solution: Concatenate OSC pieces. --- src/terminal.c | 20 +++++++++++++++++--- src/version.c | 2 ++ 2 files changed, 19 insertions(+), 3 deletions(-) diff --git a/src/terminal.c b/src/terminal.c index 5774dba9a2..1fdad2aeec 100644 --- a/src/terminal.c +++ b/src/terminal.c @@ -162,6 +162,7 @@ struct terminal_S { char_u *tl_cursor_color; // NULL or allocated int tl_using_altscreen; + garray_T tl_osc_buf; // incomplete OSC string }; #define TMODE_ONCE 1 // CTRL-\ CTRL-N used @@ -445,6 +446,7 @@ term_start( #endif ga_init2(&term->tl_scrollback, sizeof(sb_line_T), 300); ga_init2(&term->tl_scrollback_postponed, sizeof(sb_line_T), 300); + ga_init2(&term->tl_osc_buf, sizeof(char), 300); CLEAR_FIELD(split_ea); if (opt->jo_curwin) @@ -1015,6 +1017,7 @@ free_unused_terminals() terminals_to_free = term->tl_next; free_scrollback(term); + ga_clear(&term->tl_osc_buf); term_free_vterm(term); vim_free(term->tl_api); @@ -4202,14 +4205,25 @@ parse_osc(int command, VTermStringFragment frag, void *user) typval_T tv; channel_T *channel = term->tl_job == NULL ? NULL : term->tl_job->jv_channel; + garray_T *gap = &term->tl_osc_buf; // We recognize only OSC 5 1 ; {command} if (command != 51) return 0; - reader.js_buf = vim_strnsave((char_u *)frag.str, (int)(frag.len)); - if (reader.js_buf == NULL) + // Concatenate what was received until the final piece is found. + if (ga_grow(gap, (int)frag.len + 1) == FAIL) + { + ga_clear(gap); return 1; + } + mch_memmove((char *)gap->ga_data + gap->ga_len, frag.str, frag.len); + gap->ga_len += frag.len; + if (!frag.final) + return 1; + + ((char *)gap->ga_data)[gap->ga_len] = 0; + reader.js_buf = gap->ga_data; reader.js_fill = NULL; reader.js_used = 0; if (json_decode(&reader, &tv, 0) == OK @@ -4243,7 +4257,7 @@ parse_osc(int command, VTermStringFragment frag, void *user) else ch_log(channel, "Invalid JSON received"); - vim_free(reader.js_buf); + ga_clear(gap); clear_tv(&tv); return 1; } diff --git a/src/version.c b/src/version.c index ede8ad10bc..68d1db90dd 100644 --- a/src/version.c +++ b/src/version.c @@ -746,6 +746,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 801, /**/ 800, /**/ From d863728913801c8fa6d633f6580edfcada533fd0 Mon Sep 17 00:00:00 2001 From: Bram Moolenaar <Bram@vim.org> Date: Wed, 20 May 2020 18:41:41 +0200 Subject: [PATCH 201/230] patch 8.2.0802: libvterm code lags behind the upstream version Problem: Libvterm code lags behind the upstream version. Solution: Include revisions 759 - 762. --- src/libvterm/doc/seqs.txt | 2 ++ src/libvterm/include/vterm.h | 18 +++++++++++++----- src/libvterm/src/pen.c | 19 +++++++++++++++++++ src/libvterm/src/screen.c | 12 +++++++++++- src/libvterm/src/state.c | 18 +++++++++++++++++- src/libvterm/src/vterm.c | 1 + src/libvterm/src/vterm_internal.h | 3 ++- src/libvterm/t/12state_scroll.test | 8 +++++++- src/libvterm/t/harness.c | 15 +++++++++++++-- src/terminal.c | 9 +++------ src/version.c | 2 ++ 11 files changed, 90 insertions(+), 17 deletions(-) diff --git a/src/libvterm/doc/seqs.txt b/src/libvterm/doc/seqs.txt index c03fa51d7f..aa15fec3df 100644 --- a/src/libvterm/doc/seqs.txt +++ b/src/libvterm/doc/seqs.txt @@ -170,6 +170,7 @@ between states. SGR 4:x = Underline style 123 SGR 5 = Blink on 123 SGR 7 = Reverse on + SGR 8 = Conceal on SGR 9 = Strikethrough on SGR 10-19 = Select font SGR 21 = Underline double @@ -178,6 +179,7 @@ between states. 23 SGR 24 = Underline off 23 SGR 25 = Blink off 23 SGR 27 = Reverse off + SGR 28 = Conceal off SGR 29 = Strikethrough off SGR 30-37 = Foreground ANSI SGR 38 = Foreground alternative palette diff --git a/src/libvterm/include/vterm.h b/src/libvterm/include/vterm.h index 8b6a64d96a..b6491f1f70 100644 --- a/src/libvterm/include/vterm.h +++ b/src/libvterm/include/vterm.h @@ -128,6 +128,7 @@ typedef enum { VTERM_ATTR_ITALIC, // bool: 3, 23 VTERM_ATTR_BLINK, // bool: 5, 25 VTERM_ATTR_REVERSE, // bool: 7, 27 + VTERM_ATTR_CONCEAL, // bool: 8, 28 VTERM_ATTR_STRIKE, // bool: 9, 29 VTERM_ATTR_FONT, // number: 10-19 VTERM_ATTR_FOREGROUND, // color: 30-39 90-97 @@ -314,13 +315,19 @@ typedef struct { // useful to add protocol? } VTermMouseState; +typedef struct { + int (*control)(unsigned char control, void *user); + int (*csi)(const char *leader, const long args[], int argcount, const char *intermed, char command, void *user); + int (*osc)(int command, VTermStringFragment frag, void *user); + int (*dcs)(const char *command, size_t commandlen, VTermStringFragment frag, void *user); +} VTermStateFallbacks; + VTermState *vterm_obtain_state(VTerm *vt); void vterm_state_set_callbacks(VTermState *state, const VTermStateCallbacks *callbacks, void *user); void *vterm_state_get_cbdata(VTermState *state); -// Only invokes control, csi, osc, dcs -void vterm_state_set_unrecognised_fallbacks(VTermState *state, const VTermParserCallbacks *fallbacks, void *user); +void vterm_state_set_unrecognised_fallbacks(VTermState *state, const VTermStateFallbacks *fallbacks, void *user); void *vterm_state_get_unrecognised_fbdata(VTermState *state); // Initialize the state. @@ -349,6 +356,7 @@ typedef struct { unsigned int italic : 1; unsigned int blink : 1; unsigned int reverse : 1; + unsigned int conceal : 1; unsigned int strike : 1; unsigned int font : 4; // 0 to 9 unsigned int dwl : 1; // On a DECDWL or DECDHL line @@ -395,8 +403,7 @@ VTermScreen *vterm_obtain_screen(VTerm *vt); void vterm_screen_set_callbacks(VTermScreen *screen, const VTermScreenCallbacks *callbacks, void *user); void *vterm_screen_get_cbdata(VTermScreen *screen); -// Only invokes control, csi, osc, dcs -void vterm_screen_set_unrecognised_fallbacks(VTermScreen *screen, const VTermParserCallbacks *fallbacks, void *user); +void vterm_screen_set_unrecognised_fallbacks(VTermScreen *screen, const VTermStateFallbacks *fallbacks, void *user); void *vterm_screen_get_unrecognised_fbdata(VTermScreen *screen); // Enable support for using the alternate screen if "altscreen" is non-zero. @@ -438,8 +445,9 @@ typedef enum { VTERM_ATTR_FONT_MASK = 1 << 6, VTERM_ATTR_FOREGROUND_MASK = 1 << 7, VTERM_ATTR_BACKGROUND_MASK = 1 << 8, + VTERM_ATTR_CONCEAL_MASK = 1 << 9, - VTERM_ALL_ATTRS_MASK = (1 << 9) - 1 + VTERM_ALL_ATTRS_MASK = (1 << 10) - 1 } VTermAttrMask; int vterm_screen_get_attrs_extent(const VTermScreen *screen, VTermRect *extent, VTermPos pos, VTermAttrMask attrs); diff --git a/src/libvterm/src/pen.c b/src/libvterm/src/pen.c index 5619f276d6..831d1803f4 100644 --- a/src/libvterm/src/pen.c +++ b/src/libvterm/src/pen.c @@ -170,6 +170,7 @@ INTERNAL void vterm_state_resetpen(VTermState *state) state->pen.italic = 0; setpenattr_bool(state, VTERM_ATTR_ITALIC, 0); state->pen.blink = 0; setpenattr_bool(state, VTERM_ATTR_BLINK, 0); state->pen.reverse = 0; setpenattr_bool(state, VTERM_ATTR_REVERSE, 0); + state->pen.conceal = 0; setpenattr_bool(state, VTERM_ATTR_CONCEAL, 0); state->pen.strike = 0; setpenattr_bool(state, VTERM_ATTR_STRIKE, 0); state->pen.font = 0; setpenattr_int( state, VTERM_ATTR_FONT, 0); @@ -192,6 +193,7 @@ INTERNAL void vterm_state_savepen(VTermState *state, int save) setpenattr_bool(state, VTERM_ATTR_ITALIC, state->pen.italic); setpenattr_bool(state, VTERM_ATTR_BLINK, state->pen.blink); setpenattr_bool(state, VTERM_ATTR_REVERSE, state->pen.reverse); + setpenattr_bool(state, VTERM_ATTR_CONCEAL, state->pen.conceal); setpenattr_bool(state, VTERM_ATTR_STRIKE, state->pen.strike); setpenattr_int( state, VTERM_ATTR_FONT, state->pen.font); setpenattr_col( state, VTERM_ATTR_FOREGROUND, state->pen.fg); @@ -293,6 +295,11 @@ INTERNAL void vterm_state_setpen(VTermState *state, const long args[], int argco setpenattr_bool(state, VTERM_ATTR_REVERSE, 1); break; + case 8: // Conceal on + state->pen.conceal = 1; + setpenattr_bool(state, VTERM_ATTR_CONCEAL, 1); + break; + case 9: // Strikethrough on state->pen.strike = 1; setpenattr_bool(state, VTERM_ATTR_STRIKE, 1); @@ -334,6 +341,11 @@ INTERNAL void vterm_state_setpen(VTermState *state, const long args[], int argco setpenattr_bool(state, VTERM_ATTR_REVERSE, 0); break; + case 28: // Conceal off (Reveal) + state->pen.conceal = 0; + setpenattr_bool(state, VTERM_ATTR_CONCEAL, 0); + break; + case 29: // Strikethrough off state->pen.strike = 0; setpenattr_bool(state, VTERM_ATTR_STRIKE, 0); @@ -433,6 +445,9 @@ INTERNAL int vterm_state_getpen(VTermState *state, long args[], int argcount UNU if(state->pen.reverse) args[argi++] = 7; + if(state->pen.conceal) + args[argi++] = 8; + if(state->pen.strike) args[argi++] = 9; @@ -512,6 +527,10 @@ int vterm_state_get_penattr(const VTermState *state, VTermAttr attr, VTermValue val->boolean = state->pen.reverse; return 1; + case VTERM_ATTR_CONCEAL: + val->boolean = state->pen.conceal; + return 1; + case VTERM_ATTR_STRIKE: val->boolean = state->pen.strike; return 1; diff --git a/src/libvterm/src/screen.c b/src/libvterm/src/screen.c index 0dd6276a1c..1e2439c497 100644 --- a/src/libvterm/src/screen.c +++ b/src/libvterm/src/screen.c @@ -21,6 +21,7 @@ typedef struct unsigned int italic : 1; unsigned int blink : 1; unsigned int reverse : 1; + unsigned int conceal : 1; unsigned int strike : 1; unsigned int font : 4; // 0 to 9 @@ -420,6 +421,9 @@ static int setpenattr(VTermAttr attr, VTermValue *val, void *user) case VTERM_ATTR_REVERSE: screen->pen.reverse = val->boolean; return 1; + case VTERM_ATTR_CONCEAL: + screen->pen.conceal = val->boolean; + return 1; case VTERM_ATTR_STRIKE: screen->pen.strike = val->boolean; return 1; @@ -544,6 +548,7 @@ static void resize_buffer(VTermScreen *screen, int bufidx, int new_rows, int new dst->pen.italic = src->attrs.italic; dst->pen.blink = src->attrs.blink; dst->pen.reverse = src->attrs.reverse ^ screen->global_reverse; + dst->pen.conceal = src->attrs.conceal; dst->pen.strike = src->attrs.strike; dst->pen.font = src->attrs.font; @@ -553,6 +558,8 @@ static void resize_buffer(VTermScreen *screen, int bufidx, int new_rows, int new if(src->width == 2 && pos.col < (new_cols-1)) (dst + 1)->chars[0] = (uint32_t) -1; } + for( ; pos.col < new_cols; pos.col++) + clearcell(screen, &new_buffer[pos.row * new_cols + pos.col]); new_row--; if(active) @@ -815,6 +822,7 @@ int vterm_screen_get_cell(const VTermScreen *screen, VTermPos pos, VTermScreenCe cell->attrs.italic = intcell->pen.italic; cell->attrs.blink = intcell->pen.blink; cell->attrs.reverse = intcell->pen.reverse ^ screen->global_reverse; + cell->attrs.conceal = intcell->pen.conceal; cell->attrs.strike = intcell->pen.strike; cell->attrs.font = intcell->pen.font; @@ -890,7 +898,7 @@ void *vterm_screen_get_cbdata(VTermScreen *screen) return screen->cbdata; } -void vterm_screen_set_unrecognised_fallbacks(VTermScreen *screen, const VTermParserCallbacks *fallbacks, void *user) +void vterm_screen_set_unrecognised_fallbacks(VTermScreen *screen, const VTermStateFallbacks *fallbacks, void *user) { vterm_state_set_unrecognised_fallbacks(screen->state, fallbacks, user); } @@ -935,6 +943,8 @@ static int attrs_differ(VTermAttrMask attrs, ScreenCell *a, ScreenCell *b) return 1; if((attrs & VTERM_ATTR_REVERSE_MASK) && (a->pen.reverse != b->pen.reverse)) return 1; + if((attrs & VTERM_ATTR_CONCEAL_MASK) && (a->pen.conceal != b->pen.conceal)) + return 1; if((attrs & VTERM_ATTR_STRIKE_MASK) && (a->pen.strike != b->pen.strike)) return 1; if((attrs & VTERM_ATTR_FONT_MASK) && (a->pen.font != b->pen.font)) diff --git a/src/libvterm/src/state.c b/src/libvterm/src/state.c index 42f61f256d..15579d2c4c 100644 --- a/src/libvterm/src/state.c +++ b/src/libvterm/src/state.c @@ -1478,6 +1478,14 @@ static int on_csi(const char *leader, const long args[], int argcount, const cha state->scrollregion_bottom = -1; } + // Setting the scrolling region restores the cursor to the home position + state->pos.row = 0; + state->pos.col = 0; + if(state->mode.origin) { + state->pos.row += state->scrollregion_top; + state->pos.col += SCROLLREGION_LEFT(state); + } + break; case 0x73: // DECSLRM - DEC custom @@ -1499,6 +1507,14 @@ static int on_csi(const char *leader, const long args[], int argcount, const cha state->scrollregion_right = -1; } + // Setting the scrolling region restores the cursor to the home position + state->pos.row = 0; + state->pos.col = 0; + if(state->mode.origin) { + state->pos.row += state->scrollregion_top; + state->pos.col += SCROLLREGION_LEFT(state); + } + break; case 0x74: @@ -1979,7 +1995,7 @@ void *vterm_state_get_cbdata(VTermState *state) return state->cbdata; } -void vterm_state_set_unrecognised_fallbacks(VTermState *state, const VTermParserCallbacks *fallbacks, void *user) +void vterm_state_set_unrecognised_fallbacks(VTermState *state, const VTermStateFallbacks *fallbacks, void *user) { if(fallbacks) { state->fallbacks = fallbacks; diff --git a/src/libvterm/src/vterm.c b/src/libvterm/src/vterm.c index d03b7b4d70..a9fd3eda7a 100644 --- a/src/libvterm/src/vterm.c +++ b/src/libvterm/src/vterm.c @@ -261,6 +261,7 @@ VTermValueType vterm_get_attr_type(VTermAttr attr) case VTERM_ATTR_ITALIC: return VTERM_VALUETYPE_BOOL; case VTERM_ATTR_BLINK: return VTERM_VALUETYPE_BOOL; case VTERM_ATTR_REVERSE: return VTERM_VALUETYPE_BOOL; + case VTERM_ATTR_CONCEAL: return VTERM_VALUETYPE_BOOL; case VTERM_ATTR_STRIKE: return VTERM_VALUETYPE_BOOL; case VTERM_ATTR_FONT: return VTERM_VALUETYPE_INT; case VTERM_ATTR_FOREGROUND: return VTERM_VALUETYPE_COLOR; diff --git a/src/libvterm/src/vterm_internal.h b/src/libvterm/src/vterm_internal.h index 7321d0d856..1cfe9383d3 100644 --- a/src/libvterm/src/vterm_internal.h +++ b/src/libvterm/src/vterm_internal.h @@ -53,6 +53,7 @@ struct VTermPen unsigned int italic:1; unsigned int blink:1; unsigned int reverse:1; + unsigned int conceal:1; unsigned int strike:1; unsigned int font:4; // To store 0-9 }; @@ -73,7 +74,7 @@ struct VTermState const VTermStateCallbacks *callbacks; void *cbdata; - const VTermParserCallbacks *fallbacks; + const VTermStateFallbacks *fallbacks; void *fbdata; int rows; diff --git a/src/libvterm/t/12state_scroll.test b/src/libvterm/t/12state_scroll.test index ca305d499b..c1f2791d00 100644 --- a/src/libvterm/t/12state_scroll.test +++ b/src/libvterm/t/12state_scroll.test @@ -40,8 +40,8 @@ PUSH "\n" ?cursor = 20,0 !Index in DECSTBM -PUSH "\e[10H" PUSH "\e[9;10r" +PUSH "\e[10H" PUSH "\eM" ?cursor = 8,0 PUSH "\eM" @@ -148,3 +148,9 @@ PUSH "\e[2T" moverect 0..23,0..80 -> 2..25,0..80 erase 0..2,0..80 ?cursor = 0,0 + +!DECSTBM resets cursor position +PUSH "\e[5;5H" + ?cursor = 4,4 +PUSH "\e[r" + ?cursor = 0,0 diff --git a/src/libvterm/t/harness.c b/src/libvterm/t/harness.c index 92882fdfd9..fd129b715e 100644 --- a/src/libvterm/t/harness.c +++ b/src/libvterm/t/harness.c @@ -206,7 +206,14 @@ static VTermParserCallbacks parser_cbs = { NULL // resize }; -// These callbacks are shared by State and Screen +static VTermStateFallbacks fallbacks = { + parser_control, // control + parser_csi, // csi + parser_osc, // osc + parser_dcs // dcs +}; + +/* These callbacks are shared by State and Screen */ static int want_movecursor = 0; static VTermPos state_pos; @@ -319,6 +326,7 @@ static struct { int italic; int blink; int reverse; + int conceal; int strike; int font; VTermColor foreground; @@ -342,6 +350,9 @@ static int state_setpenattr(VTermAttr attr, VTermValue *val, void *user UNUSED) case VTERM_ATTR_REVERSE: state_pen.reverse = val->boolean; break; + case VTERM_ATTR_CONCEAL: + state_pen.conceal = val->boolean; + break; case VTERM_ATTR_STRIKE: state_pen.strike = val->boolean; break; @@ -552,7 +563,7 @@ int main(int argc UNUSED, char **argv UNUSED) want_settermprop = sense; break; case 'f': - vterm_state_set_unrecognised_fallbacks(state, sense ? &parser_cbs : NULL, NULL); + vterm_state_set_unrecognised_fallbacks(state, sense ? &fallbacks : NULL, NULL); break; default: fprintf(stderr, "Unrecognised WANTSTATE flag '%c'\n", line[i]); diff --git a/src/terminal.c b/src/terminal.c index 1fdad2aeec..c41b2f1006 100644 --- a/src/terminal.c +++ b/src/terminal.c @@ -4321,14 +4321,11 @@ parse_csi( return 1; } -static VTermParserCallbacks parser_fallbacks = { - NULL, // text +static VTermStateFallbacks state_fallbacks = { NULL, // control - NULL, // escape parse_csi, // csi parse_osc, // osc - NULL, // dcs - NULL // resize + NULL // dcs }; /* @@ -4411,7 +4408,7 @@ create_vterm(term_T *term, int rows, int cols) value.boolean = 0; #endif vterm_state_set_termprop(state, VTERM_PROP_CURSORBLINK, &value); - vterm_state_set_unrecognised_fallbacks(state, &parser_fallbacks, term); + vterm_state_set_unrecognised_fallbacks(state, &state_fallbacks, term); return OK; } diff --git a/src/version.c b/src/version.c index 68d1db90dd..ab899f3e49 100644 --- a/src/version.c +++ b/src/version.c @@ -746,6 +746,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 802, /**/ 801, /**/ From 83a52533b23c88f90be0dea01bc5e32ddadc1d6a Mon Sep 17 00:00:00 2001 From: Bram Moolenaar <Bram@vim.org> Date: Wed, 20 May 2020 19:30:19 +0200 Subject: [PATCH 202/230] patch 8.2.0803: libvterm code lags behind the upstream version Problem: Libvterm code lags behind the upstream version. Solution: Include revisions 764 - 767 --- src/Makefile | 2 +- src/libvterm/find-wide-chars.pl | 6 +---- src/libvterm/src/fullwidth.inc | 37 ++++++++++++++++++------------- src/libvterm/src/parser.c | 16 ++++++++----- src/libvterm/src/vterm_internal.h | 4 ++-- src/libvterm/t/02parser.test | 8 +++++++ src/libvterm/t/run-test.pl | 2 +- src/version.c | 2 ++ 8 files changed, 47 insertions(+), 30 deletions(-) diff --git a/src/Makefile b/src/Makefile index ad8f241de7..9b50eca6d9 100644 --- a/src/Makefile +++ b/src/Makefile @@ -3562,7 +3562,7 @@ objects/vterm_screen.o: libvterm/src/screen.c $(TERM_DEPS) objects/vterm_state.o: libvterm/src/state.c $(TERM_DEPS) $(CCCTERM) -o $@ libvterm/src/state.c -objects/vterm_unicode.o: libvterm/src/unicode.c $(TERM_DEPS) +objects/vterm_unicode.o: libvterm/src/unicode.c $(TERM_DEPS) libvterm/src/fullwidth.inc $(CCCTERM) -o $@ libvterm/src/unicode.c objects/vterm_vterm.o: libvterm/src/vterm.c $(TERM_DEPS) diff --git a/src/libvterm/find-wide-chars.pl b/src/libvterm/find-wide-chars.pl index fc4a23444c..f7f22051bd 100644 --- a/src/libvterm/find-wide-chars.pl +++ b/src/libvterm/find-wide-chars.pl @@ -3,16 +3,12 @@ use strict; use warnings; -use Unicode::UCD qw( charprop ); - STDOUT->autoflush(1); sub iswide { my ( $cp ) = @_; - - my $width = charprop( $cp, "East_Asian_Width" ) or return; - return $width eq "Wide" || $width eq "Fullwidth"; + return chr($cp) =~ m/\p{East_Asian_Width=Wide}|\p{East_Asian_Width=Fullwidth}/; } my ( $start, $end ); diff --git a/src/libvterm/src/fullwidth.inc b/src/libvterm/src/fullwidth.inc index 7ff142f77c..a703529a76 100644 --- a/src/libvterm/src/fullwidth.inc +++ b/src/libvterm/src/fullwidth.inc @@ -40,14 +40,13 @@ { 0x3000, 0x303e }, { 0x3041, 0x3096 }, { 0x3099, 0x30ff }, - { 0x3105, 0x312d }, + { 0x3105, 0x312f }, { 0x3131, 0x318e }, { 0x3190, 0x31ba }, { 0x31c0, 0x31e3 }, { 0x31f0, 0x321e }, { 0x3220, 0x3247 }, - { 0x3250, 0x32fe }, - { 0x3300, 0x4dbf }, + { 0x3250, 0x4dbf }, { 0x4e00, 0xa48c }, { 0xa490, 0xa4c6 }, { 0xa960, 0xa97c }, @@ -59,10 +58,13 @@ { 0xfe68, 0xfe6b }, { 0xff01, 0xff60 }, { 0xffe0, 0xffe6 }, - { 0x16fe0, 0x16fe0 }, - { 0x17000, 0x187ec }, + { 0x16fe0, 0x16fe3 }, + { 0x17000, 0x187f7 }, { 0x18800, 0x18af2 }, - { 0x1b000, 0x1b001 }, + { 0x1b000, 0x1b11e }, + { 0x1b150, 0x1b152 }, + { 0x1b164, 0x1b167 }, + { 0x1b170, 0x1b2fb }, { 0x1f004, 0x1f004 }, { 0x1f0cf, 0x1f0cf }, { 0x1f18e, 0x1f18e }, @@ -71,6 +73,7 @@ { 0x1f210, 0x1f23b }, { 0x1f240, 0x1f248 }, { 0x1f250, 0x1f251 }, + { 0x1f260, 0x1f265 }, { 0x1f300, 0x1f320 }, { 0x1f32d, 0x1f335 }, { 0x1f337, 0x1f37c }, @@ -92,13 +95,17 @@ { 0x1f680, 0x1f6c5 }, { 0x1f6cc, 0x1f6cc }, { 0x1f6d0, 0x1f6d2 }, + { 0x1f6d5, 0x1f6d5 }, { 0x1f6eb, 0x1f6ec }, - { 0x1f6f4, 0x1f6f6 }, - { 0x1f910, 0x1f91e }, - { 0x1f920, 0x1f927 }, - { 0x1f930, 0x1f930 }, - { 0x1f933, 0x1f93e }, - { 0x1f940, 0x1f94b }, - { 0x1f950, 0x1f95e }, - { 0x1f980, 0x1f991 }, - { 0x1f9c0, 0x1f9c0 }, + { 0x1f6f4, 0x1f6fa }, + { 0x1f7e0, 0x1f7eb }, + { 0x1f90d, 0x1f971 }, + { 0x1f973, 0x1f976 }, + { 0x1f97a, 0x1f9a2 }, + { 0x1f9a5, 0x1f9aa }, + { 0x1f9ae, 0x1f9ca }, + { 0x1f9cd, 0x1f9ff }, + { 0x1fa70, 0x1fa73 }, + { 0x1fa78, 0x1fa7a }, + { 0x1fa80, 0x1fa82 }, + { 0x1fa90, 0x1fa95 }, diff --git a/src/libvterm/src/parser.c b/src/libvterm/src/parser.c index 520ec2cdc6..fef5bd3ad2 100644 --- a/src/libvterm/src/parser.c +++ b/src/libvterm/src/parser.c @@ -119,13 +119,15 @@ size_t vterm_input_write(VTerm *vt, const char *bytes, size_t len) #define ENTER_STATE(st) do { vt->parser.state = st; string_start = NULL; } while(0) #define ENTER_NORMAL_STATE() ENTER_STATE(NORMAL) +#define IS_STRING_STATE() (vt->parser.state >= OSC_COMMAND) + for( ; pos < len; pos++) { unsigned char c = bytes[pos]; int c1_allowed = !vt->mode.utf8; size_t string_len; if(c == 0x00 || c == 0x7f) { // NUL, DEL - if(vt->parser.state >= OSC) { + if(IS_STRING_STATE()) { string_fragment(vt, string_start, bytes + pos - string_start, FALSE); string_start = bytes + pos + 1; } @@ -138,13 +140,13 @@ size_t vterm_input_write(VTerm *vt, const char *bytes, size_t len) } else if(c == 0x1b) { // ESC vt->parser.intermedlen = 0; - if(vt->parser.state < OSC) + if(!IS_STRING_STATE()) vt->parser.state = NORMAL; vt->parser.in_esc = TRUE; continue; } else if(c == 0x07 && // BEL, can stand for ST in OSC or DCS state - vt->parser.state >= OSC) { + IS_STRING_STATE()) { // fallthrough } else if(c < 0x20) { // other C0 @@ -155,10 +157,10 @@ size_t vterm_input_write(VTerm *vt, const char *bytes, size_t len) if(pos + 2 < len && bytes[pos + 1] == 0x20 && bytes[pos + 2] == 0x08) vt->in_backspace = 2; // Trigger when count down to 1 } - if(vt->parser.state >= OSC) + if(IS_STRING_STATE()) string_fragment(vt, string_start, bytes + pos - string_start, FALSE); do_control(vt, c); - if(vt->parser.state >= OSC) + if(IS_STRING_STATE()) string_start = bytes + pos + 1; continue; } @@ -171,7 +173,7 @@ size_t vterm_input_write(VTerm *vt, const char *bytes, size_t len) // Always accept ESC \ == ST even in string mode if(!vt->parser.intermedlen && c >= 0x40 && c < 0x60 && - ((vt->parser.state < OSC || c == 0x5c))) { + ((!IS_STRING_STATE() || c == 0x5c))) { c += 0x40; c1_allowed = TRUE; string_len -= 1; @@ -260,6 +262,7 @@ size_t vterm_input_write(VTerm *vt, const char *bytes, size_t len) /* else fallthrough */ string_start = bytes + pos; + string_len = 0; vt->parser.state = OSC; goto string_state; @@ -312,6 +315,7 @@ string_state: case 0x9d: // OSC vt->parser.v.osc.command = -1; vt->parser.string_initial = TRUE; + string_start = bytes + pos + 1; ENTER_STATE(OSC_COMMAND); break; default: diff --git a/src/libvterm/src/vterm_internal.h b/src/libvterm/src/vterm_internal.h index 1cfe9383d3..a65e57675a 100644 --- a/src/libvterm/src/vterm_internal.h +++ b/src/libvterm/src/vterm_internal.h @@ -187,9 +187,9 @@ struct VTerm CSI_LEADER, CSI_ARGS, CSI_INTERMED, - OSC_COMMAND, DCS_COMMAND, - // below here are the "string states" + /* below here are the "string states" */ + OSC_COMMAND, OSC, DCS, } state; diff --git a/src/libvterm/t/02parser.test b/src/libvterm/t/02parser.test index 4a4a65bca0..0a21b927e6 100644 --- a/src/libvterm/t/02parser.test +++ b/src/libvterm/t/02parser.test @@ -150,6 +150,14 @@ PUSH "def" PUSH "ghi\e\\" osc "ghi"] +!OSC BEL without semicolon +PUSH "\e]1234\x07" + osc [1234 ] + +!OSC ST without semicolon +PUSH "\e]1234\e\\" + osc [1234 ] + !Escape cancels OSC, starts Escape PUSH "\e]Something\e9" escape "9" diff --git a/src/libvterm/t/run-test.pl b/src/libvterm/t/run-test.pl index 9f48c5cade..96f47fb868 100644 --- a/src/libvterm/t/run-test.pl +++ b/src/libvterm/t/run-test.pl @@ -112,7 +112,7 @@ sub do_line $initial //= ""; $initial .= ";" if $initial =~ m/\d+/; - $line = "$cmd $initial" . join( "", map sprintf("%02x", $_), unpack "C*", eval($data) ) . "$final"; + $line = "$cmd $initial" . join( "", map sprintf("%02x", $_), unpack "C*", length $data ? eval($data) : "" ) . "$final"; } elsif( $line =~ m/^(escape|dcs) (\[?)(.*?)(\]?)$/ ) { $line = "$1 $2" . join( "", map sprintf("%02x", $_), unpack "C*", eval($3) ) . "$4"; diff --git a/src/version.c b/src/version.c index ab899f3e49..31aa395876 100644 --- a/src/version.c +++ b/src/version.c @@ -746,6 +746,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 803, /**/ 802, /**/ From e5886ccb5163873dd01fc67b09ab10e681351ee9 Mon Sep 17 00:00:00 2001 From: Bram Moolenaar <Bram@vim.org> Date: Thu, 21 May 2020 20:10:04 +0200 Subject: [PATCH 203/230] patch 8.2.0804: libvterm code lags behind the upstream version Problem: Libvterm code lags behind the upstream version. Solution: Include revision 727, but add the index instead of switching between RGB and indexed. --- src/libvterm/include/vterm.h | 121 ++++++++++++++- src/libvterm/src/pen.c | 238 ++++++++++++++++++------------ src/libvterm/src/screen.c | 9 +- src/libvterm/src/state.c | 2 - src/libvterm/src/vterm_internal.h | 11 -- src/libvterm/t/26state_query.test | 8 +- src/libvterm/t/30state_pen.test | 32 ++-- src/libvterm/t/64screen_pen.test | 16 +- src/libvterm/t/harness.c | 39 ++++- src/term.c | 14 +- src/terminal.c | 107 ++++++++++---- src/version.c | 2 + 12 files changed, 408 insertions(+), 191 deletions(-) diff --git a/src/libvterm/include/vterm.h b/src/libvterm/include/vterm.h index b6491f1f70..3a174041ab 100644 --- a/src/libvterm/include/vterm.h +++ b/src/libvterm/include/vterm.h @@ -85,18 +85,107 @@ INLINE void vterm_rect_move(VTermRect *rect, int row_delta, int col_delta) } #endif -// The ansi_index is used for the lower 16 colors, which can be set to any -// color. -#define VTERM_ANSI_INDEX_DEFAULT 0 // color cleared -#define VTERM_ANSI_INDEX_MIN 1 -#define VTERM_ANSI_INDEX_MAX 16 -#define VTERM_ANSI_INDEX_NONE 255 // non-ANSI color, use red/green/blue +/** + * Bit-field describing the value of VTermColor.type + */ +typedef enum { + /** + * If the lower bit of `type` is not set, the colour is 24-bit RGB. + */ + VTERM_COLOR_RGB = 0x00, + + /** + * The colour is an index into a palette of 256 colours. + */ + VTERM_COLOR_INDEXED = 0x01, + + /** + * Mask that can be used to extract the RGB/Indexed bit. + */ + VTERM_COLOR_TYPE_MASK = 0x01, + + /** + * If set, indicates that this colour should be the default foreground + * color, i.e. there was no SGR request for another colour. When + * rendering this colour it is possible to ignore "idx" and just use a + * colour that is not in the palette. + */ + VTERM_COLOR_DEFAULT_FG = 0x02, + + /** + * If set, indicates that this colour should be the default background + * color, i.e. there was no SGR request for another colour. A common + * option when rendering this colour is to not render a background at + * all, for example by rendering the window transparently at this spot. + */ + VTERM_COLOR_DEFAULT_BG = 0x04, + + /** + * Mask that can be used to extract the default foreground/background bit. + */ + VTERM_COLOR_DEFAULT_MASK = 0x06 +} VTermColorType; + +/** + * Returns true if the VTERM_COLOR_RGB `type` flag is set, indicating that the + * given VTermColor instance is an indexed colour. + */ +#define VTERM_COLOR_IS_INDEXED(col) \ + (((col)->type & VTERM_COLOR_TYPE_MASK) == VTERM_COLOR_INDEXED) + +/** + * Returns true if the VTERM_COLOR_INDEXED `type` flag is set, indicating that + * the given VTermColor instance is an rgb colour. + */ +#define VTERM_COLOR_IS_RGB(col) \ + (((col)->type & VTERM_COLOR_TYPE_MASK) == VTERM_COLOR_RGB) + +/** + * Returns true if the VTERM_COLOR_DEFAULT_FG `type` flag is set, indicating + * that the given VTermColor instance corresponds to the default foreground + * color. + */ +#define VTERM_COLOR_IS_DEFAULT_FG(col) \ + (!!((col)->type & VTERM_COLOR_DEFAULT_FG)) + +/** + * Returns true if the VTERM_COLOR_DEFAULT_BG `type` flag is set, indicating + * that the given VTermColor instance corresponds to the default background + * color. + */ +#define VTERM_COLOR_IS_DEFAULT_BG(col) \ + (!!((col)->type & VTERM_COLOR_DEFAULT_BG)) typedef struct { + /** + * Tag indicating which member is actually valid. + * Please use the `VTERM_COLOR_IS_*` test macros to check whether a + * particular type flag is set. + */ + uint8_t type; + uint8_t red, green, blue; - uint8_t ansi_index; + + uint8_t index; } VTermColor; +/** + * Constructs a new VTermColor instance representing the given RGB values. + */ +void vterm_color_rgb(VTermColor *col, uint8_t red, uint8_t green, uint8_t blue); + +/** + * Construct a new VTermColor instance representing an indexed color with the + * given index. + */ +void vterm_color_indexed(VTermColor *col, uint8_t idx); + +/** + * Compares two colours. Returns true if the colors are equal, false otherwise. + */ +int vterm_color_is_equal(const VTermColor *a, const VTermColor *b); + + typedef enum { // VTERM_VALUETYPE_NONE = 0 VTERM_VALUETYPE_BOOL = 1, @@ -346,6 +435,18 @@ void vterm_state_focus_in(VTermState *state); void vterm_state_focus_out(VTermState *state); const VTermLineInfo *vterm_state_get_lineinfo(const VTermState *state, int row); +/** + * Makes sure that the given color `col` is indeed an RGB colour. After this + * function returns, VTERM_COLOR_IS_RGB(col) will return true, while all other + * flags stored in `col->type` will have been reset. + * + * @param state is the VTermState instance from which the colour palette should + * be extracted. + * @param col is a pointer at the VTermColor instance that should be converted + * to an RGB colour. + */ +void vterm_state_convert_color_to_rgb(const VTermState *state, VTermColor *col); + // ------------ // Screen layer // ------------ @@ -456,6 +557,12 @@ int vterm_screen_get_cell(const VTermScreen *screen, VTermPos pos, VTermScreenCe int vterm_screen_is_eol(const VTermScreen *screen, VTermPos pos); +/** + * Same as vterm_state_convert_color_to_rgb(), but takes a `screen` instead of a `state` + * instance. + */ +void vterm_screen_convert_color_to_rgb(const VTermScreen *screen, VTermColor *col); + // --------- // Utilities // --------- diff --git a/src/libvterm/src/pen.c b/src/libvterm/src/pen.c index 831d1803f4..98c5af9269 100644 --- a/src/libvterm/src/pen.c +++ b/src/libvterm/src/pen.c @@ -2,26 +2,34 @@ #include <stdio.h> -static const VTermColor ansi_colors[] = { - // R G B index - { 0, 0, 0, 1 }, // black - { 224, 0, 0, 2 }, // red - { 0, 224, 0, 3 }, // green - { 224, 224, 0, 4 }, // yellow - { 0, 0, 224, 5 }, // blue - { 224, 0, 224, 6 }, // magenta - { 0, 224, 224, 7 }, // cyan - { 224, 224, 224, 8 }, // white == light grey +/** + * Structure used to store RGB triples without the additional metadata stored in + * VTermColor. + */ +typedef struct { + uint8_t red, green, blue; +} VTermRGB; + +static const VTermRGB ansi_colors[] = { + // R G B + { 0, 0, 0 }, // black + { 224, 0, 0 }, // red + { 0, 224, 0 }, // green + { 224, 224, 0 }, // yellow + { 0, 0, 224 }, // blue + { 224, 0, 224 }, // magenta + { 0, 224, 224 }, // cyan + { 224, 224, 224 }, // white == light grey // high intensity - { 128, 128, 128, 9 }, // black - { 255, 64, 64, 10 }, // red - { 64, 255, 64, 11 }, // green - { 255, 255, 64, 12 }, // yellow - { 64, 64, 255, 13 }, // blue - { 255, 64, 255, 14 }, // magenta - { 64, 255, 255, 15 }, // cyan - { 255, 255, 255, 16 }, // white for real + { 128, 128, 128 }, // black + { 255, 64, 64 }, // red + { 64, 255, 64 }, // green + { 255, 255, 64 }, // yellow + { 64, 64, 255 }, // blue + { 255, 64, 255 }, // magenta + { 64, 255, 255 }, // cyan + { 255, 255, 255 }, // white for real }; static int ramp6[] = { @@ -34,6 +42,15 @@ static int ramp24[] = { 0x81, 0x8A, 0x94, 0x9E, 0xA8, 0xB2, 0xBC, 0xC6, 0xD0, 0xDA, 0xE4, 0xEE, }; +static void lookup_default_colour_ansi(long idx, VTermColor *col) +{ + vterm_color_rgb( + col, + ansi_colors[idx].red, ansi_colors[idx].green, ansi_colors[idx].blue); + col->index = idx; + col->type = VTERM_COLOR_INDEXED; +} + static int lookup_colour_ansi(const VTermState *state, long index, VTermColor *col) { if(index >= 0 && index < 16) { @@ -54,10 +71,9 @@ static int lookup_colour_palette(const VTermState *state, long index, VTermColor // 216-colour cube index -= 16; - col->blue = ramp6[index % 6]; - col->green = ramp6[index/6 % 6]; - col->red = ramp6[index/6/6 % 6]; - col->ansi_index = VTERM_ANSI_INDEX_NONE; + vterm_color_rgb(col, ramp6[index/6/6 % 6], + ramp6[index/6 % 6], + ramp6[index % 6]); return TRUE; } @@ -65,10 +81,7 @@ static int lookup_colour_palette(const VTermState *state, long index, VTermColor // 24 greyscales index -= 232; - col->blue = ramp24[index]; - col->green = ramp24[index]; - col->red = ramp24[index]; - col->ansi_index = VTERM_ANSI_INDEX_NONE; + vterm_color_rgb(col, ramp24[index], ramp24[index], ramp24[index]); return TRUE; } @@ -76,25 +89,23 @@ static int lookup_colour_palette(const VTermState *state, long index, VTermColor return FALSE; } -static int lookup_colour(const VTermState *state, int palette, const long args[], int argcount, VTermColor *col, int *index) +static int lookup_colour(const VTermState *state, int palette, const long args[], int argcount, VTermColor *col) { switch(palette) { case 2: // RGB mode - 3 args contain colour values directly if(argcount < 3) return argcount; - col->red = (uint8_t)CSI_ARG(args[0]); - col->green = (uint8_t)CSI_ARG(args[1]); - col->blue = (uint8_t)CSI_ARG(args[2]); - col->ansi_index = VTERM_ANSI_INDEX_NONE; + vterm_color_rgb(col, CSI_ARG(args[0]), CSI_ARG(args[1]), CSI_ARG(args[2])); return 3; case 5: // XTerm 256-colour mode - if(index) - *index = CSI_ARG_OR(args[0], -1); + if (!argcount || CSI_ARG_IS_MISSING(args[0])) { + return argcount ? 1 : 0; + } - lookup_colour_palette(state, argcount ? CSI_ARG_OR(args[0], -1) : -1, col); + lookup_colour_palette(state, args[0], col); return argcount ? 1 : 0; @@ -154,13 +165,12 @@ INTERNAL void vterm_state_newpen(VTermState *state) int col; // 90% grey so that pure white is brighter - state->default_fg.red = state->default_fg.green = state->default_fg.blue = 240; - state->default_fg.ansi_index = VTERM_ANSI_INDEX_DEFAULT; - state->default_bg.red = state->default_bg.green = state->default_bg.blue = 0; - state->default_bg.ansi_index = VTERM_ANSI_INDEX_DEFAULT; + vterm_color_rgb(&state->default_fg, 240, 240, 240); + vterm_color_rgb(&state->default_bg, 0, 0, 0); + vterm_state_set_default_colors(state, &state->default_fg, &state->default_bg); for(col = 0; col < 16; col++) - state->colors[col] = ansi_colors[col]; + lookup_default_colour_ansi(col, &state->colors[col]); } INTERNAL void vterm_state_resetpen(VTermState *state) @@ -174,8 +184,6 @@ INTERNAL void vterm_state_resetpen(VTermState *state) state->pen.strike = 0; setpenattr_bool(state, VTERM_ATTR_STRIKE, 0); state->pen.font = 0; setpenattr_int( state, VTERM_ATTR_FONT, 0); - state->fg_index = -1; - state->bg_index = -1; state->pen.fg = state->default_fg; setpenattr_col(state, VTERM_ATTR_FOREGROUND, state->default_fg); state->pen.bg = state->default_bg; setpenattr_col(state, VTERM_ATTR_BACKGROUND, state->default_bg); } @@ -201,6 +209,40 @@ INTERNAL void vterm_state_savepen(VTermState *state, int save) } } +void vterm_color_rgb(VTermColor *col, uint8_t red, uint8_t green, uint8_t blue) +{ + col->type = VTERM_COLOR_RGB; + col->red = red; + col->green = green; + col->blue = blue; +} + +void vterm_color_indexed(VTermColor *col, uint8_t idx) +{ + col->type = VTERM_COLOR_INDEXED; + col->index = idx; +} + +int vterm_color_is_equal(const VTermColor *a, const VTermColor *b) +{ + /* First make sure that the two colours are of the same type (RGB/Indexed) */ + if (a->type != b->type) { + return FALSE; + } + + /* Depending on the type inspect the corresponding members */ + if (VTERM_COLOR_IS_INDEXED(a)) { + return a->index == b->index; + } + else if (VTERM_COLOR_IS_RGB(a)) { + return (a->red == b->red) + && (a->green == b->green) + && (a->blue == b->blue); + } + + return 0; +} + void vterm_state_get_default_colors(const VTermState *state, VTermColor *default_fg, VTermColor *default_bg) { *default_fg = state->default_fg; @@ -214,8 +256,15 @@ void vterm_state_get_palette_color(const VTermState *state, int index, VTermColo void vterm_state_set_default_colors(VTermState *state, const VTermColor *default_fg, const VTermColor *default_bg) { + /* Copy the given colors */ state->default_fg = *default_fg; state->default_bg = *default_bg; + + /* Make sure the correct type flags are set */ + state->default_fg.type = (state->default_fg.type & ~VTERM_COLOR_DEFAULT_MASK) + | VTERM_COLOR_DEFAULT_FG; + state->default_bg.type = (state->default_bg.type & ~VTERM_COLOR_DEFAULT_MASK) + | VTERM_COLOR_DEFAULT_BG; } void vterm_state_set_palette_color(VTermState *state, int index, const VTermColor *col) @@ -223,10 +272,18 @@ void vterm_state_set_palette_color(VTermState *state, int index, const VTermColo if(index >= 0 && index < 16) { state->colors[index] = *col; - state->colors[index].ansi_index = index + VTERM_ANSI_INDEX_MIN; + state->colors[index].index = index + 1; } } +void vterm_state_convert_color_to_rgb(const VTermState *state, VTermColor *col) +{ + if (VTERM_COLOR_IS_INDEXED(col)) { /* Convert indexed colors to RGB */ + lookup_colour_palette(state, col->index, col); + } + col->type &= VTERM_COLOR_TYPE_MASK; /* Reset any metadata but the type */ +} + void vterm_state_set_bold_highbright(VTermState *state, int bold_is_highbright) { state->bold_is_highbright = bold_is_highbright; @@ -251,12 +308,14 @@ INTERNAL void vterm_state_setpen(VTermState *state, const long args[], int argco vterm_state_resetpen(state); break; - case 1: // Bold on + case 1: { // Bold on + const VTermColor *fg = &state->pen.fg; state->pen.bold = 1; setpenattr_bool(state, VTERM_ATTR_BOLD, 1); - if(state->fg_index > -1 && state->fg_index < 8 && state->bold_is_highbright) - set_pen_col_ansi(state, VTERM_ATTR_FOREGROUND, state->fg_index + (state->pen.bold ? 8 : 0)); + if(!VTERM_COLOR_IS_DEFAULT_FG(fg) && VTERM_COLOR_IS_INDEXED(fg) && fg->index < 8 && state->bold_is_highbright) + set_pen_col_ansi(state, VTERM_ATTR_FOREGROUND, fg->index + (state->pen.bold ? 8 : 0)); break; + } case 3: // Italic on state->pen.italic = 1; @@ -354,22 +413,19 @@ INTERNAL void vterm_state_setpen(VTermState *state, const long args[], int argco case 30: case 31: case 32: case 33: case 34: case 35: case 36: case 37: // Foreground colour palette value = CSI_ARG(args[argi]) - 30; - state->fg_index = value; if(state->pen.bold && state->bold_is_highbright) value += 8; set_pen_col_ansi(state, VTERM_ATTR_FOREGROUND, value); break; case 38: // Foreground colour alternative palette - state->fg_index = -1; if(argcount - argi < 1) return; - argi += 1 + lookup_colour(state, CSI_ARG(args[argi+1]), args+argi+2, argcount-argi-2, &state->pen.fg, &state->fg_index); + argi += 1 + lookup_colour(state, CSI_ARG(args[argi+1]), args+argi+2, argcount-argi-2, &state->pen.fg); setpenattr_col(state, VTERM_ATTR_FOREGROUND, state->pen.fg); break; case 39: // Foreground colour default - state->fg_index = -1; state->pen.fg = state->default_fg; setpenattr_col(state, VTERM_ATTR_FOREGROUND, state->pen.fg); break; @@ -377,20 +433,17 @@ INTERNAL void vterm_state_setpen(VTermState *state, const long args[], int argco case 40: case 41: case 42: case 43: case 44: case 45: case 46: case 47: // Background colour palette value = CSI_ARG(args[argi]) - 40; - state->bg_index = value; set_pen_col_ansi(state, VTERM_ATTR_BACKGROUND, value); break; case 48: // Background colour alternative palette - state->bg_index = -1; if(argcount - argi < 1) return; - argi += 1 + lookup_colour(state, CSI_ARG(args[argi+1]), args+argi+2, argcount-argi-2, &state->pen.bg, &state->bg_index); + argi += 1 + lookup_colour(state, CSI_ARG(args[argi+1]), args+argi+2, argcount-argi-2, &state->pen.bg); setpenattr_col(state, VTERM_ATTR_BACKGROUND, state->pen.bg); break; case 49: // Default background - state->bg_index = -1; state->pen.bg = state->default_bg; setpenattr_col(state, VTERM_ATTR_BACKGROUND, state->pen.bg); break; @@ -398,14 +451,12 @@ INTERNAL void vterm_state_setpen(VTermState *state, const long args[], int argco case 90: case 91: case 92: case 93: case 94: case 95: case 96: case 97: // Foreground colour high-intensity palette value = CSI_ARG(args[argi]) - 90 + 8; - state->fg_index = value; set_pen_col_ansi(state, VTERM_ATTR_FOREGROUND, value); break; case 100: case 101: case 102: case 103: case 104: case 105: case 106: case 107: // Background colour high-intensity palette value = CSI_ARG(args[argi]) - 100 + 8; - state->bg_index = value; set_pen_col_ansi(state, VTERM_ATTR_BACKGROUND, value); break; @@ -424,6 +475,39 @@ INTERNAL void vterm_state_setpen(VTermState *state, const long args[], int argco } } +static int vterm_state_getpen_color(const VTermColor *col, int argi, long args[], int fg) +{ + /* Do nothing if the given color is the default color */ + if (( fg && VTERM_COLOR_IS_DEFAULT_FG(col)) || + (!fg && VTERM_COLOR_IS_DEFAULT_BG(col))) { + return argi; + } + + /* Decide whether to send an indexed color or an RGB color */ + if (VTERM_COLOR_IS_INDEXED(col)) { + const uint8_t idx = col->index; + if (idx < 8) { + args[argi++] = (idx + (fg ? 30 : 40)); + } + else if (idx < 16) { + args[argi++] = (idx - 8 + (fg ? 90 : 100)); + } + else { + args[argi++] = CSI_ARG_FLAG_MORE | (fg ? 38 : 48); + args[argi++] = CSI_ARG_FLAG_MORE | 5; + args[argi++] = idx; + } + } + else if (VTERM_COLOR_IS_RGB(col)) { + args[argi++] = CSI_ARG_FLAG_MORE | (fg ? 38 : 48); + args[argi++] = CSI_ARG_FLAG_MORE | 2; + args[argi++] = CSI_ARG_FLAG_MORE | col->red; + args[argi++] = CSI_ARG_FLAG_MORE | col->green; + args[argi++] = col->blue; + } + return argi; +} + INTERNAL int vterm_state_getpen(VTermState *state, long args[], int argcount UNUSED) { int argi = 0; @@ -457,49 +541,9 @@ INTERNAL int vterm_state_getpen(VTermState *state, long args[], int argcount UNU if(state->pen.underline == VTERM_UNDERLINE_DOUBLE) args[argi++] = 21; - if(state->fg_index >= 0 && state->fg_index < 8) - args[argi++] = 30 + state->fg_index; - else if(state->fg_index >= 8 && state->fg_index < 16) - args[argi++] = 90 + state->fg_index - 8; - else if(state->fg_index >= 16 && state->fg_index < 256) { - args[argi++] = CSI_ARG_FLAG_MORE|38; - args[argi++] = CSI_ARG_FLAG_MORE|5; - args[argi++] = state->fg_index; - } - else if(state->fg_index == -1) { - // Send palette 2 if the actual FG colour is not default - if(state->pen.fg.red != state->default_fg.red || - state->pen.fg.green != state->default_fg.green || - state->pen.fg.blue != state->default_fg.blue ) { - args[argi++] = CSI_ARG_FLAG_MORE|38; - args[argi++] = CSI_ARG_FLAG_MORE|2; - args[argi++] = CSI_ARG_FLAG_MORE | state->pen.fg.red; - args[argi++] = CSI_ARG_FLAG_MORE | state->pen.fg.green; - args[argi++] = state->pen.fg.blue; - } - } + argi = vterm_state_getpen_color(&state->pen.fg, argi, args, TRUE); - if(state->bg_index >= 0 && state->bg_index < 8) - args[argi++] = 40 + state->bg_index; - else if(state->bg_index >= 8 && state->bg_index < 16) - args[argi++] = 100 + state->bg_index - 8; - else if(state->bg_index >= 16 && state->bg_index < 256) { - args[argi++] = CSI_ARG_FLAG_MORE|48; - args[argi++] = CSI_ARG_FLAG_MORE|5; - args[argi++] = state->bg_index; - } - else if(state->bg_index == -1) { - // Send palette 2 if the actual BG colour is not default - if(state->pen.bg.red != state->default_bg.red || - state->pen.bg.green != state->default_bg.green || - state->pen.bg.blue != state->default_bg.blue ) { - args[argi++] = CSI_ARG_FLAG_MORE|48; - args[argi++] = CSI_ARG_FLAG_MORE|2; - args[argi++] = CSI_ARG_FLAG_MORE | state->pen.bg.red; - args[argi++] = CSI_ARG_FLAG_MORE | state->pen.bg.green; - args[argi++] = state->pen.bg.blue; - } - } + argi = vterm_state_getpen_color(&state->pen.bg, argi, args, FALSE); return argi; } diff --git a/src/libvterm/src/screen.c b/src/libvterm/src/screen.c index 1e2439c497..ea551f9f4b 100644 --- a/src/libvterm/src/screen.c +++ b/src/libvterm/src/screen.c @@ -949,9 +949,9 @@ static int attrs_differ(VTermAttrMask attrs, ScreenCell *a, ScreenCell *b) return 1; if((attrs & VTERM_ATTR_FONT_MASK) && (a->pen.font != b->pen.font)) return 1; - if((attrs & VTERM_ATTR_FOREGROUND_MASK) && !vterm_color_equal(a->pen.fg, b->pen.fg)) + if((attrs & VTERM_ATTR_FOREGROUND_MASK) && !vterm_color_is_equal(&a->pen.fg, &b->pen.fg)) return 1; - if((attrs & VTERM_ATTR_BACKGROUND_MASK) && !vterm_color_equal(a->pen.bg, b->pen.bg)) + if((attrs & VTERM_ATTR_BACKGROUND_MASK) && !vterm_color_is_equal(&a->pen.bg, &b->pen.bg)) return 1; return 0; @@ -984,3 +984,8 @@ int vterm_screen_get_attrs_extent(const VTermScreen *screen, VTermRect *extent, return 1; } + +void vterm_screen_convert_color_to_rgb(const VTermScreen *screen, VTermColor *col) +{ + vterm_state_convert_color_to_rgb(screen->state, col); +} diff --git a/src/libvterm/src/state.c b/src/libvterm/src/state.c index 15579d2c4c..1fff43ce3f 100644 --- a/src/libvterm/src/state.c +++ b/src/libvterm/src/state.c @@ -1680,8 +1680,6 @@ static void request_status_string(VTermState *state, VTermStringFragment frag) if(!frag.final) return; - fprintf(stderr, "DECRQSS on <%s>\n", tmp); - switch(tmp[0] | tmp[1]<<8 | tmp[2]<<16) { case 'm': { // Query SGR diff --git a/src/libvterm/src/vterm_internal.h b/src/libvterm/src/vterm_internal.h index a65e57675a..942315d6ec 100644 --- a/src/libvterm/src/vterm_internal.h +++ b/src/libvterm/src/vterm_internal.h @@ -58,15 +58,6 @@ struct VTermPen unsigned int font:4; // To store 0-9 }; -int vterm_color_equal(VTermColor a, VTermColor b); - -#if defined(DEFINE_INLINES) || USE_INLINE -INLINE int vterm_color_equal(VTermColor a, VTermColor b) -{ - return a.red == b.red && a.green == b.green && a.blue == b.blue; -} -#endif - struct VTermState { VTerm *vt; @@ -144,8 +135,6 @@ struct VTermState VTermColor default_bg; VTermColor colors[16]; // Store the 8 ANSI and the 8 ANSI high-brights only - int fg_index; - int bg_index; int bold_is_highbright; unsigned int protected_cell : 1; diff --git a/src/libvterm/t/26state_query.test b/src/libvterm/t/26state_query.test index c6be90b619..c543b92456 100644 --- a/src/libvterm/t/26state_query.test +++ b/src/libvterm/t/26state_query.test @@ -41,10 +41,10 @@ PUSH "\e[0;93;104m" PUSH "\eP\$qm\e\\" output "\eP1\$r93;104m\e\\" -!DECRQSS on SGR 256-palette colours -PUSH "\e[0;38:5:56;48:5:78m" -PUSH "\eP\$qm\e\\" - output "\eP1\$r38:5:56;48:5:78m\e\\" +##!DECRQSS on SGR 256-palette colours +#PUSH "\e[0;38:5:56;48:5:78m" +#PUSH "\eP\$qm\e\\" +# output "\eP1\$r38:5:56;48:5:78m\e\\" !DECRQSS on SGR RGB8 colours PUSH "\e[0;38:2:24:68:112;48:2:13:57:101m" diff --git a/src/libvterm/t/30state_pen.test b/src/libvterm/t/30state_pen.test index d1e0d14700..915baec7cd 100644 --- a/src/libvterm/t/30state_pen.test +++ b/src/libvterm/t/30state_pen.test @@ -10,8 +10,8 @@ PUSH "\e[m" ?pen blink = off ?pen reverse = off ?pen font = 0 - ?pen foreground = rgb(240,240,240) - ?pen background = rgb(0,0,0) + ?pen foreground = rgb(240,240,240,is_default_fg) + ?pen background = rgb(0,0,0,is_default_bg) !Bold PUSH "\e[1m" @@ -75,40 +75,40 @@ PUSH "\e[11m\e[m" !Foreground PUSH "\e[31m" - ?pen foreground = rgb(224,0,0) + ?pen foreground = idx(1) PUSH "\e[32m" - ?pen foreground = rgb(0,224,0) + ?pen foreground = idx(2) PUSH "\e[34m" - ?pen foreground = rgb(0,0,224) + ?pen foreground = idx(4) PUSH "\e[91m" - ?pen foreground = rgb(255,64,64) + ?pen foreground = idx(9) PUSH "\e[38:2:10:20:30m" ?pen foreground = rgb(10,20,30) PUSH "\e[38:5:1m" - ?pen foreground = rgb(224,0,0) + ?pen foreground = idx(1) PUSH "\e[39m" - ?pen foreground = rgb(240,240,240) + ?pen foreground = rgb(240,240,240,is_default_fg) !Background PUSH "\e[41m" - ?pen background = rgb(224,0,0) + ?pen background = idx(1) PUSH "\e[42m" - ?pen background = rgb(0,224,0) + ?pen background = idx(2) PUSH "\e[44m" - ?pen background = rgb(0,0,224) + ?pen background = idx(4) PUSH "\e[101m" - ?pen background = rgb(255,64,64) + ?pen background = idx(9) PUSH "\e[48:2:10:20:30m" ?pen background = rgb(10,20,30) PUSH "\e[48:5:1m" - ?pen background = rgb(224,0,0) + ?pen background = idx(1) PUSH "\e[49m" - ?pen background = rgb(0,0,0) + ?pen background = rgb(0,0,0,is_default_bg) !Bold+ANSI colour == highbright PUSH "\e[m\e[1;37m" ?pen bold = on - ?pen foreground = rgb(255,255,255) + ?pen foreground = idx(15) PUSH "\e[m\e[37;1m" ?pen bold = on - ?pen foreground = rgb(255,255,255) + ?pen foreground = idx(15) diff --git a/src/libvterm/t/64screen_pen.test b/src/libvterm/t/64screen_pen.test index f1ee639ac7..3a7814087e 100644 --- a/src/libvterm/t/64screen_pen.test +++ b/src/libvterm/t/64screen_pen.test @@ -29,27 +29,27 @@ PUSH "\e[11mF\e[m" !Foreground PUSH "\e[31mG\e[m" - ?screen_cell 0,6 = {0x47} width=1 attrs={} fg=rgb(224,0,0) bg=rgb(0,0,0) + ?screen_cell 0,6 = {0x47} width=1 attrs={} fg=idx(1) bg=rgb(0,0,0) !Background PUSH "\e[42mH\e[m" - ?screen_cell 0,7 = {0x48} width=1 attrs={} fg=rgb(240,240,240) bg=rgb(0,224,0) + ?screen_cell 0,7 = {0x48} width=1 attrs={} fg=rgb(240,240,240) bg=idx(2) !EL sets reverse and colours to end of line PUSH "\e[H\e[7;33;44m\e[K" - ?screen_cell 0,0 = {} width=1 attrs={R} fg=rgb(224,224,0) bg=rgb(0,0,224) - ?screen_cell 0,79 = {} width=1 attrs={R} fg=rgb(224,224,0) bg=rgb(0,0,224) + ?screen_cell 0,0 = {} width=1 attrs={R} fg=idx(3) bg=idx(4) + ?screen_cell 0,79 = {} width=1 attrs={R} fg=idx(3) bg=idx(4) !DECSCNM xors reverse for entire screen PUSH "\e[?5h" - ?screen_cell 0,0 = {} width=1 attrs={} fg=rgb(224,224,0) bg=rgb(0,0,224) - ?screen_cell 0,79 = {} width=1 attrs={} fg=rgb(224,224,0) bg=rgb(0,0,224) + ?screen_cell 0,0 = {} width=1 attrs={} fg=idx(3) bg=idx(4) + ?screen_cell 0,79 = {} width=1 attrs={} fg=idx(3) bg=idx(4) ?screen_cell 1,0 = {} width=1 attrs={R} fg=rgb(240,240,240) bg=rgb(0,0,0) PUSH "\e[?5\$p" output "\e[?5;1\$y" PUSH "\e[?5l" - ?screen_cell 0,0 = {} width=1 attrs={R} fg=rgb(224,224,0) bg=rgb(0,0,224) - ?screen_cell 0,79 = {} width=1 attrs={R} fg=rgb(224,224,0) bg=rgb(0,0,224) + ?screen_cell 0,0 = {} width=1 attrs={R} fg=idx(3) bg=idx(4) + ?screen_cell 0,79 = {} width=1 attrs={R} fg=idx(3) bg=idx(4) ?screen_cell 1,0 = {} width=1 attrs={} fg=rgb(240,240,240) bg=rgb(0,0,0) PUSH "\e[?5\$p" output "\e[?5;2\$y" diff --git a/src/libvterm/t/harness.c b/src/libvterm/t/harness.c index fd129b715e..10afbfd768 100644 --- a/src/libvterm/t/harness.c +++ b/src/libvterm/t/harness.c @@ -60,6 +60,26 @@ static VTermKey strp_key(char *str) return VTERM_KEY_NONE; } +static void print_color(const VTermColor *col) +{ + if (VTERM_COLOR_IS_RGB(col)) { + printf("rgb(%d,%d,%d", col->red, col->green, col->blue); + } + else if (VTERM_COLOR_IS_INDEXED(col)) { + printf("idx(%d", col->index); + } + else { + printf("invalid(%d", col->type); + } + if (VTERM_COLOR_IS_DEFAULT_FG(col)) { + printf(",is_default_fg"); + } + if (VTERM_COLOR_IS_DEFAULT_BG(col)) { + printf(",is_default_bg"); + } + printf(")"); +} + static VTerm *vt; static VTermState *state; static VTermScreen *screen; @@ -273,7 +293,9 @@ static int settermprop(VTermProp prop, VTermValue *val, void *user UNUSED) val->string.initial ? "[" : "", val->string.len, val->string.str, val->string.final ? "]" : ""); return 1; case VTERM_VALUETYPE_COLOR: - printf("settermprop %d rgb(%d,%d,%d)\n", prop, val->color.red, val->color.green, val->color.blue); + printf("settermprop %d ", prop); + print_color(&val->color); + printf("\n"); return 1; case VTERM_N_VALUETYPES: @@ -834,10 +856,12 @@ int main(int argc UNUSED, char **argv UNUSED) printf("%d\n", state_pen.font); } else if(streq(linep, "foreground")) { - printf("rgb(%d,%d,%d)\n", state_pen.foreground.red, state_pen.foreground.green, state_pen.foreground.blue); + print_color(&state_pen.foreground); + printf("\n"); } else if(streq(linep, "background")) { - printf("rgb(%d,%d,%d)\n", state_pen.background.red, state_pen.background.green, state_pen.background.blue); + print_color(&state_pen.background); + printf("\n"); } else printf("?\n"); @@ -952,8 +976,13 @@ int main(int argc UNUSED, char **argv UNUSED) printf("} "); if(cell.attrs.dwl) printf("dwl "); if(cell.attrs.dhl) printf("dhl-%s ", cell.attrs.dhl == 2 ? "bottom" : "top"); - printf("fg=rgb(%d,%d,%d) ", cell.fg.red, cell.fg.green, cell.fg.blue); - printf("bg=rgb(%d,%d,%d)\n", cell.bg.red, cell.bg.green, cell.bg.blue); + printf("fg="); + vterm_screen_convert_color_to_rgb(screen, &cell.fg); + print_color(&cell.fg); + printf(" bg="); + vterm_screen_convert_color_to_rgb(screen, &cell.bg); + print_color(&cell.bg); + printf("\n"); } else if(strstartswith(line, "?screen_eol ")) { VTermPos pos; diff --git a/src/term.c b/src/term.c index 11972a15b0..e79fa5eb2a 100644 --- a/src/term.c +++ b/src/term.c @@ -6357,12 +6357,6 @@ static int grey_ramp[] = { 0x80, 0x8A, 0x94, 0x9E, 0xA8, 0xB2, 0xBC, 0xC6, 0xD0, 0xDA, 0xE4, 0xEE }; -# ifdef FEAT_TERMINAL -# include "libvterm/include/vterm.h" // for VTERM_ANSI_INDEX_NONE -# else -# define VTERM_ANSI_INDEX_NONE 0 -# endif - static char_u ansi_table[16][4] = { // R G B idx { 0, 0, 0, 1}, // black @@ -6384,6 +6378,8 @@ static char_u ansi_table[16][4] = { {255, 255, 255, 16}, // white }; +#define ANSI_INDEX_NONE 0 + void cterm_color2rgb(int nr, char_u *r, char_u *g, char_u *b, char_u *ansi_idx) { @@ -6403,7 +6399,7 @@ cterm_color2rgb(int nr, char_u *r, char_u *g, char_u *b, char_u *ansi_idx) *r = cube_value[idx / 36 % 6]; *g = cube_value[idx / 6 % 6]; *b = cube_value[idx % 6]; - *ansi_idx = VTERM_ANSI_INDEX_NONE; + *ansi_idx = ANSI_INDEX_NONE; } else if (nr < 256) { @@ -6412,14 +6408,14 @@ cterm_color2rgb(int nr, char_u *r, char_u *g, char_u *b, char_u *ansi_idx) *r = grey_ramp[idx]; *g = grey_ramp[idx]; *b = grey_ramp[idx]; - *ansi_idx = VTERM_ANSI_INDEX_NONE; + *ansi_idx = ANSI_INDEX_NONE; } else { *r = 0; *g = 0; *b = 0; - *ansi_idx = 0; + *ansi_idx = ANSI_INDEX_NONE; } } #endif diff --git a/src/terminal.c b/src/terminal.c index c41b2f1006..3fcd659fca 100644 --- a/src/terminal.c +++ b/src/terminal.c @@ -1626,7 +1626,8 @@ cell2cellattr(const VTermScreenCell *cell, cellattr_T *attr) static int equal_celattr(cellattr_T *a, cellattr_T *b) { - // Comparing the colors should be sufficient. + // We only compare the RGB colors, ignoring the ANSI index and type. + // Thus black set explicitly is equal the background black. return a->fg.red == b->fg.red && a->fg.green == b->fg.green && a->fg.blue == b->fg.blue @@ -2692,10 +2693,13 @@ color2index(VTermColor *color, int fg, int *boldp) int blue = color->blue; int green = color->green; - if (color->ansi_index != VTERM_ANSI_INDEX_NONE) + if (VTERM_COLOR_IS_DEFAULT_FG(color) + || VTERM_COLOR_IS_DEFAULT_BG(color)) + return 0; + if (VTERM_COLOR_IS_INDEXED(color)) { // The first 16 colors and default: use the ANSI index. - switch (color->ansi_index) + switch (color->index + 1) { case 0: return 0; case 1: return lookup_color( 0, fg, boldp) + 1; // black @@ -3832,7 +3836,14 @@ term_get_attr(win_T *wp, linenr_T lnum, int col) static void cterm_color2vterm(int nr, VTermColor *rgb) { - cterm_color2rgb(nr, &rgb->red, &rgb->green, &rgb->blue, &rgb->ansi_index); + cterm_color2rgb(nr, &rgb->red, &rgb->green, &rgb->blue, &rgb->index); + if (rgb->index == 0) + rgb->type = VTERM_COLOR_RGB; + else + { + rgb->type = VTERM_COLOR_INDEXED; + --rgb->index; + } } /* @@ -3864,7 +3875,8 @@ init_default_colors(term_T *term, win_T *wp) } fg->red = fg->green = fg->blue = fgval; bg->red = bg->green = bg->blue = bgval; - fg->ansi_index = bg->ansi_index = VTERM_ANSI_INDEX_DEFAULT; + fg->type = VTERM_COLOR_RGB | VTERM_COLOR_DEFAULT_FG; + bg->type = VTERM_COLOR_RGB | VTERM_COLOR_DEFAULT_BG; // The 'wincolor' or the highlight group overrules the defaults. if (wp != NULL && *wp->w_p_wcr != NUL) @@ -4509,21 +4521,30 @@ term_get_buf(typval_T *argvars, char *where) return buf; } - static int -same_color(VTermColor *a, VTermColor *b) + static void +clear_cell(VTermScreenCell *cell) { - return a->red == b->red - && a->green == b->green - && a->blue == b->blue - && a->ansi_index == b->ansi_index; + CLEAR_FIELD(*cell); + cell->fg.type = VTERM_COLOR_DEFAULT_FG; + cell->bg.type = VTERM_COLOR_DEFAULT_BG; } static void dump_term_color(FILE *fd, VTermColor *color) { + int index; + + if (VTERM_COLOR_IS_INDEXED(color)) + index = color->index + 1; + else if (color->type == 0) + // use RGB values + index = 255; + else + // default color + index = 0; fprintf(fd, "%02x%02x%02x%d", (int)color->red, (int)color->green, (int)color->blue, - (int)color->ansi_index); + index); } /* @@ -4607,7 +4628,7 @@ f_term_dumpwrite(typval_T *argvars, typval_T *rettv UNUSED) return; } - CLEAR_FIELD(prev_cell); + clear_cell(&prev_cell); screen = vterm_obtain_screen(term->tl_vterm); state = vterm_obtain_state(term->tl_vterm); @@ -4629,7 +4650,7 @@ f_term_dumpwrite(typval_T *argvars, typval_T *rettv UNUSED) && pos.row == cursor_pos.row); if (vterm_screen_get_cell(screen, pos, &cell) == 0) - CLEAR_FIELD(cell); + clear_cell(&cell); for (i = 0; i < VTERM_MAX_CHARS_PER_CELL; ++i) { @@ -4649,8 +4670,8 @@ f_term_dumpwrite(typval_T *argvars, typval_T *rettv UNUSED) } same_attr = vtermAttr2hl(cell.attrs) == vtermAttr2hl(prev_cell.attrs) - && same_color(&cell.fg, &prev_cell.fg) - && same_color(&cell.bg, &prev_cell.bg); + && vterm_color_is_equal(&cell.fg, &prev_cell.fg) + && vterm_color_is_equal(&cell.bg, &prev_cell.bg); if (same_chars && cell.width == prev_cell.width && same_attr && !is_cursor_pos) { @@ -4697,14 +4718,14 @@ f_term_dumpwrite(typval_T *argvars, typval_T *rettv UNUSED) else { fprintf(fd, "%d", vtermAttr2hl(cell.attrs)); - if (same_color(&cell.fg, &prev_cell.fg)) + if (vterm_color_is_equal(&cell.fg, &prev_cell.fg)) fputs("&", fd); else { fputs("#", fd); dump_term_color(fd, &cell.fg); } - if (same_color(&cell.bg, &prev_cell.bg)) + if (vterm_color_is_equal(&cell.bg, &prev_cell.bg)) fputs("&", fd); else { @@ -4747,6 +4768,14 @@ append_cell(garray_T *gap, cellattr_T *cell) } } + static void +clear_cellattr(cellattr_T *cell) +{ + CLEAR_FIELD(*cell); + cell->fg.type = VTERM_COLOR_DEFAULT_FG; + cell->bg.type = VTERM_COLOR_DEFAULT_BG; +} + /* * Read the dump file from "fd" and append lines to the current buffer. * Return the cell width of the longest line. @@ -4767,8 +4796,8 @@ read_dump_file(FILE *fd, VTermPos *cursor_pos) ga_init2(&ga_text, 1, 90); ga_init2(&ga_cell, sizeof(cellattr_T), 90); - CLEAR_FIELD(cell); - CLEAR_FIELD(empty_cell); + clear_cellattr(&cell); + clear_cellattr(&empty_cell); cursor_pos->row = -1; cursor_pos->col = -1; @@ -4878,7 +4907,7 @@ read_dump_file(FILE *fd, VTermPos *cursor_pos) } else if (c == '#') { - int red, green, blue, index = 0; + int red, green, blue, index = 0, type; c = fgetc(fd); red = hex2nr(c); @@ -4900,20 +4929,37 @@ read_dump_file(FILE *fd, VTermPos *cursor_pos) index = index * 10 + (c - '0'); c = fgetc(fd); } - - if (is_bg) + if (index == 0 || index == 255) { - cell.bg.red = red; - cell.bg.green = green; - cell.bg.blue = blue; - cell.bg.ansi_index = index; + type = VTERM_COLOR_RGB; + if (index == 0) + { + if (is_bg) + type |= VTERM_COLOR_DEFAULT_BG; + else + type |= VTERM_COLOR_DEFAULT_FG; + } } else { + type = VTERM_COLOR_INDEXED; + index -= 1; + } + if (is_bg) + { + cell.bg.type = type; + cell.bg.red = red; + cell.bg.green = green; + cell.bg.blue = blue; + cell.bg.index = index; + } + else + { + cell.fg.type = type; cell.fg.red = red; cell.fg.green = green; cell.fg.blue = blue; - cell.fg.ansi_index = index; + cell.fg.index = index; } } else @@ -5226,10 +5272,10 @@ term_load_dump(typval_T *argvars, typval_T *rettv, int do_diff) if ((cellattr1 + col)->width != (cellattr2 + col)->width) textline[col] = 'w'; - else if (!same_color(&(cellattr1 + col)->fg, + else if (!vterm_color_is_equal(&(cellattr1 + col)->fg, &(cellattr2 + col)->fg)) textline[col] = 'f'; - else if (!same_color(&(cellattr1 + col)->bg, + else if (!vterm_color_is_equal(&(cellattr1 + col)->bg, &(cellattr2 + col)->bg)) textline[col] = 'b'; else if (vtermAttr2hl((cellattr1 + col)->attrs) @@ -5808,6 +5854,7 @@ f_term_scrape(typval_T *argvars, typval_T *rettv) else { VTermScreenCell cell; + if (vterm_screen_get_cell(screen, pos, &cell) == 0) break; for (i = 0; i < VTERM_MAX_CHARS_PER_CELL; ++i) diff --git a/src/version.c b/src/version.c index 31aa395876..a710bc5a16 100644 --- a/src/version.c +++ b/src/version.c @@ -746,6 +746,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 804, /**/ 803, /**/ From fe81389d606ae79415d208207295f41a4375c580 Mon Sep 17 00:00:00 2001 From: Bram Moolenaar <Bram@vim.org> Date: Thu, 21 May 2020 20:38:31 +0200 Subject: [PATCH 204/230] patch 8.2.0805: terminal key codes test fails on some systems Problem: Terminal key codes test fails on some systems. Solution: Skip keypad 3 and 9. (Yegappan Lakshmanan, closes #6070) --- src/testdir/test_terminal.vim | 45 ++++++++++++++++++++++++++--------- src/version.c | 2 ++ 2 files changed, 36 insertions(+), 11 deletions(-) diff --git a/src/testdir/test_terminal.vim b/src/testdir/test_terminal.vim index 7f85f6cf10..31052b5d6e 100644 --- a/src/testdir/test_terminal.vim +++ b/src/testdir/test_terminal.vim @@ -2683,22 +2683,45 @@ func Test_term_keycode_translation() \ '<F8>', '<F9>', '<F10>', '<F11>', '<F12>', '<Home>', '<S-Home>', \ '<C-Home>', '<End>', '<S-End>', '<C-End>', '<Insert>', '<Del>', \ '<Left>', '<S-Left>', '<C-Left>', '<Right>', '<S-Right>', - \ '<C-Right>', '<Up>', '<S-Up>', '<Down>', '<S-Down>', - \ '0123456789', "\t\t.+-*/"] + \ '<C-Right>', '<Up>', '<S-Up>', '<Down>', '<S-Down>'] - for k in keys - call term_sendkeys(buf, "i\<C-K>" .. k .. "\<CR>\<C-\>\<C-N>") + call term_sendkeys(buf, "i") + for i in range(len(keys)) + call term_sendkeys(buf, "\<C-U>\<C-K>" .. keys[i]) + call term_wait(buf) + call assert_equal(output[i], term_getline(buf, 1)) endfor - call term_sendkeys(buf, "i\<K0>\<K1>\<K2>\<K3>\<K4>\<K5>\<K6>\<K7>") - call term_sendkeys(buf, "\<K8>\<K9>\<kEnter>\<kPoint>\<kPlus>") - call term_sendkeys(buf, "\<kMinus>\<kMultiply>\<kDivide>\<C-\>\<C-N>") - call term_sendkeys(buf, "\<Home>\<Ins>\<Tab>\<S-Tab>\<C-\>\<C-N>") - call term_sendkeys(buf, ":write Xkeycodes\<CR>") + "call term_sendkeys(buf, "\<K0>\<K1>\<K2>\<K3>\<K4>\<K5>\<K6>\<K7>\<K8>\<K9>") + "call term_sendkeys(buf, "\<kEnter>\<kPoint>\<kPlus>") + "call term_sendkeys(buf, "\<kMinus>\<kMultiply>\<kDivide>") + "call term_sendkeys(buf, "\<Esc>") + "call term_sendkeys(buf, "\<Home>\<Ins>\<Tab>\<S-Tab>") + "call term_sendkeys(buf, "\<Esc>") + + "call term_sendkeys(buf, ":write Xkeycodes\<CR>") + + let keypad_keys = ["\<k0>", "\<k1>", "\<k2>", "\<k3>", "\<k4>", "\<k5>", + \ "\<k6>", "\<k7>", "\<k8>", "\<k9>", "\<kPoint>", "\<kPlus>", + \ "\<kMinus>", "\<kMultiply>", "\<kDivide>"] + let keypad_output = ['0', '1', '2', '3', '4', '5', + \ '6', '7', '8', '9', '.', '+', + \ '-', '*', '/'] + for i in range(len(keypad_keys)) + " TODO: Mysteriously keypad 3 and 9 do not work on some systems. + if keypad_output[i] == '3' || keypad_output[i] == '9' + continue + endif + call term_sendkeys(buf, "\<C-U>" .. keypad_keys[i]) + call term_wait(buf) + call assert_equal(keypad_output[i], term_getline(buf, 1)) + endfor + + call feedkeys("\<C-U>\<kEnter>\<BS>one\<C-W>.two", 'xt') call term_wait(buf) + call assert_equal('two', term_getline(buf, 1)) + call StopVimInTerminal(buf) - call assert_equal(output, readfile('Xkeycodes')) - call delete('Xkeycodes') endfunc " Test for using the mouse in a terminal diff --git a/src/version.c b/src/version.c index a710bc5a16..c112f7d47d 100644 --- a/src/version.c +++ b/src/version.c @@ -746,6 +746,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 805, /**/ 804, /**/ From 74fae513f8032cfa9e129eedc33454f0bf68668b Mon Sep 17 00:00:00 2001 From: Bram Moolenaar <Bram@vim.org> Date: Thu, 21 May 2020 21:50:58 +0200 Subject: [PATCH 205/230] patch 8.2.0806: using "func!" after vim9script gives confusing error Problem: using "func!" after vim9script gives confusing error. Solution: Give E477. (closes #6107) --- src/testdir/test_vim9_script.vim | 7 ++++++- src/version.c | 2 ++ src/vim9script.c | 6 ++++++ 3 files changed, 14 insertions(+), 1 deletion(-) diff --git a/src/testdir/test_vim9_script.vim b/src/testdir/test_vim9_script.vim index 22166fcb90..cc313285a5 100644 --- a/src/testdir/test_vim9_script.vim +++ b/src/testdir/test_vim9_script.vim @@ -136,7 +136,7 @@ def Test_assignment_dict() let dict2: dict<number> = #{one: 1, two: 2} let dict3: dict<string> = #{key: 'value'} let dict4: dict<any> = #{one: 1, two: '2'} - let dict5: dict<blob> = #{one: 0z01, tw: 0z02} + let dict5: dict<blob> = #{one: 0z01, two: 0z02} call CheckDefExecFailure(['let dd = {}', 'dd[""] = 6'], 'E713:') @@ -1721,6 +1721,11 @@ def Test_vim9_comment_not_compiled() 'dsearch /pat/#comment', 'bwipe!', ], 'E488:') + + CheckScriptFailure([ + 'vim9script', + 'func! SomeFunc()', + ], 'E477:') enddef def Test_finish() diff --git a/src/version.c b/src/version.c index c112f7d47d..d36fa4a2a1 100644 --- a/src/version.c +++ b/src/version.c @@ -746,6 +746,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 806, /**/ 805, /**/ diff --git a/src/vim9script.c b/src/vim9script.c index e213d61f1d..76650f8998 100644 --- a/src/vim9script.c +++ b/src/vim9script.c @@ -84,6 +84,12 @@ ex_vim9script(exarg_T *eap) { int lnum_start = SOURCING_LNUM - 1; + if (*p == '!') + { + emsg(_(e_nobang)); + break; + } + // Handle :function and :def by calling def_function(). // It will read upto the matching :endded or :endfunction. eap->cmdidx = *line == 'f' ? CMD_function : CMD_def; From 4c9243f9fb708c9010867d3cc8e928f36b58509a Mon Sep 17 00:00:00 2001 From: Bram Moolenaar <Bram@vim.org> Date: Fri, 22 May 2020 13:10:44 +0200 Subject: [PATCH 206/230] patch 8.2.0807: cannot easily restore a mapping Problem: Cannot easily restore a mapping. Solution: Add mapset(). --- runtime/doc/eval.txt | 19 +++ src/evalfunc.c | 1 + src/map.c | 222 ++++++++++++++++++++++++++++-------- src/proto/map.pro | 1 + src/testdir/test_maparg.vim | 47 ++++++-- src/version.c | 2 + 6 files changed, 231 insertions(+), 61 deletions(-) diff --git a/runtime/doc/eval.txt b/runtime/doc/eval.txt index 8259e9920b..afda3505b1 100644 --- a/runtime/doc/eval.txt +++ b/runtime/doc/eval.txt @@ -2586,6 +2586,8 @@ maparg({name} [, {mode} [, {abbr} [, {dict}]]]) rhs of mapping {name} in mode {mode} mapcheck({name} [, {mode} [, {abbr}]]) String check for mappings matching {name} +mapset({name}, {mode}, {abbr}, {dict} + none restore mapping from |maparg()| result match({expr}, {pat} [, {start} [, {count}]]) Number position where {pat} matches in {expr} matchadd({group}, {pattern} [, {priority} [, {id} [, {dict}]]]) @@ -6794,6 +6796,7 @@ map({expr1}, {expr2}) *map()* Can also be used as a |method|: > mylist->map(expr2) + maparg({name} [, {mode} [, {abbr} [, {dict}]]]) *maparg()* When {dict} is omitted or zero: Return the rhs of mapping {name} in mode {mode}. The returned String has special @@ -6844,6 +6847,10 @@ maparg({name} [, {mode} [, {abbr} [, {dict}]]]) *maparg()* "lnum" The line number in "sid", zero if unknown. "nowait" Do not wait for other, longer mappings. (|:map-<nowait>|). + "simplified" + + The dictionary can be used to restore a mapping with + |mapset()|. The mappings local to the current buffer are checked first, then the global mappings. @@ -6890,6 +6897,18 @@ mapcheck({name} [, {mode} [, {abbr}]]) *mapcheck()* Can also be used as a |method|: > GetKey()->mapcheck('n') +mapset({mode}, {abbr}, {dict}) *mapset()* + Restore a mapping from a dictionary returned by |maparg()|. + {name}, {mode} and {abbr} should be the same as for the call + to |maparg()|. + {mode} is used to define the mode in which the mapping is set, + not the "mode" entry in {dict}. + Example for saving and restoring a mapping: > + let save_map = maparg('K', 'n', 0, 1) + nnoremap K somethingelse + ... + call mapset('n', 0, save_map) +< match({expr}, {pat} [, {start} [, {count}]]) *match()* When {expr} is a |List| then this returns the index of the first item where {pat} matches. Each item is used as a diff --git a/src/evalfunc.c b/src/evalfunc.c index 297961184a..37cb72f7ee 100644 --- a/src/evalfunc.c +++ b/src/evalfunc.c @@ -664,6 +664,7 @@ static funcentry_T global_functions[] = {"map", 2, 2, FEARG_1, ret_any, f_map}, {"maparg", 1, 4, FEARG_1, ret_string, f_maparg}, {"mapcheck", 1, 3, FEARG_1, ret_string, f_mapcheck}, + {"mapset", 3, 3, FEARG_1, ret_void, f_mapset}, {"match", 2, 4, FEARG_1, ret_any, f_match}, {"matchadd", 2, 5, FEARG_1, ret_number, f_matchadd}, {"matchaddpos", 2, 5, FEARG_1, ret_number, f_matchaddpos}, diff --git a/src/map.c b/src/map.c index 2e20d401cb..34a956e0be 100644 --- a/src/map.c +++ b/src/map.c @@ -204,6 +204,86 @@ showmap( out_flush(); // show one line at a time } + static int +map_add( + mapblock_T **map_table, + mapblock_T **abbr_table, + char_u *keys, + char_u *rhs, + char_u *orig_rhs, + int expr, + int noremap, + int nowait, + int silent, + int mode, + int is_abbr, +#ifdef FEAT_EVAL + scid_T sid, // -1 to use current_sctx + linenr_T lnum, +#endif + int simplified) +{ + mapblock_T *mp = ALLOC_ONE(mapblock_T); + + if (mp == NULL) + return FAIL; + + // If CTRL-C has been mapped, don't always use it for Interrupting. + if (*keys == Ctrl_C) + { + if (map_table == curbuf->b_maphash) + curbuf->b_mapped_ctrl_c |= mode; + else + mapped_ctrl_c |= mode; + } + + mp->m_keys = vim_strsave(keys); + mp->m_str = vim_strsave(rhs); + mp->m_orig_str = vim_strsave(orig_rhs); + if (mp->m_keys == NULL || mp->m_str == NULL) + { + vim_free(mp->m_keys); + vim_free(mp->m_str); + vim_free(mp->m_orig_str); + vim_free(mp); + return FAIL; + } + mp->m_keylen = (int)STRLEN(mp->m_keys); + mp->m_noremap = noremap; + mp->m_nowait = nowait; + mp->m_silent = silent; + mp->m_mode = mode; + mp->m_simplified = simplified; +#ifdef FEAT_EVAL + mp->m_expr = expr; + if (sid >= 0) + { + mp->m_script_ctx.sc_sid = sid; + mp->m_script_ctx.sc_lnum = lnum; + } + else + { + mp->m_script_ctx = current_sctx; + mp->m_script_ctx.sc_lnum += SOURCING_LNUM; + } +#endif + + // add the new entry in front of the abbrlist or maphash[] list + if (is_abbr) + { + mp->m_next = *abbr_table; + *abbr_table = mp; + } + else + { + int n = MAP_HASH(mp->m_mode, mp->m_keys[0]); + + mp->m_next = map_table[n]; + map_table[n] = mp; + } + return OK; +} + /* * map[!] : show all key mappings * map[!] {lhs} : show key mapping for {lhs} @@ -501,7 +581,8 @@ do_map( msg_start(); // Check if a new local mapping wasn't already defined globally. - if (map_table == curbuf->b_maphash && haskey && hasarg && maptype != 1) + if (unique && map_table == curbuf->b_maphash + && haskey && hasarg && maptype != 1) { // need to loop over all global hash lists for (hash = 0; hash < 256 && !got_int; ++hash) @@ -519,7 +600,6 @@ do_map( // check entries with the same mode if ((mp->m_mode & mode) != 0 && mp->m_keylen == len - && unique && STRNCMP(mp->m_keys, keys, (size_t)len) == 0) { if (abbrev) @@ -759,58 +839,17 @@ do_map( continue; // have added the new entry already // Get here when adding a new entry to the maphash[] list or abbrlist. - mp = ALLOC_ONE(mapblock_T); - if (mp == NULL) + if (map_add(map_table, abbr_table, keys, rhs, orig_rhs, expr, + noremap, nowait, silent, mode, + abbrev, +#ifdef FEAT_EVAL + /* sid */ -1, /* lnum */ 0, +#endif + did_simplify && keyround == 1) == FAIL) { retval = 4; // no mem goto theend; } - - // If CTRL-C has been mapped, don't always use it for Interrupting. - if (*keys == Ctrl_C) - { - if (map_table == curbuf->b_maphash) - curbuf->b_mapped_ctrl_c |= mode; - else - mapped_ctrl_c |= mode; - } - - mp->m_keys = vim_strsave(keys); - mp->m_str = vim_strsave(rhs); - mp->m_orig_str = vim_strsave(orig_rhs); - if (mp->m_keys == NULL || mp->m_str == NULL) - { - vim_free(mp->m_keys); - vim_free(mp->m_str); - vim_free(mp->m_orig_str); - vim_free(mp); - retval = 4; // no mem - goto theend; - } - mp->m_keylen = (int)STRLEN(mp->m_keys); - mp->m_noremap = noremap; - mp->m_nowait = nowait; - mp->m_silent = silent; - mp->m_mode = mode; - mp->m_simplified = did_simplify && keyround == 1; -#ifdef FEAT_EVAL - mp->m_expr = expr; - mp->m_script_ctx = current_sctx; - mp->m_script_ctx.sc_lnum += SOURCING_LNUM; -#endif - - // add the new entry in front of the abbrlist or maphash[] list - if (abbrev) - { - mp->m_next = *abbr_table; - *abbr_table = mp; - } - else - { - n = MAP_HASH(mp->m_mode, mp->m_keys[0]); - mp->m_next = map_table[n]; - map_table[n] = mp; - } } theend: @@ -2209,13 +2248,96 @@ get_maparg(typval_T *argvars, typval_T *rettv, int exact) dict_add_number(dict, "buffer", (long)buffer_local); dict_add_number(dict, "nowait", mp->m_nowait ? 1L : 0L); dict_add_string(dict, "mode", mapmode); + dict_add_number(dict, "simplified", mp->m_simplified); vim_free(lhs); vim_free(mapmode); } } + +/* + * "mapset()" function + */ + void +f_mapset(typval_T *argvars, typval_T *rettv UNUSED) +{ + char_u *keys; + char_u *keys_buf = NULL; + char_u *which; + int mode; + char_u buf[NUMBUFLEN]; + int is_abbr; + dict_T *d; + char_u *lhs; + char_u *rhs; + int noremap; + int expr; + int silent; + scid_T sid; + linenr_T lnum; + mapblock_T **map_table = maphash; + mapblock_T **abbr_table = &first_abbr; + int nowait; + int simplified; + char_u *arg; + + which = tv_get_string_buf_chk(&argvars[0], buf); + mode = get_map_mode(&which, 0); + is_abbr = (int)tv_get_number(&argvars[1]); + + if (argvars[2].v_type != VAR_DICT) + { + emsg(_(e_dictkey)); + return; + } + d = argvars[2].vval.v_dict; + + // Get the values in the same order as above in get_maparg(). + lhs = dict_get_string(d, (char_u *)"lhs", FALSE); + if (lhs == NULL) + { + emsg(_("E99: lhs entry missing in mapset() dict argument")); + return; + } + rhs = dict_get_string(d, (char_u *)"rhs", FALSE); + if (rhs == NULL) + { + emsg(_("E99: rhs entry missing in mapset() dict argument")); + return; + } + + noremap = dict_get_number(d, (char_u *)"noremap") ? REMAP_NONE: 0; + if (dict_get_number(d, (char_u *)"script") != 0) + noremap = REMAP_SCRIPT; + expr = dict_get_number(d, (char_u *)"expr") != 0; + silent = dict_get_number(d, (char_u *)"silent") != 0; + sid = dict_get_number(d, (char_u *)"sid"); + lnum = dict_get_number(d, (char_u *)"lnum"); + if (dict_get_number(d, (char_u *)"buffer")) + { + map_table = curbuf->b_maphash; + abbr_table = &curbuf->b_first_abbr; + } + nowait = dict_get_number(d, (char_u *)"nowait") != 0; + // mode from the dict is not used + simplified = dict_get_number(d, (char_u *)"simplified") != 0; + + // Delete any existing mapping for this lhs and mode. + arg = vim_strsave(lhs); + if (arg == NULL) + return; + do_map(1, arg, mode, is_abbr); + vim_free(arg); + + keys = replace_termcodes(lhs, &keys_buf, + REPTERM_FROM_PART | REPTERM_DO_LT, NULL); + (void)map_add(map_table, abbr_table, keys, rhs, rhs, expr, + noremap, nowait, silent, mode, is_abbr, sid, lnum, simplified); + vim_free(keys_buf); +} #endif + #if defined(MSWIN) || defined(MACOS_X) # define VIS_SEL (VISUAL+SELECTMODE) // abbreviation diff --git a/src/proto/map.pro b/src/proto/map.pro index cf1b31a4cc..6da455a7e4 100644 --- a/src/proto/map.pro +++ b/src/proto/map.pro @@ -18,6 +18,7 @@ int put_escstr(FILE *fd, char_u *strstart, int what); void check_map_keycodes(void); char_u *check_map(char_u *keys, int mode, int exact, int ign_mod, int abbr, mapblock_T **mp_ptr, int *local_ptr); void get_maparg(typval_T *argvars, typval_T *rettv, int exact); +void f_mapset(typval_T *argvars, typval_T *rettv); void init_mappings(void); void add_map(char_u *map, int mode); int langmap_adjust_mb(int c); diff --git a/src/testdir/test_maparg.vim b/src/testdir/test_maparg.vim index cc72e7e8e6..5fb8045a64 100644 --- a/src/testdir/test_maparg.vim +++ b/src/testdir/test_maparg.vim @@ -1,12 +1,12 @@ -" Tests for maparg(). +" Tests for maparg(), mapcheck() and mapset(). " Also test utf8 map with a 0x80 byte. " Also test mapcheck() -function s:SID() +func s:SID() return str2nr(matchstr(expand('<sfile>'), '<SNR>\zs\d\+\ze_SID$')) -endfun +endfunc -function Test_maparg() +funct Test_maparg() new set cpo-=< set encoding=utf8 @@ -18,23 +18,23 @@ function Test_maparg() call assert_equal("is<F4>foo", maparg('foo<C-V>')) call assert_equal({'silent': 0, 'noremap': 0, 'script': 0, 'lhs': 'foo<C-V>', \ 'mode': ' ', 'nowait': 0, 'expr': 0, 'sid': sid, 'lnum': lnum + 1, - \ 'rhs': 'is<F4>foo', 'buffer': 0}, + \ 'simplified': 1, 'rhs': 'is<F4>foo', 'buffer': 0}, \ maparg('foo<C-V>', '', 0, 1)) call assert_equal({'silent': 1, 'noremap': 1, 'script': 1, 'lhs': 'bar', 'mode': 'v', \ 'nowait': 0, 'expr': 1, 'sid': sid, 'lnum': lnum + 2, - \ 'rhs': 'isbar', 'buffer': 1}, + \ 'simplified': 0, 'rhs': 'isbar', 'buffer': 1}, \ 'bar'->maparg('', 0, 1)) let lnum = expand('<sflnum>') map <buffer> <nowait> foo bar call assert_equal({'silent': 0, 'noremap': 0, 'script': 0, 'lhs': 'foo', 'mode': ' ', \ 'nowait': 1, 'expr': 0, 'sid': sid, 'lnum': lnum + 1, 'rhs': 'bar', - \ 'buffer': 1}, + \ 'simplified': 0, 'buffer': 1}, \ maparg('foo', '', 0, 1)) let lnum = expand('<sflnum>') tmap baz foo call assert_equal({'silent': 0, 'noremap': 0, 'script': 0, 'lhs': 'baz', 'mode': 't', \ 'nowait': 0, 'expr': 0, 'sid': sid, 'lnum': lnum + 1, 'rhs': 'foo', - \ 'buffer': 0}, + \ 'simplified': 0, 'buffer': 0}, \ maparg('baz', 't', 0, 1)) map abc x<char-114>x @@ -75,7 +75,7 @@ function Test_maparg() let d = maparg('esc', 'i', 1, 1) call assert_equal(['esc', "\<C-V>\<C-V>\<Esc>", '!'], [d.lhs, d.rhs, d.mode]) abclear -endfunction +endfunc func Test_mapcheck() call assert_equal('', mapcheck('a')) @@ -116,7 +116,7 @@ func Test_mapcheck() unabbr ab endfunc -function Test_range_map() +func Test_range_map() new " Outside of the range, minimum inoremap <Char-0x1040> a @@ -131,6 +131,31 @@ function Test_range_map() inoremap <Char-0xf040> d execute "normal a\uf040\<Esc>" call assert_equal("abcd", getline(1)) -endfunction +endfunc + +func One_mapset_test(keys) + exe 'nnoremap ' .. a:keys .. ' original<CR>' + let orig = maparg(a:keys, 'n', 0, 1) + call assert_equal(a:keys, orig.lhs) + call assert_equal('original<CR>', orig.rhs) + call assert_equal('n', orig.mode) + + exe 'nunmap ' .. a:keys + let d = maparg(a:keys, 'n', 0, 1) + call assert_equal({}, d) + + call mapset('n', 0, orig) + let d = maparg(a:keys, 'n', 0, 1) + call assert_equal(a:keys, d.lhs) + call assert_equal('original<CR>', d.rhs) + call assert_equal('n', d.mode) + + exe 'nunmap ' .. a:keys +endfunc + +func Test_mapset() + call One_mapset_test('K') + call One_mapset_test('<F3>') +endfunc " vim: shiftwidth=2 sts=2 expandtab diff --git a/src/version.c b/src/version.c index d36fa4a2a1..565ebbbcb3 100644 --- a/src/version.c +++ b/src/version.c @@ -746,6 +746,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 807, /**/ 806, /**/ From 98f1671cc0ab0ad6139cb9c6ce5262e7f646bc0a Mon Sep 17 00:00:00 2001 From: Bram Moolenaar <Bram@vim.org> Date: Fri, 22 May 2020 13:34:01 +0200 Subject: [PATCH 207/230] patch 8.2.0808: not enough testing for the terminal window Problem: Not enough testing for the terminal window. Solution: Add more tests. (Yegappan Lakshmanan, closes #6069) Fix memory leak. --- src/terminal.c | 2 +- src/testdir/test_gui.vim | 3 +- src/testdir/test_terminal.vim | 53 ++++++++++++++++++++++++----------- src/version.c | 2 ++ 4 files changed, 41 insertions(+), 19 deletions(-) diff --git a/src/terminal.c b/src/terminal.c index 3fcd659fca..0a5ccbc597 100644 --- a/src/terminal.c +++ b/src/terminal.c @@ -3047,7 +3047,7 @@ handle_settermprop( #endif else { - term->tl_title = vim_strsave(strval); + term->tl_title = strval; strval = NULL; } VIM_CLEAR(term->tl_status_text); diff --git a/src/testdir/test_gui.vim b/src/testdir/test_gui.vim index 28782f00c0..c9e3f7f13f 100644 --- a/src/testdir/test_gui.vim +++ b/src/testdir/test_gui.vim @@ -850,8 +850,7 @@ func Test_gui_run_cmd_in_terminal() " assume all the other systems have a cat command let cmd = 'cat' endif - let cmd = ':silent !' . cmd . " test_gui.vim\<CR>\<CR>" - call feedkeys(cmd, 'xt') + exe "silent !" . cmd . " test_gui.vim" " TODO: how to check that the command ran in a separate terminal? " Maybe check for $TERM (dumb vs xterm) in the spawned shell? let &guioptions = save_guioptions diff --git a/src/testdir/test_terminal.vim b/src/testdir/test_terminal.vim index 31052b5d6e..395de5207b 100644 --- a/src/testdir/test_terminal.vim +++ b/src/testdir/test_terminal.vim @@ -1220,6 +1220,7 @@ func Test_terminal_dumpwrite_errors() call delete('Xtest.dump') call assert_fails("call term_dumpwrite(buf, '')", 'E482:') call assert_fails("call term_dumpwrite(buf, test_null_string())", 'E482:') + call test_garbagecollect_now() call StopVimInTerminal(buf) call term_wait(buf) call assert_fails("call term_dumpwrite(buf, 'Xtest.dump')", 'E958:') @@ -1305,6 +1306,16 @@ func Test_terminal_dumpdiff_swap() call assert_match('three four five', getline(3)) call assert_match('Undo', getline(45)) quit + + " Diff two terminal dump files with different number of rows + " Swap the diffs + call term_dumpdiff('dumps/Test_popup_command_01.dump', 'dumps/Test_winline_rnu.dump') + call assert_match('Test_popup_command_01.dump', getline(21)) + call assert_match('Test_winline_rnu.dump', getline(42)) + normal s + call assert_match('Test_winline_rnu.dump', getline(6)) + call assert_match('Test_popup_command_01.dump', getline(27)) + quit endfunc func Test_terminal_dumpdiff_options() @@ -1619,6 +1630,7 @@ func Test_terminal_ansicolors_default() call assert_equal(colors, term_getansicolors(buf)) call StopShellInTerminal(buf) call TermWait(buf) + call assert_equal([], term_getansicolors(buf)) exe buf . 'bwipe' endfunc @@ -1673,9 +1685,11 @@ func Test_terminal_ansicolors_func() let colors[4] = 'Invalid' call assert_fails('call term_setansicolors(buf, colors)', 'E474:') + call assert_fails('call term_setansicolors(buf, {})', 'E714:') call StopShellInTerminal(buf) call TermWait(buf) + call assert_equal(0, term_setansicolors(buf, [])) exe buf . 'bwipe' endfunc @@ -2029,7 +2043,7 @@ func Test_terminal_switch_mode() call WaitForAssert({-> assert_equal('running,normal', term_getstatus(bnr))}) call feedkeys("A", 'xt') call WaitForAssert({-> assert_equal('running', term_getstatus(bnr))}) - call feedkeys("\<C-W>N", 'xt') + call feedkeys("\<C-\>\<C-N>", 'xt') call WaitForAssert({-> assert_equal('running,normal', term_getstatus(bnr))}) call feedkeys("I", 'xt') call WaitForAssert({-> assert_equal('running', term_getstatus(bnr))}) @@ -2066,6 +2080,7 @@ func Test_terminal_normal_mode() call term_sendkeys(buf, ":set culopt=line\r") call VerifyScreenDump(buf, 'Test_terminal_normal_3', {}) + call assert_fails('call term_sendkeys(buf, [])', 'E730:') call term_sendkeys(buf, "a:q!\<CR>:q\<CR>:q\<CR>") call StopVimInTerminal(buf) call delete('XtermNormal') @@ -2178,17 +2193,18 @@ func Test_term_getcursor() call StopShellInTerminal(buf) endfunc +" Test for term_gettitle() func Test_term_gettitle() " term_gettitle() returns an empty string for a non-terminal buffer " and for a non-existing buffer. call assert_equal('', bufnr('%')->term_gettitle()) call assert_equal('', term_gettitle(bufnr('$') + 1)) - if !has('title') || &title == 0 || empty(&t_ts) + if !has('title') || empty(&t_ts) throw "Skipped: can't get/set title" endif - let term = term_start([GetVimProg(), '--clean', '-c', 'set noswapfile']) + let term = term_start([GetVimProg(), '--clean', '-c', 'set noswapfile', '-c', 'set title']) if has('autoservername') call WaitForAssert({-> assert_match('^\[No Name\] - VIM\d\+$', term_gettitle(term)) }) call term_sendkeys(term, ":e Xfoo\r") @@ -2692,15 +2708,6 @@ func Test_term_keycode_translation() call assert_equal(output[i], term_getline(buf, 1)) endfor - "call term_sendkeys(buf, "\<K0>\<K1>\<K2>\<K3>\<K4>\<K5>\<K6>\<K7>\<K8>\<K9>") - "call term_sendkeys(buf, "\<kEnter>\<kPoint>\<kPlus>") - "call term_sendkeys(buf, "\<kMinus>\<kMultiply>\<kDivide>") - "call term_sendkeys(buf, "\<Esc>") - "call term_sendkeys(buf, "\<Home>\<Ins>\<Tab>\<S-Tab>") - "call term_sendkeys(buf, "\<Esc>") - - "call term_sendkeys(buf, ":write Xkeycodes\<CR>") - let keypad_keys = ["\<k0>", "\<k1>", "\<k2>", "\<k3>", "\<k4>", "\<k5>", \ "\<k6>", "\<k7>", "\<k8>", "\<k9>", "\<kPoint>", "\<kPlus>", \ "\<kMinus>", "\<kMultiply>", "\<kDivide>"] @@ -2733,7 +2740,6 @@ func Test_term_mouse() let save_term = &term let save_ttymouse = &ttymouse let save_clipboard = &clipboard - call test_override('no_query_mouse', 1) set mouse=a term=xterm ttymouse=sgr mousetime=200 clipboard= let lines =<< trim END @@ -2743,6 +2749,8 @@ func Test_term_mouse() END call writefile(lines, 'Xtest_mouse') + " Create a terminal window running Vim for the test with mouse enabled + let prev_win = win_getid() let buf = RunVimInTerminal('Xtest_mouse -n', {}) call term_sendkeys(buf, ":set nocompatible\<CR>") call term_sendkeys(buf, ":set mouse=a term=xterm ttymouse=sgr\<CR>") @@ -2751,6 +2759,12 @@ func Test_term_mouse() call term_wait(buf) redraw! + " Use the mouse to enter the terminal window + call win_gotoid(prev_win) + call feedkeys(MouseLeftClickCode(1, 1), 'x') + call feedkeys(MouseLeftReleaseCode(1, 1), 'x') + call assert_equal(1, getwininfo(win_getid())[0].terminal) + " Test for <LeftMouse> click/release call test_setmouse(2, 5) call feedkeys("\<LeftMouse>\<LeftRelease>", 'xt') @@ -2833,7 +2847,6 @@ func Test_term_mouse() let &ttymouse = save_ttymouse let &clipboard = save_clipboard set mousetime& - call test_override('no_query_mouse', 0) call delete('Xtest_mouse') call delete('Xbuf') endfunc @@ -2848,7 +2861,6 @@ func Test_term_modeless_selection() let save_mouse = &mouse let save_term = &term let save_ttymouse = &ttymouse - call test_override('no_query_mouse', 1) set mouse=a term=xterm ttymouse=sgr mousetime=200 set clipboard=autoselectml @@ -2859,12 +2871,21 @@ func Test_term_modeless_selection() END call writefile(lines, 'Xtest_modeless') + " Create a terminal window running Vim for the test with mouse disabled + let prev_win = win_getid() let buf = RunVimInTerminal('Xtest_modeless -n', {}) call term_sendkeys(buf, ":set nocompatible\<CR>") call term_sendkeys(buf, ":set mouse=\<CR>") call term_wait(buf) redraw! + " Use the mouse to enter the terminal window + call win_gotoid(prev_win) + call feedkeys(MouseLeftClickCode(1, 1), 'x') + call feedkeys(MouseLeftReleaseCode(1, 1), 'x') + call term_wait(buf) + call assert_equal(1, getwininfo(win_getid())[0].terminal) + " Test for copying a modeless selection to clipboard let @* = 'clean' " communicating with X server may take a little time @@ -2881,8 +2902,8 @@ func Test_term_modeless_selection() let &term = save_term let &ttymouse = save_ttymouse set mousetime& clipboard& - call test_override('no_query_mouse', 0) call delete('Xtest_modeless') + new | only! endfunc " vim: shiftwidth=2 sts=2 expandtab diff --git a/src/version.c b/src/version.c index 565ebbbcb3..ad904970ea 100644 --- a/src/version.c +++ b/src/version.c @@ -746,6 +746,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 808, /**/ 807, /**/ From 5a80f8ad5dc0b2cc63400255dcf3c63f6c1a2ef9 Mon Sep 17 00:00:00 2001 From: Bram Moolenaar <Bram@vim.org> Date: Fri, 22 May 2020 13:38:18 +0200 Subject: [PATCH 208/230] patch 8.2.0809: build failure with small features Problem: Build failure with small features. (Tony Mechelynck) Solution: Move "expr" inside #ifdef. --- src/map.c | 13 ++++++------- src/version.c | 2 ++ 2 files changed, 8 insertions(+), 7 deletions(-) diff --git a/src/map.c b/src/map.c index 34a956e0be..6f926852d0 100644 --- a/src/map.c +++ b/src/map.c @@ -211,13 +211,13 @@ map_add( char_u *keys, char_u *rhs, char_u *orig_rhs, - int expr, int noremap, int nowait, int silent, int mode, int is_abbr, #ifdef FEAT_EVAL + int expr, scid_T sid, // -1 to use current_sctx linenr_T lnum, #endif @@ -839,11 +839,10 @@ do_map( continue; // have added the new entry already // Get here when adding a new entry to the maphash[] list or abbrlist. - if (map_add(map_table, abbr_table, keys, rhs, orig_rhs, expr, - noremap, nowait, silent, mode, - abbrev, + if (map_add(map_table, abbr_table, keys, rhs, orig_rhs, + noremap, nowait, silent, mode, abbrev, #ifdef FEAT_EVAL - /* sid */ -1, /* lnum */ 0, + expr, /* sid */ -1, /* lnum */ 0, #endif did_simplify && keyround == 1) == FAIL) { @@ -2331,8 +2330,8 @@ f_mapset(typval_T *argvars, typval_T *rettv UNUSED) keys = replace_termcodes(lhs, &keys_buf, REPTERM_FROM_PART | REPTERM_DO_LT, NULL); - (void)map_add(map_table, abbr_table, keys, rhs, rhs, expr, - noremap, nowait, silent, mode, is_abbr, sid, lnum, simplified); + (void)map_add(map_table, abbr_table, keys, rhs, rhs, noremap, + nowait, silent, mode, is_abbr, expr, sid, lnum, simplified); vim_free(keys_buf); } #endif diff --git a/src/version.c b/src/version.c index ad904970ea..1ca9dee70b 100644 --- a/src/version.c +++ b/src/version.c @@ -746,6 +746,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 809, /**/ 808, /**/ From 2e61e2d08390623fcf933fd06646ac91f81fb772 Mon Sep 17 00:00:00 2001 From: Bram Moolenaar <Bram@vim.org> Date: Fri, 22 May 2020 14:10:36 +0200 Subject: [PATCH 209/230] patch 8.2.0810: error when appending "tagfile" to 'wildoptions' Problem: Error when appending "tagfile" to 'wildoptions'. Solution: use flags P_ONECOMMA and P_NODUP. (Dmitri Vereshchagin, closes #6105) --- src/optiondefs.h | 2 +- src/testdir/test_options.vim | 7 +++++++ src/version.c | 2 ++ 3 files changed, 10 insertions(+), 1 deletion(-) diff --git a/src/optiondefs.h b/src/optiondefs.h index 36701070dd..374764be6b 100644 --- a/src/optiondefs.h +++ b/src/optiondefs.h @@ -2837,7 +2837,7 @@ static struct vimoption options[] = {"wildmode", "wim", P_STRING|P_VI_DEF|P_ONECOMMA|P_NODUP, (char_u *)&p_wim, PV_NONE, {(char_u *)"full", (char_u *)0L} SCTX_INIT}, - {"wildoptions", "wop", P_STRING|P_VI_DEF, + {"wildoptions", "wop", P_STRING|P_VI_DEF|P_ONECOMMA|P_NODUP, (char_u *)&p_wop, PV_NONE, {(char_u *)"", (char_u *)0L} SCTX_INIT}, diff --git a/src/testdir/test_options.vim b/src/testdir/test_options.vim index ce925d8172..17ae09496b 100644 --- a/src/testdir/test_options.vim +++ b/src/testdir/test_options.vim @@ -60,6 +60,13 @@ func Test_wildchar() set wildchar& endfunc +func Test_wildoptions() + set wildoptions= + set wildoptions+=tagfile + set wildoptions+=tagfile + call assert_equal('tagfile', &wildoptions) +endfunc + func Test_options_command() let caught = 'ok' try diff --git a/src/version.c b/src/version.c index 1ca9dee70b..9e8ba9288e 100644 --- a/src/version.c +++ b/src/version.c @@ -746,6 +746,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 810, /**/ 809, /**/ From 9cdcd1d0dc3bbea41b731639fd2431c2ef5cffaa Mon Sep 17 00:00:00 2001 From: Bram Moolenaar <Bram@vim.org> Date: Fri, 22 May 2020 14:44:26 +0200 Subject: [PATCH 210/230] patch 8.2.0811: terminal keycode test is flaky Problem: Terminal keycode test is flaky. Solution: Use WaitForAssert() --- src/testdir/test_terminal.vim | 12 +++++------- src/version.c | 2 ++ 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/testdir/test_terminal.vim b/src/testdir/test_terminal.vim index 395de5207b..bb9cdc7736 100644 --- a/src/testdir/test_terminal.vim +++ b/src/testdir/test_terminal.vim @@ -2493,6 +2493,7 @@ func Test_terminal_in_popup() call term_sendkeys(buf, ":call OpenTerm(1)\<CR>") call TermWait(buf, 150) call term_sendkeys(buf, ":set hlsearch\<CR>") + call TermWait(buf, 100) call term_sendkeys(buf, "/edit\<CR>") call VerifyScreenDump(buf, 'Test_terminal_popup_3', {}) @@ -2517,7 +2518,7 @@ func Test_terminal_in_popup() call TermWait(buf, 50) call term_sendkeys(buf, ":q\<CR>") - call TermWait(buf, 100) " wait for terminal to vanish + call TermWait(buf, 150) " wait for terminal to vanish call StopVimInTerminal(buf) call delete('Xtext') @@ -2704,8 +2705,7 @@ func Test_term_keycode_translation() call term_sendkeys(buf, "i") for i in range(len(keys)) call term_sendkeys(buf, "\<C-U>\<C-K>" .. keys[i]) - call term_wait(buf) - call assert_equal(output[i], term_getline(buf, 1)) + call WaitForAssert({-> assert_equal(output[i], term_getline(buf, 1))}) endfor let keypad_keys = ["\<k0>", "\<k1>", "\<k2>", "\<k3>", "\<k4>", "\<k5>", @@ -2720,13 +2720,11 @@ func Test_term_keycode_translation() continue endif call term_sendkeys(buf, "\<C-U>" .. keypad_keys[i]) - call term_wait(buf) - call assert_equal(keypad_output[i], term_getline(buf, 1)) + call WaitForAssert({-> assert_equal(keypad_output[i], term_getline(buf, 1))}) endfor call feedkeys("\<C-U>\<kEnter>\<BS>one\<C-W>.two", 'xt') - call term_wait(buf) - call assert_equal('two', term_getline(buf, 1)) + call WaitForAssert({-> assert_equal('two', term_getline(buf, 1))}) call StopVimInTerminal(buf) endfunc diff --git a/src/version.c b/src/version.c index 9e8ba9288e..3bd0ec468d 100644 --- a/src/version.c +++ b/src/version.c @@ -746,6 +746,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 811, /**/ 810, /**/ From c94c1467b9b86156a6b7c8d3e41ff01c13d2be07 Mon Sep 17 00:00:00 2001 From: Bram Moolenaar <Bram@vim.org> Date: Fri, 22 May 2020 20:01:06 +0200 Subject: [PATCH 211/230] patch 8.2.0812: mapset() does not properly handle <> notation Problem: mapset() does not properly handle <> notation. Solution: Convert <> codes. (closes #6116) --- src/map.c | 8 ++++- src/testdir/test_maparg.vim | 69 ++++++++++++++++++++++++++++++++++++- src/version.c | 2 ++ 3 files changed, 77 insertions(+), 2 deletions(-) diff --git a/src/map.c b/src/map.c index 6f926852d0..4a9849d334 100644 --- a/src/map.c +++ b/src/map.c @@ -2269,6 +2269,8 @@ f_mapset(typval_T *argvars, typval_T *rettv UNUSED) dict_T *d; char_u *lhs; char_u *rhs; + char_u *orig_rhs; + char_u *arg_buf = NULL; int noremap; int expr; int silent; @@ -2304,6 +2306,9 @@ f_mapset(typval_T *argvars, typval_T *rettv UNUSED) emsg(_("E99: rhs entry missing in mapset() dict argument")); return; } + orig_rhs = rhs; + rhs = replace_termcodes(rhs, &arg_buf, + REPTERM_DO_LT | REPTERM_SPECIAL, NULL); noremap = dict_get_number(d, (char_u *)"noremap") ? REMAP_NONE: 0; if (dict_get_number(d, (char_u *)"script") != 0) @@ -2330,9 +2335,10 @@ f_mapset(typval_T *argvars, typval_T *rettv UNUSED) keys = replace_termcodes(lhs, &keys_buf, REPTERM_FROM_PART | REPTERM_DO_LT, NULL); - (void)map_add(map_table, abbr_table, keys, rhs, rhs, noremap, + (void)map_add(map_table, abbr_table, keys, rhs, orig_rhs, noremap, nowait, silent, mode, is_abbr, expr, sid, lnum, simplified); vim_free(keys_buf); + vim_free(arg_buf); } #endif diff --git a/src/testdir/test_maparg.vim b/src/testdir/test_maparg.vim index 5fb8045a64..b971be46f0 100644 --- a/src/testdir/test_maparg.vim +++ b/src/testdir/test_maparg.vim @@ -6,7 +6,7 @@ func s:SID() return str2nr(matchstr(expand('<sfile>'), '<SNR>\zs\d\+\ze_SID$')) endfunc -funct Test_maparg() +func Test_maparg() new set cpo-=< set encoding=utf8 @@ -156,6 +156,73 @@ endfunc func Test_mapset() call One_mapset_test('K') call One_mapset_test('<F3>') + + " Check <> key conversion + new + inoremap K one<Left>x + call feedkeys("iK\<Esc>", 'xt') + call assert_equal('onxe', getline(1)) + + let orig = maparg('K', 'i', 0, 1) + call assert_equal('K', orig.lhs) + call assert_equal('one<Left>x', orig.rhs) + call assert_equal('i', orig.mode) + + iunmap K + let d = maparg('K', 'i', 0, 1) + call assert_equal({}, d) + + call mapset('i', 0, orig) + call feedkeys("SK\<Esc>", 'xt') + call assert_equal('onxe', getline(1)) + + iunmap K + + " Test literal <CR> using a backslash + let cpo_save = &cpo + set cpo-=B + inoremap K one\<CR>two + call feedkeys("SK\<Esc>", 'xt') + call assert_equal('one<CR>two', getline(1)) + + let orig = maparg('K', 'i', 0, 1) + call assert_equal('K', orig.lhs) + call assert_equal('one\<CR>two', orig.rhs) + call assert_equal('i', orig.mode) + + iunmap K + let d = maparg('K', 'i', 0, 1) + call assert_equal({}, d) + + call mapset('i', 0, orig) + call feedkeys("SK\<Esc>", 'xt') + call assert_equal('one<CR>two', getline(1)) + + iunmap K + let &cpo = cpo_save + + " Test literal <CR> using CTRL-V + inoremap K one<CR>two + call feedkeys("SK\<Esc>", 'xt') + call assert_equal('one<CR>two', getline(1)) + + let orig = maparg('K', 'i', 0, 1) + call assert_equal('K', orig.lhs) + call assert_equal("one\x16<CR>two", orig.rhs) + call assert_equal('i', orig.mode) + + iunmap K + let d = maparg('K', 'i', 0, 1) + call assert_equal({}, d) + + call mapset('i', 0, orig) + call feedkeys("SK\<Esc>", 'xt') + call assert_equal('one<CR>two', getline(1)) + + iunmap K + let &cpo = cpo_save + + bwipe! endfunc " vim: shiftwidth=2 sts=2 expandtab diff --git a/src/version.c b/src/version.c index 3bd0ec468d..7d860b2981 100644 --- a/src/version.c +++ b/src/version.c @@ -746,6 +746,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 812, /**/ 811, /**/ From 591cec8366e87a172495c362477cbf5de8d399f0 Mon Sep 17 00:00:00 2001 From: Bram Moolenaar <Bram@vim.org> Date: Fri, 22 May 2020 22:06:06 +0200 Subject: [PATCH 212/230] patch 8.2.0813: libvterm code is slightly different from upstream Problem: libvterm code is slightly different from upstream. Solution: Use upstream text to avoid future merge problems. Mainly comment style changes. --- src/libvterm/include/vterm.h | 75 +++++++++++++++---------------- src/libvterm/src/encoding.c | 2 +- src/libvterm/src/keyboard.c | 19 ++++---- src/libvterm/src/mouse.c | 2 +- src/libvterm/src/parser.c | 18 ++++---- src/libvterm/src/pen.c | 6 +-- src/libvterm/src/rect.h | 12 ++--- src/libvterm/src/screen.c | 57 +++++++++++------------ src/libvterm/src/state.c | 36 ++++++++------- src/libvterm/src/unicode.c | 47 +++++++++---------- src/libvterm/src/utf8.h | 4 +- src/libvterm/src/vterm.c | 34 +++++++------- src/libvterm/src/vterm_internal.h | 20 ++++----- src/version.c | 2 + 14 files changed, 170 insertions(+), 164 deletions(-) diff --git a/src/libvterm/include/vterm.h b/src/libvterm/include/vterm.h index 3a174041ab..fe4a6fce82 100644 --- a/src/libvterm/include/vterm.h +++ b/src/libvterm/include/vterm.h @@ -35,9 +35,7 @@ typedef struct { int col; } VTermPos; -/* - * Some small utility functions; we can just keep these static here. - */ +/* some small utility functions; we can just keep these static here */ /* * Order points by on-screen flow order: @@ -62,7 +60,7 @@ typedef struct { int end_col; } VTermRect; -// Return true if the rect "r" contains the point "p". +/* true if the rect contains the point */ int vterm_rect_contains(VTermRect r, VTermPos p); #if defined(DEFINE_INLINES) || USE_INLINE @@ -73,6 +71,7 @@ INLINE int vterm_rect_contains(VTermRect r, VTermPos p) } #endif +/* move a rect */ // Move "rect" "row_delta" down and "col_delta" right. // Does not check boundaries. void vterm_rect_move(VTermRect *rect, int row_delta, int col_delta); @@ -185,9 +184,8 @@ void vterm_color_indexed(VTermColor *col, uint8_t idx); */ int vterm_color_is_equal(const VTermColor *a, const VTermColor *b); - typedef enum { - // VTERM_VALUETYPE_NONE = 0 + /* VTERM_VALUETYPE_NONE = 0 */ VTERM_VALUETYPE_BOOL = 1, VTERM_VALUETYPE_INT, VTERM_VALUETYPE_STRING, @@ -211,7 +209,7 @@ typedef union { } VTermValue; typedef enum { - // VTERM_ATTR_NONE = 0 + /* VTERM_ATTR_NONE = 0 */ VTERM_ATTR_BOLD = 1, // bool: 1, 22 VTERM_ATTR_UNDERLINE, // number: 4, 21, 24 VTERM_ATTR_ITALIC, // bool: 3, 23 @@ -227,7 +225,7 @@ typedef enum { } VTermAttr; typedef enum { - // VTERM_PROP_NONE = 0 + /* VTERM_PROP_NONE = 0 */ VTERM_PROP_CURSORVISIBLE = 1, // bool VTERM_PROP_CURSORBLINK, // bool VTERM_PROP_ALTSCREEN, // bool @@ -261,9 +259,9 @@ enum { typedef struct { const uint32_t *chars; int width; - unsigned int protected_cell:1; // DECSCA-protected against DECSEL/DECSED - unsigned int dwl:1; // DECDWL or DECDHL double-width line - unsigned int dhl:2; // DECDHL double-height line (1=top 2=bottom) + unsigned int protected_cell:1; /* DECSCA-protected against DECSEL/DECSED */ + unsigned int dwl:1; /* DECDWL or DECDHL double-width line */ + unsigned int dhl:2; /* DECDHL double-height line (1=top 2=bottom) */ } VTermGlyphInfo; typedef struct { @@ -272,9 +270,18 @@ typedef struct { unsigned int continuation:1; /* Line is a flow continuation of the previous */ } VTermLineInfo; +/* Copies of VTermState fields that the 'resize' callback might have reason to + * edit. 'resize' callback gets total control of these fields and may + * free-and-reallocate them if required. They will be copied back from the + * struct after the callback has returned. + */ typedef struct { - // libvterm relies on the allocated memory to be zeroed out before it is - // returned by the allocator. + VTermPos pos; /* current cursor position */ +} VTermStateFields; + +typedef struct { + /* libvterm relies on this memory to be zeroed out before it is returned + * by the allocator. */ void *(*malloc)(size_t size, void *allocdata); void (*free)(void *ptr, void *allocdata); } VTermAllocatorFunctions; @@ -329,20 +336,21 @@ void vterm_mouse_button(VTerm *vt, int button, int pressed, VTermModifier mod); // Parser layer // ------------ -// Flag to indicate non-final subparameters in a single CSI parameter. -// Consider -// CSI 1;2:3:4;5a -// 1 4 and 5 are final. -// 2 and 3 are non-final and will have this bit set -// -// Don't confuse this with the final byte of the CSI escape; 'a' in this case. +/* Flag to indicate non-final subparameters in a single CSI parameter. + * Consider + * CSI 1;2:3:4;5a + * 1 4 and 5 are final. + * 2 and 3 are non-final and will have this bit set + * + * Don't confuse this with the final byte of the CSI escape; 'a' in this case. + */ #define CSI_ARG_FLAG_MORE (1U<<31) #define CSI_ARG_MASK (~(1U<<31)) #define CSI_ARG_HAS_MORE(a) ((a) & CSI_ARG_FLAG_MORE) #define CSI_ARG(a) ((a) & CSI_ARG_MASK) -// Can't use -1 to indicate a missing argument; use this instead +/* Can't use -1 to indicate a missing argument; use this instead */ #define CSI_ARG_MISSING ((1<<30)-1) #define CSI_ARG_IS_MISSING(a) (CSI_ARG(a) == CSI_ARG_MISSING) @@ -366,15 +374,6 @@ void *vterm_parser_get_cbdata(VTerm *vt); // State layer // ----------- -/* Copies of VTermState fields that the 'resize' callback might have reason to - * edit. 'resize' callback gets total control of these fields and may - * free-and-reallocate them if required. They will be copied back from the - * struct after the callback has returned. - */ -typedef struct { - VTermPos pos; /* current cursor position */ -} VTermStateFields; - typedef struct { int (*putglyph)(VTermGlyphInfo *info, VTermPos pos, void *user); int (*movecursor)(VTermPos pos, VTermPos oldpos, int visible, void *user); @@ -459,9 +458,9 @@ typedef struct { unsigned int reverse : 1; unsigned int conceal : 1; unsigned int strike : 1; - unsigned int font : 4; // 0 to 9 - unsigned int dwl : 1; // On a DECDWL or DECDHL line - unsigned int dhl : 2; // On a DECDHL line (1=top 2=bottom) + unsigned int font : 4; /* 0 to 9 */ + unsigned int dwl : 1; /* On a DECDWL or DECDHL line */ + unsigned int dhl : 2; /* On a DECDHL line (1=top 2=bottom) */ } VTermScreenCellAttrs; enum { @@ -513,10 +512,10 @@ void *vterm_screen_get_unrecognised_fbdata(VTermScreen *screen); void vterm_screen_enable_altscreen(VTermScreen *screen, int altscreen); typedef enum { - VTERM_DAMAGE_CELL, // every cell - VTERM_DAMAGE_ROW, // entire rows - VTERM_DAMAGE_SCREEN, // entire screen - VTERM_DAMAGE_SCROLL, // entire screen + scrollrect + VTERM_DAMAGE_CELL, /* every cell */ + VTERM_DAMAGE_ROW, /* entire rows */ + VTERM_DAMAGE_SCREEN, /* entire screen */ + VTERM_DAMAGE_SCROLL, /* entire screen + scrollrect */ VTERM_N_DAMAGES } VTermDamageSize; @@ -532,7 +531,7 @@ void vterm_screen_set_damage_merge(VTermScreen *screen, VTermDamageSize size); */ void vterm_screen_reset(VTermScreen *screen, int hard); -// Neither of these functions NUL-terminate the buffer +/* Neither of these functions NUL-terminate the buffer */ size_t vterm_screen_get_chars(const VTermScreen *screen, uint32_t *chars, size_t len, const VTermRect rect); size_t vterm_screen_get_text(const VTermScreen *screen, char *str, size_t len, const VTermRect rect); diff --git a/src/libvterm/src/encoding.c b/src/libvterm/src/encoding.c index 623b14f2ac..694ed6a0ca 100644 --- a/src/libvterm/src/encoding.c +++ b/src/libvterm/src/encoding.c @@ -223,7 +223,7 @@ encodings[] = { { 0, 0, NULL }, }; -// This ought to be INTERNAL but isn't because it's used by unit testing +/* This ought to be INTERNAL but isn't because it's used by unit testing */ VTermEncoding *vterm_lookup_encoding(VTermEncodingType type, char designation) { int i; diff --git a/src/libvterm/src/keyboard.c b/src/libvterm/src/keyboard.c index 9c2a53d7b1..87288fe970 100644 --- a/src/libvterm/src/keyboard.c +++ b/src/libvterm/src/keyboard.c @@ -19,8 +19,9 @@ void vterm_keyboard_unichar(VTerm *vt, uint32_t c, VTermModifier mod) return; } - // The shift modifier is never important for Unicode characters - // apart from Space + /* The shift modifier is never important for Unicode characters + * apart from Space + */ if(c != ' ') mod &= ~VTERM_MOD_SHIFT; @@ -33,24 +34,24 @@ void vterm_keyboard_unichar(VTerm *vt, uint32_t c, VTermModifier mod) } switch(c) { - // Special Ctrl- letters that can't be represented elsewise + /* Special Ctrl- letters that can't be represented elsewise */ case 'i': case 'j': case 'm': case '[': needs_CSIu = 1; break; - // Ctrl-\ ] ^ _ don't need CSUu + /* Ctrl-\ ] ^ _ don't need CSUu */ case '\\': case ']': case '^': case '_': needs_CSIu = 0; break; - // Shift-space needs CSIu + /* Shift-space needs CSIu */ case ' ': needs_CSIu = !!(mod & VTERM_MOD_SHIFT); break; - // All other characters needs CSIu except for letters a-z + /* All other characters needs CSIu except for letters a-z */ default: needs_CSIu = (c < 'a' || c > 'z'); } - // ALT we can just prefix with ESC; anything else requires CSI u + /* ALT we can just prefix with ESC; anything else requires CSI u */ if(needs_CSIu && (mod & ~VTERM_MOD_ALT)) { vterm_push_output_sprintf_ctrl(vt, C1_CSI, "%d;%du", c, mod+1); return; @@ -165,7 +166,7 @@ void vterm_keyboard_key(VTerm *vt, VTermKey key, VTermModifier mod) break; case KEYCODE_TAB: - // Shift-Tab is CSI Z but plain Tab is 0x09 + /* Shift-Tab is CSI Z but plain Tab is 0x09 */ if(mod == VTERM_MOD_SHIFT) vterm_push_output_sprintf_ctrl(vt, C1_CSI, "Z"); else if(mod & VTERM_MOD_SHIFT) @@ -175,7 +176,7 @@ void vterm_keyboard_key(VTerm *vt, VTermKey key, VTermModifier mod) break; case KEYCODE_ENTER: - // Enter is CRLF in newline mode, but just LF in linefeed + /* Enter is CRLF in newline mode, but just LF in linefeed */ if(vt->state->mode.newline) vterm_push_output_sprintf(vt, "\r\n"); else diff --git a/src/libvterm/src/mouse.c b/src/libvterm/src/mouse.c index ae74cfc4bb..4e363134eb 100644 --- a/src/libvterm/src/mouse.c +++ b/src/libvterm/src/mouse.c @@ -83,7 +83,7 @@ void vterm_mouse_button(VTerm *vt, int button, int pressed, VTermModifier mod) state->mouse_buttons &= ~(1 << (button-1)); } - // Most of the time we don't get button releases from 4/5 + /* Most of the time we don't get button releases from 4/5 */ if(state->mouse_buttons == old_buttons && button < 4) return; if (!(state->mouse_flags & MOUSE_WANT_CLICK)) diff --git a/src/libvterm/src/parser.c b/src/libvterm/src/parser.c index fef5bd3ad2..490f5ce1bb 100644 --- a/src/libvterm/src/parser.c +++ b/src/libvterm/src/parser.c @@ -34,7 +34,7 @@ static void do_csi(VTerm *vt, char command) if(vt->parser.callbacks && vt->parser.callbacks->csi) if((*vt->parser.callbacks->csi)( - vt->parser.v.csi.leaderlen ? vt->parser.v.csi.leader : NULL, + vt->parser.v.csi.leaderlen ? vt->parser.v.csi.leader : NULL, vt->parser.v.csi.args, vt->parser.v.csi.argi, vt->parser.intermedlen ? vt->parser.intermed : NULL, @@ -187,23 +187,23 @@ size_t vterm_input_write(VTerm *vt, const char *bytes, size_t len) switch(vt->parser.state) { case CSI_LEADER: - // Extract leader bytes 0x3c to 0x3f + /* Extract leader bytes 0x3c to 0x3f */ if(c >= 0x3c && c <= 0x3f) { if(vt->parser.v.csi.leaderlen < CSI_LEADER_MAX-1) vt->parser.v.csi.leader[vt->parser.v.csi.leaderlen++] = c; break; } - // else fallthrough + /* else fallthrough */ vt->parser.v.csi.leader[vt->parser.v.csi.leaderlen] = 0; vt->parser.v.csi.argi = 0; vt->parser.v.csi.args[0] = CSI_ARG_MISSING; vt->parser.state = CSI_ARGS; - // fallthrough + /* fallthrough */ case CSI_ARGS: - // Numerical value of argument + /* Numerical value of argument */ if(c >= '0' && c <= '9') { if(vt->parser.v.csi.args[vt->parser.v.csi.argi] == CSI_ARG_MISSING) vt->parser.v.csi.args[vt->parser.v.csi.argi] = 0; @@ -221,7 +221,7 @@ size_t vterm_input_write(VTerm *vt, const char *bytes, size_t len) break; } - // else fallthrough + /* else fallthrough */ vt->parser.v.csi.argi++; vt->parser.intermedlen = 0; vt->parser.state = CSI_INTERMED; @@ -233,13 +233,13 @@ size_t vterm_input_write(VTerm *vt, const char *bytes, size_t len) break; } else if(c == 0x1b) { - // ESC in CSI cancels + /* ESC in CSI cancels */ } else if(c >= 0x40 && c <= 0x7e) { vt->parser.intermed[vt->parser.intermedlen] = 0; do_csi(vt, c); } - // else was invalid CSI + /* else was invalid CSI */ ENTER_NORMAL_STATE(); break; @@ -330,7 +330,7 @@ string_state: if(!eaten) { DEBUG_LOG("libvterm: Text callback did not consume any input\n"); - // force it to make progress + /* force it to make progress */ eaten = 1; } diff --git a/src/libvterm/src/pen.c b/src/libvterm/src/pen.c index 98c5af9269..d3738b9191 100644 --- a/src/libvterm/src/pen.c +++ b/src/libvterm/src/pen.c @@ -11,7 +11,7 @@ typedef struct { } VTermRGB; static const VTermRGB ansi_colors[] = { - // R G B + /* R G B */ { 0, 0, 0 }, // black { 224, 0, 0 }, // red { 0, 224, 0 }, // green @@ -465,12 +465,12 @@ INTERNAL void vterm_state_setpen(VTermState *state, const long args[], int argco break; } - if (!done) + if(!done) { DEBUG_LOG1("libvterm: Unhandled CSI SGR %ld\n", arg); } - while (CSI_ARG_HAS_MORE(args[argi++])) + while(CSI_ARG_HAS_MORE(args[argi++])) ; } } diff --git a/src/libvterm/src/rect.h b/src/libvterm/src/rect.h index 3c070e1cd5..2114f24c1b 100644 --- a/src/libvterm/src/rect.h +++ b/src/libvterm/src/rect.h @@ -5,7 +5,7 @@ #define STRFrect "(%d,%d-%d,%d)" #define ARGSrect(r) (r).start_row, (r).start_col, (r).end_row, (r).end_col -// Expand dst to contain src as well +/* Expand dst to contain src as well */ static void rect_expand(VTermRect *dst, VTermRect *src) { if(dst->start_row > src->start_row) dst->start_row = src->start_row; @@ -14,19 +14,19 @@ static void rect_expand(VTermRect *dst, VTermRect *src) if(dst->end_col < src->end_col) dst->end_col = src->end_col; } -// Clip the dst to ensure it does not step outside of bounds +/* Clip the dst to ensure it does not step outside of bounds */ static void rect_clip(VTermRect *dst, VTermRect *bounds) { if(dst->start_row < bounds->start_row) dst->start_row = bounds->start_row; if(dst->start_col < bounds->start_col) dst->start_col = bounds->start_col; if(dst->end_row > bounds->end_row) dst->end_row = bounds->end_row; if(dst->end_col > bounds->end_col) dst->end_col = bounds->end_col; - // Ensure it doesn't end up negatively-sized + /* Ensure it doesn't end up negatively-sized */ if(dst->end_row < dst->start_row) dst->end_row = dst->start_row; if(dst->end_col < dst->start_col) dst->end_col = dst->start_col; } -// True if the two rectangles are equal +/* True if the two rectangles are equal */ static int rect_equal(VTermRect *a, VTermRect *b) { return (a->start_row == b->start_row) && @@ -35,7 +35,7 @@ static int rect_equal(VTermRect *a, VTermRect *b) (a->end_col == b->end_col); } -// True if small is contained entirely within big +/* True if small is contained entirely within big */ static int rect_contains(VTermRect *big, VTermRect *small) { if(small->start_row < big->start_row) return 0; @@ -45,7 +45,7 @@ static int rect_contains(VTermRect *big, VTermRect *small) return 1; } -// True if the rectangles overlap at all +/* True if the rectangles overlap at all */ static int rect_intersects(VTermRect *a, VTermRect *b) { if(a->start_row > b->end_row || b->start_row > a->end_row) diff --git a/src/libvterm/src/screen.c b/src/libvterm/src/screen.c index ea551f9f4b..3e72e4bbe6 100644 --- a/src/libvterm/src/screen.c +++ b/src/libvterm/src/screen.c @@ -10,10 +10,10 @@ #define UNICODE_SPACE 0x20 #define UNICODE_LINEFEED 0x0a -// State of the pen at some moment in time, also used in a cell +/* State of the pen at some moment in time, also used in a cell */ typedef struct { - // After the bitfield + /* After the bitfield */ VTermColor fg, bg; unsigned int bold : 1; @@ -23,15 +23,15 @@ typedef struct unsigned int reverse : 1; unsigned int conceal : 1; unsigned int strike : 1; - unsigned int font : 4; // 0 to 9 + unsigned int font : 4; /* 0 to 9 */ - // Extra state storage that isn't strictly pen-related + /* Extra state storage that isn't strictly pen-related */ unsigned int protected_cell : 1; - unsigned int dwl : 1; // on a DECDWL or DECDHL line - unsigned int dhl : 2; // on a DECDHL line (1=top 2=bottom) + unsigned int dwl : 1; /* on a DECDWL or DECDHL line */ + unsigned int dhl : 2; /* on a DECDHL line (1=top 2=bottom) */ } ScreenPen; -// Internal representation of a screen cell +/* Internal representation of a screen cell */ typedef struct { uint32_t chars[VTERM_MAX_CHARS_PER_CELL]; @@ -47,7 +47,7 @@ struct VTermScreen void *cbdata; VTermDamageSize damage_merge; - // start_row == -1 => no damage + /* start_row == -1 => no damage */ VTermRect damaged; VTermRect pending_scrollrect; int pending_scroll_downward, pending_scroll_rightward; @@ -56,13 +56,13 @@ struct VTermScreen int cols; int global_reverse; - // Primary and Altscreen. buffers[1] is lazily allocated as needed + /* Primary and Altscreen. buffers[1] is lazily allocated as needed */ ScreenCell *buffers[2]; - // buffer will == buffers[0] or buffers[1], depending on altscreen + /* buffer will == buffers[0] or buffers[1], depending on altscreen */ ScreenCell *buffer; - // buffer for a single screen row used in scrollback storage callbacks + /* buffer for a single screen row used in scrollback storage callbacks */ VTermScreenCell *sb_buffer; ScreenPen pen; @@ -106,13 +106,13 @@ static void damagerect(VTermScreen *screen, VTermRect rect) switch(screen->damage_merge) { case VTERM_DAMAGE_CELL: - // Always emit damage event + /* Always emit damage event */ emit = rect; break; case VTERM_DAMAGE_ROW: - // Emit damage longer than one row. Try to merge with existing damage in - // the same row + /* Emit damage longer than one row. Try to merge with existing damage in + * the same row */ if(rect.end_row > rect.start_row + 1) { // Bigger than 1 line - flush existing, emit this vterm_screen_flush_damage(screen); @@ -140,7 +140,7 @@ static void damagerect(VTermScreen *screen, VTermRect rect) case VTERM_DAMAGE_SCREEN: case VTERM_DAMAGE_SCROLL: - // Never emit damage event + /* Never emit damage event */ if(screen->damaged.start_row == -1) screen->damaged = rect; else { @@ -355,14 +355,15 @@ static int scrollrect(VTermRect rect, int downward, int rightward, void *user) return 1; if(rect_contains(&rect, &screen->damaged)) { - // Scroll region entirely contains the damage; just move it + /* Scroll region entirely contains the damage; just move it */ vterm_rect_move(&screen->damaged, -downward, -rightward); rect_clip(&screen->damaged, &rect); } - // There are a number of possible cases here, but lets restrict this to only - // the common case where we might actually gain some performance by - // optimising it. Namely, a vertical scroll that neatly cuts the damage - // region in half. + /* There are a number of possible cases here, but lets restrict this to only + * the common case where we might actually gain some performance by + * optimising it. Namely, a vertical scroll that neatly cuts the damage + * region in half. + */ else if(rect.start_col <= screen->damaged.start_col && rect.end_col >= screen->damaged.end_col && rightward == 0) { @@ -454,8 +455,9 @@ static int settermprop(VTermProp prop, VTermValue *val, void *user) return 0; screen->buffer = val->boolean ? screen->buffers[BUFIDX_ALTSCREEN] : screen->buffers[BUFIDX_PRIMARY]; - // only send a damage event on disable; because during enable there's an - // erase that sends a damage anyway + /* only send a damage event on disable; because during enable there's an + * erase that sends a damage anyway + */ if(!val->boolean) damagescreen(screen); break; @@ -464,7 +466,7 @@ static int settermprop(VTermProp prop, VTermValue *val, void *user) damagescreen(screen); break; default: - ; // ignore + ; /* ignore */ } if(screen->callbacks && screen->callbacks->settermprop) @@ -491,7 +493,7 @@ static void resize_buffer(VTermScreen *screen, int bufidx, int new_rows, int new ScreenCell *old_buffer = screen->buffers[bufidx]; ScreenCell *new_buffer = vterm_allocator_malloc(screen->vt, sizeof(ScreenCell) * new_rows * new_cols); - /* Find the final row of old buffer content */ + // Find the final row of old buffer content int old_row = old_rows - 1; int new_row = new_rows - 1; int col; @@ -573,10 +575,8 @@ static void resize_buffer(VTermScreen *screen, int bufidx, int new_rows, int new memmove(&new_buffer[0], &new_buffer[(new_row + 1) * new_cols], moverows * new_cols * sizeof(ScreenCell)); for(new_row = moverows; new_row < new_rows; new_row++) - { for(col = 0; col < new_cols; col++) clearcell(screen, &new_buffer[new_row * new_cols + col]); - } } vterm_allocator_free(screen->vt, old_buffer); @@ -729,6 +729,7 @@ INTERNAL void vterm_screen_free(VTermScreen *screen) vterm_allocator_free(screen->vt, screen->buffers[BUFIDX_ALTSCREEN]); vterm_allocator_free(screen->vt, screen->sb_buffer); + vterm_allocator_free(screen->vt, screen); } @@ -802,7 +803,7 @@ size_t vterm_screen_get_text(const VTermScreen *screen, char *str, size_t len, c return _get_chars(screen, 1, str, len, rect); } -// Copy internal to external representation of a screen cell +/* Copy internal to external representation of a screen cell */ int vterm_screen_get_cell(const VTermScreen *screen, VTermPos pos, VTermScreenCell *cell) { ScreenCell *intcell = getcell(screen, pos.row, pos.col); @@ -860,7 +861,7 @@ int vterm_screen_get_cell(const VTermScreen *screen, VTermPos pos, VTermScreenCe int vterm_screen_is_eol(const VTermScreen *screen, VTermPos pos) { - // This cell is EOL if this and every cell to the right is black + /* This cell is EOL if this and every cell to the right is black */ for(; pos.col < screen->cols; pos.col++) { ScreenCell *cell = getcell(screen, pos.row, pos.col); if(cell->chars[0] != 0) diff --git a/src/libvterm/src/state.c b/src/libvterm/src/state.c index 1fff43ce3f..a621822333 100644 --- a/src/libvterm/src/state.c +++ b/src/libvterm/src/state.c @@ -11,7 +11,7 @@ static int on_resize(int rows, int cols, void *user); -// Some convenient wrappers to make callback functions easier +/* Some convenient wrappers to make callback functions easier */ static void putglyph(VTermState *state, const uint32_t chars[], int width, VTermPos pos) { @@ -299,8 +299,9 @@ static int on_text(const char bytes[], size_t len, void *user) codepoints, &npoints, state->gsingle_set ? 1 : (int)len, bytes, &eaten, len); - // There's a chance an encoding (e.g. UTF-8) hasn't found enough bytes yet - // for even a single codepoint + /* There's a chance an encoding (e.g. UTF-8) hasn't found enough bytes yet + * for even a single codepoint + */ if(!npoints) { vterm_allocator_free(state->vt, codepoints); @@ -310,10 +311,10 @@ static int on_text(const char bytes[], size_t len, void *user) if(state->gsingle_set && npoints) state->gsingle_set = 0; - // This is a combining char. that needs to be merged with the previous - // glyph output + /* This is a combining char. that needs to be merged with the previous + * glyph output */ if(vterm_unicode_is_combining(codepoints[i])) { - // See if the cursor has moved since + /* See if the cursor has moved since */ if(state->pos.row == state->combine_pos.row && state->pos.col == state->combine_pos.col + state->combine_width) { #ifdef DEBUG_GLYPH_COMBINE int printpos; @@ -323,12 +324,12 @@ static int on_text(const char bytes[], size_t len, void *user) printf("} + {"); #endif - // Find where we need to append these combining chars + /* Find where we need to append these combining chars */ int saved_i = 0; while(state->combine_chars[saved_i]) saved_i++; - // Add extra ones + /* Add extra ones */ while(i < npoints && vterm_unicode_is_combining(codepoints[i])) { if(saved_i >= (int)state->combine_chars_size) grow_combine_buffer(state); @@ -344,7 +345,7 @@ static int on_text(const char bytes[], size_t len, void *user) printf("}\n"); #endif - // Now render it + /* Now render it */ putglyph(state, state->combine_chars, state->combine_width, state->combine_pos); } else { @@ -418,8 +419,8 @@ static int on_text(const char bytes[], size_t len, void *user) putglyph(state, chars, width, state->pos); if(i == npoints - 1) { - // End of the buffer. Save the chars in case we have to combine with - // more on the next call + /* End of the buffer. Save the chars in case we have to combine with + * more on the next call */ int save_i; for(save_i = 0; chars[save_i]; save_i++) { if(save_i >= (int)state->combine_chars_size) @@ -619,8 +620,9 @@ static int on_escape(const char *bytes, size_t len, void *user) { VTermState *state = user; - // Easier to decode this from the first byte, even though the final - // byte terminates it + /* Easier to decode this from the first byte, even though the final + * byte terminates it + */ switch(bytes[0]) { case ' ': if(len != 2) @@ -1338,7 +1340,7 @@ static int on_csi(const char *leader, const long args[], int argcount, const cha case 2: case 4: break; - // TODO: 1, 2 and 4 aren't meaningful yet without line tab stops + /* TODO: 1, 2 and 4 aren't meaningful yet without line tab stops */ default: return 0; } @@ -1773,7 +1775,7 @@ static int on_resize(int rows, int cols, void *user) if (newtabstops == NULL) return 0; - // TODO: This can all be done much more efficiently bytewise + /* TODO: This can all be done much more efficiently bytewise */ for(col = 0; col < state->cols && col < cols; col++) { unsigned char mask = 1 << (col & 7); if(state->tabstops[col >> 3] & mask) @@ -2012,8 +2014,8 @@ void *vterm_state_get_unrecognised_fbdata(VTermState *state) int vterm_state_set_termprop(VTermState *state, VTermProp prop, VTermValue *val) { - // Only store the new value of the property if usercode said it was happy. - // This is especially important for altscreen switching + /* Only store the new value of the property if usercode said it was happy. + * This is especially important for altscreen switching */ if(state->callbacks && state->callbacks->settermprop) if(!(*state->callbacks->settermprop)(prop, val, state->cbdata)) return 0; diff --git a/src/libvterm/src/unicode.c b/src/libvterm/src/unicode.c index 1c0b2db3a1..651e5552c6 100644 --- a/src/libvterm/src/unicode.c +++ b/src/libvterm/src/unicode.c @@ -1,11 +1,10 @@ #include "vterm_internal.h" -/* ### The following from http://www.cl.cam.ac.uk/~mgk25/ucs/wcwidth.c - * With modifications: - * made functions static - * moved 'combining' table to file scope, so other functions can see it - * ################################################################### - */ +// ### The following from http://www.cl.cam.ac.uk/~mgk25/ucs/wcwidth.c +// With modifications: +// made functions static +// moved 'combining' table to file scope, so other functions can see it +// ################################################################### /* * This is an implementation of wcwidth() and wcswidth() (defined in @@ -75,8 +74,8 @@ struct interval { #if !defined(WCWIDTH_FUNCTION) || !defined(IS_COMBINING_FUNCTION) -// sorted list of non-overlapping intervals of non-spacing characters -// generated by "uniset +cat=Me +cat=Mn +cat=Cf -00AD +1160-11FF +200B c" +/* sorted list of non-overlapping intervals of non-spacing characters */ +/* generated by "uniset +cat=Me +cat=Mn +cat=Cf -00AD +1160-11FF +200B c" */ // Replaced by the combining table from Vim. static const struct interval combining[] = { {0X0300, 0X036F}, @@ -362,7 +361,7 @@ static const struct interval combining[] = { }; #endif -// auxiliary function for binary search in interval table +/* auxiliary function for binary search in interval table */ static int bisearch(uint32_t ucs, const struct interval *table, int max) { int min = 0; int mid; @@ -382,6 +381,7 @@ static int bisearch(uint32_t ucs, const struct interval *table, int max) { return 0; } + /* The following two functions define the column width of an ISO 10646 * character as follows: * @@ -422,30 +422,30 @@ int WCWIDTH_FUNCTION(uint32_t ucs); static int mk_wcwidth(uint32_t ucs) { - // test for 8-bit control characters + /* test for 8-bit control characters */ if (ucs == 0) return 0; if (ucs < 32 || (ucs >= 0x7f && ucs < 0xa0)) return -1; - // binary search in table of non-spacing characters + /* binary search in table of non-spacing characters */ if (bisearch(ucs, combining, sizeof(combining) / sizeof(struct interval) - 1)) return 0; - // if we arrive here, ucs is not a combining or C0/C1 control character + /* if we arrive here, ucs is not a combining or C0/C1 control character */ - return 1 + + return 1 + (ucs >= 0x1100 && - (ucs <= 0x115f || // Hangul Jamo init. consonants + (ucs <= 0x115f || /* Hangul Jamo init. consonants */ ucs == 0x2329 || ucs == 0x232a || (ucs >= 0x2e80 && ucs <= 0xa4cf && - ucs != 0x303f) || // CJK ... Yi - (ucs >= 0xac00 && ucs <= 0xd7a3) || // Hangul Syllables - (ucs >= 0xf900 && ucs <= 0xfaff) || // CJK Compatibility Ideographs - (ucs >= 0xfe10 && ucs <= 0xfe19) || // Vertical forms - (ucs >= 0xfe30 && ucs <= 0xfe6f) || // CJK Compatibility Forms - (ucs >= 0xff00 && ucs <= 0xff60) || // Fullwidth Forms + ucs != 0x303f) || /* CJK ... Yi */ + (ucs >= 0xac00 && ucs <= 0xd7a3) || /* Hangul Syllables */ + (ucs >= 0xf900 && ucs <= 0xfaff) || /* CJK Compatibility Ideographs */ + (ucs >= 0xfe10 && ucs <= 0xfe19) || /* Vertical forms */ + (ucs >= 0xfe30 && ucs <= 0xfe6f) || /* CJK Compatibility Forms */ + (ucs >= 0xff00 && ucs <= 0xff60) || /* Fullwidth Forms */ (ucs >= 0xffe0 && ucs <= 0xffe6) || (ucs >= 0x20000 && ucs <= 0x2fffd) || (ucs >= 0x30000 && ucs <= 0x3fffd))); @@ -479,8 +479,8 @@ static int mk_wcswidth(const uint32_t *pwcs, size_t n) static int mk_wcwidth_cjk(uint32_t ucs) { #endif - // sorted list of non-overlapping intervals of East Asian Ambiguous - // characters, generated by "uniset +WIDTH-A -cat=Me -cat=Mn -cat=Cf c" + /* sorted list of non-overlapping intervals of East Asian Ambiguous + * characters, generated by "uniset +WIDTH-A -cat=Me -cat=Mn -cat=Cf c" */ static const struct interval ambiguous[] = { { 0x00A1, 0x00A1 }, { 0x00A4, 0x00A4 }, { 0x00A7, 0x00A8 }, { 0x00AA, 0x00AA }, { 0x00AE, 0x00AE }, { 0x00B0, 0x00B4 }, @@ -537,7 +537,7 @@ static int mk_wcwidth_cjk(uint32_t ucs) }; #if 0 - // binary search in table of non-spacing characters + /* binary search in table of non-spacing characters */ if (bisearch(ucs, ambiguous, sizeof(ambiguous) / sizeof(struct interval) - 1)) return 2; @@ -545,6 +545,7 @@ static int mk_wcwidth_cjk(uint32_t ucs) return mk_wcwidth(ucs); } + static int mk_wcswidth_cjk(const uint32_t *pwcs, size_t n) { int w, width = 0; diff --git a/src/libvterm/src/utf8.h b/src/libvterm/src/utf8.h index d2538d5f82..886a1ca5a6 100644 --- a/src/libvterm/src/utf8.h +++ b/src/libvterm/src/utf8.h @@ -16,7 +16,7 @@ INLINE unsigned int utf8_seqlen(long codepoint) } #endif -// Does NOT NUL-terminate the buffer +/* Does NOT NUL-terminate the buffer */ int fill_utf8(long codepoint, char *str); #if defined(DEFINE_INLINES) || USE_INLINE @@ -44,4 +44,4 @@ INLINE int fill_utf8(long codepoint, char *str) return nbytes; } #endif -// end copy +/* end copy */ diff --git a/src/libvterm/src/vterm.c b/src/libvterm/src/vterm.c index a9fd3eda7a..0211ea1479 100644 --- a/src/libvterm/src/vterm.c +++ b/src/libvterm/src/vterm.c @@ -10,9 +10,9 @@ #include "utf8.h" -/////////////////// -// API functions // -/////////////////// +/***************** + * API functions * + *****************/ static void *default_malloc(size_t size, void *allocdata UNUSED) { @@ -39,7 +39,7 @@ VTerm *vterm_new(int rows, int cols) VTerm *vterm_new_with_allocator(int rows, int cols, VTermAllocatorFunctions *funcs, void *allocdata) { - // Need to bootstrap using the allocator function directly + /* Need to bootstrap using the allocator function directly */ VTerm *vt = (*funcs->malloc)(sizeof(VTerm), allocdata); if (vt == NULL) @@ -269,7 +269,7 @@ VTermValueType vterm_get_attr_type(VTermAttr attr) case VTERM_N_ATTRS: return 0; } - return 0; // UNREACHABLE + return 0; /* UNREACHABLE */ } VTermValueType vterm_get_prop_type(VTermProp prop) @@ -287,7 +287,7 @@ VTermValueType vterm_get_prop_type(VTermProp prop) case VTERM_N_PROPS: return 0; } - return 0; // UNREACHABLE + return 0; /* UNREACHABLE */ } void vterm_scroll_rect(VTermRect rect, @@ -302,24 +302,26 @@ void vterm_scroll_rect(VTermRect rect, if(abs(downward) >= rect.end_row - rect.start_row || abs(rightward) >= rect.end_col - rect.start_col) { - // Scroll more than area; just erase the lot + /* Scroll more than area; just erase the lot */ (*eraserect)(rect, 0, user); return; } if(rightward >= 0) { - // rect: [XXX................] - // src: [----------------] - // dest: [----------------] + /* rect: [XXX................] + * src: [----------------] + * dest: [----------------] + */ dest.start_col = rect.start_col; dest.end_col = rect.end_col - rightward; src.start_col = rect.start_col + rightward; src.end_col = rect.end_col; } else { - // rect: [................XXX] - // src: [----------------] - // dest: [----------------] + /* rect: [................XXX] + * src: [----------------] + * dest: [----------------] + */ int leftward = -rightward; dest.start_col = rect.start_col + leftward; dest.end_col = rect.end_col; @@ -375,8 +377,7 @@ void vterm_copy_cells(VTermRect dest, test_row = dest.start_row - 1; inc_row = -1; } - else { - // downward >= 0 + else /* downward >= 0 */ { init_row = dest.start_row; test_row = dest.end_row; inc_row = +1; @@ -387,8 +388,7 @@ void vterm_copy_cells(VTermRect dest, test_col = dest.start_col - 1; inc_col = -1; } - else { - // rightward >= 0 + else /* rightward >= 0 */ { init_col = dest.start_col; test_col = dest.end_col; inc_col = +1; diff --git a/src/libvterm/src/vterm_internal.h b/src/libvterm/src/vterm_internal.h index 942315d6ec..cc0c64d30a 100644 --- a/src/libvterm/src/vterm_internal.h +++ b/src/libvterm/src/vterm_internal.h @@ -55,7 +55,7 @@ struct VTermPen unsigned int reverse:1; unsigned int conceal:1; unsigned int strike:1; - unsigned int font:4; // To store 0-9 + unsigned int font:4; /* To store 0-9 */ }; struct VTermState @@ -71,20 +71,20 @@ struct VTermState int rows; int cols; - // Current cursor position + /* Current cursor position */ VTermPos pos; - int at_phantom; // True if we're on the "81st" phantom column to defer a wraparound + int at_phantom; /* True if we're on the "81st" phantom column to defer a wraparound */ int scrollregion_top; - int scrollregion_bottom; // -1 means unbounded + int scrollregion_bottom; /* -1 means unbounded */ #define SCROLLREGION_BOTTOM(state) ((state)->scrollregion_bottom > -1 ? (state)->scrollregion_bottom : (state)->rows) int scrollregion_left; #define SCROLLREGION_LEFT(state) ((state)->mode.leftrightmargin ? (state)->scrollregion_left : 0) - int scrollregion_right; // -1 means unbounded + int scrollregion_right; /* -1 means unbounded */ #define SCROLLREGION_RIGHT(state) ((state)->mode.leftrightmargin && (state)->scrollregion_right > -1 ? (state)->scrollregion_right : (state)->cols) - // Bitvector of tab stops + /* Bitvector of tab stops */ unsigned char *tabstops; /* Primary and Altscreen; lineinfos[1] is lazily allocated as needed */ @@ -95,14 +95,14 @@ struct VTermState #define ROWWIDTH(state,row) ((state)->lineinfo[(row)].doublewidth ? ((state)->cols / 2) : (state)->cols) #define THISROWWIDTH(state) ROWWIDTH(state, (state)->pos.row) - // Mouse state + /* Mouse state */ int mouse_col, mouse_row; int mouse_buttons; int mouse_flags; enum { MOUSE_X10, MOUSE_UTF8, MOUSE_SGR, MOUSE_RXVT } mouse_protocol; - // Last glyph output, for Unicode recombining purposes + /* Last glyph output, for Unicode recombining purposes */ uint32_t *combine_chars; size_t combine_chars_size; // Number of ELEMENTS in the above int combine_width; // The width of the glyph above @@ -139,7 +139,7 @@ struct VTermState unsigned int protected_cell : 1; - // Saved state under DEC mode 1048/1049 + /* Saved state under DEC mode 1048/1049 */ struct { VTermPos pos; struct VTermPen pen; @@ -211,7 +211,7 @@ struct VTerm int string_initial; } parser; - // len == malloc()ed size; cur == number of valid bytes + /* len == malloc()ed size; cur == number of valid bytes */ VTermOutputCallback *outfunc; void *outdata; diff --git a/src/version.c b/src/version.c index 7d860b2981..ce0bc486da 100644 --- a/src/version.c +++ b/src/version.c @@ -746,6 +746,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 813, /**/ 812, /**/ From 3718427ba3c28ccab30726880389e44070640d3b Mon Sep 17 00:00:00 2001 From: Bram Moolenaar <Bram@vim.org> Date: Sat, 23 May 2020 19:30:05 +0200 Subject: [PATCH 213/230] patch 8.2.0814: clang warning for implicit conversion Problem: Clang warning for implicit conversion. Solution: Add type cast. (Dominique Pelle, closes #6124) --- src/evalfunc.c | 4 ++-- src/version.c | 2 ++ 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/src/evalfunc.c b/src/evalfunc.c index 37cb72f7ee..11452ce078 100644 --- a/src/evalfunc.c +++ b/src/evalfunc.c @@ -2603,9 +2603,9 @@ f_float2nr(typval_T *argvars, typval_T *rettv) if (get_float_arg(argvars, &f) == OK) { - if (f <= -VARNUM_MAX + DBL_EPSILON) + if (f <= (float_T)-VARNUM_MAX + DBL_EPSILON) rettv->vval.v_number = -VARNUM_MAX; - else if (f >= VARNUM_MAX - DBL_EPSILON) + else if (f >= (float_T)VARNUM_MAX - DBL_EPSILON) rettv->vval.v_number = VARNUM_MAX; else rettv->vval.v_number = (varnumber_T)f; diff --git a/src/version.c b/src/version.c index ce0bc486da..34852c3699 100644 --- a/src/version.c +++ b/src/version.c @@ -746,6 +746,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 814, /**/ 813, /**/ From 9c65253fe702ea010afec11aa971acd542c35de2 Mon Sep 17 00:00:00 2001 From: Bram Moolenaar <Bram@vim.org> Date: Sun, 24 May 2020 13:10:18 +0200 Subject: [PATCH 214/230] patch 8.2.0815: maparg() does not provide enough information for mapset() Problem: maparg() does not provide enough information for mapset(). Solution: Add "lhsraw" and "lhsrawalt" items. Drop "simplified" --- runtime/doc/eval.txt | 19 ++++++++---- src/map.c | 58 ++++++++++++++++++++++++------------- src/testdir/test_maparg.vim | 48 ++++++++++++++++++++++++------ src/version.c | 2 ++ 4 files changed, 92 insertions(+), 35 deletions(-) diff --git a/runtime/doc/eval.txt b/runtime/doc/eval.txt index afda3505b1..1e0760fea2 100644 --- a/runtime/doc/eval.txt +++ b/runtime/doc/eval.txt @@ -2586,7 +2586,7 @@ maparg({name} [, {mode} [, {abbr} [, {dict}]]]) rhs of mapping {name} in mode {mode} mapcheck({name} [, {mode} [, {abbr}]]) String check for mappings matching {name} -mapset({name}, {mode}, {abbr}, {dict} +mapset({mode}, {abbr}, {dict}) none restore mapping from |maparg()| result match({expr}, {pat} [, {start} [, {count}]]) Number position where {pat} matches in {expr} @@ -6829,7 +6829,10 @@ maparg({name} [, {mode} [, {abbr} [, {dict}]]]) *maparg()* When {dict} is there and it is |TRUE| return a dictionary containing all the information of the mapping with the following items: - "lhs" The {lhs} of the mapping. + "lhs" The {lhs} of the mapping as it would be typed + "lhsraw" The {lhs} of the mapping as raw bytes + "lhsrawalt" The {lhs} of the mapping as raw bytes, alternate + form, only present when it differs from "lhsraw" "rhs" The {rhs} of the mapping as typed. "silent" 1 for a |:map-silent| mapping, else 0. "noremap" 1 if the {rhs} of the mapping is not remappable. @@ -6847,7 +6850,6 @@ maparg({name} [, {mode} [, {abbr} [, {dict}]]]) *maparg()* "lnum" The line number in "sid", zero if unknown. "nowait" Do not wait for other, longer mappings. (|:map-<nowait>|). - "simplified" The dictionary can be used to restore a mapping with |mapset()|. @@ -6897,10 +6899,11 @@ mapcheck({name} [, {mode} [, {abbr}]]) *mapcheck()* Can also be used as a |method|: > GetKey()->mapcheck('n') + mapset({mode}, {abbr}, {dict}) *mapset()* Restore a mapping from a dictionary returned by |maparg()|. - {name}, {mode} and {abbr} should be the same as for the call - to |maparg()|. + {mode} and {abbr} should be the same as for the call to + |maparg()|. *E460* {mode} is used to define the mode in which the mapping is set, not the "mode" entry in {dict}. Example for saving and restoring a mapping: > @@ -6908,7 +6911,11 @@ mapset({mode}, {abbr}, {dict}) *mapset()* nnoremap K somethingelse ... call mapset('n', 0, save_map) -< +< Note that if you are going to replace a map in several modes, + e.g. with `:map!`, you need to save the mapping for all of + them, since they can differe. + + match({expr}, {pat} [, {start} [, {count}]]) *match()* When {expr} is a |List| then this returns the index of the first item where {pat} matches. Each item is used as a diff --git a/src/map.c b/src/map.c index 4a9849d334..6c926336c1 100644 --- a/src/map.c +++ b/src/map.c @@ -2176,15 +2176,20 @@ check_map( get_maparg(typval_T *argvars, typval_T *rettv, int exact) { char_u *keys; + char_u *keys_simplified; char_u *which; char_u buf[NUMBUFLEN]; char_u *keys_buf = NULL; + char_u *alt_keys_buf = NULL; + int did_simplify = FALSE; char_u *rhs; int mode; int abbr = FALSE; int get_dict = FALSE; mapblock_T *mp; + mapblock_T *mp_simplified; int buffer_local; + int flags = REPTERM_FROM_PART | REPTERM_DO_LT; // return empty string for failure rettv->v_type = VAR_STRING; @@ -2211,10 +2216,20 @@ get_maparg(typval_T *argvars, typval_T *rettv, int exact) mode = get_map_mode(&which, 0); - keys = replace_termcodes(keys, &keys_buf, - REPTERM_FROM_PART | REPTERM_DO_LT, NULL); - rhs = check_map(keys, mode, exact, FALSE, abbr, &mp, &buffer_local); - vim_free(keys_buf); + keys_simplified = replace_termcodes(keys, &keys_buf, flags, &did_simplify); + rhs = check_map(keys_simplified, mode, exact, FALSE, abbr, + &mp, &buffer_local); + if (did_simplify) + { + // When the lhs is being simplified the not-simplified keys are + // preferred for priting, like in do_map(). + // The "rhs" and "buffer_local" values are not expected to change. + mp_simplified = mp; + (void)replace_termcodes(keys, &alt_keys_buf, + flags | REPTERM_NO_SIMPLIFY, NULL); + rhs = check_map(alt_keys_buf, mode, exact, FALSE, abbr, &mp, + &buffer_local); + } if (!get_dict) { @@ -2236,6 +2251,11 @@ get_maparg(typval_T *argvars, typval_T *rettv, int exact) dict_T *dict = rettv->vval.v_dict; dict_add_string(dict, "lhs", lhs); + vim_free(lhs); + dict_add_string(dict, "lhsraw", mp->m_keys); + if (did_simplify) + // Also add the value for the simplified entry. + dict_add_string(dict, "lhsrawalt", mp_simplified->m_keys); dict_add_string(dict, "rhs", mp->m_orig_str); dict_add_number(dict, "noremap", mp->m_noremap ? 1L : 0L); dict_add_number(dict, "script", mp->m_noremap == REMAP_SCRIPT @@ -2247,11 +2267,12 @@ get_maparg(typval_T *argvars, typval_T *rettv, int exact) dict_add_number(dict, "buffer", (long)buffer_local); dict_add_number(dict, "nowait", mp->m_nowait ? 1L : 0L); dict_add_string(dict, "mode", mapmode); - dict_add_number(dict, "simplified", mp->m_simplified); - vim_free(lhs); vim_free(mapmode); } + + vim_free(keys_buf); + vim_free(alt_keys_buf); } /* @@ -2260,7 +2281,6 @@ get_maparg(typval_T *argvars, typval_T *rettv, int exact) void f_mapset(typval_T *argvars, typval_T *rettv UNUSED) { - char_u *keys; char_u *keys_buf = NULL; char_u *which; int mode; @@ -2268,6 +2288,8 @@ f_mapset(typval_T *argvars, typval_T *rettv UNUSED) int is_abbr; dict_T *d; char_u *lhs; + char_u *lhsraw; + char_u *lhsrawalt; char_u *rhs; char_u *orig_rhs; char_u *arg_buf = NULL; @@ -2279,7 +2301,6 @@ f_mapset(typval_T *argvars, typval_T *rettv UNUSED) mapblock_T **map_table = maphash; mapblock_T **abbr_table = &first_abbr; int nowait; - int simplified; char_u *arg; which = tv_get_string_buf_chk(&argvars[0], buf); @@ -2295,15 +2316,12 @@ f_mapset(typval_T *argvars, typval_T *rettv UNUSED) // Get the values in the same order as above in get_maparg(). lhs = dict_get_string(d, (char_u *)"lhs", FALSE); - if (lhs == NULL) - { - emsg(_("E99: lhs entry missing in mapset() dict argument")); - return; - } + lhsraw = dict_get_string(d, (char_u *)"lhsraw", FALSE); + lhsrawalt = dict_get_string(d, (char_u *)"lhsrawalt", FALSE); rhs = dict_get_string(d, (char_u *)"rhs", FALSE); - if (rhs == NULL) + if (lhs == NULL || lhsraw == NULL || rhs == NULL) { - emsg(_("E99: rhs entry missing in mapset() dict argument")); + emsg(_("E460: entries missing in mapset() dict argument")); return; } orig_rhs = rhs; @@ -2324,7 +2342,6 @@ f_mapset(typval_T *argvars, typval_T *rettv UNUSED) } nowait = dict_get_number(d, (char_u *)"nowait") != 0; // mode from the dict is not used - simplified = dict_get_number(d, (char_u *)"simplified") != 0; // Delete any existing mapping for this lhs and mode. arg = vim_strsave(lhs); @@ -2333,10 +2350,11 @@ f_mapset(typval_T *argvars, typval_T *rettv UNUSED) do_map(1, arg, mode, is_abbr); vim_free(arg); - keys = replace_termcodes(lhs, &keys_buf, - REPTERM_FROM_PART | REPTERM_DO_LT, NULL); - (void)map_add(map_table, abbr_table, keys, rhs, orig_rhs, noremap, - nowait, silent, mode, is_abbr, expr, sid, lnum, simplified); + (void)map_add(map_table, abbr_table, lhsraw, rhs, orig_rhs, noremap, + nowait, silent, mode, is_abbr, expr, sid, lnum, 0); + if (lhsrawalt != NULL) + (void)map_add(map_table, abbr_table, lhsrawalt, rhs, orig_rhs, noremap, + nowait, silent, mode, is_abbr, expr, sid, lnum, 1); vim_free(keys_buf); vim_free(arg_buf); } diff --git a/src/testdir/test_maparg.vim b/src/testdir/test_maparg.vim index b971be46f0..81e057adca 100644 --- a/src/testdir/test_maparg.vim +++ b/src/testdir/test_maparg.vim @@ -17,24 +17,28 @@ func Test_maparg() vnoremap <script> <buffer> <expr> <silent> bar isbar call assert_equal("is<F4>foo", maparg('foo<C-V>')) call assert_equal({'silent': 0, 'noremap': 0, 'script': 0, 'lhs': 'foo<C-V>', + \ 'lhsraw': "foo\x80\xfc\x04V", 'lhsrawalt': "foo\x16", \ 'mode': ' ', 'nowait': 0, 'expr': 0, 'sid': sid, 'lnum': lnum + 1, - \ 'simplified': 1, 'rhs': 'is<F4>foo', 'buffer': 0}, + \ 'rhs': 'is<F4>foo', 'buffer': 0}, \ maparg('foo<C-V>', '', 0, 1)) - call assert_equal({'silent': 1, 'noremap': 1, 'script': 1, 'lhs': 'bar', 'mode': 'v', + call assert_equal({'silent': 1, 'noremap': 1, 'script': 1, 'lhs': 'bar', + \ 'lhsraw': 'bar', 'mode': 'v', \ 'nowait': 0, 'expr': 1, 'sid': sid, 'lnum': lnum + 2, - \ 'simplified': 0, 'rhs': 'isbar', 'buffer': 1}, + \ 'rhs': 'isbar', 'buffer': 1}, \ 'bar'->maparg('', 0, 1)) let lnum = expand('<sflnum>') map <buffer> <nowait> foo bar - call assert_equal({'silent': 0, 'noremap': 0, 'script': 0, 'lhs': 'foo', 'mode': ' ', + call assert_equal({'silent': 0, 'noremap': 0, 'script': 0, 'lhs': 'foo', + \ 'lhsraw': 'foo', 'mode': ' ', \ 'nowait': 1, 'expr': 0, 'sid': sid, 'lnum': lnum + 1, 'rhs': 'bar', - \ 'simplified': 0, 'buffer': 1}, + \ 'buffer': 1}, \ maparg('foo', '', 0, 1)) let lnum = expand('<sflnum>') tmap baz foo - call assert_equal({'silent': 0, 'noremap': 0, 'script': 0, 'lhs': 'baz', 'mode': 't', + call assert_equal({'silent': 0, 'noremap': 0, 'script': 0, 'lhs': 'baz', + \ 'lhsraw': 'baz', 'mode': 't', \ 'nowait': 0, 'expr': 0, 'sid': sid, 'lnum': lnum + 1, 'rhs': 'foo', - \ 'simplified': 0, 'buffer': 0}, + \ 'buffer': 0}, \ maparg('baz', 't', 0, 1)) map abc x<char-114>x @@ -199,7 +203,6 @@ func Test_mapset() call assert_equal('one<CR>two', getline(1)) iunmap K - let &cpo = cpo_save " Test literal <CR> using CTRL-V inoremap K one<CR>two @@ -221,8 +224,35 @@ func Test_mapset() iunmap K let &cpo = cpo_save - bwipe! endfunc +func Check_ctrlb_map(d, check_alt) + call assert_equal('<C-B>', a:d.lhs) + if a:check_alt + call assert_equal("\x80\xfc\x04B", a:d.lhsraw) + call assert_equal("\x02", a:d.lhsrawalt) + else + call assert_equal("\x02", a:d.lhsraw) + endif +endfunc + +func Test_map_restore() + " Test restoring map with alternate keycode + nmap <C-B> back + let d = maparg('<C-B>', 'n', 0, 1) + call Check_ctrlb_map(d, 1) + let dsimp = maparg("\x02", 'n', 0, 1) + call Check_ctrlb_map(dsimp, 0) + nunmap <C-B> + call mapset('n', 0, d) + let d = maparg('<C-B>', 'n', 0, 1) + call Check_ctrlb_map(d, 1) + let dsimp = maparg("\x02", 'n', 0, 1) + call Check_ctrlb_map(dsimp, 0) + + nunmap <C-B> + +endfunc + " vim: shiftwidth=2 sts=2 expandtab diff --git a/src/version.c b/src/version.c index 34852c3699..543f5a8eea 100644 --- a/src/version.c +++ b/src/version.c @@ -746,6 +746,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 815, /**/ 814, /**/ From 87202264f8e27f084c0e58f98aeb27fa5c6d5251 Mon Sep 17 00:00:00 2001 From: Bram Moolenaar <Bram@vim.org> Date: Sun, 24 May 2020 17:23:45 +0200 Subject: [PATCH 215/230] patch 8.2.0816: terminal test fails when compiled with Athena Problem: Terminal test fails when compiled with Athena. Solution: Do give an error when the GUI is not running. (hint by Dominique Pelle, closes #5928, closes #6132) --- src/channel.c | 6 ++++++ src/globals.h | 3 +++ src/gui.c | 2 +- src/term.c | 10 +++++----- src/testdir/test_terminal.vim | 14 ++++++++++---- src/version.c | 2 ++ 6 files changed, 27 insertions(+), 10 deletions(-) diff --git a/src/channel.c b/src/channel.c index 68adbc3782..2b85ec91da 100644 --- a/src/channel.c +++ b/src/channel.c @@ -5308,6 +5308,7 @@ get_job_options(typval_T *tv, jobopt_T *opt, int supported, int supported2) { char_u *color_name; guicolor_T guicolor; + int called_emsg_before = called_emsg; color_name = tv_get_string_chk(&li->li_tv); if (color_name == NULL) @@ -5315,7 +5316,12 @@ get_job_options(typval_T *tv, jobopt_T *opt, int supported, int supported2) guicolor = GUI_GET_COLOR(color_name); if (guicolor == INVALCOLOR) + { + if (called_emsg_before == called_emsg) + // may not get the error if the GUI didn't start + semsg(_(e_alloc_color), color_name); return FAIL; + } rgb[n] = GUI_MCH_GET_RGB(guicolor); } diff --git a/src/globals.h b/src/globals.h index 60c3c668b8..648da7dcef 100644 --- a/src/globals.h +++ b/src/globals.h @@ -1767,6 +1767,9 @@ EXTERN char e_no_white_before[] INIT(= N_("E1068: No white space allowed before EXTERN char e_lock_unlock[] INIT(= N_("E940: Cannot lock or unlock variable %s")); #endif +#if defined(FEAT_GUI) || defined(FEAT_TERMGUICOLORS) +EXTERN char e_alloc_color[] INIT(= N_("E254: Cannot allocate color %s")); +#endif #ifdef FEAT_GUI_MAC EXTERN short disallow_gui INIT(= FALSE); diff --git a/src/gui.c b/src/gui.c index 13b65cb03c..93b8bb63f4 100644 --- a/src/gui.c +++ b/src/gui.c @@ -4741,7 +4741,7 @@ gui_get_color(char_u *name) && gui.in_use #endif ) - semsg(_("E254: Cannot allocate color %s"), name); + semsg(_(e_alloc_color), name); return t; } diff --git a/src/term.c b/src/term.c index e79fa5eb2a..588058941d 100644 --- a/src/term.c +++ b/src/term.c @@ -1381,7 +1381,7 @@ termgui_get_color(char_u *name) t = termgui_mch_get_color(name); if (t == INVALCOLOR) - semsg(_("E254: Cannot allocate color %s"), name); + semsg(_(e_alloc_color), name); return t; } @@ -1587,9 +1587,9 @@ may_adjust_color_count(int val) log_tr("Received t_Co, redraw_asap(): %d", r); } -#else +# else redraw_asap(CLEAR); -#endif +# endif } } #endif @@ -1597,10 +1597,10 @@ may_adjust_color_count(int val) #ifdef HAVE_TGETENT static char *(key_names[]) = { -#ifdef FEAT_TERMRESPONSE +# ifdef FEAT_TERMRESPONSE // Do this one first, it may cause a screen redraw. "Co", -#endif +# endif "ku", "kd", "kr", "kl", "#2", "#4", "%i", "*7", "k1", "k2", "k3", "k4", "k5", "k6", diff --git a/src/testdir/test_terminal.vim b/src/testdir/test_terminal.vim index bb9cdc7736..a8a549cbd9 100644 --- a/src/testdir/test_terminal.vim +++ b/src/testdir/test_terminal.vim @@ -1009,13 +1009,17 @@ func Test_terminal_term_start_empty_command() call assert_fails(cmd, 'E475:') let cmd = "call term_start('', {'term_highlight' : []})" call assert_fails(cmd, 'E475:') - if has('gui') + if has('gui') || has('termguicolors') let cmd = "call term_start('', {'ansi_colors' : 'abc'})" call assert_fails(cmd, 'E475:') let cmd = "call term_start('', {'ansi_colors' : [[]]})" call assert_fails(cmd, 'E730:') let cmd = "call term_start('', {'ansi_colors' : repeat(['blue'], 18)})" - call assert_fails(cmd, 'E475:') + if has('gui_running') || has('termguicolors') + call assert_fails(cmd, 'E475:') + else + call assert_fails(cmd, 'E254:') + endif endif endfunc @@ -2668,7 +2672,6 @@ endfunc " Test for passing invalid arguments to terminal functions func Test_term_func_invalid_arg() call assert_fails('let b = term_getaltscreen([])', 'E745:') - call assert_fails('let p = term_getansicolors([])', 'E745:') call assert_fails('let a = term_getattr(1, [])', 'E730:') call assert_fails('let c = term_getcursor([])', 'E745:') call assert_fails('let l = term_getline([], 1)', 'E745:') @@ -2677,10 +2680,13 @@ func Test_term_func_invalid_arg() call assert_fails('let s = term_getstatus([])', 'E745:') call assert_fails('let s = term_scrape([], 1)', 'E745:') call assert_fails('call term_sendkeys([], "a")', 'E745:') - call assert_fails('call term_setansicolors([], [])', 'E745:') call assert_fails('call term_setapi([], "")', 'E745:') call assert_fails('call term_setrestore([], "")', 'E745:') call assert_fails('call term_setkill([], "")', 'E745:') + if has('gui') || has('termguicolors') + call assert_fails('let p = term_getansicolors([])', 'E745:') + call assert_fails('call term_setansicolors([], [])', 'E745:') + endif endfunc " Test for sending various special keycodes to a terminal diff --git a/src/version.c b/src/version.c index 543f5a8eea..f2afc0b443 100644 --- a/src/version.c +++ b/src/version.c @@ -746,6 +746,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 816, /**/ 815, /**/ From f7271e831614d15d173c7f562cc26f48c2554ce9 Mon Sep 17 00:00:00 2001 From: Bram Moolenaar <Bram@vim.org> Date: Sun, 24 May 2020 18:45:07 +0200 Subject: [PATCH 216/230] patch 8.2.0817: not enough memory allocated when converting string Problem: Not enough memory allocated when converting string with special character. Solution: Reserve space for modifier code. (closes #6130) --- src/eval.c | 11 ++++++++--- src/testdir/test_functions.vim | 2 ++ src/version.c | 2 ++ 3 files changed, 12 insertions(+), 3 deletions(-) diff --git a/src/eval.c b/src/eval.c index dbc10c1b69..00b6c59df2 100644 --- a/src/eval.c +++ b/src/eval.c @@ -3503,6 +3503,7 @@ get_string_tv(char_u **arg, typval_T *rettv, int evaluate) char_u *p; char_u *name; int extra = 0; + int len; /* * Find the end of the string, skipping backslashed characters. @@ -3513,9 +3514,10 @@ get_string_tv(char_u **arg, typval_T *rettv, int evaluate) { ++p; // A "\<x>" form occupies at least 4 characters, and produces up - // to 6 characters: reserve space for 2 extra + // to 9 characters (6 for the char and 3 for a modifier): reserve + // space for 5 extra. if (*p == '<') - extra += 2; + extra += 5; } } @@ -3536,7 +3538,8 @@ get_string_tv(char_u **arg, typval_T *rettv, int evaluate) * Copy the string into allocated memory, handling backslashed * characters. */ - name = alloc(p - *arg + extra); + len = (int)(p - *arg + extra); + name = alloc(len); if (name == NULL) return FAIL; rettv->v_type = VAR_STRING; @@ -3610,6 +3613,8 @@ get_string_tv(char_u **arg, typval_T *rettv, int evaluate) if (extra != 0) { name += extra; + if (name >= rettv->vval.v_string + len) + iemsg("get_string_tv() used more space than allocated"); break; } // FALLTHROUGH diff --git a/src/testdir/test_functions.vim b/src/testdir/test_functions.vim index a8506a8f76..712aec4eae 100644 --- a/src/testdir/test_functions.vim +++ b/src/testdir/test_functions.vim @@ -2278,6 +2278,8 @@ func Test_nr2char() set encoding=utf8 call assert_equal('a', nr2char(97, 1)) call assert_equal('a', nr2char(97, 0)) + + call assert_equal("\x80\xfc\b\xf4\x80\xfeX\x80\xfeX\x80\xfeX", eval('"\<M-' .. nr2char(0x100000) .. '>"')) endfunc " Test for screenattr(), screenchar() and screenchars() functions diff --git a/src/version.c b/src/version.c index f2afc0b443..94084c30d5 100644 --- a/src/version.c +++ b/src/version.c @@ -746,6 +746,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 817, /**/ 816, /**/ From 822ba24743af9ee1b5e7f656a7a61a38f3638bca Mon Sep 17 00:00:00 2001 From: Bram Moolenaar <Bram@vim.org> Date: Sun, 24 May 2020 23:00:18 +0200 Subject: [PATCH 217/230] patch 8.2.0818: Vim9: using a discovery phase doesn't work well Problem: Vim9: using a discovery phase doesn't work well. Solution: Remove the discovery phase, instead compile a function only when it is used. Add :defcompile to compile def functions earlier. --- src/eval.c | 3 +- src/evalvars.c | 37 +++------ src/ex_cmdidxs.h | 48 ++++++------ src/ex_cmds.h | 3 + src/ex_docmd.c | 2 + src/proto/evalvars.pro | 1 - src/proto/userfunc.pro | 3 +- src/proto/vim9compile.pro | 3 +- src/structs.h | 5 +- src/testdir/test_vim9_disassemble.vim | 6 +- src/testdir/test_vim9_func.vim | 40 ++++++---- src/testdir/test_vim9_script.vim | 76 ++++-------------- src/testdir/vim9.vim | 2 +- src/userfunc.c | 56 ++++++++++--- src/version.c | 2 + src/vim.h | 1 - src/vim9compile.c | 27 ++++--- src/vim9execute.c | 13 ++- src/vim9script.c | 109 -------------------------- 19 files changed, 165 insertions(+), 272 deletions(-) diff --git a/src/eval.c b/src/eval.c index 00b6c59df2..d76ec94102 100644 --- a/src/eval.c +++ b/src/eval.c @@ -244,7 +244,8 @@ eval_expr_typval(typval_T *expr, typval_T *argv, int argc, typval_T *rettv) if (partial == NULL) return FAIL; - if (partial->pt_func != NULL && partial->pt_func->uf_dfunc_idx >= 0) + if (partial->pt_func != NULL + && partial->pt_func->uf_dfunc_idx != UF_NOT_COMPILED) { if (call_def_function(partial->pt_func, argc, argv, partial, rettv) == FAIL) diff --git a/src/evalvars.c b/src/evalvars.c index fd652ae109..6ab33184b4 100644 --- a/src/evalvars.c +++ b/src/evalvars.c @@ -164,6 +164,7 @@ static dict_T vimvardict; // Dictionary with v: variables // for VIM_VERSION_ defines #include "version.h" +static void ex_let_const(exarg_T *eap); static char_u *skip_var_one(char_u *arg, int include_type); static void list_glob_vars(int *first); static void list_buf_vars(int *first); @@ -685,7 +686,7 @@ heredoc_get(exarg_T *eap, char_u *cmd, int script_get) void ex_let(exarg_T *eap) { - ex_let_const(eap, FALSE); + ex_let_const(eap); } /* @@ -697,18 +698,11 @@ ex_let(exarg_T *eap) void ex_const(exarg_T *eap) { - ex_let_const(eap, FALSE); + ex_let_const(eap); } -/* - * When "discovery" is TRUE the ":let" or ":const" is encountered during the - * discovery phase of vim9script: - * - The command will be executed again, redefining the variable is OK then. - * - The expresion argument must be a constant. - * - If no constant expression a type must be specified. - */ - void -ex_let_const(exarg_T *eap, int discovery) + static void +ex_let_const(exarg_T *eap) { char_u *arg = eap->arg; char_u *expr = NULL; @@ -726,8 +720,6 @@ ex_let_const(exarg_T *eap, int discovery) // detect Vim9 assignment without ":let" or ":const" if (eap->arg == eap->cmd) flags |= LET_NO_COMMAND; - if (discovery) - flags |= LET_DISCOVERY; argend = skip_var_list(arg, TRUE, &var_count, &semicolon); if (argend == NULL) @@ -740,7 +732,7 @@ ex_let_const(exarg_T *eap, int discovery) || (expr[1] == '.' && expr[2] == '=')); has_assign = *expr == '=' || (vim_strchr((char_u *)"+-*/%", *expr) != NULL && expr[1] == '='); - if (!has_assign && !concat && !discovery) + if (!has_assign && !concat) { // ":let" without "=": list variables if (*arg == '[') @@ -809,8 +801,6 @@ ex_let_const(exarg_T *eap, int discovery) if (eap->skip) ++emsg_skip; eval_flags = eap->skip ? 0 : EVAL_EVALUATE; - if (discovery) - eval_flags |= EVAL_CONSTANT; i = eval0(expr, &rettv, &eap->nextcmd, eval_flags); } if (eap->skip) @@ -819,10 +809,8 @@ ex_let_const(exarg_T *eap, int discovery) clear_tv(&rettv); --emsg_skip; } - else if (i != FAIL || (discovery && save_called_emsg == called_emsg)) + else if (i != FAIL) { - // In Vim9 script discovery "let v: bool = Func()" fails but is - // still a valid declaration. (void)ex_let_vars(eap->arg, &rettv, FALSE, semicolon, var_count, flags, op); clear_tv(&rettv); @@ -1371,12 +1359,7 @@ ex_let_one( lval_T lv; p = get_lval(arg, tv, &lv, FALSE, FALSE, 0, FNE_CHECK_START); - if ((flags & LET_DISCOVERY) && tv->v_type == VAR_UNKNOWN - && lv.ll_type == NULL) - { - semsg(_("E1091: type missing for %s"), arg); - } - else if (p != NULL && lv.ll_name != NULL) + if (p != NULL && lv.ll_name != NULL) { if (endchars != NULL && vim_strchr(endchars, *skipwhite(lv.ll_name_end)) == NULL) @@ -2621,7 +2604,7 @@ find_var_ht(char_u *name, char_u **varname) if (*name == 'v') // v: variable return &vimvarht; if (get_current_funccal() != NULL - && get_current_funccal()->func->uf_dfunc_idx < 0) + && get_current_funccal()->func->uf_dfunc_idx == UF_NOT_COMPILED) { // a: and l: are only used in functions defined with ":function" if (*name == 'a') // a: function argument @@ -3004,8 +2987,6 @@ set_var_const( if (flags & LET_IS_CONST) di->di_tv.v_lock |= VAR_LOCKED; - if (flags & LET_DISCOVERY) - di->di_flags |= DI_FLAGS_RELOAD; } /* diff --git a/src/ex_cmdidxs.h b/src/ex_cmdidxs.h index 790cbf4b59..53081d0690 100644 --- a/src/ex_cmdidxs.h +++ b/src/ex_cmdidxs.h @@ -9,28 +9,28 @@ static const unsigned short cmdidxs1[26] = /* b */ 19, /* c */ 42, /* d */ 108, - /* e */ 132, - /* f */ 155, - /* g */ 171, - /* h */ 177, - /* i */ 186, - /* j */ 205, - /* k */ 207, - /* l */ 212, - /* m */ 274, - /* n */ 292, - /* o */ 312, - /* p */ 324, - /* q */ 363, - /* r */ 366, - /* s */ 386, - /* t */ 455, - /* u */ 500, - /* v */ 511, - /* w */ 530, - /* x */ 544, - /* y */ 554, - /* z */ 555 + /* e */ 133, + /* f */ 156, + /* g */ 172, + /* h */ 178, + /* i */ 187, + /* j */ 206, + /* k */ 208, + /* l */ 213, + /* m */ 275, + /* n */ 293, + /* o */ 313, + /* p */ 325, + /* q */ 364, + /* r */ 367, + /* s */ 387, + /* t */ 456, + /* u */ 501, + /* v */ 512, + /* w */ 531, + /* x */ 545, + /* y */ 555, + /* z */ 556 }; /* @@ -44,7 +44,7 @@ static const unsigned char cmdidxs2[26][26] = /* a */ { 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 5, 6, 0, 0, 0, 7, 15, 0, 16, 0, 0, 0, 0, 0 }, /* b */ { 2, 0, 0, 4, 5, 7, 0, 0, 0, 0, 0, 8, 9, 10, 11, 12, 0, 13, 0, 0, 0, 0, 22, 0, 0, 0 }, /* c */ { 3, 12, 16, 18, 20, 22, 25, 0, 0, 0, 0, 33, 37, 40, 46, 56, 58, 59, 60, 0, 62, 0, 65, 0, 0, 0 }, - /* d */ { 0, 0, 0, 0, 0, 0, 0, 0, 7, 17, 0, 18, 0, 0, 19, 0, 0, 21, 22, 0, 0, 0, 0, 0, 0, 0 }, + /* d */ { 0, 0, 0, 0, 0, 0, 0, 0, 8, 18, 0, 19, 0, 0, 20, 0, 0, 22, 23, 0, 0, 0, 0, 0, 0, 0 }, /* e */ { 1, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 7, 9, 10, 0, 0, 0, 0, 0, 0, 0, 17, 0, 18, 0, 0 }, /* f */ { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 0, 0, 0, 0, 0, 15, 0, 0, 0, 0, 0 }, /* g */ { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 2, 0, 0, 4, 5, 0, 0, 0, 0 }, @@ -69,4 +69,4 @@ static const unsigned char cmdidxs2[26][26] = /* z */ { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 } }; -static const int command_count = 568; +static const int command_count = 569; diff --git a/src/ex_cmds.h b/src/ex_cmds.h index 25a0853bda..2d86c5dc7e 100644 --- a/src/ex_cmds.h +++ b/src/ex_cmds.h @@ -447,6 +447,9 @@ EXCMD(CMD_debuggreedy, "debuggreedy", ex_debuggreedy, EXCMD(CMD_def, "def", ex_function, EX_EXTRA|EX_BANG|EX_SBOXOK|EX_CMDWIN, ADDR_NONE), +EXCMD(CMD_defcompile, "defcompile", ex_defcompile, + EX_SBOXOK|EX_CMDWIN|EX_TRLBAR, + ADDR_NONE), EXCMD(CMD_delcommand, "delcommand", ex_delcommand, EX_NEEDARG|EX_WORD1|EX_TRLBAR|EX_CMDWIN, ADDR_NONE), diff --git a/src/ex_docmd.c b/src/ex_docmd.c index 5447b74195..3d590e5577 100644 --- a/src/ex_docmd.c +++ b/src/ex_docmd.c @@ -273,6 +273,8 @@ static void ex_tag_cmd(exarg_T *eap, char_u *name); # define ex_continue ex_ni # define ex_debug ex_ni # define ex_debuggreedy ex_ni +# define ex_def ex_ni +# define ex_defcompile ex_ni # define ex_delfunction ex_ni # define ex_disassemble ex_ni # define ex_echo ex_ni diff --git a/src/proto/evalvars.pro b/src/proto/evalvars.pro index 3d07a6dfeb..58e922113e 100644 --- a/src/proto/evalvars.pro +++ b/src/proto/evalvars.pro @@ -16,7 +16,6 @@ void restore_vimvar(int idx, typval_T *save_tv); list_T *heredoc_get(exarg_T *eap, char_u *cmd, int script_get); void ex_let(exarg_T *eap); void ex_const(exarg_T *eap); -void ex_let_const(exarg_T *eap, int redefine); int ex_let_vars(char_u *arg_start, typval_T *tv, int copy, int semicolon, int var_count, int flags, char_u *op); char_u *skip_var_list(char_u *arg, int include_type, int *var_count, int *semicolon); void list_hashtable_vars(hashtab_T *ht, char *prefix, int empty, int *first); diff --git a/src/proto/userfunc.pro b/src/proto/userfunc.pro index 4295ce269f..6ed79ba035 100644 --- a/src/proto/userfunc.pro +++ b/src/proto/userfunc.pro @@ -23,8 +23,9 @@ void user_func_error(int error, char_u *name); int call_func(char_u *funcname, int len, typval_T *rettv, int argcount_in, typval_T *argvars_in, funcexe_T *funcexe); char_u *trans_function_name(char_u **pp, int *is_global, int skip, int flags, funcdict_T *fdp, partial_T **partial); char_u *untrans_function_name(char_u *name); -ufunc_T *def_function(exarg_T *eap, char_u *name_arg, void *context, int compile); +ufunc_T *def_function(exarg_T *eap, char_u *name_arg); void ex_function(exarg_T *eap); +void ex_defcompile(exarg_T *eap); int eval_fname_script(char_u *p); int translated_function_exists(char_u *name, int is_global); int has_varargs(ufunc_T *ufunc); diff --git a/src/proto/vim9compile.pro b/src/proto/vim9compile.pro index 6a3d9b5b23..67c7224007 100644 --- a/src/proto/vim9compile.pro +++ b/src/proto/vim9compile.pro @@ -9,8 +9,7 @@ imported_T *find_imported(char_u *name, size_t len, cctx_T *cctx); char_u *to_name_const_end(char_u *arg); int assignment_len(char_u *p, int *heredoc); int check_vim9_unlet(char_u *name); -int add_def_function(ufunc_T *ufunc); -void compile_def_function(ufunc_T *ufunc, int set_return_type, cctx_T *outer_cctx); +int compile_def_function(ufunc_T *ufunc, int set_return_type, cctx_T *outer_cctx); void delete_instr(isn_T *isn); void delete_def_function(ufunc_T *ufunc); void free_def_functions(void); diff --git a/src/structs.h b/src/structs.h index 69233a9673..e58e644726 100644 --- a/src/structs.h +++ b/src/structs.h @@ -1516,6 +1516,9 @@ struct blobvar_S #if defined(FEAT_EVAL) || defined(PROTO) typedef struct funccall_S funccall_T; +# define UF_NOT_COMPILED -2 +# define UF_TO_BE_COMPILED -1 + /* * Structure to hold info for a user function. */ @@ -1525,7 +1528,7 @@ typedef struct int uf_flags; // FC_ flags int uf_calls; // nr of active calls int uf_cleared; // func_clear() was already called - int uf_dfunc_idx; // >= 0 for :def function only + int uf_dfunc_idx; // UF_NOT_COMPILED, UF_TO_BE_COMPILED or >= 0 garray_T uf_args; // arguments, including optional arguments garray_T uf_def_args; // default argument expressions diff --git a/src/testdir/test_vim9_disassemble.vim b/src/testdir/test_vim9_disassemble.vim index 74804b4cf2..e1042588cf 100644 --- a/src/testdir/test_vim9_disassemble.vim +++ b/src/testdir/test_vim9_disassemble.vim @@ -423,8 +423,7 @@ def Test_disassemble_update_instr() assert_match('FuncWithForwardCall\_s*' .. 'return g:DefinedLater("yes")\_s*' .. '\d PUSHS "yes"\_s*' .. - '\d UCALL g:DefinedLater(argc 1)\_s*' .. - '\d CHECKTYPE string stack\[-1]\_s*' .. + '\d DCALL DefinedLater(argc 1)\_s*' .. '\d RETURN', res) @@ -436,7 +435,6 @@ def Test_disassemble_update_instr() 'return g:DefinedLater("yes")\_s*' .. '\d PUSHS "yes"\_s*' .. '\d DCALL DefinedLater(argc 1)\_s*' .. - '\d CHECKTYPE string stack\[-1]\_s*' .. '\d RETURN', res) enddef @@ -604,7 +602,7 @@ def Test_disassemble_lambda() '\d PUSHS "x"\_s*' .. '\d LOAD $0\_s*' .. '\d PCALL (argc 1)\_s*' .. - '\d CHECKTYPE string stack\[-1]', + '\d RETURN', instr) enddef diff --git a/src/testdir/test_vim9_func.vim b/src/testdir/test_vim9_func.vim index 100d86aa66..d099bd2cb7 100644 --- a/src/testdir/test_vim9_func.vim +++ b/src/testdir/test_vim9_func.vim @@ -83,8 +83,8 @@ def Test_call_default_args() assert_equal('one', MyDefaultArgs('one')) assert_fails('call MyDefaultArgs("one", "two")', 'E118:') - CheckScriptFailure(['def Func(arg: number = asdf)', 'enddef'], 'E1001:') - CheckScriptFailure(['def Func(arg: number = "text")', 'enddef'], 'E1013: argument 1: type mismatch, expected number but got string') + CheckScriptFailure(['def Func(arg: number = asdf)', 'enddef', 'defcompile'], 'E1001:') + CheckScriptFailure(['def Func(arg: number = "text")', 'enddef', 'defcompile'], 'E1013: argument 1: type mismatch, expected number but got string') enddef def Test_nested_function() @@ -188,7 +188,7 @@ def Test_call_varargs_only() enddef def Test_using_var_as_arg() - call writefile(['def Func(x: number)', 'let x = 234', 'enddef'], 'Xdef') + call writefile(['def Func(x: number)', 'let x = 234', 'enddef', 'defcompile'], 'Xdef') call assert_fails('so Xdef', 'E1006:') call delete('Xdef') enddef @@ -210,7 +210,7 @@ def Test_assign_to_argument() ListArg(l) assert_equal('value', l[0]) - call CheckScriptFailure(['def Func(arg: number)', 'arg = 3', 'enddef'], 'E1090:') + call CheckScriptFailure(['def Func(arg: number)', 'arg = 3', 'enddef', 'defcompile'], 'E1090:') enddef def Test_call_func_defined_later() @@ -261,16 +261,16 @@ enddef def Test_error_in_nested_function() " Error in called function requires unwinding the call stack. - assert_fails('call FuncWithForwardCall()', 'E1029') + assert_fails('call FuncWithForwardCall()', 'E1013') enddef def Test_return_type_wrong() - CheckScriptFailure(['def Func(): number', 'return "a"', 'enddef'], 'expected number but got string') - CheckScriptFailure(['def Func(): string', 'return 1', 'enddef'], 'expected string but got number') - CheckScriptFailure(['def Func(): void', 'return "a"', 'enddef'], 'expected void but got string') - CheckScriptFailure(['def Func()', 'return "a"', 'enddef'], 'expected void but got string') + CheckScriptFailure(['def Func(): number', 'return "a"', 'enddef', 'defcompile'], 'expected number but got string') + CheckScriptFailure(['def Func(): string', 'return 1', 'enddef', 'defcompile'], 'expected string but got number') + CheckScriptFailure(['def Func(): void', 'return "a"', 'enddef', 'defcompile'], 'expected void but got string') + CheckScriptFailure(['def Func()', 'return "a"', 'enddef', 'defcompile'], 'expected void but got string') - CheckScriptFailure(['def Func(): number', 'return', 'enddef'], 'E1003:') + CheckScriptFailure(['def Func(): number', 'return', 'enddef', 'defcompile'], 'E1003:') CheckScriptFailure(['def Func(): list', 'return []', 'enddef'], 'E1008:') CheckScriptFailure(['def Func(): dict', 'return {}', 'enddef'], 'E1008:') @@ -341,6 +341,7 @@ def Test_vim9script_call_fail_decl() def MyFunc(arg: string) let var = 123 enddef + defcompile END writefile(lines, 'Xcall_decl.vim') assert_fails('source Xcall_decl.vim', 'E1054:') @@ -354,6 +355,7 @@ def Test_vim9script_call_fail_const() def MyFunc(arg: string) var = 'asdf' enddef + defcompile END writefile(lines, 'Xcall_const.vim') assert_fails('source Xcall_const.vim', 'E46:') @@ -381,6 +383,7 @@ def Test_delfunc() def CallGoneSoon() GoneSoon() enddef + defcompile delfunc g:GoneSoon CallGoneSoon() @@ -397,7 +400,7 @@ def Test_redef_failure() so Xdef call writefile(['def Func1(): string', 'return "Func1"', 'enddef'], 'Xdef') so Xdef - call writefile(['def! Func0(): string', 'enddef'], 'Xdef') + call writefile(['def! Func0(): string', 'enddef', 'defcompile'], 'Xdef') call assert_fails('so Xdef', 'E1027:') call writefile(['def Func2(): string', 'return "Func2"', 'enddef'], 'Xdef') so Xdef @@ -471,6 +474,7 @@ func Test_internalfunc_arg_error() def! FArgErr(): float return ceil(1.1, 2) enddef + defcompile END call writefile(l, 'Xinvalidarg') call assert_fails('so Xinvalidarg', 'E118:') @@ -478,6 +482,7 @@ func Test_internalfunc_arg_error() def! FArgErr(): float return ceil() enddef + defcompile END call writefile(l, 'Xinvalidarg') call assert_fails('so Xinvalidarg', 'E119:') @@ -555,7 +560,8 @@ def Test_func_type_part() RefVoid = FuncNoArgNoRet RefVoid = FuncOneArgNoRet CheckDefFailure(['let RefVoid: func: void', 'RefVoid = FuncNoArgRetNumber'], 'E1013: type mismatch, expected func() but got func(): number') - CheckDefFailure(['let RefVoid: func: void', 'RefVoid = FuncNoArgRetString'], 'E1013: type mismatch, expected func() but got func(): string') +" TODO: these should fail +" CheckDefFailure(['let RefVoid: func: void', 'RefVoid = FuncNoArgRetString'], 'E1013: type mismatch, expected func() but got func(): string') let RefAny: func(): any RefAny = FuncNoArgRetNumber @@ -567,7 +573,8 @@ def Test_func_type_part() RefNr = FuncNoArgRetNumber RefNr = FuncOneArgRetNumber CheckDefFailure(['let RefNr: func: number', 'RefNr = FuncNoArgNoRet'], 'E1013: type mismatch, expected func(): number but got func()') - CheckDefFailure(['let RefNr: func: number', 'RefNr = FuncNoArgRetString'], 'E1013: type mismatch, expected func(): number but got func(): string') +" TODO: should fail +" CheckDefFailure(['let RefNr: func: number', 'RefNr = FuncNoArgRetString'], 'E1013: type mismatch, expected func(): number but got func(): string') let RefStr: func: string RefStr = FuncNoArgRetString @@ -582,9 +589,10 @@ def Test_func_type_fails() CheckDefFailure(['let Ref1: func()', 'Ref1 = FuncNoArgRetNumber'], 'E1013: type mismatch, expected func() but got func(): number') CheckDefFailure(['let Ref1: func()', 'Ref1 = FuncOneArgNoRet'], 'E1013: type mismatch, expected func() but got func(number)') CheckDefFailure(['let Ref1: func()', 'Ref1 = FuncOneArgRetNumber'], 'E1013: type mismatch, expected func() but got func(number): number') - CheckDefFailure(['let Ref1: func(bool)', 'Ref1 = FuncTwoArgNoRet'], 'E1013: type mismatch, expected func(bool) but got func(bool, number)') - CheckDefFailure(['let Ref1: func(?bool)', 'Ref1 = FuncTwoArgNoRet'], 'E1013: type mismatch, expected func(?bool) but got func(bool, number)') - CheckDefFailure(['let Ref1: func(...bool)', 'Ref1 = FuncTwoArgNoRet'], 'E1013: type mismatch, expected func(...bool) but got func(bool, number)') +" TODO: these don't fail +" CheckDefFailure(['let Ref1: func(bool)', 'Ref1 = FuncTwoArgNoRet'], 'E1013: type mismatch, expected func(bool) but got func(bool, number)') +" CheckDefFailure(['let Ref1: func(?bool)', 'Ref1 = FuncTwoArgNoRet'], 'E1013: type mismatch, expected func(?bool) but got func(bool, number)') +" CheckDefFailure(['let Ref1: func(...bool)', 'Ref1 = FuncTwoArgNoRet'], 'E1013: type mismatch, expected func(...bool) but got func(bool, number)') call CheckDefFailure(['let RefWrong: func(string ,number)'], 'E1068:') call CheckDefFailure(['let RefWrong: func(string,number)'], 'E1069:') diff --git a/src/testdir/test_vim9_script.vim b/src/testdir/test_vim9_script.vim index cc313285a5..ea976c52c9 100644 --- a/src/testdir/test_vim9_script.vim +++ b/src/testdir/test_vim9_script.vim @@ -255,7 +255,7 @@ def Test_assignment_failure() call CheckDefFailure(['let anr = 4', 'anr ..= "text"'], 'E1019:') call CheckDefFailure(['let xnr += 4'], 'E1020:') - call CheckScriptFailure(['vim9script', 'def Func()', 'let dummy = s:notfound', 'enddef'], 'E1050:') + call CheckScriptFailure(['vim9script', 'def Func()', 'let dummy = s:notfound', 'enddef', 'defcompile'], 'E1050:') call CheckDefFailure(['let var: list<string> = [123]'], 'expected list<string> but got list<number>') call CheckDefFailure(['let var: list<number> = ["xx"]'], 'expected list<number> but got list<string>') @@ -296,6 +296,7 @@ def Test_unlet() 'def Func()', ' unlet svar', 'enddef', + 'defcompile', ], 'E1081:') call CheckScriptFailure([ 'vim9script', @@ -303,6 +304,7 @@ def Test_unlet() 'def Func()', ' unlet s:svar', 'enddef', + 'defcompile', ], 'E1081:') $ENVVAR = 'foobar' @@ -606,6 +608,7 @@ def Test_vim9_import_export() let dummy = 1 let imported = Export + dummy enddef + defcompile END writefile(import_star_as_lines_no_dot, 'Ximport.vim') assert_fails('source Ximport.vim', 'E1060:') @@ -616,6 +619,7 @@ def Test_vim9_import_export() def Func() let imported = Export . exported enddef + defcompile END writefile(import_star_as_lines_dot_space, 'Ximport.vim') assert_fails('source Ximport.vim', 'E1074:') @@ -626,6 +630,7 @@ def Test_vim9_import_export() def Func() let imported = Export. enddef + defcompile END writefile(import_star_as_lines_missing_name, 'Ximport.vim') assert_fails('source Ximport.vim', 'E1048:') @@ -740,6 +745,9 @@ def Test_vim9script_fails() enddef def Test_vim9script_reload_import() + " TODO: make it work to compile when not in the script context anymore + return + let lines =<< trim END vim9script const var = '' @@ -789,6 +797,9 @@ def Test_vim9script_reload_import() enddef def Test_vim9script_reload_delfunc() + " TODO: make it work to compile when not in the script context anymore + return + let first_lines =<< trim END vim9script def FuncYes(): string @@ -1163,7 +1174,7 @@ def Test_for_loop_fails() CheckDefFailure(['for # in range(5)'], 'E690:') CheckDefFailure(['for i In range(5)'], 'E690:') CheckDefFailure(['let x = 5', 'for x in range(5)'], 'E1023:') - CheckScriptFailure(['def Func(arg: any)', 'for arg in range(5)', 'enddef'], 'E1006:') + CheckScriptFailure(['def Func(arg: any)', 'for arg in range(5)', 'enddef', 'defcompile'], 'E1006:') CheckDefFailure(['for i in "text"'], 'E1024:') CheckDefFailure(['for i in xxx'], 'E1001:') CheckDefFailure(['endfor'], 'E588:') @@ -1699,11 +1710,6 @@ def Test_vim9_comment_not_compiled() 'let v = 1# comment6', ], 'E15:') - CheckScriptFailure([ - 'vim9script', - 'let v:version', - ], 'E1091:') - CheckScriptSuccess([ 'vim9script', 'new' @@ -1771,77 +1777,27 @@ enddef def Test_let_missing_type() let lines =<< trim END - vim9script - func GetValue() - return 'this' - endfunc - let val = GetValue() - END - CheckScriptFailure(lines, 'E1091:') - - lines =<< trim END - vim9script - func GetValue() - return 'this' - endfunc - let val = [GetValue()] - END - CheckScriptFailure(lines, 'E1091:') - - lines =<< trim END - vim9script - func GetValue() - return 'this' - endfunc - let val = {GetValue(): 123} - END - CheckScriptFailure(lines, 'E1091:') - - lines =<< trim END - vim9script - func GetValue() - return 'this' - endfunc - let val = {'a': GetValue()} - END - CheckScriptFailure(lines, 'E1091:') - - lines =<< trim END vim9script let var = g:unknown END - CheckScriptFailure(lines, 'E1091:') - - " TODO: eventually this would work - lines =<< trim END - vim9script - let var = has('eval') - END - CheckScriptFailure(lines, 'E1091:') - - " TODO: eventually this would work - lines =<< trim END - vim9script - let var = len('string') - END - CheckScriptFailure(lines, 'E1091:') + CheckScriptFailure(lines, 'E121:') lines =<< trim END vim9script let nr: number = 123 let var = nr END - CheckScriptFailure(lines, 'E1091:') + CheckScriptSuccess(lines) enddef def Test_forward_declaration() let lines =<< trim END vim9script - g:initVal = GetValue() def GetValue(): string return theVal enddef let theVal = 'something' + g:initVal = GetValue() theVal = 'else' g:laterVal = GetValue() END diff --git a/src/testdir/vim9.vim b/src/testdir/vim9.vim index 0c16576c69..fdad9f7c3a 100644 --- a/src/testdir/vim9.vim +++ b/src/testdir/vim9.vim @@ -2,7 +2,7 @@ " Check that "lines" inside ":def" results in an "error" message. func CheckDefFailure(lines, error) - call writefile(['def Func()'] + a:lines + ['enddef'], 'Xdef') + call writefile(['def Func()'] + a:lines + ['enddef', 'defcompile'], 'Xdef') call assert_fails('so Xdef', a:error, a:lines) call delete('Xdef') endfunc diff --git a/src/userfunc.c b/src/userfunc.c index 99c45b3e76..f29a7b5c4a 100644 --- a/src/userfunc.c +++ b/src/userfunc.c @@ -409,7 +409,7 @@ get_lambda_tv(char_u **arg, typval_T *rettv, int evaluate) fp = alloc_clear(offsetof(ufunc_T, uf_name) + STRLEN(name) + 1); if (fp == NULL) goto errret; - fp->uf_dfunc_idx = -1; + fp->uf_dfunc_idx = UF_NOT_COMPILED; pt = ALLOC_CLEAR_ONE(partial_T); if (pt == NULL) goto errret; @@ -1112,7 +1112,7 @@ call_user_func( ga_init2(&fc->fc_funcs, sizeof(ufunc_T *), 1); func_ptr_ref(fp); - if (fp->uf_dfunc_idx >= 0) + if (fp->uf_dfunc_idx != UF_NOT_COMPILED) { estack_push_ufunc(ETYPE_UFUNC, fp, 1); save_current_sctx = current_sctx; @@ -1637,7 +1637,7 @@ free_all_functions(void) // clear the def function index now fp = HI2UF(hi); fp->uf_flags &= ~FC_DEAD; - fp->uf_dfunc_idx = -1; + fp->uf_dfunc_idx = UF_NOT_COMPILED; // Only free functions that are not refcounted, those are // supposed to be freed when no longer referenced. @@ -2033,7 +2033,7 @@ list_func_head(ufunc_T *fp, int indent) msg_start(); if (indent) msg_puts(" "); - if (fp->uf_dfunc_idx >= 0) + if (fp->uf_dfunc_idx != UF_NOT_COMPILED) msg_puts("def "); else msg_puts("function "); @@ -2082,7 +2082,7 @@ list_func_head(ufunc_T *fp, int indent) } msg_putchar(')'); - if (fp->uf_dfunc_idx >= 0) + if (fp->uf_dfunc_idx != UF_NOT_COMPILED) { if (fp->uf_ret_type != &t_void) { @@ -2377,7 +2377,7 @@ untrans_function_name(char_u *name) * Returns a pointer to the function or NULL if no function defined. */ ufunc_T * -def_function(exarg_T *eap, char_u *name_arg, void *context, int compile) +def_function(exarg_T *eap, char_u *name_arg) { char_u *theline; char_u *line_to_free = NULL; @@ -2416,6 +2416,12 @@ def_function(exarg_T *eap, char_u *name_arg, void *context, int compile) char_u *skip_until = NULL; char_u *heredoc_trimmed = NULL; + if (in_vim9script() && eap->forceit) + { + emsg(_(e_nobang)); + return NULL; + } + /* * ":function" without argument: list functions. */ @@ -2584,7 +2590,7 @@ def_function(exarg_T *eap, char_u *name_arg, void *context, int compile) if (!got_int) { msg_putchar('\n'); - if (fp->uf_dfunc_idx >= 0) + if (fp->uf_dfunc_idx != UF_NOT_COMPILED) msg_puts(" enddef"); else msg_puts(" endfunction"); @@ -3122,7 +3128,8 @@ def_function(exarg_T *eap, char_u *name_arg, void *context, int compile) fp = alloc_clear(offsetof(ufunc_T, uf_name) + STRLEN(name) + 1); if (fp == NULL) goto erret; - fp->uf_dfunc_idx = -1; + fp->uf_dfunc_idx = eap->cmdidx == CMD_def ? UF_TO_BE_COMPILED + : UF_NOT_COMPILED; if (fudi.fd_dict != NULL) { @@ -3175,6 +3182,8 @@ def_function(exarg_T *eap, char_u *name_arg, void *context, int compile) { int lnum_save = SOURCING_LNUM; + fp->uf_dfunc_idx = UF_TO_BE_COMPILED; + // error messages are for the first function line SOURCING_LNUM = sourcing_lnum_top; @@ -3242,6 +3251,8 @@ def_function(exarg_T *eap, char_u *name_arg, void *context, int compile) } SOURCING_LNUM = lnum_save; } + else + fp->uf_dfunc_idx = UF_NOT_COMPILED; fp->uf_lines = newlines; if ((flags & FC_CLOSURE) != 0) @@ -3273,10 +3284,6 @@ def_function(exarg_T *eap, char_u *name_arg, void *context, int compile) is_export = FALSE; } - // ":def Func()" may need to be compiled - if (eap->cmdidx == CMD_def && compile) - compile_def_function(fp, FALSE, context); - goto ret_free; erret: @@ -3304,7 +3311,30 @@ ret_free: void ex_function(exarg_T *eap) { - (void)def_function(eap, NULL, NULL, TRUE); + (void)def_function(eap, NULL); +} + +/* + * :defcompile - compile all :def functions in the current script. + */ + void +ex_defcompile(exarg_T *eap UNUSED) +{ + int todo = (int)func_hashtab.ht_used; + hashitem_T *hi; + ufunc_T *ufunc; + + for (hi = func_hashtab.ht_array; todo > 0 && !got_int; ++hi) + { + if (!HASHITEM_EMPTY(hi)) + { + --todo; + ufunc = HI2UF(hi); + if (ufunc->uf_script_ctx.sc_sid == current_sctx.sc_sid + && ufunc->uf_dfunc_idx == UF_TO_BE_COMPILED) + compile_def_function(ufunc, FALSE, NULL); + } + } } /* diff --git a/src/version.c b/src/version.c index 94084c30d5..a5d2a8f7bf 100644 --- a/src/version.c +++ b/src/version.c @@ -746,6 +746,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 818, /**/ 817, /**/ diff --git a/src/vim.h b/src/vim.h index 667e290299..708bb99cc5 100644 --- a/src/vim.h +++ b/src/vim.h @@ -2133,7 +2133,6 @@ typedef enum { // Flags for assignment functions. #define LET_IS_CONST 1 // ":const" #define LET_NO_COMMAND 2 // "var = expr" without ":let" or ":const" -#define LET_DISCOVERY 4 // discovery phase: variable can be redefined later #include "ex_cmds.h" // Ex command defines #include "spell.h" // spell checking stuff diff --git a/src/vim9compile.c b/src/vim9compile.c index 416198a0c4..d41dd53961 100644 --- a/src/vim9compile.c +++ b/src/vim9compile.c @@ -1418,7 +1418,7 @@ generate_CALL(cctx_T *cctx, ufunc_T *ufunc, int pushed_argcount) return FAIL; } - if (ufunc->uf_dfunc_idx >= 0) + if (ufunc->uf_dfunc_idx != UF_NOT_COMPILED) { int i; @@ -1442,12 +1442,16 @@ generate_CALL(cctx_T *cctx, ufunc_T *ufunc, int pushed_argcount) return FAIL; } } + if (ufunc->uf_dfunc_idx == UF_TO_BE_COMPILED) + if (compile_def_function(ufunc, TRUE, cctx) == FAIL) + return FAIL; } if ((isn = generate_instr(cctx, - ufunc->uf_dfunc_idx >= 0 ? ISN_DCALL : ISN_UCALL)) == NULL) + ufunc->uf_dfunc_idx != UF_NOT_COMPILED ? ISN_DCALL + : ISN_UCALL)) == NULL) return FAIL; - if (ufunc->uf_dfunc_idx >= 0) + if (ufunc->uf_dfunc_idx != UF_NOT_COMPILED) { isn->isn_arg.dfunc.cdf_idx = ufunc->uf_dfunc_idx; isn->isn_arg.dfunc.cdf_argcount = argcount; @@ -4454,9 +4458,12 @@ compile_nested_function(exarg_T *eap, cctx_T *cctx) eap->cookie = cctx; eap->skip = cctx->ctx_skip == TRUE; eap->forceit = FALSE; - ufunc = def_function(eap, name, cctx, TRUE); + ufunc = def_function(eap, name); - if (ufunc == NULL || ufunc->uf_dfunc_idx < 0) + if (ufunc == NULL) + return NULL; + if (ufunc->uf_dfunc_idx == UF_TO_BE_COMPILED + && compile_def_function(ufunc, TRUE, cctx) == FAIL) return NULL; // Define a local variable for the function reference. @@ -6302,7 +6309,7 @@ theend: * Add a function to the list of :def functions. * This "sets ufunc->uf_dfunc_idx" but the function isn't compiled yet. */ - int + static int add_def_function(ufunc_T *ufunc) { dfunc_T *dfunc; @@ -6328,8 +6335,9 @@ add_def_function(ufunc_T *ufunc) * "outer_cctx" is set for a nested function. * This can be used recursively through compile_lambda(), which may reallocate * "def_functions". + * Returns OK or FAIL. */ - void + int compile_def_function(ufunc_T *ufunc, int set_return_type, cctx_T *outer_cctx) { char_u *line = NULL; @@ -6352,7 +6360,7 @@ compile_def_function(ufunc_T *ufunc, int set_return_type, cctx_T *outer_cctx) delete_def_function_contents(dfunc); } else if (add_def_function(ufunc) == FAIL) - return; + return FAIL; CLEAR_FIELD(cctx); cctx.ctx_ufunc = ufunc; @@ -6816,7 +6824,7 @@ erret: delete_instr(((isn_T *)instr->ga_data) + idx); ga_clear(instr); - ufunc->uf_dfunc_idx = -1; + ufunc->uf_dfunc_idx = UF_NOT_COMPILED; if (!dfunc->df_deleted) --def_functions.ga_len; @@ -6836,6 +6844,7 @@ erret: free_imported(&cctx); free_locals(&cctx); ga_clear(&cctx.ctx_type_stack); + return ret; } /* diff --git a/src/vim9execute.c b/src/vim9execute.c index fe6adda601..f6aa140653 100644 --- a/src/vim9execute.c +++ b/src/vim9execute.c @@ -487,6 +487,9 @@ call_ufunc(ufunc_T *ufunc, int argcount, ectx_T *ectx, isn_T *iptr) int error; int idx; + if (ufunc->uf_dfunc_idx == UF_TO_BE_COMPILED + && compile_def_function(ufunc, FALSE, NULL) == FAIL) + return FAIL; if (ufunc->uf_dfunc_idx >= 0) { // The function has been compiled, can call it quickly. For a function @@ -667,8 +670,13 @@ call_def_function( // Like STACK_TV_VAR but use the outer scope #define STACK_OUT_TV_VAR(idx) (((typval_T *)ectx.ec_outer_stack->ga_data) + ectx.ec_outer_frame + STACK_FRAME_SIZE + idx) + if (ufunc->uf_dfunc_idx == UF_NOT_COMPILED + || (ufunc->uf_dfunc_idx == UF_TO_BE_COMPILED + && compile_def_function(ufunc, FALSE, NULL) == FAIL)) + return FAIL; + { - // Check the function was compiled, it is postponed in ex_vim9script(). + // Check the function was really compiled. dfunc_T *dfunc = ((dfunc_T *)def_functions.ga_data) + ufunc->uf_dfunc_idx; if (dfunc->df_instr == NULL) @@ -2303,6 +2311,9 @@ ex_disassemble(exarg_T *eap) semsg(_("E1061: Cannot find function %s"), eap->arg); return; } + if (ufunc->uf_dfunc_idx == UF_TO_BE_COMPILED + && compile_def_function(ufunc, FALSE, NULL) == FAIL) + return; if (ufunc->uf_dfunc_idx < 0) { semsg(_("E1062: Function %s is not compiled"), eap->arg); diff --git a/src/vim9script.c b/src/vim9script.c index 76650f8998..fa0f8c6732 100644 --- a/src/vim9script.c +++ b/src/vim9script.c @@ -33,11 +33,6 @@ in_vim9script(void) ex_vim9script(exarg_T *eap) { scriptitem_T *si = SCRIPT_ITEM(current_sctx.sc_sid); - garray_T *gap; - garray_T func_ga; - int idx; - ufunc_T *ufunc; - int start_called_emsg = called_emsg; if (!getline_equal(eap->getline, eap->cookie, getsourceline)) { @@ -52,116 +47,12 @@ ex_vim9script(exarg_T *eap) current_sctx.sc_version = SCRIPT_VERSION_VIM9; si->sn_version = SCRIPT_VERSION_VIM9; si->sn_had_command = TRUE; - ga_init2(&func_ga, sizeof(ufunc_T *), 20); if (STRCMP(p_cpo, CPO_VIM) != 0) { si->sn_save_cpo = p_cpo; p_cpo = vim_strsave((char_u *)CPO_VIM); } - - // Make a pass through the script to find: - // - function declarations - // - variable and constant declarations - // - imports - // The types are recognized, so that they can be used when compiling a - // function. - gap = source_get_line_ga(eap->cookie); - while (called_emsg == start_called_emsg) - { - char_u *line; - char_u *p; - - if (ga_grow(gap, 1) == FAIL) - return; - line = eap->getline(':', eap->cookie, 0, TRUE); - if (line == NULL) - break; - ((char_u **)(gap->ga_data))[gap->ga_len++] = line; - line = skipwhite(line); - p = line; - if (checkforcmd(&p, "function", 2) || checkforcmd(&p, "def", 3)) - { - int lnum_start = SOURCING_LNUM - 1; - - if (*p == '!') - { - emsg(_(e_nobang)); - break; - } - - // Handle :function and :def by calling def_function(). - // It will read upto the matching :endded or :endfunction. - eap->cmdidx = *line == 'f' ? CMD_function : CMD_def; - eap->cmd = line; - eap->arg = p; - eap->forceit = FALSE; - ufunc = def_function(eap, NULL, NULL, FALSE); - - if (ufunc != NULL && *line == 'd' && ga_grow(&func_ga, 1) == OK) - { - // Add the function to the list of :def functions, so that it - // can be referenced by index. It's compiled below. - add_def_function(ufunc); - ((ufunc_T **)(func_ga.ga_data))[func_ga.ga_len++] = ufunc; - } - - // Store empty lines in place of the function, we don't need to - // process it again. - vim_free(((char_u **)(gap->ga_data))[--gap->ga_len]); - if (ga_grow(gap, SOURCING_LNUM - lnum_start) == OK) - while (lnum_start < SOURCING_LNUM) - { - // getsourceline() will skip over NULL lines. - ((char_u **)(gap->ga_data))[gap->ga_len++] = NULL; - ++lnum_start; - } - } - else if (checkforcmd(&p, "let", 3) || checkforcmd(&p, "const", 4)) - { - eap->cmd = line; - eap->arg = p; - eap->forceit = FALSE; - eap->cmdidx = *line == 'l' ? CMD_let: CMD_const; - - // The command will be executed again, it's OK to redefine the - // variable then. - ex_let_const(eap, TRUE); - } - else if (checkforcmd(&p, "import", 3)) - { - eap->arg = p; - ex_import(eap); - - // Store empty line, we don't need to process the command again. - vim_free(((char_u **)(gap->ga_data))[--gap->ga_len]); - ((char_u **)(gap->ga_data))[gap->ga_len++] = NULL; - } - else if (checkforcmd(&p, "finish", 4)) - { - break; - } - } - - // Compile the :def functions. - for (idx = 0; idx < func_ga.ga_len && called_emsg == start_called_emsg; ++idx) - { - ufunc = ((ufunc_T **)(func_ga.ga_data))[idx]; - compile_def_function(ufunc, FALSE, NULL); - } - ga_clear(&func_ga); - - if (called_emsg == start_called_emsg) - { - // Return to process the commands at the script level. - source_use_line_ga(eap->cookie); - } - else - { - // If there was an error in the first or second phase then don't - // execute the script lines. - do_finish(eap, FALSE); - } } /* From f40e51a880a95f94dbbbecc9476559506c2cc345 Mon Sep 17 00:00:00 2001 From: Bram Moolenaar <Bram@vim.org> Date: Sun, 24 May 2020 23:14:23 +0200 Subject: [PATCH 218/230] patch 8.2.0819: compiler warning for unused variable Problem: Compiler warning for unused variable. Solution: Remove the variable. --- src/evalvars.c | 1 - src/version.c | 2 ++ 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/src/evalvars.c b/src/evalvars.c index 6ab33184b4..a45080b540 100644 --- a/src/evalvars.c +++ b/src/evalvars.c @@ -777,7 +777,6 @@ ex_let_const(exarg_T *eap) else { int eval_flags; - int save_called_emsg = called_emsg; rettv.v_type = VAR_UNKNOWN; i = FAIL; diff --git a/src/version.c b/src/version.c index a5d2a8f7bf..63bf51d5c1 100644 --- a/src/version.c +++ b/src/version.c @@ -746,6 +746,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 819, /**/ 818, /**/ From 6ff71d8b7fbdf667a2f119a2487302e240961816 Mon Sep 17 00:00:00 2001 From: Bram Moolenaar <Bram@vim.org> Date: Sun, 24 May 2020 23:45:24 +0200 Subject: [PATCH 219/230] patch 8.2.0820: Vim9: function type isn't set until compiled Problem: Vim9: function type isn't set until compiled. Solution: Set function type early. --- src/proto/vim9compile.pro | 1 + src/testdir/test_vim9_func.vim | 13 ++--- src/userfunc.c | 3 ++ src/version.c | 2 + src/vim9compile.c | 95 +++++++++++++++++----------------- 5 files changed, 58 insertions(+), 56 deletions(-) diff --git a/src/proto/vim9compile.pro b/src/proto/vim9compile.pro index 67c7224007..0f3ebc394a 100644 --- a/src/proto/vim9compile.pro +++ b/src/proto/vim9compile.pro @@ -10,6 +10,7 @@ char_u *to_name_const_end(char_u *arg); int assignment_len(char_u *p, int *heredoc); int check_vim9_unlet(char_u *name); int compile_def_function(ufunc_T *ufunc, int set_return_type, cctx_T *outer_cctx); +void set_function_type(ufunc_T *ufunc); void delete_instr(isn_T *isn); void delete_def_function(ufunc_T *ufunc); void free_def_functions(void); diff --git a/src/testdir/test_vim9_func.vim b/src/testdir/test_vim9_func.vim index d099bd2cb7..6c661111a0 100644 --- a/src/testdir/test_vim9_func.vim +++ b/src/testdir/test_vim9_func.vim @@ -560,8 +560,7 @@ def Test_func_type_part() RefVoid = FuncNoArgNoRet RefVoid = FuncOneArgNoRet CheckDefFailure(['let RefVoid: func: void', 'RefVoid = FuncNoArgRetNumber'], 'E1013: type mismatch, expected func() but got func(): number') -" TODO: these should fail -" CheckDefFailure(['let RefVoid: func: void', 'RefVoid = FuncNoArgRetString'], 'E1013: type mismatch, expected func() but got func(): string') + CheckDefFailure(['let RefVoid: func: void', 'RefVoid = FuncNoArgRetString'], 'E1013: type mismatch, expected func() but got func(): string') let RefAny: func(): any RefAny = FuncNoArgRetNumber @@ -573,8 +572,7 @@ def Test_func_type_part() RefNr = FuncNoArgRetNumber RefNr = FuncOneArgRetNumber CheckDefFailure(['let RefNr: func: number', 'RefNr = FuncNoArgNoRet'], 'E1013: type mismatch, expected func(): number but got func()') -" TODO: should fail -" CheckDefFailure(['let RefNr: func: number', 'RefNr = FuncNoArgRetString'], 'E1013: type mismatch, expected func(): number but got func(): string') + CheckDefFailure(['let RefNr: func: number', 'RefNr = FuncNoArgRetString'], 'E1013: type mismatch, expected func(): number but got func(): string') let RefStr: func: string RefStr = FuncNoArgRetString @@ -589,10 +587,9 @@ def Test_func_type_fails() CheckDefFailure(['let Ref1: func()', 'Ref1 = FuncNoArgRetNumber'], 'E1013: type mismatch, expected func() but got func(): number') CheckDefFailure(['let Ref1: func()', 'Ref1 = FuncOneArgNoRet'], 'E1013: type mismatch, expected func() but got func(number)') CheckDefFailure(['let Ref1: func()', 'Ref1 = FuncOneArgRetNumber'], 'E1013: type mismatch, expected func() but got func(number): number') -" TODO: these don't fail -" CheckDefFailure(['let Ref1: func(bool)', 'Ref1 = FuncTwoArgNoRet'], 'E1013: type mismatch, expected func(bool) but got func(bool, number)') -" CheckDefFailure(['let Ref1: func(?bool)', 'Ref1 = FuncTwoArgNoRet'], 'E1013: type mismatch, expected func(?bool) but got func(bool, number)') -" CheckDefFailure(['let Ref1: func(...bool)', 'Ref1 = FuncTwoArgNoRet'], 'E1013: type mismatch, expected func(...bool) but got func(bool, number)') + CheckDefFailure(['let Ref1: func(bool)', 'Ref1 = FuncTwoArgNoRet'], 'E1013: type mismatch, expected func(bool) but got func(bool, number)') + CheckDefFailure(['let Ref1: func(?bool)', 'Ref1 = FuncTwoArgNoRet'], 'E1013: type mismatch, expected func(?bool) but got func(bool, number)') + CheckDefFailure(['let Ref1: func(...bool)', 'Ref1 = FuncTwoArgNoRet'], 'E1013: type mismatch, expected func(...bool) but got func(bool, number)') call CheckDefFailure(['let RefWrong: func(string ,number)'], 'E1068:') call CheckDefFailure(['let RefWrong: func(string,number)'], 'E1069:') diff --git a/src/userfunc.c b/src/userfunc.c index f29a7b5c4a..bc92c2aaf3 100644 --- a/src/userfunc.c +++ b/src/userfunc.c @@ -3284,6 +3284,9 @@ def_function(exarg_T *eap, char_u *name_arg) is_export = FALSE; } + if (eap->cmdidx == CMD_def) + set_function_type(fp); + goto ret_free; erret: diff --git a/src/version.c b/src/version.c index 63bf51d5c1..a1e4a7f487 100644 --- a/src/version.c +++ b/src/version.c @@ -746,6 +746,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 820, /**/ 819, /**/ diff --git a/src/vim9compile.c b/src/vim9compile.c index d41dd53961..7d302da83a 100644 --- a/src/vim9compile.c +++ b/src/vim9compile.c @@ -6763,54 +6763,6 @@ compile_def_function(ufunc_T *ufunc, int set_return_type, cctx_T *outer_cctx) ufunc->uf_flags |= FC_CLOSURE; } - { - int varargs = ufunc->uf_va_name != NULL; - int argcount = ufunc->uf_args.ga_len; - - // Create a type for the function, with the return type and any - // argument types. - // A vararg is included in uf_args.ga_len but not in uf_arg_types. - // The type is included in "tt_args". - if (argcount > 0 || varargs) - { - ufunc->uf_func_type = alloc_func_type(ufunc->uf_ret_type, - argcount, &ufunc->uf_type_list); - // Add argument types to the function type. - if (func_type_add_arg_types(ufunc->uf_func_type, - argcount + varargs, - &ufunc->uf_type_list) == FAIL) - { - ret = FAIL; - goto erret; - } - ufunc->uf_func_type->tt_argcount = argcount + varargs; - ufunc->uf_func_type->tt_min_argcount = - argcount - ufunc->uf_def_args.ga_len; - if (ufunc->uf_arg_types == NULL) - { - int i; - - // lambda does not have argument types. - for (i = 0; i < argcount; ++i) - ufunc->uf_func_type->tt_args[i] = &t_any; - } - else - mch_memmove(ufunc->uf_func_type->tt_args, - ufunc->uf_arg_types, sizeof(type_T *) * argcount); - if (varargs) - { - ufunc->uf_func_type->tt_args[argcount] = - ufunc->uf_va_type == NULL ? &t_any : ufunc->uf_va_type; - ufunc->uf_func_type->tt_flags = TTFLAG_VARARGS; - } - } - else - // No arguments, can use a predefined type. - ufunc->uf_func_type = get_func_type(ufunc->uf_ret_type, - argcount, &ufunc->uf_type_list); - - } - ret = OK; erret: @@ -6847,6 +6799,53 @@ erret: return ret; } + void +set_function_type(ufunc_T *ufunc) +{ + int varargs = ufunc->uf_va_name != NULL; + int argcount = ufunc->uf_args.ga_len; + + // Create a type for the function, with the return type and any + // argument types. + // A vararg is included in uf_args.ga_len but not in uf_arg_types. + // The type is included in "tt_args". + if (argcount > 0 || varargs) + { + ufunc->uf_func_type = alloc_func_type(ufunc->uf_ret_type, + argcount, &ufunc->uf_type_list); + // Add argument types to the function type. + if (func_type_add_arg_types(ufunc->uf_func_type, + argcount + varargs, + &ufunc->uf_type_list) == FAIL) + return; + ufunc->uf_func_type->tt_argcount = argcount + varargs; + ufunc->uf_func_type->tt_min_argcount = + argcount - ufunc->uf_def_args.ga_len; + if (ufunc->uf_arg_types == NULL) + { + int i; + + // lambda does not have argument types. + for (i = 0; i < argcount; ++i) + ufunc->uf_func_type->tt_args[i] = &t_any; + } + else + mch_memmove(ufunc->uf_func_type->tt_args, + ufunc->uf_arg_types, sizeof(type_T *) * argcount); + if (varargs) + { + ufunc->uf_func_type->tt_args[argcount] = + ufunc->uf_va_type == NULL ? &t_any : ufunc->uf_va_type; + ufunc->uf_func_type->tt_flags = TTFLAG_VARARGS; + } + } + else + // No arguments, can use a predefined type. + ufunc->uf_func_type = get_func_type(ufunc->uf_ret_type, + argcount, &ufunc->uf_type_list); +} + + /* * Delete an instruction, free what it contains. */ From 45a1508a229b1d1d2eb79cabe55a183dc18fd040 Mon Sep 17 00:00:00 2001 From: Bram Moolenaar <Bram@vim.org> Date: Mon, 25 May 2020 00:28:33 +0200 Subject: [PATCH 220/230] patch 8.2.0821: Vim9: memory leak in expr test Problem: Vim9: memory leak in expr test. Solution: Do not decrement the length of the list of functions if the current function is not at the end. --- src/version.c | 2 ++ src/vim9compile.c | 8 +++++--- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/src/version.c b/src/version.c index a1e4a7f487..2d99068b09 100644 --- a/src/version.c +++ b/src/version.c @@ -746,6 +746,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 821, /**/ 820, /**/ diff --git a/src/vim9compile.c b/src/vim9compile.c index 7d302da83a..5adea9f7e0 100644 --- a/src/vim9compile.c +++ b/src/vim9compile.c @@ -1443,7 +1443,7 @@ generate_CALL(cctx_T *cctx, ufunc_T *ufunc, int pushed_argcount) } } if (ufunc->uf_dfunc_idx == UF_TO_BE_COMPILED) - if (compile_def_function(ufunc, TRUE, cctx) == FAIL) + if (compile_def_function(ufunc, TRUE, NULL) == FAIL) return FAIL; } @@ -6776,9 +6776,11 @@ erret: delete_instr(((isn_T *)instr->ga_data) + idx); ga_clear(instr); - ufunc->uf_dfunc_idx = UF_NOT_COMPILED; - if (!dfunc->df_deleted) + // if using the last entry in the table we might as well remove it + if (!dfunc->df_deleted + && ufunc->uf_dfunc_idx == def_functions.ga_len - 1) --def_functions.ga_len; + ufunc->uf_dfunc_idx = UF_NOT_COMPILED; while (cctx.ctx_scope != NULL) drop_scope(&cctx); From 2eec37926db6d31beb36f162ac00357a30c093c8 Mon Sep 17 00:00:00 2001 From: Bram Moolenaar <Bram@vim.org> Date: Mon, 25 May 2020 20:33:55 +0200 Subject: [PATCH 221/230] patch 8.2.0822: Vim9: code left over from discovery phase Problem: Vim9: code left over from discovery phase. Solution: Remove the dead code. --- src/evalvars.c | 18 ++---------- src/ex_cmds.h | 2 +- src/ex_docmd.c | 1 - src/proto/evalvars.pro | 1 - src/proto/scriptfile.pro | 2 -- src/scriptfile.c | 60 +++------------------------------------- src/version.c | 2 ++ 7 files changed, 9 insertions(+), 77 deletions(-) diff --git a/src/evalvars.c b/src/evalvars.c index a45080b540..e7a1b6d7ce 100644 --- a/src/evalvars.c +++ b/src/evalvars.c @@ -164,7 +164,6 @@ static dict_T vimvardict; // Dictionary with v: variables // for VIM_VERSION_ defines #include "version.h" -static void ex_let_const(exarg_T *eap); static char_u *skip_var_one(char_u *arg, int include_type); static void list_glob_vars(int *first); static void list_buf_vars(int *first); @@ -682,27 +681,14 @@ heredoc_get(exarg_T *eap, char_u *cmd, int script_get) * ":let [var1, var2] = expr" unpack list. * ":let var =<< ..." heredoc * ":let var: string" Vim9 declaration - */ - void -ex_let(exarg_T *eap) -{ - ex_let_const(eap); -} - -/* + * * ":const" list all variable values * ":const var1 var2" list variable values * ":const var = expr" assignment command. * ":const [var1, var2] = expr" unpack list. */ void -ex_const(exarg_T *eap) -{ - ex_let_const(eap); -} - - static void -ex_let_const(exarg_T *eap) +ex_let(exarg_T *eap) { char_u *arg = eap->arg; char_u *expr = NULL; diff --git a/src/ex_cmds.h b/src/ex_cmds.h index 2d86c5dc7e..f68c4fd0b2 100644 --- a/src/ex_cmds.h +++ b/src/ex_cmds.h @@ -396,7 +396,7 @@ EXCMD(CMD_continue, "continue", ex_continue, EXCMD(CMD_confirm, "confirm", ex_wrongmodifier, EX_NEEDARG|EX_EXTRA|EX_NOTRLCOM|EX_CMDWIN, ADDR_NONE), -EXCMD(CMD_const, "const", ex_const, +EXCMD(CMD_const, "const", ex_let, EX_EXTRA|EX_NOTRLCOM|EX_SBOXOK|EX_CMDWIN, ADDR_NONE), EXCMD(CMD_copen, "copen", ex_copen, diff --git a/src/ex_docmd.c b/src/ex_docmd.c index 3d590e5577..90f3a6dc29 100644 --- a/src/ex_docmd.c +++ b/src/ex_docmd.c @@ -269,7 +269,6 @@ static void ex_tag_cmd(exarg_T *eap, char_u *name); # define ex_call ex_ni # define ex_catch ex_ni # define ex_compiler ex_ni -# define ex_const ex_ni # define ex_continue ex_ni # define ex_debug ex_ni # define ex_debuggreedy ex_ni diff --git a/src/proto/evalvars.pro b/src/proto/evalvars.pro index 58e922113e..0d2e7b40d0 100644 --- a/src/proto/evalvars.pro +++ b/src/proto/evalvars.pro @@ -15,7 +15,6 @@ void prepare_vimvar(int idx, typval_T *save_tv); void restore_vimvar(int idx, typval_T *save_tv); list_T *heredoc_get(exarg_T *eap, char_u *cmd, int script_get); void ex_let(exarg_T *eap); -void ex_const(exarg_T *eap); int ex_let_vars(char_u *arg_start, typval_T *tv, int copy, int semicolon, int var_count, int flags, char_u *op); char_u *skip_var_list(char_u *arg, int include_type, int *var_count, int *semicolon); void list_hashtable_vars(hashtab_T *ht, char *prefix, int empty, int *first); diff --git a/src/proto/scriptfile.pro b/src/proto/scriptfile.pro index 84536ba78e..111e855a74 100644 --- a/src/proto/scriptfile.pro +++ b/src/proto/scriptfile.pro @@ -19,8 +19,6 @@ int ExpandPackAddDir(char_u *pat, int *num_file, char_u ***file); void ex_source(exarg_T *eap); void ex_options(exarg_T *eap); linenr_T *source_breakpoint(void *cookie); -garray_T *source_get_line_ga(void *cookie); -void source_use_line_ga(void *cookie); int *source_dbg_tick(void *cookie); int source_level(void *cookie); int do_source(char_u *fname, int check_other, int is_vimrc, int *ret_sid); diff --git a/src/scriptfile.c b/src/scriptfile.c index 7a148a7c8a..f42c3d04b0 100644 --- a/src/scriptfile.c +++ b/src/scriptfile.c @@ -998,8 +998,6 @@ struct source_cookie int error; // TRUE if LF found after CR-LF #endif #ifdef FEAT_EVAL - garray_T lines_ga; // lines read in previous pass - int use_lines_ga; // next line to get from "lines_ga" linenr_T breakpoint; // next line with breakpoint or zero char_u *fname; // name of sourced file int dbg_tick; // debug_tick when breakpoint was set @@ -1018,24 +1016,6 @@ source_breakpoint(void *cookie) return &((struct source_cookie *)cookie)->breakpoint; } -/* - * Get the grow array to store script lines in. - */ - garray_T * -source_get_line_ga(void *cookie) -{ - return &((struct source_cookie *)cookie)->lines_ga; -} - -/* - * Set the index to start reading from the grow array with script lines. - */ - void -source_use_line_ga(void *cookie) -{ - ((struct source_cookie *)cookie)->use_lines_ga = 0; -} - /* * Return the address holding the debug tick for a source cookie. */ @@ -1255,9 +1235,6 @@ do_source( cookie.finished = FALSE; #ifdef FEAT_EVAL - ga_init2(&cookie.lines_ga, sizeof(char_u *), 200); - cookie.use_lines_ga = -1; - // Check if this script has a breakpoint. cookie.breakpoint = dbg_find_breakpoint(TRUE, fname_exp, (linenr_T)0); cookie.fname = fname_exp; @@ -1302,6 +1279,9 @@ do_source( si->sn_version = 1; current_sctx.sc_sid = sid; + // In Vim9 script all script-local variables are removed when reloading + // the same script. In legacy script they remain but "const" can be + // set again. ht = &SCRIPT_VARS(sid); if (is_vim9) hashtab_free_contents(ht); @@ -1475,9 +1455,6 @@ almosttheend: vim_free(cookie.nextline); vim_free(firstline); convert_setup(&cookie.conv, NULL, NULL); -#ifdef FEAT_EVAL - ga_clear_strings(&cookie.lines_ga); -#endif if (trigger_source_post) apply_autocmds(EVENT_SOURCEPOST, fname_exp, fname_exp, FALSE, curbuf); @@ -1733,31 +1710,6 @@ getsourceline(int c UNUSED, void *cookie, int indent UNUSED, int do_concat) // one now. if (sp->finished) line = NULL; -#ifdef FEAT_EVAL - else if (sp->use_lines_ga >= 0) - { - // Get a line that was read in ex_vim9script(). - for (;;) - { - if (sp->use_lines_ga >= sp->lines_ga.ga_len) - { - line = NULL; - break; - } - else - { - line = ((char_u **)(sp->lines_ga.ga_data))[sp->use_lines_ga]; - ((char_u **)(sp->lines_ga.ga_data))[sp->use_lines_ga] = NULL; - ++sp->use_lines_ga; - if (line != NULL) - break; - // Skip NULL lines, they are equivalent to blank lines. - ++sp->sourcing_lnum; - } - } - SOURCING_LNUM = sp->sourcing_lnum + 1; - } -#endif else if (sp->nextline == NULL) line = get_one_sourceline(sp); else @@ -1773,11 +1725,7 @@ getsourceline(int c UNUSED, void *cookie, int indent UNUSED, int do_concat) // Only concatenate lines starting with a \ when 'cpoptions' doesn't // contain the 'C' flag. - if (line != NULL && do_concat && vim_strchr(p_cpo, CPO_CONCAT) == NULL -#ifdef FEAT_EVAL - && sp->use_lines_ga < 0 -#endif - ) + if (line != NULL && do_concat && vim_strchr(p_cpo, CPO_CONCAT) == NULL) { // compensate for the one line read-ahead --sp->sourcing_lnum; diff --git a/src/version.c b/src/version.c index 2d99068b09..c120d82f09 100644 --- a/src/version.c +++ b/src/version.c @@ -746,6 +746,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 822, /**/ 821, /**/ From 25e0f5863e9010a75a1ff0d04e8f886403968755 Mon Sep 17 00:00:00 2001 From: Bram Moolenaar <Bram@vim.org> Date: Mon, 25 May 2020 22:36:50 +0200 Subject: [PATCH 222/230] patch 8.2.0823: Vim9: script reload test is disabled Problem: Vim9: script reload test is disabled. Solution: Compile a function in the context of the script where it was defined. Set execution stack for compiled function. Add a test that an error is reported for the right file/function. --- src/ex_docmd.c | 6 ++-- src/ex_eval.c | 47 ++++++++++++++++++++++---------- src/globals.h | 2 +- src/proto/scriptfile.pro | 3 +- src/scriptfile.c | 21 ++++++++++++-- src/structs.h | 12 +++++--- src/testdir/test_vim9_script.vim | 37 +++++++++++++++++++++---- src/userfunc.c | 6 ++-- src/version.c | 2 ++ src/vim9compile.c | 21 ++++++++++---- src/vim9execute.c | 9 +++++- 11 files changed, 125 insertions(+), 41 deletions(-) diff --git a/src/ex_docmd.c b/src/ex_docmd.c index 90f3a6dc29..adde9d75f2 100644 --- a/src/ex_docmd.c +++ b/src/ex_docmd.c @@ -634,8 +634,8 @@ do_cmdline( int *dbg_tick = NULL; // ptr to dbg_tick field in cookie struct dbg_stuff debug_saved; // saved things for debug mode int initial_trylevel; - struct msglist **saved_msg_list = NULL; - struct msglist *private_msg_list; + msglist_T **saved_msg_list = NULL; + msglist_T *private_msg_list; // "fgetline" and "cookie" passed to do_one_cmd() char_u *(*cmd_getline)(int, void *, int, int); @@ -1238,7 +1238,7 @@ do_cmdline( if (did_throw) { void *p = NULL; - struct msglist *messages = NULL, *next; + msglist_T *messages = NULL, *next; /* * If the uncaught exception is a user exception, report it as an diff --git a/src/ex_eval.c b/src/ex_eval.c index f7253438d7..68207cbe7c 100644 --- a/src/ex_eval.c +++ b/src/ex_eval.c @@ -146,8 +146,8 @@ cause_errthrow( int severe, int *ignore) { - struct msglist *elem; - struct msglist **plist; + msglist_T *elem; + msglist_T **plist; /* * Do nothing when displaying the interrupt message or reporting an @@ -251,7 +251,7 @@ cause_errthrow( while (*plist != NULL) plist = &(*plist)->next; - elem = ALLOC_ONE(struct msglist); + elem = ALLOC_CLEAR_ONE(msglist_T); if (elem == NULL) { suppress_errthrow = TRUE; @@ -287,6 +287,11 @@ cause_errthrow( else (*msg_list)->throw_msg = tmsg; } + + // Get the source name and lnum now, it may change before + // reaching do_errthrow(). + elem->sfile = estack_sfile(); + elem->slnum = SOURCING_LNUM; } } } @@ -298,15 +303,16 @@ cause_errthrow( * Free a "msg_list" and the messages it contains. */ static void -free_msglist(struct msglist *l) +free_msglist(msglist_T *l) { - struct msglist *messages, *next; + msglist_T *messages, *next; messages = l; while (messages != NULL) { next = messages->next; vim_free(messages->msg); + vim_free(messages->sfile); vim_free(messages); messages = next; } @@ -428,7 +434,7 @@ get_exception_string( if (type == ET_ERROR) { *should_free = TRUE; - mesg = ((struct msglist *)value)->throw_msg; + mesg = ((msglist_T *)value)->throw_msg; if (cmdname != NULL && *cmdname != NUL) { cmdlen = (int)STRLEN(cmdname); @@ -526,23 +532,34 @@ throw_exception(void *value, except_type_T type, char_u *cmdname) if (type == ET_ERROR) // Store the original message and prefix the exception value with // "Vim:" or, if a command name is given, "Vim(cmdname):". - excp->messages = (struct msglist *)value; + excp->messages = (msglist_T *)value; excp->value = get_exception_string(value, type, cmdname, &should_free); if (excp->value == NULL && should_free) goto nomem; excp->type = type; - excp->throw_name = estack_sfile(); - if (excp->throw_name == NULL) - excp->throw_name = vim_strsave((char_u *)""); - if (excp->throw_name == NULL) + if (type == ET_ERROR && ((msglist_T *)value)->sfile != NULL) { - if (should_free) - vim_free(excp->value); - goto nomem; + msglist_T *entry = (msglist_T *)value; + + excp->throw_name = entry->sfile; + entry->sfile = NULL; + excp->throw_lnum = entry->slnum; + } + else + { + excp->throw_name = estack_sfile(); + if (excp->throw_name == NULL) + excp->throw_name = vim_strsave((char_u *)""); + if (excp->throw_name == NULL) + { + if (should_free) + vim_free(excp->value); + goto nomem; + } + excp->throw_lnum = SOURCING_LNUM; } - excp->throw_lnum = SOURCING_LNUM; if (p_verbose >= 13 || debug_break_level > 0) { diff --git a/src/globals.h b/src/globals.h index 648da7dcef..f0716c506c 100644 --- a/src/globals.h +++ b/src/globals.h @@ -344,7 +344,7 @@ EXTERN int force_abort INIT(= FALSE); * field of a later list element, when the "emsg_severe" flag was set when the * emsg() call was made. */ -EXTERN struct msglist **msg_list INIT(= NULL); +EXTERN msglist_T **msg_list INIT(= NULL); /* * suppress_errthrow: When TRUE, don't convert an error to an exception. Used diff --git a/src/proto/scriptfile.pro b/src/proto/scriptfile.pro index 111e855a74..e2a267141a 100644 --- a/src/proto/scriptfile.pro +++ b/src/proto/scriptfile.pro @@ -1,7 +1,8 @@ /* scriptfile.c */ void estack_init(void); estack_T *estack_push(etype_T type, char_u *name, long lnum); -void estack_push_ufunc(etype_T type, ufunc_T *ufunc, long lnum); +void estack_push_ufunc(ufunc_T *ufunc, long lnum); +int estack_top_is_ufunc(ufunc_T *ufunc, long lnum); void estack_pop(void); char_u *estack_sfile(void); void ex_runtime(exarg_T *eap); diff --git a/src/scriptfile.c b/src/scriptfile.c index f42c3d04b0..746a3d3444 100644 --- a/src/scriptfile.c +++ b/src/scriptfile.c @@ -69,14 +69,31 @@ estack_push(etype_T type, char_u *name, long lnum) * Add a user function to the execution stack. */ void -estack_push_ufunc(etype_T type, ufunc_T *ufunc, long lnum) +estack_push_ufunc(ufunc_T *ufunc, long lnum) { - estack_T *entry = estack_push(type, + estack_T *entry = estack_push(ETYPE_UFUNC, ufunc->uf_name_exp != NULL ? ufunc->uf_name_exp : ufunc->uf_name, lnum); if (entry != NULL) entry->es_info.ufunc = ufunc; } + +/* + * Return TRUE if "ufunc" with "lnum" is already at the top of the exe stack. + */ + int +estack_top_is_ufunc(ufunc_T *ufunc, long lnum) +{ + estack_T *entry; + + if (exestack.ga_len == 0) + return FALSE; + entry = ((estack_T *)exestack.ga_data) + exestack.ga_len - 1; + return entry->es_type == ETYPE_UFUNC + && STRCMP( entry->es_name, ufunc->uf_name_exp != NULL + ? ufunc->uf_name_exp : ufunc->uf_name) == 0 + && entry->es_lnum == lnum; +} #endif /* diff --git a/src/structs.h b/src/structs.h index e58e644726..d6f9030c9e 100644 --- a/src/structs.h +++ b/src/structs.h @@ -927,13 +927,16 @@ typedef struct { * A list of error messages that can be converted to an exception. "throw_msg" * is only set in the first element of the list. Usually, it points to the * original message stored in that element, but sometimes it points to a later - * message in the list. See cause_errthrow() below. + * message in the list. See cause_errthrow(). */ +typedef struct msglist msglist_T; struct msglist { - char *msg; // original message - char *throw_msg; // msg to throw: usually original one - struct msglist *next; // next of several messages in a row + char *msg; // original message, allocated + char *throw_msg; // msg to throw: usually original one + char_u *sfile; // value from estack_sfile(), allocated + long slnum; // line number for "sfile" + msglist_T *next; // next of several messages in a row }; /* @@ -1516,6 +1519,7 @@ struct blobvar_S #if defined(FEAT_EVAL) || defined(PROTO) typedef struct funccall_S funccall_T; +// values used for "uf_dfunc_idx" # define UF_NOT_COMPILED -2 # define UF_TO_BE_COMPILED -1 diff --git a/src/testdir/test_vim9_script.vim b/src/testdir/test_vim9_script.vim index ea976c52c9..1092ff9f26 100644 --- a/src/testdir/test_vim9_script.vim +++ b/src/testdir/test_vim9_script.vim @@ -745,9 +745,6 @@ def Test_vim9script_fails() enddef def Test_vim9script_reload_import() - " TODO: make it work to compile when not in the script context anymore - return - let lines =<< trim END vim9script const var = '' @@ -797,9 +794,6 @@ def Test_vim9script_reload_import() enddef def Test_vim9script_reload_delfunc() - " TODO: make it work to compile when not in the script context anymore - return - let first_lines =<< trim END vim9script def FuncYes(): string @@ -920,6 +914,37 @@ def Test_import_rtp() delete('import', 'rf') enddef +def Test_import_compile_error() + let export_lines = [ + 'vim9script', + 'export def ExpFunc(): string', + ' return notDefined', + 'enddef', + ] + writefile(export_lines, 'Xexported.vim') + + let import_lines = [ + 'vim9script', + 'import ExpFunc from "./Xexported.vim"', + 'def ImpFunc()', + ' echo ExpFunc()', + 'enddef', + 'defcompile', + ] + writefile(import_lines, 'Ximport.vim') + + try + source Ximport.vim + catch /E1001/ + " Error should be fore the Xexported.vim file. + assert_match('E1001: variable not found: notDefined', v:exception) + assert_match('function <SNR>\d\+_ImpFunc\[1\]..<SNR>\d\+_ExpFunc, line 1', v:throwpoint) + endtry + + delete('Xexported.vim') + delete('Ximport.vim') +enddef + def Test_fixed_size_list() " will be allocated as one piece of memory, check that changes work let l = [1, 2, 3, 4] diff --git a/src/userfunc.c b/src/userfunc.c index bc92c2aaf3..87e06c61da 100644 --- a/src/userfunc.c +++ b/src/userfunc.c @@ -1114,11 +1114,11 @@ call_user_func( if (fp->uf_dfunc_idx != UF_NOT_COMPILED) { - estack_push_ufunc(ETYPE_UFUNC, fp, 1); + estack_push_ufunc(fp, 1); save_current_sctx = current_sctx; current_sctx = fp->uf_script_ctx; - // Execute the compiled function. + // Execute the function, possibly compiling it first. call_def_function(fp, argcount, argvars, funcexe->partial, rettv); --depth; current_funccal = fc->caller; @@ -1288,7 +1288,7 @@ call_user_func( ++sandbox; } - estack_push_ufunc(ETYPE_UFUNC, fp, 1); + estack_push_ufunc(fp, 1); ESTACK_CHECK_SETUP if (p_verbose >= 12) { diff --git a/src/version.c b/src/version.c index c120d82f09..c4648f74f9 100644 --- a/src/version.c +++ b/src/version.c @@ -746,6 +746,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 823, /**/ 822, /**/ diff --git a/src/vim9compile.c b/src/vim9compile.c index 5adea9f7e0..f59ec12b7f 100644 --- a/src/vim9compile.c +++ b/src/vim9compile.c @@ -2323,8 +2323,7 @@ next_line_from_context(cctx_T *cctx) } line = ((char_u **)cctx->ctx_ufunc->uf_lines.ga_data)[cctx->ctx_lnum]; cctx->ctx_line_start = line; - SOURCING_LNUM = cctx->ctx_ufunc->uf_script_ctx.sc_lnum - + cctx->ctx_lnum + 1; + SOURCING_LNUM = cctx->ctx_lnum + 1; } while (line == NULL || *skipwhite(line) == NUL); return line; } @@ -6349,14 +6348,15 @@ compile_def_function(ufunc_T *ufunc, int set_return_type, cctx_T *outer_cctx) int called_emsg_before = called_emsg; int ret = FAIL; sctx_T save_current_sctx = current_sctx; + int do_estack_push; int emsg_before = called_emsg; + // When using a function that was compiled before: Free old instructions. + // Otherwise add a new entry in "def_functions". if (ufunc->uf_dfunc_idx >= 0) { - // Redefining a function that was compiled before. dfunc_T *dfunc = ((dfunc_T *)def_functions.ga_data) + ufunc->uf_dfunc_idx; - // Free old instructions. delete_def_function_contents(dfunc); } else if (add_def_function(ufunc) == FAIL) @@ -6373,9 +6373,17 @@ compile_def_function(ufunc_T *ufunc, int set_return_type, cctx_T *outer_cctx) ga_init2(&cctx.ctx_instr, sizeof(isn_T), 50); instr = &cctx.ctx_instr; - // Most modern script version. + // Set the context to the function, it may be compiled when called from + // another script. Set the script version to the most modern one. + // The line number will be set in next_line_from_context(). + current_sctx = ufunc->uf_script_ctx; current_sctx.sc_version = SCRIPT_VERSION_VIM9; + // Make sure error messages are OK. + do_estack_push = !estack_top_is_ufunc(ufunc, 1); + if (do_estack_push) + estack_push_ufunc(ufunc, 1); + if (ufunc->uf_def_args.ga_len > 0) { int count = ufunc->uf_def_args.ga_len; @@ -6795,6 +6803,9 @@ erret: } current_sctx = save_current_sctx; + if (do_estack_push) + estack_pop(); + free_imported(&cctx); free_locals(&cctx); ga_clear(&cctx.ctx_type_stack); diff --git a/src/vim9execute.c b/src/vim9execute.c index f6aa140653..1a87476dc0 100644 --- a/src/vim9execute.c +++ b/src/vim9execute.c @@ -230,7 +230,7 @@ call_dfunc(int cdf_idx, int argcount_arg, ectx_T *ectx) // Set execution state to the start of the called function. ectx->ec_dfunc_idx = cdf_idx; ectx->ec_instr = dfunc->df_instr; - estack_push_ufunc(ETYPE_UFUNC, dfunc->df_ufunc, 1); + estack_push_ufunc(dfunc->df_ufunc, 1); // Decide where to start execution, handles optional arguments. init_instr_idx(ufunc, argcount, ectx); @@ -656,6 +656,7 @@ call_def_function( int defcount = ufunc->uf_args.ga_len - argc; int save_sc_version = current_sctx.sc_version; int breakcheck_count = 0; + int called_emsg_before = called_emsg; // Get pointer to item in the stack. #define STACK_TV(idx) (((typval_T *)ectx.ec_stack.ga_data) + idx) @@ -673,7 +674,13 @@ call_def_function( if (ufunc->uf_dfunc_idx == UF_NOT_COMPILED || (ufunc->uf_dfunc_idx == UF_TO_BE_COMPILED && compile_def_function(ufunc, FALSE, NULL) == FAIL)) + { + if (called_emsg == called_emsg_before) + semsg(_("E1091: Function is not compiled: %s"), + ufunc->uf_name_exp == NULL + ? ufunc->uf_name : ufunc->uf_name_exp); return FAIL; + } { // Check the function was really compiled. From 1919371b2b9ddb1a645f40b59adbd89317530882 Mon Sep 17 00:00:00 2001 From: Bram Moolenaar <Bram@vim.org> Date: Mon, 25 May 2020 23:01:42 +0200 Subject: [PATCH 223/230] patch 8.2.0824: still not enough memory allocated when converting string Problem: Still not enough memory allocated when converting string with special character. Solution: Reserve space for expanding K_SPECIAL. (closes #6130) --- src/eval.c | 7 ++++--- src/testdir/test_functions.vim | 1 + src/version.c | 2 ++ 3 files changed, 7 insertions(+), 3 deletions(-) diff --git a/src/eval.c b/src/eval.c index d76ec94102..87b7644251 100644 --- a/src/eval.c +++ b/src/eval.c @@ -3515,10 +3515,11 @@ get_string_tv(char_u **arg, typval_T *rettv, int evaluate) { ++p; // A "\<x>" form occupies at least 4 characters, and produces up - // to 9 characters (6 for the char and 3 for a modifier): reserve - // space for 5 extra. + // to 21 characters (3 * 6 for the char and 3 for a modifier): + // reserve space for 18 extra. + // Each byte in the char could be encoded as K_SPECIAL K_EXTRA x. if (*p == '<') - extra += 5; + extra += 18; } } diff --git a/src/testdir/test_functions.vim b/src/testdir/test_functions.vim index 712aec4eae..d342e513ff 100644 --- a/src/testdir/test_functions.vim +++ b/src/testdir/test_functions.vim @@ -2280,6 +2280,7 @@ func Test_nr2char() call assert_equal('a', nr2char(97, 0)) call assert_equal("\x80\xfc\b\xf4\x80\xfeX\x80\xfeX\x80\xfeX", eval('"\<M-' .. nr2char(0x100000) .. '>"')) + call assert_equal("\x80\xfc\b\xfd\x80\xfeX\x80\xfeX\x80\xfeX\x80\xfeX\x80\xfeX", eval('"\<M-' .. nr2char(0x40000000) .. '>"')) endfunc " Test for screenattr(), screenchar() and screenchars() functions diff --git a/src/version.c b/src/version.c index c4648f74f9..ce5f627ca2 100644 --- a/src/version.c +++ b/src/version.c @@ -746,6 +746,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 824, /**/ 823, /**/ From a14e6975478adeddcc2161edc1ec611016aa89f3 Mon Sep 17 00:00:00 2001 From: Bram Moolenaar <Bram@vim.org> Date: Mon, 25 May 2020 23:29:28 +0200 Subject: [PATCH 224/230] patch 8.2.0825: def_function() may return pointer that was freed Problem: def_function() may return pointer that was freed. Solution: Set "fp" to NULL after freeing it. --- src/userfunc.c | 3 +++ src/version.c | 2 ++ 2 files changed, 5 insertions(+) diff --git a/src/userfunc.c b/src/userfunc.c index 87e06c61da..c50a871c2b 100644 --- a/src/userfunc.c +++ b/src/userfunc.c @@ -3140,12 +3140,14 @@ def_function(exarg_T *eap, char_u *name_arg) if (fudi.fd_di == NULL) { vim_free(fp); + fp = NULL; goto erret; } if (dict_add(fudi.fd_dict, fudi.fd_di) == FAIL) { vim_free(fudi.fd_di); vim_free(fp); + fp = NULL; goto erret; } } @@ -3169,6 +3171,7 @@ def_function(exarg_T *eap, char_u *name_arg) else if (hash_add(&func_hashtab, UF2HIKEY(fp)) == FAIL) { vim_free(fp); + fp = NULL; goto erret; } fp->uf_refcount = 1; diff --git a/src/version.c b/src/version.c index ce5f627ca2..5ccbfad01e 100644 --- a/src/version.c +++ b/src/version.c @@ -746,6 +746,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 825, /**/ 824, /**/ From ebc3de634f4c2893f34e41b4f8da1d59212e59ea Mon Sep 17 00:00:00 2001 From: Bram Moolenaar <Bram@vim.org> Date: Tue, 26 May 2020 11:08:28 +0200 Subject: [PATCH 225/230] patch 8.2.0826: Vim9: crash in :defcompile Problem: Vim9: crash in :defcompile. Solution: Restart the loop after a call to compile_def_function() caused the hash table to resize. --- src/userfunc.c | 13 ++++++++++++- src/version.c | 2 ++ 2 files changed, 14 insertions(+), 1 deletion(-) diff --git a/src/userfunc.c b/src/userfunc.c index c50a871c2b..4a12c1984c 100644 --- a/src/userfunc.c +++ b/src/userfunc.c @@ -3326,7 +3326,8 @@ ex_function(exarg_T *eap) void ex_defcompile(exarg_T *eap UNUSED) { - int todo = (int)func_hashtab.ht_used; + long_u ht_used = func_hashtab.ht_used; + int todo = (int)ht_used; hashitem_T *hi; ufunc_T *ufunc; @@ -3338,7 +3339,17 @@ ex_defcompile(exarg_T *eap UNUSED) ufunc = HI2UF(hi); if (ufunc->uf_script_ctx.sc_sid == current_sctx.sc_sid && ufunc->uf_dfunc_idx == UF_TO_BE_COMPILED) + { compile_def_function(ufunc, FALSE, NULL); + + if (func_hashtab.ht_used != ht_used) + { + // another function has been defined, need to start over + hi = func_hashtab.ht_array; + ht_used = func_hashtab.ht_used; + todo = (int)ht_used; + } + } } } } diff --git a/src/version.c b/src/version.c index 5ccbfad01e..1730875514 100644 --- a/src/version.c +++ b/src/version.c @@ -746,6 +746,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 826, /**/ 825, /**/ From 285b189260e2d753454449e429f2caa17e1c39a5 Mon Sep 17 00:00:00 2001 From: Bram Moolenaar <Bram@vim.org> Date: Tue, 26 May 2020 11:37:26 +0200 Subject: [PATCH 226/230] patch 8.2.0827: Vim9: crash in :defcompile Problem: Vim9: crash in :defcompile. Solution: Fix off-by-one error. --- src/userfunc.c | 1 + src/version.c | 2 ++ 2 files changed, 3 insertions(+) diff --git a/src/userfunc.c b/src/userfunc.c index 4a12c1984c..469dcc1a53 100644 --- a/src/userfunc.c +++ b/src/userfunc.c @@ -3348,6 +3348,7 @@ ex_defcompile(exarg_T *eap UNUSED) hi = func_hashtab.ht_array; ht_used = func_hashtab.ht_used; todo = (int)ht_used; + --hi; } } } diff --git a/src/version.c b/src/version.c index 1730875514..8a94dde4c1 100644 --- a/src/version.c +++ b/src/version.c @@ -746,6 +746,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 827, /**/ 826, /**/ From 92c098d18e435a7a762409744ebe2dbb3746ed77 Mon Sep 17 00:00:00 2001 From: Bram Moolenaar <Bram@vim.org> Date: Tue, 26 May 2020 20:09:11 +0200 Subject: [PATCH 227/230] patch 8.2.0828: Travis: regexp patttern doesn't work everywhere Problem: Travis: regexp patttern doesn't work everywhere. Solution: Use [:blank:] instead of \b. (Ozaki Kiichi, closes #6146) --- .travis.yml | 16 ++++++++++------ ci/config.mk.clang.sed | 3 ++- ci/config.mk.gcc.sed | 2 +- ci/config.mk.sed | 4 ++-- src/if_ruby.c | 8 +++++++- src/version.c | 2 ++ 6 files changed, 24 insertions(+), 11 deletions(-) diff --git a/.travis.yml b/.travis.yml index 7c1ecbca56..ef96f084d0 100644 --- a/.travis.yml +++ b/.travis.yml @@ -125,7 +125,12 @@ script: # Append various warning flags to CFLAGS. # BSD sed needs backup extension specified. sed -i.bak -f ci/config.mk.sed ${SRCDIR}/auto/config.mk - sed -i.bak -f ci/config.mk.${CC}.sed ${SRCDIR}/auto/config.mk + if [[ "${TRAVIS_OS_NAME}" = "osx" ]]; then + # On macOS, the entity of gcc is clang. + sed -i.bak -f ci/config.mk.clang.sed ${SRCDIR}/auto/config.mk + else + sed -i.bak -f ci/config.mk.${CC}.sed ${SRCDIR}/auto/config.mk + fi make ${SHADOWOPT} -j${NPROC} fi - echo -en "travis_fold:end:build\\r\\033[0K" @@ -141,11 +146,10 @@ script: - do_test make ${SHADOWOPT} ${TEST} && FOLD_MARKER=travis_fold - echo -en "${FOLD_MARKER}:end:test\\r\\033[0K" - -# instead of a 2*2*8 matrix (2*os + 2*compiler + 8*env), -# exclude some builds on mac os x and linux -# on mac os x "tiny" is always without GUI -# linux: 2*compiler + 5*env + mac: 2*compiler + 2*env +# Instead of using all environments with both compilers on both systems, +# exclude some builds on mac os x and linux. +# On mac os x "tiny" is always without GUI, use 2 compilers in 2 environments. +# Linux: 2 compilers on some of the environments + gcc on os390 jobs: include: - <<: *osx diff --git a/ci/config.mk.clang.sed b/ci/config.mk.clang.sed index 40c6705ac3..da6044d830 100644 --- a/ci/config.mk.clang.sed +++ b/ci/config.mk.clang.sed @@ -1 +1,2 @@ -/^RUBY_CFLAGS\b/s/$/ -Wno-error=unknown-attributes -Wno-error=ignored-attributes/ +/^CFLAGS[[:blank:]]*=/s/$/ -Wno-error=missing-field-initializers/ +/^RUBY_CFLAGS[[:blank:]]*=/s/$/ -Wno-error=unknown-attributes -Wno-error=ignored-attributes/ diff --git a/ci/config.mk.gcc.sed b/ci/config.mk.gcc.sed index 3b11569eb0..f46e488488 100644 --- a/ci/config.mk.gcc.sed +++ b/ci/config.mk.gcc.sed @@ -1 +1 @@ -/^CFLAGS\b/s/$/ -Wno-error=maybe-uninitialized/ +/^CFLAGS[[:blank:]]*=/s/$/ -Wno-error=maybe-uninitialized/ diff --git a/ci/config.mk.sed b/ci/config.mk.sed index 31682787eb..cd2cd9c452 100644 --- a/ci/config.mk.sed +++ b/ci/config.mk.sed @@ -1,2 +1,2 @@ -/^CFLAGS\b/s/$/ -Wall -Wextra -Wshadow -Werror/ -/^PERL_CFLAGS\b/s/$/ -Wno-error=unused-function/ +/^CFLAGS[[:blank:]]*=/s/$/ -Wall -Wextra -Wshadow -Werror/ +/^PERL_CFLAGS[[:blank:]]*=/s/$/ -Wno-error=unused-function/ diff --git a/src/if_ruby.c b/src/if_ruby.c index e989c01336..6773a2a38a 100644 --- a/src/if_ruby.c +++ b/src/if_ruby.c @@ -100,7 +100,8 @@ #endif // On macOS pre-installed Ruby defines "SIZEOF_TIME_T" as "SIZEOF_LONG" so it -// conflicts with the definition in config.h then causes macro-redifned warning. +// conflicts with the definition in config.h then causes a macro-redefined +// warning. #ifdef SIZEOF_TIME_T # undef SIZEOF_TIME_T #endif @@ -113,6 +114,11 @@ # include <st.h> // for ST_STOP and ST_CONTINUE #endif +// See above. +#ifdef SIZEOF_TIME_T +# undef SIZEOF_TIME_T +#endif + #undef off_t // ruby defines off_t as _int64, Mingw uses long #undef EXTERN #undef _ diff --git a/src/version.c b/src/version.c index 8a94dde4c1..c2cb3ca690 100644 --- a/src/version.c +++ b/src/version.c @@ -746,6 +746,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 828, /**/ 827, /**/ From fcb0b61d15f66f0e9116a6bc56d9d8105bb913cf Mon Sep 17 00:00:00 2001 From: Bram Moolenaar <Bram@vim.org> Date: Tue, 26 May 2020 20:22:01 +0200 Subject: [PATCH 228/230] patch 8.2.0829: filter() may give misleading error message Problem: filter() may give misleading error message. Solution: Also mention Blob as an allowed argument. --- src/list.c | 2 +- src/testdir/test_filter_map.vim | 4 ++-- src/version.c | 2 ++ 3 files changed, 5 insertions(+), 3 deletions(-) diff --git a/src/list.c b/src/list.c index b9e7e340d7..7c06cfce57 100644 --- a/src/list.c +++ b/src/list.c @@ -1768,7 +1768,7 @@ filter_map(typval_T *argvars, typval_T *rettv, int map) } else { - semsg(_(e_listdictarg), ermsg); + semsg(_(e_listdictblobarg), ermsg); return; } diff --git a/src/testdir/test_filter_map.vim b/src/testdir/test_filter_map.vim index 0f58685c60..8883ea3cc5 100644 --- a/src/testdir/test_filter_map.vim +++ b/src/testdir/test_filter_map.vim @@ -92,8 +92,8 @@ endfunc func Test_map_filter_fails() call assert_fails('call map([1], "42 +")', 'E15:') call assert_fails('call filter([1], "42 +")', 'E15:') - call assert_fails("let l = map('abc', '\"> \" . v:val')", 'E712:') - call assert_fails("let l = filter('abc', '\"> \" . v:val')", 'E712:') + call assert_fails("let l = map('abc', '\"> \" . v:val')", 'E896:') + call assert_fails("let l = filter('abc', '\"> \" . v:val')", 'E896:') call assert_fails("let l = filter([1, 2, 3], '{}')", 'E728:') call assert_fails("let l = filter({'k' : 10}, '{}')", 'E728:') call assert_fails("let l = filter([1, 2], {})", 'E731:') diff --git a/src/version.c b/src/version.c index c2cb3ca690..f91ff1a99d 100644 --- a/src/version.c +++ b/src/version.c @@ -746,6 +746,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 829, /**/ 828, /**/ From 388a5d4f20b4b64341d1604aa238cab85827b892 Mon Sep 17 00:00:00 2001 From: Bram Moolenaar <Bram@vim.org> Date: Tue, 26 May 2020 21:20:45 +0200 Subject: [PATCH 229/230] Update runtime files --- runtime/compiler/eslint.vim | 16 ++++ runtime/compiler/standard.vim | 16 ++++ runtime/doc/eval.txt | 11 ++- runtime/doc/if_lua.txt | 2 +- runtime/doc/index.txt | 11 +-- runtime/doc/makehtml.awk | 2 +- runtime/doc/os_haiku.txt | 5 +- runtime/doc/popup.txt | 2 +- runtime/doc/repeat.txt | 9 +- runtime/doc/tags | 7 ++ runtime/doc/terminal.txt | 9 +- runtime/doc/todo.txt | 76 +++++++++++----- runtime/doc/vim9.txt | 89 ++++++------------- runtime/ftplugin/vim.vim | 20 ++--- runtime/indent/sshconfig.vim | 34 +++++++ runtime/indent/testdir/sshconfig.in | 53 +++++++++++ runtime/indent/testdir/sshconfig.ok | 53 +++++++++++ runtime/indent/tex.vim | 22 +++-- runtime/macros/less.vim | 6 +- .../dist/opt/termdebug/plugin/termdebug.vim | 13 ++- runtime/syntax/groovy.vim | 10 +-- runtime/syntax/javascript.vim | 8 +- runtime/syntax/spec.vim | 5 +- runtime/syntax/tex.vim | 5 +- runtime/syntax/vim.vim | 13 +-- 25 files changed, 349 insertions(+), 148 deletions(-) create mode 100644 runtime/compiler/eslint.vim create mode 100644 runtime/compiler/standard.vim create mode 100644 runtime/indent/sshconfig.vim create mode 100644 runtime/indent/testdir/sshconfig.in create mode 100644 runtime/indent/testdir/sshconfig.ok diff --git a/runtime/compiler/eslint.vim b/runtime/compiler/eslint.vim new file mode 100644 index 0000000000..1e7af2b182 --- /dev/null +++ b/runtime/compiler/eslint.vim @@ -0,0 +1,16 @@ +" Vim compiler file +" Compiler: ESLint for JavaScript +" Maintainer: Romain Lafourcade <romainlafourcade@gmail.com> +" Last Change: 2020 May 17 + +if exists("current_compiler") + finish +endif +let current_compiler = "eslint" + +if exists(":CompilerSet") != 2 + command -nargs=* CompilerSet setlocal <args> +endif + +CompilerSet makeprg=eslint\ --format\ compact +CompilerSet errorformat=%f:\ line\ %l\\,\ col\ %c\\,\ %m,%-G%.%# diff --git a/runtime/compiler/standard.vim b/runtime/compiler/standard.vim new file mode 100644 index 0000000000..b6bcf1f6b0 --- /dev/null +++ b/runtime/compiler/standard.vim @@ -0,0 +1,16 @@ +" Vim compiler file +" Compiler: Standard for JavaScript +" Maintainer: Romain Lafourcade <romainlafourcade@gmail.com> +" Last Change: 2020 May 17 + +if exists("current_compiler") + finish +endif +let current_compiler = "standard" + +if exists(":CompilerSet") != 2 + command -nargs=* CompilerSet setlocal <args> +endif + +CompilerSet makeprg=standard +CompilerSet errorformat=%f:\ line\ %l\\,\ col\ %c\\,\ %m,%-G%.%# diff --git a/runtime/doc/eval.txt b/runtime/doc/eval.txt index 1e0760fea2..89f011b8cf 100644 --- a/runtime/doc/eval.txt +++ b/runtime/doc/eval.txt @@ -1,4 +1,4 @@ -*eval.txt* For Vim version 8.2. Last change: 2020 Apr 19 +*eval.txt* For Vim version 8.2. Last change: 2020 May 25 VIM REFERENCE MANUAL by Bram Moolenaar @@ -584,6 +584,8 @@ adict. Weeding out entries from a Dictionary can be done with |filter()|: > :call filter(dict, 'v:val =~ "x"') This removes all entries from "dict" with a value not matching 'x'. +This can also be used to remove all entries: > + call filter(dict, 0) Dictionary function ~ @@ -1485,7 +1487,7 @@ the function returns: > :echo Bar(6) < 5 -Note that the variables must exist in the outer scope before the lamba is +Note that the variables must exist in the outer scope before the lambda is defined for this to work. See also |:func-closure|. Lambda and closure support can be checked with: > @@ -2916,6 +2918,7 @@ win_splitmove({nr}, {target} [, {options}]) Number move window {nr} to split of {target} winbufnr({nr}) Number buffer number of window {nr} wincol() Number window column of the cursor +windowsversion() String MS-Windows OS version winheight({nr}) Number height of window {nr} winlayout([{tabnr}]) List layout of windows in tab {tabnr} winline() Number window line of the cursor @@ -10221,7 +10224,7 @@ tr({src}, {fromstr}, {tostr}) *tr()* trim({text} [, {mask}]) *trim()* Return {text} as a String where any character in {mask} is - removed from the beginning and end of {text}. + removed from the beginning and end of {text}. If {mask} is not given, {mask} is all characters up to 0x20, which includes Tab, space, NL and CR, plus the non-breaking space character 0xa0. @@ -11144,6 +11147,8 @@ See |:verbose-cmd| for more information. NOTE: Use ! wisely. If used without care it can cause an existing function to be replaced unexpectedly, which is hard to debug. + NOTE: In Vim9 script script-local functions cannot be + deleted or redefined. For the {arguments} see |function-argument|. diff --git a/runtime/doc/if_lua.txt b/runtime/doc/if_lua.txt index ff108eebb6..63e227d303 100644 --- a/runtime/doc/if_lua.txt +++ b/runtime/doc/if_lua.txt @@ -1,4 +1,4 @@ -*if_lua.txt* For Vim version 8.2. Last change: 2019 Jul 21 +*if_lua.txt* For Vim version 8.2. Last change: 2020 May 17 VIM REFERENCE MANUAL by Luis Carvalho diff --git a/runtime/doc/index.txt b/runtime/doc/index.txt index 78d557f51e..0d47cc2938 100644 --- a/runtime/doc/index.txt +++ b/runtime/doc/index.txt @@ -1,4 +1,4 @@ -*index.txt* For Vim version 8.2. Last change: 2020 May 10 +*index.txt* For Vim version 8.2. Last change: 2020 May 26 VIM REFERENCE MANUAL by Bram Moolenaar @@ -828,7 +828,7 @@ tag char note action in Normal mode ~ |zD| zD delete folds recursively |zE| zE eliminate all folds |zF| zF create a fold for N lines -|zG| zG mark word as good spelled word +|zG| zG temporarily mark word as good spelled word |zH| zH when 'wrap' off scroll half a screenwidth to the right |zL| zL when 'wrap' off scroll half a screenwidth @@ -837,7 +837,7 @@ tag char note action in Normal mode ~ |zN| zN set 'foldenable' |zO| zO open folds recursively |zR| zR set 'foldlevel' to the deepest fold -|zW| zW mark word as wrong (bad) spelled word +|zW| zW temporarily mark word as bad spelled word |zX| zX re-apply 'foldlevel' |z^| z^ cursor on line N (default line above window), otherwise like "z-" @@ -849,7 +849,7 @@ tag char note action in Normal mode ~ position the cursor at the end (right side) of the screen |zf| zf{motion} create a fold for Nmove text -|zg| zg mark word as good spelled word +|zg| zg permanently mark word as good spelled word |zh| zh when 'wrap' off scroll screen N characters to the right |zi| zi toggle 'foldenable' @@ -870,7 +870,7 @@ tag char note action in Normal mode ~ |zuW| zuW undo |zW| |zuG| zuG undo |zG| |zv| zv open enough folds to view the cursor line -|zw| zw mark word as wrong (bad) spelled word +|zw| zw permanently mark word as bad spelled word |zx| zx re-apply 'foldlevel' and do "zv" |zz| zz redraw, cursor line at center of window |z<Left>| z<Left> same as "zh" @@ -1262,6 +1262,7 @@ tag command action ~ |:debug| :deb[ug] run a command in debugging mode |:debuggreedy| :debugg[reedy] read debug mode commands from normal input |:def| :def define a Vim9 user function +|:defcompile| :defc[ompile] compile Vim9 user functions in current script |:delcommand| :delc[ommand] delete user-defined command |:delfunction| :delf[unction] delete a user function |:delmarks| :delm[arks] delete marks diff --git a/runtime/doc/makehtml.awk b/runtime/doc/makehtml.awk index 5e40069391..40154b063b 100644 --- a/runtime/doc/makehtml.awk +++ b/runtime/doc/makehtml.awk @@ -58,7 +58,7 @@ substr($0,length($0),1) == "~" { print "<B><FONT COLOR=\"PURPLE\">" substr($0,1, # #ad hoc code # -/^"\|\& / {gsub(/\|/,"\\|"); } +/^"\|& / {gsub(/\|/,"\\|"); } / = b / {gsub(/ b /," \\b "); } # # one letter tag diff --git a/runtime/doc/os_haiku.txt b/runtime/doc/os_haiku.txt index 6eff91c275..5c520b0683 100644 --- a/runtime/doc/os_haiku.txt +++ b/runtime/doc/os_haiku.txt @@ -1,4 +1,4 @@ -*os_haiku.txt* For Vim version 8.2. Last change: 2020 Apr 30 +*os_haiku.txt* For Vim version 8.2. Last change: 2020 May 13 VIM REFERENCE MANUAL by Bram Moolenaar @@ -84,9 +84,6 @@ Stuff that does not work yet: in when the window is activated or deactivated (so it works best with focus- follows-mouse turned on). - The cursor does not flash. -- Built-in terminal is not available in GUI, and does not work reliably on - console version as well; e.g. it is not possible to exit using the 'exit' - command. If you need to use it, enable at your own risk. 4. The $VIM directory *haiku-vimdir* diff --git a/runtime/doc/popup.txt b/runtime/doc/popup.txt index fdf28a5e7a..ff99fce9ab 100644 --- a/runtime/doc/popup.txt +++ b/runtime/doc/popup.txt @@ -1,4 +1,4 @@ -*popup.txt* For Vim version 8.2. Last change: 2020 May 12 +*popup.txt* For Vim version 8.2. Last change: 2020 May 18 VIM REFERENCE MANUAL by Bram Moolenaar diff --git a/runtime/doc/repeat.txt b/runtime/doc/repeat.txt index 365f6da1e9..29cdd73bb3 100644 --- a/runtime/doc/repeat.txt +++ b/runtime/doc/repeat.txt @@ -1,4 +1,4 @@ -*repeat.txt* For Vim version 8.2. Last change: 2020 Apr 26 +*repeat.txt* For Vim version 8.2. Last change: 2020 May 14 VIM REFERENCE MANUAL by Bram Moolenaar @@ -126,6 +126,11 @@ q{0-9a-zA-Z"} Record typed characters into register {0-9a-zA-Z"} recorded macro and the yank will overwrite the recorded macro. + Note: The recording happens while you type, replaying + the register happens as if the keys come from a + mapping. This matters, for example, for undo, which + only syncs when commands were typed. + q Stops recording. (Implementation note: The 'q' that stops recording is not stored in the register, unless it was the result of a mapping) @@ -137,7 +142,7 @@ q Stops recording. (Implementation note: The 'q' that used. The register is executed like a mapping, that means that the difference between 'wildchar' and 'wildcharm' - applies. + applies, and undo might not be synced in the same way. For "@=" you are prompted to enter an expression. The result of the expression is then executed. See also |@:|. diff --git a/runtime/doc/tags b/runtime/doc/tags index 18e88f5708..601b95fa59 100644 --- a/runtime/doc/tags +++ b/runtime/doc/tags @@ -2317,6 +2317,8 @@ $VIM_POSIX vi_diff.txt /*$VIM_POSIX* :debugg repeat.txt /*:debugg* :debuggreedy repeat.txt /*:debuggreedy* :def vim9.txt /*:def* +:defc vim9.txt /*:defc* +:defcompile vim9.txt /*:defcompile* :del change.txt /*:del* :delc map.txt /*:delc* :delcommand map.txt /*:delcommand* @@ -4253,6 +4255,7 @@ E457 print.txt /*E457* E458 message.txt /*E458* E459 message.txt /*E459* E46 message.txt /*E46* +E460 eval.txt /*E460* E461 eval.txt /*E461* E462 editing.txt /*E462* E463 netbeans.txt /*E463* @@ -4678,6 +4681,7 @@ E855 autocmd.txt /*E855* E858 eval.txt /*E858* E859 eval.txt /*E859* E86 windows.txt /*E86* +E861 popup.txt /*E861* E862 eval.txt /*E862* E863 popup.txt /*E863* E864 pattern.txt /*E864* @@ -7700,6 +7704,7 @@ mapmode-v map.txt /*mapmode-v* mapmode-x map.txt /*mapmode-x* mapping map.txt /*mapping* mapping-functions usr_41.txt /*mapping-functions* +mapset() eval.txt /*mapset()* mark motion.txt /*mark* mark-functions usr_41.txt /*mark-functions* mark-motions motion.txt /*mark-motions* @@ -8383,6 +8388,7 @@ popup_findpreview() popup.txt /*popup_findpreview()* popup_getoptions() popup.txt /*popup_getoptions()* popup_getpos() popup.txt /*popup_getpos()* popup_hide() popup.txt /*popup_hide()* +popup_list() popup.txt /*popup_list()* popup_locate() popup.txt /*popup_locate()* popup_menu() popup.txt /*popup_menu()* popup_menu-shortcut-example popup.txt /*popup_menu-shortcut-example* @@ -9460,6 +9466,7 @@ termdebug-prompt terminal.txt /*termdebug-prompt* termdebug-starting terminal.txt /*termdebug-starting* termdebug-stepping terminal.txt /*termdebug-stepping* termdebug-variables terminal.txt /*termdebug-variables* +termdebug_map_K terminal.txt /*termdebug_map_K* termdebug_popup terminal.txt /*termdebug_popup* termdebug_shortcuts terminal.txt /*termdebug_shortcuts* termdebug_use_prompt terminal.txt /*termdebug_use_prompt* diff --git a/runtime/doc/terminal.txt b/runtime/doc/terminal.txt index ddc0906a15..1a3cabbad9 100644 --- a/runtime/doc/terminal.txt +++ b/runtime/doc/terminal.txt @@ -1,4 +1,4 @@ -*terminal.txt* For Vim version 8.2. Last change: 2020 Apr 23 +*terminal.txt* For Vim version 8.2. Last change: 2020 May 24 VIM REFERENCE MANUAL by Bram Moolenaar @@ -161,6 +161,7 @@ terminal windows may be configured using the variable hexadecimal color codes, similar to those accepted by |highlight-guifg|. When not using GUI colors, the terminal window always uses the 16 ANSI colors of the underlying terminal. +When using `term_start()` the colors can be set with the "ansi_colors" option. The |term_setansicolors()| function can be used to change the colors, and |term_getansicolors()| to get the currently used colors. @@ -1305,7 +1306,7 @@ breakpoint, or use the "Clear breakpoint" right-click menu entry. Inspecting variables ~ *termdebug-variables* *:Evaluate* `:Evaluate` evaluate the expression under the cursor - `K` same + `K` same (see |termdebug_map_K| to disable) `:Evaluate` {expr} evaluate {expr} `:'<,'>Evaluate` evaluate the Visually selected text @@ -1336,6 +1337,10 @@ in a buffer with 'buftype' set to "prompt". This works slightly differently: *termdebug_use_prompt* Prompt mode can be used even when the |+terminal| feature is present with: > let g:termdebug_use_prompt = 1 +< + *termdebug_map_K* +The K key is normally mapped to :Evaluate. If you do not want this use: > + let g:termdebug_map_K = 0 Communication ~ diff --git a/runtime/doc/todo.txt b/runtime/doc/todo.txt index acc55fe337..abdd346adf 100644 --- a/runtime/doc/todo.txt +++ b/runtime/doc/todo.txt @@ -1,4 +1,4 @@ -*todo.txt* For Vim version 8.2. Last change: 2020 May 11 +*todo.txt* For Vim version 8.2. Last change: 2020 May 26 VIM REFERENCE MANUAL by Bram Moolenaar @@ -38,27 +38,19 @@ browser use: https://github.com/vim/vim/issues/1234 *known-bugs* -------------------- Known bugs and current work ----------------------- -Patch to test TERM signal. (Dominique, #6055) - -Include src/po/vim.pot +Include src/po/vim.pot ? Vim9 script: -Make closures work: - - call closure from not compiled context - - Create closure in a loop. Need to make a list of them. -Forward declarations: - - Cleanup when sourcing a script again: all script-local variables, imports - and functions are deleted. - - make sure only constants in declarations are executed, no function calls. - - Declare a variable at script level without an assignment. - let var: string - Error without a type or assignment - let var # error! Making everything work: +- possible memory leak in test_vim9_func through compile_nested_function. +- memory leaks in test_vim9_expr +- memory leaks in test_vim9_script - Test that a script-local function in Vim9 script cannot be deleted. +- Make "true" and "false" work in vim9script - Test that a function defined inside a :def function is local to that function, g: functions can be defined and script-local functions cannot be defined. +- make 0 == 'string' fail on the script level, like inside :def. - Check that when using a user function name without prefix, it does not find a global function. Prefixing g: is required. - Compile: let [var, var] = expr @@ -75,16 +67,21 @@ Making everything work: - Expand `=expr` in :next, :argedit, :argadd, :argdelete, :drop - Expand `=expr` in :vimgrep, :vimgrepadd, :lvimgrep, :lvimgrepadd - Expand `=expr` in :mkspell +- When evaluating constants for script variables, some functions could work: + has('asdf'), len('string') - Support type for ":let"/":const" at script level for Vim9 script. (Ben Jackson, #5671) Can we share the code from ex_let_const() between direct execution and compiling? - Disallow unlet for local/script/imported vars - Make "++nr" work. +- Make closures work: + - Create closure in a loop. Need to make a list of them. - expandcmd() with `=expr` in filename uses legacy expression. - eval_expr() in ex_cexpr() - eval_expr() call in dbg_parsearg() and debuggy_find() -- Make "true" and "false" work in vim9script +- has() is compiled as a constant, but some checks are dynamic. + Check for dynamic values, such as "gui_running". New syntax and functionality: Improve error checking: - "echo Func()" is an error if Func() does not return anything. @@ -113,6 +110,7 @@ Also: - implement class - implement interface - predefined class: Promise<T> +- implement enum - Make accessing varargs faster: arg[expr] EVAL expr LOADVARARG (varags idx) @@ -125,10 +123,12 @@ Further improvements: body enddef - compile get_lambda_tv() in popup_add_timeout() +- inline call to map() and filter() - compile "skip" argument of searchpair() - compile "expr" and "call" expression of a channel in channel_exe_cmd()? Popup windows: +- Can put focus in another window using API and "drop". (#6077) - With some sequence get get hidden finished terminal buffer. (#5768) Cannot close popup terminal (#5744) Buffer can't be wiped, gets status "aF". (#5764) @@ -201,8 +201,12 @@ Terminal emulator window: background process, the window remains open, because the channel still exists (and output still shows). Perhaps close the window when an explicit ++close was used? (#5931) +- Using "CTRL-W :confirm quite" and selecting "yes" should work like ":quit!". + (Harm te Hennepe, #6129) - When the job in the terminal doesn't use mouse events, let the scroll wheel scroll the scrollback, like a terminal does at the shell prompt. #2490 + A bit like using CTRL-W N first. + Jump back like with "a" when any key is typed. And use modeless selection. #2962 - Use CTRL-W CTRL-K to enter a digraph? #5371 - When Vim runs in the terminal and changes the title, the statusline needs to @@ -232,8 +236,10 @@ Terminal emulator window: conversions. Error numbers available: -E453, E454, E460, E489, E491, E610, E611, E653, -E856, E857, E861, E900 +E453, E454, E489, E610, E611, E653, E856, E857, E861, E900 + +Patch to fix that typval related code is spread out. (Yegappan Lakshmanan, +#6093) Buffer autocommands are a bit inconsistent. Add a separate set of autocommands for the buffer lifecycle: @@ -254,6 +260,10 @@ Patch to explain use of "%" in :!. (David Briscoe, #5591) Patch to improve Windows terminal support. (Nobuhiro Takasaki, #5546) Ready to include. +Patch to improve use of Lua path. (Prabir Shrestha, #6098) + +Patch to make exepath() work better on MS-Windows. (#6115) + Patch to add "-d" to xxd. (#5616) Patch for the Haiku port: #5961 @@ -271,12 +281,17 @@ Patch to support different color for undercurl in cterm. Patch to support cindent option to handle pragmas differently. (Max Rumpf, #5468) +Patch to add ":syn foldlevel" to use fold level further down the line. +(Brad King, 2016 Oct 19, update 2017 Jan 30, now in #6087) + File marks merging has duplicates since 7.4.1925. (Ingo Karkat, #5733) -Running test_gui and test_gui_init with Motif sometimes kills the window -manager. Problem with Motif? Now test_gui crashes in submenu_change(). +"make test_gui" crashed in submenu_change(). Fix and remove workaround in +add_pixmap_args(). Athena is OK. Motif: Build on Ubuntu can't enter any text in dialog text fields. +Running test_gui and test_gui_init with Motif sometimes kills the window +manager. Problem with Motif? :map output does not clear the reset of the command line. (#5623, also see #5962) @@ -287,6 +302,9 @@ Flag in 'formatoptions' is not used in the tests. Patch to add 'vtp' option. (#5344) Needs better docs. Is there a better name? +Patch to add argument to trim() to only trim start or end of a string. +(Yegappan, #6126) + undo result wrong: Masato Nishihata, #4798 Patch for Template string: #4491. New pull: #4634 @@ -300,6 +318,14 @@ Patch to delete BeOS code. (#5817) Anyone who wants to keep it? With bash ":make" does not set v:shell_error. Possible solution: set 'shellpipe' to "2>&1| tee %s; exit ${PIPESTATUS[0]}" #5994 +Using mode() when "/pat" is used in Visual mode returns "v" instead of "c", +which is not useful. Return "c/v" instead. And "c/o" when using "d/pat". +#6127 + +When 'fileignorecase' is set ":e testfile.c" works to edit TestFile.c, but +":find testfile.c" does not ignore case. +Might be related to #6088. + When changing the crypt key the buffer should be considered modified. Like when changing 'fileformat'. Save the old key in save_file_ff(). (Ninu-Ciprian Marginean) @@ -319,6 +345,8 @@ Patch to add function to return the text used in the quickfix window. Patch to add readdirex() (Ken Takata, #5619) +Wrong error when using local arglist. (Harm te Hennepe, #6133) + Request to support <Cmd> in mappings, similar to how Neovim does this. (Daniel Hahler, #4784) @@ -389,6 +417,9 @@ support combining characters. (Charles Campbell) Also #4687 Add "t" action to settagstack(): truncate and add new entries. (#5405) +When 'relativenumber' is set the line just below a diff change doesn't get +updated. (#6138) + Result of synID() sometimes wrong in help files. (#5252) Status line is nut updated when splitting windows. (Marcin Szamotulski, #5496) @@ -1329,6 +1360,8 @@ sort() is not stable when using numeric/float sort (Nikolay Pavlov, 2016 Sep - Add ch_readlines(): for a channel in NL mode, reads as many lines as are available. Should be more efficient than looping over ch_read() with ch_status() to check for more. +- If buffer contents is changed in a callback, set w_redr_status so that it + gets redrawn in redraw_after_callback(). #6120 - Add a separate timeout for opening a socket. Currently it's fixed at 50 msec, which is too small for a remote connection. (tverniquet, #2130) - Problem with stderr on Windows? (Vincent Rischmann, 2016 Aug 31, #1026) @@ -1452,9 +1485,6 @@ Also with latest version. Cannot delete a file with square brackets with delete(). (#696) -Patch to add ":syn foldlevel" to use fold level further down the line. -(Brad King, 2016 Oct 19, update 2017 Jan 30) - Completion for input() does not expand environment variables. (chdiza, 2016 Jul 25, #948) diff --git a/runtime/doc/vim9.txt b/runtime/doc/vim9.txt index 3eec280364..9a74b3ae7b 100644 --- a/runtime/doc/vim9.txt +++ b/runtime/doc/vim9.txt @@ -1,4 +1,4 @@ -*vim9.txt* For Vim version 8.2. Last change: 2020 May 09 +*vim9.txt* For Vim version 8.2. Last change: 2020 May 25 VIM REFERENCE MANUAL by Bram Moolenaar @@ -41,9 +41,10 @@ A secondary goal is to avoid Vim-specific constructs and get closer to commonly used programming languages, such as JavaScript, TypeScript and Java. The performance improvements can only be achieved by not being 100% backwards -compatible. For example, in a function the arguments are not available in the -"a:" dictionary, because creating that dictionary adds quite a lot of -overhead. Other differences are more subtle, such as how errors are handled. +compatible. For example, making function arguments available in the +"a:" dictionary adds quite a lot of overhead. In a Vim9 function this +dictionary is not available. Other differences are more subtle, such as how +errors are handled. The Vim9 script syntax and semantics are used in: - a function defined with the `:def` command @@ -79,12 +80,16 @@ Vim9 functions ~ A function defined with `:def` is compiled. Execution is many times faster, often 10x to 100x times. -Many errors are already found when compiling, before the function is called. +Many errors are already found when compiling, before the function is executed. The syntax is strict, to enforce code that is easy to read and understand. -`:def` has no extra arguments like `:function` does: "range", "abort", "dict" -or "closure". A `:def` function always aborts on an error, does not get a -range passed and cannot be a "dict" function. +Compilation is done when the function is first called, or when the +`:defcompile` command is encountered in the script where the function was +defined. + +`:def` has no options like `:function` does: "range", "abort", "dict" or +"closure". A `:def` function always aborts on an error, does not get a range +passed and cannot be a "dict" function. The argument types and return type need to be specified. The "any" type can be used, type checking will then be done at runtime, like with legacy @@ -118,8 +123,8 @@ search for the function in this order: - Local to the current scope and outer scopes up to the function scope. - Local to the current script file. - Imported functions, see `:import`. -In all cases the function must be defined before used. To make a call cycle a -global function needs to be used. (TODO: can we fix this?) +In all cases the function must be defined before used. That is when it is +first called or when `:defcompile` causes the call to be compiled. The result is that functions and variables without a namespace can always be found in the script, either defined there or imported. Global functions and @@ -127,57 +132,7 @@ variables could be defined anywhere (good luck finding where!). Global functions can be still be defined and deleted at nearly any time. In Vim9 script script-local functions are defined once when the script is sourced -and cannot be deleted. - - -Four phases when loading a Vim9 script ~ - -In legacy script the functions are created when encountered, but parsed only -when used. This allows for defining functions in any order and having them -call each other, so long as the function is defined when it is called: > - func One() - call Two() - endfunc - func Two() - if cond - call One() " recursive call - endif - endfunc - call One() - -In Vim9 script the functions are compiled. When using the same functions as -the above example it is not possible to compile function One without knowing -that function Two exists. Or this would require a runtime check, which is slow -and does not allow for compile time type checking. - -When sourcing a Vim9 script this happens in four phases: -1. Cleanup: If the script was sourced before all script-local variables, - imports and functions are deleted. -2. Discovery: The script is read and declarations of functions, imports and - variables are recognized and the type is parsed. Variable initializers - that are a constant are evaluated, this can also give the type of the - variable. -3. Compilation: Functions are compiled. The script-local functions, imports - and variables from the discovery phase are found and types are checked. -4. Execution: the commands in the script are executed, top to bottom. - Functions are skipped over, they do do not need to be processed again. - Variable initializers are evaluated when encountered. Note that if a - function called earlier has set the value this will be over-written. It is - best to declare variables before where they are used to avoid confusion. - -The result is that items defined at the script level can be used anywhere in -the script. This allows for putting the main function at the top: > - def Main() - SubOne() - SubTwo() - enddef - def SubOne() - ... - def SubTwo() - ... - -Note that script-local variables should either have a type defined or have a -constant initializer. Otherwise an error is given for the type being unknown. +and cannot be deleted or replaced. Variable declarations with :let and :const ~ @@ -212,8 +167,8 @@ The declaration must be done earlier: > endif echo inner -To intentionally use a variable that won't be available later, a block can be -used: > +To intentionally avoid a variable being available later, a block can be used: +> { let temp = 'temp' ... @@ -437,7 +392,9 @@ THIS IS STILL UNDER DEVELOPMENT - ANYTHING CAN BREAK - ANYTHING CAN CHANGE `:def`, but it is not possible to nest `:def` inside `:function`, for backwards compatibility. - [!] is used as with `:function`. + [!] is used as with `:function`. Note that in Vim9 + script script-local functions cannot be deleted or + redefined. *:enddef* :enddef End of a function defined with `:def`. @@ -448,6 +405,10 @@ variables can be accessed without the "s:" prefix. They must be defined before the function. If the script the function is defined in is legacy script, then script-local variables must be accessed with the "s:" prefix. + *:defc* *:defcompile* +:defc[ompile] Compile functions defined in the current script that + were not compiled yet. + This will report errors found during the compilation. *:disa* *:disassemble* :disa[ssemble] {func} Show the instructions generated for {func}. diff --git a/runtime/ftplugin/vim.vim b/runtime/ftplugin/vim.vim index 751a033045..150f54a54e 100644 --- a/runtime/ftplugin/vim.vim +++ b/runtime/ftplugin/vim.vim @@ -1,7 +1,7 @@ " Vim filetype plugin " Language: Vim " Maintainer: Bram Moolenaar <Bram@vim.org> -" Last Change: 2018 Aug 07 +" Last Change: 2020 May 17 " Only do this when not done yet for this buffer if exists("b:did_ftplugin") @@ -12,7 +12,7 @@ endif let b:did_ftplugin = 1 let s:cpo_save = &cpo -set cpo-=C +set cpo&vim if !exists('*VimFtpluginUndo') func VimFtpluginUndo() @@ -63,14 +63,14 @@ if !exists("no_plugin_maps") && !exists("no_vim_maps") let b:did_add_maps = 1 " Move around functions. - nnoremap <silent><buffer> [[ m':call search('^\s*fu\%[nction]\>', "bW")<CR> - vnoremap <silent><buffer> [[ m':<C-U>exe "normal! gv"<Bar>call search('^\s*fu\%[nction]\>', "bW")<CR> - nnoremap <silent><buffer> ]] m':call search('^\s*fu\%[nction]\>', "W")<CR> - vnoremap <silent><buffer> ]] m':<C-U>exe "normal! gv"<Bar>call search('^\s*fu\%[nction]\>', "W")<CR> - nnoremap <silent><buffer> [] m':call search('^\s*endf\%[unction]\>', "bW")<CR> - vnoremap <silent><buffer> [] m':<C-U>exe "normal! gv"<Bar>call search('^\s*endf\%[unction]\>', "bW")<CR> - nnoremap <silent><buffer> ][ m':call search('^\s*endf\%[unction]\>', "W")<CR> - vnoremap <silent><buffer> ][ m':<C-U>exe "normal! gv"<Bar>call search('^\s*endf\%[unction]\>', "W")<CR> + nnoremap <silent><buffer> [[ m':call search('^\s*\(fu\%[nction]\\|def\)\>', "bW")<CR> + vnoremap <silent><buffer> [[ m':<C-U>exe "normal! gv"<Bar>call search('^\s*\(fu\%[nction]\\|def\)\>', "bW")<CR> + nnoremap <silent><buffer> ]] m':call search('^\s*\(fu\%[nction]\\|def\)\>', "W")<CR> + vnoremap <silent><buffer> ]] m':<C-U>exe "normal! gv"<Bar>call search('^\s*\(fu\%[nction]\\|def\)\>', "W")<CR> + nnoremap <silent><buffer> [] m':call search('^\s*end\(f\%[unction]\\|def\)\>', "bW")<CR> + vnoremap <silent><buffer> [] m':<C-U>exe "normal! gv"<Bar>call search('^\s*end\(f\%[unction]\\|def\)\>', "bW")<CR> + nnoremap <silent><buffer> ][ m':call search('^\s*end\(f\%[unction]\\|def\)\>', "W")<CR> + vnoremap <silent><buffer> ][ m':<C-U>exe "normal! gv"<Bar>call search('^\s*end\(f\%[unction]\\|def\)\>', "W")<CR> " Move around comments nnoremap <silent><buffer> ]" :call search('^\(\s*".*\n\)\@<!\(\s*"\)', "W")<CR> diff --git a/runtime/indent/sshconfig.vim b/runtime/indent/sshconfig.vim new file mode 100644 index 0000000000..b456a9e3aa --- /dev/null +++ b/runtime/indent/sshconfig.vim @@ -0,0 +1,34 @@ +" Vim indent file +" Language: ssh config file +" Maintainer: JasonKim <git@jasonk.me> +" Last Change: 2020 May 16 + +if exists("b:did_indent") + finish +endif +let b:did_indent = 1 + +setlocal autoindent +setlocal indentexpr=GetSshconfigIndent(v:lnum) +setlocal indentkeys=o,O,*<Return>,0=~host\ ,0=~match\ ,0#,!^F + +let b:undo_indent = "setlocal autoindent< indentexpr< indentkeys<" + +if exists("*GetSshconfigIndent") + finish +endif + +function GetSshconfigIndent(lnum) + let sw = shiftwidth() + let prev_lnum = prevnonblank(a:lnum - 1) + let curr_lnum = a:lnum + let prev_line = getline(prev_lnum) + let curr_line = getline(curr_lnum) + if curr_line =~? '^\s*\(host\|match\)\s' + return 0 + elseif prev_line =~? '^\s*\(host\|match\)\s' + return sw + else + return indent(prev_lnum) + endif +endfunction diff --git a/runtime/indent/testdir/sshconfig.in b/runtime/indent/testdir/sshconfig.in new file mode 100644 index 0000000000..87b998e465 --- /dev/null +++ b/runtime/indent/testdir/sshconfig.in @@ -0,0 +1,53 @@ +# vim: set filetype=sshconfig shiftwidth=4 expandtab : + +# START_INDENT +Host myhost +User myuser +PasswordAuthentication no +# END_INDENT + +# START_INDENT +Host aaa +User bbb +Host ccc +Host ddd +# END_INDENT + +# START_INDENT +host aaa +HOST bbb +hoSt ccc +match ddd +MATCH eee +MatCH fff +# END_INDENT + +# START_INDENT +Host aaa +User host +PasswordAuthentication no +Host * +User user +PasswordAuthentication no +Host match +User bbb +# END_INDENT + +# START_INDENT +Host tab +User myuser +# END_INDENT + +# START_INDENT +Host mix +User myuser +# END_INDENT + +# START_INDENT +Host aaa +User bbb +Match ccc +User ddd +HostKeyAlgorithms ssh-ed25519 +Match eee +# END_INDENT diff --git a/runtime/indent/testdir/sshconfig.ok b/runtime/indent/testdir/sshconfig.ok new file mode 100644 index 0000000000..b24b7cf4e1 --- /dev/null +++ b/runtime/indent/testdir/sshconfig.ok @@ -0,0 +1,53 @@ +# vim: set filetype=sshconfig shiftwidth=4 expandtab : + +# START_INDENT +Host myhost + User myuser + PasswordAuthentication no +# END_INDENT + +# START_INDENT +Host aaa + User bbb +Host ccc +Host ddd +# END_INDENT + +# START_INDENT +host aaa +HOST bbb +hoSt ccc +match ddd +MATCH eee +MatCH fff +# END_INDENT + +# START_INDENT +Host aaa + User host + PasswordAuthentication no +Host * + User user + PasswordAuthentication no +Host match + User bbb +# END_INDENT + +# START_INDENT +Host tab + User myuser +# END_INDENT + +# START_INDENT +Host mix + User myuser +# END_INDENT + +# START_INDENT +Host aaa + User bbb +Match ccc + User ddd + HostKeyAlgorithms ssh-ed25519 +Match eee +# END_INDENT diff --git a/runtime/indent/tex.vim b/runtime/indent/tex.vim index a748cfbb40..8a44ade1ac 100644 --- a/runtime/indent/tex.vim +++ b/runtime/indent/tex.vim @@ -64,14 +64,17 @@ " style) is supported. Thanks Miles Wheeler for reporting. " 2018/02/07 by Yichao Zhou <broken.zhou AT gmail.com> " (*) Make indentation more smart in the normal mode +" 2020/04/26 by Yichao Zhou <broken.zhou AT gmail.com> +" (*) Fix a bug related to \[ & \]. Thanks Manuel Boni for +" reporting. " " }}} " Document: {{{ " -" To set the following options (ok, currently it's just one), add a line like -" let g:tex_indent_items = 1 -" to your ~/.vimrc. +" For proper latex experience, please put +" let g:tex_flavor = "latex" +" into your vimrc. " " * g:tex_indent_brace " @@ -184,13 +187,18 @@ function! GetTeXIndent() " {{{ let line = substitute(getline(lnum), '\s*%.*', '','g') " last line let cline = substitute(getline(v:lnum), '\s*%.*', '', 'g') " current line + let ccol = 1 + while cline[ccol] =~ '\s' + let ccol += 1 + endwhile + " We are in verbatim, so do what our user what. - if synIDattr(synID(v:lnum, indent(v:lnum), 1), "name") == "texZone" + if synIDattr(synID(v:lnum, ccol, 1), "name") == "texZone" if empty(cline) return indent(lnum) else return indent(v:lnum) - end + endif endif if lnum == 0 @@ -253,13 +261,13 @@ function! GetTeXIndent() " {{{ let stay = 0 endif - if cline =~ '^\s*\\\?[\]}]' && s:CheckPairedIsLastCharacter(v:lnum, indent(v:lnum)) + if cline =~ '^\s*\\\?[\]}]' && s:CheckPairedIsLastCharacter(v:lnum, ccol) let ind -= shiftwidth() let stay = 0 endif if line !~ '^\s*\\\?[\]}]' - for i in range(indent(lnum)+1, strlen(line)-1) + for i in range(1, strlen(line)-1) let char = line[i] if char == ']' || char == '}' if s:CheckPairedIsLastCharacter(lnum, i) diff --git a/runtime/macros/less.vim b/runtime/macros/less.vim index 53857c6c08..5ba685cbc3 100644 --- a/runtime/macros/less.vim +++ b/runtime/macros/less.vim @@ -1,6 +1,6 @@ " Vim script to work like "less" " Maintainer: Bram Moolenaar <Bram@vim.org> -" Last Change: 2017 Mar 31 +" Last Change: 2020 May 18 " Avoid loading this file twice, allow the user to define his own script. if exists("loaded_less") @@ -66,8 +66,8 @@ endif " When reading from stdin don't consider the file modified. au VimEnter * set nomod -" Can't modify the text -set noma +" Can't modify the text or write the file. +set nomodifiable readonly " Give help noremap h :call <SID>Help()<CR> diff --git a/runtime/pack/dist/opt/termdebug/plugin/termdebug.vim b/runtime/pack/dist/opt/termdebug/plugin/termdebug.vim index 3ba1f7e1d4..479b35c3f7 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: 2020 Feb 19 +" Last Change: 2020 May 22 " " WORK IN PROGRESS - Only the basics work " Note: On MS-Windows you need a recent version of gdb. The one included with @@ -657,8 +657,10 @@ func s:InstallCommands() command Source call s:GotoSourcewinOrCreateIt() command Winbar call s:InstallWinbar() - " TODO: can the K mapping be restored? - nnoremap K :Evaluate<CR> + if !exists('g:termdebug_map_K') || g:termdebug_map_K + let s:k_map_saved = maparg('K', 'n', 0, 1) + nnoremap K :Evaluate<CR> + endif if has('menu') && &mouse != '' call s:InstallWinbar() @@ -708,7 +710,10 @@ func s:DeleteCommands() delcommand Source delcommand Winbar - nunmap K + if exists('s:k_map_saved') + call mapset('n', 0, s:k_map_saved) + unlet s:k_map_saved + endif if has('menu') " Remove the WinBar entries from all windows where it was added. diff --git a/runtime/syntax/groovy.vim b/runtime/syntax/groovy.vim index 2245b79d04..9bc1bd6d8d 100644 --- a/runtime/syntax/groovy.vim +++ b/runtime/syntax/groovy.vim @@ -1,10 +1,10 @@ " Vim syntax file " Language: Groovy -" Original Author: Alessio Pace <billy.corgan@tiscali.it> -" Maintainer: Tobias Rapp <yahuxo@gmx.de> -" Version: 0.1.16 +" Original Author: Alessio Pace <billy.corgan AT tiscali.it> +" Maintainer: Tobias Rapp <yahuxo+vim AT mailbox.org> +" Version: 0.1.17 " URL: http://www.vim.org/scripts/script.php?script_id=945 -" Last Change: 2016 May 23 +" Last Change: 2020 May 26 " THE ORIGINAL AUTHOR'S NOTES: " @@ -253,7 +253,7 @@ if exists("groovy_regex_strings") endif " syn region groovyELExpr start=+${+ end=+}+ keepend contained syn match groovyELExpr /\${.\{-}}/ contained -syn match groovyELExpr /\$[a-zA-Z_][a-zA-Z0-9_.]*/ contained +syn match groovyELExpr /\$[a-zA-Z\u00C0-\u00D6\u00D8-\u00F6\u00F8-\u00FF\u0100-\uFFFE_][a-zA-Z\u00C0-\u00D6\u00D8-\u00F6\u00F8-\u00FF\u0100-\uFFFE0-9_.]*/ contained hi def link groovyELExpr Identifier " TODO: better matching. I am waiting to understand how it really works in groovy diff --git a/runtime/syntax/javascript.vim b/runtime/syntax/javascript.vim index 5c6439f9e0..8a5e10b261 100644 --- a/runtime/syntax/javascript.vim +++ b/runtime/syntax/javascript.vim @@ -7,7 +7,7 @@ " (ss) repaired several quoting and grouping glitches " (ss) fixed regex parsing issue with multiple qualifiers [gi] " (ss) additional factoring of keywords, globals, and members -" Last Change: 2019 Sep 27 +" Last Change: 2020 May 14 " 2013 Jun 12: adjusted javaScriptRegexpString (Kevin Locke) " 2018 Apr 14: adjusted javaScriptRegexpString (LongJohnCoder) @@ -77,10 +77,10 @@ else syn match javaScriptParens "[()]" endif -syn sync fromstart -syn sync maxlines=100 - if main_syntax == "javascript" + syn sync fromstart + syn sync maxlines=100 + syn sync ccomment javaScriptComment endif diff --git a/runtime/syntax/spec.vim b/runtime/syntax/spec.vim index 4df549e677..d7d5877943 100644 --- a/runtime/syntax/spec.vim +++ b/runtime/syntax/spec.vim @@ -3,7 +3,7 @@ " Language: SPEC: Build/install scripts for Linux RPM packages " Maintainer: Igor Gnatenko i.gnatenko.brain@gmail.com " Former Maintainer: Donovan Rebbechi elflord@panix.com (until March 2014) -" Last Change: 2020 Feb 07 +" Last Change: 2020 May 25 " quit when a syntax file was already loaded if exists("b:current_syntax") @@ -128,6 +128,8 @@ syn case match "sh-like comment stile, only valid in script part syn match shComment contained '#.*$' +syn region dnlComment matchgroup=specComment start=+%dnl+ end=+$+ + syn region shQuote1 contained matchgroup=shQuoteDelim start=+'+ skip=+\\'+ end=+'+ contains=specMacroIdentifier syn region shQuote2 contained matchgroup=shQuoteDelim start=+"+ skip=+\\"+ end=+"+ contains=specVariables,specMacroIdentifier @@ -173,6 +175,7 @@ endif "sh colors hi def link shComment Comment +hi def link dnlComment Comment hi def link shIf Statement hi def link shOperator Special hi def link shQuote1 String diff --git a/runtime/syntax/tex.vim b/runtime/syntax/tex.vim index 83f6f82547..22b43aa38b 100644 --- a/runtime/syntax/tex.vim +++ b/runtime/syntax/tex.vim @@ -1,8 +1,8 @@ " Vim syntax file " Language: TeX " Maintainer: Charles E. Campbell <NcampObell@SdrPchip.AorgM-NOSPAM> -" Last Change: Jan 24, 2020 -" Version: 116 +" Last Change: May 19, 2020 +" Version: 117 " URL: http://www.drchip.org/astronaut/vim/index.html#SYNTAX_TEX " " Notes: {{{1 @@ -1057,6 +1057,7 @@ if has("conceal") && &enc == 'utf-8' call s:SuperSub('texSuperscript','\^','R','ᴿ') call s:SuperSub('texSuperscript','\^','T','ᵀ') call s:SuperSub('texSuperscript','\^','U','ᵁ') + call s:SuperSub('texSuperscript','\^','V','ⱽ') call s:SuperSub('texSuperscript','\^','W','ᵂ') call s:SuperSub('texSuperscript','\^',',','︐') call s:SuperSub('texSuperscript','\^',':','︓') diff --git a/runtime/syntax/vim.vim b/runtime/syntax/vim.vim index 22947bff1a..1eef428112 100644 --- a/runtime/syntax/vim.vim +++ b/runtime/syntax/vim.vim @@ -1,8 +1,8 @@ " Vim syntax file " Language: Vim 8.0 script -" Maintainer: Charles E. Campbell <NdrOchipS@PcampbellAfamily.Mbiz> -" Last Change: Apr 15, 2020 -" Version: 8.0-33 +" Maintainer: Charles E. Campbell <NcampObell@SdrPchip.AorgM-NOSPAM> +" Last Change: May 26, 2020 +" Version: 8.0-35 " URL: http://www.drchip.org/astronaut/vim/index.html#SYNTAX_VIM " Automatically generated keyword lists: {{{1 @@ -228,7 +228,7 @@ syn cluster vimOperGroup contains=vimEnvvar,vimFunc,vimFuncVar,vimOper,vimOperPa syn match vimOper "\%#=1\(==\|!=\|>=\|<=\|=\~\|!\~\|>\|<\|=\)[?#]\{0,2}" skipwhite nextgroup=vimString,vimSpecFile syn match vimOper "\(\<is\|\<isnot\)[?#]\{0,2}\>" skipwhite nextgroup=vimString,vimSpecFile syn match vimOper "||\|&&\|[-+.!]" skipwhite nextgroup=vimString,vimSpecFile -syn region vimOperParen matchgroup=vimParenSep start="(" end=")" contains=@vimOperGroup +syn region vimOperParen matchgroup=vimParenSep start="(" end=")" contains=vimoperStar,@vimOperGroup syn region vimOperParen matchgroup=vimSep start="{" end="}" contains=@vimOperGroup nextgroup=vimVar,vimFuncVar if !exists("g:vimsyn_noerror") && !exists("g:vimsyn_noopererror") syn match vimOperError ")" @@ -300,7 +300,7 @@ syn match vimComment excludenl +\s#[^{].*$+lc=1 contains=@vimCommentGroup,vimCom syn match vimComment +\<endif\s\+#[^{].*$+lc=5 contains=@vimCommentGroup,vimCommentString syn match vimComment +\<else\s\+#[^{].*$+lc=4 contains=@vimCommentGroup,vimCommentString " Vim9 comment inside expression -syn match vim9Comment +\s\zs#[^{].*$+ contains=@vimCommentGroup,vimCommentString +syn match vim9Comment +\s\zs#[^{].*$+ms=s+1 contains=@vimCommentGroup,vimCommentString " Environment Variables: {{{2 " ===================== @@ -321,7 +321,7 @@ syn region vimString oneline keepend start=+[^a-zA-Z>!\\@]"+lc=1 skip=+\\\\\|\\" syn region vimString oneline keepend start=+[^a-zA-Z>!\\@]'+lc=1 end=+'+ syn region vimString oneline start=+=!+lc=1 skip=+\\\\\|\\!+ end=+!+ contains=@vimStringGroup syn region vimString oneline start="=+"lc=1 skip="\\\\\|\\+" end="+" contains=@vimStringGroup -syn region vimString oneline start="\s/\s*\A"lc=1 skip="\\\\\|\\+" end="/" contains=@vimStringGroup +"syn region vimString oneline start="\s/\s*\A"lc=1 skip="\\\\\|\\+" end="/" contains=@vimStringGroup syn match vimString contained +"[^"]*\\$+ skipnl nextgroup=vimStringCont syn match vimStringCont contained +\(\\\\\|.\)\{-}[^\\]"+ @@ -932,6 +932,7 @@ if !exists("skip_vim_syntax_inits") hi def link vimNumber Number hi def link vimOperError Error hi def link vimOper Operator + hi def link vimOperStar vimOper hi def link vimOption PreProc hi def link vimParenSep Delimiter hi def link vimPatSepErr vimError From 80a20df86a1ceefa3506cc578ba0ba35da979e38 Mon Sep 17 00:00:00 2001 From: Bram Moolenaar <Bram@vim.org> Date: Tue, 26 May 2020 22:14:27 +0200 Subject: [PATCH 230/230] patch 8.2.0830: Motif: can't map "!" Problem: Motif: can't map "!". (Ben Jackson) Solution: Remove the shift modifier if it's already included in the key. (closes #6147) --- src/gui_x11.c | 5 +++++ src/version.c | 2 ++ 2 files changed, 7 insertions(+) diff --git a/src/gui_x11.c b/src/gui_x11.c index c03b210443..1eec793e5a 100644 --- a/src/gui_x11.c +++ b/src/gui_x11.c @@ -948,6 +948,11 @@ gui_x11_key_hit_cb( { string[0] = key; len = 1; + + // Remove the SHIFT modifier for keys where it's already included, + // e.g., '(', '!' and '*'. + if (!ASCII_ISALPHA(key) && key > 0x20 && key < 0x7f) + modifiers &= ~MOD_MASK_SHIFT; } if (modifiers != 0) diff --git a/src/version.c b/src/version.c index f91ff1a99d..f088e61227 100644 --- a/src/version.c +++ b/src/version.c @@ -746,6 +746,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 830, /**/ 829, /**/