Add ANSI output format
This commit is contained in:
+1
-1
@@ -1,6 +1,6 @@
|
||||
# Package
|
||||
|
||||
version = "1.1.1"
|
||||
version = "1.2.0"
|
||||
author = "Jonathan Bernard"
|
||||
description = "Simple Nim CLI for retrieving Biblical passages"
|
||||
license = "MIT"
|
||||
|
||||
+49
-6
@@ -106,9 +106,15 @@ proc fetchPlainPassages(
|
||||
|
||||
case translation
|
||||
of "akjv", "kjv":
|
||||
result = kjv.fetchPlainPassages(reference, keepVerseNumbers)
|
||||
result = kjv.fetchPlainPassages(
|
||||
reference,
|
||||
keepVerseNumbers,
|
||||
cfg.getVal("annotations", "all"))
|
||||
of "mev":
|
||||
result = mev.fetchPlainPassages(reference, keepVerseNumbers)
|
||||
result = mev.fetchPlainPassages(
|
||||
reference,
|
||||
keepVerseNumbers,
|
||||
cfg.getVal("annotations", "all"))
|
||||
else:
|
||||
for passage in fetchPassages(reference, translation, cfg):
|
||||
result.add(formatPlain(passage, translation, keepVerseNumbers))
|
||||
@@ -120,13 +126,38 @@ proc fetchMarkdownPassages(
|
||||
|
||||
case translation
|
||||
of "akjv", "kjv":
|
||||
result = kjv.fetchMarkdownPassages(reference)
|
||||
result = kjv.fetchMarkdownPassages(
|
||||
reference,
|
||||
cfg.getVal("annotations", "all"))
|
||||
of "mev":
|
||||
result = mev.fetchMarkdownPassages(reference)
|
||||
result = mev.fetchMarkdownPassages(
|
||||
reference,
|
||||
cfg.getVal("annotations", "all"))
|
||||
else:
|
||||
for passage in fetchPassages(reference, translation, cfg):
|
||||
result.add(formatMarkdown(passage, translation))
|
||||
|
||||
proc fetchAnsiPassages(
|
||||
reference,
|
||||
translation: string,
|
||||
keepVerseNumbers: bool,
|
||||
cfg: CombinedConfig): seq[string] =
|
||||
|
||||
case translation
|
||||
of "akjv", "kjv":
|
||||
result = kjv.fetchAnsiPassages(
|
||||
reference,
|
||||
keepVerseNumbers,
|
||||
cfg.getVal("annotations", "all"))
|
||||
of "mev":
|
||||
result = mev.fetchAnsiPassages(
|
||||
reference,
|
||||
keepVerseNumbers,
|
||||
cfg.getVal("annotations", "all"))
|
||||
else:
|
||||
for passage in fetchPassages(reference, translation, cfg):
|
||||
result.add(formatPlain(passage, translation, keepVerseNumbers))
|
||||
|
||||
when isMainModule:
|
||||
const USAGE = """Usage:
|
||||
bibleref <reference> [options]
|
||||
@@ -139,7 +170,13 @@ Options:
|
||||
command line for debugging purposes.
|
||||
|
||||
-f, --output-format <format> Select a specific output format. Valid values
|
||||
are 'raw', 'markdown', 'plain', 'reading'.
|
||||
are 'ansi', 'raw', 'markdown', 'plain',
|
||||
'reading'.
|
||||
|
||||
--annotations <annotations> Select embedded Bible annotations to render.
|
||||
Valid values are 'none', 'all', or a
|
||||
comma-separated list of annotation kinds such
|
||||
as 'note,crossReference'. Defaults to 'all'.
|
||||
|
||||
-t, --translation <translation>
|
||||
Select a specific translation. Supported values
|
||||
@@ -167,7 +204,7 @@ Options:
|
||||
--api-bible-nkjv-bible-id <id>
|
||||
Override the API.Bible Bible ID for NKJV.
|
||||
"""
|
||||
const VERSION = "1.1.1"
|
||||
const VERSION = "1.2.0"
|
||||
|
||||
let consoleLogger = newConsoleLogger(
|
||||
levelThreshold=lvlInfo,
|
||||
@@ -197,6 +234,12 @@ Options:
|
||||
var formattedPassages: seq[string] = @[]
|
||||
for query in queries:
|
||||
case $args["--output-format"]
|
||||
of "ansi":
|
||||
formattedPassages.add(fetchAnsiPassages(
|
||||
query.referenceText,
|
||||
query.translation,
|
||||
keepVerseNumbers = true,
|
||||
cfg))
|
||||
of "plain":
|
||||
formattedPassages.add(fetchPlainPassages(
|
||||
query.referenceText,
|
||||
|
||||
+187
-24
@@ -17,6 +17,7 @@ type
|
||||
indent: int
|
||||
text: string
|
||||
annotations: seq[BibleAnnotation]
|
||||
wordsOfChrist: bool
|
||||
|
||||
BibleAnnotation = object
|
||||
kind: string
|
||||
@@ -25,8 +26,18 @@ type
|
||||
|
||||
EmbeddedOutputFormat = enum
|
||||
eofPlain
|
||||
eofAnsi
|
||||
eofMarkdown
|
||||
|
||||
AnnotationFilterKind = enum
|
||||
afNone
|
||||
afAll
|
||||
afKinds
|
||||
|
||||
AnnotationFilter = object
|
||||
kind: AnnotationFilterKind
|
||||
kinds: seq[string]
|
||||
|
||||
BibleIndex = object
|
||||
segments: seq[BibleSegment]
|
||||
verses: Table[string, bool]
|
||||
@@ -34,6 +45,12 @@ type
|
||||
lastChapterByBook: Table[string, int]
|
||||
translationName: string
|
||||
|
||||
const
|
||||
ansiReset = "\x1b[0m"
|
||||
ansiDarkRed = "\x1b[31m"
|
||||
ansiGray = "\x1b[90m"
|
||||
ansiCyan = "\x1b[36m"
|
||||
|
||||
proc verseKey(code: string, chapter, verse: int): string =
|
||||
code & "\t" & $chapter & "\t" & $verse
|
||||
|
||||
@@ -59,12 +76,20 @@ proc parseSegmentBreak(s: string): SegmentBreak =
|
||||
else:
|
||||
raise newException(ValueError, "invalid embedded Bible segment break: " & s)
|
||||
|
||||
proc parseAnnotations(metadata: string): seq[BibleAnnotation] =
|
||||
proc parseMetadata(metadata: string):
|
||||
tuple[annotations: seq[BibleAnnotation], wordsOfChrist: bool] =
|
||||
|
||||
if metadata.strip.len == 0:
|
||||
return
|
||||
|
||||
let node = parseJson(metadata)
|
||||
if node.kind != JObject or not node.hasKey("annotations"):
|
||||
if node.kind != JObject:
|
||||
return
|
||||
|
||||
result.wordsOfChrist =
|
||||
node.hasKey("wordsOfChrist") and node["wordsOfChrist"].getBool
|
||||
|
||||
if not node.hasKey("annotations"):
|
||||
return
|
||||
|
||||
for item in node["annotations"].getElems:
|
||||
@@ -75,7 +100,7 @@ proc parseAnnotations(metadata: string): seq[BibleAnnotation] =
|
||||
if targetText.strip.len == 0:
|
||||
continue
|
||||
|
||||
result.add(BibleAnnotation(
|
||||
result.annotations.add(BibleAnnotation(
|
||||
kind:
|
||||
if item.hasKey("kind"): item["kind"].getStr
|
||||
else: "",
|
||||
@@ -120,6 +145,10 @@ proc loadBibleIndex(rows, translationName: string): BibleIndex =
|
||||
indent: 0,
|
||||
text: legacy.text))
|
||||
else:
|
||||
let metadata =
|
||||
if parts.len == 8: parseMetadata(parts[7])
|
||||
else: (annotations: newSeq[BibleAnnotation](), wordsOfChrist: false)
|
||||
|
||||
result.addSegment(BibleSegment(
|
||||
code: parts[0],
|
||||
chapter: parseInt(parts[1]),
|
||||
@@ -128,9 +157,8 @@ proc loadBibleIndex(rows, translationName: string): BibleIndex =
|
||||
breakKind: parseSegmentBreak(parts[4]),
|
||||
indent: parseInt(parts[5]),
|
||||
text: parts[6],
|
||||
annotations:
|
||||
if parts.len == 8: parseAnnotations(parts[7])
|
||||
else: @[]))
|
||||
annotations: metadata.annotations,
|
||||
wordsOfChrist: metadata.wordsOfChrist))
|
||||
|
||||
proc requireLastChapter(index: BibleIndex, code: string): int =
|
||||
if not index.lastChapterByBook.hasKey(code):
|
||||
@@ -284,6 +312,41 @@ proc fetchPassages*(rows, reference, translationName: string): seq[string] =
|
||||
for parsedReference in parseReferences(reference):
|
||||
result.add(fetchReference(index, parsedReference))
|
||||
|
||||
proc normalizeAnnotationKind(kind: string): string =
|
||||
case kind.strip
|
||||
of "note":
|
||||
"note"
|
||||
of "crossReference", "crossreference", "cross-reference", "cross_reference":
|
||||
"crossReference"
|
||||
else:
|
||||
raise newException(ValueError,
|
||||
"unsupported annotation kind '" & kind &
|
||||
"'; supported annotation kinds: note, crossReference")
|
||||
|
||||
proc parseAnnotationFilter(value: string): AnnotationFilter =
|
||||
let normalized = value.strip
|
||||
|
||||
case normalized
|
||||
of "", "all":
|
||||
return AnnotationFilter(kind: afAll)
|
||||
of "none":
|
||||
return AnnotationFilter(kind: afNone)
|
||||
else:
|
||||
result.kind = afKinds
|
||||
for part in normalized.split(','):
|
||||
let annotationKind = normalizeAnnotationKind(part)
|
||||
if annotationKind notin result.kinds:
|
||||
result.kinds.add(annotationKind)
|
||||
|
||||
proc includes(filter: AnnotationFilter, annotation: BibleAnnotation): bool =
|
||||
case filter.kind
|
||||
of afNone:
|
||||
false
|
||||
of afAll:
|
||||
true
|
||||
of afKinds:
|
||||
annotation.kind in filter.kinds
|
||||
|
||||
proc footnoteLabel(index: int): string =
|
||||
var n = index
|
||||
while true:
|
||||
@@ -292,12 +355,66 @@ proc footnoteLabel(index: int): string =
|
||||
if n < 0:
|
||||
break
|
||||
|
||||
proc annotationMarker(
|
||||
label: string,
|
||||
outputFormat: EmbeddedOutputFormat,
|
||||
resumeWordsOfChrist: bool): string =
|
||||
|
||||
case outputFormat
|
||||
of eofPlain:
|
||||
"[" & label & "]"
|
||||
of eofAnsi:
|
||||
ansiCyan & "[" & label & "]" & ansiReset &
|
||||
(if resumeWordsOfChrist: ansiDarkRed else: "")
|
||||
of eofMarkdown:
|
||||
"[^" & label & "]"
|
||||
|
||||
proc visibleLen(s: string): int =
|
||||
var idx = 0
|
||||
while idx < s.len:
|
||||
if s[idx] == '\x1b' and idx + 1 < s.len and s[idx + 1] == '[':
|
||||
idx += 2
|
||||
while idx < s.len and not s[idx].isAlphaAscii:
|
||||
inc idx
|
||||
if idx < s.len:
|
||||
inc idx
|
||||
else:
|
||||
inc result
|
||||
inc idx
|
||||
|
||||
proc wrapAnsiWords(line: string, maxLineWidth = 74): string =
|
||||
let indentLen = line.len - line.strip(leading = true, trailing = false).len
|
||||
let indent = repeat(" ", indentLen)
|
||||
let words = line.strip.splitWhitespace
|
||||
if words.len == 0:
|
||||
return ""
|
||||
|
||||
var lines: seq[string]
|
||||
var current = indent
|
||||
|
||||
for word in words:
|
||||
let separator =
|
||||
if current.strip.len == 0: ""
|
||||
else: " "
|
||||
if current.strip.len > 0 and
|
||||
current.visibleLen + separator.len + word.visibleLen > maxLineWidth:
|
||||
lines.add(current)
|
||||
current = word
|
||||
else:
|
||||
current.add(separator & word)
|
||||
|
||||
if current.len > 0:
|
||||
lines.add(current)
|
||||
|
||||
lines.join("\p")
|
||||
|
||||
proc addSegmentWithFootnotes(
|
||||
line: var string,
|
||||
segment: BibleSegment,
|
||||
keepVerseNumbers: bool,
|
||||
notes: var seq[string],
|
||||
outputFormat: EmbeddedOutputFormat) =
|
||||
outputFormat: EmbeddedOutputFormat,
|
||||
annotationFilter: AnnotationFilter) =
|
||||
|
||||
var text = segment.text
|
||||
var annotations = segment.annotations
|
||||
@@ -305,21 +422,28 @@ proc addSegmentWithFootnotes(
|
||||
|
||||
var inserted = 0
|
||||
for annotation in annotations:
|
||||
if not annotationFilter.includes(annotation):
|
||||
continue
|
||||
|
||||
let label = footnoteLabel(notes.len)
|
||||
notes.add(annotation.targetText)
|
||||
|
||||
let insertAt = max(0, min(text.len, annotation.offset + inserted))
|
||||
let marker =
|
||||
case outputFormat
|
||||
of eofPlain: "[" & label & "]"
|
||||
of eofMarkdown: "[^" & label & "]"
|
||||
let marker = annotationMarker(
|
||||
label,
|
||||
outputFormat,
|
||||
resumeWordsOfChrist = segment.wordsOfChrist)
|
||||
text.insert(marker, insertAt)
|
||||
inserted += marker.len
|
||||
|
||||
if outputFormat == eofAnsi and segment.wordsOfChrist:
|
||||
text = ansiDarkRed & text & ansiReset
|
||||
|
||||
let marker =
|
||||
if keepVerseNumbers:
|
||||
case outputFormat
|
||||
of eofPlain: $segment.verse & " "
|
||||
of eofAnsi: ansiGray & $segment.verse & ansiReset & " "
|
||||
of eofMarkdown: "**" & $segment.verse & "** "
|
||||
else:
|
||||
""
|
||||
@@ -345,6 +469,7 @@ proc addFootnotes(
|
||||
lines.add(
|
||||
case outputFormat
|
||||
of eofPlain: label & ". " & note
|
||||
of eofAnsi: ansiCyan & label & ". " & note & ansiReset
|
||||
of eofMarkdown: "[^" & label & "]: " & note)
|
||||
|
||||
proc selectedChapters(index: BibleIndex, reference: PassageReference):
|
||||
@@ -377,7 +502,8 @@ proc formattedChapter(
|
||||
code: string,
|
||||
selected: Table[string, bool],
|
||||
keepVerseNumbers: bool,
|
||||
outputFormat: EmbeddedOutputFormat): string =
|
||||
outputFormat: EmbeddedOutputFormat,
|
||||
annotationFilter: AnnotationFilter): string =
|
||||
|
||||
var lines: seq[string]
|
||||
var currentLine = ""
|
||||
@@ -428,12 +554,18 @@ proc formattedChapter(
|
||||
renderSegment,
|
||||
keepVerseNumbers,
|
||||
notes,
|
||||
outputFormat)
|
||||
outputFormat,
|
||||
annotationFilter)
|
||||
else:
|
||||
var noVerseSegment = renderSegment
|
||||
noVerseSegment.text = renderSegment.text
|
||||
noVerseSegment.breakKind = sbSame
|
||||
currentLine.addSegmentWithFootnotes(noVerseSegment, false, notes, outputFormat)
|
||||
currentLine.addSegmentWithFootnotes(
|
||||
noVerseSegment,
|
||||
false,
|
||||
notes,
|
||||
outputFormat,
|
||||
annotationFilter)
|
||||
|
||||
firstSelected = false
|
||||
|
||||
@@ -449,7 +581,10 @@ proc formattedChapter(
|
||||
let prepared =
|
||||
if line.len > 90: line.strip
|
||||
else: line & " "
|
||||
wrapped.add(wrapWords(prepared, maxLineWidth = 74, newLine = "\p"))
|
||||
if outputFormat == eofAnsi:
|
||||
wrapped.add(wrapAnsiWords(prepared))
|
||||
else:
|
||||
wrapped.add(wrapWords(prepared, maxLineWidth = 74, newLine = "\p"))
|
||||
wrapped.join("\p")
|
||||
|
||||
proc fetchFormattedPassages(
|
||||
@@ -457,9 +592,12 @@ proc fetchFormattedPassages(
|
||||
reference,
|
||||
translationName: string,
|
||||
keepVerseNumbers: bool,
|
||||
outputFormat: EmbeddedOutputFormat): seq[string] =
|
||||
outputFormat: EmbeddedOutputFormat,
|
||||
annotations: string): seq[string] =
|
||||
|
||||
let index = loadBibleIndex(rows, translationName)
|
||||
let annotationFilter = parseAnnotationFilter(annotations)
|
||||
|
||||
for parsedReference in parseReferences(reference):
|
||||
var parts: seq[string]
|
||||
for chapter in index.selectedChapters(parsedReference):
|
||||
@@ -467,13 +605,15 @@ proc fetchFormattedPassages(
|
||||
parsedReference.book.code,
|
||||
chapter.verses,
|
||||
keepVerseNumbers,
|
||||
outputFormat))
|
||||
outputFormat,
|
||||
annotationFilter))
|
||||
|
||||
let body = parts.join("\p\p")
|
||||
let referenceSeparator =
|
||||
case outputFormat
|
||||
of eofPlain:
|
||||
of eofPlain, eofAnsi:
|
||||
if body.contains("\pa. "): "\p\p"
|
||||
elif body.contains("\p" & ansiCyan & "a. "): "\p\p"
|
||||
else: "\p"
|
||||
of eofMarkdown:
|
||||
if body.contains("\p[^a]: "): "\p\p"
|
||||
@@ -481,7 +621,7 @@ proc fetchFormattedPassages(
|
||||
|
||||
let referenceLine =
|
||||
case outputFormat
|
||||
of eofPlain:
|
||||
of eofPlain, eofAnsi:
|
||||
"– " & $parsedReference & " (" & translationName.toUpperAscii & ")"
|
||||
of eofMarkdown:
|
||||
"> -- *" & $parsedReference & " (" &
|
||||
@@ -489,7 +629,7 @@ proc fetchFormattedPassages(
|
||||
|
||||
let formattedBody =
|
||||
case outputFormat
|
||||
of eofPlain:
|
||||
of eofPlain, eofAnsi:
|
||||
body
|
||||
of eofMarkdown:
|
||||
var markdownLines: seq[string]
|
||||
@@ -508,19 +648,42 @@ proc fetchPlainPassages*(
|
||||
rows,
|
||||
reference,
|
||||
translationName: string,
|
||||
keepVerseNumbers = true): seq[string] =
|
||||
keepVerseNumbers = true,
|
||||
annotations = "all"): seq[string] =
|
||||
|
||||
fetchFormattedPassages(
|
||||
rows,
|
||||
reference,
|
||||
translationName,
|
||||
keepVerseNumbers,
|
||||
eofPlain)
|
||||
eofPlain,
|
||||
annotations)
|
||||
|
||||
proc fetchAnsiPassages*(
|
||||
rows,
|
||||
reference,
|
||||
translationName: string,
|
||||
keepVerseNumbers = true,
|
||||
annotations = "all"): seq[string] =
|
||||
|
||||
fetchFormattedPassages(
|
||||
rows,
|
||||
reference,
|
||||
translationName,
|
||||
keepVerseNumbers,
|
||||
eofAnsi,
|
||||
annotations)
|
||||
|
||||
proc fetchMarkdownPassages*(
|
||||
rows,
|
||||
reference,
|
||||
translationName: string,
|
||||
annotations = "all"): seq[string] =
|
||||
|
||||
proc fetchMarkdownPassages*(rows, reference, translationName: string): seq[string] =
|
||||
fetchFormattedPassages(
|
||||
rows,
|
||||
reference,
|
||||
translationName,
|
||||
keepVerseNumbers = true,
|
||||
eofMarkdown)
|
||||
eofMarkdown,
|
||||
annotations)
|
||||
|
||||
+25
-4
@@ -6,8 +6,29 @@ const kjvRows = embeddedTranslationData("kjv")
|
||||
proc fetchPassages*(reference: string): seq[string] =
|
||||
embedded_bible.fetchPassages(kjvRows, reference, "KJV")
|
||||
|
||||
proc fetchPlainPassages*(reference: string, keepVerseNumbers = true): seq[string] =
|
||||
embedded_bible.fetchPlainPassages(kjvRows, reference, "KJV", keepVerseNumbers)
|
||||
proc fetchPlainPassages*(
|
||||
reference: string,
|
||||
keepVerseNumbers = true,
|
||||
annotations = "all"): seq[string] =
|
||||
|
||||
proc fetchMarkdownPassages*(reference: string): seq[string] =
|
||||
embedded_bible.fetchMarkdownPassages(kjvRows, reference, "KJV")
|
||||
embedded_bible.fetchPlainPassages(
|
||||
kjvRows,
|
||||
reference,
|
||||
"KJV",
|
||||
keepVerseNumbers,
|
||||
annotations)
|
||||
|
||||
proc fetchMarkdownPassages*(reference: string, annotations = "all"): seq[string] =
|
||||
embedded_bible.fetchMarkdownPassages(kjvRows, reference, "KJV", annotations)
|
||||
|
||||
proc fetchAnsiPassages*(
|
||||
reference: string,
|
||||
keepVerseNumbers = true,
|
||||
annotations = "all"): seq[string] =
|
||||
|
||||
embedded_bible.fetchAnsiPassages(
|
||||
kjvRows,
|
||||
reference,
|
||||
"KJV",
|
||||
keepVerseNumbers,
|
||||
annotations)
|
||||
|
||||
+29
-4
@@ -12,16 +12,41 @@ proc fetchPassages*(reference: string): seq[string] =
|
||||
raise newException(ValueError,
|
||||
"MEV data is not embedded; generate data/private/mev.tsv and rebuild")
|
||||
|
||||
proc fetchPlainPassages*(reference: string, keepVerseNumbers = true): seq[string] =
|
||||
proc fetchPlainPassages*(
|
||||
reference: string,
|
||||
keepVerseNumbers = true,
|
||||
annotations = "all"): seq[string] =
|
||||
|
||||
when hasEmbeddedTranslationData("mev"):
|
||||
embedded_bible.fetchPlainPassages(mevRows, reference, "MEV", keepVerseNumbers)
|
||||
embedded_bible.fetchPlainPassages(
|
||||
mevRows,
|
||||
reference,
|
||||
"MEV",
|
||||
keepVerseNumbers,
|
||||
annotations)
|
||||
else:
|
||||
raise newException(ValueError,
|
||||
"MEV data is not embedded; generate data/private/mev.tsv and rebuild")
|
||||
|
||||
proc fetchMarkdownPassages*(reference: string): seq[string] =
|
||||
proc fetchMarkdownPassages*(reference: string, annotations = "all"): seq[string] =
|
||||
when hasEmbeddedTranslationData("mev"):
|
||||
embedded_bible.fetchMarkdownPassages(mevRows, reference, "MEV")
|
||||
embedded_bible.fetchMarkdownPassages(mevRows, reference, "MEV", annotations)
|
||||
else:
|
||||
raise newException(ValueError,
|
||||
"MEV data is not embedded; generate data/private/mev.tsv and rebuild")
|
||||
|
||||
proc fetchAnsiPassages*(
|
||||
reference: string,
|
||||
keepVerseNumbers = true,
|
||||
annotations = "all"): seq[string] =
|
||||
|
||||
when hasEmbeddedTranslationData("mev"):
|
||||
embedded_bible.fetchAnsiPassages(
|
||||
mevRows,
|
||||
reference,
|
||||
"MEV",
|
||||
keepVerseNumbers,
|
||||
annotations)
|
||||
else:
|
||||
raise newException(ValueError,
|
||||
"MEV data is not embedded; generate data/private/mev.tsv and rebuild")
|
||||
|
||||
@@ -187,6 +187,71 @@ HEB 4 7 2 line 1 do not harden your hearts."
|
||||
"\n" &
|
||||
"– John 8:1-2 (TEST)"
|
||||
|
||||
test "plain output can suppress annotation footnotes":
|
||||
const rows =
|
||||
"JHN\t8\t1\t0\tparagraph\t0\tJesus spoke.\t" &
|
||||
"""{"annotations":[{"kind":"crossReference","offset":12,"targetText":"Mt 21:1"}]}""" & "\n"
|
||||
let passages = embedded_bible.fetchPlainPassages(
|
||||
rows,
|
||||
"John 8:1",
|
||||
"TEST",
|
||||
annotations = "none")
|
||||
|
||||
check passages[0] == "1 Jesus spoke.\n" &
|
||||
"– John 8:1 (TEST)"
|
||||
|
||||
test "plain output filters annotation footnotes by kind":
|
||||
const rows =
|
||||
"JHN\t8\t1\t0\tparagraph\t0\tJesus spoke plainly.\t" &
|
||||
"""{"annotations":[{"kind":"note","offset":20,"targetText":"A note."}]}""" & "\n" &
|
||||
"JHN\t8\t2\t0\tsame\t0\tHe taught.\t" &
|
||||
"""{"annotations":[{"kind":"crossReference","offset":10,"targetText":"Mt 26:55"}]}""" & "\n"
|
||||
|
||||
let notesOnly = embedded_bible.fetchPlainPassages(
|
||||
rows,
|
||||
"John 8:1-2",
|
||||
"TEST",
|
||||
annotations = "note")
|
||||
let crossReferencesOnly = embedded_bible.fetchPlainPassages(
|
||||
rows,
|
||||
"John 8:1-2",
|
||||
"TEST",
|
||||
annotations = "crossReference")
|
||||
let both = embedded_bible.fetchPlainPassages(
|
||||
rows,
|
||||
"John 8:1-2",
|
||||
"TEST",
|
||||
annotations = "note,crossReference")
|
||||
|
||||
check notesOnly[0] == "1 Jesus spoke plainly.[a] 2 He taught.\n" &
|
||||
"\n" &
|
||||
"a. A note.\n" &
|
||||
"\n" &
|
||||
"– John 8:1-2 (TEST)"
|
||||
check crossReferencesOnly[0] == "1 Jesus spoke plainly. 2 He taught.[a]\n" &
|
||||
"\n" &
|
||||
"a. Mt 26:55\n" &
|
||||
"\n" &
|
||||
"– John 8:1-2 (TEST)"
|
||||
check both[0] == "1 Jesus spoke plainly.[a] 2 He taught.[b]\n" &
|
||||
"\n" &
|
||||
"a. A note.\n" &
|
||||
"b. Mt 26:55\n" &
|
||||
"\n" &
|
||||
"– John 8:1-2 (TEST)"
|
||||
|
||||
test "rejects unknown annotation filter kinds":
|
||||
const rows =
|
||||
"JHN\t8\t1\t0\tparagraph\t0\tJesus spoke.\t" &
|
||||
"""{"annotations":[{"kind":"note","offset":12,"targetText":"A note."}]}""" & "\n"
|
||||
|
||||
expect ValueError:
|
||||
discard embedded_bible.fetchPlainPassages(
|
||||
rows,
|
||||
"John 8:1",
|
||||
"TEST",
|
||||
annotations = "gloss")
|
||||
|
||||
test "plain output resets footnote labels per chapter":
|
||||
const rows =
|
||||
"JHN\t8\t59\t0\tparagraph\t0\tThey took up stones.\t" &
|
||||
@@ -238,3 +303,25 @@ HEB 4 7 2 line 1 do not harden your hearts."
|
||||
"[^a]: Jn 8:12\n" &
|
||||
"\n" &
|
||||
"> -- *John 8:59-9:1 (TEST)*"
|
||||
|
||||
test "ansi output renders verse numbers in gray and words of Christ in dark red":
|
||||
const rows =
|
||||
"JHN\t8\t1\t0\tparagraph\t0\tJesus said.\t" &
|
||||
"""{"wordsOfChrist":true}""" & "\n"
|
||||
let passages = embedded_bible.fetchAnsiPassages(rows, "John 8:1", "TEST")
|
||||
|
||||
check passages[0] == "\x1b[90m1\x1b[0m \x1b[31mJesus said.\x1b[0m\n" &
|
||||
"– John 8:1 (TEST)"
|
||||
|
||||
test "ansi output renders footnotes in cyan":
|
||||
const rows =
|
||||
"JHN\t8\t1\t0\tparagraph\t0\tJesus said.\t" &
|
||||
"""{"wordsOfChrist":true,"annotations":[{"kind":"crossReference","offset":11,"targetText":"Mt 21:1"}]}""" &
|
||||
"\n"
|
||||
let passages = embedded_bible.fetchAnsiPassages(rows, "John 8:1", "TEST")
|
||||
|
||||
check passages[0] == "\x1b[90m1\x1b[0m \x1b[31mJesus said.\x1b[36m[a]\x1b[0m\x1b[31m\x1b[0m\n" &
|
||||
"\n" &
|
||||
"\x1b[36ma. Mt 21:1\x1b[0m\n" &
|
||||
"\n" &
|
||||
"– John 8:1 (TEST)"
|
||||
|
||||
Reference in New Issue
Block a user