Detailed changes
@@ -20,6 +20,7 @@ use parking_lot::{Mutex, RwLock};
use serde::Deserialize;
use serde_json::Value;
use std::{
+ any::Any,
cell::RefCell,
ops::Range,
path::{Path, PathBuf},
@@ -61,9 +62,9 @@ pub trait ToLspPosition {
fn to_lsp_position(self) -> lsp::Position;
}
-pub struct LspBinaryVersion {
+pub struct GitHubLspBinaryVersion {
pub name: String,
- pub url: Option<http::Url>,
+ pub url: http::Url,
}
pub trait LspAdapter: 'static + Send + Sync {
@@ -71,10 +72,10 @@ pub trait LspAdapter: 'static + Send + Sync {
fn fetch_latest_server_version(
&self,
http: Arc<dyn HttpClient>,
- ) -> BoxFuture<'static, Result<LspBinaryVersion>>;
+ ) -> BoxFuture<'static, Result<Box<dyn 'static + Send + Any>>>;
fn fetch_server_binary(
&self,
- version: LspBinaryVersion,
+ version: Box<dyn 'static + Send + Any>,
http: Arc<dyn HttpClient>,
container_dir: PathBuf,
) -> BoxFuture<'static, Result<PathBuf>>;
@@ -2278,11 +2278,12 @@ impl Project {
Ok(completions
.into_iter()
.filter_map(|lsp_completion| {
- let (old_range, new_text) = match lsp_completion.text_edit.as_ref()? {
- lsp::CompletionTextEdit::Edit(edit) => {
+ let (old_range, new_text) = match lsp_completion.text_edit.as_ref() {
+ Some(lsp::CompletionTextEdit::Edit(edit)) => {
(range_from_lsp(edit.range), edit.new_text.clone())
}
- lsp::CompletionTextEdit::InsertAndReplace(_) => {
+ None => (position..position, lsp_completion.label.clone()),
+ Some(lsp::CompletionTextEdit::InsertAndReplace(_)) => {
log::info!("unsupported insert/replace completion");
return None;
}
@@ -2307,6 +2308,7 @@ impl Project {
lsp_completion,
})
} else {
+ log::info!("completion out of expected range");
None
}
})
@@ -1,4 +1,4 @@
-use client::http::{self, HttpClient, Method};
+use client::http;
use gpui::Task;
pub use language::*;
use rust_embed::RustEmbed;
@@ -53,7 +53,7 @@ pub fn build_language_registry(login_shell_env_loaded: Task<()>) -> LanguageRegi
(
"tsx",
tree_sitter_typescript::language_tsx(),
- None, //
+ Some(Arc::new(typescript::TypeScriptLspAdapter)),
),
(
"typescript",
@@ -3,7 +3,7 @@ use client::http::{self, HttpClient, Method};
use futures::{future::BoxFuture, FutureExt, StreamExt};
pub use language::*;
use smol::fs::{self, File};
-use std::{path::PathBuf, str, sync::Arc};
+use std::{any::Any, path::PathBuf, str, sync::Arc};
use util::{ResultExt, TryFutureExt};
use super::GithubRelease;
@@ -18,7 +18,7 @@ impl super::LspAdapter for CLspAdapter {
fn fetch_latest_server_version(
&self,
http: Arc<dyn HttpClient>,
- ) -> BoxFuture<'static, Result<LspBinaryVersion>> {
+ ) -> BoxFuture<'static, Result<Box<dyn 'static + Send + Any>>> {
async move {
let release = http
.send(
@@ -43,20 +43,21 @@ impl super::LspAdapter for CLspAdapter {
.iter()
.find(|asset| asset.name == asset_name)
.ok_or_else(|| anyhow!("no release found matching {:?}", asset_name))?;
- Ok(LspBinaryVersion {
+ Ok(Box::new(GitHubLspBinaryVersion {
name: release.name,
- url: Some(asset.browser_download_url.clone()),
- })
+ url: asset.browser_download_url.clone(),
+ }) as Box<_>)
}
.boxed()
}
fn fetch_server_binary(
&self,
- version: LspBinaryVersion,
+ version: Box<dyn 'static + Send + Any>,
http: Arc<dyn HttpClient>,
container_dir: PathBuf,
) -> BoxFuture<'static, Result<PathBuf>> {
+ let version = version.downcast::<GitHubLspBinaryVersion>().unwrap();
async move {
let zip_path = container_dir.join(format!("clangd_{}.zip", version.name));
let version_dir = container_dir.join(format!("clangd_{}", version.name));
@@ -65,7 +66,7 @@ impl super::LspAdapter for CLspAdapter {
if fs::metadata(&binary_path).await.is_err() {
let response = http
.send(
- surf::RequestBuilder::new(Method::Get, version.url.unwrap())
+ surf::RequestBuilder::new(Method::Get, version.url)
.middleware(surf::middleware::Redirect::default())
.build(),
)
@@ -1,12 +1,12 @@
use anyhow::{anyhow, Context, Result};
use client::http::HttpClient;
use futures::{future::BoxFuture, FutureExt, StreamExt};
-use language::{LspAdapter, LspBinaryVersion};
+use language::LspAdapter;
use serde::Deserialize;
use serde_json::json;
use smol::fs;
-use std::{path::PathBuf, sync::Arc};
-use util::ResultExt;
+use std::{any::Any, path::PathBuf, sync::Arc};
+use util::{ResultExt, TryFutureExt};
pub struct JsonLspAdapter;
@@ -27,7 +27,7 @@ impl LspAdapter for JsonLspAdapter {
fn fetch_latest_server_version(
&self,
_: Arc<dyn HttpClient>,
- ) -> BoxFuture<'static, Result<LspBinaryVersion>> {
+ ) -> BoxFuture<'static, Result<Box<dyn 'static + Any + Send>>> {
async move {
#[derive(Deserialize)]
struct NpmInfo {
@@ -43,25 +43,24 @@ impl LspAdapter for JsonLspAdapter {
}
let mut info: NpmInfo = serde_json::from_slice(&output.stdout)?;
- Ok(LspBinaryVersion {
- name: info
- .versions
+ Ok(Box::new(
+ info.versions
.pop()
.ok_or_else(|| anyhow!("no versions found in npm info"))?,
- url: Default::default(),
- })
+ ) as Box<_>)
}
.boxed()
}
fn fetch_server_binary(
&self,
- version: LspBinaryVersion,
+ version: Box<dyn 'static + Send + Any>,
_: Arc<dyn HttpClient>,
container_dir: PathBuf,
) -> BoxFuture<'static, Result<PathBuf>> {
+ let version = version.downcast::<String>().unwrap();
async move {
- let version_dir = container_dir.join(&version.name);
+ let version_dir = container_dir.join(version.as_str());
fs::create_dir_all(&version_dir)
.await
.context("failed to create version directory")?;
@@ -71,7 +70,7 @@ impl LspAdapter for JsonLspAdapter {
let output = smol::process::Command::new("npm")
.current_dir(&version_dir)
.arg("install")
- .arg(format!("vscode-json-languageserver@{}", version.name))
+ .arg(format!("vscode-json-languageserver@{}", version))
.output()
.await
.context("failed to run npm install")?;
@@ -6,7 +6,7 @@ pub use language::*;
use lazy_static::lazy_static;
use regex::Regex;
use smol::fs::{self, File};
-use std::{borrow::Cow, env::consts, path::PathBuf, str, sync::Arc};
+use std::{any::Any, borrow::Cow, env::consts, path::PathBuf, str, sync::Arc};
use util::{ResultExt, TryFutureExt};
use super::GithubRelease;
@@ -21,7 +21,7 @@ impl LspAdapter for RustLspAdapter {
fn fetch_latest_server_version(
&self,
http: Arc<dyn HttpClient>,
- ) -> BoxFuture<'static, Result<LspBinaryVersion>> {
+ ) -> BoxFuture<'static, Result<Box<dyn 'static + Send + Any>>> {
async move {
let release = http
.send(
@@ -46,27 +46,28 @@ impl LspAdapter for RustLspAdapter {
.iter()
.find(|asset| asset.name == asset_name)
.ok_or_else(|| anyhow!("no release found matching {:?}", asset_name))?;
- Ok(LspBinaryVersion {
+ Ok(Box::new(GitHubLspBinaryVersion {
name: release.name,
- url: Some(asset.browser_download_url.clone()),
- })
+ url: asset.browser_download_url.clone(),
+ }) as Box<_>)
}
.boxed()
}
fn fetch_server_binary(
&self,
- version: LspBinaryVersion,
+ version: Box<dyn 'static + Send + Any>,
http: Arc<dyn HttpClient>,
container_dir: PathBuf,
) -> BoxFuture<'static, Result<PathBuf>> {
async move {
+ 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 response = http
.send(
- surf::RequestBuilder::new(Method::Get, version.url.unwrap())
+ surf::RequestBuilder::new(Method::Get, version.url)
.middleware(surf::middleware::Redirect::default())
.build(),
)
@@ -1,57 +1,86 @@
+use anyhow::{anyhow, Context, Result};
+use client::http::HttpClient;
+use futures::{future::BoxFuture, FutureExt, StreamExt};
+use language::LspAdapter;
+use serde::Deserialize;
+use serde_json::json;
+use smol::fs;
+use std::{any::Any, path::PathBuf, sync::Arc};
+use util::{ResultExt, TryFutureExt};
+
pub struct TypeScriptLspAdapter;
impl TypeScriptLspAdapter {
- const BIN_PATH: &'static str =
- "node_modules/vscode-json-languageserver/bin/vscode-json-languageserver";
+ const BIN_PATH: &'static str = "node_modules/typescript-language-server/lib/cli.js";
+}
+
+struct Versions {
+ typescript_version: String,
+ server_version: String,
}
-impl super::LspAdapter for TypeScriptLspAdapter {
+impl LspAdapter for TypeScriptLspAdapter {
fn name(&self) -> &'static str {
"typescript-language-server"
}
fn server_args(&self) -> &[&str] {
- &["--stdio"]
+ &["--stdio", "--tsserver-path", "node_modules/typescript/lib"]
}
fn fetch_latest_server_version(
&self,
_: Arc<dyn HttpClient>,
- ) -> BoxFuture<'static, Result<LspBinaryVersion>> {
+ ) -> BoxFuture<'static, Result<Box<dyn 'static + Send + Any>>> {
async move {
#[derive(Deserialize)]
struct NpmInfo {
versions: Vec<String>,
}
- let output = smol::process::Command::new("npm")
- .args(["info", "vscode-json-languageserver", "--json"])
+ let typescript_output = smol::process::Command::new("npm")
+ .args(["info", "typescript", "--json"])
+ .output()
+ .await?;
+ if !typescript_output.status.success() {
+ Err(anyhow!("failed to execute npm info"))?;
+ }
+ let mut typescript_info: NpmInfo = serde_json::from_slice(&typescript_output.stdout)?;
+
+ let server_output = smol::process::Command::new("npm")
+ .args(["info", "typescript-language-server", "--json"])
.output()
.await?;
- if !output.status.success() {
+ if !server_output.status.success() {
Err(anyhow!("failed to execute npm info"))?;
}
- let mut info: NpmInfo = serde_json::from_slice(&output.stdout)?;
+ let mut server_info: NpmInfo = serde_json::from_slice(&server_output.stdout)?;
- Ok(LspBinaryVersion {
- name: info
+ Ok(Box::new(Versions {
+ typescript_version: typescript_info
.versions
.pop()
- .ok_or_else(|| anyhow!("no versions found in npm info"))?,
- url: Default::default(),
- })
+ .ok_or_else(|| anyhow!("no versions found in typescript npm info"))?,
+ server_version: server_info.versions.pop().ok_or_else(|| {
+ anyhow!("no versions found in typescript language server npm info")
+ })?,
+ }) as Box<_>)
}
.boxed()
}
fn fetch_server_binary(
&self,
- version: LspBinaryVersion,
+ versions: Box<dyn 'static + Send + Any>,
_: Arc<dyn HttpClient>,
container_dir: PathBuf,
) -> BoxFuture<'static, Result<PathBuf>> {
+ let versions = versions.downcast::<Versions>().unwrap();
async move {
- let version_dir = container_dir.join(&version.name);
+ let version_dir = container_dir.join(&format!(
+ "typescript-{}:server-{}",
+ versions.typescript_version, versions.server_version
+ ));
fs::create_dir_all(&version_dir)
.await
.context("failed to create version directory")?;
@@ -61,12 +90,16 @@ impl super::LspAdapter for TypeScriptLspAdapter {
let output = smol::process::Command::new("npm")
.current_dir(&version_dir)
.arg("install")
- .arg(format!("vscode-json-languageserver@{}", version.name))
+ .arg(format!("typescript@{}", versions.typescript_version))
+ .arg(format!(
+ "typescript-language-server@{}",
+ versions.server_version
+ ))
.output()
.await
.context("failed to run npm install")?;
if !output.status.success() {
- Err(anyhow!("failed to install vscode-json-languageserver"))?;
+ Err(anyhow!("failed to install typescript-language-server"))?;
}
if let Some(mut entries) = fs::read_dir(&container_dir).await.log_err() {