diff --git a/src/cache.go b/src/cache.go index 0540bdc..df1a6ab 100644 --- a/src/cache.go +++ b/src/cache.go @@ -3,7 +3,7 @@ package fzf import "sync" // queryCache associates strings to lists of items -type queryCache map[string][]*Result +type queryCache map[string][]Result // ChunkCache associates Chunk and query string to lists of items type ChunkCache struct { @@ -17,7 +17,7 @@ func NewChunkCache() ChunkCache { } // Add adds the list to the cache -func (cc *ChunkCache) Add(chunk *Chunk, key string, list []*Result) { +func (cc *ChunkCache) Add(chunk *Chunk, key string, list []Result) { if len(key) == 0 || !chunk.IsFull() || len(list) > queryCacheMax { return } @@ -34,7 +34,7 @@ func (cc *ChunkCache) Add(chunk *Chunk, key string, list []*Result) { } // Lookup is called to lookup ChunkCache -func (cc *ChunkCache) Lookup(chunk *Chunk, key string) []*Result { +func (cc *ChunkCache) Lookup(chunk *Chunk, key string) []Result { if len(key) == 0 || !chunk.IsFull() { return nil } @@ -52,7 +52,7 @@ func (cc *ChunkCache) Lookup(chunk *Chunk, key string) []*Result { return nil } -func (cc *ChunkCache) Search(chunk *Chunk, key string) []*Result { +func (cc *ChunkCache) Search(chunk *Chunk, key string) []Result { if len(key) == 0 || !chunk.IsFull() { return nil } diff --git a/src/cache_test.go b/src/cache_test.go index 54f3fb0..8a2d2cf 100644 --- a/src/cache_test.go +++ b/src/cache_test.go @@ -7,8 +7,8 @@ func TestChunkCache(t *testing.T) { chunk2 := make(Chunk, chunkSize) chunk1p := &Chunk{} chunk2p := &chunk2 - items1 := []*Result{&Result{}} - items2 := []*Result{&Result{}, &Result{}} + items1 := []Result{Result{}} + items2 := []Result{Result{}, Result{}} cache.Add(chunk1p, "foo", items1) cache.Add(chunk2p, "foo", items1) cache.Add(chunk2p, "bar", items2) diff --git a/src/matcher.go b/src/matcher.go index 57c263a..c29f2b6 100644 --- a/src/matcher.go +++ b/src/matcher.go @@ -131,7 +131,7 @@ func (m *Matcher) sliceChunks(chunks []*Chunk) [][]*Chunk { type partialResult struct { index int - matches []*Result + matches []Result } func (m *Matcher) scan(request MatchRequest) (*Merger, bool) { @@ -162,7 +162,7 @@ func (m *Matcher) scan(request MatchRequest) (*Merger, bool) { go func(idx int, slab *util.Slab, chunks []*Chunk) { defer func() { waitGroup.Done() }() count := 0 - allMatches := make([][]*Result, len(chunks)) + allMatches := make([][]Result, len(chunks)) for idx, chunk := range chunks { matches := request.pattern.Match(chunk, slab) allMatches[idx] = matches @@ -172,7 +172,7 @@ func (m *Matcher) scan(request MatchRequest) (*Merger, bool) { } countChan <- len(matches) } - sliceMatches := make([]*Result, 0, count) + sliceMatches := make([]Result, 0, count) for _, matches := range allMatches { sliceMatches = append(sliceMatches, matches...) } @@ -212,7 +212,7 @@ func (m *Matcher) scan(request MatchRequest) (*Merger, bool) { } } - partialResults := make([][]*Result, numSlices) + partialResults := make([][]Result, numSlices) for _ = range slices { partialResult := <-resultChan partialResults[partialResult.index] = partialResult.matches diff --git a/src/merger.go b/src/merger.go index 950ba04..7d30a76 100644 --- a/src/merger.go +++ b/src/merger.go @@ -3,14 +3,14 @@ package fzf import "fmt" // EmptyMerger is a Merger with no data -var EmptyMerger = NewMerger(nil, [][]*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 // a single, globally-sorted list type Merger struct { pattern *Pattern - lists [][]*Result - merged []*Result + lists [][]Result + merged []Result chunks *[]*Chunk cursors []int sorted bool @@ -35,11 +35,11 @@ func PassMerger(chunks *[]*Chunk, tac bool) *Merger { } // NewMerger returns a new Merger -func NewMerger(pattern *Pattern, lists [][]*Result, sorted bool, tac bool) *Merger { +func NewMerger(pattern *Pattern, lists [][]Result, sorted bool, tac bool) *Merger { mg := Merger{ pattern: pattern, lists: lists, - merged: []*Result{}, + merged: []Result{}, chunks: nil, cursors: make([]int, len(lists)), sorted: sorted, @@ -59,13 +59,13 @@ func (mg *Merger) Length() int { } // Get returns the pointer to the Result object indexed by the given integer -func (mg *Merger) Get(idx int) *Result { +func (mg *Merger) Get(idx int) Result { if mg.chunks != nil { if mg.tac { idx = mg.count - idx - 1 } chunk := (*mg.chunks)[idx/chunkSize] - return &Result{item: &(*chunk)[idx%chunkSize]} + return Result{item: &(*chunk)[idx%chunkSize]} } if mg.sorted { @@ -89,7 +89,7 @@ func (mg *Merger) cacheable() bool { return mg.count < mergerCacheMax } -func (mg *Merger) mergedGet(idx int) *Result { +func (mg *Merger) mergedGet(idx int) Result { for i := len(mg.merged); i <= idx; i++ { minRank := minRank() minIdx := -1 @@ -100,7 +100,7 @@ func (mg *Merger) mergedGet(idx int) *Result { continue } if cursor >= 0 { - rank := list[cursor].rank + rank := list[cursor] if minIdx < 0 || compareRanks(rank, minRank, mg.tac) { minRank = rank minIdx = listIdx diff --git a/src/merger_test.go b/src/merger_test.go index a4adee1..b98aca8 100644 --- a/src/merger_test.go +++ b/src/merger_test.go @@ -15,11 +15,11 @@ func assert(t *testing.T, cond bool, msg ...string) { } } -func randResult() *Result { +func randResult() Result { str := fmt.Sprintf("%d", rand.Uint32()) - return &Result{ - item: &Item{text: util.RunesToChars([]rune(str))}, - rank: rank{index: rand.Int31()}} + chars := util.RunesToChars([]rune(str)) + chars.Index = rand.Int31() + return Result{item: &Item{text: chars}} } func TestEmptyMerger(t *testing.T) { @@ -29,14 +29,14 @@ func TestEmptyMerger(t *testing.T) { assert(t, len(EmptyMerger.merged) == 0, "Invalid merged list") } -func buildLists(partiallySorted bool) ([][]*Result, []*Result) { +func buildLists(partiallySorted bool) ([][]Result, []Result) { numLists := 4 - lists := make([][]*Result, numLists) + lists := make([][]Result, numLists) cnt := 0 for i := 0; i < numLists; i++ { numResults := rand.Int() % 20 cnt += numResults - lists[i] = make([]*Result, numResults) + lists[i] = make([]Result, numResults) for j := 0; j < numResults; j++ { item := randResult() lists[i][j] = item @@ -45,7 +45,7 @@ func buildLists(partiallySorted bool) ([][]*Result, []*Result) { sort.Sort(ByRelevance(lists[i])) } } - items := []*Result{} + items := []Result{} for _, list := range lists { items = append(items, list...) } diff --git a/src/pattern.go b/src/pattern.go index 07ed9cd..97ee8fd 100644 --- a/src/pattern.go +++ b/src/pattern.go @@ -243,7 +243,7 @@ func (p *Pattern) CacheKey() string { } // Match returns the list of matches Items in the given Chunk -func (p *Pattern) Match(chunk *Chunk, slab *util.Slab) []*Result { +func (p *Pattern) Match(chunk *Chunk, slab *util.Slab) []Result { // ChunkCache: Exact match cacheKey := p.CacheKey() if p.cacheable { @@ -263,19 +263,19 @@ func (p *Pattern) Match(chunk *Chunk, slab *util.Slab) []*Result { return matches } -func (p *Pattern) matchChunk(chunk *Chunk, space []*Result, slab *util.Slab) []*Result { - matches := []*Result{} +func (p *Pattern) matchChunk(chunk *Chunk, space []Result, slab *util.Slab) []Result { + matches := []Result{} if space == nil { for idx := range *chunk { if match, _, _ := p.MatchItem(&(*chunk)[idx], false, slab); match != nil { - matches = append(matches, match) + matches = append(matches, *match) } } } else { for _, result := range space { if match, _, _ := p.MatchItem(result.item, false, slab); match != nil { - matches = append(matches, match) + matches = append(matches, *match) } } } @@ -286,14 +286,16 @@ func (p *Pattern) matchChunk(chunk *Chunk, space []*Result, slab *util.Slab) []* func (p *Pattern) MatchItem(item *Item, withPos bool, slab *util.Slab) (*Result, []Offset, *[]int) { if p.extended { if offsets, bonus, pos := p.extendedMatch(item, withPos, slab); len(offsets) == len(p.termSets) { - return buildResult(item, offsets, bonus), offsets, pos + result := buildResult(item, offsets, bonus) + return &result, offsets, pos } return nil, nil, nil } offset, bonus, pos := p.basicMatch(item, withPos, slab) if sidx := offset[0]; sidx >= 0 { offsets := []Offset{offset} - return buildResult(item, offsets, bonus), offsets, pos + result := buildResult(item, offsets, bonus) + return &result, offsets, pos } return nil, nil, nil } diff --git a/src/result.go b/src/result.go index fd4d1a9..2df101b 100644 --- a/src/result.go +++ b/src/result.go @@ -19,22 +19,17 @@ type colorOffset struct { index int32 } -type rank struct { - points [4]uint16 - index int32 -} - type Result struct { - item *Item - rank rank + item *Item + points [4]uint16 } -func buildResult(item *Item, offsets []Offset, score int) *Result { +func buildResult(item *Item, offsets []Offset, score int) Result { if len(offsets) > 1 { sort.Sort(ByOrder(offsets)) } - result := Result{item: item, rank: rank{index: item.Index()}} + result := Result{item: item} numChars := item.text.Length() minBegin := math.MaxUint16 minEnd := math.MaxUint16 @@ -75,10 +70,10 @@ func buildResult(item *Item, offsets []Offset, score int) *Result { } } } - result.rank.points[idx] = val + result.points[idx] = val } - return &result + return result } // Sort criteria to use. Never changes once fzf is started. @@ -89,8 +84,8 @@ func (result *Result) Index() int32 { return result.item.Index() } -func minRank() rank { - return rank{index: 0, points: [4]uint16{math.MaxUint16, 0, 0, 0}} +func minRank() Result { + return Result{item: &nilItem, points: [4]uint16{math.MaxUint16, 0, 0, 0}} } func (result *Result) colorOffsets(matchOffsets []Offset, theme *tui.ColorTheme, color tui.ColorPair, attr tui.Attr, current bool) []colorOffset { @@ -201,7 +196,7 @@ func (a ByOrder) Less(i, j int) bool { } // ByRelevance is for sorting Items -type ByRelevance []*Result +type ByRelevance []Result func (a ByRelevance) Len() int { return len(a) @@ -212,11 +207,11 @@ func (a ByRelevance) Swap(i, j int) { } func (a ByRelevance) Less(i, j int) bool { - return compareRanks((*a[i]).rank, (*a[j]).rank, false) + return compareRanks(a[i], a[j], false) } // ByRelevanceTac is for sorting Items -type ByRelevanceTac []*Result +type ByRelevanceTac []Result func (a ByRelevanceTac) Len() int { return len(a) @@ -227,10 +222,10 @@ func (a ByRelevanceTac) Swap(i, j int) { } func (a ByRelevanceTac) Less(i, j int) bool { - return compareRanks((*a[i]).rank, (*a[j]).rank, true) + return compareRanks(a[i], a[j], true) } -func compareRanks(irank rank, jrank rank, tac bool) bool { +func compareRanks(irank Result, jrank Result, tac bool) bool { for idx := 0; idx < 4; idx++ { left := irank.points[idx] right := jrank.points[idx] @@ -240,5 +235,5 @@ func compareRanks(irank rank, jrank rank, tac bool) bool { return false } } - return (irank.index <= jrank.index) != tac + return (irank.item.Index() <= jrank.item.Index()) != tac } diff --git a/src/result_test.go b/src/result_test.go index 8c74691..1d86b1d 100644 --- a/src/result_test.go +++ b/src/result_test.go @@ -31,10 +31,10 @@ func TestOffsetSort(t *testing.T) { } func TestRankComparison(t *testing.T) { - rank := func(vals ...uint16) rank { - return rank{ + rank := func(vals ...uint16) Result { + return Result{ points: [4]uint16{vals[0], vals[1], vals[2], vals[3]}, - index: int32(vals[4])} + item: &Item{text: util.Chars{Index: int32(vals[4])}}} } if compareRanks(rank(3, 0, 0, 0, 5), rank(2, 0, 0, 0, 7), false) || !compareRanks(rank(3, 0, 0, 0, 5), rank(3, 0, 0, 0, 6), false) || @@ -59,23 +59,23 @@ func TestResultRank(t *testing.T) { strs := [][]rune{[]rune("foo"), []rune("foobar"), []rune("bar"), []rune("baz")} item1 := buildResult( withIndex(&Item{text: util.RunesToChars(strs[0])}, 1), []Offset{}, 2) - if item1.rank.points[0] != math.MaxUint16-2 || // Bonus - item1.rank.points[1] != 3 || // Length - item1.rank.points[2] != 0 || // Unused - item1.rank.points[3] != 0 || // Unused + if item1.points[0] != math.MaxUint16-2 || // Bonus + item1.points[1] != 3 || // Length + item1.points[2] != 0 || // Unused + item1.points[3] != 0 || // Unused item1.item.Index() != 1 { - t.Error(item1.rank) + t.Error(item1) } // Only differ in index item2 := buildResult(&Item{text: util.RunesToChars(strs[0])}, []Offset{}, 2) - items := []*Result{item1, item2} + items := []Result{item1, item2} sort.Sort(ByRelevance(items)) if items[0] != item2 || items[1] != item1 { t.Error(items) } - items = []*Result{item2, item1, item1, item2} + items = []Result{item2, item1, item1, item2} sort.Sort(ByRelevance(items)) if items[0] != item2 || items[1] != item2 || items[2] != item1 || items[3] != item1 { @@ -91,7 +91,7 @@ func TestResultRank(t *testing.T) { withIndex(&Item{}, 2), []Offset{Offset{1, 3}, Offset{5, 7}}, 5) item6 := buildResult( withIndex(&Item{}, 2), []Offset{Offset{1, 2}, Offset{6, 7}}, 6) - items = []*Result{item1, item2, item3, item4, item5, item6} + items = []Result{item1, item2, item3, item4, item5, item6} sort.Sort(ByRelevance(items)) if !(items[0] == item6 && items[1] == item5 && items[2] == item4 && items[3] == item3 && diff --git a/src/terminal.go b/src/terminal.go index d3c808d..d4f4c85 100644 --- a/src/terminal.go +++ b/src/terminal.go @@ -714,7 +714,7 @@ func (t *Terminal) printHeader() { colors: colors} t.move(line, 2, true) - t.printHighlighted(&Result{item: item}, + t.printHighlighted(Result{item: item}, tui.AttrRegular, tui.ColHeader, tui.ColDefault, false, false) } } @@ -742,7 +742,7 @@ func (t *Terminal) printList() { } } -func (t *Terminal) printItem(result *Result, line int, i int, current bool) { +func (t *Terminal) printItem(result Result, line int, i int, current bool) { item := result.item _, selected := t.selected[item.Index()] label := " " @@ -758,7 +758,7 @@ func (t *Terminal) printItem(result *Result, line int, i int, current bool) { // Avoid unnecessary redraw newLine := itemLine{current: current, selected: selected, label: label, - result: *result, queryLen: len(t.input), width: 0} + result: result, queryLen: len(t.input), width: 0} prevLine := t.prevLines[i] if prevLine.current == newLine.current && prevLine.selected == newLine.selected && @@ -840,7 +840,7 @@ func (t *Terminal) overflow(runes []rune, max int) bool { return t.displayWidthWithLimit(runes, 0, max) > max } -func (t *Terminal) printHighlighted(result *Result, attr tui.Attr, col1 tui.ColorPair, col2 tui.ColorPair, current bool, match bool) int { +func (t *Terminal) printHighlighted(result Result, attr tui.Attr, col1 tui.ColorPair, col2 tui.ColorPair, current bool, match bool) int { item := result.item // Overflow