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

Python code coverage for Lib/idlelib/replace.py

#countcontent
1n/a"""Replace dialog for IDLE. Inherits SearchDialogBase for GUI.
2n/aUses idlelib.SearchEngine for search capability.
3n/aDefines various replace related functions like replace, replace all,
4n/areplace+find.
5n/a"""
6n/aimport re
7n/a
8n/afrom tkinter import StringVar, TclError
9n/a
10n/afrom idlelib.searchbase import SearchDialogBase
11n/afrom idlelib import searchengine
12n/a
13n/adef replace(text):
14n/a """Returns a singleton ReplaceDialog instance.The single dialog
15n/a saves user entries and preferences across instances."""
16n/a root = text._root()
17n/a engine = searchengine.get(root)
18n/a if not hasattr(engine, "_replacedialog"):
19n/a engine._replacedialog = ReplaceDialog(root, engine)
20n/a dialog = engine._replacedialog
21n/a dialog.open(text)
22n/a
23n/a
24n/aclass ReplaceDialog(SearchDialogBase):
25n/a
26n/a title = "Replace Dialog"
27n/a icon = "Replace"
28n/a
29n/a def __init__(self, root, engine):
30n/a SearchDialogBase.__init__(self, root, engine)
31n/a self.replvar = StringVar(root)
32n/a
33n/a def open(self, text):
34n/a """Display the replace dialog"""
35n/a SearchDialogBase.open(self, text)
36n/a try:
37n/a first = text.index("sel.first")
38n/a except TclError:
39n/a first = None
40n/a try:
41n/a last = text.index("sel.last")
42n/a except TclError:
43n/a last = None
44n/a first = first or text.index("insert")
45n/a last = last or first
46n/a self.show_hit(first, last)
47n/a self.ok = 1
48n/a
49n/a def create_entries(self):
50n/a """Create label and text entry widgets"""
51n/a SearchDialogBase.create_entries(self)
52n/a self.replent = self.make_entry("Replace with:", self.replvar)[0]
53n/a
54n/a def create_command_buttons(self):
55n/a SearchDialogBase.create_command_buttons(self)
56n/a self.make_button("Find", self.find_it)
57n/a self.make_button("Replace", self.replace_it)
58n/a self.make_button("Replace+Find", self.default_command, 1)
59n/a self.make_button("Replace All", self.replace_all)
60n/a
61n/a def find_it(self, event=None):
62n/a self.do_find(0)
63n/a
64n/a def replace_it(self, event=None):
65n/a if self.do_find(self.ok):
66n/a self.do_replace()
67n/a
68n/a def default_command(self, event=None):
69n/a "Replace and find next."
70n/a if self.do_find(self.ok):
71n/a if self.do_replace(): # Only find next match if replace succeeded.
72n/a # A bad re can cause it to fail.
73n/a self.do_find(0)
74n/a
75n/a def _replace_expand(self, m, repl):
76n/a """ Helper function for expanding a regular expression
77n/a in the replace field, if needed. """
78n/a if self.engine.isre():
79n/a try:
80n/a new = m.expand(repl)
81n/a except re.error:
82n/a self.engine.report_error(repl, 'Invalid Replace Expression')
83n/a new = None
84n/a else:
85n/a new = repl
86n/a
87n/a return new
88n/a
89n/a def replace_all(self, event=None):
90n/a """Replace all instances of patvar with replvar in text"""
91n/a prog = self.engine.getprog()
92n/a if not prog:
93n/a return
94n/a repl = self.replvar.get()
95n/a text = self.text
96n/a res = self.engine.search_text(text, prog)
97n/a if not res:
98n/a self.bell()
99n/a return
100n/a text.tag_remove("sel", "1.0", "end")
101n/a text.tag_remove("hit", "1.0", "end")
102n/a line = res[0]
103n/a col = res[1].start()
104n/a if self.engine.iswrap():
105n/a line = 1
106n/a col = 0
107n/a ok = 1
108n/a first = last = None
109n/a # XXX ought to replace circular instead of top-to-bottom when wrapping
110n/a text.undo_block_start()
111n/a while 1:
112n/a res = self.engine.search_forward(text, prog, line, col, 0, ok)
113n/a if not res:
114n/a break
115n/a line, m = res
116n/a chars = text.get("%d.0" % line, "%d.0" % (line+1))
117n/a orig = m.group()
118n/a new = self._replace_expand(m, repl)
119n/a if new is None:
120n/a break
121n/a i, j = m.span()
122n/a first = "%d.%d" % (line, i)
123n/a last = "%d.%d" % (line, j)
124n/a if new == orig:
125n/a text.mark_set("insert", last)
126n/a else:
127n/a text.mark_set("insert", first)
128n/a if first != last:
129n/a text.delete(first, last)
130n/a if new:
131n/a text.insert(first, new)
132n/a col = i + len(new)
133n/a ok = 0
134n/a text.undo_block_stop()
135n/a if first and last:
136n/a self.show_hit(first, last)
137n/a self.close()
138n/a
139n/a def do_find(self, ok=0):
140n/a if not self.engine.getprog():
141n/a return False
142n/a text = self.text
143n/a res = self.engine.search_text(text, None, ok)
144n/a if not res:
145n/a self.bell()
146n/a return False
147n/a line, m = res
148n/a i, j = m.span()
149n/a first = "%d.%d" % (line, i)
150n/a last = "%d.%d" % (line, j)
151n/a self.show_hit(first, last)
152n/a self.ok = 1
153n/a return True
154n/a
155n/a def do_replace(self):
156n/a prog = self.engine.getprog()
157n/a if not prog:
158n/a return False
159n/a text = self.text
160n/a try:
161n/a first = pos = text.index("sel.first")
162n/a last = text.index("sel.last")
163n/a except TclError:
164n/a pos = None
165n/a if not pos:
166n/a first = last = pos = text.index("insert")
167n/a line, col = searchengine.get_line_col(pos)
168n/a chars = text.get("%d.0" % line, "%d.0" % (line+1))
169n/a m = prog.match(chars, col)
170n/a if not prog:
171n/a return False
172n/a new = self._replace_expand(m, self.replvar.get())
173n/a if new is None:
174n/a return False
175n/a text.mark_set("insert", first)
176n/a text.undo_block_start()
177n/a if m.group():
178n/a text.delete(first, last)
179n/a if new:
180n/a text.insert(first, new)
181n/a text.undo_block_stop()
182n/a self.show_hit(first, text.index("insert"))
183n/a self.ok = 0
184n/a return True
185n/a
186n/a def show_hit(self, first, last):
187n/a """Highlight text from 'first' to 'last'.
188n/a 'first', 'last' - Text indices"""
189n/a text = self.text
190n/a text.mark_set("insert", first)
191n/a text.tag_remove("sel", "1.0", "end")
192n/a text.tag_add("sel", first, last)
193n/a text.tag_remove("hit", "1.0", "end")
194n/a if first == last:
195n/a text.tag_add("hit", first)
196n/a else:
197n/a text.tag_add("hit", first, last)
198n/a text.see("insert")
199n/a text.update_idletasks()
200n/a
201n/a def close(self, event=None):
202n/a SearchDialogBase.close(self, event)
203n/a self.text.tag_remove("hit", "1.0", "end")
204n/a
205n/a
206n/adef _replace_dialog(parent): # htest #
207n/a from tkinter import Toplevel, Text, END, SEL
208n/a from tkinter.ttk import Button
209n/a
210n/a box = Toplevel(parent)
211n/a box.title("Test ReplaceDialog")
212n/a x, y = map(int, parent.geometry().split('+')[1:])
213n/a box.geometry("+%d+%d" % (x, y + 175))
214n/a
215n/a # mock undo delegator methods
216n/a def undo_block_start():
217n/a pass
218n/a
219n/a def undo_block_stop():
220n/a pass
221n/a
222n/a text = Text(box, inactiveselectbackground='gray')
223n/a text.undo_block_start = undo_block_start
224n/a text.undo_block_stop = undo_block_stop
225n/a text.pack()
226n/a text.insert("insert","This is a sample sTring\nPlus MORE.")
227n/a text.focus_set()
228n/a
229n/a def show_replace():
230n/a text.tag_add(SEL, "1.0", END)
231n/a replace(text)
232n/a text.tag_remove(SEL, "1.0", END)
233n/a
234n/a button = Button(box, text="Replace", command=show_replace)
235n/a button.pack()
236n/a
237n/aif __name__ == '__main__':
238n/a import unittest
239n/a unittest.main('idlelib.idle_test.test_replace',
240n/a verbosity=2, exit=False)
241n/a
242n/a from idlelib.idle_test.htest import run
243n/a run(_replace_dialog)