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.
fzf/src/item.go

210 lines
4.0 KiB
Go

10 years ago
package fzf
import (
"github.com/junegunn/fzf/src/curses"
)
10 years ago
// Offset holds two 32-bit integers denoting the offsets of a matched substring
type Offset [2]int32
10 years ago
9 years ago
type colorOffset struct {
offset [2]int32
color int
bold bool
}
10 years ago
// Item represents each input line
10 years ago
type Item struct {
text *string
origText *string
transformed *Transformed
index uint32
10 years ago
offsets []Offset
9 years ago
colors []ansiOffset
10 years ago
rank Rank
}
10 years ago
// Rank is used to sort the search result
type Rank struct {
matchlen uint16
strlen uint16
index uint32
}
10 years ago
10 years ago
// Rank calculates rank of the Item
func (i *Item) Rank(cache bool) Rank {
if cache && (i.rank.matchlen > 0 || i.rank.strlen > 0) {
10 years ago
return i.rank
}
matchlen := 0
prevEnd := 0
for _, offset := range i.offsets {
begin := int(offset[0])
end := int(offset[1])
10 years ago
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
10 years ago
}
10 years ago
// AsString returns the original string
func (i *Item) AsString() string {
10 years ago
if i.origText != nil {
10 years ago
return *i.origText
10 years ago
}
10 years ago
return *i.text
10 years ago
}
9 years ago
func (item *Item) colorOffsets(color int, bold bool, current bool) []colorOffset {
if len(item.colors) == 0 {
9 years ago
var offsets []colorOffset
for _, off := range item.offsets {
9 years ago
offsets = append(offsets, colorOffset{offset: off, color: color, bold: bold})
}
return offsets
}
// Find max column
9 years ago
var maxCol int32
for _, off := range item.offsets {
if off[1] > maxCol {
maxCol = off[1]
}
}
for _, ansi := range item.colors {
if ansi.offset[1] > maxCol {
maxCol = ansi.offset[1]
}
}
cols := make([]int, maxCol)
for colorIndex, ansi := range item.colors {
for i := ansi.offset[0]; i < ansi.offset[1]; i++ {
cols[i] = colorIndex + 1 // XXX
}
}
for _, off := range item.offsets {
for i := off[0]; i < off[1]; i++ {
cols[i] = -1
}
}
// sort.Sort(ByOrder(offsets))
// Merge offsets
// ------------ ---- -- ----
// ++++++++ ++++++++++
// --++++++++-- --++++++++++---
curr := 0
start := 0
9 years ago
var offsets []colorOffset
add := func(idx int) {
if curr != 0 && idx > start {
if curr == -1 {
9 years ago
offsets = append(offsets, colorOffset{
offset: Offset{int32(start), int32(idx)}, color: color, bold: bold})
} else {
ansi := item.colors[curr-1]
bg := ansi.color.bg
if current && bg == -1 {
bg = int(curses.DarkBG)
}
9 years ago
offsets = append(offsets, colorOffset{
offset: Offset{int32(start), int32(idx)},
color: curses.PairFor(ansi.color.fg, bg),
bold: ansi.color.bold || bold})
}
}
}
for idx, col := range cols {
if col != curr {
add(idx)
start = idx
curr = col
}
}
add(int(maxCol))
return offsets
}
10 years ago
// ByOrder is for sorting substring offsets
10 years ago
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])
}
10 years ago
// ByRelevance is for sorting Items
10 years ago
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)
10 years ago
return compareRanks(irank, jrank, false)
10 years ago
}
// 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
10 years ago
}