fix(deps): update module github.com/charmbracelet/bubbletea to v2 - #2768
fix(deps): update module github.com/charmbracelet/bubbletea to v2#2768renovate[bot] wants to merge 1 commit into
Conversation
|
e71e507 to
a2a0da2
Compare
a2a0da2 to
3f98b6a
Compare
3f98b6a to
457279e
Compare
pikachuren
left a comment
There was a problem hiding this comment.
🙏 感谢贡献
感谢 @app/renovate 提交此自动依赖更新 PR!我已完成代码评审,以下是评审结果。
🤖 AI 自动审核声明
本评审报告由 AI 自动生成,当前使用 Claude Opus 5 模型进行分析,部分复杂场景可能辅助使用 ChatGPT、DeepSeek 等模型进行交叉验证。
⚠️ AI 分析结果仅供参考,可能存在误判或遗漏。如您发现任何问题或有不同意见,欢迎随时提出讨论和纠正。
⚠️ 重要提醒:即使 AI 评审认为代码质量良好且建议合并,最终是否合并仍需由项目维护者进行人工判定。项目维护者会综合考虑代码质量、项目规划、技术方向、团队资源等多方面因素做出决策。
📖 PR背景与需求
PR标题:fix(deps): update module github.com/charmbracelet/bubbletea to v2
依赖更新类型:主版本升级(Major Version Update)
需求说明:
Renovate Bot 自动创建的依赖更新 PR,将 github.com/charmbracelet/bubbletea 从 v1.3.10 升级到 v2.0.8(主版本升级)。
预期目标:
- 使用 Bubble Tea v2 的新架构和功能
- 获得性能提升(Cursed Renderer、带宽优化)
- 支持增强键盘输入(Kitty Keyboard Protocol)
- 更好的声明式 View API
📋 问题摘要
⚠️ 破坏性变更风险:主版本升级包含大量不兼容的 API 变更(⚠️ ⚠️ ⚠️ 极高风险)⚠️ 不完整迁移:同时保留 v1 和 v2 两个版本,依赖冗余(⚠️ 重要)⚠️ 缺少兼容性验证:未检查代码是否需要适配新 API(⚠️ 关键)⚠️ 依赖链问题:bubbles 和 lipgloss 也需要升级到 v2(⚠️ 阻塞性)- 💡 需要大规模代码重构:View()、Key、Mouse、Paste 等核心 API 全部变更
📂 逐文件分析
go.mod
改动意图:
将 Bubble Tea 依赖从 v1.3.10 升级到 v2.0.8。
代码修改逻辑:
- github.com/charmbracelet/bubbletea v1.3.10
+ github.com/charmbracelet/bubbletea/v2 v2.0.8在 Go modules 中,主版本 v2+ 需要在模块路径中包含版本后缀(/v2)。
合理性评估:
✅ 优点:
- 符合 Go modules 规范:正确使用了
/v2路径后缀 - 版本选择合理:v2.0.8 是 v2 系列的稳定版本,包含多个 bug 修复
- 上游质量良好:Bubble Tea v2 经过充分测试,由 Charm 团队维护
- 性能提升显著:Cursed Renderer 将带宽使用降低数个数量级
-
依赖冗余问题(
⚠️ 关键)- 当前
go.mod中同时保留了 v1 和 v2 两个版本 - 这会导致编译后的二进制文件包含两份 Bubble Tea 代码,显著增大体积
- 必须检查并移除 v1 依赖
- 当前
-
依赖链不兼容问题(
⚠️ ⚠️ ⚠️ 阻塞性)-
当前
go.mod中:bubbles仍是 v0.21.1(v1 系列,依赖 bubbletea v1)lipgloss仍是 v1.1.0(v1 系列)
-
Bubble Tea v2 要求:
- 必须使用
bubbles/v2(兼容 bubbletea v2) - 必须使用
lipgloss/v2(Bubble Tea v2 已集成)
- 必须使用
-
结果:此 PR 单独合并会导致编译失败,因为依赖版本不匹配
-
-
代码兼容性问题(
⚠️ ⚠️ ⚠️ 极高风险)Bubble Tea v2 包含大量破坏性 API 变更:
v1 API v2 API 影响范围 View() stringView() tea.View所有组件的 View 方法 tea.KeyMsgtea.KeyPressMsg/tea.KeyReleaseMsg所有键盘处理逻辑 msg.Type,msg.Runesmsg.Code,msg.Text所有按键判断 msg.Alt,msg.Ctrl,msg.Shiftmsg.Mod所有修饰键判断 tea.MouseMsgtea.MouseClickMsg/tea.MouseReleaseMsg/tea.MouseWheelMsg/tea.MouseMotionMsg所有鼠标处理 tea.KeyMsgwithmsg.Pastetea.PasteMsg/tea.PasteStartMsg/tea.PasteEndMsg粘贴事件处理 tea.EnterAltScreen()view.AltScreen = true终端模式切换 tea.EnableMouseCellMotion()view.MouseMode = tea.MouseModeCellMotion鼠标模式设置 必须修改的代码位置(影响全局):
- 所有实现了
View() string的组件 → 改为View() tea.View - 所有
case tea.KeyMsg:→ 改为case tea.KeyPressMsg: - 所有
switch msg.Type:→ 改为switch msg.String(): - 所有
msg.Alt、msg.Ctrl→ 改为msg.Mod.Has(tea.ModAlt) - 所有
case tea.MouseMsg:→ 拆分为多种鼠标消息类型 - 所有使用
tea.EnterAltScreen等命令 → 改为声明式 View 字段
- 所有实现了
-
迁移策略不明确
- 是完全迁移到 v2?(推荐,但工作量巨大)
- 还是渐进式迁移?(需要明确计划)
- 还是意外引入?(需要回退)
❌ 明确问题:
-
缺少配套依赖升级
- 必须同时升级
bubbles到 v2 - 必须同时升级
lipgloss到 v2 - 否则会出现版本冲突和编译失败
- 必须同时升级
-
缺少兼容性验证
- PR 描述中没有提到是否检查了代码兼容性
- 没有提到是否运行了测试套件
- 没有提到是否查阅了 v2 的 breaking changes
-
缺少迁移说明
- 没有说明哪些代码需要修改
- 没有提供迁移 checklist
- 没有说明预计的迁移工作量
🎯 总体评价
功能性:
安全性:⭐⭐⭐⭐ - Bubble Tea 不涉及安全关键逻辑,上游可信
代码质量:
实现方案:
建议操作:
- ✅ Approve(建议合并)
- 🔄 Request Changes(需要修改)
- ❌ Close(建议关闭)
理由:
此 PR 是一个主版本升级,包含大量破坏性 API 变更,需要极其谨慎处理。当前状态存在以下阻塞性问题:
-
依赖链不完整,无法编译:
- 仅升级了
bubbletea到 v2,但bubbles和lipgloss仍是 v1 bubbles v0.21.1依赖bubbletea v1,与bubbletea v2不兼容- 此 PR 单独合并会导致编译失败
- 仅升级了
-
未进行代码迁移:
- 仅修改了
go.mod,但没有任何代码层面的修改 - Bubble Tea v2 的核心 API 完全重构,所有使用 Bubble Tea 的代码都需要修改
- 如果没有修改代码,即使能编译,运行时也会出错
- 仅修改了
-
影响范围巨大:
- Bubble Tea 是整个 TUI 应用的核心框架
- 所有组件、所有 Update/View 函数、所有事件处理都需要修改
- 这是一个全局性的重大重构,不是简单的依赖更新
📝 详细建议
必须完成的步骤(按顺序):
1. 评估迁移工作量
# 统计使用 Bubble Tea API 的文件数量
grep -r "bubbletea" . --include="*.go" | wc -l
# 统计所有 View() 方法(需要全部改为 tea.View)
grep -r "func.*View().*string" . --include="*.go" | wc -l
# 统计所有 KeyMsg 处理(需要改为 KeyPressMsg)
grep -r "tea.KeyMsg" . --include="*.go" | wc -l
# 统计所有 MouseMsg 处理(需要拆分为多种消息类型)
grep -r "tea.MouseMsg" . --include="*.go" | wc -l
# 统计所有命令式调用(需要改为声明式 View 字段)
grep -r "tea.EnterAltScreen\|tea.EnableMouse\|tea.EnableReportFocus" . --include="*.go" | wc -l2. 决定迁移策略
方案 A:完全迁移到 v2(✅ 推荐,但工作量巨大)
优点:
- 获得 v2 的所有新功能和性能提升
- 长期维护更简单
- 清理了依赖,减小二进制体积
缺点:
- 工作量极大:需要修改数百个文件
- 高风险:容易引入 bug 和回归
- 耗时长:可能需要数周甚至数月
步骤:
- 制定详细的迁移计划,分阶段进行
- 同时升级所有相关依赖:
go get charm.land/bubbletea/v2@latest go get charm.land/bubbles/v2@latest go get charm.land/lipgloss/v2@latest
- 修改所有导入语句:
// Before import tea "github.com/charmbracelet/bubbletea" // After import tea "charm.land/bubbletea/v2"
- 重构所有 View() 方法:
// Before (v1) func (m model) View() string { return "Hello, World!" } // After (v2) func (m model) View() tea.View { return tea.NewView("Hello, World!") }
- 重构所有事件处理:
// Before (v1) case tea.KeyMsg: switch msg.Type { case tea.KeyEnter: if msg.Alt { // Alt+Enter } } // After (v2) case tea.KeyPressMsg: switch msg.String() { case "enter": // Enter case "alt+enter": // Alt+Enter }
- 将命令式调用改为声明式:
// Before (v1) func (m model) Init() tea.Cmd { return tea.Batch( tea.EnterAltScreen, tea.EnableMouseCellMotion, ) } // After (v2) func (m model) View() tea.View { v := tea.NewView(m.content) v.AltScreen = true v.MouseMode = tea.MouseModeCellMotion return v }
- 运行完整测试:
go test ./... -v - 手动测试所有 TUI 功能
方案 B:保持 v1(✅ 如果迁移成本不可接受)
如果迁移工作量过大或时机不合适:
- 关闭此 PR(以及 #2769 lipgloss v2 PR)
- 在
renovate.json中配置忽略 v2 升级:{ "packageRules": [ { "matchPackageNames": [ "github.com/charmbracelet/bubbletea", "github.com/charmbracelet/lipgloss", "github.com/charmbracelet/bubbles" ], "allowedVersions": "< 2.0.0" } ] } - 继续使用 v1 系列的最新版本,等待合适的迁移时机
方案 C:渐进式迁移(❌ 不推荐)
由于依赖链的强关联性,渐进式迁移几乎不可行:
- 不能只升级
bubbletea而不升级bubbles和lipgloss - 不能让部分组件使用 v1,部分使用 v2(类型不兼容)
- 同时维护两个版本会导致极大的代码复杂度
3. 查阅官方迁移指南
必读文档:
关键变更摘要(Bubble Tea v2):
| 类别 | v1 API | v2 API |
|---|---|---|
| View 方法 | View() string |
View() tea.View |
| 按键消息 | tea.KeyMsg |
tea.KeyPressMsg / tea.KeyReleaseMsg |
| 按键字段 | msg.Type, msg.Runes |
msg.Code, msg.Text |
| 修饰键 | msg.Alt, msg.Ctrl, msg.Shift |
msg.Mod.Has(tea.ModAlt) |
| 空格键 | " " |
"space" |
| 鼠标消息 | tea.MouseMsg |
tea.MouseClickMsg / tea.MouseReleaseMsg / tea.MouseWheelMsg / tea.MouseMotionMsg |
| 粘贴消息 | tea.KeyMsg with msg.Paste |
tea.PasteMsg / tea.PasteStartMsg / tea.PasteEndMsg |
| 终端模式 | tea.EnterAltScreen() 命令 |
view.AltScreen = true 字段 |
| 鼠标模式 | tea.EnableMouseCellMotion() 命令 |
view.MouseMode = tea.MouseModeCellMotion 字段 |
| 焦点报告 | tea.EnableReportFocus() 命令 |
view.ReportFocus = true 字段 |
4. 配套依赖升级
必须同时升级(作为一个原子操作):
# 升级整个 Charm 生态到 v2
go get charm.land/bubbletea/v2@latest
go get charm.land/bubbles/v2@latest
go get charm.land/lipgloss/v2@latest
# 清理依赖
go mod tidy
# 验证没有 v1 残留
go mod graph | grep "bubbletea@v1\|lipgloss@v1\|bubbles@v0"5. 运行测试并验证
# 编译检查
go build ./...
# 运行单元测试
go test ./... -v
# 运行集成测试(如果有)
go test ./... -tags=integration
# 手动测试 TUI 功能
# 启动应用,逐一测试:
# - 键盘输入(包括特殊组合键)
# - 鼠标交互
# - 全屏模式
# - 粘贴功能
# - 样式渲染
# - 所有 UI 组件💡 迁移示例
示例 1:View() 方法重构
// Before (v1)
type model struct {
content string
}
func (m model) View() string {
return lipgloss.NewStyle().
Bold(true).
Foreground(lipgloss.Color("#FF0000")).
Render(m.content)
}
// After (v2)
import (
tea "charm.land/bubbletea/v2"
"charm.land/lipgloss/v2"
)
type model struct {
content string
}
func (m model) View() tea.View {
style := lipgloss.NewStyle().
Bold(true).
Foreground(lipgloss.Color("#FF0000"))
content := style.Render(m.content)
v := tea.NewView(content)
v.AltScreen = true // 如果需要全屏
v.MouseMode = tea.MouseModeCellMotion // 如果需要鼠标
return v
}示例 2:按键处理重构
// Before (v1)
func (m model) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
switch msg := msg.(type) {
case tea.KeyMsg:
switch msg.Type {
case tea.KeyEnter:
if msg.Alt {
return m, m.doAltEnter()
}
return m, m.doEnter()
case tea.KeySpace:
return m, m.doSpace()
case tea.KeyCtrlC:
return m, tea.Quit
}
}
return m, nil
}
// After (v2)
func (m model) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
switch msg := msg.(type) {
case tea.KeyPressMsg:
switch msg.String() {
case "enter":
return m, m.doEnter()
case "alt+enter":
return m, m.doAltEnter()
case "space": // 注意:v2 中空格是 "space" 而不是 " "
return m, m.doSpace()
case "ctrl+c":
return m, tea.Quit
}
}
return m, nil
}示例 3:鼠标处理重构
// Before (v1)
func (m model) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
switch msg := msg.(type) {
case tea.MouseMsg:
switch msg.Type {
case tea.MouseLeft:
m.handleClick(msg.X, msg.Y)
case tea.MouseWheelUp:
m.scrollUp()
case tea.MouseWheelDown:
m.scrollDown()
}
}
return m, nil
}
// After (v2)
func (m model) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
switch msg := msg.(type) {
case tea.MouseClickMsg:
if msg.Button == tea.MouseLeft {
m.handleClick(msg.X, msg.Y)
}
case tea.MouseWheelMsg:
if msg.Direction == tea.MouseWheelUp {
m.scrollUp()
} else {
m.scrollDown()
}
}
return m, nil
}🔍 需要回答的问题
在合并此 PR 之前,请确认以下问题:
- ✅ 是否已评估迁移工作量和所需时间?
- ✅ 是否制定了详细的迁移计划和里程碑?
- ✅ 是否同时升级了 bubbles 和 lipgloss 到 v2?
- ✅ 是否查阅了 Bubble Tea v2 的升级指南和 breaking changes?
- ✅ 是否修改了所有 View() 方法返回类型?
- ✅ 是否重构了所有事件处理逻辑(Key、Mouse、Paste)?
- ✅ 是否将命令式调用改为声明式 View 字段?
- ✅ 是否运行了
go mod tidy并确认 v1 已被移除? - ✅ 是否运行了完整的测试套件并通过?
- ✅ 是否手动测试了所有 TUI 功能,确认无回归?
如果以上任何一项为 ❌,此 PR 不应合并。
🚨 特别警告
此 PR 单独合并会导致项目无法编译!
原因:
bubbletea v2与bubbles v0.21.1不兼容bubbles v0.21.1依赖bubbletea v1- Go modules 会尝试同时引入 v1 和 v2,导致类型冲突
必须同时合并以下 PR(或创建新的 PR):
- 升级
bubbletea到 v2.0.8(当前 PR) - 升级
bubbles到 v2.x - 升级
lipgloss到 v2.x(PR #2769) - 修改所有使用 Bubble Tea 的代码
建议操作:
- 关闭当前所有单独的依赖升级 PR
- 创建一个完整的 v2 迁移 PR,包含:
- 所有依赖升级
- 所有代码修改
- 完整的测试验证
- 或者,如果暂时不迁移,配置 Renovate 忽略 v2 升级
📚 参考资料
官方文档:
社区资源:
- Charm Discord - 可以咨询迁移问题
- Bubble Tea 示例代码
总结
这是一个需要极其谨慎处理的重大重构 PR。Bubble Tea v2 是一个激动人心的升级,但不是简单的依赖更新,而是需要大规模代码重构的架构变更。
强烈建议:
- 暂不合并,先评估工作量和影响范围
- 制定完整的迁移计划,分配足够的人力和时间
- 同时升级所有相关依赖,作为一个原子操作
- 全面测试,确保无回归
- 或者,暂时保持 v1,在合适的时机进行迁移
如果需要帮助迁移代码,请随时提问!我可以协助分析具体的代码修改需求和最佳实践。
特别提醒:此 PR 与 #2769(lipgloss v2)、可能的 bubbles v2 PR 互相关联,必须作为一个整体来处理。
This PR contains the following updates:
v1.3.10→v2.0.8Release Notes
charmbracelet/bubbletea (github.com/charmbracelet/bubbletea)
v2.0.8Compare Source
Graphemes, schmraphemes
No terminal can render emojis perfectly, but we can try. This release improves some very specific edge cases around emoji rendering. Enjoy!
Changelog
db569ad: fix(deps): bump ultraviolet for emoji-related rendering improvementsThoughts? Questions? We love hearing from you. Feel free to reach out on X, Discord, Slack, The Fediverse, Bluesky.
v2.0.7Compare Source
A few lil’ stability patches
Hi! This is a patch release with a few solid improvements around stability and correctness.
Thanks for using Bubble Tea, and if you see anything awry please do let us know!
—Charm 👋
Changelog
Fixed
c60f0c5: fix: prevent data race with cursedRenderer.onMouse (#1691) (@lrstanley)074596e: fix: skip input reader restore when input is disabled (#1680) (@lawrence3699)878d7df: fix(deps): bump ultraviolet for kitty keyboard fix (@meowgorithm)Thoughts? Questions? We love hearing from you. Feel free to reach out on X, Discord, Slack, The Fediverse, Bluesky.
v2.0.6Compare Source
This release fixes an issue with how Bubble Tea handled wide characters. Before, a wide character might be skipped or cause an infinite loop causing the CPU to spike. See
fdcd0cfand charmbracelet/ultraviolet#109 for more details.Thoughts? Questions? We love hearing from you. Feel free to reach out on X, Discord, Slack, The Fediverse, Bluesky.
v2.0.5Compare Source
Changelog
Thoughts? Questions? We love hearing from you. Feel free to reach out on X, Discord, Slack, The Fediverse, Bluesky.
v2.0.4Compare Source
Changelog
Thoughts? Questions? We love hearing from you. Feel free to reach out on X, Discord, Slack, The Fediverse, Bluesky.
v2.0.3Compare Source
Extra Extra Extended Keyboard Enhancements!
This release adds support for the full set of Keyboard Enhancements. Now you can enable any enhancements on top of the default disambiguate one.
Smarter Renderer
We also fixed a few renderer related bugs and made the Cursed Renderer smarter. Now, we always reset the terminal tab stops for the Bubble Tea program process context. People using
tabs -Nin their shell profiles shouldn't be affected.See the full changelog below.
Changelog
New!
05df5ae: feat: support extended keyboard enhancements (#1626) (@aymanbagabas)Fixed
a3d7807: fix(ci): only run build-examples on non-dependabot PRs (@aymanbagabas)7df1e65: fix(examples): migrate imports to charm.land for the glamour example (#1642) (@mhdna)ee06e98: fix(examples): resolve nil pointer dereference (#1663) (@mattpcaswell)ac355fe: fix(renderer): restore tab stops if hard tabs are enabled (#1677) (@aymanbagabas)729f05c: fix: add missing signal.Stop in suspendProcess to prevent signal channel leak (Closes #1673) (#1674) (@kuishou68)Docs
bbe4faf: docs(example): add textarea dynamic height example (#1639) (@meowgorithm)e19d255: docs: fix README wording (#1624) (@Rohan5commit)Other stuff
65c3978: ci: sync golangci-lint config (#1556) (@github-actions[bot])Thoughts? Questions? We love hearing from you. Feel free to reach out on X, Discord, Slack, The Fediverse, Bluesky.
v2.0.2Compare Source
This release contains a small patch fixing a rendering that might affect Wish users running on Unix platforms.
Changelog
Fixed
f25595a: fix(renderer): use mapNl optimization when not on Windows and no PTY input (#1615) (@aymanbagabas)Thoughts? Questions? We love hearing from you. Feel free to reach out on X, Discord, Slack, The Fediverse, Bluesky.
v2.0.1Compare Source
A small patch release to fix opening the proper default stdin file for input.
Changelog
Fixed
110a919: fix(examples): add missingWithWidthto table example (#1598) (@shv-ng)66b7abd: fix: check if os.Stdin is a terminal before opening the TTY (@aymanbagabas)Docs
c751374: docs: correct whats new link (@aymanbagabas)736fba2: docs: upgrade guide: correct badge url (@aymanbagabas)Thoughts? Questions? We love hearing from you. Feel free to reach out on X, Discord, Slack, The Fediverse, Bluesky.
v2.0.0Compare Source
What's New in Bubble Tea v2
We're very excited to announce the second major release of Bubble Tea!
If you (or your LLM) are just looking for technical details on on migrating from v1, please check out the Upgrade Guide.
❤️ Charm Land Import Path
We've updated our import paths to use vanity domains and use our domain to import Go packages.
Everything else stays the same 🙂
👾 The Cursed Renderer
Bubble Tea v2 ships with the all-new Cursed Renderer which was built from the ground up. It's based on the ncurses rendering algorithm and is highly optimized for speed, efficiency, and accuracy and is built on an enormous amount of research and development.
Optimized renders also means that Wish users get big performance benefits and lower bandwidth usage by orders of magnitude.
To take advantage of the new Cursed Renderer you don't need to do anything at all except keep on using the Bubble Tea you know and love.
✌️ Key handling is way better now
Newer terminals can now take advantage of all sorts keyboard input via progressive keyboard enhancements. You can now map all sorts of keys and modifiers like shift+enter and super+space. You can also detect key releases (we're looking at you, game developers).
It's easy to detect support for supporting terminals and add fallbacks for those that don't. For details, see keyboard enhancements below.
🥊 No more fighting
In the past, Bubble Tea and Lip Gloss would often fight over i/o. Bubble Tea wanted to read keyboard input and Lip Gloss wanted to query for the background color. This means that things could get messy. Not anymore! In v2, Lip Gloss is now pure, which means, Bubble Tea manages i/o and gives orders to Lip Gloss. In short, we only need one lib to call the shots, and in the context of this relationship, that lib is Bubble Tea.
But what about color downsampling? That's a great question.
👨🏻🎨 Built-in Color Downsampling
We sneakily released a little library called colorprofile that will detect the terminal's color profile and auto-downsample any ANSI styling that flows through it to the best available color profile. This means that color will "just work" (and not misbehave) no matter where the ANSI styling comes from.
Downsampling is built-into Bubble Tea and is automatically enabled.
🧘 Declarative, Not Imperative
This is a big one. In v1, you'd toggle terminal features on and off with commands like
tea.EnterAltScreen,tea.EnableMouseCellMotion,tea.EnableReportFocus, and so on. In v2, all of that is gone and replaced by fields on theViewstruct. You just declare what you want your view to look like and Bubble Tea takes care of the rest.This means no more fighting over startup options and commands. Just set the fields and forget about it. For example, to enter full screen mode:
The same goes for mouse mode, bracketed paste, focus reporting, window title, keyboard enhancements, and more. See A Declarative View below for the full picture.
Keyboard Enhancements
Progressive keyboard enhancements allow you to receive key events not normally possible in traditional terminals. For example, you can now listen for the ctrl+m key, as well as previously unavailable key combinations like shift+enter.
Bubble Tea v2 will always try to enable basic keyboard enhancements that disambiguate keys. If your terminal supports it, your program will receive a
tea.KeyboardEnhancementsMsgmessage that indicates support for requested features.Historically, certain key combinations in terminals map to control codes. For example, ctrl+h outputs a backspace by default, which means you can't normally bind a key event to ctrl+h. With key disambiguation, you can now actually bind events to those key combinations.
You can detect if a terminal supports keyboard enhancements by listening for
tea.KeyboardEnhancementsMsg.Which terminals support progressive enhancement?
Key Messages
Key messages are now split into
tea.KeyPressMsgandtea.KeyReleaseMsg. Usetea.KeyMsgto match against both. We've also replacedkey.Typeandkey.Runeswithkey.Codeandkey.Text. Modifiers live inkey.Modnow instead of being separate booleans. Oh, and space bar returns"space"instead of" ".The easiest way to match against key press events is to use
msg.String():The
Keystruct also has some nice new fields:key.BaseCode— the key according to a standard US PC-101 layout. Handy for international keyboards where the physical key might differ.key.IsRepeat— tells you if the key is being held down and auto-repeating. Only available with the Kitty Keyboard Protocol or Windows Console API.key.Keystroke()— a new method that returns the keystroke representation (e.g.,"ctrl+shift+alt+a"). UnlikeString(), it always includes modifier info.For the full list of changes and before/after code samples, see the Upgrade Guide.
Paste Messages
Paste events used to arrive as
tea.KeyMsgwith a confusingmsg.Pasteflag. Now they're their own thing:Mouse Messages
We've improved the mouse API. Mouse messages are now split into
tea.MouseClickMsg,tea.MouseReleaseMsg,tea.MouseWheelMsg, andtea.MouseMotionMsg. And mouse mode is set declaratively in yourView():A Declarative View
In v1,
View()returned astring. In v2, it returns atea.Viewstruct that lets you declare everything about your view — content, cursor, alt screen, mouse mode, colors, window title, progress bar, and more:No more fighting over options and commands! Just set the fields:
An Actual Cursor
You can now control the cursor position, color, and shape right from your view function. Want it hidden? Just set
view.Cursor = nil.You can also use
tea.NewCursor(x, y)for a quick block cursor with default settings.Progress Bar Support
Now you can ask Bubble Tea to render a native progress bar for your application. Just set the
view.ProgressBarfield and Bubble Tea will take care of the rest.Synchronized Updates (Mode 2026)
Bubble Tea will try and use mode 2026 to push updates to the terminal. This mode helps reduce tearing and cursor flickering by atomically updating the terminal window once all the update sequences are pushed out and read by the terminal. This is enabled by default and there's nothing you need to do.
Better Terminal Unicode Support (mode 2027)
Now Bubble Tea will automatically enable mode 2027
on terminals that support it. This mode allows the terminal to properly handle wide Unicode
characters and emojis without breaking the layout of your app. Again, this is
enabled by default and there's nothing you need to do.
Native Clipboard Support
Bubble Tea now supports native clipboard operations, also known as OSC52. This means you can even copy and paste over SSH!
X11 and Wayland users can also use
tea.SetPrimaryClipboardto set the primary clipboard. Note that this is a very niche sort of thing and may or may not work on macOS, Windows, and other platforms without the notion of more than one clipboard.Terminal Colors
You can now read and set the terminal's foreground, background, and cursor colors. To change them, set
view.ForegroundColor,view.BackgroundColor, andview.Cursor.Colorin yourView()function.🌍 Environment Variables
Bubble Tea now sends you a
tea.EnvMsgat startup with the environment variables. This is especially handy for SSH apps whereos.Getenvwould give you the server's environment, not the client's.🔮 Raw Escape Sequences
For the power users out there, you can now send raw escape sequences directly to the terminal with
tea.Raw. This is great for querying terminal capabilities or doing things Bubble Tea doesn't have a built-in for (yet).Responses from the terminal will come back as messages in
Update. Just be sure you know what you're doing — with great power comes great terminal weirdness.📍 Cursor Position Queries
Need to know where the cursor is? Now you can ask.
📊 Terminal Mode Reports
You can query whether the terminal supports specific modes (like focus events or synchronized output) using DECRPM mode reports. Send a raw DECRQM request and listen for
tea.ModeReportMsg.Terminal Version and Name
Don't know what terminal you're running in?
$TERMis too vague? Bubble Tea now has atea.RequestTerminalVersioncommand that queries the terminal for its name and version using the XTVERSION escape sequence.Terminfo and Termcap Capabilities
Sometimes you need to know what capabilities the terminal has. Bubble Tea now has a
tea.RequestCapabilitycommand that queries the terminal for a specific terminfo/termcap capability.Detecting the Color Profile
Need to use the detected color profile in your app? Listen to
tea.ColorProfileMsginUpdate:Manually Applying a Color Profile
Want to manually set a color profile for testing? Now you can, on the program level.
Want to hard detect the color profile in Wish? We bet you do.
🪟 Window Size for Testing
When running tests or in non-interactive environments, you can now set the initial terminal size:
No more mocking terminals just to run your tests. Nice!
Use the Terminal's TTY
Sometimes your program will write to stdout while it's being piped or
redirected. In these cases, you might want to write directly to the terminal's
TTY instead of stdout because stdout might not be a terminal. Or your program
expects to read from stdin but stdin is being piped from another program.
In Bubble Tea v1, there wasn't a good way to do this. In the latter case, you
could use the
WithInputTTY()option to read from the terminal's TTY insteadof stdin. However, there was no easy way to write to the terminal's TTY instead
of stdout without fiddling with file descriptors.
In Bubble Tea v2, you can now simply use the global
OpenTTY()to open theterminal's TTY for reading and writing. You can then pass the TTY file handles
to the
WithInput()andWithOutput()options.Note that Bubble Tea v2 will always use the TTY for input when input is not specified
via
WithInput(...).Changelog
New!
Fixed
Docs
Other stuff
🌈 More on Bubble Tea v2
Ready to migrate? Head over to the Upgrade Guide for the full migration checklist.
Feedback
Have thoughts on Bubble Tea v2? We'd love to hear about it. Let us know on…
Part of Charm.
Charm热爱开源 • Charm loves open source • نحنُ نحب المصادر المفتوحة
Configuration
📅 Schedule: (UTC)
🚦 Automerge: Disabled by config. Please merge this manually once you are satisfied.
♻ Rebasing: Whenever PR becomes conflicted, or you tick the rebase/retry checkbox.
🔕 Ignore: Close this PR and you won't be reminded about this update again.
This PR was generated by Mend Renovate. View the repository job log.