Show More
@@ -369,6 +369,15 b' class annotateline(object):' | |||||
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) | |||
|
373 | class _annotatedfile(object): | |||
|
374 | # list indexed by lineno - 1 | |||
|
375 | fctxs = attr.ib() | |||
|
376 | linenos = attr.ib() | |||
|
377 | skips = attr.ib() | |||
|
378 | # full file content | |||
|
379 | text = attr.ib() | |||
|
380 | ||||
372 | def _countlines(text): |
|
381 | def _countlines(text): | |
373 | if text.endswith("\n"): |
|
382 | if text.endswith("\n"): | |
374 | return text.count("\n") |
|
383 | return text.count("\n") | |
@@ -385,7 +394,7 b' def _annotatepair(parents, childfctx, ch' | |||||
385 |
|
394 | |||
386 | See test-annotate.py for unit tests. |
|
395 | See test-annotate.py for unit tests. | |
387 | ''' |
|
396 | ''' | |
388 |
pblocks = [(parent, mdiff.allblocks(parent |
|
397 | pblocks = [(parent, mdiff.allblocks(parent.text, child.text, opts=diffopts)) | |
389 | for parent in parents] |
|
398 | for parent in parents] | |
390 |
|
399 | |||
391 | if skipchild: |
|
400 | if skipchild: | |
@@ -398,7 +407,9 b' def _annotatepair(parents, childfctx, ch' | |||||
398 | # Changed blocks ('!') or blocks made only of blank lines ('~') |
|
407 | # Changed blocks ('!') or blocks made only of blank lines ('~') | |
399 | # belong to the child. |
|
408 | # belong to the child. | |
400 | if t == '=': |
|
409 | if t == '=': | |
401 |
child |
|
410 | child.fctxs[b1:b2] = parent.fctxs[a1:a2] | |
|
411 | child.linenos[b1:b2] = parent.linenos[a1:a2] | |||
|
412 | child.skips[b1:b2] = parent.skips[a1:a2] | |||
402 |
|
413 | |||
403 | if skipchild: |
|
414 | if skipchild: | |
404 | # Now try and match up anything that couldn't be matched, |
|
415 | # Now try and match up anything that couldn't be matched, | |
@@ -419,9 +430,11 b' def _annotatepair(parents, childfctx, ch' | |||||
419 | for (a1, a2, b1, b2), _t in blocks: |
|
430 | for (a1, a2, b1, b2), _t in blocks: | |
420 | if a2 - a1 >= b2 - b1: |
|
431 | if a2 - a1 >= b2 - b1: | |
421 | for bk in xrange(b1, b2): |
|
432 | for bk in xrange(b1, b2): | |
422 |
if child |
|
433 | if child.fctxs[bk] == childfctx: | |
423 | ak = min(a1 + (bk - b1), a2 - 1) |
|
434 | ak = min(a1 + (bk - b1), a2 - 1) | |
424 |
child |
|
435 | child.fctxs[bk] = parent.fctxs[ak] | |
|
436 | child.linenos[bk] = parent.linenos[ak] | |||
|
437 | child.skips[bk] = True | |||
425 | else: |
|
438 | else: | |
426 | remaining[idx][1].append((a1, a2, b1, b2)) |
|
439 | remaining[idx][1].append((a1, a2, b1, b2)) | |
427 |
|
440 | |||
@@ -430,9 +443,11 b' def _annotatepair(parents, childfctx, ch' | |||||
430 | for parent, blocks in remaining: |
|
443 | for parent, blocks in remaining: | |
431 | for a1, a2, b1, b2 in blocks: |
|
444 | for a1, a2, b1, b2 in blocks: | |
432 | for bk in xrange(b1, b2): |
|
445 | for bk in xrange(b1, b2): | |
433 |
if child |
|
446 | if child.fctxs[bk] == childfctx: | |
434 | ak = min(a1 + (bk - b1), a2 - 1) |
|
447 | ak = min(a1 + (bk - b1), a2 - 1) | |
435 |
child |
|
448 | child.fctxs[bk] = parent.fctxs[ak] | |
|
449 | child.linenos[bk] = parent.linenos[ak] | |||
|
450 | child.skips[bk] = True | |||
436 | return child |
|
451 | return child | |
437 |
|
452 | |||
438 | def annotate(base, parents, linenumber=False, skiprevs=None, diffopts=None): |
|
453 | def annotate(base, parents, linenumber=False, skiprevs=None, diffopts=None): | |
@@ -443,11 +458,13 b' def annotate(base, parents, linenumber=F' | |||||
443 |
|
458 | |||
444 | if linenumber: |
|
459 | if linenumber: | |
445 | def decorate(text, fctx): |
|
460 | def decorate(text, fctx): | |
446 | return ([annotateline(fctx=fctx, lineno=i) |
|
461 | n = _countlines(text) | |
447 | for i in xrange(1, _countlines(text) + 1)], text) |
|
462 | linenos = pycompat.rangelist(1, n + 1) | |
|
463 | return _annotatedfile([fctx] * n, linenos, [False] * n, text) | |||
448 | else: |
|
464 | else: | |
449 | def decorate(text, fctx): |
|
465 | def decorate(text, fctx): | |
450 |
|
|
466 | n = _countlines(text) | |
|
467 | return _annotatedfile([fctx] * n, [False] * n, [False] * n, text) | |||
451 |
|
468 | |||
452 | # This algorithm would prefer to be recursive, but Python is a |
|
469 | # This algorithm would prefer to be recursive, but Python is a | |
453 | # bit recursion-hostile. Instead we do an iterative |
|
470 | # bit recursion-hostile. Instead we do an iterative | |
@@ -501,8 +518,10 b' def annotate(base, parents, linenumber=F' | |||||
501 | hist[f] = curr |
|
518 | hist[f] = curr | |
502 | del pcache[f] |
|
519 | del pcache[f] | |
503 |
|
520 | |||
504 |
|
|
521 | a = hist[base] | |
505 | return pycompat.ziplist(lineattrs, mdiff.splitnewlines(text)) |
|
522 | return [(annotateline(fctx, lineno, skip), line) | |
|
523 | for fctx, lineno, skip, line | |||
|
524 | in zip(a.fctxs, a.linenos, a.skips, mdiff.splitnewlines(a.text))] | |||
506 |
|
525 | |||
507 | def toposort(revs, parentsfunc, firstbranch=()): |
|
526 | def toposort(revs, parentsfunc, firstbranch=()): | |
508 | """Yield revisions from heads to roots one (topo) branch at a time. |
|
527 | """Yield revisions from heads to roots one (topo) branch at a time. |
@@ -71,6 +71,9 b' if ispy3:' | |||||
71 | def maplist(*args): |
|
71 | def maplist(*args): | |
72 | return list(map(*args)) |
|
72 | return list(map(*args)) | |
73 |
|
73 | |||
|
74 | def rangelist(*args): | |||
|
75 | return list(range(*args)) | |||
|
76 | ||||
74 | def ziplist(*args): |
|
77 | def ziplist(*args): | |
75 | return list(zip(*args)) |
|
78 | return list(zip(*args)) | |
76 |
|
79 | |||
@@ -348,6 +351,7 b' else:' | |||||
348 | bytesio = cStringIO.StringIO |
|
351 | bytesio = cStringIO.StringIO | |
349 | stringio = bytesio |
|
352 | stringio = bytesio | |
350 | maplist = map |
|
353 | maplist = map | |
|
354 | rangelist = range | |||
351 | ziplist = zip |
|
355 | ziplist = zip | |
352 | rawinput = raw_input |
|
356 | rawinput = raw_input | |
353 | getargspec = inspect.getargspec |
|
357 | getargspec = inspect.getargspec |
@@ -5,12 +5,18 b' import unittest' | |||||
5 |
|
5 | |||
6 | from mercurial import ( |
|
6 | from mercurial import ( | |
7 | mdiff, |
|
7 | mdiff, | |
|
8 | pycompat, | |||
8 | ) |
|
9 | ) | |
9 | from mercurial.dagop import ( |
|
10 | from mercurial.dagop import ( | |
10 | annotateline, |
|
11 | annotateline, | |
|
12 | _annotatedfile, | |||
11 | _annotatepair, |
|
13 | _annotatepair, | |
12 | ) |
|
14 | ) | |
13 |
|
15 | |||
|
16 | def tr(a): | |||
|
17 | return [annotateline(fctx, lineno, skip) | |||
|
18 | for fctx, lineno, skip in zip(a.fctxs, a.linenos, a.skips)] | |||
|
19 | ||||
14 | class AnnotateTests(unittest.TestCase): |
|
20 | class AnnotateTests(unittest.TestCase): | |
15 | """Unit tests for annotate code.""" |
|
21 | """Unit tests for annotate code.""" | |
16 |
|
22 | |||
@@ -26,16 +32,16 b' class AnnotateTests(unittest.TestCase):' | |||||
26 | diffopts = mdiff.diffopts() |
|
32 | diffopts = mdiff.diffopts() | |
27 |
|
33 | |||
28 | def decorate(text, fctx): |
|
34 | def decorate(text, fctx): | |
29 | return ([annotateline(fctx=fctx, lineno=i) |
|
35 | n = text.count(b'\n') | |
30 | for i in range(1, text.count(b'\n') + 1)], |
|
36 | linenos = pycompat.rangelist(1, n + 1) | |
31 | text) |
|
37 | return _annotatedfile([fctx] * n, linenos, [False] * n, text) | |
32 |
|
38 | |||
33 | # Basic usage |
|
39 | # Basic usage | |
34 |
|
40 | |||
35 | oldann = decorate(olddata, oldfctx) |
|
41 | oldann = decorate(olddata, oldfctx) | |
36 | p1ann = decorate(p1data, p1fctx) |
|
42 | p1ann = decorate(p1data, p1fctx) | |
37 | p1ann = _annotatepair([oldann], p1fctx, p1ann, False, diffopts) |
|
43 | p1ann = _annotatepair([oldann], p1fctx, p1ann, False, diffopts) | |
38 |
self.assertEqual(p1ann |
|
44 | self.assertEqual(tr(p1ann), [ | |
39 | annotateline(b'old', 1), |
|
45 | annotateline(b'old', 1), | |
40 | annotateline(b'old', 2), |
|
46 | annotateline(b'old', 2), | |
41 | annotateline(b'p1', 3), |
|
47 | annotateline(b'p1', 3), | |
@@ -43,7 +49,7 b' class AnnotateTests(unittest.TestCase):' | |||||
43 |
|
49 | |||
44 | p2ann = decorate(p2data, p2fctx) |
|
50 | p2ann = decorate(p2data, p2fctx) | |
45 | p2ann = _annotatepair([oldann], p2fctx, p2ann, False, diffopts) |
|
51 | p2ann = _annotatepair([oldann], p2fctx, p2ann, False, diffopts) | |
46 |
self.assertEqual(p2ann |
|
52 | self.assertEqual(tr(p2ann), [ | |
47 | annotateline(b'old', 1), |
|
53 | annotateline(b'old', 1), | |
48 | annotateline(b'p2', 2), |
|
54 | annotateline(b'p2', 2), | |
49 | annotateline(b'p2', 3), |
|
55 | annotateline(b'p2', 3), | |
@@ -54,7 +60,7 b' class AnnotateTests(unittest.TestCase):' | |||||
54 | childann = decorate(childdata, childfctx) |
|
60 | childann = decorate(childdata, childfctx) | |
55 | childann = _annotatepair([p1ann, p2ann], childfctx, childann, False, |
|
61 | childann = _annotatepair([p1ann, p2ann], childfctx, childann, False, | |
56 | diffopts) |
|
62 | diffopts) | |
57 |
self.assertEqual(childann |
|
63 | self.assertEqual(tr(childann), [ | |
58 | annotateline(b'old', 1), |
|
64 | annotateline(b'old', 1), | |
59 | annotateline(b'c', 2), |
|
65 | annotateline(b'c', 2), | |
60 | annotateline(b'p2', 2), |
|
66 | annotateline(b'p2', 2), | |
@@ -65,7 +71,7 b' class AnnotateTests(unittest.TestCase):' | |||||
65 | childann = decorate(childdata, childfctx) |
|
71 | childann = decorate(childdata, childfctx) | |
66 | childann = _annotatepair([p2ann, p1ann], childfctx, childann, False, |
|
72 | childann = _annotatepair([p2ann, p1ann], childfctx, childann, False, | |
67 | diffopts) |
|
73 | diffopts) | |
68 |
self.assertEqual(childann |
|
74 | self.assertEqual(tr(childann), [ | |
69 | annotateline(b'old', 1), |
|
75 | annotateline(b'old', 1), | |
70 | annotateline(b'c', 2), |
|
76 | annotateline(b'c', 2), | |
71 | annotateline(b'p1', 3), |
|
77 | annotateline(b'p1', 3), | |
@@ -78,7 +84,7 b' class AnnotateTests(unittest.TestCase):' | |||||
78 | childann = decorate(childdata, childfctx) |
|
84 | childann = decorate(childdata, childfctx) | |
79 | childann = _annotatepair([p1ann, p2ann], childfctx, childann, True, |
|
85 | childann = _annotatepair([p1ann, p2ann], childfctx, childann, True, | |
80 | diffopts) |
|
86 | diffopts) | |
81 |
self.assertEqual(childann |
|
87 | self.assertEqual(tr(childann), [ | |
82 | annotateline(b'old', 1), |
|
88 | annotateline(b'old', 1), | |
83 | annotateline(b'old', 2, True), |
|
89 | annotateline(b'old', 2, True), | |
84 | # note that this line was carried over from earlier so it is *not* |
|
90 | # note that this line was carried over from earlier so it is *not* | |
@@ -91,7 +97,7 b' class AnnotateTests(unittest.TestCase):' | |||||
91 | childann = decorate(childdata, childfctx) |
|
97 | childann = decorate(childdata, childfctx) | |
92 | childann = _annotatepair([p2ann, p1ann], childfctx, childann, True, |
|
98 | childann = _annotatepair([p2ann, p1ann], childfctx, childann, True, | |
93 | diffopts) |
|
99 | diffopts) | |
94 |
self.assertEqual(childann |
|
100 | self.assertEqual(tr(childann), [ | |
95 | annotateline(b'old', 1), |
|
101 | annotateline(b'old', 1), | |
96 | annotateline(b'old', 2, True), |
|
102 | annotateline(b'old', 2, True), | |
97 | annotateline(b'p1', 3), |
|
103 | annotateline(b'p1', 3), |
General Comments 0
You need to be logged in to leave comments.
Login now