1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
|
package bible
import (
"os"
"path/filepath"
"sort"
"strings"
"sync"
)
var (
regMu sync.Mutex
userDir string
regBuilt bool
regMeta map[string]CorpusMeta // code -> meta (user overrides embed)
regUserTSV map[string]string // code -> user .tsv path (override source)
)
// SetUserCorporaDir sets the drop-in dir and invalidates the registry cache.
// Empty string disables user corpora (used by tests).
func SetUserCorporaDir(dir string) {
regMu.Lock()
userDir = dir
regBuilt = false
regMu.Unlock()
corporaMu.Lock()
corpora = map[string]*corpus{} // drop cached loads so overrides take effect
corporaMu.Unlock()
}
func buildRegistry() {
if regBuilt {
return
}
regMeta = map[string]CorpusMeta{}
regUserTSV = map[string]string{}
// embedded first (core FS = vul always; optional FS = rest under -tags fullbible)
for _, name := range embCorpusFiles() {
if code, ok := strings.CutSuffix(name, ".ini"); ok {
if m, ok := embeddedCorpusMeta(code); ok {
regMeta[code] = m
}
}
}
// user dir overrides
if userDir != "" {
ents, _ := os.ReadDir(userDir)
for _, e := range ents {
name := e.Name()
if code, ok := strings.CutSuffix(name, ".tsv"); ok {
regUserTSV[code] = filepath.Join(userDir, name)
if _, have := regMeta[code]; !have {
regMeta[code] = CorpusMeta{Code: code, PsalmSystem: "vulgate", Autoselect: true}
}
}
}
for _, e := range ents {
if code, ok := strings.CutSuffix(e.Name(), ".ini"); ok {
data, err := os.ReadFile(filepath.Join(userDir, e.Name()))
if err == nil {
regMeta[code] = parseCorpusMeta(code, data)
}
}
}
}
regBuilt = true
}
// Corpora returns all known corpora, sorted by code.
func Corpora() []CorpusMeta {
regMu.Lock()
defer regMu.Unlock()
buildRegistry()
out := make([]CorpusMeta, 0, len(regMeta))
for _, m := range regMeta {
out = append(out, m)
}
sort.Slice(out, func(i, j int) bool { return out[i].Code < out[j].Code })
return out
}
// Meta returns a corpus's metadata.
func Meta(code string) (CorpusMeta, bool) {
regMu.Lock()
defer regMu.Unlock()
buildRegistry()
m, ok := regMeta[code]
return m, ok
}
// CorporaForLang returns corpora whose lang == lang, sorted by code.
func CorporaForLang(lang string) []CorpusMeta {
var out []CorpusMeta
for _, m := range Corpora() {
if m.Lang == lang {
out = append(out, m)
}
}
return out
}
// userTSVPath returns the override .tsv path for code, or "".
func userTSVPath(code string) string {
regMu.Lock()
defer regMu.Unlock()
buildRegistry()
return regUserTSV[code]
}
|