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] }