editor: Hide mouse context menu when modal is opened (#29127)

Closes #28787 

The context menu appears before the modal because it is a Deferred
element, which is always displayed above normal elements.

Release Notes:

Previously, the editor context menu appeared before the Command Palette.
This commit ensures the editor context menu is hidden when a modal,
including the Command Palette, is opened.
This commit is contained in:
redforks 2025-04-21 22:43:26 +08:00 committed by GitHub
parent 9a3434efb4
commit 6d2bdc3bac
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
4 changed files with 84 additions and 5 deletions

View file

@ -12,8 +12,8 @@ use crate::{
use buffer_diff::{BufferDiff, DiffHunkSecondaryStatus, DiffHunkStatus, DiffHunkStatusKind};
use futures::StreamExt;
use gpui::{
BackgroundExecutor, SemanticVersion, TestAppContext, UpdateGlobal, VisualTestContext,
WindowBounds, WindowOptions, div,
BackgroundExecutor, DismissEvent, SemanticVersion, TestAppContext, UpdateGlobal,
VisualTestContext, WindowBounds, WindowOptions, div,
};
use indoc::indoc;
use language::{
@ -19549,6 +19549,64 @@ println!("5");
});
}
#[gpui::test]
async fn test_hide_mouse_context_menu_on_modal_opened(cx: &mut TestAppContext) {
struct EmptyModalView {
focus_handle: gpui::FocusHandle,
}
impl EventEmitter<DismissEvent> for EmptyModalView {}
impl Render for EmptyModalView {
fn render(&mut self, _: &mut Window, _: &mut Context<'_, Self>) -> impl IntoElement {
div()
}
}
impl Focusable for EmptyModalView {
fn focus_handle(&self, _cx: &App) -> gpui::FocusHandle {
self.focus_handle.clone()
}
}
impl workspace::ModalView for EmptyModalView {}
fn new_empty_modal_view(cx: &App) -> EmptyModalView {
EmptyModalView {
focus_handle: cx.focus_handle(),
}
}
init_test(cx, |_| {});
let fs = FakeFs::new(cx.executor());
let project = Project::test(fs, [], cx).await;
let workspace = cx.add_window(|window, cx| Workspace::test_new(project.clone(), window, cx));
let buffer = cx.update(|cx| MultiBuffer::build_simple("hello world!", cx));
let cx = &mut VisualTestContext::from_window(*workspace.deref(), cx);
let editor = cx.new_window_entity(|window, cx| {
Editor::new(
EditorMode::full(),
buffer,
Some(project.clone()),
window,
cx,
)
});
workspace
.update(cx, |workspace, window, cx| {
workspace.add_item_to_active_pane(Box::new(editor.clone()), None, true, window, cx);
})
.unwrap();
editor.update_in(cx, |editor, window, cx| {
editor.open_context_menu(&OpenContextMenu, window, cx);
assert!(editor.mouse_context_menu.is_some());
});
workspace
.update(cx, |workspace, window, cx| {
workspace.toggle_modal(window, cx, |_, cx| new_empty_modal_view(cx));
})
.unwrap();
cx.read(|cx| {
assert!(editor.read(cx).mouse_context_menu.is_none());
});
}
fn empty_range(row: usize, column: usize) -> Range<DisplayPoint> {
let point = DisplayPoint::new(DisplayRow(row as u32), column as u32);
point..point

View file

@ -928,9 +928,17 @@ impl Item for Editor {
&mut self,
workspace: &mut Workspace,
_window: &mut Window,
_: &mut Context<Self>,
cx: &mut Context<Self>,
) {
self.workspace = Some((workspace.weak_handle(), workspace.database_id()));
if let Some(workspace) = &workspace.weak_handle().upgrade() {
cx.subscribe(&workspace, |editor, _, event: &workspace::Event, _cx| {
if matches!(event, workspace::Event::ModalOpened) {
editor.mouse_context_menu.take();
}
})
.detach();
}
}
fn to_item_events(event: &EditorEvent, mut f: impl FnMut(ItemEvent)) {