Files
beads/internal/ui/markdown.go
Ryan Snodgrass cfd1f39e1e feat(ux): visual improvements for list tree, graph, and show commands
bd list --tree:
- Use actual parent-child dependencies instead of dotted ID hierarchy
- Treat epic dependencies as parent-child relationships
- Sort children by priority (P0 first)
- Fix tree display in daemon mode with read-only store access

bd graph:
- Add --all flag to show dependency graph of all open issues
- Add --compact flag for tree-style rendering (reduces 44+ lines to 13)
- Fix "needs:N" cognitive noise by using semantic colors
- Add blocks:N indicator with semantic red coloring

bd show:
- Tufte-aligned header with status icon, priority, and type badges
- Add glamour markdown rendering with auto light/dark mode detection
- Cap markdown line width at 100 chars for readability
- Mute entire row for closed dependencies (work done, no attention needed)

Design system:
- Add shared status icons (○ ◐ ● ✓ ❄) with semantic colors
- Implement priority colors: P0 red, P1 orange, P2 muted gold, P3-P4 neutral
- Add TrueColor profile for distinct hex color rendering
- Type badges for epic (purple) and bug (red)

Design principles:
- Semantic colors only for actionable items
- Closed items fade (muted gray)
- Icons > text labels for better scanability

Co-Authored-By: SageOx <ox@sageox.ai>
2026-01-08 20:50:56 -08:00

55 lines
1.4 KiB
Go

// Package ui provides terminal styling for beads CLI output.
package ui
import (
"os"
"github.com/charmbracelet/glamour"
"golang.org/x/term"
)
// RenderMarkdown renders markdown text using glamour with beads theme colors.
// Returns the rendered markdown or the original text if rendering fails.
// Word wraps at terminal width (or 80 columns if width can't be detected).
func RenderMarkdown(markdown string) string {
// Skip glamour in agent mode to keep output clean for parsing
if IsAgentMode() {
return markdown
}
// Skip glamour if colors are disabled
if !ShouldUseColor() {
return markdown
}
// Detect terminal width for word wrap
// Cap at 100 chars for readability - wider lines cause eye-tracking fatigue
// Typography research suggests 50-75 chars optimal, 80-100 comfortable max
const maxReadableWidth = 100
wrapWidth := 80 // default if terminal size unavailable
if w, _, err := term.GetSize(int(os.Stdout.Fd())); err == nil && w > 0 {
wrapWidth = w
}
if wrapWidth > maxReadableWidth {
wrapWidth = maxReadableWidth
}
// Create renderer with auto-detected style (respects terminal light/dark mode)
renderer, err := glamour.NewTermRenderer(
glamour.WithAutoStyle(),
glamour.WithWordWrap(wrapWidth),
)
if err != nil {
// fallback to raw markdown on error
return markdown
}
rendered, err := renderer.Render(markdown)
if err != nil {
// fallback to raw markdown on error
return markdown
}
return rendered
}