diff --git a/server/unified_diff.py b/server/unified_diff.py index 9e21f1e0..adacd839 100644 --- a/server/unified_diff.py +++ b/server/unified_diff.py @@ -152,6 +152,13 @@ def append_file(old_path: str = "", new_path: str = "") -> dict[str, Any] | None old_remaining = max(0, old_remaining - 1) if prefix in {" ", "+"}: new_remaining = max(0, new_remaining - 1) + # The line cap bounds the rendered hunk lines only. File and patch + # totals still count every change, so a file after the cap is not + # listed as +0 / -0. + if prefix == "+": + current_file["additions"] += 1 + elif prefix == "-": + current_file["deletions"] += 1 if parsed_lines >= max_lines: truncated = True continue @@ -161,12 +168,10 @@ def append_file(old_path: str = "", new_path: str = "") -> dict[str, Any] | None kind = "add" line_item = {"kind": kind, "newLine": new_line, "text": text} new_line += 1 - current_file["additions"] += 1 elif prefix == "-": kind = "remove" line_item = {"kind": kind, "oldLine": old_line, "text": text} old_line += 1 - current_file["deletions"] += 1 elif prefix == " ": kind = "context" line_item = { diff --git a/tests/test_unified_diff_canvas.py b/tests/test_unified_diff_canvas.py index 2a1f5e23..bc0970a4 100644 --- a/tests/test_unified_diff_canvas.py +++ b/tests/test_unified_diff_canvas.py @@ -216,6 +216,43 @@ def test_parse_unified_diff_caps_files_without_merging_hunks() -> None: assert parsed["files"][0]["deletions"] == 1 +def test_parse_unified_diff_counts_changes_past_the_line_cap() -> None: + patch = "\n".join( + [ + "diff --git a/data.txt b/data.txt", + "--- a/data.txt", + "+++ b/data.txt", + "@@ -1,2 +1,3 @@", + " keep", + "-old", + "+new", + "+extra", + "diff --git a/app.py b/app.py", + "--- a/app.py", + "+++ b/app.py", + "@@ -1 +1 @@", + "-before", + "+after", + ] + ) + parsed = parse_unified_diff(patch, max_lines=2) + + assert parsed["truncated"] is True + assert parsed["lineCount"] == 2 + assert [(item["path"], item["additions"], item["deletions"]) for item in parsed["files"]] == [ + ("data.txt", 2, 1), + ("app.py", 1, 1), + ] + assert parsed["additions"] == 3 + assert parsed["deletions"] == 2 + data, app = parsed["files"] + assert data["hunks"][0]["lines"] == [ + {"kind": "context", "oldLine": 1, "newLine": 1, "text": "keep"}, + {"kind": "remove", "oldLine": 2, "text": "old"}, + ] + assert app["hunks"][0]["lines"] == [] + + def test_parse_unified_diff_splits_hunk_lines_only_at_newlines() -> None: parsed = parse_unified_diff( "diff --git a/app.py b/app.py\n" @@ -330,6 +367,7 @@ def test_parse_unified_diff_reads_copy_headers() -> None: test_parse_unified_diff_keeps_spaced_paths_without_marker_lines() test_diff_canvas_payload_keeps_report_for_local_mode_switch() test_parse_unified_diff_caps_files_without_merging_hunks() + test_parse_unified_diff_counts_changes_past_the_line_cap() test_parse_unified_diff_splits_hunk_lines_only_at_newlines() test_parse_unified_diff_reads_empty_lines_inside_hunks_as_blank_context() test_parse_unified_diff_reads_copy_headers()