1
1
# -*- coding: iso-8859-1 -*-
3
3
MoinMoin - diff3 algorithm
5
@copyright: 2002 by Florian Festi
5
@copyright: 2002 Florian Festi
6
6
@license: GNU GPL, see COPYING for details.
9
def text_merge(old, other, new, allow_conflicts=1,
10
marker1='<<<<<<<<<<<<<<<<<<<<<<<<<\n',
11
marker2='=========================\n',
12
marker3='>>>>>>>>>>>>>>>>>>>>>>>>>\n'):
9
default_markers = ('<<<<<<<<<<<<<<<<<<<<<<<<<\n',
10
'=========================\n',
11
'>>>>>>>>>>>>>>>>>>>>>>>>>\n')
13
def text_merge(old, other, new, allow_conflicts=1, *markers):
13
14
""" do line by line diff3 merge with three strings """
14
15
result = merge(old.splitlines(1), other.splitlines(1), new.splitlines(1),
15
allow_conflicts, marker1, marker2, marker3)
16
allow_conflicts, *markers)
16
17
return ''.join(result)
18
def merge(old, other, new, allow_conflicts=1,
19
marker1='<<<<<<<<<<<<<<<<<<<<<<<<<\n',
20
marker2='=========================\n',
21
marker3='>>>>>>>>>>>>>>>>>>>>>>>>>\n'):
19
def merge(old, other, new, allow_conflicts=1, *markers):
22
20
""" do line by line diff3 merge
23
input must be lists containing single lines
21
input must be lists containing single lines
24
markers = default_markers
25
marker1, marker2, marker3 = markers
25
27
old_nr, other_nr, new_nr = 0, 0, 0
26
28
old_len, other_len, new_len = len(old), len(other), len(new)
28
while old_nr < old_len and other_nr < other_len and new_nr < new_len:
31
while old_nr < old_len and other_nr < other_len and new_nr < new_len:
30
33
if old[old_nr] == other[other_nr] == new[new_nr]:
31
34
result.append(old[old_nr])
39
if allow_conflicts == 2: # experimental addition to the algorithm
40
if other[other_nr] == new[new_nr]:
41
result.append(new[new_nr])
36
45
new_match = find_match(old, new, old_nr, new_nr)
37
46
other_match = find_match(old, other, old_nr, other_nr)
85
if old_nr == old_len and other_nr == other_len and new_nr == new_len:
94
if old_nr == old_len and other_nr == other_len and new_nr == new_len:
88
97
elif old_nr == old_len and other_nr == other_len:
89
98
result.extend(new[new_nr:])
90
99
# other added lines
91
100
elif old_nr == old_len and new_nr == new_len:
92
result.extend(other[other_nr])
101
result.extend(other[other_nr:])
93
102
# new deleted lines
94
103
elif (new_nr == new_len and (old_len - old_nr == other_len - other_nr) and
95
104
match(old, other, old_nr, other_nr, old_len-old_nr) == old_len - old_nr):
103
if not allow_conflicts:
105
result.append(marker1)
106
result.extend(other[other_nr:])
107
result.append(marker2)
108
result.extend(new[new_nr:])
109
result.append(marker3)
113
result.extend(new[new_nr:])
115
if not allow_conflicts:
117
result.append(marker1)
118
result.extend(other[other_nr:])
119
result.append(marker2)
120
result.extend(new[new_nr:])
121
result.append(marker3)
112
124
def tripple_match(old, other, new, other_match, new_match):
122
134
if match_len == difference:
123
135
return (new_match[0], other_match[1]+difference, new_match[1])
125
other_match = find_match(old, other,
126
other_match[0] + match_len,
127
other_match[1] + match_len)
137
other_match = find_match(old, other,
138
other_match[0] + match_len,
139
other_match[1] + match_len)
128
140
# other changed more lines
129
141
elif difference < 0:
130
142
difference = -difference
134
146
return (other_match[0], other_match[1],
135
147
new_match[0] + difference)
137
new_match = find_match(old, new,
138
new_match[0] + match_len,
139
new_match[1] + match_len)
149
new_match = find_match(old, new,
150
new_match[0] + match_len,
151
new_match[1] + match_len)
140
152
# both conflicts change same number of lines
141
153
# or no match till the end
143
155
return (new_match[0], other_match[1], new_match[1])
145
157
def match(list1, list2, nr1, nr2, maxcount=3):
146
158
""" return the number matching items after the given positions
147
maximum maxcount lines are are processed
159
maximum maxcount lines are are processed
150
162
len1 = len(list1)