1import os
2import fnmatch
3import sys
4from Tkinter import *
5from idlelib import SearchEngine
6from idlelib.SearchDialogBase import SearchDialogBase
7
8def grep(text, io=None, flist=None):
9    root = text._root()
10    engine = SearchEngine.get(root)
11    if not hasattr(engine, "_grepdialog"):
12        engine._grepdialog = GrepDialog(root, engine, flist)
13    dialog = engine._grepdialog
14    searchphrase = text.get("sel.first", "sel.last")
15    dialog.open(text, searchphrase, io)
16
17class GrepDialog(SearchDialogBase):
18
19    title = "Find in Files Dialog"
20    icon = "Grep"
21    needwrapbutton = 0
22
23    def __init__(self, root, engine, flist):
24        SearchDialogBase.__init__(self, root, engine)
25        self.flist = flist
26        self.globvar = StringVar(root)
27        self.recvar = BooleanVar(root)
28
29    def open(self, text, searchphrase, io=None):
30        SearchDialogBase.open(self, text, searchphrase)
31        if io:
32            path = io.filename or ""
33        else:
34            path = ""
35        dir, base = os.path.split(path)
36        head, tail = os.path.splitext(base)
37        if not tail:
38            tail = ".py"
39        self.globvar.set(os.path.join(dir, "*" + tail))
40
41    def create_entries(self):
42        SearchDialogBase.create_entries(self)
43        self.globent = self.make_entry("In files:", self.globvar)
44
45    def create_other_buttons(self):
46        f = self.make_frame()
47
48        btn = Checkbutton(f, anchor="w",
49                variable=self.recvar,
50                text="Recurse down subdirectories")
51        btn.pack(side="top", fill="both")
52        btn.select()
53
54    def create_command_buttons(self):
55        SearchDialogBase.create_command_buttons(self)
56        self.make_button("Search Files", self.default_command, 1)
57
58    def default_command(self, event=None):
59        prog = self.engine.getprog()
60        if not prog:
61            return
62        path = self.globvar.get()
63        if not path:
64            self.top.bell()
65            return
66        from idlelib.OutputWindow import OutputWindow
67        save = sys.stdout
68        try:
69            sys.stdout = OutputWindow(self.flist)
70            self.grep_it(prog, path)
71        finally:
72            sys.stdout = save
73
74    def grep_it(self, prog, path):
75        dir, base = os.path.split(path)
76        list = self.findfiles(dir, base, self.recvar.get())
77        list.sort()
78        self.close()
79        pat = self.engine.getpat()
80        print "Searching %r in %s ..." % (pat, path)
81        hits = 0
82        for fn in list:
83            try:
84                f = open(fn)
85            except IOError, msg:
86                print msg
87                continue
88            lineno = 0
89            while 1:
90                block = f.readlines(100000)
91                if not block:
92                    break
93                for line in block:
94                    lineno = lineno + 1
95                    if line[-1:] == '\n':
96                        line = line[:-1]
97                    if prog.search(line):
98                        sys.stdout.write("%s: %s: %s\n" % (fn, lineno, line))
99                        hits = hits + 1
100        if hits:
101            if hits == 1:
102                s = ""
103            else:
104                s = "s"
105            print "Found", hits, "hit%s." % s
106            print "(Hint: right-click to open locations.)"
107        else:
108            print "No hits."
109
110    def findfiles(self, dir, base, rec):
111        try:
112            names = os.listdir(dir or os.curdir)
113        except os.error, msg:
114            print msg
115            return []
116        list = []
117        subdirs = []
118        for name in names:
119            fn = os.path.join(dir, name)
120            if os.path.isdir(fn):
121                subdirs.append(fn)
122            else:
123                if fnmatch.fnmatch(name, base):
124                    list.append(fn)
125        if rec:
126            for subdir in subdirs:
127                list.extend(self.findfiles(subdir, base, rec))
128        return list
129
130    def close(self, event=None):
131        if self.top:
132            self.top.grab_release()
133            self.top.withdraw()
134