@@ -5081,7 +5081,7 @@ impl Editor {
if editor.focus_handle.is_focused(window) && menu.is_some() {
let mut menu = menu.unwrap();
menu.resolve_visible_completions(editor.completion_provider.as_deref(), cx);
-
+ crate::hover_popover::hide_hover(editor, cx);
*editor.context_menu.borrow_mut() =
Some(CodeContextMenu::Completions(menu));
@@ -5512,6 +5512,7 @@ impl Editor {
.map_or(true, |actions| actions.is_empty())
&& debug_scenarios.is_empty();
if let Ok(task) = editor.update_in(cx, |editor, window, cx| {
+ crate::hover_popover::hide_hover(editor, cx);
*editor.context_menu.borrow_mut() =
Some(CodeContextMenu::CodeActions(CodeActionsMenu {
buffer,
@@ -13980,6 +13980,148 @@ async fn test_completions_resolve_updates_labels_if_filter_text_matches(cx: &mut
});
}
+#[gpui::test]
+async fn test_context_menus_hide_hover_popover(cx: &mut gpui::TestAppContext) {
+ init_test(cx, |_| {});
+ let mut cx = EditorLspTestContext::new_rust(
+ lsp::ServerCapabilities {
+ hover_provider: Some(lsp::HoverProviderCapability::Simple(true)),
+ code_action_provider: Some(lsp::CodeActionProviderCapability::Simple(true)),
+ completion_provider: Some(lsp::CompletionOptions {
+ resolve_provider: Some(true),
+ ..Default::default()
+ }),
+ ..Default::default()
+ },
+ cx,
+ )
+ .await;
+ cx.set_state(indoc! {"
+ struct TestStruct {
+ field: i32
+ }
+
+ fn mainˇ() {
+ let unused_var = 42;
+ let test_struct = TestStruct { field: 42 };
+ }
+ "});
+ let symbol_range = cx.lsp_range(indoc! {"
+ struct TestStruct {
+ field: i32
+ }
+
+ «fn main»() {
+ let unused_var = 42;
+ let test_struct = TestStruct { field: 42 };
+ }
+ "});
+ let mut hover_requests =
+ cx.set_request_handler::<lsp::request::HoverRequest, _, _>(move |_, _, _| async move {
+ Ok(Some(lsp::Hover {
+ contents: lsp::HoverContents::Markup(lsp::MarkupContent {
+ kind: lsp::MarkupKind::Markdown,
+ value: "Function documentation".to_string(),
+ }),
+ range: Some(symbol_range),
+ }))
+ });
+
+ // Case 1: Test that code action menu hide hover popover
+ cx.dispatch_action(Hover);
+ hover_requests.next().await;
+ cx.condition(|editor, _| editor.hover_state.visible()).await;
+ let mut code_action_requests = cx.set_request_handler::<lsp::request::CodeActionRequest, _, _>(
+ move |_, _, _| async move {
+ Ok(Some(vec![lsp::CodeActionOrCommand::CodeAction(
+ lsp::CodeAction {
+ title: "Remove unused variable".to_string(),
+ kind: Some(CodeActionKind::QUICKFIX),
+ edit: Some(lsp::WorkspaceEdit {
+ changes: Some(
+ [(
+ lsp::Url::from_file_path(path!("/file.rs")).unwrap(),
+ vec![lsp::TextEdit {
+ range: lsp::Range::new(
+ lsp::Position::new(5, 4),
+ lsp::Position::new(5, 27),
+ ),
+ new_text: "".to_string(),
+ }],
+ )]
+ .into_iter()
+ .collect(),
+ ),
+ ..Default::default()
+ }),
+ ..Default::default()
+ },
+ )]))
+ },
+ );
+ cx.update_editor(|editor, window, cx| {
+ editor.toggle_code_actions(
+ &ToggleCodeActions {
+ deployed_from_indicator: None,
+ quick_launch: false,
+ },
+ window,
+ cx,
+ );
+ });
+ code_action_requests.next().await;
+ cx.run_until_parked();
+ cx.condition(|editor, _| editor.context_menu_visible())
+ .await;
+ cx.update_editor(|editor, _, _| {
+ assert!(
+ !editor.hover_state.visible(),
+ "Hover popover should be hidden when code action menu is shown"
+ );
+ // Hide code actions
+ editor.context_menu.take();
+ });
+
+ // Case 2: Test that code completions hide hover popover
+ cx.dispatch_action(Hover);
+ hover_requests.next().await;
+ cx.condition(|editor, _| editor.hover_state.visible()).await;
+ let counter = Arc::new(AtomicUsize::new(0));
+ let mut completion_requests =
+ cx.set_request_handler::<lsp::request::Completion, _, _>(move |_, _, _| {
+ let counter = counter.clone();
+ async move {
+ counter.fetch_add(1, atomic::Ordering::Release);
+ Ok(Some(lsp::CompletionResponse::Array(vec![
+ lsp::CompletionItem {
+ label: "main".into(),
+ kind: Some(lsp::CompletionItemKind::FUNCTION),
+ detail: Some("() -> ()".to_string()),
+ ..Default::default()
+ },
+ lsp::CompletionItem {
+ label: "TestStruct".into(),
+ kind: Some(lsp::CompletionItemKind::STRUCT),
+ detail: Some("struct TestStruct".to_string()),
+ ..Default::default()
+ },
+ ])))
+ }
+ });
+ cx.update_editor(|editor, window, cx| {
+ editor.show_completions(&ShowCompletions { trigger: None }, window, cx);
+ });
+ completion_requests.next().await;
+ cx.condition(|editor, _| editor.context_menu_visible())
+ .await;
+ cx.update_editor(|editor, _, _| {
+ assert!(
+ !editor.hover_state.visible(),
+ "Hover popover should be hidden when completion menu is shown"
+ );
+ });
+}
+
#[gpui::test]
async fn test_completions_resolve_happens_once(cx: &mut TestAppContext) {
init_test(cx, |_| {});