Detailed changes
@@ -2439,16 +2439,49 @@ impl Editor {
return;
};
- let hover = HoverPopover {
- // TODO: beginning of symbol based on range
- point: action.0,
- text: "Test hover information".to_string(),
- runs: Vec::new(),
+ let snapshot = self.snapshot(cx);
+ let (buffer, buffer_position) = if let Some(output) = self
+ .buffer
+ .read(cx)
+ .text_anchor_for_position(action.0.to_point(&snapshot.display_snapshot), cx)
+ {
+ output
+ } else {
+ return;
};
+ let hover = project.update(cx, |project, cx| {
+ project.hover(&buffer, buffer_position.clone(), cx)
+ });
+
+ let point = action.0.clone();
+
let id = post_inc(&mut self.next_completion_id);
let task = cx.spawn_weak(|this, mut cx| {
async move {
+ // TODO: what to show while language server is loading?
+ let text: String = match hover.await? {
+ None => "Language server is warming up...".into(),
+ Some(hover) => match hover.contents {
+ lsp::HoverContents::Scalar(marked_string) => match marked_string {
+ lsp::MarkedString::String(string) => string,
+ lsp::MarkedString::LanguageString(string) => string.value,
+ },
+ lsp::HoverContents::Array(marked_strings) => {
+ // TODO: what to do?
+ todo!()
+ }
+ lsp::HoverContents::Markup(markup) => markup.value,
+ },
+ };
+
+ let mut hover_popover = HoverPopover {
+ // TODO: fix tooltip to beginning of symbol based on range
+ point,
+ text,
+ runs: Vec::new(),
+ };
+
if let Some(this) = this.upgrade(&cx) {
this.update(&mut cx, |this, cx| {
if !matches!(
@@ -2459,7 +2492,7 @@ impl Editor {
}
if this.focused {
- this.show_context_menu(ContextMenu::Hover(hover), cx);
+ this.show_context_menu(ContextMenu::Hover(hover_popover), cx);
}
cx.notify();
@@ -80,6 +80,10 @@ pub(crate) struct GetDocumentHighlights {
pub position: PointUtf16,
}
+pub(crate) struct GetHover {
+ pub position: PointUtf16,
+}
+
#[async_trait(?Send)]
impl LspCommand for PrepareRename {
type Response = Option<Range<Anchor>>;
@@ -794,3 +798,99 @@ impl LspCommand for GetDocumentHighlights {
message.buffer_id
}
}
+
+#[async_trait(?Send)]
+impl LspCommand for GetHover {
+ // TODO: proper response type
+ type Response = Option<lsp::Hover>;
+ type LspRequest = lsp::request::HoverRequest;
+ type ProtoRequest = proto::GetHover;
+
+ fn to_lsp(&self, path: &Path, cx: &AppContext) -> lsp::HoverParams {
+ lsp::HoverParams {
+ 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(),
+ }
+ }
+
+ async fn response_from_lsp(
+ self,
+ message: Option<lsp::Hover>,
+ project: ModelHandle<Project>,
+ buffer: ModelHandle<Buffer>,
+ cx: AsyncAppContext,
+ ) -> Result<Self::Response> {
+ // let (lsp_adapter, language_server) = project
+ // .read_with(&cx, |project, cx| {
+ // project
+ // .language_server_for_buffer(buffer.read(cx), cx)
+ // .cloned()
+ // })
+ // .ok_or_else(|| anyhow!("no language server found for buffer"))?;
+
+ // TODO: what here?
+ Ok(Some(
+ message.ok_or_else(|| anyhow!("invalid lsp response"))?,
+ ))
+ }
+
+ fn to_proto(&self, project_id: u64, buffer: &Buffer) -> Self::ProtoRequest {
+ proto::GetHover {
+ project_id,
+ buffer_id: buffer.remote_id(),
+ position: Some(language::proto::serialize_anchor(
+ &buffer.anchor_before(self.position),
+ )),
+ version: serialize_version(&buffer.version),
+ }
+ }
+
+ async fn from_proto(
+ message: Self::ProtoRequest,
+ project: ModelHandle<Project>,
+ buffer: ModelHandle<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.read_with(&cx, |buffer, _| position.to_point_utf16(buffer)),
+ })
+ }
+
+ fn response_to_proto(
+ response: Self::Response,
+ project: &mut Project,
+ peer_id: PeerId,
+ buffer_version: &clock::Global,
+ cx: &AppContext,
+ ) -> proto::GetHoverResponse {
+ todo!()
+ }
+
+ async fn response_from_proto(
+ self,
+ message: <Self::ProtoRequest as proto::RequestMessage>::Response,
+ project: ModelHandle<Project>,
+ buffer: ModelHandle<Buffer>,
+ cx: AsyncAppContext,
+ ) -> Result<Self::Response> {
+ todo!()
+ }
+
+ fn buffer_id_from_proto(message: &Self::ProtoRequest) -> u64 {
+ message.buffer_id
+ }
+}
@@ -302,6 +302,7 @@ impl Project {
client.add_model_request_handler(Self::handle_format_buffers);
client.add_model_request_handler(Self::handle_get_code_actions);
client.add_model_request_handler(Self::handle_get_completions);
+ 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::<GetDocumentHighlights>);
client.add_model_request_handler(Self::handle_lsp_command::<GetReferences>);
@@ -2884,6 +2885,17 @@ impl Project {
}
}
+ pub fn hover<T: ToPointUtf16>(
+ &self,
+ buffer: &ModelHandle<Buffer>,
+ position: T,
+ cx: &mut ModelContext<Self>,
+ ) -> Task<Result<Option<lsp::Hover>>> {
+ // TODO: proper return type
+ let position = position.to_point_utf16(buffer.read(cx));
+ self.request_lsp(buffer.clone(), GetHover { position }, cx)
+ }
+
pub fn completions<T: ToPointUtf16>(
&self,
source_buffer_handle: &ModelHandle<Buffer>,
@@ -66,41 +66,43 @@ message Envelope {
ApplyCompletionAdditionalEditsResponse apply_completion_additional_edits_response = 56;
GetCodeActions get_code_actions = 57;
GetCodeActionsResponse get_code_actions_response = 58;
- ApplyCodeAction apply_code_action = 59;
- ApplyCodeActionResponse apply_code_action_response = 60;
- PrepareRename prepare_rename = 61;
- PrepareRenameResponse prepare_rename_response = 62;
- PerformRename perform_rename = 63;
- PerformRenameResponse perform_rename_response = 64;
- SearchProject search_project = 65;
- SearchProjectResponse search_project_response = 66;
-
- GetChannels get_channels = 67;
- GetChannelsResponse get_channels_response = 68;
- JoinChannel join_channel = 69;
- JoinChannelResponse join_channel_response = 70;
- LeaveChannel leave_channel = 71;
- SendChannelMessage send_channel_message = 72;
- SendChannelMessageResponse send_channel_message_response = 73;
- ChannelMessageSent channel_message_sent = 74;
- GetChannelMessages get_channel_messages = 75;
- GetChannelMessagesResponse get_channel_messages_response = 76;
-
- UpdateContacts update_contacts = 77;
- UpdateInviteInfo update_invite_info = 78;
- ShowContacts show_contacts = 79;
-
- GetUsers get_users = 80;
- FuzzySearchUsers fuzzy_search_users = 81;
- UsersResponse users_response = 82;
- RequestContact request_contact = 83;
- RespondToContactRequest respond_to_contact_request = 84;
- RemoveContact remove_contact = 85;
-
- Follow follow = 86;
- FollowResponse follow_response = 87;
- UpdateFollowers update_followers = 88;
- Unfollow unfollow = 89;
+ GetHover get_hover = 59;
+ GetHoverResponse get_hover_response = 60;
+ ApplyCodeAction apply_code_action = 61;
+ ApplyCodeActionResponse apply_code_action_response = 62;
+ PrepareRename prepare_rename = 63;
+ PrepareRenameResponse prepare_rename_response = 64;
+ PerformRename perform_rename = 65;
+ PerformRenameResponse perform_rename_response = 66;
+ SearchProject search_project = 67;
+ SearchProjectResponse search_project_response = 68;
+
+ GetChannels get_channels = 69;
+ GetChannelsResponse get_channels_response = 70;
+ JoinChannel join_channel = 71;
+ JoinChannelResponse join_channel_response = 72;
+ LeaveChannel leave_channel = 73;
+ SendChannelMessage send_channel_message = 74;
+ SendChannelMessageResponse send_channel_message_response = 75;
+ ChannelMessageSent channel_message_sent = 76;
+ GetChannelMessages get_channel_messages = 77;
+ GetChannelMessagesResponse get_channel_messages_response = 78;
+
+ UpdateContacts update_contacts = 79;
+ UpdateInviteInfo update_invite_info = 80;
+ ShowContacts show_contacts = 81;
+
+ GetUsers get_users = 82;
+ FuzzySearchUsers fuzzy_search_users = 83;
+ UsersResponse users_response = 84;
+ RequestContact request_contact = 85;
+ RespondToContactRequest respond_to_contact_request = 86;
+ RemoveContact remove_contact = 87;
+
+ Follow follow = 88;
+ FollowResponse follow_response = 89;
+ UpdateFollowers update_followers = 90;
+ Unfollow unfollow = 91;
}
}
@@ -426,6 +428,18 @@ message GetCodeActionsResponse {
repeated VectorClockEntry version = 2;
}
+message GetHover {
+ uint64 project_id = 1;
+ uint64 buffer_id = 2;
+ Anchor position = 3;
+ repeated VectorClockEntry version = 5;
+}
+
+message GetHoverResponse {
+ repeated CodeAction actions = 1;
+ repeated VectorClockEntry version = 2;
+}
+
message ApplyCodeAction {
uint64 project_id = 1;
uint64 buffer_id = 2;
@@ -99,6 +99,8 @@ messages!(
(GetChannelsResponse, Foreground),
(GetCodeActions, Background),
(GetCodeActionsResponse, Background),
+ (GetHover, Background),
+ (GetHoverResponse, Background),
(GetCompletions, Background),
(GetCompletionsResponse, Background),
(GetDefinition, Background),
@@ -175,6 +177,7 @@ request_messages!(
(GetChannelMessages, GetChannelMessagesResponse),
(GetChannels, GetChannelsResponse),
(GetCodeActions, GetCodeActionsResponse),
+ (GetHover, GetHoverResponse),
(GetCompletions, GetCompletionsResponse),
(GetDefinition, GetDefinitionResponse),
(GetDocumentHighlights, GetDocumentHighlightsResponse),
@@ -221,6 +224,7 @@ entity_messages!(
GetCompletions,
GetDefinition,
GetDocumentHighlights,
+ GetHover,
GetReferences,
GetProjectSymbols,
JoinProject,