diff --git a/gptdiff/applydiff.py b/gptdiff/applydiff.py index f5bd51d..b066e03 100644 --- a/gptdiff/applydiff.py +++ b/gptdiff/applydiff.py @@ -96,8 +96,19 @@ def apply_patch_to_file(file_path, patch): # Addition line: add to new_lines. new_lines.append(pline[1:] + "\n") else: - print("Unexpected line in hunk:", pline) - return False + # Some diffs (especially LLM-generated) omit the leading space on + # context lines. Treat bare lines as context when they match the + # original file to make patch application more forgiving. + expected = pline + if current_index >= len(original_lines): + print("Context line expected but file ended") + return False + orig_line = original_lines[current_index].rstrip("\n") + if orig_line != expected: + print("Context line mismatch. Expected:", expected, "Got:", orig_line) + return False + new_lines.append(original_lines[current_index]) + current_index += 1 i += 1 else: # Skip non-hunk header lines. diff --git a/tests/test_applydiff_edgecases.py b/tests/test_applydiff_edgecases.py index 50d57cd..377e34b 100644 --- a/tests/test_applydiff_edgecases.py +++ b/tests/test_applydiff_edgecases.py @@ -141,6 +141,30 @@ def test_diff_with_whitespace_changes(tmp_project_dir): assert "line2 " in content, "Whitespace change should be reflected in the file" +def test_diff_without_context_prefixes(tmp_project_dir): + """ + Diffs generated by LLMs sometimes omit the leading space on context lines. + Ensure we still treat those lines as context when they match the file. + """ + file = tmp_project_dir / "example.txt" + file.write_text("line1\nline2\nline3\n") + diff_text = ( + "diff --git a/example.txt b/example.txt\n" + "--- a/example.txt\n" + "+++ a/example.txt\n" + "@@ -1,3 +1,3 @@\n" + "line1\n" + "-line2\n" + "+line2 updated\n" + "line3\n" + ) + + result = apply_diff(str(tmp_project_dir), diff_text) + + assert result is True, "Diff without context prefixes should still apply" + assert file.read_text() == "line1\nline2 updated\nline3\n" + + def test_diff_file_deletion_edge(tmp_project_dir): """ Test deletion diff for a file with minimal content.