settings_ui: Make open project settings action open settings UI (#42669)
This PR makes the `OpenProjectSettings` action open the settings UI in project settings mode for the first visible worktree, instead of opening the file. It also adds a `OpenProjectSettingsFile` action that maintains the old behavior. Finally, this PR partially fixes a bug where the settings UI won't load project settings when the settings window is loaded before opening a project/workspace. This happens because the global `app_state` isn't correct in the `Subscription` that refreshes the available setting files to open. The bug is still present in some cases, but it's out of scope for this PR. Release Notes: - settings ui: Project Settings action now opens settings UI instead of a file
This commit is contained in:
@@ -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::<Workspace>()
|
||||
.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::<Workspace>()
|
||||
.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::<Workspace>()
|
||||
.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::<Workspace>()
|
||||
.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<Workspace>,
|
||||
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<SettingsWindow>,
|
||||
@@ -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<SharedString> {
|
||||
}
|
||||
|
||||
#[allow(unused)]
|
||||
#[derive(Clone, PartialEq)]
|
||||
#[derive(Clone, PartialEq, Debug)]
|
||||
enum SettingsUiFile {
|
||||
User, // Uses all settings.
|
||||
Project((WorktreeId, Arc<RelPath>)), // Has a special name, and special set of settings
|
||||
@@ -1283,15 +1310,34 @@ impl SettingsWindow {
|
||||
})
|
||||
.collect::<Vec<_>>()
|
||||
{
|
||||
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::<Project>({
|
||||
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::<Workspace>(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<SettingsWindow>) {
|
||||
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,
|
||||
)
|
||||
}))
|
||||
|
||||
@@ -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<Workspace>,
|
||||
) {
|
||||
@@ -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();
|
||||
|
||||
|
||||
@@ -69,7 +69,11 @@ pub fn app_menus(cx: &mut App) -> Vec<Menu> {
|
||||
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),
|
||||
|
||||
@@ -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.
|
||||
|
||||
Reference in New Issue
Block a user