xref: /openbsd-src/gnu/llvm/lldb/third_party/Python/module/pexpect-4.6/pexpect/ANSI.py (revision 061da546b983eb767bad15e67af1174fb0bcf31c)
1*061da546Spatrick'''This implements an ANSI (VT100) terminal emulator as a subclass of screen.
2*061da546Spatrick
3*061da546SpatrickPEXPECT LICENSE
4*061da546Spatrick
5*061da546Spatrick    This license is approved by the OSI and FSF as GPL-compatible.
6*061da546Spatrick        http://opensource.org/licenses/isc-license.txt
7*061da546Spatrick
8*061da546Spatrick    Copyright (c) 2012, Noah Spurrier <noah@noah.org>
9*061da546Spatrick    PERMISSION TO USE, COPY, MODIFY, AND/OR DISTRIBUTE THIS SOFTWARE FOR ANY
10*061da546Spatrick    PURPOSE WITH OR WITHOUT FEE IS HEREBY GRANTED, PROVIDED THAT THE ABOVE
11*061da546Spatrick    COPYRIGHT NOTICE AND THIS PERMISSION NOTICE APPEAR IN ALL COPIES.
12*061da546Spatrick    THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
13*061da546Spatrick    WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
14*061da546Spatrick    MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
15*061da546Spatrick    ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
16*061da546Spatrick    WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
17*061da546Spatrick    ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
18*061da546Spatrick    OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
19*061da546Spatrick
20*061da546Spatrick'''
21*061da546Spatrick
22*061da546Spatrick# references:
23*061da546Spatrick#     http://en.wikipedia.org/wiki/ANSI_escape_code
24*061da546Spatrick#     http://www.retards.org/terminals/vt102.html
25*061da546Spatrick#     http://vt100.net/docs/vt102-ug/contents.html
26*061da546Spatrick#     http://vt100.net/docs/vt220-rm/
27*061da546Spatrick#     http://www.termsys.demon.co.uk/vtansi.htm
28*061da546Spatrick
29*061da546Spatrickfrom . import screen
30*061da546Spatrickfrom . import FSM
31*061da546Spatrickimport string
32*061da546Spatrick
33*061da546Spatrick#
34*061da546Spatrick# The 'Do.*' functions are helper functions for the ANSI class.
35*061da546Spatrick#
36*061da546Spatrickdef DoEmit (fsm):
37*061da546Spatrick
38*061da546Spatrick    screen = fsm.memory[0]
39*061da546Spatrick    screen.write_ch(fsm.input_symbol)
40*061da546Spatrick
41*061da546Spatrickdef DoStartNumber (fsm):
42*061da546Spatrick
43*061da546Spatrick    fsm.memory.append (fsm.input_symbol)
44*061da546Spatrick
45*061da546Spatrickdef DoBuildNumber (fsm):
46*061da546Spatrick
47*061da546Spatrick    ns = fsm.memory.pop()
48*061da546Spatrick    ns = ns + fsm.input_symbol
49*061da546Spatrick    fsm.memory.append (ns)
50*061da546Spatrick
51*061da546Spatrickdef DoBackOne (fsm):
52*061da546Spatrick
53*061da546Spatrick    screen = fsm.memory[0]
54*061da546Spatrick    screen.cursor_back ()
55*061da546Spatrick
56*061da546Spatrickdef DoBack (fsm):
57*061da546Spatrick
58*061da546Spatrick    count = int(fsm.memory.pop())
59*061da546Spatrick    screen = fsm.memory[0]
60*061da546Spatrick    screen.cursor_back (count)
61*061da546Spatrick
62*061da546Spatrickdef DoDownOne (fsm):
63*061da546Spatrick
64*061da546Spatrick    screen = fsm.memory[0]
65*061da546Spatrick    screen.cursor_down ()
66*061da546Spatrick
67*061da546Spatrickdef DoDown (fsm):
68*061da546Spatrick
69*061da546Spatrick    count = int(fsm.memory.pop())
70*061da546Spatrick    screen = fsm.memory[0]
71*061da546Spatrick    screen.cursor_down (count)
72*061da546Spatrick
73*061da546Spatrickdef DoForwardOne (fsm):
74*061da546Spatrick
75*061da546Spatrick    screen = fsm.memory[0]
76*061da546Spatrick    screen.cursor_forward ()
77*061da546Spatrick
78*061da546Spatrickdef DoForward (fsm):
79*061da546Spatrick
80*061da546Spatrick    count = int(fsm.memory.pop())
81*061da546Spatrick    screen = fsm.memory[0]
82*061da546Spatrick    screen.cursor_forward (count)
83*061da546Spatrick
84*061da546Spatrickdef DoUpReverse (fsm):
85*061da546Spatrick
86*061da546Spatrick    screen = fsm.memory[0]
87*061da546Spatrick    screen.cursor_up_reverse()
88*061da546Spatrick
89*061da546Spatrickdef DoUpOne (fsm):
90*061da546Spatrick
91*061da546Spatrick    screen = fsm.memory[0]
92*061da546Spatrick    screen.cursor_up ()
93*061da546Spatrick
94*061da546Spatrickdef DoUp (fsm):
95*061da546Spatrick
96*061da546Spatrick    count = int(fsm.memory.pop())
97*061da546Spatrick    screen = fsm.memory[0]
98*061da546Spatrick    screen.cursor_up (count)
99*061da546Spatrick
100*061da546Spatrickdef DoHome (fsm):
101*061da546Spatrick
102*061da546Spatrick    c = int(fsm.memory.pop())
103*061da546Spatrick    r = int(fsm.memory.pop())
104*061da546Spatrick    screen = fsm.memory[0]
105*061da546Spatrick    screen.cursor_home (r,c)
106*061da546Spatrick
107*061da546Spatrickdef DoHomeOrigin (fsm):
108*061da546Spatrick
109*061da546Spatrick    c = 1
110*061da546Spatrick    r = 1
111*061da546Spatrick    screen = fsm.memory[0]
112*061da546Spatrick    screen.cursor_home (r,c)
113*061da546Spatrick
114*061da546Spatrickdef DoEraseDown (fsm):
115*061da546Spatrick
116*061da546Spatrick    screen = fsm.memory[0]
117*061da546Spatrick    screen.erase_down()
118*061da546Spatrick
119*061da546Spatrickdef DoErase (fsm):
120*061da546Spatrick
121*061da546Spatrick    arg = int(fsm.memory.pop())
122*061da546Spatrick    screen = fsm.memory[0]
123*061da546Spatrick    if arg == 0:
124*061da546Spatrick        screen.erase_down()
125*061da546Spatrick    elif arg == 1:
126*061da546Spatrick        screen.erase_up()
127*061da546Spatrick    elif arg == 2:
128*061da546Spatrick        screen.erase_screen()
129*061da546Spatrick
130*061da546Spatrickdef DoEraseEndOfLine (fsm):
131*061da546Spatrick
132*061da546Spatrick    screen = fsm.memory[0]
133*061da546Spatrick    screen.erase_end_of_line()
134*061da546Spatrick
135*061da546Spatrickdef DoEraseLine (fsm):
136*061da546Spatrick
137*061da546Spatrick    arg = int(fsm.memory.pop())
138*061da546Spatrick    screen = fsm.memory[0]
139*061da546Spatrick    if arg == 0:
140*061da546Spatrick        screen.erase_end_of_line()
141*061da546Spatrick    elif arg == 1:
142*061da546Spatrick        screen.erase_start_of_line()
143*061da546Spatrick    elif arg == 2:
144*061da546Spatrick        screen.erase_line()
145*061da546Spatrick
146*061da546Spatrickdef DoEnableScroll (fsm):
147*061da546Spatrick
148*061da546Spatrick    screen = fsm.memory[0]
149*061da546Spatrick    screen.scroll_screen()
150*061da546Spatrick
151*061da546Spatrickdef DoCursorSave (fsm):
152*061da546Spatrick
153*061da546Spatrick    screen = fsm.memory[0]
154*061da546Spatrick    screen.cursor_save_attrs()
155*061da546Spatrick
156*061da546Spatrickdef DoCursorRestore (fsm):
157*061da546Spatrick
158*061da546Spatrick    screen = fsm.memory[0]
159*061da546Spatrick    screen.cursor_restore_attrs()
160*061da546Spatrick
161*061da546Spatrickdef DoScrollRegion (fsm):
162*061da546Spatrick
163*061da546Spatrick    screen = fsm.memory[0]
164*061da546Spatrick    r2 = int(fsm.memory.pop())
165*061da546Spatrick    r1 = int(fsm.memory.pop())
166*061da546Spatrick    screen.scroll_screen_rows (r1,r2)
167*061da546Spatrick
168*061da546Spatrickdef DoMode (fsm):
169*061da546Spatrick
170*061da546Spatrick    screen = fsm.memory[0]
171*061da546Spatrick    mode = fsm.memory.pop() # Should be 4
172*061da546Spatrick    # screen.setReplaceMode ()
173*061da546Spatrick
174*061da546Spatrickdef DoLog (fsm):
175*061da546Spatrick
176*061da546Spatrick    screen = fsm.memory[0]
177*061da546Spatrick    fsm.memory = [screen]
178*061da546Spatrick    fout = open ('log', 'a')
179*061da546Spatrick    fout.write (fsm.input_symbol + ',' + fsm.current_state + '\n')
180*061da546Spatrick    fout.close()
181*061da546Spatrick
182*061da546Spatrickclass term (screen.screen):
183*061da546Spatrick
184*061da546Spatrick    '''This class is an abstract, generic terminal.
185*061da546Spatrick    This does nothing. This is a placeholder that
186*061da546Spatrick    provides a common base class for other terminals
187*061da546Spatrick    such as an ANSI terminal. '''
188*061da546Spatrick
189*061da546Spatrick    def __init__ (self, r=24, c=80, *args, **kwargs):
190*061da546Spatrick
191*061da546Spatrick        screen.screen.__init__(self, r,c,*args,**kwargs)
192*061da546Spatrick
193*061da546Spatrickclass ANSI (term):
194*061da546Spatrick    '''This class implements an ANSI (VT100) terminal.
195*061da546Spatrick    It is a stream filter that recognizes ANSI terminal
196*061da546Spatrick    escape sequences and maintains the state of a screen object. '''
197*061da546Spatrick
198*061da546Spatrick    def __init__ (self, r=24,c=80,*args,**kwargs):
199*061da546Spatrick
200*061da546Spatrick        term.__init__(self,r,c,*args,**kwargs)
201*061da546Spatrick
202*061da546Spatrick        #self.screen = screen (24,80)
203*061da546Spatrick        self.state = FSM.FSM ('INIT',[self])
204*061da546Spatrick        self.state.set_default_transition (DoLog, 'INIT')
205*061da546Spatrick        self.state.add_transition_any ('INIT', DoEmit, 'INIT')
206*061da546Spatrick        self.state.add_transition ('\x1b', 'INIT', None, 'ESC')
207*061da546Spatrick        self.state.add_transition_any ('ESC', DoLog, 'INIT')
208*061da546Spatrick        self.state.add_transition ('(', 'ESC', None, 'G0SCS')
209*061da546Spatrick        self.state.add_transition (')', 'ESC', None, 'G1SCS')
210*061da546Spatrick        self.state.add_transition_list ('AB012', 'G0SCS', None, 'INIT')
211*061da546Spatrick        self.state.add_transition_list ('AB012', 'G1SCS', None, 'INIT')
212*061da546Spatrick        self.state.add_transition ('7', 'ESC', DoCursorSave, 'INIT')
213*061da546Spatrick        self.state.add_transition ('8', 'ESC', DoCursorRestore, 'INIT')
214*061da546Spatrick        self.state.add_transition ('M', 'ESC', DoUpReverse, 'INIT')
215*061da546Spatrick        self.state.add_transition ('>', 'ESC', DoUpReverse, 'INIT')
216*061da546Spatrick        self.state.add_transition ('<', 'ESC', DoUpReverse, 'INIT')
217*061da546Spatrick        self.state.add_transition ('=', 'ESC', None, 'INIT') # Selects application keypad.
218*061da546Spatrick        self.state.add_transition ('#', 'ESC', None, 'GRAPHICS_POUND')
219*061da546Spatrick        self.state.add_transition_any ('GRAPHICS_POUND', None, 'INIT')
220*061da546Spatrick        self.state.add_transition ('[', 'ESC', None, 'ELB')
221*061da546Spatrick        # ELB means Escape Left Bracket. That is ^[[
222*061da546Spatrick        self.state.add_transition ('H', 'ELB', DoHomeOrigin, 'INIT')
223*061da546Spatrick        self.state.add_transition ('D', 'ELB', DoBackOne, 'INIT')
224*061da546Spatrick        self.state.add_transition ('B', 'ELB', DoDownOne, 'INIT')
225*061da546Spatrick        self.state.add_transition ('C', 'ELB', DoForwardOne, 'INIT')
226*061da546Spatrick        self.state.add_transition ('A', 'ELB', DoUpOne, 'INIT')
227*061da546Spatrick        self.state.add_transition ('J', 'ELB', DoEraseDown, 'INIT')
228*061da546Spatrick        self.state.add_transition ('K', 'ELB', DoEraseEndOfLine, 'INIT')
229*061da546Spatrick        self.state.add_transition ('r', 'ELB', DoEnableScroll, 'INIT')
230*061da546Spatrick        self.state.add_transition ('m', 'ELB', self.do_sgr, 'INIT')
231*061da546Spatrick        self.state.add_transition ('?', 'ELB', None, 'MODECRAP')
232*061da546Spatrick        self.state.add_transition_list (string.digits, 'ELB', DoStartNumber, 'NUMBER_1')
233*061da546Spatrick        self.state.add_transition_list (string.digits, 'NUMBER_1', DoBuildNumber, 'NUMBER_1')
234*061da546Spatrick        self.state.add_transition ('D', 'NUMBER_1', DoBack, 'INIT')
235*061da546Spatrick        self.state.add_transition ('B', 'NUMBER_1', DoDown, 'INIT')
236*061da546Spatrick        self.state.add_transition ('C', 'NUMBER_1', DoForward, 'INIT')
237*061da546Spatrick        self.state.add_transition ('A', 'NUMBER_1', DoUp, 'INIT')
238*061da546Spatrick        self.state.add_transition ('J', 'NUMBER_1', DoErase, 'INIT')
239*061da546Spatrick        self.state.add_transition ('K', 'NUMBER_1', DoEraseLine, 'INIT')
240*061da546Spatrick        self.state.add_transition ('l', 'NUMBER_1', DoMode, 'INIT')
241*061da546Spatrick        ### It gets worse... the 'm' code can have infinite number of
242*061da546Spatrick        ### number;number;number before it. I've never seen more than two,
243*061da546Spatrick        ### but the specs say it's allowed. crap!
244*061da546Spatrick        self.state.add_transition ('m', 'NUMBER_1', self.do_sgr, 'INIT')
245*061da546Spatrick        ### LED control. Same implementation problem as 'm' code.
246*061da546Spatrick        self.state.add_transition ('q', 'NUMBER_1', self.do_decsca, 'INIT')
247*061da546Spatrick
248*061da546Spatrick        # \E[?47h switch to alternate screen
249*061da546Spatrick        # \E[?47l restores to normal screen from alternate screen.
250*061da546Spatrick        self.state.add_transition_list (string.digits, 'MODECRAP', DoStartNumber, 'MODECRAP_NUM')
251*061da546Spatrick        self.state.add_transition_list (string.digits, 'MODECRAP_NUM', DoBuildNumber, 'MODECRAP_NUM')
252*061da546Spatrick        self.state.add_transition ('l', 'MODECRAP_NUM', self.do_modecrap, 'INIT')
253*061da546Spatrick        self.state.add_transition ('h', 'MODECRAP_NUM', self.do_modecrap, 'INIT')
254*061da546Spatrick
255*061da546Spatrick#RM   Reset Mode                Esc [ Ps l                   none
256*061da546Spatrick        self.state.add_transition (';', 'NUMBER_1', None, 'SEMICOLON')
257*061da546Spatrick        self.state.add_transition_any ('SEMICOLON', DoLog, 'INIT')
258*061da546Spatrick        self.state.add_transition_list (string.digits, 'SEMICOLON', DoStartNumber, 'NUMBER_2')
259*061da546Spatrick        self.state.add_transition_list (string.digits, 'NUMBER_2', DoBuildNumber, 'NUMBER_2')
260*061da546Spatrick        self.state.add_transition_any ('NUMBER_2', DoLog, 'INIT')
261*061da546Spatrick        self.state.add_transition ('H', 'NUMBER_2', DoHome, 'INIT')
262*061da546Spatrick        self.state.add_transition ('f', 'NUMBER_2', DoHome, 'INIT')
263*061da546Spatrick        self.state.add_transition ('r', 'NUMBER_2', DoScrollRegion, 'INIT')
264*061da546Spatrick        ### It gets worse... the 'm' code can have infinite number of
265*061da546Spatrick        ### number;number;number before it. I've never seen more than two,
266*061da546Spatrick        ### but the specs say it's allowed. crap!
267*061da546Spatrick        self.state.add_transition ('m', 'NUMBER_2', self.do_sgr, 'INIT')
268*061da546Spatrick        ### LED control. Same problem as 'm' code.
269*061da546Spatrick        self.state.add_transition ('q', 'NUMBER_2', self.do_decsca, 'INIT')
270*061da546Spatrick        self.state.add_transition (';', 'NUMBER_2', None, 'SEMICOLON_X')
271*061da546Spatrick
272*061da546Spatrick        # Create a state for 'q' and 'm' which allows an infinite number of ignored numbers
273*061da546Spatrick        self.state.add_transition_any ('SEMICOLON_X', DoLog, 'INIT')
274*061da546Spatrick        self.state.add_transition_list (string.digits, 'SEMICOLON_X', DoStartNumber, 'NUMBER_X')
275*061da546Spatrick        self.state.add_transition_list (string.digits, 'NUMBER_X', DoBuildNumber, 'NUMBER_X')
276*061da546Spatrick        self.state.add_transition_any ('NUMBER_X', DoLog, 'INIT')
277*061da546Spatrick        self.state.add_transition ('m', 'NUMBER_X', self.do_sgr, 'INIT')
278*061da546Spatrick        self.state.add_transition ('q', 'NUMBER_X', self.do_decsca, 'INIT')
279*061da546Spatrick        self.state.add_transition (';', 'NUMBER_X', None, 'SEMICOLON_X')
280*061da546Spatrick
281*061da546Spatrick    def process (self, c):
282*061da546Spatrick        """Process a single character. Called by :meth:`write`."""
283*061da546Spatrick        if isinstance(c, bytes):
284*061da546Spatrick            c = self._decode(c)
285*061da546Spatrick        self.state.process(c)
286*061da546Spatrick
287*061da546Spatrick    def process_list (self, l):
288*061da546Spatrick
289*061da546Spatrick        self.write(l)
290*061da546Spatrick
291*061da546Spatrick    def write (self, s):
292*061da546Spatrick        """Process text, writing it to the virtual screen while handling
293*061da546Spatrick        ANSI escape codes.
294*061da546Spatrick        """
295*061da546Spatrick        if isinstance(s, bytes):
296*061da546Spatrick            s = self._decode(s)
297*061da546Spatrick        for c in s:
298*061da546Spatrick            self.process(c)
299*061da546Spatrick
300*061da546Spatrick    def flush (self):
301*061da546Spatrick        pass
302*061da546Spatrick
303*061da546Spatrick    def write_ch (self, ch):
304*061da546Spatrick        '''This puts a character at the current cursor position. The cursor
305*061da546Spatrick        position is moved forward with wrap-around, but no scrolling is done if
306*061da546Spatrick        the cursor hits the lower-right corner of the screen. '''
307*061da546Spatrick
308*061da546Spatrick        if isinstance(ch, bytes):
309*061da546Spatrick            ch = self._decode(ch)
310*061da546Spatrick
311*061da546Spatrick        #\r and \n both produce a call to cr() and lf(), respectively.
312*061da546Spatrick        ch = ch[0]
313*061da546Spatrick
314*061da546Spatrick        if ch == u'\r':
315*061da546Spatrick            self.cr()
316*061da546Spatrick            return
317*061da546Spatrick        if ch == u'\n':
318*061da546Spatrick            self.crlf()
319*061da546Spatrick            return
320*061da546Spatrick        if ch == chr(screen.BS):
321*061da546Spatrick            self.cursor_back()
322*061da546Spatrick            return
323*061da546Spatrick        self.put_abs(self.cur_r, self.cur_c, ch)
324*061da546Spatrick        old_r = self.cur_r
325*061da546Spatrick        old_c = self.cur_c
326*061da546Spatrick        self.cursor_forward()
327*061da546Spatrick        if old_c == self.cur_c:
328*061da546Spatrick            self.cursor_down()
329*061da546Spatrick            if old_r != self.cur_r:
330*061da546Spatrick                self.cursor_home (self.cur_r, 1)
331*061da546Spatrick            else:
332*061da546Spatrick                self.scroll_up ()
333*061da546Spatrick                self.cursor_home (self.cur_r, 1)
334*061da546Spatrick                self.erase_line()
335*061da546Spatrick
336*061da546Spatrick    def do_sgr (self, fsm):
337*061da546Spatrick        '''Select Graphic Rendition, e.g. color. '''
338*061da546Spatrick        screen = fsm.memory[0]
339*061da546Spatrick        fsm.memory = [screen]
340*061da546Spatrick
341*061da546Spatrick    def do_decsca (self, fsm):
342*061da546Spatrick        '''Select character protection attribute. '''
343*061da546Spatrick        screen = fsm.memory[0]
344*061da546Spatrick        fsm.memory = [screen]
345*061da546Spatrick
346*061da546Spatrick    def do_modecrap (self, fsm):
347*061da546Spatrick        '''Handler for \x1b[?<number>h and \x1b[?<number>l. If anyone
348*061da546Spatrick        wanted to actually use these, they'd need to add more states to the
349*061da546Spatrick        FSM rather than just improve or override this method. '''
350*061da546Spatrick        screen = fsm.memory[0]
351*061da546Spatrick        fsm.memory = [screen]
352