'''
This software is licensed under the GPL (GNU General Public License) version 2
as it appears here: http://www.gnu.org/copyleft/gpl.html
It is also included with this archive as `gpl.txt <gpl.txt>`_.
'''
"""
This is a test version of an alternate find in files ui.
"""
# Initial version for PyPE
# Based on work from Josiah Carlson and others.
# License GPL
# Further work by parameter@sourceforge (Dave Schuyler).
# Further further work by Josiah Carlson.
from wx import ImageFromStream,BitmapFromImage,Yield
from wx.stc import StyledTextCtrl
import cStringIO
import threading
import wx
import wx.lib.mixins.listctrl as listmix
import wx.lib.scrolledpanel as scrolled
import os
import re
import fnmatch
import posixpath
import time
import tokenize
import cStringIO
import compiler
newlines = re.compile(r'((\r\n)|(\r)|(\n))')
quotedPattern=re.compile(
r'''((?:"(?:[^\\"]*(?:\\.[^\\"]*)*)["])|(?:'(?:[^\\']*(?:\\.[^\\']*)*)[']))''')
commentedPatterns = {
'cpp' :re.compile('[^/]*//(.*)$'),
'python' :re.compile('[^#]*#(.*)$'),
'html' :re.compile('.*?<!--(.*?)(?=-->)?$'),
'tex' :re.compile('(?=[^%]*)%(.*)$')
}
commentedPatterns['text'] = commentedPatterns['pyrex'] = commentedPatterns['python']
commentedPatterns['xml'] = commentedPatterns['html']
uncommentedPatterns = {
'cpp' :re.compile('((.*(?=//))|(.*))'),
'python' :re.compile('(^[^#]*)'),
'html' :re.compile('(.*?)(?=<!--)?'),
'tex' :re.compile('([^%]*)(?=\%.*)')
}
uncommentedPatterns['text'] = uncommentedPatterns['pyrex'] = uncommentedPatterns['python']
uncommentedPatterns['xml'] = uncommentedPatterns['html']
def fixnewlines(string):
return newlines.sub('\n', string)
def namematches(name, include, exclude):
for extn in include:
if fnmatch.fnmatch(name, extn):
for i in exclude:
if fnmatch.fnmatch(name, i):
return 0
else:
return 1
return 0
columns = (
(0, "Path", 200, 0),
(1, "Filename", 100, 0),
(2, "L#", 40, wx.LIST_FORMAT_RIGHT),
(3, "Item", 15, 0))
OP = tokenize.OP
NAME = tokenize.NAME
NTOK = tokenize.N_TOKENS
NEWL = tokenize.NEWLINE
include_re = re.compile('^#include\s+"([^"\\n\\r ]+)".*?$', re.MULTILINE)
PY = 0
C = 1
enable_options = ['Directories', 'Tags in Directories']
def find_imports(txt):
if 'import' in txt:
#probably a python file
#this part runs around 450k/second on my 2.8 ghz P4, fast enough.
imports = []
parname = ''
curname = ''
ok = 0
x = 0
for typ, token, st, en, lin in tokenize.generate_tokens(cStringIO.StringIO(txt).readline):
x += 1
if x >= 100:
x = 0
Yield()
if typ == NAME:
if token == 'from':
parname = ''
curname = ''
ok = 1
elif token == 'import':
parname = curname
curname = ''
ok = 1
elif ok:
curname += token
elif typ == OP:
if token == '.':
curname += '.'
elif token in '*,':
if parname and curname:
imports.append(parname + '.' + curname)
elif token == '*' and parname:
imports.append(parname)
elif curname:
imports.append(curname)
curname = ''
elif typ == NEWL or typ >= NTOK:
if parname and curname:
imports.append(parname + '.' + curname)
elif curname:
imports.append(curname)
parname = ''
curname = ''
ok = 0
return PY, [i for i in imports if len(i) != i.count('.')]
elif '#include' in txt:
#probably a c/c++ file
return C, [i for i in include_re.findall(txt)]
return -1, []
#-----------------------------------------------------------------------------
class FoundTable(wx.ListCtrl, listmix.ColumnSorterMixin, listmix.ListCtrlAutoWidthMixin):
def __init__(self, parent, columns = columns):
wx.ListCtrl.__init__(
self, parent, -1,
style=wx.LC_REPORT|wx.LC_VIRTUAL|wx.LC_HRULES|wx.LC_VRULES)
self.parent = parent.GetParent()
self.c = columns
self.imageList = wx.ImageList(16, 16)
self.sm_up = self.imageList.Add(getSmallUpArrowBitmap())
self.sm_dn = self.imageList.Add(getSmallDnArrowBitmap())
self.SetImageList(self.imageList, wx.IMAGE_LIST_SMALL)
for i in columns:
if 0:
info = wx.ListItem()
info.SetMask(
wx.LIST_MASK_TEXT|wx.LIST_MASK_IMAGE|wx.LIST_MASK_FORMAT)
info.SetImage(-1)
info.SetText(i[1])
info.SetAlign(i[3])
self.InsertColumnInfo(i[0], info)
else:
self.InsertColumn(i[0], i[1], i[3])
self.SetColumnWidth(i[0], i[2])
self.data=[]
self.cache=[]
listmix.ColumnSorterMixin.__init__(self, len(columns))
listmix.ListCtrlAutoWidthMixin.__init__(self)
self.Bind(wx.EVT_LIST_ITEM_SELECTED, self.OnItemSelected)
self.Bind(wx.EVT_LIST_ITEM_ACTIVATED, self.OnItemActivated)
#self.Bind(wx.EVT_LIST_ITEM_DESELECTED, self.OnItemDeselected)
self.pattern = None
self.currentItem = 0
self.Bind(wx.EVT_SIZE, self._thisResize)
def _thisResize(self, e):
if e.GetSize()[1] < 32:
return
e.Skip()
def setData(self, arrayOfTuples, copy=1):
if copy:
self.data=arrayOfTuples[:]
else:
self.data=arrayOfTuples
if self.c is columns:
self.cache = [os.path.split(i[0]) for i in self.data]
self.SetItemCount(len(arrayOfTuples))
self.Refresh()
def Clear(self):
self.data=[]
self.cache=[]
self.SetItemCount(0)
self.DeleteAllItems()
self.Refresh()
def AppendEntry(self, tuple):
"""
((filename, line, line contents, extra), *)
"""
self.data.append(tuple)
if self.c is columns:
self.cache.append(os.path.split(tuple[0]))
self.SetItemCount(len(self.data))
def ExtendEntries(self, array):
self.data.extend(array)
if self.c is columns:
self.cache.extend([os.path.split(i[0]) for i in array])
self.SetItemCount(len(self.data))
# Used by the ColumnSorterMixin, see wx/lib/mixins/listctrl.py
def GetListCtrl(self):
return self
# Used by the ColumnSorterMixin, see wx/lib/mixins/listctrl.py
def GetSortImages(self):
return (self.sm_dn, self.sm_up)
def GetColumnSorter(self):
# Override listctrl mixin default to do nothing.
pass
def SortItems(self, *args, **kwargs):
# Override listctrl mixin
col=self._col
ascending = self._colSortFlag[col]
col -= 1
if col in (0,1) and self.c is columns:
ops = os.path.split
fcn = lambda a:ops(a[0])[col]
else:
fcn = lambda a:a[col]
def cmpf(a,b):
return cmp(fcn(a), fcn(b))
if ascending:
self.data.sort(cmpf)
if self.c is columns:
self.cache = [os.path.split(i[0]) for i in self.data]
else:
self.data.reverse()
self.cache.reverse()
self.Refresh()
def OnItemSelected(self, event):
self.currentItem = event.m_itemIndex
def OnItemActivated(self, event):
self.currentItem = event.m_itemIndex
path = self.GetItem(self.currentItem, 0).GetText()
file = self.GetItem(self.currentItem, 1).GetText()
line = self.GetItem(self.currentItem, 2).GetText()
data = self.GetItem(self.currentItem, 3).GetText()
self.parent.OpenFound(os.path.join(path, file), int(line), self.pattern, ('\\n' in data) and len(data.encode('utf-8')))
def OnItemRightClick(self, event):
self.PopupMenu(self.popm)
def OpenAll(self, event):
for i in range(self.GetItemCount()):
path = self.GetItem(i, 0).GetText()
file = self.GetItem(i, 1).GetText()
line = self.GetItem(i, 2).GetText()
data = self.GetItem(i, 3).GetText()
self.parent.OpenFound(os.path.join(path, file), int(line), self.pattern, ('\\n' in data) and len(data.encode('utf-8')))
def OnGetItemText(self, item, col):
if col in (0,1):
return self.cache[item][col]
return "%s" % (self.data[item][col-1],)
#-----------------------------------------------------------------------------
class FoundText(wx.ListBox):
def __init__(self, parent):
wx.ListBox.__init__(
self, parent, -1,
style=wx.LB_SINGLE|wx.LB_NEEDED_SB)
self.parent = parent.GetParent()
wx.EVT_LISTBOX_DCLICK(parent, self.GetId(), self.OnItemActivated)
self.last = ''
self.pattern = None
def setData(self, arrayOfTuples):
self.Clear()
self.ExtendEntries(arrayOfTuples)
def AppendEntry(self, tuple):
#tuple is (filename, line, line contents, extra)
if tuple[0] != self.last:
#set text color
self.Append(tuple[0])
self.last = tuple[0]
self.Append(" %s: %s"%tuple[1:3])
def ExtendEntries(self, array):
a = []
for tuple in array:
if tuple[0] != self.last:
#set text color
a.append(tuple[0])
self.last = tuple[0]
a.append(" %s: %s"%tuple[1:3])
self.InsertItems(a, self.GetCount())
def OnItemActivated(self, event):
selected = self.GetSelection()
if selected < 0:
return
cur = selected
while (cur > 0) and (self.GetString(cur)[0] == ' '):
cur -= 1
file = self.GetString(cur)
line = 1
a = self.GetString(selected)
if a[0] == ' ':
line = int(a.split(':', 1)[0])
self.parent.OpenFound(file, int(line), self.pattern, ('\\n' in a) and len(a.encode('utf-8')))
#---------------------------------------------------------------------------
class FoundTree(wx.TreeCtrl):
def __init__(self, parent):
wx.TreeCtrl.__init__(self, parent,
style=wx.TR_HAS_BUTTONS | wx.TR_HIDE_ROOT | wx.TR_NO_LINES)
self.parent = parent.GetParent()
isz = (16,16)
il = wx.ImageList(isz[0], isz[1])
self.img0 = fldridx = il.Add(wx.ArtProvider_GetBitmap(wx.ART_FOLDER, wx.ART_OTHER, isz))
self.img1 = fldropenidx = il.Add(wx.ArtProvider_GetBitmap(wx.ART_FILE_OPEN, wx.ART_OTHER, isz))
i = wx.EmptyImage(*isz)
i.SetData(isz[0]*isz[1]*3*'\xff')
self.img2 = fileidx = il.Add(wx.BitmapFromImage(i))
self.SetImageList(il)
self.il = il
self.root = self.AddRoot("The hidden root item")
self.SetItemImage(self.root, fldridx, wx.TreeItemIcon_Normal)
self.SetItemImage(self.root, fldropenidx, wx.TreeItemIcon_Expanded)
self.Bind(wx.EVT_TREE_ITEM_ACTIVATED, self.OnActivate, self)
self.last = ''
self.lasti = None
self.pattern = None
def setData(self, arrayOfTuples):
self.Clear()
self.ExtendEntries(arrayOfTuples)
def Clear(self):
self.DeleteAllItems()
def AppendEntry(self, tuple):
if tuple[0] != self.last:
self.last = tuple[0]
self.lasti = self.AppendItem(self.root, self.last)
self.SetItemImage(self.lasti, self.img0, wx.TreeItemIcon_Normal)
self.SetItemImage(self.lasti, self.img1, wx.TreeItemIcon_Expanded)
self.Expand(self.lasti)
#set color of item
it = self.AppendItem(self.lasti, " %s: %s"%(tuple[1:3]))
self.SetItemImage(it, self.img2, wx.TreeItemIcon_Normal)
def ExtendEntries(self, arrayOfTuples):
for i in arrayOfTuples:
self.AppendEntry(i)
def OnActivate(self, event):
item = event.GetItem()
parent = self.GetItemParent(item)
if parent == self.root:
event.Skip()
return
file = self.GetItemText(parent)
data = self.GetItemText(item)
line = int(data.split(':')[0].strip())
self.parent.OpenFound(file, line, self.pattern, ('\\n' in data) and len(data.encode('utf-8')))
#-----------------------------------------------------------------------------
viewoptions = {'table': FoundTable,
'tree' : FoundTree,
'text' : FoundText}
class FindInFiles(wx.Panel):
def __init__(self, parent, root):
wx.Panel.__init__(self, parent, -1)
self.current_thread = None
self.found = []
self.parent = parent
self.root = root
self.running = 0
self.stopping = 0
self.starting = 0
winids = []
## controlsWindow = wx.SashLayoutWindow(
## self, -1, wx.DefaultPosition, (200, 30),
## wx.NO_BORDER|wx.SW_3D)
## controlsWindow.SetOrientation(wx.LAYOUT_VERTICAL)
## controlsWindow.SetAlignment(wx.LAYOUT_LEFT)
## controlsWindow.SetSashVisible(wx.SASH_RIGHT, True)
## self.controlsWindow = controlsWindow
## winids.append(controlsWindow.GetId())
self.controlsWindow = controlsWindow = wx.SplitterWindow(self, -1, style=wx.SP_NOBORDER)
fc = self.readPreferences()
self.scope = fc['scope']
## self.Bind(wx.EVT_SIZE, self.OnSize)
self.scrolledPanel = scrolled.ScrolledPanel(controlsWindow, -1,
style=wx.TAB_TRAVERSAL|wx.SUNKEN_BORDER)
SLF = self.scrolledPanel
self.viewResultsAs = fc['view']
self.resultsWindow = viewoptions.get(fc['view'], FoundText)(controlsWindow)
## winids.append(self.resultsWindow.GetId())
## self.Bind(
## wx.EVT_SASH_DRAGGED_RANGE, self.OnSashDrag,
## id=min(winids), id2=max(winids)
## )
def static(text, style=wx.ALIGN_LEFT):
return wx.StaticText(SLF, -1, text, style=style)
def checkb(text, val=0, style=wx.NO_BORDER):
a = wx.CheckBox(SLF, -1, text, style=style)
a.SetValue(val)
return a
def combobox(ch, d=''):
a = wx.ComboBox(SLF, -1, choices=ch, style=wx.CB_DROPDOWN,
size=(100, 1))
if ch: a.SetSelection(0)
elif d: a.SetValue(d)
return a
def button(name, fcn):
id = wx.NewId()
a = wx.Button(SLF, id, name)
wx.EVT_BUTTON(SLF, id, fcn)
return a
#------------------------------
gbs = self.gbs = wx.GridBagSizer(5, 5)
outsideBorder=5
lastColumn=4
editBoxSpan=(1, lastColumn-1)
allSpan=(1, lastColumn+1)
row=0
gbs.Add(static("Search for:"), (row,0),
flag=wx.ALIGN_RIGHT|wx.ALIGN_CENTER_VERTICAL|wx.LEFT|wx.TOP,
border=outsideBorder)
self.search = combobox(fc['search'])
gbs.Add(self.search, (row,1), editBoxSpan,
flag=wx.EXPAND|wx.TOP,
border=outsideBorder)
self.b=button("Start Search", self.OnFindButtonClick)
self.b.SetDefault()
gbs.Add(self.b, (row,lastColumn),
flag=wx.ALIGN_LEFT|wx.RIGHT|wx.TOP,
border=outsideBorder)
row+=1
gbs.Add(static("Within:"), (row,0),
flag=wx.ALIGN_RIGHT|wx.ALIGN_CENTER_VERTICAL|wx.LEFT,
border=outsideBorder)
scopes = [
'Selected Text',
'Current File',
'Current File with Includes',
'',
'Open Files',
#'Project', #perhaps if/when PyPE has projects
#'Workspace', #perhaps for PyPE 2.1
'Directories',
'Tags in Directories',
#'',
#'Dictionary', #yikes, requires shipping a dictionary or the internet requirements.
#'Internet', #yikes, requires shipping urllib, a parser, etc.
]
self.scopeChoice = wx.Choice(self.scrolledPanel, -1,
choices = scopes)
try:
self.scopeChoice.SetSelection(scopes.index(fc['scope']))
except:
self.scopeChoice.SetSelection('Directories')
self.Bind(wx.EVT_CHOICE, self.OnScopeChoice, self.scopeChoice)
gbs.Add(self.scopeChoice, (row,1), editBoxSpan,
flag=wx.EXPAND)
opt_sizer = wx.BoxSizer(wx.VERTICAL)
self.cs = checkb("Case sensitive", fc['case'])
self.re = checkb("Regular Expression", fc['regex'])
self.multiline = checkb("Multiline", fc['multiline'])
opt_sizer.Add(self.cs, flag=wx.ALIGN_LEFT|wx.TOP, border=2)
opt_sizer.Add(self.re, flag=wx.ALIGN_LEFT|wx.TOP, border=2)
opt_sizer.Add(self.multiline, flag=wx.ALIGN_LEFT|wx.TOP, border=2)
opt_sizer.Layout()
row+=1
gbs.Add(opt_sizer, (row,1), (1,2),
wx.RIGHT, outsideBorder)
opt_sizer2 = wx.BoxSizer(wx.VERTICAL)
self.ww = checkb("Whole Word", fc['whole_word'])
self.quoted = checkb("Quoted", fc['quoted'])
self.commented = checkb("Commented", fc['commented'])
self.uncommented = checkb("Uncommented", fc['uncommented'])
opt_sizer2.Add(self.ww, flag=wx.ALIGN_LEFT|wx.TOP, border=2)
opt_sizer2.Add(self.quoted, flag=wx.ALIGN_LEFT|wx.TOP, border=2)
opt_sizer2.Add(self.commented, flag=wx.ALIGN_LEFT|wx.TOP, border=2)
opt_sizer2.Add(self.uncommented, flag=wx.ALIGN_LEFT|wx.TOP, border=2)
opt_sizer2.Layout()
#row+=1
gbs.Add(opt_sizer2, (row,3), (1,2),
wx.RIGHT, outsideBorder)
self.Bind(wx.EVT_CHECKBOX, self.VerifyChecks, self.commented)
self.Bind(wx.EVT_CHECKBOX, self.VerifyChecks, self.uncommented)
row+=1
self.line = wx.StaticLine(
self.scrolledPanel, -1, style=wx.LI_HORIZONTAL)
gbs.Add(self.line, (row,0), allSpan,
wx.EXPAND|wx.ALIGN_CENTER_VERTICAL|wx.ALL, 10)
row+=1
gbs.Add(
static("Separate multiple directories and criteria with ; (semicolons)"),
(row,0), allSpan, flag=wx.ALIGN_CENTER)
row+=1
gbs.Add(static("Directories:"), (row,0),
flag=wx.ALIGN_RIGHT|wx.ALIGN_CENTER_VERTICAL|wx.LEFT,
border=outsideBorder)
self.sdirs = combobox(fc['dirs'])
gbs.Add(self.sdirs, (row,1), editBoxSpan, flag=wx.EXPAND)
self.add_path = button("Add Path", self.OnDirButtonClick)
gbs.Add(self.add_path, (row,lastColumn),
flag=wx.ALIGN_LEFT|wx.RIGHT,
border=outsideBorder)
row+=1
gbs.Add(static("Exclude Dirs:"), (row,0),
flag=wx.ALIGN_RIGHT|wx.ALIGN_CENTER_VERTICAL|wx.LEFT,
border=outsideBorder)
self.exdirs = combobox(fc['excludedirs'])
gbs.Add(self.exdirs, (row,1), editBoxSpan, flag=wx.EXPAND)
row+=1
gbs.Add(static("Include:"), (row,0),
flag=wx.ALIGN_RIGHT|wx.ALIGN_CENTER_VERTICAL|wx.LEFT,
border=outsideBorder)
self.include = combobox(fc['include'])
gbs.Add(self.include, (row,1), editBoxSpan,
flag=wx.EXPAND)
row+=1
gbs.Add(static("Exclude:"), (row,0),
flag=wx.ALIGN_RIGHT|wx.ALIGN_CENTER_VERTICAL|wx.LEFT,
border=outsideBorder)
self.exclude = combobox(fc['exclude'])
gbs.Add(self.exclude, (row,1), editBoxSpan,
flag=wx.EXPAND)
row+=1
self.ss = checkb("Search Subdirectories", fc['search_sub_dirs'])
## gbs.Add(self.ss, (row,1), (1,lastColumn),
gbs.Add(self.ss, (row,1), (1,2),
flag=wx.ALIGN_LEFT|wx.BOTTOM,
border=outsideBorder)
self.dd = checkb("Ignore .subdirs", fc['ignore_dotted_dirs'])
gbs.Add(self.dd, (row,3), (1,2),
flag=wx.ALIGN_LEFT|wx.BOTTOM,
border=outsideBorder)
row+=1
self.line = wx.StaticLine(
self.scrolledPanel, -1, style=wx.LI_HORIZONTAL)
gbs.Add(self.line, (row,0), allSpan,
wx.EXPAND|wx.ALIGN_CENTER_VERTICAL|wx.ALL, 10)
row+=1
gbs.Add(static("View As:"), (row,0),
flag=wx.ALIGN_RIGHT|wx.ALIGN_CENTER_VERTICAL|wx.LEFT,
border=outsideBorder)
#views=['table', 'text', 'tree']
views=['table', 'text', 'tree']
self.viewChoice = wx.Choice(self.scrolledPanel, -1,
choices = views)
self.viewChoice.SetSelection(views.index(fc['view']))
self.Bind(wx.EVT_CHOICE, self.OnViewChoice, self.viewChoice)
gbs.Add(self.viewChoice, (row,1), editBoxSpan,
flag=wx.EXPAND|wx.TOP,
border=outsideBorder)
self.enable_controls = [self.sdirs, self.add_path, self.ss, self.dd]
self.checkscope()
#------------------------------
#gbs.AddGrowableRow(0)
gbs.AddGrowableCol(1)
self.scrolledPanel.SetSizer(gbs)
## self.scrolledPanel.SetAutoLayout(True)
self.scrolledPanel.SetupScrolling()
## cwSizer = wx.BoxSizer(wx.HORIZONTAL)
## cwSizer.Add(self.scrolledPanel, 1, wx.EXPAND)
## self.controlsWindow.SetSizerAndFit(cwSizer)
## self.controlsWindow.SetAutoLayout(True)
## self.controlsWindow.Layout()
## #HACK:
## minSize=[i+40 for i in self.controlsWindow.GetMinSize()]
## self.controlsWindow.SetDefaultSize(minSize)
## parent.SetClientSize(self.GetSize())
s = wx.BoxSizer(wx.VERTICAL)
self.controlsWindow.SplitVertically(self.scrolledPanel, self.resultsWindow)
s.Add(self.controlsWindow, 1, wx.EXPAND)
self.SetSizer(s)
#------------------------------
## self.SetAutoLayout(True)
self.timer = Timer(self.OnFindButtonClick)
wx.CallAfter(self.splitctrl, _pype.SEARCH_SASH_POSITION)
def splitctrl(self, size):
self.controlsWindow.SetSashPosition(max(size, 200))
#-------------------------------------------------------------------------
def VerifyChecks(self, evt):
if self.commented.IsChecked() and self.uncommented.IsChecked():
if evt.GetEventObject() == self.commented:
self.uncommented.SetValue(0)
else:
self.commented.SetValue(0)
def getfn(self, win):
return win.getlong()
def OnScopeChoice(self, event):
scope=event.GetString()
## print 'scope', scope
if self.scope != scope:
self.scope=scope
self.savePreferences()
self.checkscope()
def checkscope(self):
enable = self.scopeChoice.GetStringSelection() in enable_options
for i in self.enable_controls:
i.Enable(enable)
def OnViewChoice(self, event):
view=event.GetString()
if self.viewResultsAs != view:
self.viewResultsAs=view
self.savePreferences()
#toss old results window
x = self.resultsWindow.pattern
y = self.controlsWindow.GetSashPosition()
self.controlsWindow.Unsplit()
self.resultsWindow.Destroy()
#create new results window
self.resultsWindow = viewoptions.get(view, FoundText)(self.controlsWindow)
self.controlsWindow.SplitVertically(self.scrolledPanel, self.resultsWindow, y)
self.resultsWindow.pattern = x
## self.Bind(wx.EVT_SASH_DRAGGED_RANGE, self.OnSashDrag, self.resultsWindow)
#populate new results window
self.resultsWindow.setData(self.found)
## self.OnSize(event)
def OnSashDrag(self, event):
if event.GetDragStatus() == wx.SASH_STATUS_OUT_OF_RANGE:
self.log.write('drag is out of range')
return
eobj = event.GetEventObject()
if eobj is self.controlsWindow:
self.controlsWindow.SetDefaultSize((event.GetDragRect().width, 1000))
elif eobj is self.resultsWindow:
self.resultsWindow.SetDefaultSize((event.GetDragRect().width, 1000))
wx.LayoutAlgorithm().LayoutWindow(self, self.resultsWindow)
#self.controlsWindow.Layout()
self.resultsWindow.Refresh()
x = self.scrolledPanel.GetSize()[0]
y = self.GetSize()[1]
self.scrolledPanel.SetSize((x,y))
print "sash dragged", (x,y)
def OnSize(self, event):
y = event.GetSize()[1]
wx.LayoutAlgorithm().LayoutWindow(self, self.resultsWindow)
x = self.scrolledPanel.GetSize()[0]
self.scrolledPanel.SetSize((x,y))
print "resized", (x,y)
def OnClear(self, e):
print "OnClear"
self.results.Clear()
def OnExit(self, e):
print "OnExit"
def OpenFound(self, file, line, pattern, multiline):
if file[:1] == '<':
#untitled files
a = self.root.getPositionAbsolute(file, 1)
if a == -1:
return
self.root.control.SetSelection(a)
else:
self.root.OnDrop([file], 1)
wx.CallAfter(self._OpenFound, file, line, pattern, multiline)
def _OpenFound(self, file, line, pattern, multiline):
a = self.root.control.GetSelection()
if a > -1:
line -= 1
stc = self.root.control.GetPage(a).GetWindow1()
start = 0
end = stc.GetLineEndPosition(line)
if line != 0:
start = stc.GetLineEndPosition(line-1)+len(stc.format)
#handle overflow
eml = min(end+multiline, stc.GetLength())
if multiline:
t = fixnewlines(stc.GetTextRange(start, eml))
else:
t = stc.GetLine(line)
grp = pattern(t)
if grp != None:
end = grp.end() + start
start = grp.start() + start
if stc.format == '\r\n':
#handle line ending fixing
end += grp.group().count('\n')
stc.SetFocus()
line = stc.LineFromPosition((start+end)//2)
stc.GotoLine(line)
stc.SetSelection(start, end)
stc.EnsureVisible(line)
stc.EnsureCaretVisible()
def OnDirButtonClick(self, e):
dlg = wx.DirDialog(self, "Choose a directory", style=wx.DD_DEFAULT_STYLE, pos=(0,0))
a = dlg.ShowModal()
if a == wx.ID_OK:
a = self.sdirs.GetValue()
if a:
self.sdirs.SetValue(a+';'+dlg.GetPath())
else:
self.sdirs.SetValue(dlg.GetPath())
dlg.Destroy()
self.savePreferences()
def OnFindButtonClick(self, e):
global spaces_per_tab
if self.stopping:
#already stopping
return
elif self.running:
#running, we want to try to stop
self.stopping = 1
self.b.SetLabel("Start Search")
return
if e.GetId() == self.b.GetId():
if self.starting:
#previously was waiting to start due to an
#external yield, abort waiting and cancel
#search
self.starting = 0
self.b.SetLabel("Start Search")
return
elif not self.starting:
#I was a waiting timer event, but I don't
#need to start anymore
return
spaces_per_tab = self.root.getglobal('spaces_per_tab')
#try to start
self.starting = 1
self.b.SetLabel("Stop Search")
try:
wx.Yield()
except:
## print "excepted", 1
#would have tried to start while in another function's
#wx.Yield() call. Will wait 100ms and try again.
self.timer.Start(100, wx.TIMER_ONE_SHOT)
return
self.savePreferences()
#am currently the topmost call, so will continue.
self.starting = 0
self.running = 1
wx.Yield()
pattern = self.search.GetValue()
paths = self.sdirs.GetValue().split(';')
exdirs = self.exdirs.GetValue().split(';')
include = self.include.GetValue().split(';')
exclude = self.exclude.GetValue().split(';')
caseSensitive = self.cs.IsChecked()
wholeWord = self.ww.IsChecked()
self.checkComment = self.commented.IsChecked()*2 + self.uncommented.IsChecked()
self.checkQuoted = self.quoted.IsChecked()
multiline = self.multiline.IsChecked()
subd = self.ss.IsChecked()
igndot = self.dd.IsChecked()
#python strings
if pattern and pattern[-1] in ['"', "'"]:
try:
pattern = [i for i in compiler.parse(str(pattern)).getChildren()[:1] if isinstance(i, basestring)][0]
except Exception, e:
pass
multiline = multiline or '\n' in pattern
if not self.re.IsChecked():
pattern = re.escape(pattern)
if wholeWord:
pattern = "\\b%s\\b"%(pattern,)
try:
if caseSensitive:
pattern = re.compile(pattern)
else:
pattern = re.compile(pattern, re.IGNORECASE)
except Exception, why:
self.starting = 0
self.stopping = 0
self.running = 0
self.b.SetLabel("Start Search")
self.root.SetStatusText("regular expression compilation failed: %r"%(why,))
return
self.pattern = pattern
self.resultsWindow.Clear()
self.resultsWindow.pattern = pattern.search
if multiline:
searchFile = self.searchFileMultiline
else:
searchFile = self.searchFileEachLine
self.found = found = []
fileCount = 0
hitFileCount = 0
ch = self.scope.lower().replace(' ', '_')
fcn = self.directories
if hasattr(self, ch):
fcn = getattr(self, ch)
if ch not in ('tags_in_directories', 'directories'):
paths = ('',)
self.startTime=time.time()
state = iter(paths), iter(()), fcn, searchFile, found, 0, 0, exdirs, subd, include, exclude, igndot
t = threading.Thread(target=self._threaded_search, args=(state,))
t.setDaemon(1)
t.start()
def _threaded_search(self, state):
path_i, data_i, nf_fcn, s_fcn, found, hfc, fc, exdirs, subd, include, exclude, igndot = state
ss = "Found %i instances in %i files out of %i files %s%s."
for path in path_i:
for fn, data in nf_fcn(path, exdirs, subd, include, exclude, igndot):
fc += 1
new_found = s_fcn(fn, data, state)
if new_found:
hfc += 1
found += new_found
wx.CallAfter(self.resultsWindow.ExtendEntries, new_found)
if self.stopping:
break
pfn = ''
if fn:
pfn = ' "'+fn+'"'
wx.CallAfter(self.root.SetStatusText, ss%(len(found), hfc, fc, "so far", pfn), log=0)
if self.stopping:
break
msg = 'Find in files cancelled.'
if not self.stopping:
msg = ss%(len(found), hfc, fc, "checked (in %.2f seconds)"%(time.time()-self.startTime,), "")
wx.CallAfter(self._finish_search, msg)
def _finish_search(self, msg):
self.running = 0
self.starting = 0
self.stopping = 0
self.root.SetStatusText(msg)
self.b.SetLabel("Start Search")
#--------------------------- scopes for searching ----------------------------
def current_file(self, *args):
try:
_, win = self.root.getNumWin()
yield self.getfn(win), fixnewlines(StyledTextCtrl.GetText(win))
except cancelled:
pass
def current_file_with_includes(self, path, subdirs, include, exclude, ignore_dotted=0):
try:
_, win = self.root.getNumWin()
t = fixnewlines(StyledTextCtrl.GetText(win))
yield self.getfn(win), t
typ, lst = find_imports(t)
if typ == C:
for pth in lst:
a = os.path.join(win.dirname, pth)
if os.path.isfile(a):
if namematches(a.split('/')[-1], include, exclude):
try:
x = self.root.GetPositionAbsolute(a)
if x != -1:
t = StyledTextCtrl.GetText(self.root.GetPage(x).GetWindow1())
else:
t = open(a, 'rb').read()
t = fixnewlines(t)
except:
continue
yield a, t
elif typ == PY:
tried = {}
extns = ['.py', '.pyw', os.path.sep+'__init__.py', os.path.sep+'__init__.pyw']
for pth in lst:
found = 0
pth = pth.split('.')
while not found and pth:
for extn in extns:
a = win.dirname + os.path.sep + os.path.sep.join(pth) + extn
if a in tried:
found = 1
break
tried[a] = None
if os.path.isfile(a):
if namematches(a.split('/')[-1], include, exclude):
try:
x = self.root.GetPositionAbsolute(a)
if x != -1:
t = StyledTextCtrl.GetText(self.root.GetPage(x).GetWindow1())
else:
t = open(a, 'rb').read()
t = fixnewlines(t)
found = 1
tried[a] = 1
break
except Exception, why:
continue
if not found and pth:
_ = pth.pop()
if found and pth and tried[a]:
yield a,t
tried[a] = None
except cancelled:
pass
def selected_text(self, *args):
try:
_, win = self.root.getNumWin()
#add some prefix lines so that the line offset is correct
data = (win.LineFromPosition(win.GetSelection()[0])*'\n' +
fixnewlines(win.GetTextRange(*win.GetSelection())))
yield self.getfn(win), data
except cancelled:
pass
def open_files(self, path, exdirs, subdirs, include, exclude, ignore_dotted=0):
for win in self.root.control:
full = self.getfn(win)
if namematches(win.filename, include, exclude) and not [i for i in exdirs if i and full.startswith(i)]:
yield full, fixnewlines(StyledTextCtrl.GetText(win))
## else:
## print win.filename, namematches(win.filename, include, exclude), [i for i in exdirs if i and full.startswith(i)]
def directories(self, path, exdirs, subdirs, include, exclude, ignore_dotted=0):
try:
lst = os.listdir(path)
except Exception, e:
print e
self.root.SetStatusText("Directory \"%s\" not found."%(path,))
return
d = []
for filen in lst:
a = os.path.join(path, filen)
if os.path.isfile(a):
if namematches(filen, include, exclude):
yield a, open(a, 'rU').read()
elif subdirs and os.path.isdir(a):
if (not ignore_dotted) or filen[:1] != '.':
excluded = 0
for exdir in exdirs:
if fnmatch.fnmatch(filen, exdir):
excluded = 1
if not excluded:
d.append(a)
if subdirs:
for p in d:
for f in self.directories(p, exdirs, subdirs, include, exclude, ignore_dotted):
yield f
def tags_in_directories(self, *args):
for fn, content in self.directories(*args):
for line in content.split('\n'):
if line and line.count('\t') != 2:
break
else:
yield fn, content
#----------------------------- searching methods -----------------------------
def searchFileMultiline(self, fileName, data, state):
found = []
cp = 0
lc = 0
t = time.time()
for match in self.pattern.finditer(data):
lc += data.count('\n', cp, match.start())
cp = match.start()
found.append((fileName, lc + 1, match.group().replace('\n', '\\n'), ''))
if self.stopping:
break
if _pype.UNICODE:
found = [(i,j,k.decode('latin-1'),l.decode('latin-1')) for i,j,k,l in found]
return found
def searchFileEachLine(self, fileName, data, state):
lines = data.split('\n')
found = []
search=self.pattern.search
pth = os.path.split(fileName)[0] #for tags support
language = _pype.get_filetype(fileName)
t = time.time()
for number, line in enumerate(lines):
itemOrig=line
if self.checkComment == 2:
match=commentedPatterns[language].search(line)
if match is None:
continue
line=match.group(1)
elif self.checkComment == 1:
match=uncommentedPatterns[language].search(line)
if match is None:
continue
line=match.group(1)
if self.checkQuoted:
matches=quotedPattern.finditer(line)
if matches is None:
continue
for match in matches:
line=match.group()[1:-1]
if search(line) is not None:
# (filename, line, line contents, extra)
found.append((fileName, int(number) + 1, itemOrig.strip(), ''))
else:
if search(line) is not None:
# (filename, line, line contents, extra)
if self.scope == 'Tags':
try:
tag, fn, xtra = line.split('\t')
lineno = int(xtra.split(';')[0])
found.append((os.path.join(pth, fn), lineno, itemOrig.strip(), ';'.join(xtra.split(';')[1:])))
except:
found.append((fileName, int(number) + 1, itemOrig.strip(), ''))
else:
found.append((fileName, int(number) + 1, itemOrig.strip(), ''))
if self.stopping:
break
if _pype.UNICODE:
found = [(i,j,k.decode('latin-1'),l.decode('latin-1')) for i,j,k,l in found]
return found
#---------------------------- preference handling ----------------------------
def readPreferences(self):
prefs = self.root.config.setdefault('FindInFilesPlugin', {})
# Set the defaults individually so that adding options works
# as expected.
prefs.setdefault('prefs_version', 1)
prefs.setdefault('search', [])
prefs.setdefault('case', 0)
prefs.setdefault('regex', 0)
prefs.setdefault('multiline', 0)
prefs.setdefault('whole_word', 0)
prefs.setdefault('quoted', 0)
prefs.setdefault('commented', 0)
prefs.setdefault('uncommented', 0)
if prefs['commented'] and prefs['uncommented']:
prefs['uncommented'] = 0
prefs.setdefault('scope', 'Current File')
prefs.setdefault('dirs', [])
prefs.setdefault('excludedirs',[])
prefs.setdefault('include', ['*.*'])
prefs.setdefault('exclude', ['.*;*.bak;*.orig;~*;*.swp;CVS'])
prefs.setdefault('search_sub_dirs', 1)
prefs.setdefault('ignore_dotted_dirs', 1)
prefs.setdefault('view', 'table')
self.preferences = prefs
return prefs
def savePreferences(self):
def getlist(c):
cc = c.GetCount()
e = [c.GetString(i) for i in xrange(cc)]
a = c.GetValue()
if a in e:
e.remove(a)
e = [a] + e
e = e[:10]
if len(e) > cc:
c.Append(e[-1])
for i in xrange(len(e)):
c.SetString(i, e[i])
c.SetSelection(0)
return e
prefs = {
'prefs_version': 1,
'scope': self.scopeChoice.GetStringSelection(),
'search': getlist(self.search),
'case': self.cs.IsChecked(),
'regex': self.re.IsChecked(),
'multiline': self.multiline.IsChecked(),
'whole_word': self.ww.IsChecked(),
'quoted': self.quoted.IsChecked(),
'commented': self.commented.IsChecked(),
'uncommented': self.uncommented.IsChecked(),
'dirs': getlist(self.sdirs),
'excludedirs': getlist(self.exdirs),
'include': getlist(self.include),
'exclude': getlist(self.exclude),
'search_sub_dirs': self.ss.IsChecked(),
'ignore_dotted_dirs': self.dd.IsChecked(),
'view': self.viewChoice.GetStringSelection(),
}
self.root.config['FindInFilesPlugin'] = prefs
#-------------------------------------------------------------------------
#------------------------------ small up arrow -------------------------------
def getSmallUpArrowData():
return \
'\x89PNG\r\n\x1a\n\x00\x00\x00\rIHDR\x00\x00\x00\x10\x00\x00\x00\x10\x08\x06\
\x00\x00\x00\x1f\xf3\xffa\x00\x00\x00\x04sBIT\x08\x08\x08\x08|\x08d\x88\x00\
\x00\x00<IDATx\x9ccddbf\xa0\x040Q\xa4{h\x18\xf0\xff\xdf\xdf\xffd\x1b\x00\xd3\
\x8c\xcf\x10\x9c\x06\xa0k\xc2e\x08m\xc2\x00\x97m\xd8\xc41\x0c \x14h\xe8\xf2\
\x8c\xa3)q\x10\x18\x00\x00R\xd8#\xec\x95{\xc4\x11\x00\x00\x00\x00IEND\xaeB`\
\x82'
def getSmallUpArrowBitmap():
return BitmapFromImage(getSmallUpArrowImage())
def getSmallUpArrowImage():
stream = cStringIO.StringIO(getSmallUpArrowData())
return ImageFromStream(stream)
#----------------------------- small down arrow ------------------------------
def getSmallDnArrowData():
return \
"\x89PNG\r\n\x1a\n\x00\x00\x00\rIHDR\x00\x00\x00\x10\x00\x00\x00\x10\x08\x06\
\x00\x00\x00\x1f\xf3\xffa\x00\x00\x00\x04sBIT\x08\x08\x08\x08|\x08d\x88\x00\
\x00\x00HIDATx\x9ccddbf\xa0\x040Q\xa4{\xd4\x00\x06\x06\x06\x06\x06\x16t\x81\
\xff\xff\xfe\xfe'\xa4\x89\x91\x89\x99\x11\xa7\x0b\x90%\ti\xc6j\x00>C\xb0\x89\
\xd3.\x10\xd1m\xc3\xe5*\xbc.\x80i\xc2\x17.\x8c\xa3y\x81\x01\x00\xa1\x0e\x04e\
\x1d\xc4;\xb7\x00\x00\x00\x00IEND\xaeB`\x82"
def getSmallDnArrowBitmap():
return BitmapFromImage(getSmallDnArrowImage())
def getSmallDnArrowImage():
stream = cStringIO.StringIO(getSmallDnArrowData())
return ImageFromStream(stream)
|