changeset 25445:65f04b6effd5 v8.2.3259

patch 8.2.3259: when 'indentexpr' causes an error did_throw may hang Commit: https://github.com/vim/vim/commit/620c959c6c00e469c4d3b1ab2e08e4767ee142a4 Author: Bram Moolenaar <Bram@vim.org> Date: Sat Jul 31 21:32:31 2021 +0200 patch 8.2.3259: when 'indentexpr' causes an error did_throw may hang Problem: When 'indentexpr' causes an error the did_throw flag may remain set. Solution: Reset did_throw and show the error. (closes #8677)
author Bram Moolenaar <Bram@vim.org>
date Sat, 31 Jul 2021 21:45:04 +0200
parents c80bfd306c7d
children c0fd3b2cdbc0
files src/ex_docmd.c src/indent.c src/proto/ex_docmd.pro src/version.c
diffstat 4 files changed, 78 insertions(+), 61 deletions(-) [+]
line wrap: on
line diff
--- a/src/ex_docmd.c
+++ b/src/ex_docmd.c
@@ -1268,67 +1268,7 @@ do_cmdline(
 	 * commands are executed.
 	 */
 	if (did_throw)
-	{
-	    char	*p = NULL;
-	    msglist_T	*messages = NULL;
-
-	    /*
-	     * If the uncaught exception is a user exception, report it as an
-	     * error.  If it is an error exception, display the saved error
-	     * message now.  For an interrupt exception, do nothing; the
-	     * interrupt message is given elsewhere.
-	     */
-	    switch (current_exception->type)
-	    {
-		case ET_USER:
-		    vim_snprintf((char *)IObuff, IOSIZE,
-			    _("E605: Exception not caught: %s"),
-			    current_exception->value);
-		    p = (char *)vim_strsave(IObuff);
-		    break;
-		case ET_ERROR:
-		    messages = current_exception->messages;
-		    current_exception->messages = NULL;
-		    break;
-		case ET_INTERRUPT:
-		    break;
-	    }
-
-	    estack_push(ETYPE_EXCEPT, current_exception->throw_name,
-						current_exception->throw_lnum);
-	    ESTACK_CHECK_SETUP
-	    current_exception->throw_name = NULL;
-
-	    discard_current_exception();	// uses IObuff if 'verbose'
-	    suppress_errthrow = TRUE;
-	    force_abort = TRUE;
-
-	    if (messages != NULL)
-	    {
-		do
-		{
-		    msglist_T	*next = messages->next;
-		    int		save_compiling = estack_compiling;
-
-		    estack_compiling = messages->msg_compiling;
-		    emsg(messages->msg);
-		    vim_free(messages->msg);
-		    vim_free(messages->sfile);
-		    vim_free(messages);
-		    messages = next;
-		    estack_compiling = save_compiling;
-		}
-		while (messages != NULL);
-	    }
-	    else if (p != NULL)
-	    {
-		emsg(p);
-		vim_free(p);
-	    }
-	    vim_free(SOURCING_NAME);
-	    ESTACK_CHECK_NOW
-	    estack_pop();
-	}
+	    handle_did_throw();
 
 	/*
 	 * On an interrupt or an aborting error not converted to an exception,
@@ -1448,6 +1388,73 @@ do_cmdline(
     return retval;
 }
 
+/*
+ * Handle when "did_throw" is set after executing commands.
+ */
+    void
+handle_did_throw()
+{
+    char	*p = NULL;
+    msglist_T	*messages = NULL;
+
+    /*
+     * If the uncaught exception is a user exception, report it as an
+     * error.  If it is an error exception, display the saved error
+     * message now.  For an interrupt exception, do nothing; the
+     * interrupt message is given elsewhere.
+     */
+    switch (current_exception->type)
+    {
+	case ET_USER:
+	    vim_snprintf((char *)IObuff, IOSIZE,
+		    _("E605: Exception not caught: %s"),
+		    current_exception->value);
+	    p = (char *)vim_strsave(IObuff);
+	    break;
+	case ET_ERROR:
+	    messages = current_exception->messages;
+	    current_exception->messages = NULL;
+	    break;
+	case ET_INTERRUPT:
+	    break;
+    }
+
+    estack_push(ETYPE_EXCEPT, current_exception->throw_name,
+					current_exception->throw_lnum);
+    ESTACK_CHECK_SETUP
+    current_exception->throw_name = NULL;
+
+    discard_current_exception();	// uses IObuff if 'verbose'
+    suppress_errthrow = TRUE;
+    force_abort = TRUE;
+
+    if (messages != NULL)
+    {
+	do
+	{
+	    msglist_T	*next = messages->next;
+	    int		save_compiling = estack_compiling;
+
+	    estack_compiling = messages->msg_compiling;
+	    emsg(messages->msg);
+	    vim_free(messages->msg);
+	    vim_free(messages->sfile);
+	    vim_free(messages);
+	    messages = next;
+	    estack_compiling = save_compiling;
+	}
+	while (messages != NULL);
+    }
+    else if (p != NULL)
+    {
+	emsg(p);
+	vim_free(p);
+    }
+    vim_free(SOURCING_NAME);
+    ESTACK_CHECK_NOW
+    estack_pop();
+}
+
 #ifdef FEAT_EVAL
 /*
  * Obtain a line when inside a ":while" or ":for" loop.
--- a/src/indent.c
+++ b/src/indent.c
@@ -1822,6 +1822,13 @@ get_expr_indent(void)
     check_cursor();
     State = save_State;
 
+    // Reset did_throw, unless 'debug' has "throw" and inside a try/catch.
+    if (did_throw && (vim_strchr(p_debug, 't') == NULL || trylevel == 0))
+    {
+	handle_did_throw();
+	did_throw = FALSE;
+    }
+
     // If there is an error, just keep the current indent.
     if (indent < 0)
 	indent = get_indent();
--- a/src/proto/ex_docmd.pro
+++ b/src/proto/ex_docmd.pro
@@ -3,6 +3,7 @@ void do_exmode(int improved);
 int do_cmdline_cmd(char_u *cmd);
 int do_cmd_argument(char_u *cmd);
 int do_cmdline(char_u *cmdline, char_u *(*fgetline)(int, void *, int, getline_opt_T), void *cookie, int flags);
+void handle_did_throw(void);
 int getline_equal(char_u *(*fgetline)(int, void *, int, getline_opt_T), void *cookie, char_u *(*func)(int, void *, int, getline_opt_T));
 void *getline_cookie(char_u *(*fgetline)(int, void *, int, getline_opt_T), void *cookie);
 char_u *getline_peek(char_u *(*fgetline)(int, void *, int, getline_opt_T), void *cookie);
--- a/src/version.c
+++ b/src/version.c
@@ -756,6 +756,8 @@ static char *(features[]) =
 static int included_patches[] =
 {   /* Add new patch number below this line */
 /**/
+    3259,
+/**/
     3258,
 /**/
     3257,