17 from functools
import partial
18 from itertools
import cycle
25 _image_exts = (
'.jpg',
'.jpeg',
'.png',
'.gif',
'.bmp')
29 _link = re.compile(
'\[(.+?\|.*?)\]')
34 ((^|\ ) ["'\(\[]*) # begin of line or space and opt. any char "'([
35 ([a-z][\w+-.]*://[^\s|]+?) # url
36 (?=[\]\)|"'.,!?:;]* ($|\ )) # opt. any char ])"'.,!?:; and end of line or space
37 ''', re.VERBOSE|re.MULTILINE|re.IGNORECASE)
40 return self.
_format_url_format_url(text, format_as_image=
False)
45 return self.
_url_url.sub(partial(self.
_replace_url_replace_url, format_as_image), text)
50 if format_as_image
and self.
_is_image_is_image(url):
55 return '<img src="%s" title="%s">' \
56 % (self.
_quot_quot(src), self.
_quot_quot(title
or src))
59 return '<a href="%s">%s</a>' % (self.
_quot_quot(href), content
or href)
62 return attr
if '"' not in attr
else attr.replace(
'"',
'"')
66 tokens = self.
_link_link.split(text)
68 return ''.join(f(t)
for f, t
in zip(formatters, tokens))
71 link, content = [t.strip()
for t
in text.split(
'|', 1)]
73 content = self.
_get_image_get_image(content, link)
75 return self.
_get_image_get_image(link, content)
76 return self.
_get_link_get_link(link, content)
79 return text.lower().endswith(self.
_image_exts_image_exts)
83 handles =
lambda self, line:
True
88 _bold = re.compile(
'''
90 (^|\ ) # begin of line or space
91 ["'(]* _? # optionally any char "'( and optional begin of italic
94 ([^\ ].*?) # no space and then anything (group 3)
96 (?= # start of postfix (non-capturing group)
97 _? ["').,!?:;]* # optional end of italic and any char "').,!?:;
98 ($|\ ) # end of line or space
104 _italic = re.compile(
'''
105 ( (^|\ ) ["'(]* ) # begin of line or space and opt. any char "'(
107 ([^\ _].*?) # no space or underline and then anything
109 (?= ["').,!?:;]* ($|\ ) ) # opt. any char "').,!?:; and end of line or space
114 _code = re.compile(
'''
115 ( (^|\ ) ["'(]* ) # same as above with _ changed to ``
119 (?= ["').,!?:;]* ($|\ ) )
129 for marker, formatter
in self.
_formatters_formatters:
131 line = formatter(line)
135 return self.
_bold_bold.sub(
'\\1<b>\\3</b>', line)
138 return self.
_italic_italic.sub(
'\\1<i>\\3</i>', line)
141 return self.
_code_code.sub(
'\\1<code>\\3</code>', line)
157 for line
in text.splitlines():
160 return '\n'.join(self.
_results_results)
179 if formatter.handles(line):
196 raise NotImplementedError
207 raise NotImplementedError
213 return not self.
_lines_lines
and self.
matchmatch(line)
216 raise NotImplementedError
222 raise NotImplementedError
226 match = re.compile(
'^-{3,}$').match
233 match = re.compile(
r'^(={1,3})\s+(\S.*?)\s+\1$').match
236 level, text = self.
matchmatchmatch(line).groups()
237 level = len(level) + 1
238 return '<h%d>%s</h%d>' % (level, text, level)
248 _Formatter.__init__(self)
252 return not any(other.handles(line)
256 return '<p>%s</p>' % self.
_format_line_format_line(
' '.join(lines))
263 _table_line = re.compile(
'^\| (.* |)\|$')
267 _line_splitter = re.compile(
' \|(?= )')
274 return self.
_table_line_table_line.match(line)
is not None
280 return [cell.strip()
for cell
in self.
_line_splitter_line_splitter.split(line[1:-1])]
283 maxlen = max(len(row)
for row
in rows)
284 table = [
'<table border="1">']
286 row += [
''] * (maxlen - len(row))
288 table.extend(self.
_format_cell_format_cell(cell)
for cell
in row)
289 table.append(
'</tr>')
290 table.append(
'</table>')
291 return '\n'.join(table)
294 if content.startswith(
'=')
and content.endswith(
'='):
296 content = content[1:-1].strip()
309 return line.startswith(
'| ')
or line ==
'|'
312 lines = [self.
_format_line_format_line(line[2:])
for line
in lines]
313 return '\n'.join([
'<pre>'] + lines + [
'</pre>'])
327 return line.strip().startswith(
'- ')
or \
328 line.startswith(
' ')
and self.
_lines_lines
331 items = [
'<li>%s</li>' % self.
_format_item_format_item(line)
333 return '\n'.join([
'<ul>'] + items + [
'</ul>'])
339 if not line.startswith(
'- '):
343 yield ' '.join(current)
344 current = [line[2:].strip()]
345 yield ' '.join(current)