Cargo.lock 🔗
@@ -16083,6 +16083,7 @@ dependencies = [
"languages",
"libc",
"log",
+ "markdown",
"markdown_preview",
"menu",
"mimalloc",
tims created
Closes #21305
As Linux doesn’t have native prompts, Zed uses a custom GPU-based
prompt, like the "About Zed" prompt. Currently, the detail in the prompt
isn’t selectable.
This PR fixes that by using the editor's multi-line selectable
functionality to make the detail selectable (and thus copyable). It
achieves this by disabling editing and setting the cursor to
transparent. The editor also does all the heavy lifting, like
double-clicking to select a word or triple-clicking to select a line,
like what user expects from selectable.
Before/After:
<img
src="https://github.com/user-attachments/assets/2012a6cc-a1ed-4efe-8bfb-440a9259f07a"
alt="before" width="360px" />
<img
src="https://github.com/user-attachments/assets/31922ef5-cb2d-4e90-a1a1-00843e767432"
alt="after" width="360px" />
When detail is `None` or empty string:
<img
src="https://github.com/user-attachments/assets/2be5c921-bda1-4db3-85cd-b4b0e2df86d2"
alt="none" width="360px" />
Release Notes:
- N/A
Cargo.lock | 1
crates/zed/Cargo.toml | 1
crates/zed/src/zed/linux_prompts.rs | 43 +++++++++++++++++++++---------
3 files changed, 32 insertions(+), 13 deletions(-)
@@ -16083,6 +16083,7 @@ dependencies = [
"languages",
"libc",
"log",
+ "markdown",
"markdown_preview",
"menu",
"mimalloc",
@@ -69,6 +69,7 @@ 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
mimalloc = { version = "0.1", optional = true }
@@ -1,13 +1,15 @@
use gpui::{
div, AppContext, EventEmitter, FocusHandle, FocusableView, FontWeight, InteractiveElement,
- IntoElement, ParentElement, PromptHandle, PromptLevel, PromptResponse, Render,
- RenderablePromptHandle, Styled, ViewContext, VisualContext, WindowContext,
+ IntoElement, ParentElement, PromptHandle, PromptLevel, PromptResponse, Refineable, Render,
+ RenderablePromptHandle, Styled, TextStyleRefinement, View, ViewContext, VisualContext,
+ WindowContext,
};
+use markdown::{Markdown, MarkdownStyle};
use settings::Settings;
use theme::ThemeSettings;
use ui::{
- h_flex, v_flex, ButtonCommon, ButtonStyle, Clickable, ElevationIndex, FluentBuilder, LabelSize,
- TintColor,
+ h_flex, v_flex, ActiveTheme, ButtonCommon, ButtonStyle, Clickable, ElevationIndex,
+ FluentBuilder, LabelSize, TintColor,
};
use workspace::ui::StyledExt;
@@ -28,10 +30,27 @@ pub fn fallback_prompt_renderer(
|cx| FallbackPromptRenderer {
_level: level,
message: message.to_string(),
- detail: detail.map(ToString::to_string),
actions: actions.iter().map(ToString::to_string).collect(),
focus: cx.focus_handle(),
active_action_id: 0,
+ detail: detail.filter(|text| !text.is_empty()).map(|text| {
+ cx.new_view(|cx| {
+ let settings = ThemeSettings::get_global(cx);
+ let mut base_text_style = cx.text_style();
+ base_text_style.refine(&TextStyleRefinement {
+ font_family: Some(settings.ui_font.family.clone()),
+ font_size: Some(settings.ui_font_size.into()),
+ color: Some(ui::Color::Muted.color(cx)),
+ ..Default::default()
+ });
+ let markdown_style = MarkdownStyle {
+ base_text_style,
+ selection_background_color: { cx.theme().players().local().selection },
+ ..Default::default()
+ };
+ Markdown::new(text.to_string(), markdown_style, None, None, cx)
+ })
+ }),
}
});
@@ -42,10 +61,10 @@ pub fn fallback_prompt_renderer(
pub struct FallbackPromptRenderer {
_level: PromptLevel,
message: String,
- detail: Option<String>,
actions: Vec<String>,
focus: FocusHandle,
active_action_id: usize,
+ detail: Option<View<Markdown>>,
}
impl FallbackPromptRenderer {
@@ -111,13 +130,11 @@ impl Render for FallbackPromptRenderer {
.child(self.message.clone())
.text_color(ui::Color::Default.color(cx)),
)
- .children(self.detail.clone().map(|detail| {
- div()
- .w_full()
- .text_xs()
- .text_color(ui::Color::Muted.color(cx))
- .child(detail)
- }))
+ .children(
+ self.detail
+ .clone()
+ .map(|detail| div().w_full().text_xs().child(detail)),
+ )
.child(h_flex().justify_end().gap_2().children(
self.actions.iter().enumerate().rev().map(|(ix, action)| {
ui::Button::new(ix, action.clone())