diff --git a/crates/settings_ui/src/settings_ui.rs b/crates/settings_ui/src/settings_ui.rs index 6a561086f2d614eb8fc06c5be146b5e02dc05b3d..3911a4e0cd3023524df9e023cfdc670fc7c24a8a 100644 --- a/crates/settings_ui/src/settings_ui.rs +++ b/crates/settings_ui/src/settings_ui.rs @@ -15,7 +15,7 @@ use project::{Project, WorktreeId}; use release_channel::ReleaseChannel; use schemars::JsonSchema; use serde::Deserialize; -use settings::{Settings, SettingsContent, SettingsStore}; +use settings::{Settings, SettingsContent, SettingsStore, initial_project_settings_content}; use std::{ any::{Any, TypeId, type_name}, cell::RefCell, @@ -35,7 +35,7 @@ use ui::{ use ui_input::{NumberField, NumberFieldType}; use util::{ResultExt as _, paths::PathStyle, rel_path::RelPath}; use workspace::{AppState, OpenOptions, OpenVisible, Workspace, client_side_decorations}; -use zed_actions::{OpenSettings, OpenSettingsAt}; +use zed_actions::{OpenProjectSettings, OpenSettings, OpenSettingsAt}; use crate::components::{ EnumVariantDropdown, SettingsInputField, font_picker, icon_theme_picker, theme_picker, @@ -379,26 +379,30 @@ pub fn init(cx: &mut App) { init_renderers(cx); cx.observe_new(|workspace: &mut workspace::Workspace, _, _| { - workspace.register_action( - |workspace, OpenSettingsAt { path }: &OpenSettingsAt, window, cx| { + workspace + .register_action( + |workspace, OpenSettingsAt { path }: &OpenSettingsAt, window, cx| { + let window_handle = window + .window_handle() + .downcast::() + .expect("Workspaces are root Windows"); + open_settings_editor(workspace, Some(&path), false, window_handle, cx); + }, + ) + .register_action(|workspace, _: &OpenSettings, window, cx| { let window_handle = window .window_handle() .downcast::() .expect("Workspaces are root Windows"); - open_settings_editor(workspace, Some(&path), window_handle, cx); - }, - ); - }) - .detach(); - - cx.observe_new(|workspace: &mut workspace::Workspace, _, _| { - workspace.register_action(|workspace, _: &OpenSettings, window, cx| { - let window_handle = window - .window_handle() - .downcast::() - .expect("Workspaces are root Windows"); - open_settings_editor(workspace, None, window_handle, cx); - }); + open_settings_editor(workspace, None, false, window_handle, cx); + }) + .register_action(|workspace, _: &OpenProjectSettings, window, cx| { + let window_handle = window + .window_handle() + .downcast::() + .expect("Workspaces are root Windows"); + open_settings_editor(workspace, None, true, window_handle, cx); + }); }) .detach(); } @@ -506,6 +510,7 @@ fn init_renderers(cx: &mut App) { pub fn open_settings_editor( _workspace: &mut Workspace, path: Option<&str>, + open_project_settings: bool, workspace_handle: WindowHandle, cx: &mut App, ) { @@ -514,6 +519,8 @@ pub fn open_settings_editor( /// Assumes a settings GUI window is already open fn open_path( path: &str, + // Note: This option is unsupported right now + _open_project_settings: bool, settings_window: &mut SettingsWindow, window: &mut Window, cx: &mut Context, @@ -540,7 +547,17 @@ pub fn open_settings_editor( settings_window.original_window = Some(workspace_handle); window.activate_window(); if let Some(path) = path { - open_path(path, settings_window, window, cx); + open_path(path, open_project_settings, settings_window, window, cx); + } else if open_project_settings { + if let Some(file_index) = settings_window + .files + .iter() + .position(|(file, _)| file.worktree_id().is_some()) + { + settings_window.change_file(file_index, window, cx); + } + + cx.notify(); } }) .ok(); @@ -588,7 +605,17 @@ pub fn open_settings_editor( cx.new(|cx| SettingsWindow::new(Some(workspace_handle), window, cx)); settings_window.update(cx, |settings_window, cx| { if let Some(path) = path { - open_path(&path, settings_window, window, cx); + open_path(&path, open_project_settings, settings_window, window, cx); + } else if open_project_settings { + if let Some(file_index) = settings_window + .files + .iter() + .position(|(file, _)| file.worktree_id().is_some()) + { + settings_window.change_file(file_index, window, cx); + } + + settings_window.fetch_files(window, cx); } }); @@ -1159,7 +1186,7 @@ fn all_language_names(cx: &App) -> Vec { } #[allow(unused)] -#[derive(Clone, PartialEq)] +#[derive(Clone, PartialEq, Debug)] enum SettingsUiFile { User, // Uses all settings. Project((WorktreeId, Arc)), // Has a special name, and special set of settings @@ -1283,15 +1310,34 @@ impl SettingsWindow { }) .collect::>() { + cx.observe_release_in(&project, window, |this, _, window, cx| { + this.fetch_files(window, cx) + }) + .detach(); cx.subscribe_in(&project, window, Self::handle_project_event) .detach(); } + + for workspace in app_state + .workspace_store + .read(cx) + .workspaces() + .iter() + .filter_map(|space| space.entity(cx).ok()) + { + cx.observe_release_in(&workspace, window, |this, _, window, cx| { + this.fetch_files(window, cx) + }) + .detach(); + } } else { log::error!("App state doesn't exist when creating a new settings window"); } let this_weak = cx.weak_entity(); cx.observe_new::({ + let this_weak = this_weak.clone(); + move |_, window, cx| { let project = cx.entity(); let Some(window) = window else { @@ -1299,7 +1345,13 @@ impl SettingsWindow { }; this_weak - .update(cx, |_, cx| { + .update(cx, |this, cx| { + this.fetch_files(window, cx); + cx.observe_release_in(&project, window, |_, _, window, cx| { + cx.defer_in(window, |this, window, cx| this.fetch_files(window, cx)); + }) + .detach(); + cx.subscribe_in(&project, window, Self::handle_project_event) .detach(); }) @@ -1308,6 +1360,24 @@ impl SettingsWindow { }) .detach(); + cx.observe_new::(move |_, window, cx| { + let workspace = cx.entity(); + let Some(window) = window else { + return; + }; + + this_weak + .update(cx, |this, cx| { + this.fetch_files(window, cx); + cx.observe_release_in(&workspace, window, |this, _, window, cx| { + this.fetch_files(window, cx) + }) + .detach(); + }) + .ok(); + }) + .detach(); + let title_bar = if !cfg!(target_os = "macos") { Some(cx.new(|cx| PlatformTitleBar::new("settings-title-bar", cx))) } else { @@ -1818,6 +1888,7 @@ impl SettingsWindow { cx.notify(); } + #[track_caller] fn fetch_files(&mut self, window: &mut Window, cx: &mut Context) { self.worktree_root_dirs.clear(); let prev_files = self.files.clone(); @@ -1870,7 +1941,7 @@ impl SettingsWindow { let mut missing_worktrees = Vec::new(); for worktree in all_projects(cx) - .flat_map(|project| project.read(cx).worktrees(cx)) + .flat_map(|project| project.read(cx).visible_worktrees(cx)) .filter(|tree| !self.worktree_root_dirs.contains_key(&tree.read(cx).id())) { let worktree = worktree.read(cx); @@ -3028,7 +3099,7 @@ impl SettingsWindow { tree.create_entry( settings_path.clone(), false, - Some("{\n\n}".as_bytes().to_vec()), + Some(initial_project_settings_content().as_bytes().to_vec()), cx, ) })) diff --git a/crates/zed/src/zed.rs b/crates/zed/src/zed.rs index 49f1206caeaaba2d54f5084de025ba7bb70f310d..617534ee0f8a68f91e8e55d58d0d9550d265c6b2 100644 --- a/crates/zed/src/zed.rs +++ b/crates/zed/src/zed.rs @@ -107,8 +107,8 @@ actions!( Minimize, /// Opens the default settings file. OpenDefaultSettings, - /// Opens project-specific settings. - OpenProjectSettings, + /// Opens project-specific settings file. + OpenProjectSettingsFile, /// Opens the project tasks configuration. OpenProjectTasks, /// Opens the tasks panel. @@ -1783,7 +1783,7 @@ pub fn open_new_ssh_project_from_project( fn open_project_settings_file( workspace: &mut Workspace, - _: &OpenProjectSettings, + _: &OpenProjectSettingsFile, window: &mut Window, cx: &mut Context, ) { @@ -5067,7 +5067,7 @@ mod tests { .update(cx, |workspace, window, cx| { // Call the exact function that contains the bug eprintln!("About to call open_project_settings_file"); - open_project_settings_file(workspace, &OpenProjectSettings, window, cx); + open_project_settings_file(workspace, &OpenProjectSettingsFile, window, cx); }) .unwrap(); diff --git a/crates/zed/src/zed/app_menus.rs b/crates/zed/src/zed/app_menus.rs index b86889f60acb5f738c93012335ef27b091edc0e2..20a4f8be3b25991b4b22e4fcabd6008c7e502b65 100644 --- a/crates/zed/src/zed/app_menus.rs +++ b/crates/zed/src/zed/app_menus.rs @@ -69,7 +69,11 @@ pub fn app_menus(cx: &mut App) -> Vec { items: vec![ MenuItem::action("Open Settings", zed_actions::OpenSettings), MenuItem::action("Open Settings File", super::OpenSettingsFile), - MenuItem::action("Open Project Settings", super::OpenProjectSettings), + MenuItem::action("Open Project Settings", zed_actions::OpenProjectSettings), + MenuItem::action( + "Open Project Settings File", + super::OpenProjectSettingsFile, + ), MenuItem::action("Open Default Settings", super::OpenDefaultSettings), MenuItem::separator(), MenuItem::action("Open Keymap", zed_actions::OpenKeymap), diff --git a/crates/zed_actions/src/lib.rs b/crates/zed_actions/src/lib.rs index f00b2a7bfd3371359659f310a37ee36ef75b04f5..b9fde1f34402c56becd811a76a1d33da93413c50 100644 --- a/crates/zed_actions/src/lib.rs +++ b/crates/zed_actions/src/lib.rs @@ -43,6 +43,9 @@ actions!( /// Opens the settings JSON file. #[action(deprecated_aliases = ["zed_actions::OpenSettings"])] OpenSettingsFile, + /// Opens project-specific settings. + #[action(deprecated_aliases = ["zed_actions::OpenProjectSettings"])] + OpenProjectSettings, /// Opens the default keymap file. OpenDefaultKeymap, /// Opens the user keymap file.