grep dialog for find in files functionality inherits from searchdialogbase for gui and uses searchengine to prepare search pattern importing outputwindow here fails due to import loop editorwindow grepdialog outputwindow editorwindow open the find in files dialog modulelevel function to access the singleton grepdialog instance and open the dialog if text is selected it is used as the search phrase otherwise the previous entry is used args text text widget that contains the selected text for default search phrase io iomenu iobinding instance with default path to search flist filelist filelist instance for outputwindow parent generate file names in dir that match pattern args folder root directory to search pattern file pattern to match recursive true to include subdirectories create search dialog for searching for a phrase in the file system uses searchdialogbase as the basis for the gui and a searchengine instance to prepare the search attributes flist filelist filelist instance for outputwindow parent globvar string value of entry widget for path to search globent entry widget for globvar created in createentries recvar boolean value of checkbutton widget for traversing through subdirectories make dialog visible on top of others and ready to use extend the searchdialogbase open to set the initial value for globvar args text multicall object containing the text information searchphrase string phrase to search io iomenu iobinding instance containing file path grep for search pattern in file path the default command is bound to return if entry values are populated set outputwindow as stdout and perform search the search dialog is closed automatically when the search begins search for prog within the lines of the files in path for the each file in the path directory open the file and search each line for the matching pattern if the pattern is found write the file and line information to stdout which is an outputwindow args prog the compiled cooked search pattern path string containing the search path tk window has been closed outputwindow text none so in ow write ow text insert fails frame imported in base importing outputwindow here fails due to import loop editorwindow grepdialog outputwindow editorwindow open the find in files dialog module level function to access the singleton grepdialog instance and open the dialog if text is selected it is used as the search phrase otherwise the previous entry is used args text text widget that contains the selected text for default search phrase io iomenu iobinding instance with default path to search flist filelist filelist instance for outputwindow parent generate file names in dir that match pattern args folder root directory to search pattern file pattern to match recursive true to include subdirectories create search dialog for searching for a phrase in the file system uses searchdialogbase as the basis for the gui and a searchengine instance to prepare the search attributes flist filelist filelist instance for outputwindow parent globvar string value of entry widget for path to search globent entry widget for globvar created in create_entries recvar boolean value of checkbutton widget for traversing through subdirectories make dialog visible on top of others and ready to use extend the searchdialogbase open to set the initial value for globvar args text multicall object containing the text information searchphrase string phrase to search io iomenu iobinding instance containing file path grep for search pattern in file path the default command is bound to return if entry values are populated set outputwindow as stdout and perform search the search dialog is closed automatically when the search begins leave here search for prog within the lines of the files in path for the each file in the path directory open the file and search each line for the matching pattern if the pattern is found write the file and line information to stdout which is an outputwindow args prog the compiled cooked search pattern path string containing the search path tk window has been closed outputwindow text none so in ow write ow text insert fails htest
import fnmatch
import os
import sys

from tkinter import StringVar, BooleanVar
from tkinter.ttk import Checkbutton  

from idlelib.searchbase import SearchDialogBase
from idlelib import searchengine





def grep(text, io=None, flist=None):
    
    root = text._root()
    engine = searchengine.get(root)
    if not hasattr(engine, "_grepdialog"):
        engine._grepdialog = GrepDialog(root, engine, flist)
    dialog = engine._grepdialog
    searchphrase = text.get("sel.first", "sel.last")
    dialog.open(text, searchphrase, io)


def walk_error(msg):
    "Handle os.walk error."
    print(msg)


def findfiles(folder, pattern, recursive):
    
    for dirpath, _, filenames in os.walk(folder, onerror=walk_error):
        yield from (os.path.join(dirpath, name)
                    for name in filenames
                    if fnmatch.fnmatch(name, pattern))
        if not recursive:
            break


class GrepDialog(SearchDialogBase):
    "Dialog for searching multiple files."

    title = "Find in Files Dialog"
    icon = "Grep"
    needwrapbutton = 0

    def __init__(self, root, engine, flist):
        
        super().__init__(root, engine)
        self.flist = flist
        self.globvar = StringVar(root)
        self.recvar = BooleanVar(root)

    def open(self, text, searchphrase, io=None):
        
        SearchDialogBase.open(self, text, searchphrase)
        if io:
            path = io.filename or ""
        else:
            path = ""
        dir, base = os.path.split(path)
        head, tail = os.path.splitext(base)
        if not tail:
            tail = ".py"
        self.globvar.set(os.path.join(dir, "*" + tail))

    def create_entries(self):
        "Create base entry widgets and add widget for search path."
        SearchDialogBase.create_entries(self)
        self.globent = self.make_entry("In files:", self.globvar)[0]

    def create_other_buttons(self):
        "Add check button to recurse down subdirectories."
        btn = Checkbutton(
                self.make_frame()[0], variable=self.recvar,
                text="Recurse down subdirectories")
        btn.pack(side="top", fill="both")

    def create_command_buttons(self):
        "Create base command buttons and add button for Search Files."
        SearchDialogBase.create_command_buttons(self)
        self.make_button("Search Files", self.default_command, isdef=True)

    def default_command(self, event=None):
        
        prog = self.engine.getprog()
        if not prog:
            return
        path = self.globvar.get()
        if not path:
            self.top.bell()
            return
        from idlelib.outwin import OutputWindow  
        save = sys.stdout
        try:
            sys.stdout = OutputWindow(self.flist)
            self.grep_it(prog, path)
        finally:
            sys.stdout = save

    def grep_it(self, prog, path):
        
        folder, filepat = os.path.split(path)
        if not folder:
            folder = os.curdir
        filelist = sorted(findfiles(folder, filepat, self.recvar.get()))
        self.close()
        pat = self.engine.getpat()
        print(f"Searching {pat!r} in {path} ...")
        hits = 0
        try:
            for fn in filelist:
                try:
                    with open(fn, errors='replace') as f:
                        for lineno, line in enumerate(f, 1):
                            if line[-1:] == '\n':
                                line = line[:-1]
                            if prog.search(line):
                                sys.stdout.write(f"{fn}: {lineno}: {line}\n")
                                hits += 1
                except OSError as msg:
                    print(msg)
            print(f"Hits found: {hits}\n(Hint: right-click to open locations.)"
                  if hits else "No hits.")
        except AttributeError:
            
            
            pass


def _grep_dialog(parent):  
    from tkinter import Toplevel, Text, SEL, END
    from tkinter.ttk import Frame, Button
    from idlelib.pyshell import PyShellFileList

    top = Toplevel(parent)
    top.title("Test GrepDialog")
    x, y = map(int, parent.geometry().split('+')[1:])
    top.geometry(f"+{x}+{y + 175}")

    flist = PyShellFileList(top)
    frame = Frame(top)
    frame.pack()
    text = Text(frame, height=5)
    text.pack()

    def show_grep_dialog():
        text.tag_add(SEL, "1.0", END)
        grep(text, flist=flist)
        text.tag_remove(SEL, "1.0", END)

    button = Button(frame, text="Show GrepDialog", command=show_grep_dialog)
    button.pack()

if __name__ == "__main__":
    from unittest import main
    main('idlelib.idle_test.test_grep', verbosity=2, exit=False)

    from idlelib.idle_test.htest import run
    run(_grep_dialog)