diff --git a/Cargo.lock b/Cargo.lock index 91c14858c4..2e8fa86d77 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 22e26ff796..d803c3cc1b 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 de4d371bb4..2d01562413 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 5a4ce720f3..5d956ab591 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 70d016fb79..0b2d67afa7 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 2129daae84..04cb010ed6 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 0000000000..55a9828843 --- /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 0000000000..89e542f750 --- /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 20cd14c444..780a94cff3 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 3a86667bd8..8d444ad48f 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 a7d9e2021a..2a24131d69 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 3080943d7f..ed2ea1d1bf 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 152cc90f7a..99bfe4992d 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;