Detailed changes
@@ -17,7 +17,7 @@ use futures::{
future::{BoxFuture, Shared},
FutureExt, TryFutureExt as _,
};
-use gpui::{executor::Background, AppContext, Task};
+use gpui::{executor::Background, AppContext, AsyncAppContext, Task};
use highlight_map::HighlightMap;
use lazy_static::lazy_static;
use lsp::CodeActionKind;
@@ -125,27 +125,46 @@ impl CachedLspAdapter {
pub async fn fetch_latest_server_version(
&self,
- http: Arc<dyn HttpClient>,
+ delegate: &dyn LspAdapterDelegate,
) -> Result<Box<dyn 'static + Send + Any>> {
- self.adapter.fetch_latest_server_version(http).await
+ self.adapter.fetch_latest_server_version(delegate).await
+ }
+
+ pub fn will_fetch_server(
+ &self,
+ delegate: &Arc<dyn LspAdapterDelegate>,
+ cx: &mut AsyncAppContext,
+ ) -> Option<Task<Result<()>>> {
+ self.adapter.will_fetch_server(delegate, cx)
+ }
+
+ pub fn will_start_server(
+ &self,
+ delegate: &Arc<dyn LspAdapterDelegate>,
+ cx: &mut AsyncAppContext,
+ ) -> Option<Task<Result<()>>> {
+ self.adapter.will_start_server(delegate, cx)
}
pub async fn fetch_server_binary(
&self,
version: Box<dyn 'static + Send + Any>,
- http: Arc<dyn HttpClient>,
container_dir: PathBuf,
+ delegate: &dyn LspAdapterDelegate,
) -> Result<LanguageServerBinary> {
self.adapter
- .fetch_server_binary(version, http, container_dir)
+ .fetch_server_binary(version, container_dir, delegate)
.await
}
pub async fn cached_server_binary(
&self,
container_dir: PathBuf,
+ delegate: &dyn LspAdapterDelegate,
) -> Option<LanguageServerBinary> {
- self.adapter.cached_server_binary(container_dir).await
+ self.adapter
+ .cached_server_binary(container_dir, delegate)
+ .await
}
pub fn code_action_kinds(&self) -> Option<Vec<CodeActionKind>> {
@@ -187,23 +206,48 @@ impl CachedLspAdapter {
}
}
+pub trait LspAdapterDelegate: Send + Sync {
+ fn show_notification(&self, message: &str, cx: &mut AppContext);
+ fn http_client(&self) -> Arc<dyn HttpClient>;
+}
+
#[async_trait]
pub trait LspAdapter: 'static + Send + Sync {
async fn name(&self) -> LanguageServerName;
async fn fetch_latest_server_version(
&self,
- http: Arc<dyn HttpClient>,
+ delegate: &dyn LspAdapterDelegate,
) -> Result<Box<dyn 'static + Send + Any>>;
+ fn will_fetch_server(
+ &self,
+ _: &Arc<dyn LspAdapterDelegate>,
+ _: &mut AsyncAppContext,
+ ) -> Option<Task<Result<()>>> {
+ None
+ }
+
+ fn will_start_server(
+ &self,
+ _: &Arc<dyn LspAdapterDelegate>,
+ _: &mut AsyncAppContext,
+ ) -> Option<Task<Result<()>>> {
+ None
+ }
+
async fn fetch_server_binary(
&self,
version: Box<dyn 'static + Send + Any>,
- http: Arc<dyn HttpClient>,
container_dir: PathBuf,
+ delegate: &dyn LspAdapterDelegate,
) -> Result<LanguageServerBinary>;
- async fn cached_server_binary(&self, container_dir: PathBuf) -> Option<LanguageServerBinary>;
+ async fn cached_server_binary(
+ &self,
+ container_dir: PathBuf,
+ delegate: &dyn LspAdapterDelegate,
+ ) -> Option<LanguageServerBinary>;
async fn process_diagnostics(&self, _: &mut lsp::PublishDiagnosticsParams) {}
@@ -513,10 +557,7 @@ pub struct LanguageRegistry {
login_shell_env_loaded: Shared<Task<()>>,
#[allow(clippy::type_complexity)]
lsp_binary_paths: Mutex<
- HashMap<
- LanguageServerName,
- Shared<BoxFuture<'static, Result<LanguageServerBinary, Arc<anyhow::Error>>>>,
- >,
+ HashMap<LanguageServerName, Shared<Task<Result<LanguageServerBinary, Arc<anyhow::Error>>>>>,
>,
executor: Option<Arc<Background>>,
}
@@ -812,7 +853,7 @@ impl LanguageRegistry {
language: Arc<Language>,
adapter: Arc<CachedLspAdapter>,
root_path: Arc<Path>,
- http_client: Arc<dyn HttpClient>,
+ delegate: Arc<dyn LspAdapterDelegate>,
cx: &mut AppContext,
) -> Option<PendingLanguageServer> {
let server_id = self.state.write().next_language_server_id();
@@ -860,35 +901,40 @@ impl LanguageRegistry {
.log_err()?;
let this = self.clone();
let language = language.clone();
- let http_client = http_client.clone();
let download_dir = download_dir.clone();
let root_path = root_path.clone();
let adapter = adapter.clone();
let lsp_binary_statuses = self.lsp_binary_statuses_tx.clone();
let login_shell_env_loaded = self.login_shell_env_loaded.clone();
- let task = cx.spawn(|cx| async move {
+ let task = cx.spawn(|mut cx| async move {
login_shell_env_loaded.await;
- let mut lock = this.lsp_binary_paths.lock();
- let entry = lock
+ let entry = this
+ .lsp_binary_paths
+ .lock()
.entry(adapter.name.clone())
.or_insert_with(|| {
- get_binary(
- adapter.clone(),
- language.clone(),
- http_client,
- download_dir,
- lsp_binary_statuses,
- )
- .map_err(Arc::new)
- .boxed()
+ cx.spawn(|cx| {
+ get_binary(
+ adapter.clone(),
+ language.clone(),
+ delegate.clone(),
+ download_dir,
+ lsp_binary_statuses,
+ cx,
+ )
+ .map_err(Arc::new)
+ })
.shared()
})
.clone();
- drop(lock);
let binary = entry.clone().map_err(|e| anyhow!(e)).await?;
+ if let Some(task) = adapter.will_start_server(&delegate, &mut cx) {
+ task.await?;
+ }
+
let server = lsp::LanguageServer::new(
server_id,
&binary.path,
@@ -958,9 +1004,10 @@ impl Default for LanguageRegistry {
async fn get_binary(
adapter: Arc<CachedLspAdapter>,
language: Arc<Language>,
- http_client: Arc<dyn HttpClient>,
+ delegate: Arc<dyn LspAdapterDelegate>,
download_dir: Arc<Path>,
statuses: async_broadcast::Sender<(Arc<Language>, LanguageServerBinaryStatus)>,
+ mut cx: AsyncAppContext,
) -> Result<LanguageServerBinary> {
let container_dir = download_dir.join(adapter.name.0.as_ref());
if !container_dir.exists() {
@@ -969,17 +1016,24 @@ async fn get_binary(
.context("failed to create container directory")?;
}
+ if let Some(task) = adapter.will_fetch_server(&delegate, &mut cx) {
+ task.await?;
+ }
+
let binary = fetch_latest_binary(
adapter.clone(),
language.clone(),
- http_client,
+ delegate.as_ref(),
&container_dir,
statuses.clone(),
)
.await;
if let Err(error) = binary.as_ref() {
- if let Some(cached) = adapter.cached_server_binary(container_dir).await {
+ if let Some(cached) = adapter
+ .cached_server_binary(container_dir, delegate.as_ref())
+ .await
+ {
statuses
.broadcast((language.clone(), LanguageServerBinaryStatus::Cached))
.await?;
@@ -1001,7 +1055,7 @@ async fn get_binary(
async fn fetch_latest_binary(
adapter: Arc<CachedLspAdapter>,
language: Arc<Language>,
- http_client: Arc<dyn HttpClient>,
+ delegate: &dyn LspAdapterDelegate,
container_dir: &Path,
lsp_binary_statuses_tx: async_broadcast::Sender<(Arc<Language>, LanguageServerBinaryStatus)>,
) -> Result<LanguageServerBinary> {
@@ -1012,14 +1066,12 @@ async fn fetch_latest_binary(
LanguageServerBinaryStatus::CheckingForUpdate,
))
.await?;
- let version_info = adapter
- .fetch_latest_server_version(http_client.clone())
- .await?;
+ let version_info = adapter.fetch_latest_server_version(delegate).await?;
lsp_binary_statuses_tx
.broadcast((language.clone(), LanguageServerBinaryStatus::Downloading))
.await?;
let binary = adapter
- .fetch_server_binary(version_info, http_client, container_dir.to_path_buf())
+ .fetch_server_binary(version_info, container_dir.to_path_buf(), delegate)
.await?;
lsp_binary_statuses_tx
.broadcast((language.clone(), LanguageServerBinaryStatus::Downloaded))
@@ -1543,7 +1595,7 @@ impl LspAdapter for Arc<FakeLspAdapter> {
async fn fetch_latest_server_version(
&self,
- _: Arc<dyn HttpClient>,
+ _: &dyn LspAdapterDelegate,
) -> Result<Box<dyn 'static + Send + Any>> {
unreachable!();
}
@@ -1551,13 +1603,17 @@ impl LspAdapter for Arc<FakeLspAdapter> {
async fn fetch_server_binary(
&self,
_: Box<dyn 'static + Send + Any>,
- _: Arc<dyn HttpClient>,
_: PathBuf,
+ _: &dyn LspAdapterDelegate,
) -> Result<LanguageServerBinary> {
unreachable!();
}
- async fn cached_server_binary(&self, _: PathBuf) -> Option<LanguageServerBinary> {
+ async fn cached_server_binary(
+ &self,
+ _: PathBuf,
+ _: &dyn LspAdapterDelegate,
+ ) -> Option<LanguageServerBinary> {
unreachable!();
}
@@ -38,9 +38,9 @@ use language::{
},
range_from_lsp, range_to_lsp, Anchor, Bias, Buffer, CachedLspAdapter, CodeAction, CodeLabel,
Completion, Diagnostic, DiagnosticEntry, DiagnosticSet, Diff, Event as BufferEvent, File as _,
- Language, LanguageRegistry, LanguageServerName, LocalFile, OffsetRangeExt, Operation, Patch,
- PendingLanguageServer, PointUtf16, TextBufferSnapshot, ToOffset, ToPointUtf16, Transaction,
- Unclipped,
+ Language, LanguageRegistry, LanguageServerName, LocalFile, LspAdapterDelegate, OffsetRangeExt,
+ Operation, Patch, PendingLanguageServer, PointUtf16, TextBufferSnapshot, ToOffset,
+ ToPointUtf16, Transaction, Unclipped,
};
use log::error;
use lsp::{
@@ -75,8 +75,8 @@ use std::{
};
use terminals::Terminals;
use util::{
- debug_panic, defer, merge_json_value_into, paths::LOCAL_SETTINGS_RELATIVE_PATH, post_inc,
- ResultExt, TryFutureExt as _,
+ debug_panic, defer, http::HttpClient, merge_json_value_into,
+ paths::LOCAL_SETTINGS_RELATIVE_PATH, post_inc, ResultExt, TryFutureExt as _,
};
pub use fs::*;
@@ -252,6 +252,7 @@ pub enum Event {
LanguageServerAdded(LanguageServerId),
LanguageServerRemoved(LanguageServerId),
LanguageServerLog(LanguageServerId, String),
+ Notification(String),
ActiveEntryChanged(Option<ProjectEntryId>),
WorktreeAdded,
WorktreeRemoved(WorktreeId),
@@ -435,6 +436,11 @@ pub enum FormatTrigger {
Manual,
}
+struct ProjectLspAdapterDelegate {
+ project: ModelHandle<Project>,
+ http_client: Arc<dyn HttpClient>,
+}
+
impl FormatTrigger {
fn from_proto(value: i32) -> FormatTrigger {
match value {
@@ -2407,7 +2413,7 @@ impl Project {
language.clone(),
adapter.clone(),
worktree_path.clone(),
- self.client.http_client(),
+ ProjectLspAdapterDelegate::new(self, cx),
cx,
) {
Some(pending_server) => pending_server,
@@ -7188,6 +7194,26 @@ impl<P: AsRef<Path>> From<(WorktreeId, P)> for ProjectPath {
}
}
+impl ProjectLspAdapterDelegate {
+ fn new(project: &Project, cx: &ModelContext<Project>) -> Arc<Self> {
+ Arc::new(Self {
+ project: cx.handle(),
+ http_client: project.client.http_client(),
+ })
+ }
+}
+
+impl LspAdapterDelegate for ProjectLspAdapterDelegate {
+ fn show_notification(&self, message: &str, cx: &mut AppContext) {
+ self.project
+ .update(cx, |_, cx| cx.emit(Event::Notification(message.to_owned())));
+ }
+
+ fn http_client(&self) -> Arc<dyn HttpClient> {
+ self.http_client.clone()
+ }
+}
+
fn split_operations(
mut operations: Vec<proto::Operation>,
) -> impl Iterator<Item = Vec<proto::Operation>> {
@@ -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()
@@ -4,12 +4,11 @@ use futures::StreamExt;
pub use language::*;
use smol::fs::{self, File};
use std::{any::Any, path::PathBuf, sync::Arc};
-use util::fs::remove_matching;
-use util::github::latest_github_release;
-use util::http::HttpClient;
-use util::ResultExt;
-
-use util::github::GitHubLspBinaryVersion;
+use util::{
+ fs::remove_matching,
+ github::{latest_github_release, GitHubLspBinaryVersion},
+ ResultExt,
+};
pub struct CLspAdapter;
@@ -21,9 +20,9 @@ impl super::LspAdapter for CLspAdapter {
async fn fetch_latest_server_version(
&self,
- http: Arc<dyn HttpClient>,
+ delegate: &dyn LspAdapterDelegate,
) -> Result<Box<dyn 'static + Send + Any>> {
- let release = latest_github_release("clangd/clangd", false, http).await?;
+ let release = latest_github_release("clangd/clangd", false, delegate.http_client()).await?;
let asset_name = format!("clangd-mac-{}.zip", release.name);
let asset = release
.assets
@@ -40,8 +39,8 @@ impl super::LspAdapter for CLspAdapter {
async fn fetch_server_binary(
&self,
version: Box<dyn 'static + Send + Any>,
- http: Arc<dyn HttpClient>,
container_dir: PathBuf,
+ delegate: &dyn LspAdapterDelegate,
) -> Result<LanguageServerBinary> {
let version = version.downcast::<GitHubLspBinaryVersion>().unwrap();
let zip_path = container_dir.join(format!("clangd_{}.zip", version.name));
@@ -49,7 +48,8 @@ impl super::LspAdapter for CLspAdapter {
let binary_path = version_dir.join("bin/clangd");
if fs::metadata(&binary_path).await.is_err() {
- let mut response = http
+ let mut response = delegate
+ .http_client()
.get(&version.url, Default::default(), true)
.await
.context("error downloading release")?;
@@ -81,7 +81,11 @@ impl super::LspAdapter for CLspAdapter {
})
}
- async fn cached_server_binary(&self, container_dir: PathBuf) -> Option<LanguageServerBinary> {
+ async fn cached_server_binary(
+ &self,
+ container_dir: PathBuf,
+ _: &dyn LspAdapterDelegate,
+ ) -> Option<LanguageServerBinary> {
(|| async move {
let mut last_clangd_dir = None;
let mut entries = fs::read_dir(&container_dir).await?;
@@ -1,16 +1,23 @@
use anyhow::{anyhow, Context, Result};
use async_trait::async_trait;
use futures::StreamExt;
+use gpui::{AsyncAppContext, Task};
pub use language::*;
use lsp::{CompletionItemKind, SymbolKind};
use smol::fs::{self, File};
-use std::{any::Any, path::PathBuf, sync::Arc};
-use util::fs::remove_matching;
-use util::github::latest_github_release;
-use util::http::HttpClient;
-use util::ResultExt;
-
-use util::github::GitHubLspBinaryVersion;
+use std::{
+ any::Any,
+ path::PathBuf,
+ sync::{
+ atomic::{AtomicBool, Ordering::SeqCst},
+ Arc,
+ },
+};
+use util::{
+ fs::remove_matching,
+ github::{latest_github_release, GitHubLspBinaryVersion},
+ ResultExt,
+};
pub struct ElixirLspAdapter;
@@ -20,11 +27,43 @@ impl LspAdapter for ElixirLspAdapter {
LanguageServerName("elixir-ls".into())
}
+ fn will_start_server(
+ &self,
+ delegate: &Arc<dyn LspAdapterDelegate>,
+ cx: &mut AsyncAppContext,
+ ) -> Option<Task<Result<()>>> {
+ static DID_SHOW_NOTIFICATION: AtomicBool = AtomicBool::new(false);
+
+ const NOTIFICATION_MESSAGE: &str = "Could not run the elixir language server, `elixir-ls`, because `elixir` was not found.";
+
+ let delegate = delegate.clone();
+ Some(cx.spawn(|mut cx| async move {
+ let elixir_output = smol::process::Command::new("elixir")
+ .args(["--version"])
+ .output()
+ .await;
+ if elixir_output.is_err() {
+ if DID_SHOW_NOTIFICATION
+ .compare_exchange(false, true, SeqCst, SeqCst)
+ .is_ok()
+ {
+ cx.update(|cx| {
+ delegate.show_notification(NOTIFICATION_MESSAGE, cx);
+ })
+ }
+ return Err(anyhow!("cannot run elixir-ls"));
+ }
+
+ Ok(())
+ }))
+ }
+
async fn fetch_latest_server_version(
&self,
- http: Arc<dyn HttpClient>,
+ delegate: &dyn LspAdapterDelegate,
) -> Result<Box<dyn 'static + Send + Any>> {
- let release = latest_github_release("elixir-lsp/elixir-ls", false, http).await?;
+ let release =
+ latest_github_release("elixir-lsp/elixir-ls", false, delegate.http_client()).await?;
let asset_name = "elixir-ls.zip";
let asset = release
.assets
@@ -41,8 +80,8 @@ impl LspAdapter for ElixirLspAdapter {
async fn fetch_server_binary(
&self,
version: Box<dyn 'static + Send + Any>,
- http: Arc<dyn HttpClient>,
container_dir: PathBuf,
+ delegate: &dyn LspAdapterDelegate,
) -> Result<LanguageServerBinary> {
let version = version.downcast::<GitHubLspBinaryVersion>().unwrap();
let zip_path = container_dir.join(format!("elixir-ls_{}.zip", version.name));
@@ -50,7 +89,8 @@ impl LspAdapter for ElixirLspAdapter {
let binary_path = version_dir.join("language_server.sh");
if fs::metadata(&binary_path).await.is_err() {
- let mut response = http
+ let mut response = delegate
+ .http_client()
.get(&version.url, Default::default(), true)
.await
.context("error downloading release")?;
@@ -88,7 +128,11 @@ impl LspAdapter for ElixirLspAdapter {
})
}
- async fn cached_server_binary(&self, container_dir: PathBuf) -> Option<LanguageServerBinary> {
+ async fn cached_server_binary(
+ &self,
+ container_dir: PathBuf,
+ _: &dyn LspAdapterDelegate,
+ ) -> Option<LanguageServerBinary> {
(|| async move {
let mut last = None;
let mut entries = fs::read_dir(&container_dir).await?;
@@ -1,16 +1,23 @@
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;
use smol::{fs, process};
-use std::ffi::{OsStr, OsString};
-use std::{any::Any, ops::Range, path::PathBuf, str, sync::Arc};
-use util::fs::remove_matching;
-use util::github::latest_github_release;
-use util::http::HttpClient;
-use util::ResultExt;
+use std::{
+ any::Any,
+ ffi::{OsStr, OsString},
+ ops::Range,
+ path::PathBuf,
+ str,
+ sync::{
+ atomic::{AtomicBool, Ordering::SeqCst},
+ Arc,
+ },
+};
+use util::{fs::remove_matching, github::latest_github_release, ResultExt};
fn server_binary_arguments() -> Vec<OsString> {
vec!["-mode=stdio".into()]
@@ -31,9 +38,9 @@ impl super::LspAdapter for GoLspAdapter {
async fn fetch_latest_server_version(
&self,
- http: Arc<dyn HttpClient>,
+ delegate: &dyn LspAdapterDelegate,
) -> Result<Box<dyn 'static + Send + Any>> {
- let release = latest_github_release("golang/tools", false, http).await?;
+ let release = latest_github_release("golang/tools", false, delegate.http_client()).await?;
let version: Option<String> = release.name.strip_prefix("gopls/v").map(str::to_string);
if version.is_none() {
log::warn!(
@@ -44,11 +51,39 @@ impl super::LspAdapter for GoLspAdapter {
Ok(Box::new(version) as Box<_>)
}
+ fn will_fetch_server(
+ &self,
+ delegate: &Arc<dyn LspAdapterDelegate>,
+ cx: &mut AsyncAppContext,
+ ) -> Option<Task<Result<()>>> {
+ static DID_SHOW_NOTIFICATION: AtomicBool = AtomicBool::new(false);
+
+ const NOTIFICATION_MESSAGE: &str =
+ "Could not install the Go language server `gopls`, because `go` was not found.";
+
+ 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() {
+ if DID_SHOW_NOTIFICATION
+ .compare_exchange(false, true, SeqCst, SeqCst)
+ .is_ok()
+ {
+ cx.update(|cx| {
+ delegate.show_notification(NOTIFICATION_MESSAGE, cx);
+ })
+ }
+ return Err(anyhow!("cannot install gopls"));
+ }
+ Ok(())
+ }))
+ }
+
async fn fetch_server_binary(
&self,
version: Box<dyn 'static + Send + Any>,
- _: Arc<dyn HttpClient>,
container_dir: PathBuf,
+ delegate: &dyn LspAdapterDelegate,
) -> Result<LanguageServerBinary> {
let version = version.downcast::<Option<String>>().unwrap();
let this = *self;
@@ -68,7 +103,10 @@ impl super::LspAdapter for GoLspAdapter {
});
}
}
- } else if let Some(path) = this.cached_server_binary(container_dir.clone()).await {
+ } else if let Some(path) = this
+ .cached_server_binary(container_dir.clone(), delegate)
+ .await
+ {
return Ok(path);
}
@@ -105,7 +143,11 @@ impl super::LspAdapter for GoLspAdapter {
})
}
- async fn cached_server_binary(&self, container_dir: PathBuf) -> Option<LanguageServerBinary> {
+ async fn cached_server_binary(
+ &self,
+ container_dir: PathBuf,
+ _: &dyn LspAdapterDelegate,
+ ) -> Option<LanguageServerBinary> {
(|| async move {
let mut last_binary_path = None;
let mut entries = fs::read_dir(&container_dir).await?;
@@ -1,14 +1,16 @@
use anyhow::{anyhow, Result};
use async_trait::async_trait;
use futures::StreamExt;
-use language::{LanguageServerBinary, LanguageServerName, LspAdapter};
+use language::{LanguageServerBinary, LanguageServerName, LspAdapter, LspAdapterDelegate};
use node_runtime::NodeRuntime;
use serde_json::json;
use smol::fs;
-use std::ffi::OsString;
-use std::path::Path;
-use std::{any::Any, path::PathBuf, sync::Arc};
-use util::http::HttpClient;
+use std::{
+ any::Any,
+ ffi::OsString,
+ path::{Path, PathBuf},
+ sync::Arc,
+};
use util::ResultExt;
fn server_binary_arguments(server_path: &Path) -> Vec<OsString> {
@@ -36,7 +38,7 @@ impl LspAdapter for HtmlLspAdapter {
async fn fetch_latest_server_version(
&self,
- _: Arc<dyn HttpClient>,
+ _: &dyn LspAdapterDelegate,
) -> Result<Box<dyn 'static + Any + Send>> {
Ok(Box::new(
self.node
@@ -48,8 +50,8 @@ impl LspAdapter for HtmlLspAdapter {
async fn fetch_server_binary(
&self,
version: Box<dyn 'static + Send + Any>,
- _: Arc<dyn HttpClient>,
container_dir: PathBuf,
+ _: &dyn LspAdapterDelegate,
) -> Result<LanguageServerBinary> {
let version = version.downcast::<String>().unwrap();
let server_path = container_dir.join(Self::SERVER_PATH);
@@ -69,7 +71,11 @@ impl LspAdapter for HtmlLspAdapter {
})
}
- async fn cached_server_binary(&self, container_dir: PathBuf) -> Option<LanguageServerBinary> {
+ async fn cached_server_binary(
+ &self,
+ container_dir: PathBuf,
+ _: &dyn LspAdapterDelegate,
+ ) -> Option<LanguageServerBinary> {
(|| async move {
let mut last_version_dir = None;
let mut entries = fs::read_dir(&container_dir).await?;
@@ -3,7 +3,9 @@ use async_trait::async_trait;
use collections::HashMap;
use futures::{future::BoxFuture, FutureExt, StreamExt};
use gpui::AppContext;
-use language::{LanguageRegistry, LanguageServerBinary, LanguageServerName, LspAdapter};
+use language::{
+ LanguageRegistry, LanguageServerBinary, LanguageServerName, LspAdapter, LspAdapterDelegate,
+};
use node_runtime::NodeRuntime;
use serde_json::json;
use settings::{KeymapFile, SettingsJsonSchemaParams, SettingsStore};
@@ -16,7 +18,6 @@ use std::{
path::{Path, PathBuf},
sync::Arc,
};
-use util::http::HttpClient;
use util::{paths, ResultExt};
const SERVER_PATH: &'static str =
@@ -45,7 +46,7 @@ impl LspAdapter for JsonLspAdapter {
async fn fetch_latest_server_version(
&self,
- _: Arc<dyn HttpClient>,
+ _: &dyn LspAdapterDelegate,
) -> Result<Box<dyn 'static + Send + Any>> {
Ok(Box::new(
self.node
@@ -57,8 +58,8 @@ impl LspAdapter for JsonLspAdapter {
async fn fetch_server_binary(
&self,
version: Box<dyn 'static + Send + Any>,
- _: Arc<dyn HttpClient>,
container_dir: PathBuf,
+ _: &dyn LspAdapterDelegate,
) -> Result<LanguageServerBinary> {
let version = version.downcast::<String>().unwrap();
let server_path = container_dir.join(SERVER_PATH);
@@ -78,7 +79,11 @@ impl LspAdapter for JsonLspAdapter {
})
}
- async fn cached_server_binary(&self, container_dir: PathBuf) -> Option<LanguageServerBinary> {
+ async fn cached_server_binary(
+ &self,
+ container_dir: PathBuf,
+ _: &dyn LspAdapterDelegate,
+ ) -> Option<LanguageServerBinary> {
(|| async move {
let mut last_version_dir = None;
let mut entries = fs::read_dir(&container_dir).await?;
@@ -3,10 +3,9 @@ use async_trait::async_trait;
use collections::HashMap;
use futures::lock::Mutex;
use gpui::executor::Background;
-use language::{LanguageServerBinary, LanguageServerName, LspAdapter};
+use language::{LanguageServerBinary, LanguageServerName, LspAdapter, LspAdapterDelegate};
use plugin_runtime::{Plugin, PluginBinary, PluginBuilder, WasiFn};
use std::{any::Any, path::PathBuf, sync::Arc};
-use util::http::HttpClient;
use util::ResultExt;
#[allow(dead_code)]
@@ -72,7 +71,7 @@ impl LspAdapter for PluginLspAdapter {
async fn fetch_latest_server_version(
&self,
- _: Arc<dyn HttpClient>,
+ _: &dyn LspAdapterDelegate,
) -> Result<Box<dyn 'static + Send + Any>> {
let runtime = self.runtime.clone();
let function = self.fetch_latest_server_version;
@@ -92,8 +91,8 @@ impl LspAdapter for PluginLspAdapter {
async fn fetch_server_binary(
&self,
version: Box<dyn 'static + Send + Any>,
- _: Arc<dyn HttpClient>,
container_dir: PathBuf,
+ _: &dyn LspAdapterDelegate,
) -> Result<LanguageServerBinary> {
let version = *version.downcast::<String>().unwrap();
let runtime = self.runtime.clone();
@@ -110,7 +109,11 @@ impl LspAdapter for PluginLspAdapter {
.await
}
- async fn cached_server_binary(&self, container_dir: PathBuf) -> Option<LanguageServerBinary> {
+ async fn cached_server_binary(
+ &self,
+ container_dir: PathBuf,
+ _: &dyn LspAdapterDelegate,
+ ) -> Option<LanguageServerBinary> {
let runtime = self.runtime.clone();
let function = self.cached_server_binary;
@@ -3,12 +3,14 @@ use async_compression::futures::bufread::GzipDecoder;
use async_tar::Archive;
use async_trait::async_trait;
use futures::{io::BufReader, StreamExt};
-use language::{LanguageServerBinary, LanguageServerName};
+use language::{LanguageServerBinary, LanguageServerName, LspAdapterDelegate};
use smol::fs;
-use std::{any::Any, env::consts, ffi::OsString, path::PathBuf, sync::Arc};
-use util::{async_iife, github::latest_github_release, http::HttpClient, ResultExt};
-
-use util::github::GitHubLspBinaryVersion;
+use std::{any::Any, env::consts, ffi::OsString, path::PathBuf};
+use util::{
+ async_iife,
+ github::{latest_github_release, GitHubLspBinaryVersion},
+ ResultExt,
+};
#[derive(Copy, Clone)]
pub struct LuaLspAdapter;
@@ -28,9 +30,11 @@ impl super::LspAdapter for LuaLspAdapter {
async fn fetch_latest_server_version(
&self,
- http: Arc<dyn HttpClient>,
+ delegate: &dyn LspAdapterDelegate,
) -> Result<Box<dyn 'static + Send + Any>> {
- let release = latest_github_release("LuaLS/lua-language-server", false, http).await?;
+ let release =
+ latest_github_release("LuaLS/lua-language-server", false, delegate.http_client())
+ .await?;
let version = release.name.clone();
let platform = match consts::ARCH {
"x86_64" => "x64",
@@ -53,15 +57,16 @@ impl super::LspAdapter for LuaLspAdapter {
async fn fetch_server_binary(
&self,
version: Box<dyn 'static + Send + Any>,
- http: Arc<dyn HttpClient>,
container_dir: PathBuf,
+ delegate: &dyn LspAdapterDelegate,
) -> Result<LanguageServerBinary> {
let version = version.downcast::<GitHubLspBinaryVersion>().unwrap();
let binary_path = container_dir.join("bin/lua-language-server");
if fs::metadata(&binary_path).await.is_err() {
- let mut response = http
+ let mut response = delegate
+ .http_client()
.get(&version.url, Default::default(), true)
.await
.map_err(|err| anyhow!("error downloading release: {}", err))?;
@@ -81,7 +86,11 @@ impl super::LspAdapter for LuaLspAdapter {
})
}
- async fn cached_server_binary(&self, container_dir: PathBuf) -> Option<LanguageServerBinary> {
+ async fn cached_server_binary(
+ &self,
+ container_dir: PathBuf,
+ _: &dyn LspAdapterDelegate,
+ ) -> Option<LanguageServerBinary> {
async_iife!({
let mut last_binary_path = None;
let mut entries = fs::read_dir(&container_dir).await?;
@@ -1,7 +1,7 @@
use anyhow::{anyhow, Result};
use async_trait::async_trait;
use futures::StreamExt;
-use language::{LanguageServerBinary, LanguageServerName, LspAdapter};
+use language::{LanguageServerBinary, LanguageServerName, LspAdapter, LspAdapterDelegate};
use node_runtime::NodeRuntime;
use smol::fs;
use std::{
@@ -10,7 +10,6 @@ use std::{
path::{Path, PathBuf},
sync::Arc,
};
-use util::http::HttpClient;
use util::ResultExt;
fn server_binary_arguments(server_path: &Path) -> Vec<OsString> {
@@ -37,7 +36,7 @@ impl LspAdapter for PythonLspAdapter {
async fn fetch_latest_server_version(
&self,
- _: Arc<dyn HttpClient>,
+ _: &dyn LspAdapterDelegate,
) -> Result<Box<dyn 'static + Any + Send>> {
Ok(Box::new(self.node.npm_package_latest_version("pyright").await?) as Box<_>)
}
@@ -45,8 +44,8 @@ impl LspAdapter for PythonLspAdapter {
async fn fetch_server_binary(
&self,
version: Box<dyn 'static + Send + Any>,
- _: Arc<dyn HttpClient>,
container_dir: PathBuf,
+ _: &dyn LspAdapterDelegate,
) -> Result<LanguageServerBinary> {
let version = version.downcast::<String>().unwrap();
let server_path = container_dir.join(Self::SERVER_PATH);
@@ -63,7 +62,11 @@ impl LspAdapter for PythonLspAdapter {
})
}
- async fn cached_server_binary(&self, container_dir: PathBuf) -> Option<LanguageServerBinary> {
+ async fn cached_server_binary(
+ &self,
+ container_dir: PathBuf,
+ _: &dyn LspAdapterDelegate,
+ ) -> Option<LanguageServerBinary> {
(|| async move {
let mut last_version_dir = None;
let mut entries = fs::read_dir(&container_dir).await?;
@@ -1,8 +1,7 @@
use anyhow::{anyhow, Result};
use async_trait::async_trait;
-use language::{LanguageServerBinary, LanguageServerName, LspAdapter};
+use language::{LanguageServerBinary, LanguageServerName, LspAdapter, LspAdapterDelegate};
use std::{any::Any, path::PathBuf, sync::Arc};
-use util::http::HttpClient;
pub struct RubyLanguageServer;
@@ -14,7 +13,7 @@ impl LspAdapter for RubyLanguageServer {
async fn fetch_latest_server_version(
&self,
- _: Arc<dyn HttpClient>,
+ _: &dyn LspAdapterDelegate,
) -> Result<Box<dyn 'static + Any + Send>> {
Ok(Box::new(()))
}
@@ -22,13 +21,17 @@ impl LspAdapter for RubyLanguageServer {
async fn fetch_server_binary(
&self,
_version: Box<dyn 'static + Send + Any>,
- _: Arc<dyn HttpClient>,
_container_dir: PathBuf,
+ _: &dyn LspAdapterDelegate,
) -> Result<LanguageServerBinary> {
Err(anyhow!("solargraph must be installed manually"))
}
- async fn cached_server_binary(&self, _container_dir: PathBuf) -> Option<LanguageServerBinary> {
+ async fn cached_server_binary(
+ &self,
+ _: PathBuf,
+ _: &dyn LspAdapterDelegate,
+ ) -> Option<LanguageServerBinary> {
Some(LanguageServerBinary {
path: "solargraph".into(),
arguments: vec!["stdio".into()],
@@ -7,10 +7,11 @@ use lazy_static::lazy_static;
use regex::Regex;
use smol::fs::{self, File};
use std::{any::Any, borrow::Cow, env::consts, path::PathBuf, str, sync::Arc};
-use util::fs::remove_matching;
-use util::github::{latest_github_release, GitHubLspBinaryVersion};
-use util::http::HttpClient;
-use util::ResultExt;
+use util::{
+ fs::remove_matching,
+ github::{latest_github_release, GitHubLspBinaryVersion},
+ ResultExt,
+};
pub struct RustLspAdapter;
@@ -22,9 +23,11 @@ impl LspAdapter for RustLspAdapter {
async fn fetch_latest_server_version(
&self,
- http: Arc<dyn HttpClient>,
+ delegate: &dyn LspAdapterDelegate,
) -> Result<Box<dyn 'static + Send + Any>> {
- let release = latest_github_release("rust-analyzer/rust-analyzer", false, http).await?;
+ let release =
+ latest_github_release("rust-analyzer/rust-analyzer", false, delegate.http_client())
+ .await?;
let asset_name = format!("rust-analyzer-{}-apple-darwin.gz", consts::ARCH);
let asset = release
.assets
@@ -40,14 +43,15 @@ impl LspAdapter for RustLspAdapter {
async fn fetch_server_binary(
&self,
version: Box<dyn 'static + Send + Any>,
- http: Arc<dyn HttpClient>,
container_dir: PathBuf,
+ delegate: &dyn LspAdapterDelegate,
) -> Result<LanguageServerBinary> {
let version = version.downcast::<GitHubLspBinaryVersion>().unwrap();
let destination_path = container_dir.join(format!("rust-analyzer-{}", version.name));
if fs::metadata(&destination_path).await.is_err() {
- let mut response = http
+ let mut response = delegate
+ .http_client()
.get(&version.url, Default::default(), true)
.await
.map_err(|err| anyhow!("error downloading release: {}", err))?;
@@ -69,7 +73,11 @@ impl LspAdapter for RustLspAdapter {
})
}
- async fn cached_server_binary(&self, container_dir: PathBuf) -> Option<LanguageServerBinary> {
+ async fn cached_server_binary(
+ &self,
+ container_dir: PathBuf,
+ _: &dyn LspAdapterDelegate,
+ ) -> Option<LanguageServerBinary> {
(|| async move {
let mut last = None;
let mut entries = fs::read_dir(&container_dir).await?;
@@ -4,7 +4,7 @@ use async_tar::Archive;
use async_trait::async_trait;
use futures::{future::BoxFuture, FutureExt};
use gpui::AppContext;
-use language::{LanguageServerBinary, LanguageServerName, LspAdapter};
+use language::{LanguageServerBinary, LanguageServerName, LspAdapter, LspAdapterDelegate};
use lsp::CodeActionKind;
use node_runtime::NodeRuntime;
use serde_json::{json, Value};
@@ -16,7 +16,7 @@ use std::{
path::{Path, PathBuf},
sync::Arc,
};
-use util::{fs::remove_matching, github::latest_github_release, http::HttpClient};
+use util::{fs::remove_matching, github::latest_github_release};
use util::{github::GitHubLspBinaryVersion, ResultExt};
fn typescript_server_binary_arguments(server_path: &Path) -> Vec<OsString> {
@@ -58,7 +58,7 @@ impl LspAdapter for TypeScriptLspAdapter {
async fn fetch_latest_server_version(
&self,
- _: Arc<dyn HttpClient>,
+ _: &dyn LspAdapterDelegate,
) -> Result<Box<dyn 'static + Send + Any>> {
Ok(Box::new(TypeScriptVersions {
typescript_version: self.node.npm_package_latest_version("typescript").await?,
@@ -72,8 +72,8 @@ impl LspAdapter for TypeScriptLspAdapter {
async fn fetch_server_binary(
&self,
version: Box<dyn 'static + Send + Any>,
- _: Arc<dyn HttpClient>,
container_dir: PathBuf,
+ _: &dyn LspAdapterDelegate,
) -> Result<LanguageServerBinary> {
let version = version.downcast::<TypeScriptVersions>().unwrap();
let server_path = container_dir.join(Self::NEW_SERVER_PATH);
@@ -99,7 +99,11 @@ impl LspAdapter for TypeScriptLspAdapter {
})
}
- async fn cached_server_binary(&self, container_dir: PathBuf) -> Option<LanguageServerBinary> {
+ async fn cached_server_binary(
+ &self,
+ container_dir: PathBuf,
+ _: &dyn LspAdapterDelegate,
+ ) -> Option<LanguageServerBinary> {
(|| async move {
let old_server_path = container_dir.join(Self::OLD_SERVER_PATH);
let new_server_path = container_dir.join(Self::NEW_SERVER_PATH);
@@ -204,12 +208,13 @@ impl LspAdapter for EsLintLspAdapter {
async fn fetch_latest_server_version(
&self,
- http: Arc<dyn HttpClient>,
+ delegate: &dyn LspAdapterDelegate,
) -> Result<Box<dyn 'static + Send + Any>> {
// At the time of writing the latest vscode-eslint release was released in 2020 and requires
// special custom LSP protocol extensions be handled to fully initialize. Download the latest
// prerelease instead to sidestep this issue
- let release = latest_github_release("microsoft/vscode-eslint", true, http).await?;
+ let release =
+ latest_github_release("microsoft/vscode-eslint", true, delegate.http_client()).await?;
Ok(Box::new(GitHubLspBinaryVersion {
name: release.name,
url: release.tarball_url,
@@ -219,8 +224,8 @@ impl LspAdapter for EsLintLspAdapter {
async fn fetch_server_binary(
&self,
version: Box<dyn 'static + Send + Any>,
- http: Arc<dyn HttpClient>,
container_dir: PathBuf,
+ delegate: &dyn LspAdapterDelegate,
) -> Result<LanguageServerBinary> {
let version = version.downcast::<GitHubLspBinaryVersion>().unwrap();
let destination_path = container_dir.join(format!("vscode-eslint-{}", version.name));
@@ -229,7 +234,8 @@ impl LspAdapter for EsLintLspAdapter {
if fs::metadata(&server_path).await.is_err() {
remove_matching(&container_dir, |entry| entry != destination_path).await;
- let mut response = http
+ let mut response = delegate
+ .http_client()
.get(&version.url, Default::default(), true)
.await
.map_err(|err| anyhow!("error downloading release: {}", err))?;
@@ -257,7 +263,11 @@ impl LspAdapter for EsLintLspAdapter {
})
}
- async fn cached_server_binary(&self, container_dir: PathBuf) -> Option<LanguageServerBinary> {
+ async fn cached_server_binary(
+ &self,
+ container_dir: PathBuf,
+ _: &dyn LspAdapterDelegate,
+ ) -> Option<LanguageServerBinary> {
(|| async move {
// This is unfortunate but we don't know what the version is to build a path directly
let mut dir = fs::read_dir(&container_dir).await?;
@@ -4,6 +4,7 @@ use futures::{future::BoxFuture, FutureExt, StreamExt};
use gpui::AppContext;
use language::{
language_settings::all_language_settings, LanguageServerBinary, LanguageServerName, LspAdapter,
+ LspAdapterDelegate,
};
use node_runtime::NodeRuntime;
use serde_json::Value;
@@ -15,7 +16,6 @@ use std::{
path::{Path, PathBuf},
sync::Arc,
};
-use util::http::HttpClient;
use util::ResultExt;
fn server_binary_arguments(server_path: &Path) -> Vec<OsString> {
@@ -42,7 +42,7 @@ impl LspAdapter for YamlLspAdapter {
async fn fetch_latest_server_version(
&self,
- _: Arc<dyn HttpClient>,
+ _: &dyn LspAdapterDelegate,
) -> Result<Box<dyn 'static + Any + Send>> {
Ok(Box::new(
self.node
@@ -54,8 +54,8 @@ impl LspAdapter for YamlLspAdapter {
async fn fetch_server_binary(
&self,
version: Box<dyn 'static + Send + Any>,
- _: Arc<dyn HttpClient>,
container_dir: PathBuf,
+ _: &dyn LspAdapterDelegate,
) -> Result<LanguageServerBinary> {
let version = version.downcast::<String>().unwrap();
let server_path = container_dir.join(Self::SERVER_PATH);
@@ -72,7 +72,11 @@ impl LspAdapter for YamlLspAdapter {
})
}
- async fn cached_server_binary(&self, container_dir: PathBuf) -> Option<LanguageServerBinary> {
+ async fn cached_server_binary(
+ &self,
+ container_dir: PathBuf,
+ _: &dyn LspAdapterDelegate,
+ ) -> Option<LanguageServerBinary> {
(|| async move {
let mut last_version_dir = None;
let mut entries = fs::read_dir(&container_dir).await?;