From ec7ec9934d6f80f99474ebeca16bce7b52fe78a1 Mon Sep 17 00:00:00 2001
From: Patrick Monnerat <patrick@monnerat.net>
Date: Fri, 10 May 2019 16:26:39 +0200
Subject: [PATCH 1/6] Reindent all Python sources to ts=4. Strip trailing
 spaces.

---
 plugins/externaltools/tools/__init__.py       |   22 +-
 plugins/externaltools/tools/capture.py        |   18 +-
 plugins/externaltools/tools/functions.py      |   44 +-
 plugins/externaltools/tools/library.py        |   18 +-
 plugins/externaltools/tools/linkparsing.py    |    2 +-
 plugins/externaltools/tools/manager.py        |  272 +--
 plugins/externaltools/tools/outputpanel.py    |    6 +-
 .../pythonconsole/pythonconsole/__init__.py   |    2 +-
 plugins/quickopen/quickopen/__init__.py       |   36 +-
 plugins/quickopen/quickopen/popup.py          |  877 ++++---
 plugins/quickopen/quickopen/virtualdirs.py    |   84 +-
 plugins/quickopen/quickopen/windowhelper.py   |  218 +-
 plugins/snippets/snippets/Completion.py       |  304 +--
 plugins/snippets/snippets/Document.py         | 1994 ++++++++-------
 plugins/snippets/snippets/Exporter.py         |  176 +-
 plugins/snippets/snippets/Helper.py           |  244 +-
 plugins/snippets/snippets/Importer.py         |  184 +-
 plugins/snippets/snippets/LanguageManager.py  |   25 +-
 plugins/snippets/snippets/Library.py          | 1892 +++++++-------
 plugins/snippets/snippets/Manager.py          | 2176 ++++++++---------
 plugins/snippets/snippets/Parser.py           |  466 ++--
 plugins/snippets/snippets/Placeholder.py      | 1278 +++++-----
 plugins/snippets/snippets/Snippet.py          |  657 ++---
 .../snippets/snippets/SubstitutionParser.py   |  356 +--
 plugins/snippets/snippets/WindowHelper.py     |  248 +-
 plugins/snippets/snippets/__init__.py         |   94 +-
 28 files changed, 5871 insertions(+), 5856 deletions(-)
 mode change 100755 => 100644 plugins/quickopen/quickopen/__init__.py
 mode change 100755 => 100644 plugins/quickopen/quickopen/popup.py
 mode change 100755 => 100644 plugins/quickopen/quickopen/virtualdirs.py
 mode change 100755 => 100644 plugins/quickopen/quickopen/windowhelper.py
 mode change 100755 => 100644 plugins/snippets/snippets/Completion.py
 mode change 100755 => 100644 plugins/snippets/snippets/Document.py
 mode change 100755 => 100644 plugins/snippets/snippets/Exporter.py
 mode change 100755 => 100644 plugins/snippets/snippets/Helper.py
 mode change 100755 => 100644 plugins/snippets/snippets/Importer.py
 mode change 100755 => 100644 plugins/snippets/snippets/LanguageManager.py
 mode change 100755 => 100644 plugins/snippets/snippets/Library.py
 mode change 100755 => 100644 plugins/snippets/snippets/Manager.py
 mode change 100755 => 100644 plugins/snippets/snippets/Parser.py
 mode change 100755 => 100644 plugins/snippets/snippets/Placeholder.py
 mode change 100755 => 100644 plugins/snippets/snippets/Snippet.py
 mode change 100755 => 100644 plugins/snippets/snippets/SubstitutionParser.py
 mode change 100755 => 100644 plugins/snippets/snippets/WindowHelper.py
 mode change 100755 => 100644 plugins/snippets/snippets/__init__.py

diff --git a/plugins/externaltools/tools/__init__.py b/plugins/externaltools/tools/__init__.py
index 463c8f5..153d6c6 100755
--- a/plugins/externaltools/tools/__init__.py
+++ b/plugins/externaltools/tools/__init__.py
@@ -57,12 +57,12 @@ class ToolMenu(object):
             action._tool_handler = None
 
             self._action_group.remove_action(action)
-        
+
         accelmap = Gtk.AccelMap.get()
 
         for s in self._signals:
             accelmap.disconnect(s)
-        
+
         self._signals = []
 
     def _insert_directory(self, directory, path):
@@ -76,7 +76,7 @@ class ToolMenu(object):
             manager.add_ui(self._merge_id, path,
                            action_name, action_name,
                            Gtk.UIManagerItemType.MENU, False)
-                           
+
             self._insert_directory(item, path + '/' + action_name)
 
         for item in directory.tools:
@@ -87,16 +87,16 @@ class ToolMenu(object):
             # Attach the item and the handler to the action object
             action._tool_item = item
             action._tool_handler = handler
-            
+
             # Make sure to replace accel
             accelpath = '<Actions>/ExternalToolsPluginToolActions/%s' % (action_name, )
-            
+
             if item.shortcut:
                 key, mod = Gtk.accelerator_parse(item.shortcut)
                 Gtk.AccelMap.change_entry(accelpath, key, mod, True)
-                
+
                 self._signals.append(Gtk.AccelMap.get().connect('changed::%s' % (accelpath,), self.on_accelmap_changed, item))
-                
+
             self._action_group.add_action_with_accel(action, item.shortcut)
 
             manager.add_ui(self._merge_id, path,
@@ -106,7 +106,7 @@ class ToolMenu(object):
     def on_accelmap_changed(self, accelmap, path, key, mod, tool):
         tool.shortcut = Gtk.accelerator_name(key, mod)
         tool.save()
-        
+
         self._plugin.update_manager(tool)
 
     def update(self):
@@ -119,10 +119,10 @@ class ToolMenu(object):
     def filter_language(self, language, item):
         if not item.languages:
             return True
-        
+
         if not language and 'plain' in item.languages:
             return True
-        
+
         if language and (language.get_id() in item.languages):
             return True
         else:
@@ -142,7 +142,7 @@ class ToolMenu(object):
             'titled': titled,
             'untitled': not titled,
         }
-        
+
         language = document.get_language()
 
         for action in self._action_group.list_actions():
diff --git a/plugins/externaltools/tools/capture.py b/plugins/externaltools/tools/capture.py
index 487c8db..73ce270 100755
--- a/plugins/externaltools/tools/capture.py
+++ b/plugins/externaltools/tools/capture.py
@@ -29,7 +29,7 @@ class Capture(GObject.Object):
     CAPTURE_STDERR = 0x02
     CAPTURE_BOTH   = 0x03
     CAPTURE_NEEDS_SHELL = 0x04
-    
+
     WRITE_BUFFER_SIZE = 0x4000
 
     __gsignals__ = {
@@ -73,7 +73,7 @@ class Capture(GObject.Object):
             'shell': self.flags & self.CAPTURE_NEEDS_SHELL,
             'env'  : self.env
         }
-        
+
         if self.input_text is not None:
             popen_args['stdin'] = subprocess.PIPE
         if self.flags & self.CAPTURE_STDOUT:
@@ -84,17 +84,17 @@ class Capture(GObject.Object):
         self.tried_killing = False
         self.idle_write_id = 0
         self.read_buffer = ''
-        
+
         try:
             self.pipe = subprocess.Popen(self.command, **popen_args)
         except OSError, e:
             self.pipe = None
             self.emit('stderr-line', _('Could not execute command: %s') % (e, ))
             return
-        
+
         # Signal
         self.emit('begin-execute')
-        
+
         if self.flags & self.CAPTURE_STDOUT:
             # Set non blocking
             flags = fcntl.fcntl(self.pipe.stdout.fileno(), fcntl.F_GETFL) | os.O_NONBLOCK
@@ -132,13 +132,13 @@ class Capture(GObject.Object):
         try:
             l = len(self.write_buffer)
             m = min(l, self.WRITE_BUFFER_SIZE)
-         
+
             self.pipe.stdin.write(self.write_buffer[:m])
-            
+
             if m == l:
                 self.write_buffer = ''
                 self.pipe.stdin.close()
-                
+
                 self.idle_write_id = 0
 
                 return False
@@ -165,7 +165,7 @@ class Capture(GObject.Object):
 
                 self.read_buffer += line
                 lines = self.read_buffer.splitlines(True)
-                
+
                 if not lines[-1].endswith("\n"):
                     self.read_buffer = lines[-1]
                     lines = lines[0:-1]
diff --git a/plugins/externaltools/tools/functions.py b/plugins/externaltools/tools/functions.py
index e126844..dd4f82b 100755
--- a/plugins/externaltools/tools/functions.py
+++ b/plugins/externaltools/tools/functions.py
@@ -30,13 +30,13 @@ def default(val, d):
 def current_word(document):
     piter = document.get_iter_at_mark(document.get_insert())
     start = piter.copy()
-    
+
     if not piter.starts_word() and (piter.inside_word() or piter.ends_word()):
         start.backward_word_start()
-    
+
     if not piter.ends_word() and piter.inside_word():
         piter.forward_word_end()
-            
+
     return (start, piter)
 
 # ==== Capture related functions ====
@@ -56,32 +56,32 @@ def run_external_tool(window, panel, node):
         # Environment vars relative to current document
         document = view.get_buffer()
         uri = document.get_uri()
-        
+
         # Current line number
         piter = document.get_iter_at_mark(document.get_insert())
         capture.set_env(PLUMA_CURRENT_LINE_NUMBER=str(piter.get_line() + 1))
-        
+
         # Current line text
         piter.set_line_offset(0)
         end = piter.copy()
-        
+
         if not end.ends_line():
             end.forward_to_line_end()
-        
+
         capture.set_env(PLUMA_CURRENT_LINE=piter.get_text(end))
-        
+
         # Selected text (only if input is not selection)
         if node.input != 'selection' and node.input != 'selection-document':
             bounds = document.get_selection_bounds()
-            
+
             if bounds:
                 capture.set_env(PLUMA_SELECTED_TEXT=bounds[0].get_text(bounds[1]))
-        
+
         bounds = current_word(document)
         capture.set_env(PLUMA_CURRENT_WORD=bounds[0].get_text(bounds[1]))
-        
+
         capture.set_env(PLUMA_CURRENT_DOCUMENT_TYPE=document.get_mime_type())
-        
+
         if uri is not None:
             gfile = Gio.file_new_for_uri(uri)
             scheme = gfile.get_uri_scheme()
@@ -106,7 +106,7 @@ def run_external_tool(window, panel, node):
                         PLUMA_DOCUMENTS_PATH = ' '.join(documents_path))
 
     flags = capture.CAPTURE_BOTH
-    
+
     if not node.has_hash_bang():
         flags |= capture.CAPTURE_NEEDS_SHELL
 
@@ -131,7 +131,7 @@ def run_external_tool(window, panel, node):
         elif input_type == 'selection' or input_type == 'selection-document':
             try:
                 start, end = document.get_selection_bounds()
-                
+
                 print start, end
             except ValueError:
                 if input_type == 'selection-document':
@@ -142,7 +142,7 @@ def run_external_tool(window, panel, node):
                 else:
                     start = document.get_iter_at_mark(document.get_insert())
                     end = start.copy()
-                    
+
         elif input_type == 'line':
             start = document.get_iter_at_mark(document.get_insert())
             end = start.copy()
@@ -196,12 +196,12 @@ def run_external_tool(window, panel, node):
         document.begin_user_action()
 
     capture.connect('stderr-line', capture_stderr_line_panel, panel)
-    capture.connect('begin-execute', capture_begin_execute_panel, panel, view, node.name)    
+    capture.connect('begin-execute', capture_begin_execute_panel, panel, view, node.name)
     capture.connect('end-execute', capture_end_execute_panel, panel, view, output_type)
 
     # Run the command
     capture.execute()
-    
+
     if output_type != 'nothing':
         document.end_user_action()
 
@@ -222,7 +222,7 @@ class MultipleDocumentsSaver:
             signals[doc] = doc.connect('saving', self.on_document_saving)
             Pluma.commands_save_document(window, doc)
             doc.disconnect(signals[doc])
-    
+
     def on_document_saving(self, doc, size, total_size):
         self._counter += 1
         self._signal_ids[doc] = doc.connect('saved', self.on_document_saved)
@@ -230,12 +230,12 @@ class MultipleDocumentsSaver:
     def on_document_saved(self, doc, error):
         if error:
             self._error = True
-        
+
         doc.disconnect(self._signal_ids[doc])
         del self._signal_ids[doc]
-        
+
         self._counter -= 1
-        
+
         if self._counter == 0 and not self._error:
             run_external_tool(self._window, self._panel, self._node)
 
@@ -275,7 +275,7 @@ def capture_end_execute_panel(capture, exit_code, panel, view, output_type):
         mtype, uncertain = Gio.content_type_guess(None, doc.get_text(start, end, False).encode('utf-8'))
         lmanager = GtkSource.LanguageManager.get_default()
         language = lmanager.guess_language(doc.get_uri(), mtype)
-        
+
         if language is not None:
             doc.set_language(language)
 
diff --git a/plugins/externaltools/tools/library.py b/plugins/externaltools/tools/library.py
index b4e6924..186c33f 100755
--- a/plugins/externaltools/tools/library.py
+++ b/plugins/externaltools/tools/library.py
@@ -286,64 +286,80 @@ class Tool(object):
         applicability = self._properties.get('Applicability')
         if applicability: return applicability
         return 'all'
+
     def set_applicability(self, value):
         self._set_property_if_changed('Applicability', value)
+
     applicability = property(get_applicability, set_applicability)
 
     def get_name(self):
         name = self._properties.get('Name')
         if name: return name
         return os.path.basename(self.filename)
+
     def set_name(self, value):
         self._set_property_if_changed('Name', value)
+
     name = property(get_name, set_name)
 
     def get_shortcut(self):
         shortcut = self._properties.get('Shortcut')
         if shortcut: return shortcut
         return None
+
     def set_shortcut(self, value):
         self._set_property_if_changed('Shortcut', value)
+
     shortcut = property(get_shortcut, set_shortcut)
 
     def get_comment(self):
         comment = self._properties.get('Comment')
         if comment: return comment
         return self.filename
+
     def set_comment(self, value):
         self._set_property_if_changed('Comment', value)
+
     comment = property(get_comment, set_comment)
 
     def get_input(self):
         input = self._properties.get('Input')
         if input: return input
         return 'nothing'
+
     def set_input(self, value):
         self._set_property_if_changed('Input', value)
+
     input = property(get_input, set_input)
 
     def get_output(self):
         output = self._properties.get('Output')
         if output: return output
         return 'output-panel'
+
     def set_output(self, value):
         self._set_property_if_changed('Output', value)
+
     output = property(get_output, set_output)
 
     def get_save_files(self):
         save_files = self._properties.get('Save-files')
         if save_files: return save_files
         return 'nothing'
+
     def set_save_files(self, value):
         self._set_property_if_changed('Save-files', value)
+
     save_files = property(get_save_files, set_save_files)
 
     def get_languages(self):
         languages = self._properties.get('Languages')
         if languages: return languages
         return []
+
     def set_languages(self, value):
         self._set_property_if_changed('Languages', value)
+
     languages = property(get_languages, set_languages)
 
     def has_hash_bang(self):
@@ -358,7 +374,6 @@ class Tool(object):
         for line in fp:
             if line.strip() == '':
                 continue
-
             return line.startswith('#!')
 
     # There is no property for this one because this function is quite
@@ -404,7 +419,6 @@ class Tool(object):
 
     def save_with_script(self, script):
         filename = self.library.get_full_path(self.filename, 'w')
-
         fp = open(filename, 'w', 1)
 
         # Make sure to first print header (shebang, modeline), then
diff --git a/plugins/externaltools/tools/linkparsing.py b/plugins/externaltools/tools/linkparsing.py
index 27b9ba8..33ed614 100755
--- a/plugins/externaltools/tools/linkparsing.py
+++ b/plugins/externaltools/tools/linkparsing.py
@@ -193,7 +193,7 @@ REGEXP_VALAC = r"""
 
 #ruby
 #test.rb:5: ...
-#	from test.rb:3:in `each'
+#   from test.rb:3:in `each'
 # fist line parsed by REGEXP_STANDARD
 REGEXP_RUBY = r"""
 ^\s+from\s
diff --git a/plugins/externaltools/tools/manager.py b/plugins/externaltools/tools/manager.py
index 24d7d71..4da0deb 100755
--- a/plugins/externaltools/tools/manager.py
+++ b/plugins/externaltools/tools/manager.py
@@ -34,7 +34,7 @@ class LanguagesPopup(Gtk.Window):
 
     def __init__(self, languages):
         Gtk.Window.__init__(self, type=Gtk.WindowType.POPUP)
-        
+
         self.set_default_size(200, 200)
         self.props.can_focus = True
 
@@ -42,9 +42,9 @@ class LanguagesPopup(Gtk.Window):
         self.init_languages(languages)
 
         self.show()
-        
+
         self.grab_add()
-        
+
         self.keyboard = None
         device_manager = Gdk.Display.get_device_manager(self.get_window().get_display())
         for device in device_manager.list_devices(Gdk.DeviceType.MASTER):
@@ -76,40 +76,40 @@ class LanguagesPopup(Gtk.Window):
 
     def build(self):
         self.model = Gtk.ListStore(str, str, bool)
-        
+
         self.sw = Gtk.ScrolledWindow()
         self.sw.show()
-        
+
         self.sw.set_policy(Gtk.PolicyType.AUTOMATIC, Gtk.PolicyType.AUTOMATIC)
         self.sw.set_shadow_type(Gtk.ShadowType.ETCHED_IN)
-        
+
         self.view = Gtk.TreeView(self.model)
         self.view.show()
-        
+
         self.view.set_headers_visible(False)
-        
+
         column = Gtk.TreeViewColumn()
-        
+
         renderer = Gtk.CellRendererToggle()
         column.pack_start(renderer, False)
         column.set_attributes(renderer, active=self.COLUMN_ENABLED)
-        
+
         renderer.connect('toggled', self.on_language_toggled)
-        
+
         renderer = Gtk.CellRendererText()
         column.pack_start(renderer, True)
         column.set_attributes(renderer, text=self.COLUMN_NAME)
-        
+
         self.view.append_column(column)
         self.view.set_row_separator_func(self.on_separator)
-        
+
         self.sw.add(self.view)
-        
+
         self.add(self.sw)
-    
+
     def enabled_languages(self, model, path, piter, ret):
         enabled = model.get_value(piter, self.COLUMN_ENABLED)
-        
+
         if path.get_indices()[0] == 0 and enabled:
             return True
 
@@ -117,42 +117,42 @@ class LanguagesPopup(Gtk.Window):
             ret.append(model.get_value(piter, self.COLUMN_ID))
 
         return False
-    
+
     def languages(self):
         ret = []
-        
+
         self.model.foreach(self.enabled_languages, ret)
         return ret
-    
+
     def on_separator(self, model, piter):
         val = model.get_value(piter, self.COLUMN_NAME)
         return val == '-'
-    
+
     def init_languages(self, languages):
         manager = GtkSource.LanguageManager()
         langs = [manager.get_language(x) for x in manager.get_language_ids()]
         langs.sort(key=lambda x: x.get_name())
-        
+
         self.model.append([_('All languages'), None, not languages])
         self.model.append(['-', None, False])
         self.model.append([_('Plain Text'), 'plain', 'plain' in languages])
         self.model.append(['-', None, False])
-        
+
         for lang in langs:
             self.model.append([lang.get_name(), lang.get_id(), lang.get_id() in languages])
 
     def correct_all(self, model, path, piter, enabled):
         if path == (0,):
             return False
-        
+
         model.set_value(piter, self.COLUMN_ENABLED, enabled)
 
     def on_language_toggled(self, renderer, path):
         piter = self.model.get_iter(path)
-        
+
         enabled = self.model.get_value(piter, self.COLUMN_ENABLED)
         self.model.set_value(piter, self.COLUMN_ENABLED, not enabled)
-        
+
         if path == '0':
             self.model.foreach(self.correct_all, False)
         else:
@@ -165,55 +165,55 @@ class LanguagesPopup(Gtk.Window):
         else:
             event.window = self.view.get_bin_window()
             return self.view.event(event)
-    
+
     def do_key_release_event(self, event):
         event.window = self.view.get_bin_window()
         return self.view.event(event)
-    
+
     def in_window(self, event, window=None):
         if not window:
             window = self.get_window()
 
         geometry = window.get_geometry()
         origin = window.get_origin()
-        
+
         return event.x_root >= origin[1] and \
                event.x_root <= origin[1] + geometry[2] and \
                event.y_root >= origin[2] and \
                event.y_root <= origin[2] + geometry[3]
-    
+
     def do_destroy(self):
         if self.keyboard:
             self.keyboard.ungrab(Gdk.CURRENT_TIME)
         self.pointer.ungrab(Gdk.CURRENT_TIME)
-        
+
         return Gtk.Window.do_destroy(self)
-    
+
     def setup_event(self, event, window):
         fr = event.window.get_origin()
         to = window.get_origin()
-        
+
         event.window = window
         event.x += fr[1] - to[1]
         event.y += fr[2] - to[2]
-    
+
     def resolve_widgets(self, root):
         res = [root]
-        
+
         if isinstance(root, Gtk.Container):
             root.forall(lambda x, y: res.extend(self.resolve_widgets(x)), None)
-        
+
         return res
-    
+
     def resolve_windows(self, window):
         if not window:
             return []
 
         res = [window]
         res.extend(window.get_children())
-        
+
         return res
-    
+
     def propagate_mouse_event(self, event, reverse=True):
         allwidgets = self.resolve_widgets(self.get_child())
 
@@ -223,19 +223,19 @@ class LanguagesPopup(Gtk.Window):
         for widget in allwidgets:
             windows = self.resolve_windows(widget.get_window())
             windows.reverse()
-            
+
             for window in windows:
                 if not (window.get_events() & event.type):
                     continue
 
-                if self.in_window(event, window):                    
+                if self.in_window(event, window):
                     self.setup_event(event, window)
 
                     if widget.event(event):
                         return True
-        
+
         return False
-    
+
     def do_button_press_event(self, event):
         if not self.in_window(event):
             self.destroy()
@@ -250,19 +250,19 @@ class LanguagesPopup(Gtk.Window):
 
     def do_scroll_event(self, event):
         return self.propagate_mouse_event(event, False)
-    
+
     def do_motion_notify_event(self, event):
         return self.propagate_mouse_event(event)
-    
+
     def do_enter_notify_event(self, event):
         return self.propagate_mouse_event(event)
 
     def do_leave_notify_event(self, event):
         return self.propagate_mouse_event(event)
-    
+
     def do_proximity_in_event(self, event):
         return self.propagate_mouse_event(event)
-    
+
     def do_proximity_out_event(self, event):
         return self.propagate_mouse_event(event)
 
@@ -281,12 +281,12 @@ class Manager(GObject.Object):
         self._size = (0, 0)
         self._languages = {}
         self._tool_rows = {}
-        
+
         self.build()
 
     def get_final_size(self):
         return self._size
-    
+
     def build(self):
         callbacks = {
             'on_new_tool_button_clicked'      : self.on_new_tool_button_clicked,
@@ -305,42 +305,42 @@ class Manager(GObject.Object):
         self.ui.add_from_file(os.path.join(self.datadir, 'ui', 'tools.ui'))
         self.ui.connect_signals(callbacks)
         self.dialog = self.ui.get_object('tool-manager-dialog')
-        
+
         self.view = self.ui.get_object('view')
-        
+
         self.__init_tools_model()
         self.__init_tools_view()
 
         for name in ['input', 'output', 'applicability', 'save-files']:
             self.__init_combobox(name)
-        
+
         self.do_update()
 
     def expand_from_doc(self, doc):
         row = None
-        
+
         if doc:
             if doc.get_language():
                 lid = doc.get_language().get_id()
-            
+
                 if lid in self._languages:
                     row = self._languages[lid]
             elif 'plain' in self._languages:
                 row = self._languages['plain']
-    
+
         if not row and None in self._languages:
             row = self._languages[None]
-    
+
         if not row:
             return
-        
+
         self.view.expand_row(row.get_path(), False)
         self.view.get_selection().select_path(row.get_path())
-    
+
     def run(self, window):
         if self.dialog == None:
             self.build()
-        
+
         # Open up language
         self.expand_from_doc(window.get_active_document())
 
@@ -351,7 +351,7 @@ class Manager(GObject.Object):
     def add_accelerator(self, item):
         if not item.shortcut:
             return
-        
+
         if item.shortcut in self.accelerators:
             if not item in self.accelerators[item.shortcut]:
                 self.accelerators[item.shortcut].append(item)
@@ -375,42 +375,42 @@ class Manager(GObject.Object):
             lid = language.get_id()
         else:
             lid = language
-            
+
         if not lid in self._languages:
             piter = self.model.append(None, [language])
-            
+
             parent = Gtk.TreeRowReference.new(self.model, self.model.get_path(piter))
             self._languages[lid] = parent
         else:
             parent = self._languages[lid]
-        
+
         piter = self.model.get_iter(parent.get_path())
         child = self.model.append(piter, [tool])
-        
+
         if not tool in self._tool_rows:
             self._tool_rows[tool] = []
-        
+
         self._tool_rows[tool].append(Gtk.TreeRowReference.new(self.model, self.model.get_path(child)))
         return child
 
     def add_tool(self, tool):
         manager = GtkSource.LanguageManager()
         ret = None
-        
+
         for lang in tool.languages:
             l = manager.get_language(lang)
-            
+
             if l:
                 ret = self.add_tool_to_language(tool, l)
             elif lang == 'plain':
                 ret = self.add_tool_to_language(tool, 'plain')
-            
+
         if not ret:
             ret = self.add_tool_to_language(tool, None)
 
         self.add_accelerator(tool)
         return ret
-        
+
     def __init_tools_model(self):
         self.tools = ToolLibrary()
         self.current_node = None
@@ -430,26 +430,26 @@ class Manager(GObject.Object):
         # For languages, sort All before everything else, otherwise alphabetical
         t1 = model.get_value(iter1, self.TOOL_COLUMN)
         t2 = model.get_value(iter2, self.TOOL_COLUMN)
-        
+
         if model.iter_parent(iter1) == None:
             if t1 == None:
                 return -1
-            
+
             if t2 == None:
                 return 1
-            
+
             def lang_name(lang):
                 if isinstance(lang, GtkSource.Language):
                     return lang.get_name()
                 else:
                     return _('Plain Text')
-            
+
             n1 = lang_name(t1)
             n2 = lang_name(t2)
         else:
             n1 = t1.name
             n2 = t2.name
-        
+
         return cmp(n1.lower(), n2.lower())
 
     def __init_tools_view(self):
@@ -459,12 +459,12 @@ class Manager(GObject.Object):
         column.pack_start(renderer, False)
         renderer.set_property('editable', True)
         self.view.append_column(column)
-        
+
         column.set_cell_data_func(renderer, self.get_cell_data_cb, None)
 
         renderer.connect('edited', self.on_view_label_cell_edited)
         renderer.connect('editing-started', self.on_view_label_cell_editing_started)
-        
+
         self.selection_changed_id = self.view.get_selection().connect('changed', self.on_view_selection_changed, None)
 
     def __init_combobox(self, name):
@@ -491,10 +491,10 @@ class Manager(GObject.Object):
 
         if piter is not None:
             tool = model.get_value(piter, self.TOOL_COLUMN)
-            
+
             if not isinstance(tool, Tool):
                 tool = None
-            
+
             return piter, tool
         else:
             return None, None
@@ -541,27 +541,27 @@ class Manager(GObject.Object):
 
         for nm in ('input', 'output', 'applicability', 'save-files'):
             self[nm].set_active(0)
-        
+
         self['languages_label'].set_text(_('All Languages'))
-    
+
     def fill_languages_button(self):
         if not self.current_node or not self.current_node.languages:
             self['languages_label'].set_text(_('All Languages'))
         else:
             manager = GtkSource.LanguageManager()
             langs = []
-            
+
             for lang in self.current_node.languages:
                 if lang == 'plain':
                     langs.append(_('Plain Text'))
                 else:
                     l = manager.get_language(lang)
-                    
+
                     if l:
                         langs.append(l.get_name())
-            
+
             self['languages_label'].set_text(', '.join(langs))
-    
+
     def fill_fields(self):
         node = self.current_node
         self['accelerator'].set_text(default(node.shortcut, ''))
@@ -587,7 +587,7 @@ class Manager(GObject.Object):
         for nm in ('input', 'output', 'applicability', 'save-files'):
             model = self[nm].get_model()
             piter = model.get_iter_first()
-            
+
             self.set_active_by_name(nm,
                                     default(node.__getattribute__(nm.replace('-', '_')),
                                     model.get_value(piter, self.NAME_COLUMN)))
@@ -620,34 +620,34 @@ class Manager(GObject.Object):
             self['tool-table'].set_sensitive(True)
         else:
             self.clear_fields()
-            self['tool-table'].set_sensitive(False)       
+            self['tool-table'].set_sensitive(False)
 
     def language_id_from_iter(self, piter):
         if not piter:
             return None
 
         tool = self.model.get_value(piter, self.TOOL_COLUMN)
-        
+
         if isinstance(tool, Tool):
             piter = self.model.iter_parent(piter)
             tool = self.model.get_value(piter, self.TOOL_COLUMN)
-        
+
         if isinstance(tool, GtkSource.Language):
             return tool.get_id()
         elif tool:
             return 'plain'
-        
+
         return None
 
     def selected_language_id(self):
         # Find current language if there is any
         model, piter = self.view.get_selection().get_selected()
-        
+
         return self.language_id_from_iter(piter)
 
     def on_new_tool_button_clicked(self, button):
         self.save_current_tool()
-        
+
         # block handlers while inserting a new item
         self.view.get_selection().handler_block(self.selection_changed_id)
 
@@ -656,10 +656,10 @@ class Manager(GObject.Object):
         self.tools.tree.tools.append(self.current_node)
 
         lang = self.selected_language_id()
-        
+
         if lang:
             self.current_node.languages = [lang]
-        
+
         piter = self.add_tool(self.current_node)
 
         self.view.set_cursor(self.model.get_path(piter), self.view.get_column(self.TOOL_COLUMN), True)
@@ -671,7 +671,7 @@ class Manager(GObject.Object):
     def tool_changed(self, tool, refresh=False):
         for row in self._tool_rows[tool]:
             self.model.row_changed(row.get_path(), self.model.get_iter(row.get_path()))
-        
+
         if refresh and tool == self.current_node:
             self.fill_fields()
 
@@ -685,29 +685,29 @@ class Manager(GObject.Object):
 
         if node.is_global():
             shortcut = node.shortcut
-            
+
             if node.parent.revert_tool(node):
                 self.remove_accelerator(node, shortcut)
                 self.add_accelerator(node)
 
                 self['revert-tool-button'].set_sensitive(False)
                 self.fill_fields()
-                
+
                 self.tool_changed(node)
         else:
             parent = self.model.iter_parent(piter)
             language = self.language_id_from_iter(parent)
-            
+
             self.model.remove(piter)
-            
+
             if language in node.languages:
                 node.languages.remove(language)
 
             self._tool_rows[node] = filter(lambda x: x.valid(), self._tool_rows[node])
-            
+
             if not self._tool_rows[node]:
                 del self._tool_rows[node]
-                
+
                 if node.parent.delete_tool(node):
                     self.remove_accelerator(node)
                     self.current_node = None
@@ -717,10 +717,10 @@ class Manager(GObject.Object):
                         self.view.set_cursor(self.model.get_path(piter), self.view.get_column(self.TOOL_COLUMN), False)
 
                 self.view.grab_focus()
-            
+
             path = self._languages[language].get_path()
             parent = self.model.get_iter(path)
-            
+
             if not self.model.iter_has_child(parent):
                 self.model.remove(parent)
                 del self._languages[language]
@@ -729,9 +729,9 @@ class Manager(GObject.Object):
         if new_text != '':
             piter = self.model.get_iter(path)
             tool = self.model.get_value(piter, self.TOOL_COLUMN)
-            
+
             tool.name = new_text
-            
+
             self.save_current_tool()
             self.tool_changed(tool)
 
@@ -742,7 +742,7 @@ class Manager(GObject.Object):
             if isinstance(editable, Gtk.Entry):
                 editable.set_text(tool.name)
                 editable.grab_focus()
-    
+
     def on_view_selection_changed(self, selection, userdata):
         self.save_current_tool()
         self.do_update()
@@ -750,19 +750,19 @@ class Manager(GObject.Object):
     def accelerator_collision(self, name, node):
         if not name in self.accelerators:
             return []
-            
+
         ret = []
-        
+
         for other in self.accelerators[name]:
             if not other.languages or not node.languages:
                 ret.append(other)
                 continue
-            
+
             for lang in other.languages:
                 if lang in node.languages:
                     ret.append(other)
                     continue
-        
+
         return ret
 
     def set_accelerator(self, keyval, mod):
@@ -775,9 +775,9 @@ class Manager(GObject.Object):
             self.current_node.shorcut = None
             self.save_current_tool()
             return True
-            
+
         col = self.accelerator_collision(name, self.current_node)
-        
+
         if col:
             dialog = Gtk.MessageDialog(self.dialog,
                                        Gtk.DialogFlags.MODAL,
@@ -787,7 +787,7 @@ class Manager(GObject.Object):
 
             dialog.run()
             dialog.destroy()
-            
+
             self.add_accelerator(self.current_node)
             return False
 
@@ -816,7 +816,7 @@ class Manager(GObject.Object):
             if self.set_accelerator(event.keyval, mask):
                 entry.set_text(default(self.current_node.shortcut, ''))
                 self['commands'].grab_focus()
-    
+
             # Capture all `normal characters`
             return True
         elif Gdk.keyval_to_unicode(event.keyval):
@@ -849,7 +849,7 @@ class Manager(GObject.Object):
             return
 
         self.on_tool_manager_dialog_focus_out(dialog, None)
-        
+
         self.dialog.destroy()
         self.dialog = None
         self.tools = None
@@ -873,7 +873,7 @@ class Manager(GObject.Object):
                 label = _('Plain Text')
             else:
                 label = tool.get_name()
-                
+
             markup = saxutils.escape(label)
             editable = False
         else:
@@ -885,7 +885,7 @@ class Manager(GObject.Object):
                 markup = escaped
 
             editable = True
-            
+
         cell.set_properties(markup=markup, editable=editable)
 
     def tool_in_language(self, tool, lang):
@@ -894,84 +894,84 @@ class Manager(GObject.Object):
 
         ref = self._languages[lang]
         parent = ref.get_path()
-        
+
         for row in self._tool_rows[tool]:
             path = row.get_path()
-            
+
             if path.get_indices()[0] == parent.get_indices()[0]:
                 return True
-        
+
         return False
 
     def update_languages(self, popup):
         self.current_node.languages = popup.languages()
         self.fill_languages_button()
-        
+
         piter, node = self.get_selected_tool()
         ret = None
-        
+
         if node:
             ref = Gtk.TreeRowReference(self.model, self.model.get_path(piter))
-        
+
         # Update languages, make sure to inhibit selection change stuff
         self.view.get_selection().handler_block(self.selection_changed_id)
-        
+
         # Remove all rows that are no longer
         for row in list(self._tool_rows[self.current_node]):
             piter = self.model.get_iter(row.get_path())
             language = self.language_id_from_iter(piter)
-            
+
             if (not language and not self.current_node.languages) or \
                (language in self.current_node.languages):
                 continue
-            
+
             # Remove from language
             self.model.remove(piter)
             self._tool_rows[self.current_node].remove(row)
-            
+
             # If language is empty, remove it
             parent = self.model.get_iter(self._languages[language].get_path())
-            
+
             if not self.model.iter_has_child(parent):
                 self.model.remove(parent)
                 del self._languages[language]
-        
+
         # Now, add for any that are new
         manager = GtkSource.LanguageManager()
-        
+
         for lang in self.current_node.languages:
             if not self.tool_in_language(self.current_node, lang):
                 l = manager.get_language(lang)
-                
+
                 if not l:
                     l = 'plain'
-                    
+
                 self.add_tool_to_language(self.current_node, l)
-        
+
         if not self.current_node.languages and not self.tool_in_language(self.current_node, None):
             self.add_tool_to_language(self.current_node, None)
-        
+
         # Check if we can still keep the current
         if not ref or not ref.valid():
             # Change selection to first language
             path = self._tool_rows[self.current_node][0].get_path()
             piter = self.model.get_iter(path)
             parent = self.model.iter_parent(piter)
-            
+
             # Expand parent, select child and scroll to it
             self.view.expand_row(self.model.get_path(parent), False)
             self.view.get_selection().select_path(path)
             self.view.set_cursor(path, self.view.get_column(self.TOOL_COLUMN), False)
-        
+
         self.view.get_selection().handler_unblock(self.selection_changed_id)
 
     def on_languages_button_clicked(self, button):
         popup = LanguagesPopup(self.current_node.languages)
         popup.set_transient_for(self.dialog)
-        
+
         origin = button.get_window().get_origin()
         popup.move(origin[1], origin[2] - popup.get_allocation().height)
-        
+
         popup.connect('destroy', self.update_languages)
 
 # ex:et:ts=4:
diff --git a/plugins/externaltools/tools/outputpanel.py b/plugins/externaltools/tools/outputpanel.py
index 9613d78..e063eb2 100755
--- a/plugins/externaltools/tools/outputpanel.py
+++ b/plugins/externaltools/tools/outputpanel.py
@@ -129,11 +129,11 @@ class OutputPanel(UniqueById):
         # find all links and apply the appropriate tag for them
         links = self.link_parser.parse(text)
         for lnk in links:
-            
+
             insert_iter = buffer.get_iter_at_mark(insert)
             lnk.start = insert_iter.get_offset() + lnk.start
             lnk.end = insert_iter.get_offset() + lnk.end
-            
+
             start_iter = buffer.get_iter_at_offset(lnk.start)
             end_iter = buffer.get_iter_at_offset(lnk.end)
 
@@ -156,7 +156,7 @@ class OutputPanel(UniqueById):
         panel.show()
         panel.activate_item(self.panel)
 
-    def update_cursor_style(self, view, x, y):       
+    def update_cursor_style(self, view, x, y):
         if self.get_link_at_location(view, x, y) is not None:
             cursor = self.link_cursor
         else:
diff --git a/plugins/pythonconsole/pythonconsole/__init__.py b/plugins/pythonconsole/pythonconsole/__init__.py
index 59ac413..07d13c7 100755
--- a/plugins/pythonconsole/pythonconsole/__init__.py
+++ b/plugins/pythonconsole/pythonconsole/__init__.py
@@ -8,7 +8,7 @@
 # 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
diff --git a/plugins/quickopen/quickopen/__init__.py b/plugins/quickopen/quickopen/__init__.py
old mode 100755
new mode 100644
index 54e9598..3ae72a4
--- a/plugins/quickopen/quickopen/__init__.py
+++ b/plugins/quickopen/quickopen/__init__.py
@@ -21,30 +21,30 @@ from gi.repository import GObject, Peas
 from windowhelper import WindowHelper
 
 class QuickOpenPlugin(GObject.Object, Peas.Activatable):
-        __gtype_name__ = "QuickOpenPlugin"
+    __gtype_name__ = "QuickOpenPlugin"
 
-        object = GObject.Property(type=GObject.Object)
+    object = GObject.Property(type=GObject.Object)
 
-        def __init__(self):
-                GObject.Object.__init__(self)
+    def __init__(self):
+        GObject.Object.__init__(self)
 
-                self._popup_size = (450, 300)
+        self._popup_size = (450, 300)
 
-        def do_activate(self):
-                window = self.object
-                self._helper = WindowHelper(window, self)
+    def do_activate(self):
+        window = self.object
+        self._helper = WindowHelper(window, self)
 
-        def do_deactivate(self):
-                self._helper.deactivate()
-                self._helper = None
+    def do_deactivate(self):
+        self._helper.deactivate()
+        self._helper = None
 
-        def do_update_state(self):
-                self._helper.update_ui()
+    def do_update_state(self):
+        self._helper.update_ui()
 
-        def get_popup_size(self):
-                return self._popup_size
+    def get_popup_size(self):
+        return self._popup_size
 
-        def set_popup_size(self, size):
-                self._popup_size = size
+    def set_popup_size(self, size):
+        self._popup_size = size
 
-# ex:ts=8:et:
+# ex:ts=4:et:
diff --git a/plugins/quickopen/quickopen/popup.py b/plugins/quickopen/quickopen/popup.py
old mode 100755
new mode 100644
index b571b68..c6cc801
--- a/plugins/quickopen/quickopen/popup.py
+++ b/plugins/quickopen/quickopen/popup.py
@@ -24,533 +24,532 @@ from gi.repository import GObject, Gio, GLib, Gdk, Gtk, Pango, Pluma
 from virtualdirs import VirtualDirectory
 
 class Popup(Gtk.Dialog):
-        __gtype_name__ = "QuickOpenPopup"
+    __gtype_name__ = "QuickOpenPopup"
 
-        def __init__(self, window, paths, handler):
-                Gtk.Dialog.__init__(self,
-                                    title=_('Quick Open'),
-                                    parent=window,
-                                    flags=Gtk.DialogFlags.DESTROY_WITH_PARENT | Gtk.DialogFlags.MODAL,
-                                    buttons=(Gtk.STOCK_CANCEL, Gtk.ResponseType.CANCEL))
+    def __init__(self, window, paths, handler):
+        Gtk.Dialog.__init__(self,
+                            title=_('Quick Open'),
+                            parent=window,
+                            flags=Gtk.DialogFlags.DESTROY_WITH_PARENT | Gtk.DialogFlags.MODAL,
+                            buttons=(Gtk.STOCK_CANCEL, Gtk.ResponseType.CANCEL))
 
-                self._open_button = self.add_button(Gtk.STOCK_OPEN, Gtk.ResponseType.ACCEPT)
+        self._open_button = self.add_button(Gtk.STOCK_OPEN, Gtk.ResponseType.ACCEPT)
 
-                self._handler = handler
-                self._build_ui()
+        self._handler = handler
+        self._build_ui()
 
-                self._size = (0, 0)
-                self._dirs = []
-                self._cache = {}
-                self._theme = None
-                self._cursor = None
-                self._shift_start = None
+        self._size = (0, 0)
+        self._dirs = []
+        self._cache = {}
+        self._theme = None
+        self._cursor = None
+        self._shift_start = None
 
-                self._busy_cursor = Gdk.Cursor(Gdk.CursorType.WATCH)
+        self._busy_cursor = Gdk.Cursor(Gdk.CursorType.WATCH)
 
-                accel_group = Gtk.AccelGroup()
-                accel_group.connect(Gdk.KEY_l, Gdk.ModifierType.CONTROL_MASK, 0, self.on_focus_entry)
+        accel_group = Gtk.AccelGroup()
+        accel_group.connect(Gdk.KEY_l, Gdk.ModifierType.CONTROL_MASK, 0, self.on_focus_entry)
 
-                self.add_accel_group(accel_group)
+        self.add_accel_group(accel_group)
 
-                unique = []
+        unique = []
 
-                for path in paths:
-                        if not path.get_uri() in unique:
-                                self._dirs.append(path)
-                                unique.append(path.get_uri())
+        for path in paths:
+            if not path.get_uri() in unique:
+                self._dirs.append(path)
+                unique.append(path.get_uri())
 
-        def get_final_size(self):
-                return self._size
+    def get_final_size(self):
+        return self._size
 
-        def _build_ui(self):
-                vbox = self.get_content_area()
-                vbox.set_spacing(3)
+    def _build_ui(self):
+        vbox = self.get_content_area()
+        vbox.set_spacing(3)
 
-                self._entry = Gtk.Entry()
+        self._entry = Gtk.Entry()
 
-                self._entry.connect('changed', self.on_changed)
-                self._entry.connect('key-press-event', self.on_key_press_event)
+        self._entry.connect('changed', self.on_changed)
+        self._entry.connect('key-press-event', self.on_key_press_event)
 
-                sw = Gtk.ScrolledWindow()
-                sw.set_policy(Gtk.PolicyType.AUTOMATIC, Gtk.PolicyType.AUTOMATIC)
-                sw.set_shadow_type(Gtk.ShadowType.OUT)
+        sw = Gtk.ScrolledWindow()
+        sw.set_policy(Gtk.PolicyType.AUTOMATIC, Gtk.PolicyType.AUTOMATIC)
+        sw.set_shadow_type(Gtk.ShadowType.OUT)
 
-                tv = Gtk.TreeView()
-                tv.set_headers_visible(False)
+        tv = Gtk.TreeView()
+        tv.set_headers_visible(False)
 
-                self._store = Gtk.ListStore(Gio.Icon, str, GObject.Object, Gio.FileType)
-                tv.set_model(self._store)
+        self._store = Gtk.ListStore(Gio.Icon, str, GObject.Object, Gio.FileType)
+        tv.set_model(self._store)
 
-                self._treeview = tv
-                tv.connect('row-activated', self.on_row_activated)
+        self._treeview = tv
+        tv.connect('row-activated', self.on_row_activated)
 
-                renderer = Gtk.CellRendererPixbuf()
-                column = Gtk.TreeViewColumn()
-                column.pack_start(renderer, False)
-                column.add_attribute(renderer, "gicon", 0)
+        renderer = Gtk.CellRendererPixbuf()
+        column = Gtk.TreeViewColumn()
+        column.pack_start(renderer, False)
+        column.add_attribute(renderer, "gicon", 0)
 
-                renderer = Gtk.CellRendererText()
-                column.pack_start(renderer, True)
-                column.add_attribute(renderer, "markup", 1)
+        renderer = Gtk.CellRendererText()
+        column.pack_start(renderer, True)
+        column.add_attribute(renderer, "markup", 1)
 
-                column.set_cell_data_func(renderer, self.on_cell_data_cb, None)
+        column.set_cell_data_func(renderer, self.on_cell_data_cb, None)
 
-                tv.append_column(column)
-                sw.add(tv)
-                
-                selection = tv.get_selection()
-                selection.connect('changed', self.on_selection_changed)
-                selection.set_mode(Gtk.SelectionMode.MULTIPLE)
+        tv.append_column(column)
+        sw.add(tv)
 
-                vbox.pack_start(self._entry, False, False, 0)
-                vbox.pack_start(sw, True, True, 0)
+        selection = tv.get_selection()
+        selection.connect('changed', self.on_selection_changed)
+        selection.set_mode(Gtk.SelectionMode.MULTIPLE)
 
-                lbl = Gtk.Label()
-                lbl.set_alignment(0, 0.5)
-                lbl.set_ellipsize(Pango.EllipsizeMode.MIDDLE)
-                self._info_label = lbl
+        vbox.pack_start(self._entry, False, False, 0)
+        vbox.pack_start(sw, True, True, 0)
 
-                vbox.pack_start(lbl, False, False, 0)
+        lbl = Gtk.Label()
+        lbl.set_alignment(0, 0.5)
+        lbl.set_ellipsize(Pango.EllipsizeMode.MIDDLE)
+        self._info_label = lbl
 
-                # Initial selection
-                self.on_selection_changed(tv.get_selection())
-                vbox.show_all()
+        vbox.pack_start(lbl, False, False, 0)
 
-        def on_cell_data_cb(self, column, cell, model, piter, user_data):
-                path = model.get_path(piter)
-                
-                if self._cursor and path == self._cursor.get_path():
-                        style = self._treeview.get_style()
-                        bg = style.bg[Gtk.StateType.PRELIGHT]
-                        
-                        cell.set_property('cell-background-gdk', bg)
-                        cell.set_property('style', Pango.Style.ITALIC)
-                else:
-                        cell.set_property('cell-background-set', False)
-                        cell.set_property('style-set', False)
+        # Initial selection
+        self.on_selection_changed(tv.get_selection())
+        vbox.show_all()
 
-        def _icon_from_stock(self, stock):
-                theme = Gtk.icon_theme_get_default()
-                size = Gtk.icon_size_lookup(Gtk.IconSize.MENU)
-                pixbuf = theme.load_icon(stock, size[0], Gtk.IconLookupFlags.USE_BUILTIN)
+    def on_cell_data_cb(self, column, cell, model, piter, user_data):
+        path = model.get_path(piter)
 
-                return pixbuf
+        if self._cursor and path == self._cursor.get_path():
+            style = self._treeview.get_style()
+            bg = style.bg[Gtk.StateType.PRELIGHT]
 
-        def _list_dir(self, gfile):
-                entries = []
+            cell.set_property('cell-background-gdk', bg)
+            cell.set_property('style', Pango.Style.ITALIC)
+        else:
+            cell.set_property('cell-background-set', False)
+            cell.set_property('style-set', False)
 
-                try:
-                        ret = gfile.enumerate_children("standard::*", Gio.FileQueryInfoFlags.NONE, None)
-                except GLib.GError:
-                        pass
+    def _icon_from_stock(self, stock):
+        theme = Gtk.icon_theme_get_default()
+        size = Gtk.icon_size_lookup(Gtk.IconSize.MENU)
+        pixbuf = theme.load_icon(stock, size[0], Gtk.IconLookupFlags.USE_BUILTIN)
 
-                if isinstance(ret, Gio.FileEnumerator):
-                        while True:
-                                entry = ret.next_file(None)
+        return pixbuf
 
-                                if not entry:
-                                        break
+    def _list_dir(self, gfile):
+        entries = []
 
-                                entries.append((gfile.get_child(entry.get_name()), entry))
-                else:
-                        entries = ret
+        try:
+            ret = gfile.enumerate_children("standard::*", Gio.FileQueryInfoFlags.NONE, None)
+        except GLib.GError:
+            pass
 
-                children = []
+        if isinstance(ret, Gio.FileEnumerator):
+            while True:
+                entry = ret.next_file(None)
 
-                for entry in entries:
-                        children.append((entry[0], entry[1].get_name(), entry[1].get_file_type(), entry[1].get_icon()))
+                if not entry:
+                    break
 
-                return children
+                entries.append((gfile.get_child(entry.get_name()), entry))
+        else:
+            entries = ret
 
-        def _compare_entries(self, a, b, lpart):
-                if lpart in a:
-                        if lpart in b:
-                                return cmp(a.index(lpart), b.index(lpart))
-                        else:
-                                return -1
-                elif lpart in b:
-                        return 1
-                else:
-                        return 0
+        children = []
 
-        def _match_glob(self, s, glob):
-                if glob:
-                        glob += '*'
+        for entry in entries:
+            children.append((entry[0], entry[1].get_name(), entry[1].get_file_type(), entry[1].get_icon()))
 
-                return fnmatch.fnmatch(s, glob)
+        return children
 
-        def do_search_dir(self, parts, d):
-                if not parts or not d:
-                        return []
+    def _compare_entries(self, a, b, lpart):
+        if lpart in a:
+            if lpart in b:
+                return cmp(a.index(lpart), b.index(lpart))
+            else:
+                return -1
+        elif lpart in b:
+            return 1
+        else:
+            return 0
 
-                if not d in self._cache:
-                        entries = self._list_dir(d)
-                        entries.sort(lambda x, y: cmp(x[1].lower(), y[1].lower()))
+    def _match_glob(self, s, glob):
+        if glob:
+            glob += '*'
 
-                        self._cache[d] = entries
-                else:
-                        entries = self._cache[d]
+        return fnmatch.fnmatch(s, glob)
 
-                found = []
-                newdirs = []
+    def do_search_dir(self, parts, d):
+        if not parts or not d:
+            return []
 
-                lpart = parts[0].lower()
+        if not d in self._cache:
+            entries = self._list_dir(d)
+            entries.sort(lambda x, y: cmp(x[1].lower(), y[1].lower()))
 
-                for entry in entries:
-                        if not entry:
-                                continue
+            self._cache[d] = entries
+        else:
+            entries = self._cache[d]
 
-                        lentry = entry[1].lower()
+        found = []
+        newdirs = []
 
-                        if not lpart or lpart in lentry or self._match_glob(lentry, lpart):
-                                if entry[2] == Gio.FileType.DIRECTORY:
-                                        if len(parts) > 1:
-                                                newdirs.append(entry[0])
-                                        else:
-                                                found.append(entry)
-                                elif entry[2] == Gio.FileType.REGULAR and \
-                                     (not lpart or len(parts) == 1):
-                                        found.append(entry)
+        lpart = parts[0].lower()
 
-                found.sort(lambda a, b: self._compare_entries(a[1].lower(), b[1].lower(), lpart))
+        for entry in entries:
+            if not entry:
+                continue
 
-                if lpart == '..':
-                        newdirs.append(d.get_parent())
+            lentry = entry[1].lower()
 
-                for dd in newdirs:
-                        found.extend(self.do_search_dir(parts[1:], dd))
+            if not lpart or lpart in lentry or self._match_glob(lentry, lpart):
+                if entry[2] == Gio.FileType.DIRECTORY:
+                    if len(parts) > 1:
+                        newdirs.append(entry[0])
+                    else:
+                        found.append(entry)
+                elif entry[2] == Gio.FileType.REGULAR and \
+                        (not lpart or len(parts) == 1):
+                    found.append(entry)
 
-                return found
+        found.sort(lambda a, b: self._compare_entries(a[1].lower(), b[1].lower(), lpart))
 
-        def _replace_insensitive(self, s, find, rep):
-                out = ''
-                l = s.lower()
-                find = find.lower()
-                last = 0
+        if lpart == '..':
+            newdirs.append(d.get_parent())
 
-                if len(find) == 0:
-                        return xml.sax.saxutils.escape(s)
+        for dd in newdirs:
+            found.extend(self.do_search_dir(parts[1:], dd))
 
-                while True:
-                        m = l.find(find, last)
+        return found
 
-                        if m == -1:
-                                break
-                        else:
-                                out += xml.sax.saxutils.escape(s[last:m]) + rep % (xml.sax.saxutils.escape(s[m:m + len(find)]),)
-                                last = m + len(find)
+    def _replace_insensitive(self, s, find, rep):
+        out = ''
+        l = s.lower()
+        find = find.lower()
+        last = 0
 
-                return out + xml.sax.saxutils.escape(s[last:])
+        if len(find) == 0:
+            return xml.sax.saxutils.escape(s)
 
+        while True:
+            m = l.find(find, last)
 
-        def make_markup(self, parts, path):
-                out = []
+            if m == -1:
+                break
+            else:
+                out += xml.sax.saxutils.escape(s[last:m]) + rep % (xml.sax.saxutils.escape(s[m:m + len(find)]),)
+                last = m + len(find)
 
-                for i in range(0, len(parts)):
-                        out.append(self._replace_insensitive(path[i], parts[i], "<b>%s</b>"))
+        return out + xml.sax.saxutils.escape(s[last:])
 
-                return os.sep.join(out)
+    def make_markup(self, parts, path):
+        out = []
 
-        def _get_icon(self, f):
-                query = f.query_info(Gio.FILE_ATTRIBUTE_STANDARD_ICON, Gio.FileQueryInfoFlags.NONE, None)
+        for i in range(0, len(parts)):
+            out.append(self._replace_insensitive(path[i], parts[i], "<b>%s</b>"))
 
-                if not query:
-                        return None
-                else:
-                        return query.get_icon()
+        return os.sep.join(out)
 
-        def _make_parts(self, parent, child, pp):
-                parts = []
+    def _get_icon(self, f):
+        query = f.query_info(Gio.FILE_ATTRIBUTE_STANDARD_ICON, Gio.FileQueryInfoFlags.NONE, None)
 
-                # We went from parent, to child, using pp
-                idx = len(pp) - 1
+        if not query:
+            return None
+        else:
+            return query.get_icon()
 
-                while idx >= 0:
-                        if pp[idx] == '..':
-                                parts.insert(0, '..')
-                        else:
-                                parts.insert(0, child.get_basename())
-                                child = child.get_parent()
+    def _make_parts(self, parent, child, pp):
+        parts = []
 
-                        idx -= 1
+        # We went from parent, to child, using pp
+        idx = len(pp) - 1
 
-                return parts
+        while idx >= 0:
+            if pp[idx] == '..':
+                parts.insert(0, '..')
+            else:
+                parts.insert(0, child.get_basename())
+                child = child.get_parent()
 
-        def normalize_relative(self, parts):
-                if not parts:
-                        return []
+            idx -= 1
 
-                out = self.normalize_relative(parts[:-1])
+        return parts
 
-                if parts[-1] == '..':
-                        if not out or (out[-1] == '..') or len(out) == 1:
-                                out.append('..')
-                        else:
-                                del out[-1]
-                else:
-                        out.append(parts[-1])
+    def normalize_relative(self, parts):
+        if not parts:
+            return []
 
-                return out
+        out = self.normalize_relative(parts[:-1])
 
-        def _append_to_store(self, item):
-                if not item in self._stored_items:
-                        self._store.append(item)
-                        self._stored_items[item] = True
+        if parts[-1] == '..':
+            if not out or (out[-1] == '..') or len(out) == 1:
+                out.append('..')
+            else:
+                del out[-1]
+        else:
+            out.append(parts[-1])
 
-        def _clear_store(self):
-                self._store.clear()
-                self._stored_items = {}
+        return out
 
-        def _show_virtuals(self):
-                for d in self._dirs:
-                        if isinstance(d, VirtualDirectory):
-                                for entry in d.enumerate_children("standard::*", 0, None):
-                                        self._append_to_store((entry[1].get_icon(), xml.sax.saxutils.escape(entry[1].get_name()), entry[0], entry[1].get_file_type()))
+    def _append_to_store(self, item):
+        if not item in self._stored_items:
+            self._store.append(item)
+            self._stored_items[item] = True
 
-        def _set_busy(self, busy):
-                if busy:
-                        self.get_window().set_cursor(self._busy_cursor)
-                else:
-                        self.get_window().set_cursor(None)
+    def _clear_store(self):
+        self._store.clear()
+        self._stored_items = {}
 
-                Gdk.flush()
+    def _show_virtuals(self):
+        for d in self._dirs:
+            if isinstance(d, VirtualDirectory):
+                for entry in d.enumerate_children("standard::*", 0, None):
+                    self._append_to_store((entry[1].get_icon(), xml.sax.saxutils.escape(entry[1].get_name()), entry[0], entry[1].get_file_type()))
 
-        def _remove_cursor(self):
-                if self._cursor:
-                        path = self._cursor.get_path()
-                        self._cursor = None
+    def _set_busy(self, busy):
+        if busy:
+            self.get_window().set_cursor(self._busy_cursor)
+        else:
+            self.get_window().set_cursor(None)
 
-                        self._store.row_changed(path, self._store.get_iter(path))
+        Gdk.flush()
 
-        def do_search(self):
-                self._set_busy(True)
-                self._remove_cursor()
+    def _remove_cursor(self):
+        if self._cursor:
+            path = self._cursor.get_path()
+            self._cursor = None
 
-                text = self._entry.get_text().strip()
-                self._clear_store()
+            self._store.row_changed(path, self._store.get_iter(path))
 
-                if text == '':
-                        self._show_virtuals()
-                else:
-                        parts = self.normalize_relative(text.split(os.sep))
-                        files = []
+    def do_search(self):
+        self._set_busy(True)
+        self._remove_cursor()
 
-                        for d in self._dirs:
-                                for entry in self.do_search_dir(parts, d):
-                                        pathparts = self._make_parts(d, entry[0], parts)
-                                        self._append_to_store((entry[3], self.make_markup(parts, pathparts), entry[0], entry[2]))
+        text = self._entry.get_text().strip()
+        self._clear_store()
 
-                piter = self._store.get_iter_first()
+        if text == '':
+            self._show_virtuals()
+        else:
+            parts = self.normalize_relative(text.split(os.sep))
+            files = []
 
-                if piter:
-                        self._treeview.get_selection().select_path(self._store.get_path(piter))
+            for d in self._dirs:
+                for entry in self.do_search_dir(parts, d):
+                    pathparts = self._make_parts(d, entry[0], parts)
+                    self._append_to_store((entry[3], self.make_markup(parts, pathparts), entry[0], entry[2]))
 
-                self.get_window().set_cursor(None)
-                self._set_busy(False)
+        piter = self._store.get_iter_first()
 
-        def do_show(self):
-                Gtk.Window.do_show(self)
+        if piter:
+            self._treeview.get_selection().select_path(self._store.get_path(piter))
 
-                self._entry.grab_focus()
-                self._entry.set_text("")
-
-                self.do_search()
-
-        def on_changed(self, editable):
-                self.do_search()
-                self.on_selection_changed(self._treeview.get_selection())
-
-        def _shift_extend(self, towhere):
-                selection = self._treeview.get_selection()
-                
-                if not self._shift_start:
-                        model, rows = selection.get_selected_rows()
-                        start = rows[0]
-
-                        self._shift_start = Gtk.TreeRowReference(self._store, start)
-                else:
-                        start = self._shift_start.get_path()
-
-                selection.unselect_all()
-                selection.select_range(start, towhere)
-
-        def _select_index(self, idx, hasctrl, hasshift):
-                path = (idx,)
-                
-                if not (hasctrl or hasshift):
-                        self._treeview.get_selection().unselect_all()
-                
-                if hasshift:
-                        self._shift_extend(path)
-                else:
-                        self._shift_start = None
-                        
-                        if not hasctrl:
-                                self._treeview.get_selection().select_path(path)
-
-                self._treeview.scroll_to_cell(path, None, True, 0.5, 0)
-                self._remove_cursor()
-
-                if hasctrl or hasshift:
-                        self._cursor = Gtk.TreeRowReference(self._store, path)
-                        
-                        piter = self._store.get_iter(path)
-                        self._store.row_changed(path, piter)
-
-        def _move_selection(self, howmany, hasctrl, hasshift):
-                num = self._store.iter_n_children(None)
-
-                if num == 0:
-                        return True
-
-                # Test for cursor
-                path = None
-                
-                if self._cursor:
-                        path = self._cursor.get_path()
-                else:
-                        model, rows = self._treeview.get_selection().get_selected_rows()
-                        
-                        if len(rows) == 1:
-                                path = rows[0]
-
-                if not path:
-                        if howmany > 0:
-                                self._select_index(0, hasctrl, hasshift)
-                        else:
-                                self._select_index(num - 1, hasctrl, hasshift)
-                else:
-                        idx = path[0]
-
-                        if idx + howmany < 0:
-                                self._select_index(0, hasctrl, hasshift)
-                        elif idx + howmany >= num:
-                                self._select_index(num - 1, hasctrl, hasshift)
-                        else:
-                                self._select_index(idx + howmany, hasctrl, hasshift)
+        self.get_window().set_cursor(None)
+        self._set_busy(False)
 
-                return True
+    def do_show(self):
+        Gtk.Window.do_show(self)
+
+        self._entry.grab_focus()
+        self._entry.set_text("")
+
+        self.do_search()
+
+    def on_changed(self, editable):
+        self.do_search()
+        self.on_selection_changed(self._treeview.get_selection())
+
+    def _shift_extend(self, towhere):
+        selection = self._treeview.get_selection()
+
+        if not self._shift_start:
+            model, rows = selection.get_selected_rows()
+            start = rows[0]
+
+            self._shift_start = Gtk.TreeRowReference(self._store, start)
+        else:
+            start = self._shift_start.get_path()
+
+        selection.unselect_all()
+        selection.select_range(start, towhere)
+
+    def _select_index(self, idx, hasctrl, hasshift):
+        path = (idx,)
+
+        if not (hasctrl or hasshift):
+            self._treeview.get_selection().unselect_all()
+
+        if hasshift:
+            self._shift_extend(path)
+        else:
+            self._shift_start = None
+
+            if not hasctrl:
+                self._treeview.get_selection().select_path(path)
+
+        self._treeview.scroll_to_cell(path, None, True, 0.5, 0)
+        self._remove_cursor()
+
+        if hasctrl or hasshift:
+            self._cursor = Gtk.TreeRowReference(self._store, path)
+
+            piter = self._store.get_iter(path)
+            self._store.row_changed(path, piter)
+
+    def _move_selection(self, howmany, hasctrl, hasshift):
+        num = self._store.iter_n_children(None)
 
-        def _direct_file(self):
-                uri = self._entry.get_text()
-                gfile = None
-
-                if Pluma.utils_is_valid_uri(uri):
-                        gfile = Gio.file_new_for_uri(uri)
-                elif os.path.isabs(uri):
-                        f = Gio.file_new_for_uri(uri)
-
-                        if f.query_exists():
-                                gfile = f
-
-                return gfile
-
-        def _activate(self):
-                model, rows = self._treeview.get_selection().get_selected_rows()
-                ret = True
-                
-                for row in rows:
-                        s = model.get_iter(row)
-                        info = model.get(s, 2, 3)
-
-                        if info[1] != Gio.FileType.DIRECTORY:
-                                ret = ret and self._handler(info[0])
-                        else:
-                                text = self._entry.get_text()
-
-                                for i in range(len(text) - 1, -1, -1):
-                                        if text[i] == os.sep:
-                                                break
-
-                                self._entry.set_text(os.path.join(text[:i], os.path.basename(info[0].get_uri())) + os.sep)
-                                self._entry.set_position(-1)
-                                self._entry.grab_focus()
-                                return True
-
-                if rows and ret:
-                        self.destroy()
-
-                if not rows:
-                        gfile = self._direct_file()
-
-                        if gfile and self._handler(gfile):
-                                self.destroy()
-                        else:
-                                ret = False
-                else:
-                        ret = False
-
-                return ret
-
-        def toggle_cursor(self):
-                if not self._cursor:
-                        return
-                
-                path = self._cursor.get_path()
-                selection = self._treeview.get_selection()
-                
-                if selection.path_is_selected(path):
-                        selection.unselect_path(path)
-                else:
-                        selection.select_path(path)
-
-        def on_key_press_event(self, widget, event):
-                move_mapping = {
-                        Gdk.KEY_Down: 1,
-                        Gdk.KEY_Up: -1,
-                        Gdk.KEY_Page_Down: 5,
-                        Gdk.KEY_Page_Up: -5
-                }
-                
-                if event.keyval == Gdk.KEY_Escape:
-                        self.destroy()
-                        return True
-                elif event.keyval in move_mapping:
-                        return self._move_selection(move_mapping[event.keyval], event.state & Gdk.ModifierType.CONTROL_MASK, event.state & Gdk.ModifierType.SHIFT_MASK)
-                elif event.keyval in [Gdk.KEY_Return, Gdk.KEY_KP_Enter, Gdk.KEY_Tab, Gdk.KEY_ISO_Left_Tab]:
-                        return self._activate()
-                elif event.keyval == Gdk.KEY_space and event.state & Gdk.ModifierType.CONTROL_MASK:
-                        self.toggle_cursor()
-
-                return False
-
-        def on_row_activated(self, view, path, column):
-                self._activate()
-
-        def do_response(self, response):
-                if response != Gtk.ResponseType.ACCEPT or not self._activate():
-                        self.destroy()
-
-        def do_configure_event(self, event):
-                if self.get_realized():
-                        alloc = self.get_allocation()
-                        self._size = (alloc.width, alloc.height)
-
-                return Gtk.Dialog.do_configure_event(self, event)
-
-        def on_selection_changed(self, selection):
-                model, rows = selection.get_selected_rows()
-                
-                gfile = None
-                fname = None
-
-                if not rows:
-                        gfile = self._direct_file()
-                elif len(rows) == 1:
-                        gfile = model.get(model.get_iter(rows[0]), 2)[0]
-                else:
-                        fname = ''
-
-                if gfile:
-                        if gfile.is_native():
-                                fname = xml.sax.saxutils.escape(gfile.get_path())
-                        else:
-                                fname = xml.sax.saxutils.escape(gfile.get_uri())
-
-                self._open_button.set_sensitive(fname != None)
-                self._info_label.set_markup(fname or '')
-
-        def on_focus_entry(self, group, accel, keyval, modifier):
+        if num == 0:
+            return True
+
+        # Test for cursor
+        path = None
+
+        if self._cursor:
+            path = self._cursor.get_path()
+        else:
+            model, rows = self._treeview.get_selection().get_selected_rows()
+
+            if len(rows) == 1:
+                path = rows[0]
+
+        if not path:
+            if howmany > 0:
+                self._select_index(0, hasctrl, hasshift)
+            else:
+                self._select_index(num - 1, hasctrl, hasshift)
+        else:
+            idx = path[0]
+
+            if idx + howmany < 0:
+                self._select_index(0, hasctrl, hasshift)
+            elif idx + howmany >= num:
+                self._select_index(num - 1, hasctrl, hasshift)
+            else:
+                self._select_index(idx + howmany, hasctrl, hasshift)
+
+        return True
+
+    def _direct_file(self):
+        uri = self._entry.get_text()
+        gfile = None
+
+        if Pluma.utils_is_valid_uri(uri):
+            gfile = Gio.file_new_for_uri(uri)
+        elif os.path.isabs(uri):
+            f = Gio.file_new_for_uri(uri)
+
+            if f.query_exists():
+                gfile = f
+
+        return gfile
+
+    def _activate(self):
+        model, rows = self._treeview.get_selection().get_selected_rows()
+        ret = True
+
+        for row in rows:
+            s = model.get_iter(row)
+            info = model.get(s, 2, 3)
+
+            if info[1] != Gio.FileType.DIRECTORY:
+                ret = ret and self._handler(info[0])
+            else:
+                text = self._entry.get_text()
+
+                for i in range(len(text) - 1, -1, -1):
+                    if text[i] == os.sep:
+                        break
+
+                self._entry.set_text(os.path.join(text[:i], os.path.basename(info[0].get_uri())) + os.sep)
+                self._entry.set_position(-1)
                 self._entry.grab_focus()
+                return True
 
-# ex:ts=8:et:
+        if rows and ret:
+            self.destroy()
+
+        if not rows:
+            gfile = self._direct_file()
+
+            if gfile and self._handler(gfile):
+                self.destroy()
+            else:
+                ret = False
+        else:
+            ret = False
+
+        return ret
+
+    def toggle_cursor(self):
+        if not self._cursor:
+            return
+
+        path = self._cursor.get_path()
+        selection = self._treeview.get_selection()
+
+        if selection.path_is_selected(path):
+            selection.unselect_path(path)
+        else:
+            selection.select_path(path)
+
+    def on_key_press_event(self, widget, event):
+        move_mapping = {
+            Gdk.KEY_Down: 1,
+            Gdk.KEY_Up: -1,
+            Gdk.KEY_Page_Down: 5,
+            Gdk.KEY_Page_Up: -5
+        }
+
+        if event.keyval == Gdk.KEY_Escape:
+            self.destroy()
+            return True
+        elif event.keyval in move_mapping:
+            return self._move_selection(move_mapping[event.keyval], event.state & Gdk.ModifierType.CONTROL_MASK, event.state & Gdk.ModifierType.SHIFT_MASK)
+        elif event.keyval in [Gdk.KEY_Return, Gdk.KEY_KP_Enter, Gdk.KEY_Tab, Gdk.KEY_ISO_Left_Tab]:
+            return self._activate()
+        elif event.keyval == Gdk.KEY_space and event.state & Gdk.ModifierType.CONTROL_MASK:
+            self.toggle_cursor()
+
+        return False
+
+    def on_row_activated(self, view, path, column):
+        self._activate()
+
+    def do_response(self, response):
+        if response != Gtk.ResponseType.ACCEPT or not self._activate():
+            self.destroy()
+
+    def do_configure_event(self, event):
+        if self.get_realized():
+            alloc = self.get_allocation()
+            self._size = (alloc.width, alloc.height)
+
+        return Gtk.Dialog.do_configure_event(self, event)
+
+    def on_selection_changed(self, selection):
+        model, rows = selection.get_selected_rows()
+
+        gfile = None
+        fname = None
+
+        if not rows:
+            gfile = self._direct_file()
+        elif len(rows) == 1:
+            gfile = model.get(model.get_iter(rows[0]), 2)[0]
+        else:
+            fname = ''
+
+        if gfile:
+            if gfile.is_native():
+                fname = xml.sax.saxutils.escape(gfile.get_path())
+            else:
+                fname = xml.sax.saxutils.escape(gfile.get_uri())
+
+        self._open_button.set_sensitive(fname != None)
+        self._info_label.set_markup(fname or '')
+
+    def on_focus_entry(self, group, accel, keyval, modifier):
+        self._entry.grab_focus()
+
+# ex:ts=4:et:
diff --git a/plugins/quickopen/quickopen/virtualdirs.py b/plugins/quickopen/quickopen/virtualdirs.py
old mode 100755
new mode 100644
index a2d6985..53d716a
--- a/plugins/quickopen/quickopen/virtualdirs.py
+++ b/plugins/quickopen/quickopen/virtualdirs.py
@@ -20,64 +20,64 @@
 from gi.repository import Gio, Gtk
 
 class VirtualDirectory(object):
-        def __init__(self, name):
-                self._name = name
-                self._children = []
+    def __init__(self, name):
+        self._name = name
+        self._children = []
 
-        def get_uri(self):
-                return 'virtual://' + self._name
+    def get_uri(self):
+        return 'virtual://' + self._name
 
-        def get_parent(self):
-                return None
+    def get_parent(self):
+        return None
 
-        def enumerate_children(self, attr, flags, callback):
-                return self._children
+    def enumerate_children(self, attr, flags, callback):
+        return self._children
 
-        def append(self, child):
-                if not child.is_native():
-                        return
+    def append(self, child):
+        if not child.is_native():
+            return
 
-                try:
-                        info = child.query_info("standard::*", Gio.FileQueryInfoFlags.NONE, None)
+        try:
+            info = child.query_info("standard::*", Gio.FileQueryInfoFlags.NONE, None)
 
-                        if info:
-                                self._children.append((child, info))
-                except:
-                        pass
+            if info:
+                self._children.append((child, info))
+        except:
+            pass
 
 class RecentDocumentsDirectory(VirtualDirectory):
-        def __init__(self, maxitems=10):
-                VirtualDirectory.__init__(self, 'recent')
+    def __init__(self, maxitems=10):
+        VirtualDirectory.__init__(self, 'recent')
 
-                self._maxitems = maxitems
-                self.fill()
+        self._maxitems = maxitems
+        self.fill()
 
-        def fill(self):
-                manager = Gtk.RecentManager.get_default()
+    def fill(self):
+        manager = Gtk.RecentManager.get_default()
 
-                items = manager.get_items()
-                items.sort(lambda a, b: cmp(b.get_visited(), a.get_visited()))
+        items = manager.get_items()
+        items.sort(lambda a, b: cmp(b.get_visited(), a.get_visited()))
 
-                added = 0
+        added = 0
 
-                for item in items:
-                        if item.has_group('pluma'):
-                                self.append(Gio.file_new_for_uri(item.get_uri()))
-                                added += 1
+        for item in items:
+            if item.has_group('pluma'):
+                self.append(Gio.file_new_for_uri(item.get_uri()))
+                added += 1
 
-                                if added >= self._maxitems:
-                                        break
+                if added >= self._maxitems:
+                    break
 
 class CurrentDocumentsDirectory(VirtualDirectory):
-        def __init__(self, window):
-                VirtualDirectory.__init__(self, 'documents')
+    def __init__(self, window):
+        VirtualDirectory.__init__(self, 'documents')
 
-                self.fill(window)
+        self.fill(window)
 
-        def fill(self, window):
-                for doc in window.get_documents():
-                        location = doc.get_location()
-                        if location:
-                                self.append(location)
+    def fill(self, window):
+        for doc in window.get_documents():
+            location = doc.get_location()
+            if location:
+                self.append(location)
 
-# ex:ts=8:et:
+# ex:ts=4:et:
diff --git a/plugins/quickopen/quickopen/windowhelper.py b/plugins/quickopen/quickopen/windowhelper.py
old mode 100755
new mode 100644
index c23629c..19e44cb
--- a/plugins/quickopen/quickopen/windowhelper.py
+++ b/plugins/quickopen/quickopen/windowhelper.py
@@ -27,7 +27,7 @@ ui_str = """<ui>
   <menubar name="MenuBar">
     <menu name="FileMenu" action="File">
       <placeholder name="FileOps_2">
-        <menuitem name="QuickOpen" action="QuickOpen"/>
+    <menuitem name="QuickOpen" action="QuickOpen"/>
       </placeholder>
     </menu>
   </menubar>
@@ -35,157 +35,157 @@ ui_str = """<ui>
 """
 
 class WindowHelper:
-        def __init__(self, window, plugin):
-                self._window = window
-                self._plugin = plugin
+    def __init__(self, window, plugin):
+        self._window = window
+        self._plugin = plugin
 
-                self._popup = None
-                self._install_menu()
+        self._popup = None
+        self._install_menu()
 
-        def deactivate(self):
-                self._uninstall_menu()
-                self._window = None
-                self._plugin = None
+    def deactivate(self):
+        self._uninstall_menu()
+        self._window = None
+        self._plugin = None
 
-        def update_ui(self):
-                pass
+    def update_ui(self):
+        pass
 
-        def _uninstall_menu(self):
-                manager = self._window.get_ui_manager()
+    def _uninstall_menu(self):
+        manager = self._window.get_ui_manager()
 
-                manager.remove_ui(self._ui_id)
-                manager.remove_action_group(self._action_group)
+        manager.remove_ui(self._ui_id)
+        manager.remove_action_group(self._action_group)
 
-                manager.ensure_update()
+        manager.ensure_update()
 
-        def _install_menu(self):
-                manager = self._window.get_ui_manager()
-                self._action_group = Gtk.ActionGroup("PlumaQuickOpenPluginActions")
-                self._action_group.add_actions([
-                        ("QuickOpen", Gtk.STOCK_OPEN, _("Quick open"),
-                         '<Ctrl><Alt>O', _("Quickly open documents"),
-                         self.on_quick_open_activate)
-                ])
+    def _install_menu(self):
+        manager = self._window.get_ui_manager()
+        self._action_group = Gtk.ActionGroup("PlumaQuickOpenPluginActions")
+        self._action_group.add_actions([
+            ("QuickOpen", Gtk.STOCK_OPEN, _("Quick open"),
+             '<Ctrl><Alt>O', _("Quickly open documents"),
+             self.on_quick_open_activate)
+        ])
 
-                manager.insert_action_group(self._action_group, -1)
-                self._ui_id = manager.add_ui_from_string(ui_str)
+        manager.insert_action_group(self._action_group, -1)
+        self._ui_id = manager.add_ui_from_string(ui_str)
 
-        def _create_popup(self):
-                paths = []
+    def _create_popup(self):
+        paths = []
 
-                # Open documents
-                paths.append(CurrentDocumentsDirectory(self._window))
+        # Open documents
+        paths.append(CurrentDocumentsDirectory(self._window))
 
-                doc = self._window.get_active_document()
+        doc = self._window.get_active_document()
 
-                # Current document directory
-                if doc and doc.is_local():
-                        gfile = doc.get_location()
-                        paths.append(gfile.get_parent())
+        # Current document directory
+        if doc and doc.is_local():
+            gfile = doc.get_location()
+            paths.append(gfile.get_parent())
 
-                # File browser root directory
-                bus = self._window.get_message_bus()
+        # File browser root directory
+        bus = self._window.get_message_bus()
 
-                try:
-                        msg = bus.send_sync('/plugins/filebrowser', 'get_root')
+        try:
+            msg = bus.send_sync('/plugins/filebrowser', 'get_root')
 
-                        if msg:
-                                uri = msg.get_value('uri')
+            if msg:
+                uri = msg.get_value('uri')
 
-                                if uri:
-                                        gfile = Gio.file_new_for_uri(uri)
+                if uri:
+                    gfile = Gio.file_new_for_uri(uri)
 
-                                        if gfile.is_native():
-                                                paths.append(gfile)
+                    if gfile.is_native():
+                        paths.append(gfile)
 
-                except StandardError:
-                        pass
+        except StandardError:
+            pass
 
-                # Recent documents
-                paths.append(RecentDocumentsDirectory())
+        # Recent documents
+        paths.append(RecentDocumentsDirectory())
 
-                # Local bookmarks
-                for path in self._local_bookmarks():
-                        paths.append(path)
+        # Local bookmarks
+        for path in self._local_bookmarks():
+            paths.append(path)
 
-                # Desktop directory
-                desktopdir = self._desktop_dir()
+        # Desktop directory
+        desktopdir = self._desktop_dir()
 
-                if desktopdir:
-                        paths.append(Gio.file_new_for_path(desktopdir))
+        if desktopdir:
+            paths.append(Gio.file_new_for_path(desktopdir))
 
-                # Home directory
-                paths.append(Gio.file_new_for_path(os.path.expanduser('~')))
+        # Home directory
+        paths.append(Gio.file_new_for_path(os.path.expanduser('~')))
 
-                self._popup = Popup(self._window, paths, self.on_activated)
+        self._popup = Popup(self._window, paths, self.on_activated)
 
-                self._popup.set_default_size(*self._plugin.get_popup_size())
-                self._popup.set_transient_for(self._window)
-                self._popup.set_position(Gtk.WindowPosition.CENTER_ON_PARENT)
+        self._popup.set_default_size(*self._plugin.get_popup_size())
+        self._popup.set_transient_for(self._window)
+        self._popup.set_position(Gtk.WindowPosition.CENTER_ON_PARENT)
 
-                self._window.get_group().add_window(self._popup)
+        self._window.get_group().add_window(self._popup)
 
-                self._popup.connect('destroy', self.on_popup_destroy)
+        self._popup.connect('destroy', self.on_popup_destroy)
 
-        def _local_bookmarks(self):
-                filename = os.path.expanduser('~/.gtk-bookmarks')
+    def _local_bookmarks(self):
+        filename = os.path.expanduser('~/.gtk-bookmarks')
 
-                if not os.path.isfile(filename):
-                        return []
+        if not os.path.isfile(filename):
+            return []
 
-                paths = []
+        paths = []
 
-                for line in file(filename, 'r').xreadlines():
-                        uri = line.strip().split(" ")[0]
-                        f = Gio.file_new_for_uri(uri)
+        for line in file(filename, 'r').xreadlines():
+            uri = line.strip().split(" ")[0]
+            f = Gio.file_new_for_uri(uri)
 
-                        if f.is_native():
-                                try:
-                                        info = f.query_info(Gio.FILE_ATTRIBUTE_STANDARD_TYPE, Gio.FileQueryInfoFlags.NONE, None)
+            if f.is_native():
+                try:
+                    info = f.query_info(Gio.FILE_ATTRIBUTE_STANDARD_TYPE, Gio.FileQueryInfoFlags.NONE, None)
 
-                                        if info and info.get_file_type() == Gio.FileType.DIRECTORY:
-                                                paths.append(f)
-                                except GLib.GError:
-                                        pass
+                    if info and info.get_file_type() == Gio.FileType.DIRECTORY:
+                        paths.append(f)
+                except GLib.GError:
+                    pass
 
-                return paths
+        return paths
 
-        def _desktop_dir(self):
-                config = os.getenv('XDG_CONFIG_HOME')
+    def _desktop_dir(self):
+        config = os.getenv('XDG_CONFIG_HOME')
 
-                if not config:
-                        config = os.path.expanduser('~/.config')
+        if not config:
+            config = os.path.expanduser('~/.config')
 
-                config = os.path.join(config, 'user-dirs.dirs')
-                desktopdir = None
+        config = os.path.join(config, 'user-dirs.dirs')
+        desktopdir = None
 
-                if os.path.isfile(config):
-                        for line in file(config, 'r').xreadlines():
-                                line = line.strip()
+        if os.path.isfile(config):
+            for line in file(config, 'r').xreadlines():
+                line = line.strip()
 
-                                if line.startswith('XDG_DESKTOP_DIR'):
-                                        parts = line.split('=', 1)
-                                        desktopdir = os.path.expandvars(parts[1].strip('"').strip("'"))
-                                        break
+                if line.startswith('XDG_DESKTOP_DIR'):
+                    parts = line.split('=', 1)
+                    desktopdir = os.path.expandvars(parts[1].strip('"').strip("'"))
+                    break
 
-                if not desktopdir:
-                        desktopdir = os.path.expanduser('~/Desktop')
+        if not desktopdir:
+            desktopdir = os.path.expanduser('~/Desktop')
 
-                return desktopdir
+        return desktopdir
 
-        # Callbacks
-        def on_quick_open_activate(self, action):
-                if not self._popup:
-                        self._create_popup()
+    # Callbacks
+    def on_quick_open_activate(self, action):
+        if not self._popup:
+            self._create_popup()
 
-                self._popup.show()
+        self._popup.show()
 
-        def on_popup_destroy(self, popup):
-                self._plugin.set_popup_size(popup.get_final_size())
-                self._popup = None
+    def on_popup_destroy(self, popup):
+        self._plugin.set_popup_size(popup.get_final_size())
+        self._popup = None
 
-        def on_activated(self, gfile):
-                Pluma.commands_load_uri(self._window, gfile.get_uri(), None, -1)
-                return True
+    def on_activated(self, gfile):
+        Pluma.commands_load_uri(self._window, gfile.get_uri(), None, -1)
+        return True
 
-# ex:ts=8:et:
+# ex:ts=4:et:
diff --git a/plugins/snippets/snippets/Completion.py b/plugins/snippets/snippets/Completion.py
old mode 100755
new mode 100644
index 1788ecd..a860d21
--- a/plugins/snippets/snippets/Completion.py
+++ b/plugins/snippets/snippets/Completion.py
@@ -5,159 +5,159 @@ from LanguageManager import get_language_manager
 from Snippet import Snippet
 
 class Proposal(GObject.Object, GtkSource.CompletionProposal):
-        __gtype_name__ = "PlumaSnippetsProposal"
-
-        def __init__(self, snippet):
-                GObject.Object.__init__(self)
-                self._snippet = Snippet(snippet)
-        
-        def snippet(self):
-                return self._snippet.data
-        
-        # Interface implementation
-        def do_get_markup(self):
-                return self._snippet.display()
-        
-        def do_get_info(self):
-                return self._snippet.data['text']
+    __gtype_name__ = "PlumaSnippetsProposal"
+
+    def __init__(self, snippet):
+        GObject.Object.__init__(self)
+        self._snippet = Snippet(snippet)
+
+    def snippet(self):
+        return self._snippet.data
+
+    # Interface implementation
+    def do_get_markup(self):
+        return self._snippet.display()
+
+    def do_get_info(self):
+        return self._snippet.data['text']
 
 class Provider(GObject.Object, GtkSource.CompletionProvider):
-        __gtype_name__ = "PlumaSnippetsProvider"
-
-        def __init__(self, name, language_id, handler):
-                GObject.Object.__init__(self)
-                
-                self.name = name
-                self.info_widget = None
-                self.proposals = []
-                self.language_id = language_id
-                self.handler = handler
-                self.info_widget = None
-                self.mark = None
-                
-                theme = Gtk.IconTheme.get_default()
-                f, w, h = Gtk.icon_size_lookup(Gtk.IconSize.MENU)
-
-                self.icon = theme.load_icon(Gtk.STOCK_JUSTIFY_LEFT, w, 0)
-        
-        def __del__(self):
-                if self.mark:
-                        self.mark.get_buffer().delete_mark(self.mark)
-        
-        def set_proposals(self, proposals):
-                self.proposals = proposals
-
-        def mark_position(self, it):
-                if not self.mark:
-                        self.mark = it.get_buffer().create_mark(None, it, True)
-                else:
-                        self.mark.get_buffer().move_mark(self.mark, it)
-        
-        def get_word(self, context):
-                (valid_context, it) = context.get_iter()
-                if not valid_context:
-                        return None
-                
-                if it.starts_word() or it.starts_line() or not it.ends_word():
-                        return None
-                
-                start = it.copy()
-                
-                if start.backward_word_start():
-                        self.mark_position(start)
-                        return start.get_text(it)
-                else:
-                        return None
-        
-        def do_get_start_iter(self, context, proposal):
-                if not self.mark or self.mark.get_deleted():
-                        return (False, None)
-                
-                return (True, self.mark.get_buffer().get_iter_at_mark(self.mark))
-                
-        def do_match(self, context):
-                return True
-
-        def get_proposals(self, word):
-                if self.proposals:
-                        proposals = self.proposals
-                else:
-                        proposals = Library().get_snippets(None)
-                        
-                        if self.language_id:
-                                proposals += Library().get_snippets(self.language_id)
-
-                # Filter based on the current word
-                if word:
-                        proposals = filter(lambda x: x['tag'].startswith(word), proposals)
-
-                return map(lambda x: Proposal(x), proposals)
-
-        def do_populate(self, context):
-                proposals = self.get_proposals(self.get_word(context))
-                context.add_proposals(self, proposals, True)
-
-        def do_get_name(self):
-                return self.name
-
-        def do_activate_proposal(self, proposal, piter):
-                return self.handler(proposal, piter)
-        
-        def do_get_info_widget(self, proposal):
-                if not self.info_widget:
-                        view = Pluma.View.new_with_buffer(Pluma.Document())
-                        manager = get_language_manager()
-
-                        lang = manager.get_language('snippets')
-                        view.get_buffer().set_language(lang)
-                        
-                        sw = Gtk.ScrolledWindow()
-                        sw.add(view)
-                        
-                        self.info_view = view
-                        self.info_widget = sw
-                
-                return self.info_widget
-        
-        def do_update_info(self, proposal, info):
-                buf = self.info_view.get_buffer()
-                
-                buf.set_text(proposal.get_info())
-                buf.move_mark(buf.get_insert(), buf.get_start_iter())
-                buf.move_mark(buf.get_selection_bound(), buf.get_start_iter())
-                self.info_view.scroll_to_iter(buf.get_start_iter(), 0.0, False, 0.5, 0.5)
-        
-        def do_get_icon(self):
-                return self.icon
-
-        def do_get_activation(self):
-                return GtkSource.CompletionActivation.USER_REQUESTED
+    __gtype_name__ = "PlumaSnippetsProvider"
+
+    def __init__(self, name, language_id, handler):
+        GObject.Object.__init__(self)
+
+        self.name = name
+        self.info_widget = None
+        self.proposals = []
+        self.language_id = language_id
+        self.handler = handler
+        self.info_widget = None
+        self.mark = None
+
+        theme = Gtk.IconTheme.get_default()
+        f, w, h = Gtk.icon_size_lookup(Gtk.IconSize.MENU)
+
+        self.icon = theme.load_icon(Gtk.STOCK_JUSTIFY_LEFT, w, 0)
+
+    def __del__(self):
+        if self.mark:
+            self.mark.get_buffer().delete_mark(self.mark)
+
+    def set_proposals(self, proposals):
+        self.proposals = proposals
+
+    def mark_position(self, it):
+        if not self.mark:
+            self.mark = it.get_buffer().create_mark(None, it, True)
+        else:
+            self.mark.get_buffer().move_mark(self.mark, it)
+
+    def get_word(self, context):
+        (valid_context, it) = context.get_iter()
+        if not valid_context:
+            return None
+
+        if it.starts_word() or it.starts_line() or not it.ends_word():
+            return None
+
+        start = it.copy()
+
+        if start.backward_word_start():
+            self.mark_position(start)
+            return start.get_text(it)
+        else:
+            return None
+
+    def do_get_start_iter(self, context, proposal):
+        if not self.mark or self.mark.get_deleted():
+            return (False, None)
+
+        return (True, self.mark.get_buffer().get_iter_at_mark(self.mark))
+
+    def do_match(self, context):
+        return True
+
+    def get_proposals(self, word):
+        if self.proposals:
+            proposals = self.proposals
+        else:
+            proposals = Library().get_snippets(None)
+
+            if self.language_id:
+                proposals += Library().get_snippets(self.language_id)
+
+        # Filter based on the current word
+        if word:
+            proposals = filter(lambda x: x['tag'].startswith(word), proposals)
+
+        return map(lambda x: Proposal(x), proposals)
+
+    def do_populate(self, context):
+        proposals = self.get_proposals(self.get_word(context))
+        context.add_proposals(self, proposals, True)
+
+    def do_get_name(self):
+        return self.name
+
+    def do_activate_proposal(self, proposal, piter):
+        return self.handler(proposal, piter)
+
+    def do_get_info_widget(self, proposal):
+        if not self.info_widget:
+            view = Pluma.View.new_with_buffer(Pluma.Document())
+            manager = get_language_manager()
+
+            lang = manager.get_language('snippets')
+            view.get_buffer().set_language(lang)
+
+            sw = Gtk.ScrolledWindow()
+            sw.add(view)
+
+            self.info_view = view
+            self.info_widget = sw
+
+        return self.info_widget
+
+    def do_update_info(self, proposal, info):
+        buf = self.info_view.get_buffer()
+
+        buf.set_text(proposal.get_info())
+        buf.move_mark(buf.get_insert(), buf.get_start_iter())
+        buf.move_mark(buf.get_selection_bound(), buf.get_start_iter())
+        self.info_view.scroll_to_iter(buf.get_start_iter(), 0.0, False, 0.5, 0.5)
+
+    def do_get_icon(self):
+        return self.icon
+
+    def do_get_activation(self):
+        return GtkSource.CompletionActivation.USER_REQUESTED
 
 class Defaults(GObject.Object, GtkSource.CompletionProvider):
-        __gtype_name__ = "PlumaSnippetsDefaultsProvider"
-
-        def __init__(self, handler):
-                GObject.Object.__init__(self)
-
-                self.handler = handler
-                self.proposals = []
-        
-        def set_defaults(self, defaults):
-                self.proposals = []
-                
-                for d in defaults:
-                        self.proposals.append(GtkSource.CompletionItem.new(d, d, None, None))
-                
-        def do_get_name(self):
-                return ""
-        
-        def do_activate_proposal(self, proposal, piter):
-                return self.handler(proposal, piter)
-        
-        def do_populate(self, context):
-                context.add_proposals(self, self.proposals, True)
-
-        def do_get_activation(self):
-                return GtkSource.CompletionActivation.USER_REQUESTED
-
-# ex:ts=8:et:
+    __gtype_name__ = "PlumaSnippetsDefaultsProvider"
+
+    def __init__(self, handler):
+        GObject.Object.__init__(self)
+
+        self.handler = handler
+        self.proposals = []
+
+    def set_defaults(self, defaults):
+        self.proposals = []
+
+        for d in defaults:
+            self.proposals.append(GtkSource.CompletionItem.new(d, d, None, None))
+
+    def do_get_name(self):
+        return ""
+
+    def do_activate_proposal(self, proposal, piter):
+        return self.handler(proposal, piter)
+
+    def do_populate(self, context):
+        context.add_proposals(self, self.proposals, True)
+
+    def do_get_activation(self):
+        return GtkSource.CompletionActivation.USER_REQUESTED
+
+# ex:ts=4:et:
diff --git a/plugins/snippets/snippets/Document.py b/plugins/snippets/snippets/Document.py
old mode 100755
new mode 100644
index 07faf2a..f1cc065
--- a/plugins/snippets/snippets/Document.py
+++ b/plugins/snippets/snippets/Document.py
@@ -26,1070 +26,1068 @@ from Placeholder import *
 import Completion
 
 class DynamicSnippet(dict):
-        def __init__(self, text):
-                self['text'] = text
-                self.valid = True
+    def __init__(self, text):
+        self['text'] = text
+        self.valid = True
 
 class Document:
-        TAB_KEY_VAL = (Gdk.KEY_Tab, \
-                        Gdk.KEY_ISO_Left_Tab)
-        SPACE_KEY_VAL = (Gdk.KEY_space,)
-        
-        def __init__(self, instance, view):
-                self.view = None
-                self.instance = instance
-                
-                self.placeholders = []
-                self.active_snippets = []
-                self.active_placeholder = None
-                self.signal_ids = {}
-                
-                self.ordered_placeholders = []
-                self.update_placeholders = []
-                self.jump_placeholders = []
-                self.language_id = 0
-                self.timeout_update_id = 0
-                
-                self.provider = Completion.Provider(_('Snippets'), self.language_id, self.on_proposal_activated)
-                
-                # Always have a reference to the global snippets
-                Library().ref(None)
-                self.set_view(view)
-        
-        # Stop controlling the view. Remove all active snippets, remove references
-        # to the view and the plugin instance, disconnect all signal handlers
-        def stop(self):
-                if self.timeout_update_id != 0:
-                        GLib.source_remove(self.timeout_update_id)
-                        self.timeout_update_id = 0
-                        del self.update_placeholders[:]
-                        del self.jump_placeholders[:]
-
-                # Always release the reference to the global snippets
-                Library().unref(None)
-                self.set_view(None)
-                self.instance = None
-                self.active_placeholder = None
+    TAB_KEY_VAL = (Gdk.KEY_Tab, \
+            Gdk.KEY_ISO_Left_Tab)
+    SPACE_KEY_VAL = (Gdk.KEY_space,)
+
+    def __init__(self, instance, view):
+        self.view = None
+        self.instance = instance
+
+        self.placeholders = []
+        self.active_snippets = []
+        self.active_placeholder = None
+        self.signal_ids = {}
+
+        self.ordered_placeholders = []
+        self.update_placeholders = []
+        self.jump_placeholders = []
+        self.language_id = 0
+        self.timeout_update_id = 0
+
+        self.provider = Completion.Provider(_('Snippets'), self.language_id, self.on_proposal_activated)
+
+        # Always have a reference to the global snippets
+        Library().ref(None)
+        self.set_view(view)
+
+    # Stop controlling the view. Remove all active snippets, remove references
+    # to the view and the plugin instance, disconnect all signal handlers
+    def stop(self):
+        if self.timeout_update_id != 0:
+            GLib.source_remove(self.timeout_update_id)
+            self.timeout_update_id = 0
+            del self.update_placeholders[:]
+            del self.jump_placeholders[:]
+
+        # Always release the reference to the global snippets
+        Library().unref(None)
+        self.set_view(None)
+        self.instance = None
+        self.active_placeholder = None
+
+    def disconnect_signal(self, obj, signal):
+        if (obj, signal) in self.signal_ids:
+            obj.disconnect(self.signal_ids[(obj, signal)])
+            del self.signal_ids[(obj, signal)]
+
+    def connect_signal(self, obj, signal, cb):
+        self.disconnect_signal(obj, signal)
+        self.signal_ids[(obj, signal)] = obj.connect(signal, cb)
+
+    def connect_signal_after(self, obj, signal, cb):
+        self.disconnect_signal(obj, signal)
+        self.signal_ids[(obj, signal)] = obj.connect_after(signal, cb)
 
-        def disconnect_signal(self, obj, signal):
-                if (obj, signal) in self.signal_ids:
-                        obj.disconnect(self.signal_ids[(obj, signal)])
-                        del self.signal_ids[(obj, signal)]
-                
-        def connect_signal(self, obj, signal, cb):
-                self.disconnect_signal(obj, signal)     
-                self.signal_ids[(obj, signal)] = obj.connect(signal, cb)
-
-        def connect_signal_after(self, obj, signal, cb):
-                self.disconnect_signal(obj, signal)
-                self.signal_ids[(obj, signal)] = obj.connect_after(signal, cb)
-                
-        # Set the view to be controlled. Installs signal handlers and sets current
-        # language. If there is already a view set this function will first remove
-        # all currently active snippets and disconnect all current signals. So
-        # self.set_view(None) will effectively remove all the control from the
-        # current view
-        def _set_view(self, view):
-                if self.view:
-                        buf = self.view.get_buffer()
-
-                        # Remove signals
-                        signals = {self.view: ('key-press-event', 'destroy', 
-                                               'notify::editable', 'drag-data-received', 'expose-event'),
-                                   buf:       ('notify::language', 'changed', 'cursor-moved', 'insert-text'),
-                                   self.view.get_completion(): ('hide',)}
-
-                        for obj, sig in signals.items():
-                                if obj:
-                                        for s in sig:
-                                                self.disconnect_signal(obj, s)
-                        
-                        # Remove all active snippets
-                        for snippet in list(self.active_snippets):
-                                self.deactivate_snippet(snippet, True)
-                        
-                        completion = self.view.get_completion()
-                        if completion:
-                                completion.remove_provider(self.provider)
-
-                self.view = view
-                
-                if view != None:
-                        buf = view.get_buffer()
-                       
-                        self.connect_signal(view, 'destroy', self.on_view_destroy)
-
-                        if view.get_editable():
-                                self.connect_signal(view, 'key-press-event', self.on_view_key_press)
-
-                        self.connect_signal(buf, 'notify::language', self.on_notify_language)
-                        self.connect_signal(view, 'notify::editable', self.on_notify_editable)
-                        self.connect_signal(view, 'drag-data-received', self.on_drag_data_received)
-                        self.connect_signal_after(view, 'draw', self.on_draw)
-
-                        self.update_language()
-
-                        completion = view.get_completion()
-                        completion.add_provider(self.provider)
-                elif self.language_id != 0:
-                        langid = self.language_id
-                        
-                        self.language_id = None;
-                        self.provider.language_id = self.language_id
-                        
-                        if self.instance:
-                                self.instance.language_changed(self)
-
-                        Library().unref(langid)
-
-        def set_view(self, view):
-                if view == self.view:
-                        return
-                
-                self._set_view(view)
-
-        # Call this whenever the language in the view changes. This makes sure that
-        # the correct language is used when finding snippets
-        def update_language(self):
-                lang = self.view.get_buffer().get_language()
-
-                if lang == None and self.language_id == None:
-                        return
-                elif lang and lang.get_id() == self.language_id:
-                        return
-
-                langid = self.language_id
-
-                if lang:
-                        self.language_id = lang.get_id()
-                else:
-                        self.language_id = None
+    # Set the view to be controlled. Installs signal handlers and sets current
+    # language. If there is already a view set this function will first remove
+    # all currently active snippets and disconnect all current signals. So
+    # self.set_view(None) will effectively remove all the control from the
+    # current view
+    def _set_view(self, view):
+        if self.view:
+            buf = self.view.get_buffer()
+
+            # Remove signals
+            signals = {self.view: ('key-press-event', 'destroy',
+                           'notify::editable', 'drag-data-received', 'expose-event'),
+                   buf:       ('notify::language', 'changed', 'cursor-moved', 'insert-text'),
+                   self.view.get_completion(): ('hide',)}
+
+            for obj, sig in signals.items():
+                if obj:
+                    for s in sig:
+                        self.disconnect_signal(obj, s)
 
-                if self.instance:
-                        self.instance.language_changed(self)
+            # Remove all active snippets
+            for snippet in list(self.active_snippets):
+                self.deactivate_snippet(snippet, True)
+
+            completion = self.view.get_completion()
+            if completion:
+                completion.remove_provider(self.provider)
+
+        self.view = view
 
-                if langid != 0:
-                        Library().unref(langid)
+        if view != None:
+            buf = view.get_buffer()
 
-                Library().ref(self.language_id)
-                self.provider.language_id = self.language_id
+            self.connect_signal(view, 'destroy', self.on_view_destroy)
+
+            if view.get_editable():
+                self.connect_signal(view, 'key-press-event', self.on_view_key_press)
 
-        def accelerator_activate(self, keyval, mod):
-                if not self.view or not self.view.get_editable():
-                        return False
+            self.connect_signal(buf, 'notify::language', self.on_notify_language)
+            self.connect_signal(view, 'notify::editable', self.on_notify_editable)
+            self.connect_signal(view, 'drag-data-received', self.on_drag_data_received)
+            self.connect_signal_after(view, 'draw', self.on_draw)
+
+            self.update_language()
+
+            completion = view.get_completion()
+            completion.add_provider(self.provider)
+        elif self.language_id != 0:
+            langid = self.language_id
 
-                accelerator = Gtk.accelerator_name(keyval, mod)
-                snippets = Library().from_accelerator(accelerator, \
-                                self.language_id)
+            self.language_id = None;
+            self.provider.language_id = self.language_id
+
+            if self.instance:
+                self.instance.language_changed(self)
 
-                snippets_debug('Accel!')
+            Library().unref(langid)
 
-                if len(snippets) == 0:
-                        return False
-                elif len(snippets) == 1:
-                        self.apply_snippet(snippets[0])
-                else:
-                        # Do the fancy completion dialog
-                        provider = Completion.Provider(_('Snippets'), self.language_id, self.on_proposal_activated)
-                        provider.set_proposals(snippets)
+    def set_view(self, view):
+        if view == self.view:
+            return
 
-                        cm.show([provider], cm.create_context(None))
+        self._set_view(view)
 
-                return True
+    # Call this whenever the language in the view changes. This makes sure that
+    # the correct language is used when finding snippets
+    def update_language(self):
+        lang = self.view.get_buffer().get_language()
+
+        if lang == None and self.language_id == None:
+            return
+        elif lang and lang.get_id() == self.language_id:
+            return
+
+        langid = self.language_id
+
+        if lang:
+            self.language_id = lang.get_id()
+        else:
+            self.language_id = None
 
-        def first_snippet_inserted(self):
-                buf = self.view.get_buffer()
-                
-                self.connect_signal(buf, 'changed', self.on_buffer_changed)
-                self.connect_signal(buf, 'cursor-moved', self.on_buffer_cursor_moved)
-                self.connect_signal_after(buf, 'insert-text', self.on_buffer_insert_text)
-        
-        def last_snippet_removed(self):
-                buf = self.view.get_buffer()
-                self.disconnect_signal(buf, 'changed')
-                self.disconnect_signal(buf, 'cursor-moved')
-                self.disconnect_signal(buf, 'insert-text')
-
-        def current_placeholder(self):
-                buf = self.view.get_buffer()
-                
-                piter = buf.get_iter_at_mark(buf.get_insert())        
-                found = []
-
-                for placeholder in self.placeholders:
-                        begin = placeholder.begin_iter()
-                        end = placeholder.end_iter()
-
-                        if piter.compare(begin) >= 0 and piter.compare(end) <= 0:
-                                found.append(placeholder)
-
-                if self.active_placeholder in found:
-                        return self.active_placeholder
-                elif len(found) > 0:
-                        return found[0]
-                else:
-                        return None
-
-        def advance_placeholder(self, direction):
-                # Returns (CurrentPlaceholder, NextPlaceholder), depending on direction
-                buf = self.view.get_buffer()
-                
-                piter = buf.get_iter_at_mark(buf.get_insert())
-                found = current = next = None
-                length = len(self.placeholders)
-                
-                placeholders = list(self.placeholders)
-                
-                if self.active_placeholder:
-                        begin = self.active_placeholder.begin_iter()
-                        end = self.active_placeholder.end_iter()
-                        
-                        if piter.compare(begin) >= 0 and piter.compare(end) <= 0:
-                                current = self.active_placeholder
-                                currentIndex = placeholders.index(self.active_placeholder)
-
-                if direction == 1:
-                        # w = piter, x = begin, y = end, z = found
-                        nearest = lambda w, x, y, z: (w.compare(x) <= 0 and (not z or \
-                                        x.compare(z.begin_iter()) < 0))
-                        indexer = lambda x: x < length - 1
-                else:
-                        # w = piter, x = begin, y = end, z = prev
-                        nearest = lambda w, x, y, z: (w.compare(x) >= 0 and (not z or \
-                                        x.compare(z.begin_iter()) >= 0))
-                        indexer = lambda x: x > 0
-
-                for index in range(0, length):
-                        placeholder = placeholders[index]
-                        begin = placeholder.begin_iter()
-                        end = placeholder.end_iter()
-                        
-                        # Find the nearest placeholder
-                        if nearest(piter, begin, end, found):
-                                foundIndex = index
-                                found = placeholder
-                        
-                        # Find the current placeholder
-                        if piter.compare(begin) >= 0 and \
-                                        piter.compare(end) <= 0 and \
-                                        current == None:
-                                currentIndex = index
-                                current = placeholder
-                
-                if current and current != found and \
-                   (current.begin_iter().compare(found.begin_iter()) == 0 or \
-                    current.end_iter().compare(found.begin_iter()) == 0) and \
-                   self.active_placeholder and \
-                   current.begin_iter().compare(self.active_placeholder.begin_iter()) == 0:
-                        # if current and found are at the same place, then
-                        # resolve the 'hugging' problem
-                        current = self.active_placeholder
-                        currentIndex = placeholders.index(current)
-                
-                if current:
-                        if indexer(currentIndex):
-                                next = placeholders[currentIndex + direction]
-                elif found:
-                        next = found
-                elif length > 0:
-                        next = self.placeholders[0]
-                
-                return current, next
-        
-        def next_placeholder(self):
-                return self.advance_placeholder(1)
-        
-        def previous_placeholder(self):
-                return self.advance_placeholder(-1)
-
-        def cursor_on_screen(self):
-                buf = self.view.get_buffer()
-                self.view.scroll_mark_onscreen(buf.get_insert())
-        
-        def set_active_placeholder(self, placeholder):
-                self.active_placeholder = placeholder
-
-        def goto_placeholder(self, current, next):
-                last = None
-
-                if current:
-                        # Signal this placeholder to end action
-                        self.view.get_completion().hide()
-                        current.leave()
-                        
-                        if current.__class__ == PlaceholderEnd:
-                                last = current
-                
-                self.set_active_placeholder(next)
-                
-                if next:
-                        next.enter()
-                        
-                        if next.__class__ == PlaceholderEnd:
-                                last = next
-                        elif len(next.defaults) > 1 and next.get_text() == next.default:
-                                provider = Completion.Defaults(self.on_default_activated)
-                                provider.set_defaults(next.defaults)
-                                
-                                cm = self.view.get_completion()
-                                cm.show([provider], cm.create_context(None))
-
-                if last:
-                        # This is the end of the placeholder, remove the snippet etc
-                        for snippet in list(self.active_snippets):
-                                if snippet.placeholders[0] == last:
-                                        self.deactivate_snippet(snippet)
-                                        break
-                
-                self.cursor_on_screen()
-                
-                return next != None
-        
-        def skip_to_next_placeholder(self):
-                (current, next) = self.next_placeholder()
-                return self.goto_placeholder(current, next)
-        
-        def skip_to_previous_placeholder(self):
-                (current, prev) = self.previous_placeholder()
-                return self.goto_placeholder(current, prev)
-
-        def env_get_selected_text(self, buf):
-                bounds = buf.get_selection_bounds()
-
-                if bounds:
-                        return buf.get_text(bounds[0], bounds[1], False)
-                else:
-                        return ''
-
-        def env_get_current_word(self, buf):
-                start, end = buffer_word_boundary(buf)
-                
-                return buf.get_text(start, end, False)
-
-        def env_get_current_line(self, buf):
-                start, end = buffer_line_boundary(buf)
-                
-                return buf.get_text(start, end, False)
-
-        def env_get_current_line_number(self, buf):
-                start, end = buffer_line_boundary(buf)
-                
-                return str(start.get_line() + 1)
-                
-        def env_get_document_uri(self, buf):
-                location = buf.get_location()
-                
-                if location:
-                        return location.get_uri()
-                else:
-                        return ''
-        
-        def env_get_document_name(self, buf):
-                location = buf.get_location()
-                
-                if location:
-                        return location.get_basename()
-                else:
-                        return ''
+        if self.instance:
+            self.instance.language_changed(self)
+
+        if langid != 0:
+            Library().unref(langid)
 
-        def env_get_document_scheme(self, buf):
-                location = buf.get_location()
-                
-                if location:
-                        return location.get_uri_scheme()
-                else:
-                        return ''
+        Library().ref(self.language_id)
+        self.provider.language_id = self.language_id
+
+    def accelerator_activate(self, keyval, mod):
+        if not self.view or not self.view.get_editable():
+            return False
+
+        accelerator = Gtk.accelerator_name(keyval, mod)
+        snippets = Library().from_accelerator(accelerator, \
+                self.language_id)
+
+        snippets_debug('Accel!')
+
+        if len(snippets) == 0:
+            return False
+        elif len(snippets) == 1:
+            self.apply_snippet(snippets[0])
+        else:
+            # Do the fancy completion dialog
+            provider = Completion.Provider(_('Snippets'), self.language_id, self.on_proposal_activated)
+            provider.set_proposals(snippets)
+
+            cm.show([provider], cm.create_context(None))
+
+        return True
+
+    def first_snippet_inserted(self):
+        buf = self.view.get_buffer()
+
+        self.connect_signal(buf, 'changed', self.on_buffer_changed)
+        self.connect_signal(buf, 'cursor-moved', self.on_buffer_cursor_moved)
+        self.connect_signal_after(buf, 'insert-text', self.on_buffer_insert_text)
 
-        def env_get_document_path(self, buf):
-                location = buf.get_location()
-                
-                if location:
-                        return location.get_path()
-                else:
-                        return ''
+    def last_snippet_removed(self):
+        buf = self.view.get_buffer()
+        self.disconnect_signal(buf, 'changed')
+        self.disconnect_signal(buf, 'cursor-moved')
+        self.disconnect_signal(buf, 'insert-text')
 
-        def env_get_document_dir(self, buf):
-                location = buf.get_location()
+    def current_placeholder(self):
+        buf = self.view.get_buffer()
 
-                if location:
-                        return location.get_parent().get_path() or ''
-                else:
-                        return ''
+        piter = buf.get_iter_at_mark(buf.get_insert())
+        found = []
+
+        for placeholder in self.placeholders:
+            begin = placeholder.begin_iter()
+            end = placeholder.end_iter()
+
+            if piter.compare(begin) >= 0 and piter.compare(end) <= 0:
+                found.append(placeholder)
+
+        if self.active_placeholder in found:
+            return self.active_placeholder
+        elif len(found) > 0:
+            return found[0]
+        else:
+            return None
+
+    def advance_placeholder(self, direction):
+        # Returns (CurrentPlaceholder, NextPlaceholder), depending on direction
+        buf = self.view.get_buffer()
 
-        def env_get_document_type(self, buf):
-                typ = buf.get_mime_type()
-                
-                if typ:
-                        return typ
-                else:
-                        return ''
-
-        def env_get_documents_uri(self, buf):
-                toplevel = self.view.get_toplevel()
-                
-                if isinstance(toplevel, Pluma.Window):
-                        documents_uri = [doc.get_location().get_uri()
-                                         for doc in toplevel.get_documents()
-                                         if doc.get_location() is not None]
-                else:
-                        documents_uri = []
-                
-                return ' '.join(documents_uri)
-
-        def env_get_documents_path(self, buf):
-                toplevel = self.view.get_toplevel()
-                
-                if isinstance(toplevel, Pluma.Window):
-                        documents_location = [doc.get_location()
-                                              for doc in toplevel.get_documents()
-                                              if doc.get_location() is not None]
-
-                        documents_path = [location.get_path()
-                                          for location in documents_location
-                                          if Pluma.utils_uri_has_file_scheme(location.get_uri())]
-                else:
-                        documents_path = []
-                
-                return ' '.join(documents_path)
-
-        def update_environment(self):
-                buf = self.view.get_buffer()
-                
-                variables = {'PLUMA_SELECTED_TEXT': self.env_get_selected_text, 
-                             'PLUMA_CURRENT_WORD': self.env_get_current_word, 
-                             'PLUMA_CURRENT_LINE': self.env_get_current_line,
-                             'PLUMA_CURRENT_LINE_NUMBER': self.env_get_current_line_number,
-                             'PLUMA_CURRENT_DOCUMENT_URI': self.env_get_document_uri, 
-                             'PLUMA_CURRENT_DOCUMENT_NAME': self.env_get_document_name,
-                             'PLUMA_CURRENT_DOCUMENT_SCHEME': self.env_get_document_scheme,
-                             'PLUMA_CURRENT_DOCUMENT_PATH': self.env_get_document_path,
-                             'PLUMA_CURRENT_DOCUMENT_DIR': self.env_get_document_dir,
-                             'PLUMA_CURRENT_DOCUMENT_TYPE': self.env_get_document_type,
-                             'PLUMA_DOCUMENTS_URI': self.env_get_documents_uri,
-                             'PLUMA_DOCUMENTS_PATH': self.env_get_documents_path,
-                             }
-                
-                for var in variables:
-                        os.environ[var] = variables[var](buf)
-        
-        def uses_current_word(self, snippet):
-                matches = re.findall('(\\\\*)\\$PLUMA_CURRENT_WORD', snippet['text'])
-                
-                for match in matches:
-                        if len(match) % 2 == 0:
-                                return True
-                
-                return False
-        
-        def uses_current_line(self, snippet):
-                matches = re.findall('(\\\\*)\\$PLUMA_CURRENT_LINE', snippet['text'])
-                
-                for match in matches:
-                        if len(match) % 2 == 0:
-                                return True
-                
-                return False
-
-        def apply_snippet(self, snippet, start = None, end = None):
-                if not snippet.valid:
-                        return False
-
-                buf = self.view.get_buffer()
-                s = Snippet(snippet)
-                
-                if not start:
-                        start = buf.get_iter_at_mark(buf.get_insert())
-                
-                if not end:
-                        end = buf.get_iter_at_mark(buf.get_selection_bound())
-
-                if start.equal(end) and self.uses_current_word(s):
-                        # There is no tab trigger and no selection and the snippet uses
-                        # the current word. Set start and end to the word boundary so that 
-                        # it will be removed
-                        start, end = buffer_word_boundary(buf)
-                elif start.equal(end) and self.uses_current_line(s):
-                        # There is no tab trigger and no selection and the snippet uses
-                        # the current line. Set start and end to the line boundary so that 
-                        # it will be removed
-                        start, end = buffer_line_boundary(buf)
-
-                # Set environmental variables
-                self.update_environment()
-                
-                # You know, we could be in an end placeholder
-                (current, next) = self.next_placeholder()
-                if current and current.__class__ == PlaceholderEnd:
-                        self.goto_placeholder(current, None)
-                
-                buf.begin_user_action()
-
-                # Remove the tag, selection or current word
-                buf.delete(start, end)
-                
-                # Insert the snippet
-                holders = len(self.placeholders)
-                
-                if len(self.active_snippets) == 0:
-                        self.first_snippet_inserted()
-
-                sn = s.insert_into(self, start)
-                self.active_snippets.append(sn)
-
-                # Put cursor at first tab placeholder
-                keys = filter(lambda x: x > 0, sn.placeholders.keys())
-
-                if len(keys) == 0:
-                        if 0 in sn.placeholders:
-                                self.goto_placeholder(self.active_placeholder, sn.placeholders[0])
-                        else:
-                                buf.place_cursor(sn.begin_iter())
-                else:
-                        self.goto_placeholder(self.active_placeholder, sn.placeholders[keys[0]])
+        piter = buf.get_iter_at_mark(buf.get_insert())
+        found = current = next = None
+        length = len(self.placeholders)
+
+        placeholders = list(self.placeholders)
+
+        if self.active_placeholder:
+            begin = self.active_placeholder.begin_iter()
+            end = self.active_placeholder.end_iter()
+
+            if piter.compare(begin) >= 0 and piter.compare(end) <= 0:
+                current = self.active_placeholder
+                currentIndex = placeholders.index(self.active_placeholder)
+
+        if direction == 1:
+            # w = piter, x = begin, y = end, z = found
+            nearest = lambda w, x, y, z: (w.compare(x) <= 0 and (not z or \
+                    x.compare(z.begin_iter()) < 0))
+            indexer = lambda x: x < length - 1
+        else:
+            # w = piter, x = begin, y = end, z = prev
+            nearest = lambda w, x, y, z: (w.compare(x) >= 0 and (not z or \
+                    x.compare(z.begin_iter()) >= 0))
+            indexer = lambda x: x > 0
+
+        for index in range(0, length):
+            placeholder = placeholders[index]
+            begin = placeholder.begin_iter()
+            end = placeholder.end_iter()
+
+            # Find the nearest placeholder
+            if nearest(piter, begin, end, found):
+                foundIndex = index
+                found = placeholder
+
+            # Find the current placeholder
+            if piter.compare(begin) >= 0 and \
+                    piter.compare(end) <= 0 and \
+                    current == None:
+                currentIndex = index
+                current = placeholder
+
+        if current and current != found and \
+           (current.begin_iter().compare(found.begin_iter()) == 0 or \
+            current.end_iter().compare(found.begin_iter()) == 0) and \
+           self.active_placeholder and \
+           current.begin_iter().compare(self.active_placeholder.begin_iter()) == 0:
+            # if current and found are at the same place, then
+            # resolve the 'hugging' problem
+            current = self.active_placeholder
+            currentIndex = placeholders.index(current)
+
+        if current:
+            if indexer(currentIndex):
+                next = placeholders[currentIndex + direction]
+        elif found:
+            next = found
+        elif length > 0:
+            next = self.placeholders[0]
+
+        return current, next
+
+    def next_placeholder(self):
+        return self.advance_placeholder(1)
+
+    def previous_placeholder(self):
+        return self.advance_placeholder(-1)
+
+    def cursor_on_screen(self):
+        buf = self.view.get_buffer()
+        self.view.scroll_mark_onscreen(buf.get_insert())
+
+    def set_active_placeholder(self, placeholder):
+        self.active_placeholder = placeholder
+
+    def goto_placeholder(self, current, next):
+        last = None
+
+        if current:
+            # Signal this placeholder to end action
+            self.view.get_completion().hide()
+            current.leave()
+
+            if current.__class__ == PlaceholderEnd:
+                last = current
+
+        self.set_active_placeholder(next)
+
+        if next:
+            next.enter()
+
+            if next.__class__ == PlaceholderEnd:
+                last = next
+            elif len(next.defaults) > 1 and next.get_text() == next.default:
+                provider = Completion.Defaults(self.on_default_activated)
+                provider.set_defaults(next.defaults)
+
+                cm = self.view.get_completion()
+                cm.show([provider], cm.create_context(None))
+
+        if last:
+            # This is the end of the placeholder, remove the snippet etc
+            for snippet in list(self.active_snippets):
+                if snippet.placeholders[0] == last:
+                    self.deactivate_snippet(snippet)
+                    break
+
+        self.cursor_on_screen()
+
+        return next != None
+
+    def skip_to_next_placeholder(self):
+        (current, next) = self.next_placeholder()
+        return self.goto_placeholder(current, next)
+
+    def skip_to_previous_placeholder(self):
+        (current, prev) = self.previous_placeholder()
+        return self.goto_placeholder(current, prev)
+
+    def env_get_selected_text(self, buf):
+        bounds = buf.get_selection_bounds()
+
+        if bounds:
+            return buf.get_text(bounds[0], bounds[1], False)
+        else:
+            return ''
+
+    def env_get_current_word(self, buf):
+        start, end = buffer_word_boundary(buf)
+
+        return buf.get_text(start, end, False)
+
+    def env_get_current_line(self, buf):
+        start, end = buffer_line_boundary(buf)
+
+        return buf.get_text(start, end, False)
+
+    def env_get_current_line_number(self, buf):
+        start, end = buffer_line_boundary(buf)
+        return str(start.get_line() + 1)
+
+    def env_get_document_uri(self, buf):
+        location = buf.get_location()
+
+        if location:
+            return location.get_uri()
+        else:
+            return ''
+
+    def env_get_document_name(self, buf):
+        location = buf.get_location()
+
+        if location:
+            return location.get_basename()
+        else:
+            return ''
+
+    def env_get_document_scheme(self, buf):
+        location = buf.get_location()
+
+        if location:
+            return location.get_uri_scheme()
+        else:
+            return ''
+
+    def env_get_document_path(self, buf):
+        location = buf.get_location()
+
+        if location:
+            return location.get_path()
+        else:
+            return ''
+
+    def env_get_document_dir(self, buf):
+        location = buf.get_location()
+
+        if location:
+            return location.get_parent().get_path() or ''
+        else:
+            return ''
+
+    def env_get_document_type(self, buf):
+        typ = buf.get_mime_type()
+
+        if typ:
+            return typ
+        else:
+            return ''
+
+    def env_get_documents_uri(self, buf):
+        toplevel = self.view.get_toplevel()
+
+        if isinstance(toplevel, Pluma.Window):
+            documents_uri = [doc.get_location().get_uri()
+                     for doc in toplevel.get_documents()
+                     if doc.get_location() is not None]
+        else:
+            documents_uri = []
+
+        return ' '.join(documents_uri)
+
+    def env_get_documents_path(self, buf):
+        toplevel = self.view.get_toplevel()
 
-                if sn in self.active_snippets:
-                        # Check if we can get end_iter in view without moving the
-                        # current cursor position out of view
-                        cur = buf.get_iter_at_mark(buf.get_insert())
-                        last = sn.end_iter()
+        if isinstance(toplevel, Pluma.Window):
+            documents_location = [doc.get_location()
+                          for doc in toplevel.get_documents()
+                          if doc.get_location() is not None]
 
-                        curloc = self.view.get_iter_location(cur)
-                        lastloc = self.view.get_iter_location(last)
+            documents_path = [location.get_path()
+                      for location in documents_location
+                      if Pluma.utils_uri_has_file_scheme(location.get_uri())]
+        else:
+            documents_path = []
 
-                        if (lastloc.y + lastloc.height) - curloc.y <= \
-                           self.view.get_visible_rect().height:
-                                self.view.scroll_mark_onscreen(sn.end_mark)
+        return ' '.join(documents_path)
 
-                buf.end_user_action()
-                self.view.grab_focus()
+    def update_environment(self):
+        buf = self.view.get_buffer()
 
+        variables = {'PLUMA_SELECTED_TEXT': self.env_get_selected_text,
+                 'PLUMA_CURRENT_WORD': self.env_get_current_word,
+                 'PLUMA_CURRENT_LINE': self.env_get_current_line,
+                 'PLUMA_CURRENT_LINE_NUMBER': self.env_get_current_line_number,
+                 'PLUMA_CURRENT_DOCUMENT_URI': self.env_get_document_uri,
+                 'PLUMA_CURRENT_DOCUMENT_NAME': self.env_get_document_name,
+                 'PLUMA_CURRENT_DOCUMENT_SCHEME': self.env_get_document_scheme,
+                 'PLUMA_CURRENT_DOCUMENT_PATH': self.env_get_document_path,
+                 'PLUMA_CURRENT_DOCUMENT_DIR': self.env_get_document_dir,
+                 'PLUMA_CURRENT_DOCUMENT_TYPE': self.env_get_document_type,
+                 'PLUMA_DOCUMENTS_URI': self.env_get_documents_uri,
+                 'PLUMA_DOCUMENTS_PATH': self.env_get_documents_path,
+            }
+
+        for var in variables:
+            os.environ[var] = variables[var](buf)
+
+    def uses_current_word(self, snippet):
+        matches = re.findall('(\\\\*)\\$PLUMA_CURRENT_WORD', snippet['text'])
+
+        for match in matches:
+            if len(match) % 2 == 0:
                 return True
 
-        def get_tab_tag(self, buf, end = None):
-                if not end:
-                        end = buf.get_iter_at_mark(buf.get_insert())
+        return False
 
-                start = end.copy()
-                
-                word = None
-                
-                if start.backward_word_start():
-                        # Check if we were at a word start ourselves
-                        tmp = start.copy()
-                        tmp.forward_word_end()
-                        
-                        if tmp.equal(end):
-                                word = buf.get_text(start, end, False)
-                        else:
-                                start = end.copy()
-                else:
-                        start = end.copy()
-                
-                if not word or word == '':
-                        if start.backward_char():
-                                word = start.get_char()
+    def uses_current_line(self, snippet):
+        matches = re.findall('(\\\\*)\\$PLUMA_CURRENT_LINE', snippet['text'])
 
-                                if word.isalnum() or word.isspace():
-                                        return (None, None, None)
-                        else:
-                                return (None, None, None)
+        for match in matches:
+            if len(match) % 2 == 0:
+                return True
 
-                return (word, start, end)
+        return False
 
-        def parse_and_run_snippet(self, data, iter):
-                self.apply_snippet(DynamicSnippet(data), iter, iter)
+    def apply_snippet(self, snippet, start = None, end = None):
+        if not snippet.valid:
+            return False
 
-        def run_snippet_trigger(self, trigger, bounds):
-                if not self.view:
-                        return False
+        buf = self.view.get_buffer()
+        s = Snippet(snippet)
 
-                snippets = Library().from_tag(trigger, self.language_id)
-                buf = self.view.get_buffer()
+        if not start:
+            start = buf.get_iter_at_mark(buf.get_insert())
 
-                if snippets:
-                        if len(snippets) == 1:
-                                return self.apply_snippet(snippets[0], bounds[0], bounds[1])
-                        else:
-                                # Do the fancy completion dialog
-                                provider = Completion.Provider(_('Snippets'), self.language_id, self.on_proposal_activated)
-                                provider.set_proposals(snippets)
+        if not end:
+            end = buf.get_iter_at_mark(buf.get_selection_bound())
 
-                                cm = self.view.get_completion()
-                                cm.show([provider], cm.create_context(None))
+        if start.equal(end) and self.uses_current_word(s):
+            # There is no tab trigger and no selection and the snippet uses
+            # the current word. Set start and end to the word boundary so that
+            # it will be removed
+            start, end = buffer_word_boundary(buf)
+        elif start.equal(end) and self.uses_current_line(s):
+            # There is no tab trigger and no selection and the snippet uses
+            # the current line. Set start and end to the line boundary so that
+            # it will be removed
+            start, end = buffer_line_boundary(buf)
 
-                                return True
+        # Set environmental variables
+        self.update_environment()
 
-                return False
-                
-        def run_snippet(self):
-                if not self.view:
-                        return False
+        # You know, we could be in an end placeholder
+        (current, next) = self.next_placeholder()
+        if current and current.__class__ == PlaceholderEnd:
+            self.goto_placeholder(current, None)
 
-                buf = self.view.get_buffer()
+        buf.begin_user_action()
 
-                # get the word preceding the current insertion position
-                (word, start, end) = self.get_tab_tag(buf)
+        # Remove the tag, selection or current word
+        buf.delete(start, end)
 
-                if not word:
-                        return self.skip_to_next_placeholder()
+        # Insert the snippet
+        holders = len(self.placeholders)
 
-                if not self.run_snippet_trigger(word, (start, end)):
-                        return self.skip_to_next_placeholder()
-                else:
-                        return True
+        if len(self.active_snippets) == 0:
+            self.first_snippet_inserted()
 
-        def deactivate_snippet(self, snippet, force = False):
-                buf = self.view.get_buffer()
-                remove = []
-                ordered_remove = []
+        sn = s.insert_into(self, start)
+        self.active_snippets.append(sn)
 
-                for tabstop in snippet.placeholders:
-                        if tabstop == -1:
-                                placeholders = snippet.placeholders[-1]
-                        else:
-                                placeholders = [snippet.placeholders[tabstop]]
-                        
-                        for placeholder in placeholders:
-                                if placeholder in self.placeholders:
-                                        if placeholder in self.update_placeholders:
-                                                placeholder.update_contents()
-                                                
-                                                self.update_placeholders.remove(placeholder)
-                                        elif placeholder in self.jump_placeholders:
-                                                placeholder[0].leave()
+        # Put cursor at first tab placeholder
+        keys = filter(lambda x: x > 0, sn.placeholders.keys())
 
-                                        remove.append(placeholder)
-                                elif placeholder in self.ordered_placeholders:
-                                        ordered_remove.append(placeholder)
+        if len(keys) == 0:
+            if 0 in sn.placeholders:
+                self.goto_placeholder(self.active_placeholder, sn.placeholders[0])
+            else:
+                buf.place_cursor(sn.begin_iter())
+        else:
+            self.goto_placeholder(self.active_placeholder, sn.placeholders[keys[0]])
 
-                for placeholder in remove:
-                        if placeholder == self.active_placeholder:
-                                self.active_placeholder = None
+        if sn in self.active_snippets:
+            # Check if we can get end_iter in view without moving the
+            # current cursor position out of view
+            cur = buf.get_iter_at_mark(buf.get_insert())
+            last = sn.end_iter()
 
-                        self.placeholders.remove(placeholder)
-                        self.ordered_placeholders.remove(placeholder)
+            curloc = self.view.get_iter_location(cur)
+            lastloc = self.view.get_iter_location(last)
 
-                        placeholder.remove(force)
+            if (lastloc.y + lastloc.height) - curloc.y <= \
+               self.view.get_visible_rect().height:
+                self.view.scroll_mark_onscreen(sn.end_mark)
 
-                for placeholder in ordered_remove:
-                        self.ordered_placeholders.remove(placeholder)
-                        placeholder.remove(force)
+        buf.end_user_action()
+        self.view.grab_focus()
 
-                snippet.deactivate()
-                self.active_snippets.remove(snippet)
+        return True
 
-                if len(self.active_snippets) == 0:
-                        self.last_snippet_removed()
+    def get_tab_tag(self, buf, end = None):
+        if not end:
+            end = buf.get_iter_at_mark(buf.get_insert())
 
-                self.view.queue_draw()
+        start = end.copy()
+        word = None
 
-        def update_snippet_contents(self):
-                self.timeout_update_id = 0
+        if start.backward_word_start():
+            # Check if we were at a word start ourselves
+            tmp = start.copy()
+            tmp.forward_word_end()
 
-                for placeholder in self.update_placeholders:
-                        placeholder.update_contents()
+            if tmp.equal(end):
+                word = buf.get_text(start, end, False)
+            else:
+                start = end.copy()
+        else:
+            start = end.copy()
 
-                for placeholder in self.jump_placeholders:
-                        self.goto_placeholder(placeholder[0], placeholder[1])
-
-                del self.update_placeholders[:]
-                del self.jump_placeholders[:]
-
-                return False
-
-        # Callbacks
-        def on_view_destroy(self, view):
-                self.stop()
-                return
-
-        def on_buffer_cursor_moved(self, buf):
-                piter = buf.get_iter_at_mark(buf.get_insert())
-
-                # Check for all snippets if the cursor is outside its scope
-                for snippet in list(self.active_snippets):
-                        if snippet.begin_mark.get_deleted() or snippet.end_mark.get_deleted():
-                                self.deactivate(snippet)
-                        else:
-                                begin = snippet.begin_iter()
-                                end = snippet.end_iter()
-                        
-                                if piter.compare(begin) < 0 or piter.compare(end) > 0:
-                                        # Oh no! Remove the snippet this instant!!
-                                        self.deactivate_snippet(snippet)
-
-                current = self.current_placeholder()
-
-                if current != self.active_placeholder:
-                        self.jump_placeholders.append((self.active_placeholder, current))
-
-                        if self.timeout_update_id == 0:
-                                self.timeout_update_id = GLib.timeout_add(0, 
-                                                self.update_snippet_contents)
-
-        def on_buffer_changed(self, buf):
-                for snippet in list(self.active_snippets):
-                        begin = snippet.begin_iter()
-                        end = snippet.end_iter()
-
-                        if begin.compare(end) >= 0:
-                                # Begin collapsed on end, just remove it
-                                self.deactivate_snippet(snippet)
-
-                current = self.current_placeholder()
-
-                if current:
-                        if not current in self.update_placeholders:
-                                self.update_placeholders.append(current)
-                
-                        if self.timeout_update_id == 0:
-                                self.timeout_update_id = GLib.timeout_add(0, \
-                                                self.update_snippet_contents)
-        
-        def on_buffer_insert_text(self, buf, piter, text, length):
-                ctx = get_buffer_context(buf)
-                
-                # do nothing special if there is no context and no active 
-                # placeholder
-                if (not ctx) and (not self.active_placeholder):
-                        return
-                
-                if not ctx:
-                        ctx = self.active_placeholder
-                
-                if not ctx in self.ordered_placeholders:
-                        return
-                        
-                # move any marks that were incorrectly moved by this insertion
-                # back to where they belong
-                begin = ctx.begin_iter()
-                end = ctx.end_iter()
-                idx = self.ordered_placeholders.index(ctx)
-                
-                for placeholder in self.ordered_placeholders:
-                        if placeholder == ctx:
-                                continue
-                        
-                        ob = placeholder.begin_iter()
-                        oe = placeholder.end_iter()
-                        
-                        if ob.compare(begin) == 0 and ((not oe) or oe.compare(end) == 0):
-                                oidx = self.ordered_placeholders.index(placeholder)
-                                
-                                if oidx > idx and ob:
-                                        buf.move_mark(placeholder.begin, end)
-                                elif oidx < idx and oe:
-                                        buf.move_mark(placeholder.end, begin)
-                        elif ob.compare(begin) >= 0 and ob.compare(end) < 0 and (oe and oe.compare(end) >= 0):
-                                buf.move_mark(placeholder.begin, end)
-                        elif (oe and oe.compare(begin) > 0) and ob.compare(begin) <= 0:
-                                buf.move_mark(placeholder.end, begin)
-        
-        def on_notify_language(self, buf, spec):
-                self.update_language()
-
-        def on_notify_editable(self, view, spec):
-                self._set_view(view)
-        
-        def on_view_key_press(self, view, event):
-                library = Library()
-
-                state = event.get_state()
-
-                if not (state & Gdk.ModifierType.CONTROL_MASK) and \
-                                not (state & Gdk.ModifierType.MOD1_MASK) and \
-                                event.keyval in self.TAB_KEY_VAL:
-                        if not state & Gdk.ModifierType.SHIFT_MASK:
-                                return self.run_snippet()
-                        else:
-                                return self.skip_to_previous_placeholder()
-                elif not library.loaded and \
-                                library.valid_accelerator(event.keyval, state):
-                        library.ensure_files()
-                        library.ensure(self.language_id)
-                        self.accelerator_activate(event.keyval, \
-                                        state & Gtk.accelerator_get_default_mod_mask())
-
-                return False
-        
-        def path_split(self, path, components=[]):
-                head, tail = os.path.split(path)
-                
-                if not tail and head:
-                        return [head] + components
-                elif tail:
-                        return self.path_split(head, [tail] + components)
-                else:
-                        return components
-
-        def relative_path(self, first, second, mime):
-                prot1 = re.match('(^[a-z]+:\/\/|\/)(.*)', first)
-                prot2 = re.match('(^[a-z]+:\/\/|\/)(.*)', second)
-
-                if not prot1 or not prot2:
-                        return second
-
-                # Different protocols
-                if prot1.group(1) != prot2.group(1):
-                        return second
-
-                # Split on backslash
-                path1 = self.path_split(prot1.group(2))
-                path2 = self.path_split(prot2.group(2))
-
-                # Remove as long as common
-                while path1 and path2 and path1[0] == path2[0]:
-                        path1.pop(0)
-                        path2.pop(0)
-
-                # If we need to ../ more than 3 times, then just return
-                # the absolute path
-                if len(path1) - 1 > 3:
-                        return second
-
-                if mime.startswith('x-directory'):
-                        # directory, special case
-                        if not path2:
-                                result = './'
-                        else:
-                                result = '../' * (len(path1) - 1)
-                else:
-                        # Insert ../
-                        result = '../' * (len(path1) - 1)
-
-                        if not path2:
-                                result = os.path.basename(second)
-                
-                if path2:
-                        result += os.path.join(*path2)
-
-                return result
-
-        def apply_uri_snippet(self, snippet, mime, uri):
-                # Remove file scheme
-                gfile = Gio.file_new_for_uri(uri)
-                pathname = ''
-                dirname = ''
-                ruri = ''
-
-                if Pluma.utils_uri_has_file_scheme(uri):
-                        pathname = gfile.get_path()
-                        dirname = gfile.get_parent().get_path()
-
-                name = os.path.basename(uri)
-                scheme = gfile.get_uri_scheme()
-
-                os.environ['PLUMA_DROP_DOCUMENT_URI'] = uri
-                os.environ['PLUMA_DROP_DOCUMENT_NAME'] = name
-                os.environ['PLUMA_DROP_DOCUMENT_SCHEME'] = scheme
-                os.environ['PLUMA_DROP_DOCUMENT_PATH'] = pathname
-                os.environ['PLUMA_DROP_DOCUMENT_DIR'] = dirname
-                os.environ['PLUMA_DROP_DOCUMENT_TYPE'] = mime
-
-                buf = self.view.get_buffer()
-                location = buf.get_location()
-                if location:
-                        ruri = location.get_uri()
-
-                relpath = self.relative_path(ruri, uri, mime)
-
-                os.environ['PLUMA_DROP_DOCUMENT_RELATIVE_PATH'] = relpath
-
-                mark = buf.get_mark('gtk_drag_target')
-                
-                if not mark:
-                        mark = buf.get_insert()
-
-                piter = buf.get_iter_at_mark(mark)
-                self.apply_snippet(snippet, piter, piter)
-
-        def in_bounds(self, x, y):
-                rect = self.view.get_visible_rect()
-                rect.x, rect.y = self.view.buffer_to_window_coords(Gtk.TextWindowType.WIDGET, rect.x, rect.y)
-
-                return not (x < rect.x or x > rect.x + rect.width or y < rect.y or y > rect.y + rect.height)
-        
-        def on_drag_data_received(self, view, context, x, y, data, info, timestamp):   
-                uris = drop_get_uris(data)
-                if not uris:
-                        return
-
-                if not self.in_bounds(x, y):
-                        return
-
-                uris.reverse()
-                stop = False
-                
-                for uri in uris:
-                        try:
-                                mime = Gio.content_type_guess(uri)
-                        except:
-                                mime = None
-
-                        if not mime:
-                                continue
-                        
-                        snippets = Library().from_drop_target(mime, self.language_id)
-                        
-                        if snippets:
-                                stop = True
-                                self.apply_uri_snippet(snippets[0], mime, uri)
-
-                if stop:
-                        context.finish(True, False, timestamp)
-                        view.stop_emission('drag-data-received')
-                        view.get_toplevel().present()
-                        view.grab_focus()
-        
-        def find_uri_target(self, context):
-                lst = Gtk.target_list_add_uri_targets((), 0)
-                
-                return self.view.drag_dest_find_target(context, lst)
-        
-        def on_proposal_activated(self, proposal, piter):
-                buf = self.view.get_buffer()
-                bounds = buf.get_selection_bounds()
-                
-                if bounds:
-                        self.apply_snippet(proposal.snippet(), None, None)
-                else:
-                        (word, start, end) = self.get_tab_tag(buf, piter)
-                        self.apply_snippet(proposal.snippet(), start, end)
+        if not word or word == '':
+            if start.backward_char():
+                word = start.get_char()
+
+                if word.isalnum() or word.isspace():
+                    return (None, None, None)
+            else:
+                return (None, None, None)
+
+        return (word, start, end)
+
+    def parse_and_run_snippet(self, data, iter):
+        self.apply_snippet(DynamicSnippet(data), iter, iter)
+
+    def run_snippet_trigger(self, trigger, bounds):
+        if not self.view:
+            return False
+
+        snippets = Library().from_tag(trigger, self.language_id)
+        buf = self.view.get_buffer()
+
+        if snippets:
+            if len(snippets) == 1:
+                return self.apply_snippet(snippets[0], bounds[0], bounds[1])
+            else:
+                # Do the fancy completion dialog
+                provider = Completion.Provider(_('Snippets'), self.language_id, self.on_proposal_activated)
+                provider.set_proposals(snippets)
+
+                cm = self.view.get_completion()
+                cm.show([provider], cm.create_context(None))
 
                 return True
-        
-        def on_default_activated(self, proposal, piter):
-                buf = self.view.get_buffer()
-                bounds = buf.get_selection_bounds()
-
-                if bounds:
-                        buf.begin_user_action()
-                        buf.delete(bounds[0], bounds[1])
-                        buf.insert(bounds[0], proposal.props.label)
-                        buf.end_user_action()
-
-                        return True
+
+        return False
+
+    def run_snippet(self):
+        if not self.view:
+            return False
+
+        buf = self.view.get_buffer()
+
+        # get the word preceding the current insertion position
+        (word, start, end) = self.get_tab_tag(buf)
+
+        if not word:
+            return self.skip_to_next_placeholder()
+
+        if not self.run_snippet_trigger(word, (start, end)):
+            return self.skip_to_next_placeholder()
+        else:
+            return True
+
+    def deactivate_snippet(self, snippet, force = False):
+        buf = self.view.get_buffer()
+        remove = []
+        ordered_remove = []
+
+        for tabstop in snippet.placeholders:
+            if tabstop == -1:
+                placeholders = snippet.placeholders[-1]
+            else:
+                placeholders = [snippet.placeholders[tabstop]]
+
+            for placeholder in placeholders:
+                if placeholder in self.placeholders:
+                    if placeholder in self.update_placeholders:
+                        placeholder.update_contents()
+
+                        self.update_placeholders.remove(placeholder)
+                    elif placeholder in self.jump_placeholders:
+                        placeholder[0].leave()
+
+                    remove.append(placeholder)
+                elif placeholder in self.ordered_placeholders:
+                    ordered_remove.append(placeholder)
+
+        for placeholder in remove:
+            if placeholder == self.active_placeholder:
+                self.active_placeholder = None
+
+            self.placeholders.remove(placeholder)
+            self.ordered_placeholders.remove(placeholder)
+
+            placeholder.remove(force)
+
+        for placeholder in ordered_remove:
+            self.ordered_placeholders.remove(placeholder)
+            placeholder.remove(force)
+
+        snippet.deactivate()
+        self.active_snippets.remove(snippet)
+
+        if len(self.active_snippets) == 0:
+            self.last_snippet_removed()
+
+        self.view.queue_draw()
+
+    def update_snippet_contents(self):
+        self.timeout_update_id = 0
+
+        for placeholder in self.update_placeholders:
+            placeholder.update_contents()
+
+        for placeholder in self.jump_placeholders:
+            self.goto_placeholder(placeholder[0], placeholder[1])
+
+        del self.update_placeholders[:]
+        del self.jump_placeholders[:]
+
+        return False
+
+    # Callbacks
+    def on_view_destroy(self, view):
+        self.stop()
+        return
+
+    def on_buffer_cursor_moved(self, buf):
+        piter = buf.get_iter_at_mark(buf.get_insert())
+
+        # Check for all snippets if the cursor is outside its scope
+        for snippet in list(self.active_snippets):
+            if snippet.begin_mark.get_deleted() or snippet.end_mark.get_deleted():
+                self.deactivate(snippet)
+            else:
+                begin = snippet.begin_iter()
+                end = snippet.end_iter()
+
+                if piter.compare(begin) < 0 or piter.compare(end) > 0:
+                    # Oh no! Remove the snippet this instant!!
+                    self.deactivate_snippet(snippet)
+
+        current = self.current_placeholder()
+
+        if current != self.active_placeholder:
+            self.jump_placeholders.append((self.active_placeholder, current))
+
+            if self.timeout_update_id == 0:
+                self.timeout_update_id = GLib.timeout_add(0,
+                        self.update_snippet_contents)
+
+    def on_buffer_changed(self, buf):
+        for snippet in list(self.active_snippets):
+            begin = snippet.begin_iter()
+            end = snippet.end_iter()
+
+            if begin.compare(end) >= 0:
+                # Begin collapsed on end, just remove it
+                self.deactivate_snippet(snippet)
+
+        current = self.current_placeholder()
+
+        if current:
+            if not current in self.update_placeholders:
+                self.update_placeholders.append(current)
+
+            if self.timeout_update_id == 0:
+                self.timeout_update_id = GLib.timeout_add(0, \
+                        self.update_snippet_contents)
+
+    def on_buffer_insert_text(self, buf, piter, text, length):
+        ctx = get_buffer_context(buf)
+
+        # do nothing special if there is no context and no active
+        # placeholder
+        if (not ctx) and (not self.active_placeholder):
+            return
+
+        if not ctx:
+            ctx = self.active_placeholder
+
+        if not ctx in self.ordered_placeholders:
+            return
+
+        # move any marks that were incorrectly moved by this insertion
+        # back to where they belong
+        begin = ctx.begin_iter()
+        end = ctx.end_iter()
+        idx = self.ordered_placeholders.index(ctx)
+
+        for placeholder in self.ordered_placeholders:
+            if placeholder == ctx:
+                continue
+
+            ob = placeholder.begin_iter()
+            oe = placeholder.end_iter()
+
+            if ob.compare(begin) == 0 and ((not oe) or oe.compare(end) == 0):
+                oidx = self.ordered_placeholders.index(placeholder)
+
+                if oidx > idx and ob:
+                    buf.move_mark(placeholder.begin, end)
+                elif oidx < idx and oe:
+                    buf.move_mark(placeholder.end, begin)
+            elif ob.compare(begin) >= 0 and ob.compare(end) < 0 and (oe and oe.compare(end) >= 0):
+                buf.move_mark(placeholder.begin, end)
+            elif (oe and oe.compare(begin) > 0) and ob.compare(begin) <= 0:
+                buf.move_mark(placeholder.end, begin)
+
+    def on_notify_language(self, buf, spec):
+        self.update_language()
+
+    def on_notify_editable(self, view, spec):
+        self._set_view(view)
+
+    def on_view_key_press(self, view, event):
+        library = Library()
+
+        state = event.get_state()
+
+        if not (state & Gdk.ModifierType.CONTROL_MASK) and \
+                not (state & Gdk.ModifierType.MOD1_MASK) and \
+                event.keyval in self.TAB_KEY_VAL:
+            if not state & Gdk.ModifierType.SHIFT_MASK:
+                return self.run_snippet()
+            else:
+                return self.skip_to_previous_placeholder()
+        elif not library.loaded and \
+                library.valid_accelerator(event.keyval, state):
+            library.ensure_files()
+            library.ensure(self.language_id)
+            self.accelerator_activate(event.keyval, \
+                    state & Gtk.accelerator_get_default_mod_mask())
+
+        return False
+
+    def path_split(self, path, components=[]):
+        head, tail = os.path.split(path)
+
+        if not tail and head:
+            return [head] + components
+        elif tail:
+            return self.path_split(head, [tail] + components)
+        else:
+            return components
+
+    def relative_path(self, first, second, mime):
+        prot1 = re.match('(^[a-z]+:\/\/|\/)(.*)', first)
+        prot2 = re.match('(^[a-z]+:\/\/|\/)(.*)', second)
+
+        if not prot1 or not prot2:
+            return second
+
+        # Different protocols
+        if prot1.group(1) != prot2.group(1):
+            return second
+
+        # Split on backslash
+        path1 = self.path_split(prot1.group(2))
+        path2 = self.path_split(prot2.group(2))
+
+        # Remove as long as common
+        while path1 and path2 and path1[0] == path2[0]:
+            path1.pop(0)
+            path2.pop(0)
+
+        # If we need to ../ more than 3 times, then just return
+        # the absolute path
+        if len(path1) - 1 > 3:
+            return second
+
+        if mime.startswith('x-directory'):
+            # directory, special case
+            if not path2:
+                result = './'
+            else:
+                result = '../' * (len(path1) - 1)
+        else:
+            # Insert ../
+            result = '../' * (len(path1) - 1)
+
+            if not path2:
+                result = os.path.basename(second)
+
+        if path2:
+            result += os.path.join(*path2)
+
+        return result
+
+    def apply_uri_snippet(self, snippet, mime, uri):
+        # Remove file scheme
+        gfile = Gio.file_new_for_uri(uri)
+        pathname = ''
+        dirname = ''
+        ruri = ''
+
+        if Pluma.utils_uri_has_file_scheme(uri):
+            pathname = gfile.get_path()
+            dirname = gfile.get_parent().get_path()
+
+        name = os.path.basename(uri)
+        scheme = gfile.get_uri_scheme()
+
+        os.environ['PLUMA_DROP_DOCUMENT_URI'] = uri
+        os.environ['PLUMA_DROP_DOCUMENT_NAME'] = name
+        os.environ['PLUMA_DROP_DOCUMENT_SCHEME'] = scheme
+        os.environ['PLUMA_DROP_DOCUMENT_PATH'] = pathname
+        os.environ['PLUMA_DROP_DOCUMENT_DIR'] = dirname
+        os.environ['PLUMA_DROP_DOCUMENT_TYPE'] = mime
+
+        buf = self.view.get_buffer()
+        location = buf.get_location()
+        if location:
+            ruri = location.get_uri()
+
+        relpath = self.relative_path(ruri, uri, mime)
+
+        os.environ['PLUMA_DROP_DOCUMENT_RELATIVE_PATH'] = relpath
+
+        mark = buf.get_mark('gtk_drag_target')
+
+        if not mark:
+            mark = buf.get_insert()
+
+        piter = buf.get_iter_at_mark(mark)
+        self.apply_snippet(snippet, piter, piter)
+
+    def in_bounds(self, x, y):
+        rect = self.view.get_visible_rect()
+        rect.x, rect.y = self.view.buffer_to_window_coords(Gtk.TextWindowType.WIDGET, rect.x, rect.y)
+
+        return not (x < rect.x or x > rect.x + rect.width or y < rect.y or y > rect.y + rect.height)
+
+    def on_drag_data_received(self, view, context, x, y, data, info, timestamp):
+        uris = drop_get_uris(data)
+        if not uris:
+            return
+
+        if not self.in_bounds(x, y):
+            return
+
+        uris.reverse()
+        stop = False
+
+        for uri in uris:
+            try:
+                mime = Gio.content_type_guess(uri)
+            except:
+                mime = None
+
+            if not mime:
+                continue
+
+            snippets = Library().from_drop_target(mime, self.language_id)
+
+            if snippets:
+                stop = True
+                self.apply_uri_snippet(snippets[0], mime, uri)
+
+        if stop:
+            context.finish(True, False, timestamp)
+            view.stop_emission('drag-data-received')
+            view.get_toplevel().present()
+            view.grab_focus()
+
+    def find_uri_target(self, context):
+        lst = Gtk.target_list_add_uri_targets((), 0)
+
+        return self.view.drag_dest_find_target(context, lst)
+
+    def on_proposal_activated(self, proposal, piter):
+        buf = self.view.get_buffer()
+        bounds = buf.get_selection_bounds()
+
+        if bounds:
+            self.apply_snippet(proposal.snippet(), None, None)
+        else:
+            (word, start, end) = self.get_tab_tag(buf, piter)
+            self.apply_snippet(proposal.snippet(), start, end)
+
+        return True
+
+    def on_default_activated(self, proposal, piter):
+        buf = self.view.get_buffer()
+        bounds = buf.get_selection_bounds()
+
+        if bounds:
+            buf.begin_user_action()
+            buf.delete(bounds[0], bounds[1])
+            buf.insert(bounds[0], proposal.props.label)
+            buf.end_user_action()
+
+            return True
+        else:
+            return False
+
+    def iter_coords(self, piter):
+        rect = self.view.get_iter_location(piter)
+        rect.x, rect.y = self.view.buffer_to_window_coords(Gtk.TextWindowType.TEXT, rect.x, rect.y)
+
+        return rect
+
+    def placeholder_in_area(self, placeholder, area):
+        start = placeholder.begin_iter()
+        end = placeholder.end_iter()
+
+        if not start or not end:
+            return False
+
+        # Test if start is before bottom, and end is after top
+        start_rect = self.iter_coords(start)
+        end_rect = self.iter_coords(end)
+
+        return start_rect.y <= area.y + area.height and \
+               end_rect.y + end_rect.height >= area.y
+
+    def draw_placeholder_rect(self, ctx, placeholder):
+        start = placeholder.begin_iter()
+        start_rect = self.iter_coords(start)
+        start_line = start.get_line()
+
+        end = placeholder.end_iter()
+        end_rect = self.iter_coords(end)
+        end_line = end.get_line()
+
+        line = start.copy()
+        line.set_line_offset(0)
+        geom = self.view.get_window(Gtk.TextWindowType.TEXT).get_geometry()
+
+        ctx.translate(0.5, 0.5)
+
+        while line.get_line() <= end_line:
+            ypos, height = self.view.get_line_yrange(line)
+            x_, ypos = self.view.window_to_buffer_coords(Gtk.TextWindowType.TEXT, 0, ypos)
+
+            if line.get_line() == start_line and line.get_line() == end_line:
+                # Simply draw a box, both are on the same line
+                ctx.rectangle(start_rect.x, start_rect.y, end_rect.x - start_rect.x, start_rect.height - 1)
+                ctx.stroke()
+            elif line.get_line() == start_line or line.get_line() == end_line:
+                if line.get_line() == start_line:
+                    rect = start_rect
                 else:
-                        return False
-
-        def iter_coords(self, piter):
-                rect = self.view.get_iter_location(piter)
-                rect.x, rect.y = self.view.buffer_to_window_coords(Gtk.TextWindowType.TEXT, rect.x, rect.y)
-
-                return rect
-
-        def placeholder_in_area(self, placeholder, area):
-                start = placeholder.begin_iter()
-                end = placeholder.end_iter()
-
-                if not start or not end:
-                        return False
-
-                # Test if start is before bottom, and end is after top
-                start_rect = self.iter_coords(start)
-                end_rect = self.iter_coords(end)
-
-                return start_rect.y <= area.y + area.height and \
-                       end_rect.y + end_rect.height >= area.y
-
-        def draw_placeholder_rect(self, ctx, placeholder):
-                start = placeholder.begin_iter()
-                start_rect = self.iter_coords(start)
-                start_line = start.get_line()
-
-                end = placeholder.end_iter()
-                end_rect = self.iter_coords(end)
-                end_line = end.get_line()
-
-                line = start.copy()
-                line.set_line_offset(0)
-                geom = self.view.get_window(Gtk.TextWindowType.TEXT).get_geometry()
-                
-                ctx.translate(0.5, 0.5)
-                
-                while line.get_line() <= end_line:
-                        ypos, height = self.view.get_line_yrange(line)
-                        x_, ypos = self.view.window_to_buffer_coords(Gtk.TextWindowType.TEXT, 0, ypos)
-
-                        if line.get_line() == start_line and line.get_line() == end_line:
-                                # Simply draw a box, both are on the same line
-                                ctx.rectangle(start_rect.x, start_rect.y, end_rect.x - start_rect.x, start_rect.height - 1)
-                                ctx.stroke()
-                        elif line.get_line() == start_line or line.get_line() == end_line:
-                                if line.get_line() == start_line:
-                                        rect = start_rect
-                                else:
-                                        rect = end_rect
-
-                                ctx.move_to(0, rect.y + rect.height - 1)
-                                ctx.rel_line_to(rect.x, 0)
-                                ctx.rel_line_to(0, -rect.height + 1)
-                                ctx.rel_line_to(geom[2], 0)
-                                ctx.stroke()
-
-                        if not line.forward_line():
-                                break
-
-        def draw_placeholder_bar(self, ctx, placeholder):
-                start = placeholder.begin_iter()
-                start_rect = self.iter_coords(start)
-                
-                ctx.translate(0.5, 0.5)
-                extend_width = 2.5
-
-                ctx.move_to(start_rect.x - extend_width, start_rect.y)
-                ctx.rel_line_to(extend_width * 2, 0)
-
-                ctx.move_to(start_rect.x, start_rect.y)
-                ctx.rel_line_to(0, start_rect.height - 1)
-                
-                ctx.rel_move_to(-extend_width, 0)
-                ctx.rel_line_to(extend_width * 2, 0)
+                    rect = end_rect
+
+                ctx.move_to(0, rect.y + rect.height - 1)
+                ctx.rel_line_to(rect.x, 0)
+                ctx.rel_line_to(0, -rect.height + 1)
+                ctx.rel_line_to(geom[2], 0)
                 ctx.stroke()
 
-        def draw_placeholder(self, ctx, placeholder):
-                if isinstance(placeholder, PlaceholderEnd):
-                        return
+            if not line.forward_line():
+                break
 
-                buf = self.view.get_buffer()
+    def draw_placeholder_bar(self, ctx, placeholder):
+        start = placeholder.begin_iter()
+        start_rect = self.iter_coords(start)
 
-                col = self.view.get_style_context().get_color(Gtk.StateFlags.INSENSITIVE)
-                col.alpha = 0.5
-                Gdk.cairo_set_source_rgba(ctx, col)
-                
-                if placeholder.tabstop > 0:
-                        ctx.set_dash([], 0)
-                else:
-                        ctx.set_dash([2], 0)
+        ctx.translate(0.5, 0.5)
+        extend_width = 2.5
 
-                start = placeholder.begin_iter()
-                end = placeholder.end_iter()
+        ctx.move_to(start_rect.x - extend_width, start_rect.y)
+        ctx.rel_line_to(extend_width * 2, 0)
 
-                if start.equal(end):
-                        self.draw_placeholder_bar(ctx, placeholder)
-                else:
-                        self.draw_placeholder_rect(ctx, placeholder)
+        ctx.move_to(start_rect.x, start_rect.y)
+        ctx.rel_line_to(0, start_rect.height - 1)
+
+        ctx.rel_move_to(-extend_width, 0)
+        ctx.rel_line_to(extend_width * 2, 0)
+        ctx.stroke()
+
+    def draw_placeholder(self, ctx, placeholder):
+        if isinstance(placeholder, PlaceholderEnd):
+            return
+
+        buf = self.view.get_buffer()
+
+        col = self.view.get_style_context().get_color(Gtk.StateFlags.INSENSITIVE)
+        col.alpha = 0.5
+        Gdk.cairo_set_source_rgba(ctx, col)
+
+        if placeholder.tabstop > 0:
+            ctx.set_dash([], 0)
+        else:
+            ctx.set_dash([2], 0)
+
+        start = placeholder.begin_iter()
+        end = placeholder.end_iter()
+
+        if start.equal(end):
+            self.draw_placeholder_bar(ctx, placeholder)
+        else:
+            self.draw_placeholder_rect(ctx, placeholder)
 
-        def on_draw(self, view, ctx):
-                window = view.get_window(Gtk.TextWindowType.TEXT)
+    def on_draw(self, view, ctx):
+        window = view.get_window(Gtk.TextWindowType.TEXT)
 
-                if not Gtk.cairo_should_draw_window(ctx, window):
-                        return False
+        if not Gtk.cairo_should_draw_window(ctx, window):
+            return False
 
-                ctx.set_line_width(1.0)
-                Gtk.cairo_transform_to_window(ctx, view, window)
-                clipped, clip = Gdk.cairo_get_clip_rectangle(ctx)
+        ctx.set_line_width(1.0)
+        Gtk.cairo_transform_to_window(ctx, view, window)
+        clipped, clip = Gdk.cairo_get_clip_rectangle(ctx)
 
-                if not clipped:
-                        return False
+        if not clipped:
+            return False
 
-                for placeholder in self.ordered_placeholders:
-                        if not self.placeholder_in_area(placeholder, clip):
-                                continue
+        for placeholder in self.ordered_placeholders:
+            if not self.placeholder_in_area(placeholder, clip):
+                continue
 
-                        ctx.save()
-                        self.draw_placeholder(ctx, placeholder)
-                        ctx.restore()
+            ctx.save()
+            self.draw_placeholder(ctx, placeholder)
+            ctx.restore()
 
-                return False
+        return False
 
-# ex:ts=8:et:
+# ex:ts=4:et:
diff --git a/plugins/snippets/snippets/Exporter.py b/plugins/snippets/snippets/Exporter.py
old mode 100755
new mode 100644
index 18369a6..850c3a4
--- a/plugins/snippets/snippets/Exporter.py
+++ b/plugins/snippets/snippets/Exporter.py
@@ -8,91 +8,91 @@ import xml.etree.ElementTree as et
 from Helper import *
 
 class Exporter:
-        def __init__(self, filename, snippets):
-                self.filename = filename
-                self.set_snippets(snippets)
-
-        def set_snippets(self, snippets):
-                self.snippets = {}
-                
-                for snippet in snippets:
-                        lang = snippet.language()
-
-                        if lang in self.snippets:
-                                self.snippets[lang].append(snippet)
-                        else:
-                                self.snippets[lang] = [snippet]
-
-        def export_xml(self, dirname, language, snippets):
-                # Create the root snippets node
-                root = et.Element('snippets')
-                
-                # Create filename based on language
-                if language:
-                        filename = os.path.join(dirname, language + '.xml')
-                        
-                        # Set the language attribute
-                        root.attrib['language'] = language
-                else:
-                        filename = os.path.join(dirname, 'global.xml')
-                
-                # Add all snippets to the root node
-                for snippet in snippets:
-                        root.append(snippet.to_xml())
-                
-                # Write xml
-                write_xml(root, filename, ('text', 'accelerator'))
-
-        def export_archive(self, cmd):
-                dirname = tempfile.mkdtemp()
-                
-                # Save current working directory and change to temporary directory
-                curdir = os.getcwd()
-                
-                try:
-                        os.chdir(dirname)
-                
-                        # Write snippet xml files
-                        for language, snippets in self.snippets.items():
-                                self.export_xml(dirname, language , snippets)
-                
-                        # Archive files
-                        status = os.system('%s "%s" *.xml' % (cmd, self.filename))
-                finally:
-                        os.chdir(curdir)
-                
-                if status != 0:
-                        return _('The archive "%s" could not be created' % self.filename)
-                
-                # Remove the temporary directory
-                shutil.rmtree(dirname)
-
-        def export_targz(self):
-                self.export_archive('tar -c --gzip -f')
-        
-        def export_tarbz2(self):
-                self.export_archive('tar -c --bzip2 -f')
-
-        def export_tar(self):
-                self.export_archive('tar -cf')
-        
-        def run(self):
-                dirname = os.path.dirname(self.filename)
-                if not os.path.exists(dirname):
-                        return _('Target directory "%s" does not exist') % dirname
-                
-                if not os.path.isdir(dirname):
-                        return _('Target directory "%s" is not a valid directory') % dirname
-                
-                (root, ext) = os.path.splitext(self.filename)
-                
-                actions = {'.tar.gz': self.export_targz,
-                           '.tar.bz2': self.export_tarbz2,
-                           '.tar': self.export_tar}
-
-                for k, v in actions.items():
-                        if self.filename.endswith(k):
-                                return v()
-                        
-                return self.export_targz()
-# ex:ts=8:et:
+    def __init__(self, filename, snippets):
+        self.filename = filename
+        self.set_snippets(snippets)
+
+    def set_snippets(self, snippets):
+        self.snippets = {}
+
+        for snippet in snippets:
+            lang = snippet.language()
+
+            if lang in self.snippets:
+                self.snippets[lang].append(snippet)
+            else:
+                self.snippets[lang] = [snippet]
+
+    def export_xml(self, dirname, language, snippets):
+        # Create the root snippets node
+        root = et.Element('snippets')
+
+        # Create filename based on language
+        if language:
+            filename = os.path.join(dirname, language + '.xml')
+
+            # Set the language attribute
+            root.attrib['language'] = language
+        else:
+            filename = os.path.join(dirname, 'global.xml')
+
+        # Add all snippets to the root node
+        for snippet in snippets:
+            root.append(snippet.to_xml())
+
+        # Write xml
+        write_xml(root, filename, ('text', 'accelerator'))
+
+    def export_archive(self, cmd):
+        dirname = tempfile.mkdtemp()
+
+        # Save current working directory and change to temporary directory
+        curdir = os.getcwd()
+
+        try:
+            os.chdir(dirname)
+
+            # Write snippet xml files
+            for language, snippets in self.snippets.items():
+                self.export_xml(dirname, language , snippets)
+
+            # Archive files
+            status = os.system('%s "%s" *.xml' % (cmd, self.filename))
+        finally:
+            os.chdir(curdir)
+
+        if status != 0:
+            return _('The archive "%s" could not be created' % self.filename)
+
+        # Remove the temporary directory
+        shutil.rmtree(dirname)
+
+    def export_targz(self):
+        self.export_archive('tar -c --gzip -f')
+
+    def export_tarbz2(self):
+        self.export_archive('tar -c --bzip2 -f')
+
+    def export_tar(self):
+        self.export_archive('tar -cf')
+
+    def run(self):
+        dirname = os.path.dirname(self.filename)
+        if not os.path.exists(dirname):
+            return _('Target directory "%s" does not exist') % dirname
+
+        if not os.path.isdir(dirname):
+            return _('Target directory "%s" is not a valid directory') % dirname
+
+        (root, ext) = os.path.splitext(self.filename)
+
+        actions = {'.tar.gz': self.export_targz,
+               '.tar.bz2': self.export_tarbz2,
+               '.tar': self.export_tar}
+
+        for k, v in actions.items():
+            if self.filename.endswith(k):
+                return v()
+
+        return self.export_targz()
+# ex:ts=4:et:
diff --git a/plugins/snippets/snippets/Helper.py b/plugins/snippets/snippets/Helper.py
old mode 100755
new mode 100644
index d8a1967..6d440d0
--- a/plugins/snippets/snippets/Helper.py
+++ b/plugins/snippets/snippets/Helper.py
@@ -23,164 +23,164 @@ import re
 from gi.repository import Gtk
 
 def message_dialog(par, typ, msg):
-        d = Gtk.MessageDialog(par, Gtk.DialogFlags.MODAL, typ, Gtk.ButtonsType.OK, msg)
-        d.set_property('use-markup', True)
+    d = Gtk.MessageDialog(par, Gtk.DialogFlags.MODAL, typ, Gtk.ButtonsType.OK, msg)
+    d.set_property('use-markup', True)
 
-        d.run()
-        d.destroy()
+    d.run()
+    d.destroy()
 
 def compute_indentation(view, piter):
-        line = piter.get_line()
-        start = view.get_buffer().get_iter_at_line(line)
-        end = start.copy()
-        
+    line = piter.get_line()
+    start = view.get_buffer().get_iter_at_line(line)
+    end = start.copy()
+
+    ch = end.get_char()
+
+    while (ch.isspace() and ch != '\r' and ch != '\n' and \
+            end.compare(piter) < 0):
+        if not end.forward_char():
+            break;
+
         ch = end.get_char()
-        
-        while (ch.isspace() and ch != '\r' and ch != '\n' and \
-                        end.compare(piter) < 0):
-                if not end.forward_char():
-                        break;
-                
-                ch = end.get_char()
-        
-        if start.equal(end):
-                return ''
-        
-        return start.get_slice(end)
+
+    if start.equal(end):
+        return ''
+
+    return start.get_slice(end)
 
 def markup_escape(text):
-        return saxutils.escape(text)
+    return saxutils.escape(text)
 
 def spaces_instead_of_tabs(view, text):
-        if not view.get_insert_spaces_instead_of_tabs():
-                return text
+    if not view.get_insert_spaces_instead_of_tabs():
+        return text
 
-        return text.replace("\t", view.get_tab_width() * ' ')
+    return text.replace("\t", view.get_tab_width() * ' ')
 
 def insert_with_indent(view, piter, text, indentfirst = True, context = None):
-        text = spaces_instead_of_tabs(view, text)
-        lines = text.split('\n')
-        buf = view.get_buffer()
+    text = spaces_instead_of_tabs(view, text)
+    lines = text.split('\n')
+    buf = view.get_buffer()
+
+    buf._snippets_context = context
 
-        buf._snippets_context = context
+    if len(lines) == 1:
+        view.get_buffer().insert(piter, text)
+    else:
+        # Compute indentation
+        indent = compute_indentation(view, piter)
+        text = ''
 
-        if len(lines) == 1:
-                view.get_buffer().insert(piter, text)
-        else:
-                # Compute indentation
-                indent = compute_indentation(view, piter)
-                text = ''
+        for i in range(0, len(lines)):
+            if indentfirst or i > 0:
+                text += indent + lines[i] + '\n'
+            else:
+                text += lines[i] + '\n'
 
-                for i in range(0, len(lines)):
-                        if indentfirst or i > 0:
-                                text += indent + lines[i] + '\n'
-                        else:
-                                text += lines[i] + '\n'
-                
-                buf.insert(piter, text[:-1])
+        buf.insert(piter, text[:-1])
 
-        buf._snippets_context = None
+    buf._snippets_context = None
 
 def get_buffer_context(buf):
-        if hasattr(buf, "_snippets_context"):
-                return buf._snippets_context
-        return None
+    if hasattr(buf, "_snippets_context"):
+        return buf._snippets_context
+    return None
 
 def snippets_debug(*s):
-        return
+    return
 
 def write_xml(node, f, cdata_nodes=()):
-        assert node is not None
+    assert node is not None
 
-        if not hasattr(f, "write"):
-                f = open(f, "wb")
+    if not hasattr(f, "write"):
+        f = open(f, "wb")
 
-        # Encoding
-        f.write("<?xml version='1.0' encoding='utf-8'?>\n")
+    # Encoding
+    f.write("<?xml version='1.0' encoding='utf-8'?>\n")
 
-        _write_node(node, f, cdata_nodes)
+    _write_node(node, f, cdata_nodes)
 
 def _write_indent(file, text, indent):
-        file.write('  ' * indent + text)
+    file.write('  ' * indent + text)
 
 def _write_node(node, file, cdata_nodes=(), indent=0):
-        # write XML to file
-        tag = node.tag
-
-        if node is Comment:
-                _write_indent(file, "<!-- %s -->\n" % saxutils.escape(node.text.encode('utf-8')), indent)
-        elif node is ProcessingInstruction:
-                _write_indent(file, "<?%s?>\n" % saxutils.escape(node.text.encode('utf-8')), indent)
-        else:
-                items = node.items()
-                
-                if items or node.text or len(node):
-                        _write_indent(file, "<" + tag.encode('utf-8'), indent)
-
-                        if items:
-                                items.sort() # lexical order
-                                for k, v in items:
-                                        file.write(" %s=%s" % (k.encode('utf-8'), saxutils.quoteattr(v.encode('utf-8'))))
-                        if node.text or len(node):
-                                file.write(">")
-                                if node.text and node.text.strip() != "":
-                                        if tag in cdata_nodes:
-                                                file.write(_cdata(node.text))
-                                        else:
-                                                file.write(saxutils.escape(node.text.encode('utf-8')))
-                                else:
-                                        file.write("\n")
-
-                                for n in node:
-                                        _write_node(n, file, cdata_nodes, indent + 1)
-                        
-                                if not len(node):
-                                        file.write("</" + tag.encode('utf-8') + ">\n")
-                                else:
-                                        _write_indent(file, "</" + tag.encode('utf-8') + ">\n", \
-                                                        indent)
-                        else:
-                                file.write(" />\n")
-
-                if node.tail and node.tail.strip() != "":
-                        file.write(saxutils.escape(node.tail.encode('utf-8')))
+    # write XML to file
+    tag = node.tag
+
+    if node is Comment:
+        _write_indent(file, "<!-- %s -->\n" % saxutils.escape(node.text.encode('utf-8')), indent)
+    elif node is ProcessingInstruction:
+        _write_indent(file, "<?%s?>\n" % saxutils.escape(node.text.encode('utf-8')), indent)
+    else:
+        items = node.items()
+
+        if items or node.text or len(node):
+            _write_indent(file, "<" + tag.encode('utf-8'), indent)
+
+            if items:
+                items.sort() # lexical order
+                for k, v in items:
+                    file.write(" %s=%s" % (k.encode('utf-8'), saxutils.quoteattr(v.encode('utf-8'))))
+            if node.text or len(node):
+                file.write(">")
+                if node.text and node.text.strip() != "":
+                    if tag in cdata_nodes:
+                        file.write(_cdata(node.text))
+                    else:
+                        file.write(saxutils.escape(node.text.encode('utf-8')))
+                else:
+                    file.write("\n")
+
+                for n in node:
+                    _write_node(n, file, cdata_nodes, indent + 1)
+
+                if not len(node):
+                    file.write("</" + tag.encode('utf-8') + ">\n")
+                else:
+                    _write_indent(file, "</" + tag.encode('utf-8') + ">\n", \
+                            indent)
+            else:
+                file.write(" />\n")
+
+        if node.tail and node.tail.strip() != "":
+            file.write(saxutils.escape(node.tail.encode('utf-8')))
 
 def _cdata(text, replace=string.replace):
-        text = text.encode('utf-8')
-        return '<![CDATA[' + replace(text, ']]>', ']]]]><![CDATA[>') + ']]>'
+    text = text.encode('utf-8')
+    return '<![CDATA[' + replace(text, ']]>', ']]]]><![CDATA[>') + ']]>'
 
 def buffer_word_boundary(buf):
-        iter = buf.get_iter_at_mark(buf.get_insert())
-        start = iter.copy()
-        
-        if not iter.starts_word() and (iter.inside_word() or iter.ends_word()):
-                start.backward_word_start()
-        
-        if not iter.ends_word() and iter.inside_word():
-                iter.forward_word_end()
-                
-        return (start, iter)
+    iter = buf.get_iter_at_mark(buf.get_insert())
+    start = iter.copy()
+
+    if not iter.starts_word() and (iter.inside_word() or iter.ends_word()):
+        start.backward_word_start()
+
+    if not iter.ends_word() and iter.inside_word():
+        iter.forward_word_end()
+
+    return (start, iter)
 
 def buffer_line_boundary(buf):
-        iter = buf.get_iter_at_mark(buf.get_insert())
-        start = iter.copy()
-        start.set_line_offset(0)
-        
-        if not iter.ends_line():
-                iter.forward_to_line_end()
-        
-        return (start, iter)
+    iter = buf.get_iter_at_mark(buf.get_insert())
+    start = iter.copy()
+    start.set_line_offset(0)
+
+    if not iter.ends_line():
+        iter.forward_to_line_end()
+
+    return (start, iter)
 
 def drop_get_uris(selection):
-        uris = []
-        if selection.targets_include_uri():
-                data = selection.get_data()
-                lines = re.split('\\s*[\\n\\r]+\\s*', data.strip())
+    uris = []
+    if selection.targets_include_uri():
+        data = selection.get_data()
+        lines = re.split('\\s*[\\n\\r]+\\s*', data.strip())
 
-                for line in lines:
-                        if not line.startswith('#'):
-                                uris.append(line)
+        for line in lines:
+            if not line.startswith('#'):
+                uris.append(line)
 
-        return uris
+    return uris
 
-# ex:ts=8:et:
+# ex:ts=4:et:
diff --git a/plugins/snippets/snippets/Importer.py b/plugins/snippets/snippets/Importer.py
old mode 100755
new mode 100644
index b2e8723..c1d211e
--- a/plugins/snippets/snippets/Importer.py
+++ b/plugins/snippets/snippets/Importer.py
@@ -6,95 +6,95 @@ import shutil
 from Library import *
 
 class Importer:
-        def __init__(self, filename):
-                self.filename = filename
-
-        def import_destination(self, filename):
-                userdir = Library().userdir
-                
-                filename = os.path.basename(filename)
-                (root, ext) = os.path.splitext(filename)
-
-                filename = os.path.join(userdir, root + ext)
-                i = 1
-                
-                while os.path.exists(filename):
-                        filename = os.path.join(userdir, root + '_' + str(i) + ext)
-                        i += 1
-                
-                return filename
-                
-        def import_file(self, filename):
-                if not os.path.exists(filename):
-                        return _('File "%s" does not exist') % filename
-                
-                if not os.path.isfile(filename):
-                        return _('File "%s" is not a valid snippets file') % filename
-                
-                # Find destination for file to copy to
-                dest = self.import_destination(filename)
-
-                # Copy file
-                shutil.copy(filename, dest)
-                
-                # Add library
-                if not Library().add_user_library(dest):
-                        return _('Imported file "%s" is not a valid snippets file') % os.path.basename(dest)
-        
-        def import_xml(self):
-                return self.import_file(self.filename)
-
-        def import_archive(self, cmd):
-                dirname = tempfile.mkdtemp()
-                status = os.system('cd %s; %s "%s"' % (dirname, cmd, self.filename))
-                
-                if status != 0:
-                        return _('The archive "%s" could not be extracted' % self.filename)
-                
-                errors = []
-
-                # Now import all the files from the archive
-                for f in os.listdir(dirname):
-                        f = os.path.join(dirname, f)
-
-                        if os.path.isfile(f):
-                                if self.import_file(f):
-                                        errors.append(os.path.basename(f))
-                        else:
-                                sys.stderr.write('Skipping %s, not a valid snippets file' % os.path.basename(f))
-                
-                # Remove the temporary directory
-                shutil.rmtree(dirname)
-
-                if len(errors) > 0:
-                        return _('The following files could not be imported: %s') % ', '.join(errors)
-                        
-        def import_targz(self):
-                self.import_archive('tar -x --gzip -f')
-        
-        def import_tarbz2(self):
-                self.import_archive('tar -x --bzip2 -f')
-
-        def import_tar(self):
-                self.import_archive('tar -xf')
-        
-        def run(self):
-                if not os.path.exists(self.filename):
-                        return _('File "%s" does not exist') % self.filename
-                
-                if not os.path.isfile(self.filename):
-                        return _('File "%s" is not a valid snippets archive') % self.filename
-                
-                (root, ext) = os.path.splitext(self.filename)
-                
-                actions = {'.tar.gz': self.import_targz,
-                           '.tar.bz2': self.import_tarbz2,
-                           '.xml': self.import_xml,
-                           '.tar': self.import_tar}
-
-                for k, v in actions.items():
-                        if self.filename.endswith(k):
-                                return v()
-                        
-                return _('File "%s" is not a valid snippets archive') % self.filename
-# ex:ts=8:et:
+    def __init__(self, filename):
+        self.filename = filename
+
+    def import_destination(self, filename):
+        userdir = Library().userdir
+
+        filename = os.path.basename(filename)
+        (root, ext) = os.path.splitext(filename)
+
+        filename = os.path.join(userdir, root + ext)
+        i = 1
+
+        while os.path.exists(filename):
+            filename = os.path.join(userdir, root + '_' + str(i) + ext)
+            i += 1
+
+        return filename
+
+    def import_file(self, filename):
+        if not os.path.exists(filename):
+            return _('File "%s" does not exist') % filename
+
+        if not os.path.isfile(filename):
+            return _('File "%s" is not a valid snippets file') % filename
+
+        # Find destination for file to copy to
+        dest = self.import_destination(filename)
+
+        # Copy file
+        shutil.copy(filename, dest)
+
+        # Add library
+        if not Library().add_user_library(dest):
+            return _('Imported file "%s" is not a valid snippets file') % os.path.basename(dest)
+
+    def import_xml(self):
+        return self.import_file(self.filename)
+
+    def import_archive(self, cmd):
+        dirname = tempfile.mkdtemp()
+        status = os.system('cd %s; %s "%s"' % (dirname, cmd, self.filename))
+
+        if status != 0:
+            return _('The archive "%s" could not be extracted' % self.filename)
+
+        errors = []
+
+        # Now import all the files from the archive
+        for f in os.listdir(dirname):
+            f = os.path.join(dirname, f)
+
+            if os.path.isfile(f):
+                if self.import_file(f):
+                    errors.append(os.path.basename(f))
+            else:
+                sys.stderr.write('Skipping %s, not a valid snippets file' % os.path.basename(f))
+
+        # Remove the temporary directory
+        shutil.rmtree(dirname)
+
+        if len(errors) > 0:
+            return _('The following files could not be imported: %s') % ', '.join(errors)
+
+    def import_targz(self):
+        self.import_archive('tar -x --gzip -f')
+
+    def import_tarbz2(self):
+        self.import_archive('tar -x --bzip2 -f')
+
+    def import_tar(self):
+        self.import_archive('tar -xf')
+
+    def run(self):
+        if not os.path.exists(self.filename):
+            return _('File "%s" does not exist') % self.filename
+
+        if not os.path.isfile(self.filename):
+            return _('File "%s" is not a valid snippets archive') % self.filename
+
+        (root, ext) = os.path.splitext(self.filename)
+
+        actions = {'.tar.gz': self.import_targz,
+               '.tar.bz2': self.import_tarbz2,
+               '.xml': self.import_xml,
+               '.tar': self.import_tar}
+
+        for k, v in actions.items():
+            if self.filename.endswith(k):
+                return v()
+
+        return _('File "%s" is not a valid snippets archive') % self.filename
+# ex:ts=4:et:
diff --git a/plugins/snippets/snippets/LanguageManager.py b/plugins/snippets/snippets/LanguageManager.py
old mode 100755
new mode 100644
index 1fb4347..e738333
--- a/plugins/snippets/snippets/LanguageManager.py
+++ b/plugins/snippets/snippets/LanguageManager.py
@@ -7,15 +7,16 @@ global manager
 manager = None
 
 def get_language_manager():
-        global manager
-        
-        if not manager:
-                dirs = []
-        
-                for d in Library().systemdirs:
-                        dirs.append(os.path.join(d, 'lang'))
-        
-                manager = GtkSource.LanguageManager()
-                manager.set_search_path(dirs + manager.get_search_path())
-        
-        return manager
+    global manager
+
+    if not manager:
+        dirs = []
+
+        for d in Library().systemdirs:
+            dirs.append(os.path.join(d, 'lang'))
+
+        manager = GtkSource.LanguageManager()
+        manager.set_search_path(dirs + manager.get_search_path())
+
+    return manager
+# ex:ts=4:et:
diff --git a/plugins/snippets/snippets/Library.py b/plugins/snippets/snippets/Library.py
old mode 100755
new mode 100644
index 5b3773a..f152082
--- a/plugins/snippets/snippets/Library.py
+++ b/plugins/snippets/snippets/Library.py
@@ -27,973 +27,973 @@ import xml.etree.ElementTree as et
 from Helper import *
 
 class NamespacedId:
-        def __init__(self, namespace, id):
-                if not id:
-                        self.id = None
-                else:
-                        if namespace:
-                                self.id = namespace + '-'
-                        else:
-                                self.id = 'global-'
-                
-                        self.id += id
+    def __init__(self, namespace, id):
+        if not id:
+            self.id = None
+        else:
+            if namespace:
+                self.id = namespace + '-'
+            else:
+                self.id = 'global-'
+
+            self.id += id
 
 class SnippetData:
-        PROPS = {'tag': '', 'text': '', 'description': 'New snippet', 
-                        'accelerator': '', 'drop-targets': ''}
+    PROPS = {'tag': '', 'text': '', 'description': 'New snippet',
+            'accelerator': '', 'drop-targets': ''}
 
-        def __init__(self, node, library):
-                self.priv_id = node.attrib.get('id')
+    def __init__(self, node, library):
+        self.priv_id = node.attrib.get('id')
 
-                self.set_library(library)
-                self.valid = False
-                self.set_node(node)
+        self.set_library(library)
+        self.valid = False
+        self.set_node(node)
 
-        def can_modify(self):
-                return (self.library and (isinstance(self.library(), SnippetsUserFile)))
+    def can_modify(self):
+        return (self.library and (isinstance(self.library(), SnippetsUserFile)))
 
-        def set_library(self, library):
-                if library:
-                        self.library = weakref.ref(library)
-                else:
-                        self.library = None
+    def set_library(self, library):
+        if library:
+            self.library = weakref.ref(library)
+        else:
+            self.library = None
+
+        self.id = NamespacedId(self.language(), self.priv_id).id
+
+    def set_node(self, node):
+        if self.can_modify():
+            self.node = node
+        else:
+            self.node = None
+
+        self.init_snippet_data(node)
+
+    def init_snippet_data(self, node):
+        if node == None:
+            return
+
+        self.override = node.attrib.get('override')
 
-                self.id = NamespacedId(self.language(), self.priv_id).id
+        self.properties = {}
+        props = SnippetData.PROPS.copy()
+
+        # Store all properties present
+        for child in node:
+            if child.tag in props:
+                del props[child.tag]
+
+                # Normalize accelerator
+                if child.tag == 'accelerator' and child.text != None:
+                    keyval, mod = Gtk.accelerator_parse(child.text)
+
+                    if Gtk.accelerator_valid(keyval, mod):
+                        child.text = Gtk.accelerator_name(keyval, mod)
+                    else:
+                        child.text = ''
 
-        def set_node(self, node):
                 if self.can_modify():
-                        self.node = node
-                else:
-                        self.node = None
-                
-                self.init_snippet_data(node)
-                
-        def init_snippet_data(self, node):
-                if node == None:
-                        return
-
-                self.override = node.attrib.get('override')
-
-                self.properties = {}
-                props = SnippetData.PROPS.copy()
-
-                # Store all properties present
-                for child in node:
-                        if child.tag in props:
-                                del props[child.tag]
-
-                                # Normalize accelerator
-                                if child.tag == 'accelerator' and child.text != None:
-                                        keyval, mod = Gtk.accelerator_parse(child.text)
-
-                                        if Gtk.accelerator_valid(keyval, mod):
-                                                child.text = Gtk.accelerator_name(keyval, mod)
-                                        else:
-                                                child.text = ''
-
-                                if self.can_modify():
-                                        self.properties[child.tag] = child
-                                else:
-                                        self.properties[child.tag] = child.text or ''
-                
-                # Create all the props that were not found so we stay consistent
-                for prop in props:
-                        if self.can_modify():
-                                child = et.SubElement(node, prop)
-
-                                child.text = props[prop]
-                                self.properties[prop] = child
-                        else:
-                                self.properties[prop] = props[prop]
-                
-                self.check_validation()
-        
-        def check_validation(self):
-                if not self['tag'] and not self['accelerator'] and not self['drop-targets']:
-                        return False
-
-                library = Library()
-                keyval, mod = Gtk.accelerator_parse(self['accelerator'])
-                
-                self.valid = library.valid_tab_trigger(self['tag']) and \
-                                (not self['accelerator'] or library.valid_accelerator(keyval, mod))
-        
-        def _format_prop(self, prop, value):
-                if prop == 'drop-targets' and value != '':
-                        return re.split('\\s*[,;]\\s*', value)
+                    self.properties[child.tag] = child
                 else:
-                        return value
-        
-        def __getitem__(self, prop):
-                if prop in self.properties:
-                        if self.can_modify():
-                                return self._format_prop(prop, self.properties[prop].text or '')
-                        else:
-                                return self._format_prop(prop, self.properties[prop] or '')
-                
-                return self._format_prop(prop, '')
-        
-        def __setitem__(self, prop, value):
-                if not prop in self.properties:
-                        return
-                
-                if isinstance(value, list):
-                        value = ','.join(value)
-                               
-                if not self.can_modify() and self.properties[prop] != value:
-                        # ohoh, this is not can_modify, but it needs to be changed...
-                        # make sure it is transfered to the changes file and set all the
-                        # fields.
-                        # This snippet data container will effectively become the container
-                        # for the newly created node, but transparently to whoever uses
-                        # it
-                        self._override()
-
-                if self.can_modify() and self.properties[prop].text != value:
-                        if self.library():
-                                self.library().tainted = True
-
-                        oldvalue = self.properties[prop].text
-                        self.properties[prop].text = value
-                        
-                        if prop == 'tag' or prop == 'accelerator' or prop == 'drop-targets':
-                                container = Library().container(self.language())
-                                container.prop_changed(self, prop, oldvalue)
-                
-                self.check_validation()
-
-        def language(self):
-                if self.library and self.library():
-                        return self.library().language
-                else:
-                        return None
-        
-        def is_override(self):
-                return self.override and Library().overridden[self.override]
-        
-        def to_xml(self):
-                return self._create_xml()
-
-        def _create_xml(self, parent=None, update=False, attrib={}):
-                # Create a new node
-                if parent != None:
-                        element = et.SubElement(parent, 'snippet', attrib)
-                else:
-                        element = et.Element('snippet')
-
-                # Create all the properties
-                for p in self.properties:
-                        prop = et.SubElement(element, p)
-                        prop.text = self[p]
-                        
-                        if update:
-                                self.properties[p] = prop
-                
-                return element              
-        
-        def _override(self):
-                # Find the user file
-                target = Library().get_user_library(self.language())
-
-                # Create a new node there with override
-                element = self._create_xml(target.root, True, {'override': self.id})
-
-                # Create an override snippet data, feed it element so that it stores
-                # all the values and then set the node to None so that it only contains
-                # the values in .properties
-                override = SnippetData(element, self.library())
-                override.set_node(None)
-                override.id = self.id
-                
-                # Set our node to the new element
-                self.node = element
-                
-                # Set the override to our id
-                self.override = self.id
-                self.id = None
-                
-                # Set the new library
-                self.set_library(target)
-                
-                # The library is tainted because we added this snippet
-                target.tainted = True
-                
-                # Add the override
-                Library().overridden[self.override] = override
-        
-        def revert(self, snippet):
-                userlib = self.library()
-                self.set_library(snippet.library())
-                
-                userlib.remove(self.node)
-                
-                self.set_node(None)
-
-                # Copy the properties
-                self.properties = snippet.properties
-                
-                # Set the id
-                self.id = snippet.id
-
-                # Reset the override flag
-                self.override = None
+                    self.properties[child.tag] = child.text or ''
+
+        # Create all the props that were not found so we stay consistent
+        for prop in props:
+            if self.can_modify():
+                child = et.SubElement(node, prop)
+
+                child.text = props[prop]
+                self.properties[prop] = child
+            else:
+                self.properties[prop] = props[prop]
+
+        self.check_validation()
+
+    def check_validation(self):
+        if not self['tag'] and not self['accelerator'] and not self['drop-targets']:
+            return False
+
+        library = Library()
+        keyval, mod = Gtk.accelerator_parse(self['accelerator'])
+
+        self.valid = library.valid_tab_trigger(self['tag']) and \
+                (not self['accelerator'] or library.valid_accelerator(keyval, mod))
+
+    def _format_prop(self, prop, value):
+        if prop == 'drop-targets' and value != '':
+            return re.split('\\s*[,;]\\s*', value)
+        else:
+            return value
+
+    def __getitem__(self, prop):
+        if prop in self.properties:
+            if self.can_modify():
+                return self._format_prop(prop, self.properties[prop].text or '')
+            else:
+                return self._format_prop(prop, self.properties[prop] or '')
+
+        return self._format_prop(prop, '')
+
+    def __setitem__(self, prop, value):
+        if not prop in self.properties:
+            return
+
+        if isinstance(value, list):
+            value = ','.join(value)
+
+        if not self.can_modify() and self.properties[prop] != value:
+            # ohoh, this is not can_modify, but it needs to be changed...
+            # make sure it is transfered to the changes file and set all the
+            # fields.
+            # This snippet data container will effectively become the container
+            # for the newly created node, but transparently to whoever uses
+            # it
+            self._override()
+
+        if self.can_modify() and self.properties[prop].text != value:
+            if self.library():
+                self.library().tainted = True
+
+            oldvalue = self.properties[prop].text
+            self.properties[prop].text = value
+
+            if prop == 'tag' or prop == 'accelerator' or prop == 'drop-targets':
+                container = Library().container(self.language())
+                container.prop_changed(self, prop, oldvalue)
+
+        self.check_validation()
+
+    def language(self):
+        if self.library and self.library():
+            return self.library().language
+        else:
+            return None
+
+    def is_override(self):
+        return self.override and Library().overridden[self.override]
+
+    def to_xml(self):
+        return self._create_xml()
+
+    def _create_xml(self, parent=None, update=False, attrib={}):
+        # Create a new node
+        if parent != None:
+            element = et.SubElement(parent, 'snippet', attrib)
+        else:
+            element = et.Element('snippet')
+
+        # Create all the properties
+        for p in self.properties:
+            prop = et.SubElement(element, p)
+            prop.text = self[p]
+
+            if update:
+                self.properties[p] = prop
+
+        return element
+
+    def _override(self):
+        # Find the user file
+        target = Library().get_user_library(self.language())
+
+        # Create a new node there with override
+        element = self._create_xml(target.root, True, {'override': self.id})
+
+        # Create an override snippet data, feed it element so that it stores
+        # all the values and then set the node to None so that it only contains
+        # the values in .properties
+        override = SnippetData(element, self.library())
+        override.set_node(None)
+        override.id = self.id
+
+        # Set our node to the new element
+        self.node = element
+
+        # Set the override to our id
+        self.override = self.id
+        self.id = None
+
+        # Set the new library
+        self.set_library(target)
+
+        # The library is tainted because we added this snippet
+        target.tainted = True
+
+        # Add the override
+        Library().overridden[self.override] = override
+
+    def revert(self, snippet):
+        userlib = self.library()
+        self.set_library(snippet.library())
+
+        userlib.remove(self.node)
+
+        self.set_node(None)
+
+        # Copy the properties
+        self.properties = snippet.properties
+
+        # Set the id
+        self.id = snippet.id
+
+        # Reset the override flag
+        self.override = None
 
 class SnippetsTreeBuilder(et.TreeBuilder):
-        def __init__(self, start=None, end=None):
-                et.TreeBuilder.__init__(self)
-                self.set_start(start)
-                self.set_end(end)
-
-        def set_start(self, start):
-                self._start_cb = start
-        
-        def set_end(self, end):
-                self._end_cb = end
-
-        def start(self, tag, attrs):
-                result = et.TreeBuilder.start(self, tag, attrs)
-        
-                if self._start_cb:
-                        self._start_cb(result)
-        
-                return result
-                
-        def end(self, tag):
-                result = et.TreeBuilder.end(self, tag)
-        
-                if self._end_cb:
-                        self._end_cb(result)
-        
-                return result
+    def __init__(self, start=None, end=None):
+        et.TreeBuilder.__init__(self)
+        self.set_start(start)
+        self.set_end(end)
+
+    def set_start(self, start):
+        self._start_cb = start
+
+    def set_end(self, end):
+        self._end_cb = end
+
+    def start(self, tag, attrs):
+        result = et.TreeBuilder.start(self, tag, attrs)
+
+        if self._start_cb:
+            self._start_cb(result)
+
+        return result
+
+    def end(self, tag):
+        result = et.TreeBuilder.end(self, tag)
+
+        if self._end_cb:
+            self._end_cb(result)
+
+        return result
 
 class LanguageContainer:
-        def __init__(self, language):
-                self.language = language
-                self.snippets = []
-                self.snippets_by_prop = {'tag': {}, 'accelerator': {}, 'drop-targets': {}}
-                self.accel_group = Gtk.AccelGroup()
-                self._refs = 0
-
-        def _add_prop(self, snippet, prop, value=0):
-                if value == 0:
-                        value = snippet[prop]
-                
-                if not value or value == '':
-                        return
-
-                snippets_debug('Added ', prop ,' ', value, ' to ', str(self.language))
-                
-                if prop == 'accelerator':
-                        keyval, mod = Gtk.accelerator_parse(value)
-                        self.accel_group.connect(keyval, mod, 0, \
-                                        Library().accelerator_activated)
-                
-                snippets = self.snippets_by_prop[prop]
-                
-                if not isinstance(value, list):
-                        value = [value]
-                
-                for val in value:
-                        if val in snippets:
-                                snippets[val].append(snippet)
-                        else:
-                                snippets[val] = [snippet]
-
-        def _remove_prop(self, snippet, prop, value=0):
-                if value == 0:
-                        value = snippet[prop]
-
-                if not value or value == '':
-                        return
-
-                snippets_debug('Removed ', prop, ' ', value, ' from ', str(self.language))
-
-                if prop == 'accelerator':
-                        keyval, mod = Gtk.accelerator_parse(value)
-                        self.accel_group.disconnect_key(keyval, mod)
-
-                snippets = self.snippets_by_prop[prop]
-                
-                if not isinstance(value, list):
-                        value = [value]
-                
-                for val in value:
-                        try:
-                                snippets[val].remove(snippet)
-                        except:
-                                True
-
-        def append(self, snippet):
-                tag = snippet['tag']
-                accelerator = snippet['accelerator']
-                
-                self.snippets.append(snippet)
-                
-                self._add_prop(snippet, 'tag')
-                self._add_prop(snippet, 'accelerator')
-                self._add_prop(snippet, 'drop-targets')
-
-                return snippet
-        
-        def remove(self, snippet):
-                try:
-                        self.snippets.remove(snippet)
-                except:
-                        True
-                        
-                self._remove_prop(snippet, 'tag')
-                self._remove_prop(snippet, 'accelerator')
-                self._remove_prop(snippet, 'drop-targets')
-        
-        def prop_changed(self, snippet, prop, oldvalue):
-                snippets_debug('PROP CHANGED (', prop, ')', oldvalue)
-
-                self._remove_prop(snippet, prop, oldvalue)
-                self._add_prop(snippet, prop)
-        
-        def from_prop(self, prop, value):
-                snippets = self.snippets_by_prop[prop]
-                
-                if prop == 'drop-targets':
-                        s = []
-                        
-                        # FIXME: change this to use 
-                        # matevfs.mime_type_get_equivalence when it comes
-                        # available
-                        for key, val in snippets.items():
-                                if not value.startswith(key):
-                                        continue
-                                
-                                for snippet in snippets[key]:
-                                        if not snippet in s:
-                                                s.append(snippet)
-                        
-                        return s
-                else:
-                        if value in snippets:
-                                return snippets[value]
-                        else:
-                                return []
-        
-        def ref(self):
-                self._refs += 1
-        
-                return True
-
-        def unref(self):
-                if self._refs > 0:
-                        self._refs -= 1
-                
-                return self._refs != 0
+    def __init__(self, language):
+        self.language = language
+        self.snippets = []
+        self.snippets_by_prop = {'tag': {}, 'accelerator': {}, 'drop-targets': {}}
+        self.accel_group = Gtk.AccelGroup()
+        self._refs = 0
+
+    def _add_prop(self, snippet, prop, value=0):
+        if value == 0:
+            value = snippet[prop]
+
+        if not value or value == '':
+            return
+
+        snippets_debug('Added ', prop ,' ', value, ' to ', str(self.language))
+
+        if prop == 'accelerator':
+            keyval, mod = Gtk.accelerator_parse(value)
+            self.accel_group.connect(keyval, mod, 0, \
+                    Library().accelerator_activated)
+
+        snippets = self.snippets_by_prop[prop]
+
+        if not isinstance(value, list):
+            value = [value]
+
+        for val in value:
+            if val in snippets:
+                snippets[val].append(snippet)
+            else:
+                snippets[val] = [snippet]
+
+    def _remove_prop(self, snippet, prop, value=0):
+        if value == 0:
+            value = snippet[prop]
+
+        if not value or value == '':
+            return
+
+        snippets_debug('Removed ', prop, ' ', value, ' from ', str(self.language))
+
+        if prop == 'accelerator':
+            keyval, mod = Gtk.accelerator_parse(value)
+            self.accel_group.disconnect_key(keyval, mod)
+
+        snippets = self.snippets_by_prop[prop]
+
+        if not isinstance(value, list):
+            value = [value]
+
+        for val in value:
+            try:
+                snippets[val].remove(snippet)
+            except:
+                True
+
+    def append(self, snippet):
+        tag = snippet['tag']
+        accelerator = snippet['accelerator']
+
+        self.snippets.append(snippet)
+
+        self._add_prop(snippet, 'tag')
+        self._add_prop(snippet, 'accelerator')
+        self._add_prop(snippet, 'drop-targets')
+
+        return snippet
+
+    def remove(self, snippet):
+        try:
+            self.snippets.remove(snippet)
+        except:
+            True
+
+        self._remove_prop(snippet, 'tag')
+        self._remove_prop(snippet, 'accelerator')
+        self._remove_prop(snippet, 'drop-targets')
+
+    def prop_changed(self, snippet, prop, oldvalue):
+        snippets_debug('PROP CHANGED (', prop, ')', oldvalue)
+
+        self._remove_prop(snippet, prop, oldvalue)
+        self._add_prop(snippet, prop)
+
+    def from_prop(self, prop, value):
+        snippets = self.snippets_by_prop[prop]
+
+        if prop == 'drop-targets':
+            s = []
+
+            # FIXME: change this to use
+            # matevfs.mime_type_get_equivalence when it comes
+            # available
+            for key, val in snippets.items():
+                if not value.startswith(key):
+                    continue
+
+                for snippet in snippets[key]:
+                    if not snippet in s:
+                        s.append(snippet)
+
+            return s
+        else:
+            if value in snippets:
+                return snippets[value]
+            else:
+                return []
+
+    def ref(self):
+        self._refs += 1
+
+        return True
+
+    def unref(self):
+        if self._refs > 0:
+            self._refs -= 1
+
+        return self._refs != 0
 
 class SnippetsSystemFile:
-        def __init__(self, path=None):
-                self.path = path
-                self.loaded = False
-                self.language = None
-                self.ok = True
-                self.need_id = True
-                
-        def load_error(self, message):
-                sys.stderr.write("An error occurred loading " + self.path + ":\n")
-                sys.stderr.write(message + "\nSnippets in this file will not be " \
-                                "available, please correct or remove the file.\n")
-
-        def _add_snippet(self, element):
-                if not self.need_id or element.attrib.get('id'):
-                        self.loading_elements.append(element)
-
-        def set_language(self, element):
-                self.language = element.attrib.get('language')
-                
-                if self.language:
-                        self.language = self.language.lower()
-        
-        def _set_root(self, element):
-                self.set_language(element)
-                
-        def _preprocess_element(self, element):
-                if not self.loaded:
-                        if not element.tag == "snippets":
-                                self.load_error("Root element should be `snippets' instead " \
-                                                "of `%s'" % element.tag)
-                                return False
-                        else:
-                                self._set_root(element)
-                                self.loaded = True
-                elif element.tag != 'snippet' and not self.insnippet:
-                        self.load_error("Element should be `snippet' instead of `%s'" \
-                                        % element.tag)
-                        return False
-                else:
-                        self.insnippet = True
-
-                return True
-
-        def _process_element(self, element):
-                if element.tag == 'snippet':
-                        self._add_snippet(element)
-                        self.insnippet = False                        
-
-                return True
-
-        def ensure(self):
-                if not self.ok or self.loaded:
-                        return
-                
-                self.load()
-
-        def parse_xml(self, readsize=16384):
-                if not self.path:
-                        return
-                        
-                elements = []
-
-                builder = SnippetsTreeBuilder( \
-                                lambda node: elements.append((node, True)), \
-                                lambda node: elements.append((node, False)))
-
-                parser = et.XMLTreeBuilder(target=builder)
-                self.insnippet = False
-                
-                try:
-                        f = open(self.path, "r")
-                        
-                        while True:
-                                data = f.read(readsize)
-                                
-                                if not data:
-                                        break
-                                
-                                parser.feed(data)
-                                
-                                for element in elements:
-                                        yield element
-                                
-                                del elements[:]
-                        
-                        f.close()
-                except IOError:
-                        self.ok = False
-
-        def load(self):
-                if not self.ok:
-                        return
-
-                snippets_debug("Loading library (" + str(self.language) + "): " + \
-                                self.path)
-                
-                self.loaded = False
-                self.ok = False
-                self.loading_elements = []
-                
-                for element in self.parse_xml():
-                        if element[1]:
-                                if not self._preprocess_element(element[0]):
-                                        del self.loading_elements[:]
-                                        return
-                        else:
-                                if not self._process_element(element[0]):
-                                        del self.loading_elements[:]
-                                        return
-
-                for element in self.loading_elements:
-                        snippet = Library().add_snippet(self, element)
-                
-                del self.loading_elements[:]
-                self.ok = True
-
-        # This function will get the language for a file by just inspecting the
-        # root element of the file. This is provided so that a cache can be built
-        # for which file contains which language.
-        # It returns the name of the language
-        def ensure_language(self):
-                if not self.loaded:
-                        self.ok = False
-                        
-                        for element in self.parse_xml(256):
-                                if element[1]:
-                                        if element[0].tag == 'snippets':
-                                                self.set_language(element[0])
-                                                self.ok = True
-
-                                        break
-        
-        def unload(self):
-                snippets_debug("Unloading library (" + str(self.language) + "): " + \
-                                self.path)
-                self.language = None
-                self.loaded = False
-                self.ok = True
+    def __init__(self, path=None):
+        self.path = path
+        self.loaded = False
+        self.language = None
+        self.ok = True
+        self.need_id = True
+
+    def load_error(self, message):
+        sys.stderr.write("An error occurred loading " + self.path + ":\n")
+        sys.stderr.write(message + "\nSnippets in this file will not be " \
+                "available, please correct or remove the file.\n")
+
+    def _add_snippet(self, element):
+        if not self.need_id or element.attrib.get('id'):
+            self.loading_elements.append(element)
+
+    def set_language(self, element):
+        self.language = element.attrib.get('language')
+
+        if self.language:
+            self.language = self.language.lower()
+
+    def _set_root(self, element):
+        self.set_language(element)
+
+    def _preprocess_element(self, element):
+        if not self.loaded:
+            if not element.tag == "snippets":
+                self.load_error("Root element should be `snippets' instead " \
+                        "of `%s'" % element.tag)
+                return False
+            else:
+                self._set_root(element)
+                self.loaded = True
+        elif element.tag != 'snippet' and not self.insnippet:
+            self.load_error("Element should be `snippet' instead of `%s'" \
+                    % element.tag)
+            return False
+        else:
+            self.insnippet = True
+
+        return True
+
+    def _process_element(self, element):
+        if element.tag == 'snippet':
+            self._add_snippet(element)
+            self.insnippet = False
+
+        return True
+
+    def ensure(self):
+        if not self.ok or self.loaded:
+            return
+
+        self.load()
+
+    def parse_xml(self, readsize=16384):
+        if not self.path:
+            return
+
+        elements = []
+
+        builder = SnippetsTreeBuilder( \
+                lambda node: elements.append((node, True)), \
+                lambda node: elements.append((node, False)))
+
+        parser = et.XMLTreeBuilder(target=builder)
+        self.insnippet = False
+
+        try:
+            f = open(self.path, "r")
+
+            while True:
+                data = f.read(readsize)
+
+                if not data:
+                    break
+
+                parser.feed(data)
+
+                for element in elements:
+                    yield element
+
+                del elements[:]
+
+            f.close()
+        except IOError:
+            self.ok = False
+
+    def load(self):
+        if not self.ok:
+            return
+
+        snippets_debug("Loading library (" + str(self.language) + "): " + \
+                self.path)
+
+        self.loaded = False
+        self.ok = False
+        self.loading_elements = []
+
+        for element in self.parse_xml():
+            if element[1]:
+                if not self._preprocess_element(element[0]):
+                    del self.loading_elements[:]
+                    return
+            else:
+                if not self._process_element(element[0]):
+                    del self.loading_elements[:]
+                    return
+
+        for element in self.loading_elements:
+            snippet = Library().add_snippet(self, element)
+
+        del self.loading_elements[:]
+        self.ok = True
+
+    # This function will get the language for a file by just inspecting the
+    # root element of the file. This is provided so that a cache can be built
+    # for which file contains which language.
+    # It returns the name of the language
+    def ensure_language(self):
+        if not self.loaded:
+            self.ok = False
+
+            for element in self.parse_xml(256):
+                if element[1]:
+                    if element[0].tag == 'snippets':
+                        self.set_language(element[0])
+                        self.ok = True
+
+                    break
+
+    def unload(self):
+        snippets_debug("Unloading library (" + str(self.language) + "): " + \
+                self.path)
+        self.language = None
+        self.loaded = False
+        self.ok = True
 
 class SnippetsUserFile(SnippetsSystemFile):
-        def __init__(self, path=None):
-                SnippetsSystemFile.__init__(self, path)
-                self.tainted = False
-                self.need_id = False
-                
-        def _set_root(self, element):
-                SnippetsSystemFile._set_root(self, element)
-                self.root = element
-                        
-        def add_prop(self, node, tag, data):
-                if data[tag]:
-                        prop = et.SubElement(node, tag)
-                        prop.text = data[tag]
-                
-                        return prop
-                else:
-                        return None
-
-        def new_snippet(self, properties=None):
-                if (not self.ok) or self.root == None:
-                        return None
-                
-                element = et.SubElement(self.root, 'snippet')
-                
-                if properties:
-                        for prop in properties:
-                                sub = et.SubElement(element, prop)
-                                sub.text = properties[prop]
-                
-                self.tainted = True
-                
-                return Library().add_snippet(self, element)
-        
-        def set_language(self, element):
-                SnippetsSystemFile.set_language(self, element)
-                
-                filename = os.path.basename(self.path).lower()
-                
-                if not self.language and filename == "global.xml":
-                        self.modifier = True
-                elif self.language and filename == self.language + ".xml":
-                        self.modifier = True
-                else:
-                        self.modifier = False
-        
-        def create_root(self, language):
-                if self.loaded:
-                        snippets_debug('Not creating root, already loaded')
-                        return
-                
-                if language:
-                        root = et.Element('snippets', {'language': language})
-                        self.path = os.path.join(Library().userdir, language.lower() + '.xml')
-                else:
-                        root = et.Element('snippets')
-                        self.path = os.path.join(Library().userdir, 'global.xml')
-                
-                self._set_root(root)
-                self.loaded = True
-                self.ok = True
-                self.tainted = True
-                self.save()
-        
-        def remove(self, element):
-                try:
-                        self.root.remove(element)
-                        self.tainted = True
-                except:
-                        return
-                
-                try:
-                        first = self.root[0]
-                except:
-                        # No more elements, this library is useless now
-                        Library().remove_library(self)
-        
-        def save(self):
-                if not self.ok or self.root == None or not self.tainted:
-                        return
-
-                path = os.path.dirname(self.path)
-                
-                try:
-                        if not os.path.isdir(path):
-                                os.makedirs(path, 0755)
-                except OSError:
-                        # TODO: this is bad...
-                        sys.stderr.write("Error in making dirs\n")
-
-                try:
-                        write_xml(self.root, self.path, ('text', 'accelerator'))
-                        self.tainted = False
-                except IOError:
-                        # Couldn't save, what to do
-                        sys.stderr.write("Could not save user snippets file to " + \
-                                        self.path + "\n")
-        
-        def unload(self):
-                SnippetsSystemFile.unload(self)
-                self.root = None
+    def __init__(self, path=None):
+        SnippetsSystemFile.__init__(self, path)
+        self.tainted = False
+        self.need_id = False
+
+    def _set_root(self, element):
+        SnippetsSystemFile._set_root(self, element)
+        self.root = element
+
+    def add_prop(self, node, tag, data):
+        if data[tag]:
+            prop = et.SubElement(node, tag)
+            prop.text = data[tag]
+
+            return prop
+        else:
+            return None
+
+    def new_snippet(self, properties=None):
+        if (not self.ok) or self.root == None:
+            return None
+
+        element = et.SubElement(self.root, 'snippet')
+
+        if properties:
+            for prop in properties:
+                sub = et.SubElement(element, prop)
+                sub.text = properties[prop]
+
+        self.tainted = True
+
+        return Library().add_snippet(self, element)
+
+    def set_language(self, element):
+        SnippetsSystemFile.set_language(self, element)
+
+        filename = os.path.basename(self.path).lower()
+
+        if not self.language and filename == "global.xml":
+            self.modifier = True
+        elif self.language and filename == self.language + ".xml":
+            self.modifier = True
+        else:
+            self.modifier = False
+
+    def create_root(self, language):
+        if self.loaded:
+            snippets_debug('Not creating root, already loaded')
+            return
+
+        if language:
+            root = et.Element('snippets', {'language': language})
+            self.path = os.path.join(Library().userdir, language.lower() + '.xml')
+        else:
+            root = et.Element('snippets')
+            self.path = os.path.join(Library().userdir, 'global.xml')
+
+        self._set_root(root)
+        self.loaded = True
+        self.ok = True
+        self.tainted = True
+        self.save()
+
+    def remove(self, element):
+        try:
+            self.root.remove(element)
+            self.tainted = True
+        except:
+            return
+
+        try:
+            first = self.root[0]
+        except:
+            # No more elements, this library is useless now
+            Library().remove_library(self)
+
+    def save(self):
+        if not self.ok or self.root == None or not self.tainted:
+            return
+
+        path = os.path.dirname(self.path)
+
+        try:
+            if not os.path.isdir(path):
+                os.makedirs(path, 0755)
+        except OSError:
+            # TODO: this is bad...
+            sys.stderr.write("Error in making dirs\n")
+
+        try:
+            write_xml(self.root, self.path, ('text', 'accelerator'))
+            self.tainted = False
+        except IOError:
+            # Couldn't save, what to do
+            sys.stderr.write("Could not save user snippets file to " + \
+                    self.path + "\n")
+
+    def unload(self):
+        SnippetsSystemFile.unload(self)
+        self.root = None
 
 class Singleton(object):
-        _instance = None
-
-        def __new__(cls, *args, **kwargs):
-                if not cls._instance:
-                        cls._instance = super(Singleton, cls).__new__(
-                                         cls, *args, **kwargs)
-                        cls._instance.__init_once__()
-
-                return cls._instance
-
-class Library(Singleton):        
-        def __init_once__(self):
-                self._accelerator_activated_cb = []
-                self.loaded = False
-                self.check_buffer = Gtk.TextBuffer()
-
-        def set_dirs(self, userdir, systemdirs):
-                self.userdir = userdir
-                self.systemdirs = systemdirs
-                
-                self.libraries = {}
-                self.containers = {}
-                self.overridden = {}
-                self.loaded_ids = []
-
-                self.loaded = False
-        
-        def add_accelerator_callback(self, cb):
-                self._accelerator_activated_cb.append(cb)
-
-        def remove_accelerator_callback(self, cb):
-                self._accelerator_activated_cb.remove(cb)
-        
-        def accelerator_activated(self, group, obj, keyval, mod):
-                ret = False
-
-                for cb in self._accelerator_activated_cb:
-                        ret = cb(group, obj, keyval, mod)
-
-                        if ret:
-                                break
-
-                return ret
-
-        def add_snippet(self, library, element):
-                container = self.container(library.language)
-                overrided = self.overrided(library, element)
-                
-                if overrided:
-                        overrided.set_library(library)
-                        snippets_debug('Snippet is overriden: ' + overrided['description'])
-                        return None
-                
-                snippet = SnippetData(element, library)
-                
-                if snippet.id in self.loaded_ids:
-                        snippets_debug('Not added snippet ' + str(library.language) + \
-                                        '::' + snippet['description'] + ' (duplicate)')
-                        return None
-
-                snippet = container.append(snippet)
-                snippets_debug('Added snippet ' + str(library.language) + '::' + \
-                                snippet['description'])
-                
-                if snippet and snippet.override:
-                        self.add_override(snippet)
-                
-                if snippet.id:
-                        self.loaded_ids.append(snippet.id)
-
-                return snippet
-        
-        def container(self, language):
-                language = self.normalize_language(language)
-                
-                if not language in self.containers:
-                        self.containers[language] = LanguageContainer(language)
-                
-                return self.containers[language]
-        
-        def get_user_library(self, language):
-                target = None
-                
-                if language in self.libraries:
-                        for library in self.libraries[language]:
-                                if isinstance(library, SnippetsUserFile) and library.modifier:
-                                        target = library
-                                elif not isinstance(library, SnippetsUserFile):
-                                        break
-                
-                if not target:
-                        # Create a new user file then
-                        snippets_debug('Creating a new user file for language ' + \
-                                        str(language))
-                        target = SnippetsUserFile()
-                        target.create_root(language)
-                        self.add_library(target)
-        
-                return target
-        
-        def new_snippet(self, language, properties=None):
-                language = self.normalize_language(language)
-                library = self.get_user_library(language)
-
-                return library.new_snippet(properties)
-        
-        def revert_snippet(self, snippet):
-                # This will revert the snippet to the one it overrides
-                if not snippet.can_modify() or not snippet.override in self.overridden:
-                        # It can't be reverted, shouldn't happen, but oh..
-                        return
-                
-                # The snippet in self.overriden only contains the property contents and
-                # the library it belongs to
-                revertto = self.overridden[snippet.override]
-                del self.overridden[snippet.override]
-                
-                if revertto:
-                        snippet.revert(revertto)
-                
-                        if revertto.id:
-                                self.loaded_ids.append(revertto.id)
-        
-        def remove_snippet(self, snippet):
-                if not snippet.can_modify() or snippet.is_override():
-                        return
-                
-                # Remove from the library
-                userlib = snippet.library()
-                userlib.remove(snippet.node)
-                
-                # Remove from the container
-                container = self.containers[userlib.language]
+    _instance = None
+
+    def __new__(cls, *args, **kwargs):
+        if not cls._instance:
+            cls._instance = super(Singleton, cls).__new__(
+                     cls, *args, **kwargs)
+            cls._instance.__init_once__()
+
+        return cls._instance
+
+class Library(Singleton):
+    def __init_once__(self):
+        self._accelerator_activated_cb = []
+        self.loaded = False
+        self.check_buffer = Gtk.TextBuffer()
+
+    def set_dirs(self, userdir, systemdirs):
+        self.userdir = userdir
+        self.systemdirs = systemdirs
+
+        self.libraries = {}
+        self.containers = {}
+        self.overridden = {}
+        self.loaded_ids = []
+
+        self.loaded = False
+
+    def add_accelerator_callback(self, cb):
+        self._accelerator_activated_cb.append(cb)
+
+    def remove_accelerator_callback(self, cb):
+        self._accelerator_activated_cb.remove(cb)
+
+    def accelerator_activated(self, group, obj, keyval, mod):
+        ret = False
+
+        for cb in self._accelerator_activated_cb:
+            ret = cb(group, obj, keyval, mod)
+
+            if ret:
+                break
+
+        return ret
+
+    def add_snippet(self, library, element):
+        container = self.container(library.language)
+        overrided = self.overrided(library, element)
+
+        if overrided:
+            overrided.set_library(library)
+            snippets_debug('Snippet is overriden: ' + overrided['description'])
+            return None
+
+        snippet = SnippetData(element, library)
+
+        if snippet.id in self.loaded_ids:
+            snippets_debug('Not added snippet ' + str(library.language) + \
+                    '::' + snippet['description'] + ' (duplicate)')
+            return None
+
+        snippet = container.append(snippet)
+        snippets_debug('Added snippet ' + str(library.language) + '::' + \
+                snippet['description'])
+
+        if snippet and snippet.override:
+            self.add_override(snippet)
+
+        if snippet.id:
+            self.loaded_ids.append(snippet.id)
+
+        return snippet
+
+    def container(self, language):
+        language = self.normalize_language(language)
+
+        if not language in self.containers:
+            self.containers[language] = LanguageContainer(language)
+
+        return self.containers[language]
+
+    def get_user_library(self, language):
+        target = None
+
+        if language in self.libraries:
+            for library in self.libraries[language]:
+                if isinstance(library, SnippetsUserFile) and library.modifier:
+                    target = library
+                elif not isinstance(library, SnippetsUserFile):
+                    break
+
+        if not target:
+            # Create a new user file then
+            snippets_debug('Creating a new user file for language ' + \
+                    str(language))
+            target = SnippetsUserFile()
+            target.create_root(language)
+            self.add_library(target)
+
+        return target
+
+    def new_snippet(self, language, properties=None):
+        language = self.normalize_language(language)
+        library = self.get_user_library(language)
+
+        return library.new_snippet(properties)
+
+    def revert_snippet(self, snippet):
+        # This will revert the snippet to the one it overrides
+        if not snippet.can_modify() or not snippet.override in self.overridden:
+            # It can't be reverted, shouldn't happen, but oh..
+            return
+
+        # The snippet in self.overriden only contains the property contents and
+        # the library it belongs to
+        revertto = self.overridden[snippet.override]
+        del self.overridden[snippet.override]
+
+        if revertto:
+            snippet.revert(revertto)
+
+            if revertto.id:
+                self.loaded_ids.append(revertto.id)
+
+    def remove_snippet(self, snippet):
+        if not snippet.can_modify() or snippet.is_override():
+            return
+
+        # Remove from the library
+        userlib = snippet.library()
+        userlib.remove(snippet.node)
+
+        # Remove from the container
+        container = self.containers[userlib.language]
+        container.remove(snippet)
+
+    def overrided(self, library, element):
+        id = NamespacedId(library.language, element.attrib.get('id')).id
+
+        if id in self.overridden:
+            snippet = SnippetData(element, None)
+            snippet.set_node(None)
+
+            self.overridden[id] = snippet
+            return snippet
+        else:
+            return None
+
+    def add_override(self, snippet):
+        snippets_debug('Add override:', snippet.override)
+        if not snippet.override in self.overridden:
+            self.overridden[snippet.override] = None
+
+    def add_library(self, library):
+        library.ensure_language()
+
+        if not library.ok:
+            snippets_debug('Library in wrong format, ignoring')
+            return False
+
+        snippets_debug('Adding library (' + str(library.language) + '): ' + \
+                library.path)
+
+        if library.language in self.libraries:
+            # Make sure all the user files are before the system files
+            if isinstance(library, SnippetsUserFile):
+                self.libraries[library.language].insert(0, library)
+            else:
+                self.libraries[library.language].append(library)
+        else:
+            self.libraries[library.language] = [library]
+
+        return True
+
+    def remove_library(self, library):
+        if not library.ok:
+            return
+
+        if library.path and os.path.isfile(library.path):
+            os.unlink(library.path)
+
+        try:
+            self.libraries[library.language].remove(library)
+        except KeyError:
+            True
+
+        container = self.containers[library.language]
+
+        for snippet in list(container.snippets):
+            if snippet.library() == library:
                 container.remove(snippet)
-        
-        def overrided(self, library, element):
-                id = NamespacedId(library.language, element.attrib.get('id')).id
-                
-                if id in self.overridden:
-                        snippet = SnippetData(element, None)
-                        snippet.set_node(None)
-                        
-                        self.overridden[id] = snippet
-                        return snippet
-                else:
-                        return None
-        
-        def add_override(self, snippet):
-                snippets_debug('Add override:', snippet.override)
-                if not snippet.override in self.overridden:
-                        self.overridden[snippet.override] = None
-        
-        def add_library(self, library):
-                library.ensure_language()
-                
-                if not library.ok:
-                        snippets_debug('Library in wrong format, ignoring')
-                        return False
-                
-                snippets_debug('Adding library (' + str(library.language) + '): ' + \
-                                library.path)
-
-                if library.language in self.libraries:
-                        # Make sure all the user files are before the system files
-                        if isinstance(library, SnippetsUserFile):
-                                self.libraries[library.language].insert(0, library)
-                        else:
-                                self.libraries[library.language].append(library)
+
+    def add_user_library(self, path):
+        library = SnippetsUserFile(path)
+        return self.add_library(library)
+
+    def add_system_library(self, path):
+        library = SnippetsSystemFile(path)
+        return self.add_library(library)
+
+    def find_libraries(self, path, searched, addcb):
+        snippets_debug("Finding in: " + path)
+
+        if not os.path.isdir(path):
+            return searched
+
+        files = os.listdir(path)
+        searched.append(path)
+
+        for f in files:
+            f = os.path.realpath(os.path.join(path, f))
+
+            # Determine what language this file provides snippets for
+            if os.path.isfile(f):
+                addcb(f)
+
+        return searched
+
+    def normalize_language(self, language):
+        if language:
+            return language.lower()
+
+        return language
+
+    def remove_container(self, language):
+        for snippet in self.containers[language].snippets:
+            if snippet.id in self.loaded_ids:
+                self.loaded_ids.remove(snippet.id)
+
+            if snippet.override in self.overridden:
+                del self.overridden[snippet.override]
+
+        del self.containers[language]
+
+    def get_accel_group(self, language):
+        language = self.normalize_language(language)
+        container = self.container(language)
+
+        self.ensure(language)
+        return container.accel_group
+
+    def save(self, language):
+        language = self.normalize_language(language)
+
+        if language in self.libraries:
+            for library in self.libraries[language]:
+                if isinstance(library, SnippetsUserFile):
+                    library.save()
                 else:
-                        self.libraries[library.language] = [library]
-
-                return True
-        
-        def remove_library(self, library):
-                if not library.ok:
-                        return
-                
-                if library.path and os.path.isfile(library.path):
-                        os.unlink(library.path)
-                
-                try:
-                        self.libraries[library.language].remove(library)
-                except KeyError:
-                        True
-                        
-                container = self.containers[library.language]
-                        
-                for snippet in list(container.snippets):
-                        if snippet.library() == library:
-                                container.remove(snippet)
-        
-        def add_user_library(self, path):
-                library = SnippetsUserFile(path)
-                return self.add_library(library)
-                
-        def add_system_library(self, path):
-                library = SnippetsSystemFile(path)
-                return self.add_library(library)
-
-        def find_libraries(self, path, searched, addcb):
-                snippets_debug("Finding in: " + path)
-                
-                if not os.path.isdir(path):
-                        return searched
-
-                files = os.listdir(path)
-                searched.append(path)
-                
-                for f in files:
-                        f = os.path.realpath(os.path.join(path, f))
-
-                        # Determine what language this file provides snippets for
-                        if os.path.isfile(f):
-                                addcb(f)
-                
-                return searched
-        
-        def normalize_language(self, language):
-                if language:
-                        return language.lower()
-                
-                return language
-        
-        def remove_container(self, language):
-                for snippet in self.containers[language].snippets:
-                        if snippet.id in self.loaded_ids:
-                                self.loaded_ids.remove(snippet.id)
-
-                        if snippet.override in self.overridden:
-                                del self.overridden[snippet.override]
-
-                del self.containers[language]
-                
-        def get_accel_group(self, language):
-                language = self.normalize_language(language)
-                container = self.container(language)
-
-                self.ensure(language)
-                return container.accel_group
-                
-        def save(self, language):
-                language = self.normalize_language(language)
-                
-                if language in self.libraries:
-                        for library in self.libraries[language]:
-                                if isinstance(library, SnippetsUserFile):
-                                        library.save()
-                                else:
-                                        break
-        
-        def ref(self, language):
-                language = self.normalize_language(language)
-
-                snippets_debug('Ref:', language)
-                self.container(language).ref()
-        
-        def unref(self, language):
-                language = self.normalize_language(language)
-                
-                snippets_debug('Unref:', language)
-                
-                if language in self.containers:
-                        if not self.containers[language].unref() and \
-                                        language in self.libraries:
-
-                                for library in self.libraries[language]:
-                                        library.unload()
-                                
-                                self.remove_container(language)
-
-        def ensure(self, language):
-                self.ensure_files()
-                language = self.normalize_language(language)
-
-                # Ensure language as well as the global snippets (None)
-                for lang in (None, language):
-                        if lang in self.libraries:
-                                # Ensure the container exists
-                                self.container(lang)
-
-                                for library in self.libraries[lang]:
-                                        library.ensure()
-
-        def ensure_files(self):
-                if self.loaded:
-                        return
-
-                searched = []
-                searched = self.find_libraries(self.userdir, searched, \
-                                self.add_user_library)
-                
-                for d in self.systemdirs:
-                        searched = self.find_libraries(d, searched, \
-                                        self.add_system_library)
+                    break
 
-                self.loaded = True
+    def ref(self, language):
+        language = self.normalize_language(language)
+
+        snippets_debug('Ref:', language)
+        self.container(language).ref()
+
+    def unref(self, language):
+        language = self.normalize_language(language)
+
+        snippets_debug('Unref:', language)
+
+        if language in self.containers:
+            if not self.containers[language].unref() and \
+                    language in self.libraries:
+
+                for library in self.libraries[language]:
+                    library.unload()
+
+                self.remove_container(language)
+
+    def ensure(self, language):
+        self.ensure_files()
+        language = self.normalize_language(language)
+
+        # Ensure language as well as the global snippets (None)
+        for lang in (None, language):
+            if lang in self.libraries:
+                # Ensure the container exists
+                self.container(lang)
+
+                for library in self.libraries[lang]:
+                    library.ensure()
+
+    def ensure_files(self):
+        if self.loaded:
+            return
+
+        searched = []
+        searched = self.find_libraries(self.userdir, searched, \
+                self.add_user_library)
+
+        for d in self.systemdirs:
+            searched = self.find_libraries(d, searched, \
+                    self.add_system_library)
+
+        self.loaded = True
+
+    def valid_accelerator(self, keyval, mod):
+        mod &= Gtk.accelerator_get_default_mod_mask()
+
+        return (mod and (Gdk.keyval_to_unicode(keyval) or \
+                keyval in range(Gdk.KEY_F1, Gdk.KEY_F12 + 1)))
+
+    def valid_tab_trigger(self, trigger):
+        if not trigger:
+            return True
+
+        if trigger.isdigit():
+            return False
+
+        self.check_buffer.set_text(trigger)
+
+        start, end = self.check_buffer.get_bounds()
+        text = self.check_buffer.get_text(start, end, False)
+
+        s = start.copy()
+        e = end.copy()
+
+        end.backward_word_start()
+        start.forward_word_end()
+
+        return (s.equal(end) and e.equal(start)) or (len(text) == 1 and not (text.isalnum() or text.isspace()))
+
+    # Snippet getters
+    # ===============
+    def _from_prop(self, prop, value, language=None):
+        self.ensure_files()
+
+        result = []
+        language = self.normalize_language(language)
+
+        if not language in self.containers:
+            return []
+
+        self.ensure(language)
+        result = self.containers[language].from_prop(prop, value)
+
+        if len(result) == 0 and language and None in self.containers:
+            result = self.containers[None].from_prop(prop, value)
+
+        return result
+
+    # Get snippets for a given language
+    def get_snippets(self, language=None):
+        self.ensure_files()
+        language = self.normalize_language(language)
+
+        if not language in self.libraries:
+            return []
+
+        snippets = []
+        self.ensure(language)
+
+        return list(self.containers[language].snippets)
+
+    # Get snippets for a given accelerator
+    def from_accelerator(self, accelerator, language=None):
+        return self._from_prop('accelerator', accelerator, language)
+
+    # Get snippets for a given tag
+    def from_tag(self, tag, language=None):
+        return self._from_prop('tag', tag, language)
+
+    # Get snippets for a given drop target
+    def from_drop_target(self, drop_target, language=None):
+        return self._from_prop('drop-targets', drop_target, language)
 
-        def valid_accelerator(self, keyval, mod):
-                mod &= Gtk.accelerator_get_default_mod_mask()
-        
-                return (mod and (Gdk.keyval_to_unicode(keyval) or \
-                                keyval in range(Gdk.KEY_F1, Gdk.KEY_F12 + 1)))
-        
-        def valid_tab_trigger(self, trigger):
-                if not trigger:
-                        return True
-
-                if trigger.isdigit():
-                        return False
-
-                self.check_buffer.set_text(trigger)
-
-                start, end = self.check_buffer.get_bounds()
-                text = self.check_buffer.get_text(start, end, False)
-                                
-                s = start.copy()
-                e = end.copy()
-                
-                end.backward_word_start()
-                start.forward_word_end()
-                
-                return (s.equal(end) and e.equal(start)) or (len(text) == 1 and not (text.isalnum() or text.isspace()))
-
-        # Snippet getters
-        # ===============
-        def _from_prop(self, prop, value, language=None):
-                self.ensure_files()
-                
-                result = []                
-                language = self.normalize_language(language)
-                        
-                if not language in self.containers:
-                        return []
-
-                self.ensure(language)
-                result = self.containers[language].from_prop(prop, value)
-                
-                if len(result) == 0 and language and None in self.containers:
-                        result = self.containers[None].from_prop(prop, value)
-                
-                return result
-        
-        # Get snippets for a given language
-        def get_snippets(self, language=None):
-                self.ensure_files()
-                language = self.normalize_language(language)
-                
-                if not language in self.libraries:
-                        return []
-                
-                snippets = []
-                self.ensure(language)
-                
-                return list(self.containers[language].snippets)
-
-        # Get snippets for a given accelerator
-        def from_accelerator(self, accelerator, language=None):
-                return self._from_prop('accelerator', accelerator, language)
-
-        # Get snippets for a given tag
-        def from_tag(self, tag, language=None):
-                return self._from_prop('tag', tag, language)
-        
-        # Get snippets for a given drop target
-        def from_drop_target(self, drop_target, language=None):
-                return self._from_prop('drop-targets', drop_target, language)
-                
-# ex:ts=8:et:
+# ex:ts=4:et:
diff --git a/plugins/snippets/snippets/Manager.py b/plugins/snippets/snippets/Manager.py
old mode 100755
new mode 100644
index f496b1c..9760fa7
--- a/plugins/snippets/snippets/Manager.py
+++ b/plugins/snippets/snippets/Manager.py
@@ -30,1119 +30,1119 @@ from Document import Document
 from LanguageManager import get_language_manager
 
 class Manager:
-        NAME_COLUMN = 0
-        SORT_COLUMN = 1
-        LANG_COLUMN = 2
-        SNIPPET_COLUMN = 3
-        TARGET_URI = 105
-
-        model = None
-        drag_icons = ('mate-mime-application-x-tarz', 'mate-package', 'package')
-        default_export_name = _('Snippets archive') + '.tar.gz'
-        dragging = False
-        dnd_target_list = [Gtk.TargetEntry.new('text/uri-list', 0, TARGET_URI)]
-
-        def __init__(self, datadir):
-                self.datadir = datadir
-                self.snippet = None
-                self.dlg = None
-                self._temp_export = None
-                self.snippets_doc = None
-                self.manager = None
-                self.default_size = None
-
-                self.key_press_id = 0
-                self.run()
-        
-        def get_language_snippets(self, path, name = None):
-                library = Library()
-                
-                name = self.get_language(path)
-                nodes = library.get_snippets(name)
-
-                return nodes
-
-        def add_new_snippet_node(self, parent):
-                return self.model.append(parent, ('<i>' + _('Add a new snippet...') + \
-                                '</i>', '', None, None))
-
-        def fill_language(self, piter, expand=True):
-                # Remove all children
-                child = self.model.iter_children(piter)
-                
-                while child and self.model.remove(child):
-                        True
-                
-                path = self.model.get_path(piter)
-                nodes = self.get_language_snippets(path)
-                language = self.get_language(path)
-                
-                Library().ref(language)
-                
-                if nodes:
-                        for node in nodes:
-                                self.add_snippet(piter, node)
-                else:
-                        # Add node that tells there are no snippets currently
-                        self.add_new_snippet_node(piter)
+    NAME_COLUMN = 0
+    SORT_COLUMN = 1
+    LANG_COLUMN = 2
+    SNIPPET_COLUMN = 3
+    TARGET_URI = 105
+
+    model = None
+    drag_icons = ('mate-mime-application-x-tarz', 'mate-package', 'package')
+    default_export_name = _('Snippets archive') + '.tar.gz'
+    dragging = False
+    dnd_target_list = [Gtk.TargetEntry.new('text/uri-list', 0, TARGET_URI)]
+
+    def __init__(self, datadir):
+        self.datadir = datadir
+        self.snippet = None
+        self.dlg = None
+        self._temp_export = None
+        self.snippets_doc = None
+        self.manager = None
+        self.default_size = None
+
+        self.key_press_id = 0
+        self.run()
+
+    def get_language_snippets(self, path, name = None):
+        library = Library()
+
+        name = self.get_language(path)
+        nodes = library.get_snippets(name)
+
+        return nodes
+
+    def add_new_snippet_node(self, parent):
+        return self.model.append(parent, ('<i>' + _('Add a new snippet...') + \
+                '</i>', '', None, None))
+
+    def fill_language(self, piter, expand=True):
+        # Remove all children
+        child = self.model.iter_children(piter)
+
+        while child and self.model.remove(child):
+            True
+
+        path = self.model.get_path(piter)
+        nodes = self.get_language_snippets(path)
+        language = self.get_language(path)
+
+        Library().ref(language)
+
+        if nodes:
+            for node in nodes:
+                self.add_snippet(piter, node)
+        else:
+            # Add node that tells there are no snippets currently
+            self.add_new_snippet_node(piter)
+
+        if expand:
+            self.tree_view.expand_row(path, False)
+
+    def build_model(self, force_reload = False):
+        window = Pluma.App.get_default().get_active_window()
+
+        if window:
+            view = window.get_active_view()
+
+            if not view:
+                current_lang = None
+            else:
+                current_lang = view.get_buffer().get_language()
+                source_view = self['source_view_snippet']
 
-                if expand:
-                        self.tree_view.expand_row(path, False)
+        else:
+            current_lang = None
 
-        def build_model(self, force_reload = False):
-                window = Pluma.App.get_default().get_active_window()
-                
-                if window:
-                        view = window.get_active_view()
+        tree_view = self['tree_view_snippets']
+        expand = None
 
-                        if not view:
-                                current_lang = None
-                        else:
-                                current_lang = view.get_buffer().get_language()
-                                source_view = self['source_view_snippet']
+        if not self.model or force_reload:
+            self.model = Gtk.TreeStore(str, str, GObject.Object, object)
+            self.model.set_sort_column_id(self.SORT_COLUMN, Gtk.SortType.ASCENDING)
+            manager = get_language_manager()
+            langs = [manager.get_language(x) for x in manager.get_language_ids()]
+            langs.sort(key=lambda x: x.get_name())
 
-                else:
-                        current_lang = None
-
-                tree_view = self['tree_view_snippets']
-                expand = None
-                
-                if not self.model or force_reload:
-                        self.model = Gtk.TreeStore(str, str, GObject.Object, object)
-                        self.model.set_sort_column_id(self.SORT_COLUMN, Gtk.SortType.ASCENDING)
-                        manager = get_language_manager()
-                        langs = [manager.get_language(x) for x in manager.get_language_ids()]
-                        langs.sort(key=lambda x: x.get_name())
-                        
-                        piter = self.model.append(None, (_('Global'), '', None, None))
-                        # Add dummy node
-                        self.model.append(piter, ('', '', None, None))
-                        
-                        nm = None
-                        
-                        if current_lang:
-                                nm = current_lang.get_name()
-                
-                        for lang in langs:
-                                name = lang.get_name()
-                                parent = self.model.append(None, (name, name, lang, None))
-
-                                # Add dummy node
-                                self.model.append(parent, ('', '', None, None))
-
-                                if (nm == name):
-                                        expand = parent
-                else:
-                        if current_lang:
-                                piter = self.model.get_iter_first()
-                                nm = current_lang.get_name()
-                                
-                                while piter:
-                                        lang = self.model.get_value(piter, \
-                                                        self.SORT_COLUMN)
-                                        
-                                        if lang == nm:
-                                                expand = piter
-                                                break;
-                                                
-                                        piter = self.model.iter_next(piter)
-
-                tree_view.set_model(self.model)
-                
-                if not expand:
-                        expand = self.model.get_iter_first()
-                        
-                tree_view.expand_row(self.model.get_path(expand), False)
-                self.select_iter(expand)
-
-        def get_cell_data_pixbuf_cb(self, column, cell, model, iter, data):
-                snippet = model.get_value(iter, self.SNIPPET_COLUMN)
-                
-                if snippet and not snippet.valid:
-                        cell.set_property('stock-id', Gtk.STOCK_DIALOG_ERROR)
-                else:
-                        cell.set_property('stock-id', None)
-
-                cell.set_property('xalign', 1.0)
-                
-        def get_cell_data_cb(self, column, cell, model, iter, data):
-                snippet = model.get_value(iter, self.SNIPPET_COLUMN)
-                
-                cell.set_property('editable', snippet != None)
-                cell.set_property('markup', model.get_value(iter, self.NAME_COLUMN))
-
-        def on_tree_view_drag_data_get(self, widget, context, selection_data, info, time):
-                gfile = Gio.file_new_for_path(self._temp_export)
-                selection_data.set_uris([gfile.get_uri()])
-       
-        def on_tree_view_drag_begin(self, widget, context):
-                self.dragging = True
-                
-                if self._temp_export:
-                      shutil.rmtree(os.path.dirname(self._temp_export))
-                      self._temp_export = None
-
-                if self.dnd_name:
-                        Gtk.drag_set_icon_name(context, self.dnd_name, 0, 0)
-
-                dirname = tempfile.mkdtemp()
-                filename = os.path.join(dirname, self.default_export_name)
-                
-                # Generate temporary file name
-                self.export_snippets(filename, False)
-                self._temp_export = filename
-        
-        def on_tree_view_drag_end(self, widget, context):
-                self.dragging = False
-
-        def on_tree_view_drag_data_received(self, widget, context, x, y, selection, info, timestamp):
-                uris = selection.get_uris()
-                
-                self.import_snippets(uris)
-
-        def on_tree_view_drag_motion(self, widget, context, x, y, timestamp):
-                # Return False if we are dragging
-                if self.dragging:
-                        return False
-                
-                # Check uri target
-                if not Gtk.targets_include_uri(context.targets):
-                        return False
-
-                # Check action
-                action = None
-                if context.suggested_action == Gdk.DragAction.COPY:
-                        action = Gdk.DragAction.COPY
-                else:
-                        for act in context.actions:
-                                if act == Gdk.DragAction.COPY:
-                                      action = Gdk.DragAction.COPY
-                                      break  
-                
-                if action == Gdk.DragAction.COPY:
-                        context.drag_status(Gdk.DragAction.COPY, timestamp)
-                        return True
-                else:
-                        return False
-
-        def build_dnd(self):
-                tv = self.tree_view
-                
-                # Set it as a drag source for exporting snippets
-                tv.drag_source_set(Gdk.ModifierType.BUTTON1_MASK, self.dnd_target_list, Gdk.DragAction.DEFAULT | Gdk.DragAction.COPY)
-                
-                # Set it as a drag destination for importing snippets
-                tv.drag_dest_set(Gtk.DestDefaults.HIGHLIGHT | Gtk.DestDefaults.DROP,
-                                 self.dnd_target_list, Gdk.DragAction.DEFAULT | Gdk.DragAction.COPY)
-                
-                tv.connect('drag_data_get', self.on_tree_view_drag_data_get)
-                tv.connect('drag_begin', self.on_tree_view_drag_begin)
-                tv.connect('drag_end', self.on_tree_view_drag_end)
-                tv.connect('drag_data_received', self.on_tree_view_drag_data_received)
-                tv.connect('drag_motion', self.on_tree_view_drag_motion)
-
-                theme = Gtk.IconTheme.get_for_screen(tv.get_screen())
-                
-                self.dnd_name = None
-                for name in self.drag_icons:
-                        icon = theme.lookup_icon(name, Gtk.IconSize.DND, 0)
-                        
-                        if icon:
-                                self.dnd_name = name
-                                break
-                
-        def build_tree_view(self):                
-                self.tree_view = self['tree_view_snippets']
-                
-                self.column = Gtk.TreeViewColumn(None)
-
-                self.renderer = Gtk.CellRendererText()
-                self.column.pack_start(self.renderer, False)
-                self.column.set_cell_data_func(self.renderer, self.get_cell_data_cb, None)
-
-                renderer = Gtk.CellRendererPixbuf()
-                self.column.pack_start(renderer, True)
-                self.column.set_cell_data_func(renderer, self.get_cell_data_pixbuf_cb, None)
-
-                self.tree_view.append_column(self.column)
-                
-                self.renderer.connect('edited', self.on_cell_edited)
-                self.renderer.connect('editing-started', self.on_cell_editing_started)
-
-                selection = self.tree_view.get_selection()
-                selection.set_mode(Gtk.SelectionMode.MULTIPLE)
-                selection.connect('changed', self.on_tree_view_selection_changed)
-                
-                self.build_dnd()
-        
-        def build(self):
-                self.builder = Gtk.Builder()
-                self.builder.add_from_file(os.path.join(self.datadir, 'ui', 'snippets.ui'))
-                
-                handlers_dic = {
-                        'on_dialog_snippets_response': self.on_dialog_snippets_response,
-                        'on_dialog_snippets_destroy': self.on_dialog_snippets_destroy,
-                        'on_button_new_snippet_clicked': self.on_button_new_snippet_clicked,
-                        'on_button_import_snippets_clicked': self.on_button_import_snippets_clicked,
-                        'on_button_export_snippets_clicked': self.on_button_export_snippets_clicked,
-                        'on_button_remove_snippet_clicked': self.on_button_remove_snippet_clicked,
-                        'on_entry_tab_trigger_focus_out': self.on_entry_tab_trigger_focus_out,
-                        'on_entry_tab_trigger_changed': self.on_entry_tab_trigger_changed,
-                        'on_entry_accelerator_focus_out': self.on_entry_accelerator_focus_out,
-                        'on_entry_accelerator_focus_in': self.on_entry_accelerator_focus_in,
-                        'on_entry_accelerator_key_press': self.on_entry_accelerator_key_press,
-                        'on_source_view_snippet_focus_out': self.on_source_view_snippet_focus_out,
-                        'on_tree_view_snippets_row_expanded': self.on_tree_view_snippets_row_expanded,
-                        'on_tree_view_snippets_key_press': self.on_tree_view_snippets_key_press}
-
-                self.builder.connect_signals(handlers_dic)
-                
-                self.build_tree_view()
-                self.build_model()
-
-                image = self['image_remove']
-                image.set_from_stock(Gtk.STOCK_REMOVE, Gtk.IconSize.SMALL_TOOLBAR)
+            piter = self.model.append(None, (_('Global'), '', None, None))
+            # Add dummy node
+            self.model.append(piter, ('', '', None, None))
 
-                source_view = self['source_view_snippet']
-                manager = get_language_manager()
-                lang = manager.get_language('snippets')
-
-                if lang:
-                        source_view.get_buffer().set_highlight_syntax(True)
-                        source_view.get_buffer().set_language(lang)
-                        self.snippets_doc = Document(None, source_view)
-
-                combo = self['combo_drop_targets']
-
-                entry = combo.get_child()
-                entry.connect('focus-out-event', self.on_entry_drop_targets_focus_out)
-                entry.connect('drag-data-received', self.on_entry_drop_targets_drag_data_received)
-                
-                lst = entry.drag_dest_get_target_list()
-                lst.add_uri_targets(self.TARGET_URI)
-                
-                self.dlg = self['dialog_snippets']
-                
-                if self.default_size:
-                        self.dlg.set_default_size(*self.default_size)
-        
-        def __getitem__(self, key):
-                return self.builder.get_object(key)
-
-        def is_filled(self, piter):
-                if not self.model.iter_has_child(piter):
-                        return True
-                
-                child = self.model.iter_children(piter)
-                nm = self.model.get_value(child, self.NAME_COLUMN)
-                lang = self.model.get_value(child, self.LANG_COLUMN)
-                snippet = self.model.get_value(child, self.SNIPPET_COLUMN)
-                
-                return (lang or snippet or nm)
-
-        def fill_if_needed(self, piter, expand=True):
-                if not self.is_filled(piter):
-                        self.fill_language(piter, expand)
-
-        def find_iter(self, parent, snippet):
-                self.fill_if_needed(parent)
-                piter = self.model.iter_children(parent)
-                
-                while (piter):
-                        node = self.model.get_value(piter, self.SNIPPET_COLUMN)
-
-                        if node == snippet.data:
-                                return piter
-                        
-                        piter = self.model.iter_next(piter)
-                
-                return None
-
-        def selected_snippets_state(self):
-                snippets = self.selected_snippets(False)
-                override = False
-                remove = False
-                system = False
-                
-                for snippet in snippets:
-                        if not snippet:
-                                continue
-
-                        if snippet.is_override():
-                                override = True
-                        elif snippet.can_modify():
-                                remove = True
-                        else:
-                                system = True
-                        
-                        # No need to continue if both are found
-                        if override and remove:
-                                break
-
-                return (override, remove, system)
-
-        def update_buttons(self):
-                button_remove = self['button_remove_snippet']
-                button_new = self['button_new_snippet']
-                image_remove = self['image_remove']
-
-                button_new.set_sensitive(self.language_path != None)
-                override, remove, system = self.selected_snippets_state()
-                
-                if not (override ^ remove) or system:
-                        button_remove.set_sensitive(False)
-                        image_remove.set_from_stock(Gtk.STOCK_DELETE, Gtk.IconSize.BUTTON)
-                else:
-                        button_remove.set_sensitive(True)
-                        
-                        if override:
-                                image_remove.set_from_stock(Gtk.STOCK_UNDO, Gtk.IconSize.BUTTON)
-                                tooltip = _('Revert selected snippet')
-                        else:
-                                image_remove.set_from_stock(Gtk.STOCK_DELETE, Gtk.IconSize.BUTTON)
-                                tooltip = _('Delete selected snippet')
-                        
-                        button_remove.set_tooltip_text(tooltip)
-
-        def snippet_changed(self, piter = None):
-                if piter:
-                        node = self.model.get_value(piter, self.SNIPPET_COLUMN)
-                        s = Snippet(node)
-                else:
-                        s = self.snippet
-                        piter = self.find_iter(self.model.get_iter(self.language_path), s)
+            nm = None
+
+            if current_lang:
+                nm = current_lang.get_name()
+
+            for lang in langs:
+                name = lang.get_name()
+                parent = self.model.append(None, (name, name, lang, None))
+
+                # Add dummy node
+                self.model.append(parent, ('', '', None, None))
+
+                if (nm == name):
+                    expand = parent
+        else:
+            if current_lang:
+                piter = self.model.get_iter_first()
+                nm = current_lang.get_name()
+
+                while piter:
+                    lang = self.model.get_value(piter, \
+                            self.SORT_COLUMN)
+
+                    if lang == nm:
+                        expand = piter
+                        break;
+
+                    piter = self.model.iter_next(piter)
+
+        tree_view.set_model(self.model)
+
+        if not expand:
+            expand = self.model.get_iter_first()
+
+        tree_view.expand_row(self.model.get_path(expand), False)
+        self.select_iter(expand)
+
+    def get_cell_data_pixbuf_cb(self, column, cell, model, iter, data):
+        snippet = model.get_value(iter, self.SNIPPET_COLUMN)
+
+        if snippet and not snippet.valid:
+            cell.set_property('stock-id', Gtk.STOCK_DIALOG_ERROR)
+        else:
+            cell.set_property('stock-id', None)
+
+        cell.set_property('xalign', 1.0)
+
+    def get_cell_data_cb(self, column, cell, model, iter, data):
+        snippet = model.get_value(iter, self.SNIPPET_COLUMN)
+
+        cell.set_property('editable', snippet != None)
+        cell.set_property('markup', model.get_value(iter, self.NAME_COLUMN))
+
+    def on_tree_view_drag_data_get(self, widget, context, selection_data, info, time):
+        gfile = Gio.file_new_for_path(self._temp_export)
+        selection_data.set_uris([gfile.get_uri()])
+
+    def on_tree_view_drag_begin(self, widget, context):
+        self.dragging = True
+
+        if self._temp_export:
+              shutil.rmtree(os.path.dirname(self._temp_export))
+              self._temp_export = None
+
+        if self.dnd_name:
+            Gtk.drag_set_icon_name(context, self.dnd_name, 0, 0)
+
+        dirname = tempfile.mkdtemp()
+        filename = os.path.join(dirname, self.default_export_name)
+
+        # Generate temporary file name
+        self.export_snippets(filename, False)
+        self._temp_export = filename
+
+    def on_tree_view_drag_end(self, widget, context):
+        self.dragging = False
+
+    def on_tree_view_drag_data_received(self, widget, context, x, y, selection, info, timestamp):
+        uris = selection.get_uris()
+
+        self.import_snippets(uris)
+
+    def on_tree_view_drag_motion(self, widget, context, x, y, timestamp):
+        # Return False if we are dragging
+        if self.dragging:
+            return False
+
+        # Check uri target
+        if not Gtk.targets_include_uri(context.targets):
+            return False
+
+        # Check action
+        action = None
+        if context.suggested_action == Gdk.DragAction.COPY:
+            action = Gdk.DragAction.COPY
+        else:
+            for act in context.actions:
+                if act == Gdk.DragAction.COPY:
+                      action = Gdk.DragAction.COPY
+                      break
+
+        if action == Gdk.DragAction.COPY:
+            context.drag_status(Gdk.DragAction.COPY, timestamp)
+            return True
+        else:
+            return False
+
+    def build_dnd(self):
+        tv = self.tree_view
+
+        # Set it as a drag source for exporting snippets
+        tv.drag_source_set(Gdk.ModifierType.BUTTON1_MASK, self.dnd_target_list, Gdk.DragAction.DEFAULT | Gdk.DragAction.COPY)
+
+        # Set it as a drag destination for importing snippets
+        tv.drag_dest_set(Gtk.DestDefaults.HIGHLIGHT | Gtk.DestDefaults.DROP,
+                 self.dnd_target_list, Gdk.DragAction.DEFAULT | Gdk.DragAction.COPY)
+
+        tv.connect('drag_data_get', self.on_tree_view_drag_data_get)
+        tv.connect('drag_begin', self.on_tree_view_drag_begin)
+        tv.connect('drag_end', self.on_tree_view_drag_end)
+        tv.connect('drag_data_received', self.on_tree_view_drag_data_received)
+        tv.connect('drag_motion', self.on_tree_view_drag_motion)
+
+        theme = Gtk.IconTheme.get_for_screen(tv.get_screen())
+
+        self.dnd_name = None
+        for name in self.drag_icons:
+            icon = theme.lookup_icon(name, Gtk.IconSize.DND, 0)
+
+            if icon:
+                self.dnd_name = name
+                break
+
+    def build_tree_view(self):
+        self.tree_view = self['tree_view_snippets']
+
+        self.column = Gtk.TreeViewColumn(None)
+
+        self.renderer = Gtk.CellRendererText()
+        self.column.pack_start(self.renderer, False)
+        self.column.set_cell_data_func(self.renderer, self.get_cell_data_cb, None)
+
+        renderer = Gtk.CellRendererPixbuf()
+        self.column.pack_start(renderer, True)
+        self.column.set_cell_data_func(renderer, self.get_cell_data_pixbuf_cb, None)
+
+        self.tree_view.append_column(self.column)
+
+        self.renderer.connect('edited', self.on_cell_edited)
+        self.renderer.connect('editing-started', self.on_cell_editing_started)
+
+        selection = self.tree_view.get_selection()
+        selection.set_mode(Gtk.SelectionMode.MULTIPLE)
+        selection.connect('changed', self.on_tree_view_selection_changed)
+
+        self.build_dnd()
+
+    def build(self):
+        self.builder = Gtk.Builder()
+        self.builder.add_from_file(os.path.join(self.datadir, 'ui', 'snippets.ui'))
+
+        handlers_dic = {
+            'on_dialog_snippets_response': self.on_dialog_snippets_response,
+            'on_dialog_snippets_destroy': self.on_dialog_snippets_destroy,
+            'on_button_new_snippet_clicked': self.on_button_new_snippet_clicked,
+            'on_button_import_snippets_clicked': self.on_button_import_snippets_clicked,
+            'on_button_export_snippets_clicked': self.on_button_export_snippets_clicked,
+            'on_button_remove_snippet_clicked': self.on_button_remove_snippet_clicked,
+            'on_entry_tab_trigger_focus_out': self.on_entry_tab_trigger_focus_out,
+            'on_entry_tab_trigger_changed': self.on_entry_tab_trigger_changed,
+            'on_entry_accelerator_focus_out': self.on_entry_accelerator_focus_out,
+            'on_entry_accelerator_focus_in': self.on_entry_accelerator_focus_in,
+            'on_entry_accelerator_key_press': self.on_entry_accelerator_key_press,
+            'on_source_view_snippet_focus_out': self.on_source_view_snippet_focus_out,
+            'on_tree_view_snippets_row_expanded': self.on_tree_view_snippets_row_expanded,
+            'on_tree_view_snippets_key_press': self.on_tree_view_snippets_key_press}
 
-                if piter:
-                        nm = s.display()
-                        
-                        self.model.set_value(piter, self.NAME_COLUMN, nm)
-                        self.model.set_value(piter, self.SORT_COLUMN, nm)
-                        self.update_buttons()
-                        self.entry_tab_trigger_update_valid()
+        self.builder.connect_signals(handlers_dic)
 
+        self.build_tree_view()
+        self.build_model()
+
+        image = self['image_remove']
+        image.set_from_stock(Gtk.STOCK_REMOVE, Gtk.IconSize.SMALL_TOOLBAR)
+
+        source_view = self['source_view_snippet']
+        manager = get_language_manager()
+        lang = manager.get_language('snippets')
+
+        if lang:
+            source_view.get_buffer().set_highlight_syntax(True)
+            source_view.get_buffer().set_language(lang)
+            self.snippets_doc = Document(None, source_view)
+
+        combo = self['combo_drop_targets']
+
+        entry = combo.get_child()
+        entry.connect('focus-out-event', self.on_entry_drop_targets_focus_out)
+        entry.connect('drag-data-received', self.on_entry_drop_targets_drag_data_received)
+
+        lst = entry.drag_dest_get_target_list()
+        lst.add_uri_targets(self.TARGET_URI)
+
+        self.dlg = self['dialog_snippets']
+
+        if self.default_size:
+            self.dlg.set_default_size(*self.default_size)
+
+    def __getitem__(self, key):
+        return self.builder.get_object(key)
+
+    def is_filled(self, piter):
+        if not self.model.iter_has_child(piter):
+            return True
+
+        child = self.model.iter_children(piter)
+        nm = self.model.get_value(child, self.NAME_COLUMN)
+        lang = self.model.get_value(child, self.LANG_COLUMN)
+        snippet = self.model.get_value(child, self.SNIPPET_COLUMN)
+
+        return (lang or snippet or nm)
+
+    def fill_if_needed(self, piter, expand=True):
+        if not self.is_filled(piter):
+            self.fill_language(piter, expand)
+
+    def find_iter(self, parent, snippet):
+        self.fill_if_needed(parent)
+        piter = self.model.iter_children(parent)
+
+        while (piter):
+            node = self.model.get_value(piter, self.SNIPPET_COLUMN)
+
+            if node == snippet.data:
                 return piter
 
-        def add_snippet(self, parent, snippet):
-                piter = self.model.append(parent, ('', '', None, snippet))
-                
-                return self.snippet_changed(piter)
+            piter = self.model.iter_next(piter)
 
-        def run(self):
-                if not self.dlg:
-                        self.build()
-                        self.dlg.show()
+        return None
+
+    def selected_snippets_state(self):
+        snippets = self.selected_snippets(False)
+        override = False
+        remove = False
+        system = False
+
+        for snippet in snippets:
+            if not snippet:
+                continue
+
+            if snippet.is_override():
+                override = True
+            elif snippet.can_modify():
+                remove = True
+            else:
+                system = True
+
+            # No need to continue if both are found
+            if override and remove:
+                break
+
+        return (override, remove, system)
+
+    def update_buttons(self):
+        button_remove = self['button_remove_snippet']
+        button_new = self['button_new_snippet']
+        image_remove = self['image_remove']
+
+        button_new.set_sensitive(self.language_path != None)
+        override, remove, system = self.selected_snippets_state()
+
+        if not (override ^ remove) or system:
+            button_remove.set_sensitive(False)
+            image_remove.set_from_stock(Gtk.STOCK_DELETE, Gtk.IconSize.BUTTON)
+        else:
+            button_remove.set_sensitive(True)
+
+            if override:
+                image_remove.set_from_stock(Gtk.STOCK_UNDO, Gtk.IconSize.BUTTON)
+                tooltip = _('Revert selected snippet')
+            else:
+                image_remove.set_from_stock(Gtk.STOCK_DELETE, Gtk.IconSize.BUTTON)
+                tooltip = _('Delete selected snippet')
+
+            button_remove.set_tooltip_text(tooltip)
+
+    def snippet_changed(self, piter = None):
+        if piter:
+            node = self.model.get_value(piter, self.SNIPPET_COLUMN)
+            s = Snippet(node)
+        else:
+            s = self.snippet
+            piter = self.find_iter(self.model.get_iter(self.language_path), s)
+
+        if piter:
+            nm = s.display()
+
+            self.model.set_value(piter, self.NAME_COLUMN, nm)
+            self.model.set_value(piter, self.SORT_COLUMN, nm)
+            self.update_buttons()
+            self.entry_tab_trigger_update_valid()
+
+        return piter
+
+    def add_snippet(self, parent, snippet):
+        piter = self.model.append(parent, ('', '', None, snippet))
+
+        return self.snippet_changed(piter)
+
+    def run(self):
+        if not self.dlg:
+            self.build()
+            self.dlg.show()
+        else:
+            self.build_model()
+            self.dlg.present()
+
+    def snippet_from_iter(self, model, piter):
+        parent = model.iter_parent(piter)
+
+        if parent:
+            return model.get_value(piter, self.SNIPPET_COLUMN)
+        else:
+            return None
+
+    def language_snippets(self, model, parent, as_path=False):
+        self.fill_if_needed(parent, False)
+        piter = model.iter_children(parent)
+        snippets = []
+
+        if not piter:
+            return snippets
+
+        while piter:
+            snippet = self.snippet_from_iter(model, piter)
+
+            if snippet:
+                if as_path:
+                    snippets.append(model.get_path(piter))
                 else:
-                        self.build_model()
-                        self.dlg.present()
+                    snippets.append(snippet)
+
+            piter = model.iter_next(piter)
+
+        return snippets
 
-        def snippet_from_iter(self, model, piter):
+    def selected_snippets(self, include_languages=True, as_path=False):
+        selection = self.tree_view.get_selection()
+        (model, paths) = selection.get_selected_rows()
+        snippets = []
+
+        if paths and len(paths) != 0:
+            for p in paths:
+                piter = model.get_iter(p)
                 parent = model.iter_parent(piter)
-                
-                if parent:
-                        return model.get_value(piter, self.SNIPPET_COLUMN)
-                else:
-                        return None
-        
-        def language_snippets(self, model, parent, as_path=False):
-                self.fill_if_needed(parent, False)
-                piter = model.iter_children(parent)
-                snippets = []
-                
+
                 if not piter:
-                        return snippets
-                
-                while piter:
-                        snippet = self.snippet_from_iter(model, piter)
-                        
-                        if snippet:
-                                if as_path:
-                                        snippets.append(model.get_path(piter))
-                                else:
-                                        snippets.append(snippet)
-
-                        piter = model.iter_next(piter)
-                
-                return snippets
-        
-        def selected_snippets(self, include_languages=True, as_path=False):
-                selection = self.tree_view.get_selection()
-                (model, paths) = selection.get_selected_rows()
-                snippets = []
-                
-                if paths and len(paths) != 0:
-                        for p in paths:
-                                piter = model.get_iter(p)
-                                parent = model.iter_parent(piter)
-                                
-                                if not piter:
-                                        continue
-                                
-                                if parent:
-                                        snippet = self.snippet_from_iter(model, piter)
-                                        
-                                        if not snippet:
-                                                continue
-                                        
-                                        if as_path:
-                                                snippets.append(p)
-                                        else:
-                                                snippets.append(snippet)
-                                elif include_languages:
-                                        snippets += self.language_snippets(model, piter, as_path)
-                        
-                return snippets                        
-        
-        def selected_snippet(self):
-                selection = self.tree_view.get_selection()
-                (model, paths) = selection.get_selected_rows()
-                
-                if len(paths) == 1:
-                        piter = model.get_iter(paths[0])
-                        parent = model.iter_parent(piter)
-                        snippet = self.snippet_from_iter(model, piter)
-                        
-                        return parent, piter, snippet
-                else:
-                        return None, None, None
+                    continue
 
-        def selection_changed(self):
-                if not self.snippet:
-                        sens = False
+                if parent:
+                    snippet = self.snippet_from_iter(model, piter)
 
-                        self['entry_tab_trigger'].set_text('')
-                        self['entry_accelerator'].set_text('')
-                        buf = self['source_view_snippet'].get_buffer()
-                        buf.begin_not_undoable_action()
-                        buf.set_text('')
-                        buf.end_not_undoable_action()
-                        self['combo_drop_targets'].get_child().set_text('')
+                    if not snippet:
+                        continue
 
+                    if as_path:
+                        snippets.append(p)
+                    else:
+                        snippets.append(snippet)
+                elif include_languages:
+                    snippets += self.language_snippets(model, piter, as_path)
+
+        return snippets
+
+    def selected_snippet(self):
+        selection = self.tree_view.get_selection()
+        (model, paths) = selection.get_selected_rows()
+
+        if len(paths) == 1:
+            piter = model.get_iter(paths[0])
+            parent = model.iter_parent(piter)
+            snippet = self.snippet_from_iter(model, piter)
+
+            return parent, piter, snippet
+        else:
+            return None, None, None
+
+    def selection_changed(self):
+        if not self.snippet:
+            sens = False
+
+            self['entry_tab_trigger'].set_text('')
+            self['entry_accelerator'].set_text('')
+            buf = self['source_view_snippet'].get_buffer()
+            buf.begin_not_undoable_action()
+            buf.set_text('')
+            buf.end_not_undoable_action()
+            self['combo_drop_targets'].get_child().set_text('')
+
+        else:
+            sens = True
+
+            self['entry_tab_trigger'].set_text(self.snippet['tag'])
+            self['entry_accelerator'].set_text( \
+                    self.snippet.accelerator_display())
+            self['combo_drop_targets'].get_child().set_text(', '.join(self.snippet['drop-targets']))
+
+            buf = self['source_view_snippet'].get_buffer()
+            buf.begin_not_undoable_action()
+            buf.set_text(self.snippet['text'])
+            buf.end_not_undoable_action()
+
+
+        for name in ['source_view_snippet', 'label_tab_trigger',
+                'entry_tab_trigger', 'label_accelerator',
+                'entry_accelerator', 'label_drop_targets',
+                'combo_drop_targets']:
+            self[name].set_sensitive(sens)
+
+        self.update_buttons()
+
+    def select_iter(self, piter, unselect=True):
+        selection = self.tree_view.get_selection()
+
+        if unselect:
+            selection.unselect_all()
+
+        selection.select_iter(piter)
+
+        self.tree_view.scroll_to_cell(self.model.get_path(piter), None, \
+            True, 0.5, 0.5)
+
+    def get_language(self, path):
+        if path.get_indices()[0] == 0:
+            return None
+        else:
+            return self.model.get_value(self.model.get_iter(path), \
+                            self.LANG_COLUMN).get_id()
+
+    def new_snippet(self, properties=None):
+        if not self.language_path:
+            return None
+
+        snippet = Library().new_snippet(self.get_language(self.language_path), properties)
+
+        return Snippet(snippet)
+
+    def get_dummy(self, parent):
+        if not self.model.iter_n_children(parent) == 1:
+            return None
+
+        dummy = self.model.iter_children(parent)
+
+        if not self.model.get_value(dummy, self.SNIPPET_COLUMN):
+            return dummy
+
+        return None
+
+    def unref_languages(self):
+        piter = self.model.get_iter_first()
+        library = Library()
+
+        while piter:
+            if self.is_filled(piter):
+                language = self.get_language(self.model.get_path(piter))
+                library.save(language)
+
+                library.unref(language)
+
+            piter = self.model.iter_next(piter)
+
+    # Callbacks
+    def on_dialog_snippets_destroy(self, dlg):
+        # Remove temporary drag export
+        if self._temp_export:
+              shutil.rmtree(os.path.dirname(self._temp_export))
+              self._temp_export = None
+
+        if self.snippets_doc:
+            self.snippets_doc.stop()
+
+        self.manager = None
+        self.unref_languages()
+        self.snippet = None
+        self.model = None
+        self.dlg = None
+
+    def on_dialog_snippets_response(self, dlg, resp):
+
+        alloc = dlg.get_allocation()
+        self.default_size = [alloc.width, alloc.height]
+
+        if resp == Gtk.ResponseType.HELP:
+            Pluma.help_display(self, 'pluma', 'pluma-snippets-plugin')
+            return
+
+        self.dlg.destroy()
+
+    def on_cell_editing_started(self, renderer, editable, path):
+        piter = self.model.get_iter(path)
+
+        if not self.model.iter_parent(piter):
+            renderer.stop_editing(True)
+            editable.remove_widget()
+        elif isinstance(editable, Gtk.Entry):
+            if self.snippet:
+                editable.set_text(self.snippet['description'])
+            else:
+                # This is the `Add a new snippet...` item
+                editable.set_text('')
+
+            editable.grab_focus()
+
+    def on_cell_edited(self, cell, path, new_text):
+        if new_text != '':
+            piter = self.model.get_iter(path)
+            node = self.model.get_value(piter, self.SNIPPET_COLUMN)
+
+            if node:
+                if node == self.snippet.data:
+                    s = self.snippet
                 else:
-                        sens = True
-
-                        self['entry_tab_trigger'].set_text(self.snippet['tag'])
-                        self['entry_accelerator'].set_text( \
-                                        self.snippet.accelerator_display())
-                        self['combo_drop_targets'].get_child().set_text(', '.join(self.snippet['drop-targets']))
-                        
-                        buf = self['source_view_snippet'].get_buffer()
-                        buf.begin_not_undoable_action()
-                        buf.set_text(self.snippet['text'])
-                        buf.end_not_undoable_action()
-
-
-                for name in ['source_view_snippet', 'label_tab_trigger',
-                                'entry_tab_trigger', 'label_accelerator', 
-                                'entry_accelerator', 'label_drop_targets',
-                                'combo_drop_targets']:
-                        self[name].set_sensitive(sens)
-                
-                self.update_buttons()
-                        
-        def select_iter(self, piter, unselect=True):
-                selection = self.tree_view.get_selection()
-                
-                if unselect:
-                        selection.unselect_all()
-
-                selection.select_iter(piter)
-                
-                self.tree_view.scroll_to_cell(self.model.get_path(piter), None, \
-                        True, 0.5, 0.5)
-
-        def get_language(self, path):
-                if path.get_indices()[0] == 0:
-                        return None
-                else:
-                        return self.model.get_value(self.model.get_iter(path), \
-                                                    self.LANG_COLUMN).get_id()
-
-        def new_snippet(self, properties=None):
-                if not self.language_path:
-                        return None
-
-                snippet = Library().new_snippet(self.get_language(self.language_path), properties)
-                
-                return Snippet(snippet)
-
-        def get_dummy(self, parent):
-                if not self.model.iter_n_children(parent) == 1:
-                        return None
-                
-                dummy = self.model.iter_children(parent)
-                
-                if not self.model.get_value(dummy, self.SNIPPET_COLUMN):
-                        return dummy
-        
-                return None
-        
-        def unref_languages(self):
-                piter = self.model.get_iter_first()
-                library = Library()
-                
-                while piter:
-                        if self.is_filled(piter):
-                                language = self.get_language(self.model.get_path(piter))
-                                library.save(language)
-
-                                library.unref(language)
-                        
-                        piter = self.model.iter_next(piter)
-
-        # Callbacks
-        def on_dialog_snippets_destroy(self, dlg):
-                # Remove temporary drag export
-                if self._temp_export:
-                      shutil.rmtree(os.path.dirname(self._temp_export))
-                      self._temp_export = None
-
-                if self.snippets_doc:
-                        self.snippets_doc.stop()
-                
-                self.manager = None
-                self.unref_languages()        
-                self.snippet = None        
-                self.model = None
-                self.dlg = None                
-        
-        def on_dialog_snippets_response(self, dlg, resp):
-
-                alloc = dlg.get_allocation()
-                self.default_size = [alloc.width, alloc.height]
-
-                if resp == Gtk.ResponseType.HELP:
-                        Pluma.help_display(self, 'pluma', 'pluma-snippets-plugin')
-                        return
-
-                self.dlg.destroy()
-        
-        def on_cell_editing_started(self, renderer, editable, path):
-                piter = self.model.get_iter(path)
-                
-                if not self.model.iter_parent(piter):
-                        renderer.stop_editing(True)
-                        editable.remove_widget()
-                elif isinstance(editable, Gtk.Entry):
-                        if self.snippet:
-                                editable.set_text(self.snippet['description'])
-                        else:
-                                # This is the `Add a new snippet...` item
-                                editable.set_text('')
-                        
-                        editable.grab_focus()
-        
-        def on_cell_edited(self, cell, path, new_text):                
-                if new_text != '':
-                        piter = self.model.get_iter(path)
-                        node = self.model.get_value(piter, self.SNIPPET_COLUMN)
-                        
-                        if node:
-                                if node == self.snippet.data:
-                                        s = self.snippet
-                                else:
-                                        s = Snippet(node)
-                        
-                                s['description'] = new_text
-                                self.snippet_changed(piter)
-                                self.select_iter(piter)
-                        else:
-                                # This is the `Add a new snippet...` item
-                                # We create a new snippet
-                                snippet = self.new_snippet({'description': new_text})
-                                
-                                if snippet:
-                                        self.model.set_value(piter, self.SNIPPET_COLUMN, snippet.data)
-                                        self.snippet_changed(piter)
-                                        self.snippet = snippet
-                                        self.selection_changed()
-        
-        def on_entry_accelerator_focus_out(self, entry, event):
-                if not self.snippet:
-                        return
-
-                entry.set_text(self.snippet.accelerator_display())
-
-        def entry_tab_trigger_update_valid(self):
-                entry = self['entry_tab_trigger']
-                text = entry.get_text()
-                
-                if text and not Library().valid_tab_trigger(text):
-                        img = self['image_tab_trigger']
-                        img.set_from_stock(Gtk.STOCK_DIALOG_ERROR, Gtk.IconSize.BUTTON)
-                        img.show()
-
-                        #self['hbox_tab_trigger'].set_spacing(3)
-                        tip = _('This is not a valid Tab trigger. Triggers can either contain letters or a single (non-alphanumeric) character like: {, [, etc.')
-                        
-                        entry.set_tooltip_text(tip)
-                        img.set_tooltip_text(tip)
-                else:
-                        self['image_tab_trigger'].hide()
-                        #self['hbox_tab_trigger'].set_spacing(0)
-                        entry.set_tooltip_text(_('Single word the snippet is activated with after pressing Tab'))
-                
-                return False
+                    s = Snippet(node)
 
-        def on_entry_tab_trigger_focus_out(self, entry, event):
-                if not self.snippet:
-                        return
-
-                text = entry.get_text()
-
-                # save tag
-                self.snippet['tag'] = text
-                self.snippet_changed()
-        
-        def on_entry_drop_targets_focus_out(self, entry, event):
-                if not self.snippet:
-                        return
-                
-                text = entry.get_text()
-
-                # save drop targets
-                self.snippet['drop-targets'] = text
-                self.snippet_changed()
-        
-        def on_entry_tab_trigger_changed(self, entry):
-                self.entry_tab_trigger_update_valid()
-        
-        def on_source_view_snippet_focus_out(self, source_view, event):
-                if not self.snippet:
-                        return
-
-                buf = source_view.get_buffer()
-                text = buf.get_text(buf.get_start_iter(), \
-                                buf.get_end_iter(), False)
-
-                self.snippet['text'] = text
-                self.snippet_changed()
-        
-        def on_button_new_snippet_clicked(self, button):
-                snippet = self.new_snippet()
-                
-                if not snippet:
-                        return
-
-                parent = self.model.get_iter(self.language_path)
-                path = self.model.get_path(parent)
-                
-                dummy = self.get_dummy(parent)
-                
-                if dummy:
-                        # Remove the dummy
-                        self.model.remove(dummy)
-                
-                # Add the snippet
-                piter = self.add_snippet(parent, snippet.data)
+                s['description'] = new_text
+                self.snippet_changed(piter)
                 self.select_iter(piter)
+            else:
+                # This is the `Add a new snippet...` item
+                # We create a new snippet
+                snippet = self.new_snippet({'description': new_text})
 
-                if not self.tree_view.row_expanded(path):
-                        self.tree_view.expand_row(path, False)
-                        self.select_iter(piter)
-
-                self.tree_view.grab_focus()
-
-                path = self.model.get_path(piter)
-                self.tree_view.set_cursor(path, self.column, True)
-        
-        def file_filter(self, name, pattern):
-                fil = Gtk.FileFilter()
-                fil.set_name(name)
-                
-                for p in pattern:
-                        fil.add_pattern(p)
-                
-                return fil
-        
-        def import_snippets(self, filenames):
-                success = True
-                
-                for filename in filenames:
-                        if not Pluma.utils_uri_has_file_scheme(filename):
-                                continue
-
-                        # Remove file://
-                        gfile = Gio.file_new_for_uri(filename)
-                        filename = gfile.get_path()
-
-                        importer = Importer(filename)
-                        error = importer.run()
-         
-                        if error:
-                                message = _('The following error occurred while importing: %s') % error
-                                success = False
-                                message_dialog(self.dlg, Gtk.MessageType.ERROR, message)
-                
-                self.build_model(True)
-
-                if success:
-                        message = _('Import successfully completed')
-                        message_dialog(self.dlg, Gtk.MessageType.INFO, message)
-               
-        def on_import_response(self, dialog, response):
-                if response == Gtk.ResponseType.CANCEL or response == Gtk.ResponseType.CLOSE:
-                        dialog.destroy()
-                        return
-                
-                f = dialog.get_uris()
-                dialog.destroy()
-                
-                self.import_snippets(f)
-                
-        def on_button_import_snippets_clicked(self, button):
-                dlg = Gtk.FileChooserDialog(parent=self.dlg, title=_("Import snippets"),
-                                action=Gtk.FileChooserAction.OPEN,
-                                buttons=(Gtk.STOCK_CANCEL, Gtk.ResponseType.CANCEL,
-                                         Gtk.STOCK_OPEN, Gtk.ResponseType.OK))
-                
-                dlg.add_filter(self.file_filter(_('All supported archives'), ('*.gz','*.bz2','*.tar', '*.xml')))
-                dlg.add_filter(self.file_filter(_('Gzip compressed archive'), ('*.tar.gz',)))
-                dlg.add_filter(self.file_filter(_('Bzip2 compressed archive'), ('*.tar.bz2',)))
-                dlg.add_filter(self.file_filter(_('Single snippets file'), ('*.xml',)))
-                dlg.add_filter(self.file_filter(_('All files'), '*'))
-
-                dlg.connect('response', self.on_import_response)
-                dlg.set_local_only(True)
-                
-                dlg.show()
-
-        def export_snippets_real(self, filename, snippets, show_dialogs=True):
-                export = Exporter(filename, snippets)
-                error = export.run()
-                
-                if error:
-                        message = _('The following error occurred while exporting: %s') % error
-                        msgtype = Gtk.MessageType.ERROR
-                        retval = False
-                else:
-                        message = _('Export successfully completed')
-                        msgtype = Gtk.MessageType.INFO
-                        retval = True
-
-                if show_dialogs:
-                        message_dialog(self.dlg, msgtype, message)
-
-                return retval
-                
-        def on_export_response(self, dialog, response):
-                filename = dialog.get_filename()
-                snippets = dialog._export_snippets
-                
-                dialog.destroy()
-                
-                if response != Gtk.ResponseType.OK:
-                        return
-                
-                self.export_snippets_real(filename, snippets);
-        
-        def export_snippets(self, filename=None, show_dialogs=True):
-                snippets = self.selected_snippets()
-                
-                if not snippets or len(snippets) == 0:
-                        return False
-                        
-                usersnippets = []
-                systemsnippets = []
-
-                # Iterate through snippets and look for system snippets
-                for snippet in snippets:
-                        if snippet.can_modify():
-                                usersnippets.append(snippet)
-                        else:
-                                systemsnippets.append(snippet)
-               
-                export_snippets = snippets
-
-                if len(systemsnippets) != 0 and show_dialogs:
-                        # Ask if system snippets should also be exported
-                        message = _('Do you want to include selected <b>system</b> snippets in your export?')
-                        mes = Gtk.MessageDialog(flags=Gtk.DialogFlags.MODAL,
-                                        type=Gtk.MessageType.QUESTION,
-                                        buttons=Gtk.ButtonsType.YES_NO,
-                                        message_format=message)
-                        mes.set_property('use-markup', True)
-                        resp = mes.run()
-                        mes.destroy()
-                        
-                        if resp == Gtk.ResponseType.NO:
-                                export_snippets = usersnippets
-                        elif resp != Gtk.ResponseType.YES:
-                                return False
-                
-                if len(export_snippets) == 0 and show_dialogs:                        
-                        message = _('There are no snippets selected to be exported')
-                        message_dialog(self.dlg, Gtk.MessageType.INFO, message)
-                        return False
-                
-                if not filename:
-                        dlg = Gtk.FileChooserDialog(parent=self.dlg, title=_('Export snippets'),
-                                        action=Gtk.FileChooserAction.SAVE,
-                                        buttons=(Gtk.STOCK_CANCEL, Gtk.ResponseType.CANCEL,
-                                                 Gtk.STOCK_SAVE, Gtk.ResponseType.OK))
-                        
-                        dlg._export_snippets = export_snippets
-                        dlg.add_filter(self.file_filter(_('All supported archives'), ('*.gz','*.bz2','*.tar')))
-                        dlg.add_filter(self.file_filter(_('Gzip compressed archive'), ('*.tar.gz',)))
-                        dlg.add_filter(self.file_filter(_('Bzip2 compressed archive'), ('*.tar.bz2',)))
-
-                        dlg.add_filter(self.file_filter(_('All files'), '*'))
-                        dlg.set_do_overwrite_confirmation(True)
-                        dlg.set_current_name(self.default_export_name)
-                
-                        dlg.connect('response', self.on_export_response)
-                        dlg.set_local_only(True)
-                
-                        dlg.show()
-                        return True
-                else:
-                        return self.export_snippets_real(filename, export_snippets, show_dialogs)
-        
-        def on_button_export_snippets_clicked(self, button):
-                snippets = self.selected_snippets()
-                
-                if not snippets or len(snippets) == 0:
-                        return
-                        
-                usersnippets = []
-                systemsnippets = []
-
-                # Iterate through snippets and look for system snippets
-                for snippet in snippets:
-                        if snippet.can_modify():
-                                usersnippets.append(snippet)
-                        else:
-                                systemsnippets.append(snippet)
-
-                dlg = Gtk.FileChooserDialog(parent=self.dlg, title=_('Export snippets'),
-                                action=Gtk.FileChooserAction.SAVE,
-                                buttons=(Gtk.STOCK_CANCEL, Gtk.ResponseType.CANCEL,
-                                         Gtk.STOCK_SAVE, Gtk.ResponseType.OK))
-                
-                dlg._export_snippets = snippets
-
-                if len(systemsnippets) != 0:
-                        # Ask if system snippets should also be exported
-                        message = _('Do you want to include selected <b>system</b> snippets in your export?')
-                        mes = Gtk.MessageDialog(flags=Gtk.DialogFlags.MODAL,
-                                        type=Gtk.MessageType.QUESTION,
-                                        buttons=Gtk.ButtonsType.YES_NO,
-                                        message_format=message)
-                        mes.set_property('use-markup', True)
-                        resp = mes.run()
-                        mes.destroy()
-                        
-                        if resp == Gtk.ResponseType.NO:
-                                dlg._export_snippets = usersnippets
-                        elif resp != Gtk.ResponseType.YES:
-                                dlg.destroy()
-                                return
-                
-                if len(dlg._export_snippets) == 0:
-                        dlg.destroy()
-                        
-                        message = _('There are no snippets selected to be exported')
-                        message_dialog(self.dlg, Gtk.MessageType.INFO, message)
-                        return
-                
-                dlg.add_filter(self.file_filter(_('All supported archives'), ('*.gz','*.bz2','*.tar')))
-                dlg.add_filter(self.file_filter(_('Gzip compressed archive'), ('*.tar.gz',)))
-                dlg.add_filter(self.file_filter(_('Bzip2 compressed archive'), ('*.tar.bz2',)))
-
-                dlg.add_filter(self.file_filter(_('All files'), '*'))
-                dlg.set_do_overwrite_confirmation(True)
-                dlg.set_current_name(self.default_export_name)
-                
-                dlg.connect('response', self.on_export_response)
-                dlg.set_local_only(True)
-                
-                dlg.show()                
-        
-        def remove_snippet_revert(self, path, piter):
-                node = self.snippet_from_iter(self.model, piter)
-                Library().revert_snippet(node)
-                
-                return piter
-        
-        def remove_snippet_delete(self, path, piter):
-                node = self.snippet_from_iter(self.model, piter)
-                parent = self.model.iter_parent(piter)
-
-                Library().remove_snippet(node)
-                idx = path.get_indices()
-
-                if self.model.remove(piter):
-                        return piter
-                elif idx[-1] != 0:
-                        self.select_iter(self.model.get_iter((idx[0], idx[1] - 1)))
-                else:
-                        dummy = self.add_new_snippet_node(parent)
-                        self.tree_view.expand_row(self.model.get_path(parent), False)
-                        return dummy
-       
-        def on_button_remove_snippet_clicked(self, button):
-                override, remove, system = self.selected_snippets_state()
-                
-                if not (override ^ remove) or system:
-                        return
-                
-                paths = self.selected_snippets(include_languages=False, as_path=True)
-                
-                if override:
-                        action = self.remove_snippet_revert
-                else:
-                        action = self.remove_snippet_delete
-                
-                # Remove selection
-                self.tree_view.get_selection().unselect_all()
-                
-                # Create tree row references
-                references = []
-                for path in paths:
-                        references.append(Gtk.TreeRowReference(self.model, path))
-
-                # Remove/revert snippets
-                select = None
-                for reference in references:
-                        path = reference.get_path()
-                        piter = self.model.get_iter(path)
-                        
-                        res = action(path, piter)
-                        
-                        if res:
-                                select = res
-
-                if select:
-                        self.select_iter(select)
-
-                self.selection_changed()
-        
-        def set_accelerator(self, keyval, mod):
-                accelerator = Gtk.accelerator_name(keyval, mod)
-                self.snippet['accelerator'] = accelerator
-
-                return True
-        
-        def on_entry_accelerator_key_press(self, entry, event):
-                source_view = self['source_view_snippet']
+                if snippet:
+                    self.model.set_value(piter, self.SNIPPET_COLUMN, snippet.data)
+                    self.snippet_changed(piter)
+                    self.snippet = snippet
+                    self.selection_changed()
 
-                if event.keyval == Gdk.keyval_from_name('Escape'):
-                        # Reset
-                        entry.set_text(self.snippet.accelerator_display())
-                        self.tree_view.grab_focus()
-                        
-                        return True
-                elif event.keyval == Gdk.keyval_from_name('Delete') or \
-                                event.keyval == Gdk.keyval_from_name('BackSpace'):
-                        # Remove the accelerator
-                        entry.set_text('')
-                        self.snippet['accelerator'] = ''
-                        self.tree_view.grab_focus()
-                        
-                        self.snippet_changed()
-                        return True
-                elif Library().valid_accelerator(event.keyval, event.state):
-                        # New accelerator
-                        self.set_accelerator(event.keyval, \
-                                        event.state & Gtk.accelerator_get_default_mod_mask())
-                        entry.set_text(self.snippet.accelerator_display())
-                        self.snippet_changed()
-                        self.tree_view.grab_focus()
+    def on_entry_accelerator_focus_out(self, entry, event):
+        if not self.snippet:
+            return
 
-                else:
-                        return True
-        
-        def on_entry_accelerator_focus_in(self, entry, event):
-                if self.snippet['accelerator']:
-                        entry.set_text(_('Type a new shortcut, or press Backspace to clear'))
-                else:
-                        entry.set_text(_('Type a new shortcut'))
-        
-        def update_language_path(self):
-                model, paths = self.tree_view.get_selection().get_selected_rows()
-                
-                # Check if all have the same language parent
-                current_parent = None
+        entry.set_text(self.snippet.accelerator_display())
 
-                for path in paths:
-                        piter = model.get_iter(path)
-                        parent = model.iter_parent(piter)
-                        
-                        if parent:
-                                path = model.get_path(parent)
-
-                        if current_parent != None and current_parent != path:
-                                current_parent = None
-                                break
-                        else:
-                                current_parent = path
-
-                self.language_path = current_parent
-                
-        def on_tree_view_selection_changed(self, selection):
-                parent, piter, node = self.selected_snippet()
-                
-                if self.snippet:
-                        self.on_entry_tab_trigger_focus_out(self['entry_tab_trigger'],
-                                        None)
-                        self.on_source_view_snippet_focus_out(self['source_view_snippet'], 
-                                        None)
-                        self.on_entry_drop_targets_focus_out(self['combo_drop_targets'].get_child(),
-                                        None)
-                
-                self.update_language_path()
-
-                if node:
-                        self.snippet = Snippet(node)
-                else:
-                        self.snippet = None
+    def entry_tab_trigger_update_valid(self):
+        entry = self['entry_tab_trigger']
+        text = entry.get_text()
+
+        if text and not Library().valid_tab_trigger(text):
+            img = self['image_tab_trigger']
+            img.set_from_stock(Gtk.STOCK_DIALOG_ERROR, Gtk.IconSize.BUTTON)
+            img.show()
+
+            #self['hbox_tab_trigger'].set_spacing(3)
+            tip = _('This is not a valid Tab trigger. Triggers can either contain letters or a single (non-alphanumeric) character like: {, [, etc.')
+
+            entry.set_tooltip_text(tip)
+            img.set_tooltip_text(tip)
+        else:
+            self['image_tab_trigger'].hide()
+            #self['hbox_tab_trigger'].set_spacing(0)
+            entry.set_tooltip_text(_('Single word the snippet is activated with after pressing Tab'))
+
+        return False
+
+    def on_entry_tab_trigger_focus_out(self, entry, event):
+        if not self.snippet:
+            return
+
+        text = entry.get_text()
+
+        # save tag
+        self.snippet['tag'] = text
+        self.snippet_changed()
+
+    def on_entry_drop_targets_focus_out(self, entry, event):
+        if not self.snippet:
+            return
+
+        text = entry.get_text()
+
+        # save drop targets
+        self.snippet['drop-targets'] = text
+        self.snippet_changed()
+
+    def on_entry_tab_trigger_changed(self, entry):
+        self.entry_tab_trigger_update_valid()
+
+    def on_source_view_snippet_focus_out(self, source_view, event):
+        if not self.snippet:
+            return
+
+        buf = source_view.get_buffer()
+        text = buf.get_text(buf.get_start_iter(), \
+                buf.get_end_iter(), False)
+
+        self.snippet['text'] = text
+        self.snippet_changed()
+
+    def on_button_new_snippet_clicked(self, button):
+        snippet = self.new_snippet()
+
+        if not snippet:
+            return
+
+        parent = self.model.get_iter(self.language_path)
+        path = self.model.get_path(parent)
+
+        dummy = self.get_dummy(parent)
+
+        if dummy:
+            # Remove the dummy
+            self.model.remove(dummy)
+
+        # Add the snippet
+        piter = self.add_snippet(parent, snippet.data)
+        self.select_iter(piter)
+
+        if not self.tree_view.row_expanded(path):
+            self.tree_view.expand_row(path, False)
+            self.select_iter(piter)
+
+        self.tree_view.grab_focus()
+
+        path = self.model.get_path(piter)
+        self.tree_view.set_cursor(path, self.column, True)
+
+    def file_filter(self, name, pattern):
+        fil = Gtk.FileFilter()
+        fil.set_name(name)
+
+        for p in pattern:
+            fil.add_pattern(p)
+
+        return fil
+
+    def import_snippets(self, filenames):
+        success = True
+
+        for filename in filenames:
+            if not Pluma.utils_uri_has_file_scheme(filename):
+                continue
+
+            # Remove file://
+            gfile = Gio.file_new_for_uri(filename)
+            filename = gfile.get_path()
+
+            importer = Importer(filename)
+            error = importer.run()
+
+            if error:
+                message = _('The following error occurred while importing: %s') % error
+                success = False
+                message_dialog(self.dlg, Gtk.MessageType.ERROR, message)
+
+        self.build_model(True)
+
+        if success:
+            message = _('Import successfully completed')
+            message_dialog(self.dlg, Gtk.MessageType.INFO, message)
 
-                self.selection_changed()
+    def on_import_response(self, dialog, response):
+        if response == Gtk.ResponseType.CANCEL or response == Gtk.ResponseType.CLOSE:
+            dialog.destroy()
+            return
 
-        def iter_after(self, target, after):
-                if not after:
-                        return True
+        f = dialog.get_uris()
+        dialog.destroy()
 
-                tp = self.model.get_path(target)
-                ap = self.model.get_path(after)
-                
-                if tp[0] > ap[0] or (tp[0] == ap[0] and (len(ap) == 1 or tp[1] > ap[1])):
-                        return True
-                
+        self.import_snippets(f)
+
+    def on_button_import_snippets_clicked(self, button):
+        dlg = Gtk.FileChooserDialog(parent=self.dlg, title=_("Import snippets"),
+                action=Gtk.FileChooserAction.OPEN,
+                buttons=(Gtk.STOCK_CANCEL, Gtk.ResponseType.CANCEL,
+                     Gtk.STOCK_OPEN, Gtk.ResponseType.OK))
+
+        dlg.add_filter(self.file_filter(_('All supported archives'), ('*.gz','*.bz2','*.tar', '*.xml')))
+        dlg.add_filter(self.file_filter(_('Gzip compressed archive'), ('*.tar.gz',)))
+        dlg.add_filter(self.file_filter(_('Bzip2 compressed archive'), ('*.tar.bz2',)))
+        dlg.add_filter(self.file_filter(_('Single snippets file'), ('*.xml',)))
+        dlg.add_filter(self.file_filter(_('All files'), '*'))
+
+        dlg.connect('response', self.on_import_response)
+        dlg.set_local_only(True)
+
+        dlg.show()
+
+    def export_snippets_real(self, filename, snippets, show_dialogs=True):
+        export = Exporter(filename, snippets)
+        error = export.run()
+
+        if error:
+            message = _('The following error occurred while exporting: %s') % error
+            msgtype = Gtk.MessageType.ERROR
+            retval = False
+        else:
+            message = _('Export successfully completed')
+            msgtype = Gtk.MessageType.INFO
+            retval = True
+
+        if show_dialogs:
+            message_dialog(self.dlg, msgtype, message)
+
+        return retval
+
+    def on_export_response(self, dialog, response):
+        filename = dialog.get_filename()
+        snippets = dialog._export_snippets
+
+        dialog.destroy()
+
+        if response != Gtk.ResponseType.OK:
+            return
+
+        self.export_snippets_real(filename, snippets);
+
+    def export_snippets(self, filename=None, show_dialogs=True):
+        snippets = self.selected_snippets()
+
+        if not snippets or len(snippets) == 0:
+            return False
+
+        usersnippets = []
+        systemsnippets = []
+
+        # Iterate through snippets and look for system snippets
+        for snippet in snippets:
+            if snippet.can_modify():
+                usersnippets.append(snippet)
+            else:
+                systemsnippets.append(snippet)
+
+        export_snippets = snippets
+
+        if len(systemsnippets) != 0 and show_dialogs:
+            # Ask if system snippets should also be exported
+            message = _('Do you want to include selected <b>system</b> snippets in your export?')
+            mes = Gtk.MessageDialog(flags=Gtk.DialogFlags.MODAL,
+                    type=Gtk.MessageType.QUESTION,
+                    buttons=Gtk.ButtonsType.YES_NO,
+                    message_format=message)
+            mes.set_property('use-markup', True)
+            resp = mes.run()
+            mes.destroy()
+
+            if resp == Gtk.ResponseType.NO:
+                export_snippets = usersnippets
+            elif resp != Gtk.ResponseType.YES:
                 return False
-                
-        def on_tree_view_snippets_key_press(self, treeview, event):
-                if event.keyval == Gdk.keyval_from_name('Delete'):
-                        self.on_button_remove_snippet_clicked(None)
-                        return True
-
-        def on_tree_view_snippets_row_expanded(self, treeview, piter, path):
-                # Check if it is already filled
-                self.fill_if_needed(piter)
-                self.select_iter(piter)
-        
-        def on_entry_drop_targets_drag_data_received(self, entry, context, x, y, selection_data, info, timestamp):
-                uris = drop_get_uris(selection_data)
-                
-                if not uris:
-                        return
-                
-                if entry.get_text():
-                        mimes = [entry.get_text()]
-                else:
-                        mimes = []
-                
-                for uri in uris:
-                        try:
-                                mime = Gio.content_type_guess(uri)
-                        except:
-                                mime = None
-                        
-                        if mime:
-                                mimes.append(mime)
-                
-                entry.set_text(', '.join(mimes))
-                self.on_entry_drop_targets_focus_out(entry, None)
-                context.finish(True, False, timestamp)
-                
-                entry.stop_emission('drag_data_received')
-# ex:ts=8:et:
+
+        if len(export_snippets) == 0 and show_dialogs:
+            message = _('There are no snippets selected to be exported')
+            message_dialog(self.dlg, Gtk.MessageType.INFO, message)
+            return False
+
+        if not filename:
+            dlg = Gtk.FileChooserDialog(parent=self.dlg, title=_('Export snippets'),
+                    action=Gtk.FileChooserAction.SAVE,
+                    buttons=(Gtk.STOCK_CANCEL, Gtk.ResponseType.CANCEL,
+                         Gtk.STOCK_SAVE, Gtk.ResponseType.OK))
+
+            dlg._export_snippets = export_snippets
+            dlg.add_filter(self.file_filter(_('All supported archives'), ('*.gz','*.bz2','*.tar')))
+            dlg.add_filter(self.file_filter(_('Gzip compressed archive'), ('*.tar.gz',)))
+            dlg.add_filter(self.file_filter(_('Bzip2 compressed archive'), ('*.tar.bz2',)))
+
+            dlg.add_filter(self.file_filter(_('All files'), '*'))
+            dlg.set_do_overwrite_confirmation(True)
+            dlg.set_current_name(self.default_export_name)
+
+            dlg.connect('response', self.on_export_response)
+            dlg.set_local_only(True)
+
+            dlg.show()
+            return True
+        else:
+            return self.export_snippets_real(filename, export_snippets, show_dialogs)
+
+    def on_button_export_snippets_clicked(self, button):
+        snippets = self.selected_snippets()
+
+        if not snippets or len(snippets) == 0:
+            return
+
+        usersnippets = []
+        systemsnippets = []
+
+        # Iterate through snippets and look for system snippets
+        for snippet in snippets:
+            if snippet.can_modify():
+                usersnippets.append(snippet)
+            else:
+                systemsnippets.append(snippet)
+
+        dlg = Gtk.FileChooserDialog(parent=self.dlg, title=_('Export snippets'),
+                action=Gtk.FileChooserAction.SAVE,
+                buttons=(Gtk.STOCK_CANCEL, Gtk.ResponseType.CANCEL,
+                     Gtk.STOCK_SAVE, Gtk.ResponseType.OK))
+
+        dlg._export_snippets = snippets
+
+        if len(systemsnippets) != 0:
+            # Ask if system snippets should also be exported
+            message = _('Do you want to include selected <b>system</b> snippets in your export?')
+            mes = Gtk.MessageDialog(flags=Gtk.DialogFlags.MODAL,
+                    type=Gtk.MessageType.QUESTION,
+                    buttons=Gtk.ButtonsType.YES_NO,
+                    message_format=message)
+            mes.set_property('use-markup', True)
+            resp = mes.run()
+            mes.destroy()
+
+            if resp == Gtk.ResponseType.NO:
+                dlg._export_snippets = usersnippets
+            elif resp != Gtk.ResponseType.YES:
+                dlg.destroy()
+                return
+
+        if len(dlg._export_snippets) == 0:
+            dlg.destroy()
+
+            message = _('There are no snippets selected to be exported')
+            message_dialog(self.dlg, Gtk.MessageType.INFO, message)
+            return
+
+        dlg.add_filter(self.file_filter(_('All supported archives'), ('*.gz','*.bz2','*.tar')))
+        dlg.add_filter(self.file_filter(_('Gzip compressed archive'), ('*.tar.gz',)))
+        dlg.add_filter(self.file_filter(_('Bzip2 compressed archive'), ('*.tar.bz2',)))
+
+        dlg.add_filter(self.file_filter(_('All files'), '*'))
+        dlg.set_do_overwrite_confirmation(True)
+        dlg.set_current_name(self.default_export_name)
+
+        dlg.connect('response', self.on_export_response)
+        dlg.set_local_only(True)
+
+        dlg.show()
+
+    def remove_snippet_revert(self, path, piter):
+        node = self.snippet_from_iter(self.model, piter)
+        Library().revert_snippet(node)
+
+        return piter
+
+    def remove_snippet_delete(self, path, piter):
+        node = self.snippet_from_iter(self.model, piter)
+        parent = self.model.iter_parent(piter)
+
+        Library().remove_snippet(node)
+        idx = path.get_indices()
+
+        if self.model.remove(piter):
+            return piter
+        elif idx[-1] != 0:
+            self.select_iter(self.model.get_iter((idx[0], idx[1] - 1)))
+        else:
+            dummy = self.add_new_snippet_node(parent)
+            self.tree_view.expand_row(self.model.get_path(parent), False)
+            return dummy
+
+    def on_button_remove_snippet_clicked(self, button):
+        override, remove, system = self.selected_snippets_state()
+
+        if not (override ^ remove) or system:
+            return
+
+        paths = self.selected_snippets(include_languages=False, as_path=True)
+
+        if override:
+            action = self.remove_snippet_revert
+        else:
+            action = self.remove_snippet_delete
+
+        # Remove selection
+        self.tree_view.get_selection().unselect_all()
+
+        # Create tree row references
+        references = []
+        for path in paths:
+            references.append(Gtk.TreeRowReference(self.model, path))
+
+        # Remove/revert snippets
+        select = None
+        for reference in references:
+            path = reference.get_path()
+            piter = self.model.get_iter(path)
+
+            res = action(path, piter)
+
+            if res:
+                select = res
+
+        if select:
+            self.select_iter(select)
+
+        self.selection_changed()
+
+    def set_accelerator(self, keyval, mod):
+        accelerator = Gtk.accelerator_name(keyval, mod)
+        self.snippet['accelerator'] = accelerator
+
+        return True
+
+    def on_entry_accelerator_key_press(self, entry, event):
+        source_view = self['source_view_snippet']
+
+        if event.keyval == Gdk.keyval_from_name('Escape'):
+            # Reset
+            entry.set_text(self.snippet.accelerator_display())
+            self.tree_view.grab_focus()
+
+            return True
+        elif event.keyval == Gdk.keyval_from_name('Delete') or \
+                event.keyval == Gdk.keyval_from_name('BackSpace'):
+            # Remove the accelerator
+            entry.set_text('')
+            self.snippet['accelerator'] = ''
+            self.tree_view.grab_focus()
+
+            self.snippet_changed()
+            return True
+        elif Library().valid_accelerator(event.keyval, event.state):
+            # New accelerator
+            self.set_accelerator(event.keyval, \
+                    event.state & Gtk.accelerator_get_default_mod_mask())
+            entry.set_text(self.snippet.accelerator_display())
+            self.snippet_changed()
+            self.tree_view.grab_focus()
+
+        else:
+            return True
+
+    def on_entry_accelerator_focus_in(self, entry, event):
+        if self.snippet['accelerator']:
+            entry.set_text(_('Type a new shortcut, or press Backspace to clear'))
+        else:
+            entry.set_text(_('Type a new shortcut'))
+
+    def update_language_path(self):
+        model, paths = self.tree_view.get_selection().get_selected_rows()
+
+        # Check if all have the same language parent
+        current_parent = None
+
+        for path in paths:
+            piter = model.get_iter(path)
+            parent = model.iter_parent(piter)
+
+            if parent:
+                path = model.get_path(parent)
+
+            if current_parent != None and current_parent != path:
+                current_parent = None
+                break
+            else:
+                current_parent = path
+
+        self.language_path = current_parent
+
+    def on_tree_view_selection_changed(self, selection):
+        parent, piter, node = self.selected_snippet()
+
+        if self.snippet:
+            self.on_entry_tab_trigger_focus_out(self['entry_tab_trigger'],
+                    None)
+            self.on_source_view_snippet_focus_out(self['source_view_snippet'],
+                    None)
+            self.on_entry_drop_targets_focus_out(self['combo_drop_targets'].get_child(),
+                    None)
+
+        self.update_language_path()
+
+        if node:
+            self.snippet = Snippet(node)
+        else:
+            self.snippet = None
+
+        self.selection_changed()
+
+    def iter_after(self, target, after):
+        if not after:
+            return True
+
+        tp = self.model.get_path(target)
+        ap = self.model.get_path(after)
+
+        if tp[0] > ap[0] or (tp[0] == ap[0] and (len(ap) == 1 or tp[1] > ap[1])):
+            return True
+
+        return False
+
+    def on_tree_view_snippets_key_press(self, treeview, event):
+        if event.keyval == Gdk.keyval_from_name('Delete'):
+            self.on_button_remove_snippet_clicked(None)
+            return True
+
+    def on_tree_view_snippets_row_expanded(self, treeview, piter, path):
+        # Check if it is already filled
+        self.fill_if_needed(piter)
+        self.select_iter(piter)
+
+    def on_entry_drop_targets_drag_data_received(self, entry, context, x, y, selection_data, info, timestamp):
+        uris = drop_get_uris(selection_data)
+
+        if not uris:
+            return
+
+        if entry.get_text():
+            mimes = [entry.get_text()]
+        else:
+            mimes = []
+
+        for uri in uris:
+            try:
+                mime = Gio.content_type_guess(uri)
+            except:
+                mime = None
+
+            if mime:
+                mimes.append(mime)
+
+        entry.set_text(', '.join(mimes))
+        self.on_entry_drop_targets_focus_out(entry, None)
+        context.finish(True, False, timestamp)
+
+        entry.stop_emission('drag_data_received')
+# ex:ts=4:et:
diff --git a/plugins/snippets/snippets/Parser.py b/plugins/snippets/snippets/Parser.py
old mode 100755
new mode 100644
index 0c638df..280ce0c
--- a/plugins/snippets/snippets/Parser.py
+++ b/plugins/snippets/snippets/Parser.py
@@ -21,239 +21,239 @@ import sys
 from SubstitutionParser import SubstitutionParser
 
 class Token:
-        def __init__(self, klass, data):
-                self.klass = klass
-                self.data = data
-
-        def __str__(self):
-                return '%s: [%s]' % (self.klass, self.data)
-                
-        def __eq__(self, other):
-                return self.klass == other.klass and self.data == other.data
-        
-        def __ne__(self, other):
-                return not self.__eq__(other)
+    def __init__(self, klass, data):
+        self.klass = klass
+        self.data = data
+
+    def __str__(self):
+        return '%s: [%s]' % (self.klass, self.data)
+
+    def __eq__(self, other):
+        return self.klass == other.klass and self.data == other.data
+
+    def __ne__(self, other):
+        return not self.__eq__(other)
 
 class Parser:
-        SREG_ENV = '[A-Z_]+'
-        SREG_ID = '[0-9]+'
-
-        REG_ESCAPE = re.compile('(\\$(%s|\\(|\\{|<|%s)|`|\\\\)' % (SREG_ENV, SREG_ID))
-        
-        def __init__(self, **kwargs):
-                for k, v in kwargs.items():
-                        setattr(self, k, v)
-
-                self.position = 0
-                self.data_length = len(self.data)
-                
-                self.RULES = (self._match_env, self._match_regex, self._match_placeholder, self._match_shell, self._match_eval, self._text)
-        
-        def remains(self):
-                return self.data[self.position:]
-
-        def next_char(self):
-                if self.position + 1 >= self.data_length:
-                        return ''
-                else:
-                        return self.data[self.position + 1]
-                
-        def char(self):
-                if self.position >= self.data_length:
-                        return ''
-                else:
-                        return self.data[self.position]
-
-        def token(self):
-                self.tktext = ''
-
-                while self.position < self.data_length:
-                        try:
-                                # Get first character
-                                func = {'$': self._rule,
-                                        '`': self._try_match_shell}[self.char()]
-                        except:
-                                func = self._text
-
-                        # Detect end of text token
-                        if func != self._text and self.tktext != '':
-                                return Token('text', self.tktext)
-                        
-                        tk = func()
-
-                        if tk:
-                                return tk
-                
-                if self.tktext != '':
-                        return Token('text', self.tktext)
-
-        def _need_escape(self):
-                text = self.remains()[1:]
-
-                if text == '':
-                        return False
-                
-                return self.REG_ESCAPE.match(text)
-                
-        def _escape(self):                
-                if not self._need_escape():
-                        return
-                
-                # Increase position with 1
-                self.position += 1
-                
-        def _text(self):
-                if self.char() == '\\':
-                        self._escape()
-
-                self.tktext += self.char()
-                self.position += 1
-        
-        def _rule(self):
-                for rule in self.RULES:
-                        res = rule()
-                        
-                        if res:
-                                return res
-
-        def _match_env(self):
-                text = self.remains()
-                match = re.match('\\$(%s)' % self.SREG_ENV, text) or re.match('\\${(%s)}' % self.SREG_ENV, text)
-                
-                if match:
-                        self.position += len(match.group(0))
-                        return Token('environment', match.group(1))
-        
-        def _parse_list(self, lst):
-                pos = 0
-                length = len(lst)
-                items = []
-                last = None
-                
-                while pos < length:
-                        char = lst[pos]
-                        next = pos < length - 1 and lst[pos + 1]
-                        
-                        if char == '\\' and (next == ',' or next == ']'):
-                                char = next
-                                pos += 1
-                        elif char == ',':
-                                if last != None:
-                                        items.append(last)
-                                
-                                last = None
-                                pos += 1
-                                continue
-
-                        last = (last != None and last + char) or char
-                        pos += 1
-                
+    SREG_ENV = '[A-Z_]+'
+    SREG_ID = '[0-9]+'
+
+    REG_ESCAPE = re.compile('(\\$(%s|\\(|\\{|<|%s)|`|\\\\)' % (SREG_ENV, SREG_ID))
+
+    def __init__(self, **kwargs):
+        for k, v in kwargs.items():
+            setattr(self, k, v)
+
+        self.position = 0
+        self.data_length = len(self.data)
+
+        self.RULES = (self._match_env, self._match_regex, self._match_placeholder, self._match_shell, self._match_eval, self._text)
+
+    def remains(self):
+        return self.data[self.position:]
+
+    def next_char(self):
+        if self.position + 1 >= self.data_length:
+            return ''
+        else:
+            return self.data[self.position + 1]
+
+    def char(self):
+        if self.position >= self.data_length:
+            return ''
+        else:
+            return self.data[self.position]
+
+    def token(self):
+        self.tktext = ''
+
+        while self.position < self.data_length:
+            try:
+                # Get first character
+                func = {'$': self._rule,
+                    '`': self._try_match_shell}[self.char()]
+            except:
+                func = self._text
+
+            # Detect end of text token
+            if func != self._text and self.tktext != '':
+                return Token('text', self.tktext)
+
+            tk = func()
+
+            if tk:
+                return tk
+
+        if self.tktext != '':
+            return Token('text', self.tktext)
+
+    def _need_escape(self):
+        text = self.remains()[1:]
+
+        if text == '':
+            return False
+
+        return self.REG_ESCAPE.match(text)
+
+    def _escape(self):
+        if not self._need_escape():
+            return
+
+        # Increase position with 1
+        self.position += 1
+
+    def _text(self):
+        if self.char() == '\\':
+            self._escape()
+
+        self.tktext += self.char()
+        self.position += 1
+
+    def _rule(self):
+        for rule in self.RULES:
+            res = rule()
+
+            if res:
+                return res
+
+    def _match_env(self):
+        text = self.remains()
+        match = re.match('\\$(%s)' % self.SREG_ENV, text) or re.match('\\${(%s)}' % self.SREG_ENV, text)
+
+        if match:
+            self.position += len(match.group(0))
+            return Token('environment', match.group(1))
+
+    def _parse_list(self, lst):
+        pos = 0
+        length = len(lst)
+        items = []
+        last = None
+
+        while pos < length:
+            char = lst[pos]
+            next = pos < length - 1 and lst[pos + 1]
+
+            if char == '\\' and (next == ',' or next == ']'):
+                char = next
+                pos += 1
+            elif char == ',':
                 if last != None:
-                        items.append(last)
-                
-                return items
-        
-        def _parse_default(self, default):
-                match = re.match('^\\s*(\\\\)?(\\[((\\\\]|[^\\]])+)\\]\\s*)$', default)
-                
-                if not match:
-                        return [default]
-                
-                groups = match.groups()
-                
-                if groups[0]:
-                        return [groups[1]]
-
-                return self._parse_list(groups[2])
-        
-        def _match_placeholder(self):
-                text = self.remains()
-                
-                match = re.match('\\${(%s)(:((\\\\\\}|[^}])+))?}' % self.SREG_ID, text) or re.match('\\$(%s)' % self.SREG_ID, text)
-                
-                if not match:
-                        return None
-                
-                groups = match.groups()
-                default = ''
-                tabstop = int(groups[0])
-                self.position += len(match.group(0))
-                
-                if len(groups) > 1 and groups[2]:
-                        default = self._parse_default(groups[2].replace('\\}', '}'))
-
-                return Token('placeholder', {'tabstop': tabstop, 'default': default})
-
-        def _match_shell(self):
-                text = self.remains()
-                match = re.match('`((%s):)?((\\\\`|[^`])+?)`' % self.SREG_ID, text) or re.match('\\$\\(((%s):)?((\\\\\\)|[^\\)])+?)\\)' % self.SREG_ID, text)
-                
-                if not match:
-                        return None
-                
-                groups = match.groups()
-                tabstop = (groups[1] and int(groups[1])) or -1
-                self.position += len(match.group(0))
-
-                if text[0] == '`':
-                        contents = groups[2].replace('\\`', '`')
-                else:
-                        contents = groups[2].replace('\\)', ')')
-                
-                return Token('shell', {'tabstop': tabstop, 'contents': contents})
-
-        def _try_match_shell(self):
-                return self._match_shell() or self._text()
-        
-        def _eval_options(self, options):
-                reg = re.compile(self.SREG_ID)
-                tabstop = -1
-                depend = []
-                
-                options = options.split(':')
-                
-                for opt in options:
-                        if reg.match(opt):
-                                tabstop = int(opt)
-                        else:
-                                depend += self._parse_list(opt[1:-1])
-                
-                return (tabstop, depend)
-                
-        def _match_eval(self):
-                text = self.remains()
-                
-                options = '((%s)|\\[([0-9, ]+)\\])' % self.SREG_ID
-                match = re.match('\\$<((%s:)*)((\\\\>|[^>])+?)>' % options, text)
-                
-                if not match:
-                        return None
-                
-                groups = match.groups()
-                (tabstop, depend) = (groups[0] and self._eval_options(groups[0][:-1])) or (-1, [])
-                self.position += len(match.group(0))
-                
-                return Token('eval', {'tabstop': tabstop, 'dependencies': depend, 'contents': groups[5].replace('\\>', '>')})
-                
-        def _match_regex(self):
-                text = self.remains()
-                
-                content = '((?:\\\\[/]|\\\\}|[^/}])+)'
-                match = re.match('\\${(?:(%s):)?\\s*(%s|\\$([A-Z_]+))?[/]%s[/]%s(?:[/]([a-zA-Z]*))?}' % (self.SREG_ID, self.SREG_ID, content, content), text)
-                
-                if not match:
-                        return None
-                
-                groups = match.groups()
-                tabstop = (groups[0] and int(groups[0])) or -1
-                inp = (groups[2] or (groups[1] and int(groups[1]))) or ''
-                
-                pattern = re.sub('\\\\([/}])', '\\1', groups[3])
-                substitution = re.sub('\\\\([/}])', '\\1', groups[4])
-                modifiers = groups[5] or ''
-                
-                self.position += len(match.group(0))
-                
-                return Token('regex', {'tabstop': tabstop, 'input': inp, 'pattern': pattern, 'substitution': substitution, 'modifiers': modifiers})
-
-# ex:ts=8:et:
+                    items.append(last)
+
+                last = None
+                pos += 1
+                continue
+
+            last = (last != None and last + char) or char
+            pos += 1
+
+        if last != None:
+            items.append(last)
+
+        return items
+
+    def _parse_default(self, default):
+        match = re.match('^\\s*(\\\\)?(\\[((\\\\]|[^\\]])+)\\]\\s*)$', default)
+
+        if not match:
+            return [default]
+
+        groups = match.groups()
+
+        if groups[0]:
+            return [groups[1]]
+
+        return self._parse_list(groups[2])
+
+    def _match_placeholder(self):
+        text = self.remains()
+
+        match = re.match('\\${(%s)(:((\\\\\\}|[^}])+))?}' % self.SREG_ID, text) or re.match('\\$(%s)' % self.SREG_ID, text)
+
+        if not match:
+            return None
+
+        groups = match.groups()
+        default = ''
+        tabstop = int(groups[0])
+        self.position += len(match.group(0))
+
+        if len(groups) > 1 and groups[2]:
+            default = self._parse_default(groups[2].replace('\\}', '}'))
+
+        return Token('placeholder', {'tabstop': tabstop, 'default': default})
+
+    def _match_shell(self):
+        text = self.remains()
+        match = re.match('`((%s):)?((\\\\`|[^`])+?)`' % self.SREG_ID, text) or re.match('\\$\\(((%s):)?((\\\\\\)|[^\\)])+?)\\)' % self.SREG_ID, text)
+
+        if not match:
+            return None
+
+        groups = match.groups()
+        tabstop = (groups[1] and int(groups[1])) or -1
+        self.position += len(match.group(0))
+
+        if text[0] == '`':
+            contents = groups[2].replace('\\`', '`')
+        else:
+            contents = groups[2].replace('\\)', ')')
+
+        return Token('shell', {'tabstop': tabstop, 'contents': contents})
+
+    def _try_match_shell(self):
+        return self._match_shell() or self._text()
+
+    def _eval_options(self, options):
+        reg = re.compile(self.SREG_ID)
+        tabstop = -1
+        depend = []
+
+        options = options.split(':')
+
+        for opt in options:
+            if reg.match(opt):
+                tabstop = int(opt)
+            else:
+                depend += self._parse_list(opt[1:-1])
+
+        return (tabstop, depend)
+
+    def _match_eval(self):
+        text = self.remains()
+
+        options = '((%s)|\\[([0-9, ]+)\\])' % self.SREG_ID
+        match = re.match('\\$<((%s:)*)((\\\\>|[^>])+?)>' % options, text)
+
+        if not match:
+            return None
+
+        groups = match.groups()
+        (tabstop, depend) = (groups[0] and self._eval_options(groups[0][:-1])) or (-1, [])
+        self.position += len(match.group(0))
+
+        return Token('eval', {'tabstop': tabstop, 'dependencies': depend, 'contents': groups[5].replace('\\>', '>')})
+
+    def _match_regex(self):
+        text = self.remains()
+
+        content = '((?:\\\\[/]|\\\\}|[^/}])+)'
+        match = re.match('\\${(?:(%s):)?\\s*(%s|\\$([A-Z_]+))?[/]%s[/]%s(?:[/]([a-zA-Z]*))?}' % (self.SREG_ID, self.SREG_ID, content, content), text)
+
+        if not match:
+            return None
+
+        groups = match.groups()
+        tabstop = (groups[0] and int(groups[0])) or -1
+        inp = (groups[2] or (groups[1] and int(groups[1]))) or ''
+
+        pattern = re.sub('\\\\([/}])', '\\1', groups[3])
+        substitution = re.sub('\\\\([/}])', '\\1', groups[4])
+        modifiers = groups[5] or ''
+
+        self.position += len(match.group(0))
+
+        return Token('regex', {'tabstop': tabstop, 'input': inp, 'pattern': pattern, 'substitution': substitution, 'modifiers': modifiers})
+
+# ex:ts=4:et:
diff --git a/plugins/snippets/snippets/Placeholder.py b/plugins/snippets/snippets/Placeholder.py
old mode 100755
new mode 100644
index 5fa6e55..9edf099
--- a/plugins/snippets/snippets/Placeholder.py
+++ b/plugins/snippets/snippets/Placeholder.py
@@ -29,671 +29,671 @@ from Helper import *
 
 # These are places in a view where the cursor can go and do things
 class Placeholder:
-        def __init__(self, view, tabstop, defaults, begin):
-                self.ok = True
-                self.done = False
-                self.buf = view.get_buffer()
-                self.view = view
-                self.has_references = False
-                self.mirrors = []
-                self.leave_mirrors = []
-                self.tabstop = tabstop
-                self.set_default(defaults)
-                self.prev_contents = self.default
-                self.set_mark_gravity()
-                
-                if begin:
-                        self.begin = self.buf.create_mark(None, begin, self.mark_gravity[0])
-                else:
-                        self.begin = None
-                
-                self.end = None
-        
-        def __str__(self):
-                return '%s (%s)' % (str(self.__class__), str(self.default))
-
-        def set_mark_gravity(self):
-                self.mark_gravity = [True, False]
-
-        def set_default(self, defaults):
-                self.default = None
-                self.defaults = []
-
-                if not defaults:
-                        return
-
-                for d in defaults:
-                        dm = self.expand_environment(d)
-                        
-                        if dm:
-                                self.defaults.append(dm)
-
-                                if not self.default:
-                                        self.default = dm
-                                
-                                if dm != d:
-                                        break
-
-        
-        def literal(self, s):
-                return repr(s)
-                
-        def format_environment(self, s):
-                return s
-
-        def re_environment(self, m):
-                if m.group(1) or not m.group(2) in os.environ:
-                        return '$' + m.group(2)
-                else:
-                        return self.format_environment(os.environ[m.group(2)])
-
-        def expand_environment(self, text):
-                if not text:
-                        return text
-
-                return re.sub('(\\\\)?\\$([A-Z_]+)', self.re_environment, text)
-        
-        def get_iter(self, mark):
-                if mark and not mark.get_deleted():
-                        return self.buf.get_iter_at_mark(mark)
-                else:
-                        return None
-
-        def begin_iter(self):
-                return self.get_iter(self.begin)
-        
-        def end_iter(self):
-                return self.get_iter(self.end)
-        
-        def run_last(self, placeholders):
-                begin = self.begin_iter()
-                self.end = self.buf.create_mark(None, begin, self.mark_gravity[1])
-
-                if self.default:
-                        insert_with_indent(self.view, begin, self.default, False, self)
-        
-        def remove(self, force = False):
-                if self.begin and not self.begin.get_deleted():
-                        self.buf.delete_mark(self.begin)
-                
-                if self.end and not self.end.get_deleted():
-                        self.buf.delete_mark(self.end)
-                
-        # Do something on beginning this placeholder
-        def enter(self):
-                if not self.begin or self.begin.get_deleted():
-                        return
-
-                self.buf.move_mark(self.buf.get_insert(), self.begin_iter())
-
-                if self.end:
-                        self.buf.move_mark(self.buf.get_selection_bound(), self.end_iter())
-                else:
-                        self.buf.move_mark(self.buf.get_selection_bound(), self.begin_iter())
-        
-        def get_text(self):
-                if self.begin and self.end:
-                        biter = self.begin_iter()
-                        eiter = self.end_iter()
-                        
-                        if biter and eiter:
-                                return self.buf.get_text(self.begin_iter(), self.end_iter(), False)
-                        else:
-                                return ''
-                else:
-                        return ''
-        
-        def add_mirror(self, mirror, onleave = False):
-                mirror.has_references = True
-
-                if onleave:
-                        self.leave_mirrors.append(mirror)
-                else:
-                        self.mirrors.append(mirror)
-
-        def set_text(self, text):
-                if self.begin.get_deleted() or self.end.get_deleted():
-                        return
-
-                # Set from self.begin to self.end to text!
-                self.buf.begin_user_action()
-                # Remove everything between self.begin and self.end
-                begin = self.begin_iter()
-                self.buf.delete(begin, self.end_iter())
-
-                # Insert the text from the mirror
-                insert_with_indent(self.view, begin, text, True, self)
-                self.buf.end_user_action()
-                
-                self.update_contents()
-
-        def update_contents(self):
-                prev = self.prev_contents
-                self.prev_contents = self.get_text()
-                
-                if prev != self.get_text():
-                        for mirror in self.mirrors:
-                                if not mirror.update(self):
-                                        return
-
-        def update_leave_mirrors(self):
-                # Notify mirrors
-                for mirror in self.leave_mirrors:
-                        if not mirror.update(self):
-                                return
-
-        # Do something on ending this placeholder
-        def leave(self):
-               self.update_leave_mirrors()
-
-        def find_mirrors(self, text, placeholders):
-                mirrors = []
-                
-                while (True):
-                        m = re.search('(\\\\)?\\$(?:{([0-9]+)}|([0-9]+))', text)
-                        
-                        if not m:
-                                break
-                        
-                        # Skip escaped mirrors
-                        if m.group(1):
-                                text = text[m.end():]
-                                continue
-
-                        tabstop = int(m.group(2) or m.group(3))
-
-                        if tabstop in placeholders:
-                                if not tabstop in mirrors:
-                                        mirrors.append(tabstop)
-
-                                text = text[m.end():]
-                        else:
-                                self.ok = False
-                                return None
-                
-                return mirrors 
-
-# This is an placeholder which inserts a mirror of another Placeholder        
+    def __init__(self, view, tabstop, defaults, begin):
+        self.ok = True
+        self.done = False
+        self.buf = view.get_buffer()
+        self.view = view
+        self.has_references = False
+        self.mirrors = []
+        self.leave_mirrors = []
+        self.tabstop = tabstop
+        self.set_default(defaults)
+        self.prev_contents = self.default
+        self.set_mark_gravity()
+
+        if begin:
+            self.begin = self.buf.create_mark(None, begin, self.mark_gravity[0])
+        else:
+            self.begin = None
+
+        self.end = None
+
+    def __str__(self):
+        return '%s (%s)' % (str(self.__class__), str(self.default))
+
+    def set_mark_gravity(self):
+        self.mark_gravity = [True, False]
+
+    def set_default(self, defaults):
+        self.default = None
+        self.defaults = []
+
+        if not defaults:
+            return
+
+        for d in defaults:
+            dm = self.expand_environment(d)
+
+            if dm:
+                self.defaults.append(dm)
+
+                if not self.default:
+                    self.default = dm
+
+                if dm != d:
+                    break
+
+    def literal(self, s):
+        return repr(s)
+
+    def format_environment(self, s):
+        return s
+
+    def re_environment(self, m):
+        if m.group(1) or not m.group(2) in os.environ:
+            return '$' + m.group(2)
+        else:
+            return self.format_environment(os.environ[m.group(2)])
+
+    def expand_environment(self, text):
+        if not text:
+            return text
+
+        return re.sub('(\\\\)?\\$([A-Z_]+)', self.re_environment, text)
+
+    def get_iter(self, mark):
+        if mark and not mark.get_deleted():
+            return self.buf.get_iter_at_mark(mark)
+        else:
+            return None
+
+    def begin_iter(self):
+        return self.get_iter(self.begin)
+
+    def end_iter(self):
+        return self.get_iter(self.end)
+
+    def run_last(self, placeholders):
+        begin = self.begin_iter()
+        self.end = self.buf.create_mark(None, begin, self.mark_gravity[1])
+
+        if self.default:
+            insert_with_indent(self.view, begin, self.default, False, self)
+
+    def remove(self, force = False):
+        if self.begin and not self.begin.get_deleted():
+            self.buf.delete_mark(self.begin)
+
+        if self.end and not self.end.get_deleted():
+            self.buf.delete_mark(self.end)
+
+    # Do something on beginning this placeholder
+    def enter(self):
+        if not self.begin or self.begin.get_deleted():
+            return
+
+        self.buf.move_mark(self.buf.get_insert(), self.begin_iter())
+
+        if self.end:
+            self.buf.move_mark(self.buf.get_selection_bound(), self.end_iter())
+        else:
+            self.buf.move_mark(self.buf.get_selection_bound(), self.begin_iter())
+
+    def get_text(self):
+        if self.begin and self.end:
+            biter = self.begin_iter()
+            eiter = self.end_iter()
+
+            if biter and eiter:
+                return self.buf.get_text(self.begin_iter(), self.end_iter(), False)
+            else:
+                return ''
+        else:
+            return ''
+
+    def add_mirror(self, mirror, onleave = False):
+        mirror.has_references = True
+
+        if onleave:
+            self.leave_mirrors.append(mirror)
+        else:
+            self.mirrors.append(mirror)
+
+    def set_text(self, text):
+        if self.begin.get_deleted() or self.end.get_deleted():
+            return
+
+        # Set from self.begin to self.end to text!
+        self.buf.begin_user_action()
+        # Remove everything between self.begin and self.end
+        begin = self.begin_iter()
+        self.buf.delete(begin, self.end_iter())
+
+        # Insert the text from the mirror
+        insert_with_indent(self.view, begin, text, True, self)
+        self.buf.end_user_action()
+
+        self.update_contents()
+
+    def update_contents(self):
+        prev = self.prev_contents
+        self.prev_contents = self.get_text()
+
+        if prev != self.get_text():
+            for mirror in self.mirrors:
+                if not mirror.update(self):
+                    return
+
+    def update_leave_mirrors(self):
+        # Notify mirrors
+        for mirror in self.leave_mirrors:
+            if not mirror.update(self):
+                return
+
+    # Do something on ending this placeholder
+    def leave(self):
+           self.update_leave_mirrors()
+
+    def find_mirrors(self, text, placeholders):
+        mirrors = []
+
+        while (True):
+            m = re.search('(\\\\)?\\$(?:{([0-9]+)}|([0-9]+))', text)
+
+            if not m:
+                break
+
+            # Skip escaped mirrors
+            if m.group(1):
+                text = text[m.end():]
+                continue
+
+            tabstop = int(m.group(2) or m.group(3))
+
+            if tabstop in placeholders:
+                if not tabstop in mirrors:
+                    mirrors.append(tabstop)
+
+                text = text[m.end():]
+            else:
+                self.ok = False
+                return None
+
+        return mirrors
+
+# This is an placeholder which inserts a mirror of another Placeholder
 class PlaceholderMirror(Placeholder):
-        def __init__(self, view, tabstop, begin):
-                Placeholder.__init__(self, view, -1, None, begin)
-                self.mirror_stop = tabstop
-
-        def update(self, mirror):
-                self.set_text(mirror.get_text())
-                return True
-
-        def run_last(self, placeholders):
-                Placeholder.run_last(self, placeholders)
-
-                if self.mirror_stop in placeholders:
-                        mirror = placeholders[self.mirror_stop]
-                        
-                        mirror.add_mirror(self)
-                        
-                        if mirror.default:
-                                self.set_text(mirror.default)
-                else:
-                        self.ok = False
+    def __init__(self, view, tabstop, begin):
+        Placeholder.__init__(self, view, -1, None, begin)
+        self.mirror_stop = tabstop
+
+    def update(self, mirror):
+        self.set_text(mirror.get_text())
+        return True
+
+    def run_last(self, placeholders):
+        Placeholder.run_last(self, placeholders)
+
+        if self.mirror_stop in placeholders:
+            mirror = placeholders[self.mirror_stop]
+
+            mirror.add_mirror(self)
+
+            if mirror.default:
+                self.set_text(mirror.default)
+        else:
+            self.ok = False
 
 # This placeholder indicates the end of a snippet
 class PlaceholderEnd(Placeholder):
-        def __init__(self, view, begin, default):
-                Placeholder.__init__(self, view, 0, default, begin)
-        
-        def run_last(self, placeholders):
-                Placeholder.run_last(self, placeholders)
-                
-                # Remove the begin mark and set the begin mark
-                # to the end mark, this is needed so the end placeholder won't contain
-                # any text
-                
-                if not self.default:
-                        self.mark_gravity[0] = False
-                        self.buf.delete_mark(self.begin)
-                        self.begin = self.buf.create_mark(None, self.end_iter(), self.mark_gravity[0])
-
-        def enter(self):
-                if self.begin and not self.begin.get_deleted():
-                        self.buf.move_mark(self.buf.get_insert(), self.begin_iter())
-                
-                if self.end and not self.end.get_deleted():
-                        self.buf.move_mark(self.buf.get_selection_bound(), self.end_iter())
-                
-        def leave(self):
-                self.enter()                        
-
-# This placeholder is used to expand a command with embedded mirrors        
+    def __init__(self, view, begin, default):
+        Placeholder.__init__(self, view, 0, default, begin)
+
+    def run_last(self, placeholders):
+        Placeholder.run_last(self, placeholders)
+
+        # Remove the begin mark and set the begin mark
+        # to the end mark, this is needed so the end placeholder won't contain
+        # any text
+
+        if not self.default:
+            self.mark_gravity[0] = False
+            self.buf.delete_mark(self.begin)
+            self.begin = self.buf.create_mark(None, self.end_iter(), self.mark_gravity[0])
+
+    def enter(self):
+        if self.begin and not self.begin.get_deleted():
+            self.buf.move_mark(self.buf.get_insert(), self.begin_iter())
+
+        if self.end and not self.end.get_deleted():
+            self.buf.move_mark(self.buf.get_selection_bound(), self.end_iter())
+
+    def leave(self):
+        self.enter()
+
+# This placeholder is used to expand a command with embedded mirrors
 class PlaceholderExpand(Placeholder):
-        def __init__(self, view, tabstop, begin, s):
-                Placeholder.__init__(self, view, tabstop, None, begin)
-
-                self.mirror_text = {0: ''}
-                self.timeout_id = None
-                self.cmd = s
-                self.instant_update = False
-
-        def __str__(self):
-                s = Placeholder.__str__(self)
-                
-                return s + ' ' + self.cmd
-
-        def get_mirrors(self, placeholders):
-                return self.find_mirrors(self.cmd, placeholders)
-                
-        # Check if all substitution placeholders are accounted for
-        def run_last(self, placeholders):
-                Placeholder.run_last(self, placeholders)
-
-                self.ok = True
-                mirrors = self.get_mirrors(placeholders)
-                
-                if mirrors:
-                        allDefault = True
-                                
-                        for mirror in mirrors:
-                                p = placeholders[mirror]
-                                p.add_mirror(self, not self.instant_update)
-                                self.mirror_text[p.tabstop] = p.default
-                                
-                                if not p.default and not isinstance(p, PlaceholderExpand):
-                                        allDefault = False
-                        
-                        if allDefault:
-                                self.update(None)
-                                self.default = self.get_text() or None
-                else:
-                        self.update(None)
-                        self.default = self.get_text() or None
-
-                        if self.tabstop == -1:
-                                self.done = True
-                
-        def re_placeholder(self, m, formatter):
-                if m.group(1):
-                        return '"$' + m.group(2) + '"'
-                else:
-                        if m.group(3):
-                                index = int(m.group(3))
-                        else:
-                                index = int(m.group(4))
-                        
-                        return formatter(self.mirror_text[index])
-
-        def remove_timeout(self):
-                if self.timeout_id != None:
-                        GLib.source_remove(self.timeout_id)
-                        self.timeout_id = None
-                
-        def install_timeout(self):
-                self.remove_timeout()
-                self.timeout_id = GLib.timeout_add(1000, self.timeout_cb)
+    def __init__(self, view, tabstop, begin, s):
+        Placeholder.__init__(self, view, tabstop, None, begin)
 
-        def timeout_cb(self):
-                self.timeout_id = None
-                
-                return False
-        
-        def format_environment(self, text):
-                return self.literal(text)
-
-        def substitute(self, text, formatter = None):
-                formatter = formatter or self.literal
-
-                # substitute all mirrors, but also environmental variables
-                text = re.sub('(\\\\)?\\$({([0-9]+)}|([0-9]+))', lambda m: self.re_placeholder(m, formatter), 
-                                text)
-                
-                return self.expand_environment(text)
-        
-        def run_update(self):
-                text = self.substitute(self.cmd)
-                
-                if text:
-                        ret = self.expand(text)
-                        
-                        if ret:
-                                self.update_leave_mirrors()
-                else:
-                        ret = True
-                
-                return ret
-              
-        def update(self, mirror):
-                text = None
-                
-                if mirror:
-                        self.mirror_text[mirror.tabstop] = mirror.get_text()
-                        
-                        # Check if all substitutions have been made
-                        for tabstop in self.mirror_text:
-                                if tabstop == 0:
-                                        continue
-
-                                if self.mirror_text[tabstop] == None:
-                                        return False
-
-                return self.run_update()
-
-        def expand(self, text):
-                return True
+        self.mirror_text = {0: ''}
+        self.timeout_id = None
+        self.cmd = s
+        self.instant_update = False
+
+    def __str__(self):
+        s = Placeholder.__str__(self)
+
+        return s + ' ' + self.cmd
+
+    def get_mirrors(self, placeholders):
+        return self.find_mirrors(self.cmd, placeholders)
+
+    # Check if all substitution placeholders are accounted for
+    def run_last(self, placeholders):
+        Placeholder.run_last(self, placeholders)
+
+        self.ok = True
+        mirrors = self.get_mirrors(placeholders)
+
+        if mirrors:
+            allDefault = True
+
+            for mirror in mirrors:
+                p = placeholders[mirror]
+                p.add_mirror(self, not self.instant_update)
+                self.mirror_text[p.tabstop] = p.default
+
+                if not p.default and not isinstance(p, PlaceholderExpand):
+                    allDefault = False
+
+            if allDefault:
+                self.update(None)
+                self.default = self.get_text() or None
+        else:
+            self.update(None)
+            self.default = self.get_text() or None
+
+            if self.tabstop == -1:
+                self.done = True
+
+    def re_placeholder(self, m, formatter):
+        if m.group(1):
+            return '"$' + m.group(2) + '"'
+        else:
+            if m.group(3):
+                index = int(m.group(3))
+            else:
+                index = int(m.group(4))
+
+            return formatter(self.mirror_text[index])
+
+    def remove_timeout(self):
+        if self.timeout_id != None:
+            GLib.source_remove(self.timeout_id)
+            self.timeout_id = None
+
+    def install_timeout(self):
+        self.remove_timeout()
+        self.timeout_id = GLib.timeout_add(1000, self.timeout_cb)
+
+    def timeout_cb(self):
+        self.timeout_id = None
+
+        return False
+
+    def format_environment(self, text):
+        return self.literal(text)
+
+    def substitute(self, text, formatter = None):
+        formatter = formatter or self.literal
+
+        # substitute all mirrors, but also environmental variables
+        text = re.sub('(\\\\)?\\$({([0-9]+)}|([0-9]+))', lambda m: self.re_placeholder(m, formatter),
+                text)
+
+        return self.expand_environment(text)
+
+    def run_update(self):
+        text = self.substitute(self.cmd)
+
+        if text:
+            ret = self.expand(text)
+
+            if ret:
+                self.update_leave_mirrors()
+        else:
+            ret = True
+
+        return ret
+
+    def update(self, mirror):
+        text = None
+
+        if mirror:
+            self.mirror_text[mirror.tabstop] = mirror.get_text()
+
+            # Check if all substitutions have been made
+            for tabstop in self.mirror_text:
+                if tabstop == 0:
+                    continue
+
+                if self.mirror_text[tabstop] == None:
+                    return False
+
+        return self.run_update()
+
+    def expand(self, text):
+        return True
 
 # The shell placeholder executes commands in a subshell
 class PlaceholderShell(PlaceholderExpand):
-        def __init__(self, view, tabstop, begin, s):
-                PlaceholderExpand.__init__(self, view, tabstop, begin, s)
-
-                self.shell = None
-                self.remove_me = False
-
-        def close_shell(self):
-                self.shell.stdout.close()
-                self.shell = None        
-        
-        def timeout_cb(self):
-                PlaceholderExpand.timeout_cb(self)
-                self.remove_timeout()
-                
-                if not self.shell:
-                        return False
+    def __init__(self, view, tabstop, begin, s):
+        PlaceholderExpand.__init__(self, view, tabstop, begin, s)
 
-                GLib.source_remove(self.watch_id)
-                self.close_shell()
+        self.shell = None
+        self.remove_me = False
 
-                if self.remove_me:
-                        PlaceholderExpand.remove(self)
+    def close_shell(self):
+        self.shell.stdout.close()
+        self.shell = None
 
-                message_dialog(None, Gtk.MessageType.ERROR, 'Execution of the shell ' \
-                                'command (%s) exceeded the maximum time; ' \
-                                'execution aborted.' % self.command)
-                
-                return False
-        
-        def process_close(self):
-                self.close_shell()
-                self.remove_timeout()
+    def timeout_cb(self):
+        PlaceholderExpand.timeout_cb(self)
+        self.remove_timeout()
 
-                self.set_text(str.join('', self.shell_output).rstrip('\n'))
-                
-                if self.default == None:
-                        self.default = self.get_text()
-                        self.leave()
-                        
-                if self.remove_me:
-                        PlaceholderExpand.remove(self, True)
-                
-        def process_cb(self, source, condition):
-                if condition & GObject.IO_IN:
-                        line = source.readline()
-
-                        if len(line) > 0:
-                                try:
-                                        line = unicode(line, 'utf-8')
-                                except:
-                                        line = unicode(line, locale.getdefaultlocale()[1], 
-                                                        'replace')
-
-                        self.shell_output += line
-                        self.install_timeout()
-
-                        return True
-
-                self.process_close()
-                return False
-        
-        def literal_replace(self, match):
-                return "\\%s" % (match.group(0))
-
-        def literal(self, text):
-                return '"' + re.sub('([\\\\"])', self.literal_replace, text) + '"'
-        
-        def expand(self, text):
+        if not self.shell:
+            return False
+
+        GLib.source_remove(self.watch_id)
+        self.close_shell()
+
+        if self.remove_me:
+            PlaceholderExpand.remove(self)
+
+        message_dialog(None, Gtk.MessageType.ERROR, 'Execution of the shell ' \
+                'command (%s) exceeded the maximum time; ' \
+                'execution aborted.' % self.command)
+
+        return False
+
+    def process_close(self):
+        self.close_shell()
+        self.remove_timeout()
+
+        self.set_text(str.join('', self.shell_output).rstrip('\n'))
+
+        if self.default == None:
+            self.default = self.get_text()
+            self.leave()
+
+        if self.remove_me:
+            PlaceholderExpand.remove(self, True)
+
+    def process_cb(self, source, condition):
+        if condition & GObject.IO_IN:
+            line = source.readline()
+
+            if len(line) > 0:
+                try:
+                    line = unicode(line, 'utf-8')
+                except:
+                    line = unicode(line, locale.getdefaultlocale()[1],
+                            'replace')
+
+            self.shell_output += line
+            self.install_timeout()
+
+            return True
+
+        self.process_close()
+        return False
+
+    def literal_replace(self, match):
+        return "\\%s" % (match.group(0))
+
+    def literal(self, text):
+        return '"' + re.sub('([\\\\"])', self.literal_replace, text) + '"'
+
+    def expand(self, text):
+        self.remove_timeout()
+
+        if self.shell:
+            GLib.source_remove(self.watch_id)
+            self.close_shell()
+
+        popen_args = {
+            'cwd'  : None,
+            'shell': True,
+            'env'  : os.environ,
+            'stdout': subprocess.PIPE
+        }
+
+        self.command = text
+        self.shell = subprocess.Popen(text, **popen_args)
+        self.shell_output = ''
+        self.watch_id = GLib.io_add_watch(self.shell.stdout, GObject.IO_IN | \
+                GObject.IO_HUP, self.process_cb)
+        self.install_timeout()
+
+        return True
+
+    def remove(self, force = False):
+        if not force and self.shell:
+            # Still executing shell command
+            self.remove_me = True
+        else:
+            if force:
                 self.remove_timeout()
 
                 if self.shell:
-                        GLib.source_remove(self.watch_id)
-                        self.close_shell()
-
-                popen_args = {
-                        'cwd'  : None,
-                        'shell': True,
-                        'env'  : os.environ,
-                        'stdout': subprocess.PIPE
-                }
-
-                self.command = text
-                self.shell = subprocess.Popen(text, **popen_args)
-                self.shell_output = ''
-                self.watch_id = GLib.io_add_watch(self.shell.stdout, GObject.IO_IN | \
-                                GObject.IO_HUP, self.process_cb)
-                self.install_timeout()
-                
-                return True
-                
-        def remove(self, force = False):
-                if not force and self.shell:
-                        # Still executing shell command
-                        self.remove_me = True
-                else:
-                        if force:
-                                self.remove_timeout()
-                                
-                                if self.shell:
-                                        self.close_shell()
-
-                        PlaceholderExpand.remove(self, force)
+                    self.close_shell()
+
+            PlaceholderExpand.remove(self, force)
 
 class TimeoutError(Exception):
-        def __init__(self, value):
-                self.value = value
-        
-        def __str__(self):
-                return repr(self.value)
+    def __init__(self, value):
+        self.value = value
+
+    def __str__(self):
+        return repr(self.value)
 
 # The python placeholder evaluates commands in python
 class PlaceholderEval(PlaceholderExpand):
-        def __init__(self, view, tabstop, refs, begin, s, namespace):
-                PlaceholderExpand.__init__(self, view, tabstop, begin, s)
-
-                self.fdread = 0
-                self.remove_me = False
-                self.namespace = namespace
-                
-                self.refs = []
-                
-                if refs:
-                        for ref in refs:
-                                self.refs.append(int(ref.strip()))
-
-        def get_mirrors(self, placeholders):
-                mirrors = PlaceholderExpand.get_mirrors(self, placeholders)
-
-                if not self.ok:
-                        return None
-
-                for ref in self.refs:
-                        if ref in placeholders:
-                                if ref not in mirrors:
-                                        mirrors.append(ref)
-                        else:
-                                self.ok = False
-                                return None
-
-                return mirrors
-
-        # SIGALRM is not supported on all platforms (e.g. windows). Timeout
-        # with SIGALRM will not be used on those platforms. This will
-        # potentially block pluma if you have a placeholder which gets stuck,
-        # but it's better than not supporting them at all. At some point we
-        # might have proper thread support and we can fix this in a better way
-        def timeout_supported(self):
-                return hasattr(signal, 'SIGALRM')
-
-        def timeout_cb(self, signum = 0, frame = 0):
-                raise TimeoutError, "Operation timed out (>2 seconds)"
-        
-        def install_timeout(self):
-                if not self.timeout_supported():
-                        return
-
-                if self.timeout_id != None:
-                        self.remove_timeout()
-                
-                self.timeout_id = signal.signal(signal.SIGALRM, self.timeout_cb)
-                signal.alarm(2)
-                
-        def remove_timeout(self):
-                if not self.timeout_supported():
-                        return
-
-                if self.timeout_id != None:
-                        signal.alarm(0)
-                        
-                        signal.signal(signal.SIGALRM, self.timeout_id)
-
-                        self.timeout_id = None
-                
-        def expand(self, text):
+    def __init__(self, view, tabstop, refs, begin, s, namespace):
+        PlaceholderExpand.__init__(self, view, tabstop, begin, s)
+
+        self.fdread = 0
+        self.remove_me = False
+        self.namespace = namespace
+
+        self.refs = []
+
+        if refs:
+            for ref in refs:
+                self.refs.append(int(ref.strip()))
+
+    def get_mirrors(self, placeholders):
+        mirrors = PlaceholderExpand.get_mirrors(self, placeholders)
+
+        if not self.ok:
+            return None
+
+        for ref in self.refs:
+            if ref in placeholders:
+                if ref not in mirrors:
+                    mirrors.append(ref)
+            else:
+                self.ok = False
+                return None
+
+        return mirrors
+
+    # SIGALRM is not supported on all platforms (e.g. windows). Timeout
+    # with SIGALRM will not be used on those platforms. This will
+    # potentially block pluma if you have a placeholder which gets stuck,
+    # but it's better than not supporting them at all. At some point we
+    # might have proper thread support and we can fix this in a better way
+    def timeout_supported(self):
+        return hasattr(signal, 'SIGALRM')
+
+    def timeout_cb(self, signum = 0, frame = 0):
+        raise TimeoutError, "Operation timed out (>2 seconds)"
+
+    def install_timeout(self):
+        if not self.timeout_supported():
+            return
+
+        if self.timeout_id != None:
+            self.remove_timeout()
+
+        self.timeout_id = signal.signal(signal.SIGALRM, self.timeout_cb)
+        signal.alarm(2)
+
+    def remove_timeout(self):
+        if not self.timeout_supported():
+            return
+
+        if self.timeout_id != None:
+            signal.alarm(0)
+
+            signal.signal(signal.SIGALRM, self.timeout_id)
+
+            self.timeout_id = None
+
+    def expand(self, text):
+        self.remove_timeout()
+
+        text = text.strip()
+        self.command = text
+
+        if not self.command or self.command == '':
+            self.set_text('')
+            return
+
+        text = "def process_snippet():\n\t" + "\n\t".join(text.split("\n"))
+
+        if 'process_snippet' in self.namespace:
+            del self.namespace['process_snippet']
+
+        try:
+            exec text in self.namespace
+        except:
+            traceback.print_exc()
+
+        if 'process_snippet' in self.namespace:
+            try:
+                # Install a sigalarm signal. This is a HACK to make sure
+                # pluma doesn't get freezed by someone creating a python
+                # placeholder which for instance loops indefinately. Since
+                # the code is executed synchronously it will hang pluma. With
+                # the alarm signal we raise an exception and catch this
+                # (see below). We show an error message and return False.
+                # ___this is a HACK___ and should be fixed properly (I just
+                # don't know how)
+                self.install_timeout()
+                result = self.namespace['process_snippet']()
+                self.remove_timeout()
+            except TimeoutError:
                 self.remove_timeout()
 
-                text = text.strip()
-                self.command = text
+                message_dialog(None, Gtk.MessageType.ERROR, \
+                _('Execution of the Python command (%s) exceeds the maximum ' \
+                'time, execution aborted.') % self.command)
 
-                if not self.command or self.command == '':
-                        self.set_text('')
-                        return
+                return False
+            except Exception, detail:
+                self.remove_timeout()
 
-                text = "def process_snippet():\n\t" + "\n\t".join(text.split("\n"))
-                
-                if 'process_snippet' in self.namespace:
-                        del self.namespace['process_snippet']
+                message_dialog(None, Gtk.MessageType.ERROR,
+                _('Execution of the Python command (%s) failed: %s') %
+                (self.command, detail))
 
-                try:
-                        exec text in self.namespace
-                except:
-                        traceback.print_exc()
-
-                if 'process_snippet' in self.namespace:
-                        try:
-                                # Install a sigalarm signal. This is a HACK to make sure 
-                                # pluma doesn't get freezed by someone creating a python
-                                # placeholder which for instance loops indefinately. Since
-                                # the code is executed synchronously it will hang pluma. With
-                                # the alarm signal we raise an exception and catch this
-                                # (see below). We show an error message and return False.
-                                # ___this is a HACK___ and should be fixed properly (I just 
-                                # don't know how)                                
-                                self.install_timeout()
-                                result = self.namespace['process_snippet']()
-                                self.remove_timeout()
-                        except TimeoutError:
-                                self.remove_timeout()
-
-                                message_dialog(None, Gtk.MessageType.ERROR, \
-                                _('Execution of the Python command (%s) exceeds the maximum ' \
-                                'time, execution aborted.') % self.command)
-                                
-                                return False
-                        except Exception, detail:
-                                self.remove_timeout()
-                                
-                                message_dialog(None, Gtk.MessageType.ERROR,
-                                _('Execution of the Python command (%s) failed: %s') % 
-                                (self.command, detail))
-
-                                return False
-
-                        if result == None:
-                                # sys.stderr.write("%s:\n>> %s\n" % (_('The following python code, run in a snippet, does not return a value'), "\n>> ".join(self.command.split("\n"))))
-                                result = ''
-
-                        self.set_text(str(result))
-                
-                return True
+                return False
+
+            if result == None:
+                # sys.stderr.write("%s:\n>> %s\n" % (_('The following python code, run in a snippet, does not return a value'), "\n>> ".join(self.command.split("\n"))))
+                result = ''
+
+            self.set_text(str(result))
+
+        return True
 
 # Regular expression placeholder
 class PlaceholderRegex(PlaceholderExpand):
-        def __init__(self, view, tabstop, begin, inp, pattern, substitution, modifiers):
-                PlaceholderExpand.__init__(self, view, tabstop, begin, '')
-                
-                self.instant_update = True
-                self.inp = inp
-                self.pattern = pattern
-                self.substitution = substitution
-                
-                self.init_modifiers(modifiers)
-        
-        def init_modifiers(self, modifiers):
-                mods = {'I': re.I,
-                        'L': re.L,
-                        'M': re.M,
-                        'S': re.S,
-                        'U': re.U,
-                        'X': re.X}
-                
-                self.modifiers = 0
-
-                for modifier in modifiers:
-                        if modifier in mods:
-                                self.modifiers |= mods[modifier]
-
-        def get_mirrors(self, placeholders):
-                mirrors = self.find_mirrors(self.pattern, placeholders) + self.find_mirrors(self.substitution, placeholders)
-
-                if isinstance(self.inp, int):
-                        if self.inp not in placeholders:
-                                self.ok = False
-                                return None
-                        elif self.inp not in mirrors:
-                                mirrors.append(self.inp)
-
-                return mirrors
-
-        def literal(self, s):
-                return re.escape(s)
-
-        def get_input(self):
-                if isinstance(self.inp, int):
-                        return self.mirror_text[self.inp]
-                elif self.inp in os.environ:
-                        return os.environ[self.inp]
-                else:
-                        return ''
-        
-        def run_update(self):
-                pattern = self.substitute(self.pattern)
-                substitution = self.substitute(self.substitution, SubstitutionParser.escape_substitution)
-                
-                if pattern:
-                        return self.expand(pattern, substitution)
-                
-                return True
-        
-        def expand(self, pattern, substitution):
-                # Try to compile pattern
-                try:
-                        regex = re.compile(pattern, self.modifiers)
-                except re.error, message:
-                        sys.stderr.write('Could not compile regular expression: %s\n%s\n' % (pattern, message))
-                        return False
-                
-                inp = self.get_input()
-                match = regex.search(inp)
-                
-                if not match:
-                        self.set_text(inp)
-                else:
-                        groups = match.groupdict()
-                        
-                        idx = 0
-                        for group in match.groups():
-                                groups[str(idx + 1)] = group
-                                idx += 1
-
-                        groups['0'] = match.group(0)
-
-                        parser = SubstitutionParser(substitution, groups)
-                        self.set_text(parser.parse())
-                
-                return True
-# ex:ts=8:et:
+    def __init__(self, view, tabstop, begin, inp, pattern, substitution, modifiers):
+        PlaceholderExpand.__init__(self, view, tabstop, begin, '')
+
+        self.instant_update = True
+        self.inp = inp
+        self.pattern = pattern
+        self.substitution = substitution
+
+        self.init_modifiers(modifiers)
+
+    def init_modifiers(self, modifiers):
+        mods = {'I': re.I,
+            'L': re.L,
+            'M': re.M,
+            'S': re.S,
+            'U': re.U,
+            'X': re.X}
+
+        self.modifiers = 0
+
+        for modifier in modifiers:
+            if modifier in mods:
+                self.modifiers |= mods[modifier]
+
+    def get_mirrors(self, placeholders):
+        mirrors = self.find_mirrors(self.pattern, placeholders) + self.find_mirrors(self.substitution, placeholders)
+
+        if isinstance(self.inp, int):
+            if self.inp not in placeholders:
+                self.ok = False
+                return None
+            elif self.inp not in mirrors:
+                mirrors.append(self.inp)
+
+        return mirrors
+
+    def literal(self, s):
+        return re.escape(s)
+
+    def get_input(self):
+        if isinstance(self.inp, int):
+            return self.mirror_text[self.inp]
+        elif self.inp in os.environ:
+            return os.environ[self.inp]
+        else:
+            return ''
+
+    def run_update(self):
+        pattern = self.substitute(self.pattern)
+        substitution = self.substitute(self.substitution, SubstitutionParser.escape_substitution)
+
+        if pattern:
+            return self.expand(pattern, substitution)
+
+        return True
+
+    def expand(self, pattern, substitution):
+        # Try to compile pattern
+        try:
+            regex = re.compile(pattern, self.modifiers)
+        except re.error, message:
+            sys.stderr.write('Could not compile regular expression: %s\n%s\n' % (pattern, message))
+            return False
+
+        inp = self.get_input()
+        match = regex.search(inp)
+
+        if not match:
+            self.set_text(inp)
+        else:
+            groups = match.groupdict()
+
+            idx = 0
+            for group in match.groups():
+                groups[str(idx + 1)] = group
+                idx += 1
+
+            groups['0'] = match.group(0)
+
+            parser = SubstitutionParser(substitution, groups)
+            self.set_text(parser.parse())
+
+        return True
+
+# ex:ts=4:et:
diff --git a/plugins/snippets/snippets/Snippet.py b/plugins/snippets/snippets/Snippet.py
old mode 100755
new mode 100644
index 2d7f67d..192b036
--- a/plugins/snippets/snippets/Snippet.py
+++ b/plugins/snippets/snippets/Snippet.py
@@ -23,333 +23,334 @@ from Parser import Parser, Token
 from Helper import *
 
 class EvalUtilities:
-        def __init__(self, view=None):
-                self.view = view
-                self._init_namespace()
-        
-        def _init_namespace(self):
-                self.namespace = {
-                        '__builtins__': __builtins__,
-                        'align': self.util_align,
-                        'readfile': self.util_readfile,
-                        'filesize': self.util_filesize
-                }
-
-        def _real_len(self, s, tablen = 0):
-                if tablen == 0:
-                        tablen = self.view.get_tab_width()
-
-                return len(s.expandtabs(tablen))
-
-        def _filename_to_uri(self, filename):
-                gfile = Gio.file_new_for_path(filename)
-
-                return gfile.get_uri()
-
-        def util_readfile(self, filename):
-                stream = Gio.file_new_for_path(filename).read()
-                
-                if not stream:
-                        return ''
-                
-                res = stream.read()
-                stream.close()
-                
-                return res
-
-        def util_filesize(self, filename):
-                gfile = Gio.file_new_for_path(filename)
-                info = gfile.query_info(Gio.FILE_ATTRIBUTE_STANDARD_SIZE)
-                
-                if not info:
-                        return 0
-                
-                return info.get_size()
-
-        def util_align(self, items):
-                maxlen = []
-                tablen = self.view.get_tab_width()
-
-                for row in range(0, len(items)):
-                        for col in range(0, len(items[row]) - 1):
-                                if row == 0:
-                                        maxlen.append(0)
-                                
-                                items[row][col] += "\t"
-                                rl = self._real_len(items[row][col], tablen)
-                                
-                                if (rl > maxlen[col]):
-                                        maxlen[col] = rl
-
-                result = ''
-                
-                for row in range(0, len(items)):
-                        for col in range(0, len(items[row]) - 1):
-                                item = items[row][col]
-                                
-                                result += item + ("\t" * ((maxlen[col] - \
-                                                self._real_len(item, tablen)) / tablen))
-                        
-                        result += items[row][len(items[row]) - 1]
-                        
-                        if row != len(items) - 1:
-                                result += "\n"
-                
-                return result
+    def __init__(self, view=None):
+        self.view = view
+        self._init_namespace()
+
+    def _init_namespace(self):
+        self.namespace = {
+            '__builtins__': __builtins__,
+            'align': self.util_align,
+            'readfile': self.util_readfile,
+            'filesize': self.util_filesize
+        }
+
+    def _real_len(self, s, tablen = 0):
+        if tablen == 0:
+            tablen = self.view.get_tab_width()
+
+        return len(s.expandtabs(tablen))
+
+    def _filename_to_uri(self, filename):
+        gfile = Gio.file_new_for_path(filename)
+
+        return gfile.get_uri()
+
+    def util_readfile(self, filename):
+        stream = Gio.file_new_for_path(filename).read()
+
+        if not stream:
+            return ''
+
+        res = stream.read()
+        stream.close()
+
+        return res
+
+    def util_filesize(self, filename):
+        gfile = Gio.file_new_for_path(filename)
+        info = gfile.query_info(Gio.FILE_ATTRIBUTE_STANDARD_SIZE)
+
+        if not info:
+            return 0
+
+        return info.get_size()
+
+    def util_align(self, items):
+        maxlen = []
+        tablen = self.view.get_tab_width()
+
+        for row in range(0, len(items)):
+            for col in range(0, len(items[row]) - 1):
+                if row == 0:
+                    maxlen.append(0)
+
+                items[row][col] += "\t"
+                rl = self._real_len(items[row][col], tablen)
+
+                if (rl > maxlen[col]):
+                    maxlen[col] = rl
+
+        result = ''
+
+        for row in range(0, len(items)):
+            for col in range(0, len(items[row]) - 1):
+                item = items[row][col]
+
+                result += item + ("\t" * ((maxlen[col] - \
+                        self._real_len(item, tablen)) / tablen))
+
+            result += items[row][len(items[row]) - 1]
+
+            if row != len(items) - 1:
+                result += "\n"
+
+        return result
 
 class Snippet:
-        def __init__(self, data):
-                self.data = data
-        
-        def __getitem__(self, prop):
-                return self.data[prop]
-        
-        def __setitem__(self, prop, value):
-                self.data[prop] = value
-        
-        def accelerator_display(self):
-                accel = self['accelerator']
-
-                if accel:
-                        keyval, mod = Gtk.accelerator_parse(accel)
-                        accel = Gtk.accelerator_get_label(keyval, mod)
-                
-                return accel or ''
-
-        def display(self):
-                nm = markup_escape(self['description'])
-                
-                tag = self['tag']
-                accel = self.accelerator_display()
-                detail = []
-                
-                if tag and tag != '':
-                        detail.append(tag)
-                        
-                if accel and accel != '':
-                        detail.append(accel)
-                
-                if not detail:
-                        return nm
-                else:
-                        return nm + ' (<b>' + markup_escape(str.join(', ', detail)) + \
-                                        '</b>)'
-
-        def _add_placeholder(self, placeholder):
-                if placeholder.tabstop in self.placeholders:
-                        if placeholder.tabstop == -1:
-                                self.placeholders[-1].append(placeholder)
-                                self.plugin_data.ordered_placeholders.append(placeholder)
-                elif placeholder.tabstop == -1:
-                        self.placeholders[-1] = [placeholder]
-                        self.plugin_data.ordered_placeholders.append(placeholder)
-                else:
-                        self.placeholders[placeholder.tabstop] = placeholder
-                        self.plugin_data.ordered_placeholders.append(placeholder)
-
-        def _insert_text(self, text):
-                # Insert text keeping indentation in mind
-                indented = unicode.join('\n' + unicode(self._indent), spaces_instead_of_tabs(self._view, text).split('\n'))
-                self._view.get_buffer().insert(self._insert_iter(), indented)
-
-        def _insert_iter(self):
-                return self._view.get_buffer().get_iter_at_mark(self._insert_mark)
-                
-        def _create_environment(self, data):
-                val = ((data in os.environ) and os.environ[data]) or ''
-                
-                # Get all the current indentation
-                all_indent = compute_indentation(self._view, self._insert_iter())
-                
-                # Substract initial indentation to get the snippet indentation
-                indent = all_indent[len(self._indent):]
-
-                # Keep indentation
-                return unicode.join('\n' + unicode(indent), val.split('\n'))
-        
-        def _create_placeholder(self, data):
-                tabstop = data['tabstop']
-                begin = self._insert_iter()
-                
-                if tabstop == 0:
-                        # End placeholder
-                        return PlaceholderEnd(self._view, begin, data['default'])
-                elif tabstop in self.placeholders:
-                        # Mirror placeholder
-                        return PlaceholderMirror(self._view, tabstop, begin)
-                else:
-                        # Default placeholder
-                        return Placeholder(self._view, tabstop, data['default'], begin)
-
-        def _create_shell(self, data):
-                begin = self._insert_iter()
-                return PlaceholderShell(self._view, data['tabstop'], begin, data['contents'])
-
-        def _create_eval(self, data):
-                begin = self._insert_iter()
-                return PlaceholderEval(self._view, data['tabstop'], data['dependencies'], begin, data['contents'], self._utils.namespace)
-        
-        def _create_regex(self, data):
-                begin = self._insert_iter()
-                return PlaceholderRegex(self._view, data['tabstop'], begin, data['input'], data['pattern'], data['substitution'], data['modifiers'])
-                
-        def _create_text(self, data):
-                return data
-
-        def _invalid_placeholder(self, placeholder, remove):
-                buf = self._view.get_buffer()
-              
-                # Remove the text because this placeholder is invalid
-                if placeholder.default and remove:
-                        buf.delete(placeholder.begin_iter(), placeholder.end_iter())
-                
-                placeholder.remove()
-
-                if placeholder.tabstop == -1:
-                        index = self.placeholders[-1].index(placeholder)
-                        del self.placeholders[-1][index]
-                else:
-                        del self.placeholders[placeholder.tabstop]
-                
-                self.plugin_data.ordered_placeholders.remove(placeholder)
-
-        def _parse(self, plugin_data):
-                # Initialize current variables
-                self._view = plugin_data.view
-                self._indent = compute_indentation(self._view, self._view.get_buffer().get_iter_at_mark(self.begin_mark))        
-                self._utils = EvalUtilities(self._view)
-                self.placeholders = {}
-                self._insert_mark = self.end_mark
-                self.plugin_data = plugin_data
-                
-                # Create parser
-                parser = Parser(data=self['text'])
-
-                # Parse tokens
-                while (True):
-                        token = parser.token()
-                        
-                        if not token:
-                                break
-
-                        try:
-                                val = {'environment': self._create_environment,
-                                        'placeholder': self._create_placeholder,
-                                        'shell': self._create_shell,
-                                        'eval': self._create_eval,
-                                        'regex': self._create_regex,
-                                        'text': self._create_text}[token.klass](token.data)
-                        except:
-                                sys.stderr.write('Token class not supported: %s\n' % token.klass)
-                                continue
-                        
-                        if isinstance(val, basestring):
-                                # Insert text
-                                self._insert_text(val)
-                        else:
-                                # Insert placeholder
-                                self._add_placeholder(val)
-
-                # Create end placeholder if there isn't one yet
-                if 0 not in self.placeholders:
-                        self.placeholders[0] = PlaceholderEnd(self._view, self.end_iter(), None)
-                        self.plugin_data.ordered_placeholders.append(self.placeholders[0])
-
-                # Make sure run_last is ran for all placeholders and remove any
-                # non `ok` placeholders
-                for tabstop in self.placeholders.copy():
-                        ph = (tabstop == -1 and list(self.placeholders[-1])) or [self.placeholders[tabstop]]
-
-                        for placeholder in ph:
-                                placeholder.run_last(self.placeholders)
-                                
-                                if not placeholder.ok or placeholder.done:
-                                        self._invalid_placeholder(placeholder, not placeholder.ok)
-
-                # Remove all the Expand placeholders which have a tabstop because
-                # they can be used to mirror, but they shouldn't be real tabstops
-                # (if they have mirrors installed). This is problably a bit of 
-                # a dirty hack :)
-                if -1 not in self.placeholders:
-                        self.placeholders[-1] = []
-
-                for tabstop in self.placeholders.copy():
-                        placeholder = self.placeholders[tabstop]
-
-                        if tabstop != -1:
-                                if isinstance(placeholder, PlaceholderExpand) and \
-                                   placeholder.has_references:
-                                        # Add to anonymous placeholders
-                                        self.placeholders[-1].append(placeholder)
-                                        
-                                        # Remove placeholder
-                                        del self.placeholders[tabstop]
-        
-                self.plugin_data = None
-
-        def insert_into(self, plugin_data, insert):
-                buf = plugin_data.view.get_buffer()
-                last_index = 0
-                
-                # Find closest mark at current insertion, so that we may insert
-                # our marks in the correct order
-                (current, next) = plugin_data.next_placeholder()
-                
-                if current:
-                        # Insert AFTER current
-                        last_index = plugin_data.placeholders.index(current) + 1
-                elif next:
-                        # Insert BEFORE next
-                        last_index = plugin_data.placeholders.index(next)
-                else:
-                        # Insert at first position
-                        last_index = 0
-                
-                # lastIndex now contains the position of the last mark
-                # Create snippet bounding marks
-                self.begin_mark = buf.create_mark(None, insert, True)
-                self.end_mark = buf.create_mark(None, insert, False)
-                
-                # Now parse the contents of this snippet, create Placeholders
-                # and insert the placholder marks in the marks array of plugin_data
-                self._parse(plugin_data)
-                
-                # So now all of the snippet is in the buffer, we have all our 
-                # placeholders right here, what's next, put all marks in the 
-                # plugin_data.marks
-                k = self.placeholders.keys()
-                k.sort(reverse=True)
-                
-                plugin_data.placeholders.insert(last_index, self.placeholders[0])
-                last_iter = self.placeholders[0].end_iter()
-                
-                for tabstop in k:
-                        if tabstop != -1 and tabstop != 0:
-                                placeholder = self.placeholders[tabstop]
-                                end_iter = placeholder.end_iter()
-                                
-                                if last_iter.compare(end_iter) < 0:
-                                        last_iter = end_iter
-                                
-                                # Inserting placeholder
-                                plugin_data.placeholders.insert(last_index, placeholder)
-                
-                # Move end mark to last placeholder
-                buf.move_mark(self.end_mark, last_iter)
-
-                return self
-                
-        def deactivate(self):
-                buf = self.begin_mark.get_buffer()
-                
-                buf.delete_mark(self.begin_mark)
-                buf.delete_mark(self.end_mark)
-                
-                self.placeholders = {}
-        
-        def begin_iter(self):
-                return self.begin_mark.get_buffer().get_iter_at_mark(self.begin_mark)
-        
-        def end_iter(self):
-                return self.end_mark.get_buffer().get_iter_at_mark(self.end_mark)
-# ex:ts=8:et:
+    def __init__(self, data):
+        self.data = data
+
+    def __getitem__(self, prop):
+        return self.data[prop]
+
+    def __setitem__(self, prop, value):
+        self.data[prop] = value
+
+    def accelerator_display(self):
+        accel = self['accelerator']
+
+        if accel:
+            keyval, mod = Gtk.accelerator_parse(accel)
+            accel = Gtk.accelerator_get_label(keyval, mod)
+
+        return accel or ''
+
+    def display(self):
+        nm = markup_escape(self['description'])
+
+        tag = self['tag']
+        accel = self.accelerator_display()
+        detail = []
+
+        if tag and tag != '':
+            detail.append(tag)
+
+        if accel and accel != '':
+            detail.append(accel)
+
+        if not detail:
+            return nm
+        else:
+            return nm + ' (<b>' + markup_escape(str.join(', ', detail)) + \
+                    '</b>)'
+
+    def _add_placeholder(self, placeholder):
+        if placeholder.tabstop in self.placeholders:
+            if placeholder.tabstop == -1:
+                self.placeholders[-1].append(placeholder)
+                self.plugin_data.ordered_placeholders.append(placeholder)
+        elif placeholder.tabstop == -1:
+            self.placeholders[-1] = [placeholder]
+            self.plugin_data.ordered_placeholders.append(placeholder)
+        else:
+            self.placeholders[placeholder.tabstop] = placeholder
+            self.plugin_data.ordered_placeholders.append(placeholder)
+
+    def _insert_text(self, text):
+        # Insert text keeping indentation in mind
+        indented = unicode.join('\n' + unicode(self._indent), spaces_instead_of_tabs(self._view, text).split('\n'))
+        self._view.get_buffer().insert(self._insert_iter(), indented)
+
+    def _insert_iter(self):
+        return self._view.get_buffer().get_iter_at_mark(self._insert_mark)
+
+    def _create_environment(self, data):
+        val = ((data in os.environ) and os.environ[data]) or ''
+
+        # Get all the current indentation
+        all_indent = compute_indentation(self._view, self._insert_iter())
+
+        # Substract initial indentation to get the snippet indentation
+        indent = all_indent[len(self._indent):]
+
+        # Keep indentation
+        return unicode.join('\n' + unicode(indent), val.split('\n'))
+
+    def _create_placeholder(self, data):
+        tabstop = data['tabstop']
+        begin = self._insert_iter()
+
+        if tabstop == 0:
+            # End placeholder
+            return PlaceholderEnd(self._view, begin, data['default'])
+        elif tabstop in self.placeholders:
+            # Mirror placeholder
+            return PlaceholderMirror(self._view, tabstop, begin)
+        else:
+            # Default placeholder
+            return Placeholder(self._view, tabstop, data['default'], begin)
+
+    def _create_shell(self, data):
+        begin = self._insert_iter()
+        return PlaceholderShell(self._view, data['tabstop'], begin, data['contents'])
+
+    def _create_eval(self, data):
+        begin = self._insert_iter()
+        return PlaceholderEval(self._view, data['tabstop'], data['dependencies'], begin, data['contents'], self._utils.namespace)
+
+    def _create_regex(self, data):
+        begin = self._insert_iter()
+        return PlaceholderRegex(self._view, data['tabstop'], begin, data['input'], data['pattern'], data['substitution'], data['modifiers'])
+
+    def _create_text(self, data):
+        return data
+
+    def _invalid_placeholder(self, placeholder, remove):
+        buf = self._view.get_buffer()
+
+        # Remove the text because this placeholder is invalid
+        if placeholder.default and remove:
+            buf.delete(placeholder.begin_iter(), placeholder.end_iter())
+
+        placeholder.remove()
+
+        if placeholder.tabstop == -1:
+            index = self.placeholders[-1].index(placeholder)
+            del self.placeholders[-1][index]
+        else:
+            del self.placeholders[placeholder.tabstop]
+
+        self.plugin_data.ordered_placeholders.remove(placeholder)
+
+    def _parse(self, plugin_data):
+        # Initialize current variables
+        self._view = plugin_data.view
+        self._indent = compute_indentation(self._view, self._view.get_buffer().get_iter_at_mark(self.begin_mark))
+        self._utils = EvalUtilities(self._view)
+        self.placeholders = {}
+        self._insert_mark = self.end_mark
+        self.plugin_data = plugin_data
+
+        # Create parser
+        parser = Parser(data=self['text'])
+
+        # Parse tokens
+        while (True):
+            token = parser.token()
+
+            if not token:
+                break
+
+            try:
+                val = {'environment': self._create_environment,
+                    'placeholder': self._create_placeholder,
+                    'shell': self._create_shell,
+                    'eval': self._create_eval,
+                    'regex': self._create_regex,
+                    'text': self._create_text}[token.klass](token.data)
+            except:
+                sys.stderr.write('Token class not supported: %s\n' % token.klass)
+                continue
+
+            if isinstance(val, basestring):
+                # Insert text
+                self._insert_text(val)
+            else:
+                # Insert placeholder
+                self._add_placeholder(val)
+
+        # Create end placeholder if there isn't one yet
+        if 0 not in self.placeholders:
+            self.placeholders[0] = PlaceholderEnd(self._view, self.end_iter(), None)
+            self.plugin_data.ordered_placeholders.append(self.placeholders[0])
+
+        # Make sure run_last is ran for all placeholders and remove any
+        # non `ok` placeholders
+        for tabstop in self.placeholders.copy():
+            ph = (tabstop == -1 and list(self.placeholders[-1])) or [self.placeholders[tabstop]]
+
+            for placeholder in ph:
+                placeholder.run_last(self.placeholders)
+
+                if not placeholder.ok or placeholder.done:
+                    self._invalid_placeholder(placeholder, not placeholder.ok)
+
+        # Remove all the Expand placeholders which have a tabstop because
+        # they can be used to mirror, but they shouldn't be real tabstops
+        # (if they have mirrors installed). This is problably a bit of
+        # a dirty hack :)
+        if -1 not in self.placeholders:
+            self.placeholders[-1] = []
+
+        for tabstop in self.placeholders.copy():
+            placeholder = self.placeholders[tabstop]
+
+            if tabstop != -1:
+                if isinstance(placeholder, PlaceholderExpand) and \
+                   placeholder.has_references:
+                    # Add to anonymous placeholders
+                    self.placeholders[-1].append(placeholder)
+
+                    # Remove placeholder
+                    del self.placeholders[tabstop]
+
+        self.plugin_data = None
+
+    def insert_into(self, plugin_data, insert):
+        buf = plugin_data.view.get_buffer()
+        last_index = 0
+
+        # Find closest mark at current insertion, so that we may insert
+        # our marks in the correct order
+        (current, next) = plugin_data.next_placeholder()
+
+        if current:
+            # Insert AFTER current
+            last_index = plugin_data.placeholders.index(current) + 1
+        elif next:
+            # Insert BEFORE next
+            last_index = plugin_data.placeholders.index(next)
+        else:
+            # Insert at first position
+            last_index = 0
+
+        # lastIndex now contains the position of the last mark
+        # Create snippet bounding marks
+        self.begin_mark = buf.create_mark(None, insert, True)
+        self.end_mark = buf.create_mark(None, insert, False)
+
+        # Now parse the contents of this snippet, create Placeholders
+        # and insert the placholder marks in the marks array of plugin_data
+        self._parse(plugin_data)
+
+        # So now all of the snippet is in the buffer, we have all our
+        # placeholders right here, what's next, put all marks in the
+        # plugin_data.marks
+        k = self.placeholders.keys()
+        k.sort(reverse=True)
+
+        plugin_data.placeholders.insert(last_index, self.placeholders[0])
+        last_iter = self.placeholders[0].end_iter()
+
+        for tabstop in k:
+            if tabstop != -1 and tabstop != 0:
+                placeholder = self.placeholders[tabstop]
+                end_iter = placeholder.end_iter()
+
+                if last_iter.compare(end_iter) < 0:
+                    last_iter = end_iter
+
+                # Inserting placeholder
+                plugin_data.placeholders.insert(last_index, placeholder)
+
+        # Move end mark to last placeholder
+        buf.move_mark(self.end_mark, last_iter)
+
+        return self
+
+    def deactivate(self):
+        buf = self.begin_mark.get_buffer()
+
+        buf.delete_mark(self.begin_mark)
+        buf.delete_mark(self.end_mark)
+
+        self.placeholders = {}
+
+    def begin_iter(self):
+        return self.begin_mark.get_buffer().get_iter_at_mark(self.begin_mark)
+
+    def end_iter(self):
+        return self.end_mark.get_buffer().get_iter_at_mark(self.end_mark)
+
+# ex:ts=4:et:
diff --git a/plugins/snippets/snippets/SubstitutionParser.py b/plugins/snippets/snippets/SubstitutionParser.py
old mode 100755
new mode 100644
index a41f5a6..246f4da
--- a/plugins/snippets/snippets/SubstitutionParser.py
+++ b/plugins/snippets/snippets/SubstitutionParser.py
@@ -18,185 +18,185 @@
 import re
 
 class ParseError(Exception):
-        def __str__(self):
-                return 'Parse error, resume next'
+    def __str__(self):
+        return 'Parse error, resume next'
 
 class Modifiers:
-        def _first_char(s):
-                first = (s != '' and s[0]) or ''
-                rest = (len(s) > 1 and s[1:]) or ''
-                
-                return first, rest
-        
-        def upper_first(s):
-                first, rest = Modifiers._first_char(s)
-
-                return '%s%s' % (first.upper(), rest)
-
-        def upper(s):
-                return s.upper()
-
-        def lower_first(s):
-                first, rest = Modifiers._first_char(s)
-
-                return '%s%s' % (first.lower(), rest)
-                
-        def lower(s):
-                return s.lower()
-                
-        def title(s):
-                return s.title()
-        
-        upper_first = staticmethod(upper_first)
-        upper = staticmethod(upper)
-        lower_first = staticmethod(lower_first)
-        lower = staticmethod(lower)
-        title = staticmethod(title)
-        _first_char = staticmethod(_first_char)
+    def _first_char(s):
+        first = (s != '' and s[0]) or ''
+        rest = (len(s) > 1 and s[1:]) or ''
+
+        return first, rest
+
+    def upper_first(s):
+        first, rest = Modifiers._first_char(s)
+
+        return '%s%s' % (first.upper(), rest)
+
+    def upper(s):
+        return s.upper()
+
+    def lower_first(s):
+        first, rest = Modifiers._first_char(s)
+
+        return '%s%s' % (first.lower(), rest)
+
+    def lower(s):
+        return s.lower()
+
+    def title(s):
+        return s.title()
+
+    upper_first = staticmethod(upper_first)
+    upper = staticmethod(upper)
+    lower_first = staticmethod(lower_first)
+    lower = staticmethod(lower)
+    title = staticmethod(title)
+    _first_char = staticmethod(_first_char)
 
 class SubstitutionParser:
-        REG_ID = '[0-9]+'
-        REG_NAME = '[a-zA-Z_]+'
-        REG_MOD = '[a-zA-Z]+'
-        REG_ESCAPE = '\\\\|\\(\\?|,|\\)'
-
-        def __init__(self, pattern, groups = {}, modifiers = {}):
-                self.pattern = pattern
-                self.groups = groups
-                
-                self.REG_GROUP = '(?:(%s)|<(%s|%s)(?:,(%s))?>)' % (self.REG_ID, self.REG_ID, self.REG_NAME, self.REG_MOD)
-                self.modifiers = {'u': Modifiers.upper_first,
-                                  'U': Modifiers.upper,
-                                  'l': Modifiers.lower_first,
-                                  'L': Modifiers.lower,
-                                  't': Modifiers.title}
-                
-                for k, v in modifiers.items():
-                        self.modifiers[k] = v
-        
-        def parse(self):
-                result, tokens = self._parse(self.pattern, None)
-                
-                return result
-        
-        def _parse(self, tokens, terminator):
-                result = ''
-
-                while tokens != '':
-                        if self._peek(tokens) == '' or self._peek(tokens) == terminator:
-                                tokens = self._remains(tokens)
-                                break
-
-                        try:
-                                res, tokens = self._expr(tokens, terminator)
-                        except ParseError:
-                                res, tokens = self._text(tokens)
-                        
-                        result += res
-                                
-                return result, tokens
-       
-        def _peek(self, tokens, num = 0):
-                return (num < len(tokens) and tokens[num])
-        
-        def _token(self, tokens):
-                if tokens == '':
-                        return '', '';
-
-                return tokens[0], (len(tokens) > 1 and tokens[1:]) or ''
-        
-        def _remains(self, tokens, num = 1):
-                return (num < len(tokens) and tokens[num:]) or ''
-
-        def _expr(self, tokens, terminator):                
-                if tokens == '':
-                        return ''
-
-                try:
-                        return {'\\': self._escape,
-                                '(': self._condition}[self._peek(tokens)](tokens, terminator)
-                except KeyError:
-                        raise ParseError
-
-        def _text(self, tokens):
-                return self._token(tokens)
-
-        def _substitute(self, group, modifiers = ''):
-                result = (self.groups.has_key(group) and self.groups[group]) or ''
-                
-                for modifier in modifiers:
-                        if self.modifiers.has_key(modifier):
-                                result = self.modifiers[modifier](result)
-                
-                return result
-                
-        def _match_group(self, tokens):
-                match = re.match('\\\\%s' % self.REG_GROUP, tokens)
-                
-                if not match:
-                        return None, tokens
-                
-                return self._substitute(match.group(1) or match.group(2), match.group(3) or ''), tokens[match.end():]
-                
-        def _escape(self, tokens, terminator):
-                # Try to match a group
-                result, tokens = self._match_group(tokens)
-                
-                if result != None:
-                        return result, tokens
-                
-                s = self.REG_GROUP
-                
-                if terminator:
-                        s += '|%s' % re.escape(terminator)
-
-                match = re.match('\\\\(\\\\%s|%s)' % (s, self.REG_ESCAPE), tokens)
-
-                if not match:
-                        raise ParseError
-                               
-                return match.group(1), tokens[match.end():]  
-        
-        def _condition_value(self, tokens):
-                match = re.match('\\\\?%s\s*' % self.REG_GROUP, tokens)
-                
-                if not match:
-                        return None, tokens
-
-                groups = match.groups()
-                name = groups[0] or groups[1]
-
-                return self.groups.has_key(name) and self.groups[name] != None, tokens[match.end():]        
-        
-        def _condition(self, tokens, terminator):
-                # Match ? after (
-                if self._peek(tokens, 1) != '?':
-                        raise ParseError
-               
-                # Remove initial (? token
-                tokens = self._remains(tokens, 2)
-                condition, tokens = self._condition_value(tokens)
-                
-                if condition == None or self._peek(tokens) != ',':
-                        raise ParseError
-
-                truepart, tokens = self._parse(self._remains(tokens), ',')
-                
-                if truepart == None:
-                        raise ParseError
-                        
-                falsepart, tokens = self._parse(tokens, ')')
-                
-                if falsepart == None:
-                        raise ParseError
-
-                if condition:
-                        return truepart, tokens
-                else:
-                        return falsepart, tokens
-        
-        def escape_substitution(substitution):
-                return re.sub('(%s|%s)' % (self.REG_GROUP, self.REG_ESCAPE), '\\\\\\1', substitution)
-                
-        escapesubstitution = staticmethod(escape_substitution)
-# ex:ts=8:et:
+    REG_ID = '[0-9]+'
+    REG_NAME = '[a-zA-Z_]+'
+    REG_MOD = '[a-zA-Z]+'
+    REG_ESCAPE = '\\\\|\\(\\?|,|\\)'
+
+    def __init__(self, pattern, groups = {}, modifiers = {}):
+        self.pattern = pattern
+        self.groups = groups
+
+        self.REG_GROUP = '(?:(%s)|<(%s|%s)(?:,(%s))?>)' % (self.REG_ID, self.REG_ID, self.REG_NAME, self.REG_MOD)
+        self.modifiers = {'u': Modifiers.upper_first,
+                  'U': Modifiers.upper,
+                  'l': Modifiers.lower_first,
+                  'L': Modifiers.lower,
+                  't': Modifiers.title}
+
+        for k, v in modifiers.items():
+            self.modifiers[k] = v
+
+    def parse(self):
+        result, tokens = self._parse(self.pattern, None)
+
+        return result
+
+    def _parse(self, tokens, terminator):
+        result = ''
+
+        while tokens != '':
+            if self._peek(tokens) == '' or self._peek(tokens) == terminator:
+                tokens = self._remains(tokens)
+                break
+
+            try:
+                res, tokens = self._expr(tokens, terminator)
+            except ParseError:
+                res, tokens = self._text(tokens)
+
+            result += res
+
+        return result, tokens
+
+    def _peek(self, tokens, num = 0):
+        return (num < len(tokens) and tokens[num])
+
+    def _token(self, tokens):
+        if tokens == '':
+            return '', '';
+
+        return tokens[0], (len(tokens) > 1 and tokens[1:]) or ''
+
+    def _remains(self, tokens, num = 1):
+        return (num < len(tokens) and tokens[num:]) or ''
+
+    def _expr(self, tokens, terminator):
+        if tokens == '':
+            return ''
+
+        try:
+            return {'\\': self._escape,
+                '(': self._condition}[self._peek(tokens)](tokens, terminator)
+        except KeyError:
+            raise ParseError
+
+    def _text(self, tokens):
+        return self._token(tokens)
+
+    def _substitute(self, group, modifiers = ''):
+        result = (self.groups.has_key(group) and self.groups[group]) or ''
+
+        for modifier in modifiers:
+            if self.modifiers.has_key(modifier):
+                result = self.modifiers[modifier](result)
+
+        return result
+
+    def _match_group(self, tokens):
+        match = re.match('\\\\%s' % self.REG_GROUP, tokens)
+
+        if not match:
+            return None, tokens
+
+        return self._substitute(match.group(1) or match.group(2), match.group(3) or ''), tokens[match.end():]
+
+    def _escape(self, tokens, terminator):
+        # Try to match a group
+        result, tokens = self._match_group(tokens)
+
+        if result != None:
+            return result, tokens
+
+        s = self.REG_GROUP
+
+        if terminator:
+            s += '|%s' % re.escape(terminator)
+
+        match = re.match('\\\\(\\\\%s|%s)' % (s, self.REG_ESCAPE), tokens)
+
+        if not match:
+            raise ParseError
+
+        return match.group(1), tokens[match.end():]
+
+    def _condition_value(self, tokens):
+        match = re.match('\\\\?%s\s*' % self.REG_GROUP, tokens)
+
+        if not match:
+            return None, tokens
+
+        groups = match.groups()
+        name = groups[0] or groups[1]
+
+        return self.groups.has_key(name) and self.groups[name] != None, tokens[match.end():]
+
+    def _condition(self, tokens, terminator):
+        # Match ? after (
+        if self._peek(tokens, 1) != '?':
+            raise ParseError
+
+        # Remove initial (? token
+        tokens = self._remains(tokens, 2)
+        condition, tokens = self._condition_value(tokens)
+
+        if condition == None or self._peek(tokens) != ',':
+            raise ParseError
+
+        truepart, tokens = self._parse(self._remains(tokens), ',')
+
+        if truepart == None:
+            raise ParseError
+
+        falsepart, tokens = self._parse(tokens, ')')
+
+        if falsepart == None:
+            raise ParseError
+
+        if condition:
+            return truepart, tokens
+        else:
+            return falsepart, tokens
+
+    def escape_substitution(substitution):
+        return re.sub('(%s|%s)' % (self.REG_GROUP, self.REG_ESCAPE), '\\\\\\1', substitution)
+
+    escapesubstitution = staticmethod(escape_substitution)
+# ex:ts=4:et:
diff --git a/plugins/snippets/snippets/WindowHelper.py b/plugins/snippets/snippets/WindowHelper.py
old mode 100755
new mode 100644
index 3b08d12..296ff03
--- a/plugins/snippets/snippets/WindowHelper.py
+++ b/plugins/snippets/snippets/WindowHelper.py
@@ -25,127 +25,127 @@ from Document import Document
 from Library import Library
 
 class WindowHelper:
-        def __init__(self, plugin):
-                self.plugin = plugin
-                self.current_controller = None
-                self.current_language = None
-                self.signal_ids = {}
-                
-        def run(self, window):
-                self.window = window
-
-                self.insert_menu()
-                
-                self.accel_group = Library().get_accel_group(None)
-                
-                window.add_accel_group(self.accel_group)
-                window.connect('tab-added', self.on_tab_added)
-                
-                # Add controllers to all the current views
-                for view in self.window.get_views():
-                        if isinstance(view, Pluma.View) and not self.has_controller(view):
-                                view._snippet_controller = Document(self, view)
-                
-                self.update()
-        
-        def stop(self):
-                self.window.remove_accel_group(self.accel_group)
-                self.accel_group = None
-                
-                self.remove_menu()
-
-                # Iterate over all the tabs and remove every controller
-                for view in self.window.get_views():
-                        if isinstance(view, Pluma.View) and self.has_controller(view):
-                                view._snippet_controller.stop()
-                                view._snippet_controller = None
-                
-                self.window = None
-                self.plugin = None
-
-        def insert_menu(self):
-                manager = self.window.get_ui_manager()
-
-                self.action_group = Gtk.ActionGroup("PlumaSnippetPluginActions")
-                self.action_group.set_translation_domain('pluma')
-                self.action_group.add_actions([('ManageSnippets', None,
-                                _('Manage _Snippets...'), \
-                                None, _('Manage snippets'), \
-                                self.on_action_snippets_activate)])
-
-                self.merge_id = manager.new_merge_id()
-                manager.insert_action_group(self.action_group, -1)
-                manager.add_ui(self.merge_id, '/MenuBar/ToolsMenu/ToolsOps_5', \
-                                'ManageSnippets', 'ManageSnippets', Gtk.UIManagerItemType.MENUITEM, False)
-
-        def remove_menu(self):
-                manager = self.window.get_ui_manager()
-                manager.remove_ui(self.merge_id)
-                manager.remove_action_group(self.action_group)
-                self.action_group = None
-        
-        def find_snippet(self, snippets, tag):
-                result = []
-                
-                for snippet in snippets:
-                        if Snippet(snippet)['tag'] == tag:
-                                result.append(snippet)
-                
-                return result
-
-        def has_controller(self, view):
-                return hasattr(view, '_snippet_controller') and view._snippet_controller
-
-        def update_language(self):
-                if not self.window:
-                        return
-
-                if self.current_language:
-                        accel_group = Library().get_accel_group( \
-                                        self.current_language)
-                        self.window.remove_accel_group(accel_group)
-
-                if self.current_controller:
-                        self.current_language = self.current_controller.language_id
-                        
-                        if self.current_language != None:
-                                accel_group = Library().get_accel_group( \
-                                                self.current_language)
-                                self.window.add_accel_group(accel_group)
-                else:
-                        self.current_language = None
-                
-        def language_changed(self, controller):
-                if controller == self.current_controller:
-                        self.update_language()
-                
-        def update(self):
-                view = self.window.get_active_view()
-                
-                if not view or not self.has_controller(view):
-                        return
-                
-                controller = view._snippet_controller
-                
-                if controller != self.current_controller:
-                        self.current_controller = controller
-                        self.update_language()
-
-        # Callbacks
-        
-        def on_tab_added(self, window, tab):
-                # Create a new controller for this tab if it has a standard pluma view
-                view = tab.get_view()
-                
-                if isinstance(view, Pluma.View) and not self.has_controller(view):
-                        view._snippet_controller = Document(self, view)
-
-                self.update()
-
-        def on_action_snippets_activate(self, item):
-                self.plugin.create_configure_dialog()
-
-        def accelerator_activated(self, keyval, mod):
-                return self.current_controller.accelerator_activate(keyval, mod)
-
-# ex:ts=8:et:
+    def __init__(self, plugin):
+        self.plugin = plugin
+        self.current_controller = None
+        self.current_language = None
+        self.signal_ids = {}
+
+    def run(self, window):
+        self.window = window
+
+        self.insert_menu()
+
+        self.accel_group = Library().get_accel_group(None)
+
+        window.add_accel_group(self.accel_group)
+        window.connect('tab-added', self.on_tab_added)
+
+        # Add controllers to all the current views
+        for view in self.window.get_views():
+            if isinstance(view, Pluma.View) and not self.has_controller(view):
+                view._snippet_controller = Document(self, view)
+
+        self.update()
+
+    def stop(self):
+        self.window.remove_accel_group(self.accel_group)
+        self.accel_group = None
+
+        self.remove_menu()
+
+        # Iterate over all the tabs and remove every controller
+        for view in self.window.get_views():
+            if isinstance(view, Pluma.View) and self.has_controller(view):
+                view._snippet_controller.stop()
+                view._snippet_controller = None
+
+        self.window = None
+        self.plugin = None
+
+    def insert_menu(self):
+        manager = self.window.get_ui_manager()
+
+        self.action_group = Gtk.ActionGroup("PlumaSnippetPluginActions")
+        self.action_group.set_translation_domain('pluma')
+        self.action_group.add_actions([('ManageSnippets', None,
+                _('Manage _Snippets...'), \
+                None, _('Manage snippets'), \
+                self.on_action_snippets_activate)])
+
+        self.merge_id = manager.new_merge_id()
+        manager.insert_action_group(self.action_group, -1)
+        manager.add_ui(self.merge_id, '/MenuBar/ToolsMenu/ToolsOps_5', \
+                'ManageSnippets', 'ManageSnippets', Gtk.UIManagerItemType.MENUITEM, False)
+
+    def remove_menu(self):
+        manager = self.window.get_ui_manager()
+        manager.remove_ui(self.merge_id)
+        manager.remove_action_group(self.action_group)
+        self.action_group = None
+
+    def find_snippet(self, snippets, tag):
+        result = []
+
+        for snippet in snippets:
+            if Snippet(snippet)['tag'] == tag:
+                result.append(snippet)
+
+        return result
+
+    def has_controller(self, view):
+        return hasattr(view, '_snippet_controller') and view._snippet_controller
+
+    def update_language(self):
+        if not self.window:
+            return
+
+        if self.current_language:
+            accel_group = Library().get_accel_group( \
+                    self.current_language)
+            self.window.remove_accel_group(accel_group)
+
+        if self.current_controller:
+            self.current_language = self.current_controller.language_id
+
+            if self.current_language != None:
+                accel_group = Library().get_accel_group( \
+                        self.current_language)
+                self.window.add_accel_group(accel_group)
+        else:
+            self.current_language = None
+
+    def language_changed(self, controller):
+        if controller == self.current_controller:
+            self.update_language()
+
+    def update(self):
+        view = self.window.get_active_view()
+
+        if not view or not self.has_controller(view):
+            return
+
+        controller = view._snippet_controller
+
+        if controller != self.current_controller:
+            self.current_controller = controller
+            self.update_language()
+
+    # Callbacks
+
+    def on_tab_added(self, window, tab):
+        # Create a new controller for this tab if it has a standard pluma view
+        view = tab.get_view()
+
+        if isinstance(view, Pluma.View) and not self.has_controller(view):
+            view._snippet_controller = Document(self, view)
+
+        self.update()
+
+    def on_action_snippets_activate(self, item):
+        self.plugin.create_configure_dialog()
+
+    def accelerator_activated(self, keyval, mod):
+        return self.current_controller.accelerator_activate(keyval, mod)
+
+# ex:ts=4:et:
diff --git a/plugins/snippets/snippets/__init__.py b/plugins/snippets/snippets/__init__.py
old mode 100755
new mode 100644
index d005e89..8642406
--- a/plugins/snippets/snippets/__init__.py
+++ b/plugins/snippets/snippets/__init__.py
@@ -23,71 +23,73 @@ from Library import Library
 from Manager import Manager
 
 class SnippetsPlugin(GObject.Object, Peas.Activatable):
-        __gtype_name__ = "SnippetsPlugin"
+    __gtype_name__ = "SnippetsPlugin"
 
-        object = GObject.Property(type=GObject.Object)
+    object = GObject.Property(type=GObject.Object)
 
-        def __init__(self):
-                GObject.Object.__init__(self)
+    def __init__(self):
+        GObject.Object.__init__(self)
 
-                self.dlg = None
+        self.dlg = None
 
-        def system_dirs(self):
-                if 'XDG_DATA_DIRS' in os.environ:
-                        datadirs = os.environ['XDG_DATA_DIRS']
-                else:
-                        datadirs = '/usr/local/share' + os.pathsep + '/usr/share'
+    def system_dirs(self):
+        if 'XDG_DATA_DIRS' in os.environ:
+            datadirs = os.environ['XDG_DATA_DIRS']
+        else:
+            datadirs = '/usr/local/share' + os.pathsep + '/usr/share'
 
-                dirs = []
+        dirs = []
 
-                for d in datadirs.split(os.pathsep):
-                        d = os.path.join(d, 'pluma', 'plugins', 'snippets')
+        for d in datadirs.split(os.pathsep):
+            d = os.path.join(d, 'pluma', 'plugins', 'snippets')
 
-                        if os.path.isdir(d):
-                                dirs.append(d)
+            if os.path.isdir(d):
+                dirs.append(d)
 
-                dirs.append(self.plugin_info.get_data_dir())
-                return dirs
+        dirs.append(self.plugin_info.get_data_dir())
+        return dirs
 
-        def do_activate(self):
-                library = Library()
-                library.add_accelerator_callback(self.accelerator_activated)
+    def do_activate(self):
+        library = Library()
+        library.add_accelerator_callback(self.accelerator_activated)
 
-                snippetsdir = os.path.join(GLib.get_user_config_dir(), '/pluma/snippets')
-                library.set_dirs(snippetsdir, self.system_dirs())
+        snippetsdir = os.path.join(GLib.get_user_config_dir(), '/pluma/snippets')
+        library.set_dirs(snippetsdir, self.system_dirs())
 
-                self._helper = WindowHelper(self)
+        self._helper = WindowHelper(self)
 
-                window = self.object
-                self._helper.run(window)
+        window = self.object
+        self._helper.run(window)
 
-        def do_deactivate(self):
-                library = Library()
-                library.remove_accelerator_callback(self.accelerator_activated)
+    def do_deactivate(self):
+        library = Library()
+        library.remove_accelerator_callback(self.accelerator_activated)
 
-                self._helper.stop()
-                self._helper = None
+        self._helper.stop()
+        self._helper = None
 
-        def do_update_state(self):
-                self._helper.update()
+    def do_update_state(self):
+        self._helper.update()
 
-        def create_configure_dialog(self):
-                if not self.dlg:
-                        self.dlg = Manager(self.plugin_info.get_data_dir())
-                else:
-                        self.dlg.run()
+    def create_configure_dialog(self):
+        if not self.dlg:
+            self.dlg = Manager(self.plugin_info.get_data_dir())
+        else:
+            self.dlg.run()
 
-                window = Pluma.App.get_default().get_active_window()
+        window = Pluma.App.get_default().get_active_window()
 
-                if window:
-                        self.dlg.dlg.set_transient_for(window)
+        if window:
+            self.dlg.dlg.set_transient_for(window)
 
-                return self.dlg.dlg
+        return self.dlg.dlg
 
-        def accelerator_activated(self, group, obj, keyval, mod):
-                ret = False
+    def accelerator_activated(self, group, obj, keyval, mod):
+        ret = False
 
-                if self._helper:
-                        ret = self._helper.accelerator_activated(keyval, mod)
+        if self._helper:
+            ret = self._helper.accelerator_activated(keyval, mod)
 
-                return ret
+        return ret
+
+# ex:ts=4:et:
-- 
2.21.0

