summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLukasz Kasprzak <lukas@labunix.xyz>2026-08-20 16:19:25 +0200
committerLukasz Kasprzak <lukas@labunix.xyz>2026-08-20 16:19:25 +0200
commit87b155b913cea7f5c55b5a2391aff7819ba541a6 (patch)
tree616df0de0f9fa8a08f6fd4156fa5fdac8fb9a1c3
parent263d0d889073d214229aef9655d3db29540c0d12 (diff)
downloadcolitur-87b155b913cea7f5c55b5a2391aff7819ba541a6.tar.gz
colitur-87b155b913cea7f5c55b5a2391aff7819ba541a6.zip
feat(config): sigla_style, sigla_book and sigla_tradition
Same flag > config > default precedence as --lang, and each reported by config --show with its source, so an override is visible rather than mysterious. A language file's [sigla] section IS a style; a config key SELECTS one and may override settings within it -- the two are not a duplicate setting.
-rw-r--r--bin/main.ml147
-rw-r--r--lib/naming/config.ml13
-rw-r--r--lib/naming/config.mli24
-rw-r--r--test/cli.t99
-rw-r--r--test/test_config.ml35
5 files changed, 284 insertions, 34 deletions
diff --git a/bin/main.ml b/bin/main.ml
index 5c9f342..8434586 100644
--- a/bin/main.ml
+++ b/bin/main.ml
@@ -672,13 +672,15 @@ let load_lang ~raw ~flag ~config =
every other tradition uses -- one code path, not a special case for the
default.
- Not called from anywhere in this file yet: citations reach output at
- exactly two places, [View.citation_ref] and [part_ref] below, and
- threading [Sigla.t] (which this feeds) through both is a dedicated task
- on its own, deliberately not done here alongside the loader. [-32] is
- silenced for exactly that reason -- this is a complete, correct,
- ready-to-call function with no caller yet, not dead code. *)
-let[@warning "-32"] load_tradition name =
+ Called from [config_show] below (Task 8's own [--sigla-tradition]
+ plumbing), which discards the returned [tradition] and keeps only the
+ validation side effect -- `config --show` reports the RESOLVED STRING,
+ exactly like every other row, not a loaded object. Citations themselves
+ still reach output at exactly two places, [View.citation_ref] and
+ [part_ref] below, and threading the loaded [tradition] through both to
+ actually renumber a reference is Task 9's own dedicated job, not this
+ one's. *)
+let load_tradition name =
let path = Filename.concat (lang_dir ()) "traditions.ini" in
let vulgate () = Colitur_citation.Book.vulgate in
match read_file path with
@@ -1157,6 +1159,24 @@ naming:
it is `colitur lang`'s own identity table, under which every
lookup echoes its key back unchanged.
+ --sigla-style CODE|FILE, --sigla-book full|abbr, --sigla-tradition NAME
+ settings for how a Mass reading CITATION is written -- WHICH
+ punctuation/abbreviation style, WHICH book form, and WHICH
+ numbering tradition. Each has a config-key counterpart
+ (`sigla_style`/`sigla_book`/`sigla_tradition`) resolved with
+ the identical flag > config > default precedence as --lang, and
+ each is reported by `colitur config --show` with its source.
+ Defaults: `sigla_style` the resolved language code (so a
+ booklet's citations follow its own --lang unless told
+ otherwise), `sigla_book` `abbr`, `sigla_tradition` `vulgate`.
+ An unrecognised `--sigla-book` is a hard ERROR (want `full` or
+ `abbr`), the same discipline as an unknown `--lang`; an
+ unrecognised `--sigla-tradition` is not -- it degrades to the
+ Vulgate with a stderr warning, because asking for a renumbering
+ is optional the way asking for a language is not. Settings
+ only, for now: this build resolves and reports them but does
+ not yet render a citation through them.
+
colitur lang --list which language files this build can find, and
each one's own declared fallback, if any.
colitur lang --dump CODE the named language's full key set, in INI
@@ -1170,7 +1190,8 @@ naming:
anything is unknown, so it fits a Makefile or
a pre-commit hook.
colitur config --show every effective setting -- lang, overlay,
- template, format -- its resolved value, and
+ template, format, sigla_style, sigla_book,
+ sigla_tradition -- its resolved value, and
where it came from: `flag`, `config` or
`default`. See colitur-config(5) for the
config file's location and full precedence.
@@ -1322,6 +1343,10 @@ let with_year ys f =
the same shape as [prune]. [dump]/[check]/[list]/[show] (Task 7,
`colitur lang`/`colitur config`) follow the identical two shapes --
[dump]/[check] each take one value, [list]/[show] are bare. *)
+(* [sigla_style]/[sigla_book]/[sigla_tradition] (Task 8) are three more
+ single-valued optional settings, the same shape as [lang] -- each has a
+ config-key counterpart in [Colitur_naming.Config] and is resolved through
+ the identical [Config.resolve] precedence (flag > config > default). *)
type parsed_args = {
overlays : string list;
format : string option;
@@ -1339,6 +1364,9 @@ type parsed_args = {
check : string option;
list : bool;
show : bool;
+ sigla_style : string option;
+ sigla_book : string option;
+ sigla_tradition : string option;
positional : string list;
}
@@ -1373,6 +1401,12 @@ let parse_args argv =
| [ "--check" ] -> Error "--check needs a file path"
| "--list" :: rest -> go { acc with list = true } rest
| "--show" :: rest -> go { acc with show = true } rest
+ | "--sigla-style" :: v :: rest -> go { acc with sigla_style = Some v } rest
+ | [ "--sigla-style" ] -> Error "--sigla-style needs a language code or file path"
+ | "--sigla-book" :: v :: rest -> go { acc with sigla_book = Some v } rest
+ | [ "--sigla-book" ] -> Error "--sigla-book needs a value (full or abbr)"
+ | "--sigla-tradition" :: v :: rest -> go { acc with sigla_tradition = Some v } rest
+ | [ "--sigla-tradition" ] -> Error "--sigla-tradition needs a section name from lang/traditions.ini"
(* The recognised bare flags pass through as positional words for the
dispatch below to match; anything else beginning with '-' is rejected
rather than silently treated as a command or a year. *)
@@ -1386,7 +1420,8 @@ let parse_args argv =
go
{ overlays = []; format = None; from_y = None; to_y = None; dtstamp = None; year = None;
template = None; flavour = None; out = None; prune = false; lang = None; raw = false;
- dump = None; check = None; list = false; show = false; positional = [] }
+ dump = None; check = None; list = false; show = false; sigla_style = None; sigla_book = None;
+ sigla_tradition = None; positional = [] }
argv
(* Sibling to [reject_overlays_for]: `emit`'s own four flags have no meaning
@@ -1467,6 +1502,21 @@ let reject_lang_subcommand_flags_for cmd ~dump ~check ~list ~show =
exit 2
end
+(* Sibling again: `--sigla-style`/`--sigla-book`/`--sigla-tradition` (Task 8)
+ are settings plumbing only -- resolved and reported by `colitur config
+ --show` alone. Actually rendering a citation through them is Task 9's
+ job, so every OTHER command refuses the three flags rather than silently
+ accepting and ignoring them, the same discipline every rejector above
+ keeps; `config` is the one place that wires them in. *)
+let reject_sigla_for cmd ~sigla_style ~sigla_book ~sigla_tradition =
+ if sigla_style <> None || sigla_book <> None || sigla_tradition <> None then begin
+ Printf.eprintf
+ "colitur: --sigla-style/--sigla-book/--sigla-tradition have no effect on `%s`; refusing rather \
+ than ignoring them\n"
+ cmd;
+ exit 2
+ end
+
(* `colitur check FILE...` -- load a user overlay, apply it to the real
shipped calendar, and say what it did, without printing a year of output.
@@ -1739,24 +1789,68 @@ let lang_check path =
given these SAME command-line flags (so `config --show --lang fr` shows
exactly what a real `--lang fr` run would use); [overlay] is a list, so
it has no single "value" to resolve -- shown as one line per effective
- entry instead, with its own source. *)
-let config_show ~lang_flag ~template_flag ~format_flag ~overlays_flag config =
+ entry instead, with its own source.
+
+ [sigla_style]/[sigla_book]/[sigla_tradition] (Task 8) join the same
+ scalar rows, resolved through the identical [Config.resolve]. Two are
+ NOT arbitrary strings, though, so "report" also means "validate", the
+ same way an unknown [--lang] is an error rather than a silent Latin
+ fallback:
+ - [sigla_book] is a closed two-value setting ([full]/[abbr]) --
+ [Colitur_citation.Render.with_book] takes a variant, not a string, so
+ an unrecognised value could never mean anything downstream. Checked
+ HERE, not deferred to Task 9's actual renderer, because this is
+ currently the only place that consumes the value at all.
+ - [sigla_tradition] names a section of [lang/traditions.ini]; resolving
+ it for real (via [load_tradition], the same reader Task 9's renderer
+ will use) rather than only printing the string means a typo is caught
+ right here too -- though, unlike [sigla_book], [load_tradition] is
+ BY DESIGN never fatal (see its own comment: asking for a renumbering
+ is optional, unlike asking for a language), so an unknown tradition
+ degrades to a stderr warning and the Vulgate, exactly as it will under
+ Task 9, not a [config --show] failure.
+ [sigla_style] gets no such check: like [lang] itself, it is an open
+ language code or path, not a closed set, and [config --show] does not
+ validate [lang] either (that only happens when a command actually loads
+ it via [load_lang]). *)
+let config_show ~lang_flag ~template_flag ~format_flag ~overlays_flag ~sigla_style_flag ~sigla_book_flag
+ ~sigla_tradition_flag config =
let cpath = config_path () in
Printf.printf "config file: %s (%s)\n" cpath
(if cpath <> "" && Sys.file_exists cpath then "exists" else "not found");
let scalar name flag cfgval default =
let v, src = Colitur_naming.Config.resolve ~flag ~config:cfgval ~default in
- Printf.printf "%-10s %-24s (%s)\n" name v src
+ Printf.printf "%-16s %-24s (%s)\n" name v src;
+ v
+ in
+ let lang_value = scalar "lang" lang_flag (Colitur_naming.Config.lang config) "la" in
+ let _ = scalar "template" template_flag (Colitur_naming.Config.template config) "(none)" in
+ let _ = scalar "format" format_flag (Colitur_naming.Config.format config) "(none)" in
+ (* Default is the resolved LANGUAGE, not a literal "la": a booklet that
+ asked for --lang fr and named no --sigla-style of its own gets French
+ citations too, not a silent switch back to Latin punctuation. *)
+ let _ = scalar "sigla_style" sigla_style_flag (Colitur_naming.Config.sigla_style config) lang_value in
+ let sigla_book_value, sigla_book_src =
+ Colitur_naming.Config.resolve ~flag:sigla_book_flag ~config:(Colitur_naming.Config.sigla_book config)
+ ~default:"abbr"
+ in
+ if sigla_book_value <> "full" && sigla_book_value <> "abbr" then begin
+ Printf.eprintf "colitur: unknown --sigla-book %S (want \"full\" or \"abbr\")\n" sigla_book_value;
+ exit 2
+ end;
+ Printf.printf "%-16s %-24s (%s)\n" "sigla_book" sigla_book_value sigla_book_src;
+ let sigla_tradition_value, sigla_tradition_src =
+ Colitur_naming.Config.resolve ~flag:sigla_tradition_flag
+ ~config:(Colitur_naming.Config.sigla_tradition config) ~default:"vulgate"
in
- scalar "lang" lang_flag (Colitur_naming.Config.lang config) "la";
- scalar "template" template_flag (Colitur_naming.Config.template config) "(none)";
- scalar "format" format_flag (Colitur_naming.Config.format config) "(none)";
+ let _ = load_tradition sigla_tradition_value in
+ Printf.printf "%-16s %-24s (%s)\n" "sigla_tradition" sigla_tradition_value sigla_tradition_src;
(match overlays_flag with
- | _ :: _ as l -> List.iter (fun o -> Printf.printf "%-10s %-24s (%s)\n" "overlay" o "flag") l
+ | _ :: _ as l -> List.iter (fun o -> Printf.printf "%-16s %-24s (%s)\n" "overlay" o "flag") l
| [] -> (
match Colitur_naming.Config.overlays config with
- | [] -> Printf.printf "%-10s %-24s (%s)\n" "overlay" "(none)" "default"
- | l -> List.iter (fun o -> Printf.printf "%-10s %-24s (%s)\n" "overlay" o "config") l))
+ | [] -> Printf.printf "%-16s %-24s (%s)\n" "overlay" "(none)" "default"
+ | l -> List.iter (fun o -> Printf.printf "%-16s %-24s (%s)\n" "overlay" o "config") l))
(* `colitur new-overlay` -- a starter file on stdout, for redirection.
Deliberately printed rather than written: the user picks the path, and a
@@ -1819,12 +1913,13 @@ let () =
Printf.eprintf "colitur: %s\n" msg;
usage ()
| Ok { overlays; format; from_y; to_y; dtstamp; year; template; flavour; out; prune; lang;
- raw; dump; check; list; show; positional } -> (
+ raw; dump; check; list; show; sigla_style; sigla_book; sigla_tradition; positional } -> (
let reject_emit = reject_emit_flags_for ~format ~from_y ~to_y ~dtstamp in
let reject_table = reject_table_flags_for ~year ~template ~flavour in
let reject_publish = reject_publish_flags_for ~out ~prune in
let reject_lang = reject_lang_for ~lang ~raw in
let reject_lang_sub = reject_lang_subcommand_flags_for ~dump ~check ~list ~show in
+ let reject_sigla = reject_sigla_for ~sigla_style ~sigla_book ~sigla_tradition in
(* Loaded once, unconditionally: a config file the user wrote and
colitur cannot honour (missing HOME aside, [load_config] treats
that as "no config" rather than an error) is worth surfacing on
@@ -1855,6 +1950,7 @@ let () =
reject_publish "--help";
reject_lang "--help";
reject_lang_sub "--help";
+ reject_sigla "--help";
print_help ()
| [ ("-V" | "--version" | "version") ] ->
reject_overlays_for "--version" overlays;
@@ -1863,6 +1959,7 @@ let () =
reject_publish "--version";
reject_lang "--version";
reject_lang_sub "--version";
+ reject_sigla "--version";
print_endline version;
exit 0
| [ "easter"; ys ] ->
@@ -1872,6 +1969,7 @@ let () =
reject_publish "easter";
reject_lang "easter";
reject_lang_sub "easter";
+ reject_sigla "easter";
with_year ys easter_report
| [ "temporal"; ys ] ->
reject_overlays_for "temporal" overlays;
@@ -1880,6 +1978,7 @@ let () =
reject_publish "temporal";
reject_lang "temporal";
reject_lang_sub "temporal";
+ reject_sigla "temporal";
with_year ys temporal_report
| "check" :: (_ :: _ as files) ->
reject_overlays_for "check" overlays;
@@ -1888,6 +1987,7 @@ let () =
reject_publish "check";
reject_lang "check";
reject_lang_sub "check";
+ reject_sigla "check";
check_report files
| [ "convert"; path ] ->
reject_overlays_for "convert" overlays;
@@ -1896,6 +1996,7 @@ let () =
reject_publish "convert";
reject_lang "convert";
reject_lang_sub "convert";
+ reject_sigla "convert";
convert_report path
| [ "new-overlay" ] ->
reject_overlays_for "new-overlay" overlays;
@@ -1904,6 +2005,7 @@ let () =
reject_publish "new-overlay";
reject_lang "new-overlay";
reject_lang_sub "new-overlay";
+ reject_sigla "new-overlay";
print_string new_overlay_template;
exit 0
| [ "lang" ] -> (
@@ -1912,6 +2014,7 @@ let () =
reject_table "lang";
reject_publish "lang";
reject_lang "lang";
+ reject_sigla "lang";
if show then begin
Printf.eprintf "colitur: --show has no effect on `lang`; refusing rather than ignoring it\n";
exit 2
@@ -1956,23 +2059,27 @@ let () =
exit 2
end;
config_show ~lang_flag:lang ~template_flag:template ~format_flag:format ~overlays_flag:overlays
+ ~sigla_style_flag:sigla_style ~sigla_book_flag:sigla_book ~sigla_tradition_flag:sigla_tradition
config
| [ "day"; ys ] ->
reject_emit "day";
reject_table "day";
reject_publish "day";
reject_lang_sub "day";
+ reject_sigla "day";
with_year ys (day_report ~lang:(resolved_lang ()) ~overlays:effective_overlays)
| [ "readings"; ys ] ->
reject_emit "readings";
reject_table "readings";
reject_publish "readings";
reject_lang_sub "readings";
+ reject_sigla "readings";
with_year ys (readings_report ~lang:(resolved_lang ()) ~overlays:effective_overlays)
| [ "emit" ] -> (
reject_table "emit";
reject_publish "emit";
reject_lang_sub "emit";
+ reject_sigla "emit";
match (match format with Some f -> Some f | None -> Colitur_naming.Config.format config) with
| None ->
Printf.eprintf "colitur: emit requires --format csv|json|sexp|xml|ics\n";
@@ -1992,6 +2099,7 @@ let () =
reject_emit cmd;
reject_publish cmd;
reject_lang_sub cmd;
+ reject_sigla cmd;
match (match template with Some t -> Some t | None -> Colitur_naming.Config.template config) with
| None ->
Printf.eprintf "colitur: %s requires --year YEAR and --template FILE\n" cmd;
@@ -2010,6 +2118,7 @@ let () =
reject_table "publish";
reject_format_for "publish" format;
reject_lang_sub "publish";
+ reject_sigla "publish";
match out with
| None ->
Printf.eprintf "colitur: publish requires --out DIR\n";
diff --git a/lib/naming/config.ml b/lib/naming/config.ml
index 7d87d62..068b40a 100644
--- a/lib/naming/config.ml
+++ b/lib/naming/config.ml
@@ -5,18 +5,24 @@ type t = {
overlays : string list;
template : string option;
format : string option;
+ sigla_style : string option;
+ sigla_book : string option;
+ sigla_tradition : string option;
unknown_keys : string list;
unknown_sections : string list;
}
let empty =
- { lang = None; overlays = []; template = None; format = None; unknown_keys = [];
- unknown_sections = [] }
+ { lang = None; overlays = []; template = None; format = None; sigla_style = None;
+ sigla_book = None; sigla_tradition = None; unknown_keys = []; unknown_sections = [] }
let lang t = t.lang
let overlays t = t.overlays
let template t = t.template
let format t = t.format
+let sigla_style t = t.sigla_style
+let sigla_book t = t.sigla_book
+let sigla_tradition t = t.sigla_tradition
let unknown_keys t = t.unknown_keys
let unknown_sections t = t.unknown_sections
@@ -65,6 +71,9 @@ let of_string text =
| "lang" -> { acc with lang = Some v }
| "template" -> { acc with template = Some v }
| "format" -> { acc with format = Some v }
+ | "sigla_style" -> { acc with sigla_style = Some v }
+ | "sigla_book" -> { acc with sigla_book = Some v }
+ | "sigla_tradition" -> { acc with sigla_tradition = Some v }
(* accumulates: a user has more than one overlay *)
| "overlay" -> { acc with overlays = v :: acc.overlays }
| other -> { acc with unknown_keys = other :: acc.unknown_keys })
diff --git a/lib/naming/config.mli b/lib/naming/config.mli
index a84f95b..a5205c4 100644
--- a/lib/naming/config.mli
+++ b/lib/naming/config.mli
@@ -29,6 +29,30 @@ val overlays : t -> string list
val template : t -> string option
val format : t -> string option
+(** Which citation style to render a reference in: a language CODE, looked
+ up the same way {!lang} is, or a path -- but a DIFFERENT axis from
+ {!lang}: a language file's own [\[sigla\]] section IS a style
+ ({!Colitur_citation.Render.style_of_fields}), and this key SELECTS
+ which file's [\[sigla\]] section supplies it, independently of which
+ file's other sections supply names elsewhere (a booklet may want
+ Polish names but Latin-convention citations). Same last-wins duplicate
+ policy as {!lang}. *)
+val sigla_style : t -> string option
+
+(** [full] or [abbr] -- overrides the style's own [book] setting rather than
+ replacing the style outright, so a chosen style's punctuation survives
+ even when the book form is overridden ({!Colitur_citation.Render.with_book}).
+ Same last-wins duplicate policy as {!lang}. *)
+val sigla_book : t -> string option
+
+(** The name of a section in [lang/traditions.ini] -- which BOOK a reference
+ DENOTES (Vulgate numbering by default), a different question again from
+ both {!sigla_style} (how a reference is WRITTEN) and {!lang} (what
+ everything else is CALLED): naming and numbering both vary by
+ convention, but not together. Same last-wins duplicate policy as
+ {!lang}. *)
+val sigla_tradition : t -> string option
+
(** Keys present in the [\[defaults\]] section that this build does not
understand. Reported, never fatal: a config written for a newer colitur
must still work on an older one, but silently ignoring a line the user
diff --git a/test/cli.t b/test/cli.t
index 9ea7beb..e0a0058 100644
--- a/test/cli.t
+++ b/test/cli.t
@@ -1258,10 +1258,13 @@ literally either):
$ XDG_CONFIG_HOME=xdg-test colitur config --show
config file: xdg-test/colitur/config.ini (not found)
- lang la (default)
- template (none) (default)
- format (none) (default)
- overlay (none) (default)
+ lang la (default)
+ template (none) (default)
+ format (none) (default)
+ sigla_style la (default)
+ sigla_book abbr (default)
+ sigla_tradition vulgate (default)
+ overlay (none) (default)
A flag on the SAME command line previews exactly what it would resolve to
on any other command -- `overlay` has no single scalar value, so it is
@@ -1269,10 +1272,13 @@ listed one line per effective entry instead:
$ XDG_CONFIG_HOME=xdg-test colitur config --show --lang fr --overlay mine.sexp
config file: xdg-test/colitur/config.ini (not found)
- lang fr (flag)
- template (none) (default)
- format (none) (default)
- overlay mine.sexp (flag)
+ lang fr (flag)
+ template (none) (default)
+ format (none) (default)
+ sigla_style fr (default)
+ sigla_book abbr (default)
+ sigla_tradition vulgate (default)
+ overlay mine.sexp (flag)
A real config file supplies a default that a command with no explicit flag
then uses. An unrecognised key and an unrecognised section are each warned
@@ -1284,13 +1290,82 @@ differently from a misspelled key inside a recognised one:
$ printf '[defaults]\nlang = en\noverlay = /nonexistent/parish.sexp\nbogus = 1\n\n[deafults]\nlang = xx\n' > xdg-test/colitur/config.ini
$ XDG_CONFIG_HOME=xdg-test colitur config --show
config file: xdg-test/colitur/config.ini (exists)
- lang en (config)
- template (none) (default)
- format (none) (default)
- overlay /nonexistent/parish.sexp (config)
+ lang en (config)
+ template (none) (default)
+ format (none) (default)
+ sigla_style en (default)
+ sigla_book abbr (default)
+ sigla_tradition vulgate (default)
+ overlay /nonexistent/parish.sexp (config)
colitur: xdg-test/colitur/config.ini: unknown setting "bogus" (ignored)
colitur: xdg-test/colitur/config.ini: unknown section [deafults] (ignored)
+`--sigla-style`/`--sigla-book`/`--sigla-tradition` (Task 8) resolve through
+the identical flag > config > default precedence as --lang/--template/
+--format, each reported by its own row. `sigla_style` defaults to the
+RESOLVED language, not a literal "la" -- a booklet that asked for a
+different --lang gets its citations in that language too unless told
+otherwise. Run through a fresh XDG_CONFIG_HOME, so this does not depend on
+the config file the earlier examples left behind:
+
+ $ XDG_CONFIG_HOME=xdg-sigla colitur config --show --sigla-style pl --sigla-book full --sigla-tradition modern
+ config file: xdg-sigla/colitur/config.ini (not found)
+ lang la (default)
+ template (none) (default)
+ format (none) (default)
+ sigla_style pl (flag)
+ sigla_book full (flag)
+ sigla_tradition modern (flag)
+ overlay (none) (default)
+
+An unrecognised `--sigla-book` is a hard usage ERROR -- exit 2, one line on
+stderr -- the same discipline an unrecognised `--lang` gets, never a silent
+fallback: `Colitur_citation.Render.with_book` takes a closed variant, not an
+arbitrary string, so anything other than "full"/"abbr" could never mean
+anything downstream.
+
+ $ XDG_CONFIG_HOME=xdg-sigla colitur config --show --sigla-book bogus
+ config file: xdg-sigla/colitur/config.ini (not found)
+ lang la (default)
+ template (none) (default)
+ format (none) (default)
+ sigla_style la (default)
+ colitur: unknown --sigla-book "bogus" (want "full" or "abbr")
+ [2]
+
+An unrecognised `--sigla-tradition`, by contrast, is NOT fatal: it is
+resolved for real against lang/traditions.ini (the same reader a future
+renderer will use), and a name matching no section there degrades to the
+Vulgate with a warning on stderr, exactly as an unknown tradition does
+everywhere else in this project -- asking for a renumbering is optional the
+way asking for a language is not, so a run is not lost over a typo here.
+The warning itself carries lang/traditions.ini's own resolved PATH, which is
+absolute and build-tree-specific -- grepped for rather than matched in
+full, the same way the pre-existing "unknown language" case above already
+sidesteps that same non-portability:
+
+ $ XDG_CONFIG_HOME=xdg-sigla colitur config --show --sigla-tradition nonsense 2>/dev/null
+ config file: xdg-sigla/colitur/config.ini (not found)
+ lang la (default)
+ template (none) (default)
+ format (none) (default)
+ sigla_style la (default)
+ sigla_book abbr (default)
+ sigla_tradition nonsense (flag)
+ overlay (none) (default)
+ $ XDG_CONFIG_HOME=xdg-sigla colitur config --show --sigla-tradition nonsense 2>&1 >/dev/null | grep -c 'no tradition "nonsense"; falling back to the Vulgate'
+ 1
+
+`--sigla-style`/`--sigla-book`/`--sigla-tradition` have no effect on any
+other command yet -- resolving and reporting them is all this build does;
+actually rendering a citation through them is a later task -- refused
+rather than silently ignored, the same discipline `--dump`/`--check`/
+`--list`/`--show` already get above:
+
+ $ colitur day 2027 --sigla-style la > /dev/null
+ colitur: --sigla-style/--sigla-book/--sigla-tradition have no effect on `day`; refusing rather than ignoring them
+ [2]
+
`config` requires --show:
$ colitur config
diff --git a/test/test_config.ml b/test/test_config.ml
index 83da015..d348d9b 100644
--- a/test/test_config.ml
+++ b/test/test_config.ml
@@ -102,6 +102,35 @@ let test_two_defaults_blocks_report_no_unknown_sections () =
let c = ok (C.of_string text) in
Alcotest.(check (list string)) "no unknown sections" [] (C.unknown_sections c)
+(* Task 8: sigla_style/sigla_book/sigla_tradition read the same way
+ lang/template/format do, in the same [\[defaults\]] section -- no new
+ section, and every key recognised (so [unknown_keys] stays empty). *)
+let test_sigla_keys_are_read () =
+ let text =
+ "[defaults]\nsigla_style = la\nsigla_book = full\nsigla_tradition = modern\n"
+ in
+ match C.of_string text with
+ | Error e -> Alcotest.failf "parse: %s" e
+ | Ok c ->
+ Alcotest.(check (option string)) "style" (Some "la") (C.sigla_style c);
+ Alcotest.(check (option string)) "book" (Some "full") (C.sigla_book c);
+ Alcotest.(check (option string)) "tradition" (Some "modern") (C.sigla_tradition c);
+ Alcotest.(check (list string)) "nothing unknown" [] (C.unknown_keys c)
+
+(* The empty config carries no sigla settings either -- same "all None"
+ contract [test_empty_config_is_all_none] already asserts for lang. *)
+let test_empty_config_sigla_keys_are_none () =
+ Alcotest.(check (option string)) "sigla_style" None (C.sigla_style C.empty);
+ Alcotest.(check (option string)) "sigla_book" None (C.sigla_book C.empty);
+ Alcotest.(check (option string)) "sigla_tradition" None (C.sigla_tradition C.empty)
+
+(* Same last-wins duplicate policy as lang/template/format: a key repeated
+ across two [\[defaults\]] blocks resolves to the LATER block's value. *)
+let test_sigla_key_repeated_across_blocks_last_wins () =
+ let text = "[defaults]\nsigla_book = full\n\n[defaults]\nsigla_book = abbr\n" in
+ let c = ok (C.of_string text) in
+ Alcotest.(check (option string)) "later block's sigla_book wins" (Some "abbr") (C.sigla_book c)
+
let suite =
( "Config",
[ Alcotest.test_case "reads defaults" `Quick test_reads_defaults;
@@ -119,4 +148,8 @@ let suite =
Alcotest.test_case "overlays accumulate across blocks"
`Quick test_overlays_accumulate_across_blocks;
Alcotest.test_case "two defaults blocks report no unknown sections"
- `Quick test_two_defaults_blocks_report_no_unknown_sections ] )
+ `Quick test_two_defaults_blocks_report_no_unknown_sections;
+ Alcotest.test_case "sigla keys are read" `Quick test_sigla_keys_are_read;
+ Alcotest.test_case "empty config sigla keys are none" `Quick test_empty_config_sigla_keys_are_none;
+ Alcotest.test_case "sigla key repeated across blocks last wins"
+ `Quick test_sigla_key_repeated_across_blocks_last_wins ] )