diff --git a/runtime/doc/api.txt b/runtime/doc/api.txt index cb3b2a3f77..70fda5ce8a 100644 --- a/runtime/doc/api.txt +++ b/runtime/doc/api.txt @@ -1647,11 +1647,9 @@ nvim_command({command}) *nvim_command()* 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 or an Ex command directly, use - |nvim_exec2()|. To construct an Ex command using a structured 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()|. + Prefer |nvim_cmd()| or |nvim_exec2()| instead. To modify an Ex command in + a structured way before executing it, modify the result of + |nvim_parse_cmd()| then pass it to |nvim_cmd()|. Parameters: ~ • {command} Ex command string diff --git a/runtime/lua/vim/_meta/api.lua b/runtime/lua/vim/_meta/api.lua index b2385197bd..55274963ed 100644 --- a/runtime/lua/vim/_meta/api.lua +++ b/runtime/lua/vim/_meta/api.lua @@ -885,10 +885,8 @@ function vim.api.nvim_cmd(cmd, opts) end --- --- 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 ---- or an Ex command directly, use `nvim_exec2()`. To construct an Ex command using a structured ---- 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()`. +--- Prefer `nvim_cmd()` or `nvim_exec2()` instead. To modify an Ex command in a structured way +--- before executing it, modify the result of `nvim_parse_cmd()` then pass it to `nvim_cmd()`. --- --- @param command string Ex command string function vim.api.nvim_command(command) end diff --git a/src/nvim/api/vim.c b/src/nvim/api/vim.c index 1acfa0d34b..d82f90d1dd 100644 --- a/src/nvim/api/vim.c +++ b/src/nvim/api/vim.c @@ -669,16 +669,9 @@ void nvim_set_current_dir(String dir, Error *err) memcpy(string, dir.data, dir.size); string[dir.size] = NUL; - try_start(); - - if (!changedir_func(string, kCdScopeGlobal)) { - if (!try_end(err)) { - api_set_error(err, kErrorTypeException, "Failed to change directory"); - } - return; - } - - try_end(err); + TRY_WRAP(err, { + changedir_func(string, kCdScopeGlobal); + }); } /// Gets the current line. @@ -942,14 +935,9 @@ void nvim_set_current_win(Window window, Error *err) return; } - try_start(); - 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); - } + TRY_WRAP(err, { + goto_tabpage_win(win_find_tabpage(win), win); + }); } /// Creates a new, empty, unnamed buffer. @@ -1208,14 +1196,9 @@ void nvim_set_current_tabpage(Tabpage tabpage, Error *err) return; } - try_start(); - goto_tabpage_tp(tp, true, true); - if (!try_end(err) && tp != curtab) { - api_set_error(err, - kErrorTypeException, - "Failed to switch to tabpage %d", - tabpage); - } + TRY_WRAP(err, { + goto_tabpage_tp(tp, true, true); + }); } /// Pastes at cursor (in any mode), and sets "redo" so dot (|.|) will repeat the input. UIs call diff --git a/src/nvim/api/vimscript.c b/src/nvim/api/vimscript.c index 165cc93fbe..0ff2b037ce 100644 --- a/src/nvim/api/vimscript.c +++ b/src/nvim/api/vimscript.c @@ -125,19 +125,17 @@ theend: /// /// 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 -/// or an Ex command directly, use |nvim_exec2()|. To construct an Ex command using a structured -/// 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()|. +/// Prefer |nvim_cmd()| or |nvim_exec2()| instead. To modify an Ex command in a structured way +/// before executing it, modify the result of |nvim_parse_cmd()| then pass it to |nvim_cmd()|. /// /// @param command Ex command string /// @param[out] err Error details (Vim error), if any void nvim_command(String command, Error *err) FUNC_API_SINCE(1) { - try_start(); - do_cmdline_cmd(command.data); - try_end(err); + TRY_WRAP(err, { + do_cmdline_cmd(command.data); + }); } /// 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; switch (dict.type) { case kObjectTypeString: - try_start(); - if (eval0(dict.data.string.data, &rettv, NULL, &EVALARG_EVALUATE) == FAIL) { - api_set_error(err, kErrorTypeException, - "Failed to evaluate dict expression"); - } - clear_evalarg(&EVALARG_EVALUATE, NULL); - if (try_end(err)) { + TRY_WRAP(err, { + eval0(dict.data.string.data, &rettv, NULL, &EVALARG_EVALUATE); + clear_evalarg(&EVALARG_EVALUATE, NULL); + }); + if (ERROR_SET(err)) { return rv; } // Evaluation of the string arg created a new dict or increased the diff --git a/src/nvim/api/window.c b/src/nvim/api/window.c index 170d5c6cdb..f5e8d8f086 100644 --- a/src/nvim/api/window.c +++ b/src/nvim/api/window.c @@ -182,14 +182,9 @@ void nvim_win_set_height(Window window, Integer height, Error *err) return; } - if (height > INT_MAX || height < INT_MIN) { - api_set_error(err, kErrorTypeValidation, "Height value outside range"); - return; - } - - try_start(); - win_setheight_win((int)height, win); - try_end(err); + TRY_WRAP(err, { + win_setheight_win((int)height, win); + }); } /// Gets the window width @@ -224,14 +219,9 @@ void nvim_win_set_width(Window window, Integer width, Error *err) return; } - if (width > INT_MAX || width < INT_MIN) { - api_set_error(err, kErrorTypeValidation, "Width value outside range"); - return; - } - - try_start(); - win_setwidth_win((int)width, win); - try_end(err); + TRY_WRAP(err, { + win_setwidth_win((int)width, win); + }); } /// 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); - try_start(); Object res = OBJECT_INIT; - win_execute_T win_execute_args; - if (win_execute_before(&win_execute_args, win, tabpage)) { - Array args = ARRAY_DICT_INIT; - res = nlua_call_ref(fun, NULL, args, kRetLuaref, NULL, err); - } - win_execute_after(&win_execute_args); - try_end(err); + TRY_WRAP(err, { + win_execute_T win_execute_args; + if (win_execute_before(&win_execute_args, win, tabpage)) { + Array args = ARRAY_DICT_INIT; + res = nlua_call_ref(fun, NULL, args, kRetLuaref, NULL, err); + } + win_execute_after(&win_execute_args); + }); return res; } diff --git a/test/functional/api/vim_spec.lua b/test/functional/api/vim_spec.lua index 2eeb5c18a1..879df690d1 100644 --- a/test/functional/api/vim_spec.lua +++ b/test/functional/api/vim_spec.lua @@ -695,7 +695,7 @@ describe('API', function() pcall_err(request, 'nvim_call_dict_function', 42, 'f', { 1, 2 }) ) eq( - 'Failed to evaluate dict expression', + 'Vim:E121: Undefined variable: foo', 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 })) @@ -1957,6 +1957,16 @@ describe('API', function() api.nvim_set_current_win(api.nvim_list_wins()[2]) eq(api.nvim_list_wins()[2], api.nvim_get_current_win()) 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) 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_wins()[2], api.nvim_get_current_win()) 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) describe('nvim_get_mode', function() diff --git a/test/functional/api/window_spec.lua b/test/functional/api/window_spec.lua index 4662ace4bf..078d581b6f 100644 --- a/test/functional/api/window_spec.lua +++ b/test/functional/api/window_spec.lua @@ -359,6 +359,15 @@ describe('API/win', function() eq(2, api.nvim_win_get_height(api.nvim_list_wins()[2])) 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() command('split') 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])) 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() insert([[ aaaaa diff --git a/test/functional/autocmd/dirchanged_spec.lua b/test/functional/autocmd/dirchanged_spec.lua index 1cde0e0552..9b572df568 100644 --- a/test/functional/autocmd/dirchanged_spec.lua +++ b/test/functional/autocmd/dirchanged_spec.lua @@ -351,11 +351,10 @@ describe('autocmd DirChanged and DirChangedPre', function() eq(2, eval('g:cdprecount')) eq(2, eval('g:cdcount')) - local status, err = pcall(function() - request('nvim_set_current_dir', '/doesnotexist') - end) - eq(false, status) - eq('Failed to change directory', string.match(err, ': (.*)')) + eq( + 'Vim:E344: Can\'t find directory "/doesnotexist" in cdpath', + t.pcall_err(request, 'nvim_set_current_dir', '/doesnotexist') + ) eq({ directory = '/doesnotexist', scope = 'global', changed_window = false }, eval('g:evpre')) eq(3, eval('g:cdprecount')) eq(2, eval('g:cdcount')) diff --git a/test/functional/lua/vim_spec.lua b/test/functional/lua/vim_spec.lua index 3cfbfe167a..9e75861aa0 100644 --- a/test/functional/lua/vim_spec.lua +++ b/test/functional/lua/vim_spec.lua @@ -3955,6 +3955,17 @@ stack traceback: eq(win2, val) 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 ""]: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() -- Add lines to the current buffer and make another window looking into an empty buffer. exec_lua [[