Show a notification when a dependency for a language server is missing (#2630)
Closes https://linear.app/zed-industries/issue/Z-2402/elixir-ls-requires-a-system-elixir-runtime-to-be-installed Closes https://linear.app/zed-industries/issue/Z-666/notify-users-that-they-need-go-installed-to-use-go-language-server Release Notes: - Added a notification when unable to download the Go language server because Go is not installed. - Added a notification when unable to run the Elixir language server because Elixir is not installed.
This commit is contained in:
@@ -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?;
|
||||
|
||||
Reference in New Issue
Block a user