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)
|
||||
if objtype is types.DictType:
|
||||
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):
|
||||
# Believe it or not, some attributes can disappear, such as
|
||||
# the exc_traceback attribute of the sys module. So this is
|
||||
@@ -170,10 +171,16 @@ if wxPlatform == '__WXMSW__':
|
||||
'helv' : 'Lucida Console',
|
||||
'lucida' : 'Lucida Console',
|
||||
'other' : 'Comic Sans MS',
|
||||
'size' : 8,
|
||||
'lnsize' : 7,
|
||||
'size' : 10,
|
||||
'lnsize' : 9,
|
||||
'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
|
||||
faces = { 'times' : 'Times',
|
||||
'mono' : 'Courier',
|
||||
@@ -299,3 +306,4 @@ class App(wxApp):
|
||||
return true
|
||||
|
||||
|
||||
|
@@ -48,16 +48,17 @@ class Interpreter(InteractiveInterpreter):
|
||||
"""Send command to the interpreter to be executed.
|
||||
|
||||
Because this may be called recursively, we append a new list
|
||||
onto the commandBuffer list and then append commands into
|
||||
that. If the passed in command is part of a multi-line command
|
||||
we keep appending the pieces to the last list in commandBuffer
|
||||
until we have a complete command, then, finally, we delete
|
||||
that last list."""
|
||||
onto the commandBuffer list and then append commands into that.
|
||||
If the passed in command is part of a multi-line command we keep
|
||||
appending the pieces to the last list in commandBuffer until we
|
||||
have a complete command. If not, we delete that last list."""
|
||||
if not self.more:
|
||||
try: del self.commandBuffer[-1]
|
||||
except IndexError: pass
|
||||
if not self.more: self.commandBuffer.append([])
|
||||
self.commandBuffer[-1].append(command)
|
||||
source = '\n'.join(self.commandBuffer[-1])
|
||||
self.more = self.runsource(source)
|
||||
if not self.more: del self.commandBuffer[-1]
|
||||
return self.more
|
||||
|
||||
def runsource(self, source):
|
||||
@@ -102,3 +103,4 @@ class InterpreterAlaCarte(Interpreter):
|
||||
sys.ps1 = ps1
|
||||
sys.ps2 = ps2
|
||||
|
||||
|
@@ -49,10 +49,17 @@ def getAllAttributeNames(object):
|
||||
Recursively walk through a class and all base classes.
|
||||
"""
|
||||
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.
|
||||
attributes += dir(object)
|
||||
# For a class instance, get the attributes for the class.
|
||||
if hasattr(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.
|
||||
if hasattr(object, '__bases__'):
|
||||
@@ -74,13 +81,13 @@ def getCallTip(command='', locals=None):
|
||||
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):
|
||||
# Get the function from the object otherwise inspec.getargspec()
|
||||
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 for the class.
|
||||
# Get the __init__ method function for the class.
|
||||
try:
|
||||
object = object.__init__.im_func
|
||||
dropSelf = 1
|
||||
@@ -92,10 +99,11 @@ def getCallTip(command='', locals=None):
|
||||
dropSelf = 1
|
||||
break
|
||||
name = object.__name__
|
||||
tip1 = ''
|
||||
if inspect.isbuiltin(object):
|
||||
# Builtin functions don't have an argspec that we can get.
|
||||
tip1 = ''
|
||||
else:
|
||||
pass
|
||||
elif inspect.isfunction(object):
|
||||
# tip1 is a string like: "getCallTip(command='', locals=None)"
|
||||
argspec = apply(inspect.formatargspec, inspect.getargspec(object))
|
||||
if dropSelf:
|
||||
@@ -129,7 +137,7 @@ def getRoot(command, terminator=None):
|
||||
|
||||
The command would normally terminate with a "(" or ".". Anything after
|
||||
the terminator will be dropped, allowing you to get back to the root.
|
||||
Return only the root portion that can be eval()'d without side effect.
|
||||
Return only the root portion that can be eval()'d without side effects.
|
||||
"""
|
||||
root = ''
|
||||
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.
|
||||
# This code catches the simplest case, but needs to catch others.
|
||||
if command[i-1] in ("'", '"'):
|
||||
# Were in the middle of a string so we aren't dealing with an
|
||||
# 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.
|
||||
root = ''
|
||||
else:
|
||||
@@ -159,3 +167,4 @@ def getRoot(command, terminator=None):
|
||||
root = command[i:]
|
||||
return root
|
||||
|
||||
|
@@ -25,10 +25,16 @@ if wxPlatform == '__WXMSW__':
|
||||
'helv' : 'Lucida Console',
|
||||
'lucida' : 'Lucida Console',
|
||||
'other' : 'Comic Sans MS',
|
||||
'size' : 8,
|
||||
'lnsize' : 7,
|
||||
'size' : 10,
|
||||
'lnsize' : 9,
|
||||
'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
|
||||
faces = { 'times' : 'Times',
|
||||
'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):
|
||||
"""PyCrust Shell based on wxStyledTextCtrl."""
|
||||
|
||||
@@ -78,26 +140,18 @@ class Shell(wxStyledTextCtrl):
|
||||
*args, **kwds)
|
||||
# Keep track of the most recent prompt starting and ending positions.
|
||||
self.promptPos = [0, 0]
|
||||
# Keep track of the most recent non-continuation prompt.
|
||||
self.prompt1Pos = [0, 0]
|
||||
# Keep track of multi-line commands.
|
||||
self.more = 0
|
||||
# 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 current position in the history; it gets incremented as you
|
||||
# retrieve the previous command, decremented as you retrieve the next,
|
||||
# and reset when you hit Enter. self.historyPos == -1 means you're on
|
||||
# the current command, not in the history. self.tempCommand is
|
||||
# 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.
|
||||
# the list (ie. at index 0) as they are entered. self.historyIndex
|
||||
# is the current position in the history; it gets incremented as you
|
||||
# retrieve the previous command, decremented as you retrieve the
|
||||
# next, and reset when you hit Enter. self.historyIndex == -1 means
|
||||
# you're on the current command, not in the history.
|
||||
self.history = []
|
||||
self.historyPos = -1
|
||||
self.tempCommand = ''
|
||||
self.lastCommandRecalled = -1
|
||||
self.historyIndex = -1
|
||||
# Assign handlers for keyboard events.
|
||||
EVT_KEY_DOWN(self, self.OnKeyDown)
|
||||
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.
|
||||
|
||||
# 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
|
||||
# quit so we should just post the event and let the surrounding app
|
||||
# decide what it wants to do.
|
||||
self.write('Click on the close button to leave the application.')
|
||||
|
||||
def setLocalShell(self):
|
||||
"""Add 'shell' to locals."""
|
||||
self.interp.locals['shell'] = self
|
||||
"""Add 'shell' to locals as reference to ShellFacade instance."""
|
||||
self.interp.locals['shell'] = ShellFacade(other=self)
|
||||
|
||||
def execStartupScript(self, startupScript):
|
||||
"""Execute the user's PYTHONSTARTUP script if they have one."""
|
||||
@@ -225,137 +279,25 @@ class Shell(wxStyledTextCtrl):
|
||||
self.StyleSetSpec(wxSTC_P_COMMENTBLOCK, "fore:#7F7F7F")
|
||||
self.StyleSetSpec(wxSTC_P_STRINGEOL, "fore:#000000,face:%(mono)s,back:#E0C0E0,eolfilled" % faces)
|
||||
|
||||
def OnKeyDown(self, event):
|
||||
"""Key down event handler.
|
||||
|
||||
The main goal here is to not allow modifications to previous
|
||||
lines of text."""
|
||||
key = event.KeyCode()
|
||||
currpos = self.GetCurrentPos()
|
||||
stoppos = self.promptPos[1]
|
||||
# If the auto-complete window is up let it do its thing.
|
||||
if self.AutoCompActive():
|
||||
event.Skip()
|
||||
# Control+UpArrow steps up through the history.
|
||||
elif key == WXK_UP and event.ControlDown() \
|
||||
and self.historyPos < len(self.history) - 1:
|
||||
# Move to the end of the buffer.
|
||||
endpos = self.GetTextLength()
|
||||
self.SetCurrentPos(endpos)
|
||||
# The first Control+Up stores the current command;
|
||||
# Control+Down brings it back.
|
||||
if self.historyPos == -1:
|
||||
self.tempCommand = self.getCommand()
|
||||
# Now replace the current line with the next one from the history.
|
||||
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.
|
||||
elif key == WXK_RETURN:
|
||||
if self.CallTipActive: self.CallTipCancel()
|
||||
self.processLine()
|
||||
# Home needs to be aware of the prompt.
|
||||
elif key == WXK_HOME:
|
||||
if currpos >= stoppos:
|
||||
self.SetCurrentPos(stoppos)
|
||||
self.SetAnchor(stoppos)
|
||||
else:
|
||||
event.Skip()
|
||||
# Basic navigation keys should work anywhere.
|
||||
elif key in (WXK_END, WXK_LEFT, WXK_RIGHT, WXK_UP, WXK_DOWN, \
|
||||
WXK_PRIOR, WXK_NEXT):
|
||||
event.Skip()
|
||||
# Don't backspace over the latest prompt.
|
||||
elif key == WXK_BACK:
|
||||
if currpos > stoppos:
|
||||
event.Skip()
|
||||
# Only allow these keys after the latest prompt.
|
||||
elif key in (WXK_TAB, WXK_DELETE):
|
||||
if currpos >= stoppos:
|
||||
event.Skip()
|
||||
# Don't toggle between insert mode and overwrite mode.
|
||||
elif key == WXK_INSERT:
|
||||
pass
|
||||
else:
|
||||
event.Skip()
|
||||
|
||||
def OnChar(self, event):
|
||||
"""Keypress event handler.
|
||||
|
||||
The main goal here is to not allow modifications to previous
|
||||
lines of text."""
|
||||
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 currpos >= stoppos:
|
||||
if key == 46:
|
||||
# "." The dot or period key activates auto completion.
|
||||
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 == 40:
|
||||
# "(" The left paren activates a call tip and cancels
|
||||
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.
|
||||
@@ -366,8 +308,113 @@ class Shell(wxStyledTextCtrl):
|
||||
else:
|
||||
# Allow the normal event handling to take place.
|
||||
event.Skip()
|
||||
|
||||
def OnKeyDown(self, event):
|
||||
"""Key down event handler.
|
||||
|
||||
Prevents modification of previously submitted commands/responses."""
|
||||
key = event.KeyCode()
|
||||
currpos = self.GetCurrentPos()
|
||||
stoppos = self.promptPos[1]
|
||||
# If the auto-complete window is up let it do its thing.
|
||||
if self.AutoCompActive():
|
||||
event.Skip()
|
||||
# Retrieve the previous command from the history buffer.
|
||||
elif (event.ControlDown() and key == WXK_UP) \
|
||||
or (event.AltDown() and key in (ord('P'), ord('p'))):
|
||||
self.OnHistoryRetrieve(step=+1)
|
||||
# Retrieve the next command from the history buffer.
|
||||
elif (event.ControlDown() and key == WXK_DOWN) \
|
||||
or (event.AltDown() and key in (ord('N'), ord('n'))):
|
||||
self.OnHistoryRetrieve(step=-1)
|
||||
# Search up the history for the text in front of the cursor.
|
||||
elif key == WXK_F8:
|
||||
self.OnHistorySearch()
|
||||
# Return is used to submit a command to the interpreter.
|
||||
elif key == WXK_RETURN:
|
||||
if self.CallTipActive: self.CallTipCancel()
|
||||
self.processLine()
|
||||
# Home needs to be aware of the prompt.
|
||||
elif key == WXK_HOME:
|
||||
if currpos >= stoppos:
|
||||
if event.ShiftDown():
|
||||
# Select text from current position to end of prompt.
|
||||
self.SetSelection(self.GetCurrentPos(), stoppos)
|
||||
else:
|
||||
self.SetCurrentPos(stoppos)
|
||||
self.SetAnchor(stoppos)
|
||||
else:
|
||||
event.Skip()
|
||||
# Basic navigation keys should work anywhere.
|
||||
elif key in (WXK_END, WXK_LEFT, WXK_RIGHT, WXK_UP, WXK_DOWN, \
|
||||
WXK_PRIOR, WXK_NEXT):
|
||||
event.Skip()
|
||||
# Don't backspace over the latest prompt.
|
||||
elif key == WXK_BACK:
|
||||
if currpos > self.prompt1Pos[1]:
|
||||
event.Skip()
|
||||
# Only allow these keys after the latest prompt.
|
||||
elif key in (WXK_TAB, WXK_DELETE):
|
||||
if currpos >= self.prompt1Pos[1]:
|
||||
event.Skip()
|
||||
# Don't toggle between insert mode and overwrite mode.
|
||||
elif key == WXK_INSERT:
|
||||
pass
|
||||
else:
|
||||
event.Skip()
|
||||
|
||||
def OnHistoryRetrieve(self, step):
|
||||
"""Retrieve the previous/next command from the history buffer."""
|
||||
startpos = self.GetCurrentPos()
|
||||
if startpos < self.prompt1Pos[1]:
|
||||
wxBell()
|
||||
return
|
||||
newindex = self.historyIndex + step
|
||||
if not (-1 <= newindex < len(self.history)):
|
||||
wxBell()
|
||||
return
|
||||
self.historyIndex = newindex
|
||||
if newindex == -1:
|
||||
self.ReplaceSelection('')
|
||||
else:
|
||||
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):
|
||||
"""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
|
||||
# sitting on any line in the shell.
|
||||
|
||||
# Grab information about the current line.
|
||||
thepos = self.GetCurrentPos()
|
||||
endpos = self.GetTextLength()
|
||||
# If they hit RETURN at the very bottom, execute the command.
|
||||
if thepos == endpos:
|
||||
self.interp.more = 0
|
||||
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)
|
||||
# Otherwise, replace the last command with the new command.
|
||||
elif thepos < self.prompt1Pos[0]:
|
||||
theline = self.GetCurrentLine()
|
||||
command = self.getCommand()
|
||||
# Go to the very bottom of the text.
|
||||
endpos = self.GetTextLength()
|
||||
self.SetCurrentPos(endpos)
|
||||
endline = self.GetCurrentLine()
|
||||
# If they hit RETURN on the last line, execute the command.
|
||||
if theline == endline:
|
||||
self.push(command)
|
||||
# Otherwise, replace the last line with the new line.
|
||||
else:
|
||||
# If the new line contains a command (even an invalid one).
|
||||
if command:
|
||||
startpos = self.PositionFromLine(endline)
|
||||
self.SetCurrentPos(endpos)
|
||||
startpos = self.prompt1Pos[1]
|
||||
self.SetSelection(startpos, endpos)
|
||||
self.ReplaceSelection('')
|
||||
self.prompt()
|
||||
self.write(command)
|
||||
self.more = 0
|
||||
# Otherwise, put the cursor back where we started.
|
||||
else:
|
||||
self.SetCurrentPos(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.
|
||||
|
||||
The command may not necessarily be valid Python syntax."""
|
||||
@@ -419,6 +470,7 @@ class Shell(wxStyledTextCtrl):
|
||||
ps1size = len(ps1)
|
||||
ps2 = str(sys.ps2)
|
||||
ps2size = len(ps2)
|
||||
if rstrip:
|
||||
text = text.rstrip()
|
||||
# Strip the prompt off the front of text leaving just the command.
|
||||
if text[:ps1size] == ps1:
|
||||
@@ -431,9 +483,10 @@ class Shell(wxStyledTextCtrl):
|
||||
|
||||
def push(self, command):
|
||||
"""Send command to the interpreter for execution."""
|
||||
self.addHistory(command)
|
||||
self.write(os.linesep)
|
||||
self.more = self.interp.push(command)
|
||||
if not self.more:
|
||||
self.addHistory(command.rstrip())
|
||||
self.prompt()
|
||||
# Keep the undo feature from undoing previous responses. The only
|
||||
# thing that can be undone is stuff typed after the prompt, before
|
||||
@@ -442,12 +495,8 @@ class Shell(wxStyledTextCtrl):
|
||||
|
||||
def addHistory(self, command):
|
||||
"""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.
|
||||
self.historyPos = -1
|
||||
self.historyIndex = -1
|
||||
# Insert this command into the history, unless it's a blank
|
||||
# line or the same as the last command.
|
||||
if command != '' \
|
||||
@@ -480,11 +529,13 @@ class Shell(wxStyledTextCtrl):
|
||||
pos = self.GetCurLine()[1]
|
||||
if pos > 0: self.write(os.linesep)
|
||||
self.promptPos[0] = self.GetCurrentPos()
|
||||
if not self.more: self.prompt1Pos[0] = self.GetCurrentPos()
|
||||
self.write(prompt)
|
||||
self.promptPos[1] = self.GetCurrentPos()
|
||||
if not self.more: self.prompt1Pos[1] = self.GetCurrentPos()
|
||||
# XXX Add some autoindent magic here if more.
|
||||
if self.more:
|
||||
self.write('\t') # Temporary hack indentation.
|
||||
self.write(' '*4) # Temporary hack indentation.
|
||||
self.EnsureCaretVisible()
|
||||
self.ScrollToColumn(0)
|
||||
|
||||
@@ -533,6 +584,9 @@ class Shell(wxStyledTextCtrl):
|
||||
this
|
||||
>>>
|
||||
"""
|
||||
# Go to the very bottom of the text.
|
||||
endpos = self.GetTextLength()
|
||||
self.SetCurrentPos(endpos)
|
||||
command = command.rstrip()
|
||||
if prompt: self.prompt()
|
||||
if verbose: self.write(command)
|
||||
@@ -813,3 +867,4 @@ class ShellFrame(wxFrame, ShellMenu):
|
||||
self.createMenus()
|
||||
|
||||
|
||||
|
||||
|
@@ -7,4 +7,4 @@ __cvsid__ = "$Id$"
|
||||
__date__ = "July 1, 2001"
|
||||
__version__ = "$Revision$"[11:-2]
|
||||
|
||||
VERSION = '0.6'
|
||||
VERSION = '0.7'
|
||||
|
Reference in New Issue
Block a user