]> git.saurik.com Git - wxWidgets.git/commitdiff
Updated PyCrust from Patrick O'Brien
authorRobin Dunn <robin@alldunn.com>
Fri, 22 Feb 2002 00:09:42 +0000 (00:09 +0000)
committerRobin Dunn <robin@alldunn.com>
Fri, 22 Feb 2002 00:09:42 +0000 (00:09 +0000)
git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@14343 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775

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

index 5bb78f3d9489a2281f6efbb6efeaac0afc89cf0e..128ce54cd2eddded444bc8f9a2b8c9f111adaf43 100644 (file)
@@ -52,7 +52,7 @@ class CrustFrame(wxFrame, ShellMenu):
         """Create a PyCrust CrustFrame instance."""
         wxFrame.__init__(self, parent, id, title, pos, size, style)
         intro = 'Welcome To PyCrust %s - The Flakiest Python Shell' % VERSION
-        intro += '\nSponsored by Orbtech.com - Your Source For Python Development Services'
+        intro += '\nSponsored by Orbtech - Your Source For Python Development Services'
         self.CreateStatusBar()
         self.SetStatusText(intro.replace('\n', ', '))
         if wxPlatform == '__WXMSW__':
index b7a29eda78a2da5ef32903f2874983c128a687db..4cb15af1d0fe70db55eca95b7cad18c8ae16392f 100644 (file)
@@ -50,11 +50,13 @@ class FillingTree(wxTreeCtrl):
         """Return a dictionary with the attributes or contents of object."""
         dict = {}
         objtype = type(object)
-        if objtype is types.DictType:
+        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)):
+                          types.ModuleType)) \
+        or str(objtype)[1:10] == 'extension':
             for key in introspect.getAttributeNames(object):
                 # Believe it or not, some attributes can disappear, such as
                 # the exc_traceback attribute of the sys module. So this is
@@ -74,7 +76,10 @@ class FillingTree(wxTreeCtrl):
         if not children:
             return
         list = children.keys()
-        list.sort(lambda x, y: cmp(x.lower(), y.lower()))
+        try:
+            list.sort(lambda x, y: cmp(x.lower(), y.lower()))
+        except:
+            pass
         for item in list:
             itemtext = str(item)
             # Show string dictionary items with single quotes, except for
@@ -101,7 +106,7 @@ class FillingTree(wxTreeCtrl):
         object = self.GetPyData(item)
         text = ''
         text += self.getFullName(item)
-        text += '\n\nType: ' + str(type(object))[7:-2]
+        text += '\n\nType: ' + str(type(object))
         value = str(object)
         if type(object) is types.StringType:
             value = repr(value)
@@ -133,9 +138,11 @@ class FillingTree(wxTreeCtrl):
         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 \
+        if (type(parentobject) is types.DictType \
+            or str(type(parentobject))[17:23] == 'BTrees' \
+            and hasattr(parentobject, 'keys')) \
         and ((item != self.root and parent != self.root) \
-        or (parent == self.root and not self.rootIsNamespace)):
+            or (parent == self.root and not self.rootIsNamespace)):
             name = '[' + name + ']'
         # Apply dot syntax to multipart names.
         if partial:
index 7a09a40cd6906c60149a1df484547a1c43bbdf17..7f4efb64c12f2646487daff4ae6cbfdef4fe1fac 100644 (file)
@@ -93,59 +93,70 @@ def getCallTip(command='', locals=None):
     
     The call tip information will be based on the locals namespace."""
 
+    calltip = ('', '', '')
     # Get the proper chunk of code from the command.
     root = getRoot(command, terminator='(')
     try:
         object = eval(root, locals)
     except:
-        return ''
-    dropSelf = 0
-    if hasattr(object, '__name__'):  # Make sure this is a useable object.
-        # Switch to the object that has the information we need.
-        if inspect.ismethod(object) or hasattr(object, 'im_func'):
-            # Get the function from the object otherwise inspect.getargspec()
-            # complains that the object isn't a Python function.
-            object = object.im_func
-            dropSelf = 1
-        elif inspect.isclass(object):
-            # Get the __init__ method function for the class.
-            constructor = getConstructor(object)
-            if constructor is not None:
-                object = constructor
-                dropSelf = 1
+        return calltip
+    name = ''
+    dropSelf = 1
+    # Switch to the object that has the information we need.
+    if inspect.isbuiltin(object):
+        # Builtin functions don't have an argspec that we can get.
+        pass
+    elif inspect.ismethod(object) or hasattr(object, 'im_func'):
+        # Get the function from the object otherwise inspect.getargspec()
+        # complains that the object isn't a Python function.
+        object = object.im_func
+    elif inspect.isclass(object):
+        # Get the __init__ method function for the class.
+        constructor = getConstructor(object)
+        if constructor is not None:
+            object = constructor
+    elif callable(object):
+        # Get the __call__ method instead.
+        try:
+            object = object.__call__.im_func
+        except:
+            dropSelf = 0
+    else:
+        dropSelf = 0
+    if hasattr(object, '__name__'):
         name = object.__name__
-        tip1 = ''
-        if inspect.isbuiltin(object):
-            # Builtin functions don't have an argspec that we can get.
-            pass
-        elif inspect.isfunction(object):
-            # tip1 is a string like: "getCallTip(command='', locals=None)"
-            argspec = apply(inspect.formatargspec, inspect.getargspec(object))
-            if dropSelf:
-                # The first parameter to a method is a reference to the
-                # instance, usually coded as "self", and is passed
-                # automatically by Python and therefore we want to drop it.
-                temp = argspec.split(',')
-                if len(temp) == 1:  # No other arguments.
-                    argspec = '()'
-                else:  # Drop the first argument.
-                    argspec = '(' + ','.join(temp[1:]).lstrip()
-            tip1 = name + argspec
-        doc = inspect.getdoc(object)
-        if doc:
-            # tip2 is the first separated line of the docstring, like:
-            # "Return call tip text for a command."
-            # tip3 is the rest of the docstring, like:
-            # "The call tip information will be based on ... <snip>
-            docpieces = doc.split('\n\n')
-            tip2 = docpieces[0]
-            tip3 = '\n\n'.join(docpieces[1:])
-            tip = '%s\n\n%s\n\n%s' % (tip1, tip2, tip3)
-        else:
-            tip = tip1
-        return tip.strip()
+    tip1 = ''
+    argspec = ''
+    if inspect.isbuiltin(object):
+        # Builtin functions don't have an argspec that we can get.
+        pass
+    elif inspect.isfunction(object):
+        # tip1 is a string like: "getCallTip(command='', locals=None)"
+        argspec = apply(inspect.formatargspec, inspect.getargspec(object))
+        if dropSelf:
+            # The first parameter to a method is a reference to the
+            # instance, usually coded as "self", and is passed
+            # automatically by Python and therefore we want to drop it.
+            temp = argspec.split(',')
+            if len(temp) == 1:  # No other arguments.
+                argspec = '()'
+            else:  # Drop the first argument.
+                argspec = '(' + ','.join(temp[1:]).lstrip()
+        tip1 = name + argspec
+    doc = inspect.getdoc(object)
+    if doc:
+        # tip2 is the first separated line of the docstring, like:
+        # "Return call tip text for a command."
+        # tip3 is the rest of the docstring, like:
+        # "The call tip information will be based on ... <snip>
+        docpieces = doc.split('\n\n')
+        tip2 = docpieces[0]
+        tip3 = '\n\n'.join(docpieces[1:])
+        tip = '%s\n\n%s\n\n%s' % (tip1, tip2, tip3)
     else:
-        return ''
+        tip = tip1
+    calltip = (name, argspec[1:-1], tip.strip())
+    return calltip
 
 def getConstructor(object):
     """Return constructor for class object, or None if there isn't one."""
index 245f80bc42285471680a89ec89603c719a038d2b..556b144a9ffc56ff7af1537bd339d69139c72984 100644 (file)
@@ -2,7 +2,7 @@
 commands to be sent to the interpreter. This particular shell is based on
 wxPython's wxStyledTextCtrl. The latest files are always available at the
 SourceForge project page at http://sourceforge.net/projects/pycrust/.
-Sponsored by Orbtech.com - Your Source For Python Development Services"""
+Sponsored by Orbtech - Your Source For Python Development Services"""
 
 __author__ = "Patrick K. O'Brien <pobrien@orbtech.com>"
 __cvsid__ = "$Id$"
@@ -82,10 +82,13 @@ Ctrl+C            Copy selected text, removing prompts.
 Ctrl+Shift+C      Copy selected text, retaining 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 then press F8.)
 """
@@ -335,17 +338,32 @@ class Shell(wxStyledTextCtrl):
         altDown = event.AltDown()
         shiftDown = event.ShiftDown()
         currpos = self.GetCurrentPos()
-        # Return is used to submit a command to the interpreter.
-        if key == WXK_RETURN:
+        endpos = self.GetTextLength()
+        # Return (Enter) is used to submit a command to the interpreter.
+        if not controlDown and key == WXK_RETURN:
             if self.AutoCompActive(): self.AutoCompCancel()
             if self.CallTipActive(): self.CallTipCancel()
             self.processLine()
+        # Ctrl+Return (Cntrl+Enter) is used to insert a line break.
+        elif controlDown and key == WXK_RETURN:
+            if self.AutoCompActive(): self.AutoCompCancel()
+            if self.CallTipActive(): self.CallTipCancel()
+            if currpos == endpos:
+                self.processLine()
+            else:
+                self.insertLineBreak()
         # If the auto-complete window is up let it do its thing.
         elif self.AutoCompActive():
             event.Skip()
         # Let Ctrl-Alt-* get handled normally.
         elif controlDown and altDown:
             event.Skip()
+        # Clear the current, unexecuted command.
+        elif key == WXK_ESCAPE:
+            if self.CallTipActive():
+                event.Skip()
+            else:
+                self.clearCommand()
         # Cut to the clipboard.
         elif (controlDown and key in (ord('X'), ord('x'))) \
         or (shiftDown and key == WXK_DELETE):
@@ -359,17 +377,28 @@ class Shell(wxStyledTextCtrl):
             and key in (ord('C'), ord('c'), WXK_INSERT):
             self.CopyWithPrompts()
         # Paste from the clipboard.
-        elif (controlDown and key in (ord('V'), ord('v'), WXK_INSERT)) \
-        or (shiftDown and key == WXK_INSERT):
+        elif (controlDown and not shiftDown \
+            and key in (ord('V'), ord('v'))) \
+        or (shiftDown and not controlDown and key == WXK_INSERT):
             self.Paste()
-        # Retrieve the previous command from the history buffer.
+        # 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 == WXK_UP) \
         or (altDown and key in (ord('P'), ord('p'))):
-            self.OnHistoryRetrieve(step=+1)
-        # Retrieve the next command from the history buffer.
+            self.OnHistoryReplace(step=+1)
+        # Replace with the next command from the history buffer.
         elif (controlDown and key == WXK_DOWN) \
         or (altDown and key in (ord('N'), ord('n'))):
-            self.OnHistoryRetrieve(step=-1)
+            self.OnHistoryReplace(step=-1)
+        # Insert the previous command from the history buffer.
+        elif (shiftDown and key == WXK_UP):
+            self.OnHistoryInsert(step=+1)
+        # Insert the next command from the history buffer.
+        elif (shiftDown and key == WXK_DOWN):
+            self.OnHistoryInsert(step=-1)
         # Search up the history for the text in front of the cursor.
         elif key == WXK_F8:
             self.OnHistorySearch()
@@ -383,6 +412,7 @@ class Shell(wxStyledTextCtrl):
                 else:
                     self.SetCurrentPos(home)
                     self.SetAnchor(home)
+                    self.EnsureCaretVisible()
             else:
                 event.Skip()
         # Basic navigation keys should work anywhere.
@@ -412,22 +442,36 @@ class Shell(wxStyledTextCtrl):
         else:
             event.Skip()
 
-    def OnHistoryRetrieve(self, step):
-        """Retrieve the previous/next command from the history buffer."""
-        if not self.CanEdit():
-            return
-        startpos = self.GetCurrentPos()
+    def clearCommand(self):
+        """Delete the current, unexecuted command."""
+        startpos = self.promptPosEnd
+        endpos = self.GetTextLength()
+        self.SetSelection(startpos, endpos)
+        self.ReplaceSelection('')
+        self.more = 0
+
+    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."""
+        self.ReplaceSelection('')
         newindex = self.historyIndex + step
-        if not (-1 <= newindex < len(self.history)):
-            return
-        self.historyIndex = newindex
-        if newindex == -1:
-            self.ReplaceSelection('')
-        else:
-            self.ReplaceSelection('')
+        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 + sys.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)
 
@@ -469,48 +513,42 @@ class Shell(wxStyledTextCtrl):
         # 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 = 1
+            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()
+
+        thepos = self.GetCurrentPos()        
+        startpos = self.promptPosEnd
         endpos = self.GetTextLength()
-        # If they hit RETURN at the very bottom, execute the command.
-        if thepos == endpos:
+        # If they hit RETURN inside the current command, execute the command.
+        if self.CanEdit():
+            self.SetCurrentPos(endpos)
             self.interp.more = 0
-            if self.getCommand():
-                command = self.GetTextRange(self.promptPosEnd, endpos)
-            else:
-                # This is a hack, now that we allow editing of previous
-                # lines, which throws off our promptPos values.
-                newend = endpos - len(self.getCommand(rstrip=0))
-                command = self.GetTextRange(self.promptPosEnd, newend)
-            command = command.replace(os.linesep + sys.ps2, '\n')
+            command = self.GetTextRange(startpos, endpos)
+            lines = command.split(os.linesep + sys.ps2)
+            lines = [line.rstrip() for line in lines]
+            command = '\n'.join(lines)
             self.push(command)
         # Or replace the current command with the other command.
-        elif thepos < self.promptPosStart:
-            theline = self.GetCurrentLine()
-            command = self.getCommand(rstrip=0)
-            # If the new line contains a command (even an invalid one).
-            if command:
+        else:
+            # If the line contains a command (even an invalid one).
+            if self.getCommand(rstrip=0):
                 command = self.getMultilineCommand()
-                self.SetCurrentPos(endpos)
-                startpos = self.promptPosEnd
-                self.SetSelection(startpos, endpos)
-                self.ReplaceSelection('')
+                self.clearCommand()
                 self.write(command)
-                self.more = 0
             # Otherwise, put the cursor back where we started.
             else:
                 self.SetCurrentPos(thepos)
                 self.SetAnchor(thepos)
-        # Or add a new line to the current single or multi-line command.
-        elif thepos > self.promptPosEnd:
-            self.write(os.linesep)
-            self.more = 1
-            self.prompt()
 
     def getMultilineCommand(self, rstrip=1):
         """Extract a multi-line command from the editor.
@@ -716,10 +754,19 @@ class Shell(wxStyledTextCtrl):
     def autoCallTipShow(self, command):
         """Display argument spec and docstring in a popup bubble thingie."""
         if self.CallTipActive: self.CallTipCancel()
-        tip = self.interp.getCallTip(command)
+        (name, argspec, tip) = self.interp.getCallTip(command)
+        if argspec:
+            startpos = self.GetCurrentPos()
+            self.write(argspec + ')')
+            endpos = self.GetCurrentPos()
+            self.SetSelection(endpos, startpos)
         if tip:
-            offset = self.GetCurrentPos()
-            self.CallTipShow(offset, 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 writeOut(self, text):
         """Replacement for stdout."""
@@ -805,21 +852,60 @@ class Shell(wxStyledTextCtrl):
 
     def Paste(self):
         """Replace selection with clipboard contents."""
-        if self.CanPaste():
-            if wxTheClipboard.Open():
-                if wxTheClipboard.IsSupported(wxDataFormat(wxDF_TEXT)):
-                    data = wxTextDataObject()
-                    if wxTheClipboard.GetData(data):
-                        command = data.GetText()
-                        command = command.rstrip()
-                        command = self.fixLineEndings(command)
-                        command = self.lstripPrompt(text=command)
-                        command = command.replace(os.linesep + sys.ps2, '\n')
-                        command = command.replace(os.linesep, '\n')
+        if self.CanPaste() and wxTheClipboard.Open():
+            if wxTheClipboard.IsSupported(wxDataFormat(wxDF_TEXT)):
+                data = wxTextDataObject()
+                if wxTheClipboard.GetData(data):
+                    self.ReplaceSelection('')
+                    command = data.GetText()
+                    command = command.rstrip()
+                    command = self.fixLineEndings(command)
+                    command = self.lstripPrompt(text=command)
+                    command = command.replace(os.linesep + sys.ps2, '\n')
+                    command = command.replace(os.linesep, '\n')
+                    command = command.replace('\n', os.linesep + sys.ps2)
+                    self.write(command)
+            wxTheClipboard.Close()
+
+    def PasteAndRun(self):
+        """Replace selection with clipboard contents, run commands."""
+        if wxTheClipboard.Open():
+            if wxTheClipboard.IsSupported(wxDataFormat(wxDF_TEXT)):
+                data = wxTextDataObject()
+                if wxTheClipboard.GetData(data):
+                    endpos = self.GetTextLength()
+                    self.SetCurrentPos(endpos)
+                    startpos = self.promptPosEnd
+                    self.SetSelection(startpos, endpos)
+                    self.ReplaceSelection('')
+                    text = data.GetText()
+                    text = text.strip()
+                    text = self.fixLineEndings(text)
+                    text = self.lstripPrompt(text=text)
+                    text = text.replace(os.linesep + sys.ps1, '\n')
+                    text = text.replace(os.linesep + sys.ps2, '\n')
+                    text = text.replace(os.linesep, '\n')
+                    lines = text.split('\n')
+                    commands = []
+                    command = ''
+                    for line in lines:
+                        if line.strip() != '' and line.lstrip() == line:
+                            # 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 + sys.ps2)
-                        self.ReplaceSelection('')
                         self.write(command)
-                wxTheClipboard.Close()
+                        self.processLine()
+            wxTheClipboard.Close()
 
 
 wxID_SELECTALL = NewId()  # This *should* be defined by wxPython.
@@ -1014,7 +1100,7 @@ class ShellFrame(wxFrame, ShellMenu):
         """Create a PyCrust ShellFrame instance."""
         wxFrame.__init__(self, parent, id, title, pos, size, style)
         intro = 'Welcome To PyCrust %s - The Flakiest Python Shell' % VERSION
-        intro += '\nSponsored by Orbtech.com - Your Source For Python Development Services'
+        intro += '\nSponsored by Orbtech - Your Source For Python Development Services'
         self.CreateStatusBar()
         self.SetStatusText(intro.replace('\n', ', '))
         if wxPlatform == '__WXMSW__':