diff options
author | zeertzjq <zeertzjq@outlook.com> | 2022-11-30 11:47:30 +0800 |
---|---|---|
committer | GitHub <noreply@github.com> | 2022-11-30 11:47:30 +0800 |
commit | c0d17cec0b691488dbb3a57433e39d97aff36c47 (patch) | |
tree | ebd41705a12a0dbac92eda8d6f085417b3432390 | |
parent | bfdddec8bab85340b4b293f1467a56f495e26c2f (diff) | |
download | rneovim-c0d17cec0b691488dbb3a57433e39d97aff36c47.tar.gz rneovim-c0d17cec0b691488dbb3a57433e39d97aff36c47.tar.bz2 rneovim-c0d17cec0b691488dbb3a57433e39d97aff36c47.zip |
vim-patch:8.2.3259 when 'indentexpr' causes an error did_throw may hang (#21240)
vim-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 vim/vim#8677)
https://github.com/vim/vim/commit/620c959c6c00e469c4d3b1ab2e08e4767ee142a4
Co-authored-by: Bram Moolenaar <Bram@vim.org>
-rw-r--r-- | src/nvim/ex_docmd.c | 99 | ||||
-rw-r--r-- | src/nvim/indent.c | 7 |
2 files changed, 59 insertions, 47 deletions
diff --git a/src/nvim/ex_docmd.c b/src/nvim/ex_docmd.c index 8e7dfcbd43..1ea344dc0e 100644 --- a/src/nvim/ex_docmd.c +++ b/src/nvim/ex_docmd.c @@ -766,53 +766,7 @@ int do_cmdline(char *cmdline, LineGetter fgetline, void *cookie, int flags) // of interrupts or errors to exceptions, and ensure that no more // commands are executed. if (did_throw) { - assert(current_exception != NULL); - char *p = NULL; - msglist_T *messages = NULL; - msglist_T *next; - - // 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 = xstrdup((char *)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); - current_exception->throw_name = NULL; - - discard_current_exception(); // uses IObuff if 'verbose' - suppress_errthrow = true; - force_abort = true; - msg_ext_set_kind("emsg"); // kind=emsg for :throw, exceptions. #9993 - - if (messages != NULL) { - do { - next = messages->next; - emsg(messages->msg); - xfree(messages->msg); - xfree(messages->sfile); - xfree(messages); - messages = next; - } while (messages != NULL); - } else if (p != NULL) { - emsg(p); - xfree(p); - } - xfree(SOURCING_NAME); - estack_pop(); + handle_did_throw(); } else if (got_int || (did_emsg && force_abort)) { // On an interrupt or an aborting error not converted to an exception, // disable the conversion of errors to exceptions. (Interrupts are not @@ -902,6 +856,57 @@ int do_cmdline(char *cmdline, LineGetter fgetline, void *cookie, int flags) return retval; } +/// Handle when "did_throw" is set after executing commands. +void handle_did_throw(void) +{ + assert(current_exception != NULL); + 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 = xstrdup((char *)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); + current_exception->throw_name = NULL; + + discard_current_exception(); // uses IObuff if 'verbose' + suppress_errthrow = true; + force_abort = true; + msg_ext_set_kind("emsg"); // kind=emsg for :throw, exceptions. #9993 + + if (messages != NULL) { + do { + msglist_T *next = messages->next; + emsg(messages->msg); + xfree(messages->msg); + xfree(messages->sfile); + xfree(messages); + messages = next; + } while (messages != NULL); + } else if (p != NULL) { + emsg(p); + xfree(p); + } + xfree(SOURCING_NAME); + estack_pop(); +} + /// Obtain a line when inside a ":while" or ":for" loop. static char *get_loop_line(int c, void *cookie, int indent, bool do_concat) { diff --git a/src/nvim/indent.c b/src/nvim/indent.c index 0ffa152af7..bd91d1d4da 100644 --- a/src/nvim/indent.c +++ b/src/nvim/indent.c @@ -17,6 +17,7 @@ #include "nvim/edit.h" #include "nvim/eval.h" #include "nvim/eval/typval_defs.h" +#include "nvim/ex_docmd.h" #include "nvim/extmark.h" #include "nvim/gettext.h" #include "nvim/globals.h" @@ -1153,6 +1154,12 @@ int 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(); |