From 1d2d32c847e39818bedae5f86ca75e6b70b60444 Mon Sep 17 00:00:00 2001 From: Junegunn Choi Date: Wed, 13 Jan 2016 03:07:42 +0900 Subject: Accept comma-separated list of sort criteria --- src/item.go | 110 ++++++++++++++++++++++++++++++++++-------------------------- 1 file changed, 63 insertions(+), 47 deletions(-) (limited to 'src/item.go') diff --git a/src/item.go b/src/item.go index 5ce25c71..a4fa609b 100644 --- a/src/item.go +++ b/src/item.go @@ -20,25 +20,35 @@ type Item struct { text []rune origText *[]rune transformed []Token - index uint32 + index int32 offsets []Offset colors []ansiOffset - rank Rank + rank []int32 } -// Rank is used to sort the search result -type Rank struct { - matchlen uint16 - tiebreak uint16 - index uint32 +// Sort criteria to use. Never changes once fzf is started. +var sortCriteria []criterion + +func isRankValid(rank []int32) bool { + // Exclude ordinal index + for i := 0; i < len(rank)-1; i++ { + if rank[i] > 0 { + return true + } + } + return false } -// Tiebreak criterion to use. Never changes once fzf is started. -var rankTiebreak tiebreak +func buildEmptyRank(index int32) []int32 { + len := len(sortCriteria) + arr := make([]int32, len) + arr[len-1] = index + return arr +} // Rank calculates rank of the Item -func (item *Item) Rank(cache bool) Rank { - if cache && (item.rank.matchlen > 0 || item.rank.tiebreak > 0) { +func (item *Item) Rank(cache bool) []int32 { + if cache && isRankValid(item.rank) { return item.rank } matchlen := 0 @@ -64,32 +74,37 @@ func (item *Item) Rank(cache bool) Rank { } } if matchlen == 0 { - matchlen = math.MaxUint16 + matchlen = math.MaxInt32 } - var tiebreak uint16 - switch rankTiebreak { - case byLength: - // It is guaranteed that .transformed in not null in normal execution - if item.transformed != nil { - // If offsets is empty, lenSum will be 0, but we don't care - tiebreak = uint16(lenSum) - } else { - tiebreak = uint16(len(item.text)) - } - case byBegin: - // We can't just look at item.offsets[0][0] because it can be an inverse term - tiebreak = uint16(minBegin) - case byEnd: - if prevEnd > 0 { - tiebreak = uint16(1 + len(item.text) - prevEnd) - } else { - // Empty offsets due to inverse terms. - tiebreak = 1 + rank := make([]int32, len(sortCriteria)) + for idx, criterion := range sortCriteria { + var val int32 + switch criterion { + case byMatchLen: + val = int32(matchlen) + case byLength: + // It is guaranteed that .transformed in not null in normal execution + if item.transformed != nil { + // If offsets is empty, lenSum will be 0, but we don't care + val = int32(lenSum) + } else { + val = int32(len(item.text)) + } + case byBegin: + // We can't just look at item.offsets[0][0] because it can be an inverse term + val = int32(minBegin) + case byEnd: + if prevEnd > 0 { + val = int32(1 + len(item.text) - prevEnd) + } else { + // Empty offsets due to inverse terms. + val = 1 + } + case byIndex: + val = item.index } - case byIndex: - tiebreak = 1 + rank[idx] = val } - rank := Rank{uint16(matchlen), tiebreak, item.index} if cache { item.rank = rank } @@ -254,18 +269,19 @@ func (a ByRelevanceTac) Less(i, j int) bool { return compareRanks(irank, jrank, true) } -func compareRanks(irank Rank, jrank Rank, tac bool) bool { - if irank.matchlen < jrank.matchlen { - return true - } else if irank.matchlen > jrank.matchlen { - return false - } - - if irank.tiebreak < jrank.tiebreak { - return true - } else if irank.tiebreak > jrank.tiebreak { - return false +func compareRanks(irank []int32, jrank []int32, tac bool) bool { + lastIdx := len(irank) - 1 + for idx, left := range irank { + right := jrank[idx] + if tac && idx == lastIdx { + left = left * -1 + right = right * -1 + } + if left < right { + return true + } else if left > right { + return false + } } - - return (irank.index <= jrank.index) != tac + return true } -- cgit v1.2.3