]> git.saurik.com Git - wxWidgets.git/blob - wxPython/wx/py/shell.py
Treat Ctrl-Shift-Backspace the same as ESC in the shell.
[wxWidgets.git] / wxPython / wx / py / shell.py
1 """Shell is an interactive text control in which a user types in
2 commands to be sent to the interpreter. This particular shell is
3 based on wxPython's wxStyledTextCtrl.
4
5 Sponsored by Orbtech - Your source for Python programming expertise."""
6
7 __author__ = "Patrick K. O'Brien <pobrien@orbtech.com>"
8 __cvsid__ = "$Id$"
9 __revision__ = "$Revision$"[11:-2]
10
11 import wx
12 from wx import stc
13
14 import keyword
15 import os
16 import sys
17 import time
18
19 from buffer import Buffer
20 import dispatcher
21 import editwindow
22 import frame
23 from pseudo import PseudoFileIn
24 from pseudo import PseudoFileOut
25 from pseudo import PseudoFileErr
26 from version import VERSION
27
28 sys.ps3 = '<-- ' # Input prompt.
29
30 NAVKEYS = (wx.WXK_END, wx.WXK_LEFT, wx.WXK_RIGHT,
31 wx.WXK_UP, wx.WXK_DOWN, wx.WXK_PRIOR, wx.WXK_NEXT)
32
33
34 class ShellFrame(frame.Frame, frame.ShellFrameMixin):
35 """Frame containing the shell component."""
36
37 name = 'Shell Frame'
38 revision = __revision__
39
40 def __init__(self, parent=None, id=-1, title='PyShell',
41 pos=wx.DefaultPosition, size=wx.DefaultSize,
42 style=wx.DEFAULT_FRAME_STYLE, locals=None,
43 InterpClass=None,
44 config=None, dataDir=None,
45 *args, **kwds):
46 """Create ShellFrame instance."""
47 frame.Frame.__init__(self, parent, id, title, pos, size, style)
48 frame.ShellFrameMixin.__init__(self, config, dataDir)
49
50 if size == wx.DefaultSize:
51 self.SetSize((750, 525))
52
53 intro = 'PyShell %s - The Flakiest Python Shell' % VERSION
54 self.SetStatusText(intro.replace('\n', ', '))
55 self.shell = Shell(parent=self, id=-1, introText=intro,
56 locals=locals, InterpClass=InterpClass,
57 startupScript=self.startupScript,
58 execStartupScript=self.execStartupScript,
59 *args, **kwds)
60
61 # Override the shell so that status messages go to the status bar.
62 self.shell.setStatusText = self.SetStatusText
63
64 self.shell.SetFocus()
65 self.LoadSettings()
66
67
68 def OnClose(self, event):
69 """Event handler for closing."""
70 # This isn't working the way I want, but I'll leave it for now.
71 if self.shell.waiting:
72 if event.CanVeto():
73 event.Veto(True)
74 else:
75 self.SaveSettings()
76 self.shell.destroy()
77 self.Destroy()
78
79 def OnAbout(self, event):
80 """Display an About window."""
81 title = 'About PyShell'
82 text = 'PyShell %s\n\n' % VERSION + \
83 'Yet another Python shell, only flakier.\n\n' + \
84 'Half-baked by Patrick K. O\'Brien,\n' + \
85 'the other half is still in the oven.\n\n' + \
86 'Shell Revision: %s\n' % self.shell.revision + \
87 'Interpreter Revision: %s\n\n' % self.shell.interp.revision + \
88 'Platform: %s\n' % sys.platform + \
89 'Python Version: %s\n' % sys.version.split()[0] + \
90 'wxPython Version: %s\n' % wx.VERSION_STRING + \
91 ('\t(%s)\n' % ", ".join(wx.PlatformInfo[1:]))
92 dialog = wx.MessageDialog(self, text, title,
93 wx.OK | wx.ICON_INFORMATION)
94 dialog.ShowModal()
95 dialog.Destroy()
96
97
98 def OnHelp(self, event):
99 """Show a help dialog."""
100 frame.ShellFrameMixin.OnHelp(self, event)
101
102
103 def LoadSettings(self):
104 if self.config is not None:
105 frame.ShellFrameMixin.LoadSettings(self)
106 frame.Frame.LoadSettings(self, self.config)
107 self.shell.LoadSettings(self.config)
108
109 def SaveSettings(self, force=False):
110 if self.config is not None:
111 frame.ShellFrameMixin.SaveSettings(self)
112 if self.autoSaveSettings or force:
113 frame.Frame.SaveSettings(self, self.config)
114 self.shell.SaveSettings(self.config)
115
116 def DoSaveSettings(self):
117 if self.config is not None:
118 self.SaveSettings(force=True)
119 self.config.Flush()
120
121
122
123
124 HELP_TEXT = """\
125 * Key bindings:
126 Home Go to the beginning of the command or line.
127 Shift+Home Select to the beginning of the command or line.
128 Shift+End Select to the end of the line.
129 End Go to the end of the line.
130 Ctrl+C Copy selected text, removing prompts.
131 Ctrl+Shift+C Copy selected text, retaining prompts.
132 Alt+C Copy to the clipboard, including prefixed prompts.
133 Ctrl+X Cut selected text.
134 Ctrl+V Paste from clipboard.
135 Ctrl+Shift+V Paste and run multiple commands from clipboard.
136 Ctrl+Up Arrow Retrieve Previous History item.
137 Alt+P Retrieve Previous History item.
138 Ctrl+Down Arrow Retrieve Next History item.
139 Alt+N Retrieve Next History item.
140 Shift+Up Arrow Insert Previous History item.
141 Shift+Down Arrow Insert Next History item.
142 F8 Command-completion of History item.
143 (Type a few characters of a previous command and press F8.)
144 Ctrl+Enter Insert new line into multiline command.
145 Ctrl+] Increase font size.
146 Ctrl+[ Decrease font size.
147 Ctrl+= Default font size.
148 Ctrl-Space Show Auto Completion.
149 Ctrl-Alt-Space Show Call Tip.
150 Alt+Shift+C Clear Screen.
151 Shift+Enter Complete Text from History.
152 Ctrl+F Search (backwards) TODO: regexp-wholeWords-...
153 Ctrl+G Search next
154 Ctrl+H "hide" lines containing selection / "unhide"
155 F12 on/off "free-edit" mode
156 """
157
158 class ShellFacade:
159 """Simplified interface to all shell-related functionality.
160
161 This is a semi-transparent facade, in that all attributes of other
162 are accessible, even though only some are visible to the user."""
163
164 name = 'Shell Interface'
165 revision = __revision__
166
167 def __init__(self, other):
168 """Create a ShellFacade instance."""
169 d = self.__dict__
170 d['other'] = other
171 d['helpText'] = HELP_TEXT
172
173 def help(self):
174 """Display some useful information about how to use the shell."""
175 self.write(self.helpText)
176
177 def __getattr__(self, name):
178 if hasattr(self.other, name):
179 return getattr(self.other, name)
180 else:
181 raise AttributeError, name
182
183 def __setattr__(self, name, value):
184 if self.__dict__.has_key(name):
185 self.__dict__[name] = value
186 elif hasattr(self.other, name):
187 setattr(self.other, name, value)
188 else:
189 raise AttributeError, name
190
191 def _getAttributeNames(self):
192 """Return list of magic attributes to extend introspection."""
193 list = [
194 'about',
195 'ask',
196 'autoCallTip',
197 'autoComplete',
198 'autoCompleteAutoHide',
199 'autoCompleteCaseInsensitive',
200 'autoCompleteIncludeDouble',
201 'autoCompleteIncludeMagic',
202 'autoCompleteIncludeSingle',
203 'callTipInsert',
204 'clear',
205 'pause',
206 'prompt',
207 'quit',
208 'redirectStderr',
209 'redirectStdin',
210 'redirectStdout',
211 'run',
212 'runfile',
213 'wrap',
214 'zoom',
215 ]
216 list.sort()
217 return list
218
219
220
221 class Shell(editwindow.EditWindow):
222 """Shell based on StyledTextCtrl."""
223
224 name = 'Shell'
225 revision = __revision__
226
227 def __init__(self, parent, id=-1, pos=wx.DefaultPosition,
228 size=wx.DefaultSize, style=wx.CLIP_CHILDREN,
229 introText='', locals=None, InterpClass=None,
230 startupScript=None, execStartupScript=True,
231 *args, **kwds):
232 """Create Shell instance."""
233 editwindow.EditWindow.__init__(self, parent, id, pos, size, style)
234 self.wrap()
235 if locals is None:
236 import __main__
237 locals = __main__.__dict__
238
239 # Grab these so they can be restored by self.redirect* methods.
240 self.stdin = sys.stdin
241 self.stdout = sys.stdout
242 self.stderr = sys.stderr
243
244 # Import a default interpreter class if one isn't provided.
245 if InterpClass == None:
246 from interpreter import Interpreter
247 else:
248 Interpreter = InterpClass
249
250 # Create a replacement for stdin.
251 self.reader = PseudoFileIn(self.readline, self.readlines)
252 self.reader.input = ''
253 self.reader.isreading = False
254
255 # Set up the interpreter.
256 self.interp = Interpreter(locals=locals,
257 rawin=self.raw_input,
258 stdin=self.reader,
259 stdout=PseudoFileOut(self.writeOut),
260 stderr=PseudoFileErr(self.writeErr),
261 *args, **kwds)
262
263 # Set up the buffer.
264 self.buffer = Buffer()
265
266 # Find out for which keycodes the interpreter will autocomplete.
267 self.autoCompleteKeys = self.interp.getAutoCompleteKeys()
268
269 # Keep track of the last non-continuation prompt positions.
270 self.promptPosStart = 0
271 self.promptPosEnd = 0
272
273 # Keep track of multi-line commands.
274 self.more = False
275
276 # Create the command history. Commands are added into the
277 # front of the list (ie. at index 0) as they are entered.
278 # self.historyIndex is the current position in the history; it
279 # gets incremented as you retrieve the previous command,
280 # decremented as you retrieve the next, and reset when you hit
281 # Enter. self.historyIndex == -1 means you're on the current
282 # command, not in the history.
283 self.history = []
284 self.historyIndex = -1
285
286 #seb add mode for "free edit"
287 self.noteMode = 0
288 self.MarkerDefine(0,stc.STC_MARK_ROUNDRECT) # marker for hidden
289 self.searchTxt = ""
290
291 # Assign handlers for keyboard events.
292 self.Bind(wx.EVT_CHAR, self.OnChar)
293 self.Bind(wx.EVT_KEY_DOWN, self.OnKeyDown)
294
295 # Assign handler for idle time.
296 self.waiting = False
297 self.Bind(wx.EVT_IDLE, self.OnIdle)
298
299 # Display the introductory banner information.
300 self.showIntro(introText)
301
302 # Assign some pseudo keywords to the interpreter's namespace.
303 self.setBuiltinKeywords()
304
305 # Add 'shell' to the interpreter's local namespace.
306 self.setLocalShell()
307
308 ## NOTE: See note at bottom of this file...
309 ## #seb: File drag and drop
310 ## self.SetDropTarget( FileDropTarget(self) )
311
312 # Do this last so the user has complete control over their
313 # environment. They can override anything they want.
314 if execStartupScript:
315 if startupScript is None:
316 startupScript = os.environ.get('PYTHONSTARTUP')
317 self.execStartupScript(startupScript)
318 else:
319 self.prompt()
320
321 wx.CallAfter(self.ScrollToLine, 0)
322
323
324
325 def destroy(self):
326 del self.interp
327
328 def setFocus(self):
329 """Set focus to the shell."""
330 self.SetFocus()
331
332 def OnIdle(self, event):
333 """Free the CPU to do other things."""
334 if self.waiting:
335 time.sleep(0.05)
336 event.Skip()
337
338 def showIntro(self, text=''):
339 """Display introductory text in the shell."""
340 if text:
341 if not text.endswith(os.linesep):
342 text += os.linesep
343 self.write(text)
344 try:
345 self.write(self.interp.introText)
346 except AttributeError:
347 pass
348
349 def setBuiltinKeywords(self):
350 """Create pseudo keywords as part of builtins.
351
352 This sets `close`, `exit` and `quit` to a helpful string.
353 """
354 import __builtin__
355 __builtin__.close = __builtin__.exit = __builtin__.quit = \
356 'Click on the close button to leave the application.'
357
358
359 def quit(self):
360 """Quit the application."""
361 # XXX Good enough for now but later we want to send a close event.
362 # In the close event handler we can make sure they want to
363 # quit. Other applications, like PythonCard, may choose to
364 # hide rather than quit so we should just post the event and
365 # let the surrounding app decide what it wants to do.
366 self.write('Click on the close button to leave the application.')
367
368
369 def setLocalShell(self):
370 """Add 'shell' to locals as reference to ShellFacade instance."""
371 self.interp.locals['shell'] = ShellFacade(other=self)
372
373
374 def execStartupScript(self, startupScript):
375 """Execute the user's PYTHONSTARTUP script if they have one."""
376 if startupScript and os.path.isfile(startupScript):
377 text = 'Startup script executed: ' + startupScript
378 self.push('print %r; execfile(%r)' % (text, startupScript))
379 self.interp.startupScript = startupScript
380 else:
381 self.push('')
382
383
384 def about(self):
385 """Display information about Py."""
386 text = """
387 Author: %r
388 Py Version: %s
389 Py Shell Revision: %s
390 Py Interpreter Revision: %s
391 Python Version: %s
392 wxPython Version: %s
393 wxPython PlatformInfo: %s
394 Platform: %s""" % \
395 (__author__, VERSION, self.revision, self.interp.revision,
396 sys.version.split()[0], wx.VERSION_STRING, str(wx.PlatformInfo),
397 sys.platform)
398 self.write(text.strip())
399
400
401 def OnChar(self, event):
402 """Keypress event handler.
403
404 Only receives an event if OnKeyDown calls event.Skip() for the
405 corresponding event."""
406
407 if self.noteMode:
408 event.Skip()
409 return
410
411 # Prevent modification of previously submitted
412 # commands/responses.
413 if not self.CanEdit():
414 return
415 key = event.KeyCode()
416 currpos = self.GetCurrentPos()
417 stoppos = self.promptPosEnd
418 # Return (Enter) needs to be ignored in this handler.
419 if key == wx.WXK_RETURN:
420 pass
421 elif key in self.autoCompleteKeys:
422 # Usually the dot (period) key activates auto completion.
423 # Get the command between the prompt and the cursor. Add
424 # the autocomplete character to the end of the command.
425 if self.AutoCompActive():
426 self.AutoCompCancel()
427 command = self.GetTextRange(stoppos, currpos) + chr(key)
428 self.write(chr(key))
429 if self.autoComplete:
430 self.autoCompleteShow(command)
431 elif key == ord('('):
432 # The left paren activates a call tip and cancels an
433 # active auto completion.
434 if self.AutoCompActive():
435 self.AutoCompCancel()
436 # Get the command between the prompt and the cursor. Add
437 # the '(' to the end of the command.
438 self.ReplaceSelection('')
439 command = self.GetTextRange(stoppos, currpos) + '('
440 self.write('(')
441 self.autoCallTipShow(command, self.GetCurrentPos() == self.GetTextLength())
442 else:
443 # Allow the normal event handling to take place.
444 event.Skip()
445
446
447 def OnKeyDown(self, event):
448 """Key down event handler."""
449
450 key = event.KeyCode()
451 # If the auto-complete window is up let it do its thing.
452 if self.AutoCompActive():
453 event.Skip()
454 return
455
456 # Prevent modification of previously submitted
457 # commands/responses.
458 controlDown = event.ControlDown()
459 altDown = event.AltDown()
460 shiftDown = event.ShiftDown()
461 currpos = self.GetCurrentPos()
462 endpos = self.GetTextLength()
463 selecting = self.GetSelectionStart() != self.GetSelectionEnd()
464
465 if controlDown and shiftDown and key in (ord('F'), ord('f')):
466 li = self.GetCurrentLine()
467 m = self.MarkerGet(li)
468 if m & 1<<0:
469 startP = self.PositionFromLine(li)
470 self.MarkerDelete(li, 0)
471 maxli = self.GetLineCount()
472 li += 1 # li stayed visible as header-line
473 li0 = li
474 while li<maxli and self.GetLineVisible(li) == 0:
475 li += 1
476 endP = self.GetLineEndPosition(li-1)
477 self.ShowLines(li0, li-1)
478 self.SetSelection( startP, endP ) # select reappearing text to allow "hide again"
479 return
480 startP,endP = self.GetSelection()
481 endP-=1
482 startL,endL = self.LineFromPosition(startP), self.LineFromPosition(endP)
483
484 if endL == self.LineFromPosition(self.promptPosEnd): # never hide last prompt
485 endL -= 1
486
487 m = self.MarkerGet(startL)
488 self.MarkerAdd(startL, 0)
489 self.HideLines(startL+1,endL)
490 self.SetCurrentPos( startP ) # to ensure caret stays visible !
491
492 if key == wx.WXK_F12: #seb
493 if self.noteMode:
494 # self.promptPosStart not used anyway - or ?
495 self.promptPosEnd = self.PositionFromLine( self.GetLineCount()-1 ) + len(str(sys.ps1))
496 self.GotoLine(self.GetLineCount())
497 self.GotoPos(self.promptPosEnd)
498 self.prompt() #make sure we have a prompt
499 self.SetCaretForeground("black")
500 self.SetCaretWidth(1) #default
501 self.SetCaretPeriod(500) #default
502 else:
503 self.SetCaretForeground("red")
504 self.SetCaretWidth(4)
505 self.SetCaretPeriod(0) #steady
506
507 self.noteMode = not self.noteMode
508 return
509 if self.noteMode:
510 event.Skip()
511 return
512
513 # Return (Enter) is used to submit a command to the
514 # interpreter.
515 if (not controlDown and not shiftDown and not altDown) and key == wx.WXK_RETURN:
516 if self.CallTipActive():
517 self.CallTipCancel()
518 self.processLine()
519
520 # Complete Text (from already typed words)
521 elif shiftDown and key == wx.WXK_RETURN:
522 self.OnShowCompHistory()
523
524 # Ctrl+Return (Ctrl+Enter) is used to insert a line break.
525 elif controlDown and key == wx.WXK_RETURN:
526 if self.CallTipActive():
527 self.CallTipCancel()
528 if currpos == endpos:
529 self.processLine()
530 else:
531 self.insertLineBreak()
532
533 # Let Ctrl-Alt-* get handled normally.
534 elif controlDown and altDown:
535 event.Skip()
536
537 # Clear the current, unexecuted command.
538 elif key == wx.WXK_ESCAPE:
539 if self.CallTipActive():
540 event.Skip()
541 else:
542 self.clearCommand()
543
544 # Clear the current command
545 elif key == wx.WXK_BACK and controlDown and shiftDown:
546 self.clearCommand()
547
548 # Increase font size.
549 elif controlDown and key in (ord(']'), wx.WXK_NUMPAD_ADD):
550 dispatcher.send(signal='FontIncrease')
551
552 # Decrease font size.
553 elif controlDown and key in (ord('['), wx.WXK_NUMPAD_SUBTRACT):
554 dispatcher.send(signal='FontDecrease')
555
556 # Default font size.
557 elif controlDown and key in (ord('='), wx.WXK_NUMPAD_DIVIDE):
558 dispatcher.send(signal='FontDefault')
559
560 # Cut to the clipboard.
561 elif (controlDown and key in (ord('X'), ord('x'))) \
562 or (shiftDown and key == wx.WXK_DELETE):
563 self.Cut()
564
565 # Copy to the clipboard.
566 elif controlDown and not shiftDown \
567 and key in (ord('C'), ord('c'), wx.WXK_INSERT):
568 self.Copy()
569
570 # Copy to the clipboard, including prompts.
571 elif controlDown and shiftDown \
572 and key in (ord('C'), ord('c'), wx.WXK_INSERT):
573 self.CopyWithPrompts()
574
575 # Copy to the clipboard, including prefixed prompts.
576 elif altDown and not controlDown \
577 and key in (ord('C'), ord('c'), wx.WXK_INSERT):
578 self.CopyWithPromptsPrefixed()
579
580 # Home needs to be aware of the prompt.
581 elif key == wx.WXK_HOME:
582 home = self.promptPosEnd
583 if currpos > home:
584 self.SetCurrentPos(home)
585 if not selecting and not shiftDown:
586 self.SetAnchor(home)
587 self.EnsureCaretVisible()
588 else:
589 event.Skip()
590
591 #
592 # The following handlers modify text, so we need to see if
593 # there is a selection that includes text prior to the prompt.
594 #
595 # Don't modify a selection with text prior to the prompt.
596 elif selecting and key not in NAVKEYS and not self.CanEdit():
597 pass
598
599 # Paste from the clipboard.
600 elif (controlDown and not shiftDown and key in (ord('V'), ord('v'))) \
601 or (shiftDown and not controlDown and key == wx.WXK_INSERT):
602 self.Paste()
603
604 # manually invoke AutoComplete and Calltips
605 elif controlDown and key == wx.WXK_SPACE:
606 self.OnCallTipAutoCompleteManually(shiftDown)
607
608 # Paste from the clipboard, run commands.
609 elif controlDown and shiftDown and key in (ord('V'), ord('v')):
610 self.PasteAndRun()
611
612 # Replace with the previous command from the history buffer.
613 elif (controlDown and key == wx.WXK_UP) \
614 or (altDown and key in (ord('P'), ord('p'))):
615 self.OnHistoryReplace(step=+1)
616
617 # Replace with the next command from the history buffer.
618 elif (controlDown and key == wx.WXK_DOWN) \
619 or (altDown and key in (ord('N'), ord('n'))):
620 self.OnHistoryReplace(step=-1)
621
622 # Insert the previous command from the history buffer.
623 elif (shiftDown and key == wx.WXK_UP) and self.CanEdit():
624 self.OnHistoryInsert(step=+1)
625
626 # Insert the next command from the history buffer.
627 elif (shiftDown and key == wx.WXK_DOWN) and self.CanEdit():
628 self.OnHistoryInsert(step=-1)
629
630 # Search up the history for the text in front of the cursor.
631 elif key == wx.WXK_F8:
632 self.OnHistorySearch()
633
634 # Don't backspace over the latest non-continuation prompt.
635 elif key == wx.WXK_BACK:
636 if selecting and self.CanEdit():
637 event.Skip()
638 elif currpos > self.promptPosEnd:
639 event.Skip()
640
641 # Only allow these keys after the latest prompt.
642 elif key in (wx.WXK_TAB, wx.WXK_DELETE):
643 if self.CanEdit():
644 event.Skip()
645
646 # Don't toggle between insert mode and overwrite mode.
647 elif key == wx.WXK_INSERT:
648 pass
649
650 # Don't allow line deletion.
651 elif controlDown and key in (ord('L'), ord('l')):
652 pass
653
654 # Don't allow line transposition.
655 elif controlDown and key in (ord('T'), ord('t')):
656 pass
657
658 # Basic navigation keys should work anywhere.
659 elif key in NAVKEYS:
660 event.Skip()
661
662 # Protect the readonly portion of the shell.
663 elif not self.CanEdit():
664 pass
665
666 else:
667 event.Skip()
668
669
670 def OnShowCompHistory(self):
671 """Show possible autocompletion Words from already typed words."""
672
673 #copy from history
674 his = self.history[:]
675
676 #put together in one string
677 joined = " ".join (his)
678 import re
679
680 #sort out only "good" words
681 newlist = re.split("[ \.\[\]=}(\)\,0-9\"]", joined)
682
683 #length > 1 (mix out "trash")
684 thlist = []
685 for i in newlist:
686 if len (i) > 1:
687 thlist.append (i)
688
689 #unique (no duplicate words
690 #oneliner from german python forum => unique list
691 unlist = [thlist[i] for i in xrange(len(thlist)) if thlist[i] not in thlist[:i]]
692
693 #sort lowercase
694 unlist.sort(lambda a, b: cmp(a.lower(), b.lower()))
695
696 #this is more convenient, isn't it?
697 self.AutoCompSetIgnoreCase(True)
698
699 #join again together in a string
700 stringlist = " ".join(unlist)
701
702 #pos von 0 noch ausrechnen
703
704 #how big is the offset?
705 cpos = self.GetCurrentPos() - 1
706 while chr (self.GetCharAt (cpos)).isalnum():
707 cpos -= 1
708
709 #the most important part
710 self.AutoCompShow(self.GetCurrentPos() - cpos -1, stringlist)
711
712
713 def clearCommand(self):
714 """Delete the current, unexecuted command."""
715 startpos = self.promptPosEnd
716 endpos = self.GetTextLength()
717 self.SetSelection(startpos, endpos)
718 self.ReplaceSelection('')
719 self.more = False
720
721 def OnHistoryReplace(self, step):
722 """Replace with the previous/next command from the history buffer."""
723 self.clearCommand()
724 self.replaceFromHistory(step)
725
726 def replaceFromHistory(self, step):
727 """Replace selection with command from the history buffer."""
728 ps2 = str(sys.ps2)
729 self.ReplaceSelection('')
730 newindex = self.historyIndex + step
731 if -1 <= newindex <= len(self.history):
732 self.historyIndex = newindex
733 if 0 <= newindex <= len(self.history)-1:
734 command = self.history[self.historyIndex]
735 command = command.replace('\n', os.linesep + ps2)
736 self.ReplaceSelection(command)
737
738 def OnHistoryInsert(self, step):
739 """Insert the previous/next command from the history buffer."""
740 if not self.CanEdit():
741 return
742 startpos = self.GetCurrentPos()
743 self.replaceFromHistory(step)
744 endpos = self.GetCurrentPos()
745 self.SetSelection(endpos, startpos)
746
747 def OnHistorySearch(self):
748 """Search up the history buffer for the text in front of the cursor."""
749 if not self.CanEdit():
750 return
751 startpos = self.GetCurrentPos()
752 # The text up to the cursor is what we search for.
753 numCharsAfterCursor = self.GetTextLength() - startpos
754 searchText = self.getCommand(rstrip=False)
755 if numCharsAfterCursor > 0:
756 searchText = searchText[:-numCharsAfterCursor]
757 if not searchText:
758 return
759 # Search upwards from the current history position and loop
760 # back to the beginning if we don't find anything.
761 if (self.historyIndex <= -1) \
762 or (self.historyIndex >= len(self.history)-2):
763 searchOrder = range(len(self.history))
764 else:
765 searchOrder = range(self.historyIndex+1, len(self.history)) + \
766 range(self.historyIndex)
767 for i in searchOrder:
768 command = self.history[i]
769 if command[:len(searchText)] == searchText:
770 # Replace the current selection with the one we found.
771 self.ReplaceSelection(command[len(searchText):])
772 endpos = self.GetCurrentPos()
773 self.SetSelection(endpos, startpos)
774 # We've now warped into middle of the history.
775 self.historyIndex = i
776 break
777
778 def setStatusText(self, text):
779 """Display status information."""
780
781 # This method will likely be replaced by the enclosing app to
782 # do something more interesting, like write to a status bar.
783 print text
784
785 def insertLineBreak(self):
786 """Insert a new line break."""
787 if self.CanEdit():
788 self.write(os.linesep)
789 self.more = True
790 self.prompt()
791
792 def processLine(self):
793 """Process the line of text at which the user hit Enter."""
794
795 # The user hit ENTER and we need to decide what to do. They
796 # could be sitting on any line in the shell.
797
798 thepos = self.GetCurrentPos()
799 startpos = self.promptPosEnd
800 endpos = self.GetTextLength()
801 ps2 = str(sys.ps2)
802 # If they hit RETURN inside the current command, execute the
803 # command.
804 if self.CanEdit():
805 self.SetCurrentPos(endpos)
806 self.interp.more = False
807 command = self.GetTextRange(startpos, endpos)
808 lines = command.split(os.linesep + ps2)
809 lines = [line.rstrip() for line in lines]
810 command = '\n'.join(lines)
811 if self.reader.isreading:
812 if not command:
813 # Match the behavior of the standard Python shell
814 # when the user hits return without entering a
815 # value.
816 command = '\n'
817 self.reader.input = command
818 self.write(os.linesep)
819 else:
820 self.push(command)
821 wx.FutureCall(1, self.EnsureCaretVisible)
822 # Or replace the current command with the other command.
823 else:
824 # If the line contains a command (even an invalid one).
825 if self.getCommand(rstrip=False):
826 command = self.getMultilineCommand()
827 self.clearCommand()
828 self.write(command)
829 # Otherwise, put the cursor back where we started.
830 else:
831 self.SetCurrentPos(thepos)
832 self.SetAnchor(thepos)
833
834 def getMultilineCommand(self, rstrip=True):
835 """Extract a multi-line command from the editor.
836
837 The command may not necessarily be valid Python syntax."""
838 # XXX Need to extract real prompts here. Need to keep track of
839 # the prompt every time a command is issued.
840 ps1 = str(sys.ps1)
841 ps1size = len(ps1)
842 ps2 = str(sys.ps2)
843 ps2size = len(ps2)
844 # This is a total hack job, but it works.
845 text = self.GetCurLine()[0]
846 line = self.GetCurrentLine()
847 while text[:ps2size] == ps2 and line > 0:
848 line -= 1
849 self.GotoLine(line)
850 text = self.GetCurLine()[0]
851 if text[:ps1size] == ps1:
852 line = self.GetCurrentLine()
853 self.GotoLine(line)
854 startpos = self.GetCurrentPos() + ps1size
855 line += 1
856 self.GotoLine(line)
857 while self.GetCurLine()[0][:ps2size] == ps2:
858 line += 1
859 self.GotoLine(line)
860 stoppos = self.GetCurrentPos()
861 command = self.GetTextRange(startpos, stoppos)
862 command = command.replace(os.linesep + ps2, '\n')
863 command = command.rstrip()
864 command = command.replace('\n', os.linesep + ps2)
865 else:
866 command = ''
867 if rstrip:
868 command = command.rstrip()
869 return command
870
871 def getCommand(self, text=None, rstrip=True):
872 """Extract a command from text which may include a shell prompt.
873
874 The command may not necessarily be valid Python syntax."""
875 if not text:
876 text = self.GetCurLine()[0]
877 # Strip the prompt off the front leaving just the command.
878 command = self.lstripPrompt(text)
879 if command == text:
880 command = '' # Real commands have prompts.
881 if rstrip:
882 command = command.rstrip()
883 return command
884
885 def lstripPrompt(self, text):
886 """Return text without a leading prompt."""
887 ps1 = str(sys.ps1)
888 ps1size = len(ps1)
889 ps2 = str(sys.ps2)
890 ps2size = len(ps2)
891 # Strip the prompt off the front of text.
892 if text[:ps1size] == ps1:
893 text = text[ps1size:]
894 elif text[:ps2size] == ps2:
895 text = text[ps2size:]
896 return text
897
898 def push(self, command, silent = False):
899 """Send command to the interpreter for execution."""
900 if not silent:
901 self.write(os.linesep)
902 busy = wx.BusyCursor()
903 self.waiting = True
904 self.more = self.interp.push(command)
905 self.waiting = False
906 del busy
907 if not self.more:
908 self.addHistory(command.rstrip())
909 if not silent:
910 self.prompt()
911
912 def addHistory(self, command):
913 """Add command to the command history."""
914 # Reset the history position.
915 self.historyIndex = -1
916 # Insert this command into the history, unless it's a blank
917 # line or the same as the last command.
918 if command != '' \
919 and (len(self.history) == 0 or command != self.history[0]):
920 self.history.insert(0, command)
921
922 def write(self, text):
923 """Display text in the shell.
924
925 Replace line endings with OS-specific endings."""
926 text = self.fixLineEndings(text)
927 self.AddText(text)
928 self.EnsureCaretVisible()
929
930 def fixLineEndings(self, text):
931 """Return text with line endings replaced by OS-specific endings."""
932 lines = text.split('\r\n')
933 for l in range(len(lines)):
934 chunks = lines[l].split('\r')
935 for c in range(len(chunks)):
936 chunks[c] = os.linesep.join(chunks[c].split('\n'))
937 lines[l] = os.linesep.join(chunks)
938 text = os.linesep.join(lines)
939 return text
940
941 def prompt(self):
942 """Display proper prompt for the context: ps1, ps2 or ps3.
943
944 If this is a continuation line, autoindent as necessary."""
945 isreading = self.reader.isreading
946 skip = False
947 if isreading:
948 prompt = str(sys.ps3)
949 elif self.more:
950 prompt = str(sys.ps2)
951 else:
952 prompt = str(sys.ps1)
953 pos = self.GetCurLine()[1]
954 if pos > 0:
955 if isreading:
956 skip = True
957 else:
958 self.write(os.linesep)
959 if not self.more:
960 self.promptPosStart = self.GetCurrentPos()
961 if not skip:
962 self.write(prompt)
963 if not self.more:
964 self.promptPosEnd = self.GetCurrentPos()
965 # Keep the undo feature from undoing previous responses.
966 self.EmptyUndoBuffer()
967 # XXX Add some autoindent magic here if more.
968 if self.more:
969 self.write(' '*4) # Temporary hack indentation.
970 self.EnsureCaretVisible()
971 self.ScrollToColumn(0)
972
973 def readline(self):
974 """Replacement for stdin.readline()."""
975 input = ''
976 reader = self.reader
977 reader.isreading = True
978 self.prompt()
979 try:
980 while not reader.input:
981 wx.YieldIfNeeded()
982 input = reader.input
983 finally:
984 reader.input = ''
985 reader.isreading = False
986 input = str(input) # In case of Unicode.
987 return input
988
989 def readlines(self):
990 """Replacement for stdin.readlines()."""
991 lines = []
992 while lines[-1:] != ['\n']:
993 lines.append(self.readline())
994 return lines
995
996 def raw_input(self, prompt=''):
997 """Return string based on user input."""
998 if prompt:
999 self.write(prompt)
1000 return self.readline()
1001
1002 def ask(self, prompt='Please enter your response:'):
1003 """Get response from the user using a dialog box."""
1004 dialog = wx.TextEntryDialog(None, prompt,
1005 'Input Dialog (Raw)', '')
1006 try:
1007 if dialog.ShowModal() == wx.ID_OK:
1008 text = dialog.GetValue()
1009 return text
1010 finally:
1011 dialog.Destroy()
1012 return ''
1013
1014 def pause(self):
1015 """Halt execution pending a response from the user."""
1016 self.ask('Press enter to continue:')
1017
1018 def clear(self):
1019 """Delete all text from the shell."""
1020 self.ClearAll()
1021
1022 def run(self, command, prompt=True, verbose=True):
1023 """Execute command as if it was typed in directly.
1024 >>> shell.run('print "this"')
1025 >>> print "this"
1026 this
1027 >>>
1028 """
1029 # Go to the very bottom of the text.
1030 endpos = self.GetTextLength()
1031 self.SetCurrentPos(endpos)
1032 command = command.rstrip()
1033 if prompt: self.prompt()
1034 if verbose: self.write(command)
1035 self.push(command)
1036
1037 def runfile(self, filename):
1038 """Execute all commands in file as if they were typed into the
1039 shell."""
1040 file = open(filename)
1041 try:
1042 self.prompt()
1043 for command in file.readlines():
1044 if command[:6] == 'shell.':
1045 # Run shell methods silently.
1046 self.run(command, prompt=False, verbose=False)
1047 else:
1048 self.run(command, prompt=False, verbose=True)
1049 finally:
1050 file.close()
1051
1052 def autoCompleteShow(self, command, offset = 0):
1053 """Display auto-completion popup list."""
1054 self.AutoCompSetAutoHide(self.autoCompleteAutoHide)
1055 self.AutoCompSetIgnoreCase(self.autoCompleteCaseInsensitive)
1056 list = self.interp.getAutoCompleteList(command,
1057 includeMagic=self.autoCompleteIncludeMagic,
1058 includeSingle=self.autoCompleteIncludeSingle,
1059 includeDouble=self.autoCompleteIncludeDouble)
1060 if list:
1061 options = ' '.join(list)
1062 #offset = 0
1063 self.AutoCompShow(offset, options)
1064
1065 def autoCallTipShow(self, command, insertcalltip = True, forceCallTip = False):
1066 """Display argument spec and docstring in a popup window."""
1067 if self.CallTipActive():
1068 self.CallTipCancel()
1069 (name, argspec, tip) = self.interp.getCallTip(command)
1070 if tip:
1071 dispatcher.send(signal='Shell.calltip', sender=self, calltip=tip)
1072 if not self.autoCallTip and not forceCallTip:
1073 return
1074 if argspec and insertcalltip and self.callTipInsert:
1075 startpos = self.GetCurrentPos()
1076 self.write(argspec + ')')
1077 endpos = self.GetCurrentPos()
1078 self.SetSelection(endpos, startpos)
1079 if tip:
1080 curpos = self.GetCurrentPos()
1081 tippos = curpos - (len(name) + 1)
1082 fallback = curpos - self.GetColumn(curpos)
1083 # In case there isn't enough room, only go back to the
1084 # fallback.
1085 tippos = max(tippos, fallback)
1086 self.CallTipShow(tippos, tip)
1087
1088 def OnCallTipAutoCompleteManually (self, shiftDown):
1089 """AutoComplete and Calltips manually."""
1090 if self.AutoCompActive():
1091 self.AutoCompCancel()
1092 currpos = self.GetCurrentPos()
1093 stoppos = self.promptPosEnd
1094
1095 cpos = currpos
1096 #go back until '.' is found
1097 pointavailpos = -1
1098 while cpos >= stoppos:
1099 if self.GetCharAt(cpos) == ord ('.'):
1100 pointavailpos = cpos
1101 break
1102 cpos -= 1
1103
1104 #word from non whitespace until '.'
1105 if pointavailpos != -1:
1106 #look backward for first whitespace char
1107 textbehind = self.GetTextRange (pointavailpos + 1, currpos)
1108 pointavailpos += 1
1109
1110 if not shiftDown:
1111 #call AutoComplete
1112 stoppos = self.promptPosEnd
1113 textbefore = self.GetTextRange(stoppos, pointavailpos)
1114 self.autoCompleteShow(textbefore, len (textbehind))
1115 else:
1116 #call CallTips
1117 cpos = pointavailpos
1118 begpos = -1
1119 while cpos > stoppos:
1120 if chr(self.GetCharAt(cpos)).isspace():
1121 begpos = cpos
1122 break
1123 cpos -= 1
1124 if begpos == -1:
1125 begpos = cpos
1126 ctips = self.GetTextRange (begpos, currpos)
1127 ctindex = ctips.find ('(')
1128 if ctindex != -1 and not self.CallTipActive():
1129 #insert calltip, if current pos is '(', otherwise show it only
1130 self.autoCallTipShow(ctips[:ctindex + 1],
1131 self.GetCharAt(currpos - 1) == ord('(') and self.GetCurrentPos() == self.GetTextLength(),
1132 True)
1133
1134
1135 def writeOut(self, text):
1136 """Replacement for stdout."""
1137 self.write(text)
1138
1139 def writeErr(self, text):
1140 """Replacement for stderr."""
1141 self.write(text)
1142
1143 def redirectStdin(self, redirect=True):
1144 """If redirect is true then sys.stdin will come from the shell."""
1145 if redirect:
1146 sys.stdin = self.reader
1147 else:
1148 sys.stdin = self.stdin
1149
1150 def redirectStdout(self, redirect=True):
1151 """If redirect is true then sys.stdout will go to the shell."""
1152 if redirect:
1153 sys.stdout = PseudoFileOut(self.writeOut)
1154 else:
1155 sys.stdout = self.stdout
1156
1157 def redirectStderr(self, redirect=True):
1158 """If redirect is true then sys.stderr will go to the shell."""
1159 if redirect:
1160 sys.stderr = PseudoFileErr(self.writeErr)
1161 else:
1162 sys.stderr = self.stderr
1163
1164 def CanCut(self):
1165 """Return true if text is selected and can be cut."""
1166 if self.GetSelectionStart() != self.GetSelectionEnd() \
1167 and self.GetSelectionStart() >= self.promptPosEnd \
1168 and self.GetSelectionEnd() >= self.promptPosEnd:
1169 return True
1170 else:
1171 return False
1172
1173 def CanPaste(self):
1174 """Return true if a paste should succeed."""
1175 if self.CanEdit() and editwindow.EditWindow.CanPaste(self):
1176 return True
1177 else:
1178 return False
1179
1180 def CanEdit(self):
1181 """Return true if editing should succeed."""
1182 if self.GetSelectionStart() != self.GetSelectionEnd():
1183 if self.GetSelectionStart() >= self.promptPosEnd \
1184 and self.GetSelectionEnd() >= self.promptPosEnd:
1185 return True
1186 else:
1187 return False
1188 else:
1189 return self.GetCurrentPos() >= self.promptPosEnd
1190
1191 def Cut(self):
1192 """Remove selection and place it on the clipboard."""
1193 if self.CanCut() and self.CanCopy():
1194 if self.AutoCompActive():
1195 self.AutoCompCancel()
1196 if self.CallTipActive():
1197 self.CallTipCancel()
1198 self.Copy()
1199 self.ReplaceSelection('')
1200
1201 def Copy(self):
1202 """Copy selection and place it on the clipboard."""
1203 if self.CanCopy():
1204 ps1 = str(sys.ps1)
1205 ps2 = str(sys.ps2)
1206 command = self.GetSelectedText()
1207 command = command.replace(os.linesep + ps2, os.linesep)
1208 command = command.replace(os.linesep + ps1, os.linesep)
1209 command = self.lstripPrompt(text=command)
1210 data = wx.TextDataObject(command)
1211 self._clip(data)
1212
1213 def CopyWithPrompts(self):
1214 """Copy selection, including prompts, and place it on the clipboard."""
1215 if self.CanCopy():
1216 command = self.GetSelectedText()
1217 data = wx.TextDataObject(command)
1218 self._clip(data)
1219
1220 def CopyWithPromptsPrefixed(self):
1221 """Copy selection, including prompts prefixed with four
1222 spaces, and place it on the clipboard."""
1223 if self.CanCopy():
1224 command = self.GetSelectedText()
1225 spaces = ' ' * 4
1226 command = spaces + command.replace(os.linesep,
1227 os.linesep + spaces)
1228 data = wx.TextDataObject(command)
1229 self._clip(data)
1230
1231 def _clip(self, data):
1232 if wx.TheClipboard.Open():
1233 wx.TheClipboard.UsePrimarySelection(False)
1234 wx.TheClipboard.SetData(data)
1235 wx.TheClipboard.Flush()
1236 wx.TheClipboard.Close()
1237
1238 def Paste(self):
1239 """Replace selection with clipboard contents."""
1240 if self.CanPaste() and wx.TheClipboard.Open():
1241 ps2 = str(sys.ps2)
1242 if wx.TheClipboard.IsSupported(wx.DataFormat(wx.DF_TEXT)):
1243 data = wx.TextDataObject()
1244 if wx.TheClipboard.GetData(data):
1245 self.ReplaceSelection('')
1246 command = data.GetText()
1247 command = command.rstrip()
1248 command = self.fixLineEndings(command)
1249 command = self.lstripPrompt(text=command)
1250 command = command.replace(os.linesep + ps2, '\n')
1251 command = command.replace(os.linesep, '\n')
1252 command = command.replace('\n', os.linesep + ps2)
1253 self.write(command)
1254 wx.TheClipboard.Close()
1255
1256
1257 def PasteAndRun(self):
1258 """Replace selection with clipboard contents, run commands."""
1259 text = ''
1260 if wx.TheClipboard.Open():
1261 if wx.TheClipboard.IsSupported(wx.DataFormat(wx.DF_TEXT)):
1262 data = wx.TextDataObject()
1263 if wx.TheClipboard.GetData(data):
1264 text = data.GetText()
1265 wx.TheClipboard.Close()
1266 if text:
1267 self.Execute(text)
1268
1269
1270 def Execute(self, text):
1271 """Replace selection with text and run commands."""
1272 ps1 = str(sys.ps1)
1273 ps2 = str(sys.ps2)
1274 endpos = self.GetTextLength()
1275 self.SetCurrentPos(endpos)
1276 startpos = self.promptPosEnd
1277 self.SetSelection(startpos, endpos)
1278 self.ReplaceSelection('')
1279 text = text.lstrip()
1280 text = self.fixLineEndings(text)
1281 text = self.lstripPrompt(text)
1282 text = text.replace(os.linesep + ps1, '\n')
1283 text = text.replace(os.linesep + ps2, '\n')
1284 text = text.replace(os.linesep, '\n')
1285 lines = text.split('\n')
1286 commands = []
1287 command = ''
1288 for line in lines:
1289 if line.strip() == ps2.strip():
1290 # If we are pasting from something like a
1291 # web page that drops the trailing space
1292 # from the ps2 prompt of a blank line.
1293 line = ''
1294 lstrip = line.lstrip()
1295 if line.strip() != '' and lstrip == line and \
1296 lstrip[:4] not in ['else','elif'] and \
1297 lstrip[:6] != 'except':
1298 # New command.
1299 if command:
1300 # Add the previous command to the list.
1301 commands.append(command)
1302 # Start a new command, which may be multiline.
1303 command = line
1304 else:
1305 # Multiline command. Add to the command.
1306 command += '\n'
1307 command += line
1308 commands.append(command)
1309 for command in commands:
1310 command = command.replace('\n', os.linesep + ps2)
1311 self.write(command)
1312 self.processLine()
1313
1314
1315 def wrap(self, wrap=True):
1316 """Sets whether text is word wrapped."""
1317 try:
1318 self.SetWrapMode(wrap)
1319 except AttributeError:
1320 return 'Wrapping is not available in this version.'
1321
1322 def zoom(self, points=0):
1323 """Set the zoom level.
1324
1325 This number of points is added to the size of all fonts. It
1326 may be positive to magnify or negative to reduce."""
1327 self.SetZoom(points)
1328
1329
1330
1331 def LoadSettings(self, config):
1332 self.autoComplete = config.ReadBool('Options/AutoComplete', True)
1333 self.autoCompleteIncludeMagic = config.ReadBool('Options/AutoCompleteIncludeMagic', True)
1334 self.autoCompleteIncludeSingle = config.ReadBool('Options/AutoCompleteIncludeSingle', True)
1335 self.autoCompleteIncludeDouble = config.ReadBool('Options/AutoCompleteIncludeDouble', True)
1336
1337 self.autoCallTip = config.ReadBool('Options/AutoCallTip', True)
1338 self.callTipInsert = config.ReadBool('Options/CallTipInsert', True)
1339 self.SetWrapMode(config.ReadBool('View/WrapMode', True))
1340
1341 useAA = config.ReadBool('Options/UseAntiAliasing', self.GetUseAntiAliasing())
1342 self.SetUseAntiAliasing(useAA)
1343 self.lineNumbers = config.ReadBool('View/ShowLineNumbers', True)
1344 self.setDisplayLineNumbers (self.lineNumbers)
1345 zoom = config.ReadInt('View/Zoom/Shell', -99)
1346 if zoom != -99:
1347 self.SetZoom(zoom)
1348
1349
1350
1351 def SaveSettings(self, config):
1352 config.WriteBool('Options/AutoComplete', self.autoComplete)
1353 config.WriteBool('Options/AutoCompleteIncludeMagic', self.autoCompleteIncludeMagic)
1354 config.WriteBool('Options/AutoCompleteIncludeSingle', self.autoCompleteIncludeSingle)
1355 config.WriteBool('Options/AutoCompleteIncludeDouble', self.autoCompleteIncludeDouble)
1356 config.WriteBool('Options/AutoCallTip', self.autoCallTip)
1357 config.WriteBool('Options/CallTipInsert', self.callTipInsert)
1358 config.WriteBool('Options/UseAntiAliasing', self.GetUseAntiAliasing())
1359 config.WriteBool('View/WrapMode', self.GetWrapMode())
1360 config.WriteBool('View/ShowLineNumbers', self.lineNumbers)
1361 config.WriteInt('View/Zoom/Shell', self.GetZoom())
1362
1363
1364
1365 ## NOTE: The DnD of file names is disabled until I can figure out how
1366 ## best to still allow DnD of text.
1367
1368
1369 ## #seb : File drag and drop
1370 ## class FileDropTarget(wx.FileDropTarget):
1371 ## def __init__(self, obj):
1372 ## wx.FileDropTarget.__init__(self)
1373 ## self.obj = obj
1374 ## def OnDropFiles(self, x, y, filenames):
1375 ## if len(filenames) == 1:
1376 ## txt = 'r\"%s\"' % filenames[0]
1377 ## else:
1378 ## txt = '( '
1379 ## for f in filenames:
1380 ## txt += 'r\"%s\" , ' % f
1381 ## txt += ')'
1382 ## self.obj.AppendText(txt)
1383 ## pos = self.obj.GetCurrentPos()
1384 ## self.obj.SetCurrentPos( pos )
1385 ## self.obj.SetSelection( pos, pos )
1386
1387
1388
1389 ## class TextAndFileDropTarget(wx.DropTarget):
1390 ## def __init__(self, shell):
1391 ## wx.DropTarget.__init__(self)
1392 ## self.shell = shell
1393 ## self.compdo = wx.DataObjectComposite()
1394 ## self.textdo = wx.TextDataObject()
1395 ## self.filedo = wx.FileDataObject()
1396 ## self.compdo.Add(self.textdo)
1397 ## self.compdo.Add(self.filedo, True)
1398
1399 ## self.SetDataObject(self.compdo)
1400
1401 ## def OnDrop(self, x, y):
1402 ## return True
1403
1404 ## def OnData(self, x, y, result):
1405 ## self.GetData()
1406 ## if self.textdo.GetTextLength() > 1:
1407 ## text = self.textdo.GetText()
1408 ## # *** Do somethign with the dragged text here...
1409 ## self.textdo.SetText('')
1410 ## else:
1411 ## filenames = str(self.filename.GetFilenames())
1412 ## if len(filenames) == 1:
1413 ## txt = 'r\"%s\"' % filenames[0]
1414 ## else:
1415 ## txt = '( '
1416 ## for f in filenames:
1417 ## txt += 'r\"%s\" , ' % f
1418 ## txt += ')'
1419 ## self.shell.AppendText(txt)
1420 ## pos = self.shell.GetCurrentPos()
1421 ## self.shell.SetCurrentPos( pos )
1422 ## self.shell.SetSelection( pos, pos )
1423
1424 ## return result
1425