mirror of https://github.com/encounter/objdiff.git
Remove alternate diff algorithms, only keep Patience
This commit is contained in:
parent
9a7d2bcebf
commit
cff6a230a3
|
@ -110,9 +110,9 @@ checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "ahash"
|
name = "ahash"
|
||||||
version = "0.8.9"
|
version = "0.8.10"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "d713b3834d76b85304d4d525563c1276e2e30dc97cc67bfb4585a4a29fc2c89f"
|
checksum = "8b79b82693f705137f8fb9b37871d99e4f9a7df12b917eed79c3d3954830a60b"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"cfg-if",
|
"cfg-if",
|
||||||
"getrandom",
|
"getrandom",
|
||||||
|
@ -1576,9 +1576,9 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "error-code"
|
name = "error-code"
|
||||||
version = "3.1.0"
|
version = "3.2.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "26a147e1a6641a55d994b3e4e9fa4d9b180c8d652c09b363af8c9bf1b8e04139"
|
checksum = "a0474425d51df81997e2f90a21591180b38eccf27292d755f3e30750225c175b"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "event-listener"
|
name = "event-listener"
|
||||||
|
@ -2101,7 +2101,7 @@ dependencies = [
|
||||||
"presser",
|
"presser",
|
||||||
"thiserror",
|
"thiserror",
|
||||||
"winapi",
|
"winapi",
|
||||||
"windows 0.51.1",
|
"windows 0.52.0",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
@ -3004,7 +3004,6 @@ dependencies = [
|
||||||
"serde_json",
|
"serde_json",
|
||||||
"serde_yaml",
|
"serde_yaml",
|
||||||
"similar",
|
"similar",
|
||||||
"twox-hash",
|
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
@ -3456,9 +3455,9 @@ checksum = "42a9830a0e1b9fb145ebb365b8bc4ccd75f290f98c0247deafbbe2c75cefb544"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "rayon"
|
name = "rayon"
|
||||||
version = "1.8.1"
|
version = "1.9.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "fa7237101a77a10773db45d62004a272517633fbcc3df19d96455ede1122e051"
|
checksum = "e4963ed1bc86e4f3ee217022bd855b297cef07fb9eac5dfa1f788b220b49b3bd"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"either",
|
"either",
|
||||||
"rayon-core",
|
"rayon-core",
|
||||||
|
@ -4180,9 +4179,9 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "tempfile"
|
name = "tempfile"
|
||||||
version = "3.10.0"
|
version = "3.10.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "a365e8cd18e44762ef95d87f284f4b5cd04107fec2ff3052bd6a3e6069669e67"
|
checksum = "85b77fafb263dd9d05cbeac119526425676db3784113aa9295c88498cbf8bff1"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"cfg-if",
|
"cfg-if",
|
||||||
"fastrand 2.0.1",
|
"fastrand 2.0.1",
|
||||||
|
@ -4507,17 +4506,6 @@ version = "0.20.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "17f77d76d837a7830fe1d4f12b7b4ba4192c1888001c7164257e4bc6d21d96b4"
|
checksum = "17f77d76d837a7830fe1d4f12b7b4ba4192c1888001c7164257e4bc6d21d96b4"
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "twox-hash"
|
|
||||||
version = "1.6.3"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "97fee6b57c6a41524a810daee9286c02d7752c4253064d0b05472833a438f675"
|
|
||||||
dependencies = [
|
|
||||||
"cfg-if",
|
|
||||||
"rand",
|
|
||||||
"static_assertions",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "type-map"
|
name = "type-map"
|
||||||
version = "0.5.0"
|
version = "0.5.0"
|
||||||
|
@ -5056,21 +5044,21 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "windows"
|
name = "windows"
|
||||||
version = "0.51.1"
|
version = "0.52.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "ca229916c5ee38c2f2bc1e9d8f04df975b4bd93f9955dc69fabb5d91270045c9"
|
checksum = "e48a53791691ab099e5e2ad123536d0fff50652600abaf43bbf952894110d0be"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"windows-core",
|
"windows-core",
|
||||||
"windows-targets 0.48.5",
|
"windows-targets 0.52.3",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "windows-core"
|
name = "windows-core"
|
||||||
version = "0.51.1"
|
version = "0.52.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "f1f8cf84f35d2db49a46868f947758c7a1138116f7fac3bc844f43ade1292e64"
|
checksum = "33ab640c8d7e35bf8ba19b884ba838ceb4fba93a4e8c65a9059d08afcfc683d9"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"windows-targets 0.48.5",
|
"windows-targets 0.52.3",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
|
|
@ -108,7 +108,7 @@ pub fn run(args: Args) -> Result<()> {
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
.collect::<Result<Vec<Option<ReportUnit>>>>()?;
|
.collect::<Result<Vec<Option<ReportUnit>>>>()?;
|
||||||
report.units = units.into_iter().flatten().collect::<Vec<ReportUnit>>();
|
report.units = units.into_iter().flatten().collect();
|
||||||
}
|
}
|
||||||
for unit in &report.units {
|
for unit in &report.units {
|
||||||
report.fuzzy_match_percent += unit.match_percent * unit.total_size as f32;
|
report.fuzzy_match_percent += unit.match_percent * unit.total_size as f32;
|
||||||
|
@ -198,10 +198,14 @@ fn report_object(
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
let match_percent = symbol.match_percent.unwrap_or(if object.complete == Some(true) {
|
let match_percent = symbol.match_percent.unwrap_or_else(|| {
|
||||||
|
// Support cases where we don't have a target object,
|
||||||
|
// assume complete means 100% match
|
||||||
|
if object.complete == Some(true) {
|
||||||
100.0
|
100.0
|
||||||
} else {
|
} else {
|
||||||
0.0
|
0.0
|
||||||
|
}
|
||||||
});
|
});
|
||||||
unit.match_percent += match_percent * symbol.size as f32;
|
unit.match_percent += match_percent * symbol.size as f32;
|
||||||
unit.total_size += symbol.size;
|
unit.total_size += symbol.size;
|
||||||
|
|
|
@ -33,8 +33,7 @@ object = { version = "0.32.2", features = ["read_core", "std", "elf"], default-f
|
||||||
ppc750cl = { git = "https://github.com/encounter/ppc750cl", rev = "4a2bbbc6f84dcb76255ab6f3595a8d4a0ce96618", optional = true }
|
ppc750cl = { git = "https://github.com/encounter/ppc750cl", rev = "4a2bbbc6f84dcb76255ab6f3595a8d4a0ce96618", optional = true }
|
||||||
rabbitizer = { version = "1.8.1", optional = true }
|
rabbitizer = { version = "1.8.1", optional = true }
|
||||||
serde = { version = "1", features = ["derive"] }
|
serde = { version = "1", features = ["derive"] }
|
||||||
similar = "2.4.0"
|
similar = { version = "2.4.0", default-features = false }
|
||||||
twox-hash = "1.6.3"
|
|
||||||
|
|
||||||
# config
|
# config
|
||||||
globset = { version = "0.4.14", features = ["serde1"] }
|
globset = { version = "0.4.14", features = ["serde1"] }
|
||||||
|
|
|
@ -8,10 +8,7 @@ use anyhow::Result;
|
||||||
use similar::{capture_diff_slices_deadline, Algorithm};
|
use similar::{capture_diff_slices_deadline, Algorithm};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
diff::{
|
diff::{DiffObjConfig, ProcessCodeResult},
|
||||||
editops::{editops_find, LevEditType},
|
|
||||||
DiffAlg, DiffObjConfig, ProcessCodeResult,
|
|
||||||
},
|
|
||||||
obj,
|
obj,
|
||||||
obj::{
|
obj::{
|
||||||
ObjArchitecture, ObjInfo, ObjInsArg, ObjInsArgDiff, ObjInsBranchFrom, ObjInsBranchTo,
|
ObjArchitecture, ObjInfo, ObjInsArg, ObjInsArgDiff, ObjInsBranchFrom, ObjInsBranchTo,
|
||||||
|
@ -101,45 +98,7 @@ pub fn diff_code(
|
||||||
|
|
||||||
let mut left_diff = Vec::<ObjInsDiff>::new();
|
let mut left_diff = Vec::<ObjInsDiff>::new();
|
||||||
let mut right_diff = Vec::<ObjInsDiff>::new();
|
let mut right_diff = Vec::<ObjInsDiff>::new();
|
||||||
match config.code_alg {
|
diff_instructions(&mut left_diff, &mut right_diff, &left_out, &right_out)?;
|
||||||
DiffAlg::Levenshtein => {
|
|
||||||
diff_instructions_lev(
|
|
||||||
&mut left_diff,
|
|
||||||
&mut right_diff,
|
|
||||||
left_symbol,
|
|
||||||
right_symbol,
|
|
||||||
&left_out,
|
|
||||||
&right_out,
|
|
||||||
)?;
|
|
||||||
}
|
|
||||||
DiffAlg::Lcs => {
|
|
||||||
diff_instructions_similar(
|
|
||||||
Algorithm::Lcs,
|
|
||||||
&mut left_diff,
|
|
||||||
&mut right_diff,
|
|
||||||
&left_out,
|
|
||||||
&right_out,
|
|
||||||
)?;
|
|
||||||
}
|
|
||||||
DiffAlg::Myers => {
|
|
||||||
diff_instructions_similar(
|
|
||||||
Algorithm::Myers,
|
|
||||||
&mut left_diff,
|
|
||||||
&mut right_diff,
|
|
||||||
&left_out,
|
|
||||||
&right_out,
|
|
||||||
)?;
|
|
||||||
}
|
|
||||||
DiffAlg::Patience => {
|
|
||||||
diff_instructions_similar(
|
|
||||||
Algorithm::Patience,
|
|
||||||
&mut left_diff,
|
|
||||||
&mut right_diff,
|
|
||||||
&left_out,
|
|
||||||
&right_out,
|
|
||||||
)?;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
resolve_branches(&mut left_diff);
|
resolve_branches(&mut left_diff);
|
||||||
resolve_branches(&mut right_diff);
|
resolve_branches(&mut right_diff);
|
||||||
|
@ -168,15 +127,19 @@ pub fn diff_code(
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn diff_instructions_similar(
|
fn diff_instructions(
|
||||||
alg: Algorithm,
|
|
||||||
left_diff: &mut Vec<ObjInsDiff>,
|
left_diff: &mut Vec<ObjInsDiff>,
|
||||||
right_diff: &mut Vec<ObjInsDiff>,
|
right_diff: &mut Vec<ObjInsDiff>,
|
||||||
left_code: &ProcessCodeResult,
|
left_code: &ProcessCodeResult,
|
||||||
right_code: &ProcessCodeResult,
|
right_code: &ProcessCodeResult,
|
||||||
) -> Result<()> {
|
) -> Result<()> {
|
||||||
let deadline = Instant::now() + Duration::from_secs(5);
|
let deadline = Instant::now() + Duration::from_secs(5);
|
||||||
let ops = capture_diff_slices_deadline(alg, &left_code.ops, &right_code.ops, Some(deadline));
|
let ops = capture_diff_slices_deadline(
|
||||||
|
Algorithm::Patience,
|
||||||
|
&left_code.ops,
|
||||||
|
&right_code.ops,
|
||||||
|
Some(deadline),
|
||||||
|
);
|
||||||
if ops.is_empty() {
|
if ops.is_empty() {
|
||||||
left_diff.extend(
|
left_diff.extend(
|
||||||
left_code
|
left_code
|
||||||
|
@ -217,75 +180,6 @@ fn diff_instructions_similar(
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn diff_instructions_lev(
|
|
||||||
left_diff: &mut Vec<ObjInsDiff>,
|
|
||||||
right_diff: &mut Vec<ObjInsDiff>,
|
|
||||||
left_symbol: &ObjSymbol,
|
|
||||||
right_symbol: &ObjSymbol,
|
|
||||||
left_code: &ProcessCodeResult,
|
|
||||||
right_code: &ProcessCodeResult,
|
|
||||||
) -> Result<()> {
|
|
||||||
let edit_ops = editops_find(&left_code.ops, &right_code.ops);
|
|
||||||
|
|
||||||
let mut op_iter = edit_ops.iter();
|
|
||||||
let mut left_iter = left_code.insts.iter();
|
|
||||||
let mut right_iter = right_code.insts.iter();
|
|
||||||
let mut cur_op = op_iter.next();
|
|
||||||
let mut cur_left = left_iter.next();
|
|
||||||
let mut cur_right = right_iter.next();
|
|
||||||
while let Some(op) = cur_op {
|
|
||||||
let left_addr = op.first_start as u32 * 4;
|
|
||||||
let right_addr = op.second_start as u32 * 4;
|
|
||||||
while let (Some(left), Some(right)) = (cur_left, cur_right) {
|
|
||||||
if (left.address - left_symbol.address as u32) < left_addr {
|
|
||||||
left_diff.push(ObjInsDiff { ins: Some(left.clone()), ..ObjInsDiff::default() });
|
|
||||||
right_diff.push(ObjInsDiff { ins: Some(right.clone()), ..ObjInsDiff::default() });
|
|
||||||
} else {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
cur_left = left_iter.next();
|
|
||||||
cur_right = right_iter.next();
|
|
||||||
}
|
|
||||||
if let (Some(left), Some(right)) = (cur_left, cur_right) {
|
|
||||||
debug_assert_eq!(left.address - left_symbol.address as u32, left_addr);
|
|
||||||
debug_assert_eq!(right.address - right_symbol.address as u32, right_addr);
|
|
||||||
match op.op_type {
|
|
||||||
LevEditType::Replace => {
|
|
||||||
left_diff.push(ObjInsDiff { ins: Some(left.clone()), ..ObjInsDiff::default() });
|
|
||||||
right_diff
|
|
||||||
.push(ObjInsDiff { ins: Some(right.clone()), ..ObjInsDiff::default() });
|
|
||||||
cur_left = left_iter.next();
|
|
||||||
cur_right = right_iter.next();
|
|
||||||
}
|
|
||||||
LevEditType::Insert => {
|
|
||||||
left_diff.push(ObjInsDiff::default());
|
|
||||||
right_diff
|
|
||||||
.push(ObjInsDiff { ins: Some(right.clone()), ..ObjInsDiff::default() });
|
|
||||||
cur_right = right_iter.next();
|
|
||||||
}
|
|
||||||
LevEditType::Delete => {
|
|
||||||
left_diff.push(ObjInsDiff { ins: Some(left.clone()), ..ObjInsDiff::default() });
|
|
||||||
right_diff.push(ObjInsDiff::default());
|
|
||||||
cur_left = left_iter.next();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
cur_op = op_iter.next();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Finalize
|
|
||||||
while cur_left.is_some() || cur_right.is_some() {
|
|
||||||
left_diff.push(ObjInsDiff { ins: cur_left.cloned(), ..ObjInsDiff::default() });
|
|
||||||
right_diff.push(ObjInsDiff { ins: cur_right.cloned(), ..ObjInsDiff::default() });
|
|
||||||
cur_left = left_iter.next();
|
|
||||||
cur_right = right_iter.next();
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
fn resolve_branches(vec: &mut [ObjInsDiff]) {
|
fn resolve_branches(vec: &mut [ObjInsDiff]) {
|
||||||
let mut branch_idx = 0usize;
|
let mut branch_idx = 0usize;
|
||||||
// Map addresses to indices
|
// Map addresses to indices
|
||||||
|
|
|
@ -1,28 +1,12 @@
|
||||||
use std::{
|
use std::{
|
||||||
cmp::{max, min, Ordering},
|
cmp::{max, min, Ordering},
|
||||||
mem::take,
|
|
||||||
time::{Duration, Instant},
|
time::{Duration, Instant},
|
||||||
};
|
};
|
||||||
|
|
||||||
use anyhow::{ensure, Result};
|
use anyhow::Result;
|
||||||
use similar::{capture_diff_slices_deadline, Algorithm};
|
use similar::{capture_diff_slices_deadline, Algorithm};
|
||||||
|
|
||||||
use crate::{
|
use crate::obj::{ObjDataDiff, ObjDataDiffKind, ObjSection, ObjSymbol};
|
||||||
diff::{
|
|
||||||
editops::{editops_find, LevEditType},
|
|
||||||
DiffAlg,
|
|
||||||
},
|
|
||||||
obj::{ObjDataDiff, ObjDataDiffKind, ObjSection, ObjSymbol},
|
|
||||||
};
|
|
||||||
|
|
||||||
pub fn diff_data(alg: DiffAlg, left: &mut ObjSection, right: &mut ObjSection) -> Result<()> {
|
|
||||||
match alg {
|
|
||||||
DiffAlg::Levenshtein => diff_data_lev(left, right),
|
|
||||||
DiffAlg::Lcs => diff_data_similar(Algorithm::Lcs, left, right),
|
|
||||||
DiffAlg::Myers => diff_data_similar(Algorithm::Myers, left, right),
|
|
||||||
DiffAlg::Patience => diff_data_similar(Algorithm::Patience, left, right),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn diff_bss_symbols(
|
pub fn diff_bss_symbols(
|
||||||
left_symbols: &mut [ObjSymbol],
|
left_symbols: &mut [ObjSymbol],
|
||||||
|
@ -40,67 +24,10 @@ pub fn diff_bss_symbols(
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
// WIP diff-by-symbol
|
pub fn diff_data(left: &mut ObjSection, right: &mut ObjSection) -> Result<()> {
|
||||||
#[allow(dead_code)]
|
|
||||||
pub fn diff_data_symbols(left: &mut ObjSection, right: &mut ObjSection) -> Result<()> {
|
|
||||||
let mut left_ops = Vec::<u32>::with_capacity(left.symbols.len());
|
|
||||||
let mut right_ops = Vec::<u32>::with_capacity(right.symbols.len());
|
|
||||||
for left_symbol in &left.symbols {
|
|
||||||
let data = &left.data
|
|
||||||
[left_symbol.address as usize..(left_symbol.address + left_symbol.size) as usize];
|
|
||||||
let hash = twox_hash::xxh3::hash64(data);
|
|
||||||
left_ops.push(hash as u32);
|
|
||||||
}
|
|
||||||
for symbol in &right.symbols {
|
|
||||||
let data = &right.data[symbol.address as usize..(symbol.address + symbol.size) as usize];
|
|
||||||
let hash = twox_hash::xxh3::hash64(data);
|
|
||||||
right_ops.push(hash as u32);
|
|
||||||
}
|
|
||||||
|
|
||||||
let edit_ops = editops_find(&left_ops, &right_ops);
|
|
||||||
if edit_ops.is_empty() && !left.data.is_empty() {
|
|
||||||
let mut left_iter = left.symbols.iter_mut();
|
|
||||||
let mut right_iter = right.symbols.iter_mut();
|
|
||||||
loop {
|
|
||||||
let (left_symbol, right_symbol) = match (left_iter.next(), right_iter.next()) {
|
|
||||||
(Some(l), Some(r)) => (l, r),
|
|
||||||
(None, None) => break,
|
|
||||||
_ => return Err(anyhow::Error::msg("L/R mismatch in diff_data_symbols")),
|
|
||||||
};
|
|
||||||
let left_data = &left.data
|
|
||||||
[left_symbol.address as usize..(left_symbol.address + left_symbol.size) as usize];
|
|
||||||
let right_data = &right.data[right_symbol.address as usize
|
|
||||||
..(right_symbol.address + right_symbol.size) as usize];
|
|
||||||
|
|
||||||
left.data_diff.push(ObjDataDiff {
|
|
||||||
data: left_data.to_vec(),
|
|
||||||
kind: ObjDataDiffKind::None,
|
|
||||||
len: left_symbol.size as usize,
|
|
||||||
symbol: left_symbol.name.clone(),
|
|
||||||
});
|
|
||||||
right.data_diff.push(ObjDataDiff {
|
|
||||||
data: right_data.to_vec(),
|
|
||||||
kind: ObjDataDiffKind::None,
|
|
||||||
len: right_symbol.size as usize,
|
|
||||||
symbol: right_symbol.name.clone(),
|
|
||||||
});
|
|
||||||
left_symbol.diff_symbol = Some(right_symbol.name.clone());
|
|
||||||
left_symbol.match_percent = Some(100.0);
|
|
||||||
right_symbol.diff_symbol = Some(left_symbol.name.clone());
|
|
||||||
right_symbol.match_percent = Some(100.0);
|
|
||||||
}
|
|
||||||
return Ok(());
|
|
||||||
}
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn diff_data_similar(
|
|
||||||
alg: Algorithm,
|
|
||||||
left: &mut ObjSection,
|
|
||||||
right: &mut ObjSection,
|
|
||||||
) -> Result<()> {
|
|
||||||
let deadline = Instant::now() + Duration::from_secs(5);
|
let deadline = Instant::now() + Duration::from_secs(5);
|
||||||
let ops = capture_diff_slices_deadline(alg, &left.data, &right.data, Some(deadline));
|
let ops =
|
||||||
|
capture_diff_slices_deadline(Algorithm::Patience, &left.data, &right.data, Some(deadline));
|
||||||
|
|
||||||
let mut left_diff = Vec::<ObjDataDiff>::new();
|
let mut left_diff = Vec::<ObjDataDiff>::new();
|
||||||
let mut right_diff = Vec::<ObjDataDiff>::new();
|
let mut right_diff = Vec::<ObjDataDiff>::new();
|
||||||
|
@ -175,226 +102,6 @@ pub fn diff_data_similar(
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn diff_data_lev(left: &mut ObjSection, right: &mut ObjSection) -> Result<()> {
|
|
||||||
let matrix_size = (left.data.len() as u64).saturating_mul(right.data.len() as u64);
|
|
||||||
ensure!(
|
|
||||||
matrix_size < 1_000_000_000,
|
|
||||||
"Data section {} too large for Levenshtein diff ({} * {} = {})",
|
|
||||||
left.name,
|
|
||||||
left.data.len(),
|
|
||||||
right.data.len(),
|
|
||||||
matrix_size
|
|
||||||
);
|
|
||||||
|
|
||||||
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(),
|
|
||||||
symbol: String::new(),
|
|
||||||
}];
|
|
||||||
right.data_diff = vec![ObjDataDiff {
|
|
||||||
data: right.data.clone(),
|
|
||||||
kind: ObjDataDiffKind::None,
|
|
||||||
len: right.data.len(),
|
|
||||||
symbol: String::new(),
|
|
||||||
}];
|
|
||||||
return Ok(());
|
|
||||||
}
|
|
||||||
|
|
||||||
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::Replace;
|
|
||||||
let mut cur_left_data = Vec::<u8>::new();
|
|
||||||
let mut cur_right_data = Vec::<u8>::new();
|
|
||||||
for op in edit_ops {
|
|
||||||
if cur_op != op.op_type || left_cur < op.first_start || right_cur < op.second_start {
|
|
||||||
match cur_op {
|
|
||||||
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,
|
|
||||||
symbol: String::new(),
|
|
||||||
});
|
|
||||||
right_diff.push(ObjDataDiff {
|
|
||||||
data: right_data,
|
|
||||||
kind: ObjDataDiffKind::Replace,
|
|
||||||
len: right_data_len,
|
|
||||||
symbol: String::new(),
|
|
||||||
});
|
|
||||||
}
|
|
||||||
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,
|
|
||||||
symbol: String::new(),
|
|
||||||
});
|
|
||||||
right_diff.push(ObjDataDiff {
|
|
||||||
data: right_data,
|
|
||||||
kind: ObjDataDiffKind::Insert,
|
|
||||||
len: right_data_len,
|
|
||||||
symbol: String::new(),
|
|
||||||
});
|
|
||||||
}
|
|
||||||
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,
|
|
||||||
symbol: String::new(),
|
|
||||||
});
|
|
||||||
right_diff.push(ObjDataDiff {
|
|
||||||
data: vec![],
|
|
||||||
kind: ObjDataDiffKind::Delete,
|
|
||||||
len: left_data_len,
|
|
||||||
symbol: String::new(),
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
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,
|
|
||||||
symbol: String::new(),
|
|
||||||
});
|
|
||||||
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,
|
|
||||||
symbol: String::new(),
|
|
||||||
});
|
|
||||||
right_cur = op.second_start;
|
|
||||||
}
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
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::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,
|
|
||||||
symbol: String::new(),
|
|
||||||
});
|
|
||||||
right_diff.push(ObjDataDiff {
|
|
||||||
data: right_data,
|
|
||||||
kind: ObjDataDiffKind::Replace,
|
|
||||||
len: right_data_len,
|
|
||||||
symbol: String::new(),
|
|
||||||
});
|
|
||||||
}
|
|
||||||
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,
|
|
||||||
symbol: String::new(),
|
|
||||||
});
|
|
||||||
right_diff.push(ObjDataDiff {
|
|
||||||
data: right_data,
|
|
||||||
kind: ObjDataDiffKind::Insert,
|
|
||||||
len: right_data_len,
|
|
||||||
symbol: String::new(),
|
|
||||||
});
|
|
||||||
}
|
|
||||||
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,
|
|
||||||
symbol: String::new(),
|
|
||||||
});
|
|
||||||
right_diff.push(ObjDataDiff {
|
|
||||||
data: vec![],
|
|
||||||
kind: ObjDataDiffKind::Delete,
|
|
||||||
len: left_data_len,
|
|
||||||
symbol: String::new(),
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if left_cur < left.data.len() {
|
|
||||||
left_diff.push(ObjDataDiff {
|
|
||||||
data: left.data[left_cur..].to_vec(),
|
|
||||||
kind: ObjDataDiffKind::None,
|
|
||||||
len: left.data.len() - left_cur,
|
|
||||||
symbol: String::new(),
|
|
||||||
});
|
|
||||||
}
|
|
||||||
if right_cur < right.data.len() {
|
|
||||||
right_diff.push(ObjDataDiff {
|
|
||||||
data: right.data[right_cur..].to_vec(),
|
|
||||||
kind: ObjDataDiffKind::None,
|
|
||||||
len: right.data.len() - right_cur,
|
|
||||||
symbol: String::new(),
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
left.data_diff = left_diff;
|
|
||||||
right.data_diff = right_diff;
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn no_diff_data(section: &mut ObjSection) {
|
pub fn no_diff_data(section: &mut ObjSection) {
|
||||||
section.data_diff = vec![ObjDataDiff {
|
section.data_diff = vec![ObjDataDiff {
|
||||||
data: section.data.clone(),
|
data: section.data.clone(),
|
||||||
|
|
|
@ -1,162 +0,0 @@
|
||||||
/// Adapted from https://crates.io/crates/rapidfuzz
|
|
||||||
// Copyright 2020 maxbachmann
|
|
||||||
//
|
|
||||||
// Permission is hereby granted, free of charge, to any
|
|
||||||
// person obtaining a copy of this software and associated
|
|
||||||
// documentation files (the "Software"), to deal in the
|
|
||||||
// Software without restriction, including without
|
|
||||||
// limitation the rights to use, copy, modify, merge,
|
|
||||||
// publish, distribute, sublicense, and/or sell copies of
|
|
||||||
// the Software, and to permit persons to whom the Software
|
|
||||||
// is furnished to do so, subject to the following
|
|
||||||
// conditions:
|
|
||||||
//
|
|
||||||
// The above copyright notice and this permission notice
|
|
||||||
// shall be included in all copies or substantial portions
|
|
||||||
// of the Software.
|
|
||||||
//
|
|
||||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF
|
|
||||||
// ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
|
|
||||||
// TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
|
|
||||||
// PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT
|
|
||||||
// SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
|
||||||
// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
|
||||||
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR
|
|
||||||
// IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
|
||||||
// DEALINGS IN THE SOFTWARE.
|
|
||||||
|
|
||||||
#[derive(Debug, PartialEq, Eq, Copy, Clone)]
|
|
||||||
pub enum LevEditType {
|
|
||||||
Replace,
|
|
||||||
Insert,
|
|
||||||
Delete,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, PartialEq, Eq)]
|
|
||||||
pub struct LevEditOp {
|
|
||||||
pub op_type: LevEditType, /* editing operation type */
|
|
||||||
pub first_start: usize, /* source block position */
|
|
||||||
pub second_start: usize, /* destination position */
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn editops_find<T>(query: &[T], choice: &[T]) -> Vec<LevEditOp>
|
|
||||||
where T: PartialEq {
|
|
||||||
let Affix { prefix_len, suffix_len } = Affix::find(query, choice);
|
|
||||||
|
|
||||||
let first_string = &query[prefix_len..query.len() - suffix_len];
|
|
||||||
let second_string = &choice[prefix_len..choice.len() - suffix_len];
|
|
||||||
|
|
||||||
let matrix_columns = first_string.len() + 1;
|
|
||||||
let matrix_rows = second_string.len() + 1;
|
|
||||||
|
|
||||||
// TODO maybe use an actual matrix for readability
|
|
||||||
let mut cache_matrix: Vec<usize> = vec![0; matrix_rows * matrix_columns];
|
|
||||||
for (i, elem) in cache_matrix.iter_mut().enumerate().take(matrix_rows) {
|
|
||||||
*elem = i;
|
|
||||||
}
|
|
||||||
for i in 1..matrix_columns {
|
|
||||||
cache_matrix[matrix_rows * i] = i;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (i, char1) in first_string.iter().enumerate() {
|
|
||||||
let mut prev = i * matrix_rows;
|
|
||||||
let current = prev + matrix_rows;
|
|
||||||
let mut x = i + 1;
|
|
||||||
for (p, char2p) in second_string.iter().enumerate() {
|
|
||||||
let mut c3 = cache_matrix[prev] + (char1 != char2p) as usize;
|
|
||||||
prev += 1;
|
|
||||||
x += 1;
|
|
||||||
if x >= c3 {
|
|
||||||
x = c3;
|
|
||||||
}
|
|
||||||
c3 = cache_matrix[prev] + 1;
|
|
||||||
if x > c3 {
|
|
||||||
x = c3;
|
|
||||||
}
|
|
||||||
cache_matrix[current + 1 + p] = x;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
editops_from_cost_matrix(matrix_columns, matrix_rows, prefix_len, cache_matrix)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn editops_from_cost_matrix(
|
|
||||||
len1: usize,
|
|
||||||
len2: usize,
|
|
||||||
prefix_len: usize,
|
|
||||||
cache_matrix: Vec<usize>,
|
|
||||||
) -> Vec<LevEditOp> {
|
|
||||||
let mut ops = Vec::with_capacity(cache_matrix[len1 * len2 - 1]);
|
|
||||||
let mut dir = 0;
|
|
||||||
let mut i = len1 - 1;
|
|
||||||
let mut j = len2 - 1;
|
|
||||||
let mut p = len1 * len2 - 1;
|
|
||||||
|
|
||||||
//TODO this is still pretty ugly
|
|
||||||
while i > 0 || j > 0 {
|
|
||||||
let current_value = cache_matrix[p];
|
|
||||||
|
|
||||||
// More than one operation can be possible at a time. We use `dir` to
|
|
||||||
// decide when ambiguous.
|
|
||||||
let is_insert = j > 0 && current_value == cache_matrix[p - 1] + 1;
|
|
||||||
let is_delete = i > 0 && current_value == cache_matrix[p - len2] + 1;
|
|
||||||
let is_replace = i > 0 && j > 0 && current_value == cache_matrix[p - len2 - 1] + 1;
|
|
||||||
|
|
||||||
let (op_type, new_dir) = match (dir, is_insert, is_delete, is_replace) {
|
|
||||||
(_, false, false, false) => (None, 0),
|
|
||||||
(-1, true, _, _) => (Some(LevEditType::Insert), -1),
|
|
||||||
(1, _, true, _) => (Some(LevEditType::Delete), 1),
|
|
||||||
(_, _, _, true) => (Some(LevEditType::Replace), 0),
|
|
||||||
(0, true, _, _) => (Some(LevEditType::Insert), -1),
|
|
||||||
(0, _, true, _) => (Some(LevEditType::Delete), 1),
|
|
||||||
_ => panic!("something went terribly wrong"),
|
|
||||||
};
|
|
||||||
|
|
||||||
match new_dir {
|
|
||||||
-1 => {
|
|
||||||
j -= 1;
|
|
||||||
p -= 1;
|
|
||||||
}
|
|
||||||
1 => {
|
|
||||||
i -= 1;
|
|
||||||
p -= len2;
|
|
||||||
}
|
|
||||||
0 => {
|
|
||||||
i -= 1;
|
|
||||||
j -= 1;
|
|
||||||
p -= len2 + 1;
|
|
||||||
}
|
|
||||||
_ => panic!("something went terribly wrong"),
|
|
||||||
};
|
|
||||||
dir = new_dir;
|
|
||||||
|
|
||||||
if let Some(op_type) = op_type {
|
|
||||||
ops.insert(0, LevEditOp {
|
|
||||||
op_type,
|
|
||||||
first_start: i + prefix_len,
|
|
||||||
second_start: j + prefix_len,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
ops
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct Affix {
|
|
||||||
pub prefix_len: usize,
|
|
||||||
pub suffix_len: usize,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Affix {
|
|
||||||
pub fn find<T>(s1: &[T], s2: &[T]) -> Affix
|
|
||||||
where T: PartialEq {
|
|
||||||
let prefix_len = s1.iter().zip(s2.iter()).take_while(|t| t.0 == t.1).count();
|
|
||||||
let suffix_len = s1[prefix_len..]
|
|
||||||
.iter()
|
|
||||||
.rev()
|
|
||||||
.zip(s2[prefix_len..].iter().rev())
|
|
||||||
.take_while(|t| t.0 == t.1)
|
|
||||||
.count();
|
|
||||||
|
|
||||||
Affix { prefix_len, suffix_len }
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,10 +1,8 @@
|
||||||
pub mod code;
|
pub mod code;
|
||||||
pub mod data;
|
pub mod data;
|
||||||
pub mod display;
|
pub mod display;
|
||||||
pub mod editops;
|
|
||||||
|
|
||||||
use anyhow::Result;
|
use anyhow::Result;
|
||||||
use serde::{Deserialize, Serialize};
|
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
diff::{
|
diff::{
|
||||||
|
@ -14,19 +12,8 @@ use crate::{
|
||||||
obj::{ObjInfo, ObjIns, ObjSectionKind},
|
obj::{ObjInfo, ObjIns, ObjSectionKind},
|
||||||
};
|
};
|
||||||
|
|
||||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, Default, Serialize, Deserialize)]
|
|
||||||
pub enum DiffAlg {
|
|
||||||
#[default]
|
|
||||||
Patience,
|
|
||||||
Levenshtein,
|
|
||||||
Myers,
|
|
||||||
Lcs,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, Clone, Default, Eq, PartialEq)]
|
#[derive(Debug, Clone, Default, Eq, PartialEq)]
|
||||||
pub struct DiffObjConfig {
|
pub struct DiffObjConfig {
|
||||||
pub code_alg: DiffAlg,
|
|
||||||
pub data_alg: DiffAlg,
|
|
||||||
pub relax_reloc_diffs: bool,
|
pub relax_reloc_diffs: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -80,7 +67,7 @@ pub fn diff_objs(
|
||||||
.and_then(|obj| obj.sections.iter_mut().find(|s| s.name == left_section.name))
|
.and_then(|obj| obj.sections.iter_mut().find(|s| s.name == left_section.name))
|
||||||
{
|
{
|
||||||
if left_section.kind == ObjSectionKind::Data {
|
if left_section.kind == ObjSectionKind::Data {
|
||||||
diff_data(config.data_alg, left_section, right_section)?;
|
diff_data(left_section, right_section)?;
|
||||||
} else if left_section.kind == ObjSectionKind::Bss {
|
} else if left_section.kind == ObjSectionKind::Bss {
|
||||||
diff_bss_symbols(&mut left_section.symbols, &mut right_section.symbols)?;
|
diff_bss_symbols(&mut left_section.symbols, &mut right_section.symbols)?;
|
||||||
}
|
}
|
||||||
|
|
|
@ -106,10 +106,6 @@ pub struct AppConfig {
|
||||||
#[serde(default)]
|
#[serde(default)]
|
||||||
pub recent_projects: Vec<PathBuf>,
|
pub recent_projects: Vec<PathBuf>,
|
||||||
#[serde(default)]
|
#[serde(default)]
|
||||||
pub code_alg: DiffAlg,
|
|
||||||
#[serde(default)]
|
|
||||||
pub data_alg: DiffAlg,
|
|
||||||
#[serde(default)]
|
|
||||||
pub relax_reloc_diffs: bool,
|
pub relax_reloc_diffs: bool,
|
||||||
|
|
||||||
#[serde(skip)]
|
#[serde(skip)]
|
||||||
|
@ -148,8 +144,6 @@ impl Default for AppConfig {
|
||||||
auto_update_check: true,
|
auto_update_check: true,
|
||||||
watch_patterns: DEFAULT_WATCH_PATTERNS.iter().map(|s| Glob::new(s).unwrap()).collect(),
|
watch_patterns: DEFAULT_WATCH_PATTERNS.iter().map(|s| Glob::new(s).unwrap()).collect(),
|
||||||
recent_projects: vec![],
|
recent_projects: vec![],
|
||||||
code_alg: Default::default(),
|
|
||||||
data_alg: Default::default(),
|
|
||||||
relax_reloc_diffs: false,
|
relax_reloc_diffs: false,
|
||||||
objects: vec![],
|
objects: vec![],
|
||||||
object_nodes: vec![],
|
object_nodes: vec![],
|
||||||
|
|
|
@ -57,8 +57,6 @@ pub struct ObjDiffConfig {
|
||||||
pub build_base: bool,
|
pub build_base: bool,
|
||||||
pub build_target: bool,
|
pub build_target: bool,
|
||||||
pub selected_obj: Option<ObjectConfig>,
|
pub selected_obj: Option<ObjectConfig>,
|
||||||
pub code_alg: DiffAlg,
|
|
||||||
pub data_alg: DiffAlg,
|
|
||||||
pub relax_reloc_diffs: bool,
|
pub relax_reloc_diffs: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -69,8 +67,6 @@ impl ObjDiffConfig {
|
||||||
build_base: config.build_base,
|
build_base: config.build_base,
|
||||||
build_target: config.build_target,
|
build_target: config.build_target,
|
||||||
selected_obj: config.selected_obj.clone(),
|
selected_obj: config.selected_obj.clone(),
|
||||||
code_alg: config.code_alg,
|
|
||||||
data_alg: config.data_alg,
|
|
||||||
relax_reloc_diffs: config.relax_reloc_diffs,
|
relax_reloc_diffs: config.relax_reloc_diffs,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -253,11 +249,7 @@ fn run_build(
|
||||||
};
|
};
|
||||||
|
|
||||||
update_status(context, "Performing diff".to_string(), 4, total, &cancel)?;
|
update_status(context, "Performing diff".to_string(), 4, total, &cancel)?;
|
||||||
let diff_config = DiffObjConfig {
|
let diff_config = DiffObjConfig { relax_reloc_diffs: config.relax_reloc_diffs };
|
||||||
code_alg: config.code_alg,
|
|
||||||
data_alg: config.data_alg,
|
|
||||||
relax_reloc_diffs: config.relax_reloc_diffs,
|
|
||||||
};
|
|
||||||
diff_objs(&diff_config, first_obj.as_mut(), second_obj.as_mut())?;
|
diff_objs(&diff_config, first_obj.as_mut(), second_obj.as_mut())?;
|
||||||
|
|
||||||
update_status(context, "Complete".to_string(), total, total, &cancel)?;
|
update_status(context, "Complete".to_string(), total, total, &cancel)?;
|
||||||
|
|
|
@ -14,10 +14,7 @@ use egui::{
|
||||||
SelectableLabel, TextFormat, Widget, WidgetText,
|
SelectableLabel, TextFormat, Widget, WidgetText,
|
||||||
};
|
};
|
||||||
use globset::Glob;
|
use globset::Glob;
|
||||||
use objdiff_core::{
|
use objdiff_core::config::{ProjectObject, DEFAULT_WATCH_PATTERNS};
|
||||||
config::{ProjectObject, DEFAULT_WATCH_PATTERNS},
|
|
||||||
diff::DiffAlg,
|
|
||||||
};
|
|
||||||
use self_update::cargo_crate_version;
|
use self_update::cargo_crate_version;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
|
@ -853,58 +850,3 @@ pub fn diff_options_window(
|
||||||
diff_options_ui(ui, &mut config_guard, appearance);
|
diff_options_ui(ui, &mut config_guard, appearance);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
fn diff_options_ui(ui: &mut egui::Ui, config: &mut AppConfig, appearance: &Appearance) {
|
|
||||||
let mut job = LayoutJob::default();
|
|
||||||
job.append(
|
|
||||||
"Current default: ",
|
|
||||||
0.0,
|
|
||||||
TextFormat::simple(appearance.ui_font.clone(), appearance.text_color),
|
|
||||||
);
|
|
||||||
job.append(
|
|
||||||
diff_alg_to_string(DiffAlg::default()),
|
|
||||||
0.0,
|
|
||||||
TextFormat::simple(appearance.ui_font.clone(), appearance.emphasized_text_color),
|
|
||||||
);
|
|
||||||
ui.label(job);
|
|
||||||
let mut job = LayoutJob::default();
|
|
||||||
job.append(
|
|
||||||
"Previous default: ",
|
|
||||||
0.0,
|
|
||||||
TextFormat::simple(appearance.ui_font.clone(), appearance.text_color),
|
|
||||||
);
|
|
||||||
job.append(
|
|
||||||
"Levenshtein",
|
|
||||||
0.0,
|
|
||||||
TextFormat::simple(appearance.ui_font.clone(), appearance.emphasized_text_color),
|
|
||||||
);
|
|
||||||
ui.label(job);
|
|
||||||
ui.label("Please provide feedback!");
|
|
||||||
if diff_alg_ui(ui, "Code diff algorithm", &mut config.code_alg) {
|
|
||||||
config.queue_reload = true;
|
|
||||||
}
|
|
||||||
if diff_alg_ui(ui, "Data diff algorithm", &mut config.data_alg) {
|
|
||||||
config.queue_reload = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn diff_alg_ui(ui: &mut egui::Ui, label: impl Into<WidgetText>, alg: &mut DiffAlg) -> bool {
|
|
||||||
let response = egui::ComboBox::from_label(label)
|
|
||||||
.selected_text(diff_alg_to_string(*alg))
|
|
||||||
.show_ui(ui, |ui| {
|
|
||||||
ui.selectable_value(alg, DiffAlg::Patience, "Patience").changed()
|
|
||||||
| ui.selectable_value(alg, DiffAlg::Levenshtein, "Levenshtein").changed()
|
|
||||||
| ui.selectable_value(alg, DiffAlg::Myers, "Myers").changed()
|
|
||||||
| ui.selectable_value(alg, DiffAlg::Lcs, "LCS").changed()
|
|
||||||
});
|
|
||||||
response.inner.unwrap_or(false)
|
|
||||||
}
|
|
||||||
|
|
||||||
const fn diff_alg_to_string(alg: DiffAlg) -> &'static str {
|
|
||||||
match alg {
|
|
||||||
DiffAlg::Patience => "Patience",
|
|
||||||
DiffAlg::Levenshtein => "Levenshtein",
|
|
||||||
DiffAlg::Lcs => "LCS",
|
|
||||||
DiffAlg::Myers => "Myers",
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
Loading…
Reference in New Issue