你有没有遇到过这种场景:打开一个不熟悉的项目,想快速了解目录结构,却要在 IDE 里一层层展开文件夹?tree 命令可以解决问题,但 Windows 默认不带,Linux 也要单独安装。
今天我们用 OpenCode,用三句自然语言描述,3 分钟写出一个跨平台目录树可视化工具。
用 Go 语言实现一个命令行目录树工具,支持三个核心功能:
├── 和 └── 绘制目录层级-L 2 限制最大递归深度-d 只显示目录,-a 显示隐藏文件最终代码约 100 行,无任何第三方依赖。
npm install -g @anthropic/opencode(或用 pip install opencode)opencode 启动交互会话我直接对 OpenCode 描述需求,让它生成代码骨架:
> 我对 OpenCode 说:
> 用 Go 写一个命令行工具,读取指定目录(默认当前目录),递归遍历所有子目录和文件,用树形结构打印出来。只打印文件名,不打印完整路径。
OpenCode 几秒钟就生成了核心逻辑——用 os.ReadDir 读取目录,递归调用自身,用 ├── 和 └── 做连接符,并根据是否是最后一个条目决定缩进前缀(│ 还是空格)。
func printTree(path string, prefix string, maxDepth int, depth int, dirsOnly bool, showHidden bool) {
if maxDepth >= 0 && depth > maxDepth {
return
}
entries, _ := os.ReadDir(path)
// 排序、过滤、打印...
}
骨架跑通后,我对 OpenCode 说:
> 我对 OpenCode 说:
> 加上命令行参数:-L 控制最大深度(默认 -1 表示不限制),-d 只显示目录不显示文件,-a 显示隐藏文件(以 . 开头的文件和目录)。
OpenCode 用 Go 标准库的 flag 包解析参数,在遍历时增加对应的过滤逻辑——dirsOnly 跳过非目录项,showHidden 控制 . 开头文件的可见性。
func main() {
maxDepth := flag.Int("L", -1, "最大深度,-1 表示不限制")
dirsOnly := flag.Bool("d", false, "只显示目录")
showHidden := flag.Bool("a", false, "显示隐藏文件")
flag.Parse()
// ...
}
基础功能完成后,我发现缺少统计信息,于是对 OpenCode 说:
> 我对 OpenCode 说:
> 遍历结束后在最后一行打印统计信息:显示了多少个目录、多少个文件,格式为 N directories, M files。
OpenCode 在主函数里增加了两个计数器,递归遍历时分别统计目录和文件数量,最后用 fmt.Printf 输出汇总行。
整个过程我没有手写一行代码,全靠自然语言描述。从说出需求到可运行的工具,前后不到 3 分钟。
package main
import (
"flag"
"fmt"
"os"
"path/filepath"
"sort"
)
var (
dirCount int
fileCount int
)
func main() {
maxDepth := flag.Int("L", -1, "最大深度,-1 表示不限制")
dirsOnly := flag.Bool("d", false, "只显示目录")
showHidden := flag.Bool("a", false, "显示隐藏文件")
flag.Parse()
root := "."
if flag.NArg() > 0 {
root = flag.Arg(0)
}
fmt.Println(root)
printTree(root, "", *maxDepth, 0, *dirsOnly, *showHidden)
fmt.Printf("\n%d directories, %d files\n", dirCount, fileCount)
}
func printTree(path string, prefix string, maxDepth int, depth int, dirsOnly bool, showHidden bool) {
if maxDepth >= 0 && depth > maxDepth {
return
}
entries, err := os.ReadDir(path)
if err != nil {
return
}
sort.Slice(entries, func(i, j int) bool {
return entries[i].Name() < entries[j].Name()
})
var filtered []os.DirEntry
for _, e := range entries {
if !showHidden && e.Name()[0] == '.' {
continue
}
if dirsOnly && !e.IsDir() {
continue
}
filtered = append(filtered, e)
}
for i, entry := range filtered {
isLast := i == len(filtered)-1
isDir := entry.IsDir()
if isDir {
dirCount++
} else {
fileCount++
}
connector := "├── "
if isLast {
connector = "└── "
}
fmt.Printf("%s%s%s\n", prefix, connector, entry.Name())
if isDir {
newPrefix := prefix
if isLast {
newPrefix += " "
} else {
newPrefix += "│ "
}
printTree(filepath.Join(path, entry.Name()), newPrefix, maxDepth, depth+1, dirsOnly, showHidden)
}
}
}
运行效果:
$ go run main.go -L 2 -d myproject/
myproject/
├── cmd
│ └── server
├── internal
│ ├── config
│ └── handler
└── pkg
└── utils
5 directories, 0 files
这个小工具的开发过程展示了 OpenCode 的核心价值:用自然语言驱动开发,让 AI 处理代码细节,人的精力聚焦在需求描述和结果验证上。
传统方式写这个工具,你需要回忆 os.ReadDir 的返回值类型、查 sort.Slice 的用法、调试缩进前缀的拼接逻辑——这些细节至少花 15-20 分钟。用 OpenCode,你只需清晰描述想要什么,3 分钟内就能拿到可运行的代码。
更有意思的是迭代过程:你觉得缺点什么,说一句话,OpenCode 就帮你改好。这种"对话式编程"的体验,比传统"打字—编译—报错—修改"的循环高效太多了。
如果你还没试过 OpenCode,不妨从这个小工具开始——相信我,一旦习惯了用嘴编程,你就回不去了。