{"id":13579968,"url":"https://github.com/kivikakk/comrak","last_synced_at":"2025-05-12T15:16:03.619Z","repository":{"id":19035833,"uuid":"73984862","full_name":"kivikakk/comrak","owner":"kivikakk","description":"CommonMark + GFM compatible Markdown parser and renderer","archived":false,"fork":false,"pushed_at":"2025-05-02T11:29:06.000Z","size":2437,"stargazers_count":1318,"open_issues_count":21,"forks_count":152,"subscribers_count":14,"default_branch":"main","last_synced_at":"2025-05-08T19:02:41.315Z","etag":null,"topics":["commonmark","markdown","rust"],"latest_commit_sha":null,"homepage":"","language":"Rust","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"other","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/kivikakk.png","metadata":{"files":{"readme":"README.md","changelog":"changelog.txt","contributing":null,"funding":".github/FUNDING.yml","license":"COPYING","code_of_conduct":"CODE_OF_CONDUCT.md","threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null},"funding":{"github":["kivikakk"]}},"created_at":"2016-11-17T03:04:36.000Z","updated_at":"2025-05-08T16:24:21.000Z","dependencies_parsed_at":"2023-10-11T21:09:05.094Z","dependency_job_id":"5e8ff9b2-4457-49c3-983b-c642ed07f3e4","html_url":"https://github.com/kivikakk/comrak","commit_stats":{"total_commits":1024,"total_committers":74,"mean_commits":"13.837837837837839","dds":0.6484375,"last_synced_commit":"b27a3dd0a16c2960aad706eefa80f4c1977fca5e"},"previous_names":[],"tags_count":83,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/kivikakk%2Fcomrak","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/kivikakk%2Fcomrak/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/kivikakk%2Fcomrak/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/kivikakk%2Fcomrak/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/kivikakk","download_url":"https://codeload.github.com/kivikakk/comrak/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":253171210,"owners_count":21865280,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["commonmark","markdown","rust"],"created_at":"2024-08-01T15:01:45.381Z","updated_at":"2025-05-12T15:16:03.608Z","avatar_url":"https://github.com/kivikakk.png","language":"Rust","readme":"# [Comrak](https://github.com/kivikakk/comrak)\n\n[![Build status](https://github.com/kivikakk/comrak/actions/workflows/rust.yml/badge.svg)](https://github.com/kivikakk/comrak/actions/workflows/rust.yml)\n[![CommonMark: 652/652](https://img.shields.io/badge/commonmark-652%2F652-brightgreen.svg)](https://github.com/commonmark/commonmark-spec/blob/9103e341a973013013bb1a80e13567007c5cef6f/spec.txt)\n[![GFM: 670/670](https://img.shields.io/badge/gfm-670%2F670-brightgreen.svg)](https://github.com/kivikakk/cmark-gfm/blob/2f13eeedfe9906c72a1843b03552550af7bee29a/test/spec.txt)\n[![crates.io version](https://img.shields.io/crates/v/comrak.svg)](https://crates.io/crates/comrak)\n[![docs.rs](https://docs.rs/comrak/badge.svg)](https://docs.rs/comrak)\n\nRust port of [github's `cmark-gfm`](https://github.com/github/cmark-gfm).\n\nCompliant with [CommonMark 0.31.2](https://spec.commonmark.org/0.31.2/) in default mode.\nGFM support synced with release `0.29.0.gfm.13`.\n\n## Installation\n\nSpecify it as a requirement in `Cargo.toml`:\n\n``` toml\n[dependencies]\ncomrak = \"0.39\"\n```\n\nComrak's library supports Rust \u003cspan class=\"msrv\"\u003e1.65\u003c/span\u003e+.\n\n### CLI\n\n- Anywhere with a Rust toolchain:\n  - `cargo install comrak`\n- Many Unix distributions:\n  - `pacman -S comrak`\n  - `brew install comrak`\n  - `dnf install comrak`\n  - `nix run nixpkgs#comrak`\n\nYou can also find builds I've published in [GitHub Releases](https://github.com/kivikakk/comrak/releases), but they're limited to machines I have access to at the time of making them! [webinstall.dev](https://webinstall.dev/comrak/) offers `curl | shell`-style installation of the latest of these for your OS.\n\n## Usage\n\n\u003cdetails\u003e\n\n\u003csummary\u003eClick to expand the CLI \u003ccode\u003e--help\u003c/code\u003e output.\n\n``` console\n$ comrak --help\n```\n\n\u003c/summary\u003e\n\n```\nA 100% CommonMark-compatible GitHub Flavored Markdown parser and formatter\n\nUsage: comrak [OPTIONS] [FILE]...\n\nArguments:\n  [FILE]...\n          CommonMark file(s) to parse; or standard input if none passed\n\nOptions:\n  -c, --config-file \u003cPATH\u003e\n          Path to config file containing command-line arguments, or 'none'\n          \n          [default: /home/runner/.config/comrak/config]\n\n  -i, --inplace\n          To perform an in-place formatting\n\n      --hardbreaks\n          Treat newlines as hard line breaks\n\n      --smart\n          Use smart punctuation\n\n      --github-pre-lang\n          Use GitHub-style \u003cpre lang\u003e for code blocks\n\n      --full-info-string\n          Enable full info strings for code blocks\n\n      --gfm\n          Enable GitHub-flavored markdown extensions: strikethrough, tagfilter, table, autolink, and\n          tasklist. Also enables --github-pre-lang and --gfm-quirks\n\n      --gfm-quirks\n          Enables GFM-style quirks in output HTML, such as not nesting \u003cstrong\u003e tags, which\n          otherwise breaks CommonMark compatibility\n\n      --relaxed-tasklist-character\n          Enable relaxing which character is allowed in a tasklists\n\n      --relaxed-autolinks\n          Enable relaxing of autolink parsing, allow links to be recognized when in brackets and\n          allow all url schemes\n\n      --tasklist-classes\n          Output classes on tasklist elements so that they can be styled with CSS\n\n      --default-info-string \u003cINFO\u003e\n          Default value for fenced code block's info strings if none is given\n\n      --unsafe\n          Allow raw HTML and dangerous URLs\n\n      --gemojis\n          Translate gemojis into UTF-8 characters\n\n      --escape\n          Escape raw HTML instead of clobbering it\n\n      --escaped-char-spans\n          Wrap escaped characters in span tags\n\n  -e, --extension \u003cEXTENSION\u003e\n          Specify extension name(s) to use\n          \n          Multiple extensions can be delimited with \",\", e.g. --extension strikethrough,table\n          \n          [possible values: strikethrough, tagfilter, table, autolink, tasklist, superscript,\n          footnotes, description-lists, multiline-block-quotes, math-dollars, math-code,\n          wikilinks-title-after-pipe, wikilinks-title-before-pipe, underline, subscript, spoiler,\n          greentext, alerts]\n\n  -t, --to \u003cFORMAT\u003e\n          Specify output format\n          \n          [default: html]\n          [possible values: html, xml, commonmark]\n\n  -o, --output \u003cFILE\u003e\n          Write output to FILE instead of stdout\n\n      --width \u003cWIDTH\u003e\n          Specify wrap width (0 = nowrap)\n          \n          [default: 0]\n\n      --header-ids \u003cPREFIX\u003e\n          Use the Comrak header IDs extension, with the given ID prefix\n\n      --front-matter-delimiter \u003cDELIMITER\u003e\n          Ignore front-matter that starts and ends with the given string\n\n      --syntax-highlighting \u003cTHEME\u003e\n          Syntax highlighting for codefence blocks. Choose a theme or 'none' for disabling\n          \n          [default: base16-ocean.dark]\n\n      --list-style \u003cLIST_STYLE\u003e\n          Specify bullet character for lists (-, +, *) in CommonMark output\n          \n          [default: dash]\n          [possible values: dash, plus, star]\n\n      --sourcepos\n          Include source position attribute in HTML and XML output\n\n      --ignore-setext\n          Ignore setext headers\n\n      --ignore-empty-links\n          Ignore empty links\n\n      --experimental-minimize-commonmark\n          Minimize escapes in CommonMark output using a trial-and-error algorithm\n\n  -h, --help\n          Print help information (use `-h` for a summary)\n\n  -V, --version\n          Print version information\n\nBy default, Comrak will attempt to read command-line options from a config file specified by\n--config-file. This behaviour can be disabled by passing --config-file none. It is not an error if\nthe file does not exist.\n```\n\n\u003c/details\u003e\n\nAnd there's a Rust interface. You can use `comrak::markdown_to_html` directly:\n\n``` rust\nuse comrak::{markdown_to_html, Options};\nassert_eq!(markdown_to_html(\"Hello, **世界**!\", \u0026Options::default()),\n           \"\u003cp\u003eHello, \u003cstrong\u003e世界\u003c/strong\u003e!\u003c/p\u003e\\n\");\n```\n\nOr you can parse the input into an AST yourself, manipulate it, and then use your desired formatter:\n\n``` rust\nuse comrak::nodes::NodeValue;\nuse comrak::{format_html, parse_document, Arena, Options};\n\nfn replace_text(document: \u0026str, orig_string: \u0026str, replacement: \u0026str) -\u003e String {\n    // The returned nodes are created in the supplied Arena, and are bound by its lifetime.\n    let arena = Arena::new();\n\n    // Parse the document into a root `AstNode`\n    let root = parse_document(\u0026arena, document, \u0026Options::default());\n\n    // Iterate over all the descendants of root.\n    for node in root.descendants() {\n        if let NodeValue::Text(ref mut text) = node.data.borrow_mut().value {\n            // If the node is a text node, perform the string replacement.\n            *text = text.replace(orig_string, replacement);\n        }\n    }\n\n    let mut html = vec![];\n    format_html(root, \u0026Options::default(), \u0026mut html).unwrap();\n\n    String::from_utf8(html).unwrap()\n}\n\nfn main() {\n    let doc = \"This is my input.\\n\\n1. Also [my](#) input.\\n2. Certainly *my* input.\\n\";\n    let orig = \"my\";\n    let repl = \"your\";\n    let html = replace_text(\u0026doc, \u0026orig, \u0026repl);\n\n    println!(\"{}\", html);\n    // Output:\n    //\n    // \u003cp\u003eThis is your input.\u003c/p\u003e\n    // \u003col\u003e\n    // \u003cli\u003eAlso \u003ca href=\"#\"\u003eyour\u003c/a\u003e input.\u003c/li\u003e\n    // \u003cli\u003eCertainly \u003cem\u003eyour\u003c/em\u003e input.\u003c/li\u003e\n    // \u003c/ol\u003e\n}\n```\n\nFor a slightly more real-world example, see how I [generate my GitHub user README](https://github.com/kivikakk/kivikakk) from a base document with embedded YAML, which itself has embedded Markdown, or\n[check out some of Comrak's dependents on crates.io](https://crates.io/crates/comrak/reverse_dependencies) or [on GitHub](https://github.com/kivikakk/comrak/network/dependents).\n\n## Security\n\nAs with [`cmark`](https://github.com/commonmark/cmark) and [`cmark-gfm`](https://github.com/github/cmark-gfm#security),\nComrak will scrub raw HTML and potentially dangerous links. This change was introduced in Comrak 0.4.0 in support of a\nsafe-by-default posture, and later adopted by our contemporaries. :)\n\nTo allow these, use the `unsafe_` option (or `--unsafe` with the command line program). If doing so, we recommend the\nuse of a sanitisation library like [`ammonia`](https://github.com/notriddle/ammonia) configured specific to your needs.\n\n## Extensions\n\nComrak supports the five extensions to CommonMark defined in the [GitHub Flavored Markdown\nSpec](https://github.github.com/gfm/):\n\n- [Tables](https://github.github.com/gfm/#tables-extension-)\n- [Task list items](https://github.github.com/gfm/#task-list-items-extension-)\n- [Strikethrough](https://github.github.com/gfm/#strikethrough-extension-)\n- [Autolinks](https://github.github.com/gfm/#autolinks-extension-)\n- [Disallowed Raw HTML](https://github.github.com/gfm/#disallowed-raw-html-extension-)\n\nComrak additionally supports its own extensions, which are yet to be specced out (PRs welcome!):\n\n- Superscript\n- Header IDs\n- Footnotes\n- Description lists\n- Front matter\n- Multi-line blockquotes\n- Math\n- Emoji shortcodes\n- Wikilinks\n- Underline\n- Spoiler text\n- \"Greentext\"\n\nBy default none are enabled; they are individually enabled with each parse by setting the appropriate values in the\n[`ExtensionOptions` struct](https://docs.rs/comrak/latest/comrak/struct.ExtensionOptions.html).\n\n## Plugins\n\n### Fenced code block syntax highlighting\n\nYou can provide your own syntax highlighting engine.\n\nCreate an implementation of the `SyntaxHighlighterAdapter` trait, and then provide an instance of such adapter to\n`Plugins.render.codefence_syntax_highlighter`. For formatting a Markdown document with plugins, use the\n`markdown_to_html_with_plugins` function, which accepts your plugins object as a parameter.\n\nSee the `syntax_highlighter.rs` and `syntect.rs` examples for more details.\n\n#### Syntect\n\n[`syntect`](https://github.com/trishume/syntect) is a syntax highlighting library for Rust. By default, `comrak` offers\na plugin for it. In order to utilize it, create an instance of `plugins::syntect::SyntectAdapter` and use it in your\n`Plugins` option.\n\n## Related projects\n\nComrak's design goal is to model the upstream [`cmark-gfm`](https://github.com/github/cmark-gfm) as closely as possible\nin terms of code structure. The upside of this is that a change in `cmark-gfm` has a very predictable change in Comrak.\nLikewise, any bug in `cmark-gfm` is likely to be reproduced in Comrak. This could be considered a pro or a con,\ndepending on your use case.\n\nThe downside, of course, is that the code often diverges from idiomatic Rust, especially in the AST's extensive use of `RefCell`, and while\ncontributors have made it as fast as possible, it simply won't be as fast as some other CommonMark parsers\ndepending on your use-case. Here are some other projects to consider:\n\n- [Raph Levien](https://github.com/raphlinus)'s [`pulldown-cmark`](https://github.com/google/pulldown-cmark). It's\n  very fast, uses a novel parsing algorithm, and doesn't construct an AST (but you can use it to make one if you\n  want). `cargo doc` uses this, as do many other projects in the ecosystem.\n- [markdown-rs](https://github.com/wooorm/markdown-rs) (1.x) looks worth watching.\n- Know of another library? Please open a PR to add it!\n\nAs far as I know, Comrak is the only library to implement all of the [GitHub Flavored Markdown\nextensions](https://github.github.com/gfm) rigorously.\n\n### Elixir bindings\n\n- [mdex](https://github.com/leandrocp/mdex) - Elixir bindings for this library built with Rustler.\n  Available on Hex as [`mdex`](https://hex.pm/packages/mdex).\n\n### Python bindings\n\n- [comrak (Python package)](https://github.com/lmmx/comrak) — Python bindings for this library built with PyO3.\n  Available on PyPI as [`comrak`](https://pypi.org/project/comrak), benchmarked at 15-60x faster than pure Python alternatives.\n\n### Ruby bindings\n\n- [commonmarker](https://github.com/gjtorikian/commonmarker) - Ruby bindings for this library built with Magnus/rb-sys.\n  Available on RubyGems as [`commonmarker`](https://rubygems.org/gems/commonmarker).\n\n## Benchmarking\n\nYou'll need to [install hyperfine](https://github.com/sharkdp/hyperfine#installation), and CMake if you want to compare against `cmark-gfm`.\n\nIf you want to just run the benchmark for the `comrak` binary itself, run:\n\n``` bash\nmake bench-comrak\n```\n\nThis will build Comrak in release mode, and run benchmark on it. You will see the time measurements as reported by hyperfine in the console.\n\nThe `Makefile` also provides a way to run benchmarks for `comrak` current state (with your changes), `comrak` main branch, [`cmark-gfm`](https://github.com/github/cmark-gfm), [`pulldown-cmark`](https://github.com/raphlinus/pulldown-cmark) and [`markdown-it.rs`](https://github.com/rlidwka/markdown-it.rs). You'll need CMake, and ensure [submodules are prepared](https://stackoverflow.com/a/10168693/499609).\n\n``` bash\nmake bench-all\n```\n\nThis will build and run benchmarks across all, and report the time taken by each as well as relative time.\n\n\u003c!-- XXX: The following isn't really true at the moment, due to https://github.com/kivikakk/comrak/issues/339 --\u003e\n\n\u003c!-- Apart from this, CI is also setup for running benchmarks when a pull request is first opened. It will add a comment with the results on the pull request in a tabular format comparing the 5 versions. After that you can manually trigger this CI by commenting `/run-bench` on the PR, this will update the existing comment with new results. Note benchmarks won't be automatically run on each push. --\u003e\n\n## Contributing\n\nContributions are **highly encouraged**; if you'd like to assist, consider checking out the [`good first issue` label](https://github.com/kivikakk/comrak/issues?q=is%3Aissue+is%3Aopen+label%3A%22good+first+issue%22)! I'm happy to help provide direction and guidance throughout, even if (especially if!) you're new to Rust or open source.\n\nWhere possible I practice [Optimistic Merging](http://hintjens.com/blog:106) as described by Peter Hintjens. Please keep the [code of conduct](CODE_OF_CONDUCT.md) in mind too.\n\nThank you to Comrak's many contributors for PRs and issues opened!\n\n### Code Contributors\n\n[![Small chart showing Comrak contributors.](https://opencollective.com/comrak/contributors.svg?width=890\u0026button=false)](https://github.com/kivikakk/comrak/graphs/contributors)\n\n### Financial Contributors\n\nBecome a financial contributor and help sustain Comrak's development.  I'm\nself-employed — open-source software relies on the collective.\n\n- [GitHub Sponsors](https://github.com/sponsors/kivikakk)\n\n## Contact\n\nAsherah Connor \u003cashe kivikakk ee\\\u003e\n\n## Legal\n\nCopyright (c) 2017–2025, Comrak contributors. Licensed under\nthe [2-Clause BSD License](https://opensource.org/licenses/BSD-2-Clause).\n\n`cmark` itself is is copyright (c) 2014, John MacFarlane.\n\nSee [COPYING](COPYING) for all the details.\n","funding_links":["https://github.com/sponsors/kivikakk"],"categories":["Uncategorized","Rust","Projects"],"sub_categories":["Uncategorized"],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fkivikakk%2Fcomrak","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fkivikakk%2Fcomrak","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fkivikakk%2Fcomrak/lists"}