363 yield c, linerange1 |
363 yield c, linerange1 |
364 |
364 |
365 @attr.s(slots=True, frozen=True) |
365 @attr.s(slots=True, frozen=True) |
366 class annotateline(object): |
366 class annotateline(object): |
367 fctx = attr.ib() |
367 fctx = attr.ib() |
368 lineno = attr.ib(default=False) |
368 lineno = attr.ib() |
369 # Whether this annotation was the result of a skip-annotate. |
369 # Whether this annotation was the result of a skip-annotate. |
370 skip = attr.ib(default=False) |
370 skip = attr.ib(default=False) |
371 |
371 |
372 @attr.s(slots=True, frozen=True) |
372 @attr.s(slots=True, frozen=True) |
373 class _annotatedfile(object): |
373 class _annotatedfile(object): |
380 |
380 |
381 def _countlines(text): |
381 def _countlines(text): |
382 if text.endswith("\n"): |
382 if text.endswith("\n"): |
383 return text.count("\n") |
383 return text.count("\n") |
384 return text.count("\n") + int(bool(text)) |
384 return text.count("\n") + int(bool(text)) |
|
385 |
|
386 def _decoratelines(text, fctx): |
|
387 n = _countlines(text) |
|
388 linenos = pycompat.rangelist(1, n + 1) |
|
389 return _annotatedfile([fctx] * n, linenos, [False] * n, text) |
385 |
390 |
386 def _annotatepair(parents, childfctx, child, skipchild, diffopts): |
391 def _annotatepair(parents, childfctx, child, skipchild, diffopts): |
387 r''' |
392 r''' |
388 Given parent and child fctxes and annotate data for parents, for all lines |
393 Given parent and child fctxes and annotate data for parents, for all lines |
389 in either parent that match the child, annotate the child with the parent's |
394 in either parent that match the child, annotate the child with the parent's |
448 child.fctxs[bk] = parent.fctxs[ak] |
453 child.fctxs[bk] = parent.fctxs[ak] |
449 child.linenos[bk] = parent.linenos[ak] |
454 child.linenos[bk] = parent.linenos[ak] |
450 child.skips[bk] = True |
455 child.skips[bk] = True |
451 return child |
456 return child |
452 |
457 |
453 def annotate(base, parents, linenumber=False, skiprevs=None, diffopts=None): |
458 def annotate(base, parents, skiprevs=None, diffopts=None): |
454 """Core algorithm for filectx.annotate() |
459 """Core algorithm for filectx.annotate() |
455 |
460 |
456 `parents(fctx)` is a function returning a list of parent filectxs. |
461 `parents(fctx)` is a function returning a list of parent filectxs. |
457 """ |
462 """ |
458 |
|
459 if linenumber: |
|
460 def decorate(text, fctx): |
|
461 n = _countlines(text) |
|
462 linenos = pycompat.rangelist(1, n + 1) |
|
463 return _annotatedfile([fctx] * n, linenos, [False] * n, text) |
|
464 else: |
|
465 def decorate(text, fctx): |
|
466 n = _countlines(text) |
|
467 return _annotatedfile([fctx] * n, [False] * n, [False] * n, text) |
|
468 |
463 |
469 # This algorithm would prefer to be recursive, but Python is a |
464 # This algorithm would prefer to be recursive, but Python is a |
470 # bit recursion-hostile. Instead we do an iterative |
465 # bit recursion-hostile. Instead we do an iterative |
471 # depth-first search. |
466 # depth-first search. |
472 |
467 |
500 if p not in hist: |
495 if p not in hist: |
501 ready = False |
496 ready = False |
502 visit.append(p) |
497 visit.append(p) |
503 if ready: |
498 if ready: |
504 visit.pop() |
499 visit.pop() |
505 curr = decorate(f.data(), f) |
500 curr = _decoratelines(f.data(), f) |
506 skipchild = False |
501 skipchild = False |
507 if skiprevs is not None: |
502 if skiprevs is not None: |
508 skipchild = f._changeid in skiprevs |
503 skipchild = f._changeid in skiprevs |
509 curr = _annotatepair([hist[p] for p in pl], f, curr, skipchild, |
504 curr = _annotatepair([hist[p] for p in pl], f, curr, skipchild, |
510 diffopts) |
505 diffopts) |