Parse a pseudo-patch file into structured hunks. Args: patch_content: The complete patch file content Returns: List of PatchHunk objects Raises: ValueError: If patch format is invalid
(patch_content: str)
| 72 | |
| 73 | |
| 74 | def _parse_patch_file(patch_content: str) -> List[PatchHunk]: |
| 75 | """ |
| 76 | Parse a pseudo-patch file into structured hunks. |
| 77 | |
| 78 | Args: |
| 79 | patch_content: The complete patch file content |
| 80 | |
| 81 | Returns: |
| 82 | List of PatchHunk objects |
| 83 | |
| 84 | Raises: |
| 85 | ValueError: If patch format is invalid |
| 86 | """ |
| 87 | lines = patch_content.split("\n") |
| 88 | hunks = [] |
| 89 | current_hunk = None |
| 90 | in_patch = False |
| 91 | |
| 92 | i = 0 |
| 93 | while i < len(lines): |
| 94 | line = lines[i] |
| 95 | |
| 96 | # Start of a patch block |
| 97 | if line.strip() == "*** Begin Patch": |
| 98 | in_patch = True |
| 99 | current_hunk = PatchHunk() |
| 100 | i += 1 |
| 101 | continue |
| 102 | |
| 103 | # End of a patch block |
| 104 | if line.strip() == "*** End Patch": |
| 105 | if current_hunk: |
| 106 | hunks.append(current_hunk) |
| 107 | current_hunk = None |
| 108 | in_patch = False |
| 109 | i += 1 |
| 110 | continue |
| 111 | |
| 112 | if not in_patch: |
| 113 | i += 1 |
| 114 | continue |
| 115 | |
| 116 | # Operation and file line: *** [Operation] File: [filepath] |
| 117 | if line.startswith("***") and "File:" in line: |
| 118 | match = re.match(r"\*\*\*\s*(\w+)\s+File:\s*(.+)$", line.strip()) |
| 119 | if match: |
| 120 | current_hunk.operation = match.group(1).strip() |
| 121 | current_hunk.filepath = match.group(2).strip() |
| 122 | i += 1 |
| 123 | continue |
| 124 | |
| 125 | # Search hint line: @@ some text @@ |
| 126 | if line.strip().startswith("@@"): |
| 127 | current_hunk.search_hint = line.strip().strip("@").strip() |
| 128 | i += 1 |
| 129 | continue |
| 130 | |
| 131 | # Parse hunk content (context, old, new lines) |