cc: Added inline to Tile::IsReadyToDraw
[chromium-blink-merge.git] / third_party / pexpect / ANSI.py
blob69f8c5412a711ee7b163b0a1de7d9adcd768bfd5
1 """This implements an ANSI (VT100) terminal emulator as a subclass of screen.
3 PEXPECT LICENSE
5 This license is approved by the OSI and FSF as GPL-compatible.
6 http://opensource.org/licenses/isc-license.txt
8 Copyright (c) 2012, Noah Spurrier <noah@noah.org>
9 PERMISSION TO USE, COPY, MODIFY, AND/OR DISTRIBUTE THIS SOFTWARE FOR ANY
10 PURPOSE WITH OR WITHOUT FEE IS HEREBY GRANTED, PROVIDED THAT THE ABOVE
11 COPYRIGHT NOTICE AND THIS PERMISSION NOTICE APPEAR IN ALL COPIES.
12 THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
13 WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
14 MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
15 ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
16 WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
17 ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
18 OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
20 """
22 # references:
23 # http://en.wikipedia.org/wiki/ANSI_escape_code
24 # http://www.retards.org/terminals/vt102.html
25 # http://vt100.net/docs/vt102-ug/contents.html
26 # http://vt100.net/docs/vt220-rm/
27 # http://www.termsys.demon.co.uk/vtansi.htm
29 import screen
30 import FSM
31 import copy
32 import string
35 # The 'Do.*' functions are helper functions for the ANSI class.
37 def DoEmit (fsm):
39 screen = fsm.memory[0]
40 screen.write_ch(fsm.input_symbol)
42 def DoStartNumber (fsm):
44 fsm.memory.append (fsm.input_symbol)
46 def DoBuildNumber (fsm):
48 ns = fsm.memory.pop()
49 ns = ns + fsm.input_symbol
50 fsm.memory.append (ns)
52 def DoBackOne (fsm):
54 screen = fsm.memory[0]
55 screen.cursor_back ()
57 def DoBack (fsm):
59 count = int(fsm.memory.pop())
60 screen = fsm.memory[0]
61 screen.cursor_back (count)
63 def DoDownOne (fsm):
65 screen = fsm.memory[0]
66 screen.cursor_down ()
68 def DoDown (fsm):
70 count = int(fsm.memory.pop())
71 screen = fsm.memory[0]
72 screen.cursor_down (count)
74 def DoForwardOne (fsm):
76 screen = fsm.memory[0]
77 screen.cursor_forward ()
79 def DoForward (fsm):
81 count = int(fsm.memory.pop())
82 screen = fsm.memory[0]
83 screen.cursor_forward (count)
85 def DoUpReverse (fsm):
87 screen = fsm.memory[0]
88 screen.cursor_up_reverse()
90 def DoUpOne (fsm):
92 screen = fsm.memory[0]
93 screen.cursor_up ()
95 def DoUp (fsm):
97 count = int(fsm.memory.pop())
98 screen = fsm.memory[0]
99 screen.cursor_up (count)
101 def DoHome (fsm):
103 c = int(fsm.memory.pop())
104 r = int(fsm.memory.pop())
105 screen = fsm.memory[0]
106 screen.cursor_home (r,c)
108 def DoHomeOrigin (fsm):
110 c = 1
111 r = 1
112 screen = fsm.memory[0]
113 screen.cursor_home (r,c)
115 def DoEraseDown (fsm):
117 screen = fsm.memory[0]
118 screen.erase_down()
120 def DoErase (fsm):
122 arg = int(fsm.memory.pop())
123 screen = fsm.memory[0]
124 if arg == 0:
125 screen.erase_down()
126 elif arg == 1:
127 screen.erase_up()
128 elif arg == 2:
129 screen.erase_screen()
131 def DoEraseEndOfLine (fsm):
133 screen = fsm.memory[0]
134 screen.erase_end_of_line()
136 def DoEraseLine (fsm):
138 arg = int(fsm.memory.pop())
139 screen = fsm.memory[0]
140 if arg == 0:
141 screen.erase_end_of_line()
142 elif arg == 1:
143 screen.erase_start_of_line()
144 elif arg == 2:
145 screen.erase_line()
147 def DoEnableScroll (fsm):
149 screen = fsm.memory[0]
150 screen.scroll_screen()
152 def DoCursorSave (fsm):
154 screen = fsm.memory[0]
155 screen.cursor_save_attrs()
157 def DoCursorRestore (fsm):
159 screen = fsm.memory[0]
160 screen.cursor_restore_attrs()
162 def DoScrollRegion (fsm):
164 screen = fsm.memory[0]
165 r2 = int(fsm.memory.pop())
166 r1 = int(fsm.memory.pop())
167 screen.scroll_screen_rows (r1,r2)
169 def DoMode (fsm):
171 screen = fsm.memory[0]
172 mode = fsm.memory.pop() # Should be 4
173 # screen.setReplaceMode ()
175 def DoLog (fsm):
177 screen = fsm.memory[0]
178 fsm.memory = [screen]
179 fout = open ('log', 'a')
180 fout.write (fsm.input_symbol + ',' + fsm.current_state + '\n')
181 fout.close()
183 class term (screen.screen):
185 """This class is an abstract, generic terminal.
186 This does nothing. This is a placeholder that
187 provides a common base class for other terminals
188 such as an ANSI terminal. """
190 def __init__ (self, r=24, c=80):
192 screen.screen.__init__(self, r,c)
194 class ANSI (term):
196 """This class implements an ANSI (VT100) terminal.
197 It is a stream filter that recognizes ANSI terminal
198 escape sequences and maintains the state of a screen object. """
200 def __init__ (self, r=24,c=80):
202 term.__init__(self,r,c)
204 #self.screen = screen (24,80)
205 self.state = FSM.FSM ('INIT',[self])
206 self.state.set_default_transition (DoLog, 'INIT')
207 self.state.add_transition_any ('INIT', DoEmit, 'INIT')
208 self.state.add_transition ('\x1b', 'INIT', None, 'ESC')
209 self.state.add_transition_any ('ESC', DoLog, 'INIT')
210 self.state.add_transition ('(', 'ESC', None, 'G0SCS')
211 self.state.add_transition (')', 'ESC', None, 'G1SCS')
212 self.state.add_transition_list ('AB012', 'G0SCS', None, 'INIT')
213 self.state.add_transition_list ('AB012', 'G1SCS', None, 'INIT')
214 self.state.add_transition ('7', 'ESC', DoCursorSave, 'INIT')
215 self.state.add_transition ('8', 'ESC', DoCursorRestore, 'INIT')
216 self.state.add_transition ('M', 'ESC', DoUpReverse, 'INIT')
217 self.state.add_transition ('>', 'ESC', DoUpReverse, 'INIT')
218 self.state.add_transition ('<', 'ESC', DoUpReverse, 'INIT')
219 self.state.add_transition ('=', 'ESC', None, 'INIT') # Selects application keypad.
220 self.state.add_transition ('#', 'ESC', None, 'GRAPHICS_POUND')
221 self.state.add_transition_any ('GRAPHICS_POUND', None, 'INIT')
222 self.state.add_transition ('[', 'ESC', None, 'ELB')
223 # ELB means Escape Left Bracket. That is ^[[
224 self.state.add_transition ('H', 'ELB', DoHomeOrigin, 'INIT')
225 self.state.add_transition ('D', 'ELB', DoBackOne, 'INIT')
226 self.state.add_transition ('B', 'ELB', DoDownOne, 'INIT')
227 self.state.add_transition ('C', 'ELB', DoForwardOne, 'INIT')
228 self.state.add_transition ('A', 'ELB', DoUpOne, 'INIT')
229 self.state.add_transition ('J', 'ELB', DoEraseDown, 'INIT')
230 self.state.add_transition ('K', 'ELB', DoEraseEndOfLine, 'INIT')
231 self.state.add_transition ('r', 'ELB', DoEnableScroll, 'INIT')
232 self.state.add_transition ('m', 'ELB', None, 'INIT')
233 self.state.add_transition ('?', 'ELB', None, 'MODECRAP')
234 self.state.add_transition_list (string.digits, 'ELB', DoStartNumber, 'NUMBER_1')
235 self.state.add_transition_list (string.digits, 'NUMBER_1', DoBuildNumber, 'NUMBER_1')
236 self.state.add_transition ('D', 'NUMBER_1', DoBack, 'INIT')
237 self.state.add_transition ('B', 'NUMBER_1', DoDown, 'INIT')
238 self.state.add_transition ('C', 'NUMBER_1', DoForward, 'INIT')
239 self.state.add_transition ('A', 'NUMBER_1', DoUp, 'INIT')
240 self.state.add_transition ('J', 'NUMBER_1', DoErase, 'INIT')
241 self.state.add_transition ('K', 'NUMBER_1', DoEraseLine, 'INIT')
242 self.state.add_transition ('l', 'NUMBER_1', DoMode, 'INIT')
243 ### It gets worse... the 'm' code can have infinite number of
244 ### number;number;number before it. I've never seen more than two,
245 ### but the specs say it's allowed. crap!
246 self.state.add_transition ('m', 'NUMBER_1', None, 'INIT')
247 ### LED control. Same implementation problem as 'm' code.
248 self.state.add_transition ('q', 'NUMBER_1', None, 'INIT')
250 # \E[?47h switch to alternate screen
251 # \E[?47l restores to normal screen from alternate screen.
252 self.state.add_transition_list (string.digits, 'MODECRAP', DoStartNumber, 'MODECRAP_NUM')
253 self.state.add_transition_list (string.digits, 'MODECRAP_NUM', DoBuildNumber, 'MODECRAP_NUM')
254 self.state.add_transition ('l', 'MODECRAP_NUM', None, 'INIT')
255 self.state.add_transition ('h', 'MODECRAP_NUM', None, 'INIT')
257 #RM Reset Mode Esc [ Ps l none
258 self.state.add_transition (';', 'NUMBER_1', None, 'SEMICOLON')
259 self.state.add_transition_any ('SEMICOLON', DoLog, 'INIT')
260 self.state.add_transition_list (string.digits, 'SEMICOLON', DoStartNumber, 'NUMBER_2')
261 self.state.add_transition_list (string.digits, 'NUMBER_2', DoBuildNumber, 'NUMBER_2')
262 self.state.add_transition_any ('NUMBER_2', DoLog, 'INIT')
263 self.state.add_transition ('H', 'NUMBER_2', DoHome, 'INIT')
264 self.state.add_transition ('f', 'NUMBER_2', DoHome, 'INIT')
265 self.state.add_transition ('r', 'NUMBER_2', DoScrollRegion, 'INIT')
266 ### It gets worse... the 'm' code can have infinite number of
267 ### number;number;number before it. I've never seen more than two,
268 ### but the specs say it's allowed. crap!
269 self.state.add_transition ('m', 'NUMBER_2', None, 'INIT')
270 ### LED control. Same problem as 'm' code.
271 self.state.add_transition ('q', 'NUMBER_2', None, 'INIT')
272 self.state.add_transition (';', 'NUMBER_2', None, 'SEMICOLON_X')
274 # Create a state for 'q' and 'm' which allows an infinite number of ignored numbers
275 self.state.add_transition_any ('SEMICOLON_X', DoLog, 'INIT')
276 self.state.add_transition_list (string.digits, 'SEMICOLON_X', None, 'NUMBER_X')
277 self.state.add_transition_any ('NUMBER_X', DoLog, 'INIT')
278 self.state.add_transition ('m', 'NUMBER_X', None, 'INIT')
279 self.state.add_transition ('q', 'NUMBER_X', None, 'INIT')
280 self.state.add_transition (';', 'NUMBER_2', None, 'SEMICOLON_X')
282 def process (self, c):
284 self.state.process(c)
286 def process_list (self, l):
288 self.write(l)
290 def write (self, s):
292 for c in s:
293 self.process(c)
295 def flush (self):
297 pass
299 def write_ch (self, ch):
301 """This puts a character at the current cursor position. The cursor
302 position is moved forward with wrap-around, but no scrolling is done if
303 the cursor hits the lower-right corner of the screen. """
305 #\r and \n both produce a call to cr() and lf(), respectively.
306 ch = ch[0]
308 if ch == '\r':
309 self.cr()
310 return
311 if ch == '\n':
312 self.crlf()
313 return
314 if ch == chr(screen.BS):
315 self.cursor_back()
316 return
317 if ch not in string.printable:
318 fout = open ('log', 'a')
319 fout.write ('Nonprint: ' + str(ord(ch)) + '\n')
320 fout.close()
321 return
322 self.put_abs(self.cur_r, self.cur_c, ch)
323 old_r = self.cur_r
324 old_c = self.cur_c
325 self.cursor_forward()
326 if old_c == self.cur_c:
327 self.cursor_down()
328 if old_r != self.cur_r:
329 self.cursor_home (self.cur_r, 1)
330 else:
331 self.scroll_up ()
332 self.cursor_home (self.cur_r, 1)
333 self.erase_line()
335 # def test (self):
337 # import sys
338 # write_text = 'I\'ve got a ferret sticking up my nose.\n' + \
339 # '(He\'s got a ferret sticking up his nose.)\n' + \
340 # 'How it got there I can\'t tell\n' + \
341 # 'But now it\'s there it hurts like hell\n' + \
342 # 'And what is more it radically affects my sense of smell.\n' + \
343 # '(His sense of smell.)\n' + \
344 # 'I can see a bare-bottomed mandril.\n' + \
345 # '(Slyly eyeing his other nostril.)\n' + \
346 # 'If it jumps inside there too I really don\'t know what to do\n' + \
347 # 'I\'ll be the proud posessor of a kind of nasal zoo.\n' + \
348 # '(A nasal zoo.)\n' + \
349 # 'I\'ve got a ferret sticking up my nose.\n' + \
350 # '(And what is worst of all it constantly explodes.)\n' + \
351 # '"Ferrets don\'t explode," you say\n' + \
352 # 'But it happened nine times yesterday\n' + \
353 # 'And I should know for each time I was standing in the way.\n' + \
354 # 'I\'ve got a ferret sticking up my nose.\n' + \
355 # '(He\'s got a ferret sticking up his nose.)\n' + \
356 # 'How it got there I can\'t tell\n' + \
357 # 'But now it\'s there it hurts like hell\n' + \
358 # 'And what is more it radically affects my sense of smell.\n' + \
359 # '(His sense of smell.)'
360 # self.fill('.')
361 # self.cursor_home()
362 # for c in write_text:
363 # self.write_ch (c)
364 # print str(self)
366 #if __name__ == '__main__':
367 # t = ANSI(6,65)
368 # t.test()