110 lines
3.5 KiB
Nim
110 lines
3.5 KiB
Nim
import std/[strutils, tables]
|
|
|
|
import ./offline_data
|
|
import ./reference_parser
|
|
|
|
const kjvRows = embeddedTranslationData("kjv")
|
|
|
|
type BibleIndex = object
|
|
verses: Table[string, string]
|
|
lastVerseByChapter: Table[string, int]
|
|
lastChapterByBook: Table[string, int]
|
|
|
|
proc verseKey(code: string, chapter, verse: int): string =
|
|
code & "\t" & $chapter & "\t" & $verse
|
|
|
|
proc chapterKey(code: string, chapter: int): string =
|
|
code & "\t" & $chapter
|
|
|
|
proc loadBibleIndex(): BibleIndex =
|
|
for line in kjvRows.splitLines:
|
|
if line.strip.len == 0:
|
|
continue
|
|
|
|
let parts = line.split('\t', maxsplit = 3)
|
|
if parts.len != 4:
|
|
raise newException(ValueError, "invalid embedded KJV row: " & line)
|
|
|
|
let code = parts[0]
|
|
let chapter = parseInt(parts[1])
|
|
let verse = parseInt(parts[2])
|
|
let text = parts[3]
|
|
|
|
result.verses[verseKey(code, chapter, verse)] = text
|
|
|
|
let cKey = chapterKey(code, chapter)
|
|
if not result.lastVerseByChapter.hasKey(cKey) or
|
|
verse > result.lastVerseByChapter[cKey]:
|
|
result.lastVerseByChapter[cKey] = verse
|
|
|
|
if not result.lastChapterByBook.hasKey(code) or
|
|
chapter > result.lastChapterByBook[code]:
|
|
result.lastChapterByBook[code] = chapter
|
|
|
|
proc requireLastChapter(index: BibleIndex, code: string): int =
|
|
if not index.lastChapterByBook.hasKey(code):
|
|
raise newException(ValueError, "no embedded KJV data for " & code)
|
|
index.lastChapterByBook[code]
|
|
|
|
proc requireLastVerse(index: BibleIndex, code: string, chapter: int): int =
|
|
let cKey = chapterKey(code, chapter)
|
|
if not index.lastVerseByChapter.hasKey(cKey):
|
|
raise newException(ValueError,
|
|
"no embedded KJV data for " & bookInfo(code).name & " " & $chapter)
|
|
index.lastVerseByChapter[cKey]
|
|
|
|
proc requireVerse(index: BibleIndex, code: string, chapter, verse: int): string =
|
|
let vKey = verseKey(code, chapter, verse)
|
|
if not index.verses.hasKey(vKey):
|
|
raise newException(ValueError,
|
|
"no embedded KJV data for " & bookInfo(code).name & " " &
|
|
$chapter & ":" & $verse)
|
|
index.verses[vKey]
|
|
|
|
proc addVerseLines(
|
|
lines: var seq[string],
|
|
index: BibleIndex,
|
|
reference: PassageReference,
|
|
range: RefRange) =
|
|
|
|
let code = reference.book.code
|
|
discard index.requireLastChapter(code)
|
|
|
|
for chapter in range.start.chapter .. range.finish.chapter:
|
|
let startVerse =
|
|
if chapter == range.start.chapter and range.start.verse > 0:
|
|
range.start.verse
|
|
else:
|
|
1
|
|
|
|
let endVerse =
|
|
if chapter == range.finish.chapter and range.finish.verse > 0:
|
|
range.finish.verse
|
|
else:
|
|
index.requireLastVerse(code, chapter)
|
|
|
|
if startVerse > endVerse:
|
|
raise newException(ValueError, "reference range starts after it ends")
|
|
|
|
for verse in startVerse .. endVerse:
|
|
lines.add(" [" & $verse & "] " & index.requireVerse(code, chapter, verse))
|
|
|
|
proc fetchReference(index: BibleIndex, reference: PassageReference): string =
|
|
var lines = @[$reference]
|
|
let code = reference.book.code
|
|
|
|
if reference.ranges.len == 0:
|
|
for chapter in 1 .. index.requireLastChapter(code):
|
|
for verse in 1 .. index.requireLastVerse(code, chapter):
|
|
lines.add(" [" & $verse & "] " & index.requireVerse(code, chapter, verse))
|
|
else:
|
|
for range in reference.ranges:
|
|
lines.addVerseLines(index, reference, range)
|
|
|
|
lines.join("\n")
|
|
|
|
proc fetchPassages*(reference: string): seq[string] =
|
|
let index = loadBibleIndex()
|
|
for parsedReference in parseReferences(reference):
|
|
result.add(fetchReference(index, parsedReference))
|