summaryrefslogtreecommitdiffstats
path: root/src/item.go
blob: 2b8a9d134488fea5077e5c9fb948b99d88c2b459 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
package fzf

// Offset holds two 32-bit integers denoting the offsets of a matched substring
type Offset [2]int32

// Item represents each input line
type Item struct {
	text        *string
	origText    *string
	transformed *Transformed
	index       uint32
	offsets     []Offset
	rank        Rank
}

// Rank is used to sort the search result
type Rank struct {
	matchlen uint16
	strlen   uint16
	index    uint32
}

// Rank calculates rank of the Item
func (i *Item) Rank(cache bool) Rank {
	if cache && (i.rank.matchlen > 0 || i.rank.strlen > 0) {
		return i.rank
	}
	matchlen := 0
	prevEnd := 0
	for _, offset := range i.offsets {
		begin := int(offset[0])
		end := int(offset[1])
		if prevEnd > begin {
			begin = prevEnd
		}
		if end > prevEnd {
			prevEnd = end
		}
		if end > begin {
			matchlen += end - begin
		}
	}
	rank := Rank{uint16(matchlen), uint16(len(*i.text)), i.index}
	if cache {
		i.rank = rank
	}
	return rank
}

// AsString returns the original string
func (i *Item) AsString() string {
	if i.origText != nil {
		return *i.origText
	}
	return *i.text
}

// ByOrder is for sorting substring offsets
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])
}

// ByRelevance is for sorting Items
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(true)
	jrank := a[j].Rank(true)

	return compareRanks(irank, jrank, false)
}

// ByRelevanceTac is for sorting Items
type ByRelevanceTac []*Item

func (a ByRelevanceTac) Len() int {
	return len(a)
}

func (a ByRelevanceTac) Swap(i, j int) {
	a[i], a[j] = a[j], a[i]
}

func (a ByRelevanceTac) Less(i, j int) bool {
	irank := a[i].Rank(true)
	jrank := a[j].Rank(true)

	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.strlen < jrank.strlen {
		return true
	} else if irank.strlen > jrank.strlen {
		return false
	}

	return (irank.index <= jrank.index) != tac
}