2022-08-25 03:25:38 +03:00
|
|
|
package wcswidth
|
2022-08-22 08:03:31 +03:00
|
|
|
|
2022-08-22 08:51:23 +03:00
|
|
|
import (
|
|
|
|
"bytes"
|
2022-08-25 03:25:38 +03:00
|
|
|
"kitty/tools/utils"
|
2022-08-22 08:51:23 +03:00
|
|
|
)
|
2022-08-22 08:03:31 +03:00
|
|
|
|
|
|
|
type parser_state uint8
|
|
|
|
type csi_state uint8
|
|
|
|
type csi_char_type uint8
|
|
|
|
|
|
|
|
var bracketed_paste_start = []byte{'2', '0', '0', '~'}
|
|
|
|
|
|
|
|
const (
|
|
|
|
normal parser_state = iota
|
|
|
|
esc
|
|
|
|
csi
|
|
|
|
st
|
2022-08-22 08:51:23 +03:00
|
|
|
st_or_bel
|
2022-08-22 08:03:31 +03:00
|
|
|
esc_st
|
|
|
|
c1_st
|
|
|
|
bracketed_paste
|
|
|
|
)
|
|
|
|
|
|
|
|
const (
|
|
|
|
parameter csi_state = iota
|
|
|
|
intermediate
|
|
|
|
)
|
|
|
|
|
|
|
|
const (
|
|
|
|
unknown_csi_char csi_char_type = iota
|
|
|
|
parameter_csi_char
|
|
|
|
intermediate_csi_char
|
|
|
|
final_csi_char
|
|
|
|
)
|
|
|
|
|
|
|
|
type EscapeCodeParser struct {
|
|
|
|
state parser_state
|
2022-08-25 03:25:38 +03:00
|
|
|
utf8_state utils.UTF8State
|
2022-08-22 08:03:31 +03:00
|
|
|
csi_state csi_state
|
|
|
|
current_buffer []byte
|
2022-08-25 03:25:38 +03:00
|
|
|
bracketed_paste_buffer []utils.UTF8State
|
2022-08-23 17:21:31 +03:00
|
|
|
current_callback func([]byte) error
|
2022-08-22 08:03:31 +03:00
|
|
|
|
|
|
|
// Callbacks
|
2022-08-23 17:21:31 +03:00
|
|
|
HandleRune func(rune) error
|
|
|
|
HandleCSI func([]byte) error
|
|
|
|
HandleOSC func([]byte) error
|
|
|
|
HandleDCS func([]byte) error
|
|
|
|
HandlePM func([]byte) error
|
|
|
|
HandleSOS func([]byte) error
|
|
|
|
HandleAPC func([]byte) error
|
2022-08-22 08:51:23 +03:00
|
|
|
}
|
|
|
|
|
2022-08-24 08:31:04 +03:00
|
|
|
func (self *EscapeCodeParser) InBracketedPaste() bool { return self.state == bracketed_paste }
|
|
|
|
|
2022-08-23 17:21:31 +03:00
|
|
|
func (self *EscapeCodeParser) Parse(data []byte) error {
|
2022-08-25 03:25:38 +03:00
|
|
|
prev := utils.UTF8_ACCEPT
|
|
|
|
codep := utils.UTF8_ACCEPT
|
2022-08-22 08:03:31 +03:00
|
|
|
for i := 0; i < len(data); i++ {
|
|
|
|
switch self.state {
|
|
|
|
case normal, bracketed_paste:
|
2022-08-25 03:25:38 +03:00
|
|
|
switch utils.DecodeUtf8(&self.utf8_state, &codep, data[i]) {
|
|
|
|
case utils.UTF8_ACCEPT:
|
2022-08-23 17:21:31 +03:00
|
|
|
err := self.dispatch_char(codep)
|
|
|
|
if err != nil {
|
|
|
|
self.Reset()
|
|
|
|
return err
|
|
|
|
}
|
2022-08-25 03:25:38 +03:00
|
|
|
case utils.UTF8_REJECT:
|
|
|
|
self.utf8_state = utils.UTF8_ACCEPT
|
|
|
|
if prev != utils.UTF8_ACCEPT && i > 0 {
|
2022-08-22 08:03:31 +03:00
|
|
|
i = i - 1
|
|
|
|
}
|
|
|
|
}
|
|
|
|
prev = self.utf8_state
|
|
|
|
default:
|
2022-08-23 17:21:31 +03:00
|
|
|
err := self.dispatch_byte(data[i])
|
|
|
|
if err != nil {
|
|
|
|
self.Reset()
|
|
|
|
return err
|
|
|
|
}
|
2022-08-22 08:03:31 +03:00
|
|
|
}
|
|
|
|
}
|
2022-08-23 17:21:31 +03:00
|
|
|
return nil
|
2022-08-22 08:03:31 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
func (self *EscapeCodeParser) Reset() {
|
|
|
|
self.reset_state()
|
|
|
|
}
|
|
|
|
|
|
|
|
func (self *EscapeCodeParser) write_ch(ch byte) {
|
2022-08-23 17:21:31 +03:00
|
|
|
self.current_buffer = append(self.current_buffer, ch)
|
2022-08-22 08:03:31 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
func csi_type(ch byte) csi_char_type {
|
|
|
|
if 0x30 <= ch && ch <= 0x3f {
|
|
|
|
return parameter_csi_char
|
|
|
|
}
|
|
|
|
if 0x40 <= ch && ch <= 0x7E {
|
|
|
|
return final_csi_char
|
|
|
|
}
|
|
|
|
if 0x20 <= ch && ch <= 0x2F {
|
|
|
|
return intermediate_csi_char
|
|
|
|
}
|
|
|
|
return unknown_csi_char
|
|
|
|
}
|
|
|
|
|
|
|
|
func (self *EscapeCodeParser) reset_state() {
|
|
|
|
self.current_buffer = self.current_buffer[:0]
|
|
|
|
self.bracketed_paste_buffer = self.bracketed_paste_buffer[:0]
|
|
|
|
self.state = normal
|
2022-08-25 03:25:38 +03:00
|
|
|
self.utf8_state = utils.UTF8_ACCEPT
|
2022-08-22 08:03:31 +03:00
|
|
|
self.current_callback = nil
|
|
|
|
self.csi_state = parameter
|
|
|
|
}
|
|
|
|
|
2022-08-23 17:21:31 +03:00
|
|
|
func (self *EscapeCodeParser) dispatch_esc_code() error {
|
2022-08-22 08:03:31 +03:00
|
|
|
if self.state == csi && bytes.Equal(self.current_buffer, bracketed_paste_start) {
|
|
|
|
self.reset_state()
|
|
|
|
self.state = bracketed_paste
|
2022-08-23 17:21:31 +03:00
|
|
|
return nil
|
2022-08-22 08:03:31 +03:00
|
|
|
}
|
2022-08-23 17:21:31 +03:00
|
|
|
var err error
|
2022-08-22 08:03:31 +03:00
|
|
|
if self.current_callback != nil {
|
2022-08-23 17:21:31 +03:00
|
|
|
err = self.current_callback(self.current_buffer)
|
2022-08-22 08:03:31 +03:00
|
|
|
}
|
|
|
|
self.reset_state()
|
2022-08-23 17:21:31 +03:00
|
|
|
return err
|
2022-08-22 08:03:31 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
func (self *EscapeCodeParser) invalid_escape_code() {
|
|
|
|
self.reset_state()
|
|
|
|
}
|
|
|
|
|
2022-08-25 03:25:38 +03:00
|
|
|
func (self *EscapeCodeParser) dispatch_rune(ch utils.UTF8State) error {
|
2022-08-22 08:03:31 +03:00
|
|
|
if self.HandleRune != nil {
|
2022-08-23 17:21:31 +03:00
|
|
|
return self.HandleRune(rune(ch))
|
2022-08-22 08:03:31 +03:00
|
|
|
}
|
2022-08-23 17:21:31 +03:00
|
|
|
return nil
|
2022-08-22 08:03:31 +03:00
|
|
|
}
|
|
|
|
|
2022-08-25 03:25:38 +03:00
|
|
|
func (self *EscapeCodeParser) bp_buffer_equals(chars []utils.UTF8State) bool {
|
2022-08-22 08:03:31 +03:00
|
|
|
if len(self.bracketed_paste_buffer) != len(chars) {
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
for i, q := range chars {
|
|
|
|
if self.bracketed_paste_buffer[i] != q {
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return true
|
|
|
|
}
|
|
|
|
|
2022-08-25 03:25:38 +03:00
|
|
|
func (self *EscapeCodeParser) dispatch_char(ch utils.UTF8State) error {
|
2022-08-22 08:03:31 +03:00
|
|
|
if self.state == bracketed_paste {
|
2022-08-23 17:21:31 +03:00
|
|
|
dispatch := func() error {
|
2022-08-22 08:03:31 +03:00
|
|
|
if len(self.bracketed_paste_buffer) > 0 {
|
|
|
|
for _, c := range self.bracketed_paste_buffer {
|
2022-08-23 17:21:31 +03:00
|
|
|
err := self.dispatch_rune(c)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
2022-08-22 08:03:31 +03:00
|
|
|
}
|
|
|
|
self.bracketed_paste_buffer = self.bracketed_paste_buffer[:0]
|
|
|
|
}
|
2022-08-23 17:21:31 +03:00
|
|
|
return self.dispatch_rune(ch)
|
2022-08-22 08:03:31 +03:00
|
|
|
}
|
2022-08-25 03:25:38 +03:00
|
|
|
handle_ch := func(chars ...utils.UTF8State) error {
|
2022-08-22 08:03:31 +03:00
|
|
|
if self.bp_buffer_equals(chars) {
|
|
|
|
self.bracketed_paste_buffer = append(self.bracketed_paste_buffer, ch)
|
|
|
|
if self.bracketed_paste_buffer[len(self.bracketed_paste_buffer)-1] == '~' {
|
|
|
|
self.reset_state()
|
|
|
|
}
|
2022-08-23 17:21:31 +03:00
|
|
|
return nil
|
2022-08-22 08:03:31 +03:00
|
|
|
} else {
|
2022-08-23 17:21:31 +03:00
|
|
|
return dispatch()
|
2022-08-22 08:03:31 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
switch ch {
|
|
|
|
case 0x1b:
|
2022-08-23 17:21:31 +03:00
|
|
|
return handle_ch()
|
2022-08-22 08:03:31 +03:00
|
|
|
case '[':
|
2022-08-23 17:21:31 +03:00
|
|
|
return handle_ch(0x1b)
|
2022-08-22 08:03:31 +03:00
|
|
|
case '2':
|
2022-08-23 17:21:31 +03:00
|
|
|
return handle_ch(0x1b, '[')
|
2022-08-22 08:03:31 +03:00
|
|
|
case '0':
|
2022-08-23 17:21:31 +03:00
|
|
|
return handle_ch(0x1b, '[', '2')
|
2022-08-22 08:03:31 +03:00
|
|
|
case '1':
|
2022-08-23 17:21:31 +03:00
|
|
|
return handle_ch(0x1b, '[', '2', '0')
|
2022-08-22 08:03:31 +03:00
|
|
|
case '~':
|
2022-08-23 17:21:31 +03:00
|
|
|
return handle_ch(0x1b, '[', '2', '0', '1')
|
2022-08-22 08:03:31 +03:00
|
|
|
default:
|
2022-08-23 17:21:31 +03:00
|
|
|
return dispatch()
|
2022-08-22 08:03:31 +03:00
|
|
|
}
|
2022-08-22 08:51:23 +03:00
|
|
|
} // end self.state == bracketed_paste
|
2022-08-22 08:03:31 +03:00
|
|
|
|
|
|
|
switch ch {
|
|
|
|
case 0x1b:
|
|
|
|
self.state = esc
|
|
|
|
case 0x90:
|
|
|
|
self.state = st
|
|
|
|
self.current_callback = self.HandleDCS
|
|
|
|
case 0x9b:
|
|
|
|
self.state = csi
|
|
|
|
self.current_callback = self.HandleCSI
|
|
|
|
case 0x9d:
|
2022-08-22 08:51:23 +03:00
|
|
|
self.state = st_or_bel
|
2022-08-22 08:03:31 +03:00
|
|
|
self.current_callback = self.HandleOSC
|
|
|
|
case 0x98:
|
|
|
|
self.state = st
|
|
|
|
self.current_callback = self.HandleSOS
|
|
|
|
case 0x9e:
|
|
|
|
self.state = st
|
|
|
|
self.current_callback = self.HandlePM
|
|
|
|
case 0x9f:
|
|
|
|
self.state = st
|
|
|
|
self.current_callback = self.HandleAPC
|
|
|
|
default:
|
2022-08-23 17:21:31 +03:00
|
|
|
return self.dispatch_rune(ch)
|
2022-08-22 08:03:31 +03:00
|
|
|
}
|
2022-08-23 17:21:31 +03:00
|
|
|
return nil
|
2022-08-22 08:03:31 +03:00
|
|
|
}
|
|
|
|
|
2022-08-23 17:21:31 +03:00
|
|
|
func (self *EscapeCodeParser) dispatch_byte(ch byte) error {
|
2022-08-22 08:03:31 +03:00
|
|
|
switch self.state {
|
|
|
|
case esc:
|
|
|
|
switch ch {
|
|
|
|
case 'P':
|
|
|
|
self.state = st
|
|
|
|
self.current_callback = self.HandleDCS
|
|
|
|
case '[':
|
|
|
|
self.state = csi
|
|
|
|
self.csi_state = parameter
|
|
|
|
self.current_callback = self.HandleCSI
|
|
|
|
case ']':
|
2022-08-22 08:51:23 +03:00
|
|
|
self.state = st_or_bel
|
2022-08-22 08:03:31 +03:00
|
|
|
self.current_callback = self.HandleOSC
|
|
|
|
case '^':
|
|
|
|
self.state = st
|
|
|
|
self.current_callback = self.HandlePM
|
|
|
|
case '_':
|
|
|
|
self.state = st
|
|
|
|
self.current_callback = self.HandleAPC
|
|
|
|
default:
|
|
|
|
self.state = normal
|
|
|
|
}
|
|
|
|
case csi:
|
|
|
|
self.write_ch(ch)
|
|
|
|
switch self.csi_state {
|
|
|
|
case parameter:
|
|
|
|
switch csi_type(ch) {
|
|
|
|
case intermediate_csi_char:
|
|
|
|
self.csi_state = intermediate
|
|
|
|
case final_csi_char:
|
2022-08-23 17:21:31 +03:00
|
|
|
return self.dispatch_esc_code()
|
2022-08-22 08:03:31 +03:00
|
|
|
case unknown_csi_char:
|
|
|
|
self.invalid_escape_code()
|
|
|
|
}
|
|
|
|
case intermediate:
|
|
|
|
switch csi_type(ch) {
|
|
|
|
case parameter_csi_char, unknown_csi_char:
|
|
|
|
self.invalid_escape_code()
|
|
|
|
case final_csi_char:
|
2022-08-23 17:21:31 +03:00
|
|
|
return self.dispatch_esc_code()
|
2022-08-22 08:03:31 +03:00
|
|
|
}
|
|
|
|
}
|
2022-08-22 08:51:23 +03:00
|
|
|
case st_or_bel:
|
|
|
|
if ch == 0x7 {
|
2022-08-23 17:21:31 +03:00
|
|
|
return self.dispatch_esc_code()
|
2022-08-22 08:51:23 +03:00
|
|
|
}
|
|
|
|
fallthrough
|
2022-08-22 08:03:31 +03:00
|
|
|
case st:
|
|
|
|
if ch == 0x1b {
|
|
|
|
self.state = esc_st
|
|
|
|
} else if ch == 0xc2 {
|
|
|
|
self.state = c1_st
|
|
|
|
} else {
|
|
|
|
self.write_ch(ch)
|
|
|
|
}
|
|
|
|
case esc_st:
|
|
|
|
if ch == '\\' {
|
2022-08-23 17:21:31 +03:00
|
|
|
return self.dispatch_esc_code()
|
2022-08-22 08:03:31 +03:00
|
|
|
} else {
|
|
|
|
self.state = st
|
|
|
|
self.write_ch(0x1b)
|
|
|
|
if ch != 0x1b {
|
|
|
|
self.write_ch(ch)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
case c1_st:
|
|
|
|
if ch == 0x9c {
|
2022-08-23 17:21:31 +03:00
|
|
|
return self.dispatch_esc_code()
|
2022-08-22 08:03:31 +03:00
|
|
|
} else {
|
|
|
|
self.state = st
|
|
|
|
self.write_ch(0xc2)
|
|
|
|
self.write_ch(ch)
|
|
|
|
}
|
|
|
|
}
|
2022-08-23 17:21:31 +03:00
|
|
|
return nil
|
2022-08-22 08:03:31 +03:00
|
|
|
}
|