diff options
Diffstat (limited to 'src/nvim/api/private/helpers.c')
| -rw-r--r-- | src/nvim/api/private/helpers.c | 69 | 
1 files changed, 68 insertions, 1 deletions
| diff --git a/src/nvim/api/private/helpers.c b/src/nvim/api/private/helpers.c index 1ed2bc013e..e736e29e2d 100644 --- a/src/nvim/api/private/helpers.c +++ b/src/nvim/api/private/helpers.c @@ -37,7 +37,72 @@ 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) { +    .current_exception = current_exception, +    .msg_list = (const struct msglist *const *)msg_list, +    .private_msg_list = NULL, +    .trylevel = trylevel, +    .got_int = got_int, +    .did_throw = did_throw, +    .need_rethrow = need_rethrow, +    .did_emsg = did_emsg, +  }; +  msg_list = &tstate->private_msg_list; +  current_exception = NULL; +  trylevel = 1; +  got_int = false; +  did_throw = false; +  need_rethrow = false; +  did_emsg = false; +} + +/// 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(!need_rethrow); +  assert(!got_int); +  assert(!did_throw); +  assert(!did_emsg); +  assert(msg_list == &tstate->private_msg_list); +  assert(*msg_list == NULL); +  assert(current_exception == NULL); +  msg_list = (struct msglist **)tstate->msg_list; +  current_exception = tstate->current_exception; +  trylevel = tstate->trylevel; +  got_int = tstate->got_int; +  did_throw = tstate->did_throw; +  need_rethrow = tstate->need_rethrow; +  did_emsg = tstate->did_emsg; +  return ret; +} +  /// Start block that may cause vimscript exceptions +/// +/// Each try_start() call should be mirrored by try_end() call. +/// +/// To be used as a replacement of `:try … catch … endtry` in C code, in cases +/// when error flag could not already be set. If there may be pending error +/// state at the time try_start() is executed which needs to be preserved, +/// try_enter()/try_leave() pair should be used instead.  void try_start(void)  {    ++trylevel; @@ -50,7 +115,9 @@ void try_start(void)  /// @return true if an error occurred  bool try_end(Error *err)  { -  --trylevel; +  // Note: all globals manipulated here should be saved/restored in +  // try_enter/try_leave. +  trylevel--;    // Without this it stops processing all subsequent VimL commands and    // generates strange error messages if I e.g. try calling Test() in a | 
