diff --git a/crates/editor/src/editor_tests.rs b/crates/editor/src/editor_tests.rs index f0a9fd90af..4196f60c5f 100644 --- a/crates/editor/src/editor_tests.rs +++ b/crates/editor/src/editor_tests.rs @@ -6839,7 +6839,7 @@ async fn test_document_format_during_save(cx: &mut gpui::TestAppContext) { let fs = FakeFs::new(cx.executor()); fs.insert_file("/file.rs", Default::default()).await; - let project = Project::test(fs, ["/".as_ref()], cx).await; + let project = Project::test(fs, ["/file.rs".as_ref()], cx).await; let language_registry = project.read_with(cx, |project, _| project.languages().clone()); language_registry.add(rust_lang()); @@ -7193,7 +7193,7 @@ async fn test_range_format_during_save(cx: &mut gpui::TestAppContext) { let fs = FakeFs::new(cx.executor()); fs.insert_file("/file.rs", Default::default()).await; - let project = Project::test(fs, ["/".as_ref()], cx).await; + let project = Project::test(fs, ["/file.rs".as_ref()], cx).await; let language_registry = project.read_with(cx, |project, _| project.languages().clone()); language_registry.add(rust_lang()); @@ -7327,7 +7327,7 @@ async fn test_document_format_manual_trigger(cx: &mut gpui::TestAppContext) { let fs = FakeFs::new(cx.executor()); fs.insert_file("/file.rs", Default::default()).await; - let project = Project::test(fs, ["/".as_ref()], cx).await; + let project = Project::test(fs, ["/file.rs".as_ref()], cx).await; let language_registry = project.read_with(cx, |project, _| project.languages().clone()); language_registry.add(Arc::new(Language::new( diff --git a/crates/project/src/lsp_store.rs b/crates/project/src/lsp_store.rs index 801e87fc38..e1e3c2ef93 100644 --- a/crates/project/src/lsp_store.rs +++ b/crates/project/src/lsp_store.rs @@ -6,7 +6,7 @@ use crate::{ lsp_ext_command, prettier_store::{self, PrettierStore, PrettierStoreEvent}, project_settings::{LspSettings, ProjectSettings}, - project_tree::{LanguageServerTree, LaunchDisposition, ProjectTree}, + project_tree::{AdapterQuery, LanguageServerTree, LaunchDisposition, ProjectTree}, relativize_path, resolve_path, toolchain_store::{EmptyToolchainStore, ToolchainStoreEvent}, worktree_store::{WorktreeStore, WorktreeStoreEvent}, @@ -983,9 +983,11 @@ impl LocalLspStore { if let Some((file, language)) = File::from_dyn(buffer.file()).zip(buffer.language()) { let worktree_id = file.worktree_id(cx); - let Some(path): Option> = file.path().parent().map(Arc::from) else { - return vec![]; - }; + let path: Arc = file + .path() + .parent() + .map(Arc::from) + .unwrap_or_else(|| file.path().clone()); let worktree_path = ProjectPath { worktree_id, path }; let Some(worktree) = self .worktree_store @@ -996,9 +998,14 @@ impl LocalLspStore { }; let delegate = LocalLspAdapterDelegate::from_local_lsp(self, &worktree, cx); let root = self.lsp_tree.update(cx, |this, cx| { - this.get(worktree_path, &language.name(), delegate, cx) - .filter_map(|node| node.server_id()) - .collect::>() + this.get( + worktree_path, + AdapterQuery::Language(&language.name()), + delegate, + cx, + ) + .filter_map(|node| node.server_id()) + .collect::>() }); root @@ -1740,7 +1747,7 @@ impl LocalLspStore { let nodes = self.lsp_tree.update(cx, |this, cx| { this.get( ProjectPath { worktree_id, path }, - &language.name(), + AdapterQuery::Language(&language.name()), delegate, cx, ) @@ -1860,9 +1867,11 @@ impl LocalLspStore { let Some(language) = buffer.language().cloned() else { return; }; - let Some(path): Option> = file.path().parent().map(Arc::from) else { - return; - }; + let path: Arc = file + .path() + .parent() + .map(Arc::from) + .unwrap_or_else(|| file.path().clone()); let Some(worktree) = self .worktree_store .read(cx) @@ -1874,7 +1883,7 @@ impl LocalLspStore { let servers = self.lsp_tree.clone().update(cx, |this, cx| { this.get( ProjectPath { worktree_id, path }, - &language.name(), + AdapterQuery::Language(&language.name()), delegate.clone(), cx, ) @@ -5361,12 +5370,35 @@ impl LspStore { fn register_local_language_server( &mut self, - worktree_id: WorktreeId, + worktree: Model, language_server_name: LanguageServerName, language_server_id: LanguageServerId, + cx: &mut AppContext, ) { - self.as_local_mut() - .unwrap() + let Some(local) = self.as_local_mut() else { + return; + }; + let worktree_id = worktree.read(cx).id(); + let path = ProjectPath { + worktree_id, + path: Arc::from("".as_ref()), + }; + let delegate = LocalLspAdapterDelegate::from_local_lsp(local, &worktree, cx); + local.lsp_tree.update(cx, |this, cx| { + for node in this.get( + path, + AdapterQuery::Adapter(&language_server_name), + delegate, + cx, + ) { + node.server_id_or_init(|disposition| { + assert_eq!(disposition.server_name, &language_server_name); + + language_server_id + }); + } + }); + local .language_server_ids .entry((worktree_id, language_server_name)) .or_default() @@ -5609,9 +5641,10 @@ impl LspStore { lsp_store .update(&mut cx, |lsp_store, cx| { lsp_store.register_local_language_server( - worktree.read(cx).id(), + worktree.clone(), language_server_name, language_server_id, + cx, ) }) .ok(); diff --git a/crates/project/src/project_tree.rs b/crates/project/src/project_tree.rs index 2a172711f4..ac6344cfec 100644 --- a/crates/project/src/project_tree.rs +++ b/crates/project/src/project_tree.rs @@ -25,7 +25,7 @@ use crate::{ ProjectPath, }; -pub(crate) use server_tree::{LanguageServerTree, LaunchDisposition}; +pub(crate) use server_tree::{AdapterQuery, LanguageServerTree, LaunchDisposition}; struct WorktreeRoots { roots: RootPathTrie, diff --git a/crates/project/src/project_tree/server_tree.rs b/crates/project/src/project_tree/server_tree.rs index c222b68a2b..62ab067d02 100644 --- a/crates/project/src/project_tree/server_tree.rs +++ b/crates/project/src/project_tree/server_tree.rs @@ -128,6 +128,14 @@ impl InnerTreeNode { } } +/// Determines how the list of adapters to query should be constructed. +pub(crate) enum AdapterQuery<'a> { + /// Search for roots of all adapters associated with a given language name. + Language(&'a LanguageName), + /// Search for roots of adapter with a given name. + Adapter(&'a LanguageServerName), +} + impl LanguageServerTree { pub(crate) fn new( project_tree: Model, @@ -159,7 +167,7 @@ impl LanguageServerTree { pub(crate) fn get<'a>( &'a mut self, path: ProjectPath, - language_name: &LanguageName, + query: AdapterQuery<'_>, delegate: Arc, cx: &mut AppContext, ) -> impl Iterator + 'a { @@ -167,7 +175,15 @@ impl LanguageServerTree { worktree_id: path.worktree_id, path: &path.path, }; - let adapters = self.adapters_for_language(settings_location, language_name, cx); + let adapters = match query { + AdapterQuery::Language(language_name) => { + self.adapters_for_language(settings_location, language_name, cx) + } + AdapterQuery::Adapter(language_server_name) => IndexMap::from_iter( + self.adapter_for_name(language_server_name) + .map(|adapter| (adapter, (LspSettings::default(), BTreeSet::new()))), + ), + }; self.get_with_adapters(path, adapters, delegate, cx) } @@ -231,6 +247,10 @@ impl LanguageServerTree { }) } + fn adapter_for_name(&self, name: &LanguageServerName) -> Option { + self.languages.adapter_for_name(name).map(AdapterWrapper) + } + fn adapters_for_language( &self, settings_location: SettingsLocation,