mercurial/mdiff.py
changeset 35851 a9d07bd8f758
parent 35850 079b27b5a869
child 35852 6a33e81e4c5e
equal deleted inserted replaced
35850:079b27b5a869 35851:a9d07bd8f758
    16     error,
    16     error,
    17     policy,
    17     policy,
    18     pycompat,
    18     pycompat,
    19     util,
    19     util,
    20 )
    20 )
       
    21 
       
    22 _missing_newline_marker = "\\ No newline at end of file\n"
    21 
    23 
    22 bdiff = policy.importmod(r'bdiff')
    24 bdiff = policy.importmod(r'bdiff')
    23 mpatch = policy.importmod(r'mpatch')
    25 mpatch = policy.importmod(r'mpatch')
    24 
    26 
    25 blocks = bdiff.blocks
    27 blocks = bdiff.blocks
   265     epoch = util.datestr((0, 0))
   267     epoch = util.datestr((0, 0))
   266 
   268 
   267     fn1 = util.pconvert(fn1)
   269     fn1 = util.pconvert(fn1)
   268     fn2 = util.pconvert(fn2)
   270     fn2 = util.pconvert(fn2)
   269 
   271 
   270     def checknonewline(lines):
       
   271         for text in lines:
       
   272             if text[-1:] != '\n':
       
   273                 text += "\n\ No newline at end of file\n"
       
   274             yield text
       
   275 
       
   276     if not opts.text and check_binary and (util.binary(a) or util.binary(b)):
   272     if not opts.text and check_binary and (util.binary(a) or util.binary(b)):
   277         if a and b and len(a) == len(b) and a == b:
   273         if a and b and len(a) == len(b) and a == b:
   278             return sentinel
   274             return sentinel
   279         headerlines = []
   275         headerlines = []
   280         hunks = (None, ['Binary file %s has changed\n' % fn1]),
   276         hunks = (None, ['Binary file %s has changed\n' % fn1]),
   281     elif not a:
   277     elif not a:
       
   278         without_newline = b[-1] != '\n'
   282         b = splitnewlines(b)
   279         b = splitnewlines(b)
   283         if a is None:
   280         if a is None:
   284             l1 = '--- /dev/null%s' % datetag(epoch)
   281             l1 = '--- /dev/null%s' % datetag(epoch)
   285         else:
   282         else:
   286             l1 = "--- %s%s%s" % (aprefix, fn1, datetag(ad, fn1))
   283             l1 = "--- %s%s%s" % (aprefix, fn1, datetag(ad, fn1))
   287         l2 = "+++ %s%s" % (bprefix + fn2, datetag(bd, fn2))
   284         l2 = "+++ %s%s" % (bprefix + fn2, datetag(bd, fn2))
   288         headerlines = [l1, l2]
   285         headerlines = [l1, l2]
   289         size = len(b)
   286         size = len(b)
   290         hunkrange = (0, 0, 1, size)
   287         hunkrange = (0, 0, 1, size)
   291         hunklines = ["@@ -0,0 +1,%d @@\n" % size] + ["+" + e for e in b]
   288         hunklines = ["@@ -0,0 +1,%d @@\n" % size] + ["+" + e for e in b]
   292         hunks = (hunkrange, checknonewline(hunklines)),
   289         if without_newline:
       
   290             hunklines[-1] += '\n'
       
   291             hunklines.append(_missing_newline_marker)
       
   292         hunks = (hunkrange, hunklines),
   293     elif not b:
   293     elif not b:
       
   294         without_newline = a[-1] != '\n'
   294         a = splitnewlines(a)
   295         a = splitnewlines(a)
   295         l1 = "--- %s%s%s" % (aprefix, fn1, datetag(ad, fn1))
   296         l1 = "--- %s%s%s" % (aprefix, fn1, datetag(ad, fn1))
   296         if b is None:
   297         if b is None:
   297             l2 = '+++ /dev/null%s' % datetag(epoch)
   298             l2 = '+++ /dev/null%s' % datetag(epoch)
   298         else:
   299         else:
   299             l2 = "+++ %s%s%s" % (bprefix, fn2, datetag(bd, fn2))
   300             l2 = "+++ %s%s%s" % (bprefix, fn2, datetag(bd, fn2))
   300         headerlines = [l1, l2]
   301         headerlines = [l1, l2]
   301         size = len(a)
   302         size = len(a)
   302         hunkrange = (1, size, 0, 0)
   303         hunkrange = (1, size, 0, 0)
   303         hunklines = ["@@ -1,%d +0,0 @@\n" % size] + ["-" + e for e in a]
   304         hunklines = ["@@ -1,%d +0,0 @@\n" % size] + ["-" + e for e in a]
   304         hunks = (hunkrange, checknonewline(hunklines)),
   305         if without_newline:
       
   306             hunklines[-1] += '\n'
       
   307             hunklines.append(_missing_newline_marker)
       
   308         hunks = (hunkrange, hunklines),
   305     else:
   309     else:
   306         diffhunks = _unidiff(a, b, opts=opts)
   310         diffhunks = _unidiff(a, b, opts=opts)
   307         try:
   311         try:
   308             hunkrange, hunklines = next(diffhunks)
   312             hunkrange, hunklines = next(diffhunks)
   309         except StopIteration:
   313         except StopIteration:
   312         headerlines = [
   316         headerlines = [
   313             "--- %s%s%s" % (aprefix, fn1, datetag(ad, fn1)),
   317             "--- %s%s%s" % (aprefix, fn1, datetag(ad, fn1)),
   314             "+++ %s%s%s" % (bprefix, fn2, datetag(bd, fn2)),
   318             "+++ %s%s%s" % (bprefix, fn2, datetag(bd, fn2)),
   315         ]
   319         ]
   316         def rewindhunks():
   320         def rewindhunks():
   317             yield hunkrange, checknonewline(hunklines)
   321             yield hunkrange, hunklines
   318             for hr, hl in diffhunks:
   322             for hr, hl in diffhunks:
   319                 yield hr, checknonewline(hl)
   323                 yield hr, hl
   320 
   324 
   321         hunks = rewindhunks()
   325         hunks = rewindhunks()
   322 
   326 
   323     return headerlines, hunks
   327     return headerlines, hunks
   324 
   328 
   328     Each hunk consists of a (hunkrange, hunklines) tuple where `hunkrange` is a
   332     Each hunk consists of a (hunkrange, hunklines) tuple where `hunkrange` is a
   329     tuple (s1, l1, s2, l2) representing the range information of the hunk to
   333     tuple (s1, l1, s2, l2) representing the range information of the hunk to
   330     form the '@@ -s1,l1 +s2,l2 @@' header and `hunklines` is a list of lines
   334     form the '@@ -s1,l1 +s2,l2 @@' header and `hunklines` is a list of lines
   331     of the hunk combining said header followed by line additions and
   335     of the hunk combining said header followed by line additions and
   332     deletions.
   336     deletions.
       
   337 
       
   338     The hunks are prefixed with a bool.
   333     """
   339     """
   334     l1 = splitnewlines(t1)
   340     l1 = splitnewlines(t1)
   335     l2 = splitnewlines(t2)
   341     l2 = splitnewlines(t2)
   336     def contextend(l, len):
   342     def contextend(l, len):
   337         ret = l + opts.context
   343         ret = l + opts.context
   378         hunklines = (
   384         hunklines = (
   379             ["@@ -%d,%d +%d,%d @@%s\n" % (hunkrange + (func,))]
   385             ["@@ -%d,%d +%d,%d @@%s\n" % (hunkrange + (func,))]
   380             + delta
   386             + delta
   381             + [' ' + l1[x] for x in xrange(a2, aend)]
   387             + [' ' + l1[x] for x in xrange(a2, aend)]
   382         )
   388         )
       
   389         # If either file ends without a newline and the last line of
       
   390         # that file is part of a hunk, a marker is printed. If the
       
   391         # last line of both files is identical and neither ends in
       
   392         # a newline, print only one marker. That's the only case in
       
   393         # which the hunk can end in a shared line without a newline.
       
   394         skip = False
       
   395         if t1[-1] != '\n' and astart + alen == len(l1) + 1:
       
   396             for i in xrange(len(hunklines) - 1, -1, -1):
       
   397                 if hunklines[i][0] in ('-', ' '):
       
   398                     if hunklines[i][0] == ' ':
       
   399                         skip = True
       
   400                     hunklines[i] += '\n'
       
   401                     hunklines.insert(i + 1, _missing_newline_marker)
       
   402                     break
       
   403         if not skip and t2[-1] != '\n' and bstart + blen == len(l2) + 1:
       
   404             for i in xrange(len(hunklines) - 1, -1, -1):
       
   405                 if hunklines[i][0] == '+':
       
   406                     hunklines[i] += '\n'
       
   407                     hunklines.insert(i + 1, _missing_newline_marker)
       
   408                     break
   383         yield hunkrange, hunklines
   409         yield hunkrange, hunklines
   384 
   410 
   385     # bdiff.blocks gives us the matching sequences in the files.  The loop
   411     # bdiff.blocks gives us the matching sequences in the files.  The loop
   386     # below finds the spaces between those matching sequences and translates
   412     # below finds the spaces between those matching sequences and translates
   387     # them into diff output.
   413     # them into diff output.