1+ '''Define SearchEngine for search dialogs.'''
12import re
23from tkinter import *
34import tkinter .messagebox as tkMessageBox
45
56def get (root ):
7+ '''Return the singleton SearchEngine instance for the process.
8+
9+ The single SearchEngine saves settings between dialog instances.
10+ If there is not a SearchEngine already, make one.
11+ '''
612 if not hasattr (root , "_searchengine" ):
713 root ._searchengine = SearchEngine (root )
8- # XXX This will never garbage-collect -- who cares
14+ # This creates a cycle that persists until root is deleted.
915 return root ._searchengine
1016
1117class SearchEngine :
18+ """Handles searching a text widget for Find, Replace, and Grep."""
1219
1320 def __init__ (self , root ):
21+ '''Initialize Variables that save search state.
22+
23+ The dialogs bind these to the UI elements present in the dialogs.
24+ '''
1425 self .root = root
15- # State shared by search, replace, and grep;
16- # the search dialogs bind these to UI elements.
1726 self .patvar = StringVar (root ) # search pattern
1827 self .revar = BooleanVar (root ) # regular expression?
1928 self .casevar = BooleanVar (root ) # match case?
@@ -56,6 +65,7 @@ def getcookedpat(self):
5665 return pat
5766
5867 def getprog (self ):
68+ "Return compiled cooked search pattern."
5969 pat = self .getpat ()
6070 if not pat :
6171 self .report_error (pat , "Empty regular expression" )
@@ -77,7 +87,7 @@ def getprog(self):
7787 return prog
7888
7989 def report_error (self , pat , msg , col = - 1 ):
80- # Derived class could overrid this with something fancier
90+ # Derived class could override this with something fancier
8191 msg = "Error: " + str (msg )
8292 if pat :
8393 msg = msg + "\n p\Pattern: " + str (pat )
@@ -92,25 +102,23 @@ def setcookedpat(self, pat):
92102 self .setpat (pat )
93103
94104 def search_text (self , text , prog = None , ok = 0 ):
95- """Search a text widget for the pattern .
105+ '''Return (lineno, matchobj) for prog in text widget, or None .
96106
97- If prog is given, it should be the precompiled pattern.
98- Return a tuple (lineno, matchobj); None if not found .
107+ If prog is given, it should be a precompiled pattern.
108+ Wrap (yes/no) and direction (forward/back) settings are used .
99109
100- This obeys the wrap and direction (back) settings.
101-
102- The search starts at the selection (if there is one) or
103- at the insert mark (otherwise). If the search is forward,
104- it starts at the right of the selection; for a backward
105- search, it starts at the left end. An empty match exactly
106- at either end of the selection (or at the insert mark if
107- there is no selection) is ignored unless the ok flag is true
108- -- this is done to guarantee progress.
110+ The search starts at the selection (if there is one) or at the
111+ insert mark (otherwise). If the search is forward, it starts
112+ at the right of the selection; for a backward search, it
113+ starts at the left end. An empty match exactly at either end
114+ of the selection (or at the insert mark if there is no
115+ selection) is ignored unless the ok flag is true -- this is
116+ done to guarantee progress.
109117
110118 If the search is allowed to wrap around, it will return the
111119 original selection if (and only if) it is the only match.
120+ '''
112121
113- """
114122 if not prog :
115123 prog = self .getprog ()
116124 if not prog :
@@ -179,10 +187,11 @@ def search_backward(self, text, prog, line, col, wrap, ok=0):
179187 col = len (chars ) - 1
180188 return None
181189
182- # Helper to search backwards in a string.
183- # (Optimized for the case where the pattern isn't found.)
184-
185190def search_reverse (prog , chars , col ):
191+ '''Search backwards in a string (line of text).
192+
193+ This is done by searching forwards until there is no match.
194+ '''
186195 m = prog .search (chars )
187196 if not m :
188197 return None
@@ -198,10 +207,9 @@ def search_reverse(prog, chars, col):
198207 i , j = m .span ()
199208 return found
200209
201- # Helper to get selection end points, defaulting to insert mark.
202- # Return a tuple of indices ("line.col" strings).
203-
204210def get_selection (text ):
211+ '''Return tuple of 'line.col' indexes from selection or insert mark.
212+ '''
205213 try :
206214 first = text .index ("sel.first" )
207215 last = text .index ("sel.last" )
@@ -213,8 +221,12 @@ def get_selection(text):
213221 last = first
214222 return first , last
215223
216- # Helper to parse a text index into a (line, col) tuple.
217-
218224def get_line_col (index ):
225+ '''Return (line, col) tuple of ints from 'line.col' string.'''
219226 line , col = map (int , index .split ("." )) # Fails on invalid index
220227 return line , col
228+
229+ ##if __name__ == "__main__":
230+ ## from test import support; support.use_resources = ['gui']
231+ ## import unittest
232+ ## unittest.main('idlelib.idle_test.test_searchengine', verbosity=2, exit=False)
0 commit comments