# 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
* **CommonMark Compatible**: Supports standard Markdown syntax like headers, lists, blockquotes, code blocks, emphasis, and links.
* **Macro System**: unique TeX-like macro system (`%macro{arg1}{arg2}`) that powers the entire rendering process.
* **Custom Markups**: Define custom prefix or delimited markup patterns that transform into macro calls.
* **Customizable**: Define your own macros using the `%def` intrinsic.
* **Two-Step Rendering**: Exposes the syntax tree for inspection or modification before rendering to HTML.
## 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:
* `# 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.
## Building
MacroDown uses CMake for building. You will need a C++23 compliant compiler.
```bash
mkdir build
cd build
cmake ..
make
```
## Integration
### Using FetchContent
You can add MacroDown to your project using CMake's `FetchContent`.
```cmake
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:**
```bash
./macrodown input.md > output.html
```
**From stdin:**
```bash
echo "# Hello World" | ./macrodown
```
### Library Interface
You can integrate MacroDown into your C++ projects using the `MacroDown` class.
```cpp
#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:
```markdown
%def[greet]{name}{Hello, %strong{%name}!}
%greet{World}
```
Output:
```html
<p>Hello, <strong>World</strong>!</p>
```
Or programmatically in C++:
```cpp
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.
```cpp
// 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.
```cpp
// Transforms :important: into %highlight{important}
md.defineDelimitedMarkup({":", "highlight"});
md.evaluator().define("highlight", {"content"}, "<mark>%content</mark>");
```
## Testing
To run the unit tests:
```bash
cd build
./macrodown_test
```
## Project Structure
* `include/`: Header files.
* `src/`: Source code.
* `tests/`: Unit and integration tests.
* `design.md`: Detailed design document.