import gtk import gedit #todo: these should be real options #todo: options to only draw leading/trailing stuff DRAW_TABS = True DRAW_SPACES = True def draw_tab_at_iter(view, event, iter): if not DRAW_TABS: return rect = view.get_iter_location(iter) x, y = view.buffer_to_window_coords (gtk.TEXT_WINDOW_TEXT, rect.x, rect.y + rect.height / 2) # should we use the insensitive color? no idea if it's a good guess event.window.draw_line(view.style.text_gc[gtk.STATE_NORMAL], x + 4, y, x + rect.width - 4, y) def draw_space_at_iter(view, event, iter): if not DRAW_SPACES: return rect = view.get_iter_location(iter) x, y = view.buffer_to_window_coords (gtk.TEXT_WINDOW_TEXT, rect.x + rect.width / 2, rect.y + rect.height / 2) event.window.draw_point(view.style.text_gc[gtk.STATE_NORMAL], x, y) def draw_tabs_and_spaces(view, event, start, end): i = start.copy(); while i.compare(end) < 0: if i.get_char() == '\t': draw_tab_at_iter (view, event, i) elif i.get_char() == ' ': draw_space_at_iter (view, event, i) if not i.forward_char(): break class DrawSpacesHelper(object): def expose_cb(self, view, event): if event.window == view.get_window(gtk.TEXT_WINDOW_TEXT): y = view.window_to_buffer_coords(gtk.TEXT_WINDOW_TEXT, event.area.x, event.area.y)[1] s = view.get_line_at_y(y)[0] e = view.get_line_at_y(y + event.area.height)[0] draw_tabs_and_spaces(view, event, s, e) def attach(self, view): self._view = view self.expose_id = view.connect('expose-event', self.expose_cb) def detach(self): self._view.disconnect(self.expose_id) class DrawSpacesPlugin(gedit.Plugin): def __init__(self): gedit.Plugin.__init__(self) def activate(self, window): for view in window.get_views(): self._create_view_helper(view) tab_added_id = window.connect("tab_added", lambda w, t: self._create_view_helper(t.get_view())) window.set_data("DrawSpacesPluginHandlerId", tab_added_id) def deactivate(self, window): tab_added_id = window.get_data("DrawSpacesPluginHandlerId") window.disconnect(tab_added_id) window.set_data("DrawSpacesPluginHandlerId", None) for view in window.get_views(): self._destroy_view_helper(view) def update_ui(self, window): pass def _create_view_helper(self, view): helper = DrawSpacesHelper() helper.attach(view) view.set_data("DrawSpacesHelper", helper) def _destroy_view_helper(self, view): helper = view.get_data("DrawSpacesHelper") helper.detach() view.set_data("DrawSpacesHelper", None)