fix(ui): keep what is loaded on screen while it reloads - #48
Merged
Conversation
Deleting a local branch blanked the history twice. Each blank is one reload: `reload_head`, `reload_references` and `reload_history` each assigned `LoadState::Loading` before spawning their read, discarding the value the views were drawing. `HistoryTableDelegate::recompute_visible` returns early on anything but `Ready`, so `rows_count` drops to zero and the table renders nothing until the walk lands. The sidebar loses its branch list the same way. There are two reloads because nothing deduplicates them. `delete_local_branch` reloads the moment `git branch -D` returns, and 200-350 ms later FSEvents reports the removal of `refs/heads/<branch>` — classified `Aspect::References` — and the watch loop reloads again. The gap is FSEvents latency plus the 200 ms debounce window plus up to one 100 ms mailbox poll, which is long enough for the two blanks to read as two flashes rather than one. That the echo is real was checked by watching a repository through `FsRepositoryWatcher` across a `git branch -D`: it reports `Aspect::References` every time. `start_reload` moves to `Loading` only when there is nothing worth keeping, so a first load and a retry after a failure still show the loading state, while a re-read leaves the previous value up until `apply_*` replaces it. That also stops `apply_history` from seeing `references` as `Loading` and building an empty `refs_by_commit`, which wiped every badge for a frame. The second reload stays. It is invisible now, and suppressing gitr's own echo would need the watcher to tell gitr's writes from a terminal's, which nothing in the tree does — `domain::watch` leaves that to the caller by design.
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.
Deleting a local branch made the history blank out twice, about a third of a second apart.
Why it blanks
reload_head,reload_referencesandreload_historyeach assignedLoadState::Loadingbefore spawning their read, discarding the value the views were drawing.HistoryTableDelegate::recompute_visiblereturns early on anything butReady, sorows_countdrops to zero and the table renders nothing until the walk lands. The sidebar loses its branch list the same way.So any reload flickers — a commit made in a terminal, a fetch, a scope change. Deleting a branch is just where it shows up twice.
Why twice
Nothing deduplicates the two reloads a deletion causes:
delete_local_branchreloads the momentgit branch -Dreturns (workspace.rs:619).refs/heads/<branch>gone,classifymaps it toAspect::References, and the watch loop reloads again.The gap is FSEvents latency + the 200 ms debounce window + up to one 100 ms mailbox poll — long enough for the two blanks to read as separate flashes.
I confirmed the echo rather than assuming it: watching a repository through
FsRepositoryWatcheracross agit branch -DreportsAspect::Referencesevery time.The change
LoadState::start_reloadmoves toLoadingonly when there is nothing worth keeping. A first load and a retry after a failure still show the loading state; a re-read leaves the previous value on screen untilapply_*replaces it.One change, three call sites, and it fixes the flicker for every reload path rather than just deletion.
It also fixes a smaller artifact in the same family:
apply_historyreadsself.references.ready(), so when references was stillLoadingit built an emptyrefs_by_commitand every badge vanished for a frame.What I deliberately did not do
The redundant second reload stays. It is invisible now, and suppressing gitr's own echo would need the watcher to tell gitr's writes from a terminal's —
domain::watchleaves that to the caller by design, and nothing in the tree does it. Worth its own change if the duplicate walk ever costs measurably on a large history.Testing
Four unit tests on the state transition, written before the code and seen to fail.
cargo test --workspace,cargo clippy --workspace --all-targets -- -D warningsandcargo fmt --all --checkall pass.Not yet confirmed in the running app. gitr is single-instance and the installed binary held the socket, so I never got the fixed build in front of a human eye. The reasoning above is from reading the code plus the watcher probe — the visual result is unverified.