markdown
1 Quick start
1.1 Syntax supported
John Gruber’s original description.
Enhancements controlled by the current-strict-markdown? parameter.
1.2 Use at the command line, to generate HTML
You can run this at the command-line: Pipe in markdown and it pipes out HTML.
$ raco markdown I am _emph_ and I am **strong**. ^D <!DOCTYPE html> <html> <head> <meta charset="utf-8" /></head> <body> <p>I am <em>emph</em> and I am <strong>strong</strong>.</p></body></html>
1.3 Use as a library, to generate xexprs and HTML
Use parse-markdown to convert a string? or path? to a (listof xexpr?).
You can modify the (listof xexpr?), splice it into the body element of an (html ...) wrapper, and convert to HTML text.
(require markdown)
; 1. Parse string to a list of xexprs
(define xs (parse-markdown "I am _emph_ and I am **strong**."))
xs '((p () "I am " (em () "emph") " and I am " (strong () "strong") "."))
; 2. Optionally, process the xexprs somehow: ; ... nom nom nom ... ; 3. Splice them into an HTML `xexpr` and... ; 4. Convert to HTML text:
(display-xexpr `(html () (head ()) (body () ,@xs)))
<html>
<head></head>
<body>
<p>I am <em>emph</em> and I am <strong>strong</strong>.</p></body></html>
display-xexpr is provided as a "warm bowl of porridge" —
1.4 Use as a library, to generate "pre-Scribble"
The xexprs returned by
read-markdown can also be fed to the function
xexprs->scribble-pres, which returns a Scribble
representation —
2 Notes
Originally this was implemented using a pile of regular expressions,
somewhat like how Markdown.pl works —
In October 2013 I redesigned it to be a "real" parser with a grammar, using Stephen Chang’s parsack, a monadic parser combinator library. The grammar was developed by looking first at peg-markdown and later at pandoc. For a few edge cases I found Babelmark and Babelmark2 helpful to compare result with many other implementations. The many unit tests from the old version also helped.
2.1 Links
3 API
(require markdown) | package: markdown |
The markdown module provides all bindings from the markdown/display-xexpr, markdown/parse, and markdown/toc modules.
3.1 Parsing Markdown
(require markdown/parse) | package: markdown |
procedure
(parse-markdown input [ footnote-prefix-symbol?]) → (listof xexpr?) input : (or/c path? string?) footnote-prefix-symbol? : symbol? = (gensym)
When given a string?, parses the string as a markdown file. When given a path?, calls file->string and parses the result.
Deletes all \r (including but not limited to \r\n).
Appends a \r\n to simplify whole-document processing.
parameter
(current-strict-markdown? strict?) → void? strict? : boolean?
= #f
Fenced code blocks using triple backticks ```. An optional language descriptor may follow the opening backticks. This results in the code element getting a class attribute whose value is brush: lang.
Inline code using single backticks may be followed by a language descriptor in square brackets. This results in the code element getting a class attribute whose value is brush: lang.
Heading elements get an id attribute whose value is a "slug" of the heading text.
Images alone in their own paragraph are nested in a in div.figure along with a p.caption element following the img.
"Smart" punctuation (hyphens, dashes, single and double quotes, aspostrophes, prime, ellipses).
Footnote definitions and references as in PHP Markdown Extra and Python-Markdown.
Support for math-jax expressions —
inline within \\( and \\) delimiters and display within \\[ and \\] delimiters — resulting in eqivalent markup in the output.
procedure
(read-markdown [footnote-prefix-symbol?]) → (listof xexpr?)
footnote-prefix-symbol? : symbol? = (gensym)
NOTE: This function is deprecated; use parse-markdown, instead.
3.2 Building a Table of Contents
(require markdown/toc) | package: markdown |
> (toc (parse-markdown (string-join '("# 1" "## 1.1" "# 2" "## 2.1") "\n\n")))
'(div
((class "toc"))
(ol
(li (a ((href "#1")) "1") (ul (li (a ((href "#11")) "1.1"))))
(li (a ((href "#2")) "2") (ul (li (a ((href "#21")) "2.1"))))))
3.3 Displaying Parsed Markdown
(require markdown/display-xexpr) | package: markdown |
procedure
(display-xexpr xexpr) → any/c
xexpr : xexpr?
procedure
(xexpr->string xexpr) → string?
xexpr : xexpr?
3.4 Generating Pre-Scribble
(require markdown/scrib) | package: markdown |
The bindings documented in this section are not provided by the markdown module.
procedure
(xexprs->scribble-pres xexprs [convert])
→ (listof (or/c pre-part? pre-flow? pre-content?)) xexprs : (listof xexpr?)
convert : (-> xexpr? (or/c #f pre-part? pre-flow? pre-content?)) = (lambda _ #f)
Caveat: This is provided as a possible convenience. Like any "do what I mean" function, it might not do so. It only handles the subset of HTML produced by read-markdown. Furthermore, you might not like its choice of Scribble representation for any given x-expression. You may override this by supplying an optional convert function, which should return either a Scribble element or #f to accept the default conversion.
#lang racket/base (require markdown markdown/scrib net/sendurl racket/class racket/format racket/runtime-path scribble/base-render scribble/decode scribble/html-render) (define work-dir (find-system-path 'temp-dir)) (define (build-html-doc docs dest-file) (let* ([renderer (new (render-mixin render%) [dest-dir work-dir])] [fns (list (build-path work-dir dest-file))] [fp (send renderer traverse docs fns)] [info (send renderer collect docs fns fp)] [r-info (send renderer resolve docs fns info)]) (send renderer render docs fns r-info) (send renderer get-undefined r-info))) (define-runtime-path test.md "test/test.md") (define part (decode (xexprs->scribble-pres (with-input-from-file test.md read-markdown)))) (build-html-doc (list part) "test.html") (send-url (~a "file://" work-dir "test.html"))