[PATCH 04 of 13] diff: make use of output labeling

Brodie Rao dackze at gmail.com
Wed Mar 31 10:00:40 CDT 2010


# HG changeset patch
# User Brodie Rao <brodie at bitheap.org>
# Date 1270046196 18000
# Node ID ae40415f9c4a6d3a6be4d4b9b4fb5a1a7d45079a
# Parent  39912057aad42b0f3b979edc2f0d9ea85741c5f1
diff: make use of output labeling

diff --git a/mercurial/commands.py b/mercurial/commands.py
--- a/mercurial/commands.py
+++ b/mercurial/commands.py
@@ -1174,14 +1174,16 @@ def diff(ui, repo, *pats, **opts):
     diffopts = patch.diffopts(ui, opts)
 
     m = cmdutil.match(repo, pats, opts)
-    it = patch.diff(repo, node1, node2, match=m, opts=diffopts)
     if stat:
+        it = patch.diff(repo, node1, node2, match=m, opts=diffopts)
         width = ui.interactive() and util.termwidth() or 80
-        ui.write(patch.diffstat(util.iterlines(it), width=width,
-                                git=diffopts.git))
+        for chunk, label in patch.diffstatui(util.iterlines(it), width=width,
+                                             git=diffopts.git):
+            ui.write(chunk, label=label)
     else:
-        for chunk in it:
-            ui.write(chunk)
+        it = patch.diffui(repo, node1, node2, match=m, opts=diffopts)
+        for chunk, label in it:
+            ui.write(chunk, label=label)
 
 def export(ui, repo, *changesets, **opts):
     """dump the header and diffs for one or more changesets
diff --git a/mercurial/patch.py b/mercurial/patch.py
--- a/mercurial/patch.py
+++ b/mercurial/patch.py
@@ -1466,6 +1466,43 @@ def diff(repo, node1=None, node2=None, m
     else:
         return difffn(opts, None)
 
+def difflabel(func, *args, **kw):
+    '''yields 2-tuples of (output, label) based on the output of func()'''
+    prefixes = [('diff', 'diff.diffline'),
+                ('copy', 'diff.extended'),
+                ('rename', 'diff.extended'),
+                ('old', 'diff.extended'),
+                ('new', 'diff.extended'),
+                ('deleted', 'diff.extended'),
+                ('---', 'diff.file_a'),
+                ('+++', 'diff.file_b'),
+                ('@@', 'diff.hunk'),
+                ('-', 'diff.deleted'),
+                ('+', 'diff.inserted')]
+
+    for chunk in func(*args, **kw):
+        lines = chunk.split('\n')
+        for i, line in enumerate(lines):
+            if i != 0:
+                yield ('\n', '')
+            stripline = line
+            if line and line[0] in '+-':
+                # highlight trailing whitespace, but only in changed lines
+                stripline = line.rstrip()
+            for prefix, label in prefixes:
+                if stripline.startswith(prefix):
+                    yield (stripline, label)
+                    break
+            else:
+                yield (line, '')
+            if line != stripline:
+                yield (line[len(stripline):], 'diff.trailingwhitespace')
+
+def diffui(*args, **kw):
+    '''like diff(), but yields 2-tuples of (output, label) for ui.write()'''
+    return difflabel(diff, *args, **kw)
+
+
 def _addmodehdr(header, omode, nmode):
     if omode != nmode:
         header.append('old mode %s\n' % omode)
@@ -1636,3 +1673,22 @@ def diffstat(lines, width=80, git=False)
                       % (len(stats), totaladds, totalremoves))
 
     return ''.join(output)
+
+def diffstatui(*args, **kw):
+    '''like diffstat(), but yields 2-tuples of (output, label) for
+    ui.write()
+    '''
+
+    for line in diffstat(*args, **kw).splitlines():
+        if line and line[-1] in '+-':
+            name, graph = line.rsplit(' ', 1)
+            yield (name + ' ', '')
+            m = re.search(r'\++', graph)
+            if m:
+                yield (m.group(0), 'diffstat.inserted')
+            m = re.search(r'-+', graph)
+            if m:
+                yield (m.group(0), 'diffstat.deleted')
+        else:
+            yield (line, '')
+        yield ('\n', '')


More information about the Mercurial-devel mailing list