diff options
Diffstat (limited to 'man/colitur.1')
| -rw-r--r-- | man/colitur.1 | 501 |
1 files changed, 493 insertions, 8 deletions
diff --git a/man/colitur.1 b/man/colitur.1 index 58e46ff..005cc0a 100644 --- a/man/colitur.1 +++ b/man/colitur.1 @@ -13,6 +13,30 @@ colitur \- deterministic liturgical calendar and lectionary engine (Roman rite, .RI [ ... ] .br .B colitur +.B emit +.BI \-\-format " FMT" +.BI \-\-from " YEAR" +.BI \-\-to " YEAR" +.RB [ \-\-overlay " FILE" " ...]" +.RB [ \-\-dtstamp " STAMP" ] +.br +.B colitur +.BR table | render +.BI \-\-year " YEAR" +.BI \-\-template " FILE" +.RB [ \-\-flavour " FLAVOUR" ] +.RB [ \-\-overlay " FILE" " ...]" +.br +.B colitur +.B publish +.BI \-\-from " YEAR" +.BI \-\-to " YEAR" +.BI \-\-out " DIR" +.RB [ \-\-overlay " FILE" " ...]" +.RB [ \-\-prune ] +.RB [ \-\-dtstamp " STAMP" ] +.br +.B colitur .BR \-h | \-\-help .SH DESCRIPTION .B colitur @@ -65,6 +89,32 @@ occurrence, commemoration and transfer. .BI readings " YEAR" The Mass reading citations, one line per day. .TP +.B emit +Render a civil\-year range through one of five emitters \(em +.BR csv ", " json ", " sexp ", " xml " or " ics . +See +.B EMIT +below. +.TP +.BR table | render +Compute one civil year and render it through a user\-supplied template, in one +process. +.B table +and +.B render +are the same operation under two names \(em see +.B RENDERING +below for why there is no separate, stdin\-fed +.B render . +.TP +.B publish +Write the static tree that +.I is +this program's API: a civil\-year range rendered once, as files, so any web +server or git repository can serve it and nothing runs at request time. See +.B PUBLISH +below. +.TP .BI convert " FILE" .ini Convert a flat INI overlay to the S\-expression form, on standard output. The conversion verifies its own output before emitting it: the generated text is @@ -97,13 +147,81 @@ below. .TP .BI \-\-overlay " FILE" Apply a user calendar on top of the shipped one. Repeatable and ordered; -.B day -and -.B readings +.BR day ", " readings ", " emit ", " table ", " render " and " publish only. See .B OVERLAYS below. .TP +.BI \-\-format " FMT" +.RB ( "colitur emit" " only)" +One of +.BR csv ", " json ", " sexp ", " xml " or " ics . +Required. See +.B EMIT +below. +.TP +.BI \-\-from " YEAR" ", " \-\-to " YEAR" +.RB ( "colitur emit" " and " "colitur publish" " only)" +The inclusive civil\-year range to render, each +.B 1583..9999 +as elsewhere. +.I FROM +must not be after +.IR TO . +Both required. +.TP +.BI \-\-dtstamp " STAMP" +.RB ( "colitur emit \-\-format ics" " and " "colitur publish" " only)" +Fix the feed's own DTSTAMP instead of the default +.IR YYYY0101T000000Z , +where +.I YYYY +is the emitted year. Never a clock read either way \(em see +.B EMIT +below. +.TP +.BI \-\-out " DIR" +.RB ( "colitur publish" " only)" +The directory to write the static tree into. Created if it does not exist. +Required. See +.B PUBLISH +below. +.TP +.B \-\-prune +.RB ( "colitur publish" " only)" +Remove files a previous +.B publish +run into the same +.B \-\-out +wrote that this run did not rewrite. Never removes a file that is not +recorded in +.IR out /.colitur\-manifest , +regardless of this flag. See +.B PUBLISH +below. +.TP +.BI \-\-year " YEAR" +.RB ( "colitur table" " and " "colitur render" " only)" +The civil year to compute, +.B 1583..9999 +as elsewhere. Required. +.TP +.BI \-\-template " FILE" +.RB ( "colitur table" " and " "colitur render" " only)" +The template file to render the year through. Required. See +.B RENDERING +below. +.TP +.BI \-\-flavour " FLAVOUR" +.RB ( "colitur table" " and " "colitur render" " only)" +One of +.BR latex ", " groff ", " html ", " xml ", " ics " or " none . +Overrides the flavour that would otherwise be inferred from +.BR \-\-template 's +own extension. See +.B RENDERING +below. +.TP .BR \-h ", " \-\-help Print a usage summary to standard output and exit 0. .TP @@ -162,6 +280,349 @@ Both reports are one line per day and ordered by date, so they compose with and .BR join (1) in the ordinary way. +.SH EMIT +.BI "colitur emit " \-\-format " FMT " \-\-from " YEAR " \-\-to " YEAR" +renders the same resolved day \(em season, week, slug, rank, colour, +subject, Latin and English names, citations, commemorations \(em through one +of five emitters, for every day in the inclusive civil\-year range +.IR FROM .. TO . +Every emitter consumes one shared view of the data, so all five describe +exactly the same fields. +.TP +.B csv +RFC 4180. One header row for the whole run, not one per year, so a +multi\-year range still has exactly one header and +.BR wc (1) +or +.B "awk 'NR>1'" +behave as expected. +.RS +.nf + +.B colitur emit \-\-format csv \-\-from 2026 \-\-to 2026 | head \-2 +date,rite,season,week,slug,rank,colour,subject,name_la,name_en,first,gospel,comms +2026\-01\-01,ef,christmastide,,ef\-circumcision,class\-1,white,temporal,,,Titus 2:11\-15,Luke 2:21, +.fi +.RE +.TP +.B json +One JSON object per requested year, concatenated. Shape pinned by +.IR schema/day\-v1.json . +.RS +.nf + +.B colitur emit \-\-format json \-\-from 2026 \-\-to 2026 | head \-c 40 +{"rite":"ef","year":"2026","months":[{... +.fi +.RE +.TP +.B sexp +One S\-expression per day, one per line \(em the same +.I Liturgical_day.t +shape used internally, printed with +.IR sexplib "'s " to_string_hum . +.TP +.B xml +Element\-per\-field, one +.I <calendar> +document per requested year, concatenated. Attributes carry identity only +(rite, year, date); everything else is an element. Shape pinned by +.IR schema/colitur\-v1.xsd , +checked by +.B make check\-schema +when +.BR xmllint (1) +is installed. +.TP +.B ics +RFC 5545. One +.I VCALENDAR +per requested year, concatenated, one all\-day +.I VEVENT +per day. Lines are folded at 75 octets and end +.RI ( CRLF ), +matching the protocol exactly \(em +.RB \(lq " cat \-A " \(rq +on the output shows +.B ^M$ +at each line end. +.RS +.nf + +.B colitur emit \-\-format ics \-\-from 2026 \-\-to 2026 | head \-1 +BEGIN:VCALENDAR +.fi +.RE +.PP +.B \-\-dtstamp +fixes the feed's own +.I DTSTAMP +field, which RFC 5545 requires on every event. Without it the value defaults +to +.I YYYY0101T000000Z +for the emitted year \(em a fixed value, not a clock read \(em so two +.B emit \-\-format ics +runs over identical data are byte\-identical, which matters for a +reproducible build or a diffable published calendar file. Nothing in the +.B emit +path reads the wall clock, for any format. +.PP +.BR \-\-overlay +is accepted exactly as on +.B day +and +.BR readings : +applied on top of the shipped calendar, in order, before the range is +rendered. See +.B OVERLAYS +below. +.SH RENDERING +.BI "colitur table " \-\-year " YEAR " \-\-template " FILE" +and +.BI "colitur render " \-\-template " FILE " \-\-year " YEAR" +are the +.I same +operation under two names: compute the resolved year, shape it into the +same view +.B emit +uses, and render it through +.I FILE +in one process. Both accept +.BR \-\-flavour " and " \-\-overlay +identically. +.SS Why there is no stdin\-fed render +The design this project followed originally sketched a Unix pipe, +.BR "compute | render" , +with +.B render +reading a serialised view back from standard input. That is deliberately +.I not +built. +Honouring the pipe would require a JSON +.I parser +inside +.B colitur +\(em a second hand\-rolled component, purely so this program could read back a +view it had just serialised itself, and a second place for the published +output schema to drift out of step with what the parser actually accepts. +That is a real cost for no benefit over calling the same view builder +directly in the same process, which is what +.B table +and +.B render +both do. +.PP +Unix composition is not abandoned, only narrowed to where it is cheap and +honest: +.B "colitur emit \-\-format json | jq" +still composes fine, because that JSON is the +.I output +of the pipeline, never something +.B colitur +itself has to parse back in. +.SS Templates +.I FILE +is a deliberately logic\-less, Mustache\-family template: it is +.I data, +never a program. The only constructs are +.BR {{placeholder}} , +.BR {{#section}}...{{/section}} , +.BR {{^inverted}}...{{/inverted}} +and +.BR {{!comment}} . +There are no partials, no lambdas, no expression evaluation, no arithmetic, +and no filesystem or process access from inside a template. There is +deliberately no "raw" or triple\-brace form either \(em a template cannot opt +out of its flavour's escaping. +.PP +The template renders against the same schema +.B emit +uses (season, week, slug, rank, colour, subject, names, citations, +commemorations), reshaped for two artefacts from one model: a flat booklet +(the +.B days +list, one entry per day of the year) and a month grid (the +.B weeks +list, with padding cells flagged for the leading and trailing blanks a grid +needs and a booklet does not). A key absent on a given day (an optional field +a rite does not always set) renders as the empty string rather than an error +\(em the one deliberate silence, so a template survives a day that does not +carry every optional field. +.PP +See +.BR colitur\-templates (5) +for the full syntax, the escaping table per flavour, the complete +view\-model field reference, and \(em before writing a template of any +complexity \(em its +.B SCOPE AND LOOKUP +section: an inner key silently loses to an outer key of the same name (a bare +.B {{name.la}} +inside a day resolves to the enclosing MONTH's name, not the day's own), +which has produced wrong output in this project's own templates. +.SS Flavours +.BI \-\-flavour +controls how interpolated +.I values +are escaped for the target format. It never touches the template's own +literal markup, which is the author's and is trusted as\-is. One of: +.RS +.nf + +latex groff html xml ics none +.fi +.RE +.PP +When +.B \-\-flavour +is omitted it is inferred from +.BR \-\-template 's +own file extension: +.RS +.nf + +.I .tex -> latex +.I .ms .mom .me -> groff +.I .html .htm -> html +.I .xml -> xml +.I .ics -> ics +.I .md .adoc .txt -> none +.fi +.RE +.PP +.B none +escapes nothing: Markdown, AsciiDoc and plain text have no fixed +metacharacter set, so escaping them here would produce worse output than +leaving them alone. +.PP +An extension +.B colitur +does not recognise is a hard error naming the six flavours above; it is +.I never +a silent fallback to +.BR none . +Guessing the flavour wrong produces output that looks fine right up until +the metacharacters it silently failed to escape show up in a rendered +document. +.RS +.nf + +.B colitur table \-\-year 2027 \-\-template invite.wat +colitur: cannot infer a flavour from ".wat"; pass \-\-flavour latex|groff|html|xml|ics|none +.fi +.RE +.PP +A malformed template reports the parser's own reason and exits 2, never a +crash \(em a template is user input, exactly like an overlay file. +.RS +.nf + +.B colitur table \-\-year 2027 \-\-template bad.txt +colitur: template bad.txt: unclosed section {{#days}} +.fi +.RE +.SH PUBLISH +.BI "colitur publish " \-\-from " YEAR " \-\-to " YEAR " \-\-out " DIR" +writes the static tree that +.I is +this program's API: every file a civil\-year range can be asked for, +computed once and written out, so any web server or git repository can +serve the result as\-is and nothing runs at request time. +.RS +.nf + +ef/<year>.json one civil year, all days, whole\-year emitters +ef/<year>.csv +ef/<year>.xml +ef/<year>.ics +ef/<year>/<mm>/<dd>.json one file per day +schema/day\-v1.json the published JSON contract +index.html a generated index page, not a template +\&.colitur\-manifest every path this run wrote, one per line +.fi +.RE +.PP +Every emitted file goes through the same emitters +.B emit +uses; a published +.I .ics +file for a given year is byte\-for\-byte what +.B "colitur emit \-\-format ics" +would print for that year, and +.B \-\-dtstamp +means exactly what it means there. The per\-day JSON files carry the same +shape as the whole\-year one, scoped to a single day \(em +.B "colitur table" +and template authors needing one day's data can read either. +.PP +.B Deterministic. +Publishing the same +.B \-\-from / \-\-to +range into an empty directory twice produces a byte\-identical tree. Nothing +in the publish path reads the wall clock; the +.I .ics +files' own DTSTAMP defaults to a fixed value derived from the emitted year, +exactly as it does under +.B emit +(see +.B EMIT +above), and +.B \-\-dtstamp +overrides it the same way. This is what makes publishing into a git +repository safe: +.B git status +shows only genuine change, and you review an actual diff before pushing, +never a rewrite of files that did not change. +.PP +.B Non\-destructive. +.B publish +writes only files it owns, and records the relative path of every one of +them in +.IR out /.colitur\-manifest +(itself never subject to pruning). A file you put in the output directory +yourself \(em by hand, or from some other tool \(em is never named in that +manifest, so it is never touched, +.I whether or not +.B \-\-prune +is given. +.RS +.nf + +.B "touch out/MY\-NOTES.txt" +.B "colitur publish \-\-from 2027 \-\-to 2027 \-\-out out \-\-prune" +.B "test \-f out/MY\-NOTES.txt && echo kept" +kept +.fi +.RE +.PP +.B \-\-prune +removes exactly the entries a +.I previous +publish into the same +.B \-\-out +wrote that this run did not rewrite \(em typically an earlier year's own +per\-day files, when a later +.B publish +targets a different +.B \-\-from / \-\-to +range into the same directory. A directory a stale entry's removal leaves +empty is removed too (so, for example, +.I out/ef/2027/ +itself goes away once every file under it is gone), but nothing above +.B \-\-out +is ever touched, and +.B \-\-out +itself is never removed even when nothing is left in it. Without +.BR \-\-prune , +old entries are left in place, and only the manifest is rewritten to +describe the current run. +.PP +.BR \-\-overlay +is accepted exactly as on +.BR day ", " readings " and " emit : +applied on top of the shipped calendar, in order, before each year in the +range is rendered. See +.B OVERLAYS +below. .SH OVERLAYS .TP .BI \-\-overlay " FILE" @@ -242,11 +703,9 @@ shapes: .RE .PP Accepted on -.B day -and -.B readings -only. The other commands read no sanctoral data at all, so the flag would have -no effect there and is +.BR day ", " readings ", " emit ", " table ", " render " and " publish . +.BR easter " and " temporal +read no sanctoral data at all, so the flag would have no effect there and is .I refused rather than silently ignored. .PP @@ -347,6 +806,25 @@ Run against a checkout's data rather than the installed copy: .B COLITUR_DATA_DIR=~/git/projects/colitur/data/ef colitur day 2026 .fi .RE +.PP +Render a year through a template, flavour inferred from the extension: +.RS +.nf + +.B colitur table \-\-year 2026 \-\-template booklet.tex > booklet.tex.out +.fi +.RE +.PP +Publish a year range as a static tree, then keep it in step with +.B \-\-prune +as the range moves: +.RS +.nf + +.B colitur publish \-\-from 2026 \-\-to 2027 \-\-out ~/public/colitur +.B colitur publish \-\-from 2027 \-\-to 2028 \-\-out ~/public/colitur \-\-prune +.fi +.RE .SH SOURCES The calendar is computed against the 1962 .I Missale Romanum @@ -376,6 +854,13 @@ reading citations fall back to the day's ordinary ones. for the overlay file format \(em every directive, every field, the three date shapes and worked examples. .PP +.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 +view\-model field reference, and the scope\-shadowing hazard a template author +will hit. +.PP .BR lectio (1) .SH LICENSE AGPL\-3.0\-or\-later. |
