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:
Robin Dunn
2001-10-18 01:20:54 +00:00
parent 5a8f04e382
commit 2fe212b033
5 changed files with 275 additions and 201 deletions

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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()

View File

@@ -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'