search: make a regex with a beginning-of-word anchor work correctly
The search routine begins searching right after the cursor and behaves as if the line starts there, which means that a beginning-of-word anchor (\< or \b) will match there also when in fact the cursor is sitting in the middle of a word. To prevent finding a false match, verify that for a regex that starts with a BOW anchor the found match is actually the start of a word. This fixes https://savannah.gnu.org/bugs/?45630.master
parent
e36e829ad0
commit
cbf7e57ed0
26
src/search.c
26
src/search.c
|
@ -38,6 +38,8 @@ static bool history_changed = FALSE;
|
||||||
#ifdef HAVE_REGEX_H
|
#ifdef HAVE_REGEX_H
|
||||||
static bool regexp_compiled = FALSE;
|
static bool regexp_compiled = FALSE;
|
||||||
/* Have we compiled any regular expressions? */
|
/* Have we compiled any regular expressions? */
|
||||||
|
static bool bow_anchored = FALSE;
|
||||||
|
/* Whether a regex starts with a beginning-of-word anchor. */
|
||||||
|
|
||||||
/* Compile the given regular expression and store it in search_regexp.
|
/* Compile the given regular expression and store it in search_regexp.
|
||||||
* Return TRUE if the expression is valid, and FALSE otherwise. */
|
* Return TRUE if the expression is valid, and FALSE otherwise. */
|
||||||
|
@ -60,6 +62,10 @@ bool regexp_init(const char *regexp)
|
||||||
|
|
||||||
regexp_compiled = TRUE;
|
regexp_compiled = TRUE;
|
||||||
|
|
||||||
|
/* Remember whether the regex starts with a beginning-of-word anchor. */
|
||||||
|
bow_anchored = (strncmp(regexp, "\\<", 2) == 0 ||
|
||||||
|
strncmp(regexp, "\\b", 2) == 0);
|
||||||
|
|
||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -292,8 +298,24 @@ int findnextstr(const char *needle, bool whole_word_only, size_t *match_len,
|
||||||
if (found != NULL) {
|
if (found != NULL) {
|
||||||
#ifdef HAVE_REGEX_H
|
#ifdef HAVE_REGEX_H
|
||||||
/* When doing a regex search, compute the length of the match. */
|
/* When doing a regex search, compute the length of the match. */
|
||||||
if (ISSET(USE_REGEXP))
|
if (ISSET(USE_REGEXP)) {
|
||||||
found_len = regmatches[0].rm_eo - regmatches[0].rm_so;
|
found_len = regmatches[0].rm_eo - regmatches[0].rm_so;
|
||||||
|
|
||||||
|
/* If the regex starts with a BOW anchor, check that the found
|
||||||
|
* match actually is the start of a word. If not, continue. */
|
||||||
|
if (bow_anchored && found != fileptr->data) {
|
||||||
|
size_t before = move_mbleft(fileptr->data, found - fileptr->data);
|
||||||
|
|
||||||
|
/* If a word char is before the match, skip this match. */
|
||||||
|
if (is_word_mbchar(fileptr->data + before, FALSE)) {
|
||||||
|
if (ISSET(BACKWARDS_SEARCH))
|
||||||
|
rev_start = fileptr->data + before;
|
||||||
|
else
|
||||||
|
rev_start = found + move_mbright(found, 0);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
#ifndef DISABLE_SPELLER
|
#ifndef DISABLE_SPELLER
|
||||||
/* When we're spell checking, a match is only a true match when
|
/* When we're spell checking, a match is only a true match when
|
||||||
|
@ -304,7 +326,7 @@ int findnextstr(const char *needle, bool whole_word_only, size_t *match_len,
|
||||||
break;
|
break;
|
||||||
else {
|
else {
|
||||||
/* Maybe there is a whole word in the rest of the line. */
|
/* Maybe there is a whole word in the rest of the line. */
|
||||||
rev_start = found + 1;
|
rev_start = found + move_mbright(found, 0);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
} else
|
} else
|
||||||
|
|
Loading…
Reference in New Issue