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

Side by Side Diff: third_party/twisted_8_1/twisted/conch/recvline.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_recvline -*-
2 # Copyright (c) 2001-2004 Twisted Matrix Laboratories.
3 # See LICENSE for details.
4
5 """
6 Basic line editing support.
7
8 @author: U{Jp Calderone<mailto:exarkun@twistedmatrix.com>}
9 """
10
11 import string
12
13 from zope.interface import implements
14
15 from twisted.conch.insults import insults, helper
16
17 from twisted.python import log, reflect
18
19 _counters = {}
20 class Logging(object):
21 """Wrapper which logs attribute lookups.
22
23 This was useful in debugging something, I guess. I forget what.
24 It can probably be deleted or moved somewhere more appropriate.
25 Nothing special going on here, really.
26 """
27 def __init__(self, original):
28 self.original = original
29 key = reflect.qual(original.__class__)
30 count = _counters.get(key, 0)
31 _counters[key] = count + 1
32 self._logFile = file(key + '-' + str(count), 'w')
33
34 def __str__(self):
35 return str(super(Logging, self).__getattribute__('original'))
36
37 def __repr__(self):
38 return repr(super(Logging, self).__getattribute__('original'))
39
40 def __getattribute__(self, name):
41 original = super(Logging, self).__getattribute__('original')
42 logFile = super(Logging, self).__getattribute__('_logFile')
43 logFile.write(name + '\n')
44 return getattr(original, name)
45
46 class TransportSequence(object):
47 """An L{ITerminalTransport} implementation which forwards calls to
48 one or more other L{ITerminalTransport}s.
49
50 This is a cheap way for servers to keep track of the state they
51 expect the client to see, since all terminal manipulations can be
52 send to the real client and to a terminal emulator that lives in
53 the server process.
54 """
55 implements(insults.ITerminalTransport)
56
57 for keyID in ('UP_ARROW', 'DOWN_ARROW', 'RIGHT_ARROW', 'LEFT_ARROW',
58 'HOME', 'INSERT', 'DELETE', 'END', 'PGUP', 'PGDN',
59 'F1', 'F2', 'F3', 'F4', 'F5', 'F6', 'F7', 'F8', 'F9',
60 'F10', 'F11', 'F12'):
61 exec '%s = object()' % (keyID,)
62
63 TAB = '\t'
64 BACKSPACE = '\x7f'
65
66 def __init__(self, *transports):
67 assert transports, "Cannot construct a TransportSequence with no transpo rts"
68 self.transports = transports
69
70 for method in insults.ITerminalTransport:
71 exec """\
72 def %s(self, *a, **kw):
73 for tpt in self.transports:
74 result = tpt.%s(*a, **kw)
75 return result
76 """ % (method, method)
77
78 class LocalTerminalBufferMixin(object):
79 """A mixin for RecvLine subclasses which records the state of the terminal.
80
81 This is accomplished by performing all L{ITerminalTransport} operations on b oth
82 the transport passed to makeConnection and an instance of helper.TerminalBuf fer.
83
84 @ivar terminalCopy: A L{helper.TerminalBuffer} instance which efforts
85 will be made to keep up to date with the actual terminal
86 associated with this protocol instance.
87 """
88
89 def makeConnection(self, transport):
90 self.terminalCopy = helper.TerminalBuffer()
91 self.terminalCopy.connectionMade()
92 return super(LocalTerminalBufferMixin, self).makeConnection(
93 TransportSequence(transport, self.terminalCopy))
94
95 def __str__(self):
96 return str(self.terminalCopy)
97
98 class RecvLine(insults.TerminalProtocol):
99 """L{TerminalProtocol} which adds line editing features.
100
101 Clients will be prompted for lines of input with all the usual
102 features: character echoing, left and right arrow support for
103 moving the cursor to different areas of the line buffer, backspace
104 and delete for removing characters, and insert for toggling
105 between typeover and insert mode. Tabs will be expanded to enough
106 spaces to move the cursor to the next tabstop (every four
107 characters by default). Enter causes the line buffer to be
108 cleared and the line to be passed to the lineReceived() method
109 which, by default, does nothing. Subclasses are responsible for
110 redrawing the input prompt (this will probably change).
111 """
112 width = 80
113 height = 24
114
115 TABSTOP = 4
116
117 ps = ('>>> ', '... ')
118 pn = 0
119
120 def connectionMade(self):
121 # A list containing the characters making up the current line
122 self.lineBuffer = []
123
124 # A zero-based (wtf else?) index into self.lineBuffer.
125 # Indicates the current cursor position.
126 self.lineBufferIndex = 0
127
128 t = self.terminal
129 # A map of keyIDs to bound instance methods.
130 self.keyHandlers = {
131 t.LEFT_ARROW: self.handle_LEFT,
132 t.RIGHT_ARROW: self.handle_RIGHT,
133 t.TAB: self.handle_TAB,
134
135 # Both of these should not be necessary, but figuring out
136 # which is necessary is a huge hassle.
137 '\r': self.handle_RETURN,
138 '\n': self.handle_RETURN,
139
140 t.BACKSPACE: self.handle_BACKSPACE,
141 t.DELETE: self.handle_DELETE,
142 t.INSERT: self.handle_INSERT,
143 t.HOME: self.handle_HOME,
144 t.END: self.handle_END}
145
146 self.initializeScreen()
147
148 def initializeScreen(self):
149 # Hmm, state sucks. Oh well.
150 # For now we will just take over the whole terminal.
151 self.terminal.reset()
152 self.terminal.write(self.ps[self.pn])
153 # XXX Note: I would prefer to default to starting in insert
154 # mode, however this does not seem to actually work! I do not
155 # know why. This is probably of interest to implementors
156 # subclassing RecvLine.
157
158 # XXX XXX Note: But the unit tests all expect the initial mode
159 # to be insert right now. Fuck, there needs to be a way to
160 # query the current mode or something.
161 # self.setTypeoverMode()
162 self.setInsertMode()
163
164 def currentLineBuffer(self):
165 s = ''.join(self.lineBuffer)
166 return s[:self.lineBufferIndex], s[self.lineBufferIndex:]
167
168 def setInsertMode(self):
169 self.mode = 'insert'
170 self.terminal.setModes([insults.modes.IRM])
171
172 def setTypeoverMode(self):
173 self.mode = 'typeover'
174 self.terminal.resetModes([insults.modes.IRM])
175
176 def drawInputLine(self):
177 """
178 Write a line containing the current input prompt and the current line
179 buffer at the current cursor position.
180 """
181 self.terminal.write(self.ps[self.pn] + ''.join(self.lineBuffer))
182
183 def terminalSize(self, width, height):
184 # XXX - Clear the previous input line, redraw it at the new
185 # cursor position
186 self.terminal.eraseDisplay()
187 self.terminal.cursorHome()
188 self.width = width
189 self.height = height
190 self.drawInputLine()
191
192 def unhandledControlSequence(self, seq):
193 pass
194
195 def keystrokeReceived(self, keyID, modifier):
196 m = self.keyHandlers.get(keyID)
197 if m is not None:
198 m()
199 elif keyID in string.printable:
200 self.characterReceived(keyID, False)
201 else:
202 log.msg("Received unhandled keyID: %r" % (keyID,))
203
204 def characterReceived(self, ch, moreCharactersComing):
205 if self.mode == 'insert':
206 self.lineBuffer.insert(self.lineBufferIndex, ch)
207 else:
208 self.lineBuffer[self.lineBufferIndex:self.lineBufferIndex+1] = [ch]
209 self.lineBufferIndex += 1
210 self.terminal.write(ch)
211
212 def handle_TAB(self):
213 n = self.TABSTOP - (len(self.lineBuffer) % self.TABSTOP)
214 self.terminal.cursorForward(n)
215 self.lineBufferIndex += n
216 self.lineBuffer.extend(' ' * n)
217
218 def handle_LEFT(self):
219 if self.lineBufferIndex > 0:
220 self.lineBufferIndex -= 1
221 self.terminal.cursorBackward()
222
223 def handle_RIGHT(self):
224 if self.lineBufferIndex < len(self.lineBuffer):
225 self.lineBufferIndex += 1
226 self.terminal.cursorForward()
227
228 def handle_HOME(self):
229 if self.lineBufferIndex:
230 self.terminal.cursorBackward(self.lineBufferIndex)
231 self.lineBufferIndex = 0
232
233 def handle_END(self):
234 offset = len(self.lineBuffer) - self.lineBufferIndex
235 if offset:
236 self.terminal.cursorForward(offset)
237 self.lineBufferIndex = len(self.lineBuffer)
238
239 def handle_BACKSPACE(self):
240 if self.lineBufferIndex > 0:
241 self.lineBufferIndex -= 1
242 del self.lineBuffer[self.lineBufferIndex]
243 self.terminal.cursorBackward()
244 self.terminal.deleteCharacter()
245
246 def handle_DELETE(self):
247 if self.lineBufferIndex < len(self.lineBuffer):
248 del self.lineBuffer[self.lineBufferIndex]
249 self.terminal.deleteCharacter()
250
251 def handle_RETURN(self):
252 line = ''.join(self.lineBuffer)
253 self.lineBuffer = []
254 self.lineBufferIndex = 0
255 self.terminal.nextLine()
256 self.lineReceived(line)
257
258 def handle_INSERT(self):
259 assert self.mode in ('typeover', 'insert')
260 if self.mode == 'typeover':
261 self.setInsertMode()
262 else:
263 self.setTypeoverMode()
264
265 def lineReceived(self, line):
266 pass
267
268 class HistoricRecvLine(RecvLine):
269 """L{TerminalProtocol} which adds both basic line-editing features and input history.
270
271 Everything supported by L{RecvLine} is also supported by this class. In add ition, the
272 up and down arrows traverse the input history. Each received line is automa tically
273 added to the end of the input history.
274 """
275 def connectionMade(self):
276 RecvLine.connectionMade(self)
277
278 self.historyLines = []
279 self.historyPosition = 0
280
281 t = self.terminal
282 self.keyHandlers.update({t.UP_ARROW: self.handle_UP,
283 t.DOWN_ARROW: self.handle_DOWN})
284
285 def currentHistoryBuffer(self):
286 b = tuple(self.historyLines)
287 return b[:self.historyPosition], b[self.historyPosition:]
288
289 def _deliverBuffer(self, buf):
290 if buf:
291 for ch in buf[:-1]:
292 self.characterReceived(ch, True)
293 self.characterReceived(buf[-1], False)
294
295 def handle_UP(self):
296 if self.lineBuffer and self.historyPosition == len(self.historyLines):
297 self.historyLines.append(self.lineBuffer)
298 if self.historyPosition > 0:
299 self.handle_HOME()
300 self.terminal.eraseToLineEnd()
301
302 self.historyPosition -= 1
303 self.lineBuffer = []
304
305 self._deliverBuffer(self.historyLines[self.historyPosition])
306
307 def handle_DOWN(self):
308 if self.historyPosition < len(self.historyLines) - 1:
309 self.handle_HOME()
310 self.terminal.eraseToLineEnd()
311
312 self.historyPosition += 1
313 self.lineBuffer = []
314
315 self._deliverBuffer(self.historyLines[self.historyPosition])
316 else:
317 self.handle_HOME()
318 self.terminal.eraseToLineEnd()
319
320 self.historyPosition = len(self.historyLines)
321 self.lineBuffer = []
322 self.lineBufferIndex = 0
323
324 def handle_RETURN(self):
325 if self.lineBuffer:
326 self.historyLines.append(''.join(self.lineBuffer))
327 self.historyPosition = len(self.historyLines)
328 return RecvLine.handle_RETURN(self)
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698