MacroDown is a C++ Markdown processor that extends the CommonMark syntax with a powerful TeX-like macro system. It treats all markup elements as syntactic sugar for macro calls, allowing for extensive customization and extension.
%macro{arg1}{arg2}) that powers the entire rendering process.%def intrinsic.MacroDown uses a unified approach to document processing. Instead of having separate logic for every Markdown element, the parser first transforms standard Markdown syntax into an internal tree of macro calls.
For example:
# Heading is converted to %h1{Heading}*Emphasis* is converted to %em{Emphasis}> Quote is converted to %quote{Quote}These macros are then evaluated using a standard library of definitions that produce the final HTML output. This architecture makes it incredibly easy to change the output of standard Markdown elements by simply redefining their corresponding macros.
MacroDown uses CMake for building. You will need a C++23 compliant compiler.
mkdir build
cd build
cmake ..
make
You can add MacroDown to your project using CMake's FetchContent.
include(FetchContent)
FetchContent_Declare(
macrodown
GIT_REPOSITORY https://git.xeno.darksair.org/macrodown.git
GIT_TAG master # Or a specific tag/commit
)
FetchContent_MakeAvailable(macrodown)
# Link to the library
target_link_libraries(your_target PRIVATE MacroDown::MacroDown)
You can use the macrodown executable to convert Markdown to HTML.
From a file:
./macrodown input.md > output.html
From stdin:
echo "# Hello World" | ./macrodown
You can integrate MacroDown into your C++ projects using the MacroDown class.
#include "macrodown.h"
#include <iostream>
int main() {
macrodown::MacroDown md;
std::string input = "# Hello\n\nThis is **MacroDown**.";
// Step 1: Parse to Syntax Tree
auto root = md.parse(input);
// Step 2: Render to HTML
std::string html = md.render(*root);
std::cout << html << std::endl;
return 0;
}
You can define macros directly in your Markdown document:
%def[greet]{name}{Hello, %strong{%name}!}
%greet{World}
Output:
<p>Hello, <strong>World</strong>!</p>
Or programmatically in C++:
md.evaluator().define("greet", {"name"}, "Hello, %name!");
MacroDown allows you to define custom shorthand syntax that maps to macros.
Useful for tags or mentions. A prefix markup starts with a character and ends at a whitespace or punctuation boundary.
// Transforms #test into %tag{test}
md.definePrefixMarkup({"#", "tag", ""});
md.evaluator().define("tag", {"content"}, "<span class=\"tag\">#%content</span>");
Useful for custom inline styles. A delimited markup starts and ends with the same character.
// Transforms :important: into %highlight{important}
md.defineDelimitedMarkup({":", "highlight"});
md.evaluator().define("highlight", {"content"}, "<mark>%content</mark>");
To run the unit tests:
cd build
./macrodown_test
include/: Header files.src/: Source code.tests/: Unit and integration tests.design.md: Detailed design document.