ok/jj
1
0
Fork 0
forked from mirrors/jj

files: make MergeHunk support any number of removes and adds

I think `files::merge()` will be a useful place to share code for
resolving conflicting hunks after all. We'll want `MergeHunk` to
support multi-way merges then.
This commit is contained in:
Martin von Zweigbergk 2021-06-30 08:57:49 -07:00
parent c93e806265
commit f8c016a8ea
2 changed files with 33 additions and 27 deletions

View file

@ -141,13 +141,13 @@ pub fn materialize_conflict(
files::MergeHunk::Resolved(contents) => { files::MergeHunk::Resolved(contents) => {
file.write_all(&contents).unwrap(); file.write_all(&contents).unwrap();
} }
files::MergeHunk::Conflict { base, left, right } => { files::MergeHunk::Conflict { removes, adds } => {
file.write_all(b"<<<<<<<\n").unwrap(); file.write_all(b"<<<<<<<\n").unwrap();
file.write_all(&left).unwrap(); file.write_all(&adds[0]).unwrap();
file.write_all(b"|||||||\n").unwrap(); file.write_all(b"|||||||\n").unwrap();
file.write_all(&base).unwrap(); file.write_all(&removes[0]).unwrap();
file.write_all(b"=======\n").unwrap(); file.write_all(b"=======\n").unwrap();
file.write_all(&right).unwrap(); file.write_all(&adds[1]).unwrap();
file.write_all(b">>>>>>>\n").unwrap(); file.write_all(b">>>>>>>\n").unwrap();
} }
} }

View file

@ -16,6 +16,8 @@ use std::collections::VecDeque;
use std::fmt::{Debug, Error, Formatter}; use std::fmt::{Debug, Error, Formatter};
use std::ops::Range; use std::ops::Range;
use itertools::Itertools;
use crate::diff; use crate::diff;
use crate::diff::{Diff, DiffHunk}; use crate::diff::{Diff, DiffHunk};
@ -145,9 +147,8 @@ impl<'a> Iterator for DiffLineIterator<'a> {
pub enum MergeHunk { pub enum MergeHunk {
Resolved(Vec<u8>), Resolved(Vec<u8>),
Conflict { Conflict {
base: Vec<u8>, removes: Vec<Vec<u8>>,
left: Vec<u8>, adds: Vec<Vec<u8>>,
right: Vec<u8>,
}, },
} }
@ -158,11 +159,22 @@ impl Debug for MergeHunk {
.debug_tuple("Resolved") .debug_tuple("Resolved")
.field(&String::from_utf8_lossy(data)) .field(&String::from_utf8_lossy(data))
.finish(), .finish(),
MergeHunk::Conflict { base, left, right } => f MergeHunk::Conflict { removes, adds } => f
.debug_struct("Conflict") .debug_struct("Conflict")
.field("base", &String::from_utf8_lossy(base)) .field(
.field("left", &String::from_utf8_lossy(left)) "removes",
.field("right", &String::from_utf8_lossy(right)) &removes
.iter()
.map(|part| String::from_utf8_lossy(part))
.collect_vec(),
)
.field(
"adds",
&adds
.iter()
.map(|part| String::from_utf8_lossy(part))
.collect_vec(),
)
.finish(), .finish(),
} }
} }
@ -182,7 +194,6 @@ struct SyncRegion {
right: Range<usize>, right: Range<usize>,
} }
// TODO: Update callers to use diff::Diff directly instead.
pub fn merge(base: &[u8], left: &[u8], right: &[u8]) -> MergeResult { pub fn merge(base: &[u8], left: &[u8], right: &[u8]) -> MergeResult {
let diff = Diff::for_tokenizer(&[base, left, right], &diff::find_line_ranges); let diff = Diff::for_tokenizer(&[base, left, right], &diff::find_line_ranges);
let mut resolved_hunk: Vec<u8> = vec![]; let mut resolved_hunk: Vec<u8> = vec![];
@ -206,9 +217,8 @@ pub fn merge(base: &[u8], left: &[u8], right: &[u8]) -> MergeResult {
resolved_hunk = vec![]; resolved_hunk = vec![];
} }
merge_hunks.push(MergeHunk::Conflict { merge_hunks.push(MergeHunk::Conflict {
base: base_content.to_vec(), removes: vec![base_content.to_vec()],
left: left_content.to_vec(), adds: vec![left_content.to_vec(), right_content.to_vec()],
right: right_content.to_vec(),
}); });
} }
} }
@ -252,9 +262,8 @@ mod tests {
MergeResult::Conflict(vec![ MergeResult::Conflict(vec![
MergeHunk::Resolved(b"a\n".to_vec()), MergeHunk::Resolved(b"a\n".to_vec()),
MergeHunk::Conflict { MergeHunk::Conflict {
base: b"".to_vec(), removes: vec![b"".to_vec()],
left: b"b\n".to_vec(), adds: vec![b"b\n".to_vec(), b"c\n".to_vec()]
right: b"c\n".to_vec()
} }
]) ])
); );
@ -269,25 +278,22 @@ mod tests {
assert_eq!( assert_eq!(
merge(b"a", b"", b"b"), merge(b"a", b"", b"b"),
MergeResult::Conflict(vec![MergeHunk::Conflict { MergeResult::Conflict(vec![MergeHunk::Conflict {
base: b"a".to_vec(), removes: vec![b"a".to_vec()],
left: b"".to_vec(), adds: vec![b"".to_vec(), b"b".to_vec()]
right: b"b".to_vec()
}]) }])
); );
assert_eq!( assert_eq!(
merge(b"a", b"b", b""), merge(b"a", b"b", b""),
MergeResult::Conflict(vec![MergeHunk::Conflict { MergeResult::Conflict(vec![MergeHunk::Conflict {
base: b"a".to_vec(), removes: vec![b"a".to_vec()],
left: b"b".to_vec(), adds: vec![b"b".to_vec(), b"".to_vec()]
right: b"".to_vec()
}]) }])
); );
assert_eq!( assert_eq!(
merge(b"a", b"b", b"c"), merge(b"a", b"b", b"c"),
MergeResult::Conflict(vec![MergeHunk::Conflict { MergeResult::Conflict(vec![MergeHunk::Conflict {
base: b"a".to_vec(), removes: vec![b"a".to_vec()],
left: b"b".to_vec(), adds: vec![b"b".to_vec(), b"c".to_vec()]
right: b"c".to_vec()
}]) }])
); );
} }