forked from Mirrors/bubbletea
fix: race condition on repaint with alt screen
I didn't realise at the time, but the tea.Program and the renderer share the mutex. This make the code difficult to reason about - it turns out the program sometimes acquires the lock and then calls the `setAltScreen` method of the renderer which in turns calls `repaint`. That causes a deadlock as `repaint` is trying to acquire the lock too.
This commit is contained in:
parent
50a8461fbf
commit
958dc20024
|
@ -230,9 +230,7 @@ func (r *standardRenderer) write(s string) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *standardRenderer) repaint() {
|
func (r *standardRenderer) repaint() {
|
||||||
r.mtx.Lock()
|
|
||||||
r.lastRender = ""
|
r.lastRender = ""
|
||||||
r.mtx.Unlock()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *standardRenderer) altScreen() bool {
|
func (r *standardRenderer) altScreen() bool {
|
||||||
|
@ -350,7 +348,9 @@ func (r *standardRenderer) handleMessages(msg Msg) {
|
||||||
case repaintMsg:
|
case repaintMsg:
|
||||||
// Force a repaint by clearing the render cache as we slide into a
|
// Force a repaint by clearing the render cache as we slide into a
|
||||||
// render.
|
// render.
|
||||||
|
r.mtx.Lock()
|
||||||
r.repaint()
|
r.repaint()
|
||||||
|
r.mtx.Unlock()
|
||||||
|
|
||||||
case WindowSizeMsg:
|
case WindowSizeMsg:
|
||||||
r.mtx.Lock()
|
r.mtx.Lock()
|
||||||
|
@ -363,7 +363,9 @@ func (r *standardRenderer) handleMessages(msg Msg) {
|
||||||
|
|
||||||
// Force a repaint on the area where the scrollable stuff was in this
|
// Force a repaint on the area where the scrollable stuff was in this
|
||||||
// update cycle
|
// update cycle
|
||||||
|
r.mtx.Lock()
|
||||||
r.repaint()
|
r.repaint()
|
||||||
|
r.mtx.Unlock()
|
||||||
|
|
||||||
case syncScrollAreaMsg:
|
case syncScrollAreaMsg:
|
||||||
// Re-render scrolling area
|
// Re-render scrolling area
|
||||||
|
@ -372,7 +374,9 @@ func (r *standardRenderer) handleMessages(msg Msg) {
|
||||||
r.insertTop(msg.lines, msg.topBoundary, msg.bottomBoundary)
|
r.insertTop(msg.lines, msg.topBoundary, msg.bottomBoundary)
|
||||||
|
|
||||||
// Force non-scrolling stuff to repaint in this update cycle
|
// Force non-scrolling stuff to repaint in this update cycle
|
||||||
|
r.mtx.Lock()
|
||||||
r.repaint()
|
r.repaint()
|
||||||
|
r.mtx.Unlock()
|
||||||
|
|
||||||
case scrollUpMsg:
|
case scrollUpMsg:
|
||||||
r.insertTop(msg.lines, msg.topBoundary, msg.bottomBoundary)
|
r.insertTop(msg.lines, msg.topBoundary, msg.bottomBoundary)
|
||||||
|
|
2
tea.go
2
tea.go
|
@ -503,7 +503,9 @@ func (p *Program) StartReturningModel() (Model, error) {
|
||||||
continue
|
continue
|
||||||
|
|
||||||
case WindowSizeMsg:
|
case WindowSizeMsg:
|
||||||
|
p.mtx.Lock()
|
||||||
p.renderer.repaint()
|
p.renderer.repaint()
|
||||||
|
p.mtx.Unlock()
|
||||||
|
|
||||||
case enterAltScreenMsg:
|
case enterAltScreenMsg:
|
||||||
p.EnterAltScreen()
|
p.EnterAltScreen()
|
||||||
|
|
Loading…
Reference in New Issue