mirror of
https://github.com/junegunn/fzf.git
synced 2025-11-16 07:13:48 -05:00
Fix selection lost on revision bump
This commit is contained in:
@@ -41,6 +41,13 @@ func (c *Chunk) IsFull() bool {
|
||||
return c.count == chunkSize
|
||||
}
|
||||
|
||||
func (c *Chunk) lastIndex(minValue int32) int32 {
|
||||
if c.count == 0 {
|
||||
return minValue
|
||||
}
|
||||
return c.items[c.count-1].Index() + 1 // Exclusive
|
||||
}
|
||||
|
||||
func (cl *ChunkList) lastChunk() *Chunk {
|
||||
return cl.chunks[len(cl.chunks)-1]
|
||||
}
|
||||
|
||||
@@ -165,6 +165,7 @@ func (m *Matcher) scan(request MatchRequest) (*Merger, bool) {
|
||||
}
|
||||
|
||||
minIndex := request.chunks[0].items[0].Index()
|
||||
maxIndex := request.chunks[numChunks-1].lastIndex(minIndex)
|
||||
cancelled := util.NewAtomicBool(false)
|
||||
|
||||
slices := m.sliceChunks(request.chunks)
|
||||
@@ -236,7 +237,7 @@ func (m *Matcher) scan(request MatchRequest) (*Merger, bool) {
|
||||
partialResult := <-resultChan
|
||||
partialResults[partialResult.index] = partialResult.matches
|
||||
}
|
||||
return NewMerger(pattern, partialResults, m.sort && request.pattern.sortable, m.tac, request.revision, minIndex), false
|
||||
return NewMerger(pattern, partialResults, m.sort && request.pattern.sortable, m.tac, request.revision, minIndex, maxIndex), false
|
||||
}
|
||||
|
||||
// Reset is called to interrupt/signal the ongoing search
|
||||
|
||||
@@ -4,7 +4,7 @@ import "fmt"
|
||||
|
||||
// EmptyMerger is a Merger with no data
|
||||
func EmptyMerger(revision revision) *Merger {
|
||||
return NewMerger(nil, [][]Result{}, false, false, revision, 0)
|
||||
return NewMerger(nil, [][]Result{}, false, false, revision, 0, 0)
|
||||
}
|
||||
|
||||
// Merger holds a set of locally sorted lists of items and provides the view of
|
||||
@@ -22,14 +22,16 @@ type Merger struct {
|
||||
pass bool
|
||||
revision revision
|
||||
minIndex int32
|
||||
maxIndex int32
|
||||
}
|
||||
|
||||
// PassMerger returns a new Merger that simply returns the items in the
|
||||
// original order
|
||||
func PassMerger(chunks *[]*Chunk, tac bool, revision revision) *Merger {
|
||||
var minIndex int32
|
||||
var minIndex, maxIndex int32
|
||||
if len(*chunks) > 0 {
|
||||
minIndex = (*chunks)[0].items[0].Index()
|
||||
maxIndex = (*chunks)[len(*chunks)-1].lastIndex(minIndex)
|
||||
}
|
||||
mg := Merger{
|
||||
pattern: nil,
|
||||
@@ -38,7 +40,8 @@ func PassMerger(chunks *[]*Chunk, tac bool, revision revision) *Merger {
|
||||
count: 0,
|
||||
pass: true,
|
||||
revision: revision,
|
||||
minIndex: minIndex}
|
||||
minIndex: minIndex,
|
||||
maxIndex: maxIndex}
|
||||
|
||||
for _, chunk := range *mg.chunks {
|
||||
mg.count += chunk.count
|
||||
@@ -47,7 +50,7 @@ func PassMerger(chunks *[]*Chunk, tac bool, revision revision) *Merger {
|
||||
}
|
||||
|
||||
// NewMerger returns a new Merger
|
||||
func NewMerger(pattern *Pattern, lists [][]Result, sorted bool, tac bool, revision revision, minIndex int32) *Merger {
|
||||
func NewMerger(pattern *Pattern, lists [][]Result, sorted bool, tac bool, revision revision, minIndex int32, maxIndex int32) *Merger {
|
||||
mg := Merger{
|
||||
pattern: pattern,
|
||||
lists: lists,
|
||||
@@ -59,7 +62,8 @@ func NewMerger(pattern *Pattern, lists [][]Result, sorted bool, tac bool, revisi
|
||||
final: false,
|
||||
count: 0,
|
||||
revision: revision,
|
||||
minIndex: minIndex}
|
||||
minIndex: minIndex,
|
||||
maxIndex: maxIndex}
|
||||
|
||||
for _, list := range mg.lists {
|
||||
mg.count += len(list)
|
||||
|
||||
@@ -58,7 +58,7 @@ func TestMergerUnsorted(t *testing.T) {
|
||||
cnt := len(items)
|
||||
|
||||
// Not sorted: same order
|
||||
mg := NewMerger(nil, lists, false, false, revision{}, 0)
|
||||
mg := NewMerger(nil, lists, false, false, revision{}, 0, 0)
|
||||
assert(t, cnt == mg.Length(), "Invalid Length")
|
||||
for i := 0; i < cnt; i++ {
|
||||
assert(t, items[i] == mg.Get(i), "Invalid Get")
|
||||
@@ -70,7 +70,7 @@ func TestMergerSorted(t *testing.T) {
|
||||
cnt := len(items)
|
||||
|
||||
// Sorted sorted order
|
||||
mg := NewMerger(nil, lists, true, false, revision{}, 0)
|
||||
mg := NewMerger(nil, lists, true, false, revision{}, 0, 0)
|
||||
assert(t, cnt == mg.Length(), "Invalid Length")
|
||||
sort.Sort(ByRelevance(items))
|
||||
for i := 0; i < cnt; i++ {
|
||||
@@ -80,7 +80,7 @@ func TestMergerSorted(t *testing.T) {
|
||||
}
|
||||
|
||||
// Inverse order
|
||||
mg2 := NewMerger(nil, lists, true, false, revision{}, 0)
|
||||
mg2 := NewMerger(nil, lists, true, false, revision{}, 0, 0)
|
||||
for i := cnt - 1; i >= 0; i-- {
|
||||
if items[i] != mg2.Get(i) {
|
||||
t.Error("Not sorted", items[i], mg2.Get(i))
|
||||
|
||||
@@ -1680,12 +1680,12 @@ func (t *Terminal) UpdateList(merger *Merger) {
|
||||
// Trimmed by --tail: filter selection by index
|
||||
filtered := make(map[int32]selectedItem)
|
||||
minIndex := merger.minIndex
|
||||
maxIndex := minIndex + int32(merger.Length())
|
||||
maxIndex := merger.maxIndex
|
||||
for k, v := range t.selected {
|
||||
var included bool
|
||||
if maxIndex > minIndex {
|
||||
included = k >= minIndex && k < maxIndex
|
||||
} else { // int32 overflow [==> <==]
|
||||
} else if maxIndex < minIndex { // int32 overflow [==> <==]
|
||||
included = k >= minIndex || k < maxIndex
|
||||
}
|
||||
if included {
|
||||
|
||||
@@ -2002,4 +2002,37 @@ class TestCore < TestInteractive
|
||||
tmux.until { assert_equal 0, it.select_count }
|
||||
tmux.until { refute it.any_include?('Selected') }
|
||||
end
|
||||
|
||||
def test_preserve_selection_on_revision_bump
|
||||
tmux.send_keys %(seq 100 | #{FZF} --multi --sync --query "'1" --bind 'a:select-all+change-header(pressed a),b:change-header(pressed b)+change-nth(1),c:exclude'), :Enter
|
||||
tmux.until do
|
||||
assert_equal 20, it.match_count
|
||||
assert_equal 0, it.select_count
|
||||
end
|
||||
tmux.send_keys :a
|
||||
tmux.until do
|
||||
assert_equal 20, it.match_count
|
||||
assert_equal 20, it.select_count
|
||||
assert it.any_include?('pressed a')
|
||||
end
|
||||
tmux.send_keys :b
|
||||
tmux.until do
|
||||
assert_equal 20, it.match_count
|
||||
assert_equal 20, it.select_count
|
||||
refute it.any_include?('pressed a')
|
||||
assert it.any_include?('pressed b')
|
||||
end
|
||||
tmux.send_keys :a
|
||||
tmux.until do
|
||||
assert_equal 20, it.match_count
|
||||
assert_equal 20, it.select_count
|
||||
assert it.any_include?('pressed a')
|
||||
refute it.any_include?('pressed b')
|
||||
end
|
||||
tmux.send_keys :c
|
||||
tmux.until do
|
||||
assert_equal 19, it.match_count
|
||||
assert_equal 19, it.select_count
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
Reference in New Issue
Block a user