# HG changeset patch # User Bram Moolenaar # Date 1627760704 -7200 # Node ID 65f04b6effd5c65066069501315e22c151fb8e9a # Parent c80bfd306c7d00029116424b2376b2ec7268f848 patch 8.2.3259: when 'indentexpr' causes an error did_throw may hang Commit: https://github.com/vim/vim/commit/620c959c6c00e469c4d3b1ab2e08e4767ee142a4 Author: Bram Moolenaar 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) diff --git a/src/ex_docmd.c b/src/ex_docmd.c --- 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. diff --git a/src/indent.c b/src/indent.c --- 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(); diff --git a/src/proto/ex_docmd.pro b/src/proto/ex_docmd.pro --- 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); diff --git a/src/version.c b/src/version.c --- 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,