Movatterモバイル変換


[0]ホーム

URL:


File: pyedit-grep-code.py

class TextEditor:    def start(self):                                # run by GuiMaker.__init__        self.menuBar = [                            # configure menu/toolbar            ...etc...            ('Search', 0,                 [('Goto...',    0, self.onGoto),                  ('Find...',    0, self.onFind),                  ('Refind',     0, self.onRefind),                  ('Change...',  0, self.onChange),                  ('Grep...',    3, self.onGrep)]            ...etc...    ...etc...    def onGrep(self):        """        new in version 2.1: threaded external file search;        search matched filenames in directory tree for string;        listbox clicks open matched file at line of occurrence;        search is threaded so the GUI remains active and is not        blocked, and to allow multiple greps to overlap in time;        could use threadtools, but avoid loop if no active grep;        grep Unicode policy: text files content in the searched tree         might be in any Unicode encoding: we don't ask about each (as        we do for opens), but allow the encoding used for the entire        tree to be input, preset it to the platform filesystem or         text default, and skip files that fail to decode; in worst         cases, users may need to run grep N times if N encodings might        exist;  else opens may raise exceptions, and opening in binary        mode might fail to match encoded text against search string;        TBD: better to issue an error if any file fails to decode?         but utf-16 2-bytes/char format created in Notepad may decode         without error per utf-8, and search strings won't be found;        TBD: could allow input of multiple encoding names, split on         comma, try each one for every file, without open loadEncode?        """        from PP4E.Gui.ShellGui.formrows import makeFormRow        # nonmodal dialog: get dirnname, filenamepatt, grepkey        popup = Toplevel()        popup.title('PyEdit - grep')        var1 = makeFormRow(popup, label='Directory root',   width=18, browse=False)        var2 = makeFormRow(popup, label='Filename pattern', width=18, browse=False)        var3 = makeFormRow(popup, label='Search string',    width=18, browse=False)        var4 = makeFormRow(popup, label='Content encoding', width=18, browse=False)        var1.set('.')      # current dir        var2.set('*.py')   # initial values        var4.set(sys.getdefaultencoding())    # for file content, not filenames        cb = lambda: self.onDoGrep(var1.get(), var2.get(), var3.get(), var4.get())        Button(popup, text='Go',command=cb).pack()    def onDoGrep(self, dirname, filenamepatt, grepkey, encoding):        """        on Go in grep dialog: populate scrolled list with matches        tbd: should producer thread be daemon so it dies with app?        """        import threading, queue        # make non-modal un-closeable dialog        mypopup = Tk()        mypopup.title('PyEdit - grepping')        status = Label(mypopup, text='Grep thread searching for: %r...' % grepkey)        status.pack(padx=20, pady=20)        mypopup.protocol('WM_DELETE_WINDOW', lambda: None)  # ignore X close        # start producer thread, consumer loop        myqueue = queue.Queue()        threadargs = (filenamepatt, dirname, grepkey, encoding, myqueue)        threading.Thread(target=self.grepThreadProducer, args=threadargs).start()        self.grepThreadConsumer(grepkey, encoding, myqueue, mypopup)    def grepThreadProducer(self, filenamepatt, dirname, grepkey, encoding, myqueue):        """        in a non-GUI parallel thread: queue find.find results list;        could also queue matches as found, but need to keep window;        file content and file names may both fail to decode here;        TBD: could pass encoded bytes to find() to avoid filename        decoding excs in os.walk/listdir, but which encoding to use:        sys.getfilesystemencoding() if not None?  see also Chapter6         footnote issue: 3.1 fnmatch always converts bytes per Latin-1;        """        from PP4E.Tools.find import find        matches = []        try:            for filepath in find(pattern=filenamepatt, startdir=dirname):                try:                    textfile = open(filepath, encoding=encoding)                    for (linenum, linestr) in enumerate(textfile):                        if grepkey in linestr:                            msg = '%s@%d  [%s]' % (filepath, linenum + 1, linestr)                            matches.append(msg)                except UnicodeError as X:                    print('Unicode error in:', filepath, X)       # eg: decode, bom                except IOError as X:                    print('IO error in:', filepath, X)            # eg: permission        finally:            myqueue.put(matches)      # stop consumer loop on find excs: filenames?    def grepThreadConsumer(self, grepkey, encoding, myqueue, mypopup):        """        in the main GUI thread: watch queue for results or [];        there may be multiple active grep threads/loops/queues;        there may be other types of threads/checkers in process,        especially when PyEdit is attached component (PyMailGUI);        """        import queue        try:            matches = myqueue.get(block=False)        except queue.Empty:            myargs  = (grepkey, encoding, myqueue, mypopup)            self.after(250, self.grepThreadConsumer, *myargs)        else:            mypopup.destroy()     # close status            self.update()         # erase it now            if not matches:                showinfo('PyEdit', 'Grep found no matches for: %r' % grepkey)            else:                self.grepMatchesList(matches, grepkey, encoding)    def grepMatchesList(self, matches, grepkey, encoding):        """        populate list after successful matches;        we already know Unicode encoding from the search: use         it here when filename clicked, so open doesn't ask user;        """        from PP4E.Gui.Tour.scrolledlist import ScrolledList        print('Matches for %s: %s' % (grepkey, len(matches)))        # catch list double-click        class ScrolledFilenames(ScrolledList):            def runCommand(self, selection):                  file, line = selection.split('  [', 1)[0].split('@')                editor = TextEditorMainPopup(                    loadFirst=file, winTitle=' grep match', loadEncode=encoding)                editor.onGoto(int(line))                editor.text.focus_force()   # no, really        # new non-modal window        popup = Tk()        popup.title('PyEdit - grep matches: %r (%s)' % (grepkey, encoding))        ScrolledFilenames(parent=popup, options=matches)    ...etc...



[Home page]BooksCodeBlogPythonAuthorTrainFind©M.Lutz

[8]ページ先頭

©2009-2025 Movatter.jp