aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/nvim/ex_docmd.c41
-rw-r--r--test/functional/api/vim_spec.lua49
2 files changed, 74 insertions, 16 deletions
diff --git a/src/nvim/ex_docmd.c b/src/nvim/ex_docmd.c
index 3b1b6e81e3..5e8c7dbdda 100644
--- a/src/nvim/ex_docmd.c
+++ b/src/nvim/ex_docmd.c
@@ -1361,6 +1361,13 @@ bool is_cmd_ni(cmdidx_T cmdidx)
bool parse_cmdline(char *cmdline, exarg_T *eap, CmdParseInfo *cmdinfo, char **errormsg)
{
char *after_modifier = NULL;
+ bool retval = false;
+ // parsing the command modifiers may set ex_pressedreturn
+ const bool save_ex_pressedreturn = ex_pressedreturn;
+ // parsing the command range may require moving the cursor
+ const pos_T save_cursor = curwin->w_cursor;
+ // parsing the command range may set the last search pattern
+ save_last_search_pattern();
// Initialize cmdinfo
CLEAR_POINTER(cmdinfo);
@@ -1375,13 +1382,10 @@ bool parse_cmdline(char *cmdline, exarg_T *eap, CmdParseInfo *cmdinfo, char **er
.cookie = NULL,
};
- const bool save_ex_pressedreturn = ex_pressedreturn;
// Parse command modifiers
if (parse_command_modifiers(eap, errormsg, &cmdinfo->cmdmod, false) == FAIL) {
- ex_pressedreturn = save_ex_pressedreturn;
- goto err;
+ goto end;
}
- ex_pressedreturn = save_ex_pressedreturn;
after_modifier = eap->cmd;
// Save location after command modifiers
@@ -1394,21 +1398,21 @@ bool parse_cmdline(char *cmdline, exarg_T *eap, CmdParseInfo *cmdinfo, char **er
char *p = find_ex_command(eap, NULL);
if (p == NULL) {
*errormsg = _(e_ambiguous_use_of_user_defined_command);
- goto err;
+ goto end;
}
// Set command address type and parse command range
set_cmd_addr_type(eap, p);
eap->cmd = cmd;
- if (parse_cmd_address(eap, errormsg, false) == FAIL) {
- goto err;
+ if (parse_cmd_address(eap, errormsg, true) == FAIL) {
+ goto end;
}
// Skip colon and whitespace
eap->cmd = skip_colon_white(eap->cmd, true);
// Fail if command is a comment or if command doesn't exist
if (*eap->cmd == NUL || *eap->cmd == '"') {
- goto err;
+ goto end;
}
// Fail if command is invalid
if (eap->cmdidx == CMD_SIZE) {
@@ -1417,7 +1421,7 @@ bool parse_cmdline(char *cmdline, exarg_T *eap, CmdParseInfo *cmdinfo, char **er
char *cmdname = after_modifier ? after_modifier : cmdline;
append_command(cmdname);
*errormsg = (char *)IObuff;
- goto err;
+ goto end;
}
// Correctly set 'forceit' for commands
@@ -1456,12 +1460,12 @@ bool parse_cmdline(char *cmdline, exarg_T *eap, CmdParseInfo *cmdinfo, char **er
// Fail if command doesn't support bang but is used with a bang
if (!(eap->argt & EX_BANG) && eap->forceit) {
*errormsg = _(e_nobang);
- goto err;
+ goto end;
}
// Fail if command doesn't support a range but it is given a range
if (!(eap->argt & EX_RANGE) && eap->addr_count > 0) {
*errormsg = _(e_norange);
- goto err;
+ goto end;
}
// Set default range for command if required
if ((eap->argt & EX_DFLALL) && eap->addr_count == 0) {
@@ -1471,7 +1475,7 @@ bool parse_cmdline(char *cmdline, exarg_T *eap, CmdParseInfo *cmdinfo, char **er
// Parse register and count
parse_register(eap);
if (parse_count(eap, errormsg, false) == FAIL) {
- goto err;
+ goto end;
}
// Remove leading whitespace and colon from next command
@@ -1487,10 +1491,15 @@ bool parse_cmdline(char *cmdline, exarg_T *eap, CmdParseInfo *cmdinfo, char **er
cmdinfo->magic.bar = true;
}
- return true;
-err:
- undo_cmdmod(&cmdinfo->cmdmod);
- return false;
+ retval = true;
+end:
+ if (!retval) {
+ undo_cmdmod(&cmdinfo->cmdmod);
+ }
+ ex_pressedreturn = save_ex_pressedreturn;
+ curwin->w_cursor = save_cursor;
+ restore_last_search_pattern();
+ return retval;
}
static int execute_cmd0(int *retv, exarg_T *eap, char **errormsg, bool preview)
diff --git a/test/functional/api/vim_spec.lua b/test/functional/api/vim_spec.lua
index 72a03c409a..24d0b6da45 100644
--- a/test/functional/api/vim_spec.lua
+++ b/test/functional/api/vim_spec.lua
@@ -3668,6 +3668,55 @@ describe('API', function()
:^ |
]])
end)
+ it('does not move cursor or change search history/pattern #19878 #19890', function()
+ meths.buf_set_lines(0, 0, -1, true, {'foo', 'bar', 'foo', 'bar'})
+ eq({1, 0}, meths.win_get_cursor(0))
+ eq('', funcs.getreg('/'))
+ eq('', funcs.histget('search'))
+ feed(':') -- call the API in cmdline mode to test whether it changes search history
+ eq({
+ cmd = 'normal',
+ args = {'x'},
+ bang = true,
+ range = {3, 4},
+ count = -1,
+ reg = '',
+ addr = 'line',
+ magic = {
+ file = false,
+ bar = false,
+ },
+ nargs = '+',
+ nextcmd = '',
+ mods = {
+ browse = false,
+ confirm = false,
+ emsg_silent = false,
+ filter = {
+ pattern = "",
+ force = false,
+ },
+ hide = false,
+ keepalt = false,
+ keepjumps = false,
+ keepmarks = false,
+ keeppatterns = false,
+ lockmarks = false,
+ noautocmd = false,
+ noswapfile = false,
+ sandbox = false,
+ silent = false,
+ split = "",
+ tab = 0,
+ unsilent = false,
+ verbose = -1,
+ vertical = false,
+ }
+ }, meths.parse_cmd('+2;/bar/normal! x', {}))
+ eq({1, 0}, meths.win_get_cursor(0))
+ eq('', funcs.getreg('/'))
+ eq('', funcs.histget('search'))
+ end)
end)
describe('nvim_cmd', function()
it('works', function ()