mattn / go-runewidth

wcwidth for golang
MIT License
609 stars 94 forks source link

Width of Box Drawing characters and LANG=zh_CN.UTF-8 #64

Closed jedib0t closed 2 years ago

jedib0t commented 2 years ago

Hello!

I maintain a golang library for drawing ASCII tables at https://github.com/jedib0t/go-pretty and this is one of the few dependencies I have, to calculate rune width for drawing the tables. Sample: https://go.dev/play/p/I6uxssyXxhN?v=goprev

Now, a couple of users reported some alignment issues, and after some investigation I figured that the Width returned for Box Drawing characters were not the expected values when LANG=zh_CN.UTF-8 or when EastAsianWidth=true is set in go-runewidth.

To replicate the bug, I create this program -- say foo.go:

package main

import (
    "fmt"
    "strings"

    "github.com/mattn/go-runewidth"
)

func main() {
    boxDrawingChars := []string{
        "+", "-", "=",
        "┏", "┳", "┓",
        "┣", "╋", "┫",
        "┗", "┻", "┛",
        "━", "┃",
    }

    cellWidth := 8
    for _, boxDrawingChar := range boxDrawingChars {
        padding := strings.Repeat(" ", cellWidth-runewidth.StringWidth(boxDrawingChar))
        fmt.Printf("| %s%s |\n", boxDrawingChar, padding)
    }
}

Output:

$ LANG=en_US.UTF-8 go run foo.go
| +        |
| -        |
| =        |
| ┏        |
| ┳        |
| ┓        |
| ┣        |
| ╋        |
| ┫        |
| ┗        |
| ┻        |
| ┛        |
| ━        |
| ┃        |

$ LANG=zh_CN.UTF-8 go run foo.go 
| +        |
| -        |
| =        |
| ┏       |
| ┳       |
| ┓       |
| ┣       |
| ╋       |
| ┫       |
| ┗       |
| ┻       |
| ┛       |
| ━       |
| ┃       |

Is this behavior right, or am I using runewidth.RuneWidth/StringWidth incorrectly?

mattn commented 2 years ago

go-runewidth returns the value 2 for the East Asian Ambiguous Width as same as that wcwidth(3) depend on your locales. It is caused by the difference between the character width of the ruled line as represented in the terminal and the actual value returned by wcwidth(3) or runewidth. If you want it to be fixed behavior under certain conditions, change the value of the EastAsianWidth variable.

jedib0t commented 2 years ago

Thanks for the response. Will provide a workaround for my library's users.