Preprocessor features

The preprocessor translates the content directory into the hugo directory. Its input is Markdown files, and its output is Markdown files that are suitable for Hugo to translate into HTML.

The preprocessor has two main forms of blocks that are rendered on the page: the pair of cooperating script and upload blocks, and the standalone code block. script and upload blocks can be hidden from the reader.

script and upload blocks

A script block contains one or more commands that are executed in turn, with their individual outputs interleaved on the rendered page. They are displayed with a $ prefix (indicating a shell context) with the pane’s copy button picking up only the newline-separated list of commands (i.e. no output and no $-prefix).

Each page’s script and upload blocks are transformed into a single bash script, which is invoked by the preprocessor. This means that each block operates in the context of the filesystem (and process) state created by the preceding script and upload blocks.

Example

Here is the start of a CUE package:
{{{with upload "en" "upload initial files"}}}
-- foo.cue --
package example

x: 1
-- bar.cue --
package example

y: 2
{{{end}}}

Here is the package being evaluated:
{{{with script "en" "cue eval initial files"}}}
cue eval
{{{end}}}

Here we add to the package:
{{{with upload "en" "upload additional file"}}}
-- baz.cue --
package example

z: 3
{{{end}}}

Here is the package being evaluated again:
{{{with script "en" "cue eval all files"}}}
cue eval > result.txt
cat *.txt
{{{end}}}

Rendered output

Here is the start of a CUE package:

package example

x: 1
package example

y: 2

Here is the package being evaluated:

TERMINAL
$ cue eval
y: 2
x: 1

Here we add to the package:

baz.cue
package example

z: 3

Here is the package being evaluated again:

TERMINAL
$ cue eval >result.txt
$ cat *.txt
y: 2
z: 3
x: 1

Hidden scripts and uploads

Any script or upload block can be hidden from the reader. This is useful when performing necessary tasks such as comparing content to assert that a page works as intended, (re-)uploading content that makes a page’s narrative work correctly, or deleting previously-uploaded files in order to reset the script context for the page’s next section.

To hide a block, surround its class with underscores.

Example

Here is some prose, followed by a hidden upload:
{{{with _upload_ "en" "a hidden file"}}}
-- foo.txt --
bar
{{{end}}}

Here is a hidden script. Whilst it isn't visible, if any of the commands in
this script fail to return the anticipated exit code then the site build will
not succeed:
{{{with _script_ "en" "check hidden file"}}}
grep bar foo.txt
{{{end}}}

Here is some more prose.

Rendered output

Here is some prose, followed by a hidden upload: Here is a hidden script and, whilst it isn’t visible, if any of the commands in this script fail to return the anticipated exit code then the site build will not succeed: Here is some more prose.

code blocks

The contents of script and upload blocks interact with each other, cummulatively, as a page progresses. If you don’t need this behaviour, use a code block to display a single command in an entirely standalone, isolated context, where it can only access a specific set of files.

A code block presents the reader with zero or more files, a single command, and the command’s output. The command is shown in a shell context, with a $ prefix. Unlike script blocks, this shell context is emulated, and lacks some shell-like capabilities such as filename globs and stream redirection.

A command inside a code block can only interact with the files that are present in that specific block, and cannot interact with files in other code blocks, upload blocks, or files created by script blocks. The reverse is also true: script blocks cannot interact with code blocks’ content.

A code block’s content is a txtar archive, with the files, command string, and command output that it contains being displayed in predefined locations in a 2x2 grid, based on the number of files present in the archive. File locations can be overridden with the #location tag, which requires the same number of locations as there are files (the command’s output is “a file”, in this context). A location is one of top, bottom, left, right, or a combination constrained by {top,bottom}-{left,right}. Completely overlapping locations are allowed, with their files being displayed as stacked code tabs. Partially overlapping locations are technically permitted, but render very poorly and should not be used.

There is no form of hidden code block.

Example

Here is a standalone code example:
{{{with code "en" "a code example"}}}
#location top-left top-left top-left top-right bottom
exec wc -l file1.txt file2.txt file3.txt file4.txt
cmp stdout out
-- file1.txt --
a b c
-- file2.txt --
d
e
-- file3.txt --
1 2 3
4 5 6
7 8 9
-- file4.txt --
Some content that needs its own pane
-- out --
{{{end}}}

Rendered output

Here is a standalone code example:

a b c
d
e
1 2 3
4 5 6
7 8 9
file4.txt
Some content that needs its own pane
TERMINAL
$ wc -l file1.txt file2.txt file3.txt file4.txt
 1 file1.txt
 2 file2.txt
 3 file3.txt
 1 file4.txt
 7 total