diff options
Diffstat (limited to 'presentty/ansiparser.py')
-rw-r--r-- | presentty/ansiparser.py | 185 |
1 files changed, 185 insertions, 0 deletions
diff --git a/presentty/ansiparser.py b/presentty/ansiparser.py new file mode 100644 index 0000000..a780b42 --- /dev/null +++ b/presentty/ansiparser.py | |||
@@ -0,0 +1,185 @@ | |||
1 | # Copyright (C) 2015 James E. Blair <corvus@gnu.org> | ||
2 | # | ||
3 | # This program is free software: you can redistribute it and/or modify | ||
4 | # it under the terms of the GNU General Public License as published by | ||
5 | # the Free Software Foundation, either version 3 of the License, or | ||
6 | # (at your option) any later version. | ||
7 | # | ||
8 | # This program is distributed in the hope that it will be useful, | ||
9 | # but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
10 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
11 | # GNU General Public License for more details. | ||
12 | # | ||
13 | # You should have received a copy of the GNU General Public License | ||
14 | # along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
15 | |||
16 | import re | ||
17 | |||
18 | import urwid | ||
19 | |||
20 | class ANSIParser(object): | ||
21 | colors = [ | ||
22 | urwid.BLACK, | ||
23 | urwid.DARK_RED, | ||
24 | urwid.DARK_GREEN, | ||
25 | urwid.BROWN, | ||
26 | urwid.DARK_BLUE, | ||
27 | urwid.DARK_MAGENTA, | ||
28 | urwid.DARK_CYAN, | ||
29 | urwid.LIGHT_GRAY, | ||
30 | urwid.DARK_GRAY, | ||
31 | urwid.LIGHT_RED, | ||
32 | urwid.LIGHT_GREEN, | ||
33 | urwid.YELLOW, | ||
34 | urwid.LIGHT_BLUE, | ||
35 | urwid.LIGHT_MAGENTA, | ||
36 | urwid.LIGHT_CYAN, | ||
37 | urwid.WHITE, | ||
38 | ] | ||
39 | |||
40 | colors256 = ['0', '6', '8', 'a', 'd', 'f'] | ||
41 | colorsgray = ['3', '7', '11', '13', '15', '19', '23', '27', '31', | ||
42 | '35', '38', '42', '46', '50', '52', '58', '62', '66', | ||
43 | '70', '74', '78', '82', '85', '89', '93'] | ||
44 | |||
45 | def __init__(self): | ||
46 | self.x = 0 | ||
47 | self.y = 0 | ||
48 | self.text_lines = [] | ||
49 | self.attr_lines = [] | ||
50 | self.background = urwid.AttrSpec('light gray', 'black') | ||
51 | self.attr = self.background | ||
52 | self.resetColor() | ||
53 | self.moveTo(0,0) | ||
54 | |||
55 | def resetColor(self): | ||
56 | self.bold = False | ||
57 | self.blink = False | ||
58 | self.fg = 7 | ||
59 | self.bg = 0 | ||
60 | |||
61 | def moveTo(self, x, y): | ||
62 | while x>80: | ||
63 | x-=80 | ||
64 | y+=1 | ||
65 | while y+1 > len(self.text_lines): | ||
66 | self.text_lines.append([u' ' for i in range(80)]) | ||
67 | self.attr_lines.append([self.attr for i in range(80)]) | ||
68 | self.x = x | ||
69 | self.y = y | ||
70 | |||
71 | def parseSequence(self, seq): | ||
72 | values = [] | ||
73 | buf = '' | ||
74 | for c in seq: | ||
75 | if c in ['\x1b', '[']: | ||
76 | continue | ||
77 | if c == ';': | ||
78 | values.append(int(buf)) | ||
79 | buf = '' | ||
80 | continue | ||
81 | if ord(c) < 64: | ||
82 | buf += c | ||
83 | if buf: | ||
84 | values.append(int(buf)) | ||
85 | if c == 'm': | ||
86 | if not values: | ||
87 | values = [0] | ||
88 | fg256 = None | ||
89 | for v in values: | ||
90 | if fg256 is True: | ||
91 | if v <= 0x08: | ||
92 | self.fg = v | ||
93 | elif v <= 0x0f: | ||
94 | self.fg = v - 0x08 | ||
95 | self.bold = True | ||
96 | elif v <= 0xe7: | ||
97 | r, x = divmod(v-16, 36) | ||
98 | g, x = divmod(x, 6) | ||
99 | b = x % 6 | ||
100 | fg256 = ('#' + | ||
101 | self.colors256[r] + | ||
102 | self.colors256[g] + | ||
103 | self.colors256[b]) | ||
104 | else: | ||
105 | fg256 = 'g' + str(self.colorsgray[v-232]) | ||
106 | elif v == 0: | ||
107 | self.resetColor() | ||
108 | elif v == 1: | ||
109 | self.bold = True | ||
110 | elif v == 5: | ||
111 | self.blink = True | ||
112 | elif v>29 and v<38: | ||
113 | self.fg = v-30 | ||
114 | elif v>39 and v<48: | ||
115 | self.bg = v-40 | ||
116 | elif v==38: | ||
117 | fg256=True | ||
118 | fg = self.fg | ||
119 | if self.bold: | ||
120 | fg += 8 | ||
121 | fgattrs = [] | ||
122 | if self.blink: | ||
123 | fgattrs.append('blink') | ||
124 | if fg256: | ||
125 | fgattrs.append(fg256) | ||
126 | else: | ||
127 | fgattrs.append(self.colors[fg]) | ||
128 | self.attr = urwid.AttrSpec(', '.join(fgattrs), self.colors[self.bg]) | ||
129 | if c == 'A': | ||
130 | if not values: | ||
131 | values = [1] | ||
132 | y = max(self.y-values[0], 0) | ||
133 | self.moveTo(self.x, y) | ||
134 | if c == 'C': | ||
135 | if not values: | ||
136 | values = [1] | ||
137 | x = self.x + values[0] | ||
138 | self.moveTo(x, self.y) | ||
139 | if c == 'H': | ||
140 | self.moveTo(values[1]-1, values[0]-1) | ||
141 | |||
142 | def parse(self, data): | ||
143 | seq = '' | ||
144 | for char in data: | ||
145 | if seq: | ||
146 | seq += char | ||
147 | if ord(char) >= 64 and char != '[': | ||
148 | self.parseSequence(seq) | ||
149 | seq = '' | ||
150 | continue | ||
151 | if char == '\x1a': | ||
152 | continue | ||
153 | if char == '\x1b': | ||
154 | seq = char | ||
155 | continue | ||
156 | if char == '\r': | ||
157 | self.moveTo(0, self.y) | ||
158 | continue | ||
159 | if char == '\n': | ||
160 | self.moveTo(self.x, self.y+1) | ||
161 | continue | ||
162 | if not seq: | ||
163 | self.text_lines[self.y][self.x] = char | ||
164 | self.attr_lines[self.y][self.x] = self.attr | ||
165 | x = self.x + 1 | ||
166 | self.moveTo(x, self.y) | ||
167 | text = [] | ||
168 | current_attr = self.attr_lines[0][0] | ||
169 | current_text = u'' | ||
170 | for y in range(len(self.text_lines)): | ||
171 | for x in range(80): | ||
172 | char = self.text_lines[y][x] | ||
173 | attr = self.attr_lines[y][x] | ||
174 | if (attr.foreground_number != current_attr.foreground_number or | ||
175 | attr.background_number != current_attr.background_number): | ||
176 | text.append((current_attr, current_text)) | ||
177 | current_attr = attr | ||
178 | current_text = u'' | ||
179 | current_text += char | ||
180 | if (current_attr.background_number==0): | ||
181 | current_text = current_text.rstrip(' ') | ||
182 | current_text += u'\n' | ||
183 | current_text = re.sub('\n+$', '\n', current_text) | ||
184 | text.append((current_attr, current_text)) | ||
185 | return text | ||