Diff view refactor

This commit is contained in:
2025-02-02 17:32:08 -07:00
parent 3e6efb7736
commit d938988d43
8 changed files with 814 additions and 1118 deletions

View File

@@ -1,22 +1,10 @@
use egui::{RichText, ScrollArea};
use egui::ScrollArea;
use objdiff_core::{
arch::ppc::ExceptionInfo,
obj::{ObjInfo, ObjSymbol},
};
use time::format_description;
use crate::{
hotkeys,
views::{
appearance::Appearance,
column_layout::{render_header, render_strips},
function_diff::FunctionDiffContext,
symbol_diff::{
match_color_for_symbol, DiffViewAction, DiffViewNavigation, DiffViewState,
SymbolRefByName, View,
},
},
};
use crate::views::{appearance::Appearance, function_diff::FunctionDiffContext};
fn decode_extab(extab: &ExceptionInfo) -> String {
let mut text = String::from("");
@@ -57,7 +45,7 @@ fn extab_text_ui(
None
}
fn extab_ui(
pub(crate) fn extab_ui(
ui: &mut egui::Ui,
ctx: FunctionDiffContext<'_>,
appearance: &Appearance,
@@ -76,178 +64,3 @@ fn extab_ui(
});
});
}
#[must_use]
pub fn extab_diff_ui(
ui: &mut egui::Ui,
state: &DiffViewState,
appearance: &Appearance,
) -> Option<DiffViewAction> {
let mut ret = None;
let Some(result) = &state.build else {
return ret;
};
let mut left_ctx = FunctionDiffContext::new(
result.first_obj.as_ref(),
state.symbol_state.left_symbol.as_ref(),
);
let mut right_ctx = FunctionDiffContext::new(
result.second_obj.as_ref(),
state.symbol_state.right_symbol.as_ref(),
);
// If one side is missing a symbol, but the diff process found a match, use that symbol
let left_diff_symbol = left_ctx.and_then(|ctx| {
ctx.symbol_ref.and_then(|symbol_ref| ctx.diff.symbol_diff(symbol_ref).target_symbol)
});
let right_diff_symbol = right_ctx.and_then(|ctx| {
ctx.symbol_ref.and_then(|symbol_ref| ctx.diff.symbol_diff(symbol_ref).target_symbol)
});
if left_diff_symbol.is_some() && right_ctx.is_some_and(|ctx| !ctx.has_symbol()) {
let (right_section, right_symbol) =
right_ctx.unwrap().obj.section_symbol(left_diff_symbol.unwrap());
let symbol_ref = SymbolRefByName::new(right_symbol, right_section);
right_ctx = FunctionDiffContext::new(result.second_obj.as_ref(), Some(&symbol_ref));
ret = Some(DiffViewAction::Navigate(DiffViewNavigation {
view: Some(View::FunctionDiff),
left_symbol: state.symbol_state.left_symbol.clone(),
right_symbol: Some(symbol_ref),
}));
} else if right_diff_symbol.is_some() && left_ctx.is_some_and(|ctx| !ctx.has_symbol()) {
let (left_section, left_symbol) =
left_ctx.unwrap().obj.section_symbol(right_diff_symbol.unwrap());
let symbol_ref = SymbolRefByName::new(left_symbol, left_section);
left_ctx = FunctionDiffContext::new(result.first_obj.as_ref(), Some(&symbol_ref));
ret = Some(DiffViewAction::Navigate(DiffViewNavigation {
view: Some(View::FunctionDiff),
left_symbol: Some(symbol_ref),
right_symbol: state.symbol_state.right_symbol.clone(),
}));
}
// If both sides are missing a symbol, switch to symbol diff view
if right_ctx.is_some_and(|ctx| !ctx.has_symbol())
&& left_ctx.is_some_and(|ctx| !ctx.has_symbol())
{
return Some(DiffViewAction::Navigate(DiffViewNavigation::symbol_diff()));
}
// Header
let available_width = ui.available_width();
render_header(ui, available_width, 2, |ui, column| {
if column == 0 {
// Left column
ui.horizontal(|ui| {
if ui.button("⏴ Back").clicked() || hotkeys::back_pressed(ui.ctx()) {
ret = Some(DiffViewAction::Navigate(DiffViewNavigation::symbol_diff()));
}
ui.separator();
if ui
.add_enabled(
!state.scratch_running
&& state.scratch_available
&& left_ctx.is_some_and(|ctx| ctx.has_symbol()),
egui::Button::new("📲 decomp.me"),
)
.on_hover_text_at_pointer("Create a new scratch on decomp.me (beta)")
.on_disabled_hover_text("Scratch configuration missing")
.clicked()
{
if let Some((_section, symbol)) = left_ctx.and_then(|ctx| {
ctx.symbol_ref.map(|symbol_ref| ctx.obj.section_symbol(symbol_ref))
}) {
ret = Some(DiffViewAction::CreateScratch(symbol.name.clone()));
}
}
});
if let Some((_section, symbol)) = left_ctx
.and_then(|ctx| ctx.symbol_ref.map(|symbol_ref| ctx.obj.section_symbol(symbol_ref)))
{
let name = symbol.demangled_name.as_deref().unwrap_or(&symbol.name);
ui.label(
RichText::new(name)
.font(appearance.code_font.clone())
.color(appearance.highlight_color),
);
} else {
ui.label(
RichText::new("Missing")
.font(appearance.code_font.clone())
.color(appearance.replace_color),
);
}
} else if column == 1 {
// Right column
ui.horizontal(|ui| {
if ui.add_enabled(!state.build_running, egui::Button::new("Build")).clicked() {
ret = Some(DiffViewAction::Build);
}
ui.scope(|ui| {
ui.style_mut().override_text_style = Some(egui::TextStyle::Monospace);
if state.build_running {
ui.colored_label(appearance.replace_color, "Building…");
} else {
ui.label("Last built:");
let format = format_description::parse("[hour]:[minute]:[second]").unwrap();
ui.label(
result.time.to_offset(appearance.utc_offset).format(&format).unwrap(),
);
}
});
ui.separator();
if ui
.add_enabled(state.source_path_available, egui::Button::new("🖹 Source file"))
.on_hover_text_at_pointer("Open the source file in the default editor")
.on_disabled_hover_text("Source file metadata missing")
.clicked()
{
ret = Some(DiffViewAction::OpenSourcePath);
}
});
if let Some(((_section, symbol), symbol_diff)) = right_ctx.and_then(|ctx| {
ctx.symbol_ref.map(|symbol_ref| {
(ctx.obj.section_symbol(symbol_ref), ctx.diff.symbol_diff(symbol_ref))
})
}) {
let name = symbol.demangled_name.as_deref().unwrap_or(&symbol.name);
ui.label(
RichText::new(name)
.font(appearance.code_font.clone())
.color(appearance.highlight_color),
);
if let Some(match_percent) = symbol_diff.match_percent {
ui.label(
RichText::new(format!("{:.0}%", match_percent.floor()))
.font(appearance.code_font.clone())
.color(match_color_for_symbol(match_percent, appearance)),
);
}
} else {
ui.label(
RichText::new("Missing")
.font(appearance.code_font.clone())
.color(appearance.replace_color),
);
}
}
});
hotkeys::check_scroll_hotkeys(ui, true);
// Table
render_strips(ui, available_width, 2, |ui, column| {
if column == 0 {
if let Some(ctx) = left_ctx {
extab_ui(ui, ctx, appearance, column);
}
} else if column == 1 {
if let Some(ctx) = right_ctx {
extab_ui(ui, ctx, appearance, column);
}
}
});
ret
}