///| Type aliases for core diff components
typealias @algorithms.Range
///|
typealias @algorithms.DiffOp
///|
typealias @algorithms.Replace
///|
typealias @algorithms.Capture
///|
typealias @algorithms.Compact
///| Computes the difference between two arrays of `T`.
///| Main entry point for standard diffing logic using Myers algorithm with `Replace` hook.
pub fn[T : Eq] diff(old : Array[T], new : Array[T]) -> Array[DiffOp] {
let d = Replace::new(Capture::new())
let _ = @algorithms.Myers::diff(
d,
old,
Range::new(0, old.length()),
new,
Range::new(0, new.length()),
)
d.into_inner().into_ops()
}
///| Computes the difference between two strings, character by character.
pub fn diff_str(old : String, new : String) -> Array[DiffOp] {
diff(old.to_array(), new.to_array())
}
///| Computes the difference between two arrays of strings, line by line.
pub fn diff_line(old : Array[String], new : Array[String]) -> Array[DiffOp] {
diff(old, new)
}
///| Computes the diff between two arrays and prints the result in a line-by-line format.
pub fn[T : Eq + Show] print_diff_line(old : Array[T], new : Array[T]) -> Unit {
let ops = diff(old, new)
print_diff_ops(old, new, ops)
}
///| Prints a formatted diff to the console based on a list of `DiffOp`.
pub fn[T : Show] print_diff_ops(
old : Array[T],
new : Array[T],
ops : Array[DiffOp],
) -> Unit {
for op in ops {
match op {
DiffOp::Equal(old_index~, new_index=_, len~) => {
let mut i = 0
while i < len {
println(" \{old[old_index + i]}")
i += 1
}
}
DiffOp::Delete(old_index~, old_len~, new_index=_) => {
let mut i = 0
while i < old_len {
println(" - \{old[old_index + i]}")
i += 1
}
}
DiffOp::Insert(old_index=_, new_index~, new_len~) => {
let mut i = 0
while i < new_len {
println(" + \{new[new_index + i]}")
i += 1
}
}
DiffOp::Replace(old_index~, old_len~, new_index~, new_len~) => {
let mut i = 0
while i < old_len {
println(" - \{old[old_index + i]}")
i += 1
}
i = 0
while i < new_len {
println(" + \{new[new_index + i]}")
i += 1
}
}
}
}
}
///| Computes the difference between two arrays using the `Compact` hook
///| to produce a more readable and concise result.
pub fn[T : Eq] diff_with_compact(
old : Array[T],
new : Array[T],
) -> Array[DiffOp] {
let d = Compact::new(Replace::new(Capture::new()), old, new)
let _ = @algorithms.Myers::diff(
d,
old,
Range::new(0, old.length()),
new,
Range::new(0, new.length()),
)
d.into_ops()
}
///| Test basic diff functionality
test "test_diff" {
let a = [1, 2, 3, 4, 5, 8, 9]
let b = [1, 2, 0, 4, 5, 6, 7]
let diffs = diff(a, b)
inspect(
diffs,
content="[Equal(old_index=0, new_index=0, len=2), Replace(old_index=2, old_len=1, new_index=2, new_len=1), Equal(old_index=3, new_index=3, len=2), Replace(old_index=5, old_len=2, new_index=5, new_len=2)]",
)
}
///| Test line-by-line diff printing
test "test_print_diff_line" {
let old = ["0", "1", "2", "3", "4", "5"]
let new = ["9", "1", "2", "5", "6", "7"]
print_diff_line(old, new)
}
///| Test compact diff functionality
test "test_diff_with_compact" {
let old = "a b c d".to_array()
let new = "a b d c".to_array()
let compact_diffs = diff_with_compact(old, new)
inspect(
compact_diffs,
content="[Equal(old_index=0, new_index=0, len=4), Insert(old_index=4, new_index=4, new_len=2), Equal(old_index=4, new_index=6, len=1), Delete(old_index=5, old_len=2, new_index=7)]",
)
}