blob: 64ba28d94a5c141154a99068da94a86cad154798 [file] [log] [blame]
David Scherer7aced172000-08-15 01:13:23 +00001import fnmatch
Terry Jan Reedybfbaa6b2016-08-31 00:50:55 -04002import os
David Scherer7aced172000-08-15 01:13:23 +00003import sys
Terry Jan Reedybfbaa6b2016-08-31 00:50:55 -04004
Terry Jan Reedy6f7b0f52016-07-10 20:21:31 -04005from tkinter import StringVar, BooleanVar
6from tkinter.ttk import Checkbutton
Terry Jan Reedybfbaa6b2016-08-31 00:50:55 -04007
Terry Jan Reedy6fa5bdc2016-05-28 13:22:31 -04008from idlelib.searchbase import SearchDialogBase
Terry Jan Reedybfbaa6b2016-08-31 00:50:55 -04009from idlelib import searchengine
10
11# Importing OutputWindow here fails due to import loop
Terry Jan Reedy47623822014-06-10 02:49:35 -040012# EditorWindow -> GrepDialop -> OutputWindow -> EditorWindow
David Scherer7aced172000-08-15 01:13:23 +000013
14def grep(text, io=None, flist=None):
15 root = text._root()
Terry Jan Reedy6fa5bdc2016-05-28 13:22:31 -040016 engine = searchengine.get(root)
David Scherer7aced172000-08-15 01:13:23 +000017 if not hasattr(engine, "_grepdialog"):
18 engine._grepdialog = GrepDialog(root, engine, flist)
19 dialog = engine._grepdialog
Kurt B. Kaiseref58adf2003-06-07 03:21:17 +000020 searchphrase = text.get("sel.first", "sel.last")
21 dialog.open(text, searchphrase, io)
David Scherer7aced172000-08-15 01:13:23 +000022
23class GrepDialog(SearchDialogBase):
24
25 title = "Find in Files Dialog"
26 icon = "Grep"
27 needwrapbutton = 0
28
29 def __init__(self, root, engine, flist):
30 SearchDialogBase.__init__(self, root, engine)
31 self.flist = flist
32 self.globvar = StringVar(root)
33 self.recvar = BooleanVar(root)
34
Kurt B. Kaiseref58adf2003-06-07 03:21:17 +000035 def open(self, text, searchphrase, io=None):
36 SearchDialogBase.open(self, text, searchphrase)
David Scherer7aced172000-08-15 01:13:23 +000037 if io:
38 path = io.filename or ""
39 else:
40 path = ""
41 dir, base = os.path.split(path)
42 head, tail = os.path.splitext(base)
43 if not tail:
44 tail = ".py"
45 self.globvar.set(os.path.join(dir, "*" + tail))
46
47 def create_entries(self):
48 SearchDialogBase.create_entries(self)
Terry Jan Reedy5283c4e2014-07-13 17:27:26 -040049 self.globent = self.make_entry("In files:", self.globvar)[0]
David Scherer7aced172000-08-15 01:13:23 +000050
51 def create_other_buttons(self):
Terry Jan Reedy6f7b0f52016-07-10 20:21:31 -040052 btn = Checkbutton(
53 self.make_frame()[0], variable=self.recvar,
David Scherer7aced172000-08-15 01:13:23 +000054 text="Recurse down subdirectories")
55 btn.pack(side="top", fill="both")
David Scherer7aced172000-08-15 01:13:23 +000056
57 def create_command_buttons(self):
58 SearchDialogBase.create_command_buttons(self)
59 self.make_button("Search Files", self.default_command, 1)
60
61 def default_command(self, event=None):
62 prog = self.engine.getprog()
63 if not prog:
64 return
65 path = self.globvar.get()
66 if not path:
67 self.top.bell()
68 return
Terry Jan Reedy6fa5bdc2016-05-28 13:22:31 -040069 from idlelib.outwin import OutputWindow # leave here!
David Scherer7aced172000-08-15 01:13:23 +000070 save = sys.stdout
71 try:
72 sys.stdout = OutputWindow(self.flist)
73 self.grep_it(prog, path)
74 finally:
75 sys.stdout = save
76
77 def grep_it(self, prog, path):
78 dir, base = os.path.split(path)
79 list = self.findfiles(dir, base, self.recvar.get())
80 list.sort()
81 self.close()
82 pat = self.engine.getpat()
Guido van Rossumbe19ed72007-02-09 05:37:30 +000083 print("Searching %r in %s ..." % (pat, path))
David Scherer7aced172000-08-15 01:13:23 +000084 hits = 0
Terry Jan Reedy47623822014-06-10 02:49:35 -040085 try:
86 for fn in list:
87 try:
88 with open(fn, errors='replace') as f:
89 for lineno, line in enumerate(f, 1):
90 if line[-1:] == '\n':
91 line = line[:-1]
92 if prog.search(line):
93 sys.stdout.write("%s: %s: %s\n" %
94 (fn, lineno, line))
95 hits += 1
96 except OSError as msg:
97 print(msg)
98 print(("Hits found: %s\n"
99 "(Hint: right-click to open locations.)"
100 % hits) if hits else "No hits.")
101 except AttributeError:
102 # Tk window has been closed, OutputWindow.text = None,
103 # so in OW.write, OW.text.insert fails.
104 pass
David Scherer7aced172000-08-15 01:13:23 +0000105
106 def findfiles(self, dir, base, rec):
107 try:
108 names = os.listdir(dir or os.curdir)
Terry Jan Reedyc3111fc2014-02-23 00:37:16 -0500109 except OSError as msg:
Guido van Rossumbe19ed72007-02-09 05:37:30 +0000110 print(msg)
David Scherer7aced172000-08-15 01:13:23 +0000111 return []
112 list = []
113 subdirs = []
114 for name in names:
115 fn = os.path.join(dir, name)
116 if os.path.isdir(fn):
117 subdirs.append(fn)
118 else:
119 if fnmatch.fnmatch(name, base):
120 list.append(fn)
121 if rec:
122 for subdir in subdirs:
123 list.extend(self.findfiles(subdir, base, rec))
124 return list
125
126 def close(self, event=None):
127 if self.top:
128 self.top.grab_release()
129 self.top.withdraw()
Terry Jan Reedyde3beb22013-06-22 18:26:51 -0400130
Terry Jan Reedy47623822014-06-10 02:49:35 -0400131
Terry Jan Reedycd567362014-10-17 01:31:35 -0400132def _grep_dialog(parent): # htest #
Terry Jan Reedy6f7b0f52016-07-10 20:21:31 -0400133 from tkinter import Toplevel, Text, SEL, END
134 from tkinter.ttk import Button
Terry Jan Reedybfbaa6b2016-08-31 00:50:55 -0400135 from idlelib.pyshell import PyShellFileList
Terry Jan Reedyb60adc52016-06-21 18:41:38 -0400136 top = Toplevel(parent)
137 top.title("Test GrepDialog")
Terry Jan Reedya7480322016-07-10 17:28:10 -0400138 x, y = map(int, parent.geometry().split('+')[1:])
139 top.geometry("+%d+%d" % (x, y + 175))
Terry Jan Reedy2e8234a2014-05-29 01:46:26 -0400140
Terry Jan Reedyb60adc52016-06-21 18:41:38 -0400141 flist = PyShellFileList(top)
142 text = Text(top, height=5)
Terry Jan Reedy2e8234a2014-05-29 01:46:26 -0400143 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
Terry Jan Reedyb60adc52016-06-21 18:41:38 -0400150 button = Button(top, text="Show GrepDialog", command=show_grep_dialog)
Terry Jan Reedy2e8234a2014-05-29 01:46:26 -0400151 button.pack()
Terry Jan Reedy2e8234a2014-05-29 01:46:26 -0400152
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)