Show More
@@ -1044,7 +1044,8 class basefilectx(object): | |||||
1044 | if ready: |
|
1044 | if ready: | |
1045 | visit.pop() |
|
1045 | visit.pop() | |
1046 | curr = decorate(f.data(), f) |
|
1046 | curr = decorate(f.data(), f) | |
1047 |
curr = _annotatepair([hist[p] for p in pl], curr, |
|
1047 | curr = _annotatepair([hist[p] for p in pl], f, curr, False, | |
|
1048 | diffopts) | |||
1048 | for p in pl: |
|
1049 | for p in pl: | |
1049 | if needed[p] == 1: |
|
1050 | if needed[p] == 1: | |
1050 | del hist[p] |
|
1051 | del hist[p] | |
@@ -1073,9 +1074,72 class basefilectx(object): | |||||
1073 | c = visit.pop(max(visit)) |
|
1074 | c = visit.pop(max(visit)) | |
1074 | yield c |
|
1075 | yield c | |
1075 |
|
1076 | |||
1076 | def _annotatepair(parents, child, diffopts): |
|
1077 | def _annotatepair(parents, childfctx, child, skipchild, diffopts): | |
|
1078 | r''' | |||
|
1079 | Given parent and child fctxes and annotate data for parents, for all lines | |||
|
1080 | in either parent that match the child, annotate the child with the parent's | |||
|
1081 | data. | |||
|
1082 | ||||
|
1083 | Additionally, if `skipchild` is True, replace all other lines with parent | |||
|
1084 | annotate data as well such that child is never blamed for any lines. | |||
|
1085 | ||||
|
1086 | >>> oldfctx = 'old' | |||
|
1087 | >>> p1fctx, p2fctx, childfctx = 'p1', 'p2', 'c' | |||
|
1088 | >>> olddata = 'a\nb\n' | |||
|
1089 | >>> p1data = 'a\nb\nc\n' | |||
|
1090 | >>> p2data = 'a\nc\nd\n' | |||
|
1091 | >>> childdata = 'a\nb2\nc\nc2\nd\n' | |||
|
1092 | >>> diffopts = mdiff.diffopts() | |||
|
1093 | ||||
|
1094 | >>> def decorate(text, rev): | |||
|
1095 | ... return ([(rev, i) for i in xrange(1, text.count('\n') + 1)], text) | |||
|
1096 | ||||
|
1097 | Basic usage: | |||
|
1098 | ||||
|
1099 | >>> oldann = decorate(olddata, oldfctx) | |||
|
1100 | >>> p1ann = decorate(p1data, p1fctx) | |||
|
1101 | >>> p1ann = _annotatepair([oldann], p1fctx, p1ann, False, diffopts) | |||
|
1102 | >>> p1ann[0] | |||
|
1103 | [('old', 1), ('old', 2), ('p1', 3)] | |||
|
1104 | >>> p2ann = decorate(p2data, p2fctx) | |||
|
1105 | >>> p2ann = _annotatepair([oldann], p2fctx, p2ann, False, diffopts) | |||
|
1106 | >>> p2ann[0] | |||
|
1107 | [('old', 1), ('p2', 2), ('p2', 3)] | |||
|
1108 | ||||
|
1109 | Test with multiple parents (note the difference caused by ordering): | |||
|
1110 | ||||
|
1111 | >>> childann = decorate(childdata, childfctx) | |||
|
1112 | >>> childann = _annotatepair([p1ann, p2ann], childfctx, childann, False, | |||
|
1113 | ... diffopts) | |||
|
1114 | >>> childann[0] | |||
|
1115 | [('old', 1), ('c', 2), ('p2', 2), ('c', 4), ('p2', 3)] | |||
|
1116 | ||||
|
1117 | >>> childann = decorate(childdata, childfctx) | |||
|
1118 | >>> childann = _annotatepair([p2ann, p1ann], childfctx, childann, False, | |||
|
1119 | ... diffopts) | |||
|
1120 | >>> childann[0] | |||
|
1121 | [('old', 1), ('c', 2), ('p1', 3), ('c', 4), ('p2', 3)] | |||
|
1122 | ||||
|
1123 | Test with skipchild (note the difference caused by ordering): | |||
|
1124 | ||||
|
1125 | >>> childann = decorate(childdata, childfctx) | |||
|
1126 | >>> childann = _annotatepair([p1ann, p2ann], childfctx, childann, True, | |||
|
1127 | ... diffopts) | |||
|
1128 | >>> childann[0] | |||
|
1129 | [('old', 1), ('old', 2), ('p2', 2), ('p2', 2), ('p2', 3)] | |||
|
1130 | ||||
|
1131 | >>> childann = decorate(childdata, childfctx) | |||
|
1132 | >>> childann = _annotatepair([p2ann, p1ann], childfctx, childann, True, | |||
|
1133 | ... diffopts) | |||
|
1134 | >>> childann[0] | |||
|
1135 | [('old', 1), ('old', 2), ('p1', 3), ('p1', 3), ('p2', 3)] | |||
|
1136 | ''' | |||
1077 | pblocks = [(parent, mdiff.allblocks(parent[1], child[1], opts=diffopts)) |
|
1137 | pblocks = [(parent, mdiff.allblocks(parent[1], child[1], opts=diffopts)) | |
1078 | for parent in parents] |
|
1138 | for parent in parents] | |
|
1139 | ||||
|
1140 | if skipchild: | |||
|
1141 | # Need to iterate over the blocks twice -- make it a list | |||
|
1142 | pblocks = [(p, list(blocks)) for (p, blocks) in pblocks] | |||
1079 | # Mercurial currently prefers p2 over p1 for annotate. |
|
1143 | # Mercurial currently prefers p2 over p1 for annotate. | |
1080 | # TODO: change this? |
|
1144 | # TODO: change this? | |
1081 | for parent, blocks in pblocks: |
|
1145 | for parent, blocks in pblocks: | |
@@ -1084,6 +1148,40 def _annotatepair(parents, child, diffop | |||||
1084 | # belong to the child. |
|
1148 | # belong to the child. | |
1085 | if t == '=': |
|
1149 | if t == '=': | |
1086 | child[0][b1:b2] = parent[0][a1:a2] |
|
1150 | child[0][b1:b2] = parent[0][a1:a2] | |
|
1151 | ||||
|
1152 | if skipchild: | |||
|
1153 | # Now try and match up anything that couldn't be matched, | |||
|
1154 | # Reversing pblocks maintains bias towards p2, matching above | |||
|
1155 | # behavior. | |||
|
1156 | pblocks.reverse() | |||
|
1157 | ||||
|
1158 | # The heuristics are: | |||
|
1159 | # * Work on blocks of changed lines (effectively diff hunks with -U0). | |||
|
1160 | # This could potentially be smarter but works well enough. | |||
|
1161 | # * For a non-matching section, do a best-effort fit. Match lines in | |||
|
1162 | # diff hunks 1:1, dropping lines as necessary. | |||
|
1163 | # * Repeat the last line as a last resort. | |||
|
1164 | ||||
|
1165 | # First, replace as much as possible without repeating the last line. | |||
|
1166 | remaining = [(parent, []) for parent, _blocks in pblocks] | |||
|
1167 | for idx, (parent, blocks) in enumerate(pblocks): | |||
|
1168 | for (a1, a2, b1, b2), _t in blocks: | |||
|
1169 | if a2 - a1 >= b2 - b1: | |||
|
1170 | for bk in xrange(b1, b2): | |||
|
1171 | if child[0][bk][0] == childfctx: | |||
|
1172 | ak = min(a1 + (bk - b1), a2 - 1) | |||
|
1173 | child[0][bk] = parent[0][ak] | |||
|
1174 | else: | |||
|
1175 | remaining[idx][1].append((a1, a2, b1, b2)) | |||
|
1176 | ||||
|
1177 | # Then, look at anything left, which might involve repeating the last | |||
|
1178 | # line. | |||
|
1179 | for parent, blocks in remaining: | |||
|
1180 | for a1, a2, b1, b2 in blocks: | |||
|
1181 | for bk in xrange(b1, b2): | |||
|
1182 | if child[0][bk][0] == childfctx: | |||
|
1183 | ak = min(a1 + (bk - b1), a2 - 1) | |||
|
1184 | child[0][bk] = parent[0][ak] | |||
1087 | return child |
|
1185 | return child | |
1088 |
|
1186 | |||
1089 | class filectx(basefilectx): |
|
1187 | class filectx(basefilectx): |
@@ -25,6 +25,7 testmod('mercurial.changegroup') | |||||
25 | testmod('mercurial.changelog') |
|
25 | testmod('mercurial.changelog') | |
26 | testmod('mercurial.color') |
|
26 | testmod('mercurial.color') | |
27 | testmod('mercurial.config') |
|
27 | testmod('mercurial.config') | |
|
28 | testmod('mercurial.context') | |||
28 | testmod('mercurial.dagparser', optionflags=doctest.NORMALIZE_WHITESPACE) |
|
29 | testmod('mercurial.dagparser', optionflags=doctest.NORMALIZE_WHITESPACE) | |
29 | testmod('mercurial.dispatch') |
|
30 | testmod('mercurial.dispatch') | |
30 | testmod('mercurial.encoding') |
|
31 | testmod('mercurial.encoding') |
General Comments 0
You need to be logged in to leave comments.
Login now