diff --git a/crates/language/src/language.rs b/crates/language/src/language.rs index c62bbbb146..24fe2cb7ba 100644 --- a/crates/language/src/language.rs +++ b/crates/language/src/language.rs @@ -83,12 +83,17 @@ pub enum ServerExecutionKind { Node, } +#[derive(Debug, Clone, Deserialize)] +pub struct LanguageServerBinary { + pub path: PathBuf, + pub arguments: Vec, +} + /// Represents a Language Server, with certain cached sync properties. /// Uses [`LspAdapter`] under the hood, but calls all 'static' methods /// once at startup, and caches the results. pub struct CachedLspAdapter { pub name: LanguageServerName, - pub server_args: Vec, pub initialization_options: Option, pub disk_based_diagnostic_sources: Vec, pub disk_based_diagnostics_progress_token: Option, @@ -99,7 +104,6 @@ pub struct CachedLspAdapter { impl CachedLspAdapter { pub async fn new(adapter: Arc) -> Arc { let name = adapter.name().await; - let server_args = adapter.server_args().await; let initialization_options = adapter.initialization_options().await; let disk_based_diagnostic_sources = adapter.disk_based_diagnostic_sources().await; let disk_based_diagnostics_progress_token = @@ -108,7 +112,6 @@ impl CachedLspAdapter { Arc::new(CachedLspAdapter { name, - server_args, initialization_options, disk_based_diagnostic_sources, disk_based_diagnostics_progress_token, @@ -129,13 +132,16 @@ impl CachedLspAdapter { version: Box, http: Arc, container_dir: PathBuf, - ) -> Result { + ) -> Result { self.adapter .fetch_server_binary(version, http, container_dir) .await } - pub async fn cached_server_binary(&self, container_dir: PathBuf) -> Option { + pub async fn cached_server_binary( + &self, + container_dir: PathBuf, + ) -> Option { self.adapter.cached_server_binary(container_dir).await } @@ -190,9 +196,9 @@ pub trait LspAdapter: 'static + Send + Sync { version: Box, http: Arc, container_dir: PathBuf, - ) -> Result; + ) -> Result; - async fn cached_server_binary(&self, container_dir: PathBuf) -> Option; + async fn cached_server_binary(&self, container_dir: PathBuf) -> Option; async fn process_diagnostics(&self, _: &mut lsp::PublishDiagnosticsParams) {} @@ -215,10 +221,6 @@ pub trait LspAdapter: 'static + Send + Sync { None } - async fn server_args(&self) -> Vec { - Vec::new() - } - async fn initialization_options(&self) -> Option { None } @@ -497,7 +499,7 @@ pub struct LanguageRegistry { lsp_binary_paths: Mutex< HashMap< LanguageServerName, - Shared>>>, + Shared>>>, >, >, executor: Option>, @@ -810,12 +812,12 @@ impl LanguageRegistry { login_shell_env_loaded.await; let node_path = node_path.await; - let server_binary_path = this + let server_binary = this .lsp_binary_paths .lock() .entry(adapter.name.clone()) .or_insert_with(|| { - get_server_binary_path( + get_server_binary( adapter.clone(), language.clone(), http_client, @@ -829,8 +831,9 @@ impl LanguageRegistry { .clone() .map_err(|e| anyhow!(e)); - let server_binary_path = server_binary_path.await?; - let server_name = server_binary_path + let server_binary = server_binary.await?; + let server_name = server_binary + .path .file_name() .map(|name| name.to_string_lossy().to_string()); @@ -839,16 +842,15 @@ impl LanguageRegistry { let node_path = node_path .ok_or(anyhow!("Missing Node path for Node based language server"))?; let node_binary = node_path.join("bin/node"); - dbg!(&node_binary); let mut command = smol::process::Command::new(node_binary); - command.arg(dbg!(server_binary_path)); + command.arg(dbg!(server_binary.path)); command } - ServerExecutionKind::Launch => smol::process::Command::new(server_binary_path), + ServerExecutionKind::Launch => smol::process::Command::new(server_binary.path), }; - command.args(&adapter.server_args); + command.args(dbg!(&server_binary.arguments)); let server = lsp::LanguageServer::new(server_id, server_name, command, &root_path, cx)?; Ok(server) @@ -880,13 +882,13 @@ impl Default for LanguageRegistry { } } -async fn get_server_binary_path( +async fn get_server_binary( adapter: Arc, language: Arc, http_client: Arc, download_dir: Arc, statuses: async_broadcast::Sender<(Arc, LanguageServerBinaryStatus)>, -) -> Result { +) -> Result { let container_dir = download_dir.join(adapter.name.0.as_ref()); if !container_dir.exists() { smol::fs::create_dir_all(&container_dir) @@ -894,7 +896,7 @@ async fn get_server_binary_path( .context("failed to create container directory")?; } - let path = fetch_latest_server_binary_path( + let binary = fetch_latest_server_binary( adapter.clone(), language.clone(), http_client, @@ -902,12 +904,12 @@ async fn get_server_binary_path( statuses.clone(), ) .await; - if let Err(error) = path.as_ref() { - if let Some(cached_path) = adapter.cached_server_binary(container_dir).await { + if let Err(error) = binary.as_ref() { + if let Some(cached) = adapter.cached_server_binary(container_dir).await { statuses .broadcast((language.clone(), LanguageServerBinaryStatus::Cached)) .await?; - return Ok(cached_path); + return Ok(cached); } else { statuses .broadcast(( @@ -919,16 +921,16 @@ async fn get_server_binary_path( .await?; } } - path + binary } -async fn fetch_latest_server_binary_path( +async fn fetch_latest_server_binary( adapter: Arc, language: Arc, http_client: Arc, container_dir: &Path, lsp_binary_statuses_tx: async_broadcast::Sender<(Arc, LanguageServerBinaryStatus)>, -) -> Result { +) -> Result { let container_dir: Arc = container_dir.into(); lsp_binary_statuses_tx .broadcast(( @@ -942,13 +944,13 @@ async fn fetch_latest_server_binary_path( lsp_binary_statuses_tx .broadcast((language.clone(), LanguageServerBinaryStatus::Downloading)) .await?; - let path = adapter + let binary = adapter .fetch_server_binary(version_info, http_client, container_dir.to_path_buf()) .await?; lsp_binary_statuses_tx .broadcast((language.clone(), LanguageServerBinaryStatus::Downloaded)) .await?; - Ok(path) + Ok(binary) } impl Language { @@ -1485,11 +1487,11 @@ impl LspAdapter for Arc { _: Box, _: Arc, _: PathBuf, - ) -> Result { + ) -> Result { unreachable!(); } - async fn cached_server_binary(&self, _: PathBuf) -> Option { + async fn cached_server_binary(&self, _: PathBuf) -> Option { unreachable!(); } diff --git a/crates/zed/src/languages/c.rs b/crates/zed/src/languages/c.rs index 826de55874..afd94604d9 100644 --- a/crates/zed/src/languages/c.rs +++ b/crates/zed/src/languages/c.rs @@ -43,7 +43,7 @@ impl super::LspAdapter for CLspAdapter { version: Box, http: Arc, container_dir: PathBuf, - ) -> Result { + ) -> Result { let version = version.downcast::().unwrap(); let zip_path = container_dir.join(format!("clangd_{}.zip", version.name)); let version_dir = container_dir.join(format!("clangd_{}", version.name)); @@ -85,10 +85,13 @@ impl super::LspAdapter for CLspAdapter { } } - Ok(binary_path) + Ok(LanguageServerBinary { + path: binary_path, + arguments: vec![], + }) } - async fn cached_server_binary(&self, container_dir: PathBuf) -> Option { + async fn cached_server_binary(&self, container_dir: PathBuf) -> Option { (|| async move { let mut last_clangd_dir = None; let mut entries = fs::read_dir(&container_dir).await?; @@ -101,7 +104,10 @@ impl super::LspAdapter for CLspAdapter { let clangd_dir = last_clangd_dir.ok_or_else(|| anyhow!("no cached binary"))?; let clangd_bin = clangd_dir.join("bin/clangd"); if clangd_bin.exists() { - Ok(clangd_bin) + Ok(LanguageServerBinary { + path: clangd_bin, + arguments: vec![], + }) } else { Err(anyhow!( "missing clangd binary in directory {:?}", diff --git a/crates/zed/src/languages/elixir.rs b/crates/zed/src/languages/elixir.rs index 0bdbaddd68..390a35fa3d 100644 --- a/crates/zed/src/languages/elixir.rs +++ b/crates/zed/src/languages/elixir.rs @@ -44,7 +44,7 @@ impl LspAdapter for ElixirLspAdapter { version: Box, http: Arc, container_dir: PathBuf, - ) -> Result { + ) -> Result { let version = version.downcast::().unwrap(); let zip_path = container_dir.join(format!("elixir-ls_{}.zip", version.name)); let version_dir = container_dir.join(format!("elixir-ls_{}", version.name)); @@ -98,17 +98,24 @@ impl LspAdapter for ElixirLspAdapter { } } - Ok(binary_path) + Ok(LanguageServerBinary { + path: binary_path, + arguments: vec![], + }) } - async fn cached_server_binary(&self, container_dir: PathBuf) -> Option { + async fn cached_server_binary(&self, container_dir: PathBuf) -> Option { (|| async move { let mut last = None; let mut entries = fs::read_dir(&container_dir).await?; while let Some(entry) = entries.next().await { last = Some(entry?.path()); } - last.ok_or_else(|| anyhow!("no cached binary")) + last.map(|path| LanguageServerBinary { + path, + arguments: vec![], + }) + .ok_or_else(|| anyhow!("no cached binary")) })() .await .log_err() diff --git a/crates/zed/src/languages/go.rs b/crates/zed/src/languages/go.rs index 4e34b126a1..f51c57ab8c 100644 --- a/crates/zed/src/languages/go.rs +++ b/crates/zed/src/languages/go.rs @@ -10,6 +10,10 @@ use smol::{fs, process}; use std::{any::Any, ops::Range, path::PathBuf, str, sync::Arc}; use util::ResultExt; +fn server_binary_arguments() -> Vec { + vec!["-mode=stdio".into()] +} + #[derive(Copy, Clone)] pub struct GoLspAdapter; @@ -27,10 +31,6 @@ impl super::LspAdapter for GoLspAdapter { ServerExecutionKind::Launch } - async fn server_args(&self) -> Vec { - vec!["-mode=stdio".into()] - } - async fn fetch_latest_server_version( &self, http: Arc, @@ -51,7 +51,7 @@ impl super::LspAdapter for GoLspAdapter { version: Box, _: Arc, container_dir: PathBuf, - ) -> Result { + ) -> Result { let version = version.downcast::>().unwrap(); let this = *self; @@ -72,7 +72,10 @@ impl super::LspAdapter for GoLspAdapter { } } - return Ok(binary_path.to_path_buf()); + return Ok(LanguageServerBinary { + path: binary_path.to_path_buf(), + arguments: server_binary_arguments(), + }); } } } else if let Some(path) = this.cached_server_binary(container_dir.clone()).await { @@ -106,10 +109,13 @@ impl super::LspAdapter for GoLspAdapter { let binary_path = container_dir.join(&format!("gopls_{version}")); fs::rename(&installed_binary_path, &binary_path).await?; - Ok(binary_path.to_path_buf()) + Ok(LanguageServerBinary { + path: binary_path.to_path_buf(), + arguments: server_binary_arguments(), + }) } - async fn cached_server_binary(&self, container_dir: PathBuf) -> Option { + async fn cached_server_binary(&self, container_dir: PathBuf) -> Option { (|| async move { let mut last_binary_path = None; let mut entries = fs::read_dir(&container_dir).await?; @@ -126,7 +132,10 @@ impl super::LspAdapter for GoLspAdapter { } if let Some(path) = last_binary_path { - Ok(path) + Ok(LanguageServerBinary { + path, + arguments: server_binary_arguments(), + }) } else { Err(anyhow!("no cached binary")) } diff --git a/crates/zed/src/languages/html.rs b/crates/zed/src/languages/html.rs index f7ade20dfb..8c0f8e026d 100644 --- a/crates/zed/src/languages/html.rs +++ b/crates/zed/src/languages/html.rs @@ -3,12 +3,16 @@ use anyhow::{anyhow, Context, Result}; use async_trait::async_trait; use client::http::HttpClient; use futures::StreamExt; -use language::{LanguageServerName, LspAdapter, ServerExecutionKind}; +use language::{LanguageServerBinary, LanguageServerName, LspAdapter, ServerExecutionKind}; use serde_json::json; use smol::fs; use std::{any::Any, path::PathBuf, sync::Arc}; use util::ResultExt; +fn server_binary_arguments() -> Vec { + vec!["--stdio".into()] +} + pub struct HtmlLspAdapter; impl HtmlLspAdapter { @@ -26,10 +30,6 @@ impl LspAdapter for HtmlLspAdapter { ServerExecutionKind::Node } - async fn server_args(&self) -> Vec { - vec!["--stdio".into()] - } - async fn fetch_latest_server_version( &self, http: Arc, @@ -45,7 +45,7 @@ impl LspAdapter for HtmlLspAdapter { version: Box, http: Arc, container_dir: PathBuf, - ) -> Result { + ) -> Result { let version = version.downcast::().unwrap(); let version_dir = container_dir.join(version.as_str()); fs::create_dir_all(&version_dir) @@ -73,10 +73,13 @@ impl LspAdapter for HtmlLspAdapter { } } - Ok(binary_path) + Ok(LanguageServerBinary { + path: binary_path, + arguments: server_binary_arguments(), + }) } - async fn cached_server_binary(&self, container_dir: PathBuf) -> Option { + async fn cached_server_binary(&self, container_dir: PathBuf) -> Option { (|| async move { let mut last_version_dir = None; let mut entries = fs::read_dir(&container_dir).await?; @@ -89,7 +92,10 @@ impl LspAdapter for HtmlLspAdapter { let last_version_dir = last_version_dir.ok_or_else(|| anyhow!("no cached binary"))?; let bin_path = last_version_dir.join(Self::BIN_PATH); if bin_path.exists() { - Ok(bin_path) + Ok(LanguageServerBinary { + path: bin_path, + arguments: server_binary_arguments(), + }) } else { Err(anyhow!( "missing executable in directory {:?}", diff --git a/crates/zed/src/languages/installation.rs b/crates/zed/src/languages/installation.rs index 852b8f0de0..0eb6e0b760 100644 --- a/crates/zed/src/languages/installation.rs +++ b/crates/zed/src/languages/installation.rs @@ -48,8 +48,8 @@ pub async fn ensure_node_installation_dir(http: Arc) -> Result

) -> Result

) -> Result

, name: &str) -> Result { diff --git a/crates/zed/src/languages/json.rs b/crates/zed/src/languages/json.rs index 9df5bec6c0..7c07165b2b 100644 --- a/crates/zed/src/languages/json.rs +++ b/crates/zed/src/languages/json.rs @@ -6,7 +6,9 @@ use client::http::HttpClient; use collections::HashMap; use futures::{future::BoxFuture, io::BufReader, FutureExt, StreamExt}; use gpui::MutableAppContext; -use language::{LanguageRegistry, LanguageServerName, LspAdapter, ServerExecutionKind}; +use language::{ + LanguageRegistry, LanguageServerBinary, LanguageServerName, LspAdapter, ServerExecutionKind, +}; use serde_json::json; use settings::{keymap_file_json_schema, settings_file_json_schema}; use smol::fs::{self, File}; @@ -20,6 +22,10 @@ use std::{ use theme::ThemeRegistry; use util::{paths, ResultExt, StaffMode}; +fn server_binary_arguments() -> Vec { + vec!["--stdio".into()] +} + pub struct JsonLspAdapter { languages: Arc, themes: Arc, @@ -41,10 +47,6 @@ impl LspAdapter for JsonLspAdapter { ServerExecutionKind::Node } - async fn server_args(&self) -> Vec { - vec!["--stdio".into()] - } - async fn fetch_latest_server_version( &self, http: Arc, @@ -68,7 +70,7 @@ impl LspAdapter for JsonLspAdapter { version: Box, http: Arc, container_dir: PathBuf, - ) -> Result { + ) -> Result { let version = version.downcast::().unwrap(); let destination_path = container_dir.join(format!( "json-language-server-{}-{}", @@ -102,17 +104,23 @@ impl LspAdapter for JsonLspAdapter { } } - Ok(destination_path) + Ok(LanguageServerBinary { + path: destination_path, + arguments: server_binary_arguments(), + }) } - async fn cached_server_binary(&self, container_dir: PathBuf) -> Option { + async fn cached_server_binary(&self, container_dir: PathBuf) -> Option { (|| async move { let mut last = None; let mut entries = fs::read_dir(&container_dir).await?; while let Some(entry) = entries.next().await { last = Some(entry?.path()); } - last.ok_or_else(|| anyhow!("no cached binary")) + anyhow::Ok(LanguageServerBinary { + path: last.ok_or_else(|| anyhow!("no cached binary"))?, + arguments: server_binary_arguments(), + }) })() .await .log_err() diff --git a/crates/zed/src/languages/language_plugin.rs b/crates/zed/src/languages/language_plugin.rs index de3cabcef8..9f12878990 100644 --- a/crates/zed/src/languages/language_plugin.rs +++ b/crates/zed/src/languages/language_plugin.rs @@ -4,7 +4,7 @@ use client::http::HttpClient; use collections::HashMap; use futures::lock::Mutex; use gpui::executor::Background; -use language::{LanguageServerName, LspAdapter, ServerExecutionKind}; +use language::{LanguageServerBinary, LanguageServerName, LspAdapter, ServerExecutionKind}; use plugin_runtime::{Plugin, PluginBinary, PluginBuilder, WasiFn}; use std::{any::Any, path::PathBuf, sync::Arc}; use util::ResultExt; @@ -33,10 +33,9 @@ pub async fn new_json(executor: Arc) -> Result { pub struct PluginLspAdapter { name: WasiFn<(), String>, server_execution_kind: WasiFn<(), ServerExecutionKind>, - server_args: WasiFn<(), Vec>, fetch_latest_server_version: WasiFn<(), Option>, - fetch_server_binary: WasiFn<(PathBuf, String), Result>, - cached_server_binary: WasiFn>, + fetch_server_binary: WasiFn<(PathBuf, String), Result>, + cached_server_binary: WasiFn>, initialization_options: WasiFn<(), String>, language_ids: WasiFn<(), Vec<(String, String)>>, executor: Arc, @@ -49,7 +48,6 @@ impl PluginLspAdapter { Ok(Self { name: plugin.function("name")?, server_execution_kind: plugin.function("server_execution_kind")?, - server_args: plugin.function("server_args")?, fetch_latest_server_version: plugin.function("fetch_latest_server_version")?, fetch_server_binary: plugin.function("fetch_server_binary")?, cached_server_binary: plugin.function("cached_server_binary")?, @@ -83,15 +81,6 @@ impl LspAdapter for PluginLspAdapter { .unwrap() } - async fn server_args<'a>(&'a self) -> Vec { - self.runtime - .lock() - .await - .call(&self.server_args, ()) - .await - .unwrap() - } - async fn fetch_latest_server_version( &self, _: Arc, @@ -116,7 +105,7 @@ impl LspAdapter for PluginLspAdapter { version: Box, _: Arc, container_dir: PathBuf, - ) -> Result { + ) -> Result { let version = *version.downcast::().unwrap(); let runtime = self.runtime.clone(); let function = self.fetch_server_binary; @@ -124,7 +113,7 @@ impl LspAdapter for PluginLspAdapter { .spawn(async move { let mut runtime = runtime.lock().await; let handle = runtime.attach_path(&container_dir)?; - let result: Result = + let result: Result = runtime.call(&function, (container_dir, version)).await?; runtime.remove_resource(handle)?; result.map_err(|e| anyhow!("{}", e)) @@ -132,7 +121,7 @@ impl LspAdapter for PluginLspAdapter { .await } - async fn cached_server_binary(&self, container_dir: PathBuf) -> Option { + async fn cached_server_binary(&self, container_dir: PathBuf) -> Option { let runtime = self.runtime.clone(); let function = self.cached_server_binary; @@ -140,7 +129,8 @@ impl LspAdapter for PluginLspAdapter { .spawn(async move { let mut runtime = runtime.lock().await; let handle = runtime.attach_path(&container_dir).ok()?; - let result: Option = runtime.call(&function, container_dir).await.ok()?; + let result: Option = + runtime.call(&function, container_dir).await.ok()?; runtime.remove_resource(handle).ok()?; result }) diff --git a/crates/zed/src/languages/lua.rs b/crates/zed/src/languages/lua.rs index c51235e1f1..2ee67016dd 100644 --- a/crates/zed/src/languages/lua.rs +++ b/crates/zed/src/languages/lua.rs @@ -6,7 +6,7 @@ use async_tar::Archive; use async_trait::async_trait; use client::http::HttpClient; use futures::{io::BufReader, StreamExt}; -use language::{LanguageServerName, ServerExecutionKind}; +use language::{LanguageServerBinary, LanguageServerName, ServerExecutionKind}; use smol::fs; use util::{async_iife, ResultExt}; @@ -15,6 +15,13 @@ use super::installation::{latest_github_release, GitHubLspBinaryVersion}; #[derive(Copy, Clone)] pub struct LuaLspAdapter; +fn server_binary_arguments() -> Vec { + vec![ + "--logpath=~/lua-language-server.log".into(), + "--loglevel=trace".into(), + ] +} + #[async_trait] impl super::LspAdapter for LuaLspAdapter { async fn name(&self) -> LanguageServerName { @@ -25,13 +32,6 @@ impl super::LspAdapter for LuaLspAdapter { ServerExecutionKind::Launch } - async fn server_args(&self) -> Vec { - vec![ - "--logpath=~/lua-language-server.log".into(), - "--loglevel=trace".into(), - ] - } - async fn fetch_latest_server_version( &self, http: Arc, @@ -61,7 +61,7 @@ impl super::LspAdapter for LuaLspAdapter { version: Box, http: Arc, container_dir: PathBuf, - ) -> Result { + ) -> Result { let version = version.downcast::().unwrap(); let binary_path = container_dir.join("bin/lua-language-server"); @@ -81,10 +81,13 @@ impl super::LspAdapter for LuaLspAdapter { ::from_mode(0o755), ) .await?; - Ok(binary_path) + Ok(LanguageServerBinary { + path: binary_path, + arguments: server_binary_arguments(), + }) } - async fn cached_server_binary(&self, container_dir: PathBuf) -> Option { + async fn cached_server_binary(&self, container_dir: PathBuf) -> Option { async_iife!({ let mut last_binary_path = None; let mut entries = fs::read_dir(&container_dir).await?; @@ -101,7 +104,10 @@ impl super::LspAdapter for LuaLspAdapter { } if let Some(path) = last_binary_path { - Ok(path) + Ok(LanguageServerBinary { + path, + arguments: server_binary_arguments(), + }) } else { Err(anyhow!("no cached binary")) } diff --git a/crates/zed/src/languages/python.rs b/crates/zed/src/languages/python.rs index 4495b9e4d8..ece8f70362 100644 --- a/crates/zed/src/languages/python.rs +++ b/crates/zed/src/languages/python.rs @@ -3,13 +3,17 @@ use anyhow::{anyhow, Context, Result}; use async_trait::async_trait; use client::http::HttpClient; use futures::StreamExt; -use language::{LanguageServerName, LspAdapter, ServerExecutionKind}; +use language::{LanguageServerBinary, LanguageServerName, LspAdapter, ServerExecutionKind}; use smol::fs; use std::{any::Any, path::PathBuf, sync::Arc}; use util::ResultExt; pub struct PythonLspAdapter; +fn server_binary_arguments() -> Vec { + vec!["--stdio".into()] +} + impl PythonLspAdapter { const BIN_PATH: &'static str = "node_modules/pyright/langserver.index.js"; } @@ -24,10 +28,6 @@ impl LspAdapter for PythonLspAdapter { ServerExecutionKind::Node } - async fn server_args(&self) -> Vec { - vec!["--stdio".into()] - } - async fn fetch_latest_server_version( &self, http: Arc, @@ -40,7 +40,7 @@ impl LspAdapter for PythonLspAdapter { version: Box, http: Arc, container_dir: PathBuf, - ) -> Result { + ) -> Result { let version = version.downcast::().unwrap(); let version_dir = container_dir.join(version.as_str()); fs::create_dir_all(&version_dir) @@ -63,10 +63,13 @@ impl LspAdapter for PythonLspAdapter { } } - Ok(binary_path) + Ok(LanguageServerBinary { + path: binary_path, + arguments: server_binary_arguments(), + }) } - async fn cached_server_binary(&self, container_dir: PathBuf) -> Option { + async fn cached_server_binary(&self, container_dir: PathBuf) -> Option { (|| async move { let mut last_version_dir = None; let mut entries = fs::read_dir(&container_dir).await?; @@ -79,7 +82,10 @@ impl LspAdapter for PythonLspAdapter { let last_version_dir = last_version_dir.ok_or_else(|| anyhow!("no cached binary"))?; let bin_path = last_version_dir.join(Self::BIN_PATH); if bin_path.exists() { - Ok(bin_path) + Ok(LanguageServerBinary { + path: bin_path, + arguments: server_binary_arguments(), + }) } else { Err(anyhow!( "missing executable in directory {:?}", diff --git a/crates/zed/src/languages/ruby.rs b/crates/zed/src/languages/ruby.rs index 1308610a5a..f30a536746 100644 --- a/crates/zed/src/languages/ruby.rs +++ b/crates/zed/src/languages/ruby.rs @@ -1,7 +1,7 @@ use anyhow::{anyhow, Result}; use async_trait::async_trait; use client::http::HttpClient; -use language::{LanguageServerName, LspAdapter, ServerExecutionKind}; +use language::{LanguageServerBinary, LanguageServerName, LspAdapter, ServerExecutionKind}; use std::{any::Any, path::PathBuf, sync::Arc}; pub struct RubyLanguageServer; @@ -16,10 +16,6 @@ impl LspAdapter for RubyLanguageServer { ServerExecutionKind::Launch } - async fn server_args(&self) -> Vec { - vec!["stdio".into()] - } - async fn fetch_latest_server_version( &self, _: Arc, @@ -32,12 +28,15 @@ impl LspAdapter for RubyLanguageServer { _version: Box, _: Arc, _container_dir: PathBuf, - ) -> Result { + ) -> Result { Err(anyhow!("solargraph must be installed manually")) } - async fn cached_server_binary(&self, _container_dir: PathBuf) -> Option { - Some("solargraph".into()) + async fn cached_server_binary(&self, _container_dir: PathBuf) -> Option { + Some(LanguageServerBinary { + path: "solargraph".into(), + arguments: vec!["stdio".into()], + }) } async fn label_for_completion( diff --git a/crates/zed/src/languages/rust.rs b/crates/zed/src/languages/rust.rs index 1f9940ac0d..5eac0fca0a 100644 --- a/crates/zed/src/languages/rust.rs +++ b/crates/zed/src/languages/rust.rs @@ -46,7 +46,7 @@ impl LspAdapter for RustLspAdapter { version: Box, http: Arc, container_dir: PathBuf, - ) -> Result { + ) -> Result { let version = version.downcast::().unwrap(); let destination_path = container_dir.join(format!("rust-analyzer-{}", version.name)); @@ -76,17 +76,23 @@ impl LspAdapter for RustLspAdapter { } } - Ok(destination_path) + Ok(LanguageServerBinary { + path: destination_path, + arguments: Default::default(), + }) } - async fn cached_server_binary(&self, container_dir: PathBuf) -> Option { + async fn cached_server_binary(&self, container_dir: PathBuf) -> Option { (|| async move { let mut last = None; let mut entries = fs::read_dir(&container_dir).await?; while let Some(entry) = entries.next().await { last = Some(entry?.path()); } - last.ok_or_else(|| anyhow!("no cached binary")) + anyhow::Ok(LanguageServerBinary { + path: last.ok_or_else(|| anyhow!("no cached binary"))?, + arguments: Default::default(), + }) })() .await .log_err() diff --git a/crates/zed/src/languages/typescript.rs b/crates/zed/src/languages/typescript.rs index 7775da6067..316f5d7627 100644 --- a/crates/zed/src/languages/typescript.rs +++ b/crates/zed/src/languages/typescript.rs @@ -3,12 +3,19 @@ use anyhow::{anyhow, Context, Result}; use async_trait::async_trait; use client::http::HttpClient; use futures::StreamExt; -use language::{LanguageServerName, LspAdapter, ServerExecutionKind}; +use language::{LanguageServerBinary, LanguageServerName, LspAdapter, ServerExecutionKind}; use serde_json::json; use smol::fs; use std::{any::Any, path::PathBuf, sync::Arc}; use util::ResultExt; +fn server_binary_arguments() -> Vec { + ["--stdio", "--tsserver-path", "node_modules/typescript/lib"] + .into_iter() + .map(Into::into) + .collect() +} + pub struct TypeScriptLspAdapter; impl TypeScriptLspAdapter { @@ -31,13 +38,6 @@ impl LspAdapter for TypeScriptLspAdapter { ServerExecutionKind::Node } - async fn server_args(&self) -> Vec { - ["--stdio", "--tsserver-path", "node_modules/typescript/lib"] - .into_iter() - .map(str::to_string) - .collect() - } - async fn fetch_latest_server_version( &self, http: Arc, @@ -53,7 +53,7 @@ impl LspAdapter for TypeScriptLspAdapter { versions: Box, http: Arc, container_dir: PathBuf, - ) -> Result { + ) -> Result { let versions = versions.downcast::().unwrap(); let version_dir = container_dir.join(&format!( "typescript-{}:server-{}", @@ -90,10 +90,13 @@ impl LspAdapter for TypeScriptLspAdapter { } } - Ok(binary_path) + Ok(LanguageServerBinary { + path: binary_path, + arguments: server_binary_arguments(), + }) } - async fn cached_server_binary(&self, container_dir: PathBuf) -> Option { + async fn cached_server_binary(&self, container_dir: PathBuf) -> Option { (|| async move { let mut last_version_dir = None; let mut entries = fs::read_dir(&container_dir).await?; @@ -107,9 +110,15 @@ impl LspAdapter for TypeScriptLspAdapter { let old_bin_path = last_version_dir.join(Self::OLD_BIN_PATH); let new_bin_path = last_version_dir.join(Self::NEW_BIN_PATH); if new_bin_path.exists() { - Ok(new_bin_path) + Ok(LanguageServerBinary { + path: new_bin_path, + arguments: server_binary_arguments(), + }) } else if old_bin_path.exists() { - Ok(old_bin_path) + Ok(LanguageServerBinary { + path: old_bin_path, + arguments: server_binary_arguments(), + }) } else { Err(anyhow!( "missing executable in directory {:?}", diff --git a/crates/zed/src/languages/yaml.rs b/crates/zed/src/languages/yaml.rs index da03e6d5cf..a9b9fbe1ef 100644 --- a/crates/zed/src/languages/yaml.rs +++ b/crates/zed/src/languages/yaml.rs @@ -3,7 +3,7 @@ use async_trait::async_trait; use client::http::HttpClient; use futures::{future::BoxFuture, FutureExt, StreamExt}; use gpui::MutableAppContext; -use language::{LanguageServerName, LspAdapter, ServerExecutionKind}; +use language::{LanguageServerBinary, LanguageServerName, LspAdapter, ServerExecutionKind}; use serde_json::Value; use settings::Settings; use smol::fs; @@ -12,6 +12,10 @@ use util::ResultExt; use super::installation::{npm_install_packages, npm_package_latest_version}; +fn server_binary_arguments() -> Vec { + vec!["--stdio".into()] +} + pub struct YamlLspAdapter; impl YamlLspAdapter { @@ -28,10 +32,6 @@ impl LspAdapter for YamlLspAdapter { ServerExecutionKind::Node } - async fn server_args(&self) -> Vec { - vec!["--stdio".into()] - } - async fn fetch_latest_server_version( &self, http: Arc, @@ -44,7 +44,7 @@ impl LspAdapter for YamlLspAdapter { version: Box, http: Arc, container_dir: PathBuf, - ) -> Result { + ) -> Result { let version = version.downcast::().unwrap(); let version_dir = container_dir.join(version.as_str()); fs::create_dir_all(&version_dir) @@ -72,10 +72,13 @@ impl LspAdapter for YamlLspAdapter { } } - Ok(binary_path) + Ok(LanguageServerBinary { + path: binary_path, + arguments: server_binary_arguments(), + }) } - async fn cached_server_binary(&self, container_dir: PathBuf) -> Option { + async fn cached_server_binary(&self, container_dir: PathBuf) -> Option { (|| async move { let mut last_version_dir = None; let mut entries = fs::read_dir(&container_dir).await?; @@ -88,7 +91,10 @@ impl LspAdapter for YamlLspAdapter { let last_version_dir = last_version_dir.ok_or_else(|| anyhow!("no cached binary"))?; let bin_path = last_version_dir.join(Self::BIN_PATH); if bin_path.exists() { - Ok(bin_path) + Ok(LanguageServerBinary { + path: bin_path, + arguments: server_binary_arguments(), + }) } else { Err(anyhow!( "missing executable in directory {:?}",