Cargo.lock 🔗
@@ -13338,6 +13338,7 @@ dependencies = [
"theme_selector",
"tree-sitter-markdown",
"tree-sitter-rust",
+ "ui",
"urlencoding",
"util",
"uuid",
Conrad Irwin created
Also prompt with a sensible error on install:cli
Release Notes:
- N/A
Cargo.lock | 1
crates/zed/Cargo.toml | 1
crates/zed/src/main.rs | 3
crates/zed/src/zed.rs | 13 +++
crates/zed/src/zed/linux_prompts.rs | 120 +++++++++++++++++++++++++++++++
5 files changed, 138 insertions(+)
@@ -13338,6 +13338,7 @@ dependencies = [
"theme_selector",
"tree-sitter-markdown",
"tree-sitter-rust",
+ "ui",
"urlencoding",
"util",
"uuid",
@@ -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
@@ -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);
@@ -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;
@@ -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()
+ }
+}