diff --git a/lib/src/conflicts.rs b/lib/src/conflicts.rs index 4d139e235..44557c768 100644 --- a/lib/src/conflicts.rs +++ b/lib/src/conflicts.rs @@ -20,6 +20,7 @@ use std::io::Write; use std::iter::zip; use bstr::BString; +use bstr::ByteSlice; use futures::stream::BoxStream; use futures::try_join; use futures::Stream; @@ -394,7 +395,7 @@ pub fn parse_conflict(input: &[u8], num_sides: usize) -> Option Merge { let mut removes = vec![]; let mut adds = vec![]; for line in input.split_inclusive(|b| *b == b'\n') { - if CONFLICT_MARKER_REGEX.is_match_at(line, 0) { + if is_conflict_marker_line(line) { match line[0] { CONFLICT_DIFF_LINE_CHAR => { state = State::Diff; @@ -492,6 +493,13 @@ fn parse_conflict_hunk(input: &[u8]) -> Merge { } } +/// Check whether a line is a conflict marker. Removes trailing whitespace +/// before checking against regex to ensure it parses CRLF endings correctly. +fn is_conflict_marker_line(line: &[u8]) -> bool { + let line = line.trim_end_with(|ch| ch.is_ascii_whitespace()); + CONFLICT_MARKER_REGEX.is_match_at(line, 0) +} + /// Parses conflict markers in `content` and returns an updated version of /// `file_ids` with the new contents. If no (valid) conflict markers remain, a /// single resolves `FileId` will be returned. diff --git a/lib/tests/test_conflicts.rs b/lib/tests/test_conflicts.rs index 8534f817e..126d879d6 100644 --- a/lib/tests/test_conflicts.rs +++ b/lib/tests/test_conflicts.rs @@ -727,8 +727,8 @@ fn test_parse_conflict_multi_way() { #[test] fn test_parse_conflict_crlf_markers() { - // Conflict markers aren't recognized due to CRLF - assert_eq!( + // Conflict markers should be recognized even with CRLF + insta::assert_debug_snapshot!( parse_conflict( indoc! {b" line 1\r @@ -744,7 +744,25 @@ fn test_parse_conflict_crlf_markers() { "}, 2 ), - None + @r#" + Some( + [ + Resolved( + "line 1\r\n", + ), + Conflicted( + [ + "left\r\n", + "base\r\n", + "right\r\n", + ], + ), + Resolved( + "line 5\r\n", + ), + ], + ) + "# ); }