| Commit message (Collapse) | Author | Age | Files | Lines |
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
The task this branch of work set out to test was whether the template
engine is genuinely flavour-agnostic outside lib/render/escape.ml. It
is not, quite: bin/main.ml's own --flavour error/help text and both
man pages hand-typed the flavour list and its count ("the six
flavours") as literal prose, so adding Typst as a seventh left three
places silently wrong (an incomplete flavour list in two error
messages, and "six" where the true count is now seven) until this
commit.
bin/main.ml's two error messages (unknown --flavour value, and cannot
infer a flavour from an extension) now build their flavour list by
walking Escape.all/to_string instead of a literal string, so the next
flavour added will not reintroduce the same drift; the static --help
body text and colitur(1)/colitur-templates(5) still name flavours and
their count by hand; there was no equivalent gain available for
prose formatted this specifically, so those were updated by hand
instead, along with colitur-templates(5)'s FLAVOURS section, which
gained typst's own subsection alongside latex/groff/html/xml/ics/none.
test/cli.t's two pinned error-text assertions are updated to match,
and gained a new case: .typ inferred from extension, and a real
shipped citation's hyphen surviving --flavour typst's own escaping
live, the same shape the 2035 Ss. Petri et Pauli case already proves
for latex's ampersand just above it.
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
colitur-config.5 documents the file's location, the flag > config >
default precedence, every setting, and that an unknown key is warned
about rather than fatal. Its worked example is a real run against the
shipped example overlay, pasted rather than hand-typed -- including one
genuine gotcha found while verifying it: overlay/template values are not
shell-expanded, so a bare "~/..." written into the config file fails to
load; the full path must be written out instead.
colitur-templates.5's field reference is updated for the view change --
every field checked against lib/render/view.ml and schema/day-v1.json,
not transcribed from memory or an earlier version of this page -- and its
worked example is pasted from a real `colitur table` run. Its
scope-shadowing warning about {{name.la}} is REMOVED and replaced with a
short note that the hazard is now unrepresentable, because name is a
plain resolved string with no dotted path left to fall back through. The
num collision between a month and a week (both carry num, and a bare
{{num}} read from inside a day silently climbs to the week's own value,
not the month's) still exists and is demonstrated with a real render, not
merely asserted. A man page describing a hazard that was fixed is as
wrong as one that omits a real hazard.
Two further stale mentions of the removed {{name.la}} hazard, and two
places describing the schema as "Latin and English names" rather than one
resolved display name, were found in colitur.1 while cross-checking and
fixed alongside the primary rewrite; its own CSV example in EMIT was also
still the pre-Task-5 column list (name_la/name_en, no *_name columns) and
is now the real, verified header.
lang/ already installs beside templates/ and schema/ (a prior hotfix);
colitur-config.5 is added to install/uninstall/man/doc in the Makefile so
`make install`/`make doc` cover it too.
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
Names are Latin by default now; --raw restores the old byte-exact output,
verified against a pre-branch binary built from a clean HEAD checkout, not
merely asserted. day and readings gain a trailing display-name field
(day's own name suffix, readings' own " | name" suffix) rather than a
substitution in the slug's existing position: a name contains spaces and
would otherwise break the space-separated columns, the same reasoning that
already keeps readings a separate command. The field is present only when
it differs from the slug already shown, which is a direct consequence of
Lang.raw being the identity table (no lookup ever misses), not a special
case threaded through day_line/readings_line -- under --raw, or any
language with no entry for a given day, the trailing field is simply
absent, byte for byte what this project printed before naming existed.
An unknown language is an error naming what is available, never a silent
fallback to Latin: a booklet quietly printed in the wrong language is worse
than one that refuses to print. A declared fallback still chains, so a
partial translation shows its fallback language rather than slugs.
lang_dir mirrors data_dir's probe order exactly -- installed prefix, then
build tree -- because an installed binary that finds calendar data but no
language files is the failure this would otherwise ship.
Config (lang/overlay/template/format) is loaded once, unconditionally,
before dispatch: a config file that exists but fails to parse is fatal on
every command, not only the ones that consult it, because a config the
user wrote and colitur cannot honour is not something to silently carry on
past. An unknown key or unknown section is reported and ignored, worded
differently so a misspelled section reads differently from a misspelled
key inside a recognised one. overlay's config default applies only when
zero --overlay flags were given, never merged with a partial CLI list, so
precedence stays flag > config > default in one direction throughout.
colitur lang --list/--dump/--check and colitur config --show are what make
"anyone can write a language file" true rather than merely permitted, the
same pattern the overlay system already established with new-overlay and
check. --check reports what is missing AND rejects an unknown slug (exit
1), because a key matching nothing is silently dead and its author would
otherwise never learn why their own name does not appear. --dump emits
sections in a fixed order (Lang.keys' own global sort keeps every
section's keys contiguous), so two dumps of the same table are
byte-identical. config --show resolves through the same Config.resolve
every other command uses -- deliberately no separate provenance function,
so the two cannot disagree -- and previews exactly what flags given on the
same command line would resolve to anywhere else.
One authorized change outside this task's own file list: emit_ics.ml's
SUMMARY line was reading the unlocalised rank/colour pair ("class-1,
white") beside an already-localised name, where the JSON schema right next
to it correctly carries rank_name/colour_name ("II classis"/"albus").
Found while reviewing the published site; fixed at the source.
|
| |
|
|
|
|
|
|
|
|
|
|
| |
It read "an inner key silently loses to an outer key of the SAME NAME" --
false: the document's own num entry, two paragraphs below, shows the
opposite (inside {{#weeks}}, a bare {{num}} is the week's own number,
correctly, because the inner scope wins). The real hazard, matching the
body text and the name example that were already correct: a DOTTED path
that resolves only part way inward (the day's own name object exists but
lacks the key the path needs) falls back WHOLESALE to an outer scope of
the same name, not a bare key losing outright. Corrected the headline
only; re-linted clean with groff -man -Tutf8 -ww -z.
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
The worked minimal template iterated the top-level, flat days list
and claimed the naive {{name.la}} form would print the enclosing
month's name there. It would not: with no {{#months}} wrapping it,
the flat days list has no month anywhere on the scope stack, so the
naive form on an unnamed day resolves to nothing, not to the month.
Reproduced against the live engine before touching the page: the
flat shape renders empty; the identical naive form nested inside
{{#months}} genuinely does print the month's name on both unnamed
days. The example now nests days inside months -- the shape every
shipped template actually uses, and the shape the hazard needs to
fire -- with a second, verified rendering showing the collision for
real, and a closing note stating plainly that the flat shape does not
reproduce it. SCOPE AND LOOKUP's own name-collision paragraph gained
the same nesting precondition it was missing.
Both rendered blocks were checked mechanically: extracted verbatim
from the page source and diffed against a fresh colitur table run
over the exact templates shown, byte for byte.
One cosmetic fix along the way: a transition sentence embedded the
full safe-idiom string inline via .B, which groff's justifier
stretched into visibly wide gaps when rendered. Reworded to reference
the idiom shown above instead of repeating it.
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
colitur-templates.5 documents the four syntax forms, the six flavours
and their escaping, and the full view-model field reference. It states
plainly that there are no partials, no raw form and no expression
evaluation -- a template is data, never a program. It documents two
real hazards found during this build, not theoretical ones: the
outward scope fallback silently shadowing an inner name/num key with
an outer one of the same name (with the safe {{#name}}...{{^la}}
idiom), and the engine's lack of host-comment awareness (a {{...}}
inside a LaTeX %, groff .\" or HTML <!-- --> comment is still parsed
as a tag).
It also states the limitation rather than hiding it: AsciiDoc and
Markdown are not escaped, so a feast name containing * or _ renders as
emphasis.
templates/ and schema/ now install into <prefix>/share/colitur/,
matching data/ef/, via new install stanzas; colitur-templates.5
installs to man5 beside colitur-overlay.5. Verified against a scratch
prefix: the installed binary resolves both from the prefix, not the
source tree, when run from an unrelated working directory.
make check-templates typesets every shipped template through pdflatex
and groff when they are installed, and prints SKIPPED loudly when they
are not. Golden tests prove templates render; only this proves they
typeset. A silent skip would read as a pass.
Fixed a real doc/help drift while here: bin/main.ml's --help still said
--overlay was accepted on day and readings only, three commands out of
date (emit, table/render and publish all accept it too), disagreeing
with the man page's own OVERLAYS section, which carried the identical
stale line. Both are corrected; --overlay's own behaviour is unchanged.
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
Writes ef/<year>.{json,csv,xml,ics}, one JSON per day, the schema and a
generated index. That tree is the API: any web server or git repo serves
it, and nothing runs at request time.
Deterministic: publishing twice is byte-identical, asserted in cli.t.
That is what makes publishing into a git repo safe -- the diff shows
only real change, and you review it before pushing.
Non-destructive: a manifest records exactly the files this tool wrote,
so --prune can only remove files a previous run created. A file you put
in the output directory yourself is never touched, with or without
--prune. Asserted in both directions.
Pruning a stale file also removes any directory it leaves empty behind
it (e.g. an old year's own ef/<year>/ tree), stopping at --out itself --
without this, a pruned year's own directory would survive empty and
test -d would still see it.
schema/day-v1.json is resolved the same prefix-relative way data/ef's
own sexp files are (installed vs build-tree, probed rather than
assumed), never from cwd, and a missing schema fails with one line on
stderr before anything is written rather than emitting an empty file.
Needed schema/day-v1.json wired into the root dune file's default alias
and into test/dune's cram deps -- unlike data/ and templates/, nothing
made dune mirror schema/ into the build tree before this.
unix is added to bin/dune's libraries for mkdir_p; it ships with the
compiler, so colitur.opam and dune-project are unchanged.
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
Computes and renders in one process. There is deliberately no stdin-fed
render: honouring the pipe would need a JSON parser we would have to
write, purely to serialise and immediately re-parse our own view -- a
second hand-rolled component and a second place for the contract to
drift, for no benefit. colitur emit --format json | jq still composes.
An unknown extension with no --flavour is an error naming the six valid
flavours, never a silent fallback to none: guessing wrong produces
malformed output that looks fine until it does not.
A malformed template reports the parser's own reason and exits 2. A
template is user input; it must never crash the program.
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
Reuses resolved_year_report's existing two-liturgical-year indexing
rather than copying it: that walk owns the civil-vs-liturgical span
reasoning, and a second copy would drift. It is refactored to return the
days, with the printer layered on top, so day and readings behave
identically -- which cli.t proves byte-for-byte.
CSV emits one header for a whole multi-year run, not one per year.
A reversed range is a usage error rather than silently empty output.
Asserted in cli.t: two ics runs are byte-identical, because nothing in
the path reads a clock.
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
Poland and the Benedictines, in the flat INI form, installed beside the
invented diocesan example.
poland.ini -- 17 entries from the Calendarium Perpetuum pro Dioecesium
Poloniae (1964), promulgated under Rubricarum instructum and applying to the
1962 Missal. Transcribed from a published Polish EF ordo that names that same
calendar, cross-checked against missalemeum's supplement page for the two
formularies 1964 added (13 and 15 July). Date, Latin name and class were read
from the source for every entry; three classes could not be recovered from
the PDF's column layout and are marked INFERRED where they appear, with the
reasoning. The header carries an edition warning that is a real trap here:
the Proprium Poloniae of 1921 and 1934 is still bound into many missals and
carries an outdated arrangement of dioceses and ranks. It is not this
calendar, and it is exactly the kind of plausible wrong-edition source that
has cost this project time before.
benedictine.ini -- two entries, and the comment explaining why is the point of
shipping it. Counted across the Norcia ordo: 86 "I cl.", 43 "II cl.", ZERO
"III cl." and ZERO "IV cl.", against 103 "Semidup." and ~96 "Dup.". The
monastic rite uses the Roman classes at the top and the older Duplex /
Semiduplex grades below, exactly where the Roman calendar has III and IV
class. colitur's rank vocabulary cannot express those, so most Benedictine
propers cannot be written here at all -- a mismatch of vocabularies between
related rites, not a gap in the data. Rather than invent a Duplex -> Class3
mapping the source never states, that file ships only what its ordo gives in
Roman terms and lists roughly two dozen excluded feasts BY NAME, so the
omission is visible instead of silent.
Both headers say plainly that they are examples and not authorities: they are
transcriptions from published ordines, none of the five test layers can vouch
for either, and both should be checked against the reader's own ordo. The
cram test asserts only what we control -- that they parse, convert and apply
-- and says so.
They also demonstrate the precedence engine on real data: the Benedictine
Transitus is I class and takes 21 March with the Lenten feria commemorated,
and Maurus is II class and takes 15 January with Paul the First Hermit
commemorated.
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
The format was documented; the pipeline was not. The commonest surprise when
writing a local calendar is 'my feast does not appear', and it is almost never
a loading failure -- which means the existing docs answered a question nobody
was asking.
Four stages, named: load, merge, resolve, emit. The one that matters is
resolve, and the point it makes explicit is that overlay entries take part in
precedence on EQUAL TERMS. A local feast is not privileged for being local; it
competes under RG 91's table exactly as a universal one does.
Three concrete causes of a missing feast, each of which came up while testing
this branch: outranked by the day it lands on, a date structurally occupied
(an easter+60 feast can never appear, because Corpus Christi is Easter+60 and
is I class), or a commemoration past RG 111's limit for the day's class. And
the diagnostic rule -- if check says the file loaded and every directive found
its target, the answer is stage 3, so raise the class or move the date.
Also records why the shipped adjustments are applied first and why that is not
configurable: replacing rather than layering would silently drop the
inseparable Peter/Paul commemoration, the Major Litanies, St Barbara and
Rogation Wednesday. Overriding one deliberately by naming its slug is a
different thing from losing it by accident.
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
A convenience format for calendars that add a few local feasts and drop one
or two universal entries. Section names are slugs, a [overlay] section carries
the id, and status/subject/layer default so the common case -- an ordinary
local saint's feast -- says only what distinguishes it.
It is a FRONT DOOR, not a second data model. It parses to exactly the
Overlay.t the S-expression form parses to, and everything downstream is the
same code on the same values; a test asserts an INI overlay and its
hand-written sexp equivalent produce identical Overlay.t values. It is also
deliberately less expressive -- Add, Suppress and single-field Edit only --
and refuses Replace, multi-field edits and citation edits BY NAME rather than
dropping them silently. Anything it cannot say is a reason to write sexp.
Little of this is new machinery: tools/bootstrap_sanctoral.ml has parsed INI
and mapped it to celebrations since the sanctoral was bootstrapped from
lectio. The dates needed extending, since that mapping handled only MM-DD;
the flat forms are easter+N/easter-N and mon/day/nth, with nth negative to
count from the end.
`colitur convert` is a separate step rather than --overlay sniffing the
extension, so the author can read what their INI became. When a date form was
mistyped, "what did the engine actually get" is the question, and an invisible
transpile cannot answer it.
The conversion verifies its own output: the emitted text is parsed back with
the same function that loads an overlay and must equal what the INI denoted,
or nothing is written. That is the point of the module. A transpiler emitting
valid-but-wrong sexp is the failure a convenience format invites, and `colitur
check` could never catch it -- the output would parse cleanly and mean
something else.
That check was WRONG on the first attempt, in exactly the way it exists to
prevent. It re-serialised the parsed value instead of parsing the text being
returned, so it verified t -> sexp -> t, which is true by construction and
proves nothing. Found by mutation: corrupting the renderer to emit a different
overlay id sailed through and exited 0. It now parses the returned text, the
mutation is caught with exit 2, and two tests fail under it where none did
before.
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
The overlay format was documented in three partial places -- a paragraph in
colitur(1), a block in --help, and the comments inside the shipped example --
none of which was a reference. Someone writing a diocesan calendar had to
read all three and infer the rest.
Section 5 because an overlay is a thing a user AUTHORS rather than a command
they run: it belongs beside fstab(5), not in man1.
Covers every directive and every field edit, the six required fields and the
two optional ones, all three date specifications including the signed
Easter_offset and the negative nth, three worked examples, and the caveats.
The subject field gets a note explaining that it is not decoration -- it
decides whether a feast displaces an occurring Sunday under RG 16(a).
Two things it says that the code says and the old prose did not. There is no
Set_status and no Set_date among the field edits, deliberately: changing an
entry's status or its date makes it a different celebration rather than an
edited one, so Replace is the right directive and the change stays visible in
`colitur check` output. And a local feast missing from output has usually
LOST its day under the general rubrics rather than failed to load -- the
engine applies precedence to overlay entries exactly as to universal ones,
which is the first thing an author hits and was written down nowhere.
Writing it caught a documentation bug before it shipped: a first draft listed
a Set_status edit that does not exist and omitted Remove_name that does. Every
documented edit is now cross-checked against overlay.mli.
Linked from colitur(1)'s SEE ALSO and its OVERLAYS section, and from --help.
The Makefile installs it into man5, removes it on uninstall, and the man and
doc targets lint both pages.
|
| |
|
|
|
|
|
|
|
|
|
|
|
| |
Both listed check and new-overlay among the commands but neither told a
reader how they fit together, which is the part that makes them useful. The
overlay sections now carry the four-step loop -- new-overlay, edit, check,
run -- and state what check does not do, since its name invites a stronger
reading than it earns.
Also documents what the format now permits: citations and layer optional, the
signed Easter_offset, the negative nth counting from the end of the month,
and the legal values of each of the six required fields, which previously
appeared only in the shipped example.
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
Writing a local calendar had no feedback loop. An overlay is applied, not
validated -- that stays true, and the five test layers still cannot vouch for
a user's file -- but before this the only way to learn whether yours did what
you meant was to generate a year of output and grep for your own slug, and the
only way to see that a directive matched nothing was to notice a warning
scroll past among 365 lines.
`check` loads each overlay, applies it to the real shipped calendar, and
reports the directive counts, the slug each one targets, and any directive
that found no target. It exits 2 when a file fails to load or a directive
matched nothing, so it composes into a Makefile or a pre-commit hook rather
than merely being readable. It is applied to the SHIPPED calendar and not to
an empty layer on purpose: against an empty one every Suppress would fail
trivially and the check would be worthless.
It answers three narrow questions -- does the file parse, does every directive
find its target, what does the merged result contain. It does not validate a
calendar against the rubrics and cannot, and both the help text and the man
page say so rather than letting the name imply more than it does.
`new-overlay` prints a starter to stdout for redirection, rather than writing
a file where it likes. Every value in it is a placeholder that will appear in
`day` output if left unedited, so a half-finished overlay is visible rather
than silently inert, and it documents the three date shapes and the legal
values for each closed field inline.
load_ef_layer now returns its diagnostics instead of printing them: day and
readings still want them on stderr beside a year of output, while check wants
them on stdout, attributed to the overlay that produced them, and counted.
Printing at the source made the second impossible.
The cram test round-trips new-overlay through check rather than pinning the
template line by line -- editing its prose should not fail a test, but a
syntax error in it still must.
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
`--overlay` shipped last week with nothing to point at. The only example
was a test fixture, explicitly labelled invented and living where no user
would find it, so "colitur supports local calendars" was true but
undemonstrated.
data/ef/examples/diocesan-example.sexp is installed to
<prefix>/share/colitur/examples/ and is runnable documentation: every
celebration in it is invented, with example- slugs that cannot collide,
and its header explains the four directives, the three date shapes, and
the field vocabularies before showing any of them.
It demonstrates the range deliberately rather than the minimum: a
fixed-date local patron with its own propers; a movable dedication on the
first Sunday of October, I class because a church's own dedication
anniversary is I class in that church and at III it would lose to the
Sunday every year; an Easter-relative commemoration; an Edit raising a
universal feast for local use; and a Suppress shown commented out,
because suppressing a universal feast is a real liturgical act and an
example should not invite it casually.
Two things the header says plainly, since this is the one file that lets
someone change what colitur computes: an overlay is applied ON TOP of the
shipped calendar and never instead of it, and an overlay is applied, NOT
validated -- the five test layers assert things about the shipped data
and cannot vouch for a user's file.
A test asserts it loads against the real EF rank vocabulary, still
demonstrates at least four directives, and applies with NO diagnostics.
The last matters most: a directive naming a slug the universal calendar
lacks would warn, and an example that warns teaches the wrong lesson. It
deliberately does not pin which days it produces -- those celebrations
are invented, and pinning their dates would make an illustrative file
behave like calendar data.
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
The Overlay algebra has been built and tested since Plan 2, and
Date_spec grew movable variants last commit, but there was still no way
to hand colitur a file: bin/main.ml applied exactly one overlay, the
shipped data/ef/adjustments.sexp, with the path hardcoded. This is the
plumbing.
--overlay is repeatable and ordered, and applies ON TOP of the shipped
adjustments rather than instead of them. That ordering is the whole
point: adjustments.sexp carries RG 110's own 30 June companion, the Major
Litanies, St Barbara and Rogation Wednesday, and a user file that
replaced it would silently drop all four while appearing merely to add a
local feast. Overlay.merge is last-writer-wins, so a local calendar can
still override a universal entry deliberately, by naming its slug.
The dispatch needed real argument parsing. It matched Sys.argv as an
exact array, which does not survive a repeatable flag -- two --overlay
arguments are a different array shape from one, and each further flag
would multiply the patterns again. Flags are now stripped first and the
remaining words matched as command plus year. Hand-rolled, because the
dependency list is frozen and this is fifteen lines. One defect found by
the cram suite on the first run: the unknown-option guard rejected
--help and --version, having excluded only their short forms.
Refused, not ignored, on easter and temporal. Neither reads sanctoral
data -- temporal deliberately runs the cycle before any layer exists --
so accepting the flag there and silently doing nothing is the failure
mode this project refuses everywhere else.
A file that fails to load is fatal, exactly as the shipped overlay is; a
directive naming a slug that does not exist warns on stderr and the run
continues. The second matters more for a user file than for ours: a typo
in a diocesan calendar should say so rather than quietly do nothing.
test/fixtures/overlay-example-diocesan.sexp is a worked example and is
labelled as invented, not calendar data. It carries both shapes a real
local calendar needs: a fixed-date patron, and a dedication on "the first
Sunday of October" -- which is the case the Date_spec work existed to
unlock and which lands on 4 October in 2026, 3 October in 2027, 1 October
in 2028. The dedication is I class because a church's own dedication
anniversary is I class in that church; at III class it lost to the
II-class Sunday every year, which a first draft demonstrated correctly
and uselessly.
The man page gains an OVERLAYS section saying plainly that an overlay is
applied, NOT validated: the five test layers assert things about the
shipped calendar and none of them can vouch for a file the user supplies.
This is the first feature that lets someone change what colitur computes,
and that distinction should not have to be inferred.
|
|
|
Three things the project had no answer for: how to install it without
knowing dune, where to read about it, and what it does when asked.
Makefile, same shape as lectio's -- PREFIX ?= $(HOME)/.local, BINDIR,
MANDIR, and the '## '-comment help target -- so the two siblings are
driven the same way. Every recipe wraps dune in `opam exec --`, which is
the actual point of having one here: `make build` works from a plain
shell with no `eval $(opam env)` first. install goes through `dune
install` rather than a hand-rolled copy, because the binary finds its
calendar data relative to its own path; the man page is installed
separately to share/man/man1, matching lectio. install and uninstall
were both run against a scratch prefix and checked: uninstall leaves
zero files behind.
PREFIX defaults to ~/.local because that is where lectio installs and
where it actually lives on this machine, so colitur lands on an existing
PATH with no shell change. An earlier install this session went to
~/opt/colitur, which was me over-applying a rule meant for third-party
tools to one of the author's own projects; it has been removed rather
than left as a second, staler binary competing on PATH.
man/colitur.1 documents the four commands, both output formats and why
they differ, COLITUR_DATA_DIR and its refusal to fall back, the data
resolution order, exit statuses, and -- deliberately -- the limitations:
EF only, Epistle and Gospel only with the chants unbuilt and rejected
rather than guessed, and the BVM Saturday Mass-selection gap. A man page
that only lists what works is half a man page. Renders clean under
`groff -ww -z`, no warnings.
--help prints to stdout and exits 0; a usage error prints one line to
stderr and exits 2. That is the Unix convention rather than a
preference: asking for help succeeded and should be pipeable, being
invoked wrongly did not and must not pollute stdout. Both directions are
asserted in cli.t, along with a loop confirming every command the help
text advertises is one the dispatch actually accepts -- the check that
catches help drifting away from the code.
|