git_ui: Add collapse_untracked_diff settings to improve usability for untracked files (#32591)

Arseny Kapoulkine created

In repositories with untracked files that are not intended to be added,
showing the expanded diffs in the panel is confusing, as it places the
changes side by side with changes in tracked files.

This change adds a setting, collapse_untracked_diff, that can be enabled
to collapse untracked diffs by default when the panel is opened.

See
https://github.com/zed-industries/zed/pull/31855#issuecomment-2957547018
(and previous comment for examples of why this is useful).

Example before this change, or with the setting in its default state:


![image](https://github.com/user-attachments/assets/f974c849-7ebf-424e-9397-442a6cc2513b)

Example after this change with the setting set to `true`:


![image](https://github.com/user-attachments/assets/bd8934f5-bd9a-4f5a-b723-cd4b798d2c2c)

Release Notes:

- Git: Added `collapse_untracked_diff` setting to auto-collapse
untracked diffs

Change summary

assets/settings/default.json            |  4 ++++
crates/git_ui/src/git_panel_settings.rs |  6 ++++++
crates/git_ui/src/project_diff.rs       | 17 ++++++++++++++---
3 files changed, 24 insertions(+), 3 deletions(-)

Detailed changes

assets/settings/default.json 🔗

@@ -713,6 +713,10 @@
     //
     // Default: false
     "sort_by_path": false,
+    // Whether to collapse untracked files in the diff panel.
+    //
+    // Default: false
+    "collapse_untracked_diff": false,
     "scrollbar": {
       // When to show the scrollbar in the git panel.
       //

crates/git_ui/src/git_panel_settings.rs 🔗

@@ -70,6 +70,11 @@ pub struct GitPanelSettingsContent {
     ///
     /// Default: false
     pub sort_by_path: Option<bool>,
+
+    /// Whether to collapse untracked files in the diff panel.
+    ///
+    /// Default: false
+    pub collapse_untracked_diff: Option<bool>,
 }
 
 #[derive(Deserialize, Debug, Clone, PartialEq)]
@@ -81,6 +86,7 @@ pub struct GitPanelSettings {
     pub scrollbar: ScrollbarSettings,
     pub fallback_branch_name: String,
     pub sort_by_path: bool,
+    pub collapse_untracked_diff: bool,
 }
 
 impl Settings for GitPanelSettings {

crates/git_ui/src/project_diff.rs 🔗

@@ -177,12 +177,19 @@ impl ProjectDiff {
         );
 
         let mut was_sort_by_path = GitPanelSettings::get_global(cx).sort_by_path;
+        let mut was_collapse_untracked_diff =
+            GitPanelSettings::get_global(cx).collapse_untracked_diff;
         cx.observe_global::<SettingsStore>(move |this, cx| {
             let is_sort_by_path = GitPanelSettings::get_global(cx).sort_by_path;
-            if is_sort_by_path != was_sort_by_path {
+            let is_collapse_untracked_diff =
+                GitPanelSettings::get_global(cx).collapse_untracked_diff;
+            if is_sort_by_path != was_sort_by_path
+                || is_collapse_untracked_diff != was_collapse_untracked_diff
+            {
                 *this.update_needed.borrow_mut() = ();
             }
-            was_sort_by_path = is_sort_by_path
+            was_sort_by_path = is_sort_by_path;
+            was_collapse_untracked_diff = is_collapse_untracked_diff;
         })
         .detach();
 
@@ -461,7 +468,11 @@ impl ProjectDiff {
                     selections.select_ranges([0..0])
                 });
             }
-            if is_excerpt_newly_added && diff_buffer.file_status.is_deleted() {
+            if is_excerpt_newly_added
+                && (diff_buffer.file_status.is_deleted()
+                    || (diff_buffer.file_status.is_untracked()
+                        && GitPanelSettings::get_global(cx).collapse_untracked_diff))
+            {
                 editor.fold_buffer(snapshot.text.remote_id(), cx)
             }
         });