git: Fix project diff shortcuts (#26045)

Release Notes:

- git: Fix keyboard shortcut display in project diff view
This commit is contained in:
Conrad Irwin 2025-03-04 10:32:20 -07:00 committed by GitHub
parent ad94642e83
commit 85211889e5
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
16 changed files with 108 additions and 233 deletions

View file

@ -370,10 +370,10 @@
"ctrl-shift-v": "markdown::OpenPreview", "ctrl-shift-v": "markdown::OpenPreview",
"ctrl-alt-shift-c": "editor::DisplayCursorNames", "ctrl-alt-shift-c": "editor::DisplayCursorNames",
"ctrl-alt-y": "git::ToggleStaged", "ctrl-alt-y": "git::ToggleStaged",
"alt-y": ["git::StageAndNext", { "whole_excerpt": false }], "alt-y": "git::StageAndNext",
"alt-shift-y": ["git::UnstageAndNext", { "whole_excerpt": false }], "alt-shift-y": "git::UnstageAndNext",
"alt-.": ["editor::GoToHunk", { "center_cursor": true }], "alt-.": "editor::GoToHunk",
"alt-,": ["editor::GoToPreviousHunk", { "center_cursor": true }] "alt-,": "editor::GoToPreviousHunk"
} }
}, },
{ {
@ -564,8 +564,8 @@
"shift-enter": "editor::ExpandExcerpts", "shift-enter": "editor::ExpandExcerpts",
"ctrl-alt-enter": "editor::OpenExcerptsSplit", "ctrl-alt-enter": "editor::OpenExcerptsSplit",
"ctrl-shift-e": "pane::RevealInProjectPanel", "ctrl-shift-e": "pane::RevealInProjectPanel",
"ctrl-f8": ["editor::GoToHunk", { "center_cursor": true }], "ctrl-f8": "editor::GoToHunk",
"ctrl-shift-f8": ["editor::GoToPreviousHunk", { "center_cursor": true }], "ctrl-shift-f8": "editor::GoToPreviousHunk",
"ctrl-enter": "assistant::InlineAssist", "ctrl-enter": "assistant::InlineAssist",
"ctrl-:": "editor::ToggleInlayHints" "ctrl-:": "editor::ToggleInlayHints"
} }
@ -739,7 +739,7 @@
"tab": "git_panel::FocusEditor", "tab": "git_panel::FocusEditor",
"shift-tab": "git_panel::FocusEditor", "shift-tab": "git_panel::FocusEditor",
"escape": "git_panel::ToggleFocus", "escape": "git_panel::ToggleFocus",
"ctrl-enter": "git::Commit", "ctrl-enter": "git::ShowCommitEditor",
"alt-enter": "menu::SecondaryConfirm" "alt-enter": "menu::SecondaryConfirm"
} }
}, },
@ -753,7 +753,7 @@
{ {
"context": "GitDiff > Editor", "context": "GitDiff > Editor",
"bindings": { "bindings": {
"ctrl-enter": "git::Commit" "ctrl-enter": "git::ShowCommitEditor"
} }
}, },
{ {
@ -766,14 +766,6 @@
"alt-up": "git_panel::FocusChanges" "alt-up": "git_panel::FocusChanges"
} }
}, },
{
"context": "GitCommit > Editor",
"use_key_equivalents": true,
"bindings": {
"enter": "editor::Newline",
"ctrl-enter": "git::Commit"
}
},
{ {
"context": "CollabPanel && not_editing", "context": "CollabPanel && not_editing",
"bindings": { "bindings": {

View file

@ -142,8 +142,8 @@
"cmd-;": "editor::ToggleLineNumbers", "cmd-;": "editor::ToggleLineNumbers",
"cmd-alt-z": "git::Restore", "cmd-alt-z": "git::Restore",
"cmd-alt-y": "git::ToggleStaged", "cmd-alt-y": "git::ToggleStaged",
"cmd-y": ["git::StageAndNext", { "whole_excerpt": false }], "cmd-y": "git::StageAndNext",
"cmd-shift-y": ["git::UnstageAndNext", { "whole_excerpt": false }], "cmd-shift-y": "git::UnstageAndNext",
"cmd-'": "editor::ToggleSelectedDiffHunks", "cmd-'": "editor::ToggleSelectedDiffHunks",
"cmd-\"": "editor::ExpandAllDiffHunks", "cmd-\"": "editor::ExpandAllDiffHunks",
"cmd-alt-g b": "editor::ToggleGitBlame", "cmd-alt-g b": "editor::ToggleGitBlame",
@ -659,8 +659,8 @@
"shift-enter": "editor::ExpandExcerpts", "shift-enter": "editor::ExpandExcerpts",
"cmd-alt-enter": "editor::OpenExcerptsSplit", "cmd-alt-enter": "editor::OpenExcerptsSplit",
"cmd-shift-e": "pane::RevealInProjectPanel", "cmd-shift-e": "pane::RevealInProjectPanel",
"cmd-f8": ["editor::GoToHunk", { "center_cursor": true }], "cmd-f8": "editor::GoToHunk",
"cmd-shift-f8": ["editor::GoToPreviousHunk", { "center_cursor": true }], "cmd-shift-f8": "editor::GoToPreviousHunk",
"ctrl-enter": "assistant::InlineAssist", "ctrl-enter": "assistant::InlineAssist",
"ctrl-:": "editor::ToggleInlayHints" "ctrl-:": "editor::ToggleInlayHints"
} }
@ -760,14 +760,14 @@
"tab": "git_panel::FocusEditor", "tab": "git_panel::FocusEditor",
"shift-tab": "git_panel::FocusEditor", "shift-tab": "git_panel::FocusEditor",
"escape": "git_panel::ToggleFocus", "escape": "git_panel::ToggleFocus",
"cmd-enter": "git::Commit" "cmd-enter": "git::ShowCommitEditor"
} }
}, },
{ {
"context": "GitDiff > Editor", "context": "GitDiff > Editor",
"use_key_equivalents": true, "use_key_equivalents": true,
"bindings": { "bindings": {
"cmd-enter": "git::Commit" "cmd-enter": "git::ShowCommitEditor"
} }
}, },
{ {

View file

@ -42,8 +42,8 @@
"ctrl-alt-shift-b": "editor::GoToTypeDefinitionSplit", "ctrl-alt-shift-b": "editor::GoToTypeDefinitionSplit",
"f2": "editor::GoToDiagnostic", "f2": "editor::GoToDiagnostic",
"shift-f2": "editor::GoToPreviousDiagnostic", "shift-f2": "editor::GoToPreviousDiagnostic",
"ctrl-alt-shift-down": ["editor::GoToHunk", { "center_cursor": true }], "ctrl-alt-shift-down": "editor::GoToHunk",
"ctrl-alt-shift-up": ["editor::GoToPreviousHunk", { "center_cursor": true }], "ctrl-alt-shift-up": "editor::GoToPreviousHunk",
"ctrl-alt-z": "git::Restore", "ctrl-alt-z": "git::Restore",
"ctrl-home": "editor::MoveToBeginning", "ctrl-home": "editor::MoveToBeginning",
"ctrl-end": "editor::MoveToEnd", "ctrl-end": "editor::MoveToEnd",

View file

@ -43,8 +43,8 @@
"ctrl-f12": "editor::GoToDefinitionSplit", "ctrl-f12": "editor::GoToDefinitionSplit",
"shift-f12": "editor::FindAllReferences", "shift-f12": "editor::FindAllReferences",
"ctrl-shift-f12": "editor::FindAllReferences", "ctrl-shift-f12": "editor::FindAllReferences",
"ctrl-.": ["editor::GoToHunk", { "center_cursor": true }], "ctrl-.": "editor::GoToHunk",
"ctrl-,": ["editor::GoToPreviousHunk", { "center_cursor": true }], "ctrl-,": "editor::GoToPreviousHunk",
"ctrl-k ctrl-u": "editor::ConvertToUpperCase", "ctrl-k ctrl-u": "editor::ConvertToUpperCase",
"ctrl-k ctrl-l": "editor::ConvertToLowerCase", "ctrl-k ctrl-l": "editor::ConvertToLowerCase",
"shift-alt-m": "markdown::OpenPreviewToTheSide", "shift-alt-m": "markdown::OpenPreviewToTheSide",

View file

@ -40,8 +40,8 @@
"cmd-alt-shift-b": "editor::GoToTypeDefinitionSplit", "cmd-alt-shift-b": "editor::GoToTypeDefinitionSplit",
"f2": "editor::GoToDiagnostic", "f2": "editor::GoToDiagnostic",
"shift-f2": "editor::GoToPreviousDiagnostic", "shift-f2": "editor::GoToPreviousDiagnostic",
"ctrl-alt-shift-down": ["editor::GoToHunk", { "center_cursor": true }], "ctrl-alt-shift-down": "editor::GoToHunk",
"ctrl-alt-shift-up": ["editor::GoToPreviousHunk", { "center_cursor": true }], "ctrl-alt-shift-up": "editor::GoToPreviousHunk",
"cmd-home": "editor::MoveToBeginning", "cmd-home": "editor::MoveToBeginning",
"cmd-end": "editor::MoveToEnd", "cmd-end": "editor::MoveToEnd",
"cmd-shift-home": "editor::SelectToBeginning", "cmd-shift-home": "editor::SelectToBeginning",

View file

@ -44,8 +44,8 @@
"alt-cmd-down": "editor::GoToDefinition", "alt-cmd-down": "editor::GoToDefinition",
"ctrl-alt-cmd-down": "editor::GoToDefinitionSplit", "ctrl-alt-cmd-down": "editor::GoToDefinitionSplit",
"alt-shift-cmd-down": "editor::FindAllReferences", "alt-shift-cmd-down": "editor::FindAllReferences",
"ctrl-.": ["editor::GoToHunk", { "center_cursor": true }], "ctrl-.": "editor::GoToHunk",
"ctrl-,": ["editor::GoToPreviousHunk", { "center_cursor": true }], "ctrl-,": "editor::GoToPreviousHunk",
"cmd-k cmd-u": "editor::ConvertToUpperCase", "cmd-k cmd-u": "editor::ConvertToUpperCase",
"cmd-k cmd-l": "editor::ConvertToLowerCase", "cmd-k cmd-l": "editor::ConvertToLowerCase",
"cmd-shift-j": "editor::JoinLines", "cmd-shift-j": "editor::JoinLines",

View file

@ -238,8 +238,8 @@
"] x": "vim::SelectSmallerSyntaxNode", "] x": "vim::SelectSmallerSyntaxNode",
"] d": "editor::GoToDiagnostic", "] d": "editor::GoToDiagnostic",
"[ d": "editor::GoToPreviousDiagnostic", "[ d": "editor::GoToPreviousDiagnostic",
"] c": ["editor::GoToHunk", { "center_cursor": true }], "] c": "editor::GoToHunk",
"[ c": ["editor::GoToPreviousHunk", { "center_cursor": true }], "[ c": "editor::GoToPreviousHunk",
"g c": "vim::PushToggleComments" "g c": "vim::PushToggleComments"
} }
}, },
@ -448,7 +448,10 @@
"d": "vim::CurrentLine", "d": "vim::CurrentLine",
"s": "vim::PushDeleteSurrounds", "s": "vim::PushDeleteSurrounds",
"o": "editor::ToggleSelectedDiffHunks", // "d o" "o": "editor::ToggleSelectedDiffHunks", // "d o"
"p": "git::Restore" // "d p" "shift-o": "git::ToggleStaged",
"p": "git::Restore", // "d p"
"u": "git::StageAndNext", // "d u"
"shift-u": "git::UnstageAndNext" // "d shift-u"
} }
}, },
{ {

View file

@ -196,20 +196,6 @@ pub struct DeleteToPreviousWordStart {
pub ignore_newlines: bool, pub ignore_newlines: bool,
} }
#[derive(PartialEq, Clone, Deserialize, Default, JsonSchema)]
#[serde(deny_unknown_fields)]
pub struct GoToHunk {
#[serde(default)]
pub center_cursor: bool,
}
#[derive(PartialEq, Clone, Deserialize, Default, JsonSchema)]
#[serde(deny_unknown_fields)]
pub struct GoToPreviousHunk {
#[serde(default)]
pub center_cursor: bool,
}
#[derive(PartialEq, Clone, Deserialize, Default, JsonSchema)] #[derive(PartialEq, Clone, Deserialize, Default, JsonSchema)]
pub struct FoldAtLevel(pub u32); pub struct FoldAtLevel(pub u32);
@ -240,8 +226,6 @@ impl_actions!(
ExpandExcerptsDown, ExpandExcerptsDown,
ExpandExcerptsUp, ExpandExcerptsUp,
FoldAt, FoldAt,
GoToHunk,
GoToPreviousHunk,
HandleInput, HandleInput,
MoveDownByLines, MoveDownByLines,
MovePageDown, MovePageDown,
@ -323,6 +307,8 @@ gpui::actions!(
GoToDefinition, GoToDefinition,
GoToDefinitionSplit, GoToDefinitionSplit,
GoToDiagnostic, GoToDiagnostic,
GoToHunk,
GoToPreviousHunk,
GoToImplementation, GoToImplementation,
GoToImplementationSplit, GoToImplementationSplit,
GoToPreviousDiagnostic, GoToPreviousDiagnostic,

View file

@ -73,7 +73,7 @@ use futures::{
}; };
use fuzzy::StringMatchCandidate; use fuzzy::StringMatchCandidate;
use ::git::{status::FileStatus, Restore}; use ::git::Restore;
use code_context_menus::{ use code_context_menus::{
AvailableCodeAction, CodeActionContents, CodeActionsItem, CodeActionsMenu, CodeContextMenu, AvailableCodeAction, CodeActionContents, CodeActionsItem, CodeActionsMenu, CodeContextMenu,
CompletionsMenu, ContextMenuOrigin, CompletionsMenu, ContextMenuOrigin,
@ -11488,14 +11488,13 @@ impl Editor {
} }
} }
fn go_to_next_hunk(&mut self, action: &GoToHunk, window: &mut Window, cx: &mut Context<Self>) { fn go_to_next_hunk(&mut self, _: &GoToHunk, window: &mut Window, cx: &mut Context<Self>) {
let snapshot = self.snapshot(window, cx); let snapshot = self.snapshot(window, cx);
let selection = self.selections.newest::<Point>(cx); let selection = self.selections.newest::<Point>(cx);
self.go_to_hunk_after_or_before_position( self.go_to_hunk_after_or_before_position(
&snapshot, &snapshot,
selection.head(), selection.head(),
true, Direction::Next,
action.center_cursor,
window, window,
cx, cx,
); );
@ -11505,12 +11504,11 @@ impl Editor {
&mut self, &mut self,
snapshot: &EditorSnapshot, snapshot: &EditorSnapshot,
position: Point, position: Point,
after: bool, direction: Direction,
scroll_center: bool,
window: &mut Window, window: &mut Window,
cx: &mut Context<Editor>, cx: &mut Context<Editor>,
) -> Option<MultiBufferDiffHunk> { ) -> Option<MultiBufferDiffHunk> {
let hunk = if after { let hunk = if direction == Direction::Next {
self.hunk_after_position(snapshot, position) self.hunk_after_position(snapshot, position)
} else { } else {
self.hunk_before_position(snapshot, position) self.hunk_before_position(snapshot, position)
@ -11518,11 +11516,7 @@ impl Editor {
if let Some(hunk) = &hunk { if let Some(hunk) = &hunk {
let destination = Point::new(hunk.row_range.start.0, 0); let destination = Point::new(hunk.row_range.start.0, 0);
let autoscroll = if scroll_center { let autoscroll = Autoscroll::center();
Autoscroll::center()
} else {
Autoscroll::fit()
};
self.unfold_ranges(&[destination..destination], false, false, cx); self.unfold_ranges(&[destination..destination], false, false, cx);
self.change_selections(Some(autoscroll), window, cx, |s| { self.change_selections(Some(autoscroll), window, cx, |s| {
@ -11552,7 +11546,7 @@ impl Editor {
fn go_to_prev_hunk( fn go_to_prev_hunk(
&mut self, &mut self,
action: &GoToPreviousHunk, _: &GoToPreviousHunk,
window: &mut Window, window: &mut Window,
cx: &mut Context<Self>, cx: &mut Context<Self>,
) { ) {
@ -11561,8 +11555,7 @@ impl Editor {
self.go_to_hunk_after_or_before_position( self.go_to_hunk_after_or_before_position(
&snapshot, &snapshot,
selection.head(), selection.head(),
false, Direction::Prev,
action.center_cursor,
window, window,
cx, cx,
); );
@ -13639,20 +13632,20 @@ impl Editor {
pub fn stage_and_next( pub fn stage_and_next(
&mut self, &mut self,
action: &::git::StageAndNext, _: &::git::StageAndNext,
window: &mut Window, window: &mut Window,
cx: &mut Context<Self>, cx: &mut Context<Self>,
) { ) {
self.do_stage_or_unstage_and_next(true, action.whole_excerpt, window, cx); self.do_stage_or_unstage_and_next(true, window, cx);
} }
pub fn unstage_and_next( pub fn unstage_and_next(
&mut self, &mut self,
action: &::git::UnstageAndNext, _: &::git::UnstageAndNext,
window: &mut Window, window: &mut Window,
cx: &mut Context<Self>, cx: &mut Context<Self>,
) { ) {
self.do_stage_or_unstage_and_next(false, action.whole_excerpt, window, cx); self.do_stage_or_unstage_and_next(false, window, cx);
} }
pub fn stage_or_unstage_diff_hunks( pub fn stage_or_unstage_diff_hunks(
@ -13674,102 +13667,33 @@ impl Editor {
fn do_stage_or_unstage_and_next( fn do_stage_or_unstage_and_next(
&mut self, &mut self,
stage: bool, stage: bool,
whole_excerpt: bool,
window: &mut Window, window: &mut Window,
cx: &mut Context<Self>, cx: &mut Context<Self>,
) { ) {
let mut ranges = self.selections.disjoint_anchor_ranges().collect::<Vec<_>>(); let ranges = self.selections.disjoint_anchor_ranges().collect::<Vec<_>>();
if ranges.iter().any(|range| range.start != range.end) { if ranges.iter().any(|range| range.start != range.end) {
self.stage_or_unstage_diff_hunks(stage, &ranges[..], window, cx); self.stage_or_unstage_diff_hunks(stage, &ranges[..], window, cx);
return; return;
} }
if !whole_excerpt { let snapshot = self.snapshot(window, cx);
let snapshot = self.snapshot(window, cx); let newest_range = self.selections.newest::<Point>(cx).range();
let newest_range = self.selections.newest::<Point>(cx).range();
let run_twice = snapshot let run_twice = snapshot
.hunks_for_ranges([newest_range]) .hunks_for_ranges([newest_range])
.first() .first()
.is_some_and(|hunk| { .is_some_and(|hunk| {
let next_line = Point::new(hunk.row_range.end.0 + 1, 0); let next_line = Point::new(hunk.row_range.end.0 + 1, 0);
self.hunk_after_position(&snapshot, next_line) self.hunk_after_position(&snapshot, next_line)
.is_some_and(|other| other.row_range == hunk.row_range) .is_some_and(|other| other.row_range == hunk.row_range)
}); });
if run_twice { if run_twice {
self.go_to_next_hunk( self.go_to_next_hunk(&GoToHunk, window, cx);
&GoToHunk {
center_cursor: true,
},
window,
cx,
);
}
} else if !self.buffer().read(cx).is_singleton() {
self.stage_or_unstage_diff_hunks(stage, &ranges[..], window, cx);
if let Some((excerpt_id, buffer, range)) = self.active_excerpt(cx) {
if buffer.read(cx).is_empty() {
let buffer = buffer.read(cx);
let Some(file) = buffer.file() else {
return;
};
let project_path = project::ProjectPath {
worktree_id: file.worktree_id(cx),
path: file.path().clone(),
};
let Some(project) = self.project.as_ref() else {
return;
};
let Some(repo) = project.read(cx).git_store().read(cx).active_repository()
else {
return;
};
repo.update(cx, |repo, cx| {
let Some(repo_path) = repo.project_path_to_repo_path(&project_path) else {
return;
};
let Some(status) = repo.repository_entry.status_for_path(&repo_path) else {
return;
};
if stage && status.status == FileStatus::Untracked {
repo.stage_entries(vec![repo_path], cx)
.detach_and_log_err(cx);
return;
}
})
}
ranges = vec![multi_buffer::Anchor::range_in_buffer(
excerpt_id,
buffer.read(cx).remote_id(),
range,
)];
self.stage_or_unstage_diff_hunks(stage, &ranges[..], window, cx);
let snapshot = self.buffer().read(cx).snapshot(cx);
let mut point = ranges.last().unwrap().end.to_point(&snapshot);
if point.row < snapshot.max_row().0 {
point.row += 1;
point.column = 0;
point = snapshot.clip_point(point, Bias::Right);
self.change_selections(Some(Autoscroll::top_relative(6)), window, cx, |s| {
s.select_ranges([point..point]);
});
}
return;
}
} }
self.stage_or_unstage_diff_hunks(stage, &ranges[..], window, cx); self.stage_or_unstage_diff_hunks(stage, &ranges[..], window, cx);
self.go_to_next_hunk( self.go_to_next_hunk(&GoToHunk, window, cx);
&GoToHunk {
center_cursor: true,
},
window,
cx,
);
} }
fn do_stage_or_unstage( fn do_stage_or_unstage(

View file

@ -11413,7 +11413,7 @@ async fn test_go_to_hunk(executor: BackgroundExecutor, cx: &mut TestAppContext)
cx.update_editor(|editor, window, cx| { cx.update_editor(|editor, window, cx| {
//Wrap around the bottom of the buffer //Wrap around the bottom of the buffer
for _ in 0..3 { for _ in 0..3 {
editor.go_to_next_hunk(&GoToHunk::default(), window, cx); editor.go_to_next_hunk(&GoToHunk, window, cx);
} }
}); });
@ -11435,7 +11435,7 @@ async fn test_go_to_hunk(executor: BackgroundExecutor, cx: &mut TestAppContext)
cx.update_editor(|editor, window, cx| { cx.update_editor(|editor, window, cx| {
//Wrap around the top of the buffer //Wrap around the top of the buffer
for _ in 0..2 { for _ in 0..2 {
editor.go_to_prev_hunk(&GoToPreviousHunk::default(), window, cx); editor.go_to_prev_hunk(&GoToPreviousHunk, window, cx);
} }
}); });
@ -11455,7 +11455,7 @@ async fn test_go_to_hunk(executor: BackgroundExecutor, cx: &mut TestAppContext)
); );
cx.update_editor(|editor, window, cx| { cx.update_editor(|editor, window, cx| {
editor.go_to_prev_hunk(&GoToPreviousHunk::default(), window, cx); editor.go_to_prev_hunk(&GoToPreviousHunk, window, cx);
}); });
cx.assert_editor_state( cx.assert_editor_state(
@ -11474,7 +11474,7 @@ async fn test_go_to_hunk(executor: BackgroundExecutor, cx: &mut TestAppContext)
); );
cx.update_editor(|editor, window, cx| { cx.update_editor(|editor, window, cx| {
editor.go_to_prev_hunk(&GoToPreviousHunk::default(), window, cx); editor.go_to_prev_hunk(&GoToPreviousHunk, window, cx);
}); });
cx.assert_editor_state( cx.assert_editor_state(
@ -11494,7 +11494,7 @@ async fn test_go_to_hunk(executor: BackgroundExecutor, cx: &mut TestAppContext)
cx.update_editor(|editor, window, cx| { cx.update_editor(|editor, window, cx| {
for _ in 0..2 { for _ in 0..2 {
editor.go_to_prev_hunk(&GoToPreviousHunk::default(), window, cx); editor.go_to_prev_hunk(&GoToPreviousHunk, window, cx);
} }
}); });
@ -11518,7 +11518,7 @@ async fn test_go_to_hunk(executor: BackgroundExecutor, cx: &mut TestAppContext)
}); });
cx.update_editor(|editor, window, cx| { cx.update_editor(|editor, window, cx| {
editor.go_to_next_hunk(&GoToHunk::default(), window, cx); editor.go_to_next_hunk(&GoToHunk, window, cx);
}); });
cx.assert_editor_state( cx.assert_editor_state(
@ -13525,7 +13525,7 @@ async fn test_toggle_selected_diff_hunks(executor: BackgroundExecutor, cx: &mut
executor.run_until_parked(); executor.run_until_parked();
cx.update_editor(|editor, window, cx| { cx.update_editor(|editor, window, cx| {
editor.go_to_next_hunk(&GoToHunk::default(), window, cx); editor.go_to_next_hunk(&GoToHunk, window, cx);
editor.toggle_selected_diff_hunks(&ToggleSelectedDiffHunks, window, cx); editor.toggle_selected_diff_hunks(&ToggleSelectedDiffHunks, window, cx);
}); });
executor.run_until_parked(); executor.run_until_parked();
@ -13547,7 +13547,7 @@ async fn test_toggle_selected_diff_hunks(executor: BackgroundExecutor, cx: &mut
cx.update_editor(|editor, window, cx| { cx.update_editor(|editor, window, cx| {
for _ in 0..2 { for _ in 0..2 {
editor.go_to_next_hunk(&GoToHunk::default(), window, cx); editor.go_to_next_hunk(&GoToHunk, window, cx);
editor.toggle_selected_diff_hunks(&ToggleSelectedDiffHunks, window, cx); editor.toggle_selected_diff_hunks(&ToggleSelectedDiffHunks, window, cx);
} }
}); });
@ -13570,7 +13570,7 @@ async fn test_toggle_selected_diff_hunks(executor: BackgroundExecutor, cx: &mut
); );
cx.update_editor(|editor, window, cx| { cx.update_editor(|editor, window, cx| {
editor.go_to_next_hunk(&GoToHunk::default(), window, cx); editor.go_to_next_hunk(&GoToHunk, window, cx);
editor.toggle_selected_diff_hunks(&ToggleSelectedDiffHunks, window, cx); editor.toggle_selected_diff_hunks(&ToggleSelectedDiffHunks, window, cx);
}); });
executor.run_until_parked(); executor.run_until_parked();

View file

@ -42,6 +42,7 @@ use gpui::{
SharedString, Size, StatefulInteractiveElement, Style, Styled, Subscription, TextRun, SharedString, Size, StatefulInteractiveElement, Style, Styled, Subscription, TextRun,
TextStyleRefinement, Window, TextStyleRefinement, Window,
}; };
use inline_completion::Direction;
use itertools::Itertools; use itertools::Itertools;
use language::{ use language::{
language_settings::{ language_settings::{
@ -8906,7 +8907,7 @@ fn diff_hunk_controls(
move |window, cx| { move |window, cx| {
Tooltip::for_action_in( Tooltip::for_action_in(
"Next Hunk", "Next Hunk",
&GoToHunk::default(), &GoToHunk,
&focus_handle, &focus_handle,
window, window,
cx, cx,
@ -8921,7 +8922,11 @@ fn diff_hunk_controls(
let position = let position =
hunk_range.end.to_point(&snapshot.buffer_snapshot); hunk_range.end.to_point(&snapshot.buffer_snapshot);
editor.go_to_hunk_after_or_before_position( editor.go_to_hunk_after_or_before_position(
&snapshot, position, true, true, window, cx, &snapshot,
position,
Direction::Next,
window,
cx,
); );
editor.expand_selected_diff_hunks(cx); editor.expand_selected_diff_hunks(cx);
}); });
@ -8938,7 +8943,7 @@ fn diff_hunk_controls(
move |window, cx| { move |window, cx| {
Tooltip::for_action_in( Tooltip::for_action_in(
"Previous Hunk", "Previous Hunk",
&GoToPreviousHunk::default(), &GoToPreviousHunk,
&focus_handle, &focus_handle,
window, window,
cx, cx,
@ -8953,7 +8958,11 @@ fn diff_hunk_controls(
let point = let point =
hunk_range.start.to_point(&snapshot.buffer_snapshot); hunk_range.start.to_point(&snapshot.buffer_snapshot);
editor.go_to_hunk_after_or_before_position( editor.go_to_hunk_after_or_before_position(
&snapshot, point, false, true, window, cx, &snapshot,
point,
Direction::Prev,
window,
cx,
); );
editor.expand_selected_diff_hunks(cx); editor.expand_selected_diff_hunks(cx);
}); });

View file

@ -36,23 +36,15 @@ pub struct Push {
pub options: Option<PushOptions>, pub options: Option<PushOptions>,
} }
#[derive(Debug, Copy, Clone, PartialEq, Deserialize, JsonSchema)] impl_actions!(git, [Push]);
pub struct StageAndNext {
pub whole_excerpt: bool,
}
#[derive(Debug, Copy, Clone, PartialEq, Deserialize, JsonSchema)]
pub struct UnstageAndNext {
pub whole_excerpt: bool,
}
impl_actions!(git, [Push, StageAndNext, UnstageAndNext]);
actions!( actions!(
git, git,
[ [
// per-hunk // per-hunk
ToggleStaged, ToggleStaged,
StageAndNext,
UnstageAndNext,
// per-file // per-file
StageFile, StageFile,
UnstageFile, UnstageFile,

View file

@ -812,10 +812,8 @@ impl Render for ProjectDiffToolbar {
el.child( el.child(
Button::new("stage", "Stage") Button::new("stage", "Stage")
.tooltip(Tooltip::for_action_title_in( .tooltip(Tooltip::for_action_title_in(
"Stage", "Stage and go to next hunk",
&StageAndNext { &StageAndNext,
whole_excerpt: false,
},
&focus_handle, &focus_handle,
)) ))
// don't actually disable the button so it's mashable // don't actually disable the button so it's mashable
@ -825,22 +823,14 @@ impl Render for ProjectDiffToolbar {
Color::Disabled Color::Disabled
}) })
.on_click(cx.listener(|this, _, window, cx| { .on_click(cx.listener(|this, _, window, cx| {
this.dispatch_action( this.dispatch_action(&StageAndNext, window, cx)
&StageAndNext {
whole_excerpt: false,
},
window,
cx,
)
})), })),
) )
.child( .child(
Button::new("unstage", "Unstage") Button::new("unstage", "Unstage")
.tooltip(Tooltip::for_action_title_in( .tooltip(Tooltip::for_action_title_in(
"Unstage", "Unstage and go to next hunk",
&UnstageAndNext { &UnstageAndNext,
whole_excerpt: false,
},
&focus_handle, &focus_handle,
)) ))
.color(if button_states.unstage { .color(if button_states.unstage {
@ -849,13 +839,7 @@ impl Render for ProjectDiffToolbar {
Color::Disabled Color::Disabled
}) })
.on_click(cx.listener(|this, _, window, cx| { .on_click(cx.listener(|this, _, window, cx| {
this.dispatch_action( this.dispatch_action(&UnstageAndNext, window, cx)
&UnstageAndNext {
whole_excerpt: false,
},
window,
cx,
)
})), })),
) )
}), }),
@ -869,20 +853,12 @@ impl Render for ProjectDiffToolbar {
.shape(ui::IconButtonShape::Square) .shape(ui::IconButtonShape::Square)
.tooltip(Tooltip::for_action_title_in( .tooltip(Tooltip::for_action_title_in(
"Go to previous hunk", "Go to previous hunk",
&GoToPreviousHunk { &GoToPreviousHunk,
center_cursor: false,
},
&focus_handle, &focus_handle,
)) ))
.disabled(!button_states.prev_next) .disabled(!button_states.prev_next)
.on_click(cx.listener(|this, _, window, cx| { .on_click(cx.listener(|this, _, window, cx| {
this.dispatch_action( this.dispatch_action(&GoToPreviousHunk, window, cx)
&GoToPreviousHunk {
center_cursor: true,
},
window,
cx,
)
})), })),
) )
.child( .child(
@ -890,20 +866,12 @@ impl Render for ProjectDiffToolbar {
.shape(ui::IconButtonShape::Square) .shape(ui::IconButtonShape::Square)
.tooltip(Tooltip::for_action_title_in( .tooltip(Tooltip::for_action_title_in(
"Go to next hunk", "Go to next hunk",
&GoToHunk { &GoToHunk,
center_cursor: false,
},
&focus_handle, &focus_handle,
)) ))
.disabled(!button_states.prev_next) .disabled(!button_states.prev_next)
.on_click(cx.listener(|this, _, window, cx| { .on_click(cx.listener(|this, _, window, cx| {
this.dispatch_action( this.dispatch_action(&GoToHunk, window, cx)
&GoToHunk {
center_cursor: true,
},
window,
cx,
)
})), })),
), ),
) )

View file

@ -182,18 +182,8 @@ impl Render for QuickActionBar {
.action("Next Problem", Box::new(GoToDiagnostic)) .action("Next Problem", Box::new(GoToDiagnostic))
.action("Previous Problem", Box::new(GoToPreviousDiagnostic)) .action("Previous Problem", Box::new(GoToPreviousDiagnostic))
.separator() .separator()
.action( .action("Next Hunk", Box::new(GoToHunk))
"Next Hunk", .action("Previous Hunk", Box::new(GoToPreviousHunk))
Box::new(GoToHunk {
center_cursor: true,
}),
)
.action(
"Previous Hunk",
Box::new(GoToPreviousHunk {
center_cursor: true,
}),
)
.separator() .separator()
.action("Move Line Up", Box::new(MoveLineUp)) .action("Move Line Up", Box::new(MoveLineUp))
.action("Move Line Down", Box::new(MoveLineDown)) .action("Move Line Down", Box::new(MoveLineDown))

View file

@ -10,6 +10,12 @@ To preview the docs locally you will need to install [mdBook](https://rust-lang.
mdbook serve docs mdbook serve docs
``` ```
Before committing, verify that the docs are formatted in the way prettier expects with:
```
cd docs && pnpm dlx prettier@3.5.0 . --write && cd ..
```
## Preprocessor ## Preprocessor
We have a custom mdbook preprocessor for interfacing with our crates (`crates/docs_preprocessor`). We have a custom mdbook preprocessor for interfacing with our crates (`crates/docs_preprocessor`).

View file

@ -72,10 +72,15 @@ The following commands use the language server to help you navigate and refactor
### Git ### Git
| Command | Default Shortcut | | Command | Default Shortcut |
| ------------------------- | ---------------- | | ------------------------------- | ---------------- |
| Go to next git change | `] c` | | Go to next git change | `] c` |
| Go to previous git change | `[ c` | | Go to previous git change | `[ c` |
| Expand diff hunk | `d o` |
| Toggle staged | `d O` |
| Stage and next (in diff view) | `d u` |
| Unstage and next (in diff view) | `d U` |
| Restore change | `d p` |
### Treesitter ### Treesitter