mirror of
https://github.com/jesseduffield/lazygit.git
synced 2026-09-10 07:36:27 -04:00
Take the write mutex when clearing view lines and reading the buffer
A view's line buffer, its viewLines/tainted flags, and its hover state are all written from the command-task goroutine (under writeMutex) as it renders. But three accessors reached that same state from the UI thread without the lock: SetView and the GUI-resize path cleared a view's lines directly, viewsToRedrawContentOnly read the tainted flag, and Buffer read the line buffer. Each raced a rendering task. Guard them with writeMutex, matching the view's other buffer accessors. These are reads/clears of state writeMutex already protects, not new callers of it -- the view's geometry stays outside the mutex. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
f6eaed8cd4
commit
65cb439076
|
|
@ -385,7 +385,7 @@ func (g *Gui) SetView(name string, x0, y0, x1, y1 int, overlaps byte) (*View, er
|
|||
v.y1 = y1
|
||||
|
||||
if sizeChanged {
|
||||
v.clearViewLines()
|
||||
v.ClearViewLines()
|
||||
|
||||
if v.Editable {
|
||||
cursorX, cursorY := v.TextArea.GetCursorXY()
|
||||
|
|
@ -1461,7 +1461,7 @@ func (g *Gui) flush() error {
|
|||
// if GUI's size has changed, we need to redraw all views
|
||||
if maxX != g.maxX || maxY != g.maxY {
|
||||
for _, v := range g.views {
|
||||
v.clearViewLines()
|
||||
v.ClearViewLines()
|
||||
}
|
||||
}
|
||||
g.maxX, g.maxY = maxX, maxY
|
||||
|
|
@ -1500,7 +1500,7 @@ func viewsToRedrawContentOnly(views []*View) []*View {
|
|||
redrawIndexes := set.New[int]()
|
||||
|
||||
for i, v := range views {
|
||||
if !v.tainted && !redrawIndexes.Includes(i) {
|
||||
if !v.IsTainted() && !redrawIndexes.Includes(i) {
|
||||
continue
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -214,6 +214,16 @@ func (v *View) clearViewLines() {
|
|||
v.clearHover()
|
||||
}
|
||||
|
||||
// ClearViewLines is clearViewLines guarded by writeMutex. It's for callers on
|
||||
// the UI thread (the layout pass) that touch a view whose content a task
|
||||
// goroutine may be writing concurrently: viewLines/tainted/hover are all
|
||||
// buffer state that writeMutex protects.
|
||||
func (v *View) ClearViewLines() {
|
||||
v.writeMutex.Lock()
|
||||
defer v.writeMutex.Unlock()
|
||||
v.clearViewLines()
|
||||
}
|
||||
|
||||
type searcher struct {
|
||||
searchString string
|
||||
searchPositions []SearchPosition
|
||||
|
|
@ -1287,6 +1297,8 @@ func (v *View) updateSearchPositions() {
|
|||
|
||||
// IsTainted tells us if the view is tainted
|
||||
func (v *View) IsTainted() bool {
|
||||
v.writeMutex.Lock()
|
||||
defer v.writeMutex.Unlock()
|
||||
return v.tainted
|
||||
}
|
||||
|
||||
|
|
@ -1535,6 +1547,9 @@ func (v *View) BufferLines() []string {
|
|||
// Buffer returns a string with the contents of the view's internal
|
||||
// buffer.
|
||||
func (v *View) Buffer() string {
|
||||
v.writeMutex.Lock()
|
||||
defer v.writeMutex.Unlock()
|
||||
|
||||
return linesToString(v.lines)
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue