# HG changeset patch # User Bram Moolenaar # Date 1586721604 -7200 # Node ID c001ee73519a76b651e479a8db16ce6b196ccb3c # Parent 1609b2b2733d9ac182dc996616aacda2dc29a74c patch 8.2.0563: Vim9: cannot split a function line Commit: https://github.com/vim/vim/commit/5e774c7579a4a00d3f44fdcfcb56861bd73372e4 Author: Bram Moolenaar Date: Sun Apr 12 21:53:00 2020 +0200 patch 8.2.0563: Vim9: cannot split a function line Problem: Vim9: cannot split a function line. Solution: Continue in next line so long as the function isn't done. diff --git a/runtime/doc/vim9.txt b/runtime/doc/vim9.txt --- a/runtime/doc/vim9.txt +++ b/runtime/doc/vim9.txt @@ -210,6 +210,13 @@ possible AFTER the operators. For examp Note that "enddef" cannot be used at the start of a continuation line, it ends the current function. +It is also possible to split a function header over multiple lines, in between +arguments: > + def MyFunc( + text: string, + separator = '-' + ): string + No curly braces expansion ~ diff --git a/src/proto/userfunc.pro b/src/proto/userfunc.pro --- a/src/proto/userfunc.pro +++ b/src/proto/userfunc.pro @@ -1,7 +1,7 @@ /* userfunc.c */ void func_init(void); hashtab_T *func_tbl_get(void); -int get_function_args(char_u **argp, char_u endchar, garray_T *newargs, garray_T *argtypes, int *varargs, garray_T *default_args, int skip); +int get_function_args(char_u **argp, char_u endchar, garray_T *newargs, garray_T *argtypes, int *varargs, garray_T *default_args, int skip, exarg_T *eap, char_u **line_to_free); int get_lambda_tv(char_u **arg, typval_T *rettv, int evaluate); char_u *deref_func_name(char_u *name, int *lenp, partial_T **partialp, int no_autoload); void emsg_funcname(char *ermsg, char_u *name); diff --git a/src/testdir/test_vim9_func.vim b/src/testdir/test_vim9_func.vim --- a/src/testdir/test_vim9_func.vim +++ b/src/testdir/test_vim9_func.vim @@ -561,6 +561,22 @@ def Test_func_return_type() CheckDefFailure(['let str: string', 'str = FuncNoArgRetNumber()'], 'E1013: type mismatch, expected string but got number') enddef +def MultiLine( + arg1: string, + arg2 = 1234, + ...rest: list + ): string + return arg1 .. arg2 .. join(rest, '-') +enddef + +def Test_multiline() + assert_equal('text1234', MultiLine('text')) + assert_equal('text777', MultiLine('text', 777)) + assert_equal('text777one', MultiLine('text', 777, 'one')) + assert_equal('text777one-two', MultiLine('text', 777, 'one', 'two')) +enddef + + " When using CheckScriptFailure() for the below test, E1010 is generated instead " of E1056. func Test_E1056_1059() diff --git a/src/userfunc.c b/src/userfunc.c --- a/src/userfunc.c +++ b/src/userfunc.c @@ -144,7 +144,9 @@ get_function_args( garray_T *argtypes, // NULL unless using :def int *varargs, garray_T *default_args, - int skip) + int skip, + exarg_T *eap, + char_u **line_to_free) { int mustend = FALSE; char_u *arg = *argp; @@ -168,6 +170,28 @@ get_function_args( */ while (*p != endchar) { + if (eap != NULL && *p == NUL && eap->getline != NULL) + { + char_u *theline; + + // End of the line, get the next one. + theline = eap->getline(':', eap->cookie, 0, TRUE); + if (theline == NULL) + break; + vim_free(*line_to_free); + *line_to_free = theline; + p = skipwhite(theline); + } + + if (mustend && *p != endchar) + { + if (!skip) + semsg(_(e_invarg2), *argp); + break; + } + if (*p == endchar) + break; + if (p[0] == '.' && p[1] == '.' && p[2] == '.') { if (varargs != NULL) @@ -241,13 +265,8 @@ get_function_args( mustend = TRUE; } p = skipwhite(p); - if (mustend && *p != endchar) - { - if (!skip) - semsg(_(e_invarg2), *argp); - break; - } } + if (*p != endchar) goto err_ret; ++p; // skip "endchar" @@ -323,7 +342,8 @@ get_lambda_tv(char_u **arg, typval_T *re ga_init(&newlines); // First, check if this is a lambda expression. "->" must exist. - ret = get_function_args(&start, '-', NULL, NULL, NULL, NULL, TRUE); + ret = get_function_args(&start, '-', NULL, NULL, NULL, NULL, TRUE, + NULL, NULL); if (ret == FAIL || *start != '>') return NOTDONE; @@ -334,7 +354,8 @@ get_lambda_tv(char_u **arg, typval_T *re pnewargs = NULL; *arg = skipwhite(*arg + 1); // TODO: argument types - ret = get_function_args(arg, '-', pnewargs, NULL, &varargs, NULL, FALSE); + ret = get_function_args(arg, '-', pnewargs, NULL, &varargs, NULL, FALSE, + NULL, NULL); if (ret == FAIL || **arg != '>') goto errret; @@ -2508,9 +2529,12 @@ ex_function(exarg_T *eap) emsg(_("E862: Cannot use g: here")); } + // This may get more lines and make the pointers into the first line + // invalid. if (get_function_args(&p, ')', &newargs, eap->cmdidx == CMD_def ? &argtypes : NULL, - &varargs, &default_args, eap->skip) == FAIL) + &varargs, &default_args, eap->skip, + eap, &line_to_free) == FAIL) goto errret_2; if (eap->cmdidx == CMD_def) @@ -2521,9 +2545,15 @@ ex_function(exarg_T *eap) ret_type = skipwhite(p + 1); p = skip_type(ret_type); if (p > ret_type) + { + ret_type = vim_strnsave(ret_type, (int)(p - ret_type)); p = skipwhite(p); + } else + { + ret_type = NULL; semsg(_("E1056: expected a type: %s"), ret_type); + } } } else @@ -3134,6 +3164,7 @@ ret_free: vim_free(line_to_free); vim_free(fudi.fd_newkey); vim_free(name); + vim_free(ret_type); did_emsg |= saved_did_emsg; need_wait_return |= saved_wait_return; } diff --git a/src/version.c b/src/version.c --- a/src/version.c +++ b/src/version.c @@ -739,6 +739,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ /**/ + 563, +/**/ 562, /**/ 561, diff --git a/src/vim9compile.c b/src/vim9compile.c --- a/src/vim9compile.c +++ b/src/vim9compile.c @@ -3275,8 +3275,9 @@ compile_expr7(char_u **arg, cctx_T *cctx char_u *start = skipwhite(*arg + 1); // Find out what comes after the arguments. + // TODO: pass getline function ret = get_function_args(&start, '-', NULL, - NULL, NULL, NULL, TRUE); + NULL, NULL, NULL, TRUE, NULL, NULL); if (ret != FAIL && *start == '>') ret = compile_lambda(arg, cctx); else