##// END OF EJS Templates
clean up...
ldufrechou -
Show More
@@ -1,735 +1,737 b''
1 1 #!/usr/bin/python
2 2 # -*- coding: iso-8859-15 -*-
3 3 '''
4 4 Provides IPython WX console widgets.
5 5
6 6 @author: Laurent Dufrechou
7 7 laurent.dufrechou _at_ gmail.com
8 8 This WX widget is based on the original work of Eitan Isaacson
9 9 that provided the console for the GTK toolkit.
10 10
11 11 Original work from:
12 12 @author: Eitan Isaacson
13 13 @organization: IBM Corporation
14 14 @copyright: Copyright (c) 2007 IBM Corporation
15 15 @license: BSD
16 16
17 17 All rights reserved. This program and the accompanying materials are made
18 18 available under the terms of the BSD which accompanies this distribution, and
19 19 is available at U{http://www.opensource.org/licenses/bsd-license.php}
20 20 '''
21 21
22 22 __version__ = 0.8
23 23 __author__ = "Laurent Dufrechou"
24 24 __email__ = "laurent.dufrechou _at_ gmail.com"
25 25 __license__ = "BSD"
26 26
27 27 import wx
28 28 import wx.stc as stc
29 29 import wx.lib.newevent
30 30
31 31 import re
32 32 import sys
33 33 import locale
34 34 from StringIO import StringIO
35 35 try:
36 36 import IPython
37 37 except Exception,e:
38 38 raise "Error importing IPython (%s)" % str(e)
39 39
40 40 from ipshell_nonblocking import NonBlockingIPShell
41 41
42 42
43 43 class WxNonBlockingIPShell(NonBlockingIPShell):
44 44 '''
45 45 An NonBlockingIPShell Thread that is WX dependent.
46 46 '''
47 47 def __init__(self, parent,
48 48 argv=[],user_ns={},user_global_ns=None,
49 49 cin=None, cout=None, cerr=None,
50 50 ask_exit_handler=None, rawinput=None):
51 51
52 52 NonBlockingIPShell.__init__(self,argv,user_ns,user_global_ns,
53 53 cin, cout, cerr,
54 54 ask_exit_handler,
55 55 rawinput)
56 56
57 57 self.parent = parent
58 58
59 59 self.ask_exit_callback = ask_exit_handler
60 60 self._IP.exit = self._askExit
61 61
62 62 def addGUIShortcut(self,text,func):
63 63 wx.CallAfter(self.parent.add_button_handler,
64 64 button_info={ 'text':text,
65 65 'func':self.parent.doExecuteLine(func)})
66 66
67 67 def _askExit(self):
68 68 wx.CallAfter(self.ask_exit_callback, ())
69 69
70 70 def _afterExecute(self):
71 71 wx.CallAfter(self.parent.evtStateExecuteDone, ())
72 72
73 73
74 74 class WxConsoleView(stc.StyledTextCtrl):
75 75 '''
76 76 Specialized styled text control view for console-like workflow.
77 77 We use here a scintilla frontend thus it can be reused in any GUI that
78 78 supports scintilla with less work.
79 79
80 80 @cvar ANSI_COLORS_BLACK: Mapping of terminal colors to X11 names.
81 81 (with Black background)
82 82 @type ANSI_COLORS_BLACK: dictionary
83 83
84 84 @cvar ANSI_COLORS_WHITE: Mapping of terminal colors to X11 names.
85 85 (with White background)
86 86 @type ANSI_COLORS_WHITE: dictionary
87 87
88 88 @ivar color_pat: Regex of terminal color pattern
89 89 @type color_pat: _sre.SRE_Pattern
90 90 '''
91 91 ANSI_STYLES_BLACK={'0;30': [0,'WHITE'], '0;31': [1,'RED'],
92 92 '0;32': [2,'GREEN'], '0;33': [3,'BROWN'],
93 93 '0;34': [4,'BLUE'], '0;35': [5,'PURPLE'],
94 94 '0;36': [6,'CYAN'], '0;37': [7,'LIGHT GREY'],
95 95 '1;30': [8,'DARK GREY'], '1;31': [9,'RED'],
96 96 '1;32': [10,'SEA GREEN'], '1;33': [11,'YELLOW'],
97 97 '1;34': [12,'LIGHT BLUE'], '1;35':
98 98 [13,'MEDIUM VIOLET RED'],
99 99 '1;36': [14,'LIGHT STEEL BLUE'],'1;37': [15,'YELLOW']}
100 100
101 101 ANSI_STYLES_WHITE={'0;30': [0,'BLACK'], '0;31': [1,'RED'],
102 102 '0;32': [2,'GREEN'], '0;33': [3,'BROWN'],
103 103 '0;34': [4,'BLUE'], '0;35': [5,'PURPLE'],
104 104 '0;36': [6,'CYAN'], '0;37': [7,'LIGHT GREY'],
105 105 '1;30': [8,'DARK GREY'], '1;31': [9,'RED'],
106 106 '1;32': [10,'SEA GREEN'], '1;33': [11,'YELLOW'],
107 107 '1;34': [12,'LIGHT BLUE'], '1;35':
108 108 [13,'MEDIUM VIOLET RED'],
109 109 '1;36': [14,'LIGHT STEEL BLUE'],'1;37': [15,'YELLOW']}
110 110
111 111 def __init__(self,parent,prompt,intro="",background_color="BLACK",
112 112 pos=wx.DefaultPosition, ID = -1, size=wx.DefaultSize,
113 113 style=0):
114 114 '''
115 115 Initialize console view.
116 116
117 117 @param parent: Parent widget
118 118 @param prompt: User specified prompt
119 119 @type intro: string
120 120 @param intro: User specified startup introduction string
121 121 @type intro: string
122 122 @param background_color: Can be BLACK or WHITE
123 123 @type background_color: string
124 124 @param other: init param of styledTextControl (can be used as-is)
125 125 '''
126 126 stc.StyledTextCtrl.__init__(self, parent, ID, pos, size, style)
127 127
128 128 ####### Scintilla configuration ###################################
129 129
130 130 # Ctrl + B or Ctrl + N can be used to zoomin/zoomout the text inside
131 131 # the widget
132 132 self.CmdKeyAssign(ord('B'), stc.STC_SCMOD_CTRL, stc.STC_CMD_ZOOMIN)
133 133 self.CmdKeyAssign(ord('N'), stc.STC_SCMOD_CTRL, stc.STC_CMD_ZOOMOUT)
134 134
135 135 #we define platform specific fonts
136 136 if wx.Platform == '__WXMSW__':
137 137 faces = { 'times': 'Times New Roman',
138 138 'mono' : 'Courier New',
139 139 'helv' : 'Arial',
140 140 'other': 'Comic Sans MS',
141 141 'size' : 10,
142 142 'size2': 8,
143 143 }
144 144 elif wx.Platform == '__WXMAC__':
145 145 faces = { 'times': 'Times New Roman',
146 146 'mono' : 'Monaco',
147 147 'helv' : 'Arial',
148 148 'other': 'Comic Sans MS',
149 149 'size' : 10,
150 150 'size2': 8,
151 151 }
152 152 else:
153 153 faces = { 'times': 'Times',
154 154 'mono' : 'Courier',
155 155 'helv' : 'Helvetica',
156 156 'other': 'new century schoolbook',
157 157 'size' : 10,
158 158 'size2': 8,
159 159 }
160 160
161 161 #We draw a line at position 80
162 162 self.SetEdgeMode(stc.STC_EDGE_LINE)
163 163 self.SetEdgeColumn(80)
164 164 self.SetEdgeColour(wx.LIGHT_GREY)
165 165
166 166 #self.SetViewWhiteSpace(True)
167 167 #self.SetViewEOL(True)
168 168 self.SetEOLMode(stc.STC_EOL_CRLF)
169 169 #self.SetWrapMode(stc.STC_WRAP_CHAR)
170 170 #self.SetWrapMode(stc.STC_WRAP_WORD)
171 171 self.SetBufferedDraw(True)
172 172 #self.SetUseAntiAliasing(True)
173 173 self.SetLayoutCache(stc.STC_CACHE_PAGE)
174 174
175 175 self.EnsureCaretVisible()
176 176
177 177 self.SetMargins(3,3) #text is moved away from border with 3px
178 178 # Suppressing Scintilla margins
179 179 self.SetMarginWidth(0,0)
180 180 self.SetMarginWidth(1,0)
181 181 self.SetMarginWidth(2,0)
182 182
183 183 # make some styles
184 184 if background_color != "BLACK":
185 185 self.background_color = "WHITE"
186 186 self.SetCaretForeground("BLACK")
187 187 self.ANSI_STYLES = self.ANSI_STYLES_WHITE
188 188 else:
189 189 self.background_color = background_color
190 190 self.SetCaretForeground("WHITE")
191 191 self.ANSI_STYLES = self.ANSI_STYLES_BLACK
192 192
193 193 self.StyleSetSpec(stc.STC_STYLE_DEFAULT,
194 194 "fore:%s,back:%s,size:%d,face:%s"
195 195 % (self.ANSI_STYLES['0;30'][1],
196 196 self.background_color,
197 197 faces['size'], faces['mono']))
198 198 self.StyleClearAll()
199 199 self.StyleSetSpec(stc.STC_STYLE_BRACELIGHT,
200 200 "fore:#FF0000,back:#0000FF,bold")
201 201 self.StyleSetSpec(stc.STC_STYLE_BRACEBAD,
202 202 "fore:#000000,back:#FF0000,bold")
203 203
204 204 for style in self.ANSI_STYLES.values():
205 205 self.StyleSetSpec(style[0], "bold,fore:%s" % style[1])
206 206
207 207 #######################################################################
208 208
209 209 self.indent = 0
210 210 self.prompt_count = 0
211 211 self.color_pat = re.compile('\x01?\x1b\[(.*?)m\x02?')
212 212
213 213 self.write(intro)
214 214 self.setPrompt(prompt)
215 215 self.showPrompt()
216 216
217 217 self.Bind(wx.EVT_KEY_DOWN, self._onKeypress, self)
218 218
219 219 def write(self, text):
220 220 '''
221 221 Write given text to buffer.
222 222
223 223 @param text: Text to append.
224 224 @type text: string
225 225 '''
226 226 segments = self.color_pat.split(text)
227 227 segment = segments.pop(0)
228 228 self.StartStyling(self.getCurrentLineEnd(),0xFF)
229 229 self.AppendText(segment)
230 230
231 231 if segments:
232 232 ansi_tags = self.color_pat.findall(text)
233 233
234 234 for tag in ansi_tags:
235 235 i = segments.index(tag)
236 236 self.StartStyling(self.getCurrentLineEnd(),0xFF)
237 237 self.AppendText(segments[i+1])
238 238
239 239 if tag != '0':
240 240 self.SetStyling(len(segments[i+1]),self.ANSI_STYLES[tag][0])
241 241
242 242 segments.pop(i)
243 243
244 244 self.moveCursor(self.getCurrentLineEnd())
245 245
246 246 def getPromptLen(self):
247 247 '''
248 248 Return the length of current prompt
249 249 '''
250 250 return len(str(self.prompt_count)) + 7
251 251
252 252 def setPrompt(self,prompt):
253 253 self.prompt = prompt
254 254
255 255 def setIndentation(self,indentation):
256 256 self.indent = indentation
257 257
258 258 def setPromptCount(self,count):
259 259 self.prompt_count = count
260 260
261 261 def showPrompt(self):
262 262 '''
263 263 Prints prompt at start of line.
264 264
265 265 @param prompt: Prompt to print.
266 266 @type prompt: string
267 267 '''
268 268 self.write(self.prompt)
269 269 #now we update the position of end of prompt
270 270 self.current_start = self.getCurrentLineEnd()
271 271
272 272 autoindent = self.indent*' '
273 273 autoindent = autoindent.replace(' ','\t')
274 274 self.write(autoindent)
275 275
276 276 def changeLine(self, text):
277 277 '''
278 278 Replace currently entered command line with given text.
279 279
280 280 @param text: Text to use as replacement.
281 281 @type text: string
282 282 '''
283 283 self.SetSelection(self.getCurrentPromptStart(),self.getCurrentLineEnd())
284 284 self.ReplaceSelection(text)
285 285 self.moveCursor(self.getCurrentLineEnd())
286 286
287 287 def getCurrentPromptStart(self):
288 288 return self.current_start
289 289
290 290 def getCurrentLineStart(self):
291 291 return self.GotoLine(self.LineFromPosition(self.GetCurrentPos()))
292 292
293 293 def getCurrentLineEnd(self):
294 294 return self.GetLength()
295 295
296 296 def getCurrentLine(self):
297 297 '''
298 298 Get text in current command line.
299 299
300 300 @return: Text of current command line.
301 301 @rtype: string
302 302 '''
303 303 return self.GetTextRange(self.getCurrentPromptStart(),
304 304 self.getCurrentLineEnd())
305 305
306 306 def moveCursorOnNewValidKey(self):
307 307 #If cursor is at wrong position put it at last line...
308 308 if self.GetCurrentPos() < self.getCurrentPromptStart():
309 309 self.GotoPos(self.getCurrentPromptStart())
310 310
311 311 def removeFromTo(self,from_pos,to_pos):
312 312 if from_pos < to_pos:
313 313 self.SetSelection(from_pos,to_pos)
314 314 self.DeleteBack()
315 315
316 316 def removeCurrentLine(self):
317 317 self.LineDelete()
318 318
319 319 def moveCursor(self,position):
320 320 self.GotoPos(position)
321 321
322 322 def getCursorPos(self):
323 323 return self.GetCurrentPos()
324 324
325 325 def selectFromTo(self,from_pos,to_pos):
326 326 self.SetSelectionStart(from_pos)
327 327 self.SetSelectionEnd(to_pos)
328 328
329 329 def writeHistory(self,history):
330 330 self.removeFromTo(self.getCurrentPromptStart(),self.getCurrentLineEnd())
331 331 self.changeLine(history)
332 332
333 333 def writeCompletion(self, possibilities):
334 334 max_len = len(max(possibilities,key=len))
335 335 max_symbol =' '*max_len
336 336
337 337 #now we check how much symbol we can put on a line...
338 338 cursor_pos = self.getCursorPos()
339 339 test_buffer = max_symbol + ' '*4
340 340 current_lines = self.GetLineCount()
341 341
342 342 allowed_symbols = 80/len(test_buffer)
343 343 if allowed_symbols == 0:
344 344 allowed_symbols = 1
345 345
346 346 pos = 1
347 347 buf = ''
348 348 for symbol in possibilities:
349 349 #buf += symbol+'\n'#*spaces)
350 350 if pos<allowed_symbols:
351 351 spaces = max_len - len(symbol) + 4
352 352 buf += symbol+' '*spaces
353 353 pos += 1
354 354 else:
355 355 buf+=symbol+'\n'
356 356 pos = 1
357 357 self.write(buf)
358 358
359 359 def _onKeypress(self, event, skip=True):
360 360 '''
361 361 Key press callback used for correcting behavior for console-like
362 362 interfaces. For example 'home' should go to prompt, not to begining of
363 363 line.
364 364
365 365 @param widget: Widget that key press accored in.
366 366 @type widget: gtk.Widget
367 367 @param event: Event object
368 368 @type event: gtk.gdk.Event
369 369
370 370 @return: Return True if event as been catched.
371 371 @rtype: boolean
372 372 '''
373 373
374 374 if event.GetKeyCode() == wx.WXK_HOME:
375 375 if event.Modifiers == wx.MOD_NONE:
376 376 self.moveCursorOnNewValidKey()
377 377 self.moveCursor(self.getCurrentPromptStart())
378 378 return True
379 379 elif event.Modifiers == wx.MOD_SHIFT:
380 380 self.moveCursorOnNewValidKey()
381 381 self.selectFromTo(self.getCurrentPromptStart(),self.getCursorPos())
382 382 return True
383 383 else:
384 384 return False
385 385
386 386 elif event.GetKeyCode() == wx.WXK_LEFT:
387 387 if event.Modifiers == wx.MOD_NONE:
388 388 self.moveCursorOnNewValidKey()
389 389
390 390 self.moveCursor(self.getCursorPos()-1)
391 391 if self.getCursorPos() < self.getCurrentPromptStart():
392 392 self.moveCursor(self.getCurrentPromptStart())
393 393 return True
394 394
395 395 elif event.GetKeyCode() == wx.WXK_BACK:
396 396 self.moveCursorOnNewValidKey()
397 397 if self.getCursorPos() > self.getCurrentPromptStart():
398 398 event.Skip()
399 399 return True
400 400
401 401 if skip:
402 402 if event.GetKeyCode() not in [wx.WXK_PAGEUP,wx.WXK_PAGEDOWN] and event.Modifiers == wx.MOD_NONE:
403 403 self.moveCursorOnNewValidKey()
404 404
405 405 event.Skip()
406 406 return True
407 407 return False
408 408
409 409 def OnUpdateUI(self, evt):
410 410 # check for matching braces
411 411 braceAtCaret = -1
412 412 braceOpposite = -1
413 413 charBefore = None
414 414 caretPos = self.GetCurrentPos()
415 415
416 416 if caretPos > 0:
417 417 charBefore = self.GetCharAt(caretPos - 1)
418 418 styleBefore = self.GetStyleAt(caretPos - 1)
419 419
420 420 # check before
421 421 if charBefore and chr(charBefore) in "[]{}()" and styleBefore == stc.STC_P_OPERATOR:
422 422 braceAtCaret = caretPos - 1
423 423
424 424 # check after
425 425 if braceAtCaret < 0:
426 426 charAfter = self.GetCharAt(caretPos)
427 427 styleAfter = self.GetStyleAt(caretPos)
428 428
429 429 if charAfter and chr(charAfter) in "[]{}()" and styleAfter == stc.STC_P_OPERATOR:
430 430 braceAtCaret = caretPos
431 431
432 432 if braceAtCaret >= 0:
433 433 braceOpposite = self.BraceMatch(braceAtCaret)
434 434
435 435 if braceAtCaret != -1 and braceOpposite == -1:
436 436 self.BraceBadLight(braceAtCaret)
437 437 else:
438 438 self.BraceHighlight(braceAtCaret, braceOpposite)
439 439 #pt = self.PointFromPosition(braceOpposite)
440 440 #self.Refresh(True, wxRect(pt.x, pt.y, 5,5))
441 441 #print pt
442 442 #self.Refresh(False)
443 443
444 444 class IPShellWidget(wx.Panel):
445 445 '''
446 446 This is wx.Panel that embbed the IPython Thread and the wx.StyledTextControl
447 447 If you want to port this to any other GUI toolkit, just replace the
448 448 WxConsoleView by YOURGUIConsoleView and make YOURGUIIPythonView derivate
449 449 from whatever container you want. I've choosed to derivate from a wx.Panel
450 450 because it seems to be more useful
451 451 Any idea to make it more 'generic' welcomed.
452 452 '''
453 453
454 454 def __init__(self, parent, intro=None,
455 455 background_color="BLACK", add_button_handler=None,
456 456 wx_ip_shell=None,
457 457 ):
458 458 '''
459 459 Initialize.
460 460 Instanciate an IPython thread.
461 461 Instanciate a WxConsoleView.
462 462 Redirect I/O to console.
463 463 '''
464 464 wx.Panel.__init__(self,parent,-1)
465 465
466 466 ### IPython non blocking shell instanciation ###
467 467 self.cout = StringIO()
468 468 self.add_button_handler = add_button_handler
469 469
470 470 if wx_ip_shell is not None:
471 471 self.IP = wx_ip_shell
472 472 else:
473 473 self.IP = WxNonBlockingIPShell(self,
474 474 cout = self.cout, cerr = self.cout,
475 475 ask_exit_handler = self.askExitCallback,
476 476 rawinput = self.rawInput)
477 477
478 478 ### IPython wx console view instanciation ###
479 479 #If user didn't defined an intro text, we create one for him
480 480 #If you really wnat an empty intrp just call wxIPythonViewPanel
481 481 #with intro=''
482 482 if intro is None:
483 483 welcome_text = "Welcome to WxIPython Shell.\n\n"
484 484 welcome_text+= self.IP.getBanner()
485 485 welcome_text+= "!command -> Execute command in shell\n"
486 486 welcome_text+= "TAB -> Autocompletion\n"
487 487 else:
488 488 welcome_text = intro
489 489
490 490 self.text_ctrl = WxConsoleView(self,
491 491 self.IP.getPrompt(),
492 492 intro=welcome_text,
493 493 background_color=background_color)
494 494
495 495 self.cout.write = self.text_ctrl.write
496 496
497 497 self.text_ctrl.Bind(wx.EVT_KEY_DOWN, self.keyPress, self.text_ctrl)
498 498
499 499 ### making the layout of the panel ###
500 500 sizer = wx.BoxSizer(wx.VERTICAL)
501 501 sizer.Add(self.text_ctrl, 1, wx.EXPAND)
502 502 self.SetAutoLayout(True)
503 503 sizer.Fit(self)
504 504 sizer.SetSizeHints(self)
505 505 self.SetSizer(sizer)
506 506 #and we focus on the widget :)
507 507 self.SetFocus()
508 508
509 509 #widget state management (for key handling different cases)
510 510 self.setCurrentState('IDLE')
511 511 self.pager_state = 'DONE'
512 512
513 513 def askExitCallback(self, event):
514 514 self.askExitHandler(event)
515 515
516 516 #---------------------- IPython Thread Management ------------------------
517 517 def stateDoExecuteLine(self):
518 518 #print >>sys.__stdout__,"command:",self.getCurrentLine()
519 line=self.text_ctrl.getCurrentLine()
519 lines=self.text_ctrl.getCurrentLine()
520 520 self.text_ctrl.write('\n')
521 self.IP.doExecute((line.replace('\t',' '*4)).encode('cp1252'))
521 for line in lines.split('\n'):
522 self.IP.doExecute((line.replace('\t',' '*4)).encode('cp1252'))
522 523 self.updateHistoryTracker(self.text_ctrl.getCurrentLine())
523 524 self.setCurrentState('WAIT_END_OF_EXECUTION')
524 525
525 526 def evtStateExecuteDone(self,evt):
526 527 self.doc = self.IP.getDocText()
527 528 self.help = self.IP.getHelpText()
528 529 if self.doc:
529 530 self.pager_lines = self.doc[7:].split('\n')
530 self.pager_state = 'INIT'
531 self.pager_state = 'INIT'
531 532 self.setCurrentState('SHOW_DOC')
532 533 self.pager(self.doc)
533 534 elif self.help:
534 535 self.pager_lines = self.help.split('\n')
535 self.pager_state = 'INIT'
536 self.pager_state = 'INIT'
536 537 self.setCurrentState('SHOW_DOC')
537 538 self.pager(self.help)
538 539 else:
539 540 self.stateShowPrompt()
540 541
541 542 def stateShowPrompt(self):
542 543 self.setCurrentState('SHOW_PROMPT')
543 544 self.text_ctrl.setPrompt(self.IP.getPrompt())
544 545 self.text_ctrl.setIndentation(self.IP.getIndentation())
545 546 self.text_ctrl.setPromptCount(self.IP.getPromptCount())
546 547 self.text_ctrl.showPrompt()
547 548 self.IP.initHistoryIndex()
548 549 self.setCurrentState('IDLE')
549 550
550 551 def setCurrentState(self, state):
551 552 self.cur_state = state
552 553 self.updateStatusTracker(self.cur_state)
553 554 #---------------------------- Ipython raw_input -----------------------------------
554 555 def rawInput(self, prompt=''):
555 556 self.setCurrentState('WAITING_USER_INPUT')
556 557 while self.cur_state != 'WAIT_END_OF_EXECUTION':
557 558 pass
558 559 line = self.text_ctrl.getCurrentLine()
559 560 line = line.split('\n')
560 561 return line[-2]
561 562
562 563 #---------------------------- IPython pager ---------------------------------------
563 564 def pager(self,text):
564 565
565 566 if self.pager_state == 'INIT':
566 #print >>sys.__stdout__,"PAGER state:",self.pager_state
567 #print >>sys.__stdout__,"PAGER state:",self.pager_state
567 568 self.pager_nb_lines = len(self.pager_lines)
568 self.pager_index = 0
569 self.pager_do_remove = False
570 self.text_ctrl.write('\n')
571 self.pager_state = 'PROCESS_LINES'
572
573 if self.pager_state == 'PROCESS_LINES':
574 #print >>sys.__stdout__,"PAGER state:",self.pager_state
575 if self.pager_do_remove == True:
576 self.text_ctrl.removeCurrentLine()
577 self.pager_do_remove = False
578
579 if self.pager_nb_lines > 10:
580 #print >>sys.__stdout__,"PAGER processing 10 lines"
581 if self.pager_index > 0:
582 self.text_ctrl.write(">\x01\x1b[1;36m\x02"+self.pager_lines[self.pager_index]+'\n')
583 else:
584 self.text_ctrl.write("\x01\x1b[1;36m\x02 "+self.pager_lines[self.pager_index]+'\n')
585
586 for line in self.pager_lines[self.pager_index+1:self.pager_index+9]:
587 self.text_ctrl.write("\x01\x1b[1;36m\x02 "+line+'\n')
588 self.pager_index += 10
589 self.pager_nb_lines -= 10
590 self.text_ctrl.write("--- Push Enter to continue or 'Q' to quit---")
591 self.pager_do_remove = True
592 self.pager_state = 'WAITING'
593 return
594 else:
595 #print >>sys.__stdout__,"PAGER processing last lines"
596 if self.pager_nb_lines > 0:
597 if self.pager_index > 0:
598 self.text_ctrl.write(">\x01\x1b[1;36m\x02"+self.pager_lines[self.pager_index]+'\n')
599 else:
600 self.text_ctrl.write("\x01\x1b[1;36m\x02 "+self.pager_lines[self.pager_index]+'\n')
601
602 self.pager_index += 1
569 self.pager_index = 0
570 self.pager_do_remove = False
571 self.text_ctrl.write('\n')
572 self.pager_state = 'PROCESS_LINES'
573
574 if self.pager_state == 'PROCESS_LINES':
575 #print >>sys.__stdout__,"PAGER state:",self.pager_state
576 if self.pager_do_remove == True:
577 self.text_ctrl.removeCurrentLine()
578 self.pager_do_remove = False
579
580 if self.pager_nb_lines > 10:
581 #print >>sys.__stdout__,"PAGER processing 10 lines"
582 if self.pager_index > 0:
583 self.text_ctrl.write(">\x01\x1b[1;36m\x02"+self.pager_lines[self.pager_index]+'\n')
584 else:
585 self.text_ctrl.write("\x01\x1b[1;36m\x02 "+self.pager_lines[self.pager_index]+'\n')
586
587 for line in self.pager_lines[self.pager_index+1:self.pager_index+9]:
588 self.text_ctrl.write("\x01\x1b[1;36m\x02 "+line+'\n')
589 self.pager_index += 10
590 self.pager_nb_lines -= 10
591 self.text_ctrl.write("--- Push Enter to continue or 'Q' to quit---")
592 self.pager_do_remove = True
593 self.pager_state = 'WAITING'
594 return
595 else:
596 #print >>sys.__stdout__,"PAGER processing last lines"
597 if self.pager_nb_lines > 0:
598 if self.pager_index > 0:
599 self.text_ctrl.write(">\x01\x1b[1;36m\x02"+self.pager_lines[self.pager_index]+'\n')
600 else:
601 self.text_ctrl.write("\x01\x1b[1;36m\x02 "+self.pager_lines[self.pager_index]+'\n')
602
603 self.pager_index += 1
603 604 self.pager_nb_lines -= 1
604 605 if self.pager_nb_lines > 0:
605 606 for line in self.pager_lines[self.pager_index:]:
606 607 self.text_ctrl.write("\x01\x1b[1;36m\x02 "+line+'\n')
607 608 self.pager_nb_lines = 0
608 609 self.pager_state = 'DONE'
609 610 self.stateShowPrompt()
610 611
611 612 #------------------------ Key Handler ------------------------------------
612 613 def keyPress(self, event):
613 614 '''
614 615 Key press callback with plenty of shell goodness, like history,
615 616 autocompletions, etc.
616 617 '''
617 618
618 619 if event.GetKeyCode() == ord('C'):
619 620 if event.Modifiers == wx.MOD_CONTROL:
620 621 if self.cur_state == 'WAIT_END_OF_EXECUTION':
621 622 #we raise an exception inside the IPython thread container
622 623 self.IP.ce.raise_exc(KeyboardInterrupt)
623 624 return
624 625
625 626 if event.KeyCode == wx.WXK_RETURN:
626 627 if self.cur_state == 'IDLE':
627 628 #we change the state ot the state machine
628 629 self.setCurrentState('DO_EXECUTE_LINE')
629 630 self.stateDoExecuteLine()
630 631 return
631 632 if self.pager_state == 'WAITING':
632 633 self.pager_state = 'PROCESS_LINES'
633 634 self.pager(self.doc)
634 635 return
635 636
636 637 if self.cur_state == 'WAITING_USER_INPUT':
637 638 line=self.text_ctrl.getCurrentLine()
638 639 self.text_ctrl.write('\n')
639 640 self.setCurrentState('WAIT_END_OF_EXECUTION')
640 641 return
641 642
642 643 if event.GetKeyCode() in [ord('q'),ord('Q')]:
643 644 if self.pager_state == 'WAITING':
644 645 self.pager_state = 'DONE'
646 self.text_ctrl.write('\n')
645 647 self.stateShowPrompt()
646 648 return
647 649
648 650 if self.cur_state == 'WAITING_USER_INPUT':
649 651 event.Skip()
650 652
651 653 if self.cur_state == 'IDLE':
652 654 if event.KeyCode == wx.WXK_UP:
653 655 history = self.IP.historyBack()
654 656 self.text_ctrl.writeHistory(history)
655 657 return
656 658 if event.KeyCode == wx.WXK_DOWN:
657 659 history = self.IP.historyForward()
658 660 self.text_ctrl.writeHistory(history)
659 661 return
660 662 if event.KeyCode == wx.WXK_TAB:
661 663 #if line empty we disable tab completion
662 664 if not self.text_ctrl.getCurrentLine().strip():
663 665 self.text_ctrl.write('\t')
664 666 return
665 667 completed, possibilities = self.IP.complete(self.text_ctrl.getCurrentLine())
666 668 if len(possibilities) > 1:
667 669 cur_slice = self.text_ctrl.getCurrentLine()
668 670 self.text_ctrl.write('\n')
669 671 self.text_ctrl.writeCompletion(possibilities)
670 672 self.text_ctrl.write('\n')
671 673
672 674 self.text_ctrl.showPrompt()
673 675 self.text_ctrl.write(cur_slice)
674 676 self.text_ctrl.changeLine(completed or cur_slice)
675 677
676 678 return
677 679 event.Skip()
678 680
679 681 #------------------------ Hook Section -----------------------------------
680 682 def updateHistoryTracker(self,command_line):
681 683 '''
682 684 Default history tracker (does nothing)
683 685 '''
684 686 pass
685 687
686 688 def setHistoryTrackerHook(self,func):
687 689 '''
688 690 Define a new history tracker
689 691 '''
690 692 self.updateHistoryTracker = func
691 693
692 694 def updateStatusTracker(self,status):
693 695 '''
694 696 Default status tracker (does nothing)
695 697 '''
696 698 pass
697 699
698 700 def setStatusTrackerHook(self,func):
699 701 '''
700 702 Define a new status tracker
701 703 '''
702 704 self.updateStatusTracker = func
703 705
704 706 def askExitHandler(self, event):
705 707 '''
706 708 Default exit handler
707 709 '''
708 710 self.text_ctrl.write('\nExit callback has not been set.')
709 711
710 712 def setAskExitHandler(self, func):
711 713 '''
712 714 Define an exit handler
713 715 '''
714 716 self.askExitHandler = func
715 717
716 718 if __name__ == '__main__':
717 719 # Some simple code to test the shell widget.
718 720 class MainWindow(wx.Frame):
719 721 def __init__(self, parent, id, title):
720 722 wx.Frame.__init__(self, parent, id, title, size=(300,250))
721 723 self._sizer = wx.BoxSizer(wx.VERTICAL)
722 724 self.shell = IPShellWidget(self)
723 725 self._sizer.Add(self.shell, 1, wx.EXPAND)
724 726 self.SetSizer(self._sizer)
725 727 self.SetAutoLayout(1)
726 728 self.Show(True)
727 729
728 730 app = wx.PySimpleApp()
729 731 frame = MainWindow(None, wx.ID_ANY, 'Ipython')
730 732 frame.SetSize((780, 460))
731 733 shell = frame.shell
732 734
733 735 app.MainLoop()
734 736
735 737
@@ -1,4 +1,4 b''
1 1 import os
2 2 def oscmd(c):
3 os.system(c)
3 os.system(c)
4 4 oscmd('sphinx-build -d build/doctrees source build/html') No newline at end of file
General Comments 0
You need to be logged in to leave comments. Login now