Skip to content

Commit 244b4ae

Browse files
committed
Implement go to next/previous difference
1 parent 7834185 commit 244b4ae

4 files changed

Lines changed: 108 additions & 10 deletions

File tree

objdiff-gui/src/hotkeys.rs

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -50,9 +50,9 @@ pub fn end_pressed(ctx: &Context) -> bool { ctx.input_mut(|i| i.key_pressed(Key:
5050

5151
pub fn check_scroll_hotkeys(ui: &mut egui::Ui, include_small_increments: bool) {
5252
let ui_height = ui.available_rect_before_wrap().height();
53-
if up_pressed(ui.ctx()) && include_small_increments {
53+
if include_small_increments && consume_up_key(ui.ctx()) {
5454
ui.scroll_with_delta_animation(vec2(0.0, ui_height / 10.0), ScrollAnimation::none());
55-
} else if down_pressed(ui.ctx()) && include_small_increments {
55+
} else if include_small_increments && consume_down_key(ui.ctx()) {
5656
ui.scroll_with_delta_animation(vec2(0.0, -ui_height / 10.0), ScrollAnimation::none());
5757
} else if page_up_pressed(ui.ctx()) {
5858
ui.scroll_with_delta_animation(vec2(0.0, ui_height), ScrollAnimation::none());
@@ -106,3 +106,15 @@ const CHANGE_BASE_SHORTCUT: KeyboardShortcut = KeyboardShortcut::new(Modifiers::
106106
pub fn consume_change_base_shortcut(ctx: &Context) -> bool {
107107
ctx.input_mut(|i| i.consume_shortcut(&CHANGE_BASE_SHORTCUT))
108108
}
109+
110+
const PREV_DIFF_SHORTCUT: KeyboardShortcut = KeyboardShortcut::new(Modifiers::CTRL, Key::ArrowUp);
111+
112+
pub fn consume_prev_diff_shortcut(ctx: &Context) -> bool {
113+
ctx.input_mut(|i| i.consume_shortcut(&PREV_DIFF_SHORTCUT))
114+
}
115+
116+
const NEXT_DIFF_SHORTCUT: KeyboardShortcut = KeyboardShortcut::new(Modifiers::CTRL, Key::ArrowDown);
117+
118+
pub fn consume_next_diff_shortcut(ctx: &Context) -> bool {
119+
ctx.input_mut(|i| i.consume_shortcut(&NEXT_DIFF_SHORTCUT))
120+
}

objdiff-gui/src/views/diff.rs

Lines changed: 91 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ use egui::{Id, Layout, RichText, ScrollArea, TextEdit, Ui, Widget, text::LayoutJ
44
use objdiff_core::{
55
build::BuildStatus,
66
diff::{
7-
DiffObjConfig, ObjectDiff, SymbolDiff,
7+
DataDiffKind, DiffObjConfig, InstructionDiffKind, ObjectDiff, SymbolDiff,
88
data::BYTES_PER_ROW,
99
display::{
1010
ContextItem, DiffText, HoverItem, HoverItemColor, SymbolFilter, SymbolNavigationKind,
@@ -185,6 +185,9 @@ pub fn diff_view_ui(
185185
let available_width = ui.available_width();
186186
let mut open_sections = (None, None);
187187

188+
let mut scroll_to_prev_diff = false;
189+
let mut scroll_to_next_diff = false;
190+
188191
render_header(ui, available_width, 2, |ui, column| {
189192
if column == 0 {
190193
// Left column
@@ -450,6 +453,31 @@ pub fn diff_view_ui(
450453
{
451454
ret = Some(DiffViewAction::SelectingRight(symbol_ref.clone()));
452455
}
456+
needs_separator = true;
457+
}
458+
459+
if state.current_view == View::FunctionDiff
460+
|| state.current_view == View::DataDiff
461+
{
462+
if needs_separator {
463+
ui.separator();
464+
}
465+
if ui
466+
.button("⏴ Prev diff")
467+
.on_hover_text_at_pointer("Scroll to the previous difference (Ctrl+Up)")
468+
.clicked()
469+
|| hotkeys::consume_prev_diff_shortcut(ui.ctx())
470+
{
471+
scroll_to_prev_diff = true;
472+
}
473+
if ui
474+
.button("Next diff ⏵")
475+
.on_hover_text_at_pointer("Scroll to the next difference (Ctrl+Down)")
476+
.clicked()
477+
|| hotkeys::consume_next_diff_shortcut(ui.ctx())
478+
{
479+
scroll_to_next_diff = true;
480+
}
453481
}
454482
} else if right_ctx.status.success && !right_ctx.has_symbol() {
455483
let mut search = state.search.clone();
@@ -493,14 +521,21 @@ pub fn diff_view_ui(
493521
return;
494522
}
495523
let instructions_len = left_symbol_diff.instruction_rows.len();
524+
let mut min_row = None;
525+
let mut max_row = None;
496526
render_table(
497527
ui,
498528
available_width,
499529
2,
500530
appearance.code_font.size,
501531
instructions_len,
502-
state.function_state.scroll_to_row,
532+
state.scroll_to_diff_row,
503533
|row, column| {
534+
if min_row.is_none() {
535+
min_row = Some(row.index());
536+
}
537+
max_row = Some(row.index());
538+
504539
if column == 0 {
505540
if let Some(action) = asm_col_ui(
506541
row,
@@ -537,6 +572,27 @@ pub fn diff_view_ui(
537572
}
538573
},
539574
);
575+
576+
if scroll_to_prev_diff && let Some(min_row) = min_row {
577+
for (ins_idx, ins_diff) in
578+
right_diff.symbols[right_symbol_idx].instruction_rows.iter().enumerate().rev()
579+
{
580+
if ins_idx <= min_row && ins_diff.kind != InstructionDiffKind::None {
581+
ret = Some(DiffViewAction::ScrollToRow(ins_idx));
582+
break;
583+
}
584+
}
585+
}
586+
if scroll_to_next_diff && let Some(max_row) = max_row {
587+
for (ins_idx, ins_diff) in
588+
right_diff.symbols[right_symbol_idx].instruction_rows.iter().enumerate()
589+
{
590+
if ins_idx >= max_row - 1 && ins_diff.kind != InstructionDiffKind::None {
591+
ret = Some(DiffViewAction::ScrollToRow(ins_idx));
592+
break;
593+
}
594+
}
595+
}
540596
} else if let (
541597
View::DataDiff,
542598
Some((left_obj, _left_diff)),
@@ -556,14 +612,21 @@ pub fn diff_view_ui(
556612
if total_rows == 0 {
557613
return;
558614
}
615+
let mut min_row = None;
616+
let mut max_row = None;
559617
render_table(
560618
ui,
561619
available_width,
562620
2,
563621
appearance.code_font.size,
564622
total_rows,
565-
None,
623+
state.scroll_to_diff_row,
566624
|row, column| {
625+
if min_row.is_none() {
626+
min_row = Some(row.index());
627+
}
628+
max_row = Some(row.index());
629+
567630
let i = row.index();
568631
let row_offset = i as u64 * BYTES_PER_ROW as u64;
569632
row.col(|ui| {
@@ -591,6 +654,29 @@ pub fn diff_view_ui(
591654
});
592655
},
593656
);
657+
658+
if scroll_to_prev_diff && let Some(min_row) = min_row {
659+
for (row_idx, diff_row) in right_symbol_diff.data_rows.iter().enumerate().rev() {
660+
if row_idx <= min_row
661+
&& (diff_row.segments.iter().any(|dd| dd.kind != DataDiffKind::None)
662+
|| diff_row.relocations.iter().any(|rd| rd.kind != DataDiffKind::None))
663+
{
664+
ret = Some(DiffViewAction::ScrollToRow(row_idx));
665+
break;
666+
}
667+
}
668+
}
669+
if scroll_to_next_diff && let Some(max_row) = max_row {
670+
for (row_idx, diff_row) in right_symbol_diff.data_rows.iter().enumerate() {
671+
if row_idx >= max_row - 1
672+
&& (diff_row.segments.iter().any(|dd| dd.kind != DataDiffKind::None)
673+
|| diff_row.relocations.iter().any(|rd| rd.kind != DataDiffKind::None))
674+
{
675+
ret = Some(DiffViewAction::ScrollToRow(row_idx));
676+
break;
677+
}
678+
}
679+
}
594680
} else {
595681
// Split view
596682
render_strips(ui, available_width, 2, |ui, column| {
@@ -693,7 +779,7 @@ fn diff_col_ui(
693779
1,
694780
appearance.code_font.size,
695781
total_rows,
696-
None,
782+
state.scroll_to_diff_row,
697783
|row, _column| {
698784
let i = row.index();
699785
let row_offset = i as u64 * BYTES_PER_ROW as u64;
@@ -717,7 +803,7 @@ fn diff_col_ui(
717803
1,
718804
appearance.code_font.size,
719805
symbol_diff.instruction_rows.len(),
720-
state.function_state.scroll_to_row,
806+
state.scroll_to_diff_row,
721807
|row, column| {
722808
if let Some(action) = asm_col_ui(
723809
row,

objdiff-gui/src/views/function_diff.rs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,6 @@ use crate::views::{
2424
pub struct FunctionViewState {
2525
left_highlight: HighlightKind,
2626
right_highlight: HighlightKind,
27-
pub scroll_to_row: Option<usize>,
2827
}
2928

3029
impl FunctionViewState {

objdiff-gui/src/views/symbol_diff.rs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -118,6 +118,7 @@ pub struct DiffViewState {
118118
pub function_state: FunctionViewState,
119119
pub search: String,
120120
pub search_regex: Option<Regex>,
121+
pub scroll_to_diff_row: Option<usize>,
121122
pub build_running: bool,
122123
pub scratch_available: bool,
123124
pub scratch_running: bool,
@@ -197,7 +198,7 @@ impl DiffViewState {
197198

198199
// Clear the scroll flags to prevent it from scrolling continuously.
199200
self.symbol_state.autoscroll_to_highlighted_symbols = false;
200-
self.function_state.scroll_to_row = None;
201+
self.scroll_to_diff_row = None;
201202

202203
let Some(action) = action else {
203204
return;
@@ -366,7 +367,7 @@ impl DiffViewState {
366367
state.config.diff_obj_config.show_data_flow = value;
367368
}
368369
DiffViewAction::ScrollToRow(row) => {
369-
self.function_state.scroll_to_row = Some(row);
370+
self.scroll_to_diff_row = Some(row);
370371
}
371372
}
372373
}

0 commit comments

Comments
 (0)