comrak
| Language | Rust |
|---|---|
| License | BSD-2-Clause |
| Repository | github.com/kivikakk/comrak |
| Documentation | docs.rs/comrak |
| Depends on | typed-arena, caseless, finl_unicode, memchr, phf, smallvec; optional syntect (highlighting), emojis, clap (CLI) |
| Read / write | parses CommonMark + GFM + many extensions; renders HTML, CommonMark and XML |
comrak is a Rust port of GitHub’s cmark-gfm. It passes the CommonMark and GFM spec tests, builds an arena-allocated AST of AstNodes, and renders it with format_html, format_commonmark or format_xml. Options are grouped into extension, parse and render. Beyond GFM (strikethrough, table, autolink, tasklist) it supports footnotes, front matter, header IDs, description lists, superscript and subscript, alerts, math, wiki links, underline, spoilers, emoji shortcodes and more. The Ruby gem commonmarker and many Rust tools use it.
Like cmark, it’s safe by default: raw HTML and dangerous links are removed unless you set render.r#unsafe = true.
Installation#
cargo add comrak
Basic usage: convert Markdown to HTML#
use comrak::{markdown_to_html, Options};
use std::fs;
fn main() -> std::io::Result<()> {
let markdown = fs::read_to_string("README.md")?;
let mut options = Options::default();
options.extension.strikethrough = true;
options.extension.table = true;
options.extension.autolink = true;
options.extension.tasklist = true;
options.extension.footnotes = true;
let html = markdown_to_html(&markdown, &options);
fs::write("README.html", html)?;
Ok(())
}
How to add heading IDs and skip front matter#
let mut options = Options::default();
options.extension.header_id_prefix = Some(String::new()); // <h2 id="install">
options.extension.front_matter_delimiter = Some("---".to_string()); // YAML block becomes a FrontMatter node
How to list headings and links#
use comrak::nodes::NodeValue;
use comrak::{parse_document, Arena, Options};
let arena = Arena::new();
let root = parse_document(&arena, &markdown, &Options::default());
for node in root.descendants() {
match &node.data().value {
NodeValue::Heading(h) => println!("heading level {}", h.level),
NodeValue::Link(link) => println!("link: {}", link.url),
_ => {}
}
}
How to change the document and render it#
use comrak::nodes::NodeValue;
use comrak::{format_commonmark, format_html, parse_document, Arena, Options};
let arena = Arena::new();
let options = Options::default();
let root = parse_document(&arena, &markdown, &options);
for node in root.descendants() {
if let NodeValue::Link(ref mut link) = node.data_mut().value {
link.url = link.url.replace("http://", "https://");
}
}
let mut html = String::new();
format_html(root, &options, &mut html).unwrap();
let mut md = String::new();
format_commonmark(root, &options, &mut md).unwrap();
How to render untrusted input#
Keep the defaults: raw HTML is omitted and javascript: links are dropped. If you need raw HTML, set options.render.r#unsafe = true and sanitize the output with a crate like ammonia. options.render.escape = true shows raw HTML as text instead of dropping it.
Tips#
- Nodes live in the
Arena; they’re valid as long as the arena is. options.render.hardbreaks = trueturns newlines into<br />;options.parse.smart = truemakes quotes and dashes typographic.- The
comrakbinary (cargo install comrak) converts files from the command line with the same options (--gfm,-e footnotes).