summaryrefslogtreecommitdiff
path: root/presentty/ansiparser.py
diff options
context:
space:
mode:
Diffstat (limited to 'presentty/ansiparser.py')
-rw-r--r--presentty/ansiparser.py185
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
16import re
17
18import urwid
19
20class 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