Team Ai
Datasetpublic

codekingpro/portable-devtools

sourceHugging Faceupdated 5mo agoView on Hugging Face
1likes14kdownloads
grep.py224 linesDownload Raw Back to idlelib
1"""Grep dialog for Find in Files functionality.2 3   Inherits from SearchDialogBase for GUI and uses searchengine4   to prepare search pattern.5"""6import fnmatch7import os8import sys9 10from tkinter import StringVar, BooleanVar11from tkinter.ttk import Checkbutton  # Frame imported in ...Base12 13from idlelib.searchbase import SearchDialogBase14from idlelib import searchengine15 16# Importing OutputWindow here fails due to import loop17# EditorWindow -> GrepDialog -> OutputWindow -> EditorWindow18 19 20def grep(text, io=None, flist=None):21    """Open the Find in Files dialog.22 23    Module-level function to access the singleton GrepDialog24    instance and open the dialog.  If text is selected, it is25    used as the search phrase; otherwise, the previous entry26    is used.27 28    Args:29        text: Text widget that contains the selected text for30              default search phrase.31        io: iomenu.IOBinding instance with default path to search.32        flist: filelist.FileList instance for OutputWindow parent.33    """34    root = text._root()35    engine = searchengine.get(root)36    if not hasattr(engine, "_grepdialog"):37        engine._grepdialog = GrepDialog(root, engine, flist)38    dialog = engine._grepdialog39    searchphrase = text.get("sel.first", "sel.last")40    dialog.open(text, searchphrase, io)41 42 43def walk_error(msg):44    "Handle os.walk error."45    print(msg)46 47 48def findfiles(folder, pattern, recursive):49    """Generate file names in dir that match pattern.50 51    Args:52        folder: Root directory to search.53        pattern: File pattern to match.54        recursive: True to include subdirectories.55    """56    for dirpath, _, filenames in os.walk(folder, onerror=walk_error):57        yield from (os.path.join(dirpath, name)58                    for name in filenames59                    if fnmatch.fnmatch(name, pattern))60        if not recursive:61            break62 63 64class GrepDialog(SearchDialogBase):65    "Dialog for searching multiple files."66 67    title = "Find in Files Dialog"68    icon = "Grep"69    needwrapbutton = 070 71    def __init__(self, root, engine, flist):72        """Create search dialog for searching for a phrase in the file system.73 74        Uses SearchDialogBase as the basis for the GUI and a75        searchengine instance to prepare the search.76 77        Attributes:78            flist: filelist.Filelist instance for OutputWindow parent.79            globvar: String value of Entry widget for path to search.80            globent: Entry widget for globvar.  Created in81                create_entries().82            recvar: Boolean value of Checkbutton widget for83                traversing through subdirectories.84        """85        super().__init__(root, engine)86        self.flist = flist87        self.globvar = StringVar(root)88        self.recvar = BooleanVar(root)89 90    def open(self, text, searchphrase, io=None):91        """Make dialog visible on top of others and ready to use.92 93        Extend the SearchDialogBase open() to set the initial value94        for globvar.95 96        Args:97            text: Multicall object containing the text information.98            searchphrase: String phrase to search.99            io: iomenu.IOBinding instance containing file path.100        """101        SearchDialogBase.open(self, text, searchphrase)102        if io:103            path = io.filename or ""104        else:105            path = ""106        dir, base = os.path.split(path)107        head, tail = os.path.splitext(base)108        if not tail:109            tail = ".py"110        self.globvar.set(os.path.join(dir, "*" + tail))111 112    def create_entries(self):113        "Create base entry widgets and add widget for search path."114        SearchDialogBase.create_entries(self)115        self.globent = self.make_entry("In files:", self.globvar)[0]116 117    def create_other_buttons(self):118        "Add check button to recurse down subdirectories."119        btn = Checkbutton(120                self.make_frame()[0], variable=self.recvar,121                text="Recurse down subdirectories")122        btn.pack(side="top", fill="both")123 124    def create_command_buttons(self):125        "Create base command buttons and add button for Search Files."126        SearchDialogBase.create_command_buttons(self)127        self.make_button("Search Files", self.default_command, isdef=True)128 129    def default_command(self, event=None):130        """Grep for search pattern in file path. The default command is bound131        to <Return>.132 133        If entry values are populated, set OutputWindow as stdout134        and perform search.  The search dialog is closed automatically135        when the search begins.136        """137        prog = self.engine.getprog()138        if not prog:139            return140        path = self.globvar.get()141        if not path:142            self.top.bell()143            return144        from idlelib.outwin import OutputWindow  # leave here!145        save = sys.stdout146        try:147            sys.stdout = OutputWindow(self.flist)148            self.grep_it(prog, path)149        finally:150            sys.stdout = save151 152    def grep_it(self, prog, path):153        """Search for prog within the lines of the files in path.154 155        For the each file in the path directory, open the file and156        search each line for the matching pattern.  If the pattern is157        found,  write the file and line information to stdout (which158        is an OutputWindow).159 160        Args:161            prog: The compiled, cooked search pattern.162            path: String containing the search path.163        """164        folder, filepat = os.path.split(path)165        if not folder:166            folder = os.curdir167        filelist = sorted(findfiles(folder, filepat, self.recvar.get()))168        self.close()169        pat = self.engine.getpat()170        print(f"Searching {pat!r} in {path} ...")171        hits = 0172        try:173            for fn in filelist:174                try:175                    with open(fn, errors='replace') as f:176                        for lineno, line in enumerate(f, 1):177                            if line[-1:] == '\n':178                                line = line[:-1]179                            if prog.search(line):180                                sys.stdout.write(f"{fn}: {lineno}: {line}\n")181                                hits += 1182                except OSError as msg:183                    print(msg)184            print(f"Hits found: {hits}\n(Hint: right-click to open locations.)"185                  if hits else "No hits.")186        except AttributeError:187            # Tk window has been closed, OutputWindow.text = None,188            # so in OW.write, OW.text.insert fails.189            pass190 191 192def _grep_dialog(parent):  # htest #193    from tkinter import Toplevel, Text, SEL194    from tkinter.ttk import Frame, Button195    from idlelib.pyshell import PyShellFileList196 197    top = Toplevel(parent)198    top.title("Test GrepDialog")199    x, y = map(int, parent.geometry().split('+')[1:])200    top.geometry(f"+{x}+{y + 175}")201 202    flist = PyShellFileList(top)203    frame = Frame(top)204    frame.pack()205    text = Text(frame, height=5)206    text.pack()207    text.insert('1.0', 'import grep')208 209    def show_grep_dialog():210        text.tag_add(SEL, "1.0", '1.end')211        grep(text, flist=flist)212        text.tag_remove(SEL, "1.0", '1.end')213 214    button = Button(frame, text="Show GrepDialog", command=show_grep_dialog)215    button.pack()216 217 218if __name__ == "__main__":219    from unittest import main220    main('idlelib.idle_test.test_grep', verbosity=2, exit=False)221 222    from idlelib.idle_test.htest import run223    run(_grep_dialog)224 
codekingpro/portable-devtools · Team Ai