[meld] Move filter parsing and compilation logic from MeldApp to FilterEntry



commit 39316bd3d63f6c0fc63c41b99b7fd3c915cf4655
Author: Kai Willadsen <kai willadsen gmail com>
Date:   Fri Feb 11 18:47:42 2011 +1000

    Move filter parsing and compilation logic from MeldApp to FilterEntry
    
    In addition to making the code cleaner, this movement makes it somewhat
    simpler to implement input validation for filter patterns in our
    Preferences dialog.

 meld/meldapp.py     |  103 ++++++++++++++++++++++++++++++---------------------
 meld/misc.py        |   11 -----
 meld/preferences.py |   16 +++++---
 3 files changed, 71 insertions(+), 59 deletions(-)
---
diff --git a/meld/meldapp.py b/meld/meldapp.py
index 2de7b48..91df41d 100644
--- a/meld/meldapp.py
+++ b/meld/meldapp.py
@@ -32,15 +32,65 @@ version = "1.5.0"
 
 class FilterEntry(object):
 
-    __slots__ = ("label", "active", "filter")
+    __slots__ = ("label", "active", "filter", "filter_string")
 
-    def __init__(self, label, active, filter):
+    REGEX, SHELL = 0, 1
+
+    def __init__(self, label, active, filter, filter_string):
         self.label = label
         self.active = active
         self.filter = filter
+        self.filter_string = filter_string
+
+    @classmethod
+    def _compile_regex(cls, regex):
+        try:
+            compiled = re.compile(regex + "(?m)")
+        except re.error:
+            compiled = None
+        return compiled
+
+    @classmethod
+    def _compile_shell_pattern(cls, pattern):
+        bits = pattern.split()
+        if len(bits) > 1:
+            regexes = [misc.shell_to_regex(b)[:-1] for b in bits]
+            regex = "(%s)$" % "|".join(regexes)
+        elif len(bits):
+            regex = misc.shell_to_regex(bits[0])
+        else:
+            # An empty pattern would match everything, so skip it
+            return None
+
+        try:
+            compiled = re.compile(regex)
+        except re.error:
+            compiled = None
+
+        return compiled
+
+    @classmethod
+    def parse(cls, string, filter_type):
+        elements = string.split("\t")
+        name, active = elements[0], bool(int(elements[1]))
+        filter_string = " ".join(elements[2:])
+        compiled = FilterEntry.compile_filter(filter_string, filter_type)
+        if compiled is None:
+            active = False
+        return FilterEntry(name, active, compiled, filter_string)
+
+    @classmethod
+    def compile_filter(cls, filter_string, filter_type):
+        if filter_type == FilterEntry.REGEX:
+            compiled = FilterEntry._compile_regex(filter_string)
+        elif filter_type == FilterEntry.SHELL:
+            compiled = FilterEntry._compile_shell_pattern(filter_string)
+        else:
+            raise ValueError, "Unknown filter type"
+        return compiled
 
     def __copy__(self):
-        new = type(self)(self.label, self.active, None)
+        new = type(self)(self.label, self.active, None, self.filter_string)
         if self.filter is not None:
             new.filter = re.compile(self.filter.pattern, self.filter.flags)
         return new
@@ -54,8 +104,10 @@ class MeldApp(object):
         self.version = version
         self.prefs = preferences.MeldPreferences()
         self.prefs.notify_add(self.on_preference_changed)
-        self.file_filters = self._update_filters(self.prefs.filters)
-        self.text_filters = self._update_regexes(self.prefs.regexes)
+        self.file_filters = self._parse_filters(self.prefs.filters,
+                                                FilterEntry.SHELL)
+        self.text_filters = self._parse_filters(self.prefs.regexes,
+                                                FilterEntry.REGEX)
 
     def create_window(self):
         self.window = meldwindow.MeldWindow()
@@ -63,49 +115,16 @@ class MeldApp(object):
 
     def on_preference_changed(self, key, val):
         if key == "filters":
-            self.file_filters = self._update_filters(val)
+            self.file_filters = self._parse_filters(val, FilterEntry.SHELL)
             # FIXME: should emit a file-filters-changed signal here for
             # DirDiff to respond to
         elif key == "regexes":
-            self.text_filters = self._update_regexes(val)
+            self.text_filters = self._parse_filters(val, FilterEntry.REGEX)
             # FIXME: should emit a text-filters-changed signal here for
             # FileDiff and DirDiff to respond to
 
-    def _update_filters(self, filters_string):
-        filters = []
-        for filter_string in filters_string.split("\n"):
-            elements = filter_string.split("\t")
-            name, active = elements[0], bool(int(elements[1]))
-            bits = (" ".join(elements[2:])).split()
-            if len(bits) > 1:
-                regexes = [misc.shell_to_regex(b)[:-1] for b in bits]
-                regex = "(%s)$" % "|".join(regexes)
-            elif len(bits):
-                regex = misc.shell_to_regex(bits[0])
-            else: # an empty pattern would match anything, skip it
-                continue
-            try:
-                compiled = re.compile(regex)
-            except re.error:
-                active = False
-                compiled = None
-            filters.append(FilterEntry(name, active, compiled))
-        return filters
-
-    def _update_regexes(self, regexes_string):
-        regexes = []
-        for regex_string in regexes_string.split("\n"):
-            elements = regex_string.split("\t")
-            name, active = elements[0], bool(int(elements[1]))
-            regex = " ".join(elements[2:])
-            try:
-                compiled = re.compile(regex + "(?m)")
-            except re.error:
-                active = False
-                compiled = None
-            regexes.append(FilterEntry(name, active, compiled))
-        return regexes
-
+    def _parse_filters(self, string, filt_type):
+        return [FilterEntry.parse(l, filt_type) for l in string.split("\n")]
 
     def diff_files_callback(self, option, opt_str, value, parser):
         """Gather --diff arguments and append to a list"""
diff --git a/meld/misc.py b/meld/misc.py
index 755bf6d..17fe275 100644
--- a/meld/misc.py
+++ b/meld/misc.py
@@ -350,14 +350,3 @@ def shell_to_regex(pat):
         else:
             res += re.escape(c)
     return res + "$"
-
-class ListItem(object):
-    __slots__ = ("name", "active", "value")
-    def __init__(self, s):
-        a = s.split("\t")
-        self.name = a.pop(0)
-        self.active = int(a.pop(0))
-        self.value = " ".join(a)
-    def __str__(self):
-        return "<%s %s %i %s>" % ( self.__class__, self.name, self.active, self.value )
-
diff --git a/meld/preferences.py b/meld/preferences.py
index 1ac80fc..39cf691 100644
--- a/meld/preferences.py
+++ b/meld/preferences.py
@@ -21,6 +21,7 @@ import gtk
 
 from ui import gnomeglade
 from ui import listwidget
+import meldapp
 import misc
 import paths
 from util import prefs
@@ -31,14 +32,15 @@ from util.sourceviewer import srcviewer
 
 class FilterList(listwidget.ListWidget):
 
-    def __init__(self, prefs, key):
-        listwidget.ListWidget.__init__(self, [_("label"), 0, _("pattern")])
+    def __init__(self, prefs, key, filter_type):
+        default_entry = [_("label"), False, _("pattern")]
+        listwidget.ListWidget.__init__(self, default_entry)
         self.prefs = prefs
         self.key = key
 
         for filtstring in getattr(self.prefs, self.key).split("\n"):
-            filt = misc.ListItem(filtstring)
-            self.model.append([filt.name, filt.active, filt.value])
+            filt = meldapp.FilterEntry.parse(filtstring, filter_type)
+            self.model.append([filt.label, filt.active, filt.filter_string])
 
         for signal in ('row-changed', 'row-deleted', 'row-inserted',
                        'rows-reordered'):
@@ -110,12 +112,14 @@ class PreferencesDialog(gnomeglade.Component):
         self.custom_edit_command_entry.set_text( " ".join(self.prefs.get_custom_editor_command([])) )
 
         # file filters
-        self.filefilter = FilterList(self.prefs, "filters")
+        self.filefilter = FilterList(self.prefs, "filters",
+                                     meldapp.FilterEntry.SHELL)
         self.file_filters_tab.pack_start(self.filefilter.widget)
         self.checkbutton_ignore_symlinks.set_active( self.prefs.ignore_symlinks)
 
         # text filters
-        self.textfilter = FilterList(self.prefs, "regexes")
+        self.textfilter = FilterList(self.prefs, "regexes",
+                                     meldapp.FilterEntry.REGEX)
         self.text_filters_tab.pack_start(self.textfilter.widget)
         self.checkbutton_ignore_blank_lines.set_active( self.prefs.ignore_blank_lines )
         # encoding



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]