From 27da40941d90e1d4c8ff9b48a2bca49cc53c9b5a Mon Sep 17 00:00:00 2001 From: Ben Kunkle Date: Tue, 16 Sep 2025 18:34:01 -0500 Subject: [PATCH] workspace pt 2 --- Cargo.lock | 1 + crates/project/src/project_settings.rs | 2 +- .../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(-) diff --git a/Cargo.lock b/Cargo.lock index cdc3adb1f170eb23bc02abd511b9cc6c093fcc53..5a9ca9a409c622b5cc7b5316b92f43399946e092 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -16600,6 +16600,7 @@ version = "0.1.0" dependencies = [ "anyhow", "clap", + "collections", "gpui", "indexmap", "log", diff --git a/crates/project/src/project_settings.rs b/crates/project/src/project_settings.rs index b9bd386de361c77edbba0fb4570652983b6ed0fa..192728ac66af21b02c8562b2f14a4a0f8b484364 100644 --- a/crates/project/src/project_settings.rs +++ b/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, }); diff --git a/crates/settings/src/settings_content/workspace.rs b/crates/settings/src/settings_content/workspace.rs index c9ecd867c4b56907c7ee189dcfe5f79aebabcc12..6a981ae0f9c3376536e4f23cd3ddccad5f765688 100644 --- a/crates/settings/src/settings_content/workspace.rs +++ b/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, @@ -69,7 +72,8 @@ pub struct WorkspaceSettingsContent { /// it will be assumed to equal the value. /// /// Default: true - pub command_aliases: Option>, + #[serde(default)] + pub command_aliases: HashMap, /// 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>, + #[serde(default)] + pub resize_all_panels_in_dock: Vec, /// 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, + + // Settings related to the editor's tab bar. + pub tab_bar: Option, + + pub tabs: Option, } #[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, } + +#[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, +} diff --git a/crates/settings/src/vscode_import.rs b/crates/settings/src/vscode_import.rs index 0c63b4ad304761d7d088a80baa9dbe281c2d266d..c0a055c3b6d33f741610852fab620fbb97f5c05b 100644 --- a/crates/settings/src/vscode_import.rs +++ b/crates/settings/src/vscode_import.rs @@ -137,7 +137,7 @@ impl VsCodeSettings { } // todo! replace enum_setting - pub fn read_enum_setting(&self, key: &str, f: impl FnOnce(&str) -> Option) -> Option { + pub fn read_enum(&self, key: &str, f: impl FnOnce(&str) -> Option) -> Option { self.content.get(key).and_then(Value::as_str).and_then(f) } } diff --git a/crates/theme_importer/Cargo.toml b/crates/theme_importer/Cargo.toml index f9f7daa5b3bd7d48ce0631d26d6a3c21767e5d5e..2fef5a62498d9ac0abfef3913edbd1dc711e5e64 100644 --- a/crates/theme_importer/Cargo.toml +++ b/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 diff --git a/crates/theme_importer/src/main.rs b/crates/theme_importer/src/main.rs index 339c88adea016dc260867ebce1128962bcd563e1..e10d21e4e297fef1ec96d98dea0e45de0ec7e73f 100644 --- a/crates/theme_importer/src/main.rs +++ b/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(); diff --git a/crates/theme_importer/src/vscode/converter.rs b/crates/theme_importer/src/vscode/converter.rs index b0fd312fff7cb45ed80743187ca313e3957b3fba..e4a9769978e7f2b987c1404474d0f029bec7977b 100644 --- a/crates/theme_importer/src/vscode/converter.rs +++ b/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> { - let mut highlight_styles = IndexMap::new(); + let mut highlight_styles = IndexMap::default(); for syntax_token in ZedSyntaxToken::iter() { let override_match = self diff --git a/crates/title_bar/src/title_bar_settings.rs b/crates/title_bar/src/title_bar_settings.rs index 0b386d496788547a91255ec5f175a99c1391bda4..5dce89b0cea0413a9c7096ad85c4d39e257d55ce 100644 --- a/crates/title_bar/src/title_bar_settings.rs +++ b/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); diff --git a/crates/workspace/src/dock.rs b/crates/workspace/src/dock.rs index 149a122c0c6a31b7c4713601acca5091accb96ac..e706a949b2ec713e17381ccd51497018fc2642c7 100644 --- a/crates/workspace/src/dock.rs +++ b/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 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 { diff --git a/crates/workspace/src/item.rs b/crates/workspace/src/item.rs index 055859bec395445de91978397905d2162723fce2..da4e557776072e33bd691c38d73b0c6623ac5a4c 100644 --- a/crates/workspace/src/item.rs +++ b/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, diff --git a/crates/workspace/src/pane.rs b/crates/workspace/src/pane.rs index 4ce8a890237f97db5596f55f607a603a2695ab7b..37706cc3985612777e26ac0d12e08cfbb4fb9b83 100644 --- a/crates/workspace/src/pane.rs +++ b/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::(|s, cx| { - s.update_user_settings::(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::(|s, cx| { - s.update_user_settings::(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) { cx.update_global(|store: &mut SettingsStore, cx| { - store.update_user_settings::(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()) }); }); } diff --git a/crates/workspace/src/workspace.rs b/crates/workspace/src/workspace.rs index 34aa0da8896fd66b00ffa7a5ce9c32ec74dd8b99..11425472a20ef8ac3f4639942be1f4f35ec88e47 100644 --- a/crates/workspace/src/workspace.rs +++ b/crates/workspace/src/workspace.rs @@ -1695,8 +1695,8 @@ impl Workspace { cx: &mut Context, ) { let fs = self.project().read(cx).fs(); - settings::update_settings_file::(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::(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::(cx, |settings| { - settings.autosave = Some(AutosaveSetting::OnWindowChange); + settings.update_user_settings(cx, |settings| { + settings.workspace.autosave = Some(AutosaveSetting::OnWindowChange); }) }); item.is_dirty = true; diff --git a/crates/workspace/src/workspace_settings.rs b/crates/workspace/src/workspace_settings.rs index 4108bec78384d49ecfbff83e5cbc2f6edcc11368..64e6c94e10a89c5ed03e5faa54488d11fea93ff1 100644 --- a/crates/workspace/src/workspace_settings.rs +++ b/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, pub max_tabs: Option, - pub when_closing_with_no_tabs: CloseWindowWhenNoItems, - pub on_last_window_closed: OnLastWindowClosed, - pub resize_all_panels_in_dock: Vec, + pub when_closing_with_no_tabs: settings::CloseWindowWhenNoItems, + pub on_last_window_closed: settings::OnLastWindowClosed, + pub resize_all_panels_in_dock: Vec, // <- 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, + /// 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, } #[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, _: &mut App) -> Result { - 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::::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, _: &mut App) -> Result { - 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) } } }