git_ui: Fix indent guide rendering in tree view with collapsed folders (#48194)

Dino created

The indent guide computation was using visible list indices directly to
access entries, instead of mapping through `logical_indices` first. This
caused incorrect depths to be read from hidden entries when a folder was
collapsed, resulting in stray vertical lines extending to unrelated folders.

Closes #48189 

Release Notes:

- Fixed a visual bug in the Git Panel where collapsing a folder in tree
view would cause indent guide lines to incorrectly extend to unrelated
folders below it.

Change summary

Cargo.lock                     |  1 
crates/git_ui/Cargo.toml       |  1 
crates/git_ui/src/git_panel.rs | 38 +++++++++++++++++++++++++++--------
3 files changed, 31 insertions(+), 9 deletions(-)

Detailed changes

Cargo.lock 🔗

@@ -7303,6 +7303,7 @@ dependencies = [
  "serde",
  "serde_json",
  "settings",
+ "smallvec",
  "smol",
  "strum 0.27.2",
  "telemetry",

crates/git_ui/Cargo.toml 🔗

@@ -51,6 +51,7 @@ schemars.workspace = true
 serde.workspace = true
 serde_json.workspace = true
 settings.workspace = true
+smallvec.workspace = true
 smol.workspace = true
 strum.workspace = true
 telemetry.workspace = true

crates/git_ui/src/git_panel.rs 🔗

@@ -57,6 +57,7 @@ use project::{
 use prompt_store::{BuiltInPrompt, PromptId, PromptStore, RULES_FILE_NAMES};
 use serde::{Deserialize, Serialize};
 use settings::{Settings, SettingsStore, StatusStyle};
+use smallvec::SmallVec;
 use std::future::Future;
 use std::ops::Range;
 use std::path::Path;
@@ -290,6 +291,15 @@ impl GitListEntry {
             _ => None,
         }
     }
+
+    /// Returns the tree indentation depth for this entry.
+    fn depth(&self) -> usize {
+        match self {
+            GitListEntry::Directory(dir) => dir.depth,
+            GitListEntry::TreeStatus(status) => status.depth,
+            _ => 0,
+        }
+    }
 }
 
 enum GitPanelViewMode {
@@ -3806,6 +3816,24 @@ impl GitPanel {
         self.has_staged_changes()
     }
 
+    /// Computes tree indentation depths for visible entries in the given range.
+    /// Used by indent guides to render vertical connector lines in tree view.
+    fn compute_visible_depths(&self, range: Range<usize>) -> SmallVec<[usize; 64]> {
+        let GitPanelViewMode::Tree(state) = &self.view_mode else {
+            return SmallVec::new();
+        };
+
+        range
+            .map(|ix| {
+                state
+                    .logical_indices
+                    .get(ix)
+                    .and_then(|&entry_ix| self.entries.get(entry_ix))
+                    .map_or(0, |entry| entry.depth())
+            })
+            .collect()
+    }
+
     fn status_width_estimate(
         tree_view: bool,
         entry: &GitStatusEntry,
@@ -4683,15 +4711,7 @@ impl GitPanel {
                                     .with_compute_indents_fn(
                                         cx.entity(),
                                         |this, range, _window, _cx| {
-                                            range
-                                                .map(|ix| match this.entries.get(ix) {
-                                                    Some(GitListEntry::Directory(dir)) => dir.depth,
-                                                    Some(GitListEntry::TreeStatus(status)) => {
-                                                        status.depth
-                                                    }
-                                                    _ => 0,
-                                                })
-                                                .collect()
+                                            this.compute_visible_depths(range)
                                         },
                                     )
                                     .with_render_fn(cx.entity(), |_, params, _, _| {