Detailed changes
@@ -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;
@@ -183,7 +192,10 @@ message Envelope {
LspExtExpandMacroResponse lsp_ext_expand_macro_response = 155;
SetRoomParticipantRole set_room_participant_role = 156;
- UpdateUserChannels update_user_channels = 157;
+ 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,