apply — executing edits on a text body
apply_edits(text, &edits) is the pure executor: given a text body and the
flat list of Edits the parser produced, it returns the
post-edit text. No filesystem, no I/O — input in, output out.
pub fn apply_edits(text: &str, edits: &[Edit]) -> ApplyResult
How it applies
Edits are bucketed by anchor line and applied bottom-up (highest line first), so earlier anchors are never shifted out from under later ones:
Why bottom-up application: If we applied edits from top to bottom, deleting or inserting lines would shift the line numbers of subsequent edits, causing them to target the wrong lines. By applying from bottom to top, we ensure that earlier edits (with lower line numbers) are never affected by the line shifts caused by later edits. This guarantees that each edit targets exactly the lines it was intended to modify.
- Boundary-balance repair runs first (see below).
insert head:rows are collected and spliced at the top;insert tail:rows at the bottom (respecting a trailing-newline sentinel line).- Each anchor line gets its bucket applied:
beforeinserts above, replacement rows in place of the line (when deleted), the original line kept when not deleted,afterinserts below.
An empty edit list returns the input unchanged with first_changed_line: None — the no-op signal the patcher uses to reject “Edits to X resulted in
no changes being made.”
Errors
- Out-of-bounds anchor — panics:
Line N does not exist (file has M lines). (The patcher surfaces this as a boxed error; the panic form is whatapply_editsitself does, matching the “pure function” contract.) - Unresolved
Blockedit — panics:internal error: unresolved \replace block` edit reached the applier (resolve_block_edits was not run).Block edits must be expanded by [resolve_block_edits`](block.md) first; hitting this is a wiring bug.
Boundary-balance repair
Models routinely miscount a replacement range’s edges. The payload either
restates a closing delimiter that still lives just outside the range
(producing a duplicate } / ); / ]) or the range deletes a closer
the payload never restates. Both leave the file syntactically broken, and
both are the same defect: a replacement whose payload does not preserve the
deleted region’s delimiter balance.
apply_edits therefore repairs the boundary before applying, but only
under strict conditions — a repair fires when:
- the payload’s delimiter balance differs from the deleted region’s, and
- one boundary operation (dropping an exact multi-line boundary echo or a single pure structural-closer line, or sparing a deleted pure structural-closer line) drives the difference to exactly zero while leaving the surrounding text byte-identical.
Each repair emits a warning so the caller knows content was adjusted:
Auto-repaired a delimiter-balance mismatch in the replacement at line N: dropped 1 duplicated trailing payload line(s) already present below the range. Issue the payload as the final desired content only — never restate or omit a closing bracket bordering the range.
Balance-preserving edits are left strictly alone, and content lines are never moved or lost — only duplicated closers dropped or deleted closers spared.
PatchSection::apply_to — the convenient path
For callers who have already validated the file content and just want the
result, PatchSection::apply_to ties the whole pure pipeline
together: parse (cached) → resolve blocks (with your
BlockResolver) → apply. apply_partial_to is the
streaming-tolerant counterpart: it parses with the tolerant parser and
drops unresolvable blocks instead of throwing, so a half-written file does
not blow up a live preview.
Summary
apply_edits(text, &edits)is the pure executor: given text body and flat list of edits, returns post-edit text (no filesystem, no I/O).- Application order: edits bucketed by anchor line and applied bottom-up (highest line first) so earlier anchors never shift out from under later ones.
- Boundary-balance repair: automatically fixes delimiter mismatches when payload’s delimiter balance differs from deleted region’s, under strict conditions (one boundary operation drives difference to zero).
- Repair fires when: payload delimiter balance ≠ deleted region balance AND one boundary operation (dropping duplicated closer or sparing deleted closer) drives difference to zero while keeping surrounding text byte-identical.
- Errors: out-of-bounds anchor (panic: “Line N does not exist”), unresolved
Blockedit (panic: “internal error: unresolved replace block edit reached the applier”). PatchSection::apply_tois the convenient path tying pure pipeline together (parse → resolve blocks → apply);apply_partial_tois streaming-tolerant (tolerant parser, drops unresolvable blocks).