Support CR line endings in apply_patch

This commit is contained in:
Charlie Marsh
2026-07-02 15:48:25 -04:00
parent 1403829fb5
commit fab3e245ff
2 changed files with 31 additions and 10 deletions

View File

@@ -4,6 +4,7 @@ pub(super) type Replacement = (usize, usize, Vec<String>);
enum LineEnding {
Lf,
CrLf,
Cr,
}
impl LineEnding {
@@ -11,6 +12,7 @@ impl LineEnding {
match self {
Self::Lf => "\n",
Self::CrLf => "\r\n",
Self::Cr => "\r",
}
}
}
@@ -34,20 +36,27 @@ impl SourceFile {
let mut lines = Vec::new();
let mut preferred_ending = None;
let mut line_start = 0;
let mut cursor = 0;
for (newline, _) in contents.match_indices('\n') {
let line = &contents[line_start..newline];
let (text, ending) = if let Some(text) = line.strip_suffix('\r') {
(text, LineEnding::CrLf)
} else {
(line, LineEnding::Lf)
while cursor < contents.len() {
let (ending, ending_len) = match contents.as_bytes()[cursor] {
b'\r' if contents.as_bytes().get(cursor + 1) == Some(&b'\n') => {
(LineEnding::CrLf, 2)
}
b'\r' => (LineEnding::Cr, 1),
b'\n' => (LineEnding::Lf, 1),
_ => {
cursor += 1;
continue;
}
};
preferred_ending.get_or_insert(ending);
lines.push(SourceLine {
text: text.to_string(),
text: contents[line_start..cursor].to_string(),
ending: Some(ending),
});
line_start = newline + 1;
cursor += ending_len;
line_start = cursor;
}
if line_start < contents.len() {

View File

@@ -96,6 +96,18 @@ fn test_apply_patch_cli_preserves_crlf_from_target_file() -> anyhow::Result<()>
)
}
#[test]
fn test_apply_patch_cli_preserves_cr_from_target_file() -> anyhow::Result<()> {
let patch = "*** Begin Patch\n*** Update File: cr.txt\n@@\n-one\n+uno\n@@\n two\n+\n+between\n three\n*** End Patch";
assert_apply_patch_updates_file(
"cr.txt",
b"one\rtwo\rthree\r",
patch,
b"uno\rtwo\r\rbetween\rthree\r",
)
}
#[test]
fn test_apply_patch_cli_preserves_change_order_with_repeated_lines() -> anyhow::Result<()> {
let patch =
@@ -118,9 +130,9 @@ fn test_apply_patch_cli_preserves_untouched_mixed_line_endings() -> anyhow::Resu
assert_apply_patch_updates_file(
"mixed.txt",
b"one\r\ntwo\nthree\r\nfour\n",
b"one\r\ntwo\rthree\nfour\r\n",
patch,
b"one\r\ntwo\nTHREE\r\nfour\n",
b"one\r\ntwo\rTHREE\r\nfour\r\n",
)
}