@@ -764,10 +764,10 @@ impl ContextMenu {
max_height: Pixels,
workspace: Option<WeakView<Workspace>>,
cx: &mut ViewContext<Editor>,
- ) -> (DisplayPoint, AnyElement) {
+ ) -> (ContextMenuOrigin, AnyElement) {
match self {
ContextMenu::Completions(menu) => (
- cursor_position,
+ ContextMenuOrigin::EditorPoint(cursor_position),
menu.render(style, max_height, workspace, cx),
),
ContextMenu::CodeActions(menu) => menu.render(cursor_position, style, max_height, cx),
@@ -775,6 +775,11 @@ impl ContextMenu {
}
}
+enum ContextMenuOrigin {
+ EditorPoint(DisplayPoint),
+ GutterIndicator(u32),
+}
+
#[derive(Clone)]
struct CompletionsMenu {
id: CompletionId,
@@ -1208,11 +1213,11 @@ impl CodeActionsMenu {
fn render(
&self,
- mut cursor_position: DisplayPoint,
+ cursor_position: DisplayPoint,
_style: &EditorStyle,
max_height: Pixels,
cx: &mut ViewContext<Editor>,
- ) -> (DisplayPoint, AnyElement) {
+ ) -> (ContextMenuOrigin, AnyElement) {
let actions = self.actions.clone();
let selected_item = self.selected_item;
@@ -1277,10 +1282,11 @@ impl CodeActionsMenu {
)
.into_any_element();
- if self.deployed_from_indicator {
- *cursor_position.column_mut() = 0;
- }
-
+ let cursor_position = if self.deployed_from_indicator {
+ ContextMenuOrigin::GutterIndicator(cursor_position.row())
+ } else {
+ ContextMenuOrigin::EditorPoint(cursor_position)
+ };
(cursor_position, element)
}
}
@@ -4247,13 +4253,13 @@ impl Editor {
.map_or(false, |menu| menu.visible())
}
- pub fn render_context_menu(
+ fn render_context_menu(
&self,
cursor_position: DisplayPoint,
style: &EditorStyle,
max_height: Pixels,
cx: &mut ViewContext<Editor>,
- ) -> Option<(DisplayPoint, AnyElement)> {
+ ) -> Option<(ContextMenuOrigin, AnyElement)> {
self.context_menu.read().as_ref().map(|menu| {
menu.render(
cursor_position,
@@ -1949,6 +1949,7 @@ impl EditorElement {
scroll_pixel_position: gpui::Point<Pixels>,
line_layouts: &[LineWithInvisibles],
newest_selection_head: DisplayPoint,
+ gutter_overshoot: Pixels,
cx: &mut WindowContext,
) -> bool {
let max_height = cmp::min(
@@ -1968,9 +1969,23 @@ impl EditorElement {
let available_space = size(AvailableSpace::MinContent, AvailableSpace::MinContent);
let context_menu_size = context_menu.layout_as_root(available_space, cx);
- let cursor_row_layout = &line_layouts[(position.row() - start_row) as usize].line;
- let x = cursor_row_layout.x_for_index(position.column() as usize) - scroll_pixel_position.x;
- let y = (position.row() + 1) as f32 * line_height - scroll_pixel_position.y;
+ let (x, y) = match position {
+ crate::ContextMenuOrigin::EditorPoint(point) => {
+ let cursor_row_layout = &line_layouts[(point.row() - start_row) as usize].line;
+ let x = cursor_row_layout.x_for_index(point.column() as usize)
+ - scroll_pixel_position.x;
+ let y = (point.row() + 1) as f32 * line_height - scroll_pixel_position.y;
+ (x, y)
+ }
+ crate::ContextMenuOrigin::GutterIndicator(row) => {
+ // Context menu was spawned via a click on a gutter. Ensure it's a bit closer to the indicator than just a plain first column of the
+ // text field.
+ let x = -gutter_overshoot;
+ let y = (row + 1) as f32 * line_height - scroll_pixel_position.y;
+ (x, y)
+ }
+ };
+
let mut list_origin = content_origin + point(x, y);
let list_width = context_menu_size.width;
let list_height = context_menu_size.height;
@@ -3826,6 +3841,7 @@ impl Element for EditorElement {
scroll_pixel_position,
&line_layouts,
newest_selection_head,
+ gutter_dimensions.width - gutter_dimensions.left_padding,
cx,
);
if gutter_settings.code_actions {