]> git.saurik.com Git - wxWidgets.git/blobdiff - wxPython/wx/py/shell.py
little tweaks
[wxWidgets.git] / wxPython / wx / py / shell.py
index 9b16953fc61fc3880b55ba9d7b4d8381300706f4..c86ced152d88d50d8e0d5498df966302e1c2aa18 100644 (file)
+"""Shell is an interactive text control in which a user types in
+commands to be sent to the interpreter.  This particular shell is
+based on wxPython's wxStyledTextCtrl.
 
 
-"""Renamer stub: provides a way to drop the wx prefix from wxPython objects."""
+Sponsored by Orbtech - Your source for Python programming expertise."""
 
 
-from wx import _rename
-from wxPython.py import shell
-_rename(globals(), shell.__dict__, modulename='py.shell')
-del shell
-del _rename
+__author__ = "Patrick K. O'Brien <pobrien@orbtech.com>"
+__cvsid__ = "$Id$"
+__revision__ = "$Revision$"[11:-2]
+
+import wx
+from wx import stc
+
+import keyword
+import os
+import sys
+import time
+
+from buffer import Buffer
+import dispatcher
+import editwindow
+import frame
+from pseudo import PseudoFileIn
+from pseudo import PseudoFileOut
+from pseudo import PseudoFileErr
+from version import VERSION
+
+sys.ps3 = '<-- '  # Input prompt.
+
+NAVKEYS = (wx.WXK_END, wx.WXK_LEFT, wx.WXK_RIGHT,
+           wx.WXK_UP, wx.WXK_DOWN, wx.WXK_PRIOR, wx.WXK_NEXT)
+
+
+class ShellFrame(frame.Frame, frame.ShellFrameMixin):
+    """Frame containing the shell component."""
+
+    name = 'Shell Frame'
+    revision = __revision__
+
+    def __init__(self, parent=None, id=-1, title='PyShell',
+                 pos=wx.DefaultPosition, size=wx.DefaultSize,
+                 style=wx.DEFAULT_FRAME_STYLE, locals=None,
+                 InterpClass=None,
+                 config=None, dataDir=None,
+                 *args, **kwds):
+        """Create ShellFrame instance."""
+        frame.Frame.__init__(self, parent, id, title, pos, size, style)
+        frame.ShellFrameMixin.__init__(self, config, dataDir)
+
+        if size == wx.DefaultSize:
+            self.SetSize((750, 525))
+
+        intro = 'PyShell %s - The Flakiest Python Shell' % VERSION
+        self.SetStatusText(intro.replace('\n', ', '))
+        self.shell = Shell(parent=self, id=-1, introText=intro,
+                           locals=locals, InterpClass=InterpClass,
+                           startupScript=self.startupScript,
+                           execStartupScript=self.execStartupScript,
+                           *args, **kwds)
+
+        # Override the shell so that status messages go to the status bar.
+        self.shell.setStatusText = self.SetStatusText
+
+        self.shell.SetFocus()
+        self.LoadSettings()
+
+
+    def OnClose(self, event):
+        """Event handler for closing."""
+        # This isn't working the way I want, but I'll leave it for now.
+        if self.shell.waiting:
+            if event.CanVeto():
+                event.Veto(True)
+        else:
+            self.SaveSettings()
+            self.shell.destroy()
+            self.Destroy()
+
+    def OnAbout(self, event):
+        """Display an About window."""
+        title = 'About PyShell'
+        text = 'PyShell %s\n\n' % VERSION + \
+               'Yet another Python shell, only flakier.\n\n' + \
+               'Half-baked by Patrick K. O\'Brien,\n' + \
+               'the other half is still in the oven.\n\n' + \
+               'Shell Revision: %s\n' % self.shell.revision + \
+               'Interpreter Revision: %s\n\n' % self.shell.interp.revision + \
+               'Platform: %s\n' % sys.platform + \
+               'Python Version: %s\n' % sys.version.split()[0] + \
+               'wxPython Version: %s\n' % wx.VERSION_STRING + \
+               ('\t(%s)\n' % ", ".join(wx.PlatformInfo[1:])) 
+        dialog = wx.MessageDialog(self, text, title,
+                                  wx.OK | wx.ICON_INFORMATION)
+        dialog.ShowModal()
+        dialog.Destroy()
+
+
+    def OnHelp(self, event):
+        """Show a help dialog."""
+        frame.ShellFrameMixin.OnHelp(self, event)
+
+
+    def LoadSettings(self):
+        if self.config is not None:
+            frame.ShellFrameMixin.LoadSettings(self)
+            frame.Frame.LoadSettings(self, self.config)
+            self.shell.LoadSettings(self.config)
+
+    def SaveSettings(self, force=False):
+        if self.config is not None:
+            frame.ShellFrameMixin.SaveSettings(self)
+            if self.autoSaveSettings or force:
+                frame.Frame.SaveSettings(self, self.config)
+                self.shell.SaveSettings(self.config)
+
+    def DoSaveSettings(self):
+        if self.config is not None:
+            self.SaveSettings(force=True)
+            self.config.Flush()
+        
+
+
+
+HELP_TEXT = """\
+* Key bindings:
+Home              Go to the beginning of the command or line.
+Shift+Home        Select to the beginning of the command or line.
+Shift+End         Select to the end of the line.
+End               Go to the end of the line.
+Ctrl+C            Copy selected text, removing prompts.
+Ctrl+Shift+C      Copy selected text, retaining prompts.
+Alt+C             Copy to the clipboard, including prefixed prompts.
+Ctrl+X            Cut selected text.
+Ctrl+V            Paste from clipboard.
+Ctrl+Shift+V      Paste and run multiple commands from clipboard.
+Ctrl+Up Arrow     Retrieve Previous History item.
+Alt+P             Retrieve Previous History item.
+Ctrl+Down Arrow   Retrieve Next History item.
+Alt+N             Retrieve Next History item.
+Shift+Up Arrow    Insert Previous History item.
+Shift+Down Arrow  Insert Next History item.
+F8                Command-completion of History item.
+                  (Type a few characters of a previous command and press F8.)
+Ctrl+Enter        Insert new line into multiline command.
+Ctrl+]            Increase font size.
+Ctrl+[            Decrease font size.
+Ctrl+=            Default font size.
+Ctrl-Space        Show Auto Completion.
+Ctrl-Alt-Space    Show Call Tip.
+Shift+Enter       Complete Text from History.
+Ctrl+F            Search 
+F3                Search next
+Ctrl+H            "hide" lines containing selection / "unhide"
+F12               on/off "free-edit" mode
+"""
+
+class ShellFacade:
+    """Simplified interface to all shell-related functionality.
+
+    This is a semi-transparent facade, in that all attributes of other
+    are accessible, even though only some are visible to the user."""
+
+    name = 'Shell Interface'
+    revision = __revision__
+
+    def __init__(self, other):
+        """Create a ShellFacade instance."""
+        d = self.__dict__
+        d['other'] = other
+        d['helpText'] = HELP_TEXT
+        d['this'] = other.this
+
+    def help(self):
+        """Display some useful information about how to use the shell."""
+        self.write(self.helpText)
+
+    def __getattr__(self, name):
+        if hasattr(self.other, name):
+            return getattr(self.other, name)
+        else:
+            raise AttributeError, name
+
+    def __setattr__(self, name, value):
+        if self.__dict__.has_key(name):
+            self.__dict__[name] = value
+        elif hasattr(self.other, name):
+            setattr(self.other, name, value)
+        else:
+            raise AttributeError, name
+
+    def _getAttributeNames(self):
+        """Return list of magic attributes to extend introspection."""
+        list = [
+            'about',
+            'ask',
+            'autoCallTip',
+            'autoComplete',
+            'autoCompleteAutoHide',
+            'autoCompleteCaseInsensitive',
+            'autoCompleteIncludeDouble',
+            'autoCompleteIncludeMagic',
+            'autoCompleteIncludeSingle',
+            'callTipInsert',
+            'clear',
+            'pause',
+            'prompt',
+            'quit',
+            'redirectStderr',
+            'redirectStdin',
+            'redirectStdout',
+            'run',
+            'runfile',
+            'wrap',
+            'zoom',
+            ]
+        list.sort()
+        return list
+
+
+
+class Shell(editwindow.EditWindow):
+    """Shell based on StyledTextCtrl."""
+
+    name = 'Shell'
+    revision = __revision__
+
+    def __init__(self, parent, id=-1, pos=wx.DefaultPosition,
+                 size=wx.DefaultSize, style=wx.CLIP_CHILDREN,
+                 introText='', locals=None, InterpClass=None,
+                 startupScript=None, execStartupScript=True,
+                 *args, **kwds):
+        """Create Shell instance."""
+        editwindow.EditWindow.__init__(self, parent, id, pos, size, style)
+        self.wrap()
+        if locals is None:
+            import __main__
+            locals = __main__.__dict__
+
+        # Grab these so they can be restored by self.redirect* methods.
+        self.stdin = sys.stdin
+        self.stdout = sys.stdout
+        self.stderr = sys.stderr
+
+        # Import a default interpreter class if one isn't provided.
+        if InterpClass == None:
+            from interpreter import Interpreter
+        else:
+            Interpreter = InterpClass
+
+        # Create a replacement for stdin.
+        self.reader = PseudoFileIn(self.readline, self.readlines)
+        self.reader.input = ''
+        self.reader.isreading = False
+
+        # Set up the interpreter.
+        self.interp = Interpreter(locals=locals,
+                                  rawin=self.raw_input,
+                                  stdin=self.reader,
+                                  stdout=PseudoFileOut(self.writeOut),
+                                  stderr=PseudoFileErr(self.writeErr),
+                                  *args, **kwds)
+
+        # Set up the buffer.
+        self.buffer = Buffer()
+
+        # Find out for which keycodes the interpreter will autocomplete.
+        self.autoCompleteKeys = self.interp.getAutoCompleteKeys()
+
+        # Keep track of the last non-continuation prompt positions.
+        self.promptPosStart = 0
+        self.promptPosEnd = 0
+
+        # Keep track of multi-line commands.
+        self.more = False
+
+        # Create the command history.  Commands are added into the
+        # front of the list (ie. at index 0) as they are entered.
+        # self.historyIndex is the current position in the history; it
+        # gets incremented as you retrieve the previous command,
+        # decremented as you retrieve the next, and reset when you hit
+        # Enter.  self.historyIndex == -1 means you're on the current
+        # command, not in the history.
+        self.history = []
+        self.historyIndex = -1
+
+        #seb add mode for "free edit"
+        self.noteMode = 0
+        self.MarkerDefine(0,stc.STC_MARK_ROUNDRECT)  # marker for hidden
+        self.searchTxt = ""
+
+        # Assign handlers for keyboard events.
+        self.Bind(wx.EVT_CHAR, self.OnChar)
+        self.Bind(wx.EVT_KEY_DOWN, self.OnKeyDown)
+
+        # Assign handler for idle time.
+        self.waiting = False
+        self.Bind(wx.EVT_IDLE, self.OnIdle)
+
+        # Display the introductory banner information.
+        self.showIntro(introText)
+
+        # Assign some pseudo keywords to the interpreter's namespace.
+        self.setBuiltinKeywords()
+
+        # Add 'shell' to the interpreter's local namespace.
+        self.setLocalShell()
+
+        ## NOTE:  See note at bottom of this file...
+        ## #seb: File drag and drop
+        ## self.SetDropTarget( FileDropTarget(self) )
+
+        # Do this last so the user has complete control over their
+        # environment.  They can override anything they want.
+        if execStartupScript:
+            if startupScript is None:
+                startupScript = os.environ.get('PYTHONSTARTUP')
+            self.execStartupScript(startupScript)
+        else:
+            self.prompt()
+        
+        wx.CallAfter(self.ScrollToLine, 0)
+
+
+    def clearHistory(self):
+        self.history = []
+        self.historyIndex = -1
+        dispatcher.send(signal="Shell.clearHistory")
+
+
+    def destroy(self):
+        del self.interp
+
+    def setFocus(self):
+        """Set focus to the shell."""
+        self.SetFocus()
+
+    def OnIdle(self, event):
+        """Free the CPU to do other things."""
+        if self.waiting:
+            time.sleep(0.05)
+        event.Skip()
+
+    def showIntro(self, text=''):
+        """Display introductory text in the shell."""
+        if text:
+            if not text.endswith(os.linesep):
+                text += os.linesep
+            self.write(text)
+        try:
+            self.write(self.interp.introText)
+        except AttributeError:
+            pass
+
+    def setBuiltinKeywords(self):
+        """Create pseudo keywords as part of builtins.
+
+        This sets "close", "exit" and "quit" to a helpful string.
+        """
+        import __builtin__
+        __builtin__.close = __builtin__.exit = __builtin__.quit = \
+            'Click on the close button to leave the application.'
+
+
+    def quit(self):
+        """Quit the application."""
+        # XXX Good enough for now but later we want to send a close event.
+        # In the close event handler we can make sure they want to
+        # quit.  Other applications, like PythonCard, may choose to
+        # hide rather than quit so we should just post the event and
+        # let the surrounding app decide what it wants to do.
+        self.write('Click on the close button to leave the application.')
+
+
+    def setLocalShell(self):
+        """Add 'shell' to locals as reference to ShellFacade instance."""
+        self.interp.locals['shell'] = ShellFacade(other=self)
+
+
+    def execStartupScript(self, startupScript):
+        """Execute the user's PYTHONSTARTUP script if they have one."""
+        if startupScript and os.path.isfile(startupScript):
+            text = 'Startup script executed: ' + startupScript
+            self.push('print %r; execfile(%r)' % (text, startupScript))
+            self.interp.startupScript = startupScript
+        else:
+            self.push('')
+
+
+    def about(self):
+        """Display information about Py."""
+        text = """
+Author: %r
+Py Version: %s
+Py Shell Revision: %s
+Py Interpreter Revision: %s
+Python Version: %s
+wxPython Version: %s
+wxPython PlatformInfo: %s
+Platform: %s""" % \
+        (__author__, VERSION, self.revision, self.interp.revision,
+         sys.version.split()[0], wx.VERSION_STRING, str(wx.PlatformInfo),
+         sys.platform)
+        self.write(text.strip())
+
+
+    def OnChar(self, event):
+        """Keypress event handler.
+
+        Only receives an event if OnKeyDown calls event.Skip() for the
+        corresponding event."""
+
+        if self.noteMode:
+            event.Skip()
+            return
+
+        # Prevent modification of previously submitted
+        # commands/responses.
+        if not self.CanEdit():
+            return
+        key = event.KeyCode()
+        currpos = self.GetCurrentPos()
+        stoppos = self.promptPosEnd
+        # Return (Enter) needs to be ignored in this handler.
+        if key in [wx.WXK_RETURN, wx.WXK_NUMPAD_ENTER]:
+            pass
+        elif key in self.autoCompleteKeys:
+            # Usually the dot (period) key activates auto completion.
+            # Get the command between the prompt and the cursor.  Add
+            # the autocomplete character to the end of the command.
+            if self.AutoCompActive():
+                self.AutoCompCancel()
+            command = self.GetTextRange(stoppos, currpos) + chr(key)
+            self.write(chr(key))
+            if self.autoComplete:
+                self.autoCompleteShow(command)
+        elif key == ord('('):
+            # The left paren activates a call tip and cancels an
+            # active auto completion.
+            if self.AutoCompActive():
+                self.AutoCompCancel()
+            # Get the command between the prompt and the cursor.  Add
+            # the '(' to the end of the command.
+            self.ReplaceSelection('')
+            command = self.GetTextRange(stoppos, currpos) + '('
+            self.write('(')
+            self.autoCallTipShow(command, self.GetCurrentPos() == self.GetTextLength())
+        else:
+            # Allow the normal event handling to take place.
+            event.Skip()
+
+
+    def OnKeyDown(self, event):
+        """Key down event handler."""
+
+        key = event.KeyCode()
+        # If the auto-complete window is up let it do its thing.
+        if self.AutoCompActive():
+            event.Skip()
+            return
+        
+        # Prevent modification of previously submitted
+        # commands/responses.
+        controlDown = event.ControlDown()
+        altDown = event.AltDown()
+        shiftDown = event.ShiftDown()
+        currpos = self.GetCurrentPos()
+        endpos = self.GetTextLength()
+        selecting = self.GetSelectionStart() != self.GetSelectionEnd()
+        
+        if controlDown and shiftDown and key in (ord('F'), ord('f')): 
+            li = self.GetCurrentLine()
+            m = self.MarkerGet(li)
+            if m & 1<<0:
+                startP = self.PositionFromLine(li)
+                self.MarkerDelete(li, 0)
+                maxli = self.GetLineCount()
+                li += 1 # li stayed visible as header-line
+                li0 = li 
+                while li<maxli and self.GetLineVisible(li) == 0:
+                    li += 1
+                endP = self.GetLineEndPosition(li-1)
+                self.ShowLines(li0, li-1)
+                self.SetSelection( startP, endP ) # select reappearing text to allow "hide again"
+                return
+            startP,endP = self.GetSelection()
+            endP-=1
+            startL,endL = self.LineFromPosition(startP), self.LineFromPosition(endP)
+
+            if endL == self.LineFromPosition(self.promptPosEnd): # never hide last prompt
+                endL -= 1
+
+            m = self.MarkerGet(startL)
+            self.MarkerAdd(startL, 0)
+            self.HideLines(startL+1,endL)
+            self.SetCurrentPos( startP ) # to ensure caret stays visible !
+
+        if key == wx.WXK_F12: #seb
+            if self.noteMode:
+                # self.promptPosStart not used anyway - or ? 
+                self.promptPosEnd = self.PositionFromLine( self.GetLineCount()-1 ) + len(str(sys.ps1))
+                self.GotoLine(self.GetLineCount())
+                self.GotoPos(self.promptPosEnd)
+                self.prompt()  #make sure we have a prompt
+                self.SetCaretForeground("black")
+                self.SetCaretWidth(1)    #default
+                self.SetCaretPeriod(500) #default
+            else:
+                self.SetCaretForeground("red")
+                self.SetCaretWidth(4)
+                self.SetCaretPeriod(0) #steady
+
+            self.noteMode = not self.noteMode
+            return
+        if self.noteMode:
+            event.Skip()
+            return
+
+        # Return (Enter) is used to submit a command to the
+        # interpreter.
+        if (not controlDown and not shiftDown and not altDown) and key in [wx.WXK_RETURN, wx.WXK_NUMPAD_ENTER]:
+            if self.CallTipActive():
+                self.CallTipCancel()
+            self.processLine()
+            
+        # Complete Text (from already typed words)    
+        elif shiftDown and key in [wx.WXK_RETURN, wx.WXK_NUMPAD_ENTER]:
+            self.OnShowCompHistory()
+            
+        # Ctrl+Return (Ctrl+Enter) is used to insert a line break.
+        elif controlDown and key in [wx.WXK_RETURN, wx.WXK_NUMPAD_ENTER]:
+            if self.CallTipActive():
+                self.CallTipCancel()
+            if currpos == endpos:
+                self.processLine()
+            else:
+                self.insertLineBreak()
+                
+        # Let Ctrl-Alt-* get handled normally.
+        elif controlDown and altDown:
+            event.Skip()
+            
+        # Clear the current, unexecuted command.
+        elif key == wx.WXK_ESCAPE:
+            if self.CallTipActive():
+                event.Skip()
+            else:
+                self.clearCommand()
+
+        # Clear the current command
+        elif key == wx.WXK_BACK and controlDown and shiftDown:
+            self.clearCommand()
+
+        # Increase font size.
+        elif controlDown and key in (ord(']'), wx.WXK_NUMPAD_ADD):
+            dispatcher.send(signal='FontIncrease')
+
+        # Decrease font size.
+        elif controlDown and key in (ord('['), wx.WXK_NUMPAD_SUBTRACT):
+            dispatcher.send(signal='FontDecrease')
+
+        # Default font size.
+        elif controlDown and key in (ord('='), wx.WXK_NUMPAD_DIVIDE):
+            dispatcher.send(signal='FontDefault')
+
+        # Cut to the clipboard.
+        elif (controlDown and key in (ord('X'), ord('x'))) \
+                 or (shiftDown and key == wx.WXK_DELETE):
+            self.Cut()
+
+        # Copy to the clipboard.
+        elif controlDown and not shiftDown \
+                 and key in (ord('C'), ord('c'), wx.WXK_INSERT):
+            self.Copy()
+
+        # Copy to the clipboard, including prompts.
+        elif controlDown and shiftDown \
+                 and key in (ord('C'), ord('c'), wx.WXK_INSERT):
+            self.CopyWithPrompts()
+
+        # Copy to the clipboard, including prefixed prompts.
+        elif altDown and not controlDown \
+                 and key in (ord('C'), ord('c'), wx.WXK_INSERT):
+            self.CopyWithPromptsPrefixed()
+
+        # Home needs to be aware of the prompt.
+        elif key == wx.WXK_HOME:
+            home = self.promptPosEnd
+            if currpos > home:
+                self.SetCurrentPos(home)
+                if not selecting and not shiftDown:
+                    self.SetAnchor(home)
+                    self.EnsureCaretVisible()
+            else:
+                event.Skip()
+
+        #
+        # The following handlers modify text, so we need to see if
+        # there is a selection that includes text prior to the prompt.
+        #
+        # Don't modify a selection with text prior to the prompt.
+        elif selecting and key not in NAVKEYS and not self.CanEdit():
+            pass
+
+        # Paste from the clipboard.
+        elif (controlDown and not shiftDown and key in (ord('V'), ord('v'))) \
+                 or (shiftDown and not controlDown and key == wx.WXK_INSERT):
+            self.Paste()
+
+        # manually invoke AutoComplete and Calltips
+        elif controlDown and key == wx.WXK_SPACE:
+            self.OnCallTipAutoCompleteManually(shiftDown)
+
+        # Paste from the clipboard, run commands.
+        elif controlDown and shiftDown and key in (ord('V'), ord('v')):
+            self.PasteAndRun()
+            
+        # Replace with the previous command from the history buffer.
+        elif (controlDown and key == wx.WXK_UP) \
+                 or (altDown and key in (ord('P'), ord('p'))):
+            self.OnHistoryReplace(step=+1)
+            
+        # Replace with the next command from the history buffer.
+        elif (controlDown and key == wx.WXK_DOWN) \
+                 or (altDown and key in (ord('N'), ord('n'))):
+            self.OnHistoryReplace(step=-1)
+            
+        # Insert the previous command from the history buffer.
+        elif (shiftDown and key == wx.WXK_UP) and self.CanEdit():
+            self.OnHistoryInsert(step=+1)
+            
+        # Insert the next command from the history buffer.
+        elif (shiftDown and key == wx.WXK_DOWN) and self.CanEdit():
+            self.OnHistoryInsert(step=-1)
+            
+        # Search up the history for the text in front of the cursor.
+        elif key == wx.WXK_F8:
+            self.OnHistorySearch()
+            
+        # Don't backspace over the latest non-continuation prompt.
+        elif key == wx.WXK_BACK:
+            if selecting and self.CanEdit():
+                event.Skip()
+            elif currpos > self.promptPosEnd:
+                event.Skip()
+                
+        # Only allow these keys after the latest prompt.
+        elif key in (wx.WXK_TAB, wx.WXK_DELETE):
+            if self.CanEdit():
+                event.Skip()
+                
+        # Don't toggle between insert mode and overwrite mode.
+        elif key == wx.WXK_INSERT:
+            pass
+        
+        # Don't allow line deletion.
+        elif controlDown and key in (ord('L'), ord('l')):
+            pass
+
+        # Don't allow line transposition.
+        elif controlDown and key in (ord('T'), ord('t')):
+            pass
+
+        # Basic navigation keys should work anywhere.
+        elif key in NAVKEYS:
+            event.Skip()
+
+        # Protect the readonly portion of the shell.
+        elif not self.CanEdit():
+            pass
+
+        else:
+            event.Skip()
+
+
+    def OnShowCompHistory(self):
+        """Show possible autocompletion Words from already typed words."""
+        
+        #copy from history
+        his = self.history[:]
+        
+        #put together in one string
+        joined = " ".join (his)
+        import re
+
+        #sort out only "good" words
+        newlist = re.split("[ \.\[\]=}(\)\,0-9\"]", joined)
+        
+        #length > 1 (mix out "trash")
+        thlist = []
+        for i in newlist:
+            if len (i) > 1:
+                thlist.append (i)
+        
+        #unique (no duplicate words
+        #oneliner from german python forum => unique list
+        unlist = [thlist[i] for i in xrange(len(thlist)) if thlist[i] not in thlist[:i]]
+            
+        #sort lowercase
+        unlist.sort(lambda a, b: cmp(a.lower(), b.lower()))
+        
+        #this is more convenient, isn't it?
+        self.AutoCompSetIgnoreCase(True)
+        
+        #join again together in a string
+        stringlist = " ".join(unlist)
+
+        #pos von 0 noch ausrechnen
+
+        #how big is the offset?
+        cpos = self.GetCurrentPos() - 1
+        while chr (self.GetCharAt (cpos)).isalnum():
+            cpos -= 1
+            
+        #the most important part
+        self.AutoCompShow(self.GetCurrentPos() - cpos -1, stringlist)
+
+
+    def clearCommand(self):
+        """Delete the current, unexecuted command."""
+        startpos = self.promptPosEnd
+        endpos = self.GetTextLength()
+        self.SetSelection(startpos, endpos)
+        self.ReplaceSelection('')
+        self.more = False
+
+    def OnHistoryReplace(self, step):
+        """Replace with the previous/next command from the history buffer."""
+        self.clearCommand()
+        self.replaceFromHistory(step)
+
+    def replaceFromHistory(self, step):
+        """Replace selection with command from the history buffer."""
+        ps2 = str(sys.ps2)
+        self.ReplaceSelection('')
+        newindex = self.historyIndex + step
+        if -1 <= newindex <= len(self.history):
+            self.historyIndex = newindex
+        if 0 <= newindex <= len(self.history)-1:
+            command = self.history[self.historyIndex]
+            command = command.replace('\n', os.linesep + ps2)
+            self.ReplaceSelection(command)
+
+    def OnHistoryInsert(self, step):
+        """Insert the previous/next command from the history buffer."""
+        if not self.CanEdit():
+            return
+        startpos = self.GetCurrentPos()
+        self.replaceFromHistory(step)
+        endpos = self.GetCurrentPos()
+        self.SetSelection(endpos, startpos)
+
+    def OnHistorySearch(self):
+        """Search up the history buffer for the text in front of the cursor."""
+        if not self.CanEdit():
+            return
+        startpos = self.GetCurrentPos()
+        # The text up to the cursor is what we search for.
+        numCharsAfterCursor = self.GetTextLength() - startpos
+        searchText = self.getCommand(rstrip=False)
+        if numCharsAfterCursor > 0:
+            searchText = searchText[:-numCharsAfterCursor]
+        if not searchText:
+            return
+        # Search upwards from the current history position and loop
+        # back to the beginning if we don't find anything.
+        if (self.historyIndex <= -1) \
+        or (self.historyIndex >= len(self.history)-2):
+            searchOrder = range(len(self.history))
+        else:
+            searchOrder = range(self.historyIndex+1, len(self.history)) + \
+                          range(self.historyIndex)
+        for i in searchOrder:
+            command = self.history[i]
+            if command[:len(searchText)] == searchText:
+                # Replace the current selection with the one we found.
+                self.ReplaceSelection(command[len(searchText):])
+                endpos = self.GetCurrentPos()
+                self.SetSelection(endpos, startpos)
+                # We've now warped into middle of the history.
+                self.historyIndex = i
+                break
+
+    def setStatusText(self, text):
+        """Display status information."""
+
+        # This method will likely be replaced by the enclosing app to
+        # do something more interesting, like write to a status bar.
+        print text
+
+    def insertLineBreak(self):
+        """Insert a new line break."""
+        if self.CanEdit():
+            self.write(os.linesep)
+            self.more = True
+            self.prompt()
+
+    def processLine(self):
+        """Process the line of text at which the user hit Enter."""
+
+        # The user hit ENTER and we need to decide what to do. They
+        # could be sitting on any line in the shell.
+
+        thepos = self.GetCurrentPos()
+        startpos = self.promptPosEnd
+        endpos = self.GetTextLength()
+        ps2 = str(sys.ps2)
+        # If they hit RETURN inside the current command, execute the
+        # command.
+        if self.CanEdit():
+            self.SetCurrentPos(endpos)
+            self.interp.more = False
+            command = self.GetTextRange(startpos, endpos)
+            lines = command.split(os.linesep + ps2)
+            lines = [line.rstrip() for line in lines]
+            command = '\n'.join(lines)
+            if self.reader.isreading:
+                if not command:
+                    # Match the behavior of the standard Python shell
+                    # when the user hits return without entering a
+                    # value.
+                    command = '\n'
+                self.reader.input = command
+                self.write(os.linesep)
+            else:
+                self.push(command)
+                wx.FutureCall(1, self.EnsureCaretVisible)
+        # Or replace the current command with the other command.
+        else:
+            # If the line contains a command (even an invalid one).
+            if self.getCommand(rstrip=False):
+                command = self.getMultilineCommand()
+                self.clearCommand()
+                self.write(command)
+            # Otherwise, put the cursor back where we started.
+            else:
+                self.SetCurrentPos(thepos)
+                self.SetAnchor(thepos)
+
+    def getMultilineCommand(self, rstrip=True):
+        """Extract a multi-line command from the editor.
+
+        The command may not necessarily be valid Python syntax."""
+        # XXX Need to extract real prompts here. Need to keep track of
+        # the prompt every time a command is issued.
+        ps1 = str(sys.ps1)
+        ps1size = len(ps1)
+        ps2 = str(sys.ps2)
+        ps2size = len(ps2)
+        # This is a total hack job, but it works.
+        text = self.GetCurLine()[0]
+        line = self.GetCurrentLine()
+        while text[:ps2size] == ps2 and line > 0:
+            line -= 1
+            self.GotoLine(line)
+            text = self.GetCurLine()[0]
+        if text[:ps1size] == ps1:
+            line = self.GetCurrentLine()
+            self.GotoLine(line)
+            startpos = self.GetCurrentPos() + ps1size
+            line += 1
+            self.GotoLine(line)
+            while self.GetCurLine()[0][:ps2size] == ps2:
+                line += 1
+                self.GotoLine(line)
+            stoppos = self.GetCurrentPos()
+            command = self.GetTextRange(startpos, stoppos)
+            command = command.replace(os.linesep + ps2, '\n')
+            command = command.rstrip()
+            command = command.replace('\n', os.linesep + ps2)
+        else:
+            command = ''
+        if rstrip:
+            command = command.rstrip()
+        return command
+
+    def getCommand(self, text=None, rstrip=True):
+        """Extract a command from text which may include a shell prompt.
+
+        The command may not necessarily be valid Python syntax."""
+        if not text:
+            text = self.GetCurLine()[0]
+        # Strip the prompt off the front leaving just the command.
+        command = self.lstripPrompt(text)
+        if command == text:
+            command = ''  # Real commands have prompts.
+        if rstrip:
+            command = command.rstrip()
+        return command
+
+    def lstripPrompt(self, text):
+        """Return text without a leading prompt."""
+        ps1 = str(sys.ps1)
+        ps1size = len(ps1)
+        ps2 = str(sys.ps2)
+        ps2size = len(ps2)
+        # Strip the prompt off the front of text.
+        if text[:ps1size] == ps1:
+            text = text[ps1size:]
+        elif text[:ps2size] == ps2:
+            text = text[ps2size:]
+        return text
+
+    def push(self, command, silent = False):
+        """Send command to the interpreter for execution."""
+        if not silent:
+            self.write(os.linesep)
+        busy = wx.BusyCursor()
+        self.waiting = True
+        self.more = self.interp.push(command)
+        self.waiting = False
+        del busy
+        if not self.more:
+            self.addHistory(command.rstrip())
+        if not silent:
+            self.prompt()
+
+    def addHistory(self, command):
+        """Add command to the command history."""
+        # Reset the history position.
+        self.historyIndex = -1
+        # Insert this command into the history, unless it's a blank
+        # line or the same as the last command.
+        if command != '' \
+        and (len(self.history) == 0 or command != self.history[0]):
+            self.history.insert(0, command)
+            dispatcher.send(signal="Shell.addHistory", command=command)
+
+    def write(self, text):
+        """Display text in the shell.
+
+        Replace line endings with OS-specific endings."""
+        text = self.fixLineEndings(text)
+        self.AddText(text)
+        self.EnsureCaretVisible()
+
+    def fixLineEndings(self, text):
+        """Return text with line endings replaced by OS-specific endings."""
+        lines = text.split('\r\n')
+        for l in range(len(lines)):
+            chunks = lines[l].split('\r')
+            for c in range(len(chunks)):
+                chunks[c] = os.linesep.join(chunks[c].split('\n'))
+            lines[l] = os.linesep.join(chunks)
+        text = os.linesep.join(lines)
+        return text
+
+    def prompt(self):
+        """Display proper prompt for the context: ps1, ps2 or ps3.
+
+        If this is a continuation line, autoindent as necessary."""
+        isreading = self.reader.isreading
+        skip = False
+        if isreading:
+            prompt = str(sys.ps3)
+        elif self.more:
+            prompt = str(sys.ps2)
+        else:
+            prompt = str(sys.ps1)
+        pos = self.GetCurLine()[1]
+        if pos > 0:
+            if isreading:
+                skip = True
+            else:
+                self.write(os.linesep)
+        if not self.more:
+            self.promptPosStart = self.GetCurrentPos()
+        if not skip:
+            self.write(prompt)
+        if not self.more:
+            self.promptPosEnd = self.GetCurrentPos()
+            # Keep the undo feature from undoing previous responses.
+            self.EmptyUndoBuffer()
+        # XXX Add some autoindent magic here if more.
+        if self.more:
+            self.write(' '*4)  # Temporary hack indentation.
+        self.EnsureCaretVisible()
+        self.ScrollToColumn(0)
+
+    def readline(self):
+        """Replacement for stdin.readline()."""
+        input = ''
+        reader = self.reader
+        reader.isreading = True
+        self.prompt()
+        try:
+            while not reader.input:
+                wx.YieldIfNeeded()
+            input = reader.input
+        finally:
+            reader.input = ''
+            reader.isreading = False
+        input = str(input)  # In case of Unicode.
+        return input
+
+    def readlines(self):
+        """Replacement for stdin.readlines()."""
+        lines = []
+        while lines[-1:] != ['\n']:
+            lines.append(self.readline())
+        return lines
+
+    def raw_input(self, prompt=''):
+        """Return string based on user input."""
+        if prompt:
+            self.write(prompt)
+        return self.readline()
+
+    def ask(self, prompt='Please enter your response:'):
+        """Get response from the user using a dialog box."""
+        dialog = wx.TextEntryDialog(None, prompt,
+                                    'Input Dialog (Raw)', '')
+        try:
+            if dialog.ShowModal() == wx.ID_OK:
+                text = dialog.GetValue()
+                return text
+        finally:
+            dialog.Destroy()
+        return ''
+
+    def pause(self):
+        """Halt execution pending a response from the user."""
+        self.ask('Press enter to continue:')
+
+    def clear(self):
+        """Delete all text from the shell."""
+        self.ClearAll()
+
+    def run(self, command, prompt=True, verbose=True):
+        """Execute command as if it was typed in directly.
+        >>> shell.run('print "this"')
+        >>> print "this"
+        this
+        >>>
+        """
+        # Go to the very bottom of the text.
+        endpos = self.GetTextLength()
+        self.SetCurrentPos(endpos)
+        command = command.rstrip()
+        if prompt: self.prompt()
+        if verbose: self.write(command)
+        self.push(command)
+
+    def runfile(self, filename):
+        """Execute all commands in file as if they were typed into the
+        shell."""
+        file = open(filename)
+        try:
+            self.prompt()
+            for command in file.readlines():
+                if command[:6] == 'shell.':
+                    # Run shell methods silently.
+                    self.run(command, prompt=False, verbose=False)
+                else:
+                    self.run(command, prompt=False, verbose=True)
+        finally:
+            file.close()
+
+    def autoCompleteShow(self, command, offset = 0):
+        """Display auto-completion popup list."""
+        self.AutoCompSetAutoHide(self.autoCompleteAutoHide)
+        self.AutoCompSetIgnoreCase(self.autoCompleteCaseInsensitive)
+        list = self.interp.getAutoCompleteList(command,
+                    includeMagic=self.autoCompleteIncludeMagic,
+                    includeSingle=self.autoCompleteIncludeSingle,
+                    includeDouble=self.autoCompleteIncludeDouble)
+        if list:
+            options = ' '.join(list)
+            #offset = 0
+            self.AutoCompShow(offset, options)
+
+    def autoCallTipShow(self, command, insertcalltip = True, forceCallTip = False):
+        """Display argument spec and docstring in a popup window."""
+        if self.CallTipActive():
+            self.CallTipCancel()
+        (name, argspec, tip) = self.interp.getCallTip(command)
+        if tip:
+            dispatcher.send(signal='Shell.calltip', sender=self, calltip=tip)
+        if not self.autoCallTip and not forceCallTip:
+            return
+        if argspec and insertcalltip and self.callTipInsert:
+            startpos = self.GetCurrentPos()
+            self.write(argspec + ')')
+            endpos = self.GetCurrentPos()
+            self.SetSelection(endpos, startpos)
+        if tip:
+            curpos = self.GetCurrentPos()
+            tippos = curpos - (len(name) + 1)
+            fallback = curpos - self.GetColumn(curpos)
+            # In case there isn't enough room, only go back to the
+            # fallback.
+            tippos = max(tippos, fallback)
+            self.CallTipShow(tippos, tip)
+    
+    def OnCallTipAutoCompleteManually (self, shiftDown):
+        """AutoComplete and Calltips manually."""
+        if self.AutoCompActive():
+            self.AutoCompCancel()
+        currpos = self.GetCurrentPos()
+        stoppos = self.promptPosEnd
+
+        cpos = currpos
+        #go back until '.' is found
+        pointavailpos = -1
+        while cpos >= stoppos:
+            if self.GetCharAt(cpos) == ord ('.'):
+                pointavailpos = cpos
+                break
+            cpos -= 1
+
+        #word from non whitespace until '.'
+        if pointavailpos != -1:
+            #look backward for first whitespace char
+            textbehind = self.GetTextRange (pointavailpos + 1, currpos)
+            pointavailpos += 1
+
+            if not shiftDown:
+                #call AutoComplete
+                stoppos = self.promptPosEnd
+                textbefore = self.GetTextRange(stoppos, pointavailpos)
+                self.autoCompleteShow(textbefore, len (textbehind))
+            else:
+                #call CallTips
+                cpos = pointavailpos
+                begpos = -1
+                while cpos > stoppos:
+                    if chr(self.GetCharAt(cpos)).isspace():
+                        begpos = cpos
+                        break
+                    cpos -= 1
+                if begpos == -1:
+                    begpos = cpos
+                ctips = self.GetTextRange (begpos, currpos)
+                ctindex = ctips.find ('(')
+                if ctindex != -1 and not self.CallTipActive():
+                    #insert calltip, if current pos is '(', otherwise show it only
+                    self.autoCallTipShow(ctips[:ctindex + 1], 
+                        self.GetCharAt(currpos - 1) == ord('(') and self.GetCurrentPos() == self.GetTextLength(),
+                        True)
+                
+
+    def writeOut(self, text):
+        """Replacement for stdout."""
+        self.write(text)
+
+    def writeErr(self, text):
+        """Replacement for stderr."""
+        self.write(text)
+
+    def redirectStdin(self, redirect=True):
+        """If redirect is true then sys.stdin will come from the shell."""
+        if redirect:
+            sys.stdin = self.reader
+        else:
+            sys.stdin = self.stdin
+
+    def redirectStdout(self, redirect=True):
+        """If redirect is true then sys.stdout will go to the shell."""
+        if redirect:
+            sys.stdout = PseudoFileOut(self.writeOut)
+        else:
+            sys.stdout = self.stdout
+
+    def redirectStderr(self, redirect=True):
+        """If redirect is true then sys.stderr will go to the shell."""
+        if redirect:
+            sys.stderr = PseudoFileErr(self.writeErr)
+        else:
+            sys.stderr = self.stderr
+
+    def CanCut(self):
+        """Return true if text is selected and can be cut."""
+        if self.GetSelectionStart() != self.GetSelectionEnd() \
+               and self.GetSelectionStart() >= self.promptPosEnd \
+               and self.GetSelectionEnd() >= self.promptPosEnd:
+            return True
+        else:
+            return False
+
+    def CanPaste(self):
+        """Return true if a paste should succeed."""
+        if self.CanEdit() and editwindow.EditWindow.CanPaste(self):
+            return True
+        else:
+            return False
+
+    def CanEdit(self):
+        """Return true if editing should succeed."""
+        if self.GetSelectionStart() != self.GetSelectionEnd():
+            if self.GetSelectionStart() >= self.promptPosEnd \
+                   and self.GetSelectionEnd() >= self.promptPosEnd:
+                return True
+            else:
+                return False
+        else:
+            return self.GetCurrentPos() >= self.promptPosEnd
+
+    def Cut(self):
+        """Remove selection and place it on the clipboard."""
+        if self.CanCut() and self.CanCopy():
+            if self.AutoCompActive():
+                self.AutoCompCancel()
+            if self.CallTipActive():
+                self.CallTipCancel()
+            self.Copy()
+            self.ReplaceSelection('')
+
+    def Copy(self):
+        """Copy selection and place it on the clipboard."""
+        if self.CanCopy():
+            ps1 = str(sys.ps1)
+            ps2 = str(sys.ps2)
+            command = self.GetSelectedText()
+            command = command.replace(os.linesep + ps2, os.linesep)
+            command = command.replace(os.linesep + ps1, os.linesep)
+            command = self.lstripPrompt(text=command)
+            data = wx.TextDataObject(command)
+            self._clip(data)
+
+    def CopyWithPrompts(self):
+        """Copy selection, including prompts, and place it on the clipboard."""
+        if self.CanCopy():
+            command = self.GetSelectedText()
+            data = wx.TextDataObject(command)
+            self._clip(data)
+
+    def CopyWithPromptsPrefixed(self):
+        """Copy selection, including prompts prefixed with four
+        spaces, and place it on the clipboard."""
+        if self.CanCopy():
+            command = self.GetSelectedText()
+            spaces = ' ' * 4
+            command = spaces + command.replace(os.linesep,
+                                               os.linesep + spaces)
+            data = wx.TextDataObject(command)
+            self._clip(data)
+
+    def _clip(self, data):
+        if wx.TheClipboard.Open():
+            wx.TheClipboard.UsePrimarySelection(False)
+            wx.TheClipboard.SetData(data)
+            wx.TheClipboard.Flush()
+            wx.TheClipboard.Close()
+
+    def Paste(self):
+        """Replace selection with clipboard contents."""
+        if self.CanPaste() and wx.TheClipboard.Open():
+            ps2 = str(sys.ps2)
+            if wx.TheClipboard.IsSupported(wx.DataFormat(wx.DF_TEXT)):
+                data = wx.TextDataObject()
+                if wx.TheClipboard.GetData(data):
+                    self.ReplaceSelection('')
+                    command = data.GetText()
+                    command = command.rstrip()
+                    command = self.fixLineEndings(command)
+                    command = self.lstripPrompt(text=command)
+                    command = command.replace(os.linesep + ps2, '\n')
+                    command = command.replace(os.linesep, '\n')
+                    command = command.replace('\n', os.linesep + ps2)
+                    self.write(command)
+            wx.TheClipboard.Close()
+
+
+    def PasteAndRun(self):
+        """Replace selection with clipboard contents, run commands."""
+        text = ''
+        if wx.TheClipboard.Open():
+            if wx.TheClipboard.IsSupported(wx.DataFormat(wx.DF_TEXT)):
+                data = wx.TextDataObject()
+                if wx.TheClipboard.GetData(data):
+                    text = data.GetText()
+            wx.TheClipboard.Close()
+        if text:
+            self.Execute(text)
+            
+
+    def Execute(self, text):
+        """Replace selection with text and run commands."""
+        ps1 = str(sys.ps1)
+        ps2 = str(sys.ps2)
+        endpos = self.GetTextLength()
+        self.SetCurrentPos(endpos)
+        startpos = self.promptPosEnd
+        self.SetSelection(startpos, endpos)
+        self.ReplaceSelection('')
+        text = text.lstrip()
+        text = self.fixLineEndings(text)
+        text = self.lstripPrompt(text)
+        text = text.replace(os.linesep + ps1, '\n')
+        text = text.replace(os.linesep + ps2, '\n')
+        text = text.replace(os.linesep, '\n')
+        lines = text.split('\n')
+        commands = []
+        command = ''
+        for line in lines:
+            if line.strip() == ps2.strip():
+                # If we are pasting from something like a
+                # web page that drops the trailing space
+                # from the ps2 prompt of a blank line.
+                line = ''
+            lstrip = line.lstrip()
+            if line.strip() != '' and lstrip == line and \
+                    lstrip[:4] not in ['else','elif'] and \
+                    lstrip[:6] != 'except':
+                # New command.
+                if command:
+                    # Add the previous command to the list.
+                    commands.append(command)
+                # Start a new command, which may be multiline.
+                command = line
+            else:
+                # Multiline command. Add to the command.
+                command += '\n'
+                command += line
+        commands.append(command)
+        for command in commands:
+            command = command.replace('\n', os.linesep + ps2)
+            self.write(command)
+            self.processLine()
+
+
+    def wrap(self, wrap=True):
+        """Sets whether text is word wrapped."""
+        try:
+            self.SetWrapMode(wrap)
+        except AttributeError:
+            return 'Wrapping is not available in this version.'
+
+    def zoom(self, points=0):
+        """Set the zoom level.
+
+        This number of points is added to the size of all fonts.  It
+        may be positive to magnify or negative to reduce."""
+        self.SetZoom(points)
+
+
+
+    def LoadSettings(self, config):
+        self.autoComplete              = config.ReadBool('Options/AutoComplete', True)
+        self.autoCompleteIncludeMagic  = config.ReadBool('Options/AutoCompleteIncludeMagic', True)
+        self.autoCompleteIncludeSingle = config.ReadBool('Options/AutoCompleteIncludeSingle', True)
+        self.autoCompleteIncludeDouble = config.ReadBool('Options/AutoCompleteIncludeDouble', True)
+
+        self.autoCallTip = config.ReadBool('Options/AutoCallTip', True)
+        self.callTipInsert = config.ReadBool('Options/CallTipInsert', True)
+        self.SetWrapMode(config.ReadBool('View/WrapMode', True))
+
+        useAA = config.ReadBool('Options/UseAntiAliasing', self.GetUseAntiAliasing())
+        self.SetUseAntiAliasing(useAA)
+        self.lineNumbers = config.ReadBool('View/ShowLineNumbers', True)
+        self.setDisplayLineNumbers (self.lineNumbers)
+        zoom = config.ReadInt('View/Zoom/Shell', -99)
+        if zoom != -99:
+            self.SetZoom(zoom)
+
+
+    
+    def SaveSettings(self, config):
+        config.WriteBool('Options/AutoComplete', self.autoComplete)
+        config.WriteBool('Options/AutoCompleteIncludeMagic', self.autoCompleteIncludeMagic)
+        config.WriteBool('Options/AutoCompleteIncludeSingle', self.autoCompleteIncludeSingle)
+        config.WriteBool('Options/AutoCompleteIncludeDouble', self.autoCompleteIncludeDouble)
+        config.WriteBool('Options/AutoCallTip', self.autoCallTip)
+        config.WriteBool('Options/CallTipInsert', self.callTipInsert)
+        config.WriteBool('Options/UseAntiAliasing', self.GetUseAntiAliasing())
+        config.WriteBool('View/WrapMode', self.GetWrapMode())
+        config.WriteBool('View/ShowLineNumbers', self.lineNumbers)
+        config.WriteInt('View/Zoom/Shell', self.GetZoom())
+
+
+
+## NOTE: The DnD of file names is disabled until I can figure out how
+## best to still allow DnD of text.
+
+
+## #seb : File drag and drop
+## class FileDropTarget(wx.FileDropTarget):
+##     def __init__(self, obj):
+##         wx.FileDropTarget.__init__(self)
+##         self.obj = obj
+##     def OnDropFiles(self, x, y, filenames):
+##         if len(filenames) == 1:
+##             txt = 'r\"%s\"' % filenames[0]
+##         else:
+##             txt = '( '
+##             for f in filenames:
+##                 txt += 'r\"%s\" , ' % f
+##             txt += ')'
+##         self.obj.AppendText(txt)
+##         pos = self.obj.GetCurrentPos()
+##         self.obj.SetCurrentPos( pos )
+##         self.obj.SetSelection( pos, pos )
+
+
+
+## class TextAndFileDropTarget(wx.DropTarget):
+##     def __init__(self, shell):
+##         wx.DropTarget.__init__(self)
+##         self.shell = shell
+##         self.compdo = wx.DataObjectComposite()
+##         self.textdo = wx.TextDataObject()
+##         self.filedo = wx.FileDataObject()
+##         self.compdo.Add(self.textdo)
+##         self.compdo.Add(self.filedo, True)
+        
+##         self.SetDataObject(self.compdo)
+                
+##     def OnDrop(self, x, y):
+##         return True
+    
+##     def OnData(self, x, y, result):
+##         self.GetData()
+##         if self.textdo.GetTextLength() > 1:
+##             text = self.textdo.GetText()
+##             # *** Do somethign with the dragged text here...
+##             self.textdo.SetText('')
+##         else:
+##             filenames = str(self.filename.GetFilenames())
+##             if len(filenames) == 1:
+##                 txt = 'r\"%s\"' % filenames[0]
+##             else:
+##                 txt = '( '
+##                 for f in filenames:
+##                     txt += 'r\"%s\" , ' % f
+##                 txt += ')'
+##             self.shell.AppendText(txt)
+##             pos = self.shell.GetCurrentPos()
+##             self.shell.SetCurrentPos( pos )
+##             self.shell.SetSelection( pos, pos )
+
+##         return result
+