mirror of
https://github.com/junegunn/fzf.git
synced 2026-03-06 15:14:32 +08:00
Fix data race
This commit is contained in:
@@ -460,6 +460,11 @@ func Run(opts *Options) (int, error) {
|
|||||||
}
|
}
|
||||||
if val.withNth != nil {
|
if val.withNth != nil {
|
||||||
newTransformer := val.withNth.fn
|
newTransformer := val.withNth.fn
|
||||||
|
// Cancel any in-flight scan and block the terminal from reading
|
||||||
|
// items before mutating them in-place. Snapshot shares middle
|
||||||
|
// chunk pointers, so the matcher and terminal can race with us.
|
||||||
|
matcher.CancelScan()
|
||||||
|
terminal.PauseRendering()
|
||||||
// Reset cross-line ANSI state before re-processing all items
|
// Reset cross-line ANSI state before re-processing all items
|
||||||
lineAnsiState = nil
|
lineAnsiState = nil
|
||||||
prevLineAnsiState = nil
|
prevLineAnsiState = nil
|
||||||
@@ -476,6 +481,8 @@ func Run(opts *Options) (int, error) {
|
|||||||
}, func() {
|
}, func() {
|
||||||
nthTransformer = newTransformer
|
nthTransformer = newTransformer
|
||||||
})
|
})
|
||||||
|
terminal.ResumeRendering()
|
||||||
|
matcher.ResumeScan()
|
||||||
withNthChanged = true
|
withNthChanged = true
|
||||||
bump = true
|
bump = true
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -45,6 +45,8 @@ type Matcher struct {
|
|||||||
slab []*util.Slab
|
slab []*util.Slab
|
||||||
mergerCache map[string]MatchResult
|
mergerCache map[string]MatchResult
|
||||||
revision revision
|
revision revision
|
||||||
|
scanMutex sync.Mutex
|
||||||
|
cancelScan *util.AtomicBool
|
||||||
}
|
}
|
||||||
|
|
||||||
const (
|
const (
|
||||||
@@ -66,7 +68,8 @@ func NewMatcher(cache *ChunkCache, patternBuilder func([]rune) *Pattern,
|
|||||||
partitions: partitions,
|
partitions: partitions,
|
||||||
slab: make([]*util.Slab, partitions),
|
slab: make([]*util.Slab, partitions),
|
||||||
mergerCache: make(map[string]MatchResult),
|
mergerCache: make(map[string]MatchResult),
|
||||||
revision: revision}
|
revision: revision,
|
||||||
|
cancelScan: util.NewAtomicBool(false)}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Loop puts Matcher in action
|
// Loop puts Matcher in action
|
||||||
@@ -126,7 +129,9 @@ func (m *Matcher) Loop() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if result.merger == nil {
|
if result.merger == nil {
|
||||||
|
m.scanMutex.Lock()
|
||||||
result = m.scan(request)
|
result = m.scan(request)
|
||||||
|
m.scanMutex.Unlock()
|
||||||
}
|
}
|
||||||
|
|
||||||
if !result.cancelled {
|
if !result.cancelled {
|
||||||
@@ -238,7 +243,7 @@ func (m *Matcher) scan(request MatchRequest) MatchResult {
|
|||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
|
||||||
if m.reqBox.Peek(reqReset) {
|
if m.cancelScan.Get() || m.reqBox.Peek(reqReset) {
|
||||||
return MatchResult{nil, nil, wait()}
|
return MatchResult{nil, nil, wait()}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -269,6 +274,20 @@ func (m *Matcher) Reset(chunks []*Chunk, patternRunes []rune, cancel bool, final
|
|||||||
m.reqBox.Set(event, MatchRequest{chunks, pattern, final, sort, revision})
|
m.reqBox.Set(event, MatchRequest{chunks, pattern, final, sort, revision})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// CancelScan cancels any in-flight scan, waits for it to finish,
|
||||||
|
// and prevents new scans from starting until ResumeScan is called.
|
||||||
|
// This is used to safely mutate shared items (e.g., during with-nth changes).
|
||||||
|
func (m *Matcher) CancelScan() {
|
||||||
|
m.cancelScan.Set(true)
|
||||||
|
m.scanMutex.Lock()
|
||||||
|
m.cancelScan.Set(false)
|
||||||
|
}
|
||||||
|
|
||||||
|
// ResumeScan allows scans to proceed again after CancelScan.
|
||||||
|
func (m *Matcher) ResumeScan() {
|
||||||
|
m.scanMutex.Unlock()
|
||||||
|
}
|
||||||
|
|
||||||
func (m *Matcher) Stop() {
|
func (m *Matcher) Stop() {
|
||||||
m.reqBox.Set(reqQuit, nil)
|
m.reqBox.Set(reqQuit, nil)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1738,6 +1738,17 @@ func (t *Terminal) Input() (bool, []rune) {
|
|||||||
return paused, copySlice(src)
|
return paused, copySlice(src)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// PauseRendering blocks the terminal from reading items.
|
||||||
|
// Must be paired with ResumeRendering.
|
||||||
|
func (t *Terminal) PauseRendering() {
|
||||||
|
t.mutex.Lock()
|
||||||
|
}
|
||||||
|
|
||||||
|
// ResumeRendering releases the lock acquired by PauseRendering.
|
||||||
|
func (t *Terminal) ResumeRendering() {
|
||||||
|
t.mutex.Unlock()
|
||||||
|
}
|
||||||
|
|
||||||
// UpdateCount updates the count information
|
// UpdateCount updates the count information
|
||||||
func (t *Terminal) UpdateCount(cnt int, final bool, failedCommand *string) {
|
func (t *Terminal) UpdateCount(cnt int, final bool, failedCommand *string) {
|
||||||
t.mutex.Lock()
|
t.mutex.Lock()
|
||||||
|
|||||||
Reference in New Issue
Block a user