diff options
Diffstat (limited to 'src/nvim/ex_docmd.c')
-rw-r--r-- | src/nvim/ex_docmd.c | 270 |
1 files changed, 90 insertions, 180 deletions
diff --git a/src/nvim/ex_docmd.c b/src/nvim/ex_docmd.c index 73c4332543..9b0e05b19f 100644 --- a/src/nvim/ex_docmd.c +++ b/src/nvim/ex_docmd.c @@ -137,32 +137,6 @@ struct dbg_stuff { except_T *current_exception; }; -typedef struct { - // parsed results - exarg_T *eap; - char_u *parsed_upto; // local we've parsed up to so far - char_u *cmd; // start of command - char_u *after_modifier; - - // errors - char_u *errormsg; - - // globals that need to be updated - cmdmod_T cmdmod; - int sandbox; - int msg_silent; - int emsg_silent; - bool ex_pressedreturn; - long p_verbose; - - // other side-effects - bool set_eventignore; - long verbose_save; - int save_msg_silent; - int did_esilent; - bool did_sandbox; -} parse_state_T; - #ifdef INCLUDE_GENERATED_DECLARATIONS # include "ex_docmd.c.generated.h" #endif @@ -1235,89 +1209,6 @@ static char_u *skip_colon_white(const char_u *p, bool skipleadingwhite) return (char_u *)p; } -static void parse_state_to_global(const parse_state_T *parse_state) -{ - cmdmod = parse_state->cmdmod; - sandbox = parse_state->sandbox; - msg_silent = parse_state->msg_silent; - emsg_silent = parse_state->emsg_silent; - ex_pressedreturn = parse_state->ex_pressedreturn; - p_verbose = parse_state->p_verbose; - - if (parse_state->set_eventignore) { - set_string_option_direct( - (char_u *)"ei", -1, (char_u *)"all", OPT_FREE, SID_NONE); - } -} - -static void parse_state_from_global(parse_state_T *parse_state) -{ - memset(parse_state, 0, sizeof(*parse_state)); - parse_state->cmdmod = cmdmod; - parse_state->sandbox = sandbox; - parse_state->msg_silent = msg_silent; - parse_state->emsg_silent = emsg_silent; - parse_state->ex_pressedreturn = ex_pressedreturn; - parse_state->p_verbose = p_verbose; -} - -// -// Parse one Ex command. -// -// This has no side-effects, except for modifying parameters -// passed in by pointer. -// -// The `out` should be zeroed, and its `ea` member initialised, -// before calling this function. -// -static bool parse_one_cmd( - char_u **cmdlinep, - parse_state_T *const out, - cstack_T *cstack, - LineGetter fgetline, - void *fgetline_cookie) -{ - exarg_T ea = { - .line1 = 1, - .line2 = 1, - }; - *out->eap = ea; - - // "#!anything" is handled like a comment. - if ((*cmdlinep)[0] == '#' && (*cmdlinep)[1] == '!') { - return false; - } - - /* - * Repeat until no more command modifiers are found. - * The "ea" structure holds the arguments that can be used. - */ - ea.cmd = *cmdlinep; - ea.cmdlinep = cmdlinep; - ea.getline = fgetline; - ea.cookie = fgetline_cookie; - ea.cstack = cstack; - if (parse_command_modifiers(&ea, out, &out->errormsg) == FAIL) { - return false; - } - out->after_modifier = ea.cmd; - - // 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. - - out->cmd = ea.cmd; - ea.cmd = skip_range(ea.cmd, NULL); - if (*ea.cmd == '*') { - ea.cmd = skipwhite(ea.cmd + 1); - } - out->parsed_upto = find_command(&ea, NULL); - - *out->eap = ea; - - return true; -} - /* * Execute one Ex command. * @@ -1346,12 +1237,16 @@ static char_u * do_one_cmd(char_u **cmdlinep, linenr_T lnum; long n; char_u *errormsg = NULL; // error message + char_u *after_modifier = NULL; exarg_T ea; int save_msg_scroll = msg_scroll; - parse_state_T parsed; cmdmod_T save_cmdmod; const int save_reg_executing = reg_executing; + char_u *cmd; + memset(&ea, 0, sizeof(ea)); + ea.line1 = 1; + ea.line2 = 1; ex_nesting_level++; /* When the last file has not been edited :q has to be typed twice. */ @@ -1369,29 +1264,43 @@ static char_u * do_one_cmd(char_u **cmdlinep, */ save_cmdmod = cmdmod; - parse_state_from_global(&parsed); - parsed.eap = &ea; - parsed.verbose_save = -1; - parsed.save_msg_silent = -1; - parsed.did_esilent = 0; - parsed.did_sandbox = false; - bool parse_success = parse_one_cmd(cmdlinep, &parsed, cstack, fgetline, cookie); - parse_state_to_global(&parsed); + // "#!anything" is handled like a comment. + if ((*cmdlinep)[0] == '#' && (*cmdlinep)[1] == '!') { + goto doend; + } - // Update locals from parse_one_cmd() - errormsg = parsed.errormsg; - p = parsed.parsed_upto; + /* + * Repeat until no more command modifiers are found. + * The "ea" structure holds the arguments that can be used. + */ + ea.cmd = *cmdlinep; + ea.cmdlinep = cmdlinep; + ea.getline = fgetline; + ea.cookie = cookie; + ea.cstack = cstack; - if (!parse_success) { + if (parse_command_modifiers(&ea, &errormsg) == FAIL) { goto doend; } + after_modifier = ea.cmd; + ea.skip = (did_emsg || got_int || current_exception || (cstack->cs_idx >= 0 && !(cstack->cs_flags[cstack->cs_idx] & CSF_ACTIVE))); + // 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. + cmd = ea.cmd; + ea.cmd = skip_range(ea.cmd, NULL); + if (*ea.cmd == '*') { + ea.cmd = skipwhite(ea.cmd + 1); + } + p = find_command(&ea, NULL); + // Count this line for profiling if skip is TRUE. if (do_profiling == PROF_YES && (!ea.skip || cstack->cs_idx == 0 @@ -1461,7 +1370,7 @@ static char_u * do_one_cmd(char_u **cmdlinep, } } - ea.cmd = parsed.cmd; + ea.cmd = cmd; if (parse_cmd_address(&ea, &errormsg) == FAIL) { goto doend; } @@ -1542,8 +1451,8 @@ static char_u * do_one_cmd(char_u **cmdlinep, if (!(flags & DOCMD_VERBOSE)) { // If the modifier was parsed OK the error must be in the following // command - if (parsed.after_modifier != NULL) { - append_command(parsed.after_modifier); + if (after_modifier != NULL) { + append_command(after_modifier); } else { append_command(*cmdlinep); } @@ -2018,12 +1927,12 @@ static char_u * do_one_cmd(char_u **cmdlinep, // The :try command saves the emsg_silent flag, reset it here when // ":silent! try" was used, it should only apply to :try itself. - if (ea.cmdidx == CMD_try && parsed.did_esilent > 0) { - emsg_silent -= parsed.did_esilent; + if (ea.cmdidx == CMD_try && ea.did_esilent > 0) { + emsg_silent -= ea.did_esilent; if (emsg_silent < 0) { emsg_silent = 0; } - parsed.did_esilent = 0; + ea.did_esilent = 0; } // 7. Execute the command. @@ -2082,8 +1991,8 @@ doend: ? cmdnames[(int)ea.cmdidx].cmd_name : (char_u *)NULL); - if (parsed.verbose_save >= 0) { - p_verbose = parsed.verbose_save; + if (ea.verbose_save >= 0) { + p_verbose = ea.verbose_save; } if (cmdmod.save_ei != NULL) { /* Restore 'eventignore' to the value before ":noautocmd". */ @@ -2099,13 +2008,13 @@ doend: cmdmod = save_cmdmod; reg_executing = save_reg_executing; - if (parsed.save_msg_silent != -1) { + if (ea.save_msg_silent != -1) { // messages could be enabled for a serious error, need to check if the // counters don't become negative - if (!did_emsg || msg_silent > parsed.save_msg_silent) { - msg_silent = parsed.save_msg_silent; + if (!did_emsg || msg_silent > ea.save_msg_silent) { + msg_silent = ea.save_msg_silent; } - emsg_silent -= parsed.did_esilent; + emsg_silent -= ea.did_esilent; if (emsg_silent < 0) { emsg_silent = 0; } @@ -2119,7 +2028,7 @@ doend: msg_col = 0; } - if (parsed.did_sandbox) { + if (ea.did_sandbox) { sandbox--; } @@ -2140,13 +2049,13 @@ doend: // - Increment "sandbox" for ":sandbox" // Return FAIL when the command is not to be executed. // May set "errormsg" to an error message. -int parse_command_modifiers(exarg_T *eap, parse_state_T *const out, char_u **errormsg) +int parse_command_modifiers(exarg_T *eap, char_u **errormsg) { char_u *p; memset(&cmdmod, 0, sizeof(cmdmod)); - out->verbose_save = -1; - out->save_msg_silent = -1; + eap->verbose_save = -1; + eap->save_msg_silent = -1; for (;; ) { /* @@ -2164,7 +2073,7 @@ int parse_command_modifiers(exarg_T *eap, parse_state_T *const out, char_u **err || getline_equal(eap->getline, eap->cookie, getexline)) && curwin->w_cursor.lnum < curbuf->b_ml.ml_line_count) { eap->cmd = (char_u *)"+"; - out->ex_pressedreturn = true; + ex_pressedreturn = true; } // ignore comment and empty lines @@ -2172,7 +2081,7 @@ int parse_command_modifiers(exarg_T *eap, parse_state_T *const out, char_u **err return FAIL; } if (*eap->cmd == NUL) { - out->ex_pressedreturn = true; + ex_pressedreturn = true; return FAIL; } @@ -2184,44 +2093,44 @@ int parse_command_modifiers(exarg_T *eap, parse_state_T *const out, char_u **err // When adding an entry, also modify cmd_exists(). case 'a': if (!checkforcmd(&eap->cmd, "aboveleft", 3)) break; - out->cmdmod.split |= WSP_ABOVE; + cmdmod.split |= WSP_ABOVE; continue; case 'b': if (checkforcmd(&eap->cmd, "belowright", 3)) { - out->cmdmod.split |= WSP_BELOW; + cmdmod.split |= WSP_BELOW; continue; } if (checkforcmd(&eap->cmd, "browse", 3)) { - out->cmdmod.browse = true; + cmdmod.browse = true; continue; } if (!checkforcmd(&eap->cmd, "botright", 2)) { break; } - out->cmdmod.split |= WSP_BOT; + cmdmod.split |= WSP_BOT; continue; case 'c': if (!checkforcmd(&eap->cmd, "confirm", 4)) break; - out->cmdmod.confirm = true; + cmdmod.confirm = true; continue; case 'k': if (checkforcmd(&eap->cmd, "keepmarks", 3)) { - out->cmdmod.keepmarks = true; + cmdmod.keepmarks = true; continue; } if (checkforcmd(&eap->cmd, "keepalt", 5)) { - out->cmdmod.keepalt = true; + cmdmod.keepalt = true; continue; } if (checkforcmd(&eap->cmd, "keeppatterns", 5)) { - out->cmdmod.keeppatterns = true; + cmdmod.keeppatterns = true; continue; } if (!checkforcmd(&eap->cmd, "keepjumps", 5)) { break; } - out->cmdmod.keepjumps = true; + cmdmod.keepjumps = true; continue; case 'f': { // only accept ":filter {pat} cmd" @@ -2231,7 +2140,7 @@ int parse_command_modifiers(exarg_T *eap, parse_state_T *const out, char_u **err break; } if (*p == '!') { - out->cmdmod.filter_force = true; + cmdmod.filter_force = true; p = skipwhite(p + 1); if (*p == NUL || ends_excmd(*p)) { break; @@ -2241,8 +2150,8 @@ int parse_command_modifiers(exarg_T *eap, parse_state_T *const out, char_u **err if (p == NULL || *p == NUL) { break; } - out->cmdmod.filter_regmatch.regprog = vim_regcomp(reg_pat, RE_MAGIC); - if (out->cmdmod.filter_regmatch.regprog == NULL) { + cmdmod.filter_regmatch.regprog = vim_regcomp(reg_pat, RE_MAGIC); + if (cmdmod.filter_regmatch.regprog == NULL) { break; } eap->cmd = p; @@ -2254,60 +2163,61 @@ int parse_command_modifiers(exarg_T *eap, parse_state_T *const out, char_u **err || *p == NUL || ends_excmd(*p)) break; eap->cmd = p; - out->cmdmod.hide = true; + cmdmod.hide = true; continue; case 'l': if (checkforcmd(&eap->cmd, "lockmarks", 3)) { - out->cmdmod.lockmarks = true; + cmdmod.lockmarks = true; continue; } if (!checkforcmd(&eap->cmd, "leftabove", 5)) { break; } - out->cmdmod.split |= WSP_ABOVE; + cmdmod.split |= WSP_ABOVE; continue; case 'n': if (checkforcmd(&eap->cmd, "noautocmd", 3)) { - if (out->cmdmod.save_ei == NULL) { + if (cmdmod.save_ei == NULL) { // Set 'eventignore' to "all". Restore the // existing option value later. - out->cmdmod.save_ei = vim_strsave(p_ei); - out->set_eventignore = true; + cmdmod.save_ei = vim_strsave(p_ei); + set_string_option_direct((char_u *)"ei", -1, + (char_u *)"all", OPT_FREE, SID_NONE); } continue; } if (!checkforcmd(&eap->cmd, "noswapfile", 3)) { break; } - out->cmdmod.noswapfile = true; + cmdmod.noswapfile = true; continue; case 'r': if (!checkforcmd(&eap->cmd, "rightbelow", 6)) break; - out->cmdmod.split |= WSP_BELOW; + cmdmod.split |= WSP_BELOW; continue; case 's': if (checkforcmd(&eap->cmd, "sandbox", 3)) { - if (!out->did_sandbox) { - out->sandbox++; + if (!eap->did_sandbox) { + sandbox++; } - out->did_sandbox = true; + eap->did_sandbox = true; continue; } if (!checkforcmd(&eap->cmd, "silent", 3)) { break; } - if (out->save_msg_silent == -1) { - out->save_msg_silent = out->msg_silent; + if (eap->save_msg_silent == -1) { + eap->save_msg_silent = msg_silent; } - out->msg_silent++; + msg_silent++; if (*eap->cmd == '!' && !ascii_iswhite(eap->cmd[-1])) { // ":silent!", but not "silent !cmd" eap->cmd = skipwhite(eap->cmd + 1); - out->emsg_silent++; - out->did_esilent++; + emsg_silent++; + eap->did_esilent++; } continue; @@ -2316,13 +2226,13 @@ int parse_command_modifiers(exarg_T *eap, parse_state_T *const out, char_u **err eap, &eap->cmd, ADDR_TABS, eap->skip, false, 1); if (tabnr == MAXLNUM) { - out->cmdmod.tab = tabpage_index(curtab) + 1; + cmdmod.tab = tabpage_index(curtab) + 1; } else { if (tabnr < 0 || tabnr > LAST_TAB_NR) { - out->errormsg = (char_u *)_(e_invrange); + *errormsg = (char_u *)_(e_invrange); return false; } - out->cmdmod.tab = tabnr + 1; + cmdmod.tab = tabnr + 1; } eap->cmd = p; continue; @@ -2330,30 +2240,30 @@ int parse_command_modifiers(exarg_T *eap, parse_state_T *const out, char_u **err if (!checkforcmd(&eap->cmd, "topleft", 2)) { break; } - out->cmdmod.split |= WSP_TOP; + cmdmod.split |= WSP_TOP; continue; case 'u': if (!checkforcmd(&eap->cmd, "unsilent", 3)) break; - if (out->save_msg_silent == -1) { - out->save_msg_silent = out->msg_silent; + if (eap->save_msg_silent == -1) { + eap->save_msg_silent = msg_silent; } - out->msg_silent = 0; + msg_silent = 0; continue; case 'v': if (checkforcmd(&eap->cmd, "vertical", 4)) { - out->cmdmod.split |= WSP_VERT; + cmdmod.split |= WSP_VERT; continue; } if (!checkforcmd(&p, "verbose", 4)) break; - if (out->verbose_save < 0) { - out->verbose_save = out->p_verbose; + if (eap->verbose_save < 0) { + eap->verbose_save = p_verbose; } if (ascii_isdigit(*eap->cmd)) { - out->p_verbose = atoi((char *)eap->cmd); + p_verbose = atoi((char *)eap->cmd); } else { - out->p_verbose = 1; + p_verbose = 1; } eap->cmd = p; continue; |