aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorzeertzjq <zeertzjq@outlook.com>2022-11-30 11:47:30 +0800
committerGitHub <noreply@github.com>2022-11-30 11:47:30 +0800
commitc0d17cec0b691488dbb3a57433e39d97aff36c47 (patch)
treeebd41705a12a0dbac92eda8d6f085417b3432390
parentbfdddec8bab85340b4b293f1467a56f495e26c2f (diff)
downloadrneovim-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.c99
-rw-r--r--src/nvim/indent.c7
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();