summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBram Moolenaar <Bram@vim.org>2020-12-05 21:22:08 +0100
committerBram Moolenaar <Bram@vim.org>2020-12-05 21:22:08 +0100
commit56602ba153af7130b76daf83933922aaea3e2646 (patch)
tree13cf686a65d3673353517f66f2d9ad88f336cb8b
parentf665e97ffa06817975810cb511b13dbaa83ec630 (diff)
downloadvim-git-56602ba153af7130b76daf83933922aaea3e2646.tar.gz
patch 8.2.2097: Vim9: using :silent! when calling a function prevents abortv8.2.2097
Problem: Vim9: using :silent! when calling a function prevents abortng that function. Solution: Add emsg_silent_def and did_emsg_def.
-rw-r--r--src/globals.h6
-rw-r--r--src/message.c6
-rw-r--r--src/testdir/test_vim9_func.vim16
-rw-r--r--src/version.c2
-rw-r--r--src/vim9execute.c15
5 files changed, 43 insertions, 2 deletions
diff --git a/src/globals.h b/src/globals.h
index af1a85c82..4f54d0fae 100644
--- a/src/globals.h
+++ b/src/globals.h
@@ -230,6 +230,8 @@ EXTERN int did_endif INIT(= FALSE); // just had ":endif"
EXTERN int did_emsg; // set by emsg() when the message
// is displayed or thrown
#ifdef FEAT_EVAL
+EXTERN int did_emsg_def; // set by emsg() when emsg_silent
+ // is set before calling a function
EXTERN int did_emsg_cumul; // cumulative did_emsg, increased
// when did_emsg is reset.
EXTERN int called_vim_beep; // set if vim_beep() is called
@@ -1134,6 +1136,10 @@ EXTERN int is_export INIT(= FALSE); // :export {cmd}
EXTERN int msg_silent INIT(= 0); // don't print messages
EXTERN int emsg_silent INIT(= 0); // don't print error messages
+#ifdef FEAT_EVAL
+EXTERN int emsg_silent_def INIT(= 0); // value of emsg_silent when a :def
+ // function is called
+#endif
EXTERN int emsg_noredir INIT(= 0); // don't redirect error messages
EXTERN int cmd_silent INIT(= FALSE); // don't echo the command line
diff --git a/src/message.c b/src/message.c
index 43e7e5e52..e4f96d0de 100644
--- a/src/message.c
+++ b/src/message.c
@@ -697,6 +697,12 @@ emsg_core(char_u *s)
}
redir_write(s, -1);
}
+#ifdef FEAT_EVAL
+ // Only increment did_emsg_def when :silent! wasn't used inside the
+ // :def function.
+ if (emsg_silent == emsg_silent_def)
+ ++did_emsg_def;
+#endif
#ifdef FEAT_JOB_CHANNEL
ch_log(NULL, "ERROR silent: %s", (char *)s);
#endif
diff --git a/src/testdir/test_vim9_func.vim b/src/testdir/test_vim9_func.vim
index 4e8ee888d..f831c7199 100644
--- a/src/testdir/test_vim9_func.vim
+++ b/src/testdir/test_vim9_func.vim
@@ -1784,6 +1784,22 @@ def Test_reset_did_emsg()
delfunc! g:Func
enddef
+def Test_abort_with_silent_call()
+ var lines =<< trim END
+ vim9script
+ g:result = 'none'
+ def Func()
+ g:result += 3
+ g:result = 'yes'
+ enddef
+ # error is silenced, but function aborts on error
+ silent! Func()
+ assert_equal('none', g:result)
+ unlet g:result
+ END
+ CheckScriptSuccess(lines)
+enddef
+
def Test_continues_with_silent_error()
var lines =<< trim END
vim9script
diff --git a/src/version.c b/src/version.c
index 66ec86a20..95f3f62e7 100644
--- 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 */
/**/
+ 2097,
+/**/
2096,
/**/
2095,
diff --git a/src/vim9execute.c b/src/vim9execute.c
index 980ebb51a..7e8b336d0 100644
--- a/src/vim9execute.c
+++ b/src/vim9execute.c
@@ -851,6 +851,8 @@ call_def_function(
msglist_T *private_msg_list = NULL;
cmdmod_T save_cmdmod;
int restore_cmdmod = FALSE;
+ int save_emsg_silent_def = emsg_silent_def;
+ int save_did_emsg_def = did_emsg_def;
int trylevel_at_start = trylevel;
int orig_funcdepth;
@@ -1021,6 +1023,11 @@ call_def_function(
// Do turn errors into exceptions.
suppress_errthrow = FALSE;
+ // When ":silent!" was used before calling then we still abort the
+ // function. If ":silent!" is used in the function then we don't.
+ emsg_silent_def = emsg_silent;
+ did_emsg_def = 0;
+
// Decide where to start execution, handles optional arguments.
init_instr_idx(ufunc, argc, &ectx);
@@ -3008,8 +3015,10 @@ func_return:
on_error:
// Jump here for an error that does not require aborting execution.
- // If "emsg_silent" is set then ignore the error.
- if (did_emsg_cumul + did_emsg == did_emsg_before && emsg_silent)
+ // If "emsg_silent" is set then ignore the error, unless it was set
+ // when calling the function.
+ if (did_emsg_cumul + did_emsg == did_emsg_before
+ && emsg_silent && did_emsg_def == 0)
continue;
on_fatal_error:
// Jump here for an error that messes up the stack.
@@ -3056,6 +3065,8 @@ failed:
undo_cmdmod(&cmdmod);
cmdmod = save_cmdmod;
}
+ emsg_silent_def = save_emsg_silent_def;
+ did_emsg_def += save_did_emsg_def;
failed_early:
// Free all local variables, but not arguments.