Loading...
Loading...
Compare original and translation side by side
| I need to... | Use | Reference |
|---|---|---|
| Add prompts/spinners to a shell script | Gum (no Go) | Shell Scripts |
| Build a Go TUI | Bubble Tea + Lip Gloss | Go TUI |
| Build a production-grade Go TUI | Above + elite patterns | Production Architecture |
| Serve a TUI over SSH | Wish + Bubble Tea | Infrastructure |
| Record a terminal demo | VHS | Shell Scripts |
| Find a Bubbles component | list, table, viewport, spinner, progress... | Component Catalog |
| Get a copy-paste pattern | Layouts, forms, animation, testing | Quick Reference / Advanced Patterns |
| 我想要... | 使用工具 | 参考文档 |
|---|---|---|
| 给 Shell 脚本添加提示/加载动画 | Gum(无需 Go) | Shell 脚本 |
| 开发 Go TUI | Bubble Tea + Lip Gloss | Go TUI |
| 开发生产级 Go TUI | 以上工具 + 高级模式 | 生产架构 |
| 通过 SSH 提供 TUI 服务 | Wish + Bubble Tea | 基础设施 |
| 录制终端演示视频 | VHS | Shell 脚本 |
| 查找 Bubbles 组件 | list、table、viewport、spinner、progress... | 组件目录 |
| 获取可直接复制的代码模式 | 布局、表单、动画、测试 | 快速参考 / 高级模式 |
Is it a shell script?
├─ Yes → Use Gum
│ Need recording? → VHS
│ Need AI? → Mods
│
└─ No (Go application)
│
├─ Just styled output? → Lip Gloss only
├─ Simple prompts/forms? → Huh standalone
├─ Full interactive TUI? → Bubble Tea + Bubbles + Lip Gloss
│ │
│ └─ Production-grade? → Also add elite patterns:
│ (multi-view, data- two-phase async, immutable snapshots,
│ dense, must be adaptive layout, focus state machine,
│ fast & polished) semantic theming, pre-computed styles
│ → See Production Architecture reference
│
└─ Need SSH access? → Wish + Bubble Tea是 Shell 脚本吗?
├─ 是 → 使用 Gum
│ 需要录屏? → VHS
│ 需要 AI 功能? → Mods
│
└─ 否(Go 应用)
│
├─ 仅需要带样式的输出? → 仅用 Lip Gloss
├─ 简单提示/表单? → 独立使用 Huh
├─ 完整交互式 TUI? → Bubble Tea + Bubbles + Lip Gloss
│ │
│ └─ 生产级 TUI? → 额外加入高级模式:
│ (多视图、数据密集、必须快速流畅且体验精致) 两阶段异步、不可变快照、自适应布局、焦点状态机、语义化主题、预计算样式
│ → 查看生产架构参考文档
│
└─ 需要 SSH 访问? → Wish + Bubble Teabrew install gum # One-time installundefinedbrew install gum # 仅需安装一次undefined
**[Full Gum Reference →](references/shell-scripts.md#gum-the-essential-tool)**
**[VHS Recording →](references/shell-scripts.md#vhs-terminal-recording)**
**[Mods AI →](references/shell-scripts.md#mods-ai-in-terminal)**
---
**[完整 Gum 参考 →](references/shell-scripts.md#gum-the-essential-tool)**
**[VHS 录屏 →](references/shell-scripts.md#vhs-terminal-recording)**
**[Mods AI →](references/shell-scripts.md#mods-ai-in-terminal)**
---go get github.com/charmbracelet/bubbletea github.com/charmbracelet/lipglossgo get github.com/charmbracelet/bubbletea github.com/charmbracelet/lipglosspackage main
import (
"fmt"
tea "github.com/charmbracelet/bubbletea"
"github.com/charmbracelet/lipgloss"
)
var highlight = lipgloss.NewStyle().Foreground(lipgloss.Color("212")).Bold(true)
type model struct {
items []string
cursor int
}
func (m model) Init() tea.Cmd { return nil }
func (m model) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
switch msg := msg.(type) {
case tea.KeyMsg:
switch msg.String() {
case "q", "ctrl+c":
return m, tea.Quit
case "up", "k":
if m.cursor > 0 { m.cursor-- }
case "down", "j":
if m.cursor < len(m.items)-1 { m.cursor++ }
case "enter":
fmt.Printf("Selected: %s\n", m.items[m.cursor])
return m, tea.Quit
}
}
return m, nil
}
func (m model) View() string {
s := ""
for i, item := range m.items {
if i == m.cursor {
s += highlight.Render("▸ "+item) + "\n"
} else {
s += " " + item + "\n"
}
}
return s + "\n(↑/↓ move, enter select, q quit)"
}
func main() {
m := model{items: []string{"Option A", "Option B", "Option C"}}
tea.NewProgram(m).Run()
}package main
import (
"fmt"
tea "github.com/charmbracelet/bubbletea"
"github.com/charmbracelet/lipgloss"
)
var highlight = lipgloss.NewStyle().Foreground(lipgloss.Color("212")).Bold(true)
type model struct {
items []string
cursor int
}
func (m model) Init() tea.Cmd { return nil }
func (m model) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
switch msg := msg.(type) {
case tea.KeyMsg:
switch msg.String() {
case "q", "ctrl+c":
return m, tea.Quit
case "up", "k":
if m.cursor > 0 { m.cursor-- }
case "down", "j":
if m.cursor < len(m.items)-1 { m.cursor++ }
case "enter":
fmt.Printf("Selected: %s\n", m.items[m.cursor])
return m, tea.Quit
}
}
return m, nil
}
func (m model) View() string {
s := ""
for i, item := range m.items {
if i == m.cursor {
s += highlight.Render("▸ "+item) + "\n"
} else {
s += " " + item + "\n"
}
}
return s + "\n(↑/↓ move, enter select, q quit)"
}
func main() {
m := model{items: []string{"Option A", "Option B", "Option C"}}
tea.NewProgram(m).Run()
}| Need | Library | Example |
|---|---|---|
| TUI framework | | |
| Components | | |
| Styling | | |
| Forms | | |
| Markdown | | |
| Animation | | |
| 需求 | 依赖库 | 示例 |
|---|---|---|
| TUI 开发框架 | | |
| UI 组件 | | |
| 样式处理 | | |
| 表单开发 | | |
| Markdown 渲染 | | |
| 动画效果 | | |
s, _ := wish.NewServer(
wish.WithAddress(":2222"),
wish.WithHostKeyPath(".ssh/key"),
wish.WithMiddleware(
bubbletea.Middleware(handler),
logging.Middleware(),
),
)
s.ListenAndServe()ssh localhost -p 2222s, _ := wish.NewServer(
wish.WithAddress(":2222"),
wish.WithHostKeyPath(".ssh/key"),
wish.WithMiddleware(
bubbletea.Middleware(handler),
logging.Middleware(),
),
)
s.ListenAndServe()ssh localhost -p 2222| Symptom | Pattern | Fix |
|---|---|---|
| UI blocks during computation | Two-Phase Async | Phase 1 instant, Phase 2 background goroutine |
| Render path holds mutex | Immutable Snapshots | Pre-build snapshot, atomic pointer swap |
| File changes cause stutter | Background Worker | Debounced watcher + coalescing |
| Thousands of allocs per frame | Pre-Computed Styles | Allocate delegate styles once at startup |
| O(n²) string concat in View() | strings.Builder | Pre-allocated Builder with Grow() |
| Glamour re-renders every frame | Cached Markdown | Cache by content hash, invalidate on width change |
| GC pauses during interaction | Idle-Time GC | Trigger GC during idle periods |
| Large dataset = high memory | Object Pooling | sync.Pool with pre-allocated slices |
| Rendering off-screen items | Viewport Virtualization | Only render visible rows |
| 症状 | 模式 | 解决方案 |
|---|---|---|
| 计算过程中 UI 阻塞 | 两阶段异步架构 | 第一阶段即时响应,第二阶段后台 goroutine 执行 |
| 渲染路径持有互斥锁 | 不可变快照模式 | 预构建快照,原子指针交换 |
| 文件变更导致卡顿 | 带文件监听的后台 worker | 防抖监听 + 事件合并 |
| 每帧渲染产生数千次内存分配 | 预计算样式提升性能 | 启动时一次性分配所有样式 |
| View() 中存在 O(n²) 字符串拼接 | 在 View() 中使用 strings.Builder | 通过 Grow() 预分配 Builder 内存 |
| Glamour 每帧重复渲染 | Markdown 渲染缓存 | 按内容哈希缓存,宽度变更时失效 |
| 交互过程中出现 GC 停顿 | 空闲时段 GC 管理 | 在空闲时段触发 GC |
| 大数据集导致内存占用过高 | 对象池提升内存效率 | 配合预分配切片使用 sync.Pool |
| 渲染屏幕外的元素 | 视口虚拟化 | 仅渲染可见行 |
| Symptom | Pattern | Fix |
|---|---|---|
| Hardcoded widths break | Adaptive Layout | 3-4 responsive breakpoints (80/100/140/180 cols) |
| Colors wrong on light terminals | Semantic Theming | |
| Items have equal priority → list shuffles | Deterministic Sorting | Stable sort with tie-breaking secondary key |
| Sort mode not visible | Dynamic Status Bar | Left/right segments with gap-fill |
| 症状 | 模式 | 解决方案 |
|---|---|---|
| 硬编码宽度导致显示错误 | 自适应布局引擎 | 3-4 个响应式断点(80/100/140/180 列) |
| 浅色终端下颜色显示错误 | 语义化主题系统 | |
| 元素优先级相同导致列表顺序随机 | 确定性稳定排序 | 带次级排序键的稳定排序 |
| 排序模式不可见 | 带动态分段的状态栏 | 左右分段,中间自动填充间隙 |
| Symptom | Pattern | Fix |
|---|---|---|
| Key routing chaos | Focus State Machine | Explicit focus enum + modal priority layer |
| User gets lost in nested views | Breadcrumb Navigation | |
| Overlay dismiss loses position | Focus Restoration | Save focus before overlay, restore on dismiss |
| Old async results overwrite new data | Stale Message Detection | Compare data hash before applying results |
| Multiple component updates per frame | tea.Batch Accumulation | Collect cmds in slice, return |
| Background goroutine panic kills TUI | Error Recovery | |
| 症状 | 模式 | 解决方案 |
|---|---|---|
| 按键路由逻辑混乱 | 多视图焦点状态机 | 显式焦点枚举 + 模态优先级层级 |
| 用户在嵌套视图中迷路 | 面包屑导航 | |
| 关闭浮层后焦点位置丢失 | 焦点恢复 | 打开浮层前保存焦点,关闭后恢复 |
| 旧的异步结果覆盖新数据 | 过期消息检测 | 应用结果前对比数据哈希 |
| 每帧多次更新组件 | tea.Batch 命令累加 | 将命令收集到切片中,返回 |
| 后台 goroutine panic 导致 TUI 崩溃 | 后台 goroutine 错误恢复 | 所有 goroutine 加 |
| Want | Pattern | Code |
|---|---|---|
| Bar charts in list columns | Unicode Sparklines | |
| Color-by-intensity | Perceptual Heatmaps | gray → blue → purple → pink gradient |
| Dependency graph in terminal | ASCII Graph Renderer | Canvas + Manhattan routing (╭─╮│╰╯) |
| Age at a glance | Age Color Coding | Fresh=green, aging=yellow, stale=red |
| Borders that mean something | Semantic Borders | Red=blocked, green=ready, yellow=high-impact |
| 需求 | 模式 | 代码 |
|---|---|---|
| 列表列中的柱状图 | Unicode 迷你折线图 | 使用 8 级块字符实现 |
| 按强度着色 | 感知热力图 | 灰 → 蓝 → 紫 → 粉渐变 |
| 终端中的依赖图 | ASCII 图渲染器 | 画布 + 曼哈顿路由 (╭─╮│╰╯) |
| 快速查看内容新旧程度 | 年龄颜色编码 | 新鲜=绿色,即将过期=黄色,过期=红色 |
| 边框携带状态信息 | 语义化边框 | 红色=阻塞,绿色=就绪,黄色=高影响 |
| Want | Pattern | Key Idea |
|---|---|---|
Vim-style | Vim Key Combos | Track |
| Search without jank | Debounced Search | 150ms timer, fire only when typing stops |
| Search across all fields at once | Composite FilterValue | Flatten all fields into one string |
| 4-line cards with metadata | Rich Delegates | Custom delegate with Height()=4 |
| Expand detail inline | Inline Expansion | Toggle with |
| Copy to clipboard | Clipboard Integration | |
| Multi-Tier Help | Quick ref + tutorial + persistent sidebar |
| Kanban with mode switching | Kanban Swimlanes | Pre-computed board states, O(1) switch |
| Collapsible tree with h/l | Tree Navigation | Flatten tree to visible list for j/k nav |
| Suspend TUI for vim edit | Editor Dispatch | |
| Remember expand/collapse | Persistent State | Save to JSON, graceful degradation on corrupt |
| Tune via env vars | Env Preferences | |
| Optional feature missing? | Graceful Degradation | Detect at startup, hide unavailable features |
| 需求 | 模式 | 核心思路 |
|---|---|---|
Vim 风格 | Vim 按键组合追踪 | 两次按键之间追踪 |
| 搜索无卡顿 | 防抖搜索 | 150ms 计时器,仅在输入停止时触发 |
| 同时搜索所有字段 | 零分配模糊搜索的复合过滤值 | 将所有字段扁平化为单个字符串 |
| 带元数据的 4 行卡片 | 丰富的多行列表代理 | 自定义代理,Height()=4 |
| 行内展开详情 | 行内展开 | 按 |
| 复制到剪贴板 | 剪贴板集成 | 按 |
| 多层级帮助系统 | 快速参考 + 教程 + 持久化侧边栏 |
| 带模式切换的看板 | 带泳道模式的看板 | 预计算看板状态,O(1) 切换 |
| 按 h/l 折叠/展开树 | 树导航 | 将树扁平化为可见列表,支持 j/k 导航 |
| 挂起 TUI 打开 vim 编辑 | 编辑器调度 | 终端用 |
| 记住展开/折叠状态 | 持久化状态 | 保存到 JSON,损坏时优雅降级 |
| 通过环境变量调优 | 环境变量配置 | |
| 可选功能缺失? | 优雅降级 | 启动时检测,隐藏不可用功能 |
tea.WindowSizeMsgctrl+c--no-tuiNO_TUINO_COLOR=1TERM=dumbtea.WindowSizeMsgctrl+c--no-tuiNO_TUINO_COLOR=1TERM=dumbmytool | grepfmt.Scanfif !term.IsTerminal(os.Stdin.Fd()) || os.Getenv("NO_TUI") != "" {
runPlainMode()
return
}mytool | grepfmt.Scanfif !term.IsTerminal(os.Stdin.Fd()) || os.Getenv("NO_TUI") != "" {
runPlainMode()
return
}| I need... | Read this |
|---|---|
| Copy-paste one-liners | Quick Reference |
| Prompts to give Claude for TUI tasks | Prompts |
| Gum / VHS / Mods / Freeze / Glow | Shell Scripts |
| Bubble Tea architecture, debugging, anti-patterns | Go TUI |
| Bubbles component APIs (list, table, viewport...) | Component Catalog |
| Theming, layouts, animation, Huh forms, testing | Advanced Patterns |
| Elite patterns: async, snapshots, focus machines, adaptive layout, sparklines, kanban, trees, caching | Production Architecture |
| Wish SSH server, Soft Serve, teatest | Infrastructure |
| 我需要... | 阅读本文 |
|---|---|
| 可直接复制的单行代码 | 快速参考 |
| 给 Claude 的 TUI 开发提示词 | 提示词 |
| Gum / VHS / Mods / Freeze / Glow 用法 | Shell 脚本 |
| Bubble Tea 架构、调试、反模式 | Go TUI |
| Bubbles 组件 API(list、table、viewport...) | 组件目录 |
| 主题、布局、动画、Huh 表单、测试 | 高级模式 |
| 高阶模式:异步、快照、焦点状态机、自适应布局、迷你折线图、看板、树、缓存 | 生产架构 |
| Wish SSH 服务端、Soft Serve、teatest | 基础设施 |