project: Bring back language servers in detached worktrees (#23530)
Closes #ISSUE Release Notes: - N/A
This commit is contained in:
parent
bb937b6cee
commit
9e6b10018a
4 changed files with 75 additions and 22 deletions
|
@ -6839,7 +6839,7 @@ async fn test_document_format_during_save(cx: &mut gpui::TestAppContext) {
|
||||||
let fs = FakeFs::new(cx.executor());
|
let fs = FakeFs::new(cx.executor());
|
||||||
fs.insert_file("/file.rs", Default::default()).await;
|
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());
|
let language_registry = project.read_with(cx, |project, _| project.languages().clone());
|
||||||
language_registry.add(rust_lang());
|
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());
|
let fs = FakeFs::new(cx.executor());
|
||||||
fs.insert_file("/file.rs", Default::default()).await;
|
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());
|
let language_registry = project.read_with(cx, |project, _| project.languages().clone());
|
||||||
language_registry.add(rust_lang());
|
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());
|
let fs = FakeFs::new(cx.executor());
|
||||||
fs.insert_file("/file.rs", Default::default()).await;
|
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());
|
let language_registry = project.read_with(cx, |project, _| project.languages().clone());
|
||||||
language_registry.add(Arc::new(Language::new(
|
language_registry.add(Arc::new(Language::new(
|
||||||
|
|
|
@ -6,7 +6,7 @@ use crate::{
|
||||||
lsp_ext_command,
|
lsp_ext_command,
|
||||||
prettier_store::{self, PrettierStore, PrettierStoreEvent},
|
prettier_store::{self, PrettierStore, PrettierStoreEvent},
|
||||||
project_settings::{LspSettings, ProjectSettings},
|
project_settings::{LspSettings, ProjectSettings},
|
||||||
project_tree::{LanguageServerTree, LaunchDisposition, ProjectTree},
|
project_tree::{AdapterQuery, LanguageServerTree, LaunchDisposition, ProjectTree},
|
||||||
relativize_path, resolve_path,
|
relativize_path, resolve_path,
|
||||||
toolchain_store::{EmptyToolchainStore, ToolchainStoreEvent},
|
toolchain_store::{EmptyToolchainStore, ToolchainStoreEvent},
|
||||||
worktree_store::{WorktreeStore, WorktreeStoreEvent},
|
worktree_store::{WorktreeStore, WorktreeStoreEvent},
|
||||||
|
@ -983,9 +983,11 @@ impl LocalLspStore {
|
||||||
if let Some((file, language)) = File::from_dyn(buffer.file()).zip(buffer.language()) {
|
if let Some((file, language)) = File::from_dyn(buffer.file()).zip(buffer.language()) {
|
||||||
let worktree_id = file.worktree_id(cx);
|
let worktree_id = file.worktree_id(cx);
|
||||||
|
|
||||||
let Some(path): Option<Arc<Path>> = file.path().parent().map(Arc::from) else {
|
let path: Arc<Path> = file
|
||||||
return vec![];
|
.path()
|
||||||
};
|
.parent()
|
||||||
|
.map(Arc::from)
|
||||||
|
.unwrap_or_else(|| file.path().clone());
|
||||||
let worktree_path = ProjectPath { worktree_id, path };
|
let worktree_path = ProjectPath { worktree_id, path };
|
||||||
let Some(worktree) = self
|
let Some(worktree) = self
|
||||||
.worktree_store
|
.worktree_store
|
||||||
|
@ -996,9 +998,14 @@ impl LocalLspStore {
|
||||||
};
|
};
|
||||||
let delegate = LocalLspAdapterDelegate::from_local_lsp(self, &worktree, cx);
|
let delegate = LocalLspAdapterDelegate::from_local_lsp(self, &worktree, cx);
|
||||||
let root = self.lsp_tree.update(cx, |this, cx| {
|
let root = self.lsp_tree.update(cx, |this, cx| {
|
||||||
this.get(worktree_path, &language.name(), delegate, cx)
|
this.get(
|
||||||
.filter_map(|node| node.server_id())
|
worktree_path,
|
||||||
.collect::<Vec<_>>()
|
AdapterQuery::Language(&language.name()),
|
||||||
|
delegate,
|
||||||
|
cx,
|
||||||
|
)
|
||||||
|
.filter_map(|node| node.server_id())
|
||||||
|
.collect::<Vec<_>>()
|
||||||
});
|
});
|
||||||
|
|
||||||
root
|
root
|
||||||
|
@ -1740,7 +1747,7 @@ impl LocalLspStore {
|
||||||
let nodes = self.lsp_tree.update(cx, |this, cx| {
|
let nodes = self.lsp_tree.update(cx, |this, cx| {
|
||||||
this.get(
|
this.get(
|
||||||
ProjectPath { worktree_id, path },
|
ProjectPath { worktree_id, path },
|
||||||
&language.name(),
|
AdapterQuery::Language(&language.name()),
|
||||||
delegate,
|
delegate,
|
||||||
cx,
|
cx,
|
||||||
)
|
)
|
||||||
|
@ -1860,9 +1867,11 @@ impl LocalLspStore {
|
||||||
let Some(language) = buffer.language().cloned() else {
|
let Some(language) = buffer.language().cloned() else {
|
||||||
return;
|
return;
|
||||||
};
|
};
|
||||||
let Some(path): Option<Arc<Path>> = file.path().parent().map(Arc::from) else {
|
let path: Arc<Path> = file
|
||||||
return;
|
.path()
|
||||||
};
|
.parent()
|
||||||
|
.map(Arc::from)
|
||||||
|
.unwrap_or_else(|| file.path().clone());
|
||||||
let Some(worktree) = self
|
let Some(worktree) = self
|
||||||
.worktree_store
|
.worktree_store
|
||||||
.read(cx)
|
.read(cx)
|
||||||
|
@ -1874,7 +1883,7 @@ impl LocalLspStore {
|
||||||
let servers = self.lsp_tree.clone().update(cx, |this, cx| {
|
let servers = self.lsp_tree.clone().update(cx, |this, cx| {
|
||||||
this.get(
|
this.get(
|
||||||
ProjectPath { worktree_id, path },
|
ProjectPath { worktree_id, path },
|
||||||
&language.name(),
|
AdapterQuery::Language(&language.name()),
|
||||||
delegate.clone(),
|
delegate.clone(),
|
||||||
cx,
|
cx,
|
||||||
)
|
)
|
||||||
|
@ -5361,12 +5370,35 @@ impl LspStore {
|
||||||
|
|
||||||
fn register_local_language_server(
|
fn register_local_language_server(
|
||||||
&mut self,
|
&mut self,
|
||||||
worktree_id: WorktreeId,
|
worktree: Model<Worktree>,
|
||||||
language_server_name: LanguageServerName,
|
language_server_name: LanguageServerName,
|
||||||
language_server_id: LanguageServerId,
|
language_server_id: LanguageServerId,
|
||||||
|
cx: &mut AppContext,
|
||||||
) {
|
) {
|
||||||
self.as_local_mut()
|
let Some(local) = self.as_local_mut() else {
|
||||||
.unwrap()
|
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
|
.language_server_ids
|
||||||
.entry((worktree_id, language_server_name))
|
.entry((worktree_id, language_server_name))
|
||||||
.or_default()
|
.or_default()
|
||||||
|
@ -5609,9 +5641,10 @@ impl LspStore {
|
||||||
lsp_store
|
lsp_store
|
||||||
.update(&mut cx, |lsp_store, cx| {
|
.update(&mut cx, |lsp_store, cx| {
|
||||||
lsp_store.register_local_language_server(
|
lsp_store.register_local_language_server(
|
||||||
worktree.read(cx).id(),
|
worktree.clone(),
|
||||||
language_server_name,
|
language_server_name,
|
||||||
language_server_id,
|
language_server_id,
|
||||||
|
cx,
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
.ok();
|
.ok();
|
||||||
|
|
|
@ -25,7 +25,7 @@ use crate::{
|
||||||
ProjectPath,
|
ProjectPath,
|
||||||
};
|
};
|
||||||
|
|
||||||
pub(crate) use server_tree::{LanguageServerTree, LaunchDisposition};
|
pub(crate) use server_tree::{AdapterQuery, LanguageServerTree, LaunchDisposition};
|
||||||
|
|
||||||
struct WorktreeRoots {
|
struct WorktreeRoots {
|
||||||
roots: RootPathTrie<LanguageServerName>,
|
roots: RootPathTrie<LanguageServerName>,
|
||||||
|
|
|
@ -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 {
|
impl LanguageServerTree {
|
||||||
pub(crate) fn new(
|
pub(crate) fn new(
|
||||||
project_tree: Model<ProjectTree>,
|
project_tree: Model<ProjectTree>,
|
||||||
|
@ -159,7 +167,7 @@ impl LanguageServerTree {
|
||||||
pub(crate) fn get<'a>(
|
pub(crate) fn get<'a>(
|
||||||
&'a mut self,
|
&'a mut self,
|
||||||
path: ProjectPath,
|
path: ProjectPath,
|
||||||
language_name: &LanguageName,
|
query: AdapterQuery<'_>,
|
||||||
delegate: Arc<dyn LspAdapterDelegate>,
|
delegate: Arc<dyn LspAdapterDelegate>,
|
||||||
cx: &mut AppContext,
|
cx: &mut AppContext,
|
||||||
) -> impl Iterator<Item = LanguageServerTreeNode> + 'a {
|
) -> impl Iterator<Item = LanguageServerTreeNode> + 'a {
|
||||||
|
@ -167,7 +175,15 @@ impl LanguageServerTree {
|
||||||
worktree_id: path.worktree_id,
|
worktree_id: path.worktree_id,
|
||||||
path: &path.path,
|
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)
|
self.get_with_adapters(path, adapters, delegate, cx)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -231,6 +247,10 @@ impl LanguageServerTree {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn adapter_for_name(&self, name: &LanguageServerName) -> Option<AdapterWrapper> {
|
||||||
|
self.languages.adapter_for_name(name).map(AdapterWrapper)
|
||||||
|
}
|
||||||
|
|
||||||
fn adapters_for_language(
|
fn adapters_for_language(
|
||||||
&self,
|
&self,
|
||||||
settings_location: SettingsLocation,
|
settings_location: SettingsLocation,
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue