mirror of
https://github.com/zed-industries/zed.git
synced 2024-11-08 07:35:01 +03:00
Editor: support go to implementation (#7890)
Release Notes: - Added "Go to implementation" support in editor.
This commit is contained in:
parent
94bc216bbd
commit
b716035d02
@ -165,6 +165,8 @@ gpui::actions!(
|
||||
GoToPrevHunk,
|
||||
GoToTypeDefinition,
|
||||
GoToTypeDefinitionSplit,
|
||||
GoToImplementation,
|
||||
GoToImplementationSplit,
|
||||
OpenUrl,
|
||||
HalfPageDown,
|
||||
HalfPageUp,
|
||||
|
@ -1346,6 +1346,7 @@ pub(crate) struct NavigationData {
|
||||
enum GotoDefinitionKind {
|
||||
Symbol,
|
||||
Type,
|
||||
Implementation,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
@ -7352,6 +7353,18 @@ impl Editor {
|
||||
self.go_to_definition_of_kind(GotoDefinitionKind::Symbol, false, cx);
|
||||
}
|
||||
|
||||
pub fn go_to_implementation(&mut self, _: &GoToImplementation, cx: &mut ViewContext<Self>) {
|
||||
self.go_to_definition_of_kind(GotoDefinitionKind::Implementation, false, cx);
|
||||
}
|
||||
|
||||
pub fn go_to_implementation_split(
|
||||
&mut self,
|
||||
_: &GoToImplementationSplit,
|
||||
cx: &mut ViewContext<Self>,
|
||||
) {
|
||||
self.go_to_definition_of_kind(GotoDefinitionKind::Implementation, true, cx);
|
||||
}
|
||||
|
||||
pub fn go_to_type_definition(&mut self, _: &GoToTypeDefinition, cx: &mut ViewContext<Self>) {
|
||||
self.go_to_definition_of_kind(GotoDefinitionKind::Type, false, cx);
|
||||
}
|
||||
@ -7389,6 +7402,7 @@ impl Editor {
|
||||
let definitions = project.update(cx, |project, cx| match kind {
|
||||
GotoDefinitionKind::Symbol => project.definition(&buffer, head, cx),
|
||||
GotoDefinitionKind::Type => project.type_definition(&buffer, head, cx),
|
||||
GotoDefinitionKind::Implementation => project.implementation(&buffer, head, cx),
|
||||
});
|
||||
|
||||
cx.spawn(|editor, mut cx| async move {
|
||||
|
@ -260,6 +260,8 @@ impl EditorElement {
|
||||
register_action(view, cx, Editor::go_to_prev_hunk);
|
||||
register_action(view, cx, Editor::go_to_definition);
|
||||
register_action(view, cx, Editor::go_to_definition_split);
|
||||
register_action(view, cx, Editor::go_to_implementation);
|
||||
register_action(view, cx, Editor::go_to_implementation_split);
|
||||
register_action(view, cx, Editor::go_to_type_definition);
|
||||
register_action(view, cx, Editor::go_to_type_definition_split);
|
||||
register_action(view, cx, Editor::open_url);
|
||||
|
@ -1,6 +1,6 @@
|
||||
use crate::{
|
||||
DisplayPoint, Editor, EditorMode, FindAllReferences, GoToDefinition, GoToTypeDefinition,
|
||||
Rename, RevealInFinder, SelectMode, ToggleCodeActions,
|
||||
DisplayPoint, Editor, EditorMode, FindAllReferences, GoToDefinition, GoToImplementation,
|
||||
GoToTypeDefinition, Rename, RevealInFinder, SelectMode, ToggleCodeActions,
|
||||
};
|
||||
use gpui::{DismissEvent, Pixels, Point, Subscription, View, ViewContext};
|
||||
|
||||
@ -48,6 +48,7 @@ pub fn deploy_context_menu(
|
||||
menu.action("Rename Symbol", Box::new(Rename))
|
||||
.action("Go to Definition", Box::new(GoToDefinition))
|
||||
.action("Go to Type Definition", Box::new(GoToTypeDefinition))
|
||||
.action("Go to Implementation", Box::new(GoToImplementation))
|
||||
.action("Find All References", Box::new(FindAllReferences))
|
||||
.action(
|
||||
"Code Actions",
|
||||
|
@ -1136,6 +1136,7 @@ impl LanguageServer {
|
||||
document_formatting_provider: Some(OneOf::Left(true)),
|
||||
document_range_formatting_provider: Some(OneOf::Left(true)),
|
||||
definition_provider: Some(OneOf::Left(true)),
|
||||
implementation_provider: Some(ImplementationProviderCapability::Simple(true)),
|
||||
type_definition_provider: Some(TypeDefinitionProviderCapability::Simple(true)),
|
||||
..Default::default()
|
||||
}
|
||||
|
@ -105,6 +105,10 @@ pub(crate) struct GetTypeDefinition {
|
||||
pub position: PointUtf16,
|
||||
}
|
||||
|
||||
pub(crate) struct GetImplementation {
|
||||
pub position: PointUtf16,
|
||||
}
|
||||
|
||||
pub(crate) struct GetReferences {
|
||||
pub position: PointUtf16,
|
||||
}
|
||||
@ -492,6 +496,99 @@ impl LspCommand for GetDefinition {
|
||||
}
|
||||
}
|
||||
|
||||
#[async_trait(?Send)]
|
||||
impl LspCommand for GetImplementation {
|
||||
type Response = Vec<LocationLink>;
|
||||
type LspRequest = lsp::request::GotoImplementation;
|
||||
type ProtoRequest = proto::GetImplementation;
|
||||
|
||||
fn to_lsp(
|
||||
&self,
|
||||
path: &Path,
|
||||
_: &Buffer,
|
||||
_: &Arc<LanguageServer>,
|
||||
_: &AppContext,
|
||||
) -> lsp::GotoImplementationParams {
|
||||
lsp::GotoImplementationParams {
|
||||
text_document_position_params: lsp::TextDocumentPositionParams {
|
||||
text_document: lsp::TextDocumentIdentifier {
|
||||
uri: lsp::Url::from_file_path(path).unwrap(),
|
||||
},
|
||||
position: point_to_lsp(self.position),
|
||||
},
|
||||
work_done_progress_params: Default::default(),
|
||||
partial_result_params: Default::default(),
|
||||
}
|
||||
}
|
||||
|
||||
async fn response_from_lsp(
|
||||
self,
|
||||
message: Option<lsp::GotoImplementationResponse>,
|
||||
project: Model<Project>,
|
||||
buffer: Model<Buffer>,
|
||||
server_id: LanguageServerId,
|
||||
cx: AsyncAppContext,
|
||||
) -> Result<Vec<LocationLink>> {
|
||||
location_links_from_lsp(message, project, buffer, server_id, cx).await
|
||||
}
|
||||
|
||||
fn to_proto(&self, project_id: u64, buffer: &Buffer) -> proto::GetImplementation {
|
||||
proto::GetImplementation {
|
||||
project_id,
|
||||
buffer_id: buffer.remote_id().into(),
|
||||
position: Some(language::proto::serialize_anchor(
|
||||
&buffer.anchor_before(self.position),
|
||||
)),
|
||||
version: serialize_version(&buffer.version()),
|
||||
}
|
||||
}
|
||||
|
||||
async fn from_proto(
|
||||
message: proto::GetImplementation,
|
||||
_: Model<Project>,
|
||||
buffer: Model<Buffer>,
|
||||
mut cx: AsyncAppContext,
|
||||
) -> Result<Self> {
|
||||
let position = message
|
||||
.position
|
||||
.and_then(deserialize_anchor)
|
||||
.ok_or_else(|| anyhow!("invalid position"))?;
|
||||
buffer
|
||||
.update(&mut cx, |buffer, _| {
|
||||
buffer.wait_for_version(deserialize_version(&message.version))
|
||||
})?
|
||||
.await?;
|
||||
Ok(Self {
|
||||
position: buffer.update(&mut cx, |buffer, _| position.to_point_utf16(buffer))?,
|
||||
})
|
||||
}
|
||||
|
||||
fn response_to_proto(
|
||||
response: Vec<LocationLink>,
|
||||
project: &mut Project,
|
||||
peer_id: PeerId,
|
||||
_: &clock::Global,
|
||||
cx: &mut AppContext,
|
||||
) -> proto::GetImplementationResponse {
|
||||
let links = location_links_to_proto(response, project, peer_id, cx);
|
||||
proto::GetImplementationResponse { links }
|
||||
}
|
||||
|
||||
async fn response_from_proto(
|
||||
self,
|
||||
message: proto::GetImplementationResponse,
|
||||
project: Model<Project>,
|
||||
_: Model<Buffer>,
|
||||
cx: AsyncAppContext,
|
||||
) -> Result<Vec<LocationLink>> {
|
||||
location_links_from_proto(message.links, project, cx).await
|
||||
}
|
||||
|
||||
fn buffer_id_from_proto(message: &proto::GetImplementation) -> Result<BufferId> {
|
||||
BufferId::new(message.buffer_id)
|
||||
}
|
||||
}
|
||||
|
||||
#[async_trait(?Send)]
|
||||
impl LspCommand for GetTypeDefinition {
|
||||
type Response = Vec<LocationLink>;
|
||||
|
@ -4646,6 +4646,7 @@ impl Project {
|
||||
cx,
|
||||
)
|
||||
}
|
||||
|
||||
pub fn type_definition<T: ToPointUtf16>(
|
||||
&self,
|
||||
buffer: &Model<Buffer>,
|
||||
@ -4653,10 +4654,33 @@ impl Project {
|
||||
cx: &mut ModelContext<Self>,
|
||||
) -> Task<Result<Vec<LocationLink>>> {
|
||||
let position = position.to_point_utf16(buffer.read(cx));
|
||||
|
||||
self.type_definition_impl(buffer, position, cx)
|
||||
}
|
||||
|
||||
fn implementation_impl(
|
||||
&self,
|
||||
buffer: &Model<Buffer>,
|
||||
position: PointUtf16,
|
||||
cx: &mut ModelContext<Self>,
|
||||
) -> Task<Result<Vec<LocationLink>>> {
|
||||
self.request_lsp(
|
||||
buffer.clone(),
|
||||
LanguageServerToQuery::Primary,
|
||||
GetImplementation { position },
|
||||
cx,
|
||||
)
|
||||
}
|
||||
|
||||
pub fn implementation<T: ToPointUtf16>(
|
||||
&self,
|
||||
buffer: &Model<Buffer>,
|
||||
position: T,
|
||||
cx: &mut ModelContext<Self>,
|
||||
) -> Task<Result<Vec<LocationLink>>> {
|
||||
let position = position.to_point_utf16(buffer.read(cx));
|
||||
self.implementation_impl(buffer, position, cx)
|
||||
}
|
||||
|
||||
fn references_impl(
|
||||
&self,
|
||||
buffer: &Model<Buffer>,
|
||||
|
@ -12,6 +12,14 @@ message Envelope {
|
||||
uint32 id = 1;
|
||||
optional uint32 responding_to = 2;
|
||||
optional PeerId original_sender_id = 3;
|
||||
|
||||
/*
|
||||
When you are adding a new message type, instead of adding it in semantic order
|
||||
and bumping the message ID's of everything that follows, add it at the end of the
|
||||
file and bump the max number. See this
|
||||
https://github.com/zed-industries/zed/pull/7890#discussion_r1496621823
|
||||
|
||||
*/
|
||||
oneof payload {
|
||||
Hello hello = 4;
|
||||
Ack ack = 5;
|
||||
@ -48,6 +56,7 @@ message Envelope {
|
||||
GetDefinitionResponse get_definition_response = 33;
|
||||
GetTypeDefinition get_type_definition = 34;
|
||||
GetTypeDefinitionResponse get_type_definition_response = 35;
|
||||
|
||||
GetReferences get_references = 36;
|
||||
GetReferencesResponse get_references_response = 37;
|
||||
GetDocumentHighlights get_document_highlights = 38;
|
||||
@ -184,6 +193,9 @@ message Envelope {
|
||||
SetRoomParticipantRole set_room_participant_role = 156;
|
||||
|
||||
UpdateUserChannels update_user_channels = 157;
|
||||
|
||||
GetImplementation get_implementation = 162;
|
||||
GetImplementationResponse get_implementation_response = 163;
|
||||
}
|
||||
|
||||
reserved 158 to 161;
|
||||
@ -503,6 +515,16 @@ message GetTypeDefinition {
|
||||
message GetTypeDefinitionResponse {
|
||||
repeated LocationLink links = 1;
|
||||
}
|
||||
message GetImplementation {
|
||||
uint64 project_id = 1;
|
||||
uint64 buffer_id = 2;
|
||||
Anchor position = 3;
|
||||
repeated VectorClockEntry version = 4;
|
||||
}
|
||||
|
||||
message GetImplementationResponse {
|
||||
repeated LocationLink links = 1;
|
||||
}
|
||||
|
||||
message GetReferences {
|
||||
uint64 project_id = 1;
|
||||
|
@ -192,6 +192,8 @@ messages!(
|
||||
(GetReferencesResponse, Background),
|
||||
(GetTypeDefinition, Background),
|
||||
(GetTypeDefinitionResponse, Background),
|
||||
(GetImplementation, Background),
|
||||
(GetImplementationResponse, Background),
|
||||
(GetUsers, Foreground),
|
||||
(Hello, Foreground),
|
||||
(IncomingCall, Foreground),
|
||||
@ -312,6 +314,7 @@ request_messages!(
|
||||
(GetCodeActions, GetCodeActionsResponse),
|
||||
(GetCompletions, GetCompletionsResponse),
|
||||
(GetDefinition, GetDefinitionResponse),
|
||||
(GetImplementation, GetImplementationResponse),
|
||||
(GetDocumentHighlights, GetDocumentHighlightsResponse),
|
||||
(GetHover, GetHoverResponse),
|
||||
(GetNotifications, GetNotificationsResponse),
|
||||
@ -388,6 +391,7 @@ entity_messages!(
|
||||
GetCodeActions,
|
||||
GetCompletions,
|
||||
GetDefinition,
|
||||
GetImplementation,
|
||||
GetDocumentHighlights,
|
||||
GetHover,
|
||||
GetProjectSymbols,
|
||||
|
Loading…
Reference in New Issue
Block a user