Make linux prompts a bit better (#13067)

Also prompt with a sensible error on install:cli

Release Notes:

- N/A
This commit is contained in:
Conrad Irwin 2024-06-14 16:40:54 -06:00 committed by GitHub
parent 2f6cb49d84
commit fab4b01655
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
5 changed files with 138 additions and 0 deletions

1
Cargo.lock generated
View File

@ -13338,6 +13338,7 @@ dependencies = [
"theme_selector",
"tree-sitter-markdown",
"tree-sitter-rust",
"ui",
"urlencoding",
"util",
"uuid",

View File

@ -94,6 +94,7 @@ terminal_view.workspace = true
theme.workspace = true
theme_selector.workspace = true
urlencoding = "2.1.2"
ui.workspace = true
util.workspace = true
uuid.workspace = true
vim.workspace = true

View File

@ -168,6 +168,9 @@ fn init_ui(app_state: Arc<AppState>, cx: &mut AppContext) -> Result<()> {
SystemAppearance::init(cx);
load_embedded_fonts(cx);
#[cfg(target_os = "linux")]
crate::zed::linux_prompts::init(cx);
theme::init(theme::LoadThemes::All(Box::new(Assets)), cx);
app_state.languages.set_theme(cx.theme().clone());
command_palette::init(cx);

View File

@ -1,5 +1,7 @@
mod app_menus;
pub mod inline_completion_registry;
#[cfg(target_os = "linux")]
pub(crate) mod linux_prompts;
#[cfg(not(target_os = "linux"))]
pub(crate) mod only_instance;
mod open_listener;
@ -262,9 +264,20 @@ pub fn initialize_workspace(app_state: Arc<AppState>, cx: &mut AppContext) {
.register_action(move |_, _: &ResetBufferFontSize, cx| theme::reset_font_size(cx))
.register_action(|_, _: &install_cli::Install, cx| {
cx.spawn(|workspace, mut cx| async move {
if cfg!(target_os = "linux") {
let prompt = cx.prompt(
PromptLevel::Warning,
"Could not install the CLI",
Some("If you installed Zed from our official release add ~/.local/bin to your PATH.\n\nIf you installed Zed from a different source you may need to create an alias/symlink manually."),
&["Ok"],
);
cx.background_executor().spawn(prompt).detach();
return Ok(());
}
let path = install_cli::install_cli(cx.deref())
.await
.context("error creating CLI symlink")?;
workspace.update(&mut cx, |workspace, cx| {
struct InstalledZedCli;

View File

@ -0,0 +1,120 @@
use gpui::{
div, opaque_grey, AppContext, EventEmitter, FocusHandle, FocusableView, FontWeight,
InteractiveElement, IntoElement, ParentElement, PromptHandle, PromptLevel, PromptResponse,
Render, RenderablePromptHandle, Styled, ViewContext, VisualContext, WindowContext,
};
use ui::{h_flex, v_flex, ButtonCommon, ButtonStyle, Clickable, ElevationIndex, LabelSize};
use workspace::ui::StyledExt;
pub fn init(cx: &mut AppContext) {
cx.set_prompt_builder(fallback_prompt_renderer)
}
/// Use this function in conjunction with [AppContext::set_prompt_renderer] to force
/// GPUI to always use the fallback prompt renderer.
pub fn fallback_prompt_renderer(
level: PromptLevel,
message: &str,
detail: Option<&str>,
actions: &[&str],
handle: PromptHandle,
cx: &mut WindowContext,
) -> RenderablePromptHandle {
let renderer = cx.new_view({
|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(),
}
});
handle.with_view(renderer, cx)
}
/// The default GPUI fallback for rendering prompts, when the platform doesn't support it.
pub struct FallbackPromptRenderer {
_level: PromptLevel,
message: String,
detail: Option<String>,
actions: Vec<String>,
focus: FocusHandle,
}
impl Render for FallbackPromptRenderer {
fn render(&mut self, cx: &mut ViewContext<Self>) -> impl IntoElement {
let prompt =
v_flex()
.cursor_default()
.track_focus(&self.focus)
.elevation_3(cx)
.w_72()
.overflow_hidden()
.p_4()
.gap_4()
.font_family("Zed Sans")
.child(
div()
.w_full()
.font_weight(FontWeight::BOLD)
.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)
}))
.child(h_flex().justify_end().gap_2().children(
self.actions.iter().enumerate().map(|(ix, action)| {
ui::Button::new(ix, action.clone())
.label_size(LabelSize::Large)
.style(ButtonStyle::Filled)
.layer(ElevationIndex::ModalSurface)
.on_click(cx.listener(move |_, _, cx| {
cx.emit(PromptResponse(ix));
}))
}),
));
div()
.size_full()
.occlude()
.child(
div()
.size_full()
.bg(opaque_grey(0.5, 0.6))
.absolute()
.top_0()
.left_0(),
)
.child(
div()
.size_full()
.absolute()
.top_0()
.left_0()
.flex()
.flex_col()
.justify_around()
.child(
div()
.w_full()
.flex()
.flex_row()
.justify_around()
.child(prompt),
),
)
}
}
impl EventEmitter<PromptResponse> for FallbackPromptRenderer {}
impl FocusableView for FallbackPromptRenderer {
fn focus_handle(&self, _: &crate::AppContext) -> FocusHandle {
self.focus.clone()
}
}