;; content-on-sx — Markdown render mode. ;; ;; A third boundary format alongside asHTML / asSx, via the same polymorphic ;; dispatch. The newline is supplied by the boundary as a keyword arg ;; (asMarkdown: nl) because this Smalltalk dialect has no Character newline ;; constructor — blocks that need internal newlines (code, lists, doc) use it. ;; ;; No Markdown escaping yet (Markdown's escaping rules differ from HTML); raw ;; text is emitted. Ordered lists emit "1." for every item (Markdown renumbers). ;; ;; Requires (loaded by harness): block.sx, doc.sx. (define content-bootstrap-markdown! (fn () (begin (ct-def-method! "CtHeading" "asMarkdown:" "asMarkdown: nl | h i | h := ''. i := 0. [i < level] whileTrue: [h := h , '#'. i := i + 1]. ^ h , ' ' , text") (ct-def-method! "CtText" "asMarkdown:" "asMarkdown: nl ^ text") (ct-def-method! "CtCode" "asMarkdown:" "asMarkdown: nl ^ '```' , language , nl , text , nl , '```'") (ct-def-method! "CtQuote" "asMarkdown:" "asMarkdown: nl ^ '> ' , text") (ct-def-method! "CtImage" "asMarkdown:" "asMarkdown: nl ^ '![' , alt , '](' , src , ')'") (ct-def-method! "CtEmbed" "asMarkdown:" "asMarkdown: nl ^ '[embed](' , url , ')'") (ct-def-method! "CtDivider" "asMarkdown:" "asMarkdown: nl ^ '---'") (ct-def-method! "CtList" "asMarkdown:" "asMarkdown: nl | mark | mark := ordered ifTrue: ['1. '] ifFalse: ['- ']. ^ (items inject: '' into: [:a :x | a , (a = '' ifTrue: [''] ifFalse: [nl]) , mark , x])") (ct-def-method! "CtDoc" "asMarkdown:" "asMarkdown: nl ^ (blocks inject: '' into: [:a :b | a , (a = '' ifTrue: [''] ifFalse: [nl , nl]) , (b asMarkdown: nl)])") true))) (define ct-nl (str "\n")) ;; ── SX boundary ── (define asMarkdown (fn (node) (str (st-send node "asMarkdown:" (list ct-nl))))) (define content/markdown asMarkdown) (define render-markdown asMarkdown) (define block-markdown asMarkdown)