From a0e069e9c960ac11fb6fbf4c3822a9fdba1f8ee3 Mon Sep 17 00:00:00 2001 From: Francesco Minnocci Date: Mon, 1 Sep 2025 12:56:25 +0200 Subject: [PATCH] feat: side-panel navigation and expansion --- main.go | 71 +++++++++++++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 64 insertions(+), 7 deletions(-) diff --git a/main.go b/main.go index a955657..de77567 100644 --- a/main.go +++ b/main.go @@ -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...)