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."
47 def setup(self
, window
):
49 buffer = window
.buffer
50 s
, e
= window
.get_selection_range()
51 self
.window
.mini_entry
.set_text(buffer.get_text(s
, e
, False))
52 cursor
= buffer.get_iter_at_mark(window
.insert_mark
)
53 buffer.move_mark_by_name('search_base', cursor
)
57 fwd
= rox
.ButtonMixed(g
.STOCK_GO_DOWN
, _('Find Next'))
58 fwd
.set_relief(g
.RELIEF_NONE
)
59 fwd
.unset_flags(g
.CAN_FOCUS
)
60 fwd
.connect('clicked', lambda e
: self
.set_dir(1))
62 rev
= rox
.ButtonMixed(g
.STOCK_GO_UP
, _('Find Previous'))
63 rev
.set_relief(g
.RELIEF_NONE
)
64 rev
.unset_flags(g
.CAN_FOCUS
)
65 rev
.connect('clicked', lambda e
: self
.set_dir(-1))
67 case
= g
.CheckButton(label
=_('Match case'))
68 case
.set_relief(g
.RELIEF_NONE
)
69 case
.unset_flags(g
.CAN_FOCUS
)
71 self
.window
.mini_hbox
.pack_start(fwd
, False, True, 0)
72 self
.window
.mini_hbox
.pack_start(rev
, False, True, 0)
73 # self.window.mini_hbox.pack_start(case, False, True, 10)
75 self
.items
= [fwd
, rev
] #, case]
78 pattern
= self
.window
.mini_entry
.get_text()
80 self
.last_search
= pattern
82 self
.window
.mini_hbox
.remove(x
)
84 info
= _('Type a string to search for. The display will scroll to show the ' \
85 'next match as you type. Use the Up and Down cursor keys to move ' \
86 'to the next or previous match. Press Escape or Return to finish.')
89 self
.window
.set_mini_label(_(' Find: '))
91 def set_dir(self
, dir):
92 assert dir == 1 or dir == -1
94 buffer = self
.window
.buffer
95 cursor
= buffer.get_iter_at_mark(self
.window
.insert_mark
)
96 buffer.move_mark_by_name('search_base', cursor
)
100 cursor
.forward_char()
102 cursor
.backward_char()
103 if self
.search(cursor
):
104 buffer.move_mark_by_name('search_base', cursor
)
111 self
.window
.set_minibuffer(None)
113 def search_again(self
):
114 self
.set_dir(self
.dir)
116 def key_press(self
, kev
):
118 if k
== g
.keysyms
.Up
:
120 elif k
== g
.keysyms
.Down
:
126 def search(self
, start
):
127 "Search forwards or backwards for the pattern. Matches at 'start'"
128 "are allowed in both directions. Returns (match_start, match_end) if"
131 pattern
= self
.window
.mini_entry
.get_text()
135 found
= iter.forward_search(pattern
, 0, None)
137 iter.forward_chars(len(pattern
))
138 found
= iter.backward_search(pattern
, 0, None)
141 def restore_previous_search(self
):
143 self
.window
.mini_entry
.set_text(self
.last_search
)
146 buffer = self
.window
.buffer
147 pos
= buffer.get_iter_at_mark(self
.window
.search_base
)
149 found
= self
.search(pos
)
151 buffer.move_mark_by_name('insert', found
[0])
152 buffer.move_mark_by_name('selection_bound', found
[1])
153 self
.window
.text
.scroll_to_iter(found
[0], 0.05, False)
157 class RegexHelp(g
.ScrolledWindow
):
159 g
.ScrolledWindow
.__init
__(self
)
160 self
.set_shadow_type(g
.SHADOW_IN
)
161 self
.set_policy(g
.POLICY_NEVER
, g
.POLICY_AUTOMATIC
)
163 model
= g
.ListStore(str, str)
164 view
= g
.TreeView(model
)
168 cell
= g
.CellRendererText()
169 column
= g
.TreeViewColumn(_('Code'), cell
, text
= 0)
170 view
.append_column(column
)
171 column
= g
.TreeViewColumn(_('Meaning'), cell
, text
= 1)
172 view
.append_column(column
)
174 for c
, m
in regex_help
:
176 model
.set(new
, 0, c
, 1, m
)
178 self
.set_size_request(-1, 150)
180 view
.get_selection().set_mode(g
.SELECTION_NONE
)
182 history
= {} # Field name -> last value
184 class Replace(rox
.Dialog
):
185 def __init__(self
, window
):
186 self
.edit_window
= window
187 rox
.Dialog
.__init
__(self
, parent
= window
,
188 flags
= g
.DIALOG_DESTROY_WITH_PARENT |
189 g
.DIALOG_NO_SEPARATOR
)
190 self
.add_button(g
.STOCK_CANCEL
, g
.RESPONSE_CANCEL
)
191 self
.add_button(g
.STOCK_FIND_AND_REPLACE
, g
.RESPONSE_OK
)
192 self
.set_default_response(g
.RESPONSE_OK
)
194 def response(dialog
, resp
):
195 if resp
== int(g
.RESPONSE_OK
):
199 self
.connect('response', response
)
201 vbox
= g
.VBox(False, 5)
202 self
.vbox
.pack_start(vbox
, True, True, 0)
203 vbox
.set_border_width(5)
204 self
.sizegroup
= g
.SizeGroup(g
.SIZE_GROUP_HORIZONTAL
)
207 hbox
= g
.HBox(False, 2)
208 vbox
.pack_start(hbox
, False, True, 0)
210 label
= g
.Label(name
)
211 self
.sizegroup
.add_widget(label
)
212 hbox
.pack_start(label
, False, True, 0)
213 hbox
.pack_start(entry
, True, True, 0)
214 entry
.set_text(history
.get(name
, ''))
216 history
[name
] = entry
.get_text()
217 entry
.connect('changed', changed
)
218 entry
.set_activates_default(True)
222 self
.replace_entry
= field(_('Replace:'))
223 self
.with_entry
= field(_('With:'))
228 self
.sizegroup
.add_widget(label
)
229 hbox
.pack_start(label
, False, False, 3)
230 self
.regex
= g
.CheckButton(_('Advanced search and replace'))
231 hbox
.pack_start(self
.regex
, False, False, 0)
232 vbox
.pack_start(hbox
, False, True, 0)
235 regex_help
= RegexHelp()
236 vbox
.pack_start(regex_help
, True, True, 0)
238 self
.python_with
= g
.CheckButton(_("Evaluate 'With' as Python expression"))
239 def changed(toggle
): history
['Python'] = toggle
.get_active()
240 vbox
.pack_start(self
.python_with
, False, True, 0)
241 self
.python_with
.set_active(history
.get('Python', False))
242 self
.python_with
.connect('toggled', changed
)
245 history
['Advanced'] = toggle
.get_active()
246 if toggle
.get_active():
248 self
.python_with
.show()
251 self
.python_with
.hide()
253 self
.regex
.connect('toggled', changed
)
254 self
.regex
.set_active(history
.get('Advanced', False))
256 def do_replace(self
, show_info
= True):
257 regex
= self
.regex
.get_active()
259 replace
= self
.replace_entry
.get_text()
261 rox
.alert(_('You need to specify something to search for...'))
263 replacement
= self
.with_entry
.get_text()
269 prog
= re
.compile(replace
)
271 rox
.report_exception()
273 python
= self
.python_with
.get_active()
276 code
= compile(replacement
, 'With', 'eval')
277 def replacement(match
):
278 locals = {'old': match
.group(0)}
280 locals['x'] = float(locals['old'])
283 return str(eval(code
, locals))
285 rox
.report_exception()
288 new
, n
= prog
.subn(replacement
, line
)
294 new
= line
.replace(replace
, replacement
)
301 self
.edit_window
.process_selected(do_line
)
303 rox
.report_exception()
306 rox
.alert(_('Search string not found'))
310 rox
.info(_('One line changed'))
312 rox
.info(_('%d lines changed') % changes
[0])