Render embedded Bible paragraphs inline

This commit is contained in:
2026-07-05 20:55:43 -05:00
parent 98253920ca
commit 6972a4e531
2 changed files with 78 additions and 13 deletions
+55 -13
View File
@@ -30,6 +30,17 @@ proc verseKey(code: string, chapter, verse: int): string =
proc chapterKey(code: string, chapter: int): string = proc chapterKey(code: string, chapter: int): string =
code & "\t" & $chapter code & "\t" & $chapter
proc legacySegment(text: string): tuple[breakKind: SegmentBreak, text: string] =
const pilcrow = "\xC2\xB6"
let stripped = text.strip(leading = true, trailing = false)
if stripped.startsWith(pilcrow):
result.breakKind = sbParagraph
result.text = stripped[pilcrow.len .. ^1].strip(leading = true, trailing = false)
else:
result.breakKind = sbSame
result.text = text
proc parseSegmentBreak(s: string): SegmentBreak = proc parseSegmentBreak(s: string): SegmentBreak =
case s case s
of "same": sbSame of "same": sbSame
@@ -64,14 +75,15 @@ proc loadBibleIndex(rows, translationName: string): BibleIndex =
"invalid embedded " & translationName & " row: " & line) "invalid embedded " & translationName & " row: " & line)
if parts.len == 4: if parts.len == 4:
let legacy = legacySegment(parts[3])
result.addSegment(BibleSegment( result.addSegment(BibleSegment(
code: parts[0], code: parts[0],
chapter: parseInt(parts[1]), chapter: parseInt(parts[1]),
verse: parseInt(parts[2]), verse: parseInt(parts[2]),
segment: 0, segment: 0,
breakKind: sbLine, breakKind: legacy.breakKind,
indent: 0, indent: 0,
text: parts[3])) text: legacy.text))
else: else:
result.addSegment(BibleSegment( result.addSegment(BibleSegment(
code: parts[0], code: parts[0],
@@ -151,9 +163,41 @@ proc addFormattedSegment(
lines[^1].add(" ") lines[^1].add(" ")
lines[^1].add(content) lines[^1].add(content)
else: else:
if segment.breakKind == sbParagraph and hasPassageLine: let isMarkerlessParagraphContinuation =
lines.add("") segment.breakKind == sbParagraph and marker.len == 0 and hasPassageLine
lines.add(prefix & content)
if isMarkerlessParagraphContinuation:
if lines[^1].len > 0 and not lines[^1][^1].isSpaceAscii:
lines[^1].add(" ")
lines[^1].add(content)
else:
if segment.breakKind == sbParagraph and hasPassageLine:
lines.add("")
lines.add(prefix & content)
proc normalizeFirstSelectedSegment(segment: BibleSegment): BibleSegment =
result = segment
if result.breakKind == sbSame:
result.breakKind = sbLine
elif result.breakKind == sbParagraph and result.segment == 0:
result.breakKind = sbLine
proc addAllSegments(lines: var seq[string], index: BibleIndex, code: string) =
var emittedVerses: Table[string, bool]
var firstSelected = true
discard index.requireLastChapter(code)
for segment in index.segments:
if segment.code == code:
var adjusted = segment
if firstSelected:
adjusted = normalizeFirstSelectedSegment(adjusted)
lines.addFormattedSegment(adjusted, emittedVerses)
firstSelected = false
proc addRangeSeparator(lines: var seq[string]) =
if lines.len > 1 and lines[^1].len > 0:
lines.add("")
proc addVerseLines( proc addVerseLines(
lines: var seq[string], lines: var seq[string],
@@ -170,8 +214,8 @@ proc addVerseLines(
if segment.code == code and if segment.code == code and
selected.hasKey(verseKey(segment.code, segment.chapter, segment.verse)): selected.hasKey(verseKey(segment.code, segment.chapter, segment.verse)):
var adjusted = segment var adjusted = segment
if firstSelected and adjusted.breakKind == sbSame: if firstSelected:
adjusted.breakKind = sbLine adjusted = normalizeFirstSelectedSegment(adjusted)
lines.addFormattedSegment(adjusted, emittedVerses) lines.addFormattedSegment(adjusted, emittedVerses)
firstSelected = false firstSelected = false
@@ -180,13 +224,11 @@ proc fetchReference(index: BibleIndex, reference: PassageReference): string =
let code = reference.book.code let code = reference.book.code
if reference.ranges.len == 0: if reference.ranges.len == 0:
var emittedVerses: Table[string, bool] lines.addAllSegments(index, code)
discard index.requireLastChapter(code)
for segment in index.segments:
if segment.code == code:
lines.addFormattedSegment(segment, emittedVerses)
else: else:
for range in reference.ranges: for idx, range in reference.ranges:
if idx > 0:
lines.addRangeSeparator()
lines.addVerseLines(index, reference, range) lines.addVerseLines(index, reference, range)
lines.join("\n") lines.join("\n")
+23
View File
@@ -90,6 +90,9 @@ JHN 8 31 0 paragraph 0 Then Jesus said,
JHN 8 31 1 same 0 "If you remain in My word, JHN 8 31 1 same 0 "If you remain in My word,
JHN 8 32 0 same 0 you shall know the truth." JHN 8 32 0 same 0 you shall know the truth."
JHN 8 33 0 paragraph 0 They answered Him. JHN 8 33 0 paragraph 0 They answered Him.
JHN 8 39 0 paragraph 0 They answered Him, "Abraham is our father."
JHN 8 39 1 paragraph 0 Jesus said to them, "If you were Abraham's children,
JHN 8 40 0 same 0 you would do the works of Abraham."
HEB 4 7 0 paragraph 0 again He establishes a certain day: HEB 4 7 0 paragraph 0 again He establishes a certain day:
HEB 4 7 1 line 0 "Today, if you will hear His voice, HEB 4 7 1 line 0 "Today, if you will hear His voice,
HEB 4 7 2 line 1 do not harden your hearts." HEB 4 7 2 line 1 do not harden your hearts."
@@ -126,8 +129,28 @@ HEB 4 7 2 line 1 do not harden your hearts."
"\n" & "\n" &
" [33] They answered Him." " [33] They answered Him."
test "joins markerless paragraph continuations":
let passages = embedded_bible.fetchPassages(layoutRows, "John 8:39-40", "TEST")
check passages[0] == "John 8:39-40\n" &
" [39] They answered Him, \"Abraham is our father.\" " &
"Jesus said to them, \"If you were Abraham's children, " &
"[40] you would do the works of Abraham.\""
test "supports legacy verse rows": test "supports legacy verse rows":
const legacyRows = "JHN\t3\t16\tFor God so loved the world.\n" const legacyRows = "JHN\t3\t16\tFor God so loved the world.\n"
let passages = embedded_bible.fetchPassages(legacyRows, "John 3:16", "TEST") let passages = embedded_bible.fetchPassages(legacyRows, "John 3:16", "TEST")
check passages[0] == "John 3:16\n [16] For God so loved the world." check passages[0] == "John 3:16\n [16] For God so loved the world."
test "groups legacy rows into paragraphs using pilcrows":
const legacyRows =
"JHN\t8\t31\tThen Jesus said.\n" &
"JHN\t8\t32\tYou shall know the truth.\n" &
"JHN\t8\t33\t\xC2\xB6 They answered Him.\n"
let passages = embedded_bible.fetchPassages(legacyRows, "John 8:31-33", "TEST")
check passages[0] == "John 8:31-33\n" &
" [31] Then Jesus said. [32] You shall know the truth.\n" &
"\n" &
" [33] They answered Him."