md-inc - Include files in Markdown docs

Overview

Preview

Example

Here is a code file, file.rs, that we want to include in our Markdown document:

rust fn main() { println!("Hello, World!"); }

The file can be included using command tags, sneakily disguised as comments so they aren't rendered in the actual document: markdown Look at the following rust code: <!--{ "file.rs" | code: rust }--> <!--{ end }--> This will print 'Hello World' to the console.

After running md-inc, the file will be transformed into: markdown Look at the following rust code: <!--{ "file.rs" | code: rust }--> ```rust fn main() { println!("Hello, World!"); } ``` <!--{ end }--> This will print 'Hello World' to the console.

Note: The surrounding ```rust and ``` lines were inserted because we piped the input into the code: rust command. More on this later!

Install

bash cargo install md-inc

Run

bash md-inc [FLAGS] [OPTIONS] [files]...

If no files are given, the files field in .md-inc.toml is used.

Configuration

.md-inc.toml can be configured by setting any of the following:

open_tag: The opening tag for a command ```toml

^^^^^

open_tag = "

^^^^

close_tag = "}-->" ```

end_command: The name to use for the end command ```toml

<>

^^^

end_command = "end" ```

base_dir: The base directory for relative imported file paths, relative to the config file ```toml

For the directory tree:

├╼ README.md

├╼ .md-inc.toml

╰╼ doc

├╼ file.txt

╰╼ other

╰╼ file2.txt

If base_dir = "doc", then files can be named relative to doc

...

basedir = "doc" `files`: A list of files to be transformed, relative to the config file toml files = ["README.md", "doc/file.md"] `depend_dirs`: A list of directories containing ".md-inc.toml" that will be visited before this one. toml dependdirs = ["doc/example1", "doc/example2"] ```

next_dirs: A list of directories containing ".md-inc.toml" that will be visited after this one. toml next_dirs = ["doc/example1", "doc/example2"] Note: "dependdirs" and "nextdirs" are NOT called recursively.

out_dir: An optional output directory for generated files. If this is defined, the generated files will be written to this directory instead of overwriting the original files. toml out_dir = "path/to/output"

Commands

Included files can be manipulated by piping commands together.

General Syntax:

Include file.txt: markdown <!--{ "file.txt }--> <!--{ end }--> Include file.txt inside a code block: markdown <!--{ "file.txt | code }--> <!--{ end }--> Include file.py inside a code block with python syntax highlighting: markdown <!--{ "file.py" | code: python }--> <!--{ end }--> Include only lines 4 to 10 of file.py inside a code block with python syntax highlighting: markdown <!--{ "file.py" | lines: 4 10 | code: python }--> <!--{ end }-->

code: [language]

Without language: markdown <!--{ "doc/file.txt" | code }--> ``` FILE_CONTENTS ``` <!--{ end }-->

With language: markdown <!--{ "doc/file.html" | code: html }--> ```html FILE_CONTENTS ``` <!--{ end }-->

lines: first [last]

Given the file, alphabet.txt: txt A B C D E

Trim leading lines

Input: markdown <!--{ "alphabet.txt" | lines: 4 }--> <!--{ end }-->

This keeps the 4th line until the end of the file.

Output: markdown <!--{ "alphabet.txt" | lines: 4 }--> D E <!--{ end }-->

Trim trailing lines

Input: markdown <!--{ "alphabet.txt" | lines: 1 3 }--> <!--{ end }-->

This keeps only lines 1 to 3 Output: markdown <!--{ "alphabet.txt" | lines: 1 3 }--> A B C <!--{ end }-->

Trim both leading and trailing lines

Input: markdown <!--{ "alphabet.txt" | lines: 2 4 }--> <!--{ end }-->

This keeps only lines 2 to 4

Output: markdown <!--{ "alphabet.txt" | lines: 2 4 }--> B C D <!--{ end }-->

line: list...

Input: markdown <!--{ "alphabet.txt" | line: 3 2 1 }--> <!--{ end }-->

Output: markdown <!--{ "alphabet.txt" | line: 3 2 1 }--> C B A <!--{ end }-->

line-numbers: [separator] [width]

With Default Arguments:

Input: markdown <!--{ "full_alphabet.txt" | line-numbers | lines: 8 14 }--> <!--{ end }-->

Output: markdown <!--{ "full_alphabet.txt" | line-numbers | lines: 8 14 }--> 8: H 9: I 10: J 11: K 12: L 13: M 14: N <!--{ end }-->

With Provided Arguments:

Input: markdown <!--{ "alphabet.txt" | line-numbers: " " 4 }--> <!--{ end }-->

Output: markdown <!--{ "alphabet.txt" | line-numbers: " " 4 }--> 1 A 2 B 3 C 4 D 5 E <!--{ end }-->

wrap: text or wrap: before after

wrap-lines: text or wrap-lines: before after

match: pattern [group_num]

For a file, hello_world.rs: rust // Main fn main() { println!("Hello, World!"); } // Goodbye fn goodbye() { println!("Goodbye, World!"); }

The main() function can be extracted using the match command:

Input: markdown <!--{ "hello_world.rs" | match: "\n(fn main[\s\S]*?\n\})" 1 | code: rust }--> <!--{ end }-->

Output: markdown <!--{ "hello_world.rs" | match: "\n(fn main[\s\S]*?\n\})" 1 | code: rust }--> ```rust fn main() { println!("Hello, World!"); } ``` <!--{ end }-->