Merged modifications from the 2.6 branch

git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@36607 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775
This commit is contained in:
Robin Dunn
2005-12-30 23:02:03 +00:00
parent a780a8dc19
commit 02b800ce7c
104 changed files with 14102 additions and 46560 deletions

View File

@@ -1,3 +1,81 @@
0.9.5 (12/23/2005)
-------------------
Applied a series of enhancments by Franz Steinaeusler, Adi Sieker, and
Sebastian Haase, up until their 7-31-2005 version. (Their next
version broke some existing functionality, and added some confusing
hacks, and I didn't feel that the incremental gains were worth the
loss at that point so I stopped at 7-31-2005.)
Their changes include the following:
* The Autocomplete and Calltip windows can now be opened manually with
Ctrl-Space and Ctrl-Shift-Space.
* In the stand alone PyCrust app the various option settings, window
size and position, and etc. are saved and restored at the next run.
* Added a help dialog bound to the F1 key that shows the key bindings.
* Added a new text completion function that suggests words from the
history. Bound to Shift-Return.
* F11 will toggle the maximized state of the frame.
* switched to Bind() from wx.EVT_*().
* Display of line numbers can be toggled.
* F12 toggles a "free edit" mode of the shell buffer. This mode is
useful, for example, if you would like to remove some output or
errors or etc. from the buffer before doing a copy/paste. The free
edit mode is designated by the use of a red, non-flashing caret.
* Ctrl-H will fold/unfold (hide/show) the selected lines.
On top of these changes I (Robin Dunn) added the following:
* General code cleanup and fixes.
* Use wx.StandardPaths to determine the location of the config files.
* Remove Orbtech attributions from the UI, they've been there long
enough.
* Use wx.SP_LIVE_UPDATE on crust and filling windows.
* Extended the saving of the config info and other new features to the
PyShell app too. Additionally, other apps that embed a PyCrust or a
PyShell can pass their own wx.Config object and have the Py code
save/restore its settings to/from there.
* All of the classes with config info get an opportunity to save/load
their own settings instead of putting all the save/load code in one
place that then has to reach all over the place to do anything.
* Enable editing of the startup python code, which will either be the
file pointed to by PYTHONSTARTUP or a file in the config dir if
PYTHONSTARTUP is not set in the environment.
* Added an option to skip the running of the startup code when
PyShell or PyCrust starts.
* PyCrust adds a pp(item) function to the shell's namespace that
pretty prints the item in the Display tab of the notebook. Added
code to raise that tab when pp() is called.
* Added an option for whether to insert text for function parameters
when popping up the call tip.
* Added Find and Find-Next functions that use the wx.FindReplaceDialog.
0.9.4 (1/25/2004 to //2004)
------------------------------

View File

@@ -17,15 +17,26 @@ class App(wx.App):
"""PyCrust standalone application."""
def OnInit(self):
import os
import wx
from wx import py
wx.InitAllImageHandlers()
self.frame = py.crust.CrustFrame()
self.frame.SetSize((800, 600))
self.SetAppName("pycrust")
confDir = wx.StandardPaths.Get().GetUserDataDir()
if not os.path.exists(confDir):
os.mkdir(confDir)
fileName = os.path.join(confDir, 'config')
self.config = wx.FileConfig(localFilename=fileName)
self.config.SetRecordDefaults(True)
self.frame = py.crust.CrustFrame(config=self.config, dataDir=confDir)
## self.frame.startupFileName = os.path.join(confDir,'pycrust_startup')
## self.frame.historyFileName = os.path.join(confDir,'pycrust_history')
self.frame.Show()
self.SetTopWindow(self.frame)
return True
'''
The main() function needs to handle being imported, such as with the
pycrust script that wxPython installs:

View File

@@ -17,14 +17,21 @@ class App(wx.App):
"""PyShell standalone application."""
def OnInit(self):
import os
import wx
from wx import py
wx.InitAllImageHandlers()
self.frame = py.shell.ShellFrame()
self.frame.SetSize((750, 525))
self.SetAppName("pyshell")
confDir = wx.StandardPaths.Get().GetUserDataDir()
if not os.path.exists(confDir):
os.mkdir(confDir)
fileName = os.path.join(confDir, 'config')
self.config = wx.FileConfig(localFilename=fileName)
self.config.SetRecordDefaults(True)
self.frame = py.shell.ShellFrame(config=self.config, dataDir=confDir)
self.frame.Show()
self.SetTopWindow(self.frame)
self.frame.shell.SetFocus()
return True
'''

View File

@@ -8,6 +8,7 @@ import wx
import os
import pprint
import re
import sys
import dispatcher
@@ -23,55 +24,95 @@ class Crust(wx.SplitterWindow):
name = 'Crust'
revision = __revision__
sashoffset = 300
def __init__(self, parent, id=-1, pos=wx.DefaultPosition,
size=wx.DefaultSize, style=wx.SP_3D,
def __init__(self, parent, id=-1, pos=wx.DefaultPosition,
size=wx.DefaultSize, style=wx.SP_3D|wx.SP_LIVE_UPDATE,
name='Crust Window', rootObject=None, rootLabel=None,
rootIsNamespace=True, intro='', locals=None,
InterpClass=None, *args, **kwds):
rootIsNamespace=True, intro='', locals=None,
InterpClass=None,
startupScript=None, execStartupScript=True,
*args, **kwds):
"""Create Crust instance."""
wx.SplitterWindow.__init__(self, parent, id, pos, size, style, name)
self.shell = Shell(parent=self, introText=intro,
locals=locals, InterpClass=InterpClass,
self.shell = Shell(parent=self, introText=intro,
locals=locals, InterpClass=InterpClass,
startupScript=startupScript,
execStartupScript=execStartupScript,
*args, **kwds)
self.editor = self.shell
if rootObject is None:
rootObject = self.shell.interp.locals
self.notebook = wx.Notebook(parent=self, id=-1)
self.shell.interp.locals['notebook'] = self.notebook
self.filling = Filling(parent=self.notebook,
rootObject=rootObject,
rootLabel=rootLabel,
self.filling = Filling(parent=self.notebook,
rootObject=rootObject,
rootLabel=rootLabel,
rootIsNamespace=rootIsNamespace)
# Add 'filling' to the interpreter's locals.
self.shell.interp.locals['filling'] = self.filling
self.notebook.AddPage(page=self.filling, text='Namespace', select=True)
self.display = Display(parent=self.notebook)
self.notebook.AddPage(page=self.display, text='Display')
# Add 'pp' (pretty print) to the interpreter's locals.
self.shell.interp.locals['pp'] = self.display.setItem
self.display.nbTab = self.notebook.GetPageCount()-1
self.calltip = Calltip(parent=self.notebook)
self.notebook.AddPage(page=self.calltip, text='Calltip')
self.sessionlisting = SessionListing(parent=self.notebook)
self.notebook.AddPage(page=self.sessionlisting, text='Session')
self.dispatcherlisting = DispatcherListing(parent=self.notebook)
self.notebook.AddPage(page=self.dispatcherlisting, text='Dispatcher')
## from wxd import wx_
## self.wxdocs = Filling(parent=self.notebook,
## rootObject=wx_,
## rootLabel='wx',
## rootIsNamespace=False,
## static=True)
## self.notebook.AddPage(page=self.wxdocs, text='wxPython Docs')
## from wxd import stc_
## self.stcdocs = Filling(parent=self.notebook,
## rootObject=stc_.StyledTextCtrl,
## rootLabel='StyledTextCtrl',
## rootIsNamespace=False,
## static=True)
## self.notebook.AddPage(page=self.stcdocs, text='StyledTextCtrl Docs')
self.SplitHorizontally(self.shell, self.notebook, 300)
self.SetMinimumPaneSize(1)
self.SplitHorizontally(self.shell, self.notebook, -self.sashoffset)
self.SetMinimumPaneSize(100)
self.Bind(wx.EVT_SIZE, self.SplitterOnSize)
self.Bind(wx.EVT_SPLITTER_SASH_POS_CHANGED, self.OnChanged)
def OnChanged(self, event):
"""update sash offset from the bottom of the window"""
self.sashoffset = self.GetSize().height - event.GetSashPosition()
event.Skip()
# Make the splitter expand the top window when resized
def SplitterOnSize(self, event):
splitter = event.GetEventObject()
sz = splitter.GetSize()
splitter.SetSashPosition(sz.height - self.sashoffset, True)
event.Skip()
def LoadSettings(self, config):
self.shell.LoadSettings(config)
self.filling.LoadSettings(config)
pos = config.ReadInt('Sash/CrustPos', 400)
wx.CallAfter(self.SetSashPosition, pos)
def _updateSashPosValue():
sz = self.GetSize()
self.sashoffset = sz.height - self.GetSashPosition()
wx.CallAfter(_updateSashPosValue)
zoom = config.ReadInt('View/Zoom/Display', -99)
if zoom != -99:
self.display.SetZoom(zoom)
def SaveSettings(self, config):
self.shell.SaveSettings(config)
self.filling.SaveSettings(config)
config.WriteInt('Sash/CrustPos', self.GetSashPosition())
config.WriteInt('View/Zoom/Display', self.display.GetZoom())
class Display(editwindow.EditWindow):
@@ -105,15 +146,20 @@ class Display(editwindow.EditWindow):
"""Set item to pretty print in the notebook Display tab."""
self.item = item
self.Refresh()
if self.GetParent().GetSelection() != self.nbTab:
focus = wx.Window.FindFocus()
self.GetParent().SetSelection(self.nbTab)
wx.CallAfter(focus.SetFocus)
# TODO: Switch this to a editwindow.EditWindow
class Calltip(wx.TextCtrl):
"""Text control containing the most recent shell calltip."""
def __init__(self, parent=None, id=-1):
style = (wx.TE_MULTILINE | wx.TE_READONLY | wx.TE_RICH2)
wx.TextCtrl.__init__(self, parent, id, style=style)
self.SetBackgroundColour(wx.Colour(255, 255, 232))
self.SetBackgroundColour(wx.Colour(255, 255, 208))
dispatcher.connect(receiver=self.display, signal='Shell.calltip')
def display(self, calltip):
@@ -123,6 +169,7 @@ class Calltip(wx.TextCtrl):
self.AppendText(calltip)
# TODO: Switch this to a editwindow.EditWindow
class SessionListing(wx.TextCtrl):
"""Text control containing all commands for session."""
@@ -161,44 +208,58 @@ class DispatcherListing(wx.TextCtrl):
self.AppendText(text + '\n')
class CrustFrame(frame.Frame):
class CrustFrame(frame.Frame, frame.ShellFrameMixin):
"""Frame containing all the PyCrust components."""
name = 'CrustFrame'
revision = __revision__
def __init__(self, parent=None, id=-1, title='PyCrust',
pos=wx.DefaultPosition, size=wx.DefaultSize,
style=wx.DEFAULT_FRAME_STYLE,
rootObject=None, rootLabel=None, rootIsNamespace=True,
locals=None, InterpClass=None, *args, **kwds):
locals=None, InterpClass=None,
config=None, dataDir=None,
*args, **kwds):
"""Create CrustFrame instance."""
frame.Frame.__init__(self, parent, id, title, pos, size, style)
frame.ShellFrameMixin.__init__(self, config, dataDir)
if size == wx.DefaultSize:
self.SetSize((800, 600))
intro = 'PyCrust %s - The Flakiest Python Shell' % VERSION
intro += '\nSponsored by Orbtech - '
intro += 'Your source for Python programming expertise.'
self.SetStatusText(intro.replace('\n', ', '))
self.crust = Crust(parent=self, intro=intro,
rootObject=rootObject,
rootLabel=rootLabel,
rootIsNamespace=rootIsNamespace,
locals=locals,
InterpClass=InterpClass, *args, **kwds)
InterpClass=InterpClass,
startupScript=self.startupScript,
execStartupScript=self.execStartupScript,
*args, **kwds)
self.shell = self.crust.shell
# Override the filling so that status messages go to the status bar.
self.crust.filling.tree.setStatusText = self.SetStatusText
# Override the shell so that status messages go to the status bar.
self.shell.setStatusText = self.SetStatusText
# Fix a problem with the sash shrinking to nothing.
self.crust.filling.SetSashPosition(200)
# Set focus to the shell editor.
self.shell.SetFocus()
self.LoadSettings()
def OnClose(self, event):
"""Event handler for closing."""
self.SaveSettings()
self.crust.shell.destroy()
self.Destroy()
def OnAbout(self, event):
"""Display an About window."""
title = 'About PyCrust'
@@ -211,8 +272,33 @@ class CrustFrame(frame.Frame):
'Platform: %s\n' % sys.platform + \
'Python Version: %s\n' % sys.version.split()[0] + \
'wxPython Version: %s\n' % wx.VERSION_STRING + \
('\t(%s)\n' % ", ".join(wx.PlatformInfo[1:]))
('\t(%s)\n' % ", ".join(wx.PlatformInfo[1:]))
dialog = wx.MessageDialog(self, text, title,
wx.OK | wx.ICON_INFORMATION)
dialog.ShowModal()
dialog.Destroy()
def LoadSettings(self):
if self.config is not None:
frame.ShellFrameMixin.LoadSettings(self)
frame.Frame.LoadSettings(self, self.config)
self.crust.LoadSettings(self.config)
def SaveSettings(self):
if self.config is not None:
frame.ShellFrameMixin.SaveSettings(self)
if self.autoSaveSettings:
frame.Frame.SaveSettings(self, self.config)
self.crust.SaveSettings(self.config)
def DoSaveSettings(self):
if self.config is not None:
self.SaveSettings()
self.config.Flush()

View File

@@ -30,7 +30,7 @@ class EditorFrame(frame.Frame):
self._defaultText = title + ' - the tastiest Python editor.'
self._statusText = self._defaultText
self.SetStatusText(self._statusText)
wx.EVT_IDLE(self, self.OnIdle)
self.Bind(wx.EVT_IDLE, self.OnIdle)
self._setup()
if filename:
self.bufferCreate(filename)
@@ -137,7 +137,7 @@ class EditorFrame(frame.Frame):
self.bufferDestroy()
buffer = Buffer()
self.panel = panel = wx.Panel(parent=self, id=-1)
wx.EVT_ERASE_BACKGROUND(panel, lambda x: x)
panel.Bind (wx.EVT_ERASE_BACKGROUND, lambda x: x)
editor = Editor(parent=panel)
panel.editor = editor
sizer = wx.BoxSizer(wx.VERTICAL)
@@ -318,7 +318,7 @@ class EditorNotebookFrame(EditorFrame):
"""Create new buffer."""
buffer = Buffer()
panel = wx.Panel(parent=self.notebook, id=-1)
wx.EVT_ERASE_BACKGROUND(panel, lambda x: x)
panel.Bind(wx.EVT_ERASE_BACKGROUND, lambda x: x)
editor = Editor(parent=panel)
panel.editor = editor
sizer = wx.BoxSizer(wx.VERTICAL)
@@ -366,11 +366,9 @@ class EditorNotebook(wx.Notebook):
def __init__(self, parent):
"""Create EditorNotebook instance."""
wx.Notebook.__init__(self, parent, id=-1, style=wx.CLIP_CHILDREN)
wx.EVT_NOTEBOOK_PAGE_CHANGING(self, self.GetId(),
self.OnPageChanging)
wx.EVT_NOTEBOOK_PAGE_CHANGED(self, self.GetId(),
self.OnPageChanged)
wx.EVT_IDLE(self, self.OnIdle)
self.Bind(wx.EVT_NOTEBOOK_PAGE_CHANGING, self.OnPageChanging, id=self.GetId())
self.Bind(wx.EVT_NOTEBOOK_PAGE_CHANGED, self.OnPageChanged, id=self.GetId())
self.Bind(wx.EVT_IDLE, self.OnIdle)
def OnIdle(self, event):
"""Event handler for idle time."""
@@ -552,7 +550,7 @@ class EditorShellNotebook(wx.Notebook):
self.AddPage(page=self.editor.window, text='Editor', select=True)
self.AddPage(page=self.shell, text='Shell')
self.editor.setFocus()
wx.EVT_NOTEBOOK_PAGE_CHANGED(self, self.GetId(), self.OnPageChanged)
self.Bind(wx.EVT_NOTEBOOK_PAGE_CHANGED, self.OnPageChanged, id=self.GetId())
def OnPageChanged(self, event):
"""Page changed event handler."""
@@ -583,8 +581,8 @@ class Editor:
self.id = self.window.GetId()
self.buffer = None
# Assign handlers for keyboard events.
wx.EVT_CHAR(self.window, self.OnChar)
wx.EVT_KEY_DOWN(self.window, self.OnKeyDown)
self.window.Bind(wx.EVT_CHAR, self.OnChar)
self.window.Bind(wx.EVT_KEY_DOWN, self.OnKeyDown)
def _setBuffer(self, buffer, text):
"""Set the editor to a buffer. Private callback called by buffer."""

View File

@@ -92,11 +92,10 @@ class EditWindow(stc.StyledTextCtrl):
size = 0
self.SetZoom(size)
def __config(self):
"""Configure shell based on user preferences."""
self.SetMarginType(1, stc.STC_MARGIN_NUMBER)
self.SetMarginWidth(1, 40)
def __config(self):
self.setDisplayLineNumbers(False)
self.SetLexer(stc.STC_LEX_PYTHON)
self.SetKeyWords(0, ' '.join(keyword.kwlist))
@@ -116,6 +115,7 @@ class EditWindow(stc.StyledTextCtrl):
self.AutoCompStops(' .,;:([)]}\'"\\<>%^&+-=*/|`')
# Do we want to automatically pop up command argument help?
self.autoCallTip = True
self.callTipInsert = True
self.CallTipSetBackground(FACES['calltipbg'])
self.CallTipSetForeground(FACES['calltipfg'])
self.SetWrapMode(False)
@@ -124,6 +124,16 @@ class EditWindow(stc.StyledTextCtrl):
except AttributeError:
pass
def setDisplayLineNumbers(self, state):
self.lineNumbers = state
if state:
self.SetMarginType(1, stc.STC_MARGIN_NUMBER)
self.SetMarginWidth(1, 40)
else:
# Leave a small margin so the feature hidden lines marker can be seen
self.SetMarginType(1, 0)
self.SetMarginWidth(1, 10)
def setStyles(self, faces):
"""Configure font size, typeface and color for lexer."""
@@ -136,7 +146,7 @@ class EditWindow(stc.StyledTextCtrl):
# Built in styles
self.StyleSetSpec(stc.STC_STYLE_LINENUMBER,
"back:#C0C0C0,face:%(mono)s,size:%(lnsize)d" % faces)
"back:#C0C0C0,face:%(mono)s,size:%(lnsize)d" % FACES)
self.StyleSetSpec(stc.STC_STYLE_CONTROLCHAR,
"face:%(mono)s" % faces)
self.StyleSetSpec(stc.STC_STYLE_BRACELIGHT,
@@ -223,3 +233,65 @@ class EditWindow(stc.StyledTextCtrl):
def CanPaste(self):
"""Return True if pasting should succeed."""
return stc.StyledTextCtrl.CanPaste(self) and self.CanEdit()
def GetLastPosition(self):
return self.GetLength()
def GetRange(self, start, end):
return self.GetTextRange(start, end)
def GetSelection(self):
return self.GetAnchor(), self.GetCurrentPos()
def SetSelection(self, start, end):
self.SetSelectionStart(start)
self.SetSelectionEnd(end)
def ShowPosition(self, pos):
line = self.LineFromPosition(pos)
#self.EnsureVisible(line)
self.GotoLine(line)
def DoFindNext(self, findData, findDlg=None):
backward = not (findData.GetFlags() & wx.FR_DOWN)
matchcase = findData.GetFlags() & wx.FR_MATCHCASE
end = self.GetLastPosition()
textstring = self.GetRange(0, end)
findstring = findData.GetFindString()
if not matchcase:
textstring.lower()
findstring.lower()
if backward:
start = self.GetSelection()[0]
loc = textstring.rfind(findstring, 0, start)
else:
start = self.GetSelection()[1]
loc = textstring.find(findstring, start)
# if it wasn't found then restart at begining
if loc == -1 and start != 0:
if backward:
start = end
loc = textstring.rfind(findstring, 0, start)
else:
start = 0
loc = textstring.find(findstring, start)
# was it still not found?
if loc == -1:
dlg = wx.MessageDialog(self, 'Unable to find the search text.',
'Not found!',
wx.OK | wx.ICON_INFORMATION)
dlg.ShowModal()
dlg.Destroy()
if findDlg:
if loc == -1:
wx.CallAfter(findDlg.SetFocus)
return
else:
findDlg.Close()
# show and select the found text
self.ShowPosition(loc)
self.SetSelection(loc, loc + len(findstring))

View File

@@ -61,10 +61,10 @@ class FillingTree(wx.TreeCtrl):
rootData = wx.TreeItemData(rootObject)
self.item = self.root = self.AddRoot(rootLabel, -1, -1, rootData)
self.SetItemHasChildren(self.root, self.objHasChildren(rootObject))
wx.EVT_TREE_ITEM_EXPANDING(self, self.GetId(), self.OnItemExpanding)
wx.EVT_TREE_ITEM_COLLAPSED(self, self.GetId(), self.OnItemCollapsed)
wx.EVT_TREE_SEL_CHANGED(self, self.GetId(), self.OnSelChanged)
wx.EVT_TREE_ITEM_ACTIVATED(self, self.GetId(), self.OnItemActivated)
self.Bind(wx.EVT_TREE_ITEM_EXPANDING, self.OnItemExpanding, id=self.GetId())
self.Bind(wx.EVT_TREE_ITEM_COLLAPSED, self.OnItemCollapsed, id=self.GetId())
self.Bind(wx.EVT_TREE_SEL_CHANGED, self.OnSelChanged, id=self.GetId())
self.Bind(wx.EVT_TREE_ITEM_ACTIVATED, self.OnItemActivated, id=self.GetId())
if not static:
dispatcher.connect(receiver=self.push, signal='Interpreter.push')
@@ -277,24 +277,49 @@ class Filling(wx.SplitterWindow):
revision = __revision__
def __init__(self, parent, id=-1, pos=wx.DefaultPosition,
size=wx.DefaultSize, style=wx.SP_3D,
size=wx.DefaultSize, style=wx.SP_3D|wx.SP_LIVE_UPDATE,
name='Filling Window', rootObject=None,
rootLabel=None, rootIsNamespace=False, static=False):
"""Create a Filling instance."""
wx.SplitterWindow.__init__(self, parent, id, pos, size, style, name)
self.tree = FillingTree(parent=self, rootObject=rootObject,
rootLabel=rootLabel,
rootIsNamespace=rootIsNamespace,
static=static)
self.text = FillingText(parent=self, static=static)
self.SplitVertically(self.tree, self.text, 130)
wx.FutureCall(1, self.SplitVertically, self.tree, self.text, 200)
self.SetMinimumPaneSize(1)
# Override the filling so that descriptions go to FillingText.
self.tree.setText = self.text.SetText
# Display the root item.
## self.tree.SelectItem(self.tree.root)
self.tree.SelectItem(self.tree.root)
self.tree.display()
self.Bind(wx.EVT_SPLITTER_SASH_POS_CHANGED, self.OnChanged)
def OnChanged(self, event):
#this is important: do not evaluate this event=> otherwise, splitterwindow behaves strange
#event.Skip()
pass
def LoadSettings(self, config):
pos = config.ReadInt('Sash/FillingPos', 200)
wx.FutureCall(250, self.SetSashPosition, pos)
zoom = config.ReadInt('View/Zoom/Filling', -99)
if zoom != -99:
self.text.SetZoom(zoom)
def SaveSettings(self, config):
config.WriteInt('Sash/FillingPos', self.GetSashPosition())
config.WriteInt('View/Zoom/Filling', self.text.GetZoom())
class FillingFrame(wx.Frame):
"""Frame containing the namespace tree component."""

View File

@@ -5,8 +5,9 @@ __cvsid__ = "$Id$"
__revision__ = "$Revision$"[11:-2]
import wx
import os
from version import VERSION
import editwindow
ID_NEW = wx.ID_NEW
ID_OPEN = wx.ID_OPEN
@@ -23,7 +24,9 @@ ID_COPY = wx.ID_COPY
ID_PASTE = wx.ID_PASTE
ID_CLEAR = wx.ID_CLEAR
ID_SELECTALL = wx.ID_SELECTALL
ID_EMPTYBUFFER = wx.NewId()
ID_ABOUT = wx.ID_ABOUT
ID_HELP = wx.NewId()
ID_AUTOCOMP = wx.NewId()
ID_AUTOCOMP_SHOW = wx.NewId()
ID_AUTOCOMP_MAGIC = wx.NewId()
@@ -31,11 +34,25 @@ ID_AUTOCOMP_SINGLE = wx.NewId()
ID_AUTOCOMP_DOUBLE = wx.NewId()
ID_CALLTIPS = wx.NewId()
ID_CALLTIPS_SHOW = wx.NewId()
ID_CALLTIPS_INSERT = wx.NewId()
ID_COPY_PLUS = wx.NewId()
ID_NAMESPACE = wx.NewId()
ID_PASTE_PLUS = wx.NewId()
ID_WRAP = wx.NewId()
ID_TOGGLE_MAXIMIZE = wx.NewId()
ID_USEAA = wx.NewId()
ID_SHOW_LINENUMBERS = wx.NewId()
ID_AUTO_SAVESETTINGS = wx.NewId()
ID_SAVEHISTORY = wx.NewId()
ID_SAVESETTINGS = wx.NewId()
ID_DELSETTINGSFILE = wx.NewId()
ID_EDITSTARTUPSCRIPT = wx.NewId()
ID_EXECSTARTUPSCRIPT = wx.NewId()
ID_STARTUP = wx.NewId()
ID_SETTINGS = wx.NewId()
ID_FIND = wx.ID_FIND
ID_FINDNEXT = wx.NewId()
class Frame(wx.Frame):
@@ -53,13 +70,28 @@ class Frame(wx.Frame):
import images
self.SetIcon(images.getPyIcon())
self.__createMenus()
wx.EVT_CLOSE(self, self.OnClose)
self.iconized = False
self.findDlg = None
self.findData = wx.FindReplaceData()
self.findData.SetFlags(wx.FR_DOWN)
self.Bind(wx.EVT_CLOSE, self.OnClose)
self.Bind(wx.EVT_ICONIZE, self.OnIconize)
def OnIconize(self, event):
"""Event handler for Iconize."""
self.iconized = event.Iconized()
def OnClose(self, event):
"""Event handler for closing."""
self.Destroy()
def __createMenus(self):
# File Menu
m = self.fileMenu = wx.Menu()
m.Append(ID_NEW, '&New \tCtrl+N',
'New file')
@@ -73,17 +105,18 @@ class Frame(wx.Frame):
m.AppendSeparator()
m.Append(ID_SAVE, '&Save... \tCtrl+S',
'Save file')
m.Append(ID_SAVEAS, 'Save &As \tShift+Ctrl+S',
m.Append(ID_SAVEAS, 'Save &As \tCtrl+Shift+S',
'Save file with new name')
m.AppendSeparator()
m.Append(ID_PRINT, '&Print... \tCtrl+P',
'Print file')
m.AppendSeparator()
m.Append(ID_NAMESPACE, '&Update Namespace \tShift+Ctrl+N',
m.Append(ID_NAMESPACE, '&Update Namespace \tCtrl+Shift+N',
'Update namespace for autocompletion and calltips')
m.AppendSeparator()
m.Append(ID_EXIT, 'E&xit', 'Exit Program')
m.Append(ID_EXIT, 'E&xit\tCtrl+Q', 'Exit Program')
# Edit
m = self.editMenu = wx.Menu()
m.Append(ID_UNDO, '&Undo \tCtrl+Z',
'Undo the last action')
@@ -94,105 +127,175 @@ class Frame(wx.Frame):
'Cut the selection')
m.Append(ID_COPY, '&Copy \tCtrl+C',
'Copy the selection')
m.Append(ID_COPY_PLUS, 'Cop&y Plus \tShift+Ctrl+C',
m.Append(ID_COPY_PLUS, 'Cop&y Plus \tCtrl+Shift+C',
'Copy the selection - retaining prompts')
m.Append(ID_PASTE, '&Paste \tCtrl+V', 'Paste from clipboard')
m.Append(ID_PASTE_PLUS, 'Past&e Plus \tShift+Ctrl+V',
m.Append(ID_PASTE_PLUS, 'Past&e Plus \tCtrl+Shift+V',
'Paste and run commands')
m.AppendSeparator()
m.Append(ID_CLEAR, 'Cle&ar',
'Delete the selection')
m.Append(ID_SELECTALL, 'Select A&ll \tCtrl+A',
'Select all text')
m.AppendSeparator()
m.Append(ID_EMPTYBUFFER, 'E&mpty Buffer',
'Delete all the contents of the edit buffer')
m.Append(ID_FIND, '&Find Text \tCtrl+F',
'Search for text in the edit buffer')
m.Append(ID_FINDNEXT, 'Find &Next \tF3',
'Find next/previous instance of the search text')
# View
m = self.viewMenu = wx.Menu()
m.Append(ID_WRAP, '&Wrap Lines\tCtrl+Shift+W',
'Wrap lines at right edge', wx.ITEM_CHECK)
m.Append(ID_SHOW_LINENUMBERS, '&Show Line Numbers\tCtrl+Shift+L', 'Show Line Numbers', wx.ITEM_CHECK)
m.Append(ID_TOGGLE_MAXIMIZE, '&Toggle Maximize\tF11', 'Maximize/Restore Application')
# Options
m = self.autocompMenu = wx.Menu()
m.Append(ID_AUTOCOMP_SHOW, 'Show Auto Completion',
m.Append(ID_AUTOCOMP_SHOW, 'Show &Auto Completion\tCtrl+Shift+A',
'Show auto completion list', wx.ITEM_CHECK)
m.Append(ID_AUTOCOMP_MAGIC, 'Include Magic Attributes',
m.Append(ID_AUTOCOMP_MAGIC, 'Include &Magic Attributes\tCtrl+Shift+M',
'Include attributes visible to __getattr__ and __setattr__',
wx.ITEM_CHECK)
m.Append(ID_AUTOCOMP_SINGLE, 'Include Single Underscores',
m.Append(ID_AUTOCOMP_SINGLE, 'Include Single &Underscores\tCtrl+Shift+U',
'Include attibutes prefixed by a single underscore', wx.ITEM_CHECK)
m.Append(ID_AUTOCOMP_DOUBLE, 'Include Double Underscores',
m.Append(ID_AUTOCOMP_DOUBLE, 'Include &Double Underscores\tCtrl+Shift+D',
'Include attibutes prefixed by a double underscore', wx.ITEM_CHECK)
m = self.calltipsMenu = wx.Menu()
m.Append(ID_CALLTIPS_SHOW, 'Show Call Tips',
m.Append(ID_CALLTIPS_SHOW, 'Show Call &Tips\tCtrl+Shift+T',
'Show call tips with argument signature and docstring', wx.ITEM_CHECK)
m.Append(ID_CALLTIPS_INSERT, '&Insert Call Tips\tCtrl+Shift+I',
'&Insert Call Tips', wx.ITEM_CHECK)
m = self.optionsMenu = wx.Menu()
m.AppendMenu(ID_AUTOCOMP, '&Auto Completion', self.autocompMenu,
'Auto Completion Options')
m.AppendMenu(ID_CALLTIPS, '&Call Tips', self.calltipsMenu,
'Call Tip Options')
m.Append(ID_WRAP, '&Wrap Lines',
'Wrap lines at right edge', wx.ITEM_CHECK)
if wx.Platform == "__WXMAC__":
m.Append(ID_USEAA, '&Use AntiAliasing',
m.Append(ID_USEAA, '&Use AntiAliasing\tCtrl+Shift+A',
'Use anti-aliased fonts', wx.ITEM_CHECK)
m.AppendSeparator()
m.Append(ID_SAVEHISTORY, '&Save History\tAlt+Ctrl+A', 'Automatically save history on close', wx.ITEM_CHECK)
self.startupMenu = wx.Menu()
self.startupMenu.Append(ID_EXECSTARTUPSCRIPT, 'E&xecute Startup Script\tAlt+Ctrl+X', 'Execute Startup Script', wx.ITEM_CHECK)
self.startupMenu.Append(ID_EDITSTARTUPSCRIPT, '&Edit Startup Script\tAlt+Ctrl+E', 'Edit Startup Script')
m.AppendMenu(ID_STARTUP, '&Startup', self.startupMenu, 'Startup Options')
self.settingsMenu = wx.Menu()
self.settingsMenu.Append(ID_AUTO_SAVESETTINGS, '&Auto Save Settings\tAlt+Ctrl+A', 'Automatically save settings on close', wx.ITEM_CHECK)
self.settingsMenu.Append(ID_SAVESETTINGS, '&Save Settings\tAlt+Ctrl+S', 'Save settings now')
self.settingsMenu.Append(ID_DELSETTINGSFILE, '&Revert to default\tAlt+Ctrl+R', 'Revert to the default settings')
m.AppendMenu(ID_SETTINGS, '&Settings', self.settingsMenu, 'Settings Options')
m = self.helpMenu = wx.Menu()
m.Append(ID_HELP, '&Help\tF1', 'Help!')
m.AppendSeparator()
m.Append(ID_ABOUT, '&About...', 'About this program')
m.Append(ID_ABOUT, '&About...\tAlt+A', 'About this program')
b = self.menuBar = wx.MenuBar()
b.Append(self.fileMenu, '&File')
b.Append(self.editMenu, '&Edit')
b.Append(self.viewMenu, '&View')
b.Append(self.optionsMenu, '&Options')
b.Append(self.helpMenu, '&Help')
self.SetMenuBar(b)
wx.EVT_MENU(self, ID_NEW, self.OnFileNew)
wx.EVT_MENU(self, ID_OPEN, self.OnFileOpen)
wx.EVT_MENU(self, ID_REVERT, self.OnFileRevert)
wx.EVT_MENU(self, ID_CLOSE, self.OnFileClose)
wx.EVT_MENU(self, ID_SAVE, self.OnFileSave)
wx.EVT_MENU(self, ID_SAVEAS, self.OnFileSaveAs)
wx.EVT_MENU(self, ID_NAMESPACE, self.OnFileUpdateNamespace)
wx.EVT_MENU(self, ID_PRINT, self.OnFilePrint)
wx.EVT_MENU(self, ID_EXIT, self.OnExit)
wx.EVT_MENU(self, ID_UNDO, self.OnUndo)
wx.EVT_MENU(self, ID_REDO, self.OnRedo)
wx.EVT_MENU(self, ID_CUT, self.OnCut)
wx.EVT_MENU(self, ID_COPY, self.OnCopy)
wx.EVT_MENU(self, ID_COPY_PLUS, self.OnCopyPlus)
wx.EVT_MENU(self, ID_PASTE, self.OnPaste)
wx.EVT_MENU(self, ID_PASTE_PLUS, self.OnPastePlus)
wx.EVT_MENU(self, ID_CLEAR, self.OnClear)
wx.EVT_MENU(self, ID_SELECTALL, self.OnSelectAll)
wx.EVT_MENU(self, ID_ABOUT, self.OnAbout)
wx.EVT_MENU(self, ID_AUTOCOMP_SHOW, self.OnAutoCompleteShow)
wx.EVT_MENU(self, ID_AUTOCOMP_MAGIC, self.OnAutoCompleteMagic)
wx.EVT_MENU(self, ID_AUTOCOMP_SINGLE, self.OnAutoCompleteSingle)
wx.EVT_MENU(self, ID_AUTOCOMP_DOUBLE, self.OnAutoCompleteDouble)
wx.EVT_MENU(self, ID_CALLTIPS_SHOW, self.OnCallTipsShow)
wx.EVT_MENU(self, ID_WRAP, self.OnWrap)
wx.EVT_MENU(self, ID_USEAA, self.OnUseAA)
self.Bind(wx.EVT_MENU, self.OnFileNew, id=ID_NEW)
self.Bind(wx.EVT_MENU, self.OnFileOpen, id=ID_OPEN)
self.Bind(wx.EVT_MENU, self.OnFileRevert, id=ID_REVERT)
self.Bind(wx.EVT_MENU, self.OnFileClose, id=ID_CLOSE)
self.Bind(wx.EVT_MENU, self.OnFileSave, id=ID_SAVE)
self.Bind(wx.EVT_MENU, self.OnFileSaveAs, id=ID_SAVEAS)
self.Bind(wx.EVT_MENU, self.OnFileUpdateNamespace, id=ID_NAMESPACE)
self.Bind(wx.EVT_MENU, self.OnFilePrint, id=ID_PRINT)
self.Bind(wx.EVT_MENU, self.OnExit, id=ID_EXIT)
self.Bind(wx.EVT_MENU, self.OnUndo, id=ID_UNDO)
self.Bind(wx.EVT_MENU, self.OnRedo, id=ID_REDO)
self.Bind(wx.EVT_MENU, self.OnCut, id=ID_CUT)
self.Bind(wx.EVT_MENU, self.OnCopy, id=ID_COPY)
self.Bind(wx.EVT_MENU, self.OnCopyPlus, id=ID_COPY_PLUS)
self.Bind(wx.EVT_MENU, self.OnPaste, id=ID_PASTE)
self.Bind(wx.EVT_MENU, self.OnPastePlus, id=ID_PASTE_PLUS)
self.Bind(wx.EVT_MENU, self.OnClear, id=ID_CLEAR)
self.Bind(wx.EVT_MENU, self.OnSelectAll, id=ID_SELECTALL)
self.Bind(wx.EVT_MENU, self.OnEmptyBuffer, id=ID_EMPTYBUFFER)
self.Bind(wx.EVT_MENU, self.OnAbout, id=ID_ABOUT)
self.Bind(wx.EVT_MENU, self.OnHelp, id=ID_HELP)
self.Bind(wx.EVT_MENU, self.OnAutoCompleteShow, id=ID_AUTOCOMP_SHOW)
self.Bind(wx.EVT_MENU, self.OnAutoCompleteMagic, id=ID_AUTOCOMP_MAGIC)
self.Bind(wx.EVT_MENU, self.OnAutoCompleteSingle, id=ID_AUTOCOMP_SINGLE)
self.Bind(wx.EVT_MENU, self.OnAutoCompleteDouble, id=ID_AUTOCOMP_DOUBLE)
self.Bind(wx.EVT_MENU, self.OnCallTipsShow, id=ID_CALLTIPS_SHOW)
self.Bind(wx.EVT_MENU, self.OnCallTipsInsert, id=ID_CALLTIPS_INSERT)
self.Bind(wx.EVT_MENU, self.OnWrap, id=ID_WRAP)
self.Bind(wx.EVT_MENU, self.OnUseAA, id=ID_USEAA)
self.Bind(wx.EVT_MENU, self.OnToggleMaximize, id=ID_TOGGLE_MAXIMIZE)
self.Bind(wx.EVT_MENU, self.OnShowLineNumbers, id=ID_SHOW_LINENUMBERS)
self.Bind(wx.EVT_MENU, self.OnAutoSaveSettings, id=ID_AUTO_SAVESETTINGS)
self.Bind(wx.EVT_MENU, self.OnSaveHistory, id=ID_SAVEHISTORY)
self.Bind(wx.EVT_MENU, self.OnSaveSettings, id=ID_SAVESETTINGS)
self.Bind(wx.EVT_MENU, self.OnDelSettingsFile, id=ID_DELSETTINGSFILE)
self.Bind(wx.EVT_MENU, self.OnEditStartupScript, id=ID_EDITSTARTUPSCRIPT)
self.Bind(wx.EVT_MENU, self.OnExecStartupScript, id=ID_EXECSTARTUPSCRIPT)
self.Bind(wx.EVT_MENU, self.OnFindText, id=ID_FIND)
self.Bind(wx.EVT_MENU, self.OnFindNext, id=ID_FINDNEXT)
wx.EVT_UPDATE_UI(self, ID_NEW, self.OnUpdateMenu)
wx.EVT_UPDATE_UI(self, ID_OPEN, self.OnUpdateMenu)
wx.EVT_UPDATE_UI(self, ID_REVERT, self.OnUpdateMenu)
wx.EVT_UPDATE_UI(self, ID_CLOSE, self.OnUpdateMenu)
wx.EVT_UPDATE_UI(self, ID_SAVE, self.OnUpdateMenu)
wx.EVT_UPDATE_UI(self, ID_SAVEAS, self.OnUpdateMenu)
wx.EVT_UPDATE_UI(self, ID_NAMESPACE, self.OnUpdateMenu)
wx.EVT_UPDATE_UI(self, ID_PRINT, self.OnUpdateMenu)
wx.EVT_UPDATE_UI(self, ID_UNDO, self.OnUpdateMenu)
wx.EVT_UPDATE_UI(self, ID_REDO, self.OnUpdateMenu)
wx.EVT_UPDATE_UI(self, ID_CUT, self.OnUpdateMenu)
wx.EVT_UPDATE_UI(self, ID_COPY, self.OnUpdateMenu)
wx.EVT_UPDATE_UI(self, ID_COPY_PLUS, self.OnUpdateMenu)
wx.EVT_UPDATE_UI(self, ID_PASTE, self.OnUpdateMenu)
wx.EVT_UPDATE_UI(self, ID_PASTE_PLUS, self.OnUpdateMenu)
wx.EVT_UPDATE_UI(self, ID_CLEAR, self.OnUpdateMenu)
wx.EVT_UPDATE_UI(self, ID_SELECTALL, self.OnUpdateMenu)
wx.EVT_UPDATE_UI(self, ID_AUTOCOMP_SHOW, self.OnUpdateMenu)
wx.EVT_UPDATE_UI(self, ID_AUTOCOMP_MAGIC, self.OnUpdateMenu)
wx.EVT_UPDATE_UI(self, ID_AUTOCOMP_SINGLE, self.OnUpdateMenu)
wx.EVT_UPDATE_UI(self, ID_AUTOCOMP_DOUBLE, self.OnUpdateMenu)
wx.EVT_UPDATE_UI(self, ID_CALLTIPS_SHOW, self.OnUpdateMenu)
wx.EVT_UPDATE_UI(self, ID_WRAP, self.OnUpdateMenu)
wx.EVT_UPDATE_UI(self, ID_USEAA, self.OnUpdateMenu)
self.Bind(wx.EVT_UPDATE_UI, self.OnUpdateMenu, id=ID_NEW)
self.Bind(wx.EVT_UPDATE_UI, self.OnUpdateMenu, id=ID_OPEN)
self.Bind(wx.EVT_UPDATE_UI, self.OnUpdateMenu, id=ID_REVERT)
self.Bind(wx.EVT_UPDATE_UI, self.OnUpdateMenu, id=ID_CLOSE)
self.Bind(wx.EVT_UPDATE_UI, self.OnUpdateMenu, id=ID_SAVE)
self.Bind(wx.EVT_UPDATE_UI, self.OnUpdateMenu, id=ID_SAVEAS)
self.Bind(wx.EVT_UPDATE_UI, self.OnUpdateMenu, id=ID_NAMESPACE)
self.Bind(wx.EVT_UPDATE_UI, self.OnUpdateMenu, id=ID_PRINT)
self.Bind(wx.EVT_UPDATE_UI, self.OnUpdateMenu, id=ID_UNDO)
self.Bind(wx.EVT_UPDATE_UI, self.OnUpdateMenu, id=ID_REDO)
self.Bind(wx.EVT_UPDATE_UI, self.OnUpdateMenu, id=ID_CUT)
self.Bind(wx.EVT_UPDATE_UI, self.OnUpdateMenu, id=ID_COPY)
self.Bind(wx.EVT_UPDATE_UI, self.OnUpdateMenu, id=ID_COPY_PLUS)
self.Bind(wx.EVT_UPDATE_UI, self.OnUpdateMenu, id=ID_PASTE)
self.Bind(wx.EVT_UPDATE_UI, self.OnUpdateMenu, id=ID_PASTE_PLUS)
self.Bind(wx.EVT_UPDATE_UI, self.OnUpdateMenu, id=ID_CLEAR)
self.Bind(wx.EVT_UPDATE_UI, self.OnUpdateMenu, id=ID_SELECTALL)
self.Bind(wx.EVT_UPDATE_UI, self.OnUpdateMenu, id=ID_EMPTYBUFFER)
self.Bind(wx.EVT_UPDATE_UI, self.OnUpdateMenu, id=ID_AUTOCOMP_SHOW)
self.Bind(wx.EVT_UPDATE_UI, self.OnUpdateMenu, id=ID_AUTOCOMP_MAGIC)
self.Bind(wx.EVT_UPDATE_UI, self.OnUpdateMenu, id=ID_AUTOCOMP_SINGLE)
self.Bind(wx.EVT_UPDATE_UI, self.OnUpdateMenu, id=ID_AUTOCOMP_DOUBLE)
self.Bind(wx.EVT_UPDATE_UI, self.OnUpdateMenu, id=ID_CALLTIPS_SHOW)
self.Bind(wx.EVT_UPDATE_UI, self.OnUpdateMenu, id=ID_CALLTIPS_INSERT)
self.Bind(wx.EVT_UPDATE_UI, self.OnUpdateMenu, id=ID_WRAP)
self.Bind(wx.EVT_UPDATE_UI, self.OnUpdateMenu, id=ID_USEAA)
self.Bind(wx.EVT_UPDATE_UI, self.OnUpdateMenu, id=ID_SHOW_LINENUMBERS)
self.Bind(wx.EVT_UPDATE_UI, self.OnUpdateMenu, id=ID_AUTO_SAVESETTINGS)
self.Bind(wx.EVT_UPDATE_UI, self.OnUpdateMenu, id=ID_SAVESETTINGS)
self.Bind(wx.EVT_UPDATE_UI, self.OnUpdateMenu, id=ID_DELSETTINGSFILE)
self.Bind(wx.EVT_UPDATE_UI, self.OnUpdateMenu, id=ID_EXECSTARTUPSCRIPT)
self.Bind(wx.EVT_UPDATE_UI, self.OnUpdateMenu, id=ID_SAVEHISTORY)
self.Bind(wx.EVT_UPDATE_UI, self.OnUpdateMenu, id=ID_EDITSTARTUPSCRIPT)
self.Bind(wx.EVT_UPDATE_UI, self.OnUpdateMenu, id=ID_FIND)
self.Bind(wx.EVT_UPDATE_UI, self.OnUpdateMenu, id=ID_FINDNEXT)
self.Bind(wx.EVT_ACTIVATE, self.OnActivate)
self.Bind(wx.EVT_FIND, self.OnFindNext)
self.Bind(wx.EVT_FIND_NEXT, self.OnFindNext)
self.Bind(wx.EVT_FIND_CLOSE, self.OnFindClose)
def OnShowLineNumbers(self, event):
win = wx.Window.FindFocus()
if hasattr(win, 'lineNumbers'):
win.lineNumbers = event.IsChecked()
win.setDisplayLineNumbers(win.lineNumbers)
def OnToggleMaximize(self, event):
self.Maximize(not self.IsMaximized())
def OnFileNew(self, event):
self.bufferNew()
@@ -222,39 +325,52 @@ class Frame(wx.Frame):
self.Close(False)
def OnUndo(self, event):
win = wx.Window_FindFocus()
win = wx.Window.FindFocus()
win.Undo()
def OnRedo(self, event):
win = wx.Window_FindFocus()
win = wx.Window.FindFocus()
win.Redo()
def OnCut(self, event):
win = wx.Window_FindFocus()
win = wx.Window.FindFocus()
win.Cut()
def OnCopy(self, event):
win = wx.Window_FindFocus()
win = wx.Window.FindFocus()
win.Copy()
def OnCopyPlus(self, event):
win = wx.Window_FindFocus()
win = wx.Window.FindFocus()
win.CopyWithPrompts()
def OnPaste(self, event):
win = wx.Window_FindFocus()
win = wx.Window.FindFocus()
win.Paste()
def OnPastePlus(self, event):
win = wx.Window_FindFocus()
win = wx.Window.FindFocus()
win.PasteAndRun()
def OnClear(self, event):
win = wx.Window_FindFocus()
win = wx.Window.FindFocus()
win.Clear()
def OnEmptyBuffer(self, event):
win = wx.Window.FindFocus()
d = wx.MessageDialog(self,
"Are you sure you want to clear the edit buffer,\n"
"deleting all the text?",
"Empty Buffer", wx.OK | wx.CANCEL | wx.ICON_QUESTION)
answer = d.ShowModal()
d.Destroy()
if (answer == wx.ID_OK):
win.ClearAll()
if hasattr(win,'prompt'):
win.prompt()
def OnSelectAll(self, event):
win = wx.Window_FindFocus()
win = wx.Window.FindFocus()
win.SelectAll()
def OnAbout(self, event):
@@ -266,38 +382,102 @@ class Frame(wx.Frame):
dialog.ShowModal()
dialog.Destroy()
def OnHelp(self, event):
"""Display a Help window."""
title = 'Help'
text = "Type 'shell.help()' in the shell window."
dialog = wx.MessageDialog(self, text, title,
wx.OK | wx.ICON_INFORMATION)
dialog.ShowModal()
dialog.Destroy()
def OnAutoCompleteShow(self, event):
win = wx.Window_FindFocus()
win = wx.Window.FindFocus()
win.autoComplete = event.IsChecked()
def OnAutoCompleteMagic(self, event):
win = wx.Window_FindFocus()
win = wx.Window.FindFocus()
win.autoCompleteIncludeMagic = event.IsChecked()
def OnAutoCompleteSingle(self, event):
win = wx.Window_FindFocus()
win = wx.Window.FindFocus()
win.autoCompleteIncludeSingle = event.IsChecked()
def OnAutoCompleteDouble(self, event):
win = wx.Window_FindFocus()
win = wx.Window.FindFocus()
win.autoCompleteIncludeDouble = event.IsChecked()
def OnCallTipsShow(self, event):
win = wx.Window_FindFocus()
win = wx.Window.FindFocus()
win.autoCallTip = event.IsChecked()
def OnCallTipsInsert(self, event):
win = wx.Window.FindFocus()
win.callTipInsert = event.IsChecked()
def OnWrap(self, event):
win = wx.Window_FindFocus()
win = wx.Window.FindFocus()
win.SetWrapMode(event.IsChecked())
wx.FutureCall(1, self.shell.EnsureCaretVisible)
def OnUseAA(self, event):
win = wx.Window_FindFocus()
win = wx.Window.FindFocus()
win.SetUseAntiAliasing(event.IsChecked())
def OnSaveHistory(self, event):
self.saveHistory = event.IsChecked()
def OnAutoSaveSettings(self, event):
self.autoSaveSettings = event.IsChecked()
def OnSaveSettings(self, event):
self.DoSaveSettings()
def OnDelSettingsFile(self, event):
if self.config is not None:
d = wx.MessageDialog(
self, "Do you want to revert to the default settings?\n" +
"A restart is needed for the change to take effect",
"Warning", wx.OK | wx.CANCEL | wx.ICON_QUESTION)
answer = d.ShowModal()
d.Destroy()
if (answer == wx.ID_OK):
self.config.DeleteAll()
self.LoadSettings()
def OnEditStartupScript(self, event):
if hasattr(self, 'EditStartupScript'):
self.EditStartupScript()
def OnExecStartupScript(self, event):
self.execStartupScript = event.IsChecked()
def OnFindText(self, event):
if self.findDlg is not None:
return
win = wx.Window.FindFocus()
self.findDlg = wx.FindReplaceDialog(win, self.findData, "Find",
wx.FR_NOWHOLEWORD)
self.findDlg.Show()
def OnFindNext(self, event):
if isinstance(event, wx.FindDialogEvent):
win = self.findDlg.GetParent()
else:
win = wx.Window.FindFocus()
win.DoFindNext(self.findData, self.findDlg)
def OnFindClose(self, event):
self.findDlg.Destroy()
self.findDlg = None
def OnUpdateMenu(self, event):
"""Update menu items based on current status and context."""
win = wx.Window_FindFocus()
win = wx.Window.FindFocus()
id = event.GetId()
event.Enable(True)
try:
@@ -341,6 +521,8 @@ class Frame(wx.Frame):
event.Enable(win.CanCut())
elif id == ID_SELECTALL:
event.Enable(hasattr(win, 'SelectAll'))
elif id == ID_EMPTYBUFFER:
event.Enable(hasattr(win, 'ClearAll') and not win.GetReadOnly())
elif id == ID_AUTOCOMP_SHOW:
event.Check(win.autoComplete)
elif id == ID_AUTOCOMP_MAGIC:
@@ -351,12 +533,273 @@ class Frame(wx.Frame):
event.Check(win.autoCompleteIncludeDouble)
elif id == ID_CALLTIPS_SHOW:
event.Check(win.autoCallTip)
elif id == ID_CALLTIPS_INSERT:
event.Check(win.callTipInsert)
elif id == ID_WRAP:
event.Check(win.GetWrapMode())
elif id == ID_USEAA:
event.Check(win.GetUseAntiAliasing())
elif id == ID_SHOW_LINENUMBERS:
event.Check(win.lineNumbers)
elif id == ID_AUTO_SAVESETTINGS:
event.Check(self.autoSaveSettings)
elif id == ID_SAVESETTINGS:
event.Enable(self.config is not None and
hasattr(self, 'DoSaveSettings'))
elif id == ID_DELSETTINGSFILE:
event.Enable(self.config is not None)
elif id == ID_EXECSTARTUPSCRIPT:
event.Check(self.execStartupScript)
elif id == ID_SAVEHISTORY:
event.Check(self.saveHistory and self.dataDir is not None)
elif id == ID_EDITSTARTUPSCRIPT:
event.Enable(hasattr(self, 'EditStartupScript'))
elif id == ID_FIND:
event.Enable(hasattr(win, 'DoFindNext'))
elif id == ID_FINDNEXT:
event.Enable(hasattr(win, 'DoFindNext') and
self.findData.GetFindString() != '')
else:
event.Enable(False)
except AttributeError:
# This menu option is not supported in the current context.
event.Enable(False)
def OnActivate(self, event):
"""
Event Handler for losing the focus of the Frame. Should close
Autocomplete listbox, if shown.
"""
if not event.GetActive():
# If autocomplete active, cancel it. Otherwise, the
# autocomplete list will stay visible on top of the
# z-order after switching to another application
win = wx.Window.FindFocus()
if hasattr(win, 'AutoCompActive') and win.AutoCompActive():
win.AutoCompCancel()
event.Skip()
def LoadSettings(self, config):
"""Called be derived classes to load settings specific to the Frame"""
pos = wx.Point(config.ReadInt('Window/PosX', -1),
config.ReadInt('Window/PosY', -1))
size = wx.Size(config.ReadInt('Window/Width', -1),
config.ReadInt('Window/Height', -1))
self.SetSize(size)
self.Move(pos)
def SaveSettings(self, config):
"""Called by derived classes to save Frame settings to a wx.Config object"""
# TODO: track position/size so we can save it even if the
# frame is maximized or iconized.
if not self.iconized and not self.IsMaximized():
w, h = self.GetSize()
config.WriteInt('Window/Width', w)
config.WriteInt('Window/Height', h)
px, py = self.GetPosition()
config.WriteInt('Window/PosX', px)
config.WriteInt('Window/PosY', py)
class ShellFrameMixin:
"""
A mix-in class for frames that will have a Shell or a Crust window
and that want to add history, startupScript and other common
functionality.
"""
def __init__(self, config, dataDir):
self.config = config
self.dataDir = dataDir
self.startupScript = os.environ.get('PYTHONSTARTUP')
if not self.startupScript and self.dataDir:
self.startupScript = os.path.join(self.dataDir, 'startup')
self.autoSaveSettings = False
self.saveHistory = False
# We need this one before we have a chance to load the settings...
self.execStartupScript = True
if self.config:
self.execStartupScript = self.config.ReadBool('Options/ExecStartupScript', True)
def OnHelp(self, event):
"""Display a Help window."""
import wx.lib.dialogs
title = 'Help on key bindings'
text = wx.py.shell.HELP_TEXT
dlg = wx.lib.dialogs.ScrolledMessageDialog(self, text, title, size = ((700, 540)))
fnt = wx.Font(10, wx.TELETYPE, wx.NORMAL, wx.NORMAL)
dlg.GetChildren()[0].SetFont(fnt)
dlg.GetChildren()[0].SetInsertionPoint(0)
dlg.ShowModal()
dlg.Destroy()
def LoadSettings(self):
if self.config is not None:
self.autoSaveSettings = self.config.ReadBool('Options/AutoSaveSettings', False)
self.execStartupScript = self.config.ReadBool('Options/ExecStartupScript', True)
self.saveHistory = self.config.ReadBool('Options/SaveHistory', False)
self.LoadHistory()
def SaveSettings(self):
if self.config is not None:
# always save this one
self.config.WriteBool('Options/AutoSaveSettings', self.autoSaveSettings)
if self.autoSaveSettings:
self.config.WriteBool('Options/SaveHistory', self.saveHistory)
self.config.WriteBool('Options/ExecStartupScript', self.execStartupScript)
self.SaveHistory()
def SaveHistory(self):
if self.dataDir:
try:
# always open the file so that when we are not
# saving the history, the old file is emptied.
name = os.path.join(self.dataDir, 'history')
f = file(name, 'w')
if self.saveHistory:
hist = '\n'.join(self.shell.history)
f.write(hist)
f.close()
except:
d = wx.MessageDialog(self, "Error saving history file.",
"Error", wx.ICON_EXCLAMATION)
d.ShowModal()
d.Destroy()
def LoadHistory(self):
if self.dataDir:
name = os.path.join(self.dataDir, 'history')
if os.path.exists(name):
try:
f = file(name, 'U')
hist = f.read()
f.close()
self.shell.history = hist.split('\n')
except:
d = wx.MessageDialog(self, "Error loading history file.",
"Error", wx.ICON_EXCLAMATION)
d.ShowModal()
d.Destroy()
def bufferHasChanged(self):
# the shell buffers can always be saved
return True
def bufferSave(self):
import time
appname = wx.GetApp().GetAppName()
default = appname + '-' + time.strftime("%Y%m%d-%H%M.py")
fileName = wx.FileSelector("Save File As", "Saving",
default_filename=default,
default_extension="py",
wildcard="*.py",
flags = wx.SAVE | wx.OVERWRITE_PROMPT)
if not fileName:
return
text = self.shell.GetText()
## This isn't working currently...
## d = wx.MessageDialog(self,u'Save source code only?\nAnswering yes will only save lines starting with >>> and ...',u'Question', wx.YES_NO | wx.ICON_QUESTION)
## yes_no = d.ShowModal()
## if yes_no == wx.ID_YES:
## m = re.findall('^[>\.]{3,3} (.*)\r', text, re.MULTILINE | re.LOCALE)
## text = '\n'.join(m)
## d.Destroy()
try:
f = open(fileName, "w")
f.write(text)
f.close()
except:
d = wx.MessageDialog(self, u'Error saving session',u'Error',
wx.OK | wx.ICON_ERROR)
d.ShowModal()
d.Destroy()
def EditStartupScript(self):
if os.path.exists(self.startupScript):
text = file(self.startupScript, 'U').read()
else:
text = ''
dlg = EditStartupScriptDialog(self, self.startupScript, text)
if dlg.ShowModal() == wx.ID_OK:
text = dlg.GetText()
try:
f = file(self.startupScript, 'w')
f.write(text)
f.close()
except:
d = wx.MessageDialog(self, "Error saving startup file.",
"Error", wx.ICON_EXCLAMATION)
d.ShowModal()
d.Destroy()
class EditStartupScriptDialog(wx.Dialog):
def __init__(self, parent, fileName, text):
wx.Dialog.__init__(self, parent, size=(425,350),
title="Edit Startup Script",
style=wx.DEFAULT_DIALOG_STYLE|wx.RESIZE_BORDER)
pst = wx.StaticText(self, -1, "Path:")
ptx = wx.TextCtrl(self, -1, fileName, style=wx.TE_READONLY)
self.editor = editwindow.EditWindow(self)
self.editor.SetText(text)
wx.CallAfter(self.editor.SetFocus)
ok = wx.Button(self, wx.ID_OK)
cancel = wx.Button(self, wx.ID_CANCEL)
mainSizer = wx.BoxSizer(wx.VERTICAL)
pthSizer = wx.BoxSizer(wx.HORIZONTAL)
pthSizer.Add(pst, flag=wx.ALIGN_CENTER_VERTICAL)
pthSizer.Add((5,5))
pthSizer.Add(ptx, 1)
mainSizer.Add(pthSizer, 0, wx.EXPAND|wx.ALL, 10)
mainSizer.Add(self.editor, 1, wx.EXPAND|wx.LEFT|wx.RIGHT, 10)
btnSizer = wx.BoxSizer(wx.HORIZONTAL)
btnSizer.Add((5,5), 1)
btnSizer.Add(ok)
btnSizer.Add((5,5), 1)
btnSizer.Add(cancel)
btnSizer.Add((5,5), 1)
mainSizer.Add(btnSizer, 0, wx.EXPAND|wx.ALL, 10)
self.SetSizer(mainSizer)
self.Layout()
def GetText(self):
return self.editor.GetText()

View File

@@ -42,7 +42,8 @@ class Interpreter(InteractiveInterpreter):
self.more = 0
# List of lists to support recursive push().
self.commandBuffer = []
self.startupScript = os.environ.get('PYTHONSTARTUP')
self.startupScript = None
def push(self, command):
"""Send command to the interpreter to be executed.

View File

@@ -31,7 +31,7 @@ NAVKEYS = (wx.WXK_END, wx.WXK_LEFT, wx.WXK_RIGHT,
wx.WXK_UP, wx.WXK_DOWN, wx.WXK_PRIOR, wx.WXK_NEXT)
class ShellFrame(frame.Frame):
class ShellFrame(frame.Frame, frame.ShellFrameMixin):
"""Frame containing the shell component."""
name = 'Shell Frame'
@@ -40,19 +40,31 @@ class ShellFrame(frame.Frame):
def __init__(self, parent=None, id=-1, title='PyShell',
pos=wx.DefaultPosition, size=wx.DefaultSize,
style=wx.DEFAULT_FRAME_STYLE, locals=None,
InterpClass=None, *args, **kwds):
InterpClass=None,
config=None, dataDir=None,
*args, **kwds):
"""Create ShellFrame instance."""
frame.Frame.__init__(self, parent, id, title, pos, size, style)
frame.ShellFrameMixin.__init__(self, config, dataDir)
if size == wx.DefaultSize:
self.SetSize((750, 525))
intro = 'PyShell %s - The Flakiest Python Shell' % VERSION
intro += '\nSponsored by Orbtech - ' + \
'Your source for Python programming expertise.'
self.SetStatusText(intro.replace('\n', ', '))
self.shell = Shell(parent=self, id=-1, introText=intro,
locals=locals, InterpClass=InterpClass,
startupScript=self.startupScript,
execStartupScript=self.execStartupScript,
*args, **kwds)
# Override the shell so that status messages go to the status bar.
self.shell.setStatusText = self.SetStatusText
self.shell.SetFocus()
self.LoadSettings()
def OnClose(self, event):
"""Event handler for closing."""
# This isn't working the way I want, but I'll leave it for now.
@@ -60,6 +72,7 @@ class ShellFrame(frame.Frame):
if event.CanVeto():
event.Veto(True)
else:
self.SaveSettings()
self.shell.destroy()
self.Destroy()
@@ -82,21 +95,28 @@ class ShellFrame(frame.Frame):
dialog.Destroy()
class ShellFacade:
"""Simplified interface to all shell-related functionality.
def LoadSettings(self):
if self.config is not None:
frame.ShellFrameMixin.LoadSettings(self)
frame.Frame.LoadSettings(self, self.config)
self.shell.LoadSettings(self.config)
This is a semi-transparent facade, in that all attributes of other
are accessible, even though only some are visible to the user."""
def SaveSettings(self):
if self.config is not None:
frame.ShellFrameMixin.SaveSettings(self)
if self.autoSaveSettings:
frame.Frame.SaveSettings(self, self.config)
self.shell.SaveSettings(self.config)
name = 'Shell Interface'
revision = __revision__
def DoSaveSettings(self):
if self.config is not None:
self.SaveSettings()
self.config.Flush()
def __init__(self, other):
"""Create a ShellFacade instance."""
d = self.__dict__
d['other'] = other
d['helpText'] = \
"""
HELP_TEXT = """\
* Key bindings:
Home Go to the beginning of the command or line.
Shift+Home Select to the beginning of the command or line.
@@ -104,6 +124,7 @@ Shift+End Select to the end of the line.
End Go to the end of the line.
Ctrl+C Copy selected text, removing prompts.
Ctrl+Shift+C Copy selected text, retaining prompts.
Alt+C Copy to the clipboard, including prefixed prompts.
Ctrl+X Cut selected text.
Ctrl+V Paste from clipboard.
Ctrl+Shift+V Paste and run multiple commands from clipboard.
@@ -119,8 +140,31 @@ Ctrl+Enter Insert new line into multiline command.
Ctrl+] Increase font size.
Ctrl+[ Decrease font size.
Ctrl+= Default font size.
Ctrl-Space Show Auto Completion.
Ctrl-Alt-Space Show Call Tip.
Alt+Shift+C Clear Screen.
Shift+Enter Complete Text from History.
Ctrl+F Search (backwards) TODO: regexp-wholeWords-...
Ctrl+G Search next
Ctrl+H "hide" lines containing selection / "unhide"
F12 on/off "free-edit" mode
"""
class ShellFacade:
"""Simplified interface to all shell-related functionality.
This is a semi-transparent facade, in that all attributes of other
are accessible, even though only some are visible to the user."""
name = 'Shell Interface'
revision = __revision__
def __init__(self, other):
"""Create a ShellFacade instance."""
d = self.__dict__
d['other'] = other
d['helpText'] = HELP_TEXT
def help(self):
"""Display some useful information about how to use the shell."""
self.write(self.helpText)
@@ -151,6 +195,7 @@ Ctrl+= Default font size.
'autoCompleteIncludeDouble',
'autoCompleteIncludeMagic',
'autoCompleteIncludeSingle',
'callTipInsert',
'clear',
'pause',
'prompt',
@@ -167,6 +212,7 @@ Ctrl+= Default font size.
return list
class Shell(editwindow.EditWindow):
"""Shell based on StyledTextCtrl."""
@@ -175,26 +221,32 @@ class Shell(editwindow.EditWindow):
def __init__(self, parent, id=-1, pos=wx.DefaultPosition,
size=wx.DefaultSize, style=wx.CLIP_CHILDREN,
introText='', locals=None, InterpClass=None, *args, **kwds):
introText='', locals=None, InterpClass=None,
startupScript=None, execStartupScript=True,
*args, **kwds):
"""Create Shell instance."""
editwindow.EditWindow.__init__(self, parent, id, pos, size, style)
self.wrap()
if locals is None:
import __main__
locals = __main__.__dict__
# Grab these so they can be restored by self.redirect* methods.
self.stdin = sys.stdin
self.stdout = sys.stdout
self.stderr = sys.stderr
# Import a default interpreter class if one isn't provided.
if InterpClass == None:
from interpreter import Interpreter
else:
Interpreter = InterpClass
# Create a replacement for stdin.
self.reader = PseudoFileIn(self.readline, self.readlines)
self.reader.input = ''
self.reader.isreading = False
# Set up the interpreter.
self.interp = Interpreter(locals=locals,
rawin=self.raw_input,
@@ -202,15 +254,20 @@ class Shell(editwindow.EditWindow):
stdout=PseudoFileOut(self.writeOut),
stderr=PseudoFileErr(self.writeErr),
*args, **kwds)
# Set up the buffer.
self.buffer = Buffer()
# Find out for which keycodes the interpreter will autocomplete.
self.autoCompleteKeys = self.interp.getAutoCompleteKeys()
# Keep track of the last non-continuation prompt positions.
self.promptPosStart = 0
self.promptPosEnd = 0
# Keep track of multi-line commands.
self.more = False
# Create the command history. Commands are added into the
# front of the list (ie. at index 0) as they are entered.
# self.historyIndex is the current position in the history; it
@@ -220,23 +277,46 @@ class Shell(editwindow.EditWindow):
# command, not in the history.
self.history = []
self.historyIndex = -1
#seb add mode for "free edit"
self.noteMode = 0
self.MarkerDefine(0,stc.STC_MARK_ROUNDRECT) # marker for hidden
self.searchTxt = ""
# Assign handlers for keyboard events.
wx.EVT_CHAR(self, self.OnChar)
wx.EVT_KEY_DOWN(self, self.OnKeyDown)
self.Bind(wx.EVT_CHAR, self.OnChar)
self.Bind(wx.EVT_KEY_DOWN, self.OnKeyDown)
# Assign handler for idle time.
self.waiting = False
wx.EVT_IDLE(self, self.OnIdle)
self.Bind(wx.EVT_IDLE, self.OnIdle)
# Display the introductory banner information.
self.showIntro(introText)
# Assign some pseudo keywords to the interpreter's namespace.
self.setBuiltinKeywords()
# Add 'shell' to the interpreter's local namespace.
self.setLocalShell()
## NOTE: See note at bottom of this file...
## #seb: File drag and drop
## self.SetDropTarget( FileDropTarget(self) )
# Do this last so the user has complete control over their
# environment. They can override anything they want.
self.execStartupScript(self.interp.startupScript)
if execStartupScript:
if startupScript is None:
startupScript = os.environ.get('PYTHONSTARTUP')
self.execStartupScript(startupScript)
else:
self.prompt()
wx.CallAfter(self.ScrollToLine, 0)
def destroy(self):
del self.interp
@@ -270,29 +350,32 @@ class Shell(editwindow.EditWindow):
__builtin__.close = __builtin__.exit = __builtin__.quit = \
'Click on the close button to leave the application.'
def quit(self):
"""Quit the application."""
# XXX Good enough for now but later we want to send a close event.
# In the close event handler we can make sure they want to
# quit. Other applications, like PythonCard, may choose to
# hide rather than quit so we should just post the event and
# let the surrounding app decide what it wants to do.
self.write('Click on the close button to leave the application.')
def setLocalShell(self):
"""Add 'shell' to locals as reference to ShellFacade instance."""
self.interp.locals['shell'] = ShellFacade(other=self)
def execStartupScript(self, startupScript):
"""Execute the user's PYTHONSTARTUP script if they have one."""
if startupScript and os.path.isfile(startupScript):
text = 'Startup script executed: ' + startupScript
self.push('print %r; execfile(%r)' % (text, startupScript))
self.interp.startupScript = startupScript
else:
self.push('')
def about(self):
"""Display information about Py."""
text = """
@@ -302,17 +385,24 @@ Py Shell Revision: %s
Py Interpreter Revision: %s
Python Version: %s
wxPython Version: %s
wxPython PlatformInfo: %s
Platform: %s""" % \
(__author__, VERSION, self.revision, self.interp.revision,
sys.version.split()[0], wx.VERSION_STRING, sys.platform)
sys.version.split()[0], wx.VERSION_STRING, str(wx.PlatformInfo),
sys.platform)
self.write(text.strip())
def OnChar(self, event):
"""Keypress event handler.
Only receives an event if OnKeyDown calls event.Skip() for the
corresponding event."""
if self.noteMode:
event.Skip()
return
# Prevent modification of previously submitted
# commands/responses.
if not self.CanEdit():
@@ -343,11 +433,12 @@ Platform: %s""" % \
self.ReplaceSelection('')
command = self.GetTextRange(stoppos, currpos) + '('
self.write('(')
self.autoCallTipShow(command)
self.autoCallTipShow(command, self.GetCurrentPos() == self.GetTextLength())
else:
# Allow the normal event handling to take place.
event.Skip()
def OnKeyDown(self, event):
"""Key down event handler."""
@@ -364,12 +455,64 @@ Platform: %s""" % \
currpos = self.GetCurrentPos()
endpos = self.GetTextLength()
selecting = self.GetSelectionStart() != self.GetSelectionEnd()
if controlDown and key in (ord('H'), ord('h')):
li = self.GetCurrentLine()
m = self.MarkerGet(li)
if m & 1<<0:
startP = self.PositionFromLine(li)
self.MarkerDelete(li, 0)
maxli = self.GetLineCount()
li += 1 # li stayed visible as header-line
li0 = li
while li<maxli and self.GetLineVisible(li) == 0:
li += 1
endP = self.GetLineEndPosition(li-1)
self.ShowLines(li0, li-1)
self.SetSelection( startP, endP ) # select reappearing text to allow "hide again"
return
startP,endP = self.GetSelection()
endP-=1
startL,endL = self.LineFromPosition(startP), self.LineFromPosition(endP)
if endL == self.LineFromPosition(self.promptPosEnd): # never hide last prompt
endL -= 1
m = self.MarkerGet(startL)
self.MarkerAdd(startL, 0)
self.HideLines(startL+1,endL)
self.SetCurrentPos( startP ) # to ensure caret stays visible !
if key == wx.WXK_F12: #seb
if self.noteMode:
# self.promptPosStart not used anyway - or ?
self.promptPosEnd = self.PositionFromLine( self.GetLineCount()-1 ) + len(str(sys.ps1))
self.GotoLine(self.GetLineCount())
self.GotoPos(self.promptPosEnd)
self.prompt() #make sure we have a prompt
self.SetCaretForeground("black")
self.SetCaretWidth(1) #default
self.SetCaretPeriod(500) #default
else:
self.SetCaretForeground("red")
self.SetCaretWidth(4)
self.SetCaretPeriod(0) #steady
self.noteMode = not self.noteMode
return
if self.noteMode:
event.Skip()
return
# Return (Enter) is used to submit a command to the
# interpreter.
if not controlDown and key == wx.WXK_RETURN:
if (not controlDown and not shiftDown and not altDown) and key == wx.WXK_RETURN:
if self.CallTipActive():
self.CallTipCancel()
self.processLine()
#Complete Text (from already typed words)
elif shiftDown and key == wx.WXK_RETURN:
self.OnShowCompHistory()
# Ctrl+Return (Cntrl+Enter) is used to insert a line break.
elif controlDown and key == wx.WXK_RETURN:
if self.CallTipActive():
@@ -433,6 +576,9 @@ Platform: %s""" % \
elif (controlDown and not shiftDown and key in (ord('V'), ord('v'))) \
or (shiftDown and not controlDown and key == wx.WXK_INSERT):
self.Paste()
elif controlDown and key == wx.WXK_SPACE:
"""AutoComplete and Calltips manually."""
self.OnCallTipAutoCompleteManually (shiftDown)
# Paste from the clipboard, run commands.
elif controlDown and shiftDown and key in (ord('V'), ord('v')):
self.PasteAndRun()
@@ -481,6 +627,49 @@ Platform: %s""" % \
else:
event.Skip()
def OnShowCompHistory(self):
"""Show possible autocompletion Words from already typed words."""
#copy from history
his = self.history[:]
#put together in one string
joined = " ".join (his)
import re
#sort out only "good" words
newlist = re.split("[ \.\[\]=}(\)\,0-9\"]", joined)
#length > 1 (mix out "trash")
thlist = []
for i in newlist:
if len (i) > 1:
thlist.append (i)
#unique (no duplicate words
#oneliner from german python forum => unique list
unlist = [thlist[i] for i in xrange(len(thlist)) if thlist[i] not in thlist[:i]]
#sort lowercase
unlist.sort(lambda a, b: cmp(a.lower(), b.lower()))
#this is more convenient, isn't it?
self.AutoCompSetIgnoreCase(True)
#join again together in a string
stringlist = " ".join(unlist)
#pos von 0 noch ausrechnen
#how big is the offset?
cpos = self.GetCurrentPos() - 1
while chr (self.GetCharAt (cpos)).isalnum():
cpos -= 1
#the most important part
self.AutoCompShow(self.GetCurrentPos() - cpos -1, stringlist)
def clearCommand(self):
"""Delete the current, unexecuted command."""
startpos = self.promptPosEnd
@@ -589,6 +778,7 @@ Platform: %s""" % \
self.write(os.linesep)
else:
self.push(command)
wx.FutureCall(1, self.EnsureCaretVisible)
# Or replace the current command with the other command.
else:
# If the line contains a command (even an invalid one).
@@ -665,9 +855,10 @@ Platform: %s""" % \
text = text[ps2size:]
return text
def push(self, command):
def push(self, command, silent = False):
"""Send command to the interpreter for execution."""
self.write(os.linesep)
if not silent:
self.write(os.linesep)
busy = wx.BusyCursor()
self.waiting = True
self.more = self.interp.push(command)
@@ -675,7 +866,8 @@ Platform: %s""" % \
del busy
if not self.more:
self.addHistory(command.rstrip())
self.prompt()
if not silent:
self.prompt()
def addHistory(self, command):
"""Add command to the command history."""
@@ -817,7 +1009,7 @@ Platform: %s""" % \
finally:
file.close()
def autoCompleteShow(self, command):
def autoCompleteShow(self, command, offset = 0):
"""Display auto-completion popup list."""
self.AutoCompSetAutoHide(self.autoCompleteAutoHide)
self.AutoCompSetIgnoreCase(self.autoCompleteCaseInsensitive)
@@ -827,19 +1019,19 @@ Platform: %s""" % \
includeDouble=self.autoCompleteIncludeDouble)
if list:
options = ' '.join(list)
offset = 0
#offset = 0
self.AutoCompShow(offset, options)
def autoCallTipShow(self, command):
def autoCallTipShow(self, command, insertcalltip = True, forceCallTip = False):
"""Display argument spec and docstring in a popup window."""
if self.CallTipActive():
self.CallTipCancel()
(name, argspec, tip) = self.interp.getCallTip(command)
if tip:
dispatcher.send(signal='Shell.calltip', sender=self, calltip=tip)
if not self.autoCallTip:
if not self.autoCallTip and not forceCallTip:
return
if argspec:
if argspec and insertcalltip and self.callTipInsert:
startpos = self.GetCurrentPos()
self.write(argspec + ')')
endpos = self.GetCurrentPos()
@@ -852,6 +1044,53 @@ Platform: %s""" % \
# fallback.
tippos = max(tippos, fallback)
self.CallTipShow(tippos, tip)
def OnCallTipAutoCompleteManually (self, shiftDown):
"""AutoComplete and Calltips manually."""
if self.AutoCompActive():
self.AutoCompCancel()
currpos = self.GetCurrentPos()
stoppos = self.promptPosEnd
cpos = currpos
#go back until '.' is found
pointavailpos = -1
while cpos >= stoppos:
if self.GetCharAt(cpos) == ord ('.'):
pointavailpos = cpos
break
cpos -= 1
#word from non whitespace until '.'
if pointavailpos != -1:
#look backward for first whitespace char
textbehind = self.GetTextRange (pointavailpos + 1, currpos)
pointavailpos += 1
if not shiftDown:
#call AutoComplete
stoppos = self.promptPosEnd
textbefore = self.GetTextRange(stoppos, pointavailpos)
self.autoCompleteShow(textbefore, len (textbehind))
else:
#call CallTips
cpos = pointavailpos
begpos = -1
while cpos > stoppos:
if chr(self.GetCharAt(cpos)).isspace():
begpos = cpos
break
cpos -= 1
if begpos == -1:
begpos = cpos
ctips = self.GetTextRange (begpos, currpos)
ctindex = ctips.find ('(')
if ctindex != -1 and not self.CallTipActive():
#insert calltip, if current pos is '(', otherwise show it only
self.autoCallTipShow(ctips[:ctindex + 1], \
self.GetCharAt(currpos - 1) == ord('(') and self.GetCurrentPos() == self.GetTextLength(),\
True)
def writeOut(self, text):
"""Replacement for stdout."""
@@ -1034,3 +1273,101 @@ Platform: %s""" % \
This number of points is added to the size of all fonts. It
may be positive to magnify or negative to reduce."""
self.SetZoom(points)
def LoadSettings(self, config):
self.autoComplete = config.ReadBool('Options/AutoComplete', True)
self.autoCompleteIncludeMagic = config.ReadBool('Options/AutoCompleteIncludeMagic', True)
self.autoCompleteIncludeSingle = config.ReadBool('Options/AutoCompleteIncludeSingle', True)
self.autoCompleteIncludeDouble = config.ReadBool('Options/AutoCompleteIncludeDouble', True)
self.autoCallTip = config.ReadBool('Options/AutoCallTip', True)
self.callTipInsert = config.ReadBool('Options/CallTipInsert', True)
self.SetWrapMode(config.ReadBool('View/WrapMode', True))
useAA = config.ReadBool('Options/UseAntiAliasing', self.GetUseAntiAliasing())
self.SetUseAntiAliasing(useAA)
self.lineNumbers = config.ReadBool('View/ShowLineNumbers', True)
self.setDisplayLineNumbers (self.lineNumbers)
zoom = config.ReadInt('View/Zoom/Shell', -99)
if zoom != -99:
self.SetZoom(zoom)
def SaveSettings(self, config):
config.WriteBool('Options/AutoComplete', self.autoComplete)
config.WriteBool('Options/AutoCompleteIncludeMagic', self.autoCompleteIncludeMagic)
config.WriteBool('Options/AutoCompleteIncludeSingle', self.autoCompleteIncludeSingle)
config.WriteBool('Options/AutoCompleteIncludeDouble', self.autoCompleteIncludeDouble)
config.WriteBool('Options/AutoCallTip', self.autoCallTip)
config.WriteBool('Options/CallTipInsert', self.callTipInsert)
config.WriteBool('Options/UseAntiAliasing', self.GetUseAntiAliasing())
config.WriteBool('View/WrapMode', self.GetWrapMode())
config.WriteBool('View/ShowLineNumbers', self.lineNumbers)
config.WriteInt('View/Zoom/Shell', self.GetZoom())
## NOTE: The DnD of file names is disabled until I can figure out how
## best to still allow DnD of text.
## #seb : File drag and drop
## class FileDropTarget(wx.FileDropTarget):
## def __init__(self, obj):
## wx.FileDropTarget.__init__(self)
## self.obj = obj
## def OnDropFiles(self, x, y, filenames):
## if len(filenames) == 1:
## txt = 'r\"%s\"' % filenames[0]
## else:
## txt = '( '
## for f in filenames:
## txt += 'r\"%s\" , ' % f
## txt += ')'
## self.obj.AppendText(txt)
## pos = self.obj.GetCurrentPos()
## self.obj.SetCurrentPos( pos )
## self.obj.SetSelection( pos, pos )
## class TextAndFileDropTarget(wx.DropTarget):
## def __init__(self, shell):
## wx.DropTarget.__init__(self)
## self.shell = shell
## self.compdo = wx.DataObjectComposite()
## self.textdo = wx.TextDataObject()
## self.filedo = wx.FileDataObject()
## self.compdo.Add(self.textdo)
## self.compdo.Add(self.filedo, True)
## self.SetDataObject(self.compdo)
## def OnDrop(self, x, y):
## return True
## def OnData(self, x, y, result):
## self.GetData()
## if self.textdo.GetTextLength() > 1:
## text = self.textdo.GetText()
## # *** Do somethign with the dragged text here...
## self.textdo.SetText('')
## else:
## filenames = str(self.filename.GetFilenames())
## if len(filenames) == 1:
## txt = 'r\"%s\"' % filenames[0]
## else:
## txt = '( '
## for f in filenames:
## txt += 'r\"%s\" , ' % f
## txt += ')'
## self.shell.AppendText(txt)
## pos = self.shell.GetCurrentPos()
## self.shell.SetCurrentPos( pos )
## self.shell.SetSelection( pos, pos )
## return result

View File

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