home *** CD-ROM | disk | FTP | other *** search
/ Mac Easy 2010 May / Mac Life Ubuntu.iso / casper / filesystem.squashfs / usr / lib / gedit-2 / plugins / snippets / Library.py < prev    next >
Encoding:
Python Source  |  2009-04-14  |  37.7 KB  |  990 lines

  1. #    Gedit snippets plugin
  2. #    Copyright (C) 2005-2006  Jesse van den Kieboom <jesse@icecrew.nl>
  3. #
  4. #    This program is free software; you can redistribute it and/or modify
  5. #    it under the terms of the GNU General Public License as published by
  6. #    the Free Software Foundation; either version 2 of the License, or
  7. #    (at your option) any later version.
  8. #
  9. #    This program is distributed in the hope that it will be useful,
  10. #    but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. #    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  12. #    GNU General Public License for more details.
  13. #
  14. #    You should have received a copy of the GNU General Public License
  15. #    along with this program; if not, write to the Free Software
  16. #    Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
  17.  
  18. import os
  19. import weakref
  20. import sys
  21. import tempfile
  22. import re
  23.  
  24. import gtk
  25.  
  26. import ElementTree as et
  27. from Helper import *
  28.  
  29. class NamespacedId:
  30.         def __init__(self, namespace, id):
  31.                 if not id:
  32.                         self.id = None
  33.                 else:
  34.                         if namespace:
  35.                                 self.id = namespace + '-'
  36.                         else:
  37.                                 self.id = 'global-'
  38.                 
  39.                         self.id += id
  40.  
  41. class SnippetData:
  42.         PROPS = {'tag': '', 'text': '', 'description': 'New snippet', 
  43.                         'accelerator': '', 'drop-targets': ''}
  44.  
  45.         def __init__(self, node, library):
  46.                 self.priv_id = node.attrib.get('id')
  47.  
  48.                 self.set_library(library)
  49.                 self.valid = False
  50.                 self.set_node(node)
  51.  
  52.         def can_modify(self):
  53.                 return (self.library and (isinstance(self.library(), SnippetsUserFile)))
  54.  
  55.         def set_library(self, library):
  56.                 if library:
  57.                         self.library = weakref.ref(library)
  58.                 else:
  59.                         self.library = None
  60.  
  61.                 self.id = NamespacedId(self.language(), self.priv_id).id
  62.  
  63.         def set_node(self, node):
  64.                 if self.can_modify():
  65.                         self.node = node
  66.                 else:
  67.                         self.node = None
  68.                 
  69.                 self.init_snippet_data(node)
  70.                 
  71.         def init_snippet_data(self, node):
  72.                 if node == None:
  73.                         return
  74.  
  75.                 self.override = node.attrib.get('override')
  76.  
  77.                 self.properties = {}
  78.                 props = SnippetData.PROPS.copy()
  79.  
  80.                 # Store all properties present
  81.                 for child in node:
  82.                         if child.tag in props:
  83.                                 del props[child.tag]
  84.  
  85.                                 # Normalize accelerator
  86.                                 if child.tag == 'accelerator' and child.text != None:
  87.                                         keyval, mod = gtk.accelerator_parse(child.text)
  88.  
  89.                                         if gtk.accelerator_valid(keyval, mod):
  90.                                                 child.text = gtk.accelerator_name(keyval, mod)
  91.                                         else:
  92.                                                 child.text = ''
  93.  
  94.                                 if self.can_modify():
  95.                                         self.properties[child.tag] = child
  96.                                 else:
  97.                                         self.properties[child.tag] = child.text or ''
  98.                 
  99.                 # Create all the props that were not found so we stay consistent
  100.                 for prop in props:
  101.                         if self.can_modify():
  102.                                 child = et.SubElement(node, prop)
  103.  
  104.                                 child.text = props[prop]
  105.                                 self.properties[prop] = child
  106.                         else:
  107.                                 self.properties[prop] = props[prop]
  108.                 
  109.                 self.check_validation()
  110.         
  111.         def check_validation(self):
  112.                 if not self['tag'] and not self['accelerator'] and not self['drop-targets']:
  113.                         return False
  114.  
  115.                 library = Library()
  116.                 keyval, mod = gtk.accelerator_parse(self['accelerator'])
  117.                 
  118.                 self.valid = library.valid_tab_trigger(self['tag']) and \
  119.                                 (not self['accelerator'] or library.valid_accelerator(keyval, mod))
  120.         
  121.         def _format_prop(self, prop, value):
  122.                 if prop == 'drop-targets' and value != '':
  123.                         return re.split('\\s*[,;]\\s*', value)
  124.                 else:
  125.                         return value
  126.         
  127.         def __getitem__(self, prop):
  128.                 if prop in self.properties:
  129.                         if self.can_modify():
  130.                                 return self._format_prop(prop, self.properties[prop].text or '')
  131.                         else:
  132.                                 return self._format_prop(prop, self.properties[prop] or '')
  133.                 
  134.                 return self._format_prop(prop, '')
  135.         
  136.         def __setitem__(self, prop, value):
  137.                 if not prop in self.properties:
  138.                         return
  139.                 
  140.                 if isinstance(value, list):
  141.                         value = ','.join(value)
  142.                                
  143.                 if not self.can_modify() and self.properties[prop] != value:
  144.                         # ohoh, this is not can_modify, but it needs to be changed...
  145.                         # make sure it is transfered to the changes file and set all the
  146.                         # fields.
  147.                         # This snippet data container will effectively become the container
  148.                         # for the newly created node, but transparently to whoever uses
  149.                         # it
  150.                         self._override()
  151.  
  152.                 if self.can_modify() and self.properties[prop].text != value:
  153.                         if self.library():
  154.                                 self.library().tainted = True
  155.  
  156.                         oldvalue = self.properties[prop].text
  157.                         self.properties[prop].text = value
  158.                         
  159.                         if prop == 'tag' or prop == 'accelerator' or prop == 'drop-targets':
  160.                                 container = Library().container(self.language())
  161.                                 container.prop_changed(self, prop, oldvalue)
  162.                 
  163.                 self.check_validation()
  164.  
  165.         def language(self):
  166.                 if self.library and self.library():
  167.                         return self.library().language
  168.                 else:
  169.                         return None
  170.         
  171.         def is_override(self):
  172.                 return self.override and Library().overridden[self.override]
  173.         
  174.         def to_xml(self):
  175.                 return self._create_xml()
  176.  
  177.         def _create_xml(self, parent=None, update=False, attrib={}):
  178.                 # Create a new node
  179.                 if parent != None:
  180.                         element = et.SubElement(parent, 'snippet', attrib)
  181.                 else:
  182.                         element = et.Element('snippet')
  183.  
  184.                 # Create all the properties
  185.                 for p in self.properties:
  186.                         prop = et.SubElement(element, p)
  187.                         prop.text = self[p]
  188.                         
  189.                         if update:
  190.                                 self.properties[p] = prop
  191.                 
  192.                 return element              
  193.         
  194.         def _override(self):
  195.                 # Find the user file
  196.                 target = Library().get_user_library(self.language())
  197.  
  198.                 # Create a new node there with override
  199.                 element = self._create_xml(target.root, True, {'override': self.id})
  200.  
  201.                 # Create an override snippet data, feed it element so that it stores
  202.                 # all the values and then set the node to None so that it only contains
  203.                 # the values in .properties
  204.                 override = SnippetData(element, self.library())
  205.                 override.set_node(None)
  206.                 override.id = self.id
  207.                 
  208.                 # Set our node to the new element
  209.                 self.node = element
  210.                 
  211.                 # Set the override to our id
  212.                 self.override = self.id
  213.                 self.id = None
  214.                 
  215.                 # Set the new library
  216.                 self.set_library(target)
  217.                 
  218.                 # The library is tainted because we added this snippet
  219.                 target.tainted = True
  220.                 
  221.                 # Add the override
  222.                 Library().overridden[self.override] = override
  223.         
  224.         def revert(self, snippet):
  225.                 userlib = self.library()
  226.                 self.set_library(snippet.library())
  227.                 
  228.                 userlib.remove(self.node)
  229.                 
  230.                 self.set_node(None)
  231.  
  232.                 # Copy the properties
  233.                 self.properties = snippet.properties
  234.                 
  235.                 # Set the id
  236.                 self.id = snippet.id
  237.  
  238.                 # Reset the override flag
  239.                 self.override = None
  240.  
  241. class SnippetsTreeBuilder(et.TreeBuilder):
  242.         def __init__(self, start=None, end=None):
  243.                 et.TreeBuilder.__init__(self)
  244.                 self.set_start(start)
  245.                 self.set_end(end)
  246.  
  247.         def set_start(self, start):
  248.                 self._start_cb = start
  249.         
  250.         def set_end(self, end):
  251.                 self._end_cb = end
  252.  
  253.         def start(self, tag, attrs):
  254.                 result = et.TreeBuilder.start(self, tag, attrs)
  255.         
  256.                 if self._start_cb:
  257.                         self._start_cb(result)
  258.         
  259.                 return result
  260.                 
  261.         def end(self, tag):
  262.                 result = et.TreeBuilder.end(self, tag)
  263.         
  264.                 if self._end_cb:
  265.                         self._end_cb(result)
  266.         
  267.                 return result
  268.  
  269. class LanguageContainer:
  270.         def __init__(self, language):
  271.                 self.language = language
  272.                 self.snippets = []
  273.                 self.snippets_by_prop = {'tag': {}, 'accelerator': {}, 'drop-targets': {}}
  274.                 self.accel_group = gtk.AccelGroup()
  275.                 self._refs = 0
  276.  
  277.         def _add_prop(self, snippet, prop, value=0):
  278.                 if value == 0:
  279.                         value = snippet[prop]
  280.                 
  281.                 if not value or value == '':
  282.                         return
  283.  
  284.                 snippets_debug('Added ', prop ,' ', value, ' to ', str(self.language))
  285.                 
  286.                 if prop == 'accelerator':
  287.                         keyval, mod = gtk.accelerator_parse(value)
  288.                         self.accel_group.connect_group(keyval, mod, 0, \
  289.                                         Library().accelerator_activated)
  290.                 
  291.                 snippets = self.snippets_by_prop[prop]
  292.                 
  293.                 if not isinstance(value, list):
  294.                         value = [value]
  295.                 
  296.                 for val in value:
  297.                         if val in snippets:
  298.                                 snippets[val].append(snippet)
  299.                         else:
  300.                                 snippets[val] = [snippet]
  301.  
  302.         def _remove_prop(self, snippet, prop, value=0):
  303.                 if value == 0:
  304.                         value = snippet[prop]
  305.  
  306.                 if not value or value == '':
  307.                         return
  308.  
  309.                 snippets_debug('Removed ', prop, ' ', value, ' from ', str(self.language))
  310.  
  311.                 if prop == 'accelerator':
  312.                         keyval, mod = gtk.accelerator_parse(value)
  313.                         self.accel_group.disconnect_key(keyval, mod)
  314.  
  315.                 snippets = self.snippets_by_prop[prop]
  316.                 
  317.                 if not isinstance(value, list):
  318.                         value = [value]
  319.                 
  320.                 for val in value:
  321.                         try:
  322.                                 snippets[val].remove(snippet)
  323.                         except:
  324.                                 True
  325.  
  326.         def append(self, snippet):
  327.                 tag = snippet['tag']
  328.                 accelerator = snippet['accelerator']
  329.                 
  330.                 self.snippets.append(snippet)
  331.                 
  332.                 self._add_prop(snippet, 'tag')
  333.                 self._add_prop(snippet, 'accelerator')
  334.                 self._add_prop(snippet, 'drop-targets')
  335.  
  336.                 return snippet
  337.         
  338.         def remove(self, snippet):
  339.                 try:
  340.                         self.snippets.remove(snippet)
  341.                 except:
  342.                         True
  343.                         
  344.                 self._remove_prop(snippet, 'tag')
  345.                 self._remove_prop(snippet, 'accelerator')
  346.                 self._remove_prop(snippet, 'drop-targets')
  347.         
  348.         def prop_changed(self, snippet, prop, oldvalue):
  349.                 snippets_debug('PROP CHANGED (', prop, ')', oldvalue)
  350.  
  351.                 self._remove_prop(snippet, prop, oldvalue)
  352.                 self._add_prop(snippet, prop)
  353.         
  354.         def from_prop(self, prop, value):
  355.                 snippets = self.snippets_by_prop[prop]
  356.                 
  357.                 if prop == 'drop-targets':
  358.                         s = []
  359.                         
  360.                         # FIXME: change this to use 
  361.                         # gnomevfs.mime_type_get_equivalence when it comes
  362.                         # available
  363.                         for key, val in snippets.items():
  364.                                 if not value.startswith(key):
  365.                                         continue
  366.                                 
  367.                                 for snippet in snippets[key]:
  368.                                         if not snippet in s:
  369.                                                 s.append(snippet)
  370.                         
  371.                         return s
  372.                 else:
  373.                         if value in snippets:
  374.                                 return snippets[value]
  375.                         else:
  376.                                 return []
  377.         
  378.         def ref(self):
  379.                 self._refs += 1
  380.         
  381.                 return True
  382.  
  383.         def unref(self):
  384.                 if self._refs > 0:
  385.                         self._refs -= 1
  386.                 
  387.                 return self._refs != 0
  388.  
  389. class SnippetsSystemFile:
  390.         def __init__(self, path=None):
  391.                 self.path = path
  392.                 self.loaded = False
  393.                 self.language = None
  394.                 self.ok = True
  395.                 self.need_id = True
  396.                 
  397.         def load_error(self, message):
  398.                 sys.stderr.write("An error occurred loading " + self.path + ":\n")
  399.                 sys.stderr.write(message + "\nSnippets in this file will not be " \
  400.                                 "available, please correct or remove the file.\n")
  401.  
  402.         def _add_snippet(self, element):
  403.                 if not self.need_id or element.attrib.get('id'):
  404.                         self.loading_elements.append(element)
  405.  
  406.         def set_language(self, element):
  407.                 self.language = element.attrib.get('language')
  408.                 
  409.                 if self.language:
  410.                         self.language = self.language.lower()
  411.         
  412.         def _set_root(self, element):
  413.                 self.set_language(element)
  414.                 
  415.         def _preprocess_element(self, element):
  416.                 if not self.loaded:
  417.                         if not element.tag == "snippets":
  418.                                 self.load_error("Root element should be `snippets' instead " \
  419.                                                 "of `%s'" % element.tag)
  420.                                 return False
  421.                         else:
  422.                                 self._set_root(element)
  423.                                 self.loaded = True
  424.                 elif element.tag != 'snippet' and not self.insnippet:
  425.                         self.load_error("Element should be `snippet' instead of `%s'" \
  426.                                         % element.tag)
  427.                         return False
  428.                 else:
  429.                         self.insnippet = True
  430.  
  431.                 return True
  432.  
  433.         def _process_element(self, element):
  434.                 if element.tag == 'snippet':
  435.                         self._add_snippet(element)
  436.                         self.insnippet = False                        
  437.  
  438.                 return True
  439.  
  440.         def ensure(self):
  441.                 if not self.ok or self.loaded:
  442.                         return
  443.                 
  444.                 self.load()
  445.  
  446.         def parse_xml(self, readsize=16384):
  447.                 if not self.path:
  448.                         return
  449.                         
  450.                 elements = []
  451.  
  452.                 builder = SnippetsTreeBuilder( \
  453.                                 lambda node: elements.append((node, True)), \
  454.                                 lambda node: elements.append((node, False)))
  455.  
  456.                 parser = et.XMLTreeBuilder(target=builder)
  457.                 self.insnippet = False
  458.                 
  459.                 try:
  460.                         f = open(self.path, "r")
  461.                         
  462.                         while True:
  463.                                 data = f.read(readsize)
  464.                                 
  465.                                 if not data:
  466.                                         break
  467.                                 
  468.                                 parser.feed(data)
  469.                                 
  470.                                 for element in elements:
  471.                                         yield element
  472.                                 
  473.                                 del elements[:]
  474.                         
  475.                         f.close()
  476.                 except IOError:
  477.                         self.ok = False
  478.  
  479.         def load(self):
  480.                 if not self.ok:
  481.                         return
  482.  
  483.                 snippets_debug("Loading library (" + str(self.language) + "): " + \
  484.                                 self.path)
  485.                 
  486.                 self.loaded = False
  487.                 self.ok = False
  488.                 self.loading_elements = []
  489.                 
  490.                 for element in self.parse_xml():
  491.                         if element[1]:
  492.                                 if not self._preprocess_element(element[0]):
  493.                                         del self.loading_elements[:]
  494.                                         return
  495.                         else:
  496.                                 if not self._process_element(element[0]):
  497.                                         del self.loading_elements[:]
  498.                                         return
  499.  
  500.                 for element in self.loading_elements:
  501.                         snippet = Library().add_snippet(self, element)
  502.                 
  503.                 del self.loading_elements[:]
  504.                 self.ok = True
  505.  
  506.         # This function will get the language for a file by just inspecting the
  507.         # root element of the file. This is provided so that a cache can be built
  508.         # for which file contains which language.
  509.         # It returns the name of the language
  510.         def ensure_language(self):
  511.                 if not self.loaded:
  512.                         self.ok = False
  513.                         
  514.                         for element in self.parse_xml(256):
  515.                                 if element[1]:
  516.                                         if element[0].tag == 'snippets':
  517.                                                 self.set_language(element[0])
  518.                                                 self.ok = True
  519.  
  520.                                         break
  521.         
  522.         def unload(self):
  523.                 snippets_debug("Unloading library (" + str(self.language) + "): " + \
  524.                                 self.path)
  525.                 self.language = None
  526.                 self.loaded = False
  527.                 self.ok = True
  528.  
  529. class SnippetsUserFile(SnippetsSystemFile):
  530.         def __init__(self, path=None):
  531.                 SnippetsSystemFile.__init__(self, path)
  532.                 self.tainted = False
  533.                 self.need_id = False
  534.                 
  535.         def _set_root(self, element):
  536.                 SnippetsSystemFile._set_root(self, element)
  537.                 self.root = element
  538.                         
  539.         def add_prop(self, node, tag, data):
  540.                 if data[tag]:
  541.                         prop = et.SubElement(node, tag)
  542.                         prop.text = data[tag]
  543.                 
  544.                         return prop
  545.                 else:
  546.                         return None
  547.  
  548.         def new_snippet(self, properties=None):
  549.                 if (not self.ok) or self.root == None:
  550.                         return None
  551.                 
  552.                 element = et.SubElement(self.root, 'snippet')
  553.                 
  554.                 if properties:
  555.                         for prop in properties:
  556.                                 sub = et.SubElement(element, prop)
  557.                                 sub.text = properties[prop]
  558.                 
  559.                 self.tainted = True
  560.                 
  561.                 return Library().add_snippet(self, element)
  562.         
  563.         def set_language(self, element):
  564.                 SnippetsSystemFile.set_language(self, element)
  565.                 
  566.                 filename = os.path.basename(self.path).lower()
  567.                 
  568.                 if not self.language and filename == "global.xml":
  569.                         self.modifier = True
  570.                 elif self.language and filename == self.language + ".xml":
  571.                         self.modifier = True
  572.                 else:
  573.                         self.modifier = False
  574.         
  575.         def create_root(self, language):
  576.                 if self.loaded:
  577.                         snippets_debug('Not creating root, already loaded')
  578.                         return
  579.                 
  580.                 if language:
  581.                         root = et.Element('snippets', {'language': language})
  582.                         self.path = os.path.join(Library().userdir, language.lower() + '.xml')
  583.                 else:
  584.                         root = et.Element('snippets')
  585.                         self.path = os.path.join(Library().userdir, 'global.xml')
  586.                 
  587.                 self._set_root(root)
  588.                 self.loaded = True
  589.                 self.ok = True
  590.                 self.tainted = True
  591.                 self.save()
  592.         
  593.         def remove(self, element):
  594.                 try:
  595.                         self.root.remove(element)
  596.                         self.tainted = True
  597.                 except:
  598.                         return
  599.                 
  600.                 try:
  601.                         first = self.root[0]
  602.                 except:
  603.                         # No more elements, this library is useless now
  604.                         Library().remove_library(self)
  605.         
  606.         def save(self):
  607.                 if not self.ok or self.root == None or not self.tainted:
  608.                         return
  609.  
  610.                 path = os.path.dirname(self.path)
  611.                 
  612.                 try:
  613.                         if not os.path.isdir(path):
  614.                                 os.makedirs(path, 0755)
  615.                 except OSError:
  616.                         # TODO: this is bad...
  617.                         sys.stderr.write("Error in making dirs\n")
  618.  
  619.                 try:
  620.                         write_xml(self.root, self.path, ('text', 'accelerator'))
  621.                         self.tainted = False
  622.                 except IOError:
  623.                         # Couldn't save, what to do
  624.                         sys.stderr.write("Could not save user snippets file to " + \
  625.                                         self.path + "\n")
  626.         
  627.         def unload(self):
  628.                 SnippetsSystemFile.unload(self)
  629.                 self.root = None
  630.  
  631. class Singleton(object):
  632.         _instance = None
  633.  
  634.         def __new__(cls, *args, **kwargs):
  635.                 if not cls._instance:
  636.                         cls._instance = super(Singleton, cls).__new__(
  637.                                          cls, *args, **kwargs)
  638.                         cls._instance.__init_once__()
  639.  
  640.                 return cls._instance
  641.  
  642. class Library(Singleton):        
  643.         def __init_once__(self):
  644.                 self._accelerator_activated_cb = None
  645.                 self.loaded = False
  646.                 self.check_buffer = gtk.TextBuffer()
  647.  
  648.         def set_dirs(self, userdir, systemdirs):
  649.                 self.userdir = userdir
  650.                 self.systemdirs = systemdirs
  651.                 
  652.                 self.libraries = {}
  653.                 self.containers = {}
  654.                 self.overridden = {}
  655.                 self.loaded_ids = []
  656.  
  657.                 self.loaded = False
  658.         
  659.         def set_accelerator_callback(self, cb):
  660.                 self._accelerator_activated_cb = cb
  661.         
  662.         def accelerator_activated(self, group, obj, keyval, mod):
  663.                 if self._accelerator_activated_cb:
  664.                         self._accelerator_activated_cb(group, obj, keyval, mod)
  665.  
  666.         def add_snippet(self, library, element):
  667.                 container = self.container(library.language)
  668.                 overrided = self.overrided(library, element)
  669.                 
  670.                 if overrided:
  671.                         overrided.set_library(library)
  672.                         snippets_debug('Snippet is overriden: ' + overrided['description'])
  673.                         return None
  674.                 
  675.                 snippet = SnippetData(element, library)
  676.                 
  677.                 if snippet.id in self.loaded_ids:
  678.                         snippets_debug('Not added snippet ' + str(library.language) + \
  679.                                         '::' + snippet['description'] + ' (duplicate)')
  680.                         return None
  681.  
  682.                 snippet = container.append(snippet)
  683.                 snippets_debug('Added snippet ' + str(library.language) + '::' + \
  684.                                 snippet['description'])
  685.                 
  686.                 if snippet and snippet.override:
  687.                         self.add_override(snippet)
  688.                 
  689.                 if snippet.id:
  690.                         self.loaded_ids.append(snippet.id)
  691.  
  692.                 return snippet
  693.         
  694.         def container(self, language):
  695.                 language = self.normalize_language(language)
  696.                 
  697.                 if not language in self.containers:
  698.                         self.containers[language] = LanguageContainer(language)
  699.                 
  700.                 return self.containers[language]
  701.         
  702.         def get_user_library(self, language):
  703.                 target = None
  704.                 
  705.                 if language in self.libraries:
  706.                         for library in self.libraries[language]:
  707.                                 if isinstance(library, SnippetsUserFile) and library.modifier:
  708.                                         target = library
  709.                                 elif not isinstance(library, SnippetsUserFile):
  710.                                         break
  711.                 
  712.                 if not target:
  713.                         # Create a new user file then
  714.                         snippets_debug('Creating a new user file for language ' + \
  715.                                         str(language))
  716.                         target = SnippetsUserFile()
  717.                         target.create_root(language)
  718.                         self.add_library(target)
  719.         
  720.                 return target
  721.         
  722.         def new_snippet(self, language, properties=None):
  723.                 language = self.normalize_language(language)
  724.                 library = self.get_user_library(language)
  725.  
  726.                 return library.new_snippet(properties)
  727.         
  728.         def revert_snippet(self, snippet):
  729.                 # This will revert the snippet to the one it overrides
  730.                 if not snippet.can_modify() or not snippet.override in self.overridden:
  731.                         # It can't be reverted, shouldn't happen, but oh..
  732.                         return
  733.                 
  734.                 # The snippet in self.overriden only contains the property contents and
  735.                 # the library it belongs to
  736.                 revertto = self.overridden[snippet.override]
  737.                 del self.overridden[snippet.override]
  738.                 
  739.                 if revertto:
  740.                         snippet.revert(revertto)
  741.                 
  742.                         if revertto.id:
  743.                                 self.loaded_ids.append(revertto.id)
  744.         
  745.         def remove_snippet(self, snippet):
  746.                 if not snippet.can_modify() or snippet.is_override():
  747.                         return
  748.                 
  749.                 # Remove from the library
  750.                 userlib = snippet.library()
  751.                 userlib.remove(snippet.node)
  752.                 
  753.                 # Remove from the container
  754.                 container = self.containers[userlib.language]
  755.                 container.remove(snippet)
  756.         
  757.         def overrided(self, library, element):
  758.                 id = NamespacedId(library.language, element.attrib.get('id')).id
  759.                 
  760.                 if id in self.overridden:
  761.                         snippet = SnippetData(element, None)
  762.                         snippet.set_node(None)
  763.                         
  764.                         self.overridden[id] = snippet
  765.                         return snippet
  766.                 else:
  767.                         return None
  768.         
  769.         def add_override(self, snippet):
  770.                 snippets_debug('Add override:', snippet.override)
  771.                 if not snippet.override in self.overridden:
  772.                         self.overridden[snippet.override] = None
  773.         
  774.         def add_library(self, library):
  775.                 library.ensure_language()
  776.                 
  777.                 if not library.ok:
  778.                         snippets_debug('Library in wrong format, ignoring')
  779.                         return False
  780.                 
  781.                 snippets_debug('Adding library (' + str(library.language) + '): ' + \
  782.                                 library.path)
  783.  
  784.                 if library.language in self.libraries:
  785.                         # Make sure all the user files are before the system files
  786.                         if isinstance(library, SnippetsUserFile):
  787.                                 self.libraries[library.language].insert(0, library)
  788.                         else:
  789.                                 self.libraries[library.language].append(library)
  790.                 else:
  791.                         self.libraries[library.language] = [library]
  792.  
  793.                 return True
  794.         
  795.         def remove_library(self, library):
  796.                 if not library.ok:
  797.                         return
  798.                 
  799.                 if library.path and os.path.isfile(library.path):
  800.                         os.unlink(library.path)
  801.                 
  802.                 try:
  803.                         self.libraries[library.language].remove(library)
  804.                 except KeyError:
  805.                         True
  806.                         
  807.                 container = self.containers[library.language]
  808.                         
  809.                 for snippet in list(container.snippets):
  810.                         if snippet.library() == library:
  811.                                 container.remove(snippet)
  812.         
  813.         def add_user_library(self, path):
  814.                 library = SnippetsUserFile(path)
  815.                 return self.add_library(library)
  816.                 
  817.         def add_system_library(self, path):
  818.                 library = SnippetsSystemFile(path)
  819.                 return self.add_library(library)
  820.  
  821.         def find_libraries(self, path, searched, addcb):
  822.                 snippets_debug("Finding in: " + path)
  823.                 
  824.                 if not os.path.isdir(path):
  825.                         return searched
  826.  
  827.                 files = os.listdir(path)
  828.                 searched.append(path)
  829.                 
  830.                 for f in files:
  831.                         f = os.path.realpath(os.path.join(path, f))
  832.  
  833.                         # Determine what language this file provides snippets for
  834.                         if os.path.isfile(f):
  835.                                 addcb(f)
  836.                 
  837.                 return searched
  838.         
  839.         def normalize_language(self, language):
  840.                 if language:
  841.                         return language.lower()
  842.                 
  843.                 return language
  844.         
  845.         def remove_container(self, language):
  846.                 for snippet in self.containers[language].snippets:
  847.                         if snippet.id in self.loaded_ids:
  848.                                 self.loaded_ids.remove(snippet.id)
  849.  
  850.                         if snippet.override in self.overridden:
  851.                                 del self.overridden[snippet.override]
  852.  
  853.                 del self.containers[language]
  854.                 
  855.         def get_accel_group(self, language):
  856.                 language = self.normalize_language(language)
  857.                 container = self.container(language)
  858.  
  859.                 self.ensure(language)
  860.                 return container.accel_group
  861.                 
  862.         def save(self, language):
  863.                 language = self.normalize_language(language)
  864.                 
  865.                 if language in self.libraries:
  866.                         for library in self.libraries[language]:
  867.                                 if isinstance(library, SnippetsUserFile):
  868.                                         library.save()
  869.                                 else:
  870.                                         break
  871.         
  872.         def ref(self, language):
  873.                 language = self.normalize_language(language)
  874.  
  875.                 snippets_debug('Ref:', language)
  876.                 self.container(language).ref()
  877.         
  878.         def unref(self, language):
  879.                 language = self.normalize_language(language)
  880.                 
  881.                 snippets_debug('Unref:', language)
  882.                 
  883.                 if language in self.containers:
  884.                         if not self.containers[language].unref() and \
  885.                                         language in self.libraries:
  886.  
  887.                                 for library in self.libraries[language]:
  888.                                         library.unload()
  889.                                 
  890.                                 self.remove_container(language)
  891.  
  892.         def ensure(self, language):
  893.                 self.ensure_files()
  894.                 language = self.normalize_language(language)
  895.  
  896.                 # Ensure language as well as the global snippets (None)
  897.                 for lang in (None, language):
  898.                         if lang in self.libraries:
  899.                                 # Ensure the container exists
  900.                                 self.container(lang)
  901.  
  902.                                 for library in self.libraries[lang]:
  903.                                         library.ensure()
  904.  
  905.         def ensure_files(self):
  906.                 if self.loaded:
  907.                         return
  908.  
  909.                 searched = []
  910.                 searched = self.find_libraries(self.userdir, searched, \
  911.                                 self.add_user_library)
  912.                 
  913.                 for d in self.systemdirs:
  914.                         searched = self.find_libraries(d, searched, \
  915.                                         self.add_system_library)
  916.  
  917.                 self.loaded = True
  918.  
  919.         def valid_accelerator(self, keyval, mod):
  920.                 mod &= gtk.accelerator_get_default_mod_mask()
  921.         
  922.                 return (mod and (gdk.keyval_to_unicode(keyval) or \
  923.                                 keyval in range(gtk.keysyms.F1, gtk.keysyms.F12 + 1)))
  924.         
  925.         def valid_tab_trigger(self, trigger):
  926.                 if not trigger:
  927.                         return True
  928.  
  929.                 if trigger.isdigit():
  930.                         return False
  931.  
  932.                 self.check_buffer.set_text(trigger)
  933.  
  934.                 start, end = self.check_buffer.get_bounds()
  935.                 text = self.check_buffer.get_text(start, end)
  936.                                 
  937.                 s = start.copy()
  938.                 e = end.copy()
  939.                 
  940.                 end.backward_word_start()
  941.                 start.forward_word_end()
  942.                 
  943.                 return (s.equal(end) and e.equal(start)) or (len(text) == 1 and not (text.isalnum() or text.isspace()))
  944.  
  945.         # Snippet getters
  946.         # ===============
  947.         def _from_prop(self, prop, value, language=None):
  948.                 self.ensure_files()
  949.                 
  950.                 result = []                
  951.                 language = self.normalize_language(language)
  952.                         
  953.                 if not language in self.containers:
  954.                         return []
  955.  
  956.                 self.ensure(language)
  957.                 result = self.containers[language].from_prop(prop, value)
  958.                 
  959.                 if len(result) == 0 and language and None in self.containers:
  960.                         result = self.containers[None].from_prop(prop, value)
  961.                 
  962.                 return result
  963.         
  964.         # Get snippets for a given language
  965.         def get_snippets(self, language=None):
  966.                 self.ensure_files()
  967.                 language = self.normalize_language(language)
  968.                 
  969.                 if not language in self.libraries:
  970.                         return []
  971.                 
  972.                 snippets = []
  973.                 self.ensure(language)
  974.                 
  975.                 return list(self.containers[language].snippets)
  976.  
  977.         # Get snippets for a given accelerator
  978.         def from_accelerator(self, accelerator, language=None):
  979.                 return self._from_prop('accelerator', accelerator, language)
  980.  
  981.         # Get snippets for a given tag
  982.         def from_tag(self, tag, language=None):
  983.                 return self._from_prop('tag', tag, language)
  984.         
  985.         # Get snippets for a given drop target
  986.         def from_drop_target(self, drop_target, language=None):
  987.                 return self._from_prop('drop-targets', drop_target, language)
  988.                 
  989. # ex:ts=8:et:
  990.