summaryrefslogtreecommitdiff
path: root/internal
diff options
context:
space:
mode:
authorLukasz Kasprzak <lukas@labunix.xyz>2026-07-23 23:28:15 +0200
committerLukasz Kasprzak <lukas@labunix.xyz>2026-07-23 23:28:15 +0200
commit9ec2c438a39542ec485e221d485c43b04d692aca (patch)
tree88e881306215de030ef70279be4de9c6d533e112 /internal
parentf73decedab916d336247d4ea43ead2b7f7da1e83 (diff)
downloadlectio-9ec2c438a39542ec485e221d485c43b04d692aca.tar.gz
lectio-9ec2c438a39542ec485e221d485c43b04d692aca.zip
tui: fix width-wrap garbling + straight-aligned verse column (export render.Wrap, hanging indent); strip niedziela summary subtitle (tui/cli/web); web verse grid alignment; refrain-italic pl-only
Diffstat (limited to 'internal')
-rw-r--r--internal/cli/cli.go3
-rw-r--r--internal/render/render.go7
-rw-r--r--internal/tui/tui.go57
-rw-r--r--internal/web/static/base.css20
-rw-r--r--internal/web/templates/readings-interlinear.html1
-rw-r--r--internal/web/templates/readings-vertical.html3
-rw-r--r--internal/web/templates/readings.html3
7 files changed, 73 insertions, 21 deletions
diff --git a/internal/cli/cli.go b/internal/cli/cli.go
index 38de4c1..720c165 100644
--- a/internal/cli/cli.go
+++ b/internal/cli/cli.go
@@ -371,9 +371,6 @@ func renderSection(sec liturgy.Section, version, lectionary, lang string, width
var lines []string
if !raw {
lines = append(lines, render.LocalizeHeading(sec.Heading, sec.PartID, lang))
- if sec.Subtitle != "" {
- lines = append(lines, sec.Subtitle)
- }
lines = append(lines, "")
}
_, blocks := render.GatherVersion(version, sec, lectionary, lang)
diff --git a/internal/render/render.go b/internal/render/render.go
index 265ed18..8a36f12 100644
--- a/internal/render/render.go
+++ b/internal/render/render.go
@@ -271,7 +271,7 @@ func compareSection(sec liturgy.Section, versions []string, width int, lectionar
label, blocks := GatherVersion(v, sec, lectionary, lang)
var lines []string
for _, b := range blocks {
- lines = append(lines, strings.Split(wrap(b, w), "\n")...)
+ lines = append(lines, strings.Split(Wrap(b, w), "\n")...)
lines = append(lines, "")
}
if len(lines) > 0 {
@@ -313,7 +313,10 @@ func compareSection(sec liturgy.Section, versions []string, width int, lectionar
// line and never splitting a word (even one longer than width), matching
// ewangelia.py's textwrap.fill(..., break_long_words=False,
// break_on_hyphens=False).
-func wrap(line string, width int) string {
+// Wrap greedily word-wraps line to width without padding (each output line is
+// at most width runes, no trailing spaces), never splitting a word. Shared by
+// the CLI, the TUI reader and Compare so all three wrap identically.
+func Wrap(line string, width int) string {
words := strings.Fields(line)
if len(words) == 0 {
return ""
diff --git a/internal/tui/tui.go b/internal/tui/tui.go
index 06ad19f..a4c14b9 100644
--- a/internal/tui/tui.go
+++ b/internal/tui/tui.go
@@ -306,16 +306,16 @@ func (m Model) bodyLines(w int) []string {
}
heading := render.LocalizeHeading(sec.Heading, sec.PartID, m.cfg.UILanguage)
lines = append(lines, headingStyle.Render(heading))
- if sec.Subtitle != "" {
- lines = append(lines, citationStyle.Render(sec.Subtitle))
- }
lines = append(lines, "")
_, blocks := render.GatherVersion(ver, sec, m.cfg.Lectionary, m.cfg.UILanguage)
- isPsalm := sec.PartID == "psalm"
+ numW := maxNumWidth(blocks)
+ // The refrain-italic only applies to the pl responsorial-psalm block
+ // (its first, deduped paragraph); bible versions have no refrain block.
+ isPsalm := sec.PartID == "psalm" && ver == "pl"
for bi, b := range blocks {
refrain := isPsalm && bi == 0
- lines = append(lines, styleBlock(b, refrain, w)...)
+ lines = append(lines, styleBlock(b, refrain, w, numW)...)
lines = append(lines, "")
}
}
@@ -330,18 +330,53 @@ var verseNumRe = regexp.MustCompile(`^(\d+:\d+) (.*)$`)
// block gets its "chapter:verse" prefix in the muted verse-number style and
// its text in the default verse style; a psalm's first (refrain) block
// renders italic; everything else renders in the default verse style.
-func styleBlock(b string, refrain bool, w int) []string {
+func styleBlock(b string, refrain bool, w, numW int) []string {
+ if w < 1 {
+ w = 1
+ }
if g := verseNumRe.FindStringSubmatch(b); g != nil {
num, text := g[1], g[2]
- wrapped := verseTextStyle.Width(w).Render(text)
- wlines := strings.Split(wrapped, "\n")
- wlines[0] = verseNumStyle.Render(num+" ") + wlines[0]
- return wlines
+ col := numW + 2 // verse-number column: widest "chapter:verse" + 2 spaces
+ indent := strings.Repeat(" ", col)
+ tw := w - col
+ if tw < 1 {
+ tw = 1
+ }
+ lines := strings.Split(render.Wrap(text, tw), "\n")
+ out := make([]string, 0, len(lines))
+ for i, ln := range lines {
+ if i == 0 {
+ pad := strings.Repeat(" ", col-len([]rune(num)))
+ out = append(out, verseNumStyle.Render(num)+pad+verseTextStyle.Render(ln))
+ } else {
+ out = append(out, indent+verseTextStyle.Render(ln))
+ }
+ }
+ return out
}
style := verseTextStyle
if refrain {
style = refrainStyle
}
- return strings.Split(style.Width(w).Render(b), "\n")
+ lines := strings.Split(render.Wrap(b, w), "\n")
+ out := make([]string, 0, len(lines))
+ for _, ln := range lines {
+ out = append(out, style.Render(ln))
+ }
+ return out
+}
+
+// maxNumWidth returns the widest "chapter:verse" prefix rune-width among the
+// verse blocks, so styleBlock can align every verse's text to one column.
+func maxNumWidth(blocks []string) int {
+ m := 0
+ for _, b := range blocks {
+ if g := verseNumRe.FindStringSubmatch(b); g != nil {
+ if n := len([]rune(g[1])); n > m {
+ m = n
+ }
+ }
+ }
+ return m
}
diff --git a/internal/web/static/base.css b/internal/web/static/base.css
index 4e942d5..b5ce9a5 100644
--- a/internal/web/static/base.css
+++ b/internal/web/static/base.css
@@ -154,6 +154,26 @@ body.mono {
font-style: italic;
}
+/* Verse block: a fixed number column + a text column, so every verse's text
+ starts at the same left edge (a straight margin) and continuation lines
+ hang-indent under it -- matching the CLI/TUI reader. */
+.block.verse {
+ display: grid;
+ grid-template-columns: 3rem 1fr;
+ column-gap: 0.4rem;
+ align-items: baseline;
+}
+
+.block.verse .vnum {
+ min-width: 0;
+ margin-right: 0;
+ text-align: right;
+}
+
+.block.verse .vtext {
+ min-width: 0;
+}
+
.vnum {
display: inline-block;
min-width: 2.5em;
diff --git a/internal/web/templates/readings-interlinear.html b/internal/web/templates/readings-interlinear.html
index 0ba7c02..5b71318 100644
--- a/internal/web/templates/readings-interlinear.html
+++ b/internal/web/templates/readings-interlinear.html
@@ -10,7 +10,6 @@
{{range .}}
<section class="reading-section" data-part="{{.PartID}}">
<h2 class="heading">{{.Heading}}</h2>
- {{if .Subtitle}}<p class="citation">{{.Subtitle}}</p>{{end}}
{{if .Note}}
<p class="error">{{.Note}}</p>
{{else}}
diff --git a/internal/web/templates/readings-vertical.html b/internal/web/templates/readings-vertical.html
index 08f526d..d9896c1 100644
--- a/internal/web/templates/readings-vertical.html
+++ b/internal/web/templates/readings-vertical.html
@@ -8,7 +8,6 @@
{{range .}}
<section class="reading-section" data-part="{{.PartID}}">
<h2 class="heading">{{.Heading}}</h2>
- {{if .Subtitle}}<p class="citation">{{.Subtitle}}</p>{{end}}
<div class="display-vertical">
{{range .Columns}}
<div class="vcol">
@@ -17,7 +16,7 @@
{{if .Refrain}}
<p class="block refrain">{{.Text}}</p>
{{else if .VNum}}
- <p class="block verse"><span class="vnum">{{.VNum}}</span> {{.Text}}</p>
+ <p class="block verse"><span class="vnum">{{.VNum}}</span><span class="vtext">{{.Text}}</span></p>
{{else}}
<p class="block">{{.Text}}</p>
{{end}}
diff --git a/internal/web/templates/readings.html b/internal/web/templates/readings.html
index 0c57ddd..a1cbcdb 100644
--- a/internal/web/templates/readings.html
+++ b/internal/web/templates/readings.html
@@ -5,7 +5,6 @@
{{range .}}
<section class="reading-section" data-part="{{.PartID}}">
<h2 class="heading">{{.Heading}}</h2>
- {{if .Subtitle}}<p class="citation">{{.Subtitle}}</p>{{end}}
<div class="columns">
{{range .Columns}}
<div class="column">
@@ -14,7 +13,7 @@
{{if .Refrain}}
<p class="block refrain">{{.Text}}</p>
{{else if .VNum}}
- <p class="block verse"><span class="vnum">{{.VNum}}</span> {{.Text}}</p>
+ <p class="block verse"><span class="vnum">{{.VNum}}</span><span class="vtext">{{.Text}}</span></p>
{{else}}
<p class="block">{{.Text}}</p>
{{end}}