ep: Allow matching patches against files without trailing newlines (#46357)

Oleksiy Syvokon created

A proper fix would be to add `\No trailing newline` marker and handle
it. For now, we do a simpler workaround

Release Notes:

- N/A

Change summary

crates/edit_prediction/src/zeta2.rs | 18 +++++++++++++++++-
1 file changed, 17 insertions(+), 1 deletion(-)

Detailed changes

crates/edit_prediction/src/zeta2.rs 🔗

@@ -285,7 +285,23 @@ pub fn zeta2_output_for_patch(input: &zeta_prompt::ZetaPromptInput, patch: &str)
     let old_prefix = &text[..editable_region.start];
     let old_suffix = &text[editable_region.end..];
 
-    let new = crate::udiff::apply_diff_to_string(patch, text)?;
+    // Try applying the patch directly first
+    let new = match crate::udiff::apply_diff_to_string(patch, text) {
+        Ok(new) => new,
+        Err(_) if !text.ends_with('\n') => {
+            // If the text doesn't end with a newline, the patch context may expect one
+            // (due to missing "no newline at EOF" markers). Try again with a trailing newline.
+            let text_with_newline = format!("{}\n", text);
+            let mut new = crate::udiff::apply_diff_to_string(patch, &text_with_newline)?;
+            // Remove the trailing newline we added if the result still has it
+            if new.ends_with('\n') && !text.ends_with('\n') {
+                new.pop();
+            }
+            new
+        }
+        Err(e) => return Err(e),
+    };
+
     if !new.starts_with(old_prefix) || !new.ends_with(old_suffix) {
         anyhow::bail!("Patch shouldn't affect text outside of editable region");
     }