# HG changeset patch # User Bram Moolenaar # Date 1603553404 -7200 # Node ID c996700d569f13645489e50fdde95d7b8755049d # Parent 91956373639886165414290234f15478e46d2045 patch 8.2.1897: command modifiers are saved and set inconsistently Commit: https://github.com/vim/vim/commit/5661ed6c833e05467cab33cb9b1c535e7e5cc570 Author: Bram Moolenaar Date: Sat Oct 24 17:19:16 2020 +0200 patch 8.2.1897: command modifiers are saved and set inconsistently Problem: Command modifiers are saved and set inconsistently. Solution: Separate parsing and applying command modifiers. Save values in cmdmod_T. diff --git a/src/ex_cmds.h b/src/ex_cmds.h --- a/src/ex_cmds.h +++ b/src/ex_cmds.h @@ -1884,12 +1884,6 @@ struct exarg #ifdef FEAT_EVAL cstack_T *cstack; // condition stack for ":if" etc. #endif - long verbose_save; // saved value of p_verbose - int save_msg_silent; // saved value of msg_silent - int did_esilent; // how many times emsg_silent was incremented -#ifdef HAVE_SANDBOX - int did_sandbox; // when TRUE did ++sandbox -#endif }; #define FORCE_BIN 1 // ":edit ++bin file" diff --git a/src/ex_docmd.c b/src/ex_docmd.c --- a/src/ex_docmd.c +++ b/src/ex_docmd.c @@ -1764,6 +1764,7 @@ do_one_cmd( #endif if (parse_command_modifiers(&ea, &errormsg, FALSE) == FAIL) goto doend; + apply_cmdmod(&cmdmod); after_modifier = ea.cmd; @@ -2515,12 +2516,12 @@ do_one_cmd( // 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 && ea.did_esilent > 0) - { - emsg_silent -= ea.did_esilent; + if (ea.cmdidx == CMD_try && cmdmod.cmod_did_esilent > 0) + { + emsg_silent -= cmdmod.cmod_did_esilent; if (emsg_silent < 0) emsg_silent = 0; - ea.did_esilent = 0; + cmdmod.cmod_did_esilent = 0; } /* @@ -2597,15 +2598,10 @@ doend: ? cmdnames[(int)ea.cmdidx].cmd_name : (char_u *)NULL); #endif - undo_cmdmod(&ea, save_msg_scroll); + undo_cmdmod(save_msg_scroll); cmdmod = save_cmdmod; reg_executing = save_reg_executing; -#ifdef HAVE_SANDBOX - if (ea.did_sandbox) - --sandbox; -#endif - if (ea.nextcmd && *ea.nextcmd == NUL) // not really a next command ea.nextcmd = NULL; @@ -2641,10 +2637,11 @@ ex_errmsg(char *msg, char_u *arg) * - Set ex_pressedreturn for an empty command line. * - set msg_silent for ":silent" * - set 'eventignore' to "all" for ":noautocmd" - * - set p_verbose for ":verbose" - * - Increment "sandbox" for ":sandbox" * When "skip_only" is TRUE the global variables are not changed, except for * "cmdmod". + * Call apply_cmdmod() to get the side effects of the modifiers: + * - Increment "sandbox" for ":sandbox" + * - set p_verbose for ":verbose" * Return FAIL when the command is not to be executed. * May set "errormsg" to an error message. */ @@ -2655,8 +2652,6 @@ parse_command_modifiers(exarg_T *eap, ch int starts_with_colon = FALSE; CLEAR_FIELD(cmdmod); - eap->verbose_save = -1; - eap->save_msg_silent = -1; // Repeat until no more command modifiers are found. for (;;) @@ -2800,14 +2795,7 @@ parse_command_modifiers(exarg_T *eap, ch case 'n': if (checkforcmd(&eap->cmd, "noautocmd", 3)) { - if (cmdmod.save_ei == NULL && !skip_only) - { - // Set 'eventignore' to "all". Restore the - // existing option value later. - cmdmod.save_ei = vim_strsave(p_ei); - set_string_option_direct((char_u *)"ei", -1, - (char_u *)"all", OPT_FREE, SID_NONE); - } + cmdmod.cmod_flags |= CMOD_NOAUTOCMD; continue; } if (!checkforcmd(&eap->cmd, "noswapfile", 3)) @@ -2822,37 +2810,18 @@ parse_command_modifiers(exarg_T *eap, ch case 's': if (checkforcmd(&eap->cmd, "sandbox", 3)) { -#ifdef HAVE_SANDBOX - if (!skip_only) - { - if (!eap->did_sandbox) - ++sandbox; - eap->did_sandbox = TRUE; - } -#endif + cmdmod.cmod_flags |= CMOD_SANDBOX; continue; } if (!checkforcmd(&eap->cmd, "silent", 3)) break; - if (!skip_only) - { - if (eap->save_msg_silent == -1) - eap->save_msg_silent = msg_silent; - ++msg_silent; - } + cmdmod.cmod_flags |= CMOD_SILENT; if (*eap->cmd == '!' && !VIM_ISWHITE(eap->cmd[-1])) { // ":silent!", but not "silent !cmd" eap->cmd = skipwhite(eap->cmd + 1); - if (!skip_only) - { - ++emsg_silent; - ++eap->did_esilent; - } - cmdmod.emsg_silent = TRUE; + cmdmod.cmod_flags |= CMOD_ERRSILENT; } - else - cmdmod.msg_silent = TRUE; continue; case 't': if (checkforcmd(&p, "tab", 3)) @@ -2884,12 +2853,7 @@ parse_command_modifiers(exarg_T *eap, ch case 'u': if (!checkforcmd(&eap->cmd, "unsilent", 3)) break; - if (!skip_only) - { - if (eap->save_msg_silent == -1) - eap->save_msg_silent = msg_silent; - msg_silent = 0; - } + cmdmod.cmod_flags |= CMOD_UNSILENT; continue; case 'v': if (checkforcmd(&eap->cmd, "vertical", 4)) @@ -2899,15 +2863,10 @@ parse_command_modifiers(exarg_T *eap, ch } if (!checkforcmd(&p, "verbose", 4)) break; - if (!skip_only) - { - if (eap->verbose_save < 0) - eap->verbose_save = p_verbose; - if (vim_isdigit(*eap->cmd)) - p_verbose = atoi((char *)eap->cmd); - else - p_verbose = 1; - } + if (vim_isdigit(*eap->cmd)) + cmdmod.cmod_verbose = atoi((char *)eap->cmd); + else + cmdmod.cmod_verbose = 1; eap->cmd = p; continue; } @@ -2918,32 +2877,89 @@ parse_command_modifiers(exarg_T *eap, ch } /* + * Apply the command modifiers. Saves current state in "cmdmod", call + * undo_cmdmod() later. + */ + void +apply_cmdmod(cmdmod_T *cmod) +{ +#ifdef HAVE_SANDBOX + if ((cmod->cmod_flags & CMOD_SANDBOX) && !cmod->cmod_did_sandbox) + { + ++sandbox; + cmod->cmod_did_sandbox = TRUE; + } +#endif + if (cmod->cmod_verbose > 0) + { + if (cmod->cmod_verbose_save == 0) + cmod->cmod_verbose_save = p_verbose + 1; + p_verbose = cmod->cmod_verbose; + } + + if ((cmod->cmod_flags & (CMOD_SILENT | CMOD_UNSILENT)) + && cmod->cmod_save_msg_silent == 0) + cmod->cmod_save_msg_silent = msg_silent + 1; + if (cmod->cmod_flags & CMOD_SILENT) + ++msg_silent; + if (cmod->cmod_flags & CMOD_UNSILENT) + msg_silent = 0; + + if (cmod->cmod_flags & CMOD_ERRSILENT) + { + ++emsg_silent; + ++cmod->cmod_did_esilent; + } + + if ((cmod->cmod_flags & CMOD_NOAUTOCMD) && cmdmod.cmod_save_ei == NULL) + { + // Set 'eventignore' to "all". + // First save the existing option value for restoring it later. + cmdmod.cmod_save_ei = vim_strsave(p_ei); + set_string_option_direct((char_u *)"ei", -1, + (char_u *)"all", OPT_FREE, SID_NONE); + } +} + +/* * Undo and free contents of "cmdmod". */ void -undo_cmdmod(exarg_T *eap, int save_msg_scroll) -{ - if (eap->verbose_save >= 0) - p_verbose = eap->verbose_save; - - if (cmdmod.save_ei != NULL) +undo_cmdmod(int save_msg_scroll) +{ + if (cmdmod.cmod_verbose_save > 0) + { + p_verbose = cmdmod.cmod_verbose_save - 1; + cmdmod.cmod_verbose_save = 0; + } + +#ifdef HAVE_SANDBOX + if (cmdmod.cmod_did_sandbox) + { + --sandbox; + cmdmod.cmod_did_sandbox = FALSE; + } +#endif + + if (cmdmod.cmod_save_ei != NULL) { // Restore 'eventignore' to the value before ":noautocmd". - set_string_option_direct((char_u *)"ei", -1, cmdmod.save_ei, + set_string_option_direct((char_u *)"ei", -1, cmdmod.cmod_save_ei, OPT_FREE, SID_NONE); - free_string_option(cmdmod.save_ei); + free_string_option(cmdmod.cmod_save_ei); + cmdmod.cmod_save_ei = NULL; } if (cmdmod.filter_regmatch.regprog != NULL) vim_regfree(cmdmod.filter_regmatch.regprog); - if (eap->save_msg_silent != -1) + if (cmdmod.cmod_save_msg_silent > 0) { // messages could be enabled for a serious error, need to check if the // counters don't become negative - if (!did_emsg || msg_silent > eap->save_msg_silent) - msg_silent = eap->save_msg_silent; - emsg_silent -= eap->did_esilent; + if (!did_emsg || msg_silent > cmdmod.cmod_save_msg_silent - 1) + msg_silent = cmdmod.cmod_save_msg_silent - 1; + emsg_silent -= cmdmod.cmod_did_esilent; if (emsg_silent < 0) emsg_silent = 0; // Restore msg_scroll, it's set by file I/O commands, even when no @@ -2954,6 +2970,9 @@ undo_cmdmod(exarg_T *eap, int save_msg_s // somewhere in the line. Put it back in the first column. if (redirecting()) msg_col = 0; + + cmdmod.cmod_save_msg_silent = 0; + cmdmod.cmod_did_esilent = 0; } } diff --git a/src/proto/ex_docmd.pro b/src/proto/ex_docmd.pro --- a/src/proto/ex_docmd.pro +++ b/src/proto/ex_docmd.pro @@ -7,7 +7,8 @@ void *getline_cookie(char_u *(*fgetline) char_u *getline_peek(char_u *(*fgetline)(int, void *, int, getline_opt_T), void *cookie); char *ex_errmsg(char *msg, char_u *arg); int parse_command_modifiers(exarg_T *eap, char **errormsg, int skip_only); -void undo_cmdmod(exarg_T *eap, int save_msg_scroll); +void apply_cmdmod(cmdmod_T *cmod); +void undo_cmdmod(int save_msg_scroll); int parse_cmd_address(exarg_T *eap, char **errormsg, int silent); int checkforcmd(char_u **pp, char *cmd, int len); char_u *skip_option_env_lead(char_u *start); diff --git a/src/structs.h b/src/structs.h --- a/src/structs.h +++ b/src/structs.h @@ -625,6 +625,7 @@ typedef struct */ typedef struct { + int cmod_flags; // CMOD_ flags, see below int hide; // TRUE when ":hide" was used # ifdef FEAT_BROWSE_CMD int browse; // TRUE to invoke file dialog @@ -640,13 +641,29 @@ typedef struct int lockmarks; // TRUE when ":lockmarks" was used int keeppatterns; // TRUE when ":keeppatterns" was used int noswapfile; // TRUE when ":noswapfile" was used - char_u *save_ei; // saved value of 'eventignore' regmatch_T filter_regmatch; // set by :filter /pat/ int filter_force; // set for :filter! - int msg_silent; // TRUE when ":silent" was used - int emsg_silent; // TRUE when ":silent!" was used + + int cmod_verbose; // non-zero to set 'verbose' + + // values for undo_cmdmod() + char_u *cmod_save_ei; // saved value of 'eventignore' +#ifdef HAVE_SANDBOX + int cmod_did_sandbox; // set when "sandbox" was incremented +#endif + long cmod_verbose_save; // if 'verbose' was set: value of + // p_verbose plus one + int cmod_save_msg_silent; // if non-zero: saved value of + // msg_silent + 1 + int cmod_did_esilent; // incremented when emsg_silent is } cmdmod_T; +#define CMOD_SANDBOX 0x01 +#define CMOD_SILENT 0x02 +#define CMOD_ERRSILENT 0x04 +#define CMOD_UNSILENT 0x08 +#define CMOD_NOAUTOCMD 0x10 + #define MF_SEED_LEN 8 struct memfile diff --git a/src/version.c b/src/version.c --- a/src/version.c +++ b/src/version.c @@ -751,6 +751,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ /**/ + 1897, +/**/ 1896, /**/ 1895, diff --git a/src/vim9compile.c b/src/vim9compile.c --- a/src/vim9compile.c +++ b/src/vim9compile.c @@ -1831,12 +1831,12 @@ generate_cmdmods(cctx_T *cctx) isn_T *isn; // TODO: use more modifiers in the command - if (cmdmod.msg_silent || cmdmod.emsg_silent) + if (cmdmod.cmod_flags & (CMOD_SILENT | CMOD_ERRSILENT)) { if ((isn = generate_instr(cctx, ISN_SILENT)) == NULL) return FAIL; - isn->isn_arg.number = cmdmod.emsg_silent; - cctx->ctx_silent = cmdmod.emsg_silent ? 2 : 1; + isn->isn_arg.number = (cmdmod.cmod_flags & CMOD_ERRSILENT) != 0; + cctx->ctx_silent = (cmdmod.cmod_flags & CMOD_ERRSILENT) ? 2 : 1; } return OK; } @@ -7187,7 +7187,7 @@ compile_def_function(ufunc_T *ufunc, int } generate_cmdmods(&cctx); - undo_cmdmod(&ea, save_msg_scroll); + undo_cmdmod(save_msg_scroll); cmdmod = save_cmdmod; // Skip ":call" to get to the function name.