Show a notification that gopls can't be installed without go

Max Brunsfeld created

Change summary

crates/language/src/language.rs   | 22 +++++++++++++++++++++-
crates/project/src/project.rs     |  7 +++----
crates/workspace/src/workspace.rs |  4 ++++
crates/zed/src/languages/go.rs    | 19 +++++++++++++++++++
4 files changed, 47 insertions(+), 5 deletions(-)

Detailed changes

crates/language/src/language.rs 🔗

@@ -130,6 +130,14 @@ impl CachedLspAdapter {
         self.adapter.fetch_latest_server_version(delegate).await
     }
 
+    pub fn will_fetch_server_binary(
+        &self,
+        delegate: &Arc<dyn LspAdapterDelegate>,
+        cx: &mut AsyncAppContext,
+    ) -> Option<Task<Result<()>>> {
+        self.adapter.will_fetch_server_binary(delegate, cx)
+    }
+
     pub async fn fetch_server_binary(
         &self,
         version: Box<dyn 'static + Send + Any>,
@@ -204,6 +212,14 @@ pub trait LspAdapter: 'static + Send + Sync {
         delegate: &dyn LspAdapterDelegate,
     ) -> Result<Box<dyn 'static + Send + Any>>;
 
+    fn will_fetch_server_binary(
+        &self,
+        _: &Arc<dyn LspAdapterDelegate>,
+        _: &mut AsyncAppContext,
+    ) -> Option<Task<Result<()>>> {
+        None
+    }
+
     async fn fetch_server_binary(
         &self,
         version: Box<dyn 'static + Send + Any>,
@@ -971,7 +987,7 @@ async fn get_binary(
     delegate: Arc<dyn LspAdapterDelegate>,
     download_dir: Arc<Path>,
     statuses: async_broadcast::Sender<(Arc<Language>, LanguageServerBinaryStatus)>,
-    _cx: AsyncAppContext,
+    mut cx: AsyncAppContext,
 ) -> Result<LanguageServerBinary> {
     let container_dir = download_dir.join(adapter.name.0.as_ref());
     if !container_dir.exists() {
@@ -980,6 +996,10 @@ async fn get_binary(
             .context("failed to create container directory")?;
     }
 
+    if let Some(task) = adapter.will_fetch_server_binary(&delegate, &mut cx) {
+        task.await?;
+    }
+
     let binary = fetch_latest_binary(
         adapter.clone(),
         language.clone(),

crates/project/src/project.rs 🔗

@@ -252,7 +252,7 @@ pub enum Event {
     LanguageServerAdded(LanguageServerId),
     LanguageServerRemoved(LanguageServerId),
     LanguageServerLog(LanguageServerId, String),
-    LanguageServerNotification(String),
+    Notification(String),
     ActiveEntryChanged(Option<ProjectEntryId>),
     WorktreeAdded,
     WorktreeRemoved(WorktreeId),
@@ -7205,9 +7205,8 @@ impl ProjectLspAdapterDelegate {
 
 impl LspAdapterDelegate for ProjectLspAdapterDelegate {
     fn show_notification(&self, message: &str, cx: &mut AppContext) {
-        self.project.update(cx, |_, cx| {
-            cx.emit(Event::LanguageServerNotification(message.to_owned()))
-        });
+        self.project
+            .update(cx, |_, cx| cx.emit(Event::Notification(message.to_owned())));
     }
 
     fn http_client(&self) -> Arc<dyn HttpClient> {

crates/workspace/src/workspace.rs 🔗

@@ -553,6 +553,10 @@ impl Workspace {
                     }
                 }
 
+                project::Event::Notification(message) => this.show_notification(0, cx, |cx| {
+                    cx.add_view(|_| MessageNotification::new(message.clone()))
+                }),
+
                 _ => {}
             }
             cx.notify()

crates/zed/src/languages/go.rs 🔗

@@ -1,6 +1,7 @@
 use anyhow::{anyhow, Result};
 use async_trait::async_trait;
 use futures::StreamExt;
+use gpui::{AsyncAppContext, Task};
 pub use language::*;
 use lazy_static::lazy_static;
 use regex::Regex;
@@ -47,6 +48,24 @@ impl super::LspAdapter for GoLspAdapter {
         Ok(Box::new(version) as Box<_>)
     }
 
+    fn will_fetch_server_binary(
+        &self,
+        delegate: &Arc<dyn LspAdapterDelegate>,
+        cx: &mut AsyncAppContext,
+    ) -> Option<Task<Result<()>>> {
+        let delegate = delegate.clone();
+        Some(cx.spawn(|mut cx| async move {
+            let install_output = process::Command::new("go").args(["version"]).output().await;
+            if install_output.is_err() {
+                cx.update(|cx| {
+                    delegate
+                        .show_notification("go is not installed. gopls will not be available.", cx);
+                })
+            }
+            Ok(())
+        }))
+    }
+
     async fn fetch_server_binary(
         &self,
         version: Box<dyn 'static + Send + Any>,