changeset 12375:ab0d827151a1 v8.0.1067

patch 8.0.1067: try/catch in timer does not prevent it from being stopped commit https://github.com/vim/vim/commit/e723c42836d971180d1bf9f98916966c5543fff1 Author: Bram Moolenaar <Bram@vim.org> Date: Wed Sep 6 23:40:10 2017 +0200 patch 8.0.1067: try/catch in timer does not prevent it from being stopped Problem: Using try/catch in timer does not prevent it from being stopped. Solution: Reset the exception context and use did_emsg instead of called_emsg.
author Christian Brabandt <cb@256bit.org>
date Wed, 06 Sep 2017 23:45:04 +0200
parents a3a35f113a36
children 9e28f47e15b2
files src/ex_cmds2.c src/globals.h src/message.c src/testdir/test_timers.vim src/version.c
diffstat 5 files changed, 50 insertions(+), 15 deletions(-) [+]
line wrap: on
line diff
--- a/src/ex_cmds2.c
+++ b/src/ex_cmds2.c
@@ -1219,30 +1219,40 @@ check_due_timer(void)
 	{
 	    int save_timer_busy = timer_busy;
 	    int save_vgetc_busy = vgetc_busy;
-	    int did_emsg_save = did_emsg;
-	    int called_emsg_save = called_emsg;
-	    int did_throw_save = did_throw;
+	    int save_did_emsg = did_emsg;
+	    int save_called_emsg = called_emsg;
 	    int	save_must_redraw = must_redraw;
-
+	    int	save_trylevel = trylevel;
+	    int save_did_throw = did_throw;
+	    except_T *save_current_exception = current_exception;
+
+	    /* Create a scope for running the timer callback, ignoring most of
+	     * the current scope, such as being inside a try/catch. */
 	    timer_busy = timer_busy > 0 || vgetc_busy > 0;
 	    vgetc_busy = 0;
 	    called_emsg = FALSE;
+	    did_emsg = FALSE;
+	    did_uncaught_emsg = FALSE;
 	    must_redraw = 0;
+	    trylevel = 0;
+	    did_throw = FALSE;
+	    current_exception = NULL;
+
 	    timer->tr_firing = TRUE;
 	    timer_callback(timer);
 	    timer->tr_firing = FALSE;
+
 	    timer_next = timer->tr_next;
 	    did_one = TRUE;
 	    timer_busy = save_timer_busy;
 	    vgetc_busy = save_vgetc_busy;
-	    if (called_emsg)
-	    {
+	    if (did_uncaught_emsg)
 		++timer->tr_emsg_count;
-		if (!did_throw_save && did_throw && current_exception != NULL)
-		    discard_current_exception();
-	    }
-	    did_emsg = did_emsg_save;
-	    called_emsg = called_emsg_save;
+	    did_emsg = save_did_emsg;
+	    called_emsg = save_called_emsg;
+	    trylevel = save_trylevel;
+	    did_throw = save_did_throw;
+	    current_exception = save_current_exception;
 	    if (must_redraw != 0)
 		need_update_screen = TRUE;
 	    must_redraw = must_redraw > save_must_redraw
--- a/src/globals.h
+++ b/src/globals.h
@@ -182,6 +182,10 @@ EXTERN dict_T	globvardict;		    /* Dicti
 #endif
 EXTERN int	did_emsg;		    /* set by emsg() when the message
 					       is displayed or thrown */
+#ifdef FEAT_EVAL
+EXTERN int	did_uncaught_emsg;	    /* emsg() was called and did not
+					       cause an exception */
+#endif
 EXTERN int	did_emsg_syntax;	    /* did_emsg set because of a
 					       syntax error */
 EXTERN int	called_emsg;		    /* always set by emsg() */
--- a/src/message.c
+++ b/src/message.c
@@ -609,11 +609,9 @@ emsg(char_u *s)
 
     called_emsg = TRUE;
 
-    /*
-     * If "emsg_severe" is TRUE: When an error exception is to be thrown,
-     * prefer this message over previous messages for the same command.
-     */
 #ifdef FEAT_EVAL
+    /* If "emsg_severe" is TRUE: When an error exception is to be thrown,
+     * prefer this message over previous messages for the same command. */
     severe = emsg_severe;
     emsg_severe = FALSE;
 #endif
@@ -684,6 +682,9 @@ emsg(char_u *s)
 	else
 	    flush_buffers(FALSE);	/* flush internal buffers */
 	did_emsg = TRUE;		/* flag for DoOneCmd() */
+#ifdef FEAT_EVAL
+	did_uncaught_emsg = TRUE;
+#endif
     }
 
     emsg_on_display = TRUE;	/* remember there is an error message */
--- a/src/testdir/test_timers.vim
+++ b/src/testdir/test_timers.vim
@@ -208,6 +208,24 @@ func Test_timer_errors()
   call assert_equal(3, g:call_count)
 endfunc
 
+func FuncWithCaughtError(timer)
+  let g:call_count += 1
+  try
+    doesnotexist
+  catch
+    " nop
+  endtry
+endfunc
+
+func Test_timer_catch_error()
+  let g:call_count = 0
+  let timer = timer_start(10, 'FuncWithCaughtError', {'repeat': 4})
+  " Timer will not be stopped.
+  call WaitFor('g:call_count == 4')
+  sleep 50m
+  call assert_equal(4, g:call_count)
+endfunc
+
 func FeedAndPeek(timer)
   call test_feedinput('a')
   call getchar(1)
--- a/src/version.c
+++ b/src/version.c
@@ -770,6 +770,8 @@ static char *(features[]) =
 static int included_patches[] =
 {   /* Add new patch number below this line */
 /**/
+    1067,
+/**/
     1066,
 /**/
     1065,