From a13dd6224a095242da54062e4775570c4f16a718 Mon Sep 17 00:00:00 2001 From: Lukasz Kasprzak Date: Mon, 27 Jul 2026 14:42:56 +0200 Subject: feat(cli,caldata): EF feast proper readings — offline text in --liturgy MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Added 1962 Epistle+Gospel citations (from missalemeum) to the 15 EF feasts; --liturgy now resolves + renders the reading text via the corpora (drb/wuj), incl. deuterocanon (Assumption's Judith epistle). Cross-chapter citations use their primary range pending multi-chapter parser support. --- internal/caldata/tridentine-calendar.ini | 30 +++++++++++++++++++++++ internal/cli/liturgy.go | 41 +++++++++++++++++++++++++++++--- internal/cli/liturgy_test.go | 2 +- 3 files changed, 69 insertions(+), 4 deletions(-) diff --git a/internal/caldata/tridentine-calendar.ini b/internal/caldata/tridentine-calendar.ini index f3e9111..81b6349 100644 --- a/internal/caldata/tridentine-calendar.ini +++ b/internal/caldata/tridentine-calendar.ini @@ -14,6 +14,8 @@ type = universal ; --- I class --- [immaculate-conception] +reading.first = Prov 8:22-35 +reading.gospel = Luke 1:26-28 date = 12-08 rank = class-1 colour = white @@ -21,6 +23,8 @@ name.en = The Immaculate Conception of the Blessed Virgin Mary name.la = In Conceptione Immaculata Beatae Mariae Virginis [st-joseph] +reading.first = Sir 45:1-6 +reading.gospel = Matt 1:18-21 date = 03-19 rank = class-1 colour = white @@ -28,6 +32,8 @@ name.en = Saint Joseph, Spouse of the Blessed Virgin Mary name.la = Sancti Joseph Sponsi Beatae Mariae Virginis [annunciation] +reading.first = Isa 7:10-15 +reading.gospel = Luke 1:26-38 date = 03-25 rank = class-1 colour = white @@ -35,18 +41,24 @@ name.en = The Annunciation of the Blessed Virgin Mary name.la = In Annuntiatione Beatae Mariae Virginis [nativity-john-baptist] +reading.first = Isa 49:1-3,5-7 +reading.gospel = Luke 1:57-68 date = 06-24 rank = class-1 colour = white name.en = The Nativity of Saint John the Baptist [peter-and-paul] +reading.first = Acts 12:1-11 +reading.gospel = Matt 16:13-19 date = 06-29 rank = class-1 colour = red name.en = Saints Peter and Paul, Apostles [assumption] +reading.first = Judith 13:22-25 +reading.gospel = Luke 1:41-50 date = 08-15 rank = class-1 colour = white @@ -54,12 +66,16 @@ name.en = The Assumption of the Blessed Virgin Mary name.la = In Assumptione Beatae Mariae Virginis [st-michael] +reading.first = Rev 1:1-5 +reading.gospel = Matt 18:1-10 date = 09-29 rank = class-1 colour = white name.en = The Dedication of Saint Michael the Archangel [all-saints] +reading.first = Rev 7:2-12 +reading.gospel = Matt 5:1-12 date = 11-01 rank = class-1 colour = white @@ -68,30 +84,40 @@ name.en = All Saints ; --- II class --- [purification] +reading.first = Mal 3:1-4 +reading.gospel = Luke 2:22-32 date = 02-02 rank = class-2 colour = white name.en = The Purification of the Blessed Virgin Mary [st-lawrence] +reading.first = 2 Cor 9:6-10 +reading.gospel = John 12:24-26 date = 08-10 rank = class-2 colour = red name.en = Saint Lawrence, Martyr [nativity-bvm] +reading.first = Prov 8:22-35 +reading.gospel = Matt 1:1-16 date = 09-08 rank = class-2 colour = white name.en = The Nativity of the Blessed Virgin Mary [exaltation-of-the-cross] +reading.first = Phil 2:5-11 +reading.gospel = John 12:31-36 date = 09-14 rank = class-2 colour = red name.en = The Exaltation of the Holy Cross [st-andrew] +reading.first = Rom 10:10-18 +reading.gospel = Matt 4:18-22 date = 11-30 rank = class-2 colour = red @@ -100,12 +126,16 @@ name.en = Saint Andrew, Apostle ; --- III class --- [conversion-of-paul] +reading.first = Acts 9:1-22 +reading.gospel = Matt 19:27-29 date = 01-25 rank = class-3 colour = white name.en = The Conversion of Saint Paul the Apostle [st-lucy] +reading.first = 2 Cor 10:17-18 +reading.gospel = Matt 13:44-52 date = 12-13 rank = class-3 colour = red diff --git a/internal/cli/liturgy.go b/internal/cli/liturgy.go index b1a8874..fc3efae 100644 --- a/internal/cli/liturgy.go +++ b/internal/cli/liturgy.go @@ -6,9 +6,11 @@ import ( "strings" "time" + "github.com/lukaszkasprzak/lectio/internal/bible" "github.com/lukaszkasprzak/lectio/internal/caldata" "github.com/lukaszkasprzak/lectio/internal/calendar" "github.com/lukaszkasprzak/lectio/internal/config" + "github.com/lukaszkasprzak/lectio/internal/render" ) // runLiturgy prints the computed liturgical day for date (default today) using @@ -29,11 +31,36 @@ func runLiturgy(cfg config.Config, date string, stdout, stderr io.Writer) int { fmt.Fprintln(stderr, "lectio: warning:", e) } day := calendar.Compute(d.UTC(), cfg.Selection(), layers) - printLiturgicalDay(stdout, cfg, day) + tbl, _ := bible.LoadBookTable(userBooksTOML()) + printLiturgicalDay(stdout, cfg, tbl, day) return 0 } -func printLiturgicalDay(out io.Writer, cfg config.Config, day calendar.LiturgicalDay) { +// vernacularVersion is the offline corpus used to render reading text: Wujek +// for Polish, Douay-Rheims otherwise (bt is scraped, so it is not used here). +func vernacularVersion(cfg config.Config) string { + if cfg.TraditionalLang == "pl" || cfg.UILanguage == "pl" { + return "wuj" + } + return "drb" +} + +// readingText resolves an English citation and returns its text from version, +// or "" if it does not resolve. +func readingText(tbl *bible.BookTable, version, citation string) string { + engRef, ok := tbl.ParseRef("en", citation) + if !ok { + return "" + } + vs, _ := bible.Lookup(version, engRef) + parts := make([]string, 0, len(vs)) + for _, v := range vs { + parts = append(parts, strings.TrimSpace(v.Text)) + } + return strings.Join(parts, " ") +} + +func printLiturgicalDay(out io.Writer, cfg config.Config, tbl *bible.BookTable, day calendar.LiturgicalDay) { fmt.Fprintf(out, "%s %s\n", day.Date.Format("2006-01-02"), day.Weekday.String()) if day.SundayCycle != "" { // OF carries the reading cycles; EF does not fmt.Fprintf(out, "season: %s (week %d · Sunday cycle %s · weekday cycle %s)\n", @@ -47,13 +74,21 @@ func printLiturgicalDay(out io.Writer, cfg config.Config, day calendar.Liturgica fmt.Fprintf(out, " also: %s [%s]\n", n, rankLabel(o.Rank)) } } + vern := vernacularVersion(cfg) for _, m := range day.Observed.Masses { for _, r := range m.Readings { label := r.Part if m.Variant != "" { label = m.Variant + " " + label } - fmt.Fprintf(out, " %-16s %s\n", label+":", r.Citation) + fmt.Fprintf(out, "\n %s (%s):\n", label, r.Citation) + if txt := readingText(tbl, vern, r.Citation); txt != "" { + for _, line := range strings.Split(render.Wrap(txt, 72), "\n") { + fmt.Fprintf(out, " %s\n", line) + } + } else { + fmt.Fprintf(out, " (text not in %s)\n", vern) + } } } } diff --git a/internal/cli/liturgy_test.go b/internal/cli/liturgy_test.go index c9d66a5..91e3974 100644 --- a/internal/cli/liturgy_test.go +++ b/internal/cli/liturgy_test.go @@ -28,7 +28,7 @@ func TestRunLiturgy(t *testing.T) { if !strings.Contains(strings.ToLower(out), "solemnity") || !strings.Contains(out, "Assumption") { t.Errorf("2025-08-15 should be the Assumption solemnity:\n%s", out) } - if !strings.Contains(out, "gospel:") { + if !strings.Contains(out, "gospel (") { t.Errorf("proper reading not shown:\n%s", out) } } -- cgit v1.3