Skip to content

Commit 4cd425f

Browse files
committed
feat: support 'n'/'p' key to move to the next/prev hunk.
1 parent ff48840 commit 4cd425f

File tree

3 files changed

+92
-1
lines changed

3 files changed

+92
-1
lines changed

src/components/diff.rs

Lines changed: 64 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -629,6 +629,48 @@ impl DiffComponent {
629629
Ok(())
630630
}
631631

632+
fn calc_hunk_move_target(
633+
&self,
634+
direction: isize,
635+
) -> Option<usize> {
636+
let diff = self.diff.as_ref()?;
637+
if diff.hunks.is_empty() {
638+
return None;
639+
}
640+
let max = diff.hunks.len() as isize - 1;
641+
let target_index = self
642+
.selected_hunk
643+
.map(|i| {
644+
std::cmp::max(
645+
0,
646+
std::cmp::min(max, i as isize + direction),
647+
)
648+
})
649+
.unwrap_or(0) as usize;
650+
Some(target_index)
651+
}
652+
653+
fn diff_hunk_move_up_down(&mut self, direction: isize) {
654+
let diff = match &self.diff {
655+
Some(diff) => diff,
656+
None => return,
657+
};
658+
let target_index = self.calc_hunk_move_target(direction);
659+
// return if selected_hunk not change
660+
if self.selected_hunk == target_index {
661+
return;
662+
}
663+
if let Some(target_index) = target_index {
664+
let lines = diff
665+
.hunks
666+
.iter()
667+
.take(target_index)
668+
.fold(0, |sum, hunk| sum + hunk.lines.len());
669+
self.selection = Selection::Single(lines);
670+
self.selected_hunk = Some(target_index);
671+
}
672+
}
673+
632674
const fn is_stage(&self) -> bool {
633675
self.current.is_stage
634676
}
@@ -710,7 +752,16 @@ impl Component for DiffComponent {
710752
self.can_scroll(),
711753
self.focused(),
712754
));
713-
755+
out.push(CommandInfo::new(
756+
strings::commands::diff_hunk_next(&self.key_config),
757+
self.calc_hunk_move_target(1) != self.selected_hunk,
758+
self.focused(),
759+
));
760+
out.push(CommandInfo::new(
761+
strings::commands::diff_hunk_prev(&self.key_config),
762+
self.calc_hunk_move_target(-1) != self.selected_hunk,
763+
self.focused(),
764+
));
714765
out.push(
715766
CommandInfo::new(
716767
strings::commands::diff_home_end(&self.key_config),
@@ -815,6 +866,18 @@ impl Component for DiffComponent {
815866
self.horizontal_scroll
816867
.move_right(HorizontalScrollType::Left);
817868
Ok(EventState::Consumed)
869+
} else if key_match(
870+
e,
871+
self.key_config.keys.diff_hunk_next,
872+
) {
873+
self.diff_hunk_move_up_down(1);
874+
Ok(EventState::Consumed)
875+
} else if key_match(
876+
e,
877+
self.key_config.keys.diff_hunk_prev,
878+
) {
879+
self.diff_hunk_move_up_down(-1);
880+
Ok(EventState::Consumed)
818881
} else if key_match(
819882
e,
820883
self.key_config.keys.stage_unstage_item,

src/keys/key_list.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -109,6 +109,8 @@ pub struct KeysList {
109109
pub pull: GituiKeyEvent,
110110
pub abort_merge: GituiKeyEvent,
111111
pub undo_commit: GituiKeyEvent,
112+
pub diff_hunk_next: GituiKeyEvent,
113+
pub diff_hunk_prev: GituiKeyEvent,
112114
pub stage_unstage_item: GituiKeyEvent,
113115
pub tag_annotate: GituiKeyEvent,
114116
pub view_submodules: GituiKeyEvent,
@@ -193,6 +195,8 @@ impl Default for KeysList {
193195
open_file_tree: GituiKeyEvent::new(KeyCode::Char('F'), KeyModifiers::SHIFT),
194196
file_find: GituiKeyEvent::new(KeyCode::Char('f'), KeyModifiers::empty()),
195197
branch_find: GituiKeyEvent::new(KeyCode::Char('f'), KeyModifiers::empty()),
198+
diff_hunk_next: GituiKeyEvent::new(KeyCode::Char('n'), KeyModifiers::empty()),
199+
diff_hunk_prev: GituiKeyEvent::new(KeyCode::Char('p'), KeyModifiers::empty()),
196200
stage_unstage_item: GituiKeyEvent::new(KeyCode::Enter, KeyModifiers::empty()),
197201
tag_annotate: GituiKeyEvent::new(KeyCode::Char('a'), KeyModifiers::CONTROL),
198202
view_submodules: GituiKeyEvent::new(KeyCode::Char('S'), KeyModifiers::SHIFT),

src/strings.rs

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -603,6 +603,30 @@ pub mod commands {
603603
CMD_GROUP_LOG,
604604
)
605605
}
606+
pub fn diff_hunk_next(
607+
key_config: &SharedKeyConfig,
608+
) -> CommandText {
609+
CommandText::new(
610+
format!(
611+
"Next hunk [{}]",
612+
key_config.get_hint(key_config.keys.diff_hunk_next),
613+
),
614+
"move cursor to next hunk",
615+
CMD_GROUP_DIFF,
616+
)
617+
}
618+
pub fn diff_hunk_prev(
619+
key_config: &SharedKeyConfig,
620+
) -> CommandText {
621+
CommandText::new(
622+
format!(
623+
"Prev hunk [{}]",
624+
key_config.get_hint(key_config.keys.diff_hunk_prev),
625+
),
626+
"move cursor to prev hunk",
627+
CMD_GROUP_DIFF,
628+
)
629+
}
606630
pub fn diff_home_end(
607631
key_config: &SharedKeyConfig,
608632
) -> CommandText {

0 commit comments

Comments
 (0)