mouse_context_menu.rs

 1use crate::{
 2    DisplayPoint, Editor, EditorMode, FindAllReferences, GoToDefinition, GoToTypeDefinition,
 3    Rename, RevealInFinder, SelectMode, ToggleCodeActions,
 4};
 5use context_menu::ContextMenuItem;
 6use gpui::{elements::AnchorCorner, geometry::vector::Vector2F, ViewContext};
 7
 8pub fn deploy_context_menu(
 9    editor: &mut Editor,
10    position: Vector2F,
11    point: DisplayPoint,
12    cx: &mut ViewContext<Editor>,
13) {
14    if !editor.focused {
15        cx.focus_self();
16    }
17
18    // Don't show context menu for inline editors
19    if editor.mode() != EditorMode::Full {
20        return;
21    }
22
23    // Don't show the context menu if there isn't a project associated with this editor
24    if editor.project.is_none() {
25        return;
26    }
27
28    // Move the cursor to the clicked location so that dispatched actions make sense
29    editor.change_selections(None, cx, |s| {
30        s.clear_disjoint();
31        s.set_pending_display_range(point..point, SelectMode::Character);
32    });
33
34    editor.mouse_context_menu.update(cx, |menu, cx| {
35        menu.show(
36            position,
37            AnchorCorner::TopLeft,
38            vec![
39                ContextMenuItem::action("Rename Symbol", Rename),
40                ContextMenuItem::action("Go to Definition", GoToDefinition),
41                ContextMenuItem::action("Go to Type Definition", GoToTypeDefinition),
42                ContextMenuItem::action("Find All References", FindAllReferences),
43                ContextMenuItem::action(
44                    "Code Actions",
45                    ToggleCodeActions {
46                        deployed_from_indicator: false,
47                    },
48                ),
49                ContextMenuItem::Separator,
50                ContextMenuItem::action("Reveal in Finder", RevealInFinder),
51            ],
52            cx,
53        );
54    });
55    cx.notify();
56}
57
58#[cfg(test)]
59mod tests {
60    use super::*;
61    use crate::{editor_tests::init_test, test::editor_lsp_test_context::EditorLspTestContext};
62    use indoc::indoc;
63
64    #[gpui::test]
65    async fn test_mouse_context_menu(cx: &mut gpui::TestAppContext) {
66        init_test(cx, |_| {});
67
68        let mut cx = EditorLspTestContext::new_rust(
69            lsp::ServerCapabilities {
70                hover_provider: Some(lsp::HoverProviderCapability::Simple(true)),
71                ..Default::default()
72            },
73            cx,
74        )
75        .await;
76
77        cx.set_state(indoc! {"
78            fn teˇst() {
79                do_work();
80            }
81        "});
82        let point = cx.display_point(indoc! {"
83            fn test() {
84                do_wˇork();
85            }
86        "});
87        cx.update_editor(|editor, cx| deploy_context_menu(editor, Default::default(), point, cx));
88
89        cx.assert_editor_state(indoc! {"
90            fn test() {
91                do_wˇork();
92            }
93        "});
94        cx.editor(|editor, app| assert!(editor.mouse_context_menu.read(app).visible()));
95    }
96}