changeset 22691:dda110a14be4 v8.2.1894

patch 8.2.1894: Vim9: command modifiers are not supported Commit: https://github.com/vim/vim/commit/f4c6e1e75c2a7f2ca3a7f4529e7da31dc98557e9 Author: Bram Moolenaar <Bram@vim.org> Date: Fri Oct 23 18:02:32 2020 +0200 patch 8.2.1894: Vim9: command modifiers are not supported Problem: Vim9: command modifiers are not supported. Solution: Support "silent" and "silent!".
author Bram Moolenaar <Bram@vim.org>
date Fri, 23 Oct 2020 18:15:03 +0200
parents 3b5c9b442a73
children e3c3096f7e64
files src/evalvars.c src/structs.h src/testdir/test_vim9_cmd.vim src/testdir/test_vim9_disassemble.vim src/version.c src/vim9.h src/vim9compile.c src/vim9execute.c
diffstat 8 files changed, 120 insertions(+), 3 deletions(-) [+]
line wrap: on
line diff
--- a/src/evalvars.c
+++ b/src/evalvars.c
@@ -3577,9 +3577,11 @@ var_redir_start(char_u *name, int append
     tv.v_type = VAR_STRING;
     tv.vval.v_string = (char_u *)"";
     if (append)
-	set_var_lval(redir_lval, redir_endp, &tv, TRUE, 0, (char_u *)".");
+	set_var_lval(redir_lval, redir_endp, &tv, TRUE,
+						ASSIGN_NO_DECL, (char_u *)".");
     else
-	set_var_lval(redir_lval, redir_endp, &tv, TRUE, 0, (char_u *)"=");
+	set_var_lval(redir_lval, redir_endp, &tv, TRUE,
+						ASSIGN_NO_DECL, (char_u *)"=");
     clear_lval(redir_lval);
     if (called_emsg > called_emsg_before)
     {
--- a/src/structs.h
+++ b/src/structs.h
@@ -643,6 +643,8 @@ typedef struct
     char_u	*save_ei;		// saved value of 'eventignore'
     regmatch_T	filter_regmatch;	// set by :filter /pat/
     int		filter_force;		// set for :filter!
+    int		msg_silent;		// TRUE when ":silent" was used
+    int		emsg_silent;		// TRUE when ":silent!" was used
 } cmdmod_T;
 
 #define MF_SEED_LEN	8
--- a/src/testdir/test_vim9_cmd.vim
+++ b/src/testdir/test_vim9_cmd.vim
@@ -401,5 +401,17 @@ def Test_f_args()
   CheckScriptSuccess(lines)
 enddef
 
+def Test_modifier_silent()
+  echomsg 'last one'
+  silent echomsg "text"
+  redir => g:testmsg
+    :1messages
+  redir END
+  assert_equal("\nlast one", g:testmsg)
+  unlet g:testmsg
+
+  silent! echoerr "error"
+enddef
+
 
 " vim: ts=8 sw=2 sts=2 expandtab tw=80 fdm=marker
--- a/src/testdir/test_vim9_disassemble.vim
+++ b/src/testdir/test_vim9_disassemble.vim
@@ -1617,4 +1617,28 @@ def Test_shuffle()
         res)
 enddef
 
+
+def s:SilentMessage()
+  silent echomsg "text"
+  silent! echoerr "error"
+enddef
+
+def Test_silent()
+  var res = execute('disass s:SilentMessage')
+  assert_match('<SNR>\d*_SilentMessage\_s*' ..
+        'silent echomsg "text"\_s*' ..
+        '\d SILENT\_s*' ..
+        '\d PUSHS "text"\_s*' ..
+        '\d ECHOMSG 1\_s*' ..
+        '\d UNSILENT\_s*' ..
+        'silent! echoerr "error"\_s*' ..
+        '\d SILENT!\_s*' ..
+        '\d PUSHS "error"\_s*' ..
+        '\d ECHOERR 1\_s*' ..
+        '\d UNSILENT!\_s*' ..
+        '\d PUSHNR 0\_s*' ..
+        '\d RETURN',
+        res)
+enddef
+
 " vim: ts=8 sw=2 sts=2 expandtab tw=80 fdm=marker
--- a/src/version.c
+++ b/src/version.c
@@ -751,6 +751,8 @@ static char *(features[]) =
 static int included_patches[] =
 {   /* Add new patch number below this line */
 /**/
+    1894,
+/**/
     1893,
 /**/
     1892,
--- a/src/vim9.h
+++ b/src/vim9.h
@@ -142,6 +142,9 @@ typedef enum {
 
     ISN_PUT,	    // ":put", uses isn_arg.put
 
+    ISN_SILENT,	    // set msg_silent or emsg_silent if arg_number is non-zero
+    ISN_UNSILENT,   // undo ISN_SILENT
+
     ISN_SHUFFLE,    // move item on stack up or down
     ISN_DROP	    // pop stack and discard value
 } isntype_T;
--- a/src/vim9compile.c
+++ b/src/vim9compile.c
@@ -141,6 +141,8 @@ struct cctx_S {
 
     garray_T	ctx_type_stack;	    // type of each item on the stack
     garray_T	*ctx_type_list;	    // list of pointers to allocated types
+
+    int		ctx_silent;	    // set when ISN_SILENT was generated
 };
 
 static void delete_def_function_contents(dfunc_T *dfunc);
@@ -1821,6 +1823,40 @@ generate_EXECCONCAT(cctx_T *cctx, int co
 }
 
 /*
+ * Generate any instructions for side effects of "cmdmod".
+ */
+    static int
+generate_cmdmods(cctx_T *cctx)
+{
+    isn_T	*isn;
+
+    // TODO: use more modifiers in the command
+    if (cmdmod.msg_silent || cmdmod.emsg_silent)
+    {
+	if ((isn = generate_instr(cctx, ISN_SILENT)) == NULL)
+	    return FAIL;
+	isn->isn_arg.number = cmdmod.emsg_silent;
+	cctx->ctx_silent = cmdmod.emsg_silent ? 2 : 1;
+    }
+    return OK;
+}
+
+    static int
+generate_restore_cmdmods(cctx_T *cctx)
+{
+    isn_T	*isn;
+
+    if (cctx->ctx_silent > 0)
+    {
+	if ((isn = generate_instr(cctx, ISN_UNSILENT)) == NULL)
+	    return FAIL;
+	isn->isn_arg.number = cctx->ctx_silent == 2;
+	cctx->ctx_silent = 0;
+    }
+    return OK;
+}
+
+/*
  * Reserve space for a local variable.
  * Return the variable or NULL if it failed.
  */
@@ -7149,7 +7185,8 @@ compile_def_function(ufunc_T *ufunc, int
 	    line = (char_u *)"";
 	    continue;
 	}
-	// TODO: use modifiers in the command
+	generate_cmdmods(&cctx);
+
 	undo_cmdmod(&ea, save_msg_scroll);
 	cmdmod = save_cmdmod;
 
@@ -7461,6 +7498,9 @@ nextline:
 	    goto erret;
 	line = skipwhite(line);
 
+	// Undo any command modifiers.
+	generate_restore_cmdmods(&cctx);
+
 	if (cctx.ctx_type_stack.ga_len < 0)
 	{
 	    iemsg("Type stack underflow");
@@ -7767,6 +7807,7 @@ delete_instr(isn_T *isn)
 	case ISN_PUT:
 	case ISN_RETURN:
 	case ISN_SHUFFLE:
+	case ISN_SILENT:
 	case ISN_SLICE:
 	case ISN_STORE:
 	case ISN_STOREDICT:
@@ -7780,6 +7821,7 @@ delete_instr(isn_T *isn)
 	case ISN_STRSLICE:
 	case ISN_THROW:
 	case ISN_TRY:
+	case ISN_UNSILENT:
 	    // nothing allocated
 	    break;
     }
--- a/src/vim9execute.c
+++ b/src/vim9execute.c
@@ -832,6 +832,8 @@ call_def_function(
     int		save_suppress_errthrow = suppress_errthrow;
     msglist_T	**saved_msg_list = NULL;
     msglist_T	*private_msg_list = NULL;
+    int		save_msg_silent = -1;
+    int		save_emsg_silent = -1;
 
 // Get pointer to item in the stack.
 #define STACK_TV(idx) (((typval_T *)ectx.ec_stack.ga_data) + idx)
@@ -2814,6 +2816,24 @@ call_def_function(
 		}
 		break;
 
+	    case ISN_SILENT:
+		if (save_msg_silent == -1)
+		    save_msg_silent = msg_silent;
+		++msg_silent;
+		if (iptr->isn_arg.number)
+		{
+		    if (save_emsg_silent == -1)
+			save_emsg_silent = emsg_silent;
+		    ++emsg_silent;
+		}
+		break;
+
+	    case ISN_UNSILENT:
+		--msg_silent;
+		if (iptr->isn_arg.number)
+		    --emsg_silent;
+		break;
+
 	    case ISN_SHUFFLE:
 		{
 		    typval_T	    tmp_tv;
@@ -2885,6 +2905,11 @@ failed:
     }
     msg_list = saved_msg_list;
 
+    if (save_msg_silent != -1)
+	msg_silent = save_msg_silent;
+    if (save_emsg_silent != -1)
+	emsg_silent = save_emsg_silent;
+
 failed_early:
     // Free all local variables, but not arguments.
     for (idx = 0; idx < ectx.ec_stack.ga_len; ++idx)
@@ -3502,6 +3527,11 @@ ex_disassemble(exarg_T *eap)
 					     (long)iptr->isn_arg.put.put_lnum);
 		break;
 
+	    case ISN_SILENT: smsg("%4d SILENT%s", current,
+				       iptr->isn_arg.number ? "!" : ""); break;
+	    case ISN_UNSILENT: smsg("%4d UNSILENT%s", current,
+				       iptr->isn_arg.number ? "!" : ""); break;
+
 	    case ISN_SHUFFLE: smsg("%4d SHUFFLE %d up %d", current,
 					 iptr->isn_arg.shuffle.shfl_item,
 					 iptr->isn_arg.shuffle.shfl_up);