blob: 721b231a9e86bc654e17da318fd7f239be2defba [file] [log] [blame]
David Scherer7aced172000-08-15 01:13:23 +00001import os
David Scherer7aced172000-08-15 01:13:23 +00002import fnmatch
Terry Jan Reedy47623822014-06-10 02:49:35 -04003import re # for htest
David Scherer7aced172000-08-15 01:13:23 +00004import sys
Terry Jan Reedy47623822014-06-10 02:49:35 -04005from tkinter import StringVar, BooleanVar, Checkbutton # for GrepDialog
6from tkinter import Tk, Text, Button, SEL, END # for htest
Kurt B. Kaiser2d7f6a02007-08-22 23:01:33 +00007from idlelib import SearchEngine
8from idlelib.SearchDialogBase import SearchDialogBase
Terry Jan Reedy47623822014-06-10 02:49:35 -04009# Importing OutputWindow fails due to import loop
10# EditorWindow -> GrepDialop -> OutputWindow -> EditorWindow
David Scherer7aced172000-08-15 01:13:23 +000011
12def grep(text, io=None, flist=None):
13 root = text._root()
14 engine = SearchEngine.get(root)
15 if not hasattr(engine, "_grepdialog"):
16 engine._grepdialog = GrepDialog(root, engine, flist)
17 dialog = engine._grepdialog
Kurt B. Kaiseref58adf2003-06-07 03:21:17 +000018 searchphrase = text.get("sel.first", "sel.last")
19 dialog.open(text, searchphrase, io)
David Scherer7aced172000-08-15 01:13:23 +000020
21class GrepDialog(SearchDialogBase):
22
23 title = "Find in Files Dialog"
24 icon = "Grep"
25 needwrapbutton = 0
26
27 def __init__(self, root, engine, flist):
28 SearchDialogBase.__init__(self, root, engine)
29 self.flist = flist
30 self.globvar = StringVar(root)
31 self.recvar = BooleanVar(root)
32
Kurt B. Kaiseref58adf2003-06-07 03:21:17 +000033 def open(self, text, searchphrase, io=None):
34 SearchDialogBase.open(self, text, searchphrase)
David Scherer7aced172000-08-15 01:13:23 +000035 if io:
36 path = io.filename or ""
37 else:
38 path = ""
39 dir, base = os.path.split(path)
40 head, tail = os.path.splitext(base)
41 if not tail:
42 tail = ".py"
43 self.globvar.set(os.path.join(dir, "*" + tail))
44
45 def create_entries(self):
46 SearchDialogBase.create_entries(self)
Terry Jan Reedy5283c4e2014-07-13 17:27:26 -040047 self.globent = self.make_entry("In files:", self.globvar)[0]
David Scherer7aced172000-08-15 01:13:23 +000048
49 def create_other_buttons(self):
Terry Jan Reedy5283c4e2014-07-13 17:27:26 -040050 f = self.make_frame()[0]
David Scherer7aced172000-08-15 01:13:23 +000051
52 btn = Checkbutton(f, anchor="w",
53 variable=self.recvar,
54 text="Recurse down subdirectories")
55 btn.pack(side="top", fill="both")
56 btn.select()
57
58 def create_command_buttons(self):
59 SearchDialogBase.create_command_buttons(self)
60 self.make_button("Search Files", self.default_command, 1)
61
62 def default_command(self, event=None):
63 prog = self.engine.getprog()
64 if not prog:
65 return
66 path = self.globvar.get()
67 if not path:
68 self.top.bell()
69 return
Terry Jan Reedy47623822014-06-10 02:49:35 -040070 from idlelib.OutputWindow import OutputWindow # leave here!
David Scherer7aced172000-08-15 01:13:23 +000071 save = sys.stdout
72 try:
73 sys.stdout = OutputWindow(self.flist)
74 self.grep_it(prog, path)
75 finally:
76 sys.stdout = save
77
78 def grep_it(self, prog, path):
79 dir, base = os.path.split(path)
80 list = self.findfiles(dir, base, self.recvar.get())
81 list.sort()
82 self.close()
83 pat = self.engine.getpat()
Guido van Rossumbe19ed72007-02-09 05:37:30 +000084 print("Searching %r in %s ..." % (pat, path))
David Scherer7aced172000-08-15 01:13:23 +000085 hits = 0
Terry Jan Reedy47623822014-06-10 02:49:35 -040086 try:
87 for fn in list:
88 try:
89 with open(fn, errors='replace') as f:
90 for lineno, line in enumerate(f, 1):
91 if line[-1:] == '\n':
92 line = line[:-1]
93 if prog.search(line):
94 sys.stdout.write("%s: %s: %s\n" %
95 (fn, lineno, line))
96 hits += 1
97 except OSError as msg:
98 print(msg)
99 print(("Hits found: %s\n"
100 "(Hint: right-click to open locations.)"
101 % hits) if hits else "No hits.")
102 except AttributeError:
103 # Tk window has been closed, OutputWindow.text = None,
104 # so in OW.write, OW.text.insert fails.
105 pass
David Scherer7aced172000-08-15 01:13:23 +0000106
107 def findfiles(self, dir, base, rec):
108 try:
109 names = os.listdir(dir or os.curdir)
Terry Jan Reedyc3111fc2014-02-23 00:37:16 -0500110 except OSError as msg:
Guido van Rossumbe19ed72007-02-09 05:37:30 +0000111 print(msg)
David Scherer7aced172000-08-15 01:13:23 +0000112 return []
113 list = []
114 subdirs = []
115 for name in names:
116 fn = os.path.join(dir, name)
117 if os.path.isdir(fn):
118 subdirs.append(fn)
119 else:
120 if fnmatch.fnmatch(name, base):
121 list.append(fn)
122 if rec:
123 for subdir in subdirs:
124 list.extend(self.findfiles(subdir, base, rec))
125 return list
126
127 def close(self, event=None):
128 if self.top:
129 self.top.grab_release()
130 self.top.withdraw()
Terry Jan Reedyde3beb22013-06-22 18:26:51 -0400131
Terry Jan Reedy47623822014-06-10 02:49:35 -0400132
Terry Jan Reedycd567362014-10-17 01:31:35 -0400133def _grep_dialog(parent): # htest #
Terry Jan Reedy2e8234a2014-05-29 01:46:26 -0400134 from idlelib.PyShell import PyShellFileList
135 root = Tk()
136 root.title("Test GrepDialog")
137 width, height, x, y = list(map(int, re.split('[x+]', parent.geometry())))
138 root.geometry("+%d+%d"%(x, y + 150))
139
140 flist = PyShellFileList(root)
141 text = Text(root, height=5)
142 text.pack()
143
144 def show_grep_dialog():
145 text.tag_add(SEL, "1.0", END)
146 grep(text, flist=flist)
147 text.tag_remove(SEL, "1.0", END)
148
149 button = Button(root, text="Show GrepDialog", command=show_grep_dialog)
150 button.pack()
151 root.mainloop()
152
Terry Jan Reedyde3beb22013-06-22 18:26:51 -0400153if __name__ == "__main__":
Terry Jan Reedyde3beb22013-06-22 18:26:51 -0400154 import unittest
155 unittest.main('idlelib.idle_test.test_grep', verbosity=2, exit=False)
Terry Jan Reedy2e8234a2014-05-29 01:46:26 -0400156
157 from idlelib.idle_test.htest import run
158 run(_grep_dialog)