mirror of
https://github.com/encounter/objdiff.git
synced 2025-12-11 14:41:51 +00:00
Copy button (#271)
* Update diff.rs * Fixes * More fixes * More fixes... * Cargo fmt * fmt * Trim extra * cargo +nightly fmt * Update 'Copy ASM' button text to include emoji
This commit is contained in:
@@ -1,12 +1,18 @@
|
|||||||
|
use std::cmp::Ordering;
|
||||||
|
|
||||||
use egui::{Id, Layout, RichText, ScrollArea, TextEdit, Ui, Widget, text::LayoutJob};
|
use egui::{Id, Layout, RichText, ScrollArea, TextEdit, Ui, Widget, text::LayoutJob};
|
||||||
use objdiff_core::{
|
use objdiff_core::{
|
||||||
build::BuildStatus,
|
build::BuildStatus,
|
||||||
diff::{
|
diff::{
|
||||||
DiffObjConfig, ObjectDiff, SymbolDiff,
|
DiffObjConfig, ObjectDiff, SymbolDiff,
|
||||||
data::BYTES_PER_ROW,
|
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;
|
use time::format_description;
|
||||||
|
|
||||||
@@ -64,6 +70,51 @@ impl<'a> DiffColumnContext<'a> {
|
|||||||
pub fn id(&self) -> Option<&str> { self.symbol.map(|(symbol, _, _)| symbol.name.as_str()) }
|
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]
|
#[must_use]
|
||||||
pub fn diff_view_ui(
|
pub fn diff_view_ui(
|
||||||
ui: &mut Ui,
|
ui: &mut Ui,
|
||||||
@@ -208,16 +259,33 @@ pub fn diff_view_ui(
|
|||||||
|
|
||||||
// Third row
|
// Third row
|
||||||
if left_ctx.has_symbol() && right_ctx.has_symbol() {
|
if left_ctx.has_symbol() && right_ctx.has_symbol() {
|
||||||
if (state.current_view == View::FunctionDiff
|
ui.horizontal(|ui| {
|
||||||
&& ui
|
if (state.current_view == View::FunctionDiff
|
||||||
.button("Change target")
|
&& ui
|
||||||
.on_hover_text_at_pointer("Choose a different symbol to use as the target")
|
.button("Change target")
|
||||||
.clicked()
|
.on_hover_text_at_pointer(
|
||||||
|| hotkeys::consume_change_target_shortcut(ui.ctx()))
|
"Choose a different symbol to use as the target",
|
||||||
&& let Some(symbol_ref) = state.symbol_state.right_symbol.as_ref()
|
)
|
||||||
{
|
.clicked()
|
||||||
ret = Some(DiffViewAction::SelectingLeft(symbol_ref.clone()));
|
|| 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() {
|
} else if left_ctx.status.success && !left_ctx.has_symbol() {
|
||||||
ui.horizontal(|ui| {
|
ui.horizontal(|ui| {
|
||||||
let mut search = state.search.clone();
|
let mut search = state.search.clone();
|
||||||
@@ -374,6 +442,18 @@ pub fn diff_view_ui(
|
|||||||
{
|
{
|
||||||
ret = Some(DiffViewAction::SelectingRight(symbol_ref.clone()));
|
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() {
|
} else if right_ctx.status.success && !right_ctx.has_symbol() {
|
||||||
let mut search = state.search.clone();
|
let mut search = state.search.clone();
|
||||||
|
|||||||
Reference in New Issue
Block a user