To: vim_dev@googlegroups.com Subject: Patch 8.2.2295 Fcc: outbox From: Bram Moolenaar Mime-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ------------ 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, "\") + + " 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 -- Bram@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 ///