Describe the bug
Hi folks, really loving building out a TUI with your libraries, thanks for providing them <3. I've just noticed a difference in how padding background is rendered when serving a TUI locally as opposed to serving from a docker container. I'm pretty new to TUIs, Go and Wish/Bubble Tea/Lip Gloss so could be an issue on my end, looking for guidance either way.
Setup
Please complete the following information along with version numbers, if applicable.
- OS [e.g. Ubuntu, macOS] - macOS (apple silicon)
- Shell [e.g. zsh, fish] - zsh
- Terminal Emulator [e.g. kitty, iterm] - iterm
- Terminal Multiplexer [e.g. tmux] - NA
- Go version: 1.24.2
>> locale
LANG="en_AU.UTF-8"
LC_COLLATE="en_AU.UTF-8"
LC_CTYPE="en_AU.UTF-8"
LC_MESSAGES="en_AU.UTF-8"
LC_MONETARY="en_AU.UTF-8"
LC_NUMERIC="en_AU.UTF-8"
LC_TIME="en_AU.UTF-8"
LC_ALL=
To Reproduce
Steps to reproduce the behavior:
- local
run application
connect to TUI
notice that the background color is set for padding as expected, see screenshots below
- docker
build and run container
docker build -t wish-padding-test:0.0.1 .
docker run -p "8080:8080" -e "PORT=8080" -e "HOST=0.0.0.0" wish-padding-test:0.0.1
connect to TUI
notice that the background color is not applied to padding, see screenshots below
Source Code
main.go
package main
import (
"context"
"errors"
"net"
"os"
"os/signal"
"strings"
"syscall"
"time"
tea "github.com/charmbracelet/bubbletea"
gloss "github.com/charmbracelet/lipgloss"
"github.com/charmbracelet/log"
"github.com/charmbracelet/ssh"
"github.com/charmbracelet/wish"
"github.com/charmbracelet/wish/activeterm"
"github.com/charmbracelet/wish/bubbletea"
"github.com/charmbracelet/wish/logging"
"github.com/muesli/termenv"
)
var (
blue = gloss.Color("#6ea3ff")
pink = gloss.Color("#ff83fc")
)
type style struct {
background gloss.Style
base gloss.Style
}
type model struct {
width int
height int
style style
term ssh.Pty
}
func initModel(theme theme, renderer *gloss.Renderer, term ssh.Pty) model {
background := renderer.NewStyle().
MarginBackground(blue).
Background(blue)
base := renderer.NewStyle().
Inherit(background).
Foreground(pink)
return model{
width: 0,
height: 0,
style: style{
background: background,
base: base,
},
term: term,
}
}
func (m model) Init() tea.Cmd {
return nil
}
func (m model) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
switch msg := msg.(type) {
case tea.KeyMsg:
switch msg.String() {
case "ctrl+c", "q":
return m, tea.Quit
}
case tea.WindowSizeMsg:
m.height = msg.Height
m.width = msg.Width
}
return m, nil
}
func (m model) View() string {
document := strings.Builder{}
document.WriteString(gloss.PlaceHorizontal(20, gloss.Center, m.style.base.Render("hello"), gloss.WithWhitespaceBackground(blue), gloss.WithWhitespaceChars("/")))
return m.style.background.Render(gloss.Place(m.width, m.height, gloss.Center, gloss.Top, document.String(), gloss.WithWhitespaceBackground(blue), gloss.WithWhitespaceChars(".")))
}
type theme int
const (
Dark theme = iota
Light
)
func teaHandler(session ssh.Session) (tea.Model, []tea.ProgramOption) {
// should never fail as we are using the activeTerm middleware
pty, _, _ := session.Pty()
renderer := bubbletea.MakeRenderer(session)
// set the TrueColor profile so that we get some pretty colors
renderer.SetColorProfile(termenv.TrueColor)
theme := Light
if renderer.HasDarkBackground() {
theme = Dark
}
return initModel(theme, renderer, pty), []tea.ProgramOption{
tea.WithAltScreen(),
tea.WithInput(pty.Slave),
tea.WithOutput(pty.Slave)}
}
func main() {
host := os.Getenv("HOST")
if host == "" {
host = "localhost"
}
port := os.Getenv("PORT")
if port == "" {
port = "8080"
}
s, err := wish.NewServer(
wish.WithAddress(net.JoinHostPort(host, port)),
wish.WithHostKeyPath(".ssh/id_ed25519"),
wish.WithMiddleware(
bubbletea.Middleware(teaHandler),
activeterm.Middleware(), // Bubble Tea apps usually require a PTY.
logging.Middleware(),
),
)
if err != nil {
log.Error("Could not start server", "error", err)
}
done := make(chan os.Signal, 1)
signal.Notify(done, os.Interrupt, syscall.SIGINT, syscall.SIGTERM)
log.Info("Starting SSH server", "host", host, "port", port)
go func() {
if err = s.ListenAndServe(); err != nil && !errors.Is(err, ssh.ErrServerClosed) {
log.Error("Could not start server", "error", err)
done <- nil
}
}()
<-done
log.Info("Stopping SSH server")
ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
defer func() { cancel() }()
if err := s.Shutdown(ctx); err != nil && !errors.Is(err, ssh.ErrServerClosed) {
log.Error("Could not stop server", "error", err)
}
}
Dockerfile
FROM golang:1.24.2
WORKDIR /app
COPY ./go.mod ./go.sum ./
RUN go mod download
COPY ./*.go ./
RUN CGO_ENABLED=0 GOOS=linux go build -o /under-test
ENV PORT=8080
ENV HOST=0.0.0.0
EXPOSE ${PORT}
CMD ["/under-test"]
minimal reproducible project
Expected behavior
Padding background should be consistent between local and docker deployments
Screenshots
local

docker (padding background not applied)

Additional context
NA
Describe the bug
Hi folks, really loving building out a TUI with your libraries, thanks for providing them <3. I've just noticed a difference in how padding background is rendered when serving a TUI locally as opposed to serving from a docker container. I'm pretty new to TUIs, Go and Wish/Bubble Tea/Lip Gloss so could be an issue on my end, looking for guidance either way.
Setup
Please complete the following information along with version numbers, if applicable.
To Reproduce
Steps to reproduce the behavior:
run application
go run .connect to TUI
notice that the background color is set for padding as expected, see screenshots below
build and run container
docker build -t wish-padding-test:0.0.1 .connect to TUI
notice that the background color is not applied to padding, see screenshots below
Source Code
main.goDockerfileminimal reproducible project
Expected behavior
Padding background should be consistent between local and docker deployments
Screenshots
local
docker (padding background not applied)
Additional context
NA