Implement go to next/previous difference (#313)

This commit is contained in:
LagoLunatic
2026-01-24 18:47:27 -05:00
committed by GitHub
parent 7834185223
commit 8356fe670d
4 changed files with 108 additions and 10 deletions
+14 -2
View File
@@ -50,9 +50,9 @@ pub fn end_pressed(ctx: &Context) -> bool { ctx.input_mut(|i| i.key_pressed(Key:
pub fn check_scroll_hotkeys(ui: &mut egui::Ui, include_small_increments: bool) {
let ui_height = ui.available_rect_before_wrap().height();
if up_pressed(ui.ctx()) && include_small_increments {
if include_small_increments && consume_up_key(ui.ctx()) {
ui.scroll_with_delta_animation(vec2(0.0, ui_height / 10.0), ScrollAnimation::none());
} else if down_pressed(ui.ctx()) && include_small_increments {
} else if include_small_increments && consume_down_key(ui.ctx()) {
ui.scroll_with_delta_animation(vec2(0.0, -ui_height / 10.0), ScrollAnimation::none());
} else if page_up_pressed(ui.ctx()) {
ui.scroll_with_delta_animation(vec2(0.0, ui_height), ScrollAnimation::none());
@@ -106,3 +106,15 @@ const CHANGE_BASE_SHORTCUT: KeyboardShortcut = KeyboardShortcut::new(Modifiers::
pub fn consume_change_base_shortcut(ctx: &Context) -> bool {
ctx.input_mut(|i| i.consume_shortcut(&CHANGE_BASE_SHORTCUT))
}
const PREV_DIFF_SHORTCUT: KeyboardShortcut = KeyboardShortcut::new(Modifiers::CTRL, Key::ArrowUp);
pub fn consume_prev_diff_shortcut(ctx: &Context) -> bool {
ctx.input_mut(|i| i.consume_shortcut(&PREV_DIFF_SHORTCUT))
}
const NEXT_DIFF_SHORTCUT: KeyboardShortcut = KeyboardShortcut::new(Modifiers::CTRL, Key::ArrowDown);
pub fn consume_next_diff_shortcut(ctx: &Context) -> bool {
ctx.input_mut(|i| i.consume_shortcut(&NEXT_DIFF_SHORTCUT))
}
+91 -5
View File
@@ -4,7 +4,7 @@ use egui::{Id, Layout, RichText, ScrollArea, TextEdit, Ui, Widget, text::LayoutJ
use objdiff_core::{
build::BuildStatus,
diff::{
DiffObjConfig, ObjectDiff, SymbolDiff,
DataDiffKind, DiffObjConfig, InstructionDiffKind, ObjectDiff, SymbolDiff,
data::BYTES_PER_ROW,
display::{
ContextItem, DiffText, HoverItem, HoverItemColor, SymbolFilter, SymbolNavigationKind,
@@ -185,6 +185,9 @@ pub fn diff_view_ui(
let available_width = ui.available_width();
let mut open_sections = (None, None);
let mut scroll_to_prev_diff = false;
let mut scroll_to_next_diff = false;
render_header(ui, available_width, 2, |ui, column| {
if column == 0 {
// Left column
@@ -450,6 +453,31 @@ pub fn diff_view_ui(
{
ret = Some(DiffViewAction::SelectingRight(symbol_ref.clone()));
}
needs_separator = true;
}
if state.current_view == View::FunctionDiff
|| state.current_view == View::DataDiff
{
if needs_separator {
ui.separator();
}
if ui
.button("⏴ Prev diff")
.on_hover_text_at_pointer("Scroll to the previous difference (Ctrl+Up)")
.clicked()
|| hotkeys::consume_prev_diff_shortcut(ui.ctx())
{
scroll_to_prev_diff = true;
}
if ui
.button("Next diff ⏵")
.on_hover_text_at_pointer("Scroll to the next difference (Ctrl+Down)")
.clicked()
|| hotkeys::consume_next_diff_shortcut(ui.ctx())
{
scroll_to_next_diff = true;
}
}
} else if right_ctx.status.success && !right_ctx.has_symbol() {
let mut search = state.search.clone();
@@ -493,14 +521,21 @@ pub fn diff_view_ui(
return;
}
let instructions_len = left_symbol_diff.instruction_rows.len();
let mut min_row = None;
let mut max_row = None;
render_table(
ui,
available_width,
2,
appearance.code_font.size,
instructions_len,
state.function_state.scroll_to_row,
state.scroll_to_diff_row,
|row, column| {
if min_row.is_none() {
min_row = Some(row.index());
}
max_row = Some(row.index());
if column == 0 {
if let Some(action) = asm_col_ui(
row,
@@ -537,6 +572,27 @@ pub fn diff_view_ui(
}
},
);
if scroll_to_prev_diff && let Some(min_row) = min_row {
for (ins_idx, ins_diff) in
right_diff.symbols[right_symbol_idx].instruction_rows.iter().enumerate().rev()
{
if ins_idx <= min_row && ins_diff.kind != InstructionDiffKind::None {
ret = Some(DiffViewAction::ScrollToRow(ins_idx));
break;
}
}
}
if scroll_to_next_diff && let Some(max_row) = max_row {
for (ins_idx, ins_diff) in
right_diff.symbols[right_symbol_idx].instruction_rows.iter().enumerate()
{
if ins_idx >= max_row - 1 && ins_diff.kind != InstructionDiffKind::None {
ret = Some(DiffViewAction::ScrollToRow(ins_idx));
break;
}
}
}
} else if let (
View::DataDiff,
Some((left_obj, _left_diff)),
@@ -556,14 +612,21 @@ pub fn diff_view_ui(
if total_rows == 0 {
return;
}
let mut min_row = None;
let mut max_row = None;
render_table(
ui,
available_width,
2,
appearance.code_font.size,
total_rows,
None,
state.scroll_to_diff_row,
|row, column| {
if min_row.is_none() {
min_row = Some(row.index());
}
max_row = Some(row.index());
let i = row.index();
let row_offset = i as u64 * BYTES_PER_ROW as u64;
row.col(|ui| {
@@ -591,6 +654,29 @@ pub fn diff_view_ui(
});
},
);
if scroll_to_prev_diff && let Some(min_row) = min_row {
for (row_idx, diff_row) in right_symbol_diff.data_rows.iter().enumerate().rev() {
if row_idx <= min_row
&& (diff_row.segments.iter().any(|dd| dd.kind != DataDiffKind::None)
|| diff_row.relocations.iter().any(|rd| rd.kind != DataDiffKind::None))
{
ret = Some(DiffViewAction::ScrollToRow(row_idx));
break;
}
}
}
if scroll_to_next_diff && let Some(max_row) = max_row {
for (row_idx, diff_row) in right_symbol_diff.data_rows.iter().enumerate() {
if row_idx >= max_row - 1
&& (diff_row.segments.iter().any(|dd| dd.kind != DataDiffKind::None)
|| diff_row.relocations.iter().any(|rd| rd.kind != DataDiffKind::None))
{
ret = Some(DiffViewAction::ScrollToRow(row_idx));
break;
}
}
}
} else {
// Split view
render_strips(ui, available_width, 2, |ui, column| {
@@ -693,7 +779,7 @@ fn diff_col_ui(
1,
appearance.code_font.size,
total_rows,
None,
state.scroll_to_diff_row,
|row, _column| {
let i = row.index();
let row_offset = i as u64 * BYTES_PER_ROW as u64;
@@ -717,7 +803,7 @@ fn diff_col_ui(
1,
appearance.code_font.size,
symbol_diff.instruction_rows.len(),
state.function_state.scroll_to_row,
state.scroll_to_diff_row,
|row, column| {
if let Some(action) = asm_col_ui(
row,
-1
View File
@@ -24,7 +24,6 @@ use crate::views::{
pub struct FunctionViewState {
left_highlight: HighlightKind,
right_highlight: HighlightKind,
pub scroll_to_row: Option<usize>,
}
impl FunctionViewState {
+3 -2
View File
@@ -118,6 +118,7 @@ pub struct DiffViewState {
pub function_state: FunctionViewState,
pub search: String,
pub search_regex: Option<Regex>,
pub scroll_to_diff_row: Option<usize>,
pub build_running: bool,
pub scratch_available: bool,
pub scratch_running: bool,
@@ -197,7 +198,7 @@ impl DiffViewState {
// Clear the scroll flags to prevent it from scrolling continuously.
self.symbol_state.autoscroll_to_highlighted_symbols = false;
self.function_state.scroll_to_row = None;
self.scroll_to_diff_row = None;
let Some(action) = action else {
return;
@@ -366,7 +367,7 @@ impl DiffViewState {
state.config.diff_obj_config.show_data_flow = value;
}
DiffViewAction::ScrollToRow(row) => {
self.function_state.scroll_to_row = Some(row);
self.scroll_to_diff_row = Some(row);
}
}
}