119 lines
2.2 KiB
Go
119 lines
2.2 KiB
Go
package tree
|
|
|
|
import (
|
|
"fmt"
|
|
"path/filepath"
|
|
"sort"
|
|
"strings"
|
|
|
|
"github.com/charmbracelet/bubbles/list"
|
|
)
|
|
|
|
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)}
|
|
|
|
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
|
|
}
|
|
|
|
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":
|
|
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 ""
|
|
}
|
|
}
|