fix: draw a frame only when there is something new to show - #104
Merged
Conversation
The loop bracketed and drew on every 80ms tick regardless of whether anything had changed — `app.redraw` gated only the full clear above it, not the draw itself. An idle chart therefore put a DEC 2026 open/close pair on the wire about twelve times a second, forever, for a picture that was not moving: 244 repaints over a 20-second idle wait against 2 after load. It draws when something changed instead. Three sources: input (a key, a mouse report, a resize), the full-clear flag, and a fetch landing — which is the one model change no event announces, so it is detected rather than reported, by watching `Load::Loading` leave. The spinner is the exception that shapes the rest. It turns off `app.tick` with no event behind it, so a fetch in flight keeps the loop painting; the guard is `dirty || matches!(app.load, Load::Loading)` for exactly that reason. `tick` still advances every iteration, so it turns at the rate it always did. Three tests used "wait for N more repaints" to mean "give it time to have acted, then check nothing did" — an idiom the free-running timer was propping up. They now wait for the picture to hold still, which is both what they meant and what survives the app getting quieter. The fourth, `an_idle_chart_stops_writing`, gets a stronger claim than it had: it counted printable characters in idle frames because it could not stop the frames; now it asserts there are none, and that a keystroke still draws. Known and accepted: `today()` reads the clock when `--today` is absent, so a chart left open across midnight no longer self-corrects on the next tick. Any key fixes it, and the alternative is a wakeup every 80ms for the rest of the process's life. Closes #102 Signed-off-by: Vyncint Ng <115854244+vyncint@users.noreply.github.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Closes #102.
The bug
app.redrawgated only the full clear, not the draw itself, so the loop bracketed and drew on every 80 ms tick regardless of whether anything had changed. An idle chart put a DEC 2026 open/close pair on the wire ~12.5 times a second, forever, for a picture that was not moving.Measured: 244 repaints over a 20-second idle wait, against 2 immediately after load. Now: 0.
The fix
Draw when something changed. Three sources:
app.redrawimplies a draw, or the clear would blank the screen with nothing to repaint it;Load::Loadingleave.The spinner is the exception that shapes the guard
ui::loading()turns offapp.tickwith no event behind it, so a naive "draw only on change" would freeze it mid-fetch. The guard isdirty || matches!(app.load, Load::Loading)for exactly that reason, andtickstill advances every iteration so it turns at the rate it always did. This was the case I flagged as deciding whether #102 was a one-line guard or a real change — it is why the condition has two halves.Four tests had to move, and three of them get better for it
Three used "wait for N more repaints" to mean "give it time to have acted, then check nothing did" — an idiom the free-running timer was propping up. They now wait for the picture to hold still (
wait_stable), which is both what they actually meant and what survives the app getting quieter still.The fourth is the interesting one.
an_idle_chart_stops_writingcounted printable characters in idle frames and asserted they were zero — the next best thing available while the frames could not be stopped. Its claim is now strictly stronger: there are no idle frames. It asserts that, and that a keystroke still draws, so "idle" cannot be confused with "wedged".Known and accepted
today()reads the clock when--todayis absent, so a chart left open across midnight no longer self-corrects on the next tick. Any key fixes it, and the alternative is a wakeup every 80 ms for the life of the process. Recorded here rather than discovered later.240 tests pass; stress dispatched against this branch.