BareGit
Commits
Clone:
Name Latest commit Last update
📂 include
📂 src
📂 tests
📄 CMakeLists.txt Export library target and add FetchContent integration instructions 9 days ago
📄 README.md Export library target and add FetchContent integration instructions 9 days ago
📄 design.md Enhance custom markup with regex patterns and extended character support 10 days ago
📄 prd.md Enhance custom markup with regex patterns and extended character support 10 days ago

MacroDown

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.

Features

How it Works

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:

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.

Building

MacroDown uses CMake for building. You will need a C++23 compliant compiler.

mkdir build
cd build
cmake ..
make

Integration

Using FetchContent

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)

Usage

CLI

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

Library Interface

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;
}

Defining Macros

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!");

Custom Markups

MacroDown allows you to define custom shorthand syntax that maps to macros.

Prefix Markups

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>");

Delimited Markups

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>");

Testing

To run the unit tests:

cd build
./macrodown_test

Project Structure