;; content-on-sx — block reorder + reparent. ;; ;; Relative reorder of top-level blocks (move-before/after/to-front/to-back by ;; id) plus TREE reparenting: move a block into a section (content/move-into) or ;; promote a nested block back out to the top level (content/promote). Reparent ;; ops are tree-wide (the block may start anywhere) and cycle-safe — moving a ;; block into its own descendant is rejected (no-op), so a section can never ;; become its own ancestor. No-op if any id is missing. Immutable; composes the ;; doc.sx list + tree helpers (doc-find-deep / ct-find-id / ct-remove-id / ;; ct-replace-id / ct-insert-at). ;; ;; Requires (loaded by harness): doc.sx. (define content/move-before (fn (doc id target) (let ((blk (doc-find doc id))) (if (= blk nil) doc (let ((without (ct-remove-id (doc-blocks doc) id))) (let ((idx (ct-index-of without target))) (if (= idx -1) doc (doc-with-blocks doc (ct-insert-at without idx blk))))))))) (define content/move-after (fn (doc id target) (let ((blk (doc-find doc id))) (if (= blk nil) doc (let ((without (ct-remove-id (doc-blocks doc) id))) (let ((idx (ct-index-of without target))) (if (= idx -1) doc (doc-with-blocks doc (ct-insert-at without (+ idx 1) blk))))))))) (define content/move-to-front (fn (doc id) (let ((blk (doc-find doc id))) (if (= blk nil) doc (doc-with-blocks doc (cons blk (ct-remove-id (doc-blocks doc) id))))))) (define content/move-to-back (fn (doc id) (let ((blk (doc-find doc id))) (if (= blk nil) doc (doc-with-blocks doc (append (ct-remove-id (doc-blocks doc) id) (list blk))))))) ;; ── reparent (tree-wide) ── ;; move block `id` (from anywhere in the tree) to be a child of section ;; `section-id` at index `i`. No-op if either id is missing, if id = section-id, ;; or if section-id sits inside id's own subtree (would create a cycle). (define content/move-into (fn (doc id section-id i) (let ((blk (doc-find-deep doc id))) (if (= blk nil) doc (if (= (doc-find-deep doc section-id) nil) doc (if (= id section-id) doc (if (= (ct-find-id (list blk) section-id) nil) (let ((without (ct-remove-id (doc-blocks doc) id))) (doc-with-blocks doc (ct-replace-id without section-id (fn (sec) (let ((ch (st-iv-get sec "children"))) (if (list? ch) (st-iv-set! sec "children" (ct-insert-at ch i blk)) sec)))))) doc))))))) ;; promote block `id` (wherever it sits) out to the end of the top level. If it ;; is already top-level this is a move-to-back. No-op if missing. A section keeps ;; its whole subtree. (define content/promote (fn (doc id) (let ((blk (doc-find-deep doc id))) (if (= blk nil) doc (doc-with-blocks doc (append (ct-remove-id (doc-blocks doc) id) (list blk)))))))