~lifeless/bzrtools/trunk

« back to all changes in this revision

Viewing changes to colordiff.py

  • Committer: Robert Collins
  • Date: 2008-07-08 04:11:21 UTC
  • mfrom: (623.1.33 bzrtools)
  • Revision ID: robertc@robertcollins.net-20080708041121-lo0k7os2y03uclt2
Merge trunk.

Show diffs side-by-side

added added

removed removed

Lines of Context:
15
15
#    along with this program; if not, write to the Free Software
16
16
#    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
17
17
 
 
18
import re
18
19
import sys
19
20
from os.path import expanduser
20
21
 
21
22
from bzrlib import patiencediff, trace
22
23
from bzrlib.commands import get_cmd_object
23
24
from bzrlib.patches import (hunk_from_header, InsertLine, RemoveLine,
24
 
                            ContextLine, Hunk)
 
25
                            ContextLine, Hunk, HunkLine)
25
26
 
26
27
import terminal
27
28
 
42
43
class DiffWriter(object):
43
44
 
44
45
    colors = {
45
 
        'metaline':    'darkyellow',
46
 
        'plain':       'darkwhite',
47
 
        'newtext':     'darkblue',
48
 
        'oldtext':     'darkred',
49
 
        'diffstuff':   'darkgreen'
 
46
        'metaline':      'darkyellow',
 
47
        'plain':         'darkwhite',
 
48
        'newtext':       'darkblue',
 
49
        'oldtext':       'darkred',
 
50
        'diffstuff':     'darkgreen',
 
51
        'trailingspace': 'yellow',
 
52
        'leadingtabs':   'magenta',
 
53
        'longline':      'cyan',
50
54
    }
51
55
 
52
56
    def __init__(self, target, check_style):
54
58
        self.lp = LineParser()
55
59
        self.chunks = []
56
60
        self._read_colordiffrc()
 
61
        self.added_leading_tabs = 0
57
62
        self.added_trailing_whitespace = 0
58
63
        self.spurious_whitespace = 0
59
64
        self.long_lines = 0
87
92
 
88
93
            self.colors[key] = val
89
94
 
90
 
    def colorstring(self, type, string):
 
95
    def colorstring(self, type, item, bad_ws_match):
91
96
        color = self.colors[type]
92
97
        if color is not None:
93
 
            string = terminal.colorstring(str(string), color)
 
98
            if self.check_style and bad_ws_match:
 
99
                #highlight were needed
 
100
                item.contents = ''.join(terminal.colorstring(txt, color, bcol)
 
101
                    for txt, bcol in (
 
102
                        (bad_ws_match.group(1).expandtabs(),
 
103
                             self.colors['leadingtabs']),
 
104
                        (bad_ws_match.group(2)[0:self.max_line_len], None),
 
105
                        (bad_ws_match.group(2)[self.max_line_len:],
 
106
                             self.colors['longline']),
 
107
                        (bad_ws_match.group(3), self.colors['trailingspace'])
 
108
                    )) + bad_ws_match.group(4)
 
109
            string = terminal.colorstring(str(item), color)
 
110
        else:
 
111
            string = str(item)
94
112
        self.target.write(string)
95
113
 
96
114
    def write(self, text):
102
120
 
103
121
    def _writeline(self, line):
104
122
        item = self.lp.parse_line(line)
 
123
        bad_ws_match = None
105
124
        if isinstance(item, Hunk):
106
125
            line_class = 'diffstuff'
107
126
            self._analyse_old_new()
108
 
        elif isinstance(item, InsertLine):
109
 
            if item.contents.endswith(' \n'):
110
 
                self.added_trailing_whitespace += 1
111
 
            if (len(item.contents.rstrip('\n')) > self.max_line_len and
112
 
                not item.contents.startswith('++ ')):
113
 
                self.long_lines += 1
114
 
            line_class = 'newtext'
115
 
            self._new_lines.append(item)
116
 
        elif isinstance(item, RemoveLine):
117
 
            line_class = 'oldtext'
118
 
            self._old_lines.append(item)
 
127
        elif isinstance(item, HunkLine):
 
128
            bad_ws_match = re.match(r'^([\t]*)(.*?)([\t ]*)(\r?\n)$',
 
129
                                    item.contents)
 
130
            has_leading_tabs = bool(bad_ws_match.group(1))
 
131
            has_trailing_whitespace = bool(bad_ws_match.group(3))
 
132
            if isinstance(item, InsertLine):
 
133
                if has_leading_tabs:
 
134
                    self.added_leading_tabs += 1
 
135
                if has_trailing_whitespace:
 
136
                    self.added_trailing_whitespace += 1
 
137
                if (len(bad_ws_match.group(2)) > self.max_line_len and
 
138
                    not item.contents.startswith('++ ')):
 
139
                    self.long_lines += 1
 
140
                line_class = 'newtext'
 
141
                self._new_lines.append(item)
 
142
            elif isinstance(item, RemoveLine):
 
143
                line_class = 'oldtext'
 
144
                self._old_lines.append(item)
 
145
            else:
 
146
                line_class = 'plain'
119
147
        elif isinstance(item, basestring) and item.startswith('==='):
120
148
            line_class = 'metaline'
121
149
            self._analyse_old_new()
122
150
        else:
123
151
            line_class = 'plain'
124
152
            self._analyse_old_new()
125
 
        self.colorstring(line_class, str(item))
 
153
        self.colorstring(line_class, item, bad_ws_match)
126
154
 
127
155
    def flush(self):
128
156
        self.target.flush()
160
188
    finally:
161
189
        sys.stdout = real_stdout
162
190
    if check_style:
 
191
        if dw.added_leading_tabs > 0:
 
192
            trace.warning('%d new line(s) have leading tabs.' %
 
193
                          dw.added_leading_tabs)
163
194
        if dw.added_trailing_whitespace > 0:
164
195
            trace.warning('%d new line(s) have trailing whitespace.' %
165
196
                          dw.added_trailing_whitespace)