From: Robin Dunn Date: Thu, 16 Aug 2001 17:48:52 +0000 (+0000) Subject: new version of PyCrust X-Git-Url: https://git.saurik.com/wxWidgets.git/commitdiff_plain/5e08014381335fced8d75bcbc84e5f61f734c09e new version of PyCrust git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@11395 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775 --- diff --git a/wxPython/wxPython/lib/PyCrust/.cvsignore b/wxPython/wxPython/lib/PyCrust/.cvsignore new file mode 100644 index 0000000000..9020783b5e --- /dev/null +++ b/wxPython/wxPython/lib/PyCrust/.cvsignore @@ -0,0 +1,3 @@ +*.pyc +*.BAK +*.$$$ \ No newline at end of file diff --git a/wxPython/wxPython/lib/PyCrust/PyCrust.ico b/wxPython/wxPython/lib/PyCrust/PyCrust.ico new file mode 100644 index 0000000000..bb29c8edd7 Binary files /dev/null and b/wxPython/wxPython/lib/PyCrust/PyCrust.ico differ diff --git a/wxPython/wxPython/lib/PyCrust/PyCrust.py b/wxPython/wxPython/lib/PyCrust/PyCrust.py index 43423d65d5..84edad7ca0 100644 --- a/wxPython/wxPython/lib/PyCrust/PyCrust.py +++ b/wxPython/wxPython/lib/PyCrust/PyCrust.py @@ -9,8 +9,16 @@ __version__ = "$Revision$"[11:-2] 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): @@ -18,15 +26,17 @@ 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() @@ -44,6 +54,26 @@ class Frame(wxFrame): 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') @@ -51,6 +81,7 @@ class Frame(wxFrame): 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) @@ -63,6 +94,11 @@ class Frame(wxFrame): 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) @@ -70,58 +106,90 @@ class Frame(wxFrame): 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): diff --git a/wxPython/wxPython/lib/PyCrust/PyCrustEditor.py b/wxPython/wxPython/lib/PyCrust/PyCrustEditor.py deleted file mode 100644 index 458e0ad5b1..0000000000 --- a/wxPython/wxPython/lib/PyCrust/PyCrustEditor.py +++ /dev/null @@ -1,349 +0,0 @@ - -__author__ = "Patrick K. O'Brien " -__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() - diff --git a/wxPython/wxPython/lib/PyCrust/PyCrustInterp.py b/wxPython/wxPython/lib/PyCrust/PyCrustInterp.py deleted file mode 100644 index dd606c2138..0000000000 --- a/wxPython/wxPython/lib/PyCrust/PyCrustInterp.py +++ /dev/null @@ -1,81 +0,0 @@ - -__author__ = "Patrick K. O'Brien " -__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) - diff --git a/wxPython/wxPython/lib/PyCrust/PyCrustShell.py b/wxPython/wxPython/lib/PyCrust/PyCrustShell.py deleted file mode 100644 index 07c232d156..0000000000 --- a/wxPython/wxPython/lib/PyCrust/PyCrustShell.py +++ /dev/null @@ -1,180 +0,0 @@ -""" -""" -__author__ = "Patrick K. O'Brien " -__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() - - diff --git a/wxPython/wxPython/lib/PyCrust/PyCrustVersion.py b/wxPython/wxPython/lib/PyCrust/PyCrustVersion.py deleted file mode 100644 index de8a0d0d0f..0000000000 --- a/wxPython/wxPython/lib/PyCrust/PyCrustVersion.py +++ /dev/null @@ -1,10 +0,0 @@ -"""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 " -__cvsid__ = "$Id$" -__date__ = "July 1, 2001" -__version__ = "$Revision$"[11:-2] - -version = '0.5' diff --git a/wxPython/wxPython/lib/PyCrust/README.txt b/wxPython/wxPython/lib/PyCrust/README.txt new file mode 100644 index 0000000000..73ad07bc2b --- /dev/null +++ b/wxPython/wxPython/lib/PyCrust/README.txt @@ -0,0 +1,43 @@ +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$ diff --git a/wxPython/wxPython/lib/PyCrust/interpreter.py b/wxPython/wxPython/lib/PyCrust/interpreter.py new file mode 100644 index 0000000000..5f12c01f34 --- /dev/null +++ b/wxPython/wxPython/lib/PyCrust/interpreter.py @@ -0,0 +1,83 @@ +"""PyCrust Interpreter executes Python commands. +""" + +__author__ = "Patrick K. O'Brien " +__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) + diff --git a/wxPython/wxPython/lib/PyCrust/introspect.py b/wxPython/wxPython/lib/PyCrust/introspect.py index c9342c8a0c..8cf6ae8505 100644 --- a/wxPython/wxPython/lib/PyCrust/introspect.py +++ b/wxPython/wxPython/lib/PyCrust/introspect.py @@ -9,7 +9,8 @@ __version__ = "$Revision$"[11:-2] 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.""" @@ -18,37 +19,45 @@ def getAutoCompleteList(command='', locals=None): 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. @@ -119,22 +128,31 @@ 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. """ 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 diff --git a/wxPython/wxPython/lib/PyCrust/shell.py b/wxPython/wxPython/lib/PyCrust/shell.py new file mode 100644 index 0000000000..0c71206bd2 --- /dev/null +++ b/wxPython/wxPython/lib/PyCrust/shell.py @@ -0,0 +1,478 @@ +"""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 " +__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() + diff --git a/wxPython/wxPython/lib/PyCrust/version.py b/wxPython/wxPython/lib/PyCrust/version.py new file mode 100644 index 0000000000..0c48e4021d --- /dev/null +++ b/wxPython/wxPython/lib/PyCrust/version.py @@ -0,0 +1,10 @@ +"""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 " +__cvsid__ = "$Id$" +__date__ = "July 1, 2001" +__version__ = "$Revision$"[11:-2] + +VERSION = '0.5.2'