From 0f5a3afe94fb8f7557a5deaf0473a47b19fbb040 Mon Sep 17 00:00:00 2001 From: Ryan Hawkins Date: Tue, 18 Mar 2025 22:27:09 -0600 Subject: [PATCH] Support built-in Zed prompts for all platforms (#26201) This pull request does two things: 1. Adds a setting to force Zed to use the built-in prompts, instead of the system provided ones. I've personally found the system prompts on macOS often fail to respond to keyboard input, are slow to render initially, and don't match Zed's style. 2. Makes the previously Linux-only Zed provided prompts available to everybody using the above setting. Release Notes: - Added support for a built-in prompting system, regardless of platform. Use the new `use_system_prompts` setting to control whether to use the system provided prompts or Zed's built-in system. Note that on Linux, this setting has no effect, as Linux doesn't have a system prompting mechanism. --- Cargo.lock | 15 +++++++- Cargo.toml | 2 + assets/keymaps/default-linux.json | 4 +- assets/keymaps/default-macos.json | 10 +++++ assets/settings/default.json | 5 +++ crates/gpui/src/app.rs | 5 +++ crates/ui_prompt/Cargo.toml | 24 ++++++++++++ crates/ui_prompt/LICENSE-GPL | 1 + .../src/ui_prompt.rs} | 38 ++++++++++++------- crates/workspace/src/workspace_settings.rs | 8 ++++ crates/zed/Cargo.toml | 2 +- crates/zed/src/main.rs | 4 +- crates/zed/src/zed.rs | 2 - 13 files changed, 99 insertions(+), 21 deletions(-) create mode 100644 crates/ui_prompt/Cargo.toml create mode 120000 crates/ui_prompt/LICENSE-GPL rename crates/{zed/src/zed/linux_prompts.rs => ui_prompt/src/ui_prompt.rs} (88%) diff --git a/Cargo.lock b/Cargo.lock index 91c14858c4a80b6d86169e82c30481eb6e60487d..2e8fa86d77edd8599fee0a40442d32c31bb714c5 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -15022,6 +15022,19 @@ dependencies = [ "syn 1.0.109", ] +[[package]] +name = "ui_prompt" +version = "0.1.0" +dependencies = [ + "gpui", + "markdown", + "menu", + "settings", + "theme", + "ui", + "workspace", +] + [[package]] name = "unicase" version = "2.8.1" @@ -17381,7 +17394,6 @@ dependencies = [ "languages", "libc", "log", - "markdown", "markdown_preview", "menu", "migrator", @@ -17433,6 +17445,7 @@ dependencies = [ "tree-sitter-md", "tree-sitter-rust", "ui", + "ui_prompt", "url", "urlencoding", "util", diff --git a/Cargo.toml b/Cargo.toml index 22e26ff796a93a3d7fbf97e7ad5ea7200e9e8284..d803c3cc1b0dce977f60516818ae9b3b5187069a 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -160,6 +160,7 @@ members = [ "crates/ui", "crates/ui_input", "crates/ui_macros", + "crates/ui_prompt", "crates/util", "crates/util_macros", "crates/vim", @@ -362,6 +363,7 @@ toolchain_selector = { path = "crates/toolchain_selector" } ui = { path = "crates/ui" } ui_input = { path = "crates/ui_input" } ui_macros = { path = "crates/ui_macros" } +ui_prompt = { path = "crates/ui_prompt" } util = { path = "crates/util" } util_macros = { path = "crates/util_macros" } vim = { path = "crates/vim" } diff --git a/assets/keymaps/default-linux.json b/assets/keymaps/default-linux.json index de4d371bb409d8f3b45251beb83db8d39ea85235..2d015624134ff18ba5b63aeafbbf5ccc92d1f665 100644 --- a/assets/keymaps/default-linux.json +++ b/assets/keymaps/default-linux.json @@ -53,7 +53,9 @@ "context": "Prompt", "bindings": { "left": "menu::SelectPrevious", - "right": "menu::SelectNext" + "right": "menu::SelectNext", + "h": "menu::SelectPrevious", + "l": "menu::SelectNext" } }, { diff --git a/assets/keymaps/default-macos.json b/assets/keymaps/default-macos.json index 5a4ce720f37411f0e7864f4bdafa3c96775df890..5d956ab591a7ecef3c59c0aef156cbf266cce2f1 100644 --- a/assets/keymaps/default-macos.json +++ b/assets/keymaps/default-macos.json @@ -705,6 +705,16 @@ "ctrl-]": "assistant::CycleNextInlineAssist" } }, + { + "context": "Prompt", + "use_key_equivalents": true, + "bindings": { + "left": "menu::SelectPrevious", + "right": "menu::SelectNext", + "h": "menu::SelectPrevious", + "l": "menu::SelectNext" + } + }, { "context": "ProjectSearchBar && !in_replace", "use_key_equivalents": true, diff --git a/assets/settings/default.json b/assets/settings/default.json index 70d016fb7960d9fe7cbd678a2d1c3bbd54e8adea..0b2d67afa7e11a586f6a03738ca319f9d637bd23 100644 --- a/assets/settings/default.json +++ b/assets/settings/default.json @@ -136,6 +136,11 @@ // Whether to use the system provided dialogs for Open and Save As. // When set to false, Zed will use the built-in keyboard-first pickers. "use_system_path_prompts": true, + // Whether to use the system provided dialogs for prompts, such as confirmation + // prompts. + // When set to false, Zed will use its built-in prompts. Note that on Linux, + // this option is ignored and Zed will always use the built-in prompts. + "use_system_prompts": true, // Whether the cursor blinks in the editor. "cursor_blink": true, // Cursor shape for the default editor. diff --git a/crates/gpui/src/app.rs b/crates/gpui/src/app.rs index 2129daae8432f09a291189c99a6caf9ab815a201..04cb010ed68526aa838597b562f160658160aeb1 100644 --- a/crates/gpui/src/app.rs +++ b/crates/gpui/src/app.rs @@ -1526,6 +1526,11 @@ impl App { self.prompt_builder = Some(PromptBuilder::Custom(Box::new(renderer))) } + /// Reset the prompt builder to the default implementation. + pub fn reset_prompt_builder(&mut self) { + self.prompt_builder = Some(PromptBuilder::Default); + } + /// Remove an asset from GPUI's cache pub fn remove_asset(&mut self, source: &A::Source) { let asset_id = (TypeId::of::(), hash(source)); diff --git a/crates/ui_prompt/Cargo.toml b/crates/ui_prompt/Cargo.toml new file mode 100644 index 0000000000000000000000000000000000000000..55a98288433a7b31507310e20c4209a9d419e45f --- /dev/null +++ b/crates/ui_prompt/Cargo.toml @@ -0,0 +1,24 @@ +[package] +name = "ui_prompt" +version = "0.1.0" +edition.workspace = true +publish.workspace = true +license = "GPL-3.0-or-later" + +[lints] +workspace = true + +[lib] +path = "src/ui_prompt.rs" + +[features] +default = [] + +[dependencies] +gpui.workspace = true +markdown.workspace = true +menu.workspace = true +settings.workspace = true +theme.workspace = true +ui.workspace = true +workspace.workspace = true diff --git a/crates/ui_prompt/LICENSE-GPL b/crates/ui_prompt/LICENSE-GPL new file mode 120000 index 0000000000000000000000000000000000000000..89e542f750cd3860a0598eff0dc34b56d7336dc4 --- /dev/null +++ b/crates/ui_prompt/LICENSE-GPL @@ -0,0 +1 @@ +../../LICENSE-GPL \ No newline at end of file diff --git a/crates/zed/src/zed/linux_prompts.rs b/crates/ui_prompt/src/ui_prompt.rs similarity index 88% rename from crates/zed/src/zed/linux_prompts.rs rename to crates/ui_prompt/src/ui_prompt.rs index 20cd14c4444778d86716c5263505f6711460570e..780a94cff3b13e0000aa9c58faa4fa8ecb5b9a32 100644 --- a/crates/zed/src/zed/linux_prompts.rs +++ b/crates/ui_prompt/src/ui_prompt.rs @@ -4,20 +4,33 @@ use gpui::{ Refineable, Render, RenderablePromptHandle, SharedString, Styled, TextStyleRefinement, Window, }; use markdown::{Markdown, MarkdownStyle}; -use settings::Settings; +use settings::{Settings, SettingsStore}; use theme::ThemeSettings; use ui::{ h_flex, v_flex, ActiveTheme, ButtonCommon, ButtonStyle, Clickable, ElevationIndex, - FluentBuilder, LabelSize, TintColor, + FluentBuilder, LabelSize, StyledExt, TintColor, }; -use workspace::ui::StyledExt; +use workspace::WorkspaceSettings; pub fn init(cx: &mut App) { - cx.set_prompt_builder(fallback_prompt_renderer) + process_settings(cx); + + cx.observe_global::(process_settings) + .detach(); } + +fn process_settings(cx: &mut App) { + let settings = WorkspaceSettings::get_global(cx); + if settings.use_system_prompts && cfg!(not(any(target_os = "linux", target_os = "freebsd"))) { + cx.reset_prompt_builder(); + } else { + cx.set_prompt_builder(zed_prompt_renderer); + } +} + /// Use this function in conjunction with [App::set_prompt_builder] to force -/// GPUI to always use the fallback prompt renderer. -pub fn fallback_prompt_renderer( +/// GPUI to use the internal prompt system. +fn zed_prompt_renderer( level: PromptLevel, message: &str, detail: Option<&str>, @@ -27,7 +40,7 @@ pub fn fallback_prompt_renderer( cx: &mut App, ) -> RenderablePromptHandle { let renderer = cx.new({ - |cx| FallbackPromptRenderer { + |cx| ZedPromptRenderer { _level: level, message: message.to_string(), actions: actions.iter().map(ToString::to_string).collect(), @@ -57,8 +70,7 @@ pub fn fallback_prompt_renderer( handle.with_view(renderer, window, cx) } -/// The default GPUI fallback for rendering prompts, when the platform doesn't support it. -pub struct FallbackPromptRenderer { +pub struct ZedPromptRenderer { _level: PromptLevel, message: String, actions: Vec, @@ -67,7 +79,7 @@ pub struct FallbackPromptRenderer { detail: Option>, } -impl FallbackPromptRenderer { +impl ZedPromptRenderer { fn confirm(&mut self, _: &menu::Confirm, _window: &mut Window, cx: &mut Context) { cx.emit(PromptResponse(self.active_action_id)); } @@ -113,7 +125,7 @@ impl FallbackPromptRenderer { } } -impl Render for FallbackPromptRenderer { +impl Render for ZedPromptRenderer { fn render(&mut self, _window: &mut Window, cx: &mut Context) -> impl IntoElement { let settings = ThemeSettings::get_global(cx); let font_family = settings.ui_font.family.clone(); @@ -181,9 +193,9 @@ impl Render for FallbackPromptRenderer { } } -impl EventEmitter for FallbackPromptRenderer {} +impl EventEmitter for ZedPromptRenderer {} -impl Focusable for FallbackPromptRenderer { +impl Focusable for ZedPromptRenderer { fn focus_handle(&self, _: &crate::App) -> FocusHandle { self.focus.clone() } diff --git a/crates/workspace/src/workspace_settings.rs b/crates/workspace/src/workspace_settings.rs index 3a86667bd87dab682376daea242cb9460af71dc6..8d444ad48fb66572f791fae247eba0bc929d3a23 100644 --- a/crates/workspace/src/workspace_settings.rs +++ b/crates/workspace/src/workspace_settings.rs @@ -19,6 +19,7 @@ pub struct WorkspaceSettings { pub restore_on_startup: RestoreOnStartupBehavior, pub drop_target_size: f32, pub use_system_path_prompts: bool, + pub use_system_prompts: bool, pub command_aliases: HashMap, pub show_user_picture: bool, pub max_tabs: Option, @@ -147,6 +148,13 @@ pub struct WorkspaceSettingsContent { /// /// Default: true pub use_system_path_prompts: Option, + /// Whether to use the system provided prompts. + /// When set to false, Zed will use the built-in prompts. + /// Note that this setting has no effect on Linux, where Zed will always + /// use the built-in prompts. + /// + /// Default: true + pub use_system_prompts: Option, /// Aliases for the command palette. When you type a key in this map, /// it will be assumed to equal the value. /// diff --git a/crates/zed/Cargo.toml b/crates/zed/Cargo.toml index a7d9e2021a2a0824ea3bb52c95018569acd88ec3..2a24131d6996b941047543d1c13595359e8f6174 100644 --- a/crates/zed/Cargo.toml +++ b/crates/zed/Cargo.toml @@ -75,7 +75,6 @@ language_tools.workspace = true languages = { workspace = true, features = ["load-grammars"] } libc.workspace = true log.workspace = true -markdown.workspace = true markdown_preview.workspace = true menu.workspace = true migrator.workspace = true @@ -125,6 +124,7 @@ theme_selector.workspace = true time.workspace = true toolchain_selector.workspace = true ui.workspace = true +ui_prompt.workspace = true url.workspace = true urlencoding.workspace = true util.workspace = true diff --git a/crates/zed/src/main.rs b/crates/zed/src/main.rs index 3080943d7fe39cdf855857618053e0dc48a6de2e..ed2ea1d1bfae7c3da5d93fb718e27027220ed511 100644 --- a/crates/zed/src/main.rs +++ b/crates/zed/src/main.rs @@ -487,9 +487,6 @@ fn main() { load_embedded_fonts(cx); - #[cfg(any(target_os = "linux", target_os = "freebsd"))] - crate::zed::linux_prompts::init(cx); - app_state.languages.set_theme(cx.theme().clone()); editor::init(cx); image_viewer::init(cx); @@ -498,6 +495,7 @@ fn main() { audio::init(Assets, cx); workspace::init(app_state.clone(), cx); + ui_prompt::init(cx); go_to_line::init(cx); file_finder::init(cx); diff --git a/crates/zed/src/zed.rs b/crates/zed/src/zed.rs index 152cc90f7a80b2880527ddab8b7de855ae6e6480..99bfe4992d474518d9da6a7042c01c67b0380965 100644 --- a/crates/zed/src/zed.rs +++ b/crates/zed/src/zed.rs @@ -1,7 +1,5 @@ mod app_menus; pub mod inline_completion_registry; -#[cfg(any(target_os = "linux", target_os = "freebsd"))] -pub(crate) mod linux_prompts; #[cfg(target_os = "macos")] pub(crate) mod mac_only_instance; mod migrate;