diff options
author | luukvbaal <luukvbaal@gmail.com> | 2024-12-17 13:12:22 +0100 |
---|---|---|
committer | GitHub <noreply@github.com> | 2024-12-17 04:12:22 -0800 |
commit | 6bf2a6fc5bb395b67c88cb26d332f882a106c7ab (patch) | |
tree | 44259c3b4df40c5af3a4bacec308945f93365d6e /src/nvim/api | |
parent | b03e790cddd19b57fa91f4fbfcc30c28f3c173bf (diff) | |
download | rneovim-6bf2a6fc5bb395b67c88cb26d332f882a106c7ab.tar.gz rneovim-6bf2a6fc5bb395b67c88cb26d332f882a106c7ab.tar.bz2 rneovim-6bf2a6fc5bb395b67c88cb26d332f882a106c7ab.zip |
refactor(api): always use TRY_WRAP #31600
Problem: Two separate try/end wrappers, that only marginally differ by
restoring a few variables. Wrappers that don't restore
previous state are dangerous to use in "api-fast" functions.
Solution: Remove wrappers that don't restore the previous state.
Always use TRY_WRAP.
Diffstat (limited to 'src/nvim/api')
-rw-r--r-- | src/nvim/api/buffer.c | 346 | ||||
-rw-r--r-- | src/nvim/api/private/helpers.c | 79 | ||||
-rw-r--r-- | src/nvim/api/private/helpers.h | 14 | ||||
-rw-r--r-- | src/nvim/api/tabpage.c | 8 | ||||
-rw-r--r-- | src/nvim/api/vim.c | 116 | ||||
-rw-r--r-- | src/nvim/api/vimscript.c | 30 | ||||
-rw-r--r-- | src/nvim/api/window.c | 30 |
7 files changed, 291 insertions, 332 deletions
diff --git a/src/nvim/api/buffer.c b/src/nvim/api/buffer.c index 9480292d9a..2b6aa8b371 100644 --- a/src/nvim/api/buffer.c +++ b/src/nvim/api/buffer.c @@ -360,93 +360,91 @@ void nvim_buf_set_lines(uint64_t channel_id, Buffer buffer, Integer start, Integ memchrsub(lines[i], NUL, NL, l.size); } - try_start(); - - if (!MODIFIABLE(buf)) { - api_set_error(err, kErrorTypeException, "Buffer is not 'modifiable'"); - goto end; - } - - if (u_save_buf(buf, (linenr_T)(start - 1), (linenr_T)end) == FAIL) { - api_set_error(err, kErrorTypeException, "Failed to save undo information"); - goto end; - } - - bcount_t deleted_bytes = get_region_bytecount(buf, (linenr_T)start, (linenr_T)end, 0, 0); - - // If the size of the range is reducing (ie, new_len < old_len) we - // need to delete some old_len. We do this at the start, by - // repeatedly deleting line "start". - size_t to_delete = (new_len < old_len) ? old_len - new_len : 0; - for (size_t i = 0; i < to_delete; i++) { - if (ml_delete_buf(buf, (linenr_T)start, false) == FAIL) { - api_set_error(err, kErrorTypeException, "Failed to delete line"); + TRY_WRAP(err, { + if (!MODIFIABLE(buf)) { + api_set_error(err, kErrorTypeException, "Buffer is not 'modifiable'"); goto end; } - } - if (to_delete > 0) { - extra -= (ptrdiff_t)to_delete; - } + if (u_save_buf(buf, (linenr_T)(start - 1), (linenr_T)end) == FAIL) { + api_set_error(err, kErrorTypeException, "Failed to save undo information"); + goto end; + } - // For as long as possible, replace the existing old_len with the - // new old_len. This is a more efficient operation, as it requires - // less memory allocation and freeing. - size_t to_replace = old_len < new_len ? old_len : new_len; - bcount_t inserted_bytes = 0; - for (size_t i = 0; i < to_replace; i++) { - int64_t lnum = start + (int64_t)i; + bcount_t deleted_bytes = get_region_bytecount(buf, (linenr_T)start, (linenr_T)end, 0, 0); - VALIDATE(lnum < MAXLNUM, "%s", "Index out of bounds", { - goto end; - }); + // If the size of the range is reducing (ie, new_len < old_len) we + // need to delete some old_len. We do this at the start, by + // repeatedly deleting line "start". + size_t to_delete = (new_len < old_len) ? old_len - new_len : 0; + for (size_t i = 0; i < to_delete; i++) { + if (ml_delete_buf(buf, (linenr_T)start, false) == FAIL) { + api_set_error(err, kErrorTypeException, "Failed to delete line"); + goto end; + } + } - if (ml_replace_buf(buf, (linenr_T)lnum, lines[i], false, true) == FAIL) { - api_set_error(err, kErrorTypeException, "Failed to replace line"); - goto end; + if (to_delete > 0) { + extra -= (ptrdiff_t)to_delete; } - inserted_bytes += (bcount_t)strlen(lines[i]) + 1; - } + // For as long as possible, replace the existing old_len with the + // new old_len. This is a more efficient operation, as it requires + // less memory allocation and freeing. + size_t to_replace = old_len < new_len ? old_len : new_len; + bcount_t inserted_bytes = 0; + for (size_t i = 0; i < to_replace; i++) { + int64_t lnum = start + (int64_t)i; + + VALIDATE(lnum < MAXLNUM, "%s", "Index out of bounds", { + goto end; + }); + + if (ml_replace_buf(buf, (linenr_T)lnum, lines[i], false, true) == FAIL) { + api_set_error(err, kErrorTypeException, "Failed to replace line"); + goto end; + } - // Now we may need to insert the remaining new old_len - for (size_t i = to_replace; i < new_len; i++) { - int64_t lnum = start + (int64_t)i - 1; + inserted_bytes += (bcount_t)strlen(lines[i]) + 1; + } - VALIDATE(lnum < MAXLNUM, "%s", "Index out of bounds", { - goto end; - }); + // Now we may need to insert the remaining new old_len + for (size_t i = to_replace; i < new_len; i++) { + int64_t lnum = start + (int64_t)i - 1; - if (ml_append_buf(buf, (linenr_T)lnum, lines[i], 0, false) == FAIL) { - api_set_error(err, kErrorTypeException, "Failed to insert line"); - goto end; - } + VALIDATE(lnum < MAXLNUM, "%s", "Index out of bounds", { + goto end; + }); - inserted_bytes += (bcount_t)strlen(lines[i]) + 1; + if (ml_append_buf(buf, (linenr_T)lnum, lines[i], 0, false) == FAIL) { + api_set_error(err, kErrorTypeException, "Failed to insert line"); + goto end; + } - extra++; - } + inserted_bytes += (bcount_t)strlen(lines[i]) + 1; - // Adjust marks. Invalidate any which lie in the - // changed range, and move any in the remainder of the buffer. - linenr_T adjust = end > start ? MAXLNUM : 0; - mark_adjust_buf(buf, (linenr_T)start, (linenr_T)(end - 1), adjust, (linenr_T)extra, - true, true, kExtmarkNOOP); + extra++; + } - extmark_splice(buf, (int)start - 1, 0, (int)(end - start), 0, - deleted_bytes, (int)new_len, 0, inserted_bytes, - kExtmarkUndo); + // Adjust marks. Invalidate any which lie in the + // changed range, and move any in the remainder of the buffer. + linenr_T adjust = end > start ? MAXLNUM : 0; + mark_adjust_buf(buf, (linenr_T)start, (linenr_T)(end - 1), adjust, (linenr_T)extra, + true, true, kExtmarkNOOP); - changed_lines(buf, (linenr_T)start, 0, (linenr_T)end, (linenr_T)extra, true); + extmark_splice(buf, (int)start - 1, 0, (int)(end - start), 0, + deleted_bytes, (int)new_len, 0, inserted_bytes, + kExtmarkUndo); - FOR_ALL_TAB_WINDOWS(tp, win) { - if (win->w_buffer == buf) { - fix_cursor(win, (linenr_T)start, (linenr_T)end, (linenr_T)extra); - } - } + changed_lines(buf, (linenr_T)start, 0, (linenr_T)end, (linenr_T)extra, true); -end: - try_end(err); + FOR_ALL_TAB_WINDOWS(tp, win) { + if (win->w_buffer == buf) { + fix_cursor(win, (linenr_T)start, (linenr_T)end, (linenr_T)extra); + } + } + end:; + }); } /// Sets (replaces) a range in the buffer @@ -593,101 +591,99 @@ void nvim_buf_set_text(uint64_t channel_id, Buffer buffer, Integer start_row, In new_byte += (bcount_t)(last_item.size) + 1; } - try_start(); - - if (!MODIFIABLE(buf)) { - api_set_error(err, kErrorTypeException, "Buffer is not 'modifiable'"); - goto end; - } - - // Small note about undo states: unlike set_lines, we want to save the - // undo state of one past the end_row, since end_row is inclusive. - if (u_save_buf(buf, (linenr_T)start_row - 1, (linenr_T)end_row + 1) == FAIL) { - api_set_error(err, kErrorTypeException, "Failed to save undo information"); - goto end; - } - - ptrdiff_t extra = 0; // lines added to text, can be negative - size_t old_len = (size_t)(end_row - start_row + 1); - - // If the size of the range is reducing (ie, new_len < old_len) we - // need to delete some old_len. We do this at the start, by - // repeatedly deleting line "start". - size_t to_delete = (new_len < old_len) ? old_len - new_len : 0; - for (size_t i = 0; i < to_delete; i++) { - if (ml_delete_buf(buf, (linenr_T)start_row, false) == FAIL) { - api_set_error(err, kErrorTypeException, "Failed to delete line"); + TRY_WRAP(err, { + if (!MODIFIABLE(buf)) { + api_set_error(err, kErrorTypeException, "Buffer is not 'modifiable'"); goto end; } - } - if (to_delete > 0) { - extra -= (ptrdiff_t)to_delete; - } - - // For as long as possible, replace the existing old_len with the - // new old_len. This is a more efficient operation, as it requires - // less memory allocation and freeing. - size_t to_replace = old_len < new_len ? old_len : new_len; - for (size_t i = 0; i < to_replace; i++) { - int64_t lnum = start_row + (int64_t)i; - - VALIDATE((lnum < MAXLNUM), "%s", "Index out of bounds", { + // Small note about undo states: unlike set_lines, we want to save the + // undo state of one past the end_row, since end_row is inclusive. + if (u_save_buf(buf, (linenr_T)start_row - 1, (linenr_T)end_row + 1) == FAIL) { + api_set_error(err, kErrorTypeException, "Failed to save undo information"); goto end; - }); + } - if (ml_replace_buf(buf, (linenr_T)lnum, lines[i], false, true) == FAIL) { - api_set_error(err, kErrorTypeException, "Failed to replace line"); - goto end; + ptrdiff_t extra = 0; // lines added to text, can be negative + size_t old_len = (size_t)(end_row - start_row + 1); + + // If the size of the range is reducing (ie, new_len < old_len) we + // need to delete some old_len. We do this at the start, by + // repeatedly deleting line "start". + size_t to_delete = (new_len < old_len) ? old_len - new_len : 0; + for (size_t i = 0; i < to_delete; i++) { + if (ml_delete_buf(buf, (linenr_T)start_row, false) == FAIL) { + api_set_error(err, kErrorTypeException, "Failed to delete line"); + goto end; + } } - } - // Now we may need to insert the remaining new old_len - for (size_t i = to_replace; i < new_len; i++) { - int64_t lnum = start_row + (int64_t)i - 1; + if (to_delete > 0) { + extra -= (ptrdiff_t)to_delete; + } - VALIDATE((lnum < MAXLNUM), "%s", "Index out of bounds", { - goto end; - }); + // For as long as possible, replace the existing old_len with the + // new old_len. This is a more efficient operation, as it requires + // less memory allocation and freeing. + size_t to_replace = old_len < new_len ? old_len : new_len; + for (size_t i = 0; i < to_replace; i++) { + int64_t lnum = start_row + (int64_t)i; - if (ml_append_buf(buf, (linenr_T)lnum, lines[i], 0, false) == FAIL) { - api_set_error(err, kErrorTypeException, "Failed to insert line"); - goto end; + VALIDATE((lnum < MAXLNUM), "%s", "Index out of bounds", { + goto end; + }); + + if (ml_replace_buf(buf, (linenr_T)lnum, lines[i], false, true) == FAIL) { + api_set_error(err, kErrorTypeException, "Failed to replace line"); + goto end; + } } - extra++; - } + // Now we may need to insert the remaining new old_len + for (size_t i = to_replace; i < new_len; i++) { + int64_t lnum = start_row + (int64_t)i - 1; - colnr_T col_extent = (colnr_T)(end_col - - ((end_row == start_row) ? start_col : 0)); - - // Adjust marks. Invalidate any which lie in the - // changed range, and move any in the remainder of the buffer. - // Do not adjust any cursors. need to use column-aware logic (below) - linenr_T adjust = end_row >= start_row ? MAXLNUM : 0; - mark_adjust_buf(buf, (linenr_T)start_row, (linenr_T)end_row, adjust, (linenr_T)extra, - true, true, kExtmarkNOOP); - - extmark_splice(buf, (int)start_row - 1, (colnr_T)start_col, - (int)(end_row - start_row), col_extent, old_byte, - (int)new_len - 1, (colnr_T)last_item.size, new_byte, - kExtmarkUndo); - - changed_lines(buf, (linenr_T)start_row, 0, (linenr_T)end_row + 1, (linenr_T)extra, true); - - FOR_ALL_TAB_WINDOWS(tp, win) { - if (win->w_buffer == buf) { - if (win->w_cursor.lnum >= start_row && win->w_cursor.lnum <= end_row) { - fix_cursor_cols(win, (linenr_T)start_row, (colnr_T)start_col, (linenr_T)end_row, - (colnr_T)end_col, (linenr_T)new_len, (colnr_T)last_item.size); - } else { - fix_cursor(win, (linenr_T)start_row, (linenr_T)end_row, (linenr_T)extra); + VALIDATE((lnum < MAXLNUM), "%s", "Index out of bounds", { + goto end; + }); + + if (ml_append_buf(buf, (linenr_T)lnum, lines[i], 0, false) == FAIL) { + api_set_error(err, kErrorTypeException, "Failed to insert line"); + goto end; } + + extra++; } - } -end: - try_end(err); + colnr_T col_extent = (colnr_T)(end_col + - ((end_row == start_row) ? start_col : 0)); + + // Adjust marks. Invalidate any which lie in the + // changed range, and move any in the remainder of the buffer. + // Do not adjust any cursors. need to use column-aware logic (below) + linenr_T adjust = end_row >= start_row ? MAXLNUM : 0; + mark_adjust_buf(buf, (linenr_T)start_row, (linenr_T)end_row, adjust, (linenr_T)extra, + true, true, kExtmarkNOOP); + + extmark_splice(buf, (int)start_row - 1, (colnr_T)start_col, + (int)(end_row - start_row), col_extent, old_byte, + (int)new_len - 1, (colnr_T)last_item.size, new_byte, + kExtmarkUndo); + + changed_lines(buf, (linenr_T)start_row, 0, (linenr_T)end_row + 1, (linenr_T)extra, true); + + FOR_ALL_TAB_WINDOWS(tp, win) { + if (win->w_buffer == buf) { + if (win->w_cursor.lnum >= start_row && win->w_cursor.lnum <= end_row) { + fix_cursor_cols(win, (linenr_T)start_row, (colnr_T)start_col, (linenr_T)end_row, + (colnr_T)end_col, (linenr_T)new_len, (colnr_T)last_item.size); + } else { + fix_cursor(win, (linenr_T)start_row, (linenr_T)end_row, (linenr_T)extra); + } + } + } + end:; + }); } /// Gets a range from the buffer. @@ -965,26 +961,27 @@ void nvim_buf_set_name(Buffer buffer, String name, Error *err) return; } - try_start(); - - const bool is_curbuf = buf == curbuf; - const int save_acd = p_acd; - if (!is_curbuf) { - // Temporarily disable 'autochdir' when setting file name for another buffer. - p_acd = false; - } + int ren_ret = OK; + TRY_WRAP(err, { + const bool is_curbuf = buf == curbuf; + const int save_acd = p_acd; + if (!is_curbuf) { + // Temporarily disable 'autochdir' when setting file name for another buffer. + p_acd = false; + } - // Using aucmd_*: autocommands will be executed by rename_buffer - aco_save_T aco; - aucmd_prepbuf(&aco, buf); - int ren_ret = rename_buffer(name.data); - aucmd_restbuf(&aco); + // Using aucmd_*: autocommands will be executed by rename_buffer + aco_save_T aco; + aucmd_prepbuf(&aco, buf); + ren_ret = rename_buffer(name.data); + aucmd_restbuf(&aco); - if (!is_curbuf) { - p_acd = save_acd; - } + if (!is_curbuf) { + p_acd = save_acd; + } + }); - if (try_end(err)) { + if (ERROR_SET(err)) { return; } @@ -1204,15 +1201,18 @@ Object nvim_buf_call(Buffer buffer, LuaRef fun, Error *err) if (!buf) { return NIL; } - try_start(); - aco_save_T aco; - aucmd_prepbuf(&aco, buf); - Array args = ARRAY_DICT_INIT; - Object res = nlua_call_ref(fun, NULL, args, kRetLuaref, NULL, err); + Object res = OBJECT_INIT; + TRY_WRAP(err, { + aco_save_T aco; + aucmd_prepbuf(&aco, buf); + + Array args = ARRAY_DICT_INIT; + res = nlua_call_ref(fun, NULL, args, kRetLuaref, NULL, err); + + aucmd_restbuf(&aco); + }); - aucmd_restbuf(&aco); - try_end(err); return res; } diff --git a/src/nvim/api/private/helpers.c b/src/nvim/api/private/helpers.c index 5bf66a092f..4389ae3b35 100644 --- a/src/nvim/api/private/helpers.c +++ b/src/nvim/api/private/helpers.c @@ -42,8 +42,10 @@ /// Start block that may cause Vimscript exceptions while evaluating another code /// -/// Used when caller is supposed to be operating when other Vimscript code is being -/// processed and that “other Vimscript code” must not be affected. +/// Used just in case caller is supposed to be operating when other Vimscript code +/// is being processed and that “other Vimscript code” must not be affected. +/// +/// @warning Avoid calling directly; use TRY_WRAP instead. /// /// @param[out] tstate Location where try state should be saved. void try_enter(TryState *const tstate) @@ -55,75 +57,33 @@ void try_enter(TryState *const tstate) .current_exception = current_exception, .msg_list = (const msglist_T *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` controls the collection of abort-causing non-exception errors, + // which would otherwise be ignored. This pattern is from do_cmdline(). 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 = (msglist_T **)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; -} - -/// Starts a block that may cause Vimscript exceptions; must be mirrored by `try_end()` call. -/// -/// Note: use `TRY_WRAP` instead (except in `FUNC_API_FAST` functions such as nvim_get_runtime_file). -/// -/// 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++; } -/// Ends a `try_start` block; sets error message if any and returns true if an error occurred. +/// Ends a `try_enter` block; sets error message if any. /// -/// Note: use `TRY_WRAP` instead (except in `FUNC_API_FAST` functions such as nvim_get_runtime_file). +/// @warning Avoid calling directly; use TRY_WRAP instead. /// -/// @param err Pointer to the stack-allocated error object -/// @return true if an error occurred -bool try_end(Error *err) +/// @param[out] err Pointer to the stack-allocated error object +void try_leave(const TryState *const tstate, Error *const err) + FUNC_ATTR_NONNULL_ALL { // Note: all globals manipulated here should be saved/restored in // try_enter/try_leave. + assert(trylevel > 0); trylevel--; // Set by emsg(), affects aborting(). See also enter_cleanup(). @@ -166,7 +126,20 @@ bool try_end(Error *err) discard_current_exception(); } - return ERROR_SET(err); + assert(msg_list == &tstate->private_msg_list); + assert(*msg_list == NULL); + assert(current_exception == NULL); + assert(!got_int); + assert(!did_throw); + assert(!need_rethrow); + assert(!did_emsg); + // Restore the exception context. + msg_list = (msglist_T **)tstate->msg_list; + current_exception = tstate->current_exception; + got_int = tstate->got_int; + did_throw = tstate->did_throw; + need_rethrow = tstate->need_rethrow; + did_emsg = tstate->did_emsg; } /// Recursively expands a vimscript value in a dict diff --git a/src/nvim/api/private/helpers.h b/src/nvim/api/private/helpers.h index d06f5c9c65..03ff811449 100644 --- a/src/nvim/api/private/helpers.h +++ b/src/nvim/api/private/helpers.h @@ -147,27 +147,19 @@ typedef struct { except_T *current_exception; msglist_T *private_msg_list; const msglist_T *const *msg_list; - int trylevel; int got_int; bool did_throw; int need_rethrow; int did_emsg; } TryState; -// `msg_list` controls the collection of abort-causing non-exception errors, -// which would otherwise be ignored. This pattern is from do_cmdline(). -// // TODO(bfredl): prepare error-handling at "top level" (nv_event). #define TRY_WRAP(err, code) \ do { \ - msglist_T **saved_msg_list = msg_list; \ - msglist_T *private_msg_list; \ - msg_list = &private_msg_list; \ - private_msg_list = NULL; \ - try_start(); \ + TryState tstate; \ + try_enter(&tstate); \ code; \ - try_end(err); \ - msg_list = saved_msg_list; /* Restore the exception context. */ \ + try_leave(&tstate, err); \ } while (0) // Execute code with cursor position saved and restored and textlock active. diff --git a/src/nvim/api/tabpage.c b/src/nvim/api/tabpage.c index 56a3f1cf23..b4d519dc98 100644 --- a/src/nvim/api/tabpage.c +++ b/src/nvim/api/tabpage.c @@ -146,11 +146,9 @@ void nvim_tabpage_set_win(Tabpage tabpage, Window win, Error *err) } if (tp == curtab) { - try_start(); - win_goto(wp); - if (!try_end(err) && curwin != wp) { - api_set_error(err, kErrorTypeException, "Failed to switch to window %d", win); - } + TRY_WRAP(err, { + win_goto(wp); + }); } else if (tp->tp_curwin != wp) { tp->tp_prevwin = tp->tp_curwin; tp->tp_curwin = wp; diff --git a/src/nvim/api/vim.c b/src/nvim/api/vim.c index d82f90d1dd..fce7a86245 100644 --- a/src/nvim/api/vim.c +++ b/src/nvim/api/vim.c @@ -594,12 +594,10 @@ ArrayOf(String) nvim_get_runtime_file(String name, Boolean all, Arena *arena, Er kvi_init(cookie.rv); int flags = DIP_DIRFILE | (all ? DIP_ALL : 0); - TryState tstate; - // XXX: intentionally not using `TRY_WRAP`, to avoid `did_emsg=false` in `try_end`. - try_enter(&tstate); - do_in_runtimepath((name.size ? name.data : ""), flags, find_runtime_cb, &cookie); - vim_ignored = try_leave(&tstate, err); + TRY_WRAP(err, { + do_in_runtimepath((name.size ? name.data : ""), flags, find_runtime_cb, &cookie); + }); return arena_take_arraybuilder(arena, &cookie.rv); } @@ -952,68 +950,70 @@ void nvim_set_current_win(Window window, Error *err) Buffer nvim_create_buf(Boolean listed, Boolean scratch, Error *err) FUNC_API_SINCE(6) { - try_start(); - // Block autocommands for now so they don't mess with the buffer before we - // finish configuring it. - block_autocmds(); - - buf_T *buf = buflist_new(NULL, NULL, 0, - BLN_NOOPT | BLN_NEW | (listed ? BLN_LISTED : 0)); - if (buf == NULL) { - unblock_autocmds(); - goto fail; - } + Buffer ret = 0; - // Open the memline for the buffer. This will avoid spurious autocmds when - // a later nvim_buf_set_lines call would have needed to "open" the buffer. - if (ml_open(buf) == FAIL) { - unblock_autocmds(); - goto fail; - } - - // Set last_changedtick to avoid triggering a TextChanged autocommand right - // after it was added. - buf->b_last_changedtick = buf_get_changedtick(buf); - buf->b_last_changedtick_i = buf_get_changedtick(buf); - buf->b_last_changedtick_pum = buf_get_changedtick(buf); + TRY_WRAP(err, { + // Block autocommands for now so they don't mess with the buffer before we + // finish configuring it. + block_autocmds(); + + buf_T *buf = buflist_new(NULL, NULL, 0, + BLN_NOOPT | BLN_NEW | (listed ? BLN_LISTED : 0)); + if (buf == NULL) { + unblock_autocmds(); + goto fail; + } - // Only strictly needed for scratch, but could just as well be consistent - // and do this now. Buffer is created NOW, not when it later first happens - // to reach a window or aucmd_prepbuf() .. - buf_copy_options(buf, BCO_ENTER | BCO_NOHELP); + // Open the memline for the buffer. This will avoid spurious autocmds when + // a later nvim_buf_set_lines call would have needed to "open" the buffer. + if (ml_open(buf) == FAIL) { + unblock_autocmds(); + goto fail; + } - if (scratch) { - set_option_direct_for(kOptBufhidden, STATIC_CSTR_AS_OPTVAL("hide"), OPT_LOCAL, 0, - kOptScopeBuf, buf); - set_option_direct_for(kOptBuftype, STATIC_CSTR_AS_OPTVAL("nofile"), OPT_LOCAL, 0, - kOptScopeBuf, buf); - assert(buf->b_ml.ml_mfp->mf_fd < 0); // ml_open() should not have opened swapfile already - buf->b_p_swf = false; - buf->b_p_ml = false; - } + // Set last_changedtick to avoid triggering a TextChanged autocommand right + // after it was added. + buf->b_last_changedtick = buf_get_changedtick(buf); + buf->b_last_changedtick_i = buf_get_changedtick(buf); + buf->b_last_changedtick_pum = buf_get_changedtick(buf); + + // Only strictly needed for scratch, but could just as well be consistent + // and do this now. Buffer is created NOW, not when it later first happens + // to reach a window or aucmd_prepbuf() .. + buf_copy_options(buf, BCO_ENTER | BCO_NOHELP); + + if (scratch) { + set_option_direct_for(kOptBufhidden, STATIC_CSTR_AS_OPTVAL("hide"), OPT_LOCAL, 0, + kOptScopeBuf, buf); + set_option_direct_for(kOptBuftype, STATIC_CSTR_AS_OPTVAL("nofile"), OPT_LOCAL, 0, + kOptScopeBuf, buf); + assert(buf->b_ml.ml_mfp->mf_fd < 0); // ml_open() should not have opened swapfile already + buf->b_p_swf = false; + buf->b_p_ml = false; + } - unblock_autocmds(); + unblock_autocmds(); - bufref_T bufref; - set_bufref(&bufref, buf); - if (apply_autocmds(EVENT_BUFNEW, NULL, NULL, false, buf) - && !bufref_valid(&bufref)) { - goto fail; - } - if (listed - && apply_autocmds(EVENT_BUFADD, NULL, NULL, false, buf) - && !bufref_valid(&bufref)) { - goto fail; - } + bufref_T bufref; + set_bufref(&bufref, buf); + if (apply_autocmds(EVENT_BUFNEW, NULL, NULL, false, buf) + && !bufref_valid(&bufref)) { + goto fail; + } + if (listed + && apply_autocmds(EVENT_BUFADD, NULL, NULL, false, buf) + && !bufref_valid(&bufref)) { + goto fail; + } - try_end(err); - return buf->b_fnum; + ret = buf->b_fnum; + fail:; + }); -fail: - if (!try_end(err)) { + if (ret == 0 && !ERROR_SET(err)) { api_set_error(err, kErrorTypeException, "Failed to create buffer"); } - return 0; + return ret; } /// Open a terminal instance in a buffer diff --git a/src/nvim/api/vimscript.c b/src/nvim/api/vimscript.c index 0ff2b037ce..67db615b20 100644 --- a/src/nvim/api/vimscript.c +++ b/src/nvim/api/vimscript.c @@ -78,24 +78,24 @@ String exec_impl(uint64_t channel_id, String src, Dict(exec_opts) *opts, Error * capture_ga = &capture_local; } - try_start(); - if (opts->output) { - msg_silent++; - msg_col = 0; // prevent leading spaces - } + TRY_WRAP(err, { + if (opts->output) { + msg_silent++; + msg_col = 0; // prevent leading spaces + } - const sctx_T save_current_sctx = api_set_sctx(channel_id); + const sctx_T save_current_sctx = api_set_sctx(channel_id); - do_source_str(src.data, "nvim_exec2()"); - if (opts->output) { - capture_ga = save_capture_ga; - msg_silent = save_msg_silent; - // Put msg_col back where it was, since nothing should have been written. - msg_col = save_msg_col; - } + do_source_str(src.data, "nvim_exec2()"); + if (opts->output) { + capture_ga = save_capture_ga; + msg_silent = save_msg_silent; + // Put msg_col back where it was, since nothing should have been written. + msg_col = save_msg_col; + } - current_sctx = save_current_sctx; - try_end(err); + current_sctx = save_current_sctx; + }); if (ERROR_SET(err)) { goto theend; diff --git a/src/nvim/api/window.c b/src/nvim/api/window.c index f5e8d8f086..387dad899e 100644 --- a/src/nvim/api/window.c +++ b/src/nvim/api/window.c @@ -368,19 +368,16 @@ void nvim_win_hide(Window window, Error *err) } tabpage_T *tabpage = win_find_tabpage(win); - TryState tstate; - try_enter(&tstate); - - // Never close the autocommand window. - if (is_aucmd_win(win)) { - emsg(_(e_autocmd_close)); - } else if (tabpage == curtab) { - win_close(win, false, false); - } else { - win_close_othertab(win, false, tabpage); - } - - vim_ignored = try_leave(&tstate, err); + TRY_WRAP(err, { + // Never close the autocommand window. + if (is_aucmd_win(win)) { + emsg(_(e_autocmd_close)); + } else if (tabpage == curtab) { + win_close(win, false, false); + } else { + win_close_othertab(win, false, tabpage); + } + }); } /// Closes the window (like |:close| with a |window-ID|). @@ -400,10 +397,9 @@ void nvim_win_close(Window window, Boolean force, Error *err) } tabpage_T *tabpage = win_find_tabpage(win); - TryState tstate; - try_enter(&tstate); - ex_win_close(force, win, tabpage == curtab ? NULL : tabpage); - vim_ignored = try_leave(&tstate, err); + TRY_WRAP(err, { + ex_win_close(force, win, tabpage == curtab ? NULL : tabpage); + }); } /// Calls a function with window as temporary current window. |