From edb3e51680fe34347552b52501fbeb65fbc11c29 Mon Sep 17 00:00:00 2001 From: Johan Walles Date: Mon, 13 May 2024 07:59:40 +0200 Subject: [PATCH] Don't search the whole file more than once Should improve the performance situation reported here: https://github.com/walles/moar/issues/209 --- m/pager_test.go | 10 +++++----- m/search.go | 15 ++++++++++----- 2 files changed, 15 insertions(+), 10 deletions(-) diff --git a/m/pager_test.go b/m/pager_test.go index 6ecbbd6..c3a6790 100644 --- a/m/pager_test.go +++ b/m/pager_test.go @@ -298,7 +298,7 @@ func TestFindFirstHitSimple(t *testing.T) { pager.searchPattern = toPattern("AB") - hit := pager.findFirstHit(linenumbers.LineNumber{}, false) + hit := pager.findFirstHit(linenumbers.LineNumber{}, nil, false) assert.Assert(t, hit.internalDontTouch.lineNumber.IsZero()) assert.Equal(t, hit.internalDontTouch.deltaScreenLines, 0) } @@ -312,7 +312,7 @@ func TestFindFirstHitAnsi(t *testing.T) { pager.searchPattern = toPattern("AB") - hit := pager.findFirstHit(linenumbers.LineNumber{}, false) + hit := pager.findFirstHit(linenumbers.LineNumber{}, nil, false) assert.Assert(t, hit.internalDontTouch.lineNumber.IsZero()) assert.Equal(t, hit.internalDontTouch.deltaScreenLines, 0) } @@ -326,7 +326,7 @@ func TestFindFirstHitNoMatch(t *testing.T) { pager.searchPattern = toPattern("this pattern should not be found") - hit := pager.findFirstHit(linenumbers.LineNumber{}, false) + hit := pager.findFirstHit(linenumbers.LineNumber{}, nil, false) assert.Assert(t, hit == nil) } @@ -340,7 +340,7 @@ func TestFindFirstHitNoMatchBackwards(t *testing.T) { pager.searchPattern = toPattern("this pattern should not be found") theEnd := *linenumbers.LineNumberFromLength(reader.GetLineCount()) - hit := pager.findFirstHit(theEnd, true) + hit := pager.findFirstHit(theEnd, nil, true) assert.Assert(t, hit == nil) } @@ -682,7 +682,7 @@ func benchmarkSearch(b *testing.B, highlighted bool) { b.ResetTimer() // This test will search through all the N copies we made of our file - hit := pager.findFirstHit(linenumbers.LineNumber{}, false) + hit := pager.findFirstHit(linenumbers.LineNumber{}, nil, false) if hit != nil { panic(fmt.Errorf("This test is meant to scan the whole file without finding anything")) diff --git a/m/search.go b/m/search.go index 3a8fef8..d61e51b 100644 --- a/m/search.go +++ b/m/search.go @@ -12,10 +12,10 @@ func (p *Pager) scrollToSearchHits() { return } - firstHitPosition := p.findFirstHit(*p.scrollPosition.lineNumber(p), false) + firstHitPosition := p.findFirstHit(*p.scrollPosition.lineNumber(p), nil, false) if firstHitPosition == nil { // Try again from the top - firstHitPosition = p.findFirstHit(linenumbers.LineNumber{}, false) + firstHitPosition = p.findFirstHit(linenumbers.LineNumber{}, p.scrollPosition.lineNumber(p), false) } if firstHitPosition == nil { // No match, give up @@ -35,7 +35,7 @@ func (p *Pager) scrollToSearchHits() { // scrollPosition for searching. // // FIXME: We should take startPosition.deltaScreenLines into account as well! -func (p *Pager) findFirstHit(startPosition linenumbers.LineNumber, backwards bool) *scrollPosition { +func (p *Pager) findFirstHit(startPosition linenumbers.LineNumber, beforePosition *linenumbers.LineNumber, backwards bool) *scrollPosition { searchPosition := startPosition for { line := p.reader.GetLine(searchPosition) @@ -58,6 +58,11 @@ func (p *Pager) findFirstHit(startPosition linenumbers.LineNumber, backwards boo searchPosition = searchPosition.NonWrappingAdd(-1) } else { searchPosition = searchPosition.NonWrappingAdd(1) + + if beforePosition != nil && searchPosition == *beforePosition { + // No match, give up + return nil + } } } } @@ -105,7 +110,7 @@ func (p *Pager) scrollToNextSearchHit() { panic(fmt.Sprint("Unknown search mode when finding next: ", p.mode)) } - firstHitPosition := p.findFirstHit(firstSearchPosition, false) + firstHitPosition := p.findFirstHit(firstSearchPosition, nil, false) if firstHitPosition == nil { p.mode = PagerModeNotFound{pager: p} return @@ -144,7 +149,7 @@ func (p *Pager) scrollToPreviousSearchHit() { panic(fmt.Sprint("Unknown search mode when finding previous: ", p.mode)) } - firstHitPosition := p.findFirstHit(firstSearchPosition, true) + firstHitPosition := p.findFirstHit(firstSearchPosition, nil, true) if firstHitPosition == nil { p.mode = PagerModeNotFound{pager: p} return