Liking cljdoc? Tell your friends :D

com.blockether.vis.internal.foundation.editing.patch

Fuzzy line-based matching toolkit used by patch exact-replace.

This namespace USED to also carry the Codex apply_patch envelope parser, but envelope mode was retired — we consolidated to a single per-intent mutation surface (patch exact-replace + write / move / delete). The fuzzy matcher stays because it is what lets multi-line :search blocks tolerate whitespace and typographic drift before they fall through to :no-match.

Public surface (all pure): seek-sequence lines pattern start eof? -> start-index or nil seek-sequence-with-pass lines pattern start eof? -> {:start :pass :indent-delta?} or nil split-content-lines string -> vec of lines (no trailing \n element) char-offset-at-line content line-idx -> char offset apply-indent-delta delta lines -> re-indented lines

It also owns the reusable HASHLINE layer (content-addressed editing): line-hash / lines->anchors text -> 6-hex anchor / {ln hash} render-hashline-block / -range-block tuples -> <hash>| text gutter indices-matching-hash / resolve-anchor-edit self-locating range replace

Fuzzy line-based matching toolkit used by `patch` exact-replace.

This namespace USED to also carry the Codex `apply_patch` envelope
parser, but envelope mode was retired — we consolidated to a single
per-intent mutation surface (`patch` exact-replace + `write` /
`move` / `delete`). The fuzzy matcher stays because it is what
lets multi-line `:search` blocks tolerate whitespace and typographic
drift before they fall through to `:no-match`.

Public surface (all pure):
  seek-sequence            lines pattern start eof? -> start-index or nil
  seek-sequence-with-pass  lines pattern start eof?
                           -> {:start :pass :indent-delta?} or nil
  split-content-lines      string -> vec of lines (no trailing \n element)
  char-offset-at-line      content line-idx -> char offset
  apply-indent-delta       delta lines -> re-indented lines

It also owns the reusable HASHLINE layer (content-addressed editing):
  line-hash / lines->anchors              text -> 6-hex anchor / {ln hash}
  render-hashline-block / -range-block   tuples -> `<hash>| text` gutter
  indices-matching-hash / resolve-anchor-edit  self-locating range replace
raw docstring

anchor->lineclj

(anchor->line anchor)

Parse the line number out of a <lineno>:<hash> anchor.

Parse the line number out of a `<lineno>:<hash>` anchor.
sourceraw docstring

anchor-map->tuplesclj

(anchor-map->tuples m)

Inverse of lines->anchor-map: {anchor text}[[ln text]…] tuples, line number parsed from each <lineno>:<hash> key, sorted by line. For the channel/human gutter and any internal consumer that still wants tuples.

Inverse of `lines->anchor-map`: `{anchor text}` → `[[ln text]…]` tuples,
line number parsed from each `<lineno>:<hash>` key, sorted by line. For the
channel/human gutter and any internal consumer that still wants tuples.
sourceraw docstring

apply-indent-deltaclj

(apply-indent-delta delta lines)

Re-indent lines by delta leading spaces (positive adds, negative strips). Blank lines untouched. Used by exact-replace when a fuzzy :relative-indent hit fires and the replace payload must follow the file's actual indentation rather than the SEARCH block's.

Re-indent `lines` by `delta` leading spaces (positive adds, negative
strips). Blank lines untouched. Used by exact-replace when a fuzzy
:relative-indent hit fires and the `replace` payload must follow the
file's actual indentation rather than the SEARCH block's.
sourceraw docstring

char-offset-at-lineclj

(char-offset-at-line content line-idx)

Char offset in content where 0-based line line-idx starts. Returns (count content) if line-idx reaches past the last line. Public so the exact-replace path can map line indices back to char positions for substring splicing.

Char offset in `content` where 0-based line `line-idx` starts.
Returns `(count content)` if `line-idx` reaches past the last line.
Public so the exact-replace path can map line indices back to char
positions for substring splicing.
sourceraw docstring

hash-line-drift-toleranceclj

How far (in lines) a content hash may sit from its stated line number before resolve-one-anchor calls the anchor MISPLACED and refuses. The common path never needs it — within one patch batch every hunk resolves against the file's ORIGINAL snapshot, so the stated line number is exact and the fast path fires. This window only forgives small drift when the model reuses anchors across patch calls without re-reading; anything larger (the ~200-line gap of a genuinely wrong/stale anchor — the corruption this whole scheme exists to stop) is refused so the model re-reads. Deliberately tight: a false refuse costs one re-read, a false accept corrupts the file.

How far (in lines) a content hash may sit from its stated line number
before `resolve-one-anchor` calls the anchor MISPLACED and refuses. The
common path never needs it — within one patch batch every hunk resolves
against the file's ORIGINAL snapshot, so the stated line number is exact and
the fast path fires. This window only forgives small drift when the model
reuses anchors across patch calls without re-reading; anything larger (the
~200-line gap of a genuinely wrong/stale anchor — the corruption this whole
scheme exists to stop) is refused so the model re-reads. Deliberately tight:
a false refuse costs one re-read, a false accept corrupts the file.
sourceraw docstring

hash-widthclj

Hex chars in a line's content hash. Anchors now carry the LINE NUMBER too (<lineno>:<hash> — see line-anchor / lines->anchors), so the hash no longer has to be globally unique: the line number LOCATES the line and the hash only VERIFIES the content there (drift + misattribution). That collapses the hash's job from whole-file disambiguation — which forced width 4 / 65536 buckets back when the hash was the SOLE anchor (see git history for the old collision-vs-token table) — to a local check inside a hash-line-drift-tolerance-sized window. 3 hex (4096 buckets) is ample there: the residual in-window collision chance is ~0.1%, and the line number disambiguates even that. Bump this and the mask/pad follow automatically. (This is exactly Can Bölük's original lineno:hash hashline shape — the bare-hash variant was the vis-specific detour that lost the line coordinate and, with it, the wrong-line guard.)

Hex chars in a line's content hash. Anchors now carry the LINE NUMBER too
(`<lineno>:<hash>` — see `line-anchor` / `lines->anchors`), so the hash no
longer has to be globally unique: the line number LOCATES the line and the
hash only VERIFIES the content there (drift + misattribution). That
collapses the hash's job from whole-file disambiguation — which forced
width 4 / 65536 buckets back when the hash was the SOLE anchor (see git
history for the old collision-vs-token table) — to a local check inside a
`hash-line-drift-tolerance`-sized window. 3 hex (4096 buckets) is ample
there: the residual in-window collision chance is ~0.1%, and the line
number disambiguates even that. Bump this and the mask/pad follow
automatically. (This is exactly Can Bölük's original `lineno:hash` hashline
shape — the bare-hash variant was the vis-specific detour that lost the
line coordinate and, with it, the wrong-line guard.)
sourceraw docstring

hashline-anchor-sepclj

Separator between the line number and the content hash inside an anchor (<lineno>:<hash>). A single char so the gutter stays narrow.

Separator between the line number and the content hash inside an anchor
(`<lineno>:<hash>`). A single char so the gutter stays narrow.
sourceraw docstring

hashline-gutterclj

Separator between the anchor and the line text in rendered output.

Separator between the anchor and the line text in rendered output.
sourceraw docstring

indices-matching-hashclj

(indices-matching-hash lines h)

0-based indices of lines whose content line-hash equals the bare hash h. Pure content match — the line-number coordinate is applied separately by resolve-one-anchor, so this just answers "which lines carry this content".

0-based indices of `lines` whose content `line-hash` equals the bare hash
`h`. Pure content match — the line-number coordinate is applied separately
by `resolve-one-anchor`, so this just answers "which lines carry this
content".
sourceraw docstring

line-anchorclj

(line-anchor ln text)

The editable anchor for a line: <line-number>:<content-hash> (e.g. 325:0e3). The line number LOCATES the line; the hash VERIFIES its content. patch :from_anchor parses this back via resolve-anchor-range, matching the line number against live content and refusing if the hash no longer agrees (the line changed) or that content now lives far from the stated line (a misattributed / stale anchor). Two coordinates, so a single reused hash can no longer silently land an edit on the wrong line.

The editable anchor for a line: `<line-number>:<content-hash>` (e.g.
`325:0e3`). The line number LOCATES the line; the hash VERIFIES its
content. `patch :from_anchor` parses this back via `resolve-anchor-range`,
matching the line number against live content and refusing if the hash no
longer agrees (the line changed) or that content now lives far from the
stated line (a misattributed / stale anchor). Two coordinates, so a single
reused hash can no longer silently land an edit on the wrong line.
sourceraw docstring

line-hashclj

(line-hash line)

Stable hash-width-hex-char content hash of line (trimmed). Folds the spec'd String/hashCode algorithm over the whitespace-trimmed line, so it is deterministic across JVM runs. Identical trimmed lines share a hash — a dup-line collision makes a :from_anchor anchor ambiguous and resolve-anchor-edit refuses it (caller falls back to :search).

Hot path: runs once per line on every cat render AND every patch resolve. Formats with Integer/toHexString + a left-pad rather than java.util.Formatter, which benches ~1.5x slower; the trimmed String/hashCode is a JIT intrinsic so we lean on it instead of a hand loop.

Stable `hash-width`-hex-char content hash of `line` (trimmed). Folds
the spec'd `String/hashCode` algorithm over the whitespace-trimmed
line, so it is deterministic across JVM runs. Identical trimmed lines
share a hash — a dup-line collision makes a `:from_anchor` anchor
ambiguous and `resolve-anchor-edit` refuses it (caller falls back to
`:search`).

Hot path: runs once per line on every `cat` render AND every patch
resolve. Formats with `Integer/toHexString` + a left-pad rather than
java.util.Formatter, which benches ~1.5x slower; the trimmed
`String/hashCode` is a JIT intrinsic so we lean on it instead of a
hand loop.
sourceraw docstring

line-index-atclj

(line-index-at content off)

0-based line index of char offset off in content (count of before it).

0-based line index of char offset `off` in `content` (count of `
`
   before it).
sourceraw docstring

lines->anchor-mapclj

(lines->anchor-map tuples)

Ordered {anchor text} map for [[ln text]…] tuples: a REAL java.util.LinkedHashMap (natively insertion-ordered), built in line order — each KEY is the line's <lineno>:<hash> line-anchor, each VALUE the verbatim text. Being an ordered hashmap (not a Clojure map), it stays in file order across the Clojure → JSON/charred → GraalPy dict boundary at ANY size, with NO comparator. EVERY line is keyed (blanks included, so the read stays gap-free); duplicate text differs by line number, so keys are unique. THE single model-facing line payload cat returns; the key IS the patch :from_anchor.

Ordered `{anchor text}` map for `[[ln text]…]` tuples: a REAL
`java.util.LinkedHashMap` (natively insertion-ordered), built in line order
— each KEY is the line's `<lineno>:<hash>` `line-anchor`, each VALUE the
verbatim text. Being an ordered hashmap (not a Clojure map), it stays in
file order across the Clojure → JSON/charred → GraalPy dict boundary at ANY
size, with NO comparator. EVERY line is keyed (blanks included, so the read
stays gap-free); duplicate text differs by line number, so keys are unique.
THE single model-facing line payload `cat` returns; the key IS the
`patch :from_anchor`.
sourceraw docstring

lines->anchorsclj

(lines->anchors tuples)

{line-number anchor} map of every non-blank line in tuples, where each anchor is <line-number>:<content-hash> (line-anchor). The canonical :anchors payload cat returns — the SINGLE place it is built (read-file / read-file-ranges / tail-file / rg all route here). Blank lines are omitted: the model only ever sees anchors it can actually edit by. Line numbers come straight from the [ln text] tuples, so a windowed read (range / tail / by-hash) carries the file's real line numbers with NO second full-file pass — the #N file-wide-ordinal scheme (and its whole-file rescan) is gone now that the line number, not the hash, disambiguates duplicate lines.

`{line-number anchor}` map of every non-blank line in `tuples`, where each
anchor is `<line-number>:<content-hash>` (`line-anchor`). The canonical
`:anchors` payload `cat` returns — the SINGLE place it is built (read-file /
read-file-ranges / tail-file / rg all route here). Blank lines are omitted:
the model only ever sees anchors it can actually edit by. Line numbers come
straight from the `[ln text]` tuples, so a windowed read (range / tail /
by-hash) carries the file's real line numbers with NO second full-file pass
— the `#N` file-wide-ordinal scheme (and its whole-file rescan) is gone now
that the line number, not the hash, disambiguates duplicate lines.
sourceraw docstring

render-lineno-blockclj

(render-lineno-block tuples)

Render [line-number text] tuples as a HUMAN line-number gutter <ln>│ <text>, line numbers right-aligned to the widest number in the block. Unlike render-hashline-block (the MODEL surface, whose gutter is the editable :from_anchor anchor), this is the channel/TUI display surface: humans navigate by line number, not by content hash.

Render `[line-number text]` tuples as a HUMAN line-number gutter
`<ln>│ <text>`, line numbers right-aligned to the widest number in
the block. Unlike `render-hashline-block` (the MODEL surface, whose
gutter is the editable `:from_anchor` anchor), this is the channel/TUI
display surface: humans navigate by line number, not by content hash.
sourceraw docstring

render-lineno-range-blockclj

(render-lineno-range-block ranges)

render-lineno-block analogue for :ranges windows — -- range S-E -- headers followed by the human line-number gutter for each window.

`render-lineno-block` analogue for `:ranges` windows — `-- range S-E --`
headers followed by the human line-number gutter for each window.
sourceraw docstring

resolve-anchor-editclj

(resolve-anchor-edit current from_anchor to_anchor replace)

Content-addressed line-range replace returning full {:new-content S :applied-line N} (or {:error …}). Thin wrapper over resolve-anchor-edit-span; prefer the span variant inside a batch.

Content-addressed line-range replace returning full `{:new-content S
:applied-line N}` (or `{:error …}`). Thin wrapper over
`resolve-anchor-edit-span`; prefer the span variant inside a batch.
sourceraw docstring

resolve-anchor-edit-spanclj

(resolve-anchor-edit-span current from_anchor to_anchor replace)

Resolve a content-addressed line-range edit to a CHAR SPAN against current, WITHOUT building new content: {:start S :end E :replacement R :applied-line N} or {:error {:reason KW …}}. Lets a multi-edit batch resolve every anchor against the ORIGINAL snapshot and splice all spans together atomically, so an earlier edit can't drift a later edit's hash/ordinal. to_anchor defaults to from_anchor (single line). The stated line is tried first and only then small drift is considered; duplicate hashes at other lines do not make an exact lineno:hash anchor ambiguous.

Resolve a content-addressed line-range edit to a CHAR SPAN against `current`,
WITHOUT building new content: `{:start S :end E :replacement R :applied-line N}`
or `{:error {:reason KW …}}`. Lets a multi-edit batch resolve every anchor
against the ORIGINAL snapshot and splice all spans together atomically, so an
earlier edit can't drift a later edit's hash/ordinal. `to_anchor` defaults to
`from_anchor` (single line). The stated line is tried first and only then
small drift is considered; duplicate hashes at other lines do not make an
exact `lineno:hash` anchor ambiguous.
sourceraw docstring

resolve-anchor-rangeclj

(resolve-anchor-range current from_anchor to_anchor)

Resolve from_anchor (and to_anchor, defaulting to from_anchor for a single line) against LIVE current. Each is a <line-number>:<hash> anchor: the line number LOCATES it, the hash VERIFIES the content still matches AND sits near the stated line (else :hashline-misplaced — the wrong-line guard). Both coordinates are REQUIRED; a bare hash with no line number is refused (:hashline-malformed). Returns {:from-line N :to-line N} (1-based, INCLUSIVE) or {:error {:reason KW …}}.

Shared by resolve-anchor-edit (WRITE — patch :from_anchor) and the cat :anchor READ path so both address lines identically.

Resolve `from_anchor` (and `to_anchor`, defaulting to `from_anchor` for a single
line) against LIVE `current`. Each is a `<line-number>:<hash>` anchor: the
line number LOCATES it, the hash VERIFIES the content still matches AND sits
near the stated line (else `:hashline-misplaced` — the wrong-line guard). Both
coordinates are REQUIRED; a bare hash with no line number is refused
(`:hashline-malformed`). Returns `{:from-line N :to-line N}` (1-based,
INCLUSIVE) or `{:error {:reason KW …}}`.

Shared by `resolve-anchor-edit` (WRITE — patch :from_anchor) and the cat
`:anchor` READ path so both address lines identically.
sourceraw docstring

seek-sequenceclj

(seek-sequence lines pattern start eof?)

Find pattern (a vec of strings) inside lines (vec of strings) starting at start. When eof? is true, first try the EOF position then fall back to start.

Match strictness, in order: exact -> rstrip -> unicode -> relative-indent -> trim. Returns the start index or nil. For pass attribution use seek-sequence-with-pass.

Find `pattern` (a vec of strings) inside `lines` (vec of strings)
starting at `start`. When `eof?` is true, first try the EOF position
then fall back to `start`.

Match strictness, in order: exact -> rstrip -> unicode -> relative-indent
-> trim. Returns the start index or nil. For pass attribution use
`seek-sequence-with-pass`.
sourceraw docstring

seek-sequence-with-passclj

(seek-sequence-with-pass lines pattern start eof?)

Like seek-sequence but returns {:start <i> :pass <kw> :indent-delta <n>?} so callers can surface which fuzzy pass produced the hit. pass is one of :exact :rstrip :unicode :relative-indent :trim. nil when no pass matches.

Pass priority is deliberately: :exact → :rstrip → :unicode → :relative-indent → :trim :relative-indent runs BEFORE :trim because :trim is destructive (it drops both leading and trailing whitespace from each line and so collapses different indentation structures to the same key). The more structure-preserving :relative-indent should win whenever it can.

Like `seek-sequence` but returns `{:start <i> :pass <kw> :indent-delta <n>?}`
so callers can surface which fuzzy pass produced the hit. `pass` is one of
`:exact :rstrip :unicode :relative-indent :trim`. nil when no pass matches.

Pass priority is deliberately:
  :exact → :rstrip → :unicode → :relative-indent → :trim
`:relative-indent` runs BEFORE `:trim` because `:trim` is destructive
(it drops both leading and trailing whitespace from each line and so
collapses different indentation structures to the same key). The more
structure-preserving `:relative-indent` should win whenever it can.
sourceraw docstring

split-content-linesclj

(split-content-lines s)

Split a file blob into a vec of lines. Trailing empty element (from a final newline) is dropped, matching the convention used by the exact-replace path.

Split a file blob into a vec of lines. Trailing empty element (from a
final newline) is dropped, matching the convention used by the
exact-replace path.
sourceraw docstring

tokenize-with-offsetsclj

(tokenize-with-offsets s)

Vec of [token ^long start ^long end] for every maximal non-whitespace run in s. start/end are raw char offsets (end exclusive).

Vec of `[token ^long start ^long end]` for every maximal non-whitespace
run in `s`. `start`/`end` are raw char offsets (end exclusive).
sourceraw docstring

tuples->rangesclj

(tuples->ranges tuples)

Split flat [[ln text]…] tuples into contiguous :ranges windows [{:range [start end] :lines [[ln text]…]}…], breaking the run whenever the line number jumps by more than 1. Produces exactly the shape render-lineno-range-block / render-hashline-range-block consume, so a flat tuple list (e.g. grouped grep hits) renders with the same -- range S-E -- gap headers as a native multi-range read.

Split flat `[[ln text]…]` tuples into contiguous `:ranges` windows
`[{:range [start end] :lines [[ln text]…]}…]`, breaking the run whenever
the line number jumps by more than 1. Produces exactly the shape
`render-lineno-range-block` / `render-hashline-range-block` consume, so a
flat tuple list (e.g. grouped grep hits) renders with the same
`-- range S-E --` gap headers as a native multi-range read.
sourceraw docstring

ws-agnostic-line-spanclj

(ws-agnostic-line-span content search)

Whitespace-agnostic token-subsequence match. Folds search and content to whitespace-free token streams and looks for search's tokens as a contiguous subsequence of content's. Because all whitespace (incl. newline structure) is discarded, a SEARCH block whose line breaks drifted from the file still locates.

Returns {:line-start <i> :line-end <j> :occurrences <n>} (0-based, :line-end exclusive) snapped to whole lines around the FIRST hit, or nil when zero tokens match. :occurrences is the total contiguous-hit count so callers can refuse ambiguous (>1) applies.

Whitespace-agnostic token-subsequence match. Folds `search` and
`content` to whitespace-free token streams and looks for `search`'s
tokens as a contiguous subsequence of `content`'s. Because all
whitespace (incl. newline structure) is discarded, a SEARCH block whose
line breaks drifted from the file still locates.

Returns `{:line-start <i> :line-end <j> :occurrences <n>}` (0-based,
`:line-end` exclusive) snapped to whole lines around the FIRST hit, or
nil when zero tokens match. `:occurrences` is the total contiguous-hit
count so callers can refuse ambiguous (>1) applies.
sourceraw docstring

cljdoc builds & hosts documentation for Clojure/Script libraries

Keyboard shortcuts
Ctrl+kJump to recent docs
Move to previous article
Move to next article
Ctrl+/Jump to the search field
× close