~abentley/bzrtools/bzrtools.dev

399 by Aaron Bentley
Implement cdiff (based on old Fai code)
1
# Copyright (C) 2006 Aaron Bentley
2
# <aaron.bentley@utoronto.ca>
3
#
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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
17
18
import sys
400.1.2 by Michael Ellerman
Parse ~/.colordiffrc for colour information if it's there.
19
from os.path import expanduser
399 by Aaron Bentley
Implement cdiff (based on old Fai code)
20
408.1.1 by Adeodato Simó
Get command objects via get_cmd_object(), instead of directly importing
21
from bzrlib.commands import get_cmd_object
399 by Aaron Bentley
Implement cdiff (based on old Fai code)
22
from bzrlib.patches import (hunk_from_header, InsertLine, RemoveLine,
23
                            ContextLine, Hunk)
24
400.1.2 by Michael Ellerman
Parse ~/.colordiffrc for colour information if it's there.
25
import terminal
399 by Aaron Bentley
Implement cdiff (based on old Fai code)
26
27
class LineParser(object):
28
    def parse_line(self, line):
29
        if line.startswith("@"):
30
            return hunk_from_header(line)
31
        elif line.startswith("+"):
32
            return InsertLine(line[1:])
33
        elif line.startswith("-"):
34
            return RemoveLine(line[1:])
35
        elif line.startswith(" "):
36
            return ContextLine(line[1:])
37
        else:
38
            return line
39
400.1.2 by Michael Ellerman
Parse ~/.colordiffrc for colour information if it's there.
40
399 by Aaron Bentley
Implement cdiff (based on old Fai code)
41
class DiffWriter(object):
400.1.2 by Michael Ellerman
Parse ~/.colordiffrc for colour information if it's there.
42
43
    colors = {
406 by Aaron Bentley
Rename modline -> metaline, style tweakage
44
        'metaline':    'darkyellow',
412 by Aaron Bentley
Make Ellerman's cdiff colours the default
45
        'plain':       'darkwhite',
46
        'newtext':     'darkblue',
47
        'oldtext':     'darkred',
48
        'diffstuff':   'darkgreen'
400.1.2 by Michael Ellerman
Parse ~/.colordiffrc for colour information if it's there.
49
    }
50
399 by Aaron Bentley
Implement cdiff (based on old Fai code)
51
    def __init__(self, target):
52
        self.target = target
53
        self.lp = LineParser()
400 by Aaron Bentley
Don't just assume we get lines
54
        self.chunks = []
400.1.2 by Michael Ellerman
Parse ~/.colordiffrc for colour information if it's there.
55
        self._read_colordiffrc()
56
57
    def _read_colordiffrc(self):
58
        path = expanduser('~/.colordiffrc')
59
        try:
60
            f = open(path, 'r')
61
        except IOError:
62
            return
63
64
        for line in f.readlines():
65
            try:
66
                key, val = line.split('=')
67
            except ValueError:
68
                continue
69
70
            key = key.strip()
71
            val = val.strip()
72
73
            tmp = val
74
            if val.startswith('dark'):
75
                tmp = val[4:]
76
77
            if tmp not in terminal.colors:
78
                continue
79
80
            self.colors[key] = val
81
82
    def colorstring(self, type, string):
83
        color = self.colors[type]
400.1.3 by Michael Ellerman
Support for colordiff's 'plain', which colours the context text.
84
        if color is not None:
85
            string = terminal.colorstring(str(string), color)
86
        self.target.write(string)
399 by Aaron Bentley
Implement cdiff (based on old Fai code)
87
88
    def write(self, text):
400 by Aaron Bentley
Don't just assume we get lines
89
        newstuff = text.split('\n')
90
        for newchunk in newstuff[:-1]:
91
            self._writeline(''.join(self.chunks + [newchunk, '\n']))
92
            self.chunks = []
93
        self.chunks = [newstuff[-1]]
94
95
    def _writeline(self, line):
96
        item = self.lp.parse_line(line)
399 by Aaron Bentley
Implement cdiff (based on old Fai code)
97
        if isinstance(item, Hunk):
406 by Aaron Bentley
Rename modline -> metaline, style tweakage
98
            line_class = 'diffstuff'
399 by Aaron Bentley
Implement cdiff (based on old Fai code)
99
        elif isinstance(item, InsertLine):
406 by Aaron Bentley
Rename modline -> metaline, style tweakage
100
            line_class = 'newtext'
399 by Aaron Bentley
Implement cdiff (based on old Fai code)
101
        elif isinstance(item, RemoveLine):
406 by Aaron Bentley
Rename modline -> metaline, style tweakage
102
            line_class = 'oldtext'
400.1.3 by Michael Ellerman
Support for colordiff's 'plain', which colours the context text.
103
        elif isinstance(item, basestring) and item.startswith('==='):
406 by Aaron Bentley
Rename modline -> metaline, style tweakage
104
            line_class = 'metaline'
399 by Aaron Bentley
Implement cdiff (based on old Fai code)
105
        else:
406 by Aaron Bentley
Rename modline -> metaline, style tweakage
106
            line_class = 'plain'
107
        self.colorstring(line_class, str(item))
399 by Aaron Bentley
Implement cdiff (based on old Fai code)
108
109
    def flush(self):
110
        self.target.flush()
111
112
def colordiff(self, *args, **kwargs):
113
    real_stdout = sys.stdout
114
    sys.stdout = DiffWriter(real_stdout)
115
    try:
408.1.1 by Adeodato Simó
Get command objects via get_cmd_object(), instead of directly importing
116
        get_cmd_object('diff').run(*args, **kwargs)
399 by Aaron Bentley
Implement cdiff (based on old Fai code)
117
    finally:
118
        sys.stdout = real_stdout