From 360bbebbd9b972205a27812a8aa973d387ec5582 Mon Sep 17 00:00:00 2001 From: Max Brunsfeld Date: Mon, 19 Jun 2023 15:56:40 -0700 Subject: [PATCH] Introduce LspAdapterDelegate trait, passed to LspDelegates --- crates/language/src/language.rs | 92 +++++++++++++++----------- crates/project/src/project.rs | 39 +++++++++-- crates/zed/src/languages/c.rs | 26 +++++--- crates/zed/src/languages/elixir.rs | 27 +++++--- crates/zed/src/languages/go.rs | 32 ++++++--- crates/zed/src/languages/html.rs | 22 +++--- crates/zed/src/languages/json.rs | 15 +++-- crates/zed/src/languages/lua.rs | 29 +++++--- crates/zed/src/languages/python.rs | 13 ++-- crates/zed/src/languages/ruby.rs | 13 ++-- crates/zed/src/languages/rust.rs | 26 +++++--- crates/zed/src/languages/typescript.rs | 30 ++++++--- crates/zed/src/languages/yaml.rs | 12 ++-- 13 files changed, 243 insertions(+), 133 deletions(-) diff --git a/crates/language/src/language.rs b/crates/language/src/language.rs index e91d5770cf..c8554074cd 100644 --- a/crates/language/src/language.rs +++ b/crates/language/src/language.rs @@ -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,30 @@ impl CachedLspAdapter { pub async fn fetch_latest_server_version( &self, - http: Arc, + delegate: &dyn LspAdapterDelegate, ) -> Result> { - self.adapter.fetch_latest_server_version(http).await + self.adapter.fetch_latest_server_version(delegate).await } pub async fn fetch_server_binary( &self, version: Box, - http: Arc, container_dir: PathBuf, + delegate: &dyn LspAdapterDelegate, ) -> Result { 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 { - self.adapter.cached_server_binary(container_dir).await + self.adapter + .cached_server_binary(container_dir, delegate) + .await } pub fn code_action_kinds(&self) -> Option> { @@ -187,23 +190,32 @@ impl CachedLspAdapter { } } +pub trait LspAdapterDelegate: Send + Sync { + fn show_notification(&self, message: &str, cx: &mut AppContext); + fn http_client(&self) -> Arc; +} + #[async_trait] pub trait LspAdapter: 'static + Send + Sync { async fn name(&self) -> LanguageServerName; async fn fetch_latest_server_version( &self, - http: Arc, + delegate: &dyn LspAdapterDelegate, ) -> Result>; async fn fetch_server_binary( &self, version: Box, - http: Arc, container_dir: PathBuf, + delegate: &dyn LspAdapterDelegate, ) -> Result; - async fn cached_server_binary(&self, container_dir: PathBuf) -> Option; + async fn cached_server_binary( + &self, + container_dir: PathBuf, + delegate: &dyn LspAdapterDelegate, + ) -> Option; async fn process_diagnostics(&self, _: &mut lsp::PublishDiagnosticsParams) {} @@ -513,10 +525,7 @@ pub struct LanguageRegistry { login_shell_env_loaded: Shared>, #[allow(clippy::type_complexity)] lsp_binary_paths: Mutex< - HashMap< - LanguageServerName, - Shared>>>, - >, + HashMap>>>>, >, executor: Option>, } @@ -812,7 +821,7 @@ impl LanguageRegistry { language: Arc, adapter: Arc, root_path: Arc, - http_client: Arc, + delegate: Arc, cx: &mut AppContext, ) -> Option { let server_id = self.state.write().next_language_server_id(); @@ -860,7 +869,6 @@ 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(); @@ -870,23 +878,25 @@ impl LanguageRegistry { let task = cx.spawn(|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, + download_dir, + lsp_binary_statuses, + cx, + ) + .map_err(Arc::new) + }) .shared() }) .clone(); - drop(lock); let binary = entry.clone().map_err(|e| anyhow!(e)).await?; let server = lsp::LanguageServer::new( @@ -958,9 +968,10 @@ impl Default for LanguageRegistry { async fn get_binary( adapter: Arc, language: Arc, - http_client: Arc, + delegate: Arc, download_dir: Arc, statuses: async_broadcast::Sender<(Arc, LanguageServerBinaryStatus)>, + _cx: AsyncAppContext, ) -> Result { let container_dir = download_dir.join(adapter.name.0.as_ref()); if !container_dir.exists() { @@ -972,14 +983,17 @@ async fn get_binary( 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 +1015,7 @@ async fn get_binary( async fn fetch_latest_binary( adapter: Arc, language: Arc, - http_client: Arc, + delegate: &dyn LspAdapterDelegate, container_dir: &Path, lsp_binary_statuses_tx: async_broadcast::Sender<(Arc, LanguageServerBinaryStatus)>, ) -> Result { @@ -1012,14 +1026,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 +1555,7 @@ impl LspAdapter for Arc { async fn fetch_latest_server_version( &self, - _: Arc, + _: &dyn LspAdapterDelegate, ) -> Result> { unreachable!(); } @@ -1551,13 +1563,17 @@ impl LspAdapter for Arc { async fn fetch_server_binary( &self, _: Box, - _: Arc, _: PathBuf, + _: &dyn LspAdapterDelegate, ) -> Result { unreachable!(); } - async fn cached_server_binary(&self, _: PathBuf) -> Option { + async fn cached_server_binary( + &self, + _: PathBuf, + _: &dyn LspAdapterDelegate, + ) -> Option { unreachable!(); } diff --git a/crates/project/src/project.rs b/crates/project/src/project.rs index 5069c805b7..6d823f0107 100644 --- a/crates/project/src/project.rs +++ b/crates/project/src/project.rs @@ -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), + LanguageServerNotification(String), ActiveEntryChanged(Option), WorktreeAdded, WorktreeRemoved(WorktreeId), @@ -435,6 +436,11 @@ pub enum FormatTrigger { Manual, } +struct ProjectLspAdapterDelegate { + project: ModelHandle, + http_client: Arc, +} + 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,27 @@ impl> From<(WorktreeId, P)> for ProjectPath { } } +impl ProjectLspAdapterDelegate { + fn new(project: &Project, cx: &ModelContext) -> Arc { + 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::LanguageServerNotification(message.to_owned())) + }); + } + + fn http_client(&self) -> Arc { + self.http_client.clone() + } +} + fn split_operations( mut operations: Vec, ) -> impl Iterator> { diff --git a/crates/zed/src/languages/c.rs b/crates/zed/src/languages/c.rs index 7e4ddcef19..241b11b47c 100644 --- a/crates/zed/src/languages/c.rs +++ b/crates/zed/src/languages/c.rs @@ -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, + delegate: &dyn LspAdapterDelegate, ) -> Result> { - 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, - http: Arc, container_dir: PathBuf, + delegate: &dyn LspAdapterDelegate, ) -> Result { let version = version.downcast::().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 { + async fn cached_server_binary( + &self, + container_dir: PathBuf, + _: &dyn LspAdapterDelegate, + ) -> Option { (|| async move { let mut last_clangd_dir = None; let mut entries = fs::read_dir(&container_dir).await?; diff --git a/crates/zed/src/languages/elixir.rs b/crates/zed/src/languages/elixir.rs index 2939a0fa5f..b63dba3778 100644 --- a/crates/zed/src/languages/elixir.rs +++ b/crates/zed/src/languages/elixir.rs @@ -5,12 +5,11 @@ 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 util::{ + fs::remove_matching, + github::{latest_github_release, GitHubLspBinaryVersion}, + ResultExt, +}; pub struct ElixirLspAdapter; @@ -22,9 +21,10 @@ impl LspAdapter for ElixirLspAdapter { async fn fetch_latest_server_version( &self, - http: Arc, + delegate: &dyn LspAdapterDelegate, ) -> Result> { - 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 +41,8 @@ impl LspAdapter for ElixirLspAdapter { async fn fetch_server_binary( &self, version: Box, - http: Arc, container_dir: PathBuf, + delegate: &dyn LspAdapterDelegate, ) -> Result { let version = version.downcast::().unwrap(); let zip_path = container_dir.join(format!("elixir-ls_{}.zip", version.name)); @@ -50,7 +50,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 +89,11 @@ impl LspAdapter for ElixirLspAdapter { }) } - async fn cached_server_binary(&self, container_dir: PathBuf) -> Option { + async fn cached_server_binary( + &self, + container_dir: PathBuf, + _: &dyn LspAdapterDelegate, + ) -> Option { (|| async move { let mut last = None; let mut entries = fs::read_dir(&container_dir).await?; diff --git a/crates/zed/src/languages/go.rs b/crates/zed/src/languages/go.rs index ed24abb45c..c425e6931f 100644 --- a/crates/zed/src/languages/go.rs +++ b/crates/zed/src/languages/go.rs @@ -5,12 +5,15 @@ 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::Arc, +}; +use util::{fs::remove_matching, github::latest_github_release, ResultExt}; fn server_binary_arguments() -> Vec { vec!["-mode=stdio".into()] @@ -31,9 +34,9 @@ impl super::LspAdapter for GoLspAdapter { async fn fetch_latest_server_version( &self, - http: Arc, + delegate: &dyn LspAdapterDelegate, ) -> Result> { - 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 = release.name.strip_prefix("gopls/v").map(str::to_string); if version.is_none() { log::warn!( @@ -47,8 +50,8 @@ impl super::LspAdapter for GoLspAdapter { async fn fetch_server_binary( &self, version: Box, - _: Arc, container_dir: PathBuf, + delegate: &dyn LspAdapterDelegate, ) -> Result { let version = version.downcast::>().unwrap(); let this = *self; @@ -68,7 +71,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 +111,11 @@ impl super::LspAdapter for GoLspAdapter { }) } - async fn cached_server_binary(&self, container_dir: PathBuf) -> Option { + async fn cached_server_binary( + &self, + container_dir: PathBuf, + _: &dyn LspAdapterDelegate, + ) -> Option { (|| async move { let mut last_binary_path = None; let mut entries = fs::read_dir(&container_dir).await?; diff --git a/crates/zed/src/languages/html.rs b/crates/zed/src/languages/html.rs index 68f780c3af..d038ef8071 100644 --- a/crates/zed/src/languages/html.rs +++ b/crates/zed/src/languages/html.rs @@ -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 { @@ -36,7 +38,7 @@ impl LspAdapter for HtmlLspAdapter { async fn fetch_latest_server_version( &self, - _: Arc, + _: &dyn LspAdapterDelegate, ) -> Result> { Ok(Box::new( self.node @@ -48,8 +50,8 @@ impl LspAdapter for HtmlLspAdapter { async fn fetch_server_binary( &self, version: Box, - _: Arc, container_dir: PathBuf, + _: &dyn LspAdapterDelegate, ) -> Result { let version = version.downcast::().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 { + async fn cached_server_binary( + &self, + container_dir: PathBuf, + _: &dyn LspAdapterDelegate, + ) -> Option { (|| async move { let mut last_version_dir = None; let mut entries = fs::read_dir(&container_dir).await?; diff --git a/crates/zed/src/languages/json.rs b/crates/zed/src/languages/json.rs index e1f3da9e02..ced733fa1b 100644 --- a/crates/zed/src/languages/json.rs +++ b/crates/zed/src/languages/json.rs @@ -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 LspAdapterDelegate, ) -> Result> { Ok(Box::new( self.node @@ -57,8 +58,8 @@ impl LspAdapter for JsonLspAdapter { async fn fetch_server_binary( &self, version: Box, - _: Arc, container_dir: PathBuf, + _: &dyn LspAdapterDelegate, ) -> Result { let version = version.downcast::().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 { + async fn cached_server_binary( + &self, + container_dir: PathBuf, + _: &dyn LspAdapterDelegate, + ) -> Option { (|| async move { let mut last_version_dir = None; let mut entries = fs::read_dir(&container_dir).await?; diff --git a/crates/zed/src/languages/lua.rs b/crates/zed/src/languages/lua.rs index f204eb2555..7f63a1fae2 100644 --- a/crates/zed/src/languages/lua.rs +++ b/crates/zed/src/languages/lua.rs @@ -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, + delegate: &dyn LspAdapterDelegate, ) -> Result> { - 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, - http: Arc, container_dir: PathBuf, + delegate: &dyn LspAdapterDelegate, ) -> Result { let version = version.downcast::().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 { + async fn cached_server_binary( + &self, + container_dir: PathBuf, + _: &dyn LspAdapterDelegate, + ) -> Option { async_iife!({ let mut last_binary_path = None; let mut entries = fs::read_dir(&container_dir).await?; diff --git a/crates/zed/src/languages/python.rs b/crates/zed/src/languages/python.rs index 7aaddf5fe8..b56a0d6175 100644 --- a/crates/zed/src/languages/python.rs +++ b/crates/zed/src/languages/python.rs @@ -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 { @@ -37,7 +36,7 @@ impl LspAdapter for PythonLspAdapter { async fn fetch_latest_server_version( &self, - _: Arc, + _: &dyn LspAdapterDelegate, ) -> Result> { 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, - _: Arc, container_dir: PathBuf, + _: &dyn LspAdapterDelegate, ) -> Result { let version = version.downcast::().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 { + async fn cached_server_binary( + &self, + container_dir: PathBuf, + _: &dyn LspAdapterDelegate, + ) -> Option { (|| async move { let mut last_version_dir = None; let mut entries = fs::read_dir(&container_dir).await?; diff --git a/crates/zed/src/languages/ruby.rs b/crates/zed/src/languages/ruby.rs index d387f815f0..18756e3b77 100644 --- a/crates/zed/src/languages/ruby.rs +++ b/crates/zed/src/languages/ruby.rs @@ -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 LspAdapterDelegate, ) -> Result> { Ok(Box::new(())) } @@ -22,13 +21,17 @@ impl LspAdapter for RubyLanguageServer { async fn fetch_server_binary( &self, _version: Box, - _: Arc, _container_dir: PathBuf, + _: &dyn LspAdapterDelegate, ) -> Result { Err(anyhow!("solargraph must be installed manually")) } - async fn cached_server_binary(&self, _container_dir: PathBuf) -> Option { + async fn cached_server_binary( + &self, + _: PathBuf, + _: &dyn LspAdapterDelegate, + ) -> Option { Some(LanguageServerBinary { path: "solargraph".into(), arguments: vec!["stdio".into()], diff --git a/crates/zed/src/languages/rust.rs b/crates/zed/src/languages/rust.rs index 15700ec80a..e60846b70a 100644 --- a/crates/zed/src/languages/rust.rs +++ b/crates/zed/src/languages/rust.rs @@ -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, + delegate: &dyn LspAdapterDelegate, ) -> Result> { - 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, - http: Arc, container_dir: PathBuf, + delegate: &dyn LspAdapterDelegate, ) -> Result { let version = version.downcast::().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 { + async fn cached_server_binary( + &self, + container_dir: PathBuf, + _: &dyn LspAdapterDelegate, + ) -> Option { (|| async move { let mut last = None; let mut entries = fs::read_dir(&container_dir).await?; diff --git a/crates/zed/src/languages/typescript.rs b/crates/zed/src/languages/typescript.rs index 7d2d580857..662e73ea33 100644 --- a/crates/zed/src/languages/typescript.rs +++ b/crates/zed/src/languages/typescript.rs @@ -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 { @@ -58,7 +58,7 @@ impl LspAdapter for TypeScriptLspAdapter { async fn fetch_latest_server_version( &self, - _: Arc, + _: &dyn LspAdapterDelegate, ) -> Result> { 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, - _: Arc, container_dir: PathBuf, + _: &dyn LspAdapterDelegate, ) -> Result { let version = version.downcast::().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 { + async fn cached_server_binary( + &self, + container_dir: PathBuf, + _: &dyn LspAdapterDelegate, + ) -> Option { (|| 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, + delegate: &dyn LspAdapterDelegate, ) -> Result> { // 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, - http: Arc, container_dir: PathBuf, + delegate: &dyn LspAdapterDelegate, ) -> Result { let version = version.downcast::().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 { + async fn cached_server_binary( + &self, + container_dir: PathBuf, + _: &dyn LspAdapterDelegate, + ) -> Option { (|| 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?; diff --git a/crates/zed/src/languages/yaml.rs b/crates/zed/src/languages/yaml.rs index 7f87a7caed..99c226bba7 100644 --- a/crates/zed/src/languages/yaml.rs +++ b/crates/zed/src/languages/yaml.rs @@ -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 { @@ -42,7 +42,7 @@ impl LspAdapter for YamlLspAdapter { async fn fetch_latest_server_version( &self, - _: Arc, + _: &dyn LspAdapterDelegate, ) -> Result> { Ok(Box::new( self.node @@ -54,8 +54,8 @@ impl LspAdapter for YamlLspAdapter { async fn fetch_server_binary( &self, version: Box, - _: Arc, container_dir: PathBuf, + _: &dyn LspAdapterDelegate, ) -> Result { let version = version.downcast::().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 { + async fn cached_server_binary( + &self, + container_dir: PathBuf, + _: &dyn LspAdapterDelegate, + ) -> Option { (|| async move { let mut last_version_dir = None; let mut entries = fs::read_dir(&container_dir).await?;