Updated to new PyCrust
git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@12049 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775
This commit is contained in:
		| @@ -53,7 +53,8 @@ class FillingTree(wxTreeCtrl): | |||||||
|         objtype = type(object) |         objtype = type(object) | ||||||
|         if objtype is types.DictType: |         if objtype is types.DictType: | ||||||
|             dict = object |             dict = object | ||||||
|         elif objtype in (types.InstanceType, types.ModuleType): |         elif (objtype in (types.InstanceType, types.ModuleType)) \ | ||||||
|  |         or hasattr(object, '__class__'): | ||||||
|             for key in introspect.getAttributeNames(object): |             for key in introspect.getAttributeNames(object): | ||||||
|                 # Believe it or not, some attributes can disappear, such as |                 # Believe it or not, some attributes can disappear, such as | ||||||
|                 # the exc_traceback attribute of the sys module. So this is |                 # the exc_traceback attribute of the sys module. So this is | ||||||
| @@ -170,10 +171,16 @@ if wxPlatform == '__WXMSW__': | |||||||
|               'helv'   : 'Lucida Console', |               'helv'   : 'Lucida Console', | ||||||
|               'lucida' : 'Lucida Console', |               'lucida' : 'Lucida Console', | ||||||
|               'other'  : 'Comic Sans MS', |               'other'  : 'Comic Sans MS', | ||||||
|               'size'   : 8, |               'size'   : 10, | ||||||
|               'lnsize' : 7, |               'lnsize' : 9, | ||||||
|               'backcol': '#FFFFFF', |               'backcol': '#FFFFFF', | ||||||
|             } |             } | ||||||
|  |     # Versions of wxPython prior to 2.3.2 had a sizing bug on Win platform. | ||||||
|  |     # The font was 2 points too large. So we need to reduce the font size. | ||||||
|  |     if ((wxMAJOR_VERSION, wxMINOR_VERSION) == (2, 3) and wxRELEASE_NUMBER < 2) \ | ||||||
|  |     or (wxMAJOR_VERSION <= 2 and wxMINOR_VERSION <= 2): | ||||||
|  |         faces['size'] -= 2 | ||||||
|  |         faces['lnsize'] -= 2 | ||||||
| else:  # GTK | else:  # GTK | ||||||
|     faces = { 'times'  : 'Times', |     faces = { 'times'  : 'Times', | ||||||
|               'mono'   : 'Courier', |               'mono'   : 'Courier', | ||||||
| @@ -299,3 +306,4 @@ class App(wxApp): | |||||||
|         return true |         return true | ||||||
|  |  | ||||||
|  |  | ||||||
|  |    | ||||||
| @@ -48,16 +48,17 @@ class Interpreter(InteractiveInterpreter): | |||||||
|         """Send command to the interpreter to be executed. |         """Send command to the interpreter to be executed. | ||||||
|          |          | ||||||
|         Because this may be called recursively, we append a new list |         Because this may be called recursively, we append a new list | ||||||
|         onto the commandBuffer list and then append commands into |         onto the commandBuffer list and then append commands into that.  | ||||||
|         that. If the passed in command is part of a multi-line command |         If the passed in command is part of a multi-line command we keep  | ||||||
|         we keep appending the pieces to the last list in commandBuffer |         appending the pieces to the last list in commandBuffer until we  | ||||||
|         until we have a complete command, then, finally, we delete |         have a complete command. If not, we delete that last list.""" | ||||||
|         that last list.""" |         if not self.more: | ||||||
|  |             try: del self.commandBuffer[-1] | ||||||
|  |             except IndexError: pass | ||||||
|         if not self.more: self.commandBuffer.append([]) |         if not self.more: self.commandBuffer.append([]) | ||||||
|         self.commandBuffer[-1].append(command) |         self.commandBuffer[-1].append(command) | ||||||
|         source = '\n'.join(self.commandBuffer[-1]) |         source = '\n'.join(self.commandBuffer[-1]) | ||||||
|         self.more = self.runsource(source) |         self.more = self.runsource(source) | ||||||
|         if not self.more: del self.commandBuffer[-1] |  | ||||||
|         return self.more |         return self.more | ||||||
|          |          | ||||||
|     def runsource(self, source): |     def runsource(self, source): | ||||||
| @@ -102,3 +103,4 @@ class InterpreterAlaCarte(Interpreter): | |||||||
|         sys.ps1 = ps1 |         sys.ps1 = ps1 | ||||||
|         sys.ps2 = ps2 |         sys.ps2 = ps2 | ||||||
|  |  | ||||||
|  |    | ||||||
| @@ -49,11 +49,18 @@ def getAllAttributeNames(object): | |||||||
|     Recursively walk through a class and all base classes. |     Recursively walk through a class and all base classes. | ||||||
|     """ |     """ | ||||||
|     attributes = [] |     attributes = [] | ||||||
|  |     # Wake up sleepy objects - a hack for ZODB objects in "ghost" state. | ||||||
|  |     wakeupcall = dir(object) | ||||||
|  |     del wakeupcall | ||||||
|     # Get attributes available through the normal convention. |     # Get attributes available through the normal convention. | ||||||
|     attributes += dir(object) |     attributes += dir(object) | ||||||
|     # For a class instance, get the attributes for the class. |     # For a class instance, get the attributes for the class. | ||||||
|     if hasattr(object, '__class__'): |     if hasattr(object, '__class__'): | ||||||
|         attributes += getAllAttributeNames(object.__class__) |         # Break a circular reference. This happens with extension classes. | ||||||
|  |         if object.__class__ is object: | ||||||
|  |             pass | ||||||
|  |         else: | ||||||
|  |             attributes += getAllAttributeNames(object.__class__) | ||||||
|     # Also get attributes from any and all parent classes. |     # Also get attributes from any and all parent classes. | ||||||
|     if hasattr(object, '__bases__'): |     if hasattr(object, '__bases__'): | ||||||
|         for base in object.__bases__: |         for base in object.__bases__: | ||||||
| @@ -74,13 +81,13 @@ def getCallTip(command='', locals=None): | |||||||
|     dropSelf = 0 |     dropSelf = 0 | ||||||
|     if hasattr(object, '__name__'):  # Make sure this is a useable object. |     if hasattr(object, '__name__'):  # Make sure this is a useable object. | ||||||
|         # Switch to the object that has the information we need. |         # Switch to the object that has the information we need. | ||||||
|         if inspect.ismethod(object): |         if inspect.ismethod(object) or hasattr(object, 'im_func'): | ||||||
|             # Get the function from the object otherwise inspec.getargspec() |             # Get the function from the object otherwise inspect.getargspec() | ||||||
|             # complains that the object isn't a Python function. |             # complains that the object isn't a Python function. | ||||||
|             object = object.im_func |             object = object.im_func | ||||||
|             dropSelf = 1 |             dropSelf = 1 | ||||||
|         elif inspect.isclass(object): |         elif inspect.isclass(object): | ||||||
|             # Get the __init__ method for the class. |             # Get the __init__ method function for the class. | ||||||
|             try: |             try: | ||||||
|                 object = object.__init__.im_func |                 object = object.__init__.im_func | ||||||
|                 dropSelf = 1 |                 dropSelf = 1 | ||||||
| @@ -92,10 +99,11 @@ def getCallTip(command='', locals=None): | |||||||
|                         dropSelf = 1 |                         dropSelf = 1 | ||||||
|                         break |                         break | ||||||
|         name = object.__name__ |         name = object.__name__ | ||||||
|  |         tip1 = '' | ||||||
|         if inspect.isbuiltin(object): |         if inspect.isbuiltin(object): | ||||||
|             # Builtin functions don't have an argspec that we can get. |             # Builtin functions don't have an argspec that we can get. | ||||||
|             tip1 = '' |             pass | ||||||
|         else: |         elif inspect.isfunction(object): | ||||||
|             # tip1 is a string like: "getCallTip(command='', locals=None)" |             # tip1 is a string like: "getCallTip(command='', locals=None)" | ||||||
|             argspec = apply(inspect.formatargspec, inspect.getargspec(object)) |             argspec = apply(inspect.formatargspec, inspect.getargspec(object)) | ||||||
|             if dropSelf: |             if dropSelf: | ||||||
| @@ -129,7 +137,7 @@ def getRoot(command, terminator=None): | |||||||
|      |      | ||||||
|     The command would normally terminate with a "(" or ".". Anything after  |     The command would normally terminate with a "(" or ".". Anything after  | ||||||
|     the terminator will be dropped, allowing you to get back to the root. |     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. |     Return only the root portion that can be eval()'d without side effects. | ||||||
|     """ |     """ | ||||||
|     root = '' |     root = '' | ||||||
|     validChars = "._" + string.uppercase + string.lowercase + string.digits |     validChars = "._" + string.uppercase + string.lowercase + string.digits | ||||||
| @@ -151,7 +159,7 @@ def getRoot(command, terminator=None): | |||||||
|         # Detect situations where we are in the middle of a string. |         # Detect situations where we are in the middle of a string. | ||||||
|         # This code catches the simplest case, but needs to catch others. |         # This code catches the simplest case, but needs to catch others. | ||||||
|         if command[i-1] in ("'", '"'): |         if command[i-1] in ("'", '"'): | ||||||
|             # Were in the middle of a string so we aren't dealing with an |             # We're in the middle of a string so we aren't dealing with an | ||||||
|             # object and it would be misleading to return anything here. |             # object and it would be misleading to return anything here. | ||||||
|             root = '' |             root = '' | ||||||
|         else: |         else: | ||||||
| @@ -159,3 +167,4 @@ def getRoot(command, terminator=None): | |||||||
|             root = command[i:] |             root = command[i:] | ||||||
|     return root |     return root | ||||||
|  |  | ||||||
|  |       | ||||||
| @@ -25,10 +25,16 @@ if wxPlatform == '__WXMSW__': | |||||||
|               'helv'   : 'Lucida Console', |               'helv'   : 'Lucida Console', | ||||||
|               'lucida' : 'Lucida Console', |               'lucida' : 'Lucida Console', | ||||||
|               'other'  : 'Comic Sans MS', |               'other'  : 'Comic Sans MS', | ||||||
|               'size'   : 8, |               'size'   : 10, | ||||||
|               'lnsize' : 7, |               'lnsize' : 9, | ||||||
|               'backcol': '#FFFFFF', |               'backcol': '#FFFFFF', | ||||||
|             } |             } | ||||||
|  |     # Versions of wxPython prior to 2.3.2 had a sizing bug on Win platform. | ||||||
|  |     # The font was 2 points too large. So we need to reduce the font size. | ||||||
|  |     if ((wxMAJOR_VERSION, wxMINOR_VERSION) == (2, 3) and wxRELEASE_NUMBER < 2) \ | ||||||
|  |     or (wxMAJOR_VERSION <= 2 and wxMINOR_VERSION <= 2): | ||||||
|  |         faces['size'] -= 2 | ||||||
|  |         faces['lnsize'] -= 2 | ||||||
| else:  # GTK | else:  # GTK | ||||||
|     faces = { 'times'  : 'Times', |     faces = { 'times'  : 'Times', | ||||||
|               'mono'   : 'Courier', |               'mono'   : 'Courier', | ||||||
| @@ -40,6 +46,62 @@ else:  # GTK | |||||||
|             } |             } | ||||||
|  |  | ||||||
|  |  | ||||||
|  | class ShellFacade: | ||||||
|  |     """Simplified interface to all shell-related functionality. | ||||||
|  |  | ||||||
|  |     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' | ||||||
|  |     revision = __version__ | ||||||
|  |  | ||||||
|  |     def __init__(self, other): | ||||||
|  |         """Create a ShellFacade instance.""" | ||||||
|  |         methods = ['ask', | ||||||
|  |                    'clear', | ||||||
|  |                    'pause', | ||||||
|  |                    'prompt', | ||||||
|  |                    'quit', | ||||||
|  |                    'redirectStderr', | ||||||
|  |                    'redirectStdin', | ||||||
|  |                    'redirectStdout', | ||||||
|  |                    'run', | ||||||
|  |                    'runfile', | ||||||
|  |                   ] | ||||||
|  |         for method in methods: | ||||||
|  |             self.__dict__[method] = getattr(other, method) | ||||||
|  |         d = self.__dict__ | ||||||
|  |         d['other'] = other | ||||||
|  |         d['help'] = 'There is no help available, yet.' | ||||||
|  |  | ||||||
|  |  | ||||||
|  |     def __getattr__(self, name): | ||||||
|  |         if hasattr(self.other, name): | ||||||
|  |             return getattr(self.other, name) | ||||||
|  |         else: | ||||||
|  |             raise AttributeError, name | ||||||
|  |  | ||||||
|  |     def __setattr__(self, name, value): | ||||||
|  |         if self.__dict__.has_key(name): | ||||||
|  |             self.__dict__[name] = value | ||||||
|  |         elif hasattr(self.other, name): | ||||||
|  |             return setattr(self.other, name, value) | ||||||
|  |         else: | ||||||
|  |             raise AttributeError, name | ||||||
|  |  | ||||||
|  |     def _getAttributeNames(self): | ||||||
|  |         """Return list of magic attributes to extend introspection.""" | ||||||
|  |         list = ['autoCallTip', | ||||||
|  |                 'autoComplete', | ||||||
|  |                 'autoCompleteCaseInsensitive', | ||||||
|  |                 'autoCompleteIncludeDouble', | ||||||
|  |                 'autoCompleteIncludeMagic', | ||||||
|  |                 'autoCompleteIncludeSingle', | ||||||
|  |                ] | ||||||
|  |         list.sort() | ||||||
|  |         return list | ||||||
|  |  | ||||||
|  |  | ||||||
| class Shell(wxStyledTextCtrl): | class Shell(wxStyledTextCtrl): | ||||||
|     """PyCrust Shell based on wxStyledTextCtrl.""" |     """PyCrust Shell based on wxStyledTextCtrl.""" | ||||||
|  |  | ||||||
| @@ -78,26 +140,18 @@ class Shell(wxStyledTextCtrl): | |||||||
|                                   *args, **kwds) |                                   *args, **kwds) | ||||||
|         # Keep track of the most recent prompt starting and ending positions. |         # Keep track of the most recent prompt starting and ending positions. | ||||||
|         self.promptPos = [0, 0] |         self.promptPos = [0, 0] | ||||||
|  |         # Keep track of the most recent non-continuation prompt. | ||||||
|  |         self.prompt1Pos = [0, 0] | ||||||
|         # Keep track of multi-line commands. |         # Keep track of multi-line commands. | ||||||
|         self.more = 0 |         self.more = 0 | ||||||
|         # Create the command history.  Commands are added into the front of |         # Create the command history.  Commands are added into the front of | ||||||
|         # the list (ie. at index 0) as they are entered.  self.historyPos is |         # the list (ie. at index 0) as they are entered. self.historyIndex | ||||||
|         # the current position in the history; it gets incremented as you |         # is the current position in the history; it gets incremented as you | ||||||
|         # retrieve the previous command, decremented as you retrieve the next, |         # retrieve the previous command, decremented as you retrieve the | ||||||
|         # and reset when you hit Enter. self.historyPos == -1 means you're on |         # next, and reset when you hit Enter. self.historyIndex == -1 means | ||||||
|         # the current command, not in the history. self.tempCommand is |         # you're on the current command, not in the history. | ||||||
|         # storage space for whatever was on the last line when you first hit |  | ||||||
|         # "Retrieve-Previous", so that the final "Retrieve-Next" will restore |  | ||||||
|         # whatever was originally there.  self.lastCommandRecalled remembers |  | ||||||
|         # the index of the last command to be recalled from the history, so |  | ||||||
|         # you can repeat a group of commands by going up-up-up-enter to find |  | ||||||
|         # the first one in the group then down-enter-down-enter to recall each |  | ||||||
|         # subsequent command.  Also useful for multiline commands, in lieu of |  | ||||||
|         # a proper implementation of those. |  | ||||||
|         self.history = [] |         self.history = [] | ||||||
|         self.historyPos = -1 |         self.historyIndex = -1 | ||||||
|         self.tempCommand = '' |  | ||||||
|         self.lastCommandRecalled = -1 |  | ||||||
|         # Assign handlers for keyboard events. |         # Assign handlers for keyboard events. | ||||||
|         EVT_KEY_DOWN(self, self.OnKeyDown) |         EVT_KEY_DOWN(self, self.OnKeyDown) | ||||||
|         EVT_CHAR(self, self.OnChar) |         EVT_CHAR(self, self.OnChar) | ||||||
| @@ -176,15 +230,15 @@ class Shell(wxStyledTextCtrl): | |||||||
|  |  | ||||||
|         # XXX Good enough for now but later we want to send a close event. |         # 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. |         # In the close event handler we can make sure they want to quit. | ||||||
|         # Other applications, like PythonCard, may choose to hide rather than |         # Other applications, like PythonCard, may choose to hide rather than | ||||||
|         # quit so we should just post the event and let the surrounding app |         # quit so we should just post the event and let the surrounding app | ||||||
|         # decide what it wants to do. |         # decide what it wants to do. | ||||||
|         self.write('Click on the close button to leave the application.') |         self.write('Click on the close button to leave the application.') | ||||||
|  |  | ||||||
|     def setLocalShell(self): |     def setLocalShell(self): | ||||||
|         """Add 'shell' to locals.""" |         """Add 'shell' to locals as reference to ShellFacade instance.""" | ||||||
|         self.interp.locals['shell'] = self |         self.interp.locals['shell'] = ShellFacade(other=self) | ||||||
|  |  | ||||||
|     def execStartupScript(self, startupScript): |     def execStartupScript(self, startupScript): | ||||||
|         """Execute the user's PYTHONSTARTUP script if they have one.""" |         """Execute the user's PYTHONSTARTUP script if they have one.""" | ||||||
| @@ -225,90 +279,57 @@ class Shell(wxStyledTextCtrl): | |||||||
|         self.StyleSetSpec(wxSTC_P_COMMENTBLOCK, "fore:#7F7F7F") |         self.StyleSetSpec(wxSTC_P_COMMENTBLOCK, "fore:#7F7F7F") | ||||||
|         self.StyleSetSpec(wxSTC_P_STRINGEOL, "fore:#000000,face:%(mono)s,back:#E0C0E0,eolfilled" % faces) |         self.StyleSetSpec(wxSTC_P_STRINGEOL, "fore:#000000,face:%(mono)s,back:#E0C0E0,eolfilled" % faces) | ||||||
|  |  | ||||||
|  |     def OnChar(self, event): | ||||||
|  |         """Keypress event handler. | ||||||
|  |  | ||||||
|  |         Prevents modification of previously submitted commands/responses.""" | ||||||
|  |         key = event.KeyCode() | ||||||
|  |         currpos = self.GetCurrentPos() | ||||||
|  |         if currpos < self.prompt1Pos[1]: | ||||||
|  |             wxBell() | ||||||
|  |             return | ||||||
|  |         stoppos = self.promptPos[1] | ||||||
|  |         if key == ord('.'): | ||||||
|  |             # 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 == ord('('): | ||||||
|  |             # The left paren activates a call tip and cancels | ||||||
|  |             # an active auto completion. | ||||||
|  |             if self.AutoCompActive(): self.AutoCompCancel() | ||||||
|  |             # Get the command between the prompt and the cursor. | ||||||
|  |             # Add the '(' to the end of the command. | ||||||
|  |             command = self.GetTextRange(stoppos, currpos) + '(' | ||||||
|  |             self.write('(') | ||||||
|  |             if self.autoCallTip: self.autoCallTipShow(command) | ||||||
|  |         else: | ||||||
|  |             # Allow the normal event handling to take place. | ||||||
|  |             event.Skip() | ||||||
|  |  | ||||||
|     def OnKeyDown(self, event): |     def OnKeyDown(self, event): | ||||||
|         """Key down event handler. |         """Key down event handler. | ||||||
|  |  | ||||||
|         The main goal here is to not allow modifications to previous  |         Prevents modification of previously submitted commands/responses.""" | ||||||
|         lines of text.""" |  | ||||||
|         key = event.KeyCode() |         key = event.KeyCode() | ||||||
|         currpos = self.GetCurrentPos() |         currpos = self.GetCurrentPos() | ||||||
|         stoppos = self.promptPos[1] |         stoppos = self.promptPos[1] | ||||||
|         # If the auto-complete window is up let it do its thing. |         # If the auto-complete window is up let it do its thing. | ||||||
|         if self.AutoCompActive(): |         if self.AutoCompActive(): | ||||||
|             event.Skip() |             event.Skip() | ||||||
|         # Control+UpArrow steps up through the history. |         # Retrieve the previous command from the history buffer. | ||||||
|         elif key == WXK_UP and event.ControlDown() \ |         elif (event.ControlDown() and key == WXK_UP) \ | ||||||
|         and self.historyPos < len(self.history) - 1: |         or (event.AltDown() and key in (ord('P'), ord('p'))): | ||||||
|             # Move to the end of the buffer. |             self.OnHistoryRetrieve(step=+1) | ||||||
|             endpos = self.GetTextLength() |         # Retrieve the next command from the history buffer. | ||||||
|             self.SetCurrentPos(endpos) |         elif (event.ControlDown() and key == WXK_DOWN) \ | ||||||
|             # The first Control+Up stores the current command; |         or (event.AltDown() and key in (ord('N'), ord('n'))): | ||||||
|             # Control+Down brings it back. |             self.OnHistoryRetrieve(step=-1) | ||||||
|             if self.historyPos == -1: |         # Search up the history for the text in front of the cursor. | ||||||
|                 self.tempCommand = self.getCommand() |         elif key == WXK_F8: | ||||||
|             # Now replace the current line with the next one from the history. |             self.OnHistorySearch() | ||||||
|             self.historyPos = self.historyPos + 1 |  | ||||||
|             self.SetSelection(stoppos, endpos) |  | ||||||
|             self.ReplaceSelection(self.history[self.historyPos]) |  | ||||||
|         # Control+DownArrow steps down through the history. |  | ||||||
|         elif key == WXK_DOWN and event.ControlDown(): |  | ||||||
|             # Move to the end of the buffer. |  | ||||||
|             endpos = self.GetTextLength() |  | ||||||
|             self.SetCurrentPos(endpos) |  | ||||||
|             # Are we at the bottom end of the history? |  | ||||||
|             if self.historyPos == -1: |  | ||||||
|                 # Do we have a lastCommandRecalled stored? |  | ||||||
|                 if self.lastCommandRecalled >= 0: |  | ||||||
|                     # Replace the current line with the command after the |  | ||||||
|                     # last-recalled command (you'd think there should be a +1 |  | ||||||
|                     # here but there isn't because the history was shuffled up |  | ||||||
|                     # by 1 after the previous command was recalled). |  | ||||||
|                     self.SetSelection(stoppos, endpos) |  | ||||||
|                     self.ReplaceSelection(self.history[self.lastCommandRecalled]) |  | ||||||
|                     # We've now warped into middle of the history. |  | ||||||
|                     self.historyPos = self.lastCommandRecalled |  | ||||||
|                     self.lastCommandRecalled = -1 |  | ||||||
|             else: |  | ||||||
|                 # Fetch either the previous line from the history, or the saved |  | ||||||
|                 # command if we're back at the start. |  | ||||||
|                 self.historyPos = self.historyPos - 1 |  | ||||||
|                 if self.historyPos == -1: |  | ||||||
|                     newText = self.tempCommand |  | ||||||
|                 else: |  | ||||||
|                     newText = self.history[self.historyPos] |  | ||||||
|                 # Replace the current line with the new text. |  | ||||||
|                 self.SetSelection(stoppos, endpos) |  | ||||||
|                 self.ReplaceSelection(newText) |  | ||||||
|         # F8 on the last line does a search up the history for the text in |  | ||||||
|         # front of the cursor. |  | ||||||
|         elif key == WXK_F8 and self.GetCurrentLine() == self.GetLineCount()-1: |  | ||||||
|             tempCommand = self.getCommand() |  | ||||||
|             # The first F8 saves the current command, just like Control+Up. |  | ||||||
|             if self.historyPos == -1: |  | ||||||
|                 self.tempCommand = tempCommand |  | ||||||
|             # The text up to the cursor is what we search for. |  | ||||||
|             searchText = tempCommand |  | ||||||
|             numCharsAfterCursor = self.GetTextLength() - self.GetCurrentPos() |  | ||||||
|             if numCharsAfterCursor > 0: |  | ||||||
|                 searchText = searchText[:-numCharsAfterCursor] |  | ||||||
|             # Search upwards from the current history position and loop back |  | ||||||
|             # to the beginning if we don't find anything. |  | ||||||
|             for i in range(self.historyPos+1, len(self.history)) + \ |  | ||||||
|                      range(self.historyPos): |  | ||||||
|                 command = self.history[i] |  | ||||||
|                 if command[:len(searchText)] == searchText: |  | ||||||
|                     # Replace the current line with the one we've found. |  | ||||||
|                     endpos = self.GetTextLength() |  | ||||||
|                     self.SetSelection(stoppos, endpos) |  | ||||||
|                     self.ReplaceSelection(command) |  | ||||||
|                     # Put the cursor back at the end of the search text. |  | ||||||
|                     pos = self.GetTextLength() - len(command) + len(searchText) |  | ||||||
|                     self.SetCurrentPos(pos) |  | ||||||
|                     self.SetAnchor(pos) |  | ||||||
|                     # We've now warped into middle of the history. |  | ||||||
|                     self.historyPos = i |  | ||||||
|                     self.lastCommandRecalled = -1 |  | ||||||
|                     break |  | ||||||
|         # Return is used to submit a command to the interpreter. |         # Return is used to submit a command to the interpreter. | ||||||
|         elif key == WXK_RETURN: |         elif key == WXK_RETURN: | ||||||
|             if self.CallTipActive: self.CallTipCancel() |             if self.CallTipActive: self.CallTipCancel() | ||||||
| @@ -316,8 +337,12 @@ class Shell(wxStyledTextCtrl): | |||||||
|         # Home needs to be aware of the prompt. |         # Home needs to be aware of the prompt. | ||||||
|         elif key == WXK_HOME: |         elif key == WXK_HOME: | ||||||
|             if currpos >= stoppos: |             if currpos >= stoppos: | ||||||
|                 self.SetCurrentPos(stoppos) |                 if event.ShiftDown(): | ||||||
|                 self.SetAnchor(stoppos) |                     # Select text from current position to end of prompt. | ||||||
|  |                     self.SetSelection(self.GetCurrentPos(), stoppos) | ||||||
|  |                 else: | ||||||
|  |                     self.SetCurrentPos(stoppos) | ||||||
|  |                     self.SetAnchor(stoppos) | ||||||
|             else: |             else: | ||||||
|                 event.Skip() |                 event.Skip() | ||||||
|         # Basic navigation keys should work anywhere. |         # Basic navigation keys should work anywhere. | ||||||
| @@ -326,11 +351,11 @@ class Shell(wxStyledTextCtrl): | |||||||
|             event.Skip() |             event.Skip() | ||||||
|         # Don't backspace over the latest prompt. |         # Don't backspace over the latest prompt. | ||||||
|         elif key == WXK_BACK: |         elif key == WXK_BACK: | ||||||
|             if currpos > stoppos: |             if currpos > self.prompt1Pos[1]: | ||||||
|                 event.Skip() |                 event.Skip() | ||||||
|         # Only allow these keys after the latest prompt. |         # Only allow these keys after the latest prompt. | ||||||
|         elif key in (WXK_TAB, WXK_DELETE): |         elif key in (WXK_TAB, WXK_DELETE): | ||||||
|             if currpos >= stoppos: |             if currpos >= self.prompt1Pos[1]: | ||||||
|                 event.Skip() |                 event.Skip() | ||||||
|         # Don't toggle between insert mode and overwrite mode. |         # Don't toggle between insert mode and overwrite mode. | ||||||
|         elif key == WXK_INSERT: |         elif key == WXK_INSERT: | ||||||
| @@ -338,36 +363,58 @@ class Shell(wxStyledTextCtrl): | |||||||
|         else: |         else: | ||||||
|             event.Skip() |             event.Skip() | ||||||
|  |  | ||||||
|     def OnChar(self, event): |     def OnHistoryRetrieve(self, step): | ||||||
|         """Keypress event handler. |         """Retrieve the previous/next command from the history buffer.""" | ||||||
|          |         startpos = self.GetCurrentPos() | ||||||
|         The main goal here is to not allow modifications to previous  |         if startpos < self.prompt1Pos[1]: | ||||||
|         lines of text.""" |             wxBell() | ||||||
|         key = event.KeyCode() |             return | ||||||
|         currpos = self.GetCurrentPos() |         newindex = self.historyIndex + step | ||||||
|         stoppos = self.promptPos[1] |         if not (-1 <= newindex < len(self.history)): | ||||||
|         if currpos >= stoppos: |             wxBell() | ||||||
|             if key == 46: |             return | ||||||
|                 # "." The dot or period key activates auto completion. |         self.historyIndex = newindex | ||||||
|                 # Get the command between the prompt and the cursor. |         if newindex == -1: | ||||||
|                 # Add a dot to the end of the command. |             self.ReplaceSelection('') | ||||||
|                 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: |         else: | ||||||
|             pass |             self.ReplaceSelection('') | ||||||
|  |             command = self.history[self.historyIndex] | ||||||
|  |             command = command.replace('\n', os.linesep + sys.ps2) | ||||||
|  |             self.ReplaceSelection(command) | ||||||
|  |         endpos = self.GetCurrentPos() | ||||||
|  |         self.SetSelection(endpos, startpos) | ||||||
|  |  | ||||||
|  |     def OnHistorySearch(self): | ||||||
|  |         """Search up the history buffer for the text in front of the cursor.""" | ||||||
|  |         startpos = self.GetCurrentPos() | ||||||
|  |         if startpos < self.prompt1Pos[1]: | ||||||
|  |             wxBell() | ||||||
|  |             return | ||||||
|  |         # The text up to the cursor is what we search for. | ||||||
|  |         numCharsAfterCursor = self.GetTextLength() - startpos | ||||||
|  |         searchText = self.getCommand(rstrip=0) | ||||||
|  |         if numCharsAfterCursor > 0: | ||||||
|  |             searchText = searchText[:-numCharsAfterCursor] | ||||||
|  |         if not searchText: | ||||||
|  |             return | ||||||
|  |         # Search upwards from the current history position and loop back | ||||||
|  |         # to the beginning if we don't find anything. | ||||||
|  |         if (self.historyIndex <= -1) \ | ||||||
|  |         or (self.historyIndex >= len(self.history)-2): | ||||||
|  |             searchOrder = range(len(self.history)) | ||||||
|  |         else: | ||||||
|  |             searchOrder = range(self.historyIndex+1, len(self.history)) + \ | ||||||
|  |                           range(self.historyIndex) | ||||||
|  |         for i in searchOrder: | ||||||
|  |             command = self.history[i] | ||||||
|  |             if command[:len(searchText)] == searchText: | ||||||
|  |                 # Replace the current selection with the one we've found. | ||||||
|  |                 self.ReplaceSelection(command[len(searchText):]) | ||||||
|  |                 endpos = self.GetCurrentPos() | ||||||
|  |                 self.SetSelection(endpos, startpos) | ||||||
|  |                 # We've now warped into middle of the history. | ||||||
|  |                 self.historyIndex = i | ||||||
|  |                 break | ||||||
|  |  | ||||||
|     def setStatusText(self, text): |     def setStatusText(self, text): | ||||||
|         """Display status information.""" |         """Display status information.""" | ||||||
| @@ -382,32 +429,36 @@ class Shell(wxStyledTextCtrl): | |||||||
|         # The user hit ENTER and we need to decide what to do. They could be |         # The user hit ENTER and we need to decide what to do. They could be | ||||||
|         # sitting on any line in the shell. |         # sitting on any line in the shell. | ||||||
|  |  | ||||||
|         # Grab information about the current line. |  | ||||||
|         thepos = self.GetCurrentPos() |         thepos = self.GetCurrentPos() | ||||||
|         theline = self.GetCurrentLine() |  | ||||||
|         command = self.getCommand() |  | ||||||
|         # Go to the very bottom of the text. |  | ||||||
|         endpos = self.GetTextLength() |         endpos = self.GetTextLength() | ||||||
|         self.SetCurrentPos(endpos) |         # If they hit RETURN at the very bottom, execute the command. | ||||||
|         endline = self.GetCurrentLine() |         if thepos == endpos: | ||||||
|         # If they hit RETURN on the last line, execute the command. |             self.interp.more = 0 | ||||||
|         if theline == endline: |             if self.getCommand(): | ||||||
|  |                 command = self.GetTextRange(self.prompt1Pos[1], endpos) | ||||||
|  |             else: | ||||||
|  |                 command = self.GetTextRange(self.prompt1Pos[1], \ | ||||||
|  |                                             self.promptPos[1]) | ||||||
|  |             command = command.replace(os.linesep + sys.ps2, '\n') | ||||||
|             self.push(command) |             self.push(command) | ||||||
|         # Otherwise, replace the last line with the new line. |         # Otherwise, replace the last command with the new command. | ||||||
|         else: |         elif thepos < self.prompt1Pos[0]: | ||||||
|  |             theline = self.GetCurrentLine() | ||||||
|  |             command = self.getCommand() | ||||||
|             # If the new line contains a command (even an invalid one). |             # If the new line contains a command (even an invalid one). | ||||||
|             if command: |             if command: | ||||||
|                 startpos = self.PositionFromLine(endline) |                 self.SetCurrentPos(endpos) | ||||||
|  |                 startpos = self.prompt1Pos[1] | ||||||
|                 self.SetSelection(startpos, endpos) |                 self.SetSelection(startpos, endpos) | ||||||
|                 self.ReplaceSelection('') |                 self.ReplaceSelection('') | ||||||
|                 self.prompt() |  | ||||||
|                 self.write(command) |                 self.write(command) | ||||||
|  |                 self.more = 0 | ||||||
|             # Otherwise, put the cursor back where we started. |             # Otherwise, put the cursor back where we started. | ||||||
|             else: |             else: | ||||||
|                 self.SetCurrentPos(thepos) |                 self.SetCurrentPos(thepos) | ||||||
|                 self.SetAnchor(thepos) |                 self.SetAnchor(thepos) | ||||||
|  |  | ||||||
|     def getCommand(self, text=None): |     def getCommand(self, text=None, rstrip=1): | ||||||
|         """Extract a command from text which may include a shell prompt. |         """Extract a command from text which may include a shell prompt. | ||||||
|  |  | ||||||
|         The command may not necessarily be valid Python syntax.""" |         The command may not necessarily be valid Python syntax.""" | ||||||
| @@ -419,7 +470,8 @@ class Shell(wxStyledTextCtrl): | |||||||
|         ps1size = len(ps1) |         ps1size = len(ps1) | ||||||
|         ps2 = str(sys.ps2) |         ps2 = str(sys.ps2) | ||||||
|         ps2size = len(ps2) |         ps2size = len(ps2) | ||||||
|         text = text.rstrip() |         if rstrip: | ||||||
|  |             text = text.rstrip() | ||||||
|         # Strip the prompt off the front of text leaving just the command. |         # Strip the prompt off the front of text leaving just the command. | ||||||
|         if text[:ps1size] == ps1: |         if text[:ps1size] == ps1: | ||||||
|             command = text[ps1size:] |             command = text[ps1size:] | ||||||
| @@ -431,9 +483,10 @@ class Shell(wxStyledTextCtrl): | |||||||
|  |  | ||||||
|     def push(self, command): |     def push(self, command): | ||||||
|         """Send command to the interpreter for execution.""" |         """Send command to the interpreter for execution.""" | ||||||
|         self.addHistory(command) |  | ||||||
|         self.write(os.linesep) |         self.write(os.linesep) | ||||||
|         self.more = self.interp.push(command) |         self.more = self.interp.push(command) | ||||||
|  |         if not self.more: | ||||||
|  |             self.addHistory(command.rstrip()) | ||||||
|         self.prompt() |         self.prompt() | ||||||
|         # Keep the undo feature from undoing previous responses. The only |         # Keep the undo feature from undoing previous responses. The only | ||||||
|         # thing that can be undone is stuff typed after the prompt, before |         # thing that can be undone is stuff typed after the prompt, before | ||||||
| @@ -442,12 +495,8 @@ class Shell(wxStyledTextCtrl): | |||||||
|  |  | ||||||
|     def addHistory(self, command): |     def addHistory(self, command): | ||||||
|         """Add command to the command history.""" |         """Add command to the command history.""" | ||||||
|         # Store the last-recalled command; see the main comment for |  | ||||||
|         # self.lastCommandRecalled. |  | ||||||
|         if command != '': |  | ||||||
|             self.lastCommandRecalled = self.historyPos |  | ||||||
|         # Reset the history position. |         # Reset the history position. | ||||||
|         self.historyPos = -1 |         self.historyIndex = -1 | ||||||
|         # Insert this command into the history, unless it's a blank |         # Insert this command into the history, unless it's a blank | ||||||
|         # line or the same as the last command. |         # line or the same as the last command. | ||||||
|         if command != '' \ |         if command != '' \ | ||||||
| @@ -480,11 +529,13 @@ class Shell(wxStyledTextCtrl): | |||||||
|         pos = self.GetCurLine()[1] |         pos = self.GetCurLine()[1] | ||||||
|         if pos > 0: self.write(os.linesep) |         if pos > 0: self.write(os.linesep) | ||||||
|         self.promptPos[0] = self.GetCurrentPos() |         self.promptPos[0] = self.GetCurrentPos() | ||||||
|  |         if not self.more: self.prompt1Pos[0] = self.GetCurrentPos() | ||||||
|         self.write(prompt) |         self.write(prompt) | ||||||
|         self.promptPos[1] = self.GetCurrentPos() |         self.promptPos[1] = self.GetCurrentPos() | ||||||
|  |         if not self.more: self.prompt1Pos[1] = self.GetCurrentPos() | ||||||
|         # XXX Add some autoindent magic here if more. |         # XXX Add some autoindent magic here if more. | ||||||
|         if self.more: |         if self.more: | ||||||
|             self.write('\t')  # Temporary hack indentation. |             self.write(' '*4)  # Temporary hack indentation. | ||||||
|         self.EnsureCaretVisible() |         self.EnsureCaretVisible() | ||||||
|         self.ScrollToColumn(0) |         self.ScrollToColumn(0) | ||||||
|  |  | ||||||
| @@ -533,6 +584,9 @@ class Shell(wxStyledTextCtrl): | |||||||
|         this |         this | ||||||
|         >>> |         >>> | ||||||
|         """ |         """ | ||||||
|  |         # Go to the very bottom of the text. | ||||||
|  |         endpos = self.GetTextLength() | ||||||
|  |         self.SetCurrentPos(endpos) | ||||||
|         command = command.rstrip() |         command = command.rstrip() | ||||||
|         if prompt: self.prompt() |         if prompt: self.prompt() | ||||||
|         if verbose: self.write(command) |         if verbose: self.write(command) | ||||||
| @@ -813,3 +867,4 @@ class ShellFrame(wxFrame, ShellMenu): | |||||||
|         self.createMenus() |         self.createMenus() | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
|   | |||||||
| @@ -7,4 +7,4 @@ __cvsid__ = "$Id$" | |||||||
| __date__ = "July 1, 2001" | __date__ = "July 1, 2001" | ||||||
| __version__ = "$Revision$"[11:-2] | __version__ = "$Revision$"[11:-2] | ||||||
|  |  | ||||||
| VERSION = '0.6' | VERSION = '0.7' | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user