1from __future__ import print_function 2import os 3import fnmatch 4import re # for htest 5import sys 6from Tkinter import StringVar, BooleanVar, Checkbutton # for GrepDialog 7from Tkinter import Tk, Text, Button, SEL, END # for htest 8from idlelib import SearchEngine 9from idlelib.SearchDialogBase import SearchDialogBase 10# Importing OutputWindow fails due to import loop 11# EditorWindow -> GrepDialop -> OutputWindow -> EditorWindow 12 13def grep(text, io=None, flist=None): 14 root = text._root() 15 engine = SearchEngine.get(root) 16 if not hasattr(engine, "_grepdialog"): 17 engine._grepdialog = GrepDialog(root, engine, flist) 18 dialog = engine._grepdialog 19 searchphrase = text.get("sel.first", "sel.last") 20 dialog.open(text, searchphrase, io) 21 22class GrepDialog(SearchDialogBase): 23 24 title = "Find in Files Dialog" 25 icon = "Grep" 26 needwrapbutton = 0 27 28 def __init__(self, root, engine, flist): 29 SearchDialogBase.__init__(self, root, engine) 30 self.flist = flist 31 self.globvar = StringVar(root) 32 self.recvar = BooleanVar(root) 33 34 def open(self, text, searchphrase, io=None): 35 SearchDialogBase.open(self, text, searchphrase) 36 if io: 37 path = io.filename or "" 38 else: 39 path = "" 40 dir, base = os.path.split(path) 41 head, tail = os.path.splitext(base) 42 if not tail: 43 tail = ".py" 44 self.globvar.set(os.path.join(dir, "*" + tail)) 45 46 def create_entries(self): 47 SearchDialogBase.create_entries(self) 48 self.globent = self.make_entry("In files:", self.globvar)[0] 49 50 def create_other_buttons(self): 51 f = self.make_frame()[0] 52 53 btn = Checkbutton(f, anchor="w", 54 variable=self.recvar, 55 text="Recurse down subdirectories") 56 btn.pack(side="top", fill="both") 57 btn.select() 58 59 def create_command_buttons(self): 60 SearchDialogBase.create_command_buttons(self) 61 self.make_button("Search Files", self.default_command, 1) 62 63 def default_command(self, event=None): 64 prog = self.engine.getprog() 65 if not prog: 66 return 67 path = self.globvar.get() 68 if not path: 69 self.top.bell() 70 return 71 from idlelib.OutputWindow import OutputWindow # leave here! 72 save = sys.stdout 73 try: 74 sys.stdout = OutputWindow(self.flist) 75 self.grep_it(prog, path) 76 finally: 77 sys.stdout = save 78 79 def grep_it(self, prog, path): 80 dir, base = os.path.split(path) 81 list = self.findfiles(dir, base, self.recvar.get()) 82 list.sort() 83 self.close() 84 pat = self.engine.getpat() 85 print("Searching %r in %s ..." % (pat, path)) 86 hits = 0 87 try: 88 for fn in list: 89 try: 90 with open(fn) as f: 91 for lineno, line in enumerate(f, 1): 92 if line[-1:] == '\n': 93 line = line[:-1] 94 if prog.search(line): 95 sys.stdout.write("%s: %s: %s\n" % 96 (fn, lineno, line)) 97 hits += 1 98 except IOError as msg: 99 print(msg) 100 print(("Hits found: %s\n" 101 "(Hint: right-click to open locations.)" 102 % hits) if hits else "No hits.") 103 except AttributeError: 104 # Tk window has been closed, OutputWindow.text = None, 105 # so in OW.write, OW.text.insert fails. 106 pass 107 108 def findfiles(self, dir, base, rec): 109 try: 110 names = os.listdir(dir or os.curdir) 111 except os.error as msg: 112 print(msg) 113 return [] 114 list = [] 115 subdirs = [] 116 for name in names: 117 fn = os.path.join(dir, name) 118 if os.path.isdir(fn): 119 subdirs.append(fn) 120 else: 121 if fnmatch.fnmatch(name, base): 122 list.append(fn) 123 if rec: 124 for subdir in subdirs: 125 list.extend(self.findfiles(subdir, base, rec)) 126 return list 127 128 def close(self, event=None): 129 if self.top: 130 self.top.grab_release() 131 self.top.withdraw() 132 133 134def _grep_dialog(parent): # htest # 135 from idlelib.PyShell import PyShellFileList 136 root = Tk() 137 root.title("Test GrepDialog") 138 width, height, x, y = list(map(int, re.split('[x+]', parent.geometry()))) 139 root.geometry("+%d+%d"%(x, y + 150)) 140 141 flist = PyShellFileList(root) 142 text = Text(root, height=5) 143 text.pack() 144 145 def show_grep_dialog(): 146 text.tag_add(SEL, "1.0", END) 147 grep(text, flist=flist) 148 text.tag_remove(SEL, "1.0", END) 149 150 button = Button(root, text="Show GrepDialog", command=show_grep_dialog) 151 button.pack() 152 root.mainloop() 153 154if __name__ == "__main__": 155 import unittest 156 unittest.main('idlelib.idle_test.test_grep', verbosity=2, exit=False) 157 158 from idlelib.idle_test.htest import run 159 run(_grep_dialog) 160