diff --git a/crates/editor/src/editor.rs b/crates/editor/src/editor.rs index 0ad5a04daa7dc53dc1100e8262baa73e64bf889c..fba43dfab75d43132274c56ac4900868f4944f36 100644 --- a/crates/editor/src/editor.rs +++ b/crates/editor/src/editor.rs @@ -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, diff --git a/crates/editor/src/editor_tests.rs b/crates/editor/src/editor_tests.rs index ee0776c97b8d6fe26b3a40e4e3d8592fb5f13040..16d2d7e6037ee6256c0b5b521adc79cd9eb59199 100644 --- a/crates/editor/src/editor_tests.rs +++ b/crates/editor/src/editor_tests.rs @@ -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::(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::( + 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::(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, |_| {});