Remove server_args from LspAdapter

Prepare to remove concept of a runtime from greater server startup code,
which is important for future language server extensibility

Co-Authored-By: Antonio Scandurra <me@as-cii.com>
This commit is contained in:
Julia 2023-03-24 10:40:50 -04:00
parent ed442cfc8c
commit 1a2e509e35
14 changed files with 204 additions and 146 deletions

View File

@ -83,12 +83,17 @@ pub enum ServerExecutionKind {
Node,
}
#[derive(Debug, Clone, Deserialize)]
pub struct LanguageServerBinary {
pub path: PathBuf,
pub arguments: Vec<String>,
}
/// 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<String>,
pub initialization_options: Option<Value>,
pub disk_based_diagnostic_sources: Vec<String>,
pub disk_based_diagnostics_progress_token: Option<String>,
@ -99,7 +104,6 @@ pub struct CachedLspAdapter {
impl CachedLspAdapter {
pub async fn new(adapter: Arc<dyn LspAdapter>) -> Arc<Self> {
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<dyn 'static + Send + Any>,
http: Arc<dyn HttpClient>,
container_dir: PathBuf,
) -> Result<PathBuf> {
) -> Result<LanguageServerBinary> {
self.adapter
.fetch_server_binary(version, http, container_dir)
.await
}
pub async fn cached_server_binary(&self, container_dir: PathBuf) -> Option<PathBuf> {
pub async fn cached_server_binary(
&self,
container_dir: PathBuf,
) -> Option<LanguageServerBinary> {
self.adapter.cached_server_binary(container_dir).await
}
@ -190,9 +196,9 @@ pub trait LspAdapter: 'static + Send + Sync {
version: Box<dyn 'static + Send + Any>,
http: Arc<dyn HttpClient>,
container_dir: PathBuf,
) -> Result<PathBuf>;
) -> Result<LanguageServerBinary>;
async fn cached_server_binary(&self, container_dir: PathBuf) -> Option<PathBuf>;
async fn cached_server_binary(&self, container_dir: PathBuf) -> Option<LanguageServerBinary>;
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<String> {
Vec::new()
}
async fn initialization_options(&self) -> Option<Value> {
None
}
@ -497,7 +499,7 @@ pub struct LanguageRegistry {
lsp_binary_paths: Mutex<
HashMap<
LanguageServerName,
Shared<BoxFuture<'static, Result<PathBuf, Arc<anyhow::Error>>>>,
Shared<BoxFuture<'static, Result<LanguageServerBinary, Arc<anyhow::Error>>>>,
>,
>,
executor: Option<Arc<Background>>,
@ -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<CachedLspAdapter>,
language: Arc<Language>,
http_client: Arc<dyn HttpClient>,
download_dir: Arc<Path>,
statuses: async_broadcast::Sender<(Arc<Language>, LanguageServerBinaryStatus)>,
) -> Result<PathBuf> {
) -> Result<LanguageServerBinary> {
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<CachedLspAdapter>,
language: Arc<Language>,
http_client: Arc<dyn HttpClient>,
container_dir: &Path,
lsp_binary_statuses_tx: async_broadcast::Sender<(Arc<Language>, LanguageServerBinaryStatus)>,
) -> Result<PathBuf> {
) -> Result<LanguageServerBinary> {
let container_dir: Arc<Path> = 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<FakeLspAdapter> {
_: Box<dyn 'static + Send + Any>,
_: Arc<dyn HttpClient>,
_: PathBuf,
) -> Result<PathBuf> {
) -> Result<LanguageServerBinary> {
unreachable!();
}
async fn cached_server_binary(&self, _: PathBuf) -> Option<PathBuf> {
async fn cached_server_binary(&self, _: PathBuf) -> Option<LanguageServerBinary> {
unreachable!();
}

View File

@ -43,7 +43,7 @@ impl super::LspAdapter for CLspAdapter {
version: Box<dyn 'static + Send + Any>,
http: Arc<dyn HttpClient>,
container_dir: PathBuf,
) -> Result<PathBuf> {
) -> Result<LanguageServerBinary> {
let version = version.downcast::<GitHubLspBinaryVersion>().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<PathBuf> {
async fn cached_server_binary(&self, container_dir: PathBuf) -> Option<LanguageServerBinary> {
(|| 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 {:?}",

View File

@ -44,7 +44,7 @@ impl LspAdapter for ElixirLspAdapter {
version: Box<dyn 'static + Send + Any>,
http: Arc<dyn HttpClient>,
container_dir: PathBuf,
) -> Result<PathBuf> {
) -> Result<LanguageServerBinary> {
let version = version.downcast::<GitHubLspBinaryVersion>().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<PathBuf> {
async fn cached_server_binary(&self, container_dir: PathBuf) -> Option<LanguageServerBinary> {
(|| 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()

View File

@ -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<String> {
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<String> {
vec!["-mode=stdio".into()]
}
async fn fetch_latest_server_version(
&self,
http: Arc<dyn HttpClient>,
@ -51,7 +51,7 @@ impl super::LspAdapter for GoLspAdapter {
version: Box<dyn 'static + Send + Any>,
_: Arc<dyn HttpClient>,
container_dir: PathBuf,
) -> Result<PathBuf> {
) -> Result<LanguageServerBinary> {
let version = version.downcast::<Option<String>>().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<PathBuf> {
async fn cached_server_binary(&self, container_dir: PathBuf) -> Option<LanguageServerBinary> {
(|| 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"))
}

View File

@ -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<String> {
vec!["--stdio".into()]
}
pub struct HtmlLspAdapter;
impl HtmlLspAdapter {
@ -26,10 +30,6 @@ impl LspAdapter for HtmlLspAdapter {
ServerExecutionKind::Node
}
async fn server_args(&self) -> Vec<String> {
vec!["--stdio".into()]
}
async fn fetch_latest_server_version(
&self,
http: Arc<dyn HttpClient>,
@ -45,7 +45,7 @@ impl LspAdapter for HtmlLspAdapter {
version: Box<dyn 'static + Send + Any>,
http: Arc<dyn HttpClient>,
container_dir: PathBuf,
) -> Result<PathBuf> {
) -> Result<LanguageServerBinary> {
let version = version.downcast::<String>().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<PathBuf> {
async fn cached_server_binary(&self, container_dir: PathBuf) -> Option<LanguageServerBinary> {
(|| 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 {:?}",

View File

@ -48,8 +48,8 @@ pub async fn ensure_node_installation_dir(http: Arc<dyn HttpClient>) -> Result<P
let arch = "arm64";
let folder_name = format!("node-{version}-darwin-{arch}");
let node_containing_dir = dbg!(util::paths::SUPPORT_DIR.join("node"));
let node_dir = dbg!(node_containing_dir.join(folder_name));
let node_containing_dir = util::paths::SUPPORT_DIR.join("node");
let node_dir = node_containing_dir.join(folder_name);
let node_binary = node_dir.join("bin/node");
if fs::metadata(&node_binary).await.is_err() {
@ -59,7 +59,6 @@ pub async fn ensure_node_installation_dir(http: Arc<dyn HttpClient>) -> Result<P
.context("error creating node containing dir")?;
let url = format!("https://nodejs.org/dist/{version}/node-{version}-darwin-{arch}.tar.gz");
dbg!(&url);
let mut response = http
.get(&url, Default::default(), true)
.await
@ -71,8 +70,7 @@ pub async fn ensure_node_installation_dir(http: Arc<dyn HttpClient>) -> Result<P
eprintln!("unpacked");
}
eprintln!("returning");
Ok(dbg!(node_dir))
Ok(node_dir)
}
pub async fn npm_package_latest_version(http: Arc<dyn HttpClient>, name: &str) -> Result<String> {

View File

@ -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<String> {
vec!["--stdio".into()]
}
pub struct JsonLspAdapter {
languages: Arc<LanguageRegistry>,
themes: Arc<ThemeRegistry>,
@ -41,10 +47,6 @@ impl LspAdapter for JsonLspAdapter {
ServerExecutionKind::Node
}
async fn server_args(&self) -> Vec<String> {
vec!["--stdio".into()]
}
async fn fetch_latest_server_version(
&self,
http: Arc<dyn HttpClient>,
@ -68,7 +70,7 @@ impl LspAdapter for JsonLspAdapter {
version: Box<dyn 'static + Send + Any>,
http: Arc<dyn HttpClient>,
container_dir: PathBuf,
) -> Result<PathBuf> {
) -> Result<LanguageServerBinary> {
let version = version.downcast::<GitHubLspBinaryVersion>().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<PathBuf> {
async fn cached_server_binary(&self, container_dir: PathBuf) -> Option<LanguageServerBinary> {
(|| 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()

View File

@ -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<Background>) -> Result<PluginLspAdapter> {
pub struct PluginLspAdapter {
name: WasiFn<(), String>,
server_execution_kind: WasiFn<(), ServerExecutionKind>,
server_args: WasiFn<(), Vec<String>>,
fetch_latest_server_version: WasiFn<(), Option<String>>,
fetch_server_binary: WasiFn<(PathBuf, String), Result<PathBuf, String>>,
cached_server_binary: WasiFn<PathBuf, Option<PathBuf>>,
fetch_server_binary: WasiFn<(PathBuf, String), Result<LanguageServerBinary, String>>,
cached_server_binary: WasiFn<PathBuf, Option<LanguageServerBinary>>,
initialization_options: WasiFn<(), String>,
language_ids: WasiFn<(), Vec<(String, String)>>,
executor: Arc<Background>,
@ -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<String> {
self.runtime
.lock()
.await
.call(&self.server_args, ())
.await
.unwrap()
}
async fn fetch_latest_server_version(
&self,
_: Arc<dyn HttpClient>,
@ -116,7 +105,7 @@ impl LspAdapter for PluginLspAdapter {
version: Box<dyn 'static + Send + Any>,
_: Arc<dyn HttpClient>,
container_dir: PathBuf,
) -> Result<PathBuf> {
) -> Result<LanguageServerBinary> {
let version = *version.downcast::<String>().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<PathBuf, String> =
let result: Result<LanguageServerBinary, String> =
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<PathBuf> {
async fn cached_server_binary(&self, container_dir: PathBuf) -> Option<LanguageServerBinary> {
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<PathBuf> = runtime.call(&function, container_dir).await.ok()?;
let result: Option<LanguageServerBinary> =
runtime.call(&function, container_dir).await.ok()?;
runtime.remove_resource(handle).ok()?;
result
})

View File

@ -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<String> {
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<String> {
vec![
"--logpath=~/lua-language-server.log".into(),
"--loglevel=trace".into(),
]
}
async fn fetch_latest_server_version(
&self,
http: Arc<dyn HttpClient>,
@ -61,7 +61,7 @@ impl super::LspAdapter for LuaLspAdapter {
version: Box<dyn 'static + Send + Any>,
http: Arc<dyn HttpClient>,
container_dir: PathBuf,
) -> Result<PathBuf> {
) -> Result<LanguageServerBinary> {
let version = version.downcast::<GitHubLspBinaryVersion>().unwrap();
let binary_path = container_dir.join("bin/lua-language-server");
@ -81,10 +81,13 @@ impl super::LspAdapter for LuaLspAdapter {
<fs::Permissions as fs::unix::PermissionsExt>::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<PathBuf> {
async fn cached_server_binary(&self, container_dir: PathBuf) -> Option<LanguageServerBinary> {
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"))
}

View File

@ -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<String> {
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<String> {
vec!["--stdio".into()]
}
async fn fetch_latest_server_version(
&self,
http: Arc<dyn HttpClient>,
@ -40,7 +40,7 @@ impl LspAdapter for PythonLspAdapter {
version: Box<dyn 'static + Send + Any>,
http: Arc<dyn HttpClient>,
container_dir: PathBuf,
) -> Result<PathBuf> {
) -> Result<LanguageServerBinary> {
let version = version.downcast::<String>().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<PathBuf> {
async fn cached_server_binary(&self, container_dir: PathBuf) -> Option<LanguageServerBinary> {
(|| 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 {:?}",

View File

@ -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<String> {
vec!["stdio".into()]
}
async fn fetch_latest_server_version(
&self,
_: Arc<dyn HttpClient>,
@ -32,12 +28,15 @@ impl LspAdapter for RubyLanguageServer {
_version: Box<dyn 'static + Send + Any>,
_: Arc<dyn HttpClient>,
_container_dir: PathBuf,
) -> Result<PathBuf> {
) -> Result<LanguageServerBinary> {
Err(anyhow!("solargraph must be installed manually"))
}
async fn cached_server_binary(&self, _container_dir: PathBuf) -> Option<PathBuf> {
Some("solargraph".into())
async fn cached_server_binary(&self, _container_dir: PathBuf) -> Option<LanguageServerBinary> {
Some(LanguageServerBinary {
path: "solargraph".into(),
arguments: vec!["stdio".into()],
})
}
async fn label_for_completion(

View File

@ -46,7 +46,7 @@ impl LspAdapter for RustLspAdapter {
version: Box<dyn 'static + Send + Any>,
http: Arc<dyn HttpClient>,
container_dir: PathBuf,
) -> Result<PathBuf> {
) -> Result<LanguageServerBinary> {
let version = version.downcast::<GitHubLspBinaryVersion>().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<PathBuf> {
async fn cached_server_binary(&self, container_dir: PathBuf) -> Option<LanguageServerBinary> {
(|| 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()

View File

@ -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<String> {
["--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<String> {
["--stdio", "--tsserver-path", "node_modules/typescript/lib"]
.into_iter()
.map(str::to_string)
.collect()
}
async fn fetch_latest_server_version(
&self,
http: Arc<dyn HttpClient>,
@ -53,7 +53,7 @@ impl LspAdapter for TypeScriptLspAdapter {
versions: Box<dyn 'static + Send + Any>,
http: Arc<dyn HttpClient>,
container_dir: PathBuf,
) -> Result<PathBuf> {
) -> Result<LanguageServerBinary> {
let versions = versions.downcast::<Versions>().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<PathBuf> {
async fn cached_server_binary(&self, container_dir: PathBuf) -> Option<LanguageServerBinary> {
(|| 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 {:?}",

View File

@ -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<String> {
vec!["--stdio".into()]
}
pub struct YamlLspAdapter;
impl YamlLspAdapter {
@ -28,10 +32,6 @@ impl LspAdapter for YamlLspAdapter {
ServerExecutionKind::Node
}
async fn server_args(&self) -> Vec<String> {
vec!["--stdio".into()]
}
async fn fetch_latest_server_version(
&self,
http: Arc<dyn HttpClient>,
@ -44,7 +44,7 @@ impl LspAdapter for YamlLspAdapter {
version: Box<dyn 'static + Send + Any>,
http: Arc<dyn HttpClient>,
container_dir: PathBuf,
) -> Result<PathBuf> {
) -> Result<LanguageServerBinary> {
let version = version.downcast::<String>().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<PathBuf> {
async fn cached_server_binary(&self, container_dir: PathBuf) -> Option<LanguageServerBinary> {
(|| 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 {:?}",