From ad39c094d261109a695aba2c4f19fe336736cc55 Mon Sep 17 00:00:00 2001 From: Bram Moolenaar Date: Wed, 26 Feb 2020 18:23:43 +0100 Subject: [PATCH 01/63] patch 8.2.0321: Vim9: ":execute" does not work yet Problem: Vim9: ":execute" does not work yet. Solution: Add ISN_EXECUTE. (closes #5699) Also make :echo work with more than one argument. --- src/testdir/test_vim9_disassemble.vim | 33 ++++++++++++++++++ src/testdir/test_vim9_script.vim | 29 ++++++++++++++++ src/version.c | 2 ++ src/vim9.h | 3 +- src/vim9compile.c | 48 +++++++++++++++++++++++++-- src/vim9execute.c | 45 +++++++++++++++++++++++++ 6 files changed, 157 insertions(+), 3 deletions(-) diff --git a/src/testdir/test_vim9_disassemble.vim b/src/testdir/test_vim9_disassemble.vim index cf3dd8c450..3758697171 100644 --- a/src/testdir/test_vim9_disassemble.vim +++ b/src/testdir/test_vim9_disassemble.vim @@ -690,4 +690,37 @@ def Test_disassemble_compare() " delete('Xdisassemble') enddef +def s:Execute() + execute 'help vim9.txt' + let cmd = 'help vim9.txt' + execute cmd + let tag = 'vim9.txt' + execute 'help ' .. tag +enddef + +def Test_disassemble_execute() + let res = execute('disass s:Execute') + assert_match('\\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' + \, res) +enddef + " vim: ts=8 sw=2 sts=2 expandtab tw=80 fdm=marker diff --git a/src/testdir/test_vim9_script.vim b/src/testdir/test_vim9_script.vim index 938dc63409..3f0773b173 100644 --- a/src/testdir/test_vim9_script.vim +++ b/src/testdir/test_vim9_script.vim @@ -1,6 +1,7 @@ " Test various aspects of the Vim9 script language. source check.vim +source view_util.vim " Check that "lines" inside ":def" results in an "error" message. func CheckDefFailure(lines, error) @@ -692,5 +693,33 @@ def Test_substitute_cmd() delete('Xvim9lines') enddef +def Test_execute_cmd() + new + setline(1, 'default') + execute 'call setline(1, "execute-string")' + assert_equal('execute-string', getline(1)) + let cmd1 = 'call setline(1,' + let cmd2 = '"execute-var")' + execute cmd1 cmd2 + 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 + assert_equal('execute-var-var', getline(1)) + bwipe! +enddef + +def Test_echo_cmd() + echo 'something' + assert_match('^something$', Screenline(&lines)) + + let str1 = 'some' + let str2 = 'more' + echo str1 str2 + assert_match('^some more$', Screenline(&lines)) +enddef + " vim: ts=8 sw=2 sts=2 expandtab tw=80 fdm=marker diff --git a/src/version.c b/src/version.c index 46540e9eb9..beceb6da80 100644 --- a/src/version.c +++ b/src/version.c @@ -738,6 +738,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 321, /**/ 320, /**/ diff --git a/src/vim9.h b/src/vim9.h index a97796505f..77bf626d6f 100644 --- a/src/vim9.h +++ b/src/vim9.h @@ -13,7 +13,8 @@ typedef enum { ISN_EXEC, // execute Ex command line isn_arg.string - ISN_ECHO, // echo isn_arg.number items on top of 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 // get and set variables ISN_LOAD, // push local variable isn_arg.number diff --git a/src/vim9compile.c b/src/vim9compile.c index d62df6ed48..32d6349e51 100644 --- a/src/vim9compile.c +++ b/src/vim9compile.c @@ -1116,6 +1116,21 @@ generate_ECHO(cctx_T *cctx, int with_white, int count) return OK; } +/* + * Generate an ISN_EXECUTE instruction. + */ + static int +generate_EXECUTE(cctx_T *cctx, int count) +{ + isn_T *isn; + + if ((isn = generate_instr_drop(cctx, ISN_EXECUTE, count)) == NULL) + return FAIL; + isn->isn_arg.number = count; + + return OK; +} + static int generate_EXEC(cctx_T *cctx, char_u *line) { @@ -4671,14 +4686,40 @@ compile_echo(char_u *arg, int with_white, cctx_T *cctx) char_u *p = arg; int count = 0; - // for () + 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 "execute expr" + */ + static char_u * +compile_execute(char_u *arg, 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_EXECUTE(cctx, count); return p; } @@ -5017,12 +5058,14 @@ compile_def_function(ufunc_T *ufunc, int set_return_type) case CMD_echon: line = compile_echo(p, FALSE, &cctx); break; + case CMD_execute: + line = compile_execute(p, &cctx); + break; default: // Not recognized, execute with do_cmdline_cmd(). // TODO: // CMD_echomsg - // CMD_execute // etc. generate_EXEC(&cctx, line); line = (char_u *)""; @@ -5150,6 +5193,7 @@ delete_instr(isn_T *isn) case ISN_DCALL: case ISN_DROP: case ISN_ECHO: + case ISN_EXECUTE: case ISN_ENDTRY: case ISN_FOR: case ISN_FUNCREF: diff --git a/src/vim9execute.c b/src/vim9execute.c index 3bbf94ff67..4f22654754 100644 --- a/src/vim9execute.c +++ b/src/vim9execute.c @@ -533,6 +533,48 @@ call_def_function( } break; + // execute :execute {string} ... + case ISN_EXECUTE: + { + int count = iptr->isn_arg.number; + garray_T ga; + char_u buf[NUMBUFLEN]; + char_u *p; + int len; + int failed = FALSE; + + ga_init2(&ga, 1, 80); + for (idx = 0; idx < count; ++idx) + { + tv = STACK_TV_BOT(idx - count); + if (tv->v_type == VAR_CHANNEL || tv->v_type == VAR_JOB) + { + emsg(_(e_inval_string)); + break; + } + else + p = tv_get_string_buf(tv, buf); + + len = (int)STRLEN(p); + if (ga_grow(&ga, len + 2) == FAIL) + failed = TRUE; + else + { + if (ga.ga_len > 0) + ((char_u *)(ga.ga_data))[ga.ga_len++] = ' '; + STRCPY((char_u *)(ga.ga_data) + ga.ga_len, p); + ga.ga_len += len; + } + clear_tv(tv); + } + ectx.ec_stack.ga_len -= count; + + if (!failed && ga.ga_data != NULL) + do_cmdline_cmd((char_u *)ga.ga_data); + ga_clear(&ga); + } + break; + // load local variable or argument case ISN_LOAD: if (ga_grow(&ectx.ec_stack, 1) == FAIL) @@ -1666,6 +1708,9 @@ ex_disassemble(exarg_T *eap) echo->echo_count); } break; + case ISN_EXECUTE: + smsg("%4d EXECUTE %d", current, iptr->isn_arg.number); + break; case ISN_LOAD: if (iptr->isn_arg.number < 0) smsg("%4d LOAD arg[%lld]", current, From b35efa5ed040162f5c988c71dfc1159045e47585 Mon Sep 17 00:00:00 2001 From: Bram Moolenaar Date: Wed, 26 Feb 2020 20:15:18 +0100 Subject: [PATCH 02/63] patch 8.2.0322: Vim9: error checks not tested Problem: Vim9: error checks not tested. Solution: Add more test cases. Avoid error for function loaded later. --- src/evalvars.c | 4 +++- src/testdir/test_vim9_script.vim | 20 ++++++++++++++------ src/version.c | 2 ++ src/vim9compile.c | 13 ++++++++----- 4 files changed, 27 insertions(+), 12 deletions(-) diff --git a/src/evalvars.c b/src/evalvars.c index 894ee287da..227253e1f9 100644 --- a/src/evalvars.c +++ b/src/evalvars.c @@ -2541,8 +2541,10 @@ find_var_ht(char_u *name, char_u **varname) return &curtab->tp_vars->dv_hashtab; if (*name == 'v') // v: variable return &vimvarht; - if (current_sctx.sc_version != SCRIPT_VERSION_VIM9) + if (get_current_funccal() != NULL + && get_current_funccal()->func->uf_dfunc_idx < 0) { + // a: and l: are only used in functions defined with ":function" if (*name == 'a') // a: function argument return get_funccal_args_ht(); if (*name == 'l') // l: local function variable diff --git a/src/testdir/test_vim9_script.vim b/src/testdir/test_vim9_script.vim index 3f0773b173..53ee5119c8 100644 --- a/src/testdir/test_vim9_script.vim +++ b/src/testdir/test_vim9_script.vim @@ -178,6 +178,15 @@ func Test_call_default_args_from_func() call assert_fails('call MyDefaultArgs("one", "two")', 'E118:') endfunc +func TakesOneArg(arg) + echo a:arg +endfunc + +def Test_call_wrong_arg_count() + call CheckDefFailure(['TakesOneArg()'], 'E119:') + call CheckDefFailure(['TakesOneArg(11, 22)'], 'E118:') +enddef + " Default arg and varargs def MyDefVarargs(one: string, two = 'foo', ...rest: list): string let res = one .. ',' .. two @@ -194,13 +203,12 @@ def Test_call_def_varargs() assert_equal('one,two,three', MyDefVarargs('one', 'two', 'three')) enddef +def Test_call_func_defined_later() + call assert_equal('one', DefinedLater('one')) + call assert_fails('call NotDefined("one")', 'E117:') +enddef -"def Test_call_func_defined_later() -" call assert_equal('one', DefineLater('one')) -" call assert_fails('call NotDefined("one")', 'E99:') -"enddef - -func DefineLater(arg) +func DefinedLater(arg) return a:arg endfunc diff --git a/src/version.c b/src/version.c index beceb6da80..258cab24f6 100644 --- a/src/version.c +++ b/src/version.c @@ -738,6 +738,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 322, /**/ 321, /**/ diff --git a/src/vim9compile.c b/src/vim9compile.c index 32d6349e51..35f20c4c76 100644 --- a/src/vim9compile.c +++ b/src/vim9compile.c @@ -1545,7 +1545,8 @@ compile_load_scriptvar( cctx_T *cctx, char_u *name, // variable NUL terminated char_u *start, // start of variable - char_u **end) // end of variable + char_u **end, // end of variable + int error) // when TRUE may give error { scriptitem_T *si = SCRIPT_ITEM(current_sctx.sc_sid); int idx = get_script_item_idx(current_sctx.sc_sid, name, FALSE); @@ -1606,7 +1607,8 @@ compile_load_scriptvar( return OK; } - semsg(_("E1050: Item not found: %s"), name); + if (error) + semsg(_("E1050: Item not found: %s"), name); return FAIL; } @@ -1642,7 +1644,7 @@ compile_load(char_u **arg, char_u *end_arg, cctx_T *cctx, int error) } else if (**arg == 's') { - res = compile_load_scriptvar(cctx, name, NULL, NULL); + res = compile_load_scriptvar(cctx, name, NULL, NULL, error); } else { @@ -1698,7 +1700,7 @@ compile_load(char_u **arg, char_u *end_arg, cctx_T *cctx, int error) else if (SCRIPT_ITEM(current_sctx.sc_sid)->sn_version == SCRIPT_VERSION_VIM9) // in Vim9 script "var" can be script-local. - res = compile_load_scriptvar(cctx, name, *arg, &end); + res = compile_load_scriptvar(cctx, name, *arg, &end, error); } } if (gen_load) @@ -3465,7 +3467,8 @@ compile_assignment(char_u *arg, exarg_T *eap, cmdidx_T cmdidx, cctx_T *cctx) generate_LOAD(cctx, ISN_LOADG, 0, name + 2, type); break; case dest_script: - compile_load_scriptvar(cctx, name + (name[1] == ':' ? 2 : 0), NULL, NULL); + compile_load_scriptvar(cctx, + name + (name[1] == ':' ? 2 : 0), NULL, NULL, TRUE); break; case dest_env: // Include $ in the name here From 7eeefd4a395fe3d7c7a2a0879467cf7ed4c29fe6 Mon Sep 17 00:00:00 2001 From: Bram Moolenaar Date: Wed, 26 Feb 2020 21:24:23 +0100 Subject: [PATCH 03/63] patch 8.2.0323: Vim9: calling a function that is defined later is slow Problem: Vim9: calling a function that is defined later is slow. Solution: Once the function is found update the instruction so it can be called directly. --- src/testdir/test_vim9_disassemble.vim | 32 +++++++++++++++++++++++ src/testdir/test_vim9_script.vim | 13 ++++++++++ src/version.c | 2 ++ src/vim9execute.c | 37 ++++++++++++++++++--------- 4 files changed, 72 insertions(+), 12 deletions(-) diff --git a/src/testdir/test_vim9_disassemble.vim b/src/testdir/test_vim9_disassemble.vim index 3758697171..9196184a6f 100644 --- a/src/testdir/test_vim9_disassemble.vim +++ b/src/testdir/test_vim9_disassemble.vim @@ -222,6 +222,38 @@ def Test_disassemble_call() enddef +def FuncWithForwardCall(): string + return DefinedLater("yes") +enddef + +def DefinedLater(arg: string): string + return arg +enddef + +def Test_disassemble_update_instr() + let res = execute('disass FuncWithForwardCall') + assert_match('FuncWithForwardCall.*' + \ .. 'return DefinedLater("yes").*' + \ .. '\d PUSHS "yes".*' + \ .. '\d UCALL DefinedLater(argc 1).*' + \ .. '\d CHECKTYPE string stack\[-1].*' + \ .. '\d RETURN.*' + \, res) + + " Calling the function will change UCALL into the faster DCALL + assert_equal('yes', FuncWithForwardCall()) + + res = execute('disass FuncWithForwardCall') + assert_match('FuncWithForwardCall.*' + \ .. 'return DefinedLater("yes").*' + \ .. '\d PUSHS "yes".*' + \ .. '\d DCALL DefinedLater(argc 1).*' + \ .. '\d CHECKTYPE string stack\[-1].*' + \ .. '\d RETURN.*' + \, res) +enddef + + def FuncWithDefault(arg: string = 'default'): string return arg enddef diff --git a/src/testdir/test_vim9_script.vim b/src/testdir/test_vim9_script.vim index 53ee5119c8..f1b21d45e3 100644 --- a/src/testdir/test_vim9_script.vim +++ b/src/testdir/test_vim9_script.vim @@ -212,6 +212,19 @@ func DefinedLater(arg) return a:arg endfunc +def FuncWithForwardCall() + return DefinedEvenLater("yes") +enddef + +def DefinedEvenLater(arg: string): string + return arg +enddef + +def Test_error_in_nested_function() + " Error in called function requires unwinding the call stack. + assert_fails('call FuncWithForwardCall()', 'E1029') +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') diff --git a/src/version.c b/src/version.c index 258cab24f6..f95526c0a9 100644 --- a/src/version.c +++ b/src/version.c @@ -738,6 +738,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 323, /**/ 322, /**/ diff --git a/src/vim9execute.c b/src/vim9execute.c index 4f22654754..9ecb8657e6 100644 --- a/src/vim9execute.c +++ b/src/vim9execute.c @@ -267,9 +267,10 @@ call_bfunc(int func_idx, int argcount, ectx_T *ectx) /* * Execute a user defined function. + * "iptr" can be used to replace the instruction with a more efficient one. */ static int -call_ufunc(ufunc_T *ufunc, int argcount, ectx_T *ectx) +call_ufunc(ufunc_T *ufunc, int argcount, ectx_T *ectx, isn_T *iptr) { typval_T argvars[MAX_FUNC_ARGS]; funcexe_T funcexe; @@ -277,8 +278,17 @@ call_ufunc(ufunc_T *ufunc, int argcount, ectx_T *ectx) int idx; if (ufunc->uf_dfunc_idx >= 0) - // The function has been compiled, can call it quickly. + { + // The function has been compiled, can call it quickly. For a function + // that was defined later: we can call it directly next time. + if (iptr != NULL) + { + iptr->isn_type = ISN_DCALL; + iptr->isn_arg.dfunc.cdf_idx = ufunc->uf_dfunc_idx; + iptr->isn_arg.dfunc.cdf_argcount = argcount; + } return call_dfunc(ufunc->uf_dfunc_idx, argcount, ectx); + } if (call_prepare(argcount, argvars, ectx) == FAIL) return FAIL; @@ -305,10 +315,11 @@ call_ufunc(ufunc_T *ufunc, int argcount, ectx_T *ectx) /* * Execute a function by "name". * This can be a builtin function or a user function. + * "iptr" can be used to replace the instruction with a more efficient one. * Returns FAIL if not found without an error message. */ static int -call_by_name(char_u *name, int argcount, ectx_T *ectx) +call_by_name(char_u *name, int argcount, ectx_T *ectx, isn_T *iptr) { ufunc_T *ufunc; @@ -325,7 +336,7 @@ call_by_name(char_u *name, int argcount, ectx_T *ectx) ufunc = find_func(name, NULL); if (ufunc != NULL) - return call_ufunc(ufunc, argcount, ectx); + return call_ufunc(ufunc, argcount, ectx, iptr); return FAIL; } @@ -341,12 +352,12 @@ 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); + return call_ufunc(pt->pt_func, argcount, ectx, NULL); name = pt->pt_name; } else name = tv->vval.v_string; - if (call_by_name(name, argcount, ectx) == FAIL) + if (call_by_name(name, argcount, ectx, NULL) == FAIL) { if (called_emsg == called_emsg_before) semsg(_(e_unknownfunc), name); @@ -372,13 +383,14 @@ store_var(char_u *name, typval_T *tv) /* * Execute a function by "name". * This can be a builtin function, user function or a funcref. + * "iptr" can be used to replace the instruction with a more efficient one. */ static int -call_eval_func(char_u *name, int argcount, ectx_T *ectx) +call_eval_func(char_u *name, int argcount, ectx_T *ectx, isn_T *iptr) { int called_emsg_before = called_emsg; - if (call_by_name(name, argcount, ectx) == FAIL + 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 @@ -983,7 +995,7 @@ call_def_function( SOURCING_LNUM = iptr->isn_lnum; if (call_eval_func(cufunc->cuf_name, - cufunc->cuf_argcount, &ectx) == FAIL) + cufunc->cuf_argcount, &ectx, iptr) == FAIL) goto failed; } break; @@ -1558,10 +1570,7 @@ call_def_function( tv = STACK_TV_BOT(-1); if (check_not_string(tv) == FAIL) - { - --ectx.ec_stack.ga_len; goto failed; - } (void)tv_get_number_chk(tv, &error); if (error) goto failed; @@ -1627,6 +1636,10 @@ done: ret = OK; failed: + // When failed need to unwind the call stack. + while (ectx.ec_frame != initial_frame_ptr) + func_return(&ectx); + for (idx = 0; idx < ectx.ec_stack.ga_len; ++idx) clear_tv(STACK_TV(idx)); vim_free(ectx.ec_stack.ga_data); From 12f20038714928bfecdeee31ed1f927324542034 Mon Sep 17 00:00:00 2001 From: Bram Moolenaar Date: Wed, 26 Feb 2020 22:06:00 +0100 Subject: [PATCH 04/63] patch 8.2.0324: text property not updated correctly when inserting/deleting Problem: Text property not updated correctly when inserting/deleting. Solution: Use the right column when deleting. Make zero-width text properties respect start_incl and end_incl. (Axel Forsman, closes #5696, closes #5679) --- src/change.c | 2 +- src/testdir/test_listener.vim | 13 ++++++ src/testdir/test_textprop.vim | 13 ++++-- src/textprop.c | 81 +++++++++++++++++++++-------------- src/version.c | 2 + 5 files changed, 74 insertions(+), 37 deletions(-) diff --git a/src/change.c b/src/change.c index e5ac97bd54..3ee719812f 100644 --- a/src/change.c +++ b/src/change.c @@ -1301,7 +1301,7 @@ del_bytes( #endif // mark the buffer as changed and prepare for displaying - inserted_bytes(lnum, curwin->w_cursor.col, -count); + inserted_bytes(lnum, col, -count); return OK; } diff --git a/src/testdir/test_listener.vim b/src/testdir/test_listener.vim index a263abadd2..9c9ba7fe43 100644 --- a/src/testdir/test_listener.vim +++ b/src/testdir/test_listener.vim @@ -326,3 +326,16 @@ func Test_listener_cleared_newbuf() bwipe! delfunc Listener endfunc + +func Test_col_after_deletion_moved_cur() + func Listener(bufnr, start, end, added, changes) + call assert_equal([#{lnum: 1, end: 2, added: 0, col: 2}], a:changes) + endfunc + new + call setline(1, ['foo']) + let lid = listener_add('Listener') + call feedkeys("lD", 'xt') + call listener_flush() + bwipe! + delfunc Listener +endfunc diff --git a/src/testdir/test_textprop.vim b/src/testdir/test_textprop.vim index 32001b3622..6dbaa5350f 100644 --- a/src/testdir/test_textprop.vim +++ b/src/testdir/test_textprop.vim @@ -6,8 +6,6 @@ CheckFeature textprop source screendump.vim -" test length zero - func Test_proptype_global() call prop_type_add('comment', {'highlight': 'Directory', 'priority': 123, 'start_incl': 1, 'end_incl': 1}) let proptypes = prop_type_list() @@ -233,13 +231,20 @@ func Test_prop_add() " Prop without length or end column is zero length call prop_clear(1) - call prop_add(1, 5, {'type': 'two'}) - let expected = [{'col': 5, 'length': 0, 'type': 'two', 'id': 0, 'start': 1, 'end': 1}] + call prop_type_add('included', {'start_incl': 1, 'end_incl': 1}) + call prop_add(1, 5, #{type: 'included'}) + let expected = [#{col: 5, length: 0, type: 'included', id: 0, start: 1, end: 1}] + call assert_equal(expected, prop_list(1)) + + " Inserting text makes the prop bigger. + exe "normal 5|ixx\" + let expected = [#{col: 5, length: 2, type: 'included', id: 0, start: 1, end: 1}] call assert_equal(expected, prop_list(1)) call assert_fails("call prop_add(1, 5, {'type': 'two', 'bufnr': 234343})", 'E158:') call DeletePropTypes() + call prop_type_delete('included') bwipe! endfunc diff --git a/src/textprop.c b/src/textprop.c index 4ddb42e9d3..3ad84a2424 100644 --- a/src/textprop.c +++ b/src/textprop.c @@ -1232,7 +1232,6 @@ adjust_prop_columns( { int proplen; char_u *props; - textprop_T tmp_prop; proptype_T *pt; int dirty = FALSE; int ri, wi; @@ -1249,62 +1248,80 @@ adjust_prop_columns( wi = 0; // write index for (ri = 0; ri < proplen; ++ri) { - int start_incl; + textprop_T prop; + int start_incl, end_incl; + int can_drop; - mch_memmove(&tmp_prop, props + ri * sizeof(textprop_T), - sizeof(textprop_T)); - pt = text_prop_type_by_id(curbuf, tmp_prop.tp_type); - start_incl = (flags & APC_SUBSTITUTE) || - (pt != NULL && (pt->pt_flags & PT_FLAG_INS_START_INCL)); + mch_memmove(&prop, props + ri * sizeof(textprop_T), sizeof(textprop_T)); + pt = text_prop_type_by_id(curbuf, prop.tp_type); + start_incl = (pt != NULL && (pt->pt_flags & PT_FLAG_INS_START_INCL)) + || (flags & APC_SUBSTITUTE); + end_incl = (pt != NULL && (pt->pt_flags & PT_FLAG_INS_END_INCL)); + // Do not drop zero-width props if they later can increase in size + can_drop = !(start_incl || end_incl); - if (bytes_added > 0 - && (tmp_prop.tp_col >= col + (start_incl ? 2 : 1))) + if (bytes_added > 0) { - tmp_prop.tp_col += bytes_added; - // Save for undo if requested and not done yet. - if ((flags & APC_SAVE_FOR_UNDO) && !dirty) - u_savesub(lnum); - dirty = TRUE; + if (col + 1 <= prop.tp_col + - (start_incl || (prop.tp_len == 0 && end_incl))) + { + // Change is entirely before the text property: Only shift + prop.tp_col += bytes_added; + // Save for undo if requested and not done yet. + if ((flags & APC_SAVE_FOR_UNDO) && !dirty) + u_savesub(lnum); + dirty = TRUE; + } + else if (col + 1 < prop.tp_col + prop.tp_len + end_incl) + { + // Insertion was inside text property + prop.tp_len += bytes_added; + // Save for undo if requested and not done yet. + if ((flags & APC_SAVE_FOR_UNDO) && !dirty) + u_savesub(lnum); + dirty = TRUE; + } } - else if (bytes_added <= 0 && (tmp_prop.tp_col > col + 1)) + else if (prop.tp_col > col + 1) { int len_changed = FALSE; - if (tmp_prop.tp_col + bytes_added < col + 1) + if (prop.tp_col + bytes_added < col + 1) { - tmp_prop.tp_len += (tmp_prop.tp_col - 1 - col) + bytes_added; - tmp_prop.tp_col = col + 1; + prop.tp_len += (prop.tp_col - 1 - col) + bytes_added; + prop.tp_col = col + 1; len_changed = TRUE; } else - tmp_prop.tp_col += bytes_added; + prop.tp_col += bytes_added; // Save for undo if requested and not done yet. if ((flags & APC_SAVE_FOR_UNDO) && !dirty) u_savesub(lnum); dirty = TRUE; - if (len_changed && tmp_prop.tp_len <= 0) - continue; // drop this text property + if (len_changed && prop.tp_len <= 0) + { + prop.tp_len = 0; + if (can_drop) + continue; // drop this text property + } } - else if (tmp_prop.tp_len > 0 - && tmp_prop.tp_col + tmp_prop.tp_len > col - + ((pt != NULL && (pt->pt_flags & PT_FLAG_INS_END_INCL)) - ? 0 : 1)) + else if (prop.tp_len > 0 && prop.tp_col + prop.tp_len > col) { - int after = col - bytes_added - - (tmp_prop.tp_col - 1 + tmp_prop.tp_len); + int after = col - bytes_added - (prop.tp_col - 1 + prop.tp_len); + if (after > 0) - tmp_prop.tp_len += bytes_added + after; + prop.tp_len += bytes_added + after; else - tmp_prop.tp_len += bytes_added; + prop.tp_len += bytes_added; // Save for undo if requested and not done yet. if ((flags & APC_SAVE_FOR_UNDO) && !dirty) u_savesub(lnum); dirty = TRUE; - if (tmp_prop.tp_len <= 0) + if (prop.tp_len <= 0 && can_drop) continue; // drop this text property } - mch_memmove(props + wi * sizeof(textprop_T), &tmp_prop, - sizeof(textprop_T)); + + mch_memmove(props + wi * sizeof(textprop_T), &prop, sizeof(textprop_T)); ++wi; } if (dirty) diff --git a/src/version.c b/src/version.c index f95526c0a9..3f64431245 100644 --- a/src/version.c +++ b/src/version.c @@ -738,6 +738,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 324, /**/ 323, /**/ From 578fe947e3ad0cc7313c798cf76cc43dbf9b4ea6 Mon Sep 17 00:00:00 2001 From: Bram Moolenaar Date: Thu, 27 Feb 2020 21:32:51 +0100 Subject: [PATCH 05/63] patch 8.2.0325: ex_getln.c code not covered by tests Problem: Ex_getln.c code not covered by tests. Solution: Add a few more tests. (Yegappan Lakshmanan, closes #5702) --- src/testdir/test_cmdline.vim | 128 +++++++++++++++++++++++++++++++++ src/testdir/test_ex_mode.vim | 8 ++- src/testdir/test_functions.vim | 13 ++++ src/testdir/test_history.vim | 29 +++++++- src/testdir/test_options.vim | 23 ++++++ src/version.c | 2 + 6 files changed, 200 insertions(+), 3 deletions(-) diff --git a/src/testdir/test_cmdline.vim b/src/testdir/test_cmdline.vim index fa3446ad1a..f61d4aeab5 100644 --- a/src/testdir/test_cmdline.vim +++ b/src/testdir/test_cmdline.vim @@ -14,6 +14,11 @@ func Test_complete_list() " We can't see the output, but at least we check the code runs properly. call feedkeys(":e test\\r", "tx") call assert_equal('test', expand('%:t')) + + " If a command doesn't support completion, then CTRL-D should be literally + " used. + call feedkeys(":chistory \\\"\", 'xt') + call assert_equal("\"chistory \", @:) endfunc func Test_complete_wildmenu() @@ -51,6 +56,11 @@ func Test_complete_wildmenu() call feedkeys(":e Xdir1/\\\\\", 'tx') call assert_equal('testfile1', getline(1)) + " Test for canceling the wild menu by adding a character + redrawstatus + call feedkeys(":e Xdir1/\x\\"\", 'xt') + call assert_equal('"e Xdir1/Xdir2/x', @:) + " Completion using a relative path cd Xdir1/Xdir2 call feedkeys(":e ../\\\\\\"\", 'tx') @@ -466,6 +476,18 @@ func Test_cmdline_paste() " Use an invalid expression for e call assert_beeps('call feedkeys(":\einvalid\", "tx")') + " Try to paste an invalid register using + call feedkeys(":\"one\\two\", 'xt') + call assert_equal('"onetwo', @:) + + let @a = "xy\z" + call feedkeys(":\"\a\", 'xt') + call assert_equal('"xz', @:) + call feedkeys(":\"\\a\", 'xt') + call assert_equal("\"xy\z", @:) + + call assert_beeps('call feedkeys(":\=\=\", "xt")') + bwipe! endfunc @@ -1053,4 +1075,110 @@ func Test_cmdline_expand_home() call delete('Xdir', 'rf') endfunc +" Test for using CTRL-\ CTRL-G in the command line to go back to normal mode +" or insert mode (when 'insertmode' is set) +func Test_cmdline_ctrl_g() + new + call setline(1, 'abc') + call cursor(1, 3) + " If command line is entered from insert mode, using C-\ C-G should back to + " insert mode + call feedkeys("i\:\\xy", 'xt') + call assert_equal('abxyc', getline(1)) + call assert_equal(4, col('.')) + + " If command line is entered in 'insertmode', using C-\ C-G should back to + " 'insertmode' + call feedkeys(":set im\\:\\12\:set noim\", 'xt') + call assert_equal('ab12xyc', getline(1)) + close! +endfunc + +" Return the 'len' characters in screen starting from (row,col) +func s:ScreenLine(row, col, len) + let s = '' + for i in range(a:len) + let s .= nr2char(screenchar(a:row, a:col + i)) + endfor + return s +endfunc + +" Test for 'wildmode' +func Test_wildmode() + func T(a, c, p) + return "oneA\noneB\noneC" + endfunc + command -nargs=1 -complete=custom,T MyCmd + + func SaveScreenLine() + let g:Sline = s:ScreenLine(&lines - 1, 1, 20) + return '' + endfunc + cnoremap SaveScreenLine() + + set nowildmenu + set wildmode=full,list + let g:Sline = '' + call feedkeys(":MyCmd \t\t\\\"\", 'xt') + call assert_equal('oneA oneB oneC ', g:Sline) + call assert_equal('"MyCmd oneA', @:) + + set wildmode=longest,full + call feedkeys(":MyCmd o\t\\"\", 'xt') + call assert_equal('"MyCmd one', @:) + call feedkeys(":MyCmd o\t\t\t\t\\"\", 'xt') + call assert_equal('"MyCmd oneC', @:) + + set wildmode=longest + call feedkeys(":MyCmd one\t\t\\"\", 'xt') + call assert_equal('"MyCmd one', @:) + + set wildmode=list:longest + let g:Sline = '' + call feedkeys(":MyCmd \t\\\"\", 'xt') + call assert_equal('oneA oneB oneC ', g:Sline) + call assert_equal('"MyCmd one', @:) + + set wildmode="" + call feedkeys(":MyCmd \t\t\\"\", 'xt') + call assert_equal('"MyCmd oneA', @:) + + delcommand MyCmd + delfunc T + delfunc SaveScreenLine + cunmap + set wildmode& +endfunc + +" Test for interrupting the command-line completion +func Test_interrupt_compl() + func F(lead, cmdl, p) + if a:lead =~ 'tw' + call interrupt() + return + endif + return "one\ntwo\nthree" + endfunc + command -nargs=1 -complete=custom,F Tcmd + + set nowildmenu + set wildmode=full + let interrupted = 0 + try + call feedkeys(":Tcmd tw\\\"\", 'xt') + catch /^Vim:Interrupt$/ + let interrupted = 1 + endtry + call assert_equal(1, interrupted) + + delcommand Tcmd + delfunc F + set wildmode& +endfunc + +func Test_cmdline_edit() + call feedkeys(":\"buffer\\\\", 'xt') + call assert_equal("\"buffer", @:) +endfunc + " vim: shiftwidth=2 sts=2 expandtab diff --git a/src/testdir/test_ex_mode.vim b/src/testdir/test_ex_mode.vim index 7869c762e6..91ba012e15 100644 --- a/src/testdir/test_ex_mode.vim +++ b/src/testdir/test_ex_mode.vim @@ -116,10 +116,16 @@ endfunc func Test_Ex_global() new call setline(1, ['', 'foo', 'bar', 'foo', 'bar', 'foo']) - call feedkeys("Qg/bar/visual\$rxQ$ryQvisual\j", "xt") + call feedkeys("Q\g/bar/visual\$rxQ$ryQvisual\j", "xt") call assert_equal('bax', getline(3)) call assert_equal('bay', getline(5)) bwipe! endfunc +" In Ex-mode, a backslash escapes a newline +func Test_Ex_escape_enter() + call feedkeys("gQlet l = \"a\\\b\"\vi\", 'xt') + call assert_equal("a\rb", l) +endfunc + " vim: shiftwidth=2 sts=2 expandtab diff --git a/src/testdir/test_functions.vim b/src/testdir/test_functions.vim index 607e714ef0..327350be09 100644 --- a/src/testdir/test_functions.vim +++ b/src/testdir/test_functions.vim @@ -1162,6 +1162,19 @@ func Test_input_func() \ .. "\\", 'xt') delfunc Tcomplete call assert_equal('item1 item2 item3', c) + + call assert_fails("call input('F:', '', 'invalid')", 'E180:') + call assert_fails("call input('F:', '', [])", 'E730:') +endfunc + +" Test for the inputdialog() function +func Test_inputdialog() + CheckNotGui + + call feedkeys(":let v=inputdialog('Q:', 'xx', 'yy')\\", 'xt') + call assert_equal('xx', v) + call feedkeys(":let v=inputdialog('Q:', 'xx', 'yy')\\", 'xt') + call assert_equal('yy', v) endfunc " Test for inputlist() diff --git a/src/testdir/test_history.vim b/src/testdir/test_history.vim index b12eef008e..96006ac7e7 100644 --- a/src/testdir/test_history.vim +++ b/src/testdir/test_history.vim @@ -70,6 +70,14 @@ function History_Tests(hist) call assert_equal('', histget(a:hist, i)) call assert_equal('', histget(a:hist, i - 7 - 1)) endfor + + " Test for freeing an entry at the beginning of the history list + for i in range(1, 4) + call histadd(a:hist, 'text_' . i) + endfor + call histdel(a:hist, 1) + call assert_equal('', histget(a:hist, 1)) + call assert_equal('text_4', histget(a:hist, 4)) endfunction function Test_History() @@ -115,14 +123,14 @@ endfunc func Test_history_size() let save_histsz = &history call histdel(':') - set history=5 + set history=10 for i in range(1, 5) call histadd(':', 'cmd' .. i) endfor call assert_equal(5, histnr(':')) call assert_equal('cmd5', histget(':', -1)) - set history=10 + set history=15 for i in range(6, 10) call histadd(':', 'cmd' .. i) endfor @@ -137,6 +145,15 @@ func Test_history_size() call assert_equal('cmd7', histget(':', 7)) call assert_equal('abc', histget(':', -1)) + " This test works only when the language is English + if v:lang == "C" || v:lang =~ '^[Ee]n' + set history=0 + redir => v + call feedkeys(":history\", 'xt') + redir END + call assert_equal(["'history' option is zero"], split(v, "\n")) + endif + let &history=save_histsz endfunc @@ -158,4 +175,12 @@ func Test_history_search() delfunc SavePat endfunc +" Test for making sure the key value is not stored in history +func Test_history_crypt_key() + CheckFeature cryptv + call feedkeys(":set bs=2 key=abc ts=8\", 'xt') + call assert_equal('set bs=2 key= ts=8', histget(':')) + set key& bs& ts& +endfunc + " vim: shiftwidth=2 sts=2 expandtab diff --git a/src/testdir/test_options.vim b/src/testdir/test_options.vim index f8d09fefcf..3fc0161221 100644 --- a/src/testdir/test_options.vim +++ b/src/testdir/test_options.vim @@ -672,4 +672,27 @@ func Test_shellquote() call assert_match(': "#echo Hello#"', v) endfunc +" Test for the 'rightleftcmd' option +func Test_rightleftcmd() + CheckFeature rightleft + set rightleft + set rightleftcmd + + let g:l = [] + func AddPos() + call add(g:l, screencol()) + return '' + endfunc + cmap AddPos() + + call feedkeys("/\abc\\\\\" .. + \ "\\\", 'xt') + call assert_equal([&co - 1, &co - 4, &co - 2, &co - 3], g:l) + + cunmap + unlet g:l + set rightleftcmd& + set rightleft& +endfunc + " vim: shiftwidth=2 sts=2 expandtab diff --git a/src/version.c b/src/version.c index 3f64431245..7028ffdbf3 100644 --- a/src/version.c +++ b/src/version.c @@ -738,6 +738,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 325, /**/ 324, /**/ From d5aec0ced17f8f60761128bff32e54ad2d1d57ef Mon Sep 17 00:00:00 2001 From: Bram Moolenaar Date: Thu, 27 Feb 2020 21:48:51 +0100 Subject: [PATCH 06/63] patch 8.2.0326: compiler warning for using uninitialized variable Problem: Compiler warning for using uninitialized variable. (Yegappan Lakshmanan) Solution: Do not jump to failed but return. --- 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 7028ffdbf3..ad279466ef 100644 --- a/src/version.c +++ b/src/version.c @@ -738,6 +738,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 326, /**/ 325, /**/ diff --git a/src/vim9execute.c b/src/vim9execute.c index 9ecb8657e6..5c5fcb1573 100644 --- a/src/vim9execute.c +++ b/src/vim9execute.c @@ -436,7 +436,7 @@ call_def_function( vim_memset(&ectx, 0, sizeof(ectx)); ga_init2(&ectx.ec_stack, sizeof(typval_T), 500); if (ga_grow(&ectx.ec_stack, 20) == FAIL) - goto failed; + return FAIL; ectx.ec_dfunc_idx = ufunc->uf_dfunc_idx; ga_init2(&ectx.ec_trystack, sizeof(trycmd_T), 10); From 80ae880f5fed8022c69d05dd1efee49259929cb5 Mon Sep 17 00:00:00 2001 From: Bram Moolenaar Date: Fri, 28 Feb 2020 19:11:18 +0100 Subject: [PATCH 07/63] patch 8.2.0327: crash when opening and closing two popup terminal windows Problem: Crash when opening and closing two popup terminal windows. Solution: Check that prevwin is valid. (closes #5707) --- src/popupwin.c | 28 +++++++++++++++++++++++++--- src/testdir/test_terminal.vim | 11 +++++++++++ src/version.c | 2 ++ 3 files changed, 38 insertions(+), 3 deletions(-) diff --git a/src/popupwin.c b/src/popupwin.c index 407837850d..0e0260b900 100644 --- a/src/popupwin.c +++ b/src/popupwin.c @@ -2114,9 +2114,31 @@ popup_close_and_callback(win_T *wp, typval_T *arg) #ifdef FEAT_TERMINAL if (wp == curwin && curbuf->b_term != NULL) { - // Closing popup window with a terminal: put focus back on the previous - // window. - win_enter(prevwin, FALSE); + win_T *owp; + + // Closing popup window with a terminal: put focus back on the first + // that works: + // - another popup window with a terminal + // - the previous window + // - the first one. + for (owp = first_popupwin; owp != NULL; owp = owp->w_next) + if (owp != curwin && owp->w_buffer->b_term != NULL) + break; + if (owp != NULL) + win_enter(owp, FALSE); + else + { + for (owp = curtab->tp_first_popupwin; owp != NULL; + owp = owp->w_next) + if (owp != curwin && owp->w_buffer->b_term != NULL) + break; + if (owp != NULL) + win_enter(owp, FALSE); + else if (win_valid(prevwin)) + win_enter(prevwin, FALSE); + else + win_enter(firstwin, FALSE); + } } #endif diff --git a/src/testdir/test_terminal.vim b/src/testdir/test_terminal.vim index 20d27bc022..fb717f603f 100644 --- a/src/testdir/test_terminal.vim +++ b/src/testdir/test_terminal.vim @@ -2391,6 +2391,17 @@ func Test_terminal_in_popup() call delete('XtermPopup') endfunc +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 popup_close(win1) + call popup_close(win2) + exe buf1 .. 'bwipe!' + exe buf2 .. 'bwipe!' +endfunc + func Test_issue_5607() let wincount = winnr('$') exe 'terminal' &shell &shellcmdflag 'exit' diff --git a/src/version.c b/src/version.c index ad279466ef..693a1d6ea8 100644 --- a/src/version.c +++ b/src/version.c @@ -738,6 +738,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 327, /**/ 326, /**/ From e52e0c89d1a6305beca3c01f89a4892dcb43bc71 Mon Sep 17 00:00:00 2001 From: Bram Moolenaar Date: Fri, 28 Feb 2020 22:20:10 +0100 Subject: [PATCH 08/63] patch 8.2.0328: no redraw when leaving term-normal mode in popup terminal Problem: No redraw when leaving terminal-normal mode in a terminal popup window. Solution: Redraw the popup window. (closes #5708) --- src/drawscreen.c | 49 +++++++++++++------- src/macros.h | 2 + src/move.c | 7 +++ src/popupwin.c | 9 ++-- src/terminal.c | 45 +++++++++++++++--- src/testdir/dumps/Test_terminal_popup_7.dump | 15 ++++++ src/testdir/dumps/Test_terminal_popup_8.dump | 15 ++++++ src/testdir/test_terminal.vim | 10 +++- src/version.c | 2 + src/vim.h | 6 --- 10 files changed, 126 insertions(+), 34 deletions(-) create mode 100644 src/testdir/dumps/Test_terminal_popup_7.dump create mode 100644 src/testdir/dumps/Test_terminal_popup_8.dump diff --git a/src/drawscreen.c b/src/drawscreen.c index 6b755c8c9b..17a385c924 100644 --- a/src/drawscreen.c +++ b/src/drawscreen.c @@ -69,6 +69,9 @@ static void win_update(win_T *wp); #ifdef FEAT_STL_OPT static void redraw_custom_statusline(win_T *wp); #endif +#if defined(FEAT_SEARCH_EXTRA) || defined(FEAT_CLIPBOARD) +static int did_update_one_window; +#endif /* * Based on the current value of curwin->w_topline, transfer a screenfull @@ -81,10 +84,8 @@ update_screen(int type_arg) int type = type_arg; win_T *wp; static int did_intro = FALSE; -#if defined(FEAT_SEARCH_EXTRA) || defined(FEAT_CLIPBOARD) - int did_one; -#endif #ifdef FEAT_GUI + int did_one = FALSE; int did_undraw = FALSE; int gui_cursor_col = 0; int gui_cursor_row = 0; @@ -276,7 +277,7 @@ update_screen(int type_arg) // Go from top to bottom through the windows, redrawing the ones that need // it. #if defined(FEAT_SEARCH_EXTRA) || defined(FEAT_CLIPBOARD) - did_one = FALSE; + did_update_one_window = FALSE; #endif #ifdef FEAT_SEARCH_EXTRA screen_search_hl.rm.regprog = NULL; @@ -286,21 +287,11 @@ update_screen(int type_arg) if (wp->w_redr_type != 0) { cursor_off(); -#if defined(FEAT_SEARCH_EXTRA) || defined(FEAT_CLIPBOARD) +#ifdef FEAT_GUI if (!did_one) { did_one = TRUE; -# ifdef FEAT_SEARCH_EXTRA - start_search_hl(); -# endif -# ifdef FEAT_CLIPBOARD - // When Visual area changed, may have to update selection. - if (clip_star.available && clip_isautosel_star()) - clip_update_selection(&clip_star); - if (clip_plus.available && clip_isautosel_plus()) - clip_update_selection(&clip_plus); -# endif -#ifdef FEAT_GUI + // Remove the cursor before starting to do anything, because // scrolling may make it difficult to redraw the text under // it. @@ -311,9 +302,9 @@ update_screen(int type_arg) gui_undraw_cursor(); did_undraw = TRUE; } -#endif } #endif + win_update(wp); } @@ -1422,6 +1413,25 @@ win_update(win_T *wp) proftime_T syntax_tm; #endif +#if defined(FEAT_SEARCH_EXTRA) || defined(FEAT_CLIPBOARD) + // This needs to be done only for the first window when update_screen() is + // called. + if (!did_update_one_window) + { + did_update_one_window = TRUE; +# ifdef FEAT_SEARCH_EXTRA + start_search_hl(); +# endif +# ifdef FEAT_CLIPBOARD + // When Visual area changed, may have to update selection. + if (clip_star.available && clip_isautosel_star()) + clip_update_selection(&clip_star); + if (clip_plus.available && clip_isautosel_plus()) + clip_update_selection(&clip_plus); +# endif + } +#endif + type = wp->w_redr_type; if (type == NOT_VALID) @@ -3025,6 +3035,11 @@ redraw_buf_later(buf_T *buf, int type) if (wp->w_buffer == buf) redraw_win_later(wp, type); } +#if defined(FEAT_TERMINAL) && defined(FEAT_PROP_POPUP) + // terminal in popup window is not in list of windows + if (curwin->w_buffer == buf) + redraw_win_later(curwin, type); +#endif } #if defined(FEAT_SIGNS) || defined(PROTO) diff --git a/src/macros.h b/src/macros.h index b719462889..a7964d850a 100644 --- a/src/macros.h +++ b/src/macros.h @@ -344,9 +344,11 @@ // Give an error in curwin is a popup window and evaluate to TRUE. #ifdef FEAT_PROP_POPUP +# define WIN_IS_POPUP(wp) ((wp)->w_popup_flags != 0) # define ERROR_IF_POPUP_WINDOW error_if_popup_window(FALSE) # define ERROR_IF_ANY_POPUP_WINDOW error_if_popup_window(TRUE) #else +# define WIN_IS_POPUP(wp) 0 # define ERROR_IF_POPUP_WINDOW 0 # define ERROR_IF_ANY_POPUP_WINDOW 0 #endif diff --git a/src/move.c b/src/move.c index 6b854541c0..5b3fb35fb4 100644 --- a/src/move.c +++ b/src/move.c @@ -1174,6 +1174,13 @@ curs_columns( && !pum_visible()) redraw_later(SOME_VALID); #endif +#if defined(FEAT_PROP_POPUP) && defined(FEAT_TERMINAL) + if (popup_is_popup(curwin) && curbuf->b_term != NULL) + { + curwin->w_wrow += popup_top_extra(curwin); + curwin->w_wcol += popup_left_extra(curwin); + } +#endif // now w_leftcol is valid, avoid check_cursor_moved() thinking otherwise curwin->w_valid_leftcol = curwin->w_leftcol; diff --git a/src/popupwin.c b/src/popupwin.c index 0e0260b900..8cdb68a498 100644 --- a/src/popupwin.c +++ b/src/popupwin.c @@ -3505,9 +3505,12 @@ update_popups(void (*win_update)(win_T *wp)) wp->w_winrow -= top_off; wp->w_wincol -= left_extra; - // cursor position matters in terminal - wp->w_wrow += top_off; - wp->w_wcol += left_extra; + // cursor position matters in terminal in job mode + if (wp != curwin || !term_in_normal_mode()) + { + wp->w_wrow += top_off; + wp->w_wcol += left_extra; + } total_width = popup_width(wp); total_height = popup_height(wp); diff --git a/src/terminal.c b/src/terminal.c index 342275e40c..d4c605ed8f 100644 --- a/src/terminal.c +++ b/src/terminal.c @@ -1795,6 +1795,27 @@ update_snapshot(term_T *term) #endif } +/* + * Loop over all windows in the current tab, and also curwin, which is not + * encountered when using a terminal in a popup window. + * Return TRUE if "*wp" was set to the next window. + */ + static int +for_all_windows_and_curwin(win_T **wp, int *did_curwin) +{ + if (*wp == NULL) + *wp = firstwin; + else if ((*wp)->w_next != NULL) + *wp = (*wp)->w_next; + else if (!*did_curwin) + *wp = curwin; + else + return FALSE; + if (*wp == curwin) + *did_curwin = TRUE; + return TRUE; +} + /* * If needed, add the current lines of the terminal to scrollback and to the * buffer. Called after the job has ended and when switching to @@ -1804,8 +1825,6 @@ update_snapshot(term_T *term) static void may_move_terminal_to_buffer(term_T *term, int redraw) { - win_T *wp; - if (term->tl_vterm == NULL) return; @@ -1820,7 +1839,11 @@ may_move_terminal_to_buffer(term_T *term, int redraw) &term->tl_default_color.fg, &term->tl_default_color.bg); if (redraw) - FOR_ALL_WINDOWS(wp) + { + win_T *wp = NULL; + int did_curwin = FALSE; + + while (for_all_windows_and_curwin(&wp, &did_curwin)) { if (wp->w_buffer == term->tl_buffer) { @@ -1837,6 +1860,7 @@ may_move_terminal_to_buffer(term_T *term, int redraw) redraw_win_later(wp, NOT_VALID); } } + } } #if defined(FEAT_TIMERS) || defined(PROTO) @@ -1920,6 +1944,7 @@ term_enter_normal_mode(void) check_cursor(); if (coladvance(term->tl_cursor_pos.col) == FAIL) coladvance(MAXCOL); + curwin->w_set_curswant = TRUE; // Display the same lines as in the terminal. curwin->w_topline = term->tl_scrollback_scrolled + 1; @@ -1951,6 +1976,10 @@ term_enter_job_mode() if (term->tl_channel_closed) cleanup_vterm(term); redraw_buf_and_status_later(curbuf, NOT_VALID); +#ifdef FEAT_PROP_POPUP + if (WIN_IS_POPUP(curwin)) + redraw_win_later(curwin, NOT_VALID); +#endif } /* @@ -2801,14 +2830,15 @@ handle_damage(VTermRect rect, void *user) static void term_scroll_up(term_T *term, int start_row, int count) { - win_T *wp; + win_T *wp = NULL; + int did_curwin = FALSE; VTermColor fg, bg; VTermScreenCellAttrs attr; int clear_attr; vim_memset(&attr, 0, sizeof(attr)); - FOR_ALL_WINDOWS(wp) + while (for_all_windows_and_curwin(&wp, &did_curwin)) { if (wp->w_buffer == term->tl_buffer) { @@ -2858,12 +2888,13 @@ handle_movecursor( void *user) { term_T *term = (term_T *)user; - win_T *wp; + win_T *wp = NULL; + int did_curwin = FALSE; term->tl_cursor_pos = pos; term->tl_cursor_visible = visible; - FOR_ALL_WINDOWS(wp) + while (for_all_windows_and_curwin(&wp, &did_curwin)) { if (wp->w_buffer == term->tl_buffer) position_cursor(wp, &pos, FALSE); diff --git a/src/testdir/dumps/Test_terminal_popup_7.dump b/src/testdir/dumps/Test_terminal_popup_7.dump new file mode 100644 index 0000000000..6d0d7b69ac --- /dev/null +++ b/src/testdir/dumps/Test_terminal_popup_7.dump @@ -0,0 +1,15 @@ +|0+0&#ffffff0| @73 +|1| @73 +|2| @73 +|3| @12|╔+0#0000001#ffd7ff255|═@44|╗| +0#0000000#ffffff0@13 +|4| @12|║+0#0000001#ffd7ff255|s|o|m|e| |t|e|x|t| @35|║| +0#0000000#ffffff0@13 +|5| @12|║+0#0000001#ffd7ff255|t|o| |e+0&#ffff4012|d|i|t| +0&#ffd7ff255@37|║| +0#0000000#ffffff0@13 +|6| @12|║+0#0000001#ffd7ff255|i+0&#e0e0e08|n| |a| >p+0&#ffd7ff255|o|p|u|p| |w|i|n|d|o|w| @27|║| +0#0000000#ffffff0@13 +|7| @12|║+0#0000001#ffd7ff255|~+0#4040ff13&| @43|║+0#0000001&| +0#0000000#ffffff0@13 +|8| @12|║+0#0000001#ffd7ff255|~+0#4040ff13&| @43|║+0#0000001&| +0#0000000#ffffff0@13 +|9| @12|║+0#0000001#ffd7ff255|~+0#4040ff13&| @43|║+0#0000001&| +0#0000000#ffffff0@13 +|1|0| @11|║+0#0000001#ffd7ff255|/|e|d|i|t| @21|2|,|4| @10|A|l@1| |║| +0#0000000#ffffff0@13 +|1@1| @11|╚+0#0000001#ffd7ff255|═@44|╝| +0#0000000#ffffff0@13 +|1|2| @72 +|1|3| @72 +|-+2&&@1| |V|I|S|U|A|L| |-@1| +0&&@34|6| @8|3|,|6| @10|A|l@1| diff --git a/src/testdir/dumps/Test_terminal_popup_8.dump b/src/testdir/dumps/Test_terminal_popup_8.dump new file mode 100644 index 0000000000..f8f6d9edf5 --- /dev/null +++ b/src/testdir/dumps/Test_terminal_popup_8.dump @@ -0,0 +1,15 @@ +|0+0&#ffffff0| @73 +|1| @73 +|2| @73 +|3| @12|╔+0#0000001#ffd7ff255|═@44|╗| +0#0000000#ffffff0@13 +|4| @12|║+0#0000001#ffd7ff255|s+0#0000000#ffffff0|o|m|e| |t|e|x|t| @35|║+0#0000001#ffd7ff255| +0#0000000#ffffff0@13 +|5| @12|║+0#0000001#ffd7ff255|t+0#0000000#ffffff0|o| >e+0&#ffff4012|d|i|t| +0&#ffffff0@37|║+0#0000001#ffd7ff255| +0#0000000#ffffff0@13 +|6| @12|║+0#0000001#ffd7ff255|i+0#0000000#ffffff0|n| |a| |p|o|p|u|p| |w|i|n|d|o|w| @27|║+0#0000001#ffd7ff255| +0#0000000#ffffff0@13 +|7| @12|║+0#0000001#ffd7ff255|~+0#4040ff13#ffffff0| @43|║+0#0000001#ffd7ff255| +0#0000000#ffffff0@13 +|8| @12|║+0#0000001#ffd7ff255|~+0#4040ff13#ffffff0| @43|║+0#0000001#ffd7ff255| +0#0000000#ffffff0@13 +|9| @12|║+0#0000001#ffd7ff255|~+0#4040ff13#ffffff0| @43|║+0#0000001#ffd7ff255| +0#0000000#ffffff0@13 +|1|0| @11|║+0#0000001#ffd7ff255|/+0#0000000#ffffff0|e|d|i|t| @21|2|,|4| @10|A|l@1| |║+0#0000001#ffd7ff255| +0#0000000#ffffff0@13 +|1@1| @11|╚+0#0000001#ffd7ff255|═@44|╝| +0#0000000#ffffff0@13 +|1|2| @72 +|1|3| @72 +@57|1|,|1| @10|T|o|p| diff --git a/src/testdir/test_terminal.vim b/src/testdir/test_terminal.vim index fb717f603f..e2d7595460 100644 --- a/src/testdir/test_terminal.vim +++ b/src/testdir/test_terminal.vim @@ -2382,8 +2382,16 @@ func Test_terminal_in_popup() call term_sendkeys(buf, "\:call ReopenPopup()\") call VerifyScreenDump(buf, 'Test_terminal_popup_6', {}) - call term_wait(buf, 100) + " Go to terminal-Normal mode and visually select text. + call term_sendkeys(buf, "\Ngg/in\vww") + call VerifyScreenDump(buf, 'Test_terminal_popup_7', {}) + + " Back to job mode, redraws + call term_sendkeys(buf, "A") + call VerifyScreenDump(buf, 'Test_terminal_popup_8', {}) + + call term_wait(buf, 100) call term_sendkeys(buf, ":q\") call term_wait(buf, 100) " wait for terminal to vanish diff --git a/src/version.c b/src/version.c index 693a1d6ea8..986e10dae5 100644 --- a/src/version.c +++ b/src/version.c @@ -738,6 +738,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 328, /**/ 327, /**/ diff --git a/src/vim.h b/src/vim.h index 658a2f129c..f9866667b8 100644 --- a/src/vim.h +++ b/src/vim.h @@ -640,12 +640,6 @@ extern int (*dyn_libintl_wputenv)(const wchar_t *envstring); #define POPUP_HANDLED_4 0x08 // used by may_update_popup_mask() #define POPUP_HANDLED_5 0x10 // used by update_popups() -#ifdef FEAT_PROP_POPUP -# define WIN_IS_POPUP(wp) ((wp)->w_popup_flags != 0) -#else -# define WIN_IS_POPUP(wp) 0 -#endif - /* * Terminal highlighting attribute bits. * Attributes above HL_ALL are used for syntax highlighting. From ec084d3356cc2a23f2f44707810c38ab590d2e66 Mon Sep 17 00:00:00 2001 From: Bram Moolenaar Date: Fri, 28 Feb 2020 22:44:47 +0100 Subject: [PATCH 09/63] patch 8.2.0329: popup filter converts 0x80 bytes Problem: Popup filter converts 0x80 bytes. Solution: Keep 0x80 bytes as-is. (Ozaki Kiichi, closes #5706) --- src/popupwin.c | 2 +- src/testdir/test_popupwin.vim | 30 +++++++++++++++++++++++++++--- src/version.c | 2 ++ 3 files changed, 30 insertions(+), 4 deletions(-) diff --git a/src/popupwin.c b/src/popupwin.c index 8cdb68a498..6402ba3ad5 100644 --- a/src/popupwin.c +++ b/src/popupwin.c @@ -2999,7 +2999,7 @@ invoke_popup_filter(win_T *wp, int c) // Convert the number to a string, so that the function can use: // if a:c == "\" - buf[special_to_buf(c, mod_mask, TRUE, buf)] = NUL; + buf[special_to_buf(c, mod_mask, FALSE, buf)] = NUL; argv[1].v_type = VAR_STRING; argv[1].vval.v_string = vim_strsave(buf); diff --git a/src/testdir/test_popupwin.vim b/src/testdir/test_popupwin.vim index d331263e3f..9c22845c49 100644 --- a/src/testdir/test_popupwin.vim +++ b/src/testdir/test_popupwin.vim @@ -1409,8 +1409,8 @@ func Test_popup_filter() call setline(1, 'some text') func MyPopupFilter(winid, c) - if a:c == 'e' - let g:eaten = 'e' + if a:c == 'e' || a:c == "\" + let g:eaten = a:c return 1 endif if a:c == '0' @@ -1430,6 +1430,8 @@ func Test_popup_filter() " e is consumed by the filter call feedkeys('e', 'xt') call assert_equal('e', g:eaten) + call feedkeys("\", 'xt') + call assert_equal("\", g:eaten) " 0 is ignored by the filter normal $ @@ -1440,7 +1442,7 @@ func Test_popup_filter() " x closes the popup call feedkeys('x', 'xt') - call assert_equal('e', g:eaten) + call assert_equal("\", g:eaten) call assert_equal(-1, winbufnr(winid)) delfunc MyPopupFilter @@ -3271,4 +3273,26 @@ func Test_popupwin_bufnr() bwipe! endfunc +func Test_popupwin_filter_input_multibyte() + func MyPopupFilter(winid, c) + let g:bytes = range(a:c->strlen())->map({i -> char2nr(a:c[i])}) + return 0 + endfunc + let winid = popup_create('', #{mapping: 0, filter: 'MyPopupFilter'}) + + " UTF-8: E3 80 80, including K_SPECIAL(0x80) + call feedkeys("\u3000", 'xt') + call assert_equal([0xe3, 0x80, 0x80], g:bytes) + + if has('gui') + " UTF-8: E3 80 9B, including CSI(0x9B) + call feedkeys("\u301b", 'xt') + call assert_equal([0xe3, 0x80, 0x9b], g:bytes) + endif + + call popup_clear() + delfunc MyPopupFilter + unlet g:bytes +endfunc + " vim: shiftwidth=2 sts=2 diff --git a/src/version.c b/src/version.c index 986e10dae5..ced13f84a7 100644 --- a/src/version.c +++ b/src/version.c @@ -738,6 +738,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 329, /**/ 328, /**/ From 57c732ed782607ce6a8c4f9eeb65b95a00e37701 Mon Sep 17 00:00:00 2001 From: Bram Moolenaar Date: Fri, 28 Feb 2020 22:51:54 +0100 Subject: [PATCH 10/63] patch 8.2.0330: build error with popup window but without terminal Problem: Build error with popup window but without terminal. 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 6402ba3ad5..45d6488059 100644 --- a/src/popupwin.c +++ b/src/popupwin.c @@ -3506,7 +3506,9 @@ update_popups(void (*win_update)(win_T *wp)) wp->w_winrow -= top_off; wp->w_wincol -= left_extra; // cursor position matters in terminal in job mode +#ifdef FEAT_TERMINAL if (wp != curwin || !term_in_normal_mode()) +#endif { wp->w_wrow += top_off; wp->w_wcol += left_extra; diff --git a/src/version.c b/src/version.c index ced13f84a7..b883605c69 100644 --- a/src/version.c +++ b/src/version.c @@ -738,6 +738,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 330, /**/ 329, /**/ From 7c215c58936cbebd4132ad6112d04db54b7c153e Mon Sep 17 00:00:00 2001 From: Bram Moolenaar Date: Sat, 29 Feb 2020 13:43:27 +0100 Subject: [PATCH 11/63] patch 8.2.0331: internal error when using test_void() and test_unknown() Problem: Internal error when using test_void() and test_unknown(). (Dominique Pelle) Solution: Give a normal error. --- src/evalfunc.c | 10 ++++++++-- src/testdir/test_functions.vim | 3 +++ src/testdir/test_vimscript.vim | 2 ++ src/version.c | 2 ++ 4 files changed, 15 insertions(+), 2 deletions(-) diff --git a/src/evalfunc.c b/src/evalfunc.c index ff891eaa94..3fce946bf1 100644 --- a/src/evalfunc.c +++ b/src/evalfunc.c @@ -1890,7 +1890,10 @@ f_empty(typval_T *argvars, typval_T *rettv) #endif case VAR_UNKNOWN: case VAR_VOID: - internal_error("f_empty(UNKNOWN)"); + // Let's not use internal_error() here, otherwise + // empty(test_unknown()) with ABORT_ON_INTERNAL_ERROR defined makes + // Vim abort. + semsg(_(e_intern2), "f_empty(UNKNOWN)"); n = TRUE; break; } @@ -8275,7 +8278,10 @@ f_type(typval_T *argvars, typval_T *rettv) case VAR_BLOB: n = VAR_TYPE_BLOB; break; case VAR_UNKNOWN: case VAR_VOID: - internal_error("f_type(UNKNOWN)"); + // Let's not use internal_error() here, otherwise + // empty(test_unknown()) with ABORT_ON_INTERNAL_ERROR defined + // makes Vim abort. + semsg(_(e_intern2), "f_type(UNKNOWN)"); n = -1; break; } diff --git a/src/testdir/test_functions.vim b/src/testdir/test_functions.vim index 327350be09..6f3b81a30c 100644 --- a/src/testdir/test_functions.vim +++ b/src/testdir/test_functions.vim @@ -58,6 +58,9 @@ func Test_empty() call assert_equal(0, empty(function('Test_empty'))) call assert_equal(0, empty(function('Test_empty', [0]))) + + call assert_fails("call empty(test_void())", 'E685:') + call assert_fails("call empty(test_unknown())", 'E685:') endfunc func Test_len() diff --git a/src/testdir/test_vimscript.vim b/src/testdir/test_vimscript.vim index 7a49b57835..cac3be53af 100644 --- a/src/testdir/test_vimscript.vim +++ b/src/testdir/test_vimscript.vim @@ -1165,6 +1165,8 @@ func Test_type() call assert_equal(v:t_none, type(v:none)) call assert_equal(v:t_none, type(v:null)) + call assert_fails("call type(test_void())", 'E685:') + call assert_fails("call type(test_unknown())", 'E685:') call assert_equal(0, 0 + v:false) call assert_equal(1, 0 + v:true) diff --git a/src/version.c b/src/version.c index b883605c69..c553f20a37 100644 --- a/src/version.c +++ b/src/version.c @@ -738,6 +738,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 331, /**/ 330, /**/ From d30ae2fc4acb3861fc7dc9618c1f90eee997d412 Mon Sep 17 00:00:00 2001 From: Bram Moolenaar Date: Sat, 29 Feb 2020 14:23:58 +0100 Subject: [PATCH 12/63] patch 8.2.0332: some code in ex_getln.c not covered by tests Problem: Some code in ex_getln.c not covered by tests. Solution: Add a few more tests. (Yegappan Lakshmanan, closes #5710) --- src/testdir/test_arabic.vim | 23 ++++++++++++++++ src/testdir/test_cmdline.vim | 51 ++++++++++++++++++++++++++++++++---- src/version.c | 2 ++ 3 files changed, 71 insertions(+), 5 deletions(-) diff --git a/src/testdir/test_arabic.vim b/src/testdir/test_arabic.vim index b679ec4520..272937387d 100644 --- a/src/testdir/test_arabic.vim +++ b/src/testdir/test_arabic.vim @@ -562,3 +562,26 @@ func Test_shape_combination_isolated() set arabicshape& bwipe! endfunc + +" Test for entering arabic character in a search command +func Test_arabic_chars_in_search_cmd() + new + set arabic + call feedkeys("i\nsghl!\vim\", 'tx') + call cursor(1, 1) + call feedkeys("/^sghl!\vim$\\", 'tx') + call assert_equal([2, 1], [line('.'), col('.')]) + + " Try searching in left-to-right mode + set rightleftcmd= + call cursor(1, 1) + call feedkeys("/^sghl!\vim$\", 'tx') + call assert_equal([2, 1], [line('.'), col('.')]) + + set rightleftcmd& + set rightleft& + set arabic& + bwipe! +endfunc + +" vim: shiftwidth=2 sts=2 expandtab diff --git a/src/testdir/test_cmdline.vim b/src/testdir/test_cmdline.vim index f61d4aeab5..1baed7961f 100644 --- a/src/testdir/test_cmdline.vim +++ b/src/testdir/test_cmdline.vim @@ -473,9 +473,6 @@ func Test_cmdline_paste() endtry call assert_equal("Xtestfile", bufname("%")) - " Use an invalid expression for e - call assert_beeps('call feedkeys(":\einvalid\", "tx")') - " Try to paste an invalid register using call feedkeys(":\"one\\two\", 'xt') call assert_equal('"onetwo', @:) @@ -1176,9 +1173,53 @@ func Test_interrupt_compl() set wildmode& endfunc +" Test for moving the cursor on the : command line func Test_cmdline_edit() - call feedkeys(":\"buffer\\\\", 'xt') - call assert_equal("\"buffer", @:) + let str = ":one two\" + let str ..= "one two\\" + let str ..= "\five\" + let str ..= "\two " + let str ..= "\one " + let str ..= "\ three" + let str ..= "\\four " + let str ..= "\ six" + let str ..= "\\"\ seven\" + call feedkeys(str, 'xt') + call assert_equal("\"one two three four five six seven", @:) +endfunc + +" Test for moving the cursor on the / command line in 'rightleft' mode +func Test_cmdline_edit_rightleft() + CheckFeature rightleft + set rightleft + set rightleftcmd=search + let str = "/one two\" + let str ..= "one two\\" + let str ..= "\five\" + let str ..= "\two " + let str ..= "\one " + let str ..= "\ three" + let str ..= "\\four " + let str ..= "\ six" + let str ..= "\\"\ seven\" + call assert_fails("call feedkeys(str, 'xt')", 'E486:') + call assert_equal("\"one two three four five six seven", @/) + set rightleftcmd& + set rightleft& +endfunc + +" Test for using e in the command line to evaluate an expression +func Test_cmdline_expr() + " Evaluate an expression from the beginning of a command line + call feedkeys(":abc\\e\"\\\"hello\"\\", 'xt') + call assert_equal('"hello', @:) + + " Use an invalid expression for e + call assert_beeps('call feedkeys(":\einvalid\", "tx")') + + " Insert literal in the command line + call feedkeys(":\"e \\\", 'xt') + call assert_equal("\"e \\", @:) endfunc " vim: shiftwidth=2 sts=2 expandtab diff --git a/src/version.c b/src/version.c index c553f20a37..42b859aba3 100644 --- a/src/version.c +++ b/src/version.c @@ -738,6 +738,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 332, /**/ 331, /**/ From 57c339569e96725e24e79944bf99f70c50afb5b1 Mon Sep 17 00:00:00 2001 From: Bram Moolenaar Date: Sat, 29 Feb 2020 16:09:16 +0100 Subject: [PATCH 13/63] patch 8.2.0333: terminal in popup test is flaky Problem: Terminal in popup test is flaky. Solution: Make sure redraw is done before opening the popup. --- src/testdir/dumps/Test_terminal_popup_1.dump | 2 +- src/testdir/test_terminal.vim | 15 +++++++-------- src/version.c | 2 ++ 3 files changed, 10 insertions(+), 9 deletions(-) diff --git a/src/testdir/dumps/Test_terminal_popup_1.dump b/src/testdir/dumps/Test_terminal_popup_1.dump index a03d589811..3e071498df 100644 --- a/src/testdir/dumps/Test_terminal_popup_1.dump +++ b/src/testdir/dumps/Test_terminal_popup_1.dump @@ -12,4 +12,4 @@ |1@1| @11|╚+0#0000001#ffd7ff255|═@44|⇲| +0#0000000#ffffff0@13 |1|2| @72 |1|3| @72 -|t|e|r|m|i|n|a|l| |p|o|p|u|p| @42|0|,|0|-|1| @8|A|l@1| +|t|e|r|m|i|n|a|l| |p|o|p|u|p| @42|1|,|1| @10|T|o|p| diff --git a/src/testdir/test_terminal.vim b/src/testdir/test_terminal.vim index e2d7595460..1a9e1e3d4a 100644 --- a/src/testdir/test_terminal.vim +++ b/src/testdir/test_terminal.vim @@ -2339,29 +2339,28 @@ func Test_terminal_in_popup() \ 'hi PopTerm ctermbg=grey', \ 'func OpenTerm(setColor)', \ " let s:buf = term_start('" .. cmd .. " Xtext', #{hidden: 1, term_finish: 'close'})", - \ ' let s:winid = popup_create(s:buf, #{minwidth: 45, minheight: 7, border: [], drag: 1, resize: 1})', + \ ' let g:winid = popup_create(s:buf, #{minwidth: 45, minheight: 7, border: [], drag: 1, resize: 1})', \ ' if a:setColor', - \ ' call win_execute(s:winid, "set wincolor=PopTerm")', + \ ' call win_execute(g:winid, "set wincolor=PopTerm")', \ ' endif', \ 'endfunc', - \ 'call OpenTerm(0)', \ 'func HidePopup()', - \ ' call popup_hide(s:winid)', + \ ' call popup_hide(g:winid)', \ 'endfunc', \ 'func ClosePopup()', - \ ' call popup_close(s:winid)', + \ ' call popup_close(g:winid)', \ 'endfunc', \ 'func ReopenPopup()', \ ' call popup_create(s:buf, #{minwidth: 40, minheight: 6, border: []})', \ 'endfunc', - \ 'sleep 10m', - \ 'redraw', - \ 'echo getwinvar(s:winid, "&buftype") win_gettype(s:winid)', \ ] call writefile(lines, 'XtermPopup') let buf = RunVimInTerminal('-S XtermPopup', #{rows: 15}) call term_wait(buf, 100) + call term_sendkeys(buf, ":call OpenTerm(0)\") + call term_wait(buf, 100) call term_sendkeys(buf, ":\") + call term_sendkeys(buf, "\:echo getwinvar(g:winid, \"&buftype\") win_gettype(g:winid)\") call VerifyScreenDump(buf, 'Test_terminal_popup_1', {}) call term_sendkeys(buf, ":q\") diff --git a/src/version.c b/src/version.c index 42b859aba3..a8289633bf 100644 --- a/src/version.c +++ b/src/version.c @@ -738,6 +738,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 333, /**/ 332, /**/ From dd58923c6bcb026de7134d9874e69e0a2b01682d Mon Sep 17 00:00:00 2001 From: Bram Moolenaar Date: Sat, 29 Feb 2020 17:38:12 +0100 Subject: [PATCH 14/63] patch 8.2.0334: abort called when using test_void() Problem: Abort called when using test_void(). (Dominique Pelle) Solution: Only give an error, don't abort. --- src/eval.c | 8 ++++---- src/evalfunc.c | 10 ++-------- src/json.c | 2 +- src/message.c | 10 ++++++++++ src/proto/message.pro | 1 + src/testdir/test_functions.vim | 10 ++++++++++ src/version.c | 2 ++ 7 files changed, 30 insertions(+), 13 deletions(-) diff --git a/src/eval.c b/src/eval.c index dcaf2f02cc..c81ece1494 100644 --- a/src/eval.c +++ b/src/eval.c @@ -5560,7 +5560,7 @@ tv_get_number_chk(typval_T *varp, int *denote) break; case VAR_UNKNOWN: case VAR_VOID: - internal_error("tv_get_number(UNKNOWN)"); + internal_error_no_abort("tv_get_number(UNKNOWN)"); break; } if (denote == NULL) // useful for values that must be unsigned @@ -5614,7 +5614,7 @@ tv_get_float(typval_T *varp) break; case VAR_UNKNOWN: case VAR_VOID: - internal_error("tv_get_float(UNKNOWN)"); + internal_error_no_abort("tv_get_float(UNKNOWN)"); break; } return 0; @@ -5886,7 +5886,7 @@ copy_tv(typval_T *from, typval_T *to) break; case VAR_UNKNOWN: case VAR_VOID: - internal_error("copy_tv(UNKNOWN)"); + internal_error_no_abort("copy_tv(UNKNOWN)"); break; } } @@ -5965,7 +5965,7 @@ item_copy( break; case VAR_UNKNOWN: case VAR_VOID: - internal_error("item_copy(UNKNOWN)"); + internal_error_no_abort("item_copy(UNKNOWN)"); ret = FAIL; } --recurse; diff --git a/src/evalfunc.c b/src/evalfunc.c index 3fce946bf1..39e347ad20 100644 --- a/src/evalfunc.c +++ b/src/evalfunc.c @@ -1890,10 +1890,7 @@ f_empty(typval_T *argvars, typval_T *rettv) #endif case VAR_UNKNOWN: case VAR_VOID: - // Let's not use internal_error() here, otherwise - // empty(test_unknown()) with ABORT_ON_INTERNAL_ERROR defined makes - // Vim abort. - semsg(_(e_intern2), "f_empty(UNKNOWN)"); + internal_error_no_abort("f_empty(UNKNOWN)"); n = TRUE; break; } @@ -8278,10 +8275,7 @@ f_type(typval_T *argvars, typval_T *rettv) case VAR_BLOB: n = VAR_TYPE_BLOB; break; case VAR_UNKNOWN: case VAR_VOID: - // Let's not use internal_error() here, otherwise - // empty(test_unknown()) with ABORT_ON_INTERNAL_ERROR defined - // makes Vim abort. - semsg(_(e_intern2), "f_type(UNKNOWN)"); + internal_error_no_abort("f_type(UNKNOWN)"); n = -1; break; } diff --git a/src/json.c b/src/json.c index d5e5782c52..f4a03e61ad 100644 --- a/src/json.c +++ b/src/json.c @@ -352,7 +352,7 @@ json_encode_item(garray_T *gap, typval_T *val, int copyID, int options) #endif case VAR_UNKNOWN: case VAR_VOID: - internal_error("json_encode_item()"); + internal_error_no_abort("json_encode_item()"); return FAIL; } return OK; diff --git a/src/message.c b/src/message.c index c2855fb34b..cb1a773ce7 100644 --- a/src/message.c +++ b/src/message.c @@ -838,6 +838,16 @@ internal_error(char *where) siemsg(_(e_intern2), where); } +/* + * Like internal_error() but do not call abort(), to avoid tests using + * test_unknown() and test_void() causing Vim to exit. + */ + void +internal_error_no_abort(char *where) +{ + semsg(_(e_intern2), where); +} + // emsg3() and emsgn() are in misc2.c to avoid warnings for the prototypes. void diff --git a/src/proto/message.pro b/src/proto/message.pro index 5c9ca6cb11..16c3354840 100644 --- a/src/proto/message.pro +++ b/src/proto/message.pro @@ -12,6 +12,7 @@ void do_perror(char *msg); int emsg(char *s); void iemsg(char *s); void internal_error(char *where); +void internal_error_no_abort(char *where); void emsg_invreg(int name); void emsg_namelen(char *msg, char_u *name, int len); char *msg_trunc_attr(char *s, int force, int attr); diff --git a/src/testdir/test_functions.vim b/src/testdir/test_functions.vim index 6f3b81a30c..ef4180a770 100644 --- a/src/testdir/test_functions.vim +++ b/src/testdir/test_functions.vim @@ -63,6 +63,16 @@ func Test_empty() call assert_fails("call empty(test_unknown())", 'E685:') endfunc +func Test_test_void() + call assert_fails('echo 1 == test_void()', 'E685:') + if has('float') + call assert_fails('echo 1.0 == test_void()', 'E685:') + endif + call assert_fails('let x = json_encode(test_void())', 'E685:') + call assert_fails('let x = copy(test_void())', 'E685:') + call assert_fails('let x = copy([test_void()])', 'E685:') +endfunc + func Test_len() call assert_equal(1, len(0)) call assert_equal(2, len(12)) diff --git a/src/version.c b/src/version.c index a8289633bf..4dc9642a5c 100644 --- a/src/version.c +++ b/src/version.c @@ -738,6 +738,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 334, /**/ 333, /**/ From cc390ff5b2c8725c55b961b24322c470659ede9f Mon Sep 17 00:00:00 2001 From: Bram Moolenaar Date: Sat, 29 Feb 2020 22:06:30 +0100 Subject: [PATCH 15/63] patch 8.2.0335: no completion for :disassemble Problem: No completion for :disassemble. Solution: Make completion work. Also complete script-local functions if the name starts with "s:". --- runtime/doc/vim9.txt | 8 ++++++++ src/cmdexpand.c | 14 ++++++++++++++ src/testdir/test_cmdline.vim | 11 +++++++++++ src/version.c | 2 ++ 4 files changed, 35 insertions(+) diff --git a/runtime/doc/vim9.txt b/runtime/doc/vim9.txt index d634f22fdd..3ba92dbcaf 100644 --- a/runtime/doc/vim9.txt +++ b/runtime/doc/vim9.txt @@ -149,6 +149,12 @@ with `substitute(` this will use the function, prepend a colon to use the command instead: > :substitute(pattern (replacement ( +Note that while variables need to be defined before they can be used, +functions can be called before being defined. This is required to be able +have cyclic dependencies between functions. It is slightly less efficient, +since the function has to be looked up by name. And a typo in the function +name will only be found when the call is executed. + No curly braces expansion ~ @@ -275,6 +281,8 @@ script, then script-local variables must be accessed with the "s:" prefix. *:disa* *:disassemble* :disa[ssemble] {func} Show the instructions generated for {func}. This is for debugging and testing. + Note that for command line completion of {func} you + can prepend "s:" to find script-local functions. ============================================================================== diff --git a/src/cmdexpand.c b/src/cmdexpand.c index b5da922fd1..ece5a468b1 100644 --- a/src/cmdexpand.c +++ b/src/cmdexpand.c @@ -1550,6 +1550,7 @@ set_one_cmd_context( case CMD_function: case CMD_delfunction: + case CMD_disassemble: xp->xp_context = EXPAND_USER_FUNC; xp->xp_pattern = arg; break; @@ -1978,6 +1979,7 @@ ExpandFromContext( regmatch_T regmatch; int ret; int flags; + char_u *tofree = NULL; flags = EW_DIR; // include directories if (options & WILD_LIST_NOTFOUND) @@ -2115,6 +2117,17 @@ ExpandFromContext( if (xp->xp_context == EXPAND_PACKADD) return ExpandPackAddDir(pat, num_file, file); + // When expanding a function name starting with s:, match the nr_ + // prefix. + if (xp->xp_context == EXPAND_USER_FUNC && STRNCMP(pat, "^s:", 3) == 0) + { + int len = (int)STRLEN(pat) + 20; + + tofree = alloc(len); + snprintf((char *)tofree, len, "^\\d\\+_%s", pat + 3); + pat = tofree; + } + regmatch.regprog = vim_regcomp(pat, p_magic ? RE_MAGIC : 0); if (regmatch.regprog == NULL) return FAIL; @@ -2204,6 +2217,7 @@ ExpandFromContext( } vim_regfree(regmatch.regprog); + vim_free(tofree); return ret; } diff --git a/src/testdir/test_cmdline.vim b/src/testdir/test_cmdline.vim index 1baed7961f..8c580262ac 100644 --- a/src/testdir/test_cmdline.vim +++ b/src/testdir/test_cmdline.vim @@ -559,6 +559,17 @@ func Test_cmdline_complete_user_cmd() delcommand Foo endfunc +func s:ScriptLocalFunction() + echo 'yes' +endfunc + +func Test_cmdline_complete_user_func() + call feedkeys(":func Test_cmdline_complete_user\\\"\", 'tx') + call assert_match('"func Test_cmdline_complete_user', @:) + call feedkeys(":func s:ScriptL\\\"\", 'tx') + call assert_match('"func \d\+_ScriptLocalFunction', @:) +endfunc + func Test_cmdline_complete_user_names() if has('unix') && executable('whoami') let whoami = systemlist('whoami')[0] diff --git a/src/version.c b/src/version.c index 4dc9642a5c..23c45082c7 100644 --- a/src/version.c +++ b/src/version.c @@ -738,6 +738,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 335, /**/ 334, /**/ From 42a480bf7243ea8bce498264911e187931d083e5 Mon Sep 17 00:00:00 2001 From: Bram Moolenaar Date: Sat, 29 Feb 2020 23:23:47 +0100 Subject: [PATCH 16/63] patch 8.2.0336: Vim9: insufficient test coverage for compiling Problem: Vim9: insufficient test coverage for compiling. Solution: Add more tests. --- src/testdir/test_vim9_expr.vim | 8 ++++ src/testdir/test_vim9_script.vim | 25 +++++++++++ src/version.c | 2 + src/vim9.h | 22 ++++++---- src/vim9compile.c | 75 +++++++++++++++++++++++++++++--- src/vim9execute.c | 57 ++++++++++++++++++++++++ 6 files changed, 176 insertions(+), 13 deletions(-) diff --git a/src/testdir/test_vim9_expr.vim b/src/testdir/test_vim9_expr.vim index 5ece65274b..1ec3c6f1b0 100644 --- a/src/testdir/test_vim9_expr.vim +++ b/src/testdir/test_vim9_expr.vim @@ -9,6 +9,12 @@ func CheckDefFailure(line, error) 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') @@ -805,6 +811,8 @@ func Test_expr7_fails() 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:') endfunc let g:Funcrefs = [function('add')] diff --git a/src/testdir/test_vim9_script.vim b/src/testdir/test_vim9_script.vim index f1b21d45e3..ac8bd7512f 100644 --- a/src/testdir/test_vim9_script.vim +++ b/src/testdir/test_vim9_script.vim @@ -53,6 +53,10 @@ def Test_assignment() let dict4: dict = #{one: 1, two: '2'} let dict5: dict = #{one: 0z01, tw: 0z02} + if has('channel') + let chan1: channel + endif + g:newvar = 'new' assert_equal('new', g:newvar) @@ -91,6 +95,21 @@ func Test_assignment_failure() call CheckDefFailure(['let var = feedkeys("0")'], 'E1031:') call CheckDefFailure(['let var: number = feedkeys("0")'], 'expected number but got void') + + call CheckDefFailure(['let var: dict '], 'E1007:') + call CheckDefFailure(['let var: dictisn_arg.channel = channel; + + return OK; +} + +/* + * Generate an ISN_PUSHJOB instruction. + * Consumes "job". + */ + static int +generate_PUSHJOB(cctx_T *cctx, job_T *job) +{ + isn_T *isn; + + if ((isn = generate_instr_type(cctx, ISN_PUSHCHANNEL, &t_channel)) == NULL) + return FAIL; + isn->isn_arg.job = job; + + return OK; +} + /* * Generate an ISN_PUSHBLOB instruction. * Consumes "blob". @@ -657,6 +689,22 @@ generate_PUSHBLOB(cctx_T *cctx, blob_T *blob) return OK; } +/* + * Generate an ISN_PUSHFUNC instruction with name "name". + * Consumes "name". + */ + static int +generate_PUSHFUNC(cctx_T *cctx, char_u *name) +{ + isn_T *isn; + + if ((isn = generate_instr_type(cctx, ISN_PUSHFUNC, &t_func_void)) == NULL) + return FAIL; + isn->isn_arg.string = name; + + return OK; +} + /* * Generate an ISN_STORE instruction. */ @@ -3549,10 +3597,11 @@ compile_assignment(char_u *arg, exarg_T *eap, cmdidx_T cmdidx, cctx_T *cctx) generate_PUSHBLOB(cctx, NULL); break; case VAR_FUNC: - // generate_PUSHS(cctx, NULL); TODO + generate_PUSHFUNC(cctx, NULL); break; case VAR_PARTIAL: - // generate_PUSHS(cctx, NULL); TODO + // generate_PUSHPARTIAL(cctx, NULL); + emsg("Partial type not supported yet"); break; case VAR_LIST: generate_NEWLIST(cctx, 0); @@ -3561,10 +3610,10 @@ compile_assignment(char_u *arg, exarg_T *eap, cmdidx_T cmdidx, cctx_T *cctx) generate_NEWDICT(cctx, 0); break; case VAR_JOB: - // generate_PUSHS(cctx, NULL); TODO + generate_PUSHJOB(cctx, NULL); break; case VAR_CHANNEL: - // generate_PUSHS(cctx, NULL); TODO + generate_PUSHCHANNEL(cctx, NULL); break; case VAR_NUMBER: case VAR_UNKNOWN: @@ -4748,6 +4797,7 @@ compile_def_function(ufunc_T *ufunc, int set_return_type) int called_emsg_before = called_emsg; int ret = FAIL; sctx_T save_current_sctx = current_sctx; + int emsg_before = called_emsg; if (ufunc->uf_dfunc_idx >= 0) { @@ -4828,7 +4878,8 @@ compile_def_function(ufunc_T *ufunc, int set_return_type) ++line; else if (line != NULL && *line != NUL) { - semsg(_("E488: Trailing characters: %s"), line); + if (emsg_before == called_emsg) + semsg(_("E488: Trailing characters: %s"), line); goto erret; } else @@ -4844,6 +4895,7 @@ compile_def_function(ufunc_T *ufunc, int set_return_type) break; SOURCING_LNUM = ufunc->uf_script_ctx.sc_lnum + cctx.ctx_lnum + 1; } + emsg_before = called_emsg; had_return = FALSE; vim_memset(&ea, 0, sizeof(ea)); @@ -5153,6 +5205,7 @@ delete_instr(isn_T *isn) case ISN_PUSHS: case ISN_STOREENV: case ISN_STOREG: + case ISN_PUSHFUNC: vim_free(isn->isn_arg.string); break; @@ -5169,6 +5222,18 @@ delete_instr(isn_T *isn) blob_unref(isn->isn_arg.blob); break; + case ISN_PUSHPARTIAL: + // TODO + break; + + case ISN_PUSHJOB: + job_unref(isn->isn_arg.job); + break; + + case ISN_PUSHCHANNEL: + channel_unref(isn->isn_arg.channel); + break; + case ISN_UCALL: vim_free(isn->isn_arg.ufunc.cuf_name); break; diff --git a/src/vim9execute.c b/src/vim9execute.c index 5c5fcb1573..9d187c4b44 100644 --- a/src/vim9execute.c +++ b/src/vim9execute.c @@ -840,6 +840,10 @@ call_def_function( case ISN_PUSHF: case ISN_PUSHS: case ISN_PUSHBLOB: + case ISN_PUSHFUNC: + case ISN_PUSHPARTIAL: + case ISN_PUSHCHANNEL: + case ISN_PUSHJOB: if (ga_grow(&ectx.ec_stack, 1) == FAIL) goto failed; tv = STACK_TV_BOT(0); @@ -867,6 +871,29 @@ call_def_function( case ISN_PUSHBLOB: blob_copy(iptr->isn_arg.blob, tv); break; + case ISN_PUSHFUNC: + tv->v_type = VAR_FUNC; + tv->vval.v_string = vim_strsave(iptr->isn_arg.string); + break; + case ISN_PUSHPARTIAL: + tv->v_type = VAR_UNKNOWN; + break; + case ISN_PUSHCHANNEL: +#ifdef FEAT_JOB_CHANNEL + tv->v_type = VAR_CHANNEL; + tv->vval.v_channel = iptr->isn_arg.channel; + if (tv->vval.v_channel != NULL) + ++tv->vval.v_channel->ch_refcount; +#endif + break; + case ISN_PUSHJOB: +#ifdef FEAT_JOB_CHANNEL + tv->v_type = VAR_JOB; + tv->vval.v_job = iptr->isn_arg.job; + if (tv->vval.v_job != NULL) + ++tv->vval.v_job->jv_refcount; +#endif + break; default: tv->v_type = VAR_STRING; tv->vval.v_string = vim_strsave(iptr->isn_arg.string); @@ -1846,6 +1873,36 @@ ex_disassemble(exarg_T *eap) vim_free(tofree); } break; + case ISN_PUSHFUNC: + smsg("%4d PUSHFUNC \"%s\"", current, iptr->isn_arg.string); + break; + case ISN_PUSHPARTIAL: + // TODO + smsg("%4d PUSHPARTIAL", current); + break; + case ISN_PUSHCHANNEL: +#ifdef FEAT_JOB_CHANNEL + { + channel_T *channel = iptr->isn_arg.channel; + + smsg("%4d PUSHCHANNEL %d", current, + channel == NULL ? 0 : channel->ch_id); + } +#endif + break; + case ISN_PUSHJOB: +#ifdef FEAT_JOB_CHANNEL + { + typval_T tv; + char_u *name; + + tv.v_type = VAR_JOB; + tv.vval.v_job = iptr->isn_arg.job; + name = tv_get_string(&tv); + smsg("%4d PUSHJOB %s", current, name); + } +#endif + break; case ISN_PUSHEXC: smsg("%4d PUSH v:exception", current); break; From b54b8e0c86b0590394803157818c72412a6f0b6a Mon Sep 17 00:00:00 2001 From: Bram Moolenaar Date: Sun, 1 Mar 2020 01:05:53 +0100 Subject: [PATCH 17/63] patch 8.2.0337: build fails on a few systems Problem: Build fails on a few systems. Solution: Use vim_snprintf() instead of snprintf(). --- src/cmdexpand.c | 2 +- src/version.c | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/src/cmdexpand.c b/src/cmdexpand.c index ece5a468b1..1f70dc58e4 100644 --- a/src/cmdexpand.c +++ b/src/cmdexpand.c @@ -2124,7 +2124,7 @@ ExpandFromContext( int len = (int)STRLEN(pat) + 20; tofree = alloc(len); - snprintf((char *)tofree, len, "^\\d\\+_%s", pat + 3); + vim_snprintf((char *)tofree, len, "^\\d\\+_%s", pat + 3); pat = tofree; } diff --git a/src/version.c b/src/version.c index 06b9511816..6c519cb345 100644 --- a/src/version.c +++ b/src/version.c @@ -738,6 +738,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 337, /**/ 336, /**/ From f4f190d8219fc93c6e58e54ce7c1ac15af07840f Mon Sep 17 00:00:00 2001 From: Bram Moolenaar Date: Sun, 1 Mar 2020 13:01:16 +0100 Subject: [PATCH 18/63] patch 8.2.0338: build failure without the channel feature Problem: Build failure without the channel feature. Solution: Add #ifdef --- src/version.c | 2 ++ src/vim9compile.c | 4 ++++ 2 files changed, 6 insertions(+) diff --git a/src/version.c b/src/version.c index 6c519cb345..cd410bfed3 100644 --- a/src/version.c +++ b/src/version.c @@ -738,6 +738,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 338, /**/ 337, /**/ diff --git a/src/vim9compile.c b/src/vim9compile.c index a4525ca0c1..2e0c2ffa84 100644 --- a/src/vim9compile.c +++ b/src/vim9compile.c @@ -5227,11 +5227,15 @@ delete_instr(isn_T *isn) break; case ISN_PUSHJOB: +#ifdef FEAT_JOB_CHANNEL job_unref(isn->isn_arg.job); +#endif break; case ISN_PUSHCHANNEL: +#ifdef FEAT_JOB_CHANNEL channel_unref(isn->isn_arg.channel); +#endif break; case ISN_UCALL: From fbdd08ed9b1798885915c7f27c94786906d258e4 Mon Sep 17 00:00:00 2001 From: Bram Moolenaar Date: Sun, 1 Mar 2020 14:04:46 +0100 Subject: [PATCH 19/63] patch 8.2.0339: Vim9: function return type may depend on arguments Problem: Vim9: function return type may depend on arguments. Solution: Instead of a fixed return type use a function to figure out the return type. --- src/evalbuffer.c | 6 + src/evalfunc.c | 1084 ++++++++++++++++-------------- src/proto/evalbuffer.pro | 1 + src/proto/evalfunc.pro | 2 +- src/testdir/test_vim9_script.vim | 5 + src/version.c | 2 + src/vim9compile.c | 9 +- 7 files changed, 609 insertions(+), 500 deletions(-) diff --git a/src/evalbuffer.c b/src/evalbuffer.c index d44fb10180..de6af6ad13 100644 --- a/src/evalbuffer.c +++ b/src/evalbuffer.c @@ -752,6 +752,12 @@ f_getbufline(typval_T *argvars, typval_T *rettv) get_buffer_lines(buf, lnum, end, TRUE, rettv); } + type_T * +ret_f_getline(int argcount, type_T **argtypes UNUSED) +{ + return argcount == 1 ? &t_string : &t_list_string; +} + /* * "getline(lnum, [end])" function */ diff --git a/src/evalfunc.c b/src/evalfunc.c index 39e347ad20..363ac69492 100644 --- a/src/evalfunc.c +++ b/src/evalfunc.c @@ -264,6 +264,91 @@ static void f_windowsversion(typval_T *argvars, typval_T *rettv); static void f_wordcount(typval_T *argvars, typval_T *rettv); static void f_xor(typval_T *argvars, typval_T *rettv); + + static type_T * +ret_void(int argcount UNUSED, type_T **argtypes UNUSED) +{ + return &t_void; +} + static type_T * +ret_any(int argcount UNUSED, type_T **argtypes UNUSED) +{ + return &t_any; +} + static type_T * +ret_number(int argcount UNUSED, type_T **argtypes UNUSED) +{ + return &t_number; +} + static type_T * +ret_float(int argcount UNUSED, type_T **argtypes UNUSED) +{ + return &t_float; +} + static type_T * +ret_string(int argcount UNUSED, type_T **argtypes UNUSED) +{ + return &t_string; +} + static type_T * ret_list_any(int argcount UNUSED, type_T **argtypes UNUSED) +{ + return &t_list_any; +} + static type_T * +ret_list_number(int argcount UNUSED, type_T **argtypes UNUSED) +{ + return &t_list_number; +} + static type_T * +ret_list_string(int argcount UNUSED, type_T **argtypes UNUSED) +{ + return &t_list_string; +} + static type_T * +ret_list_dict_any(int argcount UNUSED, type_T **argtypes UNUSED) +{ + return &t_list_dict_any; +} + static type_T * +ret_dict_any(int argcount UNUSED, type_T **argtypes UNUSED) +{ + return &t_dict_any; +} + static type_T * +ret_dict_number(int argcount UNUSED, type_T **argtypes UNUSED) +{ + return &t_dict_number; +} + static type_T * +ret_dict_string(int argcount UNUSED, type_T **argtypes UNUSED) +{ + return &t_dict_string; +} + static type_T * +ret_blob(int argcount UNUSED, type_T **argtypes UNUSED) +{ + return &t_blob; +} + static type_T * +ret_partial_void(int argcount UNUSED, type_T **argtypes UNUSED) +{ + return &t_partial_void; +} +#ifdef FEAT_JOB_CHANNEL + static type_T * +ret_channel(int argcount UNUSED, type_T **argtypes UNUSED) +{ + return &t_channel; +} + static type_T * +ret_job(int argcount UNUSED, type_T **argtypes UNUSED) +{ + return &t_job; +} +#endif + +static type_T *ret_f_function(int argcount, type_T **argtypes); + /* * Array with names and number of arguments of all internal functions * MUST BE KEPT SORTED IN strcmp() ORDER FOR BINARY SEARCH! @@ -274,7 +359,8 @@ typedef struct char f_min_argc; // minimal number of arguments char f_max_argc; // maximal number of arguments char f_argtype; // for method: FEARG_ values - type_T *f_rettype; // return type + type_T *(*f_retfunc)(int argcount, type_T **argtypes); + // return type function void (*f_func)(typval_T *args, typval_T *rvar); // implementation of function } funcentry_T; @@ -289,585 +375,585 @@ typedef struct static funcentry_T global_functions[] = { #ifdef FEAT_FLOAT - {"abs", 1, 1, FEARG_1, &t_any, f_abs}, - {"acos", 1, 1, FEARG_1, &t_float, f_acos}, // WJMc + {"abs", 1, 1, FEARG_1, ret_any, f_abs}, + {"acos", 1, 1, FEARG_1, ret_float, f_acos}, // WJMc #endif - {"add", 2, 2, FEARG_1, &t_any, f_add}, - {"and", 2, 2, FEARG_1, &t_number, f_and}, - {"append", 2, 2, FEARG_LAST, &t_number, f_append}, - {"appendbufline", 3, 3, FEARG_LAST, &t_number, f_appendbufline}, - {"argc", 0, 1, 0, &t_number, f_argc}, - {"argidx", 0, 0, 0, &t_number, f_argidx}, - {"arglistid", 0, 2, 0, &t_number, f_arglistid}, - {"argv", 0, 2, 0, &t_any, f_argv}, + {"add", 2, 2, FEARG_1, ret_any, f_add}, + {"and", 2, 2, FEARG_1, ret_number, f_and}, + {"append", 2, 2, FEARG_LAST, ret_number, f_append}, + {"appendbufline", 3, 3, FEARG_LAST, ret_number, f_appendbufline}, + {"argc", 0, 1, 0, ret_number, f_argc}, + {"argidx", 0, 0, 0, ret_number, f_argidx}, + {"arglistid", 0, 2, 0, ret_number, f_arglistid}, + {"argv", 0, 2, 0, ret_any, f_argv}, #ifdef FEAT_FLOAT - {"asin", 1, 1, FEARG_1, &t_float, f_asin}, // WJMc + {"asin", 1, 1, FEARG_1, ret_float, f_asin}, // WJMc #endif - {"assert_beeps", 1, 2, FEARG_1, &t_number, f_assert_beeps}, - {"assert_equal", 2, 3, FEARG_2, &t_number, f_assert_equal}, - {"assert_equalfile", 2, 2, FEARG_1, &t_number, f_assert_equalfile}, - {"assert_exception", 1, 2, 0, &t_number, f_assert_exception}, - {"assert_fails", 1, 3, FEARG_1, &t_number, f_assert_fails}, - {"assert_false", 1, 2, FEARG_1, &t_number, f_assert_false}, - {"assert_inrange", 3, 4, FEARG_3, &t_number, f_assert_inrange}, - {"assert_match", 2, 3, FEARG_2, &t_number, f_assert_match}, - {"assert_notequal", 2, 3, FEARG_2, &t_number, f_assert_notequal}, - {"assert_notmatch", 2, 3, FEARG_2, &t_number, f_assert_notmatch}, - {"assert_report", 1, 1, FEARG_1, &t_number, f_assert_report}, - {"assert_true", 1, 2, FEARG_1, &t_number, f_assert_true}, + {"assert_beeps", 1, 2, FEARG_1, ret_number, f_assert_beeps}, + {"assert_equal", 2, 3, FEARG_2, ret_number, f_assert_equal}, + {"assert_equalfile", 2, 2, FEARG_1, ret_number, f_assert_equalfile}, + {"assert_exception", 1, 2, 0, ret_number, f_assert_exception}, + {"assert_fails", 1, 3, FEARG_1, ret_number, f_assert_fails}, + {"assert_false", 1, 2, FEARG_1, ret_number, f_assert_false}, + {"assert_inrange", 3, 4, FEARG_3, ret_number, f_assert_inrange}, + {"assert_match", 2, 3, FEARG_2, ret_number, f_assert_match}, + {"assert_notequal", 2, 3, FEARG_2, ret_number, f_assert_notequal}, + {"assert_notmatch", 2, 3, FEARG_2, ret_number, f_assert_notmatch}, + {"assert_report", 1, 1, FEARG_1, ret_number, f_assert_report}, + {"assert_true", 1, 2, FEARG_1, ret_number, f_assert_true}, #ifdef FEAT_FLOAT - {"atan", 1, 1, FEARG_1, &t_float, f_atan}, - {"atan2", 2, 2, FEARG_1, &t_float, f_atan2}, + {"atan", 1, 1, FEARG_1, ret_float, f_atan}, + {"atan2", 2, 2, FEARG_1, ret_float, f_atan2}, #endif #ifdef FEAT_BEVAL - {"balloon_gettext", 0, 0, 0, &t_string, f_balloon_gettext}, - {"balloon_show", 1, 1, FEARG_1, &t_void, f_balloon_show}, + {"balloon_gettext", 0, 0, 0, ret_string, f_balloon_gettext}, + {"balloon_show", 1, 1, FEARG_1, ret_void, f_balloon_show}, # if defined(FEAT_BEVAL_TERM) - {"balloon_split", 1, 1, FEARG_1, &t_list_string, f_balloon_split}, + {"balloon_split", 1, 1, FEARG_1, ret_list_string, f_balloon_split}, # endif #endif - {"browse", 4, 4, 0, &t_string, f_browse}, - {"browsedir", 2, 2, 0, &t_string, f_browsedir}, - {"bufadd", 1, 1, FEARG_1, &t_number, f_bufadd}, - {"bufexists", 1, 1, FEARG_1, &t_number, f_bufexists}, - {"buffer_exists", 1, 1, FEARG_1, &t_number, f_bufexists}, // obsolete - {"buffer_name", 0, 1, FEARG_1, &t_string, f_bufname}, // obsolete - {"buffer_number", 0, 1, FEARG_1, &t_number, f_bufnr}, // obsolete - {"buflisted", 1, 1, FEARG_1, &t_number, f_buflisted}, - {"bufload", 1, 1, FEARG_1, &t_void, f_bufload}, - {"bufloaded", 1, 1, FEARG_1, &t_number, f_bufloaded}, - {"bufname", 0, 1, FEARG_1, &t_string, f_bufname}, - {"bufnr", 0, 2, FEARG_1, &t_number, f_bufnr}, - {"bufwinid", 1, 1, FEARG_1, &t_number, f_bufwinid}, - {"bufwinnr", 1, 1, FEARG_1, &t_number, f_bufwinnr}, - {"byte2line", 1, 1, FEARG_1, &t_number, f_byte2line}, - {"byteidx", 2, 2, FEARG_1, &t_number, f_byteidx}, - {"byteidxcomp", 2, 2, FEARG_1, &t_number, f_byteidxcomp}, - {"call", 2, 3, FEARG_1, &t_any, f_call}, + {"browse", 4, 4, 0, ret_string, f_browse}, + {"browsedir", 2, 2, 0, ret_string, f_browsedir}, + {"bufadd", 1, 1, FEARG_1, ret_number, f_bufadd}, + {"bufexists", 1, 1, FEARG_1, ret_number, f_bufexists}, + {"buffer_exists", 1, 1, FEARG_1, ret_number, f_bufexists}, // obsolete + {"buffer_name", 0, 1, FEARG_1, ret_string, f_bufname}, // obsolete + {"buffer_number", 0, 1, FEARG_1, ret_number, f_bufnr}, // obsolete + {"buflisted", 1, 1, FEARG_1, ret_number, f_buflisted}, + {"bufload", 1, 1, FEARG_1, ret_void, f_bufload}, + {"bufloaded", 1, 1, FEARG_1, ret_number, f_bufloaded}, + {"bufname", 0, 1, FEARG_1, ret_string, f_bufname}, + {"bufnr", 0, 2, FEARG_1, ret_number, f_bufnr}, + {"bufwinid", 1, 1, FEARG_1, ret_number, f_bufwinid}, + {"bufwinnr", 1, 1, FEARG_1, ret_number, f_bufwinnr}, + {"byte2line", 1, 1, FEARG_1, ret_number, f_byte2line}, + {"byteidx", 2, 2, FEARG_1, ret_number, f_byteidx}, + {"byteidxcomp", 2, 2, FEARG_1, ret_number, f_byteidxcomp}, + {"call", 2, 3, FEARG_1, ret_any, f_call}, #ifdef FEAT_FLOAT - {"ceil", 1, 1, FEARG_1, &t_float, f_ceil}, + {"ceil", 1, 1, FEARG_1, ret_float, f_ceil}, #endif #ifdef FEAT_JOB_CHANNEL - {"ch_canread", 1, 1, FEARG_1, &t_number, f_ch_canread}, - {"ch_close", 1, 1, FEARG_1, &t_void, f_ch_close}, - {"ch_close_in", 1, 1, FEARG_1, &t_void, f_ch_close_in}, - {"ch_evalexpr", 2, 3, FEARG_1, &t_any, f_ch_evalexpr}, - {"ch_evalraw", 2, 3, FEARG_1, &t_any, f_ch_evalraw}, - {"ch_getbufnr", 2, 2, FEARG_1, &t_number, f_ch_getbufnr}, - {"ch_getjob", 1, 1, FEARG_1, &t_job, f_ch_getjob}, - {"ch_info", 1, 1, FEARG_1, &t_dict_any, f_ch_info}, - {"ch_log", 1, 2, FEARG_1, &t_void, f_ch_log}, - {"ch_logfile", 1, 2, FEARG_1, &t_void, f_ch_logfile}, - {"ch_open", 1, 2, FEARG_1, &t_channel, f_ch_open}, - {"ch_read", 1, 2, FEARG_1, &t_string, f_ch_read}, - {"ch_readblob", 1, 2, FEARG_1, &t_blob, f_ch_readblob}, - {"ch_readraw", 1, 2, FEARG_1, &t_string, f_ch_readraw}, - {"ch_sendexpr", 2, 3, FEARG_1, &t_void, f_ch_sendexpr}, - {"ch_sendraw", 2, 3, FEARG_1, &t_void, f_ch_sendraw}, - {"ch_setoptions", 2, 2, FEARG_1, &t_void, f_ch_setoptions}, - {"ch_status", 1, 2, FEARG_1, &t_string, f_ch_status}, + {"ch_canread", 1, 1, FEARG_1, ret_number, f_ch_canread}, + {"ch_close", 1, 1, FEARG_1, ret_void, f_ch_close}, + {"ch_close_in", 1, 1, FEARG_1, ret_void, f_ch_close_in}, + {"ch_evalexpr", 2, 3, FEARG_1, ret_any, f_ch_evalexpr}, + {"ch_evalraw", 2, 3, FEARG_1, ret_any, f_ch_evalraw}, + {"ch_getbufnr", 2, 2, FEARG_1, ret_number, f_ch_getbufnr}, + {"ch_getjob", 1, 1, FEARG_1, ret_job, f_ch_getjob}, + {"ch_info", 1, 1, FEARG_1, ret_dict_any, f_ch_info}, + {"ch_log", 1, 2, FEARG_1, ret_void, f_ch_log}, + {"ch_logfile", 1, 2, FEARG_1, ret_void, f_ch_logfile}, + {"ch_open", 1, 2, FEARG_1, ret_channel, f_ch_open}, + {"ch_read", 1, 2, FEARG_1, ret_string, f_ch_read}, + {"ch_readblob", 1, 2, FEARG_1, ret_blob, f_ch_readblob}, + {"ch_readraw", 1, 2, FEARG_1, ret_string, f_ch_readraw}, + {"ch_sendexpr", 2, 3, FEARG_1, ret_void, f_ch_sendexpr}, + {"ch_sendraw", 2, 3, FEARG_1, ret_void, f_ch_sendraw}, + {"ch_setoptions", 2, 2, FEARG_1, ret_void, f_ch_setoptions}, + {"ch_status", 1, 2, FEARG_1, ret_string, f_ch_status}, #endif - {"changenr", 0, 0, 0, &t_number, f_changenr}, - {"char2nr", 1, 2, FEARG_1, &t_number, f_char2nr}, - {"chdir", 1, 1, FEARG_1, &t_string, f_chdir}, - {"cindent", 1, 1, FEARG_1, &t_number, f_cindent}, - {"clearmatches", 0, 1, FEARG_1, &t_void, f_clearmatches}, - {"col", 1, 1, FEARG_1, &t_number, f_col}, - {"complete", 2, 2, FEARG_2, &t_void, f_complete}, - {"complete_add", 1, 1, FEARG_1, &t_number, f_complete_add}, - {"complete_check", 0, 0, 0, &t_number, f_complete_check}, - {"complete_info", 0, 1, FEARG_1, &t_dict_any, f_complete_info}, - {"confirm", 1, 4, FEARG_1, &t_number, f_confirm}, - {"copy", 1, 1, FEARG_1, &t_any, f_copy}, + {"changenr", 0, 0, 0, ret_number, f_changenr}, + {"char2nr", 1, 2, FEARG_1, ret_number, f_char2nr}, + {"chdir", 1, 1, FEARG_1, ret_string, f_chdir}, + {"cindent", 1, 1, FEARG_1, ret_number, f_cindent}, + {"clearmatches", 0, 1, FEARG_1, ret_void, f_clearmatches}, + {"col", 1, 1, FEARG_1, ret_number, f_col}, + {"complete", 2, 2, FEARG_2, ret_void, f_complete}, + {"complete_add", 1, 1, FEARG_1, ret_number, f_complete_add}, + {"complete_check", 0, 0, 0, ret_number, f_complete_check}, + {"complete_info", 0, 1, FEARG_1, ret_dict_any, f_complete_info}, + {"confirm", 1, 4, FEARG_1, ret_number, f_confirm}, + {"copy", 1, 1, FEARG_1, ret_any, f_copy}, #ifdef FEAT_FLOAT - {"cos", 1, 1, FEARG_1, &t_float, f_cos}, - {"cosh", 1, 1, FEARG_1, &t_float, f_cosh}, + {"cos", 1, 1, FEARG_1, ret_float, f_cos}, + {"cosh", 1, 1, FEARG_1, ret_float, f_cosh}, #endif - {"count", 2, 4, FEARG_1, &t_number, f_count}, - {"cscope_connection",0,3, 0, &t_number, f_cscope_connection}, - {"cursor", 1, 3, FEARG_1, &t_number, f_cursor}, + {"count", 2, 4, FEARG_1, ret_number, f_count}, + {"cscope_connection",0,3, 0, ret_number, f_cscope_connection}, + {"cursor", 1, 3, FEARG_1, ret_number, f_cursor}, #ifdef MSWIN - {"debugbreak", 1, 1, FEARG_1, &t_number, f_debugbreak}, + {"debugbreak", 1, 1, FEARG_1, ret_number, f_debugbreak}, #endif - {"deepcopy", 1, 2, FEARG_1, &t_any, f_deepcopy}, - {"delete", 1, 2, FEARG_1, &t_number, f_delete}, - {"deletebufline", 2, 3, FEARG_1, &t_number, f_deletebufline}, - {"did_filetype", 0, 0, 0, &t_number, f_did_filetype}, - {"diff_filler", 1, 1, FEARG_1, &t_number, f_diff_filler}, - {"diff_hlID", 2, 2, FEARG_1, &t_number, f_diff_hlID}, - {"echoraw", 1, 1, FEARG_1, &t_number, f_echoraw}, - {"empty", 1, 1, FEARG_1, &t_number, f_empty}, - {"environ", 0, 0, 0, &t_dict_string, f_environ}, - {"escape", 2, 2, FEARG_1, &t_string, f_escape}, - {"eval", 1, 1, FEARG_1, &t_any, f_eval}, - {"eventhandler", 0, 0, 0, &t_number, f_eventhandler}, - {"executable", 1, 1, FEARG_1, &t_number, f_executable}, - {"execute", 1, 2, FEARG_1, &t_string, f_execute}, - {"exepath", 1, 1, FEARG_1, &t_string, f_exepath}, - {"exists", 1, 1, FEARG_1, &t_number, f_exists}, + {"deepcopy", 1, 2, FEARG_1, ret_any, f_deepcopy}, + {"delete", 1, 2, FEARG_1, ret_number, f_delete}, + {"deletebufline", 2, 3, FEARG_1, ret_number, f_deletebufline}, + {"did_filetype", 0, 0, 0, ret_number, f_did_filetype}, + {"diff_filler", 1, 1, FEARG_1, ret_number, f_diff_filler}, + {"diff_hlID", 2, 2, FEARG_1, ret_number, f_diff_hlID}, + {"echoraw", 1, 1, FEARG_1, ret_number, f_echoraw}, + {"empty", 1, 1, FEARG_1, ret_number, f_empty}, + {"environ", 0, 0, 0, ret_dict_string, f_environ}, + {"escape", 2, 2, FEARG_1, ret_string, f_escape}, + {"eval", 1, 1, FEARG_1, ret_any, f_eval}, + {"eventhandler", 0, 0, 0, ret_number, f_eventhandler}, + {"executable", 1, 1, FEARG_1, ret_number, f_executable}, + {"execute", 1, 2, FEARG_1, ret_string, f_execute}, + {"exepath", 1, 1, FEARG_1, ret_string, f_exepath}, + {"exists", 1, 1, FEARG_1, ret_number, f_exists}, #ifdef FEAT_FLOAT - {"exp", 1, 1, FEARG_1, &t_float, f_exp}, + {"exp", 1, 1, FEARG_1, ret_float, f_exp}, #endif - {"expand", 1, 3, FEARG_1, &t_any, f_expand}, - {"expandcmd", 1, 1, FEARG_1, &t_string, f_expandcmd}, - {"extend", 2, 3, FEARG_1, &t_any, f_extend}, - {"feedkeys", 1, 2, FEARG_1, &t_void, f_feedkeys}, - {"file_readable", 1, 1, FEARG_1, &t_number, f_filereadable}, // obsolete - {"filereadable", 1, 1, FEARG_1, &t_number, f_filereadable}, - {"filewritable", 1, 1, FEARG_1, &t_number, f_filewritable}, - {"filter", 2, 2, FEARG_1, &t_any, f_filter}, - {"finddir", 1, 3, FEARG_1, &t_string, f_finddir}, - {"findfile", 1, 3, FEARG_1, &t_string, f_findfile}, + {"expand", 1, 3, FEARG_1, ret_any, f_expand}, + {"expandcmd", 1, 1, FEARG_1, ret_string, f_expandcmd}, + {"extend", 2, 3, FEARG_1, ret_any, f_extend}, + {"feedkeys", 1, 2, FEARG_1, ret_void, f_feedkeys}, + {"file_readable", 1, 1, FEARG_1, ret_number, f_filereadable}, // obsolete + {"filereadable", 1, 1, FEARG_1, ret_number, f_filereadable}, + {"filewritable", 1, 1, FEARG_1, ret_number, f_filewritable}, + {"filter", 2, 2, FEARG_1, ret_any, f_filter}, + {"finddir", 1, 3, FEARG_1, ret_string, f_finddir}, + {"findfile", 1, 3, FEARG_1, ret_string, f_findfile}, #ifdef FEAT_FLOAT - {"float2nr", 1, 1, FEARG_1, &t_number, f_float2nr}, - {"floor", 1, 1, FEARG_1, &t_float, f_floor}, - {"fmod", 2, 2, FEARG_1, &t_float, f_fmod}, + {"float2nr", 1, 1, FEARG_1, ret_number, f_float2nr}, + {"floor", 1, 1, FEARG_1, ret_float, f_floor}, + {"fmod", 2, 2, FEARG_1, ret_float, f_fmod}, #endif - {"fnameescape", 1, 1, FEARG_1, &t_string, f_fnameescape}, - {"fnamemodify", 2, 2, FEARG_1, &t_string, f_fnamemodify}, - {"foldclosed", 1, 1, FEARG_1, &t_number, f_foldclosed}, - {"foldclosedend", 1, 1, FEARG_1, &t_number, f_foldclosedend}, - {"foldlevel", 1, 1, FEARG_1, &t_number, f_foldlevel}, - {"foldtext", 0, 0, 0, &t_string, f_foldtext}, - {"foldtextresult", 1, 1, FEARG_1, &t_string, f_foldtextresult}, - {"foreground", 0, 0, 0, &t_void, f_foreground}, - {"funcref", 1, 3, FEARG_1, &t_any, f_funcref}, - {"function", 1, 3, FEARG_1, &t_any, f_function}, - {"garbagecollect", 0, 1, 0, &t_void, f_garbagecollect}, - {"get", 2, 3, FEARG_1, &t_any, f_get}, - {"getbufinfo", 0, 1, 0, &t_list_dict_any, f_getbufinfo}, - {"getbufline", 2, 3, FEARG_1, &t_list_string, f_getbufline}, - {"getbufvar", 2, 3, FEARG_1, &t_any, f_getbufvar}, - {"getchangelist", 0, 1, FEARG_1, &t_list_any, f_getchangelist}, - {"getchar", 0, 1, 0, &t_number, f_getchar}, - {"getcharmod", 0, 0, 0, &t_number, f_getcharmod}, - {"getcharsearch", 0, 0, 0, &t_dict_any, f_getcharsearch}, - {"getcmdline", 0, 0, 0, &t_string, f_getcmdline}, - {"getcmdpos", 0, 0, 0, &t_number, f_getcmdpos}, - {"getcmdtype", 0, 0, 0, &t_string, f_getcmdtype}, - {"getcmdwintype", 0, 0, 0, &t_string, f_getcmdwintype}, - {"getcompletion", 2, 3, FEARG_1, &t_list_string, f_getcompletion}, - {"getcurpos", 0, 0, 0, &t_list_number, f_getcurpos}, - {"getcwd", 0, 2, FEARG_1, &t_string, f_getcwd}, - {"getenv", 1, 1, FEARG_1, &t_string, f_getenv}, - {"getfontname", 0, 1, 0, &t_string, f_getfontname}, - {"getfperm", 1, 1, FEARG_1, &t_string, f_getfperm}, - {"getfsize", 1, 1, FEARG_1, &t_number, f_getfsize}, - {"getftime", 1, 1, FEARG_1, &t_number, f_getftime}, - {"getftype", 1, 1, FEARG_1, &t_string, f_getftype}, - {"getimstatus", 0, 0, 0, &t_number, f_getimstatus}, - {"getjumplist", 0, 2, FEARG_1, &t_list_any, f_getjumplist}, - {"getline", 1, 2, FEARG_1, &t_string, f_getline}, - {"getloclist", 1, 2, 0, &t_list_dict_any, f_getloclist}, - {"getmatches", 0, 1, 0, &t_list_dict_any, f_getmatches}, - {"getmousepos", 0, 0, 0, &t_dict_number, f_getmousepos}, - {"getpid", 0, 0, 0, &t_number, f_getpid}, - {"getpos", 1, 1, FEARG_1, &t_list_number, f_getpos}, - {"getqflist", 0, 1, 0, &t_list_dict_any, f_getqflist}, - {"getreg", 0, 3, FEARG_1, &t_string, f_getreg}, - {"getregtype", 0, 1, FEARG_1, &t_string, f_getregtype}, - {"gettabinfo", 0, 1, FEARG_1, &t_list_dict_any, f_gettabinfo}, - {"gettabvar", 2, 3, FEARG_1, &t_any, f_gettabvar}, - {"gettabwinvar", 3, 4, FEARG_1, &t_any, f_gettabwinvar}, - {"gettagstack", 0, 1, FEARG_1, &t_dict_any, f_gettagstack}, - {"getwininfo", 0, 1, FEARG_1, &t_list_dict_any, f_getwininfo}, - {"getwinpos", 0, 1, FEARG_1, &t_list_number, f_getwinpos}, - {"getwinposx", 0, 0, 0, &t_number, f_getwinposx}, - {"getwinposy", 0, 0, 0, &t_number, f_getwinposy}, - {"getwinvar", 2, 3, FEARG_1, &t_any, f_getwinvar}, - {"glob", 1, 4, FEARG_1, &t_any, f_glob}, - {"glob2regpat", 1, 1, FEARG_1, &t_string, f_glob2regpat}, - {"globpath", 2, 5, FEARG_2, &t_any, f_globpath}, - {"has", 1, 1, 0, &t_number, f_has}, - {"has_key", 2, 2, FEARG_1, &t_number, f_has_key}, - {"haslocaldir", 0, 2, FEARG_1, &t_number, f_haslocaldir}, - {"hasmapto", 1, 3, FEARG_1, &t_number, f_hasmapto}, - {"highlightID", 1, 1, FEARG_1, &t_number, f_hlID}, // obsolete - {"highlight_exists",1, 1, FEARG_1, &t_number, f_hlexists}, // obsolete - {"histadd", 2, 2, FEARG_2, &t_number, f_histadd}, - {"histdel", 1, 2, FEARG_1, &t_number, f_histdel}, - {"histget", 1, 2, FEARG_1, &t_string, f_histget}, - {"histnr", 1, 1, FEARG_1, &t_number, f_histnr}, - {"hlID", 1, 1, FEARG_1, &t_number, f_hlID}, - {"hlexists", 1, 1, FEARG_1, &t_number, f_hlexists}, - {"hostname", 0, 0, 0, &t_string, f_hostname}, - {"iconv", 3, 3, FEARG_1, &t_string, f_iconv}, - {"indent", 1, 1, FEARG_1, &t_number, f_indent}, - {"index", 2, 4, FEARG_1, &t_number, f_index}, - {"input", 1, 3, FEARG_1, &t_string, f_input}, - {"inputdialog", 1, 3, FEARG_1, &t_string, f_inputdialog}, - {"inputlist", 1, 1, FEARG_1, &t_number, f_inputlist}, - {"inputrestore", 0, 0, 0, &t_number, f_inputrestore}, - {"inputsave", 0, 0, 0, &t_number, f_inputsave}, - {"inputsecret", 1, 2, FEARG_1, &t_string, f_inputsecret}, - {"insert", 2, 3, FEARG_1, &t_any, f_insert}, - {"interrupt", 0, 0, 0, &t_void, f_interrupt}, - {"invert", 1, 1, FEARG_1, &t_number, f_invert}, - {"isdirectory", 1, 1, FEARG_1, &t_number, f_isdirectory}, + {"fnameescape", 1, 1, FEARG_1, ret_string, f_fnameescape}, + {"fnamemodify", 2, 2, FEARG_1, ret_string, f_fnamemodify}, + {"foldclosed", 1, 1, FEARG_1, ret_number, f_foldclosed}, + {"foldclosedend", 1, 1, FEARG_1, ret_number, f_foldclosedend}, + {"foldlevel", 1, 1, FEARG_1, ret_number, f_foldlevel}, + {"foldtext", 0, 0, 0, ret_string, f_foldtext}, + {"foldtextresult", 1, 1, FEARG_1, ret_string, f_foldtextresult}, + {"foreground", 0, 0, 0, ret_void, f_foreground}, + {"funcref", 1, 3, FEARG_1, ret_partial_void, f_funcref}, + {"function", 1, 3, FEARG_1, ret_f_function, f_function}, + {"garbagecollect", 0, 1, 0, ret_void, f_garbagecollect}, + {"get", 2, 3, FEARG_1, ret_any, f_get}, + {"getbufinfo", 0, 1, 0, ret_list_dict_any, f_getbufinfo}, + {"getbufline", 2, 3, FEARG_1, ret_list_string, f_getbufline}, + {"getbufvar", 2, 3, FEARG_1, ret_any, f_getbufvar}, + {"getchangelist", 0, 1, FEARG_1, ret_list_any, f_getchangelist}, + {"getchar", 0, 1, 0, ret_number, f_getchar}, + {"getcharmod", 0, 0, 0, ret_number, f_getcharmod}, + {"getcharsearch", 0, 0, 0, ret_dict_any, f_getcharsearch}, + {"getcmdline", 0, 0, 0, ret_string, f_getcmdline}, + {"getcmdpos", 0, 0, 0, ret_number, f_getcmdpos}, + {"getcmdtype", 0, 0, 0, ret_string, f_getcmdtype}, + {"getcmdwintype", 0, 0, 0, ret_string, f_getcmdwintype}, + {"getcompletion", 2, 3, FEARG_1, ret_list_string, f_getcompletion}, + {"getcurpos", 0, 0, 0, ret_list_number, f_getcurpos}, + {"getcwd", 0, 2, FEARG_1, ret_string, f_getcwd}, + {"getenv", 1, 1, FEARG_1, ret_string, f_getenv}, + {"getfontname", 0, 1, 0, ret_string, f_getfontname}, + {"getfperm", 1, 1, FEARG_1, ret_string, f_getfperm}, + {"getfsize", 1, 1, FEARG_1, ret_number, f_getfsize}, + {"getftime", 1, 1, FEARG_1, ret_number, f_getftime}, + {"getftype", 1, 1, FEARG_1, ret_string, f_getftype}, + {"getimstatus", 0, 0, 0, ret_number, f_getimstatus}, + {"getjumplist", 0, 2, FEARG_1, ret_list_any, f_getjumplist}, + {"getline", 1, 2, FEARG_1, ret_f_getline, f_getline}, + {"getloclist", 1, 2, 0, ret_list_dict_any, f_getloclist}, + {"getmatches", 0, 1, 0, ret_list_dict_any, f_getmatches}, + {"getmousepos", 0, 0, 0, ret_dict_number, f_getmousepos}, + {"getpid", 0, 0, 0, ret_number, f_getpid}, + {"getpos", 1, 1, FEARG_1, ret_list_number, f_getpos}, + {"getqflist", 0, 1, 0, ret_list_dict_any, f_getqflist}, + {"getreg", 0, 3, FEARG_1, ret_string, f_getreg}, + {"getregtype", 0, 1, FEARG_1, ret_string, f_getregtype}, + {"gettabinfo", 0, 1, FEARG_1, ret_list_dict_any, f_gettabinfo}, + {"gettabvar", 2, 3, FEARG_1, ret_any, f_gettabvar}, + {"gettabwinvar", 3, 4, FEARG_1, ret_any, f_gettabwinvar}, + {"gettagstack", 0, 1, FEARG_1, ret_dict_any, f_gettagstack}, + {"getwininfo", 0, 1, FEARG_1, ret_list_dict_any, f_getwininfo}, + {"getwinpos", 0, 1, FEARG_1, ret_list_number, f_getwinpos}, + {"getwinposx", 0, 0, 0, ret_number, f_getwinposx}, + {"getwinposy", 0, 0, 0, ret_number, f_getwinposy}, + {"getwinvar", 2, 3, FEARG_1, ret_any, f_getwinvar}, + {"glob", 1, 4, FEARG_1, ret_any, f_glob}, + {"glob2regpat", 1, 1, FEARG_1, ret_string, f_glob2regpat}, + {"globpath", 2, 5, FEARG_2, ret_any, f_globpath}, + {"has", 1, 1, 0, ret_number, f_has}, + {"has_key", 2, 2, FEARG_1, ret_number, f_has_key}, + {"haslocaldir", 0, 2, FEARG_1, ret_number, f_haslocaldir}, + {"hasmapto", 1, 3, FEARG_1, ret_number, f_hasmapto}, + {"highlightID", 1, 1, FEARG_1, ret_number, f_hlID}, // obsolete + {"highlight_exists",1, 1, FEARG_1, ret_number, f_hlexists}, // obsolete + {"histadd", 2, 2, FEARG_2, ret_number, f_histadd}, + {"histdel", 1, 2, FEARG_1, ret_number, f_histdel}, + {"histget", 1, 2, FEARG_1, ret_string, f_histget}, + {"histnr", 1, 1, FEARG_1, ret_number, f_histnr}, + {"hlID", 1, 1, FEARG_1, ret_number, f_hlID}, + {"hlexists", 1, 1, FEARG_1, ret_number, f_hlexists}, + {"hostname", 0, 0, 0, ret_string, f_hostname}, + {"iconv", 3, 3, FEARG_1, ret_string, f_iconv}, + {"indent", 1, 1, FEARG_1, ret_number, f_indent}, + {"index", 2, 4, FEARG_1, ret_number, f_index}, + {"input", 1, 3, FEARG_1, ret_string, f_input}, + {"inputdialog", 1, 3, FEARG_1, ret_string, f_inputdialog}, + {"inputlist", 1, 1, FEARG_1, ret_number, f_inputlist}, + {"inputrestore", 0, 0, 0, ret_number, f_inputrestore}, + {"inputsave", 0, 0, 0, ret_number, f_inputsave}, + {"inputsecret", 1, 2, FEARG_1, ret_string, f_inputsecret}, + {"insert", 2, 3, FEARG_1, ret_any, f_insert}, + {"interrupt", 0, 0, 0, ret_void, f_interrupt}, + {"invert", 1, 1, FEARG_1, ret_number, f_invert}, + {"isdirectory", 1, 1, FEARG_1, ret_number, f_isdirectory}, #if defined(FEAT_FLOAT) && defined(HAVE_MATH_H) - {"isinf", 1, 1, FEARG_1, &t_number, f_isinf}, + {"isinf", 1, 1, FEARG_1, ret_number, f_isinf}, #endif - {"islocked", 1, 1, FEARG_1, &t_number, f_islocked}, + {"islocked", 1, 1, FEARG_1, ret_number, f_islocked}, #if defined(FEAT_FLOAT) && defined(HAVE_MATH_H) - {"isnan", 1, 1, FEARG_1, &t_number, f_isnan}, + {"isnan", 1, 1, FEARG_1, ret_number, f_isnan}, #endif - {"items", 1, 1, FEARG_1, &t_list_any, f_items}, + {"items", 1, 1, FEARG_1, ret_list_any, f_items}, #ifdef FEAT_JOB_CHANNEL - {"job_getchannel", 1, 1, FEARG_1, &t_channel, f_job_getchannel}, - {"job_info", 0, 1, FEARG_1, &t_dict_any, f_job_info}, - {"job_setoptions", 2, 2, FEARG_1, &t_void, f_job_setoptions}, - {"job_start", 1, 2, FEARG_1, &t_job, f_job_start}, - {"job_status", 1, 1, FEARG_1, &t_string, f_job_status}, - {"job_stop", 1, 2, FEARG_1, &t_number, f_job_stop}, + {"job_getchannel", 1, 1, FEARG_1, ret_channel, f_job_getchannel}, + {"job_info", 0, 1, FEARG_1, ret_dict_any, f_job_info}, + {"job_setoptions", 2, 2, FEARG_1, ret_void, f_job_setoptions}, + {"job_start", 1, 2, FEARG_1, ret_job, f_job_start}, + {"job_status", 1, 1, FEARG_1, ret_string, f_job_status}, + {"job_stop", 1, 2, FEARG_1, ret_number, f_job_stop}, #endif - {"join", 1, 2, FEARG_1, &t_string, f_join}, - {"js_decode", 1, 1, FEARG_1, &t_any, f_js_decode}, - {"js_encode", 1, 1, FEARG_1, &t_string, f_js_encode}, - {"json_decode", 1, 1, FEARG_1, &t_any, f_json_decode}, - {"json_encode", 1, 1, FEARG_1, &t_string, f_json_encode}, - {"keys", 1, 1, FEARG_1, &t_list_any, f_keys}, - {"last_buffer_nr", 0, 0, 0, &t_number, f_last_buffer_nr}, // obsolete - {"len", 1, 1, FEARG_1, &t_number, f_len}, - {"libcall", 3, 3, FEARG_3, &t_string, f_libcall}, - {"libcallnr", 3, 3, FEARG_3, &t_number, f_libcallnr}, - {"line", 1, 2, FEARG_1, &t_number, f_line}, - {"line2byte", 1, 1, FEARG_1, &t_number, f_line2byte}, - {"lispindent", 1, 1, FEARG_1, &t_number, f_lispindent}, - {"list2str", 1, 2, FEARG_1, &t_string, f_list2str}, - {"listener_add", 1, 2, FEARG_2, &t_number, f_listener_add}, - {"listener_flush", 0, 1, FEARG_1, &t_void, f_listener_flush}, - {"listener_remove", 1, 1, FEARG_1, &t_number, f_listener_remove}, - {"localtime", 0, 0, 0, &t_number, f_localtime}, + {"join", 1, 2, FEARG_1, ret_string, f_join}, + {"js_decode", 1, 1, FEARG_1, ret_any, f_js_decode}, + {"js_encode", 1, 1, FEARG_1, ret_string, f_js_encode}, + {"json_decode", 1, 1, FEARG_1, ret_any, f_json_decode}, + {"json_encode", 1, 1, FEARG_1, ret_string, f_json_encode}, + {"keys", 1, 1, FEARG_1, ret_list_any, f_keys}, + {"last_buffer_nr", 0, 0, 0, ret_number, f_last_buffer_nr}, // obsolete + {"len", 1, 1, FEARG_1, ret_number, f_len}, + {"libcall", 3, 3, FEARG_3, ret_string, f_libcall}, + {"libcallnr", 3, 3, FEARG_3, ret_number, f_libcallnr}, + {"line", 1, 2, FEARG_1, ret_number, f_line}, + {"line2byte", 1, 1, FEARG_1, ret_number, f_line2byte}, + {"lispindent", 1, 1, FEARG_1, ret_number, f_lispindent}, + {"list2str", 1, 2, FEARG_1, ret_string, f_list2str}, + {"listener_add", 1, 2, FEARG_2, ret_number, f_listener_add}, + {"listener_flush", 0, 1, FEARG_1, ret_void, f_listener_flush}, + {"listener_remove", 1, 1, FEARG_1, ret_number, f_listener_remove}, + {"localtime", 0, 0, 0, ret_number, f_localtime}, #ifdef FEAT_FLOAT - {"log", 1, 1, FEARG_1, &t_float, f_log}, - {"log10", 1, 1, FEARG_1, &t_float, f_log10}, + {"log", 1, 1, FEARG_1, ret_float, f_log}, + {"log10", 1, 1, FEARG_1, ret_float, f_log10}, #endif #ifdef FEAT_LUA - {"luaeval", 1, 2, FEARG_1, &t_any, f_luaeval}, + {"luaeval", 1, 2, FEARG_1, ret_any, f_luaeval}, #endif - {"map", 2, 2, FEARG_1, &t_any, f_map}, - {"maparg", 1, 4, FEARG_1, &t_string, f_maparg}, - {"mapcheck", 1, 3, FEARG_1, &t_string, f_mapcheck}, - {"match", 2, 4, FEARG_1, &t_any, f_match}, - {"matchadd", 2, 5, FEARG_1, &t_number, f_matchadd}, - {"matchaddpos", 2, 5, FEARG_1, &t_number, f_matchaddpos}, - {"matcharg", 1, 1, FEARG_1, &t_list_string, f_matcharg}, - {"matchdelete", 1, 2, FEARG_1, &t_number, f_matchdelete}, - {"matchend", 2, 4, FEARG_1, &t_number, f_matchend}, - {"matchlist", 2, 4, FEARG_1, &t_list_string, f_matchlist}, - {"matchstr", 2, 4, FEARG_1, &t_string, f_matchstr}, - {"matchstrpos", 2, 4, FEARG_1, &t_list_any, f_matchstrpos}, - {"max", 1, 1, FEARG_1, &t_any, f_max}, - {"min", 1, 1, FEARG_1, &t_any, f_min}, - {"mkdir", 1, 3, FEARG_1, &t_number, f_mkdir}, - {"mode", 0, 1, FEARG_1, &t_string, f_mode}, + {"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}, + {"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}, + {"matcharg", 1, 1, FEARG_1, ret_list_string, f_matcharg}, + {"matchdelete", 1, 2, FEARG_1, ret_number, f_matchdelete}, + {"matchend", 2, 4, FEARG_1, ret_number, f_matchend}, + {"matchlist", 2, 4, FEARG_1, ret_list_string, f_matchlist}, + {"matchstr", 2, 4, FEARG_1, ret_string, f_matchstr}, + {"matchstrpos", 2, 4, FEARG_1, ret_list_any, f_matchstrpos}, + {"max", 1, 1, FEARG_1, ret_any, f_max}, + {"min", 1, 1, FEARG_1, ret_any, f_min}, + {"mkdir", 1, 3, FEARG_1, ret_number, f_mkdir}, + {"mode", 0, 1, FEARG_1, ret_string, f_mode}, #ifdef FEAT_MZSCHEME - {"mzeval", 1, 1, FEARG_1, &t_any, f_mzeval}, + {"mzeval", 1, 1, FEARG_1, ret_any, f_mzeval}, #endif - {"nextnonblank", 1, 1, FEARG_1, &t_number, f_nextnonblank}, - {"nr2char", 1, 2, FEARG_1, &t_string, f_nr2char}, - {"or", 2, 2, FEARG_1, &t_number, f_or}, - {"pathshorten", 1, 1, FEARG_1, &t_string, f_pathshorten}, + {"nextnonblank", 1, 1, FEARG_1, ret_number, f_nextnonblank}, + {"nr2char", 1, 2, FEARG_1, ret_string, f_nr2char}, + {"or", 2, 2, FEARG_1, ret_number, f_or}, + {"pathshorten", 1, 1, FEARG_1, ret_string, f_pathshorten}, #ifdef FEAT_PERL - {"perleval", 1, 1, FEARG_1, &t_any, f_perleval}, + {"perleval", 1, 1, FEARG_1, ret_any, f_perleval}, #endif #ifdef FEAT_PROP_POPUP - {"popup_atcursor", 2, 2, FEARG_1, &t_number, f_popup_atcursor}, - {"popup_beval", 2, 2, FEARG_1, &t_number, f_popup_beval}, - {"popup_clear", 0, 0, 0, &t_void, f_popup_clear}, - {"popup_close", 1, 2, FEARG_1, &t_void, f_popup_close}, - {"popup_create", 2, 2, FEARG_1, &t_number, f_popup_create}, - {"popup_dialog", 2, 2, FEARG_1, &t_number, f_popup_dialog}, - {"popup_filter_menu", 2, 2, 0, &t_number, f_popup_filter_menu}, - {"popup_filter_yesno", 2, 2, 0, &t_number, f_popup_filter_yesno}, - {"popup_findinfo", 0, 0, 0, &t_number, f_popup_findinfo}, - {"popup_findpreview", 0, 0, 0, &t_number, f_popup_findpreview}, - {"popup_getoptions", 1, 1, FEARG_1, &t_dict_any, f_popup_getoptions}, - {"popup_getpos", 1, 1, FEARG_1, &t_dict_any, f_popup_getpos}, - {"popup_hide", 1, 1, FEARG_1, &t_void, f_popup_hide}, - {"popup_locate", 2, 2, 0, &t_number, f_popup_locate}, - {"popup_menu", 2, 2, FEARG_1, &t_number, f_popup_menu}, - {"popup_move", 2, 2, FEARG_1, &t_void, f_popup_move}, - {"popup_notification", 2, 2, FEARG_1, &t_number, f_popup_notification}, - {"popup_setoptions", 2, 2, FEARG_1, &t_void, f_popup_setoptions}, - {"popup_settext", 2, 2, FEARG_1, &t_void, f_popup_settext}, - {"popup_show", 1, 1, FEARG_1, &t_void, f_popup_show}, + {"popup_atcursor", 2, 2, FEARG_1, ret_number, f_popup_atcursor}, + {"popup_beval", 2, 2, FEARG_1, ret_number, f_popup_beval}, + {"popup_clear", 0, 0, 0, ret_void, f_popup_clear}, + {"popup_close", 1, 2, FEARG_1, ret_void, f_popup_close}, + {"popup_create", 2, 2, FEARG_1, ret_number, f_popup_create}, + {"popup_dialog", 2, 2, FEARG_1, ret_number, f_popup_dialog}, + {"popup_filter_menu", 2, 2, 0, ret_number, f_popup_filter_menu}, + {"popup_filter_yesno", 2, 2, 0, ret_number, f_popup_filter_yesno}, + {"popup_findinfo", 0, 0, 0, ret_number, f_popup_findinfo}, + {"popup_findpreview", 0, 0, 0, ret_number, f_popup_findpreview}, + {"popup_getoptions", 1, 1, FEARG_1, ret_dict_any, f_popup_getoptions}, + {"popup_getpos", 1, 1, FEARG_1, ret_dict_any, f_popup_getpos}, + {"popup_hide", 1, 1, FEARG_1, ret_void, f_popup_hide}, + {"popup_locate", 2, 2, 0, ret_number, f_popup_locate}, + {"popup_menu", 2, 2, FEARG_1, ret_number, f_popup_menu}, + {"popup_move", 2, 2, FEARG_1, ret_void, f_popup_move}, + {"popup_notification", 2, 2, FEARG_1, ret_number, f_popup_notification}, + {"popup_setoptions", 2, 2, FEARG_1, ret_void, f_popup_setoptions}, + {"popup_settext", 2, 2, FEARG_1, ret_void, f_popup_settext}, + {"popup_show", 1, 1, FEARG_1, ret_void, f_popup_show}, #endif #ifdef FEAT_FLOAT - {"pow", 2, 2, FEARG_1, &t_float, f_pow}, + {"pow", 2, 2, FEARG_1, ret_float, f_pow}, #endif - {"prevnonblank", 1, 1, FEARG_1, &t_number, f_prevnonblank}, - {"printf", 1, 19, FEARG_2, &t_string, f_printf}, + {"prevnonblank", 1, 1, FEARG_1, ret_number, f_prevnonblank}, + {"printf", 1, 19, FEARG_2, ret_string, f_printf}, #ifdef FEAT_JOB_CHANNEL - {"prompt_setcallback", 2, 2, FEARG_1, &t_void, f_prompt_setcallback}, - {"prompt_setinterrupt", 2, 2, FEARG_1,&t_void, f_prompt_setinterrupt}, - {"prompt_setprompt", 2, 2, FEARG_1, &t_void, f_prompt_setprompt}, + {"prompt_setcallback", 2, 2, FEARG_1, ret_void, f_prompt_setcallback}, + {"prompt_setinterrupt", 2, 2, FEARG_1,ret_void, f_prompt_setinterrupt}, + {"prompt_setprompt", 2, 2, FEARG_1, ret_void, f_prompt_setprompt}, #endif #ifdef FEAT_PROP_POPUP - {"prop_add", 3, 3, FEARG_1, &t_void, f_prop_add}, - {"prop_clear", 1, 3, FEARG_1, &t_void, f_prop_clear}, - {"prop_find", 1, 2, FEARG_1, &t_dict_any, f_prop_find}, - {"prop_list", 1, 2, FEARG_1, &t_list_dict_any, f_prop_list}, - {"prop_remove", 1, 3, FEARG_1, &t_number, f_prop_remove}, - {"prop_type_add", 2, 2, FEARG_1, &t_void, f_prop_type_add}, - {"prop_type_change", 2, 2, FEARG_1, &t_void, f_prop_type_change}, - {"prop_type_delete", 1, 2, FEARG_1, &t_void, f_prop_type_delete}, - {"prop_type_get", 1, 2, FEARG_1, &t_dict_any, f_prop_type_get}, - {"prop_type_list", 0, 1, FEARG_1, &t_list_string, f_prop_type_list}, + {"prop_add", 3, 3, FEARG_1, ret_void, f_prop_add}, + {"prop_clear", 1, 3, FEARG_1, ret_void, f_prop_clear}, + {"prop_find", 1, 2, FEARG_1, ret_dict_any, f_prop_find}, + {"prop_list", 1, 2, FEARG_1, ret_list_dict_any, f_prop_list}, + {"prop_remove", 1, 3, FEARG_1, ret_number, f_prop_remove}, + {"prop_type_add", 2, 2, FEARG_1, ret_void, f_prop_type_add}, + {"prop_type_change", 2, 2, FEARG_1, ret_void, f_prop_type_change}, + {"prop_type_delete", 1, 2, FEARG_1, ret_void, f_prop_type_delete}, + {"prop_type_get", 1, 2, FEARG_1, ret_dict_any, f_prop_type_get}, + {"prop_type_list", 0, 1, FEARG_1, ret_list_string, f_prop_type_list}, #endif - {"pum_getpos", 0, 0, 0, &t_dict_number, f_pum_getpos}, - {"pumvisible", 0, 0, 0, &t_number, f_pumvisible}, + {"pum_getpos", 0, 0, 0, ret_dict_number, f_pum_getpos}, + {"pumvisible", 0, 0, 0, ret_number, f_pumvisible}, #ifdef FEAT_PYTHON3 - {"py3eval", 1, 1, FEARG_1, &t_any, f_py3eval}, + {"py3eval", 1, 1, FEARG_1, ret_any, f_py3eval}, #endif #ifdef FEAT_PYTHON - {"pyeval", 1, 1, FEARG_1, &t_any, f_pyeval}, + {"pyeval", 1, 1, FEARG_1, ret_any, f_pyeval}, #endif #if defined(FEAT_PYTHON) || defined(FEAT_PYTHON3) - {"pyxeval", 1, 1, FEARG_1, &t_any, f_pyxeval}, + {"pyxeval", 1, 1, FEARG_1, ret_any, f_pyxeval}, #endif - {"rand", 0, 1, FEARG_1, &t_number, f_rand}, - {"range", 1, 3, FEARG_1, &t_list_number, f_range}, - {"readdir", 1, 2, FEARG_1, &t_list_string, f_readdir}, - {"readfile", 1, 3, FEARG_1, &t_any, f_readfile}, - {"reg_executing", 0, 0, 0, &t_string, f_reg_executing}, - {"reg_recording", 0, 0, 0, &t_string, f_reg_recording}, - {"reltime", 0, 2, FEARG_1, &t_list_any, f_reltime}, + {"rand", 0, 1, FEARG_1, ret_number, f_rand}, + {"range", 1, 3, FEARG_1, ret_list_number, f_range}, + {"readdir", 1, 2, FEARG_1, ret_list_string, f_readdir}, + {"readfile", 1, 3, FEARG_1, ret_any, f_readfile}, + {"reg_executing", 0, 0, 0, ret_string, f_reg_executing}, + {"reg_recording", 0, 0, 0, ret_string, f_reg_recording}, + {"reltime", 0, 2, FEARG_1, ret_list_any, f_reltime}, #ifdef FEAT_FLOAT - {"reltimefloat", 1, 1, FEARG_1, &t_float, f_reltimefloat}, + {"reltimefloat", 1, 1, FEARG_1, ret_float, f_reltimefloat}, #endif - {"reltimestr", 1, 1, FEARG_1, &t_string, f_reltimestr}, - {"remote_expr", 2, 4, FEARG_1, &t_string, f_remote_expr}, - {"remote_foreground", 1, 1, FEARG_1, &t_string, f_remote_foreground}, - {"remote_peek", 1, 2, FEARG_1, &t_number, f_remote_peek}, - {"remote_read", 1, 2, FEARG_1, &t_string, f_remote_read}, - {"remote_send", 2, 3, FEARG_1, &t_string, f_remote_send}, - {"remote_startserver", 1, 1, FEARG_1, &t_void, f_remote_startserver}, - {"remove", 2, 3, FEARG_1, &t_any, f_remove}, - {"rename", 2, 2, FEARG_1, &t_number, f_rename}, - {"repeat", 2, 2, FEARG_1, &t_any, f_repeat}, - {"resolve", 1, 1, FEARG_1, &t_string, f_resolve}, - {"reverse", 1, 1, FEARG_1, &t_any, f_reverse}, + {"reltimestr", 1, 1, FEARG_1, ret_string, f_reltimestr}, + {"remote_expr", 2, 4, FEARG_1, ret_string, f_remote_expr}, + {"remote_foreground", 1, 1, FEARG_1, ret_string, f_remote_foreground}, + {"remote_peek", 1, 2, FEARG_1, ret_number, f_remote_peek}, + {"remote_read", 1, 2, FEARG_1, ret_string, f_remote_read}, + {"remote_send", 2, 3, FEARG_1, ret_string, f_remote_send}, + {"remote_startserver", 1, 1, FEARG_1, ret_void, f_remote_startserver}, + {"remove", 2, 3, FEARG_1, ret_any, f_remove}, + {"rename", 2, 2, FEARG_1, ret_number, f_rename}, + {"repeat", 2, 2, FEARG_1, ret_any, f_repeat}, + {"resolve", 1, 1, FEARG_1, ret_string, f_resolve}, + {"reverse", 1, 1, FEARG_1, ret_any, f_reverse}, #ifdef FEAT_FLOAT - {"round", 1, 1, FEARG_1, &t_float, f_round}, + {"round", 1, 1, FEARG_1, ret_float, f_round}, #endif #ifdef FEAT_RUBY - {"rubyeval", 1, 1, FEARG_1, &t_any, f_rubyeval}, + {"rubyeval", 1, 1, FEARG_1, ret_any, f_rubyeval}, #endif - {"screenattr", 2, 2, FEARG_1, &t_number, f_screenattr}, - {"screenchar", 2, 2, FEARG_1, &t_number, f_screenchar}, - {"screenchars", 2, 2, FEARG_1, &t_list_number, f_screenchars}, - {"screencol", 0, 0, 0, &t_number, f_screencol}, - {"screenpos", 3, 3, FEARG_1, &t_dict_number, f_screenpos}, - {"screenrow", 0, 0, 0, &t_number, f_screenrow}, - {"screenstring", 2, 2, FEARG_1, &t_string, f_screenstring}, - {"search", 1, 4, FEARG_1, &t_number, f_search}, - {"searchdecl", 1, 3, FEARG_1, &t_number, f_searchdecl}, - {"searchpair", 3, 7, 0, &t_number, f_searchpair}, - {"searchpairpos", 3, 7, 0, &t_list_number, f_searchpairpos}, - {"searchpos", 1, 4, FEARG_1, &t_list_number, f_searchpos}, - {"server2client", 2, 2, FEARG_1, &t_number, f_server2client}, - {"serverlist", 0, 0, 0, &t_string, f_serverlist}, - {"setbufline", 3, 3, FEARG_3, &t_number, f_setbufline}, - {"setbufvar", 3, 3, FEARG_3, &t_void, f_setbufvar}, - {"setcharsearch", 1, 1, FEARG_1, &t_void, f_setcharsearch}, - {"setcmdpos", 1, 1, FEARG_1, &t_number, f_setcmdpos}, - {"setenv", 2, 2, FEARG_2, &t_void, f_setenv}, - {"setfperm", 2, 2, FEARG_1, &t_number, f_setfperm}, - {"setline", 2, 2, FEARG_2, &t_number, f_setline}, - {"setloclist", 2, 4, FEARG_2, &t_number, f_setloclist}, - {"setmatches", 1, 2, FEARG_1, &t_number, f_setmatches}, - {"setpos", 2, 2, FEARG_2, &t_number, f_setpos}, - {"setqflist", 1, 3, FEARG_1, &t_number, f_setqflist}, - {"setreg", 2, 3, FEARG_2, &t_number, f_setreg}, - {"settabvar", 3, 3, FEARG_3, &t_void, f_settabvar}, - {"settabwinvar", 4, 4, FEARG_4, &t_void, f_settabwinvar}, - {"settagstack", 2, 3, FEARG_2, &t_number, f_settagstack}, - {"setwinvar", 3, 3, FEARG_3, &t_void, f_setwinvar}, + {"screenattr", 2, 2, FEARG_1, ret_number, f_screenattr}, + {"screenchar", 2, 2, FEARG_1, ret_number, f_screenchar}, + {"screenchars", 2, 2, FEARG_1, ret_list_number, f_screenchars}, + {"screencol", 0, 0, 0, ret_number, f_screencol}, + {"screenpos", 3, 3, FEARG_1, ret_dict_number, f_screenpos}, + {"screenrow", 0, 0, 0, ret_number, f_screenrow}, + {"screenstring", 2, 2, FEARG_1, ret_string, f_screenstring}, + {"search", 1, 4, FEARG_1, ret_number, f_search}, + {"searchdecl", 1, 3, FEARG_1, ret_number, f_searchdecl}, + {"searchpair", 3, 7, 0, ret_number, f_searchpair}, + {"searchpairpos", 3, 7, 0, ret_list_number, f_searchpairpos}, + {"searchpos", 1, 4, FEARG_1, ret_list_number, f_searchpos}, + {"server2client", 2, 2, FEARG_1, ret_number, f_server2client}, + {"serverlist", 0, 0, 0, ret_string, f_serverlist}, + {"setbufline", 3, 3, FEARG_3, ret_number, f_setbufline}, + {"setbufvar", 3, 3, FEARG_3, ret_void, f_setbufvar}, + {"setcharsearch", 1, 1, FEARG_1, ret_void, f_setcharsearch}, + {"setcmdpos", 1, 1, FEARG_1, ret_number, f_setcmdpos}, + {"setenv", 2, 2, FEARG_2, ret_void, f_setenv}, + {"setfperm", 2, 2, FEARG_1, ret_number, f_setfperm}, + {"setline", 2, 2, FEARG_2, ret_number, f_setline}, + {"setloclist", 2, 4, FEARG_2, ret_number, f_setloclist}, + {"setmatches", 1, 2, FEARG_1, ret_number, f_setmatches}, + {"setpos", 2, 2, FEARG_2, ret_number, f_setpos}, + {"setqflist", 1, 3, FEARG_1, ret_number, f_setqflist}, + {"setreg", 2, 3, FEARG_2, ret_number, f_setreg}, + {"settabvar", 3, 3, FEARG_3, ret_void, f_settabvar}, + {"settabwinvar", 4, 4, FEARG_4, ret_void, f_settabwinvar}, + {"settagstack", 2, 3, FEARG_2, ret_number, f_settagstack}, + {"setwinvar", 3, 3, FEARG_3, ret_void, f_setwinvar}, #ifdef FEAT_CRYPT - {"sha256", 1, 1, FEARG_1, &t_string, f_sha256}, + {"sha256", 1, 1, FEARG_1, ret_string, f_sha256}, #endif - {"shellescape", 1, 2, FEARG_1, &t_string, f_shellescape}, - {"shiftwidth", 0, 1, FEARG_1, &t_number, f_shiftwidth}, + {"shellescape", 1, 2, FEARG_1, ret_string, f_shellescape}, + {"shiftwidth", 0, 1, FEARG_1, ret_number, f_shiftwidth}, #ifdef FEAT_SIGNS - {"sign_define", 1, 2, FEARG_1, &t_any, f_sign_define}, - {"sign_getdefined", 0, 1, FEARG_1, &t_list_dict_any, f_sign_getdefined}, - {"sign_getplaced", 0, 2, FEARG_1, &t_list_dict_any, f_sign_getplaced}, - {"sign_jump", 3, 3, FEARG_1, &t_number, f_sign_jump}, - {"sign_place", 4, 5, FEARG_1, &t_number, f_sign_place}, - {"sign_placelist", 1, 1, FEARG_1, &t_list_number, f_sign_placelist}, - {"sign_undefine", 0, 1, FEARG_1, &t_number, f_sign_undefine}, - {"sign_unplace", 1, 2, FEARG_1, &t_number, f_sign_unplace}, - {"sign_unplacelist", 1, 2, FEARG_1, &t_list_number, f_sign_unplacelist}, + {"sign_define", 1, 2, FEARG_1, ret_any, f_sign_define}, + {"sign_getdefined", 0, 1, FEARG_1, ret_list_dict_any, f_sign_getdefined}, + {"sign_getplaced", 0, 2, FEARG_1, ret_list_dict_any, f_sign_getplaced}, + {"sign_jump", 3, 3, FEARG_1, ret_number, f_sign_jump}, + {"sign_place", 4, 5, FEARG_1, ret_number, f_sign_place}, + {"sign_placelist", 1, 1, FEARG_1, ret_list_number, f_sign_placelist}, + {"sign_undefine", 0, 1, FEARG_1, ret_number, f_sign_undefine}, + {"sign_unplace", 1, 2, FEARG_1, ret_number, f_sign_unplace}, + {"sign_unplacelist", 1, 2, FEARG_1, ret_list_number, f_sign_unplacelist}, #endif - {"simplify", 1, 1, 0, &t_string, f_simplify}, + {"simplify", 1, 1, 0, ret_string, f_simplify}, #ifdef FEAT_FLOAT - {"sin", 1, 1, FEARG_1, &t_float, f_sin}, - {"sinh", 1, 1, FEARG_1, &t_float, f_sinh}, + {"sin", 1, 1, FEARG_1, ret_float, f_sin}, + {"sinh", 1, 1, FEARG_1, ret_float, f_sinh}, #endif - {"sort", 1, 3, FEARG_1, &t_list_any, f_sort}, + {"sort", 1, 3, FEARG_1, ret_list_any, f_sort}, #ifdef FEAT_SOUND - {"sound_clear", 0, 0, 0, &t_void, f_sound_clear}, - {"sound_playevent", 1, 2, FEARG_1, &t_number, f_sound_playevent}, - {"sound_playfile", 1, 2, FEARG_1, &t_number, f_sound_playfile}, - {"sound_stop", 1, 1, FEARG_1, &t_void, f_sound_stop}, + {"sound_clear", 0, 0, 0, ret_void, f_sound_clear}, + {"sound_playevent", 1, 2, FEARG_1, ret_number, f_sound_playevent}, + {"sound_playfile", 1, 2, FEARG_1, ret_number, f_sound_playfile}, + {"sound_stop", 1, 1, FEARG_1, ret_void, f_sound_stop}, #endif - {"soundfold", 1, 1, FEARG_1, &t_string, f_soundfold}, - {"spellbadword", 0, 1, FEARG_1, &t_list_string, f_spellbadword}, - {"spellsuggest", 1, 3, FEARG_1, &t_list_string, f_spellsuggest}, - {"split", 1, 3, FEARG_1, &t_list_string, f_split}, + {"soundfold", 1, 1, FEARG_1, ret_string, f_soundfold}, + {"spellbadword", 0, 1, FEARG_1, ret_list_string, f_spellbadword}, + {"spellsuggest", 1, 3, FEARG_1, ret_list_string, f_spellsuggest}, + {"split", 1, 3, FEARG_1, ret_list_string, f_split}, #ifdef FEAT_FLOAT - {"sqrt", 1, 1, FEARG_1, &t_float, f_sqrt}, + {"sqrt", 1, 1, FEARG_1, ret_float, f_sqrt}, #endif - {"srand", 0, 1, FEARG_1, &t_list_number, f_srand}, - {"state", 0, 1, FEARG_1, &t_string, f_state}, + {"srand", 0, 1, FEARG_1, ret_list_number, f_srand}, + {"state", 0, 1, FEARG_1, ret_string, f_state}, #ifdef FEAT_FLOAT - {"str2float", 1, 1, FEARG_1, &t_float, f_str2float}, + {"str2float", 1, 1, FEARG_1, ret_float, f_str2float}, #endif - {"str2list", 1, 2, FEARG_1, &t_list_number, f_str2list}, - {"str2nr", 1, 3, FEARG_1, &t_number, f_str2nr}, - {"strcharpart", 2, 3, FEARG_1, &t_string, f_strcharpart}, - {"strchars", 1, 2, FEARG_1, &t_number, f_strchars}, - {"strdisplaywidth", 1, 2, FEARG_1, &t_number, f_strdisplaywidth}, + {"str2list", 1, 2, FEARG_1, ret_list_number, f_str2list}, + {"str2nr", 1, 3, FEARG_1, ret_number, f_str2nr}, + {"strcharpart", 2, 3, FEARG_1, ret_string, f_strcharpart}, + {"strchars", 1, 2, FEARG_1, ret_number, f_strchars}, + {"strdisplaywidth", 1, 2, FEARG_1, ret_number, f_strdisplaywidth}, #ifdef HAVE_STRFTIME - {"strftime", 1, 2, FEARG_1, &t_string, f_strftime}, + {"strftime", 1, 2, FEARG_1, ret_string, f_strftime}, #endif - {"strgetchar", 2, 2, FEARG_1, &t_number, f_strgetchar}, - {"stridx", 2, 3, FEARG_1, &t_number, f_stridx}, - {"string", 1, 1, FEARG_1, &t_string, f_string}, - {"strlen", 1, 1, FEARG_1, &t_number, f_strlen}, - {"strpart", 2, 3, FEARG_1, &t_string, f_strpart}, + {"strgetchar", 2, 2, FEARG_1, ret_number, f_strgetchar}, + {"stridx", 2, 3, FEARG_1, ret_number, f_stridx}, + {"string", 1, 1, FEARG_1, ret_string, f_string}, + {"strlen", 1, 1, FEARG_1, ret_number, f_strlen}, + {"strpart", 2, 3, FEARG_1, ret_string, f_strpart}, #ifdef HAVE_STRPTIME - {"strptime", 2, 2, FEARG_1, &t_number, f_strptime}, + {"strptime", 2, 2, FEARG_1, ret_number, f_strptime}, #endif - {"strridx", 2, 3, FEARG_1, &t_number, f_strridx}, - {"strtrans", 1, 1, FEARG_1, &t_string, f_strtrans}, - {"strwidth", 1, 1, FEARG_1, &t_number, f_strwidth}, - {"submatch", 1, 2, FEARG_1, &t_string, f_submatch}, - {"substitute", 4, 4, FEARG_1, &t_string, f_substitute}, - {"swapinfo", 1, 1, FEARG_1, &t_dict_any, f_swapinfo}, - {"swapname", 1, 1, FEARG_1, &t_string, f_swapname}, - {"synID", 3, 3, 0, &t_number, f_synID}, - {"synIDattr", 2, 3, FEARG_1, &t_string, f_synIDattr}, - {"synIDtrans", 1, 1, FEARG_1, &t_number, f_synIDtrans}, - {"synconcealed", 2, 2, 0, &t_list_any, f_synconcealed}, - {"synstack", 2, 2, 0, &t_list_number, f_synstack}, - {"system", 1, 2, FEARG_1, &t_string, f_system}, - {"systemlist", 1, 2, FEARG_1, &t_list_string, f_systemlist}, - {"tabpagebuflist", 0, 1, FEARG_1, &t_list_number, f_tabpagebuflist}, - {"tabpagenr", 0, 1, 0, &t_number, f_tabpagenr}, - {"tabpagewinnr", 1, 2, FEARG_1, &t_number, f_tabpagewinnr}, - {"tagfiles", 0, 0, 0, &t_list_string, f_tagfiles}, - {"taglist", 1, 2, FEARG_1, &t_list_dict_any, f_taglist}, + {"strridx", 2, 3, FEARG_1, ret_number, f_strridx}, + {"strtrans", 1, 1, FEARG_1, ret_string, f_strtrans}, + {"strwidth", 1, 1, FEARG_1, ret_number, f_strwidth}, + {"submatch", 1, 2, FEARG_1, ret_string, f_submatch}, + {"substitute", 4, 4, FEARG_1, ret_string, f_substitute}, + {"swapinfo", 1, 1, FEARG_1, ret_dict_any, f_swapinfo}, + {"swapname", 1, 1, FEARG_1, ret_string, f_swapname}, + {"synID", 3, 3, 0, ret_number, f_synID}, + {"synIDattr", 2, 3, FEARG_1, ret_string, f_synIDattr}, + {"synIDtrans", 1, 1, FEARG_1, ret_number, f_synIDtrans}, + {"synconcealed", 2, 2, 0, ret_list_any, f_synconcealed}, + {"synstack", 2, 2, 0, ret_list_number, f_synstack}, + {"system", 1, 2, FEARG_1, ret_string, f_system}, + {"systemlist", 1, 2, FEARG_1, ret_list_string, f_systemlist}, + {"tabpagebuflist", 0, 1, FEARG_1, ret_list_number, f_tabpagebuflist}, + {"tabpagenr", 0, 1, 0, ret_number, f_tabpagenr}, + {"tabpagewinnr", 1, 2, FEARG_1, ret_number, f_tabpagewinnr}, + {"tagfiles", 0, 0, 0, ret_list_string, f_tagfiles}, + {"taglist", 1, 2, FEARG_1, ret_list_dict_any, f_taglist}, #ifdef FEAT_FLOAT - {"tan", 1, 1, FEARG_1, &t_float, f_tan}, - {"tanh", 1, 1, FEARG_1, &t_float, f_tanh}, + {"tan", 1, 1, FEARG_1, ret_float, f_tan}, + {"tanh", 1, 1, FEARG_1, ret_float, f_tanh}, #endif - {"tempname", 0, 0, 0, &t_string, f_tempname}, + {"tempname", 0, 0, 0, ret_string, f_tempname}, #ifdef FEAT_TERMINAL - {"term_dumpdiff", 2, 3, FEARG_1, &t_number, f_term_dumpdiff}, - {"term_dumpload", 1, 2, FEARG_1, &t_number, f_term_dumpload}, - {"term_dumpwrite", 2, 3, FEARG_2, &t_void, f_term_dumpwrite}, - {"term_getaltscreen", 1, 1, FEARG_1, &t_number, f_term_getaltscreen}, + {"term_dumpdiff", 2, 3, FEARG_1, ret_number, f_term_dumpdiff}, + {"term_dumpload", 1, 2, FEARG_1, ret_number, f_term_dumpload}, + {"term_dumpwrite", 2, 3, FEARG_2, ret_void, f_term_dumpwrite}, + {"term_getaltscreen", 1, 1, FEARG_1, ret_number, f_term_getaltscreen}, # if defined(FEAT_GUI) || defined(FEAT_TERMGUICOLORS) - {"term_getansicolors", 1, 1, FEARG_1, &t_list_string, f_term_getansicolors}, + {"term_getansicolors", 1, 1, FEARG_1, ret_list_string, f_term_getansicolors}, # endif - {"term_getattr", 2, 2, FEARG_1, &t_number, f_term_getattr}, - {"term_getcursor", 1, 1, FEARG_1, &t_list_any, f_term_getcursor}, - {"term_getjob", 1, 1, FEARG_1, &t_job, f_term_getjob}, - {"term_getline", 2, 2, FEARG_1, &t_string, f_term_getline}, - {"term_getscrolled", 1, 1, FEARG_1, &t_number, f_term_getscrolled}, - {"term_getsize", 1, 1, FEARG_1, &t_list_number, f_term_getsize}, - {"term_getstatus", 1, 1, FEARG_1, &t_string, f_term_getstatus}, - {"term_gettitle", 1, 1, FEARG_1, &t_string, f_term_gettitle}, - {"term_gettty", 1, 2, FEARG_1, &t_string, f_term_gettty}, - {"term_list", 0, 0, 0, &t_list_number, f_term_list}, - {"term_scrape", 2, 2, FEARG_1, &t_list_dict_any, f_term_scrape}, - {"term_sendkeys", 2, 2, FEARG_1, &t_void, f_term_sendkeys}, + {"term_getattr", 2, 2, FEARG_1, ret_number, f_term_getattr}, + {"term_getcursor", 1, 1, FEARG_1, ret_list_any, f_term_getcursor}, + {"term_getjob", 1, 1, FEARG_1, ret_job, f_term_getjob}, + {"term_getline", 2, 2, FEARG_1, ret_string, f_term_getline}, + {"term_getscrolled", 1, 1, FEARG_1, ret_number, f_term_getscrolled}, + {"term_getsize", 1, 1, FEARG_1, ret_list_number, f_term_getsize}, + {"term_getstatus", 1, 1, FEARG_1, ret_string, f_term_getstatus}, + {"term_gettitle", 1, 1, FEARG_1, ret_string, f_term_gettitle}, + {"term_gettty", 1, 2, FEARG_1, ret_string, f_term_gettty}, + {"term_list", 0, 0, 0, ret_list_number, f_term_list}, + {"term_scrape", 2, 2, FEARG_1, ret_list_dict_any, f_term_scrape}, + {"term_sendkeys", 2, 2, FEARG_1, ret_void, f_term_sendkeys}, # if defined(FEAT_GUI) || defined(FEAT_TERMGUICOLORS) - {"term_setansicolors", 2, 2, FEARG_1, &t_void, f_term_setansicolors}, + {"term_setansicolors", 2, 2, FEARG_1, ret_void, f_term_setansicolors}, # endif - {"term_setapi", 2, 2, FEARG_1, &t_void, f_term_setapi}, - {"term_setkill", 2, 2, FEARG_1, &t_void, f_term_setkill}, - {"term_setrestore", 2, 2, FEARG_1, &t_void, f_term_setrestore}, - {"term_setsize", 3, 3, FEARG_1, &t_void, f_term_setsize}, - {"term_start", 1, 2, FEARG_1, &t_number, f_term_start}, - {"term_wait", 1, 2, FEARG_1, &t_void, f_term_wait}, + {"term_setapi", 2, 2, FEARG_1, ret_void, f_term_setapi}, + {"term_setkill", 2, 2, FEARG_1, ret_void, f_term_setkill}, + {"term_setrestore", 2, 2, FEARG_1, ret_void, f_term_setrestore}, + {"term_setsize", 3, 3, FEARG_1, ret_void, f_term_setsize}, + {"term_start", 1, 2, FEARG_1, ret_number, f_term_start}, + {"term_wait", 1, 2, FEARG_1, ret_void, f_term_wait}, #endif - {"test_alloc_fail", 3, 3, FEARG_1, &t_void, f_test_alloc_fail}, - {"test_autochdir", 0, 0, 0, &t_void, f_test_autochdir}, - {"test_feedinput", 1, 1, FEARG_1, &t_void, f_test_feedinput}, - {"test_garbagecollect_now", 0, 0, 0, &t_void, f_test_garbagecollect_now}, - {"test_garbagecollect_soon", 0, 0, 0, &t_void, f_test_garbagecollect_soon}, - {"test_getvalue", 1, 1, FEARG_1, &t_number, f_test_getvalue}, - {"test_ignore_error", 1, 1, FEARG_1, &t_void, f_test_ignore_error}, - {"test_null_blob", 0, 0, 0, &t_blob, f_test_null_blob}, + {"test_alloc_fail", 3, 3, FEARG_1, ret_void, f_test_alloc_fail}, + {"test_autochdir", 0, 0, 0, ret_void, f_test_autochdir}, + {"test_feedinput", 1, 1, FEARG_1, ret_void, f_test_feedinput}, + {"test_garbagecollect_now", 0, 0, 0, ret_void, f_test_garbagecollect_now}, + {"test_garbagecollect_soon", 0, 0, 0, ret_void, f_test_garbagecollect_soon}, + {"test_getvalue", 1, 1, FEARG_1, ret_number, f_test_getvalue}, + {"test_ignore_error", 1, 1, FEARG_1, ret_void, f_test_ignore_error}, + {"test_null_blob", 0, 0, 0, ret_blob, f_test_null_blob}, #ifdef FEAT_JOB_CHANNEL - {"test_null_channel", 0, 0, 0, &t_channel, f_test_null_channel}, + {"test_null_channel", 0, 0, 0, ret_channel, f_test_null_channel}, #endif - {"test_null_dict", 0, 0, 0, &t_dict_any, f_test_null_dict}, + {"test_null_dict", 0, 0, 0, ret_dict_any, f_test_null_dict}, #ifdef FEAT_JOB_CHANNEL - {"test_null_job", 0, 0, 0, &t_job, f_test_null_job}, + {"test_null_job", 0, 0, 0, ret_job, f_test_null_job}, #endif - {"test_null_list", 0, 0, 0, &t_list_any, f_test_null_list}, - {"test_null_partial", 0, 0, 0, &t_partial_void, f_test_null_partial}, - {"test_null_string", 0, 0, 0, &t_string, f_test_null_string}, - {"test_option_not_set", 1, 1, FEARG_1,&t_void, f_test_option_not_set}, - {"test_override", 2, 2, FEARG_2, &t_void, f_test_override}, - {"test_refcount", 1, 1, FEARG_1, &t_number, f_test_refcount}, + {"test_null_list", 0, 0, 0, ret_list_any, f_test_null_list}, + {"test_null_partial", 0, 0, 0, ret_partial_void, f_test_null_partial}, + {"test_null_string", 0, 0, 0, ret_string, f_test_null_string}, + {"test_option_not_set", 1, 1, FEARG_1,ret_void, f_test_option_not_set}, + {"test_override", 2, 2, FEARG_2, ret_void, f_test_override}, + {"test_refcount", 1, 1, FEARG_1, ret_number, f_test_refcount}, #ifdef FEAT_GUI - {"test_scrollbar", 3, 3, FEARG_2, &t_void, f_test_scrollbar}, + {"test_scrollbar", 3, 3, FEARG_2, ret_void, f_test_scrollbar}, #endif - {"test_setmouse", 2, 2, 0, &t_void, f_test_setmouse}, - {"test_settime", 1, 1, FEARG_1, &t_void, f_test_settime}, - {"test_srand_seed", 0, 1, FEARG_1, &t_void, f_test_srand_seed}, - {"test_unknown", 0, 0, 0, &t_any, f_test_unknown}, - {"test_void", 0, 0, 0, &t_any, f_test_void}, + {"test_setmouse", 2, 2, 0, ret_void, f_test_setmouse}, + {"test_settime", 1, 1, FEARG_1, ret_void, f_test_settime}, + {"test_srand_seed", 0, 1, FEARG_1, ret_void, f_test_srand_seed}, + {"test_unknown", 0, 0, 0, ret_any, f_test_unknown}, + {"test_void", 0, 0, 0, ret_any, f_test_void}, #ifdef FEAT_TIMERS - {"timer_info", 0, 1, FEARG_1, &t_list_dict_any, f_timer_info}, - {"timer_pause", 2, 2, FEARG_1, &t_void, f_timer_pause}, - {"timer_start", 2, 3, FEARG_1, &t_number, f_timer_start}, - {"timer_stop", 1, 1, FEARG_1, &t_void, f_timer_stop}, - {"timer_stopall", 0, 0, 0, &t_void, f_timer_stopall}, + {"timer_info", 0, 1, FEARG_1, ret_list_dict_any, f_timer_info}, + {"timer_pause", 2, 2, FEARG_1, ret_void, f_timer_pause}, + {"timer_start", 2, 3, FEARG_1, ret_number, f_timer_start}, + {"timer_stop", 1, 1, FEARG_1, ret_void, f_timer_stop}, + {"timer_stopall", 0, 0, 0, ret_void, f_timer_stopall}, #endif - {"tolower", 1, 1, FEARG_1, &t_string, f_tolower}, - {"toupper", 1, 1, FEARG_1, &t_string, f_toupper}, - {"tr", 3, 3, FEARG_1, &t_string, f_tr}, - {"trim", 1, 2, FEARG_1, &t_string, f_trim}, + {"tolower", 1, 1, FEARG_1, ret_string, f_tolower}, + {"toupper", 1, 1, FEARG_1, ret_string, f_toupper}, + {"tr", 3, 3, FEARG_1, ret_string, f_tr}, + {"trim", 1, 2, FEARG_1, ret_string, f_trim}, #ifdef FEAT_FLOAT - {"trunc", 1, 1, FEARG_1, &t_float, f_trunc}, + {"trunc", 1, 1, FEARG_1, ret_float, f_trunc}, #endif - {"type", 1, 1, FEARG_1, &t_number, f_type}, - {"undofile", 1, 1, FEARG_1, &t_string, f_undofile}, - {"undotree", 0, 0, 0, &t_dict_any, f_undotree}, - {"uniq", 1, 3, FEARG_1, &t_list_any, f_uniq}, - {"values", 1, 1, FEARG_1, &t_list_any, f_values}, - {"virtcol", 1, 1, FEARG_1, &t_number, f_virtcol}, - {"visualmode", 0, 1, 0, &t_string, f_visualmode}, - {"wildmenumode", 0, 0, 0, &t_number, f_wildmenumode}, - {"win_execute", 2, 3, FEARG_2, &t_string, f_win_execute}, - {"win_findbuf", 1, 1, FEARG_1, &t_list_number, f_win_findbuf}, - {"win_getid", 0, 2, FEARG_1, &t_number, f_win_getid}, - {"win_gettype", 0, 1, FEARG_1, &t_string, f_win_gettype}, - {"win_gotoid", 1, 1, FEARG_1, &t_number, f_win_gotoid}, - {"win_id2tabwin", 1, 1, FEARG_1, &t_list_number, f_win_id2tabwin}, - {"win_id2win", 1, 1, FEARG_1, &t_number, f_win_id2win}, - {"win_screenpos", 1, 1, FEARG_1, &t_list_number, f_win_screenpos}, - {"win_splitmove", 2, 3, FEARG_1, &t_number, f_win_splitmove}, - {"winbufnr", 1, 1, FEARG_1, &t_number, f_winbufnr}, - {"wincol", 0, 0, 0, &t_number, f_wincol}, - {"windowsversion", 0, 0, 0, &t_string, f_windowsversion}, - {"winheight", 1, 1, FEARG_1, &t_number, f_winheight}, - {"winlayout", 0, 1, FEARG_1, &t_list_any, f_winlayout}, - {"winline", 0, 0, 0, &t_number, f_winline}, - {"winnr", 0, 1, FEARG_1, &t_number, f_winnr}, - {"winrestcmd", 0, 0, 0, &t_string, f_winrestcmd}, - {"winrestview", 1, 1, FEARG_1, &t_void, f_winrestview}, - {"winsaveview", 0, 0, 0, &t_dict_any, f_winsaveview}, - {"winwidth", 1, 1, FEARG_1, &t_number, f_winwidth}, - {"wordcount", 0, 0, 0, &t_dict_number, f_wordcount}, - {"writefile", 2, 3, FEARG_1, &t_number, f_writefile}, - {"xor", 2, 2, FEARG_1, &t_number, f_xor}, + {"type", 1, 1, FEARG_1, ret_number, f_type}, + {"undofile", 1, 1, FEARG_1, ret_string, f_undofile}, + {"undotree", 0, 0, 0, ret_dict_any, f_undotree}, + {"uniq", 1, 3, FEARG_1, ret_list_any, f_uniq}, + {"values", 1, 1, FEARG_1, ret_list_any, f_values}, + {"virtcol", 1, 1, FEARG_1, ret_number, f_virtcol}, + {"visualmode", 0, 1, 0, ret_string, f_visualmode}, + {"wildmenumode", 0, 0, 0, ret_number, f_wildmenumode}, + {"win_execute", 2, 3, FEARG_2, ret_string, f_win_execute}, + {"win_findbuf", 1, 1, FEARG_1, ret_list_number, f_win_findbuf}, + {"win_getid", 0, 2, FEARG_1, ret_number, f_win_getid}, + {"win_gettype", 0, 1, FEARG_1, ret_string, f_win_gettype}, + {"win_gotoid", 1, 1, FEARG_1, ret_number, f_win_gotoid}, + {"win_id2tabwin", 1, 1, FEARG_1, ret_list_number, f_win_id2tabwin}, + {"win_id2win", 1, 1, FEARG_1, ret_number, f_win_id2win}, + {"win_screenpos", 1, 1, FEARG_1, ret_list_number, f_win_screenpos}, + {"win_splitmove", 2, 3, FEARG_1, ret_number, f_win_splitmove}, + {"winbufnr", 1, 1, FEARG_1, ret_number, f_winbufnr}, + {"wincol", 0, 0, 0, ret_number, f_wincol}, + {"windowsversion", 0, 0, 0, ret_string, f_windowsversion}, + {"winheight", 1, 1, FEARG_1, ret_number, f_winheight}, + {"winlayout", 0, 1, FEARG_1, ret_list_any, f_winlayout}, + {"winline", 0, 0, 0, ret_number, f_winline}, + {"winnr", 0, 1, FEARG_1, ret_number, f_winnr}, + {"winrestcmd", 0, 0, 0, ret_string, f_winrestcmd}, + {"winrestview", 1, 1, FEARG_1, ret_void, f_winrestview}, + {"winsaveview", 0, 0, 0, ret_dict_any, f_winsaveview}, + {"winwidth", 1, 1, FEARG_1, ret_number, f_winwidth}, + {"wordcount", 0, 0, 0, ret_dict_number, f_wordcount}, + {"writefile", 2, 3, FEARG_1, ret_number, f_writefile}, + {"xor", 2, 2, FEARG_1, ret_number, f_xor}, }; /* @@ -963,13 +1049,9 @@ internal_func_name(int idx) } type_T * -internal_func_ret_type(int idx, int argcount) +internal_func_ret_type(int idx, int argcount, type_T **argtypes) { - funcentry_T *fe = &global_functions[idx]; - - if (fe->f_func == f_getline) - return argcount == 1 ? &t_string : &t_list_string; - return fe->f_rettype; + return global_functions[idx].f_retfunc(argcount, argtypes); } /* @@ -2718,6 +2800,14 @@ f_funcref(typval_T *argvars, typval_T *rettv) common_function(argvars, rettv, TRUE); } + static type_T * +ret_f_function(int argcount, type_T **argtypes UNUSED) +{ + if (argcount == 1 && argtypes[0]->tt_type == VAR_STRING) + return &t_func_any; + return &t_partial_void; +} + /* * "function()" function */ diff --git a/src/proto/evalbuffer.pro b/src/proto/evalbuffer.pro index b59c5f5e9b..57c84ceb76 100644 --- a/src/proto/evalbuffer.pro +++ b/src/proto/evalbuffer.pro @@ -16,6 +16,7 @@ void f_bufwinnr(typval_T *argvars, typval_T *rettv); void f_deletebufline(typval_T *argvars, typval_T *rettv); void f_getbufinfo(typval_T *argvars, typval_T *rettv); void f_getbufline(typval_T *argvars, typval_T *rettv); +type_T *ret_f_getline(int argcount, type_T **argtypes); void f_getline(typval_T *argvars, typval_T *rettv); void f_setbufline(typval_T *argvars, typval_T *rettv); void f_setline(typval_T *argvars, typval_T *rettv); diff --git a/src/proto/evalfunc.pro b/src/proto/evalfunc.pro index 14a1a56ac2..33dea2c7fc 100644 --- a/src/proto/evalfunc.pro +++ b/src/proto/evalfunc.pro @@ -4,7 +4,7 @@ char_u *get_expr_name(expand_T *xp, int idx); int find_internal_func(char_u *name); int has_internal_func(char_u *name); char *internal_func_name(int idx); -type_T *internal_func_ret_type(int idx, int argcount); +type_T *internal_func_ret_type(int idx, int argcount, type_T **argtypes); int check_internal_func(int idx, int argcount); int call_internal_func(char_u *name, int argcount, typval_T *argvars, typval_T *rettv); void call_internal_func_by_idx(int idx, typval_T *argvars, typval_T *rettv); diff --git a/src/testdir/test_vim9_script.vim b/src/testdir/test_vim9_script.vim index ac8bd7512f..e5b3b476e4 100644 --- a/src/testdir/test_vim9_script.vim +++ b/src/testdir/test_vim9_script.vim @@ -55,7 +55,12 @@ def Test_assignment() if has('channel') let chan1: channel + let job1: job endif + if has('float') + let float1: float = 3.4 + endif + let party: partial = funcref('Test_syntax') g:newvar = 'new' assert_equal('new', g:newvar) diff --git a/src/version.c b/src/version.c index cd410bfed3..bdb40d312f 100644 --- a/src/version.c +++ b/src/version.c @@ -738,6 +738,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 339, /**/ 338, /**/ diff --git a/src/vim9compile.c b/src/vim9compile.c index 2e0c2ffa84..4fb5478443 100644 --- a/src/vim9compile.c +++ b/src/vim9compile.c @@ -992,6 +992,8 @@ generate_BCALL(cctx_T *cctx, int func_idx, int argcount) { isn_T *isn; garray_T *stack = &cctx->ctx_type_stack; + type_T *argtypes[MAX_FUNC_ARGS]; + int i; if (check_internal_func(func_idx, argcount) == FAIL) return FAIL; @@ -1001,11 +1003,14 @@ generate_BCALL(cctx_T *cctx, int func_idx, int argcount) isn->isn_arg.bfunc.cbf_idx = func_idx; isn->isn_arg.bfunc.cbf_argcount = argcount; + for (i = 0; i < argcount; ++i) + argtypes[i] = ((type_T **)stack->ga_data)[stack->ga_len - argcount + i]; + stack->ga_len -= argcount; // drop the arguments if (ga_grow(stack, 1) == FAIL) return FAIL; ((type_T **)stack->ga_data)[stack->ga_len] = - internal_func_ret_type(func_idx, argcount); + internal_func_ret_type(func_idx, argcount, argtypes); ++stack->ga_len; // add return value return OK; @@ -1374,7 +1379,7 @@ parse_type(char_u **arg, garray_T *type_list) } break; case 'p': - if (len == 4 && STRNCMP(*arg, "partial", len) == 0) + if (len == 7 && STRNCMP(*arg, "partial", len) == 0) { *arg += len; // TODO: arguments and return type From 087d2e15184bea3bf455dd266bd6ed66a45396e5 Mon Sep 17 00:00:00 2001 From: Bram Moolenaar Date: Sun, 1 Mar 2020 15:36:42 +0100 Subject: [PATCH 20/63] patch 8.2.0340: Vim9: function and partial types not tested Problem: Vim9: function and partial types not tested. Solution: Support more for partial, add tests. --- src/testdir/test_vim9_script.vim | 5 ++++- src/version.c | 2 ++ src/vim9.h | 1 + src/vim9compile.c | 22 +++++++++++++++++++--- src/vim9execute.c | 26 +++++++++++++++++++++----- 5 files changed, 47 insertions(+), 9 deletions(-) diff --git a/src/testdir/test_vim9_script.vim b/src/testdir/test_vim9_script.vim index e5b3b476e4..aace239787 100644 --- a/src/testdir/test_vim9_script.vim +++ b/src/testdir/test_vim9_script.vim @@ -60,7 +60,10 @@ def Test_assignment() if has('float') let float1: float = 3.4 endif - let party: partial = funcref('Test_syntax') + let funky1: func + let funky2: func = function('len') + let party1: partial + let party2: partial = funcref('Test_syntax') g:newvar = 'new' assert_equal('new', g:newvar) diff --git a/src/version.c b/src/version.c index bdb40d312f..3d126b068f 100644 --- a/src/version.c +++ b/src/version.c @@ -738,6 +738,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 340, /**/ 339, /**/ diff --git a/src/vim9.h b/src/vim9.h index 3a09c0fecb..35d34e3af4 100644 --- a/src/vim9.h +++ b/src/vim9.h @@ -215,6 +215,7 @@ typedef struct { #endif channel_T *channel; job_T *job; + partial_T *partial; jump_T jump; forloop_T forloop; try_T try; diff --git a/src/vim9compile.c b/src/vim9compile.c index 4fb5478443..64ed038009 100644 --- a/src/vim9compile.c +++ b/src/vim9compile.c @@ -705,6 +705,23 @@ generate_PUSHFUNC(cctx_T *cctx, char_u *name) return OK; } +/* + * Generate an ISN_PUSHPARTIAL instruction with partial "part". + * Consumes "name". + */ + static int +generate_PUSHPARTIAL(cctx_T *cctx, partial_T *part) +{ + isn_T *isn; + + if ((isn = generate_instr_type(cctx, ISN_PUSHPARTIAL, + &t_partial_any)) == NULL) + return FAIL; + isn->isn_arg.partial = part; + + return OK; +} + /* * Generate an ISN_STORE instruction. */ @@ -3605,8 +3622,7 @@ compile_assignment(char_u *arg, exarg_T *eap, cmdidx_T cmdidx, cctx_T *cctx) generate_PUSHFUNC(cctx, NULL); break; case VAR_PARTIAL: - // generate_PUSHPARTIAL(cctx, NULL); - emsg("Partial type not supported yet"); + generate_PUSHPARTIAL(cctx, NULL); break; case VAR_LIST: generate_NEWLIST(cctx, 0); @@ -5228,7 +5244,7 @@ delete_instr(isn_T *isn) break; case ISN_PUSHPARTIAL: - // TODO + partial_unref(isn->isn_arg.partial); break; case ISN_PUSHJOB: diff --git a/src/vim9execute.c b/src/vim9execute.c index 9d187c4b44..be19b1f7ff 100644 --- a/src/vim9execute.c +++ b/src/vim9execute.c @@ -873,10 +873,17 @@ call_def_function( break; case ISN_PUSHFUNC: tv->v_type = VAR_FUNC; - tv->vval.v_string = vim_strsave(iptr->isn_arg.string); + if (iptr->isn_arg.string == NULL) + tv->vval.v_string = NULL; + else + tv->vval.v_string = + vim_strsave(iptr->isn_arg.string); break; case ISN_PUSHPARTIAL: - tv->v_type = VAR_UNKNOWN; + tv->v_type = VAR_PARTIAL; + tv->vval.v_partial = iptr->isn_arg.partial; + if (tv->vval.v_partial != NULL) + ++tv->vval.v_partial->pt_refcount; break; case ISN_PUSHCHANNEL: #ifdef FEAT_JOB_CHANNEL @@ -1874,11 +1881,20 @@ ex_disassemble(exarg_T *eap) } break; case ISN_PUSHFUNC: - smsg("%4d PUSHFUNC \"%s\"", current, iptr->isn_arg.string); + { + char *name = (char *)iptr->isn_arg.string; + + smsg("%4d PUSHFUNC \"%s\"", current, + name == NULL ? "[none]" : name); + } break; case ISN_PUSHPARTIAL: - // TODO - smsg("%4d PUSHPARTIAL", current); + { + partial_T *part = iptr->isn_arg.partial; + + smsg("%4d PUSHPARTIAL \"%s\"", current, + part == NULL ? "[none]" : (char *)partial_name(part)); + } break; case ISN_PUSHCHANNEL: #ifdef FEAT_JOB_CHANNEL From 41fe061753923986e6676424132960d970bb2a76 Mon Sep 17 00:00:00 2001 From: Bram Moolenaar Date: Sun, 1 Mar 2020 16:22:40 +0100 Subject: [PATCH 21/63] patch 8.2.0341: using ":for" in Vim9 script gives an error Problem: Using ":for" in Vim9 script gives an error. Solution: Pass the LET_NO_COMMAND flag. (closes #5715) --- src/eval.c | 6 ++++-- src/testdir/test_vim9_script.vim | 14 ++++++++++++++ src/version.c | 2 ++ 3 files changed, 20 insertions(+), 2 deletions(-) diff --git a/src/eval.c b/src/eval.c index c81ece1494..415ed5a9d3 100644 --- a/src/eval.c +++ b/src/eval.c @@ -1491,6 +1491,8 @@ next_for_item(void *fi_void, char_u *arg) { forinfo_T *fi = (forinfo_T *)fi_void; int result; + int flag = current_sctx.sc_version == SCRIPT_VERSION_VIM9 ? + LET_NO_COMMAND : 0; listitem_T *item; if (fi->fi_blob != NULL) @@ -1504,7 +1506,7 @@ next_for_item(void *fi_void, char_u *arg) tv.vval.v_number = blob_get(fi->fi_blob, fi->fi_bi); ++fi->fi_bi; return ex_let_vars(arg, &tv, TRUE, fi->fi_semicolon, - fi->fi_varcount, 0, NULL) == OK; + fi->fi_varcount, flag, NULL) == OK; } item = fi->fi_lw.lw_item; @@ -1514,7 +1516,7 @@ next_for_item(void *fi_void, char_u *arg) { fi->fi_lw.lw_item = item->li_next; result = (ex_let_vars(arg, &item->li_tv, TRUE, fi->fi_semicolon, - fi->fi_varcount, 0, NULL) == OK); + fi->fi_varcount, flag, NULL) == OK); } return result; } diff --git a/src/testdir/test_vim9_script.vim b/src/testdir/test_vim9_script.vim index aace239787..c1865e37f7 100644 --- a/src/testdir/test_vim9_script.vim +++ b/src/testdir/test_vim9_script.vim @@ -775,5 +775,19 @@ def Test_echo_cmd() assert_match('^some more$', Screenline(&lines)) enddef +def Test_for_outside_of_function() + let lines =<< trim END + vim9script + new + for var in range(0, 3) + append(line('$'), var) + endfor + assert_equal(['', '0', '1', '2', '3'], getline(1, '$')) + bwipe! + END + writefile(lines, 'Xvim9for.vim') + source Xvim9for.vim + delete('Xvim9for.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 3d126b068f..d927b4e8c1 100644 --- a/src/version.c +++ b/src/version.c @@ -738,6 +738,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 341, /**/ 340, /**/ From 0546d7df13b041833121b2d56036e1c62ea3b0c1 Mon Sep 17 00:00:00 2001 From: Bram Moolenaar Date: Sun, 1 Mar 2020 16:53:09 +0100 Subject: [PATCH 22/63] patch 8.2.0342: some code in ex_getln.c not covered by tests Problem: Some code in ex_getln.c not covered by tests. Solution: Add more tests. (Yegappan Lakshmanan, closes #5717) --- src/testdir/test_cmdline.vim | 35 +++++++++++++++++++++++++++++++++++ src/testdir/test_ex_mode.vim | 11 +++++++++++ src/testdir/test_history.vim | 11 ++++++++++- src/testdir/test_iminsert.vim | 2 ++ src/version.c | 2 ++ 5 files changed, 60 insertions(+), 1 deletion(-) diff --git a/src/testdir/test_cmdline.vim b/src/testdir/test_cmdline.vim index 8c580262ac..c32a3f03eb 100644 --- a/src/testdir/test_cmdline.vim +++ b/src/testdir/test_cmdline.vim @@ -1188,6 +1188,7 @@ endfunc func Test_cmdline_edit() let str = ":one two\" let str ..= "one two\\" + let str ..= "one\\\" let str ..= "\five\" let str ..= "\two " let str ..= "\one " @@ -1206,6 +1207,7 @@ func Test_cmdline_edit_rightleft() set rightleftcmd=search let str = "/one two\" let str ..= "one two\\" + let str ..= "one\\\" let str ..= "\five\" let str ..= "\two " let str ..= "\one " @@ -1233,4 +1235,37 @@ func Test_cmdline_expr() call assert_equal("\"e \\", @:) endfunc +" Test for 'imcmdline' and 'imsearch' +" This test doesn't actually test the input method functionality. +func Test_cmdline_inputmethod() + new + call setline(1, ['', 'abc', '']) + set imcmdline + + call feedkeys(":\"abc\", 'xt') + call assert_equal("\"abc", @:) + call feedkeys(":\"\abc\\", 'xt') + call assert_equal("\"abc", @:) + call feedkeys("/abc\", 'xt') + call assert_equal([2, 1], [line('.'), col('.')]) + call feedkeys("/\abc\\", 'xt') + call assert_equal([2, 1], [line('.'), col('.')]) + + set imsearch=2 + call cursor(1, 1) + call feedkeys("/abc\", 'xt') + call assert_equal([2, 1], [line('.'), col('.')]) + call cursor(1, 1) + call feedkeys("/\abc\\", 'xt') + call assert_equal([2, 1], [line('.'), col('.')]) + set imdisable + call feedkeys("/\abc\\", 'xt') + call assert_equal([2, 1], [line('.'), col('.')]) + set imdisable& + set imsearch& + + set imcmdline& + %bwipe! +endfunc + " vim: shiftwidth=2 sts=2 expandtab diff --git a/src/testdir/test_ex_mode.vim b/src/testdir/test_ex_mode.vim index 91ba012e15..e88bdf5302 100644 --- a/src/testdir/test_ex_mode.vim +++ b/src/testdir/test_ex_mode.vim @@ -49,6 +49,8 @@ func Test_ex_mode() call assert_equal([' foo', ' foo'], Ex(" foo\"), e) call assert_equal(['foo', ' foo0'], Ex(" foo0\"), e) call assert_equal(['foo', ' foo^'], Ex(" foo^\"), e) + call assert_equal(['foo', 'foo'], + \ Ex("\\\foo"), e) endfor set sw& @@ -128,4 +130,13 @@ func Test_Ex_escape_enter() call assert_equal("a\rb", l) endfunc +" Test for :append! command in Ex mode +func Test_Ex_append() + new + call setline(1, "\t abc") + call feedkeys("Qappend!\npqr\nxyz\n.\nvisual\n", 'xt') + call assert_equal(["\t abc", "\t pqr", "\t xyz"], getline(1, '$')) + close! +endfunc + " vim: shiftwidth=2 sts=2 expandtab diff --git a/src/testdir/test_history.vim b/src/testdir/test_history.vim index 96006ac7e7..0312b5f579 100644 --- a/src/testdir/test_history.vim +++ b/src/testdir/test_history.vim @@ -114,6 +114,7 @@ function Test_Search_history_window() bwipe! endfunc +" Test for :history command option completion function Test_history_completion() call feedkeys(":history \\\"\", 'tx') call assert_equal('"history / : = > ? @ all cmd debug expr input search', @:) @@ -122,8 +123,9 @@ endfunc " Test for increasing the 'history' option value func Test_history_size() let save_histsz = &history - call histdel(':') set history=10 + call histadd(':', 'ls') + call histdel(':') for i in range(1, 5) call histadd(':', 'cmd' .. i) endfor @@ -173,6 +175,13 @@ func Test_history_search() call assert_equal(['pat2', 'pat1', ''], g:pat) cunmap delfunc SavePat + + " Recall patterns with 'history' set to 0 + set history=0 + let @/ = 'abc' + let cmd = 'call feedkeys("/\\\\\", "xt")' + call assert_fails(cmd, 'E486:') + set history& endfunc " Test for making sure the key value is not stored in history diff --git a/src/testdir/test_iminsert.vim b/src/testdir/test_iminsert.vim index fb2ef053bd..1880662af2 100644 --- a/src/testdir/test_iminsert.vim +++ b/src/testdir/test_iminsert.vim @@ -62,3 +62,5 @@ func Test_getimstatus() set imactivatefunc= set imstatusfunc= endfunc + +" vim: shiftwidth=2 sts=2 expandtab diff --git a/src/version.c b/src/version.c index d927b4e8c1..6ecd281ac7 100644 --- a/src/version.c +++ b/src/version.c @@ -738,6 +738,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 342, /**/ 341, /**/ From f51cb4e08ef904d137c27fe7cddb4702d8dcb2a2 Mon Sep 17 00:00:00 2001 From: Bram Moolenaar Date: Sun, 1 Mar 2020 17:55:14 +0100 Subject: [PATCH 23/63] patch 8.2.0343: Vim9: using wrong instruction, limited test coverage Problem: Vim9: using wrong instruction, limited test coverage. Solution: Use ISN_PUSHJOB. Add a few more tests. --- src/testdir/test_vim9_disassemble.vim | 59 +++++++++++++++++++++++++++ src/testdir/test_vim9_script.vim | 1 + src/version.c | 2 + src/vim9compile.c | 2 +- src/vim9execute.c | 2 +- 5 files changed, 64 insertions(+), 2 deletions(-) diff --git a/src/testdir/test_vim9_disassemble.vim b/src/testdir/test_vim9_disassemble.vim index 9196184a6f..7875e847e7 100644 --- a/src/testdir/test_vim9_disassemble.vim +++ b/src/testdir/test_vim9_disassemble.vim @@ -1,5 +1,7 @@ " Test the :disassemble command, and compilation as a side effect +source check.vim + func NotCompiled() echo "not" endfunc @@ -332,6 +334,63 @@ def Test_disassemble_const_expr() assert_notmatch('JUMP', instr) enddef +def WithFunc() + let funky1: func + let funky2: func = function("len") + let party1: partial + let party2: partial = funcref("UserFunc") +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 party1: partial.*' + \ .. '5 PUSHPARTIAL "\[none]".*' + \ .. '6 STORE $2.*' + \ .. 'let party2: partial = funcref("UserFunc").*' + \ .. '7 PUSHS "UserFunc".*' + \ .. '8 BCALL funcref(argc 1).*' + \ .. '9 STORE $3.*' + \ .. '10 PUSHNR 0.*' + \ .. '11 RETURN.*' + \, instr) +enddef + +if has('channel') + def WithChannel() + let job1: job + let job2: job = job_start("donothing") + let chan1: channel + enddef +endif + +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.*' + \, instr) +enddef + def WithLambda(): string let F = {a -> "X" .. a .. "X"} return F("x") diff --git a/src/testdir/test_vim9_script.vim b/src/testdir/test_vim9_script.vim index c1865e37f7..c01ab83164 100644 --- a/src/testdir/test_vim9_script.vim +++ b/src/testdir/test_vim9_script.vim @@ -56,6 +56,7 @@ def Test_assignment() if has('channel') let chan1: channel let job1: job + let job2: job = job_start('willfail') endif if has('float') let float1: float = 3.4 diff --git a/src/version.c b/src/version.c index 6ecd281ac7..56a0aeeef7 100644 --- a/src/version.c +++ b/src/version.c @@ -738,6 +738,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 343, /**/ 342, /**/ diff --git a/src/vim9compile.c b/src/vim9compile.c index 64ed038009..158770c3a4 100644 --- a/src/vim9compile.c +++ b/src/vim9compile.c @@ -666,7 +666,7 @@ generate_PUSHJOB(cctx_T *cctx, job_T *job) { isn_T *isn; - if ((isn = generate_instr_type(cctx, ISN_PUSHCHANNEL, &t_channel)) == NULL) + if ((isn = generate_instr_type(cctx, ISN_PUSHJOB, &t_channel)) == NULL) return FAIL; isn->isn_arg.job = job; diff --git a/src/vim9execute.c b/src/vim9execute.c index be19b1f7ff..094ee72ce9 100644 --- a/src/vim9execute.c +++ b/src/vim9execute.c @@ -1915,7 +1915,7 @@ ex_disassemble(exarg_T *eap) tv.v_type = VAR_JOB; tv.vval.v_job = iptr->isn_arg.job; name = tv_get_string(&tv); - smsg("%4d PUSHJOB %s", current, name); + smsg("%4d PUSHJOB \"%s\"", current, name); } #endif break; From eab6dff19f387469a200011bc6cf3508f5e43a4a Mon Sep 17 00:00:00 2001 From: Bram Moolenaar Date: Sun, 1 Mar 2020 19:06:45 +0100 Subject: [PATCH 24/63] Update runtime files --- runtime/autoload/xmlformat.vim | 65 ++- runtime/doc/cmdline.txt | 6 +- runtime/doc/helphelp.txt | 13 +- runtime/doc/syntax.txt | 8 +- runtime/doc/tags | 2 + runtime/doc/todo.txt | 11 +- runtime/doc/usr_03.txt | 5 +- runtime/doc/vim9.txt | 2 +- .../dist/opt/matchit/autoload/matchit.vim | 4 +- runtime/pack/dist/opt/matchit/doc/matchit.txt | 2 +- .../pack/dist/opt/matchit/plugin/matchit.vim | 2 +- src/po/de.po | 490 ++++++++++++++---- 12 files changed, 460 insertions(+), 150 deletions(-) diff --git a/runtime/autoload/xmlformat.vim b/runtime/autoload/xmlformat.vim index 30b09f1261..c89c8784b9 100644 --- a/runtime/autoload/xmlformat.vim +++ b/runtime/autoload/xmlformat.vim @@ -1,6 +1,6 @@ " Vim plugin for formatting XML -" Last Change: 2019 Oct 24 -" Version: 0.2 +" Last Change: 2020 Jan 06 +" Version: 0.3 " Author: Christian Brabandt " Repository: https://github.com/chrisbra/vim-xml-ftplugin " License: VIM License @@ -15,7 +15,7 @@ let s:keepcpo = &cpo set cpo&vim " Main function: Format the input {{{1 -func! xmlformat#Format() +func! xmlformat#Format() abort " only allow reformatting through the gq command " (e.g. Vim is in normal mode) if mode() != 'n' @@ -40,14 +40,16 @@ func! xmlformat#Format() continue elseif line !~# '<[/]\?[^>]*>' let nextmatch = match(list, '<[/]\?[^>]*>', current) - let line .= join(list[(current + 1):(nextmatch-1)], "\n") - call remove(list, current+1, nextmatch-1) + if nextmatch > -1 + let line .= ' '. join(list[(current + 1):(nextmatch-1)], " ") + call remove(list, current+1, nextmatch-1) + endif endif " split on `>`, but don't split on very first opening < " this means, items can be like ['', 'tag content'] for item in split(line, '.\@<=[>]\zs') if s:EndTag(item) - let s:indent = s:DecreaseIndent() + call s:DecreaseIndent() call add(result, s:Indent(item)) elseif s:EmptyTag(lastitem) call add(result, s:Indent(item)) @@ -59,13 +61,23 @@ func! xmlformat#Format() " Simply split on '<', if there is one, " but reformat according to &textwidth let t=split(item, '.<\@=\zs') + + " if the content fits well within a single line, add it there + " so that the output looks like this: + " + " 1 + if s:TagContent(lastitem) is# s:TagContent(t[1]) && strlen(result[-1]) + strlen(item) <= s:Textwidth() + let result[-1] .= item + let lastitem = t[1] + continue + endif " t should only contain 2 items, but just be safe here if s:IsTag(lastitem) let s:indent+=1 endif let result+=s:FormatContent([t[0]]) if s:EndTag(t[1]) - let s:indent = s:DecreaseIndent() + call s:DecreaseIndent() endif "for y in t[1:] let result+=s:FormatContent(t[1:]) @@ -97,15 +109,15 @@ func! xmlformat#Format() return 0 endfunc " Check if given tag is XML Declaration header {{{1 -func! s:IsXMLDecl(tag) +func! s:IsXMLDecl(tag) abort return a:tag =~? '^\s*\s*$' endfunc " Return tag indented by current level {{{1 -func! s:Indent(item) +func! s:Indent(item) abort return repeat(' ', shiftwidth()*s:indent). s:Trim(a:item) endfu " Return item trimmed from leading whitespace {{{1 -func! s:Trim(item) +func! s:Trim(item) abort if exists('*trim') return trim(a:item) else @@ -113,44 +125,53 @@ func! s:Trim(item) endif endfunc " Check if tag is a new opening tag {{{1 -func! s:StartTag(tag) +func! s:StartTag(tag) abort let is_comment = s:IsComment(a:tag) return a:tag =~? '^\s*<[^/?]' && !is_comment endfunc " Check if tag is a Comment start {{{1 -func! s:IsComment(tag) +func! s:IsComment(tag) abort return a:tag =~? '