While you can easily print a bubble tea UI out to stderr, color profile information is looked up using os.Stdout in a variety of places (the most important being termenv.ColorProfile
, but also in the various lipgloss.Style
and termenv.Style
instantiation.
Having colored output when stdout is not a TTY, but stderr is would be very useful. It would allow bubbletea applications to be used in the context of shell scripting (for example, like fzf).
Muesli has a new branch for termenv at https://github.com/muesli/termenv/tree/termenv-next . This supports more options for specifying termenv style based on file descriptor. However, lipgloss and bubbles need to be updated to take advantage of this functionality, so that proper color profiles are used for stderr.
There are different ways of tackling this issue.
The simplest solution that would work with the current releases is to just set an environment variable before starting the UI, forcing colors on stderr. This would also force colors on stdout, but usually bubbles/lipgloss is rendered to either stdout or stderr, and normal style-less formatting is used for the other output.
For example, this works against bubbletea master:
diff --git a/examples/list-simple/main.go b/examples/list-simple/main.go
index 97628db..443c443 100644
--- a/examples/list-simple/main.go
+++ b/examples/list-simple/main.go
@@ -111,6 +111,7 @@ func main() {
const defaultWidth = 20
+ os.Setenv("CLICOLOR_FORCE", "1")
l := list.New(items, itemDelegate{}, defaultWidth, listHeight)
l.Title = "What do you want for dinner?"
l.SetShowStatusBar(false)
@@ -121,7 +122,7 @@ func main() {
m := model{list: l}
- if err := tea.NewProgram(m).Start(); err != nil {
+ if err := tea.NewProgram(m, tea.WithOutput(os.Stderr)).Start(); err != nil {
fmt.Println("Error running program:", err)
os.Exit(1)
}
The second “clean” solution is to bubble color profile information all the way down to every method instantiating an output style. This means forbidding the creation of lipgloss/termenv styles without explicitly providing a color profile, to avoid misuse.
This adds a fair amount of API overhead to every model / style in lipgloss, but means that every API user will support stderr and stdout properly.
This is what I tried to achieve with :
- GitHub - wesen/bubbletea at work/2022-03-17/add-stderr-color-bubbles
- https://github.com/wesen/bubbles/tree/work/2022-03-17/add-stderr-color-bubbles
- https://github.com/wesen/termenv/tree/work/2022-03-17/add-stderr-color-bubbles
At the end, I introduced the global output file variable described in Proposal 3, because I would have had to bubble down color profile information to all the color styled components.
The third option would be to allow setting a global “styled output” file descriptor (in termenv), so that each future default instantiation of a style uses said descriptor. This means no API change to bubbles and bubble tea, but at least makes behavior configurable without setting a global environment variable as workaround.
I personally prefer proposal 3. It’s not super clean, but for all practical instances it should work perfectly fine and be backwards compatible.
Quick heads up: with termenv-next being merged into termenv, we're working towards proposal 3.