mirror of
https://github.com/neovim/neovim.git
synced 2025-09-15 07:48:18 +00:00
API: better way to capture abort-causing non-exception errors
This condition is not perfectly reliable: (did_emsg && force_abort && !current_exception) The more proper way to check for abort-causing non-exception errors is to set up `msg_list` using the "pattern" given by do_cmdline().
This commit is contained in:
@@ -260,7 +260,7 @@ theend:
|
|||||||
/// Evaluates a VimL expression (:help expression).
|
/// Evaluates a VimL expression (:help expression).
|
||||||
/// Dictionaries and Lists are recursively expanded.
|
/// Dictionaries and Lists are recursively expanded.
|
||||||
///
|
///
|
||||||
/// On execution error: fails with generic error; v:errmsg is not updated.
|
/// On execution error: fails with VimL error, does not update v:errmsg.
|
||||||
///
|
///
|
||||||
/// @param expr VimL expression string
|
/// @param expr VimL expression string
|
||||||
/// @param[out] err Error details, if any
|
/// @param[out] err Error details, if any
|
||||||
@@ -269,7 +269,6 @@ Object nvim_eval(String expr, Error *err)
|
|||||||
FUNC_API_SINCE(1)
|
FUNC_API_SINCE(1)
|
||||||
{
|
{
|
||||||
Object rv = OBJECT_INIT;
|
Object rv = OBJECT_INIT;
|
||||||
// Evaluate the expression
|
|
||||||
try_start();
|
try_start();
|
||||||
|
|
||||||
typval_T rettv;
|
typval_T rettv;
|
||||||
@@ -278,11 +277,9 @@ Object nvim_eval(String expr, Error *err)
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (!try_end(err)) {
|
if (!try_end(err)) {
|
||||||
// No errors, convert the result
|
|
||||||
rv = vim_to_object(&rettv);
|
rv = vim_to_object(&rettv);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Free the Vim object
|
|
||||||
tv_clear(&rettv);
|
tv_clear(&rettv);
|
||||||
|
|
||||||
return rv;
|
return rv;
|
||||||
@@ -315,7 +312,9 @@ Object nvim_execute_lua(String code, Array args, Error *err)
|
|||||||
/// @return Result of the function call
|
/// @return Result of the function call
|
||||||
static Object _call_function(String fn, Array args, dict_T *self, Error *err)
|
static Object _call_function(String fn, Array args, dict_T *self, Error *err)
|
||||||
{
|
{
|
||||||
|
static int recursive = 0; // recursion depth
|
||||||
Object rv = OBJECT_INIT;
|
Object rv = OBJECT_INIT;
|
||||||
|
|
||||||
if (args.size > MAX_FUNC_ARGS) {
|
if (args.size > MAX_FUNC_ARGS) {
|
||||||
api_set_error(err, kErrorTypeValidation,
|
api_set_error(err, kErrorTypeValidation,
|
||||||
"Function called with too many arguments");
|
"Function called with too many arguments");
|
||||||
@@ -331,25 +330,36 @@ static Object _call_function(String fn, Array args, dict_T *self, Error *err)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
try_start();
|
// `msg_list` controls the collection of abort-causing non-exception errors,
|
||||||
msg_first_ignored_err = NULL;
|
// which would otherwise be ignored. This pattern is from do_cmdline().
|
||||||
|
struct msglist **saved_msg_list = msg_list;
|
||||||
|
struct msglist *private_msg_list;
|
||||||
|
msg_list = &private_msg_list;
|
||||||
|
private_msg_list = NULL;
|
||||||
|
|
||||||
|
// Initialize `force_abort` and `suppress_errthrow` at the top level.
|
||||||
|
if (!recursive) {
|
||||||
|
force_abort = false;
|
||||||
|
suppress_errthrow = false;
|
||||||
|
current_exception = NULL;
|
||||||
|
// `did_emsg` is set by emsg(), which cancels execution.
|
||||||
|
did_emsg = false;
|
||||||
|
}
|
||||||
|
recursive++;
|
||||||
|
try_start();
|
||||||
typval_T rettv;
|
typval_T rettv;
|
||||||
int dummy;
|
int dummy;
|
||||||
int r = call_func((char_u *)fn.data, (int)fn.size, &rettv, (int)args.size,
|
// call_func() retval is deceptive, ignore it. Instead we set `msg_list`
|
||||||
vim_args, NULL, curwin->w_cursor.lnum,
|
// (see above) to capture abort-causing non-exception errors.
|
||||||
curwin->w_cursor.lnum, &dummy, true, NULL, self);
|
(void)call_func((char_u *)fn.data, (int)fn.size, &rettv, (int)args.size,
|
||||||
// call_func() retval is deceptive; must also check did_emsg et al.
|
vim_args, NULL, curwin->w_cursor.lnum, curwin->w_cursor.lnum,
|
||||||
if (msg_first_ignored_err
|
&dummy, true, NULL, self);
|
||||||
&& (r == FAIL || (did_emsg && force_abort && !current_exception))) {
|
|
||||||
api_set_error(err, kErrorTypeException, msg_first_ignored_err);
|
|
||||||
}
|
|
||||||
if (!try_end(err)) {
|
if (!try_end(err)) {
|
||||||
rv = vim_to_object(&rettv);
|
rv = vim_to_object(&rettv);
|
||||||
}
|
}
|
||||||
xfree(msg_first_ignored_err);
|
|
||||||
msg_first_ignored_err = NULL;
|
|
||||||
tv_clear(&rettv);
|
tv_clear(&rettv);
|
||||||
|
msg_list = saved_msg_list; // Restore the exception context.
|
||||||
|
recursive--;
|
||||||
|
|
||||||
free_vim_args:
|
free_vim_args:
|
||||||
while (i > 0) {
|
while (i > 0) {
|
||||||
|
@@ -6242,8 +6242,8 @@ bool set_ref_in_func(char_u *name, ufunc_T *fp_in, int copyID)
|
|||||||
/// new_argcount = argv_func(current_argcount, argv, called_func_argcount)
|
/// new_argcount = argv_func(current_argcount, argv, called_func_argcount)
|
||||||
///
|
///
|
||||||
/// @return FAIL if function cannot be called, else OK (even if an error
|
/// @return FAIL if function cannot be called, else OK (even if an error
|
||||||
/// occurred while executing the function! Use `msg_first_ignored_err`
|
/// occurred while executing the function! Set `msg_list` to capture
|
||||||
/// to get the error)
|
/// the error, see do_cmdline()).
|
||||||
int
|
int
|
||||||
call_func(
|
call_func(
|
||||||
const char_u *funcname, // name of the function
|
const char_u *funcname, // name of the function
|
||||||
|
@@ -67,7 +67,6 @@ static char_u *confirm_msg_tail; /* tail of confirm_msg */
|
|||||||
|
|
||||||
MessageHistoryEntry *first_msg_hist = NULL;
|
MessageHistoryEntry *first_msg_hist = NULL;
|
||||||
MessageHistoryEntry *last_msg_hist = NULL;
|
MessageHistoryEntry *last_msg_hist = NULL;
|
||||||
char *msg_first_ignored_err = NULL;
|
|
||||||
static int msg_hist_len = 0;
|
static int msg_hist_len = 0;
|
||||||
|
|
||||||
static FILE *verbose_fd = NULL;
|
static FILE *verbose_fd = NULL;
|
||||||
@@ -505,9 +504,6 @@ int emsg(const char_u *s_)
|
|||||||
if (cause_errthrow((char_u *)s, severe, &ignore) == true) {
|
if (cause_errthrow((char_u *)s, severe, &ignore) == true) {
|
||||||
if (!ignore) {
|
if (!ignore) {
|
||||||
did_emsg = true;
|
did_emsg = true;
|
||||||
if (msg_first_ignored_err == NULL) {
|
|
||||||
msg_first_ignored_err = xstrdup(s);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@@ -85,10 +85,6 @@ extern MessageHistoryEntry *first_msg_hist;
|
|||||||
/// Last message
|
/// Last message
|
||||||
extern MessageHistoryEntry *last_msg_hist;
|
extern MessageHistoryEntry *last_msg_hist;
|
||||||
|
|
||||||
/// Abort-causing non-exception error ignored by emsg(), needed by callers
|
|
||||||
/// (RPC API) of call_func() to get error details when messages are disabled.
|
|
||||||
extern char *msg_first_ignored_err;
|
|
||||||
|
|
||||||
#ifdef INCLUDE_GENERATED_DECLARATIONS
|
#ifdef INCLUDE_GENERATED_DECLARATIONS
|
||||||
# include "message.h.generated.h"
|
# include "message.h.generated.h"
|
||||||
#endif
|
#endif
|
||||||
|
Reference in New Issue
Block a user