Show More
@@ -26,10 +26,8 b' from .node import (' | |||
|
26 | 26 | wdirnodes, |
|
27 | 27 | wdirrev, |
|
28 | 28 | ) |
|
29 | from .thirdparty import ( | |
|
30 | attr, | |
|
31 | ) | |
|
32 | 29 | from . import ( |
|
30 | dagop, | |
|
33 | 31 | encoding, |
|
34 | 32 | error, |
|
35 | 33 | fileset, |
@@ -978,6 +976,8 b' class basefilectx(object):' | |||
|
978 | 976 | the line number at the first appearance in the managed file, otherwise, |
|
979 | 977 | number has a fixed value of False. |
|
980 | 978 | ''' |
|
979 | annotateline = dagop.annotateline | |
|
980 | _annotatepair = dagop._annotatepair | |
|
981 | 981 | |
|
982 | 982 | def lines(text): |
|
983 | 983 | if text.endswith("\n"): |
@@ -1105,74 +1105,6 b' class basefilectx(object):' | |||
|
1105 | 1105 | """ |
|
1106 | 1106 | return self._repo.wwritedata(self.path(), self.data()) |
|
1107 | 1107 | |
|
1108 | @attr.s(slots=True, frozen=True) | |
|
1109 | class annotateline(object): | |
|
1110 | fctx = attr.ib() | |
|
1111 | lineno = attr.ib(default=False) | |
|
1112 | # Whether this annotation was the result of a skip-annotate. | |
|
1113 | skip = attr.ib(default=False) | |
|
1114 | ||
|
1115 | def _annotatepair(parents, childfctx, child, skipchild, diffopts): | |
|
1116 | r''' | |
|
1117 | Given parent and child fctxes and annotate data for parents, for all lines | |
|
1118 | in either parent that match the child, annotate the child with the parent's | |
|
1119 | data. | |
|
1120 | ||
|
1121 | Additionally, if `skipchild` is True, replace all other lines with parent | |
|
1122 | annotate data as well such that child is never blamed for any lines. | |
|
1123 | ||
|
1124 | See test-annotate.py for unit tests. | |
|
1125 | ''' | |
|
1126 | pblocks = [(parent, mdiff.allblocks(parent[1], child[1], opts=diffopts)) | |
|
1127 | for parent in parents] | |
|
1128 | ||
|
1129 | if skipchild: | |
|
1130 | # Need to iterate over the blocks twice -- make it a list | |
|
1131 | pblocks = [(p, list(blocks)) for (p, blocks) in pblocks] | |
|
1132 | # Mercurial currently prefers p2 over p1 for annotate. | |
|
1133 | # TODO: change this? | |
|
1134 | for parent, blocks in pblocks: | |
|
1135 | for (a1, a2, b1, b2), t in blocks: | |
|
1136 | # Changed blocks ('!') or blocks made only of blank lines ('~') | |
|
1137 | # belong to the child. | |
|
1138 | if t == '=': | |
|
1139 | child[0][b1:b2] = parent[0][a1:a2] | |
|
1140 | ||
|
1141 | if skipchild: | |
|
1142 | # Now try and match up anything that couldn't be matched, | |
|
1143 | # Reversing pblocks maintains bias towards p2, matching above | |
|
1144 | # behavior. | |
|
1145 | pblocks.reverse() | |
|
1146 | ||
|
1147 | # The heuristics are: | |
|
1148 | # * Work on blocks of changed lines (effectively diff hunks with -U0). | |
|
1149 | # This could potentially be smarter but works well enough. | |
|
1150 | # * For a non-matching section, do a best-effort fit. Match lines in | |
|
1151 | # diff hunks 1:1, dropping lines as necessary. | |
|
1152 | # * Repeat the last line as a last resort. | |
|
1153 | ||
|
1154 | # First, replace as much as possible without repeating the last line. | |
|
1155 | remaining = [(parent, []) for parent, _blocks in pblocks] | |
|
1156 | for idx, (parent, blocks) in enumerate(pblocks): | |
|
1157 | for (a1, a2, b1, b2), _t in blocks: | |
|
1158 | if a2 - a1 >= b2 - b1: | |
|
1159 | for bk in xrange(b1, b2): | |
|
1160 | if child[0][bk].fctx == childfctx: | |
|
1161 | ak = min(a1 + (bk - b1), a2 - 1) | |
|
1162 | child[0][bk] = attr.evolve(parent[0][ak], skip=True) | |
|
1163 | else: | |
|
1164 | remaining[idx][1].append((a1, a2, b1, b2)) | |
|
1165 | ||
|
1166 | # Then, look at anything left, which might involve repeating the last | |
|
1167 | # line. | |
|
1168 | for parent, blocks in remaining: | |
|
1169 | for a1, a2, b1, b2 in blocks: | |
|
1170 | for bk in xrange(b1, b2): | |
|
1171 | if child[0][bk].fctx == childfctx: | |
|
1172 | ak = min(a1 + (bk - b1), a2 - 1) | |
|
1173 | child[0][bk] = attr.evolve(parent[0][ak], skip=True) | |
|
1174 | return child | |
|
1175 | ||
|
1176 | 1108 | class filectx(basefilectx): |
|
1177 | 1109 | """A filecontext object makes access to data related to a particular |
|
1178 | 1110 | filerevision convenient.""" |
@@ -9,6 +9,9 b' from __future__ import absolute_import' | |||
|
9 | 9 | |
|
10 | 10 | import heapq |
|
11 | 11 | |
|
12 | from .thirdparty import ( | |
|
13 | attr, | |
|
14 | ) | |
|
12 | 15 | from . import ( |
|
13 | 16 | error, |
|
14 | 17 | mdiff, |
@@ -358,6 +361,74 b' def blockdescendants(fctx, fromline, tol' | |||
|
358 | 361 | if inrange: |
|
359 | 362 | yield c, linerange1 |
|
360 | 363 | |
|
364 | @attr.s(slots=True, frozen=True) | |
|
365 | class annotateline(object): | |
|
366 | fctx = attr.ib() | |
|
367 | lineno = attr.ib(default=False) | |
|
368 | # Whether this annotation was the result of a skip-annotate. | |
|
369 | skip = attr.ib(default=False) | |
|
370 | ||
|
371 | def _annotatepair(parents, childfctx, child, skipchild, diffopts): | |
|
372 | r''' | |
|
373 | Given parent and child fctxes and annotate data for parents, for all lines | |
|
374 | in either parent that match the child, annotate the child with the parent's | |
|
375 | data. | |
|
376 | ||
|
377 | Additionally, if `skipchild` is True, replace all other lines with parent | |
|
378 | annotate data as well such that child is never blamed for any lines. | |
|
379 | ||
|
380 | See test-annotate.py for unit tests. | |
|
381 | ''' | |
|
382 | pblocks = [(parent, mdiff.allblocks(parent[1], child[1], opts=diffopts)) | |
|
383 | for parent in parents] | |
|
384 | ||
|
385 | if skipchild: | |
|
386 | # Need to iterate over the blocks twice -- make it a list | |
|
387 | pblocks = [(p, list(blocks)) for (p, blocks) in pblocks] | |
|
388 | # Mercurial currently prefers p2 over p1 for annotate. | |
|
389 | # TODO: change this? | |
|
390 | for parent, blocks in pblocks: | |
|
391 | for (a1, a2, b1, b2), t in blocks: | |
|
392 | # Changed blocks ('!') or blocks made only of blank lines ('~') | |
|
393 | # belong to the child. | |
|
394 | if t == '=': | |
|
395 | child[0][b1:b2] = parent[0][a1:a2] | |
|
396 | ||
|
397 | if skipchild: | |
|
398 | # Now try and match up anything that couldn't be matched, | |
|
399 | # Reversing pblocks maintains bias towards p2, matching above | |
|
400 | # behavior. | |
|
401 | pblocks.reverse() | |
|
402 | ||
|
403 | # The heuristics are: | |
|
404 | # * Work on blocks of changed lines (effectively diff hunks with -U0). | |
|
405 | # This could potentially be smarter but works well enough. | |
|
406 | # * For a non-matching section, do a best-effort fit. Match lines in | |
|
407 | # diff hunks 1:1, dropping lines as necessary. | |
|
408 | # * Repeat the last line as a last resort. | |
|
409 | ||
|
410 | # First, replace as much as possible without repeating the last line. | |
|
411 | remaining = [(parent, []) for parent, _blocks in pblocks] | |
|
412 | for idx, (parent, blocks) in enumerate(pblocks): | |
|
413 | for (a1, a2, b1, b2), _t in blocks: | |
|
414 | if a2 - a1 >= b2 - b1: | |
|
415 | for bk in xrange(b1, b2): | |
|
416 | if child[0][bk].fctx == childfctx: | |
|
417 | ak = min(a1 + (bk - b1), a2 - 1) | |
|
418 | child[0][bk] = attr.evolve(parent[0][ak], skip=True) | |
|
419 | else: | |
|
420 | remaining[idx][1].append((a1, a2, b1, b2)) | |
|
421 | ||
|
422 | # Then, look at anything left, which might involve repeating the last | |
|
423 | # line. | |
|
424 | for parent, blocks in remaining: | |
|
425 | for a1, a2, b1, b2 in blocks: | |
|
426 | for bk in xrange(b1, b2): | |
|
427 | if child[0][bk].fctx == childfctx: | |
|
428 | ak = min(a1 + (bk - b1), a2 - 1) | |
|
429 | child[0][bk] = attr.evolve(parent[0][ak], skip=True) | |
|
430 | return child | |
|
431 | ||
|
361 | 432 | def toposort(revs, parentsfunc, firstbranch=()): |
|
362 | 433 | """Yield revisions from heads to roots one (topo) branch at a time. |
|
363 | 434 |
General Comments 0
You need to be logged in to leave comments.
Login now