workspace pt 2

Ben Kunkle created

Change summary

Cargo.lock                                        |   1 
crates/project/src/project_settings.rs            |   2 
crates/settings/src/settings_content/workspace.rs |  51 ++
crates/settings/src/vscode_import.rs              |   2 
crates/theme_importer/Cargo.toml                  |   1 
crates/theme_importer/src/main.rs                 |   4 
crates/theme_importer/src/vscode/converter.rs     |   4 
crates/title_bar/src/title_bar_settings.rs        |   7 
crates/workspace/src/dock.rs                      |  15 
crates/workspace/src/item.rs                      |   5 
crates/workspace/src/pane.rs                      |  14 
crates/workspace/src/workspace.rs                 |  12 
crates/workspace/src/workspace_settings.rs        | 260 ++++++++++++----
13 files changed, 276 insertions(+), 102 deletions(-)

Detailed changes

Cargo.lock 🔗

@@ -16600,6 +16600,7 @@ version = "0.1.0"
 dependencies = [
  "anyhow",
  "clap",
+ "collections",
  "gpui",
  "indexmap",
  "log",

crates/project/src/project_settings.rs 🔗

@@ -652,7 +652,7 @@ impl Settings for ProjectSettings {
     ) {
         // this just sets the binary name instead of a full path so it relies on path lookup
         // resolving to the one you want
-        let npm_path = vscode.read_enum_setting("npm.packageManager", |s| match s {
+        let npm_path = vscode.read_enum("npm.packageManager", |s| match s {
             v @ ("npm" | "yarn" | "bun" | "pnpm") => Some(v.to_owned()),
             _ => None,
         });

crates/settings/src/settings_content/workspace.rs 🔗

@@ -1,7 +1,10 @@
+use std::num::NonZeroUsize;
+
+use collections::HashMap;
 use schemars::JsonSchema;
 use serde::{Deserialize, Serialize};
 
-#[derive(Clone, PartialEq, Default, Serialize, Deserialize, JsonSchema)]
+#[derive(Clone, Debug, PartialEq, Default, Serialize, Deserialize, JsonSchema)]
 pub struct WorkspaceSettingsContent {
     /// Active pane styling settings.
     pub active_pane_modifiers: Option<ActivePanelModifiers>,
@@ -69,7 +72,8 @@ pub struct WorkspaceSettingsContent {
     /// it will be assumed to equal the value.
     ///
     /// Default: true
-    pub command_aliases: Option<HashMap<String, String>>,
+    #[serde(default)]
+    pub command_aliases: HashMap<String, String>,
     /// Maximum open tabs in a pane. Will not close an unsaved
     /// tab. Set to `None` for unlimited tabs.
     ///
@@ -82,7 +86,8 @@ pub struct WorkspaceSettingsContent {
     /// Whether to resize all the panels in a dock when resizing the dock.
     ///
     /// Default: ["left"]
-    pub resize_all_panels_in_dock: Option<Vec<DockPosition>>,
+    #[serde(default)]
+    pub resize_all_panels_in_dock: Vec<DockPosition>,
     /// Whether to automatically close files that have been deleted on disk.
     ///
     /// Default: false
@@ -97,6 +102,11 @@ pub struct WorkspaceSettingsContent {
     ///
     /// Default: true
     pub zoomed_padding: Option<bool>,
+
+    // Settings related to the editor's tab bar.
+    pub tab_bar: Option<TabBarSettingsContent>,
+
+    pub tabs: Option<ItemSettingsContent>,
 }
 
 #[derive(Clone, Default, Debug, PartialEq, Serialize, Deserialize, JsonSchema)]
@@ -212,7 +222,7 @@ pub enum BottomDockLayout {
     RightAligned,
 }
 
-#[derive(Copy, Clone, PartialEq, Default, Serialize, Deserialize, JsonSchema)]
+#[derive(Copy, Clone, PartialEq, Default, Serialize, Deserialize, JsonSchema, Debug)]
 #[serde(rename_all = "snake_case")]
 pub enum CloseWindowWhenNoItems {
     /// Match platform conventions by default, so "on" on macOS and "off" everywhere else
@@ -234,7 +244,7 @@ impl CloseWindowWhenNoItems {
     }
 }
 
-#[derive(Copy, Clone, PartialEq, Eq, Default, Serialize, Deserialize, JsonSchema)]
+#[derive(Copy, Clone, PartialEq, Eq, Default, Serialize, Deserialize, JsonSchema, Debug)]
 #[serde(rename_all = "snake_case")]
 pub enum RestoreOnStartupBehavior {
     /// Always start with an empty editor
@@ -246,7 +256,7 @@ pub enum RestoreOnStartupBehavior {
     LastSession,
 }
 
-#[derive(Clone, Default, Serialize, Deserialize, JsonSchema)]
+#[derive(Clone, Default, Serialize, Deserialize, JsonSchema, Debug, PartialEq)]
 pub struct TabBarSettingsContent {
     /// Whether or not to show the tab bar in the editor.
     ///
@@ -289,7 +299,7 @@ pub enum PaneSplitDirectionVertical {
     Right,
 }
 
-#[derive(Copy, Clone, Debug, Serialize, Deserialize, JsonSchema, SettingsUi)]
+#[derive(Copy, Clone, Debug, Serialize, Deserialize, JsonSchema, PartialEq)]
 #[serde(rename_all = "snake_case")]
 pub struct CenteredLayoutSettings {
     /// The relative width of the left padding of the central pane from the
@@ -303,3 +313,30 @@ pub struct CenteredLayoutSettings {
     /// Default: 0.2
     pub right_padding: Option<f32>,
 }
+
+#[derive(Copy, Clone, Default, Serialize, Deserialize, JsonSchema, PartialEq, Debug)]
+#[serde(rename_all = "snake_case")]
+pub enum OnLastWindowClosed {
+    /// Match platform conventions by default, so don't quit on macOS, and quit on other platforms
+    #[default]
+    PlatformDefault,
+    /// Quit the application the last window is closed
+    QuitApp,
+}
+
+impl OnLastWindowClosed {
+    pub fn is_quit_app(&self) -> bool {
+        match self {
+            OnLastWindowClosed::PlatformDefault => false,
+            OnLastWindowClosed::QuitApp => true,
+        }
+    }
+}
+
+#[derive(Clone, Copy, Debug, Serialize, Deserialize, JsonSchema, PartialEq)]
+#[serde(rename_all = "lowercase")]
+pub enum DockPosition {
+    Left,
+    Bottom,
+    Right,
+}

crates/settings/src/vscode_import.rs 🔗

@@ -137,7 +137,7 @@ impl VsCodeSettings {
     }
 
     // todo! replace enum_setting
-    pub fn read_enum_setting<T>(&self, key: &str, f: impl FnOnce(&str) -> Option<T>) -> Option<T> {
+    pub fn read_enum<T>(&self, key: &str, f: impl FnOnce(&str) -> Option<T>) -> Option<T> {
         self.content.get(key).and_then(Value::as_str).and_then(f)
     }
 }

crates/theme_importer/Cargo.toml 🔗

@@ -11,6 +11,7 @@ workspace = true
 [dependencies]
 anyhow.workspace = true
 clap = { workspace = true, features = ["derive"] }
+collections.workspace = true
 gpui.workspace = true
 indexmap.workspace = true
 log.workspace = true

crates/theme_importer/src/main.rs 🔗

@@ -7,7 +7,7 @@ use std::path::PathBuf;
 
 use anyhow::{Context as _, Result};
 use clap::Parser;
-use indexmap::IndexMap;
+use collections::IndexMap;
 use log::LevelFilter;
 use serde::Deserialize;
 use simplelog::ColorChoice;
@@ -137,7 +137,7 @@ fn main() -> Result<()> {
         file_name: "".to_string(),
     };
 
-    let converter = VsCodeThemeConverter::new(vscode_theme, theme_metadata, IndexMap::new());
+    let converter = VsCodeThemeConverter::new(vscode_theme, theme_metadata, IndexMap::default());
 
     let theme = converter.convert()?;
     let mut theme = serde_json::to_value(theme).unwrap();

crates/theme_importer/src/vscode/converter.rs 🔗

@@ -1,5 +1,5 @@
 use anyhow::Result;
-use indexmap::IndexMap;
+use collections::IndexMap;
 use strum::IntoEnumIterator;
 use theme::{
     FontStyleContent, FontWeightContent, HighlightStyleContent, StatusColorsContent,
@@ -212,7 +212,7 @@ impl VsCodeThemeConverter {
     }
 
     fn convert_syntax_theme(&self) -> Result<IndexMap<String, HighlightStyleContent>> {
-        let mut highlight_styles = IndexMap::new();
+        let mut highlight_styles = IndexMap::default();
 
         for syntax_token in ZedSyntaxToken::iter() {
             let override_match = self

crates/title_bar/src/title_bar_settings.rs 🔗

@@ -40,12 +40,13 @@ impl Settings for TitleBarSettings {
 
     fn refine(&mut self, s: &SettingsContent, _: &mut App) {
         let Some(content) = s.title_bar else {
-            return
-        }
+            return;
+        };
 
         self.show.refine(&content.show);
         self.show_branch_icon.refine(content.show_branch_icon);
-        self.show_onboarding_banner.refine(content.show_onboarding_banner);
+        self.show_onboarding_banner
+            .refine(content.show_onboarding_banner);
         self.show_user_picture.refine(content.show_user_picture);
         self.show_branch_name.refine(content.show_branch_name);
         self.show_project_items.refine(content.show_project_items);

crates/workspace/src/dock.rs 🔗

@@ -9,8 +9,6 @@ use gpui::{
     Render, SharedString, StyleRefinement, Styled, Subscription, WeakEntity, Window, deferred, div,
     px,
 };
-use schemars::JsonSchema;
-use serde::{Deserialize, Serialize};
 use settings::SettingsStore;
 use std::sync::Arc;
 use ui::{ContextMenu, Divider, DividerColor, IconButton, Tooltip, h_flex};
@@ -210,14 +208,23 @@ impl Focusable for Dock {
     }
 }
 
-#[derive(Clone, Copy, Debug, Serialize, Deserialize, JsonSchema, PartialEq)]
-#[serde(rename_all = "lowercase")]
+#[derive(Clone, Copy, Debug, PartialEq)]
 pub enum DockPosition {
     Left,
     Bottom,
     Right,
 }
 
+impl From<settings::DockPosition> for DockPosition {
+    fn from(value: settings::DockPosition) -> Self {
+        match value {
+            settings::DockPosition::Left => Self::Left,
+            settings::DockPosition::Bottom => Self::Bottom,
+            settings::DockPosition::Right => Self::Right,
+        }
+    }
+}
+
 impl DockPosition {
     fn label(&self) -> &'static str {
         match self {

crates/workspace/src/item.rs 🔗

@@ -15,7 +15,7 @@ use gpui::{
     Focusable, Font, HighlightStyle, Pixels, Point, Render, SharedString, Task, WeakEntity, Window,
 };
 use project::{Project, ProjectEntryId, ProjectPath};
-use settings::{
+pub use settings::{
     ActivateOnClose, ClosePosition, Settings, SettingsLocation, ShowCloseButton, ShowDiagnostics,
 };
 use smallvec::SmallVec;
@@ -100,8 +100,7 @@ impl Settings for ItemSettings {
                 ShowCloseButton::Hidden
             })
         }
-        if let Some(s) = vscode.read_enum_setting("workbench.editor.tabActionLocation", |s| match s
-        {
+        if let Some(s) = vscode.read_enum("workbench.editor.tabActionLocation", |s| match s {
             "right" => Some(ClosePosition::Right),
             "left" => Some(ClosePosition::Left),
             _ => None,

crates/workspace/src/pane.rs 🔗

@@ -5818,8 +5818,9 @@ mod tests {
     async fn test_remove_item_ordering_neighbour(cx: &mut TestAppContext) {
         init_test(cx);
         cx.update_global::<SettingsStore, ()>(|s, cx| {
-            s.update_user_settings::<ItemSettings>(cx, |s| {
-                s.activate_on_close = Some(ActivateOnClose::Neighbour);
+            s.update_user_settings(cx, |s| {
+                s.workspace.tabs.get_or_insert_default().activate_on_close =
+                    Some(ActivateOnClose::Neighbour);
             });
         });
         let fs = FakeFs::new(cx.executor());
@@ -5907,8 +5908,9 @@ mod tests {
     async fn test_remove_item_ordering_left_neighbour(cx: &mut TestAppContext) {
         init_test(cx);
         cx.update_global::<SettingsStore, ()>(|s, cx| {
-            s.update_user_settings::<ItemSettings>(cx, |s| {
-                s.activate_on_close = Some(ActivateOnClose::LeftNeighbour);
+            s.update_user_settings(cx, |s| {
+                s.workspace.tabs.get_or_insert_default().activate_on_close =
+                    Some(ActivateOnClose::LeftNeighbour);
             });
         });
         let fs = FakeFs::new(cx.executor());
@@ -6560,8 +6562,8 @@ mod tests {
 
     fn set_max_tabs(cx: &mut TestAppContext, value: Option<usize>) {
         cx.update_global(|store: &mut SettingsStore, cx| {
-            store.update_user_settings::<WorkspaceSettings>(cx, |settings| {
-                settings.max_tabs = value.map(|v| NonZero::new(v).unwrap())
+            store.update_user_settings(cx, |settings| {
+                settings.workspace.max_tabs = value.map(|v| NonZero::new(v).unwrap())
             });
         });
     }

crates/workspace/src/workspace.rs 🔗

@@ -1695,8 +1695,8 @@ impl Workspace {
         cx: &mut Context<Self>,
     ) {
         let fs = self.project().read(cx).fs();
-        settings::update_settings_file::<WorkspaceSettings>(fs.clone(), cx, move |content, _cx| {
-            content.bottom_dock_layout = Some(layout);
+        settings::update_settings_file(fs.clone(), cx, move |content, _cx| {
+            content.workspace.bottom_dock_layout = Some(layout);
         });
 
         cx.notify();
@@ -6014,8 +6014,8 @@ impl Workspace {
     ) {
         let fs = self.project().read(cx).fs().clone();
         let show_edit_predictions = all_language_settings(None, cx).show_edit_predictions(None, cx);
-        update_settings_file::<AllLanguageSettings>(fs, cx, move |file, _| {
-            file.defaults.show_edit_predictions = Some(!show_edit_predictions)
+        update_settings_file(fs, cx, move |file, _| {
+            file.project.all_languages.defaults.show_edit_predictions = Some(!show_edit_predictions)
         });
     }
 }
@@ -8678,8 +8678,8 @@ mod tests {
         // Autosave on window change.
         item.update(cx, |item, cx| {
             SettingsStore::update_global(cx, |settings, cx| {
-                settings.update_user_settings::<WorkspaceSettings>(cx, |settings| {
-                    settings.autosave = Some(AutosaveSetting::OnWindowChange);
+                settings.update_user_settings(cx, |settings| {
+                    settings.workspace.autosave = Some(AutosaveSetting::OnWindowChange);
                 })
             });
             item.is_dirty = true;

crates/workspace/src/workspace_settings.rs 🔗

@@ -4,52 +4,70 @@ use crate::DockPosition;
 use anyhow::Result;
 use collections::HashMap;
 use gpui::App;
-use schemars::JsonSchema;
-use serde::{Deserialize, Serialize};
-use settings::{Settings, SettingsKey, SettingsSources, SettingsUi};
+use serde::Deserialize;
+pub use settings::AutosaveSetting;
+use settings::Settings;
+pub use settings::{
+    BottomDockLayout, PaneSplitDirectionHorizontal, PaneSplitDirectionVertical,
+    RestoreOnStartupBehavior,
+};
+use util::MergeFrom as _;
 
-#[derive(Deserialize)]
 pub struct WorkspaceSettings {
     pub active_pane_modifiers: ActivePanelModifiers,
-    pub bottom_dock_layout: BottomDockLayout,
-    pub pane_split_direction_horizontal: PaneSplitDirectionHorizontal,
-    pub pane_split_direction_vertical: PaneSplitDirectionVertical,
-    pub centered_layout: CenteredLayoutSettings,
+    pub bottom_dock_layout: settings::BottomDockLayout,
+    pub pane_split_direction_horizontal: settings::PaneSplitDirectionHorizontal,
+    pub pane_split_direction_vertical: settings::PaneSplitDirectionVertical,
+    pub centered_layout: settings::CenteredLayoutSettings, // <- This one is hard to describe, especially as it has
     pub confirm_quit: bool,
     pub show_call_status_icon: bool,
     pub autosave: AutosaveSetting,
-    pub restore_on_startup: RestoreOnStartupBehavior,
+    pub restore_on_startup: settings::RestoreOnStartupBehavior,
     pub restore_on_file_reopen: bool,
     pub drop_target_size: f32,
     pub use_system_path_prompts: bool,
     pub use_system_prompts: bool,
     pub command_aliases: HashMap<String, String>,
     pub max_tabs: Option<NonZeroUsize>,
-    pub when_closing_with_no_tabs: CloseWindowWhenNoItems,
-    pub on_last_window_closed: OnLastWindowClosed,
-    pub resize_all_panels_in_dock: Vec<DockPosition>,
+    pub when_closing_with_no_tabs: settings::CloseWindowWhenNoItems,
+    pub on_last_window_closed: settings::OnLastWindowClosed,
+    pub resize_all_panels_in_dock: Vec<DockPosition>, // <- This one is not an overwrite merge, it is an extend merge
     pub close_on_file_delete: bool,
     pub use_system_window_tabs: bool,
     pub zoomed_padding: bool,
 }
 
-#[derive(Copy, Clone, Default, Serialize, Deserialize, JsonSchema)]
-#[serde(rename_all = "snake_case")]
-pub enum OnLastWindowClosed {
-    /// Match platform conventions by default, so don't quit on macOS, and quit on other platforms
-    #[default]
-    PlatformDefault,
-    /// Quit the application the last window is closed
-    QuitApp,
+#[derive(Copy, Clone, Debug, PartialEq)]
+pub struct CenteredLayoutSettings {
+    /// The relative width of the left padding of the central pane from the
+    /// workspace when the centered layout is used.
+    ///
+    /// Default: 0.2
+    pub left_padding: f32,
+    // The relative width of the right padding of the central pane from the
+    // workspace when the centered layout is used.
+    ///
+    /// Default: 0.2
+    pub right_padding: f32,
 }
 
-impl OnLastWindowClosed {
-    pub fn is_quit_app(&self) -> bool {
-        match self {
-            OnLastWindowClosed::PlatformDefault => false,
-            OnLastWindowClosed::QuitApp => true,
-        }
-    }
+#[derive(Copy, Clone, PartialEq, Debug, Default)]
+pub struct ActivePanelModifiers {
+    /// Size of the border surrounding the active pane.
+    /// When set to 0, the active pane doesn't have any border.
+    /// The border is drawn inset.
+    ///
+    /// Default: `0.0`
+    // TODO: make this not an option, it is never None
+    pub border_size: Option<f32>,
+    /// Opacity of inactive panels.
+    /// When set to 1.0, the inactive panes have the same opacity as the active one.
+    /// If set to 0, the inactive panes content will not be visible at all.
+    /// Values are clamped to the [0.0, 1.0] range.
+    ///
+    /// Default: `1.0`
+    // TODO: make this not an option, it is never None
+    pub inactive_opacity: Option<f32>,
 }
 
 #[derive(Deserialize)]
@@ -58,14 +76,122 @@ pub struct TabBarSettings {
     pub show_nav_history_buttons: bool,
     pub show_tab_bar_buttons: bool,
 }
+
 impl Settings for WorkspaceSettings {
-    type FileContent = WorkspaceSettingsContent;
+    fn from_defaults(content: &settings::SettingsContent, cx: &mut App) -> Self {
+        let workspace = &content.workspace;
+        Self {
+            active_pane_modifiers: ActivePanelModifiers {
+                border_size: Some(
+                    workspace
+                        .active_pane_modifiers
+                        .unwrap()
+                        .border_size
+                        .unwrap(),
+                ),
+                inactive_opacity: Some(
+                    workspace
+                        .active_pane_modifiers
+                        .unwrap()
+                        .inactive_opacity
+                        .unwrap(),
+                ),
+            },
+            bottom_dock_layout: workspace.bottom_dock_layout.clone().unwrap(),
+            pane_split_direction_horizontal: workspace
+                .pane_split_direction_horizontal
+                .clone()
+                .unwrap(),
+            pane_split_direction_vertical: workspace.pane_split_direction_vertical.clone().unwrap(),
+            centered_layout: workspace.centered_layout.clone().unwrap(),
+            confirm_quit: workspace.confirm_quit.clone().unwrap(),
+            show_call_status_icon: workspace.show_call_status_icon.clone().unwrap(),
+            autosave: workspace.autosave.clone().unwrap(),
+            restore_on_startup: workspace.restore_on_startup.clone().unwrap(),
+            restore_on_file_reopen: workspace.restore_on_file_reopen.clone().unwrap(),
+            drop_target_size: workspace.drop_target_size.clone().unwrap(),
+            use_system_path_prompts: workspace.use_system_path_prompts.clone().unwrap(),
+            use_system_prompts: workspace.use_system_prompts.clone().unwrap(),
+            command_aliases: workspace.command_aliases.clone(),
+            max_tabs: workspace.max_tabs.clone(),
+            when_closing_with_no_tabs: workspace.when_closing_with_no_tabs.clone().unwrap(),
+            on_last_window_closed: workspace.on_last_window_closed.clone().unwrap(),
+            resize_all_panels_in_dock: workspace
+                .resize_all_panels_in_dock
+                .iter()
+                .copied()
+                .map(Into::into)
+                .collect(),
+            close_on_file_delete: workspace.close_on_file_delete.clone().unwrap(),
+            use_system_window_tabs: workspace.use_system_window_tabs.clone().unwrap(),
+            zoomed_padding: workspace.zoomed_padding.clone().unwrap(),
+        }
+    }
 
-    fn load(sources: SettingsSources<Self::FileContent>, _: &mut App) -> Result<Self> {
-        sources.json_merge()
+    fn refine(&mut self, content: &settings::SettingsContent, cx: &mut App) {
+        let workspace = &content.workspace;
+        if let Some(border_size) = *&workspace
+            .active_pane_modifiers
+            .and_then(|modifier| modifier.border_size)
+        {
+            self.active_pane_modifiers.border_size = Some(border_size);
+        }
+
+        if let Some(inactive_opacity) = *&workspace
+            .active_pane_modifiers
+            .and_then(|modifier| modifier.inactive_opacity)
+        {
+            self.active_pane_modifiers.inactive_opacity = Some(inactive_opacity);
+        }
+
+        self.bottom_dock_layout
+            .merge_from(&workspace.bottom_dock_layout);
+        self.pane_split_direction_horizontal
+            .merge_from(&workspace.pane_split_direction_horizontal);
+        self.pane_split_direction_vertical
+            .merge_from(&workspace.pane_split_direction_vertical);
+        self.centered_layout.merge_from(&workspace.centered_layout);
+        self.confirm_quit.merge_from(&workspace.confirm_quit);
+        self.show_call_status_icon
+            .merge_from(&workspace.show_call_status_icon);
+        self.autosave.merge_from(&workspace.autosave);
+        self.restore_on_startup
+            .merge_from(&workspace.restore_on_startup);
+        self.restore_on_file_reopen
+            .merge_from(&workspace.restore_on_file_reopen);
+        self.drop_target_size
+            .merge_from(&workspace.drop_target_size);
+        self.use_system_path_prompts
+            .merge_from(&workspace.use_system_path_prompts);
+        self.use_system_prompts
+            .merge_from(&workspace.use_system_prompts);
+        self.command_aliases
+            .extend(workspace.command_aliases.clone());
+        if let Some(max_tabs) = workspace.max_tabs {
+            self.max_tabs = Some(max_tabs);
+        }
+        self.when_closing_with_no_tabs
+            .merge_from(&workspace.when_closing_with_no_tabs);
+        self.on_last_window_closed
+            .merge_from(&workspace.on_last_window_closed);
+        self.resize_all_panels_in_dock.extend(
+            workspace
+                .resize_all_panels_in_dock
+                .iter()
+                .copied()
+                .map(Into::<DockPosition>::into),
+        );
+        self.close_on_file_delete
+            .merge_from(&workspace.close_on_file_delete);
+        self.use_system_window_tabs
+            .merge_from(&workspace.use_system_window_tabs);
+        self.zoomed_padding.merge_from(&workspace.zoomed_padding);
     }
 
-    fn import_from_vscode(vscode: &settings::VsCodeSettings, current: &mut Self::FileContent) {
+    fn import_from_vscode(
+        vscode: &settings::VsCodeSettings,
+        current: &mut settings::SettingsContent,
+    ) {
         if vscode
             .read_bool("accessibility.dimUnfocused.enabled")
             .unwrap_or_default()
@@ -73,19 +199,16 @@ impl Settings for WorkspaceSettings {
                 .read_value("accessibility.dimUnfocused.opacity")
                 .and_then(|v| v.as_f64())
         {
-            if let Some(settings) = current.active_pane_modifiers.as_mut() {
-                settings.inactive_opacity = Some(opacity as f32)
-            } else {
-                current.active_pane_modifiers = Some(ActivePanelModifiers {
-                    inactive_opacity: Some(opacity as f32),
-                    ..Default::default()
-                })
-            }
+            current
+                .workspace
+                .active_pane_modifiers
+                .get_or_insert_default()
+                .inactive_opacity = Some(opacity as f32);
         }
 
         vscode.enum_setting(
             "window.confirmBeforeClose",
-            &mut current.confirm_quit,
+            &mut current.workspace.confirm_quit,
             |s| match s {
                 "always" | "keyboardOnly" => Some(true),
                 "never" => Some(false),
@@ -95,22 +218,22 @@ impl Settings for WorkspaceSettings {
 
         vscode.bool_setting(
             "workbench.editor.restoreViewState",
-            &mut current.restore_on_file_reopen,
+            &mut current.workspace.restore_on_file_reopen,
         );
 
         if let Some(b) = vscode.read_bool("window.closeWhenEmpty") {
-            current.when_closing_with_no_tabs = Some(if b {
-                CloseWindowWhenNoItems::CloseWindow
+            current.workspace.when_closing_with_no_tabs = Some(if b {
+                settings::CloseWindowWhenNoItems::CloseWindow
             } else {
-                CloseWindowWhenNoItems::KeepWindowOpen
-            })
+                settings::CloseWindowWhenNoItems::KeepWindowOpen
+            });
         }
 
         if let Some(b) = vscode.read_bool("files.simpleDialog.enable") {
-            current.use_system_path_prompts = Some(!b);
+            current.workspace.use_system_path_prompts = Some(!b);
         }
 
-        vscode.enum_setting("files.autoSave", &mut current.autosave, |s| match s {
+        if let Some(v) = vscode.read_enum("files.autoSave", |s| match s {
             "off" => Some(AutosaveSetting::Off),
             "afterDelay" => Some(AutosaveSetting::AfterDelay {
                 milliseconds: vscode
@@ -121,7 +244,9 @@ impl Settings for WorkspaceSettings {
             "onFocusChange" => Some(AutosaveSetting::OnFocusChange),
             "onWindowChange" => Some(AutosaveSetting::OnWindowChange),
             _ => None,
-        });
+        }) {
+            current.workspace.autosave = Some(v);
+        }
 
         // workbench.editor.limit contains "enabled", "value", and "perEditorGroup"
         // our semantics match if those are set to true, some N, and true respectively.
@@ -134,10 +259,12 @@ impl Settings for WorkspaceSettings {
                 .read_bool("workbench.editor.limit.enabled")
                 .unwrap_or_default()
         {
-            current.max_tabs = Some(n)
+            current.workspace.max_tabs = Some(n)
         }
 
-        vscode.bool_setting("window.nativeTabs", &mut current.use_system_window_tabs);
+        if let Some(b) = vscode.read_bool("window.nativeTabs") {
+            current.workspace.use_system_window_tabs = Some(b);
+        }
 
         // some combination of "window.restoreWindows" and "workbench.startupEditor" might
         // map to our "restore_on_startup"
@@ -148,24 +275,23 @@ impl Settings for WorkspaceSettings {
 }
 
 impl Settings for TabBarSettings {
-    type FileContent = TabBarSettingsContent;
-
-    fn load(sources: SettingsSources<Self::FileContent>, _: &mut App) -> Result<Self> {
-        sources.json_merge()
-    }
-
-    fn import_from_vscode(vscode: &settings::VsCodeSettings, current: &mut Self::FileContent) {
-        vscode.enum_setting(
-            "workbench.editor.showTabs",
-            &mut current.show,
-            |s| match s {
-                "multiple" => Some(true),
-                "single" | "none" => Some(false),
-                _ => None,
-            },
-        );
+    fn import_from_vscode(
+        vscode: &settings::VsCodeSettings,
+        current: &mut settings::SettingsContent,
+    ) {
+        if let Some(b) = vscode.read_enum("workbench.editor.showTabs", |s| match s {
+            "multiple" => Some(true),
+            "single" | "none" => Some(false),
+            _ => None,
+        }) {
+            current.workspace.tab_bar.get_or_insert_default().show = Some(b);
+        }
         if Some("hidden") == vscode.read_string("workbench.editor.editorActionsLocation") {
-            current.show_tab_bar_buttons = Some(false)
+            current
+                .workspace
+                .tab_bar
+                .get_or_insert_default()
+                .show_tab_bar_buttons = Some(false)
         }
     }
 }