markdown
Overview
Fantom library for parsing and rendering Markdown text according to the CommonMark specification.
Usage
using markdown
parser := Parser()
doc := parser.parse("This is *Markdown*")
renderer := HtmlRenderer()
html := renderer.render(doc) // => "<p>This is <em>Markdown</em></p>\n"
This uses the parser and renderer with default options. Both have builders for configuring their behavior. See ParserBuilder and HtmlRendererBuilder for more details.
Use a visitor to process parsed nodes
After the source text has been parsed, the result is a tree of nodes. That tree can be modified before rendering, or just inspected without rendering. See Visitor and the HTML rendering example below.
HTML Rendering
You can take complete control over how HTML is rendered.
In this example, we're changing the rendering of indented code blocks to only wrap them in pre instead of pre and code:
parser := Parser()
renderer := HtmlRenderer.builder
.nodeRendererFactory(|HtmlContext cx->NodeRenderer| { IndentedCodeBlockRendere(cx) })
.build
html := renderer.render(parser.parse("Example:\n\n code"))
// "<p>Example:</p><pre>code</pre>\n"
class IndentedCodeBlockRenderer : NodeRenderer, Visitor
{
new make(HtmlContext cx) { this.html = cx.writer }
private HtmlWriter html
** We only want to override rendering of the Code node type
override const Type nodeTypes := [Code#]
override Void render(Node node) { node.walk(this) }
override Void visitIndentedCode(IndentedCode code)
{
html.line
.tag("pre")
.text(code.literal)
.tag("/pre")
.line
}
}
Add your own node types
In case you want to store additional data in the document, or have custom elements in the resulting HTML, you can create your own subclass of CustomNode or CustomBlock and add instances as child nodes to existing nodes.
To define the HTML rendering for them, you can use a NodeRenderer as explained above.
Plaintext Rendering
You can also render markdown to plaintext with most formatting removed. The builder for the TextRenderer supports various methods or rendering line breaks depending on your use case.
// Generate plaintext using the default "compact" rendering
doc := Parser().parse("Here, the **emphasis** is ignored")
str := TextRenderer().render(doc) // => Here the emphasis is ignored
Customize parsing
There are a few ways to extend parsing or even override built-in parsing, all of them via methods on Parser.builder. See Section 3 (Blocks and Inlines) of the spec for an overview of blocks/inlines.
- Parsing of specific block types (e.g. headings, code blocks, etc.) can be enabled/disabled with
withEnabledBlockTypes - Parsing of blocks can be extended/overridden with
customBlockParserFactory - Parsing of inline content can be extended/overridden with
customInlineContentParserFactory - Processing of links can be customized with
linkProcessorandlinkMarker
Thread-safety
Both the Parser and the HtmlRenderer are designed so that you can configure them once and then use them multiple times/from multiple Actors.
Extensions
Extensions are used to extend the parser, the HTML renderer, or both. Extensions are configured on the various builders using the extensions() method. The default parser and HTML renderer conform to the CommonMark specification. This library includes some built-in extensions that you can optionally enable.
For example, the following code enables the ImgAttrsExt which allows you to specify attributes for images.
using markdown exts := [ImgAttrsExt()] parser := Parser.builder.extensions(exts).build renderer := HtmlRenderer.builder.extensions(exts).build
Image Attributes
Adds support for specifying attributes (specifically height and width) for images. Use ImgAttrsExt to enable this extension.
The attribute elements are given as key=value pairs inside curly braces { } after the image node to which they apply. For example:
{width=640 height=480}
will be rendered as
<img src="/url.png" alt="text" width="640" height="480" />
Tables
Enables tables using pipes as in Github Flavored Markdown. See TablesExt.
| Header1 | Header2 | | ------- | ------- | | foo | bar |