sigildocs

Markdown

Parse Markdown text into SXML for use with (sigil sxml). Supports CommonMark-style syntax with YAML front matter.
(import (sigil markdown))

markdown->sxml

Parse a Markdown string to an SXML document. Returns a document element containing the parsed content. YAML front matter becomes attributes on the document element.

(markdown->sxml "# Hello\n\nWorld")
; => (document (h1 "Hello") (p "World"))

(markdown->sxml "---\ntitle: Hello\n---\n\n# Content")
; => (document (@ (title "Hello")) (h1 "Content"))

;; Inline formatting
(markdown->sxml "**bold** and *italic*")
; => (document (p (strong "bold") " and " (em "italic")))

;; Links and images
(markdown->sxml "[Sigil](https://sigil.dev)")
; => (document (p (a (@ (href "https://sigil.dev")) "Sigil")))

markdown-file->sxml

Read a file and parse its contents as Markdown.

(markdown-file->sxml "README.md")
; => (document (h1 "Project Name") (p "Description...") ...)

Supported Syntax

MarkdownSXML Tag
# H1 ... ###### H6(h1 ...) ... (h6 ...)
Blank-line separated text(p ...)
Fenced ` or indented(pre ...) or (pre (@ (lang "x")) ...)
> quoted text(blockquote ...)
- item(ul (li ...))
1. item(ol (li ...))
---(hr)
`\col \col \`(table (thead ...) (tbody ...))
` code `(code "...")
**bold**(strong ...)
*italic*(em ...)
[text](url)(a (@ (href "url")) "text")
![alt](src)(img (@ (src "src") (alt "alt")))

SXML Output Format

Code blocks with a language annotation:

(markdown->sxml "```scheme\n(+ 1 2)\n```")
; => (document (pre (@ (lang "scheme")) "(+ 1 2)"))

Tables produce thead/tbody structure with optional alignment:

(markdown->sxml "| Name | Age |\n|------|----:|\n| Alice | 30 |")
; => (document
;      (table
;        (thead (tr (th "Name") (th (@ (style "text-align: right")) "Age")))
;        (tbody (tr (td "Alice") (td (@ (style "text-align: right")) "30")))))

Lists nest inline formatting:

(markdown->sxml "- **bold** item\n- *italic* item")
; => (document (ul (li (strong "bold") " item") (li (em "italic") " item")))

Front Matter

YAML front matter is delimited by --- lines at the start of a document. Values are auto-typed: numbers become numbers, true/false become booleans, and snake_case keys are converted to kebab-case symbols.

(markdown->sxml "---\ntitle: Hello World\npost_count: 42\ndraft: true\n---\n\nContent")
; => (document (@ (title "Hello World") (post-count 42) (draft #t))
;      (p "Content"))

parse-front-matter

Parse front matter from a list of lines. Returns a pair of (metadata . remaining-lines) where metadata is an alist, or (#f . lines) if no front matter is present.

(parse-front-matter '("---" "title: Hello" "---" "" "# Content"))
; => (((title . "Hello")) "" "# Content")

(parse-front-matter '("# No front matter"))
; => (#f "# No front matter")

parse-yaml-line

Parse a single key: value line. Returns a pair or #f.

(parse-yaml-line "title: Hello World")  ; => (title . "Hello World")
(parse-yaml-line "count: 42")           ; => (count . 42)
(parse-yaml-line "no colon here")       ; => #f

parse-yaml-value

Parse a YAML value string into a typed Scheme value.

(parse-yaml-value "42")       ; => 42
(parse-yaml-value "true")     ; => #t
(parse-yaml-value "\"hi\"")   ; => "hi"
(parse-yaml-value "hello")    ; => "hello"

Lower-Level API

parse-blocks

Parse Markdown block elements from a list of lines. Returns a list of block structures (headers, paragraphs, code blocks, lists, tables, etc.).

(parse-blocks '("# Hello" "" "World"))
; => ((header 1 "Hello") (paragraph ("World")))

parse-inline

Parse inline Markdown elements from a text string. Returns a list of strings and SXML elements.

(parse-inline "Hello **world**")
; => ("Hello " (strong "world"))

(parse-inline "`code` and [link](url)")
; => ((code "code") " and " (a (@ (href "url")) "link"))

string->lines

Split a string into a list of lines on newline boundaries.

(string->lines "a\nb\nc")  ; => ("a" "b" "c")

Common Patterns

Convert Markdown to HTML

(import (sigil markdown)
        (sigil sxml))

(define (markdown->html text)
  (let ((doc (markdown->sxml text)))
    (sxml->html doc)))

Extract Metadata from a Post

(let* ((doc (markdown-file->sxml "post.md"))
       (attrs (and (pair? (cdr doc))
                   (pair? (cadr doc))
                   (eq? (caadr doc) ,@)
                   (cdadr doc))))
  (assq 'title attrs))
; => (title "My Post Title")

Use with sigil-publish

(import (sigil publish))

;; sigil-publish automatically uses (sigil markdown) for .md files.
;; The markdown classifier reads front matter during scanning and
;; parses full content during rendering.
(define my-site
  (site title: "My Blog"
        content: "posts/**/*.md"))

(run-publish my-site)