conflicts: show "noeol" state in conflict marker comment

This isn't strictly necessary since it doesn't affect parsing, but it
should make it more understandable for the user.
This commit is contained in:
Scott Taylor 2024-12-24 21:16:04 -06:00 committed by Scott Taylor
parent 326c453064
commit 66faeb4487
2 changed files with 56 additions and 17 deletions

View File

@ -58,6 +58,15 @@ pub const MIN_CONFLICT_MARKER_LEN: usize = 7;
/// existing markers.
const CONFLICT_MARKER_LEN_INCREMENT: usize = 4;
/// Comment for missing terminating newline in a term of a conflict.
const NO_EOL_COMMENT: &str = " [noeol]";
/// Comment for missing terminating newline in the "add" side of a diff.
const ADD_NO_EOL_COMMENT: &str = " [+noeol]";
/// Comment for missing terminating newline in the "remove" side of a diff.
const REMOVE_NO_EOL_COMMENT: &str = " [-noeol]";
fn write_diff_hunks(hunks: &[DiffHunk], file: &mut dyn Write) -> io::Result<()> {
for hunk in hunks {
match hunk.kind {
@ -460,7 +469,7 @@ fn materialize_git_style_conflict(
output,
ConflictMarkerLineChar::ConflictStart,
conflict_marker_len,
&format!("Side #1 ({conflict_info})"),
&format!("Side #1{} ({conflict_info})", maybe_no_eol_comment(left)),
)?;
write_and_ensure_newline(output, left)?;
@ -468,7 +477,7 @@ fn materialize_git_style_conflict(
output,
ConflictMarkerLineChar::GitAncestor,
conflict_marker_len,
"Base",
&format!("Base{}", maybe_no_eol_comment(base)),
)?;
write_and_ensure_newline(output, base)?;
@ -485,7 +494,10 @@ fn materialize_git_style_conflict(
output,
ConflictMarkerLineChar::ConflictEnd,
conflict_marker_len,
&format!("Side #2 ({conflict_info} ends)"),
&format!(
"Side #2{} ({conflict_info} ends)",
maybe_no_eol_comment(right)
),
)?;
Ok(())
@ -504,7 +516,11 @@ fn materialize_jj_style_conflict(
output,
ConflictMarkerLineChar::Add,
conflict_marker_len,
&format!("Contents of side #{}", add_index + 1),
&format!(
"Contents of side #{}{}",
add_index + 1,
maybe_no_eol_comment(data)
),
)?;
write_and_ensure_newline(output, data)
};
@ -515,7 +531,7 @@ fn materialize_jj_style_conflict(
output,
ConflictMarkerLineChar::Remove,
conflict_marker_len,
&format!("Contents of {base_str}"),
&format!("Contents of {base_str}{}", maybe_no_eol_comment(data)),
)?;
write_and_ensure_newline(output, data)
};
@ -523,11 +539,26 @@ fn materialize_jj_style_conflict(
// Write a diff from a negative term to a positive term
let write_diff =
|base_str: &str, add_index: usize, diff: &[DiffHunk], output: &mut dyn Write| {
let no_eol_remove = diff
.last()
.is_some_and(|diff_hunk| has_no_eol(diff_hunk.contents[0]));
let no_eol_add = diff
.last()
.is_some_and(|diff_hunk| has_no_eol(diff_hunk.contents[1]));
let no_eol_comment = match (no_eol_remove, no_eol_add) {
(true, true) => NO_EOL_COMMENT,
(true, _) => REMOVE_NO_EOL_COMMENT,
(_, true) => ADD_NO_EOL_COMMENT,
_ => "",
};
write_conflict_marker(
output,
ConflictMarkerLineChar::Diff,
conflict_marker_len,
&format!("Changes from {base_str} to side #{}", add_index + 1),
&format!(
"Changes from {base_str} to side #{}{no_eol_comment}",
add_index + 1
),
)?;
write_diff_hunks(diff, output)
};
@ -596,6 +627,14 @@ fn materialize_jj_style_conflict(
Ok(())
}
fn maybe_no_eol_comment(slice: &[u8]) -> &'static str {
if has_no_eol(slice) {
NO_EOL_COMMENT
} else {
""
}
}
// Write a chunk of data, ensuring that it doesn't end with a line which is
// missing its terminating newline.
fn write_and_ensure_newline(output: &mut dyn Write, data: &[u8]) -> io::Result<()> {

View File

@ -629,9 +629,9 @@ fn test_materialize_conflict_no_newlines_at_eof() {
insta::assert_snapshot!(materialized,
@r###"
<<<<<<< Conflict 1 of 1
%%%%%%% Changes from base to side #1
%%%%%%% Changes from base to side #1 [-noeol]
-base
+++++++ Contents of side #2
+++++++ Contents of side #2 [noeol]
right
>>>>>>> Conflict 1 of 1 ends
"###
@ -2057,7 +2057,7 @@ fn test_update_conflict_from_content_no_eol() {
+++++++ Contents of side #1
base
left
%%%%%%% Changes from base to side #2
%%%%%%% Changes from base to side #2 [noeol]
-base
+right
>>>>>>> Conflict 2 of 2 ends
@ -2096,9 +2096,9 @@ fn test_update_conflict_from_content_no_eol() {
+++++++ Contents of side #1
base
left
------- Contents of base
------- Contents of base [noeol]
base
+++++++ Contents of side #2
+++++++ Contents of side #2 [noeol]
right
>>>>>>> Conflict 2 of 2 ends
"##
@ -2134,11 +2134,11 @@ fn test_update_conflict_from_content_no_eol() {
<<<<<<< Side #1 (Conflict 2 of 2)
base
left
||||||| Base
||||||| Base [noeol]
base
=======
right
>>>>>>> Side #2 (Conflict 2 of 2 ends)
>>>>>>> Side #2 [noeol] (Conflict 2 of 2 ends)
"##
);
// Parse with "diff" markers to ensure the file is actually parsed
@ -2197,15 +2197,15 @@ fn test_update_conflict_from_content_no_eol_in_diff_hunk() {
<<<<<<< Conflict 1 of 1
+++++++ Contents of side #1
side
%%%%%%% Changes from base #1 to side #2
%%%%%%% Changes from base #1 to side #2 [-noeol]
add newline
-line
+line
%%%%%%% Changes from base #2 to side #3
%%%%%%% Changes from base #2 to side #3 [+noeol]
remove newline
-line
+line
%%%%%%% Changes from base #3 to side #4
%%%%%%% Changes from base #3 to side #4 [noeol]
no newline
-line 1
+line 2
@ -2253,7 +2253,7 @@ fn test_update_conflict_from_content_only_no_eol_change() {
@r##"
line 1
<<<<<<< Conflict 1 of 1
%%%%%%% Changes from base to side #1
%%%%%%% Changes from base to side #1 [+noeol]
+line 2
+++++++ Contents of side #2
line 2