Hyperscript: precedes/follows comparisons, tokenizer keywords

Parser: precedes/follows comparison operators in parse-cmp.
Tokenizer: precedes, follows, ignoring, case keywords.
Runtime: precedes?, follows? string comparison functions.

372/831 (45%)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-04-12 12:20:13 +00:00
parent ae32254dfb
commit 7d798be14f
14 changed files with 218 additions and 187 deletions

View File

@@ -1,171 +1,109 @@
;; Pretext demo — DOM-free text layout
;;
;; Visual-first: shows typeset text, then explains how.
;; All layout computed server-side in pure SX.
;; All layout computed as data, then rendered.
;; Render a single line of positioned words
(defcomp
~pretext-demo/render-line
(&key line-words line-widths gap-w y)
(let
((positions (list)) (x 0))
(for-each
(fn
(i)
(let
((w (nth line-words i)) (ww (nth line-widths i)))
(append!
positions
(span
:style (str
"position:absolute;left:"
(+ x 16)
"px;top:"
(+ y 12)
"px;font-size:15px;line-height:24px;white-space:nowrap;")
w))
(set! x (+ x ww gap-w))))
(range (len line-words)))
positions))
;; Compute positioned word data for one line.
;; Returns list of {:word :x :width} dicts.
(define
pretext-position-line
(fn
(words widths gap-w)
(let
loop
((i 0) (x 0) (acc (list)))
(if
(>= i (len words))
acc
(loop
(+ i 1)
(+ x (nth widths i) gap-w)
(append acc (list {:width (nth widths i) :x x :word (nth words i)})))))))
;; Render a paragraph as positioned words using break-lines output
;; Compute all positioned lines for a paragraph.
;; Returns list of {:y :words [{:word :x :width}...]} dicts.
(define
pretext-layout-lines
(fn
(words widths ranges space-width max-width line-height)
(let
((n-lines (len ranges)))
(map
(fn
(line-idx)
(let
((range (nth ranges line-idx)) (y (* line-idx line-height)))
(let
((start (first range)) (end (nth range 1)))
(let
((lw (slice words start end))
(lwid (slice widths start end)))
(let
((total-w (reduce + 0 lwid))
(n-gaps (max 1 (- (len lw) 1)))
(is-last (= line-idx (- n-lines 1))))
(let
((gap (if is-last space-width (/ (- max-width total-w) n-gaps))))
{:y y :words (pretext-position-line lw lwid gap)}))))))
(range n-lines)))))
;; Render pre-computed positioned lines
(defcomp
~pretext-demo/typeset-block
(&key words widths space-width max-width line-height label)
~pretext-demo/render-paragraph
(&key lines max-width line-height n-words label)
(let
((ranges (break-lines widths space-width max-width))
(lh (or line-height 24)))
((lh (or line-height 24)) (n-lines (len lines)))
(div
(~tw
:tokens "relative rounded-lg border border-stone-200 bg-white overflow-hidden")
:class "relative rounded-lg border border-stone-200 bg-white overflow-hidden"
(when
label
(div
(~tw :tokens "px-4 pt-3 pb-1")
:class "px-4 pt-3 pb-1"
(span
(~tw
:tokens "text-xs font-medium uppercase tracking-wide text-stone-400")
:class "text-xs font-medium uppercase tracking-wide text-stone-400"
label)))
(div
:style (str
"position:relative;height:"
(* (len ranges) lh)
(* n-lines lh)
"px;padding:12px 16px;")
(map-indexed
(map
(fn
(line-idx range)
(line)
(let
((start (first range))
(end (nth range 1))
(y (* line-idx lh))
(line-words (slice words start end))
(line-widths (slice widths start end))
(total-word-w (reduce + 0 line-widths))
(gaps (max 1 (- (len line-words) 1)))
(slack (- max-width total-word-w))
(is-last (= line-idx (- (len ranges) 1)))
(gap-w (if is-last space-width (/ slack gaps))))
(~pretext-demo/render-line
:line-words line-words
:line-widths line-widths
:gap-w gap-w
:y y)))
ranges))
(div
(~tw
:tokens "px-4 py-2 border-t border-stone-100 bg-stone-50 flex justify-between")
(span
(~tw :tokens "text-xs text-stone-400")
(str (len ranges) " lines, " (len words) " words"))
(span
(~tw :tokens "text-xs text-stone-400")
(str "width: " max-width "px"))))))
;; Simple greedy word wrap for comparison
(defcomp
~pretext-demo/greedy-block
(&key words widths space-width max-width line-height label)
(let
((n (len widths))
(lines (list))
(current-start 0)
(current-width 0)
(lh (or line-height 24)))
(for-each
(fn
(i)
(let
((w (nth widths i))
(needed
(if (= i current-start) w (+ current-width space-width w))))
(if
(and (> needed max-width) (not (= i current-start)))
(do
(append! lines (list current-start i))
(set! current-start i)
(set! current-width w))
(set! current-width needed))))
(range n))
(append! lines (list current-start n))
(div
(~tw
:tokens "relative rounded-lg border border-stone-200 bg-white overflow-hidden")
(when
label
(div
(~tw :tokens "px-4 pt-3 pb-1")
(span
(~tw
:tokens "text-xs font-medium uppercase tracking-wide text-stone-400")
label)))
(div
:style (str
"position:relative;height:"
(* (len lines) lh)
"px;padding:12px 16px;")
(map-indexed
(fn
(line-idx range)
(let
((start (first range))
(end (nth range 1))
(y (* line-idx lh))
(line-words (slice words start end))
(line-widths (slice widths start end))
(total-word-w (reduce + 0 line-widths))
(gaps (max 1 (- (len line-words) 1)))
(slack (- max-width total-word-w))
(is-last (= line-idx (- (len lines) 1)))
(gap-w (if is-last space-width (/ slack gaps))))
(~pretext-demo/render-line
:line-words line-words
:line-widths line-widths
:gap-w gap-w
:y y)))
((y (get line :y)))
(map
(fn
(pw)
(span
:style (str
"position:absolute;left:"
(+ (get pw :x) 16)
"px;top:"
(+ y 12)
"px;font-size:15px;line-height:"
lh
"px;white-space:nowrap;")
(get pw :word)))
(get line :words))))
lines))
(div
(~tw
:tokens "px-4 py-2 border-t border-stone-100 bg-stone-50 flex justify-between")
:class "px-4 py-2 border-t border-stone-100 bg-stone-50 flex justify-between"
(span
(~tw :tokens "text-xs text-stone-400")
(str (len lines) " lines (greedy)"))
(span
(~tw :tokens "text-xs text-stone-400")
(str "width: " max-width "px"))))))
:class "text-xs text-stone-400"
(str n-lines " lines, " n-words " words"))
(span :class "text-xs text-stone-400" (str "width: " max-width "px"))))))
(defcomp
~pretext-demo/content
()
(let
((sample-text "In the beginning was the Word, and the Word was with God, and the Word was God. The same was in the beginning with God. All things were made by him; and without him was not any thing made that was made. In him was life; and the life was the light of men.")
(sample-words
(split
"In the beginning was the Word, and the Word was with God, and the Word was God. The same was in the beginning with God. All things were made by him; and without him was not any thing made that was made. In him was life; and the life was the light of men."
" "))
((sample-words (split "In the beginning was the Word, and the Word was with God, and the Word was God. The same was in the beginning with God. All things were made by him; and without him was not any thing made that was made. In him was life; and the life was the light of men." " "))
(char-w 9.6)
(space-w 9.6))
(let
((sample-widths (map (fn (w) (* (len w) char-w)) sample-words)))
((sw (map (fn (w) (* (len w) char-w)) sample-words))
(n-words (len sample-words)))
(div
(~tw :tokens "space-y-10")
(div
@@ -177,14 +115,21 @@
(p
(~tw :tokens "mt-1 text-lg text-stone-500")
"DOM-free text layout. One IO boundary. Pure arithmetic."))
(div
(~tw :tokens "max-w-xl mx-auto mt-6")
(~pretext-demo/typeset-block
:words sample-words
:widths sample-widths
:space-width space-w
:max-width 520
:label "Knuth-Plass optimal line breaking — John 1:14")))
(let
((hero-max 520) (hero-ranges (break-lines sw space-w 520)))
(div
(~tw :tokens "max-w-xl mx-auto mt-6")
(~pretext-demo/render-paragraph
:lines (pretext-layout-lines
sample-words
sw
hero-ranges
space-w
hero-max
24)
:max-width hero-max
:n-words n-words
:label "Knuth-Plass optimal line breaking — John 1:14"))))
(div
(~tw :tokens "rounded-lg border border-violet-200 bg-violet-50 p-5")
(p
@@ -205,24 +150,35 @@
"Most web text uses greedy word wrap — break when the next word doesn't fit. "
"Knuth-Plass considers all possible breaks simultaneously, minimizing total raggedness.")
(let
((narrow-widths (map (fn (w) (* (len w) 7.8)) sample-words))
(narrow-sw 7.8)
(narrow-max 340))
((nw (map (fn (w) (* (len w) 7.8)) sample-words))
(ns 7.8)
(nm 340)
(nlh 22))
(div
(~tw :tokens "grid grid-cols-1 md:grid-cols-2 gap-4")
(~pretext-demo/greedy-block
:words sample-words
:widths narrow-widths
:space-width narrow-sw
:max-width narrow-max
:line-height 22
(~pretext-demo/render-paragraph
:lines (pretext-layout-lines
sample-words
nw
(break-lines-greedy nw ns nm)
ns
nm
nlh)
:max-width nm
:line-height nlh
:n-words n-words
:label "Greedy (browser default)")
(~pretext-demo/typeset-block
:words sample-words
:widths narrow-widths
:space-width narrow-sw
:max-width narrow-max
:line-height 22
(~pretext-demo/render-paragraph
:lines (pretext-layout-lines
sample-words
nw
(break-lines nw ns nm)
ns
nm
nlh)
:max-width nm
:line-height nlh
:n-words n-words
:label "Knuth-Plass optimal"))))
(div
(~tw :tokens "space-y-3")