3 from EditWindow
import Minibuffer
6 ('.', 'Matches any character'),
7 ('[a-z]', 'Any lowercase letter'),
8 ('[-+*/]', 'Any character listed (- must be first)'),
9 ('^A', 'A only at the start of a line'),
10 ('A$', 'A only at the end of a line'),
11 ('A*', 'Zero or more A'),
12 ('A+', 'One or more A'),
13 ('A?', 'Zero or one A'),
14 ('A{m,n}', 'Between m and n matches of A'),
15 ('A*?, A+?, A??, A{}?', 'Non-greedy versions of *, +, ? and {}'),
16 ('\*, \+, etc', 'Literal "*", "+"'),
17 ('A|B', 'Can match A or B'),
18 ('(AB)', 'Group A and B together (for *, \\1, etc)'),
19 ('\\1, \\2, etc', 'The first/second bracketed match (goes in the With: box)'),
20 ('\\b', 'Word boundary (eg, \\bWord\\b)'),
21 ('\\B', 'Non-word boundary'),
22 ('\\d, \\D', 'Digit, non-digit'),
23 ('\\s, \\S', 'Whitespace, non-whitespace'),
24 ('Others', 'See the Python regular expression documentation for more'),
27 ('Fred', 'Matches "Fred" anywhere'),
28 ('^Fred$', 'A line containing only "Fred"'),
29 ('Go+gle', '"Gogle, Google, Gooogle, etc"'),
30 ('Colou?r', 'Colour or Color'),
31 ('[tT]he', '"The" or "the"'),
32 ('M.*d', '"Md", "Mad", "Mud", "Mind", etc'),
33 ('([ab][cd])+', '"ac", "ad", "acbdad", etc'),
35 ('Python expressions:', ''),
36 ('old', 'The text that was matched'),
37 ('x', "The numerical value of 'old'"),
38 ('old.upper()', "Convert match to uppercase"),
39 ('x * 2', "Double all matched numbers"),
42 class Search(Minibuffer
):
43 "A minibuffer used to search for text."
45 def setup(self
, window
):
47 buffer = window
.buffer
48 cursor
= buffer.get_iter_at_mark(window
.insert_mark
)
49 buffer.move_mark_by_name('search_base', cursor
)
53 info
= 'Type a string to search for. The display will scroll to show the ' \
54 'next match as you type. Use the Up and Down cursor keys to move ' \
55 'to the next or previous match. Press Escape or Return to finish.'
59 self
.window
.set_mini_label('Forward search:')
61 self
.window
.set_mini_label('Backward search:')
63 def set_dir(self
, dir):
64 assert dir == 1 or dir == -1
66 buffer = self
.window
.buffer
67 cursor
= buffer.get_iter_at_mark(self
.window
.insert_mark
)
68 buffer.move_mark_by_name('search_base', cursor
)
74 cursor
.backward_char()
75 if self
.search(cursor
):
76 buffer.move_mark_by_name('search_base', cursor
)
85 self
.window
.set_minibuffer(None)
87 def key_press(self
, kev
):
91 elif k
== g
.keysyms
.Down
:
97 def search(self
, start
):
98 "Search forwards or backwards for the pattern. Matches at 'start'"
99 "are allowed in both directions. Returns (match_start, match_end) if"
102 pattern
= self
.window
.mini_entry
.get_text()
106 found
= iter.forward_search(pattern
, 0, None)
108 iter.forward_chars(len(pattern
))
109 found
= iter.backward_search(pattern
, 0, None)
113 buffer = self
.window
.buffer
114 pos
= buffer.get_iter_at_mark(self
.window
.search_base
)
116 found
= self
.search(pos
)
118 buffer.move_mark_by_name('insert', found
[0])
119 buffer.move_mark_by_name('selection_bound', found
[1])
120 self
.window
.text
.scroll_to_iter(found
[0], 0.05, g
.FALSE
)
124 class RegexHelp(g
.ScrolledWindow
):
126 g
.ScrolledWindow
.__init
__(self
)
127 self
.set_shadow_type(g
.SHADOW_IN
)
128 self
.set_policy(g
.POLICY_NEVER
, g
.POLICY_AUTOMATIC
)
130 model
= g
.ListStore(str, str)
131 view
= g
.TreeView(model
)
135 cell
= g
.CellRendererText()
136 column
= g
.TreeViewColumn('Code', cell
, text
= 0)
137 view
.append_column(column
)
138 column
= g
.TreeViewColumn('Meaning', cell
, text
= 1)
139 view
.append_column(column
)
141 for c
, m
in regex_help
:
143 model
.set(new
, 0, c
, 1, m
)
145 self
.set_size_request(-1, 150)
147 view
.get_selection().set_mode(g
.SELECTION_NONE
)
149 history
= {} # Field name -> last value
151 class Replace(rox
.Dialog
):
152 def __init__(self
, window
):
153 self
.edit_window
= window
154 rox
.Dialog
.__init
__(self
, parent
= window
,
155 flags
= g
.DIALOG_DESTROY_WITH_PARENT |
156 g
.DIALOG_NO_SEPARATOR
)
157 self
.add_button(g
.STOCK_CANCEL
, g
.RESPONSE_CANCEL
)
158 self
.add_button(g
.STOCK_FIND_AND_REPLACE
, g
.RESPONSE_OK
)
159 self
.set_default_response(g
.RESPONSE_OK
)
161 def response(dialog
, resp
):
162 if resp
== g
.RESPONSE_OK
:
166 self
.connect('response', response
)
168 vbox
= g
.VBox(False, 5)
169 self
.vbox
.pack_start(vbox
, True, True, 0)
170 vbox
.set_border_width(5)
173 hbox
= g
.HBox(False, 2)
174 vbox
.pack_start(hbox
, False, True, 0)
176 hbox
.pack_start(g
.Label(name
), False, True, 0)
177 hbox
.pack_start(entry
, True, True, 0)
178 entry
.set_text(history
.get(name
, ''))
180 history
[name
] = entry
.get_text()
181 entry
.connect('changed', changed
)
182 entry
.set_activates_default(True)
185 self
.replace_entry
= field('Replace:')
186 self
.with_entry
= field('With:')
188 self
.regex
= g
.CheckButton('Advanced search and replace')
189 vbox
.pack_start(self
.regex
, False, True, 0)
192 regex_help
= RegexHelp()
193 vbox
.pack_start(regex_help
, True, True, 0)
195 self
.python_with
= g
.CheckButton("Evaluate 'With' as Python expression")
196 def changed(toggle
): history
['Python'] = toggle
.get_active()
197 vbox
.pack_start(self
.python_with
, False, True, 0)
198 self
.python_with
.set_active(history
.get('Python', False))
199 self
.python_with
.connect('toggled', changed
)
202 history
['Advanced'] = toggle
.get_active()
203 if toggle
.get_active():
205 self
.python_with
.show()
208 self
.python_with
.hide()
210 self
.regex
.connect('toggled', changed
)
211 self
.regex
.set_active(history
.get('Advanced', False))
213 def do_replace(self
):
214 regex
= self
.regex
.get_active()
216 replace
= self
.replace_entry
.get_text()
218 rox
.alert('You need to specify something to search for...')
220 with
= self
.with_entry
.get_text()
226 prog
= re
.compile(replace
)
228 rox
.report_exception()
230 python
= self
.python_with
.get_active()
233 code
= compile(with
, 'With', 'eval')
235 locals = {'old': match
.group(0)}
237 locals['x'] = float(locals['old'])
240 return str(eval(code
, locals))
242 rox
.report_exception()
245 new
, n
= prog
.subn(with
, line
)
251 new
= line
.replace(replace
, with
)
258 self
.edit_window
.process_selected(do_line
)
260 rox
.report_exception()
263 rox
.alert('Search string not found')
266 rox
.info('One line changed')
268 rox
.info('%d lines changed' % changes
[0])