diff --git a/src/git/merging.rs b/src/git/merging.rs index 300faff..54c829a 100644 --- a/src/git/merging.rs +++ b/src/git/merging.rs @@ -146,11 +146,16 @@ fn marker(line: &str, mark: char, size: usize, labelled: bool) -> bool { run == size && (line.len() == size || (labelled && line[size..].starts_with(' '))) } +/// Lines as Git splits them: at LF only. +fn git_lines(text: &str) -> Vec<&str> { + text.split_inclusive('\n').collect() +} + /// The conflicts marked in `text` with markers `size` wide. pub fn conflicts(text: &str, size: usize) -> Vec { let mut found = Vec::new(); let (mut start, mut base, mut middle) = (None, None, None); - for (ix, line) in text.tokenize_lines().into_iter().enumerate() { + for (ix, line) in git_lines(text).into_iter().enumerate() { if marker(line, '<', size, true) { (start, base, middle) = (Some(ix), None, None); } else if marker(line, '|', size, true) && start.is_some() && middle.is_none() { @@ -173,11 +178,7 @@ pub fn conflicts(text: &str, size: usize) -> Vec { /// Regions as Git grouped marked `text`; base from diff3. pub fn marked(text: &str, size: usize) -> Vec { - let lines: Vec = text - .tokenize_lines() - .into_iter() - .map(str::to_string) - .collect(); + let lines: Vec = git_lines(text).into_iter().map(str::to_string).collect(); let same = |range: std::ops::Range| Region { kind: RegionKind::Unchanged, base: lines[range.clone()].to_vec(), @@ -213,7 +214,7 @@ pub fn resolve(text: &str, ix: usize, take: Take, size: usize) -> Option log::error!("no conflict {ix} to resolve in this text"); return None; }; - let lines = text.tokenize_lines(); + let lines = git_lines(text); // A diff3 conflict's base section is neither side. let ours = lines[conflict.start + 1..conflict.base.unwrap_or(conflict.middle)].concat(); let theirs = lines[conflict.middle + 1..conflict.end].concat(); @@ -324,10 +325,6 @@ mod tests { assert_eq!(result(&changed, &[]).0, "a\rB\n"); let held = result(®ions("a\r", "b\r", "c\r"), &[]).0; assert_eq!(held, "<<<<<<< ours\rb\r=======\rc\r>>>>>>> theirs\r"); - assert_eq!( - resolve(&held, 0, Take::Theirs, MARKER).as_deref(), - Some("c\r") - ); assert_eq!( resolve("plain\n", 0, Take::Ours, MARKER), None, @@ -335,6 +332,20 @@ mod tests { ); } + #[test] + fn git_markers_split_at_lf_only() { + let text = "<<<<<<< HEAD\nprefix\r=======\rOURS_END\n=======\nTHEIRS\n>>>>>>> side\n"; + assert_eq!( + resolve(text, 0, Take::Theirs, MARKER).as_deref(), + Some("THEIRS\n") + ); + assert_eq!( + marked(text, MARKER)[0].ours, + ["prefix\r=======\rOURS_END\n"] + ); + assert!(conflicts("<<<<<<< a\rb\r=======\rc\r>>>>>>> d\r", MARKER).is_empty()); + } + #[test] fn taking_both_adds_no_line_to_an_empty_side() { assert_eq!(result(®ions("a", "b", ""), &[Some(Take::Both)]).0, "b");