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."
46 def setup(self
, window
):
48 buffer = window
.buffer
49 s
, e
= window
.get_selection_range()
50 self
.window
.mini_entry
.set_text(buffer.get_text(s
, e
, False))
51 cursor
= buffer.get_iter_at_mark(window
.insert_mark
)
52 buffer.move_mark_by_name('search_base', cursor
)
56 fwd
= rox
.ButtonMixed(g
.STOCK_GO_DOWN
, _('Find Next'))
57 fwd
.set_relief(g
.RELIEF_NONE
)
58 fwd
.unset_flags(g
.CAN_FOCUS
)
59 fwd
.connect('clicked', lambda e
: self
.set_dir(1))
61 rev
= rox
.ButtonMixed(g
.STOCK_GO_UP
, _('Find Previous'))
62 rev
.set_relief(g
.RELIEF_NONE
)
63 rev
.unset_flags(g
.CAN_FOCUS
)
64 rev
.connect('clicked', lambda e
: self
.set_dir(-1))
66 case
= g
.CheckButton(label
=_('Match case'))
67 case
.set_relief(g
.RELIEF_NONE
)
68 case
.unset_flags(g
.CAN_FOCUS
)
70 self
.window
.mini_hbox
.pack_start(fwd
, False, True, 0)
71 self
.window
.mini_hbox
.pack_start(rev
, False, True, 0)
72 # self.window.mini_hbox.pack_start(case, False, True, 10)
74 self
.items
= [fwd
, rev
] #, case]
78 self
.window
.mini_hbox
.remove(x
)
80 info
= _('Type a string to search for. The display will scroll to show the ' \
81 'next match as you type. Use the Up and Down cursor keys to move ' \
82 'to the next or previous match. Press Escape or Return to finish.')
85 self
.window
.set_mini_label(_(' Find: '))
87 def set_dir(self
, dir):
88 assert dir == 1 or dir == -1
90 buffer = self
.window
.buffer
91 cursor
= buffer.get_iter_at_mark(self
.window
.insert_mark
)
92 buffer.move_mark_by_name('search_base', cursor
)
98 cursor
.backward_char()
99 if self
.search(cursor
):
100 buffer.move_mark_by_name('search_base', cursor
)
109 self
.set_dir(self
.dir)
111 def key_press(self
, kev
):
113 if k
== g
.keysyms
.Up
:
115 elif k
== g
.keysyms
.Down
:
121 def search(self
, start
):
122 "Search forwards or backwards for the pattern. Matches at 'start'"
123 "are allowed in both directions. Returns (match_start, match_end) if"
126 pattern
= self
.window
.mini_entry
.get_text()
130 found
= iter.forward_search(pattern
, 0, None)
132 iter.forward_chars(len(pattern
))
133 found
= iter.backward_search(pattern
, 0, None)
137 buffer = self
.window
.buffer
138 pos
= buffer.get_iter_at_mark(self
.window
.search_base
)
140 found
= self
.search(pos
)
142 buffer.move_mark_by_name('insert', found
[0])
143 buffer.move_mark_by_name('selection_bound', found
[1])
144 self
.window
.text
.scroll_to_iter(found
[0], 0.05, False)
148 class RegexHelp(g
.ScrolledWindow
):
150 g
.ScrolledWindow
.__init
__(self
)
151 self
.set_shadow_type(g
.SHADOW_IN
)
152 self
.set_policy(g
.POLICY_NEVER
, g
.POLICY_AUTOMATIC
)
154 model
= g
.ListStore(str, str)
155 view
= g
.TreeView(model
)
159 cell
= g
.CellRendererText()
160 column
= g
.TreeViewColumn(_('Code'), cell
, text
= 0)
161 view
.append_column(column
)
162 column
= g
.TreeViewColumn(_('Meaning'), cell
, text
= 1)
163 view
.append_column(column
)
165 for c
, m
in regex_help
:
167 model
.set(new
, 0, c
, 1, m
)
169 self
.set_size_request(-1, 150)
171 view
.get_selection().set_mode(g
.SELECTION_NONE
)
173 history
= {} # Field name -> last value
175 class Replace(rox
.Dialog
):
176 def __init__(self
, window
):
177 self
.edit_window
= window
178 rox
.Dialog
.__init
__(self
, parent
= window
,
179 flags
= g
.DIALOG_DESTROY_WITH_PARENT |
180 g
.DIALOG_NO_SEPARATOR
)
181 self
.add_button(g
.STOCK_CANCEL
, g
.RESPONSE_CANCEL
)
182 self
.add_button(g
.STOCK_FIND_AND_REPLACE
, g
.RESPONSE_OK
)
183 self
.set_default_response(g
.RESPONSE_OK
)
185 def response(dialog
, resp
):
186 if resp
== g
.RESPONSE_OK
:
190 self
.connect('response', response
)
192 vbox
= g
.VBox(False, 5)
193 self
.vbox
.pack_start(vbox
, True, True, 0)
194 vbox
.set_border_width(5)
195 self
.sizegroup
= g
.SizeGroup(g
.SIZE_GROUP_HORIZONTAL
)
198 hbox
= g
.HBox(False, 2)
199 vbox
.pack_start(hbox
, False, True, 0)
201 label
= g
.Label(name
)
202 self
.sizegroup
.add_widget(label
)
203 hbox
.pack_start(label
, False, True, 0)
204 hbox
.pack_start(entry
, True, True, 0)
205 entry
.set_text(history
.get(name
, ''))
207 history
[name
] = entry
.get_text()
208 entry
.connect('changed', changed
)
209 entry
.set_activates_default(True)
213 self
.replace_entry
= field(_('Replace:'))
214 self
.with_entry
= field(_('With:'))
219 self
.sizegroup
.add_widget(label
)
220 hbox
.pack_start(label
, False, False, 3)
221 self
.regex
= g
.CheckButton(_('Advanced search and replace'))
222 hbox
.pack_start(self
.regex
, False, False, 0)
223 vbox
.pack_start(hbox
, False, True, 0)
226 regex_help
= RegexHelp()
227 vbox
.pack_start(regex_help
, True, True, 0)
229 self
.python_with
= g
.CheckButton(_("Evaluate 'With' as Python expression"))
230 def changed(toggle
): history
['Python'] = toggle
.get_active()
231 vbox
.pack_start(self
.python_with
, False, True, 0)
232 self
.python_with
.set_active(history
.get('Python', False))
233 self
.python_with
.connect('toggled', changed
)
236 history
['Advanced'] = toggle
.get_active()
237 if toggle
.get_active():
239 self
.python_with
.show()
242 self
.python_with
.hide()
244 self
.regex
.connect('toggled', changed
)
245 self
.regex
.set_active(history
.get('Advanced', False))
247 def do_replace(self
, show_info
= True):
248 regex
= self
.regex
.get_active()
250 replace
= self
.replace_entry
.get_text()
252 rox
.alert(_('You need to specify something to search for...'))
254 with
= self
.with_entry
.get_text()
260 prog
= re
.compile(replace
)
262 rox
.report_exception()
264 python
= self
.python_with
.get_active()
267 code
= compile(with
, 'With', 'eval')
269 locals = {'old': match
.group(0)}
271 locals['x'] = float(locals['old'])
274 return str(eval(code
, locals))
276 rox
.report_exception()
279 new
, n
= prog
.subn(with
, line
)
285 new
= line
.replace(replace
, with
)
292 self
.edit_window
.process_selected(do_line
)
294 rox
.report_exception()
297 rox
.alert(_('Search string not found'))
301 rox
.info(_('One line changed'))
303 rox
.info(_('%d lines changed') % changes
[0])