]> git.saurik.com Git - wxWidgets.git/commitdiff
new version of PyCrust
authorRobin Dunn <robin@alldunn.com>
Thu, 16 Aug 2001 17:48:52 +0000 (17:48 +0000)
committerRobin Dunn <robin@alldunn.com>
Thu, 16 Aug 2001 17:48:52 +0000 (17:48 +0000)
git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@11395 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775

12 files changed:
wxPython/wxPython/lib/PyCrust/.cvsignore [new file with mode: 0644]
wxPython/wxPython/lib/PyCrust/PyCrust.ico [new file with mode: 0644]
wxPython/wxPython/lib/PyCrust/PyCrust.py
wxPython/wxPython/lib/PyCrust/PyCrustEditor.py [deleted file]
wxPython/wxPython/lib/PyCrust/PyCrustInterp.py [deleted file]
wxPython/wxPython/lib/PyCrust/PyCrustShell.py [deleted file]
wxPython/wxPython/lib/PyCrust/PyCrustVersion.py [deleted file]
wxPython/wxPython/lib/PyCrust/README.txt [new file with mode: 0644]
wxPython/wxPython/lib/PyCrust/interpreter.py [new file with mode: 0644]
wxPython/wxPython/lib/PyCrust/introspect.py
wxPython/wxPython/lib/PyCrust/shell.py [new file with mode: 0644]
wxPython/wxPython/lib/PyCrust/version.py [new file with mode: 0644]

diff --git a/wxPython/wxPython/lib/PyCrust/.cvsignore b/wxPython/wxPython/lib/PyCrust/.cvsignore
new file mode 100644 (file)
index 0000000..9020783
--- /dev/null
@@ -0,0 +1,3 @@
+*.pyc
+*.BAK
+*.$$$
\ No newline at end of file
diff --git a/wxPython/wxPython/lib/PyCrust/PyCrust.ico b/wxPython/wxPython/lib/PyCrust/PyCrust.ico
new file mode 100644 (file)
index 0000000..bb29c8e
Binary files /dev/null and b/wxPython/wxPython/lib/PyCrust/PyCrust.ico differ
index 43423d65d57d97ed3a19eb04dee4dd18d9d7485c..84edad7ca06ff1b3b9ae848600af62c6c735d570 100644 (file)
@@ -9,8 +9,16 @@ __version__ = "$Revision$"[11:-2]
 
 from wxPython.wx import *
 
-from PyCrustVersion import version
-from PyCrustShell import Shell
+from version import VERSION
+from shell import Shell
+
+ID_AUTOCOMP = NewId()
+ID_AUTOCOMP_SHOW = NewId()
+ID_AUTOCOMP_INCLUDE_MAGIC = NewId()
+ID_AUTOCOMP_INCLUDE_SINGLE = NewId()
+ID_AUTOCOMP_INCLUDE_DOUBLE = NewId()
+ID_CALLTIPS = NewId()
+ID_CALLTIPS_SHOW = NewId()
 
 
 class Frame(wxFrame):
@@ -18,15 +26,17 @@ class Frame(wxFrame):
     def __init__(self, parent, id, title):
         """Create the main frame object for the application."""
         wxFrame.__init__(self, parent, id, title)
-        intro = 'Welcome To PyCrust %s - The Flakiest Python Shell' % version
+        intro = 'Welcome To PyCrust %s - The Flakiest Python Shell' % VERSION
         self.CreateStatusBar()
         self.SetStatusText(intro)
+        self.icon = wxIcon('PyCrust.ico', wxBITMAP_TYPE_ICO)
+        self.SetIcon(self.icon)
         self.createMenus()
-        # Create the shell, which will create a default editor and
-        # a default interpreter.
-        self.shell = Shell(editorParent=self, introText=intro)
-        # Override the editor so that status messages go to the status bar.
-        self.shell.editor.setStatusText = self.SetStatusText
+        # Create the shell, which will create a default interpreter.
+        locals = {'__app__': 'PyCrust Application'}
+        self.shell = Shell(parent=self, id=-1, introText=intro, locals=locals)
+        # Override the shell so that status messages go to the status bar.
+        self.shell.setStatusText = self.SetStatusText
 
     def createMenus(self):
         m = self.fileMenu = wxMenu()
@@ -44,6 +54,26 @@ class Frame(wxFrame):
         m.Append(wxID_CLEAR, 'Cle&ar \tDel', 'Delete the selection')
         m.Append(wxID_SELECTALL, 'Select A&ll \tCtrl+A', 'Select all text')
 
+        m = self.autocompMenu = wxMenu()
+        m.Append(ID_AUTOCOMP_SHOW, 'Show Auto Completion', \
+                 'Show auto completion during dot syntax', checkable=1)
+        m.Append(ID_AUTOCOMP_INCLUDE_MAGIC, 'Include Magic Attributes', \
+                 'Include attributes visible to __getattr__ and __setattr__', checkable=1)
+        m.Append(ID_AUTOCOMP_INCLUDE_SINGLE, 'Include Single Underscores', \
+                 'Include attibutes prefixed by a single underscore', checkable=1)
+        m.Append(ID_AUTOCOMP_INCLUDE_DOUBLE, 'Include Double Underscores', \
+                 'Include attibutes prefixed by a double underscore', checkable=1)
+
+        m = self.calltipsMenu = wxMenu()
+        m.Append(ID_CALLTIPS_SHOW, 'Show Call Tips', \
+                 'Show call tips with argument specifications', checkable=1)
+
+        m = self.optionsMenu = wxMenu()
+        m.AppendMenu(ID_AUTOCOMP, '&Auto Completion', self.autocompMenu, \
+                     'Auto Completion Options')
+        m.AppendMenu(ID_CALLTIPS, '&Call Tips', self.calltipsMenu, \
+                     'Call Tip Options')
+
         m = self.helpMenu = wxMenu()
         m.AppendSeparator()
         m.Append(wxID_ABOUT, '&About...', 'About PyCrust')
@@ -51,6 +81,7 @@ class Frame(wxFrame):
         b = self.menuBar = wxMenuBar()
         b.Append(self.fileMenu, '&File')
         b.Append(self.editMenu, '&Edit')
+        b.Append(self.optionsMenu, '&Options')
         b.Append(self.helpMenu, '&Help')
         self.SetMenuBar(b)
 
@@ -63,6 +94,11 @@ class Frame(wxFrame):
         EVT_MENU(self, wxID_CLEAR, self.OnClear)
         EVT_MENU(self, wxID_SELECTALL, self.OnSelectAll)
         EVT_MENU(self, wxID_ABOUT, self.OnAbout)
+        EVT_MENU(self, ID_AUTOCOMP_SHOW, self.OnAutoCompleteShow)
+        EVT_MENU(self, ID_AUTOCOMP_INCLUDE_MAGIC, self.OnAutoCompleteIncludeMagic)
+        EVT_MENU(self, ID_AUTOCOMP_INCLUDE_SINGLE, self.OnAutoCompleteIncludeSingle)
+        EVT_MENU(self, ID_AUTOCOMP_INCLUDE_DOUBLE, self.OnAutoCompleteIncludeDouble)
+        EVT_MENU(self, ID_CALLTIPS_SHOW, self.OnCallTipsShow)
 
         EVT_UPDATE_UI(self, wxID_UNDO, self.OnUpdateMenu)
         EVT_UPDATE_UI(self, wxID_REDO, self.OnUpdateMenu)
@@ -70,58 +106,90 @@ class Frame(wxFrame):
         EVT_UPDATE_UI(self, wxID_COPY, self.OnUpdateMenu)
         EVT_UPDATE_UI(self, wxID_PASTE, self.OnUpdateMenu)
         EVT_UPDATE_UI(self, wxID_CLEAR, self.OnUpdateMenu)
+        EVT_UPDATE_UI(self, ID_AUTOCOMP_SHOW, self.OnUpdateMenu)
+        EVT_UPDATE_UI(self, ID_AUTOCOMP_INCLUDE_MAGIC, self.OnUpdateMenu)
+        EVT_UPDATE_UI(self, ID_AUTOCOMP_INCLUDE_SINGLE, self.OnUpdateMenu)
+        EVT_UPDATE_UI(self, ID_AUTOCOMP_INCLUDE_DOUBLE, self.OnUpdateMenu)
+        EVT_UPDATE_UI(self, ID_CALLTIPS_SHOW, self.OnUpdateMenu)
 
     def OnExit(self, event):
         self.Close(true)
 
     def OnUndo(self, event):
-        self.shell.editor.Undo()
+        self.shell.Undo()
 
     def OnRedo(self, event):
-        self.shell.editor.Redo()
+        self.shell.Redo()
 
     def OnCut(self, event):
-        self.shell.editor.Cut()
+        self.shell.Cut()
 
     def OnCopy(self, event):
-        self.shell.editor.Copy()
+        self.shell.Copy()
 
     def OnPaste(self, event):
-        self.shell.editor.Paste()
+        self.shell.Paste()
 
     def OnClear(self, event):
-        self.shell.editor.Clear()
+        self.shell.Clear()
 
     def OnSelectAll(self, event):
-        self.shell.editor.SelectAll()
+        self.shell.SelectAll()
 
     def OnAbout(self, event):
         """Display an About PyCrust window."""
         title = 'About PyCrust'
-        text = 'PyCrust %s\n\n' % version + \
+        text = 'PyCrust %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.'
+               'the other half is still in the oven.\n\n' + \
+               'Shell Revision: %s\n' % self.shell.revision + \
+               'Interpreter Revision: %s\n' % self.shell.interp.revision
         dialog = wxMessageDialog(self, text, title, wxOK | wxICON_INFORMATION)
         dialog.ShowModal()
         dialog.Destroy()
 
+    def OnAutoCompleteShow(self, event):
+        self.shell.autoComplete = event.IsChecked()
+
+    def OnAutoCompleteIncludeMagic(self, event):
+        self.shell.autoCompleteIncludeMagic = event.IsChecked()
+
+    def OnAutoCompleteIncludeSingle(self, event):
+        self.shell.autoCompleteIncludeSingle = event.IsChecked()
+
+    def OnAutoCompleteIncludeDouble(self, event):
+        self.shell.autoCompleteIncludeDouble = event.IsChecked()
+
+    def OnCallTipsShow(self, event):
+        self.shell.autoCallTip = event.IsChecked()
+
     def OnUpdateMenu(self, event):
-        """Update menu items based on which should be enabled/disabled."""
+        """Update menu items based on current status."""
         id = event.GetId()
         if id == wxID_UNDO:
-            event.Enable(self.shell.editor.CanUndo())
+            event.Enable(self.shell.CanUndo())
         elif id == wxID_REDO:
-            event.Enable(self.shell.editor.CanRedo())
+            event.Enable(self.shell.CanRedo())
         elif id == wxID_CUT:
-            event.Enable(self.shell.editor.CanCut())
+            event.Enable(self.shell.CanCut())
         elif id == wxID_COPY:
-            event.Enable(self.shell.editor.CanCopy())
+            event.Enable(self.shell.CanCopy())
         elif id == wxID_PASTE:
-            event.Enable(self.shell.editor.CanPaste())
+            event.Enable(self.shell.CanPaste())
         elif id == wxID_CLEAR:
-            event.Enable(self.shell.editor.CanCut())
-
+            event.Enable(self.shell.CanCut())
+        elif id == ID_AUTOCOMP_SHOW:
+            event.Check(self.shell.autoComplete)
+        elif id == ID_AUTOCOMP_INCLUDE_MAGIC:
+            event.Check(self.shell.autoCompleteIncludeMagic)
+        elif id == ID_AUTOCOMP_INCLUDE_SINGLE:
+            event.Check(self.shell.autoCompleteIncludeSingle)
+        elif id == ID_AUTOCOMP_INCLUDE_DOUBLE:
+            event.Check(self.shell.autoCompleteIncludeDouble)
+        elif id == ID_CALLTIPS_SHOW:
+            event.Check(self.shell.autoCallTip)
+            
 
 class App(wxApp):
     def OnInit(self):
diff --git a/wxPython/wxPython/lib/PyCrust/PyCrustEditor.py b/wxPython/wxPython/lib/PyCrust/PyCrustEditor.py
deleted file mode 100644 (file)
index 458e0ad..0000000
+++ /dev/null
@@ -1,349 +0,0 @@
-
-__author__ = "Patrick K. O'Brien <pobrien@orbtech.com>"
-__cvsid__ = "$Id$"
-__date__ = "July 1, 2001"
-__version__ = "$Revision$"[11:-2]
-
-from wxPython.wx import *
-from wxPython.stc import *
-
-import keyword
-import sys
-
-
-if wxPlatform == '__WXMSW__':
-    faces = { 'times'  : 'Times New Roman',
-              'mono'   : 'Courier New',
-              'helv'   : 'Lucida Console',
-              'lucida' : 'Lucida Console',
-              'other'  : 'Comic Sans MS',
-              'size'   : 8,
-              'lnsize' : 7,
-              'backcol': '#FFFFFF',
-            }
-else:  # GTK
-    faces = { 'times'  : 'Times',
-              'mono'   : 'Courier',
-              'helv'   : 'Helvetica',
-              'other'  : 'new century schoolbook',
-              'size'   : 9,
-              'lnsize' : 8,
-              'backcol': '#FFFFFF',
-            }
-
-
-class Editor(wxStyledTextCtrl):
-    """PyCrust Editor based on wxStyledTextCtrl."""
-    revision = __version__
-    def __init__(self, parent, id):
-        """Create a PyCrust editor object based on wxStyledTextCtrl."""
-        wxStyledTextCtrl.__init__(self, parent, id, style=wxCLIP_CHILDREN)
-        # Commands get pushed to a method determined by the outer shell.
-        #self.shellPush = pushMethod
-        # Keep track of the most recent prompt starting and ending positions.
-        self.promptPos = [0, 0]
-        # Keep track of multi-line commands.
-        self.more = 0
-        # Configure various defaults and user preferences.
-        self.config()
-        # Assign handlers for keyboard events.
-        EVT_KEY_DOWN(self, self.OnKeyDown)
-        EVT_CHAR(self, self.OnChar)
-
-    def config(self):
-        """Configure editor based on user preferences."""
-        self.SetMarginType(1, wxSTC_MARGIN_NUMBER)
-        self.SetMarginWidth(1, 40)
-        
-        self.SetLexer(wxSTC_LEX_PYTHON)
-        self.SetKeyWords(0, ' '.join(keyword.kwlist))
-
-        self.setStyles(faces)
-        self.SetViewWhiteSpace(0)
-        self.SetTabWidth(4)
-        self.SetUseTabs(0)
-        # Do we want to automatically pop up command completion options?
-        self.autoComplete = 1
-        self.autoCompleteCaseInsensitive = 1
-        self.AutoCompSetIgnoreCase(self.autoCompleteCaseInsensitive)
-        # De we want to automatically pop up command argument help?
-        self.autoCallTip = 1
-        self.CallTipSetBackground(wxColour(255, 255, 232))
-
-    def setStyles(self, faces):
-        """Configure font size, typeface and color for lexer."""
-        
-        # Default style
-        self.StyleSetSpec(wxSTC_STYLE_DEFAULT, "face:%(mono)s,size:%(size)d" % faces)
-
-        self.StyleClearAll()
-
-        # Built in styles
-        self.StyleSetSpec(wxSTC_STYLE_LINENUMBER, "back:#C0C0C0,face:%(mono)s,size:%(lnsize)d" % faces)
-        self.StyleSetSpec(wxSTC_STYLE_CONTROLCHAR, "face:%(mono)s" % faces)
-        self.StyleSetSpec(wxSTC_STYLE_BRACELIGHT, "fore:#0000FF,back:#FFFF88")
-        self.StyleSetSpec(wxSTC_STYLE_BRACEBAD, "fore:#FF0000,back:#FFFF88")
-
-        # Python styles
-        self.StyleSetSpec(wxSTC_P_DEFAULT, "face:%(mono)s" % faces)
-        self.StyleSetSpec(wxSTC_P_COMMENTLINE, "fore:#007F00,face:%(mono)s" % faces)
-        self.StyleSetSpec(wxSTC_P_NUMBER, "")
-        self.StyleSetSpec(wxSTC_P_STRING, "fore:#7F007F,face:%(mono)s" % faces)
-        self.StyleSetSpec(wxSTC_P_CHARACTER, "fore:#7F007F,face:%(mono)s" % faces)
-        self.StyleSetSpec(wxSTC_P_WORD, "fore:#00007F,bold")
-        self.StyleSetSpec(wxSTC_P_TRIPLE, "fore:#7F0000")
-        self.StyleSetSpec(wxSTC_P_TRIPLEDOUBLE, "fore:#000033,back:#FFFFE8")
-        self.StyleSetSpec(wxSTC_P_CLASSNAME, "fore:#0000FF,bold")
-        self.StyleSetSpec(wxSTC_P_DEFNAME, "fore:#007F7F,bold")
-        self.StyleSetSpec(wxSTC_P_OPERATOR, "")
-        self.StyleSetSpec(wxSTC_P_IDENTIFIER, "")
-        self.StyleSetSpec(wxSTC_P_COMMENTBLOCK, "fore:#7F7F7F")
-        self.StyleSetSpec(wxSTC_P_STRINGEOL, "fore:#000000,face:%(mono)s,back:#E0C0E0,eolfilled" % faces)
-
-    def OnKeyDown(self, event):
-        """Key down event handler.
-        
-        The main goal here is to not allow modifications to previous 
-        lines of text.
-        """
-        key = event.KeyCode()
-        currpos = self.GetCurrentPos()
-        stoppos = self.promptPos[1]
-        # If the auto-complete window is up let it do its thing.
-        if self.AutoCompActive():
-            event.Skip()
-        # Return is used to submit a command to the interpreter.
-        elif key == WXK_RETURN:
-            if self.CallTipActive: self.CallTipCancel()
-            self.processLine()
-        # Home needs to be aware of the prompt.
-        elif key == WXK_HOME:
-            if currpos >= stoppos:
-                self.SetCurrentPos(stoppos)
-                self.SetAnchor(stoppos)
-            else:
-                event.Skip()
-        # Basic navigation keys should work anywhere.
-        elif key in (WXK_END, WXK_LEFT, WXK_RIGHT, WXK_UP, WXK_DOWN, \
-                     WXK_PRIOR, WXK_NEXT):
-            event.Skip()
-        # Don't backspace over the latest prompt.
-        elif key == WXK_BACK:
-            if currpos > stoppos:
-                event.Skip()
-        # Only allow these keys after the latest prompt.
-        elif key in (WXK_TAB, WXK_DELETE):
-            if currpos >= stoppos:
-                event.Skip()
-        # Don't toggle between insert mode and overwrite mode.
-        elif key == WXK_INSERT:
-            pass
-        else:
-            event.Skip()
-
-    def OnChar(self, event):
-        """Keypress event handler.
-        
-        The main goal here is to not allow modifications to previous 
-        lines of text.
-        """
-        key = event.KeyCode()
-        currpos = self.GetCurrentPos()
-        stoppos = self.promptPos[1]
-        if currpos >= stoppos:
-            if key == 46:
-                # "." The dot or period key activates auto completion.
-                # Get the command between the prompt and the cursor.
-                # Add a dot to the end of the command.
-                command = self.GetTextRange(stoppos, currpos) + '.'
-                self.write('.')
-                if self.autoComplete: self.autoCompleteShow(command)
-            elif key == 40:
-                # "(" 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.
-                command = self.GetTextRange(stoppos, currpos) + '('
-                self.write('(')
-                if self.autoCallTip: self.autoCallTipShow(command)
-            else:
-                # Allow the normal event handling to take place.
-                event.Skip()
-        else:
-            pass
-
-    def setStatusText(self, text):
-        """Display status information."""
-        
-        # This method will most likely be replaced by the enclosing app
-        # to do something more interesting, like write to a status bar.
-        print text
-
-    def autoCompleteShow(self, command):
-        """Display auto-completion popup list."""
-        list = self.getAutoCompleteList(command)
-        if list:
-            options = ' '.join(list)
-            offset = 0
-            self.AutoCompShow(offset, options)
-
-    def getAutoCompleteList(self, command):
-        """Return list of auto-completion options for command."""
-        
-        # This method needs to be replaced by the enclosing app
-        # to get the proper auto complete list from the interpreter.
-        return []
-
-    def autoCallTipShow(self, command):
-        """Display argument spec and docstring in a popup bubble thingie."""
-        if self.CallTipActive: self.CallTipCancel()
-        tip = self.getCallTip(command)
-        if tip:
-            offset = self.GetCurrentPos()
-            self.CallTipShow(offset, tip)
-
-    def getCallTip(self, command):
-        """Return arguments and docstring for command."""
-
-        # This method needs to be replaced by the enclosing app
-        # to get the proper auto complete list from the interpreter.
-        return ''
-
-    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 editor.
-        
-        # Grab information about the current line.
-        thepos = self.GetCurrentPos()
-        theline = self.GetCurrentLine()
-        thetext = self.GetCurLine()[0]
-        command = self.getCommand(thetext)
-        # Go to the very bottom of the editor.
-        endpos = self.GetTextLength()
-        self.SetCurrentPos(endpos)
-        endline = self.GetCurrentLine()
-        # If they hit RETURN on the last line, execute the command.
-        if theline == endline:
-            self.push(command)
-        # Otherwise, replace the last line with the new line.
-        else:
-            # If the new line contains a command (even an invalid one).
-            if command:
-                startpos = self.PositionFromLine(endline)
-                self.SetSelection(startpos, endpos)
-                self.ReplaceSelection('')
-                self.prompt()
-                self.write(command)
-            # Otherwise, put the cursor back where we started.
-            else:
-                self.SetCurrentPos(thepos)
-                self.SetAnchor(thepos)
-
-    def getCommand(self, text):
-        """Extract a command from text which may include a shell prompt.
-        
-        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. Do this in the interpreter
-        # with a line number, prompt, command dictionary. For the history, perhaps.
-        ps1 = str(sys.ps1)
-        ps1size = len(ps1)
-        ps2 = str(sys.ps2)
-        ps2size = len(ps2)
-        text = text.rstrip()
-        # Strip the prompt off the front of text leaving just the command.
-        if text[:ps1size] == ps1:
-            command = text[ps1size:]
-        elif text[:ps2size] == ps2:
-            command = text[ps2size:]
-        else:
-            command = ''
-        return command
-    
-    def push(self, command):
-        """Start a new line, send command to the shell, display a prompt."""
-        self.write('\n')
-        self.more = self.shellPush(command)
-        self.prompt()
-        # Keep the undo feature from undoing previous responses. The only
-        # thing that can be undone is stuff typed after the prompt, before
-        # hitting enter. After they hit enter it becomes permanent.
-        self.EmptyUndoBuffer()
-        
-    def clear(self):
-        """Delete all text from the editor."""
-        self.ClearAll()
-        
-    def prompt(self):
-        """Display appropriate prompt for the context, either ps1 or ps2.
-        
-        If this is a continuation line, autoindent as necessary.
-        """
-        if self.more:
-            prompt = str(sys.ps2)
-        else:
-            prompt = str(sys.ps1)
-        pos = self.GetCurLine()[1]
-        if pos > 0: self.write('\n')
-        self.promptPos[0] = self.GetCurrentPos()
-        self.write(prompt)
-        self.promptPos[1] = self.GetCurrentPos()
-        # XXX Add some autoindent magic here if more.
-        if self.more:
-            self.write('\t')  # Temporary hack indentation.
-        self.EnsureCaretVisible()
-        self.ScrollToColumn(0)
-    
-    def readIn(self):
-        """Replacement for stdin."""
-        prompt = 'Please enter your response:'
-        dialog = wxTextEntryDialog(None, prompt, \
-                                   'Input Dialog (Standard)', '')
-        try:
-            if dialog.ShowModal() == wxID_OK:
-                text = dialog.GetValue()
-                self.write(text + '\n')
-                return text
-        finally:
-            dialog.Destroy()
-        return ''
-
-    def readRaw(self, prompt='Please enter your response:'):
-        """Replacement for raw_input."""
-        dialog = wxTextEntryDialog(None, prompt, \
-                                   'Input Dialog (Raw)', '')
-        try:
-            if dialog.ShowModal() == wxID_OK:
-                text = dialog.GetValue()
-                return text
-        finally:
-            dialog.Destroy()
-        return ''
-
-    def write(self, text):
-        """Display text in the editor."""
-        self.AddText(text)
-        self.EnsureCaretVisible()
-        #self.ScrollToColumn(0)
-    
-    def writeOut(self, text):
-        """Replacement for stdout."""
-        self.write(text)
-    
-    def writeErr(self, text):
-        """Replacement for stderr."""
-        self.write(text)
-    
-    def CanCut(self):
-        """Return true if text is selected and can be cut."""
-        return self.GetSelectionStart() != self.GetSelectionEnd()
-    
-    def CanCopy(self):
-        """Return true if text is selected and can be copied."""
-        return self.GetSelectionStart() != self.GetSelectionEnd()
-
diff --git a/wxPython/wxPython/lib/PyCrust/PyCrustInterp.py b/wxPython/wxPython/lib/PyCrust/PyCrustInterp.py
deleted file mode 100644 (file)
index dd606c2..0000000
+++ /dev/null
@@ -1,81 +0,0 @@
-
-__author__ = "Patrick K. O'Brien <pobrien@orbtech.com>"
-__cvsid__ = "$Id$"
-__date__ = "July 1, 2001"
-__version__ = "$Revision$"[11:-2]
-
-import os
-import sys
-
-from code import InteractiveInterpreter
-import introspect
-
-
-class Interpreter(InteractiveInterpreter):
-    """PyCrust Interpreter based on code.InteractiveInterpreter."""
-    revision = __version__
-    def __init__(self, locals=None, rawin=None,
-                 stdin=sys.stdin, stdout=sys.stdout, stderr=sys.stderr):
-        """Create an interactive interpreter object."""
-        InteractiveInterpreter.__init__(self, locals=locals)
-        self.stdin = stdin
-        self.stdout = stdout
-        self.stderr = stderr
-        if rawin is not None:
-            import __builtin__
-            __builtin__.raw_input = rawin
-            del __builtin__
-        copyright = 'Type "copyright", "credits" or "license" for more information.'
-        self.introText = 'Python %s on %s\n%s' % \
-                         (sys.version, sys.platform, copyright)
-        try:
-            sys.ps1
-        except AttributeError:
-            sys.ps1 = '>>> '
-        try:
-            sys.ps2
-        except AttributeError:
-            sys.ps2 = '... '
-        self.more = 0
-        self.commandBuffer = []  # List of lists to support recursive push().
-        self.commandHistory = []
-        self.startupScript = os.environ.get('PYTHONSTARTUP')
-
-    def push(self, command):
-        """Send command to the interpreter to be executed.
-        
-        Because this may be called recursively, we append a new list 
-        onto the commandBuffer list and then append commands into that.
-        If the passed in command is part of a multi-line command we keep
-        appending the pieces to the last list in commandBuffer until we
-        have a complete command, then, finally, we delete that last list.
-        """ 
-        if not self.more: self.commandBuffer.append([])
-        self.commandBuffer[-1].append(command)
-        source = '\n'.join(self.commandBuffer[-1])
-        self.more = self.runsource(source)
-        if not self.more: del self.commandBuffer[-1]
-        return self.more
-        
-    def runsource(self, source):
-        """Compile and run source code in the interpreter."""
-        stdin, stdout, stderr = sys.stdin, sys.stdout, sys.stderr
-        sys.stdin = self.stdin
-        sys.stdout = self.stdout
-        sys.stderr = self.stderr
-        more = InteractiveInterpreter.runsource(self, source)
-        sys.stdin, sys.stdout, sys.stderr = stdin, stdout, stderr
-        return more
-        
-    def getAutoCompleteList(self, command=''):
-        """Return list of auto-completion options for a command.
-        
-        The list of options will be based on the locals namespace."""
-        return introspect.getAutoCompleteList(command, self.locals)
-
-    def getCallTip(self, command=''):
-        """Return call tip text for a command.
-        
-        The call tip information will be based on the locals namespace."""
-        return introspect.getCallTip(command, self.locals)
-
diff --git a/wxPython/wxPython/lib/PyCrust/PyCrustShell.py b/wxPython/wxPython/lib/PyCrust/PyCrustShell.py
deleted file mode 100644 (file)
index 07c232d..0000000
+++ /dev/null
@@ -1,180 +0,0 @@
-"""
-"""
-__author__ = "Patrick K. O'Brien <pobrien@orbtech.com>"
-__cvsid__ = "$Id$"
-__date__ = "July 1, 2001"
-__version__ = "$Revision$"[11:-2]
-
-import os
-from PyCrustVersion import version
-
-class Shell:
-    """PyCrust Shell manages the Editor and Interpreter."""
-    name = 'PyCrust Shell'
-    revision = __version__
-    def __init__(self, editorParent=None, introText='', editor=None, interp=None):
-        """Create a PyCrust shell object to manage the editor and interpreter."""
-        try:
-            eval('crap')
-        except:
-            pass
-        self.introText = introText
-        # Create a default editor if one isn't provided.
-        if editor == None:
-            from PyCrustEditor import Editor
-            self.editor = Editor(editorParent, id=-1)
-        else:
-            self.editor = editor
-        # Link the editor to the shell so that the shell is a conduit for
-        # pushing commands to the interpreter.
-        self.editor.shellPush = self.shellPush
-        # Create a default interpreter if one isn't provided.
-        if interp == None:
-            from PyCrustInterp import Interpreter
-            from pseudo import PseudoFileIn, PseudoFileOut, PseudoFileErr
-            self.stdin = PseudoFileIn(self.editor.readIn)
-            self.stdout = PseudoFileOut(self.editor.writeOut)
-            self.stderr = PseudoFileErr(self.editor.writeErr)
-            # Override the default locals so we have something interesting.
-            locals = {'__name__': 'PyCrust',
-                      '__doc__': 'PyCrust, The Python Shell.',
-                      '__version__': version,
-                      }
-            self.interp = Interpreter(locals=locals,
-                                      rawin=self.editor.readRaw,
-                                      stdin=self.stdin,
-                                      stdout=self.stdout,
-                                      stderr=self.stderr)
-        else:
-            self.interp = interp
-        # XXX redo this using hasattr() or something so that we can link
-        # these if a provided editor has this method.
-        if editor == None or editor == self:
-            # Override so the auto complete list comes from the interpreter.
-            self.editor.getAutoCompleteList = self.interp.getAutoCompleteList
-            # Override so the call tip comes from the interpreter.
-            self.editor.getCallTip = self.interp.getCallTip
-        # Keep track of whether the interpreter needs more.
-        self.more = 0
-
-        try:
-            self.showIntro(self.introText)
-        except:
-            pass
-
-        try:
-            self.setBuiltinKeywords()
-        except:
-            pass
-
-        try:
-            self.setLocalShell()
-        except:
-            pass
-
-        # Do this last so the user has complete control over their
-        # environment. They can override anything they want.
-        try:
-            self.execStartupScript(self.interp.startupScript)
-        except:
-            pass
-
-    def destroy(self):
-        del self.editor
-        del self.stdin
-        del self.stdout
-        del self.stderr
-        del self.interp
-
-    def showIntro(self, text=''):
-        """Display introductory text in the shell editor."""
-        if text:
-            if text[-1] != '\n': text += '\n'
-            self.editor.write(text)
-        try:
-            self.editor.write(self.interp.introText)
-        except AttributeError:
-            pass
-
-    def setBuiltinKeywords(self):
-        """Create pseudo keywords as part of builtins.
-
-        This is a rather clever hack that sets "close", "exit" and "quit"
-        to a PseudoKeyword object so that we can make them do what we want.
-        In this case what we want is to call our self.quit() method.
-        The user can type "close", "exit" or "quit" without the final parens.
-        """
-        import __builtin__
-        from pseudo import PseudoKeyword
-        __builtin__.close = __builtin__.exit = __builtin__.quit = \
-            PseudoKeyword(self.quit)
-
-    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 prompt to 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.editor.write('Click on the close button to leave the application.')
-
-    def setLocalShell(self):
-        """Add 'shell' to locals."""
-        self.interp.locals['shell'] = self
-
-    def execStartupScript(self, startupScript):
-        """Execute the user's PYTHONSTARTUP script if they have one."""
-        if startupScript and os.path.isfile(startupScript):
-            startupText = 'Startup script executed: ' + startupScript
-            self.editor.push('print %s;execfile(%s)' % \
-                            (`startupText`, `startupScript`))
-        else:
-            self.editor.push('')
-
-    def run(self, command, prompt=1, verbose=1):
-        """Execute command within the shell as if it was typed in directly.
-        >>> shell.run('print "this"')
-        >>> print "this"
-        this
-        >>>
-        """
-        command = command.rstrip()
-        if prompt: self.editor.prompt()
-        if verbose: self.editor.write(command)
-        self.editor.push(command)
-
-    def runfile(self, filename):
-        """Execute all commands in file as if they were typed into the shell."""
-        file = open(filename)
-        try:
-            self.editor.prompt()
-            for command in file.readlines():
-                if command[:6] == 'shell.':  # Run shell methods silently.
-                    self.run(command, prompt=0, verbose=0)
-                else:
-                    self.run(command, prompt=0, verbose=1)
-        finally:
-            file.close()
-
-    def push(self, command):
-        """Send command to the interpreter for execution."""
-        self.more = self.interp.push(command)
-        return self.more
-
-    shellPush = push
-
-    def ask(self, prompt='Please enter your response:'):
-        """Get response from the user."""
-        return raw_input(prompt=prompt)
-
-    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 editor."""
-        self.editor.clear()
-
-
diff --git a/wxPython/wxPython/lib/PyCrust/PyCrustVersion.py b/wxPython/wxPython/lib/PyCrust/PyCrustVersion.py
deleted file mode 100644 (file)
index de8a0d0..0000000
+++ /dev/null
@@ -1,10 +0,0 @@
-"""Provides an object representing the current "version" or "release" of
-PyCrust as a whole. Individual classes, such as the shell, editor and
-interpreter, each have a revision property based on the CVS $Revision$."""
-
-__author__ = "Patrick K. O'Brien <pobrien@orbtech.com>"
-__cvsid__ = "$Id$"
-__date__ = "July 1, 2001"
-__version__ = "$Revision$"[11:-2]
-
-version = '0.5'
diff --git a/wxPython/wxPython/lib/PyCrust/README.txt b/wxPython/wxPython/lib/PyCrust/README.txt
new file mode 100644 (file)
index 0000000..73ad07b
--- /dev/null
@@ -0,0 +1,43 @@
+PyCrust - The Flakiest Python Shell
+Half-baked by Patrick K. O'Brien (pobrien@orbtech.com)
+======================================================
+
+What is PyCrust?
+----------------
+
+PyCrust is is an interactive Python Shell written in Python.
+PyCrust can be run standalone or integrated into other development
+environments or other Python applications.
+
+
+Where can I get the latest files and join the mailing lists?
+------------------------------------------------------------
+
+Latest PyCrust releases:
+http://sourceforge.net/project/showfiles.php?group_id=31263
+
+PyCrust home page:
+http://pycrust.sourceforge.net/
+
+SourceForge summary page:
+http://sourceforge.net/projects/pycrust/
+
+PyCrust Mailing lists:
+http://sourceforge.net/mail/?group_id=31263
+
+
+What else do I need to use PyCrust?
+-----------------------------------
+
+PyCrust requires Python 2.1 or later, and wxPython 2.3.1 or later.
+PyCrust uses wxPython and the Scintilla wrapper class (wxStyledTextCtrl).
+Python is available at http://www.python.org/.
+wxPython is available at http://www.wxpython.org/.
+
+
+What is the CVS information for this README file?
+-------------------------------------------------
+
+$Date$
+$Revision$
+$Id$
diff --git a/wxPython/wxPython/lib/PyCrust/interpreter.py b/wxPython/wxPython/lib/PyCrust/interpreter.py
new file mode 100644 (file)
index 0000000..5f12c01
--- /dev/null
@@ -0,0 +1,83 @@
+"""PyCrust Interpreter executes Python commands.
+"""
+
+__author__ = "Patrick K. O'Brien <pobrien@orbtech.com>"
+__cvsid__ = "$Id$"
+__date__ = "July 1, 2001"
+__version__ = "$Revision$"[11:-2]
+
+import os
+import sys
+
+from code import InteractiveInterpreter
+import introspect
+
+
+class Interpreter(InteractiveInterpreter):
+    """PyCrust Interpreter based on code.InteractiveInterpreter."""
+    revision = __version__
+    def __init__(self, locals=None, rawin=None,
+                 stdin=sys.stdin, stdout=sys.stdout, stderr=sys.stderr):
+        """Create an interactive interpreter object."""
+        InteractiveInterpreter.__init__(self, locals=locals)
+        self.stdin = stdin
+        self.stdout = stdout
+        self.stderr = stderr
+        if rawin is not None:
+            import __builtin__
+            __builtin__.raw_input = rawin
+            del __builtin__
+        copyright = 'Type "copyright", "credits" or "license" for more information.'
+        self.introText = 'Python %s on %s\n%s' % \
+                         (sys.version, sys.platform, copyright)
+        try:
+            sys.ps1
+        except AttributeError:
+            sys.ps1 = '>>> '
+        try:
+            sys.ps2
+        except AttributeError:
+            sys.ps2 = '... '
+        self.more = 0
+        self.commandBuffer = []  # List of lists to support recursive push().
+        self.commandHistory = []
+        self.startupScript = os.environ.get('PYTHONSTARTUP')
+
+    def push(self, command):
+        """Send command to the interpreter to be executed.
+        
+        Because this may be called recursively, we append a new list 
+        onto the commandBuffer list and then append commands into that.
+        If the passed in command is part of a multi-line command we keep
+        appending the pieces to the last list in commandBuffer until we
+        have a complete command, then, finally, we delete that last list.
+        """ 
+        if not self.more: self.commandBuffer.append([])
+        self.commandBuffer[-1].append(command)
+        source = '\n'.join(self.commandBuffer[-1])
+        self.more = self.runsource(source)
+        if not self.more: del self.commandBuffer[-1]
+        return self.more
+        
+    def runsource(self, source):
+        """Compile and run source code in the interpreter."""
+        stdin, stdout, stderr = sys.stdin, sys.stdout, sys.stderr
+        sys.stdin = self.stdin
+        sys.stdout = self.stdout
+        sys.stderr = self.stderr
+        more = InteractiveInterpreter.runsource(self, source)
+        sys.stdin, sys.stdout, sys.stderr = stdin, stdout, stderr
+        return more
+        
+    def getAutoCompleteList(self, command='', *args, **kwds):
+        """Return list of auto-completion options for a command.
+        
+        The list of options will be based on the locals namespace."""
+        return introspect.getAutoCompleteList(command, self.locals, *args, **kwds)
+
+    def getCallTip(self, command='', *args, **kwds):
+        """Return call tip text for a command.
+        
+        The call tip information will be based on the locals namespace."""
+        return introspect.getCallTip(command, self.locals, *args, **kwds)
+
index c9342c8a0c7dc78992925614effccb5abbfa1e67..8cf6ae85051e69d96b68bd9f9e90392786cb8579 100644 (file)
@@ -9,7 +9,8 @@ __version__ = "$Revision$"[11:-2]
 import inspect
 import string
 
-def getAutoCompleteList(command='', locals=None):
+def getAutoCompleteList(command='', locals=None, includeMagic=1, \
+                        includeSingle=1, includeDouble=1):
     """Return list of auto-completion options for command.
     
     The list of options will be based on the locals namespace."""
@@ -18,37 +19,45 @@ def getAutoCompleteList(command='', locals=None):
     root = getRoot(command, terminator='.')
     try:
         object = eval(root, locals)
-        attributes = getAttributes(object)
+        attributes = getAttributeNames(object)
+        if includeMagic:
+            try: attributes += object._getAttributeNames()
+            except: pass
+        if not includeSingle:
+            attributes = filter(lambda item: item[0]!='_' or item[1]=='_', attributes)
+        if not includeDouble:
+            attributes = filter(lambda item: item[:2]!='__', attributes)
         return attributes
     except:
         return []
     
-def getAttributes(object):
+def getAttributeNames(object):
     """Return list of unique attributes, including inherited, for an object."""
     attributes = []
     dict = {}
     # Remove duplicates from the attribute list.
-    for item in getAllAttributes(object):
+    for item in getAllAttributeNames(object):
         dict[item] = None
     attributes += dict.keys()
     attributes.sort()
     return attributes
 
-def getAllAttributes(object):
+def getAllAttributeNames(object):
     """Return list of all attributes, including inherited, for an object.
     
     Recursively walk through a class and all base classes.
     """
     attributes = []
-    try:
-        attributes += dir(object)
-        if hasattr(object, '__class__'):
-            attributes += getAllAttributes(object.__class__)
-        if hasattr(object, '__bases__'):
-            for base in object.__bases__:
-                attributes += getAllAttributes(base)
-    finally:
-        return attributes
+    # Get attributes available through the normal convention.
+    attributes += dir(object)
+    # For a class instance, get the attributes for the class.
+    if hasattr(object, '__class__'):
+        attributes += getAllAttributeNames(object.__class__)
+    # Also get attributes from any and all parent classes.
+    if hasattr(object, '__bases__'):
+        for base in object.__bases__:
+            attributes += getAllAttributeNames(base)
+    return attributes
 
 def getCallTip(command='', locals=None):
     """Return call tip text for a command.
@@ -119,22 +128,31 @@ def getRoot(command, terminator=None):
     
     The command would normally terminate with a "(" or ".". Anything after 
     the terminator will be dropped, allowing you to get back to the root.
+    Return only the root portion that can be eval()'d without side effect.
     """
     root = ''
     validChars = "._" + string.uppercase + string.lowercase + string.digits
-    # Remove all whitespace from the command.
-    command = ''.join(command.split())
-    # Deal with the terminator.
     if terminator:
+        # Drop the final terminator and anything that follows.
         pieces = command.split(terminator)
         if len(pieces) > 1:
-            # Drop the final terminator and anything that follows.
             command = terminator.join(pieces[:-1])
-    # Go backward through the command until we hit an "invalid" character.
-    i = len(command)
-    while i and command[i-1] in validChars:
-        i -= 1
-    # Grab everything from the "invalid" character to the end.
-    root = command[i:]
+    if command in ("''", '""', '""""""', '[]', '()', '{}'):
+        # Let empty type delimiter pairs go through.
+        root = command
+    else:
+        # Go backward through the command until we hit an "invalid" character.
+        i = len(command)
+        while i and command[i-1] in validChars:
+            i -= 1
+        # Detect situations where we are in the middle of a string.
+        # This code catches the simplest case, but needs to catch others.
+        if command[i-1] in ("'", '"'):
+            # Were in the middle of a string so we aren't dealing with an
+            # object and it would be misleading to return anything here.
+            root = ''
+        else:
+            # Grab everything from the "invalid" character to the end.
+            root = command[i:]
     return root
 
diff --git a/wxPython/wxPython/lib/PyCrust/shell.py b/wxPython/wxPython/lib/PyCrust/shell.py
new file mode 100644 (file)
index 0000000..0c71206
--- /dev/null
@@ -0,0 +1,478 @@
+"""PyCrust Shell is the gui text control in which a user interacts and types
+in commands to be sent to the interpreter. This particular shell is based on
+wxPython's wxStyledTextCtrl.
+"""
+
+__author__ = "Patrick K. O'Brien <pobrien@orbtech.com>"
+__cvsid__ = "$Id$"
+__date__ = "July 1, 2001"
+__version__ = "$Revision$"[11:-2]
+
+from wxPython.wx import *
+from wxPython.stc import *
+
+import keyword
+import os
+import sys
+
+from version import VERSION
+
+if wxPlatform == '__WXMSW__':
+    faces = { 'times'  : 'Times New Roman',
+              'mono'   : 'Courier New',
+              'helv'   : 'Lucida Console',
+              'lucida' : 'Lucida Console',
+              'other'  : 'Comic Sans MS',
+              'size'   : 8,
+              'lnsize' : 7,
+              'backcol': '#FFFFFF',
+            }
+else:  # GTK
+    faces = { 'times'  : 'Times',
+              'mono'   : 'Courier',
+              'helv'   : 'Helvetica',
+              'other'  : 'new century schoolbook',
+              'size'   : 9,
+              'lnsize' : 8,
+              'backcol': '#FFFFFF',
+            }
+
+
+class Shell(wxStyledTextCtrl):
+    """PyCrust Shell based on wxStyledTextCtrl."""
+    name = 'PyCrust Shell'
+    revision = __version__
+    def __init__(self, parent, id, introText='', locals=None, interp=None):
+        """Create a PyCrust Shell object."""
+        wxStyledTextCtrl.__init__(self, parent, id, style=wxCLIP_CHILDREN)
+        self.introText = introText
+        # Keep track of the most recent prompt starting and ending positions.
+        self.promptPos = [0, 0]
+        # Keep track of multi-line commands.
+        self.more = 0
+        # Assign handlers for keyboard events.
+        EVT_KEY_DOWN(self, self.OnKeyDown)
+        EVT_CHAR(self, self.OnChar)
+        # Create a default interpreter if one isn't provided.
+        if interp == None:
+            from interpreter import Interpreter
+            from pseudo import PseudoFileIn, PseudoFileOut, PseudoFileErr
+            self.stdin = PseudoFileIn(self.readIn)
+            self.stdout = PseudoFileOut(self.writeOut)
+            self.stderr = PseudoFileErr(self.writeErr)
+            # Override the default locals so we have something interesting.
+            self.locals = {'__name__': 'PyCrust', 
+                           '__doc__': 'PyCrust, The Python Shell.',
+                           '__version__': VERSION,
+                          }
+            # Add the dictionary that was passed in.
+            if locals:
+                self.locals.update(locals)
+            self.interp = Interpreter(locals=self.locals, 
+                                      rawin=self.readRaw,
+                                      stdin=self.stdin, 
+                                      stdout=self.stdout, 
+                                      stderr=self.stderr)
+        else:
+            self.interp = interp
+
+        # Configure various defaults and user preferences.
+        self.config()
+
+        try:
+            self.showIntro(self.introText)
+        except:
+            pass
+
+        try:
+            self.setBuiltinKeywords()
+        except:
+            pass
+        
+        try:
+            self.setLocalShell()
+        except:
+            pass
+        
+        # Do this last so the user has complete control over their
+        # environment. They can override anything they want.
+        try:
+            self.execStartupScript(self.interp.startupScript)
+        except:
+            pass
+            
+    def destroy(self):
+        del self.stdin
+        del self.stdout
+        del self.stderr
+        del self.interp
+        
+    def config(self):
+        """Configure shell based on user preferences."""
+        self.SetMarginType(1, wxSTC_MARGIN_NUMBER)
+        self.SetMarginWidth(1, 40)
+        
+        self.SetLexer(wxSTC_LEX_PYTHON)
+        self.SetKeyWords(0, ' '.join(keyword.kwlist))
+
+        self.setStyles(faces)
+        self.SetViewWhiteSpace(0)
+        self.SetTabWidth(4)
+        self.SetUseTabs(0)
+        # Do we want to automatically pop up command completion options?
+        self.autoComplete = 1
+        self.autoCompleteIncludeMagic = 1
+        self.autoCompleteIncludeSingle = 1
+        self.autoCompleteIncludeDouble = 1
+        self.autoCompleteCaseInsensitive = 1
+        self.AutoCompSetIgnoreCase(self.autoCompleteCaseInsensitive)
+        # De we want to automatically pop up command argument help?
+        self.autoCallTip = 1
+        self.CallTipSetBackground(wxColour(255, 255, 232))
+
+    def showIntro(self, text=''):
+        """Display introductory text in the shell."""
+        if text:
+            if text[-1] != '\n': text += '\n'
+            self.write(text)
+        try:
+            self.write(self.interp.introText)
+        except AttributeError:
+            pass
+    
+    def setBuiltinKeywords(self):
+        """Create pseudo keywords as part of builtins.
+        
+        This is a rather clever hack that sets "close", "exit" and "quit" 
+        to a PseudoKeyword object so that we can make them do what we want.
+        In this case what we want is to call our self.quit() method.
+        The user can type "close", "exit" or "quit" without the final parens.
+        """
+        import __builtin__
+        from pseudo import PseudoKeyword
+        __builtin__.close = __builtin__.exit = __builtin__.quit = \
+            PseudoKeyword(self.quit)
+
+    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 prompt to 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."""
+        self.interp.locals['shell'] = self
+    
+    def execStartupScript(self, startupScript):
+        """Execute the user's PYTHONSTARTUP script if they have one."""
+        if startupScript and os.path.isfile(startupScript):
+            startupText = 'Startup script executed: ' + startupScript
+            self.push('print %s;execfile(%s)' % \
+                      (`startupText`, `startupScript`))
+        else:
+            self.push('')
+            
+    def setStyles(self, faces):
+        """Configure font size, typeface and color for lexer."""
+        
+        # Default style
+        self.StyleSetSpec(wxSTC_STYLE_DEFAULT, "face:%(mono)s,size:%(size)d" % faces)
+
+        self.StyleClearAll()
+
+        # Built in styles
+        self.StyleSetSpec(wxSTC_STYLE_LINENUMBER, "back:#C0C0C0,face:%(mono)s,size:%(lnsize)d" % faces)
+        self.StyleSetSpec(wxSTC_STYLE_CONTROLCHAR, "face:%(mono)s" % faces)
+        self.StyleSetSpec(wxSTC_STYLE_BRACELIGHT, "fore:#0000FF,back:#FFFF88")
+        self.StyleSetSpec(wxSTC_STYLE_BRACEBAD, "fore:#FF0000,back:#FFFF88")
+
+        # Python styles
+        self.StyleSetSpec(wxSTC_P_DEFAULT, "face:%(mono)s" % faces)
+        self.StyleSetSpec(wxSTC_P_COMMENTLINE, "fore:#007F00,face:%(mono)s" % faces)
+        self.StyleSetSpec(wxSTC_P_NUMBER, "")
+        self.StyleSetSpec(wxSTC_P_STRING, "fore:#7F007F,face:%(mono)s" % faces)
+        self.StyleSetSpec(wxSTC_P_CHARACTER, "fore:#7F007F,face:%(mono)s" % faces)
+        self.StyleSetSpec(wxSTC_P_WORD, "fore:#00007F,bold")
+        self.StyleSetSpec(wxSTC_P_TRIPLE, "fore:#7F0000")
+        self.StyleSetSpec(wxSTC_P_TRIPLEDOUBLE, "fore:#000033,back:#FFFFE8")
+        self.StyleSetSpec(wxSTC_P_CLASSNAME, "fore:#0000FF,bold")
+        self.StyleSetSpec(wxSTC_P_DEFNAME, "fore:#007F7F,bold")
+        self.StyleSetSpec(wxSTC_P_OPERATOR, "")
+        self.StyleSetSpec(wxSTC_P_IDENTIFIER, "")
+        self.StyleSetSpec(wxSTC_P_COMMENTBLOCK, "fore:#7F7F7F")
+        self.StyleSetSpec(wxSTC_P_STRINGEOL, "fore:#000000,face:%(mono)s,back:#E0C0E0,eolfilled" % faces)
+
+    def OnKeyDown(self, event):
+        """Key down event handler.
+        
+        The main goal here is to not allow modifications to previous 
+        lines of text.
+        """
+        key = event.KeyCode()
+        currpos = self.GetCurrentPos()
+        stoppos = self.promptPos[1]
+        # If the auto-complete window is up let it do its thing.
+        if self.AutoCompActive():
+            event.Skip()
+        # Return is used to submit a command to the interpreter.
+        elif key == WXK_RETURN:
+            if self.CallTipActive: self.CallTipCancel()
+            self.processLine()
+        # Home needs to be aware of the prompt.
+        elif key == WXK_HOME:
+            if currpos >= stoppos:
+                self.SetCurrentPos(stoppos)
+                self.SetAnchor(stoppos)
+            else:
+                event.Skip()
+        # Basic navigation keys should work anywhere.
+        elif key in (WXK_END, WXK_LEFT, WXK_RIGHT, WXK_UP, WXK_DOWN, \
+                     WXK_PRIOR, WXK_NEXT):
+            event.Skip()
+        # Don't backspace over the latest prompt.
+        elif key == WXK_BACK:
+            if currpos > stoppos:
+                event.Skip()
+        # Only allow these keys after the latest prompt.
+        elif key in (WXK_TAB, WXK_DELETE):
+            if currpos >= stoppos:
+                event.Skip()
+        # Don't toggle between insert mode and overwrite mode.
+        elif key == WXK_INSERT:
+            pass
+        else:
+            event.Skip()
+
+    def OnChar(self, event):
+        """Keypress event handler.
+        
+        The main goal here is to not allow modifications to previous 
+        lines of text.
+        """
+        key = event.KeyCode()
+        currpos = self.GetCurrentPos()
+        stoppos = self.promptPos[1]
+        if currpos >= stoppos:
+            if key == 46:
+                # "." The dot or period key activates auto completion.
+                # Get the command between the prompt and the cursor.
+                # Add a dot to the end of the command.
+                command = self.GetTextRange(stoppos, currpos) + '.'
+                self.write('.')
+                if self.autoComplete: self.autoCompleteShow(command)
+            elif key == 40:
+                # "(" 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.
+                command = self.GetTextRange(stoppos, currpos) + '('
+                self.write('(')
+                if self.autoCallTip: self.autoCallTipShow(command)
+            else:
+                # Allow the normal event handling to take place.
+                event.Skip()
+        else:
+            pass
+
+    def setStatusText(self, text):
+        """Display status information."""
+        
+        # This method will most likely be replaced by the enclosing app
+        # to do something more interesting, like write to a status bar.
+        print text
+
+    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.
+        
+        # Grab information about the current line.
+        thepos = self.GetCurrentPos()
+        theline = self.GetCurrentLine()
+        thetext = self.GetCurLine()[0]
+        command = self.getCommand(thetext)
+        # Go to the very bottom of the text.
+        endpos = self.GetTextLength()
+        self.SetCurrentPos(endpos)
+        endline = self.GetCurrentLine()
+        # If they hit RETURN on the last line, execute the command.
+        if theline == endline:
+            self.push(command)
+        # Otherwise, replace the last line with the new line.
+        else:
+            # If the new line contains a command (even an invalid one).
+            if command:
+                startpos = self.PositionFromLine(endline)
+                self.SetSelection(startpos, endpos)
+                self.ReplaceSelection('')
+                self.prompt()
+                self.write(command)
+            # Otherwise, put the cursor back where we started.
+            else:
+                self.SetCurrentPos(thepos)
+                self.SetAnchor(thepos)
+
+    def getCommand(self, text):
+        """Extract a command from text which may include a shell prompt.
+        
+        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. Do this in the interpreter
+        # with a line number, prompt, command dictionary. For the history, perhaps.
+        ps1 = str(sys.ps1)
+        ps1size = len(ps1)
+        ps2 = str(sys.ps2)
+        ps2size = len(ps2)
+        text = text.rstrip()
+        # Strip the prompt off the front of text leaving just the command.
+        if text[:ps1size] == ps1:
+            command = text[ps1size:]
+        elif text[:ps2size] == ps2:
+            command = text[ps2size:]
+        else:
+            command = ''
+        return command
+    
+    def push(self, command):
+        """Send command to the interpreter for execution."""
+        self.write('\n')
+        self.more = self.interp.push(command)
+        self.prompt()
+        # Keep the undo feature from undoing previous responses. The only
+        # thing that can be undone is stuff typed after the prompt, before
+        # hitting enter. After they hit enter it becomes permanent.
+        self.EmptyUndoBuffer()
+
+    def write(self, text):
+        """Display text in the shell."""
+        self.AddText(text)
+        self.EnsureCaretVisible()
+        #self.ScrollToColumn(0)
+    
+    def prompt(self):
+        """Display appropriate prompt for the context, either ps1 or ps2.
+        
+        If this is a continuation line, autoindent as necessary.
+        """
+        if self.more:
+            prompt = str(sys.ps2)
+        else:
+            prompt = str(sys.ps1)
+        pos = self.GetCurLine()[1]
+        if pos > 0: self.write('\n')
+        self.promptPos[0] = self.GetCurrentPos()
+        self.write(prompt)
+        self.promptPos[1] = self.GetCurrentPos()
+        # XXX Add some autoindent magic here if more.
+        if self.more:
+            self.write('\t')  # Temporary hack indentation.
+        self.EnsureCaretVisible()
+        self.ScrollToColumn(0)
+    
+    def readIn(self):
+        """Replacement for stdin."""
+        prompt = 'Please enter your response:'
+        dialog = wxTextEntryDialog(None, prompt, \
+                                   'Input Dialog (Standard)', '')
+        try:
+            if dialog.ShowModal() == wxID_OK:
+                text = dialog.GetValue()
+                self.write(text + '\n')
+                return text
+        finally:
+            dialog.Destroy()
+        return ''
+
+    def readRaw(self, prompt='Please enter your response:'):
+        """Replacement for raw_input."""
+        dialog = wxTextEntryDialog(None, prompt, \
+                                   'Input Dialog (Raw)', '')
+        try:
+            if dialog.ShowModal() == wxID_OK:
+                text = dialog.GetValue()
+                return text
+        finally:
+            dialog.Destroy()
+        return ''
+
+    def ask(self, prompt='Please enter your response:'):
+        """Get response from the user."""
+        return raw_input(prompt=prompt)
+        
+    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=1, verbose=1):
+        """Execute command within the shell as if it was typed in directly.
+        >>> shell.run('print "this"')
+        >>> print "this"
+        this
+        >>> 
+        """
+        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=0, verbose=0)
+                else:
+                    self.run(command, prompt=0, verbose=1)
+        finally:
+            file.close()
+    
+    def autoCompleteShow(self, command):
+        """Display auto-completion popup list."""
+        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):
+        """Display argument spec and docstring in a popup bubble thingie."""
+        if self.CallTipActive: self.CallTipCancel()
+        tip = self.interp.getCallTip(command)
+        if tip:
+            offset = self.GetCurrentPos()
+            self.CallTipShow(offset, tip)
+
+    def writeOut(self, text):
+        """Replacement for stdout."""
+        self.write(text)
+    
+    def writeErr(self, text):
+        """Replacement for stderr."""
+        self.write(text)
+    
+    def CanCut(self):
+        """Return true if text is selected and can be cut."""
+        return self.GetSelectionStart() != self.GetSelectionEnd()
+    
+    def CanCopy(self):
+        """Return true if text is selected and can be copied."""
+        return self.GetSelectionStart() != self.GetSelectionEnd()
+
diff --git a/wxPython/wxPython/lib/PyCrust/version.py b/wxPython/wxPython/lib/PyCrust/version.py
new file mode 100644 (file)
index 0000000..0c48e40
--- /dev/null
@@ -0,0 +1,10 @@
+"""Provides an object representing the current "version" or "release" of
+PyCrust as a whole. Individual classes, such as the shell, editor and
+interpreter, each have a revision property based on the CVS Revision."""
+
+__author__ = "Patrick K. O'Brien <pobrien@orbtech.com>"
+__cvsid__ = "$Id$"
+__date__ = "July 1, 2001"
+__version__ = "$Revision$"[11:-2]
+
+VERSION = '0.5.2'