V2 `Lipgloss.Width` Does not Match Output Width In Some Cases
Describe the bug
There seems to be a bug where lipgloss.Width says one value is the width, but when you create a line with that many dashes, it does not have the same length when printed. This seems to me to be an incorrect width calculation, but it does match with what uniseg, runewidth-go, and ansi all say the width is. So I am not sure if this is truly a bug or if this is a misconception of what it means to have a specific width.
Setup Please complete the following information along with version numbers, if applicable.
- OS: Pop OS! 24.04
- Shell: Bash
- Terminal Emulator: Kitty, Ghostty
- Terminal Multiplexer: tmux and without any
- Locale: en_US.utf8
To Reproduce
Setup the following program:
package main
import (
"fmt"
"strings"
"charm.land/lipgloss/v2"
"github.com/charmbracelet/x/exp/term/ansi"
"github.com/mattn/go-runewidth"
"github.com/rivo/uniseg"
)
func main() {
line := "\"<p>Sapling-chan(<i># ゚Д゚)</i> \"Give me back my turnsssss!!\"</p>\" "
fmt.Println("|"+strings.Repeat("-", 99), "| is actually 99 in size...")
fmt.Printf("|%s| is size info: lipgloss: %d, ansi: %d, runewidth: %d, uniseg: %d\n", line, lipgloss.Width(line), ansi.StringWidth(line), runewidth.StringWidth(line), uniseg.StringWidth(line))
line = strings.ReplaceAll(line, "゚", "^")
fmt.Printf("|%s| is size info: lipgloss: %d, ansi: %d, runewidth: %d, uniseg: %d\n", line, lipgloss.Width(line), ansi.StringWidth(line), runewidth.StringWidth(line), uniseg.StringWidth(line))
fmt.Println("|"+strings.Repeat("-", 100), "| is actually 100 in size...")
}Run the program and notice that the widths do not match. I get the following output locally:
|--------------------------------------------------------------------------------------------------- | is actually 99 in size...
|"<p>Sapling-chan(<i># ゚Д゚)</i> "Give me back my turnsssss!!"</p>" | is size info: lipgloss: 99, ansi: 99, runewidth: 99, uniseg: 99
|"<p>Sapling-chan(<i># ^Д^)</i> "Give me back my turnsssss!!"</p>" | is size info: lipgloss: 101, ansi: 101, runewidth: 101, uniseg: 101
|---------------------------------------------------------------------------------------------------- | is actually 100 in size...Source Code Added above
Expected behavior
I expect that if lipgloss.Width matches for a line, then it would be rendered as the same amount of single width characters.
Screenshots N/A
Additional context
Maybe this is an issue with fonts installed for me, but I changed fonts several times and could not fix the issue. This is originally from https://github.com/charmbracelet/bubbletea/issues/1668 which was where lipgloss.Width was incorrectly calculating widths in specific scenarios causing the UI to overflow. I am still seeing the incorrect width calculation, but now it matches what other libraries report for the width which is why I am closing it there and moving it here as it is closer to the source here.
Feel free to let me know if this is not an actual issue.
Source: charmbracelet/lipgloss