def unified_diff(lines1, lines2): matches = find_matches(lines1, lines2) if len(matches) == 0 or \ matches[-1][0]+matches[-1][2] != len(lines1) or \ matches[-1][1]+matches[-1][2] != len(lines2): matches.append((len(lines1), len(lines2), 0)) text = [] if matches[0][:2] == (0, 0): line = line2 = max(matches[0][2] - 3, 0) length = min(matches[0][2], 3) m = 1 else: line, line2 = -1, 0 length = 0 m = 0 while m < len(matches): # capture as much as possible under this header m_end = m while True: line_end, line2_end, length_end = matches[m_end] if length_end > 6 or m_end + 1 == len(matches): break m_end += 1 length_end = min(length_end, 3) # print the diff header for all the hunks we can cover lfudge = max(0, line) header = "@@ -%d,%d +%d,%d @@\n" % \ (lfudge + 1, line_end - lfudge + length_end, line2 + 1, line2_end - line2 + length_end) text.append(header) # print out all the covered hunks with context for m in xrange(m, m_end+1): # fill out the previous context for line in xrange(line, line+length): text.append(' ' + lines1[line] + "\n") line2 += length - 1 s1, s2, length = matches[m] # print the removed and added lines for line in xrange(line+1, s1): text.append('-' + lines1[line] + "\n") for line2 in xrange(line2+1, s2): text.append('+' + lines2[line2] + "\n") line += 1 line2 += 1 len_full = length length = min(3, length) # print the trailing context for i in xrange(line, line + length): text.append(' ' + lines1[i] + "\n") # setup stuff for the next iteration line = s1 + len_full - length line2 = s2 + len_full - length m += 1 return ''.join(text)
def unified_diff(lines1, lines2): matches = find_matches(lines1, lines2) if len(matches) == 0 or \ matches[-1][0]+matches[-1][2] != len(lines1) or \ matches[-1][1]+matches[-1][2] != len(lines2): matches.append((len(lines1), len(lines2), 0)) text = [] if matches[0][:2] == (0, 0): line = line2 = max(matches[0][2] - 3, 0) length = min(matches[0][2], 3) m = 1 else: line, line2 = -1, 0 length = 0 m = 0 while m < len(matches): # capture as much as possible under this header m_end = m while True: line_end, line2_end, length_end = matches[m_end] if length_end > 6 or m_end + 1 == len(matches): break m_end += 1 length_end = min(length_end, 3) # print the diff header for all the hunks we can cover lfudge = max(0, line) header = "@@ -%d,%d +%d,%d @@\n" % \ (lfudge + 1, line_end - lfudge + length_end, line2 + 1, line2_end - line2 + length_end) text.append(header) # print out all the covered hunks with context for m in xrange(m, m_end + 1): # fill out the previous context for line in xrange(line, line + length): text.append(' ' + lines1[line] + "\n") line2 += length - 1 s1, s2, length = matches[m] # print the removed and added lines for line in xrange(line + 1, s1): text.append('-' + lines1[line] + "\n") for line2 in xrange(line2 + 1, s2): text.append('+' + lines2[line2] + "\n") line += 1 line2 += 1 len_full = length length = min(3, length) # print the trailing context for i in xrange(line, line + length): text.append(' ' + lines1[i] + "\n") # setup stuff for the next iteration line = s1 + len_full - length line2 = s2 + len_full - length m += 1 return ''.join(text)
def _find_conflict(local, local_line_points, local_points, remote, remote_line_points, remote_points): assert len(local_line_points) == len(local) + 1 assert len(remote_line_points) == len(remote) + 1 lpdict = Set(local_points) for point in local_line_points: assert point in lpdict rpdict = Set(remote_points) for point in remote_line_points: assert point in rpdict result = [] result_line_points = [] lastl, lastr = 0, 0 selector = SelectLinePoint() selector.push(local_points) selector.push(remote_points) for (lpos, rpos, matchlen) in find_matches( local, remote) + [(len(local), len(remote), 0)]: rapplied = _is_applied(remote_line_points[lastr:rpos + 1], lpdict) lapplied = _is_applied(local_line_points[lastl:lpos + 1], rpdict) if rapplied and not lapplied: result.extend(local[lastl:lpos + matchlen]) result_line_points.extend(local_line_points[lastl:lpos + 1]) elif lapplied and not rapplied: result.extend(remote[lastr:rpos + matchlen]) result_line_points.extend(remote_line_points[lastr:rpos + 1]) elif (lastl, lastr) == (len(local), len(remote)): result_line_points.append( selector.select(local_line_points[-1], remote_line_points[-1])) elif (lpos, rpos) == (0, 0): result.extend(local[:matchlen]) result_line_points.append( selector.select(local_line_points[0], remote_line_points[0])) else: result.append((local[lastl:lpos], remote[lastr:rpos])) result.extend(local[lpos:lpos + matchlen]) result_line_points.append((local_line_points[lastl:lpos + 1], remote_line_points[lastr:rpos + 1])) result_line_points.append(None) for i in xrange(1, matchlen): result_line_points.append( selector.select(local_line_points[lpos + i], remote_line_points[rpos + i])) lastl, lastr = lpos + matchlen, rpos + matchlen result_points = selector.dump() return (result, result_line_points, result_points)
def find_annotation(precursors, resolution): result = [None] * len(resolution) selector = SelectLinePoint() for i in xrange(len(precursors)): match = find_matches(precursors[i][0], resolution) pre = precursors[i][0] pre_line_points = precursors[i][1] selector.push(precursors[i][2]) for (matchold, matchnew, matchlen) in match: for j in xrange(matchlen): result[matchnew + j] = selector.select(result[matchnew + j], pre_line_points[matchold + j]) return result
def standard_diff(lines1, lines2): matches = find_matches(lines1, lines2) if len(matches) == 0 or matches[0][0] != 0 or matches[0][1] != 0: matches.insert(0, (0, 0, 0)) if matches[-1][0]+matches[-1][2] != len(lines1) or \ matches[-1][1]+matches[-1][2] != len(lines2): matches.append((len(lines1), len(lines2), 0)) text = [] i = 0 j = 0 for i2, j2, l in matches: if i2 == i and j2 == j: i += l j += l continue if i2 == i: at = str(i) elif i2 == i + 1: at = str(i2) else: at = "%d,%d" % (i + 1, i2) if j2 == j: bt = str(j) elif j2 == j + 1: bt = str(j2) else: bt = "%d,%d" % (j + 1, j2) if i2 > i: if j2 > j: text.extend([at, 'c', bt, "\n"]) else: text.extend([at, 'd', bt, "\n"]) else: text.extend([at, 'a', bt, "\n"]) for i in xrange(i, i2): text.extend(["< ", lines1[i], "\n"]) if i2 > i and j2 > j: text.append("---\n") for j in xrange(j, j2): text.extend(["> ", lines2[j], "\n"]) i = i2 + l j = j2 + l return ''.join(text)
def standard_diff(lines1, lines2): matches = find_matches(lines1, lines2) if len(matches) == 0 or matches[0][0] != 0 or matches[0][1] != 0: matches.insert(0, (0, 0, 0)) if matches[-1][0]+matches[-1][2] != len(lines1) or \ matches[-1][1]+matches[-1][2] != len(lines2): matches.append((len(lines1), len(lines2), 0)) text = [] i = 0 j = 0 for i2, j2, l in matches: if i2 == i and j2 == j: i += l j += l continue if i2 == i: at = str(i) elif i2 == i + 1: at = str(i2) else: at = "%d,%d" % (i+1, i2) if j2 == j: bt = str(j) elif j2 == j + 1: bt = str(j2) else: bt = "%d,%d" % (j+1, j2) if i2 > i: if j2 > j: text.extend([at, 'c', bt, "\n"]) else: text.extend([at, 'd', bt, "\n"]) else: text.extend([at, 'a', bt, "\n"]) for i in xrange(i, i2): text.extend(["< ", lines1[i], "\n"]) if i2 > i and j2 > j: text.append("---\n") for j in xrange(j, j2): text.extend(["> ", lines2[j], "\n"]) i = i2 + l j = j2 + l return ''.join(text)
def _find_conflict(local, local_line_points, local_points, remote, remote_line_points, remote_points): assert len(local_line_points) == len(local) + 1 assert len(remote_line_points) == len(remote) + 1 lpdict = Set(local_points) for point in local_line_points: assert point in lpdict rpdict = Set(remote_points) for point in remote_line_points: assert point in rpdict result = [] result_line_points = [] lastl, lastr = 0, 0 selector = SelectLinePoint() selector.push(local_points) selector.push(remote_points) for (lpos, rpos, matchlen) in find_matches(local, remote) + [(len(local), len(remote), 0)]: rapplied = _is_applied(remote_line_points[lastr:rpos + 1], lpdict) lapplied = _is_applied(local_line_points[lastl:lpos + 1], rpdict) if rapplied and not lapplied: result.extend(local[lastl:lpos + matchlen]) result_line_points.extend(local_line_points[lastl:lpos + 1]) elif lapplied and not rapplied: result.extend(remote[lastr:rpos + matchlen]) result_line_points.extend(remote_line_points[lastr:rpos + 1]) elif (lastl, lastr) == (len(local), len(remote)): result_line_points.append(selector.select(local_line_points[-1], remote_line_points[-1])) elif (lpos, rpos) == (0, 0): result.extend(local[:matchlen]) result_line_points.append(selector.select(local_line_points[0], remote_line_points[0])) else: result.append((local[lastl:lpos], remote[lastr:rpos])) result.extend(local[lpos:lpos + matchlen]) result_line_points.append((local_line_points[lastl:lpos + 1], remote_line_points[lastr:rpos + 1])) result_line_points.append(None) for i in xrange(1, matchlen): result_line_points.append(selector.select(local_line_points[lpos + i], remote_line_points[rpos + i])) lastl, lastr = lpos + matchlen, rpos + matchlen result_points = selector.dump() return (result, result_line_points, result_points)
def find_annotation(precursors, resolution): result = [None] * len(resolution) selector = SelectLinePoint() for i in xrange(len(precursors)): match = find_matches(precursors[i][0], resolution) pre = precursors[i][0] pre_line_points = precursors[i][1] selector.push(precursors[i][2]) for (matchold, matchnew, matchlen) in match: for j in xrange(matchlen): result[matchnew + j] = selector.select( result[matchnew + j], pre_line_points[matchold + j]) return result
def find_resolution(precursors, resolution): result = [None] * (len(resolution) + 1) ms = [[] for i in xrange(len(precursors))] selector = SelectLinePoint() ms = [] for i in xrange(len(precursors)): ms.append(find_matches(precursors[i][0], resolution)) pre = precursors[i][0] pre_line_points = precursors[i][1] selector.push(precursors[i][2]) for (matchold, matchnew, matchlen) in ms[i]: begina, beginb, mlen = matchold + 1, matchnew + 1, matchlen - 1 if (matchold, matchnew) == (0, 0): (begina, beginb, mlen) = (0, 0, mlen + 1) if (matchold + matchlen, matchnew + matchlen) == (len(pre), len(resolution)): mlen += 1 for j in xrange(mlen): result[beginb + j] = selector.select( result[beginb + j], pre_line_points[begina + j]) # mark each line as to whether we need a newline for it hits = [False] * len(resolution) for i in xrange(len(ms)): for (matchold, matchnew, matchlen) in ms[i]: hits[matchnew:matchnew + matchlen] = [True] * matchlen # this may seem weird, but there's this really annoying ambiguous clean # merge case which sometimes turns up when the match algorithm finds an # "incorrect" match. the same conflicts which the person has just resolved # will happen again on merges through other repositories. this code # puts in new line points to prevent that from happening. if len(precursors) > 1: breaks = [] for i in xrange(len(precursors)): l, lp, p = precursors[i] lastl, lastr = 0, 0 ms[i].append((len(l), len(resolution), 0)) for (lpos, rpos, mlen) in ms[i]: # if it doesn't declare itself the winner, it will cause # conflicts later rapplied = _is_applied(result[lastr:rpos + 1], p) if (lpos, rpos) == (0, 0) or \ (lastl, lastr) == (len(l), len(resolution)): pass elif rapplied: breaks.append((lastr, rpos - lastr)) # fix hits so newlines are created hits[lastr:rpos] = [False] * (rpos - lastr) lastl, lastr = lpos + mlen, rpos + mlen breaks.sort() # make the matches not overlap the breaks for i in xrange(len(ms)): newms = [] cur_match = 0 try: for (bpos, blen) in breaks: lpos, rpos, mlen = ms[i][cur_match] # no overlap, nothing to do while rpos + mlen <= bpos: newms.append(ms[i][cur_match]) cur_match += 1 if cur_match >= len(ms[i]): raise NoMoreMatchesException lpos, rpos, mlen = ms[i][cur_match] # some overlap at the end of the match if rpos < bpos: newms.append((lpos, rpos, bpos - rpos)) # full overlap while rpos + mlen <= bpos + blen: cur_match += 1 if cur_match >= len(ms[i]): raise NoMoreMatchesException lpos, rpos, mlen = ms[i][cur_match] # partial overlap, fix it up for the next iteration if rpos < bpos + blen: adj = bpos + blen - rpos m = (lpos + adj, bpos + blen, mlen - adj) ms[i][cur_match] = m except NoMoreMatchesException: pass # add remaining matches at the end, dropping the dummy newms.extend(ms[i][cur_match:-1]) ms[i] = newms # reset results for (bpos, blen) in breaks: result[bpos:bpos + blen + 1] = [None] * (blen + 1) # figure out what's not covered by matches newlines = [] pos = 0 while pos < len(hits): if hits[pos]: pos += 1 else: n = [] j = pos while j < len(hits) and not hits[j]: n.append(resolution[j]) j += 1 newlines.append((pos, n)) pos = j return (result, ms, newlines)
def find_resolution(precursors, resolution): result = [None] * (len(resolution) + 1) ms = [[] for i in xrange(len(precursors))] selector = SelectLinePoint() ms = [] for i in xrange(len(precursors)): ms.append(find_matches(precursors[i][0], resolution)) pre = precursors[i][0] pre_line_points = precursors[i][1] selector.push(precursors[i][2]) for (matchold, matchnew, matchlen) in ms[i]: begina, beginb, mlen = matchold + 1, matchnew + 1, matchlen - 1 if (matchold, matchnew) == (0, 0): (begina, beginb, mlen) = (0, 0, mlen + 1) if (matchold + matchlen, matchnew + matchlen) == (len(pre), len(resolution)): mlen += 1 for j in xrange(mlen): result[beginb + j] = selector.select(result[beginb + j], pre_line_points[begina + j]) # mark each line as to whether we need a newline for it hits = [False] * len(resolution) for i in xrange(len(ms)): for (matchold, matchnew, matchlen) in ms[i]: hits[matchnew:matchnew + matchlen] = [True] * matchlen # this may seem weird, but there's this really annoying ambiguous clean # merge case which sometimes turns up when the match algorithm finds an # "incorrect" match. the same conflicts which the person has just resolved # will happen again on merges through other repositories. this code # puts in new line points to prevent that from happening. if len(precursors) > 1: breaks = [] for i in xrange(len(precursors)): l, lp, p = precursors[i] lastl, lastr = 0, 0 ms[i].append((len(l), len(resolution), 0)) for (lpos, rpos, mlen) in ms[i]: # if it doesn't declare itself the winner, it will cause # conflicts later rapplied = _is_applied(result[lastr:rpos + 1], p) if (lpos, rpos) == (0, 0) or \ (lastl, lastr) == (len(l), len(resolution)): pass elif rapplied: breaks.append((lastr, rpos - lastr)) # fix hits so newlines are created hits[lastr:rpos] = [False] * (rpos - lastr) lastl, lastr = lpos + mlen, rpos + mlen breaks.sort() # make the matches not overlap the breaks for i in xrange(len(ms)): newms = [] cur_match = 0 try: for (bpos, blen) in breaks: lpos, rpos, mlen = ms[i][cur_match] # no overlap, nothing to do while rpos + mlen <= bpos: newms.append(ms[i][cur_match]) cur_match += 1 if cur_match >= len(ms[i]): raise NoMoreMatchesException lpos, rpos, mlen = ms[i][cur_match] # some overlap at the end of the match if rpos < bpos: newms.append((lpos, rpos, bpos - rpos)) # full overlap while rpos + mlen <= bpos + blen: cur_match += 1 if cur_match >= len(ms[i]): raise NoMoreMatchesException lpos, rpos, mlen = ms[i][cur_match] # partial overlap, fix it up for the next iteration if rpos < bpos + blen: adj = bpos + blen - rpos m = (lpos + adj, bpos + blen, mlen - adj) ms[i][cur_match] = m except NoMoreMatchesException: pass # add remaining matches at the end, dropping the dummy newms.extend(ms[i][cur_match:-1]) ms[i] = newms # reset results for (bpos, blen) in breaks: result[bpos:bpos + blen + 1] = [None] * (blen + 1) # figure out what's not covered by matches newlines = [] pos = 0 while pos < len(hits): if hits[pos]: pos += 1 else: n = [] j = pos while j < len(hits) and not hits[j]: n.append(resolution[j]) j += 1 newlines.append((pos, n)) pos = j return (result, ms, newlines)