aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLukasz Kasprzak <lukas@labunix.xyz>2026-07-23 23:45:07 +0200
committerLukasz Kasprzak <lukas@labunix.xyz>2026-07-23 23:45:07 +0200
commitc1b954ad517cef00bf480d5229b253a8c6524be7 (patch)
tree376a281de7604782722d5780657aff319c32a1d6
parent369c995292b0ae830e077c5845f0b09fbe3508a4 (diff)
downloadlectio-c1b954ad517cef00bf480d5229b253a8c6524be7.tar.gz
lectio-c1b954ad517cef00bf480d5229b253a8c6524be7.zip
cli-ui,web: real flag parsing for lectio-ui/lectio-web (accept useful flags, reject unknown, -h/-v)
-rw-r--r--cmd/lectio-ui/main.go162
-rw-r--r--cmd/lectio-ui/main_test.go103
-rw-r--r--cmd/lectio-web/main.go122
-rw-r--r--cmd/lectio-web/main_test.go87
-rw-r--r--internal/cli/cli.go34
-rw-r--r--internal/config/config.go24
-rw-r--r--internal/tui/tui.go23
-rw-r--r--internal/tui/tui_test.go4
8 files changed, 518 insertions, 41 deletions
diff --git a/cmd/lectio-ui/main.go b/cmd/lectio-ui/main.go
index 13e3551..1808e4a 100644
--- a/cmd/lectio-ui/main.go
+++ b/cmd/lectio-ui/main.go
@@ -1,8 +1,12 @@
+// Command lectio-ui is lectio's interactive Bubble Tea reader.
package main
import (
+ "flag"
"fmt"
+ "io"
"os"
+ "regexp"
tea "github.com/charmbracelet/bubbletea"
@@ -10,14 +14,162 @@ import (
"github.com/lukaszkasprzak/lectio/internal/tui"
)
+const helpText = `lectio-ui — interactive daily liturgy reader (Polish + 4 versions)
+
+Usage:
+ lectio-ui [DATE] [flags] DATE = YYYY-MM-DD (default: today), any position
+
+Flags:
+ -b, --bible VER start on version: pl,wuj,vul,grb,drb
+ -a, --all show all parts (override config)
+ -o, --offline cache/sigla only, no network
+ -l, --lectionary WHICH new|trad (trad -> traditional)
+ -g, --lang LANG traditional lectionary language: pl|en
+ -v, --version print the version and exit
+ -h, --help this help
+
+Versions: pl (Polski/niedziela.pl) wuj (Wujek) vul (Wulgata) grb (Grecki)
+ drb (Douay-Rheims)
+
+Flags override config. Exit codes: 0 ok, 1 runtime error, 2 usage error.
+`
+
+var dateRe = regexp.MustCompile(`^\d{4}-\d{2}-\d{2}$`)
+
func main() {
+ os.Exit(run(os.Args[1:], os.Stdout, os.Stderr))
+}
+
+// run is lectio-ui's testable entry point: parse args, validate, load
+// config, apply overrides, and launch the TUI. Returns a process exit code.
+func run(args []string, stdout, stderr io.Writer) int {
+ if wantsHelp(args) {
+ fmt.Fprint(stdout, helpText)
+ return 0
+ }
+ if wantsVersion(args) {
+ fmt.Fprintln(stdout, "lectio-ui "+config.Version)
+ return 0
+ }
+
+ date, rest, err := extractDate(args)
+ if err != nil {
+ fmt.Fprintln(stderr, "lectio-ui:", err)
+ return 2
+ }
+
cfg, err := config.Load()
if err != nil {
- fmt.Fprintln(os.Stderr, err)
- os.Exit(1)
+ fmt.Fprintln(stderr, "lectio-ui:", err)
+ return 1
+ }
+
+ var all, offline bool
+ var bibleVer, lectionary, lang string
+
+ fs := flag.NewFlagSet("lectio-ui", flag.ContinueOnError)
+ fs.SetOutput(stderr)
+ fs.Usage = func() { fmt.Fprint(stderr, helpText) }
+
+ fs.StringVar(&bibleVer, "b", "", "start on version: pl,wuj,vul,grb,drb")
+ fs.StringVar(&bibleVer, "bible", "", "start on version: pl,wuj,vul,grb,drb")
+ fs.BoolVar(&all, "a", cfg.All, "show all parts (override config)")
+ fs.BoolVar(&all, "all", cfg.All, "show all parts (override config)")
+ fs.BoolVar(&offline, "o", cfg.Offline, "cache/sigla only, no network")
+ fs.BoolVar(&offline, "offline", cfg.Offline, "cache/sigla only, no network")
+ fs.StringVar(&lectionary, "l", "", "new|trad")
+ fs.StringVar(&lectionary, "lectionary", "", "new|trad")
+ fs.StringVar(&lang, "g", "", "pl|en")
+ fs.StringVar(&lang, "lang", "", "pl|en")
+
+ if err := fs.Parse(rest); err != nil {
+ return 2
+ }
+ if fs.NArg() > 0 {
+ fmt.Fprintf(stderr, "lectio-ui: unexpected argument %q; see 'lectio-ui -h'\n", fs.Arg(0))
+ return 2
+ }
+
+ lectionary, err = normalizeLectionary(lectionary)
+ if err != nil {
+ fmt.Fprintln(stderr, "lectio-ui:", err)
+ return 2
+ }
+ if lang != "" && lang != "pl" && lang != "en" {
+ fmt.Fprintf(stderr, "lectio-ui: invalid --lang %q (want pl|en)\n", lang)
+ return 2
+ }
+ if bibleVer != "" && !config.ValidVersion(bibleVer) {
+ fmt.Fprintf(stderr, "lectio-ui: unknown version %q (want one of pl, wuj, vul, grb, drb)\n", bibleVer)
+ return 2
+ }
+
+ cfg.All = all
+ cfg.Offline = offline
+ if lectionary != "" {
+ cfg.Lectionary = lectionary
+ }
+ if lang != "" {
+ cfg.TraditionalLang = lang
+ }
+
+ if _, err := tea.NewProgram(tui.New(cfg, date, bibleVer), tea.WithAltScreen()).Run(); err != nil {
+ fmt.Fprintln(stderr, err)
+ return 1
+ }
+ return 0
+}
+
+// wantsHelp reports whether -h/--help appears anywhere in args.
+func wantsHelp(args []string) bool {
+ for _, a := range args {
+ if a == "-h" || a == "--help" {
+ return true
+ }
+ }
+ return false
+}
+
+// wantsVersion reports whether -v/--version appears anywhere in args.
+func wantsVersion(args []string) bool {
+ for _, a := range args {
+ if a == "-v" || a == "--version" {
+ return true
+ }
+ }
+ return false
+}
+
+// extractDate pulls the single positional DATE token (YYYY-MM-DD, matching
+// dateRe) out of args, wherever it appears, and returns it along with the
+// remaining tokens for flag.FlagSet to parse. Defaults to "" (New's
+// today-fallback) when no date token is present; errors if more than one is
+// found.
+func extractDate(args []string) (date string, rest []string, err error) {
+ found := false
+ for _, a := range args {
+ if dateRe.MatchString(a) {
+ if found {
+ return "", nil, fmt.Errorf("multiple dates given (%q and %q)", date, a)
+ }
+ date = a
+ found = true
+ continue
+ }
+ rest = append(rest, a)
+ }
+ return date, rest, nil
+}
+
+// normalizeLectionary maps -l/--lectionary's accepted spellings via
+// config.NormalizeLectionary; "" (flag not given) passes through unchanged.
+func normalizeLectionary(lectionary string) (string, error) {
+ if lectionary == "" {
+ return "", nil
}
- if _, err := tea.NewProgram(tui.New(cfg), tea.WithAltScreen()).Run(); err != nil {
- fmt.Fprintln(os.Stderr, err)
- os.Exit(1)
+ v, ok := config.NormalizeLectionary(lectionary)
+ if !ok {
+ return "", fmt.Errorf("invalid --lectionary %q (want new|trad)", lectionary)
}
+ return v, nil
}
diff --git a/cmd/lectio-ui/main_test.go b/cmd/lectio-ui/main_test.go
new file mode 100644
index 0000000..284fc67
--- /dev/null
+++ b/cmd/lectio-ui/main_test.go
@@ -0,0 +1,103 @@
+package main
+
+import (
+ "bytes"
+ "strings"
+ "testing"
+)
+
+func TestHelpFlag(t *testing.T) {
+ var out, errb bytes.Buffer
+ if code := run([]string{"-h"}, &out, &errb); code != 0 {
+ t.Errorf("-h code=%d (stderr=%q)", code, errb.String())
+ }
+ if !strings.Contains(out.String(), "lectio-ui") {
+ t.Errorf("-h output missing lectio-ui: %q", out.String())
+ }
+}
+
+func TestHelpLongFlag(t *testing.T) {
+ var out, errb bytes.Buffer
+ if code := run([]string{"--help"}, &out, &errb); code != 0 {
+ t.Errorf("--help code=%d (stderr=%q)", code, errb.String())
+ }
+ if !strings.Contains(out.String(), "lectio-ui") {
+ t.Errorf("--help output missing lectio-ui: %q", out.String())
+ }
+}
+
+func TestVersionFlag(t *testing.T) {
+ var out, errb bytes.Buffer
+ if code := run([]string{"-v"}, &out, &errb); code != 0 {
+ t.Errorf("-v code=%d (stderr=%q)", code, errb.String())
+ }
+ if !strings.Contains(out.String(), "lectio-ui") {
+ t.Errorf("-v output missing lectio-ui: %q", out.String())
+ }
+}
+
+func TestVersionLongFlag(t *testing.T) {
+ var out, errb bytes.Buffer
+ if code := run([]string{"--version"}, &out, &errb); code != 0 {
+ t.Errorf("--version code=%d (stderr=%q)", code, errb.String())
+ }
+ if !strings.Contains(out.String(), "lectio-ui") {
+ t.Errorf("--version output missing lectio-ui: %q", out.String())
+ }
+}
+
+func TestUnknownFlag(t *testing.T) {
+ t.Setenv("XDG_CONFIG_HOME", t.TempDir())
+ var out, errb bytes.Buffer
+ if code := run([]string{"-x"}, &out, &errb); code != 2 {
+ t.Errorf("-x code=%d want 2 (stderr=%q)", code, errb.String())
+ }
+}
+
+func TestUnknownLongFlag(t *testing.T) {
+ t.Setenv("XDG_CONFIG_HOME", t.TempDir())
+ var out, errb bytes.Buffer
+ if code := run([]string{"--bogus"}, &out, &errb); code != 2 {
+ t.Errorf("--bogus code=%d want 2 (stderr=%q)", code, errb.String())
+ }
+}
+
+func TestUnexpectedPositional(t *testing.T) {
+ t.Setenv("XDG_CONFIG_HOME", t.TempDir())
+ var out, errb bytes.Buffer
+ if code := run([]string{"bogus"}, &out, &errb); code != 2 {
+ t.Errorf("unexpected positional code=%d want 2 (stderr=%q)", code, errb.String())
+ }
+}
+
+func TestTwoDatesIsAmbiguous(t *testing.T) {
+ t.Setenv("XDG_CONFIG_HOME", t.TempDir())
+ var out, errb bytes.Buffer
+ if code := run([]string{"2026-07-22", "2026-07-23"}, &out, &errb); code != 2 {
+ t.Errorf("two dates code=%d want 2 (stderr=%q)", code, errb.String())
+ }
+}
+
+func TestLectionaryBogus(t *testing.T) {
+ t.Setenv("XDG_CONFIG_HOME", t.TempDir())
+ var out, errb bytes.Buffer
+ if code := run([]string{"-l", "bogus"}, &out, &errb); code != 2 {
+ t.Errorf("bogus lectionary code=%d want 2 (stderr=%q)", code, errb.String())
+ }
+}
+
+func TestLangBogus(t *testing.T) {
+ t.Setenv("XDG_CONFIG_HOME", t.TempDir())
+ var out, errb bytes.Buffer
+ if code := run([]string{"-g", "xx"}, &out, &errb); code != 2 {
+ t.Errorf("bogus lang code=%d want 2 (stderr=%q)", code, errb.String())
+ }
+}
+
+func TestBibleVersionBogus(t *testing.T) {
+ t.Setenv("XDG_CONFIG_HOME", t.TempDir())
+ var out, errb bytes.Buffer
+ if code := run([]string{"-b", "zzz"}, &out, &errb); code != 2 {
+ t.Errorf("bogus bible version code=%d want 2 (stderr=%q)", code, errb.String())
+ }
+}
diff --git a/cmd/lectio-web/main.go b/cmd/lectio-web/main.go
index 44845b8..2e7fa5a 100644
--- a/cmd/lectio-web/main.go
+++ b/cmd/lectio-web/main.go
@@ -1,21 +1,135 @@
+// Command lectio-web serves lectio's browser reading UI.
package main
import (
+ "flag"
"fmt"
+ "io"
"os"
"github.com/lukaszkasprzak/lectio/internal/config"
"github.com/lukaszkasprzak/lectio/internal/web"
)
+const helpText = `lectio-web — browser daily liturgy reader (Polish + 4 versions)
+
+Usage:
+ lectio-web [flags]
+
+Flags:
+ -p, --port N port (overrides web_port; 0 = auto)
+ -o, --offline cache/sigla only, no network
+ -l, --lectionary WHICH new|trad (trad -> traditional)
+ -g, --lang LANG traditional lectionary language: pl|en
+ -v, --version print the version and exit
+ -h, --help this help
+
+Flags override config. Exit codes: 0 ok, 1 runtime error, 2 usage error.
+`
+
func main() {
+ os.Exit(run(os.Args[1:], os.Stdout, os.Stderr))
+}
+
+// run is lectio-web's testable entry point: parse args, validate, load
+// config, apply overrides, and launch the server. Returns a process exit
+// code.
+func run(args []string, stdout, stderr io.Writer) int {
+ if wantsHelp(args) {
+ fmt.Fprint(stdout, helpText)
+ return 0
+ }
+ if wantsVersion(args) {
+ fmt.Fprintln(stdout, "lectio-web "+config.Version)
+ return 0
+ }
+
cfg, err := config.Load()
if err != nil {
- fmt.Fprintln(os.Stderr, err)
- os.Exit(1)
+ fmt.Fprintln(stderr, "lectio-web:", err)
+ return 1
}
+
+ var offline bool
+ var port int
+ var lectionary, lang string
+
+ fs := flag.NewFlagSet("lectio-web", flag.ContinueOnError)
+ fs.SetOutput(stderr)
+ fs.Usage = func() { fmt.Fprint(stderr, helpText) }
+
+ fs.IntVar(&port, "p", cfg.WebPort, "port (overrides web_port; 0 = auto)")
+ fs.IntVar(&port, "port", cfg.WebPort, "port (overrides web_port; 0 = auto)")
+ fs.BoolVar(&offline, "o", cfg.Offline, "cache/sigla only, no network")
+ fs.BoolVar(&offline, "offline", cfg.Offline, "cache/sigla only, no network")
+ fs.StringVar(&lectionary, "l", "", "new|trad")
+ fs.StringVar(&lectionary, "lectionary", "", "new|trad")
+ fs.StringVar(&lang, "g", "", "pl|en")
+ fs.StringVar(&lang, "lang", "", "pl|en")
+
+ if err := fs.Parse(args); err != nil {
+ return 2
+ }
+ if fs.NArg() > 0 {
+ fmt.Fprintf(stderr, "lectio-web: unexpected argument %q; see 'lectio-web -h'\n", fs.Arg(0))
+ return 2
+ }
+
+ lectionary, err = normalizeLectionary(lectionary)
+ if err != nil {
+ fmt.Fprintln(stderr, "lectio-web:", err)
+ return 2
+ }
+ if lang != "" && lang != "pl" && lang != "en" {
+ fmt.Fprintf(stderr, "lectio-web: invalid --lang %q (want pl|en)\n", lang)
+ return 2
+ }
+
+ cfg.WebPort = port
+ cfg.Offline = offline
+ if lectionary != "" {
+ cfg.Lectionary = lectionary
+ }
+ if lang != "" {
+ cfg.TraditionalLang = lang
+ }
+
if err := web.Run(cfg); err != nil {
- fmt.Fprintln(os.Stderr, err)
- os.Exit(1)
+ fmt.Fprintln(stderr, err)
+ return 1
+ }
+ return 0
+}
+
+// wantsHelp reports whether -h/--help appears anywhere in args.
+func wantsHelp(args []string) bool {
+ for _, a := range args {
+ if a == "-h" || a == "--help" {
+ return true
+ }
+ }
+ return false
+}
+
+// wantsVersion reports whether -v/--version appears anywhere in args.
+func wantsVersion(args []string) bool {
+ for _, a := range args {
+ if a == "-v" || a == "--version" {
+ return true
+ }
+ }
+ return false
+}
+
+// normalizeLectionary maps -l/--lectionary's accepted spellings via
+// config.NormalizeLectionary; "" (flag not given) passes through unchanged.
+func normalizeLectionary(lectionary string) (string, error) {
+ if lectionary == "" {
+ return "", nil
+ }
+ v, ok := config.NormalizeLectionary(lectionary)
+ if !ok {
+ return "", fmt.Errorf("invalid --lectionary %q (want new|trad)", lectionary)
}
+ return v, nil
}
diff --git a/cmd/lectio-web/main_test.go b/cmd/lectio-web/main_test.go
new file mode 100644
index 0000000..766e0d9
--- /dev/null
+++ b/cmd/lectio-web/main_test.go
@@ -0,0 +1,87 @@
+package main
+
+import (
+ "bytes"
+ "strings"
+ "testing"
+)
+
+func TestHelpFlag(t *testing.T) {
+ var out, errb bytes.Buffer
+ if code := run([]string{"-h"}, &out, &errb); code != 0 {
+ t.Errorf("-h code=%d (stderr=%q)", code, errb.String())
+ }
+ if !strings.Contains(out.String(), "lectio-web") {
+ t.Errorf("-h output missing lectio-web: %q", out.String())
+ }
+}
+
+func TestHelpLongFlag(t *testing.T) {
+ var out, errb bytes.Buffer
+ if code := run([]string{"--help"}, &out, &errb); code != 0 {
+ t.Errorf("--help code=%d (stderr=%q)", code, errb.String())
+ }
+ if !strings.Contains(out.String(), "lectio-web") {
+ t.Errorf("--help output missing lectio-web: %q", out.String())
+ }
+}
+
+func TestVersionFlag(t *testing.T) {
+ var out, errb bytes.Buffer
+ if code := run([]string{"-v"}, &out, &errb); code != 0 {
+ t.Errorf("-v code=%d (stderr=%q)", code, errb.String())
+ }
+ if !strings.Contains(out.String(), "lectio-web") {
+ t.Errorf("-v output missing lectio-web: %q", out.String())
+ }
+}
+
+func TestVersionLongFlag(t *testing.T) {
+ var out, errb bytes.Buffer
+ if code := run([]string{"--version"}, &out, &errb); code != 0 {
+ t.Errorf("--version code=%d (stderr=%q)", code, errb.String())
+ }
+ if !strings.Contains(out.String(), "lectio-web") {
+ t.Errorf("--version output missing lectio-web: %q", out.String())
+ }
+}
+
+func TestUnknownFlag(t *testing.T) {
+ t.Setenv("XDG_CONFIG_HOME", t.TempDir())
+ var out, errb bytes.Buffer
+ if code := run([]string{"-x"}, &out, &errb); code != 2 {
+ t.Errorf("-x code=%d want 2 (stderr=%q)", code, errb.String())
+ }
+}
+
+func TestUnknownLongFlag(t *testing.T) {
+ t.Setenv("XDG_CONFIG_HOME", t.TempDir())
+ var out, errb bytes.Buffer
+ if code := run([]string{"--bogus"}, &out, &errb); code != 2 {
+ t.Errorf("--bogus code=%d want 2 (stderr=%q)", code, errb.String())
+ }
+}
+
+func TestUnexpectedPositional(t *testing.T) {
+ t.Setenv("XDG_CONFIG_HOME", t.TempDir())
+ var out, errb bytes.Buffer
+ if code := run([]string{"bogus"}, &out, &errb); code != 2 {
+ t.Errorf("unexpected positional code=%d want 2 (stderr=%q)", code, errb.String())
+ }
+}
+
+func TestLectionaryBogus(t *testing.T) {
+ t.Setenv("XDG_CONFIG_HOME", t.TempDir())
+ var out, errb bytes.Buffer
+ if code := run([]string{"-l", "bogus"}, &out, &errb); code != 2 {
+ t.Errorf("bogus lectionary code=%d want 2 (stderr=%q)", code, errb.String())
+ }
+}
+
+func TestLangBogus(t *testing.T) {
+ t.Setenv("XDG_CONFIG_HOME", t.TempDir())
+ var out, errb bytes.Buffer
+ if code := run([]string{"-g", "xx"}, &out, &errb); code != 2 {
+ t.Errorf("bogus lang code=%d want 2 (stderr=%q)", code, errb.String())
+ }
+}
diff --git a/internal/cli/cli.go b/internal/cli/cli.go
index 720c165..c514607 100644
--- a/internal/cli/cli.go
+++ b/internal/cli/cli.go
@@ -20,9 +20,6 @@ import (
"github.com/lukaszkasprzak/lectio/internal/render"
)
-// versionString is printed by --version/-v.
-const versionString = "0.1.0"
-
const helpText = `lectio — daily Catholic liturgy readings (Polish + 4 versions)
Usage:
@@ -65,14 +62,6 @@ const (
var dateRe = regexp.MustCompile(`^\d{4}-\d{2}-\d{2}$`)
-var validVersions = map[string]bool{
- "pl": true,
- "wuj": true,
- "vul": true,
- "grb": true,
- "drb": true,
-}
-
func today() string {
return time.Now().Format("2006-01-02")
}
@@ -84,7 +73,7 @@ func Run(args []string, stdin io.Reader, stdout, stderr io.Writer) int {
return 0
}
if wantsVersion(args) {
- fmt.Fprintln(stdout, "lectio "+versionString)
+ fmt.Fprintln(stdout, "lectio "+config.Version)
return 0
}
if len(args) > 0 && args[0] == "help" {
@@ -179,7 +168,7 @@ func Run(args []string, stdin io.Reader, stdout, stderr io.Writer) int {
return renderCompare(cfg, compareList, date, effAll, raw, effWidth, refresh, stdout, stderr)
}
if bibleVer != "" {
- if !validVersions[bibleVer] {
+ if !config.ValidVersion(bibleVer) {
fmt.Fprintf(stderr, "lectio: unknown version %q (want one of pl, wuj, vul, grb, drb)\n", bibleVer)
return 2
}
@@ -237,19 +226,18 @@ func extractDate(args []string) (date string, rest []string, err error) {
// normalizeLectionary maps -l/--lectionary's accepted spellings ("new",
// "trad", "traditional") onto the canonical config.Config.Lectionary values
-// ("new", "traditional"); "" (flag not given) passes through unchanged so
-// the caller knows to leave config's own setting alone.
+// ("new", "traditional") via config.NormalizeLectionary; "" (flag not given)
+// passes through unchanged so the caller knows to leave config's own
+// setting alone.
func normalizeLectionary(lectionary string) (string, error) {
- switch lectionary {
- case "":
+ if lectionary == "" {
return "", nil
- case "trad":
- return "traditional", nil
- case "new", "traditional":
- return lectionary, nil
- default:
+ }
+ v, ok := config.NormalizeLectionary(lectionary)
+ if !ok {
return "", fmt.Errorf("invalid --lectionary %q (want new|trad)", lectionary)
}
+ return v, nil
}
// runHarvest handles -u/--update: harvest sigla maximally (to the
@@ -397,7 +385,7 @@ func renderCompare(cfg config.Config, list, date string, all, raw bool, width in
}
}
for _, v := range versions {
- if !validVersions[v] {
+ if !config.ValidVersion(v) {
fmt.Fprintf(stderr, "lectio: unknown version %q (want one of pl, wuj, vul, grb, drb)\n", v)
return 2
}
diff --git a/internal/config/config.go b/internal/config/config.go
index dd81544..7cef184 100644
--- a/internal/config/config.go
+++ b/internal/config/config.go
@@ -22,6 +22,10 @@ import (
//go:embed config.toml
var seedTOML []byte
+// Version is lectio's release version, shared by every binary's
+// -v/--version output (lectio, lectio-ui, lectio-web).
+const Version = "0.1.0"
+
// validVersions are the five scripture versions lectio understands.
var validVersions = map[string]bool{
"pl": true,
@@ -31,6 +35,26 @@ var validVersions = map[string]bool{
"drb": true,
}
+// ValidVersion reports whether v is one of the five scripture versions
+// lectio understands (pl, wuj, vul, grb, drb).
+func ValidVersion(v string) bool {
+ return validVersions[v]
+}
+
+// NormalizeLectionary maps -l/--lectionary's accepted spellings ("new",
+// "trad", "traditional") onto the canonical Config.Lectionary values ("new",
+// "traditional"); anything else reports ok=false.
+func NormalizeLectionary(s string) (string, bool) {
+ switch strings.ToLower(s) {
+ case "new":
+ return "new", true
+ case "trad", "traditional":
+ return "traditional", true
+ default:
+ return "", false
+ }
+}
+
// validDisplays are the lectio-web reading-pane layouts.
var validDisplays = map[string]bool{
"horizontal": true,
diff --git a/internal/tui/tui.go b/internal/tui/tui.go
index 47314b6..16cb304 100644
--- a/internal/tui/tui.go
+++ b/internal/tui/tui.go
@@ -44,24 +44,33 @@ type errMsg struct {
}
// New builds the initial model: cfg.Offline drops "pl" from the version
-// list (render.OfflineVersions), the active version starts at
-// cfg.DefaultVersion (falling back to the first version if not found, or
-// "" if there are none), and the date starts at today. The first fetch is
-// issued by Init, not here.
-func New(cfg config.Config) Model {
+// list (render.OfflineVersions). startVersion selects the active version
+// (falling back to cfg.DefaultVersion when ""), still resolved through
+// EffectiveVersions/indexOf so an unavailable version falls back to index 0.
+// startDate selects the starting date (falling back to today when ""). The
+// first fetch is issued by Init, not here.
+func New(cfg config.Config, startDate, startVersion string) Model {
versions := render.EffectiveVersions(append([]string(nil), cfg.Versions...), cfg.Lectionary, cfg.Offline)
- idx := indexOf(versions, cfg.DefaultVersion)
+ if startVersion == "" {
+ startVersion = cfg.DefaultVersion
+ }
+ idx := indexOf(versions, startVersion)
if idx < 0 {
idx = 0
}
idx = clampIndex(idx, len(versions))
+ date := startDate
+ if date == "" {
+ date = time.Now().Format("2006-01-02")
+ }
+
return Model{
cfg: cfg,
versions: versions,
verIdx: idx,
- date: time.Now().Format("2006-01-02"),
+ date: date,
loading: true,
}
}
diff --git a/internal/tui/tui_test.go b/internal/tui/tui_test.go
index 60b473b..2b966ee 100644
--- a/internal/tui/tui_test.go
+++ b/internal/tui/tui_test.go
@@ -10,7 +10,7 @@ import (
)
func TestVersionCycle(t *testing.T) {
- m := New(config.Config{Versions: []string{"pl", "wuj", "vul"}, DefaultVersion: "pl"})
+ m := New(config.Config{Versions: []string{"pl", "wuj", "vul"}, DefaultVersion: "pl"}, "", "")
if m.version() != "pl" {
t.Fatalf("start = %q", m.version())
}
@@ -25,7 +25,7 @@ func TestVersionCycle(t *testing.T) {
}
func TestOfflineDropsPL(t *testing.T) {
- m := New(config.Config{Versions: []string{"pl", "wuj", "vul"}, DefaultVersion: "pl", Offline: true})
+ m := New(config.Config{Versions: []string{"pl", "wuj", "vul"}, DefaultVersion: "pl", Offline: true}, "", "")
for _, v := range m.versions {
if v == "pl" {
t.Error("offline model kept pl")