Skip to content

Commit 9525f29

Browse files
committed
fix(renderer): debounce resize renders
This change introduces a debounce mechanism to the cursed renderer's resize handling. When a resize event occurs, the renderer will now wait for a short duration before processing the resize. This prevents multiple full resize renders from occurring in quick succession, which can lead to performance issues and visual artifacts.
1 parent 15f884b commit 9525f29

File tree

1 file changed

+18
-1
lines changed

1 file changed

+18
-1
lines changed

cursed_renderer.go

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,13 +7,19 @@ import (
77
"io"
88
"strings"
99
"sync"
10+
"time"
1011

1112
"github.com/charmbracelet/colorprofile"
1213
uv "github.com/charmbracelet/ultraviolet"
1314
"github.com/charmbracelet/x/ansi"
1415
"github.com/lucasb-eyer/go-colorful"
1516
)
1617

18+
// resizeDuration is the duration to wait after a resize event before
19+
// processing another resize event. This is to avoid processing multiple resize
20+
// events in quick succession.
21+
const resizeDuration = 100 * time.Millisecond // milliseconds
22+
1723
type cursedRenderer struct {
1824
w io.Writer
1925
buf bytes.Buffer // updates buffer to be flushed to [w]
@@ -32,6 +38,7 @@ type cursedRenderer struct {
3238
mapnl bool
3339
syncdUpdates bool // whether to use synchronized output mode for updates
3440
prependLines []string
41+
resizeTime time.Time // last resize time
3542
}
3643

3744
var _ renderer = &cursedRenderer{}
@@ -261,11 +268,20 @@ func (s *cursedRenderer) flush(closing bool) error {
261268
}
262269
}
263270

264-
if s.lastView != nil && *s.lastView == view && frameArea == s.cellbuf.Bounds() {
271+
// Avoid quick successive resizes rendering.
272+
if !s.resizeTime.IsZero() && time.Since(s.resizeTime) < resizeDuration &&
273+
// Make sure we don't skip prepended line requests.
274+
len(s.prependLines) == 0 &&
275+
// If the view is that same, we skip the render.
276+
s.lastView != nil && *s.lastView == view &&
277+
// If the frame area hasn't changed, we skip the render.
278+
frameArea == s.cellbuf.Bounds() {
265279
// No changes, nothing to do.
266280
return nil
267281
}
268282

283+
s.resizeTime = time.Time{} // reset resize time
284+
269285
if frameArea != s.cellbuf.Bounds() {
270286
s.scr.Erase() // Force a full redraw to avoid artifacts.
271287

@@ -624,6 +640,7 @@ func (s *cursedRenderer) resize(w, h int) {
624640
s.scr.Erase()
625641
s.width, s.height = w, h
626642
s.scr.Resize(s.width, s.height)
643+
s.resizeTime = time.Now()
627644
s.mu.Unlock()
628645
}
629646

0 commit comments

Comments
 (0)