3 from rox
import g
, filer
, app_options
, mime
5 from rox
.loading
import XDSLoader
6 from rox
.options
import Option
7 from rox
import OptionsBox
8 from rox
.saving
import Saveable
13 # WARNING: This is a temporary hack, until we write a way choose between
14 # the two ways of doing toolbars or we abandon the old method entirely
16 warnings
.filterwarnings('ignore', category
=DeprecationWarning,
20 def optional_section(available
):
21 """If requires is None, the section is enabled. Otherwise,
22 the section is shaded and the requires message is shown at
25 def build_enabled_section(box
, node
, label
):
26 return box
.do_box(node
, None, g
.VBox(False, 0))
27 return build_enabled_section
29 def build_disabled_section(box
, node
, label
):
30 assert label
is not None
31 box
, = box
.do_box(node
, None, g
.VBox(False, 0))
32 box
.set_sensitive(False)
33 frame
= g
.Frame(label
)
34 box
.set_border_width(4)
37 return build_disabled_section
45 to_utf8
= codecs
.getencoder('utf-8')
47 from buffer import Buffer
, have_sourceview
48 from rox
.Menu
import Menu
, set_save_name
, SubMenu
, Separator
, Action
, ToggleItem
50 OptionsBox
.widget_registry
['source-view-only'] = optional_section(have_sourceview
)
52 default_font
= Option('default_font', 'serif')
54 background_colour
= Option('background', '#fff')
55 foreground_colour
= Option('foreground', '#000')
57 auto_indent
= Option('autoindent', '1')
58 word_wrap
= Option('wordwrap', '1')
60 layout_left_margin
= Option('layout_left_margin', 2)
61 layout_right_margin
= Option('layout_right_margin', 4)
63 layout_before_para
= Option('layout_before_para', 0)
64 layout_after_para
= Option('layout_after_para', 0)
65 layout_inside_para
= Option('layout_inside_para', 0)
66 layout_indent_para
= Option('layout_indent_para', 2)
68 right_margin
= Option('right_margin', 80)
69 show_margin
= Option('show_margin', True)
70 smart_home_end
= Option('smart_home_end', True)
71 show_line_numbers
= Option('show_line_numbers', True)
72 show_line_markers
= Option('show_line_markers', True)
73 tab_width
= Option('tab_width', 4)
74 use_spaces_for_tabs
= Option('use_spaces_for_tabs', False)
76 show_toolbar
= Option('show_toolbar', 1)
78 set_save_name('Edit', site
='rox.sourceforge.net')
81 Action(_('Cut'), 'cut', '<Ctrl>X', g
.STOCK_CUT
),
82 Action(_('Copy'), 'copy', '<Ctrl>C', g
.STOCK_COPY
),
83 Action(_('Paste'), 'paste', '<Ctrl>V', g
.STOCK_PASTE
),
85 Action(_('Undo'), 'undo', '<Ctrl>Z', g
.STOCK_UNDO
),
86 Action(_('Redo'), 'redo', '<Ctrl>Y', g
.STOCK_REDO
),
88 Action(_('Search...'), 'search', 'F4', g
.STOCK_FIND
),
89 Action(_('Search and Replace....'), 'search_replace',
90 '<Ctrl>F4', g
.STOCK_FIND_AND_REPLACE
),
91 Action(_('Goto line...'), 'goto', 'F5', g
.STOCK_JUMP_TO
),
96 Action(_('Toggle Bookmark'), 'toggle_bookmark', '<Ctrl>F2'),
97 Action(_('Next Bookmark'), 'next_bookmark', 'F2'),
98 Action(_('Previous Bookmark'), 'prev_bookmark', '<Shift>F2'),
102 edit_menu
+= bookmark_menu
104 menu
= Menu('main', [
106 Action(_('Save'), 'save', '<Ctrl>S', g
.STOCK_SAVE
),
107 Action(_('Save As...'), 'save_as', '', g
.STOCK_SAVE_AS
),
108 Action(_('Open Parent'), 'up', '', g
.STOCK_GO_UP
),
109 Action(_('Show Changes'), 'diff', '', 'rox-diff'),
110 ToggleItem(_('Word Wrap'), 'word_wrap'),
111 Action(_('Close'), 'close', '', g
.STOCK_CLOSE
),
113 Action(_('New'), 'new', '', g
.STOCK_NEW
)]),
115 SubMenu(_('Edit'), edit_menu
),
117 Action(_('Options'), 'show_options', '', g
.STOCK_PROPERTIES
),
118 Action(_('Help'), 'help', 'F1', g
.STOCK_HELP
),
122 "iso8859_1", "iso8859_2", "iso8859_3", "iso8859_4", "iso8859_5",
123 "iso8859_6", "iso8859_7", "iso8859_8", "iso8859_9", "iso8859_10",
124 "iso8859_13", "iso8859_14", "iso8859_15",
125 "ascii", "base64_codec", "charmap",
126 "cp037", "cp1006", "cp1026", "cp1140", "cp1250", "cp1251", "cp1252",
127 "cp1253", "cp1254", "cp1255", "cp1256", "cp1257", "cp1258", "cp424",
128 "cp437", "cp500", "cp737", "cp775", "cp850", "cp852", "cp855", "cp856",
129 "cp857", "cp860", "cp861", "cp862", "cp863", "cp864", "cp865", "cp866",
130 "cp869", "cp874", "cp875", "hex_codec",
133 "mac_cyrillic", "mac_greek", "mac_iceland", "mac_latin2", "mac_roman", "mac_turkish",
134 "mbcs", "quopri_codec", "raw_unicode_escape",
136 "utf_16_be", "utf_16_le", "utf_16", "utf_7", "utf_8", "uu_codec",
140 class Abort(Exception):
145 """Called when the minibuffer is opened."""
147 def key_press(self
, kev
):
148 """A keypress event in the minibuffer text entry."""
151 """The minibuffer text has changed."""
154 """Return or Enter pressed."""
156 info
= 'Press Escape to close the minibuffer.'
158 class DiffLoader(XDSLoader
):
159 def __init__(self
, window
):
160 XDSLoader
.__init
__(self
, ['text/plain'])
163 def xds_load_from_file(self
, path
):
164 self
.window
.diff(path
= path
)
166 def xds_load_from_stream(self
, name
, type, stream
):
167 tmp
= diff
.Tmp(suffix
= '-' + (name
or 'tmp'))
169 shutil
.copyfileobj(stream
, tmp
)
171 self
.window
.diff(path
= tmp
.name
)
173 class EditWindow(rox
.Window
, XDSLoader
, Saveable
):
177 def __init__(self
, filename
= None, show
= True, line_number
= None):
178 rox
.Window
.__init
__(self
)
179 XDSLoader
.__init
__(self
, ['text/plain', 'UTF8_STRING'])
180 self
.set_default_size(g
.gdk
.screen_width() * 2 / 3,
181 g
.gdk
.screen_height() / 2)
187 app_options
.add_notify(self
.update_styles
)
192 self
.uri
= os
.path
.abspath(filename
)
193 self
.mime_type
= mime
.get_type(self
.uri
, 1)
196 self
.mime_type
= mime
.lookup('text', 'plain')
198 self
.buffer = Buffer()
202 self
.text
= gtksourceview
.SourceView(self
.buffer)
203 pixbuf
= g
.gdk
.pixbuf_new_from_file(rox
.app_dir
+"/images/marker.png")
204 self
.text
.set_marker_pixbuf("bookmark", pixbuf
)
206 self
.buffer.set_type(self
.mime_type
)
208 self
.text
= g
.TextView()
209 self
.text
.set_buffer(self
.buffer)
211 self
.text
.set_size_request(10, 10)
212 self
.xds_proxy_for(self
.text
)
214 self
.insert_mark
= self
.buffer.get_mark('insert')
215 self
.selection_bound_mark
= self
.buffer.get_mark('selection_bound')
216 start
= self
.buffer.get_start_iter()
217 self
.mark_start
= self
.buffer.create_mark('mark_start', start
, True)
218 self
.mark_end
= self
.buffer.create_mark('mark_end', start
, False)
219 self
.mark_tmp
= self
.buffer.create_mark('mark_tmp', start
, False)
220 tag
= self
.buffer.create_tag('marked')
221 tag
.set_property('background', 'green')
224 # When searching, this is where the cursor was when the minibuffer
226 start
= self
.buffer.get_start_iter()
227 self
.search_base
= self
.buffer.create_mark('search_base', start
, True)
233 tools
.set_style(g
.TOOLBAR_ICONS
)
234 vbox
.pack_start(tools
, False, True, 0)
236 self
.status_label
= g
.Label('')
237 tools
.append_widget(self
.status_label
, None, None)
238 tools
.insert_stock(g
.STOCK_HELP
, _('Help'), None, self
.help, None, 0)
239 diff
= tools
.insert_stock('rox-diff', _('Show changes from saved copy.\n'
240 'Or, drop a backup file onto this button to see changes from that.'),
241 None, self
.diff
, None, 0)
242 DiffLoader(self
).xds_proxy_for(diff
)
246 image_spell
= g
.Image()
247 image_spell
.set_from_stock(g
.STOCK_SPELL_CHECK
, tools
.get_icon_size())
248 self
.spell_button
= tools
.insert_element(g
.TOOLBAR_CHILD_TOGGLEBUTTON
,
249 None, _("Check Spelling"), _("Check Spelling"), None,
250 image_spell
, self
.toggle_spell
, None, 0)
252 image_wrap
= g
.Image()
253 image_wrap
.set_from_file(rox
.app_dir
+ '/images/rox-word-wrap.png')
254 self
.wrap_button
= tools
.insert_element(g
.TOOLBAR_CHILD_TOGGLEBUTTON
,
255 None, _("Word Wrap"), _("Word Wrap"), None, image_wrap
,
256 lambda button
: self
.set_word_wrap(button
.get_active()),
258 tools
.insert_stock(g
.STOCK_REDO
, _('Redo'), None, self
.redo
, None, 0)
259 tools
.insert_stock(g
.STOCK_UNDO
, _('Undo'), None, self
.undo
, None, 0)
260 tools
.insert_stock(g
.STOCK_FIND_AND_REPLACE
, _('Replace'), None, self
.search_replace
, None, 0)
261 tools
.insert_stock(g
.STOCK_FIND
, _('Search'), None, self
.search
, None, 0)
262 tools
.insert_stock(g
.STOCK_SAVE_AS
, _('Save As'), None, self
.save_as
, None, 0)
263 self
.save_button
= tools
.insert_stock(g
.STOCK_SAVE
, _('Save'), None, self
.save
, None, 0)
264 tools
.insert_stock(g
.STOCK_GO_UP
, _('Up'), None, self
.up
, None, 0)
265 tools
.insert_stock(g
.STOCK_CLOSE
, _('Close'), None, self
.close
, None, 0)
266 # Set minimum size to ignore the label
267 tools
.set_size_request(tools
.size_request()[0], -1)
271 swin
= g
.ScrolledWindow()
272 swin
.set_policy(g
.POLICY_AUTOMATIC
, g
.POLICY_AUTOMATIC
)
273 vbox
.pack_start(swin
, True, True)
283 # Create the minibuffer
284 self
.mini_hbox
= g
.HBox(False)
286 info
= rox
.ButtonMixed(g
.STOCK_DIALOG_INFO
, '')
287 info
.set_relief(g
.RELIEF_NONE
)
288 info
.unset_flags(g
.CAN_FOCUS
)
289 info
.connect('clicked', self
.mini_show_info
)
291 close
= rox
.ButtonMixed(g
.STOCK_STOP
, '')
292 close
.set_relief(g
.RELIEF_NONE
)
293 close
.unset_flags(g
.CAN_FOCUS
)
294 close
.connect('clicked', lambda e
: self
.set_minibuffer(None))
296 self
.mini_hbox
.pack_end(info
, False, True, 0)
297 self
.mini_hbox
.pack_start(close
, False, True, 0)
298 self
.mini_label
= g
.Label('')
299 self
.mini_hbox
.pack_start(self
.mini_label
, False, True, 0)
300 self
.mini_entry
= g
.Entry()
301 self
.mini_hbox
.pack_start(self
.mini_entry
, True, True, 0)
302 vbox
.pack_start(self
.mini_hbox
, False, True)
303 self
.mini_entry
.connect('key-press-event', self
.mini_key_press
)
304 self
.mini_entry
.connect('changed', self
.mini_changed
)
306 self
.connect('destroy', self
.destroyed
)
308 self
.connect('delete-event', self
.delete_event
)
309 self
.text
.grab_focus()
310 self
.text
.connect('key-press-event', self
.key_press
)
312 # FIXME: why does this freeze Edit?
314 #if self.mime_type.media == 'text' and self.mime_type.subtype == 'plain':
316 ##self.spell.set_language ("en_US")
318 def update_current_line(*unused
):
319 cursor
= self
.buffer.get_iter_at_mark(self
.insert_mark
)
320 bound
= self
.buffer.get_iter_at_mark(self
.selection_bound_mark
)
321 if cursor
.compare(bound
) == 0:
322 n_lines
= self
.buffer.get_line_count()
323 self
.status_label
.set_text(_('Line %s of %d') % (cursor
.get_line() + 1, n_lines
))
325 n_lines
= abs(cursor
.get_line() - bound
.get_line()) + 1
327 n_chars
= abs(cursor
.get_line_offset() - bound
.get_line_offset())
329 bytes
= to_utf8(self
.buffer.get_text(cursor
, bound
, False))[0]
330 self
.status_label
.set_text(_('One character selected (%s)') %
331 ' '.join(map(lambda x
: '0x%2x' % ord(x
), bytes
)))
333 self
.status_label
.set_text(_('%d characters selected') % n_chars
)
335 self
.status_label
.set_text(_('%d lines selected') % n_lines
)
336 self
.buffer.connect('mark-set', update_current_line
)
337 self
.buffer.connect('changed', update_current_line
)
340 # Loading might take a while, so get something on the screen
346 self
.load_file(filename
)
348 self
.save_last_stat
= os
.stat(filename
)
353 self
.buffer.connect('modified-changed', self
.update_title
)
354 self
.buffer.set_modified(False)
356 def button_press(text
, event
):
357 if event
.button
!= 3:
359 menu
.popup(self
, event
)
361 self
.text
.connect('button-press-event', button_press
)
362 self
.text
.connect('popup-menu', lambda text
: menu
.popup(self
, None))
364 menu
.attach(self
, self
)
365 self
.buffer.place_cursor(self
.buffer.get_start_iter())
366 self
.buffer.start_undo_history()
369 iter = self
.buffer.get_iter_at_line(int(line_number
) - 1)
370 self
.buffer.place_cursor(iter)
371 self
.text
.scroll_to_mark(self
.insert_mark
, 0.05, False)
373 def key_press(self
, text
, kev
):
374 if kev
.keyval
== g
.keysyms
.Return
or kev
.keyval
== g
.keysyms
.KP_Enter
:
375 return self
.auto_indent()
376 elif kev
.keyval
== g
.keysyms
.Tab
or kev
.keyval
== g
.keysyms
.KP_Tab
:
377 return self
.indent_block()
378 elif kev
.keyval
== g
.keysyms
.ISO_Left_Tab
:
379 return self
.unindent_block()
381 def auto_indent(self
):
382 if not auto_indent
.int_value
:
385 start
= self
.buffer.get_iter_at_mark(self
.insert_mark
)
387 start
.set_line_offset(0)
388 end
.forward_to_line_end()
389 line
= self
.buffer.get_text(start
, end
, False)
392 if self
.mime_type
.subtype
== 'x-python':
394 l
= line
.split('\n')[0]
397 if l
.endswith(':') and not l
.startswith('#'):
398 if use_spaces_for_tabs
.int_value
:
399 for i
in tab_width
.int_value
:
403 elif have_sourceview
:
412 self
.buffer.begin_user_action()
413 self
.buffer.insert_at_cursor('\n' + indent
)
414 self
.buffer.end_user_action()
417 def indent_block(self
):
419 (start
, end
) = self
.buffer.get_selection_bounds()
420 start_line
= start
.get_line()
421 end_line
= end
.get_line()
422 self
.buffer.begin_user_action()
423 for i
in range(start_line
, end_line
+1):
424 iter = self
.buffer.get_iter_at_line(i
)
425 self
.buffer.insert(iter, '\t')
426 self
.buffer.end_user_action()
431 def unindent_block(self
):
433 (start
, end
) = self
.buffer.get_selection_bounds()
434 start_line
= start
.get_line()
435 end_line
= end
.get_line()
436 self
.buffer.begin_user_action()
437 for i
in range(start_line
, end_line
+1):
438 iter = self
.buffer.get_iter_at_line(i
)
439 if iter.get_char() == '\t':
440 next_char
= iter.copy()
441 next_char
.forward_char()
442 self
.buffer.delete(iter, next_char
)
443 self
.buffer.end_user_action()
448 def destroyed(self
, widget
):
449 app_options
.remove_notify(self
.update_styles
)
451 def update_styles(self
):
454 font
= pango
.FontDescription(default_font
.value
)
455 bg
= g
.gdk
.color_parse(background_colour
.value
)
456 fg
= g
.gdk
.color_parse(foreground_colour
.value
)
458 self
.text
.set_left_margin(layout_left_margin
.int_value
)
459 self
.text
.set_right_margin(layout_right_margin
.int_value
)
461 self
.text
.set_pixels_above_lines(layout_before_para
.int_value
)
462 self
.text
.set_pixels_below_lines(layout_after_para
.int_value
)
463 self
.text
.set_pixels_inside_wrap(layout_inside_para
.int_value
)
464 self
.text
.set_indent(layout_indent_para
.int_value
)
466 self
.word_wrap
= bool(word_wrap
.int_value
)
468 if show_toolbar
.int_value
:
473 rox
.report_exception()
475 self
.text
.modify_font(font
)
476 self
.text
.modify_base(g
.STATE_NORMAL
, bg
)
477 self
.text
.modify_text(g
.STATE_NORMAL
, fg
)
480 self
.text
.set_show_line_numbers(show_line_numbers
.int_value
)
481 self
.text
.set_show_line_markers(show_line_markers
.int_value
)
482 self
.text
.set_auto_indent(auto_indent
.int_value
)
483 self
.text
.set_tabs_width(tab_width
.int_value
)
484 self
.text
.set_insert_spaces_instead_of_tabs(use_spaces_for_tabs
.int_value
)
485 self
.text
.set_margin(right_margin
.int_value
)
486 self
.text
.set_show_margin(show_margin
.int_value
)
487 self
.text
.set_smart_home_end(smart_home_end
.int_value
)
488 if self
.buffer.language
== 'Python':
489 self
.text
.set_auto_indent(False)
491 def cut(self
): self
.text
.emit('cut_clipboard')
492 def copy(self
): self
.text
.emit('copy_clipboard')
493 def paste(self
): self
.text
.emit('paste_clipboard')
495 def delete_event(self
, window
, event
):
496 if self
.buffer.get_modified():
497 self
.save_as(discard
= 1)
501 def update_title(self
, *unused
):
502 title
= self
.uri
or '<'+_('Untitled')+'>'
503 if self
.buffer.get_modified():
505 self
.save_button
.set_sensitive(True)
507 self
.save_button
.set_sensitive(False)
508 self
.set_title(title
)
510 def xds_load_from_stream(self
, name
, t
, stream
):
511 if t
== 'UTF8_STRING':
512 return # Gtk will handle it
514 self
.insert_data(stream
.read())
518 def get_encoding(self
, message
):
519 "Returns (encoding, errors), or raises Abort to cancel."
520 box
= g
.MessageDialog(self
, 0, g
.MESSAGE_QUESTION
, g
.BUTTONS_CANCEL
, message
)
521 box
.set_has_separator(False)
524 box
.vbox
.pack_start(frame
, True, True)
525 frame
.set_border_width(6)
527 hbox
= g
.HBox(False, 4)
528 hbox
.set_border_width(6)
530 hbox
.pack_start(g
.Label(_('Encoding:')), False, True, 0)
532 combo
.disable_activate()
533 combo
.entry
.connect('activate', lambda w
: box
.activate_default())
534 combo
.set_popdown_strings(known_codecs
)
535 hbox
.pack_start(combo
, True, True, 0)
536 ignore_errors
= g
.CheckButton(_('Ignore errors'))
537 hbox
.pack_start(ignore_errors
, False, True)
542 box
.add_button(g
.STOCK_CONVERT
, g
.RESPONSE_YES
)
543 box
.set_default_response(g
.RESPONSE_YES
)
546 combo
.entry
.grab_focus()
549 if resp
!= g
.RESPONSE_YES
:
553 if ignore_errors
.get_active():
557 encoding
= combo
.entry
.get_text()
559 codecs
.getdecoder(encoding
)
562 rox
.alert(_("Unknown encoding '%s'") % encoding
)
566 return encoding
, errors
568 def insert_data(self
, data
):
573 decoder
= codecs
.getdecoder(encoding
)
575 data
= decoder(data
, errors
)[0]
576 if errors
== 'strict':
577 assert '\0' not in data
580 data
= data
.replace('\0', '\\0')
585 encoding
, errors
= self
.get_encoding(
586 _("Data is not valid %s. Please select the file's encoding. "
587 "Turn on 'ignore errors' to try and load it anyway.")
590 self
.buffer.begin_user_action()
591 self
.buffer.insert_at_cursor(data
)
592 self
.buffer.end_user_action()
595 def load_file(self
, path
):
600 file = open(path
, 'r')
601 contents
= file.read()
605 self
.buffer.begin_not_undoable_action()
606 self
.insert_data(contents
)
607 self
.buffer.end_not_undoable_action()
611 rox
.report_exception()
614 def close(self
, button
= None):
615 if self
.buffer.get_modified():
616 self
.save_as(discard
= 1)
623 def up(self
, button
= None):
625 filer
.show_file(self
.uri
)
627 rox
.alert(_('File is not saved to disk yet'))
630 def toggle_spell(self
, button
= None):
634 self
.spell_button
.set_active(False)
637 self
.spell
= gtkspell
.Spell(self
.text
)
638 self
.spell_button
.set_active(True)
641 self
.spell_button
.set_active(False)
643 #self.spell_button.set_active(self.spell != None)
645 def diff(self
, button
= None, path
= None):
646 path
= path
or self
.uri
648 rox
.alert(_('This file has never been saved; nothing to compare it to!\n'
649 'Note: you can drop a file onto the toolbar button to see '
650 'the changes from that file.'))
652 diff
.show_diff(path
, self
.save_to_stream
)
654 def has_selection(self
):
655 s
, e
= self
.get_selection_range()
656 return not e
.equal(s
)
658 def get_marked_range(self
):
659 s
= self
.buffer.get_iter_at_mark(self
.mark_start
)
660 e
= self
.buffer.get_iter_at_mark(self
.mark_end
)
665 def get_selection_range(self
):
666 s
= self
.buffer.get_iter_at_mark(self
.insert_mark
)
667 e
= self
.buffer.get_iter_at_mark(self
.selection_bound_mark
)
672 def save(self
, widget
= None):
674 self
.save_to_file(self
.uri
)
675 self
.buffer.set_modified(False)
677 self
.save_as(discard
=0)
679 def save_as(self
, widget
= None, discard
= 0):
680 from rox
.saving
import SaveBox
683 self
.savebox
.destroy()
686 self
.mime_type
= mime
.get_type(self
.uri
, 1)
688 self
.mime_type
= mime
.lookup('text', 'plain')
690 mime_text
= self
.mime_type
.media
+ '/' + self
.mime_type
.subtype
692 if self
.has_selection() and not discard
:
693 saver
= SelectionSaver(self
)
694 self
.savebox
= SaveBox(saver
, 'Selection', mime_text
)
695 self
.savebox
.connect('destroy', lambda w
: saver
.destroy())
697 uri
= self
.uri
or _('TextFile')
698 self
.savebox
= SaveBox(self
, uri
, mime_text
, discard
)
701 def help(self
, button
= None):
702 filer
.open_dir(os
.path
.join(rox
.app_dir
, 'Help'))
704 def save_to_stream(self
, stream
):
705 s
= self
.buffer.get_start_iter()
706 e
= self
.buffer.get_end_iter()
707 stream
.write(self
.buffer.get_text(s
, e
, True))
709 def set_uri(self
, uri
):
711 self
.buffer.set_modified(False)
717 def change_font(self
):
718 style
= self
.text
.get_style().copy()
719 style
.font
= load_font(options
.get('edit_font'))
720 self
.text
.set_style(style
)
722 def show_options(self
):
725 def set_marked(self
, start
= None, end
= None):
726 "Set the marked region (from the selection if no region is given)."
728 assert not self
.marked
735 start
, end
= self
.get_selection_range()
736 buffer.move_mark(self
.mark_start
, start
)
737 buffer.move_mark(self
.mark_end
, end
)
738 buffer.apply_tag_by_name('marked',
739 buffer.get_iter_at_mark(self
.mark_start
),
740 buffer.get_iter_at_mark(self
.mark_end
))
743 def clear_marked(self
):
748 buffer.remove_tag_by_name('marked',
749 buffer.get_iter_at_mark(self
.mark_start
),
750 buffer.get_iter_at_mark(self
.mark_end
))
752 def undo(self
, widget
= None):
754 cursor
= self
.buffer.get_iter_at_mark(self
.insert_mark
)
755 self
.text
.scroll_to_iter(cursor
, 0.05, False)
757 def redo(self
, widget
= None):
759 cursor
= self
.buffer.get_iter_at_mark(self
.insert_mark
)
760 self
.text
.scroll_to_iter(cursor
, 0.05, False)
762 def goto(self
, widget
= None):
763 from goto
import Goto
764 self
.set_minibuffer(Goto())
766 def search(self
, widget
= None):
767 from search
import Search
768 self
.set_minibuffer(Search())
770 def search_replace(self
, widget
= None):
771 from search
import Replace
774 def toggle_bookmark(self
):
775 cursor
= self
.buffer.get_iter_at_mark(self
.insert_mark
)
776 name
= str(cursor
.get_line())
777 marker
= self
.buffer.get_marker(name
)
779 self
.buffer.delete_marker(marker
);
781 marker
= self
.buffer.create_marker(name
, "bookmark", cursor
);
783 def next_bookmark(self
):
784 cursor
= self
.buffer.get_iter_at_mark(self
.insert_mark
)
785 cursor
.forward_char()
786 marker
= self
.buffer.get_next_marker(cursor
)
788 self
.buffer.get_iter_at_marker (cursor
, marker
)
789 self
.buffer.place_cursor(cursor
)
790 self
.text
.scroll_to_iter(cursor
, 0.05, False)
792 def prev_bookmark(self
):
793 cursor
= self
.buffer.get_iter_at_mark(self
.insert_mark
)
794 cursor
.backward_char()
795 marker
= self
.buffer.get_prev_marker(cursor
)
797 self
.buffer.get_iter_at_marker (cursor
, marker
)
798 self
.buffer.place_cursor(cursor
)
799 self
.text
.scroll_to_iter(cursor
, 0.05, False)
801 def set_mini_label(self
, label
):
802 self
.mini_label
.set_text(label
)
804 def set_minibuffer(self
, minibuffer
):
805 assert minibuffer
is None or isinstance(minibuffer
, Minibuffer
)
808 self
.minibuffer
.close()
812 self
.minibuffer
= None
815 self
.mini_entry
.set_text('')
816 self
.minibuffer
= minibuffer
817 minibuffer
.setup(self
)
818 self
.mini_entry
.grab_focus()
819 self
.mini_hbox
.show_all()
821 self
.mini_hbox
.hide()
822 self
.text
.grab_focus()
824 def mini_key_press(self
, entry
, kev
):
825 if kev
.keyval
== g
.keysyms
.Escape
:
826 self
.set_minibuffer(None)
828 if kev
.keyval
== g
.keysyms
.Return
or kev
.keyval
== g
.keysyms
.KP_Enter
:
829 self
.minibuffer
.activate()
832 return self
.minibuffer
.key_press(kev
)
834 def mini_changed(self
, entry
):
835 if not self
.minibuffer
:
837 self
.minibuffer
.changed()
839 def mini_show_info(self
, *unused
):
840 assert self
.minibuffer
842 self
.info_box
.destroy()
843 self
.info_box
= g
.MessageDialog(self
, 0, g
.MESSAGE_INFO
, g
.BUTTONS_OK
,
844 self
.minibuffer
.info
)
845 self
.info_box
.set_title(_('Minibuffer help'))
848 self
.info_box
.connect('destroy', destroy
)
850 self
.info_box
.connect('response', lambda w
, r
: w
.destroy())
852 def process_selected(self
, process
):
853 """Calls process(line) on each line in the selection, or each line in the file
854 if there is no selection. If the result is not None, the text is replaced."""
855 self
.buffer.begin_user_action()
857 self
._process
_selected
(process
)
859 self
.buffer.end_user_action()
861 def _process_selected(self
, process
):
862 if self
.has_selection():
864 start
, end
= self
.get_selection_range()
865 if start
.compare(end
) > 0:
868 start
, end
= self
.get_selection_range()
869 if start
.compare(end
) > 0:
873 return self
.buffer.get_end_iter()
874 start
= self
.buffer.get_start_iter()
877 while start
.compare(end
) <= 0:
878 line_end
= start
.copy()
879 line_end
.forward_to_line_end()
880 if line_end
.compare(end
) >= 0:
882 line
= self
.buffer.get_text(start
, line_end
, False)
885 self
.buffer.move_mark(self
.mark_tmp
, start
)
886 self
.buffer.insert(line_end
, new
)
887 start
= self
.buffer.get_iter_at_mark(self
.mark_tmp
)
888 line_end
= start
.copy()
889 line_end
.forward_chars(len(line
.decode('utf-8')))
890 self
.buffer.delete(start
, line_end
)
892 start
= self
.buffer.get_iter_at_mark(self
.mark_tmp
)
894 if not start
.forward_line(): break
896 def set_word_wrap(self
, value
):
897 self
._word
_wrap
= value
898 self
.wrap_button
.set_active(value
)
900 self
.text
.set_wrap_mode(g
.WRAP_WORD
)
902 self
.text
.set_wrap_mode(g
.WRAP_NONE
)
904 word_wrap
= property(lambda self
: self
._word
_wrap
, set_word_wrap
)
906 class SelectionSaver(Saveable
):
907 def __init__(self
, window
):
911 def save_to_stream(self
, stream
):
912 s
, e
= self
.window
.get_marked_range()
913 stream
.write(self
.window
.buffer.get_text(s
, e
, True))
916 # Called when savebox is remove. Get rid of the selection marker
917 self
.window
.clear_marked()