package config import ( "os" "reflect" "regexp" "strings" "gitea.meta-tech.academy/go/core/style" "gopkg.in/yaml.v3" ) type Cfg interface { GetVar() []VarConfig GetStylesDef() []string SetStyles(*style.Styles) } type VarConfig struct { Name string `yaml:"name"` Value string `yaml:"value"` } type ConfigLoader struct { Var []VarConfig Config interface{} varDef *VarPattern refstr []*reflect.Value } func LoadConfig(path string, out Cfg, varPattern *VarPattern) { cl := &ConfigLoader{varDef: varPattern, refstr: []*reflect.Value{}} data, err := os.ReadFile(path) if err != nil { panic(err) } if err = yaml.Unmarshal(data, out); err != nil { panic(err) } cl.Var = out.GetVar() cl.Config = out cl.parse() cl.refstr = []*reflect.Value{} cl.buildStyles(out) } func (cl *ConfigLoader) buildStyles(out Cfg) { styles := style.NewStyles() for _, def := range out.GetStylesDef() { s := style.NewStyleByDef(def) styles.List[s.Name] = s } out.SetStyles(styles) } func (cl *ConfigLoader) findVarName(match string) string { re := regexp.MustCompile(cl.varDef.getPatternCaptureName()) parts := re.FindStringSubmatch(match) if len(parts) > 0 { match = parts[1] } return match } func (cl *ConfigLoader) findVarValue(v string) string { names := strings.SplitN(v, ".", 2) if names[0] == "var" { for _, varConfig := range cl.Var { if varConfig.Name == names[1] { v = varConfig.Value } } } return v } func (cl *ConfigLoader) findStringRef(ref reflect.Value) { switch ref.Kind() { case reflect.Ptr, reflect.Interface: cl.findStringRef(ref.Elem()) case reflect.Struct: for i := 0; i < ref.NumField(); i++ { refc := ref.Field(i) cl.findStringRef(refc) } case reflect.Slice: if !ref.IsNil() { for i := 0; i < ref.Len(); i++ { refc := ref.Index(i) cl.findStringRef(refc) } } case reflect.String: if ref.Len() > 0 { cl.refstr = append(cl.refstr, &ref) } } } func (cl *ConfigLoader) parse() { var name string var tmp string var parts []string var re2 *regexp.Regexp cl.findStringRef(reflect.ValueOf(&cl)) re := regexp.MustCompile(cl.varDef.getPatternVar()) for _, ref := range cl.refstr { tmp = ref.String() parts = re.FindStringSubmatch(tmp) if len(parts) > 0 { s := strings.SplitAfter(parts[1], cl.varDef.Close) for _, part := range s { name = cl.findVarName(part) re2 = regexp.MustCompile(cl.varDef.getPatternVarName(name)) tmp = re2.ReplaceAllString(tmp, cl.findVarValue(name)) } ref.SetString(tmp) } } }