commit cbf7e57ed0a0800d35f84573e353b5a1b4af0334
parent e36e829ad064d4f80fbd7b3249d3b33c4ebbf64c
Author: Benno Schulenberg <bensberg@justemail.net>
Date: Sun, 1 Jan 2017 20:16:18 +0100
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.
Diffstat:
1 file changed, 24 insertions(+), 2 deletions(-)
diff --git a/src/search.c b/src/search.c
@@ -38,6 +38,8 @@ static bool history_changed = FALSE;
#ifdef HAVE_REGEX_H
static bool regexp_compiled = FALSE;
/* 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.
* Return TRUE if the expression is valid, and FALSE otherwise. */
@@ -60,6 +62,10 @@ bool regexp_init(const char *regexp)
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;
}
@@ -292,8 +298,24 @@ int findnextstr(const char *needle, bool whole_word_only, size_t *match_len,
if (found != NULL) {
#ifdef HAVE_REGEX_H
/* 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;
+
+ /* 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
#ifndef DISABLE_SPELLER
/* 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;
else {
/* Maybe there is a whole word in the rest of the line. */
- rev_start = found + 1;
+ rev_start = found + move_mbright(found, 0);
continue;
}
} else