mirror of
https://github.com/encounter/objdiff.git
synced 2025-12-08 21:17:59 +00:00
Unify context menu / hover tooltip code + UI improvements
This commit is contained in:
@@ -25,11 +25,10 @@ wsl = []
|
||||
|
||||
[dependencies]
|
||||
anyhow = "1.0"
|
||||
bytes = "1.9"
|
||||
cfg-if = "1.0"
|
||||
const_format = "0.2"
|
||||
cwdemangle = "1.0"
|
||||
cwextab = { version = "1.0", git = "https://github.com/encounter/cwextab.git" }
|
||||
cwextab = { version = "1.0", git = "https://github.com/CelestialAmber/cwextab.git" }
|
||||
dirs = "5.0"
|
||||
egui = "0.30"
|
||||
egui_extras = "0.30"
|
||||
@@ -44,12 +43,11 @@ png = "0.17"
|
||||
pollster = "0.4"
|
||||
regex = "1.11"
|
||||
rfd = { version = "0.15" } #, default-features = false, features = ['xdg-portal']
|
||||
rlwinmdec = "1.0"
|
||||
rlwinmdec = { version = "1.0", git = "https://github.com/CelestialAmber/rlwinmdec.git" }
|
||||
ron = "0.8"
|
||||
serde = { version = "1.0", features = ["derive"] }
|
||||
serde_json = "1.0"
|
||||
shell-escape = "0.1"
|
||||
strum = { version = "0.26", features = ["derive"] }
|
||||
time = { version = "0.3", features = ["formatting", "local-offset"] }
|
||||
typed-path = "0.10"
|
||||
winit = { version = "0.30", features = ["wayland-csd-adwaita"] }
|
||||
|
||||
@@ -43,7 +43,7 @@ use crate::{
|
||||
graphics::{graphics_window, GraphicsConfig, GraphicsViewState},
|
||||
jobs::{jobs_menu_ui, jobs_window},
|
||||
rlwinm::{rlwinm_decode_window, RlwinmDecodeViewState},
|
||||
symbol_diff::{DiffViewAction, DiffViewNavigation, DiffViewState, View},
|
||||
symbol_diff::{DiffViewAction, DiffViewState, ResolvedNavigation, View},
|
||||
},
|
||||
};
|
||||
|
||||
@@ -762,7 +762,7 @@ impl eframe::App for App {
|
||||
ui.separator();
|
||||
if ui.button("Clear custom symbol mappings").clicked() {
|
||||
state.clear_mappings();
|
||||
diff_state.post_build_nav = Some(DiffViewNavigation::symbol_diff());
|
||||
diff_state.post_build_nav = Some(ResolvedNavigation::default());
|
||||
state.queue_reload = true;
|
||||
}
|
||||
});
|
||||
|
||||
@@ -25,8 +25,7 @@ use tracing_subscriber::EnvFilter;
|
||||
use crate::views::graphics::{load_graphics_config, GraphicsBackend, GraphicsConfig};
|
||||
|
||||
fn load_icon() -> Result<egui::IconData> {
|
||||
use bytes::Buf;
|
||||
let decoder = png::Decoder::new(include_bytes!("../assets/icon_64.png").reader());
|
||||
let decoder = png::Decoder::new(include_bytes!("../assets/icon_64.png").as_ref());
|
||||
let mut reader = decoder.read_info()?;
|
||||
let mut buf = vec![0; reader.output_buffer_size()];
|
||||
let info = reader.next_frame(&mut buf)?;
|
||||
|
||||
@@ -1,8 +1,11 @@
|
||||
use egui::{Id, Layout, RichText, ScrollArea, TextEdit, Ui, Widget};
|
||||
use egui::{text::LayoutJob, Id, Layout, RichText, ScrollArea, TextEdit, Ui, Widget};
|
||||
use objdiff_core::{
|
||||
build::BuildStatus,
|
||||
diff::{display::SymbolFilter, DiffObjConfig, ObjectDiff, SectionDiff, SymbolDiff},
|
||||
obj::{Object, Section, SectionKind, Symbol},
|
||||
diff::{
|
||||
display::{ContextItem, HoverItem, HoverItemColor, SymbolFilter, SymbolNavigationKind},
|
||||
DiffObjConfig, ObjectDiff, SectionDiff, SymbolDiff,
|
||||
},
|
||||
obj::{Object, Section, Symbol},
|
||||
};
|
||||
use time::format_description;
|
||||
|
||||
@@ -15,9 +18,11 @@ use crate::{
|
||||
extab_diff::extab_ui,
|
||||
function_diff::{asm_col_ui, FunctionDiffContext},
|
||||
symbol_diff::{
|
||||
match_color_for_symbol, symbol_list_ui, DiffViewAction, DiffViewNavigation,
|
||||
DiffViewState, SymbolDiffContext, SymbolRefByName, View,
|
||||
match_color_for_symbol, symbol_context_menu_ui, symbol_hover_ui, symbol_list_ui,
|
||||
DiffViewAction, DiffViewNavigation, DiffViewState, SymbolDiffContext, SymbolRefByName,
|
||||
View,
|
||||
},
|
||||
write_text,
|
||||
},
|
||||
};
|
||||
|
||||
@@ -112,21 +117,19 @@ pub fn diff_view_ui(
|
||||
|
||||
// Check if we need to perform any navigation
|
||||
let current_navigation = DiffViewNavigation {
|
||||
view: state.current_view,
|
||||
left_symbol: state.symbol_state.left_symbol.clone(),
|
||||
right_symbol: state.symbol_state.right_symbol.clone(),
|
||||
kind: match state.current_view {
|
||||
View::ExtabDiff => SymbolNavigationKind::Extab,
|
||||
_ => SymbolNavigationKind::Normal,
|
||||
},
|
||||
left_symbol: left_ctx.symbol.map(|(_, _, idx)| idx),
|
||||
right_symbol: right_ctx.symbol.map(|(_, _, idx)| idx),
|
||||
};
|
||||
let mut navigation = current_navigation.clone();
|
||||
if let Some((_symbol, symbol_diff, _symbol_idx)) = left_ctx.symbol {
|
||||
// If a matching symbol appears, select it
|
||||
if !right_ctx.has_symbol() {
|
||||
if let Some(target_symbol_ref) = symbol_diff.target_symbol {
|
||||
let (right_obj, _) = right_ctx.obj.unwrap();
|
||||
let target_symbol = &right_obj.symbols[target_symbol_ref];
|
||||
let target_section = target_symbol
|
||||
.section
|
||||
.and_then(|section_idx| right_obj.sections.get(section_idx));
|
||||
navigation.right_symbol = Some(SymbolRefByName::new(target_symbol, target_section));
|
||||
navigation.right_symbol = Some(target_symbol_ref);
|
||||
}
|
||||
}
|
||||
} else if navigation.left_symbol.is_some()
|
||||
@@ -140,12 +143,7 @@ pub fn diff_view_ui(
|
||||
// If a matching symbol appears, select it
|
||||
if !left_ctx.has_symbol() {
|
||||
if let Some(target_symbol_ref) = symbol_diff.target_symbol {
|
||||
let (left_obj, _) = left_ctx.obj.unwrap();
|
||||
let target_symbol = &left_obj.symbols[target_symbol_ref];
|
||||
let target_section = target_symbol
|
||||
.section
|
||||
.and_then(|section_idx| left_obj.sections.get(section_idx));
|
||||
navigation.left_symbol = Some(SymbolRefByName::new(target_symbol, target_section));
|
||||
navigation.left_symbol = Some(target_symbol_ref);
|
||||
}
|
||||
}
|
||||
} else if navigation.right_symbol.is_some()
|
||||
@@ -157,7 +155,7 @@ pub fn diff_view_ui(
|
||||
}
|
||||
// If both sides are missing a symbol, switch to symbol diff view
|
||||
if navigation.left_symbol.is_none() && navigation.right_symbol.is_none() {
|
||||
navigation.view = View::SymbolDiff;
|
||||
navigation = DiffViewNavigation::default();
|
||||
}
|
||||
// Execute navigation if it changed
|
||||
if navigation != current_navigation && state.post_build_nav.is_none() {
|
||||
@@ -177,7 +175,7 @@ pub fn diff_view_ui(
|
||||
} else {
|
||||
ui.horizontal(|ui| {
|
||||
if ui.button("⏴ Back").clicked() || hotkeys::back_pressed(ui.ctx()) {
|
||||
ret = Some(DiffViewAction::Navigate(DiffViewNavigation::symbol_diff()));
|
||||
ret = Some(DiffViewAction::Navigate(DiffViewNavigation::default()));
|
||||
}
|
||||
|
||||
if let Some((symbol, _, _)) = left_ctx.symbol {
|
||||
@@ -220,12 +218,12 @@ pub fn diff_view_ui(
|
||||
.color(appearance.replace_color),
|
||||
);
|
||||
}
|
||||
} else if let Some((symbol, _, _)) = left_ctx.symbol {
|
||||
ui.label(
|
||||
RichText::new(symbol.demangled_name.as_deref().unwrap_or(&symbol.name))
|
||||
.font(appearance.code_font.clone())
|
||||
.color(appearance.highlight_color),
|
||||
);
|
||||
} else if let Some((symbol, _symbol_diff, symbol_idx)) = left_ctx.symbol {
|
||||
if let Some(action) =
|
||||
symbol_label_ui(ui, left_ctx, symbol, symbol_idx, column, appearance)
|
||||
{
|
||||
ret = Some(action);
|
||||
}
|
||||
} else if let Some((section, _, _)) = left_ctx.section {
|
||||
ui.label(
|
||||
RichText::new(section.name.clone())
|
||||
@@ -341,12 +339,12 @@ pub fn diff_view_ui(
|
||||
.color(appearance.replace_color),
|
||||
);
|
||||
}
|
||||
} else if let Some((symbol, _, _)) = right_ctx.symbol {
|
||||
ui.label(
|
||||
RichText::new(symbol.demangled_name.as_deref().unwrap_or(&symbol.name))
|
||||
.font(appearance.code_font.clone())
|
||||
.color(appearance.highlight_color),
|
||||
);
|
||||
} else if let Some((symbol, _symbol_diff, symbol_idx)) = right_ctx.symbol {
|
||||
if let Some(action) =
|
||||
symbol_label_ui(ui, right_ctx, symbol, symbol_idx, column, appearance)
|
||||
{
|
||||
ret = Some(action);
|
||||
}
|
||||
} else if let Some((section, _, _)) = right_ctx.section {
|
||||
ui.label(
|
||||
RichText::new(section.name.clone())
|
||||
@@ -573,6 +571,38 @@ pub fn diff_view_ui(
|
||||
ret
|
||||
}
|
||||
|
||||
fn symbol_label_ui(
|
||||
ui: &mut Ui,
|
||||
ctx: DiffColumnContext,
|
||||
symbol: &Symbol,
|
||||
symbol_idx: usize,
|
||||
column: usize,
|
||||
appearance: &Appearance,
|
||||
) -> Option<DiffViewAction> {
|
||||
let (obj, diff) = ctx.obj.unwrap();
|
||||
let ctx = SymbolDiffContext { obj, diff };
|
||||
let mut ret = None;
|
||||
egui::Label::new(
|
||||
RichText::new(symbol.demangled_name.as_deref().unwrap_or(&symbol.name))
|
||||
.font(appearance.code_font.clone())
|
||||
.color(appearance.highlight_color),
|
||||
)
|
||||
.selectable(false)
|
||||
// TODO .show_tooltip_when_elided(false)
|
||||
// https://github.com/emilk/egui/commit/071e090e2b2601e5ed4726a63a753188503dfaf2
|
||||
.ui(ui)
|
||||
.on_hover_ui_at_pointer(|ui| symbol_hover_ui(ui, ctx, symbol_idx, appearance))
|
||||
.context_menu(|ui| {
|
||||
let section = symbol.section.and_then(|section_idx| ctx.obj.sections.get(section_idx));
|
||||
if let Some(result) =
|
||||
symbol_context_menu_ui(ui, ctx, symbol_idx, symbol, section, column, appearance)
|
||||
{
|
||||
ret = Some(result);
|
||||
}
|
||||
});
|
||||
ret
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
fn diff_col_ui(
|
||||
ui: &mut Ui,
|
||||
@@ -641,15 +671,11 @@ fn diff_col_ui(
|
||||
});
|
||||
},
|
||||
);
|
||||
} else if let (
|
||||
Some((other_section, _other_section_diff, _other_section_idx)),
|
||||
Some((other_symbol, _other_symbol_diff, other_symbol_idx)),
|
||||
) = (other_ctx.section, other_ctx.symbol)
|
||||
} else if let Some((_other_symbol, _other_symbol_diff, other_symbol_idx)) = other_ctx.symbol
|
||||
{
|
||||
if let Some(action) = symbol_list_ui(
|
||||
ui,
|
||||
SymbolDiffContext { obj, diff },
|
||||
None,
|
||||
&state.symbol_state,
|
||||
SymbolFilter::Mapping(other_symbol_idx, None),
|
||||
appearance,
|
||||
@@ -660,34 +686,20 @@ fn diff_col_ui(
|
||||
(
|
||||
0,
|
||||
DiffViewAction::Navigate(DiffViewNavigation {
|
||||
left_symbol: Some(left_symbol_ref),
|
||||
left_symbol: Some(symbol_idx),
|
||||
..
|
||||
}),
|
||||
) => {
|
||||
ret = Some(DiffViewAction::SetMapping(
|
||||
match other_section.kind {
|
||||
SectionKind::Code => View::FunctionDiff,
|
||||
_ => View::SymbolDiff,
|
||||
},
|
||||
left_symbol_ref,
|
||||
SymbolRefByName::new(other_symbol, Some(other_section)),
|
||||
));
|
||||
ret = Some(DiffViewAction::SetMapping(symbol_idx, other_symbol_idx));
|
||||
}
|
||||
(
|
||||
1,
|
||||
DiffViewAction::Navigate(DiffViewNavigation {
|
||||
right_symbol: Some(right_symbol_ref),
|
||||
right_symbol: Some(symbol_idx),
|
||||
..
|
||||
}),
|
||||
) => {
|
||||
ret = Some(DiffViewAction::SetMapping(
|
||||
match other_section.kind {
|
||||
SectionKind::Code => View::FunctionDiff,
|
||||
_ => View::SymbolDiff,
|
||||
},
|
||||
SymbolRefByName::new(other_symbol, Some(other_section)),
|
||||
right_symbol_ref,
|
||||
));
|
||||
ret = Some(DiffViewAction::SetMapping(other_symbol_idx, symbol_idx));
|
||||
}
|
||||
(_, action) => {
|
||||
ret = Some(action);
|
||||
@@ -702,7 +714,6 @@ fn diff_col_ui(
|
||||
if let Some(result) = symbol_list_ui(
|
||||
ui,
|
||||
SymbolDiffContext { obj, diff },
|
||||
other_ctx.obj.map(|(obj, diff)| SymbolDiffContext { obj, diff }),
|
||||
&state.symbol_state,
|
||||
filter,
|
||||
appearance,
|
||||
@@ -764,3 +775,91 @@ fn find_symbol(obj: &Object, selected_symbol: &SymbolRefByName) -> Option<usize>
|
||||
fn find_section(obj: &Object, section_name: &str) -> Option<usize> {
|
||||
obj.sections.iter().position(|section| section.name == section_name)
|
||||
}
|
||||
|
||||
pub fn hover_items_ui(ui: &mut Ui, items: Vec<HoverItem>, appearance: &Appearance) {
|
||||
for item in items {
|
||||
match item {
|
||||
HoverItem::Text { label, value, color } => {
|
||||
let mut job = LayoutJob::default();
|
||||
if !label.is_empty() {
|
||||
let label_color = match color {
|
||||
HoverItemColor::Special => appearance.replace_color,
|
||||
_ => appearance.highlight_color,
|
||||
};
|
||||
write_text(&label, label_color, &mut job, appearance.code_font.clone());
|
||||
write_text(": ", label_color, &mut job, appearance.code_font.clone());
|
||||
}
|
||||
write_text(
|
||||
&value,
|
||||
match color {
|
||||
HoverItemColor::Emphasized => appearance.highlight_color,
|
||||
_ => appearance.text_color,
|
||||
},
|
||||
&mut job,
|
||||
appearance.code_font.clone(),
|
||||
);
|
||||
ui.label(job);
|
||||
}
|
||||
HoverItem::Separator => {
|
||||
ui.separator();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn context_menu_items_ui(
|
||||
ui: &mut Ui,
|
||||
items: Vec<ContextItem>,
|
||||
column: usize,
|
||||
appearance: &Appearance,
|
||||
) -> Option<DiffViewAction> {
|
||||
let mut ret = None;
|
||||
for item in items {
|
||||
match item {
|
||||
ContextItem::Copy { value, label } => {
|
||||
let mut job = LayoutJob::default();
|
||||
write_text(
|
||||
"Copy \"",
|
||||
appearance.text_color,
|
||||
&mut job,
|
||||
appearance.code_font.clone(),
|
||||
);
|
||||
write_text(
|
||||
&value,
|
||||
appearance.highlight_color,
|
||||
&mut job,
|
||||
appearance.code_font.clone(),
|
||||
);
|
||||
write_text("\"", appearance.text_color, &mut job, appearance.code_font.clone());
|
||||
if let Some(label) = label {
|
||||
write_text(" (", appearance.text_color, &mut job, appearance.code_font.clone());
|
||||
write_text(
|
||||
&label,
|
||||
appearance.text_color,
|
||||
&mut job,
|
||||
appearance.code_font.clone(),
|
||||
);
|
||||
write_text(")", appearance.text_color, &mut job, appearance.code_font.clone());
|
||||
}
|
||||
if ui.button(job).clicked() {
|
||||
ui.output_mut(|output| output.copied_text = value);
|
||||
ui.close_menu();
|
||||
}
|
||||
}
|
||||
ContextItem::Navigate { label, symbol_index, kind } => {
|
||||
if ui.button(label).clicked() {
|
||||
ret = Some(DiffViewAction::Navigate(DiffViewNavigation::new(
|
||||
kind,
|
||||
symbol_index,
|
||||
column,
|
||||
)));
|
||||
ui.close_menu();
|
||||
}
|
||||
}
|
||||
ContextItem::Separator => {
|
||||
ui.separator();
|
||||
}
|
||||
}
|
||||
}
|
||||
ret
|
||||
}
|
||||
|
||||
@@ -4,17 +4,21 @@ use egui::{text::LayoutJob, Label, Response, Sense, Widget};
|
||||
use egui_extras::TableRow;
|
||||
use objdiff_core::{
|
||||
diff::{
|
||||
display::{display_row, DiffText, DiffTextColor, DiffTextSegment, HighlightKind},
|
||||
display::{
|
||||
display_row, instruction_context, instruction_hover, DiffText, DiffTextColor,
|
||||
DiffTextSegment, HighlightKind,
|
||||
},
|
||||
DiffObjConfig, InstructionDiffKind, InstructionDiffRow, ObjectDiff,
|
||||
},
|
||||
obj::{
|
||||
InstructionArg, InstructionArgValue, InstructionRef, Object, ParsedInstruction,
|
||||
ResolvedRelocation, Section, Symbol,
|
||||
},
|
||||
obj::{InstructionArgValue, InstructionRef, Object},
|
||||
util::ReallySigned,
|
||||
};
|
||||
|
||||
use crate::views::{appearance::Appearance, symbol_diff::DiffViewAction};
|
||||
use crate::views::{
|
||||
appearance::Appearance,
|
||||
diff::{context_menu_items_ui, hover_items_ui},
|
||||
symbol_diff::DiffViewAction,
|
||||
};
|
||||
|
||||
#[derive(Default)]
|
||||
pub struct FunctionViewState {
|
||||
@@ -67,51 +71,6 @@ impl FunctionViewState {
|
||||
}
|
||||
}
|
||||
|
||||
#[expect(unused)]
|
||||
#[derive(Clone, Copy)]
|
||||
pub struct ResolvedInstructionRef<'obj> {
|
||||
pub symbol: &'obj Symbol,
|
||||
pub section_idx: usize,
|
||||
pub section: &'obj Section,
|
||||
pub data: &'obj [u8],
|
||||
pub relocation: Option<ResolvedRelocation<'obj>>,
|
||||
}
|
||||
|
||||
fn resolve_instruction_ref(
|
||||
obj: &Object,
|
||||
symbol_idx: usize,
|
||||
ins_ref: InstructionRef,
|
||||
) -> Option<ResolvedInstructionRef> {
|
||||
let symbol = &obj.symbols[symbol_idx];
|
||||
let section_idx = symbol.section?;
|
||||
let section = &obj.sections[section_idx];
|
||||
let offset = ins_ref.address.checked_sub(section.address)?;
|
||||
let data = section.data.get(offset as usize..offset as usize + ins_ref.size as usize)?;
|
||||
let relocation = section.relocation_at(ins_ref, obj);
|
||||
Some(ResolvedInstructionRef { symbol, section, section_idx, data, relocation })
|
||||
}
|
||||
|
||||
fn resolve_instruction<'obj>(
|
||||
obj: &'obj Object,
|
||||
symbol_idx: usize,
|
||||
ins_ref: InstructionRef,
|
||||
diff_config: &DiffObjConfig,
|
||||
) -> Option<(ResolvedInstructionRef<'obj>, ParsedInstruction)> {
|
||||
let resolved = resolve_instruction_ref(obj, symbol_idx, ins_ref)?;
|
||||
let ins = obj
|
||||
.arch
|
||||
.process_instruction(
|
||||
ins_ref,
|
||||
resolved.data,
|
||||
resolved.relocation,
|
||||
resolved.symbol.address..resolved.symbol.address + resolved.symbol.size,
|
||||
resolved.section_idx,
|
||||
diff_config,
|
||||
)
|
||||
.ok()?;
|
||||
Some((resolved, ins))
|
||||
}
|
||||
|
||||
fn ins_hover_ui(
|
||||
ui: &mut egui::Ui,
|
||||
obj: &Object,
|
||||
@@ -120,86 +79,25 @@ fn ins_hover_ui(
|
||||
diff_config: &DiffObjConfig,
|
||||
appearance: &Appearance,
|
||||
) {
|
||||
let Some((
|
||||
ResolvedInstructionRef { symbol, section_idx: _, section: _, data, relocation },
|
||||
ins,
|
||||
)) = resolve_instruction(obj, symbol_idx, ins_ref, diff_config)
|
||||
else {
|
||||
let Some(resolved) = obj.resolve_instruction_ref(symbol_idx, ins_ref) else {
|
||||
ui.colored_label(appearance.delete_color, "Failed to resolve instruction");
|
||||
return;
|
||||
};
|
||||
let ins = match obj.arch.process_instruction(resolved, diff_config) {
|
||||
Ok(ins) => ins,
|
||||
Err(e) => {
|
||||
ui.colored_label(
|
||||
appearance.delete_color,
|
||||
format!("Failed to process instruction: {e}"),
|
||||
);
|
||||
return;
|
||||
}
|
||||
};
|
||||
|
||||
ui.scope(|ui| {
|
||||
ui.style_mut().override_text_style = Some(egui::TextStyle::Monospace);
|
||||
ui.style_mut().wrap_mode = Some(egui::TextWrapMode::Extend);
|
||||
|
||||
ui.label(format!("{:02x?}", data));
|
||||
|
||||
if let Some(virtual_address) = symbol.virtual_address {
|
||||
let offset = ins_ref.address - symbol.address;
|
||||
ui.colored_label(
|
||||
appearance.replace_color,
|
||||
format!("Virtual address: {:#x}", virtual_address + offset),
|
||||
);
|
||||
}
|
||||
|
||||
// TODO
|
||||
// if let Some(orig) = &ins.orig {
|
||||
// ui.label(format!("Original: {}", orig));
|
||||
// }
|
||||
|
||||
for arg in &ins.args {
|
||||
if let InstructionArg::Value(arg) = arg {
|
||||
match arg {
|
||||
InstructionArgValue::Signed(v) => {
|
||||
ui.label(format!("{arg} == {v}"));
|
||||
}
|
||||
InstructionArgValue::Unsigned(v) => {
|
||||
ui.label(format!("{arg} == {v}"));
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if let Some(resolved) = relocation {
|
||||
ui.label(format!(
|
||||
"Relocation type: {}",
|
||||
obj.arch.display_reloc(resolved.relocation.flags)
|
||||
));
|
||||
let addend_str = match resolved.relocation.addend.cmp(&0i64) {
|
||||
Ordering::Greater => format!("+{:x}", resolved.relocation.addend),
|
||||
Ordering::Less => format!("-{:x}", -resolved.relocation.addend),
|
||||
_ => "".to_string(),
|
||||
};
|
||||
ui.colored_label(
|
||||
appearance.highlight_color,
|
||||
format!("Name: {}{}", resolved.symbol.name, addend_str),
|
||||
);
|
||||
if let Some(orig_section_index) = resolved.symbol.section {
|
||||
let section = &obj.sections[orig_section_index];
|
||||
ui.colored_label(appearance.highlight_color, format!("Section: {}", section.name));
|
||||
ui.colored_label(
|
||||
appearance.highlight_color,
|
||||
format!("Address: {:x}{}", resolved.symbol.address, addend_str),
|
||||
);
|
||||
ui.colored_label(
|
||||
appearance.highlight_color,
|
||||
format!("Size: {:x}", resolved.symbol.size),
|
||||
);
|
||||
// TODO
|
||||
// for label in obj.arch.display_ins_data_labels(ins) {
|
||||
// ui.colored_label(appearance.highlight_color, label);
|
||||
// }
|
||||
} else {
|
||||
ui.colored_label(appearance.highlight_color, "Extern".to_string());
|
||||
}
|
||||
}
|
||||
|
||||
// TODO
|
||||
// if let Some(decoded) = rlwinmdec::decode(&ins.formatted) {
|
||||
// ui.colored_label(appearance.highlight_color, decoded.trim());
|
||||
// }
|
||||
ui.style_mut().wrap_mode = Some(egui::TextWrapMode::Wrap);
|
||||
hover_items_ui(ui, instruction_hover(obj, resolved, &ins), appearance);
|
||||
});
|
||||
}
|
||||
|
||||
@@ -208,93 +106,29 @@ fn ins_context_menu(
|
||||
obj: &Object,
|
||||
symbol_idx: usize,
|
||||
ins_ref: InstructionRef,
|
||||
column: usize,
|
||||
diff_config: &DiffObjConfig,
|
||||
appearance: &Appearance,
|
||||
) {
|
||||
let Some((
|
||||
ResolvedInstructionRef { symbol, section_idx: _, section: _, data, relocation },
|
||||
ins,
|
||||
)) = resolve_instruction(obj, symbol_idx, ins_ref, diff_config)
|
||||
else {
|
||||
let Some(resolved) = obj.resolve_instruction_ref(symbol_idx, ins_ref) else {
|
||||
ui.colored_label(appearance.delete_color, "Failed to resolve instruction");
|
||||
return;
|
||||
};
|
||||
let ins = match obj.arch.process_instruction(resolved, diff_config) {
|
||||
Ok(ins) => ins,
|
||||
Err(e) => {
|
||||
ui.colored_label(
|
||||
appearance.delete_color,
|
||||
format!("Failed to process instruction: {e}"),
|
||||
);
|
||||
return;
|
||||
}
|
||||
};
|
||||
|
||||
ui.scope(|ui| {
|
||||
ui.style_mut().override_text_style = Some(egui::TextStyle::Monospace);
|
||||
ui.style_mut().wrap_mode = Some(egui::TextWrapMode::Extend);
|
||||
|
||||
// TODO
|
||||
// if ui.button(format!("Copy \"{}\"", ins.formatted)).clicked() {
|
||||
// ui.output_mut(|output| output.copied_text.clone_from(&ins.formatted));
|
||||
// ui.close_menu();
|
||||
// }
|
||||
|
||||
let mut hex_string = "0x".to_string();
|
||||
for byte in data {
|
||||
hex_string.push_str(&format!("{:02x}", byte));
|
||||
}
|
||||
if ui.button(format!("Copy \"{hex_string}\" (instruction bytes)")).clicked() {
|
||||
ui.output_mut(|output| output.copied_text = hex_string);
|
||||
ui.close_menu();
|
||||
}
|
||||
|
||||
if let Some(virtual_address) = symbol.virtual_address {
|
||||
let offset = ins_ref.address - symbol.address;
|
||||
let offset_string = format!("{:#x}", virtual_address + offset);
|
||||
if ui.button(format!("Copy \"{offset_string}\" (virtual address)")).clicked() {
|
||||
ui.output_mut(|output| output.copied_text = offset_string);
|
||||
ui.close_menu();
|
||||
}
|
||||
}
|
||||
|
||||
for arg in &ins.args {
|
||||
if let InstructionArg::Value(arg) = arg {
|
||||
match arg {
|
||||
InstructionArgValue::Signed(v) => {
|
||||
if ui.button(format!("Copy \"{arg}\"")).clicked() {
|
||||
ui.output_mut(|output| output.copied_text = arg.to_string());
|
||||
ui.close_menu();
|
||||
}
|
||||
if ui.button(format!("Copy \"{v}\"")).clicked() {
|
||||
ui.output_mut(|output| output.copied_text = v.to_string());
|
||||
ui.close_menu();
|
||||
}
|
||||
}
|
||||
InstructionArgValue::Unsigned(v) => {
|
||||
if ui.button(format!("Copy \"{arg}\"")).clicked() {
|
||||
ui.output_mut(|output| output.copied_text = arg.to_string());
|
||||
ui.close_menu();
|
||||
}
|
||||
if ui.button(format!("Copy \"{v}\"")).clicked() {
|
||||
ui.output_mut(|output| output.copied_text = v.to_string());
|
||||
ui.close_menu();
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if let Some(resolved) = relocation {
|
||||
// TODO
|
||||
// for literal in obj.arch.display_ins_data_literals(ins) {
|
||||
// if ui.button(format!("Copy \"{literal}\"")).clicked() {
|
||||
// ui.output_mut(|output| output.copied_text.clone_from(&literal));
|
||||
// ui.close_menu();
|
||||
// }
|
||||
// }
|
||||
if let Some(name) = &resolved.symbol.demangled_name {
|
||||
if ui.button(format!("Copy \"{name}\"")).clicked() {
|
||||
ui.output_mut(|output| output.copied_text.clone_from(name));
|
||||
ui.close_menu();
|
||||
}
|
||||
}
|
||||
if ui.button(format!("Copy \"{}\"", resolved.symbol.name)).clicked() {
|
||||
ui.output_mut(|output| output.copied_text.clone_from(&resolved.symbol.name));
|
||||
ui.close_menu();
|
||||
}
|
||||
}
|
||||
ui.style_mut().wrap_mode = Some(egui::TextWrapMode::Truncate);
|
||||
context_menu_items_ui(ui, instruction_context(obj, resolved, &ins), column, appearance);
|
||||
});
|
||||
}
|
||||
|
||||
@@ -410,7 +244,7 @@ pub(crate) fn asm_col_ui(
|
||||
let response_cb = |response: Response| {
|
||||
if let Some(ins_ref) = ins_row.ins_ref {
|
||||
response.context_menu(|ui| {
|
||||
ins_context_menu(ui, ctx.obj, symbol_ref, ins_ref, diff_config, appearance)
|
||||
ins_context_menu(ui, ctx.obj, symbol_ref, ins_ref, column, diff_config, appearance)
|
||||
});
|
||||
response.on_hover_ui_at_pointer(|ui| {
|
||||
ins_hover_ui(ui, ctx.obj, symbol_ref, ins_ref, diff_config, appearance)
|
||||
|
||||
@@ -7,7 +7,6 @@ use std::{
|
||||
use anyhow::Result;
|
||||
use egui::{text::LayoutJob, Context, FontId, RichText, TextFormat, TextStyle, Window};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use strum::{EnumIter, EnumMessage, IntoEnumIterator};
|
||||
|
||||
use crate::views::{appearance::Appearance, frame_history::FrameHistory};
|
||||
|
||||
@@ -20,23 +19,24 @@ pub struct GraphicsViewState {
|
||||
pub should_relaunch: bool,
|
||||
}
|
||||
|
||||
#[derive(
|
||||
Copy, Clone, Debug, Default, PartialEq, Eq, EnumIter, EnumMessage, Serialize, Deserialize,
|
||||
)]
|
||||
#[derive(Copy, Clone, Debug, Default, PartialEq, Eq, Serialize, Deserialize)]
|
||||
pub enum GraphicsBackend {
|
||||
#[default]
|
||||
#[strum(message = "Auto")]
|
||||
Auto,
|
||||
#[strum(message = "Vulkan")]
|
||||
Vulkan,
|
||||
#[strum(message = "Metal")]
|
||||
Metal,
|
||||
#[strum(message = "DirectX 12")]
|
||||
Dx12,
|
||||
#[strum(message = "OpenGL")]
|
||||
OpenGL,
|
||||
}
|
||||
|
||||
static ALL_BACKENDS: &[GraphicsBackend] = &[
|
||||
GraphicsBackend::Auto,
|
||||
GraphicsBackend::Vulkan,
|
||||
GraphicsBackend::Metal,
|
||||
GraphicsBackend::Dx12,
|
||||
GraphicsBackend::OpenGL,
|
||||
];
|
||||
|
||||
#[derive(Clone, Debug, Default, serde::Deserialize, serde::Serialize)]
|
||||
pub struct GraphicsConfig {
|
||||
#[serde(default)]
|
||||
@@ -70,6 +70,16 @@ impl GraphicsBackend {
|
||||
GraphicsBackend::OpenGL => true,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn display_name(self) -> &'static str {
|
||||
match self {
|
||||
GraphicsBackend::Auto => "Auto",
|
||||
GraphicsBackend::Vulkan => "Vulkan",
|
||||
GraphicsBackend::Metal => "Metal",
|
||||
GraphicsBackend::Dx12 => "DirectX 12",
|
||||
GraphicsBackend::OpenGL => "OpenGL",
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn graphics_window(
|
||||
@@ -134,9 +144,9 @@ pub fn graphics_window(
|
||||
ui.add_enabled_ui(state.graphics_config_path.is_some(), |ui| {
|
||||
ui.horizontal(|ui| {
|
||||
ui.label("Desired backend:");
|
||||
for backend in GraphicsBackend::iter().filter(GraphicsBackend::is_supported) {
|
||||
for backend in ALL_BACKENDS.iter().copied().filter(GraphicsBackend::is_supported) {
|
||||
let selected = state.graphics_config.desired_backend == backend;
|
||||
if ui.selectable_label(selected, backend.get_message().unwrap()).clicked() {
|
||||
if ui.selectable_label(selected, backend.display_name()).clicked() {
|
||||
let prev_backend = state.graphics_config.desired_backend;
|
||||
state.graphics_config.desired_backend = backend;
|
||||
match save_graphics_config(
|
||||
|
||||
@@ -7,8 +7,8 @@ use egui::{
|
||||
use objdiff_core::{
|
||||
diff::{
|
||||
display::{
|
||||
display_sections, symbol_context, symbol_hover, ContextMenuItem, HighlightKind,
|
||||
HoverItem, HoverItemColor, SectionDisplay, SymbolFilter,
|
||||
display_sections, symbol_context, symbol_hover, HighlightKind, SectionDisplay,
|
||||
SymbolFilter, SymbolNavigationKind,
|
||||
},
|
||||
ObjectDiff, SymbolDiff,
|
||||
},
|
||||
@@ -21,7 +21,12 @@ use crate::{
|
||||
app::AppStateRef,
|
||||
hotkeys,
|
||||
jobs::{is_create_scratch_available, start_create_scratch},
|
||||
views::{appearance::Appearance, function_diff::FunctionViewState, write_text},
|
||||
views::{
|
||||
appearance::Appearance,
|
||||
diff::{context_menu_items_ui, hover_items_ui},
|
||||
function_diff::FunctionViewState,
|
||||
write_text,
|
||||
},
|
||||
};
|
||||
|
||||
#[derive(Debug, Clone, Eq, PartialEq)]
|
||||
@@ -71,62 +76,33 @@ pub enum DiffViewAction {
|
||||
/// The symbol reference is the left symbol to map to.
|
||||
SelectingRight(SymbolRefByName),
|
||||
/// Set a symbol mapping.
|
||||
SetMapping(View, SymbolRefByName, SymbolRefByName),
|
||||
SetMapping(usize, usize),
|
||||
/// Set the show_mapped_symbols flag
|
||||
SetShowMappedSymbols(bool),
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Default, Eq, PartialEq)]
|
||||
pub struct DiffViewNavigation {
|
||||
pub view: View,
|
||||
pub left_symbol: Option<SymbolRefByName>,
|
||||
pub right_symbol: Option<SymbolRefByName>,
|
||||
pub kind: SymbolNavigationKind,
|
||||
pub left_symbol: Option<usize>,
|
||||
pub right_symbol: Option<usize>,
|
||||
}
|
||||
|
||||
impl DiffViewNavigation {
|
||||
pub fn symbol_diff() -> Self {
|
||||
Self { view: View::SymbolDiff, left_symbol: None, right_symbol: None }
|
||||
}
|
||||
|
||||
pub fn with_symbols(
|
||||
view: View,
|
||||
other_ctx: Option<SymbolDiffContext<'_>>,
|
||||
symbol: &Symbol,
|
||||
section: &Section,
|
||||
symbol_diff: &SymbolDiff,
|
||||
column: usize,
|
||||
) -> Self {
|
||||
let symbol1 = Some(SymbolRefByName::new(symbol, Some(section)));
|
||||
let symbol2 = symbol_diff.target_symbol.and_then(|symbol_ref| {
|
||||
other_ctx.map(|ctx| {
|
||||
let symbol = &ctx.obj.symbols[symbol_ref];
|
||||
let section =
|
||||
symbol.section.and_then(|section_idx| ctx.obj.sections.get(section_idx));
|
||||
SymbolRefByName::new(symbol, section)
|
||||
})
|
||||
});
|
||||
pub fn new(kind: SymbolNavigationKind, symbol_idx: usize, column: usize) -> Self {
|
||||
match column {
|
||||
0 => Self { view, left_symbol: symbol1, right_symbol: symbol2 },
|
||||
1 => Self { view, left_symbol: symbol2, right_symbol: symbol1 },
|
||||
_ => unreachable!("Invalid column index"),
|
||||
0 => Self { kind, left_symbol: Some(symbol_idx), right_symbol: None },
|
||||
1 => Self { kind, left_symbol: None, right_symbol: Some(symbol_idx) },
|
||||
_ => panic!("Invalid column index"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn data_diff(section: &Section, column: usize) -> Self {
|
||||
let symbol = Some(SymbolRefByName {
|
||||
symbol_name: "".to_string(),
|
||||
section_name: Some(section.name.clone()),
|
||||
});
|
||||
match column {
|
||||
0 => Self {
|
||||
view: View::DataDiff,
|
||||
left_symbol: symbol.clone(),
|
||||
right_symbol: symbol.clone(),
|
||||
},
|
||||
1 => Self { view: View::DataDiff, left_symbol: symbol.clone(), right_symbol: symbol },
|
||||
_ => unreachable!("Invalid column index"),
|
||||
}
|
||||
}
|
||||
#[derive(Debug, Clone, Default, Eq, PartialEq)]
|
||||
pub struct ResolvedNavigation {
|
||||
pub view: View,
|
||||
pub left_symbol: Option<SymbolRefByName>,
|
||||
pub right_symbol: Option<SymbolRefByName>,
|
||||
}
|
||||
|
||||
#[derive(Default)]
|
||||
@@ -142,7 +118,7 @@ pub struct DiffViewState {
|
||||
pub scratch_available: bool,
|
||||
pub scratch_running: bool,
|
||||
pub source_path_available: bool,
|
||||
pub post_build_nav: Option<DiffViewNavigation>,
|
||||
pub post_build_nav: Option<ResolvedNavigation>,
|
||||
pub object_name: String,
|
||||
}
|
||||
|
||||
@@ -230,24 +206,42 @@ impl DiffViewState {
|
||||
let Ok(mut state) = state.write() else {
|
||||
return;
|
||||
};
|
||||
if (nav.left_symbol.is_some() && nav.right_symbol.is_some())
|
||||
|| (nav.left_symbol.is_none() && nav.right_symbol.is_none())
|
||||
|| nav.view != View::FunctionDiff
|
||||
|
||||
let mut resolved_left = self.resolve_symbol(nav.left_symbol, 0);
|
||||
let mut resolved_right = self.resolve_symbol(nav.right_symbol, 1);
|
||||
if let Some(resolved_right) = &resolved_right {
|
||||
if resolved_left.is_none() {
|
||||
resolved_left = resolved_right
|
||||
.target_symbol
|
||||
.and_then(|idx| self.resolve_symbol(Some(idx), 0));
|
||||
}
|
||||
}
|
||||
if let Some(resolved_left) = &resolved_left {
|
||||
if resolved_right.is_none() {
|
||||
resolved_right = resolved_left
|
||||
.target_symbol
|
||||
.and_then(|idx| self.resolve_symbol(Some(idx), 1));
|
||||
}
|
||||
}
|
||||
let resolved_nav = resolve_navigation(nav.kind, resolved_left, resolved_right);
|
||||
if (resolved_nav.left_symbol.is_some() && resolved_nav.right_symbol.is_some())
|
||||
|| (resolved_nav.left_symbol.is_none() && resolved_nav.right_symbol.is_none())
|
||||
|| resolved_nav.view != View::FunctionDiff
|
||||
{
|
||||
// Regular navigation
|
||||
if state.is_selecting_symbol() {
|
||||
// Cancel selection and reload
|
||||
state.clear_selection();
|
||||
self.post_build_nav = Some(nav);
|
||||
self.post_build_nav = Some(resolved_nav);
|
||||
} else {
|
||||
// Navigate immediately
|
||||
self.current_view = nav.view;
|
||||
self.symbol_state.left_symbol = nav.left_symbol;
|
||||
self.symbol_state.right_symbol = nav.right_symbol;
|
||||
self.current_view = resolved_nav.view;
|
||||
self.symbol_state.left_symbol = resolved_nav.left_symbol;
|
||||
self.symbol_state.right_symbol = resolved_nav.right_symbol;
|
||||
}
|
||||
} else {
|
||||
// Enter selection mode
|
||||
match (&nav.left_symbol, &nav.right_symbol) {
|
||||
match (&resolved_nav.left_symbol, &resolved_nav.right_symbol) {
|
||||
(Some(left_ref), None) => {
|
||||
state.set_selecting_right(&left_ref.symbol_name);
|
||||
}
|
||||
@@ -257,7 +251,7 @@ impl DiffViewState {
|
||||
(Some(_), Some(_)) => unreachable!(),
|
||||
(None, None) => unreachable!(),
|
||||
}
|
||||
self.post_build_nav = Some(nav);
|
||||
self.post_build_nav = Some(resolved_nav);
|
||||
}
|
||||
}
|
||||
DiffViewAction::SetSymbolHighlight(left, right, autoscroll) => {
|
||||
@@ -306,7 +300,7 @@ impl DiffViewState {
|
||||
return;
|
||||
};
|
||||
state.set_selecting_left(&right_ref.symbol_name);
|
||||
self.post_build_nav = Some(DiffViewNavigation {
|
||||
self.post_build_nav = Some(ResolvedNavigation {
|
||||
view: View::FunctionDiff,
|
||||
left_symbol: None,
|
||||
right_symbol: Some(right_ref),
|
||||
@@ -321,13 +315,13 @@ impl DiffViewState {
|
||||
return;
|
||||
};
|
||||
state.set_selecting_right(&left_ref.symbol_name);
|
||||
self.post_build_nav = Some(DiffViewNavigation {
|
||||
self.post_build_nav = Some(ResolvedNavigation {
|
||||
view: View::FunctionDiff,
|
||||
left_symbol: Some(left_ref),
|
||||
right_symbol: None,
|
||||
});
|
||||
}
|
||||
DiffViewAction::SetMapping(view, left_ref, right_ref) => {
|
||||
DiffViewAction::SetMapping(left_ref, right_ref) => {
|
||||
if self.post_build_nav.is_some() {
|
||||
// Ignore action if we're already navigating
|
||||
return;
|
||||
@@ -335,25 +329,133 @@ impl DiffViewState {
|
||||
let Ok(mut state) = state.write() else {
|
||||
return;
|
||||
};
|
||||
state.set_symbol_mapping(
|
||||
left_ref.symbol_name.clone(),
|
||||
right_ref.symbol_name.clone(),
|
||||
);
|
||||
if view == View::SymbolDiff {
|
||||
self.post_build_nav = Some(DiffViewNavigation::symbol_diff());
|
||||
let resolved_nav = if let (Some(left_ref), Some(right_ref)) = (
|
||||
self.resolve_symbol(Some(left_ref), 0),
|
||||
self.resolve_symbol(Some(right_ref), 1),
|
||||
) {
|
||||
state.set_symbol_mapping(
|
||||
left_ref.symbol.name.clone(),
|
||||
right_ref.symbol.name.clone(),
|
||||
);
|
||||
resolve_navigation(
|
||||
SymbolNavigationKind::Normal,
|
||||
Some(left_ref),
|
||||
Some(right_ref),
|
||||
)
|
||||
} else {
|
||||
self.post_build_nav = Some(DiffViewNavigation {
|
||||
view,
|
||||
left_symbol: Some(left_ref),
|
||||
right_symbol: Some(right_ref),
|
||||
});
|
||||
}
|
||||
ResolvedNavigation::default()
|
||||
};
|
||||
self.post_build_nav = Some(resolved_nav);
|
||||
}
|
||||
DiffViewAction::SetShowMappedSymbols(value) => {
|
||||
self.symbol_state.show_mapped_symbols = value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn resolve_symbol(&self, symbol_idx: Option<usize>, column: usize) -> Option<ResolvedSymbol> {
|
||||
let symbol_idx = symbol_idx?;
|
||||
let result = self.build.as_deref()?;
|
||||
let (obj, diff) = match column {
|
||||
0 => result.first_obj.as_ref()?,
|
||||
1 => result.second_obj.as_ref()?,
|
||||
_ => return None,
|
||||
};
|
||||
let symbol = obj.symbols.get(symbol_idx)?;
|
||||
let section_idx = symbol.section?;
|
||||
let section = obj.sections.get(section_idx)?;
|
||||
let symbol_diff = diff.symbols.get(symbol_idx)?;
|
||||
Some(ResolvedSymbol {
|
||||
symbol_ref: SymbolRefByName::new(symbol, Some(section)),
|
||||
symbol,
|
||||
section,
|
||||
target_symbol: symbol_diff.target_symbol,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
struct ResolvedSymbol<'obj> {
|
||||
symbol_ref: SymbolRefByName,
|
||||
symbol: &'obj Symbol,
|
||||
section: &'obj Section,
|
||||
target_symbol: Option<usize>,
|
||||
}
|
||||
|
||||
/// Determine the navigation target based on the resolved symbols.
|
||||
fn resolve_navigation(
|
||||
kind: SymbolNavigationKind,
|
||||
resolved_left: Option<ResolvedSymbol>,
|
||||
resolved_right: Option<ResolvedSymbol>,
|
||||
) -> ResolvedNavigation {
|
||||
match (resolved_left, resolved_right) {
|
||||
(Some(left), Some(right)) => match (left.section.kind, right.section.kind) {
|
||||
(SectionKind::Code, SectionKind::Code) => ResolvedNavigation {
|
||||
view: match kind {
|
||||
SymbolNavigationKind::Normal => View::FunctionDiff,
|
||||
SymbolNavigationKind::Extab => View::ExtabDiff,
|
||||
},
|
||||
left_symbol: Some(left.symbol_ref),
|
||||
right_symbol: Some(right.symbol_ref),
|
||||
},
|
||||
(SectionKind::Data, SectionKind::Data) => ResolvedNavigation {
|
||||
view: View::DataDiff,
|
||||
left_symbol: Some(SymbolRefByName {
|
||||
symbol_name: "".to_string(),
|
||||
section_name: Some(left.section.name.clone()),
|
||||
}),
|
||||
right_symbol: Some(SymbolRefByName {
|
||||
symbol_name: "".to_string(),
|
||||
section_name: Some(right.section.name.clone()),
|
||||
}),
|
||||
},
|
||||
_ => ResolvedNavigation::default(),
|
||||
},
|
||||
(Some(left), None) => match left.section.kind {
|
||||
SectionKind::Code => ResolvedNavigation {
|
||||
view: match kind {
|
||||
SymbolNavigationKind::Normal => View::FunctionDiff,
|
||||
SymbolNavigationKind::Extab => View::ExtabDiff,
|
||||
},
|
||||
left_symbol: Some(left.symbol_ref),
|
||||
right_symbol: None,
|
||||
},
|
||||
SectionKind::Data => ResolvedNavigation {
|
||||
view: View::DataDiff,
|
||||
left_symbol: Some(SymbolRefByName {
|
||||
symbol_name: "".to_string(),
|
||||
section_name: Some(left.section.name.clone()),
|
||||
}),
|
||||
right_symbol: Some(SymbolRefByName {
|
||||
symbol_name: "".to_string(),
|
||||
section_name: Some(left.section.name.clone()),
|
||||
}),
|
||||
},
|
||||
_ => ResolvedNavigation::default(),
|
||||
},
|
||||
(None, Some(right)) => match right.section.kind {
|
||||
SectionKind::Code => ResolvedNavigation {
|
||||
view: match kind {
|
||||
SymbolNavigationKind::Normal => View::FunctionDiff,
|
||||
SymbolNavigationKind::Extab => View::ExtabDiff,
|
||||
},
|
||||
left_symbol: None,
|
||||
right_symbol: Some(right.symbol_ref),
|
||||
},
|
||||
SectionKind::Data => ResolvedNavigation {
|
||||
view: View::DataDiff,
|
||||
left_symbol: Some(SymbolRefByName {
|
||||
symbol_name: "".to_string(),
|
||||
section_name: Some(right.section.name.clone()),
|
||||
}),
|
||||
right_symbol: Some(SymbolRefByName {
|
||||
symbol_name: "".to_string(),
|
||||
section_name: Some(right.section.name.clone()),
|
||||
}),
|
||||
},
|
||||
_ => ResolvedNavigation::default(),
|
||||
},
|
||||
(None, None) => ResolvedNavigation::default(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn match_color_for_symbol(match_percent: f32, appearance: &Appearance) -> Color32 {
|
||||
@@ -366,65 +468,33 @@ pub fn match_color_for_symbol(match_percent: f32, appearance: &Appearance) -> Co
|
||||
}
|
||||
}
|
||||
|
||||
fn symbol_context_menu_ui(
|
||||
pub fn symbol_context_menu_ui(
|
||||
ui: &mut Ui,
|
||||
ctx: SymbolDiffContext<'_>,
|
||||
other_ctx: Option<SymbolDiffContext<'_>>,
|
||||
symbol_idx: usize,
|
||||
symbol: &Symbol,
|
||||
symbol_diff: &SymbolDiff,
|
||||
section: Option<&Section>,
|
||||
column: usize,
|
||||
) -> Option<DiffViewNavigation> {
|
||||
appearance: &Appearance,
|
||||
) -> Option<DiffViewAction> {
|
||||
let mut ret = None;
|
||||
ui.scope(|ui| {
|
||||
ui.style_mut().override_text_style = Some(egui::TextStyle::Monospace);
|
||||
ui.style_mut().wrap_mode = Some(egui::TextWrapMode::Extend);
|
||||
ui.style_mut().wrap_mode = Some(egui::TextWrapMode::Truncate);
|
||||
|
||||
for item in symbol_context(ctx.obj, symbol) {
|
||||
match item {
|
||||
ContextMenuItem::Copy { value, label } => {
|
||||
let label = if let Some(extra) = label {
|
||||
format!("Copy \"{value}\" ({extra})")
|
||||
} else {
|
||||
format!("Copy \"{value}\"")
|
||||
};
|
||||
if ui.button(label).clicked() {
|
||||
ui.output_mut(|output| output.copied_text = value);
|
||||
ui.close_menu();
|
||||
}
|
||||
}
|
||||
ContextMenuItem::Navigate { label } => {
|
||||
if ui.button(label).clicked() {
|
||||
// TODO other navigation
|
||||
ret = Some(DiffViewNavigation::with_symbols(
|
||||
View::ExtabDiff,
|
||||
other_ctx,
|
||||
symbol,
|
||||
section.unwrap(),
|
||||
symbol_diff,
|
||||
column,
|
||||
));
|
||||
ui.close_menu();
|
||||
}
|
||||
}
|
||||
}
|
||||
if let Some(action) =
|
||||
context_menu_items_ui(ui, symbol_context(ctx.obj, symbol_idx), column, appearance)
|
||||
{
|
||||
ret = Some(action);
|
||||
}
|
||||
|
||||
if let Some(section) = section {
|
||||
if ui.button("Map symbol").clicked() {
|
||||
let symbol_ref = SymbolRefByName::new(symbol, Some(section));
|
||||
if column == 0 {
|
||||
ret = Some(DiffViewNavigation {
|
||||
view: View::FunctionDiff,
|
||||
left_symbol: Some(symbol_ref),
|
||||
right_symbol: None,
|
||||
});
|
||||
ret = Some(DiffViewAction::SelectingRight(symbol_ref));
|
||||
} else {
|
||||
ret = Some(DiffViewNavigation {
|
||||
view: View::FunctionDiff,
|
||||
left_symbol: None,
|
||||
right_symbol: Some(symbol_ref),
|
||||
});
|
||||
ret = Some(DiffViewAction::SelectingLeft(symbol_ref));
|
||||
}
|
||||
ui.close_menu();
|
||||
}
|
||||
@@ -433,24 +503,16 @@ fn symbol_context_menu_ui(
|
||||
ret
|
||||
}
|
||||
|
||||
fn symbol_hover_ui(
|
||||
pub fn symbol_hover_ui(
|
||||
ui: &mut Ui,
|
||||
ctx: SymbolDiffContext<'_>,
|
||||
symbol: &Symbol,
|
||||
symbol_idx: usize,
|
||||
appearance: &Appearance,
|
||||
) {
|
||||
ui.scope(|ui| {
|
||||
ui.style_mut().override_text_style = Some(egui::TextStyle::Monospace);
|
||||
ui.style_mut().wrap_mode = Some(egui::TextWrapMode::Extend);
|
||||
|
||||
for HoverItem { text, color } in symbol_hover(ctx.obj, symbol) {
|
||||
let color = match color {
|
||||
HoverItemColor::Normal => appearance.text_color,
|
||||
HoverItemColor::Emphasized => appearance.highlight_color,
|
||||
HoverItemColor::Special => appearance.replace_color,
|
||||
};
|
||||
ui.colored_label(color, text);
|
||||
}
|
||||
ui.style_mut().wrap_mode = Some(egui::TextWrapMode::Wrap);
|
||||
hover_items_ui(ui, symbol_hover(ctx.obj, symbol_idx, 0), appearance);
|
||||
});
|
||||
}
|
||||
|
||||
@@ -458,7 +520,6 @@ fn symbol_hover_ui(
|
||||
fn symbol_ui(
|
||||
ui: &mut Ui,
|
||||
ctx: SymbolDiffContext<'_>,
|
||||
other_ctx: Option<SymbolDiffContext<'_>>,
|
||||
symbol: &Symbol,
|
||||
symbol_diff: &SymbolDiff,
|
||||
symbol_idx: usize,
|
||||
@@ -515,12 +576,12 @@ fn symbol_ui(
|
||||
write_text(name, appearance.highlight_color, &mut job, appearance.code_font.clone());
|
||||
let response = SelectableLabel::new(selected, job)
|
||||
.ui(ui)
|
||||
.on_hover_ui_at_pointer(|ui| symbol_hover_ui(ui, ctx, symbol, appearance));
|
||||
.on_hover_ui_at_pointer(|ui| symbol_hover_ui(ui, ctx, symbol_idx, appearance));
|
||||
response.context_menu(|ui| {
|
||||
if let Some(result) =
|
||||
symbol_context_menu_ui(ui, ctx, other_ctx, symbol, symbol_diff, section, column)
|
||||
symbol_context_menu_ui(ui, ctx, symbol_idx, symbol, section, column, appearance)
|
||||
{
|
||||
ret = Some(DiffViewAction::Navigate(result));
|
||||
ret = Some(result);
|
||||
}
|
||||
});
|
||||
if selected && state.autoscroll_to_highlighted_symbols {
|
||||
@@ -532,26 +593,11 @@ fn symbol_ui(
|
||||
// manually scroll away.
|
||||
}
|
||||
if response.clicked() || (selected && hotkeys::enter_pressed(ui.ctx())) {
|
||||
if let Some(section) = section {
|
||||
match section.kind {
|
||||
SectionKind::Code => {
|
||||
ret = Some(DiffViewAction::Navigate(DiffViewNavigation::with_symbols(
|
||||
View::FunctionDiff,
|
||||
other_ctx,
|
||||
symbol,
|
||||
section,
|
||||
symbol_diff,
|
||||
column,
|
||||
)));
|
||||
}
|
||||
SectionKind::Data => {
|
||||
ret = Some(DiffViewAction::Navigate(DiffViewNavigation::data_diff(
|
||||
section, column,
|
||||
)));
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
ret = Some(DiffViewAction::Navigate(DiffViewNavigation::new(
|
||||
SymbolNavigationKind::Normal,
|
||||
symbol_idx,
|
||||
column,
|
||||
)));
|
||||
} else if response.hovered() {
|
||||
ret = Some(if column == 0 {
|
||||
DiffViewAction::SetSymbolHighlight(Some(symbol_idx), symbol_diff.target_symbol, false)
|
||||
@@ -597,7 +643,6 @@ fn find_last_symbol(section_display: &[SectionDisplay]) -> Option<usize> {
|
||||
pub fn symbol_list_ui(
|
||||
ui: &mut Ui,
|
||||
ctx: SymbolDiffContext<'_>,
|
||||
other_ctx: Option<SymbolDiffContext<'_>>,
|
||||
state: &SymbolViewState,
|
||||
filter: SymbolFilter<'_>,
|
||||
appearance: &Appearance,
|
||||
@@ -720,7 +765,6 @@ pub fn symbol_list_ui(
|
||||
if let Some(result) = symbol_ui(
|
||||
ui,
|
||||
ctx,
|
||||
other_ctx,
|
||||
symbol,
|
||||
symbol_diff,
|
||||
symbol_display.symbol,
|
||||
|
||||
Reference in New Issue
Block a user