blob: 77195b997579686c5f47ea673cabc8f88612b214 [file] [log] [blame]
David Scherer7aced172000-08-15 01:13:23 +00001import os
David Scherer7aced172000-08-15 01:13:23 +00002import fnmatch
Terry Jan Reedyc5767a62014-06-10 02:49:29 -04003import re # for htest
David Scherer7aced172000-08-15 01:13:23 +00004import sys
Terry Jan Reedyc5767a62014-06-10 02:49:29 -04005from Tkinter import StringVar, BooleanVar, Checkbutton # for GrepDialog
6from Tkinter import Tk, Text, Button, SEL, END # for htest
Florent Xiclunad630c042010-04-02 07:24:52 +00007from idlelib import SearchEngine
Terry Jan Reedyc5767a62014-06-10 02:49:29 -04008import itertools
Florent Xiclunad630c042010-04-02 07:24:52 +00009from idlelib.SearchDialogBase import SearchDialogBase
Terry Jan Reedyc5767a62014-06-10 02:49:29 -040010# Importing OutputWindow fails due to import loop
11# EditorWindow -> GrepDialop -> OutputWindow -> EditorWindow
David Scherer7aced172000-08-15 01:13:23 +000012
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
Kurt B. Kaiseref58adf2003-06-07 03:21:17 +000019 searchphrase = text.get("sel.first", "sel.last")
20 dialog.open(text, searchphrase, io)
David Scherer7aced172000-08-15 01:13:23 +000021
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
Kurt B. Kaiseref58adf2003-06-07 03:21:17 +000034 def open(self, text, searchphrase, io=None):
35 SearchDialogBase.open(self, text, searchphrase)
David Scherer7aced172000-08-15 01:13:23 +000036 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)
Terry Jan Reedye2c409f2014-07-13 17:27:21 -040048 self.globent = self.make_entry("In files:", self.globvar)[0]
David Scherer7aced172000-08-15 01:13:23 +000049
50 def create_other_buttons(self):
Terry Jan Reedye2c409f2014-07-13 17:27:21 -040051 f = self.make_frame()[0]
David Scherer7aced172000-08-15 01:13:23 +000052
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
Terry Jan Reedyc5767a62014-06-10 02:49:29 -040071 from idlelib.OutputWindow import OutputWindow # leave here!
David Scherer7aced172000-08-15 01:13:23 +000072 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()
Terry Jan Reedyc5767a62014-06-10 02:49:29 -040085 print("Searching %r in %s ..." % (pat, path))
David Scherer7aced172000-08-15 01:13:23 +000086 hits = 0
Terry Jan Reedyc5767a62014-06-10 02:49:29 -040087 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
David Scherer7aced172000-08-15 01:13:23 +0000107
108 def findfiles(self, dir, base, rec):
109 try:
110 names = os.listdir(dir or os.curdir)
Terry Jan Reedy2b149862013-06-29 00:59:34 -0400111 except os.error as msg:
Terry Jan Reedyc5767a62014-06-10 02:49:29 -0400112 print(msg)
David Scherer7aced172000-08-15 01:13:23 +0000113 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()
Terry Jan Reedy223a22b2013-06-22 18:26:38 -0400132
Terry Jan Reedyc5767a62014-06-10 02:49:29 -0400133
134def _grep_dialog(parent): # for htest
Terry Jan Reedy76916e82014-05-29 01:46:16 -0400135 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
Terry Jan Reedy223a22b2013-06-22 18:26:38 -0400154if __name__ == "__main__":
Terry Jan Reedy223a22b2013-06-22 18:26:38 -0400155 import unittest
156 unittest.main('idlelib.idle_test.test_grep', verbosity=2, exit=False)
Terry Jan Reedy76916e82014-05-29 01:46:16 -0400157
158 from idlelib.idle_test.htest import run
159 run(_grep_dialog)