WIP

Conrad Irwin created

Change summary

crates/git_ui/src/branch_picker.rs      |   1 
crates/git_ui/src/git_panel.rs          |  13 +-
crates/git_ui/src/git_panel_settings.rs | 121 ++++++++++----------------
crates/settings/src/settings_content.rs |  56 ++++++++++++
crates/workspace/src/dock.rs            |  10 ++
5 files changed, 121 insertions(+), 80 deletions(-)

Detailed changes

crates/git_ui/src/branch_picker.rs 🔗

@@ -556,7 +556,6 @@ impl PickerDelegate for BranchListDelegate {
                                     let show_author_name = ProjectSettings::get_global(cx)
                                         .git
                                         .branch_picker
-                                        .unwrap_or_default()
                                         .show_author_name;
 
                                     subject.map_or("no commits found".into(), |subject| {

crates/git_ui/src/git_panel.rs 🔗

@@ -2439,8 +2439,9 @@ impl GitPanel {
             let workspace = workspace.read(cx);
             let fs = workspace.app_state().fs.clone();
             cx.update_global::<SettingsStore, _>(|store, _cx| {
-                store.update_settings_file::<GitPanelSettings>(fs, move |settings, _cx| {
-                    settings.sort_by_path = Some(!current_setting);
+                store.update_settings_file(fs, move |settings, _cx| {
+                    settings.git_panel.get_or_insert_default().sort_by_path =
+                        Some(!current_setting);
                 });
             });
         }
@@ -4353,11 +4354,9 @@ impl Panel for GitPanel {
     }
 
     fn set_position(&mut self, position: DockPosition, _: &mut Window, cx: &mut Context<Self>) {
-        settings::update_settings_file::<GitPanelSettings>(
-            self.fs.clone(),
-            cx,
-            move |settings, _| settings.dock = Some(position),
-        );
+        settings::update_settings_file(self.fs.clone(), cx, move |settings, _| {
+            settings.git_panel.get_or_insert_default().dock = Some(position.into())
+        });
     }
 
     fn size(&self, _: &Window, cx: &App) -> Pixels {

crates/git_ui/src/git_panel_settings.rs 🔗

@@ -2,8 +2,12 @@ use editor::EditorSettings;
 use gpui::Pixels;
 use schemars::JsonSchema;
 use serde::{Deserialize, Serialize};
-use settings::{Settings, SettingsKey, SettingsSources, SettingsUi};
-use ui::scrollbars::{ScrollbarVisibility, ShowScrollbar};
+use settings::{Settings, SettingsContent, SettingsKey, SettingsSources, SettingsUi, StatusStyle};
+use ui::{
+    px,
+    scrollbars::{ScrollbarVisibility, ShowScrollbar},
+};
+use util::MergeFrom;
 use workspace::dock::DockPosition;
 
 #[derive(Copy, Clone, Debug, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
@@ -19,67 +23,7 @@ pub struct ScrollbarSettings {
     pub show: Option<ShowScrollbar>,
 }
 
-#[derive(Copy, Clone, Debug, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
-#[serde(rename_all = "snake_case")]
-// Style of the git status indicator in the panel.
-//
-// Default: icon
-pub enum StatusStyleContent {
-    Icon,
-    LabelColor,
-}
-
-#[derive(Default, Copy, Clone, Debug, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
-#[serde(rename_all = "snake_case")]
-pub enum StatusStyle {
-    #[default]
-    Icon,
-    LabelColor,
-}
-
-#[derive(Clone, Default, Serialize, Deserialize, JsonSchema, Debug, SettingsUi, SettingsKey)]
-#[settings_key(key = "git_panel")]
-pub struct GitPanelSettingsContent {
-    /// Whether to show the panel button in the status bar.
-    ///
-    /// Default: true
-    pub button: Option<bool>,
-    /// Where to dock the panel.
-    ///
-    /// Default: left
-    pub dock: Option<DockPosition>,
-    /// Default width of the panel in pixels.
-    ///
-    /// Default: 360
-    pub default_width: Option<f32>,
-    /// How entry statuses are displayed.
-    ///
-    /// Default: icon
-    pub status_style: Option<StatusStyle>,
-    /// How and when the scrollbar should be displayed.
-    ///
-    /// Default: inherits editor scrollbar settings
-    pub scrollbar: Option<ScrollbarSettings>,
-
-    /// What the default branch name should be when
-    /// `init.defaultBranch` is not set in git
-    ///
-    /// Default: main
-    pub fallback_branch_name: Option<String>,
-
-    /// Whether to sort entries in the panel by path
-    /// or by status (the default).
-    ///
-    /// 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)]
+#[derive(Debug, Clone, PartialEq)]
 pub struct GitPanelSettings {
     pub button: bool,
     pub dock: DockPosition,
@@ -108,17 +52,50 @@ impl ScrollbarVisibility for GitPanelSettings {
 }
 
 impl Settings for GitPanelSettings {
-    type FileContent = GitPanelSettingsContent;
+    fn from_defaults(content: &settings::SettingsContent, _cx: &mut ui::App) -> Self {
+        let git_panel = content.git_panel.clone().unwrap();
+        Self {
+            button: git_panel.button.unwrap(),
+            dock: git_panel.dock.unwrap().into(),
+            default_width: px(git_panel.default_width.unwrap()),
+            status_style: git_panel.status_style.unwrap(),
+            scrollbar: ScrollbarSettings {
+                show: git_panel.scrollbar.unwrap().show.map(Into::into),
+            },
+            fallback_branch_name: git_panel.fallback_branch_name.unwrap(),
+            sort_by_path: git_panel.sort_by_path.unwrap(),
+            collapse_untracked_diff: git_panel.collapse_untracked_diff.unwrap(),
+        }
+    }
 
-    fn load(
-        sources: SettingsSources<Self::FileContent>,
-        _: &mut gpui::App,
-    ) -> anyhow::Result<Self> {
-        sources.json_merge()
+    fn refine(&mut self, content: &settings::SettingsContent, _cx: &mut ui::App) {
+        let Some(git_panel) = &content.git_panel else {
+            return;
+        };
+        self.button.merge_from(&git_panel.button);
+        self.dock.merge_from(&git_panel.dock.map(Into::into));
+        self.default_width
+            .merge_from(&git_panel.default_width.map(px));
+        self.status_style.merge_from(&git_panel.status_style);
+        self.fallback_branch_name
+            .merge_from(&git_panel.fallback_branch_name);
+        self.sort_by_path.merge_from(&git_panel.sort_by_path);
+        self.collapse_untracked_diff
+            .merge_from(&git_panel.collapse_untracked_diff);
+        if let Some(show) = git_panel.scrollbar.as_ref().and_then(|s| s.show) {
+            self.scrollbar.show = Some(show.into())
+        }
     }
 
-    fn import_from_vscode(vscode: &settings::VsCodeSettings, current: &mut Self::FileContent) {
-        vscode.bool_setting("git.enabled", &mut current.button);
-        vscode.string_setting("git.defaultBranchName", &mut current.fallback_branch_name);
+    fn import_from_vscode(vscode: &settings::VsCodeSettings, current: &mut SettingsContent) {
+        if let Some(git_enabled) = vscode.read_bool("git.enabled") {
+            current.git_panel.get_or_insert_default().button = Some(git_enabled);
+        }
+        if let Some(default_branch) = vscode.read_string("git.defaultBranchName") {
+            current
+                .git_panel
+                .get_or_insert_default()
+                .fallback_branch_name = Some(default_branch.to_string());
+        }
     }
 }

crates/settings/src/settings_content.rs 🔗

@@ -41,6 +41,8 @@ pub struct SettingsContent {
     #[serde(flatten)]
     pub editor: EditorSettingsContent,
 
+    pub git_panel: Option<GitPanelSettingsContent>,
+
     pub tabs: Option<ItemSettingsContent>,
     pub tab_bar: Option<TabBarSettingsContent>,
 
@@ -364,3 +366,57 @@ pub struct ExtensionSettingsContent {
     #[serde(default)]
     pub auto_update_extensions: HashMap<Arc<str>, bool>,
 }
+
+#[derive(Clone, PartialEq, Default, Serialize, Deserialize, JsonSchema, Debug)]
+pub struct GitPanelSettingsContent {
+    /// Whether to show the panel button in the status bar.
+    ///
+    /// Default: true
+    pub button: Option<bool>,
+    /// Where to dock the panel.
+    ///
+    /// Default: left
+    pub dock: Option<DockPosition>,
+    /// Default width of the panel in pixels.
+    ///
+    /// Default: 360
+    pub default_width: Option<f32>,
+    /// How entry statuses are displayed.
+    ///
+    /// Default: icon
+    pub status_style: Option<StatusStyle>,
+    /// How and when the scrollbar should be displayed.
+    ///
+    /// Default: inherits editor scrollbar settings
+    pub scrollbar: Option<ScrollbarSettings>,
+
+    /// What the default branch name should be when
+    /// `init.defaultBranch` is not set in git
+    ///
+    /// Default: main
+    pub fallback_branch_name: Option<String>,
+
+    /// Whether to sort entries in the panel by path
+    /// or by status (the default).
+    ///
+    /// 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(Default, Copy, Clone, Debug, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
+#[serde(rename_all = "snake_case")]
+pub enum StatusStyle {
+    #[default]
+    Icon,
+    LabelColor,
+}
+
+#[derive(Copy, Clone, Debug, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
+pub struct ScrollbarSettings {
+    pub show: Option<ShowScrollbar>,
+}

crates/workspace/src/dock.rs 🔗

@@ -225,6 +225,16 @@ impl From<settings::DockPosition> for DockPosition {
     }
 }
 
+impl Into<settings::DockPosition> for DockPosition {
+    fn into(self) -> settings::DockPosition {
+        match self {
+            Self::Left => settings::DockPosition::Left,
+            Self::Bottom => settings::DockPosition::Bottom,
+            Self::Right => settings::DockPosition::Right,
+        }
+    }
+}
+
 impl DockPosition {
     fn label(&self) -> &'static str {
         match self {