Documentation
¶
Index ¶
- Constants
- func AlphabeticalBooks(books []string) []string
- func AppID() string
- func BookFromSlug(slug string) (string, bool)
- func BookSlug(name string) (string, bool)
- func ChapterNumberingAgrees(from, to, book string, chapter, spanEnd int) bool
- func ChapterNumberingDifference(from, to, book string, chapter, spanEnd int) string
- func CreateMainUI(app fyne.App, state *AppState, window fyne.Window) fyne.CanvasObject
- func DecodeNote(payload string) (DecodedNote, NoteOutcome)
- func EncodeNote(note string) string
- func EncodeNoteWire(w NoteWire) string
- func FirstLetter(book string) string
- func GroupVersesIntoParagraphs(verses []Verse) [][]Verse
- func HandleShareLink(state *AppState, rawURL string) bool
- func HighlightTintClass() string
- func IncommensurableBook(vid, book string) string
- func InstallDebugCapture()
- func InstallReadingStateFlush(myApp fyne.App, window fyne.Window, state *AppState)
- func IsWordsOfChrist(book string, chapter, verse int) bool
- func MapVerse(from, to, book string, chapter, verse int) (int, int, verseMapResult)
- func ObserveSystemThemeChanges(myApp fyne.App, state *AppState)
- func PoeticJoin(prevText, curText string) bool
- func ProductName() string
- func ReadingLinePitchEm() float64
- func ReadingOpticalScale() float64
- func Run()
- func ShareLinkURL(versionID, book string, chapter, lo, hi int) string
- func ShareLinkURLWithNote(versionID, book string, chapter, lo, hi int, note string) string
- func ShareLinkURLWithNoteNonce(versionID, book string, chapter, lo, hi int, note string, nonce []byte) string
- func SiteBase() string
- func SiteHost() string
- func StartBackgroundLoad(myApp fyne.App, window fyne.Window, state *AppState)
- func SupportEmail() string
- func SupportMailtoRecipient() string
- func VerseExistsIn(vid, book string, chapter, verse int) bool
- func VerseIsPoetic(text string) bool
- func WebNoteArrivalLeadPx() int
- func WebNoteByline() string
- func WebNotePillLabel() string
- func WebScriptureFontBold() []byte
- func WebScriptureFontLicense() []byte
- func WebScriptureFontRegular() []byte
- func WebUIFontBold() []byte
- func WebUIFontLicense() []byte
- func WebUIFontRegular() []byte
- type Annotation
- type AnnotationStore
- type AppState
- type BibleData
- func (bd *BibleData) GetChapter(book string, chapter int) []Verse
- func (bd *BibleData) GetChapterNumbersForBook(book string) []int
- func (bd *BibleData) GetChaptersForBook(book string) int
- func (bd *BibleData) GetVerse(book string, chapter int, verse int) *Verse
- func (bd *BibleData) OrphanNotesFor(book string, chapter int) []OrphanFootnote
- func (bd *BibleData) PopulateWithSampleVerses()
- func (bd *BibleData) PrepareSearchIndex()
- func (bd *BibleData) Search(query string) []Verse
- func (bd *BibleData) SearchLimited(query string, limit int) ([]Verse, bool)
- func (bd *BibleData) SearchSmartLimited(query string, limit int) ([]Verse, bool)
- func (bd *BibleData) SuperscriptionFor(book string, chapter int) Superscription
- type BibleVersion
- type ChapterBlock
- type ChapterVisit
- type DecodedNote
- type Footnote
- type FootnoteEntry
- type Heading
- type Mark
- type NoteKind
- type NoteOutcome
- type NoteRef
- type NoteVerseRun
- type NoteWire
- type OrphanFootnote
- type ShareTarget
- type StoredNote
- type Superscription
- type TextRun
- type TextSpan
- type Verse
- type VerseRef
- type VerseSpan
- type WebReaderPalette
Constants ¶
const ( // NumberingSame — every verse keeps its number; a reference may be carried // across as-is. NumberingSame = "" // NumberingMoved — the passage is in `to`, under a different number. NumberingMoved = "moved" // NumberingAbsent — `from` numbers a verse here that `to` simply does not // contain (the NKJV's Acts 8:37). Not a renumbering, and telling a reader it // is one would be false. NumberingAbsent = "absent" // NumberingIncommensurable — the two translations' versions of this BOOK do // not correspond verse by verse at all (WEBC's Greek Esther). NumberingIncommensurable = "incommensurable" )
Numbering-difference kinds returned by ChapterNumberingDifference. They are plain strings rather than the unexported verseMapResult because the one caller outside this package (cmd/websitegen) turns them straight into a sentence for a reader, and a leaked enum would be a type it could not name.
const NoteMaxRunes = 280
NoteMaxRunes caps a note. It bounds the URL (a 280-rune note lands at roughly 290 characters of link, which messengers carry without wrapping or truncating) and it bounds the abuse surface of text we will render.
ENCODER-SIDE ONLY: the decoder must not enforce a rune cap and refuse a note over it (docs/NOTE_WIRE_FORMAT.md, the limits table) — normalizeNote truncates instead.
Variables ¶
This section is empty.
Functions ¶
func AlphabeticalBooks ¶
AlphabeticalBooks orders books the way the app's "Go to" picker does — a leading numeral read as an ordinal, so 1/2/3 John group under John.
func BookFromSlug ¶
BookFromSlug resolves a URL slug back to its canonical book name.
func ChapterNumberingAgrees ¶
ChapterNumberingAgrees reports whether EVERY verse of one chapter keeps its own number when a reference is carried from translation `from` into `to`.
It exists for the web reader's parallel-passage links. The server never sees the verse — it rides in the fragment (share_link.go) — so the page has to decide at BUILD time whether "the same verse, in another translation" is a link it may offer at all. When this returns false the page offers the CHAPTER and says the numbering differs there, which is the honest answer; pointing confidently at a number that means a different passage is the worst failure this file exists to prevent.
spanEnd is the last verse number the chapter reaches in the REFERENCE translation (the WEB) — the caller has that, because the reference is one of the translations it loaded, and it does NOT have `from`'s own verse list (the point of the NKJV pages is that the site holds no NKJV data at all).
TWO THINGS THE REFERENCE'S SPAN ALONE WOULD MISS, both found by measurement rather than by reading:
- verses `from` HAS and the reference LACKS — the NKJV's Acts 8:37, Acts 15:34, Acts 24:7 and Luke 17:36. All four happen to be numbered inside the WEB chapter's span today, but relying on that is luck.
- verses `from` numbers INTO this chapter that the reference numbers elsewhere — the NKJV's Romans 16:25-27, which the WEB carries as 14:24-26. The WEB's Romans 16 stops at 24, so a 1..spanEnd scan never asks about 25 and calls the chapter safe. It is not: those three verses are exactly the ones a shared link would land in the wrong place.
It is deliberately CONSERVATIVE in the other direction: spanEnd may name verses `from` does not have (the WEB's Romans 14:24-26 against the NKJV's 23-verse chapter), so a chapter can be reported as disagreeing when no reachable reference would actually move. The cost of that is a chapter-level link and one extra sentence; the cost of the opposite is the reader being shown different words from the ones they were sent.
func ChapterNumberingDifference ¶
ChapterNumberingDifference reports HOW one chapter's verse numbers differ between two translations — NumberingSame when they do not.
When more than one kind applies the most severe wins, in the order incommensurable, absent, moved: they describe the same chapter at different scales, and a reader told only about the smallest would act on the wrong one.
func CreateMainUI ¶
CreateMainUI (desktop) assembles the whole window. The sidebar and the split are built once and stay put; navigation swaps only the reading pane's content, so the search and filter fields never lose focus. Toggling the theme rebuilds the tree with the new palette.
func DecodeNote ¶
func DecodeNote(payload string) (DecodedNote, NoteOutcome)
DecodeNote is the inverse: the decoded record plus what to do about it. On any outcome other than NoteOutcomeOK the DecodedNote is zero — it never returns a partially decoded note, because the caller's next move is to render it.
A note arriving here is UNTRUSTED — it came from a URL that anyone can write. This function guarantees only that Text is well-formed, printable UTF-8 within the length cap. It is NOT sanitised for a markup context: every caller must insert it as text (textContent, an escaped HTML write, an attributed string), never as markup. See docs/SHARED_NOTES.md → Security.
func EncodeNote ¶
EncodeNote is the text-only convenience over the record encoder: a payload carrying just 't'. Callers that know the passage should use EncodeNoteWire. It returns "" for a note that is empty once trimmed — callers then emit a plain link rather than one carrying nothing.
func EncodeNoteWire ¶
EncodeNoteWire turns a note into the payload that rides in a shared link's fragment: byte 0 'r' (or 'd' when DEFLATE comes out smaller), then records in canonical form — ascending by tag, at most one of each, minimal uvarints.
The note is TRUNCATED rather than rejected if it is too long: a share is a gesture, and failing it outright at the last moment is worse than sending a slightly shortened note. Callers should hold the writer to NoteMaxRunes in the UI so this never fires.
func FirstLetter ¶
FirstLetter is the letter a book is filed under in that picker's alphabet grid ("1 John" → "J"). Exported with AlphabeticalBooks so the web picker groups and orders identically to the app rather than re-deriving the rule in JavaScript, where "1 John" would file under "1".
func GroupVersesIntoParagraphs ¶
GroupVersesIntoParagraphs applies the app's paragraph rule (break after a sentence-ending verse once a paragraph is long enough). Exported so the web page breaks paragraphs in exactly the same places the reading pane does.
func HandleShareLink ¶
HandleShareLink is the single entry point for a tapped link, called from the platform glue on the UI goroutine. It returns false when the URL is not one of ours, so the caller can let the system open it in a browser instead.
func HighlightTintClass ¶
func HighlightTintClass() string
HighlightTintClass is the CSS class a highlighted verse carries, from the app's own tint table (verseTint.htmlClass, tint.go).
The web reader is the ONE surface that cannot consume chapterTint: its pages are static and the tint is chosen at read time, in reader.js, from the URL fragment. What it can share is the VOCABULARY — and it must, because a shared link opened in the browser and the same link opened in the app are meant to light the same verses the same way. Exported so cmd/websitegen's tests can assert its hand-written CSS and JS still spell the class the way the app's emitter does; adding a second tint means adding a name here and a rule there, and the test is what says so out loud instead of the site quietly rendering the old single wash.
func IncommensurableBook ¶
IncommensurableBook explains why a book cannot be mapped between the reference and vid, or "" when it can. Callers show this rather than inventing a verse.
func InstallDebugCapture ¶
func InstallDebugCapture()
The shipping half of debug_capture_macos.go: nothing. Kept as a real symbol so the entry point can call it unconditionally and no build tag leaks into cmd/desktop.
func InstallReadingStateFlush ¶
InstallReadingStateFlush captures the precise within-chapter scroll position when the app stops or backgrounds (and, on desktop, when the window is closed while the native text view is still alive). Navigation already saves the location + history continuously via persistReadingPosition; this is the only hook that catches a pure scroll with no navigation. Exported so both entry points (desktop Run and cmd/mobile) can install it.
func IsWordsOfChrist ¶
IsWordsOfChrist reports whether a verse falls in a red-letter range.
DEPRECATED FOR RENDERING. This is the WEB's verse-level judgement and it is version-blind, so a page rendered through it reddens the WHOLE verse and reddens it identically in every translation. Use RedLetterRuns instead, which asks the edition's own table. Kept because it is still the honest answer to the question it actually asks ("does Christ speak in this verse at all"), and removing an exported symbol is not free.
func MapVerse ¶
MapVerse carries a verse reference from one translation's numbering into another's. It returns the chapter and verse to use in `to`, and what kind of correspondence that is — callers must look at the result, because a returned 0,0 means "there is no such verse there", not "verse zero".
Composed through the reference, so a BSB→NKJV mapping is BSB→WEB→NKJV. Both halves can fail independently: Romans 16:25 in the BSB is the WEB's 14:24 (moved), which is the NKJV's 16:25 (moved back) — the same passage, two moves, and the round trip lands where it started.
func ObserveSystemThemeChanges ¶
ObserveSystemThemeChanges subscribes to Fyne's settings-change channel so a system light/dark switch rebuilds the window. Fyne re-runs Color() automatically when the variant changes, but anything generated outside the theme callback (like the HTML the iOS UITextView consumes, or the palette colors baked into canvas objects at build time) is stale until we rebuild.
The rebuild goes through rebuildWindow, NOT a bare SetContent: SetContent replaces only the content tree and never touches Canvas().Overlays(), so an OPEN popup (the Settings sheet, a picker) survived a variant flip with its captured colors while Fyne re-lit its stock widgets — the resulting dark-panel/dark-text sheet after an overnight dark→light switch with the app suspended. rebuildWindow drains the overlay stack (popups close; reopening shows fresh colors) and re-pins the native reading overlay.
applyTheme calls app.Settings().SetTheme() the first time (and on a real theme change), which ALSO fires this listener — so we guard against a rebuild loop by only acting when the actual light/dark variant has changed since last time.
func PoeticJoin ¶
PoeticJoin reports whether the boundary between two adjacent verses is a poetry line boundary — the rule that keeps the web page, the reading pane and a shared quote breaking in identical places.
func ReadingLinePitchEm ¶ added in v1.2.7
func ReadingLinePitchEm() float64
ReadingLinePitchEm is the same number for the generated site, whose CSS line-height multiplies the font size directly — no numeral in the way.
func ReadingOpticalScale ¶ added in v1.2.7
func ReadingOpticalScale() float64
ReadingOpticalScale is the correction as the site generator needs it. The generated stylesheet sets Scripture in the same face as the app and has to open it up by the same amount, or a chapter read on the web is visibly smaller than the same chapter read in the app.
func Run ¶
func Run()
Run is the desktop entry: loads the data, opens a sized window, and starts the event loop. Mobile entries (Fyne iOS) use the same data path but configure the window differently — see cmd/mobile/main.go.
func ShareLinkURL ¶
ShareLinkURL builds the permanent web URL for a passage. lo/hi are verse numbers; pass lo <= 0 for a chapter-level link, or hi <= lo for a single verse. It returns "" only if the book is unknown — callers fall back to sharing plain text rather than a broken link.
A selection spanning several chapters passes its FIRST chapter and that chapter's verse span: the link then under-highlights rather than pointing at the wrong chapter. (The app cannot select across chapters today; fixing the rule now means tomorrow's app needs no new pages.)
func ShareLinkURLWithNote ¶
ShareLinkURLWithNote is ShareLinkURL plus an optional note from the sender. An empty note (or one that is empty once normalized) yields exactly the link ShareLinkURL would have produced — byte for byte — so adding this feature changed nothing about the links that do not use it.
func ShareLinkURLWithNoteNonce ¶
func ShareLinkURLWithNoteNonce(versionID, book string, chapter, lo, hi int, note string, nonce []byte) string
ShareLinkURLWithNoteNonce is ShareLinkURLWithNote plus the note's per-share identity, which the sending device keeps so it can recognise its own note coming home (share_note.go, noteTagNonce). A nil nonce emits nothing and produces exactly the link the plain builder would — so every existing caller, and every link already in the world, is unaffected.
func SiteBase ¶
func SiteBase() string
SiteBase returns the origin the published site and every shared link live on ("https://bibletext.co.uk"). Exported for the site generators, which build canonical URLs from it.
func SiteHost ¶
func SiteHost() string
SiteHost returns SiteBase's bare host, the form deep-link matching uses.
func StartBackgroundLoad ¶
StartBackgroundLoad kicks off the Bible load on a background goroutine and swaps the result into the live state on the UI thread when it's ready. The caller shows the window FIRST (with state.loadPhase == loadPending, so CreateMainUI renders just a spinner and never attaches the native reading overlay); this keeps the main thread free, so the iOS launch watchdog can't SIGKILL the app on a slow first-run fetch. On success we copy the loaded fields into the same *AppState the UI already closed over (never swap the pointer — the showReading/surfaceReading closures captured it) and rebuild; on failure we show an in-app retry view.
Exported so both entry points (desktop Run, cmd/mobile) use the same path.
func SupportEmail ¶
func SupportEmail() string
SupportEmail returns the public mailbox used by product support surfaces. Its only tracked value lives in config/product.json.
func SupportMailtoRecipient ¶
func SupportMailtoRecipient() string
SupportMailtoRecipient returns the configured mailbox escaped for the recipient component of a mailto URI.
func VerseExistsIn ¶
VerseExistsIn reports whether a verse named in the reference's numbering is present in a translation at all. Cheaper to read than MapVerse when the caller only needs to know whether to offer something.
func VerseIsPoetic ¶
VerseIsPoetic reports whether a verse carries authored poem-line breaks.
func WebNoteArrivalLeadPx ¶
func WebNoteArrivalLeadPx() int
WebNoteArrivalLeadPx is the shared arrival lead (noteMetrics().Lead): how far below the top of the viewport an arrival places its target.
func WebNoteByline ¶
func WebNoteByline() string
WebNoteByline is the shared byline for a received note, exactly as the app panes attribute one (senderByline). Sender names do not ship, so this is a generate-time constant for the static reader; the day names ship, TestWebReaderNoteChromeComesFromTheSharedFunctions holds the seam and the template learns names rather than silently keeping the constant.
func WebNotePillLabel ¶
func WebNotePillLabel() string
WebNotePillLabel is the shared collapsed-pill label for the web reader's structural case — one placed note, nothing unplaced — from the same function every pane's pill reads (stickerPillWho).
func WebScriptureFontBold ¶ added in v1.2.7
func WebScriptureFontBold() []byte
WebScriptureFontBold is the subsetted reading face, bold. Required, and not obviously so: the only bold inside the reading column is the verse number, and with a webfont a weight of 600 resolves to the 700 face — so shipping regular alone would leave every verse number synthesised.
func WebScriptureFontLicense ¶ added in v1.2.7
func WebScriptureFontLicense() []byte
WebScriptureFontLicense is the reading face's licence. The OFL requires it to travel with the font, which is why the site publishes it beside the file.
func WebScriptureFontRegular ¶ added in v1.2.7
func WebScriptureFontRegular() []byte
WebScriptureFontRegular is the subsetted reading face (WOFF2). Built from the SAME file the app embeds, so the site and the app can never drift to different releases of it. Narrower than the app's subset: the site publishes no edition that marks a divine name, so it needs no small capitals, and its note chrome is set in the UI face, so its scripture face never draws Greek or Hebrew.
func WebUIFontBold ¶
func WebUIFontBold() []byte
WebUIFontBold is the subsetted Atkinson Hyperlegible bold face (WOFF2).
func WebUIFontLicense ¶
func WebUIFontLicense() []byte
WebUIFontLicense is the SIL Open Font License text that must be published alongside the faces above.
func WebUIFontRegular ¶
func WebUIFontRegular() []byte
WebUIFontRegular is the subsetted Atkinson Hyperlegible regular face (WOFF2).
Types ¶
type Annotation ¶
type Annotation struct {
Ref VerseRef
Note string
Color string // optional highlight colour key; "" means a plain note
Created time.Time
Updated time.Time
}
Annotation is a user note and/or highlight attached to a verse. This is the data foundation for upcoming annotation/research features; the UI and persistence are intentionally not wired yet.
type AnnotationStore ¶
type AnnotationStore struct {
// contains filtered or unexported fields
}
AnnotationStore holds annotations keyed by verse reference. It is in-memory for now; persistence can follow the versioned, atomic JSON pattern in cache.go.
func NewAnnotationStore ¶
func NewAnnotationStore() *AnnotationStore
func (*AnnotationStore) Add ¶
func (s *AnnotationStore) Add(a Annotation)
Add stores an annotation, stamping timestamps when absent.
func (*AnnotationStore) Count ¶
func (s *AnnotationStore) Count() int
Count returns the total number of annotations stored.
func (*AnnotationStore) ForVerse ¶
func (s *AnnotationStore) ForVerse(r VerseRef) []Annotation
ForVerse returns the annotations attached to a verse, in insertion order.
func (*AnnotationStore) HasAny ¶
func (s *AnnotationStore) HasAny(r VerseRef) bool
HasAny reports whether a verse carries any annotation (for gutter markers etc.).
func (*AnnotationStore) Refs ¶
func (s *AnnotationStore) Refs(bookOrder []string) []VerseRef
Refs returns every annotated verse reference, sorted canonically by book order.
type AppState ¶
type AppState struct {
Bible *BibleData
// Translation the reader is showing. CurrentVersion is a BibleVersion ID
// (see versions.go); currentMode says whether Bible is real scripture or a
// testing placeholder; loadedVersions caches already-loaded translations so
// switching back is instant (the default/base version is always present).
CurrentVersion string
CurrentBook string
CurrentChapter int
BookFilterQuery string
SearchQuery string
ActiveSearchQuery string
SearchResults []Verse
SearchTruncated bool
IsSearching bool
CanReturnToSearchResults bool
// The note attached to that highlight, when the reader arrived on a shared
// link carrying one. Minimized means the reader collapsed it: the note is
// kept but neither it nor its highlight is shown until they bring it back.
ActiveNote string
NoteMinimized bool
// NoteVerseLo is the verse the note is attached to. Kept separately from the
// highlight because minimizing CLEARS the highlight — without this the note
// would lose its anchor and its marker would jump to the top of the chapter.
NoteVerseLo int
// NoteID is the live note's identity in the scrapbook store
// (StoredNote.ID) — the ONLY handle Hide, Show and Delete address. It is
// handed to the mirror by the derive and carried whole; no verb ever
// rebuilds a key from the version, book or chapter the reader happens to
// be standing on. Rebuilding the address from the reader's position is
// what deleted the wrong note (X1), made Hide and Show address different
// objects (X5), and left a cross-chapter note unreachable by any verb
// (X13). Zero means "no live note", or a note the store could not keep.
NoteID uint64
// NoteNotice is the sentence shown in the note's place when a link's
// payload could NOT be rendered — a newer note format, or damage
// (noteOutcomeMessage). Session-only and never stored: it is the app
// reporting on a payload, not a message from a person, so it is attributed
// to nobody, carries no action and no link, and the next navigation clears
// it (addRecentChapter). See docs/NOTE_WIRE_FORMAT.md rule 5.
NoteNotice string
RecentChapters []ChapterVisit
// IsFullScreen is the "distraction-free reading" toggle, honoured on every
// platform: the shared compact layout (buildCompactUI, ui_compact.go)
// returns the reading view alone — no app header, no bottom bar or rail —
// and the desktop's opt-out sidebar layout has the same branch
// (ui_desktop.go). The way out differs per reading view: on the desktop the
// chapter toolbar stays and its focus button restores the layout
// (chapterHeader, reading.go); on iOS/Android the reading view drops the
// chapter toolbar and draws its own small exit row with the chapter
// reference (buildReadingViewMobile). The mobile toolbar's full-screen
// button (chapter_header_mobile.go) and the desktop toolbar's focus button
// are the ways in. The PRESENTED mode is readingFullScreen
// (phone_landscape.go): this choice, or the phone-landscape presentation
// (on by default on phones, Read tab only), which never writes this flag.
IsFullScreen bool
// CurrentTab is the selected mobile bottom-bar tab: 0 Read, 1 Books,
// 2 Search. The mobile UI rebuilds the window on tab change (reliable
// repaint) rather than swapping a content host in place.
CurrentTab int
// NotesMode is the Search tab's third mode: browsing the notes people have
// shared. Mutually exclusive with aiSearchMode — searchModeOf is the one
// place that resolves the pair, so no caller has to remember the rule.
NotesMode bool
// NotesQuery filters the notes browser. It is deliberately NOT the keyword
// search query: switching Search → Notes with a scripture term still in the
// box would greet the reader with "no notes match" for a search they never
// made of their notes.
NotesQuery string
// Annotations is the foundation for note/highlight + research features. It is
// populated/persisted by future work; the reading view already renders verses
// as selectable, individually-referenceable blocks.
Annotations *AnnotationStore
// contains filtered or unexported fields
}
AppState holds everything the UI renders from, plus hooks the widgets install so state-mutating helpers can request a redraw without knowing about widgets.
func NewLoadingState ¶
func NewLoadingState() *AppState
NewLoadingState returns a minimal AppState in the loadPending phase, valid for CreateMainUI to render the loading spinner before any Bible data exists. The entry points hand this to the window, then call StartBackgroundLoad.
type BibleData ¶
type BibleData struct {
// Verses is a nested map (map of maps) organizing all verses
// First key: book name ("John", "Genesis", etc.)
// Second key: chapter number (1, 2, 3, etc.)
// Value: slice of all Verse objects in that chapter
Verses map[string]map[int][]Verse
// Books is the edition's book names in canonical order (66, or 73 for the Catholic canon)
// Used to display the book list in the sidebar
Books []string
// OrphanFootnotes carries the translators' notes anchored in verses the
// translation OMITS (see OrphanFootnote), keyed book → chapter. Nothing
// but the chapter-bottom footnote section reads it — it is invisible to
// search, speech, share, copy and links by construction, because those
// all walk Verses. omitempty: caches written before this field existed
// load with a nil map, and every accessor is nil-safe (the superseded-
// epoch fallback serves such caches to offline upgraders).
OrphanFootnotes map[string]map[int][]OrphanFootnote `json:"orphan_footnotes,omitempty"`
// Superscriptions carries the Psalm titles (see Superscription), keyed
// book → chapter. omitempty + nil-safe accessors, for the same
// pre-field-cache reasons as OrphanFootnotes.
Superscriptions map[string]map[int]Superscription `json:"superscriptions,omitempty"`
// Headings carries the publisher's own section headings, keyed by book and
// chapter (see Heading). Every edition sets them and the app used to drop
// every one: 3,091 in the Berean alone, which is its translators' map of
// what each chapter is about. They are captured here whether or not any
// surface draws them, because a thing a publisher sent is kept.
//
// Like a superscription, a heading is NOT Scripture. It never enters
// Verse.Text, so it cannot reach search, speech, sharing, copying or a
// link by accident; a surface that wants to draw one asks for it.
Headings map[string]map[int][]Heading `json:"headings,omitempty"`
// contains filtered or unexported fields
}
BibleData holds all Bible verses organized by book and chapter This is the data model/storage for the entire Bible Structure:
- Books: the edition's book names in canonical order (66, or 73 for the Catholic canon)
- Verses: map[book][chapter] = list of verses Example: Verses["John"][1] = [Verse1, Verse2, ...]
func DecodeCanonical66 ¶
DecodeCanonical66 decodes a 66-book helloao complete.json (WEB, BSB).
func DecodeHelloAOCatholic ¶
DecodeHelloAOCatholic decodes the 73-book WEB Catholic complete.json.
func FetchBibleFromAPI ¶
FetchBibleFromAPI fetches the complete World English Bible from a public API This uses the free bible-api service which has the complete WEB translation Source: https://bible-api.com/
func NewBibleData ¶
func NewBibleData() *BibleData
NewBibleData creates and initializes a new BibleData structure This sets up the empty data structure ready to be populated with verses
func (*BibleData) GetChapter ¶
GetChapter returns all verses in a specific chapter Returns an empty slice if the chapter has no verses This is the main function for displaying a chapter Example: GetChapter("John", 1) returns all verses in John chapter 1
func (*BibleData) GetChapterNumbersForBook ¶
GetChapterNumbersForBook returns sorted available chapter numbers for a book. When the chapterNums cache is present (the normal loaded-Bible case) it returns the shared cached slice — callers only read/range it, so there's no defensive copy. Falls back to computing for directly-constructed BibleData (tests).
func (*BibleData) GetChaptersForBook ¶
GetChaptersForBook returns the number of chapters in a book Used by the navigation buttons to determine if we can go to the next chapter Example: GetChaptersForBook("John") might return 21 (John has 21 chapters)
func (*BibleData) GetVerse ¶
GetVerse returns a specific verse from the Bible Returns nil if the verse doesn't exist Parameters:
- book: name of the book (e.g., "John")
- chapter: chapter number
- verse: verse number
Example: GetVerse("John", 3, 16) returns "For God so loved the world..."
func (*BibleData) OrphanNotesFor ¶
func (bd *BibleData) OrphanNotesFor(book string, chapter int) []OrphanFootnote
OrphanNotesFor returns the chapter's omitted-verse footnotes, or nil. Nil-safety is load-bearing at every level: the superseded-epoch fallback serves pre-field caches (nil map) to offline upgraders, and placeholder BibleData carries no orphans at all.
func (*BibleData) PopulateWithSampleVerses ¶
func (bd *BibleData) PopulateWithSampleVerses()
PopulateWithSampleVerses loads a small set of World English Bible (public domain) verses. This is demo/fixture data used by tests and offline examples; the running app always loads the complete WEB text from cache or the API.
func (*BibleData) PrepareSearchIndex ¶
func (bd *BibleData) PrepareSearchIndex()
PrepareSearchIndex precomputes normalized verse text + reference strings used by search, and the per-book sorted chapter-number cache. It is the heavy per-load pass (~31k verses), so it runs on the background load goroutine before the UI ever sees the BibleData; afterwards the data is read-only.
func (*BibleData) Search ¶
Search searches for verses containing the given query text Returns a slice of all verses that match (case-insensitive) Example: Search("faith") returns all verses containing the word "faith"
func (*BibleData) SearchLimited ¶
SearchLimited searches for verses containing the query and caps returned results. It returns the matches and whether additional matches were omitted due to limit.
func (*BibleData) SearchSmartLimited ¶
SearchSmartLimited supports verse reference queries and ranked term matching.
func (*BibleData) SuperscriptionFor ¶
func (bd *BibleData) SuperscriptionFor(book string, chapter int) Superscription
SuperscriptionFor returns the chapter's Hebrew title, or the zero value — nil-safe at every level, like OrphanNotesFor.
type BibleVersion ¶
type BibleVersion struct {
ID string // stable id; also the per-version cache filename ("web","lsb","nkjv")
Name string // full name, e.g. "World English Bible"
Abbrev string // short label, e.g. "WEB"
Publisher string // one-line rights/copyright note, shown in the picker
// LicenseNotice is the attribution the rights holder requires displayed
// with the text — shown in the picker once the version is actually
// licensed and serving real text (versionRow). Empty for public-domain
// versions, whose Publisher line already says everything.
LicenseNotice string
// PublicDomain marks freely-distributable text (no license required).
PublicDomain bool
// PublisherCrossRefs shows the edition's OWN cross-reference apparatus in
// the cross-references panel (publisher_xrefs.go), ahead of the Treasury
// of Scripture Knowledge. False everywhere in a store build: displaying a
// licensed publisher's apparatus is the subject of a licensing enquiry that
// has been sent and not answered, so the one line that sets it — for the
// NKJV — lives behind the nkjvxrefs build tag (versions_nkjvxrefs.go),
// where no shipped binary compiles it.
PublisherCrossRefs bool
// contains filtered or unexported fields
}
BibleVersion describes one selectable translation.
type ChapterBlock ¶ added in v1.2.7
type ChapterBlock struct {
// HeadingText is the heading, or "" when this block is a paragraph.
HeadingText string
// Verses is the paragraph's verses, nil when this block is a heading.
Verses []Verse
}
ChapterBlock is one piece of a chapter as it is set on the page: either a publisher's section heading, or a paragraph of verses. The exported shape of what every reading surface now walks.
func ChapterBlocks ¶ added in v1.2.7
func ChapterBlocks(bd *BibleData, book string, chapter int, verses []Verse) []ChapterBlock
ChapterBlocks returns a chapter in the order it is set — the publisher's headings among its own paragraphs. Exported so the page places them exactly where the reading pane does.
type ChapterVisit ¶
type ChapterVisit struct {
Book string
Chapter int
Verse int `json:"v,omitempty"`
Delta float64 `json:"d,omitempty"`
Frac float64 `json:"f,omitempty"`
}
ChapterVisit is one entry in the reading history. The scroll anchor (top verse + within-verse delta, with a whole-chapter Frac fallback) records where the reader was when they left this chapter, so tapping it in the history bar returns them there instead of to the top. A zero anchor means top-of-chapter. The anchor fields are omitempty so plain (top-of-chapter) entries and pre-anchor saved blobs stay compact and backward-compatible.
type DecodedNote ¶
type DecodedNote struct {
Text string // normalized; non-empty exactly when the outcome is OK
Version string // sender's translation id ('v'), "" when absent
Book string // canonical book name resolved from 'b', "" when absent
Chapter int // 'c', 0 when absent
Runs []NoteVerseRun
Nonce []byte // 'n', nil when absent — see noteTagNonce
// Skipped holds every record this build could not USE, verbatim
// (tag+len+value): unknown lowercase tags, and known tags whose value did
// not parse. Preserved, not merely skipped (docs/NOTE_WIRE_FORMAT.md rule
// 3), so a future forward/re-share can re-emit them instead of silently
// destroying the sender's data on its way through us.
Skipped [][]byte
// Opaque is the 0xFF stop byte and everything after it, verbatim, for the
// same reason.
Opaque []byte
}
DecodedNote is everything a payload carried that this build can read. Zero-valued fields were absent; Runs distinguishes absent (nil) from present-with-zero-runs (empty, a real assertion — see docs/NOTES_SPEC.md#wire-contract on the 'a' record).
type Footnote ¶
type Footnote struct {
// Anchor is a rune offset into Verse.Text (0..len) at a word boundary —
// where the source placed the marker. For a note the source anchored
// between poem lines, Anchor sits at the end of the earlier line, before
// the "\n".
Anchor int `json:"anchor"`
// Text is the note body — the translators' words. Origin references the
// source prefixes to the body ("3:2 " in the NKJV apparatus) are
// stripped at decode time: the anchor already says where it belongs.
Text string `json:"text"`
// Kind distinguishes apparatus families: "" is a translator footnote
// (alternate rendering, manuscript variant, language note); "crossref"
// is a cross-reference entry (the only kind the NKJV feed carries).
Kind string `json:"kind,omitempty"`
// Caller is the source's marker glyph ("+" throughout helloao, "-" in
// the NKJV feed). Stored for fidelity; no surface renders it yet.
Caller string `json:"caller,omitempty"`
// Refs are the citations inside a cross-reference note that the source
// tagged with a machine-readable target, in text order. Only the NKJV feed
// tags them (its ref elements); the helloao editions' notes carry none and
// leave this nil, as does a cache written before the field existed.
// Offsets into Text, never characters added to it, so a note's words are
// the publisher's own whether or not its citations were kept.
Refs []NoteRef `json:"refs,omitempty"`
}
Footnote is one note from the TRANSLATORS (never the reader — reader notes are the separate shared-notes feature) anchored into a verse's text.
type FootnoteEntry ¶ added in v1.2.8
type FootnoteEntry struct {
// Key is "Title" for a superscription's note and the verse number
// otherwise — the same string every in-app renderer prints.
Key string
Text string
}
FootnoteEntry is one row of a chapter's footnote section: the key it is filed under and the translators' words.
func ChapterFootnoteEntries ¶ added in v1.2.8
func ChapterFootnoteEntries(bd *BibleData, book string, chapter int, verses []Verse) []FootnoteEntry
ChapterFootnoteEntries is the chapter's apparatus in the order the app shows it: title notes first, then verse notes in verse order, with an omitted verse's note sorted into its natural place between its neighbours.
Exported as a WHOLE ROW rather than as its parts so the website cannot re-derive the ordering, the key or the cross-reference exclusion and drift away from the app. In particular the exclusion is not cosmetic: the NKJV's entire apparatus is cross-references, and whether they display at all is an open licensing question (docs/SCRIPTURE_WORKLIST.md S20).
type Heading ¶ added in v1.2.7
type Heading struct {
// Text is the heading as the publisher set it.
Text string `json:"text"`
// Style is the publisher's classification: "heading" for the helloao
// feeds, which name only the one kind, and the USX paragraph style for
// API.Bible — "s" and "s1".."s4" for section heads, "ms" for a major
// section, "r"/"mr"/"sr" for a reference line, "qa" for an acrostic
// letter, and so on.
Style string `json:"style,omitempty"`
// Footnotes are the notes the publisher put INSIDE this heading. They were
// discarded with the block that carried them, which left them with less
// trace than any other note in the apparatus; they belong to the heading,
// not to whichever verse happened to be current when it was read.
Footnotes []Footnote `json:"footnotes,omitempty"`
// BeforeVerse is the verse this heading stands above. A heading at the
// head of a chapter names its first verse; one between verses names the
// verse that follows it. Zero means the heading closed a chapter with no
// verse after it, which the sources do not do but the decoders do not
// assume.
BeforeVerse int `json:"before_verse,omitempty"`
}
type Mark ¶
type Mark struct {
Origin hlOrigin
At VerseSpan
}
Mark is the highlight. The zero Mark is "nothing is highlighted", and it is the only way to say that.
type NoteKind ¶
type NoteKind string
NoteKind says what sort of record this is. Extensible: a build that meets a kind it does not know keeps the record and simply does not draw it.
type NoteOutcome ¶
type NoteOutcome uint8
NoteOutcome is what DecodeNote concluded about a payload. There is no silent arm: ok renders the note, and BOTH failure arms are TOLD to the reader (docs/NOTE_WIRE_FORMAT.md rule 5) — in the note's place, attributed to nobody, with no call to action and no link. The passage always opens.
const ( // NoteOutcomeNone: the link carried no note payload at all. DecodeNote // never returns it — it exists so ShareTarget's zero value is honest. NoteOutcomeNone NoteOutcome = iota // NoteOutcomeOK: a note, decoded, plus every field that was present. NoteOutcomeOK // NoteOutcomeNewer: byte 0 in 'A'-'Z', or an unknown UPPERCASE record tag — // a note written in a newer note format than this build understands. NoteOutcomeNewer // NoteOutcomeDamaged: any framing failure. The one arm that rejects. NoteOutcomeDamaged )
type NoteRef ¶ added in v1.2.8
NoteRef is one tagged citation inside a note: the source's own target id ("JHN.7.50"; a range is "MAT.3.1-MAT.3.12") and the rune span within Footnote.Text that the citation's words occupy ("John 7:50"). A citation the source left untagged — the NKJV's parenthesised "(Acts 10:38)" — has no NoteRef; its words are still in Text.
type NoteVerseRun ¶
type NoteVerseRun struct{ Lo, Hi int }
NoteVerseRun is one contiguous verse run of a note's anchor, inclusive.
type NoteWire ¶
type NoteWire struct {
Text string
Version string // the SENDER's translation id — not the (lossy) link path
Book string // canonical book name
Chapter int
VerseLo int // 0 = no verse run
VerseHi int // 0 or < VerseLo = single verse
Nonce []byte // per-note identity (noteTagNonce); nil emits nothing
}
NoteWire is what the encoder is given. Only Text is required; everything else is emitted when present and meaningful.
type OrphanFootnote ¶
type OrphanFootnote struct {
Verse int `json:"verse"`
Text string `json:"text"`
Kind string `json:"kind,omitempty"`
Caller string `json:"caller,omitempty"`
}
OrphanFootnote is a translators' footnote whose VERSE the translation omits — the critical-text omissions (Luke 17:36, Acts 8:37, 15:34, 24:7, Romans 16:25, plus deuterocanon versification gaps). The verse number exists in the versification but decodes to no text, so the note cannot ride on a Verse; it lives in BibleData.OrphanFootnotes and surfaces ONLY in the chapter-bottom footnote section, keyed by its verse number — the one place a reader can learn WHY that number is absent from the page.
type ShareTarget ¶
type ShareTarget struct {
// VersionID is one of the ids a link path may name (linkPathVersionIDs).
// That is NO LONGER the same as the ids the web reader publishes, and it is
// no longer a promise this reader can open it: /nkjv/ is a real link path and
// a reader without the NKJV cannot be switched to it. Code downstream must
// therefore handle "the link names a translation we do not have" rather than
// assume it away — see applyShareTarget.
// the link carries none or carries one we could not read.
//
// IT IS UNTRUSTED TEXT: anyone can write a link. Render it as TEXT, never as
// markup, and never styled as if BibleText said it — see
// docs/SHARED_NOTES.md → Security.
Note string
// NoteOutcomeNone when the fragment carried no "n" key at all, otherwise
// DecodeNote's verdict. The two failure outcomes are TOLD to the reader in
// the note's place (share_link_open.go) — never silently dropped, never a
// call to action (docs/NOTE_WIRE_FORMAT.md rule 5). The passage opens in
// every case.
NoteOutcome NoteOutcome
// question on arrival: is this the note I sent? (share_note.go,
// noteTagNonce.)
//
// A fixed ARRAY, not a slice, so ShareTarget stays comparable — seven tests
// compare whole targets with ==, and that is a good property to keep for a
// value type describing a parsed link.
//
// The zero value means "no nonce": every link made before this existed, and
// every link whose note this build could not read. An actual all-zero nonce
// from crypto/rand has probability 2^-48, and its only consequence would be
// that one note does not collapse — the safe direction.
NoteNonce [noteNonceLen]byte
// The note's OWN anchor, from the payload's v/b/c/a records — set only on
// NoteOutcomeOK, zero when the record was absent. These are AUTHORITATIVE
// for the NOTE where present: the path is lossy (webc forced for the
// deuterocanon, unknown ids falling back to web), so the wire says what the
// sender was actually reading. They do not navigate — the fragment verse
// span above remains what places the page.
// NoteLo/NoteHi above carry only the first run. A resolution is a set, not
// a span (WEB Mark 9:43-46 lands in the BSB with a hole in it), and the
// store files the whole set (rememberIncomingNote). A string in the
// noteRunsSpelling grammar, not a slice, so ShareTarget stays comparable;
// "" when the record was absent or empty.
NoteRuns string
// What the payload carried that this build could NOT use, preserved so the
// store can keep it and a future forward/re-share can re-emit it
// (docs/NOTE_WIRE_FORMAT.md rule 3). NoteSkipped is DecodedNote.Skipped
// concatenated — each skipped record is self-framing (tag+len+value), so
// the stream splits again — and NoteOpaque is the stop byte and everything
// after it. Strings, not byte slices, so ShareTarget stays comparable.
}
ShareTarget is a passage named by a shared link.
func ParseShareLink ¶
func ParseShareLink(raw string) (ShareTarget, bool)
ParseShareLink parses a BibleText web-reader URL into the passage it names. ok is false for anything that is not one of our reader links — including the landing, privacy and support pages, which must always stay in the browser.
Accepts (all of these appear in the wild):
- the canonical form https://bibletext.co.uk/web/john/3/#v16-18
- no trailing slash https://bibletext.co.uk/web/john/3#v16
- the ?v= alias https://bibletext.co.uk/web/john/3/?v=16-18
- http://, www., and any capitalisation a messenger introduced
type StoredNote ¶
type StoredNote struct {
// ID is this note's identity in the reader's scrapbook, and the ONLY thing
// a verb ever addresses. Minted from a persisted monotonic counter
// (prefNotesNextID) — NOT max(existing)+1, because deletion must never free
// an ID for reuse.
ID uint64
// Kind: "received" | "mine". See NoteKind.
Kind NoteKind
// The anchor. VersionID is the translation the note was written against —
// where it is FILED, not necessarily what is on screen.
VersionID string
Book string
Chapter int
VerseLo int
VerseHi int
// AnchorRuns is the FULL anchor as a run set
// (docs/NOTES_SPEC.md#anchor-and-placement-contract)
// — what the wire's 'a' record carried, when it carried one. A resolution
// is a set, not a span: WEB Mark 9:43-46 lands in the BSB as [43,43] and
// [45,45], which VerseLo/VerseHi cannot say. Empty for a note whose link
// carried no 'a' record; VerseLo/VerseHi always hold the FIRST run, so
// everything already reading them keeps working. Additive ("ar",
// omitempty): a store written before this field serialises byte-identically
// after it.
AnchorRuns []anchorRun
// Text is the message. UNTRUSTED: rendered as text on every surface, never
// as markup.
Text string
// Minimized has ONE meaning: the reader closed this note
// (docs/NOTES_SPEC.md#chapter-plan-and-presentation-state). Written only
// by a reader's press.
Minimized bool
// Received is this device's clock at arrival, unix seconds.
Received int64
// SenderName / SenderID are RESERVED: carried, stored, never shown — as
// SharedNote carried them before this store existed. When a name is shown
// it will be untrusted text with its own display rules.
SenderName string
SenderID string
// WireSkipped / WireOpaque preserve what the link's payload carried that
// the decoding build could not use (share_note.go DecodedNote.Skipped /
// .Opaque): WireSkipped is the unknown records concatenated verbatim
// (each is self-framing tag+len+value, so the stream splits again), and
// WireOpaque is the stop byte and everything after it. Kept so a future
// forward/re-share can re-emit them instead of silently destroying the
// sender's data on its way through us (docs/NOTE_WIRE_FORMAT.md rule 3).
// Nonce is this note's per-share identity, minted when YOU shared it and
// carried in the link (noteTagNonce). It exists for one question: is this
// arriving note the one I sent? Content cannot answer that — a friend may
// write the same words on the same verse — and the wire carries no sender
// identity by design.
Nonce []byte
WireSkipped []byte
WireOpaque []byte
// Extra holds every JSON field of this record that this build does not
// know, verbatim. A newer build's fields pass through an older build's
// read-modify-write untouched. Never inspected, only re-emitted.
Extra map[string]json.RawMessage
}
StoredNote is one record of the scrapbook store.
The anchor is VersionID/Book/Chapter plus a run set: AnchorRuns where the wire carried one, else the VerseLo/VerseHi span. Resolving it into the translation on screen is notes_anchor.go's job (S6), never an inline probe.
func (StoredNote) MarshalJSON ¶
func (n StoredNote) MarshalJSON() ([]byte, error)
MarshalJSON emits the known fields in fixed order, then every Extra key in sorted order — deterministic bytes, so an unchanged store writes unchanged.
func (*StoredNote) UnmarshalJSON ¶
func (n *StoredNote) UnmarshalJSON(data []byte) error
UnmarshalJSON reads the known fields AND keeps every field it does not know in Extra, verbatim. This is spec rule 1 of the long-term foundation: an older build's rewrite must not destroy a newer build's fields.
type Superscription ¶
type Superscription struct {
// Text is the title line, assembled by the same marked-text path verse
// text uses, so its spacing rules are identical.
Text string `json:"text"`
// Footnotes are the title's notes; Anchor is a rune offset into Text
// (stored for a future in-title marker, unrendered today).
Footnotes []Footnote `json:"footnotes,omitempty"`
}
type TextRun ¶
type TextRun struct {
Text string
Red bool
// Italic marks the words the translators supplied. The generated site sets
// them in italic exactly as the app does, because the edition discloses
// them and a reader following a shared link should see the same
// disclosure.
Italic bool
}
TextRun is a stretch of a verse that is uniformly Christ's words or is not — the exported shape of what every reading pane walks to colour a verse.
func RedLetterRuns ¶
RedLetterRuns splits one verse of one translation into its red and not-red stretches, using that translation's OWN span table.
It exists because the web reader was the fifth rendering surface and the only one left behind when per-edition spans landed: it asked IsWordsOfChrist, which answers for the WEB and answers per VERSE. Two things were wrong on the page as a result. Mixed-speaker verses came out entirely red — John 4:9 put the Samaritan woman's words in Christ's colour — and every translation was rendered with the WEB's marks, so BSB and NKJV pages could not preserve their publishers' different editorial decisions.
versionID is the translation being rendered ("web", "bsb", "webc", "nkjv"). An unknown id returns black-letter runs. Red-letter decisions are editorial, so no edition is allowed to inherit another translation's marks.
The returned runs concatenate back to the verse's text exactly, so a caller can escape and emit each in turn without having to reason about offsets.
trimRuns is applied here, not left to the caller, because every pane in the app applies it (reading.go, android_chapter_html.go, reading_mobile_segments.go) and the page must not be the one surface that does not. It trims the verse AS A WHOLE — the old web code called strings.TrimSpace on the verse text, and trimming per run instead would glue "he said" onto the quotation beside it.
type TextSpan ¶ added in v1.2.7
Superscription is a chapter's Hebrew title — "For the choirmaster. According to Gittith. A Psalm of David." — part of the transmitted text of the Psalter (the Masoretic tradition numbers these lines as verse 1; the English versification leaves them unnumbered). Print sets them as an italic, unnumbered line between the psalm number and verse 1, and that is how the reading panes render them. Never in Verse.Text: the search indexes it as a verse-0 hit (SearchSmartLimited) and speech reads it as the read-along's verse-0 row (speechSegments, audio.go); share, copy and links still omit it, each its own decision (docs/SOURCE_FIELDS_DECISIONS.md). Its notes (the "Gittith is probably a musical term" glosses) join the chapter-bottom footnote section keyed "Title", ahead of the verse-keyed notes, under the same toggle. Heading is one of the publisher's section headings — "The Beatitudes", "The LORD Is My Shepherd", the speaker labels in the Song of Songs — or one of the other non-Scripture blocks an edition sets between verses: a major section head, a parallel-passage reference line, an acrostic letter.
It is editorial matter, added by the translators rather than translated, and it is kept apart from the text for that reason. Style is the publisher's own name for what this block is, so a surface can tell a section heading from an acrostic letter without guessing from the words. TextSpan is a half-open range of runes inside a verse's text: [Start, End). It is how the app records something TRUE OF PART OF A VERSE without putting anything into the verse itself — the words the translators supplied, today, and whatever else a publisher marks tomorrow.
type Verse ¶
type Verse struct {
BookName string // Name of the book (e.g., "John", "Genesis")
Book string // Abbreviated book name/reference
Chapter int // Chapter number within the book
Verse int // Verse number within the chapter
Text string // The actual text of the verse
Search string `json:"-"` // Lowercased text for fast case-insensitive search
Ref string `json:"-"` // Lowercased "book c:v" for fast reference matching
// Footnotes is the translators' apparatus for this verse — alternate
// renderings, manuscript variants, cross-references — captured at decode
// time and carried SIDE-BAND, in the red-letter-runs mould. It is data,
// not display: nothing here is rendered anywhere yet, and nothing here
// may ever enter Text, the search index, the share pipeline, spoken
// audio, or a link. Those pipelines all read Text, which stays
// byte-identical whether footnotes are captured or not — the purity the
// project's Revelation 22:18-19 standard requires, enforced by construction
// and pinned by tests (footnotes_test.go). See docs/FOOTNOTES.md.
Footnotes []Footnote `json:"footnotes,omitempty"`
// ParaStart marks a verse that OPENS A PARAGRAPH in the publisher's own
// setting of the text. Paragraphing is the translators' work, not
// typesetting: it says where a speaker changes, a scene turns, or an
// argument moves on, and committees decide it verse by verse. All three
// editions carry it — the helloao feeds as chapter-level break nodes, the
// API.Bible feed as paragraph blocks — and the app used to discard every
// one of them and manufacture its own paragraphs from a character count,
// which produced the same shape for three different translations and cut
// the Nicodemus dialogue in the middle of a reply.
//
// It is structure, never text: Text stays byte-identical whether this is
// set or not, so search, share, speech and links are untouched. The one
// consumer is groupVersesIntoParagraphs, which every surface funnels
// through, so setting this here reaches all of them at once.
ParaStart bool `json:"para_start,omitempty"`
// Supplied marks the words the TRANSLATORS SUPPLIED — what the King James
// tradition sets in italics, added for English sense and standing in no
// Hebrew or Greek word of the original. It is the edition's own disclosure
// of where a translator made a judgement, and the app used to flatten it
// away: roughly three thousand spans in the New Testament alone.
//
// Offsets into Text, never characters inside it, so the text a reader
// searches, shares, copies, hears and links to is unchanged whether this
// is set or not.
Supplied []TextSpan `json:"supplied,omitempty"`
// SmallCaps marks the words the edition sets in SMALL CAPITALS — above all
// the divine name, where "Lord" in small capitals renders the Tetragrammaton
// and "Lord" in ordinary case renders Adonai. The distinction is the
// edition's, it is carried entirely by the letterforms, and the app used to
// realise it by uppercasing the letters into the stored text, so a reader
// who copied a verse received a spelling no edition prints.
//
// The publisher's own characters are kept instead, and this says where the
// feature applies. The feed sends the span two ways — "Lord" with the
// remainder in lower case, and a capital outside the span with the
// remainder inside it as in "G" + "OD" — so a renderer asks for smcp and
// c2sc together and the face resolves both correctly.
//
// Offsets into Text, never characters inside it.
SmallCaps []TextSpan `json:"small_caps,omitempty"`
// PoemLevels is the indent depth of each LINE of this verse, in order:
// one entry per line of Text, zero where a line is not poetry. Hebrew
// poetry is built of paired lines, and print sets the second half of a
// pair indented under the first so the pairing can be seen; every edition
// marks the depth and the app used to keep only the fact that a line was
// poetry at all, so every line drew flush left.
//
// Lines, not characters: Text is unchanged whether this is set or not.
PoemLevels []int `json:"poem_levels,omitempty"`
}
Verse represents a single verse (sentence/passage) from the Bible This is the smallest unit of text in our application
type VerseRef ¶
VerseRef identifies a single verse. It is the anchor for annotations and the unit used when citing or copying for research.
type VerseSpan ¶
type VerseSpan struct {
VersionID string
Book string
Chapter int
Lo int // first verse; 0 means the span is chapter-level
Hi int // inclusive last verse; 0 or < Lo means a single verse
}
VerseSpan is a location AND the numbering it is expressed in.
VersionID is not decoration and not optional. The whole reason a note can be shown under a translation it is not stored under is that MapVerse renumbers it; a span that does not say which translation numbers it that way cannot be renumbered later, and cannot be checked against the translation on screen.
type WebReaderPalette ¶
type WebReaderPalette struct {
Background color.NRGBA
Surface color.NRGBA
Text color.NRGBA
TextMuted color.NRGBA
Accent color.NRGBA
Border color.NRGBA
VerseNumber color.NRGBA
RedLetter color.NRGBA
Highlight color.NRGBA
ControlHover color.NRGBA
ControlSelection color.NRGBA
}
WebReaderPalette is the subset of the app palette used by the static reader. Its translucent control colours reuse the Fyne theme's hover and selection tints, while the separate opaque highlight remains reserved for scripture.
func WebReaderPalettes ¶
func WebReaderPalettes() (light, dark WebReaderPalette)
WebReaderPalettes returns the light and dark static-reader palettes. Keeping this seam beside the decoder and tint exports lets cmd/websitegen derive its CSS from the app palette instead of maintaining another set of colour values.
Source Files
¶
- ai.go
- ai_answer_markdown.go
- ai_ask.go
- ai_faster_model.go
- ai_keystore.go
- ai_menu_sync_other.go
- ai_model_resolve.go
- ai_panel.go
- ai_providers.go
- ai_search.go
- ai_secure_store_blob.go
- ai_secure_store_other.go
- ai_settings.go
- android_chapter_html.go
- annotation.go
- apibible.go
- apibible_styles.go
- app.go
- audio.go
- audio_artwork.go
- audio_button.go
- audio_controller.go
- audio_menu.go
- audio_other.go
- audio_resample.go
- audio_supported_other.go
- bible.go
- bible_key_bundled.go
- bible_key_settings.go
- books_grid.go
- bookslugs.go
- bsb.go
- bsb_audio.go
- cache.go
- cache_path_other.go
- catholic.go
- chapter_blocks.go
- copy_text.go
- crossref_list.go
- crossref_panel.go
- crossrefs.go
- debug_capture_off.go
- dev_autoopen_off.go
- dev_links_off.go
- dev_mimic_off.go
- dev_phone_landscape_off.go
- device_other.go
- external_link.go
- external_link_other.go
- fetch_bible_data.go
- fetch_stall.go
- font.go
- fonts_embed.go
- footnote_section.go
- goto.go
- helloao_census.go
- helloao_checks.go
- history.go
- icons_embed.go
- layout.go
- mark.go
- note_entry_other.go
- notes_action.go
- notes_anchor.go
- notes_arrival.go
- notes_banner.go
- notes_browse.go
- notes_bubble.go
- notes_byline.go
- notes_chrome.go
- notes_mine.go
- notes_model.go
- notes_offer.go
- notes_plan.go
- notes_refresh.go
- notes_refresh_other.go
- notes_setting.go
- notes_sticker_native_off.go
- notes_store.go
- omitted_verses.go
- omitted_verses_data.go
- outbound_text.go
- overlay_recovery_other.go
- paragraph_web.go
- paragraph_web_data.go
- parallels.go
- phone_landscape.go
- product.go
- publisher_xrefs.go
- readable_column.go
- readalong.go
- readalong_other.go
- reading.go
- reading_face_scale.go
- reading_fonts_embed.go
- reading_fullscreen_row.go
- reading_fyne.go
- reading_mobile_segments.go
- reading_scroll_fyne.go
- reading_state.go
- reading_styled_area.go
- reading_styled_footnotes.go
- reading_styled_layout.go
- reading_styled_note.go
- reading_styled_pane.go
- reading_styled_platform_on.go
- reading_styled_readalong.go
- reading_styled_select.go
- reading_styled_super.go
- reading_tint_runs.go
- red_letter.go
- red_letter_bsb.go
- red_letter_bsb_data.go
- red_letter_data.go
- red_letter_nkjv_data.go
- red_letter_runs.go
- red_letter_web_data.go
- reporter_other.go
- search.go
- seed.go
- selection_span.go
- share.go
- share_fallback.go
- share_image.go
- share_link.go
- share_link_browser_other.go
- share_link_open.go
- share_link_parse.go
- share_link_unavailable.go
- share_note.go
- share_note_canon.go
- share_note_ui.go
- share_other.go
- share_preview.go
- sheet_consume_other.go
- sheet_fit.go
- sidebar.go
- small_caps.go
- small_caps_draw.go
- state.go
- support_contact.go
- tab_rail.go
- textsize.go
- theme.go
- timezone.go
- timezone_other.go
- tint.go
- ui.go
- ui_compact.go
- ui_compact_desktop.go
- ui_desktop.go
- verse_count.go
- verse_gaps.go
- verse_of_day.go
- versification.go
- versification_data.go
- versions.go
- versions_ui.go
- web_api.go
- web_fonts.go
- webbe_audio.go
Directories
¶
| Path | Synopsis |
|---|---|
|
cmd
|
|
|
desktop
command
Command desktop is the macOS / Windows / Linux entry point for the BibleText reader.
|
Command desktop is the macOS / Windows / Linux entry point for the BibleText reader. |
|
mobile
command
Command mobile is the iOS (and Android) entry point for the BibleText reader.
|
Command mobile is the iOS (and Android) entry point for the BibleText reader. |
|
sitepages
command
Command sitepages renders the hand-written root pages that are published alongside the generated web reader.
|
Command sitepages renders the hand-written root pages that are published alongside the generated web reader. |
|
websitegen
command
Command websitegen builds the static web reader published at bibletext.co.uk — the destination of the app's "Share as link".
|
Command websitegen builds the static web reader published at bibletext.co.uk — the destination of the app's "Share as link". |



