zeta_prompt: Fix multy-hunk diff application (#55613)

Release Notes:

- N/A or Added/Fixed/Improved ...
This commit is contained in:
Oleksiy Syvokon authored and GitHub committed 2026-05-04 10:01:12 +00:00
1 parent 84d855d772
commit 5d51b35910
1 file changed
+56 -2
+56 -2
View File
@@ -415,6 +415,7 @@ pub fn apply_diff_to_string_with_hunk_offset(
let mut text = text.to_string();
let mut first_hunk_offset = None;
let mut line_delta = 0i64;
while let Some(event) = diff.next().context("Failed to parse diff")? {
match event {
@@ -424,9 +425,12 @@ pub fn apply_diff_to_string_with_hunk_offset(
status: _,
} => {
let candidates = find_context_candidates(&text, &mut hunk);
let adjusted_start_line = hunk
.start_line
.and_then(|start_line| u32::try_from(start_line as i64 + line_delta).ok());
let hunk_offset =
disambiguate_by_line_number(&candidates, hunk.start_line, &|offset| {
disambiguate_by_line_number(&candidates, adjusted_start_line, &|offset| {
text[..offset].matches('\n').count() as u32
})
.ok_or_else(|| anyhow!("couldn't resolve hunk"))?;
@@ -435,12 +439,19 @@ pub fn apply_diff_to_string_with_hunk_offset(
first_hunk_offset = Some(hunk_offset);
}
let mut hunk_line_delta = 0i64;
for edit in hunk.edits.iter().rev() {
let range = (hunk_offset + edit.range.start)..(hunk_offset + edit.range.end);
let deleted_lines = text[range.clone()].matches('\n').count() as i64;
let inserted_lines = edit.text.matches('\n').count() as i64;
text.replace_range(range, &edit.text);
hunk_line_delta += inserted_lines - deleted_lines;
}
line_delta += hunk_line_delta;
}
DiffEvent::FileEnd { .. } => {
line_delta = 0;
}
DiffEvent::FileEnd { .. } => {}
}
}
@@ -1315,6 +1326,49 @@ mod tests {
assert_eq!(result, "hello\nworld");
}
#[test]
fn test_apply_diff_to_string_adjusts_line_numbers_after_prior_hunks() {
let text = "first\nremove first\nfirst\nsame\nremove\nsame\nsame\nremove\nsame\n";
let diff = indoc! {"
--- a/file.txt
+++ b/file.txt
@@ -1,3 +1,2 @@
first
-remove first
first
@@ -4,3 +3,2 @@
same
-remove
same
"};
let result = apply_diff_to_string(diff, text).unwrap();
assert_eq!(result, "first\nfirst\nsame\nsame\nsame\nremove\nsame\n");
}
#[test]
fn test_apply_diff_to_string_adjusts_line_numbers_after_prior_insertion_hunks() {
let text = "first\nfirst\nsame\nremove\nsame\nsame\nremove\nsame\n";
let diff = indoc! {"
--- a/file.txt
+++ b/file.txt
@@ -1,2 +1,3 @@
first
+inserted
first
@@ -6,3 +7,2 @@
same
-remove
same
"};
let result = apply_diff_to_string(diff, text).unwrap();
assert_eq!(
result,
"first\ninserted\nfirst\nsame\nremove\nsame\nsame\nsame\n"
);
}
#[test]
fn test_find_context_candidates_no_false_positive_mid_text() {
// The stripped fallback must only match at the end of text, not in