diff --git a/assets/settings/default.json b/assets/settings/default.json index 4585433a69d539dd63a2d19f3c3f1f17c5b84b5d..21cd3b84041b89344516145dbdfe79151199bf65 100644 --- a/assets/settings/default.json +++ b/assets/settings/default.json @@ -1,5 +1,7 @@ { - "project_name": null, + /// The displayed name of this project. If not set or empty, the root directory name + /// will be displayed. + "project_name": "", // The name of the Zed theme to use for the UI. // // `mode` is one of: diff --git a/crates/settings/src/settings_content/project.rs b/crates/settings/src/settings_content/project.rs index cc258148e396bb1d4ebf879423f1900b84e082c3..dce2a39d32d7b570407c209668bebf56d6c34704 100644 --- a/crates/settings/src/settings_content/project.rs +++ b/crates/settings/src/settings_content/project.rs @@ -50,10 +50,10 @@ pub struct ProjectSettingsContent { #[skip_serializing_none] #[derive(Clone, Debug, Default, PartialEq, Serialize, Deserialize, JsonSchema, MergeFrom)] pub struct WorktreeSettingsContent { - /// The displayed name of this project. If not set, the root directory name + /// The displayed name of this project. If not set or empty, the root directory name /// will be displayed. /// - /// Default: none + /// Default: "" pub project_name: Option, /// Completely ignore files matching globs from `file_scan_exclusions`. Overrides diff --git a/crates/settings/src/settings_store.rs b/crates/settings/src/settings_store.rs index e959756bac8aaaddd01a49b82e2dcf0ee85d1a1f..b94a24866c76a57328f3b1ebf6a688b2fa4b3820 100644 --- a/crates/settings/src/settings_store.rs +++ b/crates/settings/src/settings_store.rs @@ -157,13 +157,12 @@ pub struct SettingsStore { mpsc::UnboundedSender LocalBoxFuture<'static, Result<()>>>>, } -#[derive(Clone, PartialEq)] +#[derive(Clone, PartialEq, Debug)] pub enum SettingsFile { User, - Global, - Extension, Server, Default, + /// Local also represents project settings in ssh projects as well as local projects Local((WorktreeId, Arc)), } @@ -479,19 +478,98 @@ impl SettingsStore { // ignoring profiles // ignoring os profiles // ignoring release channel profiles + // ignoring global + // ignoring extension if self.user_settings.is_some() { files.push(SettingsFile::User); } - if self.extension_settings.is_some() { - files.push(SettingsFile::Extension); - } - if self.global_settings.is_some() { - files.push(SettingsFile::Global); - } files.push(SettingsFile::Default); files } + + fn get_content_for_file(&self, file: SettingsFile) -> Option<&SettingsContent> { + match file { + SettingsFile::User => self + .user_settings + .as_ref() + .map(|settings| settings.content.as_ref()), + SettingsFile::Default => Some(self.default_settings.as_ref()), + SettingsFile::Server => self.server_settings.as_deref(), + SettingsFile::Local(ref key) => self.local_settings.get(key), + } + } + + pub fn get_overrides_for_field( + &self, + target_file: SettingsFile, + get: fn(&SettingsContent) -> &Option, + ) -> Vec { + let all_files = self.get_all_files(); + let mut found_file = false; + let mut overrides = Vec::new(); + + for file in all_files.into_iter().rev() { + if !found_file { + found_file = file == target_file; + continue; + } + + if let SettingsFile::Local((wt_id, ref path)) = file + && let SettingsFile::Local((target_wt_id, ref target_path)) = target_file + && (wt_id != target_wt_id || !target_path.starts_with(path)) + { + // if requesting value from a local file, don't return values from local files in different worktrees + continue; + } + + let Some(content) = self.get_content_for_file(file.clone()) else { + continue; + }; + if get(content).is_some() { + overrides.push(file); + } + } + + overrides + } + + pub fn get_value_from_file( + &self, + target_file: SettingsFile, + pick: fn(&SettingsContent) -> &Option, + ) -> (SettingsFile, &T) { + // TODO: Add a metadata field for overriding the "overrides" tag, for contextually different settings + // e.g. disable AI isn't overridden, or a vec that gets extended instead or some such + + // todo(settings_ui) cache all files + let all_files = self.get_all_files(); + let mut found_file = false; + + for file in all_files.into_iter() { + if !found_file && file != target_file && file != SettingsFile::Default { + continue; + } + found_file = true; + + if let SettingsFile::Local((wt_id, ref path)) = file + && let SettingsFile::Local((target_wt_id, ref target_path)) = target_file + && (wt_id != target_wt_id || !target_path.starts_with(&path)) + { + // if requesting value from a local file, don't return values from local files in different worktrees + continue; + } + + let Some(content) = self.get_content_for_file(file.clone()) else { + continue; + }; + if let Some(value) = pick(content).as_ref() { + return (file, value); + } + } + + unreachable!("All values should have defaults"); + } } impl SettingsStore { @@ -1609,4 +1687,314 @@ mod tests { } ); } + + #[gpui::test] + fn test_get_value_for_field_basic(cx: &mut App) { + let mut store = SettingsStore::new(cx, &test_settings()); + store.register_setting::(cx); + + store + .set_user_settings(r#"{"preferred_line_length": 0}"#, cx) + .unwrap(); + let local = (WorktreeId::from_usize(0), RelPath::empty().into_arc()); + store + .set_local_settings( + local.0, + local.1.clone(), + LocalSettingsKind::Settings, + Some(r#"{}"#), + cx, + ) + .unwrap(); + + fn get(content: &SettingsContent) -> &Option { + &content.project.all_languages.defaults.preferred_line_length + } + + let default_value = get(&store.default_settings).unwrap(); + + assert_eq!( + store.get_value_from_file(SettingsFile::Local(local.clone()), get), + (SettingsFile::User, &0) + ); + assert_eq!( + store.get_value_from_file(SettingsFile::User, get), + (SettingsFile::User, &0) + ); + store.set_user_settings(r#"{}"#, cx).unwrap(); + assert_eq!( + store.get_value_from_file(SettingsFile::Local(local.clone()), get), + (SettingsFile::Default, &default_value) + ); + store + .set_local_settings( + local.0, + local.1.clone(), + LocalSettingsKind::Settings, + Some(r#"{"preferred_line_length": 80}"#), + cx, + ) + .unwrap(); + assert_eq!( + store.get_value_from_file(SettingsFile::Local(local.clone()), get), + (SettingsFile::Local(local), &80) + ); + assert_eq!( + store.get_value_from_file(SettingsFile::User, get), + (SettingsFile::Default, &default_value) + ); + } + + #[gpui::test] + fn test_get_value_for_field_local_worktrees_dont_interfere(cx: &mut App) { + let mut store = SettingsStore::new(cx, &test_settings()); + store.register_setting::(cx); + store.register_setting::(cx); + + let local_1 = (WorktreeId::from_usize(0), RelPath::empty().into_arc()); + + let local_1_child = ( + WorktreeId::from_usize(0), + RelPath::new( + std::path::Path::new("child1"), + util::paths::PathStyle::Posix, + ) + .unwrap() + .into_arc(), + ); + + let local_2 = (WorktreeId::from_usize(1), RelPath::empty().into_arc()); + let local_2_child = ( + WorktreeId::from_usize(1), + RelPath::new( + std::path::Path::new("child2"), + util::paths::PathStyle::Posix, + ) + .unwrap() + .into_arc(), + ); + + fn get(content: &SettingsContent) -> &Option { + &content.project.all_languages.defaults.preferred_line_length + } + + store + .set_local_settings( + local_1.0, + local_1.1.clone(), + LocalSettingsKind::Settings, + Some(r#"{"preferred_line_length": 1}"#), + cx, + ) + .unwrap(); + store + .set_local_settings( + local_1_child.0, + local_1_child.1.clone(), + LocalSettingsKind::Settings, + Some(r#"{}"#), + cx, + ) + .unwrap(); + store + .set_local_settings( + local_2.0, + local_2.1.clone(), + LocalSettingsKind::Settings, + Some(r#"{"preferred_line_length": 2}"#), + cx, + ) + .unwrap(); + store + .set_local_settings( + local_2_child.0, + local_2_child.1.clone(), + LocalSettingsKind::Settings, + Some(r#"{}"#), + cx, + ) + .unwrap(); + + // each local child should only inherit from it's parent + assert_eq!( + store.get_value_from_file(SettingsFile::Local(local_2_child), get), + (SettingsFile::Local(local_2), &2) + ); + assert_eq!( + store.get_value_from_file(SettingsFile::Local(local_1_child.clone()), get), + (SettingsFile::Local(local_1.clone()), &1) + ); + + // adjacent children should be treated as siblings not inherit from each other + let local_1_adjacent_child = (local_1.0, rel_path("adjacent_child").into_arc()); + store + .set_local_settings( + local_1_adjacent_child.0, + local_1_adjacent_child.1.clone(), + LocalSettingsKind::Settings, + Some(r#"{}"#), + cx, + ) + .unwrap(); + store + .set_local_settings( + local_1_child.0, + local_1_child.1.clone(), + LocalSettingsKind::Settings, + Some(r#"{"preferred_line_length": 3}"#), + cx, + ) + .unwrap(); + + assert_eq!( + store.get_value_from_file(SettingsFile::Local(local_1_adjacent_child.clone()), get), + (SettingsFile::Local(local_1.clone()), &1) + ); + store + .set_local_settings( + local_1_adjacent_child.0, + local_1_adjacent_child.1, + LocalSettingsKind::Settings, + Some(r#"{"preferred_line_length": 3}"#), + cx, + ) + .unwrap(); + store + .set_local_settings( + local_1_child.0, + local_1_child.1.clone(), + LocalSettingsKind::Settings, + Some(r#"{}"#), + cx, + ) + .unwrap(); + assert_eq!( + store.get_value_from_file(SettingsFile::Local(local_1_child), get), + (SettingsFile::Local(local_1), &1) + ); + } + + #[gpui::test] + fn test_get_overrides_for_field(cx: &mut App) { + let mut store = SettingsStore::new(cx, &test_settings()); + store.register_setting::(cx); + + let wt0_root = (WorktreeId::from_usize(0), RelPath::empty().into_arc()); + let wt0_child1 = (WorktreeId::from_usize(0), rel_path("child1").into_arc()); + let wt0_child2 = (WorktreeId::from_usize(0), rel_path("child2").into_arc()); + + let wt1_root = (WorktreeId::from_usize(1), RelPath::empty().into_arc()); + let wt1_subdir = (WorktreeId::from_usize(1), rel_path("subdir").into_arc()); + + fn get(content: &SettingsContent) -> &Option { + &content.project.all_languages.defaults.preferred_line_length + } + + store + .set_user_settings(r#"{"preferred_line_length": 100}"#, cx) + .unwrap(); + + store + .set_local_settings( + wt0_root.0, + wt0_root.1.clone(), + LocalSettingsKind::Settings, + Some(r#"{"preferred_line_length": 80}"#), + cx, + ) + .unwrap(); + store + .set_local_settings( + wt0_child1.0, + wt0_child1.1.clone(), + LocalSettingsKind::Settings, + Some(r#"{"preferred_line_length": 120}"#), + cx, + ) + .unwrap(); + store + .set_local_settings( + wt0_child2.0, + wt0_child2.1.clone(), + LocalSettingsKind::Settings, + Some(r#"{}"#), + cx, + ) + .unwrap(); + + store + .set_local_settings( + wt1_root.0, + wt1_root.1.clone(), + LocalSettingsKind::Settings, + Some(r#"{"preferred_line_length": 90}"#), + cx, + ) + .unwrap(); + store + .set_local_settings( + wt1_subdir.0, + wt1_subdir.1.clone(), + LocalSettingsKind::Settings, + Some(r#"{}"#), + cx, + ) + .unwrap(); + + let overrides = store.get_overrides_for_field(SettingsFile::Default, get); + assert_eq!( + overrides, + vec![ + SettingsFile::User, + SettingsFile::Local(wt0_root.clone()), + SettingsFile::Local(wt0_child1.clone()), + SettingsFile::Local(wt1_root.clone()), + ] + ); + + let overrides = store.get_overrides_for_field(SettingsFile::User, get); + assert_eq!( + overrides, + vec![ + SettingsFile::Local(wt0_root.clone()), + SettingsFile::Local(wt0_child1.clone()), + SettingsFile::Local(wt1_root.clone()), + ] + ); + + let overrides = store.get_overrides_for_field(SettingsFile::Local(wt0_root), get); + assert_eq!(overrides, vec![]); + + let overrides = store.get_overrides_for_field(SettingsFile::Local(wt0_child1.clone()), get); + assert_eq!(overrides, vec![]); + + let overrides = store.get_overrides_for_field(SettingsFile::Local(wt0_child2), get); + assert_eq!(overrides, vec![]); + + let overrides = store.get_overrides_for_field(SettingsFile::Local(wt1_root), get); + assert_eq!(overrides, vec![]); + + let overrides = store.get_overrides_for_field(SettingsFile::Local(wt1_subdir), get); + assert_eq!(overrides, vec![]); + + let wt0_deep_child = ( + WorktreeId::from_usize(0), + rel_path("child1/subdir").into_arc(), + ); + store + .set_local_settings( + wt0_deep_child.0, + wt0_deep_child.1.clone(), + LocalSettingsKind::Settings, + Some(r#"{"preferred_line_length": 140}"#), + cx, + ) + .unwrap(); + + let overrides = store.get_overrides_for_field(SettingsFile::Local(wt0_deep_child), get); + assert_eq!(overrides, vec![]); + + let overrides = store.get_overrides_for_field(SettingsFile::Local(wt0_child1), get); + assert_eq!(overrides, vec![]); + } } diff --git a/crates/settings_ui/src/settings_ui.rs b/crates/settings_ui/src/settings_ui.rs index c5f9258998c7ca9a778e6046c741db7cba7f122b..d52e2eea8a09f99d7d57943cce84f02251a7bd5c 100644 --- a/crates/settings_ui/src/settings_ui.rs +++ b/crates/settings_ui/src/settings_ui.rs @@ -22,16 +22,17 @@ use util::{paths::PathStyle, rel_path::RelPath}; use crate::components::SettingsEditor; -#[derive(Clone)] +#[derive(Clone, Copy)] struct SettingField { - pick: fn(&SettingsContent) -> &T, - pick_mut: fn(&mut SettingsContent) -> &mut T, + pick: fn(&SettingsContent) -> &Option, + pick_mut: fn(&mut SettingsContent) -> &mut Option, } trait AnySettingField { fn as_any(&self) -> &dyn Any; fn type_name(&self) -> &'static str; fn type_id(&self) -> TypeId; + fn file_set_in(&self, file: SettingsUiFile, cx: &App) -> settings::SettingsFile; } impl AnySettingField for SettingField { @@ -46,6 +47,13 @@ impl AnySettingField for SettingField { fn type_id(&self) -> TypeId { TypeId::of::() } + + fn file_set_in(&self, file: SettingsUiFile, cx: &App) -> settings::SettingsFile { + let (file, _) = cx + .global::() + .get_value_from_file(file.to_settings(), self.pick); + return file; + } } #[derive(Default, Clone)] @@ -57,6 +65,7 @@ struct SettingFieldRenderer { Box< dyn Fn( &dyn AnySettingField, + SettingsUiFile, Option<&SettingsFieldMetadata>, &mut Window, &mut App, @@ -74,6 +83,7 @@ impl SettingFieldRenderer { &mut self, renderer: impl Fn( &SettingField, + SettingsUiFile, Option<&SettingsFieldMetadata>, &mut Window, &mut App, @@ -83,6 +93,7 @@ impl SettingFieldRenderer { let key = TypeId::of::(); let renderer = Box::new( move |any_setting_field: &dyn AnySettingField, + settings_file: SettingsUiFile, metadata: Option<&SettingsFieldMetadata>, window: &mut Window, cx: &mut App| { @@ -90,7 +101,7 @@ impl SettingFieldRenderer { .as_any() .downcast_ref::>() .unwrap(); - renderer(field, metadata, window, cx) + renderer(field, settings_file, metadata, window, cx) }, ); self.renderers.borrow_mut().insert(key, renderer); @@ -100,13 +111,14 @@ impl SettingFieldRenderer { fn render( &self, any_setting_field: &dyn AnySettingField, + settings_file: SettingsUiFile, metadata: Option<&SettingsFieldMetadata>, window: &mut Window, cx: &mut App, ) -> AnyElement { let key = any_setting_field.type_id(); if let Some(renderer) = self.renderers.borrow().get(&key) { - renderer(any_setting_field, metadata, window, cx) + renderer(any_setting_field, settings_file, metadata, window, cx) } else { panic!( "No renderer found for type: {}", @@ -269,18 +281,19 @@ pub fn init(cx: &mut App) { } fn init_renderers(cx: &mut App) { + // fn (field: SettingsField, current_file: SettingsFile, cx) -> (currently_set_in: SettingsFile, overridden_in: Vec) cx.default_global::() - .add_renderer::>(|settings_field, _, _, cx| { - render_toggle_button(settings_field.clone(), cx).into_any_element() + .add_renderer::(|settings_field, file, _, _, cx| { + render_toggle_button(*settings_field, file, cx).into_any_element() }) - .add_renderer::>(|settings_field, metadata, _, cx| { - render_text_field(settings_field.clone(), metadata, cx) + .add_renderer::(|settings_field, file, metadata, _, cx| { + render_text_field(settings_field.clone(), file, metadata, cx) }) - .add_renderer::>(|settings_field, _, _, cx| { - render_toggle_button(settings_field.clone(), cx) + .add_renderer::(|settings_field, file, _, _, cx| { + render_toggle_button(*settings_field, file, cx) }) - .add_renderer::>(|settings_field, _, window, cx| { - render_dropdown(settings_field.clone(), window, cx) + .add_renderer::(|settings_field, file, _, window, cx| { + render_dropdown(*settings_field, file, window, cx) }); } @@ -304,8 +317,8 @@ pub fn open_settings_editor(cx: &mut App) -> anyhow::Result, - current_file: SettingsFile, + files: Vec, + current_file: SettingsUiFile, pages: Vec, search: Entity, navbar_entry: usize, // Index into pages - should probably be (usize, Option) for section + page @@ -340,7 +353,7 @@ enum SettingsPageItem { } impl SettingsPageItem { - fn render(&self, _file: SettingsFile, window: &mut Window, cx: &mut App) -> AnyElement { + fn render(&self, file: SettingsUiFile, window: &mut Window, cx: &mut App) -> AnyElement { match self { SettingsPageItem::SectionHeader(header) => v_flex() .w_full() @@ -350,6 +363,9 @@ impl SettingsPageItem { .into_any_element(), SettingsPageItem::SettingItem(setting_item) => { let renderer = cx.default_global::().clone(); + let file_set_in = + SettingsUiFile::from_settings(setting_item.field.file_set_in(file.clone(), cx)); + h_flex() .id(setting_item.title) .w_full() @@ -361,8 +377,25 @@ impl SettingsPageItem { .max_w_1_2() .flex_shrink() .child( - Label::new(SharedString::new_static(setting_item.title)) - .size(LabelSize::Default), + h_flex() + .w_full() + .gap_4() + .child( + Label::new(SharedString::new_static(setting_item.title)) + .size(LabelSize::Default), + ) + .when_some( + file_set_in.filter(|file_set_in| file_set_in != &file), + |elem, file_set_in| { + elem.child( + Label::new(format!( + "set in {}", + file_set_in.name() + )) + .color(Color::Muted), + ) + }, + ), ) .child( Label::new(SharedString::new_static(setting_item.description)) @@ -372,6 +405,7 @@ impl SettingsPageItem { ) .child(renderer.render( setting_item.field.as_ref(), + file, setting_item.metadata.as_deref(), window, cx, @@ -391,36 +425,53 @@ struct SettingItem { #[allow(unused)] #[derive(Clone, PartialEq)] -enum SettingsFile { +enum SettingsUiFile { User, // Uses all settings. Local((WorktreeId, Arc)), // Has a special name, and special set of settings Server(&'static str), // Uses a special name, and the user settings } -impl SettingsFile { +impl SettingsUiFile { fn pages(&self) -> Vec { match self { - SettingsFile::User => user_settings_data(), - SettingsFile::Local(_) => project_settings_data(), - SettingsFile::Server(_) => user_settings_data(), + SettingsUiFile::User => user_settings_data(), + SettingsUiFile::Local(_) => project_settings_data(), + SettingsUiFile::Server(_) => user_settings_data(), } } fn name(&self) -> SharedString { match self { - SettingsFile::User => SharedString::new_static("User"), + SettingsUiFile::User => SharedString::new_static("User"), // TODO is PathStyle::local() ever not appropriate? - SettingsFile::Local((_, path)) => { + SettingsUiFile::Local((_, path)) => { format!("Local ({})", path.display(PathStyle::local())).into() } - SettingsFile::Server(file) => format!("Server ({})", file).into(), + SettingsUiFile::Server(file) => format!("Server ({})", file).into(), + } + } + + fn from_settings(file: settings::SettingsFile) -> Option { + Some(match file { + settings::SettingsFile::User => SettingsUiFile::User, + settings::SettingsFile::Local(location) => SettingsUiFile::Local(location), + settings::SettingsFile::Server => SettingsUiFile::Server("todo: server name"), + settings::SettingsFile::Default => return None, + }) + } + + fn to_settings(&self) -> settings::SettingsFile { + match self { + SettingsUiFile::User => settings::SettingsFile::User, + SettingsUiFile::Local(location) => settings::SettingsFile::Local(location.clone()), + SettingsUiFile::Server(_) => settings::SettingsFile::Server, } } } impl SettingsWindow { pub fn new(window: &mut Window, cx: &mut Context) -> Self { - let current_file = SettingsFile::User; + let current_file = SettingsUiFile::User; let search = cx.new(|cx| { let mut editor = Editor::single_line(window, cx); editor.set_placeholder_text("Search settings…", window, cx); @@ -496,26 +547,21 @@ impl SettingsWindow { let mut ui_files = vec![]; let all_files = settings_store.get_all_files(); for file in all_files { - let settings_ui_file = match file { - settings::SettingsFile::User => SettingsFile::User, - settings::SettingsFile::Global => continue, - settings::SettingsFile::Extension => continue, - settings::SettingsFile::Server => SettingsFile::Server("todo: server name"), - settings::SettingsFile::Default => continue, - settings::SettingsFile::Local(location) => SettingsFile::Local(location), + let Some(settings_ui_file) = SettingsUiFile::from_settings(file) else { + continue; }; ui_files.push(settings_ui_file); } ui_files.reverse(); - if !ui_files.contains(&self.current_file) { + self.files = ui_files; + if !self.files.contains(&self.current_file) { self.change_file(0, cx); } - self.files = ui_files; } fn change_file(&mut self, ix: usize, cx: &mut Context) { if ix >= self.files.len() { - self.current_file = SettingsFile::User; + self.current_file = SettingsUiFile::User; return; } if self.files[ix] == self.current_file { @@ -682,25 +728,19 @@ impl Render for SettingsWindow { } } +// fn read_field(pick: fn(&SettingsContent) -> &Option, file: SettingsFile, cx: &App) -> Option { +// let (_, value) = cx.global::().get_value_from_file(file.to_settings(), (), pick); +// } + fn render_text_field( - field: SettingField>, + field: SettingField, + file: SettingsUiFile, metadata: Option<&SettingsFieldMetadata>, cx: &mut App, ) -> AnyElement { - // TODO: in settings window state - let store = SettingsStore::global(cx); - - // TODO: This clone needs to go!! - let defaults = store.raw_default_settings().clone(); - let user_settings = store - .raw_user_settings() - .cloned() - .unwrap_or_default() - .content; - - let initial_text = (field.pick)(&user_settings) - .clone() - .or_else(|| (field.pick)(&defaults).clone()); + let (_, initial_text) = + SettingsStore::global(cx).get_value_from_file(file.to_settings(), field.pick); + let initial_text = Some(initial_text.clone()).filter(|s| !s.is_empty()); SettingsEditor::new() .when_some(initial_text, |editor, text| editor.with_initial_text(text)) @@ -719,24 +759,13 @@ fn render_text_field( } fn render_toggle_button + From + Copy>( - field: SettingField>, + field: SettingField, + file: SettingsUiFile, cx: &mut App, ) -> AnyElement { - // TODO: in settings window state - let store = SettingsStore::global(cx); - - // TODO: This clone needs to go!! - let defaults = store.raw_default_settings().clone(); - let user_settings = store - .raw_user_settings() - .cloned() - .unwrap_or_default() - .content; - - let toggle_state = if (field.pick)(&user_settings) - .unwrap_or_else(|| (field.pick)(&defaults).unwrap()) - .into() - { + let (_, &value) = SettingsStore::global(cx).get_value_from_file(file.to_settings(), field.pick); + + let toggle_state = if value.into() { ui::ToggleState::Selected } else { ui::ToggleState::Unselected @@ -746,7 +775,7 @@ fn render_toggle_button + From + Copy>( .on_click({ move |state, _window, cx| { let state = *state == ui::ToggleState::Selected; - let field = field.clone(); + let field = field; cx.update_global(move |store: &mut SettingsStore, cx| { store.update_settings_file(::global(cx), move |settings, _cx| { *(field.pick_mut)(settings) = Some(state.into()); @@ -758,7 +787,8 @@ fn render_toggle_button + From + Copy>( } fn render_dropdown( - field: SettingField>, + field: SettingField, + file: SettingsUiFile, window: &mut Window, cx: &mut App, ) -> AnyElement @@ -768,16 +798,9 @@ where let variants = || -> &'static [T] { ::VARIANTS }; let labels = || -> &'static [&'static str] { ::VARIANTS }; - let store = SettingsStore::global(cx); - let defaults = store.raw_default_settings().clone(); - let user_settings = store - .raw_user_settings() - .cloned() - .unwrap_or_default() - .content; + let (_, ¤t_value) = + SettingsStore::global(cx).get_value_from_file(file.to_settings(), field.pick); - let current_value = - (field.pick)(&user_settings).unwrap_or_else(|| (field.pick)(&defaults).unwrap()); let current_value_label = labels()[variants().iter().position(|v| *v == current_value).unwrap()]; @@ -894,7 +917,7 @@ mod test { let mut settings_window = SettingsWindow { files: Vec::default(), - current_file: crate::SettingsFile::User, + current_file: crate::SettingsUiFile::User, pages, search: cx.new(|cx| Editor::single_line(window, cx)), navbar_entry: selected_idx.unwrap(), diff --git a/crates/worktree/src/worktree_settings.rs b/crates/worktree/src/worktree_settings.rs index 582a40021dc7c552d784134f2abeab44f1bf44bc..3e8fc6114a7ac0ca10fbe823fff9ab3a7115b3c4 100644 --- a/crates/worktree/src/worktree_settings.rs +++ b/crates/worktree/src/worktree_settings.rs @@ -51,7 +51,7 @@ impl Settings for WorktreeSettings { .collect(); Self { - project_name: None, + project_name: worktree.project_name.filter(|p| !p.is_empty()), file_scan_exclusions: path_matchers(file_scan_exclusions, "file_scan_exclusions") .log_err() .unwrap_or_default(),