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