diff options
Diffstat (limited to 'internal/cli/cli.go')
| -rw-r--r-- | internal/cli/cli.go | 100 |
1 files changed, 97 insertions, 3 deletions
diff --git a/internal/cli/cli.go b/internal/cli/cli.go index ef00010..ff1299a 100644 --- a/internal/cli/cli.go +++ b/internal/cli/cli.go @@ -7,6 +7,7 @@ import ( "flag" "fmt" "io" + "math/rand" "os" "regexp" "strconv" @@ -45,6 +46,8 @@ Flags: --list list all books + abbreviations (dialect from sigla_style) --citation print the day's gospel reference (scripts/cron) and exit --week list the coming week's gospel references and exit + --rand, --rand-v print a random verse (corpus version) and exit + --rand-ch print a random chapter and exit -v, --version print the version and exit -h, --help this help @@ -63,6 +66,7 @@ Examples: lectio --list list every book + abbreviations lectio --citation today's gospel reference lectio --week 2026-07-22 a week of gospel references from a date + lectio --rand-v a random verse (for cron/prompt) Flags override config. Exit codes: 0 ok, 1 runtime error (fetch/parse), 2 usage error (bad flag, bad date, bad version, bad --lectionary/--lang). @@ -101,6 +105,7 @@ func Run(args []string, stdin io.Reader, stdout, stderr io.Writer) int { } var all, raw, refresh, offline, update, clean, pagerFlag, noPager, citation, week bool + var randV, randCh bool var bibleVer, compareList, lectionary, lang string var width int var list bool @@ -140,6 +145,9 @@ func Run(args []string, stdin io.Reader, stdout, stderr io.Writer) int { fs.BoolVar(&list, "list", false, "list all books + abbreviations (in your sigla_style)") fs.BoolVar(&citation, "citation", false, "print the day's gospel reference and exit") fs.BoolVar(&week, "week", false, "list the coming week's gospel references and exit") + fs.BoolVar(&randV, "rand", false, "print a random verse from the corpus and exit") + fs.BoolVar(&randV, "rand-v", false, "print a random verse from the corpus and exit") + fs.BoolVar(&randCh, "rand-ch", false, "print a random chapter from the corpus and exit") if err := fs.Parse(rest); err != nil { return 2 @@ -181,12 +189,21 @@ func Run(args []string, stdin io.Reader, stdout, stderr io.Writer) int { cfg.TraditionalLang = lang } - if citation || week { + if citation || week || randV || randCh { tbl, _ := bible.LoadBookTable(userBooksTOML()) - if citation { + switch { + case randV || randCh: + ver, verr := randVersion(cfg, bibleVer) + if verr != nil { + fmt.Fprintln(stderr, "lectio:", verr) + return 2 + } + return runRand(cfg, tbl, ver, randCh, raw, width, stdout, stderr) + case citation: return runCitation(cfg, tbl, date, refresh, stdout, stderr) + default: + return runWeek(cfg, tbl, date, refresh, stdout, stderr) } - return runWeek(cfg, tbl, date, refresh, stdout, stderr) } effAll := all || cfg.All @@ -693,6 +710,83 @@ func renderCompare(cfg config.Config, list, date string, all, raw bool, width in return 0 } +// randVersion picks the corpus version for --rand: an explicit -b VER (rejected +// if it has no corpus), else the configured default_version if it has a corpus, +// else the first corpus version in cfg.Versions, else "wuj". So a config whose +// default is "bt" (no corpus) still yields a random passage. +func randVersion(cfg config.Config, bibleVer string) (string, error) { + if bibleVer != "" { + if !isCorpusVersion(bibleVer) { + return "", fmt.Errorf("--rand needs a corpus version; %q has no full text (use wuj, vul, grb, drb)", bibleVer) + } + return bibleVer, nil + } + if isCorpusVersion(cfg.DefaultVersion) { + return cfg.DefaultVersion, nil + } + for _, v := range cfg.Versions { + if isCorpusVersion(v) { + return v, nil + } + } + return "wuj", nil +} + +// runRand prints a random verse (chapter=false) or whole chapter (chapter=true) +// from version's embedded corpus, for a "verse of the day" cron/pipe. It picks a +// random book -> chapter -> verse (not perfectly uniform across all verses, but +// fine for the purpose). Non-raw prints the reference (in cfg's sigla dialect) +// then the text; raw prints just the text (verse-numbered for a chapter). +func runRand(cfg config.Config, tbl *bible.BookTable, version string, chapter, raw bool, width int, stdout, stderr io.Writer) int { + books := bible.CorpusBooks(version) + if len(books) == 0 { + fmt.Fprintf(stderr, "lectio: no corpus for version %q\n", version) + return 1 + } + rng := rand.New(rand.NewSource(time.Now().UnixNano())) + + var book string + var chap int + var verses []bible.Verse + for tries := 0; tries < 20 && len(verses) == 0; tries++ { + book = books[rng.Intn(len(books))] + chaps := bible.Chapters(version, book) + if len(chaps) == 0 { + continue + } + chap = chaps[rng.Intn(len(chaps))] + verses = bible.Verses(version, book, chap) + } + if len(verses) == 0 { + fmt.Fprintln(stderr, "lectio: could not pick a random passage") + return 1 + } + + w := resolveWidth(width, false, stdout) + dialect := cfg.SiglaLang() + + if chapter { + if !raw { + fmt.Fprintln(stdout, fmt.Sprintf("%s %d", tbl.Abbrev(dialect, book), chap)) + fmt.Fprintln(stdout) + } + lines := make([]string, 0, len(verses)) + for _, v := range verses { + lines = append(lines, wrapText(fmt.Sprintf("%d %s", v.Verse, v.Text), w)) + } + fmt.Fprintln(stdout, strings.Join(lines, "\n")) + return 0 + } + + v := verses[rng.Intn(len(verses))] + if !raw { + fmt.Fprintln(stdout, tbl.FormatRef(dialect, fmt.Sprintf("%s %d:%d", book, chap, v.Verse))) + fmt.Fprintln(stdout) + } + fmt.Fprintln(stdout, wrapText(v.Text, w)) + return 0 +} + // isCorpusVersion reports whether v is a scripture-text version with an // embedded corpus (wuj/vul/grb/drb) -- i.e. a valid version that is not "bt" // (the niedziela.pl scrape, which has no full text to look a passage up in). |
