- add sources.
[platform/framework/web/crosswalk.git] / src / third_party / pexpect / screen.py
1 """This implements a virtual screen. This is used to support ANSI terminal
2 emulation. The screen representation and state is implemented in this class.
3 Most of the methods are inspired by ANSI screen control codes. The ANSI class
4 extends this class to add parsing of ANSI escape codes.
5
6 PEXPECT LICENSE
7
8     This license is approved by the OSI and FSF as GPL-compatible.
9         http://opensource.org/licenses/isc-license.txt
10
11     Copyright (c) 2012, Noah Spurrier <noah@noah.org>
12     PERMISSION TO USE, COPY, MODIFY, AND/OR DISTRIBUTE THIS SOFTWARE FOR ANY
13     PURPOSE WITH OR WITHOUT FEE IS HEREBY GRANTED, PROVIDED THAT THE ABOVE
14     COPYRIGHT NOTICE AND THIS PERMISSION NOTICE APPEAR IN ALL COPIES.
15     THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
16     WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
17     MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
18     ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
19     WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
20     ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
21     OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
22
23 """
24
25 import copy
26
27 NUL = 0    # Fill character; ignored on input.
28 ENQ = 5    # Transmit answerback message.
29 BEL = 7    # Ring the bell.
30 BS  = 8    # Move cursor left.
31 HT  = 9    # Move cursor to next tab stop.
32 LF = 10    # Line feed.
33 VT = 11    # Same as LF.
34 FF = 12    # Same as LF.
35 CR = 13    # Move cursor to left margin or newline.
36 SO = 14    # Invoke G1 character set.
37 SI = 15    # Invoke G0 character set.
38 XON = 17   # Resume transmission.
39 XOFF = 19  # Halt transmission.
40 CAN = 24   # Cancel escape sequence.
41 SUB = 26   # Same as CAN.
42 ESC = 27   # Introduce a control sequence.
43 DEL = 127  # Fill character; ignored on input.
44 SPACE = chr(32) # Space or blank character.
45
46 def constrain (n, min, max):
47
48     """This returns a number, n constrained to the min and max bounds. """
49
50     if n < min:
51         return min
52     if n > max:
53         return max
54     return n
55
56 class screen:
57
58     """This object maintains the state of a virtual text screen as a
59     rectangluar array. This maintains a virtual cursor position and handles
60     scrolling as characters are added. This supports most of the methods needed
61     by an ANSI text screen. Row and column indexes are 1-based (not zero-based,
62     like arrays). """
63
64     def __init__ (self, r=24,c=80):
65
66         """This initializes a blank scree of the given dimentions."""
67
68         self.rows = r
69         self.cols = c
70         self.cur_r = 1
71         self.cur_c = 1
72         self.cur_saved_r = 1
73         self.cur_saved_c = 1
74         self.scroll_row_start = 1
75         self.scroll_row_end = self.rows
76         self.w = [ [SPACE] * self.cols for c in range(self.rows)]
77
78     def __str__ (self):
79
80         """This returns a printable representation of the screen. The end of
81         each screen line is terminated by a newline. """
82
83         return '\n'.join ([ ''.join(c) for c in self.w ])
84
85     def dump (self):
86
87         """This returns a copy of the screen as a string. This is similar to
88         __str__ except that lines are not terminated with line feeds. """
89
90         return ''.join ([ ''.join(c) for c in self.w ])
91
92     def pretty (self):
93
94         """This returns a copy of the screen as a string with an ASCII text box
95         around the screen border. This is similar to __str__ except that it
96         adds a box. """
97
98         top_bot = '+' + '-'*self.cols + '+\n'
99         return top_bot + '\n'.join(['|'+line+'|' for line in str(self).split('\n')]) + '\n' + top_bot
100
101     def fill (self, ch=SPACE):
102
103         self.fill_region (1,1,self.rows,self.cols, ch)
104
105     def fill_region (self, rs,cs, re,ce, ch=SPACE):
106
107         rs = constrain (rs, 1, self.rows)
108         re = constrain (re, 1, self.rows)
109         cs = constrain (cs, 1, self.cols)
110         ce = constrain (ce, 1, self.cols)
111         if rs > re:
112             rs, re = re, rs
113         if cs > ce:
114             cs, ce = ce, cs
115         for r in range (rs, re+1):
116             for c in range (cs, ce + 1):
117                 self.put_abs (r,c,ch)
118
119     def cr (self):
120
121         """This moves the cursor to the beginning (col 1) of the current row.
122         """
123
124         self.cursor_home (self.cur_r, 1)
125
126     def lf (self):
127
128         """This moves the cursor down with scrolling.
129         """
130
131         old_r = self.cur_r
132         self.cursor_down()
133         if old_r == self.cur_r:
134             self.scroll_up ()
135             self.erase_line()
136
137     def crlf (self):
138
139         """This advances the cursor with CRLF properties.
140         The cursor will line wrap and the screen may scroll.
141         """
142
143         self.cr ()
144         self.lf ()
145
146     def newline (self):
147
148         """This is an alias for crlf().
149         """
150
151         self.crlf()
152
153     def put_abs (self, r, c, ch):
154
155         """Screen array starts at 1 index."""
156
157         r = constrain (r, 1, self.rows)
158         c = constrain (c, 1, self.cols)
159         ch = str(ch)[0]
160         self.w[r-1][c-1] = ch
161
162     def put (self, ch):
163
164         """This puts a characters at the current cursor position.
165         """
166
167         self.put_abs (self.cur_r, self.cur_c, ch)
168
169     def insert_abs (self, r, c, ch):
170
171         """This inserts a character at (r,c). Everything under
172         and to the right is shifted right one character.
173         The last character of the line is lost.
174         """
175
176         r = constrain (r, 1, self.rows)
177         c = constrain (c, 1, self.cols)
178         for ci in range (self.cols, c, -1):
179             self.put_abs (r,ci, self.get_abs(r,ci-1))
180         self.put_abs (r,c,ch)
181
182     def insert (self, ch):
183
184         self.insert_abs (self.cur_r, self.cur_c, ch)
185
186     def get_abs (self, r, c):
187
188         r = constrain (r, 1, self.rows)
189         c = constrain (c, 1, self.cols)
190         return self.w[r-1][c-1]
191
192     def get (self):
193
194         self.get_abs (self.cur_r, self.cur_c)
195
196     def get_region (self, rs,cs, re,ce):
197
198         """This returns a list of lines representing the region.
199         """
200
201         rs = constrain (rs, 1, self.rows)
202         re = constrain (re, 1, self.rows)
203         cs = constrain (cs, 1, self.cols)
204         ce = constrain (ce, 1, self.cols)
205         if rs > re:
206             rs, re = re, rs
207         if cs > ce:
208             cs, ce = ce, cs
209         sc = []
210         for r in range (rs, re+1):
211             line = ''
212             for c in range (cs, ce + 1):
213                 ch = self.get_abs (r,c)
214                 line = line + ch
215             sc.append (line)
216         return sc
217
218     def cursor_constrain (self):
219
220         """This keeps the cursor within the screen area.
221         """
222
223         self.cur_r = constrain (self.cur_r, 1, self.rows)
224         self.cur_c = constrain (self.cur_c, 1, self.cols)
225
226     def cursor_home (self, r=1, c=1): # <ESC>[{ROW};{COLUMN}H
227
228         self.cur_r = r
229         self.cur_c = c
230         self.cursor_constrain ()
231
232     def cursor_back (self,count=1): # <ESC>[{COUNT}D (not confused with down)
233
234         self.cur_c = self.cur_c - count
235         self.cursor_constrain ()
236
237     def cursor_down (self,count=1): # <ESC>[{COUNT}B (not confused with back)
238
239         self.cur_r = self.cur_r + count
240         self.cursor_constrain ()
241
242     def cursor_forward (self,count=1): # <ESC>[{COUNT}C
243
244         self.cur_c = self.cur_c + count
245         self.cursor_constrain ()
246
247     def cursor_up (self,count=1): # <ESC>[{COUNT}A
248
249         self.cur_r = self.cur_r - count
250         self.cursor_constrain ()
251
252     def cursor_up_reverse (self): # <ESC> M   (called RI -- Reverse Index)
253
254         old_r = self.cur_r
255         self.cursor_up()
256         if old_r == self.cur_r:
257             self.scroll_up()
258
259     def cursor_force_position (self, r, c): # <ESC>[{ROW};{COLUMN}f
260
261         """Identical to Cursor Home."""
262
263         self.cursor_home (r, c)
264
265     def cursor_save (self): # <ESC>[s
266
267         """Save current cursor position."""
268
269         self.cursor_save_attrs()
270
271     def cursor_unsave (self): # <ESC>[u
272
273         """Restores cursor position after a Save Cursor."""
274
275         self.cursor_restore_attrs()
276
277     def cursor_save_attrs (self): # <ESC>7
278
279         """Save current cursor position."""
280
281         self.cur_saved_r = self.cur_r
282         self.cur_saved_c = self.cur_c
283
284     def cursor_restore_attrs (self): # <ESC>8
285
286         """Restores cursor position after a Save Cursor."""
287
288         self.cursor_home (self.cur_saved_r, self.cur_saved_c)
289
290     def scroll_constrain (self):
291
292         """This keeps the scroll region within the screen region."""
293
294         if self.scroll_row_start <= 0:
295             self.scroll_row_start = 1
296         if self.scroll_row_end > self.rows:
297             self.scroll_row_end = self.rows
298
299     def scroll_screen (self): # <ESC>[r
300
301         """Enable scrolling for entire display."""
302
303         self.scroll_row_start = 1
304         self.scroll_row_end = self.rows
305
306     def scroll_screen_rows (self, rs, re): # <ESC>[{start};{end}r
307
308         """Enable scrolling from row {start} to row {end}."""
309
310         self.scroll_row_start = rs
311         self.scroll_row_end = re
312         self.scroll_constrain()
313
314     def scroll_down (self): # <ESC>D
315
316         """Scroll display down one line."""
317
318         # Screen is indexed from 1, but arrays are indexed from 0.
319         s = self.scroll_row_start - 1
320         e = self.scroll_row_end - 1
321         self.w[s+1:e+1] = copy.deepcopy(self.w[s:e])
322
323     def scroll_up (self): # <ESC>M
324
325         """Scroll display up one line."""
326
327         # Screen is indexed from 1, but arrays are indexed from 0.
328         s = self.scroll_row_start - 1
329         e = self.scroll_row_end - 1
330         self.w[s:e] = copy.deepcopy(self.w[s+1:e+1])
331
332     def erase_end_of_line (self): # <ESC>[0K -or- <ESC>[K
333
334         """Erases from the current cursor position to the end of the current
335         line."""
336
337         self.fill_region (self.cur_r, self.cur_c, self.cur_r, self.cols)
338
339     def erase_start_of_line (self): # <ESC>[1K
340
341         """Erases from the current cursor position to the start of the current
342         line."""
343
344         self.fill_region (self.cur_r, 1, self.cur_r, self.cur_c)
345
346     def erase_line (self): # <ESC>[2K
347
348         """Erases the entire current line."""
349
350         self.fill_region (self.cur_r, 1, self.cur_r, self.cols)
351
352     def erase_down (self): # <ESC>[0J -or- <ESC>[J
353
354         """Erases the screen from the current line down to the bottom of the
355         screen."""
356
357         self.erase_end_of_line ()
358         self.fill_region (self.cur_r + 1, 1, self.rows, self.cols)
359
360     def erase_up (self): # <ESC>[1J
361
362         """Erases the screen from the current line up to the top of the
363         screen."""
364
365         self.erase_start_of_line ()
366         self.fill_region (self.cur_r-1, 1, 1, self.cols)
367
368     def erase_screen (self): # <ESC>[2J
369
370         """Erases the screen with the background color."""
371
372         self.fill ()
373
374     def set_tab (self): # <ESC>H
375
376         """Sets a tab at the current position."""
377
378         pass
379
380     def clear_tab (self): # <ESC>[g
381
382         """Clears tab at the current position."""
383
384         pass
385
386     def clear_all_tabs (self): # <ESC>[3g
387
388         """Clears all tabs."""
389
390         pass
391
392 #        Insert line             Esc [ Pn L
393 #        Delete line             Esc [ Pn M
394 #        Delete character        Esc [ Pn P
395 #        Scrolling region        Esc [ Pn(top);Pn(bot) r
396