diff --git a/Cargo.lock b/Cargo.lock index 01caa941e9..2ae60fbb35 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -6791,6 +6791,7 @@ dependencies = [ "async-trait", "collections", "extension", + "fs", "futures 0.3.31", "gpui", "language", diff --git a/crates/language/src/language.rs b/crates/language/src/language.rs index 8061c7efa9..4176afca5b 100644 --- a/crates/language/src/language.rs +++ b/crates/language/src/language.rs @@ -25,6 +25,7 @@ use crate::language_settings::SoftWrap; use anyhow::{anyhow, Context, Result}; use async_trait::async_trait; use collections::{HashMap, HashSet}; +use fs::Fs; use futures::Future; use gpui::{AppContext, AsyncAppContext, Model, SharedString, Task}; pub use highlight_map::HighlightMap; @@ -464,6 +465,7 @@ pub trait LspAdapter: 'static + Send + Sync { /// Returns initialization options that are going to be sent to a LSP server as a part of [`lsp::InitializeParams`] async fn initialization_options( self: Arc, + _: &dyn Fs, _: &Arc, ) -> Result> { Ok(None) @@ -471,6 +473,7 @@ pub trait LspAdapter: 'static + Send + Sync { async fn workspace_configuration( self: Arc, + _: &dyn Fs, _: &Arc, _: Arc, _cx: &mut AsyncAppContext, @@ -1854,6 +1857,7 @@ impl LspAdapter for FakeLspAdapter { async fn initialization_options( self: Arc, + _: &dyn Fs, _: &Arc, ) -> Result> { Ok(self.initialization_options.clone()) diff --git a/crates/language_extension/Cargo.toml b/crates/language_extension/Cargo.toml index ef561b8841..6f9439fb5a 100644 --- a/crates/language_extension/Cargo.toml +++ b/crates/language_extension/Cargo.toml @@ -17,6 +17,7 @@ async-trait.workspace = true collections.workspace = true extension.workspace = true futures.workspace = true +fs.workspace = true gpui.workspace = true language.workspace = true lsp.workspace = true diff --git a/crates/language_extension/src/extension_lsp_adapter.rs b/crates/language_extension/src/extension_lsp_adapter.rs index 3286e09e2d..ec9ea1e0e5 100644 --- a/crates/language_extension/src/extension_lsp_adapter.rs +++ b/crates/language_extension/src/extension_lsp_adapter.rs @@ -8,6 +8,7 @@ use anyhow::{Context, Result}; use async_trait::async_trait; use collections::HashMap; use extension::{Extension, ExtensionLanguageServerProxy, WorktreeDelegate}; +use fs::Fs; use futures::{Future, FutureExt}; use gpui::AsyncAppContext; use language::{ @@ -224,6 +225,7 @@ impl LspAdapter for ExtensionLspAdapter { async fn initialization_options( self: Arc, + _: &dyn Fs, delegate: &Arc, ) -> Result> { let delegate = Arc::new(WorktreeDelegateAdapter(delegate.clone())) as _; @@ -246,6 +248,7 @@ impl LspAdapter for ExtensionLspAdapter { async fn workspace_configuration( self: Arc, + _: &dyn Fs, delegate: &Arc, _: Arc, _cx: &mut AsyncAppContext, diff --git a/crates/languages/src/css.rs b/crates/languages/src/css.rs index 148f6acced..50e34cea40 100644 --- a/crates/languages/src/css.rs +++ b/crates/languages/src/css.rs @@ -4,6 +4,7 @@ use futures::StreamExt; use language::{LspAdapter, LspAdapterDelegate}; use lsp::{LanguageServerBinary, LanguageServerName}; use node_runtime::NodeRuntime; +use project::Fs; use serde_json::json; use smol::fs; use std::{ @@ -107,6 +108,7 @@ impl LspAdapter for CssLspAdapter { async fn initialization_options( self: Arc, + _: &dyn Fs, _: &Arc, ) -> Result> { Ok(Some(json!({ diff --git a/crates/languages/src/go.rs b/crates/languages/src/go.rs index d56c720eb0..ca17f13e26 100644 --- a/crates/languages/src/go.rs +++ b/crates/languages/src/go.rs @@ -6,6 +6,7 @@ use gpui::{AppContext, AsyncAppContext, Task}; use http_client::github::latest_github_release; pub use language::*; use lsp::{LanguageServerBinary, LanguageServerName}; +use project::Fs; use regex::Regex; use serde_json::json; use smol::fs; @@ -197,6 +198,7 @@ impl super::LspAdapter for GoLspAdapter { async fn initialization_options( self: Arc, + _: &dyn Fs, _: &Arc, ) -> Result> { Ok(Some(json!({ diff --git a/crates/languages/src/json.rs b/crates/languages/src/json.rs index a783195db3..95aefd405a 100644 --- a/crates/languages/src/json.rs +++ b/crates/languages/src/json.rs @@ -9,7 +9,7 @@ use http_client::github::{latest_github_release, GitHubLspBinaryVersion}; use language::{LanguageRegistry, LanguageToolchainStore, LspAdapter, LspAdapterDelegate}; use lsp::{LanguageServerBinary, LanguageServerName}; use node_runtime::NodeRuntime; -use project::{lsp_store::language_server_settings, ContextProviderWithTasks}; +use project::{lsp_store::language_server_settings, ContextProviderWithTasks, Fs}; use serde_json::{json, Value}; use settings::{KeymapFile, SettingsJsonSchemaParams, SettingsStore}; use smol::{ @@ -208,6 +208,7 @@ impl LspAdapter for JsonLspAdapter { async fn initialization_options( self: Arc, + _: &dyn Fs, _: &Arc, ) -> Result> { Ok(Some(json!({ @@ -217,6 +218,7 @@ impl LspAdapter for JsonLspAdapter { async fn workspace_configuration( self: Arc, + _: &dyn Fs, delegate: &Arc, _: Arc, cx: &mut AsyncAppContext, diff --git a/crates/languages/src/python.rs b/crates/languages/src/python.rs index be9cef8651..a3cf24cf57 100644 --- a/crates/languages/src/python.rs +++ b/crates/languages/src/python.rs @@ -18,6 +18,7 @@ use pet_core::os_environment::Environment; use pet_core::python_environment::PythonEnvironmentKind; use pet_core::Configuration; use project::lsp_store::language_server_settings; +use project::Fs; use serde_json::{json, Value}; use smol::lock::OnceCell; use std::cmp::Ordering; @@ -250,6 +251,7 @@ impl LspAdapter for PythonLspAdapter { async fn workspace_configuration( self: Arc, + _: &dyn Fs, adapter: &Arc, toolchains: Arc, cx: &mut AsyncAppContext, @@ -931,6 +933,7 @@ impl LspAdapter for PyLspAdapter { async fn workspace_configuration( self: Arc, + _: &dyn Fs, adapter: &Arc, toolchains: Arc, cx: &mut AsyncAppContext, diff --git a/crates/languages/src/tailwind.rs b/crates/languages/src/tailwind.rs index 02c3dbefc2..328cf51279 100644 --- a/crates/languages/src/tailwind.rs +++ b/crates/languages/src/tailwind.rs @@ -6,7 +6,7 @@ use gpui::AsyncAppContext; use language::{LanguageToolchainStore, LspAdapter, LspAdapterDelegate}; use lsp::{LanguageServerBinary, LanguageServerName}; use node_runtime::NodeRuntime; -use project::lsp_store::language_server_settings; +use project::{lsp_store::language_server_settings, Fs}; use serde_json::{json, Value}; use smol::fs; use std::{ @@ -116,6 +116,7 @@ impl LspAdapter for TailwindLspAdapter { async fn initialization_options( self: Arc, + _: &dyn Fs, _: &Arc, ) -> Result> { Ok(Some(json!({ @@ -131,6 +132,7 @@ impl LspAdapter for TailwindLspAdapter { async fn workspace_configuration( self: Arc, + _: &dyn Fs, delegate: &Arc, _: Arc, cx: &mut AsyncAppContext, diff --git a/crates/languages/src/typescript.rs b/crates/languages/src/typescript.rs index edfdbf5f55..b14f3dc237 100644 --- a/crates/languages/src/typescript.rs +++ b/crates/languages/src/typescript.rs @@ -8,8 +8,8 @@ use http_client::github::{build_asset_url, AssetKind, GitHubLspBinaryVersion}; use language::{LanguageToolchainStore, LspAdapter, LspAdapterDelegate}; use lsp::{CodeActionKind, LanguageServerBinary, LanguageServerName}; use node_runtime::NodeRuntime; -use project::lsp_store::language_server_settings; use project::ContextProviderWithTasks; +use project::{lsp_store::language_server_settings, Fs}; use serde_json::{json, Value}; use smol::{fs, io::BufReader, stream::StreamExt}; use std::{ @@ -77,16 +77,25 @@ impl TypeScriptLspAdapter { pub fn new(node: NodeRuntime) -> Self { TypeScriptLspAdapter { node } } - async fn tsdk_path(adapter: &Arc) -> &'static str { + async fn tsdk_path(fs: &dyn Fs, adapter: &Arc) -> Option<&'static str> { let is_yarn = adapter .read_text_file(PathBuf::from(".yarn/sdks/typescript/lib/typescript.js")) .await .is_ok(); - if is_yarn { + let tsdk_path = if is_yarn { ".yarn/sdks/typescript/lib" } else { "node_modules/typescript/lib" + }; + + if fs + .is_dir(&adapter.worktree_root_path().join(tsdk_path)) + .await + { + Some(tsdk_path) + } else { + None } } } @@ -233,9 +242,10 @@ impl LspAdapter for TypeScriptLspAdapter { async fn initialization_options( self: Arc, + fs: &dyn Fs, adapter: &Arc, ) -> Result> { - let tsdk_path = Self::tsdk_path(adapter).await; + let tsdk_path = Self::tsdk_path(fs, adapter).await; Ok(Some(json!({ "provideFormatter": true, "hostInfo": "zed", @@ -257,6 +267,7 @@ impl LspAdapter for TypeScriptLspAdapter { async fn workspace_configuration( self: Arc, + _: &dyn Fs, delegate: &Arc, _: Arc, cx: &mut AsyncAppContext, @@ -353,6 +364,7 @@ impl LspAdapter for EsLintLspAdapter { async fn workspace_configuration( self: Arc, + _: &dyn Fs, delegate: &Arc, _: Arc, cx: &mut AsyncAppContext, diff --git a/crates/languages/src/vtsls.rs b/crates/languages/src/vtsls.rs index 22718e410c..33dea77540 100644 --- a/crates/languages/src/vtsls.rs +++ b/crates/languages/src/vtsls.rs @@ -5,7 +5,7 @@ use gpui::AsyncAppContext; use language::{LanguageToolchainStore, LspAdapter, LspAdapterDelegate}; use lsp::{CodeActionKind, LanguageServerBinary, LanguageServerName}; use node_runtime::NodeRuntime; -use project::lsp_store::language_server_settings; +use project::{lsp_store::language_server_settings, Fs}; use serde_json::Value; use std::{ any::Any, @@ -34,16 +34,25 @@ impl VtslsLspAdapter { VtslsLspAdapter { node } } - async fn tsdk_path(adapter: &Arc) -> &'static str { + async fn tsdk_path(fs: &dyn Fs, adapter: &Arc) -> Option<&'static str> { let is_yarn = adapter .read_text_file(PathBuf::from(".yarn/sdks/typescript/lib/typescript.js")) .await .is_ok(); - if is_yarn { + let tsdk_path = if is_yarn { ".yarn/sdks/typescript/lib" } else { Self::TYPESCRIPT_TSDK_PATH + }; + + if fs + .is_dir(&adapter.worktree_root_path().join(tsdk_path)) + .await + { + Some(tsdk_path) + } else { + None } } } @@ -196,11 +205,12 @@ impl LspAdapter for VtslsLspAdapter { async fn workspace_configuration( self: Arc, + fs: &dyn Fs, delegate: &Arc, _: Arc, cx: &mut AsyncAppContext, ) -> Result { - let tsdk_path = Self::tsdk_path(delegate).await; + let tsdk_path = Self::tsdk_path(fs, delegate).await; let config = serde_json::json!({ "tsdk": tsdk_path, "suggest": { diff --git a/crates/languages/src/yaml.rs b/crates/languages/src/yaml.rs index 12878b8f93..91f6e48aae 100644 --- a/crates/languages/src/yaml.rs +++ b/crates/languages/src/yaml.rs @@ -7,7 +7,7 @@ use language::{ }; use lsp::{LanguageServerBinary, LanguageServerName}; use node_runtime::NodeRuntime; -use project::lsp_store::language_server_settings; +use project::{lsp_store::language_server_settings, Fs}; use serde_json::Value; use settings::{Settings, SettingsLocation}; use smol::fs; @@ -128,6 +128,7 @@ impl LspAdapter for YamlLspAdapter { async fn workspace_configuration( self: Arc, + _: &dyn Fs, delegate: &Arc, _: Arc, cx: &mut AsyncAppContext, diff --git a/crates/project/src/lsp_store.rs b/crates/project/src/lsp_store.rs index ba88b5e485..7ae1c57b5f 100644 --- a/crates/project/src/lsp_store.rs +++ b/crates/project/src/lsp_store.rs @@ -244,7 +244,7 @@ impl LocalLspStore { let delegate = delegate as Arc; let key = key.clone(); let adapter = adapter.clone(); - + let fs = self.fs.clone(); cx.spawn(move |this, mut cx| async move { let result = { let delegate = delegate.clone(); @@ -260,13 +260,18 @@ impl LocalLspStore { let workspace_config = adapter .adapter .clone() - .workspace_configuration(&delegate, toolchains.clone(), &mut cx) + .workspace_configuration( + fs.as_ref(), + &delegate, + toolchains.clone(), + &mut cx, + ) .await?; let mut initialization_options = adapter .adapter .clone() - .initialization_options(&(delegate)) + .initialization_options(fs.as_ref(), &(delegate)) .await?; match (&mut initialization_options, override_options) { @@ -283,7 +288,13 @@ impl LocalLspStore { adapter.adapter.prepare_initialize_params(params) })??; - Self::setup_lsp_messages(this.clone(), &language_server, delegate, adapter); + Self::setup_lsp_messages( + this.clone(), + fs, + &language_server, + delegate, + adapter, + ); let did_change_configuration_params = Arc::new(lsp::DidChangeConfigurationParams { @@ -494,6 +505,7 @@ impl LocalLspStore { fn setup_lsp_messages( this: WeakModel, + fs: Arc, language_server: &LanguageServer, delegate: Arc, adapter: Arc, @@ -527,15 +539,17 @@ impl LocalLspStore { let adapter = adapter.adapter.clone(); let delegate = delegate.clone(); let this = this.clone(); + let fs = fs.clone(); move |params, mut cx| { let adapter = adapter.clone(); let delegate = delegate.clone(); let this = this.clone(); + let fs = fs.clone(); async move { let toolchains = this.update(&mut cx, |this, cx| this.toolchain_store(cx))?; let workspace_config = adapter - .workspace_configuration(&delegate, toolchains, &mut cx) + .workspace_configuration(fs.as_ref(), &delegate, toolchains, &mut cx) .await?; Ok(params .items @@ -2967,7 +2981,10 @@ impl LspStore { let _maintain_workspace_config = { let (sender, receiver) = watch::channel(); - (Self::maintain_workspace_config(receiver, cx), sender) + ( + Self::maintain_workspace_config(fs.clone(), receiver, cx), + sender, + ) }; Self { mode: LspStoreMode::Local(LocalLspStore { @@ -3030,6 +3047,7 @@ impl LspStore { }) } + #[allow(clippy::too_many_arguments)] pub(super) fn new_remote( buffer_store: Model, worktree_store: Model, @@ -3037,6 +3055,7 @@ impl LspStore { languages: Arc, upstream_client: AnyProtoClient, project_id: u64, + fs: Arc, cx: &mut ModelContext, ) -> Self { cx.subscribe(&buffer_store, Self::on_buffer_store_event) @@ -3045,7 +3064,7 @@ impl LspStore { .detach(); let _maintain_workspace_config = { let (sender, receiver) = watch::channel(); - (Self::maintain_workspace_config(receiver, cx), sender) + (Self::maintain_workspace_config(fs, receiver, cx), sender) }; Self { mode: LspStoreMode::Remote(RemoteLspStore { @@ -5131,6 +5150,7 @@ impl LspStore { pub(crate) async fn refresh_workspace_configurations( this: &WeakModel, + fs: Arc, mut cx: AsyncAppContext, ) { maybe!(async move { @@ -5177,7 +5197,12 @@ impl LspStore { .ok()?; for (adapter, server, delegate) in servers { let settings = adapter - .workspace_configuration(&delegate, toolchain_store.clone(), &mut cx) + .workspace_configuration( + fs.as_ref(), + &delegate, + toolchain_store.clone(), + &mut cx, + ) .await .ok()?; @@ -5200,6 +5225,7 @@ impl LspStore { } } fn maintain_workspace_config( + fs: Arc, external_refresh_requests: watch::Receiver<()>, cx: &mut ModelContext, ) -> Task> { @@ -5214,7 +5240,7 @@ impl LspStore { futures::stream::select(settings_changed_rx, external_refresh_requests); cx.spawn(move |this, cx| async move { while let Some(()) = joint_future.next().await { - Self::refresh_workspace_configurations(&this, cx.clone()).await; + Self::refresh_workspace_configurations(&this, fs.clone(), cx.clone()).await; } drop(settings_observation); @@ -8408,6 +8434,7 @@ impl LspAdapter for SshLspAdapter { async fn initialization_options( self: Arc, + _: &dyn Fs, _: &Arc, ) -> Result> { let Some(options) = &self.initialization_options else { diff --git a/crates/project/src/project.rs b/crates/project/src/project.rs index 78965f64b5..f378822d5f 100644 --- a/crates/project/src/project.rs +++ b/crates/project/src/project.rs @@ -808,6 +808,7 @@ impl Project { languages.clone(), ssh_proto.clone(), SSH_PROJECT_ID, + fs.clone(), cx, ) }); @@ -981,6 +982,7 @@ impl Project { languages.clone(), client.clone().into(), remote_id, + fs.clone(), cx, ); lsp_store.set_language_server_statuses_from_proto(response.payload.language_servers);