[meld] Move filter parsing/compilation from FileDiff and DirDiff to MeldApp
- From: Kai Willadsen <kaiw src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [meld] Move filter parsing/compilation from FileDiff and DirDiff to MeldApp
- Date: Tue, 15 Feb 2011 09:09:19 +0000 (UTC)
commit b005a9780831207aabe2ad4e42dce3cbc1d89c1c
Author: Kai Willadsen <kai willadsen gmail com>
Date: Wed Feb 9 07:34:06 2011 +1000
Move filter parsing/compilation from FileDiff and DirDiff to MeldApp
Meld uses filters extensively, and currently several issues arise
because of filter validity errors, maintaining per-view filters, and
a default vs. current-view split of active filters. This commit starts
the process of shifting filter parsing, compilation and validation to
the application level.
This commit also adds a new FilterEntry class to MeldApp. This class
supercedes the removed TypeFilter class from DirDiff, and will
eventually handle both text and file filters.
meld/dirdiff.py | 80 ++++++++++++++---------------------------------------
meld/filediff.py | 22 ++++-----------
meld/meldapp.py | 67 +++++++++++++++++++++++++++++++++++++++++++++
3 files changed, 94 insertions(+), 75 deletions(-)
---
diff --git a/meld/dirdiff.py b/meld/dirdiff.py
index 7a554bf..e22a756 100644
--- a/meld/dirdiff.py
+++ b/meld/dirdiff.py
@@ -16,6 +16,7 @@
### Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
import collections
+import copy
import errno
import paths
from ui import gnomeglade
@@ -33,10 +34,11 @@ import re
import stat
import time
-from util.namedtuple import namedtuple
-
import ui.emblemcellrenderer
+from util.namedtuple import namedtuple
+from meldapp import app
+
gdk = gtk.gdk
################################################################################
@@ -169,19 +171,6 @@ class DirDiffTreeStore(tree.DiffTreeStore):
types = [str] * COL_END * ntree
tree.DiffTreeStore.__init__(self, ntree, types)
-################################################################################
-#
-# TypeFilter
-#
-################################################################################
-
-class TypeFilter(object):
- __slots__ = ("label", "filter", "active")
- def __init__(self, label, active, filter):
- self.label = label
- self.active = active
- self.filter = filter
-
class CanonicalListing(object):
"""Multi-pane lists with canonicalised matching and error detection"""
@@ -286,17 +275,6 @@ class DirDiff(melddoc.MeldDoc, gnomeglade.Component):
tree.STATE_MODIFIED,
tree.STATE_NEW,
]
- self.update_regexes()
-
- def update_regexes(self):
- self.regexes = []
- for r in [ misc.ListItem(i) for i in self.prefs.regexes.split("\n") ]:
- if r.active:
- try:
- self.regexes.append( re.compile(r.value+"(?m)") )
- except re.error:
- misc.run_dialog(
- text=_("Error converting pattern '%s' to regular expression") % r.value )
def _custom_popup_deactivated(self, popup):
self.filter_menu_button.set_active(False)
@@ -332,39 +310,23 @@ class DirDiff(melddoc.MeldDoc, gnomeglade.Component):
melddoc.MeldDoc.on_container_switch_out_event(self, ui)
def create_name_filters(self):
- self.name_filters_available = []
- for f in [misc.ListItem(s) for s in self.prefs.filters.split("\n") ]:
- bits = f.value.split()
- if len(bits) > 1:
- regex = "(%s)$" % "|".join( [misc.shell_to_regex(b)[:-1] for b in bits] )
- elif len(bits):
- regex = misc.shell_to_regex(bits[0])
- else: # an empty pattern would match anything, skip it
- continue
- try:
- cregex = re.compile(regex)
- except re.error:
- misc.run_dialog( _("Error converting pattern '%s' to regular expression") % f.value, self )
- else:
- func = lambda x, r=cregex : r.match(x) is None
- self.name_filters_available.append( TypeFilter(f.name, f.active, func) )
- self.name_filters = [f for f in self.name_filters_available if f.active]
-
+ self.name_filters = [copy.copy(f) for f in app.file_filters]
actions = []
+ disabled_actions = []
self.filter_ui = []
- for i,f in enumerate(self.name_filters_available):
+ for i, f in enumerate(self.name_filters):
name = "Hide%d" % i
callback = lambda b, i=i: self._update_name_filter(b, i)
actions.append((name, None, f.label, None, _("Hide %s") % f.label, callback, f.active))
self.filter_ui.append(["/CustomPopup" , name, name, gtk.UI_MANAGER_MENUITEM, False])
self.filter_ui.append(["/Menubar/ViewMenu/FileFilters" , name, name, gtk.UI_MANAGER_MENUITEM, False])
+ if f.filter is None:
+ disabled_actions.append(name)
self.filter_actiongroup = gtk.ActionGroup("DirdiffFilterActions")
self.filter_actiongroup.add_toggle_actions(actions)
-
- def on_preference_changed(self, key, value):
- if key == "regexes":
- self.update_regexes()
+ for name in disabled_actions:
+ self.filter_actiongroup.get_action(name).set_sensitive(False)
def _do_to_others(self, master, objects, methodname, args):
if not hasattr(self, "do_to_others_lock"):
@@ -475,7 +437,9 @@ class DirDiff(melddoc.MeldDoc, gnomeglade.Component):
continue
for f in self.name_filters:
- entries = filter(f.filter, entries)
+ if not f.active or f.filter is None:
+ continue
+ entries = [e for e in entries if f.filter.match(e) is None]
for e in entries:
try:
@@ -816,12 +780,7 @@ class DirDiff(melddoc.MeldDoc, gnomeglade.Component):
self._update_state_filter( tree.STATE_MODIFIED, button.get_active() )
def _update_name_filter(self, button, idx):
- for i in range(len(self.name_filters)):
- if self.name_filters[i] == self.name_filters_available[idx]:
- self.name_filters.pop(i)
- break
- if button.get_active():
- self.name_filters.append( self.name_filters_available[idx] )
+ self.name_filters[idx].active = button.get_active()
self.refresh()
def on_filter_hide_current_clicked(self, button):
@@ -852,12 +811,13 @@ class DirDiff(melddoc.MeldDoc, gnomeglade.Component):
"""
assert len(roots) == self.model.ntree
ret = []
+ regexes = [f.filter for f in app.text_filters if f.active and f.filter]
for files in fileslist:
curfiles = [ os.path.join( r, f ) for r,f in zip(roots,files) ]
is_present = [ os.path.exists( f ) for f in curfiles ]
all_present = 0 not in is_present
if all_present:
- if _files_same(curfiles, self.regexes) in (Same, SameFiltered):
+ if _files_same(curfiles, regexes) in (Same, SameFiltered):
state = tree.STATE_NORMAL
else:
state = tree.STATE_MODIFIED
@@ -871,6 +831,8 @@ class DirDiff(melddoc.MeldDoc, gnomeglade.Component):
"""Update the state of the item at 'it'
"""
files = self.model.value_paths(it)
+ regexes = [f.filter for f in app.text_filters if f.active and f.filter]
+
def mtime(f):
try:
return os.stat(f).st_mtime
@@ -883,7 +845,7 @@ class DirDiff(melddoc.MeldDoc, gnomeglade.Component):
newest_index = -1 # all same
all_present = 0 not in mod_times
if all_present:
- all_same = _files_same( files, self.regexes )
+ all_same = _files_same(files, regexes)
all_present_same = all_same
else:
lof = []
@@ -891,7 +853,7 @@ class DirDiff(melddoc.MeldDoc, gnomeglade.Component):
if mod_times[j]:
lof.append( files[j] )
all_same = Different
- all_present_same = _files_same( lof, self.regexes )
+ all_present_same = _files_same(lof, regexes)
different = 1
one_isdir = [None for i in range(self.model.ntree)]
for j in range(self.model.ntree):
diff --git a/meld/filediff.py b/meld/filediff.py
index 2a1fba4..6443374 100644
--- a/meld/filediff.py
+++ b/meld/filediff.py
@@ -38,6 +38,7 @@ import patchdialog
import paths
import merge
+from meldapp import app
from util.sourceviewer import srcviewer
from util.namedtuple import namedtuple
@@ -182,7 +183,6 @@ class FileDiff(melddoc.MeldDoc, gnomeglade.Component):
melddoc.MeldDoc.__init__(self, prefs)
gnomeglade.Component.__init__(self, paths.ui_dir("filediff.ui"), "filediff")
self.map_widgets_into_lists(["textview", "fileentry", "diffmap", "scrolledwindow", "linkmap", "statusimage", "msgarea_mgr", "vbox"])
- self._update_regexes()
self.warned_bad_comparison = False
# Some sourceviews bind their own undo mechanism, which we replace
gtk.binding_entry_remove(srcviewer.GtkTextView, gtk.keysyms.z,
@@ -302,15 +302,6 @@ class FileDiff(melddoc.MeldDoc, gnomeglade.Component):
if self.textview_focussed:
self.scheduler.add_task(self.textview_focussed.grab_focus)
- def _update_regexes(self):
- self.regexes = []
- for r in [ misc.ListItem(i) for i in self.prefs.regexes.split("\n") ]:
- if r.active:
- try:
- self.regexes.append( (re.compile(r.value+"(?m)"), r.value) )
- except re.error:
- pass
-
def _disconnect_buffer_handlers(self):
for textview in self.textview:
textview.set_editable(0)
@@ -543,12 +534,13 @@ class FileDiff(melddoc.MeldDoc, gnomeglade.Component):
else:
return ""
try:
- for c,r in self.regexes:
- txt = c.sub(killit,txt)
+ for filt in app.text_filters:
+ if filt.active:
+ txt = filt.filter.sub(killit, txt)
except AssertionError:
if not self.warned_bad_comparison:
- misc.run_dialog(_("Regular expression '%s' changed the number of lines in the file. "
- "Comparison will be incorrect. See the user manual for more details.") % r)
+ misc.run_dialog(_("Filter '%s' changed the number of lines in the file. "
+ "Comparison will be incorrect. See the user manual for more details.") % filt.label)
self.warned_bad_comparison = True
return txt
@@ -616,8 +608,6 @@ class FileDiff(melddoc.MeldDoc, gnomeglade.Component):
self.textbuffer[i],
self.bufferdata[i].filename,
self.prefs.use_syntax_highlighting )
- elif key == "regexes":
- self._update_regexes()
elif key == "edit_wrap_lines":
for t in self.textview:
t.set_wrap_mode(self.prefs.edit_wrap_lines)
diff --git a/meld/meldapp.py b/meld/meldapp.py
index 302fd84..2de7b48 100644
--- a/meld/meldapp.py
+++ b/meld/meldapp.py
@@ -18,16 +18,34 @@
import optparse
import os
+import re
from gettext import gettext as _
import gobject
import gtk
+import misc
import preferences
version = "1.5.0"
+class FilterEntry(object):
+
+ __slots__ = ("label", "active", "filter")
+
+ def __init__(self, label, active, filter):
+ self.label = label
+ self.active = active
+ self.filter = filter
+
+ def __copy__(self):
+ new = type(self)(self.label, self.active, None)
+ if self.filter is not None:
+ new.filter = re.compile(self.filter.pattern, self.filter.flags)
+ return new
+
+
class MeldApp(object):
def __init__(self):
@@ -35,11 +53,60 @@ class MeldApp(object):
gtk.window_set_default_icon_name("meld")
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)
def create_window(self):
self.window = meldwindow.MeldWindow()
return self.window
+ def on_preference_changed(self, key, val):
+ if key == "filters":
+ self.file_filters = self._update_filters(val)
+ # FIXME: should emit a file-filters-changed signal here for
+ # DirDiff to respond to
+ elif key == "regexes":
+ self.text_filters = self._update_regexes(val)
+ # 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 diff_files_callback(self, option, opt_str, value, parser):
"""Gather --diff arguments and append to a list"""
assert value is None
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]