Merge with 3.3

This commit is contained in:
Terry Jan Reedy 2013-08-19 01:05:41 -04:00
commit 86d26238d3
1 changed files with 37 additions and 25 deletions

View File

@ -1,19 +1,28 @@
'''Define SearchEngine for search dialogs.'''
import re
from tkinter import *
import tkinter.messagebox as tkMessageBox
def get(root):
'''Return the singleton SearchEngine instance for the process.
The single SearchEngine saves settings between dialog instances.
If there is not a SearchEngine already, make one.
'''
if not hasattr(root, "_searchengine"):
root._searchengine = SearchEngine(root)
# XXX This will never garbage-collect -- who cares
# This creates a cycle that persists until root is deleted.
return root._searchengine
class SearchEngine:
"""Handles searching a text widget for Find, Replace, and Grep."""
def __init__(self, root):
'''Initialize Variables that save search state.
The dialogs bind these to the UI elements present in the dialogs.
'''
self.root = root
# State shared by search, replace, and grep;
# the search dialogs bind these to UI elements.
self.patvar = StringVar(root) # search pattern
self.revar = BooleanVar(root) # regular expression?
self.casevar = BooleanVar(root) # match case?
@ -56,6 +65,7 @@ class SearchEngine:
return pat
def getprog(self):
"Return compiled cooked search pattern."
pat = self.getpat()
if not pat:
self.report_error(pat, "Empty regular expression")
@ -77,7 +87,7 @@ class SearchEngine:
return prog
def report_error(self, pat, msg, col=-1):
# Derived class could overrid this with something fancier
# Derived class could override this with something fancier
msg = "Error: " + str(msg)
if pat:
msg = msg + "\np\Pattern: " + str(pat)
@ -92,25 +102,23 @@ class SearchEngine:
self.setpat(pat)
def search_text(self, text, prog=None, ok=0):
"""Search a text widget for the pattern.
'''Return (lineno, matchobj) for prog in text widget, or None.
If prog is given, it should be the precompiled pattern.
Return a tuple (lineno, matchobj); None if not found.
If prog is given, it should be a precompiled pattern.
Wrap (yes/no) and direction (forward/back) settings are used.
This obeys the wrap and direction (back) settings.
The search starts at the selection (if there is one) or
at the insert mark (otherwise). If the search is forward,
it starts at the right of the selection; for a backward
search, it starts at the left end. An empty match exactly
at either end of the selection (or at the insert mark if
there is no selection) is ignored unless the ok flag is true
-- this is done to guarantee progress.
The search starts at the selection (if there is one) or at the
insert mark (otherwise). If the search is forward, it starts
at the right of the selection; for a backward search, it
starts at the left end. An empty match exactly at either end
of the selection (or at the insert mark if there is no
selection) is ignored unless the ok flag is true -- this is
done to guarantee progress.
If the search is allowed to wrap around, it will return the
original selection if (and only if) it is the only match.
'''
"""
if not prog:
prog = self.getprog()
if not prog:
@ -179,10 +187,11 @@ class SearchEngine:
col = len(chars) - 1
return None
# Helper to search backwards in a string.
# (Optimized for the case where the pattern isn't found.)
def search_reverse(prog, chars, col):
'''Search backwards in a string (line of text).
This is done by searching forwards until there is no match.
'''
m = prog.search(chars)
if not m:
return None
@ -198,10 +207,9 @@ def search_reverse(prog, chars, col):
i, j = m.span()
return found
# Helper to get selection end points, defaulting to insert mark.
# Return a tuple of indices ("line.col" strings).
def get_selection(text):
'''Return tuple of 'line.col' indexes from selection or insert mark.
'''
try:
first = text.index("sel.first")
last = text.index("sel.last")
@ -213,8 +221,12 @@ def get_selection(text):
last = first
return first, last
# Helper to parse a text index into a (line, col) tuple.
def get_line_col(index):
'''Return (line, col) tuple of ints from 'line.col' string.'''
line, col = map(int, index.split(".")) # Fails on invalid index
return line, col
##if __name__ == "__main__":
## from test import support; support.use_resources = ['gui']
## import unittest
## unittest.main('idlelib.idle_test.test_searchengine', verbosity=2, exit=False)