internal/formatter.go (view raw)
1package bible
2
3import (
4 "fmt"
5 "strings"
6)
7
8// Formatter handles formatting Bible text for display
9type Formatter struct {
10 useColours bool
11 headerFormat string
12}
13
14// NewFormatter creates a new formatter with default settings
15func NewFormatter() *Formatter {
16 return &Formatter{
17 useColours: true,
18 headerFormat: "{book} {chapter}\nw. {first_verse}-{second_verse}",
19 }
20}
21
22// NewFormatterWithConfig creates a new formatter with configuration
23func NewFormatterWithConfig(useColours bool, headerFormat string) *Formatter {
24 return &Formatter{
25 useColours: useColours,
26 headerFormat: headerFormat,
27 }
28}
29
30// FormatHeader formats the header for a bookmark using the configured template
31func (f *Formatter) FormatHeader(bookmark *Bookmark) string {
32 template := f.headerFormat
33 if template == "" {
34 // Fall back to default template
35 template = "{book} {chapter}\nw. {first_verse}-{second_verse}"
36 }
37
38 // Replace template variables
39 result := template
40 result = strings.ReplaceAll(result, "{book}", bookmark.Book.String())
41 result = strings.ReplaceAll(result, "{chapter}", fmt.Sprintf("%d", bookmark.Chapter))
42 result = strings.ReplaceAll(result, "{first_verse}", fmt.Sprintf("%d", bookmark.FirstVerse))
43 result = strings.ReplaceAll(result, "{second_verse}", fmt.Sprintf("%d", bookmark.SecondVerse))
44
45 if !f.useColours {
46 return result
47 }
48
49 // Add ANSI colours - simple implementation
50 // For more advanced templating, we'd need a proper template engine
51 const (
52 reset = "\033[0m"
53 green = "\033[32m"
54 yellow = "\033[33m"
55 )
56
57 // Simple colouring - book and chapter in green, verse range in yellow
58 lines := strings.Split(result, "\n")
59 if len(lines) >= 1 {
60 lines[0] = green + lines[0] + reset
61 }
62 if len(lines) >= 2 {
63 lines[1] = yellow + lines[1] + reset
64 }
65 result = strings.Join(lines, "\n")
66
67 return result
68}
69
70// FormatHeaderWithTemplate is deprecated - use FormatHeader instead
71func (f *Formatter) FormatHeaderWithTemplate(bookmark *Bookmark) string {
72 return f.FormatHeader(bookmark)
73}
74
75// FormatSnippet formats the verse range text
76func (f *Formatter) FormatSnippet(verses []*Verse) string {
77 if len(verses) == 0 {
78 return "Error: No text matched"
79 }
80
81 var sb strings.Builder
82 for i, verse := range verses {
83 if i > 0 {
84 sb.WriteString(" ")
85 }
86 // Remove any leading pilcrow (¶) and trim
87 text := strings.TrimSpace(verse.Text)
88 if strings.HasPrefix(text, "¶ ") {
89 text = text[2:]
90 } else if strings.HasPrefix(text, "¶") {
91 text = text[1:]
92 }
93 sb.WriteString(text)
94 }
95
96 return sb.String()
97}
98
99// ExtractAndFormat extracts verses for a bookmark and formats them
100func (f *Formatter) ExtractAndFormat(bible *Bible, bookmark *Bookmark) string {
101 verses := bible.GetVerseRange(int(bookmark.Book), bookmark.Chapter,
102 bookmark.FirstVerse, bookmark.SecondVerse)
103 return f.FormatSnippet(verses)
104}
105
106// ExtractAndFormatWithHeader extracts verses and formats with header
107func (f *Formatter) ExtractAndFormatWithHeader(bible *Bible, bookmark *Bookmark) string {
108 header := f.FormatHeader(bookmark)
109 content := f.ExtractAndFormat(bible, bookmark)
110 return header + "\n" + content
111}