Skip to content

Commit b2dcecc

Browse files
authored
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
1 parent 67b237e commit b2dcecc

File tree

1 file changed

+92
-12
lines changed

1 file changed

+92
-12
lines changed

objdiff-gui/src/views/diff.rs

Lines changed: 92 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,18 @@
1+
use std::cmp::Ordering;
2+
13
use egui::{Id, Layout, RichText, ScrollArea, TextEdit, Ui, Widget, text::LayoutJob};
24
use objdiff_core::{
35
build::BuildStatus,
46
diff::{
57
DiffObjConfig, ObjectDiff, SymbolDiff,
68
data::BYTES_PER_ROW,
7-
display::{ContextItem, HoverItem, HoverItemColor, SymbolFilter, SymbolNavigationKind},
9+
display::{
10+
ContextItem, DiffText, HoverItem, HoverItemColor, SymbolFilter, SymbolNavigationKind,
11+
display_row,
12+
},
813
},
9-
obj::{Object, Symbol},
14+
obj::{InstructionArgValue, Object, Symbol},
15+
util::ReallySigned,
1016
};
1117
use time::format_description;
1218

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

73+
/// Obtains the assembly text for a given symbol diff, suitable for copying to clipboard.
74+
fn get_asm_text(
75+
obj: &Object,
76+
symbol_diff: &SymbolDiff,
77+
symbol_idx: usize,
78+
diff_config: &DiffObjConfig,
79+
) -> String {
80+
let mut asm_text = String::new();
81+
82+
for ins_row in &symbol_diff.instruction_rows {
83+
let mut line = String::new();
84+
let result = display_row(obj, symbol_idx, ins_row, diff_config, |segment| {
85+
let text = match segment.text {
86+
DiffText::Basic(text) => text.to_string(),
87+
DiffText::Line(num) => format!("{num} "),
88+
DiffText::Address(addr) => format!("{addr:x}:"),
89+
DiffText::Opcode(mnemonic, _op) => format!("{mnemonic} "),
90+
DiffText::Argument(arg) => match arg {
91+
InstructionArgValue::Signed(v) => format!("{:#x}", ReallySigned(v)),
92+
InstructionArgValue::Unsigned(v) => format!("{v:#x}"),
93+
InstructionArgValue::Opaque(v) => v.into_owned(),
94+
},
95+
DiffText::BranchDest(addr) => format!("{addr:x}"),
96+
DiffText::Symbol(sym) => sym.demangled_name.as_ref().unwrap_or(&sym.name).clone(),
97+
DiffText::Addend(addend) => match addend.cmp(&0i64) {
98+
Ordering::Greater => format!("+{addend:#x}"),
99+
Ordering::Less => format!("-{:#x}", -addend),
100+
_ => String::new(),
101+
},
102+
DiffText::Spacing(n) => " ".repeat(n.into()),
103+
DiffText::Eol => "\n".to_string(),
104+
};
105+
line.push_str(&text);
106+
Ok(())
107+
});
108+
109+
if result.is_ok() {
110+
asm_text.push_str(line.trim_end());
111+
asm_text.push('\n');
112+
}
113+
}
114+
115+
asm_text
116+
}
117+
67118
#[must_use]
68119
pub fn diff_view_ui(
69120
ui: &mut Ui,
@@ -208,16 +259,33 @@ pub fn diff_view_ui(
208259

209260
// Third row
210261
if left_ctx.has_symbol() && right_ctx.has_symbol() {
211-
if (state.current_view == View::FunctionDiff
212-
&& ui
213-
.button("Change target")
214-
.on_hover_text_at_pointer("Choose a different symbol to use as the target")
215-
.clicked()
216-
|| hotkeys::consume_change_target_shortcut(ui.ctx()))
217-
&& let Some(symbol_ref) = state.symbol_state.right_symbol.as_ref()
218-
{
219-
ret = Some(DiffViewAction::SelectingLeft(symbol_ref.clone()));
220-
}
262+
ui.horizontal(|ui| {
263+
if (state.current_view == View::FunctionDiff
264+
&& ui
265+
.button("Change target")
266+
.on_hover_text_at_pointer(
267+
"Choose a different symbol to use as the target",
268+
)
269+
.clicked()
270+
|| hotkeys::consume_change_target_shortcut(ui.ctx()))
271+
&& let Some(symbol_ref) = state.symbol_state.right_symbol.as_ref()
272+
{
273+
ret = Some(DiffViewAction::SelectingLeft(symbol_ref.clone()));
274+
}
275+
276+
// Copy target ASM button.
277+
if state.current_view == View::FunctionDiff
278+
&& let Some((_, symbol_diff, symbol_idx)) = left_ctx.symbol
279+
&& let Some((obj, _)) = left_ctx.obj
280+
&& ui
281+
.button("📋 Copy ASM")
282+
.on_hover_text_at_pointer("Copy assembly to clipboard")
283+
.clicked()
284+
{
285+
let asm_text = get_asm_text(obj, symbol_diff, symbol_idx, diff_config);
286+
ui.ctx().copy_text(asm_text);
287+
}
288+
});
221289
} else if left_ctx.status.success && !left_ctx.has_symbol() {
222290
ui.horizontal(|ui| {
223291
let mut search = state.search.clone();
@@ -374,6 +442,18 @@ pub fn diff_view_ui(
374442
{
375443
ret = Some(DiffViewAction::SelectingRight(symbol_ref.clone()));
376444
}
445+
446+
// Copy base ASM button.
447+
if let Some((_, symbol_diff, symbol_idx)) = right_ctx.symbol
448+
&& let Some((obj, _)) = right_ctx.obj
449+
&& ui
450+
.button("📋 Copy ASM")
451+
.on_hover_text_at_pointer("Copy assembly to clipboard")
452+
.clicked()
453+
{
454+
let asm_text = get_asm_text(obj, symbol_diff, symbol_idx, diff_config);
455+
ui.ctx().copy_text(asm_text);
456+
}
377457
}
378458
} else if right_ctx.status.success && !right_ctx.has_symbol() {
379459
let mut search = state.search.clone();

0 commit comments

Comments
 (0)