Skip to content

feat: Add Handle::update_tracked for conditional rebuilds#32

Merged
BinaryMuse merged 6 commits into
mainfrom
mkt/conditional-update
Apr 23, 2026
Merged

feat: Add Handle::update_tracked for conditional rebuilds#32
BinaryMuse merged 6 commits into
mainfrom
mkt/conditional-update

Conversation

@BinaryMuse

@BinaryMuse BinaryMuse commented Apr 23, 2026

Copy link
Copy Markdown
Member

Summary

  • Adds TrackedRef<'a, S>, a borrowing dirty-tracker that wraps &mut S — reads through Deref/read() don't set the dirty flag, writes through DerefMut do
  • Adds Handle::update_tracked() which only triggers a rebuild if the callback actually mutated state
  • Handle::update() is unchanged and always triggers a rebuild

Motivation

In apps with expensive view functions, high-frequency state updates that don't actually change values (e.g., an input handler setting is_input_blank = false when it's already false) still trigger full rebuilds. update_tracked lets callers opt into conditional rebuilds:

handle.update_tracked(|state| {
    let new_blank = text.is_empty();
    if state.read().is_input_blank != new_blank {
        state.is_input_blank = new_blank;
    }
});

Test plan

  • All 211 existing tests pass
  • Manual testing in atuin-ai TUI with rapid keystroke input

Add TrackedRef<'a, S>, a borrowing dirty-tracker that wraps &mut S.
Reads through Deref or read() don't set the dirty flag; writes through
DerefMut do.

Handle::update_tracked() accepts a callback receiving &mut TrackedRef
instead of &mut S. The application only marks itself dirty (triggering
a rebuild) if the callback actually mutated state. This allows callers
like input-change handlers to skip unnecessary rebuilds when the
relevant state hasn't changed (e.g., is_input_blank stays false while
typing additional characters).

Handle::update() is unchanged and always triggers a rebuild.
@BinaryMuse BinaryMuse marked this pull request as ready for review April 23, 2026 23:35
@greptile-apps

greptile-apps Bot commented Apr 23, 2026

Copy link
Copy Markdown

Greptile Summary

Adds TrackedRef<'a, S> and Handle::update_tracked() to enable conditional rebuilds — the callback only marks the app dirty if it actually writes through DerefMut. The implementation is correct: UpdateStateTracked is handled in all three dispatch paths, and the Deref/DerefMut split behaves exactly as documented.

Confidence Score: 5/5

Safe to merge — no logic issues found

All three message-dispatch paths handle the new variant, TrackedRef's dirty semantics are correct, and the only rough edge (remainder still using the verbose guard in renderer.rs) is a pure style inconsistency with no behavioral impact.

No files require special attention

Important Files Changed

Filename Overview
crates/eye_declare/src/component.rs Adds TrackedRef<'a, S> — borrowing dirty-tracker with correct Deref/DerefMut split; clean implementation
crates/eye_declare/src/app.rs Wires UpdateStateTracked message through all three dispatch paths (two select! arms + drain_updates) via apply_tracked_update helper; no gaps found
crates/eye_declare/src/renderer.rs Replaces manual divide-by-zero guard with checked_div for per_fill; adjacent remainder calc left unchanged (minor inconsistency, no bug)
crates/eye_declare/src/lib.rs Exports TrackedRef alongside Tracked; straightforward
docs/content/guide/application.md Adds clear documentation and example for update_tracked; example correctly guards writes with a read-first comparison

Reviews (1): Last reviewed commit: "Clippy" | Re-trigger Greptile

@BinaryMuse BinaryMuse merged commit bfabc48 into main Apr 23, 2026
5 checks passed
@BinaryMuse BinaryMuse deleted the mkt/conditional-update branch April 23, 2026 23:42
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant