| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276 |
- package terminalparser
- import (
- "bytes"
- "log"
- "strconv"
- "unicode/utf8"
- "github.com/mattn/go-runewidth"
- )
- type Screen struct {
- Rows []*Row
- Cursor *Cursor
- pasteMode bool // Set bracketed paste mode, xterm. ?2004h reset ?2004l
- title string
- }
- func (s *Screen) Parse(data []byte) []string {
- s.Cursor.Y = 1
- s.Rows = append(s.Rows, &Row{
- dataRune: make([]rune, 0, 1024),
- })
- rest := data
- for len(rest) > 0 {
- code, size := utf8.DecodeRune(rest)
- rest = rest[size:]
- switch code {
- case ESCKey:
- code, size = utf8.DecodeRune(rest)
- rest = rest[size:]
- switch code {
- case '[':
- // CSI
- rest = s.parseCSISequence(rest)
- continue
- case ']':
- // OSC
- rest = s.parseOSCSequence(rest)
- continue
- default:
- if existIndex := bytes.IndexRune([]byte(string(Intermediate)), code); existIndex >= 0 {
- // ESC
- rest = s.parseIntermediate(code, rest)
- continue
- }
- if existIndex := bytes.IndexRune([]byte(string(Parameters)), code); existIndex >= 0 {
- log.Printf("Screen 未解析 ESC `%q` %xParameters字符\n", code, code)
- continue
- }
- if existIndex := bytes.IndexRune([]byte(string(Uppercase)), code); existIndex >= 0 {
- log.Printf("Screen 未解析 ESC `%q` %x Uppercase字符\n", code, code)
- continue
- }
- if existIndex := bytes.IndexRune([]byte(string(Lowercase)), code); existIndex >= 0 {
- log.Printf("Screen 未解析 ESC `%q` %x Lowercase字符\n", code, code)
- continue
- }
- log.Printf("Screen 未解析 ESC `%q` %x\n", code, code)
- }
- continue
- case Delete:
- continue
- default:
- if existIndex := bytes.IndexRune([]byte(string(C0Control)), code); existIndex >= 0 {
- s.parseC0Sequence(code)
- } else {
- if len(s.Rows) == 0 && s.Cursor.Y == 0 {
- s.Rows = append(s.Rows, &Row{
- dataRune: make([]rune, 0, 1024),
- })
- s.Cursor.Y++
- }
- s.appendCharacter(code)
- }
- continue
- }
- }
- result := make([]string, len(s.Rows))
- for i := range s.Rows {
- result[i] = s.Rows[i].String()
- }
- return result
- }
- func (s *Screen) parseC0Sequence(code rune) {
- switch code {
- case 0x07:
- //bell 忽略
- case 0x08:
- // 后退1光标
- s.Cursor.MoveLeft(1)
- case 0x0d:
- /*
- \r
- */
- s.Cursor.X = 0
- if s.Cursor.Y > len(s.Rows) {
- s.Rows = append(s.Rows, &Row{
- dataRune: make([]rune, 0, 1024),
- })
- }
- case 0x0a:
- /*
- \n
- */
- s.Cursor.Y++
- if s.Cursor.Y > len(s.Rows) {
- s.Rows = append(s.Rows, &Row{
- dataRune: make([]rune, 0, 1024),
- })
- }
- default:
- log.Printf("未处理的字符 %q %v\n", code, code)
- }
- }
- func (s *Screen) parseCSISequence(p []byte) []byte {
- endIndex := bytes.IndexFunc(p, IsAlphabetic)
- params := []rune(string(p[:endIndex]))
- switch rune(p[endIndex]) {
- case 'Y':
- // /*
- // ESC Y Ps Ps
- // Move the cursor to given row and column.
- // */
- if len(p[endIndex+1:]) < 2 {
- return p[endIndex+1:]
- }
- if row, err := strconv.Atoi(string(p[endIndex+1])); err == nil {
- s.Cursor.Y = row
- }
- if col, err := strconv.Atoi(string(p[endIndex+2])); err == nil {
- s.Cursor.X = col
- }
- return p[endIndex+3:]
- }
- funcName, ok := CSIFuncMap[rune(p[endIndex])]
- if ok {
- funcName(s, params)
- } else {
- log.Printf("screen未处理的CSI %s %q\n", DebugString(string(params)), p[endIndex])
- }
- return p[endIndex+1:]
- }
- func (s *Screen) parseIntermediate(code rune, p []byte) []byte {
- switch code {
- case '(':
- terminationIndex := bytes.IndexFunc(p, func(r rune) bool {
- if insideIndex := bytes.IndexRune([]byte(string(Alphabetic)), r); insideIndex < 0 {
- return false
- }
- return true
- })
- params := p[:terminationIndex+1]
- switch string(params) {
- case "B":
- /*
- ESC ( C Designate G0 Character Set, VT100, ISO 2022.
- C = B ⇒ United States (USASCII), VT100.
- */
- }
- p = p[terminationIndex+1:]
- return p
- case ')':
- terminationIndex := bytes.IndexFunc(p, func(r rune) bool {
- if insideIndex := bytes.IndexRune([]byte(string(Alphabetic)), r); insideIndex < 0 {
- return false
- }
- return true
- })
- p = p[terminationIndex+1:]
- default:
- log.Printf("Screen 未解析 ESC `%q` %x Intermediate字符\n", code, code)
- }
- return p
- }
- func (s *Screen) parseOSCSequence(p []byte) []byte {
- if endIndex := bytes.IndexRune(p, BEL); endIndex >= 0 {
- return p[endIndex+1:]
- }
- if endIndex := bytes.IndexRune(p, ST); endIndex >= 0 {
- return p[endIndex+1:]
- }
- log.Println("未处理的 parseOSCSequence")
- return p
- }
- func (s *Screen) appendCharacter(code rune) {
- currentRow := s.GetCursorRow()
- currentRow.changeCursorToX(s.Cursor.X)
- currentRow.appendCharacter(code)
- width := runewidth.StringWidth(string(code))
- s.Cursor.X += width
- }
- func (s *Screen) eraseEndToLine() {
- currentRow := s.GetCursorRow()
- currentRow.changeCursorToX(s.Cursor.X)
- currentRow.eraseRight()
- }
- func (s *Screen) eraseRight() {
- currentRow := s.GetCursorRow()
- currentRow.changeCursorToX(s.Cursor.X)
- currentRow.eraseRight()
- }
- func (s *Screen) eraseLeft() {
- log.Printf("Screen %s Erase Left cursor(%d,%d) 总Row数量 %d",
- UnsupportedMsg, s.Cursor.X, s.Cursor.Y, len(s.Rows))
- }
- func (s *Screen) eraseAbove() {
- s.Rows = s.Rows[s.Cursor.Y-1:]
- }
- func (s *Screen) eraseBelow() {
- s.Rows = s.Rows[:s.Cursor.Y]
- }
- func (s *Screen) eraseAll() {
- s.Rows = s.Rows[:0]
- //htop?
- s.Cursor.X = 0
- s.Cursor.Y = 0
- }
- func (s *Screen) eraseFromCursor() {
- if s.Cursor.Y > len(s.Rows) {
- s.Cursor.Y = len(s.Rows)
- }
- s.Rows = s.Rows[:s.Cursor.Y]
- currentRow := s.GetCursorRow()
- currentRow.changeCursorToX(s.Cursor.X)
- currentRow.eraseRight()
- }
- func (s *Screen) deleteChars(ps int) {
- currentRow := s.GetCursorRow()
- currentRow.changeCursorToX(s.Cursor.X)
- currentRow.deleteChars(ps)
- }
- func (s *Screen) GetCursorRow() *Row {
- if s.Cursor.Y == 0 {
- s.Cursor.Y++
- }
- if len(s.Rows) == 0 {
- s.Rows = append(s.Rows, &Row{
- dataRune: make([]rune, 0, 1024),
- })
- }
- index := s.Cursor.Y - 1
- if index >= len(s.Rows) {
- log.Printf("总行数 %d 比当前行 %d 小,可能存在解析错误 \n", len(s.Rows), s.Cursor.Y)
- return s.Rows[len(s.Rows)-1]
- }
- return s.Rows[s.Cursor.Y-1]
- }
- const UnsupportedMsg = "Unsupported"
|