File: ansi_c_escapes.go

package info (click to toggle)
kitty 0.42.1-1
  • links: PTS, VCS
  • area: main
  • in suites: experimental
  • size: 28,564 kB
  • sloc: ansic: 82,787; python: 55,191; objc: 5,122; sh: 1,295; xml: 364; makefile: 143; javascript: 78
file content (148 lines) | stat: -rw-r--r-- 3,120 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
// License: GPLv3 Copyright: 2022, Kovid Goyal, <kovid at kovidgoyal.net>

package shlex

import (
	"fmt"
	"strconv"
	"strings"
	"unicode/utf8"
)

var _ = fmt.Print

type state int

const (
	normal state = iota
	control_char
	backslash
	hex_digit
	oct_digit
)

type ansi_c struct {
	state                        state
	max_num_of_digits, digit_idx int
	digits                       [16]rune
	output                       strings.Builder
}

func is_hex_char(ch rune) bool {
	return ('0' <= ch && ch <= '9') || ('a' <= ch && ch <= 'f') || ('A' <= ch && ch <= 'F')
}

func is_oct_char(ch rune) bool {
	return '0' <= ch && ch <= '7'
}

func (self *ansi_c) write_digits(base int) {
	if self.digit_idx > 0 {
		text := string(self.digits[:self.digit_idx])
		if val, err := strconv.ParseUint(text, base, 32); err == nil && val <= utf8.MaxRune {
			self.output.WriteRune(rune(val))
		}
	}
	self.digit_idx = 0
	self.state = normal
}

func (self *ansi_c) parse(ch rune) {
	switch self.state {
	case normal:
		if ch == '\\' {
			self.state = backslash
		} else {
			self.output.WriteRune(ch)
		}
	case control_char:
		self.output.WriteRune(ch & 0x1f)
		self.state = normal
	case hex_digit:
		if self.digit_idx < self.max_num_of_digits && is_hex_char(ch) {
			self.digits[self.digit_idx] = ch
			self.digit_idx++
		} else {
			self.write_digits(16)
			self.parse(ch)
		}
	case oct_digit:
		if self.digit_idx < self.max_num_of_digits && is_oct_char(ch) {
			self.digits[self.digit_idx] = ch
			self.digit_idx++
		} else {
			self.write_digits(8)
			self.parse(ch)
		}
	case backslash:
		self.state = normal
		switch ch {
		default:
			self.output.WriteRune('\\')
			self.output.WriteRune(ch)
		case 'a':
			self.output.WriteRune(7)
		case 'b':
			self.output.WriteRune(8)
		case 'c':
			self.state = control_char
		case 'e', 'E':
			self.output.WriteRune(27)
		case 'f':
			self.output.WriteRune(12)
		case 'n':
			self.output.WriteRune(10)
		case 'r':
			self.output.WriteRune(13)
		case 't':
			self.output.WriteRune(9)
		case 'v':
			self.output.WriteRune(11)
		case 'x':
			self.max_num_of_digits, self.digit_idx, self.state = 2, 0, hex_digit
		case 'u':
			self.max_num_of_digits, self.digit_idx, self.state = 4, 0, hex_digit
		case 'U':
			self.max_num_of_digits, self.digit_idx, self.state = 8, 0, hex_digit
		case '0', '1', '2', '3', '4', '5', '6', '7':
			self.max_num_of_digits, self.digit_idx, self.state = 3, 1, oct_digit
			self.digits[0] = ch
		case '\\':
			self.output.WriteRune('\\')
		case '?':
			self.output.WriteRune('?')
		case '"':
			self.output.WriteRune('"')
		case '\'':
			self.output.WriteRune('\'')

		}
	}
}

func (self *ansi_c) finish() string {
	switch self.state {
	case hex_digit:
		self.write_digits(16)
	case oct_digit:
		self.write_digits(8)
	case backslash:
		self.output.WriteRune('\\')
	case control_char:
		self.output.WriteString("\\c")
	}
	self.state = normal
	self.digit_idx = 0
	s := self.output.String()
	self.output.Reset()
	return s
}

func ExpandANSICEscapes(src string) string {
	p := ansi_c{}
	p.output.Grow(len(src))
	for _, ch := range src {
		p.parse(ch)
	}
	return p.finish()
}