##// END OF EJS Templates
graphmod: allow for different styles for different edge types...
Martijn Pieters -
r28600:0d613789 default
parent child Browse files
Show More
@@ -2218,6 +2218,15 b' def displaygraph(ui, repo, dag, displaye'
2218 filematcher=None):
2218 filematcher=None):
2219 formatnode = _graphnodeformatter(ui, displayer)
2219 formatnode = _graphnodeformatter(ui, displayer)
2220 state = graphmod.asciistate()
2220 state = graphmod.asciistate()
2221 styles = state['styles']
2222 edgetypes = {
2223 'parent': graphmod.PARENT,
2224 'grandparent': graphmod.GRANDPARENT,
2225 'missing': graphmod.MISSINGPARENT
2226 }
2227 for name, key in edgetypes.items():
2228 # experimental config: ui.graphstyle.*
2229 styles[key] = ui.config('ui', 'graphstyle.%s' % name, styles[key])
2221 for rev, type, ctx, parents in dag:
2230 for rev, type, ctx, parents in dag:
2222 char = formatnode(repo, ctx)
2231 char = formatnode(repo, ctx)
2223 copies = None
2232 copies = None
@@ -31,6 +31,7 b" CHANGESET = 'C'"
31 PARENT = 'P'
31 PARENT = 'P'
32 GRANDPARENT = 'G'
32 GRANDPARENT = 'G'
33 MISSINGPARENT = 'M'
33 MISSINGPARENT = 'M'
34 EDGES = {PARENT: '|', GRANDPARENT: '|', MISSINGPARENT: '|'}
34
35
35 def groupbranchiter(revs, parentsfunc, firstbranch=()):
36 def groupbranchiter(revs, parentsfunc, firstbranch=()):
36 """Yield revisions from heads to roots one (topo) branch at a time.
37 """Yield revisions from heads to roots one (topo) branch at a time.
@@ -390,11 +391,13 b' def asciiedges(type, char, lines, state,'
390 knownparents.append(parent)
391 knownparents.append(parent)
391 else:
392 else:
392 newparents.append(parent)
393 newparents.append(parent)
394 state['edges'][parent] = state['styles'].get(ptype, '|')
393
395
394 ncols = len(seen)
396 ncols = len(seen)
395 nextseen = seen[:]
397 nextseen = seen[:]
396 nextseen[nodeidx:nodeidx + 1] = newparents
398 nextseen[nodeidx:nodeidx + 1] = newparents
397 edges = [(nodeidx, nextseen.index(p)) for p in knownparents if p != nullrev]
399 edges = [(nodeidx, nextseen.index(p))
400 for p in knownparents if p != nullrev]
398
401
399 while len(newparents) > 2:
402 while len(newparents) > 2:
400 # ascii() only knows how to add or remove a single column between two
403 # ascii() only knows how to add or remove a single column between two
@@ -418,6 +421,8 b' def asciiedges(type, char, lines, state,'
418 edges.append((nodeidx, nodeidx + 1))
421 edges.append((nodeidx, nodeidx + 1))
419 nmorecols = len(nextseen) - ncols
422 nmorecols = len(nextseen) - ncols
420 seen[:] = nextseen
423 seen[:] = nextseen
424 # remove current node from edge characters, no longer needed
425 state['edges'].pop(rev, None)
421 yield (type, char, lines, (nodeidx, edges, ncols, nmorecols))
426 yield (type, char, lines, (nodeidx, edges, ncols, nmorecols))
422
427
423 def _fixlongrightedges(edges):
428 def _fixlongrightedges(edges):
@@ -426,27 +431,28 b' def _fixlongrightedges(edges):'
426 edges[i] = (start, end + 1)
431 edges[i] = (start, end + 1)
427
432
428 def _getnodelineedgestail(
433 def _getnodelineedgestail(
429 node_index, p_node_index, n_columns, n_columns_diff, p_diff, fix_tail):
434 echars, idx, pidx, ncols, coldiff, pdiff, fix_tail):
430 if fix_tail and n_columns_diff == p_diff and n_columns_diff != 0:
435 if fix_tail and coldiff == pdiff and coldiff != 0:
431 # Still going in the same non-vertical direction.
436 # Still going in the same non-vertical direction.
432 if n_columns_diff == -1:
437 if coldiff == -1:
433 start = max(node_index + 1, p_node_index)
438 start = max(idx + 1, pidx)
434 tail = ["|", " "] * (start - node_index - 1)
439 tail = echars[idx * 2:(start - 1) * 2]
435 tail.extend(["/", " "] * (n_columns - start))
440 tail.extend(["/", " "] * (ncols - start))
436 return tail
441 return tail
437 else:
442 else:
438 return ["\\", " "] * (n_columns - node_index - 1)
443 return ["\\", " "] * (ncols - idx - 1)
439 else:
444 else:
440 return ["|", " "] * (n_columns - node_index - 1)
445 remainder = (ncols - idx - 1)
446 return echars[-(remainder * 2):] if remainder > 0 else []
441
447
442 def _drawedges(edges, nodeline, interline):
448 def _drawedges(echars, edges, nodeline, interline):
443 for (start, end) in edges:
449 for (start, end) in edges:
444 if start == end + 1:
450 if start == end + 1:
445 interline[2 * end + 1] = "/"
451 interline[2 * end + 1] = "/"
446 elif start == end - 1:
452 elif start == end - 1:
447 interline[2 * start + 1] = "\\"
453 interline[2 * start + 1] = "\\"
448 elif start == end:
454 elif start == end:
449 interline[2 * start] = "|"
455 interline[2 * start] = echars[2 * start]
450 else:
456 else:
451 if 2 * end >= len(nodeline):
457 if 2 * end >= len(nodeline):
452 continue
458 continue
@@ -457,26 +463,35 b' def _drawedges(edges, nodeline, interlin'
457 if nodeline[i] != "+":
463 if nodeline[i] != "+":
458 nodeline[i] = "-"
464 nodeline[i] = "-"
459
465
460 def _getpaddingline(ni, n_columns, edges):
466 def _getpaddingline(echars, idx, ncols, edges):
461 line = []
467 # all edges up to the current node
462 line.extend(["|", " "] * ni)
468 line = echars[:idx * 2]
463 if (ni, ni - 1) in edges or (ni, ni) in edges:
469 # an edge for the current node, if there is one
464 # (ni, ni - 1) (ni, ni)
470 if (idx, idx - 1) in edges or (idx, idx) in edges:
471 # (idx, idx - 1) (idx, idx)
465 # | | | | | | | |
472 # | | | | | | | |
466 # +---o | | o---+
473 # +---o | | o---+
467 # | | c | | c | |
474 # | | X | | X | |
468 # | |/ / | |/ /
475 # | |/ / | |/ /
469 # | | | | | |
476 # | | | | | |
470 c = "|"
477 line.extend(echars[idx * 2:(idx + 1) * 2])
471 else:
478 else:
472 c = " "
479 line.extend(' ')
473 line.extend([c, " "])
480 # all edges to the right of the current node
474 line.extend(["|", " "] * (n_columns - ni - 1))
481 remainder = ncols - idx - 1
482 if remainder > 0:
483 line.extend(echars[-(remainder * 2):])
475 return line
484 return line
476
485
477 def asciistate():
486 def asciistate():
478 """returns the initial value for the "state" argument to ascii()"""
487 """returns the initial value for the "state" argument to ascii()"""
479 return {'seen': [], 'lastcoldiff': 0, 'lastindex': 0}
488 return {
489 'seen': [],
490 'edges': {},
491 'lastcoldiff': 0,
492 'lastindex': 0,
493 'styles': EDGES.copy(),
494 }
480
495
481 def ascii(ui, state, type, char, text, coldata):
496 def ascii(ui, state, type, char, text, coldata):
482 """prints an ASCII graph of the DAG
497 """prints an ASCII graph of the DAG
@@ -498,9 +513,15 b' def ascii(ui, state, type, char, text, c'
498 in the current revision. That is: -1 means one column removed;
513 in the current revision. That is: -1 means one column removed;
499 0 means no columns added or removed; 1 means one column added.
514 0 means no columns added or removed; 1 means one column added.
500 """
515 """
501
502 idx, edges, ncols, coldiff = coldata
516 idx, edges, ncols, coldiff = coldata
503 assert -2 < coldiff < 2
517 assert -2 < coldiff < 2
518
519 edgemap, seen = state['edges'], state['seen']
520 # Be tolerant of history issues; make sure we have at least ncols + coldiff
521 # elements to work with. See test-glog.t for broken history test cases.
522 echars = [c for p in seen for c in (edgemap.get(p, '|'), ' ')]
523 echars.extend(('|', ' ') * max(ncols + coldiff - len(seen), 0))
524
504 if coldiff == -1:
525 if coldiff == -1:
505 # Transform
526 # Transform
506 #
527 #
@@ -530,35 +551,33 b' def ascii(ui, state, type, char, text, c'
530 fix_nodeline_tail = len(text) <= 2 and not add_padding_line
551 fix_nodeline_tail = len(text) <= 2 and not add_padding_line
531
552
532 # nodeline is the line containing the node character (typically o)
553 # nodeline is the line containing the node character (typically o)
533 nodeline = ["|", " "] * idx
554 nodeline = echars[:idx * 2]
534 nodeline.extend([char, " "])
555 nodeline.extend([char, " "])
535
556
536 nodeline.extend(
557 nodeline.extend(
537 _getnodelineedgestail(idx, state['lastindex'], ncols, coldiff,
558 _getnodelineedgestail(
538 state['lastcoldiff'], fix_nodeline_tail))
559 echars, idx, state['lastindex'], ncols, coldiff,
560 state['lastcoldiff'], fix_nodeline_tail))
539
561
540 # shift_interline is the line containing the non-vertical
562 # shift_interline is the line containing the non-vertical
541 # edges between this entry and the next
563 # edges between this entry and the next
542 shift_interline = ["|", " "] * idx
564 shift_interline = echars[:idx * 2]
565 shift_interline.extend(' ' * (2 + coldiff))
566 count = ncols - idx - 1
543 if coldiff == -1:
567 if coldiff == -1:
544 n_spaces = 1
568 shift_interline.extend('/ ' * count)
545 edge_ch = "/"
546 elif coldiff == 0:
569 elif coldiff == 0:
547 n_spaces = 2
570 shift_interline.extend(echars[(idx + 1) * 2:ncols * 2])
548 edge_ch = "|"
549 else:
571 else:
550 n_spaces = 3
572 shift_interline.extend(r'\ ' * count)
551 edge_ch = "\\"
552 shift_interline.extend(n_spaces * [" "])
553 shift_interline.extend([edge_ch, " "] * (ncols - idx - 1))
554
573
555 # draw edges from the current node to its parents
574 # draw edges from the current node to its parents
556 _drawedges(edges, nodeline, shift_interline)
575 _drawedges(echars, edges, nodeline, shift_interline)
557
576
558 # lines is the list of all graph lines to print
577 # lines is the list of all graph lines to print
559 lines = [nodeline]
578 lines = [nodeline]
560 if add_padding_line:
579 if add_padding_line:
561 lines.append(_getpaddingline(idx, ncols, edges))
580 lines.append(_getpaddingline(echars, idx, ncols, edges))
562 lines.append(shift_interline)
581 lines.append(shift_interline)
563
582
564 # make sure that there are as many graph lines as there are
583 # make sure that there are as many graph lines as there are
@@ -566,7 +585,7 b' def ascii(ui, state, type, char, text, c'
566 while len(text) < len(lines):
585 while len(text) < len(lines):
567 text.append("")
586 text.append("")
568 if len(lines) < len(text):
587 if len(lines) < len(text):
569 extra_interline = ["|", " "] * (ncols + coldiff)
588 extra_interline = echars[:(ncols + coldiff) * 2]
570 while len(lines) < len(text):
589 while len(lines) < len(text):
571 lines.append(extra_interline)
590 lines.append(extra_interline)
572
591
@@ -2415,3 +2415,214 b' label() should just work in node templat'
2415 |
2415 |
2416
2416
2417 $ cd ..
2417 $ cd ..
2418
2419 change graph edge styling
2420
2421 $ cd repo
2422 $ cat << EOF >> $HGRCPATH
2423 > [ui]
2424 > graphstyle.parent = |
2425 > graphstyle.grandparent = :
2426 > graphstyle.missing = .
2427 > EOF
2428 $ hg log -G -r 'file("a")' -m
2429 @ changeset: 36:08a19a744424
2430 : branch: branch
2431 : tag: tip
2432 : parent: 35:9159c3644c5e
2433 : parent: 35:9159c3644c5e
2434 : user: test
2435 : date: Thu Jan 01 00:00:36 1970 +0000
2436 : summary: (36) buggy merge: identical parents
2437 :
2438 o changeset: 32:d06dffa21a31
2439 |\ parent: 27:886ed638191b
2440 | : parent: 31:621d83e11f67
2441 | : user: test
2442 | : date: Thu Jan 01 00:00:32 1970 +0000
2443 | : summary: (32) expand
2444 | :
2445 o : changeset: 31:621d83e11f67
2446 |\: parent: 21:d42a756af44d
2447 | : parent: 30:6e11cd4b648f
2448 | : user: test
2449 | : date: Thu Jan 01 00:00:31 1970 +0000
2450 | : summary: (31) expand
2451 | :
2452 o : changeset: 30:6e11cd4b648f
2453 |\ \ parent: 28:44ecd0b9ae99
2454 | . : parent: 29:cd9bb2be7593
2455 | . : user: test
2456 | . : date: Thu Jan 01 00:00:30 1970 +0000
2457 | . : summary: (30) expand
2458 | . :
2459 o . : changeset: 28:44ecd0b9ae99
2460 |\ \ \ parent: 1:6db2ef61d156
2461 | . . : parent: 26:7f25b6c2f0b9
2462 | . . : user: test
2463 | . . : date: Thu Jan 01 00:00:28 1970 +0000
2464 | . . : summary: (28) merge zero known
2465 | . . :
2466 o . . : changeset: 26:7f25b6c2f0b9
2467 |\ \ \ \ parent: 18:1aa84d96232a
2468 | | . . : parent: 25:91da8ed57247
2469 | | . . : user: test
2470 | | . . : date: Thu Jan 01 00:00:26 1970 +0000
2471 | | . . : summary: (26) merge one known; far right
2472 | | . . :
2473 | o-----+ changeset: 25:91da8ed57247
2474 | | . . : parent: 21:d42a756af44d
2475 | | . . : parent: 24:a9c19a3d96b7
2476 | | . . : user: test
2477 | | . . : date: Thu Jan 01 00:00:25 1970 +0000
2478 | | . . : summary: (25) merge one known; far left
2479 | | . . :
2480 | o . . : changeset: 24:a9c19a3d96b7
2481 | |\ \ \ \ parent: 0:e6eb3150255d
2482 | | . . . : parent: 23:a01cddf0766d
2483 | | . . . : user: test
2484 | | . . . : date: Thu Jan 01 00:00:24 1970 +0000
2485 | | . . . : summary: (24) merge one known; immediate right
2486 | | . . . :
2487 | o---+ . : changeset: 23:a01cddf0766d
2488 | | . . . : parent: 1:6db2ef61d156
2489 | | . . . : parent: 22:e0d9cccacb5d
2490 | | . . . : user: test
2491 | | . . . : date: Thu Jan 01 00:00:23 1970 +0000
2492 | | . . . : summary: (23) merge one known; immediate left
2493 | | . . . :
2494 | o-------+ changeset: 22:e0d9cccacb5d
2495 | . . . . : parent: 18:1aa84d96232a
2496 |/ / / / / parent: 21:d42a756af44d
2497 | . . . : user: test
2498 | . . . : date: Thu Jan 01 00:00:22 1970 +0000
2499 | . . . : summary: (22) merge two known; one far left, one far right
2500 | . . . :
2501 | . . . o changeset: 21:d42a756af44d
2502 | . . . |\ parent: 19:31ddc2c1573b
2503 | . . . | | parent: 20:d30ed6450e32
2504 | . . . | | user: test
2505 | . . . | | date: Thu Jan 01 00:00:21 1970 +0000
2506 | . . . | | summary: (21) expand
2507 | . . . | |
2508 +-+-------o changeset: 20:d30ed6450e32
2509 | . . . | parent: 0:e6eb3150255d
2510 | . . . | parent: 18:1aa84d96232a
2511 | . . . | user: test
2512 | . . . | date: Thu Jan 01 00:00:20 1970 +0000
2513 | . . . | summary: (20) merge two known; two far right
2514 | . . . |
2515 | . . . o changeset: 19:31ddc2c1573b
2516 | . . . |\ parent: 15:1dda3f72782d
2517 | . . . | | parent: 17:44765d7c06e0
2518 | . . . | | user: test
2519 | . . . | | date: Thu Jan 01 00:00:19 1970 +0000
2520 | . . . | | summary: (19) expand
2521 | . . . | |
2522 o---+---+ | changeset: 18:1aa84d96232a
2523 . . . | | parent: 1:6db2ef61d156
2524 / / / / / parent: 15:1dda3f72782d
2525 . . . | | user: test
2526 . . . | | date: Thu Jan 01 00:00:18 1970 +0000
2527 . . . | | summary: (18) merge two known; two far left
2528 . . . | |
2529 . . . | o changeset: 17:44765d7c06e0
2530 . . . | |\ parent: 12:86b91144a6e9
2531 . . . | | | parent: 16:3677d192927d
2532 . . . | | | user: test
2533 . . . | | | date: Thu Jan 01 00:00:17 1970 +0000
2534 . . . | | | summary: (17) expand
2535 . . . | | |
2536 +-+-------o changeset: 16:3677d192927d
2537 . . . | | parent: 0:e6eb3150255d
2538 . . . | | parent: 1:6db2ef61d156
2539 . . . | | user: test
2540 . . . | | date: Thu Jan 01 00:00:16 1970 +0000
2541 . . . | | summary: (16) merge two known; one immediate right, one near right
2542 . . . | |
2543 . . . o | changeset: 15:1dda3f72782d
2544 . . . |\ \ parent: 13:22d8966a97e3
2545 . . . | | | parent: 14:8eac370358ef
2546 . . . | | | user: test
2547 . . . | | | date: Thu Jan 01 00:00:15 1970 +0000
2548 . . . | | | summary: (15) expand
2549 . . . | | |
2550 +-------o | changeset: 14:8eac370358ef
2551 . . . | |/ parent: 0:e6eb3150255d
2552 . . . | | parent: 12:86b91144a6e9
2553 . . . | | user: test
2554 . . . | | date: Thu Jan 01 00:00:14 1970 +0000
2555 . . . | | summary: (14) merge two known; one immediate right, one far right
2556 . . . | |
2557 . . . o | changeset: 13:22d8966a97e3
2558 . . . |\ \ parent: 9:7010c0af0a35
2559 . . . | | | parent: 11:832d76e6bdf2
2560 . . . | | | user: test
2561 . . . | | | date: Thu Jan 01 00:00:13 1970 +0000
2562 . . . | | | summary: (13) expand
2563 . . . | | |
2564 . +---+---o changeset: 12:86b91144a6e9
2565 . . . | | parent: 1:6db2ef61d156
2566 . . . | | parent: 9:7010c0af0a35
2567 . . . | | user: test
2568 . . . | | date: Thu Jan 01 00:00:12 1970 +0000
2569 . . . | | summary: (12) merge two known; one immediate right, one far left
2570 . . . | |
2571 . . . | o changeset: 11:832d76e6bdf2
2572 . . . | |\ parent: 6:b105a072e251
2573 . . . | | | parent: 10:74c64d036d72
2574 . . . | | | user: test
2575 . . . | | | date: Thu Jan 01 00:00:11 1970 +0000
2576 . . . | | | summary: (11) expand
2577 . . . | | |
2578 +---------o changeset: 10:74c64d036d72
2579 . . . | |/ parent: 0:e6eb3150255d
2580 . . . | | parent: 6:b105a072e251
2581 . . . | | user: test
2582 . . . | | date: Thu Jan 01 00:00:10 1970 +0000
2583 . . . | | summary: (10) merge two known; one immediate left, one near right
2584 . . . | |
2585 . . . o | changeset: 9:7010c0af0a35
2586 . . . |\ \ parent: 7:b632bb1b1224
2587 . . . | | | parent: 8:7a0b11f71937
2588 . . . | | | user: test
2589 . . . | | | date: Thu Jan 01 00:00:09 1970 +0000
2590 . . . | | | summary: (9) expand
2591 . . . | | |
2592 +-------o | changeset: 8:7a0b11f71937
2593 . . . |/ / parent: 0:e6eb3150255d
2594 . . . | | parent: 7:b632bb1b1224
2595 . . . | | user: test
2596 . . . | | date: Thu Jan 01 00:00:08 1970 +0000
2597 . . . | | summary: (8) merge two known; one immediate left, one far right
2598 . . . | |
2599 . . . o | changeset: 7:b632bb1b1224
2600 . . . |\ \ parent: 2:3d9a33b8d1e1
2601 . . . | . | parent: 5:4409d547b708
2602 . . . | . | user: test
2603 . . . | . | date: Thu Jan 01 00:00:07 1970 +0000
2604 . . . | . | summary: (7) expand
2605 . . . | . |
2606 . . . +---o changeset: 6:b105a072e251
2607 . . . | ./ parent: 2:3d9a33b8d1e1
2608 . . . | . parent: 5:4409d547b708
2609 . . . | . user: test
2610 . . . | . date: Thu Jan 01 00:00:06 1970 +0000
2611 . . . | . summary: (6) merge two known; one immediate left, one far left
2612 . . . | .
2613 . . . o . changeset: 5:4409d547b708
2614 . . . |\ \ parent: 3:27eef8ed80b4
2615 . . . | . . parent: 4:26a8bac39d9f
2616 . . . | . . user: test
2617 . . . | . . date: Thu Jan 01 00:00:05 1970 +0000
2618 . . . | . . summary: (5) expand
2619 . . . | . .
2620 . +---o . . changeset: 4:26a8bac39d9f
2621 . . . ./ / parent: 1:6db2ef61d156
2622 . . . . . parent: 3:27eef8ed80b4
2623 . . . . . user: test
2624 . . . . . date: Thu Jan 01 00:00:04 1970 +0000
2625 . . . . . summary: (4) merge two known; one immediate left, one immediate right
2626 . . . . .
2627
2628 $ cd ..
General Comments 0
You need to be logged in to leave comments. Login now