Skip to content

Commit

Permalink
Fix width calculation for unicode characters
Browse files Browse the repository at this point in the history
  • Loading branch information
anujc25 committed Jun 13, 2024
1 parent df64c4b commit 417dad4
Show file tree
Hide file tree
Showing 2 changed files with 25 additions and 5 deletions.
24 changes: 23 additions & 1 deletion util.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,29 @@ import (
"github.com/mattn/go-runewidth"
)

var ansi = regexp.MustCompile("\033\\[(?:[0-9]{1,3}(?:;[0-9]{1,3})*)?[m|K]")
var ansi = generateEscapeFilterRegex()

// generateEscapeFilterRegex builds a regex to remove non-printing ANSI escape codes from strings so
// that their display width can be determined accurately. The regex is complicated enough that it's
// better to build it programmatically than to write it by hand.
// Based on https://en.wikipedia.org/wiki/ANSI_escape_code#Fe_Escape_sequences
func generateEscapeFilterRegex() *regexp.Regexp {
var regESC = "\x1b" // ASCII escape
var regBEL = "\x07" // ASCII bell

// String Terminator - ends ANSI sequences
var regST = "(" + regESC + "\\\\" + "|" + regBEL + ")"

// Control Sequence Introducer - usually color codes
// esc + [ + zero or more 0x30-0x3f + zero or more 0x20-0x2f and a single 0x40-0x7e
var regCSI = regESC + "\\[" + "[\x30-\x3f]*[\x20-\x2f]*[\x40-\x7e]"

// Operating System Command - hyperlinks
// esc + ] + any number of any chars + ST
var regOSC = regESC + "\\]" + ".*?" + regST

return regexp.MustCompile("(" + regCSI + "|" + regOSC + ")")
}

func DisplayWidth(str string) int {
return runewidth.StringWidth(ansi.ReplaceAllLiteralString(str, ""))
Expand Down
6 changes: 2 additions & 4 deletions wrap.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,6 @@ import (
"math"
"strings"
"unicode"

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

const (
Expand All @@ -35,7 +33,7 @@ func WrapString(s string, lim int) ([]string, int) {
var lines []string
max := 0
for _, v := range words {
max = runewidth.StringWidth(v)
max = DisplayWidth(v)
if max > lim {
lim = max
}
Expand Down Expand Up @@ -87,7 +85,7 @@ func WrapWords(words []string, spc, lim, pen int) [][]string {
}
lengths := make([]int, n)
for i := 0; i < n; i++ {
lengths[i] = runewidth.StringWidth(words[i])
lengths[i] = DisplayWidth(words[i])
}
nbrk := make([]int, n)
cost := make([]int, n)
Expand Down

0 comments on commit 417dad4

Please sign in to comment.