fix: auto-fix CBT use in JediTerm for GoLand/JetBrains' Run/Debug TTY#101
fix: auto-fix CBT use in JediTerm for GoLand/JetBrains' Run/Debug TTY#101mikeschinkel wants to merge 1 commit intocharmbracelet:mainfrom
Conversation
JetBrains GoLand and all IntelliJ-based IDEs use JediTerm as their built-in terminal emulator. JediTerm reports TERM=xterm-256color but mishandles CBT (Cursor Backward Tab), causing invalid rendering when ultraviolet's differential renderer emits it. Add isJediTerm() detection via four environment checks (TERMINAL_EMULATOR, __CFBundleIdentifier, XPC_SERVICE_NAME, TOOLBOX_VERSION) and automatically disable capCBT in xtermCaps() when detected.
|
BTW, here is research by Claude explaining the issue in depth: https://claude.ai/public/artifacts/921b2eb6-435f-469b-9f80-1bc74e1501f4 |
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## main #101 +/- ##
==========================================
+ Coverage 58.41% 58.49% +0.07%
==========================================
Files 52 52
Lines 6695 6707 +12
==========================================
+ Hits 3911 3923 +12
Misses 2539 2539
Partials 245 245 ☔ View full report in Codecov by Sentry. 🚀 New features to boost your workflow:
|
|
Just FYI, as far as I can tell all those lint failures are pre-existing failures not related to my PR. |
|
Hi @mikeschinkel, thank you for sending this patch. I agree with you that this is a bug in JediTerm, however, I strongly feel that this should be fixed upstream so that we're not stacking exceptions here in Ultraviolet. Ultraviolet expects terminal advertising themselves as |
|
Thank you for looking at this, Ayman. I genuinely understand the position as stacking terminal-specific exceptions is ugly. In an ideal world every terminal that advertises That said, I want to make the pragmatic case for reconsidering, because the practical impact on Charm's users is potentially significant. I've already gone upstream. I filed a YouTrack issue with JetBrains and notified them via Slack. But realistically, JediTerm's CBT gap affects a narrow slice of JetBrains' user base; Go developers using Bubble Tea inside GoLand's terminal. JetBrains has millions of developers across dozens of languages using their IDEs; a missing escape sequence that only surfaces with one Go TUI framework is unlikely to climb their priority list quickly, if ever. 😢 Meanwhile, GoLand is the 2nd most popular Go IDE at So there is a good chance many of those Goland-using developers will hit this bug. It took me a full week to diagnose because I assumed the problem was in my code, not in a terminal capability mismatch buried three layers deep. Most developers won't have the patience or the terminal-internals knowledge to trace it that far. They may well conclude Bubble Tea is too broken and just move on. Postel's Law says:
I would suggest that it would be in Bubble Tea's best interest ultraviolet should behave correctly even when the terminal lies about its capabilities. The patch I submitted only activates when other known-good terminals aren't matched, so it's conservative in its reach. I think there is a valid analogy to how browser vendors handle malformed HTML. Browsers could refuse to render anything that is not well-formed and insist that the upstream (the site author) fix their markup. But in practice, browsers that are strict lose users to browsers that are liberal. Users don't understand or care about the distinction, they just see one browser rendering the page and the other not. Similarly, if a Bubble Tea breaks in GoLand, developers probably won't blame JediTerm, they will blame Bubble Tea. OTOH, if none of those arguments move you I would ask to you consider making ultraviolet's renderer dependency injectable on Bubble Tea's side. Currently Either way, I appreciate your thoughtful response and the work you and the rest of the team has put ultraviolet. The ncurses-style diff renderer is genuinely impressive engineering, and the entire Charm/Bubble Tea collection of packages has enabled me to do great things I would never otherwise have been able to achieve in the time allotted. |
Summary
Automatically detect JediTerm (GoLand/IntelliJ terminal) and disable Cursor Backward Tab (CBT) to prevent invalid rendering — no action required from application developers.
Motivation
JetBrains GoLand and all IntelliJ-based IDEs use JediTerm as their built-in terminal emulator. JediTerm reports
TERM=xterm-256colorbut does not correctly handle Cursor Backward Tab (CBT), which can result in invalid rendering when ultraviolet's differential renderer emits it.This may seem like a niche edge case; however a large number of Bubble Tea apps will be run inside GoLand and may hit this bug, including when Delve debugging as GoLand is the 2nd most popular IDE for Go.
The rendering breaks in ways that are very difficult to diagnose. In my case, it took roughly a week of investigation as I kept assuming the bug was in my own code, not in terminal capability handling. I would hate for other developers to hit the same wall and come away frustrated with the Bubble Tea ecosystem when the fix is straightforward.
Without this fix, every Go developer using GoLand who builds a Bubble Tea app with view transitions would need to independently discover the issue, diagnose it, and manually work around it. Auto-detection eliminates this entirely.
How it works
JediTerm detection uses four environment checks to cover both the built-in terminal, Run/Debug configurations where
TERMINAL_EMULATORis not propagated, and JetBrains Toolbox installs:TERMINAL_EMULATOR == "JetBrains-JediTerm"__CFBundleIdentifierstarts with"com.jetbrains."XPC_SERVICE_NAMEcontains"com.jetbrains."TOOLBOX_VERSIONis non-emptyCheck 1 covers the Terminal tool window on all platforms. Checks 2–3 cover the "Emulate terminal in output console" Run/Debug path on macOS. Check 4 covers all contexts on all platforms for users who installed their IDE via JetBrains Toolbox (the default/recommended install method).
When detected,
capCBTis removed from the xterm default capability set inxtermCaps(). No application code changes are needed — existing Bubble Tea apps will just work correctly in GoLand.I have filled these which could make the problem a non-issue:
Add CBT (Cursor Backward Tabulation) issue #328 that would make this change unnecessry, but Jedit has
7open PRs some open since2021, and43open issues so I do not have high confidence they will address this anytime soon, if ever.YouTrack issue G0-20196 requesting that JetBrains set
TERMINAL_EMULATOR=JetBrains-JediTermin the "Emulate terminal" Run/Debug code path, which would make checks 2–4 unnecessary but check 1 would still be necessary.And these which would allow end-users of apps to fix broken terminal output for any edge-case terminals that ultraviolet does not currently detect:
ultraviolet #100 —
DisableCapsAPI for manually disabling capabilitiesbubbletea #1641 —
WithoutCapsoption at the Bubble Tea levelReproduction
A minimal standalone app that reproduces the rendering issue is available as a Gist: jediterm-bug. Run it inside GoLand's Run/Debug terminal (or ForceTerm) and press space to toggle between the two layouts — the second layout will render incorrectly.
Note: There is a standalone JediTerm you can use for testing named ForceTerm if you prefer not to install GoLand.
Changes
terminal_renderer.go— AddisJediTerm()function with four environment checks. InxtermCaps(), disablecapCBTin the xterm default case when JediTerm is detected.terminal_renderer_test.go— Tests forisJediTerm()detection via all four environment variables, and verification thatxtermCaps()strips CBT when in JediTerm while preserving other capabilities.Test plan
TestIsJediTerm— verifies detection viaTERMINAL_EMULATOR,__CFBundleIdentifier,XPC_SERVICE_NAME, andTOOLBOX_VERSION; verifies non-detection for empty env and other terminalsTestXtermCapsJediTermDisablesCBT— verifies CBT is present for normal xterm, absent for JediTerm xterm, and other caps (VPA, CHA) are preserved