Show HN: JWEB (a modern implementation of the CWEB Literate Programming system)
github.com
github.com
It also uses Pandoc, so supports lots of input and output formats (Markdown, LaTeX, HTML, etc.). For example, this Markdown will generate a list of numbers, along with a code listing:
The following list:
```{.unwrap pipe="tee example.py | python3 | pandoc -f md -t json"}
for i in range(10):
print(' - ' + str(i))
```
Was generated using this code:
```{.python pipe="cat example.py"}
```
The first code block gets run through the command given by `pipe`: that saves a copy of the code to `example.py`, interprets it using `python3`, then uses `pandoc` to convert the generated Markdown to "Pandoc JSON" format. That JSON replaces the original contents of the code block, and the `.unwrap` tells Pandoc to replace the code block with its contents (parsed as Pandoc JSON).The second code block gets run through the command `cat example.py`, which ignores its input (which is empty anyhow), and dumps out the `example.py` file that was generated by the first code block. The `.python` tells Pandoc to syntax-highlight this block as Python code.
I built something in a similar spirit to your comment and this larger thread, albeit a bit simplistic. Lets you document and write your bash scripts in a markdown file, then you can run the blocks. It figures out what arguments you expect in a block and turns them into CLI flags. https://github.com/khalidx/runbook
Not sure how useful it is but I use it to maintain a collection of documented bash scripts.
My system is mainly targeted towards readmes and other documentation and the way that it works is as follows:
1. My program reads in a markdown file.
2. It finds fenced code blocks in the file, that have info strings corresponding to a shell scripting language like bash or zsh. For example
```zsh
grep foo bar.txt | sort -u
```
3. Then it looks at each of those fenced code blocks and checks if they are immediately followed by another fenced code block but where the info string is that of plain text. For example ```text
foo
foobar
```
When you author the document you insert empty fenced code blocks like ```text
```
4. For each shell script fenced code block that is followed by a plain text fenced code block, the commands in the shell script fenced code block are executed and the output is captured.5. The captured output of each such shell script fenced code block is inserted into the corresponding plain text fenced code block that follows it.
6. Any fenced code block that is not immediately followed by a plain text fenced code block is ignored and not executed.
All together this allows for, among other possibilities:
- Updating outputs of sample commands in documentation all in one go.
- IPython Notebook style documents for shell scripts, except not interactive.
- Including commands that you want to inform the user about but which you explicitly don’t want to actually automatically execute.
I have a simple version of it for my own use that I put together a while back, and I started making a version of it that will eventually be usable by anyone. I will probably try and do a Show HN post about it when it is ready for others to use. Currently, completing the version that will be usable by anyone is on the back burner while I am working on some other things.
In my program, each block of code is run in an independent shell. So if you define a variable in one code block then it is available throughout that same code block but does not “transfer” to other code blocks. This is by design.
Command blocks are executed sequentially so that one can do operations that make changes to the file system in different blocks and still have the outcome be as excepted.
For example, you might be writing about generating and optimising png files, and your document might contain something like
First let's generate a 128x128 solid grey PNG and look at the size of the file.
```zsh
convert -size 100x100 xc:grey image1.png
ls -al image1.png
```
```text
```
The resulting file is quite small already.
But we can shave off a few bytes using a PNG optimizer.
```zsh
optipng image1.png
```
```text
```
And that saves us about 10% in file size in this case.
And for me this is the way that seems natural for the use case that what my program is doing. That the code blocks share operating system state and file system state, but not variables.