GrepSearch - butscher/WikidPad GitHub Wiki
Unfortunately WikidPads built-in search can be a little slow when searching a large number of files.
The plugin below is a quick hack to allow searching a via grep from within Wikidpad. If you do a large amount of searching you will notice a dramatic speedup (especially on subsequent searches due to caching).
- It is not particularly polished code and is missing a few features that I may add in the future.
- WARNING: your search is passed to the shell 'grep -ni "{--your search term--}" {--your wiki data dir--/*.wiki}' when searching.
Grep - Should be installed by default on all *nix based os' (It may well work on windows if you install [http://gnuwin32.sourceforge.net/packages/grep.htm grep] or another compatible clone)
import os, wx, subprocess, re from collections import defaultdict from urllib2 import unquote import threading WIKIDPAD_PLUGIN = (("MenuFunctions",1),) def describeMenuItems(wiki): global nextnumber return ((Grep, "Grep Search\tCtrl-Shift-F", "Search with Grep"),) class ResultsList(wx.HtmlListBox): def __init__(self, parent, pWiki): wx.HtmlListBox.__init__(self, parent, -1) self.pWiki = pWiki self.parent = parent wx.EVT_LISTBOX_DCLICK(self, -1, self.OnDClick) def SetResults(self, results, results_count): self.results = results self.results_count = results_count self.Refresh() def OnGetItem(self, n): wikipage, line, string = self.results[n] if line is None: # Header return "<table><tr><td width=100%></td></tr></table><table><tr><td bgcolor='blue' width='6'></td><td><font color='blue'><b>{0} <u>({1})</u></b></font></td></tr></table>".format(wikipage, self.results_count[wikipage]) return "<table><tr><td bgcolor='lightblue' width='6'></td><td><font color='black'><u>Line {0}</u> - {1}</font></td></tr></table>".format(line, string) def GetCount(self): return len(self.results) def OnDClick(self, evt): sel = self.GetSelection() if sel == -1 or self.GetCount() == 0: return wikiWord, line, string = self.results[sel] self.pWiki.openWikiPage(wikiWord) # TODO: check editor state and goto line if line: l = int(line) editor = self.pWiki.getActiveEditor() if editor is not None: #editor.SetCurrentPos(0) #editor.SetAnchor(0) editor.GotoLine(l-1) #print self.parent.search_string editor.SearchAnchor() editor.SearchNext(wx.stc.STC_FIND_REGEXP, self.parent.search_string) #editor.SetCaretLineVisible(True) #editor.SetCaretLineBack("red") class GrepDialog(wx.Dialog): def __init__(self, pWiki, id=wx.ID_ANY, title="Grep Search"): wx.Dialog.__init__(self, pWiki, id, title, style=wx.DEFAULT_DIALOG_STYLE|wx.RESIZE_BORDER) self.pWiki = pWiki search_box = wx.TextCtrl(self, -1) pre_search_box = wx.TextCtrl(self, -1) results_box = ResultsList(self, pWiki) #results_box.SetItemCount(0) self.results_box = results_box btnFind = wx.Button(self, label="&Search", id=wx.ID_FIND) btnCancel = wx.Button(self, label="&Cancel", id=wx.ID_CANCEL) buttons = wx.BoxSizer(wx.HORIZONTAL) buttons.Add(btnFind) buttons.Add(btnCancel) btnFind.Bind(wx.EVT_BUTTON, self.OnSearch) btnCancel.Bind(wx.EVT_BUTTON, self.OnClose) btnFind.SetDefault() sizer = wx.BoxSizer(wx.VERTICAL) sizer.Add(results_box, 1, wx.EXPAND|wx.ALL, 5) sizer.Add(search_box, 0, wx.HORIZONTAL|wx.EXPAND, 5) sizer.Add(pre_search_box, 0, wx.HORIZONTAL|wx.EXPAND, 5) sizer.Add(buttons, 0, wx.EXPAND|wx.ALL, 5) self.SetSizerAndFit(sizer) self.SetSize((200, 400)) search_box.SetFocus() self.search_box = search_box self.pre_search_box = pre_search_box self.Bind(wx.EVT_KEY_DOWN, self.OnKeyDown) def OnKeyDown(self, evt): print evt.GetKeyCode() self.OnClose() def OnSearch(self, evt): search_string = self.search_box.GetValue() if not search_string: return self.search_string = search_string data_dir = self.pWiki.dataDir self.data_dir = data_dir pre_search = self.pre_search_box.GetValue() t = threading.Thread(target=self.Search, args=(search_string, data_dir, pre_search)) self.SetTitle("Searching for: {0}".format(self.search_box.GetValue())) self.results_box.SetItemCount(0) t.start() #t.join() def LoadResults(self): results = [] pages = set() results_count = defaultdict(int) l = len(self.data_dir) + 1 for i in self.results.split("\n")[:-1]: wikipage, line, context_string = i.split(":", 2) wikipage = unquote(wikipage[l:-5]) if wikipage not in pages: results.append((wikipage, None, None)) pages.add(wikipage) results_count[wikipage] += 1 context_string = re.sub(r"({0})".format(self.search_string), r"<font color='red'>\1</font>", context_string, flags=re.IGNORECASE) results.append((wikipage, line, context_string)) self.results_box.SetResults(results, results_count) self.results_box.SetItemCount(len(results)) number_results = sum([results_count[i] for i in results_count]) self.SetTitle("Found {0} matches (on {1} pages)".format(number_results, len(results_count))) def Search(self, search_string, data_dir, pre_search=""): #self.Refresh() search_cmd = os.path.join(data_dir, "".join([pre_search, "*.wiki"])) try: ret = subprocess.check_output('grep -ni "{0}" {1}'.format(search_string, search_cmd), shell=True) except: # No results wx.CallAfter(self.SetTitle,"No Results") return self.results = ret wx.CallAfter(self.LoadResults) def OnClose(self, evt=None): #self.Show(False) self.Destroy() def Grep(pWiki, evt): search = GrepDialog(pWiki) search.Show()