mirror of
https://github.com/neovim/neovim.git
synced 2025-10-06 01:46:29 +00:00
refactor: common logic in parse_cmdline, do_one_cmd #35019
Problem: Significant code duplication between the two command parsing functions Solution: Extract shared parsing logic into helper functions while preserving original behavior
This commit is contained in:
@@ -1480,6 +1480,33 @@ bool is_cmd_ni(cmdidx_T cmdidx)
|
|||||||
|| cmdnames[cmdidx].cmd_func == ex_script_ni);
|
|| cmdnames[cmdidx].cmd_func == ex_script_ni);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Find the command name after skipping range specifiers.
|
||||||
|
static char *find_excmd_after_range(exarg_T *eap)
|
||||||
|
{
|
||||||
|
// Save location after command modifiers.
|
||||||
|
char *cmd = eap->cmd;
|
||||||
|
eap->cmd = skip_range(eap->cmd, NULL);
|
||||||
|
if (*eap->cmd == '*') {
|
||||||
|
eap->cmd = skipwhite(eap->cmd + 1);
|
||||||
|
}
|
||||||
|
char *p = find_ex_command(eap, NULL);
|
||||||
|
eap->cmd = cmd; // Restore original position for address parsing
|
||||||
|
return p;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set the forceit flag based on the presence of '!' after the command.
|
||||||
|
static bool parse_bang(const exarg_T *eap, char **p)
|
||||||
|
{
|
||||||
|
if (**p == '!'
|
||||||
|
&& eap->cmdidx != CMD_substitute
|
||||||
|
&& eap->cmdidx != CMD_smagic
|
||||||
|
&& eap->cmdidx != CMD_snomagic) {
|
||||||
|
(*p)++;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
/// Parse command line and return information about the first command.
|
/// Parse command line and return information about the first command.
|
||||||
/// If parsing is done successfully, need to free cmod_filter_pat and cmod_filter_regmatch.regprog
|
/// If parsing is done successfully, need to free cmod_filter_pat and cmod_filter_regmatch.regprog
|
||||||
/// after calling, usually done using undo_cmdmod() or execute_cmd().
|
/// after calling, usually done using undo_cmdmod() or execute_cmd().
|
||||||
@@ -1520,14 +1547,8 @@ bool parse_cmdline(char **cmdline, exarg_T *eap, CmdParseInfo *cmdinfo, const ch
|
|||||||
}
|
}
|
||||||
after_modifier = eap->cmd;
|
after_modifier = eap->cmd;
|
||||||
|
|
||||||
// Save location after command modifiers
|
// We need the command name to know what kind of range it uses.
|
||||||
char *cmd = eap->cmd;
|
char *p = find_excmd_after_range(eap);
|
||||||
// Skip ranges to find command name since we need the command to know what kind of range it uses
|
|
||||||
eap->cmd = skip_range(eap->cmd, NULL);
|
|
||||||
if (*eap->cmd == '*') {
|
|
||||||
eap->cmd = skipwhite(eap->cmd + 1);
|
|
||||||
}
|
|
||||||
char *p = find_ex_command(eap, NULL);
|
|
||||||
if (p == NULL) {
|
if (p == NULL) {
|
||||||
*errormsg = _(e_ambiguous_use_of_user_defined_command);
|
*errormsg = _(e_ambiguous_use_of_user_defined_command);
|
||||||
goto end;
|
goto end;
|
||||||
@@ -1535,7 +1556,6 @@ bool parse_cmdline(char **cmdline, exarg_T *eap, CmdParseInfo *cmdinfo, const ch
|
|||||||
|
|
||||||
// Set command address type and parse command range
|
// Set command address type and parse command range
|
||||||
set_cmd_addr_type(eap, p);
|
set_cmd_addr_type(eap, p);
|
||||||
eap->cmd = cmd;
|
|
||||||
if (parse_cmd_address(eap, errormsg, true) == FAIL) {
|
if (parse_cmd_address(eap, errormsg, true) == FAIL) {
|
||||||
goto end;
|
goto end;
|
||||||
}
|
}
|
||||||
@@ -1557,13 +1577,7 @@ bool parse_cmdline(char **cmdline, exarg_T *eap, CmdParseInfo *cmdinfo, const ch
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Correctly set 'forceit' for commands
|
// Correctly set 'forceit' for commands
|
||||||
if (*p == '!' && eap->cmdidx != CMD_substitute
|
eap->forceit = parse_bang(eap, &p);
|
||||||
&& eap->cmdidx != CMD_smagic && eap->cmdidx != CMD_snomagic) {
|
|
||||||
p++;
|
|
||||||
eap->forceit = true;
|
|
||||||
} else {
|
|
||||||
eap->forceit = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Parse arguments.
|
// Parse arguments.
|
||||||
if (!IS_USER_CMDIDX(eap->cmdidx)) {
|
if (!IS_USER_CMDIDX(eap->cmdidx)) {
|
||||||
@@ -1571,17 +1585,11 @@ bool parse_cmdline(char **cmdline, exarg_T *eap, CmdParseInfo *cmdinfo, const ch
|
|||||||
}
|
}
|
||||||
// Skip to start of argument.
|
// Skip to start of argument.
|
||||||
// Don't do this for the ":!" command, because ":!! -l" needs the space.
|
// Don't do this for the ":!" command, because ":!! -l" needs the space.
|
||||||
if (eap->cmdidx == CMD_bang) {
|
eap->arg = eap->cmdidx == CMD_bang ? p : skipwhite(p);
|
||||||
eap->arg = p;
|
|
||||||
} else {
|
|
||||||
eap->arg = skipwhite(p);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Don't treat ":r! filter" like a bang
|
// Don't treat ":r! filter" like a bang
|
||||||
if (eap->cmdidx == CMD_read) {
|
if (eap->cmdidx == CMD_read && eap->forceit) {
|
||||||
if (eap->forceit) {
|
eap->forceit = false; // :r! filter
|
||||||
eap->forceit = false; // :r! filter
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check for '|' to separate commands and '"' to start comments.
|
// Check for '|' to separate commands and '"' to start comments.
|
||||||
@@ -2033,13 +2041,7 @@ static char *do_one_cmd(char **cmdlinep, int flags, cstack_T *cstack, LineGetter
|
|||||||
// 3. Skip over the range to find the command. Let "p" point to after it.
|
// 3. Skip over the range to find the command. Let "p" point to after it.
|
||||||
//
|
//
|
||||||
// We need the command to know what kind of range it uses.
|
// We need the command to know what kind of range it uses.
|
||||||
char *cmd = ea.cmd;
|
char *p = find_excmd_after_range(&ea);
|
||||||
ea.cmd = skip_range(ea.cmd, NULL);
|
|
||||||
if (*ea.cmd == '*') {
|
|
||||||
ea.cmd = skipwhite(ea.cmd + 1);
|
|
||||||
}
|
|
||||||
char *p = find_ex_command(&ea, NULL);
|
|
||||||
|
|
||||||
profile_cmd(&ea, cstack, fgetline, cookie);
|
profile_cmd(&ea, cstack, fgetline, cookie);
|
||||||
|
|
||||||
if (!exiting) {
|
if (!exiting) {
|
||||||
@@ -2068,7 +2070,6 @@ static char *do_one_cmd(char **cmdlinep, int flags, cstack_T *cstack, LineGetter
|
|||||||
// is equal to the lower.
|
// is equal to the lower.
|
||||||
set_cmd_addr_type(&ea, p);
|
set_cmd_addr_type(&ea, p);
|
||||||
|
|
||||||
ea.cmd = cmd;
|
|
||||||
if (parse_cmd_address(&ea, &errormsg, false) == FAIL) {
|
if (parse_cmd_address(&ea, &errormsg, false) == FAIL) {
|
||||||
goto doend;
|
goto doend;
|
||||||
}
|
}
|
||||||
@@ -2099,13 +2100,13 @@ static char *do_one_cmd(char **cmdlinep, int flags, cstack_T *cstack, LineGetter
|
|||||||
if (p != NULL && ea.cmdidx == CMD_SIZE && !ea.skip
|
if (p != NULL && ea.cmdidx == CMD_SIZE && !ea.skip
|
||||||
&& ASCII_ISUPPER(*ea.cmd)
|
&& ASCII_ISUPPER(*ea.cmd)
|
||||||
&& has_event(EVENT_CMDUNDEFINED)) {
|
&& has_event(EVENT_CMDUNDEFINED)) {
|
||||||
p = ea.cmd;
|
char *cmdname = ea.cmd;
|
||||||
while (ASCII_ISALNUM(*p)) {
|
while (ASCII_ISALNUM(*cmdname)) {
|
||||||
p++;
|
cmdname++;
|
||||||
}
|
}
|
||||||
p = xmemdupz(ea.cmd, (size_t)(p - ea.cmd));
|
cmdname = xmemdupz(ea.cmd, (size_t)(cmdname - ea.cmd));
|
||||||
int ret = apply_autocmds(EVENT_CMDUNDEFINED, p, p, true, NULL);
|
int ret = apply_autocmds(EVENT_CMDUNDEFINED, cmdname, cmdname, true, NULL);
|
||||||
xfree(p);
|
xfree(cmdname);
|
||||||
// If the autocommands did something and didn't cause an error, try
|
// If the autocommands did something and didn't cause an error, try
|
||||||
// finding the command again.
|
// finding the command again.
|
||||||
p = (ret && !aborting()) ? find_ex_command(&ea, NULL) : ea.cmd;
|
p = (ret && !aborting()) ? find_ex_command(&ea, NULL) : ea.cmd;
|
||||||
@@ -2138,14 +2139,8 @@ static char *do_one_cmd(char **cmdlinep, int flags, cstack_T *cstack, LineGetter
|
|||||||
// set when Not Implemented
|
// set when Not Implemented
|
||||||
const int ni = is_cmd_ni(ea.cmdidx);
|
const int ni = is_cmd_ni(ea.cmdidx);
|
||||||
|
|
||||||
// Forced commands.
|
// Determine if command has forceit flag ('!')
|
||||||
ea.forceit = *p == '!'
|
ea.forceit = parse_bang(&ea, &p);
|
||||||
&& ea.cmdidx != CMD_substitute
|
|
||||||
&& ea.cmdidx != CMD_smagic
|
|
||||||
&& ea.cmdidx != CMD_snomagic;
|
|
||||||
if (ea.forceit) {
|
|
||||||
p++;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 6. Parse arguments. Then check for errors.
|
// 6. Parse arguments. Then check for errors.
|
||||||
if (!IS_USER_CMDIDX(ea.cmdidx)) {
|
if (!IS_USER_CMDIDX(ea.cmdidx)) {
|
||||||
|
Reference in New Issue
Block a user