Backported Google Talk mail notification support and disabling of the mail notificati...
[adiumx.git] / Utilities / listToHTML.py
blobc0c946d6663b0f385520a4b69d6972977e1ea6d6
1 #!/usr/bin/env python
3 """
4 listToHTML: convert The List from its normal format to HTML for easier (maybe) reading.
6 usage: listToHTML theList.txt theList.html
8 ---
9 submitted by Mac-arena the Bored Zo.
10 part of Adium by Adam Iser.
11 /*-------------------------------------------------------------------------------------------------------*\
12 | Adium, Copyright (C) 2001-2004, Adam Iser (adamiser@mac.com | http://www.adiumx.com) |
13 \---------------------------------------------------------------------------------------------------------/
14 | This program is free software; you can redistribute it and/or modify it under the terms of the GNU
15 | General Public License as published by the Free Software Foundation; either version 2 of the License,
16 | or (at your option) any later version.
18 | This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even
19 | the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
20 | Public License for more details.
22 | You should have received a copy of the GNU General Public License along with this program; if not,
23 | write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
24 \------------------------------------------------------------------------------------------------------ */
25 """
27 task_names = {
28 '+': "change or addition",
29 '-': "removal",
30 '*': "bug-fix",
31 '#': "debatable",
32 '=': "done",
34 task_colours = {
35 '+': "#008800", #change or addition
36 '-': "#8800FF", #removal
37 '*': "#0000FF", #bug-fix
38 '#': "#FF0000", #debatable
39 '=': "#888888", #done
41 fallbacks = []
43 def genfallbacks(fallbacks):
44 """
45 prepare to generate colours that aren't in the default dictionary, in case the legend changes.
46 'fallbacks' must have an append method.
47 """
49 increment = 0x11
50 red, green, blue = (0,0,0)
51 format = '#%x%x%x'
52 defaults = task_colours.values()
54 while red <= 0xFF and green <= 0xFF and blue <= 0xFF:
55 color = format % (red, green, blue)
56 if color not in defaults:
57 fallbacks.append(color)
58 if blue == 0xFF:
59 if green == 0xFF:
60 red += increment
61 green = 0x00
62 else:
63 green += increment
64 blue = 0x00
65 else:
66 blue += increment
67 del increment, red, green, blue, format, defaults
69 def warn(warning):
70 import sys
71 print >>sys.stderr, warning
73 def CSSclass(instr):
74 "given a string, turn it into something usable as a CSS class name."
76 index = instr.find('(')
77 if index >= 0:
78 instr = instr[:index]
80 instr = instr.strip()
82 import re
83 instr = re.sub("\s+", '_', instr)
85 return instr
87 def HTMLescape(instr):
88 "given a string, turn it into something usable inside an HTML file (by escaping '<>&' with entities)."
90 def HTMLentity(match):
91 matchstr = match.group(0)
92 if matchstr == '&':
93 return '&amp;'
94 elif matchstr == '<':
95 return '&lt;'
96 elif matchstr == '>':
97 return '&gt;'
98 else:
99 return matchstr
101 import re
102 return re.sub('[&<>]', HTMLentity, instr)
104 def listToHTML(infile, outfile):
105 "the converter. pass an iterable (infile) and a flob that exports the 'write' method (outfile)."
107 import re
109 legendRE = re.compile("Legend", re.IGNORECASE)
110 categories = []
111 catsepRE = re.compile('^\s*(?P<BULLET>.) (?P<NAME>.+)\s*$')
112 separatorRE = re.compile('^-+$')
113 subheadingRE = re.compile("^(?P<WHITESPACE>\s*)(?P<NAME>.+):\s*$")
114 taskRE = re.compile("^\s*(?P<BULLET>.) (?P<TASK>.+)$")
116 mode = object()
117 legendMode = object()
118 headingMode = object()
119 taskMode = object()
120 inBody = False
121 inTaskList = False
122 inTask = False
124 genfallbacks(fallbacks)
126 reservoir = []
128 legendFmt = '<dt>%(bullet)s</dt>\n\t<dd class="%(CSS name)s">%(name)s</dd>\n'
129 taskStartFmt = '\t<li class="%(bullet name)s">%(task)s'
130 ruleFmt = '\t.%(bullet name)s { color: %(color)s }\n'
132 outfile.write(
133 '<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">\n'
134 "<html><head>\n"
135 '<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">\n'
136 "<title>The List&trade;</title>\n"
137 '<style type="text/css">\n'
138 'body { color: black; background-color: white }\n')
140 lineno = 0
141 try:
142 for buf in infile:
143 lineno += 1
144 if legendRE.search(buf):
145 mode = legendMode
146 elif separatorRE.match(buf):
147 if not inBody:
148 outfile.write(
149 "</style>\n"
150 "</head>\n"
151 "<body>\n")
152 inBody = True
153 if inTask:
154 outfile.write("\t</li>\n")
155 inTask = False
156 if inTaskList:
157 outfile.write(
158 "</ul>\n"
159 "<hr>\n")
160 inTaskList = False
161 if mode is legendMode:
162 #starting separator.
163 #write out the legend.
164 outfile.write(
165 "<h1>Legend</h1>\n"
166 '<dl>\n')
167 outfile.write(''.join(reservoir))
168 outfile.write('</dl>\n<hr>\n')
169 del reservoir[:]
171 if mode is legendMode or mode is taskMode:
172 #begin heading mode
173 outfile.write("\n<h1>")
174 mode = headingMode
175 elif mode is headingMode:
176 #ending separator.
177 outfile.write(''.join(reservoir))
178 del reservoir[:]
179 outfile.write("</h1>\n")
180 mode = taskMode
181 else:
182 if mode is legendMode:
183 match = catsepRE.match(buf)
184 if match:
185 bullet, name = match.groups()
186 if bullet not in task_colours:
187 task_colours[bullet] = fallbacks.pop()
188 task_names[bullet] = CSSname = CSSclass(name)
189 #add the list pair for the legend section of the page.
190 reservoir.append(legendFmt % {
191 'bullet': bullet,
192 'CSS name': CSSname,
193 'name': HTMLescape(name),
194 'color': task_colours[bullet],
196 #write the CSS rule.
197 outfile.write(ruleFmt % {
198 'bullet name': CSSname,
199 'color': task_colours[bullet],
202 elif mode is headingMode:
203 reservoir.append(buf)
204 elif mode is taskMode:
205 sbuf = buf.strip()
206 match = taskRE.match(sbuf)
207 if match:
208 if not inTaskList:
209 outfile.write("<ul>\n")
210 inTaskList = True
211 bullet, taskStart = match.groups()
212 if task_names.has_key(bullet):
213 bullet_name = task_names[bullet]
214 if inTask:
215 outfile.write("\t</li>\n")
216 else:
217 inTask = True
218 outfile.write(taskStartFmt % {
219 'bullet': bullet,
220 'task': HTMLescape(taskStart)+'\n',
221 'bullet name': bullet_name
223 else:
224 match = None
225 if not match:
226 match = subheadingRE.match(buf)
227 if match:
228 if inTask:
229 outfile.write("\t</li>\n")
230 inTask = False
231 if inTaskList:
232 outfile.write("</ul>\n")
233 h_number = 2
234 ws = match.group("WHITESPACE").replace(' ', '\t')
235 h_number += len(ws)
236 outfile.write("<h%u>" % h_number)
237 outfile.write(HTMLescape(match.group("NAME")))
238 outfile.write("</h%u>\n" % h_number)
239 if inTaskList:
240 outfile.write("<ul>\n")
241 else:
242 #continue a task.
243 if buf.strip():
244 if not inTaskList:
245 outfile.write("<ul>\n")
246 inTaskList = True
247 if not inTask:
248 outfile.write("\t<li>\n")
249 inTask = True
250 outfile.write(HTMLescape(buf))
251 except:
252 print >> sys.stderr, 'Error while processing line %u: %r' % (lineno, buf)
253 raise
254 if inTask:
255 outfile.write("\t</li>\n")
256 if inTaskList:
257 outfile.write("</ul>\n")
258 if inBody:
259 outfile.write("</body>\n")
260 outfile.write("</html>\n")
262 if __name__ == "__main__":
263 import sys
264 infile = file(sys.argv[1], 'rU', 1)
265 outfile = file(sys.argv[2], 'w', 1)
266 listToHTML(infile, outfile)