Usage
This page assumes (cmark gfm) already imports; see
installing.md if it doesn't yet.
Getting started
(import (cmark gfm))
;; Safe by default: raw HTML and unsafe link schemes are suppressed.
(markdown->html "# Hello\n\n~~struck~~\n" (default-cmark-options))
Every renderer takes a cmark-options record as its second argument.
(default-cmark-options) is the one every example on this page starts
from — its ten fields are the whole subject of options.md.
Options are named symbols, passed as a plist, not positional arguments and not a mutable struct:
;; Unknown keys, duplicate keys, and unknown extensions are rejected before
;; anything native is allocated.
(markdown->html "<b>raw</b>\n" (make-cmark-options 'unsafe-html? #t))
make-cmark-options returns a new, immutable record. To change one field of
an existing record, use cmark-options-with — it rebuilds from the
original's current values plus your overrides, and the original stays
exactly as it was:
(define base (make-cmark-options 'extensions '(table)))
(markdown->html "| a |\n|---|\n| 1 |\n" (cmark-options-with base 'smart? #t))
;; base still has smart? #f -- cmark-options-with returned a third record.
The blocks above are adapted from
examples/01-rendering.sps and
examples/02-options.sps. make examples runs
every file under examples/ and diffs its output against a pinned
expectation, so those two files cannot go stale silently — but these
adapted copies are not re-checked against them, so verify by eye if either
file changes.
Parsing to a Scheme-owned tree is ast.md; converting to SXML is sxml.md. Every condition any entry point on this page can raise is catalogued in errors.md.
The renderers
Four entry points, all taking the Markdown source first and a
cmark-options record second:
| Entry point | Arity | Wraps |
|---|---|---|
markdown->html | (md options) | no |
markdown->xml | (md options) | no |
markdown->commonmark | (md options), or (md options width) | yes |
markdown->plaintext | (md options), or (md options width) | yes |
(markdown->commonmark "long paragraph text here\n" base 72)
(markdown->plaintext "long paragraph text here\n" base 72)
(markdown->xml "# Hello\n" base)
markdown->html and markdown->xml are defined at a fixed arity of two.
markdown->commonmark and markdown->plaintext are case-lambdas that
accept either two or three arguments — see Wrap width for
what the third one means, and what happens if you hand it to the wrong
renderer.
Wrap width
Width is a positional argument to the renderer, not a field of
cmark-options. That follows cmark's own split: option bits
(validate-utf8?, hardbreaks?, and the rest) govern both the parser and
the renderer, but width only ever applies to some renderers, so it lives
outside the record the parser and every renderer otherwise share.
On
markdown->commonmarkandmarkdown->plaintext, width is optional. Leaving it out is equivalent to passing0, which cmark treats as "do not wrap" — the two forms produce byte-identical output.markdown->htmlandmarkdown->xmlhave no width clause at all. Passing a third argument to either is a plain Scheme wrong-number-of-arguments error — not&cmark-invalid-option, and not a setting that gets silently ignored. There is nowhere for it to go.A width that is accepted positionally but is negative or inexact raises one of this library's own conditions instead, checked before any native resource is acquired:
(guard (e ((cmark-invalid-option? e) (list (cmark-invalid-option-key e) (cmark-invalid-option-reason e)))) (markdown->commonmark "hi\n" base -1)) ;; => (width invalid-width)
See errors.md for &cmark-invalid-option and every other
condition this library raises.
Which library is loaded
Three calls report on the native library itself, independent of anything passed to a renderer:
(cmark-gfm-version) ;; => "0.29.0.gfm.13"
(cmark-gfm-version-compatible?) ;; => #t
(cmark-gfm-available-extensions) ;; => (autolink strikethrough table tagfilter tasklist)
cmark-gfm-version and cmark-gfm-version-compatible? report on whatever
(import (cmark gfm)) already found — the same discovery
make build runs as a standalone
preflight, available here as a procedure instead of a command's exit code.
cmark-gfm-available-extensions is not the same thing as
supported-extensions. supported-extensions is pure: it names the five
extensions this binding knows how to translate to and from cmark's own
strings, with no native call involved, and it's the list make-cmark-options
checks an 'extensions entry against. cmark-gfm-available-extensions
instead probes the loaded library and returns only the subset actually
registered there.
The two coincide on the library this machine loaded. Nothing guarantees
that on every host: make-cmark-options accepting an extension symbol only
means this binding knows the name, not that the library on a given machine
has it registered. That's checked separately, per extension, when a
document is parsed — a genuinely missing one raises
&cmark-extension-unavailable naming it (see errors.md).