comparison mercurial/utils/stringutil.py @ 39378: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
comparison
equal deleted inserted replaced
39377:b4e7e1f09c09 39378:0f549da54379
41 pat = pat.translate(_regexescapemap) 41 pat = pat.translate(_regexescapemap)
42 if wantuni: 42 if wantuni:
43 return pat 43 return pat
44 return pat.encode('latin1') 44 return pat.encode('latin1')
45 45
46 def pprint(o, bprefix=False): 46 def pprint(o, bprefix=False, indent=0):
47 """Pretty print an object.""" 47 """Pretty print an object."""
48 return b''.join(pprintgen(o, bprefix=bprefix)) 48 return b''.join(pprintgen(o, bprefix=bprefix, indent=indent))
49 49
50 def pprintgen(o, bprefix=False): 50 def pprintgen(o, bprefix=False, indent=0, _level=1):
51 """Pretty print an object to a generator of atoms.""" 51 """Pretty print an object to a generator of atoms.
52
53 ``bprefix`` is a flag influencing whether bytestrings are preferred with
54 a ``b''`` prefix.
55
56 ``indent`` controls whether collections and nested data structures
57 span multiple lines via the indentation amount in spaces. By default,
58 no newlines are emitted.
59 """
52 60
53 if isinstance(o, bytes): 61 if isinstance(o, bytes):
54 if bprefix: 62 if bprefix:
55 yield "b'%s'" % escapestr(o) 63 yield "b'%s'" % escapestr(o)
56 else: 64 else:
64 yield '[]' 72 yield '[]'
65 return 73 return
66 74
67 yield '[' 75 yield '['
68 76
77 if indent:
78 yield '\n'
79 yield ' ' * (_level * indent)
80
69 for i, a in enumerate(o): 81 for i, a in enumerate(o):
70 for chunk in pprintgen(a, bprefix=bprefix): 82 for chunk in pprintgen(a, bprefix=bprefix, indent=indent,
83 _level=_level + 1):
71 yield chunk 84 yield chunk
72 85
73 if i + 1 < len(o): 86 if i + 1 < len(o):
74 yield ', ' 87 if indent:
88 yield ',\n'
89 yield ' ' * (_level * indent)
90 else:
91 yield ', '
92
93 if indent:
94 yield '\n'
95 yield ' ' * ((_level - 1) * indent)
75 96
76 yield ']' 97 yield ']'
77 elif isinstance(o, dict): 98 elif isinstance(o, dict):
78 if not o: 99 if not o:
79 yield '{}' 100 yield '{}'
80 return 101 return
81 102
82 yield '{' 103 yield '{'
83 104
105 if indent:
106 yield '\n'
107 yield ' ' * (_level * indent)
108
84 for i, (k, v) in enumerate(sorted(o.items())): 109 for i, (k, v) in enumerate(sorted(o.items())):
85 for chunk in pprintgen(k, bprefix=bprefix): 110 for chunk in pprintgen(k, bprefix=bprefix, indent=indent,
111 _level=_level + 1):
86 yield chunk 112 yield chunk
87 113
88 yield ': ' 114 yield ': '
89 115
90 for chunk in pprintgen(v, bprefix=bprefix): 116 for chunk in pprintgen(v, bprefix=bprefix, indent=indent,
117 _level=_level + 1):
91 yield chunk 118 yield chunk
92 119
93 if i + 1 < len(o): 120 if i + 1 < len(o):
94 yield ', ' 121 if indent:
122 yield ',\n'
123 yield ' ' * (_level * indent)
124 else:
125 yield ', '
126
127 if indent:
128 yield '\n'
129 yield ' ' * ((_level - 1) * indent)
95 130
96 yield '}' 131 yield '}'
97 elif isinstance(o, set): 132 elif isinstance(o, set):
98 if not o: 133 if not o:
99 yield 'set([])' 134 yield 'set([])'
100 return 135 return
101 136
102 yield 'set([' 137 yield 'set(['
103 138
139 if indent:
140 yield '\n'
141 yield ' ' * (_level * indent)
142
104 for i, k in enumerate(sorted(o)): 143 for i, k in enumerate(sorted(o)):
105 for chunk in pprintgen(k, bprefix=bprefix): 144 for chunk in pprintgen(k, bprefix=bprefix, indent=indent,
145 _level=_level + 1):
106 yield chunk 146 yield chunk
107 147
108 if i + 1 < len(o): 148 if i + 1 < len(o):
109 yield ', ' 149 if indent:
150 yield ',\n'
151 yield ' ' * (_level * indent)
152 else:
153 yield ', '
154
155 if indent:
156 yield '\n'
157 yield ' ' * ((_level - 1) * indent)
110 158
111 yield '])' 159 yield '])'
112 elif isinstance(o, tuple): 160 elif isinstance(o, tuple):
113 if not o: 161 if not o:
114 yield '()' 162 yield '()'
115 return 163 return
116 164
117 yield '(' 165 yield '('
118 166
167 if indent:
168 yield '\n'
169 yield ' ' * (_level * indent)
170
119 for i, a in enumerate(o): 171 for i, a in enumerate(o):
120 for chunk in pprintgen(a, bprefix=bprefix): 172 for chunk in pprintgen(a, bprefix=bprefix, indent=indent,
173 _level=_level + 1):
121 yield chunk 174 yield chunk
122 175
123 if i + 1 < len(o): 176 if i + 1 < len(o):
124 yield ', ' 177 if indent:
178 yield ',\n'
179 yield ' ' * (_level * indent)
180 else:
181 yield ', '
182
183 if indent:
184 yield '\n'
185 yield ' ' * ((_level - 1) * indent)
125 186
126 yield ')' 187 yield ')'
127 elif isinstance(o, types.GeneratorType): 188 elif isinstance(o, types.GeneratorType):
128 # Special case of empty generator. 189 # Special case of empty generator.
129 try: 190 try:
132 yield 'gen[]' 193 yield 'gen[]'
133 return 194 return
134 195
135 yield 'gen[' 196 yield 'gen['
136 197
198 if indent:
199 yield '\n'
200 yield ' ' * (_level * indent)
201
137 last = False 202 last = False
138 203
139 while not last: 204 while not last:
140 current = nextitem 205 current = nextitem
141 206
142 try: 207 try:
143 nextitem = next(o) 208 nextitem = next(o)
144 except StopIteration: 209 except StopIteration:
145 last = True 210 last = True
146 211
147 for chunk in pprintgen(current, bprefix=bprefix): 212 for chunk in pprintgen(current, bprefix=bprefix, indent=indent,
213 _level=_level + 1):
148 yield chunk 214 yield chunk
149 215
150 if not last: 216 if not last:
151 yield ', ' 217 if indent:
218 yield ',\n'
219 yield ' ' * (_level * indent)
220 else:
221 yield ', '
222
223 if indent:
224 yield '\n'
225 yield ' ' * ((_level -1) * indent)
152 226
153 yield ']' 227 yield ']'
154 else: 228 else:
155 yield pycompat.byterepr(o) 229 yield pycompat.byterepr(o)
156 230