changeset 28934:a712ea475390 v8.2.4989

patch 8.2.4989: cannot specify a function name for :defcompile Commit: https://github.com/vim/vim/commit/f79d9dd43f6fe05711d7e2616ab4b8bde2ccb089 Author: Bram Moolenaar <Bram@vim.org> Date: Sat May 21 15:39:02 2022 +0100 patch 8.2.4989: cannot specify a function name for :defcompile Problem: Cannot specify a function name for :defcompile. Solution: Implement a function name argument for :defcompile.
author Bram Moolenaar <Bram@vim.org>
date Sat, 21 May 2022 16:45:03 +0200
parents 57c9377b9c62
children 4b587312c133
files runtime/doc/vim9.txt src/ex_cmds.h src/proto/userfunc.pro src/testdir/test_vim9_cmd.vim src/testdir/test_vim9_disassemble.vim src/userfunc.c src/version.c src/vim9execute.c
diffstat 8 files changed, 129 insertions(+), 67 deletions(-) [+]
line wrap: on
line diff
--- a/runtime/doc/vim9.txt
+++ b/runtime/doc/vim9.txt
@@ -1210,7 +1210,14 @@ prefix if they do not exist at the time 
 						*:defc* *:defcompile*
 :defc[ompile]		Compile functions defined in the current script that
 			were not compiled yet.
-			This will report errors found during the compilation.
+			This will report any errors found during compilation.
+
+:defc[ompile] {func}
+:defc[ompile] debug {func}
+:defc[ompile] profile {func}
+			Compile function {func}, if needed.  Use "debug" and
+			"profile" to specify the compilation mode.
+			This will report any errors found during compilation.
 
 						*:disa* *:disassemble*
 :disa[ssemble] {func}	Show the instructions generated for {func}.
--- a/src/ex_cmds.h
+++ b/src/ex_cmds.h
@@ -465,7 +465,7 @@ EXCMD(CMD_def,		"def",		ex_function,
 	EX_EXTRA|EX_BANG|EX_SBOXOK|EX_CMDWIN|EX_LOCK_OK,
 	ADDR_NONE),
 EXCMD(CMD_defcompile,	"defcompile",	ex_defcompile,
-	EX_SBOXOK|EX_CMDWIN|EX_LOCK_OK|EX_TRLBAR,
+	EX_SBOXOK|EX_CMDWIN|EX_LOCK_OK|EX_TRLBAR|EX_EXTRA,
 	ADDR_NONE),
 EXCMD(CMD_delcommand,	"delcommand",	ex_delcommand,
 	EX_NEEDARG|EX_WORD1|EX_TRLBAR|EX_CMDWIN|EX_LOCK_OK,
--- a/src/proto/userfunc.pro
+++ b/src/proto/userfunc.pro
@@ -45,6 +45,7 @@ char_u *save_function_name(char_u **name
 void list_functions(regmatch_T *regmatch);
 ufunc_T *define_function(exarg_T *eap, char_u *name_arg, garray_T *lines_to_free);
 void ex_function(exarg_T *eap);
+ufunc_T *find_func_by_name(char_u *name, compiletype_T *compile_type);
 void ex_defcompile(exarg_T *eap);
 int eval_fname_script(char_u *p);
 int translated_function_exists(char_u *name, int is_global);
--- a/src/testdir/test_vim9_cmd.vim
+++ b/src/testdir/test_vim9_cmd.vim
@@ -83,6 +83,16 @@ def Test_vim9cmd()
   v9.CheckScriptSuccess(lines)
 enddef
 
+def Test_defcompile_fails()
+  assert_fails('defcompile NotExists', 'E1061:')
+  assert_fails('defcompile debug debug Test_defcompile_fails', 'E488:')
+  assert_fails('defcompile profile profile Test_defcompile_fails', 'E488:')
+enddef
+
+defcompile Test_defcompile_fails
+defcompile debug Test_defcompile_fails
+defcompile profile Test_defcompile_fails
+
 def Test_cmdmod_execute()
   # "legacy" applies not only to the "exe" argument but also to the commands
   var lines =<< trim END
--- a/src/testdir/test_vim9_disassemble.vim
+++ b/src/testdir/test_vim9_disassemble.vim
@@ -43,6 +43,9 @@ def Test_disassemble_load()
   assert_fails('disass [', 'E475:')
   assert_fails('disass 234', 'E129:')
   assert_fails('disass <XX>foo', 'E129:')
+  assert_fails('disass Test_disassemble_load burp', 'E488:')
+  assert_fails('disass debug debug Test_disassemble_load', 'E488:')
+  assert_fails('disass profile profile Test_disassemble_load', 'E488:')
 
   var res = execute('disass s:ScriptFuncLoad')
   assert_match('<SNR>\d*_ScriptFuncLoad.*' ..
--- a/src/userfunc.c
+++ b/src/userfunc.c
@@ -4997,36 +4997,115 @@ ex_function(exarg_T *eap)
 }
 
 /*
+ * Find a function by name, including "<lambda>123".
+ * Check for "profile" and "debug" arguments and set"compile_type".
+ * Return NULL if not found.
+ */
+    ufunc_T *
+find_func_by_name(char_u *name, compiletype_T *compile_type)
+{
+    char_u	*arg = name;
+    char_u	*fname;
+    ufunc_T	*ufunc;
+    int		is_global = FALSE;
+
+    *compile_type = CT_NONE;
+    if (STRNCMP(arg, "profile", 7) == 0 && VIM_ISWHITE(arg[7]))
+    {
+	*compile_type = CT_PROFILE;
+	arg = skipwhite(arg + 7);
+    }
+    else if (STRNCMP(arg, "debug", 5) == 0 && VIM_ISWHITE(arg[5]))
+    {
+	*compile_type = CT_DEBUG;
+	arg = skipwhite(arg + 5);
+    }
+
+    if (STRNCMP(arg, "<lambda>", 8) == 0)
+    {
+	arg += 8;
+	(void)getdigits(&arg);
+	fname = vim_strnsave(name, arg - name);
+    }
+    else
+	fname = trans_function_name(&arg, &is_global, FALSE,
+		      TFN_INT | TFN_QUIET | TFN_NO_AUTOLOAD, NULL, NULL, NULL);
+    if (fname == NULL)
+    {
+	semsg(_(e_invalid_argument_str), name);
+	return NULL;
+    }
+    if (!ends_excmd2(name, arg))
+    {
+	emsg(ex_errmsg(e_trailing_characters_str, arg));
+	return NULL;
+    }
+
+    ufunc = find_func(fname, is_global);
+    if (ufunc == NULL)
+    {
+	char_u *p = untrans_function_name(fname);
+
+	if (p != NULL)
+	    // Try again without making it script-local.
+	    ufunc = find_func(p, FALSE);
+    }
+    vim_free(fname);
+    if (ufunc == NULL)
+	semsg(_(e_cannot_find_function_str), name);
+    return ufunc;
+}
+
+/*
  * :defcompile - compile all :def functions in the current script that need to
- * be compiled.  Except dead functions.  Doesn't do profiling.
+ * be compiled or the one specified by the argument.
+ * Skips dead functions.  Doesn't do profiling.
  */
     void
-ex_defcompile(exarg_T *eap UNUSED)
+ex_defcompile(exarg_T *eap)
 {
-    long	todo = (long)func_hashtab.ht_used;
-    int		changed = func_hashtab.ht_changed;
-    hashitem_T	*hi;
     ufunc_T	*ufunc;
 
-    for (hi = func_hashtab.ht_array; todo > 0 && !got_int; ++hi)
-    {
-	if (!HASHITEM_EMPTY(hi))
+    if (*eap->arg != NUL)
+    {
+	compiletype_T compile_type;
+
+	ufunc = find_func_by_name(eap->arg, &compile_type);
+	if (ufunc != NULL)
 	{
-	    --todo;
-	    ufunc = HI2UF(hi);
-	    if (ufunc->uf_script_ctx.sc_sid == current_sctx.sc_sid
-		    && ufunc->uf_def_status == UF_TO_BE_COMPILED
-		    && (ufunc->uf_flags & FC_DEAD) == 0)
+	    if (func_needs_compiling(ufunc, compile_type))
+		(void)compile_def_function(ufunc, FALSE, compile_type, NULL);
+	    else
+		smsg(_("Function %s does not need compiling"), eap->arg);
+	}
+    }
+    else
+    {
+	long	todo = (long)func_hashtab.ht_used;
+	int		changed = func_hashtab.ht_changed;
+	hashitem_T	*hi;
+
+	for (hi = func_hashtab.ht_array; todo > 0 && !got_int; ++hi)
+	{
+	    if (!HASHITEM_EMPTY(hi))
 	    {
-		(void)compile_def_function(ufunc, FALSE, CT_NONE, NULL);
-
-		if (func_hashtab.ht_changed != changed)
+		--todo;
+		ufunc = HI2UF(hi);
+		if (ufunc->uf_script_ctx.sc_sid == current_sctx.sc_sid
+			&& ufunc->uf_def_status == UF_TO_BE_COMPILED
+			&& (ufunc->uf_flags & FC_DEAD) == 0)
 		{
-		    // a function has been added or removed, need to start over
-		    todo = (long)func_hashtab.ht_used;
-		    changed = func_hashtab.ht_changed;
-		    hi = func_hashtab.ht_array;
-		    --hi;
+		    (void)compile_def_function(ufunc, FALSE, CT_NONE, NULL);
+
+		    if (func_hashtab.ht_changed != changed)
+		    {
+			// a function has been added or removed, need to start
+			// over
+			todo = (long)func_hashtab.ht_used;
+			changed = func_hashtab.ht_changed;
+			hi = func_hashtab.ht_array;
+			--hi;
+		    }
 		}
 	    }
 	}
--- a/src/version.c
+++ b/src/version.c
@@ -747,6 +747,8 @@ static char *(features[]) =
 static int included_patches[] =
 {   /* Add new patch number below this line */
 /**/
+    4989,
+/**/
     4988,
 /**/
     4987,
--- a/src/vim9execute.c
+++ b/src/vim9execute.c
@@ -6277,55 +6277,15 @@ get_disassemble_argument(expand_T *xp, i
 ex_disassemble(exarg_T *eap)
 {
     char_u	*arg = eap->arg;
-    char_u	*fname;
     ufunc_T	*ufunc;
     dfunc_T	*dfunc;
     isn_T	*instr;
     int		instr_count;
-    int		is_global = FALSE;
-    compiletype_T compile_type = CT_NONE;
-
-    if (STRNCMP(arg, "profile", 7) == 0 && VIM_ISWHITE(arg[7]))
-    {
-	compile_type = CT_PROFILE;
-	arg = skipwhite(arg + 7);
-    }
-    else if (STRNCMP(arg, "debug", 5) == 0 && VIM_ISWHITE(arg[5]))
-    {
-	compile_type = CT_DEBUG;
-	arg = skipwhite(arg + 5);
-    }
-
-    if (STRNCMP(arg, "<lambda>", 8) == 0)
-    {
-	arg += 8;
-	(void)getdigits(&arg);
-	fname = vim_strnsave(eap->arg, arg - eap->arg);
-    }
-    else
-	fname = trans_function_name(&arg, &is_global, FALSE,
-		      TFN_INT | TFN_QUIET | TFN_NO_AUTOLOAD, NULL, NULL, NULL);
-    if (fname == NULL)
-    {
-	semsg(_(e_invalid_argument_str), eap->arg);
+    compiletype_T compile_type;
+
+    ufunc = find_func_by_name(arg, &compile_type);
+    if (ufunc == NULL)
 	return;
-    }
-
-    ufunc = find_func(fname, is_global);
-    if (ufunc == NULL)
-    {
-	char_u *p = untrans_function_name(fname);
-
-	if (p != NULL)
-	    // Try again without making it script-local.
-	    ufunc = find_func(p, FALSE);
-    }
-    vim_free(fname);
-    if (ufunc == NULL)
-    {
-	semsg(_(e_cannot_find_function_str), eap->arg);
-	return;
-    }
     if (func_needs_compiling(ufunc, compile_type)
 	    && compile_def_function(ufunc, FALSE, compile_type, NULL) == FAIL)
 	return;