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. |