mdpp(1)

Markdown preprocessor for cross-file code, table, title synchronization, and file inclusion. Processing is idempotent.
INSTALLATION
Pre-built binaries are available at Releases.
Build from source:
go install github.com/knaka/mdpp/cmd/mdpp@latest
SYNOPSIS
Concatenate the rewritten results and output to standard output:
mdpp input1.md input2.md >output.md
In-place rewriting:
mdpp -i rewritten1.md rewritten2.md
DESCRIPTION
mdpp(1) is a Markdown preprocessor that synchronizes code blocks, tables, and link titles across files, and includes external Markdown files using special HTML comment directives. It is designed for use in documentation build pipelines or as an editor integration to keep Markdown content up-to-date with source files and other Markdown documents.
Supported Directives
+SYNC_TITLE / +TITLE
Replaces the link text with the title from the target Markdown file.
The title is determined in the following order of priority:
- The
title property in YAML Front Matter
- The only H1 (
#) heading in the document (if there is exactly one)
- The file name (without extension)
Input:
[link text](docs/hello.md)<!-- +SYNC_TITLE -->
Output:
[Hello document](docs/hello.md)<!-- +SYNC_TITLE -->
+MILLER / +MLR
Processes the table above the directive using a Miller script. This feature is inspired by the #+TBLFM: ... line comment of Emacs Org-mode.
Input:
| Item | Unit Price | Quantity | Total |
| --- | --- | --- | --- |
| Apple | 2.5 | 12 | 0 |
| Banana | 2.0 | 5 | 0 |
| Orange | 1.2 | 8 | 0 |
<!-- +MLR:
$Total = ${Unit Price} * $Quantity;
-->
Output:
| Item | Unit Price | Quantity | Total |
| --- | --- | --- | --- |
| Apple | 2.5 | 12 | 30 |
| Banana | 2.0 | 5 | 10 |
| Orange | 1.2 | 8 | 9.6 |
<!-- +MLR:
$Total = ${Unit Price} * $Quantity;
-->
+INCLUDE ... +END
Includes the content of an external Markdown file.
Input:
<!-- +INCLUDE: path/to/another.md -->
<!-- +END -->
Output (after running mdpp):
<!-- +INCLUDE: path/to/another.md -->
## Content from another.md
This is the content of `another.md`.
<!-- +END -->
Features:
- Nested inclusion: Files included with
+INCLUDE can contain their own +INCLUDE directives, supporting multiple levels of nesting.
- Cycle detection: The processor automatically detects and prevents infinite loops when files include each other in a cycle.
Limitations:
- Indented directives: The
+INCLUDE and +END directives must be at the beginning of their lines (ignoring leading/trailing whitespace). Indented directives within code blocks or blockquotes are not supported.
- Relative path resolution: When including a file from another directory, relative paths within the included content (such as image paths) are not automatically resolved relative to the included file's location. They remain relative to the main document's directory.
+CODE
Inserts the contents of an external file into a fenced or indented code block.
Input (fenced code block):
```
foo
bar
```
<!-- +CODE: path/to/file.c -->
Output (after running mdpp):
```
#include <stdio.h>
int main(int argc, char** argv) {
printf("Hello, World!\n");
return 0;
}
```
<!-- +CODE: path/to/file.c -->
Input (indented code block):
int x = 0;
printf("%d", x);
<!-- +CODE: path/to/file.c -->
Output (indented code block):
#include <stdio.h>
int main(int argc, char** argv) {
printf("Hello, World!\n");
return 0;
}
<!-- +CODE: path/to/file.c -->
USAGE EXAMPLES
-
Write to standard output:
mdpp README.md >README.out.md
-
In-place update (for editor integration):
mdpp -i README.md
For in-place usage, VSCode's plugin “Run on Save” can automatically run mdpp when saving a Markdown file. Example settings:
"emeraldwalk.runonsave": {
"commands": [
{
"match": "\\.md$",
"cmd": "mdpp -i ${file}"
}
]
},
NOTES
- Directives must be written as HTML comments immediately after the relevant code block, table block, or link inline-element.
- For
+INCLUDE directives, both +INCLUDE and +END comments must be at the beginning of their lines (ignoring leading/trailing whitespace).
- Directive names are case-insensitive.
- The output preserves the directive comments, so repeated runs are idempotent.
- Title extraction uses the following priority:
- The
title property in YAML Front Matter
- The only H1 (
#) heading in the document (if there is exactly one)
- The file name (without extension)
LICENSE
MIT License