| David Scherer | 7aced17 | 2000-08-15 01:13:23 +0000 | [diff] [blame] | 1 | import os | 
| David Scherer | 7aced17 | 2000-08-15 01:13:23 +0000 | [diff] [blame] | 2 | import fnmatch | 
 | 3 | import sys | 
| Georg Brandl | 14fc427 | 2008-05-17 18:39:55 +0000 | [diff] [blame] | 4 | from tkinter import * | 
| Kurt B. Kaiser | 2d7f6a0 | 2007-08-22 23:01:33 +0000 | [diff] [blame] | 5 | from idlelib import SearchEngine | 
 | 6 | from idlelib.SearchDialogBase import SearchDialogBase | 
| David Scherer | 7aced17 | 2000-08-15 01:13:23 +0000 | [diff] [blame] | 7 |  | 
 | 8 | def 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 | 
| Kurt B. Kaiser | ef58adf | 2003-06-07 03:21:17 +0000 | [diff] [blame] | 14 |     searchphrase = text.get("sel.first", "sel.last") | 
 | 15 |     dialog.open(text, searchphrase, io) | 
| David Scherer | 7aced17 | 2000-08-15 01:13:23 +0000 | [diff] [blame] | 16 |  | 
 | 17 | class 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 |  | 
| Kurt B. Kaiser | ef58adf | 2003-06-07 03:21:17 +0000 | [diff] [blame] | 29 |     def open(self, text, searchphrase, io=None): | 
 | 30 |         SearchDialogBase.open(self, text, searchphrase) | 
| David Scherer | 7aced17 | 2000-08-15 01:13:23 +0000 | [diff] [blame] | 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 | 
| Kurt B. Kaiser | 2d7f6a0 | 2007-08-22 23:01:33 +0000 | [diff] [blame] | 66 |         from idlelib.OutputWindow import OutputWindow | 
| David Scherer | 7aced17 | 2000-08-15 01:13:23 +0000 | [diff] [blame] | 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() | 
| Guido van Rossum | be19ed7 | 2007-02-09 05:37:30 +0000 | [diff] [blame] | 80 |         print("Searching %r in %s ..." % (pat, path)) | 
| David Scherer | 7aced17 | 2000-08-15 01:13:23 +0000 | [diff] [blame] | 81 |         hits = 0 | 
 | 82 |         for fn in list: | 
 | 83 |             try: | 
| Terry Jan Reedy | de3beb2 | 2013-06-22 18:26:51 -0400 | [diff] [blame] | 84 |                 with open(fn, errors='replace') as f: | 
 | 85 |                     for lineno, line in enumerate(f, 1): | 
 | 86 |                         if line[-1:] == '\n': | 
 | 87 |                             line = line[:-1] | 
 | 88 |                         if prog.search(line): | 
 | 89 |                             sys.stdout.write("%s: %s: %s\n" % | 
 | 90 |                                              (fn, lineno, line)) | 
 | 91 |                             hits += 1 | 
| Andrew Svetlov | f7a17b4 | 2012-12-25 16:47:37 +0200 | [diff] [blame] | 92 |             except OSError as msg: | 
| Guido van Rossum | be19ed7 | 2007-02-09 05:37:30 +0000 | [diff] [blame] | 93 |                 print(msg) | 
| Terry Jan Reedy | de3beb2 | 2013-06-22 18:26:51 -0400 | [diff] [blame] | 94 |         print(("Hits found: %s\n" | 
 | 95 |               "(Hint: right-click to open locations.)" | 
 | 96 |               % hits) if hits else "No hits.") | 
| David Scherer | 7aced17 | 2000-08-15 01:13:23 +0000 | [diff] [blame] | 97 |  | 
 | 98 |     def findfiles(self, dir, base, rec): | 
 | 99 |         try: | 
 | 100 |             names = os.listdir(dir or os.curdir) | 
| Terry Jan Reedy | c3111fc | 2014-02-23 00:37:16 -0500 | [diff] [blame] | 101 |         except OSError as msg: | 
| Guido van Rossum | be19ed7 | 2007-02-09 05:37:30 +0000 | [diff] [blame] | 102 |             print(msg) | 
| David Scherer | 7aced17 | 2000-08-15 01:13:23 +0000 | [diff] [blame] | 103 |             return [] | 
 | 104 |         list = [] | 
 | 105 |         subdirs = [] | 
 | 106 |         for name in names: | 
 | 107 |             fn = os.path.join(dir, name) | 
 | 108 |             if os.path.isdir(fn): | 
 | 109 |                 subdirs.append(fn) | 
 | 110 |             else: | 
 | 111 |                 if fnmatch.fnmatch(name, base): | 
 | 112 |                     list.append(fn) | 
 | 113 |         if rec: | 
 | 114 |             for subdir in subdirs: | 
 | 115 |                 list.extend(self.findfiles(subdir, base, rec)) | 
 | 116 |         return list | 
 | 117 |  | 
 | 118 |     def close(self, event=None): | 
 | 119 |         if self.top: | 
 | 120 |             self.top.grab_release() | 
 | 121 |             self.top.withdraw() | 
| Terry Jan Reedy | de3beb2 | 2013-06-22 18:26:51 -0400 | [diff] [blame] | 122 |  | 
 | 123 | if __name__ == "__main__": | 
 | 124 |     # A human test is a bit tricky since EditorWindow() imports this module. | 
 | 125 |     # Hence Idle must be restarted after editing this file for a live test. | 
 | 126 |     import unittest | 
 | 127 |     unittest.main('idlelib.idle_test.test_grep', verbosity=2, exit=False) |