Remove Offset slice from Result struct

This commit is contained in:
Junegunn Choi 2016-08-20 01:46:54 +09:00
parent 3e88849386
commit 827a83efbc
No known key found for this signature in database
GPG Key ID: 254BC280FEF9C627
9 changed files with 55 additions and 46 deletions

View File

@ -161,9 +161,11 @@ func Run(opts *Options) {
reader := Reader{ reader := Reader{
func(runes []byte) bool { func(runes []byte) bool {
item := chunkList.trans(runes, 0) item := chunkList.trans(runes, 0)
if item != nil && pattern.MatchItem(item) != nil { if item != nil {
fmt.Println(item.text.ToString()) if result, _ := pattern.MatchItem(item); result != nil {
found = true fmt.Println(item.text.ToString())
found = true
}
} }
return false return false
}, eventBox, opts.ReadZero} }, eventBox, opts.ReadZero}

View File

@ -211,7 +211,7 @@ func (m *Matcher) scan(request MatchRequest) (*Merger, bool) {
partialResult := <-resultChan partialResult := <-resultChan
partialResults[partialResult.index] = partialResult.matches partialResults[partialResult.index] = partialResult.matches
} }
return NewMerger(partialResults, m.sort, m.tac), false return NewMerger(pattern, partialResults, m.sort, m.tac), false
} }
// Reset is called to interrupt/signal the ongoing search // Reset is called to interrupt/signal the ongoing search

View File

@ -3,11 +3,12 @@ package fzf
import "fmt" import "fmt"
// EmptyMerger is a Merger with no data // EmptyMerger is a Merger with no data
var EmptyMerger = NewMerger([][]*Result{}, false, false) var EmptyMerger = NewMerger(nil, [][]*Result{}, false, false)
// Merger holds a set of locally sorted lists of items and provides the view of // Merger holds a set of locally sorted lists of items and provides the view of
// a single, globally-sorted list // a single, globally-sorted list
type Merger struct { type Merger struct {
pattern *Pattern
lists [][]*Result lists [][]*Result
merged []*Result merged []*Result
chunks *[]*Chunk chunks *[]*Chunk
@ -22,9 +23,10 @@ type Merger struct {
// original order // original order
func PassMerger(chunks *[]*Chunk, tac bool) *Merger { func PassMerger(chunks *[]*Chunk, tac bool) *Merger {
mg := Merger{ mg := Merger{
chunks: chunks, pattern: nil,
tac: tac, chunks: chunks,
count: 0} tac: tac,
count: 0}
for _, chunk := range *mg.chunks { for _, chunk := range *mg.chunks {
mg.count += len(*chunk) mg.count += len(*chunk)
@ -33,8 +35,9 @@ func PassMerger(chunks *[]*Chunk, tac bool) *Merger {
} }
// NewMerger returns a new Merger // NewMerger returns a new Merger
func NewMerger(lists [][]*Result, sorted bool, tac bool) *Merger { func NewMerger(pattern *Pattern, lists [][]*Result, sorted bool, tac bool) *Merger {
mg := Merger{ mg := Merger{
pattern: pattern,
lists: lists, lists: lists,
merged: []*Result{}, merged: []*Result{},
chunks: nil, chunks: nil,

View File

@ -17,16 +17,9 @@ func assert(t *testing.T, cond bool, msg ...string) {
func randResult() *Result { func randResult() *Result {
str := fmt.Sprintf("%d", rand.Uint32()) str := fmt.Sprintf("%d", rand.Uint32())
offsets := make([]Offset, rand.Int()%3)
for idx := range offsets {
sidx := int32(rand.Uint32() % 20)
eidx := sidx + int32(rand.Uint32()%20)
offsets[idx] = Offset{sidx, eidx}
}
return &Result{ return &Result{
item: &Item{text: util.RunesToChars([]rune(str))}, item: &Item{text: util.RunesToChars([]rune(str))},
offsets: offsets, rank: rank{index: rand.Int31()}}
rank: rank{index: rand.Int31()}}
} }
func TestEmptyMerger(t *testing.T) { func TestEmptyMerger(t *testing.T) {
@ -64,7 +57,7 @@ func TestMergerUnsorted(t *testing.T) {
cnt := len(items) cnt := len(items)
// Not sorted: same order // Not sorted: same order
mg := NewMerger(lists, false, false) mg := NewMerger(nil, lists, false, false)
assert(t, cnt == mg.Length(), "Invalid Length") assert(t, cnt == mg.Length(), "Invalid Length")
for i := 0; i < cnt; i++ { for i := 0; i < cnt; i++ {
assert(t, items[i] == mg.Get(i), "Invalid Get") assert(t, items[i] == mg.Get(i), "Invalid Get")
@ -76,7 +69,7 @@ func TestMergerSorted(t *testing.T) {
cnt := len(items) cnt := len(items)
// Sorted sorted order // Sorted sorted order
mg := NewMerger(lists, true, false) mg := NewMerger(nil, lists, true, false)
assert(t, cnt == mg.Length(), "Invalid Length") assert(t, cnt == mg.Length(), "Invalid Length")
sort.Sort(ByRelevance(items)) sort.Sort(ByRelevance(items))
for i := 0; i < cnt; i++ { for i := 0; i < cnt; i++ {
@ -86,7 +79,7 @@ func TestMergerSorted(t *testing.T) {
} }
// Inverse order // Inverse order
mg2 := NewMerger(lists, true, false) mg2 := NewMerger(nil, lists, true, false)
for i := cnt - 1; i >= 0; i-- { for i := cnt - 1; i >= 0; i-- {
if items[i] != mg2.Get(i) { if items[i] != mg2.Get(i) {
t.Error("Not sorted", items[i], mg2.Get(i)) t.Error("Not sorted", items[i], mg2.Get(i))

View File

@ -273,13 +273,13 @@ func (p *Pattern) matchChunk(chunk *Chunk, space []*Result) []*Result {
if space == nil { if space == nil {
for _, item := range *chunk { for _, item := range *chunk {
if match := p.MatchItem(item); match != nil { if match, _ := p.MatchItem(item); match != nil {
matches = append(matches, match) matches = append(matches, match)
} }
} }
} else { } else {
for _, result := range space { for _, result := range space {
if match := p.MatchItem(result.item); match != nil { if match, _ := p.MatchItem(result.item); match != nil {
matches = append(matches, match) matches = append(matches, match)
} }
} }
@ -288,18 +288,19 @@ func (p *Pattern) matchChunk(chunk *Chunk, space []*Result) []*Result {
} }
// MatchItem returns true if the Item is a match // MatchItem returns true if the Item is a match
func (p *Pattern) MatchItem(item *Item) *Result { func (p *Pattern) MatchItem(item *Item) (*Result, []Offset) {
if p.extended { if p.extended {
if offsets, bonus, trimLen := p.extendedMatch(item); len(offsets) == len(p.termSets) { if offsets, bonus, trimLen := p.extendedMatch(item); len(offsets) == len(p.termSets) {
return buildResult(item, offsets, bonus, trimLen) return buildResult(item, offsets, bonus, trimLen), offsets
} }
return nil return nil, nil
} }
offset, bonus, trimLen := p.basicMatch(item) offset, bonus, trimLen := p.basicMatch(item)
if sidx := offset[0]; sidx >= 0 { if sidx := offset[0]; sidx >= 0 {
return buildResult(item, []Offset{offset}, bonus, trimLen) offsets := []Offset{offset}
return buildResult(item, offsets, bonus, trimLen), offsets
} }
return nil return nil, nil
} }
func (p *Pattern) basicMatch(item *Item) (Offset, int, int) { func (p *Pattern) basicMatch(item *Item) (Offset, int, int) {

View File

@ -135,10 +135,16 @@ func TestOrigTextAndTransformed(t *testing.T) {
pattern.extended = extended pattern.extended = extended
matches := pattern.matchChunk(&chunk, nil) // No cache matches := pattern.matchChunk(&chunk, nil) // No cache
if matches[0].item.text.ToString() != "junegunn" || string(*matches[0].item.origText) != "junegunn.choi" || if matches[0].item.text.ToString() != "junegunn" || string(*matches[0].item.origText) != "junegunn.choi" ||
matches[0].offsets[0][0] != 0 || matches[0].offsets[0][1] != 5 ||
!reflect.DeepEqual(matches[0].item.transformed, trans) { !reflect.DeepEqual(matches[0].item.transformed, trans) {
t.Error("Invalid match result", matches) t.Error("Invalid match result", matches)
} }
match, offsets := pattern.MatchItem(chunk[0])
if match.item.text.ToString() != "junegunn" || string(*match.item.origText) != "junegunn.choi" ||
offsets[0][0] != 0 || offsets[0][1] != 5 ||
!reflect.DeepEqual(match.item.transformed, trans) {
t.Error("Invalid match result", match)
}
} }
} }

View File

@ -19,15 +19,14 @@ type colorOffset struct {
} }
type rank struct { type rank struct {
index int32
// byMatchLen, byBonus, ... // byMatchLen, byBonus, ...
points [5]uint16 points [5]uint16
index int32
} }
type Result struct { type Result struct {
item *Item item *Item
offsets []Offset rank rank
rank rank
} }
func buildResult(item *Item, offsets []Offset, bonus int, trimLen int) *Result { func buildResult(item *Item, offsets []Offset, bonus int, trimLen int) *Result {
@ -35,7 +34,7 @@ func buildResult(item *Item, offsets []Offset, bonus int, trimLen int) *Result {
sort.Sort(ByOrder(offsets)) sort.Sort(ByOrder(offsets))
} }
result := Result{item: item, offsets: offsets, rank: rank{index: item.index}} result := Result{item: item, rank: rank{index: item.index}}
matchlen := 0 matchlen := 0
prevEnd := 0 prevEnd := 0
@ -110,12 +109,12 @@ func minRank() rank {
return rank{index: 0, points: [5]uint16{0, math.MaxUint16, 0, 0, 0}} return rank{index: 0, points: [5]uint16{0, math.MaxUint16, 0, 0, 0}}
} }
func (result *Result) colorOffsets(color int, bold bool, current bool) []colorOffset { func (result *Result) colorOffsets(matchOffsets []Offset, color int, bold bool, current bool) []colorOffset {
itemColors := result.item.Colors() itemColors := result.item.Colors()
if len(itemColors) == 0 { if len(itemColors) == 0 {
var offsets []colorOffset var offsets []colorOffset
for _, off := range result.offsets { for _, off := range matchOffsets {
offsets = append(offsets, colorOffset{offset: [2]int32{off[0], off[1]}, color: color, bold: bold}) offsets = append(offsets, colorOffset{offset: [2]int32{off[0], off[1]}, color: color, bold: bold})
} }
@ -124,7 +123,7 @@ func (result *Result) colorOffsets(color int, bold bool, current bool) []colorOf
// Find max column // Find max column
var maxCol int32 var maxCol int32
for _, off := range result.offsets { for _, off := range matchOffsets {
if off[1] > maxCol { if off[1] > maxCol {
maxCol = off[1] maxCol = off[1]
} }
@ -142,7 +141,7 @@ func (result *Result) colorOffsets(color int, bold bool, current bool) []colorOf
} }
} }
for _, off := range result.offsets { for _, off := range matchOffsets {
for i := off[0]; i < off[1]; i++ { for i := off[0]; i < off[1]; i++ {
cols[i] = -1 cols[i] = -1
} }

View File

@ -88,8 +88,9 @@ func TestColorOffset(t *testing.T) {
// ------------ 20 ---- -- ---- // ------------ 20 ---- -- ----
// ++++++++ ++++++++++ // ++++++++ ++++++++++
// --++++++++-- --++++++++++--- // --++++++++-- --++++++++++---
offsets := []Offset{Offset{5, 15}, Offset{25, 35}}
item := Result{ item := Result{
offsets: []Offset{Offset{5, 15}, Offset{25, 35}},
item: &Item{ item: &Item{
colors: &[]ansiOffset{ colors: &[]ansiOffset{
ansiOffset{[2]int32{0, 20}, ansiState{1, 5, false}}, ansiOffset{[2]int32{0, 20}, ansiState{1, 5, false}},
@ -98,9 +99,9 @@ func TestColorOffset(t *testing.T) {
ansiOffset{[2]int32{33, 40}, ansiState{4, 8, true}}}}} ansiOffset{[2]int32{33, 40}, ansiState{4, 8, true}}}}}
// [{[0 5] 9 false} {[5 15] 99 false} {[15 20] 9 false} {[22 25] 10 true} {[25 35] 99 false} {[35 40] 11 true}] // [{[0 5] 9 false} {[5 15] 99 false} {[15 20] 9 false} {[22 25] 10 true} {[25 35] 99 false} {[35 40] 11 true}]
offsets := item.colorOffsets(99, false, true) colors := item.colorOffsets(offsets, 99, false, true)
assert := func(idx int, b int32, e int32, c int, bold bool) { assert := func(idx int, b int32, e int32, c int, bold bool) {
o := offsets[idx] o := colors[idx]
if o.offset[0] != b || o.offset[1] != e || o.color != c || o.bold != bold { if o.offset[0] != b || o.offset[1] != e || o.color != c || o.bold != bold {
t.Error(o) t.Error(o)
} }

View File

@ -669,15 +669,19 @@ func overflow(runes []rune, max int) bool {
func (t *Terminal) printHighlighted(result *Result, bold bool, col1 int, col2 int, current bool) { func (t *Terminal) printHighlighted(result *Result, bold bool, col1 int, col2 int, current bool) {
item := result.item item := result.item
var maxe int
for _, offset := range result.offsets {
maxe = util.Max(maxe, int(offset[1]))
}
// Overflow // Overflow
text := make([]rune, item.text.Length()) text := make([]rune, item.text.Length())
copy(text, item.text.ToRunes()) copy(text, item.text.ToRunes())
offsets := result.colorOffsets(col2, bold, current) matchOffsets := []Offset{}
if t.merger.pattern != nil {
_, matchOffsets = t.merger.pattern.MatchItem(item)
}
var maxe int
for _, offset := range matchOffsets {
maxe = util.Max(maxe, int(offset[1]))
}
offsets := result.colorOffsets(matchOffsets, col2, bold, current)
maxWidth := t.window.Width - 3 maxWidth := t.window.Width - 3
maxe = util.Constrain(maxe+util.Min(maxWidth/2-2, t.hscrollOff), 0, len(text)) maxe = util.Constrain(maxe+util.Min(maxWidth/2-2, t.hscrollOff), 0, len(text))
if overflow(text, maxWidth) { if overflow(text, maxWidth) {