zoem(1)
π zoem(1) β USER COMMANDS π
okay so bestie, this is the manual page for zoem, and she lives in section 1 (USER COMMANDS). she's a long one, so she comes in parts β here's the whole roadmap so you know what you're getting into πΊοΈβ¨
- NAME
- SYNOPSIS
- DESCRIPTION
- OPTIONS
- SESSION MACROS
- THE SET MODIFIERS
- THE INSPECT SUBLANGUAGE
- THE TR SUBLANGUAGE
- TILDE EXPANSION
- ENVIRONMENT
- DIAGNOSTICS
- BUGS
- SEE ALSO
- EXAMPLES
- AUTHOR
β¨ NAME β¨
zoem β a macro processor for the Zoem macro/programming language. that's it, that's the whole name section, she's concise π
πΈ SYNOPSIS πΈ
the classic entry-file-and-output-file situation:
zoem [-i <file name>[.azm] (entry file name)] [-I <file name> (entry file name)] [-o <file name> (output file name)] [-d <device> (set device key)]
or, when you just want to vibe and type at her directly:
zoem
(enter interactive mode - happens when none of -i, -I, -o is given)
and now the full-glam, everything-included version π
zoem -i <file name>[.azm] (entry file name) -I <file name> (entry file name) [-o <file name> (output file name)] [-d <device> (set device key)] [-x (enter interactive mode on error)] [-s <key>[=<val>] (set key to val)] [-e <any> (evaluate any, exit)] [-E <any> (evaluate any, proceed)] [-chunk-size <num> (process chunks of size num)] [--trace (trace mode, default)] [--trace-all-long (long trace mode)] [--trace-all-short (short trace mode)] [--trace-regex (trace regexes)] [-trace k (trace mode, explicit)] [--stats (show symbol table stats after run)] [--split (assume \writeto usage, set \__split__)] [--stress-write (make \write#3 recover)] [--unsafe (prompt for \system#3)] [--unsafe-silent (simply allow \system#3)] [-allow cmd1[:cmdx]+ (allowable commands)] [--system-honor (require \system#3 to succeed)] [-nuser k (user dict stack size)] [-nenv k (environment dict stack size)] [-nsegment k (maximum simple nesting depth)] [-nstack k (maximum eval nesting depth)] [-buser (initial user dict capacity)] [-bzoem (initial zoem dict capacity)] [-tl k (tab length)] [-l <str> (list items)] [-h (show options)] [--apropos (show options)]
π¦ DESCRIPTION π¦
real talk first: Zoem is a macro/programming language, and the whole language is described in the Zoem User Manual (zum.html), which rn is available in HTML only. this manual page? it documents the zoem processor, not the zoem language. two different girls, okay? π
okay so about input files. if the input file is specified with the -i option and it's a regular file (i.e. not STDIN β and STDIN is what you get by passing a single hyphen), then it must have the .azm extension. you can specify that extension, but you don't have to. the zoem key \__fnbase__ will get set to the file base name, stripped of the .azm extension and of any leading path components. if instead you specify the input file with the -I option, then no extension is assumed, and \__fnbase__ is set to the file base name, period. and just so we're clear, the file base name is the file name with any leading path components stripped away. βοΈ
if neither -i nor -o is specified, zoem enters interactive mode. and she should fully recover from any error she encounters in the input. if you find an exception to this rule, consider filing a bug report (bestie, do it π«Ά). in interactive mode, zoem starts interpreting once it encounters a line containing a single dot. zoem's input behaviour can be modified by setting the key \__parmode__ β see the section SESSION MACROS for the details. also, in interactive mode, zoem does not preprocess the interactive input, which implies that it does not accept inline files and it does not recognize comments. both types of sequence will generate syntax errors. π finally, readline editing and history retrieval can be used in interactive mode, provided that they are available on the system. this means the input lines can be retrieved, edited, and discarded with a wide range of cursor positioning and text manipulation commands. iconic, honestly.
from within the entry file and included files, it's possible to open and write to arbitrary files using the \write#3 primitive. arbitrary files can be read in various modes using the \dofile#2 macro (providing four different modes with respect to file existence and output), \finsert#1, and \zinsert#1. zoem will write the default output to a single file, whose name is either specified by the -o option or constructed as described below. zoem can split the default output among multiple files, though β that's governed from within the input files by issuing \writeto#1 calls. refer to the --split option and the Zoem User Manual. π
if none of -i or -o is given, then zoem will enter interactive mode. in this mode, zoem interprets by default chunks of text that are ended by a single dot on a line of its own. this can be useful for testing or debugging. in interactive mode, zoem should recover from any failure it encounters. interactive mode can also be accessed from within a file by issuing \zinsert{stdia}, and it can be triggered as the mode to enter should an error occur (by adding the -x option to the command line). πͺ
if -o is given and -i is not, zoem reads input from STDIN.
if -i is given and -o is not, zoem will construct an output file name as follows: if the -d option was used with argument <dev>, zoem will write to the file which results from expanding \__fnbase__.<dev>. otherwise, zoem writes to (the expansion of) \__fnbase__.ozm. π
for -i and -o, the argument - is interpreted as respectively stdin and stdout.
π₯ OPTIONS π₯
get comfy, there's a lot of them, and every single one is here, no cap:
-i <file name>[.azm](entry file name) β specify the entry file name. the file must have the.azmextension, but it need not be specified. π-I <file name>[.azm](entry file name) β specify the entry file name, with no restrictions on the file name. free spirit energy.-o <file name>(output file name) β specify the output file name.-d <device>(set key\__device__) β set the key\__device__to<device>.-x(enter interactive mode on error) β the afterlife option π». if zoem encounters an error during regular processing, it will emit error messages as usual, and then enter interactive mode. this lets you, e.g., inspect the values of keys used or defined within the problematic area.-s <key>[=<val>](set key to val) β set the key\keytovalif present, and to1otherwise. any type of key can be set, including keys taking arguments and keys surrounded in quotes. beware of the shell's quote and backslash interpolation β οΈ. currentlyvalis not evaluated, so appending or prepending to a key is not possible.-e <any>(evaluate any, exit) β this causes zoem to evaluate<any>, write any result text to stdout, and exit. πββοΈ-E <any>(evaluate any, proceed) β this causes zoem to evaluate<any>, write any result text to stdout, and proceed, e.g. with the entry file or an interactive session.-chunk-size <num>(process chunks of size num) β zoem reads its input in chunks, and fully processes a chunk before moving on to the next one. this option defines the (minimum) size of the chunks. the size or count of the chunks does not at all affect zoem's output. the default minimum chunk size equals one megabyte.- zoem will read files in their entirety before further processing if
-chunk-size 0is specified. - zoem does not chunk input files arbitrarily. it will append to a chunk until it is in the outermost scope (not contained within any block) and the chunk will end with a line that was fully read.
- consequently, if, e.g., a file contains a block (delimited by balanced curlies) spanning the entire file, then zoem is forced to read it in its entirety.
- zoem will read files in their entirety before further processing if
--trace(trace mode, default) β trace in default mode.--trace-all-long(long trace mode) β sets on most trace options in long mode. trace options xxx not set have their own--trace-xxxentry (see below).--trace-all-short(short trace mode) β sets on most trace options in short mode. trace options xxx not set have their own--trace-xxxentry (see below).--trace-keys(trace keys) β trace keys.--trace-regex(trace regexes) β trace regexes (i.e. the\inspect#4primitive).-trace k(trace mode, explicit) β set trace options by adding their representing bits.--stress-write(stress test using write) β this makes\write#3recover from errors. it's a special purpose option used for creating zoem stress test suites, such asstress.azmin the zoem distribution/examplessubdirectory. πͺ--unsafe(prompt for\system#3) β see the shared note below.--unsafe-silent(simply allow\system#3) β see the shared note below.-allow cmd1[:cmdx]+(allowable commands) β see the shared note below.
with --unsafe, system calls are allowed but the user is prompted for each invocation. the command and its arguments (if any) are shown, but the STDIN information (if any) is withheld. with --unsafe-silent, system calls are allowed and the user is never prompted.
use -allow str or --allow=str to specify a list of allowable commands, as a string in which the commands are separated by colons. π
--system-honor(require\system#3to succeed) β with this option, any\system#3failure (for whatever reason, including safe behaviour) is regarded as a zoem failure. by default, failing system calls are ignored under either safe mode, unsafe mode (--unsafe), or silent unsafe mode (--unsafe-silent).--split(assume split output) β this assumes zoem input that allows output to multiple files (e.g. chapters). it sets the default output stream to stdout (anticipating custom output redirection with\writeto#1) and sets the session macro\__split__to1.--stats(show symbol table stats after run) β show symbol table chacteristics. symbol tables are maintained as hashes. π-tl k(set tab length) β set the tab length. HTML output can be indented according to nesting structure, using tabs which are expanded to simple spaces. by default, the tab length is zero, meaning that no indent is shown. the maximum value the tab length can be set to is four.-nsegment k(level of macro nesting allowed)-nstack k(stack count)-nuser k(user dictionary stack size)-nenv k(environment dictionary stack size)-buser k(initial user dict capacity)-bzoem k(initial zoem dict capacity)
probably needed only if you have some obscure and extreme use for zoem. π the segment limit applies to simple nesting of macros. the stack limit applies to nesting of macros that evaluate an argument before use β each such evaluation creates a new stack. the user limit applies to \push{user}, the env limit applies to the nesting level of environments (started with \begin#2). the user dict capacity pertains to the initial number of buckets allocated for user and environment dictionaries, and the zoem dict capacity pertains to the dictionary containing the zoem primitives.
-l <str>(list items) β list items identified by<str>. it can be any ofall,filter,legend,builtin,session,trace, orzoem. multiple identifiers can be joined in a string, e.g.-l legendzoemprints a legend followed by a listing of zoem primitives. ποΈ-h(show options) β show short synopsis of options.
π SESSION MACROS π
\__parmode__
this macro affects zoem's read behaviour in interactive mode. it can be set on the command line using the -s option. bits that can be set:
β¦to be continued π
1β chomp newlines (aka remove the newline character, gone, bye π )2β skip empty newlines4β read paragraphs (an empty line triggers input read)8β newlines can be escaped using a backslash16β read large paragraphs (a single dot on a line triggers input read)\__device__β the current output device, and it's set by the command line option-d. Themanandfaqpackages supporthtmlandroffas its values. That's the whole vibe check, no cap β¨\__fnbase__β the base name of the input file name. All the leading path components get stripped away. And if you're using the-ioption, the input file is required to have the.azmsuffix β and in that case the suffix gets stripped too, so you actually get the base name π\__fnentry__β the name of the entry file.\__fnin__β the file currently being processed, like right now, at this very moment π\__fnout__β the name of the default output file.\__fnpath__β the leading component of the input file name, and yes it can be empty, it's giving "possibly nothing, possibly everything" πΈ\__fnup__β the file that included the current file, if applicable. Your source file's source file. Ancestry reveal π₯\__fnwrite__β this key is set by\write#3to its first argument. It can be used by macros that are expanded during evaluation of the third argument. Possible usage is to branch on the name of the write output stream β for example a file calledindex.htmlmay be treated differently from other files. The key is deleted afterwards. > Heads up bestie: nested invocations of\write#3may corrupt the status of this key. Not a vibe. π\__ia__β the input/output separator used in interactive mode.\__line__β the line number in the file currently being processed. This number will be correct for any invocation outside the scope of a macro. For any invocation within a macro, the result will be the line number of the closing curly of the outermost containing macro. Like, watch this:
\__line__
\__line__
\__line__
\group{
\__line__
\group{\__line__}
\__line__}
Results in
1
2
3
7
7
7
\__searchpath__β a vararg containing a list of paths to search when a file is to be included/imported/read/loaded. When you start zoem, this key should contain the location of theman.zmmandfaq.zmmpackage files. It is advisable not to overwrite this key but to append to it instead. Respect the elders π\__zoemstat__β set to one ofok,towel(that one is a bit lame), orerrorby either the interpreter, an occurrence of\catch#2, or\try#1. The manpage saidtowelis lame, I'm just the messenger π«‘\__zoemput__β set by\try#1to the possibly truncated result of processing its argument.\__lc__β expands to a left curly. It is hard to find a need for this β the zoem stress suite uses it to generate a particular syntax error at a deeper interpretation level. Iconic chaotic use case tbh π\__rc__β expands to a right curly. The matching half of the above, they're a set, they're giving duo energy π
π THE SET MODIFIERS π
The \set#3 primitive allows a {modes}{<modifiers>} directive in its first argument. Here <modifiers> can be a combination of single-letter modifiers, each described below. Mix and match, it's a whole little alphabet of control π
aβ append to the key, do not overwrite, create if not existing.cβ conditionally; only set if not already defined.eβ existing; update existing key, possibly in lower dictionary.gβ global; set in the global (bottom) user dictionary.uβ unary; do not interpret vararg in<any>as key-value list (data keys only).vβ vararg; interpret vararg in<any>as key-value list (regular keys only).wβ warn if key exists (like\def#2and\defx#2).xβ expand argument (like\setx#2and\defx#2).
π THE INSPECT SUBLANGUAGE π
The \inspect#4 primitive takes four arguments. The languages accepted by the first two arguments are described below. The third argument is a replacement string or a replacement macro accepting back-references (supplied as an anonymous macro). The fourth argument is the data to be processed. Four args, four jobs, we love a clear structure β¨
arg 1 β is a vararg. Currently it accepts a single key mods for which the value should be a comma-separated list over the words posix, icase, dotall, iter-lines, iter-args, match-once, discard-nmp, discard-nil-out, discard-miss, count-matches. Alternatively, repeated use of mods is allowed. However you wanna serve it, bestie π
arg 2 β is a regular expression. Tilde patterns are expanded according to all of the ZOEM, UNIX, and REGEX schemes. Refer to TILDE EXPANSION for these. Yes, all three at once, it's an overachiever π
The third argument is a constant string or an anonymous key, the fourth argument is data. That's the recap, no notes π
π₯ THE TR SUBLANGUAGE π₯
The \tr#2 primitive takes two arguments. The first argument contains key-value pairs. The accepted keys are from and to which must always occur together, and delete and squash. The values of these keys must be valid translation specifications. This primitive transforms the data in the second argument by successively applying translation, deletion and squashing β in that order, no skipping the line π¦ Only the transformations that are needed need be specified, so you do you.
Translation specifications are subjected to UNIX tilde expansion as described below.
The syntax accepted by translation specifications is almost fully compliant with the syntax accepted by tr(1), with three exceptions. First, repeats are introduced as [*a*20] rather than [a*20]. Second, ranges can (for now) only be entered as X-Y, not as [X-Y]. X and Y can be entered in either octal or hexadecimal notation (see further below). As an additional feature, the magic repeat operator [*a#] stops on both class and range boundaries. Character specifications can be complemented by preceding them with the caret ^. Three exceptions, all documented, nothing hidden, we love transparency π«Ά
Specifications may contain ranges of characters such as a-z and 0-9. Posix character classes are allowed. The available classes are
[:alnum:][:alpha:][:cntrl:][:digit:][:graph:][:lower:][:print:][:punct:][:space:][:upper:][:xdigit:]
Characters can be specified using octal notation, e.g. \012 encodes the newline. Use \173 for the opening curly, \175 for the closing curly, \134 for the backslash, and \036 for the caret if it is the first character in a specification.
DON'T use\\,\{, or\}in this case! Seriously bestie, do not. π
Hexadecimal notation is written as \x7b (the left curly in this instance).
See EXAMPLES for an example of tr#2 usage.
π TILDE EXPANSION π
Some primitives interface with UNIX libraries that require backslash escape sequences to encode certain tokens or characters. The backslash is special in zoem too, and without further measures it can become very cumbersome to encode the correct escape sequences, as it is not always clear which tokens should be escaped or unprotected at what point. It is especially difficult to handle the zoem characters with special meaning, {, } and \. It's giving escape-sequence nightmare fuel π
The two primitives under consideration are \inspect#4 and \tr#2. Both treat the tilde as an additional escape character for certain arguments (as documented in the user manual). These arguments are subjected to tilde expansion, where the tilde and the character it proceeds are translated to a new character or character sequence. There are three different sets of tilde escapes: ZOEM, UNIX and REGEX escapes. \tr#2 only accepts UNIX escapes, \inspect#4 accepts all. Tilde expansion is always the last processing step before strings are passed on to external libraries. Last step, every time, periodt β¨
The ZOEM scheme contains some convenience escapes, such as ~E to encode a double backslash.
π ZOEM tilde expansion
~~β~~Eβ\\~eβ\~Iβ\{~Jβ\}~xβ\x~iβ{~jβ}
The zoem tr specification language accepts \x** as hexadecimal notation, e.g. \x0a denotes a newline in the ASCII character set.
π¦ UNIX tilde expansion
~aβ\a~bβ\b~fβ\f~nβ\n~rβ\r~tβ\t~vβ\v~0β\0~1β\1~2β\2~3β\3
πΈ REGEX tilde expansion
~^β\^~.β\.~[β\[~$β\$~(β\(~)β\)~|β\|~*β\*~+β\+~?β\?
πΈ ENVIRONMENT πΈ
The environment variable ZOEMSEARCHPATH may contain a colon and/or whitespace separated list of paths. It will be used when searching for files included via one of the dofile aliases \input, \import, \read, and \load. Note that the zoem macro \__searchpath__ contains the location where the zoem macro files were copied at the time of installation of zoem. So like, two different places, both important, don't confuse them bestie π
π DIAGNOSTICS π
On error, Zoem prints a file name and a line number to which it was able to trace the error. The number reported is the same as the one stored in the session macro \__line__. For an error-triggering macro which is not nested within another macro the line number should be correct. For a macro that does occur nested within another macro the line number will be the line number of the closing curly in the outermost containing macro. Yes, the nesting strikes again, it always does π
If in despair, use one of the tracing modes β --trace-keys is one of the first to come to mind. Another possibility is to supply the -x option. Despair is valid, but you have options π«Ά
π¦ BUGS π¦
No known bugs. \inspect#4 has not received thorough stress-testing, and the more esoteric parts of its interface will probably change. So like, it's fine, but it's also fine, yk? π
β¨ SEE ALSO β¨
Aephea is a document authoring framework largely for HTML documents.
Portable Unix Documentation provides two mini-languages for authoring in the unix environment. These languages, pud-man and pud-faq are both written in zoem. Whole ecosystem, all the way down π
π EXAMPLES π
This is a relatively new section, aimed at assembling useful or explanatory snippets. Fresh section, fresh snippets, we're building β¨
Create a vararg containing file names matching a pattern (png in this example).
\setx{images}{
\inspect{
{mods}{iter-lines,discard-miss}
}{(.*~.png)}{_#1{{\1}}}{\system{ls}}
}
Use magic boundary stops with tr#2.
\tr{
{from}{[:lower:][:upper:][:digit:][:space:][:punct:]}
{to}{[*L#][*U#][*D#][*S#][*P#]}}{
!"#$%&'()*+,-./0123456789:;<=>?@
ABCDEFGHIJKLMNOPQRSTUVWXYZ
[\\]^_`
abcdefghijklmnopqrstuvwxyz
\{|\}~]}
π AUTHOR π
Stijn van Dongen.
And that's a wrap bestie π this was zoem 21-341, dated 7 Dec 2021, page zoem(1) β go forth and write macros, you absolute main character π β¨
π¦ where this page comes from
- debian bookworm: zoem 21-341-1
- debian trixie: zoem 21-341-1
- ubuntu noble: zoem 21-341-1
- ubuntu questing: zoem 21-341-2
- ubuntu resolute: zoem 21-341-2build1 Β· GPL-3.0-or-later
- ubuntu stonking: zoem 21-341-2build1 Β· GPL-3.0-or-later
- Copyright (c) 2021 Stijn van Dongen
- π girlified by deepseek-ai/DeepSeek-V4.1-Flash on : a language model's rewrite of the original, under its terms