mtplatx-doc-diff 0.0.2

Semantic tree diff: Document -> Patch<Operation>.
Documentation

mtplatx-doc-diff

Semantic tree diff: DocumentPatch<Operation>, replayable.

The diff engine compares two Documents at the semantic level — never at the source-text level — and emits an ordered Patch of Operations that can be replayed to transform old into new. The implementation is a Myers-style block LCS over top-level blocks; nested structures (lists, tables, quotes) re-run the same algorithm over their child vectors.

Example

use mtplatx_doc_core::{Block, Document, Inline};
use mtplatx_doc_diff::{apply, diff, DiffStats, Operation};

let mut before = Document::new();
before.push(Block::heading(1, vec![Inline::from("A")]));
before.push(Block::paragraph(vec![Inline::from("one")]));

let mut after = before.clone();
after.blocks[0] = Block::heading(1, vec![Inline::from("B")]);
after.push(Block::paragraph(vec![Inline::from("new block")]));

let patch = diff(&before, &after);
let stats = DiffStats::from(&patch);
println!(
    "{} insert(s), {} replace(s), edit distance {}",
    stats.inserts,
    stats.replaces,
    patch.edit_distance(),
);

for op in &patch.operations {
    match op {
        Operation::Replace { index, .. } => println!("block {index} replaced"),
        Operation::Insert { index, .. } => println!("inserted at {index}"),
        Operation::UpdateMetadata { to, .. } => println!("metadata -> {to}"),
        _ => {}
    }
}

// Replay: apply(before, &patch) == after
let replayed = apply(before, &patch).unwrap();
assert_eq!(replayed, after);

API

  • diff(&Document, &Document) -> Patch — semantic block-level diff
  • apply(Document, &Patch) -> Result<Document, DiffError> — replay the patch
  • OperationInsert, Delete, Replace, Move, UpdateMetadata (serde-tagged op)
  • Patchoperations, len(), is_empty(), edit_distance()
  • DiffStatsFrom<&Patch> summary counters

License

Licensed under the MIT License (see the license field in Cargo.toml). Part of the Mtplatx document engine.