Major restructuring to get a better foundation.

git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/branches/WX_2_4_BRANCH@20227 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775
This commit is contained in:
Patrick K. O'Brien
2003-04-15 22:03:03 +00:00
parent 9d5aa5d876
commit 64386c666c
9 changed files with 509 additions and 260 deletions

View File

@@ -4,12 +4,12 @@ __author__ = "Patrick K. O'Brien <pobrien@orbtech.com>"
__cvsid__ = "$Id$" __cvsid__ = "$Id$"
__revision__ = "$Revision$"[11:-2] __revision__ = "$Revision$"[11:-2]
import base
import buffer import buffer
import crust import crust
import dispatcher import dispatcher
import document import document
import editor import editor
import editwindow
import filling import filling
import frame import frame
import images import images

View File

@@ -1,4 +1,4 @@
"""Base editor.""" """EditWindow class."""
__author__ = "Patrick K. O'Brien <pobrien@orbtech.com>" __author__ = "Patrick K. O'Brien <pobrien@orbtech.com>"
__cvsid__ = "$Id$" __cvsid__ = "$Id$"
@@ -42,14 +42,14 @@ else: # GTK
} }
class Editor(stc.wxStyledTextCtrl): class EditWindow(stc.wxStyledTextCtrl):
"""Editor based on StyledTextCtrl.""" """EditWindow based on StyledTextCtrl."""
revision = __revision__ revision = __revision__
def __init__(self, parent, id=-1, pos=wx.wxDefaultPosition, def __init__(self, parent, id=-1, pos=wx.wxDefaultPosition,
size=wx.wxDefaultSize, style=wx.wxCLIP_CHILDREN | wx.wxSUNKEN_BORDER): size=wx.wxDefaultSize, style=wx.wxCLIP_CHILDREN | wx.wxSUNKEN_BORDER):
"""Create an Editor instance.""" """Create EditWindow instance."""
stc.wxStyledTextCtrl.__init__(self, parent, id, pos, size, style) stc.wxStyledTextCtrl.__init__(self, parent, id, pos, size, style)
self.__config() self.__config()
stc.EVT_STC_UPDATEUI(self, id, self.OnUpdateUI) stc.EVT_STC_UPDATEUI(self, id, self.OnUpdateUI)

View File

@@ -6,6 +6,7 @@ __revision__ = "$Revision$"[11:-2]
from wxPython import wx from wxPython import wx
from interpreter import Interpreter
import imp import imp
import os import os
import sys import sys
@@ -24,13 +25,14 @@ class Buffer:
id = 0 id = 0
def __init__(self, editor, interp, filename=None): def __init__(self, filename=None):
"""Create a Buffer instance.""" """Create a Buffer instance."""
Buffer.id += 1 Buffer.id += 1
self.id = Buffer.id self.id = Buffer.id
self.interp = Interpreter(locals={})
self.name = '' self.name = ''
self.editor = editor self.editors = {}
self.interp = interp self.editor = None
self.modules = sys.modules.keys() self.modules = sys.modules.keys()
self.syspath = sys.path[:] self.syspath = sys.path[:]
while True: while True:
@@ -45,18 +47,17 @@ class Buffer:
break break
self.open(filename) self.open(filename)
def getStatus(self): def addEditor(self, editor):
"""Return (filepath, line, column) status tuple.""" """Add an editor."""
editor = self.editor self.editor = editor
pos = editor.GetCurrentPos() self.editors[editor.id] = editor
line = editor.LineFromPosition(pos) + 1
col = editor.GetColumn(pos)
status = (self.doc.filepath or self.name, line, col)
return status
def hasChanged(self): def hasChanged(self):
"""Return True if text in editor has changed since last save.""" """Return True if text in editor has changed since last save."""
return self.editor.GetModify() if self.editor:
return self.editor.hasChanged()
else:
return False
def new(self, filepath): def new(self, filepath):
"""New empty buffer.""" """New empty buffer."""
@@ -72,14 +73,16 @@ class Buffer:
self.doc = document.Document(filename) self.doc = document.Document(filename)
self.name = self.doc.filename or ('Untitled:' + str(self.id)) self.name = self.doc.filename or ('Untitled:' + str(self.id))
self.modulename = self.doc.filebase self.modulename = self.doc.filebase
if self.doc.filepath and os.path.exists(self.doc.filepath): # XXX This should really make sure filedir is first item in syspath.
self.editor.ClearAll() # XXX Or maybe this should be moved to the update namespace method.
self.editor.SetText(self.doc.read())
self.editor.EmptyUndoBuffer()
self.editor.SetSavePoint()
self.confirmed = True
if self.doc.filedir and self.doc.filedir not in self.syspath: if self.doc.filedir and self.doc.filedir not in self.syspath:
# To create the proper context for updateNamespace.
self.syspath.insert(0, self.doc.filedir) self.syspath.insert(0, self.doc.filedir)
if self.doc.filepath and os.path.exists(self.doc.filepath):
self.confirmed = True
if self.editor:
text = self.doc.read()
self.editor._setBuffer(buffer=self, text=text)
def overwriteConfirm(filepath): def overwriteConfirm(filepath):
"""Confirm overwriting an existing file.""" """Confirm overwriting an existing file."""
@@ -95,43 +98,36 @@ class Buffer:
if not self.confirmed: if not self.confirmed:
self.confirmed = self.overwriteConfirm(filepath) self.confirmed = self.overwriteConfirm(filepath)
if self.confirmed: if self.confirmed:
self.doc.write(self.editor.GetText()) self.doc.write(self.editor.getText())
self.editor.SetSavePoint() if self.editor:
self.editor.setSavePoint()
def saveAs(self, filename): def saveAs(self, filename):
"""Save buffer.""" """Save buffer."""
self.doc = document.Document(filename) self.doc = document.Document(filename)
self.name = self.doc.filename self.name = self.doc.filename
self.modulename = self.doc.filebase self.modulename = self.doc.filebase
filepath = self.doc.filepath self.save()
if not filepath:
return # XXX Get filename
## if not os.path.exists(filepath):
self.confirmed = True
if not self.confirmed:
self.confirmed = self.overwriteConfirm(filepath)
if self.confirmed:
self.doc.write(self.editor.GetText())
self.editor.SetSavePoint()
def updateNamespace(self): def updateNamespace(self):
"""Update the namespace for autocompletion and calltips. """Update the namespace for autocompletion and calltips.
Return True if updated, False if there was an error.""" Return True if updated, False if there was an error."""
backup = self.interp.locals if not self.interp or not hasattr(self.editor, 'getText'):
return False
syspath = sys.path syspath = sys.path
sys.path = self.syspath sys.path = self.syspath
code = self.editor.GetText() code = self.editor.getText()
module = imp.new_module(str(self.modulename)) module = imp.new_module(str(self.modulename))
namespace = module.__dict__.copy() namespace = module.__dict__.copy()
try: try:
try: try:
exec code in namespace exec code in namespace
except: except:
self.interp.locals = backup
return False return False
else: else:
self.interp.locals = namespace self.interp.locals.clear()
self.interp.locals.update(namespace)
return True return True
finally: finally:
sys.path = syspath sys.path = syspath

View File

@@ -38,7 +38,7 @@ class Crust(wx.wxSplitterWindow):
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.buffer = self.shell.buffer self.editor = self.shell
if rootObject is None: if rootObject is None:
rootObject = self.shell.interp.locals rootObject = self.shell.interp.locals
self.notebook = wx.wxNotebook(parent=self, id=-1) self.notebook = wx.wxNotebook(parent=self, id=-1)

View File

@@ -30,11 +30,14 @@ class Document:
def read(self): def read(self):
"""Return contents of file.""" """Return contents of file."""
if self.filepath and os.path.exists(self.filepath):
f = file(self.filepath, 'rb') f = file(self.filepath, 'rb')
try: try:
return f.read() return f.read()
finally: finally:
f.close() f.close()
else:
return ''
def write(self, text): def write(self, text):
"""Write text to file.""" """Write text to file."""

View File

@@ -6,13 +6,12 @@ __revision__ = "$Revision$"[11:-2]
from wxPython import wx from wxPython import wx
import base from buffer import Buffer
import buffer
import crust import crust
import dispatcher import dispatcher
import editwindow
import frame import frame
import interpreter from shell import Shell
import shell
import version import version
try: try:
@@ -28,12 +27,13 @@ class EditorFrame(frame.Frame):
def __init__(self, parent=None, id=-1, title='PyAlaCarte', def __init__(self, parent=None, id=-1, title='PyAlaCarte',
pos=wx.wxDefaultPosition, size=(800, 600), pos=wx.wxDefaultPosition, size=(800, 600),
style=wx.wxDEFAULT_FRAME_STYLE, filename=None): style=wx.wxDEFAULT_FRAME_STYLE, filename=None):
"""Create an EditorFrame instance.""" """Create EditorFrame instance."""
frame.Frame.__init__(self, parent, id, title, pos, size, style) frame.Frame.__init__(self, parent, id, title, pos, size, style)
self._buffers = {} self.buffers = {}
self._buffer = None # Current buffer. self.buffer = None # Current buffer.
self.editor = None self.editor = None
self._statusText = title + ' - the tastiest Python editor.' self._defaultText = title + ' - the tastiest Python editor.'
self._statusText = self._defaultText
self.SetStatusText(self._statusText) self.SetStatusText(self._statusText)
wx.EVT_IDLE(self, self.OnIdle) wx.EVT_IDLE(self, self.OnIdle)
self._setup() self._setup()
@@ -46,6 +46,11 @@ class EditorFrame(frame.Frame):
Useful for subclasses.""" Useful for subclasses."""
pass pass
def setEditor(self, editor):
self.editor = editor
self.buffer = self.editor.buffer
self.buffers[self.buffer.id] = self.buffer
def OnAbout(self, event): def OnAbout(self, event):
"""Display an About window.""" """Display an About window."""
title = 'About PyAlaCarte' title = 'About PyAlaCarte'
@@ -57,8 +62,8 @@ class EditorFrame(frame.Frame):
def OnClose(self, event): def OnClose(self, event):
"""Event handler for closing.""" """Event handler for closing."""
for buffer in self._buffers.values(): for buffer in self.buffers.values():
self._buffer = buffer self.buffer = buffer
if buffer.hasChanged(): if buffer.hasChanged():
cancel = self.bufferSuggestSave() cancel = self.bufferSuggestSave()
if cancel and event.CanVeto(): if cancel and event.CanVeto():
@@ -74,9 +79,11 @@ class EditorFrame(frame.Frame):
def _updateStatus(self): def _updateStatus(self):
"""Show current status information.""" """Show current status information."""
if self._buffer: if self.editor and hasattr(self.editor, 'getStatus'):
status = self._buffer.getStatus() status = self.editor.getStatus()
text = 'File: %s | Line: %d | Column: %d' % status text = 'File: %s | Line: %d | Column: %d' % status
else:
text = self._defaultText
if text != self._statusText: if text != self._statusText:
self.SetStatusText(text) self.SetStatusText(text)
self._statusText = text self._statusText = text
@@ -95,7 +102,7 @@ class EditorFrame(frame.Frame):
def hasBuffer(self): def hasBuffer(self):
"""Return True if there is a current buffer.""" """Return True if there is a current buffer."""
if self._buffer: if self.buffer:
return True return True
else: else:
return False return False
@@ -113,25 +120,26 @@ class EditorFrame(frame.Frame):
def bufferCreate(self, filename=None): def bufferCreate(self, filename=None):
"""Create new buffer.""" """Create new buffer."""
self.bufferDestroy() self.bufferDestroy()
interp = interpreter.Interpreter(locals={}) buffer = Buffer()
self.editor = Editor(interp=interp, parent=self, filename=filename) editor = Editor(parent=self)
self._buffer = self.editor.buffer buffer.addEditor(editor)
self._buffers[self._buffer.id] = self._buffer buffer.open(filename)
self._buffer.editor.SetFocus() self.setEditor(editor)
self.editor.setFocus()
def bufferDestroy(self): def bufferDestroy(self):
"""Destroy the current buffer.""" """Destroy the current buffer."""
if self._buffer: if self.buffer:
del self._buffers[self._buffer.id] for editor in self.buffer.editors.values():
self._buffer = None editor.destroy()
if self.editor:
self.editor.Destroy()
self.editor = None self.editor = None
del self.buffers[self.buffer.id]
self.buffer = None
def bufferHasChanged(self): def bufferHasChanged(self):
"""Return True if buffer has changed since last save.""" """Return True if buffer has changed since last save."""
if self._buffer: if self.buffer:
return self._buffer.hasChanged() return self.buffer.hasChanged()
else: else:
return False return False
@@ -152,8 +160,8 @@ class EditorFrame(frame.Frame):
if cancel: if cancel:
return cancel return cancel
filedir = '' filedir = ''
if self._buffer and self._buffer.doc.filedir: if self.buffer and self.buffer.doc.filedir:
filedir = self._buffer.doc.filedir filedir = self.buffer.doc.filedir
result = openSingle(directory=filedir) result = openSingle(directory=filedir)
if result.path: if result.path:
self.bufferCreate(result.path) self.bufferCreate(result.path)
@@ -170,8 +178,8 @@ class EditorFrame(frame.Frame):
def bufferSave(self): def bufferSave(self):
"""Save buffer to its file.""" """Save buffer to its file."""
if self._buffer.doc.filepath: if self.buffer.doc.filepath:
self._buffer.save() self.buffer.save()
cancel = False cancel = False
else: else:
cancel = self.bufferSaveAs() cancel = self.bufferSaveAs()
@@ -179,16 +187,16 @@ class EditorFrame(frame.Frame):
def bufferSaveAs(self): def bufferSaveAs(self):
"""Save buffer to a new filename.""" """Save buffer to a new filename."""
if self.bufferHasChanged() and self._buffer.doc.filepath: if self.bufferHasChanged() and self.buffer.doc.filepath:
cancel = self.bufferSuggestSave() cancel = self.bufferSuggestSave()
if cancel: if cancel:
return cancel return cancel
filedir = '' filedir = ''
if self._buffer and self._buffer.doc.filedir: if self.buffer and self.buffer.doc.filedir:
filedir = self._buffer.doc.filedir filedir = self.buffer.doc.filedir
result = saveSingle(directory=filedir) result = saveSingle(directory=filedir)
if result.path: if result.path:
self._buffer.saveAs(result.path) self.buffer.saveAs(result.path)
cancel = False cancel = False
else: else:
cancel = True cancel = True
@@ -199,7 +207,7 @@ class EditorFrame(frame.Frame):
result = messageDialog(parent=None, result = messageDialog(parent=None,
message='%s has changed.\n' message='%s has changed.\n'
'Would you like to save it first' 'Would you like to save it first'
'?' % self._buffer.name, '?' % self.buffer.name,
title='Save current file?') title='Save current file?')
if result.positive: if result.positive:
cancel = self.bufferSave() cancel = self.bufferSave()
@@ -209,7 +217,7 @@ class EditorFrame(frame.Frame):
def updateNamespace(self): def updateNamespace(self):
"""Update the buffer namespace for autocompletion and calltips.""" """Update the buffer namespace for autocompletion and calltips."""
if self._buffer.updateNamespace(): if self.buffer.updateNamespace():
self.SetStatusText('Namespace updated') self.SetStatusText('Namespace updated')
else: else:
self.SetStatusText('Error executing, unable to update namespace') self.SetStatusText('Error executing, unable to update namespace')
@@ -221,24 +229,26 @@ class EditorNotebookFrame(EditorFrame):
def __init__(self, parent=None, id=-1, title='PyAlaMode', def __init__(self, parent=None, id=-1, title='PyAlaMode',
pos=wx.wxDefaultPosition, size=(800, 600), pos=wx.wxDefaultPosition, size=(800, 600),
style=wx.wxDEFAULT_FRAME_STYLE, filename=None): style=wx.wxDEFAULT_FRAME_STYLE, filename=None):
"""Create an EditorNotebookFrame instance.""" """Create EditorNotebookFrame instance."""
self.notebook = None
EditorFrame.__init__(self, parent, id, title, pos, EditorFrame.__init__(self, parent, id, title, pos,
size, style, filename) size, style, filename)
if self.notebook:
dispatcher.connect(receiver=self._editorChange,
signal='EditorChange', sender=self.notebook)
def _setup(self): def _setup(self):
"""Setup prior to first buffer creation. """Setup prior to first buffer creation.
Useful for subclasses.""" Called automatically by base class during init."""
self._notebook = BufferNotebook(parent=self) self.notebook = EditorNotebook(parent=self)
dispatcher.connect(receiver=self._bufferChange,
signal='BufferChange', sender=self._notebook)
intro = 'PyCrust %s' % version.VERSION intro = 'PyCrust %s' % version.VERSION
import imp import imp
module = imp.new_module('__main__') module = imp.new_module('__main__')
import __builtin__ import __builtin__
module.__dict__['__builtins__'] = __builtin__ module.__dict__['__builtins__'] = __builtin__
namespace = module.__dict__.copy() namespace = module.__dict__.copy()
self.crust = crust.Crust(parent=self._notebook, intro=intro, locals=namespace) self.crust = crust.Crust(parent=self.notebook, intro=intro, locals=namespace)
self.shell = self.crust.shell self.shell = self.crust.shell
# 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.tree.setStatusText = self.SetStatusText self.crust.filling.tree.setStatusText = self.SetStatusText
@@ -246,14 +256,12 @@ class EditorNotebookFrame(EditorFrame):
self.shell.setStatusText = self.SetStatusText self.shell.setStatusText = self.SetStatusText
# Fix a problem with the sash shrinking to nothing. # Fix a problem with the sash shrinking to nothing.
self.crust.filling.SetSashPosition(200) self.crust.filling.SetSashPosition(200)
self._notebook.AddPage(page=self.crust, text='PyCrust', select=True) self.notebook.AddPage(page=self.crust, text='PyCrust', select=True)
self._buffer = self.crust.buffer self.setEditor(self.crust.editor)
self._buffers[self._buffer.id] = self._buffer
self._buffer.editor.SetFocus()
def _bufferChange(self, buffer): def _editorChange(self, editor):
"""Buffer change signal receiver.""" """Editor change signal receiver."""
self._buffer = buffer self.setEditor(editor)
def OnAbout(self, event): def OnAbout(self, event):
"""Display an About window.""" """Display an About window."""
@@ -278,24 +286,24 @@ class EditorNotebookFrame(EditorFrame):
def bufferCreate(self, filename=None): def bufferCreate(self, filename=None):
"""Create new buffer.""" """Create new buffer."""
interp = interpreter.Interpreter(locals={}) buffer = Buffer()
editor = Editor(interp=interp, parent=self._notebook, editor = Editor(parent=self.notebook)
filename=filename) buffer.addEditor(editor)
self._buffer = editor.buffer buffer.open(filename)
self._buffers[self._buffer.id] = self._buffer self.setEditor(editor)
self._notebook.AddPage(page=editor, text=self._buffer.name, self.notebook.AddPage(page=editor.window, text=self.buffer.name,
select=True) select=True)
self._buffer.editor.SetFocus() self.editor.setFocus()
def bufferDestroy(self): def bufferDestroy(self):
"""Destroy the current buffer.""" """Destroy the current buffer."""
selection = self._notebook.GetSelection() selection = self.notebook.GetSelection()
## print "Destroy Selection:", selection ## print "Destroy Selection:", selection
if selection > 0: # Don't destroy the PyCrust tab. if selection > 0: # Don't destroy the PyCrust tab.
if self._buffer: if self.buffer:
del self._buffers[self._buffer.id] del self.buffers[self.buffer.id]
self._buffer = None # Do this before DeletePage(). self.buffer = None # Do this before DeletePage().
self._notebook.DeletePage(selection) self.notebook.DeletePage(selection)
def bufferNew(self): def bufferNew(self):
"""Create new buffer.""" """Create new buffer."""
@@ -306,8 +314,8 @@ class EditorNotebookFrame(EditorFrame):
def bufferOpen(self): def bufferOpen(self):
"""Open file in buffer.""" """Open file in buffer."""
filedir = '' filedir = ''
if self._buffer and self._buffer.doc.filedir: if self.buffer and self.buffer.doc.filedir:
filedir = self._buffer.doc.filedir filedir = self.buffer.doc.filedir
result = openMultiple(directory=filedir) result = openMultiple(directory=filedir)
for path in result.paths: for path in result.paths:
self.bufferCreate(path) self.bufferCreate(path)
@@ -315,14 +323,16 @@ class EditorNotebookFrame(EditorFrame):
return cancel return cancel
class BufferNotebook(wx.wxNotebook): class EditorNotebook(wx.wxNotebook):
"""A notebook containing a page for each buffer.""" """A notebook containing a page for each editor."""
def __init__(self, parent): def __init__(self, parent):
"""Create a BufferNotebook instance.""" """Create EditorNotebook instance."""
wx.wxNotebook.__init__(self, parent, id=-1) wx.wxNotebook.__init__(self, parent, id=-1)
wx.EVT_NOTEBOOK_PAGE_CHANGING(self, self.GetId(), self.OnPageChanging) wx.EVT_NOTEBOOK_PAGE_CHANGING(self, self.GetId(),
wx.EVT_NOTEBOOK_PAGE_CHANGED(self, self.GetId(), self.OnPageChanged) self.OnPageChanging)
wx.EVT_NOTEBOOK_PAGE_CHANGED(self, self.GetId(),
self.OnPageChanged)
def OnPageChanging(self, event): def OnPageChanging(self, event):
"""Page changing event handler.""" """Page changing event handler."""
@@ -338,87 +348,70 @@ class BufferNotebook(wx.wxNotebook):
## print "Changed from:", old ## print "Changed from:", old
new = event.GetSelection() new = event.GetSelection()
## print "Changed to new:", new ## print "Changed to new:", new
page = self.GetPage(new) window = self.GetPage(new)
buffer = page.buffer dispatcher.send(signal='EditorChange', sender=self,
buffer.editor.SetFocus() editor=window.editor)
dispatcher.send(signal='BufferChange', sender=self, buffer=buffer) window.SetFocus()
event.Skip() event.Skip()
class BufferEditorShellNotebookFrame(EditorFrame): class EditorShellNotebookFrame(EditorNotebookFrame):
"""Frame containing one or more editor notebooks.""" """Frame containing a notebook containing EditorShellNotebooks."""
def __init__(self, parent=None, id=-1, title='PyAlaMode', def __init__(self, parent=None, id=-1, title='PyAlaMode',
pos=wx.wxDefaultPosition, size=(600, 400), pos=wx.wxDefaultPosition, size=(600, 400),
style=wx.wxDEFAULT_FRAME_STYLE, style=wx.wxDEFAULT_FRAME_STYLE,
filename=None, singlefile=False): filename=None, singlefile=False):
"""Create a BufferEditorShellNotebookFrame instance.""" """Create EditorShellNotebookFrame instance."""
self._singlefile = singlefile self._singlefile = singlefile
EditorFrame.__init__(self, parent, id, title, pos, EditorNotebookFrame.__init__(self, parent, id, title, pos,
size, style, filename) size, style, filename)
def _setup(self): def _setup(self):
"""Setup prior to first buffer creation. """Setup prior to first buffer creation.
Useful for subclasses.""" Called automatically by base class during init."""
if not self._singlefile: if not self._singlefile:
self._notebook = BufferNotebook(parent=self) self.notebook = EditorNotebook(parent=self)
dispatcher.connect(receiver=self._bufferChange,
signal='BufferChange', sender=self._notebook)
def _bufferChange(self, buffer):
"""Buffer change signal receiver."""
self._buffer = buffer
def OnAbout(self, event): def OnAbout(self, event):
"""Display an About window.""" """Display an About window."""
title = 'About PyAlaMode' title = 'About PyAlaModePlus'
text = 'Another fine, flaky program.' text = 'Another fine, flaky program.'
dialog = wx.wxMessageDialog(self, text, title, dialog = wx.wxMessageDialog(self, text, title,
wx.wxOK | wx.wxICON_INFORMATION) wx.wxOK | wx.wxICON_INFORMATION)
dialog.ShowModal() dialog.ShowModal()
dialog.Destroy() dialog.Destroy()
def _updateTitle(self):
"""Show current title information."""
title = self.GetTitle()
if self.bufferHasChanged():
if title.startswith('* '):
pass
else:
self.SetTitle('* ' + title)
else:
if title.startswith('* '):
self.SetTitle(title[2:])
def bufferCreate(self, filename=None): def bufferCreate(self, filename=None):
"""Create new buffer.""" """Create new buffer."""
if self._singlefile: if self._singlefile:
self.bufferDestroy() self.bufferDestroy()
notebook = self._notebook = EditorShellNotebook(parent=self, notebook = EditorShellNotebook(parent=self,
filename=filename) filename=filename)
self.notebook = notebook
else: else:
notebook = EditorShellNotebook(parent=self._notebook, notebook = EditorShellNotebook(parent=self.notebook,
filename=filename) filename=filename)
self._buffer = notebook.buffer self.setEditor(notebook.editor)
if not self._singlefile: if not self._singlefile:
self._notebook.AddPage(page=notebook, text=self._buffer.name, self.notebook.AddPage(page=notebook, text=self.buffer.name,
select=True) select=True)
self._buffers[self._buffer.id] = self._buffer self.editor.setFocus()
self._buffer.editor.SetFocus()
def bufferDestroy(self): def bufferDestroy(self):
"""Destroy the current buffer.""" """Destroy the current buffer."""
if self._buffer: if self.buffer:
del self._buffers[self._buffer.id] self.editor = None
self._buffer = None # Do this before DeletePage(). del self.buffers[self.buffer.id]
self.buffer = None # Do this before DeletePage().
if self._singlefile: if self._singlefile:
self._notebook.Destroy() self.notebook.Destroy()
self._notebook = None self.notebook = None
else: else:
selection = self._notebook.GetSelection() selection = self.notebook.GetSelection()
print "Destroy Selection:", selection ## print "Destroy Selection:", selection
self._notebook.DeletePage(selection) self.notebook.DeletePage(selection)
def bufferNew(self): def bufferNew(self):
"""Create new buffer.""" """Create new buffer."""
@@ -437,8 +430,8 @@ class BufferEditorShellNotebookFrame(EditorFrame):
if cancel: if cancel:
return cancel return cancel
filedir = '' filedir = ''
if self._buffer and self._buffer.doc.filedir: if self.buffer and self.buffer.doc.filedir:
filedir = self._buffer.doc.filedir filedir = self.buffer.doc.filedir
if self._singlefile: if self._singlefile:
result = openSingle(directory=filedir) result = openSingle(directory=filedir)
if result.path: if result.path:
@@ -451,94 +444,125 @@ class BufferEditorShellNotebookFrame(EditorFrame):
return cancel return cancel
class BufferEditorShellNotebook(wx.wxNotebook):
"""A notebook containing a page for each buffer."""
def __init__(self, parent):
"""Create a BufferEditorShellNotebook instance."""
wx.wxNotebook.__init__(self, parent, id=-1)
wx.EVT_NOTEBOOK_PAGE_CHANGED(self, self.GetId(), self.OnPageChanged)
def OnPageChanged(self, event):
"""Page changed event handler."""
## old = event.GetOldSelection()
## print "Changed from old:", old
new = event.GetSelection()
## print "Changed to new:", new
page = self.GetPage(new)
buffer = page.buffer
subselection = page.GetSelection()
page.focus(subselection)
dispatcher.send(signal='BufferChange', sender=self, buffer=buffer)
event.Skip()
class EditorShellNotebook(wx.wxNotebook): class EditorShellNotebook(wx.wxNotebook):
"""A notebook containing an editor page and a shell page.""" """A notebook containing an editor page and a shell page."""
def __init__(self, parent, filename=None): def __init__(self, parent, filename=None):
"""Create an EditorShellNotebook instance.""" """Create EditorShellNotebook instance."""
wx.wxNotebook.__init__(self, parent, id=-1) wx.wxNotebook.__init__(self, parent, id=-1)
usePanels = True usePanels = True
if usePanels: if usePanels:
shellparent = shellpanel = wx.wxPanel(self, -1)
editorparent = editorpanel = wx.wxPanel(self, -1) editorparent = editorpanel = wx.wxPanel(self, -1)
shellparent = shellpanel = wx.wxPanel(self, -1)
else: else:
shellparent = self
editorparent = self editorparent = self
self.shell = shell.Shell(parent=shellparent, shellparent = self
self.buffer = Buffer()
self.editor = Editor(parent=editorparent)
self.buffer.addEditor(self.editor)
self.buffer.open(filename)
self.shell = Shell(parent=shellparent, locals=self.buffer.interp.locals,
style=wx.wxCLIP_CHILDREN | wx.wxSUNKEN_BORDER) style=wx.wxCLIP_CHILDREN | wx.wxSUNKEN_BORDER)
self.editor = Editor(interp=self.shell.interp, parent=editorparent, self.buffer.interp.locals.clear()
filename=filename)
if usePanels: if usePanels:
self.AddPage(page=editorpanel, text='File', select=True) self.AddPage(page=editorpanel, text='Editor', select=True)
self.AddPage(page=shellpanel, text='Shell') self.AddPage(page=shellpanel, text='Shell')
# Setup sizers # Setup sizers
editorsizer = wx.wxBoxSizer(wx.wxVERTICAL)
editorsizer.Add(self.editor.window, 1, wx.wxEXPAND)
editorpanel.SetSizer(editorsizer)
editorpanel.SetAutoLayout(True)
shellsizer = wx.wxBoxSizer(wx.wxVERTICAL) shellsizer = wx.wxBoxSizer(wx.wxVERTICAL)
shellsizer.Add(self.shell, 1, wx.wxEXPAND) shellsizer.Add(self.shell, 1, wx.wxEXPAND)
shellpanel.SetSizer(shellsizer) shellpanel.SetSizer(shellsizer)
shellpanel.SetAutoLayout(True) shellpanel.SetAutoLayout(True)
editorsizer = wx.wxBoxSizer(wx.wxVERTICAL)
editorsizer.Add(self.editor, 1, wx.wxEXPAND)
editorpanel.SetSizer(editorsizer)
editorpanel.SetAutoLayout(True)
else: else:
self.AddPage(page=self.editor, text='File', select=True) self.AddPage(page=self.editor.window, text='Editor', select=True)
self.AddPage(page=self.shell, text='Shell') self.AddPage(page=self.shell, text='Shell')
self.buffer = self.editor.buffer self.editor.setFocus()
self.editor.SetFocus()
wx.EVT_NOTEBOOK_PAGE_CHANGED(self, self.GetId(), self.OnPageChanged) wx.EVT_NOTEBOOK_PAGE_CHANGED(self, self.GetId(), self.OnPageChanged)
def OnPageChanged(self, event): def OnPageChanged(self, event):
"""Page changed event handler.""" """Page changed event handler."""
selection = event.GetSelection() selection = event.GetSelection()
self.focus(selection) if selection == 0:
self.editor.setFocus()
else:
self.shell.SetFocus()
event.Skip() event.Skip()
def focus(self, selection): def SetFocus(self):
wx.wxNotebook.SetFocus(self)
selection = self.GetSelection()
if selection == 0: if selection == 0:
self.editor.SetFocus() self.editor.setFocus()
else: else:
self.shell.SetFocus() self.shell.SetFocus()
class Editor(base.Editor): class Editor:
"""Editor based on StyledTextCtrl.""" """Editor having an EditWindow."""
def __init__(self, interp, parent, id=-1, pos=wx.wxDefaultPosition, def __init__(self, parent, id=-1, pos=wx.wxDefaultPosition,
size=wx.wxDefaultSize, size=wx.wxDefaultSize,
style=wx.wxCLIP_CHILDREN | wx.wxSUNKEN_BORDER, style=wx.wxCLIP_CHILDREN | wx.wxSUNKEN_BORDER):
filename=None): """Create Editor instance."""
"""Create a Editor instance.""" self.window = EditWindow(self, parent, id, pos, size, style)
base.Editor.__init__(self, parent, id, pos, size, style) self.id = self.window.GetId()
self.interp = interp self.buffer = None
# Find out for which keycodes the interpreter will autocomplete.
self.autoCompleteKeys = self.interp.getAutoCompleteKeys()
# Assign handlers for keyboard events. # Assign handlers for keyboard events.
wx.EVT_CHAR(self, self.OnChar) wx.EVT_CHAR(self.window, self.OnChar)
wx.EVT_KEY_DOWN(self, self.OnKeyDown) wx.EVT_KEY_DOWN(self.window, self.OnKeyDown)
self.buffer = buffer.Buffer(editor=self, interp=self.interp,
filename=filename) def _setBuffer(self, buffer, text):
"""Set the editor to a buffer. Private callback called by buffer."""
self.buffer = buffer
self.autoCompleteKeys = buffer.interp.getAutoCompleteKeys()
self.clearAll()
self.setText(text)
self.emptyUndoBuffer()
self.setSavePoint()
def destroy(self):
"""Destroy all editor objects."""
self.window.Destroy()
def clearAll(self):
self.window.ClearAll()
def emptyUndoBuffer(self):
self.window.EmptyUndoBuffer()
def getStatus(self):
"""Return (filepath, line, column) status tuple."""
pos = self.window.GetCurrentPos()
line = self.window.LineFromPosition(pos) + 1
col = self.window.GetColumn(pos)
if self.buffer:
name = self.buffer.doc.filepath or self.buffer.name
else:
name = ''
status = (name, line, col)
return status
def getText(self):
"""Return contents of editor."""
return self.window.GetText()
def hasChanged(self):
"""Return True if contents have changed."""
return self.window.GetModify()
def setFocus(self):
"""Set the input focus to the editor window."""
self.window.SetFocus()
def setSavePoint(self):
self.window.SetSavePoint()
def setText(self, text):
"""Set contents of editor."""
self.window.SetText(text)
def OnChar(self, event): def OnChar(self, event):
"""Keypress event handler. """Keypress event handler.
@@ -549,22 +573,22 @@ class Editor(base.Editor):
key = event.KeyCode() key = event.KeyCode()
if key in self.autoCompleteKeys: if key in self.autoCompleteKeys:
# Usually the dot (period) key activates auto completion. # Usually the dot (period) key activates auto completion.
if self.AutoCompActive(): if self.window.AutoCompActive():
self.AutoCompCancel() self.window.AutoCompCancel()
self.ReplaceSelection('') self.window.ReplaceSelection('')
self.AddText(chr(key)) self.window.AddText(chr(key))
text, pos = self.GetCurLine() text, pos = self.window.GetCurLine()
text = text[:pos] text = text[:pos]
if self.autoComplete: if self.window.autoComplete:
self.autoCompleteShow(text) self.autoCompleteShow(text)
elif key == ord('('): elif key == ord('('):
# The left paren activates a call tip and cancels an # The left paren activates a call tip and cancels an
# active auto completion. # active auto completion.
if self.AutoCompActive(): if self.window.AutoCompActive():
self.AutoCompCancel() self.window.AutoCompCancel()
self.ReplaceSelection('') self.window.ReplaceSelection('')
self.AddText('(') self.window.AddText('(')
text, pos = self.GetCurLine() text, pos = self.window.GetCurLine()
text = text[:pos] text = text[:pos]
self.autoCallTipShow(text) self.autoCallTipShow(text)
else: else:
@@ -576,7 +600,7 @@ class Editor(base.Editor):
key = event.KeyCode() key = event.KeyCode()
# If the auto-complete window is up let it do its thing. # If the auto-complete window is up let it do its thing.
if self.AutoCompActive(): if self.window.AutoCompActive():
event.Skip() event.Skip()
return return
controlDown = event.ControlDown() controlDown = event.ControlDown()
@@ -599,46 +623,57 @@ class Editor(base.Editor):
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.buffer.interp.getAutoCompleteList(command,
includeMagic=self.autoCompleteIncludeMagic, includeMagic=self.window.autoCompleteIncludeMagic,
includeSingle=self.autoCompleteIncludeSingle, includeSingle=self.window.autoCompleteIncludeSingle,
includeDouble=self.autoCompleteIncludeDouble) includeDouble=self.window.autoCompleteIncludeDouble)
if list and len(list) < 2000: if list and len(list) < 2000:
options = ' '.join(list) options = ' '.join(list)
offset = 0 offset = 0
self.AutoCompShow(offset, options) self.window.AutoCompShow(offset, options)
def autoCallTipShow(self, command): def autoCallTipShow(self, command):
"""Display argument spec and docstring in a popup window.""" """Display argument spec and docstring in a popup window."""
if self.CallTipActive(): if self.window.CallTipActive():
self.CallTipCancel() self.window.CallTipCancel()
(name, argspec, tip) = self.interp.getCallTip(command) (name, argspec, tip) = self.buffer.interp.getCallTip(command)
if tip: if tip:
dispatcher.send(signal='Shell.calltip', sender=self, calltip=tip) dispatcher.send(signal='Shell.calltip', sender=self, calltip=tip)
if not self.autoCallTip: if not self.window.autoCallTip:
return return
if argspec: if argspec:
startpos = self.GetCurrentPos() startpos = self.window.GetCurrentPos()
self.AddText(argspec + ')') self.window.AddText(argspec + ')')
endpos = self.GetCurrentPos() endpos = self.window.GetCurrentPos()
self.SetSelection(endpos, startpos) self.window.SetSelection(endpos, startpos)
if tip: if tip:
curpos = self.GetCurrentPos() curpos = self.window.GetCurrentPos()
size = len(name) size = len(name)
tippos = curpos - (size + 1) tippos = curpos - (size + 1)
fallback = curpos - self.GetColumn(curpos) fallback = curpos - self.window.GetColumn(curpos)
# In case there isn't enough room, only go back to the # In case there isn't enough room, only go back to the
# fallback. # fallback.
tippos = max(tippos, fallback) tippos = max(tippos, fallback)
self.CallTipShow(tippos, tip) self.window.CallTipShow(tippos, tip)
self.CallTipSetHighlight(0, size) self.window.CallTipSetHighlight(0, size)
class EditWindow(editwindow.EditWindow):
"""EditWindow based on StyledTextCtrl."""
def __init__(self, editor, parent, id=-1, pos=wx.wxDefaultPosition,
size=wx.wxDefaultSize,
style=wx.wxCLIP_CHILDREN | wx.wxSUNKEN_BORDER):
"""Create EditWindow instance."""
editwindow.EditWindow.__init__(self, parent, id, pos, size, style)
self.editor = editor
class DialogResults: class DialogResults:
"""DialogResults class.""" """DialogResults class."""
def __init__(self, returned): def __init__(self, returned):
"""Create a wrapper for the results returned by a dialog.""" """Create wrapper for results returned by dialog."""
self.returned = returned self.returned = returned
self.positive = returned in (wx.wxID_OK, wx.wxID_YES) self.positive = returned in (wx.wxID_OK, wx.wxID_YES)
self.text = self._asString() self.text = self._asString()

View File

@@ -0,0 +1,195 @@
"""EditWindow class."""
__author__ = "Patrick K. O'Brien <pobrien@orbtech.com>"
__cvsid__ = "$Id$"
__revision__ = "$Revision$"[11:-2]
from wxPython import wx
from wxPython import stc
import keyword
import os
import sys
import time
import dispatcher
from version import VERSION
try:
True
except NameError:
True = 1==1
False = 1==0
if wx.wxPlatform == '__WXMSW__':
FACES = { 'times' : 'Times New Roman',
'mono' : 'Courier New',
'helv' : 'Lucida Console',
'lucida' : 'Lucida Console',
'other' : 'Comic Sans MS',
'size' : 10,
'lnsize' : 9,
'backcol': '#FFFFFF',
}
else: # GTK
FACES = { 'times' : 'Times',
'mono' : 'Courier',
'helv' : 'Helvetica',
'other' : 'new century schoolbook',
'size' : 12,
'lnsize' : 10,
'backcol': '#FFFFFF',
}
class EditWindow(stc.wxStyledTextCtrl):
"""EditWindow based on StyledTextCtrl."""
revision = __revision__
def __init__(self, parent, id=-1, pos=wx.wxDefaultPosition,
size=wx.wxDefaultSize, style=wx.wxCLIP_CHILDREN | wx.wxSUNKEN_BORDER):
"""Create EditWindow instance."""
stc.wxStyledTextCtrl.__init__(self, parent, id, pos, size, style)
self.__config()
stc.EVT_STC_UPDATEUI(self, id, self.OnUpdateUI)
dispatcher.connect(receiver=self._fontsizer, signal='FontIncrease')
dispatcher.connect(receiver=self._fontsizer, signal='FontDecrease')
dispatcher.connect(receiver=self._fontsizer, signal='FontDefault')
def _fontsizer(self, signal):
"""Receiver for Font* signals."""
size = self.GetZoom()
if signal == 'FontIncrease':
size += 1
elif signal == 'FontDecrease':
size -= 1
elif signal == 'FontDefault':
size = 0
self.SetZoom(size)
def __config(self):
"""Configure shell based on user preferences."""
self.SetMarginType(1, stc.wxSTC_MARGIN_NUMBER)
self.SetMarginWidth(1, 40)
self.SetLexer(stc.wxSTC_LEX_PYTHON)
self.SetKeyWords(0, ' '.join(keyword.kwlist))
self.setStyles(FACES)
self.SetViewWhiteSpace(False)
self.SetTabWidth(4)
self.SetUseTabs(False)
# Do we want to automatically pop up command completion options?
self.autoComplete = True
self.autoCompleteIncludeMagic = True
self.autoCompleteIncludeSingle = True
self.autoCompleteIncludeDouble = True
self.autoCompleteCaseInsensitive = True
self.AutoCompSetIgnoreCase(self.autoCompleteCaseInsensitive)
self.AutoCompSetAutoHide(False)
self.AutoCompStops(' .,;:([)]}\'"\\<>%^&+-=*/|`')
# Do we want to automatically pop up command argument help?
self.autoCallTip = True
self.CallTipSetBackground(wx.wxColour(255, 255, 232))
self.SetWrapMode(False)
try:
self.SetEndAtLastLine(False)
except AttributeError:
pass
def setStyles(self, faces):
"""Configure font size, typeface and color for lexer."""
# Default style
self.StyleSetSpec(stc.wxSTC_STYLE_DEFAULT,
"face:%(mono)s,size:%(size)d,back:%(backcol)s" % \
faces)
self.StyleClearAll()
# Built in styles
self.StyleSetSpec(stc.wxSTC_STYLE_LINENUMBER,
"back:#C0C0C0,face:%(mono)s,size:%(lnsize)d" % faces)
self.StyleSetSpec(stc.wxSTC_STYLE_CONTROLCHAR,
"face:%(mono)s" % faces)
self.StyleSetSpec(stc.wxSTC_STYLE_BRACELIGHT,
"fore:#0000FF,back:#FFFF88")
self.StyleSetSpec(stc.wxSTC_STYLE_BRACEBAD,
"fore:#FF0000,back:#FFFF88")
# Python styles
self.StyleSetSpec(stc.wxSTC_P_DEFAULT,
"face:%(mono)s" % faces)
self.StyleSetSpec(stc.wxSTC_P_COMMENTLINE,
"fore:#007F00,face:%(mono)s" % faces)
self.StyleSetSpec(stc.wxSTC_P_NUMBER,
"")
self.StyleSetSpec(stc.wxSTC_P_STRING,
"fore:#7F007F,face:%(mono)s" % faces)
self.StyleSetSpec(stc.wxSTC_P_CHARACTER,
"fore:#7F007F,face:%(mono)s" % faces)
self.StyleSetSpec(stc.wxSTC_P_WORD,
"fore:#00007F,bold")
self.StyleSetSpec(stc.wxSTC_P_TRIPLE,
"fore:#7F0000")
self.StyleSetSpec(stc.wxSTC_P_TRIPLEDOUBLE,
"fore:#000033,back:#FFFFE8")
self.StyleSetSpec(stc.wxSTC_P_CLASSNAME,
"fore:#0000FF,bold")
self.StyleSetSpec(stc.wxSTC_P_DEFNAME,
"fore:#007F7F,bold")
self.StyleSetSpec(stc.wxSTC_P_OPERATOR,
"")
self.StyleSetSpec(stc.wxSTC_P_IDENTIFIER,
"")
self.StyleSetSpec(stc.wxSTC_P_COMMENTBLOCK,
"fore:#7F7F7F")
self.StyleSetSpec(stc.wxSTC_P_STRINGEOL,
"fore:#000000,face:%(mono)s,back:#E0C0E0,eolfilled" % faces)
def OnUpdateUI(self, event):
"""Check for matching braces."""
# If the auto-complete window is up let it do its thing.
if self.AutoCompActive() or self.CallTipActive():
return
braceAtCaret = -1
braceOpposite = -1
charBefore = None
caretPos = self.GetCurrentPos()
if caretPos > 0:
charBefore = self.GetCharAt(caretPos - 1)
styleBefore = self.GetStyleAt(caretPos - 1)
# Check before.
if charBefore and chr(charBefore) in '[]{}()' \
and styleBefore == stc.wxSTC_P_OPERATOR:
braceAtCaret = caretPos - 1
# Check after.
if braceAtCaret < 0:
charAfter = self.GetCharAt(caretPos)
styleAfter = self.GetStyleAt(caretPos)
if charAfter and chr(charAfter) in '[]{}()' \
and styleAfter == stc.wxSTC_P_OPERATOR:
braceAtCaret = caretPos
if braceAtCaret >= 0:
braceOpposite = self.BraceMatch(braceAtCaret)
if braceAtCaret != -1 and braceOpposite == -1:
self.BraceBadLight(braceAtCaret)
else:
self.BraceHighlight(braceAtCaret, braceOpposite)
def CanCut(self):
"""Return true if text is selected and can be cut."""
return self.CanCopy()
def CanCopy(self):
"""Return true if text is selected and can be copied."""
return self.GetSelectionStart() != self.GetSelectionEnd()
def CanEdit(self):
"""Return true if editing should succeed."""
return True

View File

@@ -7,8 +7,8 @@ __revision__ = "$Revision$"[11:-2]
from wxPython import wx from wxPython import wx
import base
import dispatcher import dispatcher
import editwindow
import inspect import inspect
import introspect import introspect
import keyword import keyword
@@ -245,7 +245,7 @@ class FillingTree(wx.wxTreeCtrl):
print text print text
class FillingText(base.Editor): class FillingText(editwindow.EditWindow):
"""FillingText based on StyledTextCtrl.""" """FillingText based on StyledTextCtrl."""
name = 'PyFilling Text' name = 'PyFilling Text'
@@ -255,7 +255,7 @@ class FillingText(base.Editor):
size=wx.wxDefaultSize, style=wx.wxCLIP_CHILDREN, size=wx.wxDefaultSize, style=wx.wxCLIP_CHILDREN,
static=False): static=False):
"""Create a FillingText instance.""" """Create a FillingText instance."""
base.Editor.__init__(self, parent, id, pos, size, style) editwindow.EditWindow.__init__(self, parent, id, pos, size, style)
# Configure various defaults and user preferences. # Configure various defaults and user preferences.
self.SetReadOnly(True) self.SetReadOnly(True)
self.SetWrapMode(True) self.SetWrapMode(True)
@@ -269,7 +269,7 @@ class FillingText(base.Editor):
def SetText(self, *args, **kwds): def SetText(self, *args, **kwds):
self.SetReadOnly(False) self.SetReadOnly(False)
base.Editor.SetText(self, *args, **kwds) editwindow.EditWindow.SetText(self, *args, **kwds)
self.SetReadOnly(True) self.SetReadOnly(True)

View File

@@ -18,9 +18,9 @@ import os
import sys import sys
import time import time
import base from buffer import Buffer
import buffer
import dispatcher import dispatcher
import editwindow
import frame import frame
from pseudo import PseudoFileIn from pseudo import PseudoFileIn
from pseudo import PseudoFileOut from pseudo import PseudoFileOut
@@ -71,6 +71,23 @@ class ShellFrame(frame.Frame):
self.shell.destroy() self.shell.destroy()
self.Destroy() self.Destroy()
def OnAbout(self, event):
"""Display an About window."""
title = 'About PyShell'
text = 'PyShell %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()
class ShellFacade: class ShellFacade:
"""Simplified interface to all shell-related functionality. """Simplified interface to all shell-related functionality.
@@ -156,7 +173,7 @@ Ctrl+= Default font size.
return list return list
class Shell(base.Editor): class Shell(editwindow.EditWindow):
"""PyCrust Shell based on StyledTextCtrl.""" """PyCrust Shell based on StyledTextCtrl."""
name = 'PyCrust Shell' name = 'PyCrust Shell'
@@ -166,7 +183,7 @@ class Shell(base.Editor):
size=wx.wxDefaultSize, style=wx.wxCLIP_CHILDREN, size=wx.wxDefaultSize, style=wx.wxCLIP_CHILDREN,
introText='', locals=None, InterpClass=None, *args, **kwds): introText='', locals=None, InterpClass=None, *args, **kwds):
"""Create a PyCrust Shell instance.""" """Create a PyCrust Shell instance."""
base.Editor.__init__(self, parent, id, pos, size, style) editwindow.EditWindow.__init__(self, parent, id, pos, size, style)
self.wrap() self.wrap()
if locals is None: if locals is None:
locals = {} locals = {}
@@ -193,8 +210,7 @@ class Shell(base.Editor):
stderr=PseudoFileErr(self.writeErr), stderr=PseudoFileErr(self.writeErr),
*args, **kwds) *args, **kwds)
# Set up the buffer. # Set up the buffer.
self.buffer = buffer.Buffer(editor=self, interp=self.interp, self.buffer = Buffer()
filename=None)
# 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()
# Keep track of the last non-continuation prompt positions. # Keep track of the last non-continuation prompt positions.
@@ -231,6 +247,10 @@ class Shell(base.Editor):
def destroy(self): def destroy(self):
del self.interp del self.interp
def setFocus(self):
"""Set focus to the shell."""
self.SetFocus()
def OnIdle(self, event): def OnIdle(self, event):
"""Free the CPU to do other things.""" """Free the CPU to do other things."""
if self.waiting: if self.waiting:
@@ -878,7 +898,7 @@ Platform: %s""" % \
def CanPaste(self): def CanPaste(self):
"""Return true if a paste should succeed.""" """Return true if a paste should succeed."""
if self.CanEdit() and base.Editor.CanPaste(self): if self.CanEdit() and editwindow.EditWindow.CanPaste(self):
return True return True
else: else:
return False return False