Add LAZYGIT_SLOW_RENDER debug knob for watching async render frames

Re-rendering a diff into a main view is asynchronous and lazy: the read
loop fills the view a screenful at a time and refreshes as it goes. When
debugging scroll-restore and flicker behaviour, the individual frames go by
too fast to see. Setting LAZYGIT_SLOW_RENDER=<milliseconds> sleeps that long
after each line is written, stretching the load out so the frames become
visible. It has no effect when unset, so it's safe to leave in.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
Stefan Haller
2026-08-15 15:30:27 +02:00
co-authored by Claude Opus 5
parent 94018de3e8
commit d65ee95942
+17
View File
@@ -4,7 +4,9 @@ import (
"bufio"
"fmt"
"io"
"os"
"os/exec"
"strconv"
"sync"
"sync/atomic"
"time"
@@ -320,6 +322,17 @@ func (self *ViewBufferManager) NewCmdTask(start func() (Cmd, io.Reader), prefix
// this to work out how many more lines, if any, we still need to read.
linesRead := 0
// Set LAZYGIT_SLOW_RENDER=<milliseconds> to sleep that long after each
// line is written to the view, stretching async loads out so the frames
// of a re-render become visible. Useful for debugging scroll/flicker
// behaviour; has no effect when the variable is unset.
var slowRenderPerLine time.Duration
if v := os.Getenv("LAZYGIT_SLOW_RENDER"); v != "" {
if ms, err := strconv.Atoi(v); err == nil {
slowRenderPerLine = time.Duration(ms) * time.Millisecond
}
}
outer:
for {
if stopped() {
@@ -373,6 +386,10 @@ func (self *ViewBufferManager) NewCmdTask(start func() (Cmd, io.Reader), prefix
lineWrittenChan <- struct{}{}
linesRead++
if slowRenderPerLine > 0 {
time.Sleep(slowRenderPerLine)
}
if linesRead == linesToRead.InitialRefreshAfter {
// We have read enough lines to fill the view, so do a first refresh
// here to show what we have. Continue reading and refresh again at