Patch 8.2.2295
Problem:    Incsearch does not detect empty pattern properly.
Solution:   Return magic state when skipping over a pattern. (Christian
            Brabandt, closes #7612, closes #6420)
Files:      src/ex_cmds.c, src/ex_docmd.c, src/ex_getln.c, src/globals.h,
            src/option.c, src/tag.c, src/proto/regexp.pro, src/regexp.c,
            src/search.c, src/structs.h, src/vim9compile.c,
            src/testdir/dumps/Test_incsearch_sub_01.dump,
            src/testdir/dumps/Test_incsearch_sub_02.dump,
            src/testdir/test_search.vim


*** ../vim-8.2.2294/src/ex_cmds.c       2020-12-27 19:00:20.706479331 +0100
--- src/ex_cmds.c       2021-01-04 11:31:55.813633440 +0100
***************
*** 3672,3678 ****
            delimiter = *cmd++;             // remember delimiter character
            pat = cmd;                      // remember start of search pat
            cmd = skip_regexp_ex(cmd, delimiter, magic_isset(),
!                                                             &eap->arg, NULL);
            if (cmd[0] == delimiter)        // end delimiter found
                *cmd++ = NUL;               // replace it with a NUL
        }
--- 3672,3678 ----
            delimiter = *cmd++;             // remember delimiter character
            pat = cmd;                      // remember start of search pat
            cmd = skip_regexp_ex(cmd, delimiter, magic_isset(),
!                                                       &eap->arg, NULL, NULL);
            if (cmd[0] == delimiter)        // end delimiter found
                *cmd++ = NUL;               // replace it with a NUL
        }
***************
*** 4856,4862 ****
        if (delim)
            ++cmd;              // skip delimiter if there is one
        pat = cmd;              // remember start of pattern
!       cmd = skip_regexp_ex(cmd, delim, magic_isset(), &eap->arg, NULL);
        if (cmd[0] == delim)                // end delimiter found
            *cmd++ = NUL;                   // replace it with a NUL
      }
--- 4856,4862 ----
        if (delim)
            ++cmd;              // skip delimiter if there is one
        pat = cmd;              // remember start of pattern
!       cmd = skip_regexp_ex(cmd, delim, magic_isset(), &eap->arg, NULL, NULL);
        if (cmd[0] == delim)                // end delimiter found
            *cmd++ = NUL;                   // replace it with a NUL
      }
*** ../vim-8.2.2294/src/ex_docmd.c      2020-12-29 11:14:58.444606193 +0100
--- src/ex_docmd.c      2021-01-04 11:40:35.783731667 +0100
***************
*** 7529,7537 ****
      static void
  ex_submagic(exarg_T *eap)
  {
!     magic_T saved = magic_overruled;
  
!     magic_overruled = eap->cmdidx == CMD_smagic ? MAGIC_ON : MAGIC_OFF;
      ex_substitute(eap);
      magic_overruled = saved;
  }
--- 7529,7538 ----
      static void
  ex_submagic(exarg_T *eap)
  {
!     optmagic_T saved = magic_overruled;
  
!     magic_overruled = eap->cmdidx == CMD_smagic
!                                         ? OPTION_MAGIC_ON : OPTION_MAGIC_OFF;
      ex_substitute(eap);
      magic_overruled = saved;
  }
*** ../vim-8.2.2294/src/ex_getln.c      2020-12-21 19:59:04.569197722 +0100
--- src/ex_getln.c      2021-01-04 11:48:48.157971176 +0100
***************
*** 52,57 ****
--- 52,60 ----
  static int    cmdline_paste(int regname, int literally, int remcr);
  static void   redrawcmdprompt(void);
  static int    ccheck_abbr(int);
+ #ifdef FEAT_SEARCH_EXTRA
+ static int    empty_pattern_magic(char_u *pat, size_t len, magic_T magic_val);
+ #endif
  
  #ifdef FEAT_CMDWIN
  static int    open_cmdwin(void);
***************
*** 89,103 ****
   * as a trailing \|, which can happen while typing a pattern.
   */
      static int
! empty_pattern(char_u *p)
  {
!     size_t n = STRLEN(p);
  
      // remove trailing \v and the like
!     while (n >= 2 && p[n - 2] == '\\'
!                         && vim_strchr((char_u *)"mMvVcCZ", p[n - 1]) != NULL)
!       n -= 2;
!     return n == 0 || (n >= 2 && p[n - 2] == '\\' && p[n - 1] == '|');
  }
  
  // Struct to store the viewstate during 'incsearch' highlighting.
--- 92,125 ----
   * as a trailing \|, which can happen while typing a pattern.
   */
      static int
! empty_pattern(char_u *p, int delim)
  {
!     size_t    n = STRLEN(p);
!     magic_T   magic_val = MAGIC_ON;
! 
!     if (n > 0)
!       (void) skip_regexp_ex(p, delim, magic_isset(), NULL, NULL, &magic_val);
!     else
!       return TRUE;
  
+     return empty_pattern_magic(p, n, magic_val);
+ }
+ 
+     static int
+ empty_pattern_magic(char_u *p, size_t len, magic_T magic_val)
+ {
      // remove trailing \v and the like
!     while (len >= 2 && p[len - 2] == '\\'
!                         && vim_strchr((char_u *)"mMvVcCZ", p[len - 1]) != 
NULL)
!        len -= 2;
! 
!     // true, if the pattern is empty, or the pattern ends with \| and magic is
!     // set (or it ends with '|' and very magic is set)
!     return len == 0 || (len > 1
!           && ((p[len - 2] == '\\'
!                                && p[len - 1] == '|' && magic_val == MAGIC_ON)
!               || (p[len - 2] != '\\'
!                            && p[len - 1] == '|' && magic_val == MAGIC_ALL)));
  }
  
  // Struct to store the viewstate during 'incsearch' highlighting.
***************
*** 149,155 ****
      pos_T     match_end;
      int               did_incsearch;
      int               incsearch_postponed;
!     magic_T   magic_overruled_save;
  } incsearch_state_T;
  
      static void
--- 171,177 ----
      pos_T     match_end;
      int               did_incsearch;
      int               incsearch_postponed;
!     optmagic_T        magic_overruled_save;
  } incsearch_state_T;
  
      static void
***************
*** 207,212 ****
--- 229,235 ----
      pos_T     save_cursor;
      int               use_last_pat;
      int               retval = FALSE;
+     magic_T     magic = 0;
  
      *skiplen = 0;
      *patlen = ccline.cmdlen;
***************
*** 252,260 ****
            || STRNCMP(cmd, "vglobal", p - cmd) == 0)
      {
        if (*cmd == 's' && cmd[1] == 'm')
!           magic_overruled = MAGIC_ON;
        else if (*cmd == 's' && cmd[1] == 'n')
!           magic_overruled = MAGIC_OFF;
      }
      else if (STRNCMP(cmd, "sort", MAX(p - cmd, 3)) == 0)
      {
--- 275,283 ----
            || STRNCMP(cmd, "vglobal", p - cmd) == 0)
      {
        if (*cmd == 's' && cmd[1] == 'm')
!           magic_overruled = OPTION_MAGIC_ON;
        else if (*cmd == 's' && cmd[1] == 'n')
!           magic_overruled = OPTION_MAGIC_OFF;
      }
      else if (STRNCMP(cmd, "sort", MAX(p - cmd, 3)) == 0)
      {
***************
*** 288,294 ****
      p = skipwhite(p);
      delim = (delim_optional && vim_isIDc(*p)) ? ' ' : *p++;
      *search_delim = delim;
!     end = skip_regexp(p, delim, magic_isset());
  
      use_last_pat = end == p && *end == delim;
  
--- 311,317 ----
      p = skipwhite(p);
      delim = (delim_optional && vim_isIDc(*p)) ? ' ' : *p++;
      *search_delim = delim;
!     end = skip_regexp_ex(p, delim, magic_isset(), NULL, NULL, &magic);
  
      use_last_pat = end == p && *end == delim;
  
***************
*** 302,308 ****
        int  empty;
  
        *end = NUL;
!       empty = empty_pattern(p);
        *end = c;
        if (empty)
            goto theend;
--- 325,331 ----
        int  empty;
  
        *end = NUL;
!       empty = empty_pattern_magic(p, STRLEN(p), magic);
        *end = c;
        if (empty)
            goto theend;
***************
*** 535,541 ****
      {
        next_char = ccline.cmdbuff[skiplen + patlen];
        ccline.cmdbuff[skiplen + patlen] = NUL;
!       if (empty_pattern(ccline.cmdbuff) && !no_hlsearch)
        {
            redraw_all_later(SOME_VALID);
            set_no_hlsearch(TRUE);
--- 558,565 ----
      {
        next_char = ccline.cmdbuff[skiplen + patlen];
        ccline.cmdbuff[skiplen + patlen] = NUL;
!       if (empty_pattern(ccline.cmdbuff + skiplen, search_delim)
!                                                              && !no_hlsearch)
        {
            redraw_all_later(SOME_VALID);
            set_no_hlsearch(TRUE);
*** ../vim-8.2.2294/src/globals.h       2020-12-28 18:25:56.796886014 +0100
--- src/globals.h       2021-01-04 11:50:48.369544048 +0100
***************
*** 1945,1951 ****
  #define FOR_ALL_LIST_ITEMS(l, li) \
      for ((li) = (l)->lv_first; (li) != NULL; (li) = (li)->li_next)
  
! // While executing a regexp and set to MAGIC_ON or MAGIC_OFF this overrules
! // p_magic.  Otherwise set to MAGIC_NOT_SET.
! 
! EXTERN magic_T magic_overruled INIT(= MAGIC_NOT_SET);
--- 1945,1950 ----
  #define FOR_ALL_LIST_ITEMS(l, li) \
      for ((li) = (l)->lv_first; (li) != NULL; (li) = (li)->li_next)
  
! // While executing a regexp and set to OPTION_MAGIC_ON or OPTION_MAGIC_OFF 
this
! // overrules p_magic.  Otherwise set to OPTION_MAGIC_NOT_SET.
! EXTERN optmagic_T magic_overruled INIT(= OPTION_MAGIC_NOT_SET);
*** ../vim-8.2.2294/src/option.c        2021-01-02 16:53:08.294010035 +0100
--- src/option.c        2021-01-04 11:31:55.813633440 +0100
***************
*** 7009,7017 ****
  {
      switch (magic_overruled)
      {
!       case MAGIC_ON:      return TRUE;
!       case MAGIC_OFF:     return FALSE;
!       case MAGIC_NOT_SET: break;
      }
  #ifdef FEAT_EVAL
      if (in_vim9script())
--- 7009,7017 ----
  {
      switch (magic_overruled)
      {
!       case OPTION_MAGIC_ON:      return TRUE;
!       case OPTION_MAGIC_OFF:     return FALSE;
!       case OPTION_MAGIC_NOT_SET: break;
      }
  #ifdef FEAT_EVAL
      if (in_vim9script())
*** ../vim-8.2.2294/src/tag.c   2020-12-21 19:59:04.569197722 +0100
--- src/tag.c   2021-01-04 11:50:22.621635476 +0100
***************
*** 3312,3318 ****
      int               keep_help)      // keep help flag (FALSE for cscope)
  {
      int               save_secure;
!     int               save_magic_overruled;
      int               save_p_ws, save_p_scs, save_p_ic;
      linenr_T  save_lnum;
      char_u    *str;
--- 3312,3318 ----
      int               keep_help)      // keep help flag (FALSE for cscope)
  {
      int               save_secure;
!     optmagic_T        save_magic_overruled;
      int               save_p_ws, save_p_scs, save_p_ic;
      linenr_T  save_lnum;
      char_u    *str;
***************
*** 3505,3511 ****
        ++sandbox;
  #endif
        save_magic_overruled = magic_overruled;
!       magic_overruled = MAGIC_OFF;    // always execute with 'nomagic'
  #ifdef FEAT_SEARCH_EXTRA
        // Save value of no_hlsearch, jumping to a tag is not a real search
        save_no_hlsearch = no_hlsearch;
--- 3505,3511 ----
        ++sandbox;
  #endif
        save_magic_overruled = magic_overruled;
!       magic_overruled = OPTION_MAGIC_OFF;     // always execute with 'nomagic'
  #ifdef FEAT_SEARCH_EXTRA
        // Save value of no_hlsearch, jumping to a tag is not a real search
        save_no_hlsearch = no_hlsearch;
*** ../vim-8.2.2294/src/proto/regexp.pro        2020-04-20 19:42:06.590078519 
+0200
--- src/proto/regexp.pro        2021-01-04 11:45:40.958637924 +0100
***************
*** 2,8 ****
  int re_multiline(regprog_T *prog);
  char_u *skip_regexp(char_u *startp, int delim, int magic);
  char_u *skip_regexp_err(char_u *startp, int delim, int magic);
! char_u *skip_regexp_ex(char_u *startp, int dirc, int magic, char_u **newp, 
int *dropped);
  reg_extmatch_T *ref_extmatch(reg_extmatch_T *em);
  void unref_extmatch(reg_extmatch_T *em);
  char_u *regtilde(char_u *source, int magic);
--- 2,8 ----
  int re_multiline(regprog_T *prog);
  char_u *skip_regexp(char_u *startp, int delim, int magic);
  char_u *skip_regexp_err(char_u *startp, int delim, int magic);
! char_u *skip_regexp_ex(char_u *startp, int dirc, int magic, char_u **newp, 
int *dropped, magic_T *magic_val);
  reg_extmatch_T *ref_extmatch(reg_extmatch_T *em);
  void unref_extmatch(reg_extmatch_T *em);
  char_u *regtilde(char_u *source, int magic);
*** ../vim-8.2.2294/src/regexp.c        2021-01-02 17:43:44.021175836 +0100
--- src/regexp.c        2021-01-04 11:46:30.206462289 +0100
***************
*** 304,314 ****
  static int    had_eol;        // TRUE when EOL found by vim_regcomp()
  #endif
  
! static int    reg_magic;      // magicness of the pattern:
! #define MAGIC_NONE    1       // "\V" very unmagic
! #define MAGIC_OFF     2       // "\M" or 'magic' off
! #define MAGIC_ON      3       // "\m" or 'magic'
! #define MAGIC_ALL     4       // "\v" very magic
  
  static int    reg_string;     // matching with a string instead of a buffer
                                // line
--- 304,310 ----
  static int    had_eol;        // TRUE when EOL found by vim_regcomp()
  #endif
  
! static magic_T        reg_magic;      // magicness of the pattern
  
  static int    reg_string;     // matching with a string instead of a buffer
                                // line
***************
*** 548,554 ****
      int               delim,
      int               magic)
  {
!     return skip_regexp_ex(startp, delim, magic, NULL, NULL);
  }
  
  /*
--- 544,550 ----
      int               delim,
      int               magic)
  {
!     return skip_regexp_ex(startp, delim, magic, NULL, NULL, NULL);
  }
  
  /*
***************
*** 577,582 ****
--- 573,579 ----
   * expression and change "\?" to "?".  If "*newp" is not NULL the expression
   * is changed in-place.
   * If a "\?" is changed to "?" then "dropped" is incremented, unless NULL.
+  * If "magic_val" is not NULL, returns the effective magicness of the pattern
   */
      char_u *
  skip_regexp_ex(
***************
*** 584,592 ****
      int               dirc,
      int               magic,
      char_u    **newp,
!     int               *dropped)
  {
!     int               mymagic;
      char_u    *p = startp;
  
      if (magic)
--- 581,590 ----
      int               dirc,
      int               magic,
      char_u    **newp,
!     int               *dropped,
!     magic_T   *magic_val)
  {
!     magic_T   mymagic;
      char_u    *p = startp;
  
      if (magic)
***************
*** 632,637 ****
--- 630,637 ----
                mymagic = MAGIC_NONE;
        }
      }
+     if (magic_val != NULL)
+       *magic_val = mymagic;
      return p;
  }
  
*** ../vim-8.2.2294/src/search.c        2021-01-02 18:31:10.887220293 +0100
--- src/search.c        2021-01-04 11:31:55.817633424 +0100
***************
*** 1342,1348 ****
             */
            ps = strcopy;
            p = skip_regexp_ex(pat, search_delim, magic_isset(),
!                                                              &strcopy, NULL);
            if (strcopy != ps)
            {
                // made a copy of "pat" to change "\?" to "?"
--- 1342,1348 ----
             */
            ps = strcopy;
            p = skip_regexp_ex(pat, search_delim, magic_isset(),
!                                                       &strcopy, NULL, NULL);
            if (strcopy != ps)
            {
                // made a copy of "pat" to change "\?" to "?"
*** ../vim-8.2.2294/src/structs.h       2021-01-02 15:41:00.189079039 +0100
--- src/structs.h       2021-01-04 11:45:04.562767852 +0100
***************
*** 4321,4328 ****
  // with iconv() to be able to allocate a buffer.
  #define ICONV_MULT 8
  
  typedef enum {
!     MAGIC_NOT_SET,    // p_magic not overruled
!     MAGIC_ON,         // magic on inside regexp
!     MAGIC_OFF         // magic off inside regexp
  } magic_T;
--- 4321,4340 ----
  // with iconv() to be able to allocate a buffer.
  #define ICONV_MULT 8
  
+ // Used for "magic_overruled".
  typedef enum {
!     OPTION_MAGIC_NOT_SET,     // p_magic not overruled
!     OPTION_MAGIC_ON,          // magic on inside regexp
!     OPTION_MAGIC_OFF          // magic off inside regexp
! } optmagic_T;
! 
! // Magicness of a pattern, used by regexp code.
! // The order and values matter:
! //  magic <= MAGIC_OFF includes MAGIC_NONE
! //  magic >= MAGIC_ON  includes MAGIC_ALL
! typedef enum {
!     MAGIC_NONE = 1,           // "\V" very unmagic
!     MAGIC_OFF = 2,            // "\M" or 'magic' off
!     MAGIC_ON = 3,             // "\m" or 'magic'
!     MAGIC_ALL = 4             // "\v" very magic
  } magic_T;
*** ../vim-8.2.2294/src/vim9compile.c   2021-01-03 21:53:28.279020545 +0100
--- src/vim9compile.c   2021-01-04 11:31:55.817633424 +0100
***************
*** 7048,7054 ****
        // Push v:exception, push {expr} and MATCH
        generate_instr_type(cctx, ISN_PUSHEXC, &t_string);
  
!       end = skip_regexp_ex(p + 1, *p, TRUE, &tofree, &dropped);
        if (*end != *p)
        {
            semsg(_(e_separator_mismatch_str), p);
--- 7048,7054 ----
        // Push v:exception, push {expr} and MATCH
        generate_instr_type(cctx, ISN_PUSHEXC, &t_string);
  
!       end = skip_regexp_ex(p + 1, *p, TRUE, &tofree, &dropped, NULL);
        if (*end != *p)
        {
            semsg(_(e_separator_mismatch_str), p);
***************
*** 7372,7378 ****
      {
        int delim = *eap->arg;
  
!       p = skip_regexp_ex(eap->arg + 1, delim, TRUE, NULL, NULL);
        if (*p == delim)
        {
            eap->arg = p + 1;
--- 7372,7378 ----
      {
        int delim = *eap->arg;
  
!       p = skip_regexp_ex(eap->arg + 1, delim, TRUE, NULL, NULL, NULL);
        if (*p == delim)
        {
            eap->arg = p + 1;
*** ../vim-8.2.2294/src/testdir/dumps/Test_incsearch_sub_01.dump        
2021-01-04 12:41:37.447957673 +0100
--- src/testdir/dumps/Test_incsearch_sub_01.dump        2021-01-04 
11:31:55.817633424 +0100
***************
*** 0 ****
--- 1,9 ----
+ |f+0&#ffffff0|o@1| |1| @64
+ |f|o@1| |2| @64
+ |f|o@1| |3| @64
+ |f|o@1| |4| @64
+ |a|b|c|||d|e|f| @62
+ |~+0#4040ff13&| @68
+ |~| @68
+ |~| @68
+ |:+0#0000000&|%|s|/|\|v|a|b|c||> @59
*** ../vim-8.2.2294/src/testdir/dumps/Test_incsearch_sub_02.dump        
2021-01-04 12:41:37.451957653 +0100
--- src/testdir/dumps/Test_incsearch_sub_02.dump        2021-01-04 
11:31:55.817633424 +0100
***************
*** 0 ****
--- 1,9 ----
+ |f+0&#ffffff0|o@1| |1| @64
+ |f|o@1| |2| @64
+ |f|o@1| |3| @64
+ |f|o@1| |4| @64
+ |a|b|c|||d|e|f| @62
+ |~+0#4040ff13&| @68
+ |~| @68
+ |~| @68
+ |:+0#0000000&|1|,|5|s|/|\|v||> @60
*** ../vim-8.2.2294/src/testdir/test_search.vim 2020-11-25 17:41:16.453206458 
+0100
--- src/testdir/test_search.vim 2021-01-04 11:31:55.817633424 +0100
***************
*** 1808,1811 ****
--- 1808,1840 ----
    bw
  endfunc
  
+ func Test_incsearch_substitute_dump2()
+   CheckOption incsearch
+   CheckScreendump
+ 
+   call writefile([
+       \ 'set incsearch hlsearch scrolloff=0',
+       \ 'for n in range(1, 4)',
+       \ '  call setline(n, "foo " . n)',
+       \ 'endfor',
+       \ 'call setline(5, "abc|def")',
+       \ '3',
+       \ ], 'Xis_subst_script2')
+   let buf = RunVimInTerminal('-S Xis_subst_script2', {'rows': 9, 'cols': 70})
+ 
+   call term_sendkeys(buf, ':%s/\vabc|')
+   sleep 100m
+   call VerifyScreenDump(buf, 'Test_incsearch_sub_01', {})
+   call term_sendkeys(buf, "\<Esc>")
+ 
+   " The following should not be highlighted
+   call term_sendkeys(buf, ':1,5s/\v|')
+   sleep 100m
+   call VerifyScreenDump(buf, 'Test_incsearch_sub_02', {})
+ 
+ 
+   call StopVimInTerminal(buf)
+   call delete('Xis_subst_script2')
+ endfunc
+ 
  " vim: shiftwidth=2 sts=2 expandtab
*** ../vim-8.2.2294/src/version.c       2021-01-04 10:47:21.698153964 +0100
--- src/version.c       2021-01-04 11:33:53.941195043 +0100
***************
*** 752,753 ****
--- 752,755 ----
  {   /* Add new patch number below this line */
+ /**/
+     2295,
  /**/

-- 
>From "know your smileys":
 :-F    Bucktoothed vampire with one tooth missing

 /// Bram Moolenaar -- [email protected] -- 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 [email protected].
To view this discussion on the web visit 
https://groups.google.com/d/msgid/vim_dev/202101041142.104BgjmT2411208%40masaka.moolenaar.net.

Raspunde prin e-mail lui