From ad2a48ed0564101723678b3172aa0b0d2e4e7456 Mon Sep 17 00:00:00 2001 From: Jonatan Dahl Date: Wed, 28 Jan 2026 16:45:43 -0500 Subject: [PATCH] feat: use dots-style tree display for stack visualization MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Replace ASCII pipe characters with Unicode circles for cleaner tree display: - ● (filled, bold green) marks the current branch - ○ (hollow, dim) marks other branches - │ (vertical line) connects branches Also removes redundant "Processing N branch(es)..." message from sync since the progress indicator already shows this info. Co-Authored-By: Claude Opus 4.5 --- cmd/status.go | 16 ++++++++-------- cmd/sync.go | 18 ++++++++---------- internal/ui/color.go | 15 +++++++++++++++ 3 files changed, 31 insertions(+), 18 deletions(-) diff --git a/cmd/status.go b/cmd/status.go index 5ec91d1..f7cc45b 100644 --- a/cmd/status.go +++ b/cmd/status.go @@ -284,15 +284,15 @@ func printTree(gitClient git.GitClient, node *stack.TreeNode, prefix string, isL printTreeVertical(gitClient, node, currentBranch, prCache, false) } -func printTreeVertical(gitClient git.GitClient, node *stack.TreeNode, currentBranch string, prCache map[string]*github.PRInfo, isPipe bool) { +func printTreeVertical(gitClient git.GitClient, node *stack.TreeNode, currentBranch string, prCache map[string]*github.PRInfo, isChild bool) { if node == nil { return } - // Determine the current branch marker - marker := "" + // Determine the node marker (filled for current branch, hollow for others) + nodeMarker := ui.TreeNode() if node.Name == currentBranch { - marker = ui.CurrentBranchMarker() + nodeMarker = ui.TreeNodeCurrent() } // Get PR info from cache @@ -303,13 +303,13 @@ func printTreeVertical(gitClient git.GitClient, node *stack.TreeNode, currentBra } } - // Print pipe if needed - if isPipe { - fmt.Printf(" %s\n", ui.Pipe()) + // Print connecting line if this is a child node + if isChild { + fmt.Printf("%s\n", ui.TreeLine()) } // Print current node - fmt.Printf(" %s%s%s\n", ui.Branch(node.Name), prInfo, marker) + fmt.Printf("%s %s%s\n", nodeMarker, ui.Branch(node.Name), prInfo) // Print children vertically for _, child := range node.Children { diff --git a/cmd/sync.go b/cmd/sync.go index f2ba742..e87b862 100644 --- a/cmd/sync.go +++ b/cmd/sync.go @@ -459,8 +459,6 @@ func runSync(gitClient git.GitClient, githubClient github.GitHubClient) error { // Get all remote branches in one call (more efficient than checking each branch individually) remoteBranches := gitClient.GetRemoteBranchesSet() - fmt.Printf("Processing %d branch(es)...\n\n", len(sorted)) - // Build a set of stack branch names for quick lookup stackBranchSet := make(map[string]bool) for _, sb := range stackBranches { @@ -965,15 +963,15 @@ func printTreeForSync(gitClient git.GitClient, node *stack.TreeNode, currentBran printTreeVerticalForSync(gitClient, node, currentBranch, prCache, false) } -func printTreeVerticalForSync(gitClient git.GitClient, node *stack.TreeNode, currentBranch string, prCache map[string]*github.PRInfo, isPipe bool) { +func printTreeVerticalForSync(gitClient git.GitClient, node *stack.TreeNode, currentBranch string, prCache map[string]*github.PRInfo, isChild bool) { if node == nil { return } - // Determine the current branch marker - marker := "" + // Determine the node marker (filled for current branch, hollow for others) + nodeMarker := ui.TreeNode() if node.Name == currentBranch { - marker = ui.CurrentBranchMarker() + nodeMarker = ui.TreeNodeCurrent() } // Get PR info from cache @@ -984,13 +982,13 @@ func printTreeVerticalForSync(gitClient git.GitClient, node *stack.TreeNode, cur } } - // Print pipe if needed - if isPipe { - fmt.Printf(" %s\n", ui.Pipe()) + // Print connecting line if this is a child node + if isChild { + fmt.Printf("%s\n", ui.TreeLine()) } // Print current node - fmt.Printf(" %s%s%s\n", ui.Branch(node.Name), prInfo, marker) + fmt.Printf("%s %s%s\n", nodeMarker, ui.Branch(node.Name), prInfo) // Print children vertically for _, child := range node.Children { diff --git a/internal/ui/color.go b/internal/ui/color.go index ed1b1f8..8a9cb10 100644 --- a/internal/ui/color.go +++ b/internal/ui/color.go @@ -82,6 +82,21 @@ func Pipe() string { return dim.Sprint("|") } +// TreeNodeCurrent returns the filled circle for current branch (bold green) +func TreeNodeCurrent() string { + return boldGreen.Sprint("●") +} + +// TreeNode returns the hollow circle for non-current branches (dim) +func TreeNode() string { + return dim.Sprint("○") +} + +// TreeLine returns the vertical line for connecting branches (dim) +func TreeLine() string { + return dim.Sprint("│") +} + // SuccessIcon returns just the green checkmark func SuccessIcon() string { return green.Sprint("✓")