search dialog for find find again and find selection functionality inherits from searchdialogbase for gui and uses searchengine to prepare search pattern return the new or existing singleton searchdialog instance the singleton dialog saves user entries and preferences across instances args text text widget containing the text to be searched open the search dialog modulelevel function to access the singleton searchdialog instance and open the dialog if text is selected it is used as the search phrase otherwise the previous entry is used no search is done with this command repeat the search for the last pattern and preferences modulelevel function to access the singleton searchdialog instance to search again using the user entries and preferences from the last dialog if there was no prior search open the search dialog otherwise perform the search without showing the dialog search for the selected pattern in the text modulelevel function to access the singleton searchdialog instance to search using the selected text with a text selection perform the search without displaying the dialog without a selection use the prior entry as the search phrase and don t display the dialog if there has been no prior search open the search dialog todo why is this here and not in a createcommandbuttons repeat the last search if no search was previously run open a new search dialog in this case no search is done if a search was previously run the search dialog won t be shown and the options from the previous search including the search pattern will be used to find the next occurrence of the pattern next is relative based on direction position the window to display the located occurrence in the text return true if the search was successful and false otherwise search for selected text with previous dialog preferences instead of using the same pattern for searching as find again does this first resets the pattern to the currently selected text if the selected text isn t changed then use the prior search phrase return the new or existing singleton searchdialog instance the singleton dialog saves user entries and preferences across instances args text text widget containing the text to be searched open the search dialog module level function to access the singleton searchdialog instance and open the dialog if text is selected it is used as the search phrase otherwise the previous entry is used no search is done with this command open is inherited from sdbase repeat the search for the last pattern and preferences module level function to access the singleton searchdialog instance to search again using the user entries and preferences from the last dialog if there was no prior search open the search dialog otherwise perform the search without showing the dialog search for the selected pattern in the text module level function to access the singleton searchdialog instance to search using the selected text with a text selection perform the search without displaying the dialog without a selection use the prior entry as the search phrase and don t display the dialog if there has been no prior search open the search dialog todo why is this here and not in a create_command_buttons repeat the last search if no search was previously run open a new search dialog in this case no search is done if a search was previously run the search dialog won t be shown and the options from the previous search including the search pattern will be used to find the next occurrence of the pattern next is relative based on direction position the window to display the located occurrence in the text return true if the search was successful and false otherwise search for selected text with previous dialog preferences instead of using the same pattern for searching as find again does this first resets the pattern to the currently selected text if the selected text isn t changed then use the prior search phrase htest
from tkinter import TclError

from idlelib import searchengine
from idlelib.searchbase import SearchDialogBase

def _setup(text):
    
    root = text._root()
    engine = searchengine.get(root)
    if not hasattr(engine, "_searchdialog"):
        engine._searchdialog = SearchDialog(root, engine)
    return engine._searchdialog

def find(text):
    
    pat = text.get("sel.first", "sel.last")
    return _setup(text).open(text, pat)  

def find_again(text):
    
    return _setup(text).find_again(text)

def find_selection(text):
    
    return _setup(text).find_selection(text)


class SearchDialog(SearchDialogBase):
    "Dialog for finding a pattern in text."

    def create_widgets(self):
        "Create the base search dialog and add a button for Find Next."
        SearchDialogBase.create_widgets(self)
        
        self.make_button("Find Next", self.default_command, isdef=True)

    def default_command(self, event=None):
        "Handle the Find Next button as the default command."
        if not self.engine.getprog():
            return
        self.find_again(self.text)

    def find_again(self, text):
        
        if not self.engine.getpat():
            self.open(text)
            return False
        if not self.engine.getprog():
            return False
        res = self.engine.search_text(text)
        if res:
            line, m = res
            i, j = m.span()
            first = "%d.%d" % (line, i)
            last = "%d.%d" % (line, j)
            try:
                selfirst = text.index("sel.first")
                sellast = text.index("sel.last")
                if selfirst == first and sellast == last:
                    self.bell()
                    return False
            except TclError:
                pass
            text.tag_remove("sel", "1.0", "end")
            text.tag_add("sel", first, last)
            text.mark_set("insert", self.engine.isback() and first or last)
            text.see("insert")
            return True
        else:
            self.bell()
            return False

    def find_selection(self, text):
        
        pat = text.get("sel.first", "sel.last")
        if pat:
            self.engine.setcookedpat(pat)
        return self.find_again(text)


def _search_dialog(parent):  
    "Display search test box."
    from tkinter import Toplevel, Text
    from tkinter.ttk import Frame, Button

    top = Toplevel(parent)
    top.title("Test SearchDialog")
    x, y = map(int, parent.geometry().split('+')[1:])
    top.geometry("+%d+%d" % (x, y + 175))

    frame = Frame(top)
    frame.pack()
    text = Text(frame, inactiveselectbackground='gray')
    text.pack()
    text.insert("insert","This is a sample string.\n"*5)

    def show_find():
        text.tag_add('sel', '1.0', 'end')
        _setup(text).open(text)
        text.tag_remove('sel', '1.0', 'end')

    button = Button(frame, text="Search (selection ignored)", command=show_find)
    button.pack()

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

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