From f623ea55b0963ceebfceb97cf8355c4eac742260 Mon Sep 17 00:00:00 2001 From: Anthony Date: Tue, 21 Oct 2025 02:50:33 -0400 Subject: [PATCH] Basic proof of concept --- Cargo.lock | 1 + crates/settings_ui/Cargo.toml | 2 + crates/settings_ui/src/settings_ui.rs | 108 +++++++++++++++++++- crates/zed/resources/zed-debug.entitlements | 28 +++++ 4 files changed, 138 insertions(+), 1 deletion(-) create mode 100644 crates/zed/resources/zed-debug.entitlements diff --git a/Cargo.lock b/Cargo.lock index 6ff72c08b4..f4f44660f8 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -15294,6 +15294,7 @@ dependencies = [ "schemars 1.0.4", "search", "serde", + "serde_json", "session", "settings", "strum 0.27.2", diff --git a/crates/settings_ui/Cargo.toml b/crates/settings_ui/Cargo.toml index b8a75694ec..32c68b9f31 100644 --- a/crates/settings_ui/Cargo.toml +++ b/crates/settings_ui/Cargo.toml @@ -30,6 +30,7 @@ project.workspace = true schemars.workspace = true search.workspace = true serde.workspace = true +serde_json.workspace = true settings.workspace = true strum.workspace = true theme.workspace = true @@ -51,5 +52,6 @@ node_runtime.workspace = true paths.workspace = true session.workspace = true settings.workspace = true +workspace = { workspace = true, features = ["test-support"] } zlog.workspace = true pretty_assertions.workspace = true diff --git a/crates/settings_ui/src/settings_ui.rs b/crates/settings_ui/src/settings_ui.rs index ef3049ea20..b1491c6765 100644 --- a/crates/settings_ui/src/settings_ui.rs +++ b/crates/settings_ui/src/settings_ui.rs @@ -222,6 +222,81 @@ struct SettingFieldRenderer { impl Global for SettingFieldRenderer {} +#[derive(Default, Clone)] +struct SettingsJsonKeyFinder { + key_finders: Rc Option>>>>, +} + +impl Global for SettingsJsonKeyFinder {} + +impl SettingsJsonKeyFinder { + fn add_basic_json_key_finder( + &mut self, + field: SettingField, + ) -> &mut Self { + let key = TypeId::of::(); + let key_finder = Box::new(move |mut content: SettingsContent| { + // Write the field with a default value + (field.write)(&mut content, Some(T::default())); + + // Serialize to a pretty-printed JSON string + let json_string = serde_json::to_string_pretty(&content) + .expect("Failed to serialize SettingsContent"); + + // Extract the JSON path from the string (should only have one entry) + extract_json_path_from_string(&json_string) + }); + self.key_finders.borrow_mut().insert(key, key_finder); + self + } + + fn find_json_path(&self) -> Option { + let key = TypeId::of::(); + let key_finders = self.key_finders.borrow(); + let key_finder = key_finders.get(&key)?; + let content = SettingsContent::default(); + key_finder(content) + } +} + +/// Extracts the JSON key path from a serialized settings string. +/// Assumes only one field is set in the JSON. +fn extract_json_path_from_string(json: &str) -> Option { + use serde_json::Value; + + let value: Value = serde_json::from_str(json).ok()?; + + fn find_non_empty_path(value: &Value, prefix: &str) -> Option { + match value { + Value::Object(map) => { + for (key, val) in map { + let new_prefix = if prefix.is_empty() { + key.clone() + } else { + format!("{}.{}", prefix, key) + }; + + match val { + Value::Null => continue, + Value::Object(inner_map) if inner_map.is_empty() => continue, + Value::Array(arr) if arr.is_empty() => continue, + Value::Object(_) => { + if let Some(path) = find_non_empty_path(val, &new_prefix) { + return Some(path); + } + } + _ => return Some(new_prefix), + } + } + None + } + _ => None, + } + } + + find_non_empty_path(&value, "") +} + impl SettingFieldRenderer { fn add_basic_renderer( &mut self, @@ -343,6 +418,7 @@ impl FeatureFlag for SettingsUiFeatureFlag { pub fn init(cx: &mut App) { init_renderers(cx); + init_json_key_finders(cx); cx.observe_new(|workspace: &mut workspace::Workspace, _, _| { workspace.register_action(|workspace, _: &OpenSettings, window, cx| { @@ -356,6 +432,14 @@ pub fn init(cx: &mut App) { .detach(); } +fn init_json_key_finders(cx: &mut App) { + cx.default_global::() + .add_basic_json_key_finder(SettingField:: { + pick: |content| content.vim_mode.as_ref(), + write: |content, value| content.vim_mode = value, + }); +} + fn init_renderers(cx: &mut App) { cx.default_global::() .add_basic_renderer::(|_, _, _, _, _| { @@ -3114,8 +3198,25 @@ fn render_icon_theme_picker( #[cfg(test)] mod test { + use gpui::TestAppContext; + use workspace::AppState; + use super::*; + #[gpui::test] + fn test_json_path(cx: &mut TestAppContext) { + cx.update(|cx| { + register_settings(cx); + init_json_key_finders(cx); + + let json_key_finder = cx.global::(); + let path = json_key_finder.find_json_path::(); + dbg!(&path); + + assert_eq!(path, Some("vim_mode".to_string())); + }); + } + impl SettingsWindow { fn navbar_entry(&self) -> usize { self.navbar_entry @@ -3134,9 +3235,14 @@ mod test { } fn register_settings(cx: &mut App) { + let app_state = workspace::AppState::test(cx); + settings::init(cx); theme::init(theme::LoadThemes::JustBase, cx); - workspace::init_settings(cx); + // workspace::init_settings(cx); + workspace::init(app_state.clone(), cx); + AppState::set_global(Arc::downgrade(&app_state), cx); + project::Project::init_settings(cx); language::init(cx); editor::init(cx); diff --git a/crates/zed/resources/zed-debug.entitlements b/crates/zed/resources/zed-debug.entitlements new file mode 100644 index 0000000000..54705245ce --- /dev/null +++ b/crates/zed/resources/zed-debug.entitlements @@ -0,0 +1,28 @@ + + + + + com.apple.security.get-task-allow + + com.apple.security.automation.apple-events + + com.apple.security.cs.allow-jit + + com.apple.security.cs.allow-unsigned-executable-memory + + + com.apple.security.device.audio-input + + com.apple.security.device.camera + + com.apple.security.personal-information.addressbook + + com.apple.security.personal-information.calendars + + com.apple.security.personal-information.location + + com.apple.security.personal-information.photos-library + + +