Edit File by line
/home/barbar84/public_h.../wp-conte.../plugins/sujqvwi/ShExBy/shex_roo.../lib64/python2..../idlelib
File: SearchEngine.py
'''Define SearchEngine for search dialogs.'''
[0] Fix | Delete
import re
[1] Fix | Delete
from Tkinter import StringVar, BooleanVar, TclError
[2] Fix | Delete
import tkMessageBox
[3] Fix | Delete
[4] Fix | Delete
def get(root):
[5] Fix | Delete
'''Return the singleton SearchEngine instance for the process.
[6] Fix | Delete
[7] Fix | Delete
The single SearchEngine saves settings between dialog instances.
[8] Fix | Delete
If there is not a SearchEngine already, make one.
[9] Fix | Delete
'''
[10] Fix | Delete
if not hasattr(root, "_searchengine"):
[11] Fix | Delete
root._searchengine = SearchEngine(root)
[12] Fix | Delete
# This creates a cycle that persists until root is deleted.
[13] Fix | Delete
return root._searchengine
[14] Fix | Delete
[15] Fix | Delete
class SearchEngine:
[16] Fix | Delete
"""Handles searching a text widget for Find, Replace, and Grep."""
[17] Fix | Delete
[18] Fix | Delete
def __init__(self, root):
[19] Fix | Delete
'''Initialize Variables that save search state.
[20] Fix | Delete
[21] Fix | Delete
The dialogs bind these to the UI elements present in the dialogs.
[22] Fix | Delete
'''
[23] Fix | Delete
self.root = root # need for report_error()
[24] Fix | Delete
self.patvar = StringVar(root, '') # search pattern
[25] Fix | Delete
self.revar = BooleanVar(root, False) # regular expression?
[26] Fix | Delete
self.casevar = BooleanVar(root, False) # match case?
[27] Fix | Delete
self.wordvar = BooleanVar(root, False) # match whole word?
[28] Fix | Delete
self.wrapvar = BooleanVar(root, True) # wrap around buffer?
[29] Fix | Delete
self.backvar = BooleanVar(root, False) # search backwards?
[30] Fix | Delete
[31] Fix | Delete
# Access methods
[32] Fix | Delete
[33] Fix | Delete
def getpat(self):
[34] Fix | Delete
return self.patvar.get()
[35] Fix | Delete
[36] Fix | Delete
def setpat(self, pat):
[37] Fix | Delete
self.patvar.set(pat)
[38] Fix | Delete
[39] Fix | Delete
def isre(self):
[40] Fix | Delete
return self.revar.get()
[41] Fix | Delete
[42] Fix | Delete
def iscase(self):
[43] Fix | Delete
return self.casevar.get()
[44] Fix | Delete
[45] Fix | Delete
def isword(self):
[46] Fix | Delete
return self.wordvar.get()
[47] Fix | Delete
[48] Fix | Delete
def iswrap(self):
[49] Fix | Delete
return self.wrapvar.get()
[50] Fix | Delete
[51] Fix | Delete
def isback(self):
[52] Fix | Delete
return self.backvar.get()
[53] Fix | Delete
[54] Fix | Delete
# Higher level access methods
[55] Fix | Delete
[56] Fix | Delete
def setcookedpat(self, pat):
[57] Fix | Delete
"Set pattern after escaping if re."
[58] Fix | Delete
# called only in SearchDialog.py: 66
[59] Fix | Delete
if self.isre():
[60] Fix | Delete
pat = re.escape(pat)
[61] Fix | Delete
self.setpat(pat)
[62] Fix | Delete
[63] Fix | Delete
def getcookedpat(self):
[64] Fix | Delete
pat = self.getpat()
[65] Fix | Delete
if not self.isre(): # if True, see setcookedpat
[66] Fix | Delete
pat = re.escape(pat)
[67] Fix | Delete
if self.isword():
[68] Fix | Delete
pat = r"\b%s\b" % pat
[69] Fix | Delete
return pat
[70] Fix | Delete
[71] Fix | Delete
def getprog(self):
[72] Fix | Delete
"Return compiled cooked search pattern."
[73] Fix | Delete
pat = self.getpat()
[74] Fix | Delete
if not pat:
[75] Fix | Delete
self.report_error(pat, "Empty regular expression")
[76] Fix | Delete
return None
[77] Fix | Delete
pat = self.getcookedpat()
[78] Fix | Delete
flags = 0
[79] Fix | Delete
if not self.iscase():
[80] Fix | Delete
flags = flags | re.IGNORECASE
[81] Fix | Delete
try:
[82] Fix | Delete
prog = re.compile(pat, flags)
[83] Fix | Delete
except re.error as what:
[84] Fix | Delete
args = what.args
[85] Fix | Delete
msg = args[0]
[86] Fix | Delete
col = args[1] if len(args) >= 2 else -1
[87] Fix | Delete
self.report_error(pat, msg, col)
[88] Fix | Delete
return None
[89] Fix | Delete
return prog
[90] Fix | Delete
[91] Fix | Delete
def report_error(self, pat, msg, col=-1):
[92] Fix | Delete
# Derived class could override this with something fancier
[93] Fix | Delete
msg = "Error: " + str(msg)
[94] Fix | Delete
if pat:
[95] Fix | Delete
msg = msg + "\nPattern: " + str(pat)
[96] Fix | Delete
if col >= 0:
[97] Fix | Delete
msg = msg + "\nOffset: " + str(col)
[98] Fix | Delete
tkMessageBox.showerror("Regular expression error",
[99] Fix | Delete
msg, master=self.root)
[100] Fix | Delete
[101] Fix | Delete
def search_text(self, text, prog=None, ok=0):
[102] Fix | Delete
'''Return (lineno, matchobj) or None for forward/backward search.
[103] Fix | Delete
[104] Fix | Delete
This function calls the right function with the right arguments.
[105] Fix | Delete
It directly return the result of that call.
[106] Fix | Delete
[107] Fix | Delete
Text is a text widget. Prog is a precompiled pattern.
[108] Fix | Delete
The ok parameter is a bit complicated as it has two effects.
[109] Fix | Delete
[110] Fix | Delete
If there is a selection, the search begin at either end,
[111] Fix | Delete
depending on the direction setting and ok, with ok meaning that
[112] Fix | Delete
the search starts with the selection. Otherwise, search begins
[113] Fix | Delete
at the insert mark.
[114] Fix | Delete
[115] Fix | Delete
To aid progress, the search functions do not return an empty
[116] Fix | Delete
match at the starting position unless ok is True.
[117] Fix | Delete
'''
[118] Fix | Delete
[119] Fix | Delete
if not prog:
[120] Fix | Delete
prog = self.getprog()
[121] Fix | Delete
if not prog:
[122] Fix | Delete
return None # Compilation failed -- stop
[123] Fix | Delete
wrap = self.wrapvar.get()
[124] Fix | Delete
first, last = get_selection(text)
[125] Fix | Delete
if self.isback():
[126] Fix | Delete
if ok:
[127] Fix | Delete
start = last
[128] Fix | Delete
else:
[129] Fix | Delete
start = first
[130] Fix | Delete
line, col = get_line_col(start)
[131] Fix | Delete
res = self.search_backward(text, prog, line, col, wrap, ok)
[132] Fix | Delete
else:
[133] Fix | Delete
if ok:
[134] Fix | Delete
start = first
[135] Fix | Delete
else:
[136] Fix | Delete
start = last
[137] Fix | Delete
line, col = get_line_col(start)
[138] Fix | Delete
res = self.search_forward(text, prog, line, col, wrap, ok)
[139] Fix | Delete
return res
[140] Fix | Delete
[141] Fix | Delete
def search_forward(self, text, prog, line, col, wrap, ok=0):
[142] Fix | Delete
wrapped = 0
[143] Fix | Delete
startline = line
[144] Fix | Delete
chars = text.get("%d.0" % line, "%d.0" % (line+1))
[145] Fix | Delete
while chars:
[146] Fix | Delete
m = prog.search(chars[:-1], col)
[147] Fix | Delete
if m:
[148] Fix | Delete
if ok or m.end() > col:
[149] Fix | Delete
return line, m
[150] Fix | Delete
line = line + 1
[151] Fix | Delete
if wrapped and line > startline:
[152] Fix | Delete
break
[153] Fix | Delete
col = 0
[154] Fix | Delete
ok = 1
[155] Fix | Delete
chars = text.get("%d.0" % line, "%d.0" % (line+1))
[156] Fix | Delete
if not chars and wrap:
[157] Fix | Delete
wrapped = 1
[158] Fix | Delete
wrap = 0
[159] Fix | Delete
line = 1
[160] Fix | Delete
chars = text.get("1.0", "2.0")
[161] Fix | Delete
return None
[162] Fix | Delete
[163] Fix | Delete
def search_backward(self, text, prog, line, col, wrap, ok=0):
[164] Fix | Delete
wrapped = 0
[165] Fix | Delete
startline = line
[166] Fix | Delete
chars = text.get("%d.0" % line, "%d.0" % (line+1))
[167] Fix | Delete
while 1:
[168] Fix | Delete
m = search_reverse(prog, chars[:-1], col)
[169] Fix | Delete
if m:
[170] Fix | Delete
if ok or m.start() < col:
[171] Fix | Delete
return line, m
[172] Fix | Delete
line = line - 1
[173] Fix | Delete
if wrapped and line < startline:
[174] Fix | Delete
break
[175] Fix | Delete
ok = 1
[176] Fix | Delete
if line <= 0:
[177] Fix | Delete
if not wrap:
[178] Fix | Delete
break
[179] Fix | Delete
wrapped = 1
[180] Fix | Delete
wrap = 0
[181] Fix | Delete
pos = text.index("end-1c")
[182] Fix | Delete
line, col = map(int, pos.split("."))
[183] Fix | Delete
chars = text.get("%d.0" % line, "%d.0" % (line+1))
[184] Fix | Delete
col = len(chars) - 1
[185] Fix | Delete
return None
[186] Fix | Delete
[187] Fix | Delete
def search_reverse(prog, chars, col):
[188] Fix | Delete
'''Search backwards and return an re match object or None.
[189] Fix | Delete
[190] Fix | Delete
This is done by searching forwards until there is no match.
[191] Fix | Delete
Prog: compiled re object with a search method returning a match.
[192] Fix | Delete
Chars: line of text, without \\n.
[193] Fix | Delete
Col: stop index for the search; the limit for match.end().
[194] Fix | Delete
'''
[195] Fix | Delete
m = prog.search(chars)
[196] Fix | Delete
if not m:
[197] Fix | Delete
return None
[198] Fix | Delete
found = None
[199] Fix | Delete
i, j = m.span() # m.start(), m.end() == match slice indexes
[200] Fix | Delete
while i < col and j <= col:
[201] Fix | Delete
found = m
[202] Fix | Delete
if i == j:
[203] Fix | Delete
j = j+1
[204] Fix | Delete
m = prog.search(chars, j)
[205] Fix | Delete
if not m:
[206] Fix | Delete
break
[207] Fix | Delete
i, j = m.span()
[208] Fix | Delete
return found
[209] Fix | Delete
[210] Fix | Delete
def get_selection(text):
[211] Fix | Delete
'''Return tuple of 'line.col' indexes from selection or insert mark.
[212] Fix | Delete
'''
[213] Fix | Delete
try:
[214] Fix | Delete
first = text.index("sel.first")
[215] Fix | Delete
last = text.index("sel.last")
[216] Fix | Delete
except TclError:
[217] Fix | Delete
first = last = None
[218] Fix | Delete
if not first:
[219] Fix | Delete
first = text.index("insert")
[220] Fix | Delete
if not last:
[221] Fix | Delete
last = first
[222] Fix | Delete
return first, last
[223] Fix | Delete
[224] Fix | Delete
def get_line_col(index):
[225] Fix | Delete
'''Return (line, col) tuple of ints from 'line.col' string.'''
[226] Fix | Delete
line, col = map(int, index.split(".")) # Fails on invalid index
[227] Fix | Delete
return line, col
[228] Fix | Delete
[229] Fix | Delete
if __name__ == "__main__":
[230] Fix | Delete
import unittest
[231] Fix | Delete
unittest.main('idlelib.idle_test.test_searchengine', verbosity=2, exit=False)
[232] Fix | Delete
[233] Fix | Delete
It is recommended that you Edit text format, this type of Fix handles quite a lot in one request
Function