Mercurial > hg
comparison mercurial/graphmod.py @ 43776:faa8a59f4a06
graphlog: change state dict to attr struct
This should help static analysis.
author | Yuya Nishihara <yuya@tcha.org> |
---|---|
date | Thu, 21 Nov 2019 22:43:01 +0900 |
parents | 687b865b95ad |
children | 9d2b2df2c2ba |
comparison
equal
deleted
inserted
replaced
43775:b5f183eedd98 | 43776:faa8a59f4a06 |
---|---|
18 """ | 18 """ |
19 | 19 |
20 from __future__ import absolute_import | 20 from __future__ import absolute_import |
21 | 21 |
22 from .node import nullrev | 22 from .node import nullrev |
23 from .thirdparty import attr | |
23 from . import ( | 24 from . import ( |
24 dagop, | 25 dagop, |
25 pycompat, | 26 pycompat, |
26 smartset, | 27 smartset, |
27 util, | 28 util, |
190 seen = next | 191 seen = next |
191 | 192 |
192 | 193 |
193 def asciiedges(type, char, state, rev, parents): | 194 def asciiedges(type, char, state, rev, parents): |
194 """adds edge info to changelog DAG walk suitable for ascii()""" | 195 """adds edge info to changelog DAG walk suitable for ascii()""" |
195 seen = state[b'seen'] | 196 seen = state.seen |
196 if rev not in seen: | 197 if rev not in seen: |
197 seen.append(rev) | 198 seen.append(rev) |
198 nodeidx = seen.index(rev) | 199 nodeidx = seen.index(rev) |
199 | 200 |
200 knownparents = [] | 201 knownparents = [] |
205 continue | 206 continue |
206 if parent in seen: | 207 if parent in seen: |
207 knownparents.append(parent) | 208 knownparents.append(parent) |
208 else: | 209 else: |
209 newparents.append(parent) | 210 newparents.append(parent) |
210 state[b'edges'][parent] = state[b'styles'].get(ptype, b'|') | 211 state.edges[parent] = state.styles.get(ptype, b'|') |
211 | 212 |
212 ncols = len(seen) | 213 ncols = len(seen) |
213 width = 1 + ncols * 2 | 214 width = 1 + ncols * 2 |
214 nextseen = seen[:] | 215 nextseen = seen[:] |
215 nextseen[nodeidx : nodeidx + 1] = newparents | 216 nextseen[nodeidx : nodeidx + 1] = newparents |
238 edges.append((nodeidx, nodeidx + 1)) | 239 edges.append((nodeidx, nodeidx + 1)) |
239 nmorecols = len(nextseen) - ncols | 240 nmorecols = len(nextseen) - ncols |
240 if nmorecols > 0: | 241 if nmorecols > 0: |
241 width += 2 | 242 width += 2 |
242 # remove current node from edge characters, no longer needed | 243 # remove current node from edge characters, no longer needed |
243 state[b'edges'].pop(rev, None) | 244 state.edges.pop(rev, None) |
244 yield (type, char, width, (nodeidx, edges, ncols, nmorecols)) | 245 yield (type, char, width, (nodeidx, edges, ncols, nmorecols)) |
245 | 246 |
246 | 247 |
247 def _fixlongrightedges(edges): | 248 def _fixlongrightedges(edges): |
248 for (i, (start, end)) in enumerate(edges): | 249 for (i, (start, end)) in enumerate(edges): |
320 # We need enough space to draw adjustment lines for these. | 321 # We need enough space to draw adjustment lines for these. |
321 edgechars = extra[::2] | 322 edgechars = extra[::2] |
322 while edgechars and edgechars[-1] is None: | 323 while edgechars and edgechars[-1] is None: |
323 edgechars.pop() | 324 edgechars.pop() |
324 shift_size = max((edgechars.count(None) * 2) - 1, 0) | 325 shift_size = max((edgechars.count(None) * 2) - 1, 0) |
325 minlines = 3 if not state[b'graphshorten'] else 2 | 326 minlines = 3 if not state.graphshorten else 2 |
326 while len(lines) < minlines + shift_size: | 327 while len(lines) < minlines + shift_size: |
327 lines.append(extra[:]) | 328 lines.append(extra[:]) |
328 | 329 |
329 if shift_size: | 330 if shift_size: |
330 empties = [] | 331 empties = [] |
342 for i in range(len(positions)): | 343 for i in range(len(positions)): |
343 pos = positions[i] - 1 | 344 pos = positions[i] - 1 |
344 positions[i] = max(pos, targets[i]) | 345 positions[i] = max(pos, targets[i]) |
345 line[pos] = b'/' if pos > targets[i] else extra[toshift[i]] | 346 line[pos] = b'/' if pos > targets[i] else extra[toshift[i]] |
346 | 347 |
347 map = {1: b'|', 2: b'~'} if not state[b'graphshorten'] else {1: b'~'} | 348 map = {1: b'|', 2: b'~'} if not state.graphshorten else {1: b'~'} |
348 for i, line in enumerate(lines): | 349 for i, line in enumerate(lines): |
349 if None not in line: | 350 if None not in line: |
350 continue | 351 continue |
351 line[:] = [c or map.get(i, b' ') for c in line] | 352 line[:] = [c or map.get(i, b' ') for c in line] |
352 | 353 |
355 for parent in remove: | 356 for parent in remove: |
356 del edgemap[parent] | 357 del edgemap[parent] |
357 seen.remove(parent) | 358 seen.remove(parent) |
358 | 359 |
359 | 360 |
360 def asciistate(): | 361 @attr.s |
361 """returns the initial value for the "state" argument to ascii()""" | 362 class asciistate(object): |
362 return { | 363 """State of ascii() graph rendering""" |
363 b'seen': [], | 364 |
364 b'edges': {}, | 365 seen = attr.ib(init=False, default=attr.Factory(list)) |
365 b'lastcoldiff': 0, | 366 edges = attr.ib(init=False, default=attr.Factory(dict)) |
366 b'lastindex': 0, | 367 lastcoldiff = attr.ib(init=False, default=0) |
367 b'styles': EDGES.copy(), | 368 lastindex = attr.ib(init=False, default=0) |
368 b'graphshorten': False, | 369 styles = attr.ib(init=False, default=attr.Factory(EDGES.copy)) |
369 } | 370 graphshorten = attr.ib(init=False, default=False) |
370 | 371 |
371 | 372 |
372 def outputgraph(ui, graph): | 373 def outputgraph(ui, graph): |
373 """outputs an ASCII graph of a DAG | 374 """outputs an ASCII graph of a DAG |
374 | 375 |
407 0 means no columns added or removed; 1 means one column added. | 408 0 means no columns added or removed; 1 means one column added. |
408 """ | 409 """ |
409 idx, edges, ncols, coldiff = coldata | 410 idx, edges, ncols, coldiff = coldata |
410 assert -2 < coldiff < 2 | 411 assert -2 < coldiff < 2 |
411 | 412 |
412 edgemap, seen = state[b'edges'], state[b'seen'] | 413 edgemap, seen = state.edges, state.seen |
413 # Be tolerant of history issues; make sure we have at least ncols + coldiff | 414 # Be tolerant of history issues; make sure we have at least ncols + coldiff |
414 # elements to work with. See test-glog.t for broken history test cases. | 415 # elements to work with. See test-glog.t for broken history test cases. |
415 echars = [c for p in seen for c in (edgemap.get(p, b'|'), b' ')] | 416 echars = [c for p in seen for c in (edgemap.get(p, b'|'), b' ')] |
416 echars.extend((b'|', b' ') * max(ncols + coldiff - len(seen), 0)) | 417 echars.extend((b'|', b' ') * max(ncols + coldiff - len(seen), 0)) |
417 | 418 |
450 | 451 |
451 nodeline.extend( | 452 nodeline.extend( |
452 _getnodelineedgestail( | 453 _getnodelineedgestail( |
453 echars, | 454 echars, |
454 idx, | 455 idx, |
455 state[b'lastindex'], | 456 state.lastindex, |
456 ncols, | 457 ncols, |
457 coldiff, | 458 coldiff, |
458 state[b'lastcoldiff'], | 459 state.lastcoldiff, |
459 fix_nodeline_tail, | 460 fix_nodeline_tail, |
460 ) | 461 ) |
461 ) | 462 ) |
462 | 463 |
463 # shift_interline is the line containing the non-vertical | 464 # shift_interline is the line containing the non-vertical |
483 if add_padding_line: | 484 if add_padding_line: |
484 lines.append(_getpaddingline(echars, idx, ncols, edges)) | 485 lines.append(_getpaddingline(echars, idx, ncols, edges)) |
485 | 486 |
486 # If 'graphshorten' config, only draw shift_interline | 487 # If 'graphshorten' config, only draw shift_interline |
487 # when there is any non vertical flow in graph. | 488 # when there is any non vertical flow in graph. |
488 if state[b'graphshorten']: | 489 if state.graphshorten: |
489 if any(c in br'\/' for c in shift_interline if c): | 490 if any(c in br'\/' for c in shift_interline if c): |
490 lines.append(shift_interline) | 491 lines.append(shift_interline) |
491 # Else, no 'graphshorten' config so draw shift_interline. | 492 # Else, no 'graphshorten' config so draw shift_interline. |
492 else: | 493 else: |
493 lines.append(shift_interline) | 494 lines.append(shift_interline) |
510 b"%-*s " % (2 * indentation_level, b"".join(line)) for line in lines | 511 b"%-*s " % (2 * indentation_level, b"".join(line)) for line in lines |
511 ] | 512 ] |
512 outputgraph(ui, zip(lines, text)) | 513 outputgraph(ui, zip(lines, text)) |
513 | 514 |
514 # ... and start over | 515 # ... and start over |
515 state[b'lastcoldiff'] = coldiff | 516 state.lastcoldiff = coldiff |
516 state[b'lastindex'] = idx | 517 state.lastindex = idx |