diff options
| author | Raymond Hettinger <python@rcn.com> | 2011-04-12 22:48:25 (GMT) | 
|---|---|---|
| committer | Raymond Hettinger <python@rcn.com> | 2011-04-12 22:48:25 (GMT) | 
| commit | 7c9d34722db06cac1042c7a3ae0deb92c2b41dfb (patch) | |
| tree | 85d77b3fbd6d0d0fe7cd347955049a1491b9e3e2 /Lib/difflib.py | |
| parent | d92232976e1cdc77a28d28b94b897c37e847492b (diff) | |
| download | cpython-7c9d34722db06cac1042c7a3ae0deb92c2b41dfb.zip cpython-7c9d34722db06cac1042c7a3ae0deb92c2b41dfb.tar.gz cpython-7c9d34722db06cac1042c7a3ae0deb92c2b41dfb.tar.bz2  | |
Issue 11747: Fix output format for context diffs.
Diffstat (limited to 'Lib/difflib.py')
| -rw-r--r-- | Lib/difflib.py | 89 | 
1 files changed, 61 insertions, 28 deletions
diff --git a/Lib/difflib.py b/Lib/difflib.py index b1f92d6..3bbcb76 100644 --- a/Lib/difflib.py +++ b/Lib/difflib.py @@ -1140,6 +1140,21 @@ def IS_CHARACTER_JUNK(ch, ws=" \t"):      return ch in ws +######################################################################## +###  Unified Diff +######################################################################## + +def _format_range_unified(start, stop): +    'Convert range to the "ed" format' +    # Per the diff spec at http://www.unix.org/single_unix_specification/ +    beginning = start + 1     # lines start numbering with one +    length = stop - start +    if length == 1: +        return '{}'.format(beginning) +    if not length: +        beginning -= 1        # empty ranges begin at line just before the range +    return '{},{}'.format(beginning, length) +  def unified_diff(a, b, fromfile='', tofile='', fromfiledate='',                   tofiledate='', n=3, lineterm='\n'):      r""" @@ -1184,25 +1199,45 @@ def unified_diff(a, b, fromfile='', tofile='', fromfiledate='',      started = False      for group in SequenceMatcher(None,a,b).get_grouped_opcodes(n):          if not started: -            fromdate = '\t%s' % fromfiledate if fromfiledate else '' -            todate = '\t%s' % tofiledate if tofiledate else '' -            yield '--- %s%s%s' % (fromfile, fromdate, lineterm) -            yield '+++ %s%s%s' % (tofile, todate, lineterm)              started = True -        i1, i2, j1, j2 = group[0][1], group[-1][2], group[0][3], group[-1][4] -        yield "@@ -%d,%d +%d,%d @@%s" % (i1+1, i2-i1, j1+1, j2-j1, lineterm) +            fromdate = '\t{}'.format(fromfiledate) if fromfiledate else '' +            todate = '\t{}'.format(tofiledate) if tofiledate else '' +            yield '--- {}{}{}'.format(fromfile, fromdate, lineterm) +            yield '+++ {}{}{}'.format(tofile, todate, lineterm) + +        first, last = group[0], group[-1] +        file1_range = _format_range_unified(first[1], last[2]) +        file2_range = _format_range_unified(first[3], last[4]) +        yield '@@ -{} +{} @@{}'.format(file1_range, file2_range, lineterm) +          for tag, i1, i2, j1, j2 in group:              if tag == 'equal':                  for line in a[i1:i2]:                      yield ' ' + line                  continue -            if tag == 'replace' or tag == 'delete': +            if tag in ('replace', 'delete'):                  for line in a[i1:i2]:                      yield '-' + line -            if tag == 'replace' or tag == 'insert': +            if tag in ('replace', 'insert'):                  for line in b[j1:j2]:                      yield '+' + line + +######################################################################## +###  Context Diff +######################################################################## + +def _format_range_context(start, stop): +    'Convert range to the "ed" format' +    # Per the diff spec at http://www.unix.org/single_unix_specification/ +    beginning = start + 1     # lines start numbering with one +    length = stop - start +    if not length: +        beginning -= 1        # empty ranges begin at line just before the range +    if length <= 1: +        return '{}'.format(beginning) +    return '{},{}'.format(beginning, beginning + length - 1) +  # See http://www.unix.org/single_unix_specification/  def context_diff(a, b, fromfile='', tofile='',                   fromfiledate='', tofiledate='', n=3, lineterm='\n'): @@ -1247,38 +1282,36 @@ def context_diff(a, b, fromfile='', tofile='',        four      """ +    prefix = dict(insert='+ ', delete='- ', replace='! ', equal='  ')      started = False -    prefixmap = {'insert':'+ ', 'delete':'- ', 'replace':'! ', 'equal':'  '}      for group in SequenceMatcher(None,a,b).get_grouped_opcodes(n):          if not started: -            fromdate = '\t%s' % fromfiledate if fromfiledate else '' -            todate = '\t%s' % tofiledate if tofiledate else '' -            yield '*** %s%s%s' % (fromfile, fromdate, lineterm) -            yield '--- %s%s%s' % (tofile, todate, lineterm)              started = True +            fromdate = '\t{}'.format(fromfiledate) if fromfiledate else '' +            todate = '\t{}'.format(tofiledate) if tofiledate else '' +            yield '*** {}{}{}'.format(fromfile, fromdate, lineterm) +            yield '--- {}{}{}'.format(tofile, todate, lineterm) -        yield '***************%s' % (lineterm,) -        if group[-1][2] - group[0][1] >= 2: -            yield '*** %d,%d ****%s' % (group[0][1]+1, group[-1][2], lineterm) -        else: -            yield '*** %d ****%s' % (group[-1][2], lineterm) -        visiblechanges = [e for e in group if e[0] in ('replace', 'delete')] -        if visiblechanges: +        first, last = group[0], group[-1] +        yield '***************' + lineterm + +        file1_range = _format_range_context(first[1], last[2]) +        yield '*** {} ****{}'.format(file1_range, lineterm) + +        if any(tag in ('replace', 'delete') for tag, _, _, _, _ in group):              for tag, i1, i2, _, _ in group:                  if tag != 'insert':                      for line in a[i1:i2]: -                        yield prefixmap[tag] + line +                        yield prefix[tag] + line -        if group[-1][4] - group[0][3] >= 2: -            yield '--- %d,%d ----%s' % (group[0][3]+1, group[-1][4], lineterm) -        else: -            yield '--- %d ----%s' % (group[-1][4], lineterm) -        visiblechanges = [e for e in group if e[0] in ('replace', 'insert')] -        if visiblechanges: +        file2_range = _format_range_context(first[3], last[4]) +        yield '--- {} ----{}'.format(file2_range, lineterm) + +        if any(tag in ('replace', 'insert') for tag, _, _, _, _ in group):              for tag, _, _, j1, j2 in group:                  if tag != 'delete':                      for line in b[j1:j2]: -                        yield prefixmap[tag] + line +                        yield prefix[tag] + line  def ndiff(a, b, linejunk=None, charjunk=IS_CHARACTER_JUNK):      r"""  | 
