Updated PyCrust

git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/branches/WX_2_4_BRANCH@18266 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775
This commit is contained in:
Robin Dunn
2002-12-16 18:19:42 +00:00
parent 3cc4d9a7c3
commit 63e0edead7
10 changed files with 607 additions and 466 deletions

View File

@@ -4,20 +4,21 @@ __author__ = "Patrick K. O'Brien <pobrien@orbtech.com>"
__cvsid__ = "$Id$" __cvsid__ = "$Id$"
__revision__ = "$Revision$"[11:-2] __revision__ = "$Revision$"[11:-2]
from wxPython.wx import * from wxPython import wx
from crust import CrustFrame from crust import CrustFrame
True, False = 1, 0
class App(wxApp):
class App(wx.wxApp):
"""PyCrust standalone application.""" """PyCrust standalone application."""
def OnInit(self): def OnInit(self):
wxInitAllImageHandlers() wx.wxInitAllImageHandlers()
locals = {'__app__': 'PyCrust Standalone Application'} locals = {'__app__': 'PyCrust Standalone Application'}
self.crustFrame = CrustFrame(locals=locals) self.crustFrame = CrustFrame(locals=locals)
self.crustFrame.SetSize((750, 525)) self.crustFrame.SetSize((750, 525))
self.crustFrame.Show(true) self.crustFrame.Show(True)
self.crustFrame.crust.shell.SetFocus()
self.SetTopWindow(self.crustFrame) self.SetTopWindow(self.crustFrame)
# Add the application object to the sys module's namespace. # Add the application object to the sys module's namespace.
# This allows a shell user to do: # This allows a shell user to do:
@@ -25,11 +26,11 @@ class App(wxApp):
# >>> sys.application.whatever # >>> sys.application.whatever
import sys import sys
sys.application = self sys.application = self
return true return True
def main(): def main():
application = App(1) application = App(0)
application.MainLoop() application.MainLoop()
if __name__ == '__main__': if __name__ == '__main__':

View File

@@ -4,32 +4,34 @@ __author__ = "Patrick K. O'Brien <pobrien@orbtech.com>"
__cvsid__ = "$Id$" __cvsid__ = "$Id$"
__revision__ = "$Revision$"[11:-2] __revision__ = "$Revision$"[11:-2]
from wxPython.wx import * from wxPython import wx
from shell import ShellFrame from shell import ShellFrame
True, False = 1, 0
class App(wxApp):
class App(wx.wxApp):
"""PyShell standalone application.""" """PyShell standalone application."""
def OnInit(self): def OnInit(self):
wxInitAllImageHandlers() wx.wxInitAllImageHandlers()
locals = {'__app__': 'PyShell Standalone Application'} locals = {'__app__': 'PyShell Standalone Application'}
self.shellFrame = ShellFrame(locals=locals) self.shellFrame = ShellFrame(locals=locals)
self.shellFrame.SetSize((750, 525)) self.shellFrame.SetSize((750, 525))
self.shellFrame.Show(true) self.shellFrame.Show(True)
self.shellFrame.shell.SetFocus()
self.SetTopWindow(self.shellFrame) self.SetTopWindow(self.shellFrame)
self.shellFrame.shell.SetFocus()
# Add the application object to the sys module's namespace. # Add the application object to the sys module's namespace.
# This allows a shell user to do: # This allows a shell user to do:
# >>> import sys # >>> import sys
# >>> sys.application.whatever # >>> sys.application.whatever
import sys import sys
sys.application = self sys.application = self
return true return True
def main(): def main():
application = App(1) application = App(0)
application.MainLoop() application.MainLoop()
if __name__ == '__main__': if __name__ == '__main__':

View File

@@ -4,31 +4,32 @@ __author__ = "Patrick K. O'Brien <pobrien@orbtech.com>"
__cvsid__ = "$Id$" __cvsid__ = "$Id$"
__revision__ = "$Revision$"[11:-2] __revision__ = "$Revision$"[11:-2]
from wxPython.wx import * from wxPython import wx
from shell import Shell
from filling import Filling from filling import Filling
from version import VERSION
import os import os
from shell import Shell
from shellmenu import ShellMenu
from version import VERSION
class Crust(wxSplitterWindow): class Crust(wx.wxSplitterWindow):
"""PyCrust Crust based on wxSplitterWindow.""" """PyCrust Crust based on wxSplitterWindow."""
name = 'PyCrust Crust' name = 'PyCrust Crust'
revision = __revision__ revision = __revision__
def __init__(self, parent, id=-1, pos=wxDefaultPosition, \ def __init__(self, parent, id=-1, pos=wx.wxDefaultPosition,
size=wxDefaultSize, style=wxSP_3D, name='Crust Window', \ size=wx.wxDefaultSize, style=wx.wxSP_3D, name='Crust Window',
rootObject=None, rootLabel=None, rootIsNamespace=1, \ rootObject=None, rootLabel=None, rootIsNamespace=1,
intro='', locals=None, \ intro='', locals=None,
InterpClass=None, *args, **kwds): InterpClass=None, *args, **kwds):
"""Create a PyCrust Crust instance.""" """Create a PyCrust Crust instance."""
wxSplitterWindow.__init__(self, parent, id, pos, size, style, name) wx.wxSplitterWindow.__init__(self, parent, id, pos, size, style, name)
self.shell = Shell(parent=self, introText=intro, \ self.shell = Shell(parent=self, introText=intro,
locals=locals, InterpClass=InterpClass, \ locals=locals, InterpClass=InterpClass,
*args, **kwds) *args, **kwds)
self.filling = Filling(parent=self, \ self.filling = Filling(parent=self,
rootObject=self.shell.interp.locals, \ rootObject=self.shell.interp.locals,
rootLabel=rootLabel, rootIsNamespace=1) rootLabel=rootLabel, rootIsNamespace=1)
"""Add 'filling' to the interpreter's locals.""" """Add 'filling' to the interpreter's locals."""
self.shell.interp.locals['filling'] = self.filling self.shell.interp.locals['filling'] = self.filling
@@ -36,33 +37,30 @@ class Crust(wxSplitterWindow):
self.SetMinimumPaneSize(1) self.SetMinimumPaneSize(1)
# Temporary hack to share menus between PyCrust and PyShell. class CrustFrame(wx.wxFrame, ShellMenu):
from shell import ShellMenu
class CrustFrame(wxFrame, ShellMenu):
"""Frame containing all the PyCrust components.""" """Frame containing all the PyCrust components."""
name = 'PyCrust Frame' name = 'PyCrust Frame'
revision = __revision__ revision = __revision__
def __init__(self, parent=None, id=-1, title='PyCrust', \ def __init__(self, parent=None, id=-1, title='PyCrust',
pos=wxDefaultPosition, size=wxDefaultSize, \ pos=wx.wxDefaultPosition, size=wx.wxDefaultSize,
style=wxDEFAULT_FRAME_STYLE, \ style=wx.wxDEFAULT_FRAME_STYLE,
rootObject=None, rootLabel=None, rootIsNamespace=1, \ rootObject=None, rootLabel=None, rootIsNamespace=1,
locals=None, InterpClass=None, *args, **kwds): locals=None, InterpClass=None, *args, **kwds):
"""Create a PyCrust CrustFrame instance.""" """Create a PyCrust CrustFrame instance."""
wxFrame.__init__(self, parent, id, title, pos, size, style) wx.wxFrame.__init__(self, parent, id, title, pos, size, style)
intro = 'Welcome To PyCrust %s - The Flakiest Python Shell' % VERSION intro = 'Welcome To PyCrust %s - The Flakiest Python Shell' % VERSION
intro += '\nSponsored by Orbtech - Your source for Python programming expertise.' intro += '\nSponsored by Orbtech - Your source for Python programming expertise.'
self.CreateStatusBar() self.CreateStatusBar()
self.SetStatusText(intro.replace('\n', ', ')) self.SetStatusText(intro.replace('\n', ', '))
import images import images
self.SetIcon(images.getPyCrustIcon()) self.SetIcon(images.getPyCrustIcon())
self.crust = Crust(parent=self, intro=intro, \ self.crust = Crust(parent=self, intro=intro,
rootObject=rootObject, \ rootObject=rootObject,
rootLabel=rootLabel, \ rootLabel=rootLabel,
rootIsNamespace=rootIsNamespace, \ rootIsNamespace=rootIsNamespace,
locals=locals, \ locals=locals,
InterpClass=InterpClass, *args, **kwds) InterpClass=InterpClass, *args, **kwds)
# Override the filling so that status messages go to the status bar. # Override the filling so that status messages go to the status bar.
self.crust.filling.fillingTree.setStatusText = self.SetStatusText self.crust.filling.fillingTree.setStatusText = self.SetStatusText
@@ -75,7 +73,7 @@ class CrustFrame(wxFrame, ShellMenu):
# Temporary hack to share menus between PyCrust and PyShell. # Temporary hack to share menus between PyCrust and PyShell.
self.shell = self.crust.shell self.shell = self.crust.shell
self.createMenus() self.createMenus()
EVT_CLOSE(self, self.OnCloseWindow) wx.EVT_CLOSE(self, self.OnCloseWindow)
def OnCloseWindow(self, event): def OnCloseWindow(self, event):
self.crust.shell.destroy() self.crust.shell.destroy()

View File

@@ -5,8 +5,8 @@ __author__ = "Patrick K. O'Brien <pobrien@orbtech.com>"
__cvsid__ = "$Id$" __cvsid__ = "$Id$"
__revision__ = "$Revision$"[11:-2] __revision__ = "$Revision$"[11:-2]
from wxPython.wx import * from wxPython import wx
from wxPython.stc import * from wxPython import stc
from version import VERSION from version import VERSION
import inspect import inspect
import introspect import introspect
@@ -14,6 +14,8 @@ import keyword
import sys import sys
import types import types
True, False = 1, 0
COMMONTYPES = [getattr(types, t) for t in dir(types) \ COMMONTYPES = [getattr(types, t) for t in dir(types) \
if not t.startswith('_') \ if not t.startswith('_') \
and t not in ('ClassType', 'InstanceType', 'ModuleType')] and t not in ('ClassType', 'InstanceType', 'ModuleType')]
@@ -23,40 +25,40 @@ except AttributeError:
pass pass
class FillingTree(wxTreeCtrl): class FillingTree(wx.wxTreeCtrl):
"""PyCrust FillingTree based on wxTreeCtrl.""" """PyCrust FillingTree based on wxTreeCtrl."""
name = 'PyCrust Filling Tree' name = 'PyCrust Filling Tree'
revision = __revision__ revision = __revision__
def __init__(self, parent, id=-1, pos=wxDefaultPosition, \ def __init__(self, parent, id=-1, pos=wx.wxDefaultPosition,
size=wxDefaultSize, style=wxTR_HAS_BUTTONS, \ size=wx.wxDefaultSize, style=wx.wxTR_HAS_BUTTONS,
rootObject=None, rootLabel=None, rootIsNamespace=0): rootObject=None, rootLabel=None, rootIsNamespace=0):
"""Create a PyCrust FillingTree instance.""" """Create a PyCrust FillingTree instance."""
wxTreeCtrl.__init__(self, parent, id, pos, size) wx.wxTreeCtrl.__init__(self, parent, id, pos, size)
self.rootIsNamespace = rootIsNamespace self.rootIsNamespace = rootIsNamespace
if not rootObject: if not rootObject:
import __main__ import __main__
rootObject = __main__ rootObject = __main__
self.rootIsNamespace = 1 self.rootIsNamespace = 1
if not rootLabel: rootLabel = 'Ingredients' if not rootLabel: rootLabel = 'Ingredients'
rootData = wxTreeItemData(rootObject) rootData = wx.wxTreeItemData(rootObject)
self.root = self.AddRoot(rootLabel, -1, -1, rootData) self.root = self.AddRoot(rootLabel, -1, -1, rootData)
self.SetItemHasChildren(self.root, self.hasChildren(self.root)) self.SetItemHasChildren(self.root, self.hasChildren(self.root))
EVT_TREE_ITEM_EXPANDING(self, self.GetId(), self.OnItemExpanding) wx.EVT_TREE_ITEM_EXPANDING(self, self.GetId(), self.OnItemExpanding)
EVT_TREE_ITEM_COLLAPSED(self, self.GetId(), self.OnItemCollapsed) wx.EVT_TREE_ITEM_COLLAPSED(self, self.GetId(), self.OnItemCollapsed)
EVT_TREE_SEL_CHANGED(self, self.GetId(), self.OnSelChanged) wx.EVT_TREE_SEL_CHANGED(self, self.GetId(), self.OnSelChanged)
def hasChildren(self, o): def hasChildren(self, o):
"""Return true if object has children.""" """Return true if object has children."""
if self.getChildren(o): if self.getChildren(o):
return true return True
else: else:
return false return False
def getChildren(self, o): def getChildren(self, o):
"""Return a dictionary with the attributes or contents of object.""" """Return a dictionary with the attributes or contents of object."""
busy = wxBusyCursor() busy = wx.wxBusyCursor()
otype = type(o) otype = type(o)
if (otype is types.DictType) \ if (otype is types.DictType) \
or str(otype)[17:23] == 'BTrees' and hasattr(o, 'keys'): or str(otype)[17:23] == 'BTrees' and hasattr(o, 'keys'):
@@ -78,7 +80,7 @@ class FillingTree(wxTreeCtrl):
return d return d
def OnItemExpanding(self, event): def OnItemExpanding(self, event):
busy = wxBusyCursor() busy = wx.wxBusyCursor()
selection = event.GetItem() selection = event.GetItem()
if self.IsExpanded(selection): if self.IsExpanded(selection):
return return
@@ -100,18 +102,18 @@ class FillingTree(wxTreeCtrl):
and (selection != self.root \ and (selection != self.root \
or (selection == self.root and not self.rootIsNamespace)): or (selection == self.root and not self.rootIsNamespace)):
itemtext = repr(item) itemtext = repr(item)
child = self.AppendItem(selection, itemtext, -1, -1, \ child = self.AppendItem(selection, itemtext, -1, -1,
wxTreeItemData(children[item])) wx.wxTreeItemData(children[item]))
self.SetItemHasChildren(child, self.hasChildren(children[item])) self.SetItemHasChildren(child, self.hasChildren(children[item]))
def OnItemCollapsed(self, event): def OnItemCollapsed(self, event):
"""Remove all children from the item.""" """Remove all children from the item."""
busy = wxBusyCursor() busy = wx.wxBusyCursor()
item = event.GetItem() item = event.GetItem()
self.DeleteChildren(item) self.DeleteChildren(item)
def OnSelChanged(self, event): def OnSelChanged(self, event):
busy = wxBusyCursor() busy = wx.wxBusyCursor()
item = event.GetItem() item = event.GetItem()
if item == self.root: if item == self.root:
self.setText('') self.setText('')
@@ -189,7 +191,7 @@ class FillingTree(wxTreeCtrl):
print text print text
if wxPlatform == '__WXMSW__': if wx.wxPlatform == '__WXMSW__':
faces = { 'times' : 'Times New Roman', faces = { 'times' : 'Times New Roman',
'mono' : 'Courier New', 'mono' : 'Courier New',
'helv' : 'Lucida Console', 'helv' : 'Lucida Console',
@@ -201,8 +203,8 @@ if wxPlatform == '__WXMSW__':
} }
# Versions of wxPython prior to 2.3.2 had a sizing bug on Win platform. # Versions of wxPython prior to 2.3.2 had a sizing bug on Win platform.
# The font was 2 points too large. So we need to reduce the font size. # The font was 2 points too large. So we need to reduce the font size.
if ((wxMAJOR_VERSION, wxMINOR_VERSION) == (2, 3) and wxRELEASE_NUMBER < 2) \ if ((wx.wxMAJOR_VERSION, wx.wxMINOR_VERSION) == (2, 3) and wx.wxRELEASE_NUMBER < 2) \
or (wxMAJOR_VERSION <= 2 and wxMINOR_VERSION <= 2): or (wx.wxMAJOR_VERSION <= 2 and wx.wxMINOR_VERSION <= 2):
faces['size'] -= 2 faces['size'] -= 2
faces['lnsize'] -= 2 faces['lnsize'] -= 2
else: # GTK else: # GTK
@@ -216,16 +218,16 @@ else: # GTK
} }
class FillingText(wxStyledTextCtrl): class FillingText(stc.wxStyledTextCtrl):
"""PyCrust FillingText based on wxStyledTextCtrl.""" """PyCrust FillingText based on wxStyledTextCtrl."""
name = 'PyCrust Filling Text' name = 'PyCrust Filling Text'
revision = __revision__ revision = __revision__
def __init__(self, parent, id=-1, pos=wxDefaultPosition, \ def __init__(self, parent, id=-1, pos=wx.wxDefaultPosition,
size=wxDefaultSize, style=wxCLIP_CHILDREN): size=wx.wxDefaultSize, style=wx.wxCLIP_CHILDREN):
"""Create a PyCrust FillingText instance.""" """Create a PyCrust FillingText instance."""
wxStyledTextCtrl.__init__(self, parent, id, pos, size, style) stc.wxStyledTextCtrl.__init__(self, parent, id, pos, size, style)
# Configure various defaults and user preferences. # Configure various defaults and user preferences.
self.config() self.config()
@@ -233,7 +235,7 @@ class FillingText(wxStyledTextCtrl):
"""Configure shell based on user preferences.""" """Configure shell based on user preferences."""
self.SetMarginWidth(1, 0) self.SetMarginWidth(1, 0)
self.SetLexer(wxSTC_LEX_PYTHON) self.SetLexer(stc.wxSTC_LEX_PYTHON)
self.SetKeyWords(0, ' '.join(keyword.kwlist)) self.SetKeyWords(0, ' '.join(keyword.kwlist))
self.setStyles(faces) self.setStyles(faces)
@@ -250,51 +252,51 @@ class FillingText(wxStyledTextCtrl):
"""Configure font size, typeface and color for lexer.""" """Configure font size, typeface and color for lexer."""
# Default style # Default style
self.StyleSetSpec(wxSTC_STYLE_DEFAULT, "face:%(mono)s,size:%(size)d" % faces) self.StyleSetSpec(stc.wxSTC_STYLE_DEFAULT, "face:%(mono)s,size:%(size)d" % faces)
self.StyleClearAll() self.StyleClearAll()
# Built in styles # Built in styles
self.StyleSetSpec(wxSTC_STYLE_LINENUMBER, "back:#C0C0C0,face:%(mono)s,size:%(lnsize)d" % faces) self.StyleSetSpec(stc.wxSTC_STYLE_LINENUMBER, "back:#C0C0C0,face:%(mono)s,size:%(lnsize)d" % faces)
self.StyleSetSpec(wxSTC_STYLE_CONTROLCHAR, "face:%(mono)s" % faces) self.StyleSetSpec(stc.wxSTC_STYLE_CONTROLCHAR, "face:%(mono)s" % faces)
self.StyleSetSpec(wxSTC_STYLE_BRACELIGHT, "fore:#0000FF,back:#FFFF88") self.StyleSetSpec(stc.wxSTC_STYLE_BRACELIGHT, "fore:#0000FF,back:#FFFF88")
self.StyleSetSpec(wxSTC_STYLE_BRACEBAD, "fore:#FF0000,back:#FFFF88") self.StyleSetSpec(stc.wxSTC_STYLE_BRACEBAD, "fore:#FF0000,back:#FFFF88")
# Python styles # Python styles
self.StyleSetSpec(wxSTC_P_DEFAULT, "face:%(mono)s" % faces) self.StyleSetSpec(stc.wxSTC_P_DEFAULT, "face:%(mono)s" % faces)
self.StyleSetSpec(wxSTC_P_COMMENTLINE, "fore:#007F00,face:%(mono)s" % faces) self.StyleSetSpec(stc.wxSTC_P_COMMENTLINE, "fore:#007F00,face:%(mono)s" % faces)
self.StyleSetSpec(wxSTC_P_NUMBER, "") self.StyleSetSpec(stc.wxSTC_P_NUMBER, "")
self.StyleSetSpec(wxSTC_P_STRING, "fore:#7F007F,face:%(mono)s" % faces) self.StyleSetSpec(stc.wxSTC_P_STRING, "fore:#7F007F,face:%(mono)s" % faces)
self.StyleSetSpec(wxSTC_P_CHARACTER, "fore:#7F007F,face:%(mono)s" % faces) self.StyleSetSpec(stc.wxSTC_P_CHARACTER, "fore:#7F007F,face:%(mono)s" % faces)
self.StyleSetSpec(wxSTC_P_WORD, "fore:#00007F,bold") self.StyleSetSpec(stc.wxSTC_P_WORD, "fore:#00007F,bold")
self.StyleSetSpec(wxSTC_P_TRIPLE, "fore:#7F0000") self.StyleSetSpec(stc.wxSTC_P_TRIPLE, "fore:#7F0000")
self.StyleSetSpec(wxSTC_P_TRIPLEDOUBLE, "fore:#000033,back:#FFFFE8") self.StyleSetSpec(stc.wxSTC_P_TRIPLEDOUBLE, "fore:#000033,back:#FFFFE8")
self.StyleSetSpec(wxSTC_P_CLASSNAME, "fore:#0000FF,bold") self.StyleSetSpec(stc.wxSTC_P_CLASSNAME, "fore:#0000FF,bold")
self.StyleSetSpec(wxSTC_P_DEFNAME, "fore:#007F7F,bold") self.StyleSetSpec(stc.wxSTC_P_DEFNAME, "fore:#007F7F,bold")
self.StyleSetSpec(wxSTC_P_OPERATOR, "") self.StyleSetSpec(stc.wxSTC_P_OPERATOR, "")
self.StyleSetSpec(wxSTC_P_IDENTIFIER, "") self.StyleSetSpec(stc.wxSTC_P_IDENTIFIER, "")
self.StyleSetSpec(wxSTC_P_COMMENTBLOCK, "fore:#7F7F7F") self.StyleSetSpec(stc.wxSTC_P_COMMENTBLOCK, "fore:#7F7F7F")
self.StyleSetSpec(wxSTC_P_STRINGEOL, "fore:#000000,face:%(mono)s,back:#E0C0E0,eolfilled" % faces) self.StyleSetSpec(stc.wxSTC_P_STRINGEOL, "fore:#000000,face:%(mono)s,back:#E0C0E0,eolfilled" % faces)
def SetText(self, *args, **kwds): def SetText(self, *args, **kwds):
self.SetReadOnly(0) self.SetReadOnly(0)
wxStyledTextCtrl.SetText(self, *args, **kwds) stc.wxStyledTextCtrl.SetText(self, *args, **kwds)
self.SetReadOnly(1) self.SetReadOnly(1)
class Filling(wxSplitterWindow): class Filling(wx.wxSplitterWindow):
"""PyCrust Filling based on wxSplitterWindow.""" """PyCrust Filling based on wxSplitterWindow."""
name = 'PyCrust Filling' name = 'PyCrust Filling'
revision = __revision__ revision = __revision__
def __init__(self, parent, id=-1, pos=wxDefaultPosition, \ def __init__(self, parent, id=-1, pos=wx.wxDefaultPosition,
size=wxDefaultSize, style=wxSP_3D, name='Filling Window', \ size=wx.wxDefaultSize, style=wx.wxSP_3D, name='Filling Window',
rootObject=None, rootLabel=None, rootIsNamespace=0): rootObject=None, rootLabel=None, rootIsNamespace=0):
"""Create a PyCrust Filling instance.""" """Create a PyCrust Filling instance."""
wxSplitterWindow.__init__(self, parent, id, pos, size, style, name) wx.wxSplitterWindow.__init__(self, parent, id, pos, size, style, name)
self.fillingTree = FillingTree(parent=self, rootObject=rootObject, \ self.fillingTree = FillingTree(parent=self, rootObject=rootObject,
rootLabel=rootLabel, \ rootLabel=rootLabel,
rootIsNamespace=rootIsNamespace) rootIsNamespace=rootIsNamespace)
self.fillingText = FillingText(parent=self) self.fillingText = FillingText(parent=self)
self.SplitVertically(self.fillingTree, self.fillingText, 200) self.SplitVertically(self.fillingTree, self.fillingText, 200)
@@ -305,41 +307,41 @@ class Filling(wxSplitterWindow):
self.fillingTree.SelectItem(self.fillingTree.root) self.fillingTree.SelectItem(self.fillingTree.root)
class FillingFrame(wxFrame): class FillingFrame(wx.wxFrame):
"""Frame containing the PyCrust filling, or namespace tree component.""" """Frame containing the PyCrust filling, or namespace tree component."""
name = 'PyCrust Filling Frame' name = 'PyCrust Filling Frame'
revision = __revision__ revision = __revision__
def __init__(self, parent=None, id=-1, title='PyFilling', \ def __init__(self, parent=None, id=-1, title='PyFilling',
pos=wxDefaultPosition, size=wxDefaultSize, \ pos=wx.wxDefaultPosition, size=wx.wxDefaultSize,
style=wxDEFAULT_FRAME_STYLE, rootObject=None, \ style=wx.wxDEFAULT_FRAME_STYLE, rootObject=None,
rootLabel=None, rootIsNamespace=0): rootLabel=None, rootIsNamespace=0):
"""Create a PyCrust FillingFrame instance.""" """Create a PyCrust FillingFrame instance."""
wxFrame.__init__(self, parent, id, title, pos, size, style) wx.wxFrame.__init__(self, parent, id, title, pos, size, style)
intro = 'Welcome To PyFilling - The Tastiest Namespace Inspector' intro = 'Welcome To PyFilling - The Tastiest Namespace Inspector'
self.CreateStatusBar() self.CreateStatusBar()
self.SetStatusText(intro) self.SetStatusText(intro)
if wxPlatform == '__WXMSW__': if wx.wxPlatform == '__WXMSW__':
import os import os
filename = os.path.join(os.path.dirname(__file__), 'PyCrust.ico') filename = os.path.join(os.path.dirname(__file__), 'PyCrust.ico')
icon = wxIcon(filename, wxBITMAP_TYPE_ICO) icon = wx.wxIcon(filename, wx.wxBITMAP_TYPE_ICO)
self.SetIcon(icon) self.SetIcon(icon)
self.filling = Filling(parent=self, rootObject=rootObject, \ self.filling = Filling(parent=self, rootObject=rootObject,
rootLabel=rootLabel, \ rootLabel=rootLabel,
rootIsNamespace=rootIsNamespace) rootIsNamespace=rootIsNamespace)
# Override the filling so that status messages go to the status bar. # Override the filling so that status messages go to the status bar.
self.filling.fillingTree.setStatusText = self.SetStatusText self.filling.fillingTree.setStatusText = self.SetStatusText
class App(wxApp): class App(wx.wxApp):
"""PyFilling standalone application.""" """PyFilling standalone application."""
def OnInit(self): def OnInit(self):
self.fillingFrame = FillingFrame() self.fillingFrame = FillingFrame()
self.fillingFrame.Show(true) self.fillingFrame.Show(True)
self.SetTopWindow(self.fillingFrame) self.SetTopWindow(self.fillingFrame)
return true return True

View File

@@ -15,7 +15,7 @@ class Interpreter(InteractiveInterpreter):
revision = __revision__ revision = __revision__
def __init__(self, locals=None, rawin=None, \ def __init__(self, locals=None, rawin=None,
stdin=sys.stdin, stdout=sys.stdout, stderr=sys.stderr): stdin=sys.stdin, stdout=sys.stdout, stderr=sys.stderr):
"""Create an interactive interpreter object.""" """Create an interactive interpreter object."""
InteractiveInterpreter.__init__(self, locals=locals) InteractiveInterpreter.__init__(self, locals=locals)
@@ -27,7 +27,7 @@ class Interpreter(InteractiveInterpreter):
__builtin__.raw_input = rawin __builtin__.raw_input = rawin
del __builtin__ del __builtin__
copyright = \ copyright = \
'Type "copyright", "credits" or "license" for more information.' 'Type "help", "copyright", "credits" or "license" for more information.'
self.introText = 'Python %s on %s%s%s' % \ self.introText = 'Python %s on %s%s%s' % \
(sys.version, sys.platform, os.linesep, copyright) (sys.version, sys.platform, os.linesep, copyright)
try: try:
@@ -98,10 +98,10 @@ class Interpreter(InteractiveInterpreter):
class InterpreterAlaCarte(Interpreter): class InterpreterAlaCarte(Interpreter):
"""PyCrustAlaCarte Demo Interpreter.""" """PyCrustAlaCarte Demo Interpreter."""
def __init__(self, locals, rawin, stdin, stdout, stderr, \ def __init__(self, locals, rawin, stdin, stdout, stderr,
ps1='main prompt', ps2='continuation prompt'): ps1='main prompt', ps2='continuation prompt'):
"""Create an interactive interpreter object.""" """Create an interactive interpreter object."""
Interpreter.__init__(self, locals=locals, rawin=rawin, \ Interpreter.__init__(self, locals=locals, rawin=rawin,
stdin=stdin, stdout=stdout, stderr=stderr) stdin=stdin, stdout=stdout, stderr=stderr)
sys.ps1 = ps1 sys.ps1 = ps1
sys.ps2 = ps2 sys.ps2 = ps2

View File

@@ -5,11 +5,15 @@ __author__ = "Patrick K. O'Brien <pobrien@orbtech.com>"
__cvsid__ = "$Id$" __cvsid__ = "$Id$"
__revision__ = "$Revision$"[11:-2] __revision__ = "$Revision$"[11:-2]
from __future__ import nested_scopes
import cStringIO
import inspect import inspect
import string import string
import tokenize
import types import types
def getAutoCompleteList(command='', locals=None, includeMagic=1, \ def getAutoCompleteList(command='', locals=None, includeMagic=1,
includeSingle=1, includeDouble=1): includeSingle=1, includeDouble=1):
"""Return list of auto-completion options for command. """Return list of auto-completion options for command.
@@ -25,7 +29,7 @@ def getAutoCompleteList(command='', locals=None, includeMagic=1, \
except: except:
pass pass
else: else:
attributes = getAttributeNames(object, includeMagic, \ attributes = getAttributeNames(object, includeMagic,
includeSingle, includeDouble) includeSingle, includeDouble)
return attributes return attributes
@@ -36,8 +40,8 @@ def getAttributeNames(object, includeMagic=1, includeSingle=1, includeDouble=1):
if not hasattrAlwaysReturnsTrue(object): if not hasattrAlwaysReturnsTrue(object):
# Add some attributes that don't always get picked up. # Add some attributes that don't always get picked up.
# If they don't apply, they'll get filtered out at the end. # If they don't apply, they'll get filtered out at the end.
attributes += ['__bases__', '__class__', '__dict__', '__name__', \ attributes += ['__bases__', '__class__', '__dict__', '__name__',
'func_closure', 'func_code', 'func_defaults', \ 'func_closure', 'func_code', 'func_defaults',
'func_dict', 'func_doc', 'func_globals', 'func_name'] 'func_dict', 'func_doc', 'func_globals', 'func_name']
if includeMagic: if includeMagic:
try: attributes += object._getAttributeNames() try: attributes += object._getAttributeNames()
@@ -182,37 +186,83 @@ def getRoot(command, terminator=None):
Return only the root portion that can be eval()'d without side effects. Return only the root portion that can be eval()'d without side effects.
The command would normally terminate with a "(" or ".". The terminator The command would normally terminate with a "(" or ".". The terminator
and anything after the terminator will be dropped.""" and anything after the terminator will be dropped."""
root = ''
validChars = "._" + string.uppercase + string.lowercase + string.digits
emptyTypes = ("''", '""', '""""""', "''''''", '[]', '()', '{}')
validSeparators = string.whitespace + ',+-*/=%<>&|^~:([{'
# Drop the final terminator and anything that follows.
command = rtrimTerminus(command, terminator) command = rtrimTerminus(command, terminator)
if len(command) == 0: command = command.rstrip()
root = '' tokens = getTokens(command)
elif command in emptyTypes and terminator in ('.', '', None): tokens.reverse()
# Let empty type delimiter pairs go through. line = ''
root = command start = None
else: prefix = ''
# Go backward through the command until we hit an "invalid" character. laststring = '.'
i = len(command) emptyTypes = ('[]', '()', '{}')
while i and command[i-1] in validChars: for token in tokens:
i -= 1 tokentype = token[0]
# Default to everything from the "invalid" character to the end. tokenstring = token[1]
root = command[i:] line = token[4]
# Override certain exceptions. if tokentype is tokenize.ENDMARKER:
if i > 0 and command[i-1] in ("'", '"'): continue
# Detect situations where we are in the middle of a string. if tokentype in (tokenize.NAME, tokenize.STRING, tokenize.NUMBER) \
# This code catches the simplest case, but needs to catch others. and laststring != '.':
root = '' # We've reached something that's not part of the root.
elif ((2 <= i < len(command) and command[i] == '.') \ if prefix and line[token[3][1]] != ' ':
or (2 <= i <= len(command) and terminator in ('.', '', None))) \ # If it doesn't have a space after it, remove the prefix.
and command[i-2:i] in emptyTypes: prefix = ''
# Allow empty types to get through. break
# Don't confuse an empty tupple with an argumentless callable. if tokentype in (tokenize.NAME, tokenize.STRING, tokenize.NUMBER) \
if i == 2 or (i >= 3 and command[i-3] in validSeparators): or (tokentype is tokenize.OP and tokenstring == '.'):
root = command[i-2:] if prefix:
return root # The prefix isn't valid because it comes after a dot.
prefix = ''
break
else:
# start represents the last known good point in the line.
start = token[2][1]
elif tokenstring in ('[({])}'):
# Remember, we're working backwords.
# So prefix += tokenstring would be wrong.
if prefix in emptyTypes and tokenstring in ('[({'):
# We've already got an empty type identified so now we are in
# a nested situation and we can break out with what we've got.
break
else:
prefix = tokenstring + prefix
else:
# We've reached something that's not part of the root.
break
laststring = tokenstring
if start is None:
start = len(line)
root = line[start:]
if prefix in emptyTypes:
# Empty types are safe to be eval()'d and introspected.
root = prefix + root
return root
def getTokens(command):
"""Return list of token tuples for command."""
command = str(command) # In case the command is unicode, which won't work.
f = cStringIO.StringIO(command)
# tokens is a list of token tuples, each looking like:
# (type, string, (srow, scol), (erow, ecol), line)
tokens = []
# Can't use list comprehension:
# tokens = [token for token in tokenize.generate_tokens(f.readline)]
# because of need to append as much as possible before TokenError.
try:
## This code wasn't backward compatible with Python 2.1.3.
##
## for token in tokenize.generate_tokens(f.readline):
## tokens.append(token)
# This works with Python 2.1.3 (with nested_scopes).
def eater(*args):
tokens.append(args)
tokenize.tokenize_loop(f.readline, eater)
except tokenize.TokenError:
# This is due to a premature EOF, which we expect since
# we are feeding in fragments of Python code.
pass
return tokens
def rtrimTerminus(command, terminator=None): def rtrimTerminus(command, terminator=None):
"""Return command minus the final terminator and anything that follows.""" """Return command minus the final terminator and anything that follows."""

View File

@@ -64,11 +64,13 @@ class PseudoFile:
class PseudoFileIn(PseudoFile): class PseudoFileIn(PseudoFile):
def __init__(self, readline): def __init__(self, readline, readlines=None):
if callable(readline): if callable(readline):
self.readline = readline self.readline = readline
else: else:
raise ValueError, 'readline must be callable' raise ValueError, 'readline must be callable'
if callable(readlines):
self.readlines = readlines
def isatty(self): def isatty(self):
return 1 return 1

View File

@@ -8,21 +8,26 @@ __author__ = "Patrick K. O'Brien <pobrien@orbtech.com>"
__cvsid__ = "$Id$" __cvsid__ = "$Id$"
__revision__ = "$Revision$"[11:-2] __revision__ = "$Revision$"[11:-2]
from wxPython.wx import * from wxPython import wx
from wxPython.stc import * from wxPython import stc
import keyword import keyword
import os import os
import sys import sys
import time
from pseudo import PseudoFileIn from pseudo import PseudoFileIn
from pseudo import PseudoFileOut from pseudo import PseudoFileOut
from pseudo import PseudoFileErr from pseudo import PseudoFileErr
from shellmenu import ShellMenu
from version import VERSION from version import VERSION
True, False = 1, 0
sys.ps3 = '<-- ' # Input prompt. sys.ps3 = '<-- ' # Input prompt.
NAVKEYS = (WXK_END, WXK_LEFT, WXK_RIGHT, WXK_UP, WXK_DOWN, WXK_PRIOR, WXK_NEXT) NAVKEYS = (wx.WXK_END, wx.WXK_LEFT, wx.WXK_RIGHT,
wx.WXK_UP, wx.WXK_DOWN, wx.WXK_PRIOR, wx.WXK_NEXT)
if wxPlatform == '__WXMSW__': if wx.wxPlatform == '__WXMSW__':
faces = { 'times' : 'Times New Roman', faces = { 'times' : 'Times New Roman',
'mono' : 'Courier New', 'mono' : 'Courier New',
'helv' : 'Lucida Console', 'helv' : 'Lucida Console',
@@ -32,11 +37,6 @@ if wxPlatform == '__WXMSW__':
'lnsize' : 9, 'lnsize' : 9,
'backcol': '#FFFFFF', 'backcol': '#FFFFFF',
} }
# Versions of wxPython prior to 2.3.2 had a sizing bug on Win platform.
# The font was 2 points too large. So we need to reduce the font size.
if (wxMAJOR_VERSION, wxMINOR_VERSION, wxRELEASE_NUMBER) < (2, 3, 2):
faces['size'] -= 2
faces['lnsize'] -= 2
else: # GTK else: # GTK
faces = { 'times' : 'Times', faces = { 'times' : 'Times',
'mono' : 'Courier', 'mono' : 'Courier',
@@ -48,10 +48,42 @@ else: # GTK
} }
class ShellFrame(wx.wxFrame, ShellMenu):
"""Frame containing the PyCrust shell component."""
name = 'PyCrust Shell Frame'
revision = __revision__
def __init__(self, parent=None, id=-1, title='PyShell',
pos=wx.wxDefaultPosition, size=wx.wxDefaultSize,
style=wx.wxDEFAULT_FRAME_STYLE, locals=None,
InterpClass=None, *args, **kwds):
"""Create a PyCrust ShellFrame instance."""
wx.wxFrame.__init__(self, parent, id, title, pos, size, style)
intro = 'Welcome To PyCrust %s - The Flakiest Python Shell' % VERSION
intro += '\nSponsored by Orbtech - Your source for Python programming expertise.'
self.CreateStatusBar()
self.SetStatusText(intro.replace('\n', ', '))
filename = os.path.join(os.path.dirname(__file__), 'PyCrust.ico')
icon = wx.wxIcon(filename, wx.wxBITMAP_TYPE_ICO)
self.SetIcon(icon)
self.shell = Shell(parent=self, id=-1, introText=intro,
locals=locals, InterpClass=InterpClass,
*args, **kwds)
# Override the shell so that status messages go to the status bar.
self.shell.setStatusText = self.SetStatusText
self.createMenus()
wx.EVT_CLOSE(self, self.OnCloseWindow)
def OnCloseWindow(self, event):
self.shell.destroy()
self.Destroy()
class ShellFacade: class ShellFacade:
"""Simplified interface to all shell-related functionality. """Simplified interface to all shell-related functionality.
This is a semi-transparent facade, in that all attributes of other are This is a semi-transparent facade, in that all attributes of other are
still accessible, even though only some are visible to the user.""" still accessible, even though only some are visible to the user."""
name = 'PyCrust Shell Interface' name = 'PyCrust Shell Interface'
@@ -59,19 +91,21 @@ class ShellFacade:
def __init__(self, other): def __init__(self, other):
"""Create a ShellFacade instance.""" """Create a ShellFacade instance."""
methods = ['ask', methods = [
'clear', 'about',
'pause', 'ask',
'prompt', 'clear',
'quit', 'pause',
'redirectStderr', 'prompt',
'redirectStdin', 'quit',
'redirectStdout', 'redirectStderr',
'run', 'redirectStdin',
'runfile', 'redirectStdout',
'wrap', 'run',
'zoom', 'runfile',
] 'wrap',
'zoom',
]
for method in methods: for method in methods:
self.__dict__[method] = getattr(other, method) self.__dict__[method] = getattr(other, method)
d = self.__dict__ d = self.__dict__
@@ -129,17 +163,17 @@ F8 Command-completion of History item.
return list return list
class Shell(wxStyledTextCtrl): class Shell(stc.wxStyledTextCtrl):
"""PyCrust Shell based on wxStyledTextCtrl.""" """PyCrust Shell based on wxStyledTextCtrl."""
name = 'PyCrust Shell' name = 'PyCrust Shell'
revision = __revision__ revision = __revision__
def __init__(self, parent, id=-1, pos=wxDefaultPosition, \ def __init__(self, parent, id=-1, pos=wx.wxDefaultPosition,
size=wxDefaultSize, style=wxCLIP_CHILDREN, introText='', \ size=wx.wxDefaultSize, style=wx.wxCLIP_CHILDREN, introText='',
locals=None, InterpClass=None, *args, **kwds): locals=None, InterpClass=None, *args, **kwds):
"""Create a PyCrust Shell instance.""" """Create a PyCrust Shell instance."""
wxStyledTextCtrl.__init__(self, parent, id, pos, size, style) stc.wxStyledTextCtrl.__init__(self, parent, id, pos, size, style)
# Grab these so they can be restored by self.redirect* methods. # Grab these so they can be restored by self.redirect* methods.
self.stdin = sys.stdin self.stdin = sys.stdin
self.stdout = sys.stdout self.stdout = sys.stdout
@@ -160,15 +194,15 @@ class Shell(wxStyledTextCtrl):
if locals: if locals:
shellLocals.update(locals) shellLocals.update(locals)
# Create a replacement for stdin. # Create a replacement for stdin.
self.reader = PseudoFileIn(self.readline) self.reader = PseudoFileIn(self.readline, self.readlines)
self.reader.input = '' self.reader.input = ''
self.reader.isreading = 0 self.reader.isreading = 0
# Set up the interpreter. # Set up the interpreter.
self.interp = Interpreter(locals=shellLocals, \ self.interp = Interpreter(locals=shellLocals,
rawin=self.raw_input, \ rawin=self.raw_input,
stdin=self.reader, \ stdin=self.reader,
stdout=PseudoFileOut(self.writeOut), \ stdout=PseudoFileOut(self.writeOut),
stderr=PseudoFileErr(self.writeErr), \ stderr=PseudoFileErr(self.writeErr),
*args, **kwds) *args, **kwds)
# Find out for which keycodes the interpreter will autocomplete. # Find out for which keycodes the interpreter will autocomplete.
self.autoCompleteKeys = self.interp.getAutoCompleteKeys() self.autoCompleteKeys = self.interp.getAutoCompleteKeys()
@@ -186,10 +220,13 @@ class Shell(wxStyledTextCtrl):
self.history = [] self.history = []
self.historyIndex = -1 self.historyIndex = -1
# Assign handlers for keyboard events. # Assign handlers for keyboard events.
EVT_KEY_DOWN(self, self.OnKeyDown) wx.EVT_KEY_DOWN(self, self.OnKeyDown)
EVT_CHAR(self, self.OnChar) wx.EVT_CHAR(self, self.OnChar)
# Assign handlers for wxSTC events. # Assign handlers for wxSTC events.
EVT_STC_UPDATEUI(self, id, self.OnUpdateUI) stc.EVT_STC_UPDATEUI(self, id, self.OnUpdateUI)
# Assign handler for idle time.
self.waiting = False
wx.EVT_IDLE(self, self.OnIdle)
# Configure various defaults and user preferences. # Configure various defaults and user preferences.
self.config() self.config()
# Display the introductory banner information. # Display the introductory banner information.
@@ -212,10 +249,10 @@ class Shell(wxStyledTextCtrl):
def config(self): def config(self):
"""Configure shell based on user preferences.""" """Configure shell based on user preferences."""
self.SetMarginType(1, wxSTC_MARGIN_NUMBER) self.SetMarginType(1, stc.wxSTC_MARGIN_NUMBER)
self.SetMarginWidth(1, 40) self.SetMarginWidth(1, 40)
self.SetLexer(wxSTC_LEX_PYTHON) self.SetLexer(stc.wxSTC_LEX_PYTHON)
self.SetKeyWords(0, ' '.join(keyword.kwlist)) self.SetKeyWords(0, ' '.join(keyword.kwlist))
self.setStyles(faces) self.setStyles(faces)
@@ -231,10 +268,10 @@ class Shell(wxStyledTextCtrl):
self.AutoCompSetIgnoreCase(self.autoCompleteCaseInsensitive) self.AutoCompSetIgnoreCase(self.autoCompleteCaseInsensitive)
# Do we want to automatically pop up command argument help? # Do we want to automatically pop up command argument help?
self.autoCallTip = 1 self.autoCallTip = 1
self.CallTipSetBackground(wxColour(255, 255, 232)) self.CallTipSetBackground(wx.wxColour(255, 255, 232))
self.wrap() self.wrap()
try: try:
self.SetEndAtLastLine(false) self.SetEndAtLastLine(False)
except AttributeError: except AttributeError:
pass pass
@@ -247,7 +284,7 @@ class Shell(wxStyledTextCtrl):
self.write(self.interp.introText) self.write(self.interp.introText)
except AttributeError: except AttributeError:
pass pass
wxCallAfter(self.ScrollToLine, 0) wx.wxCallAfter(self.ScrollToLine, 0)
def setBuiltinKeywords(self): def setBuiltinKeywords(self):
"""Create pseudo keywords as part of builtins. """Create pseudo keywords as part of builtins.
@@ -286,33 +323,50 @@ class Shell(wxStyledTextCtrl):
"""Configure font size, typeface and color for lexer.""" """Configure font size, typeface and color for lexer."""
# Default style # Default style
self.StyleSetSpec(wxSTC_STYLE_DEFAULT, "face:%(mono)s,size:%(size)d,back:%(backcol)s" % faces) self.StyleSetSpec(stc.wxSTC_STYLE_DEFAULT, "face:%(mono)s,size:%(size)d,back:%(backcol)s" % faces)
self.StyleClearAll() self.StyleClearAll()
# Built in styles # Built in styles
self.StyleSetSpec(wxSTC_STYLE_LINENUMBER, "back:#C0C0C0,face:%(mono)s,size:%(lnsize)d" % faces) self.StyleSetSpec(stc.wxSTC_STYLE_LINENUMBER, "back:#C0C0C0,face:%(mono)s,size:%(lnsize)d" % faces)
self.StyleSetSpec(wxSTC_STYLE_CONTROLCHAR, "face:%(mono)s" % faces) self.StyleSetSpec(stc.wxSTC_STYLE_CONTROLCHAR, "face:%(mono)s" % faces)
self.StyleSetSpec(wxSTC_STYLE_BRACELIGHT, "fore:#0000FF,back:#FFFF88") self.StyleSetSpec(stc.wxSTC_STYLE_BRACELIGHT, "fore:#0000FF,back:#FFFF88")
self.StyleSetSpec(wxSTC_STYLE_BRACEBAD, "fore:#FF0000,back:#FFFF88") self.StyleSetSpec(stc.wxSTC_STYLE_BRACEBAD, "fore:#FF0000,back:#FFFF88")
# Python styles # Python styles
self.StyleSetSpec(wxSTC_P_DEFAULT, "face:%(mono)s" % faces) self.StyleSetSpec(stc.wxSTC_P_DEFAULT, "face:%(mono)s" % faces)
self.StyleSetSpec(wxSTC_P_COMMENTLINE, "fore:#007F00,face:%(mono)s" % faces) self.StyleSetSpec(stc.wxSTC_P_COMMENTLINE, "fore:#007F00,face:%(mono)s" % faces)
self.StyleSetSpec(wxSTC_P_NUMBER, "") self.StyleSetSpec(stc.wxSTC_P_NUMBER, "")
self.StyleSetSpec(wxSTC_P_STRING, "fore:#7F007F,face:%(mono)s" % faces) self.StyleSetSpec(stc.wxSTC_P_STRING, "fore:#7F007F,face:%(mono)s" % faces)
self.StyleSetSpec(wxSTC_P_CHARACTER, "fore:#7F007F,face:%(mono)s" % faces) self.StyleSetSpec(stc.wxSTC_P_CHARACTER, "fore:#7F007F,face:%(mono)s" % faces)
self.StyleSetSpec(wxSTC_P_WORD, "fore:#00007F,bold") self.StyleSetSpec(stc.wxSTC_P_WORD, "fore:#00007F,bold")
self.StyleSetSpec(wxSTC_P_TRIPLE, "fore:#7F0000") self.StyleSetSpec(stc.wxSTC_P_TRIPLE, "fore:#7F0000")
self.StyleSetSpec(wxSTC_P_TRIPLEDOUBLE, "fore:#000033,back:#FFFFE8") self.StyleSetSpec(stc.wxSTC_P_TRIPLEDOUBLE, "fore:#000033,back:#FFFFE8")
self.StyleSetSpec(wxSTC_P_CLASSNAME, "fore:#0000FF,bold") self.StyleSetSpec(stc.wxSTC_P_CLASSNAME, "fore:#0000FF,bold")
self.StyleSetSpec(wxSTC_P_DEFNAME, "fore:#007F7F,bold") self.StyleSetSpec(stc.wxSTC_P_DEFNAME, "fore:#007F7F,bold")
self.StyleSetSpec(wxSTC_P_OPERATOR, "") self.StyleSetSpec(stc.wxSTC_P_OPERATOR, "")
self.StyleSetSpec(wxSTC_P_IDENTIFIER, "") self.StyleSetSpec(stc.wxSTC_P_IDENTIFIER, "")
self.StyleSetSpec(wxSTC_P_COMMENTBLOCK, "fore:#7F7F7F") self.StyleSetSpec(stc.wxSTC_P_COMMENTBLOCK, "fore:#7F7F7F")
self.StyleSetSpec(wxSTC_P_STRINGEOL, "fore:#000000,face:%(mono)s,back:#E0C0E0,eolfilled" % faces) self.StyleSetSpec(stc.wxSTC_P_STRINGEOL, "fore:#000000,face:%(mono)s,back:#E0C0E0,eolfilled" % faces)
def OnUpdateUI(self, evt): def about(self):
"""Display information about PyCrust."""
text = """
PyCrust Version: %s
Shell Revision: %s
Interpreter Revision: %s
Python Version: %s
wxPython Version: %s
Platform: %s""" % (VERSION, self.revision, self.interp.revision,
sys.version.split()[0], wx.__version__, sys.platform)
self.write(text.strip())
def OnIdle(self, event):
"""Free the CPU to do other things."""
if self.waiting:
time.sleep(0.1)
def OnUpdateUI(self, event):
"""Check for matching braces.""" """Check for matching braces."""
braceAtCaret = -1 braceAtCaret = -1
braceOpposite = -1 braceOpposite = -1
@@ -328,7 +382,7 @@ class Shell(wxStyledTextCtrl):
# Check before. # Check before.
if charBefore and chr(charBefore) in '[]{}()' \ if charBefore and chr(charBefore) in '[]{}()' \
and styleBefore == wxSTC_P_OPERATOR: and styleBefore == stc.wxSTC_P_OPERATOR:
braceAtCaret = caretPos - 1 braceAtCaret = caretPos - 1
# Check after. # Check after.
@@ -340,7 +394,7 @@ class Shell(wxStyledTextCtrl):
#*** #***
styleAfter = self.GetStyleAt(caretPos) styleAfter = self.GetStyleAt(caretPos)
if charAfter and chr(charAfter) in '[]{}()' \ if charAfter and chr(charAfter) in '[]{}()' \
and styleAfter == wxSTC_P_OPERATOR: and styleAfter == stc.wxSTC_P_OPERATOR:
braceAtCaret = caretPos braceAtCaret = caretPos
if braceAtCaret >= 0: if braceAtCaret >= 0:
@@ -353,7 +407,7 @@ class Shell(wxStyledTextCtrl):
def OnChar(self, event): def OnChar(self, event):
"""Keypress event handler. """Keypress event handler.
Only receives an event if OnKeyDown calls event.Skip() for Only receives an event if OnKeyDown calls event.Skip() for
the corresponding event.""" the corresponding event."""
@@ -364,7 +418,7 @@ class Shell(wxStyledTextCtrl):
currpos = self.GetCurrentPos() currpos = self.GetCurrentPos()
stoppos = self.promptPosEnd stoppos = self.promptPosEnd
# Return (Enter) needs to be ignored in this handler. # Return (Enter) needs to be ignored in this handler.
if key == WXK_RETURN: if key == wx.WXK_RETURN:
pass pass
elif key in self.autoCompleteKeys: elif key in self.autoCompleteKeys:
# Usually the dot (period) key activates auto completion. # Usually the dot (period) key activates auto completion.
@@ -399,12 +453,12 @@ class Shell(wxStyledTextCtrl):
endpos = self.GetTextLength() endpos = self.GetTextLength()
selecting = self.GetSelectionStart() != self.GetSelectionEnd() selecting = self.GetSelectionStart() != self.GetSelectionEnd()
# Return (Enter) is used to submit a command to the interpreter. # Return (Enter) is used to submit a command to the interpreter.
if not controlDown and key == WXK_RETURN: if not controlDown and key == wx.WXK_RETURN:
if self.AutoCompActive(): self.AutoCompCancel() if self.AutoCompActive(): self.AutoCompCancel()
if self.CallTipActive(): self.CallTipCancel() if self.CallTipActive(): self.CallTipCancel()
self.processLine() self.processLine()
# Ctrl+Return (Cntrl+Enter) is used to insert a line break. # Ctrl+Return (Cntrl+Enter) is used to insert a line break.
elif controlDown and key == WXK_RETURN: elif controlDown and key == wx.WXK_RETURN:
if self.AutoCompActive(): self.AutoCompCancel() if self.AutoCompActive(): self.AutoCompCancel()
if self.CallTipActive(): self.CallTipCancel() if self.CallTipActive(): self.CallTipCancel()
if currpos == endpos: if currpos == endpos:
@@ -418,25 +472,25 @@ class Shell(wxStyledTextCtrl):
elif controlDown and altDown: elif controlDown and altDown:
event.Skip() event.Skip()
# Clear the current, unexecuted command. # Clear the current, unexecuted command.
elif key == WXK_ESCAPE: elif key == wx.WXK_ESCAPE:
if self.CallTipActive(): if self.CallTipActive():
event.Skip() event.Skip()
else: else:
self.clearCommand() self.clearCommand()
# Cut to the clipboard. # Cut to the clipboard.
elif (controlDown and key in (ord('X'), ord('x'))) \ elif (controlDown and key in (ord('X'), ord('x'))) \
or (shiftDown and key == WXK_DELETE): or (shiftDown and key == wx.WXK_DELETE):
self.Cut() self.Cut()
# Copy to the clipboard. # Copy to the clipboard.
elif controlDown and not shiftDown \ elif controlDown and not shiftDown \
and key in (ord('C'), ord('c'), WXK_INSERT): and key in (ord('C'), ord('c'), wx.WXK_INSERT):
self.Copy() self.Copy()
# Copy to the clipboard, including prompts. # Copy to the clipboard, including prompts.
elif controlDown and shiftDown \ elif controlDown and shiftDown \
and key in (ord('C'), ord('c'), WXK_INSERT): and key in (ord('C'), ord('c'), wx.WXK_INSERT):
self.CopyWithPrompts() self.CopyWithPrompts()
# Home needs to be aware of the prompt. # Home needs to be aware of the prompt.
elif key == WXK_HOME: elif key == wx.WXK_HOME:
home = self.promptPosEnd home = self.promptPosEnd
if currpos > home: if currpos > home:
self.SetCurrentPos(home) self.SetCurrentPos(home)
@@ -455,41 +509,41 @@ class Shell(wxStyledTextCtrl):
# Paste from the clipboard. # Paste from the clipboard.
elif (controlDown and not shiftDown \ elif (controlDown and not shiftDown \
and key in (ord('V'), ord('v'))) \ and key in (ord('V'), ord('v'))) \
or (shiftDown and not controlDown and key == WXK_INSERT): or (shiftDown and not controlDown and key == wx.WXK_INSERT):
self.Paste() self.Paste()
# Paste from the clipboard, run commands. # Paste from the clipboard, run commands.
elif controlDown and shiftDown \ elif controlDown and shiftDown \
and key in (ord('V'), ord('v')): and key in (ord('V'), ord('v')):
self.PasteAndRun() self.PasteAndRun()
# Replace with the previous command from the history buffer. # Replace with the previous command from the history buffer.
elif (controlDown and key == WXK_UP) \ elif (controlDown and key == wx.WXK_UP) \
or (altDown and key in (ord('P'), ord('p'))): or (altDown and key in (ord('P'), ord('p'))):
self.OnHistoryReplace(step=+1) self.OnHistoryReplace(step=+1)
# Replace with the next command from the history buffer. # Replace with the next command from the history buffer.
elif (controlDown and key == WXK_DOWN) \ elif (controlDown and key == wx.WXK_DOWN) \
or (altDown and key in (ord('N'), ord('n'))): or (altDown and key in (ord('N'), ord('n'))):
self.OnHistoryReplace(step=-1) self.OnHistoryReplace(step=-1)
# Insert the previous command from the history buffer. # Insert the previous command from the history buffer.
elif (shiftDown and key == WXK_UP) and self.CanEdit(): elif (shiftDown and key == wx.WXK_UP) and self.CanEdit():
self.OnHistoryInsert(step=+1) self.OnHistoryInsert(step=+1)
# Insert the next command from the history buffer. # Insert the next command from the history buffer.
elif (shiftDown and key == WXK_DOWN) and self.CanEdit(): elif (shiftDown and key == wx.WXK_DOWN) and self.CanEdit():
self.OnHistoryInsert(step=-1) self.OnHistoryInsert(step=-1)
# Search up the history for the text in front of the cursor. # Search up the history for the text in front of the cursor.
elif key == WXK_F8: elif key == wx.WXK_F8:
self.OnHistorySearch() self.OnHistorySearch()
# Don't backspace over the latest non-continuation prompt. # Don't backspace over the latest non-continuation prompt.
elif key == WXK_BACK: elif key == wx.WXK_BACK:
if selecting and self.CanEdit(): if selecting and self.CanEdit():
event.Skip() event.Skip()
elif currpos > self.promptPosEnd: elif currpos > self.promptPosEnd:
event.Skip() event.Skip()
# Only allow these keys after the latest prompt. # Only allow these keys after the latest prompt.
elif key in (WXK_TAB, WXK_DELETE): elif key in (wx.WXK_TAB, wx.WXK_DELETE):
if self.CanEdit(): if self.CanEdit():
event.Skip() event.Skip()
# Don't toggle between insert mode and overwrite mode. # Don't toggle between insert mode and overwrite mode.
elif key == WXK_INSERT: elif key == wx.WXK_INSERT:
pass pass
# Don't allow line deletion. # Don't allow line deletion.
elif controlDown and key in (ord('L'), ord('l')): elif controlDown and key in (ord('L'), ord('l')):
@@ -590,7 +644,7 @@ class Shell(wxStyledTextCtrl):
# The user hit ENTER and we need to decide what to do. They could be # The user hit ENTER and we need to decide what to do. They could be
# sitting on any line in the shell. # sitting on any line in the shell.
thepos = self.GetCurrentPos() thepos = self.GetCurrentPos()
startpos = self.promptPosEnd startpos = self.promptPosEnd
endpos = self.GetTextLength() endpos = self.GetTextLength()
# If they hit RETURN inside the current command, execute the command. # If they hit RETURN inside the current command, execute the command.
@@ -685,12 +739,14 @@ class Shell(wxStyledTextCtrl):
elif text[:ps2size] == ps2: elif text[:ps2size] == ps2:
text = text[ps2size:] text = text[ps2size:]
return text return text
def push(self, command): def push(self, command):
"""Send command to the interpreter for execution.""" """Send command to the interpreter for execution."""
self.write(os.linesep) self.write(os.linesep)
busy = wxBusyCursor() busy = wx.wxBusyCursor()
self.waiting = True
self.more = self.interp.push(command) self.more = self.interp.push(command)
self.waiting = False
del busy del busy
if not self.more: if not self.more:
self.addHistory(command.rstrip()) self.addHistory(command.rstrip())
@@ -765,13 +821,34 @@ class Shell(wxStyledTextCtrl):
self.prompt() self.prompt()
try: try:
while not reader.input: while not reader.input:
wxYield() time.sleep(0.1) # Free up the CPU.
wx.wxYield()
input = reader.input input = reader.input
finally: finally:
reader.input = '' reader.input = ''
reader.isreading = 0 reader.isreading = 0
return input return input
def readlines(self):
"""Replacement for stdin.readlines()."""
lines = []
input = ''
reader = self.reader
reader.isreading = 1
try:
while lines[-1:] != ['\n']:
self.prompt()
while not reader.input:
time.sleep(0.1) # Free up the CPU.
wx.wxYield()
input = reader.input
lines.append(input)
reader.input = ''
finally:
reader.input = ''
reader.isreading = 0
return lines
def raw_input(self, prompt=''): def raw_input(self, prompt=''):
"""Return string based on user input.""" """Return string based on user input."""
if prompt: if prompt:
@@ -780,10 +857,10 @@ class Shell(wxStyledTextCtrl):
def ask(self, prompt='Please enter your response:'): def ask(self, prompt='Please enter your response:'):
"""Get response from the user using a dialog box.""" """Get response from the user using a dialog box."""
dialog = wxTextEntryDialog(None, prompt, \ dialog = wx.wxTextEntryDialog(None, prompt,
'Input Dialog (Raw)', '') 'Input Dialog (Raw)', '')
try: try:
if dialog.ShowModal() == wxID_OK: if dialog.ShowModal() == wx.wxID_OK:
text = dialog.GetValue() text = dialog.GetValue()
return text return text
finally: finally:
@@ -803,11 +880,11 @@ class Shell(wxStyledTextCtrl):
>>> shell.run('print "this"') >>> shell.run('print "this"')
>>> print "this" >>> print "this"
this this
>>> >>>
""" """
# Go to the very bottom of the text. # Go to the very bottom of the text.
endpos = self.GetTextLength() endpos = self.GetTextLength()
self.SetCurrentPos(endpos) self.SetCurrentPos(endpos)
command = command.rstrip() command = command.rstrip()
if prompt: self.prompt() if prompt: self.prompt()
if verbose: self.write(command) if verbose: self.write(command)
@@ -828,9 +905,9 @@ class Shell(wxStyledTextCtrl):
def autoCompleteShow(self, command): def autoCompleteShow(self, command):
"""Display auto-completion popup list.""" """Display auto-completion popup list."""
list = self.interp.getAutoCompleteList(command, list = self.interp.getAutoCompleteList(command,
includeMagic=self.autoCompleteIncludeMagic, includeMagic=self.autoCompleteIncludeMagic,
includeSingle=self.autoCompleteIncludeSingle, includeSingle=self.autoCompleteIncludeSingle,
includeDouble=self.autoCompleteIncludeDouble) includeDouble=self.autoCompleteIncludeDouble)
if list: if list:
options = ' '.join(list) options = ' '.join(list)
@@ -898,7 +975,7 @@ class Shell(wxStyledTextCtrl):
def CanPaste(self): def CanPaste(self):
"""Return true if a paste should succeed.""" """Return true if a paste should succeed."""
if self.CanEdit() and wxStyledTextCtrl.CanPaste(self): if self.CanEdit() and stc.wxStyledTextCtrl.CanPaste(self):
return 1 return 1
else: else:
return 0 return 0
@@ -929,26 +1006,28 @@ class Shell(wxStyledTextCtrl):
command = command.replace(os.linesep + sys.ps2, os.linesep) command = command.replace(os.linesep + sys.ps2, os.linesep)
command = command.replace(os.linesep + sys.ps1, os.linesep) command = command.replace(os.linesep + sys.ps1, os.linesep)
command = self.lstripPrompt(text=command) command = self.lstripPrompt(text=command)
data = wxTextDataObject(command) data = wx.wxTextDataObject(command)
if wxTheClipboard.Open(): if wx.wxTheClipboard.Open():
wxTheClipboard.SetData(data) wx.wxTheClipboard.UsePrimarySelection(False)
wxTheClipboard.Close() wx.wxTheClipboard.SetData(data)
wx.wxTheClipboard.Close()
def CopyWithPrompts(self): def CopyWithPrompts(self):
"""Copy selection, including prompts, and place it on the clipboard.""" """Copy selection, including prompts, and place it on the clipboard."""
if self.CanCopy(): if self.CanCopy():
command = self.GetSelectedText() command = self.GetSelectedText()
data = wxTextDataObject(command) data = wx.wxTextDataObject(command)
if wxTheClipboard.Open(): if wx.wxTheClipboard.Open():
wxTheClipboard.SetData(data) wx.wxTheClipboard.UsePrimarySelection(False)
wxTheClipboard.Close() wx.wxTheClipboard.SetData(data)
wx.wxTheClipboard.Close()
def Paste(self): def Paste(self):
"""Replace selection with clipboard contents.""" """Replace selection with clipboard contents."""
if self.CanPaste() and wxTheClipboard.Open(): if self.CanPaste() and wx.wxTheClipboard.Open():
if wxTheClipboard.IsSupported(wxDataFormat(wxDF_TEXT)): if wx.wxTheClipboard.IsSupported(wx.wxDataFormat(wx.wxDF_TEXT)):
data = wxTextDataObject() data = wx.wxTextDataObject()
if wxTheClipboard.GetData(data): if wx.wxTheClipboard.GetData(data):
self.ReplaceSelection('') self.ReplaceSelection('')
command = data.GetText() command = data.GetText()
command = command.rstrip() command = command.rstrip()
@@ -958,14 +1037,14 @@ class Shell(wxStyledTextCtrl):
command = command.replace(os.linesep, '\n') command = command.replace(os.linesep, '\n')
command = command.replace('\n', os.linesep + sys.ps2) command = command.replace('\n', os.linesep + sys.ps2)
self.write(command) self.write(command)
wxTheClipboard.Close() wx.wxTheClipboard.Close()
def PasteAndRun(self): def PasteAndRun(self):
"""Replace selection with clipboard contents, run commands.""" """Replace selection with clipboard contents, run commands."""
if wxTheClipboard.Open(): if wx.wxTheClipboard.Open():
if wxTheClipboard.IsSupported(wxDataFormat(wxDF_TEXT)): if wx.wxTheClipboard.IsSupported(wx.wxDataFormat(wx.wxDF_TEXT)):
data = wxTextDataObject() data = wx.wxTextDataObject()
if wxTheClipboard.GetData(data): if wx.wxTheClipboard.GetData(data):
endpos = self.GetTextLength() endpos = self.GetTextLength()
self.SetCurrentPos(endpos) self.SetCurrentPos(endpos)
startpos = self.promptPosEnd startpos = self.promptPosEnd
@@ -994,11 +1073,11 @@ class Shell(wxStyledTextCtrl):
command += '\n' command += '\n'
command += line command += line
commands.append(command) commands.append(command)
for command in commands: for command in commands:
command = command.replace('\n', os.linesep + sys.ps2) command = command.replace('\n', os.linesep + sys.ps2)
self.write(command) self.write(command)
self.processLine() self.processLine()
wxTheClipboard.Close() wx.wxTheClipboard.Close()
def wrap(self, wrap=1): def wrap(self, wrap=1):
"""Sets whether text is word wrapped.""" """Sets whether text is word wrapped."""
@@ -1009,214 +1088,8 @@ class Shell(wxStyledTextCtrl):
def zoom(self, points=0): def zoom(self, points=0):
"""Set the zoom level. """Set the zoom level.
This number of points is added to the size of all fonts. This number of points is added to the size of all fonts.
It may be positive to magnify or negative to reduce.""" It may be positive to magnify or negative to reduce."""
self.SetZoom(points) self.SetZoom(points)
wxID_SELECTALL = NewId() # This *should* be defined by wxPython.
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 ShellMenu:
"""Mixin class to add standard menu items."""
def createMenus(self):
m = self.fileMenu = wxMenu()
m.AppendSeparator()
m.Append(wxID_EXIT, 'E&xit', 'Exit PyCrust')
m = self.editMenu = wxMenu()
m.Append(wxID_UNDO, '&Undo \tCtrl+Z', 'Undo the last action')
m.Append(wxID_REDO, '&Redo \tCtrl+Y', 'Redo the last undone action')
m.AppendSeparator()
m.Append(wxID_CUT, 'Cu&t \tCtrl+X', 'Cut the selection')
m.Append(wxID_COPY, '&Copy \tCtrl+C', 'Copy the selection')
m.Append(wxID_PASTE, '&Paste \tCtrl+V', 'Paste')
m.AppendSeparator()
m.Append(wxID_CLEAR, 'Cle&ar', 'Delete the selection')
m.Append(wxID_SELECTALL, 'Select A&ll', 'Select all text')
m = self.autocompMenu = wxMenu()
m.Append(ID_AUTOCOMP_SHOW, 'Show Auto Completion', \
'Show auto completion during dot syntax', 1)
m.Append(ID_AUTOCOMP_INCLUDE_MAGIC, 'Include Magic Attributes', \
'Include attributes visible to __getattr__ and __setattr__', 1)
m.Append(ID_AUTOCOMP_INCLUDE_SINGLE, 'Include Single Underscores', \
'Include attibutes prefixed by a single underscore', 1)
m.Append(ID_AUTOCOMP_INCLUDE_DOUBLE, 'Include Double Underscores', \
'Include attibutes prefixed by a double underscore', 1)
m = self.calltipsMenu = wxMenu()
m.Append(ID_CALLTIPS_SHOW, 'Show Call Tips', \
'Show call tips with argument specifications', 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_EXIT, self.OnExit)
EVT_MENU(self, wxID_UNDO, self.OnUndo)
EVT_MENU(self, wxID_REDO, self.OnRedo)
EVT_MENU(self, wxID_CUT, self.OnCut)
EVT_MENU(self, wxID_COPY, self.OnCopy)
EVT_MENU(self, wxID_PASTE, self.OnPaste)
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_CUT, 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.Undo()
def OnRedo(self, event):
self.shell.Redo()
def OnCut(self, event):
self.shell.Cut()
def OnCopy(self, event):
self.shell.Copy()
def OnPaste(self, event):
self.shell.Paste()
def OnClear(self, event):
self.shell.Clear()
def OnSelectAll(self, event):
self.shell.SelectAll()
def OnAbout(self, event):
"""Display an About PyCrust window."""
import sys
title = 'About PyCrust'
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.\n\n' + \
'Shell Revision: %s\n' % self.shell.revision + \
'Interpreter Revision: %s\n\n' % self.shell.interp.revision + \
'Python Version: %s\n' % sys.version.split()[0] + \
'wxPython Version: %s\n' % wx.__version__ + \
'Platform: %s\n' % sys.platform
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 current status."""
id = event.GetId()
if id == wxID_UNDO:
event.Enable(self.shell.CanUndo())
elif id == wxID_REDO:
event.Enable(self.shell.CanRedo())
elif id == wxID_CUT:
event.Enable(self.shell.CanCut())
elif id == wxID_COPY:
event.Enable(self.shell.CanCopy())
elif id == wxID_PASTE:
event.Enable(self.shell.CanPaste())
elif id == wxID_CLEAR:
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 ShellFrame(wxFrame, ShellMenu):
"""Frame containing the PyCrust shell component."""
name = 'PyCrust Shell Frame'
revision = __revision__
def __init__(self, parent=None, id=-1, title='PyShell', \
pos=wxDefaultPosition, size=wxDefaultSize, \
style=wxDEFAULT_FRAME_STYLE, locals=None, \
InterpClass=None, *args, **kwds):
"""Create a PyCrust ShellFrame instance."""
wxFrame.__init__(self, parent, id, title, pos, size, style)
intro = 'Welcome To PyCrust %s - The Flakiest Python Shell' % VERSION
intro += '\nSponsored by Orbtech - Your source for Python programming expertise.'
self.CreateStatusBar()
self.SetStatusText(intro.replace('\n', ', '))
import images
self.SetIcon(images.getPyCrustIcon())
self.shell = Shell(parent=self, id=-1, introText=intro, \
locals=locals, InterpClass=InterpClass, \
*args, **kwds)
# Override the shell so that status messages go to the status bar.
self.shell.setStatusText = self.SetStatusText
self.createMenus()
EVT_CLOSE(self, self.OnCloseWindow)
def OnCloseWindow(self, event):
self.shell.destroy()
self.Destroy()

View File

@@ -0,0 +1,213 @@
"""Shell menu mixin shared by shell and crust."""
__author__ = "Patrick K. O'Brien <pobrien@orbtech.com>"
__cvsid__ = "$Id$"
__revision__ = "$Revision$"[11:-2]
from wxPython import wx
import sys
from version import VERSION
True, False = 1, 0
ID_AUTOCOMP = wx.NewId()
ID_AUTOCOMP_SHOW = wx.NewId()
ID_AUTOCOMP_INCLUDE_MAGIC = wx.NewId()
ID_AUTOCOMP_INCLUDE_SINGLE = wx.NewId()
ID_AUTOCOMP_INCLUDE_DOUBLE = wx.NewId()
ID_CALLTIPS = wx.NewId()
ID_CALLTIPS_SHOW = wx.NewId()
ID_COPY_PLUS = wx.NewId()
ID_PASTE_PLUS = wx.NewId()
ID_WRAP = wx.NewId()
class ShellMenu:
"""Mixin class to add standard menu items."""
def createMenus(self):
m = self.fileMenu = wx.wxMenu()
m.AppendSeparator()
m.Append(wx.wxID_EXIT, 'E&xit', 'Exit PyCrust')
m = self.editMenu = wx.wxMenu()
m.Append(wx.wxID_UNDO, '&Undo \tCtrl+Z', 'Undo the last action')
m.Append(wx.wxID_REDO, '&Redo \tCtrl+Y', 'Redo the last undone action')
m.AppendSeparator()
m.Append(wx.wxID_CUT, 'Cu&t \tCtrl+X', 'Cut the selection')
m.Append(wx.wxID_COPY, '&Copy \tCtrl+C', 'Copy the selection - removing prompts')
m.Append(ID_COPY_PLUS, 'Cop&y Plus \tCtrl+Shift+C', 'Copy the selection - retaining prompts')
m.Append(wx.wxID_PASTE, '&Paste \tCtrl+V', 'Paste')
m.Append(ID_PASTE_PLUS, 'Past&e Plus \tCtrl+Shift+V', 'Paste and run commands')
m.AppendSeparator()
m.Append(wx.wxID_CLEAR, 'Cle&ar', 'Delete the selection')
m.Append(wx.wxID_SELECTALL, 'Select A&ll \tCtrl+A', 'Select all text')
m = self.autocompMenu = wx.wxMenu()
m.Append(ID_AUTOCOMP_SHOW, 'Show Auto Completion',
'Show auto completion during dot syntax', 1)
m.Append(ID_AUTOCOMP_INCLUDE_MAGIC, 'Include Magic Attributes',
'Include attributes visible to __getattr__ and __setattr__', 1)
m.Append(ID_AUTOCOMP_INCLUDE_SINGLE, 'Include Single Underscores',
'Include attibutes prefixed by a single underscore', 1)
m.Append(ID_AUTOCOMP_INCLUDE_DOUBLE, 'Include Double Underscores',
'Include attibutes prefixed by a double underscore', 1)
m = self.calltipsMenu = wx.wxMenu()
m.Append(ID_CALLTIPS_SHOW, 'Show Call Tips',
'Show call tips with argument specifications', 1)
m = self.optionsMenu = wx.wxMenu()
m.AppendMenu(ID_AUTOCOMP, '&Auto Completion', self.autocompMenu,
'Auto Completion Options')
m.AppendMenu(ID_CALLTIPS, '&Call Tips', self.calltipsMenu,
'Call Tip Options')
m.Append(ID_WRAP, '&Wrap Lines',
'Wrap lines at right edge', 1)
m = self.helpMenu = wx.wxMenu()
m.AppendSeparator()
m.Append(wx.wxID_ABOUT, '&About...', 'About PyCrust')
b = self.menuBar = wx.wxMenuBar()
b.Append(self.fileMenu, '&File')
b.Append(self.editMenu, '&Edit')
b.Append(self.optionsMenu, '&Options')
b.Append(self.helpMenu, '&Help')
self.SetMenuBar(b)
wx.EVT_MENU(self, wx.wxID_EXIT, self.OnExit)
wx.EVT_MENU(self, wx.wxID_UNDO, self.OnUndo)
wx.EVT_MENU(self, wx.wxID_REDO, self.OnRedo)
wx.EVT_MENU(self, wx.wxID_CUT, self.OnCut)
wx.EVT_MENU(self, wx.wxID_COPY, self.OnCopy)
wx.EVT_MENU(self, ID_COPY_PLUS, self.OnCopyPlus)
wx.EVT_MENU(self, wx.wxID_PASTE, self.OnPaste)
wx.EVT_MENU(self, ID_PASTE_PLUS, self.OnPastePlus)
wx.EVT_MENU(self, wx.wxID_CLEAR, self.OnClear)
wx.EVT_MENU(self, wx.wxID_SELECTALL, self.OnSelectAll)
wx.EVT_MENU(self, wx.wxID_ABOUT, self.OnAbout)
wx.EVT_MENU(self, ID_AUTOCOMP_SHOW,
self.OnAutoCompleteShow)
wx.EVT_MENU(self, ID_AUTOCOMP_INCLUDE_MAGIC,
self.OnAutoCompleteIncludeMagic)
wx.EVT_MENU(self, ID_AUTOCOMP_INCLUDE_SINGLE,
self.OnAutoCompleteIncludeSingle)
wx.EVT_MENU(self, ID_AUTOCOMP_INCLUDE_DOUBLE,
self.OnAutoCompleteIncludeDouble)
wx.EVT_MENU(self, ID_CALLTIPS_SHOW,
self.OnCallTipsShow)
wx.EVT_MENU(self, ID_WRAP, self.OnWrap)
wx.EVT_UPDATE_UI(self, wx.wxID_UNDO, self.OnUpdateMenu)
wx.EVT_UPDATE_UI(self, wx.wxID_REDO, self.OnUpdateMenu)
wx.EVT_UPDATE_UI(self, wx.wxID_CUT, self.OnUpdateMenu)
wx.EVT_UPDATE_UI(self, wx.wxID_COPY, self.OnUpdateMenu)
wx.EVT_UPDATE_UI(self, ID_COPY_PLUS, self.OnUpdateMenu)
wx.EVT_UPDATE_UI(self, wx.wxID_PASTE, self.OnUpdateMenu)
wx.EVT_UPDATE_UI(self, ID_PASTE_PLUS, self.OnUpdateMenu)
wx.EVT_UPDATE_UI(self, wx.wxID_CLEAR, self.OnUpdateMenu)
wx.EVT_UPDATE_UI(self, ID_AUTOCOMP_SHOW, self.OnUpdateMenu)
wx.EVT_UPDATE_UI(self, ID_AUTOCOMP_INCLUDE_MAGIC, self.OnUpdateMenu)
wx.EVT_UPDATE_UI(self, ID_AUTOCOMP_INCLUDE_SINGLE, self.OnUpdateMenu)
wx.EVT_UPDATE_UI(self, ID_AUTOCOMP_INCLUDE_DOUBLE, self.OnUpdateMenu)
wx.EVT_UPDATE_UI(self, ID_CALLTIPS_SHOW, self.OnUpdateMenu)
wx.EVT_UPDATE_UI(self, ID_WRAP, self.OnUpdateMenu)
def OnExit(self, event):
self.Close(True)
def OnUndo(self, event):
self.shell.Undo()
def OnRedo(self, event):
self.shell.Redo()
def OnCut(self, event):
self.shell.Cut()
def OnCopy(self, event):
self.shell.Copy()
def OnCopyPlus(self, event):
self.shell.CopyWithPrompts()
def OnPaste(self, event):
self.shell.Paste()
def OnPastePlus(self, event):
self.shell.PasteAndRun()
def OnClear(self, event):
self.shell.Clear()
def OnSelectAll(self, event):
self.shell.SelectAll()
def OnAbout(self, event):
"""Display an About PyCrust window."""
title = 'About PyCrust'
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.\n\n' + \
'Shell Revision: %s\n' % self.shell.revision + \
'Interpreter Revision: %s\n\n' % self.shell.interp.revision + \
'Python Version: %s\n' % sys.version.split()[0] + \
'wxPython Version: %s\n' % wx.__version__ + \
'Platform: %s\n' % sys.platform
dialog = wx.wxMessageDialog(self, text, title, wx.wxOK | wx.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 OnWrap(self, event):
self.shell.SetWrapMode(event.IsChecked())
def OnUpdateMenu(self, event):
"""Update menu items based on current status."""
id = event.GetId()
if id == wx.wxID_UNDO:
event.Enable(self.shell.CanUndo())
elif id == wx.wxID_REDO:
event.Enable(self.shell.CanRedo())
elif id == wx.wxID_CUT:
event.Enable(self.shell.CanCut())
elif id == wx.wxID_COPY:
event.Enable(self.shell.CanCopy())
elif id == ID_COPY_PLUS:
event.Enable(self.shell.CanCopy())
elif id == wx.wxID_PASTE:
event.Enable(self.shell.CanPaste())
elif id == ID_PASTE_PLUS:
event.Enable(self.shell.CanPaste())
elif id == wx.wxID_CLEAR:
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)
elif id == ID_WRAP:
event.Check(self.shell.GetWrapMode())

View File

@@ -6,5 +6,5 @@ __author__ = "Patrick K. O'Brien <pobrien@orbtech.com>"
__cvsid__ = "$Id$" __cvsid__ = "$Id$"
__revision__ = "$Revision$"[11:-2] __revision__ = "$Revision$"[11:-2]
VERSION = '0.7.2' VERSION = '0.8'