Viewing file: modelines.py (8.58 KB) -rw-r--r-- Select action/file-type: (+) | (+) | (+) | Code (+) | Session (+) | (+) | SDB (+) | (+) | (+) | (+) | (+) | (+) |
# -*- coding: utf-8 -*- # modelines.py - Emacs, Kate and Vim-style modelines support for gedit. # # Copyright (C) 2005 - Steve Frécinaux # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2, or (at your option) # any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
import gedit import re import gtk import gconf
class ModelinePlugin(gedit.Plugin): def __init__(self): gedit.Plugin.__init__(self)
def connect_handlers(self, view): doc = view.get_buffer() loaded_id = doc.connect("loaded", apply_modeline, view) saved_id = doc.connect("saved", apply_modeline, view) doc.set_data("ModelinePluginHandlerIds", (loaded_id, saved_id)) def disconnect_handlers(self, view): doc = view.get_buffer() loaded_id, saved_id = doc.get_data("ModelinePluginHandlerIds") doc.disconnect(loaded_id) doc.disconnect(saved_id) doc.set_data("ModelinePluginHandlerIds", None) def activate(self, window): for view in window.get_views(): self.connect_handlers(view) apply_modeline(view.get_buffer(), None, view) tab_added_id = window.connect("tab_added", lambda w, t: self.connect_handlers(t.get_view())) window.set_data("ModelinePluginHandlerId", tab_added_id) def deactivate(self, window): tab_added_id = window.get_data("ModelinePluginHandlerId") window.disconnect(tab_added_id) window.set_data("ModelinePluginHandlerId", None) for view in window.get_views(): self.disconnect_handlers(view)
def apply_modeline(doc, error, view): if error is None: options = get_modeline_options(doc) apply_options(options, view)
def get_modeline_options(doc): options = dict()
# Search the two first lines for emacs- or vim-style modelines start = doc.get_start_iter() for i in (1, 2): end = start.copy() if not end.forward_to_line_end(): return options modeline = doc.get_text(start, end, False) options.update(parse_modeline_kate(modeline)) options.update(parse_modeline_vim(modeline)) options.update(parse_modeline_emacs(modeline)) start = end
# Vim can read modeline on the 3rd line end = start.copy() if not end.forward_to_line_end(): return options modeline = doc.get_text(start, end, False) options.update(parse_modeline_kate(modeline)) options.update(parse_modeline_vim(modeline)) start = end
# Kate reads modelines on the 10 first lines for i in (4, 5, 6, 7, 8, 9, 10): end = start.copy() if not end.forward_to_line_end(): break modeline = doc.get_text(start, end, False) options.update(parse_modeline_kate(modeline)) start = end
# Search the three last lines for vim- and kate-style modelines start = doc.get_end_iter() start.backward_lines(2) for i in (1, 2, 3): end = start.copy() if not end.forward_to_line_end(): return options modeline = doc.get_text(start, end, False) options.update(parse_modeline_kate(modeline)) options.update(parse_modeline_vim(modeline)) start = end
# Kate reads modelines on the 10 last lines start.backward_lines(9) for i in (4, 5, 6, 7, 8, 9, 10): end = start.copy() if not end.forward_to_line_end(): return options modeline = doc.get_text(start, end, False) options.update(parse_modeline_kate(modeline)) start = end return options
def parse_modeline_vim(line): # First form modeline # [text]{white}{vi:|vim:|ex:}[white]{options} # # Second form # [text]{white}{vi:|vim:|ex:}[white]se[t] {options}:[text]
# Find the modeline for i in ('ex:', 'vi:', 'vim:'): start = line.find(i) if start != -1: start = start + len(i) break else: return {} if line[start : start + 2] == "se": end = line.find(":", start + 3) if end == -1: return {} elif line[start + 2] == 't': line = line[start + 4 : end] else: line = line[start + 3 : end] else: line = line[start :] # Get every individual directives directives = [x for x in re.split(r'[: ]', line) if x != ''] options = dict(); for directive in directives: # Reformat the directive if (directive.find("=") != -1): name, value = directive.split("=") elif directive[0:2] == "no": value = False name = directive[2:] else: value = True name = directive # Set the options according to the directive if name == "et" or name == "expandtab": options["use-tabs"] = not value elif name == "ts" or name == "tabstop": options["tabs-width"] = int(value) elif name == "wrap": options["wrapping"] = value elif name == "textwidth": options["margin"] = int(value) return options
def parse_modeline_emacs(line): # cf. http://www.delorie.com/gnu/docs/emacs/emacs_486.html # Extract the modeline from the given line start = line.find("-*-") if start == -1: return {} else: start = start + 3 end = line.find("-*-", start) if end == -1: return {} # Get every individual directives directives = [x for x in [i.strip() for i in line[start : end].split(";")] if x != ''] options = dict() for directive in directives: name, value = ([i.strip() for i in directive.split(":", 1)] + [None])[0:2] if name == "tab-width": options["tabs-width"] = int(value) elif name == "indent-tabs-mode": options["use-tabs"] = value != "nil" elif name == "autowrap": options["wrapping"] = value != "nil" return options
def parse_modeline_kate(line): # cf. http://wiki.kate-editor.org/index.php/Modelines
# Extract the modeline from the given line start = line.find("kate:") if start == -1: return {} else: start = start + 5 end = line.rfind(";") if end == -1: return {} # Get every individual directives directives = [x for x in [i.strip() for i in line[start : end].split(";")] if x != ''] options = dict() for directive in directives: name, value = ([i.strip() for i in directive.split(None, 1)] + [None])[0:2] if name == "tab-width" or name == "indent-width": options["tabs-width"] = int(value) elif name == "space-indent": options["use-tabs"] = value not in ("on", "true", "1") elif name == "word-wrap": options["wrapping"] = value in ("on", "true", "1") elif name == "word-wrap-column": options["margin"] = int(value) return options
def apply_options(options, view): old_options = view.get_data("ModelineOptions")
if not old_options: old_options = {} if not options: options = {}
if options.has_key("tabs-width"): view.set_tabs_width(options["tabs-width"]) elif old_options.has_key("tabs-width"): view.set_tabs_width(gconf_get_int("/apps/gedit-2/preferences/editor/tabs/tabs_size", 8)) if options.has_key("use-tabs"): view.set_insert_spaces_instead_of_tabs(not options["use-tabs"]) elif old_options.has_key("use-tabs"): view.set_insert_spaces_instead_of_tabs(gconf_get_bool("/apps/gedit-2/preferences/editor/tabs/insert_spaces", False))
if options.has_key("wrapping"): if options["wrapping"]: view.set_wrap_mode(gtk.WRAP_WORD) else: view.set_wrap_mode(gtk.WRAP_NONE) elif old_options.has_key("wrapping"): wrap_mode = gconf_get_str("/apps/gedit-2/preferences/editor/wrap_mode/wrap_mode", "GTK_WRAP_WORD") if wrap_mode == "GTK_WRAP_WORD": view.set_wrap_mode(gtk.WRAP_WORD) else: view.set_wrap_mode(gtk.WRAP_NONE)
if options.has_key("margin"): if options["margin"] > 0: view.set_margin(long(options["margin"])) view.set_show_margin(True) else: view.set_show_margin(False) elif old_options.has_key("margin"): view.set_margin(long(gconf_get_int("/apps/gedit-2/preferences/editor/right_margin/right_margin_position", 80))) view.set_show_margin(gconf_get_bool("/apps/gedit-2/preferences/editor/right_margin/display_right_margin", False))
view.set_data("ModelineOptions", options)
gconf_client = gconf.client_get_default() def gconf_get_bool(key, default = False): val = gconf_client.get(key) if val is not None and val.type == gconf.VALUE_BOOL: return val.get_bool() else: return default
def gconf_get_str(key, default = ""): val = gconf_client.get(key) if val is not None and val.type == gconf.VALUE_STRING: return val.get_string() else: return default
def gconf_get_int(key, default = 0): val = gconf_client.get(key) if val is not None and val.type == gconf.VALUE_INT: return val.get_int() else: return default
# ex:ts=8:noet: # kate: word-wrap-column 120;
|