Omit empty hovers (#9967)

Closes https://github.com/zed-industries/zed/issues/9962

Release Notes:

- N/A
This commit is contained in:
Kirill Bulatov 2024-03-29 20:59:01 +01:00 committed by GitHub
parent e252f90e30
commit 5d531037c4
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 87 additions and 1 deletions

View File

@ -5193,6 +5193,17 @@ impl Project {
position: PointUtf16, position: PointUtf16,
cx: &mut ModelContext<Self>, cx: &mut ModelContext<Self>,
) -> Task<Vec<Hover>> { ) -> 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() { if self.is_local() {
let snapshot = buffer.read(cx).snapshot(); let snapshot = buffer.read(cx).snapshot();
let offset = position.to_offset(&snapshot); let offset = position.to_offset(&snapshot);
@ -5225,7 +5236,11 @@ impl Project {
cx.spawn(|_, _| async move { cx.spawn(|_, _| async move {
let mut hovers = Vec::with_capacity(hover_responses.len()); let mut hovers = Vec::with_capacity(hover_responses.len());
while let Some(hover_response) = hover_responses.next().await { 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); hovers.push(hover);
} }
} }
@ -5243,6 +5258,7 @@ impl Project {
.await .await
.log_err() .log_err()
.flatten() .flatten()
.and_then(remove_empty_hover_blocks)
.map(|hover| vec![hover]) .map(|hover| vec![hover])
.unwrap_or_default() .unwrap_or_default()
}) })

View File

@ -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] #[gpui::test]
async fn test_multiple_language_server_actions(cx: &mut gpui::TestAppContext) { async fn test_multiple_language_server_actions(cx: &mut gpui::TestAppContext) {
init_test(cx); init_test(cx);