[meld] Fix overzealous inline highlighting invalidation (closes bgo#693690)
- From: Kai Willadsen <kaiw src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [meld] Fix overzealous inline highlighting invalidation (closes bgo#693690)
- Date: Sun, 17 Feb 2013 01:57:25 +0000 (UTC)
commit c91c5b459f245214071d3f68aff8094b3de608e6
Author: Kai Willadsen <kai willadsen gmail com>
Date: Sun Feb 17 10:16:08 2013 +1000
Fix overzealous inline highlighting invalidation (closes bgo#693690)
In the existing code, any buffer change invalidated all pending inline
highlighting jobs. This causes serious issues if any highlighting jobs
are pending when a change is made; these jobs will never be restarted
unless their chunks are directly changed.
The solution in this patch is to only consider inline highlighting
results to be invalid if the actual text being highlighted has changed.
We do this by using gtk.TextMarks instead of gtk.TextIters (avoiding
buffer invalidation) and checking to see whether the text we're about
to highlight actually matches what we think we're highlighting. If it
doesn't, then we have a changed block, which *will* be rehighlighted
in the relevant changed callback.
The downside to this approach is that creation of gtk.TextMarks and
validating the text before highlighting is computationally much more
expensive than our previous approach.
bin/meld | 3 ++-
meld/filediff.py | 37 ++++++++++++++++++++-----------------
2 files changed, 22 insertions(+), 18 deletions(-)
---
diff --git a/bin/meld b/bin/meld
index ce67b7f..4094176 100755
--- a/bin/meld
+++ b/bin/meld
@@ -138,10 +138,11 @@ try:
except (ImportError, AssertionError) as e:
missing_reqs("pygobject", pygobjectver, e)
-
+gobject.threads_init()
gtk.icon_theme_get_default().append_search_path(meld.paths.icon_dir())
gtk.rc_parse(meld.paths.share_dir("gtkrc"))
+
def main():
import meld.meldapp
app = meld.meldapp.app
diff --git a/meld/filediff.py b/meld/filediff.py
index 7a7df39..2010e31 100644
--- a/meld/filediff.py
+++ b/meld/filediff.py
@@ -83,7 +83,7 @@ class CachedSequenceMatcher(object):
except KeyError:
def inline_cb(opcodes):
self.cache[(text1, textn)] = [opcodes, time.time()]
- cb(opcodes)
+ gobject.idle_add(lambda: cb(opcodes))
process_pool.apply_async(matcher_worker, (text1, textn),
callback=inline_cb)
@@ -215,15 +215,6 @@ class FileDiff(melddoc.MeldDoc, gnomeglade.Component):
for buf in self.textbuffer:
buf.create_tag("inline")
- # We need to keep track of gtk.TextIter validity, but this isn't
- # exposed anywhere. Instead, we keep our own counter for changes
- # across all of our buffers.
- self._buffer_changed_stamp = 0
- def buffer_change(buf):
- self._buffer_changed_stamp += 1
- for buf in self.textbuffer:
- buf.connect("changed", buffer_change)
-
actions = (
("MakePatch", None, _("Format as patch..."), None, _("Create a patch using differences between
files"), self.make_patch),
("PrevConflict", None, _("Previous conflict"), "<Ctrl>I", _("Go to the previous conflict"),
lambda x: self.on_next_conflict(gtk.gdk.SCROLL_UP)),
@@ -1188,14 +1179,23 @@ class FileDiff(melddoc.MeldDoc, gnomeglade.Component):
textn = text_type(textn, 'utf8')
# For very long sequences, bail rather than trying a very slow comparison
- inline_limit = 8000 # arbitrary constant
+ inline_limit = 8000
if len(text1) + len(textn) > inline_limit:
for i in range(2):
bufs[i].apply_tag(tags[i], starts[i], ends[i])
continue
- def apply_highlight(bufs, tags, starts, change_stamp, matches):
- if change_stamp != self._buffer_changed_stamp:
+ def apply_highlight(bufs, tags, starts, ends, texts, matches):
+ starts = [bufs[0].get_iter_at_mark(starts[0]),
+ bufs[1].get_iter_at_mark(starts[1])]
+ ends = [bufs[0].get_iter_at_mark(ends[0]),
+ bufs[1].get_iter_at_mark(ends[1])]
+ text1 = bufs[0].get_text(starts[0], ends[0], False)
+ text1 = text_type(text1, 'utf8')
+ textn = bufs[1].get_text(starts[1], ends[1], False)
+ textn = text_type(textn, 'utf8')
+
+ if texts != (text1, textn):
return
# Remove equal matches of size greater than 3; highlight
@@ -1215,10 +1215,13 @@ class FileDiff(melddoc.MeldDoc, gnomeglade.Component):
bufs[0].remove_tag(tags[0], starts[0], ends[0])
bufs[1].remove_tag(tags[1], starts[1], ends[1])
- match_cb = functools.partial(apply_highlight,
- bufs, tags, starts,
- self._buffer_changed_stamp)
- matches = self._cached_match.match(text1, textn, match_cb)
+ starts = [bufs[0].create_mark(None, starts[0], True),
+ bufs[1].create_mark(None, starts[1], True)]
+ ends = [bufs[0].create_mark(None, ends[0], True),
+ bufs[1].create_mark(None, ends[1], True)]
+ match_cb = functools.partial(apply_highlight, bufs, tags,
+ starts, ends, (text1, textn))
+ self._cached_match.match(text1, textn, match_cb)
self._cached_match.clean(self.linediffer.diff_count())
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]