##// END OF EJS Templates
Fixed numerous bugs with tab completion, including the one recently reported by fperez.
Fixed numerous bugs with tab completion, including the one recently reported by fperez.

File last commit:

r2661:595fc3b9
r2939:6d047e62
Show More
ipython_history.py
510 lines | 20.7 KiB | text/x-python | PythonLexer
/ IPython / deathrow / gui / wx / ipython_history.py
ville
initialization (no svn history)
r988 #!/usr/bin/python
# -*- coding: iso-8859-15 -*-
import wx
import wx.stc as stc
import keyword
#-----------------------------------------
# History widget for IPython
__version__ = 0.5
__author__ = "Laurent Dufrechou"
__email__ = "laurent.dufrechou _at_ gmail.com"
__license__ = "BSD"
#-----------------------------------------
Brian Granger
More work addressing review comments for Fernando's branch....
r2499
ville
initialization (no svn history)
r988 class IPythonHistoryPanel(wx.Panel):
def __init__(self, parent,flt_empty=True,
flt_doc=True,flt_cmd=True,flt_magic=True):
wx.Panel.__init__(self,parent,-1)
#text_ctrl = wx.TextCtrl(self, -1, style=wx.TE_MULTILINE)
text_ctrl = PythonSTC(self, -1)
st_filt = wx.StaticText(self, -1, " Filter:")
self.filter_empty = wx.CheckBox(self, -1, "Empty commands")
self.filter_doc = wx.CheckBox(self, -1, "?: Doc commands")
self.filter_cmd = wx.CheckBox(self, -1, "!: Sys commands")
self.filter_magic = wx.CheckBox(self, -1, "%: Magic keys")
ldufrechou
[gui/wx] added options save/restore for history widget
r1176 self.options={'filter_empty':{'value':'True',
laurent.dufrechou@gmail.com
some more little cleanup and a bug correction with prompt that comes with last commit
r1817 'checkbox':self.filter_empty, \
'True':True,'False':False,
'setfunc':lambda x:None},
ldufrechou
[gui/wx] added options save/restore for history widget
r1176 'filter_doc':{'value':'True',
laurent.dufrechou@gmail.com
some more little cleanup and a bug correction with prompt that comes with last commit
r1817 'checkbox':self.filter_doc, \
'True':True,'False':False,
'setfunc':lambda x:None},
ldufrechou
[gui/wx] added options save/restore for history widget
r1176 'filter_cmd':{'value':'True',
laurent.dufrechou@gmail.com
some more little cleanup and a bug correction with prompt that comes with last commit
r1817 'checkbox':self.filter_cmd, \
'True':True,'False':False,
'setfunc':lambda x:None},
ldufrechou
[gui/wx] added options save/restore for history widget
r1176 'filter_magic':{'value':'True',
laurent.dufrechou@gmail.com
some more little cleanup and a bug correction with prompt that comes with last commit
r1817 'checkbox':self.filter_magic, \
'True':True,'False':False,
'setfunc':lambda x:None},
ldufrechou
[gui/wx] added options save/restore for history widget
r1176 }
self.reloadOptions(self.options)
self.filter_empty.Bind(wx.EVT_CHECKBOX, self.evtCheckEmptyFilter)
self.filter_doc.Bind(wx.EVT_CHECKBOX, self.evtCheckDocFilter)
self.filter_cmd.Bind(wx.EVT_CHECKBOX, self.evtCheckCmdFilter)
self.filter_magic.Bind(wx.EVT_CHECKBOX, self.evtCheckMagicFilter)
#self.filter_empty.SetValue(flt_empty)
#self.filter_doc.SetValue(flt_doc)
#self.filter_cmd.SetValue(flt_cmd)
#self.filter_magic.SetValue(flt_magic)
ville
initialization (no svn history)
r988
sizer = wx.BoxSizer(wx.VERTICAL)
sizer.Add(text_ctrl, 1, wx.EXPAND)
sizer.AddMany( [(5,5),
st_filt,
(10,10),
self.filter_empty,
self.filter_doc,
self.filter_cmd,
self.filter_magic,
(10,10),
])
self.SetAutoLayout(True)
sizer.Fit(self)
sizer.SetSizeHints(self)
self.SetSizer(sizer)
self.text_ctrl=text_ctrl
#text_ctrl.SetText(demoText + open('Main.py').read())
text_ctrl.EmptyUndoBuffer()
text_ctrl.Colourise(0, -1)
# line numbers in the margin
text_ctrl.SetMarginType(1, stc.STC_MARGIN_NUMBER)
text_ctrl.SetMarginWidth(1, 15)
def write(self,history_line):
add = True
if self.filter_empty.GetValue() == True and history_line == '':
add = False
if len(history_line)>0:
if self.filter_doc.GetValue() == True and history_line[-1:] == '?':
add = False
if self.filter_cmd.GetValue() == True and history_line[0] == '!':
add = False
if self.filter_magic.GetValue() == True and history_line[0] == '%':
add = False
Gael Varoquaux
Changed tabs to whitespace in the wx frontend...
r1103 if add:
self.text_ctrl.AppendText(history_line+'\n')
ville
initialization (no svn history)
r988
ldufrechou
[gui/wx] added options save/restore for history widget
r1176 #------------------------ Option Section -----------------------------------
def processOptionCheckedEvt(self, event, name):
if event.IsChecked():
self.options[name]['value']='True'
else:
self.options[name]['value']='False'
self.updateOptionTracker(name,
self.options[name]['value'])
def evtCheckEmptyFilter(self, event):
self.processOptionCheckedEvt(event, 'filter_empty')
def evtCheckDocFilter(self, event):
self.processOptionCheckedEvt(event, 'filter_doc')
def evtCheckCmdFilter(self, event):
self.processOptionCheckedEvt(event, 'filter_cmd')
def evtCheckMagicFilter(self, event):
self.processOptionCheckedEvt(event, 'filter_magic')
def getOptions(self):
return self.options
def reloadOptions(self,options):
self.options = options
for key in self.options.keys():
value = self.options[key]['value']
self.options[key]['checkbox'].SetValue(self.options[key][value])
self.options[key]['setfunc'](value)
#------------------------ Hook Section -----------------------------------
def updateOptionTracker(self,name,value):
'''
Default history tracker (does nothing)
'''
pass
def setOptionTrackerHook(self,func):
'''
Define a new history tracker
'''
self.updateOptionTracker = func
ville
initialization (no svn history)
r988
ldufrechou
[gui/wx] added options save/restore for history widget
r1176
ville
initialization (no svn history)
r988 #----------------------------------------------------------------------
# Font definition for Styled Text Control
if wx.Platform == '__WXMSW__':
faces = { 'times': 'Times New Roman',
'mono' : 'Courier New',
'helv' : 'Arial',
'other': 'Comic Sans MS',
'size' : 8,
'size2': 6,
}
elif wx.Platform == '__WXMAC__':
faces = { 'times': 'Times New Roman',
'mono' : 'Monaco',
'helv' : 'Arial',
'other': 'Comic Sans MS',
'size' : 8,
'size2': 6,
}
else:
faces = { 'times': 'Times',
'mono' : 'Courier',
'helv' : 'Helvetica',
'other': 'new century schoolbook',
'size' : 8,
'size2': 6,
}
#----------------------------------------------------------------------
class PythonSTC(stc.StyledTextCtrl):
fold_symbols = 3
def __init__(self, parent, ID,
pos=wx.DefaultPosition, size=wx.DefaultSize,
style=0):
stc.StyledTextCtrl.__init__(self, parent, ID, pos, size, style)
#self.CmdKeyAssign(ord('B'), stc.STC_SCMOD_CTRL, stc.STC_CMD_ZOOMIN)
#self.CmdKeyAssign(ord('N'), stc.STC_SCMOD_CTRL, stc.STC_CMD_ZOOMOUT)
self.SetLexer(stc.STC_LEX_PYTHON)
self.SetKeyWords(0, " ".join(keyword.kwlist))
#self.SetProperty("fold", "1")
#self.SetProperty("tab.timmy.whinge.level", "1")
#self.SetMargins(0,0)
#self.SetViewWhiteSpace(False)
#self.SetBufferedDraw(False)
#self.SetViewEOL(True)
self.SetEOLMode(stc.STC_EOL_CRLF)
#self.SetUseAntiAliasing(True)
self.SetEdgeMode(stc.STC_EDGE_LINE)
self.SetEdgeColumn(80)
self.SetEdgeColour(wx.LIGHT_GREY)
self.SetLayoutCache(stc.STC_CACHE_PAGE)
# Setup a margin to hold fold markers
laurent.dufrechou@gmail.com
some more little cleanup and a bug correction with prompt that comes with last commit
r1817 #self.SetFoldFlags(16)
### WHAT IS THIS VALUE? WHAT ARE THE OTHER FLAGS? DOES IT MATTER?
ville
initialization (no svn history)
r988 self.SetMarginType(2, stc.STC_MARGIN_SYMBOL)
self.SetMarginMask(2, stc.STC_MASK_FOLDERS)
self.SetMarginSensitive(2, True)
self.SetMarginWidth(2, 12)
if self.fold_symbols == 0:
laurent.dufrechou@gmail.com
some more little cleanup and a bug correction with prompt that comes with last commit
r1817 # Arrow pointing right for contracted folders,
# arrow pointing down for expanded
self.MarkerDefine(stc.STC_MARKNUM_FOLDEROPEN, \
stc.STC_MARK_ARROWDOWN, "black", "black")
self.MarkerDefine(stc.STC_MARKNUM_FOLDER, \
stc.STC_MARK_ARROW, "black", "black")
self.MarkerDefine(stc.STC_MARKNUM_FOLDERSUB, \
stc.STC_MARK_EMPTY, "black", "black")
self.MarkerDefine(stc.STC_MARKNUM_FOLDERTAIL, \
stc.STC_MARK_EMPTY, "black", "black")
self.MarkerDefine(stc.STC_MARKNUM_FOLDEREND, \
stc.STC_MARK_EMPTY, "white", "black")
self.MarkerDefine(stc.STC_MARKNUM_FOLDEROPENMID, \
stc.STC_MARK_EMPTY, "white", "black")
self.MarkerDefine(stc.STC_MARKNUM_FOLDERMIDTAIL, \
stc.STC_MARK_EMPTY, "white", "black")
ville
initialization (no svn history)
r988
elif self.fold_symbols == 1:
# Plus for contracted folders, minus for expanded
laurent.dufrechou@gmail.com
some more little cleanup and a bug correction with prompt that comes with last commit
r1817 self.MarkerDefine(stc.STC_MARKNUM_FOLDEROPEN, \
stc.STC_MARK_MINUS, "white", "black")
self.MarkerDefine(stc.STC_MARKNUM_FOLDER, \
stc.STC_MARK_PLUS, "white", "black")
self.MarkerDefine(stc.STC_MARKNUM_FOLDERSUB, \
stc.STC_MARK_EMPTY, "white", "black")
self.MarkerDefine(stc.STC_MARKNUM_FOLDERTAIL, \
stc.STC_MARK_EMPTY, "white", "black")
self.MarkerDefine(stc.STC_MARKNUM_FOLDEREND, \
stc.STC_MARK_EMPTY, "white", "black")
self.MarkerDefine(stc.STC_MARKNUM_FOLDEROPENMID, \
stc.STC_MARK_EMPTY, "white", "black")
self.MarkerDefine(stc.STC_MARKNUM_FOLDERMIDTAIL, \
stc.STC_MARK_EMPTY, "white", "black")
ville
initialization (no svn history)
r988
elif self.fold_symbols == 2:
# Like a flattened tree control using circular headers and curved joins
laurent.dufrechou@gmail.com
some more little cleanup and a bug correction with prompt that comes with last commit
r1817 self.MarkerDefine(stc.STC_MARKNUM_FOLDEROPEN, \
stc.STC_MARK_CIRCLEMINUS, "white", "#404040")
self.MarkerDefine(stc.STC_MARKNUM_FOLDER, \
stc.STC_MARK_CIRCLEPLUS, "white", "#404040")
self.MarkerDefine(stc.STC_MARKNUM_FOLDERSUB, \
stc.STC_MARK_VLINE, "white", "#404040")
self.MarkerDefine(stc.STC_MARKNUM_FOLDERTAIL, \
stc.STC_MARK_LCORNERCURVE, "white", "#404040")
self.MarkerDefine(stc.STC_MARKNUM_FOLDEREND, \
stc.STC_MARK_CIRCLEPLUSCONNECTED, "white", "#404040")
self.MarkerDefine(stc.STC_MARKNUM_FOLDEROPENMID, \
stc.STC_MARK_CIRCLEMINUSCONNECTED, "white", "#404040")
self.MarkerDefine(stc.STC_MARKNUM_FOLDERMIDTAIL, \
stc.STC_MARK_TCORNERCURVE, "white", "#404040")
ville
initialization (no svn history)
r988
elif self.fold_symbols == 3:
# Like a flattened tree control using square headers
laurent.dufrechou@gmail.com
some more little cleanup and a bug correction with prompt that comes with last commit
r1817 self.MarkerDefine(stc.STC_MARKNUM_FOLDEROPEN, \
stc.STC_MARK_BOXMINUS, "white", "#808080")
self.MarkerDefine(stc.STC_MARKNUM_FOLDER, \
stc.STC_MARK_BOXPLUS, "white", "#808080")
self.MarkerDefine(stc.STC_MARKNUM_FOLDERSUB, \
stc.STC_MARK_VLINE, "white", "#808080")
self.MarkerDefine(stc.STC_MARKNUM_FOLDERTAIL, \
stc.STC_MARK_LCORNER, "white", "#808080")
self.MarkerDefine(stc.STC_MARKNUM_FOLDEREND, \
stc.STC_MARK_BOXPLUSCONNECTED, "white", "#808080")
self.MarkerDefine(stc.STC_MARKNUM_FOLDEROPENMID, \
stc.STC_MARK_BOXMINUSCONNECTED, "white", "#808080")
self.MarkerDefine(stc.STC_MARKNUM_FOLDERMIDTAIL, \
stc.STC_MARK_TCORNER, "white", "#808080")
ville
initialization (no svn history)
r988
self.Bind(stc.EVT_STC_UPDATEUI, self.OnUpdateUI)
self.Bind(stc.EVT_STC_MARGINCLICK, self.OnMarginClick)
self.Bind(wx.EVT_KEY_DOWN, self.OnKeyPressed)
# Make some styles, The lexer defines what each style is used for, we
# just have to define what each style looks like. This set is adapted from
# Scintilla sample property files.
# Global default styles for all languages
self.StyleSetSpec(stc.STC_STYLE_DEFAULT, "face:%(helv)s,size:%(size)d" % faces)
self.StyleClearAll() # Reset all to be like the default
# Global default styles for all languages
self.StyleSetSpec(stc.STC_STYLE_DEFAULT, "face:%(helv)s,size:%(size)d" % faces)
self.StyleSetSpec(stc.STC_STYLE_LINENUMBER, "back:#C0C0C0,face:%(helv)s,size:%(size2)d" % faces)
self.StyleSetSpec(stc.STC_STYLE_CONTROLCHAR, "face:%(other)s" % faces)
self.StyleSetSpec(stc.STC_STYLE_BRACELIGHT, "fore:#FFFFFF,back:#0000FF,bold")
self.StyleSetSpec(stc.STC_STYLE_BRACEBAD, "fore:#000000,back:#FF0000,bold")
# Python styles
# Default
self.StyleSetSpec(stc.STC_P_DEFAULT, "fore:#000000,face:%(helv)s,size:%(size)d" % faces)
# Comments
self.StyleSetSpec(stc.STC_P_COMMENTLINE, "fore:#007F00,face:%(other)s,size:%(size)d" % faces)
# Number
self.StyleSetSpec(stc.STC_P_NUMBER, "fore:#007F7F,size:%(size)d" % faces)
# String
self.StyleSetSpec(stc.STC_P_STRING, "fore:#7F007F,face:%(helv)s,size:%(size)d" % faces)
# Single quoted string
self.StyleSetSpec(stc.STC_P_CHARACTER, "fore:#7F007F,face:%(helv)s,size:%(size)d" % faces)
# Keyword
self.StyleSetSpec(stc.STC_P_WORD, "fore:#00007F,bold,size:%(size)d" % faces)
# Triple quotes
self.StyleSetSpec(stc.STC_P_TRIPLE, "fore:#7F0000,size:%(size)d" % faces)
# Triple double quotes
self.StyleSetSpec(stc.STC_P_TRIPLEDOUBLE, "fore:#7F0000,size:%(size)d" % faces)
# Class name definition
self.StyleSetSpec(stc.STC_P_CLASSNAME, "fore:#0000FF,bold,underline,size:%(size)d" % faces)
# Function or method name definition
self.StyleSetSpec(stc.STC_P_DEFNAME, "fore:#007F7F,bold,size:%(size)d" % faces)
# Operators
self.StyleSetSpec(stc.STC_P_OPERATOR, "bold,size:%(size)d" % faces)
# Identifiers
self.StyleSetSpec(stc.STC_P_IDENTIFIER, "fore:#000000,face:%(helv)s,size:%(size)d" % faces)
# Comment-blocks
self.StyleSetSpec(stc.STC_P_COMMENTBLOCK, "fore:#7F7F7F,size:%(size)d" % faces)
# End of line where string is not closed
self.StyleSetSpec(stc.STC_P_STRINGEOL, "fore:#000000,face:%(mono)s,back:#E0C0E0,eol,size:%(size)d" % faces)
self.SetCaretForeground("BLUE")
# register some images for use in the AutoComplete box.
#self.RegisterImage(1, images.getSmilesBitmap())
#self.RegisterImage(2,
# wx.ArtProvider.GetBitmap(wx.ART_NEW, size=(16,16)))
#self.RegisterImage(3,
# wx.ArtProvider.GetBitmap(wx.ART_COPY, size=(16,16)))
def OnKeyPressed(self, event):
if self.CallTipActive():
self.CallTipCancel()
key = event.GetKeyCode()
if key == 32 and event.ControlDown():
pos = self.GetCurrentPos()
# Tips
if event.ShiftDown():
self.CallTipSetBackground("yellow")
self.CallTipShow(pos, 'lots of of text: blah, blah, blah\n\n'
'show some suff, maybe parameters..\n\n'
'fubar(param1, param2)')
# Code completion
else:
#lst = []
#for x in range(50000):
# lst.append('%05d' % x)
#st = " ".join(lst)
#print len(st)
#self.AutoCompShow(0, st)
kw = keyword.kwlist[:]
kw.sort() # Python sorts are case sensitive
self.AutoCompSetIgnoreCase(False) # so this needs to match
# Images are specified with a appended "?type"
for i in range(len(kw)):
if kw[i] in keyword.kwlist:
kw[i] = kw[i]# + "?1"
self.AutoCompShow(0, " ".join(kw))
else:
event.Skip()
def OnUpdateUI(self, evt):
# check for matching braces
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.STC_P_OPERATOR:
braceAtCaret = caretPos - 1
# check after
if braceAtCaret < 0:
charAfter = self.GetCharAt(caretPos)
styleAfter = self.GetStyleAt(caretPos)
laurent.dufrechou@gmail.com
some more little cleanup and a bug correction with prompt that comes with last commit
r1817
ville
initialization (no svn history)
r988 if charAfter and chr(charAfter) in "[]{}()" and styleAfter == stc.STC_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)
#pt = self.PointFromPosition(braceOpposite)
#self.Refresh(True, wxRect(pt.x, pt.y, 5,5))
#print pt
#self.Refresh(False)
def OnMarginClick(self, evt):
# fold and unfold as needed
if evt.GetMargin() == 2:
if evt.GetShift() and evt.GetControl():
self.FoldAll()
else:
lineClicked = self.LineFromPosition(evt.GetPosition())
if self.GetFoldLevel(lineClicked) & stc.STC_FOLDLEVELHEADERFLAG:
if evt.GetShift():
self.SetFoldExpanded(lineClicked, True)
self.Expand(lineClicked, True, True, 1)
elif evt.GetControl():
if self.GetFoldExpanded(lineClicked):
self.SetFoldExpanded(lineClicked, False)
self.Expand(lineClicked, False, True, 0)
else:
self.SetFoldExpanded(lineClicked, True)
self.Expand(lineClicked, True, True, 100)
else:
self.ToggleFold(lineClicked)
def FoldAll(self):
lineCount = self.GetLineCount()
expanding = True
# find out if we are folding or unfolding
for lineNum in range(lineCount):
if self.GetFoldLevel(lineNum) & stc.STC_FOLDLEVELHEADERFLAG:
expanding = not self.GetFoldExpanded(lineNum)
break
lineNum = 0
while lineNum < lineCount:
level = self.GetFoldLevel(lineNum)
if level & stc.STC_FOLDLEVELHEADERFLAG and \
(level & stc.STC_FOLDLEVELNUMBERMASK) == stc.STC_FOLDLEVELBASE:
if expanding:
self.SetFoldExpanded(lineNum, True)
lineNum = self.Expand(lineNum, True)
lineNum = lineNum - 1
else:
lastChild = self.GetLastChild(lineNum, -1)
self.SetFoldExpanded(lineNum, False)
if lastChild > lineNum:
self.HideLines(lineNum+1, lastChild)
lineNum = lineNum + 1
def Expand(self, line, doExpand, force=False, visLevels=0, level=-1):
lastChild = self.GetLastChild(line, level)
line = line + 1
while line <= lastChild:
if force:
if visLevels > 0:
self.ShowLines(line, line)
else:
self.HideLines(line, line)
else:
if doExpand:
self.ShowLines(line, line)
if level == -1:
level = self.GetFoldLevel(line)
if level & stc.STC_FOLDLEVELHEADERFLAG:
if force:
if visLevels > 1:
self.SetFoldExpanded(line, True)
else:
self.SetFoldExpanded(line, False)
line = self.Expand(line, doExpand, force, visLevels-1)
else:
if doExpand and self.GetFoldExpanded(line):
line = self.Expand(line, True, force, visLevels-1)
else:
line = self.Expand(line, False, force, visLevels-1)
else:
line = line + 1
return line
#----------------------------------------------------------------------