package tree import ( "fmt" "os" "path/filepath" "strings" "cliprepo/internal/gitignore" "github.com/atotto/clipboard" ) // Generate 从 root 目录开始遍历文件树,并生成类似 `tree` 命令的目录结构字符串 // // 功能特点: // 1. 递归遍历目录 // 2. 支持 .gitignore 规则过滤 // 3. 输出树形结构字符串 func Generate(root string) (string, error) { // 加载 gitignore 规则(如果失败则忽略错误,默认不过滤) ig, _ := gitignore.Load(root) var builder strings.Builder // 递归遍历目录结构 err := filepath.Walk(root, func(path string, info os.FileInfo, err error) error { if err != nil { return err } // 根目录特殊处理,统一显示为 "." if path == root { builder.WriteString(".\n") return nil } // 转换为相对路径,便于匹配 gitignore 和计算层级 rel, _ := filepath.Rel(root, path) // 如果路径匹配 gitignore 规则,则跳过 // 如果是目录,则直接跳过整个子树 if ig.MatchesPath(rel) { if info.IsDir() { return filepath.SkipDir } return nil } // 计算当前节点在目录树中的层级 // 通过路径分隔符数量判断深度 level := strings.Count(rel, string(os.PathSeparator)) // 根据层级生成缩进 prefix := strings.Repeat("│ ", level) // 写入当前节点(文件或目录) builder.WriteString(fmt.Sprintf("%s├── %s\n", prefix, info.Name())) return nil }) return builder.String(), err } // Copy 将生成的字符串写入系统剪贴板 // // 常用于 CLI 工具:直接复制 tree 输出结果 func Copy(content string) error { return clipboard.WriteAll(content) } // Write 将内容写入指定文件路径 // // 如果文件存在则覆盖 // 权限默认设置为 0644(rw-r--r--) func Write(path, content string) error { return os.WriteFile(path, []byte(content), 0644) }