mirror of https://github.com/encounter/objdiff.git
Initial work on data diffing
This commit is contained in:
parent
ff9b378445
commit
d9efa97c30
14
src/app.rs
14
src/app.rs
|
@ -20,16 +20,18 @@ use crate::{
|
|||
Job, JobResult, JobState,
|
||||
},
|
||||
views::{
|
||||
config::config_ui, function_diff::function_diff_ui, jobs::jobs_ui,
|
||||
config::config_ui, data_diff::data_diff_ui, function_diff::function_diff_ui, jobs::jobs_ui,
|
||||
symbol_diff::symbol_diff_ui,
|
||||
},
|
||||
};
|
||||
|
||||
#[allow(clippy::enum_variant_names)]
|
||||
#[derive(Default, Eq, PartialEq)]
|
||||
pub enum View {
|
||||
#[default]
|
||||
SymbolDiff,
|
||||
FunctionDiff,
|
||||
DataDiff,
|
||||
}
|
||||
|
||||
#[derive(Default, Eq, PartialEq, serde::Deserialize, serde::Serialize)]
|
||||
|
@ -197,6 +199,16 @@ impl eframe::App for App {
|
|||
.push(queue_build(config.clone(), view_state.diff_config.clone()));
|
||||
}
|
||||
});
|
||||
} else if view_state.current_view == View::DataDiff
|
||||
&& matches!(&view_state.build, Some(b) if b.first_status.success && b.second_status.success)
|
||||
{
|
||||
egui::CentralPanel::default().show(ctx, |ui| {
|
||||
if data_diff_ui(ui, view_state) {
|
||||
view_state
|
||||
.jobs
|
||||
.push(queue_build(config.clone(), view_state.diff_config.clone()));
|
||||
}
|
||||
});
|
||||
} else {
|
||||
egui::SidePanel::left("side_panel").show(ctx, |ui| {
|
||||
config_ui(ui, config, view_state);
|
||||
|
|
203
src/diff.rs
203
src/diff.rs
|
@ -1,4 +1,4 @@
|
|||
use std::collections::BTreeMap;
|
||||
use std::{collections::BTreeMap, mem::take};
|
||||
|
||||
use anyhow::Result;
|
||||
|
||||
|
@ -6,9 +6,9 @@ use crate::{
|
|||
app::DiffConfig,
|
||||
editops::{editops_find, LevEditType},
|
||||
obj::{
|
||||
mips, ppc, ObjArchitecture, ObjInfo, ObjInsArg, ObjInsArgDiff, ObjInsBranchFrom,
|
||||
ObjInsBranchTo, ObjInsDiff, ObjInsDiffKind, ObjReloc, ObjSection, ObjSectionKind,
|
||||
ObjSymbol, ObjSymbolFlags,
|
||||
mips, ppc, ObjArchitecture, ObjDataDiff, ObjDataDiffKind, ObjInfo, ObjInsArg,
|
||||
ObjInsArgDiff, ObjInsBranchFrom, ObjInsBranchTo, ObjInsDiff, ObjInsDiffKind, ObjReloc,
|
||||
ObjSection, ObjSectionKind, ObjSymbol, ObjSymbolFlags,
|
||||
},
|
||||
};
|
||||
|
||||
|
@ -340,13 +340,13 @@ fn find_symbol<'a>(symbols: &'a mut [ObjSymbol], name: &str) -> Option<&'a mut O
|
|||
pub fn diff_objs(left: &mut ObjInfo, right: &mut ObjInfo, _diff_config: &DiffConfig) -> Result<()> {
|
||||
for left_section in &mut left.sections {
|
||||
if let Some(right_section) = find_section(right, &left_section.name) {
|
||||
for left_symbol in &mut left_section.symbols {
|
||||
if let Some(right_symbol) =
|
||||
find_symbol(&mut right_section.symbols, &left_symbol.name)
|
||||
{
|
||||
left_symbol.diff_symbol = Some(right_symbol.name.clone());
|
||||
right_symbol.diff_symbol = Some(left_symbol.name.clone());
|
||||
if left_section.kind == ObjSectionKind::Code {
|
||||
if left_section.kind == ObjSectionKind::Code {
|
||||
for left_symbol in &mut left_section.symbols {
|
||||
if let Some(right_symbol) =
|
||||
find_symbol(&mut right_section.symbols, &left_symbol.name)
|
||||
{
|
||||
left_symbol.diff_symbol = Some(right_symbol.name.clone());
|
||||
right_symbol.diff_symbol = Some(left_symbol.name.clone());
|
||||
diff_code(
|
||||
left.architecture,
|
||||
&left_section.data,
|
||||
|
@ -358,8 +358,189 @@ pub fn diff_objs(left: &mut ObjInfo, right: &mut ObjInfo, _diff_config: &DiffCon
|
|||
)?;
|
||||
}
|
||||
}
|
||||
} else if left_section.kind == ObjSectionKind::Data {
|
||||
diff_data(left_section, right_section);
|
||||
}
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn diff_data(left: &mut ObjSection, right: &mut ObjSection) {
|
||||
let edit_ops = editops_find(&left.data, &right.data);
|
||||
if edit_ops.is_empty() && !left.data.is_empty() {
|
||||
left.data_diff = vec![ObjDataDiff {
|
||||
data: left.data.clone(),
|
||||
kind: ObjDataDiffKind::None,
|
||||
len: left.data.len(),
|
||||
}];
|
||||
right.data_diff = vec![ObjDataDiff {
|
||||
data: right.data.clone(),
|
||||
kind: ObjDataDiffKind::None,
|
||||
len: right.data.len(),
|
||||
}];
|
||||
return;
|
||||
}
|
||||
|
||||
let mut left_diff = Vec::<ObjDataDiff>::new();
|
||||
let mut right_diff = Vec::<ObjDataDiff>::new();
|
||||
let mut left_cur = 0usize;
|
||||
let mut right_cur = 0usize;
|
||||
let mut cur_op = LevEditType::Keep;
|
||||
let mut cur_left_data = Vec::<u8>::new();
|
||||
let mut cur_right_data = Vec::<u8>::new();
|
||||
for op in edit_ops {
|
||||
if left_cur < op.first_start {
|
||||
left_diff.push(ObjDataDiff {
|
||||
data: left.data[left_cur..op.first_start].to_vec(),
|
||||
kind: ObjDataDiffKind::None,
|
||||
len: op.first_start - left_cur,
|
||||
});
|
||||
left_cur = op.first_start;
|
||||
}
|
||||
if right_cur < op.second_start {
|
||||
right_diff.push(ObjDataDiff {
|
||||
data: right.data[right_cur..op.second_start].to_vec(),
|
||||
kind: ObjDataDiffKind::None,
|
||||
len: op.second_start - right_cur,
|
||||
});
|
||||
right_cur = op.second_start;
|
||||
}
|
||||
if cur_op != op.op_type {
|
||||
match cur_op {
|
||||
LevEditType::Keep => {}
|
||||
LevEditType::Replace => {
|
||||
let left_data = take(&mut cur_left_data);
|
||||
let right_data = take(&mut cur_right_data);
|
||||
let left_data_len = left_data.len();
|
||||
let right_data_len = right_data.len();
|
||||
left_diff.push(ObjDataDiff {
|
||||
data: left_data,
|
||||
kind: ObjDataDiffKind::Replace,
|
||||
len: left_data_len,
|
||||
});
|
||||
right_diff.push(ObjDataDiff {
|
||||
data: right_data,
|
||||
kind: ObjDataDiffKind::Replace,
|
||||
len: right_data_len,
|
||||
});
|
||||
}
|
||||
LevEditType::Insert => {
|
||||
let right_data = take(&mut cur_right_data);
|
||||
let right_data_len = right_data.len();
|
||||
left_diff.push(ObjDataDiff {
|
||||
data: vec![],
|
||||
kind: ObjDataDiffKind::Insert,
|
||||
len: right_data_len,
|
||||
});
|
||||
right_diff.push(ObjDataDiff {
|
||||
data: right_data,
|
||||
kind: ObjDataDiffKind::Insert,
|
||||
len: right_data_len,
|
||||
});
|
||||
}
|
||||
LevEditType::Delete => {
|
||||
let left_data = take(&mut cur_left_data);
|
||||
let left_data_len = left_data.len();
|
||||
left_diff.push(ObjDataDiff {
|
||||
data: left_data,
|
||||
kind: ObjDataDiffKind::Delete,
|
||||
len: left_data_len,
|
||||
});
|
||||
right_diff.push(ObjDataDiff {
|
||||
data: vec![],
|
||||
kind: ObjDataDiffKind::Delete,
|
||||
len: left_data_len,
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
match op.op_type {
|
||||
LevEditType::Replace => {
|
||||
cur_left_data.push(left.data[left_cur]);
|
||||
cur_right_data.push(right.data[right_cur]);
|
||||
left_cur += 1;
|
||||
right_cur += 1;
|
||||
}
|
||||
LevEditType::Insert => {
|
||||
cur_right_data.push(right.data[right_cur]);
|
||||
right_cur += 1;
|
||||
}
|
||||
LevEditType::Delete => {
|
||||
cur_left_data.push(left.data[left_cur]);
|
||||
left_cur += 1;
|
||||
}
|
||||
LevEditType::Keep => unreachable!(),
|
||||
}
|
||||
cur_op = op.op_type;
|
||||
}
|
||||
// if left_cur < left.data.len() {
|
||||
// let len = left.data.len() - left_cur;
|
||||
// left_diff.push(ObjDataDiff {
|
||||
// data: left.data[left_cur..].to_vec(),
|
||||
// kind: ObjDataDiffKind::Delete,
|
||||
// len,
|
||||
// });
|
||||
// right_diff.push(ObjDataDiff { data: vec![], kind: ObjDataDiffKind::Delete, len });
|
||||
// } else if right_cur < right.data.len() {
|
||||
// let len = right.data.len() - right_cur;
|
||||
// left_diff.push(ObjDataDiff { data: vec![], kind: ObjDataDiffKind::Insert, len });
|
||||
// right_diff.push(ObjDataDiff {
|
||||
// data: right.data[right_cur..].to_vec(),
|
||||
// kind: ObjDataDiffKind::Insert,
|
||||
// len,
|
||||
// });
|
||||
// }
|
||||
|
||||
// TODO: merge with above
|
||||
match cur_op {
|
||||
LevEditType::Keep => {}
|
||||
LevEditType::Replace => {
|
||||
let left_data = take(&mut cur_left_data);
|
||||
let right_data = take(&mut cur_right_data);
|
||||
let left_data_len = left_data.len();
|
||||
let right_data_len = right_data.len();
|
||||
left_diff.push(ObjDataDiff {
|
||||
data: left_data,
|
||||
kind: ObjDataDiffKind::Replace,
|
||||
len: left_data_len,
|
||||
});
|
||||
right_diff.push(ObjDataDiff {
|
||||
data: right_data,
|
||||
kind: ObjDataDiffKind::Replace,
|
||||
len: right_data_len,
|
||||
});
|
||||
}
|
||||
LevEditType::Insert => {
|
||||
let right_data = take(&mut cur_right_data);
|
||||
let right_data_len = right_data.len();
|
||||
left_diff.push(ObjDataDiff {
|
||||
data: vec![],
|
||||
kind: ObjDataDiffKind::Insert,
|
||||
len: right_data_len,
|
||||
});
|
||||
right_diff.push(ObjDataDiff {
|
||||
data: right_data,
|
||||
kind: ObjDataDiffKind::Insert,
|
||||
len: right_data_len,
|
||||
});
|
||||
}
|
||||
LevEditType::Delete => {
|
||||
let left_data = take(&mut cur_left_data);
|
||||
let left_data_len = left_data.len();
|
||||
left_diff.push(ObjDataDiff {
|
||||
data: left_data,
|
||||
kind: ObjDataDiffKind::Delete,
|
||||
len: left_data_len,
|
||||
});
|
||||
right_diff.push(ObjDataDiff {
|
||||
data: vec![],
|
||||
kind: ObjDataDiffKind::Delete,
|
||||
len: left_data_len,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
left.data_diff = left_diff;
|
||||
right.data_diff = right_diff;
|
||||
}
|
||||
|
|
|
@ -91,6 +91,8 @@ fn filter_sections(obj_file: &File<'_>) -> Result<Vec<ObjSection>> {
|
|||
index: section.index().0,
|
||||
symbols: Vec::new(),
|
||||
relocations: Vec::new(),
|
||||
data_diff: vec![],
|
||||
match_percent: 0.0,
|
||||
});
|
||||
}
|
||||
result.sort_by(|a, b| a.name.cmp(&b.name));
|
||||
|
|
|
@ -32,6 +32,10 @@ pub struct ObjSection {
|
|||
pub index: usize,
|
||||
pub symbols: Vec<ObjSymbol>,
|
||||
pub relocations: Vec<ObjReloc>,
|
||||
|
||||
// Diff
|
||||
pub data_diff: Vec<ObjDataDiff>,
|
||||
pub match_percent: f32,
|
||||
}
|
||||
#[derive(Debug, Clone)]
|
||||
pub enum ObjInsArg {
|
||||
|
@ -92,6 +96,20 @@ pub struct ObjInsDiff {
|
|||
/// Arg diffs
|
||||
pub arg_diff: Vec<Option<ObjInsArgDiff>>,
|
||||
}
|
||||
#[derive(Debug, Copy, Clone, Eq, PartialEq, Default)]
|
||||
pub enum ObjDataDiffKind {
|
||||
#[default]
|
||||
None,
|
||||
Replace,
|
||||
Delete,
|
||||
Insert,
|
||||
}
|
||||
#[derive(Debug, Clone, Default)]
|
||||
pub struct ObjDataDiff {
|
||||
pub data: Vec<u8>,
|
||||
pub kind: ObjDataDiffKind,
|
||||
pub len: usize,
|
||||
}
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct ObjSymbol {
|
||||
pub name: String,
|
||||
|
|
|
@ -0,0 +1,242 @@
|
|||
use std::{cmp::min, default::Default, mem::take};
|
||||
|
||||
use egui::{text::LayoutJob, Color32, Label, Sense};
|
||||
use egui_extras::{Size, StripBuilder, TableBuilder};
|
||||
use time::format_description;
|
||||
|
||||
use crate::{
|
||||
app::{View, ViewState},
|
||||
jobs::Job,
|
||||
obj::{ObjDataDiff, ObjDataDiffKind, ObjInfo, ObjSection},
|
||||
views::{write_text, COLOR_RED, FONT_SIZE},
|
||||
};
|
||||
|
||||
const BYTES_PER_ROW: usize = 16;
|
||||
|
||||
fn find_section<'a>(obj: &'a ObjInfo, section_name: &str) -> Option<&'a ObjSection> {
|
||||
obj.sections.iter().find(|s| s.name == section_name)
|
||||
}
|
||||
|
||||
fn data_row_ui(ui: &mut egui::Ui, address: usize, diffs: &[ObjDataDiff]) {
|
||||
if diffs.iter().any(|d| d.kind != ObjDataDiffKind::None) {
|
||||
ui.painter().rect_filled(ui.available_rect_before_wrap(), 0.0, ui.visuals().faint_bg_color);
|
||||
}
|
||||
let mut job = LayoutJob::default();
|
||||
write_text(format!("{:08X}: ", address).as_str(), Color32::GRAY, &mut job);
|
||||
let mut cur_addr = 0usize;
|
||||
for diff in diffs {
|
||||
let base_color = match diff.kind {
|
||||
ObjDataDiffKind::None => Color32::GRAY,
|
||||
ObjDataDiffKind::Replace => Color32::LIGHT_BLUE,
|
||||
ObjDataDiffKind::Delete => COLOR_RED,
|
||||
ObjDataDiffKind::Insert => Color32::GREEN,
|
||||
};
|
||||
if diff.data.is_empty() {
|
||||
let mut str = " ".repeat(diff.len);
|
||||
str.push_str(" ".repeat(diff.len / 8).as_str());
|
||||
write_text(str.as_str(), base_color, &mut job);
|
||||
cur_addr += diff.len;
|
||||
} else {
|
||||
let mut text = String::new();
|
||||
for byte in &diff.data {
|
||||
text.push_str(format!("{:02X} ", byte).as_str());
|
||||
cur_addr += 1;
|
||||
if cur_addr % 8 == 0 {
|
||||
text.push(' ');
|
||||
}
|
||||
}
|
||||
write_text(text.as_str(), base_color, &mut job);
|
||||
}
|
||||
}
|
||||
if cur_addr < BYTES_PER_ROW {
|
||||
let n = BYTES_PER_ROW - cur_addr;
|
||||
let mut str = " ".to_string();
|
||||
str.push_str(" ".repeat(n).as_str());
|
||||
str.push_str(" ".repeat(n / 8).as_str());
|
||||
write_text(str.as_str(), Color32::GRAY, &mut job);
|
||||
}
|
||||
write_text(" ", Color32::GRAY, &mut job);
|
||||
for diff in diffs {
|
||||
let base_color = match diff.kind {
|
||||
ObjDataDiffKind::None => Color32::GRAY,
|
||||
ObjDataDiffKind::Replace => Color32::LIGHT_BLUE,
|
||||
ObjDataDiffKind::Delete => COLOR_RED,
|
||||
ObjDataDiffKind::Insert => Color32::GREEN,
|
||||
};
|
||||
if diff.data.is_empty() {
|
||||
write_text(" ".repeat(diff.len).as_str(), base_color, &mut job);
|
||||
} else {
|
||||
let mut text = String::new();
|
||||
for byte in &diff.data {
|
||||
let c = char::from(*byte);
|
||||
if c.is_ascii() && !c.is_ascii_control() {
|
||||
text.push(c);
|
||||
} else {
|
||||
text.push('.');
|
||||
}
|
||||
}
|
||||
write_text(text.as_str(), base_color, &mut job);
|
||||
}
|
||||
}
|
||||
ui.add(Label::new(job).sense(Sense::click()));
|
||||
// .on_hover_ui_at_pointer(|ui| ins_hover_ui(ui, ins))
|
||||
// .context_menu(|ui| ins_context_menu(ui, ins));
|
||||
}
|
||||
|
||||
fn split_diffs(diffs: &[ObjDataDiff]) -> Vec<Vec<ObjDataDiff>> {
|
||||
let mut split_diffs = Vec::<Vec<ObjDataDiff>>::new();
|
||||
let mut row_diffs = Vec::<ObjDataDiff>::new();
|
||||
let mut cur_addr = 0usize;
|
||||
for diff in diffs {
|
||||
let mut cur_len = 0usize;
|
||||
while cur_len < diff.len {
|
||||
let remaining_len = diff.len - cur_len;
|
||||
let mut remaining_in_row = BYTES_PER_ROW - (cur_addr % BYTES_PER_ROW);
|
||||
let len = min(remaining_len, remaining_in_row);
|
||||
row_diffs.push(ObjDataDiff {
|
||||
data: if diff.data.is_empty() {
|
||||
Vec::new()
|
||||
} else {
|
||||
diff.data[cur_len..cur_len + len].to_vec()
|
||||
},
|
||||
kind: diff.kind,
|
||||
len,
|
||||
});
|
||||
remaining_in_row -= len;
|
||||
cur_len += len;
|
||||
cur_addr += len;
|
||||
if remaining_in_row == 0 {
|
||||
split_diffs.push(take(&mut row_diffs));
|
||||
}
|
||||
}
|
||||
}
|
||||
if !row_diffs.is_empty() {
|
||||
split_diffs.push(take(&mut row_diffs));
|
||||
}
|
||||
split_diffs
|
||||
}
|
||||
|
||||
fn data_table_ui(
|
||||
table: TableBuilder<'_>,
|
||||
left_obj: &ObjInfo,
|
||||
right_obj: &ObjInfo,
|
||||
section_name: &str,
|
||||
) -> Option<()> {
|
||||
let left_section = find_section(left_obj, section_name)?;
|
||||
let right_section = find_section(right_obj, section_name)?;
|
||||
|
||||
let total_bytes = left_section.data_diff.iter().fold(0usize, |accum, item| accum + item.len);
|
||||
if total_bytes == 0 {
|
||||
return None;
|
||||
}
|
||||
let total_rows = (total_bytes - 1) / BYTES_PER_ROW + 1;
|
||||
|
||||
let left_diffs = split_diffs(&left_section.data_diff);
|
||||
let right_diffs = split_diffs(&right_section.data_diff);
|
||||
|
||||
table.body(|body| {
|
||||
body.rows(FONT_SIZE, total_rows, |row_index, mut row| {
|
||||
let address = row_index * BYTES_PER_ROW;
|
||||
row.col(|ui| {
|
||||
data_row_ui(ui, address, &left_diffs[row_index]);
|
||||
});
|
||||
row.col(|ui| {
|
||||
data_row_ui(ui, address, &right_diffs[row_index]);
|
||||
});
|
||||
});
|
||||
});
|
||||
Some(())
|
||||
}
|
||||
|
||||
pub fn data_diff_ui(ui: &mut egui::Ui, view_state: &mut ViewState) -> bool {
|
||||
let mut rebuild = false;
|
||||
if let (Some(result), Some(selected_symbol)) = (&view_state.build, &view_state.selected_symbol)
|
||||
{
|
||||
StripBuilder::new(ui)
|
||||
.size(Size::exact(20.0))
|
||||
.size(Size::exact(40.0))
|
||||
.size(Size::remainder())
|
||||
.vertical(|mut strip| {
|
||||
strip.strip(|builder| {
|
||||
builder.sizes(Size::remainder(), 2).horizontal(|mut strip| {
|
||||
strip.cell(|ui| {
|
||||
ui.horizontal(|ui| {
|
||||
if ui.button("Back").clicked() {
|
||||
view_state.current_view = View::SymbolDiff;
|
||||
}
|
||||
});
|
||||
});
|
||||
strip.cell(|ui| {
|
||||
ui.horizontal(|ui| {
|
||||
if ui.button("Build").clicked() {
|
||||
rebuild = true;
|
||||
}
|
||||
ui.scope(|ui| {
|
||||
ui.style_mut().override_text_style =
|
||||
Some(egui::TextStyle::Monospace);
|
||||
ui.style_mut().wrap = Some(false);
|
||||
if view_state
|
||||
.jobs
|
||||
.iter()
|
||||
.any(|job| job.job_type == Job::ObjDiff)
|
||||
{
|
||||
ui.label("Building...");
|
||||
} else {
|
||||
ui.label("Last built:");
|
||||
let format =
|
||||
format_description::parse("[hour]:[minute]:[second]")
|
||||
.unwrap();
|
||||
ui.label(
|
||||
result
|
||||
.time
|
||||
.to_offset(view_state.utc_offset)
|
||||
.format(&format)
|
||||
.unwrap(),
|
||||
);
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
strip.strip(|builder| {
|
||||
builder.sizes(Size::remainder(), 2).horizontal(|mut strip| {
|
||||
strip.cell(|ui| {
|
||||
ui.scope(|ui| {
|
||||
ui.style_mut().override_text_style =
|
||||
Some(egui::TextStyle::Monospace);
|
||||
ui.style_mut().wrap = Some(false);
|
||||
ui.colored_label(Color32::WHITE, selected_symbol);
|
||||
ui.label("Diff target:");
|
||||
ui.separator();
|
||||
});
|
||||
});
|
||||
strip.cell(|ui| {
|
||||
ui.scope(|ui| {
|
||||
ui.style_mut().override_text_style =
|
||||
Some(egui::TextStyle::Monospace);
|
||||
ui.style_mut().wrap = Some(false);
|
||||
ui.label("");
|
||||
ui.label("Diff base:");
|
||||
ui.separator();
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
strip.cell(|ui| {
|
||||
if let (Some(left_obj), Some(right_obj)) =
|
||||
(&result.first_obj, &result.second_obj)
|
||||
{
|
||||
let table = TableBuilder::new(ui)
|
||||
.striped(false)
|
||||
.cell_layout(egui::Layout::left_to_right(egui::Align::Min))
|
||||
.column(Size::relative(0.5))
|
||||
.column(Size::relative(0.5))
|
||||
.resizable(false);
|
||||
data_table_ui(table, left_obj, right_obj, selected_symbol);
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
rebuild
|
||||
}
|
|
@ -1,6 +1,7 @@
|
|||
use egui::{text::LayoutJob, Color32, FontFamily, FontId, TextFormat};
|
||||
|
||||
pub(crate) mod config;
|
||||
pub(crate) mod data_diff;
|
||||
pub(crate) mod function_diff;
|
||||
pub(crate) mod jobs;
|
||||
pub(crate) mod symbol_diff;
|
||||
|
|
|
@ -6,7 +6,7 @@ use egui_extras::{Size, StripBuilder};
|
|||
use crate::{
|
||||
app::{View, ViewState},
|
||||
jobs::objdiff::BuildStatus,
|
||||
obj::{ObjInfo, ObjSymbol, ObjSymbolFlags},
|
||||
obj::{ObjInfo, ObjSection, ObjSectionKind, ObjSymbol, ObjSymbolFlags},
|
||||
views::write_text,
|
||||
};
|
||||
|
||||
|
@ -52,6 +52,7 @@ fn symbol_hover_ui(ui: &mut Ui, symbol: &ObjSymbol) {
|
|||
fn symbol_ui(
|
||||
ui: &mut Ui,
|
||||
symbol: &ObjSymbol,
|
||||
section: Option<&ObjSection>,
|
||||
highlighted_symbol: &mut Option<String>,
|
||||
selected_symbol: &mut Option<String>,
|
||||
current_view: &mut View,
|
||||
|
@ -90,8 +91,15 @@ fn symbol_ui(
|
|||
.context_menu(|ui| symbol_context_menu_ui(ui, symbol))
|
||||
.on_hover_ui_at_pointer(|ui| symbol_hover_ui(ui, symbol));
|
||||
if response.clicked() {
|
||||
*selected_symbol = Some(symbol.name.clone());
|
||||
*current_view = View::FunctionDiff;
|
||||
if let Some(section) = section {
|
||||
if section.kind == ObjSectionKind::Code {
|
||||
*selected_symbol = Some(symbol.name.clone());
|
||||
*current_view = View::FunctionDiff;
|
||||
} else if section.kind == ObjSectionKind::Data {
|
||||
*selected_symbol = Some(section.name.clone());
|
||||
*current_view = View::DataDiff;
|
||||
}
|
||||
}
|
||||
} else if response.hovered() {
|
||||
*highlighted_symbol = Some(symbol.name.clone());
|
||||
}
|
||||
|
@ -127,7 +135,14 @@ fn symbol_list_ui(
|
|||
if !obj.common.is_empty() {
|
||||
CollapsingHeader::new(".comm").default_open(true).show(ui, |ui| {
|
||||
for symbol in &obj.common {
|
||||
symbol_ui(ui, symbol, highlighted_symbol, selected_symbol, current_view);
|
||||
symbol_ui(
|
||||
ui,
|
||||
symbol,
|
||||
None,
|
||||
highlighted_symbol,
|
||||
selected_symbol,
|
||||
current_view,
|
||||
);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
@ -144,6 +159,7 @@ fn symbol_list_ui(
|
|||
symbol_ui(
|
||||
ui,
|
||||
symbol,
|
||||
Some(section),
|
||||
highlighted_symbol,
|
||||
selected_symbol,
|
||||
current_view,
|
||||
|
@ -157,6 +173,7 @@ fn symbol_list_ui(
|
|||
symbol_ui(
|
||||
ui,
|
||||
symbol,
|
||||
Some(section),
|
||||
highlighted_symbol,
|
||||
selected_symbol,
|
||||
current_view,
|
||||
|
|
Loading…
Reference in New Issue