Re-use the escape code parser for wcswidth calculation
This commit is contained in:
parent
7280c712d6
commit
c8292d77f1
@ -2,6 +2,7 @@ package wcswidth
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
|
"errors"
|
||||||
"kitty/tools/utils"
|
"kitty/tools/utils"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -54,6 +55,8 @@ type EscapeCodeParser struct {
|
|||||||
|
|
||||||
func (self *EscapeCodeParser) InBracketedPaste() bool { return self.state == bracketed_paste }
|
func (self *EscapeCodeParser) InBracketedPaste() bool { return self.state == bracketed_paste }
|
||||||
|
|
||||||
|
var reparse_byte = errors.New("")
|
||||||
|
|
||||||
func (self *EscapeCodeParser) Parse(data []byte) error {
|
func (self *EscapeCodeParser) Parse(data []byte) error {
|
||||||
prev := utils.UTF8_ACCEPT
|
prev := utils.UTF8_ACCEPT
|
||||||
codep := utils.UTF8_ACCEPT
|
codep := utils.UTF8_ACCEPT
|
||||||
@ -70,15 +73,18 @@ func (self *EscapeCodeParser) Parse(data []byte) error {
|
|||||||
case utils.UTF8_REJECT:
|
case utils.UTF8_REJECT:
|
||||||
self.utf8_state = utils.UTF8_ACCEPT
|
self.utf8_state = utils.UTF8_ACCEPT
|
||||||
if prev != utils.UTF8_ACCEPT && i > 0 {
|
if prev != utils.UTF8_ACCEPT && i > 0 {
|
||||||
i = i - 1
|
i--
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
prev = self.utf8_state
|
prev = self.utf8_state
|
||||||
default:
|
default:
|
||||||
err := self.dispatch_byte(data[i])
|
err := self.dispatch_byte(data[i])
|
||||||
if err != nil {
|
if err != nil {
|
||||||
self.Reset()
|
self.reset_state()
|
||||||
return err
|
if err != reparse_byte {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
i--
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -242,8 +248,9 @@ func (self *EscapeCodeParser) dispatch_byte(ch byte) error {
|
|||||||
case '_':
|
case '_':
|
||||||
self.state = st
|
self.state = st
|
||||||
self.current_callback = self.HandleAPC
|
self.current_callback = self.HandleAPC
|
||||||
|
case 'D', 'E', 'H', 'M', 'N', 'O', 'Z', '6', '7', '8', '9', '=', '>', 'F', 'c', 'l', 'm', 'n', 'o', '|', '}', '~':
|
||||||
default:
|
default:
|
||||||
self.state = normal
|
return reparse_byte
|
||||||
}
|
}
|
||||||
case csi:
|
case csi:
|
||||||
self.write_ch(ch)
|
self.write_ch(ch)
|
||||||
|
|||||||
@ -11,37 +11,31 @@ func IsFlagPair(a rune, b rune) bool {
|
|||||||
type ecparser_state uint8
|
type ecparser_state uint8
|
||||||
|
|
||||||
type WCWidthIterator struct {
|
type WCWidthIterator struct {
|
||||||
prev_ch rune
|
prev_ch rune
|
||||||
prev_width int
|
prev_width, current_width int
|
||||||
state ecparser_state
|
parser EscapeCodeParser
|
||||||
|
state ecparser_state
|
||||||
|
}
|
||||||
|
|
||||||
|
func CreateWCWidthIterator() *WCWidthIterator {
|
||||||
|
var ans WCWidthIterator
|
||||||
|
ans.parser.HandleRune = ans.handle_rune
|
||||||
|
return &ans
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *WCWidthIterator) Reset() {
|
func (self *WCWidthIterator) Reset() {
|
||||||
self.prev_ch = 0
|
self.prev_ch = 0
|
||||||
self.prev_width = 0
|
self.prev_width = 0
|
||||||
self.state = 0
|
self.current_width = 0
|
||||||
|
self.parser.Reset()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *WCWidthIterator) Step(ch rune) int {
|
func (self *WCWidthIterator) handle_rune(ch rune) error {
|
||||||
var ans int = 0
|
|
||||||
const (
|
const (
|
||||||
normal ecparser_state = 0
|
normal ecparser_state = 0
|
||||||
in_esc ecparser_state = 1
|
|
||||||
in_csi ecparser_state = 2
|
|
||||||
flag_pair_started ecparser_state = 3
|
flag_pair_started ecparser_state = 3
|
||||||
in_st_terminated ecparser_state = 4
|
|
||||||
)
|
)
|
||||||
switch self.state {
|
switch self.state {
|
||||||
case in_csi:
|
|
||||||
self.prev_width = 0
|
|
||||||
if 0x40 <= ch && ch <= 0x7e {
|
|
||||||
self.state = normal
|
|
||||||
}
|
|
||||||
case in_st_terminated:
|
|
||||||
self.prev_width = 0
|
|
||||||
if ch == 0x9c || (ch == '\\' && self.prev_ch == 0x1b) {
|
|
||||||
self.state = normal
|
|
||||||
}
|
|
||||||
case flag_pair_started:
|
case flag_pair_started:
|
||||||
self.state = normal
|
self.state = normal
|
||||||
if IsFlagPair(self.prev_ch, ch) {
|
if IsFlagPair(self.prev_ch, ch) {
|
||||||
@ -50,19 +44,16 @@ func (self *WCWidthIterator) Step(ch rune) int {
|
|||||||
fallthrough
|
fallthrough
|
||||||
case normal:
|
case normal:
|
||||||
switch ch {
|
switch ch {
|
||||||
case 0x1b:
|
|
||||||
self.prev_width = 0
|
|
||||||
self.state = in_esc
|
|
||||||
case 0xfe0f:
|
case 0xfe0f:
|
||||||
if IsEmojiPresentationBase(self.prev_ch) && self.prev_width == 1 {
|
if IsEmojiPresentationBase(self.prev_ch) && self.prev_width == 1 {
|
||||||
ans += 1
|
self.current_width += 1
|
||||||
self.prev_width = 2
|
self.prev_width = 2
|
||||||
} else {
|
} else {
|
||||||
self.prev_width = 0
|
self.prev_width = 0
|
||||||
}
|
}
|
||||||
case 0xfe0e:
|
case 0xfe0e:
|
||||||
if IsEmojiPresentationBase(self.prev_ch) && self.prev_width == 2 {
|
if IsEmojiPresentationBase(self.prev_ch) && self.prev_width == 2 {
|
||||||
ans -= 1
|
self.current_width -= 1
|
||||||
self.prev_width = 1
|
self.prev_width = 1
|
||||||
} else {
|
} else {
|
||||||
self.prev_width = 0
|
self.prev_width = 0
|
||||||
@ -81,32 +72,20 @@ func (self *WCWidthIterator) Step(ch rune) int {
|
|||||||
default:
|
default:
|
||||||
self.prev_width = 1
|
self.prev_width = 1
|
||||||
}
|
}
|
||||||
ans += self.prev_width
|
self.current_width += self.prev_width
|
||||||
}
|
|
||||||
|
|
||||||
case in_esc:
|
|
||||||
switch ch {
|
|
||||||
case '[':
|
|
||||||
self.state = in_csi
|
|
||||||
case 'P', ']', 'X', '^', '_':
|
|
||||||
self.state = in_st_terminated
|
|
||||||
case 'D', 'E', 'H', 'M', 'N', 'O', 'Z', '6', '7', '8', '9', '=', '>', 'F', 'c', 'l', 'm', 'n', 'o', '|', '}', '~':
|
|
||||||
default:
|
|
||||||
self.prev_ch = 0x1b
|
|
||||||
self.prev_width = 0
|
|
||||||
self.state = normal
|
|
||||||
return self.Step(ch)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
self.prev_ch = ch
|
self.prev_ch = ch
|
||||||
return ans
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (self *WCWidthIterator) Parse(b []byte) (ans int) {
|
||||||
|
self.current_width = 0
|
||||||
|
self.parser.Parse(b)
|
||||||
|
return self.current_width
|
||||||
}
|
}
|
||||||
|
|
||||||
func Stringwidth(text string) int {
|
func Stringwidth(text string) int {
|
||||||
var w WCWidthIterator
|
w := CreateWCWidthIterator()
|
||||||
ans := 0
|
return w.Parse([]byte(text))
|
||||||
for _, ch := range []rune(text) {
|
|
||||||
ans += w.Step(ch)
|
|
||||||
}
|
|
||||||
return ans
|
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user