mirror of
https://github.com/neovim/neovim.git
synced 2025-09-23 03:28:33 +00:00
ex_getln: Save and restore try state
Problem: when processing cycle such as :for pat in [' \ze*', ' \zs*'] : try : let l = matchlist('x x', pat) : $put ='E888 NOT detected for ' . pat : catch : $put ='E888 detected for ' . pat : endtry :endfor `:let l = …` throwing an error causes this error to be caught after color_cmdline attempts to get callback for highlighting next line (the one with `$put = 'E888 NOT…`). Saving/restoring state prevents this from happening.
This commit is contained in:
@@ -37,6 +37,52 @@ typedef struct {
|
||||
# include "api/private/ui_events_metadata.generated.h"
|
||||
#endif
|
||||
|
||||
/// Start block that may cause VimL exceptions while evaluating another code
|
||||
///
|
||||
/// Used when caller is supposed to be operating when other VimL code is being
|
||||
/// processed and that “other VimL code” must not be affected.
|
||||
///
|
||||
/// @param[out] tstate Location where try state should be saved.
|
||||
void try_enter(TryState *const tstate)
|
||||
{
|
||||
*tstate = (TryState) {
|
||||
.trylevel = trylevel,
|
||||
.got_int = got_int,
|
||||
.did_throw = did_throw,
|
||||
.msg_list = (const struct msglist *const *)msg_list,
|
||||
.private_msg_list = NULL,
|
||||
};
|
||||
trylevel = 1;
|
||||
got_int = false;
|
||||
did_throw = false;
|
||||
msg_list = &tstate->private_msg_list;
|
||||
}
|
||||
|
||||
/// End try block, set the error message if any and restore previous state
|
||||
///
|
||||
/// @warning Return is consistent with most functions (false on error), not with
|
||||
/// try_end (true on error).
|
||||
///
|
||||
/// @param[in] tstate Previous state to restore.
|
||||
/// @param[out] err Location where error should be saved.
|
||||
///
|
||||
/// @return false if error occurred, true otherwise.
|
||||
bool try_leave(const TryState *const tstate, Error *const err)
|
||||
FUNC_ATTR_NONNULL_ALL FUNC_ATTR_WARN_UNUSED_RESULT
|
||||
{
|
||||
const bool ret = !try_end(err);
|
||||
assert(trylevel == 0);
|
||||
assert(!got_int);
|
||||
assert(!did_throw);
|
||||
assert(msg_list == &tstate->private_msg_list);
|
||||
assert(*msg_list == NULL);
|
||||
trylevel = tstate->trylevel;
|
||||
got_int = tstate->got_int;
|
||||
did_throw = tstate->did_throw;
|
||||
msg_list = (struct msglist **)tstate->msg_list;
|
||||
return ret;
|
||||
}
|
||||
|
||||
/// Start block that may cause vimscript exceptions
|
||||
void try_start(void)
|
||||
{
|
||||
|
@@ -82,6 +82,18 @@
|
||||
#define api_free_window(value)
|
||||
#define api_free_tabpage(value)
|
||||
|
||||
/// Structure used for saving state for :try
|
||||
///
|
||||
/// Used when caller is supposed to be operating when other VimL code is being
|
||||
/// processed and that “other VimL code” must not be affected.
|
||||
typedef struct {
|
||||
int trylevel;
|
||||
int got_int;
|
||||
int did_throw;
|
||||
struct msglist *private_msg_list;
|
||||
const struct msglist *const *msg_list;
|
||||
} TryState;
|
||||
|
||||
#ifdef INCLUDE_GENERATED_DECLARATIONS
|
||||
# include "api/private/helpers.h.generated.h"
|
||||
#endif
|
||||
|
Reference in New Issue
Block a user