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
Human speaking here! Apologies for the full-blown AI-generated bug report, but this was sufficiently complex for me to track down and debug what was going on that I needed to get an LLM involved and help me write up the issue.
Describe the bug
bubbletea v2's cursedRenderer auto-detects the terminal's TAB0 flag via termios and replaces runs of plain space cells with \t characters as a cursor-movement optimization. This silently corrupts any application output that relies on precise space-based column alignment. The application's View() returns properly padded strings with spaces, but the renderer replaces those spaces with tab characters before writing to the terminal. There is no opt-out mechanism.
Setup
OS: macOS v25.3.0 - TAB0 is the default termios output flag
Shell: fish
Terminal Emulator: iTerm2 (but should reproduce in other terms too)
Terminal Multiplexer: N/A
bubbletea: v2.0.1
To Reproduce
Create a bubbletea v2 app that renders space-padded columns in View() (e.g. a table with strings.Repeat(" ", n) for alignment)
Run it on macOS (or any terminal where termios has TAB0 set - the macOS default)
Observe that columns are misaligned - spaces have been replaced with tab characters
Source Code
Minimal reproduction - a two-column aligned table:
The cellbuf relativeCursorMove() in screen.go then replaces runs of "clear" cells with \t. A cell is "clear" when Cell.Clear() returns true - any space with no foreground/background/underline and only Bold/Faint/Italic/Blink attributes.
This affects any bubbletea v2 application doing column-aligned output on terminals with TAB0 set (the macOS default), including huh multi-select fields.
Workaround: Wrap padding spaces in SGR 8 (conceal): \x1b[8m + spaces + \x1b[28m. The conceal attribute makes Style.Clear() return false, preventing tab compression, while being visually invisible on space characters.
Suggested fix: One or more of:
Add tea.WithHardTabs(false) option to let applications disable the optimization
Only apply tab compression to renderer-produced cells, not cells from application View() output
Disable by default - the optimization saves minimal bandwidth but breaks a very common pattern
Note
Human speaking here! Apologies for the full-blown AI-generated bug report, but this was sufficiently complex for me to track down and debug what was going on that I needed to get an LLM involved and help me write up the issue.
Describe the bug
bubbletea v2's
cursedRendererauto-detects the terminal'sTAB0flag viatermiosand replaces runs of plain space cells with\tcharacters as a cursor-movement optimization. This silently corrupts any application output that relies on precise space-based column alignment. The application'sView()returns properly padded strings with spaces, but the renderer replaces those spaces with tab characters before writing to the terminal. There is no opt-out mechanism.Setup
TAB0is the defaulttermiosoutput flagTo Reproduce
View()(e.g. a table withstrings.Repeat(" ", n)for alignment)termioshasTAB0set - the macOS default)Source Code
Minimal reproduction - a two-column aligned table:
Expected behavior
Columns should be aligned exactly as the
View()output specifies - spaces should remain as spaces.Actual behavior
Spaces are replaced with tab characters, breaking column alignment:
Additional context
The root cause is in
cursed_renderer.gowherehardTabsis set fromtermios:The cellbuf
relativeCursorMove()inscreen.gothen replaces runs of "clear" cells with\t. A cell is "clear" whenCell.Clear()returns true - any space with no foreground/background/underline and only Bold/Faint/Italic/Blink attributes.This affects any bubbletea v2 application doing column-aligned output on terminals with
TAB0set (the macOS default), includinghuhmulti-select fields.Workaround: Wrap padding spaces in SGR 8 (conceal):
\x1b[8m+ spaces +\x1b[28m. The conceal attribute makesStyle.Clear()return false, preventing tab compression, while being visually invisible on space characters.Suggested fix: One or more of:
tea.WithHardTabs(false)option to let applications disable the optimizationView()output