Liking cljdoc? Tell your friends :D

com.blockether.vis.internal.foundation.editing.hashline

Pure hashline primitives: the ANCHOR vocabulary cat mints, grep echoes and patch spends.

An anchor is <1-based line>:<3-hex content hash> (Can Bölük's original hashline shape). The LINE NUMBER locates the line; the CONTENT HASH verifies it. A write requires BOTH coordinates to match exactly: any contradiction is REFUSED (:anchor-mismatch) instead of relocating the edit. Only the non-destructive read path may follow matching content through small line drift.

This namespace is pure — no IO, no tool wiring, no extension envelope. Every surface that addresses a line routes here so the scheme is never recomputed:

split-content-lines / char-offset-at-line blob <-> line/char coordinates line-hash / line-anchor / anchor->line text -> <line>:<hash> render-hashline-block [[ln text]…] -> gutter text anchor-token / parse-anchor rendered line -> bare anchor indices-matching-hash content-only hash lookup resolve-one-anchor / resolve-anchor-range exact write resolution resolve-anchor-range-read tolerant read resolution resolve-anchor-edit-span anchor span -> char span

Pure hashline primitives: the ANCHOR vocabulary `cat` mints, `grep` echoes and
`patch` spends.

An anchor is `<1-based line>:<3-hex content hash>` (Can Bölük's original
hashline shape). The LINE NUMBER locates the line; the CONTENT HASH verifies
it. A write requires BOTH coordinates to match exactly: any contradiction is
REFUSED (`:anchor-mismatch`) instead of relocating the edit. Only the
non-destructive read path may follow matching content through small line drift.

This namespace is pure — no IO, no tool wiring, no extension envelope. Every
surface that addresses a line routes here so the scheme is never recomputed:

  split-content-lines / char-offset-at-line   blob <-> line/char coordinates
  line-hash / line-anchor / anchor->line      text  -> `<line>:<hash>`
  render-hashline-block                       [[ln text]…] -> gutter text
  anchor-token / parse-anchor                 rendered line -> bare anchor
  indices-matching-hash                       content-only hash lookup
  resolve-one-anchor / resolve-anchor-range   exact write resolution
  resolve-anchor-range-read                   tolerant read resolution
  resolve-anchor-edit-span                    anchor span -> char span
raw docstring

anchor->lineclj

(anchor->line anchor)

Parse the 1-based line number out of a <line>:<hash> anchor, rendered or bare.

Parse the 1-based line number out of a `<line>:<hash>` anchor, rendered or
bare.
sourceraw docstring

anchor-string?clj

(anchor-string? x)

True when x ADDRESSES a line: a bare <line>:<hash> token, or a whole rendered <line>:<hash>│ <text> line, which is that same anchor with the gutter still attached. cat uses it to tell an anchor endpoint from a bare line number; anything else is a number.

True when `x` ADDRESSES a line: a bare `<line>:<hash>` token, or a whole
rendered `<line>:<hash>│ <text>` line, which is that same anchor with the
gutter still attached. `cat` uses it to tell an anchor endpoint from a bare
line number; anything else is a number.
sourceraw docstring

anchor-tokenclj

(anchor-token x)

The bare <line>:<hash> token inside whatever the caller actually passed.

Every anchor a model ever sees is RENDERED — <line>:<hash>│ <text>, because cat, grep and patch's re-anchored window all print through render-hashline-block — and the contract those tools advertise is that one of their lines goes straight back in as an anchor. So everything from hashline-gutter on is DECORATION and is cut here: the line number locates and the hash verifies, while the text behind the gutter only SHOWED the line. Without this cut the text became part of the hash, no line could carry it, and the refusal handed back the very anchor it had just refused.

What is left is unwrapped from stray whitespace and quote chars — the other common JSON/LLM mistake, where "4439:a80" arrives WITH its literal quotes and parse-long chokes on the leading one.

The bare `<line>:<hash>` token inside whatever the caller actually passed.

Every anchor a model ever sees is RENDERED — `<line>:<hash>│ <text>`, because
`cat`, `grep` and `patch`'s re-anchored window all print through
`render-hashline-block` — and the contract those tools advertise is that one
of their lines goes straight back in as an anchor. So everything from
`hashline-gutter` on is DECORATION and is cut here: the line number locates
and the hash verifies, while the text behind the gutter only SHOWED the line.
Without this cut the text became part of the hash, no line could carry it,
and the refusal handed back the very anchor it had just refused.

What is left is unwrapped from stray whitespace and quote chars — the other
common JSON/LLM mistake, where `"4439:a80"` arrives WITH its literal quotes
and `parse-long` chokes on the leading one.
sourceraw docstring

anchor?clj

(anchor? x)
source

bare-anchor-string?clj

(bare-anchor-string? x)

True when x is ONLY an anchor — the token, with no line text behind it. patch asks this of its REPLACEMENT slot: a bare anchor there is the span the caller forgot to finish, while a rendered line carrying TEXT is plausibly the content it means to write and is written (with a note), not refused.

True when `x` is ONLY an anchor — the token, with no line text behind it.
`patch` asks this of its REPLACEMENT slot: a bare anchor there is the span
the caller forgot to finish, while a rendered line carrying TEXT is plausibly
the content it means to write and is written (with a note), not refused.
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) when line-idx reaches past the last line. Public so the edit-span planner can map line indices back to char positions for splicing.

Char offset in `content` where 0-based line `line-idx` starts. Returns
`(count content)` when `line-idx` reaches past the last line. Public so the
edit-span planner can map line indices back to char positions for splicing.
sourceraw docstring

hash-line-drift-toleranceclj

How far resolve-anchor-range-read may follow content from its stated line. Reads are non-destructive, so following one nearby hash match is useful; writes never use this window and require an exact line/hash pair.

How far `resolve-anchor-range-read` may follow content from its stated line.
Reads are non-destructive, so following one nearby hash match is useful; writes
never use this window and require an exact line/hash pair.
sourceraw docstring

hash-widthclj

Hex chars in a line's content hash. The line number locates; this hash verifies the exact line for writes. Three hex chars keep an anchor at 4-7 characters; the line coordinate, not a file-wide hash search, disambiguates collisions.

Hex chars in a line's content hash. The line number locates; this hash verifies
the exact line for writes. Three hex chars keep an anchor at 4-7 characters;
the line coordinate, not a file-wide hash search, disambiguates collisions.
sourceraw docstring

hash?clj

(hash? x)
source

hashline-anchor-sepclj

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

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

hashline-gutterclj

Separator between the anchor and the line text in every rendered block. U+2502 plus a space: it never occurs in source, so line.split("│ ", 1) is exact and can never be confused with the : inside the anchor.

Separator between the anchor and the line text in every rendered block.
U+2502 plus a space: it never occurs in source, so `line.split("│ ", 1)` is
exact and can never be confused with the `:` inside the anchor.
sourceraw docstring

indices-matching-hashclj

(indices-matching-hash lines h)

0-based indices of lines whose line-hash equals the bare hash h. This is only for tolerant READ resolution; writes verify the hash at the named line.

0-based indices of `lines` whose `line-hash` equals the bare hash `h`. This is
only for tolerant READ resolution; writes verify the hash at the named line.
sourceraw docstring

line-anchorclj

(line-anchor ln text)

The editable anchor for a line: <line-number>:<content-hash> (e.g. 4439:a80). The line number LOCATES the line and the hash VERIFIES its exact current content. patch refuses any mismatch instead of following the hash to another line.

The editable anchor for a line: `<line-number>:<content-hash>` (e.g.
`4439:a80`). The line number LOCATES the line and the hash VERIFIES its exact
current content. `patch` refuses any mismatch instead of following the hash
to another 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; the line coordinate disambiguates identical hashes, and a blank line hashes to 000.

Hot path: it runs once per rendered line on every cat, every grep hit and every patch resolve. Formats with Integer/toHexString plus a left-pad rather than java.util.Formatter (~1.5x slower), and leans on the trimmed String/hashCode because that is a JIT intrinsic.

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; the line coordinate disambiguates identical
hashes, and a blank line hashes to `000`.

Hot path: it runs once per rendered line on every `cat`, every `grep` hit and
every patch resolve. Formats with `Integer/toHexString` plus a left-pad
rather than java.util.Formatter (~1.5x slower), and leans on the trimmed
`String/hashCode` because that is a JIT intrinsic.
sourceraw docstring

line?clj

(line? x)
source

parse-anchorclj

(parse-anchor anchor)

Parse a <line>:<hash> anchor into {:line L :hash H} (L a 1-based long, H the hex content hash). The line number is REQUIRED: an anchor with no : separator, or a non-numeric line part, parses to {:malformed true :raw S} and resolve-one-anchor refuses it (:anchor-malformed). Every anchor must carry BOTH coordinates so the line LOCATES and the hash VERIFIES.

A WHOLE RENDERED LINE parses exactly like a bare token: anchor-token cuts the gutter and the text behind it first, so the hash is only ever the hex.

Parse a `<line>:<hash>` anchor into `{:line L :hash H}` (L a 1-based long, H
the hex content hash). The line number is REQUIRED: an anchor with no `:`
separator, or a non-numeric line part, parses to `{:malformed true :raw S}`
and `resolve-one-anchor` refuses it (`:anchor-malformed`). Every anchor must
carry BOTH coordinates so the line LOCATES and the hash VERIFIES.

A WHOLE RENDERED LINE parses exactly like a bare token: `anchor-token` cuts
the gutter and the text behind it first, so the hash is only ever the hex.
sourceraw docstring

parsed?clj

(parsed? x)
source

render-hashline-blockclj

(render-hashline-block tuples)
(render-hashline-block tuples indent)

Render [[line-number text]…] tuples as the MODEL's addressable gutter — <line>:<hash>│ <text>, one line per tuple, indent prefixed to each. This is the single renderer behind cat, grep's hit rows and patch's re-anchored window, so all three speak one format and any of their lines can be split on hashline-gutter and fed straight back to patch.

A CRLF file's lines still carry their \r: split-content-lines splits on \n alone because the char offsets an edit splices at must count every character the file really has. RENDERING drops that trailing CR — it is invisible on screen, line-hash never saw it (the hash is of the TRIMMED line, so the anchor is unchanged), and a model that copies a rendered line back as a replacement would otherwise write a SECOND carriage return in.

Render `[[line-number text]…]` tuples as the MODEL's addressable gutter —
`<line>:<hash>│ <text>`, one line per tuple, `indent` prefixed to each. This
is the single renderer behind `cat`, `grep`'s hit rows and `patch`'s
re-anchored window, so all three speak one format and any of their lines can
be split on `hashline-gutter` and fed straight back to `patch`.

A CRLF file's lines still carry their `\r`: `split-content-lines` splits on
`\n` alone because the char offsets an edit splices at must count every
character the file really has. RENDERING drops that trailing CR — it is
invisible on screen, `line-hash` never saw it (the hash is of the TRIMMED
line, so the anchor is unchanged), and a model that copies a rendered line
back as a replacement would otherwise write a SECOND carriage return in.
sourceraw docstring

resolve-anchor-edit-spanclj

(resolve-anchor-edit-span current from-anchor to-anchor replacement)

Resolve an exact anchored line range to a CHAR SPAN against current, WITHOUT building new content: {:start S :end E :replacement R :from-line N :to-line N} or {:error {:reason KW …}}. to-anchor defaults to from-anchor (a single line); every supplied endpoint must match its exact current line.

Newline semantics: a replacement need NOT end in \n — the matched region's terminator is preserved (\r\n stays \r\n on a CRLF file) — and one that DOES is not doubled: exactly one trailing terminator is dropped, so a block copied with its own newline REPLACES the span instead of growing a blank line after it. An EMPTY replacement consumes the trailing newline, so the lines actually vanish instead of leaving blanks behind.

Resolve an exact anchored line range to a CHAR SPAN against `current`, WITHOUT
building new content: `{:start S :end E :replacement R :from-line N :to-line N}`
or `{:error {:reason KW …}}`. `to-anchor` defaults to `from-anchor` (a single
line); every supplied endpoint must match its exact current line.

Newline semantics: a replacement need NOT end in `\n` — the matched region's
terminator is preserved (`\r\n` stays `\r\n` on a CRLF file) — and one that
DOES is not doubled: exactly one trailing terminator is dropped, so a block
copied with its own newline REPLACES the span instead of growing a blank line
after it. An EMPTY replacement consumes the trailing newline, so the lines
actually vanish instead of leaving blanks behind.
sourceraw docstring

resolve-anchor-rangeclj

(resolve-anchor-range current from-anchor to-anchor)

Resolve from-anchor and to-anchor against LIVE current; to defaults to from for a single-line edit. Every endpoint is a <line>:<hash> pair whose hash must match that exact line. A mismatch is refused (:anchor-mismatch), never relocated. Returns {:from-line N :to-line N} (1-based, INCLUSIVE) or {:error {:reason KW …}}; a range mismatch carries the fresh anchors for both endpoints.

The WRITE side of the contract. resolve-anchor-range-read is its tolerant, non-destructive twin.

Resolve `from-anchor` and `to-anchor` against LIVE `current`; `to` defaults to
`from` for a single-line edit. Every endpoint is a `<line>:<hash>` pair whose
hash must match that exact line. A mismatch is refused (`:anchor-mismatch`),
never relocated. Returns `{:from-line N :to-line N}` (1-based, INCLUSIVE) or
`{:error {:reason KW …}}`; a range mismatch carries the fresh anchors for both
endpoints.

The WRITE side of the contract. `resolve-anchor-range-read` is its tolerant,
non-destructive twin.
sourceraw docstring

resolve-anchor-range-readclj

(resolve-anchor-range-read current from-anchor to-anchor)

READ-tolerant twin of resolve-anchor-range, for cat. A read is NON-DESTRUCTIVE, so one nearby hash match may be followed; otherwise an in-range stale anchor falls back to its stated LINE NUMBER. Returns {:from-line N :to-line N :stale? BOOL} (1-based, INCLUSIVE; the window never inverts), or {:error …} only for a genuinely unlocatable anchor (:anchor-malformed or :anchor-line-out-of-range).

READ-tolerant twin of `resolve-anchor-range`, for `cat`. A read is
NON-DESTRUCTIVE, so one nearby hash match may be followed; otherwise an
in-range stale anchor falls back to its stated LINE NUMBER. Returns
`{:from-line N :to-line N :stale? BOOL}` (1-based, INCLUSIVE; the window never
inverts), or `{:error …}` only for a genuinely unlocatable anchor
(`:anchor-malformed` or `:anchor-line-out-of-range`).
sourceraw docstring

resolve-one-anchorclj

(resolve-one-anchor lines which {:keys [line hash malformed raw]})

Resolve one PARSED {:line :hash} write anchor to a 0-based index in lines, or {:error {:reason KW …}}. The line LOCATES and the hash VERIFIES that exact line. A mismatch is never relocated, even when the same hash occurs nearby; its error carries the current anchor at the stated line for one-step recovery.

Resolve one PARSED `{:line :hash}` write anchor to a 0-based index in `lines`,
or `{:error {:reason KW …}}`. The line LOCATES and the hash VERIFIES that exact
line. A mismatch is never relocated, even when the same hash occurs nearby;
its error carries the current anchor at the stated line for one-step recovery.
sourceraw docstring

split-content-linesclj

(split-content-lines s)

Split a file blob into a vec of lines. A trailing empty element (from the file's final newline) is dropped, so the vector's count IS the file's line count and index 0 is line 1.

Split a file blob into a vec of lines. A trailing empty element (from the
file's final newline) is dropped, so the vector's count IS the file's line
count and index 0 is line 1.
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