Anchor match
anchor_match
Single owner of how a replace anchor is located in a file.
Both the engine (which applies edits) and the preflight (which predicts the
engine's verdict) resolve anchors through :func:resolve_anchor, so the
preflight can never block an anchor the engine would accept, nor let through
one the engine would refuse.
Resolution order, first hit wins:
- the anchor as authored, then each normalized variant (smart quotes turned straight, wrapping double quotes stripped);
- for each candidate, an exact line match, then an indent-normalized one;
- with a
linehint, the hint and ±5 lines around it first, then a full-file scan that only accepts a single match.
The whitespace model (:func:common_ws_prefix) is shared by indent
detection, dedenting and :func:reindent, so detection and re-application
always agree, tabs included.
AnchorMatch
dataclass
Where, and how, an anchor resolved in a file.
Attributes:
| Name | Type | Description |
|---|---|---|
status |
AnchorStatus
|
|
line |
int | None
|
1-indexed start line when found. |
indent |
str
|
Indent prefix to re-apply to |
old |
str
|
The anchor text that matched: the authored one, or the normalized variant. |
normalizations |
tuple[str, ...]
|
What had to be normalized for the match, in order
( |
hits |
tuple[int, ...]
|
Every candidate start line when ambiguous. |
Source code in packages/axm-edit/src/axm_edit/core/anchor_match.py
anchor_matches_at(lines, old, line)
Tell whether old still matches at line, exactly or indent-normalized.
Source code in packages/axm-edit/src/axm_edit/core/anchor_match.py
common_ws_prefix(lines)
Return the literal longest common leading-whitespace prefix.
The prefix is computed across non-empty lines and is treated as an opaque character sequence: tabs and spaces are compared by identity, so a tab never collapses into spaces (or vice versa).
Source code in packages/axm-edit/src/axm_edit/core/anchor_match.py
old_line_count(old)
reindent(text, indent)
Dedent text fully, then prepend indent to each non-empty line.
Relative indentation within the block is preserved; blank lines are kept verbatim.
Source code in packages/axm-edit/src/axm_edit/core/anchor_match.py
resolve_anchor(lines, old, hint_line)
Resolve old in lines, the file split by :func:split_lines.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
lines
|
Sequence[str]
|
File content as read, split by :func: |
required |
old
|
str
|
The anchor as authored. |
required |
hint_line
|
int | None
|
Optional 1-indexed line hint. |
required |
Returns:
| Type | Description |
|---|---|
AnchorMatch
|
The match, or why there is none: |
AnchorMatch
|
anchor matches several lines and no hint picks one, |
AnchorMatch
|
otherwise. |
Source code in packages/axm-edit/src/axm_edit/core/anchor_match.py
split_lines(text)
Split text after each \n only, keeping the line ends.
The one line model of every edit. Unlike :meth:str.splitlines, a form
feed, vertical tab, file separator or U+2028 stays inside its line, so an
anchor carrying one matches the file byte for byte.