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
)
107 self
.set_dir(self
.dir)
109 def key_press(self
, kev
):
111 if k
== g
.keysyms
.Up
:
113 elif k
== g
.keysyms
.Down
:
119 def search(self
, start
):
120 "Search forwards or backwards for the pattern. Matches at 'start'"
121 "are allowed in both directions. Returns (match_start, match_end) if"
124 pattern
= self
.window
.mini_entry
.get_text()
128 found
= iter.forward_search(pattern
, 0, None)
130 iter.forward_chars(len(pattern
))
131 found
= iter.backward_search(pattern
, 0, None)
135 buffer = self
.window
.buffer
136 pos
= buffer.get_iter_at_mark(self
.window
.search_base
)
138 found
= self
.search(pos
)
140 buffer.move_mark_by_name('insert', found
[0])
141 buffer.move_mark_by_name('selection_bound', found
[1])
142 self
.window
.text
.scroll_to_iter(found
[0], 0.05, False)
146 class RegexHelp(g
.ScrolledWindow
):
148 g
.ScrolledWindow
.__init
__(self
)
149 self
.set_shadow_type(g
.SHADOW_IN
)
150 self
.set_policy(g
.POLICY_NEVER
, g
.POLICY_AUTOMATIC
)
152 model
= g
.ListStore(str, str)
153 view
= g
.TreeView(model
)
157 cell
= g
.CellRendererText()
158 column
= g
.TreeViewColumn(_('Code'), cell
, text
= 0)
159 view
.append_column(column
)
160 column
= g
.TreeViewColumn(_('Meaning'), cell
, text
= 1)
161 view
.append_column(column
)
163 for c
, m
in regex_help
:
165 model
.set(new
, 0, c
, 1, m
)
167 self
.set_size_request(-1, 150)
169 view
.get_selection().set_mode(g
.SELECTION_NONE
)
171 history
= {} # Field name -> last value
173 class Replace(rox
.Dialog
):
174 def __init__(self
, window
):
175 self
.edit_window
= window
176 rox
.Dialog
.__init
__(self
, parent
= window
,
177 flags
= g
.DIALOG_DESTROY_WITH_PARENT |
178 g
.DIALOG_NO_SEPARATOR
)
179 self
.add_button(g
.STOCK_CANCEL
, g
.RESPONSE_CANCEL
)
180 self
.add_button(g
.STOCK_FIND_AND_REPLACE
, g
.RESPONSE_OK
)
181 self
.set_default_response(g
.RESPONSE_OK
)
183 def response(dialog
, resp
):
184 if resp
== g
.RESPONSE_OK
:
188 self
.connect('response', response
)
190 vbox
= g
.VBox(False, 5)
191 self
.vbox
.pack_start(vbox
, True, True, 0)
192 vbox
.set_border_width(5)
193 self
.sizegroup
= g
.SizeGroup(g
.SIZE_GROUP_HORIZONTAL
)
196 hbox
= g
.HBox(False, 2)
197 vbox
.pack_start(hbox
, False, True, 0)
199 label
= g
.Label(name
)
200 self
.sizegroup
.add_widget(label
)
201 hbox
.pack_start(label
, False, True, 0)
202 hbox
.pack_start(entry
, True, True, 0)
203 entry
.set_text(history
.get(name
, ''))
205 history
[name
] = entry
.get_text()
206 entry
.connect('changed', changed
)
207 entry
.set_activates_default(True)
211 self
.replace_entry
= field(_('Replace:'))
212 self
.with_entry
= field(_('With:'))
217 self
.sizegroup
.add_widget(label
)
218 hbox
.pack_start(label
, False, False, 3)
219 self
.regex
= g
.CheckButton(_('Advanced search and replace'))
220 hbox
.pack_start(self
.regex
, False, False, 0)
221 vbox
.pack_start(hbox
, False, True, 0)
224 regex_help
= RegexHelp()
225 vbox
.pack_start(regex_help
, True, True, 0)
227 self
.python_with
= g
.CheckButton(_("Evaluate 'With' as Python expression"))
228 def changed(toggle
): history
['Python'] = toggle
.get_active()
229 vbox
.pack_start(self
.python_with
, False, True, 0)
230 self
.python_with
.set_active(history
.get('Python', False))
231 self
.python_with
.connect('toggled', changed
)
234 history
['Advanced'] = toggle
.get_active()
235 if toggle
.get_active():
237 self
.python_with
.show()
240 self
.python_with
.hide()
242 self
.regex
.connect('toggled', changed
)
243 self
.regex
.set_active(history
.get('Advanced', False))
245 def do_replace(self
, show_info
= True):
246 regex
= self
.regex
.get_active()
248 replace
= self
.replace_entry
.get_text()
250 rox
.alert(_('You need to specify something to search for...'))
252 with
= self
.with_entry
.get_text()
258 prog
= re
.compile(replace
)
260 rox
.report_exception()
262 python
= self
.python_with
.get_active()
265 code
= compile(with
, 'With', 'eval')
267 locals = {'old': match
.group(0)}
269 locals['x'] = float(locals['old'])
272 return str(eval(code
, locals))
274 rox
.report_exception()
277 new
, n
= prog
.subn(with
, line
)
283 new
= line
.replace(replace
, with
)
290 self
.edit_window
.process_selected(do_line
)
292 rox
.report_exception()
295 rox
.alert(_('Search string not found'))
299 rox
.info(_('One line changed'))
301 rox
.info(_('%d lines changed') % changes
[0])