difi/internal/tree/builder.go
2026-01-30 22:38:34 -05:00

127 lines
2.4 KiB
Go

package tree
import (
"fmt"
"path/filepath"
"sort"
"strings"
"github.com/charmbracelet/bubbles/list"
)
// TreeItem represents a file or folder
type TreeItem struct {
Path string
FullPath string
IsDir bool
Depth int
}
func (i TreeItem) FilterValue() string { return i.FullPath }
func (i TreeItem) Description() string { return "" }
func (i TreeItem) Title() string {
indent := strings.Repeat(" ", i.Depth)
icon := getIcon(i.Path, i.IsDir)
return fmt.Sprintf("%s%s %s", indent, icon, i.Path)
}
func Build(paths []string) []list.Item {
root := &node{
children: make(map[string]*node),
isDir: true,
}
for _, path := range paths {
parts := strings.Split(path, "/")
current := root
for i, part := range parts {
if _, exists := current.children[part]; !exists {
isDir := i < len(parts)-1
fullPath := strings.Join(parts[:i+1], "/")
current.children[part] = &node{
name: part,
fullPath: fullPath,
children: make(map[string]*node),
isDir: isDir,
}
}
current = current.children[part]
}
}
var items []list.Item
flatten(root, 0, &items)
return items
}
type node struct {
name string
fullPath string
children map[string]*node
isDir bool
}
// flatten recursively converts the tree into a linear list, sorting children by type and name.
func flatten(n *node, depth int, items *[]list.Item) {
keys := make([]string, 0, len(n.children))
for k := range n.children {
keys = append(keys, k)
}
sort.Slice(keys, func(i, j int) bool {
a, b := n.children[keys[i]], n.children[keys[j]]
if a.isDir && !b.isDir {
return true
}
if !a.isDir && b.isDir {
return false
}
return a.name < b.name
})
for _, k := range keys {
child := n.children[k]
*items = append(*items, TreeItem{
Path: child.name,
FullPath: child.fullPath,
IsDir: child.isDir,
Depth: depth,
})
if child.isDir {
flatten(child, depth+1, items)
}
}
}
func getIcon(name string, isDir bool) string {
if isDir {
return " "
}
ext := filepath.Ext(name)
switch strings.ToLower(ext) {
case ".go":
return " "
case ".js", ".ts", ".tsx":
return " "
case ".svelte":
return " "
case ".md":
return " "
case ".json":
return " "
case ".yml", ".yaml":
return " "
case ".html":
return " "
case ".css":
return " "
case ".git":
return " "
case ".dockerfile":
return " "
default:
return " "
}
}