Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
104 changes: 92 additions & 12 deletions objdiff-gui/src/views/diff.rs
Original file line number Diff line number Diff line change
@@ -1,12 +1,18 @@
use std::cmp::Ordering;

use egui::{Id, Layout, RichText, ScrollArea, TextEdit, Ui, Widget, text::LayoutJob};
use objdiff_core::{
build::BuildStatus,
diff::{
DiffObjConfig, ObjectDiff, SymbolDiff,
data::BYTES_PER_ROW,
display::{ContextItem, HoverItem, HoverItemColor, SymbolFilter, SymbolNavigationKind},
display::{
ContextItem, DiffText, HoverItem, HoverItemColor, SymbolFilter, SymbolNavigationKind,
display_row,
},
},
obj::{Object, Symbol},
obj::{InstructionArgValue, Object, Symbol},
util::ReallySigned,
};
use time::format_description;

Expand Down Expand Up @@ -64,6 +70,51 @@ impl<'a> DiffColumnContext<'a> {
pub fn id(&self) -> Option<&str> { self.symbol.map(|(symbol, _, _)| symbol.name.as_str()) }
}

/// Obtains the assembly text for a given symbol diff, suitable for copying to clipboard.
fn get_asm_text(
obj: &Object,
symbol_diff: &SymbolDiff,
symbol_idx: usize,
diff_config: &DiffObjConfig,
) -> String {
let mut asm_text = String::new();

for ins_row in &symbol_diff.instruction_rows {
let mut line = String::new();
let result = display_row(obj, symbol_idx, ins_row, diff_config, |segment| {
let text = match segment.text {
DiffText::Basic(text) => text.to_string(),
DiffText::Line(num) => format!("{num} "),
DiffText::Address(addr) => format!("{addr:x}:"),
DiffText::Opcode(mnemonic, _op) => format!("{mnemonic} "),
DiffText::Argument(arg) => match arg {
InstructionArgValue::Signed(v) => format!("{:#x}", ReallySigned(v)),
InstructionArgValue::Unsigned(v) => format!("{v:#x}"),
InstructionArgValue::Opaque(v) => v.into_owned(),
},
DiffText::BranchDest(addr) => format!("{addr:x}"),
DiffText::Symbol(sym) => sym.demangled_name.as_ref().unwrap_or(&sym.name).clone(),
DiffText::Addend(addend) => match addend.cmp(&0i64) {
Ordering::Greater => format!("+{addend:#x}"),
Ordering::Less => format!("-{:#x}", -addend),
_ => String::new(),
},
DiffText::Spacing(n) => " ".repeat(n.into()),
DiffText::Eol => "\n".to_string(),
};
line.push_str(&text);
Ok(())
});

if result.is_ok() {
asm_text.push_str(line.trim_end());
asm_text.push('\n');
}
}

asm_text
}

#[must_use]
pub fn diff_view_ui(
ui: &mut Ui,
Expand Down Expand Up @@ -208,16 +259,33 @@ pub fn diff_view_ui(

// Third row
if left_ctx.has_symbol() && right_ctx.has_symbol() {
if (state.current_view == View::FunctionDiff
&& ui
.button("Change target")
.on_hover_text_at_pointer("Choose a different symbol to use as the target")
.clicked()
|| hotkeys::consume_change_target_shortcut(ui.ctx()))
&& let Some(symbol_ref) = state.symbol_state.right_symbol.as_ref()
{
ret = Some(DiffViewAction::SelectingLeft(symbol_ref.clone()));
}
ui.horizontal(|ui| {
if (state.current_view == View::FunctionDiff
&& ui
.button("Change target")
.on_hover_text_at_pointer(
"Choose a different symbol to use as the target",
)
.clicked()
|| hotkeys::consume_change_target_shortcut(ui.ctx()))
&& let Some(symbol_ref) = state.symbol_state.right_symbol.as_ref()
{
ret = Some(DiffViewAction::SelectingLeft(symbol_ref.clone()));
}

// Copy target ASM button.
if state.current_view == View::FunctionDiff
&& let Some((_, symbol_diff, symbol_idx)) = left_ctx.symbol
&& let Some((obj, _)) = left_ctx.obj
&& ui
.button("📋 Copy ASM")
.on_hover_text_at_pointer("Copy assembly to clipboard")
.clicked()
{
let asm_text = get_asm_text(obj, symbol_diff, symbol_idx, diff_config);
ui.ctx().copy_text(asm_text);
}
});
} else if left_ctx.status.success && !left_ctx.has_symbol() {
ui.horizontal(|ui| {
let mut search = state.search.clone();
Expand Down Expand Up @@ -374,6 +442,18 @@ pub fn diff_view_ui(
{
ret = Some(DiffViewAction::SelectingRight(symbol_ref.clone()));
}

// Copy base ASM button.
if let Some((_, symbol_diff, symbol_idx)) = right_ctx.symbol
&& let Some((obj, _)) = right_ctx.obj
&& ui
.button("📋 Copy ASM")
.on_hover_text_at_pointer("Copy assembly to clipboard")
.clicked()
{
let asm_text = get_asm_text(obj, symbol_diff, symbol_idx, diff_config);
ui.ctx().copy_text(asm_text);
}
}
} else if right_ctx.status.success && !right_ctx.has_symbol() {
let mut search = state.search.clone();
Expand Down
Loading