You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Feature: Introduced support for the following new instance types on SageMaker Studio for JupyterLab and CodeEditor applications: m6i, m6id, m7i, c6i, c6id, c7i, r6i, r6id, r7i, and p5
Feature: Adding managed integrations APIs for IoT Device Management to onboard and control devices across different manufacturers, connectivity protocols and third party vendor clouds. APIs include managed thing operations, provisioning profile management, and cloud connector operations.
The update adds a new feature to automatically resize your textarea vertically as its content changes.
ta:=textarea.New()
ta.DynamicHeight=true// Enable dynamic resizingta.MinHeight=3// Minimum visible rowsta.MaxHeight=10// Maximum visible rowsta.MaxContentHeight=20// Maximum rows of content
We're thrilled to share Bubbles v2 with you! This release accompanies Bubble Tea v2 and Lip Gloss v2 and brings a ton of consistency, new features, and quality-of-life improvements across every component. Catch 'em all:
go get charm.land/bubbletea/v2
go get charm.land/bubbles/v2
go get charm.land/lipgloss/v2
There are a lot of changes in here, but we've found upgrading pretty easy, especially with a linter. Read on for the full breakdown!
[!NOTE]
When in doubt, check the examples for reference — they've all been updated for v2.
🏠 New Home
Bubbles v2 now lives at charm.land:
import"charm.land/bubbles/v2"
All sub-packages follow the same pattern: charm.land/bubbles/v2/viewport, charm.land/bubbles/v2/list, etc.
🎨 Light and Dark Styles
Some Bubbles, like help, offer default styles for both light and dark backgrounds. Since Lip Gloss v2 removes AdaptiveColor, choosing light or dark is now a manual process. You've got a couple of options.
🎩 The Best Way
Have Bubble Tea query the background color for you. This properly queries the correct inputs and outputs, and happens in lockstep with your application:
If you're using Wish you must do it this way to get the background color of the client.
🤠 The Quick Way
Use the compat package in Lip Gloss. It's less recommended because it contains blocking I/O that operates independently of Bubble Tea, and when used with Wish it won't detect the client's background:
h.Styles=help.DefaultLightStyles() // light mode!h.Styles=help.DefaultDarkStyles() // jk dark mode
This pattern applies to help, list, textarea, and textinput.
🔑 The Init You Know and Love is Back
After experimenting with a few different forms of Init during the alphas, we decided the v1 signature was the right call after all. Init was a bit too redundant for our tastes given that initialization already happens in New:
func (mModel) Init() tea.Cmd
✨ The Big Highlights
Getters and Setters Everywhere
All components now use getter/setter methods instead of exported Width and Height fields. This lets us do internal bookkeeping when things change, and it makes the API consistent across every Bubble:
All DefaultKeyMap package-level variables are now functions, so you get fresh values every time:
km:=textinput.DefaultKeyMap() // was textinput.DefaultKeyMapkm:=textarea.DefaultKeyMap() // was textarea.DefaultKeyMapkm:=paginator.DefaultKeyMap() // was paginator.DefaultKeyMap
Real Cursor Support 🖱️
Both textarea and textinput now support real terminal cursors! The feature is opt-in, so by default your programs will continue to use the easy-breezy virtual cursor. Set VirtualCursor to false and use Model.Cursor() for the real deal. Check out the textarea and textinput examples to see it in action.
Cleaned House 🧹
All previously deprecated symbols have been removed:
NewModel variants — just use New
spinner.Tick() — use Model.Tick() instead
paginator.UsePgUpPgDownKeys and friends — customize KeyMap directly
filepicker.DefaultStylesWithRenderer() — Lip Gloss is pure now, use DefaultStyles()
viewport.HighPerformanceRendering — no longer needed
runeutil and memoization packages moved to internal/ (they were never meant for public use anyway)
What's Changed: the Laundry List
🔮 Cursor
Model.Blink renamed to Model.IsBlinked for clarity
Model.BlinkCmd() renamed to Model.Blink()
Each cursor now gets a unique ID
📂 Filepicker
DefaultStylesWithRenderer() removed — Lip Gloss is pure now, so just use DefaultStyles()
Model.Height broken into SetHeight(int) / Height() int
❓ Help
Model.Width broken into SetWidth(int) / Width() int
New DefaultStyles(isDark bool), DefaultDarkStyles(), and DefaultLightStyles()
Defaults to dark background styles out of the box
🥕 List
DefaultStyles() and NewDefaultItemStyles() now take an isDark bool parameter
Styles.FilterPrompt and Styles.FilterCursor have been consolidated into Styles.Filter (a textinput.Styles)
Style type renamed to StyleState; new Styles struct groups Focused, Blurred, and Cursor
Model.SetCursor renamed to Model.SetCursorColumn
Model.Cursor is now func() *tea.Cursor for real cursor support
Model.VirtualCursor bool added — set to false when using a real cursor
New DefaultStyles(isDark bool), DefaultDarkStyles(), DefaultLightStyles()
New methods: Column(), ScrollYOffset(), ScrollPosition(), MoveToBeginning(), MoveToEnd()
Focus status now passed to SetPromptFunc
📜 Textinput
Most of the changes here bring textinput to parity with textarea, including real cursor support. Styling has been consolidated into a Styles struct with Focused and Blurred states:
DefaultKeyMap variable → DefaultKeyMap() function
Model.Width broken into SetWidth(int) / Width() int
Model.PromptStyle → StyleState.Prompt
Model.TextStyle → StyleState.Text
Model.PlaceholderStyle → StyleState.Placeholder
Model.CompletionStyle → StyleState.Suggestion
Model.Cursor is now func() *tea.Cursor for real cursor support
Highlight parts of what's being viewed with regex:
vp.SetHighlights(regexp.MustCompile("hello").FindAllStringIndex(vp.GetContent(), -1))
vp.HighlightNext() // highlight and navigate to next matchvp.HighlightPrevious() // highlight and navigate to previous matchvp.ClearHighlights() // clear all highlights
Let viewport handle soft wrapping for you:
vp.SoftWrap=truevp.SetContent("hello world from a very long line")
Or, if you need fine control, use SetContentLines with "virtual lines" containing \n — they're treated as soft wraps automatically.
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.
[!NOTE]
We don't take API changes lightly and strive to make the upgrade process as simple as possible. We believe the changes bring necessary improvements as well as pave the way for the future. If something feels way off, let us know.
❤️ Charm Land Import Path
We've updated our import paths to use vanity domains and use our domain to import Go packages.
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 the View struct. 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:
func (mModel) View() tea.View {
v:=tea.NewView("Hello, full screen!")
v.AltScreen=truereturnv
}
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.KeyboardEnhancementsMsg message 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.
func (mModel) Update(msg tea.Msg) (Model, tea.Cmd) {
switchmsg:=msg.(type) {
case tea.KeyboardEnhancementsMsg:
ifmsg.SupportsKeyDisambiguation() {
// More keys, please!
}
}
}
Key messages are now split into tea.KeyPressMsg and tea.KeyReleaseMsg. Use tea.KeyMsg to match against both. We've also replaced key.Type and key.Runes with key.Code and key.Text. Modifiers live in key.Mod now 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():
func (mModel) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
switchmsg:=msg.(type) {
case tea.KeyPressMsg:
switchmsg.String() {
case"space":
// Space bar returns "space" now :Dreturnm, tea.Println("You pressed the space bar!")
case"ctrl+c":
returnm, tea.SetClipboard("Howdy")
case"shift+enter":
// Awesome, right?case"ctrl+alt+super+enter":
// Yes, you can do that now!
}
}
}
The Key struct 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"). Unlike String(), 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.KeyMsg with a confusing msg.Paste flag. Now they're their own thing:
func (mModel) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
switchmsg:=msg.(type) {
case tea.PasteMsg:
// Here comes a paste!m.text+=msg.Contentcase tea.PasteStartMsg:
// The user started pasting.case tea.PasteEndMsg:
// The user stopped pasting.
}
}
Mouse Messages
We've improved the mouse API. Mouse messages are now split into tea.MouseClickMsg, tea.MouseReleaseMsg, tea.MouseWheelMsg, and tea.MouseMotionMsg. And mouse mode is set declaratively in your View():
func (mmodel) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
switchmsg:=msg.(type) {
case tea.MouseClickMsg:
ifmsg.Button==tea.MouseLeft {
// Clickety click
}
case tea.MouseWheelMsg:
// Scroll, scroll, scrollllll
}
returnm, nil
}
func (mmodel) View() tea.View {
v:=tea.NewView("Move that mouse around!")
v.MouseMode=tea.MouseModeAllMotion// or tea.MouseModeCellMotionreturnv
}
A Declarative View
In v1, View() returned a string. In v2, it returns a tea.View struct that lets you declare everything about your view — content, cursor, alt screen, mouse mode, colors, window title, progress bar, and more:
There is an OSV finding, that would be fixed by this PR - https://osv.dev/vulnerability/GO-2025-4116 the crypto/ssh/agent has a high vulnerability. It doesn't seem like we are using the methods that are part of this fix, but you can check it as well to be sure.
Looks like you're right Kalin, don't think the CVE applies to us because all changes are in the crypto/ssh/agent package. As far as I can tell, we don't use that package directly and I don't think we would based on the package description. The only place we use SSH is in the tsa package, but we roll our own ssh protocol and therefore wouldn't use the ssh-agent protocol used by the crypto/ssh/agent package.
# github.com/containerd/containerd/v2/pkg/oci
../gopath/pkg/mod/github.com/containerd/containerd/v2@v2.2.0/pkg/oci/spec_opts.go:1604:34: cannot use limit (variable of type int64) as *int64 value in assignment
# github.com/concourse/concourse/worker/runtime/spec
worker/runtime/spec/spec.go:197:11: cannot use maxPids (variable of type int64) as *int64 value in struct literal
Renovate failed to update an artifact related to this branch. You probably do not want to merge this PR as-is.
♻ Renovate will retry this branch, including artifacts, only when one of the following happens:
any of the package files in this branch needs updating, or
the branch becomes conflicted, or
you click the rebase/retry checkbox if found above, or
you rename this PR's title to start with "rebase!" to trigger it manually
The artifact failure details are included below:
File name: go.sum
Command failed: go get -t ./...
go: github.com/charmbracelet/bubbles/v2@v2.1.0: parsing go.mod:
module declares its path as: charm.land/bubbles/v2
but was required as: github.com/charmbracelet/bubbles/v2
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
This PR contains the following updates:
v1.61.0→v1.64.03ed7ad5→fd25714v3.61.0→v3.64.0v0.63.0→v0.66.0v1.41.1→v1.41.5v1.32.9→v1.32.14v1.19.9→v1.19.14v1.41.1→v1.41.5v1.67.8→v1.68.4v1.24.0→v1.24.3v11.3.1→v11.4.0v1.0.0→v2.1.0v1.3.10→v2.0.2v1.1.0→v2.0.2v1.12.0→v1.13.0v1.7.30→v2.2.2v2.2.1→v2.2.2v0.13.16→v0.13.19v1.18.0→v1.19.0v1.19.1→v1.19.2v1.22.0→v1.23.0v5.8.0→v5.9.1v1.18.4→v1.18.5v6.12.1→v6.12.2v1.40.0→v1.43.0v1.40.0→v1.43.0v1.40.0→v1.43.0v1.40.0→v1.43.0v1.40.0→v1.43.0v2.4.3→v2.4.4v0.48.0→v0.49.0v0.35.0→v0.36.0v0.19.0→v0.20.0v0.41.0→v0.42.0v0.40.0→v0.41.0v0.14.0→v0.15.0v1.79.3→v1.80.0v0.35.1→v0.35.3v0.35.1→v0.35.3v0.35.1→v0.35.3Release Notes
cloudfoundry/clock (code.cloudfoundry.org/clock)
v1.64.0: 1.64.0Compare Source
v1.63.0: 1.63.0Compare Source
v1.62.0: 1.62.0Compare Source
cloudfoundry/lager (code.cloudfoundry.org/lager/v3)
v3.64.0: 3.64.0Compare Source
v3.63.0: 3.63.0Compare Source
v3.62.0: 3.62.0Compare Source
cloudfoundry/localip (code.cloudfoundry.org/localip)
v0.66.0: 0.66.0Compare Source
v0.65.0: 0.65.0Compare Source
v0.64.0: 0.64.0Compare Source
aws/aws-sdk-go-v2 (github.com/aws/aws-sdk-go-v2)
v1.41.5Compare Source
Module Highlights
github.com/aws/aws-sdk-go-v2/service/bedrockagentruntime: v1.5.0github.com/aws/aws-sdk-go-v2/service/costexplorer: v1.37.0github.com/aws/aws-sdk-go-v2/service/ec2: v1.154.0github.com/aws/aws-sdk-go-v2/service/ecs: v1.41.5github.com/aws/aws-sdk-go-v2/service/finspace: v1.24.0v1.41.4Compare Source
General Highlights
Module Highlights
github.com/aws/aws-sdk-go-v2/feature/dynamodb/attributevalue: v1.13.12github.com/aws/aws-sdk-go-v2/service/codebuild: v1.32.0github.com/aws/aws-sdk-go-v2/service/ec2: v1.153.0github.com/aws/aws-sdk-go-v2/service/ecs: v1.41.4github.com/aws/aws-sdk-go-v2/service/emrcontainers: v1.26.0github.com/aws/aws-sdk-go-v2/service/globalaccelerator: v1.23.0github.com/aws/aws-sdk-go-v2/service/medialive: v1.49.0github.com/aws/aws-sdk-go-v2/service/sagemaker: v1.134.0v1.41.3Compare Source
v1.41.2Compare Source
Module Highlights
github.com/aws/aws-sdk-go-v2/service/deadline: v1.14.0github.com/aws/aws-sdk-go-v2/service/ec2: v1.227.0github.com/aws/aws-sdk-go-v2/service/iotmanagedintegrations: v1.1.0github.com/aws/aws-sdk-go-v2/service/keyspaces: v1.19.0github.com/aws/aws-sdk-go-v2/service/keyspacesstreams: v1.0.0github.com/aws/aws-sdk-go-v2/service/kms: v1.41.2github.com/aws/aws-sdk-go-v2/service/qbusiness: v1.27.0github.com/aws/aws-sdk-go-v2/service/workspaces: v1.58.0aws/smithy-go (github.com/aws/smithy-go)
v1.24.3Compare Source
General Highlights
Module Highlights
github.com/aws/smithy-go: v1.24.3github.com/aws/smithy-go/aws-http-auth: v1.1.3v1.24.2: Release (2026-02-27)Compare Source
Release (2026-02-27)
General Highlights
v1.24.1Compare Source
General Highlights
Module Highlights
github.com/aws/smithy-go: v1.24.1caarlos0/env (github.com/caarlos0/env/v11)
v11.4.0Compare Source
Changelog
New Features
2be9960: feat: option to set defaults for zero values only (#325) (@dnovikoff)Bug fixes
d3505f1: fix: all new lint issues, update golangci-lint (@caarlos0)aaa4511: fix: lint issues (@caarlos0)Documentation updates
8917d78: docs: clarify example a bit (@caarlos0)Other work
7b10cf5: ci(deps): bump github/codeql-action in the actions group (#400) (@dependabot[bot])c98ad84: ci(deps): bump github/codeql-action in the actions group (#410) (@dependabot[bot])2ca9b08: ci(deps): bump the actions group with 2 updates (#393) (@dependabot[bot])cd5c220: ci(deps): bump the actions group with 2 updates (#396) (@dependabot[bot])4d25a46: ci(deps): bump the actions group with 2 updates (#402) (@dependabot[bot])c660cc9: ci(deps): bump the actions group with 2 updates (#403) (@dependabot[bot])3a3ea05: ci(deps): bump the actions group with 2 updates (#405) (@dependabot[bot])d28373e: ci(deps): bump the actions group with 2 updates (#408) (@dependabot[bot])7b50056: ci(deps): bump the actions group with 3 updates (#397) (@dependabot[bot])6b2db30: ci(deps): bump the actions group with 3 updates (#399) (@dependabot[bot])f33230e: ci(deps): bump the actions group with 3 updates (#404) (@dependabot[bot])2dc7aec: ci(sec): add codeql, govulncheck, grype (@caarlos0)82412ce: ci: build perms (@caarlos0)02495c4: ci: build perms (@caarlos0)e5b3c2c: ci: lint workflow perms (@caarlos0)6690dfb: ci: pin github actions versions (@caarlos0)548a7a6: ci: update dependabot (@caarlos0)Released with GoReleaser Pro!
charmbracelet/bubbles (github.com/charmbracelet/bubbles)
v2.1.0Compare Source
Shrink ’n’ grow your textareas
The update adds a new feature to automatically resize your
textareavertically as its content changes.Piece of cake, right?
Enjoy! 💘
Changelog
New!
f1daacf: feat(textarea): dynamic height (#910) (@meowgorithm)Thoughts? Questions? We love hearing from you. Feel free to reach out on X, Discord, Slack, The Fediverse, Bluesky.
v2.0.0Compare Source
Bubbles v2 is here! 🫧
We're thrilled to share Bubbles v2 with you! This release accompanies Bubble Tea v2 and Lip Gloss v2 and brings a ton of consistency, new features, and quality-of-life improvements across every component. Catch 'em all:
You can also check the Upgrade Guide for more info.
There are a lot of changes in here, but we've found upgrading pretty easy, especially with a linter. Read on for the full breakdown!
🏠 New Home
Bubbles v2 now lives at
charm.land:All sub-packages follow the same pattern:
charm.land/bubbles/v2/viewport,charm.land/bubbles/v2/list, etc.🎨 Light and Dark Styles
Some Bubbles, like
help, offer default styles for both light and dark backgrounds. Since Lip Gloss v2 removesAdaptiveColor, choosing light or dark is now a manual process. You've got a couple of options.🎩 The Best Way
Have Bubble Tea query the background color for you. This properly queries the correct inputs and outputs, and happens in lockstep with your application:
If you're using Wish you must do it this way to get the background color of the client.
🤠 The Quick Way
Use the
compatpackage in Lip Gloss. It's less recommended because it contains blocking I/O that operates independently of Bubble Tea, and when used with Wish it won't detect the client's background:👀 Or Just Pick One
This pattern applies to
help,list,textarea, andtextinput.🔑 The Init You Know and Love is Back
After experimenting with a few different forms of
Initduring the alphas, we decided the v1 signature was the right call after all.Initwas a bit too redundant for our tastes given that initialization already happens inNew:✨ The Big Highlights
Getters and Setters Everywhere
All components now use getter/setter methods instead of exported
WidthandHeightfields. This lets us do internal bookkeeping when things change, and it makes the API consistent across every Bubble:Affected:
filepicker,help,progress,table,textinput,viewport.Functional Options
Constructors now use the functional options pattern instead of positional args or separate constructor functions:
DefaultKeyMap is a Function Now
All
DefaultKeyMappackage-level variables are now functions, so you get fresh values every time:Real Cursor Support 🖱️
Both
textareaandtextinputnow support real terminal cursors! The feature is opt-in, so by default your programs will continue to use the easy-breezy virtual cursor. SetVirtualCursortofalseand useModel.Cursor()for the real deal. Check out the textarea and textinput examples to see it in action.Cleaned House 🧹
All previously deprecated symbols have been removed:
NewModelvariants — just useNewspinner.Tick()— useModel.Tick()insteadpaginator.UsePgUpPgDownKeysand friends — customizeKeyMapdirectlyfilepicker.DefaultStylesWithRenderer()— Lip Gloss is pure now, useDefaultStyles()viewport.HighPerformanceRendering— no longer neededruneutilandmemoizationpackages moved tointernal/(they were never meant for public use anyway)What's Changed: the Laundry List
🔮 Cursor
Model.Blinkrenamed toModel.IsBlinkedfor clarityModel.BlinkCmd()renamed toModel.Blink()📂 Filepicker
DefaultStylesWithRenderer()removed — Lip Gloss is pure now, so just useDefaultStyles()Model.Heightbroken intoSetHeight(int)/Height() int❓ Help
Model.Widthbroken intoSetWidth(int)/Width() intDefaultStyles(isDark bool),DefaultDarkStyles(), andDefaultLightStyles()🥕 List
DefaultStyles()andNewDefaultItemStyles()now take anisDark boolparameterStyles.FilterPromptandStyles.FilterCursorhave been consolidated intoStyles.Filter(atextinput.Styles)GlobalIndexhelper added📄 Paginator
DefaultKeyMapvariable →DefaultKeyMap()functionUsePgUpPgDownKeys,UseLeftRightKeys, etc.) removed — customizeKeyMapdirectly🌈 Progress
This one got the biggest makeover!
WithGradient/WithScaledGradient→WithColors(...color.Color)— pass 2+ colors for blendingWithSolidFill(string)→WithColors(color)— pass a single color for a solid fillWithDefaultGradient()→WithDefaultBlend()WithScaled(bool)to scale the blend to fit only the filled portionWithColorFunc(func(total, current float64) color.Color)for fully dynamic coloringWithColorProfileremoved — Bubble Tea handles this automatically nowModel.FullColorandModel.EmptyColorchanged fromstringtoimage/color.ColorModel.Widthbroken intoSetWidth(int)/Width() intModel.Updatenow returnsModelinstead oftea.Model🌀 Spinner
Tick()package-level function removed — useModel.Tick()instead⏱️ Stopwatch
NewWithInterval(d)removed — useNew(WithInterval(d))instead🔢 Table
Model.Width/Model.Heightreplaced with getter/setter methodsansi.Truncateinstead ofrunewidth.Truncate✏️ Textarea
The big change here is real cursor support — but that's opt-in, so by default your programs will keep using the virtual cursor.
DefaultKeyMapvariable →DefaultKeyMap()functionPageUp/PageDownkey bindingsModel.FocusedStyle/Model.BlurredStyle→Model.Styles.Focused/Model.Styles.BlurredStyletype renamed toStyleState; newStylesstruct groupsFocused,Blurred, andCursorModel.SetCursorrenamed toModel.SetCursorColumnModel.Cursoris nowfunc() *tea.Cursorfor real cursor supportModel.VirtualCursorbool added — set tofalsewhen using a real cursorDefaultStyles(isDark bool),DefaultDarkStyles(),DefaultLightStyles()Column(),ScrollYOffset(),ScrollPosition(),MoveToBeginning(),MoveToEnd()SetPromptFunc📜 Textinput
Most of the changes here bring
textinputto parity withtextarea, including real cursor support. Styling has been consolidated into aStylesstruct withFocusedandBlurredstates:DefaultKeyMapvariable →DefaultKeyMap()functionModel.Widthbroken intoSetWidth(int)/Width() intModel.PromptStyle→StyleState.PromptModel.TextStyle→StyleState.TextModel.PlaceholderStyle→StyleState.PlaceholderModel.CompletionStyle→StyleState.SuggestionModel.Cursoris nowfunc() *tea.Cursorfor real cursor supportModel.VirtualCursor()/SetVirtualCursor(bool)addedModel.Styles()/SetStyles(Styles)addedDefaultStyles(isDark bool),DefaultDarkStyles(),DefaultLightStyles()⏲️ Timer
NewWithInterval(timeout, interval)removed — useNew(timeout, WithInterval(interval))📦 Viewport
viewportgot a ton of love in v2. Let's dive in!Breaking changes:
New(width, height int)→New(...Option)withWithWidth/WithHeightModel.Width,Model.Height,Model.YOffsetreplaced with getter/setter methodsHighPerformanceRenderingremovedShiny new features:
You can now scroll horizontally with the left and right arrow keys, and set up a custom gutter column for things like line numbers:
Highlight parts of what's being viewed with regex:
Let viewport handle soft wrapping for you:
Or, if you need fine control, use
SetContentLineswith "virtual lines" containing\n— they're treated as soft wraps automatically.Also new:
GetContent()to retrieve contentFillHeightto pad the viewport with empty linesStyleLineFuncfor per-line stylingHighlightStyleandSelectedHighlightStylefor highlight appearanceChangelog
Fixed
ansi.Truncateinstead ofrunewidth.Truncate(#884) (@jedevc)Docs
Other stuff
💝 That's a wrap!
Feel free to reach out, ask questions, give feedback, and let us know how it's going. We'd love to know what you think.
Part of Charm.
Charm热爱开源 • Charm loves open source • نحنُ نحب المصادر المفتوحة
charmbracelet/bubbletea (github.com/charmbracelet/bubbletea)
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: