@@ -5193,6 +5193,17 @@ impl Project {
position: PointUtf16,
cx: &mut ModelContext<Self>,
) -> Task<Vec<Hover>> {
+ fn remove_empty_hover_blocks(mut hover: Hover) -> Option<Hover> {
+ hover
+ .contents
+ .retain(|hover_block| !hover_block.text.trim().is_empty());
+ if hover.contents.is_empty() {
+ None
+ } else {
+ Some(hover)
+ }
+ }
+
if self.is_local() {
let snapshot = buffer.read(cx).snapshot();
let offset = position.to_offset(&snapshot);
@@ -5225,7 +5236,11 @@ impl Project {
cx.spawn(|_, _| async move {
let mut hovers = Vec::with_capacity(hover_responses.len());
while let Some(hover_response) = hover_responses.next().await {
- if let Some(hover) = hover_response.log_err().flatten() {
+ if let Some(hover) = hover_response
+ .log_err()
+ .flatten()
+ .and_then(remove_empty_hover_blocks)
+ {
hovers.push(hover);
}
}
@@ -5243,6 +5258,7 @@ impl Project {
.await
.log_err()
.flatten()
+ .and_then(remove_empty_hover_blocks)
.map(|hover| vec![hover])
.unwrap_or_default()
})
@@ -4556,6 +4556,76 @@ async fn test_multiple_language_server_hovers(cx: &mut gpui::TestAppContext) {
);
}
+#[gpui::test]
+async fn test_hovers_with_empty_parts(cx: &mut gpui::TestAppContext) {
+ init_test(cx);
+
+ let fs = FakeFs::new(cx.executor());
+ fs.insert_tree(
+ "/dir",
+ json!({
+ "a.ts": "a",
+ }),
+ )
+ .await;
+
+ let project = Project::test(fs, ["/dir".as_ref()], cx).await;
+
+ let language_registry = project.read_with(cx, |project, _| project.languages().clone());
+ language_registry.add(typescript_lang());
+ let mut fake_language_servers = language_registry.register_fake_lsp_adapter(
+ "TypeScript",
+ FakeLspAdapter {
+ capabilities: lsp::ServerCapabilities {
+ hover_provider: Some(lsp::HoverProviderCapability::Simple(true)),
+ ..lsp::ServerCapabilities::default()
+ },
+ ..FakeLspAdapter::default()
+ },
+ );
+
+ let buffer = project
+ .update(cx, |p, cx| p.open_local_buffer("/dir/a.ts", cx))
+ .await
+ .unwrap();
+ cx.executor().run_until_parked();
+
+ let fake_server = fake_language_servers
+ .next()
+ .await
+ .expect("failed to get the language server");
+
+ let mut request_handled =
+ fake_server.handle_request::<lsp::request::HoverRequest, _, _>(move |_, _| async move {
+ Ok(Some(lsp::Hover {
+ contents: lsp::HoverContents::Array(vec![
+ lsp::MarkedString::String("".to_string()),
+ lsp::MarkedString::String(" ".to_string()),
+ lsp::MarkedString::String("\n\n\n".to_string()),
+ ]),
+ range: None,
+ }))
+ });
+
+ let hover_task = project.update(cx, |project, cx| {
+ project.hover(&buffer, Point::new(0, 0), cx)
+ });
+ let () = request_handled
+ .next()
+ .await
+ .expect("All hover requests should have been triggered");
+ assert_eq!(
+ Vec::<String>::new(),
+ hover_task
+ .await
+ .into_iter()
+ .map(|hover| hover.contents.iter().map(|block| &block.text).join("|"))
+ .sorted()
+ .collect::<Vec<_>>(),
+ "Empty hover parts should be ignored"
+ );
+}
+
#[gpui::test]
async fn test_multiple_language_server_actions(cx: &mut gpui::TestAppContext) {
init_test(cx);