Patchwork [07,of,10,RESEND] mdiff: let unidiff return (diffheader, hunks)

login
register
mail settings
Submitter Denis Laxalde
Date March 9, 2017, 8:08 a.m.
Message ID <71710fc049991061b638.1489046884@sh77.tls.logilab.fr>
Download mbox | patch
Permalink /patch/19058/
State Accepted
Headers show

Comments

Denis Laxalde - March 9, 2017, 8:08 a.m.
# HG changeset patch
# User Denis Laxalde <denis.laxalde@logilab.fr>
# Date 1488559600 -3600
#      Fri Mar 03 17:46:40 2017 +0100
# Node ID 71710fc049991061b63818ea10aa24f24603c514
# Parent  9cfb7ccf0a6f4f204348165dbb204e740fa79616
# Available At http://hg.logilab.org/users/dlaxalde/hg
#              hg pull http://hg.logilab.org/users/dlaxalde/hg -r 71710fc04999
# EXP-Topic diffhunks
mdiff: let unidiff return (diffheader, hunks)

This will be used to make it possible to filter diff hunks based on this range
information.

Now unidiff returns a 'hunks' generator that yield tuple (hunkrange,
hunklines) coming from _unidiff() with 'newline at end of file' processing.

Patch

diff --git a/mercurial/mdiff.py b/mercurial/mdiff.py
--- a/mercurial/mdiff.py
+++ b/mercurial/mdiff.py
@@ -196,12 +196,12 @@  def allblocks(text1, text2, opts=None, l
         yield s1, '='
 
 def unidiff(a, ad, b, bd, fn1, fn2, opts=defaultopts):
-    """Return a unified diff as a (headers, hunkstext) tuple.
+    """Return a unified diff as a (headers, hunks) tuple.
 
     If the diff is not null, `headers` is a list with unified diff header
-    lines "--- <original>" and "+++ <new>" and `hunkstext` is a string
-    containing diff hunks. Otherwise, both `headers` and `hunkstext` are
-    empty.
+    lines "--- <original>" and "+++ <new>" and `hunks` is a generator yielding
+    (hunkrange, hunklines) coming from _unidiff().
+    Otherwise, `headers` and `hunks` are empty.
     """
     def datetag(date, fn=None):
         if not opts.git and not opts.nodates:
@@ -210,7 +210,7 @@  def unidiff(a, ad, b, bd, fn1, fn2, opts
             return '\t'
         return ''
 
-    sentinel = [], ""
+    sentinel = [], ()
     if not a and not b:
         return sentinel
 
@@ -235,7 +235,7 @@  def unidiff(a, ad, b, bd, fn1, fn2, opts
         if a and b and len(a) == len(b) and a == b:
             return sentinel
         headerlines = []
-        l = ['Binary file %s has changed\n' % fn1]
+        hunks = (None, ['Binary file %s has changed\n' % fn1]),
     elif not a:
         b = splitnewlines(b)
         if a is None:
@@ -244,7 +244,10 @@  def unidiff(a, ad, b, bd, fn1, fn2, opts
             l1 = "--- %s%s%s" % (aprefix, fn1, datetag(ad, fn1))
         l2 = "+++ %s%s" % (bprefix + fn2, datetag(bd, fn2))
         headerlines = [l1, l2]
-        l = ["@@ -0,0 +1,%d @@\n" % len(b)] + ["+" + e for e in b]
+        size = len(b)
+        hunkrange = (0, 0, 1, size)
+        hunklines = ["@@ -0,0 +1,%d @@\n" % size] + ["+" + e for e in b]
+        hunks = (hunkrange, checknonewline(hunklines)),
     elif not b:
         a = splitnewlines(a)
         l1 = "--- %s%s%s" % (aprefix, fn1, datetag(ad, fn1))
@@ -253,18 +256,29 @@  def unidiff(a, ad, b, bd, fn1, fn2, opts
         else:
             l2 = "+++ %s%s%s" % (bprefix, fn2, datetag(bd, fn2))
         headerlines = [l1, l2]
-        l = ["@@ -1,%d +0,0 @@\n" % len(a)] + ["-" + e for e in a]
+        size = len(a)
+        hunkrange = (1, size, 0, 0)
+        hunklines = ["@@ -1,%d +0,0 @@\n" % size] + ["-" + e for e in a]
+        hunks = (hunkrange, checknonewline(hunklines)),
     else:
-        l = sum((hlines for hrange, hlines in _unidiff(a, b, opts=opts)), [])
-        if not l:
+        diffhunks = _unidiff(a, b, opts=opts)
+        try:
+            hunkrange, hunklines = next(diffhunks)
+        except StopIteration:
             return sentinel
 
         headerlines = [
             "--- %s%s%s" % (aprefix, fn1, datetag(ad, fn1)),
             "+++ %s%s%s" % (bprefix, fn2, datetag(bd, fn2)),
         ]
+        def rewindhunks():
+            yield hunkrange, checknonewline(hunklines)
+            for hr, hl in diffhunks:
+                yield hr, checknonewline(hl)
 
-    return headerlines, "".join(checknonewline(l))
+        hunks = rewindhunks()
+
+    return headerlines, hunks
 
 def _unidiff(t1, t2, opts=defaultopts):
     """Yield hunks of a headerless unified diff from t1 and t2 texts.
diff --git a/mercurial/patch.py b/mercurial/patch.py
--- a/mercurial/patch.py
+++ b/mercurial/patch.py
@@ -2547,10 +2547,11 @@  def trydiff(repo, revs, ctx1, ctx2, modi
                                gitindex(content2)[0:opts.index],
                                gitmode[flag]))
 
-            uheaders, text = mdiff.unidiff(content1, date1,
-                                           content2, date2,
-                                           path1, path2, opts=opts)
+            uheaders, hunks = mdiff.unidiff(content1, date1,
+                                            content2, date2,
+                                            path1, path2, opts=opts)
             header.extend(uheaders)
+            text = ''.join(sum((list(hlines) for hrange, hlines in hunks), []))
         if header and (text or len(header) > 1):
             yield '\n'.join(header) + '\n'
         if text: