diff mercurial/utils/stringutil.py @ 39405:0f549da54379

stringutil: teach pprint() to indent This will make data structure dumping in various places a bit easier to read and diff. Since I wanted this for `hg debugwireproto` output, I added indentation to it. A more advanced pretty printer implementation would conditionally add newlines if output is too long. But it is vastly simpler to be consistent and always add newlines when indenting. Again, I'm not crazy about the verbosity of the code and there is room to consolidate logic for "print a collection." But this isn't the most complicated code in the world and I'm not convinced it is worth doing. Differential Revision: https://phab.mercurial-scm.org/D4399
author Gregory Szorc <gregory.szorc@gmail.com>
date Mon, 27 Aug 2018 09:13:58 -0700
parents 5ed7c6caf24d
children f2fbd32c7664
line wrap: on
line diff
--- a/mercurial/utils/stringutil.py	Wed Aug 22 08:20:51 2018 +0800
+++ b/mercurial/utils/stringutil.py	Mon Aug 27 09:13:58 2018 -0700
@@ -43,12 +43,20 @@
         return pat
     return pat.encode('latin1')
 
-def pprint(o, bprefix=False):
+def pprint(o, bprefix=False, indent=0):
     """Pretty print an object."""
-    return b''.join(pprintgen(o, bprefix=bprefix))
+    return b''.join(pprintgen(o, bprefix=bprefix, indent=indent))
+
+def pprintgen(o, bprefix=False, indent=0, _level=1):
+    """Pretty print an object to a generator of atoms.
 
-def pprintgen(o, bprefix=False):
-    """Pretty print an object to a generator of atoms."""
+    ``bprefix`` is a flag influencing whether bytestrings are preferred with
+    a ``b''`` prefix.
+
+    ``indent`` controls whether collections and nested data structures
+    span multiple lines via the indentation amount in spaces. By default,
+    no newlines are emitted.
+    """
 
     if isinstance(o, bytes):
         if bprefix:
@@ -66,12 +74,25 @@
 
         yield '['
 
+        if indent:
+            yield '\n'
+            yield ' ' * (_level * indent)
+
         for i, a in enumerate(o):
-            for chunk in pprintgen(a, bprefix=bprefix):
+            for chunk in pprintgen(a, bprefix=bprefix, indent=indent,
+                                   _level=_level + 1):
                 yield chunk
 
             if i + 1 < len(o):
-                yield ', '
+                if indent:
+                    yield ',\n'
+                    yield ' ' * (_level * indent)
+                else:
+                    yield ', '
+
+        if indent:
+            yield '\n'
+            yield ' ' * ((_level - 1) * indent)
 
         yield ']'
     elif isinstance(o, dict):
@@ -81,17 +102,31 @@
 
         yield '{'
 
+        if indent:
+            yield '\n'
+            yield ' ' * (_level * indent)
+
         for i, (k, v) in enumerate(sorted(o.items())):
-            for chunk in pprintgen(k, bprefix=bprefix):
+            for chunk in pprintgen(k, bprefix=bprefix, indent=indent,
+                                   _level=_level + 1):
                 yield chunk
 
             yield ': '
 
-            for chunk in pprintgen(v, bprefix=bprefix):
+            for chunk in pprintgen(v, bprefix=bprefix, indent=indent,
+                                   _level=_level + 1):
                 yield chunk
 
             if i + 1 < len(o):
-                yield ', '
+                if indent:
+                    yield ',\n'
+                    yield ' ' * (_level * indent)
+                else:
+                    yield ', '
+
+        if indent:
+            yield '\n'
+            yield ' ' * ((_level - 1) * indent)
 
         yield '}'
     elif isinstance(o, set):
@@ -101,12 +136,25 @@
 
         yield 'set(['
 
+        if indent:
+            yield '\n'
+            yield ' ' * (_level * indent)
+
         for i, k in enumerate(sorted(o)):
-            for chunk in pprintgen(k, bprefix=bprefix):
+            for chunk in pprintgen(k, bprefix=bprefix, indent=indent,
+                                   _level=_level + 1):
                 yield chunk
 
             if i + 1 < len(o):
-                yield ', '
+                if indent:
+                    yield ',\n'
+                    yield ' ' * (_level * indent)
+                else:
+                    yield ', '
+
+        if indent:
+            yield '\n'
+            yield ' ' * ((_level - 1) * indent)
 
         yield '])'
     elif isinstance(o, tuple):
@@ -116,12 +164,25 @@
 
         yield '('
 
+        if indent:
+            yield '\n'
+            yield ' ' * (_level * indent)
+
         for i, a in enumerate(o):
-            for chunk in pprintgen(a, bprefix=bprefix):
+            for chunk in pprintgen(a, bprefix=bprefix, indent=indent,
+                                   _level=_level + 1):
                 yield chunk
 
             if i + 1 < len(o):
-                yield ', '
+                if indent:
+                    yield ',\n'
+                    yield ' ' * (_level * indent)
+                else:
+                    yield ', '
+
+        if indent:
+            yield '\n'
+            yield ' ' * ((_level - 1) * indent)
 
         yield ')'
     elif isinstance(o, types.GeneratorType):
@@ -134,6 +195,10 @@
 
         yield 'gen['
 
+        if indent:
+            yield '\n'
+            yield ' ' * (_level * indent)
+
         last = False
 
         while not last:
@@ -144,11 +209,20 @@
             except StopIteration:
                 last = True
 
-            for chunk in pprintgen(current, bprefix=bprefix):
+            for chunk in pprintgen(current, bprefix=bprefix, indent=indent,
+                                   _level=_level + 1):
                 yield chunk
 
             if not last:
-                yield ', '
+                if indent:
+                    yield ',\n'
+                    yield ' ' * (_level * indent)
+                else:
+                    yield ', '
+
+        if indent:
+            yield '\n'
+            yield ' ' * ((_level -1) * indent)
 
         yield ']'
     else: