changeset 20015:c001ee73519a v8.2.0563

patch 8.2.0563: Vim9: cannot split a function line Commit: https://github.com/vim/vim/commit/5e774c7579a4a00d3f44fdcfcb56861bd73372e4 Author: Bram Moolenaar <Bram@vim.org> 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.
author Bram Moolenaar <Bram@vim.org>
date Sun, 12 Apr 2020 22:00:04 +0200
parents 1609b2b2733d
children 90d957ae667c
files runtime/doc/vim9.txt src/proto/userfunc.pro src/testdir/test_vim9_func.vim src/userfunc.c src/version.c src/vim9compile.c
diffstat 6 files changed, 69 insertions(+), 12 deletions(-) [+]
line wrap: on
line diff
--- 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 ~
 
--- 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);
--- 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>
+      ): 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()
--- 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;
 }
--- 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,
--- 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