mirror of
https://github.com/kovidgoyal/kitty
synced 2026-06-06 01:05:48 +02:00
Port wcswidth to use grapheme segmentation
This commit is contained in:
@@ -12,21 +12,12 @@ import (
|
||||
|
||||
var _ = fmt.Print
|
||||
|
||||
func IsFlagCodepoint(ch rune) bool {
|
||||
return 0x1F1E6 <= ch && ch <= 0x1F1FF
|
||||
}
|
||||
|
||||
func IsFlagPair(a rune, b rune) bool {
|
||||
return IsFlagCodepoint(a) && IsFlagCodepoint(b)
|
||||
}
|
||||
|
||||
type ecparser_state uint8
|
||||
|
||||
type WCWidthIterator struct {
|
||||
prev_ch rune
|
||||
prev_width, current_width int
|
||||
seg GraphemeSegmentationResult
|
||||
can_combine bool
|
||||
parser EscapeCodeParser
|
||||
state ecparser_state
|
||||
rune_count uint
|
||||
}
|
||||
|
||||
@@ -34,6 +25,12 @@ func CreateWCWidthIterator() *WCWidthIterator {
|
||||
var ans WCWidthIterator
|
||||
ans.parser.HandleRune = ans.handle_rune
|
||||
ans.parser.HandleCSI = ans.handle_csi
|
||||
ans.parser.HandleOSC = ans.handle_st_terminated
|
||||
ans.parser.HandleDCS = ans.handle_st_terminated
|
||||
ans.parser.HandlePM = ans.handle_st_terminated
|
||||
ans.parser.HandleSOS = ans.handle_st_terminated
|
||||
ans.parser.HandleAPC = ans.handle_st_terminated
|
||||
|
||||
return &ans
|
||||
}
|
||||
|
||||
@@ -42,6 +39,8 @@ func (self *WCWidthIterator) Reset() {
|
||||
self.prev_width = 0
|
||||
self.current_width = 0
|
||||
self.rune_count = 0
|
||||
self.can_combine = false
|
||||
self.seg = 0
|
||||
self.parser.Reset()
|
||||
}
|
||||
|
||||
@@ -58,54 +57,47 @@ func (self *WCWidthIterator) handle_csi(csi []byte) error {
|
||||
}
|
||||
}
|
||||
}
|
||||
self.can_combine = false
|
||||
self.seg = 0
|
||||
return nil
|
||||
}
|
||||
|
||||
func (self *WCWidthIterator) handle_st_terminated(data []byte) error {
|
||||
self.can_combine = false
|
||||
self.seg = 0
|
||||
return nil
|
||||
}
|
||||
|
||||
func (self *WCWidthIterator) handle_rune(ch rune) error {
|
||||
self.rune_count += 1
|
||||
const (
|
||||
normal ecparser_state = 0
|
||||
flag_pair_started ecparser_state = 3
|
||||
)
|
||||
switch self.state {
|
||||
case flag_pair_started:
|
||||
self.state = normal
|
||||
if IsFlagPair(self.prev_ch, ch) {
|
||||
break
|
||||
}
|
||||
fallthrough
|
||||
case normal:
|
||||
cp := CharPropsFor(ch)
|
||||
self.seg = self.seg.Step(cp)
|
||||
if self.can_combine && self.seg.Add_to_current_cell() == 1 {
|
||||
switch ch {
|
||||
case 0xfe0f:
|
||||
if IsEmojiPresentationBase(self.prev_ch) && self.prev_width == 1 {
|
||||
if CharPropsFor(self.prev_ch).Is_emoji_presentation_base() == 1 && self.prev_width == 1 {
|
||||
self.current_width += 1
|
||||
self.prev_width = 2
|
||||
} else {
|
||||
self.prev_width = 0
|
||||
}
|
||||
case 0xfe0e:
|
||||
if IsEmojiPresentationBase(self.prev_ch) && self.prev_width == 2 {
|
||||
if CharPropsFor(self.prev_ch).Is_emoji_presentation_base() == 1 && self.prev_width == 2 {
|
||||
self.current_width -= 1
|
||||
self.prev_width = 1
|
||||
} else {
|
||||
self.prev_width = 0
|
||||
}
|
||||
default:
|
||||
if IsFlagCodepoint(ch) {
|
||||
self.state = flag_pair_started
|
||||
}
|
||||
w := Runewidth(ch)
|
||||
switch w {
|
||||
case -1:
|
||||
case 0:
|
||||
self.prev_width = 0
|
||||
case 2:
|
||||
self.prev_width = 2
|
||||
default:
|
||||
self.prev_width = 1
|
||||
}
|
||||
self.current_width += self.prev_width
|
||||
}
|
||||
} else {
|
||||
width := cp.Width()
|
||||
switch width {
|
||||
case -1:
|
||||
case 0:
|
||||
self.prev_width = 0
|
||||
case 2:
|
||||
self.prev_width = 2
|
||||
default:
|
||||
self.prev_width = 1
|
||||
}
|
||||
self.current_width += self.prev_width
|
||||
self.can_combine = true
|
||||
}
|
||||
self.prev_ch = ch
|
||||
return nil
|
||||
|
||||
Reference in New Issue
Block a user