##// END OF EJS Templates
dagop: move annotateline and _annotatepair from context.py...
Yuya Nishihara -
r36935:7affcabf default
parent child Browse files
Show More
@@ -26,10 +26,8 b' from .node import ('
26 wdirnodes,
26 wdirnodes,
27 wdirrev,
27 wdirrev,
28 )
28 )
29 from .thirdparty import (
30 attr,
31 )
32 from . import (
29 from . import (
30 dagop,
33 encoding,
31 encoding,
34 error,
32 error,
35 fileset,
33 fileset,
@@ -978,6 +976,8 b' class basefilectx(object):'
978 the line number at the first appearance in the managed file, otherwise,
976 the line number at the first appearance in the managed file, otherwise,
979 number has a fixed value of False.
977 number has a fixed value of False.
980 '''
978 '''
979 annotateline = dagop.annotateline
980 _annotatepair = dagop._annotatepair
981
981
982 def lines(text):
982 def lines(text):
983 if text.endswith("\n"):
983 if text.endswith("\n"):
@@ -1105,74 +1105,6 b' class basefilectx(object):'
1105 """
1105 """
1106 return self._repo.wwritedata(self.path(), self.data())
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 class filectx(basefilectx):
1108 class filectx(basefilectx):
1177 """A filecontext object makes access to data related to a particular
1109 """A filecontext object makes access to data related to a particular
1178 filerevision convenient."""
1110 filerevision convenient."""
@@ -9,6 +9,9 b' from __future__ import absolute_import'
9
9
10 import heapq
10 import heapq
11
11
12 from .thirdparty import (
13 attr,
14 )
12 from . import (
15 from . import (
13 error,
16 error,
14 mdiff,
17 mdiff,
@@ -358,6 +361,74 b' def blockdescendants(fctx, fromline, tol'
358 if inrange:
361 if inrange:
359 yield c, linerange1
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 def toposort(revs, parentsfunc, firstbranch=()):
432 def toposort(revs, parentsfunc, firstbranch=()):
362 """Yield revisions from heads to roots one (topo) branch at a time.
433 """Yield revisions from heads to roots one (topo) branch at a time.
363
434
@@ -6,7 +6,7 b' import unittest'
6 from mercurial import (
6 from mercurial import (
7 mdiff,
7 mdiff,
8 )
8 )
9 from mercurial.context import (
9 from mercurial.dagop import (
10 annotateline,
10 annotateline,
11 _annotatepair,
11 _annotatepair,
12 )
12 )
General Comments 0
You need to be logged in to leave comments. Login now