diff --git a/crates/project/src/project.rs b/crates/project/src/project.rs index dcbb72883b..f1802a9b00 100644 --- a/crates/project/src/project.rs +++ b/crates/project/src/project.rs @@ -5193,6 +5193,17 @@ impl Project { position: PointUtf16, cx: &mut ModelContext, ) -> Task> { + fn remove_empty_hover_blocks(mut hover: Hover) -> Option { + 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() }) diff --git a/crates/project/src/project_tests.rs b/crates/project/src/project_tests.rs index aa96e1f974..29ca72fb30 100644 --- a/crates/project/src/project_tests.rs +++ b/crates/project/src/project_tests.rs @@ -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::(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::::new(), + hover_task + .await + .into_iter() + .map(|hover| hover.contents.iter().map(|block| &block.text).join("|")) + .sorted() + .collect::>(), + "Empty hover parts should be ignored" + ); +} + #[gpui::test] async fn test_multiple_language_server_actions(cx: &mut gpui::TestAppContext) { init_test(cx);