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",