aboutsummaryrefslogtreecommitdiff
path: root/internal/cli
diff options
context:
space:
mode:
Diffstat (limited to 'internal/cli')
-rw-r--r--internal/cli/cli.go90
-rw-r--r--internal/cli/cli_test.go87
2 files changed, 109 insertions, 68 deletions
diff --git a/internal/cli/cli.go b/internal/cli/cli.go
index bd080b9..76ebd5b 100644
--- a/internal/cli/cli.go
+++ b/internal/cli/cli.go
@@ -42,8 +42,7 @@ Flags:
-C, --clean prune cached readings older than a year
-P, --pager page reading output (like git); default from config
--no-pager never page, even if config sets one
- --list-pl list all books with Polish names + abbreviations
- --list-en list all books with English names + abbreviations
+ --list list all books + abbreviations (dialect from sigla_style)
-v, --version print the version and exit
-h, --help this help
@@ -57,9 +56,9 @@ Examples:
lectio -b vul -a Vulgate text, all readings
lectio -l trad -a traditional lectionary, all readings
lectio -u harvest sigla to the horizon
- lectio -p "J 3:16" -b vul look up a passage in one version
- lectio -p "Ps 23:1" -c wuj,drb compare a passage across versions
- lectio --list-en list every book (English) + abbreviations
+ lectio -p "Jn 3:16" -b vul look up a passage (English sigla)
+ lectio -p "J 3,16" -c wuj,drb Polish sigla when sigla_style=polish/auto+pl UI
+ lectio --list list every book + abbreviations
Flags override config. Exit codes: 0 ok, 1 runtime error (fetch/parse),
2 usage error (bad flag, bad date, bad version, bad --lectionary/--lang).
@@ -100,7 +99,7 @@ func Run(args []string, stdin io.Reader, stdout, stderr io.Writer) int {
var all, raw, refresh, offline, update, clean, pagerFlag, noPager bool
var bibleVer, compareList, lectionary, lang string
var width int
- var listPL, listEN bool
+ var list bool
var ref string
fs := flag.NewFlagSet("lectio", flag.ContinueOnError)
@@ -134,8 +133,7 @@ func Run(args []string, stdin io.Reader, stdout, stderr io.Writer) int {
fs.BoolVar(&noPager, "no-pager", false, "never page, even if config sets one")
fs.StringVar(&ref, "p", "", "look up a passage, e.g. \"J 3:16\" (with -b/-c)")
fs.StringVar(&ref, "ref", "", "look up a passage, e.g. \"J 3:16\" (with -b/-c)")
- fs.BoolVar(&listPL, "list-pl", false, "list all books with Polish names + abbreviations")
- fs.BoolVar(&listEN, "list-en", false, "list all books with English names + abbreviations")
+ fs.BoolVar(&list, "list", false, "list all books + abbreviations (in your sigla_style)")
if err := fs.Parse(rest); err != nil {
return 2
@@ -217,6 +215,15 @@ func Run(args []string, stdin io.Reader, stdout, stderr io.Writer) int {
}
}
+ var bookTbl *bible.BookTable
+ if list || ref != "" {
+ tbl, terr := bible.LoadBookTable(userBooksTOML())
+ if terr != nil {
+ fmt.Fprintln(stderr, "lectio:", terr) // warn; tbl is still a usable defaults table
+ }
+ bookTbl = tbl
+ }
+
out := stdout
finish := func() {}
if pagerRequested(pagerFlag, noPager, cfg) && isTerminalWriter(stdout) {
@@ -228,10 +235,10 @@ func Run(args []string, stdin io.Reader, stdout, stderr io.Writer) int {
var code int
switch {
- case listPL || listEN:
- code = runList(listEN && !listPL, out)
+ case list:
+ code = runList(bookTbl, cfg.SiglaLang(), out)
case ref != "":
- code = lookupRef(cfg, ref, refVersions, raw, effWidth, out, stderr)
+ code = lookupRef(cfg, bookTbl, ref, refVersions, raw, effWidth, out, stderr)
case compareList != "":
code = renderCompare(cfg, compareList, date, effAll, raw, effWidth, refresh, out, stderr)
case bibleVer != "":
@@ -243,6 +250,20 @@ func Run(args []string, stdin io.Reader, stdout, stderr io.Writer) int {
return code
}
+// userBooksTOML returns the bytes of the optional user books.toml, or nil if
+// it is absent/unreadable (built-in defaults are used).
+func userBooksTOML() []byte {
+ p, err := config.BooksPath()
+ if err != nil {
+ return nil
+ }
+ b, err := os.ReadFile(p)
+ if err != nil {
+ return nil
+ }
+ return b
+}
+
// wantsHelp reports whether -h/--help appears anywhere in args.
func wantsHelp(args []string) bool {
for _, a := range args {
@@ -603,24 +624,26 @@ func refLookupVersions(cfg config.Config, bibleVer, compareList string) ([]strin
return nil, fmt.Errorf("--ref needs a corpus version; pass -b wuj|vul|grb|drb")
}
-// lookupRef renders a passage lookup (-p/--ref). A --ref citation is already in
-// target form (a "Book chap:verse" reference), exactly like a traditional
-// (missalemeum) citation, so it reuses the same render path with
-// lectionary="traditional": render.GatherVersion/Compare then resolve the ref
-// literally via bible.Lookup (no Polish->English niedziela conversion). versions
-// is the already-validated corpus set (never "bt"). raw omits the header for
-// piping. Exit 1 if NO requested version yields any verse.
-func lookupRef(cfg config.Config, ref string, versions []string, raw bool, width int, stdout, stderr io.Writer) int {
+// lookupRef renders a passage lookup (-p/--ref). It parses the typed reference
+// in the resolved sigla dialect (bookTbl.ParseRef -- dialect-scoped book names
+// and number syntax) into an English colon-style reference, then reuses the
+// same render path as the readings with lectionary="traditional" (the ref is
+// already in target form, looked up literally per version -- no niedziela
+// conversion, no cross-version psalm renumbering). versions is the validated
+// corpus set (never "bt"). raw omits the header. Exit 2 on an unparseable ref,
+// exit 1 if no requested version has the passage.
+func lookupRef(cfg config.Config, tbl *bible.BookTable, ref string, versions []string, raw bool, width int, stdout, stderr io.Writer) int {
ref = strings.TrimSpace(ref)
- if ref == "" {
- fmt.Fprintln(stderr, "lectio: empty --ref")
+ engRef, ok := tbl.ParseRef(cfg.SiglaLang(), ref)
+ if !ok {
+ fmt.Fprintf(stderr, "lectio: could not read reference %q in the %s dialect; see 'lectio --list'\n", ref, cfg.SiglaLang())
return 2
}
- sec := liturgy.Section{Citation: ref, Heading: ref}
+ sec := liturgy.Section{Citation: engRef, Heading: engRef}
found := false
for _, v := range versions {
- if vs, _ := bible.Lookup(v, ref); len(vs) > 0 {
+ if vs, _ := bible.Lookup(v, engRef); len(vs) > 0 {
found = true
break
}
@@ -663,22 +686,17 @@ func lookupRef(cfg config.Config, ref string, versions []string, raw bool, width
return 0
}
-// runList handles --list-pl/--list-en: print every Biblical book (scriptural
-// order) as "<abbrev> <name>", the name in Polish when pl, English otherwise.
-// The abbreviation column is padded by rune count (not bytes) so diacritics
-// like "Łk"/"Kpł" still line up.
-func runList(en bool, stdout io.Writer) int {
- const col = 6
- for _, b := range bible.Books() {
- name := b.Polish
- if en {
- name = b.English
- }
- pad := col - len([]rune(b.Abbrev))
+// runList handles --list: print every book of the sigla dialect (scriptural
+// order) as "<shortcut> <name>". The shortcut column is padded by rune count
+// so diacritics ("Łk") still line up.
+func runList(tbl *bible.BookTable, dialect string, stdout io.Writer) int {
+ const col = 8
+ for _, b := range tbl.Books(dialect) {
+ pad := col - len([]rune(b.Shortcut))
if pad < 1 {
pad = 1
}
- fmt.Fprintf(stdout, "%s%s%s\n", b.Abbrev, strings.Repeat(" ", pad), name)
+ fmt.Fprintf(stdout, "%s%s%s\n", b.Shortcut, strings.Repeat(" ", pad), b.Name)
}
return 0
}
diff --git a/internal/cli/cli_test.go b/internal/cli/cli_test.go
index c76d61c..bc7dfdb 100644
--- a/internal/cli/cli_test.go
+++ b/internal/cli/cli_test.go
@@ -9,6 +9,7 @@ import (
"strings"
"testing"
+ "github.com/lukaszkasprzak/lectio/internal/bible"
"github.com/lukaszkasprzak/lectio/internal/liturgy"
)
@@ -268,64 +269,86 @@ func TestExtractDateDefaultsToday(t *testing.T) {
}
}
-func TestListEN(t *testing.T) {
+func TestRefSingle(t *testing.T) {
+ var out, errb bytes.Buffer
+ code := Run([]string{"-p", "Jn 3:16", "-b", "vul"}, nil, &out, &errb)
+ if code != 0 {
+ t.Fatalf("ref code=%d stderr=%q", code, errb.String())
+ }
+ if s := out.String(); !strings.Contains(s, "3:16") {
+ t.Errorf("ref output missing verse 3:16:\n%s", s)
+ }
+}
+
+func TestRefNotFound(t *testing.T) {
var out, errb bytes.Buffer
- if code := Run([]string{"--list-en"}, nil, &out, &errb); code != 0 {
- t.Fatalf("--list-en code=%d stderr=%q", code, errb.String())
+ // An unknown book -> ParseRef fails to resolve it in the dialect -> exit 2.
+ if code := Run([]string{"-p", "Zzz 9:9", "-b", "vul"}, nil, &out, &errb); code != 2 {
+ t.Errorf("ref unknown-book code=%d want 2 (stderr=%q)", code, errb.String())
+ }
+}
+
+func TestRunListEnglish(t *testing.T) {
+ tbl, _ := bible.LoadBookTable(nil)
+ var out bytes.Buffer
+ if code := runList(tbl, "en", &out); code != 0 {
+ t.Fatalf("runList en code=%d", code)
}
- s := out.String()
- if !strings.Contains(s, "John") || !strings.Contains(s, "Genesis") {
- t.Errorf("--list-en missing expected books:\n%s", s)
+ if s := out.String(); !strings.Contains(s, "Jn") || !strings.Contains(s, "John") {
+ t.Errorf("en list missing Jn/John:\n%s", s)
}
- // abbrev-then-name, one book per line; expect a J -> John line.
- if !strings.Contains(s, "J") {
- t.Errorf("--list-en missing John abbrev")
+}
+
+func TestRunListPolish(t *testing.T) {
+ tbl, _ := bible.LoadBookTable(nil)
+ var out bytes.Buffer
+ runList(tbl, "pl", &out)
+ if s := out.String(); !strings.Contains(s, "Jana") || !strings.Contains(s, "Rodzaju") {
+ t.Errorf("pl list missing Jana/Rodzaju:\n%s", s)
}
}
-func TestListPL(t *testing.T) {
+func TestListFlag(t *testing.T) {
var out, errb bytes.Buffer
- if code := Run([]string{"--list-pl"}, nil, &out, &errb); code != 0 {
- t.Fatalf("--list-pl code=%d stderr=%q", code, errb.String())
+ if code := Run([]string{"--list"}, nil, &out, &errb); code != 0 {
+ t.Fatalf("--list code=%d stderr=%q", code, errb.String())
}
- if s := out.String(); !strings.Contains(s, "Jan") || !strings.Contains(s, "Rodzaju") {
- t.Errorf("--list-pl missing Polish names:\n%s", s)
+ if n := strings.Count(strings.TrimSpace(out.String()), "\n") + 1; n < 73 {
+ t.Errorf("--list printed %d lines, want >=73", n)
}
}
-func TestRefSingle(t *testing.T) {
+func TestRefEnglishDialect(t *testing.T) {
var out, errb bytes.Buffer
- code := Run([]string{"-p", "J 3:16", "-b", "vul"}, nil, &out, &errb)
- if code != 0 {
+ if code := Run([]string{"-p", "Jn 3:16", "-b", "vul"}, nil, &out, &errb); code != 0 {
t.Fatalf("ref code=%d stderr=%q", code, errb.String())
}
- if s := out.String(); !strings.Contains(s, "3:16") {
- t.Errorf("ref output missing verse 3:16:\n%s", s)
+ if !strings.Contains(out.String(), "3:16") {
+ t.Errorf("ref output missing 3:16:\n%s", out.String())
+ }
+}
+
+func TestRefRejectsPolishAbbrevInEnglish(t *testing.T) {
+ var out, errb bytes.Buffer
+ // English dialect (default): the Polish abbrev "Łk" must not resolve.
+ if code := Run([]string{"-p", "Łk 3:16", "-b", "vul"}, nil, &out, &errb); code != 2 {
+ t.Errorf("Łk in en dialect code=%d want 2 (stderr=%q)", code, errb.String())
}
}
func TestRefRejectsBT(t *testing.T) {
var out, errb bytes.Buffer
- if code := Run([]string{"-p", "J 3:16", "-b", "bt"}, nil, &out, &errb); code != 2 {
+ if code := Run([]string{"-p", "Jn 3:16", "-b", "bt"}, nil, &out, &errb); code != 2 {
t.Errorf("ref -b bt code=%d want 2 (stderr=%q)", code, errb.String())
}
}
func TestRefCompare(t *testing.T) {
var out, errb bytes.Buffer
- code := Run([]string{"-p", "J 3:16", "-c", "vul,drb"}, nil, &out, &errb)
- if code != 0 {
+ if code := Run([]string{"-p", "Jn 3:16", "-c", "vul,drb"}, nil, &out, &errb); code != 0 {
t.Fatalf("ref compare code=%d stderr=%q", code, errb.String())
}
- if s := out.String(); !strings.Contains(s, "3:16") {
- t.Errorf("ref compare missing verse:\n%s", s)
- }
-}
-
-func TestRefNotFound(t *testing.T) {
- var out, errb bytes.Buffer
- // A book/verse the corpus won't have text for -> exit 1.
- if code := Run([]string{"-p", "Zzz 9:9", "-b", "vul"}, nil, &out, &errb); code != 1 {
- t.Errorf("ref not-found code=%d want 1 (stderr=%q)", code, errb.String())
+ if !strings.Contains(out.String(), "3:16") {
+ t.Errorf("ref compare missing verse:\n%s", out.String())
}
}