;; content-on-sx — plain-text render mode + excerpts.
;;
;; A fourth boundary format via polymorphic dispatch: blocks answer asText,
;; stripping all markup. Useful for search indexing, meta descriptions and
;; previews. The document joins non-empty child texts with a single space.
;;
;; Requires (loaded by harness): block.sx, doc.sx.

(define
  content-bootstrap-text!
  (fn
    ()
    (begin
      (ct-def-method! "CtHeading" "asText" "asText ^ text")
      (ct-def-method! "CtText" "asText" "asText ^ text")
      (ct-def-method! "CtCode" "asText" "asText ^ text")
      (ct-def-method! "CtQuote" "asText" "asText ^ text")
      (ct-def-method! "CtImage" "asText" "asText ^ alt")
      (ct-def-method! "CtEmbed" "asText" "asText ^ ''")
      (ct-def-method! "CtDivider" "asText" "asText ^ ''")
      (ct-def-method!
        "CtList"
        "asText"
        "asText ^ (items inject: '' into: [:a :x | (a = '' ifTrue: [x] ifFalse: [a , ', ' , x])])")
      (ct-def-method!
        "CtDoc"
        "asText"
        "asText ^ (blocks inject: '' into: [:a :b | (b asText = '') ifTrue: [a] ifFalse: [(a = '' ifTrue: [b asText] ifFalse: [a , ' ' , b asText])]])")
      true)))

;; ── SX boundary ──
(define asText (fn (node) (str (st-send node "asText" (list)))))
(define content/text asText)
(define block-text asText)

;; excerpt: first n chars of the plain text, with an ellipsis if truncated.
(define
  content/excerpt
  (fn
    (doc n)
    (let
      ((t (asText doc)))
      (if
        (<= (string-length t) n)
        t
        (str (substring t 0 n) "…")))))
