Apply sorted, validated edits by streaming to a temp file. Line numbers are 1-based. Edits use inclusive 'to'. Inserts have 'insert': True. Returns total line count after patching.
(path: str, edits: list[dict])
| 279 | |
| 280 | |
| 281 | def apply_patch(path: str, edits: list[dict]) -> int: |
| 282 | """ |
| 283 | Apply sorted, validated edits by streaming to a temp file. |
| 284 | |
| 285 | Line numbers are 1-based. Edits use inclusive 'to'. |
| 286 | Inserts have 'insert': True. |
| 287 | Returns total line count after patching. |
| 288 | """ |
| 289 | # Ensure content always ends with newline to prevent line merging |
| 290 | for e in edits: |
| 291 | if e["content"] and not e["content"].endswith("\n"): |
| 292 | e["content"] += "\n" |
| 293 | |
| 294 | dir_name = os.path.dirname(path) or "." |
| 295 | fd, tmp_path = tempfile.mkstemp(dir=dir_name, suffix=".tmp") |
| 296 | try: |
| 297 | with ( |
| 298 | open(path, "r", encoding="utf-8", errors="replace") as src, |
| 299 | os.fdopen(fd, "w", encoding="utf-8") as dst, |
| 300 | ): |
| 301 | edit_idx = 0 |
| 302 | line_no = 1 # 1-based |
| 303 | total_written = 0 |
| 304 | |
| 305 | for raw_line in src: |
| 306 | # Process all inserts targeting this line first |
| 307 | while ( |
| 308 | edit_idx < len(edits) |
| 309 | and edits[edit_idx]["insert"] |
| 310 | and edits[edit_idx]["from"] == line_no |
| 311 | ): |
| 312 | edit = edits[edit_idx] |
| 313 | if edit["content"]: |
| 314 | dst.write(edit["content"]) |
| 315 | total_written += _count_content_lines(edit["content"]) |
| 316 | edit_idx += 1 |
| 317 | |
| 318 | # Check if current line falls in a replace/delete range |
| 319 | if edit_idx < len(edits) and not edits[edit_idx]["insert"]: |
| 320 | edit = edits[edit_idx] |
| 321 | if edit["from"] <= line_no <= edit["to"]: |
| 322 | # Write replacement content once at range start |
| 323 | if line_no == edit["from"] and edit["content"]: |
| 324 | dst.write(edit["content"]) |
| 325 | total_written += _count_content_lines( |
| 326 | edit["content"] |
| 327 | ) |
| 328 | # Skip original line; advance edit at range end |
| 329 | if line_no == edit["to"]: |
| 330 | edit_idx += 1 |
| 331 | line_no += 1 |
| 332 | continue |
| 333 | |
| 334 | dst.write(raw_line) |
| 335 | total_written += 1 |
| 336 | line_no += 1 |
| 337 | |
| 338 | # Remaining edits past end of file |
no test coverage detected