mirror of
https://github.com/neovim/neovim.git
synced 2025-02-25 18:55:25 -06:00
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.
This commit is contained in:
parent
b03e790cdd
commit
6bf2a6fc5b
@ -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);
|
memchrsub(lines[i], NUL, NL, l.size);
|
||||||
}
|
}
|
||||||
|
|
||||||
try_start();
|
TRY_WRAP(err, {
|
||||||
|
if (!MODIFIABLE(buf)) {
|
||||||
if (!MODIFIABLE(buf)) {
|
api_set_error(err, kErrorTypeException, "Buffer is not 'modifiable'");
|
||||||
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");
|
|
||||||
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;
|
|
||||||
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;
|
goto end;
|
||||||
}
|
}
|
||||||
|
|
||||||
inserted_bytes += (bcount_t)strlen(lines[i]) + 1;
|
if (u_save_buf(buf, (linenr_T)(start - 1), (linenr_T)end) == FAIL) {
|
||||||
}
|
api_set_error(err, kErrorTypeException, "Failed to save undo information");
|
||||||
|
|
||||||
// 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;
|
|
||||||
|
|
||||||
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;
|
goto end;
|
||||||
}
|
}
|
||||||
|
|
||||||
inserted_bytes += (bcount_t)strlen(lines[i]) + 1;
|
bcount_t deleted_bytes = get_region_bytecount(buf, (linenr_T)start, (linenr_T)end, 0, 0);
|
||||||
|
|
||||||
extra++;
|
// 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".
|
||||||
// Adjust marks. Invalidate any which lie in the
|
size_t to_delete = (new_len < old_len) ? old_len - new_len : 0;
|
||||||
// changed range, and move any in the remainder of the buffer.
|
for (size_t i = 0; i < to_delete; i++) {
|
||||||
linenr_T adjust = end > start ? MAXLNUM : 0;
|
if (ml_delete_buf(buf, (linenr_T)start, false) == FAIL) {
|
||||||
mark_adjust_buf(buf, (linenr_T)start, (linenr_T)(end - 1), adjust, (linenr_T)extra,
|
api_set_error(err, kErrorTypeException, "Failed to delete line");
|
||||||
true, true, kExtmarkNOOP);
|
goto end;
|
||||||
|
}
|
||||||
extmark_splice(buf, (int)start - 1, 0, (int)(end - start), 0,
|
|
||||||
deleted_bytes, (int)new_len, 0, inserted_bytes,
|
|
||||||
kExtmarkUndo);
|
|
||||||
|
|
||||||
changed_lines(buf, (linenr_T)start, 0, (linenr_T)end, (linenr_T)extra, true);
|
|
||||||
|
|
||||||
FOR_ALL_TAB_WINDOWS(tp, win) {
|
|
||||||
if (win->w_buffer == buf) {
|
|
||||||
fix_cursor(win, (linenr_T)start, (linenr_T)end, (linenr_T)extra);
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
end:
|
if (to_delete > 0) {
|
||||||
try_end(err);
|
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;
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
inserted_bytes += (bcount_t)strlen(lines[i]) + 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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;
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
inserted_bytes += (bcount_t)strlen(lines[i]) + 1;
|
||||||
|
|
||||||
|
extra++;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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);
|
||||||
|
|
||||||
|
extmark_splice(buf, (int)start - 1, 0, (int)(end - start), 0,
|
||||||
|
deleted_bytes, (int)new_len, 0, inserted_bytes,
|
||||||
|
kExtmarkUndo);
|
||||||
|
|
||||||
|
changed_lines(buf, (linenr_T)start, 0, (linenr_T)end, (linenr_T)extra, true);
|
||||||
|
|
||||||
|
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
|
/// 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;
|
new_byte += (bcount_t)(last_item.size) + 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
try_start();
|
TRY_WRAP(err, {
|
||||||
|
if (!MODIFIABLE(buf)) {
|
||||||
if (!MODIFIABLE(buf)) {
|
api_set_error(err, kErrorTypeException, "Buffer is not 'modifiable'");
|
||||||
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");
|
|
||||||
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", {
|
|
||||||
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_row + (int64_t)i - 1;
|
|
||||||
|
|
||||||
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;
|
goto end;
|
||||||
}
|
}
|
||||||
|
|
||||||
extra++;
|
// 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;
|
||||||
|
}
|
||||||
|
|
||||||
colnr_T col_extent = (colnr_T)(end_col
|
ptrdiff_t extra = 0; // lines added to text, can be negative
|
||||||
- ((end_row == start_row) ? start_col : 0));
|
size_t old_len = (size_t)(end_row - start_row + 1);
|
||||||
|
|
||||||
// Adjust marks. Invalidate any which lie in the
|
// If the size of the range is reducing (ie, new_len < old_len) we
|
||||||
// changed range, and move any in the remainder of the buffer.
|
// need to delete some old_len. We do this at the start, by
|
||||||
// Do not adjust any cursors. need to use column-aware logic (below)
|
// repeatedly deleting line "start".
|
||||||
linenr_T adjust = end_row >= start_row ? MAXLNUM : 0;
|
size_t to_delete = (new_len < old_len) ? old_len - new_len : 0;
|
||||||
mark_adjust_buf(buf, (linenr_T)start_row, (linenr_T)end_row, adjust, (linenr_T)extra,
|
for (size_t i = 0; i < to_delete; i++) {
|
||||||
true, true, kExtmarkNOOP);
|
if (ml_delete_buf(buf, (linenr_T)start_row, false) == FAIL) {
|
||||||
|
api_set_error(err, kErrorTypeException, "Failed to delete line");
|
||||||
extmark_splice(buf, (int)start_row - 1, (colnr_T)start_col,
|
goto end;
|
||||||
(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:
|
if (to_delete > 0) {
|
||||||
try_end(err);
|
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", {
|
||||||
|
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_row + (int64_t)i - 1;
|
||||||
|
|
||||||
|
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++;
|
||||||
|
}
|
||||||
|
|
||||||
|
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.
|
/// Gets a range from the buffer.
|
||||||
@ -965,26 +961,27 @@ void nvim_buf_set_name(Buffer buffer, String name, Error *err)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
try_start();
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
const bool is_curbuf = buf == curbuf;
|
// Using aucmd_*: autocommands will be executed by rename_buffer
|
||||||
const int save_acd = p_acd;
|
aco_save_T aco;
|
||||||
if (!is_curbuf) {
|
aucmd_prepbuf(&aco, buf);
|
||||||
// Temporarily disable 'autochdir' when setting file name for another buffer.
|
ren_ret = rename_buffer(name.data);
|
||||||
p_acd = false;
|
aucmd_restbuf(&aco);
|
||||||
}
|
|
||||||
|
|
||||||
// Using aucmd_*: autocommands will be executed by rename_buffer
|
if (!is_curbuf) {
|
||||||
aco_save_T aco;
|
p_acd = save_acd;
|
||||||
aucmd_prepbuf(&aco, buf);
|
}
|
||||||
int ren_ret = rename_buffer(name.data);
|
});
|
||||||
aucmd_restbuf(&aco);
|
|
||||||
|
|
||||||
if (!is_curbuf) {
|
if (ERROR_SET(err)) {
|
||||||
p_acd = save_acd;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (try_end(err)) {
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1204,15 +1201,18 @@ Object nvim_buf_call(Buffer buffer, LuaRef fun, Error *err)
|
|||||||
if (!buf) {
|
if (!buf) {
|
||||||
return NIL;
|
return NIL;
|
||||||
}
|
}
|
||||||
try_start();
|
|
||||||
aco_save_T aco;
|
|
||||||
aucmd_prepbuf(&aco, buf);
|
|
||||||
|
|
||||||
Array args = ARRAY_DICT_INIT;
|
Object res = OBJECT_INIT;
|
||||||
Object res = nlua_call_ref(fun, NULL, args, kRetLuaref, NULL, err);
|
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;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -42,8 +42,10 @@
|
|||||||
|
|
||||||
/// Start block that may cause Vimscript exceptions while evaluating another code
|
/// 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
|
/// Used just in case caller is supposed to be operating when other Vimscript code
|
||||||
/// processed and that “other Vimscript code” must not be affected.
|
/// 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.
|
/// @param[out] tstate Location where try state should be saved.
|
||||||
void try_enter(TryState *const tstate)
|
void try_enter(TryState *const tstate)
|
||||||
@ -55,75 +57,33 @@ void try_enter(TryState *const tstate)
|
|||||||
.current_exception = current_exception,
|
.current_exception = current_exception,
|
||||||
.msg_list = (const msglist_T *const *)msg_list,
|
.msg_list = (const msglist_T *const *)msg_list,
|
||||||
.private_msg_list = NULL,
|
.private_msg_list = NULL,
|
||||||
.trylevel = trylevel,
|
|
||||||
.got_int = got_int,
|
.got_int = got_int,
|
||||||
.did_throw = did_throw,
|
.did_throw = did_throw,
|
||||||
.need_rethrow = need_rethrow,
|
.need_rethrow = need_rethrow,
|
||||||
.did_emsg = did_emsg,
|
.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;
|
msg_list = &tstate->private_msg_list;
|
||||||
current_exception = NULL;
|
current_exception = NULL;
|
||||||
trylevel = 1;
|
|
||||||
got_int = false;
|
got_int = false;
|
||||||
did_throw = false;
|
did_throw = false;
|
||||||
need_rethrow = false;
|
need_rethrow = false;
|
||||||
did_emsg = 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++;
|
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
|
/// @param[out] err Pointer to the stack-allocated error object
|
||||||
/// @return true if an error occurred
|
void try_leave(const TryState *const tstate, Error *const err)
|
||||||
bool try_end(Error *err)
|
FUNC_ATTR_NONNULL_ALL
|
||||||
{
|
{
|
||||||
// Note: all globals manipulated here should be saved/restored in
|
// Note: all globals manipulated here should be saved/restored in
|
||||||
// try_enter/try_leave.
|
// try_enter/try_leave.
|
||||||
|
assert(trylevel > 0);
|
||||||
trylevel--;
|
trylevel--;
|
||||||
|
|
||||||
// Set by emsg(), affects aborting(). See also enter_cleanup().
|
// Set by emsg(), affects aborting(). See also enter_cleanup().
|
||||||
@ -166,7 +126,20 @@ bool try_end(Error *err)
|
|||||||
discard_current_exception();
|
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
|
/// Recursively expands a vimscript value in a dict
|
||||||
|
@ -147,27 +147,19 @@ typedef struct {
|
|||||||
except_T *current_exception;
|
except_T *current_exception;
|
||||||
msglist_T *private_msg_list;
|
msglist_T *private_msg_list;
|
||||||
const msglist_T *const *msg_list;
|
const msglist_T *const *msg_list;
|
||||||
int trylevel;
|
|
||||||
int got_int;
|
int got_int;
|
||||||
bool did_throw;
|
bool did_throw;
|
||||||
int need_rethrow;
|
int need_rethrow;
|
||||||
int did_emsg;
|
int did_emsg;
|
||||||
} TryState;
|
} 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).
|
// TODO(bfredl): prepare error-handling at "top level" (nv_event).
|
||||||
#define TRY_WRAP(err, code) \
|
#define TRY_WRAP(err, code) \
|
||||||
do { \
|
do { \
|
||||||
msglist_T **saved_msg_list = msg_list; \
|
TryState tstate; \
|
||||||
msglist_T *private_msg_list; \
|
try_enter(&tstate); \
|
||||||
msg_list = &private_msg_list; \
|
|
||||||
private_msg_list = NULL; \
|
|
||||||
try_start(); \
|
|
||||||
code; \
|
code; \
|
||||||
try_end(err); \
|
try_leave(&tstate, err); \
|
||||||
msg_list = saved_msg_list; /* Restore the exception context. */ \
|
|
||||||
} while (0)
|
} while (0)
|
||||||
|
|
||||||
// Execute code with cursor position saved and restored and textlock active.
|
// Execute code with cursor position saved and restored and textlock active.
|
||||||
|
@ -146,11 +146,9 @@ void nvim_tabpage_set_win(Tabpage tabpage, Window win, Error *err)
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (tp == curtab) {
|
if (tp == curtab) {
|
||||||
try_start();
|
TRY_WRAP(err, {
|
||||||
win_goto(wp);
|
win_goto(wp);
|
||||||
if (!try_end(err) && curwin != wp) {
|
});
|
||||||
api_set_error(err, kErrorTypeException, "Failed to switch to window %d", win);
|
|
||||||
}
|
|
||||||
} else if (tp->tp_curwin != wp) {
|
} else if (tp->tp_curwin != wp) {
|
||||||
tp->tp_prevwin = tp->tp_curwin;
|
tp->tp_prevwin = tp->tp_curwin;
|
||||||
tp->tp_curwin = wp;
|
tp->tp_curwin = wp;
|
||||||
|
@ -594,12 +594,10 @@ ArrayOf(String) nvim_get_runtime_file(String name, Boolean all, Arena *arena, Er
|
|||||||
kvi_init(cookie.rv);
|
kvi_init(cookie.rv);
|
||||||
|
|
||||||
int flags = DIP_DIRFILE | (all ? DIP_ALL : 0);
|
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_WRAP(err, {
|
||||||
try_enter(&tstate);
|
do_in_runtimepath((name.size ? name.data : ""), flags, find_runtime_cb, &cookie);
|
||||||
do_in_runtimepath((name.size ? name.data : ""), flags, find_runtime_cb, &cookie);
|
});
|
||||||
vim_ignored = try_leave(&tstate, err);
|
|
||||||
|
|
||||||
return arena_take_arraybuilder(arena, &cookie.rv);
|
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)
|
Buffer nvim_create_buf(Boolean listed, Boolean scratch, Error *err)
|
||||||
FUNC_API_SINCE(6)
|
FUNC_API_SINCE(6)
|
||||||
{
|
{
|
||||||
try_start();
|
Buffer ret = 0;
|
||||||
// Block autocommands for now so they don't mess with the buffer before we
|
|
||||||
// finish configuring it.
|
TRY_WRAP(err, {
|
||||||
block_autocmds();
|
// 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;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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);
|
||||||
|
|
||||||
|
// 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;
|
||||||
|
}
|
||||||
|
|
||||||
buf_T *buf = buflist_new(NULL, NULL, 0,
|
|
||||||
BLN_NOOPT | BLN_NEW | (listed ? BLN_LISTED : 0));
|
|
||||||
if (buf == NULL) {
|
|
||||||
unblock_autocmds();
|
unblock_autocmds();
|
||||||
goto fail;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Open the memline for the buffer. This will avoid spurious autocmds when
|
bufref_T bufref;
|
||||||
// a later nvim_buf_set_lines call would have needed to "open" the buffer.
|
set_bufref(&bufref, buf);
|
||||||
if (ml_open(buf) == FAIL) {
|
if (apply_autocmds(EVENT_BUFNEW, NULL, NULL, false, buf)
|
||||||
unblock_autocmds();
|
&& !bufref_valid(&bufref)) {
|
||||||
goto fail;
|
goto fail;
|
||||||
}
|
}
|
||||||
|
if (listed
|
||||||
|
&& apply_autocmds(EVENT_BUFADD, NULL, NULL, false, buf)
|
||||||
|
&& !bufref_valid(&bufref)) {
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
|
||||||
// Set last_changedtick to avoid triggering a TextChanged autocommand right
|
ret = buf->b_fnum;
|
||||||
// after it was added.
|
fail:;
|
||||||
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
|
if (ret == 0 && !ERROR_SET(err)) {
|
||||||
// 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();
|
|
||||||
|
|
||||||
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;
|
|
||||||
|
|
||||||
fail:
|
|
||||||
if (!try_end(err)) {
|
|
||||||
api_set_error(err, kErrorTypeException, "Failed to create buffer");
|
api_set_error(err, kErrorTypeException, "Failed to create buffer");
|
||||||
}
|
}
|
||||||
return 0;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Open a terminal instance in a buffer
|
/// Open a terminal instance in a buffer
|
||||||
|
@ -78,24 +78,24 @@ String exec_impl(uint64_t channel_id, String src, Dict(exec_opts) *opts, Error *
|
|||||||
capture_ga = &capture_local;
|
capture_ga = &capture_local;
|
||||||
}
|
}
|
||||||
|
|
||||||
try_start();
|
TRY_WRAP(err, {
|
||||||
if (opts->output) {
|
if (opts->output) {
|
||||||
msg_silent++;
|
msg_silent++;
|
||||||
msg_col = 0; // prevent leading spaces
|
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()");
|
do_source_str(src.data, "nvim_exec2()");
|
||||||
if (opts->output) {
|
if (opts->output) {
|
||||||
capture_ga = save_capture_ga;
|
capture_ga = save_capture_ga;
|
||||||
msg_silent = save_msg_silent;
|
msg_silent = save_msg_silent;
|
||||||
// Put msg_col back where it was, since nothing should have been written.
|
// Put msg_col back where it was, since nothing should have been written.
|
||||||
msg_col = save_msg_col;
|
msg_col = save_msg_col;
|
||||||
}
|
}
|
||||||
|
|
||||||
current_sctx = save_current_sctx;
|
current_sctx = save_current_sctx;
|
||||||
try_end(err);
|
});
|
||||||
|
|
||||||
if (ERROR_SET(err)) {
|
if (ERROR_SET(err)) {
|
||||||
goto theend;
|
goto theend;
|
||||||
|
@ -368,19 +368,16 @@ void nvim_win_hide(Window window, Error *err)
|
|||||||
}
|
}
|
||||||
|
|
||||||
tabpage_T *tabpage = win_find_tabpage(win);
|
tabpage_T *tabpage = win_find_tabpage(win);
|
||||||
TryState tstate;
|
TRY_WRAP(err, {
|
||||||
try_enter(&tstate);
|
// Never close the autocommand window.
|
||||||
|
if (is_aucmd_win(win)) {
|
||||||
// Never close the autocommand window.
|
emsg(_(e_autocmd_close));
|
||||||
if (is_aucmd_win(win)) {
|
} else if (tabpage == curtab) {
|
||||||
emsg(_(e_autocmd_close));
|
win_close(win, false, false);
|
||||||
} else if (tabpage == curtab) {
|
} else {
|
||||||
win_close(win, false, false);
|
win_close_othertab(win, false, tabpage);
|
||||||
} else {
|
}
|
||||||
win_close_othertab(win, false, tabpage);
|
});
|
||||||
}
|
|
||||||
|
|
||||||
vim_ignored = try_leave(&tstate, err);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Closes the window (like |:close| with a |window-ID|).
|
/// 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);
|
tabpage_T *tabpage = win_find_tabpage(win);
|
||||||
TryState tstate;
|
TRY_WRAP(err, {
|
||||||
try_enter(&tstate);
|
ex_win_close(force, win, tabpage == curtab ? NULL : tabpage);
|
||||||
ex_win_close(force, win, tabpage == curtab ? NULL : tabpage);
|
});
|
||||||
vim_ignored = try_leave(&tstate, err);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Calls a function with window as temporary current window.
|
/// Calls a function with window as temporary current window.
|
||||||
|
@ -787,9 +787,7 @@ static uint8_t *command_line_enter(int firstc, int count, int indent, bool clear
|
|||||||
setmouse();
|
setmouse();
|
||||||
setcursor();
|
setcursor();
|
||||||
|
|
||||||
TryState tstate;
|
|
||||||
Error err = ERROR_INIT;
|
Error err = ERROR_INIT;
|
||||||
bool tl_ret = true;
|
|
||||||
char firstcbuf[2];
|
char firstcbuf[2];
|
||||||
firstcbuf[0] = (char)(firstc > 0 ? firstc : '-');
|
firstcbuf[0] = (char)(firstc > 0 ? firstc : '-');
|
||||||
firstcbuf[1] = 0;
|
firstcbuf[1] = 0;
|
||||||
@ -802,20 +800,19 @@ static uint8_t *command_line_enter(int firstc, int count, int indent, bool clear
|
|||||||
tv_dict_add_str(dict, S_LEN("cmdtype"), firstcbuf);
|
tv_dict_add_str(dict, S_LEN("cmdtype"), firstcbuf);
|
||||||
tv_dict_add_nr(dict, S_LEN("cmdlevel"), ccline.level);
|
tv_dict_add_nr(dict, S_LEN("cmdlevel"), ccline.level);
|
||||||
tv_dict_set_keys_readonly(dict);
|
tv_dict_set_keys_readonly(dict);
|
||||||
try_enter(&tstate);
|
TRY_WRAP(&err, {
|
||||||
|
apply_autocmds(EVENT_CMDLINEENTER, firstcbuf, firstcbuf, false, curbuf);
|
||||||
|
restore_v_event(dict, &save_v_event);
|
||||||
|
});
|
||||||
|
|
||||||
apply_autocmds(EVENT_CMDLINEENTER, firstcbuf, firstcbuf, false, curbuf);
|
if (ERROR_SET(&err)) {
|
||||||
restore_v_event(dict, &save_v_event);
|
|
||||||
|
|
||||||
tl_ret = try_leave(&tstate, &err);
|
|
||||||
if (!tl_ret && ERROR_SET(&err)) {
|
|
||||||
msg_putchar('\n');
|
msg_putchar('\n');
|
||||||
msg_scroll = true;
|
msg_scroll = true;
|
||||||
msg_puts_hl(err.msg, HLF_E, true);
|
msg_puts_hl(err.msg, HLF_E, true);
|
||||||
api_clear_error(&err);
|
api_clear_error(&err);
|
||||||
redrawcmd();
|
redrawcmd();
|
||||||
}
|
}
|
||||||
tl_ret = true;
|
err = ERROR_INIT;
|
||||||
}
|
}
|
||||||
may_trigger_modechanged();
|
may_trigger_modechanged();
|
||||||
|
|
||||||
@ -873,10 +870,10 @@ static uint8_t *command_line_enter(int firstc, int count, int indent, bool clear
|
|||||||
// not readonly:
|
// not readonly:
|
||||||
tv_dict_add_bool(dict, S_LEN("abort"),
|
tv_dict_add_bool(dict, S_LEN("abort"),
|
||||||
s->gotesc ? kBoolVarTrue : kBoolVarFalse);
|
s->gotesc ? kBoolVarTrue : kBoolVarFalse);
|
||||||
try_enter(&tstate);
|
TRY_WRAP(&err, {
|
||||||
apply_autocmds(EVENT_CMDLINELEAVE, firstcbuf, firstcbuf, false, curbuf);
|
apply_autocmds(EVENT_CMDLINELEAVE, firstcbuf, firstcbuf, false, curbuf);
|
||||||
// error printed below, to avoid redraw issues
|
// error printed below, to avoid redraw issues
|
||||||
tl_ret = try_leave(&tstate, &err);
|
});
|
||||||
if (tv_dict_get_number(dict, "abort") != 0) {
|
if (tv_dict_get_number(dict, "abort") != 0) {
|
||||||
s->gotesc = true;
|
s->gotesc = true;
|
||||||
}
|
}
|
||||||
@ -929,7 +926,7 @@ static uint8_t *command_line_enter(int firstc, int count, int indent, bool clear
|
|||||||
msg_scroll = s->save_msg_scroll;
|
msg_scroll = s->save_msg_scroll;
|
||||||
redir_off = false;
|
redir_off = false;
|
||||||
|
|
||||||
if (!tl_ret && ERROR_SET(&err)) {
|
if (ERROR_SET(&err)) {
|
||||||
msg_putchar('\n');
|
msg_putchar('\n');
|
||||||
emsg(err.msg);
|
emsg(err.msg);
|
||||||
did_emsg = false;
|
did_emsg = false;
|
||||||
@ -937,7 +934,7 @@ static uint8_t *command_line_enter(int firstc, int count, int indent, bool clear
|
|||||||
}
|
}
|
||||||
|
|
||||||
// When the command line was typed, no need for a wait-return prompt.
|
// When the command line was typed, no need for a wait-return prompt.
|
||||||
if (s->some_key_typed && tl_ret) {
|
if (s->some_key_typed && !ERROR_SET(&err)) {
|
||||||
need_wait_return = false;
|
need_wait_return = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2315,11 +2312,13 @@ static win_T *cmdpreview_open_win(buf_T *cmdpreview_buf)
|
|||||||
|
|
||||||
win_T *preview_win = curwin;
|
win_T *preview_win = curwin;
|
||||||
Error err = ERROR_INIT;
|
Error err = ERROR_INIT;
|
||||||
|
int result = OK;
|
||||||
|
|
||||||
// Switch to preview buffer
|
// Switch to preview buffer
|
||||||
try_start();
|
TRY_WRAP(&err, {
|
||||||
int result = do_buffer(DOBUF_GOTO, DOBUF_FIRST, FORWARD, cmdpreview_buf->handle, 0);
|
result = do_buffer(DOBUF_GOTO, DOBUF_FIRST, FORWARD, cmdpreview_buf->handle, 0);
|
||||||
if (try_end(&err) || result == FAIL) {
|
});
|
||||||
|
if (ERROR_SET(&err) || result == FAIL) {
|
||||||
api_clear_error(&err);
|
api_clear_error(&err);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
@ -2600,9 +2599,10 @@ static bool cmdpreview_may_show(CommandLineState *s)
|
|||||||
// open the preview window. The preview callback also handles doing the changes and highlights for
|
// open the preview window. The preview callback also handles doing the changes and highlights for
|
||||||
// the preview.
|
// the preview.
|
||||||
Error err = ERROR_INIT;
|
Error err = ERROR_INIT;
|
||||||
try_start();
|
TRY_WRAP(&err, {
|
||||||
cmdpreview_type = execute_cmd(&ea, &cmdinfo, true);
|
cmdpreview_type = execute_cmd(&ea, &cmdinfo, true);
|
||||||
if (try_end(&err)) {
|
});
|
||||||
|
if (ERROR_SET(&err)) {
|
||||||
api_clear_error(&err);
|
api_clear_error(&err);
|
||||||
cmdpreview_type = 0;
|
cmdpreview_type = 0;
|
||||||
}
|
}
|
||||||
@ -2643,7 +2643,6 @@ end:
|
|||||||
static void do_autocmd_cmdlinechanged(int firstc)
|
static void do_autocmd_cmdlinechanged(int firstc)
|
||||||
{
|
{
|
||||||
if (has_event(EVENT_CMDLINECHANGED)) {
|
if (has_event(EVENT_CMDLINECHANGED)) {
|
||||||
TryState tstate;
|
|
||||||
Error err = ERROR_INIT;
|
Error err = ERROR_INIT;
|
||||||
save_v_event_T save_v_event;
|
save_v_event_T save_v_event;
|
||||||
dict_T *dict = get_v_event(&save_v_event);
|
dict_T *dict = get_v_event(&save_v_event);
|
||||||
@ -2656,13 +2655,11 @@ static void do_autocmd_cmdlinechanged(int firstc)
|
|||||||
tv_dict_add_str(dict, S_LEN("cmdtype"), firstcbuf);
|
tv_dict_add_str(dict, S_LEN("cmdtype"), firstcbuf);
|
||||||
tv_dict_add_nr(dict, S_LEN("cmdlevel"), ccline.level);
|
tv_dict_add_nr(dict, S_LEN("cmdlevel"), ccline.level);
|
||||||
tv_dict_set_keys_readonly(dict);
|
tv_dict_set_keys_readonly(dict);
|
||||||
try_enter(&tstate);
|
TRY_WRAP(&err, {
|
||||||
|
apply_autocmds(EVENT_CMDLINECHANGED, firstcbuf, firstcbuf, false, curbuf);
|
||||||
apply_autocmds(EVENT_CMDLINECHANGED, firstcbuf, firstcbuf, false, curbuf);
|
restore_v_event(dict, &save_v_event);
|
||||||
restore_v_event(dict, &save_v_event);
|
});
|
||||||
|
if (ERROR_SET(&err)) {
|
||||||
bool tl_ret = try_leave(&tstate, &err);
|
|
||||||
if (!tl_ret && ERROR_SET(&err)) {
|
|
||||||
msg_putchar('\n');
|
msg_putchar('\n');
|
||||||
msg_scroll = true;
|
msg_scroll = true;
|
||||||
msg_puts_hl(err.msg, HLF_E, true);
|
msg_puts_hl(err.msg, HLF_E, true);
|
||||||
@ -3179,11 +3176,9 @@ static bool color_cmdline(CmdlineInfo *colored_ccline)
|
|||||||
static int prev_prompt_errors = 0;
|
static int prev_prompt_errors = 0;
|
||||||
Callback color_cb = CALLBACK_NONE;
|
Callback color_cb = CALLBACK_NONE;
|
||||||
bool can_free_cb = false;
|
bool can_free_cb = false;
|
||||||
TryState tstate;
|
|
||||||
Error err = ERROR_INIT;
|
Error err = ERROR_INIT;
|
||||||
const char *err_errmsg = e_intern2;
|
const char *err_errmsg = e_intern2;
|
||||||
bool dgc_ret = true;
|
bool dgc_ret = true;
|
||||||
bool tl_ret = true;
|
|
||||||
|
|
||||||
if (colored_ccline->prompt_id != prev_prompt_id) {
|
if (colored_ccline->prompt_id != prev_prompt_id) {
|
||||||
prev_prompt_errors = 0;
|
prev_prompt_errors = 0;
|
||||||
@ -3196,16 +3191,16 @@ static bool color_cmdline(CmdlineInfo *colored_ccline)
|
|||||||
assert(colored_ccline->input_fn);
|
assert(colored_ccline->input_fn);
|
||||||
color_cb = colored_ccline->highlight_callback;
|
color_cb = colored_ccline->highlight_callback;
|
||||||
} else if (colored_ccline->cmdfirstc == ':') {
|
} else if (colored_ccline->cmdfirstc == ':') {
|
||||||
try_enter(&tstate);
|
TRY_WRAP(&err, {
|
||||||
err_errmsg = N_("E5408: Unable to get g:Nvim_color_cmdline callback: %s");
|
err_errmsg = N_("E5408: Unable to get g:Nvim_color_cmdline callback: %s");
|
||||||
dgc_ret = tv_dict_get_callback(&globvardict, S_LEN("Nvim_color_cmdline"),
|
dgc_ret = tv_dict_get_callback(&globvardict, S_LEN("Nvim_color_cmdline"),
|
||||||
&color_cb);
|
&color_cb);
|
||||||
tl_ret = try_leave(&tstate, &err);
|
});
|
||||||
can_free_cb = true;
|
can_free_cb = true;
|
||||||
} else if (colored_ccline->cmdfirstc == '=') {
|
} else if (colored_ccline->cmdfirstc == '=') {
|
||||||
color_expr_cmdline(colored_ccline, ccline_colors);
|
color_expr_cmdline(colored_ccline, ccline_colors);
|
||||||
}
|
}
|
||||||
if (!tl_ret || !dgc_ret) {
|
if (ERROR_SET(&err) || !dgc_ret) {
|
||||||
goto color_cmdline_error;
|
goto color_cmdline_error;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -3226,20 +3221,22 @@ static bool color_cmdline(CmdlineInfo *colored_ccline)
|
|||||||
// correct, with msg_col it just misses leading `:`. Since `redraw!` in
|
// correct, with msg_col it just misses leading `:`. Since `redraw!` in
|
||||||
// callback lags this is least of the user problems.
|
// callback lags this is least of the user problems.
|
||||||
//
|
//
|
||||||
// Also using try_enter() because error messages may overwrite typed
|
// Also using TRY_WRAP because error messages may overwrite typed
|
||||||
// command-line which is not expected.
|
// command-line which is not expected.
|
||||||
getln_interrupted_highlight = false;
|
getln_interrupted_highlight = false;
|
||||||
try_enter(&tstate);
|
bool cbcall_ret = true;
|
||||||
err_errmsg = N_("E5407: Callback has thrown an exception: %s");
|
TRY_WRAP(&err, {
|
||||||
const int saved_msg_col = msg_col;
|
err_errmsg = N_("E5407: Callback has thrown an exception: %s");
|
||||||
msg_silent++;
|
const int saved_msg_col = msg_col;
|
||||||
const bool cbcall_ret = callback_call(&color_cb, 1, &arg, &tv);
|
msg_silent++;
|
||||||
msg_silent--;
|
cbcall_ret = callback_call(&color_cb, 1, &arg, &tv);
|
||||||
msg_col = saved_msg_col;
|
msg_silent--;
|
||||||
if (got_int) {
|
msg_col = saved_msg_col;
|
||||||
getln_interrupted_highlight = true;
|
if (got_int) {
|
||||||
}
|
getln_interrupted_highlight = true;
|
||||||
if (!try_leave(&tstate, &err) || !cbcall_ret) {
|
}
|
||||||
|
});
|
||||||
|
if (ERROR_SET(&err) || !cbcall_ret) {
|
||||||
goto color_cmdline_error;
|
goto color_cmdline_error;
|
||||||
}
|
}
|
||||||
if (tv.v_type != VAR_LIST) {
|
if (tv.v_type != VAR_LIST) {
|
||||||
|
@ -623,38 +623,32 @@ static int nlua_with(lua_State *L)
|
|||||||
cmdmod.cmod_flags = flags;
|
cmdmod.cmod_flags = flags;
|
||||||
apply_cmdmod(&cmdmod);
|
apply_cmdmod(&cmdmod);
|
||||||
|
|
||||||
if (buf || win) {
|
|
||||||
try_start();
|
|
||||||
}
|
|
||||||
|
|
||||||
aco_save_T aco;
|
|
||||||
win_execute_T win_execute_args;
|
|
||||||
Error err = ERROR_INIT;
|
Error err = ERROR_INIT;
|
||||||
|
TRY_WRAP(&err, {
|
||||||
|
aco_save_T aco;
|
||||||
|
win_execute_T win_execute_args;
|
||||||
|
|
||||||
if (win) {
|
if (win) {
|
||||||
tabpage_T *tabpage = win_find_tabpage(win);
|
tabpage_T *tabpage = win_find_tabpage(win);
|
||||||
if (!win_execute_before(&win_execute_args, win, tabpage)) {
|
if (!win_execute_before(&win_execute_args, win, tabpage)) {
|
||||||
goto end;
|
goto end;
|
||||||
|
}
|
||||||
|
} else if (buf) {
|
||||||
|
aucmd_prepbuf(&aco, buf);
|
||||||
}
|
}
|
||||||
} else if (buf) {
|
|
||||||
aucmd_prepbuf(&aco, buf);
|
|
||||||
}
|
|
||||||
|
|
||||||
int s = lua_gettop(L);
|
int s = lua_gettop(L);
|
||||||
lua_pushvalue(L, 2);
|
lua_pushvalue(L, 2);
|
||||||
status = lua_pcall(L, 0, LUA_MULTRET, 0);
|
status = lua_pcall(L, 0, LUA_MULTRET, 0);
|
||||||
rets = lua_gettop(L) - s;
|
rets = lua_gettop(L) - s;
|
||||||
|
|
||||||
if (win) {
|
if (win) {
|
||||||
win_execute_after(&win_execute_args);
|
win_execute_after(&win_execute_args);
|
||||||
} else if (buf) {
|
} else if (buf) {
|
||||||
aucmd_restbuf(&aco);
|
aucmd_restbuf(&aco);
|
||||||
}
|
}
|
||||||
|
end:;
|
||||||
end:
|
});
|
||||||
if (buf || win) {
|
|
||||||
try_end(&err);
|
|
||||||
}
|
|
||||||
|
|
||||||
undo_cmdmod(&cmdmod);
|
undo_cmdmod(&cmdmod);
|
||||||
cmdmod = save_cmdmod;
|
cmdmod = save_cmdmod;
|
||||||
|
@ -3933,7 +3933,7 @@ static bool switch_option_context(void *const ctx, OptScope scope, void *const f
|
|||||||
== FAIL) {
|
== FAIL) {
|
||||||
restore_win_noblock(switchwin, true);
|
restore_win_noblock(switchwin, true);
|
||||||
|
|
||||||
if (try_end(err)) {
|
if (ERROR_SET(err)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
api_set_error(err, kErrorTypeException, "Problem while switching windows");
|
api_set_error(err, kErrorTypeException, "Problem while switching windows");
|
||||||
|
Loading…
Reference in New Issue
Block a user