Merge pull request #18438 from famiu/feat/api/nvim_parse_cmd

fix(api): make `nvim_parse_cmd` propagate errors
This commit is contained in:
bfredl 2022-05-06 10:30:48 +02:00 committed by GitHub
commit e3edcd06e3
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 37 additions and 13 deletions

View File

@ -802,10 +802,15 @@ Dictionary nvim_parse_cmd(String str, Dictionary opts, Error *err)
// Parse command line // Parse command line
exarg_T ea; exarg_T ea;
CmdParseInfo cmdinfo; CmdParseInfo cmdinfo;
char_u *cmdline = (char_u *)string_to_cstr(str); char *cmdline = string_to_cstr(str);
char *errormsg = NULL;
if (!parse_cmdline(cmdline, &ea, &cmdinfo)) { if (!parse_cmdline(cmdline, &ea, &cmdinfo, &errormsg)) {
api_set_error(err, kErrorTypeException, "Error while parsing command line"); if (errormsg != NULL) {
api_set_error(err, kErrorTypeException, "Error while parsing command line: %s", errormsg);
} else {
api_set_error(err, kErrorTypeException, "Error while parsing command line");
}
goto end; goto end;
} }

View File

@ -1359,12 +1359,17 @@ static int parse_count(exarg_T *eap, char **errormsg)
/// Parse command line and return information about the first command. /// Parse command line and return information about the first command.
/// ///
/// @param cmdline Command line string
/// @param[out] eap Ex command arguments
/// @param[out] cmdinfo Command parse information
/// @param[out] errormsg Error message, if any
///
/// @return Success or failure /// @return Success or failure
bool parse_cmdline(char_u *cmdline, exarg_T *eap, CmdParseInfo *cmdinfo) bool parse_cmdline(char *cmdline, exarg_T *eap, CmdParseInfo *cmdinfo, char **errormsg)
{ {
char *errormsg = NULL;
char *cmd; char *cmd;
char *p; char *p;
char *after_modifier = NULL;
cmdmod_T save_cmdmod = cmdmod; cmdmod_T save_cmdmod = cmdmod;
// Initialize cmdinfo // Initialize cmdinfo
@ -1374,15 +1379,17 @@ bool parse_cmdline(char_u *cmdline, exarg_T *eap, CmdParseInfo *cmdinfo)
memset(eap, 0, sizeof(*eap)); memset(eap, 0, sizeof(*eap));
eap->line1 = 1; eap->line1 = 1;
eap->line2 = 1; eap->line2 = 1;
eap->cmd = (char *)cmdline; eap->cmd = cmdline;
eap->cmdlinep = (char **)&cmdline; eap->cmdlinep = &cmdline;
eap->getline = NULL; eap->getline = NULL;
eap->cookie = NULL; eap->cookie = NULL;
// Parse command modifiers // Parse command modifiers
if (parse_command_modifiers(eap, &errormsg, false) == FAIL) { if (parse_command_modifiers(eap, errormsg, false) == FAIL) {
return false; return false;
} }
after_modifier = eap->cmd;
// Revert the side-effects of `parse_command_modifiers` // Revert the side-effects of `parse_command_modifiers`
if (eap->save_msg_silent != -1) { if (eap->save_msg_silent != -1) {
cmdinfo->silent = !!msg_silent; cmdinfo->silent = !!msg_silent;
@ -1422,7 +1429,7 @@ bool parse_cmdline(char_u *cmdline, exarg_T *eap, CmdParseInfo *cmdinfo)
// Set command attribute type and parse command range // Set command attribute type and parse command range
set_cmd_addr_type(eap, (char_u *)p); set_cmd_addr_type(eap, (char_u *)p);
eap->cmd = cmd; eap->cmd = cmd;
if (parse_cmd_address(eap, &errormsg, false) == FAIL) { if (parse_cmd_address(eap, errormsg, false) == FAIL) {
return false; return false;
} }
@ -1434,6 +1441,11 @@ bool parse_cmdline(char_u *cmdline, exarg_T *eap, CmdParseInfo *cmdinfo)
} }
// Fail if command is invalid // Fail if command is invalid
if (eap->cmdidx == CMD_SIZE) { if (eap->cmdidx == CMD_SIZE) {
STRCPY(IObuff, _("E492: Not an editor command"));
// If the modifier was parsed OK the error must be in the following command
char *cmdname = after_modifier ? after_modifier : cmdline;
append_command(cmdname);
*errormsg = (char *)IObuff;
return false; return false;
} }
@ -1472,10 +1484,12 @@ bool parse_cmdline(char_u *cmdline, exarg_T *eap, CmdParseInfo *cmdinfo)
} }
// Fail if command doesn't support bang but is used with a bang // Fail if command doesn't support bang but is used with a bang
if (!(eap->argt & EX_BANG) && eap->forceit) { if (!(eap->argt & EX_BANG) && eap->forceit) {
*errormsg = _(e_nobang);
return false; return false;
} }
// Fail if command doesn't support a range but it is given a range // Fail if command doesn't support a range but it is given a range
if (!(eap->argt & EX_RANGE) && eap->addr_count > 0) { if (!(eap->argt & EX_RANGE) && eap->addr_count > 0) {
*errormsg = _(e_norange);
return false; return false;
} }
// Set default range for command if required // Set default range for command if required
@ -1485,7 +1499,7 @@ bool parse_cmdline(char_u *cmdline, exarg_T *eap, CmdParseInfo *cmdinfo)
// Parse register and count // Parse register and count
parse_register(eap); parse_register(eap);
if (parse_count(eap, NULL) == FAIL) { if (parse_count(eap, errormsg) == FAIL) {
return false; return false;
} }

View File

@ -3426,10 +3426,15 @@ describe('API', function()
}, meths.parse_cmd('MyCommand test it', {})) }, meths.parse_cmd('MyCommand test it', {}))
end) end)
it('errors for invalid command', function() it('errors for invalid command', function()
eq('Error while parsing command line', pcall_err(meths.parse_cmd, 'Fubar', {})) 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',
pcall_err(meths.parse_cmd, 'Fubar', {}))
command('command! Fubar echo foo') command('command! Fubar echo foo')
eq('Error while parsing command line', pcall_err(meths.parse_cmd, 'Fubar!', {})) eq('Error while parsing command line: E477: No ! allowed',
eq('Error while parsing command line', pcall_err(meths.parse_cmd, '4,6Fubar', {})) pcall_err(meths.parse_cmd, 'Fubar!', {}))
eq('Error while parsing command line: E481: No range allowed',
pcall_err(meths.parse_cmd, '4,6Fubar', {}))
end) end)
end) end)
end) end)