Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(616)

Side by Side Diff: third_party/twisted_8_1/twisted/conch/insults/insults.py

Issue 12261012: Remove third_party/twisted_8_1 (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/tools/build
Patch Set: Created 7 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
(Empty)
1 # -*- test-case-name: twisted.conch.test.test_insults -*-
2 # Copyright (c) 2001-2004 Twisted Matrix Laboratories.
3 # See LICENSE for details.
4
5 """
6 VT102 and VT220 terminal manipulation.
7
8 @author: U{Jp Calderone<mailto:exarkun@twistedmatrix.com>}
9 """
10
11 from zope.interface import implements, Interface
12
13 from twisted.internet import protocol, defer, interfaces as iinternet
14
15 class ITerminalProtocol(Interface):
16 def makeConnection(transport):
17 """Called with an L{ITerminalTransport} when a connection is established .
18 """
19
20 def keystrokeReceived(keyID, modifier):
21 """A keystroke was received.
22
23 Each keystroke corresponds to one invocation of this method.
24 keyID is a string identifier for that key. Printable characters
25 are represented by themselves. Control keys, such as arrows and
26 function keys, are represented with symbolic constants on
27 L{ServerProtocol}.
28 """
29
30 def terminalSize(width, height):
31 """Called to indicate the size of the terminal.
32
33 A terminal of 80x24 should be assumed if this method is not
34 called. This method might not be called for real terminals.
35 """
36
37 def unhandledControlSequence(seq):
38 """Called when an unsupported control sequence is received.
39
40 @type seq: C{str}
41 @param seq: The whole control sequence which could not be interpreted.
42 """
43
44 def connectionLost(reason):
45 """Called when the connection has been lost.
46
47 reason is a Failure describing why.
48 """
49
50 class TerminalProtocol(object):
51 implements(ITerminalProtocol)
52
53 def makeConnection(self, terminal):
54 # assert ITerminalTransport.providedBy(transport), "TerminalProtocol.mak eConnection must be passed an ITerminalTransport implementor"
55 self.terminal = terminal
56 self.connectionMade()
57
58 def connectionMade(self):
59 """Called after a connection has been established.
60 """
61
62 def keystrokeReceived(self, keyID, modifier):
63 pass
64
65 def terminalSize(self, width, height):
66 pass
67
68 def unhandledControlSequence(self, seq):
69 pass
70
71 def connectionLost(self, reason):
72 pass
73
74 class ITerminalTransport(iinternet.ITransport):
75 def cursorUp(n=1):
76 """Move the cursor up n lines.
77 """
78
79 def cursorDown(n=1):
80 """Move the cursor down n lines.
81 """
82
83 def cursorForward(n=1):
84 """Move the cursor right n columns.
85 """
86
87 def cursorBackward(n=1):
88 """Move the cursor left n columns.
89 """
90
91 def cursorPosition(column, line):
92 """Move the cursor to the given line and column.
93 """
94
95 def cursorHome():
96 """Move the cursor home.
97 """
98
99 def index():
100 """Move the cursor down one line, performing scrolling if necessary.
101 """
102
103 def reverseIndex():
104 """Move the cursor up one line, performing scrolling if necessary.
105 """
106
107 def nextLine():
108 """Move the cursor to the first position on the next line, performing sc rolling if necessary.
109 """
110
111 def saveCursor():
112 """Save the cursor position, character attribute, character set, and ori gin mode selection.
113 """
114
115 def restoreCursor():
116 """Restore the previously saved cursor position, character attribute, ch aracter set, and origin mode selection.
117
118 If no cursor state was previously saved, move the cursor to the home pos ition.
119 """
120
121 def setModes(modes):
122 """Set the given modes on the terminal.
123 """
124
125 def resetModes(mode):
126 """Reset the given modes on the terminal.
127 """
128
129
130 def setPrivateModes(modes):
131 """
132 Set the given DEC private modes on the terminal.
133 """
134
135
136 def resetPrivateModes(modes):
137 """
138 Reset the given DEC private modes on the terminal.
139 """
140
141
142 def applicationKeypadMode():
143 """Cause keypad to generate control functions.
144
145 Cursor key mode selects the type of characters generated by cursor keys.
146 """
147
148 def numericKeypadMode():
149 """Cause keypad to generate normal characters.
150 """
151
152 def selectCharacterSet(charSet, which):
153 """Select a character set.
154
155 charSet should be one of CS_US, CS_UK, CS_DRAWING, CS_ALTERNATE, or
156 CS_ALTERNATE_SPECIAL.
157
158 which should be one of G0 or G1.
159 """
160
161 def shiftIn():
162 """Activate the G0 character set.
163 """
164
165 def shiftOut():
166 """Activate the G1 character set.
167 """
168
169 def singleShift2():
170 """Shift to the G2 character set for a single character.
171 """
172
173 def singleShift3():
174 """Shift to the G3 character set for a single character.
175 """
176
177 def selectGraphicRendition(*attributes):
178 """Enabled one or more character attributes.
179
180 Arguments should be one or more of UNDERLINE, REVERSE_VIDEO, BLINK, or B OLD.
181 NORMAL may also be specified to disable all character attributes.
182 """
183
184 def horizontalTabulationSet():
185 """Set a tab stop at the current cursor position.
186 """
187
188 def tabulationClear():
189 """Clear the tab stop at the current cursor position.
190 """
191
192 def tabulationClearAll():
193 """Clear all tab stops.
194 """
195
196 def doubleHeightLine(top=True):
197 """Make the current line the top or bottom half of a double-height, doub le-width line.
198
199 If top is True, the current line is the top half. Otherwise, it is the bottom half.
200 """
201
202 def singleWidthLine():
203 """Make the current line a single-width, single-height line.
204 """
205
206 def doubleWidthLine():
207 """Make the current line a double-width line.
208 """
209
210 def eraseToLineEnd():
211 """Erase from the cursor to the end of line, including cursor position.
212 """
213
214 def eraseToLineBeginning():
215 """Erase from the cursor to the beginning of the line, including the cur sor position.
216 """
217
218 def eraseLine():
219 """Erase the entire cursor line.
220 """
221
222 def eraseToDisplayEnd():
223 """Erase from the cursor to the end of the display, including the cursor position.
224 """
225
226 def eraseToDisplayBeginning():
227 """Erase from the cursor to the beginning of the display, including the cursor position.
228 """
229
230 def eraseDisplay():
231 """Erase the entire display.
232 """
233
234 def deleteCharacter(n=1):
235 """Delete n characters starting at the cursor position.
236
237 Characters to the right of deleted characters are shifted to the left.
238 """
239
240 def insertLine(n=1):
241 """Insert n lines at the cursor position.
242
243 Lines below the cursor are shifted down. Lines moved past the bottom ma rgin are lost.
244 This command is ignored when the cursor is outside the scroll region.
245 """
246
247 def deleteLine(n=1):
248 """Delete n lines starting at the cursor position.
249
250 Lines below the cursor are shifted up. This command is ignored when the cursor is outside
251 the scroll region.
252 """
253
254 def reportCursorPosition():
255 """Return a Deferred that fires with a two-tuple of (x, y) indicating th e cursor position.
256 """
257
258 def reset():
259 """Reset the terminal to its initial state.
260 """
261
262 def unhandledControlSequence(seq):
263 """Called when an unsupported control sequence is received.
264
265 @type seq: C{str}
266 @param seq: The whole control sequence which could not be interpreted.
267 """
268
269
270 CSI = '\x1b'
271 CST = {'~': 'tilde'}
272
273 class modes:
274 """ECMA 48 standardized modes
275 """
276
277 # BREAKS YOPUR KEYBOARD MOFO
278 KEYBOARD_ACTION = KAM = 2
279
280 # When set, enables character insertion. New display characters
281 # move old display characters to the right. Characters moved past
282 # the right margin are lost.
283
284 # When reset, enables replacement mode (disables character
285 # insertion). New display characters replace old display
286 # characters at cursor position. The old character is erased.
287 INSERTION_REPLACEMENT = IRM = 4
288
289 # Set causes a received linefeed, form feed, or vertical tab to
290 # move cursor to first column of next line. RETURN transmits both
291 # a carriage return and linefeed. This selection is also called
292 # new line option.
293
294 # Reset causes a received linefeed, form feed, or vertical tab to
295 # move cursor to next line in current column. RETURN transmits a
296 # carriage return.
297 LINEFEED_NEWLINE = LNM = 20
298
299
300 class privateModes:
301 """ANSI-Compatible Private Modes
302 """
303 ERROR = 0
304 CURSOR_KEY = 1
305 ANSI_VT52 = 2
306 COLUMN = 3
307 SCROLL = 4
308 SCREEN = 5
309 ORIGIN = 6
310 AUTO_WRAP = 7
311 AUTO_REPEAT = 8
312 PRINTER_FORM_FEED = 18
313 PRINTER_EXTENT = 19
314
315 # Toggle cursor visibility (reset hides it)
316 CURSOR_MODE = 25
317
318
319 # Character sets
320 CS_US = 'CS_US'
321 CS_UK = 'CS_UK'
322 CS_DRAWING = 'CS_DRAWING'
323 CS_ALTERNATE = 'CS_ALTERNATE'
324 CS_ALTERNATE_SPECIAL = 'CS_ALTERNATE_SPECIAL'
325
326 # Groupings (or something?? These are like variables that can be bound to charac ter sets)
327 G0 = 'G0'
328 G1 = 'G1'
329
330 # G2 and G3 cannot be changed, but they can be shifted to.
331 G2 = 'G2'
332 G3 = 'G3'
333
334 # Character attributes
335
336 NORMAL = 0
337 BOLD = 1
338 UNDERLINE = 4
339 BLINK = 5
340 REVERSE_VIDEO = 7
341
342 class Vector:
343 def __init__(self, x, y):
344 self.x = x
345 self.y = y
346
347 def log(s):
348 file('log', 'a').write(str(s) + '\n')
349
350 # XXX TODO - These attributes are really part of the
351 # ITerminalTransport interface, I think.
352 _KEY_NAMES = ('UP_ARROW', 'DOWN_ARROW', 'RIGHT_ARROW', 'LEFT_ARROW',
353 'HOME', 'INSERT', 'DELETE', 'END', 'PGUP', 'PGDN', 'NUMPAD_MIDDLE' ,
354 'F1', 'F2', 'F3', 'F4', 'F5', 'F6', 'F7', 'F8', 'F9',
355 'F10', 'F11', 'F12',
356
357 'ALT', 'SHIFT', 'CONTROL')
358
359 class _const(object):
360 """
361 @ivar name: A string naming this constant
362 """
363 def __init__(self, name):
364 self.name = name
365
366 def __repr__(self):
367 return '[' + self.name + ']'
368
369
370 FUNCTION_KEYS = [
371 _const(_name) for _name in _KEY_NAMES]
372
373 class ServerProtocol(protocol.Protocol):
374 implements(ITerminalTransport)
375
376 protocolFactory = None
377 terminalProtocol = None
378
379 TAB = '\t'
380 BACKSPACE = '\x7f'
381 ##
382
383 lastWrite = ''
384
385 state = 'data'
386
387 termSize = Vector(80, 24)
388 cursorPos = Vector(0, 0)
389 scrollRegion = None
390
391 # Factory who instantiated me
392 factory = None
393
394 def __init__(self, protocolFactory=None, *a, **kw):
395 """
396 @param protocolFactory: A callable which will be invoked with
397 *a, **kw and should return an ITerminalProtocol implementor.
398 This will be invoked when a connection to this ServerProtocol
399 is established.
400
401 @param a: Any positional arguments to pass to protocolFactory.
402 @param kw: Any keyword arguments to pass to protocolFactory.
403 """
404 # assert protocolFactory is None or ITerminalProtocol.implementedBy(prot ocolFactory), "ServerProtocol.__init__ must be passed an ITerminalProtocol imple mentor"
405 if protocolFactory is not None:
406 self.protocolFactory = protocolFactory
407 self.protocolArgs = a
408 self.protocolKwArgs = kw
409
410 self._cursorReports = []
411
412 def connectionMade(self):
413 if self.protocolFactory is not None:
414 self.terminalProtocol = self.protocolFactory(*self.protocolArgs, **s elf.protocolKwArgs)
415
416 try:
417 factory = self.factory
418 except AttributeError:
419 pass
420 else:
421 self.terminalProtocol.factory = factory
422
423 self.terminalProtocol.makeConnection(self)
424
425 def dataReceived(self, data):
426 for ch in data:
427 if self.state == 'data':
428 if ch == '\x1b':
429 self.state = 'escaped'
430 else:
431 self.terminalProtocol.keystrokeReceived(ch, None)
432 elif self.state == 'escaped':
433 if ch == '[':
434 self.state = 'bracket-escaped'
435 self.escBuf = []
436 elif ch == 'O':
437 self.state = 'low-function-escaped'
438 else:
439 self.state = 'data'
440 self._handleShortControlSequence(ch)
441 elif self.state == 'bracket-escaped':
442 if ch == 'O':
443 self.state = 'low-function-escaped'
444 elif ch.isalpha() or ch == '~':
445 self._handleControlSequence(''.join(self.escBuf) + ch)
446 del self.escBuf
447 self.state = 'data'
448 else:
449 self.escBuf.append(ch)
450 elif self.state == 'low-function-escaped':
451 self._handleLowFunctionControlSequence(ch)
452 self.state = 'data'
453 else:
454 raise ValueError("Illegal state")
455
456 def _handleShortControlSequence(self, ch):
457 self.terminalProtocol.keystrokeReceived(ch, self.ALT)
458
459 def _handleControlSequence(self, buf):
460 buf = '\x1b[' + buf
461 f = getattr(self.controlSequenceParser, CST.get(buf[-1], buf[-1]), None)
462 if f is None:
463 self.unhandledControlSequence(buf)
464 else:
465 f(self, self.terminalProtocol, buf[:-1])
466
467 def unhandledControlSequence(self, buf):
468 self.terminalProtocol.unhandledControlSequence(buf)
469
470 def _handleLowFunctionControlSequence(self, ch):
471 map = {'P': self.F1, 'Q': self.F2, 'R': self.F3, 'S': self.F4}
472 keyID = map.get(ch)
473 if keyID is not None:
474 self.terminalProtocol.keystrokeReceived(keyID, None)
475 else:
476 self.terminalProtocol.unhandledControlSequence('\x1b[O' + ch)
477
478 class ControlSequenceParser:
479 def A(self, proto, handler, buf):
480 if buf == '\x1b[':
481 handler.keystrokeReceived(proto.UP_ARROW, None)
482 else:
483 handler.unhandledControlSequence(buf + 'A')
484
485 def B(self, proto, handler, buf):
486 if buf == '\x1b[':
487 handler.keystrokeReceived(proto.DOWN_ARROW, None)
488 else:
489 handler.unhandledControlSequence(buf + 'B')
490
491 def C(self, proto, handler, buf):
492 if buf == '\x1b[':
493 handler.keystrokeReceived(proto.RIGHT_ARROW, None)
494 else:
495 handler.unhandledControlSequence(buf + 'C')
496
497 def D(self, proto, handler, buf):
498 if buf == '\x1b[':
499 handler.keystrokeReceived(proto.LEFT_ARROW, None)
500 else:
501 handler.unhandledControlSequence(buf + 'D')
502
503 def E(self, proto, handler, buf):
504 if buf == '\x1b[':
505 handler.keystrokeReceived(proto.NUMPAD_MIDDLE, None)
506 else:
507 handler.unhandledControlSequence(buf + 'E')
508
509 def F(self, proto, handler, buf):
510 if buf == '\x1b[':
511 handler.keystrokeReceived(proto.END, None)
512 else:
513 handler.unhandledControlSequence(buf + 'F')
514
515 def H(self, proto, handler, buf):
516 if buf == '\x1b[':
517 handler.keystrokeReceived(proto.HOME, None)
518 else:
519 handler.unhandledControlSequence(buf + 'H')
520
521 def R(self, proto, handler, buf):
522 if not proto._cursorReports:
523 handler.unhandledControlSequence(buf + 'R')
524 elif buf.startswith('\x1b['):
525 report = buf[2:]
526 parts = report.split(';')
527 if len(parts) != 2:
528 handler.unhandledControlSequence(buf + 'R')
529 else:
530 Pl, Pc = parts
531 try:
532 Pl, Pc = int(Pl), int(Pc)
533 except ValueError:
534 handler.unhandledControlSequence(buf + 'R')
535 else:
536 d = proto._cursorReports.pop(0)
537 d.callback((Pc - 1, Pl - 1))
538 else:
539 handler.unhandledControlSequence(buf + 'R')
540
541 def Z(self, proto, handler, buf):
542 if buf == '\x1b[':
543 handler.keystrokeReceived(proto.TAB, proto.SHIFT)
544 else:
545 handler.unhandledControlSequence(buf + 'Z')
546
547 def tilde(self, proto, handler, buf):
548 map = {1: proto.HOME, 2: proto.INSERT, 3: proto.DELETE,
549 4: proto.END, 5: proto.PGUP, 6: proto.PGDN,
550
551 15: proto.F5, 17: proto.F6, 18: proto.F7,
552 19: proto.F8, 20: proto.F9, 21: proto.F10,
553 23: proto.F11, 24: proto.F12}
554
555 if buf.startswith('\x1b['):
556 ch = buf[2:]
557 try:
558 v = int(ch)
559 except ValueError:
560 handler.unhandledControlSequence(buf + '~')
561 else:
562 symbolic = map.get(v)
563 if symbolic is not None:
564 handler.keystrokeReceived(map[v], None)
565 else:
566 handler.unhandledControlSequence(buf + '~')
567 else:
568 handler.unhandledControlSequence(buf + '~')
569
570 controlSequenceParser = ControlSequenceParser()
571
572 # ITerminalTransport
573 def cursorUp(self, n=1):
574 assert n >= 1
575 self.cursorPos.y = max(self.cursorPos.y - n, 0)
576 self.write('\x1b[%dA' % (n,))
577
578 def cursorDown(self, n=1):
579 assert n >= 1
580 self.cursorPos.y = min(self.cursorPos.y + n, self.termSize.y - 1)
581 self.write('\x1b[%dB' % (n,))
582
583 def cursorForward(self, n=1):
584 assert n >= 1
585 self.cursorPos.x = min(self.cursorPos.x + n, self.termSize.x - 1)
586 self.write('\x1b[%dC' % (n,))
587
588 def cursorBackward(self, n=1):
589 assert n >= 1
590 self.cursorPos.x = max(self.cursorPos.x - n, 0)
591 self.write('\x1b[%dD' % (n,))
592
593 def cursorPosition(self, column, line):
594 self.write('\x1b[%d;%dH' % (line + 1, column + 1))
595
596 def cursorHome(self):
597 self.cursorPos.x = self.cursorPos.y = 0
598 self.write('\x1b[H')
599
600 def index(self):
601 self.cursorPos.y = min(self.cursorPos.y + 1, self.termSize.y - 1)
602 self.write('\x1bD')
603
604 def reverseIndex(self):
605 self.cursorPos.y = max(self.cursorPos.y - 1, 0)
606 self.write('\x1bM')
607
608 def nextLine(self):
609 self.cursorPos.x = 0
610 self.cursorPos.y = min(self.cursorPos.y + 1, self.termSize.y - 1)
611 self.write('\n')
612
613 def saveCursor(self):
614 self._savedCursorPos = Vector(self.cursorPos.x, self.cursorPos.y)
615 self.write('\x1b7')
616
617 def restoreCursor(self):
618 self.cursorPos = self._savedCursorPos
619 del self._savedCursorPos
620 self.write('\x1b8')
621
622 def setModes(self, modes):
623 # XXX Support ANSI-Compatible private modes
624 self.write('\x1b[%sh' % (';'.join(map(str, modes)),))
625
626 def setPrivateModes(self, modes):
627 self.write('\x1b[?%sh' % (';'.join(map(str, modes)),))
628
629 def resetModes(self, modes):
630 # XXX Support ANSI-Compatible private modes
631 self.write('\x1b[%sl' % (';'.join(map(str, modes)),))
632
633 def resetPrivateModes(self, modes):
634 self.write('\x1b[?%sl' % (';'.join(map(str, modes)),))
635
636 def applicationKeypadMode(self):
637 self.write('\x1b=')
638
639 def numericKeypadMode(self):
640 self.write('\x1b>')
641
642 def selectCharacterSet(self, charSet, which):
643 # XXX Rewrite these as dict lookups
644 if which == G0:
645 which = '('
646 elif which == G1:
647 which = ')'
648 else:
649 raise ValueError("`which' argument to selectCharacterSet must be G0 or G1")
650 if charSet == CS_UK:
651 charSet = 'A'
652 elif charSet == CS_US:
653 charSet = 'B'
654 elif charSet == CS_DRAWING:
655 charSet = '0'
656 elif charSet == CS_ALTERNATE:
657 charSet = '1'
658 elif charSet == CS_ALTERNATE_SPECIAL:
659 charSet = '2'
660 else:
661 raise ValueError("Invalid `charSet' argument to selectCharacterSet")
662 self.write('\x1b' + which + charSet)
663
664 def shiftIn(self):
665 self.write('\x15')
666
667 def shiftOut(self):
668 self.write('\x14')
669
670 def singleShift2(self):
671 self.write('\x1bN')
672
673 def singleShift3(self):
674 self.write('\x1bO')
675
676 def selectGraphicRendition(self, *attributes):
677 attrs = []
678 for a in attributes:
679 attrs.append(a)
680 self.write('\x1b[%sm' % (';'.join(attrs),))
681
682 def horizontalTabulationSet(self):
683 self.write('\x1bH')
684
685 def tabulationClear(self):
686 self.write('\x1b[q')
687
688 def tabulationClearAll(self):
689 self.write('\x1b[3q')
690
691 def doubleHeightLine(self, top=True):
692 if top:
693 self.write('\x1b#3')
694 else:
695 self.write('\x1b#4')
696
697 def singleWidthLine(self):
698 self.write('\x1b#5')
699
700 def doubleWidthLine(self):
701 self.write('\x1b#6')
702
703 def eraseToLineEnd(self):
704 self.write('\x1b[K')
705
706 def eraseToLineBeginning(self):
707 self.write('\x1b[1K')
708
709 def eraseLine(self):
710 self.write('\x1b[2K')
711
712 def eraseToDisplayEnd(self):
713 self.write('\x1b[J')
714
715 def eraseToDisplayBeginning(self):
716 self.write('\x1b[1J')
717
718 def eraseDisplay(self):
719 self.write('\x1b[2J')
720
721 def deleteCharacter(self, n=1):
722 self.write('\x1b[%dP' % (n,))
723
724 def insertLine(self, n=1):
725 self.write('\x1b[%dL' % (n,))
726
727 def deleteLine(self, n=1):
728 self.write('\x1b[%dM' % (n,))
729
730 def setScrollRegion(self, first=None, last=None):
731 if first is not None:
732 first = '%d' % (first,)
733 else:
734 first = ''
735 if last is not None:
736 last = '%d' % (last,)
737 else:
738 last = ''
739 self.write('\x1b[%s;%sr' % (first, last))
740
741 def resetScrollRegion(self):
742 self.setScrollRegion()
743
744 def reportCursorPosition(self):
745 d = defer.Deferred()
746 self._cursorReports.append(d)
747 self.write('\x1b[6n')
748 return d
749
750 def reset(self):
751 self.cursorPos.x = self.cursorPos.y = 0
752 try:
753 del self._savedCursorPos
754 except AttributeError:
755 pass
756 self.write('\x1bc')
757
758 # ITransport
759 def write(self, bytes):
760 if bytes:
761 self.lastWrite = bytes
762 self.transport.write('\r\n'.join(bytes.split('\n')))
763
764 def writeSequence(self, bytes):
765 self.write(''.join(bytes))
766
767 def loseConnection(self):
768 self.reset()
769 self.transport.loseConnection()
770
771 def connectionLost(self, reason):
772 if self.terminalProtocol is not None:
773 try:
774 self.terminalProtocol.connectionLost(reason)
775 finally:
776 self.terminalProtocol = None
777 # Add symbolic names for function keys
778 for name, const in zip(_KEY_NAMES, FUNCTION_KEYS):
779 setattr(ServerProtocol, name, const)
780
781
782
783 class ClientProtocol(protocol.Protocol):
784
785 terminalFactory = None
786 terminal = None
787
788 state = 'data'
789
790 _escBuf = None
791
792 _shorts = {
793 'D': 'index',
794 'M': 'reverseIndex',
795 'E': 'nextLine',
796 '7': 'saveCursor',
797 '8': 'restoreCursor',
798 '=': 'applicationKeypadMode',
799 '>': 'numericKeypadMode',
800 'N': 'singleShift2',
801 'O': 'singleShift3',
802 'H': 'horizontalTabulationSet',
803 'c': 'reset'}
804
805 _longs = {
806 '[': 'bracket-escape',
807 '(': 'select-g0',
808 ')': 'select-g1',
809 '#': 'select-height-width'}
810
811 _charsets = {
812 'A': CS_UK,
813 'B': CS_US,
814 '0': CS_DRAWING,
815 '1': CS_ALTERNATE,
816 '2': CS_ALTERNATE_SPECIAL}
817
818 # Factory who instantiated me
819 factory = None
820
821 def __init__(self, terminalFactory=None, *a, **kw):
822 """
823 @param terminalFactory: A callable which will be invoked with
824 *a, **kw and should return an ITerminalTransport provider.
825 This will be invoked when this ClientProtocol establishes a
826 connection.
827
828 @param a: Any positional arguments to pass to terminalFactory.
829 @param kw: Any keyword arguments to pass to terminalFactory.
830 """
831 # assert terminalFactory is None or ITerminalTransport.implementedBy(ter minalFactory), "ClientProtocol.__init__ must be passed an ITerminalTransport imp lementor"
832 if terminalFactory is not None:
833 self.terminalFactory = terminalFactory
834 self.terminalArgs = a
835 self.terminalKwArgs = kw
836
837 def connectionMade(self):
838 if self.terminalFactory is not None:
839 self.terminal = self.terminalFactory(*self.terminalArgs, **self.term inalKwArgs)
840 self.terminal.factory = self.factory
841 self.terminal.makeConnection(self)
842
843 def connectionLost(self, reason):
844 if self.terminal is not None:
845 try:
846 self.terminal.connectionLost(reason)
847 finally:
848 del self.terminal
849
850 def dataReceived(self, bytes):
851 for b in bytes:
852 if self.state == 'data':
853 if b == '\x1b':
854 self.state = 'escaped'
855 elif b == '\x14':
856 self.terminal.shiftOut()
857 elif b == '\x15':
858 self.terminal.shiftIn()
859 elif b == '\x08':
860 self.terminal.cursorBackward()
861 else:
862 self.terminal.write(b)
863 elif self.state == 'escaped':
864 fName = self._shorts.get(b)
865 if fName is not None:
866 self.state = 'data'
867 getattr(self.terminal, fName)()
868 else:
869 state = self._longs.get(b)
870 if state is not None:
871 self.state = state
872 else:
873 self.terminal.unhandledControlSequence('\x1b' + b)
874 self.state = 'data'
875 elif self.state == 'bracket-escape':
876 if self._escBuf is None:
877 self._escBuf = []
878 if b.isalpha() or b == '~':
879 self._handleControlSequence(''.join(self._escBuf), b)
880 del self._escBuf
881 self.state = 'data'
882 else:
883 self._escBuf.append(b)
884 elif self.state == 'select-g0':
885 self.terminal.selectCharacterSet(self._charsets.get(b, b), G0)
886 self.state = 'data'
887 elif self.state == 'select-g1':
888 self.terminal.selectCharacterSet(self._charsets.get(b, b), G1)
889 self.state = 'data'
890 elif self.state == 'select-height-width':
891 self._handleHeightWidth(b)
892 self.state = 'data'
893 else:
894 raise ValueError("Illegal state")
895
896 def _handleControlSequence(self, buf, terminal):
897 f = getattr(self.controlSequenceParser, CST.get(terminal, terminal), Non e)
898 if f is None:
899 self.terminal.unhandledControlSequence('\x1b[' + buf + terminal)
900 else:
901 f(self, self.terminal, buf)
902
903 class ControlSequenceParser:
904 def _makeSimple(ch, fName):
905 n = 'cursor' + fName
906 def simple(self, proto, handler, buf):
907 if not buf:
908 getattr(handler, n)(1)
909 else:
910 try:
911 m = int(buf)
912 except ValueError:
913 handler.unhandledControlSequence('\x1b[' + buf + ch)
914 else:
915 getattr(handler, n)(m)
916 return simple
917 for (ch, fName) in (('A', 'Up'),
918 ('B', 'Down'),
919 ('C', 'Forward'),
920 ('D', 'Backward')):
921 exec ch + " = _makeSimple(ch, fName)"
922 del _makeSimple
923
924 def h(self, proto, handler, buf):
925 # XXX - Handle '?' to introduce ANSI-Compatible private modes.
926 try:
927 modes = map(int, buf.split(';'))
928 except ValueError:
929 handler.unhandledControlSequence('\x1b[' + buf + 'h')
930 else:
931 handler.setModes(modes)
932
933 def l(self, proto, handler, buf):
934 # XXX - Handle '?' to introduce ANSI-Compatible private modes.
935 try:
936 modes = map(int, buf.split(';'))
937 except ValueError:
938 handler.unhandledControlSequence('\x1b[' + buf + 'l')
939 else:
940 handler.resetModes(modes)
941
942 def r(self, proto, handler, buf):
943 parts = buf.split(';')
944 if len(parts) == 1:
945 handler.setScrollRegion(None, None)
946 elif len(parts) == 2:
947 try:
948 if parts[0]:
949 pt = int(parts[0])
950 else:
951 pt = None
952 if parts[1]:
953 pb = int(parts[1])
954 else:
955 pb = None
956 except ValueError:
957 handler.unhandledControlSequence('\x1b[' + buf + 'r')
958 else:
959 handler.setScrollRegion(pt, pb)
960 else:
961 handler.unhandledControlSequence('\x1b[' + buf + 'r')
962
963 def K(self, proto, handler, buf):
964 if not buf:
965 handler.eraseToLineEnd()
966 elif buf == '1':
967 handler.eraseToLineBeginning()
968 elif buf == '2':
969 handler.eraseLine()
970 else:
971 handler.unhandledControlSequence('\x1b[' + buf + 'K')
972
973 def H(self, proto, handler, buf):
974 handler.cursorHome()
975
976 def J(self, proto, handler, buf):
977 if not buf:
978 handler.eraseToDisplayEnd()
979 elif buf == '1':
980 handler.eraseToDisplayBeginning()
981 elif buf == '2':
982 handler.eraseDisplay()
983 else:
984 handler.unhandledControlSequence('\x1b[' + buf + 'J')
985
986 def P(self, proto, handler, buf):
987 if not buf:
988 handler.deleteCharacter(1)
989 else:
990 try:
991 n = int(buf)
992 except ValueError:
993 handler.unhandledControlSequence('\x1b[' + buf + 'P')
994 else:
995 handler.deleteCharacter(n)
996
997 def L(self, proto, handler, buf):
998 if not buf:
999 handler.insertLine(1)
1000 else:
1001 try:
1002 n = int(buf)
1003 except ValueError:
1004 handler.unhandledControlSequence('\x1b[' + buf + 'L')
1005 else:
1006 handler.insertLine(n)
1007
1008 def M(self, proto, handler, buf):
1009 if not buf:
1010 handler.deleteLine(1)
1011 else:
1012 try:
1013 n = int(buf)
1014 except ValueError:
1015 handler.unhandledControlSequence('\x1b[' + buf + 'M')
1016 else:
1017 handler.deleteLine(n)
1018
1019 def n(self, proto, handler, buf):
1020 if buf == '6':
1021 x, y = handler.reportCursorPosition()
1022 proto.transport.write('\x1b[%d;%dR' % (x + 1, y + 1))
1023 else:
1024 handler.unhandledControlSequence('\x1b[' + buf + 'n')
1025
1026 def m(self, proto, handler, buf):
1027 if not buf:
1028 handler.selectGraphicRendition(NORMAL)
1029 else:
1030 attrs = []
1031 for a in buf.split(';'):
1032 try:
1033 a = int(a)
1034 except ValueError:
1035 pass
1036 attrs.append(a)
1037 handler.selectGraphicRendition(*attrs)
1038
1039 controlSequenceParser = ControlSequenceParser()
1040
1041 def _handleHeightWidth(self, b):
1042 if b == '3':
1043 self.terminal.doubleHeightLine(True)
1044 elif b == '4':
1045 self.terminal.doubleHeightLine(False)
1046 elif b == '5':
1047 self.terminal.singleWidthLine()
1048 elif b == '6':
1049 self.terminal.doubleWidthLine()
1050 else:
1051 self.terminal.unhandledControlSequence('\x1b#' + b)
1052
1053
1054 __all__ = [
1055 # Interfaces
1056 'ITerminalProtocol', 'ITerminalTransport',
1057
1058 # Symbolic constants
1059 'modes', 'privateModes', 'FUNCTION_KEYS',
1060
1061 'CS_US', 'CS_UK', 'CS_DRAWING', 'CS_ALTERNATE', 'CS_ALTERNATE_SPECIAL',
1062 'G0', 'G1', 'G2', 'G3',
1063
1064 'UNDERLINE', 'REVERSE_VIDEO', 'BLINK', 'BOLD', 'NORMAL',
1065
1066 # Protocol classes
1067 'ServerProtocol', 'ClientProtocol']
OLDNEW
« no previous file with comments | « third_party/twisted_8_1/twisted/conch/insults/helper.py ('k') | third_party/twisted_8_1/twisted/conch/insults/text.py » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698