wxContextMenuEvent, wxContextHelp, wxContextHelpButton, wxTipWindow,
and a demo to show them in action.
-Deprecated PyShell and PyShellWindow, added a snapshot of PyCrust.
+Deprecated PyShell and PyShellWindow, added a snapshot of PyCrust (see
+http://sourceforge.net/projects/pycrust/. )
Added the new virtual list capabilities to wxListCtrl.
Added wxNativeFontInfo and wxFontMapper.
+
+
2.3.1
-----
Added EVT_GRID_EDITOR_CREATED and wxGridEditorCreatedEvent so the user
PyObject * _resultobj;
wxString * _result;
wxStyledTextCtrl * _arg0;
- int * _arg1 = (int *) NULL;
+ int * _arg1;
int temp;
PyObject * _argo0 = 0;
char *_kwnames[] = { "self", NULL };
return _resultobj;
}
-#define wxStyledTextCtrl_SetFocus(_swigobj,_swigarg0) (_swigobj->SetFocus(_swigarg0))
-static PyObject *_wrap_wxStyledTextCtrl_SetFocus(PyObject *self, PyObject *args, PyObject *kwargs) {
+#define wxStyledTextCtrl_SetSTCFocus(_swigobj,_swigarg0) (_swigobj->SetSTCFocus(_swigarg0))
+static PyObject *_wrap_wxStyledTextCtrl_SetSTCFocus(PyObject *self, PyObject *args, PyObject *kwargs) {
PyObject * _resultobj;
wxStyledTextCtrl * _arg0;
bool _arg1;
char *_kwnames[] = { "self","focus", NULL };
self = self;
- if(!PyArg_ParseTupleAndKeywords(args,kwargs,"Oi:wxStyledTextCtrl_SetFocus",_kwnames,&_argo0,&tempbool1))
+ if(!PyArg_ParseTupleAndKeywords(args,kwargs,"Oi:wxStyledTextCtrl_SetSTCFocus",_kwnames,&_argo0,&tempbool1))
return NULL;
if (_argo0) {
if (_argo0 == Py_None) { _arg0 = NULL; }
else if (SWIG_GetPtrObj(_argo0,(void **) &_arg0,"_wxStyledTextCtrl_p")) {
- PyErr_SetString(PyExc_TypeError,"Type error in argument 1 of wxStyledTextCtrl_SetFocus. Expected _wxStyledTextCtrl_p.");
+ PyErr_SetString(PyExc_TypeError,"Type error in argument 1 of wxStyledTextCtrl_SetSTCFocus. Expected _wxStyledTextCtrl_p.");
return NULL;
}
}
_arg1 = (bool ) tempbool1;
{
wxPy_BEGIN_ALLOW_THREADS;
- wxStyledTextCtrl_SetFocus(_arg0,_arg1);
+ wxStyledTextCtrl_SetSTCFocus(_arg0,_arg1);
wxPy_END_ALLOW_THREADS;
} Py_INCREF(Py_None);
return _resultobj;
}
-#define wxStyledTextCtrl_GetFocus(_swigobj) (_swigobj->GetFocus())
-static PyObject *_wrap_wxStyledTextCtrl_GetFocus(PyObject *self, PyObject *args, PyObject *kwargs) {
+#define wxStyledTextCtrl_GetSTCFocus(_swigobj) (_swigobj->GetSTCFocus())
+static PyObject *_wrap_wxStyledTextCtrl_GetSTCFocus(PyObject *self, PyObject *args, PyObject *kwargs) {
PyObject * _resultobj;
bool _result;
wxStyledTextCtrl * _arg0;
char *_kwnames[] = { "self", NULL };
self = self;
- if(!PyArg_ParseTupleAndKeywords(args,kwargs,"O:wxStyledTextCtrl_GetFocus",_kwnames,&_argo0))
+ if(!PyArg_ParseTupleAndKeywords(args,kwargs,"O:wxStyledTextCtrl_GetSTCFocus",_kwnames,&_argo0))
return NULL;
if (_argo0) {
if (_argo0 == Py_None) { _arg0 = NULL; }
else if (SWIG_GetPtrObj(_argo0,(void **) &_arg0,"_wxStyledTextCtrl_p")) {
- PyErr_SetString(PyExc_TypeError,"Type error in argument 1 of wxStyledTextCtrl_GetFocus. Expected _wxStyledTextCtrl_p.");
+ PyErr_SetString(PyExc_TypeError,"Type error in argument 1 of wxStyledTextCtrl_GetSTCFocus. Expected _wxStyledTextCtrl_p.");
return NULL;
}
}
{
wxPy_BEGIN_ALLOW_THREADS;
- _result = (bool )wxStyledTextCtrl_GetFocus(_arg0);
+ _result = (bool )wxStyledTextCtrl_GetSTCFocus(_arg0);
wxPy_END_ALLOW_THREADS;
} _resultobj = Py_BuildValue("i",_result);
{ "wxStyledTextCtrl_SetMouseDownCaptures", (PyCFunction) _wrap_wxStyledTextCtrl_SetMouseDownCaptures, METH_VARARGS | METH_KEYWORDS },
{ "wxStyledTextCtrl_GetStatus", (PyCFunction) _wrap_wxStyledTextCtrl_GetStatus, METH_VARARGS | METH_KEYWORDS },
{ "wxStyledTextCtrl_SetStatus", (PyCFunction) _wrap_wxStyledTextCtrl_SetStatus, METH_VARARGS | METH_KEYWORDS },
- { "wxStyledTextCtrl_GetFocus", (PyCFunction) _wrap_wxStyledTextCtrl_GetFocus, METH_VARARGS | METH_KEYWORDS },
- { "wxStyledTextCtrl_SetFocus", (PyCFunction) _wrap_wxStyledTextCtrl_SetFocus, METH_VARARGS | METH_KEYWORDS },
+ { "wxStyledTextCtrl_GetSTCFocus", (PyCFunction) _wrap_wxStyledTextCtrl_GetSTCFocus, METH_VARARGS | METH_KEYWORDS },
+ { "wxStyledTextCtrl_SetSTCFocus", (PyCFunction) _wrap_wxStyledTextCtrl_SetSTCFocus, METH_VARARGS | METH_KEYWORDS },
{ "wxStyledTextCtrl_GetModEventMask", (PyCFunction) _wrap_wxStyledTextCtrl_GetModEventMask, METH_VARARGS | METH_KEYWORDS },
{ "wxStyledTextCtrl_ReleaseDocument", (PyCFunction) _wrap_wxStyledTextCtrl_ReleaseDocument, METH_VARARGS | METH_KEYWORDS },
{ "wxStyledTextCtrl_AddRefDocument", (PyCFunction) _wrap_wxStyledTextCtrl_AddRefDocument, METH_VARARGS | METH_KEYWORDS },
{ "_wxChar","_char",0},
{ "_wxCommandEvent","_wxStyledTextEvent",SwigwxStyledTextEventTowxCommandEvent},
{ "_char","_wxChar",0},
+ { "_struct_wxNativeFontInfo","_wxNativeFontInfo",0},
{ "_EBool","_wxCoord",0},
{ "_EBool","_wxPrintQuality",0},
{ "_EBool","_signed_int",0},
{ "_EBool","_int",0},
{ "_EBool","_wxWindowID",0},
{ "_unsigned_long","_long",0},
+ { "_wxNativeFontInfo","_struct_wxNativeFontInfo",0},
{ "_signed_int","_wxCoord",0},
{ "_signed_int","_wxPrintQuality",0},
{ "_signed_int","_EBool",0},
def GetModEventMask(self, *_args, **_kwargs):
val = apply(stc_c.wxStyledTextCtrl_GetModEventMask,(self,) + _args, _kwargs)
return val
- def SetFocus(self, *_args, **_kwargs):
- val = apply(stc_c.wxStyledTextCtrl_SetFocus,(self,) + _args, _kwargs)
+ def SetSTCFocus(self, *_args, **_kwargs):
+ val = apply(stc_c.wxStyledTextCtrl_SetSTCFocus,(self,) + _args, _kwargs)
return val
- def GetFocus(self, *_args, **_kwargs):
- val = apply(stc_c.wxStyledTextCtrl_GetFocus,(self,) + _args, _kwargs)
+ def GetSTCFocus(self, *_args, **_kwargs):
+ val = apply(stc_c.wxStyledTextCtrl_GetSTCFocus,(self,) + _args, _kwargs)
return val
def SetStatus(self, *_args, **_kwargs):
val = apply(stc_c.wxStyledTextCtrl_SetStatus,(self,) + _args, _kwargs)
_treeList = [
('New since last release', ['ContextHelp',
'PyCrust',
+ 'PyCrustWithFilling',
'VirtualListCtrl',
'wxListCtrl',
'TablePrint',
--- /dev/null
+
+from wxPython.wx import *
+from wxPython.lib.PyCrust import shell, version, filling
+
+
+#----------------------------------------------------------------------
+
+intro = 'Welcome To PyCrust %s - The Flakiest Python Shell' % version.VERSION
+
+def runTest(frame, nb, log):
+ win = wxSplitterWindow(nb, -1, size=(640, 480))
+ shellWin = shell.Shell(win, -1, introText=intro)
+ fillingWin = filling.Filling(win, -1, size=(640, 480),
+ ingredients=shellWin.interp.locals)
+ win.SplitHorizontally(shellWin, fillingWin)
+ return win
+
+#----------------------------------------------------------------------
+
+overview = filling.__doc__
print "GetStyledText(98, 104): ", repr(ed.GetStyledText(98, 104)), len(ed.GetStyledText(98, 104))
print
print "GetCurLine(): ", repr(ed.GetCurLine())
+ ed.GotoPos(5)
+ print "GetCurLine(): ", repr(ed.GetCurLine())
print
print "GetLine(1): ", repr(ed.GetLine(1))
print
# flags and values that affect this script
#----------------------------------------------------------------------
-VERSION = "2.3.2b1"
+VERSION = "2.3.2b2"
DESCRIPTION = "Cross platform GUI toolkit for Python"
AUTHOR = "Robin Dunn"
AUTHOR_EMAIL = "Robin Dunn <robin@alldunn.com>"
-ver = '2.3.2b1'
+ver = '2.3.2b2'
#!/usr/bin/env python
-"""PyCrust is a python shell application.
-"""
+"""PyCrust is a python shell and namespace browser application."""
__author__ = "Patrick K. O'Brien <pobrien@orbtech.com>"
__cvsid__ = "$Id$"
__version__ = "$Revision$"[11:-2]
from wxPython.wx import *
+from crust import CrustFrame
-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):
- """Main window for the PyCrust application."""
- 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
- 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 interpreter.
- locals = {'__app__': 'PyCrust Application'}
- self.shell = Shell(parent=self, id=-1, introText=intro, locals=locals)
- # Override the shell so that status messages go to the status bar.
- self.shell.setStatusText = self.SetStatusText
-
- def createMenus(self):
- m = self.fileMenu = wxMenu()
- m.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 \tDel', 'Delete the selection')
- m.Append(wxID_SELECTALL, 'Select A&ll \tCtrl+A', 'Select all text')
-
- m = self.autocompMenu = wxMenu()
- m.Append(ID_AUTOCOMP_SHOW, 'Show Auto Completion', \
- 'Show auto completion during dot syntax', checkable=1)
- m.Append(ID_AUTOCOMP_INCLUDE_MAGIC, 'Include Magic Attributes', \
- 'Include attributes visible to __getattr__ and __setattr__', checkable=1)
- m.Append(ID_AUTOCOMP_INCLUDE_SINGLE, 'Include Single Underscores', \
- 'Include attibutes prefixed by a single underscore', checkable=1)
- m.Append(ID_AUTOCOMP_INCLUDE_DOUBLE, 'Include Double Underscores', \
- 'Include attibutes prefixed by a double underscore', checkable=1)
-
- m = self.calltipsMenu = wxMenu()
- m.Append(ID_CALLTIPS_SHOW, 'Show Call Tips', \
- 'Show call tips with argument specifications', checkable=1)
-
- m = self.optionsMenu = wxMenu()
- m.AppendMenu(ID_AUTOCOMP, '&Auto Completion', self.autocompMenu, \
- 'Auto Completion Options')
- m.AppendMenu(ID_CALLTIPS, '&Call Tips', self.calltipsMenu, \
- 'Call Tip Options')
-
- m = self.helpMenu = wxMenu()
- m.AppendSeparator()
- m.Append(wxID_ABOUT, '&About...', 'About PyCrust')
-
- b = self.menuBar = wxMenuBar()
- b.Append(self.fileMenu, '&File')
- b.Append(self.editMenu, '&Edit')
- b.Append(self.optionsMenu, '&Options')
- b.Append(self.helpMenu, '&Help')
- self.SetMenuBar(b)
-
- EVT_MENU(self, wxID_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."""
- 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' % 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 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 App(wxApp):
+ """PyCrust standalone application."""
+
def OnInit(self):
- parent = None
- id = -1
- title = 'PyCrust'
- self.frame = Frame(parent, id, title)
- self.frame.Show(true)
- self.SetTopWindow(self.frame)
+ locals = {'__app__': 'PyCrust Standalone Application'}
+ self.crustFrame = CrustFrame(locals=locals)
+ self.crustFrame.Show(true)
+ # Set focus to the shell editor.
+ self.crustFrame.crust.shell.SetFocus()
+ self.SetTopWindow(self.crustFrame)
+ # Add the application object to the sys module's namespace.
+ # This allows a shell user to do:
+ # >>> import sys
+ # >>> sys.application.whatever
+ import sys
+ sys.application = self
return true
def main():
- import sys
application = App(0)
- # Add the application object to the sys module's namespace.
- # This allows a shell user to do:
- # >>> import sys
- # >>> sys.application.whatever
- sys.application = application
application.MainLoop()
if __name__ == '__main__':
main()
+
--- /dev/null
+#!/usr/bin/env python
+"""PyFilling is a python namespace inspection application."""
+
+__author__ = "Patrick K. O'Brien <pobrien@orbtech.com>"
+__cvsid__ = "$Id$"
+__date__ = "August 21, 2001"
+__version__ = "$Revision$"[11:-2]
+
+# We use this object to get more introspection when run standalone.
+application = None
+
+import filling
+
+# These are imported just to have something interesting to inspect.
+import crust
+import interpreter
+import introspect
+import pseudo
+import shell
+import sys
+from wxPython import wx
+
+
+def main():
+ """Create and run the application."""
+ global application
+ application = filling.App(0)
+ root = application.fillingFrame.filling.fillingTree.root
+ application.fillingFrame.filling.fillingTree.Expand(root)
+ application.MainLoop()
+
+
+if __name__ == '__main__':
+ main()
+
--- /dev/null
+#!/usr/bin/env python
+"""PyShell is a python shell application."""
+
+__author__ = "Patrick K. O'Brien <pobrien@orbtech.com>"
+__cvsid__ = "$Id$"
+__date__ = "July 1, 2001"
+__version__ = "$Revision$"[11:-2]
+
+from wxPython.wx import *
+from shell import ShellFrame
+
+
+class App(wxApp):
+ """PyShell standalone application."""
+
+ def OnInit(self):
+ locals = {'__app__': 'PyShell Standalone Application'}
+ self.shellFrame = ShellFrame(locals=locals)
+ self.shellFrame.Show(true)
+ self.SetTopWindow(self.shellFrame)
+ # Add the application object to the sys module's namespace.
+ # This allows a shell user to do:
+ # >>> import sys
+ # >>> sys.application.whatever
+ import sys
+ sys.application = self
+ return true
+
+
+def main():
+ application = App(0)
+ application.MainLoop()
+
+if __name__ == '__main__':
+ main()
+
What is PyCrust?
----------------
+PyCrust is an interactive Python environment written in Python.
+PyCrust components can run standalone or be integrated into other
+development environments and/or other Python applications.
-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.
+PyCrust comes with an interactive Python shell (PyShell), an
+interactive namespace/object tree control (PyFilling) and an
+integrated, split-window combination of the two (PyCrust).
-Where can I get the latest files and join the mailing lists?
-------------------------------------------------------------
+What is PyCrust good for?
+-------------------------
+Have you ever tried to bake a pie without one? Well, you
+shouldn't build a Python program without a PyCrust either.
+
-Latest PyCrust releases:
+Where can I get the latest release of PyCrust?
+------------------------------------------------------------
+The latest PyCrust releases are available at:
http://sourceforge.net/project/showfiles.php?group_id=31263
-PyCrust home page:
-http://pycrust.sourceforge.net/
-SourceForge summary page:
+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 (wxStyledTextCtrl).
+Python is available at http://www.python.org/.
+wxPython is available at http://www.wxpython.org/.
+
+
+Where is the PyCrust project hosted?
+------------------------------------
+At SourceForge, of course. The SourceForge summary page:
http://sourceforge.net/projects/pycrust/
-PyCrust Mailing lists:
+
+Does PyCrust have a mailing list full of wonderful people?
+----------------------------------------------------------
+As a matter of fact, we do. Join the PyCrust mailing lists at:
http://sourceforge.net/mail/?group_id=31263
-What else do I need to use PyCrust?
------------------------------------
+I found a bug in PyCrust, what do I do with it?
+-----------------------------------------------
+You can send it to me at pobrien@orbtech.com, or, preferably,
+submit a bug report on our bug tracker at SourceForge:
+http://sourceforge.net/tracker/?group_id=31263
-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/.
+
+I want a new feature added to PyCrust. Will you do it?
+------------------------------------------------------
+Flattery and money will get you anything. Short of that, you
+can try posting a request on our feature tracker at SourceForge:
+http://sourceforge.net/tracker/?group_id=31263
What is the CVS information for this README file?
-------------------------------------------------
-
$Date$
$Revision$
$Id$
--- /dev/null
+"""PyCrust Crust combines the shell and filling into one control."""
+
+__author__ = "Patrick K. O'Brien <pobrien@orbtech.com>"
+__cvsid__ = "$Id$"
+__date__ = "July 1, 2001"
+__version__ = "$Revision$"[11:-2]
+
+from wxPython.wx import *
+from shell import Shell
+from filling import Filling
+from version import VERSION
+
+
+class Crust(wxSplitterWindow):
+ """PyCrust Crust based on wxSplitterWindow."""
+
+ name = 'PyCrust Crust'
+ revision = __version__
+
+ def __init__(self, parent, id=-1, pos=wxDefaultPosition, \
+ size=wxDefaultSize, style=wxSP_3D, name='Crust Window', \
+ ingredients=None, rootLabel=None, intro='', locals=None, \
+ InterpClass=None, *args, **kwds):
+ """Create a PyCrust Crust instance."""
+ wxSplitterWindow.__init__(self, parent, id, pos, size, style, name)
+ self.shell = Shell(parent=self, introText=intro, \
+ locals=locals, InterpClass=InterpClass, \
+ *args, **kwds)
+ self.filling = Filling(parent=self, \
+ ingredients=self.shell.interp.locals, \
+ rootLabel=rootLabel)
+ """Add 'filling' to the interpreter's locals."""
+ self.shell.interp.locals['filling'] = self.filling
+ self.SplitHorizontally(self.shell, self.filling, 300)
+ # Set focus to the shell editor. Doesn't always work as intended.
+ self.shell.SetFocus()
+
+
+class CrustFrame(wxFrame):
+ """Frame containing all the PyCrust components."""
+
+ name = 'PyCrust Frame'
+ revision = __version__
+
+ def __init__(self, parent=None, id=-1, title='PyCrust', \
+ ingredients=None, rootLabel=None, locals=None, \
+ InterpClass=None, *args, **kwds):
+ """Create a PyCrust CrustFrame instance."""
+ wxFrame.__init__(self, parent, id, title)
+ intro = 'Welcome To PyCrust %s - The Flakiest Python Shell' % VERSION
+ self.CreateStatusBar()
+ self.SetStatusText(intro)
+ if wxPlatform == '__WXMSW__':
+ icon = wxIcon('PyCrust.ico', wxBITMAP_TYPE_ICO)
+ self.SetIcon(icon)
+ self.crust = Crust(parent=self, intro=intro, \
+ ingredients=ingredients, \
+ rootLabel=rootLabel, locals=locals, \
+ InterpClass=InterpClass, *args, **kwds)
+ # Override the filling so that status messages go to the status bar.
+ self.crust.filling.fillingTree.setStatusText = self.SetStatusText
+ # Override the shell so that status messages go to the status bar.
+ self.crust.shell.setStatusText = self.SetStatusText
+ # Set focus to the shell editor. Doesn't always work as intended.
+ self.crust.shell.SetFocus()
+
+
--- /dev/null
+"""PyCrust Filling is the gui tree control through which a user can navigate
+the local namespace or any object."""
+
+__author__ = "Patrick K. O'Brien <pobrien@orbtech.com>"
+__cvsid__ = "$Id$"
+__date__ = "August 21, 2001"
+__version__ = "$Revision$"[11:-2]
+
+from wxPython.wx import *
+from wxPython.stc import *
+from version import VERSION
+import inspect
+import introspect
+import keyword
+import sys
+import types
+
+
+class FillingTree(wxTreeCtrl):
+ """PyCrust FillingTree based on wxTreeCtrl."""
+
+ name = 'PyCrust Filling Tree'
+ revision = __version__
+
+ def __init__(self, parent, id=-1, pos=wxDefaultPosition, \
+ size=wxDefaultSize, style=wxTR_HAS_BUTTONS, \
+ ingredients=None, rootLabel=None):
+ """Create a PyCrust FillingTree instance."""
+ wxTreeCtrl.__init__(self, parent, id, pos, size)
+ if not ingredients:
+ import __main__
+ ingredients = __main__
+ if not rootLabel: rootLabel = 'Ingredients'
+ rootdata = wxTreeItemData(ingredients)
+ self.root = self.AddRoot(rootLabel, -1, -1, rootdata)
+ self.SetItemHasChildren(self.root, self.hasChildren(self.root))
+ EVT_TREE_ITEM_EXPANDING(self, self.GetId(), self.OnItemExpanding)
+ EVT_TREE_ITEM_COLLAPSED(self, self.GetId(), self.OnItemCollapsed)
+ EVT_TREE_SEL_CHANGED(self, self.GetId(), self.OnSelChanged)
+
+ def hasChildren(self, object):
+ """Return true if object has children."""
+ if self.getChildren(object):
+ return true
+ else:
+ return false
+
+ def getChildren(self, object):
+ """Return a dictionary with the attributes or contents of object."""
+ dict = {}
+ objtype = type(object)
+ if objtype is types.DictType:
+ dict = object
+ elif objtype in (types.InstanceType, types.ModuleType):
+ for key in introspect.getAttributeNames(object):
+ # Believe it or not, some attributes can disappear, such as
+ # the exc_traceback attribute of the sys module. So this is
+ # nested in a try block.
+ try:
+ dict[key] = getattr(object, key)
+ except:
+ pass
+ return dict
+
+ def OnItemExpanding(self, event):
+ selection = event.GetItem()
+ if self.IsExpanded(selection):
+ return
+ object = self.GetPyData(selection)
+ children = self.getChildren(object)
+ if not children:
+ return
+ list = children.keys()
+ list.sort()
+ for item in list:
+ itemtext = str(item)
+ # Show string dictionary items with single quotes, except for
+ # the first level of items, which represent the local namespace.
+ if type(object) is types.DictType \
+ and type(item) is types.StringType \
+ and selection != self.root:
+ itemtext = repr(item)
+ child = self.AppendItem(selection, itemtext, -1, -1, \
+ wxTreeItemData(children[item]))
+ self.SetItemHasChildren(child, self.hasChildren(children[item]))
+
+ def OnItemCollapsed(self, event):
+ """Remove all children from the item."""
+ item = event.GetItem()
+ self.DeleteChildren(item)
+
+ def OnSelChanged(self, event):
+ item = event.GetItem()
+ if item == self.root:
+ self.setText('')
+ return
+ object = self.GetPyData(item)
+ text = ''
+ text += self.getFullName(item)
+ text += '\n\nType: ' + str(type(object))[7:-2]
+ value = str(object)
+ if type(object) is types.StringType:
+ value = repr(value)
+ text += '\n\nValue: ' + value
+ if type(object) is types.InstanceType:
+ try:
+ text += '\n\nClass Definition:\n\n' + \
+ inspect.getsource(object.__class__)
+ except:
+ try:
+ text += '\n\n"""' + inspect.getdoc(object).strip() + '"""'
+ except:
+ pass
+ else:
+ try:
+ text += '\n\nSource Code:\n\n' + \
+ inspect.getsource(object)
+ except:
+ try:
+ text += '\n\n"""' + inspect.getdoc(object).strip() + '"""'
+ except:
+ pass
+ self.setText(text)
+
+ def getFullName(self, item, partial=''):
+ """Return a syntactically proper name for item."""
+ parent = self.GetItemParent(item)
+ parentobject = self.GetPyData(parent)
+ name = self.GetItemText(item)
+ # Apply dictionary syntax to dictionary items, except the root
+ # and first level children.
+ if item != self.root and parent != self.root \
+ and type(parentobject) is types.DictType:
+ name = '[' + name + ']'
+ # Apply dot syntax to multipart names.
+ if partial:
+ if partial[0] == '[':
+ name += partial
+ else:
+ name += '.' + partial
+ # Repeat for everything but the root item and first level children.
+ if item != self.root and parent != self.root:
+ name = self.getFullName(parent, partial=name)
+ return name
+
+ def setText(self, text):
+ """Display information about the current selection."""
+
+ # This method will most likely be replaced by the enclosing app
+ # to do something more interesting, like write to a text control.
+ print text
+
+ 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
+
+
+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' : 12,
+ 'lnsize' : 10,
+ 'backcol': '#FFFFFF',
+ }
+
+
+class FillingText(wxStyledTextCtrl):
+ """PyCrust FillingText based on wxStyledTextCtrl."""
+
+ name = 'PyCrust Filling Text'
+ revision = __version__
+
+ def __init__(self, parent, id=-1, pos=wxDefaultPosition, \
+ size=wxDefaultSize, style=wxCLIP_CHILDREN):
+ """Create a PyCrust FillingText instance."""
+ wxStyledTextCtrl.__init__(self, parent, id, pos, size, style)
+ # Configure various defaults and user preferences.
+ self.config()
+
+ def config(self):
+ """Configure shell based on user preferences."""
+ self.SetMarginWidth(1, 0)
+
+ self.SetLexer(wxSTC_LEX_PYTHON)
+ self.SetKeyWords(0, ' '.join(keyword.kwlist))
+
+ self.setStyles(faces)
+ self.SetViewWhiteSpace(0)
+ self.SetTabWidth(4)
+ self.SetUseTabs(0)
+
+ 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)
+
+
+class Filling(wxSplitterWindow):
+ """PyCrust Filling based on wxSplitterWindow."""
+
+ name = 'PyCrust Filling'
+ revision = __version__
+
+ def __init__(self, parent, id=-1, pos=wxDefaultPosition, \
+ size=wxDefaultSize, style=wxSP_3D, name='Filling Window', \
+ ingredients=None, rootLabel=None):
+ """Create a PyCrust Filling instance."""
+ wxSplitterWindow.__init__(self, parent, id, pos, size, style, name)
+ self.fillingTree = FillingTree(parent=self, ingredients=ingredients, \
+ rootLabel=rootLabel)
+ self.fillingText = FillingText(parent=self)
+ self.SplitVertically(self.fillingTree, self.fillingText, 200)
+ # Override the filling so that descriptions go to fillingText.
+ self.fillingTree.setText = self.fillingText.SetText
+ # Select the root item.
+ self.fillingTree.SelectItem(self.fillingTree.root)
+
+
+class FillingFrame(wxFrame):
+ """Frame containing the PyCrust filling, or namespace tree component."""
+
+ name = 'PyCrust Filling Frame'
+ revision = __version__
+
+ def __init__(self, parent=None, id=-1, title='PyFilling', \
+ pos=wxDefaultPosition, size=wxDefaultSize, \
+ style=wxDEFAULT_FRAME_STYLE, ingredients=None, \
+ rootLabel=None):
+ """Create a PyCrust FillingFrame instance."""
+ wxFrame.__init__(self, parent, id, title, pos, size, style)
+ intro = 'Welcome To PyFilling - The Tastiest Namespace Inspector'
+ self.CreateStatusBar()
+ self.SetStatusText(intro)
+ if wxPlatform == '__WXMSW__':
+ icon = wxIcon('PyCrust.ico', wxBITMAP_TYPE_ICO)
+ self.SetIcon(icon)
+ self.filling = Filling(parent=self, ingredients=ingredients, \
+ rootLabel=rootLabel)
+ # Override the filling so that status messages go to the status bar.
+ self.filling.fillingTree.setStatusText = self.SetStatusText
+
+
+class App(wxApp):
+ """PyFilling standalone application."""
+
+ def OnInit(self):
+ self.fillingFrame = FillingFrame()
+ self.fillingFrame.Show(true)
+ self.SetTopWindow(self.fillingFrame)
+ return true
+
+
-"""PyCrust Interpreter executes Python commands.
-"""
+"""PyCrust Interpreter executes Python commands."""
__author__ = "Patrick K. O'Brien <pobrien@orbtech.com>"
__cvsid__ = "$Id$"
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,
+
+ 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)
__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)
+ self.introText = 'Python %s on %s%s%s' % \
+ (sys.version, sys.platform, os.linesep, copyright)
try:
sys.ps1
except AttributeError:
The call tip information will be based on the locals namespace."""
return introspect.getCallTip(command, self.locals, *args, **kwds)
+
+class InterpreterAlaCarte(Interpreter):
+ """PyCrustAlaCarte Demo Interpreter."""
+
+ def __init__(self, locals, rawin, stdin, stdout, stderr, \
+ ps1='main prompt', ps2='continuation prompt'):
+ """Create an interactive interpreter object."""
+ Interpreter.__init__(self, locals=locals, rawin=rawin, \
+ stdin=stdin, stdout=stdout, stderr=stderr)
+ sys.ps1 = ps1
+ sys.ps2 = ps2
+
root = getRoot(command, terminator='.')
try:
object = eval(root, locals)
- 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)
+ attributes = getAttributeNames(object, includeMagic, \
+ includeSingle, includeDouble)
return attributes
except:
return []
-def getAttributeNames(object):
+def getAttributeNames(object, includeMagic=1, includeSingle=1, includeDouble=1):
"""Return list of unique attributes, including inherited, for an object."""
attributes = []
dict = {}
- # Remove duplicates from the attribute list.
+ if includeMagic:
+ try: attributes += object._getAttributeNames()
+ except: pass
+ # Get all attribute names, removing duplicates from the attribute list.
for item in getAllAttributeNames(object):
dict[item] = None
attributes += dict.keys()
attributes.sort()
+ 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
def getAllAttributeNames(object):
pieces = command.split(terminator)
if len(pieces) > 1:
command = terminator.join(pieces[:-1])
- if command in ("''", '""', '""""""', '[]', '()', '{}'):
+ if len(command) == 0:
+ root = ''
+ elif command in ("''", '""', '""""""', '[]', '()', '{}'):
# Let empty type delimiter pairs go through.
root = command
else:
-"""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.
-"""
+"""The PyCrust Shell is an interactive text control in which a user types in
+commands to be sent to the interpreter. This particular shell is based on
+wxPython's wxStyledTextCtrl. The latest files are always available at the
+SourceForge project page at http://sourceforge.net/projects/pycrust/."""
__author__ = "Patrick K. O'Brien <pobrien@orbtech.com>"
__cvsid__ = "$Id$"
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',
'mono' : 'Courier',
'helv' : 'Helvetica',
'other' : 'new century schoolbook',
- 'size' : 9,
- 'lnsize' : 8,
+ 'size' : 12,
+ 'lnsize' : 10,
'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
+
+ def __init__(self, parent, id=-1, pos=wxDefaultPosition, \
+ size=wxDefaultSize, style=wxCLIP_CHILDREN, introText='', \
+ locals=None, InterpClass=None, *args, **kwds):
+ """Create a PyCrust Shell instance."""
+ wxStyledTextCtrl.__init__(self, parent, id, pos, size, style)
+ # Import a default interpreter class if one isn't provided.
+ if InterpClass == None:
+ from interpreter import Interpreter
+ else:
+ Interpreter = InterpClass
+ # Create default locals so we have something interesting.
+ shellLocals = {'__name__': 'PyShell',
+ '__doc__': 'PyShell, The PyCrust Python Shell.',
+ '__version__': VERSION,
+ }
+ # Add the dictionary that was passed in.
+ if locals:
+ shellLocals.update(locals)
+ from pseudo import PseudoFileIn, PseudoFileOut, PseudoFileErr
+ self.interp = Interpreter(locals=shellLocals, \
+ rawin=self.readRaw, \
+ stdin=PseudoFileIn(self.readIn), \
+ stdout=PseudoFileOut(self.writeOut), \
+ stderr=PseudoFileErr(self.writeErr), \
+ *args, **kwds)
# Keep track of the most recent prompt starting and ending positions.
self.promptPos = [0, 0]
# Keep track of multi-line commands.
self.more = 0
+ # Create the command history. Commands are added into the front of
+ # the list (ie. at index 0) as they are entered. self.historyPos is
+ # the current position in the history; it gets incremented as you
+ # retrieve the previous command, decremented as you retrieve the next,
+ # and reset when you hit Enter. self.historyPos == -1 means you're on
+ # the current command, not in the history. self.tempCommand is
+ # storage space for whatever was on the last line when you first hit
+ # "Retrieve-Previous", so that the final "Retrieve-Next" will restore
+ # whatever was originally there. self.lastCommandRecalled remembers
+ # the index of the last command to be recalled from the history, so
+ # you can repeat a group of commands by going up-up-up-enter to find
+ # the first one in the group then down-enter-down-enter to recall each
+ # subsequent command. Also useful for multiline commands, in lieu of
+ # a proper implementation of those.
+ self.history = []
+ self.historyPos = -1
+ self.tempCommand = ''
+ self.lastCommandRecalled = -1
# 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
-
+ # Display the introductory banner information.
+ try: self.showIntro(introText)
+ except: pass
+ # Assign some pseudo keywords to the interpreter's namespace.
+ try: self.setBuiltinKeywords()
+ except: pass
+ # Add 'shell' to the interpreter's local namespace.
+ 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
+ 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):
def showIntro(self, text=''):
"""Display introductory text in the shell."""
if text:
- if text[-1] != '\n': text += '\n'
+ if not text.endswith(os.linesep): text += os.linesep
self.write(text)
try:
self.write(self.interp.introText)
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.
"""
+## POB: This is having some weird side-effects so I'm taking it out.
+## import __builtin__
+## from pseudo import PseudoKeyword
+## __builtin__.close = __builtin__.exit = __builtin__.quit = \
+## PseudoKeyword(self.quit)
import __builtin__
from pseudo import PseudoKeyword
__builtin__.close = __builtin__.exit = __builtin__.quit = \
- PseudoKeyword(self.quit)
+ 'Click on the close button to leave the application.'
def quit(self):
"""Quit the application."""
"""Key down event handler.
The main goal here is to not allow modifications to previous
- lines of text.
- """
+ lines of text."""
key = event.KeyCode()
currpos = self.GetCurrentPos()
stoppos = self.promptPos[1]
# If the auto-complete window is up let it do its thing.
if self.AutoCompActive():
event.Skip()
+ # Control+UpArrow steps up through the history.
+ elif key == WXK_UP and event.ControlDown() \
+ and self.historyPos < len(self.history) - 1:
+ # Move to the end of the buffer.
+ endpos = self.GetTextLength()
+ self.SetCurrentPos(endpos)
+ # The first Control+Up stores the current command;
+ # Control+Down brings it back.
+ if self.historyPos == -1:
+ self.tempCommand = self.getCommand()
+ # Now replace the current line with the next one from the history.
+ self.historyPos = self.historyPos + 1
+ self.SetSelection(stoppos, endpos)
+ self.ReplaceSelection(self.history[self.historyPos])
+ # Control+DownArrow steps down through the history.
+ elif key == WXK_DOWN and event.ControlDown():
+ # Move to the end of the buffer.
+ endpos = self.GetTextLength()
+ self.SetCurrentPos(endpos)
+ # Are we at the bottom end of the history?
+ if self.historyPos == -1:
+ # Do we have a lastCommandRecalled stored?
+ if self.lastCommandRecalled >= 0:
+ # Replace the current line with the command after the
+ # last-recalled command (you'd think there should be a +1
+ # here but there isn't because the history was shuffled up
+ # by 1 after the previous command was recalled).
+ self.SetSelection(stoppos, endpos)
+ self.ReplaceSelection(self.history[self.lastCommandRecalled])
+ # We've now warped into middle of the history.
+ self.historyPos = self.lastCommandRecalled
+ self.lastCommandRecalled = -1
+ else:
+ # Fetch either the previous line from the history, or the saved
+ # command if we're back at the start.
+ self.historyPos = self.historyPos - 1
+ if self.historyPos == -1:
+ newText = self.tempCommand
+ else:
+ newText = self.history[self.historyPos]
+ # Replace the current line with the new text.
+ self.SetSelection(stoppos, endpos)
+ self.ReplaceSelection(newText)
+ # F8 on the last line does a search up the history for the text in
+ # front of the cursor.
+ elif key == WXK_F8 and self.GetCurrentLine() == self.GetLineCount()-1:
+ tempCommand = self.getCommand()
+ # The first F8 saves the current command, just like Control+Up.
+ if self.historyPos == -1:
+ self.tempCommand = tempCommand
+ # The text up to the cursor is what we search for.
+ searchText = tempCommand
+ numCharsAfterCursor = self.GetTextLength() - self.GetCurrentPos()
+ if numCharsAfterCursor > 0:
+ searchText = searchText[:-numCharsAfterCursor]
+ # Search upwards from the current history position and loop back
+ # to the beginning if we don't find anything.
+ for i in range(self.historyPos+1, len(self.history)) + \
+ range(self.historyPos):
+ command = self.history[i]
+ if command[:len(searchText)] == searchText:
+ # Replace the current line with the one we've found.
+ endpos = self.GetTextLength()
+ self.SetSelection(stoppos, endpos)
+ self.ReplaceSelection(command)
+ # Put the cursor back at the end of the search text.
+ pos = self.GetTextLength() - len(command) + len(searchText)
+ self.SetCurrentPos(pos)
+ self.SetAnchor(pos)
+ # We've now warped into middle of the history.
+ self.historyPos = i
+ self.lastCommandRecalled = -1
+ break
# Return is used to submit a command to the interpreter.
elif key == WXK_RETURN:
if self.CallTipActive: self.CallTipCancel()
"""Keypress event handler.
The main goal here is to not allow modifications to previous
- lines of text.
- """
+ lines of text."""
key = event.KeyCode()
currpos = self.GetCurrentPos()
stoppos = self.promptPos[1]
# Grab information about the current line.
thepos = self.GetCurrentPos()
theline = self.GetCurrentLine()
- thetext = self.GetCurLine()[0]
- command = self.getCommand(thetext)
+ command = self.getCommand()
# Go to the very bottom of the text.
endpos = self.GetTextLength()
self.SetCurrentPos(endpos)
endline = self.GetCurrentLine()
# If they hit RETURN on the last line, execute the command.
if theline == endline:
+ # Store the last-recalled command; see the main comment for
+ # self.lastCommandRecalled.
+ if command != '':
+ self.lastCommandRecalled = self.historyPos
+ # Reset the history position.
+ self.historyPos = -1
+ # Insert this command into the history, unless it's a blank line
+ # or the same as the last command.
+ if command != '' \
+ and (len(self.history) == 0 or command != self.history[0]):
+ self.history.insert(0, command)
self.push(command)
# Otherwise, replace the last line with the new line.
else:
self.SetCurrentPos(thepos)
self.SetAnchor(thepos)
- def getCommand(self, text):
+ def getCommand(self, text=None):
"""Extract a command from text which may include a shell prompt.
- The command may not necessarily be valid Python syntax.
- """
-
+ The command may not necessarily be valid Python syntax."""
+ if not text:
+ text = self.GetCurLine()[0]
+## This is a hack due to a bug in the wxPython 2.3.2 beta. The following
+## two lines of code should go away once the bug has been fixed and the
+## line above should be restored.
+## self.write(' ')
+## text = self.GetCurLine()[0][:-1]
# 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.
+ # prompt every time a command is issued.
ps1 = str(sys.ps1)
ps1size = len(ps1)
ps2 = str(sys.ps2)
def push(self, command):
"""Send command to the interpreter for execution."""
- self.write('\n')
+ self.write(os.linesep)
self.more = self.interp.push(command)
self.prompt()
# Keep the undo feature from undoing previous responses. The only
self.EmptyUndoBuffer()
def write(self, text):
- """Display text in the shell."""
+ """Display text in the shell.
+
+ Replace line endings with OS-specific endings."""
+ lines = text.split('\r\n')
+ for l in range(len(lines)):
+ chunks = lines[l].split('\r')
+ for c in range(len(chunks)):
+ chunks[c] = os.linesep.join(chunks[c].split('\n'))
+ lines[l] = os.linesep.join(chunks)
+ text = os.linesep.join(lines)
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 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')
+ if pos > 0: self.write(os.linesep)
self.promptPos[0] = self.GetCurrentPos()
self.write(prompt)
self.promptPos[1] = self.GetCurrentPos()
self.write('\t') # Temporary hack indentation.
self.EnsureCaretVisible()
self.ScrollToColumn(0)
-
+
def readIn(self):
"""Replacement for stdin."""
prompt = 'Please enter your response:'
try:
if dialog.ShowModal() == wxID_OK:
text = dialog.GetValue()
- self.write(text + '\n')
+ self.write(text + os.linesep)
return text
finally:
dialog.Destroy()
"""Return true if text is selected and can be copied."""
return self.GetSelectionStart() != self.GetSelectionEnd()
+
+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 ShellFrame(wxFrame):
+ """Frame containing the PyCrust shell component."""
+
+ name = 'PyCrust Shell Frame'
+ revision = __version__
+
+ 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
+ self.CreateStatusBar()
+ self.SetStatusText(intro)
+ if wxPlatform == '__WXMSW__':
+ icon = wxIcon('PyCrust.ico', wxBITMAP_TYPE_ICO)
+ self.SetIcon(icon)
+ self.createMenus()
+ 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
+
+ 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 \tDel', 'Delete the selection')
+ m.Append(wxID_SELECTALL, 'Select A&ll \tCtrl+A', 'Select all text')
+
+ m = self.autocompMenu = wxMenu()
+ m.Append(ID_AUTOCOMP_SHOW, 'Show Auto Completion', \
+ 'Show auto completion during dot syntax', \
+ checkable=1)
+ m.Append(ID_AUTOCOMP_INCLUDE_MAGIC, 'Include Magic Attributes', \
+ 'Include attributes visible to __getattr__ and __setattr__', \
+ checkable=1)
+ m.Append(ID_AUTOCOMP_INCLUDE_SINGLE, 'Include Single Underscores', \
+ 'Include attibutes prefixed by a single underscore', \
+ checkable=1)
+ m.Append(ID_AUTOCOMP_INCLUDE_DOUBLE, 'Include Double Underscores', \
+ 'Include attibutes prefixed by a double underscore', \
+ checkable=1)
+
+ m = self.calltipsMenu = wxMenu()
+ m.Append(ID_CALLTIPS_SHOW, 'Show Call Tips', \
+ 'Show call tips with argument specifications', checkable=1)
+
+ m = self.optionsMenu = wxMenu()
+ m.AppendMenu(ID_AUTOCOMP, '&Auto Completion', self.autocompMenu, \
+ 'Auto Completion Options')
+ m.AppendMenu(ID_CALLTIPS, '&Call Tips', self.calltipsMenu, \
+ 'Call Tip Options')
+
+ m = self.helpMenu = wxMenu()
+ m.AppendSeparator()
+ m.Append(wxID_ABOUT, '&About...', 'About PyCrust')
+
+ b = self.menuBar = wxMenuBar()
+ b.Append(self.fileMenu, '&File')
+ b.Append(self.editMenu, '&Edit')
+ b.Append(self.optionsMenu, '&Options')
+ b.Append(self.helpMenu, '&Help')
+ self.SetMenuBar(b)
+
+ EVT_MENU(self, wxID_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)
+
+
"""Provides an object representing the current "version" or "release" of
-PyCrust as a whole. Individual classes, such as the shell, editor and
+PyCrust as a whole. Individual classes, such as the shell, filling and
interpreter, each have a revision property based on the CVS Revision."""
__author__ = "Patrick K. O'Brien <pobrien@orbtech.com>"
__date__ = "July 1, 2001"
__version__ = "$Revision$"[11:-2]
-VERSION = '0.5.2'
+VERSION = '0.6'