Skip to content

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

Open
fazxes wants to merge 1 commit intowarpdotdev:masterfrom
fazxes:upstream/file-tree-improvements
Open

Sidebar file tree: ancestor refresh fix + VS Code-style git decorations#10078
fazxes wants to merge 1 commit intowarpdotdev:masterfrom
fazxes:upstream/file-tree-improvements

Conversation

@fazxes
Copy link
Copy Markdown

@fazxes fazxes commented May 4, 2026

Summary

  • Bug fix: sidebar file tree silently no-ops when an ancestor-displayed root contains a nested indexed repo. The exact-path filter in FileTreeView::handle_repository_metadata_event drops FileTreeEntryUpdated events routed to the longest-matching repo path (via LocalRepoMetadataModel::find_repository_for_path_string), so the tree never rebuilds. Fix matches roots whose entry.root_directory() is a strict ancestor of the updated path; preserves existing exact-match behavior.
  • Feature: VS Code-style git status decorations in the sidebar — letter badge (M/A/U/C/R) + filename color tint + dim parent-directory rollup dot. Live updates via the existing fs watcher; reuses FileTreeEntryUpdated.

Why

The bug fix is small (~30 lines) and catches a real correctness gap. The decoration feature is independent but lands cleanly on top of the same update path.

Implementation notes

  • New repo_metadata::git_status module (uses the existing vendored libgit2 already in app/Cargo.toml; added git2 dep to repo_metadata/Cargo.toml).
  • LocalRepoMetadataModel gets git_statuses and dirty_dirs caches; recomputes off-thread inside the existing ctx.spawn block in handle_watcher_event. .git/ internal events trigger a full-repo refresh, normal events use scoped pathspecs.
  • RepoMetadataModel (wrapper) exposes git_status_for and is_dirty_dir for consumers.
  • View renders status via a new FileTreeGitDecoration enum; render_item was extended to receive &AppContext.
  • Colors use existing theme methods (ui_yellow_color, ansi_fg_red) and editor diff helpers (add_color) — no raw RGB.
  • Deleted status is mapped by the reader but skipped in the view in this version: deleted files are removed from the tree by FileTreeMutation::Remove, so there's no row to decorate. Matches VS Code Explorer behavior (deletions surface in the SCM panel).
  • Watcher debounce is unchanged at 1s.

Tests

  • git_status::tests::statuses_for_repo_maps_modified_untracked_added_and_ignored — uses a real temp git repo (init, commit baseline, modify/untrack/ignore/stage), asserts the enum mapping.
  • local_model::tests::git_status_recompute_marks_modified_file_and_dirty_ancestors — model-level cache + rollup test.
  • view_tests::git_status_decorations_update_for_ancestor_displayed_root — view-level: ancestor-displayed root with a nested modified file, asserts decoration mapping (badge M, modified color). The existing harness has no precedent for asserting rendered Text color directly; falls back to model-state + decoration assertions.

Test plan

  • cargo check -p repo_metadata
  • cargo check -p warp
  • cargo test -p repo_metadata git_status
  • cargo test -p warp git_status_decorations_update_for_ancestor_displayed_root
  • Release build (./script/run --release) launches successfully

CHANGELOG-IMPROVEMENT: File tree shows VS Code-style git status decorations and refreshes ancestor-displayed roots when nested repos change.

🤖 Generated with Claude Code

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.
@cla-bot
Copy link
Copy Markdown

cla-bot Bot commented May 4, 2026

Thank you for your pull request and welcome to our community. We could not parse the GitHub identity of the following contributors: Pranit Sharma.
This is most likely caused by a git client misconfiguration; please make sure to:

  1. check if your git client is configured with an email to sign commits git config --list | grep email
  2. If not, set it up using git config --global user.email email@example.com
  3. Make sure that the git commit email is configured in your GitHub account settings, see https://github.com/settings/emails

@oz-for-oss
Copy link
Copy Markdown
Contributor

oz-for-oss Bot commented May 4, 2026

@fazxes

I'm starting a first review of this pull request.

You can view the conversation on Warp.

I completed the review and no human review was requested for this pull request.

Comment /oz-review on this pull request to retrigger a review (up to 3 times on the same pull request).

Powered by Oz

@github-actions github-actions Bot added the external-contributor Indicates that a PR has been opened by someone outside the Warp team. label May 4, 2026
@fazxes fazxes force-pushed the upstream/file-tree-improvements branch from fb3153f to cee704c Compare May 4, 2026 19:05
@cla-bot
Copy link
Copy Markdown

cla-bot Bot commented May 4, 2026

Thank you for your pull request and welcome to our community. We could not parse the GitHub identity of the following contributors: Pranit Sharma.
This is most likely caused by a git client misconfiguration; please make sure to:

  1. check if your git client is configured with an email to sign commits git config --list | grep email
  2. If not, set it up using git config --global user.email email@example.com
  3. Make sure that the git commit email is configured in your GitHub account settings, see https://github.com/settings/emails

Copy link
Copy Markdown
Contributor

@oz-for-oss oz-for-oss Bot left a comment

Choose a reason for hiding this comment

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

Overview

This PR adds local git-status decoration support to the sidebar file tree and adjusts metadata refresh handling for ancestor-displayed roots.

Concerns

  • The new git2 dependency is unconditional even though all runtime usage is not(target_family = "wasm"), which can break wasm builds for repo_metadata.
  • Ignored statuses are included in dirty-directory rollups, so repositories with ignored build outputs can show dirty dots even when there are no real git changes.
  • Full status refreshes recurse through ignored directories, which can be expensive for common ignored trees such as target/ or node_modules/.
  • This is a user-visible UI change, but the PR description does not include screenshots or video. For faster review, please upload screenshots or a video of the feature working end to end.

Verdict

Found: 0 critical, 4 important, 0 suggestions

Request changes

Comment /oz-review on this pull request to retrigger a review (up to 3 times on the same pull request).

Powered by Oz

notify-debouncer-full.workspace = true
async-fs.workspace = true
watcher.workspace = true
git2 = { version = "0.20.4", default-features = false, features = [
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

⚠️ [IMPORTANT] git2 is only used behind not(target_family = "wasm"), but this dependency is unconditional; move it under a matching target-specific dependency section so wasm builds of repo_metadata do not try to build/link libgit2.

.include_untracked(true)
.include_ignored(true)
.recurse_untracked_dirs(true)
.recurse_ignored_dirs(true)
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

⚠️ [IMPORTANT] Full refreshes now recurse through every ignored directory, so repos with large ignored trees like target/ or node_modules/ can spend a long time in status refresh and allocate huge status caches; avoid recursing ignored dirs or make ignored status collection scoped to visible paths.

};

let mut dirty_dirs = HashSet::new();
for path in statuses.keys() {
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

⚠️ [IMPORTANT] This rolls up ignored statuses too, so a repo with only ignored files will still show dirty directory dots; filter GitStatus::Ignored out of dirty rollups or avoid storing ignored statuses as dirty descendants.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

external-contributor Indicates that a PR has been opened by someone outside the Warp team.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant