114 lines
2.5 KiB
Go
114 lines
2.5 KiB
Go
package filepicker
|
|
|
|
import (
|
|
"git.mlow.ca/mlow/lmcli/pkg/util/dirtree"
|
|
tea "github.com/charmbracelet/bubbletea"
|
|
"github.com/charmbracelet/lipgloss"
|
|
)
|
|
|
|
type Model struct {
|
|
tree *dirtree.Tree
|
|
cursor int
|
|
displayNodes []*dirtree.Node // Flattened view of visible nodes
|
|
}
|
|
|
|
func New(path string) Model {
|
|
m := Model{
|
|
tree: dirtree.NewTree(path),
|
|
}
|
|
|
|
m.tree.Root.LoadChildren(false, 0, nil)
|
|
m.updateRenderTree()
|
|
return m
|
|
}
|
|
|
|
func (m *Model) updateRenderTree() {
|
|
m.displayNodes = dirtree.FlattenTree(m.tree.Root, false)
|
|
}
|
|
|
|
func (m Model) Update(msg tea.Msg) (Model, tea.Cmd) {
|
|
switch msg := msg.(type) {
|
|
case tea.KeyMsg:
|
|
switch msg.String() {
|
|
case "j":
|
|
if m.cursor < len(m.displayNodes)-1 {
|
|
m.cursor++
|
|
}
|
|
case "k":
|
|
if m.cursor > 0 {
|
|
m.cursor--
|
|
}
|
|
case "l", "right":
|
|
current := m.displayNodes[m.cursor]
|
|
if current.IsDir() {
|
|
current.Expanded = true
|
|
current.LoadChildren(false, 0, nil)
|
|
m.updateRenderTree()
|
|
}
|
|
case "h", "left":
|
|
current := m.displayNodes[m.cursor]
|
|
if current.IsDir() && current.Expanded {
|
|
current.Expanded = false
|
|
m.updateRenderTree()
|
|
} else {
|
|
// Find and collapse parent
|
|
if !current.IsRoot() {
|
|
current.Parent().Expanded = false
|
|
m.updateRenderTree()
|
|
// Move cursor to parent
|
|
for i, node := range m.displayNodes {
|
|
if node == current.Parent() {
|
|
m.cursor = i
|
|
break
|
|
}
|
|
}
|
|
}
|
|
}
|
|
case " ":
|
|
current := m.displayNodes[m.cursor]
|
|
if current.IsSelected() {
|
|
current.Deselect(true)
|
|
} else {
|
|
current.Select(true, 0)
|
|
}
|
|
m.updateRenderTree()
|
|
case "H":
|
|
m.tree.ShowHidden = !m.tree.ShowHidden
|
|
m.tree.Root.LoadChildren(false, 0, nil)
|
|
}
|
|
}
|
|
return m, nil
|
|
}
|
|
|
|
func (m Model) Init() tea.Cmd {
|
|
return nil
|
|
}
|
|
|
|
func (m Model) View() string {
|
|
// Define styles
|
|
dirStyle := lipgloss.NewStyle().Bold(true).Foreground(lipgloss.Color("12")) // Blue for directories
|
|
fileStyle := lipgloss.NewStyle().Foreground(lipgloss.Color("7")) // White for files
|
|
selectedStyle := lipgloss.NewStyle().Bold(true)
|
|
|
|
renderNode := func(node *dirtree.Node) string {
|
|
var nodeName string
|
|
if node.IsDir() {
|
|
caret := "▶ "
|
|
if node.Expanded {
|
|
caret = "▼ "
|
|
}
|
|
nodeName = caret + node.Name + "/"
|
|
nodeName = dirStyle.Render(nodeName)
|
|
} else {
|
|
nodeName = fileStyle.Render(node.Name)
|
|
}
|
|
|
|
if node.IsSelected() {
|
|
nodeName = selectedStyle.Render(nodeName)
|
|
}
|
|
return nodeName
|
|
}
|
|
|
|
return dirtree.RenderNodes(m.displayNodes, dirtree.Compact, m.cursor, renderNode)
|
|
}
|