Added toolbar icon for Show Changes.
[rox-edit/bju.git] / diff.py
blob501af03b4ab9568da319eecd97452088f41ad4f9
1 import rox
2 from rox import processes, g
3 from rox.options import Option
5 header_fg = Option('headers_fg', '#000')
6 header_bg = Option('headers_bg', '#ddd')
8 static_fg = Option('static_fg', '#000')
9 static_bg = Option('static_bg', '#fff')
11 additions_fg = Option('additions_fg', '#000')
12 additions_bg = Option('additions_bg', '#8f8')
14 deletions_fg = Option('deletions_fg', '#000')
15 deletions_bg = Option('deletions_bg', '#f88')
17 tags = g.TextTagTable()
19 header = g.TextTag('header')
20 tags.add(header)
22 static = g.TextTag('static')
23 tags.add(static)
25 add = g.TextTag('add')
26 tags.add(add)
27 remove = g.TextTag('remove')
28 tags.add(remove)
30 def options_changed():
31 header.set_property('foreground', header_fg.value)
32 header.set_property('background', header_bg.value)
33 static.set_property('foreground', static_fg.value)
34 static.set_property('background', static_bg.value)
35 add.set_property('foreground', additions_fg.value)
36 add.set_property('background', additions_bg.value)
37 remove.set_property('foreground', deletions_fg.value)
38 remove.set_property('background', deletions_bg.value)
40 rox.app_options.add_notify(options_changed)
42 class Diff(processes.PipeThroughCommand):
43 def __init__(self, uri, src, dst):
44 processes.PipeThroughCommand.__init__(self, ('diff', '-u', uri, '-'), src, dst)
45 self.wait()
47 def check_errors(self, errors, status):
48 if errors:
49 raise Exception(errors)
51 def Tmp(mode = 'w+b', suffix = '-tmp'):
52 "Create a seekable, randomly named temp file (deleted automatically after use)."
53 import tempfile
54 try:
55 return tempfile.NamedTemporaryFile(mode, suffix = suffix)
56 except:
57 # python2.2 doesn't have NamedTemporaryFile...
58 pass
60 import random
61 name = tempfile.mktemp(`random.randint(1, 1000000)` + suffix)
63 fd = os.open(name, os.O_RDWR|os.O_CREAT|os.O_EXCL, 0700)
64 tmp = tempfile.TemporaryFileWrapper(os.fdopen(fd, mode), name)
65 tmp.name = name
66 return tmp
68 class DiffWindow(rox.Dialog):
69 def __init__(self, uri, diff):
70 rox.Dialog.__init__(self)
71 self.set_title('Changes to %s' % uri)
72 self.set_has_separator(False)
74 buffer = g.TextBuffer(tags)
75 text = g.TextView(buffer)
76 text.set_editable(False)
77 text.set_cursor_visible(False)
78 text.modify_base(g.STATE_NORMAL, g.gdk.color_parse(static_bg.value))
80 swin = g.ScrolledWindow()
81 swin.set_shadow_type(g.SHADOW_IN)
82 swin.set_policy(g.POLICY_AUTOMATIC, g.POLICY_ALWAYS)
83 self.vbox.pack_start(swin)
84 swin.add(text)
85 self.vbox.show_all()
87 self.add_button(g.STOCK_CLOSE, g.RESPONSE_OK)
88 self.connect('response', lambda b, r: self.destroy())
90 iter = buffer.get_start_iter()
91 for line in diff.split('\n'):
92 line += '\n'
93 line = line.replace('\t', ' ')
94 if line[:4] in ('--- ', '+++ ', '@@ -'):
95 tag = header
96 elif line.startswith('-'):
97 tag = remove
98 if len(line) < 3: line = ' \n'
99 elif line.startswith('+'):
100 tag = add
101 if len(line) < 3: line = ' \n'
102 else:
103 tag = static
104 buffer.insert_with_tags(iter, line[1:], tag)
106 width = g.gdk.screen_width() * 3 / 4
107 height = g.gdk.screen_height() * 1 / 2
108 self.set_default_size(width, height)
111 def show_diff(uri, writer):
112 from cStringIO import StringIO
113 src = Tmp(suffix = '-diff')
114 dst = StringIO()
115 writer(src)
116 src.seek(0)
117 Diff(uri, src, dst)
118 del src
119 diff = dst.getvalue()
120 del dst
121 if not diff:
122 rox.info('There is no difference between this version and the saved one.')
123 else:
124 DiffWindow(uri, diff).show()