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:
@@ -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
|
||||||
|
@@ -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)
|
||||||
|
@@ -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
|
||||||
|
@@ -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)
|
||||||
|
@@ -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."""
|
||||||
|
@@ -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()
|
||||||
|
195
wxPython/wxPython/py/editwindow.py
Normal file
195
wxPython/wxPython/py/editwindow.py
Normal 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
|
@@ -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)
|
||||||
|
|
||||||
|
|
||||||
|
@@ -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
|
||||||
|
Reference in New Issue
Block a user