mirror of
https://github.com/neovim/neovim.git
synced 2025-02-25 18:55:25 -06:00
Merge pull request #21279 from zeertzjq/vim-8.2.2182
vim-patch:8.2.{2182,2295,3265,3292}: search fixes
This commit is contained in:
commit
a0dd663c2d
@ -29,7 +29,7 @@
|
||||
#include "nvim/memline_defs.h"
|
||||
#include "nvim/memory.h"
|
||||
#include "nvim/message.h"
|
||||
#include "nvim/option_defs.h"
|
||||
#include "nvim/option.h"
|
||||
#include "nvim/os/input.h"
|
||||
#include "nvim/path.h"
|
||||
#include "nvim/pos.h"
|
||||
@ -380,7 +380,7 @@ static void arglist_del_files(garray_T *alist_ga)
|
||||
if (p == NULL) {
|
||||
break;
|
||||
}
|
||||
regmatch.regprog = vim_regcomp(p, p_magic ? RE_MAGIC : 0);
|
||||
regmatch.regprog = vim_regcomp(p, magic_isset() ? RE_MAGIC : 0);
|
||||
if (regmatch.regprog == NULL) {
|
||||
xfree(p);
|
||||
break;
|
||||
|
@ -2250,7 +2250,7 @@ int buflist_findpat(const char *pattern, const char *pattern_end, bool unlisted,
|
||||
}
|
||||
|
||||
regmatch_T regmatch;
|
||||
regmatch.regprog = vim_regcomp(p, p_magic ? RE_MAGIC : 0);
|
||||
regmatch.regprog = vim_regcomp(p, magic_isset() ? RE_MAGIC : 0);
|
||||
if (regmatch.regprog == NULL) {
|
||||
xfree(pat);
|
||||
return -1;
|
||||
|
@ -1505,7 +1505,7 @@ static const char *set_context_by_cmdname(const char *cmd, cmdidx_T cmdidx, cons
|
||||
arg = (const char *)skipwhite(skiptowhite(arg));
|
||||
if (*arg != NUL) {
|
||||
xp->xp_context = EXPAND_NOTHING;
|
||||
arg = (const char *)skip_regexp((char *)arg + 1, (uint8_t)(*arg), p_magic);
|
||||
arg = (const char *)skip_regexp((char *)arg + 1, (uint8_t)(*arg), magic_isset());
|
||||
}
|
||||
}
|
||||
return (const char *)find_nextcmd(arg);
|
||||
@ -1544,7 +1544,7 @@ static const char *set_context_by_cmdname(const char *cmd, cmdidx_T cmdidx, cons
|
||||
if (delim) {
|
||||
// Skip "from" part.
|
||||
arg++;
|
||||
arg = (const char *)skip_regexp((char *)arg, delim, p_magic);
|
||||
arg = (const char *)skip_regexp((char *)arg, delim, magic_isset());
|
||||
}
|
||||
// Skip "to" part.
|
||||
while (arg[0] != NUL && (uint8_t)arg[0] != delim) {
|
||||
@ -2458,7 +2458,7 @@ static int ExpandFromContext(expand_T *xp, char *pat, int *num_file, char ***fil
|
||||
return nlua_expand_pat(xp, pat, num_file, file);
|
||||
}
|
||||
|
||||
regmatch.regprog = vim_regcomp(pat, p_magic ? RE_MAGIC : 0);
|
||||
regmatch.regprog = vim_regcomp(pat, magic_isset() ? RE_MAGIC : 0);
|
||||
if (regmatch.regprog == NULL) {
|
||||
return FAIL;
|
||||
}
|
||||
|
@ -3131,7 +3131,7 @@ static bool sub_joining_lines(exarg_T *eap, char *pat, const char *sub, const ch
|
||||
|
||||
if (save) {
|
||||
if ((cmdmod.cmod_flags & CMOD_KEEPPATTERNS) == 0) {
|
||||
save_re_pat(RE_SUBST, pat, p_magic);
|
||||
save_re_pat(RE_SUBST, pat, magic_isset());
|
||||
}
|
||||
// put pattern in history
|
||||
add_to_history(HIST_SEARCH, pat, true, NUL);
|
||||
@ -3356,7 +3356,7 @@ static int do_sub(exarg_T *eap, proftime_T timeout, long cmdpreview_ns, handle_T
|
||||
which_pat = RE_LAST; // use last used regexp
|
||||
delimiter = (char_u)(*cmd++); // remember delimiter character
|
||||
pat = cmd; // remember start of search pat
|
||||
cmd = skip_regexp_ex(cmd, delimiter, p_magic, &eap->arg, NULL);
|
||||
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
|
||||
has_second_delim = true;
|
||||
@ -3472,7 +3472,7 @@ static int do_sub(exarg_T *eap, proftime_T timeout, long cmdpreview_ns, handle_T
|
||||
sub = xstrdup(sub);
|
||||
sub_copy = sub;
|
||||
} else {
|
||||
char *newsub = regtilde(sub, p_magic, cmdpreview);
|
||||
char *newsub = regtilde(sub, magic_isset(), cmdpreview);
|
||||
if (newsub != sub) {
|
||||
// newsub was allocated, free it later.
|
||||
sub_copy = newsub;
|
||||
@ -3895,7 +3895,8 @@ static int do_sub(exarg_T *eap, proftime_T timeout, long cmdpreview_ns, handle_T
|
||||
sublen = vim_regsub_multi(®match,
|
||||
sub_firstlnum - regmatch.startpos[0].lnum,
|
||||
(char_u *)sub, (char_u *)sub_firstline, 0,
|
||||
REGSUB_BACKSLASH | (p_magic ? REGSUB_MAGIC : 0));
|
||||
REGSUB_BACKSLASH
|
||||
| (magic_isset() ? REGSUB_MAGIC : 0));
|
||||
textlock--;
|
||||
|
||||
// If getting the substitute string caused an error, don't do
|
||||
@ -3937,7 +3938,8 @@ static int do_sub(exarg_T *eap, proftime_T timeout, long cmdpreview_ns, handle_T
|
||||
(void)vim_regsub_multi(®match,
|
||||
sub_firstlnum - regmatch.startpos[0].lnum,
|
||||
(char_u *)sub, (char_u *)new_end, sublen,
|
||||
REGSUB_COPY | REGSUB_BACKSLASH | (p_magic ? REGSUB_MAGIC : 0));
|
||||
REGSUB_COPY | REGSUB_BACKSLASH
|
||||
| (magic_isset() ? REGSUB_MAGIC : 0));
|
||||
textlock--;
|
||||
sub_nsubs++;
|
||||
did_sub = true;
|
||||
@ -4389,7 +4391,7 @@ void ex_global(exarg_T *eap)
|
||||
delim = *cmd; // get the delimiter
|
||||
cmd++; // skip delimiter if there is one
|
||||
pat = cmd; // remember start of pattern
|
||||
cmd = skip_regexp_ex(cmd, delim, p_magic, &eap->arg, NULL);
|
||||
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
|
||||
}
|
||||
|
@ -3355,7 +3355,7 @@ static linenr_T get_address(exarg_T *eap, char **ptr, cmd_addr_T addr_type, int
|
||||
goto error;
|
||||
}
|
||||
if (skip) { // skip "/pat/"
|
||||
cmd = skip_regexp(cmd, c, p_magic);
|
||||
cmd = skip_regexp(cmd, c, magic_isset());
|
||||
if (*cmd == c) {
|
||||
cmd++;
|
||||
}
|
||||
@ -5828,21 +5828,21 @@ void ex_may_print(exarg_T *eap)
|
||||
/// ":smagic" and ":snomagic".
|
||||
static void ex_submagic(exarg_T *eap)
|
||||
{
|
||||
int magic_save = p_magic;
|
||||
const optmagic_T saved = magic_overruled;
|
||||
|
||||
p_magic = (eap->cmdidx == CMD_smagic);
|
||||
magic_overruled = eap->cmdidx == CMD_smagic ? OPTION_MAGIC_ON : OPTION_MAGIC_OFF;
|
||||
ex_substitute(eap);
|
||||
p_magic = magic_save;
|
||||
magic_overruled = saved;
|
||||
}
|
||||
|
||||
/// ":smagic" and ":snomagic" preview callback.
|
||||
static int ex_submagic_preview(exarg_T *eap, long cmdpreview_ns, handle_T cmdpreview_bufnr)
|
||||
{
|
||||
int magic_save = p_magic;
|
||||
const optmagic_T saved = magic_overruled;
|
||||
|
||||
p_magic = (eap->cmdidx == CMD_smagic);
|
||||
magic_overruled = eap->cmdidx == CMD_smagic ? OPTION_MAGIC_ON : OPTION_MAGIC_OFF;
|
||||
int retv = ex_substitute_preview(eap, cmdpreview_ns, cmdpreview_bufnr);
|
||||
p_magic = magic_save;
|
||||
magic_overruled = saved;
|
||||
|
||||
return retv;
|
||||
}
|
||||
@ -6503,7 +6503,7 @@ static void ex_findpat(exarg_T *eap)
|
||||
if (*eap->arg == '/') { // Match regexp, not just whole words
|
||||
whole = false;
|
||||
eap->arg++;
|
||||
char *p = skip_regexp(eap->arg, '/', p_magic);
|
||||
char *p = skip_regexp(eap->arg, '/', magic_isset());
|
||||
if (*p) {
|
||||
*p++ = NUL;
|
||||
p = skipwhite(p);
|
||||
|
@ -98,7 +98,7 @@ typedef struct {
|
||||
pos_T match_end;
|
||||
bool did_incsearch;
|
||||
bool incsearch_postponed;
|
||||
int magic_save;
|
||||
optmagic_T magic_overruled_save;
|
||||
} incsearch_state_T;
|
||||
|
||||
typedef struct command_line_state {
|
||||
@ -211,7 +211,7 @@ static void init_incsearch_state(incsearch_state_T *s)
|
||||
s->match_start = curwin->w_cursor;
|
||||
s->did_incsearch = false;
|
||||
s->incsearch_postponed = false;
|
||||
s->magic_save = p_magic;
|
||||
s->magic_overruled_save = magic_overruled;
|
||||
clearpos(&s->match_end);
|
||||
s->save_cursor = curwin->w_cursor; // may be restored later
|
||||
s->search_start = curwin->w_cursor;
|
||||
@ -234,6 +234,7 @@ static bool do_incsearch_highlighting(int firstc, int *search_delim, incsearch_s
|
||||
pos_T save_cursor;
|
||||
bool use_last_pat;
|
||||
bool retval = false;
|
||||
magic_T magic = 0;
|
||||
|
||||
*skiplen = 0;
|
||||
*patlen = ccline.cmdlen;
|
||||
@ -281,9 +282,9 @@ static bool do_incsearch_highlighting(int firstc, int *search_delim, incsearch_s
|
||||
|| strncmp(cmd, "snomagic", (size_t)MAX(p - cmd, 3)) == 0
|
||||
|| strncmp(cmd, "vglobal", (size_t)(p - cmd)) == 0) {
|
||||
if (*cmd == 's' && cmd[1] == 'm') {
|
||||
p_magic = true;
|
||||
magic_overruled = OPTION_MAGIC_ON;
|
||||
} else if (*cmd == 's' && cmd[1] == 'n') {
|
||||
p_magic = false;
|
||||
magic_overruled = OPTION_MAGIC_OFF;
|
||||
}
|
||||
} else if (strncmp(cmd, "sort", (size_t)MAX(p - cmd, 3)) == 0) {
|
||||
// skip over ! and flags
|
||||
@ -318,7 +319,7 @@ static bool do_incsearch_highlighting(int firstc, int *search_delim, incsearch_s
|
||||
p = skipwhite(p);
|
||||
delim = (delim_optional && vim_isIDc(*p)) ? ' ' : *p++;
|
||||
*search_delim = delim;
|
||||
end = skip_regexp(p, delim, p_magic);
|
||||
end = skip_regexp_ex(p, delim, magic_isset(), NULL, NULL, &magic);
|
||||
|
||||
use_last_pat = end == p && *end == delim;
|
||||
if (end == p && !use_last_pat) {
|
||||
@ -328,10 +329,8 @@ static bool do_incsearch_highlighting(int firstc, int *search_delim, incsearch_s
|
||||
// Don't do 'hlsearch' highlighting if the pattern matches everything.
|
||||
if (!use_last_pat) {
|
||||
char c = *end;
|
||||
int empty;
|
||||
|
||||
*end = NUL;
|
||||
empty = empty_pattern(p);
|
||||
bool empty = empty_pattern_magic(p, strlen(p), magic);
|
||||
*end = c;
|
||||
if (empty) {
|
||||
goto theend;
|
||||
@ -486,13 +485,13 @@ static void may_do_incsearch_highlighting(int firstc, long count, incsearch_stat
|
||||
} else {
|
||||
end_pos = curwin->w_cursor; // shutup gcc 4
|
||||
}
|
||||
//
|
||||
|
||||
// Disable 'hlsearch' highlighting if the pattern matches
|
||||
// everything. Avoids a flash when typing "foo\|".
|
||||
if (!use_last_pat) {
|
||||
next_char = ccline.cmdbuff[skiplen + patlen];
|
||||
ccline.cmdbuff[skiplen + patlen] = NUL;
|
||||
if (empty_pattern(ccline.cmdbuff) && !no_hlsearch) {
|
||||
if (empty_pattern(ccline.cmdbuff + skiplen, search_delim) && !no_hlsearch) {
|
||||
redraw_all_later(UPD_SOME_VALID);
|
||||
set_no_hlsearch(true);
|
||||
}
|
||||
@ -556,7 +555,7 @@ static int may_add_char_to_search(int firstc, int *c, incsearch_state_T *s)
|
||||
*c = mb_tolower(*c);
|
||||
}
|
||||
if (*c == search_delim
|
||||
|| vim_strchr((p_magic ? "\\~^$.*[" : "\\^$"), *c) != NULL) {
|
||||
|| vim_strchr((magic_isset() ? "\\~^$.*[" : "\\^$"), *c) != NULL) {
|
||||
// put a backslash before special characters
|
||||
stuffcharReadbuff(*c);
|
||||
*c = '\\';
|
||||
@ -588,7 +587,7 @@ static void finish_incsearch_highlighting(int gotesc, incsearch_state_T *s, bool
|
||||
search_first_line = 0;
|
||||
search_last_line = MAXLNUM;
|
||||
|
||||
p_magic = s->magic_save;
|
||||
magic_overruled = s->magic_overruled_save;
|
||||
|
||||
validate_cursor(); // needed for TAB
|
||||
redraw_all_later(UPD_SOME_VALID);
|
||||
@ -2031,16 +2030,35 @@ static int command_line_not_changed(CommandLineState *s)
|
||||
|
||||
/// Guess that the pattern matches everything. Only finds specific cases, such
|
||||
/// as a trailing \|, which can happen while typing a pattern.
|
||||
static int empty_pattern(char *p)
|
||||
static bool empty_pattern(char *p, int delim)
|
||||
{
|
||||
size_t n = strlen(p);
|
||||
magic_T magic_val = MAGIC_ON;
|
||||
|
||||
// remove trailing \v and the like
|
||||
while (n >= 2 && p[n - 2] == '\\'
|
||||
&& vim_strchr("mMvVcCZ", p[n - 1]) != NULL) {
|
||||
n -= 2;
|
||||
if (n > 0) {
|
||||
(void)skip_regexp_ex(p, delim, magic_isset(), NULL, NULL, &magic_val);
|
||||
} else {
|
||||
return true;
|
||||
}
|
||||
return n == 0 || (n >= 2 && p[n - 2] == '\\' && p[n - 1] == '|');
|
||||
|
||||
return empty_pattern_magic(p, n, magic_val);
|
||||
}
|
||||
|
||||
static bool empty_pattern_magic(char *p, size_t len, magic_T magic_val)
|
||||
{
|
||||
// remove trailing \v and the like
|
||||
while (len >= 2 && p[len - 2] == '\\'
|
||||
&& vim_strchr("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)));
|
||||
}
|
||||
|
||||
handle_T cmdpreview_get_bufnr(void)
|
||||
|
@ -1087,6 +1087,10 @@ EXTERN char windowsVersion[20] INIT(= { 0 });
|
||||
|
||||
EXTERN int exit_need_delay INIT(= 0);
|
||||
|
||||
/// 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);
|
||||
|
||||
/// Skip win_fix_cursor() call for 'splitkeep' when cmdwin is closed.
|
||||
EXTERN bool skip_win_fix_cursor INIT(= false);
|
||||
/// Skip win_fix_scroll() call for 'splitkeep' when closing tab page.
|
||||
|
@ -1336,7 +1336,7 @@ static void ins_compl_dictionaries(char_u *dict_start, char_u *pat, int flags, i
|
||||
xfree(pat_esc);
|
||||
xfree(ptr);
|
||||
} else {
|
||||
regmatch.regprog = vim_regcomp((char *)pat, p_magic ? RE_MAGIC : 0);
|
||||
regmatch.regprog = vim_regcomp((char *)pat, magic_isset() ? RE_MAGIC : 0);
|
||||
if (regmatch.regprog == NULL) {
|
||||
goto theend;
|
||||
}
|
||||
@ -4430,7 +4430,7 @@ static unsigned quote_meta(char_u *dest, char_u *src, int len)
|
||||
}
|
||||
FALLTHROUGH;
|
||||
case '~':
|
||||
if (!p_magic) { // quote these only if magic is set
|
||||
if (!magic_isset()) { // quote these only if magic is set
|
||||
break;
|
||||
}
|
||||
FALLTHROUGH;
|
||||
|
@ -3507,9 +3507,9 @@ static void nv_ident(cmdarg_T *cap)
|
||||
xfree(p);
|
||||
} else {
|
||||
if (cmdchar == '*') {
|
||||
aux_ptr = (p_magic ? "/.*~[^$\\" : "/^$\\");
|
||||
aux_ptr = (magic_isset() ? "/.*~[^$\\" : "/^$\\");
|
||||
} else if (cmdchar == '#') {
|
||||
aux_ptr = (p_magic ? "/?.*~[^$\\" : "/?^$\\");
|
||||
aux_ptr = (magic_isset() ? "/?.*~[^$\\" : "/?^$\\");
|
||||
} else if (tag_cmd) {
|
||||
if (curbuf->b_help) {
|
||||
// ":help" handles unescaped argument
|
||||
|
@ -5147,6 +5147,20 @@ int fill_culopt_flags(char *val, win_T *wp)
|
||||
return OK;
|
||||
}
|
||||
|
||||
/// Get the value of 'magic' taking "magic_overruled" into account.
|
||||
bool magic_isset(void)
|
||||
{
|
||||
switch (magic_overruled) {
|
||||
case OPTION_MAGIC_ON:
|
||||
return true;
|
||||
case OPTION_MAGIC_OFF:
|
||||
return false;
|
||||
case OPTION_MAGIC_NOT_SET:
|
||||
break;
|
||||
}
|
||||
return p_magic;
|
||||
}
|
||||
|
||||
/// Set the callback function value for an option that accepts a function name,
|
||||
/// lambda, et al. (e.g. 'operatorfunc', 'tagfunc', etc.)
|
||||
/// @return OK if the option is successfully set to a function, otherwise FAIL
|
||||
|
@ -316,11 +316,7 @@ static int re_has_z; ///< \z item detected
|
||||
static unsigned regflags; ///< RF_ flags for prog
|
||||
static int had_eol; ///< true when EOL found by vim_regcomp()
|
||||
|
||||
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 magic_T reg_magic; ///< magicness of the pattern
|
||||
|
||||
static int reg_string; // matching with a string instead of a buffer
|
||||
// line
|
||||
@ -485,7 +481,7 @@ static char_u *skip_anyof(char *p)
|
||||
/// Skip strings inside [ and ].
|
||||
char *skip_regexp(char *startp, int delim, int magic)
|
||||
{
|
||||
return skip_regexp_ex(startp, delim, magic, NULL, NULL);
|
||||
return skip_regexp_ex(startp, delim, magic, NULL, NULL, NULL);
|
||||
}
|
||||
|
||||
/// Call skip_regexp() and when the delimiter does not match give an error and
|
||||
@ -506,9 +502,11 @@ char *skip_regexp_err(char *startp, int delim, int magic)
|
||||
/// 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.
|
||||
char *skip_regexp_ex(char *startp, int dirc, int magic, char **newp, int *dropped)
|
||||
/// If "magic_val" is not NULL, returns the effective magicness of the pattern
|
||||
char *skip_regexp_ex(char *startp, int dirc, int magic, char **newp, int *dropped,
|
||||
magic_T *magic_val)
|
||||
{
|
||||
int mymagic;
|
||||
magic_T mymagic;
|
||||
char *p = startp;
|
||||
|
||||
if (magic) {
|
||||
@ -549,6 +547,9 @@ char *skip_regexp_ex(char *startp, int dirc, int magic, char **newp, int *droppe
|
||||
}
|
||||
}
|
||||
}
|
||||
if (magic_val != NULL) {
|
||||
*magic_val = mymagic;
|
||||
}
|
||||
return p;
|
||||
}
|
||||
|
||||
|
@ -15,6 +15,24 @@
|
||||
#include "nvim/pos.h"
|
||||
#include "nvim/types.h"
|
||||
|
||||
/// 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;
|
||||
|
||||
// The number of sub-matches is limited to 10.
|
||||
// The first one (index 0) is the whole match, referenced with "\0".
|
||||
// The second one (index 1) is the first sub-match, referenced with "\1".
|
||||
|
@ -138,7 +138,7 @@ int search_regcomp(char_u *pat, int pat_save, int pat_use, int options, regmmatc
|
||||
int i;
|
||||
|
||||
rc_did_emsg = false;
|
||||
magic = p_magic;
|
||||
magic = magic_isset();
|
||||
|
||||
// If no pattern given, use a previously defined pattern.
|
||||
if (pat == NULL || *pat == NUL) {
|
||||
@ -373,6 +373,10 @@ bool pat_has_uppercase(char_u *pat)
|
||||
FUNC_ATTR_NONNULL_ALL
|
||||
{
|
||||
char_u *p = pat;
|
||||
magic_T magic_val = MAGIC_ON;
|
||||
|
||||
// get the magicness of the pattern
|
||||
(void)skip_regexp_ex((char *)pat, NUL, magic_isset(), NULL, NULL, &magic_val);
|
||||
|
||||
while (*p != NUL) {
|
||||
const int l = utfc_ptr2len((char *)p);
|
||||
@ -382,7 +386,7 @@ bool pat_has_uppercase(char_u *pat)
|
||||
return true;
|
||||
}
|
||||
p += l;
|
||||
} else if (*p == '\\') {
|
||||
} else if (*p == '\\' && magic_val <= MAGIC_ON) {
|
||||
if (p[1] == '_' && p[2] != NUL) { // skip "\_X"
|
||||
p += 3;
|
||||
} else if (p[1] == '%' && p[2] != NUL) { // skip "\%X"
|
||||
@ -392,6 +396,12 @@ bool pat_has_uppercase(char_u *pat)
|
||||
} else {
|
||||
p += 1;
|
||||
}
|
||||
} else if ((*p == '%' || *p == '_') && magic_val == MAGIC_ALL) {
|
||||
if (p[1] != NUL) { // skip "_X" and %X
|
||||
p += 2;
|
||||
} else {
|
||||
p++;
|
||||
}
|
||||
} else if (mb_isupper(*p)) {
|
||||
return true;
|
||||
} else {
|
||||
@ -1089,7 +1099,7 @@ int do_search(oparg_T *oap, int dirc, int search_delim, char *pat, long count, i
|
||||
// Find end of regular expression.
|
||||
// If there is a matching '/' or '?', toss it.
|
||||
ps = (char_u *)strcopy;
|
||||
p = skip_regexp_ex(pat, search_delim, p_magic, &strcopy, NULL);
|
||||
p = skip_regexp_ex(pat, search_delim, magic_isset(), &strcopy, NULL, NULL);
|
||||
if (strcopy != (char *)ps) {
|
||||
// made a copy of "pat" to change "\?" to "?"
|
||||
searchcmdlen += (int)(strlen(pat) - strlen(strcopy));
|
||||
@ -3468,7 +3478,7 @@ void find_pattern_in_path(char *ptr, Direction dir, size_t len, bool whole, bool
|
||||
snprintf((char *)pat, patlen, whole ? "\\<%.*s\\>" : "%.*s", (int)len, ptr);
|
||||
// ignore case according to p_ic, p_scs and pat
|
||||
regmatch.rm_ic = ignorecase(pat);
|
||||
regmatch.regprog = vim_regcomp((char *)pat, p_magic ? RE_MAGIC : 0);
|
||||
regmatch.regprog = vim_regcomp((char *)pat, magic_isset() ? RE_MAGIC : 0);
|
||||
xfree(pat);
|
||||
if (regmatch.regprog == NULL) {
|
||||
goto fpip_end;
|
||||
@ -3476,7 +3486,7 @@ void find_pattern_in_path(char *ptr, Direction dir, size_t len, bool whole, bool
|
||||
}
|
||||
char *inc_opt = (*curbuf->b_p_inc == NUL) ? p_inc : curbuf->b_p_inc;
|
||||
if (*inc_opt != NUL) {
|
||||
incl_regmatch.regprog = vim_regcomp(inc_opt, p_magic ? RE_MAGIC : 0);
|
||||
incl_regmatch.regprog = vim_regcomp(inc_opt, magic_isset() ? RE_MAGIC : 0);
|
||||
if (incl_regmatch.regprog == NULL) {
|
||||
goto fpip_end;
|
||||
}
|
||||
@ -3485,7 +3495,7 @@ void find_pattern_in_path(char *ptr, Direction dir, size_t len, bool whole, bool
|
||||
if (type == FIND_DEFINE && (*curbuf->b_p_def != NUL || *p_def != NUL)) {
|
||||
def_regmatch.regprog = vim_regcomp(*curbuf->b_p_def == NUL
|
||||
? p_def : curbuf->b_p_def,
|
||||
p_magic ? RE_MAGIC : 0);
|
||||
magic_isset() ? RE_MAGIC : 0);
|
||||
if (def_regmatch.regprog == NULL) {
|
||||
goto fpip_end;
|
||||
}
|
||||
|
@ -1252,7 +1252,7 @@ static void shada_read(ShaDaReadDef *const sd_reader, const int flags)
|
||||
// string is close to useless: you can only use it with :& or :~ and
|
||||
// that’s all because s//~ is not available until the first call to
|
||||
// regtilde. Vim was not calling this for some reason.
|
||||
(void)regtilde(cur_entry.data.sub_string.sub, p_magic, false);
|
||||
(void)regtilde(cur_entry.data.sub_string.sub, magic_isset(), false);
|
||||
// Do not free shada entry: its allocated memory was saved above.
|
||||
break;
|
||||
case kSDItemHistoryEntry:
|
||||
|
@ -1200,7 +1200,8 @@ static void prepare_pats(pat_T *pats, int has_re)
|
||||
pats->headlen = 0;
|
||||
} else {
|
||||
for (pats->headlen = 0; pats->head[pats->headlen] != NUL; pats->headlen++) {
|
||||
if (vim_strchr((p_magic ? ".[~*\\$" : "\\$"), pats->head[pats->headlen]) != NULL) {
|
||||
if (vim_strchr(magic_isset() ? ".[~*\\$" : "\\$",
|
||||
pats->head[pats->headlen]) != NULL) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
@ -1211,7 +1212,7 @@ static void prepare_pats(pat_T *pats, int has_re)
|
||||
}
|
||||
|
||||
if (has_re) {
|
||||
pats->regmatch.regprog = vim_regcomp(pats->pat, p_magic ? RE_MAGIC : 0);
|
||||
pats->regmatch.regprog = vim_regcomp(pats->pat, magic_isset() ? RE_MAGIC : 0);
|
||||
} else {
|
||||
pats->regmatch.regprog = NULL;
|
||||
}
|
||||
@ -2812,7 +2813,6 @@ static char_u *tag_full_fname(tagptrs_T *tagp)
|
||||
/// @return OK for success, NOTAGFILE when file not found, FAIL otherwise.
|
||||
static int jumpto_tag(const char_u *lbuf_arg, int forceit, int keep_help)
|
||||
{
|
||||
int save_magic;
|
||||
bool save_p_ws;
|
||||
int save_p_scs, save_p_ic;
|
||||
linenr_T save_lnum;
|
||||
@ -2955,8 +2955,8 @@ static int jumpto_tag(const char_u *lbuf_arg, int forceit, int keep_help)
|
||||
curwin->w_set_curswant = true;
|
||||
postponed_split = 0;
|
||||
|
||||
save_magic = p_magic;
|
||||
p_magic = false; // always execute with 'nomagic'
|
||||
const optmagic_T save_magic_overruled = magic_overruled;
|
||||
magic_overruled = OPTION_MAGIC_OFF; // always execute with 'nomagic'
|
||||
// Save value of no_hlsearch, jumping to a tag is not a real search
|
||||
const bool save_no_hlsearch = no_hlsearch;
|
||||
|
||||
@ -3063,7 +3063,7 @@ static int jumpto_tag(const char_u *lbuf_arg, int forceit, int keep_help)
|
||||
sandbox--;
|
||||
}
|
||||
|
||||
p_magic = save_magic;
|
||||
magic_overruled = save_magic_overruled;
|
||||
// restore no_hlsearch when keeping the old search pattern
|
||||
if (search_options) {
|
||||
set_no_hlsearch(save_no_hlsearch);
|
||||
|
@ -1969,6 +1969,100 @@ func Test_incsearch_highlighting_newline()
|
||||
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
|
||||
|
||||
func Test_pattern_is_uppercase_smartcase()
|
||||
new
|
||||
let input=['abc', 'ABC', 'Abc', 'abC']
|
||||
call setline(1, input)
|
||||
call cursor(1,1)
|
||||
" default, matches firstline
|
||||
%s/abc//g
|
||||
call assert_equal(['', 'ABC', 'Abc', 'abC'],
|
||||
\ getline(1, '$'))
|
||||
|
||||
set smartcase ignorecase
|
||||
sil %d
|
||||
call setline(1, input)
|
||||
call cursor(1,1)
|
||||
" with smartcase and incsearch set, matches everything
|
||||
%s/abc//g
|
||||
call assert_equal(['', '', '', ''], getline(1, '$'))
|
||||
|
||||
sil %d
|
||||
call setline(1, input)
|
||||
call cursor(1,1)
|
||||
" with smartcase and incsearch set and found an uppercase letter,
|
||||
" match only that.
|
||||
%s/abC//g
|
||||
call assert_equal(['abc', 'ABC', 'Abc', ''],
|
||||
\ getline(1, '$'))
|
||||
|
||||
sil %d
|
||||
call setline(1, input)
|
||||
call cursor(1,1)
|
||||
exe "norm! vG$\<esc>"
|
||||
" \%V should not be detected as uppercase letter
|
||||
%s/\%Vabc//g
|
||||
call assert_equal(['', '', '', ''], getline(1, '$'))
|
||||
|
||||
call setline(1, input)
|
||||
call cursor(1,1)
|
||||
exe "norm! vG$\<esc>"
|
||||
" \v%V should not be detected as uppercase letter
|
||||
%s/\v%Vabc//g
|
||||
call assert_equal(['', '', '', ''], getline(1, '$'))
|
||||
|
||||
call setline(1, input)
|
||||
call cursor(1,1)
|
||||
exe "norm! vG$\<esc>"
|
||||
" \v%VabC should be detected as uppercase letter
|
||||
%s/\v%VabC//g
|
||||
call assert_equal(['abc', 'ABC', 'Abc', ''],
|
||||
\ getline(1, '$'))
|
||||
|
||||
call setline(1, input)
|
||||
call cursor(1,1)
|
||||
" \Vabc should match everything
|
||||
%s/\Vabc//g
|
||||
call assert_equal(['', '', '', ''], getline(1, '$'))
|
||||
|
||||
call setline(1, input + ['_abc'])
|
||||
" _ matches normally
|
||||
%s/\v_.*//g
|
||||
call assert_equal(['abc', 'ABC', 'Abc', 'abC', ''], getline(1, '$'))
|
||||
|
||||
set smartcase& ignorecase&
|
||||
bw!
|
||||
endfunc
|
||||
|
||||
func Test_no_last_search_pattern()
|
||||
CheckOption incsearch
|
||||
|
||||
|
@ -14,7 +14,7 @@ describe('search cmdline', function()
|
||||
|
||||
before_each(function()
|
||||
clear()
|
||||
command('set nohlsearch')
|
||||
command('set nohlsearch inccommand=')
|
||||
screen = Screen.new(20, 3)
|
||||
screen:attach()
|
||||
screen:set_default_attr_ids({
|
||||
@ -472,8 +472,8 @@ describe('search cmdline', function()
|
||||
funcs.winsaveview())
|
||||
end)
|
||||
|
||||
-- oldtest: Test_search_cmdline4().
|
||||
it("CTRL-G with 'incsearch' and ? goes in the right direction", function()
|
||||
-- oldtest: Test_search_cmdline4().
|
||||
screen:try_resize(40, 4)
|
||||
command('enew!')
|
||||
funcs.setline(1, {' 1 the first', ' 2 the second', ' 3 the third'})
|
||||
@ -573,8 +573,8 @@ describe('search cmdline', function()
|
||||
]])
|
||||
end)
|
||||
|
||||
-- oldtest: Test_incsearch_sort_dump().
|
||||
it('incsearch works with :sort', function()
|
||||
-- oldtest: Test_incsearch_sort_dump().
|
||||
screen:try_resize(20, 4)
|
||||
command('set incsearch hlsearch scrolloff=0')
|
||||
funcs.setline(1, {'another one 2', 'that one 3', 'the one 1'})
|
||||
@ -589,8 +589,8 @@ describe('search cmdline', function()
|
||||
feed('<esc>')
|
||||
end)
|
||||
|
||||
-- oldtest: Test_incsearch_vimgrep_dump().
|
||||
it('incsearch works with :vimgrep family', function()
|
||||
-- oldtest: Test_incsearch_vimgrep_dump().
|
||||
screen:try_resize(30, 4)
|
||||
command('set incsearch hlsearch scrolloff=0')
|
||||
funcs.setline(1, {'another one 2', 'that one 3', 'the one 1'})
|
||||
@ -640,6 +640,41 @@ describe('search cmdline', function()
|
||||
]])
|
||||
feed('<esc>')
|
||||
end)
|
||||
|
||||
-- oldtest: Test_incsearch_substitute_dump2()
|
||||
it('detects empty pattern properly vim-patch:8.2.2295', function()
|
||||
screen:try_resize(70, 6)
|
||||
exec([[
|
||||
set incsearch hlsearch scrolloff=0
|
||||
for n in range(1, 4)
|
||||
call setline(n, "foo " . n)
|
||||
endfor
|
||||
call setline(5, "abc|def")
|
||||
3
|
||||
]])
|
||||
|
||||
feed([[:%s/\vabc|]])
|
||||
screen:expect([[
|
||||
foo 1 |
|
||||
foo 2 |
|
||||
foo 3 |
|
||||
foo 4 |
|
||||
abc|def |
|
||||
:%s/\vabc|^ |
|
||||
]])
|
||||
feed('<Esc>')
|
||||
|
||||
-- The following should not be highlighted
|
||||
feed([[:1,5s/\v|]])
|
||||
screen:expect([[
|
||||
foo 1 |
|
||||
foo 2 |
|
||||
foo 3 |
|
||||
foo 4 |
|
||||
abc|def |
|
||||
:1,5s/\v|^ |
|
||||
]])
|
||||
end)
|
||||
end)
|
||||
|
||||
describe('Search highlight', function()
|
||||
|
Loading…
Reference in New Issue
Block a user