mirror of
https://github.com/neovim/neovim.git
synced 2024-12-19 10:45:16 -07:00
fix(api): generic error messages, not using TRY_WRAP #31596
Problem: - API functions using `try_start` directly, do not surface the underlying error message, and instead show generic messages. - Error-handling code is duplicated in the API impl. - Failure modes are not tested. Solution: - Use `TRY_WRAP`. - Add tests.
This commit is contained in:
parent
fb8372adb3
commit
022449b522
@ -1647,11 +1647,9 @@ nvim_command({command}) *nvim_command()*
|
|||||||
|
|
||||||
On execution error: fails with Vimscript error, updates v:errmsg.
|
On execution error: fails with Vimscript error, updates v:errmsg.
|
||||||
|
|
||||||
Prefer using |nvim_cmd()| or |nvim_exec2()| over this. To evaluate
|
Prefer |nvim_cmd()| or |nvim_exec2()| instead. To modify an Ex command in
|
||||||
multiple lines of Vim script or an Ex command directly, use
|
a structured way before executing it, modify the result of
|
||||||
|nvim_exec2()|. To construct an Ex command using a structured format and
|
|nvim_parse_cmd()| then pass it to |nvim_cmd()|.
|
||||||
then execute it, use |nvim_cmd()|. To modify an Ex command before
|
|
||||||
evaluating it, use |nvim_parse_cmd()| in conjunction with |nvim_cmd()|.
|
|
||||||
|
|
||||||
Parameters: ~
|
Parameters: ~
|
||||||
• {command} Ex command string
|
• {command} Ex command string
|
||||||
|
6
runtime/lua/vim/_meta/api.lua
generated
6
runtime/lua/vim/_meta/api.lua
generated
@ -885,10 +885,8 @@ function vim.api.nvim_cmd(cmd, opts) end
|
|||||||
---
|
---
|
||||||
--- On execution error: fails with Vimscript error, updates v:errmsg.
|
--- On execution error: fails with Vimscript error, updates v:errmsg.
|
||||||
---
|
---
|
||||||
--- Prefer using `nvim_cmd()` or `nvim_exec2()` over this. To evaluate multiple lines of Vim script
|
--- Prefer `nvim_cmd()` or `nvim_exec2()` instead. To modify an Ex command in a structured way
|
||||||
--- or an Ex command directly, use `nvim_exec2()`. To construct an Ex command using a structured
|
--- before executing it, modify the result of `nvim_parse_cmd()` then pass it to `nvim_cmd()`.
|
||||||
--- format and then execute it, use `nvim_cmd()`. To modify an Ex command before evaluating it, use
|
|
||||||
--- `nvim_parse_cmd()` in conjunction with `nvim_cmd()`.
|
|
||||||
---
|
---
|
||||||
--- @param command string Ex command string
|
--- @param command string Ex command string
|
||||||
function vim.api.nvim_command(command) end
|
function vim.api.nvim_command(command) end
|
||||||
|
@ -669,16 +669,9 @@ void nvim_set_current_dir(String dir, Error *err)
|
|||||||
memcpy(string, dir.data, dir.size);
|
memcpy(string, dir.data, dir.size);
|
||||||
string[dir.size] = NUL;
|
string[dir.size] = NUL;
|
||||||
|
|
||||||
try_start();
|
TRY_WRAP(err, {
|
||||||
|
changedir_func(string, kCdScopeGlobal);
|
||||||
if (!changedir_func(string, kCdScopeGlobal)) {
|
});
|
||||||
if (!try_end(err)) {
|
|
||||||
api_set_error(err, kErrorTypeException, "Failed to change directory");
|
|
||||||
}
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
try_end(err);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Gets the current line.
|
/// Gets the current line.
|
||||||
@ -942,14 +935,9 @@ void nvim_set_current_win(Window window, Error *err)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
try_start();
|
TRY_WRAP(err, {
|
||||||
goto_tabpage_win(win_find_tabpage(win), win);
|
goto_tabpage_win(win_find_tabpage(win), win);
|
||||||
if (!try_end(err) && win != curwin) {
|
});
|
||||||
api_set_error(err,
|
|
||||||
kErrorTypeException,
|
|
||||||
"Failed to switch to window %d",
|
|
||||||
window);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Creates a new, empty, unnamed buffer.
|
/// Creates a new, empty, unnamed buffer.
|
||||||
@ -1208,14 +1196,9 @@ void nvim_set_current_tabpage(Tabpage tabpage, Error *err)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
try_start();
|
TRY_WRAP(err, {
|
||||||
goto_tabpage_tp(tp, true, true);
|
goto_tabpage_tp(tp, true, true);
|
||||||
if (!try_end(err) && tp != curtab) {
|
});
|
||||||
api_set_error(err,
|
|
||||||
kErrorTypeException,
|
|
||||||
"Failed to switch to tabpage %d",
|
|
||||||
tabpage);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Pastes at cursor (in any mode), and sets "redo" so dot (|.|) will repeat the input. UIs call
|
/// Pastes at cursor (in any mode), and sets "redo" so dot (|.|) will repeat the input. UIs call
|
||||||
|
@ -125,19 +125,17 @@ theend:
|
|||||||
///
|
///
|
||||||
/// On execution error: fails with Vimscript error, updates v:errmsg.
|
/// On execution error: fails with Vimscript error, updates v:errmsg.
|
||||||
///
|
///
|
||||||
/// Prefer using |nvim_cmd()| or |nvim_exec2()| over this. To evaluate multiple lines of Vim script
|
/// Prefer |nvim_cmd()| or |nvim_exec2()| instead. To modify an Ex command in a structured way
|
||||||
/// or an Ex command directly, use |nvim_exec2()|. To construct an Ex command using a structured
|
/// before executing it, modify the result of |nvim_parse_cmd()| then pass it to |nvim_cmd()|.
|
||||||
/// format and then execute it, use |nvim_cmd()|. To modify an Ex command before evaluating it, use
|
|
||||||
/// |nvim_parse_cmd()| in conjunction with |nvim_cmd()|.
|
|
||||||
///
|
///
|
||||||
/// @param command Ex command string
|
/// @param command Ex command string
|
||||||
/// @param[out] err Error details (Vim error), if any
|
/// @param[out] err Error details (Vim error), if any
|
||||||
void nvim_command(String command, Error *err)
|
void nvim_command(String command, Error *err)
|
||||||
FUNC_API_SINCE(1)
|
FUNC_API_SINCE(1)
|
||||||
{
|
{
|
||||||
try_start();
|
TRY_WRAP(err, {
|
||||||
do_cmdline_cmd(command.data);
|
do_cmdline_cmd(command.data);
|
||||||
try_end(err);
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Evaluates a Vimscript |expression|. Dicts and Lists are recursively expanded.
|
/// Evaluates a Vimscript |expression|. Dicts and Lists are recursively expanded.
|
||||||
@ -283,13 +281,11 @@ Object nvim_call_dict_function(Object dict, String fn, Array args, Arena *arena,
|
|||||||
bool mustfree = false;
|
bool mustfree = false;
|
||||||
switch (dict.type) {
|
switch (dict.type) {
|
||||||
case kObjectTypeString:
|
case kObjectTypeString:
|
||||||
try_start();
|
TRY_WRAP(err, {
|
||||||
if (eval0(dict.data.string.data, &rettv, NULL, &EVALARG_EVALUATE) == FAIL) {
|
eval0(dict.data.string.data, &rettv, NULL, &EVALARG_EVALUATE);
|
||||||
api_set_error(err, kErrorTypeException,
|
clear_evalarg(&EVALARG_EVALUATE, NULL);
|
||||||
"Failed to evaluate dict expression");
|
});
|
||||||
}
|
if (ERROR_SET(err)) {
|
||||||
clear_evalarg(&EVALARG_EVALUATE, NULL);
|
|
||||||
if (try_end(err)) {
|
|
||||||
return rv;
|
return rv;
|
||||||
}
|
}
|
||||||
// Evaluation of the string arg created a new dict or increased the
|
// Evaluation of the string arg created a new dict or increased the
|
||||||
|
@ -182,14 +182,9 @@ void nvim_win_set_height(Window window, Integer height, Error *err)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (height > INT_MAX || height < INT_MIN) {
|
TRY_WRAP(err, {
|
||||||
api_set_error(err, kErrorTypeValidation, "Height value outside range");
|
win_setheight_win((int)height, win);
|
||||||
return;
|
});
|
||||||
}
|
|
||||||
|
|
||||||
try_start();
|
|
||||||
win_setheight_win((int)height, win);
|
|
||||||
try_end(err);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Gets the window width
|
/// Gets the window width
|
||||||
@ -224,14 +219,9 @@ void nvim_win_set_width(Window window, Integer width, Error *err)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (width > INT_MAX || width < INT_MIN) {
|
TRY_WRAP(err, {
|
||||||
api_set_error(err, kErrorTypeValidation, "Width value outside range");
|
win_setwidth_win((int)width, win);
|
||||||
return;
|
});
|
||||||
}
|
|
||||||
|
|
||||||
try_start();
|
|
||||||
win_setwidth_win((int)width, win);
|
|
||||||
try_end(err);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Gets a window-scoped (w:) variable
|
/// Gets a window-scoped (w:) variable
|
||||||
@ -436,15 +426,15 @@ Object nvim_win_call(Window window, LuaRef fun, Error *err)
|
|||||||
}
|
}
|
||||||
tabpage_T *tabpage = win_find_tabpage(win);
|
tabpage_T *tabpage = win_find_tabpage(win);
|
||||||
|
|
||||||
try_start();
|
|
||||||
Object res = OBJECT_INIT;
|
Object res = OBJECT_INIT;
|
||||||
win_execute_T win_execute_args;
|
TRY_WRAP(err, {
|
||||||
if (win_execute_before(&win_execute_args, win, tabpage)) {
|
win_execute_T win_execute_args;
|
||||||
Array args = ARRAY_DICT_INIT;
|
if (win_execute_before(&win_execute_args, win, tabpage)) {
|
||||||
res = nlua_call_ref(fun, NULL, args, kRetLuaref, NULL, err);
|
Array args = ARRAY_DICT_INIT;
|
||||||
}
|
res = nlua_call_ref(fun, NULL, args, kRetLuaref, NULL, err);
|
||||||
win_execute_after(&win_execute_args);
|
}
|
||||||
try_end(err);
|
win_execute_after(&win_execute_args);
|
||||||
|
});
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -695,7 +695,7 @@ describe('API', function()
|
|||||||
pcall_err(request, 'nvim_call_dict_function', 42, 'f', { 1, 2 })
|
pcall_err(request, 'nvim_call_dict_function', 42, 'f', { 1, 2 })
|
||||||
)
|
)
|
||||||
eq(
|
eq(
|
||||||
'Failed to evaluate dict expression',
|
'Vim:E121: Undefined variable: foo',
|
||||||
pcall_err(request, 'nvim_call_dict_function', 'foo', 'f', { 1, 2 })
|
pcall_err(request, 'nvim_call_dict_function', 'foo', 'f', { 1, 2 })
|
||||||
)
|
)
|
||||||
eq('dict not found', pcall_err(request, 'nvim_call_dict_function', '42', 'f', { 1, 2 }))
|
eq('dict not found', pcall_err(request, 'nvim_call_dict_function', '42', 'f', { 1, 2 }))
|
||||||
@ -1957,6 +1957,16 @@ describe('API', function()
|
|||||||
api.nvim_set_current_win(api.nvim_list_wins()[2])
|
api.nvim_set_current_win(api.nvim_list_wins()[2])
|
||||||
eq(api.nvim_list_wins()[2], api.nvim_get_current_win())
|
eq(api.nvim_list_wins()[2], api.nvim_get_current_win())
|
||||||
end)
|
end)
|
||||||
|
|
||||||
|
it('failure modes', function()
|
||||||
|
n.command('split')
|
||||||
|
|
||||||
|
eq('Invalid window id: 9999', pcall_err(api.nvim_set_current_win, 9999))
|
||||||
|
|
||||||
|
-- XXX: force nvim_set_current_win to fail somehow.
|
||||||
|
n.command("au WinLeave * throw 'foo'")
|
||||||
|
eq('WinLeave Autocommands for "*": foo', pcall_err(api.nvim_set_current_win, 1000))
|
||||||
|
end)
|
||||||
end)
|
end)
|
||||||
|
|
||||||
describe('nvim_{get,set}_current_tabpage, nvim_list_tabpages', function()
|
describe('nvim_{get,set}_current_tabpage, nvim_list_tabpages', function()
|
||||||
@ -1976,6 +1986,16 @@ describe('API', function()
|
|||||||
eq(api.nvim_list_tabpages()[2], api.nvim_get_current_tabpage())
|
eq(api.nvim_list_tabpages()[2], api.nvim_get_current_tabpage())
|
||||||
eq(api.nvim_list_wins()[2], api.nvim_get_current_win())
|
eq(api.nvim_list_wins()[2], api.nvim_get_current_win())
|
||||||
end)
|
end)
|
||||||
|
|
||||||
|
it('failure modes', function()
|
||||||
|
n.command('tabnew')
|
||||||
|
|
||||||
|
eq('Invalid tabpage id: 999', pcall_err(api.nvim_set_current_tabpage, 999))
|
||||||
|
|
||||||
|
-- XXX: force nvim_set_current_tabpage to fail somehow.
|
||||||
|
n.command("au TabLeave * throw 'foo'")
|
||||||
|
eq('TabLeave Autocommands for "*": foo', pcall_err(api.nvim_set_current_tabpage, 1))
|
||||||
|
end)
|
||||||
end)
|
end)
|
||||||
|
|
||||||
describe('nvim_get_mode', function()
|
describe('nvim_get_mode', function()
|
||||||
|
@ -359,6 +359,15 @@ describe('API/win', function()
|
|||||||
eq(2, api.nvim_win_get_height(api.nvim_list_wins()[2]))
|
eq(2, api.nvim_win_get_height(api.nvim_list_wins()[2]))
|
||||||
end)
|
end)
|
||||||
|
|
||||||
|
it('failure modes', function()
|
||||||
|
command('split')
|
||||||
|
eq('Invalid window id: 999999', pcall_err(api.nvim_win_set_height, 999999, 10))
|
||||||
|
eq(
|
||||||
|
'Wrong type for argument 2 when calling nvim_win_set_height, expecting Integer',
|
||||||
|
pcall_err(api.nvim_win_set_height, 0, 0.9)
|
||||||
|
)
|
||||||
|
end)
|
||||||
|
|
||||||
it('correctly handles height=1', function()
|
it('correctly handles height=1', function()
|
||||||
command('split')
|
command('split')
|
||||||
api.nvim_set_current_win(api.nvim_list_wins()[1])
|
api.nvim_set_current_win(api.nvim_list_wins()[1])
|
||||||
@ -409,6 +418,15 @@ describe('API/win', function()
|
|||||||
eq(2, api.nvim_win_get_width(api.nvim_list_wins()[2]))
|
eq(2, api.nvim_win_get_width(api.nvim_list_wins()[2]))
|
||||||
end)
|
end)
|
||||||
|
|
||||||
|
it('failure modes', function()
|
||||||
|
command('vsplit')
|
||||||
|
eq('Invalid window id: 999999', pcall_err(api.nvim_win_set_width, 999999, 10))
|
||||||
|
eq(
|
||||||
|
'Wrong type for argument 2 when calling nvim_win_set_width, expecting Integer',
|
||||||
|
pcall_err(api.nvim_win_set_width, 0, 0.9)
|
||||||
|
)
|
||||||
|
end)
|
||||||
|
|
||||||
it('do not cause ml_get errors with foldmethod=expr #19989', function()
|
it('do not cause ml_get errors with foldmethod=expr #19989', function()
|
||||||
insert([[
|
insert([[
|
||||||
aaaaa
|
aaaaa
|
||||||
|
@ -351,11 +351,10 @@ describe('autocmd DirChanged and DirChangedPre', function()
|
|||||||
eq(2, eval('g:cdprecount'))
|
eq(2, eval('g:cdprecount'))
|
||||||
eq(2, eval('g:cdcount'))
|
eq(2, eval('g:cdcount'))
|
||||||
|
|
||||||
local status, err = pcall(function()
|
eq(
|
||||||
request('nvim_set_current_dir', '/doesnotexist')
|
'Vim:E344: Can\'t find directory "/doesnotexist" in cdpath',
|
||||||
end)
|
t.pcall_err(request, 'nvim_set_current_dir', '/doesnotexist')
|
||||||
eq(false, status)
|
)
|
||||||
eq('Failed to change directory', string.match(err, ': (.*)'))
|
|
||||||
eq({ directory = '/doesnotexist', scope = 'global', changed_window = false }, eval('g:evpre'))
|
eq({ directory = '/doesnotexist', scope = 'global', changed_window = false }, eval('g:evpre'))
|
||||||
eq(3, eval('g:cdprecount'))
|
eq(3, eval('g:cdprecount'))
|
||||||
eq(2, eval('g:cdcount'))
|
eq(2, eval('g:cdcount'))
|
||||||
|
@ -3955,6 +3955,17 @@ stack traceback:
|
|||||||
eq(win2, val)
|
eq(win2, val)
|
||||||
end)
|
end)
|
||||||
|
|
||||||
|
it('failure modes', function()
|
||||||
|
matches(
|
||||||
|
'nvim_exec2%(%): Vim:E492: Not an editor command: fooooo',
|
||||||
|
pcall_err(exec_lua, [[vim.api.nvim_win_call(0, function() vim.cmd 'fooooo' end)]])
|
||||||
|
)
|
||||||
|
eq(
|
||||||
|
'Error executing lua: [string "<nvim>"]:0: fooooo',
|
||||||
|
pcall_err(exec_lua, [[vim.api.nvim_win_call(0, function() error('fooooo') end)]])
|
||||||
|
)
|
||||||
|
end)
|
||||||
|
|
||||||
it('does not cause ml_get errors with invalid visual selection', function()
|
it('does not cause ml_get errors with invalid visual selection', function()
|
||||||
-- Add lines to the current buffer and make another window looking into an empty buffer.
|
-- Add lines to the current buffer and make another window looking into an empty buffer.
|
||||||
exec_lua [[
|
exec_lua [[
|
||||||
|
Loading…
Reference in New Issue
Block a user