mouse_context_menu.rs

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