mirror of
https://github.com/junegunn/fzf.git
synced 2025-11-15 14:53:47 -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
|
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 {
|
func (cl *ChunkList) lastChunk() *Chunk {
|
||||||
return cl.chunks[len(cl.chunks)-1]
|
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()
|
minIndex := request.chunks[0].items[0].Index()
|
||||||
|
maxIndex := request.chunks[numChunks-1].lastIndex(minIndex)
|
||||||
cancelled := util.NewAtomicBool(false)
|
cancelled := util.NewAtomicBool(false)
|
||||||
|
|
||||||
slices := m.sliceChunks(request.chunks)
|
slices := m.sliceChunks(request.chunks)
|
||||||
@@ -236,7 +237,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(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
|
// Reset is called to interrupt/signal the ongoing search
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ import "fmt"
|
|||||||
|
|
||||||
// EmptyMerger is a Merger with no data
|
// EmptyMerger is a Merger with no data
|
||||||
func EmptyMerger(revision revision) *Merger {
|
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
|
// Merger holds a set of locally sorted lists of items and provides the view of
|
||||||
@@ -22,14 +22,16 @@ type Merger struct {
|
|||||||
pass bool
|
pass bool
|
||||||
revision revision
|
revision revision
|
||||||
minIndex int32
|
minIndex int32
|
||||||
|
maxIndex int32
|
||||||
}
|
}
|
||||||
|
|
||||||
// PassMerger returns a new Merger that simply returns the items in the
|
// PassMerger returns a new Merger that simply returns the items in the
|
||||||
// original order
|
// original order
|
||||||
func PassMerger(chunks *[]*Chunk, tac bool, revision revision) *Merger {
|
func PassMerger(chunks *[]*Chunk, tac bool, revision revision) *Merger {
|
||||||
var minIndex int32
|
var minIndex, maxIndex int32
|
||||||
if len(*chunks) > 0 {
|
if len(*chunks) > 0 {
|
||||||
minIndex = (*chunks)[0].items[0].Index()
|
minIndex = (*chunks)[0].items[0].Index()
|
||||||
|
maxIndex = (*chunks)[len(*chunks)-1].lastIndex(minIndex)
|
||||||
}
|
}
|
||||||
mg := Merger{
|
mg := Merger{
|
||||||
pattern: nil,
|
pattern: nil,
|
||||||
@@ -38,7 +40,8 @@ func PassMerger(chunks *[]*Chunk, tac bool, revision revision) *Merger {
|
|||||||
count: 0,
|
count: 0,
|
||||||
pass: true,
|
pass: true,
|
||||||
revision: revision,
|
revision: revision,
|
||||||
minIndex: minIndex}
|
minIndex: minIndex,
|
||||||
|
maxIndex: maxIndex}
|
||||||
|
|
||||||
for _, chunk := range *mg.chunks {
|
for _, chunk := range *mg.chunks {
|
||||||
mg.count += chunk.count
|
mg.count += chunk.count
|
||||||
@@ -47,7 +50,7 @@ func PassMerger(chunks *[]*Chunk, tac bool, revision revision) *Merger {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// NewMerger returns a new 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{
|
mg := Merger{
|
||||||
pattern: pattern,
|
pattern: pattern,
|
||||||
lists: lists,
|
lists: lists,
|
||||||
@@ -59,7 +62,8 @@ func NewMerger(pattern *Pattern, lists [][]Result, sorted bool, tac bool, revisi
|
|||||||
final: false,
|
final: false,
|
||||||
count: 0,
|
count: 0,
|
||||||
revision: revision,
|
revision: revision,
|
||||||
minIndex: minIndex}
|
minIndex: minIndex,
|
||||||
|
maxIndex: maxIndex}
|
||||||
|
|
||||||
for _, list := range mg.lists {
|
for _, list := range mg.lists {
|
||||||
mg.count += len(list)
|
mg.count += len(list)
|
||||||
|
|||||||
@@ -58,7 +58,7 @@ func TestMergerUnsorted(t *testing.T) {
|
|||||||
cnt := len(items)
|
cnt := len(items)
|
||||||
|
|
||||||
// Not sorted: same order
|
// 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")
|
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")
|
||||||
@@ -70,7 +70,7 @@ func TestMergerSorted(t *testing.T) {
|
|||||||
cnt := len(items)
|
cnt := len(items)
|
||||||
|
|
||||||
// Sorted sorted order
|
// 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")
|
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++ {
|
||||||
@@ -80,7 +80,7 @@ func TestMergerSorted(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Inverse order
|
// 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-- {
|
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))
|
||||||
|
|||||||
@@ -1680,12 +1680,12 @@ func (t *Terminal) UpdateList(merger *Merger) {
|
|||||||
// Trimmed by --tail: filter selection by index
|
// Trimmed by --tail: filter selection by index
|
||||||
filtered := make(map[int32]selectedItem)
|
filtered := make(map[int32]selectedItem)
|
||||||
minIndex := merger.minIndex
|
minIndex := merger.minIndex
|
||||||
maxIndex := minIndex + int32(merger.Length())
|
maxIndex := merger.maxIndex
|
||||||
for k, v := range t.selected {
|
for k, v := range t.selected {
|
||||||
var included bool
|
var included bool
|
||||||
if maxIndex > minIndex {
|
if maxIndex > minIndex {
|
||||||
included = k >= minIndex && k < maxIndex
|
included = k >= minIndex && k < maxIndex
|
||||||
} else { // int32 overflow [==> <==]
|
} else if maxIndex < minIndex { // int32 overflow [==> <==]
|
||||||
included = k >= minIndex || k < maxIndex
|
included = k >= minIndex || k < maxIndex
|
||||||
}
|
}
|
||||||
if included {
|
if included {
|
||||||
|
|||||||
@@ -2002,4 +2002,37 @@ class TestCore < TestInteractive
|
|||||||
tmux.until { assert_equal 0, it.select_count }
|
tmux.until { assert_equal 0, it.select_count }
|
||||||
tmux.until { refute it.any_include?('Selected') }
|
tmux.until { refute it.any_include?('Selected') }
|
||||||
end
|
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
|
end
|
||||||
|
|||||||
Reference in New Issue
Block a user