From 66f3b326b750c5e906642aaa970745568a51dd45 Mon Sep 17 00:00:00 2001 From: claire <28279548+claiwe@users.noreply.github.com> Date: Fri, 20 Mar 2026 13:12:02 -0500 Subject: [PATCH] Allow the keymap and settings UI to be opened without an active window (#49527) Closes #49155. image Release Notes: - UI: Allow the keymap and settings UI to be opened without an active window --------- Co-authored-by: MrSubidubi Co-authored-by: Finn Evers --- crates/keymap_editor/src/keymap_editor.rs | 18 +++-- crates/settings_ui/src/settings_ui.rs | 93 +++++++++++------------ 2 files changed, 54 insertions(+), 57 deletions(-) diff --git a/crates/keymap_editor/src/keymap_editor.rs b/crates/keymap_editor/src/keymap_editor.rs index 2a66f9e9182c99a8e0f077617e75a863c1af9208..1f331811fefcf0b1fbb4e63305d4138d39931a76 100644 --- a/crates/keymap_editor/src/keymap_editor.rs +++ b/crates/keymap_editor/src/keymap_editor.rs @@ -39,7 +39,7 @@ use ui_input::InputField; use util::ResultExt; use workspace::{ Item, ModalView, SerializableItem, Workspace, notifications::NotifyTaskExt as _, - register_serializable_item, + register_serializable_item, with_active_or_new_workspace, }; pub use ui_components::*; @@ -128,14 +128,16 @@ pub fn init(cx: &mut App) { } } + cx.on_action(|_: &OpenKeymap, cx| { + with_active_or_new_workspace(cx, |workspace, window, cx| { + open_keymap_editor(None, workspace, window, cx); + }); + }); + cx.observe_new(|workspace: &mut Workspace, _window, _cx| { - workspace - .register_action(|workspace, _: &OpenKeymap, window, cx| { - open_keymap_editor(None, workspace, window, cx); - }) - .register_action(|workspace, action: &ChangeKeybinding, window, cx| { - open_keymap_editor(Some(action.action.clone()), workspace, window, cx); - }); + workspace.register_action(|workspace, action: &ChangeKeybinding, window, cx| { + open_keymap_editor(Some(action.action.clone()), workspace, window, cx); + }); }) .detach(); diff --git a/crates/settings_ui/src/settings_ui.rs b/crates/settings_ui/src/settings_ui.rs index 1bae8544b1df47786bb3b199319031888432a35f..95a8c215fb593fe3a5d64a11f0d2b14a183dc60c 100644 --- a/crates/settings_ui/src/settings_ui.rs +++ b/crates/settings_ui/src/settings_ui.rs @@ -392,29 +392,22 @@ pub fn init(cx: &mut App) { let queue = ProjectSettingsUpdateQueue::new(cx); cx.set_global(queue); + cx.on_action(|_: &OpenSettings, cx| { + open_settings_editor(None, None, None, cx); + }); + cx.observe_new(|workspace: &mut workspace::Workspace, _, _| { 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), None, 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, None, None, window_handle, cx); + .register_action(|_, OpenSettingsAt { path }: &OpenSettingsAt, window, cx| { + let window_handle = window.window_handle().downcast::(); + open_settings_editor(Some(&path), None, window_handle, cx); + }) + .register_action(|_, _: &OpenSettings, window, cx| { + let window_handle = window.window_handle().downcast::(); + open_settings_editor(None, None, window_handle, cx); }) .register_action(|workspace, _: &OpenProjectSettings, window, cx| { - let window_handle = window - .window_handle() - .downcast::() - .expect("Workspaces are root Windows"); + let window_handle = window.window_handle().downcast::(); let target_worktree_id = workspace .project() .read(cx) @@ -425,7 +418,7 @@ pub fn init(cx: &mut App) { .is_dir() .then_some(tree.read(cx).id()) }); - open_settings_editor(workspace, None, target_worktree_id, window_handle, cx); + open_settings_editor(None, target_worktree_id, window_handle, cx); }); }) .detach(); @@ -564,10 +557,9 @@ fn init_renderers(cx: &mut App) { } pub fn open_settings_editor( - _workspace: &mut Workspace, path: Option<&str>, target_worktree_id: Option, - workspace_handle: WindowHandle, + workspace_handle: Option>, cx: &mut App, ) { telemetry::event!("Settings Viewed"); @@ -624,7 +616,8 @@ pub fn open_settings_editor( if let Some(existing_window) = existing_window { existing_window .update(cx, |settings_window, window, cx| { - settings_window.original_window = Some(workspace_handle); + settings_window.original_window = workspace_handle; + window.activate_window(); if let Some(path) = path { open_path(path, settings_window, window, cx); @@ -685,7 +678,7 @@ pub fn open_settings_editor( }, |window, cx| { let settings_window = - cx.new(|cx| SettingsWindow::new(Some(workspace_handle), window, cx)); + cx.new(|cx| SettingsWindow::new(workspace_handle, window, cx)); settings_window.update(cx, |settings_window, cx| { if let Some(path) = path { open_path(&path, settings_window, window, cx); @@ -2191,37 +2184,39 @@ impl SettingsWindow { ui_files.reverse(); - let mut missing_worktrees = Vec::new(); + if self.original_window.is_some() { + let mut missing_worktrees = Vec::new(); - for worktree in all_projects(self.original_window.as_ref(), 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); - let worktree_id = worktree.id(); - let Some(directory_name) = worktree.root_dir().and_then(|file| { - file.file_name() - .map(|os_string| os_string.to_string_lossy().to_string()) - }) else { - continue; - }; + for worktree in all_projects(self.original_window.as_ref(), 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); + let worktree_id = worktree.id(); + let Some(directory_name) = worktree.root_dir().and_then(|file| { + file.file_name() + .map(|os_string| os_string.to_string_lossy().to_string()) + }) else { + continue; + }; - missing_worktrees.push((worktree_id, directory_name.clone())); - let path = RelPath::empty().to_owned().into_arc(); + missing_worktrees.push((worktree_id, directory_name.clone())); + let path = RelPath::empty().to_owned().into_arc(); - let settings_ui_file = SettingsUiFile::Project((worktree_id, path)); + let settings_ui_file = SettingsUiFile::Project((worktree_id, path)); - let focus_handle = prev_files - .iter() - .find_map(|(prev_file, handle)| { - (prev_file == &settings_ui_file).then(|| handle.clone()) - }) - .unwrap_or_else(|| cx.focus_handle().tab_index(0).tab_stop(true)); + let focus_handle = prev_files + .iter() + .find_map(|(prev_file, handle)| { + (prev_file == &settings_ui_file).then(|| handle.clone()) + }) + .unwrap_or_else(|| cx.focus_handle().tab_index(0).tab_stop(true)); - ui_files.push((settings_ui_file, focus_handle)); - } + ui_files.push((settings_ui_file, focus_handle)); + } - self.worktree_root_dirs.extend(missing_worktrees); + self.worktree_root_dirs.extend(missing_worktrees); + } self.files = ui_files; let current_file_still_exists = self