MCPcopy Create free account
hub / github.com/atomicdotdev/atomic / merge_text

Function merge_text

atomic-core/src/diff/mod.rs:610–748  ·  view source on GitHub ↗

Three-way merge of byte content. Given three versions of a file: - `base` — the common ancestor (A's original content) - `ours` — our modified version (A' after revise) - `theirs` — their modified version (A+B content after B was applied to A) This computes B's delta via `diff(base, theirs)`, then applies that delta to `ours`. For each region: - **Equal** (B didn't change): keep whatever `

(base: &[u8], ours: &[u8], theirs: &[u8])

Source from the content-addressed store, hash-verified

608/// assert_eq!(merged, b"line alpha revised\nline beta\n");
609/// ```
610pub fn merge_text(base: &[u8], ours: &[u8], theirs: &[u8]) -> Result<Vec<u8>, String> {
611 let base_lines: Vec<Line> = Line::from_bytes(base);
612 let ours_lines: Vec<Line> = Line::from_bytes(ours);
613 let theirs_lines: Vec<Line> = Line::from_bytes(theirs);
614
615 // Compute what "they" changed relative to the common base.
616 let b_delta = diff(&base_lines, &theirs_lines, Algorithm::Myers);
617
618 // Compute what "we" changed relative to the common base.
619 let a_delta = diff(&base_lines, &ours_lines, Algorithm::Myers);
620
621 // Build a set of base line indices that "we" modified (deleted or replaced).
622 // If B also touches any of these lines, that's a conflict.
623 let mut our_changed: std::collections::HashSet<usize> = std::collections::HashSet::new();
624 for op in a_delta.ops() {
625 match op {
626 DiffOp::Delete { old_pos, len, .. }
627 | DiffOp::Replace {
628 old_pos,
629 old_len: len,
630 ..
631 } => {
632 for i in *old_pos..(*old_pos + *len) {
633 our_changed.insert(i);
634 }
635 }
636 _ => {}
637 }
638 }
639
640 // Walk B's delta and build the merged output.
641 //
642 // We track our position in `ours_lines` via `ours_idx`. For Equal
643 // regions we advance ours_idx by the number of base lines consumed
644 // (which maps 1:1 to ours lines in unchanged regions). For regions
645 // B changed, we check for conflicts against our_changed.
646 let mut output: Vec<u8> = Vec::new();
647 let mut base_idx: usize = 0; // current position in base
648 let mut ours_idx: usize = 0; // current position in ours
649
650 for op in b_delta.ops() {
651 match op {
652 DiffOp::Equal { old_pos, len, .. } => {
653 // B didn't change this region. Emit from ours (which may
654 // have A' modifications for these lines).
655 // First, advance to old_pos in base.
656 let skip = old_pos - base_idx;
657 // ours_idx should already be aligned; advance by the
658 // same number of lines we skip in base.
659 ours_idx += skip;
660 base_idx = *old_pos;
661
662 // Emit `len` lines from ours at ours_idx.
663 for i in 0..*len {
664 if ours_idx + i < ours_lines.len() {
665 output.extend_from_slice(ours_lines[ours_idx + i].content());
666 }
667 }

Callers

nothing calls this directly

Calls 6

diffFunction · 0.70
opsMethod · 0.45
insertMethod · 0.45
lenMethod · 0.45
contentMethod · 0.45
containsMethod · 0.45

Tested by

no test coverage detected