~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/textmerge.py

Implemented two-way merge, refactored weave merge

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
# Copyright (C) 2005, 2006 Canonical Ltd
 
2
#
 
3
# This program is free software; you can redistribute it and/or modify
 
4
# it under the terms of the GNU General Public License as published by
 
5
# the Free Software Foundation; either version 2 of the License, or
 
6
# (at your option) any later version.
 
7
#
 
8
# This program is distributed in the hope that it will be useful,
 
9
# but WITHOUT ANY WARRANTY; without even the implied warranty of
 
10
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
11
# GNU General Public License for more details.
 
12
#
 
13
# You should have received a copy of the GNU General Public License
 
14
# along with this program; if not, write to the Free Software
 
15
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 
16
#
 
17
# Author: Martin Pool <mbp@canonical.com> 
 
18
#         Aaron Bentley <aaron.bentley@utoronto.ca>
 
19
 
 
20
from difflib import SequenceMatcher
 
21
 
 
22
 
 
23
class TextMerge(object):
 
24
    def __init__(self, a_marker='<<<<<<< \n', b_marker='>>>>>>> \n',
 
25
                 split_marker='=======\n'):
 
26
        self.a_marker = a_marker
 
27
        self.b_marker = b_marker
 
28
        self.split_marker = split_marker
 
29
 
 
30
    def struct_to_lines(self, struct_iter):
 
31
        for lines in struct_iter:
 
32
            if len(lines) == 1:
 
33
                for line in lines[0]:
 
34
                    yield line
 
35
            else:
 
36
                yield self.a_marker
 
37
                for line in lines[0]: 
 
38
                    yield line
 
39
                yield self.split_marker
 
40
                for line in lines[1]: 
 
41
                    yield line
 
42
                yield self.b_marker
 
43
 
 
44
    def iter_useful(self, struct_iter):
 
45
        for group in struct_iter:
 
46
            if len(group[0]) > 0:
 
47
                yield group
 
48
            elif len(group) > 1 and len(group[1]) > 0:
 
49
                yield group
 
50
 
 
51
    def merge_lines(self):
 
52
        return self.struct_to_lines(self.merge_struct())
 
53
 
 
54
    def merge_struct(self):
 
55
        return  self.iter_useful(self._merge_struct())
 
56
 
 
57
 
 
58
class Merge2(TextMerge):
 
59
 
 
60
    """
 
61
    Two-way merge.
 
62
    In a two way merge, common regions are shown as unconflicting, and uncommon
 
63
    regions produce conflicts.
 
64
    """
 
65
    def __init__(self, lines_a, lines_b, a_marker='<<<<<<< \n', 
 
66
                 b_marker='>>>>>>> \n', split_marker='=======\n'):
 
67
        TextMerge.__init__(self, a_marker, b_marker, split_marker)
 
68
        self.lines_a = lines_a
 
69
        self.lines_b = lines_b
 
70
 
 
71
    def _merge_struct(self):
 
72
        sm = SequenceMatcher(None, self.lines_a, self.lines_b)
 
73
        pos_a = 0
 
74
        pos_b = 0
 
75
        for ai, bi, l in sm.get_matching_blocks():
 
76
            # non-matching lines
 
77
            yield(self.lines_a[pos_a:ai], self.lines_b[pos_b:bi])
 
78
            # matching lines
 
79
            yield(self.lines_a[ai:ai+l],)
 
80
            pos_a = ai + l 
 
81
            pos_b = bi + l
 
82
        # final non-matching lines
 
83
        yield(self.lines_a[pos_a:-1], self.lines_b[pos_b:-1])