Stop waiting for part of LSP responses on remote Collab clients' part (#36557)

Instead of holding a connection for potentially long LSP queries (e.g.
rust-analyzer might take minutes to look up a definition), disconnect
right after sending the initial request and handle the follow-up
responses later.

As a bonus, this allows to cancel previously sent request on the local
Collab clients' side due to this, as instead of holding and serving the
old connection, local clients now can stop previous requests, if needed.

Current PR does not convert all LSP requests to the new paradigm, but
the problematic ones, deprecating `MultiLspQuery` and moving all its
requests to the new paradigm.

Release Notes:

- Improved resource usage when querying LSP over Collab

---------

Co-authored-by: David Kleingeld <git@davidsk.dev>
Co-authored-by: Mikayla Maki <mikayla@zed.dev>
Co-authored-by: David Kleingeld <davidsk@zed.dev>
This commit is contained in:
Kirill Bulatov 2025-08-21 09:24:34 +03:00 committed by GitHub
parent c731bb6d91
commit 5dcb90858e
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
20 changed files with 1395 additions and 681 deletions

View file

@ -15710,7 +15710,9 @@ impl Editor {
};
cx.spawn_in(window, async move |editor, cx| {
let definitions = definitions.await?;
let Some(definitions) = definitions.await? else {
return Ok(Navigated::No);
};
let navigated = editor
.update_in(cx, |editor, window, cx| {
editor.navigate_to_hover_links(
@ -16052,7 +16054,9 @@ impl Editor {
}
});
let locations = references.await?;
let Some(locations) = references.await? else {
return anyhow::Ok(Navigated::No);
};
if locations.is_empty() {
return anyhow::Ok(Navigated::No);
}
@ -21837,7 +21841,7 @@ pub trait SemanticsProvider {
buffer: &Entity<Buffer>,
position: text::Anchor,
cx: &mut App,
) -> Option<Task<Vec<project::Hover>>>;
) -> Option<Task<Option<Vec<project::Hover>>>>;
fn inline_values(
&self,
@ -21876,7 +21880,7 @@ pub trait SemanticsProvider {
position: text::Anchor,
kind: GotoDefinitionKind,
cx: &mut App,
) -> Option<Task<Result<Vec<LocationLink>>>>;
) -> Option<Task<Result<Option<Vec<LocationLink>>>>>;
fn range_for_rename(
&self,
@ -21989,7 +21993,13 @@ impl CodeActionProvider for Entity<Project> {
Ok(code_lens_actions
.context("code lens fetch")?
.into_iter()
.chain(code_actions.context("code action fetch")?)
.flatten()
.chain(
code_actions
.context("code action fetch")?
.into_iter()
.flatten(),
)
.collect())
})
})
@ -22284,7 +22294,7 @@ impl SemanticsProvider for Entity<Project> {
buffer: &Entity<Buffer>,
position: text::Anchor,
cx: &mut App,
) -> Option<Task<Vec<project::Hover>>> {
) -> Option<Task<Option<Vec<project::Hover>>>> {
Some(self.update(cx, |project, cx| project.hover(buffer, position, cx)))
}
@ -22305,7 +22315,7 @@ impl SemanticsProvider for Entity<Project> {
position: text::Anchor,
kind: GotoDefinitionKind,
cx: &mut App,
) -> Option<Task<Result<Vec<LocationLink>>>> {
) -> Option<Task<Result<Option<Vec<LocationLink>>>>> {
Some(self.update(cx, |project, cx| match kind {
GotoDefinitionKind::Symbol => project.definitions(buffer, position, cx),
GotoDefinitionKind::Declaration => project.declarations(buffer, position, cx),

View file

@ -559,7 +559,7 @@ pub fn show_link_definition(
provider.definitions(&buffer, buffer_position, preferred_kind, cx)
})?;
if let Some(task) = task {
task.await.ok().map(|definition_result| {
task.await.ok().flatten().map(|definition_result| {
(
definition_result.iter().find_map(|link| {
link.origin.as_ref().and_then(|origin| {

View file

@ -428,7 +428,7 @@ fn show_hover(
};
let hovers_response = if let Some(hover_request) = hover_request {
hover_request.await
hover_request.await.unwrap_or_default()
} else {
Vec::new()
};

View file

@ -431,7 +431,7 @@ impl SemanticsProvider for BranchBufferSemanticsProvider {
buffer: &Entity<Buffer>,
position: text::Anchor,
cx: &mut App,
) -> Option<Task<Vec<project::Hover>>> {
) -> Option<Task<Option<Vec<project::Hover>>>> {
let buffer = self.to_base(buffer, &[position], cx)?;
self.0.hover(&buffer, position, cx)
}
@ -490,7 +490,7 @@ impl SemanticsProvider for BranchBufferSemanticsProvider {
position: text::Anchor,
kind: crate::GotoDefinitionKind,
cx: &mut App,
) -> Option<Task<anyhow::Result<Vec<project::LocationLink>>>> {
) -> Option<Task<anyhow::Result<Option<Vec<project::LocationLink>>>>> {
let buffer = self.to_base(buffer, &[position], cx)?;
self.0.definitions(&buffer, position, kind, cx)
}

View file

@ -182,7 +182,9 @@ impl Editor {
let signature_help = task.await;
editor
.update(cx, |editor, cx| {
let Some(mut signature_help) = signature_help.into_iter().next() else {
let Some(mut signature_help) =
signature_help.unwrap_or_default().into_iter().next()
else {
editor
.signature_help_state
.hide(SignatureHelpHiddenBy::AutoClose);