]> git.saurik.com Git - wxWidgets.git/commitdiff
Updated PyCrust code from Patrick
authorRobin Dunn <robin@alldunn.com>
Sat, 24 Aug 2002 21:44:57 +0000 (21:44 +0000)
committerRobin Dunn <robin@alldunn.com>
Sat, 24 Aug 2002 21:44:57 +0000 (21:44 +0000)
git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@16755 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775

wxPython/wxPython/lib/PyCrust/crust.py
wxPython/wxPython/lib/PyCrust/filling.py
wxPython/wxPython/lib/PyCrust/interpreter.py
wxPython/wxPython/lib/PyCrust/shell.py

index 23235b2619402b01c8e8f2001d3e2abee9860e4a..45de8b585ad561f8bda474691f91f0385c032a98 100644 (file)
@@ -8,6 +8,7 @@ from wxPython.wx import *
 from shell import Shell
 from filling import Filling
 from version import VERSION
+import os
 
 
 class Crust(wxSplitterWindow):
@@ -55,12 +56,9 @@ class CrustFrame(wxFrame, ShellMenu):
         intro += '\nSponsored by Orbtech - Your source for Python programming expertise.'
         self.CreateStatusBar()
         self.SetStatusText(intro.replace('\n', ', '))
-
-        import os
         filename = os.path.join(os.path.dirname(__file__), 'PyCrust.ico')
         icon = wxIcon(filename, wxBITMAP_TYPE_ICO)
         self.SetIcon(icon)
-
         self.crust = Crust(parent=self, intro=intro, \
                            rootObject=rootObject, \
                            rootLabel=rootLabel, \
@@ -78,6 +76,10 @@ class CrustFrame(wxFrame, ShellMenu):
         # Temporary hack to share menus between PyCrust and PyShell.
         self.shell = self.crust.shell
         self.createMenus()
+        EVT_CLOSE(self, self.OnCloseWindow)
 
+    def OnCloseWindow(self, event):
+        self.crust.shell.destroy()
+        self.Destroy()
 
 
index b2ce11ced3e2ff64c43d036804ea5e098fa9c54c..a8da26089451cad4bf1bc8a8f2f1ed44b7d38a60 100644 (file)
@@ -14,6 +14,14 @@ import keyword
 import sys
 import types
 
+COMMONTYPES = [getattr(types, t) for t in dir(types) \
+               if not t.startswith('_') \
+               and t not in ('ClassType', 'InstanceType', 'ModuleType')]
+try:
+    COMMONTYPES.append(type(''.__repr__))  # Method-wrapper in version 2.2.x.
+except AttributeError:
+    pass
+
 
 class FillingTree(wxTreeCtrl):
     """PyCrust FillingTree based on wxTreeCtrl."""
@@ -39,40 +47,43 @@ class FillingTree(wxTreeCtrl):
         EVT_TREE_ITEM_COLLAPSED(self, self.GetId(), self.OnItemCollapsed)
         EVT_TREE_SEL_CHANGED(self, self.GetId(), self.OnSelChanged)
 
-    def hasChildren(self, object):
+    def hasChildren(self, o):
         """Return true if object has children."""
-        if self.getChildren(object):
+        if self.getChildren(o):
             return true
         else:
             return false
 
-    def getChildren(self, object):
+    def getChildren(self, o):
         """Return a dictionary with the attributes or contents of object."""
-        dict = {}
-        objtype = type(object)
-        if (objtype is types.DictType) \
-        or str(objtype)[17:23] == 'BTrees' and hasattr(object, 'keys'):
-            dict = object
-        elif (objtype in (types.ClassType, \
-                          types.InstanceType, \
-                          types.ModuleType)) \
-        or str(objtype)[1:10] == 'extension':
-            for key in introspect.getAttributeNames(object):
+        busy = wxBusyCursor()
+        otype = type(o)
+        if (otype is types.DictType) \
+        or str(otype)[17:23] == 'BTrees' and hasattr(o, 'keys'):
+            return o
+        d = {}
+        if otype is types.ListType:
+            for n in range(len(o)):
+                key = '[' + str(n) + ']'
+                d[key] = o[n]
+        if otype not in COMMONTYPES:
+            for key in introspect.getAttributeNames(o):
                 # Believe it or not, some attributes can disappear, such as
                 # the exc_traceback attribute of the sys module. So this is
                 # nested in a try block.
                 try:
-                    dict[key] = getattr(object, key)
+                    d[key] = getattr(o, key)
                 except:
                     pass
-        return dict
+        return d
 
     def OnItemExpanding(self, event):
+        busy = wxBusyCursor()
         selection = event.GetItem()
         if self.IsExpanded(selection):
             return
-        object = self.GetPyData(selection)
-        children = self.getChildren(object)
+        o = self.GetPyData(selection)
+        children = self.getChildren(o)
         if not children:
             return
         list = children.keys()
@@ -84,7 +95,7 @@ class FillingTree(wxTreeCtrl):
             itemtext = str(item)
             # Show string dictionary items with single quotes, except for
             # the first level of items, if they represent a namespace.
-            if type(object) is types.DictType \
+            if type(o) is types.DictType \
             and type(item) is types.StringType \
             and (selection != self.root \
                  or (selection == self.root and not self.rootIsNamespace)):
@@ -95,42 +106,44 @@ class FillingTree(wxTreeCtrl):
 
     def OnItemCollapsed(self, event):
         """Remove all children from the item."""
+        busy = wxBusyCursor()
         item = event.GetItem()
         self.DeleteChildren(item)
 
     def OnSelChanged(self, event):
+        busy = wxBusyCursor()
         item = event.GetItem()
         if item == self.root:
             self.setText('')
             return
-        object = self.GetPyData(item)
-        otype = type(object)
+        o = self.GetPyData(item)
+        otype = type(o)
         text = ''
         text += self.getFullName(item)
         text += '\n\nType: ' + str(otype)
         try:
-            value = str(object)
+            value = str(o)
         except:
             value = ''
         if otype is types.StringType or otype is types.UnicodeType:
-            value = repr(object)
+            value = repr(o)
         text += '\n\nValue: ' + value
         if otype is types.InstanceType:
             try:
                 text += '\n\nClass Definition:\n\n' + \
-                        inspect.getsource(object.__class__)
+                        inspect.getsource(o.__class__)
             except:
                 try:
-                    text += '\n\n"""' + inspect.getdoc(object).strip() + '"""'
+                    text += '\n\n"""' + inspect.getdoc(o).strip() + '"""'
                 except:
                     pass
         else:
             try:
                 text += '\n\nSource Code:\n\n' + \
-                        inspect.getsource(object)
+                        inspect.getsource(o)
             except:
                 try:
-                    text += '\n\n"""' + inspect.getdoc(object).strip() + '"""'
+                    text += '\n\n"""' + inspect.getdoc(o).strip() + '"""'
                 except:
                     pass
         self.setText(text)
@@ -138,13 +151,13 @@ class FillingTree(wxTreeCtrl):
     def getFullName(self, item, partial=''):
         """Return a syntactically proper name for item."""
         parent = self.GetItemParent(item)
-        parentobject = self.GetPyData(parent)
+        parento = self.GetPyData(parent)
         name = self.GetItemText(item)
         # Apply dictionary syntax to dictionary items, except the root
         # and first level children of a namepace.
-        if (type(parentobject) is types.DictType \
-            or str(type(parentobject))[17:23] == 'BTrees' \
-            and hasattr(parentobject, 'keys')) \
+        if (type(parento) is types.DictType \
+            or str(type(parento))[17:23] == 'BTrees' \
+            and hasattr(parento, 'keys')) \
         and ((item != self.root and parent != self.root) \
             or (parent == self.root and not self.rootIsNamespace)):
             name = '[' + name + ']'
@@ -228,6 +241,10 @@ class FillingText(wxStyledTextCtrl):
         self.SetTabWidth(4)
         self.SetUseTabs(0)
         self.SetReadOnly(1)
+        try:
+            self.SetWrapMode(1)
+        except AttributeError:
+            pass
 
     def setStyles(self, faces):
         """Configure font size, typeface and color for lexer."""
index f669a5d122194fd490ec65e1a508d6e614f4f22b..4cd752daa3c6972b12234459847eb3fc1c3cbc67 100644 (file)
@@ -78,6 +78,10 @@ class Interpreter(InteractiveInterpreter):
             sys.stderr = stderr
         return more
         
+    def getAutoCompleteKeys(self):
+        """Return list of auto-completion keycodes."""
+        return [ord('.')]
+
     def getAutoCompleteList(self, command='', *args, **kwds):
         """Return list of auto-completion options for a command.
         
index b96ea802184329570a22d9af71d8b0b8bec90997..8af395ed7622d6b84014c92981a5421142215dbd 100644 (file)
@@ -19,6 +19,8 @@ from pseudo import PseudoFileErr
 from version import VERSION
 
 
+NAVKEYS = (WXK_END, WXK_LEFT, WXK_RIGHT, WXK_UP, WXK_DOWN, WXK_PRIOR, WXK_NEXT)
+
 if wxPlatform == '__WXMSW__':
     faces = { 'times'  : 'Times New Roman',
               'mono'   : 'Courier New',
@@ -48,7 +50,7 @@ else:  # GTK
 class ShellFacade:
     """Simplified interface to all shell-related functionality.
 
-    This is a semi-transparent facade, in that all attributes of other are
+    This is a semi-transparent facade, in that all attributes of other are 
     still accessible, even though only some are visible to the user."""
 
     name = 'PyCrust Shell Interface'
@@ -66,6 +68,8 @@ class ShellFacade:
                    'redirectStdout',
                    'run',
                    'runfile',
+                   'wrap',
+                   'zoom',
                   ]
         for method in methods:
             self.__dict__[method] = getattr(other, method)
@@ -160,6 +164,8 @@ class Shell(wxStyledTextCtrl):
                                   stdout=PseudoFileOut(self.writeOut), \
                                   stderr=PseudoFileErr(self.writeErr), \
                                   *args, **kwds)
+        # 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
@@ -219,6 +225,7 @@ class Shell(wxStyledTextCtrl):
         # Do we want to automatically pop up command argument help?
         self.autoCallTip = 1
         self.CallTipSetBackground(wxColour(255, 255, 232))
+        self.wrap()
 
     def showIntro(self, text=''):
         """Display introductory text in the shell."""
@@ -301,6 +308,10 @@ class Shell(wxStyledTextCtrl):
         caretPos = self.GetCurrentPos()
         if caretPos > 0:
             charBefore = self.GetCharAt(caretPos - 1)
+            #*** Patch to fix bug in wxSTC for wxPython < 2.3.3.
+            if charBefore < 0:
+                charBefore = 32  # Mimic a space.
+            #***
             styleBefore = self.GetStyleAt(caretPos - 1)
 
         # Check before.
@@ -311,6 +322,10 @@ class Shell(wxStyledTextCtrl):
         # Check after.
         if braceAtCaret < 0:
             charAfter = self.GetCharAt(caretPos)
+            #*** Patch to fix bug in wxSTC for wxPython < 2.3.3.
+            if charAfter < 0:
+                charAfter = 32  # Mimic a space.
+            #***
             styleAfter = self.GetStyleAt(caretPos)
             if charAfter and chr(charAfter) in '[]{}()' \
             and styleAfter == wxSTC_P_OPERATOR:
@@ -325,20 +340,20 @@ class Shell(wxStyledTextCtrl):
             self.BraceHighlight(braceAtCaret, braceOpposite)
 
     def OnChar(self, event):
-        """Keypress event handler.
+        """Keypress event handler."""
 
-        Prevents modification of previously submitted commands/responses."""
+        # Prevent modification of previously submitted commands/responses.
         if not self.CanEdit():
             return
         key = event.KeyCode()
         currpos = self.GetCurrentPos()
         stoppos = self.promptPosEnd
-        if key == ord('.'):
-            # The dot or period key activates auto completion.
+        if key in self.autoCompleteKeys:
+            # Usually the dot (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('.')
+            # Add the autocomplete character to the end of the command.
+            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
@@ -355,9 +370,9 @@ class Shell(wxStyledTextCtrl):
             event.Skip()
 
     def OnKeyDown(self, event):
-        """Key down event handler.
+        """Key down event handler."""
 
-        Prevents modification of previously submitted commands/responses."""
+        # Prevent modification of previously submitted commands/responses.
         key = event.KeyCode()
         controlDown = event.ControlDown()
         altDown = event.AltDown()
@@ -401,6 +416,25 @@ class Shell(wxStyledTextCtrl):
         elif controlDown and shiftDown \
             and key in (ord('C'), ord('c'), WXK_INSERT):
             self.CopyWithPrompts()
+        # Home needs to be aware of the prompt.
+        elif key == WXK_HOME:
+            home = self.promptPosEnd
+            if currpos > home:
+                selecting = self.GetSelectionStart() != self.GetSelectionEnd()
+                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 self.GetSelectionStart() != self.GetSelectionEnd()\
+        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'))) \
@@ -419,34 +453,20 @@ class Shell(wxStyledTextCtrl):
         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 == WXK_UP):
+        elif (shiftDown and key == WXK_UP) and self.CanEdit():
             self.OnHistoryInsert(step=+1)
         # Insert the next command from the history buffer.
-        elif (shiftDown and key == WXK_DOWN):
+        elif (shiftDown and key == WXK_DOWN) and self.CanEdit():
             self.OnHistoryInsert(step=-1)
         # Search up the history for the text in front of the cursor.
         elif key == WXK_F8:
             self.OnHistorySearch()
-        # Home needs to be aware of the prompt.
-        elif key == WXK_HOME:
-            home = self.promptPosEnd
-            if currpos >= home:
-                if event.ShiftDown():
-                    # Select text from current position to end of prompt.
-                    self.SetSelection(self.GetCurrentPos(), home)
-                else:
-                    self.SetCurrentPos(home)
-                    self.SetAnchor(home)
-                    self.EnsureCaretVisible()
-            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 non-continuation prompt.
         elif key == WXK_BACK:
-            if currpos > self.promptPosEnd:
+            if self.GetSelectionStart() != self.GetSelectionEnd()\
+            and self.CanEdit():
+                event.Skip()
+            elif currpos > self.promptPosEnd:
                 event.Skip()
         # Only allow these keys after the latest prompt.
         elif key in (WXK_TAB, WXK_DELETE):
@@ -461,6 +481,9 @@ class Shell(wxStyledTextCtrl):
         # 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
@@ -551,7 +574,7 @@ class Shell(wxStyledTextCtrl):
         # 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()
+        thepos = self.GetCurrentPos()        
         startpos = self.promptPosEnd
         endpos = self.GetTextLength()
         # If they hit RETURN inside the current command, execute the command.
@@ -638,9 +661,10 @@ class Shell(wxStyledTextCtrl):
         elif text[:ps2size] == ps2:
             text = text[ps2size:]
         return text
-
+    
     def push(self, command):
         """Send command to the interpreter for execution."""
+        busy = wxBusyCursor()
         self.write(os.linesep)
         self.more = self.interp.push(command)
         if not self.more:
@@ -742,11 +766,11 @@ class Shell(wxStyledTextCtrl):
         >>> shell.run('print "this"')
         >>> print "this"
         this
-        >>>
+        >>> 
         """
         # Go to the very bottom of the text.
         endpos = self.GetTextLength()
-        self.SetCurrentPos(endpos)
+        self.SetCurrentPos(endpos)        
         command = command.rstrip()
         if prompt: self.prompt()
         if verbose: self.write(command)
@@ -844,7 +868,14 @@ class Shell(wxStyledTextCtrl):
 
     def CanEdit(self):
         """Return true if editing should succeed."""
-        return self.GetCurrentPos() >= self.promptPosEnd
+        if self.GetSelectionStart() != self.GetSelectionEnd():
+            if self.GetSelectionStart() >= self.promptPosEnd \
+            and self.GetSelectionEnd() >= self.promptPosEnd:
+                return 1
+            else:
+                return 0
+        else:
+            return self.GetCurrentPos() >= self.promptPosEnd
 
     def Cut(self):
         """Remove selection and place it on the clipboard."""
@@ -926,12 +957,26 @@ class Shell(wxStyledTextCtrl):
                             command += '\n'
                             command += line
                     commands.append(command)
-                    for command in commands:
+                    for command in commands:    
                         command = command.replace('\n', os.linesep + sys.ps2)
                         self.write(command)
                         self.processLine()
             wxTheClipboard.Close()
 
+    def wrap(self, wrap=1):
+        """Sets whether text is word wrapped."""
+        try:
+            self.SetWrapMode(wrap)
+        except AttributeError:
+            return 'Wrapping is not available in this version of PyCrust.'
+
+    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)
+
 
 wxID_SELECTALL = NewId()  # This *should* be defined by wxPython.
 ID_AUTOCOMP = NewId()
@@ -1124,19 +1169,18 @@ class ShellFrame(wxFrame, ShellMenu):
         intro += '\nSponsored by Orbtech - Your source for Python programming expertise.'
         self.CreateStatusBar()
         self.SetStatusText(intro.replace('\n', ', '))
-
-        import os
         filename = os.path.join(os.path.dirname(__file__), 'PyCrust.ico')
         icon = wxIcon(filename, wxBITMAP_TYPE_ICO)
         self.SetIcon(icon)
-
         self.shell = Shell(parent=self, id=-1, introText=intro, \
                            locals=locals, InterpClass=InterpClass, \
                            *args, **kwds)
         # Override the shell so that status messages go to the status bar.
         self.shell.setStatusText = self.SetStatusText
         self.createMenus()
+        EVT_CLOSE(self, self.OnCloseWindow)
 
-
-
+    def OnCloseWindow(self, event):
+        self.shell.destroy()
+        self.Destroy()