-
Notifications
You must be signed in to change notification settings - Fork 98
Description
Describe the bug
When using the bubbletea.MakeRenderer function, lipgloss.AdaptiveColor and lipgloss.Renderer.HasDarkBackground always assume a black background, even though the terminal emulator from which i am using ssh has set a light background.
Setup
I'm running the wish example locally with go run . and also use a local terminal to access the ssh server.
It happens on Fedora 40 and MacOS with Gnome Terminal, iTerm2 and the standard mac terminal (all using zsh).
To Reproduce
- Use the bubbletea example from the examples folder
- Log HasDarkBackground using
log.Info(renderer.HasDarkBackground())in theteaHandlerfunction right after creating the renderer using the bubbletea middleware - Create a new Lipgloss Style in the
teaHandlerfunction that uses the renderer created using the bubbletea middleware andlipgloss.AdaptiveColor
3.1 Render some text in theView()method of the model using the adaptive color lipgloss style
Source Code
I've created a simple one-file example in this gist:
https://gist.github.com/Aerochrome/5fd2af09f94eda22a0875068b8824acc
Expected behavior
When accessing with a terminal emulator with a light background, the second line should be colored pink.
When accessing with a dark background, the second line should be colored red.
Additional context
DISCLAIMER: I am very new to TUIs and fairly new to go, so i'm not sure how useful my debugging findings actually are, but i want to share them nonetheless in case they're of any use.
I suspect that this issue might be related to a missing Fd() method implementation on the ssh.Session struct.
In the bubbletea.newRenderer method in this file a check is performed on whether the Slave pointer is nil. If so, it passes the session struct into lipgloss.NewRenderer.
While this struct has a Write method, it doesn't seem to implement the Fd method.
When adding a very rudimentary one like so, the background color check seems to work properly and produces a working example.
func (sess *session) Fd() uintptr {
return sess.pty.Slave.Fd() // Also works if sess.pty.Slave is nil
}Of course, this doesn't account for sess.pty.Slave being nil (even though it produces a working example even if it is nil and i'm unsure why).
This suspicion is further confirmed by looking at an older wish example in the lipgloss repository, where a "helper" struct is created to pass into lipgloss.Renderer.SetOutput which also implements Write and Fd.
It also implements Read, though it doesn't seem to influence the outcome of a working example in my case.
So i've tried to use this helper struct, setting tty to pty.Slave and passing it into bubbletea.MakeRenderer like so, which produces a working example.
sessionBridge := &sshOutput{
Session: s,
tty: pty.Slave,
}
renderer := bubbletea.MakeRenderer(sessionBridge)Again, this also works if pty.Slave is nil.
It is also worth mentioning that in my case checking pty.Master and pty.Slave against nil in the teaHandler function returns true in both cases, even though s.Pty() returns true as third return value which i assume means that a PTY was accepted for this session.
I don't know if this is expected behavior in this specific case?
log.Info(pty.Master == nil)
log.Info(pty.Slave == nil)
