[meld] Move ignore-blank-lines implementation to Differ class



commit eaaabc7d4fef2590fc16bca279955fc1b0cef04d
Author: Kai Willadsen <kai willadsen gmail com>
Date:   Sun Sep 27 14:10:28 2009 +1000

    Move ignore-blank-lines implementation to Differ class
    
    One problem with the ignore-blank-lines preference is that the current
    implementation causes FileDiff to use a different set of diff chunks to
    those provided by Differ. Moving the implementation of the preference into
    the Differ class unifies these views, and makes it easier to extend the
    information provided by Differ.
    
    Also, the new implementation in Differ._consume_blank_lines() is superior
    in that it rewrites diff chunks whose nature changes when blank lines are
    ignored. For example, a 'replace' chunk in which one side consists entirely
    of blanks lines is now correctly transformed into an 'insert' or 'delete'
    chunk, as appropriate.

 meld/diffutil.py |   35 +++++++++++++++++++++++++++++++++++
 meld/filediff.py |   52 +++++++++++-----------------------------------------
 2 files changed, 46 insertions(+), 41 deletions(-)
---
diff --git a/meld/diffutil.py b/meld/diffutil.py
index 8e45a7b..b1a2047 100644
--- a/meld/diffutil.py
+++ b/meld/diffutil.py
@@ -1,4 +1,5 @@
 ### Copyright (C) 2002-2006 Stephen Kennedy <stevek gnome org>
+### Copyright (C) 2009 Kai Willadsen <kai willadsen gmail com>
 
 ### This program is free software; you can redistribute it and/or modify
 ### it under the terms of the GNU General Public License as published by
@@ -75,6 +76,7 @@ class Differ(object):
         self.seqlength = [0, 0, 0]
         self.diffs = [[], []]
         self._merge_cache = []
+        self.ignore_blanks = False
 
     def _update_merge_cache(self, texts):
         if self.num_sequences == 3:
@@ -82,6 +84,39 @@ class Differ(object):
         else:
             self._merge_cache = [(c, None) for c in self.diffs[0]]
 
+        if self.ignore_blanks:
+            # We don't handle altering the chunk-type of conflicts in three-way
+            # comparisons where e.g., pane 1 and 3 differ in blank lines
+            for i, c in enumerate(self._merge_cache):
+                self._merge_cache[i] = (self._consume_blank_lines(c[0], texts, 1, 0),
+                                        self._consume_blank_lines(c[1], texts, 1, 2))
+            self._merge_cache = [x for x in self._merge_cache if x != (None, None)]
+
+    def _consume_blank_lines(self, c, texts, pane1, pane2):
+        if c is None:
+            return None
+        c0 = c[0]
+        c1, c2 = self._find_blank_lines(texts[pane1], c[1], c[2])
+        c3, c4 = self._find_blank_lines(texts[pane2], c[3], c[4])
+        if c1 == c2 and c3 == c4:
+            return None
+        if c1 == c2 and c[0] == "replace":
+            c0 = "insert"
+        elif c3 == c4 and c[0] == "replace":
+            c0 = "delete"
+        return (c0, c1, c2, c3, c4)
+
+    def _find_blank_lines(self, txt, lo, hi):
+        for line in range(lo, hi):
+            if txt[line]:
+                break
+            lo += 1
+        for line in range(hi, lo, -1):
+            if txt[line - 1]:
+                break
+            hi -= 1
+        return lo, hi
+
     def change_sequence(self, sequence, startidx, sizechange, texts):
         assert sequence in (0, 1, 2)
         if sequence == 0 or sequence == 1:
diff --git a/meld/filediff.py b/meld/filediff.py
index 1c7302e..31bb507 100644
--- a/meld/filediff.py
+++ b/meld/filediff.py
@@ -129,6 +129,7 @@ class FileDiff(melddoc.MeldDoc, gnomeglade.Component):
         self._sync_vscroll_lock = False
         self._sync_hscroll_lock = False
         self.linediffer = diffutil.Differ()
+        self.linediffer.ignore_blanks = self.prefs.ignore_blank_lines
         self._inline_cache = set()
         self._cached_match = CachedSequenceMatcher()
         for text in self.textview:
@@ -253,6 +254,13 @@ class FileDiff(melddoc.MeldDoc, gnomeglade.Component):
                     return self.textfilter(txt).split("\n")
                 else:
                     return self.textfilter(txt).split("\n")[:-1]
+            def __getitem__(self, i):
+                line_start = get_iter_at_line_or_eof(self.buf, i)
+                line_end = line_start.copy()
+                if not line_end.ends_line():
+                    line_end.forward_to_line_end()
+                return self.buf.get_text(line_start, line_end, False)
+
         class FakeTextArray(object):
             def __init__(self, bufs, textfilter):
                 self.texts = [FakeText(b, textfilter) for b in  bufs]
@@ -342,6 +350,9 @@ class FileDiff(melddoc.MeldDoc, gnomeglade.Component):
         elif key == "spaces_instead_of_tabs":
             for t in self.textview:
                 t.set_insert_spaces_instead_of_tabs(value)
+        elif key == "ignore_blank_lines":
+            self.linediffer.ignore_blanks = self.prefs.ignore_blank_lines
+            self.set_files([None] * self.num_panes) # Refresh
 
     def _update_linkmap_buttons(self):
         for l in self.linkmap[:self.num_panes - 1]:
@@ -746,9 +757,6 @@ class FileDiff(melddoc.MeldDoc, gnomeglade.Component):
                 context.fill()
 
         for change in self.linediffer.single_changes(pane):
-            change, skip = self._consume_blank_lines(change, pane, change[5])
-            if skip:
-                continue
             if change[2] < start_line: continue
             if change[1] > end_line: break
             draw_change(change)
@@ -1042,9 +1050,6 @@ class FileDiff(melddoc.MeldDoc, gnomeglade.Component):
                 "delete":solid_green}
         for c in self.linediffer.single_changes(textindex):
             assert c[0] != "equal"
-            c, skip = self._consume_blank_lines(c, textindex, c[5])
-            if skip:
-                continue
             rect(context, ctab[c[0]], scale*c[1], scale*c[2])
 
     def on_diffmap_button_press_event(self, area, event):
@@ -1102,9 +1107,6 @@ class FileDiff(melddoc.MeldDoc, gnomeglade.Component):
         c = None
         for chunk in self.linediffer.single_changes(pane):
             assert chunk[0] != "equal"
-            chunk, skip = self._consume_blank_lines(chunk, 1, chunk[5])
-            if skip:
-                continue
             if direction == gdk.SCROLL_DOWN:
                 # Take the first chunk which is starting after curline
                 if chunk[1] > curline:
@@ -1154,31 +1156,6 @@ class FileDiff(melddoc.MeldDoc, gnomeglade.Component):
             if cursorline != c[1]:
                 buf.place_cursor(buf.get_iter_at_line(c[1]))
 
-    def _consume_blank_lines(self, c, pane1, pane2):
-        if not self.prefs.ignore_blank_lines:
-            return c, False
-        c1, c2 = self._find_blank_lines(self._get_texts()[pane1][c[1]:c[2]])
-        c3, c4 = self._find_blank_lines(self._get_texts()[pane2][c[3]:c[4]])
-        new_c = (c[0], c[1] + c1, c[2] - c2, c[3] + c3, c[4] - c4)
-        if len(c) == 6:
-            new_c += (c[5],)
-        nothing_left = new_c[1] == new_c[2] and new_c[3] == new_c[4]
-        return new_c, nothing_left
-
-    def _find_blank_lines(self, txt):
-        lo, hi = 0, 0
-        for l in txt:
-            if len(l)==0:
-                lo += 1
-            else:
-                break
-        for l in reversed(txt[lo:]):
-            if len(l)==0:
-                hi += 1
-            else:
-                break
-        return lo,hi
-
         #
         # linkmap drawing
         #
@@ -1218,10 +1195,6 @@ class FileDiff(melddoc.MeldDoc, gnomeglade.Component):
             context.identity_matrix()
 
         for c in self.linediffer.pair_changes(which, which + 1):
-            c, skip = self._consume_blank_lines(c, which, which + 1)
-            if skip:
-                continue
-
             assert c[0] != "equal"
             if c[2] < visible[1] and c[4] < visible[3]: # find first visible chunk
                 continue
@@ -1295,9 +1268,6 @@ class FileDiff(melddoc.MeldDoc, gnomeglade.Component):
             adj = self.scrolledwindow[src].get_vadjustment()
 
             for c in self.linediffer.pair_changes(src, dst):
-                c, skip = self._consume_blank_lines(c, src, dst)
-                if skip:
-                    continue
                 if c[0] == "insert":
                     continue
                 h = self._line_to_pixel(src, c[1]) - adj.value



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