Add action editor::OpenContextMenu
(#21494)
This addresses the editor context menu portion of #17819. Release Notes: - Added `editor::OpenContextMenu` action to open context menu at current cursor position.
This commit is contained in:
parent
0bde0f8e2f
commit
f0fac41ca4
5 changed files with 77 additions and 60 deletions
|
@ -108,7 +108,9 @@
|
|||
"ctrl-'": "editor::ToggleHunkDiff",
|
||||
"ctrl-\"": "editor::ExpandAllHunkDiffs",
|
||||
"ctrl-i": "editor::ShowSignatureHelp",
|
||||
"alt-g b": "editor::ToggleGitBlame"
|
||||
"alt-g b": "editor::ToggleGitBlame",
|
||||
"menu": "editor::OpenContextMenu",
|
||||
"shift-f10": "editor::OpenContextMenu"
|
||||
}
|
||||
},
|
||||
{
|
||||
|
|
|
@ -296,6 +296,7 @@ gpui::actions!(
|
|||
NewlineBelow,
|
||||
NextInlineCompletion,
|
||||
NextScreen,
|
||||
OpenContextMenu,
|
||||
OpenExcerpts,
|
||||
OpenExcerptsSplit,
|
||||
OpenProposedChangesEditor,
|
||||
|
|
|
@ -13075,6 +13075,12 @@ impl Editor {
|
|||
cx.write_to_clipboard(ClipboardItem::new_string(lines));
|
||||
}
|
||||
|
||||
pub fn open_context_menu(&mut self, _: &OpenContextMenu, cx: &mut ViewContext<Self>) {
|
||||
self.request_autoscroll(Autoscroll::newest(), cx);
|
||||
let position = self.selections.newest_display(cx).start;
|
||||
mouse_context_menu::deploy_context_menu(self, None, position, cx);
|
||||
}
|
||||
|
||||
pub fn inlay_hint_cache(&self) -> &InlayHintCache {
|
||||
&self.inlay_hint_cache
|
||||
}
|
||||
|
@ -13296,6 +13302,23 @@ impl Editor {
|
|||
.get(&type_id)
|
||||
.and_then(|item| item.to_any().downcast_ref::<T>())
|
||||
}
|
||||
|
||||
fn character_size(&self, cx: &mut ViewContext<Self>) -> gpui::Point<Pixels> {
|
||||
let text_layout_details = self.text_layout_details(cx);
|
||||
let style = &text_layout_details.editor_style;
|
||||
let font_id = cx.text_system().resolve_font(&style.text.font());
|
||||
let font_size = style.text.font_size.to_pixels(cx.rem_size());
|
||||
let line_height = style.text.line_height_in_pixels(cx.rem_size());
|
||||
|
||||
let em_width = cx
|
||||
.text_system()
|
||||
.typographic_bounds(font_id, font_size, 'm')
|
||||
.unwrap()
|
||||
.size
|
||||
.width;
|
||||
|
||||
gpui::Point::new(em_width, line_height)
|
||||
}
|
||||
}
|
||||
|
||||
fn char_len_with_expanded_tabs(offset: usize, text: &str, tab_size: NonZeroU32) -> usize {
|
||||
|
@ -14725,17 +14748,10 @@ impl ViewInputHandler for Editor {
|
|||
cx: &mut ViewContext<Self>,
|
||||
) -> Option<gpui::Bounds<Pixels>> {
|
||||
let text_layout_details = self.text_layout_details(cx);
|
||||
let style = &text_layout_details.editor_style;
|
||||
let font_id = cx.text_system().resolve_font(&style.text.font());
|
||||
let font_size = style.text.font_size.to_pixels(cx.rem_size());
|
||||
let line_height = style.text.line_height_in_pixels(cx.rem_size());
|
||||
|
||||
let em_width = cx
|
||||
.text_system()
|
||||
.typographic_bounds(font_id, font_size, 'm')
|
||||
.unwrap()
|
||||
.size
|
||||
.width;
|
||||
let gpui::Point {
|
||||
x: em_width,
|
||||
y: line_height,
|
||||
} = self.character_size(cx);
|
||||
|
||||
let snapshot = self.snapshot(cx);
|
||||
let scroll_position = snapshot.scroll_position();
|
||||
|
|
|
@ -169,6 +169,7 @@ impl EditorElement {
|
|||
|
||||
crate::rust_analyzer_ext::apply_related_actions(view, cx);
|
||||
crate::clangd_ext::apply_related_actions(view, cx);
|
||||
register_action(view, cx, Editor::open_context_menu);
|
||||
register_action(view, cx, Editor::move_left);
|
||||
register_action(view, cx, Editor::move_right);
|
||||
register_action(view, cx, Editor::move_down);
|
||||
|
@ -595,7 +596,7 @@ impl EditorElement {
|
|||
position_map.point_for_position(text_hitbox.bounds, event.position);
|
||||
mouse_context_menu::deploy_context_menu(
|
||||
editor,
|
||||
event.position,
|
||||
Some(event.position),
|
||||
point_for_position.previous_valid,
|
||||
cx,
|
||||
);
|
||||
|
@ -2730,6 +2731,7 @@ impl EditorElement {
|
|||
&self,
|
||||
editor_snapshot: &EditorSnapshot,
|
||||
visible_range: Range<DisplayRow>,
|
||||
content_origin: gpui::Point<Pixels>,
|
||||
cx: &mut WindowContext,
|
||||
) -> Option<AnyElement> {
|
||||
let position = self.editor.update(cx, |editor, cx| {
|
||||
|
@ -2747,16 +2749,11 @@ impl EditorElement {
|
|||
let mouse_context_menu = editor.mouse_context_menu.as_ref()?;
|
||||
let (source_display_point, position) = match mouse_context_menu.position {
|
||||
MenuPosition::PinnedToScreen(point) => (None, point),
|
||||
MenuPosition::PinnedToEditor {
|
||||
source,
|
||||
offset_x,
|
||||
offset_y,
|
||||
} => {
|
||||
MenuPosition::PinnedToEditor { source, offset } => {
|
||||
let source_display_point = source.to_display_point(editor_snapshot);
|
||||
let mut source_point = editor.to_pixel_point(source, editor_snapshot, cx)?;
|
||||
source_point.x += offset_x;
|
||||
source_point.y += offset_y;
|
||||
(Some(source_display_point), source_point)
|
||||
let source_point = editor.to_pixel_point(source, editor_snapshot, cx)?;
|
||||
let position = content_origin + source_point + offset;
|
||||
(Some(source_display_point), position)
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -4325,8 +4322,8 @@ fn deploy_blame_entry_context_menu(
|
|||
});
|
||||
|
||||
editor.update(cx, move |editor, cx| {
|
||||
editor.mouse_context_menu = Some(MouseContextMenu::pinned_to_screen(
|
||||
position,
|
||||
editor.mouse_context_menu = Some(MouseContextMenu::new(
|
||||
MenuPosition::PinnedToScreen(position),
|
||||
context_menu,
|
||||
cx,
|
||||
));
|
||||
|
@ -5578,8 +5575,12 @@ impl Element for EditorElement {
|
|||
);
|
||||
}
|
||||
|
||||
let mouse_context_menu =
|
||||
self.layout_mouse_context_menu(&snapshot, start_row..end_row, cx);
|
||||
let mouse_context_menu = self.layout_mouse_context_menu(
|
||||
&snapshot,
|
||||
start_row..end_row,
|
||||
content_origin,
|
||||
cx,
|
||||
);
|
||||
|
||||
cx.with_element_namespace("crease_toggles", |cx| {
|
||||
self.prepaint_crease_toggles(
|
||||
|
|
|
@ -20,8 +20,7 @@ pub enum MenuPosition {
|
|||
/// Disappears when the position is no longer visible.
|
||||
PinnedToEditor {
|
||||
source: multi_buffer::Anchor,
|
||||
offset_x: Pixels,
|
||||
offset_y: Pixels,
|
||||
offset: Point<Pixels>,
|
||||
},
|
||||
}
|
||||
|
||||
|
@ -48,36 +47,22 @@ impl MouseContextMenu {
|
|||
context_menu: View<ui::ContextMenu>,
|
||||
cx: &mut ViewContext<Editor>,
|
||||
) -> Option<Self> {
|
||||
let context_menu_focus = context_menu.focus_handle(cx);
|
||||
cx.focus(&context_menu_focus);
|
||||
|
||||
let _subscription = cx.subscribe(
|
||||
&context_menu,
|
||||
move |editor, _, _event: &DismissEvent, cx| {
|
||||
editor.mouse_context_menu.take();
|
||||
if context_menu_focus.contains_focused(cx) {
|
||||
editor.focus(cx);
|
||||
}
|
||||
},
|
||||
);
|
||||
|
||||
let editor_snapshot = editor.snapshot(cx);
|
||||
let source_point = editor.to_pixel_point(source, &editor_snapshot, cx)?;
|
||||
let offset = position - source_point;
|
||||
|
||||
Some(Self {
|
||||
position: MenuPosition::PinnedToEditor {
|
||||
source,
|
||||
offset_x: offset.x,
|
||||
offset_y: offset.y,
|
||||
},
|
||||
context_menu,
|
||||
_subscription,
|
||||
})
|
||||
let content_origin = editor.last_bounds?.origin
|
||||
+ Point {
|
||||
x: editor.gutter_dimensions.width,
|
||||
y: Pixels(0.0),
|
||||
};
|
||||
let source_position = editor.to_pixel_point(source, &editor_snapshot, cx)?;
|
||||
let menu_position = MenuPosition::PinnedToEditor {
|
||||
source,
|
||||
offset: position - (source_position + content_origin),
|
||||
};
|
||||
return Some(MouseContextMenu::new(menu_position, context_menu, cx));
|
||||
}
|
||||
|
||||
pub(crate) fn pinned_to_screen(
|
||||
position: Point<Pixels>,
|
||||
pub(crate) fn new(
|
||||
position: MenuPosition,
|
||||
context_menu: View<ui::ContextMenu>,
|
||||
cx: &mut ViewContext<Editor>,
|
||||
) -> Self {
|
||||
|
@ -95,7 +80,7 @@ impl MouseContextMenu {
|
|||
);
|
||||
|
||||
Self {
|
||||
position: MenuPosition::PinnedToScreen(position),
|
||||
position,
|
||||
context_menu,
|
||||
_subscription,
|
||||
}
|
||||
|
@ -119,7 +104,7 @@ fn display_ranges<'a>(
|
|||
|
||||
pub fn deploy_context_menu(
|
||||
editor: &mut Editor,
|
||||
position: Point<Pixels>,
|
||||
position: Option<Point<Pixels>>,
|
||||
point: DisplayPoint,
|
||||
cx: &mut ViewContext<Editor>,
|
||||
) {
|
||||
|
@ -213,8 +198,18 @@ pub fn deploy_context_menu(
|
|||
})
|
||||
};
|
||||
|
||||
editor.mouse_context_menu =
|
||||
MouseContextMenu::pinned_to_editor(editor, source_anchor, position, context_menu, cx);
|
||||
editor.mouse_context_menu = match position {
|
||||
Some(position) => {
|
||||
MouseContextMenu::pinned_to_editor(editor, source_anchor, position, context_menu, cx)
|
||||
}
|
||||
None => {
|
||||
let menu_position = MenuPosition::PinnedToEditor {
|
||||
source: source_anchor,
|
||||
offset: editor.character_size(cx),
|
||||
};
|
||||
Some(MouseContextMenu::new(menu_position, context_menu, cx))
|
||||
}
|
||||
};
|
||||
cx.notify();
|
||||
}
|
||||
|
||||
|
@ -248,7 +243,9 @@ mod tests {
|
|||
}
|
||||
"});
|
||||
cx.editor(|editor, _app| assert!(editor.mouse_context_menu.is_none()));
|
||||
cx.update_editor(|editor, cx| deploy_context_menu(editor, Default::default(), point, cx));
|
||||
cx.update_editor(|editor, cx| {
|
||||
deploy_context_menu(editor, Some(Default::default()), point, cx)
|
||||
});
|
||||
|
||||
cx.assert_editor_state(indoc! {"
|
||||
fn test() {
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue