summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--bin/main.ml37
-rw-r--r--man/colitur-templates.545
-rw-r--r--man/colitur.111
-rw-r--r--test/cli.t15
4 files changed, 87 insertions, 21 deletions
diff --git a/bin/main.ml b/bin/main.ml
index 0a09a63..cf6cb33 100644
--- a/bin/main.ml
+++ b/bin/main.ml
@@ -650,7 +650,27 @@ let extension path =
fallback to [Escape.None_]: guessing the flavour wrong produces malformed
output (unescaped LaTeX/HTML metacharacters) that looks fine until it does
not -- the same "never silently substitute" discipline [data_dir]'s own
- [COLITUR_DATA_DIR] handling documents above. *)
+ [COLITUR_DATA_DIR] handling documents above.
+
+ Both error messages below list the flavours by walking [Escape.all]
+ rather than a hand-typed literal, on purpose: a hand-typed list is
+ exactly the kind of call site the design claims does not exist outside
+ escape.ml (spec section 5) -- adding Typst as a seventh flavour found
+ this one had drifted from that claim (it silently still said "the six
+ flavours" until then), so this is now future-proof against the same
+ drift the next flavour would otherwise reintroduce. *)
+let flavour_names_comma () =
+ match List.map Colitur_render.Escape.to_string Colitur_render.Escape.all with
+ | [] -> ""
+ | [ x ] -> x
+ | xs -> (
+ match List.rev xs with
+ | last :: rest -> String.concat ", " (List.rev rest) ^ " or " ^ last
+ | [] -> "")
+
+let flavour_names_bar () =
+ String.concat "|" (List.map Colitur_render.Escape.to_string Colitur_render.Escape.all)
+
let table_report ~lang ~template ~flavour_opt ~overlays y =
let flavour =
match flavour_opt with
@@ -658,16 +678,14 @@ let table_report ~lang ~template ~flavour_opt ~overlays y =
match Colitur_render.Escape.of_string name with
| Some f -> f
| None ->
- Printf.eprintf "colitur: unknown flavour %S (want latex, groff, html, xml, ics or none)\n"
- name;
+ Printf.eprintf "colitur: unknown flavour %S (want %s)\n" name (flavour_names_comma ());
exit 2)
| None -> (
match Colitur_render.Escape.of_extension (extension template) with
| Some f -> f
| None ->
- Printf.eprintf
- "colitur: cannot infer a flavour from %S; pass --flavour latex|groff|html|xml|ics|none\n"
- (extension template);
+ Printf.eprintf "colitur: cannot infer a flavour from %S; pass --flavour %s\n"
+ (extension template) (flavour_names_bar ());
exit 2)
in
match read_file template with
@@ -1116,11 +1134,12 @@ rendering:
--flavour X selects how interpolated VALUES are escaped (never the
template's own literal markup, which is the author's). One of:
- latex groff html xml ics none
+ latex typst groff html xml ics none
Inferred from --template's extension when --flavour is omitted:
.tex -> latex
+ .typ -> typst
.ms .mom .me -> groff
.html .htm -> html
.xml -> xml
@@ -1132,7 +1151,7 @@ rendering:
them alone)
An extension colitur does not recognise is a hard ERROR naming
- the six flavours above, never a silent fallback to `none`:
+ the seven flavours above, never a silent fallback to `none`:
guessing wrong produces output that looks fine until the
metacharacters it silently failed to escape show up.
@@ -1190,7 +1209,7 @@ Reading references only (e.g. "Jn 3:16"); never scripture text.
See colitur(1) for the full description and the sources it computes against,
colitur-overlay(5) for the overlay file format in full,
colitur-templates(5) for the template format in full -- the syntax, the
-remaining scope hazard, the six flavours' escaping, and the full view-model
+remaining scope hazard, the seven flavours' escaping, and the full view-model
field reference -- and colitur-config(5) for the config file's location and
precedence in full.|}
diff --git a/man/colitur-templates.5 b/man/colitur-templates.5
index 06ad583..e04560b 100644
--- a/man/colitur-templates.5
+++ b/man/colitur-templates.5
@@ -303,9 +303,9 @@ same file exactly as any other tag would).
selects how an interpolated
.I value
is escaped before being written. It never touches the template's own literal
-markup (the LaTeX, groff, HTML, XML or ICS surrounding a
+markup (the LaTeX, Typst, groff, HTML, XML or ICS surrounding a
.BR {{tag}} ),
-which is the template author's and is trusted exactly as written. One of six:
+which is the template author's and is trusted exactly as written. One of seven:
.TP
.B latex
.BR \e " \(-> " \etextbackslash{} ,
@@ -320,6 +320,42 @@ which is the template author's and is trusted exactly as written. One of six:
.BR ~ " \(-> " \etextasciitilde{} .
Every LaTeX special character is covered; nothing else is touched.
.TP
+.B typst
+.BR \e " \(-> " \e\e ,
+.BR # " \(-> " \e# ,
+.BR * " \(-> " \e* ,
+.BR _ " \(-> " \e_ ,
+.BR $ " \(-> " \e$ ,
+.BR @ " \(-> " \e@ ,
+.BR < " \(-> " \e< ,
+.BR > " \(-> " \e> ,
+.BR \(ga " \(-> " \e\(ga ,
+.BR ~ " \(-> " \e~ ,
+.BR \- " \(-> " \e\- .
+Verified against the installed
+.B typst
+binary rather than assumed: each escaped character was confirmed to survive
+as the literal character, and each was separately confirmed to do something
+else when left bare
+.RB ( # " opens code mode, " * / _ " toggle strong/emph, " $ " opens math, "
+.B @
+opens a reference \(em a bare unresolved
+.B @word
+is a hard
+.B typst
+compile error, not merely mangled output \(em
+.BR < / > " can close around a bare word into label syntax that swallows it, "
+.B \(ga
+opens raw text, and
+.B ~
+is a non\-breaking space). A run of two or three unescaped hyphens becomes an
+en or em dash; every
+.B \-
+is escaped unconditionally, not only inside a detected run, since escaping
+is applied one character at a time with no lookahead \(em confirmed live that
+escaping every hyphen independently still typesets as literal hyphens for a
+run of any length.
+.TP
.B groff
A backslash is escaped to
.BR \ee ,
@@ -373,6 +409,7 @@ own file extension when the flag is omitted:
.nf
.I .tex \(-> latex
+.I .typ \(-> typst
.I .ms .mom .me \(-> groff
.I .html .htm \(-> html
.I .xml \(-> xml
@@ -385,7 +422,7 @@ An extension
.B colitur
does not recognise is a hard
.B ERROR
-naming the six flavours above; it is
+naming the seven flavours above; it is
.I never
a silent fallback to
.BR none .
@@ -401,7 +438,7 @@ flavour (selected for
as well as
.IR .txt )
passes every interpolated value through unchanged. This is a deliberate
-choice, not a gap: unlike LaTeX, groff, HTML, XML or ICS, AsciiDoc and
+choice, not a gap: unlike LaTeX, Typst, groff, HTML, XML or ICS, AsciiDoc and
Markdown have no fixed, small metacharacter set that could be escaped
mechanically \(em their own metacharacters are context\-dependent (a
.B *
diff --git a/man/colitur.1 b/man/colitur.1
index b9ce1d1..df7ad3e 100644
--- a/man/colitur.1
+++ b/man/colitur.1
@@ -265,7 +265,7 @@ below.
.BI \-\-flavour " FLAVOUR"
.RB ( "colitur table" " and " "colitur render" " only)"
One of
-.BR latex ", " groff ", " html ", " xml ", " ics " or " none .
+.BR latex ", " typst ", " groff ", " html ", " xml ", " ics " or " none .
Overrides the flavour that would otherwise be inferred from
.BR \-\-template 's
own extension. See
@@ -602,7 +602,7 @@ literal markup, which is the author's and is trusted as\-is. One of:
.RS
.nf
-latex groff html xml ics none
+latex typst groff html xml ics none
.fi
.RE
.PP
@@ -615,6 +615,7 @@ own file extension:
.nf
.I .tex -> latex
+.I .typ -> typst
.I .ms .mom .me -> groff
.I .html .htm -> html
.I .xml -> xml
@@ -630,7 +631,7 @@ leaving them alone.
.PP
An extension
.B colitur
-does not recognise is a hard error naming the six flavours above; it is
+does not recognise is a hard error naming the seven flavours above; it is
.I never
a silent fallback to
.BR none .
@@ -641,7 +642,7 @@ document.
.nf
.B colitur table \-\-year 2027 \-\-template invite.wat
-colitur: cannot infer a flavour from ".wat"; pass \-\-flavour latex|groff|html|xml|ics|none
+colitur: cannot infer a flavour from ".wat"; pass \-\-flavour latex|typst|groff|html|xml|ics|none
.fi
.RE
.PP
@@ -1127,7 +1128,7 @@ shapes and worked examples.
.BR colitur\-templates (5)
for the template format used by
.BR table ", " render " and " publish
-\(em the four syntax forms, the six flavours and their escaping, the full
+\(em the four syntax forms, the seven flavours and their escaping, the full
view\-model field reference, and the one remaining scope hazard a template
author can still hit.
.PP
diff --git a/test/cli.t b/test/cli.t
index 610ce5b..ef1243e 100644
--- a/test/cli.t
+++ b/test/cli.t
@@ -621,18 +621,27 @@ An unknown extension with no --flavour is an error, not a silent fallback:
$ printf 'x' > /tmp/t.wat
$ colitur table --year 2027 --template /tmp/t.wat
- colitur: cannot infer a flavour from ".wat"; pass --flavour latex|groff|html|xml|ics|none
+ colitur: cannot infer a flavour from ".wat"; pass --flavour latex|typst|groff|html|xml|ics|none
[2]
$ colitur table --year 2027 --template /tmp/t.wat --flavour none
x
-An unrecognised --flavour value is also an error naming the six valid ones:
+An unrecognised --flavour value is also an error naming the seven valid ones:
$ colitur table --year 2027 --template /tmp/t.txt --flavour bogus
- colitur: unknown flavour "bogus" (want latex, groff, html, xml, ics or none)
+ colitur: unknown flavour "bogus" (want latex, typst, groff, html, xml, ics or none)
[2]
+Typst is inferred from .typ, like every other flavour's own extension.
+Its metacharacters are escaped the same way latex's own is above -- here
+'-', verified live (against the real typst binary) to collapse into an
+en dash if left unescaped; a real shipped citation carries one:
+
+ $ printf '{{#days}}{{first}}\n{{/days}}' > /tmp/t.typ
+ $ colitur table --year 2027 --template /tmp/t.typ | grep -c '11\\-16'
+ 1
+
A malformed template is a clear error, not a crash:
$ printf '{{#days}}oops' > /tmp/bad.txt