# HG changeset patch # User Bram Moolenaar # Date 1607200203 -3600 # Node ID 3239b0f3c5920ac52e61ba69064701475e891475 # Parent fe9d456dc33b50f53d840d2ee0a62864d44f8d39 patch 8.2.2097: Vim9: using :silent! when calling a function prevents abort Commit: https://github.com/vim/vim/commit/56602ba153af7130b76daf83933922aaea3e2646 Author: Bram Moolenaar Date: Sat Dec 5 21:22:08 2020 +0100 patch 8.2.2097: Vim9: using :silent! when calling a function prevents abort Problem: Vim9: using :silent! when calling a function prevents abortng that function. Solution: Add emsg_silent_def and did_emsg_def. diff --git a/src/globals.h b/src/globals.h --- a/src/globals.h +++ b/src/globals.h @@ -230,6 +230,8 @@ EXTERN int did_endif INIT(= FALSE); / 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); / 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 --- 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 --- 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 --- 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 --- 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.