/brz/remove-bazaar

To get this branch, use:
bzr branch http://gegoxaren.bato24.eu/bzr/brz/remove-bazaar
7406.4.1 by Jelmer Vernooij
Initial work on supporting colordiff.
1
# Copyright (C) 2006 Aaron Bentley
2
# <aaron@aaronbentley.com>
3
#
7406.4.4 by Jelmer Vernooij
Fix remaining tests.
4
# This program is free software; you can redistribute it and/or modify
5
# it under the terms of the GNU General Public License as published by
6
# the Free Software Foundation; either version 2 of the License, or
7
# (at your option) any later version.
8
#
9
# This program is distributed in the hope that it will be useful,
10
# but WITHOUT ANY WARRANTY; without even the implied warranty of
11
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12
# GNU General Public License for more details.
13
#
14
# You should have received a copy of the GNU General Public License
15
# along with this program; if not, write to the Free Software
16
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
17
7406.4.1 by Jelmer Vernooij
Initial work on supporting colordiff.
18
import re
19
import sys
20
from os.path import expanduser
21
import patiencediff
22
23
from . import trace, terminal
24
from .commands import get_cmd_object
25
from .patches import (hunk_from_header, InsertLine, RemoveLine,
26
                      ContextLine, Hunk, HunkLine)
27
28
7406.4.5 by Jelmer Vernooij
Add a test.
29
GLOBAL_COLORDIFFRC = '/etc/colordiffrc'
30
7406.4.1 by Jelmer Vernooij
Initial work on supporting colordiff.
31
class LineParser(object):
32
33
    def parse_line(self, line):
7406.4.2 by Jelmer Vernooij
Fix colordiff.
34
        if line.startswith(b"@"):
7406.4.1 by Jelmer Vernooij
Initial work on supporting colordiff.
35
            return hunk_from_header(line)
7406.4.2 by Jelmer Vernooij
Fix colordiff.
36
        elif line.startswith(b"+"):
7406.4.1 by Jelmer Vernooij
Initial work on supporting colordiff.
37
            return InsertLine(line[1:])
7406.4.2 by Jelmer Vernooij
Fix colordiff.
38
        elif line.startswith(b"-"):
7406.4.1 by Jelmer Vernooij
Initial work on supporting colordiff.
39
            return RemoveLine(line[1:])
7406.4.2 by Jelmer Vernooij
Fix colordiff.
40
        elif line.startswith(b" "):
7406.4.1 by Jelmer Vernooij
Initial work on supporting colordiff.
41
            return ContextLine(line[1:])
42
        else:
43
            return line
44
45
7406.4.5 by Jelmer Vernooij
Add a test.
46
def read_colordiffrc(path):
47
    colors = {}
48
    with open(path, 'r') as f:
49
        for line in f.readlines():
50
            try:
51
                key, val = line.split('=')
52
            except ValueError:
53
                continue
54
55
            key = key.strip()
56
            val = val.strip()
57
58
            tmp = val
59
            if val.startswith('dark'):
60
                tmp = val[4:]
61
62
            if tmp not in terminal.colors:
63
                continue
64
65
            colors[key] = val
66
    return colors
67
68
7406.4.1 by Jelmer Vernooij
Initial work on supporting colordiff.
69
class DiffWriter(object):
70
71
    def __init__(self, target, check_style=False):
72
        self.target = target
73
        self.lp = LineParser()
74
        self.chunks = []
75
        self.colors = {
7406.4.4 by Jelmer Vernooij
Fix remaining tests.
76
            'metaline': 'darkyellow',
77
            'plain': 'darkwhite',
78
            'newtext': 'darkblue',
79
            'oldtext': 'darkred',
80
            'diffstuff': 'darkgreen',
7406.4.1 by Jelmer Vernooij
Initial work on supporting colordiff.
81
            'trailingspace': 'yellow',
7406.4.4 by Jelmer Vernooij
Fix remaining tests.
82
            'leadingtabs': 'magenta',
83
            'longline': 'cyan',
7406.4.1 by Jelmer Vernooij
Initial work on supporting colordiff.
84
        }
7406.4.5 by Jelmer Vernooij
Add a test.
85
        if GLOBAL_COLORDIFFRC is not None:
86
            self._read_colordiffrc(GLOBAL_COLORDIFFRC)
7406.4.1 by Jelmer Vernooij
Initial work on supporting colordiff.
87
        self._read_colordiffrc(expanduser('~/.colordiffrc'))
88
        self.added_leading_tabs = 0
89
        self.added_trailing_whitespace = 0
90
        self.spurious_whitespace = 0
91
        self.long_lines = 0
92
        self.max_line_len = 79
93
        self._new_lines = []
94
        self._old_lines = []
95
        self.check_style = check_style
96
97
    def _read_colordiffrc(self, path):
98
        try:
7406.4.5 by Jelmer Vernooij
Add a test.
99
            self.colors.update(read_colordiffrc(path))
7406.4.1 by Jelmer Vernooij
Initial work on supporting colordiff.
100
        except IOError:
7406.4.5 by Jelmer Vernooij
Add a test.
101
            pass
7406.4.1 by Jelmer Vernooij
Initial work on supporting colordiff.
102
103
    def colorstring(self, type, item, bad_ws_match):
104
        color = self.colors[type]
105
        if color is not None:
106
            if self.check_style and bad_ws_match:
107
                #highlight were needed
7406.4.4 by Jelmer Vernooij
Fix remaining tests.
108
                item.contents = ''.join(
109
                    terminal.colorstring(txt, color, bcol)
7406.4.1 by Jelmer Vernooij
Initial work on supporting colordiff.
110
                    for txt, bcol in (
111
                        (bad_ws_match.group(1).expandtabs(),
7406.4.4 by Jelmer Vernooij
Fix remaining tests.
112
                         self.colors['leadingtabs']),
7406.4.1 by Jelmer Vernooij
Initial work on supporting colordiff.
113
                        (bad_ws_match.group(2)[0:self.max_line_len], None),
114
                        (bad_ws_match.group(2)[self.max_line_len:],
7406.4.4 by Jelmer Vernooij
Fix remaining tests.
115
                         self.colors['longline']),
7406.4.1 by Jelmer Vernooij
Initial work on supporting colordiff.
116
                        (bad_ws_match.group(3), self.colors['trailingspace'])
117
                    )) + bad_ws_match.group(4)
7406.4.2 by Jelmer Vernooij
Fix colordiff.
118
            if not isinstance(item, bytes):
119
                item = item.as_bytes()
120
            string = terminal.colorstring(item, color)
7406.4.1 by Jelmer Vernooij
Initial work on supporting colordiff.
121
        else:
122
            string = str(item)
123
        self.target.write(string)
124
125
    def write(self, text):
7406.4.2 by Jelmer Vernooij
Fix colordiff.
126
        newstuff = text.split(b'\n')
7406.4.1 by Jelmer Vernooij
Initial work on supporting colordiff.
127
        for newchunk in newstuff[:-1]:
7406.4.2 by Jelmer Vernooij
Fix colordiff.
128
            self._writeline(b''.join(self.chunks + [newchunk, b'\n']))
7406.4.1 by Jelmer Vernooij
Initial work on supporting colordiff.
129
            self.chunks = []
130
        self.chunks = [newstuff[-1]]
131
132
    def writelines(self, lines):
133
        for line in lines:
134
            self.write(line)
135
136
    def _writeline(self, line):
137
        item = self.lp.parse_line(line)
138
        bad_ws_match = None
139
        if isinstance(item, Hunk):
140
            line_class = 'diffstuff'
141
            self._analyse_old_new()
142
        elif isinstance(item, HunkLine):
7406.4.2 by Jelmer Vernooij
Fix colordiff.
143
            bad_ws_match = re.match(br'^([\t]*)(.*?)([\t ]*)(\r?\n)$',
7406.4.1 by Jelmer Vernooij
Initial work on supporting colordiff.
144
                                    item.contents)
145
            has_leading_tabs = bool(bad_ws_match.group(1))
146
            has_trailing_whitespace = bool(bad_ws_match.group(3))
147
            if isinstance(item, InsertLine):
148
                if has_leading_tabs:
149
                    self.added_leading_tabs += 1
150
                if has_trailing_whitespace:
151
                    self.added_trailing_whitespace += 1
152
                if (len(bad_ws_match.group(2)) > self.max_line_len and
7406.4.4 by Jelmer Vernooij
Fix remaining tests.
153
                        not item.contents.startswith(b'++ ')):
7406.4.1 by Jelmer Vernooij
Initial work on supporting colordiff.
154
                    self.long_lines += 1
155
                line_class = 'newtext'
156
                self._new_lines.append(item)
157
            elif isinstance(item, RemoveLine):
158
                line_class = 'oldtext'
159
                self._old_lines.append(item)
160
            else:
161
                line_class = 'plain'
7406.4.2 by Jelmer Vernooij
Fix colordiff.
162
        elif isinstance(item, bytes) and item.startswith(b'==='):
7406.4.1 by Jelmer Vernooij
Initial work on supporting colordiff.
163
            line_class = 'metaline'
164
            self._analyse_old_new()
165
        else:
166
            line_class = 'plain'
167
            self._analyse_old_new()
168
        self.colorstring(line_class, item, bad_ws_match)
169
170
    def flush(self):
171
        self.target.flush()
172
173
    @staticmethod
174
    def _matched_lines(old, new):
175
        matcher = patiencediff.PatienceSequenceMatcher(None, old, new)
7406.4.2 by Jelmer Vernooij
Fix colordiff.
176
        matched_lines = sum(n for i, j, n in matcher.get_matching_blocks())
7406.4.1 by Jelmer Vernooij
Initial work on supporting colordiff.
177
        return matched_lines
178
179
    def _analyse_old_new(self):
180
        if (self._old_lines, self._new_lines) == ([], []):
181
            return
182
        if not self.check_style:
183
            return
184
        old = [l.contents for l in self._old_lines]
185
        new = [l.contents for l in self._new_lines]
186
        ws_matched = self._matched_lines(old, new)
187
        old = [l.rstrip() for l in old]
188
        new = [l.rstrip() for l in new]
189
        no_ws_matched = self._matched_lines(old, new)
7406.4.4 by Jelmer Vernooij
Fix remaining tests.
190
        if no_ws_matched < ws_matched:
191
            raise AssertionError
7406.4.1 by Jelmer Vernooij
Initial work on supporting colordiff.
192
        if no_ws_matched > ws_matched:
193
            self.spurious_whitespace += no_ws_matched - ws_matched
194
            self.target.write('^ Spurious whitespace change above.\n')
195
        self._old_lines, self._new_lines = ([], [])