charmbracelet / charmbracelet/bubbletea

Windows centering

Open
#788 0 comments 0 reactions 0 assignees View on GitHub
Dominant language
Go
Stars
44.9k
Forks
1.3k
PR merge metrics
No merged PRs in 30d

Description

**Describe the bug**
On windows, if you try to get the width and height of the terminal and then use `lipgloss.Place` to have one string in the center of your terminal while resizing, once you resize higher and wider than the initial dimension, the centered string will go up.

**Setup**
Please complete the following information along with version numbers, if applicable.
- Windows
- Command Prompt

**To Reproduce**
Steps to reproduce the behavior:
Simply get the resize width and height, make sure it is updated, center a string the most basic and classic way `return lipgloss.Place(m.width, m.height, lipgloss.Center, lipgloss.Center, fmt.Sprintf("%v-%v", m.width, m.height))`.

If it works on Linux and MacOs, perfect, now try on W10 on the Command Prompt. You should see the string going up.

**Additional context**
I've looked at `github.com/gdamore/tcell/v2` (through look at `tview`), it uses a `tcell.Screen` that always correctly match the size. The example "frame" on `tview` way working PERFECTLY on all OS. So I was surprised! Why know trying, right?

**Source Code**

This is the code with the faulty Command Prompt

```go
package main

import (
"bytes"
"fmt"
"log"
"os"
"time"

tea "github.com/charmbracelet/bubbletea"
"github.com/charmbracelet/lipgloss"

"golang.org/x/term"
)

type sizeTickMsg struct {
size tea.WindowSizeMsg
err error
}

var sizeTick = tea.Tick(time.Second/33, func(time.Time) tea.Msg {
w, h, err := term.GetSize(int(os.Stdout.Fd()))
return sizeTickMsg{
size: tea.WindowSizeMsg{
Width: w,
Height: h,
},
err: err,
}
})

func main() {
var err error
bb := BlubbleState{}
p := tea.NewProgram(bb, tea.WithAltScreen())
_, err = p.Run()
if err != nil {
log.Fatalln(err)
}
}

type BlubbleState struct {
Dimension struct {
w int
h int
}
size tea.WindowSizeMsg
style lipgloss.Style
}

func (m BlubbleState) Init() tea.Cmd {
return sizeTick
}

func (m BlubbleState) Update(msg tea.Msg) (tea.Model, tea.Cmd) {

switch msg := msg.(type) {

case sizeTickMsg:
if msg.err == nil {
m.size = msg.size
m.style = m.style.Width(m.size.Width - 2).Height(m.size.Height - 2)
}
return m, sizeTick

case tea.WindowSizeMsg:
m.size = msg
m.style = m.style.Width(m.size.Width - 2).Height(m.size.Height - 2)
return m, sizeTick

case tea.KeyMsg:
switch msg.Type {
case tea.KeyCtrlC:
return m, tea.Quit
}
}
cmds := []tea.Cmd{
sizeTick,
}

return m, tea.Batch(cmds...)
}

func (m BlubbleState) View() string {
b := bytes.NewBufferString("")

b.WriteString(
lipgloss.Place(m.style.GetWidth(), m.style.GetHeight(), lipgloss.Center, lipgloss.Center,
fmt.Sprintf("%v-%v", m.style.GetWidth(), m.style.GetHeight())))

return b.String()
}
```

Well, I did it in a stupid way but it "works". It fixes it on Command Prompt... it dirty though

```go

package main

import (
"fmt"
"log"
"time"

tea "github.com/charmbracelet/bubbletea"
"github.com/charmbracelet/lipgloss"
tcell "github.com/gdamore/tcell/v2"
)

type model struct {
width, height int
}

func (m model) Init() tea.Cmd {
return resizeCmd
}

func (m model) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
cmds := []tea.Cmd{}
switch msg := msg.(type) {
case tea.WindowSizeMsg:
m.width = msg.Width
m.height = msg.Height
cmds = append(cmds, resizeCmd)
case tea.KeyMsg:
switch msg.Type {
case tea.KeyCtrlC:
return m, tea.Quit
}
}
return m, tea.Batch(cmds...)
}

func (m model) View() string {
return lipgloss.Place(m.width, m.height, lipgloss.Center, lipgloss.Center,
fmt.Sprintf("%v-%v", m.width, m.height))
}

var resizeCmd = tea.Tick(time.Second/33, func(time.Time) tea.Msg {
screen, _ := tcell.NewScreen()
if err := screen.Init(); err != nil {
return nil
}
defer screen.Fini()
w, h := screen.Size()
return tea.WindowSizeMsg{
Width: w,
Height: h,
}
})

func main() {
p := tea.NewProgram(model{}, tea.WithAltScreen())
if _, err := p.Run(); err != nil {
log.Fatal(err)
}
}

```

**Screenshots**

Here an example of behavior when you write a basic code that center the string.

terminal vs command prompt

Strangely, the `tcell.Screen` fix it.

I just thought that maybe it wasn't on your radar and thought it would help 😄

Contributor guide

Open the contributing guide

Research direction

Start with the reported term.GetSize call and Bubble Tea's tea.WindowSizeMsg handling, comparing them with the tcell.Screen size path shown in the issue. Reproduce the resizing behavior on Windows Command Prompt and verify that centered output remains correctly positioned after enlarging the terminal.

Written by the indexing model from the issue text.

Assessment

Tech stack
go
Domain
cli, operating-systems
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Stale
Clarity
Mostly clear
Newbie friendliness
35/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.