blob: 3bff8b5e6714bacfba2b1eff442f6871688b5438 [file] [log] [blame]
Guido van Rossum504b0bf1999-01-02 21:28:54 +00001import string
2import os
3import re
4import fnmatch
5from Tkinter import *
6import tkMessageBox
7import SearchEngine
8from SearchDialogBase import SearchDialogBase
9
10def replace(text):
11 root = text._root()
12 engine = SearchEngine.get(root)
13 if not hasattr(engine, "_replacedialog"):
14 engine._replacedialog = ReplaceDialog(root, engine)
15 dialog = engine._replacedialog
16 dialog.open(text)
17
18class ReplaceDialog(SearchDialogBase):
19
20 title = "Replace Dialog"
21 icon = "Replace"
22
23 def __init__(self, root, engine):
24 SearchDialogBase.__init__(self, root, engine)
25 self.replvar = StringVar(root)
26
27 def open(self, text):
28 SearchDialogBase.open(self, text)
29 try:
30 first = text.index("sel.first")
31 except TclError:
32 first = None
33 try:
34 last = text.index("sel.last")
35 except TclError:
36 last = None
37 first = first or text.index("insert")
38 last = last or first
39 self.show_hit(first, last)
40 self.ok = 1
41
42 def create_entries(self):
43 SearchDialogBase.create_entries(self)
44 self.replent = self.make_entry("Replace with:", self.replvar)
45
46 def create_command_buttons(self):
47 SearchDialogBase.create_command_buttons(self)
48 self.make_button("Find", self.find_it)
49 self.make_button("Replace", self.replace_it)
50 self.make_button("Replace+Find", self.default_command, 1)
51 self.make_button("Replace All", self.replace_all)
52
53 def find_it(self, event=None):
54 self.do_find(0)
55
56 def replace_it(self, event=None):
57 if self.do_find(self.ok):
58 self.do_replace()
59
60 def default_command(self, event=None):
61 if self.do_find(self.ok):
62 self.do_replace()
63 self.do_find(0)
64
65 def replace_all(self, event=None):
66 prog = self.engine.getprog()
67 if not prog:
68 return
69 repl = self.replvar.get()
70 text = self.text
71 res = self.engine.search_text(text, prog)
72 if not res:
73 text.bell()
74 return
75 text.tag_remove("sel", "1.0", "end")
76 text.tag_remove("hit", "1.0", "end")
77 line = res[0]
78 col = res[1].start()
79 if self.engine.iswrap():
80 line = 1
81 col = 0
82 ok = 1
83 first = last = None
84 # XXX ought to replace circular instead of top-to-bottom when wrapping
85 while 1:
86 res = self.engine.search_forward(text, prog, line, col, 0, ok)
87 if not res:
88 break
89 line, m = res
90 chars = text.get("%d.0" % line, "%d.0" % (line+1))
91 orig = m.group()
92 new = re.pcre_expand(m, repl)
93 i, j = m.span()
94 first = "%d.%d" % (line, i)
95 last = "%d.%d" % (line, j)
96 if new == orig:
97 text.mark_set("insert", last)
98 else:
99 text.mark_set("insert", first)
100 if first != last:
101 text.delete(first, last)
102 if new:
103 text.insert(first, new)
104 col = i + len(new)
105 ok = 0
106 if first and last:
107 self.show_hit(first, last)
108 self.close()
109
110 def do_find(self, ok=0):
111 if not self.engine.getprog():
112 return 0
113 text = self.text
114 res = self.engine.search_text(text, None, ok)
115 if not res:
116 text.bell()
117 return 0
118 line, m = res
119 i, j = m.span()
120 first = "%d.%d" % (line, i)
121 last = "%d.%d" % (line, j)
122 self.show_hit(first, last)
123 self.ok = 1
124 return 1
125
126 def do_replace(self):
127 prog = self.engine.getprog()
128 if not prog:
129 return 0
130 text = self.text
131 try:
132 first = pos = text.index("sel.first")
133 last = text.index("sel.last")
134 except TclError:
135 pos = None
136 if not pos:
137 first = last = pos = text.index("insert")
138 line, col = SearchEngine.get_line_col(pos)
139 chars = text.get("%d.0" % line, "%d.0" % (line+1))
140 m = prog.match(chars, col)
141 if not prog:
142 return 0
143 new = re.pcre_expand(m, self.replvar.get())
144 text.mark_set("insert", first)
145 if m.group():
146 text.delete(first, last)
147 if new:
148 text.insert(first, new)
149 self.show_hit(first, text.index("insert"))
150 self.ok = 0
151 return 1
152
153 def show_hit(self, first, last):
154 text = self.text
155 text.mark_set("insert", first)
156 text.tag_remove("sel", "1.0", "end")
157 text.tag_add("sel", first, last)
158 text.tag_remove("hit", "1.0", "end")
159 if first == last:
160 text.tag_add("hit", first)
161 else:
162 text.tag_add("hit", first, last)
163 text.see("insert")
164 text.update_idletasks()
165
166 def close(self, event=None):
167 SearchDialogBase.close(self, event)
168 self.text.tag_remove("hit", "1.0", "end")