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 "--- " and "+++ " and `hunkstext` is a string - containing diff hunks. Otherwise, both `headers` and `hunkstext` are - empty. + lines "--- " and "+++ " 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 @@ -2549,10 +2549,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: