Patch 8.2.1897
Problem:    Command modifiers are saved and set inconsistently.
Solution:   Separate parsing and applying command modifiers.  Save values in
            cmdmod_T.
Files:      src/structs.h, src/ex_docmd.c, src/proto/ex_docmd.pro,
            src/ex_cmds.h, src/vim9compile.c


*** ../vim-8.2.1896/src/structs.h       2020-10-23 18:02:28.707453763 +0200
--- src/structs.h       2020-10-24 17:08:45.893235506 +0200
***************
*** 625,630 ****
--- 625,631 ----
   */
  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,652 ****
      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
  } cmdmod_T;
  
  #define MF_SEED_LEN   8
  
  struct memfile
--- 641,669 ----
      int               lockmarks;              // TRUE when ":lockmarks" was 
used
      int               keeppatterns;           // TRUE when ":keeppatterns" 
was used
      int               noswapfile;             // TRUE when ":noswapfile" was 
used
      regmatch_T        filter_regmatch;        // set by :filter /pat/
      int               filter_force;           // set for :filter!
! 
!     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
*** ../vim-8.2.1896/src/ex_docmd.c      2020-10-23 18:51:03.531271374 +0200
--- src/ex_docmd.c      2020-10-24 17:10:01.761070302 +0200
***************
*** 1764,1769 ****
--- 1764,1770 ----
  #endif
      if (parse_command_modifiers(&ea, &errormsg, FALSE) == FAIL)
        goto doend;
+     apply_cmdmod(&cmdmod);
  
      after_modifier = ea.cmd;
  
***************
*** 2515,2526 ****
  
      // 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 (emsg_silent < 0)
            emsg_silent = 0;
!       ea.did_esilent = 0;
      }
  
  /*
--- 2516,2527 ----
  
      // 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 && cmdmod.cmod_did_esilent > 0)
      {
!       emsg_silent -= cmdmod.cmod_did_esilent;
        if (emsg_silent < 0)
            emsg_silent = 0;
!       cmdmod.cmod_did_esilent = 0;
      }
  
  /*
***************
*** 2597,2611 ****
                        ? cmdnames[(int)ea.cmdidx].cmd_name : (char_u *)NULL);
  #endif
  
!     undo_cmdmod(&ea, 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;
  
--- 2598,2607 ----
                        ? cmdnames[(int)ea.cmdidx].cmd_name : (char_u *)NULL);
  #endif
  
!     undo_cmdmod(save_msg_scroll);
      cmdmod = save_cmdmod;
      reg_executing = save_reg_executing;
  
      if (ea.nextcmd && *ea.nextcmd == NUL)     // not really a next command
        ea.nextcmd = NULL;
  
***************
*** 2641,2650 ****
   * - 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".
   * Return FAIL when the command is not to be executed.
   * May set "errormsg" to an error message.
   */
--- 2637,2647 ----
   * - Set ex_pressedreturn for an empty command line.
   * - set msg_silent for ":silent"
   * - set 'eventignore' to "all" for ":noautocmd"
   * 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,2662 ****
      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 (;;)
--- 2652,2657 ----
***************
*** 2800,2813 ****
  
            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);
!                           }
                            continue;
                        }
                        if (!checkforcmd(&eap->cmd, "noswapfile", 3))
--- 2795,2801 ----
  
            case 'n':   if (checkforcmd(&eap->cmd, "noautocmd", 3))
                        {
!                           cmdmod.cmod_flags |= CMOD_NOAUTOCMD;
                            continue;
                        }
                        if (!checkforcmd(&eap->cmd, "noswapfile", 3))
***************
*** 2822,2858 ****
  
            case 's':   if (checkforcmd(&eap->cmd, "sandbox", 3))
                        {
! #ifdef HAVE_SANDBOX
!                           if (!skip_only)
!                           {
!                               if (!eap->did_sandbox)
!                                   ++sandbox;
!                               eap->did_sandbox = TRUE;
!                           }
! #endif
                            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;
!                       }
                        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;
                        }
-                       else
-                           cmdmod.msg_silent = TRUE;
                        continue;
  
            case 't':   if (checkforcmd(&p, "tab", 3))
--- 2810,2827 ----
  
            case 's':   if (checkforcmd(&eap->cmd, "sandbox", 3))
                        {
!                           cmdmod.cmod_flags |= CMOD_SANDBOX;
                            continue;
                        }
                        if (!checkforcmd(&eap->cmd, "silent", 3))
                            break;
!                       cmdmod.cmod_flags |= CMOD_SILENT;
                        if (*eap->cmd == '!' && !VIM_ISWHITE(eap->cmd[-1]))
                        {
                            // ":silent!", but not "silent !cmd"
                            eap->cmd = skipwhite(eap->cmd + 1);
!                           cmdmod.cmod_flags |= CMOD_ERRSILENT;
                        }
                        continue;
  
            case 't':   if (checkforcmd(&p, "tab", 3))
***************
*** 2884,2895 ****
  
            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;
!                       }
                        continue;
  
            case 'v':   if (checkforcmd(&eap->cmd, "vertical", 4))
--- 2853,2859 ----
  
            case 'u':   if (!checkforcmd(&eap->cmd, "unsilent", 3))
                            break;
!                       cmdmod.cmod_flags |= CMOD_UNSILENT;
                        continue;
  
            case 'v':   if (checkforcmd(&eap->cmd, "vertical", 4))
***************
*** 2899,2913 ****
                        }
                        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;
!                       }
                        eap->cmd = p;
                        continue;
        }
--- 2863,2872 ----
                        }
                        if (!checkforcmd(&p, "verbose", 4))
                            break;
!                       if (vim_isdigit(*eap->cmd))
!                           cmdmod.cmod_verbose = atoi((char *)eap->cmd);
!                       else
!                           cmdmod.cmod_verbose = 1;
                        eap->cmd = p;
                        continue;
        }
***************
*** 2918,2949 ****
  }
  
  /*
   * 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)
      {
        // Restore 'eventignore' to the value before ":noautocmd".
!       set_string_option_direct((char_u *)"ei", -1, cmdmod.save_ei,
                                                          OPT_FREE, SID_NONE);
!       free_string_option(cmdmod.save_ei);
      }
  
      if (cmdmod.filter_regmatch.regprog != NULL)
        vim_regfree(cmdmod.filter_regmatch.regprog);
  
!     if (eap->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 > eap->save_msg_silent)
!           msg_silent = eap->save_msg_silent;
!       emsg_silent -= eap->did_esilent;
        if (emsg_silent < 0)
            emsg_silent = 0;
        // Restore msg_scroll, it's set by file I/O commands, even when no
--- 2877,2965 ----
  }
  
  /*
+  * 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(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.cmod_save_ei,
                                                          OPT_FREE, SID_NONE);
!       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 (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 > 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,2959 ****
--- 2970,2978 ----
        // 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;
      }
  }
  
*** ../vim-8.2.1896/src/proto/ex_docmd.pro      2020-09-14 16:37:30.906845912 
+0200
--- src/proto/ex_docmd.pro      2020-10-24 16:04:10.792027114 +0200
***************
*** 7,13 ****
  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);
  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);
--- 7,14 ----
  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 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);
*** ../vim-8.2.1896/src/ex_cmds.h       2020-10-10 21:33:42.403033529 +0200
--- src/ex_cmds.h       2020-10-24 15:57:26.752808339 +0200
***************
*** 1884,1895 ****
  #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"
--- 1884,1889 ----
*** ../vim-8.2.1896/src/vim9compile.c   2020-10-23 18:02:28.707453763 +0200
--- src/vim9compile.c   2020-10-24 16:02:45.408209761 +0200
***************
*** 1831,1842 ****
      isn_T     *isn;
  
      // TODO: use more modifiers in the command
!     if (cmdmod.msg_silent || cmdmod.emsg_silent)
      {
        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;
      }
      return OK;
  }
--- 1831,1842 ----
      isn_T     *isn;
  
      // TODO: use more modifiers in the command
!     if (cmdmod.cmod_flags & (CMOD_SILENT | CMOD_ERRSILENT))
      {
        if ((isn = generate_instr(cctx, ISN_SILENT)) == NULL)
            return FAIL;
!       isn->isn_arg.number = (cmdmod.cmod_flags & CMOD_ERRSILENT) != 0;
!       cctx->ctx_silent = (cmdmod.cmod_flags & CMOD_ERRSILENT) ? 2 : 1;
      }
      return OK;
  }
***************
*** 7187,7193 ****
        }
        generate_cmdmods(&cctx);
  
!       undo_cmdmod(&ea, save_msg_scroll);
        cmdmod = save_cmdmod;
  
        // Skip ":call" to get to the function name.
--- 7187,7193 ----
        }
        generate_cmdmods(&cctx);
  
!       undo_cmdmod(save_msg_scroll);
        cmdmod = save_cmdmod;
  
        // Skip ":call" to get to the function name.
*** ../vim-8.2.1896/src/version.c       2020-10-24 13:30:46.280240528 +0200
--- src/version.c       2020-10-24 17:17:52.263945615 +0200
***************
*** 752,753 ****
--- 752,755 ----
  {   /* Add new patch number below this line */
+ /**/
+     1897,
  /**/

-- 
hundred-and-one symptoms of being an internet addict:
123. You ask the car dealer to install an extra cigarette lighter
     on your new car to power your notebook.

 /// Bram Moolenaar -- b...@moolenaar.net -- http://www.Moolenaar.net   \\\
///        sponsor Vim, vote for features -- http://www.Vim.org/sponsor/ \\\
\\\  an exciting new programming language -- http://www.Zimbu.org        ///
 \\\            help me help AIDS victims -- http://ICCF-Holland.org    ///

-- 
-- 
You received this message from the "vim_dev" maillist.
Do not top-post! Type your reply below the text you are replying to.
For more information, visit http://www.vim.org/maillist.php

--- 
You received this message because you are subscribed to the Google Groups 
"vim_dev" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to vim_dev+unsubscr...@googlegroups.com.
To view this discussion on the web visit 
https://groups.google.com/d/msgid/vim_dev/202010241519.09OFJjuQ1039509%40masaka.moolenaar.net.

Raspunde prin e-mail lui