diff --git a/matchtree.go b/matchtree.go
index 4cc73c3ce..d2c474a04 100644
--- a/matchtree.go
+++ b/matchtree.go
@@ -139,6 +139,8 @@ type regexpMatchTree struct {
reEvaluated bool
found []*candidateMatch
+ literalPrefix *substrMatchTree
+
// nextDoc, prepare.
bruteForceMatchTree
}
@@ -651,7 +653,32 @@ func (t *regexpMatchTree) matches(cp *contentProvider, cost int, known map[match
}
cp.stats.RegexpsConsidered++
- idxs := t.regexp.FindAllIndex(cp.data(t.fileName), -1)
+
+ data := cp.data(t.fileName)
+
+ var idxs [][]int
+ if t.literalPrefix != nil {
+ t.literalPrefix.prepare(cp.idx)
+ idxs = make([][]int, 0, len(t.literalPrefix.current))
+ offset := 0
+ for _, literalCandidate := range t.literalPrefix.current {
+ if offset > int(literalCandidate.byteOffset) {
+ continue
+ }
+ offset = int(literalCandidate.byteOffset)
+ idx := t.regexp.FindIndex(data[offset:])
+ if idx == nil {
+ break
+ }
+ idx[0] += offset
+ idx[1] += offset
+ idxs = append(idxs, idx)
+ offset = idx[0] + 1
+ }
+ } else {
+ idxs = t.regexp.FindAllIndex(data, -1)
+ }
+
found := t.found[:0]
for _, idx := range idxs {
cm := &candidateMatch{
@@ -788,6 +815,22 @@ func (d *indexData) newMatchTree(q query.Q) (matchTree, error) {
fileName: s.FileName,
}
+ // TODO LiteralPrefix is always empty for case insensitive search. We want
+ // this optimization even in that case.
+ if prefix, _ := tr.regexp.LiteralPrefix(); len(prefix) >= ngramSize {
+ mt, err := d.newSubstringMatchTree(&query.Substring{
+ Pattern: prefix,
+ FileName: s.FileName,
+ CaseSensitive: s.CaseSensitive,
+ })
+ if err != nil {
+ return nil, err
+ }
+ if prefixMT, ok := mt.(*substrMatchTree); ok {
+ tr.literalPrefix = prefixMT
+ }
+ }
+
return &andMatchTree{
children: []matchTree{
tr, &noVisitMatchTree{subMT},
diff --git a/web/e2e_test.go b/web/e2e_test.go
index 4e143b607..c985758fb 100644
--- a/web/e2e_test.go
+++ b/web/e2e_test.go
@@ -121,6 +121,10 @@ func TestBasic(t *testing.T) {
"href=\"file-url#line",
"carry water",
},
+ "/search?q=water.in": {
+ "href=\"file-url#line",
+ "carry water in",
+ },
"/search?q=r:": {
"1234\">master",
"Found 1 repositories",