summaryrefslogtreecommitdiffstats
path: root/vendor/prettydiff/src/basic.rs
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-05-30 18:31:44 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-05-30 18:31:44 +0000
commitc23a457e72abe608715ac76f076f47dc42af07a5 (patch)
tree2772049aaf84b5c9d0ed12ec8d86812f7a7904b6 /vendor/prettydiff/src/basic.rs
parentReleasing progress-linux version 1.73.0+dfsg1-1~progress7.99u1. (diff)
downloadrustc-c23a457e72abe608715ac76f076f47dc42af07a5.tar.xz
rustc-c23a457e72abe608715ac76f076f47dc42af07a5.zip
Merging upstream version 1.74.1+dfsg1.
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'vendor/prettydiff/src/basic.rs')
-rw-r--r--vendor/prettydiff/src/basic.rs169
1 files changed, 169 insertions, 0 deletions
diff --git a/vendor/prettydiff/src/basic.rs b/vendor/prettydiff/src/basic.rs
new file mode 100644
index 000000000..d35392a7b
--- /dev/null
+++ b/vendor/prettydiff/src/basic.rs
@@ -0,0 +1,169 @@
+//! Basic diff functions
+use crate::lcs;
+use ansi_term::Colour;
+use std::fmt;
+
+/// Single change in original slice needed to get new slice
+#[derive(Debug, PartialEq, Eq)]
+pub enum DiffOp<'a, T: 'a> {
+ /// Appears only in second slice
+ Insert(&'a [T]),
+ /// Appears in both slices, but changed
+ Replace(&'a [T], &'a [T]),
+ /// Appears only in first slice
+ Remove(&'a [T]),
+ /// Appears on both slices
+ Equal(&'a [T]),
+}
+
+/// Diffs any slices which implements PartialEq
+pub fn diff<'a, T: PartialEq>(x: &'a [T], y: &'a [T]) -> Vec<DiffOp<'a, T>> {
+ let mut ops: Vec<DiffOp<T>> = Vec::new();
+ let table = lcs::Table::new(x, y);
+
+ let mut i = 0;
+ let mut j = 0;
+
+ for m in table.matches_zero() {
+ let x_seq = &x[i..m.x];
+ let y_seq = &y[j..m.y];
+
+ if i < m.x && j < m.y {
+ ops.push(DiffOp::Replace(x_seq, y_seq));
+ } else if i < m.x {
+ ops.push(DiffOp::Remove(x_seq));
+ } else if j < m.y {
+ ops.push(DiffOp::Insert(y_seq));
+ }
+
+ i = m.x + m.len;
+ j = m.y + m.len;
+
+ if m.len > 0 {
+ ops.push(DiffOp::Equal(&x[m.x..i]));
+ }
+ }
+ ops
+}
+
+/// Container for slice diff result. Can be pretty-printed by Display trait.
+#[derive(Debug, PartialEq, Eq)]
+pub struct SliceChangeset<'a, T> {
+ pub diff: Vec<DiffOp<'a, T>>,
+}
+
+impl<'a, T: fmt::Display> SliceChangeset<'a, T> {
+ pub fn format(&self, skip_same: bool) -> String {
+ let mut out: Vec<String> = Vec::with_capacity(self.diff.len());
+ for op in &self.diff {
+ match op {
+ DiffOp::Equal(a) => {
+ if !skip_same || a.len() == 1 {
+ for i in a.iter() {
+ out.push(format!(" {}", i))
+ }
+ } else if a.len() > 1 {
+ out.push(format!(" ... skip({}) ...", a.len()));
+ }
+ }
+
+ DiffOp::Insert(a) => {
+ for i in a.iter() {
+ out.push(Colour::Green.paint(format!("+ {}", i)).to_string());
+ }
+ }
+
+ DiffOp::Remove(a) => {
+ for i in a.iter() {
+ out.push(Colour::Red.paint(format!("- {}", i)).to_string());
+ }
+ }
+ DiffOp::Replace(a, b) => {
+ let min_len = std::cmp::min(a.len(), b.len());
+ let max_len = std::cmp::max(a.len(), b.len());
+
+ for i in 0..min_len {
+ out.push(
+ Colour::Yellow
+ .paint(format!("~ {} -> {}", a[i], b[i]))
+ .to_string(),
+ );
+ }
+ for i in min_len..max_len {
+ if max_len == a.len() {
+ out.push(Colour::Red.paint(format!("- {}", a[i])).to_string());
+ } else {
+ out.push(Colour::Green.paint(format!("+ {}", b[i])).to_string());
+ }
+ }
+ }
+ }
+ }
+ format!("[\n{}\n]", out.join(",\n"))
+ }
+}
+
+impl<'a, T: fmt::Display> fmt::Display for SliceChangeset<'a, T> {
+ fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
+ write!(formatter, "{}", self.format(true))
+ }
+}
+
+/// Diff two arbitary slices with elements that support Display trait
+pub fn diff_slice<'a, T: PartialEq + std::fmt::Display>(
+ x: &'a [T],
+ y: &'a [T],
+) -> SliceChangeset<'a, T> {
+ let diff = diff(x, y);
+ SliceChangeset { diff }
+}
+
+#[test]
+fn test_basic() {
+ assert_eq!(
+ diff(&[1, 2, 3, 4, 5, 6], &[2, 3, 5, 7]),
+ vec![
+ DiffOp::Remove(&[1]),
+ DiffOp::Equal(&[2, 3]),
+ DiffOp::Remove(&[4]),
+ DiffOp::Equal(&[5]),
+ DiffOp::Replace(&[6], &[7]),
+ ]
+ );
+
+ assert_eq!(
+ diff_slice(
+ &["q", "a", "b", "x", "c", "d"],
+ &["a", "b", "y", "c", "d", "f"],
+ )
+ .diff,
+ vec![
+ DiffOp::Remove(&["q"]),
+ DiffOp::Equal(&["a", "b"]),
+ DiffOp::Replace(&["x"], &["y"]),
+ DiffOp::Equal(&["c", "d"]),
+ DiffOp::Insert(&["f"]),
+ ]
+ );
+
+ assert_eq!(
+ diff(&["a", "c", "d", "b"], &["a", "e", "b"]),
+ vec![
+ DiffOp::Equal(&["a"]),
+ DiffOp::Replace(&["c", "d"], &["e"]),
+ DiffOp::Equal(&["b"]),
+ ]
+ );
+ println!("Diff: {}", diff_slice(&[1, 2, 3, 4, 5, 6], &[2, 3, 5, 7]));
+ println!(
+ "Diff: {}",
+ diff_slice(
+ &["q", "a", "b", "x", "c", "d"],
+ &["a", "b", "y", "c", "d", "f"]
+ )
+ );
+ println!(
+ "Diff: {}",
+ diff_slice(&["a", "c", "d", "b"], &["a", "e", "b"])
+ );
+}