|
|
|
|
@ -31,8 +31,9 @@ type model struct {
|
|
|
|
|
|
|
|
|
|
leftWidth int
|
|
|
|
|
|
|
|
|
|
treeRoot *TreeNode
|
|
|
|
|
textarea textarea.Model
|
|
|
|
|
treeRoot *TreeNode
|
|
|
|
|
treeCursor int
|
|
|
|
|
textarea textarea.Model
|
|
|
|
|
|
|
|
|
|
commands []Command
|
|
|
|
|
viewport viewport.Model
|
|
|
|
|
@ -71,8 +72,10 @@ func main() {
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func flattenTree(n *TreeNode, depth int) []string {
|
|
|
|
|
var out []string
|
|
|
|
|
// returns both the string representation and corresponding nodes
|
|
|
|
|
func flattenTreeWithNodes(n *TreeNode, depth int) ([]string, []*TreeNode) {
|
|
|
|
|
var lines []string
|
|
|
|
|
var nodes []*TreeNode
|
|
|
|
|
prefix := strings.Repeat(" ", depth)
|
|
|
|
|
icon := "▸"
|
|
|
|
|
if n.Expanded && len(n.Children) > 0 {
|
|
|
|
|
@ -80,13 +83,28 @@ func flattenTree(n *TreeNode, depth int) []string {
|
|
|
|
|
} else if len(n.Children) == 0 {
|
|
|
|
|
icon = " "
|
|
|
|
|
}
|
|
|
|
|
out = append(out, fmt.Sprintf("%s%s %s", prefix, icon, n.Label))
|
|
|
|
|
lines = append(lines, fmt.Sprintf("%s%s %s", prefix, icon, n.Label))
|
|
|
|
|
nodes = append(nodes, n)
|
|
|
|
|
if n.Expanded {
|
|
|
|
|
for _, c := range n.Children {
|
|
|
|
|
out = append(out, flattenTree(c, depth+1)...)
|
|
|
|
|
childLines, childNodes := flattenTreeWithNodes(c, depth+1)
|
|
|
|
|
lines = append(lines, childLines...)
|
|
|
|
|
nodes = append(nodes, childNodes...)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return out
|
|
|
|
|
return lines, nodes
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func flattenTree(n *TreeNode, depth int) []string {
|
|
|
|
|
lines, _ := flattenTreeWithNodes(n, depth)
|
|
|
|
|
return lines
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// toggleNodeExpansion toggles the expanded state of a node if it has children
|
|
|
|
|
func (m *model) toggleNodeExpansion(node *TreeNode) {
|
|
|
|
|
if len(node.Children) > 0 {
|
|
|
|
|
node.Expanded = !node.Expanded
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (m *model) renderCommandsContent() string {
|
|
|
|
|
@ -225,6 +243,37 @@ func (m model) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
|
|
|
|
|
|
|
|
|
|
if m.focusPane == "fileview" {
|
|
|
|
|
// fileview tree behaviour (navigation, expand/collapse)
|
|
|
|
|
_, nodes := flattenTreeWithNodes(m.treeRoot, 0)
|
|
|
|
|
switch msg.String() {
|
|
|
|
|
case "up", "k":
|
|
|
|
|
if m.treeCursor > 0 {
|
|
|
|
|
m.treeCursor--
|
|
|
|
|
}
|
|
|
|
|
case "down", "j":
|
|
|
|
|
if m.treeCursor < len(nodes)-1 {
|
|
|
|
|
m.treeCursor++
|
|
|
|
|
}
|
|
|
|
|
case "left", "h":
|
|
|
|
|
if m.treeCursor < len(nodes) {
|
|
|
|
|
node := nodes[m.treeCursor]
|
|
|
|
|
if node.Expanded && len(node.Children) > 0 {
|
|
|
|
|
node.Expanded = false
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
case "right", "l":
|
|
|
|
|
if m.treeCursor < len(nodes) {
|
|
|
|
|
node := nodes[m.treeCursor]
|
|
|
|
|
if !node.Expanded && len(node.Children) > 0 {
|
|
|
|
|
node.Expanded = true
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
case "enter", " ":
|
|
|
|
|
// toggle
|
|
|
|
|
if m.treeCursor < len(nodes) {
|
|
|
|
|
m.toggleNodeExpansion(nodes[m.treeCursor])
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return m, nil
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@ -292,6 +341,14 @@ func (m model) View() string {
|
|
|
|
|
|
|
|
|
|
treeLines := flattenTree(m.treeRoot, 0)
|
|
|
|
|
|
|
|
|
|
// highlight the current selection when fileview is focused
|
|
|
|
|
if m.focusPane == "fileview" && m.treeCursor < len(treeLines) {
|
|
|
|
|
selectedStyle := lipgloss.NewStyle().
|
|
|
|
|
Background(lipgloss.Color("6")).
|
|
|
|
|
Foreground(lipgloss.Color("0"))
|
|
|
|
|
treeLines[m.treeCursor] = selectedStyle.Render(treeLines[m.treeCursor])
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// show the tree view content
|
|
|
|
|
fileviewRows = append(fileviewRows, treeLines...)
|
|
|
|
|
|
|
|
|
|
|