--- /dev/null
+*.pyc
+*.BAK
+*.$$$
\ No newline at end of file
from wxPython.wx import *
-from PyCrustVersion import version
-from PyCrustShell import Shell
+from version import VERSION
+from shell import Shell
+
+ID_AUTOCOMP = NewId()
+ID_AUTOCOMP_SHOW = NewId()
+ID_AUTOCOMP_INCLUDE_MAGIC = NewId()
+ID_AUTOCOMP_INCLUDE_SINGLE = NewId()
+ID_AUTOCOMP_INCLUDE_DOUBLE = NewId()
+ID_CALLTIPS = NewId()
+ID_CALLTIPS_SHOW = NewId()
class Frame(wxFrame):
def __init__(self, parent, id, title):
"""Create the main frame object for the application."""
wxFrame.__init__(self, parent, id, title)
- intro = 'Welcome To PyCrust %s - The Flakiest Python Shell' % version
+ intro = 'Welcome To PyCrust %s - The Flakiest Python Shell' % VERSION
self.CreateStatusBar()
self.SetStatusText(intro)
+ self.icon = wxIcon('PyCrust.ico', wxBITMAP_TYPE_ICO)
+ self.SetIcon(self.icon)
self.createMenus()
- # Create the shell, which will create a default editor and
- # a default interpreter.
- self.shell = Shell(editorParent=self, introText=intro)
- # Override the editor so that status messages go to the status bar.
- self.shell.editor.setStatusText = self.SetStatusText
+ # Create the shell, which will create a default interpreter.
+ locals = {'__app__': 'PyCrust Application'}
+ self.shell = Shell(parent=self, id=-1, introText=intro, locals=locals)
+ # Override the shell so that status messages go to the status bar.
+ self.shell.setStatusText = self.SetStatusText
def createMenus(self):
m = self.fileMenu = wxMenu()
m.Append(wxID_CLEAR, 'Cle&ar \tDel', 'Delete the selection')
m.Append(wxID_SELECTALL, 'Select A&ll \tCtrl+A', 'Select all text')
+ m = self.autocompMenu = wxMenu()
+ m.Append(ID_AUTOCOMP_SHOW, 'Show Auto Completion', \
+ 'Show auto completion during dot syntax', checkable=1)
+ m.Append(ID_AUTOCOMP_INCLUDE_MAGIC, 'Include Magic Attributes', \
+ 'Include attributes visible to __getattr__ and __setattr__', checkable=1)
+ m.Append(ID_AUTOCOMP_INCLUDE_SINGLE, 'Include Single Underscores', \
+ 'Include attibutes prefixed by a single underscore', checkable=1)
+ m.Append(ID_AUTOCOMP_INCLUDE_DOUBLE, 'Include Double Underscores', \
+ 'Include attibutes prefixed by a double underscore', checkable=1)
+
+ m = self.calltipsMenu = wxMenu()
+ m.Append(ID_CALLTIPS_SHOW, 'Show Call Tips', \
+ 'Show call tips with argument specifications', checkable=1)
+
+ m = self.optionsMenu = wxMenu()
+ m.AppendMenu(ID_AUTOCOMP, '&Auto Completion', self.autocompMenu, \
+ 'Auto Completion Options')
+ m.AppendMenu(ID_CALLTIPS, '&Call Tips', self.calltipsMenu, \
+ 'Call Tip Options')
+
m = self.helpMenu = wxMenu()
m.AppendSeparator()
m.Append(wxID_ABOUT, '&About...', 'About PyCrust')
b = self.menuBar = wxMenuBar()
b.Append(self.fileMenu, '&File')
b.Append(self.editMenu, '&Edit')
+ b.Append(self.optionsMenu, '&Options')
b.Append(self.helpMenu, '&Help')
self.SetMenuBar(b)
EVT_MENU(self, wxID_CLEAR, self.OnClear)
EVT_MENU(self, wxID_SELECTALL, self.OnSelectAll)
EVT_MENU(self, wxID_ABOUT, self.OnAbout)
+ EVT_MENU(self, ID_AUTOCOMP_SHOW, self.OnAutoCompleteShow)
+ EVT_MENU(self, ID_AUTOCOMP_INCLUDE_MAGIC, self.OnAutoCompleteIncludeMagic)
+ EVT_MENU(self, ID_AUTOCOMP_INCLUDE_SINGLE, self.OnAutoCompleteIncludeSingle)
+ EVT_MENU(self, ID_AUTOCOMP_INCLUDE_DOUBLE, self.OnAutoCompleteIncludeDouble)
+ EVT_MENU(self, ID_CALLTIPS_SHOW, self.OnCallTipsShow)
EVT_UPDATE_UI(self, wxID_UNDO, self.OnUpdateMenu)
EVT_UPDATE_UI(self, wxID_REDO, self.OnUpdateMenu)
EVT_UPDATE_UI(self, wxID_COPY, self.OnUpdateMenu)
EVT_UPDATE_UI(self, wxID_PASTE, self.OnUpdateMenu)
EVT_UPDATE_UI(self, wxID_CLEAR, self.OnUpdateMenu)
+ EVT_UPDATE_UI(self, ID_AUTOCOMP_SHOW, self.OnUpdateMenu)
+ EVT_UPDATE_UI(self, ID_AUTOCOMP_INCLUDE_MAGIC, self.OnUpdateMenu)
+ EVT_UPDATE_UI(self, ID_AUTOCOMP_INCLUDE_SINGLE, self.OnUpdateMenu)
+ EVT_UPDATE_UI(self, ID_AUTOCOMP_INCLUDE_DOUBLE, self.OnUpdateMenu)
+ EVT_UPDATE_UI(self, ID_CALLTIPS_SHOW, self.OnUpdateMenu)
def OnExit(self, event):
self.Close(true)
def OnUndo(self, event):
- self.shell.editor.Undo()
+ self.shell.Undo()
def OnRedo(self, event):
- self.shell.editor.Redo()
+ self.shell.Redo()
def OnCut(self, event):
- self.shell.editor.Cut()
+ self.shell.Cut()
def OnCopy(self, event):
- self.shell.editor.Copy()
+ self.shell.Copy()
def OnPaste(self, event):
- self.shell.editor.Paste()
+ self.shell.Paste()
def OnClear(self, event):
- self.shell.editor.Clear()
+ self.shell.Clear()
def OnSelectAll(self, event):
- self.shell.editor.SelectAll()
+ self.shell.SelectAll()
def OnAbout(self, event):
"""Display an About PyCrust window."""
title = 'About PyCrust'
- text = 'PyCrust %s\n\n' % version + \
+ text = 'PyCrust %s\n\n' % VERSION + \
'Yet another Python shell, only flakier.\n\n' + \
'Half-baked by Patrick K. O\'Brien,\n' + \
- 'the other half is still in the oven.'
+ 'the other half is still in the oven.\n\n' + \
+ 'Shell Revision: %s\n' % self.shell.revision + \
+ 'Interpreter Revision: %s\n' % self.shell.interp.revision
dialog = wxMessageDialog(self, text, title, wxOK | wxICON_INFORMATION)
dialog.ShowModal()
dialog.Destroy()
+ def OnAutoCompleteShow(self, event):
+ self.shell.autoComplete = event.IsChecked()
+
+ def OnAutoCompleteIncludeMagic(self, event):
+ self.shell.autoCompleteIncludeMagic = event.IsChecked()
+
+ def OnAutoCompleteIncludeSingle(self, event):
+ self.shell.autoCompleteIncludeSingle = event.IsChecked()
+
+ def OnAutoCompleteIncludeDouble(self, event):
+ self.shell.autoCompleteIncludeDouble = event.IsChecked()
+
+ def OnCallTipsShow(self, event):
+ self.shell.autoCallTip = event.IsChecked()
+
def OnUpdateMenu(self, event):
- """Update menu items based on which should be enabled/disabled."""
+ """Update menu items based on current status."""
id = event.GetId()
if id == wxID_UNDO:
- event.Enable(self.shell.editor.CanUndo())
+ event.Enable(self.shell.CanUndo())
elif id == wxID_REDO:
- event.Enable(self.shell.editor.CanRedo())
+ event.Enable(self.shell.CanRedo())
elif id == wxID_CUT:
- event.Enable(self.shell.editor.CanCut())
+ event.Enable(self.shell.CanCut())
elif id == wxID_COPY:
- event.Enable(self.shell.editor.CanCopy())
+ event.Enable(self.shell.CanCopy())
elif id == wxID_PASTE:
- event.Enable(self.shell.editor.CanPaste())
+ event.Enable(self.shell.CanPaste())
elif id == wxID_CLEAR:
- event.Enable(self.shell.editor.CanCut())
-
+ event.Enable(self.shell.CanCut())
+ elif id == ID_AUTOCOMP_SHOW:
+ event.Check(self.shell.autoComplete)
+ elif id == ID_AUTOCOMP_INCLUDE_MAGIC:
+ event.Check(self.shell.autoCompleteIncludeMagic)
+ elif id == ID_AUTOCOMP_INCLUDE_SINGLE:
+ event.Check(self.shell.autoCompleteIncludeSingle)
+ elif id == ID_AUTOCOMP_INCLUDE_DOUBLE:
+ event.Check(self.shell.autoCompleteIncludeDouble)
+ elif id == ID_CALLTIPS_SHOW:
+ event.Check(self.shell.autoCallTip)
+
class App(wxApp):
def OnInit(self):
+++ /dev/null
-
-__author__ = "Patrick K. O'Brien <pobrien@orbtech.com>"
-__cvsid__ = "$Id$"
-__date__ = "July 1, 2001"
-__version__ = "$Revision$"[11:-2]
-
-from wxPython.wx import *
-from wxPython.stc import *
-
-import keyword
-import sys
-
-
-if wxPlatform == '__WXMSW__':
- faces = { 'times' : 'Times New Roman',
- 'mono' : 'Courier New',
- 'helv' : 'Lucida Console',
- 'lucida' : 'Lucida Console',
- 'other' : 'Comic Sans MS',
- 'size' : 8,
- 'lnsize' : 7,
- 'backcol': '#FFFFFF',
- }
-else: # GTK
- faces = { 'times' : 'Times',
- 'mono' : 'Courier',
- 'helv' : 'Helvetica',
- 'other' : 'new century schoolbook',
- 'size' : 9,
- 'lnsize' : 8,
- 'backcol': '#FFFFFF',
- }
-
-
-class Editor(wxStyledTextCtrl):
- """PyCrust Editor based on wxStyledTextCtrl."""
- revision = __version__
- def __init__(self, parent, id):
- """Create a PyCrust editor object based on wxStyledTextCtrl."""
- wxStyledTextCtrl.__init__(self, parent, id, style=wxCLIP_CHILDREN)
- # Commands get pushed to a method determined by the outer shell.
- #self.shellPush = pushMethod
- # Keep track of the most recent prompt starting and ending positions.
- self.promptPos = [0, 0]
- # Keep track of multi-line commands.
- self.more = 0
- # Configure various defaults and user preferences.
- self.config()
- # Assign handlers for keyboard events.
- EVT_KEY_DOWN(self, self.OnKeyDown)
- EVT_CHAR(self, self.OnChar)
-
- def config(self):
- """Configure editor based on user preferences."""
- self.SetMarginType(1, wxSTC_MARGIN_NUMBER)
- self.SetMarginWidth(1, 40)
-
- self.SetLexer(wxSTC_LEX_PYTHON)
- self.SetKeyWords(0, ' '.join(keyword.kwlist))
-
- self.setStyles(faces)
- self.SetViewWhiteSpace(0)
- self.SetTabWidth(4)
- self.SetUseTabs(0)
- # Do we want to automatically pop up command completion options?
- self.autoComplete = 1
- self.autoCompleteCaseInsensitive = 1
- self.AutoCompSetIgnoreCase(self.autoCompleteCaseInsensitive)
- # De we want to automatically pop up command argument help?
- self.autoCallTip = 1
- self.CallTipSetBackground(wxColour(255, 255, 232))
-
- def setStyles(self, faces):
- """Configure font size, typeface and color for lexer."""
-
- # Default style
- self.StyleSetSpec(wxSTC_STYLE_DEFAULT, "face:%(mono)s,size:%(size)d" % faces)
-
- self.StyleClearAll()
-
- # Built in styles
- self.StyleSetSpec(wxSTC_STYLE_LINENUMBER, "back:#C0C0C0,face:%(mono)s,size:%(lnsize)d" % faces)
- self.StyleSetSpec(wxSTC_STYLE_CONTROLCHAR, "face:%(mono)s" % faces)
- self.StyleSetSpec(wxSTC_STYLE_BRACELIGHT, "fore:#0000FF,back:#FFFF88")
- self.StyleSetSpec(wxSTC_STYLE_BRACEBAD, "fore:#FF0000,back:#FFFF88")
-
- # Python styles
- self.StyleSetSpec(wxSTC_P_DEFAULT, "face:%(mono)s" % faces)
- self.StyleSetSpec(wxSTC_P_COMMENTLINE, "fore:#007F00,face:%(mono)s" % faces)
- self.StyleSetSpec(wxSTC_P_NUMBER, "")
- self.StyleSetSpec(wxSTC_P_STRING, "fore:#7F007F,face:%(mono)s" % faces)
- self.StyleSetSpec(wxSTC_P_CHARACTER, "fore:#7F007F,face:%(mono)s" % faces)
- self.StyleSetSpec(wxSTC_P_WORD, "fore:#00007F,bold")
- self.StyleSetSpec(wxSTC_P_TRIPLE, "fore:#7F0000")
- self.StyleSetSpec(wxSTC_P_TRIPLEDOUBLE, "fore:#000033,back:#FFFFE8")
- self.StyleSetSpec(wxSTC_P_CLASSNAME, "fore:#0000FF,bold")
- self.StyleSetSpec(wxSTC_P_DEFNAME, "fore:#007F7F,bold")
- self.StyleSetSpec(wxSTC_P_OPERATOR, "")
- self.StyleSetSpec(wxSTC_P_IDENTIFIER, "")
- 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()
- # 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.
- """
- key = event.KeyCode()
- currpos = self.GetCurrentPos()
- stoppos = self.promptPos[1]
- if currpos >= stoppos:
- if key == 46:
- # "." 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
- # 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:
- pass
-
- def setStatusText(self, text):
- """Display status information."""
-
- # This method will most likely be replaced by the enclosing app
- # to do something more interesting, like write to a status bar.
- print text
-
- def autoCompleteShow(self, command):
- """Display auto-completion popup list."""
- list = self.getAutoCompleteList(command)
- if list:
- options = ' '.join(list)
- offset = 0
- self.AutoCompShow(offset, options)
-
- def getAutoCompleteList(self, command):
- """Return list of auto-completion options for command."""
-
- # This method needs to be replaced by the enclosing app
- # to get the proper auto complete list from the interpreter.
- return []
-
- def autoCallTipShow(self, command):
- """Display argument spec and docstring in a popup bubble thingie."""
- if self.CallTipActive: self.CallTipCancel()
- tip = self.getCallTip(command)
- if tip:
- offset = self.GetCurrentPos()
- self.CallTipShow(offset, tip)
-
- def getCallTip(self, command):
- """Return arguments and docstring for command."""
-
- # This method needs to be replaced by the enclosing app
- # to get the proper auto complete list from the interpreter.
- return ''
-
- def processLine(self):
- """Process the line of text at which the user hit Enter."""
-
- # The user hit ENTER and we need to decide what to do. They could be
- # sitting on any line in the editor.
-
- # Grab information about the current line.
- thepos = self.GetCurrentPos()
- theline = self.GetCurrentLine()
- thetext = self.GetCurLine()[0]
- command = self.getCommand(thetext)
- # Go to the very bottom of the editor.
- 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.SetSelection(startpos, endpos)
- self.ReplaceSelection('')
- self.prompt()
- self.write(command)
- # Otherwise, put the cursor back where we started.
- else:
- self.SetCurrentPos(thepos)
- self.SetAnchor(thepos)
-
- def getCommand(self, text):
- """Extract a command from text which may include a shell prompt.
-
- The command may not necessarily be valid Python syntax.
- """
-
- # XXX Need to extract real prompts here. Need to keep track of the
- # prompt every time a command is issued. Do this in the interpreter
- # with a line number, prompt, command dictionary. For the history, perhaps.
- ps1 = str(sys.ps1)
- ps1size = len(ps1)
- ps2 = str(sys.ps2)
- ps2size = len(ps2)
- text = text.rstrip()
- # Strip the prompt off the front of text leaving just the command.
- if text[:ps1size] == ps1:
- command = text[ps1size:]
- elif text[:ps2size] == ps2:
- command = text[ps2size:]
- else:
- command = ''
- return command
-
- def push(self, command):
- """Start a new line, send command to the shell, display a prompt."""
- self.write('\n')
- self.more = self.shellPush(command)
- self.prompt()
- # Keep the undo feature from undoing previous responses. The only
- # thing that can be undone is stuff typed after the prompt, before
- # hitting enter. After they hit enter it becomes permanent.
- self.EmptyUndoBuffer()
-
- def clear(self):
- """Delete all text from the editor."""
- self.ClearAll()
-
- def prompt(self):
- """Display appropriate prompt for the context, either ps1 or ps2.
-
- If this is a continuation line, autoindent as necessary.
- """
- if self.more:
- prompt = str(sys.ps2)
- else:
- prompt = str(sys.ps1)
- pos = self.GetCurLine()[1]
- if pos > 0: self.write('\n')
- self.promptPos[0] = self.GetCurrentPos()
- self.write(prompt)
- self.promptPos[1] = self.GetCurrentPos()
- # XXX Add some autoindent magic here if more.
- if self.more:
- self.write('\t') # Temporary hack indentation.
- self.EnsureCaretVisible()
- self.ScrollToColumn(0)
-
- def readIn(self):
- """Replacement for stdin."""
- prompt = 'Please enter your response:'
- dialog = wxTextEntryDialog(None, prompt, \
- 'Input Dialog (Standard)', '')
- try:
- if dialog.ShowModal() == wxID_OK:
- text = dialog.GetValue()
- self.write(text + '\n')
- return text
- finally:
- dialog.Destroy()
- return ''
-
- def readRaw(self, prompt='Please enter your response:'):
- """Replacement for raw_input."""
- dialog = wxTextEntryDialog(None, prompt, \
- 'Input Dialog (Raw)', '')
- try:
- if dialog.ShowModal() == wxID_OK:
- text = dialog.GetValue()
- return text
- finally:
- dialog.Destroy()
- return ''
-
- def write(self, text):
- """Display text in the editor."""
- self.AddText(text)
- self.EnsureCaretVisible()
- #self.ScrollToColumn(0)
-
- def writeOut(self, text):
- """Replacement for stdout."""
- self.write(text)
-
- def writeErr(self, text):
- """Replacement for stderr."""
- self.write(text)
-
- def CanCut(self):
- """Return true if text is selected and can be cut."""
- return self.GetSelectionStart() != self.GetSelectionEnd()
-
- def CanCopy(self):
- """Return true if text is selected and can be copied."""
- return self.GetSelectionStart() != self.GetSelectionEnd()
-
+++ /dev/null
-
-__author__ = "Patrick K. O'Brien <pobrien@orbtech.com>"
-__cvsid__ = "$Id$"
-__date__ = "July 1, 2001"
-__version__ = "$Revision$"[11:-2]
-
-import os
-import sys
-
-from code import InteractiveInterpreter
-import introspect
-
-
-class Interpreter(InteractiveInterpreter):
- """PyCrust Interpreter based on code.InteractiveInterpreter."""
- revision = __version__
- def __init__(self, locals=None, rawin=None,
- stdin=sys.stdin, stdout=sys.stdout, stderr=sys.stderr):
- """Create an interactive interpreter object."""
- InteractiveInterpreter.__init__(self, locals=locals)
- self.stdin = stdin
- self.stdout = stdout
- self.stderr = stderr
- if rawin is not None:
- import __builtin__
- __builtin__.raw_input = rawin
- del __builtin__
- copyright = 'Type "copyright", "credits" or "license" for more information.'
- self.introText = 'Python %s on %s\n%s' % \
- (sys.version, sys.platform, copyright)
- try:
- sys.ps1
- except AttributeError:
- sys.ps1 = '>>> '
- try:
- sys.ps2
- except AttributeError:
- sys.ps2 = '... '
- self.more = 0
- self.commandBuffer = [] # List of lists to support recursive push().
- self.commandHistory = []
- self.startupScript = os.environ.get('PYTHONSTARTUP')
-
- def push(self, command):
- """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.
- """
- 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):
- """Compile and run source code in the interpreter."""
- stdin, stdout, stderr = sys.stdin, sys.stdout, sys.stderr
- sys.stdin = self.stdin
- sys.stdout = self.stdout
- sys.stderr = self.stderr
- more = InteractiveInterpreter.runsource(self, source)
- sys.stdin, sys.stdout, sys.stderr = stdin, stdout, stderr
- return more
-
- def getAutoCompleteList(self, command=''):
- """Return list of auto-completion options for a command.
-
- The list of options will be based on the locals namespace."""
- return introspect.getAutoCompleteList(command, self.locals)
-
- def getCallTip(self, command=''):
- """Return call tip text for a command.
-
- The call tip information will be based on the locals namespace."""
- return introspect.getCallTip(command, self.locals)
-
+++ /dev/null
-"""
-"""
-__author__ = "Patrick K. O'Brien <pobrien@orbtech.com>"
-__cvsid__ = "$Id$"
-__date__ = "July 1, 2001"
-__version__ = "$Revision$"[11:-2]
-
-import os
-from PyCrustVersion import version
-
-class Shell:
- """PyCrust Shell manages the Editor and Interpreter."""
- name = 'PyCrust Shell'
- revision = __version__
- def __init__(self, editorParent=None, introText='', editor=None, interp=None):
- """Create a PyCrust shell object to manage the editor and interpreter."""
- try:
- eval('crap')
- except:
- pass
- self.introText = introText
- # Create a default editor if one isn't provided.
- if editor == None:
- from PyCrustEditor import Editor
- self.editor = Editor(editorParent, id=-1)
- else:
- self.editor = editor
- # Link the editor to the shell so that the shell is a conduit for
- # pushing commands to the interpreter.
- self.editor.shellPush = self.shellPush
- # Create a default interpreter if one isn't provided.
- if interp == None:
- from PyCrustInterp import Interpreter
- from pseudo import PseudoFileIn, PseudoFileOut, PseudoFileErr
- self.stdin = PseudoFileIn(self.editor.readIn)
- self.stdout = PseudoFileOut(self.editor.writeOut)
- self.stderr = PseudoFileErr(self.editor.writeErr)
- # Override the default locals so we have something interesting.
- locals = {'__name__': 'PyCrust',
- '__doc__': 'PyCrust, The Python Shell.',
- '__version__': version,
- }
- self.interp = Interpreter(locals=locals,
- rawin=self.editor.readRaw,
- stdin=self.stdin,
- stdout=self.stdout,
- stderr=self.stderr)
- else:
- self.interp = interp
- # XXX redo this using hasattr() or something so that we can link
- # these if a provided editor has this method.
- if editor == None or editor == self:
- # Override so the auto complete list comes from the interpreter.
- self.editor.getAutoCompleteList = self.interp.getAutoCompleteList
- # Override so the call tip comes from the interpreter.
- self.editor.getCallTip = self.interp.getCallTip
- # Keep track of whether the interpreter needs more.
- self.more = 0
-
- try:
- self.showIntro(self.introText)
- except:
- pass
-
- try:
- self.setBuiltinKeywords()
- except:
- pass
-
- try:
- self.setLocalShell()
- except:
- pass
-
- # Do this last so the user has complete control over their
- # environment. They can override anything they want.
- try:
- self.execStartupScript(self.interp.startupScript)
- except:
- pass
-
- def destroy(self):
- del self.editor
- del self.stdin
- del self.stdout
- del self.stderr
- del self.interp
-
- def showIntro(self, text=''):
- """Display introductory text in the shell editor."""
- if text:
- if text[-1] != '\n': text += '\n'
- self.editor.write(text)
- try:
- self.editor.write(self.interp.introText)
- except AttributeError:
- pass
-
- def setBuiltinKeywords(self):
- """Create pseudo keywords as part of builtins.
-
- This is a rather clever hack that sets "close", "exit" and "quit"
- to a PseudoKeyword object so that we can make them do what we want.
- In this case what we want is to call our self.quit() method.
- The user can type "close", "exit" or "quit" without the final parens.
- """
- import __builtin__
- from pseudo import PseudoKeyword
- __builtin__.close = __builtin__.exit = __builtin__.quit = \
- PseudoKeyword(self.quit)
-
- def quit(self):
- """Quit the application."""
-
- # 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.
- # 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.editor.write('Click on the close button to leave the application.')
-
- def setLocalShell(self):
- """Add 'shell' to locals."""
- self.interp.locals['shell'] = self
-
- def execStartupScript(self, startupScript):
- """Execute the user's PYTHONSTARTUP script if they have one."""
- if startupScript and os.path.isfile(startupScript):
- startupText = 'Startup script executed: ' + startupScript
- self.editor.push('print %s;execfile(%s)' % \
- (`startupText`, `startupScript`))
- else:
- self.editor.push('')
-
- def run(self, command, prompt=1, verbose=1):
- """Execute command within the shell as if it was typed in directly.
- >>> shell.run('print "this"')
- >>> print "this"
- this
- >>>
- """
- command = command.rstrip()
- if prompt: self.editor.prompt()
- if verbose: self.editor.write(command)
- self.editor.push(command)
-
- def runfile(self, filename):
- """Execute all commands in file as if they were typed into the shell."""
- file = open(filename)
- try:
- self.editor.prompt()
- for command in file.readlines():
- if command[:6] == 'shell.': # Run shell methods silently.
- self.run(command, prompt=0, verbose=0)
- else:
- self.run(command, prompt=0, verbose=1)
- finally:
- file.close()
-
- def push(self, command):
- """Send command to the interpreter for execution."""
- self.more = self.interp.push(command)
- return self.more
-
- shellPush = push
-
- def ask(self, prompt='Please enter your response:'):
- """Get response from the user."""
- return raw_input(prompt=prompt)
-
- def pause(self):
- """Halt execution pending a response from the user."""
- self.ask('Press enter to continue:')
-
- def clear(self):
- """Delete all text from the shell editor."""
- self.editor.clear()
-
-
+++ /dev/null
-"""Provides an object representing the current "version" or "release" of
-PyCrust as a whole. Individual classes, such as the shell, editor and
-interpreter, each have a revision property based on the CVS $Revision$."""
-
-__author__ = "Patrick K. O'Brien <pobrien@orbtech.com>"
-__cvsid__ = "$Id$"
-__date__ = "July 1, 2001"
-__version__ = "$Revision$"[11:-2]
-
-version = '0.5'
--- /dev/null
+PyCrust - The Flakiest Python Shell
+Half-baked by Patrick K. O'Brien (pobrien@orbtech.com)
+======================================================
+
+What is PyCrust?
+----------------
+
+PyCrust is is an interactive Python Shell written in Python.
+PyCrust can be run standalone or integrated into other development
+environments or other Python applications.
+
+
+Where can I get the latest files and join the mailing lists?
+------------------------------------------------------------
+
+Latest PyCrust releases:
+http://sourceforge.net/project/showfiles.php?group_id=31263
+
+PyCrust home page:
+http://pycrust.sourceforge.net/
+
+SourceForge summary page:
+http://sourceforge.net/projects/pycrust/
+
+PyCrust Mailing lists:
+http://sourceforge.net/mail/?group_id=31263
+
+
+What else do I need to use PyCrust?
+-----------------------------------
+
+PyCrust requires Python 2.1 or later, and wxPython 2.3.1 or later.
+PyCrust uses wxPython and the Scintilla wrapper class (wxStyledTextCtrl).
+Python is available at http://www.python.org/.
+wxPython is available at http://www.wxpython.org/.
+
+
+What is the CVS information for this README file?
+-------------------------------------------------
+
+$Date$
+$Revision$
+$Id$
--- /dev/null
+"""PyCrust Interpreter executes Python commands.
+"""
+
+__author__ = "Patrick K. O'Brien <pobrien@orbtech.com>"
+__cvsid__ = "$Id$"
+__date__ = "July 1, 2001"
+__version__ = "$Revision$"[11:-2]
+
+import os
+import sys
+
+from code import InteractiveInterpreter
+import introspect
+
+
+class Interpreter(InteractiveInterpreter):
+ """PyCrust Interpreter based on code.InteractiveInterpreter."""
+ revision = __version__
+ def __init__(self, locals=None, rawin=None,
+ stdin=sys.stdin, stdout=sys.stdout, stderr=sys.stderr):
+ """Create an interactive interpreter object."""
+ InteractiveInterpreter.__init__(self, locals=locals)
+ self.stdin = stdin
+ self.stdout = stdout
+ self.stderr = stderr
+ if rawin is not None:
+ import __builtin__
+ __builtin__.raw_input = rawin
+ del __builtin__
+ copyright = 'Type "copyright", "credits" or "license" for more information.'
+ self.introText = 'Python %s on %s\n%s' % \
+ (sys.version, sys.platform, copyright)
+ try:
+ sys.ps1
+ except AttributeError:
+ sys.ps1 = '>>> '
+ try:
+ sys.ps2
+ except AttributeError:
+ sys.ps2 = '... '
+ self.more = 0
+ self.commandBuffer = [] # List of lists to support recursive push().
+ self.commandHistory = []
+ self.startupScript = os.environ.get('PYTHONSTARTUP')
+
+ def push(self, command):
+ """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.
+ """
+ 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):
+ """Compile and run source code in the interpreter."""
+ stdin, stdout, stderr = sys.stdin, sys.stdout, sys.stderr
+ sys.stdin = self.stdin
+ sys.stdout = self.stdout
+ sys.stderr = self.stderr
+ more = InteractiveInterpreter.runsource(self, source)
+ sys.stdin, sys.stdout, sys.stderr = stdin, stdout, stderr
+ return more
+
+ def getAutoCompleteList(self, command='', *args, **kwds):
+ """Return list of auto-completion options for a command.
+
+ The list of options will be based on the locals namespace."""
+ return introspect.getAutoCompleteList(command, self.locals, *args, **kwds)
+
+ def getCallTip(self, command='', *args, **kwds):
+ """Return call tip text for a command.
+
+ The call tip information will be based on the locals namespace."""
+ return introspect.getCallTip(command, self.locals, *args, **kwds)
+
import inspect
import string
-def getAutoCompleteList(command='', locals=None):
+def getAutoCompleteList(command='', locals=None, includeMagic=1, \
+ includeSingle=1, includeDouble=1):
"""Return list of auto-completion options for command.
The list of options will be based on the locals namespace."""
root = getRoot(command, terminator='.')
try:
object = eval(root, locals)
- attributes = getAttributes(object)
+ attributes = getAttributeNames(object)
+ if includeMagic:
+ try: attributes += object._getAttributeNames()
+ except: pass
+ if not includeSingle:
+ attributes = filter(lambda item: item[0]!='_' or item[1]=='_', attributes)
+ if not includeDouble:
+ attributes = filter(lambda item: item[:2]!='__', attributes)
return attributes
except:
return []
-def getAttributes(object):
+def getAttributeNames(object):
"""Return list of unique attributes, including inherited, for an object."""
attributes = []
dict = {}
# Remove duplicates from the attribute list.
- for item in getAllAttributes(object):
+ for item in getAllAttributeNames(object):
dict[item] = None
attributes += dict.keys()
attributes.sort()
return attributes
-def getAllAttributes(object):
+def getAllAttributeNames(object):
"""Return list of all attributes, including inherited, for an object.
Recursively walk through a class and all base classes.
"""
attributes = []
- try:
- attributes += dir(object)
- if hasattr(object, '__class__'):
- attributes += getAllAttributes(object.__class__)
- if hasattr(object, '__bases__'):
- for base in object.__bases__:
- attributes += getAllAttributes(base)
- finally:
- return attributes
+ # Get attributes available through the normal convention.
+ attributes += dir(object)
+ # For a class instance, get the attributes for the class.
+ if hasattr(object, '__class__'):
+ attributes += getAllAttributeNames(object.__class__)
+ # Also get attributes from any and all parent classes.
+ if hasattr(object, '__bases__'):
+ for base in object.__bases__:
+ attributes += getAllAttributeNames(base)
+ return attributes
def getCallTip(command='', locals=None):
"""Return call tip text for a command.
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.
"""
root = ''
validChars = "._" + string.uppercase + string.lowercase + string.digits
- # Remove all whitespace from the command.
- command = ''.join(command.split())
- # Deal with the terminator.
if terminator:
+ # Drop the final terminator and anything that follows.
pieces = command.split(terminator)
if len(pieces) > 1:
- # Drop the final terminator and anything that follows.
command = terminator.join(pieces[:-1])
- # Go backward through the command until we hit an "invalid" character.
- i = len(command)
- while i and command[i-1] in validChars:
- i -= 1
- # Grab everything from the "invalid" character to the end.
- root = command[i:]
+ if command in ("''", '""', '""""""', '[]', '()', '{}'):
+ # Let empty type delimiter pairs go through.
+ root = command
+ else:
+ # Go backward through the command until we hit an "invalid" character.
+ i = len(command)
+ while i and command[i-1] in validChars:
+ i -= 1
+ # 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
+ # object and it would be misleading to return anything here.
+ root = ''
+ else:
+ # Grab everything from the "invalid" character to the end.
+ root = command[i:]
return root
--- /dev/null
+"""PyCrust Shell is the gui text control in which a user interacts and types
+in commands to be sent to the interpreter. This particular shell is based on
+wxPython's wxStyledTextCtrl.
+"""
+
+__author__ = "Patrick K. O'Brien <pobrien@orbtech.com>"
+__cvsid__ = "$Id$"
+__date__ = "July 1, 2001"
+__version__ = "$Revision$"[11:-2]
+
+from wxPython.wx import *
+from wxPython.stc import *
+
+import keyword
+import os
+import sys
+
+from version import VERSION
+
+if wxPlatform == '__WXMSW__':
+ faces = { 'times' : 'Times New Roman',
+ 'mono' : 'Courier New',
+ 'helv' : 'Lucida Console',
+ 'lucida' : 'Lucida Console',
+ 'other' : 'Comic Sans MS',
+ 'size' : 8,
+ 'lnsize' : 7,
+ 'backcol': '#FFFFFF',
+ }
+else: # GTK
+ faces = { 'times' : 'Times',
+ 'mono' : 'Courier',
+ 'helv' : 'Helvetica',
+ 'other' : 'new century schoolbook',
+ 'size' : 9,
+ 'lnsize' : 8,
+ 'backcol': '#FFFFFF',
+ }
+
+
+class Shell(wxStyledTextCtrl):
+ """PyCrust Shell based on wxStyledTextCtrl."""
+ name = 'PyCrust Shell'
+ revision = __version__
+ def __init__(self, parent, id, introText='', locals=None, interp=None):
+ """Create a PyCrust Shell object."""
+ wxStyledTextCtrl.__init__(self, parent, id, style=wxCLIP_CHILDREN)
+ self.introText = introText
+ # Keep track of the most recent prompt starting and ending positions.
+ self.promptPos = [0, 0]
+ # Keep track of multi-line commands.
+ self.more = 0
+ # Assign handlers for keyboard events.
+ EVT_KEY_DOWN(self, self.OnKeyDown)
+ EVT_CHAR(self, self.OnChar)
+ # Create a default interpreter if one isn't provided.
+ if interp == None:
+ from interpreter import Interpreter
+ from pseudo import PseudoFileIn, PseudoFileOut, PseudoFileErr
+ self.stdin = PseudoFileIn(self.readIn)
+ self.stdout = PseudoFileOut(self.writeOut)
+ self.stderr = PseudoFileErr(self.writeErr)
+ # Override the default locals so we have something interesting.
+ self.locals = {'__name__': 'PyCrust',
+ '__doc__': 'PyCrust, The Python Shell.',
+ '__version__': VERSION,
+ }
+ # Add the dictionary that was passed in.
+ if locals:
+ self.locals.update(locals)
+ self.interp = Interpreter(locals=self.locals,
+ rawin=self.readRaw,
+ stdin=self.stdin,
+ stdout=self.stdout,
+ stderr=self.stderr)
+ else:
+ self.interp = interp
+
+ # Configure various defaults and user preferences.
+ self.config()
+
+ try:
+ self.showIntro(self.introText)
+ except:
+ pass
+
+ try:
+ self.setBuiltinKeywords()
+ except:
+ pass
+
+ try:
+ self.setLocalShell()
+ except:
+ pass
+
+ # Do this last so the user has complete control over their
+ # environment. They can override anything they want.
+ try:
+ self.execStartupScript(self.interp.startupScript)
+ except:
+ pass
+
+ def destroy(self):
+ del self.stdin
+ del self.stdout
+ del self.stderr
+ del self.interp
+
+ def config(self):
+ """Configure shell based on user preferences."""
+ self.SetMarginType(1, wxSTC_MARGIN_NUMBER)
+ self.SetMarginWidth(1, 40)
+
+ self.SetLexer(wxSTC_LEX_PYTHON)
+ self.SetKeyWords(0, ' '.join(keyword.kwlist))
+
+ self.setStyles(faces)
+ self.SetViewWhiteSpace(0)
+ self.SetTabWidth(4)
+ self.SetUseTabs(0)
+ # Do we want to automatically pop up command completion options?
+ self.autoComplete = 1
+ self.autoCompleteIncludeMagic = 1
+ self.autoCompleteIncludeSingle = 1
+ self.autoCompleteIncludeDouble = 1
+ self.autoCompleteCaseInsensitive = 1
+ self.AutoCompSetIgnoreCase(self.autoCompleteCaseInsensitive)
+ # De we want to automatically pop up command argument help?
+ self.autoCallTip = 1
+ self.CallTipSetBackground(wxColour(255, 255, 232))
+
+ def showIntro(self, text=''):
+ """Display introductory text in the shell."""
+ if text:
+ if text[-1] != '\n': text += '\n'
+ self.write(text)
+ try:
+ self.write(self.interp.introText)
+ except AttributeError:
+ pass
+
+ def setBuiltinKeywords(self):
+ """Create pseudo keywords as part of builtins.
+
+ This is a rather clever hack that sets "close", "exit" and "quit"
+ to a PseudoKeyword object so that we can make them do what we want.
+ In this case what we want is to call our self.quit() method.
+ The user can type "close", "exit" or "quit" without the final parens.
+ """
+ import __builtin__
+ from pseudo import PseudoKeyword
+ __builtin__.close = __builtin__.exit = __builtin__.quit = \
+ PseudoKeyword(self.quit)
+
+ def quit(self):
+ """Quit the application."""
+
+ # 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.
+ # 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
+
+ def execStartupScript(self, startupScript):
+ """Execute the user's PYTHONSTARTUP script if they have one."""
+ if startupScript and os.path.isfile(startupScript):
+ startupText = 'Startup script executed: ' + startupScript
+ self.push('print %s;execfile(%s)' % \
+ (`startupText`, `startupScript`))
+ else:
+ self.push('')
+
+ def setStyles(self, faces):
+ """Configure font size, typeface and color for lexer."""
+
+ # Default style
+ self.StyleSetSpec(wxSTC_STYLE_DEFAULT, "face:%(mono)s,size:%(size)d" % faces)
+
+ self.StyleClearAll()
+
+ # Built in styles
+ self.StyleSetSpec(wxSTC_STYLE_LINENUMBER, "back:#C0C0C0,face:%(mono)s,size:%(lnsize)d" % faces)
+ self.StyleSetSpec(wxSTC_STYLE_CONTROLCHAR, "face:%(mono)s" % faces)
+ self.StyleSetSpec(wxSTC_STYLE_BRACELIGHT, "fore:#0000FF,back:#FFFF88")
+ self.StyleSetSpec(wxSTC_STYLE_BRACEBAD, "fore:#FF0000,back:#FFFF88")
+
+ # Python styles
+ self.StyleSetSpec(wxSTC_P_DEFAULT, "face:%(mono)s" % faces)
+ self.StyleSetSpec(wxSTC_P_COMMENTLINE, "fore:#007F00,face:%(mono)s" % faces)
+ self.StyleSetSpec(wxSTC_P_NUMBER, "")
+ self.StyleSetSpec(wxSTC_P_STRING, "fore:#7F007F,face:%(mono)s" % faces)
+ self.StyleSetSpec(wxSTC_P_CHARACTER, "fore:#7F007F,face:%(mono)s" % faces)
+ self.StyleSetSpec(wxSTC_P_WORD, "fore:#00007F,bold")
+ self.StyleSetSpec(wxSTC_P_TRIPLE, "fore:#7F0000")
+ self.StyleSetSpec(wxSTC_P_TRIPLEDOUBLE, "fore:#000033,back:#FFFFE8")
+ self.StyleSetSpec(wxSTC_P_CLASSNAME, "fore:#0000FF,bold")
+ self.StyleSetSpec(wxSTC_P_DEFNAME, "fore:#007F7F,bold")
+ self.StyleSetSpec(wxSTC_P_OPERATOR, "")
+ self.StyleSetSpec(wxSTC_P_IDENTIFIER, "")
+ 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()
+ # 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.
+ """
+ key = event.KeyCode()
+ currpos = self.GetCurrentPos()
+ stoppos = self.promptPos[1]
+ if currpos >= stoppos:
+ if key == 46:
+ # "." 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
+ # 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:
+ pass
+
+ def setStatusText(self, text):
+ """Display status information."""
+
+ # This method will most likely be replaced by the enclosing app
+ # to do something more interesting, like write to a status bar.
+ print text
+
+ def processLine(self):
+ """Process the line of text at which the user hit Enter."""
+
+ # The user hit ENTER and we need to decide what to do. They could be
+ # sitting on any line in the shell.
+
+ # Grab information about the current line.
+ thepos = self.GetCurrentPos()
+ theline = self.GetCurrentLine()
+ thetext = self.GetCurLine()[0]
+ command = self.getCommand(thetext)
+ # 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.SetSelection(startpos, endpos)
+ self.ReplaceSelection('')
+ self.prompt()
+ self.write(command)
+ # Otherwise, put the cursor back where we started.
+ else:
+ self.SetCurrentPos(thepos)
+ self.SetAnchor(thepos)
+
+ def getCommand(self, text):
+ """Extract a command from text which may include a shell prompt.
+
+ The command may not necessarily be valid Python syntax.
+ """
+
+ # XXX Need to extract real prompts here. Need to keep track of the
+ # prompt every time a command is issued. Do this in the interpreter
+ # with a line number, prompt, command dictionary. For the history, perhaps.
+ ps1 = str(sys.ps1)
+ ps1size = len(ps1)
+ ps2 = str(sys.ps2)
+ ps2size = len(ps2)
+ text = text.rstrip()
+ # Strip the prompt off the front of text leaving just the command.
+ if text[:ps1size] == ps1:
+ command = text[ps1size:]
+ elif text[:ps2size] == ps2:
+ command = text[ps2size:]
+ else:
+ command = ''
+ return command
+
+ def push(self, command):
+ """Send command to the interpreter for execution."""
+ self.write('\n')
+ self.more = self.interp.push(command)
+ self.prompt()
+ # Keep the undo feature from undoing previous responses. The only
+ # thing that can be undone is stuff typed after the prompt, before
+ # hitting enter. After they hit enter it becomes permanent.
+ self.EmptyUndoBuffer()
+
+ def write(self, text):
+ """Display text in the shell."""
+ self.AddText(text)
+ self.EnsureCaretVisible()
+ #self.ScrollToColumn(0)
+
+ def prompt(self):
+ """Display appropriate prompt for the context, either ps1 or ps2.
+
+ If this is a continuation line, autoindent as necessary.
+ """
+ if self.more:
+ prompt = str(sys.ps2)
+ else:
+ prompt = str(sys.ps1)
+ pos = self.GetCurLine()[1]
+ if pos > 0: self.write('\n')
+ self.promptPos[0] = self.GetCurrentPos()
+ self.write(prompt)
+ self.promptPos[1] = self.GetCurrentPos()
+ # XXX Add some autoindent magic here if more.
+ if self.more:
+ self.write('\t') # Temporary hack indentation.
+ self.EnsureCaretVisible()
+ self.ScrollToColumn(0)
+
+ def readIn(self):
+ """Replacement for stdin."""
+ prompt = 'Please enter your response:'
+ dialog = wxTextEntryDialog(None, prompt, \
+ 'Input Dialog (Standard)', '')
+ try:
+ if dialog.ShowModal() == wxID_OK:
+ text = dialog.GetValue()
+ self.write(text + '\n')
+ return text
+ finally:
+ dialog.Destroy()
+ return ''
+
+ def readRaw(self, prompt='Please enter your response:'):
+ """Replacement for raw_input."""
+ dialog = wxTextEntryDialog(None, prompt, \
+ 'Input Dialog (Raw)', '')
+ try:
+ if dialog.ShowModal() == wxID_OK:
+ text = dialog.GetValue()
+ return text
+ finally:
+ dialog.Destroy()
+ return ''
+
+ def ask(self, prompt='Please enter your response:'):
+ """Get response from the user."""
+ return raw_input(prompt=prompt)
+
+ def pause(self):
+ """Halt execution pending a response from the user."""
+ self.ask('Press enter to continue:')
+
+ def clear(self):
+ """Delete all text from the shell."""
+ self.ClearAll()
+
+ def run(self, command, prompt=1, verbose=1):
+ """Execute command within the shell as if it was typed in directly.
+ >>> shell.run('print "this"')
+ >>> print "this"
+ this
+ >>>
+ """
+ command = command.rstrip()
+ if prompt: self.prompt()
+ if verbose: self.write(command)
+ self.push(command)
+
+ def runfile(self, filename):
+ """Execute all commands in file as if they were typed into the shell."""
+ file = open(filename)
+ try:
+ self.prompt()
+ for command in file.readlines():
+ if command[:6] == 'shell.': # Run shell methods silently.
+ self.run(command, prompt=0, verbose=0)
+ else:
+ self.run(command, prompt=0, verbose=1)
+ finally:
+ file.close()
+
+ def autoCompleteShow(self, command):
+ """Display auto-completion popup list."""
+ list = self.interp.getAutoCompleteList(command, \
+ includeMagic=self.autoCompleteIncludeMagic, \
+ includeSingle=self.autoCompleteIncludeSingle, \
+ includeDouble=self.autoCompleteIncludeDouble)
+ if list:
+ options = ' '.join(list)
+ offset = 0
+ self.AutoCompShow(offset, options)
+
+ def autoCallTipShow(self, command):
+ """Display argument spec and docstring in a popup bubble thingie."""
+ if self.CallTipActive: self.CallTipCancel()
+ tip = self.interp.getCallTip(command)
+ if tip:
+ offset = self.GetCurrentPos()
+ self.CallTipShow(offset, tip)
+
+ def writeOut(self, text):
+ """Replacement for stdout."""
+ self.write(text)
+
+ def writeErr(self, text):
+ """Replacement for stderr."""
+ self.write(text)
+
+ def CanCut(self):
+ """Return true if text is selected and can be cut."""
+ return self.GetSelectionStart() != self.GetSelectionEnd()
+
+ def CanCopy(self):
+ """Return true if text is selected and can be copied."""
+ return self.GetSelectionStart() != self.GetSelectionEnd()
+
--- /dev/null
+"""Provides an object representing the current "version" or "release" of
+PyCrust as a whole. Individual classes, such as the shell, editor and
+interpreter, each have a revision property based on the CVS Revision."""
+
+__author__ = "Patrick K. O'Brien <pobrien@orbtech.com>"
+__cvsid__ = "$Id$"
+__date__ = "July 1, 2001"
+__version__ = "$Revision$"[11:-2]
+
+VERSION = '0.5.2'