feat: side-panel navigation and expansion
This commit is contained in:
@@ -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...)
|
||||
|
||||
|
||||
Reference in New Issue
Block a user