9 MIRC_COLOR_BG
= MIRC_COLOR
, MIRC_COLOR
14 '#FFFFFF', '#000000', '#00007F', '#009300',
15 '#FF0000', '#7F0000', '#9C009C', '#FF7F00',
16 '#FFFF00', '#00FF00', '#009393', '#00FFFF',
17 '#0000FF', '#FF00FF', '#7F7F7F', '#D2D2D2'
20 def get_mirc_color(number
):
24 number
= int(number
) & 15
26 confcolors
= conf
.get('colors', colors
)
28 return confcolors
[number
]
30 # someone edited their colors wrongly
33 DEC_DIGITS
, HEX_DIGITS
= set('0123456789'), set('0123456789abcdefABCDEF')
35 def parse_mirc_color(string
, pos
, open_tags
, tags
):
38 if MIRC_COLOR
in open_tags
:
39 fgtag
= open_tags
.pop(MIRC_COLOR
)
43 if MIRC_COLOR_BG
in open_tags
:
44 bgtag
= open_tags
.pop(MIRC_COLOR_BG
)
52 if string
[0] in DEC_DIGITS
:
53 if string
[1] in DEC_DIGITS
:
54 fg
= get_mirc_color(string
[:2])
59 fg
= get_mirc_color(string
[0])
62 if string
[1] == "," and string
[2] in DEC_DIGITS
:
63 if string
[3] in DEC_DIGITS
:
64 bg
= get_mirc_color(string
[2:4])
68 bg
= get_mirc_color(string
[2])
75 open_tags
[MIRC_COLOR
] = {'data': ("foreground",fg
), 'from': pos
}
77 open_tags
.pop(MIRC_COLOR
,None)
80 open_tags
[MIRC_COLOR_BG
] = {'data': ("background",bg
), 'from': pos
}
82 open_tags
.pop(MIRC_COLOR_BG
,None)
86 def parse_bersirc_color(string
, pos
, open_tags
, tags
):
88 if MIRC_COLOR
in open_tags
:
89 tag
= open_tags
.pop(MIRC_COLOR
)
93 if MIRC_COLOR_BG
in open_tags
:
94 bgtag
= open_tags
.pop(MIRC_COLOR_BG
)
100 for c
in (0, 1, 2, 3, 4, 5):
101 if string
[c
] not in HEX_DIGITS
:
103 fg
= '#' + string
[:6].upper()
106 for c
in (7, 8, 9, 10, 11, 12):
107 if string
[c
] not in HEX_DIGITS
:
111 bg
= '#' + string
[7:13].upper()
115 open_tags
[MIRC_COLOR
] = {'data': ("foreground",fg
), 'from': pos
}
117 open_tags
.pop(MIRC_COLOR
,None)
120 open_tags
[MIRC_COLOR_BG
] = {'data': ("background",bg
), 'from': pos
}
122 open_tags
.pop(MIRC_COLOR_BG
,None)
126 def parse_bold(string
, pos
, open_tags
, tags
):
127 if BOLD
in open_tags
:
128 tag
= open_tags
.pop(BOLD
)
133 open_tags
[BOLD
] = {'data': ('weight', BOLD
), 'from': pos
}
137 def parse_underline(string
, pos
, open_tags
, tags
):
138 if UNDERLINE
in open_tags
:
139 tag
= open_tags
.pop(UNDERLINE
)
144 open_tags
[UNDERLINE
] = {'data': ('underline', UNDERLINE
), 'from': pos
}
148 def parse_reset(string
, pos
, open_tags
, tags
):
159 MIRC_COLOR
: parse_mirc_color
,
160 BERS_COLOR
: parse_bersirc_color
,
162 UNDERLINE
: parse_underline
,
166 def parse_mirc(string
):
172 text_i
= outtext_i
= 0
174 for tag_i
, char
in enumerate(string
):
175 if char
in tag_parser
:
176 out
+= string
[text_i
:tag_i
]
178 outtext_i
+= tag_i
- text_i
180 text_i
= tag_i
+ tag_parser
[char
](
189 #transforms for unparse_mirc
192 def transform_reset(start
, end
):
196 def transform_color_reset(start
, end
):
197 if ('foreground' in start
and 'foreground' not in end
) or \
198 ('background' in start
and 'background' not in end
):
199 result
= start
.copy()
200 result
.pop("foreground",None)
201 result
.pop("background",None)
202 return MIRC_COLOR
, DEC_DIGITS
, result
207 def transform_color(start
, end
):
208 if (start
.get('foreground',99) != end
.get('foreground',99)):
209 confcolors
= conf
.get('colors', colors
)
210 result
= start
.copy()
211 if 'foreground' in end
:
213 index
= list(confcolors
).index(end
['foreground'].upper())
216 result
['foreground'] = end
['foreground']
219 del result
['foreground']
220 return '\x03%02i' % index
, ',', result
225 def transform_bcolor(start
, end
):
226 if (start
.get('background',99) != end
.get('background',99)):
227 confcolors
= conf
.get('colors', colors
)
228 result
= start
.copy()
229 if 'foreground' in end
:
231 fg_index
= list(confcolors
).index(end
['foreground'].upper())
234 result
['foreground'] = end
['foreground']
237 result
.pop('foreground',None)
238 if 'background' in end
:
240 bg_index
= list(confcolors
).index(end
['background'].upper())
243 result
['background'] = end
['background']
246 del result
['background']
247 return '\x03%02i,%02i' % (fg_index
, bg_index
), ',', result
252 def transform_bersirc(start
, end
):
253 if 'foreground' in end
and end
['foreground'] != start
.get('foreground'):
254 result
= start
.copy()
255 result
['foreground'] = end
['foreground']
256 return "\x04%s" % end
['foreground'][1:], ',', result
261 def transform_bbersirc(start
, end
):
262 if 'foreground' in end
and 'background' in end
and (
263 end
['foreground'] != start
.get('foreground') or
264 end
['background'] != start
.get('background')):
265 result
= start
.copy()
266 result
['foreground'] = end
['foreground']
267 result
['background'] = end
['background']
268 return "\x04%s,%s" % (end
['foreground'][1:], end
['background'][1:]), ',', result
274 def transform_underline(start
, end
):
275 if ('underline' in start
) != ('underline' in end
):
276 result
= start
.copy()
277 if 'underline' in start
:
278 del result
['underline']
280 result
['underline'] = UNDERLINE
281 return UNDERLINE
, '', result
286 def transform_bold(start
, end
):
287 if ('weight' in start
) != ('weight' in end
):
288 result
= start
.copy()
289 if 'weight' in start
:
292 result
['weight'] = BOLD
293 return BOLD
, '', result
298 #In some rare circumstances, we HAVE to do this to generate a working string
299 def transform_dbold(start
, end
):
300 return BOLD
*2, '', start
302 #return the formatting needed to transform one set of format tags to another
303 def transform(start
, end
, nextchar
=" "):
304 transform_functions
= (
305 transform_reset
, transform_color_reset
, transform_color
, transform_bcolor
,
306 transform_bersirc
, transform_bbersirc
, transform_underline
,
307 transform_bold
, transform_dbold
,
310 candidates
= [('','',start
)]
313 for f
in transform_functions
:
314 for string
, badchars
, s
in candidates
[:]:
315 newstring
, badchars
, s
= f(s
, end
)
317 if newstring
and (result
== None or len(string
) < len(result
)):
318 if nextchar
not in badchars
and s
== end
:
321 candidates
.append((string
, badchars
, s
))
324 def unparse_mirc(tagsandtext
):
325 lasttags
, lastchar
= {}, ''
328 for tags
, char
in tagsandtext
:
330 string
.append(transform(lasttags
, tags
, char
[0]))
332 lasttags
, lastchar
= tags
, char
333 return ''.join(string
)
335 if __name__
== "__main__":
337 'not\x02bold\x02not',
338 'not\x1Funderline\x1Fnot',
342 'not\x030,17white-on-black\x0304red-on-black\x03nothing',
344 "\x040000CC<\x04nick\x040000CC>\x04 text",
346 '\x04770077,FFFFFFbersirc color with background! \x04000077setting foreground! \x04reset!',
348 '\x047700,FFFFbersirc',
358 "\x034,5Hello\x036Goodbye",
360 "\x04ff0000,00ff00Hello\x040000ffGoodbye",
362 "\x04777777(\x04\x0400CCCCstuff\x04\x04777777)\x04",
364 '\x0307orange\x04CCCCCCgrey\x0307orange',
366 '\x04CCCCCC,444444sdf\x0304jkl',
368 '\x0403\x02\x02,trixy',
370 '\x04FFFFFF\x02\x02,000000trixy for bersirc',
374 ([{'from': 3, 'data': ('weight', '\x02'), 'to': 7}], 'notboldnot'),
376 ([{'from': 3, 'data': ('underline', '\x1f'), 'to': 12}], 'notunderlinenot'),
378 ([{'from': 0, 'data': ('weight', '\x02'), 'to': 2}, {'from': 0, 'data': ('underline', '\x1f'), 'to': 2}], 'Hi'),
380 ([{'from': 3, 'data': ('foreground', '#FFFFFF'), 'to': 17}, {'from': 3, 'data': ('background', '#000000'), 'to': 17}, {'from': 17, 'data': ('foreground', '#FF0000'), 'to': 29}, {'from': 17, 'data': ('background', '#000000'), 'to': 29}], 'notwhite-on-blackred-on-blacknothing'),
382 ([{'from': 0, 'data': ('foreground', '#0000CC'), 'to': 1}, {'from': 5, 'data': ('foreground', '#0000CC'), 'to': 6}], '<nick> text'),
384 ([{'from': 0, 'data': ('foreground', '#770077'), 'to': 31}, {'from': 0, 'data': ('background', '#FFFFFF'), 'to': 31}, {'from': 31, 'data': ('foreground', '#000077'), 'to': 51}, {'from': 31, 'data': ('background', '#FFFFFF'), 'to': 51}], 'bersirc color with background! setting foreground! reset!'),
386 ([], '7700,FFFFbersirc'),
388 ([{'from': 0, 'data': ('foreground', '#0000FF'), 'to': 6}], '3Hello'),
390 ([{'from': 0, 'data': ('foreground', '#0000FF'), 'to': 6}], ',Hello'),
392 ([{'from': 0, 'data': ('foreground', '#FF0000'), 'to': 5}], 'Hello'),
394 ([{'from': 2, 'data': ('weight', '\x02'), 'to': 4}], 'Bold'),
396 ([{'from': 0, 'data': ('foreground', '#FF0000'), 'to': 5}, {'from': 0, 'data': ('background', '#7F0000'), 'to': 5}, {'from': 5, 'data': ('foreground', '#9C009C'), 'to': 12}, {'from': 5, 'data': ('background', '#7F0000'), 'to': 12}], 'HelloGoodbye'),
398 ([{'from': 0, 'data': ('foreground', '#FF0000'), 'to': 5}, {'from': 0, 'data': ('background', '#00FF00'), 'to': 5}, {'from': 5, 'data': ('foreground', '#0000FF'), 'to': 12}, {'from': 5, 'data': ('background', '#00FF00'), 'to': 12}], 'HelloGoodbye'),
400 ([{'from': 0, 'data': ('foreground', '#777777'), 'to': 1}, {'from': 1, 'data': ('foreground', '#00CCCC'), 'to': 6}, {'from': 6, 'data': ('foreground', '#777777'), 'to': 7}], '(stuff)'),
402 ([{'from': 0, 'data': ('foreground', '#FF7F00'), 'to': 6}, {'from': 6, 'data': ('foreground', '#CCCCCC'), 'to': 10}, {'from': 10, 'data': ('foreground', '#FF7F00'), 'to': 16}], 'orangegreyorange'),
404 ([{'from': 0, 'data': ('foreground', '#CCCCCC'), 'to': 3}, {'from': 0, 'data': ('background', '#444444'), 'to': 3}, {'from': 3, 'data': ('foreground', '#FF0000'), 'to': 6}, {'from': 3, 'data': ('background', '#444444'), 'to': 6}], 'sdfjkl'),
406 ([{'from': 2, 'data': ('weight', '\x02'), 'to': 2}], '03,trixy'),
408 ([{'from': 0, 'data': ('weight', '\x02'), 'to': 0}, {'from': 0, 'data': ('foreground', '#FFFFFF'), 'to': 24}], ',000000trixy for bersirc'),
420 lines = [eval(line.strip()) for line in file("parse_mirc_torture_test.txt")]
428 def setify_tags(tags
):
429 return set(frozenset(tag
.iteritems()) for tag
in tags
if tag
['from'] != tag
['to'])
431 def parsed_eq((tags1
, text1
), (tags2
, text2
)):
432 return setify_tags(tags1
) == setify_tags(tags2
) and text1
== text2
434 def parsed_to_unparsed((tags
, text
)):
436 for i
, char
in enumerate(text
):
438 dict(tag
['data'] for tag
in tags
if tag
['from'] <= i
< tag
['to']),
442 for i
, (test
, result
) in enumerate(zip(tests
, results
)):
443 if not parsed_eq(parse_mirc(test
), result
):
444 print "parse_mirc failed test %s:" % i
446 print parse_mirc(test
)
450 elif not parsed_eq(parse_mirc(unparse_mirc(parsed_to_unparsed(result
))), result
):
451 print "unparse_mirc failed test %s:" % i
453 print unparse_mirc(test
)