mirror of
https://github.com/zed-industries/zed.git
synced 2026-06-01 03:14:56 +07:00
git: Introduce restore and next action (#50324)
Add a `git::RestoreAndNext` action that restores the diff hunk at the cursor and advances to the next hunk. In the git diff view, the default restore keybinding (`cmd-alt-z` on macOS, `ctrl-k ctrl-r` on Linux/Windows) is remapped to this action so users can quickly restore hunks in sequence. Also refactor `go_to_hunk_before_or_after_position` to accept a `wrap_around` parameter, eliminating duplicated hunk-navigation logic in `do_stage_or_unstage_and_next` and `restore_and_next`. Release Notes: - Added a `git: restore and next` action that restores the diff hunk at the cursor and moves to the next one. In the git diff view, the default restore keybinding (`cmd-alt-z` on macOS, `ctrl-k ctrl-r` on Linux/Windows) now triggers this action instead of `git: restore`. --------- Co-authored-by: Afonso <4775087+afonsograca@users.noreply.github.com>
This commit is contained in:
parent
8475280eb1
commit
0a436bec17
9 changed files with 145 additions and 35 deletions
|
|
@ -982,6 +982,7 @@
|
|||
"ctrl-shift-enter": "git::Amend",
|
||||
"ctrl-space": "git::StageAll",
|
||||
"ctrl-shift-space": "git::UnstageAll",
|
||||
"ctrl-k ctrl-r": "git::RestoreAndNext",
|
||||
},
|
||||
},
|
||||
{
|
||||
|
|
|
|||
|
|
@ -1033,6 +1033,7 @@
|
|||
"cmd-shift-enter": "git::Amend",
|
||||
"cmd-ctrl-y": "git::StageAll",
|
||||
"cmd-ctrl-shift-y": "git::UnstageAll",
|
||||
"cmd-alt-z": "git::RestoreAndNext",
|
||||
},
|
||||
},
|
||||
{
|
||||
|
|
|
|||
|
|
@ -983,6 +983,7 @@
|
|||
"ctrl-shift-enter": "git::Amend",
|
||||
"ctrl-space": "git::StageAll",
|
||||
"ctrl-shift-space": "git::UnstageAll",
|
||||
"ctrl-k ctrl-r": "git::RestoreAndNext",
|
||||
},
|
||||
},
|
||||
{
|
||||
|
|
|
|||
|
|
@ -831,6 +831,7 @@ fn render_diff_hunk_controls(
|
|||
&snapshot,
|
||||
position,
|
||||
Direction::Next,
|
||||
true,
|
||||
window,
|
||||
cx,
|
||||
);
|
||||
|
|
@ -866,6 +867,7 @@ fn render_diff_hunk_controls(
|
|||
&snapshot,
|
||||
point,
|
||||
Direction::Prev,
|
||||
true,
|
||||
window,
|
||||
cx,
|
||||
);
|
||||
|
|
|
|||
|
|
@ -11683,6 +11683,43 @@ impl Editor {
|
|||
self.restore_hunks_in_ranges(selections, window, cx);
|
||||
}
|
||||
|
||||
/// Restores the diff hunks in the editor's selections and moves the cursor
|
||||
/// to the next diff hunk. Wraps around to the beginning of the buffer if
|
||||
/// not all diff hunks are expanded.
|
||||
pub fn restore_and_next(
|
||||
&mut self,
|
||||
_: &::git::RestoreAndNext,
|
||||
window: &mut Window,
|
||||
cx: &mut Context<Self>,
|
||||
) {
|
||||
let selections = self
|
||||
.selections
|
||||
.all(&self.display_snapshot(cx))
|
||||
.into_iter()
|
||||
.map(|selection| selection.range())
|
||||
.collect();
|
||||
|
||||
self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
|
||||
self.restore_hunks_in_ranges(selections, window, cx);
|
||||
|
||||
let all_diff_hunks_expanded = self.buffer().read(cx).all_diff_hunks_expanded();
|
||||
let wrap_around = !all_diff_hunks_expanded;
|
||||
let snapshot = self.snapshot(window, cx);
|
||||
let position = self
|
||||
.selections
|
||||
.newest::<Point>(&snapshot.display_snapshot)
|
||||
.head();
|
||||
|
||||
self.go_to_hunk_before_or_after_position(
|
||||
&snapshot,
|
||||
position,
|
||||
Direction::Next,
|
||||
wrap_around,
|
||||
window,
|
||||
cx,
|
||||
);
|
||||
}
|
||||
|
||||
pub fn restore_hunks_in_ranges(
|
||||
&mut self,
|
||||
ranges: Vec<Range<Point>>,
|
||||
|
|
@ -17735,6 +17772,7 @@ impl Editor {
|
|||
&snapshot,
|
||||
selection.head(),
|
||||
Direction::Next,
|
||||
true,
|
||||
window,
|
||||
cx,
|
||||
);
|
||||
|
|
@ -17745,14 +17783,15 @@ impl Editor {
|
|||
snapshot: &EditorSnapshot,
|
||||
position: Point,
|
||||
direction: Direction,
|
||||
wrap_around: bool,
|
||||
window: &mut Window,
|
||||
cx: &mut Context<Editor>,
|
||||
) {
|
||||
let row = if direction == Direction::Next {
|
||||
self.hunk_after_position(snapshot, position)
|
||||
self.hunk_after_position(snapshot, position, wrap_around)
|
||||
.map(|hunk| hunk.row_range.start)
|
||||
} else {
|
||||
self.hunk_before_position(snapshot, position)
|
||||
self.hunk_before_position(snapshot, position, wrap_around)
|
||||
};
|
||||
|
||||
if let Some(row) = row {
|
||||
|
|
@ -17770,17 +17809,23 @@ impl Editor {
|
|||
&mut self,
|
||||
snapshot: &EditorSnapshot,
|
||||
position: Point,
|
||||
wrap_around: bool,
|
||||
) -> Option<MultiBufferDiffHunk> {
|
||||
snapshot
|
||||
let result = snapshot
|
||||
.buffer_snapshot()
|
||||
.diff_hunks_in_range(position..snapshot.buffer_snapshot().max_point())
|
||||
.find(|hunk| hunk.row_range.start.0 > position.row)
|
||||
.or_else(|| {
|
||||
.find(|hunk| hunk.row_range.start.0 > position.row);
|
||||
|
||||
if wrap_around {
|
||||
result.or_else(|| {
|
||||
snapshot
|
||||
.buffer_snapshot()
|
||||
.diff_hunks_in_range(Point::zero()..position)
|
||||
.find(|hunk| hunk.row_range.end.0 < position.row)
|
||||
})
|
||||
} else {
|
||||
result
|
||||
}
|
||||
}
|
||||
|
||||
fn go_to_prev_hunk(
|
||||
|
|
@ -17796,6 +17841,7 @@ impl Editor {
|
|||
&snapshot,
|
||||
selection.head(),
|
||||
Direction::Prev,
|
||||
true,
|
||||
window,
|
||||
cx,
|
||||
);
|
||||
|
|
@ -17805,11 +17851,15 @@ impl Editor {
|
|||
&mut self,
|
||||
snapshot: &EditorSnapshot,
|
||||
position: Point,
|
||||
wrap_around: bool,
|
||||
) -> Option<MultiBufferRow> {
|
||||
snapshot
|
||||
.buffer_snapshot()
|
||||
.diff_hunk_before(position)
|
||||
.or_else(|| snapshot.buffer_snapshot().diff_hunk_before(Point::MAX))
|
||||
let result = snapshot.buffer_snapshot().diff_hunk_before(position);
|
||||
|
||||
if wrap_around {
|
||||
result.or_else(|| snapshot.buffer_snapshot().diff_hunk_before(Point::MAX))
|
||||
} else {
|
||||
result
|
||||
}
|
||||
}
|
||||
|
||||
fn go_to_next_change(
|
||||
|
|
@ -20793,38 +20843,23 @@ impl Editor {
|
|||
}
|
||||
|
||||
self.stage_or_unstage_diff_hunks(stage, ranges, cx);
|
||||
|
||||
let all_diff_hunks_expanded = self.buffer().read(cx).all_diff_hunks_expanded();
|
||||
let wrap_around = !all_diff_hunks_expanded;
|
||||
let snapshot = self.snapshot(window, cx);
|
||||
let position = self
|
||||
.selections
|
||||
.newest::<Point>(&snapshot.display_snapshot)
|
||||
.head();
|
||||
let mut row = snapshot
|
||||
.buffer_snapshot()
|
||||
.diff_hunks_in_range(position..snapshot.buffer_snapshot().max_point())
|
||||
.find(|hunk| hunk.row_range.start.0 > position.row)
|
||||
.map(|hunk| hunk.row_range.start);
|
||||
|
||||
let all_diff_hunks_expanded = self.buffer().read(cx).all_diff_hunks_expanded();
|
||||
// Outside of the project diff editor, wrap around to the beginning.
|
||||
if !all_diff_hunks_expanded {
|
||||
row = row.or_else(|| {
|
||||
snapshot
|
||||
.buffer_snapshot()
|
||||
.diff_hunks_in_range(Point::zero()..position)
|
||||
.find(|hunk| hunk.row_range.end.0 < position.row)
|
||||
.map(|hunk| hunk.row_range.start)
|
||||
});
|
||||
}
|
||||
|
||||
if let Some(row) = row {
|
||||
let destination = Point::new(row.0, 0);
|
||||
let autoscroll = Autoscroll::center();
|
||||
|
||||
self.unfold_ranges(&[destination..destination], false, false, cx);
|
||||
self.change_selections(SelectionEffects::scroll(autoscroll), window, cx, |s| {
|
||||
s.select_ranges([destination..destination]);
|
||||
});
|
||||
}
|
||||
self.go_to_hunk_before_or_after_position(
|
||||
&snapshot,
|
||||
position,
|
||||
Direction::Next,
|
||||
wrap_around,
|
||||
window,
|
||||
cx,
|
||||
);
|
||||
}
|
||||
|
||||
pub(crate) fn do_stage_or_unstage(
|
||||
|
|
@ -29249,6 +29284,7 @@ fn render_diff_hunk_controls(
|
|||
&snapshot,
|
||||
position,
|
||||
Direction::Next,
|
||||
true,
|
||||
window,
|
||||
cx,
|
||||
);
|
||||
|
|
@ -29284,6 +29320,7 @@ fn render_diff_hunk_controls(
|
|||
&snapshot,
|
||||
point,
|
||||
Direction::Prev,
|
||||
true,
|
||||
window,
|
||||
cx,
|
||||
);
|
||||
|
|
|
|||
|
|
@ -33557,3 +33557,66 @@ comment */ˇ»;"#},
|
|||
assert_text_with_selections(editor, indoc! {r#"let arr = [«1, 2, 3]ˇ»;"#}, cx);
|
||||
});
|
||||
}
|
||||
|
||||
#[gpui::test]
|
||||
async fn test_restore_and_next(cx: &mut TestAppContext) {
|
||||
init_test(cx, |_| {});
|
||||
let mut cx = EditorTestContext::new(cx).await;
|
||||
|
||||
let diff_base = r#"
|
||||
one
|
||||
two
|
||||
three
|
||||
four
|
||||
five
|
||||
"#
|
||||
.unindent();
|
||||
|
||||
cx.set_state(
|
||||
&r#"
|
||||
ONE
|
||||
two
|
||||
ˇTHREE
|
||||
four
|
||||
FIVE
|
||||
"#
|
||||
.unindent(),
|
||||
);
|
||||
cx.set_head_text(&diff_base);
|
||||
|
||||
cx.update_editor(|editor, window, cx| {
|
||||
editor.set_expand_all_diff_hunks(cx);
|
||||
editor.restore_and_next(&Default::default(), window, cx);
|
||||
});
|
||||
cx.run_until_parked();
|
||||
|
||||
cx.assert_state_with_diff(
|
||||
r#"
|
||||
- one
|
||||
+ ONE
|
||||
two
|
||||
three
|
||||
four
|
||||
- ˇfive
|
||||
+ FIVE
|
||||
"#
|
||||
.unindent(),
|
||||
);
|
||||
|
||||
cx.update_editor(|editor, window, cx| {
|
||||
editor.restore_and_next(&Default::default(), window, cx);
|
||||
});
|
||||
cx.run_until_parked();
|
||||
|
||||
cx.assert_state_with_diff(
|
||||
r#"
|
||||
- one
|
||||
+ ONE
|
||||
two
|
||||
three
|
||||
four
|
||||
ˇfive
|
||||
"#
|
||||
.unindent(),
|
||||
);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -637,6 +637,7 @@ impl EditorElement {
|
|||
register_action(editor, window, Editor::accept_edit_prediction);
|
||||
register_action(editor, window, Editor::restore_file);
|
||||
register_action(editor, window, Editor::git_restore);
|
||||
register_action(editor, window, Editor::restore_and_next);
|
||||
register_action(editor, window, Editor::apply_all_diff_hunks);
|
||||
register_action(editor, window, Editor::apply_selected_diff_hunks);
|
||||
register_action(editor, window, Editor::open_active_item_in_terminal);
|
||||
|
|
|
|||
|
|
@ -40,6 +40,9 @@ actions!(
|
|||
/// Restores the selected hunks to their original state.
|
||||
#[action(deprecated_aliases = ["editor::RevertSelectedHunks"])]
|
||||
Restore,
|
||||
/// Restores the selected hunks to their original state and moves to the
|
||||
/// next one.
|
||||
RestoreAndNext,
|
||||
// per-file
|
||||
/// Shows git blame information for the current file.
|
||||
#[action(deprecated_aliases = ["editor::ToggleGitBlame"])]
|
||||
|
|
|
|||
|
|
@ -1343,6 +1343,7 @@ impl GitPanel {
|
|||
&snapshot,
|
||||
language::Point::new(0, 0),
|
||||
Direction::Next,
|
||||
true,
|
||||
window,
|
||||
cx,
|
||||
);
|
||||
|
|
|
|||
Loading…
Reference in a new issue