Detailed changes
@@ -127,7 +127,9 @@
"cmd-'": "editor::ToggleHunkDiff",
"cmd-\"": "editor::ExpandAllHunkDiffs",
"cmd-alt-g b": "editor::ToggleGitBlame",
- "cmd-i": "editor::ShowSignatureHelp"
+ "cmd-i": "editor::ShowSignatureHelp",
+ "ctrl-f12": "editor::GoToDeclaration",
+ "alt-ctrl-f12": "editor::GoToDeclarationSplit"
}
},
{
@@ -89,8 +89,9 @@
"g t": "pane::ActivateNextItem",
"g shift-t": "pane::ActivatePrevItem",
"g d": "editor::GoToDefinition",
- "g shift-d": "editor::GoToTypeDefinition",
- "g cmd-d": "editor::GoToImplementation",
+ "g shift-d": "editor::GoToDeclaration",
+ "g y": "editor::GoToTypeDefinition",
+ "g shift-i": "editor::GoToImplementation",
"g x": "editor::OpenUrl",
"g n": "vim::SelectNextMatch",
"g shift-n": "vim::SelectPreviousMatch",
@@ -210,6 +210,8 @@ gpui::actions!(
Format,
GoToDefinition,
GoToDefinitionSplit,
+ GoToDeclaration,
+ GoToDeclarationSplit,
GoToDiagnostic,
GoToHunk,
GoToImplementation,
@@ -1539,6 +1539,7 @@ pub(crate) struct NavigationData {
enum GotoDefinitionKind {
Symbol,
+ Declaration,
Type,
Implementation,
}
@@ -8948,6 +8949,22 @@ impl Editor {
self.go_to_definition_of_kind(GotoDefinitionKind::Symbol, false, cx)
}
+ pub fn go_to_declaration(
+ &mut self,
+ _: &GoToDeclaration,
+ cx: &mut ViewContext<Self>,
+ ) -> Task<Result<bool>> {
+ self.go_to_definition_of_kind(GotoDefinitionKind::Declaration, false, cx)
+ }
+
+ pub fn go_to_declaration_split(
+ &mut self,
+ _: &GoToDeclaration,
+ cx: &mut ViewContext<Self>,
+ ) -> Task<Result<bool>> {
+ self.go_to_definition_of_kind(GotoDefinitionKind::Declaration, true, cx)
+ }
+
pub fn go_to_implementation(
&mut self,
_: &GoToImplementation,
@@ -9008,6 +9025,7 @@ impl Editor {
let project = workspace.read(cx).project().clone();
let definitions = project.update(cx, |project, cx| match kind {
GotoDefinitionKind::Symbol => project.definition(&buffer, head, cx),
+ GotoDefinitionKind::Declaration => project.declaration(&buffer, head, cx),
GotoDefinitionKind::Type => project.type_definition(&buffer, head, cx),
GotoDefinitionKind::Implementation => project.implementation(&buffer, head, cx),
});
@@ -300,6 +300,12 @@ impl EditorElement {
register_action(view, cx, |editor, a, cx| {
editor.go_to_definition_split(a, cx).detach_and_log_err(cx);
});
+ register_action(view, cx, |editor, a, cx| {
+ editor.go_to_declaration(a, cx).detach_and_log_err(cx);
+ });
+ register_action(view, cx, |editor, a, cx| {
+ editor.go_to_declaration_split(a, cx).detach_and_log_err(cx);
+ });
register_action(view, cx, |editor, a, cx| {
editor.go_to_implementation(a, cx).detach_and_log_err(cx);
});
@@ -1,5 +1,6 @@
use std::ops::Range;
+use crate::GoToDeclaration;
use crate::{
selections_collection::SelectionsCollection, Copy, CopyPermalinkToLine, Cut, DisplayPoint,
DisplaySnapshot, Editor, EditorMode, FindAllReferences, GoToDefinition, GoToImplementation,
@@ -163,6 +164,7 @@ pub fn deploy_context_menu(
.on_blur_subscription(Subscription::new(|| {}))
.action("Rename Symbol", Box::new(Rename))
.action("Go to Definition", Box::new(GoToDefinition))
+ .action("Go to Declaration", Box::new(GoToDeclaration))
.action("Go to Type Definition", Box::new(GoToTypeDefinition))
.action("Go to Implementation", Box::new(GoToImplementation))
.action("Find All References", Box::new(FindAllReferences))
@@ -117,6 +117,10 @@ pub struct GetDefinition {
pub position: PointUtf16,
}
+pub(crate) struct GetDeclaration {
+ pub position: PointUtf16,
+}
+
pub(crate) struct GetTypeDefinition {
pub position: PointUtf16,
}
@@ -521,6 +525,106 @@ impl LspCommand for GetDefinition {
}
}
+#[async_trait(?Send)]
+impl LspCommand for GetDeclaration {
+ type Response = Vec<LocationLink>;
+ type LspRequest = lsp::request::GotoDeclaration;
+ type ProtoRequest = proto::GetDeclaration;
+
+ fn check_capabilities(&self, capabilities: AdapterServerCapabilities) -> bool {
+ capabilities
+ .server_capabilities
+ .declaration_provider
+ .is_some()
+ }
+
+ fn to_lsp(
+ &self,
+ path: &Path,
+ _: &Buffer,
+ _: &Arc<LanguageServer>,
+ _: &AppContext,
+ ) -> lsp::GotoDeclarationParams {
+ lsp::GotoDeclarationParams {
+ 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::GotoDeclarationResponse>,
+ 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::GetDeclaration {
+ proto::GetDeclaration {
+ 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::GetDeclaration,
+ _: 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::GetDeclarationResponse {
+ let links = location_links_to_proto(response, project, peer_id, cx);
+ proto::GetDeclarationResponse { links }
+ }
+
+ async fn response_from_proto(
+ self,
+ message: proto::GetDeclarationResponse,
+ 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::GetDeclaration) -> Result<BufferId> {
+ BufferId::new(message.buffer_id)
+ }
+}
+
#[async_trait(?Send)]
impl LspCommand for GetImplementation {
type Response = Vec<LocationLink>;
@@ -714,6 +714,7 @@ impl Project {
client.add_model_request_handler(Self::handle_lsp_command::<GetCompletions>);
client.add_model_request_handler(Self::handle_lsp_command::<GetHover>);
client.add_model_request_handler(Self::handle_lsp_command::<GetDefinition>);
+ client.add_model_request_handler(Self::handle_lsp_command::<GetDeclaration>);
client.add_model_request_handler(Self::handle_lsp_command::<GetTypeDefinition>);
client.add_model_request_handler(Self::handle_lsp_command::<GetDocumentHighlights>);
client.add_model_request_handler(Self::handle_lsp_command::<GetReferences>);
@@ -5463,6 +5464,30 @@ impl Project {
self.definition_impl(buffer, position, cx)
}
+ fn declaration_impl(
+ &self,
+ buffer: &Model<Buffer>,
+ position: PointUtf16,
+ cx: &mut ModelContext<Self>,
+ ) -> Task<Result<Vec<LocationLink>>> {
+ self.request_lsp(
+ buffer.clone(),
+ LanguageServerToQuery::Primary,
+ GetDeclaration { position },
+ cx,
+ )
+ }
+
+ pub fn declaration<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.declaration_impl(buffer, position, cx)
+ }
+
fn type_definition_impl(
&self,
buffer: &Model<Buffer>,
@@ -48,6 +48,8 @@ message Envelope {
GetDefinition get_definition = 32;
GetDefinitionResponse get_definition_response = 33;
+ GetDeclaration get_declaration = 237;
+ GetDeclarationResponse get_declaration_response = 238; // current max
GetTypeDefinition get_type_definition = 34;
GetTypeDefinitionResponse get_type_definition_response = 35;
@@ -696,12 +698,23 @@ message GetDefinition {
uint64 buffer_id = 2;
Anchor position = 3;
repeated VectorClockEntry version = 4;
- }
+}
message GetDefinitionResponse {
repeated LocationLink links = 1;
}
+message GetDeclaration {
+ uint64 project_id = 1;
+ uint64 buffer_id = 2;
+ Anchor position = 3;
+ repeated VectorClockEntry version = 4;
+}
+
+message GetDeclarationResponse {
+ repeated LocationLink links = 1;
+}
+
message GetTypeDefinition {
uint64 project_id = 1;
uint64 buffer_id = 2;
@@ -239,6 +239,8 @@ messages!(
(GetCompletionsResponse, Background),
(GetDefinition, Background),
(GetDefinitionResponse, Background),
+ (GetDeclaration, Background),
+ (GetDeclarationResponse, Background),
(GetDocumentHighlights, Background),
(GetDocumentHighlightsResponse, Background),
(GetHover, Background),
@@ -437,6 +439,7 @@ request_messages!(
(GetCodeActions, GetCodeActionsResponse),
(GetCompletions, GetCompletionsResponse),
(GetDefinition, GetDefinitionResponse),
+ (GetDeclaration, GetDeclarationResponse),
(GetImplementation, GetImplementationResponse),
(GetDocumentHighlights, GetDocumentHighlightsResponse),
(GetHover, GetHoverResponse),
@@ -551,6 +554,7 @@ entity_messages!(
GetCodeActions,
GetCompletions,
GetDefinition,
+ GetDeclaration,
GetImplementation,
GetDocumentHighlights,
GetHover,
@@ -145,6 +145,7 @@ pub fn app_menus() -> Vec<Menu> {
MenuItem::action("Go to Line/Column...", editor::actions::ToggleGoToLine),
MenuItem::separator(),
MenuItem::action("Go to Definition", editor::actions::GoToDefinition),
+ MenuItem::action("Go to Declaration", editor::actions::GoToDeclaration),
MenuItem::action("Go to Type Definition", editor::actions::GoToTypeDefinition),
MenuItem::action("Find All References", editor::actions::FindAllReferences),
MenuItem::separator(),
@@ -218,6 +218,8 @@ See the [tasks documentation](/docs/tasks#custom-keybindings-for-tasks) for more
| Format | Editor | `⌘ + Shift + I` |
| Go to definition | Editor | `F12` |
| Go to definition split | Editor | `Alt + F12` |
+| Go to declaration | Editor | `Ctrl + F12` |
+| Go to declaration split | Editor | `Alt + Ctrl + F12` |
| Go to diagnostic | Editor | `F8` |
| Go to implementation | Editor | `Shift + F12` |
| Go to prev diagnostic | Editor | `Shift + F8` |
@@ -17,8 +17,10 @@ Vim mode has several "core Zed" key bindings, that will help you make the most o
```
# Language server
g d Go to definition
-g D Go to type definition
-g cmd-d Go to implementation
+g D Go to declaration
+g y Go to type definition
+g I Go to implementation
+
c d Rename (change definition)
g A Go to All references to the current word