Introduce `LspPostProcessor::download_language_server`

Antonio Scandurra created

Change summary

crates/language/src/language.rs | 32 ++++++++++++++++++++++++--------
crates/zed/src/language.rs      |  7 +++++++
2 files changed, 31 insertions(+), 8 deletions(-)

Detailed changes

crates/language/src/language.rs 🔗

@@ -8,12 +8,20 @@ mod tests;
 
 use anyhow::{anyhow, Result};
 use collections::HashSet;
+use futures::future::BoxFuture;
 use gpui::{AppContext, Task};
 use highlight_map::HighlightMap;
 use lazy_static::lazy_static;
 use parking_lot::Mutex;
 use serde::Deserialize;
-use std::{cell::RefCell, ops::Range, path::Path, str, sync::Arc};
+use std::{
+    cell::RefCell,
+    future::Future,
+    ops::Range,
+    path::{Path, PathBuf},
+    str,
+    sync::Arc,
+};
 use theme::SyntaxTheme;
 use tree_sitter::{self, Query};
 
@@ -48,6 +56,7 @@ pub trait ToLspPosition {
 }
 
 pub trait LspPostProcessor: 'static + Send + Sync {
+    fn download_language_server(&self) -> BoxFuture<'static, Result<PathBuf>>;
     fn process_diagnostics(&self, diagnostics: &mut lsp::PublishDiagnosticsParams);
     fn label_for_completion(
         &self,
@@ -259,13 +268,14 @@ impl Language {
             }
 
             let background = cx.background().clone();
-            let server = lsp::LanguageServer::new(
-                Path::new(&config.binary),
-                &root_path,
-                cx.background().clone(),
-            )
-            .map(Some);
-            cx.background().spawn(async move { server })
+            let server_binary_path = self
+                .download_language_server()
+                .ok_or_else(|| anyhow!("cannot download language server"));
+            cx.background().spawn(async move {
+                let server_binary_path = server_binary_path?.await?;
+                let server = lsp::LanguageServer::new(&server_binary_path, &root_path, background)?;
+                Ok(Some(server))
+            })
         } else {
             Task::ready(Ok(None))
         }
@@ -321,6 +331,12 @@ impl Language {
         result
     }
 
+    fn download_language_server(&self) -> Option<impl Future<Output = Result<PathBuf>>> {
+        self.lsp_post_processor
+            .as_ref()
+            .map(|processor| processor.download_language_server())
+    }
+
     pub fn brackets(&self) -> &[BracketPair] {
         &self.config.brackets
     }

crates/zed/src/language.rs 🔗

@@ -1,8 +1,11 @@
+use anyhow::Result;
+use futures::future::BoxFuture;
 pub use language::*;
 use lazy_static::lazy_static;
 use regex::Regex;
 use rust_embed::RustEmbed;
 use std::borrow::Cow;
+use std::path::PathBuf;
 use std::{str, sync::Arc};
 
 #[derive(RustEmbed)]
@@ -12,6 +15,10 @@ struct LanguageDir;
 struct RustPostProcessor;
 
 impl LspPostProcessor for RustPostProcessor {
+    fn download_language_server(&self) -> BoxFuture<'static, Result<PathBuf>> {
+        todo!()
+    }
+
     fn process_diagnostics(&self, params: &mut lsp::PublishDiagnosticsParams) {
         lazy_static! {
             static ref REGEX: Regex = Regex::new("(?m)`([^`]+)\n`$").unwrap();