]> granicus.if.org Git - vim/commitdiff
patch 8.2.1897: command modifiers are saved and set inconsistently v8.2.1897
authorBram Moolenaar <Bram@vim.org>
Sat, 24 Oct 2020 15:19:16 +0000 (17:19 +0200)
committerBram Moolenaar <Bram@vim.org>
Sat, 24 Oct 2020 15:19:16 +0000 (17:19 +0200)
Problem:    Command modifiers are saved and set inconsistently.
Solution:   Separate parsing and applying command modifiers.  Save values in
            cmdmod_T.

src/ex_cmds.h
src/ex_docmd.c
src/proto/ex_docmd.pro
src/structs.h
src/version.c
src/vim9compile.c

index 0b52c11ee022f21d3028cb49307d5d95336178ac..d53b6df6d222a6cf43413c7c4f9c14b8eab60647 100644 (file)
@@ -1883,12 +1883,6 @@ struct exarg
     void       *cookie;        // argument for getline()
 #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
 };
 
index 665a46146d2e7b918a5026885b4d47db634f419e..1e1b8e3a461245c27e1cb35f2e5370bcd0f0bf24 100644 (file)
@@ -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)
+    if (ea.cmdidx == CMD_try && cmdmod.cmod_did_esilent > 0)
     {
-       emsg_silent -= ea.did_esilent;
+       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, char **errormsg, int skip_only)
     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, char **errormsg, int skip_only)
 
            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, char **errormsg, int skip_only)
 
            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, char **errormsg, int skip_only)
 
            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, char **errormsg, int skip_only)
                        }
                        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;
        }
@@ -2917,33 +2876,90 @@ parse_command_modifiers(exarg_T *eap, char **errormsg, int skip_only)
     return OK;
 }
 
+/*
+ * 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)
+undo_cmdmod(int save_msg_scroll)
 {
-    if (eap->verbose_save >= 0)
-       p_verbose = eap->verbose_save;
+    if (cmdmod.cmod_verbose_save > 0)
+    {
+       p_verbose = cmdmod.cmod_verbose_save - 1;
+       cmdmod.cmod_verbose_save = 0;
+    }
 
-    if (cmdmod.save_ei != NULL)
+#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_scroll)
        // 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;
     }
 }
 
index 7d46f15d51bcc2a1a3ade38f8ff1a0f9d54ff168..32fada57faaa59a83ff917585098bacecadba835 100644 (file)
@@ -7,7 +7,8 @@ void *getline_cookie(char_u *(*fgetline)(int, void *, int, getline_opt_T), void
 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);
index f01598e7adfafdce7801ed51b5b1001954577ea4..98f8c9a51da2d32ff8ecf0a7383f3a03e230e4ee 100644 (file)
@@ -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
index a1ee33e1ac8621412da13c5005b15aa9358e7c1a..cdf0be38c202a87f734d634f44a821c431af3bba 100644 (file)
@@ -750,6 +750,8 @@ static char *(features[]) =
 
 static int included_patches[] =
 {   /* Add new patch number below this line */
+/**/
+    1897,
 /**/
     1896,
 /**/
index 421957708632d88446ba60f1966902b3dd8a1e2c..4c5c8d9aae4a83da1852afad35dc83db14ae8d45 100644 (file)
@@ -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 set_return_type, cctx_T *outer_cctx)
        }
        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.