Add editor::BlameHover
action for triggering the blame popover via keyboard (#32096)
Make the git blame popover available via the keymap by making it an action. The blame popover stays open after being shown via the action, similar to the `editor::Hover` action. I added a default vim-mode key binding for `g b`, which goes in hand with `g h` for hover. I'm not sure what the keybind would be for regular layouts, if any would be set by default. I'm opening this as a draft because I coludn't figure out a way to position the popover correctly above/under the cursor head. I saw some uses of `content_origin` in other places for calculating absolute pixel positions, but I'm not sure how to make use of it here without doing a big refactor of the blame popover code 🤔. I would appreciate some help/tips with positioning, because it seems like the last thing to implement here. Opening as a draft for now because I think without the correct positioning this feature is not complete. Closes https://github.com/zed-industries/zed/discussions/26447 Release Notes: - Added `editor::BlameHover` action for showing the git blame popover under the cursor. By default bound to `ctrl-k ctrl-b` and to `g h` in vim mode.
This commit is contained in:
parent
15353630e4
commit
233e66d35f
6 changed files with 52 additions and 6 deletions
|
@ -483,6 +483,7 @@
|
|||
"ctrl-k ctrl-d": ["editor::SelectNext", { "replace_newest": true }], // editor.action.moveSelectionToNextFindMatch / find_under_expand_skip
|
||||
"ctrl-k ctrl-shift-d": ["editor::SelectPrevious", { "replace_newest": true }], // editor.action.moveSelectionToPreviousFindMatch
|
||||
"ctrl-k ctrl-i": "editor::Hover",
|
||||
"ctrl-k ctrl-b": "editor::BlameHover",
|
||||
"ctrl-/": ["editor::ToggleComments", { "advance_downwards": false }],
|
||||
"f8": ["editor::GoToDiagnostic", { "severity": { "min": "hint", "max": "error" } }],
|
||||
"shift-f8": ["editor::GoToPreviousDiagnostic", { "severity": { "min": "hint", "max": "error" } }],
|
||||
|
|
|
@ -537,6 +537,7 @@
|
|||
"ctrl-cmd-d": ["editor::SelectPrevious", { "replace_newest": false }], // editor.action.addSelectionToPreviousFindMatch
|
||||
"cmd-k ctrl-cmd-d": ["editor::SelectPrevious", { "replace_newest": true }], // editor.action.moveSelectionToPreviousFindMatch
|
||||
"cmd-k cmd-i": "editor::Hover",
|
||||
"cmd-k cmd-b": "editor::BlameHover",
|
||||
"cmd-/": ["editor::ToggleComments", { "advance_downwards": false }],
|
||||
"f8": ["editor::GoToDiagnostic", { "severity": { "min": "hint", "max": "error" } }],
|
||||
"shift-f8": ["editor::GoToPreviousDiagnostic", { "severity": { "min": "hint", "max": "error" } }],
|
||||
|
|
|
@ -124,6 +124,7 @@
|
|||
"g r a": "editor::ToggleCodeActions",
|
||||
"g g": "vim::StartOfDocument",
|
||||
"g h": "editor::Hover",
|
||||
"g B": "editor::BlameHover",
|
||||
"g t": "pane::ActivateNextItem",
|
||||
"g shift-t": "pane::ActivatePreviousItem",
|
||||
"g d": "editor::GoToDefinition",
|
||||
|
|
|
@ -322,6 +322,8 @@ actions!(
|
|||
ApplyDiffHunk,
|
||||
/// Deletes the character before the cursor.
|
||||
Backspace,
|
||||
/// Shows git blame information for the current line.
|
||||
BlameHover,
|
||||
/// Cancels the current operation.
|
||||
Cancel,
|
||||
/// Cancels the running flycheck operation.
|
||||
|
|
|
@ -950,6 +950,7 @@ struct InlineBlamePopover {
|
|||
hide_task: Option<Task<()>>,
|
||||
popover_bounds: Option<Bounds<Pixels>>,
|
||||
popover_state: InlineBlamePopoverState,
|
||||
keyboard_grace: bool,
|
||||
}
|
||||
|
||||
enum SelectionDragState {
|
||||
|
@ -6517,21 +6518,55 @@ impl Editor {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn blame_hover(&mut self, _: &BlameHover, window: &mut Window, cx: &mut Context<Self>) {
|
||||
let snapshot = self.snapshot(window, cx);
|
||||
let cursor = self.selections.newest::<Point>(cx).head();
|
||||
let Some((buffer, point, _)) = snapshot.buffer_snapshot.point_to_buffer_point(cursor)
|
||||
else {
|
||||
return;
|
||||
};
|
||||
|
||||
let Some(blame) = self.blame.as_ref() else {
|
||||
return;
|
||||
};
|
||||
|
||||
let row_info = RowInfo {
|
||||
buffer_id: Some(buffer.remote_id()),
|
||||
buffer_row: Some(point.row),
|
||||
..Default::default()
|
||||
};
|
||||
let Some(blame_entry) = blame
|
||||
.update(cx, |blame, cx| blame.blame_for_rows(&[row_info], cx).next())
|
||||
.flatten()
|
||||
else {
|
||||
return;
|
||||
};
|
||||
|
||||
let anchor = self.selections.newest_anchor().head();
|
||||
let position = self.to_pixel_point(anchor, &snapshot, window);
|
||||
if let (Some(position), Some(last_bounds)) = (position, self.last_bounds) {
|
||||
self.show_blame_popover(&blame_entry, position + last_bounds.origin, true, cx);
|
||||
};
|
||||
}
|
||||
|
||||
fn show_blame_popover(
|
||||
&mut self,
|
||||
blame_entry: &BlameEntry,
|
||||
position: gpui::Point<Pixels>,
|
||||
ignore_timeout: bool,
|
||||
cx: &mut Context<Self>,
|
||||
) {
|
||||
if let Some(state) = &mut self.inline_blame_popover {
|
||||
state.hide_task.take();
|
||||
} else {
|
||||
let delay = EditorSettings::get_global(cx).hover_popover_delay;
|
||||
let blame_popover_delay = EditorSettings::get_global(cx).hover_popover_delay;
|
||||
let blame_entry = blame_entry.clone();
|
||||
let show_task = cx.spawn(async move |editor, cx| {
|
||||
cx.background_executor()
|
||||
.timer(std::time::Duration::from_millis(delay))
|
||||
.await;
|
||||
if !ignore_timeout {
|
||||
cx.background_executor()
|
||||
.timer(std::time::Duration::from_millis(blame_popover_delay))
|
||||
.await;
|
||||
}
|
||||
editor
|
||||
.update(cx, |editor, cx| {
|
||||
editor.inline_blame_popover_show_task.take();
|
||||
|
@ -6560,6 +6595,7 @@ impl Editor {
|
|||
commit_message: details,
|
||||
markdown,
|
||||
},
|
||||
keyboard_grace: ignore_timeout,
|
||||
});
|
||||
cx.notify();
|
||||
})
|
||||
|
|
|
@ -216,6 +216,7 @@ impl EditorElement {
|
|||
register_action(editor, window, Editor::newline_above);
|
||||
register_action(editor, window, Editor::newline_below);
|
||||
register_action(editor, window, Editor::backspace);
|
||||
register_action(editor, window, Editor::blame_hover);
|
||||
register_action(editor, window, Editor::delete);
|
||||
register_action(editor, window, Editor::tab);
|
||||
register_action(editor, window, Editor::backtab);
|
||||
|
@ -1143,10 +1144,14 @@ impl EditorElement {
|
|||
.as_ref()
|
||||
.and_then(|state| state.popover_bounds)
|
||||
.map_or(false, |bounds| bounds.contains(&event.position));
|
||||
let keyboard_grace = editor
|
||||
.inline_blame_popover
|
||||
.as_ref()
|
||||
.map_or(false, |state| state.keyboard_grace);
|
||||
|
||||
if mouse_over_inline_blame || mouse_over_popover {
|
||||
editor.show_blame_popover(&blame_entry, event.position, cx);
|
||||
} else {
|
||||
editor.show_blame_popover(&blame_entry, event.position, false, cx);
|
||||
} else if !keyboard_grace {
|
||||
editor.hide_blame_popover(cx);
|
||||
}
|
||||
} else {
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue