Allow information popovers while showing autocomplete suggestions (#12157)

Allows information popovers to display while autocomplete suggestions
are also being displayed.

Before: 


https://github.com/zed-industries/zed/assets/50590465/a61f0b4e-1521-42de-84fd-c5a3586b74ab

After:


https://github.com/zed-industries/zed/assets/50590465/ad2daae7-aebc-4c71-ad4c-f9d2deb6d0d0

Release Notes:
- Allow hover and completion popovers to appear at the same time ([12152](https://github.com/zed-industries/zed/issues/12152))
This commit is contained in:
Ephram
2024-05-24 12:32:17 +03:00
committed by GitHub
parent b9697fb487
commit 70e8737918
2 changed files with 175 additions and 4 deletions
+3 -3
View File
@@ -4614,11 +4614,11 @@ impl Element for EditorElement {
let gutter_settings = EditorSettings::get_global(cx).gutter;
let mut context_menu_visible = false;
let mut _context_menu_visible = false;
let mut code_actions_indicator = None;
if let Some(newest_selection_head) = newest_selection_head {
if (start_row..end_row).contains(&newest_selection_head.row()) {
context_menu_visible = self.layout_context_menu(
_context_menu_visible = self.layout_context_menu(
line_height,
&hitbox,
&text_hitbox,
@@ -4671,7 +4671,7 @@ impl Element for EditorElement {
cx,
);
if !context_menu_visible && !cx.has_active_drag() {
if !cx.has_active_drag() {
self.layout_hover_popovers(
&snapshot,
&hitbox,
+172 -1
View File
@@ -612,7 +612,8 @@ impl DiagnosticPopover {
mod tests {
use super::*;
use crate::{
editor_tests::init_test,
actions::ConfirmCompletion,
editor_tests::{handle_completion_request, init_test},
hover_links::update_inlay_link_and_hover_points,
inlay_hint_cache::tests::{cached_hint_labels, visible_hint_labels},
test::editor_lsp_test_context::EditorLspTestContext,
@@ -625,10 +626,180 @@ mod tests {
use lsp::LanguageServerId;
use project::{HoverBlock, HoverBlockKind};
use smol::stream::StreamExt;
use std::sync::atomic;
use std::sync::atomic::AtomicUsize;
use text::Bias;
use unindent::Unindent;
use util::test::marked_text_ranges;
#[gpui::test]
async fn test_mouse_hover_info_popover_with_autocomplete_popover(
cx: &mut gpui::TestAppContext,
) {
init_test(cx, |_| {});
const HOVER_DELAY_MILLIS: u64 = 350;
let mut cx = EditorLspTestContext::new_rust(
lsp::ServerCapabilities {
hover_provider: Some(lsp::HoverProviderCapability::Simple(true)),
completion_provider: Some(lsp::CompletionOptions {
trigger_characters: Some(vec![".".to_string(), ":".to_string()]),
resolve_provider: Some(true),
..Default::default()
}),
..Default::default()
},
cx,
)
.await;
let counter = Arc::new(AtomicUsize::new(0));
// Basic hover delays and then pops without moving the mouse
cx.set_state(indoc! {"
oneˇ
two
three
fn test() { println!(); }
"});
//prompt autocompletion menu
cx.simulate_keystroke(".");
handle_completion_request(
&mut cx,
indoc! {"
one.|<>
two
three
"},
vec!["first_completion", "second_completion"],
counter.clone(),
)
.await;
cx.condition(|editor, _| editor.context_menu_visible()) // wait until completion menu is visible
.await;
assert_eq!(counter.load(atomic::Ordering::Acquire), 1); // 1 completion request
let hover_point = cx.display_point(indoc! {"
one.
two
three
fn test() { printˇln!(); }
"});
cx.update_editor(|editor, cx| {
let snapshot = editor.snapshot(cx);
let anchor = snapshot
.buffer_snapshot
.anchor_before(hover_point.to_offset(&snapshot, Bias::Left));
hover_at(editor, Some(anchor), cx)
});
assert!(!cx.editor(|editor, _| editor.hover_state.visible()));
// After delay, hover should be visible.
let symbol_range = cx.lsp_range(indoc! {"
one.
two
three
fn test() { «println!»(); }
"});
let mut requests =
cx.handle_request::<lsp::request::HoverRequest, _, _>(move |_, _, _| async move {
Ok(Some(lsp::Hover {
contents: lsp::HoverContents::Markup(lsp::MarkupContent {
kind: lsp::MarkupKind::Markdown,
value: "some basic docs".to_string(),
}),
range: Some(symbol_range),
}))
});
cx.background_executor
.advance_clock(Duration::from_millis(HOVER_DELAY_MILLIS + 100));
requests.next().await;
cx.editor(|editor, _| {
assert!(editor.hover_state.visible());
assert_eq!(
editor.hover_state.info_popovers.len(),
1,
"Expected exactly one hover but got: {:?}",
editor.hover_state.info_popovers
);
let rendered = editor
.hover_state
.info_popovers
.first()
.cloned()
.unwrap()
.parsed_content;
assert_eq!(rendered.text, "some basic docs".to_string())
});
// check that the completion menu is still visible and that there still has only been 1 completion request
cx.editor(|editor, _| assert!(editor.context_menu_visible()));
assert_eq!(counter.load(atomic::Ordering::Acquire), 1);
//apply a completion and check it was successfully applied
let _apply_additional_edits = cx.update_editor(|editor, cx| {
editor.context_menu_next(&Default::default(), cx);
editor
.confirm_completion(&ConfirmCompletion::default(), cx)
.unwrap()
});
cx.assert_editor_state(indoc! {"
one.second_completionˇ
two
three
fn test() { println!(); }
"});
// check that the completion menu is no longer visible and that there still has only been 1 completion request
cx.editor(|editor, _| assert!(!editor.context_menu_visible()));
assert_eq!(counter.load(atomic::Ordering::Acquire), 1);
//verify the information popover is still visible and unchanged
cx.editor(|editor, _| {
assert!(editor.hover_state.visible());
assert_eq!(
editor.hover_state.info_popovers.len(),
1,
"Expected exactly one hover but got: {:?}",
editor.hover_state.info_popovers
);
let rendered = editor
.hover_state
.info_popovers
.first()
.cloned()
.unwrap()
.parsed_content;
assert_eq!(rendered.text, "some basic docs".to_string())
});
// Mouse moved with no hover response dismisses
let hover_point = cx.display_point(indoc! {"
one.second_completionˇ
two
three
fn teˇst() { println!(); }
"});
let mut request = cx
.lsp
.handle_request::<lsp::request::HoverRequest, _, _>(|_, _| async move { Ok(None) });
cx.update_editor(|editor, cx| {
let snapshot = editor.snapshot(cx);
let anchor = snapshot
.buffer_snapshot
.anchor_before(hover_point.to_offset(&snapshot, Bias::Left));
hover_at(editor, Some(anchor), cx)
});
cx.background_executor
.advance_clock(Duration::from_millis(HOVER_DELAY_MILLIS + 100));
request.next().await;
// verify that the information popover is no longer visible
cx.editor(|editor, _| {
assert!(!editor.hover_state.visible());
});
}
#[gpui::test]
async fn test_mouse_hover_info_popover(cx: &mut gpui::TestAppContext) {
init_test(cx, |_| {});