Skip to content

Sidebar file tree: ancestor refresh fix + VS Code-style git decorations#6

Open
fazxes wants to merge 2 commits into
masterfrom
feat/file-tree-improvements
Open

Sidebar file tree: ancestor refresh fix + VS Code-style git decorations#6
fazxes wants to merge 2 commits into
masterfrom
feat/file-tree-improvements

Conversation

@fazxes

@fazxes fazxes commented May 4, 2026

Copy link
Copy Markdown
Member

Summary

  • Fix: sidebar file tree now refreshes when an ancestor-displayed root contains a nested indexed repo (previously the exact-path filter dropped these updates silently)
  • Feature: VS Code-style git status decorations — letter badge (M/A/U/C/R) + filename color tint + dim dot rolled up onto parent directories
  • Live updates via the existing fs watcher; no new event types

Changes

Area Detail
app/src/code/file_tree/view.rs Ancestor-match in handle_repository_metadata_event; FileTreeGitDecoration enum; render_item threads &AppContext; right-edge badge + parent dirty dot
crates/repo_metadata/src/git_status.rs (new) git2-backed status reader, scoped pathspec support, returns HashMap<StandardizedPath, GitStatus>
crates/repo_metadata/src/local_model.rs git_statuses + dirty_dirs cache; off-thread recompute in handle_watcher_event; .git/ events trigger full-repo refresh; cleanup on remove_repository
crates/repo_metadata/src/wrapper_model.rs git_status_for and is_dirty_dir exposed through RepoMetadataModel
Tests (1) reader unit test with real temp git repo, (2) model test for cache + dirty-dir rollup, (3) view test for ancestor-displayed root decoration mapping
docs/superpowers/specs/2026-05-04-git-decorations-design.md Design + audit revisions

Design notes

  • Bug fix preserves exact-match semantics; ancestor case only triggers rebuild_flattened_items (does NOT clobber root_dir.entry).
  • Deleted status is mapped by the reader for completeness but skipped in the view — deleted files have no tree row in v1 (matches VS Code Explorer behavior; the SCM panel is the right home for that).
  • Watcher debounce stays at the existing 1s. Lowering is a separate cross-cutting perf decision.
  • All colors come from WarpTheme methods (ui_yellow_color, ansi_fg_red) and editor diff helpers (add_color); no raw RGB.

Test plan

  • cargo check -p repo_metadata clean
  • cargo check -p warp clean
  • cargo test -p repo_metadata git_status -- --nocapture (2 tests pass)
  • cargo test -p warp git_status_decorations_update_for_ancestor_displayed_root -- --nocapture (1 test passes)
  • Release build (./script/run --release) succeeds and launches
  • Manual UI verification: modify file → M badge yellow within ~1s; new file → U badge green; staged → A; collapse parent of modified file → dim ● dot

🤖 Generated with Claude Code

Pranit Sharma added 2 commits May 4, 2026 14:59
Two related improvements to the sidebar file tree:

1. Fix: refresh ancestor-displayed roots on FileTreeEntryUpdated.
   Previously, FileTreeView::handle_repository_metadata_event filtered
   roots by exact path equality, so when a displayed root was a common
   ancestor of an indexed repository (collapsed via group_roots_by_common_ancestor),
   updates routed to the nested repo's path were silently dropped and the
   tree never rebuilt. Now ancestor roots also trigger rebuild_flattened_items
   without clobbering their entry.

2. Feature: VS Code-style git decorations.
   - New repo_metadata::git_status module wraps git2 to compute per-file
     status (Modified, Added, Untracked, Deleted, Conflict, Renamed, Ignored).
   - LocalRepoMetadataModel caches statuses + dirty-dir rollup; recomputes
     off-thread on every watcher event, treats .git/ internals as a full-repo
     refresh, reuses FileTreeEntryUpdated for UI propagation.
   - RepoMetadataModel exposes git_status_for / is_dirty_dir to consumers.
   - FileTreeView renders a letter badge (M/A/U/C/R) + filename color tint,
     with a dim dot rolled up onto parent directories. Deleted is intentionally
     omitted in v1 because deleted files are removed from the tree.

Tests: status reader unit (real temp git repo), model cache + dirty-dir,
view-level decoration mapping. cargo check -p repo_metadata and
cargo check -p warp both clean.
Fork-only files. CLAUDE.md is a copy of WARP.md so Claude Code reads
the same project guidance; AGENTS.md is a symlink to CLAUDE.md so any
AGENTS-aware tooling converges on the same content. The design spec
records the brainstorming + audit decisions behind the git decorations
feature shipped in the previous commit.
@fazxes fazxes force-pushed the feat/file-tree-improvements branch from 2b47b3c to 303f895 Compare May 4, 2026 19:05

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 2b47b3c85e

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment on lines +763 to +764
for path in statuses.keys() {
for ancestor in path.ancestors().skip(1) {

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Exclude ignored paths from dirty-directory rollups

recompute_dirty_dirs marks ancestors dirty for every cached status entry, but it never filters out GitStatus::Ignored. Since the new status reader includes ignored files, repositories with only ignored artifacts can still populate dirty_dirs, causing persistent dirty dots on parent directories/root even when there are no actionable git changes. Filtering ignored statuses out of the rollup keeps directory decorations consistent with actual dirty state.

Useful? React with 👍 / 👎.

Comment on lines +42 to +44
.include_ignored(true)
.recurse_untracked_dirs(true)
.recurse_ignored_dirs(true)

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Avoid recursive ignored-file scans in status refresh

The new status options recurse through ignored directories for every refresh, and spawn_full_git_status_refresh invokes this with pathspec=None on initial load. In repos with large ignored trees (for example node_modules or build outputs), this can force a full walk and caching of ignored files, significantly increasing startup latency and memory for decorations. Disabling recursive ignored traversal (or limiting it to explicitly requested paths) would prevent this regression.

Useful? React with 👍 / 👎.

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