ยปCore Development>Code coverage>Lib/idlelib/SearchEngine.py

Python code coverage for Lib/idlelib/SearchEngine.py

#countcontent
1n/aimport re
2n/afrom tkinter import *
3n/aimport tkinter.messagebox as tkMessageBox
4n/a
5n/adef get(root):
6n/a if not hasattr(root, "_searchengine"):
7n/a root._searchengine = SearchEngine(root)
8n/a # XXX This will never garbage-collect -- who cares
9n/a return root._searchengine
10n/a
11n/aclass SearchEngine:
12n/a
13n/a def __init__(self, root):
14n/a self.root = root
15n/a # State shared by search, replace, and grep;
16n/a # the search dialogs bind these to UI elements.
17n/a self.patvar = StringVar(root) # search pattern
18n/a self.revar = BooleanVar(root) # regular expression?
19n/a self.casevar = BooleanVar(root) # match case?
20n/a self.wordvar = BooleanVar(root) # match whole word?
21n/a self.wrapvar = BooleanVar(root) # wrap around buffer?
22n/a self.wrapvar.set(1) # (on by default)
23n/a self.backvar = BooleanVar(root) # search backwards?
24n/a
25n/a # Access methods
26n/a
27n/a def getpat(self):
28n/a return self.patvar.get()
29n/a
30n/a def setpat(self, pat):
31n/a self.patvar.set(pat)
32n/a
33n/a def isre(self):
34n/a return self.revar.get()
35n/a
36n/a def iscase(self):
37n/a return self.casevar.get()
38n/a
39n/a def isword(self):
40n/a return self.wordvar.get()
41n/a
42n/a def iswrap(self):
43n/a return self.wrapvar.get()
44n/a
45n/a def isback(self):
46n/a return self.backvar.get()
47n/a
48n/a # Higher level access methods
49n/a
50n/a def getcookedpat(self):
51n/a pat = self.getpat()
52n/a if not self.isre():
53n/a pat = re.escape(pat)
54n/a if self.isword():
55n/a pat = r"\b%s\b" % pat
56n/a return pat
57n/a
58n/a def getprog(self):
59n/a pat = self.getpat()
60n/a if not pat:
61n/a self.report_error(pat, "Empty regular expression")
62n/a return None
63n/a pat = self.getcookedpat()
64n/a flags = 0
65n/a if not self.iscase():
66n/a flags = flags | re.IGNORECASE
67n/a try:
68n/a prog = re.compile(pat, flags)
69n/a except re.error as what:
70n/a try:
71n/a msg, col = what
72n/a except:
73n/a msg = str(what)
74n/a col = -1
75n/a self.report_error(pat, msg, col)
76n/a return None
77n/a return prog
78n/a
79n/a def report_error(self, pat, msg, col=-1):
80n/a # Derived class could overrid this with something fancier
81n/a msg = "Error: " + str(msg)
82n/a if pat:
83n/a msg = msg + "\np\Pattern: " + str(pat)
84n/a if col >= 0:
85n/a msg = msg + "\nOffset: " + str(col)
86n/a tkMessageBox.showerror("Regular expression error",
87n/a msg, master=self.root)
88n/a
89n/a def setcookedpat(self, pat):
90n/a if self.isre():
91n/a pat = re.escape(pat)
92n/a self.setpat(pat)
93n/a
94n/a def search_text(self, text, prog=None, ok=0):
95n/a """Search a text widget for the pattern.
96n/a
97n/a If prog is given, it should be the precompiled pattern.
98n/a Return a tuple (lineno, matchobj); None if not found.
99n/a
100n/a This obeys the wrap and direction (back) settings.
101n/a
102n/a The search starts at the selection (if there is one) or
103n/a at the insert mark (otherwise). If the search is forward,
104n/a it starts at the right of the selection; for a backward
105n/a search, it starts at the left end. An empty match exactly
106n/a at either end of the selection (or at the insert mark if
107n/a there is no selection) is ignored unless the ok flag is true
108n/a -- this is done to guarantee progress.
109n/a
110n/a If the search is allowed to wrap around, it will return the
111n/a original selection if (and only if) it is the only match.
112n/a
113n/a """
114n/a if not prog:
115n/a prog = self.getprog()
116n/a if not prog:
117n/a return None # Compilation failed -- stop
118n/a wrap = self.wrapvar.get()
119n/a first, last = get_selection(text)
120n/a if self.isback():
121n/a if ok:
122n/a start = last
123n/a else:
124n/a start = first
125n/a line, col = get_line_col(start)
126n/a res = self.search_backward(text, prog, line, col, wrap, ok)
127n/a else:
128n/a if ok:
129n/a start = first
130n/a else:
131n/a start = last
132n/a line, col = get_line_col(start)
133n/a res = self.search_forward(text, prog, line, col, wrap, ok)
134n/a return res
135n/a
136n/a def search_forward(self, text, prog, line, col, wrap, ok=0):
137n/a wrapped = 0
138n/a startline = line
139n/a chars = text.get("%d.0" % line, "%d.0" % (line+1))
140n/a while chars:
141n/a m = prog.search(chars[:-1], col)
142n/a if m:
143n/a if ok or m.end() > col:
144n/a return line, m
145n/a line = line + 1
146n/a if wrapped and line > startline:
147n/a break
148n/a col = 0
149n/a ok = 1
150n/a chars = text.get("%d.0" % line, "%d.0" % (line+1))
151n/a if not chars and wrap:
152n/a wrapped = 1
153n/a wrap = 0
154n/a line = 1
155n/a chars = text.get("1.0", "2.0")
156n/a return None
157n/a
158n/a def search_backward(self, text, prog, line, col, wrap, ok=0):
159n/a wrapped = 0
160n/a startline = line
161n/a chars = text.get("%d.0" % line, "%d.0" % (line+1))
162n/a while 1:
163n/a m = search_reverse(prog, chars[:-1], col)
164n/a if m:
165n/a if ok or m.start() < col:
166n/a return line, m
167n/a line = line - 1
168n/a if wrapped and line < startline:
169n/a break
170n/a ok = 1
171n/a if line <= 0:
172n/a if not wrap:
173n/a break
174n/a wrapped = 1
175n/a wrap = 0
176n/a pos = text.index("end-1c")
177n/a line, col = map(int, pos.split("."))
178n/a chars = text.get("%d.0" % line, "%d.0" % (line+1))
179n/a col = len(chars) - 1
180n/a return None
181n/a
182n/a# Helper to search backwards in a string.
183n/a# (Optimized for the case where the pattern isn't found.)
184n/a
185n/adef search_reverse(prog, chars, col):
186n/a m = prog.search(chars)
187n/a if not m:
188n/a return None
189n/a found = None
190n/a i, j = m.span()
191n/a while i < col and j <= col:
192n/a found = m
193n/a if i == j:
194n/a j = j+1
195n/a m = prog.search(chars, j)
196n/a if not m:
197n/a break
198n/a i, j = m.span()
199n/a return found
200n/a
201n/a# Helper to get selection end points, defaulting to insert mark.
202n/a# Return a tuple of indices ("line.col" strings).
203n/a
204n/adef get_selection(text):
205n/a try:
206n/a first = text.index("sel.first")
207n/a last = text.index("sel.last")
208n/a except TclError:
209n/a first = last = None
210n/a if not first:
211n/a first = text.index("insert")
212n/a if not last:
213n/a last = first
214n/a return first, last
215n/a
216n/a# Helper to parse a text index into a (line, col) tuple.
217n/a
218n/adef get_line_col(index):
219n/a line, col = map(int, index.split(".")) # Fails on invalid index
220n/a return line, col