charmbracelet / lipgloss

Style definitions for nice terminal layouts 👄
MIT License
8.03k stars 228 forks source link

"nonspacing mark" unicode causes container's width to shift #258

Closed OnFireByte closed 6 months ago

OnFireByte commented 8 months ago

Describe the bug Nonspacing mark unicodes are a type of character that doesn't consume space; instead, they "attach" themselves to the previous character. For example, "ี" or "ุ" are nonspacing marks commonly attached to another character like "ด," resulting in "ดี" or "ดุ."

When there are nonspacing mark unicodes inside lipgloss's container, the layout will shift on that line because lipgloss counts these characters as normal unicode that occupy 1 space.

Setup Please complete the following information along with version numbers, if applicable.

To Reproduce Steps to reproduce the behavior:

  1. Create a style with a fixed width, such as 16 characters.
  2. Render it with a string that has nonspacing mark unicodes, for example, "สวัสดี." ("ั" and "ี" are nonspacing marks)
  3. See the layout shift.

Source Code

package main

import (
    "fmt"

    "github.com/charmbracelet/lipgloss"
)

var box = lipgloss.NewStyle().Width(8).Height(8).Border(lipgloss.RoundedBorder())

func main() {
    fmt.Println(box.Render("สวัสดี"))
}

Screenshots

image
mikelorant commented 8 months ago

This is a known issue that is pending these pull requests:

Without these being merged, the problem cannot be resolved. For context, this is due to incorrect rune width calculations not handling grapheme clusters (which obviously understand ZWJ).

mikelorant commented 8 months ago

Confirmed this is fixed with the pull requests I have listed above: CleanShot 2024-02-16 at 16 23 20