;; content-on-sx — nested block trees (section container). ;; ;; CtSection is a block whose ivar `children` is an ordered list of blocks (any ;; type, including nested sections → arbitrary depth). This turns the document ;; from a flat sequence into the ordered TREE of the architecture sketch. ;; ;; Self-contained: CtSection answers asHTML/asSx/asText/asMarkdown: by folding ;; its children's renderings — pure polymorphic recursion, so it composes with ;; the existing render boundary with no changes to block.sx or render.sx. (The ;; relevant per-block render bootstrap must be loaded for the children.) ;; ;; Requires (loaded by harness): block.sx, doc.sx, render.sx (asHTML/asSx); ;; markdown.sx / text.sx for those formats on children. (define content-bootstrap-section! (fn () (begin (st-class-define! "CtSection" "CtBlock" (list "children")) (ct-def-method! "CtSection" "children" "children ^ children") (ct-def-method! "CtSection" "type" "type ^ #section") (ct-def-method! "CtSection" "asHTML" "asHTML ^ '
' , (children inject: '' into: [:a :b | a , (b asHTML)]) , '
'") (ct-def-method! "CtSection" "asSx" "asSx ^ '(section ' , (children inject: '' into: [:a :b | a , (b asSx)]) , ')'") (ct-def-method! "CtSection" "asText" "asText ^ (children inject: '' into: [:a :b | (b asText = '') ifTrue: [a] ifFalse: [(a = '' ifTrue: [b asText] ifFalse: [a , ' ' , b asText])]])") (ct-def-method! "CtSection" "asMarkdown:" "asMarkdown: nl ^ (children inject: '' into: [:a :b | a , (a = '' ifTrue: [''] ifFalse: [nl , nl]) , (b asMarkdown: nl)])") true))) (define mk-section (fn (id children) (st-iv-set! (st-iv-set! (st-make-instance "CtSection") "id" id) "children" children))) (define section? (fn (b) (and (st-instance? b) (= (get b :class) "CtSection")))) (define section-children (fn (sec) (st-send sec "children" (list)))) ;; copy-on-write child edits (return a new section) (define section-with-children (fn (sec children) (st-iv-set! sec "children" children))) (define section-append (fn (sec block) (section-with-children sec (append (section-children sec) (list block))))) ;; ── tree traversal (descends into nested sections) ── (define block-deep-find (fn (blocks id) (if (= (len blocks) 0) nil (let ((b (first blocks))) (if (= (blk-id b) id) b (let ((nested (if (section? b) (block-deep-find (section-children b) id) nil))) (if (= nested nil) (block-deep-find (rest blocks) id) nested))))))) (define doc-deep-find (fn (doc id) (block-deep-find (doc-blocks doc) id))) (define block-tree-ids (fn (blocks) (if (= (len blocks) 0) (list) (let ((b (first blocks))) (append (cons (blk-id b) (if (section? b) (block-tree-ids (section-children b)) (list))) (block-tree-ids (rest blocks))))))) (define doc-tree-ids (fn (doc) (block-tree-ids (doc-blocks doc)))) (define block-tree-count (fn (blocks) (len (block-tree-ids blocks)))) (define doc-tree-count (fn (doc) (len (doc-tree-ids doc))))