mirror of https://github.com/junegunn/fzf
You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
136 lines
2.3 KiB
Go
136 lines
2.3 KiB
Go
10 years ago
|
package fzf
|
||
|
|
||
|
import (
|
||
|
"fmt"
|
||
|
"sort"
|
||
|
)
|
||
|
|
||
|
type Offset [2]int
|
||
|
|
||
|
type Item struct {
|
||
|
text *string
|
||
|
origText *string
|
||
|
offsets []Offset
|
||
|
index int
|
||
|
rank Rank
|
||
|
transformed *Transformed
|
||
|
}
|
||
|
|
||
|
type Rank [3]int
|
||
|
|
||
|
var NilRank = Rank{-1, 0, 0}
|
||
|
|
||
|
func (i *Item) Rank() Rank {
|
||
|
if i.rank[0] > 0 {
|
||
|
return i.rank
|
||
|
}
|
||
|
sort.Sort(ByOrder(i.offsets))
|
||
|
matchlen := 0
|
||
|
prevEnd := 0
|
||
|
for _, offset := range i.offsets {
|
||
|
begin := offset[0]
|
||
|
end := offset[1]
|
||
|
if prevEnd > begin {
|
||
|
begin = prevEnd
|
||
|
}
|
||
|
if end > prevEnd {
|
||
|
prevEnd = end
|
||
|
}
|
||
|
if end > begin {
|
||
|
matchlen += end - begin
|
||
|
}
|
||
|
}
|
||
|
i.rank = Rank{matchlen, len(*i.text), i.index}
|
||
|
return i.rank
|
||
|
}
|
||
|
|
||
|
func (i *Item) Print() {
|
||
|
if i.origText != nil {
|
||
|
fmt.Println(*i.origText)
|
||
|
} else {
|
||
|
fmt.Println(*i.text)
|
||
|
}
|
||
|
}
|
||
|
|
||
|
type ByOrder []Offset
|
||
|
|
||
|
func (a ByOrder) Len() int {
|
||
|
return len(a)
|
||
|
}
|
||
|
|
||
|
func (a ByOrder) Swap(i, j int) {
|
||
|
a[i], a[j] = a[j], a[i]
|
||
|
}
|
||
|
|
||
|
func (a ByOrder) Less(i, j int) bool {
|
||
|
ioff := a[i]
|
||
|
joff := a[j]
|
||
|
return (ioff[0] < joff[0]) || (ioff[0] == joff[0]) && (ioff[1] <= joff[1])
|
||
|
}
|
||
|
|
||
|
type ByRelevance []*Item
|
||
|
|
||
|
func (a ByRelevance) Len() int {
|
||
|
return len(a)
|
||
|
}
|
||
|
|
||
|
func (a ByRelevance) Swap(i, j int) {
|
||
|
a[i], a[j] = a[j], a[i]
|
||
|
}
|
||
|
|
||
|
func (a ByRelevance) Less(i, j int) bool {
|
||
|
irank := a[i].Rank()
|
||
|
jrank := a[j].Rank()
|
||
|
|
||
|
return compareRanks(irank, jrank)
|
||
|
}
|
||
|
|
||
|
func compareRanks(irank Rank, jrank Rank) bool {
|
||
|
for idx := range irank {
|
||
|
if irank[idx] < jrank[idx] {
|
||
|
return true
|
||
|
} else if irank[idx] > jrank[idx] {
|
||
|
return false
|
||
|
}
|
||
|
}
|
||
|
return true
|
||
|
}
|
||
|
|
||
|
func SortMerge(partialResults [][]*Item) []*Item {
|
||
|
if len(partialResults) == 1 {
|
||
|
return partialResults[0]
|
||
|
}
|
||
|
|
||
|
merged := []*Item{}
|
||
|
|
||
|
for len(partialResults) > 0 {
|
||
|
minRank := Rank{0, 0, 0}
|
||
|
minIdx := -1
|
||
|
|
||
|
for idx, partialResult := range partialResults {
|
||
|
if len(partialResult) > 0 {
|
||
|
rank := partialResult[0].Rank()
|
||
|
if minIdx < 0 || compareRanks(rank, minRank) {
|
||
|
minRank = rank
|
||
|
minIdx = idx
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if minIdx >= 0 {
|
||
|
merged = append(merged, partialResults[minIdx][0])
|
||
|
partialResults[minIdx] = partialResults[minIdx][1:]
|
||
|
}
|
||
|
|
||
|
nonEmptyPartialResults := make([][]*Item, 0, len(partialResults))
|
||
|
for _, partialResult := range partialResults {
|
||
|
if len(partialResult) > 0 {
|
||
|
nonEmptyPartialResults = append(nonEmptyPartialResults, partialResult)
|
||
|
}
|
||
|
}
|
||
|
partialResults = nonEmptyPartialResults
|
||
|
}
|
||
|
|
||
|
return merged
|
||
|
}
|