From 5624a892311e96ffe019786c5507929d9427ad0f Mon Sep 17 00:00:00 2001 From: Junegunn Choi Date: Wed, 19 Dec 2018 23:05:29 +0900 Subject: [PATCH] Inverse-only matches should not reorder the remaining results Fix #1458 --- src/core.go | 1 + src/matcher.go | 2 +- src/pattern.go | 13 ++++++++++++- test/test_go.rb | 13 +++++++++++++ 4 files changed, 27 insertions(+), 2 deletions(-) diff --git a/src/core.go b/src/core.go index 023f7be..1653e6f 100644 --- a/src/core.go +++ b/src/core.go @@ -149,6 +149,7 @@ func Run(opts *Options, revision string) { } pattern := patternBuilder([]rune(*opts.Filter)) + matcher.sort = pattern.sortable found := false if streamingFilter { diff --git a/src/matcher.go b/src/matcher.go index c29f2b6..3c5dec0 100644 --- a/src/matcher.go +++ b/src/matcher.go @@ -230,5 +230,5 @@ func (m *Matcher) Reset(chunks []*Chunk, patternRunes []rune, cancel bool, final } else { event = reqRetry } - m.reqBox.Set(event, MatchRequest{chunks, pattern, final, sort}) + m.reqBox.Set(event, MatchRequest{chunks, pattern, final, sort && pattern.sortable}) } diff --git a/src/pattern.go b/src/pattern.go index 2627dea..4880d6e 100644 --- a/src/pattern.go +++ b/src/pattern.go @@ -52,6 +52,7 @@ type Pattern struct { forward bool text []rune termSets []termSet + sortable bool cacheable bool cacheKey string delimiter Delimiter @@ -101,18 +102,27 @@ func BuildPattern(fuzzy bool, fuzzyAlgo algo.Algo, extended bool, caseMode Case, } caseSensitive := true + sortable := true termSets := []termSet{} if extended { termSets = parseTerms(fuzzy, caseMode, normalize, asString) + // We should not sort the result if there are only inverse search terms + sortable = false Loop: for _, termSet := range termSets { for idx, term := range termSet { + if !term.inv { + sortable = true + } // If the query contains inverse search terms or OR operators, // we cannot cache the search scope if !cacheable || idx > 0 || term.inv || fuzzy && term.typ != termFuzzy || !fuzzy && term.typ != termExact { cacheable = false - break Loop + if sortable { + // Can't break until we see at least one non-inverse term + break Loop + } } } } @@ -134,6 +144,7 @@ func BuildPattern(fuzzy bool, fuzzyAlgo algo.Algo, extended bool, caseMode Case, forward: forward, text: []rune(asString), termSets: termSets, + sortable: sortable, cacheable: cacheable, nth: nth, delimiter: delimiter, diff --git a/test/test_go.rb b/test/test_go.rb index d22b893..213f15c 100755 --- a/test/test_go.rb +++ b/test/test_go.rb @@ -1519,6 +1519,19 @@ class TestGoFZF < TestBase assert_equal ['foo bar'], `#{FZF} -f'^foo\\ bar$' < #{tempname}`.lines.map(&:chomp) assert_equal input.lines.count - 1, `#{FZF} -f'!^foo\\ bar$' < #{tempname}`.lines.count end + + def test_inverse_only_search_should_not_sort_the_result + # Filter + assert_equal(%w[aaaaa b ccc], + `printf '%s\n' aaaaa b ccc BAD | #{FZF} -f '!bad'`.lines.map(&:chomp)) + + # Interactive + tmux.send_keys(%[printf '%s\n' aaaaa b ccc BAD | #{FZF} -q '!bad'], :Enter) + tmux.until { |lines| lines.item_count == 4 && lines.match_count == 3 } + tmux.until { |lines| lines[-3] == '> aaaaa' } + tmux.until { |lines| lines[-4] == ' b' } + tmux.until { |lines| lines[-5] == ' ccc' } + end end module TestShell