mirror of
https://github.com/neovim/neovim.git
synced 2025-10-08 02:46:31 +00:00
API: TRY_WRAP() for "abort-causing non-exception errors"
- Introduce TRY_WRAP() until we have an *architectural* solution. - TODO: bfredl idea: prepare error-handling at "top level" (nv_event). - nvim_paste(): Revert luaeval() hack (see parent commit). - With TRY_WRAP() in nvim_put(), 'nomodifiable' error now correctly "bubbles up".
This commit is contained in:
@@ -54,6 +54,20 @@
|
|||||||
# include "api/vim.c.generated.h"
|
# include "api/vim.c.generated.h"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
// `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(code) \
|
||||||
|
do { \
|
||||||
|
struct msglist **saved_msg_list = msg_list; \
|
||||||
|
struct msglist *private_msg_list; \
|
||||||
|
msg_list = &private_msg_list; \
|
||||||
|
private_msg_list = NULL; \
|
||||||
|
code \
|
||||||
|
msg_list = saved_msg_list; /* Restore the exception context. */ \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
void api_vim_init(void)
|
void api_vim_init(void)
|
||||||
FUNC_API_NOEXPORT
|
FUNC_API_NOEXPORT
|
||||||
{
|
{
|
||||||
@@ -392,13 +406,7 @@ Object nvim_eval(String expr, Error *err)
|
|||||||
static int recursive = 0; // recursion depth
|
static int recursive = 0; // recursion depth
|
||||||
Object rv = OBJECT_INIT;
|
Object rv = OBJECT_INIT;
|
||||||
|
|
||||||
// `msg_list` controls the collection of abort-causing non-exception errors,
|
TRY_WRAP({
|
||||||
// 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.
|
// Initialize `force_abort` and `suppress_errthrow` at the top level.
|
||||||
if (!recursive) {
|
if (!recursive) {
|
||||||
force_abort = false;
|
force_abort = false;
|
||||||
@@ -423,8 +431,8 @@ Object nvim_eval(String expr, Error *err)
|
|||||||
}
|
}
|
||||||
|
|
||||||
tv_clear(&rettv);
|
tv_clear(&rettv);
|
||||||
msg_list = saved_msg_list; // Restore the exception context.
|
|
||||||
recursive--;
|
recursive--;
|
||||||
|
});
|
||||||
|
|
||||||
return rv;
|
return rv;
|
||||||
}
|
}
|
||||||
@@ -474,13 +482,7 @@ static Object _call_function(String fn, Array args, dict_T *self, Error *err)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// `msg_list` controls the collection of abort-causing non-exception errors,
|
TRY_WRAP({
|
||||||
// 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.
|
// Initialize `force_abort` and `suppress_errthrow` at the top level.
|
||||||
if (!recursive) {
|
if (!recursive) {
|
||||||
force_abort = false;
|
force_abort = false;
|
||||||
@@ -502,8 +504,8 @@ static Object _call_function(String fn, Array args, dict_T *self, Error *err)
|
|||||||
rv = vim_to_object(&rettv);
|
rv = vim_to_object(&rettv);
|
||||||
}
|
}
|
||||||
tv_clear(&rettv);
|
tv_clear(&rettv);
|
||||||
msg_list = saved_msg_list; // Restore the exception context.
|
|
||||||
recursive--;
|
recursive--;
|
||||||
|
});
|
||||||
|
|
||||||
free_vim_args:
|
free_vim_args:
|
||||||
while (i > 0) {
|
while (i > 0) {
|
||||||
@@ -1238,7 +1240,6 @@ Boolean nvim_paste(String data, Integer phase, Error *err)
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
Array args = ARRAY_DICT_INIT;
|
Array args = ARRAY_DICT_INIT;
|
||||||
Array args2 = ARRAY_DICT_INIT;
|
|
||||||
Object rv = OBJECT_INIT;
|
Object rv = OBJECT_INIT;
|
||||||
if (phase == -1 || phase == 1) { // Start of paste-stream.
|
if (phase == -1 || phase == 1) { // Start of paste-stream.
|
||||||
draining = false;
|
draining = false;
|
||||||
@@ -1249,9 +1250,8 @@ Boolean nvim_paste(String data, Integer phase, Error *err)
|
|||||||
Array lines = string_to_array(data);
|
Array lines = string_to_array(data);
|
||||||
ADD(args, ARRAY_OBJ(lines));
|
ADD(args, ARRAY_OBJ(lines));
|
||||||
ADD(args, INTEGER_OBJ(phase));
|
ADD(args, INTEGER_OBJ(phase));
|
||||||
ADD(args2, STRING_OBJ(cstr_to_string("vim.paste(_A[1], _A[2])")));
|
rv = nvim_execute_lua(STATIC_CSTR_AS_STRING("return vim.paste(...)"), args,
|
||||||
ADD(args2, ARRAY_OBJ(args2));
|
err);
|
||||||
rv = nvim_call_function(STATIC_CSTR_AS_STRING("luaeval"), args2, err);
|
|
||||||
if (ERROR_SET(err)) {
|
if (ERROR_SET(err)) {
|
||||||
draining = true;
|
draining = true;
|
||||||
goto theend;
|
goto theend;
|
||||||
@@ -1278,7 +1278,8 @@ Boolean nvim_paste(String data, Integer phase, Error *err)
|
|||||||
AppendCharToRedobuff(ESC); // Dot-repeat.
|
AppendCharToRedobuff(ESC); // Dot-repeat.
|
||||||
}
|
}
|
||||||
theend:
|
theend:
|
||||||
api_free_array(args2);
|
api_free_object(rv);
|
||||||
|
api_free_array(args);
|
||||||
if (cancel || phase == -1 || phase == 3) { // End of paste-stream.
|
if (cancel || phase == -1 || phase == 3) { // End of paste-stream.
|
||||||
draining = false;
|
draining = false;
|
||||||
// XXX: Tickle main loop to ensure cursor is updated.
|
// XXX: Tickle main loop to ensure cursor is updated.
|
||||||
@@ -1310,10 +1311,6 @@ void nvim_put(ArrayOf(String) lines, String type, Boolean after,
|
|||||||
api_set_error(err, kErrorTypeValidation, "Invalid type: '%s'", type.data);
|
api_set_error(err, kErrorTypeValidation, "Invalid type: '%s'", type.data);
|
||||||
goto cleanup;
|
goto cleanup;
|
||||||
}
|
}
|
||||||
if (!MODIFIABLE(curbuf)) {
|
|
||||||
api_set_error(err, kErrorTypeException, "Buffer is not 'modifiable'");
|
|
||||||
goto cleanup;
|
|
||||||
}
|
|
||||||
if (lines.size == 0) {
|
if (lines.size == 0) {
|
||||||
goto cleanup; // Nothing to do.
|
goto cleanup; // Nothing to do.
|
||||||
}
|
}
|
||||||
@@ -1331,13 +1328,15 @@ void nvim_put(ArrayOf(String) lines, String type, Boolean after,
|
|||||||
|
|
||||||
finish_yankreg_from_object(reg, false);
|
finish_yankreg_from_object(reg, false);
|
||||||
|
|
||||||
bool VIsual_was_active = VIsual_active;
|
TRY_WRAP({
|
||||||
msg_silent++; // Avoid "N more lines" message.
|
try_start();
|
||||||
do_put(0, reg,
|
bool VIsual_was_active = VIsual_active;
|
||||||
after ? FORWARD : BACKWARD, 1,
|
msg_silent++; // Avoid "N more lines" message.
|
||||||
follow ? PUT_CURSEND : 0);
|
do_put(0, reg, after ? FORWARD : BACKWARD, 1, follow ? PUT_CURSEND : 0);
|
||||||
msg_silent--;
|
msg_silent--;
|
||||||
VIsual_active = VIsual_was_active;
|
VIsual_active = VIsual_was_active;
|
||||||
|
try_end(err);
|
||||||
|
});
|
||||||
|
|
||||||
cleanup:
|
cleanup:
|
||||||
free_register(reg);
|
free_register(reg);
|
||||||
|
@@ -411,7 +411,7 @@ describe('API', function()
|
|||||||
end)
|
end)
|
||||||
it("fails if 'nomodifiable'", function()
|
it("fails if 'nomodifiable'", function()
|
||||||
command('set nomodifiable')
|
command('set nomodifiable')
|
||||||
expect_err([[Buffer is not 'modifiable']], request,
|
expect_err([[Vim:E21: Cannot make changes, 'modifiable' is off]], request,
|
||||||
'nvim_put', {'a','b'}, 'l', true, true)
|
'nvim_put', {'a','b'}, 'l', true, true)
|
||||||
end)
|
end)
|
||||||
it('inserts text', function()
|
it('inserts text', function()
|
||||||
|
@@ -185,6 +185,7 @@ describe('TUI', function()
|
|||||||
{3:-- TERMINAL --} |
|
{3:-- TERMINAL --} |
|
||||||
]])
|
]])
|
||||||
feed_data('pasted from terminal')
|
feed_data('pasted from terminal')
|
||||||
|
expect_child_buf_lines({'"pasted from terminal"'})
|
||||||
screen:expect([[
|
screen:expect([[
|
||||||
"pasted from terminal{1:"} |
|
"pasted from terminal{1:"} |
|
||||||
{4:~ }|
|
{4:~ }|
|
||||||
@@ -196,6 +197,7 @@ describe('TUI', function()
|
|||||||
]])
|
]])
|
||||||
feed_data('\027[201~') -- End paste.
|
feed_data('\027[201~') -- End paste.
|
||||||
feed_data('\027\000') -- ESC: go to Normal mode.
|
feed_data('\027\000') -- ESC: go to Normal mode.
|
||||||
|
wait_for_mode('n')
|
||||||
screen:expect([[
|
screen:expect([[
|
||||||
"pasted from termina{1:l}" |
|
"pasted from termina{1:l}" |
|
||||||
{4:~ }|
|
{4:~ }|
|
||||||
@@ -207,6 +209,8 @@ describe('TUI', function()
|
|||||||
]])
|
]])
|
||||||
-- Dot-repeat/redo.
|
-- Dot-repeat/redo.
|
||||||
feed_data('2.')
|
feed_data('2.')
|
||||||
|
expect_child_buf_lines(
|
||||||
|
{'"pasted from terminapasted from terminalpasted from terminall"'})
|
||||||
screen:expect([[
|
screen:expect([[
|
||||||
"pasted from terminapasted from terminalpasted fro|
|
"pasted from terminapasted from terminalpasted fro|
|
||||||
m termina{1:l}l" |
|
m termina{1:l}l" |
|
||||||
@@ -341,18 +345,10 @@ describe('TUI', function()
|
|||||||
|
|
|
|
||||||
{3:-- TERMINAL --} |
|
{3:-- TERMINAL --} |
|
||||||
]]}
|
]]}
|
||||||
wait_for_mode('n')
|
|
||||||
-- Start pasting...
|
-- Start pasting...
|
||||||
feed_data('\027[200~line 1\nline 2\n')
|
feed_data('\027[200~line 1\nline 2\n')
|
||||||
screen:expect{grid=[[
|
wait_for_mode('n')
|
||||||
foo |
|
screen:expect{any='paste: Error executing lua'}
|
||||||
|
|
|
||||||
{4:~ }|
|
|
||||||
{5: }|
|
|
||||||
{8:paste: Vim:E5108: Error while calling lua chunk fo}|
|
|
||||||
{10:Press ENTER or type command to continue}{1: } |
|
|
||||||
{3:-- TERMINAL --} |
|
|
||||||
]]}
|
|
||||||
-- Remaining chunks are discarded after vim.paste() failure.
|
-- Remaining chunks are discarded after vim.paste() failure.
|
||||||
feed_data('line 3\nline 4\n')
|
feed_data('line 3\nline 4\n')
|
||||||
feed_data('line 5\nline 6\n')
|
feed_data('line 5\nline 6\n')
|
||||||
@@ -402,15 +398,7 @@ describe('TUI', function()
|
|||||||
it("paste: 'nomodifiable' buffer", function()
|
it("paste: 'nomodifiable' buffer", function()
|
||||||
child_session:request('nvim_command', 'set nomodifiable')
|
child_session:request('nvim_command', 'set nomodifiable')
|
||||||
feed_data('\027[200~fail 1\nfail 2\n\027[201~')
|
feed_data('\027[200~fail 1\nfail 2\n\027[201~')
|
||||||
screen:expect{grid=[[
|
screen:expect{any='Vim:E21'}
|
||||||
|
|
|
||||||
{5: }|
|
|
||||||
{8:paste: Vim:E5108: Error while calling lua chunk fo}|
|
|
||||||
{8:r luaeval(): [string "-- Nvim-Lua stdlib: the `vim}|
|
|
||||||
{8:` module (:help l..."]:193: Buffer is not 'modifia}|
|
|
||||||
{10:Press ENTER or type command to continue}{1: } |
|
|
||||||
{3:-- TERMINAL --} |
|
|
||||||
]]}
|
|
||||||
feed_data('\n') -- <Enter>
|
feed_data('\n') -- <Enter>
|
||||||
child_session:request('nvim_command', 'set modifiable')
|
child_session:request('nvim_command', 'set modifiable')
|
||||||
feed_data('\027[200~success 1\nsuccess 2\n\027[201~')
|
feed_data('\027[200~success 1\nsuccess 2\n\027[201~')
|
||||||
|
Reference in New Issue
Block a user