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