Add support for projects managed with Yarn (#13644)

TODO:
- [ ] File a PR with Yarn to add Zed to the list of supported IDEs.

Fixes: https://github.com/zed-industries/zed/issues/10107
Fixes: https://github.com/zed-industries/zed/issues/13706
Release Notes:

- Improved experience in projects using Yarn. Run `yarn dlx
@yarnpkg/sdks base` in the root of your project in order to elevate your
experience.

---------

Co-authored-by: Saurabh <79586784+m4saurabh@users.noreply.github.com>
This commit is contained in:
Piotr Osiewicz 2024-07-11 14:56:07 +02:00 committed by GitHub
parent 291d64c803
commit 2727f55772
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
9 changed files with 320 additions and 24 deletions

View file

@ -68,10 +68,22 @@ pub struct TypeScriptLspAdapter {
impl TypeScriptLspAdapter {
const OLD_SERVER_PATH: &'static str = "node_modules/typescript-language-server/lib/cli.js";
const NEW_SERVER_PATH: &'static str = "node_modules/typescript-language-server/lib/cli.mjs";
const SERVER_NAME: &'static str = "typescript-language-server";
pub fn new(node: Arc<dyn NodeRuntime>) -> Self {
TypeScriptLspAdapter { node }
}
async fn tsdk_path(adapter: &Arc<dyn LspAdapterDelegate>) -> &'static str {
let is_yarn = adapter
.read_text_file(PathBuf::from(".yarn/sdks/typescript/lib/typescript.js"))
.await
.is_ok();
if is_yarn {
".yarn/sdks/typescript/lib"
} else {
"node_modules/typescript/lib"
}
}
}
struct TypeScriptVersions {
@ -82,7 +94,7 @@ struct TypeScriptVersions {
#[async_trait(?Send)]
impl LspAdapter for TypeScriptLspAdapter {
fn name(&self) -> LanguageServerName {
LanguageServerName("typescript-language-server".into())
LanguageServerName(Self::SERVER_NAME.into())
}
async fn fetch_latest_server_version(
@ -196,13 +208,14 @@ impl LspAdapter for TypeScriptLspAdapter {
async fn initialization_options(
self: Arc<Self>,
_: &Arc<dyn LspAdapterDelegate>,
adapter: &Arc<dyn LspAdapterDelegate>,
) -> Result<Option<serde_json::Value>> {
let tsdk_path = Self::tsdk_path(adapter).await;
Ok(Some(json!({
"provideFormatter": true,
"hostInfo": "zed",
"tsserver": {
"path": "node_modules/typescript/lib",
"path": tsdk_path,
},
"preferences": {
"includeInlayParameterNameHints": "all",
@ -220,8 +233,17 @@ impl LspAdapter for TypeScriptLspAdapter {
async fn workspace_configuration(
self: Arc<Self>,
_: &Arc<dyn LspAdapterDelegate>,
_cx: &mut AsyncAppContext,
cx: &mut AsyncAppContext,
) -> Result<Value> {
let override_options = cx.update(|cx| {
ProjectSettings::get_global(cx)
.lsp
.get(Self::SERVER_NAME)
.and_then(|s| s.initialization_options.clone())
})?;
if let Some(options) = override_options {
return Ok(options);
}
Ok(json!({
"completions": {
"completeFunctionCalls": true

View file

@ -5,7 +5,9 @@ use gpui::AsyncAppContext;
use language::{LanguageServerName, LspAdapter, LspAdapterDelegate};
use lsp::{CodeActionKind, LanguageServerBinary};
use node_runtime::NodeRuntime;
use project::project_settings::ProjectSettings;
use serde_json::{json, Value};
use settings::Settings;
use std::{
any::Any,
ffi::OsString,
@ -28,6 +30,18 @@ impl VtslsLspAdapter {
pub fn new(node: Arc<dyn NodeRuntime>) -> Self {
VtslsLspAdapter { node }
}
async fn tsdk_path(adapter: &Arc<dyn LspAdapterDelegate>) -> &'static str {
let is_yarn = adapter
.read_text_file(PathBuf::from(".yarn/sdks/typescript/lib/typescript.js"))
.await
.is_ok();
if is_yarn {
".yarn/sdks/typescript/lib"
} else {
"node_modules/typescript/lib"
}
}
}
struct TypeScriptVersions {
@ -35,10 +49,11 @@ struct TypeScriptVersions {
server_version: String,
}
const SERVER_NAME: &'static str = "vtsls";
#[async_trait(?Send)]
impl LspAdapter for VtslsLspAdapter {
fn name(&self) -> LanguageServerName {
LanguageServerName("vtsls".into())
LanguageServerName(SERVER_NAME.into())
}
async fn fetch_latest_server_version(
@ -159,11 +174,12 @@ impl LspAdapter for VtslsLspAdapter {
async fn initialization_options(
self: Arc<Self>,
_: &Arc<dyn LspAdapterDelegate>,
adapter: &Arc<dyn LspAdapterDelegate>,
) -> Result<Option<serde_json::Value>> {
let tsdk_path = Self::tsdk_path(&adapter).await;
Ok(Some(json!({
"typescript": {
"tsdk": "node_modules/typescript/lib",
"tsdk": tsdk_path,
"format": {
"enable": true
},
@ -196,22 +212,33 @@ impl LspAdapter for VtslsLspAdapter {
"enableServerSideFuzzyMatch": true,
"entriesLimit": 5000,
}
}
},
"autoUseWorkspaceTsdk": true
}
})))
}
async fn workspace_configuration(
self: Arc<Self>,
_: &Arc<dyn LspAdapterDelegate>,
_cx: &mut AsyncAppContext,
adapter: &Arc<dyn LspAdapterDelegate>,
cx: &mut AsyncAppContext,
) -> Result<Value> {
let override_options = cx.update(|cx| {
ProjectSettings::get_global(cx)
.lsp
.get(SERVER_NAME)
.and_then(|s| s.initialization_options.clone())
})?;
if let Some(options) = override_options {
return Ok(options);
}
let tsdk_path = Self::tsdk_path(&adapter).await;
Ok(json!({
"typescript": {
"suggest": {
"completeFunctionCalls": true
},
"tsdk": "node_modules/typescript/lib",
"tsdk": tsdk_path,
"format": {
"enable": true
},
@ -244,7 +271,8 @@ impl LspAdapter for VtslsLspAdapter {
"enableServerSideFuzzyMatch": true,
"entriesLimit": 5000,
}
}
},
"autoUseWorkspaceTsdk": true
}
}))
}