fix(tree): stop focus snapping to open file (#17); never strand focus on hidden tree (#16)#20
Merged
Merged
Conversation
…ocus on hidden tree Two related file-tree focus-correctness bugs. #17 — Tree cursor snaps back to the open file (~1×/sec on noisy filesystems). The watcher fires `TreeDiscovered` on every filesystem change, and the handler unconditionally re-revealed the active tab's file, yanking the user's selection back and making it impossible to navigate to or open a different file (reported on Chrostini, whose inotify emits spurious IN_ACCESS events). - `FileTreeState::rebuild` now preserves the selection by path across a refresh (robust to siblings being added/removed), clamping to the old index when the path is gone. - `TreeDiscovered` only aligns the tree to the open file on the first discovery. Intentional reveals (open, search jump, link pick) keep calling `reveal_path` at their own sites. #16 — Focus could land on a hidden file tree. Several handlers set `Focus::Tree` without checking `tree_hidden`, stranding focus on an unrendered pane. Added `focus_tree_or_viewer()` and routed the 8 affected sites (Tab, last-tab close, search-Esc, copy-menu Enter/Esc, FocusLeft, ExitSearch, mouse tab-close) through it. The tree-click site is left alone — it is only reachable when the tree is rendered. Tests: failing reproduction for #17 (asserts the user's selection survives a second TreeDiscovered while the first still aligns to the open file); per-entry-point redirect tests for #16 asserting both directions (visible→Tree, hidden→Viewer). Full workspace suite green; fmt/clippy/deny clean. Closes #17 Closes #16 Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Owner
Author
🔍 Senior-engineer review (3 parallel agents: architecture / quality / testing)Reviewed Verified NOT a problem (false alarm)
🟠 Major — fixed
🟡 Minor — fixed
Out of scope (intentionally not changed)
Test delta: 6 → 13 new tests. Full workspace suite green (477 lib tests), |
…ouse hardening, branch coverage Follow-up to the self-review on PR #20. - Replace the `first_discovery = selected_path().is_none()` heuristic with an explicit `FileTreeState.aligned` latch set by `reveal_path`. Clearer intent and closes the "all files deleted then recreated" edge, where a transient empty selection would re-trigger a forced realign to the open file (#17). - Harden the mouse tree-click handler: the `tree_hidden` render branch never clears `tree_area_rect`, so a click at stale coordinates could strand focus on the hidden tree (#16 via mouse). Add a `!tree_hidden` guard and route the assignment through `focus_tree_or_viewer()`. All literal `Focus::Tree` assignments now go through the helper. - Tests: mouse last-tab-close focus redirect; rebuild index-clamp branch (selected path deleted), empty-tree branch, selection-follows-path on sibling shift, expanded-state preserved across rebuild, `reveal_path` latches only on a real match, lazy-discovery aligns a previously-hidden tree, and the empty-then-refill no-realign case. - Doc clarifications on `rebuild` (first-populate behavior, clamp underflow safety); closure form for `to_path_buf`. Full workspace suite green (477 lib tests); fmt/clippy/deny clean. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
leboiko
added a commit
that referenced
this pull request
Jun 17, 2026
Ships the file-tree focus-correctness fixes from #20: - #17: tree cursor no longer snaps back to the open file on every filesystem change (selection preserved by path across rebuilds; TreeDiscovered only aligns on first discovery). - #16: focus can no longer be stranded on a hidden file tree (8 entry points routed through focus_tree_or_viewer()). Pinned by 10 regression tests. fmt/clippy/test/deny all green locally. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This was referenced Jun 17, 2026
Closed
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.
Summary
Two related file-tree focus-correctness bugs.
#17 — Tree cursor snaps back to the open file (user-reported)
A user on Chrostini reported that with a file open, the left tree always shifts back to the opened file's index after ~1 second, making it impossible to navigate to or open a different file.
Root cause: the filesystem watcher fires
Action::TreeDiscoveredon every change — and on noisy filesystems (Chrostini inotify emits spuriousIN_ACCESS) that's roughly once a second. The handler then unconditionally calledreveal_path(active_file), yanking the user's tree selection back to the open file on every refresh.Fix:
FileTreeState::rebuildnow preserves the selection by path across a refresh (robust to sibling rows being added/removed by whatever change triggered the watcher), clamping to the old index when the path is gone.TreeDiscoveredonly aligns the tree to the open file on the first discovery. Intentional reveals (open file, search jump, link pick) still callreveal_pathat their own call sites.#16 — Focus could be stranded on a hidden file tree
Several handlers set
Focus::Treewithout checkingtree_hidden, landing focus on a pane that isn't rendered. Added afocus_tree_or_viewer()helper and routed the 8 affected sites through it:Tab, last-tab close (key + mouse), search-Esc, copy-menu Enter/Esc,FocusLeft,ExitSearch. The tree-click mouse site is intentionally left alone — it's only reachable when the tree is rendered.Testing
/fake/test.md), now asserts the user's selection survives a secondTreeDiscoveredwhile the first still aligns to the open file — guarding both directions so a no-op can't pass.visible→Treeandhidden→Viewer.cargo fmt --check,cargo clippy -D warnings,cargo deny checkall clean.Closes #17
Closes #16
🤖 Generated with Claude Code