summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJunegunn Choi <junegunn.c@gmail.com>2020-03-01 12:36:02 +0900
committerJunegunn Choi <junegunn.c@gmail.com>2020-03-01 12:36:02 +0900
commit4c9cab3f8ae7b55f7124d7c3cf7ac6b4cc3db210 (patch)
tree4c0e59346708bfd82a15743d13a56480d245d45e
parentb2c0413a98e210cedd34fbe0f6ba051906da398f (diff)
Fix prefix/suffix/equal matcher to trim whitespaces
- Prefix matcher will trim leading whitespaces only when the pattern doesn't start with a whitespace - Suffix matcher will trim trailing whitespaces only when the pattern doesn't end with a whitespace - Equal matcher will trim leading whitespaces only when the pattern doesn't start with a whitespace, and trim trailing whitespaces only when the pattern doesn't end with a whitespace Previously, only suffix matcher would trim whitespaces unconditionally. Fix #1894
-rw-r--r--src/algo/algo.go43
-rw-r--r--src/algo/algo_test.go11
-rw-r--r--src/pattern_test.go3
-rw-r--r--src/util/chars.go12
4 files changed, 60 insertions, 9 deletions
diff --git a/src/algo/algo.go b/src/algo/algo.go
index a627514c..b3f29e66 100644
--- a/src/algo/algo.go
+++ b/src/algo/algo.go
@@ -773,12 +773,17 @@ func PrefixMatch(caseSensitive bool, normalize bool, forward bool, text *util.Ch
return Result{0, 0, 0}, nil
}
- if text.Length() < len(pattern) {
+ trimmedLen := 0
+ if !unicode.IsSpace(pattern[0]) {
+ trimmedLen = text.LeadingWhitespaces()
+ }
+
+ if text.Length()-trimmedLen < len(pattern) {
return Result{-1, -1, 0}, nil
}
for index, r := range pattern {
- char := text.Get(index)
+ char := text.Get(trimmedLen + index)
if !caseSensitive {
char = unicode.ToLower(char)
}
@@ -790,14 +795,17 @@ func PrefixMatch(caseSensitive bool, normalize bool, forward bool, text *util.Ch
}
}
lenPattern := len(pattern)
- score, _ := calculateScore(caseSensitive, normalize, text, pattern, 0, lenPattern, false)
- return Result{0, lenPattern, score}, nil
+ score, _ := calculateScore(caseSensitive, normalize, text, pattern, trimmedLen, trimmedLen+lenPattern, false)
+ return Result{trimmedLen, trimmedLen + lenPattern, score}, nil
}
// SuffixMatch performs suffix-match
func SuffixMatch(caseSensitive bool, normalize bool, forward bool, text *util.Chars, pattern []rune, withPos bool, slab *util.Slab) (Result, *[]int) {
lenRunes := text.Length()
- trimmedLen := lenRunes - text.TrailingWhitespaces()
+ trimmedLen := lenRunes
+ if len(pattern) == 0 || !unicode.IsSpace(pattern[len(pattern)-1]) {
+ trimmedLen -= text.TrailingWhitespaces()
+ }
if len(pattern) == 0 {
return Result{trimmedLen, trimmedLen, 0}, nil
}
@@ -828,14 +836,30 @@ func SuffixMatch(caseSensitive bool, normalize bool, forward bool, text *util.Ch
// EqualMatch performs equal-match
func EqualMatch(caseSensitive bool, normalize bool, forward bool, text *util.Chars, pattern []rune, withPos bool, slab *util.Slab) (Result, *[]int) {
lenPattern := len(pattern)
- if text.Length() != lenPattern {
+ if lenPattern == 0 {
+ return Result{-1, -1, 0}, nil
+ }
+
+ // Strip leading whitespaces
+ trimmedLen := 0
+ if !unicode.IsSpace(pattern[0]) {
+ trimmedLen = text.LeadingWhitespaces()
+ }
+
+ // Strip trailing whitespaces
+ trimmedEndLen := 0
+ if !unicode.IsSpace(pattern[lenPattern-1]) {
+ trimmedEndLen = text.TrailingWhitespaces()
+ }
+
+ if text.Length()-trimmedLen-trimmedEndLen != lenPattern {
return Result{-1, -1, 0}, nil
}
match := true
if normalize {
runes := text.ToRunes()
for idx, pchar := range pattern {
- char := runes[idx]
+ char := runes[trimmedLen+idx]
if !caseSensitive {
char = unicode.To(unicode.LowerCase, char)
}
@@ -845,14 +869,15 @@ func EqualMatch(caseSensitive bool, normalize bool, forward bool, text *util.Cha
}
}
} else {
- runesStr := text.ToString()
+ runes := text.ToRunes()
+ runesStr := string(runes[trimmedLen : len(runes)-trimmedEndLen])
if !caseSensitive {
runesStr = strings.ToLower(runesStr)
}
match = runesStr == string(pattern)
}
if match {
- return Result{0, lenPattern, (scoreMatch+bonusBoundary)*lenPattern +
+ return Result{trimmedLen, trimmedLen + lenPattern, (scoreMatch+bonusBoundary)*lenPattern +
(bonusFirstCharMultiplier-1)*bonusBoundary}, nil
}
return Result{-1, -1, 0}, nil
diff --git a/src/algo/algo_test.go b/src/algo/algo_test.go
index 610c30e5..d8f40cdf 100644
--- a/src/algo/algo_test.go
+++ b/src/algo/algo_test.go
@@ -136,6 +136,10 @@ func TestPrefixMatch(t *testing.T) {
assertMatch(t, PrefixMatch, false, dir, "fooBarbaz", "Foo", 0, 3, score)
assertMatch(t, PrefixMatch, false, dir, "foOBarBaZ", "foo", 0, 3, score)
assertMatch(t, PrefixMatch, false, dir, "f-oBarbaz", "f-o", 0, 3, score)
+
+ assertMatch(t, PrefixMatch, false, dir, " fooBar", "foo", 1, 4, score)
+ assertMatch(t, PrefixMatch, false, dir, " fooBar", " fo", 0, 3, score)
+ assertMatch(t, PrefixMatch, false, dir, " fo", "foo", -1, -1, 0)
}
}
@@ -148,6 +152,13 @@ func TestSuffixMatch(t *testing.T) {
scoreMatch*3+bonusConsecutive*2)
assertMatch(t, SuffixMatch, false, dir, "fooBarBaZ", "baz", 6, 9,
(scoreMatch+bonusCamel123)*3+bonusCamel123*(bonusFirstCharMultiplier-1))
+
+ // Strip trailing white space from the string
+ assertMatch(t, SuffixMatch, false, dir, "fooBarbaz ", "baz", 6, 9,
+ scoreMatch*3+bonusConsecutive*2)
+ // Only when the pattern doesn't end with a space
+ assertMatch(t, SuffixMatch, false, dir, "fooBarbaz ", "baz ", 6, 10,
+ scoreMatch*4+bonusConsecutive*2+bonusNonWord)
}
}
diff --git a/src/pattern_test.go b/src/pattern_test.go
index bfadf5d8..5a622952 100644
--- a/src/pattern_test.go
+++ b/src/pattern_test.go
@@ -98,6 +98,9 @@ func TestEqual(t *testing.T) {
}
match("ABC", -1, -1)
match("AbC", 0, 3)
+ match("AbC ", 0, 3)
+ match(" AbC ", 1, 4)
+ match(" AbC", 2, 5)
}
func TestCaseSensitivity(t *testing.T) {
diff --git a/src/util/chars.go b/src/util/chars.go
index a57ba4bb..41de9243 100644
--- a/src/util/chars.go
+++ b/src/util/chars.go
@@ -130,6 +130,18 @@ func (chars *Chars) TrimLength() uint16 {
return chars.trimLength
}
+func (chars *Chars) LeadingWhitespaces() int {
+ whitespaces := 0
+ for i := 0; i < chars.Length(); i++ {
+ char := chars.Get(i)
+ if !unicode.IsSpace(char) {
+ break
+ }
+ whitespaces++
+ }
+ return whitespaces
+}
+
func (chars *Chars) TrailingWhitespaces() int {
whitespaces := 0
for i := chars.Length() - 1; i >= 0; i-- {