Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 3 additions & 22 deletions internal/terminal/app.go
Original file line number Diff line number Diff line change
Expand Up @@ -480,10 +480,8 @@ func (app *App) loop(ctx context.Context) {
stopTimer(messageWarmTimer)
defer messageWarmTimer.Stop()

dirty := true
dirty := false
for {
dirty = app.drawDirtyFrame(ctx, dirty)

shouldQuit, nextDirty := app.runLoopStep(ctx, workTicker, frameTicker, extensionTimer, messageWarmTimer, dirty)
if shouldQuit {
return
Expand All @@ -493,16 +491,6 @@ func (app *App) loop(ctx context.Context) {
}
}

func (app *App) drawDirtyFrame(ctx context.Context, dirty bool) bool {
if dirty && !app.throttleDraws() {
app.draw(ctx)

return false
}

return dirty
}

func (app *App) runLoopStep(
ctx context.Context,
workTicker *time.Ticker,
Expand Down Expand Up @@ -530,10 +518,7 @@ func (app *App) runLoopStep(

return false, true
case <-app.frameTick(frameTicker, dirty):
if dirty {
app.emitExtensionRuntimeEventOrMessage(ctx, extensionEventTick, map[string]any{})
}

app.emitExtensionRuntimeEventOrMessage(ctx, extensionEventTick, map[string]any{})
app.draw(ctx)

return false, false
Expand Down Expand Up @@ -649,7 +634,7 @@ func (app *App) workTick(ticker *time.Ticker) <-chan time.Time {
}

func (app *App) frameTick(ticker *time.Ticker, dirty bool) <-chan time.Time {
if app.throttleDraws() || dirty {
if dirty {
return ticker.C
}

Expand Down Expand Up @@ -726,10 +711,6 @@ func stopTimer(timer *time.Timer) {
}
}

func (app *App) throttleDraws() bool {
return app.busy()
}

func (app *App) busy() bool {
return app.working || app.authWorking || app.compacting
}
Expand Down
70 changes: 51 additions & 19 deletions internal/terminal/render_internal_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -866,30 +866,62 @@ func runLoopStepWithContextAndDormantTimers(
)
}

func TestDrawDirtyFrame(t *testing.T) {
func TestFrameTickOnlyRunsForDirtyState(t *testing.T) {
t.Parallel()

testCases := []struct {
name string
dirty bool
wantDraw bool
}{
{name: "clean frame skips draw", dirty: false, wantDraw: false},
{name: "dirty frame draws", dirty: true, wantDraw: true},
}
ticker := time.NewTicker(time.Hour)
t.Cleanup(ticker.Stop)

for _, testCase := range testCases {
t.Run(testCase.name, func(t *testing.T) {
t.Parallel()
app := newScrollableRenderTestApp(t)
app.working = true

app := newScrollableRenderTestApp(t)
screen, ok := app.screen.(*clipboardScreen)
require.True(t, ok)
assert.Nil(t, app.frameTick(ticker, false), "busy but unchanged UI must not redraw")
assert.Equal(t, ticker.C, app.frameTick(ticker, true), "dirty UI must wait for the frame tick")
}
Comment thread
coderabbitai[bot] marked this conversation as resolved.

assert.False(t, app.drawDirtyFrame(context.Background(), testCase.dirty))
assert.Equal(t, testCase.wantDraw, len(screen.content) > 0)
})
}
func TestRunLoopStepDrawsDirtyFrameAndEmitsTick(t *testing.T) {
t.Parallel()

app := newExtensionRuntimeTestApp(t, `
librecode.on("tick", function()
librecode.buf.set_text("tick_events", "tick")
end)
`)
screen := newClipboardScreen()
screen.SetSize(40, 8)
app.screen = screen
app.renderer = tui.NewRenderer(screen)
app.frame = nil

workTicker := time.NewTicker(time.Hour)
frameTicker := time.NewTicker(time.Millisecond)
extensionTimer := time.NewTimer(time.Hour)
messageWarmTimer := time.NewTimer(time.Hour)

t.Cleanup(func() {
workTicker.Stop()
frameTicker.Stop()
stopTimer(extensionTimer)
stopTimer(messageWarmTimer)
})

ctx, cancel := context.WithTimeout(t.Context(), time.Second)
defer cancel()

shouldQuit, dirty := app.runLoopStep(
ctx,
workTicker,
frameTicker,
extensionTimer,
messageWarmTimer,
true,
)

assert.False(t, shouldQuit)
assert.False(t, dirty)
require.NotNil(t, app.frame, "dirty frame tick must draw")
require.Contains(t, app.extensionUI.Buffers, "tick_events", "dirty frame tick must emit tick")
assert.Equal(t, "tick", app.extensionUI.Buffers["tick_events"].Text)
}

func TestDrawLatestResize(t *testing.T) {
Expand Down