Improve dmp comparison description

This commit is contained in:
Andras Schmelczer 2026-10-27 21:35:15 +00:00
commit 2ff418b834

View file

@ -3,7 +3,7 @@ use std::panic;
use diff_match_patch_rs::{Compat, DiffMatchPatch, PatchInput}; use diff_match_patch_rs::{Compat, DiffMatchPatch, PatchInput};
use reconcile_text::{BuiltinTokenizer, reconcile}; use reconcile_text::{BuiltinTokenizer, reconcile};
fn dmp_merge(parent: &str, left: &str, right: &str) -> Option<String> { fn dmp_merge(parent: &str, left: &str, right: &str) -> Option<(String, Vec<bool>)> {
let parent = parent.to_owned(); let parent = parent.to_owned();
let left = left.to_owned(); let left = left.to_owned();
let right = right.to_owned(); let right = right.to_owned();
@ -15,8 +15,7 @@ fn dmp_merge(parent: &str, left: &str, right: &str) -> Option<String> {
let patches = dmp let patches = dmp
.patch_make(PatchInput::new_text_diffs(&parent, &diffs)) .patch_make(PatchInput::new_text_diffs(&parent, &diffs))
.ok()?; .ok()?;
let (result, _) = dmp.patch_apply(&patches, &right).ok()?; dmp.patch_apply(&patches, &right).ok()
Some(result)
}) })
.ok() .ok()
.flatten() .flatten()
@ -39,32 +38,34 @@ fn try_merge(parent: &str, left: &str, right: &str) {
println!("Right: {right:?}"); println!("Right: {right:?}");
println!(); println!();
match dmp_result { match dmp_result {
Some(r) => println!("diff-match-patch: {r:?}"), Some((result, applied)) => {
println!("diff-match-patch: {result:?}");
println!("Patch success: {applied:?}");
}
None => println!("diff-match-patch: <panic or error>"), None => println!("diff-match-patch: <panic or error>"),
} }
println!("reconcile-text: {reconcile_result:?}"); println!("reconcile-text: {reconcile_result:?}");
println!(); println!();
} }
/// Demonstrates cases where diff-match-patch silently produces incorrect /// Compares applying parent → left patches to right with three-way merging.
/// output, while reconcile-text preserves both users' edits correctly /// Shows both a garbled result reported as successful and a reported patch failure.
/// ///
/// Run it with: /// Run it with:
/// `cargo run --example compare-with-diff-match-patch` /// `cargo run --example compare-with-diff-match-patch`
fn main() { fn main() {
// Example 1 // Example 1
// Two users edit the same short phrase. Alice replaces "old(!)" with // Two users edit the same short phrase. Alice replaces "old(!) broken"
// "new improved", Bob replaces "broken" with "working". These are // with "new improved", deleting "broken", while Bob replaces "broken"
// independent changes to adjacent words. // with "working". These changes overlap.
// //
// diff-match-patch has no common ancestor, so it diffs parent → left // This comparison diffs parent → left and applies the patch to right.
// and applies the patch to right. The character-level patches overlap // diff-match-patch produces garbled text ("impovind") but reports
// and produce garbled text ("impovind"). It reports success. // patch success as [true].
// //
// reconcile-text sees both changes relative to the parent and merges // reconcile-text resolves the overlap to "new improved working code".
// them cleanly.
println!("── Example 1: adjacent edits ──"); println!("── Example 1: overlapping edits ──");
try_merge( try_merge(
"old(!) broken code", "old(!) broken code",
"new improved code", "new improved code",
@ -72,18 +73,15 @@ fn main() {
); );
// Example 2 // Example 2
// Alice adds a sentence. Bob rewrites the surrounding text. Because
// diff-match-patch works without a common ancestor, Alice's entire
// sentence is silently lost.
println!("── Example 2: sentence lost ──");
// Alice adds a sentence in the middle of a paragraph. Bob rephrases // Alice adds a sentence in the middle of a paragraph. Bob rephrases
// the same paragraph. Because the patch context from Alice's edit no // the same paragraph. Because the patch context from Alice's edit no
// longer appears in Bob's version, diff-match-patch silently drops // longer matches closely enough in Bob's version, diff-match-patch
// Alice's entire sentence. // leaves Bob's text unchanged and reports patch success as [false].
// The missing sentence is a reported patch failure.
// //
// reconcile-text understands both edits relative to the common ancestor // reconcile-text retains Alice's sentence alongside Bob's rewrite.
// and keeps both.
println!("── Example 2: reported patch failure ──");
try_merge( try_merge(
"We used the existing parsing approach for processing. The output was saved to the \ "We used the existing parsing approach for processing. The output was saved to the \
database.", database.",