• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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