Query multiple LSPs for more types of requests (#29359)
This fixes an issue where lower-priority language servers cannot provide contentful responses even when the first capable server returned empty responses. Most of the diffs are copypasted since the existing implementations were also copypasted. Release Notes: - Improved Go to Definition / Declaration / Type Definition / Implementation and Find All References to include all results from different language servers
This commit is contained in:
parent
105acacff9
commit
5f70a9cf59
8 changed files with 617 additions and 93 deletions
|
@ -4821,7 +4821,7 @@ async fn test_definition(
|
||||||
);
|
);
|
||||||
|
|
||||||
let definitions_1 = project_b
|
let definitions_1 = project_b
|
||||||
.update(cx_b, |p, cx| p.definition(&buffer_b, 23, cx))
|
.update(cx_b, |p, cx| p.definitions(&buffer_b, 23, cx))
|
||||||
.await
|
.await
|
||||||
.unwrap();
|
.unwrap();
|
||||||
cx_b.read(|cx| {
|
cx_b.read(|cx| {
|
||||||
|
@ -4852,7 +4852,7 @@ async fn test_definition(
|
||||||
);
|
);
|
||||||
|
|
||||||
let definitions_2 = project_b
|
let definitions_2 = project_b
|
||||||
.update(cx_b, |p, cx| p.definition(&buffer_b, 33, cx))
|
.update(cx_b, |p, cx| p.definitions(&buffer_b, 33, cx))
|
||||||
.await
|
.await
|
||||||
.unwrap();
|
.unwrap();
|
||||||
cx_b.read(|cx| {
|
cx_b.read(|cx| {
|
||||||
|
@ -4889,7 +4889,7 @@ async fn test_definition(
|
||||||
);
|
);
|
||||||
|
|
||||||
let type_definitions = project_b
|
let type_definitions = project_b
|
||||||
.update(cx_b, |p, cx| p.type_definition(&buffer_b, 7, cx))
|
.update(cx_b, |p, cx| p.type_definitions(&buffer_b, 7, cx))
|
||||||
.await
|
.await
|
||||||
.unwrap();
|
.unwrap();
|
||||||
cx_b.read(|cx| {
|
cx_b.read(|cx| {
|
||||||
|
@ -5057,7 +5057,7 @@ async fn test_references(
|
||||||
lsp_response_tx
|
lsp_response_tx
|
||||||
.unbounded_send(Err(anyhow!("can't find references")))
|
.unbounded_send(Err(anyhow!("can't find references")))
|
||||||
.unwrap();
|
.unwrap();
|
||||||
references.await.unwrap_err();
|
assert_eq!(references.await.unwrap(), []);
|
||||||
|
|
||||||
// User is informed that the request is no longer pending.
|
// User is informed that the request is no longer pending.
|
||||||
executor.run_until_parked();
|
executor.run_until_parked();
|
||||||
|
@ -5641,7 +5641,7 @@ async fn test_open_buffer_while_getting_definition_pointing_to_it(
|
||||||
let definitions;
|
let definitions;
|
||||||
let buffer_b2;
|
let buffer_b2;
|
||||||
if rng.r#gen() {
|
if rng.r#gen() {
|
||||||
definitions = project_b.update(cx_b, |p, cx| p.definition(&buffer_b1, 23, cx));
|
definitions = project_b.update(cx_b, |p, cx| p.definitions(&buffer_b1, 23, cx));
|
||||||
(buffer_b2, _) = project_b
|
(buffer_b2, _) = project_b
|
||||||
.update(cx_b, |p, cx| {
|
.update(cx_b, |p, cx| {
|
||||||
p.open_buffer_with_lsp((worktree_id, "b.rs"), cx)
|
p.open_buffer_with_lsp((worktree_id, "b.rs"), cx)
|
||||||
|
@ -5655,7 +5655,7 @@ async fn test_open_buffer_while_getting_definition_pointing_to_it(
|
||||||
})
|
})
|
||||||
.await
|
.await
|
||||||
.unwrap();
|
.unwrap();
|
||||||
definitions = project_b.update(cx_b, |p, cx| p.definition(&buffer_b1, 23, cx));
|
definitions = project_b.update(cx_b, |p, cx| p.definitions(&buffer_b1, 23, cx));
|
||||||
}
|
}
|
||||||
|
|
||||||
let definitions = definitions.await.unwrap();
|
let definitions = definitions.await.unwrap();
|
||||||
|
|
|
@ -838,7 +838,7 @@ impl RandomizedTest for ProjectCollaborationTest {
|
||||||
.map(|_| Ok(()))
|
.map(|_| Ok(()))
|
||||||
.boxed(),
|
.boxed(),
|
||||||
LspRequestKind::Definition => project
|
LspRequestKind::Definition => project
|
||||||
.definition(&buffer, offset, cx)
|
.definitions(&buffer, offset, cx)
|
||||||
.map_ok(|_| ())
|
.map_ok(|_| ())
|
||||||
.boxed(),
|
.boxed(),
|
||||||
LspRequestKind::Highlights => project
|
LspRequestKind::Highlights => project
|
||||||
|
|
|
@ -21944,10 +21944,10 @@ impl SemanticsProvider for Entity<Project> {
|
||||||
cx: &mut App,
|
cx: &mut App,
|
||||||
) -> Option<Task<Result<Vec<LocationLink>>>> {
|
) -> Option<Task<Result<Vec<LocationLink>>>> {
|
||||||
Some(self.update(cx, |project, cx| match kind {
|
Some(self.update(cx, |project, cx| match kind {
|
||||||
GotoDefinitionKind::Symbol => project.definition(&buffer, position, cx),
|
GotoDefinitionKind::Symbol => project.definitions(&buffer, position, cx),
|
||||||
GotoDefinitionKind::Declaration => project.declaration(&buffer, position, cx),
|
GotoDefinitionKind::Declaration => project.declarations(&buffer, position, cx),
|
||||||
GotoDefinitionKind::Type => project.type_definition(&buffer, position, cx),
|
GotoDefinitionKind::Type => project.type_definitions(&buffer, position, cx),
|
||||||
GotoDefinitionKind::Implementation => project.implementation(&buffer, position, cx),
|
GotoDefinitionKind::Implementation => project.implementations(&buffer, position, cx),
|
||||||
}))
|
}))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -171,27 +171,27 @@ pub(crate) struct PerformRename {
|
||||||
pub push_to_history: bool,
|
pub push_to_history: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug, Clone, Copy)]
|
||||||
pub struct GetDefinition {
|
pub struct GetDefinitions {
|
||||||
pub position: PointUtf16,
|
pub position: PointUtf16,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug, Clone, Copy)]
|
||||||
pub(crate) struct GetDeclaration {
|
pub(crate) struct GetDeclarations {
|
||||||
pub position: PointUtf16,
|
pub position: PointUtf16,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug, Clone, Copy)]
|
||||||
pub(crate) struct GetTypeDefinition {
|
pub(crate) struct GetTypeDefinitions {
|
||||||
pub position: PointUtf16,
|
pub position: PointUtf16,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug, Clone, Copy)]
|
||||||
pub(crate) struct GetImplementation {
|
pub(crate) struct GetImplementations {
|
||||||
pub position: PointUtf16,
|
pub position: PointUtf16,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug, Clone, Copy)]
|
||||||
pub(crate) struct GetReferences {
|
pub(crate) struct GetReferences {
|
||||||
pub position: PointUtf16,
|
pub position: PointUtf16,
|
||||||
}
|
}
|
||||||
|
@ -588,7 +588,7 @@ impl LspCommand for PerformRename {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[async_trait(?Send)]
|
#[async_trait(?Send)]
|
||||||
impl LspCommand for GetDefinition {
|
impl LspCommand for GetDefinitions {
|
||||||
type Response = Vec<LocationLink>;
|
type Response = Vec<LocationLink>;
|
||||||
type LspRequest = lsp::request::GotoDefinition;
|
type LspRequest = lsp::request::GotoDefinition;
|
||||||
type ProtoRequest = proto::GetDefinition;
|
type ProtoRequest = proto::GetDefinition;
|
||||||
|
@ -690,7 +690,7 @@ impl LspCommand for GetDefinition {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[async_trait(?Send)]
|
#[async_trait(?Send)]
|
||||||
impl LspCommand for GetDeclaration {
|
impl LspCommand for GetDeclarations {
|
||||||
type Response = Vec<LocationLink>;
|
type Response = Vec<LocationLink>;
|
||||||
type LspRequest = lsp::request::GotoDeclaration;
|
type LspRequest = lsp::request::GotoDeclaration;
|
||||||
type ProtoRequest = proto::GetDeclaration;
|
type ProtoRequest = proto::GetDeclaration;
|
||||||
|
@ -793,7 +793,7 @@ impl LspCommand for GetDeclaration {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[async_trait(?Send)]
|
#[async_trait(?Send)]
|
||||||
impl LspCommand for GetImplementation {
|
impl LspCommand for GetImplementations {
|
||||||
type Response = Vec<LocationLink>;
|
type Response = Vec<LocationLink>;
|
||||||
type LspRequest = lsp::request::GotoImplementation;
|
type LspRequest = lsp::request::GotoImplementation;
|
||||||
type ProtoRequest = proto::GetImplementation;
|
type ProtoRequest = proto::GetImplementation;
|
||||||
|
@ -895,7 +895,7 @@ impl LspCommand for GetImplementation {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[async_trait(?Send)]
|
#[async_trait(?Send)]
|
||||||
impl LspCommand for GetTypeDefinition {
|
impl LspCommand for GetTypeDefinitions {
|
||||||
type Response = Vec<LocationLink>;
|
type Response = Vec<LocationLink>;
|
||||||
type LspRequest = lsp::request::GotoTypeDefinition;
|
type LspRequest = lsp::request::GotoTypeDefinition;
|
||||||
type ProtoRequest = proto::GetTypeDefinition;
|
type ProtoRequest = proto::GetTypeDefinition;
|
||||||
|
|
|
@ -4,8 +4,9 @@ pub mod rust_analyzer_ext;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
CodeAction, ColorPresentation, Completion, CompletionResponse, CompletionSource,
|
CodeAction, ColorPresentation, Completion, CompletionResponse, CompletionSource,
|
||||||
CoreCompletion, DocumentColor, Hover, InlayHint, LspAction, LspPullDiagnostics, ProjectItem,
|
CoreCompletion, DocumentColor, Hover, InlayHint, LocationLink, LspAction, LspPullDiagnostics,
|
||||||
ProjectPath, ProjectTransaction, PulledDiagnostics, ResolveState, Symbol, ToolchainStore,
|
ProjectItem, ProjectPath, ProjectTransaction, PulledDiagnostics, ResolveState, Symbol,
|
||||||
|
ToolchainStore,
|
||||||
buffer_store::{BufferStore, BufferStoreEvent},
|
buffer_store::{BufferStore, BufferStoreEvent},
|
||||||
environment::ProjectEnvironment,
|
environment::ProjectEnvironment,
|
||||||
lsp_command::{self, *},
|
lsp_command::{self, *},
|
||||||
|
@ -3660,12 +3661,8 @@ impl LspStore {
|
||||||
client.add_entity_request_handler(Self::handle_lsp_command::<GetCodeActions>);
|
client.add_entity_request_handler(Self::handle_lsp_command::<GetCodeActions>);
|
||||||
client.add_entity_request_handler(Self::handle_lsp_command::<GetCompletions>);
|
client.add_entity_request_handler(Self::handle_lsp_command::<GetCompletions>);
|
||||||
client.add_entity_request_handler(Self::handle_lsp_command::<GetHover>);
|
client.add_entity_request_handler(Self::handle_lsp_command::<GetHover>);
|
||||||
client.add_entity_request_handler(Self::handle_lsp_command::<GetDefinition>);
|
|
||||||
client.add_entity_request_handler(Self::handle_lsp_command::<GetDeclaration>);
|
|
||||||
client.add_entity_request_handler(Self::handle_lsp_command::<GetTypeDefinition>);
|
|
||||||
client.add_entity_request_handler(Self::handle_lsp_command::<GetDocumentHighlights>);
|
client.add_entity_request_handler(Self::handle_lsp_command::<GetDocumentHighlights>);
|
||||||
client.add_entity_request_handler(Self::handle_lsp_command::<GetDocumentSymbols>);
|
client.add_entity_request_handler(Self::handle_lsp_command::<GetDocumentSymbols>);
|
||||||
client.add_entity_request_handler(Self::handle_lsp_command::<GetReferences>);
|
|
||||||
client.add_entity_request_handler(Self::handle_lsp_command::<PrepareRename>);
|
client.add_entity_request_handler(Self::handle_lsp_command::<PrepareRename>);
|
||||||
client.add_entity_request_handler(Self::handle_lsp_command::<PerformRename>);
|
client.add_entity_request_handler(Self::handle_lsp_command::<PerformRename>);
|
||||||
client.add_entity_request_handler(Self::handle_lsp_command::<LinkedEditingRange>);
|
client.add_entity_request_handler(Self::handle_lsp_command::<LinkedEditingRange>);
|
||||||
|
@ -5257,6 +5254,371 @@ impl LspStore {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn definitions(
|
||||||
|
&mut self,
|
||||||
|
buffer_handle: &Entity<Buffer>,
|
||||||
|
position: PointUtf16,
|
||||||
|
cx: &mut Context<Self>,
|
||||||
|
) -> Task<Result<Vec<LocationLink>>> {
|
||||||
|
if let Some((upstream_client, project_id)) = self.upstream_client() {
|
||||||
|
let request_task = upstream_client.request(proto::MultiLspQuery {
|
||||||
|
buffer_id: buffer_handle.read(cx).remote_id().into(),
|
||||||
|
version: serialize_version(&buffer_handle.read(cx).version()),
|
||||||
|
project_id,
|
||||||
|
strategy: Some(proto::multi_lsp_query::Strategy::All(
|
||||||
|
proto::AllLanguageServers {},
|
||||||
|
)),
|
||||||
|
request: Some(proto::multi_lsp_query::Request::GetDefinition(
|
||||||
|
GetDefinitions { position }.to_proto(project_id, buffer_handle.read(cx)),
|
||||||
|
)),
|
||||||
|
});
|
||||||
|
let buffer = buffer_handle.clone();
|
||||||
|
cx.spawn(async move |weak_project, cx| {
|
||||||
|
let Some(project) = weak_project.upgrade() else {
|
||||||
|
return Ok(Vec::new());
|
||||||
|
};
|
||||||
|
let responses = request_task.await?.responses;
|
||||||
|
let actions = join_all(
|
||||||
|
responses
|
||||||
|
.into_iter()
|
||||||
|
.filter_map(|lsp_response| match lsp_response.response? {
|
||||||
|
proto::lsp_response::Response::GetDefinitionResponse(response) => {
|
||||||
|
Some(response)
|
||||||
|
}
|
||||||
|
unexpected => {
|
||||||
|
debug_panic!("Unexpected response: {unexpected:?}");
|
||||||
|
None
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.map(|definitions_response| {
|
||||||
|
GetDefinitions { position }.response_from_proto(
|
||||||
|
definitions_response,
|
||||||
|
project.clone(),
|
||||||
|
buffer.clone(),
|
||||||
|
cx.clone(),
|
||||||
|
)
|
||||||
|
}),
|
||||||
|
)
|
||||||
|
.await;
|
||||||
|
|
||||||
|
Ok(actions
|
||||||
|
.into_iter()
|
||||||
|
.collect::<Result<Vec<Vec<_>>>>()?
|
||||||
|
.into_iter()
|
||||||
|
.flatten()
|
||||||
|
.dedup()
|
||||||
|
.collect())
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
let definitions_task = self.request_multiple_lsp_locally(
|
||||||
|
buffer_handle,
|
||||||
|
Some(position),
|
||||||
|
GetDefinitions { position },
|
||||||
|
cx,
|
||||||
|
);
|
||||||
|
cx.spawn(async move |_, _| {
|
||||||
|
Ok(definitions_task
|
||||||
|
.await
|
||||||
|
.into_iter()
|
||||||
|
.flat_map(|(_, definitions)| definitions)
|
||||||
|
.dedup()
|
||||||
|
.collect())
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn declarations(
|
||||||
|
&mut self,
|
||||||
|
buffer_handle: &Entity<Buffer>,
|
||||||
|
position: PointUtf16,
|
||||||
|
cx: &mut Context<Self>,
|
||||||
|
) -> Task<Result<Vec<LocationLink>>> {
|
||||||
|
if let Some((upstream_client, project_id)) = self.upstream_client() {
|
||||||
|
let request_task = upstream_client.request(proto::MultiLspQuery {
|
||||||
|
buffer_id: buffer_handle.read(cx).remote_id().into(),
|
||||||
|
version: serialize_version(&buffer_handle.read(cx).version()),
|
||||||
|
project_id,
|
||||||
|
strategy: Some(proto::multi_lsp_query::Strategy::All(
|
||||||
|
proto::AllLanguageServers {},
|
||||||
|
)),
|
||||||
|
request: Some(proto::multi_lsp_query::Request::GetDeclaration(
|
||||||
|
GetDeclarations { position }.to_proto(project_id, buffer_handle.read(cx)),
|
||||||
|
)),
|
||||||
|
});
|
||||||
|
let buffer = buffer_handle.clone();
|
||||||
|
cx.spawn(async move |weak_project, cx| {
|
||||||
|
let Some(project) = weak_project.upgrade() else {
|
||||||
|
return Ok(Vec::new());
|
||||||
|
};
|
||||||
|
let responses = request_task.await?.responses;
|
||||||
|
let actions = join_all(
|
||||||
|
responses
|
||||||
|
.into_iter()
|
||||||
|
.filter_map(|lsp_response| match lsp_response.response? {
|
||||||
|
proto::lsp_response::Response::GetDeclarationResponse(response) => {
|
||||||
|
Some(response)
|
||||||
|
}
|
||||||
|
unexpected => {
|
||||||
|
debug_panic!("Unexpected response: {unexpected:?}");
|
||||||
|
None
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.map(|declarations_response| {
|
||||||
|
GetDeclarations { position }.response_from_proto(
|
||||||
|
declarations_response,
|
||||||
|
project.clone(),
|
||||||
|
buffer.clone(),
|
||||||
|
cx.clone(),
|
||||||
|
)
|
||||||
|
}),
|
||||||
|
)
|
||||||
|
.await;
|
||||||
|
|
||||||
|
Ok(actions
|
||||||
|
.into_iter()
|
||||||
|
.collect::<Result<Vec<Vec<_>>>>()?
|
||||||
|
.into_iter()
|
||||||
|
.flatten()
|
||||||
|
.dedup()
|
||||||
|
.collect())
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
let declarations_task = self.request_multiple_lsp_locally(
|
||||||
|
buffer_handle,
|
||||||
|
Some(position),
|
||||||
|
GetDeclarations { position },
|
||||||
|
cx,
|
||||||
|
);
|
||||||
|
cx.spawn(async move |_, _| {
|
||||||
|
Ok(declarations_task
|
||||||
|
.await
|
||||||
|
.into_iter()
|
||||||
|
.flat_map(|(_, declarations)| declarations)
|
||||||
|
.dedup()
|
||||||
|
.collect())
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn type_definitions(
|
||||||
|
&mut self,
|
||||||
|
buffer_handle: &Entity<Buffer>,
|
||||||
|
position: PointUtf16,
|
||||||
|
cx: &mut Context<Self>,
|
||||||
|
) -> Task<Result<Vec<LocationLink>>> {
|
||||||
|
if let Some((upstream_client, project_id)) = self.upstream_client() {
|
||||||
|
let request_task = upstream_client.request(proto::MultiLspQuery {
|
||||||
|
buffer_id: buffer_handle.read(cx).remote_id().into(),
|
||||||
|
version: serialize_version(&buffer_handle.read(cx).version()),
|
||||||
|
project_id,
|
||||||
|
strategy: Some(proto::multi_lsp_query::Strategy::All(
|
||||||
|
proto::AllLanguageServers {},
|
||||||
|
)),
|
||||||
|
request: Some(proto::multi_lsp_query::Request::GetTypeDefinition(
|
||||||
|
GetTypeDefinitions { position }.to_proto(project_id, buffer_handle.read(cx)),
|
||||||
|
)),
|
||||||
|
});
|
||||||
|
let buffer = buffer_handle.clone();
|
||||||
|
cx.spawn(async move |weak_project, cx| {
|
||||||
|
let Some(project) = weak_project.upgrade() else {
|
||||||
|
return Ok(Vec::new());
|
||||||
|
};
|
||||||
|
let responses = request_task.await?.responses;
|
||||||
|
let actions = join_all(
|
||||||
|
responses
|
||||||
|
.into_iter()
|
||||||
|
.filter_map(|lsp_response| match lsp_response.response? {
|
||||||
|
proto::lsp_response::Response::GetTypeDefinitionResponse(response) => {
|
||||||
|
Some(response)
|
||||||
|
}
|
||||||
|
unexpected => {
|
||||||
|
debug_panic!("Unexpected response: {unexpected:?}");
|
||||||
|
None
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.map(|type_definitions_response| {
|
||||||
|
GetTypeDefinitions { position }.response_from_proto(
|
||||||
|
type_definitions_response,
|
||||||
|
project.clone(),
|
||||||
|
buffer.clone(),
|
||||||
|
cx.clone(),
|
||||||
|
)
|
||||||
|
}),
|
||||||
|
)
|
||||||
|
.await;
|
||||||
|
|
||||||
|
Ok(actions
|
||||||
|
.into_iter()
|
||||||
|
.collect::<Result<Vec<Vec<_>>>>()?
|
||||||
|
.into_iter()
|
||||||
|
.flatten()
|
||||||
|
.dedup()
|
||||||
|
.collect())
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
let type_definitions_task = self.request_multiple_lsp_locally(
|
||||||
|
buffer_handle,
|
||||||
|
Some(position),
|
||||||
|
GetTypeDefinitions { position },
|
||||||
|
cx,
|
||||||
|
);
|
||||||
|
cx.spawn(async move |_, _| {
|
||||||
|
Ok(type_definitions_task
|
||||||
|
.await
|
||||||
|
.into_iter()
|
||||||
|
.flat_map(|(_, type_definitions)| type_definitions)
|
||||||
|
.dedup()
|
||||||
|
.collect())
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn implementations(
|
||||||
|
&mut self,
|
||||||
|
buffer_handle: &Entity<Buffer>,
|
||||||
|
position: PointUtf16,
|
||||||
|
cx: &mut Context<Self>,
|
||||||
|
) -> Task<Result<Vec<LocationLink>>> {
|
||||||
|
if let Some((upstream_client, project_id)) = self.upstream_client() {
|
||||||
|
let request_task = upstream_client.request(proto::MultiLspQuery {
|
||||||
|
buffer_id: buffer_handle.read(cx).remote_id().into(),
|
||||||
|
version: serialize_version(&buffer_handle.read(cx).version()),
|
||||||
|
project_id,
|
||||||
|
strategy: Some(proto::multi_lsp_query::Strategy::All(
|
||||||
|
proto::AllLanguageServers {},
|
||||||
|
)),
|
||||||
|
request: Some(proto::multi_lsp_query::Request::GetImplementation(
|
||||||
|
GetImplementations { position }.to_proto(project_id, buffer_handle.read(cx)),
|
||||||
|
)),
|
||||||
|
});
|
||||||
|
let buffer = buffer_handle.clone();
|
||||||
|
cx.spawn(async move |weak_project, cx| {
|
||||||
|
let Some(project) = weak_project.upgrade() else {
|
||||||
|
return Ok(Vec::new());
|
||||||
|
};
|
||||||
|
let responses = request_task.await?.responses;
|
||||||
|
let actions = join_all(
|
||||||
|
responses
|
||||||
|
.into_iter()
|
||||||
|
.filter_map(|lsp_response| match lsp_response.response? {
|
||||||
|
proto::lsp_response::Response::GetImplementationResponse(response) => {
|
||||||
|
Some(response)
|
||||||
|
}
|
||||||
|
unexpected => {
|
||||||
|
debug_panic!("Unexpected response: {unexpected:?}");
|
||||||
|
None
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.map(|implementations_response| {
|
||||||
|
GetImplementations { position }.response_from_proto(
|
||||||
|
implementations_response,
|
||||||
|
project.clone(),
|
||||||
|
buffer.clone(),
|
||||||
|
cx.clone(),
|
||||||
|
)
|
||||||
|
}),
|
||||||
|
)
|
||||||
|
.await;
|
||||||
|
|
||||||
|
Ok(actions
|
||||||
|
.into_iter()
|
||||||
|
.collect::<Result<Vec<Vec<_>>>>()?
|
||||||
|
.into_iter()
|
||||||
|
.flatten()
|
||||||
|
.dedup()
|
||||||
|
.collect())
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
let implementations_task = self.request_multiple_lsp_locally(
|
||||||
|
buffer_handle,
|
||||||
|
Some(position),
|
||||||
|
GetImplementations { position },
|
||||||
|
cx,
|
||||||
|
);
|
||||||
|
cx.spawn(async move |_, _| {
|
||||||
|
Ok(implementations_task
|
||||||
|
.await
|
||||||
|
.into_iter()
|
||||||
|
.flat_map(|(_, implementations)| implementations)
|
||||||
|
.dedup()
|
||||||
|
.collect())
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn references(
|
||||||
|
&mut self,
|
||||||
|
buffer_handle: &Entity<Buffer>,
|
||||||
|
position: PointUtf16,
|
||||||
|
cx: &mut Context<Self>,
|
||||||
|
) -> Task<Result<Vec<Location>>> {
|
||||||
|
if let Some((upstream_client, project_id)) = self.upstream_client() {
|
||||||
|
let request_task = upstream_client.request(proto::MultiLspQuery {
|
||||||
|
buffer_id: buffer_handle.read(cx).remote_id().into(),
|
||||||
|
version: serialize_version(&buffer_handle.read(cx).version()),
|
||||||
|
project_id,
|
||||||
|
strategy: Some(proto::multi_lsp_query::Strategy::All(
|
||||||
|
proto::AllLanguageServers {},
|
||||||
|
)),
|
||||||
|
request: Some(proto::multi_lsp_query::Request::GetReferences(
|
||||||
|
GetReferences { position }.to_proto(project_id, buffer_handle.read(cx)),
|
||||||
|
)),
|
||||||
|
});
|
||||||
|
let buffer = buffer_handle.clone();
|
||||||
|
cx.spawn(async move |weak_project, cx| {
|
||||||
|
let Some(project) = weak_project.upgrade() else {
|
||||||
|
return Ok(Vec::new());
|
||||||
|
};
|
||||||
|
let responses = request_task.await?.responses;
|
||||||
|
let actions = join_all(
|
||||||
|
responses
|
||||||
|
.into_iter()
|
||||||
|
.filter_map(|lsp_response| match lsp_response.response? {
|
||||||
|
proto::lsp_response::Response::GetReferencesResponse(response) => {
|
||||||
|
Some(response)
|
||||||
|
}
|
||||||
|
unexpected => {
|
||||||
|
debug_panic!("Unexpected response: {unexpected:?}");
|
||||||
|
None
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.map(|references_response| {
|
||||||
|
GetReferences { position }.response_from_proto(
|
||||||
|
references_response,
|
||||||
|
project.clone(),
|
||||||
|
buffer.clone(),
|
||||||
|
cx.clone(),
|
||||||
|
)
|
||||||
|
}),
|
||||||
|
)
|
||||||
|
.await;
|
||||||
|
|
||||||
|
Ok(actions
|
||||||
|
.into_iter()
|
||||||
|
.collect::<Result<Vec<Vec<_>>>>()?
|
||||||
|
.into_iter()
|
||||||
|
.flatten()
|
||||||
|
.dedup()
|
||||||
|
.collect())
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
let references_task = self.request_multiple_lsp_locally(
|
||||||
|
buffer_handle,
|
||||||
|
Some(position),
|
||||||
|
GetReferences { position },
|
||||||
|
cx,
|
||||||
|
);
|
||||||
|
cx.spawn(async move |_, _| {
|
||||||
|
Ok(references_task
|
||||||
|
.await
|
||||||
|
.into_iter()
|
||||||
|
.flat_map(|(_, references)| references)
|
||||||
|
.dedup()
|
||||||
|
.collect())
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub fn code_actions(
|
pub fn code_actions(
|
||||||
&mut self,
|
&mut self,
|
||||||
buffer_handle: &Entity<Buffer>,
|
buffer_handle: &Entity<Buffer>,
|
||||||
|
@ -7886,6 +8248,200 @@ impl LspStore {
|
||||||
.collect(),
|
.collect(),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
Some(proto::multi_lsp_query::Request::GetDefinition(message)) => {
|
||||||
|
let get_definitions = GetDefinitions::from_proto(
|
||||||
|
message,
|
||||||
|
lsp_store.clone(),
|
||||||
|
buffer.clone(),
|
||||||
|
cx.clone(),
|
||||||
|
)
|
||||||
|
.await?;
|
||||||
|
|
||||||
|
let definitions = lsp_store
|
||||||
|
.update(&mut cx, |project, cx| {
|
||||||
|
project.request_multiple_lsp_locally(
|
||||||
|
&buffer,
|
||||||
|
Some(get_definitions.position),
|
||||||
|
get_definitions,
|
||||||
|
cx,
|
||||||
|
)
|
||||||
|
})?
|
||||||
|
.await
|
||||||
|
.into_iter();
|
||||||
|
|
||||||
|
lsp_store.update(&mut cx, |project, cx| proto::MultiLspQueryResponse {
|
||||||
|
responses: definitions
|
||||||
|
.map(|(server_id, definitions)| proto::LspResponse {
|
||||||
|
server_id: server_id.to_proto(),
|
||||||
|
response: Some(proto::lsp_response::Response::GetDefinitionResponse(
|
||||||
|
GetDefinitions::response_to_proto(
|
||||||
|
definitions,
|
||||||
|
project,
|
||||||
|
sender_id,
|
||||||
|
&buffer_version,
|
||||||
|
cx,
|
||||||
|
),
|
||||||
|
)),
|
||||||
|
})
|
||||||
|
.collect(),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
Some(proto::multi_lsp_query::Request::GetDeclaration(message)) => {
|
||||||
|
let get_declarations = GetDeclarations::from_proto(
|
||||||
|
message,
|
||||||
|
lsp_store.clone(),
|
||||||
|
buffer.clone(),
|
||||||
|
cx.clone(),
|
||||||
|
)
|
||||||
|
.await?;
|
||||||
|
|
||||||
|
let declarations = lsp_store
|
||||||
|
.update(&mut cx, |project, cx| {
|
||||||
|
project.request_multiple_lsp_locally(
|
||||||
|
&buffer,
|
||||||
|
Some(get_declarations.position),
|
||||||
|
get_declarations,
|
||||||
|
cx,
|
||||||
|
)
|
||||||
|
})?
|
||||||
|
.await
|
||||||
|
.into_iter();
|
||||||
|
|
||||||
|
lsp_store.update(&mut cx, |project, cx| proto::MultiLspQueryResponse {
|
||||||
|
responses: declarations
|
||||||
|
.map(|(server_id, declarations)| proto::LspResponse {
|
||||||
|
server_id: server_id.to_proto(),
|
||||||
|
response: Some(proto::lsp_response::Response::GetDeclarationResponse(
|
||||||
|
GetDeclarations::response_to_proto(
|
||||||
|
declarations,
|
||||||
|
project,
|
||||||
|
sender_id,
|
||||||
|
&buffer_version,
|
||||||
|
cx,
|
||||||
|
),
|
||||||
|
)),
|
||||||
|
})
|
||||||
|
.collect(),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
Some(proto::multi_lsp_query::Request::GetTypeDefinition(message)) => {
|
||||||
|
let get_type_definitions = GetTypeDefinitions::from_proto(
|
||||||
|
message,
|
||||||
|
lsp_store.clone(),
|
||||||
|
buffer.clone(),
|
||||||
|
cx.clone(),
|
||||||
|
)
|
||||||
|
.await?;
|
||||||
|
|
||||||
|
let type_definitions = lsp_store
|
||||||
|
.update(&mut cx, |project, cx| {
|
||||||
|
project.request_multiple_lsp_locally(
|
||||||
|
&buffer,
|
||||||
|
Some(get_type_definitions.position),
|
||||||
|
get_type_definitions,
|
||||||
|
cx,
|
||||||
|
)
|
||||||
|
})?
|
||||||
|
.await
|
||||||
|
.into_iter();
|
||||||
|
|
||||||
|
lsp_store.update(&mut cx, |project, cx| proto::MultiLspQueryResponse {
|
||||||
|
responses: type_definitions
|
||||||
|
.map(|(server_id, type_definitions)| proto::LspResponse {
|
||||||
|
server_id: server_id.to_proto(),
|
||||||
|
response: Some(
|
||||||
|
proto::lsp_response::Response::GetTypeDefinitionResponse(
|
||||||
|
GetTypeDefinitions::response_to_proto(
|
||||||
|
type_definitions,
|
||||||
|
project,
|
||||||
|
sender_id,
|
||||||
|
&buffer_version,
|
||||||
|
cx,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
})
|
||||||
|
.collect(),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
Some(proto::multi_lsp_query::Request::GetImplementation(message)) => {
|
||||||
|
let get_implementations = GetImplementations::from_proto(
|
||||||
|
message,
|
||||||
|
lsp_store.clone(),
|
||||||
|
buffer.clone(),
|
||||||
|
cx.clone(),
|
||||||
|
)
|
||||||
|
.await?;
|
||||||
|
|
||||||
|
let implementations = lsp_store
|
||||||
|
.update(&mut cx, |project, cx| {
|
||||||
|
project.request_multiple_lsp_locally(
|
||||||
|
&buffer,
|
||||||
|
Some(get_implementations.position),
|
||||||
|
get_implementations,
|
||||||
|
cx,
|
||||||
|
)
|
||||||
|
})?
|
||||||
|
.await
|
||||||
|
.into_iter();
|
||||||
|
|
||||||
|
lsp_store.update(&mut cx, |project, cx| proto::MultiLspQueryResponse {
|
||||||
|
responses: implementations
|
||||||
|
.map(|(server_id, implementations)| proto::LspResponse {
|
||||||
|
server_id: server_id.to_proto(),
|
||||||
|
response: Some(
|
||||||
|
proto::lsp_response::Response::GetImplementationResponse(
|
||||||
|
GetImplementations::response_to_proto(
|
||||||
|
implementations,
|
||||||
|
project,
|
||||||
|
sender_id,
|
||||||
|
&buffer_version,
|
||||||
|
cx,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
})
|
||||||
|
.collect(),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
Some(proto::multi_lsp_query::Request::GetReferences(message)) => {
|
||||||
|
let get_references = GetReferences::from_proto(
|
||||||
|
message,
|
||||||
|
lsp_store.clone(),
|
||||||
|
buffer.clone(),
|
||||||
|
cx.clone(),
|
||||||
|
)
|
||||||
|
.await?;
|
||||||
|
|
||||||
|
let references = lsp_store
|
||||||
|
.update(&mut cx, |project, cx| {
|
||||||
|
project.request_multiple_lsp_locally(
|
||||||
|
&buffer,
|
||||||
|
Some(get_references.position),
|
||||||
|
get_references,
|
||||||
|
cx,
|
||||||
|
)
|
||||||
|
})?
|
||||||
|
.await
|
||||||
|
.into_iter();
|
||||||
|
|
||||||
|
lsp_store.update(&mut cx, |project, cx| proto::MultiLspQueryResponse {
|
||||||
|
responses: references
|
||||||
|
.map(|(server_id, references)| proto::LspResponse {
|
||||||
|
server_id: server_id.to_proto(),
|
||||||
|
response: Some(proto::lsp_response::Response::GetReferencesResponse(
|
||||||
|
GetReferences::response_to_proto(
|
||||||
|
references,
|
||||||
|
project,
|
||||||
|
sender_id,
|
||||||
|
&buffer_version,
|
||||||
|
cx,
|
||||||
|
),
|
||||||
|
)),
|
||||||
|
})
|
||||||
|
.collect(),
|
||||||
|
})
|
||||||
|
}
|
||||||
None => anyhow::bail!("empty multi lsp query request"),
|
None => anyhow::bail!("empty multi lsp query request"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -696,7 +696,7 @@ pub struct MarkupContent {
|
||||||
pub value: String,
|
pub value: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone, PartialEq)]
|
||||||
pub struct LocationLink {
|
pub struct LocationLink {
|
||||||
pub origin: Option<Location>,
|
pub origin: Option<Location>,
|
||||||
pub target: Location,
|
pub target: Location,
|
||||||
|
@ -3342,91 +3342,52 @@ impl Project {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline(never)]
|
pub fn definitions<T: ToPointUtf16>(
|
||||||
fn definition_impl(
|
|
||||||
&mut self,
|
|
||||||
buffer: &Entity<Buffer>,
|
|
||||||
position: PointUtf16,
|
|
||||||
cx: &mut Context<Self>,
|
|
||||||
) -> Task<Result<Vec<LocationLink>>> {
|
|
||||||
self.request_lsp(
|
|
||||||
buffer.clone(),
|
|
||||||
LanguageServerToQuery::FirstCapable,
|
|
||||||
GetDefinition { position },
|
|
||||||
cx,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
pub fn definition<T: ToPointUtf16>(
|
|
||||||
&mut self,
|
&mut self,
|
||||||
buffer: &Entity<Buffer>,
|
buffer: &Entity<Buffer>,
|
||||||
position: T,
|
position: T,
|
||||||
cx: &mut Context<Self>,
|
cx: &mut Context<Self>,
|
||||||
) -> Task<Result<Vec<LocationLink>>> {
|
) -> Task<Result<Vec<LocationLink>>> {
|
||||||
let position = position.to_point_utf16(buffer.read(cx));
|
let position = position.to_point_utf16(buffer.read(cx));
|
||||||
self.definition_impl(buffer, position, cx)
|
self.lsp_store.update(cx, |lsp_store, cx| {
|
||||||
|
lsp_store.definitions(buffer, position, cx)
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
fn declaration_impl(
|
pub fn declarations<T: ToPointUtf16>(
|
||||||
&mut self,
|
|
||||||
buffer: &Entity<Buffer>,
|
|
||||||
position: PointUtf16,
|
|
||||||
cx: &mut Context<Self>,
|
|
||||||
) -> Task<Result<Vec<LocationLink>>> {
|
|
||||||
self.request_lsp(
|
|
||||||
buffer.clone(),
|
|
||||||
LanguageServerToQuery::FirstCapable,
|
|
||||||
GetDeclaration { position },
|
|
||||||
cx,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn declaration<T: ToPointUtf16>(
|
|
||||||
&mut self,
|
&mut self,
|
||||||
buffer: &Entity<Buffer>,
|
buffer: &Entity<Buffer>,
|
||||||
position: T,
|
position: T,
|
||||||
cx: &mut Context<Self>,
|
cx: &mut Context<Self>,
|
||||||
) -> Task<Result<Vec<LocationLink>>> {
|
) -> Task<Result<Vec<LocationLink>>> {
|
||||||
let position = position.to_point_utf16(buffer.read(cx));
|
let position = position.to_point_utf16(buffer.read(cx));
|
||||||
self.declaration_impl(buffer, position, cx)
|
self.lsp_store.update(cx, |lsp_store, cx| {
|
||||||
|
lsp_store.declarations(buffer, position, cx)
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
fn type_definition_impl(
|
pub fn type_definitions<T: ToPointUtf16>(
|
||||||
&mut self,
|
|
||||||
buffer: &Entity<Buffer>,
|
|
||||||
position: PointUtf16,
|
|
||||||
cx: &mut Context<Self>,
|
|
||||||
) -> Task<Result<Vec<LocationLink>>> {
|
|
||||||
self.request_lsp(
|
|
||||||
buffer.clone(),
|
|
||||||
LanguageServerToQuery::FirstCapable,
|
|
||||||
GetTypeDefinition { position },
|
|
||||||
cx,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn type_definition<T: ToPointUtf16>(
|
|
||||||
&mut self,
|
&mut self,
|
||||||
buffer: &Entity<Buffer>,
|
buffer: &Entity<Buffer>,
|
||||||
position: T,
|
position: T,
|
||||||
cx: &mut Context<Self>,
|
cx: &mut Context<Self>,
|
||||||
) -> Task<Result<Vec<LocationLink>>> {
|
) -> Task<Result<Vec<LocationLink>>> {
|
||||||
let position = position.to_point_utf16(buffer.read(cx));
|
let position = position.to_point_utf16(buffer.read(cx));
|
||||||
self.type_definition_impl(buffer, position, cx)
|
self.lsp_store.update(cx, |lsp_store, cx| {
|
||||||
|
lsp_store.type_definitions(buffer, position, cx)
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn implementation<T: ToPointUtf16>(
|
pub fn implementations<T: ToPointUtf16>(
|
||||||
&mut self,
|
&mut self,
|
||||||
buffer: &Entity<Buffer>,
|
buffer: &Entity<Buffer>,
|
||||||
position: T,
|
position: T,
|
||||||
cx: &mut Context<Self>,
|
cx: &mut Context<Self>,
|
||||||
) -> Task<Result<Vec<LocationLink>>> {
|
) -> Task<Result<Vec<LocationLink>>> {
|
||||||
let position = position.to_point_utf16(buffer.read(cx));
|
let position = position.to_point_utf16(buffer.read(cx));
|
||||||
self.request_lsp(
|
self.lsp_store.update(cx, |lsp_store, cx| {
|
||||||
buffer.clone(),
|
lsp_store.implementations(buffer, position, cx)
|
||||||
LanguageServerToQuery::FirstCapable,
|
})
|
||||||
GetImplementation { position },
|
|
||||||
cx,
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn references<T: ToPointUtf16>(
|
pub fn references<T: ToPointUtf16>(
|
||||||
|
@ -3436,12 +3397,9 @@ impl Project {
|
||||||
cx: &mut Context<Self>,
|
cx: &mut Context<Self>,
|
||||||
) -> Task<Result<Vec<Location>>> {
|
) -> Task<Result<Vec<Location>>> {
|
||||||
let position = position.to_point_utf16(buffer.read(cx));
|
let position = position.to_point_utf16(buffer.read(cx));
|
||||||
self.request_lsp(
|
self.lsp_store.update(cx, |lsp_store, cx| {
|
||||||
buffer.clone(),
|
lsp_store.references(buffer, position, cx)
|
||||||
LanguageServerToQuery::FirstCapable,
|
})
|
||||||
GetReferences { position },
|
|
||||||
cx,
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn document_highlights_impl(
|
fn document_highlights_impl(
|
||||||
|
|
|
@ -2993,7 +2993,7 @@ async fn test_definition(cx: &mut gpui::TestAppContext) {
|
||||||
)))
|
)))
|
||||||
});
|
});
|
||||||
let mut definitions = project
|
let mut definitions = project
|
||||||
.update(cx, |project, cx| project.definition(&buffer, 22, cx))
|
.update(cx, |project, cx| project.definitions(&buffer, 22, cx))
|
||||||
.await
|
.await
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
|
|
|
@ -757,6 +757,11 @@ message MultiLspQuery {
|
||||||
GetCodeLens get_code_lens = 8;
|
GetCodeLens get_code_lens = 8;
|
||||||
GetDocumentDiagnostics get_document_diagnostics = 9;
|
GetDocumentDiagnostics get_document_diagnostics = 9;
|
||||||
GetDocumentColor get_document_color = 10;
|
GetDocumentColor get_document_color = 10;
|
||||||
|
GetDefinition get_definition = 11;
|
||||||
|
GetDeclaration get_declaration = 12;
|
||||||
|
GetTypeDefinition get_type_definition = 13;
|
||||||
|
GetImplementation get_implementation = 14;
|
||||||
|
GetReferences get_references = 15;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -795,6 +800,11 @@ message LspResponse {
|
||||||
GetCodeLensResponse get_code_lens_response = 4;
|
GetCodeLensResponse get_code_lens_response = 4;
|
||||||
GetDocumentDiagnosticsResponse get_document_diagnostics_response = 5;
|
GetDocumentDiagnosticsResponse get_document_diagnostics_response = 5;
|
||||||
GetDocumentColorResponse get_document_color_response = 6;
|
GetDocumentColorResponse get_document_color_response = 6;
|
||||||
|
GetDefinitionResponse get_definition_response = 8;
|
||||||
|
GetDeclarationResponse get_declaration_response = 9;
|
||||||
|
GetTypeDefinitionResponse get_type_definition_response = 10;
|
||||||
|
GetImplementationResponse get_implementation_response = 11;
|
||||||
|
GetReferencesResponse get_references_response = 12;
|
||||||
}
|
}
|
||||||
uint64 server_id = 7;
|
uint64 server_id = 7;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue