Add pkg/util/dirtree
Update dir_tree tool to use it Update filepicker bubble to use it
This commit is contained in:
113
pkg/tui/bubbles/filepicker/filepicker.go
Normal file
113
pkg/tui/bubbles/filepicker/filepicker.go
Normal file
@@ -0,0 +1,113 @@
|
||||
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)
|
||||
}
|
||||
Reference in New Issue
Block a user