fix(deps): update module github.com/charmbracelet/bubbles to v2 #132

Closed
Renovate-Clanker wants to merge 1 commits from renovate/github.com-charmbracelet-bubbles-2.x into main
Collaborator

This PR contains the following updates:

Package Change Age Confidence
github.com/charmbracelet/bubbles v1.0.0v2.1.0 age confidence

Release Notes

charmbracelet/bubbles (github.com/charmbracelet/bubbles)

v2.1.0

Compare Source

Shrink ’n’ grow your textareas

The update adds a new feature to automatically resize your textarea vertically as its content changes.

ta := textarea.New()
ta.DynamicHeight = true   // Enable dynamic resizing
ta.MinHeight = 3          // Minimum visible rows
ta.MaxHeight = 10         // Maximum visible rows
ta.MaxContentHeight = 20  // Maximum rows of content

Piece of cake, right?

Enjoy! 💘

Changelog

New!

The Charm logo

Thoughts? Questions? We love hearing from you. Feel free to reach out on X, Discord, Slack, The Fediverse, Bluesky.

v2.0.0

Compare Source

bubbles-v2-block

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:

go get charm.land/bubbletea/v2
go get charm.land/bubbles/v2
go get charm.land/lipgloss/v2

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!

[!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:

func (m model) Init() tea.Cmd {
    return tea.RequestBackgroundColor
}

func (m model) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
    switch msg := msg.(type) {
    case tea.BackgroundColorMsg:
        m.help.Styles = help.DefaultStyles(msg.IsDark())
        return m, nil
    }
    // ...
}

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:

import "charm.land/lipgloss/v2/compat"

var hasDarkBG = compat.HasDarkBackground()

h := help.New()
h.Styles = help.DefaultStyles(hasDarkBG)
👀 Or Just Pick One
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 (m Model) 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:

// Before
vp.Width = 40
fmt.Println(vp.Width)

// After
vp.SetWidth(40)
fmt.Println(vp.Width())

Affected: filepicker, help, progress, table, textinput, viewport.

Functional Options

Constructors now use the functional options pattern instead of positional args or separate constructor functions:

vp := viewport.New(viewport.WithWidth(80), viewport.WithHeight(24))
sw := stopwatch.New(stopwatch.WithInterval(500 * time.Millisecond))
t := timer.New(30*time.Second, timer.WithInterval(100*time.Millisecond))
DefaultKeyMap is a Function Now

All DefaultKeyMap package-level variables are now functions, so you get fresh values every time:

km := textinput.DefaultKeyMap()   // was textinput.DefaultKeyMap
km := textarea.DefaultKeyMap()    // was textarea.DefaultKeyMap
km := 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)
  • GlobalIndex helper added
📄 Paginator
  • DefaultKeyMap variable → DefaultKeyMap() function
  • Deprecated fields (UsePgUpPgDownKeys, UseLeftRightKeys, etc.) removed — customize KeyMap directly
🌈 Progress

This one got the biggest makeover!

  • Complete color API overhaul:
    • WithGradient / WithScaledGradientWithColors(...color.Color) — pass 2+ colors for blending
    • WithSolidFill(string)WithColors(color) — pass a single color for a solid fill
    • WithDefaultGradient()WithDefaultBlend()
    • New WithScaled(bool) to scale the blend to fit only the filled portion
    • New WithColorFunc(func(total, current float64) color.Color) for fully dynamic coloring
    • WithColorProfile removed — Bubble Tea handles this automatically now
  • Model.FullColor and Model.EmptyColor changed from string to image/color.Color
  • Model.Width broken into SetWidth(int) / Width() int
  • Model.Update now returns Model instead of tea.Model
  • Improved blend algorithm with support for multiple color stops — special thanks to the legendary @​lrstanley!
🌀 Spinner
  • Tick() package-level function removed — use Model.Tick() instead
⏱️ Stopwatch
  • NewWithInterval(d) removed — use New(WithInterval(d)) instead
  • Debounced tick messages
🔢 Table
  • Model.Width / Model.Height replaced with getter/setter methods
  • Uses ansi.Truncate instead of runewidth.Truncate
  • Fixed a critical out-of-bounds cursor bug — thanks @​s0ders!
✏️ 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.

  • DefaultKeyMap variable → DefaultKeyMap() function
  • New PageUp / PageDown key bindings
  • Model.FocusedStyle / Model.BlurredStyleModel.Styles.Focused / Model.Styles.Blurred
  • 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.PromptStyleStyleState.Prompt
  • Model.TextStyleStyleState.Text
  • Model.PlaceholderStyleStyleState.Placeholder
  • Model.CompletionStyleStyleState.Suggestion
  • Model.Cursor is now func() *tea.Cursor for real cursor support
  • Model.VirtualCursor() / SetVirtualCursor(bool) added
  • Model.Styles() / SetStyles(Styles) added
  • New DefaultStyles(isDark bool), DefaultDarkStyles(), DefaultLightStyles()
  • Exposed matched suggestions and suggestion index
⏲️ Timer
  • NewWithInterval(timeout, interval) removed — use New(timeout, WithInterval(interval))
  • Debounced tick messages
📦 Viewport

viewport got a ton of love in v2. Let's dive in!

Breaking changes:

  • New(width, height int)New(...Option) with WithWidth / WithHeight
  • Model.Width, Model.Height, Model.YOffset replaced with getter/setter methods
  • HighPerformanceRendering removed

Shiny 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:

vp := viewport.New()
vp.SetContent("hello world")

// Show line numbers:
vp.LeftGutterFunc = func(info viewport.GutterContext) string {
    if info.Soft {
        return "     │ "
    }
    if info.Index >= info.TotalLines {
        return "   ~ │ "
    }
    return fmt.Sprintf("%4d │ ", info.Index+1)
}

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 match
vp.HighlightPrevious()  // highlight and navigate to previous match
vp.ClearHighlights()    // clear all highlights

Let viewport handle soft wrapping for you:

vp.SoftWrap = true
vp.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.

Also new:

  • Horizontal mouse wheel scrolling (thanks @​UnseenBook!)
  • GetContent() to retrieve content
  • FillHeight to pad the viewport with empty lines
  • StyleLineFunc for per-line styling
  • HighlightStyle and SelectedHighlightStyle for highlight appearance

Changelog

Fixed
  • f744b929dddecc7863cf78605c5bfc396d90abc3: fix(ci): use local golangci-lint config (@​aymanbagabas)
  • 251e612949595b006e0e4739029d45e32c6b34b6: fix(filepicker): fix a panic due to an unchecked assertion (#​891) (@​meowgorithm)
  • f3f0ca0fe2f05b56e5a0c69b226b4d752c5e8f4a: fix(lint): exclude var-naming rule for revive (@​aymanbagabas)
  • d004225e8c3b8c8ddb14a76a5101728d666396f3: fix(table): use ansi.Truncate instead of runewidth.Truncate (#​884) (@​jedevc)
  • 93a004ab70c8ea979940b2720b3993c8f68bf8dc: fix(viewport): optimize subline splitting by skipping lines without line endings (@​aymanbagabas)
  • d0166363eb8176b331de98dba1d6e997560f216f: fix: changed 'recieve' to 'receive' for 100% quality of Go Report Card (#​881) (@​Atennop1)
  • af98365cc63af118d838e05522f8dddf16ad827e: fix: lint issues (@​aymanbagabas)
Docs
  • c81d525337e1a059c4343cf65a02eea020470a48: docs(readme): update for v2 (#​888) (@​aymanbagabas)
  • 6a799f4d58cc0eaeab0874f4ce9c98b5a922bd01: docs(readme): update header image, minor corrections (@​meowgorithm)
  • 24081b3590e746db4efa2ec09e31a85e2c078427: docs: add v2 upgrade and changes guide (#​885) (@​aymanbagabas)
  • 3a5ea3e2eb42aa064bb4a0ffe3262cb2b8a1f19b: docs: update mascot image (@​aymanbagabas)
Other stuff
  • ae99f46cec66f45862c2d953bb1af31efdc4f073: feat(v2/textarea): expose Column(), clarify 0-indexing (#​875) (@​caarlos0)

💝 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.

The Charm logo

Charm热爱开源 • Charm loves open source • نحنُ نحب المصادر المفتوحة


Configuration

📅 Schedule: Branch creation - At any time (no schedule defined), Automerge - At any time (no schedule defined).

🚦 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.


  • If you want to rebase/retry this PR, check this box

This PR has been generated by Renovate Bot.

This PR contains the following updates: | Package | Change | [Age](https://docs.renovatebot.com/merge-confidence/) | [Confidence](https://docs.renovatebot.com/merge-confidence/) | |---|---|---|---| | [github.com/charmbracelet/bubbles](https://github.com/charmbracelet/bubbles) | `v1.0.0` → `v2.1.0` | ![age](https://developer.mend.io/api/mc/badges/age/go/github.com%2fcharmbracelet%2fbubbles/v2.1.0?slim=true) | ![confidence](https://developer.mend.io/api/mc/badges/confidence/go/github.com%2fcharmbracelet%2fbubbles/v1.0.0/v2.1.0?slim=true) | --- ### Release Notes <details> <summary>charmbracelet/bubbles (github.com/charmbracelet/bubbles)</summary> ### [`v2.1.0`](https://github.com/charmbracelet/bubbles/releases/tag/v2.1.0) [Compare Source](https://github.com/charmbracelet/bubbles/compare/v2.0.0...v2.1.0) ### Shrink ’n’ grow your textareas The update adds a new feature to automatically resize your `textarea` vertically as its content changes. ```go ta := textarea.New() ta.DynamicHeight = true // Enable dynamic resizing ta.MinHeight = 3 // Minimum visible rows ta.MaxHeight = 10 // Maximum visible rows ta.MaxContentHeight = 20 // Maximum rows of content ``` Piece of cake, right? <p><img width="500" src="https://github.com/user-attachments/assets/6f990de7-833d-4742-b3de-c87ffff8b77e" /></p> Enjoy! 💘 #### Changelog ##### New! - [`f1daacf`](https://github.com/charmbracelet/bubbles/commit/f1daacfa0cfee07e31a12498078426d275aa5286): feat(textarea): dynamic height ([#&#8203;910](https://github.com/charmbracelet/bubbles/issues/910)) ([@&#8203;meowgorithm](https://github.com/meowgorithm)) *** <a href="https://charm.land/"><img alt="The Charm logo" src="https://stuff.charm.sh/charm-banner-next.jpg" width="400"></a> Thoughts? Questions? We love hearing from you. Feel free to reach out on [X](https://x.com/charmcli), [Discord](https://charm.land/discord), [Slack](https://charm.land/slack), [The Fediverse](https://mastodon.social/@&#8203;charmcli), [Bluesky](https://bsky.app/profile/charm.land). ### [`v2.0.0`](https://github.com/charmbracelet/bubbles/releases/tag/v2.0.0) [Compare Source](https://github.com/charmbracelet/bubbles/compare/v1.0.0...v2.0.0) ![bubbles-v2-block](https://github.com/user-attachments/assets/3ac0db88-ff60-4c8b-a056-18831efcae0c) ### Bubbles v2 is here! 🫧 We're thrilled to share Bubbles v2 with you! This release accompanies [Bubble Tea v2](https://github.com/charmbracelet/bubbletea) and [Lip Gloss v2](https://github.com/charmbracelet/lipgloss) and brings a ton of consistency, new features, and quality-of-life improvements across every component. Catch 'em all: ```sh go get charm.land/bubbletea/v2 go get charm.land/bubbles/v2 go get charm.land/lipgloss/v2 ``` You can also check the [Upgrade Guide](UPGRADE_GUIDE_V2.md) 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! > \[!NOTE] > When in doubt, check the [examples](https://github.com/charmbracelet/bubbletea/tree/v2-exp/examples) for reference — they've all been updated for v2. #### 🏠 New Home Bubbles v2 now lives at `charm.land`: ```go 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: ```go func (m model) Init() tea.Cmd { return tea.RequestBackgroundColor } func (m model) Update(msg tea.Msg) (tea.Model, tea.Cmd) { switch msg := msg.(type) { case tea.BackgroundColorMsg: m.help.Styles = help.DefaultStyles(msg.IsDark()) return m, nil } // ... } ``` If you're using [Wish](https://github.com/charmbracelet/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: ```go import "charm.land/lipgloss/v2/compat" var hasDarkBG = compat.HasDarkBackground() h := help.New() h.Styles = help.DefaultStyles(hasDarkBG) ``` ##### 👀 Or Just Pick One ```go 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`: ```go func (m Model) 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: ```go // Before vp.Width = 40 fmt.Println(vp.Width) // After vp.SetWidth(40) fmt.Println(vp.Width()) ``` Affected: `filepicker`, `help`, `progress`, `table`, `textinput`, `viewport`. ##### Functional Options Constructors now use the functional options pattern instead of positional args or separate constructor functions: ```go vp := viewport.New(viewport.WithWidth(80), viewport.WithHeight(24)) sw := stopwatch.New(stopwatch.WithInterval(500 * time.Millisecond)) t := timer.New(30*time.Second, timer.WithInterval(100*time.Millisecond)) ``` ##### DefaultKeyMap is a Function Now All `DefaultKeyMap` package-level variables are now functions, so you get fresh values every time: ```go km := textinput.DefaultKeyMap() // was textinput.DefaultKeyMap km := textarea.DefaultKeyMap() // was textarea.DefaultKeyMap km := 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](https://github.com/charmbracelet/bubbletea/blob/v2-exp/examples/textarea/main.go) and [textinput](https://github.com/charmbracelet/bubbletea/blob/v2-exp/examples/textinput/main.go) 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`) - `GlobalIndex` helper added ##### 📄 Paginator - `DefaultKeyMap` variable → `DefaultKeyMap()` function - Deprecated fields (`UsePgUpPgDownKeys`, `UseLeftRightKeys`, etc.) removed — customize `KeyMap` directly ##### 🌈 Progress This one got the biggest makeover! - **Complete color API overhaul:** - `WithGradient` / `WithScaledGradient` → `WithColors(...color.Color)` — pass 2+ colors for blending - `WithSolidFill(string)` → `WithColors(color)` — pass a single color for a solid fill - `WithDefaultGradient()` → `WithDefaultBlend()` - New `WithScaled(bool)` to scale the blend to fit only the filled portion - New `WithColorFunc(func(total, current float64) color.Color)` for fully dynamic coloring - `WithColorProfile` removed — Bubble Tea handles this automatically now - `Model.FullColor` and `Model.EmptyColor` changed from `string` to `image/color.Color` - `Model.Width` broken into `SetWidth(int)` / `Width() int` - `Model.Update` now returns `Model` instead of `tea.Model` - Improved blend algorithm with support for multiple color stops — special thanks to the legendary [@&#8203;lrstanley](https://github.com/lrstanley)! ##### 🌀 Spinner - `Tick()` package-level function removed — use `Model.Tick()` instead ##### ⏱️ Stopwatch - `NewWithInterval(d)` removed — use `New(WithInterval(d))` instead - Debounced tick messages ##### 🔢 Table - `Model.Width` / `Model.Height` replaced with getter/setter methods - Uses `ansi.Truncate` instead of `runewidth.Truncate` - Fixed a critical out-of-bounds cursor bug — thanks [@&#8203;s0ders](https://github.com/s0ders)! ##### ✏️ 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. - `DefaultKeyMap` variable → `DefaultKeyMap()` function - New `PageUp` / `PageDown` key bindings - `Model.FocusedStyle` / `Model.BlurredStyle` → `Model.Styles.Focused` / `Model.Styles.Blurred` - `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 - `Model.VirtualCursor()` / `SetVirtualCursor(bool)` added - `Model.Styles()` / `SetStyles(Styles)` added - New `DefaultStyles(isDark bool)`, `DefaultDarkStyles()`, `DefaultLightStyles()` - Exposed matched suggestions and suggestion index ##### ⏲️ Timer - `NewWithInterval(timeout, interval)` removed — use `New(timeout, WithInterval(interval))` - Debounced tick messages ##### 📦 Viewport `viewport` got a *ton* of love in v2. Let's dive in! **Breaking changes:** - `New(width, height int)` → `New(...Option)` with `WithWidth` / `WithHeight` - `Model.Width`, `Model.Height`, `Model.YOffset` replaced with getter/setter methods - `HighPerformanceRendering` removed **Shiny 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: ```go vp := viewport.New() vp.SetContent("hello world") // Show line numbers: vp.LeftGutterFunc = func(info viewport.GutterContext) string { if info.Soft { return " │ " } if info.Index >= info.TotalLines { return " ~ │ " } return fmt.Sprintf("%4d │ ", info.Index+1) } ``` Highlight parts of what's being viewed with regex: ```go vp.SetHighlights(regexp.MustCompile("hello").FindAllStringIndex(vp.GetContent(), -1)) vp.HighlightNext() // highlight and navigate to next match vp.HighlightPrevious() // highlight and navigate to previous match vp.ClearHighlights() // clear all highlights ``` Let viewport handle soft wrapping for you: ```go vp.SoftWrap = true vp.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. Also new: - Horizontal mouse wheel scrolling (thanks [@&#8203;UnseenBook](https://github.com/UnseenBook)!) - `GetContent()` to retrieve content - `FillHeight` to pad the viewport with empty lines - `StyleLineFunc` for per-line styling - `HighlightStyle` and `SelectedHighlightStyle` for highlight appearance <details> <summary> #### Changelog </summary> ##### Fixed * f744b929dddecc7863cf78605c5bfc396d90abc3: fix(ci): use local golangci-lint config (@&#8203;aymanbagabas) * 251e612949595b006e0e4739029d45e32c6b34b6: fix(filepicker): fix a panic due to an unchecked assertion (#&#8203;891) (@&#8203;meowgorithm) * f3f0ca0fe2f05b56e5a0c69b226b4d752c5e8f4a: fix(lint): exclude var-naming rule for revive (@&#8203;aymanbagabas) * d004225e8c3b8c8ddb14a76a5101728d666396f3: fix(table): use `ansi.Truncate` instead of `runewidth.Truncate` (#&#8203;884) (@&#8203;jedevc) * 93a004ab70c8ea979940b2720b3993c8f68bf8dc: fix(viewport): optimize subline splitting by skipping lines without line endings (@&#8203;aymanbagabas) * d0166363eb8176b331de98dba1d6e997560f216f: fix: changed 'recieve' to 'receive' for 100% quality of Go Report Card (#&#8203;881) (@&#8203;Atennop1) * af98365cc63af118d838e05522f8dddf16ad827e: fix: lint issues (@&#8203;aymanbagabas) ##### Docs * c81d525337e1a059c4343cf65a02eea020470a48: docs(readme): update for v2 (#&#8203;888) (@&#8203;aymanbagabas) * 6a799f4d58cc0eaeab0874f4ce9c98b5a922bd01: docs(readme): update header image, minor corrections (@&#8203;meowgorithm) * 24081b3590e746db4efa2ec09e31a85e2c078427: docs: add v2 upgrade and changes guide (#&#8203;885) (@&#8203;aymanbagabas) * 3a5ea3e2eb42aa064bb4a0ffe3262cb2b8a1f19b: docs: update mascot image (@&#8203;aymanbagabas) ##### Other stuff * ae99f46cec66f45862c2d953bb1af31efdc4f073: feat(v2/textarea): expose Column(), clarify 0-indexing (#&#8203;875) (@&#8203;caarlos0) </details> *** #### 💝 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. - [Discord](https://charm.land/discord) - [Matrix](https://charm.land/matrix) - [Email](mailto:vt100@&#8203;charm.land) *** Part of [Charm](https://charm.land). <a href="https://charm.land/"><img alt="The Charm logo" src="https://stuff.charm.sh/charm-badge.jpg" width="400"></a> Charm热爱开源 • Charm loves open source • نحنُ نحب المصادر المفتوحة </details> --- ### Configuration 📅 **Schedule**: Branch creation - At any time (no schedule defined), Automerge - At any time (no schedule defined). 🚦 **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. --- - [ ] <!-- rebase-check -->If you want to rebase/retry this PR, check this box --- This PR has been generated by [Renovate Bot](https://github.com/renovatebot/renovate). <!--renovate-debug:eyJjcmVhdGVkSW5WZXIiOiI0My4xMDAuMiIsInVwZGF0ZWRJblZlciI6IjQzLjEwMC4yIiwidGFyZ2V0QnJhbmNoIjoibWFpbiIsImxhYmVscyI6W119-->
Author
Collaborator

⚠️ Artifact update problem

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

### ⚠️ Artifact update problem 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 ```
Renovate-Clanker added 1 commit 2026-04-01 21:30:57 +07:00
fix(deps): update module github.com/charmbracelet/bubbles to v2
renovate/artifacts Artifact file update failure
Tests / Run Tests (pull_request) Failing after 11s
54473e9e35
Renovate-Clanker force-pushed renovate/github.com-charmbracelet-bubbles-2.x from 0cef3a833d to 54473e9e35 2026-04-01 21:30:57 +07:00 Compare
bagas closed this pull request 2026-04-01 21:33:32 +07:00
Author
Collaborator

Renovate Ignore Notification

Because you closed this PR without merging, Renovate will ignore this update. You will not get PRs for any future 2.x releases. But if you manually upgrade to 2.x then Renovate will re-enable minor and patch updates automatically.

If you accidentally closed this PR, or if you changed your mind: rename this PR to get a fresh replacement PR.

### Renovate Ignore Notification Because you closed this PR without merging, Renovate will ignore this update. You will not get PRs for *any* future `2.x` releases. But if you manually upgrade to `2.x` then Renovate will re-enable `minor` and `patch` updates automatically. If you accidentally closed this PR, or if you changed your mind: rename this PR to get a fresh replacement PR.
Some checks are pending
renovate/artifacts Artifact file update failure
Tests / Run Tests (pull_request) Failing after 11s

Pull request closed

Sign in to join this conversation.
No Reviewers
No Label
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: bagas/tunnel-please#132