diff --git a/lib/src/conflicts.rs b/lib/src/conflicts.rs index 958d96ed48..3c81ae3974 100644 --- a/lib/src/conflicts.rs +++ b/lib/src/conflicts.rs @@ -377,7 +377,29 @@ pub fn materialized_diff_stream<'a>( /// they don't have the expected arity. // TODO: "parse" is not usually the opposite of "materialize", so maybe we // should rename them to "serialize" and "deserialize"? -pub fn parse_conflict(input: &[u8], num_sides: usize) -> Option>> { +pub fn parse_merge_result(input: &[u8], num_sides: usize) -> Option> { + let hunks = parse_conflict_into_list_of_hunks(input, num_sides)?; + let mut result: Merge = Merge::from_vec(vec![vec![].into(); num_sides * 2 - 1]); + + for hunk in hunks { + if let Some(slice) = hunk.as_resolved() { + for content in result.iter_mut() { + content.extend_from_slice(slice); + } + } else { + for (content, slice) in zip(result.iter_mut(), hunk.into_iter()) { + content.extend(Vec::from(slice)); + } + } + } + + Some(result) +} + +fn parse_conflict_into_list_of_hunks( + input: &[u8], + num_sides: usize, +) -> Option>> { if input.is_empty() { return None; } @@ -513,13 +535,13 @@ pub async fn update_from_content( // conflicts initially. If unsuccessful, attempt to parse conflicts from with // the arity of the unsimplified conflicts since such a conflict may be // present in the working copy if written by an earlier version of jj. - let (used_file_ids, hunks) = 'hunks: { - if let Some(hunks) = parse_conflict(content, simplified_file_ids.num_sides()) { - break 'hunks (simplified_file_ids, hunks); + let (used_file_ids, contents) = 'hunks: { + if let Some(contents) = parse_merge_result(content, simplified_file_ids.num_sides()) { + break 'hunks (simplified_file_ids, contents); }; if simplified_file_ids.num_sides() != file_ids.num_sides() { - if let Some(hunks) = parse_conflict(content, file_ids.num_sides()) { - break 'hunks (file_ids, hunks); + if let Some(contents) = parse_merge_result(content, file_ids.num_sides()) { + break 'hunks (file_ids, contents); }; }; // Either there are no markers or they don't have the expected arity @@ -527,19 +549,6 @@ pub async fn update_from_content( return Ok(Merge::normal(file_id)); }; - let mut contents = used_file_ids.map(|_| vec![]); - for hunk in hunks { - if let Some(slice) = hunk.as_resolved() { - for content in contents.iter_mut() { - content.extend_from_slice(slice); - } - } else { - for (content, slice) in zip(contents.iter_mut(), hunk.into_iter()) { - content.extend(Vec::from(slice)); - } - } - } - // If the user edited the empty placeholder for an absent side, we consider the // conflict resolved. if zip(contents.iter(), used_file_ids.iter()) diff --git a/lib/tests/test_conflicts.rs b/lib/tests/test_conflicts.rs index 75066a94e3..284774455f 100644 --- a/lib/tests/test_conflicts.rs +++ b/lib/tests/test_conflicts.rs @@ -16,7 +16,7 @@ use indoc::indoc; use jj_lib::backend::FileId; use jj_lib::conflicts::extract_as_single_hunk; use jj_lib::conflicts::materialize_merge_result; -use jj_lib::conflicts::parse_conflict; +use jj_lib::conflicts::parse_merge_result; use jj_lib::conflicts::update_from_content; use jj_lib::merge::Merge; use jj_lib::repo::Repo; @@ -313,28 +313,16 @@ fn test_materialize_parse_roundtrip() { // The first add should always be from the left side insta::assert_debug_snapshot!( - parse_conflict(materialized.as_bytes(), conflict.num_sides()), + parse_merge_result(materialized.as_bytes(), conflict.num_sides()), @r###" Some( - [ - Conflicted( - [ - "line 1 left\nline 2 left\n", - "line 1\nline 2\n", - "line 1 right\nline 2\n", - ], - ), - Resolved( - "line 3\n", - ), - Conflicted( - [ - "line 4\nline 5 left\n", - "line 4\nline 5\n", - "line 4 right\nline 5 right\n", - ], - ), - ], + Conflicted( + [ + "line 1 left\nline 2 left\nline 3\nline 4\nline 5 left\n", + "line 1\nline 2\nline 3\nline 4\nline 5\n", + "line 1 right\nline 2\nline 3\nline 4 right\nline 5 right\n", + ], + ), ) "###); } @@ -363,7 +351,7 @@ fn test_materialize_conflict_no_newlines_at_eof() { "### ); // BUG(#3968): These conflict markers cannot be parsed - insta::assert_debug_snapshot!(parse_conflict( + insta::assert_debug_snapshot!(parse_merge_result( materialized.as_bytes(), conflict.num_sides() ),@"None"); @@ -524,7 +512,7 @@ fn test_materialize_conflict_two_forward_diffs() { #[test] fn test_parse_conflict_resolved() { assert_eq!( - parse_conflict( + parse_merge_result( indoc! {b" line 1 line 2 @@ -541,7 +529,7 @@ line 5 #[test] fn test_parse_conflict_simple() { insta::assert_debug_snapshot!( - parse_conflict(indoc! {b" + parse_merge_result(indoc! {b" line 1 <<<<<<< %%%%%%% @@ -558,26 +546,18 @@ fn test_parse_conflict_simple() { ), @r###" Some( - [ - Resolved( - "line 1\n", - ), - Conflicted( - [ - "line 2\nleft\nline 4\n", - "line 2\nline 3\nline 4\n", - "right\n", - ], - ), - Resolved( - "line 5\n", - ), - ], + Conflicted( + [ + "line 1\nline 2\nleft\nline 4\nline 5\n", + "line 1\nline 2\nline 3\nline 4\nline 5\n", + "line 1\nright\nline 5\n", + ], + ), ) "### ); insta::assert_debug_snapshot!( - parse_conflict(indoc! {b" + parse_merge_result(indoc! {b" line 1 <<<<<<< Text %%%%%%% Different text @@ -594,28 +574,20 @@ fn test_parse_conflict_simple() { ), @r###" Some( - [ - Resolved( - "line 1\n", - ), - Conflicted( - [ - "line 2\nleft\nline 4\n", - "line 2\nline 3\nline 4\n", - "right\n", - ], - ), - Resolved( - "line 5\n", - ), - ], + Conflicted( + [ + "line 1\nline 2\nleft\nline 4\nline 5\n", + "line 1\nline 2\nline 3\nline 4\nline 5\n", + "line 1\nright\nline 5\n", + ], + ), ) "### ); // The conflict markers are too long and shouldn't parse (though we may // decide to change this in the future) insta::assert_debug_snapshot!( - parse_conflict(indoc! {b" + parse_merge_result(indoc! {b" line 1 <<<<<<<<<<< %%%%%%%%%%% @@ -637,7 +609,7 @@ fn test_parse_conflict_simple() { #[test] fn test_parse_conflict_multi_way() { insta::assert_debug_snapshot!( - parse_conflict( + parse_merge_result( indoc! {b" line 1 <<<<<<< @@ -660,28 +632,20 @@ fn test_parse_conflict_multi_way() { ), @r###" Some( - [ - Resolved( - "line 1\n", - ), - Conflicted( - [ - "line 2\nleft\nline 4\n", - "line 2\nline 3\nline 4\n", - "right\n", - "line 2\nline 3\nline 4\n", - "line 2\nforward\nline 3\nline 4\n", - ], - ), - Resolved( - "line 5\n", - ), - ], + Conflicted( + [ + "line 1\nline 2\nleft\nline 4\nline 5\n", + "line 1\nline 2\nline 3\nline 4\nline 5\n", + "line 1\nright\nline 5\n", + "line 1\nline 2\nline 3\nline 4\nline 5\n", + "line 1\nline 2\nforward\nline 3\nline 4\nline 5\n", + ], + ), ) "### ); insta::assert_debug_snapshot!( - parse_conflict(indoc! {b" + parse_merge_result(indoc! {b" line 1 <<<<<<< Random text %%%%%%% Random text @@ -703,23 +667,15 @@ fn test_parse_conflict_multi_way() { ), @r###" Some( - [ - Resolved( - "line 1\n", - ), - Conflicted( - [ - "line 2\nleft\nline 4\n", - "line 2\nline 3\nline 4\n", - "right\n", - "line 2\nline 3\nline 4\n", - "line 2\nforward\nline 3\nline 4\n", - ], - ), - Resolved( - "line 5\n", - ), - ], + Conflicted( + [ + "line 1\nline 2\nleft\nline 4\nline 5\n", + "line 1\nline 2\nline 3\nline 4\nline 5\n", + "line 1\nright\nline 5\n", + "line 1\nline 2\nline 3\nline 4\nline 5\n", + "line 1\nline 2\nforward\nline 3\nline 4\nline 5\n", + ], + ), ) "### ); @@ -729,7 +685,7 @@ fn test_parse_conflict_multi_way() { fn test_parse_conflict_wrong_arity() { // Valid conflict marker but it has fewer sides than the caller expected assert_eq!( - parse_conflict( + parse_merge_result( indoc! {b" line 1 <<<<<<< @@ -753,7 +709,7 @@ fn test_parse_conflict_wrong_arity() { fn test_parse_conflict_malformed_missing_removes() { // Right number of adds but missing removes assert_eq!( - parse_conflict( + parse_merge_result( indoc! {b" line 1 <<<<<<< @@ -774,7 +730,7 @@ fn test_parse_conflict_malformed_missing_removes() { fn test_parse_conflict_malformed_marker() { // The conflict marker is missing `%%%%%%%` assert_eq!( - parse_conflict( + parse_merge_result( indoc! {b" line 1 <<<<<<< @@ -797,7 +753,7 @@ fn test_parse_conflict_malformed_marker() { fn test_parse_conflict_malformed_diff() { // The diff part is invalid (missing space before "line 4") assert_eq!( - parse_conflict( + parse_merge_result( indoc! {b" line 1 <<<<<<<