mdbook_cmdrun/lib.rs
1//! This is a preprocessor for the [rust-lang mdbook](https://github.com/rust-lang/mdBook) project. This allows to run arbitrary (shell) commands and include the output of these commands within the markdown file.
2//!
3//! # Getting started
4//!
5//! ```sh
6//! cargo install mdbook-cmdrun
7//! ```
8//!
9//! You also have to activate the preprocessor, put this in your `book.toml` file:
10//! ```toml
11//! [preprocessor.cmdrun]
12//! ```
13//!
14//! > :warning: This preprocessor presents a security risk, as arbitrary commands can be run. Be careful with the commands you run.
15//! > To list all the commands that will be run within an mdbook, you can run the following command:
16//! > ```sh
17//! > grep -r '<!--\s*cmdrun' . | sed 's/.*<!--\s*cmdrun \(.*\) -->.*/\1/'
18//! > ``````
19//!
20//!
21//! # How to
22//!
23//! Let's say we have these two files:
24//!
25//! Markdown file: file.md
26//! ```markdown
27//! # Title
28//!
29//! <!-- cmdrun seq 1 10 -->
30//!
31//! <!-- cmdrun python3 script.py -->
32//!
33//! ```
34//!
35//! Python file: script.py
36//! ```python
37//! def main():
38//! print("## Generated subtitle")
39//! print(" This comes from the script.py file")
40//! print(" Since I'm in a scripting language,")
41//! print(" I can compute whatever I want")
42//!
43//! if __name__ == "__main__":
44//! main()
45//!
46//! ```
47//!
48//! The preprocessor will call seq then python3, and will produce the resulting file:
49//!
50//! ```markdown
51//! # Title
52//!
53//! 1
54//! 2
55//! 3
56//! 4
57//! 5
58//! 6
59//! 7
60//! 8
61//! 9
62//! 10
63//!
64//! ## Generated subtitle
65//! This comes from the script.py file
66//! Since I'm in a scripting language,
67//! I can compute whatever I want
68//!
69//!
70//! ```
71//!
72//! # Details
73//!
74//! When the pattern `<!-- cmdrun $1 -->\n` or `<!-- cmdrun $1 -->` is encountered, the command `$1` will be run using the shell `sh` like this: `sh -c $1`.
75//! Also the working directory is the directory where the pattern was found (not root).
76//! The command invoked must take no inputs (stdin is not used), but a list of command lines arguments and must produce output in stdout, stderr is ignored.
77//!
78//! As of July 2023, mdbook-cmdrun runs on Windows platforms using the `cmd` shell!
79//!
80//! # Examples
81//!
82//! The following is valid:
83//!
84//! ````markdown
85//!
86//! <!-- cmdrun python3 generate_table.py -->
87//!
88//! ```rust
89//! <!-- cmdrun cat program.rs -->
90//! ```
91//!
92//! ```diff
93//! <!-- cmdrun diff a.rs b.rs -->
94//! ```
95//!
96//! ```console
97//! <!-- cmdrun ls -l . -->
98//! ```
99//!
100//! ## Example of inline use inside a table
101//! ````markdown
102//! Item | Price | # In stock
103//! ---|---|---
104//! Juicy Apples | <!-- cmdrun node price.mjs apples --> | *<!-- cmdrun node quantity.mjs apples -->*
105//! Bananas | *<!-- cmdrun node price.mjs bananas -->* | <!-- cmdrun node quantity.mjs bananas -->
106//! ````
107//!
108//! Which gets rendered as:
109//! ````markdown
110//! Item | Price | # In stock
111//! ---|---|---
112//! Juicy Apples | 1.99 | *7*
113//! Bananas | *1.89* | 5234
114//! ````
115//!
116//! Often, it is helpful to ensure that the commands being run successfully complete
117//! or at least return the expected exit code. This check is supported through an
118//! optional flag after `cmdrun` but before your command.
119//! Any errors encountered by cmdrun are reported in the rendered mdbook.
120//! For example, the following source
121//!
122//! ````markdown
123//! <!-- cmdrun -0 echo hello world -->
124//! ```diff
125//! <!-- cmdrun -0 diff a.rs b.rs -->
126//! ```
127//! ```diff
128//! <!-- cmdrun -1 diff a.rs b.rs -->
129//! ```
130//! ````
131//! gets rendered as
132//! ````markdown
133//! hello world
134//! ```diff
135//! **cmdrun error**: 'diff a.rs b.rs' returned exit code 1 instead of 0.
136//! ```
137//! ```diff
138//! 2c2
139//! < println!("I'm from `a.rs`");
140//! ---
141//! > println!("I'm from `b.rs`");
142//! ```
143//! ````
144//! The available flags for specifying the exit code are
145//! - `-N` where `N` is the integer exit code that the command should return.
146//! - `--strict` requires the command to return 0.
147//! - `--expect-return-code N` requires the command to return code `N`.
148//!
149//! Some more examples are implemented, and are used as regression tests. You can find them [here](https://github.com/FauconFan/mdbook-cmdrun/tree/master/tests/regression/).
150//! At the moment of writing, there are examples using:
151//! - Shell
152//! - Bash script
153//! - Batch script
154//! - Python3
155//! - Node
156//! - Rust
157//!
158pub mod cmdrun;
159mod utils;
160
161pub use cmdrun::CmdRun;