(root)/
Python-3.12.0/
Lib/
idlelib/
search.py
       1  """Search dialog for Find, Find Again, and Find Selection
       2     functionality.
       3  
       4     Inherits from SearchDialogBase for GUI and uses searchengine
       5     to prepare search pattern.
       6  """
       7  from tkinter import TclError
       8  
       9  from idlelib import searchengine
      10  from idlelib.searchbase import SearchDialogBase
      11  
      12  def _setup(text):
      13      """Return the new or existing singleton SearchDialog instance.
      14  
      15      The singleton dialog saves user entries and preferences
      16      across instances.
      17  
      18      Args:
      19          text: Text widget containing the text to be searched.
      20      """
      21      root = text._root()
      22      engine = searchengine.get(root)
      23      if not hasattr(engine, "_searchdialog"):
      24          engine._searchdialog = SearchDialog(root, engine)
      25      return engine._searchdialog
      26  
      27  def find(text):
      28      """Open the search dialog.
      29  
      30      Module-level function to access the singleton SearchDialog
      31      instance and open the dialog.  If text is selected, it is
      32      used as the search phrase; otherwise, the previous entry
      33      is used.  No search is done with this command.
      34      """
      35      pat = text.get("sel.first", "sel.last")
      36      return _setup(text).open(text, pat)  # Open is inherited from SDBase.
      37  
      38  def find_again(text):
      39      """Repeat the search for the last pattern and preferences.
      40  
      41      Module-level function to access the singleton SearchDialog
      42      instance to search again using the user entries and preferences
      43      from the last dialog.  If there was no prior search, open the
      44      search dialog; otherwise, perform the search without showing the
      45      dialog.
      46      """
      47      return _setup(text).find_again(text)
      48  
      49  def find_selection(text):
      50      """Search for the selected pattern in the text.
      51  
      52      Module-level function to access the singleton SearchDialog
      53      instance to search using the selected text.  With a text
      54      selection, perform the search without displaying the dialog.
      55      Without a selection, use the prior entry as the search phrase
      56      and don't display the dialog.  If there has been no prior
      57      search, open the search dialog.
      58      """
      59      return _setup(text).find_selection(text)
      60  
      61  
      62  class ESC[4;38;5;81mSearchDialog(ESC[4;38;5;149mSearchDialogBase):
      63      "Dialog for finding a pattern in text."
      64  
      65      def create_widgets(self):
      66          "Create the base search dialog and add a button for Find Next."
      67          SearchDialogBase.create_widgets(self)
      68          # TODO - why is this here and not in a create_command_buttons?
      69          self.make_button("Find Next", self.default_command, isdef=True)
      70  
      71      def default_command(self, event=None):
      72          "Handle the Find Next button as the default command."
      73          if not self.engine.getprog():
      74              return
      75          self.find_again(self.text)
      76  
      77      def find_again(self, text):
      78          """Repeat the last search.
      79  
      80          If no search was previously run, open a new search dialog.  In
      81          this case, no search is done.
      82  
      83          If a search was previously run, the search dialog won't be
      84          shown and the options from the previous search (including the
      85          search pattern) will be used to find the next occurrence
      86          of the pattern.  Next is relative based on direction.
      87  
      88          Position the window to display the located occurrence in the
      89          text.
      90  
      91          Return True if the search was successful and False otherwise.
      92          """
      93          if not self.engine.getpat():
      94              self.open(text)
      95              return False
      96          if not self.engine.getprog():
      97              return False
      98          res = self.engine.search_text(text)
      99          if res:
     100              line, m = res
     101              i, j = m.span()
     102              first = "%d.%d" % (line, i)
     103              last = "%d.%d" % (line, j)
     104              try:
     105                  selfirst = text.index("sel.first")
     106                  sellast = text.index("sel.last")
     107                  if selfirst == first and sellast == last:
     108                      self.bell()
     109                      return False
     110              except TclError:
     111                  pass
     112              text.tag_remove("sel", "1.0", "end")
     113              text.tag_add("sel", first, last)
     114              text.mark_set("insert", self.engine.isback() and first or last)
     115              text.see("insert")
     116              return True
     117          else:
     118              self.bell()
     119              return False
     120  
     121      def find_selection(self, text):
     122          """Search for selected text with previous dialog preferences.
     123  
     124          Instead of using the same pattern for searching (as Find
     125          Again does), this first resets the pattern to the currently
     126          selected text.  If the selected text isn't changed, then use
     127          the prior search phrase.
     128          """
     129          pat = text.get("sel.first", "sel.last")
     130          if pat:
     131              self.engine.setcookedpat(pat)
     132          return self.find_again(text)
     133  
     134  
     135  def _search_dialog(parent):  # htest #
     136      "Display search test box."
     137      from tkinter import Toplevel, Text
     138      from tkinter.ttk import Frame, Button
     139  
     140      top = Toplevel(parent)
     141      top.title("Test SearchDialog")
     142      x, y = map(int, parent.geometry().split('+')[1:])
     143      top.geometry("+%d+%d" % (x, y + 175))
     144  
     145      frame = Frame(top)
     146      frame.pack()
     147      text = Text(frame, inactiveselectbackground='gray')
     148      text.pack()
     149      text.insert("insert","This is a sample string.\n"*5)
     150  
     151      def show_find():
     152          text.tag_add('sel', '1.0', 'end')
     153          _setup(text).open(text)
     154          text.tag_remove('sel', '1.0', 'end')
     155  
     156      button = Button(frame, text="Search (selection ignored)", command=show_find)
     157      button.pack()
     158  
     159  if __name__ == '__main__':
     160      from unittest import main
     161      main('idlelib.idle_test.test_search', verbosity=2, exit=False)
     162  
     163      from idlelib.idle_test.htest import run
     164      run(_search_dialog)