diff --git a/src/nvim/README.md b/src/nvim/README.md index 75155fb9c6..0de0fb9a3f 100644 --- a/src/nvim/README.md +++ b/src/nvim/README.md @@ -208,15 +208,11 @@ To debug the main process, you can debug the nvim binary with the `--headless` flag which does not launch the TUI and will allow you to set breakpoints in code not related to TUI rendering like so: -``` -lldb -- ./build/bin/nvim --headless --listen ~/.cache/nvim/debug-server.pipe -``` + lldb -- ./build/bin/nvim --headless --listen ~/.cache/nvim/debug-server.pipe You can then attach to the headless process to interact with the editor like so: -``` -./build/bin/nvim --remote-ui --server ~/.cache/nvim/debug-server.pipe -``` + ./build/bin/nvim --remote-ui --server ~/.cache/nvim/debug-server.pipe Conversely for debugging TUI rendering, you can start a headless process and debug the remote-ui process multiple times without losing editor state. diff --git a/src/nvim/api/command.c b/src/nvim/api/command.c index eba209b424..3157132256 100644 --- a/src/nvim/api/command.c +++ b/src/nvim/api/command.c @@ -393,6 +393,12 @@ String nvim_cmd(uint64_t channel_id, Dict(cmd) *cmd, Dict(cmd_opts) *opts, Error VALIDATE(!is_cmd_ni(ea.cmdidx), "Command not implemented: %s", cmdname, { goto end; }); + const char *fullname = IS_USER_CMDIDX(ea.cmdidx) + ? get_user_command_name(ea.useridx, ea.cmdidx) + : get_command_name(NULL, ea.cmdidx); + VALIDATE(strncmp(fullname, cmdname, strlen(cmdname)) == 0, "Invalid command: \"%s\"", cmdname, { + goto end; + }); // Get the command flags so that we can know what type of arguments the command uses. // Not required for a user command since `find_ex_command` already deals with it in that case. diff --git a/test/functional/api/vim_spec.lua b/test/functional/api/vim_spec.lua index d56f780ca6..1ac732b128 100644 --- a/test/functional/api/vim_spec.lua +++ b/test/functional/api/vim_spec.lua @@ -335,8 +335,7 @@ describe('API', function() nvim('command', 'edit '..fname) nvim('command', 'normal itesting\napi') nvim('command', 'w') - local f = io.open(fname) - ok(f ~= nil) + local f = assert(io.open(fname)) if is_os('win') then eq('testing\r\napi\r\n', f:read('*a')) else @@ -3950,7 +3949,7 @@ describe('API', function() } }, meths.parse_cmd('MyCommand test it', {})) end) - it('errors for invalid command', function() + it('validates command', function() eq('Error while parsing command line', pcall_err(meths.parse_cmd, '', {})) eq('Error while parsing command line', pcall_err(meths.parse_cmd, '" foo', {})) eq('Error while parsing command line: E492: Not an editor command: Fubar', @@ -4097,6 +4096,11 @@ describe('API', function() eq("Invalid 'reg': expected single character, got xx", pcall_err(meths.cmd, { cmd = "put", args = {}, reg = 'xx' }, {})) + -- #20681 + eq('Invalid command: "win_getid"', pcall_err(meths.cmd, { cmd = 'win_getid'}, {})) + eq('Invalid command: "echo "hi""', pcall_err(meths.cmd, { cmd = 'echo "hi"'}, {})) + eq('Invalid command: "win_getid"', pcall_err(exec_lua, [[return vim.cmd.win_getid{}]])) + -- Lua call allows empty {} for dict item. eq('', exec_lua([[return vim.cmd{ cmd = "set", args = {}, magic = {} }]])) eq('', exec_lua([[return vim.cmd{ cmd = "set", args = {}, mods = {} }]]))