package internal import ( "fmt" "os" "path/filepath" "strings" "gopkg.in/yaml.v3" ) // Config YAML 配置结构(嵌套:分组 → 工作空间) type Config struct { Groups []GroupConfig `yaml:"groups"` } type GroupConfig struct { Label string `yaml:"label"` Desc string `yaml:"desc"` Base int `yaml:"base"` Items []WorkspaceConfig `yaml:"items"` } type WorkspaceConfig struct { Title string `yaml:"title"` Prompt string `yaml:"prompt"` Tech string `yaml:"tech"` Deploy string `yaml:"deploy"` Dir string `yaml:"dir"` } // LoadConfig 加载配置文件 // 优先级: ~/.u-tabs/config.yaml > exe同目录/config.yaml func LoadConfig() (*Config, error) { // 1. 尝试用户目录 userDir, err := os.UserHomeDir() if err == nil { userCfg := filepath.Join(userDir, ".u-tabs", "config.yaml") if cfg, err := loadConfigFile(userCfg); err == nil { return cfg, nil } } // 2. 尝试 exe 同目录 exePath, err := os.Executable() if err == nil { exeDir := filepath.Dir(exePath) exeCfg := filepath.Join(exeDir, "config.yaml") if cfg, err := loadConfigFile(exeCfg); err == nil { return cfg, nil } } return nil, fmt.Errorf("未找到配置文件") } func loadConfigFile(path string) (*Config, error) { data, err := os.ReadFile(path) if err != nil { return nil, err } var cfg Config if err := yaml.Unmarshal(data, &cfg); err != nil { return nil, err } return &cfg, nil } // ToInternal 将 YAML 配置转换为内部数据结构 // 自动生成: index(全局索引), n(编号=base+序号), group(继承父级) func (c *Config) ToInternal() ([]Group, []Workspace) { groups := make([]Group, len(c.Groups)) var allWorkspaces []Workspace globalIdx := 0 for gi, g := range c.Groups { groups[gi] = Group{Label: g.Label, Desc: g.Desc} for wi, w := range g.Items { allWorkspaces = append(allWorkspaces, Workspace{ Index: globalIdx, N: g.Base + wi, Title: w.Title, Prompt: w.Prompt, Tech: w.Tech, Deploy: w.Deploy, Dir: expandHome(w.Dir), Group: g.Label, }) globalIdx++ } } return groups, allWorkspaces } // expandHome 将 ~ 展开为用户主目录 func expandHome(dir string) string { if strings.HasPrefix(dir, "~") { home, _ := os.UserHomeDir() return strings.Replace(dir, "~", home, 1) } return dir }