'mu', 'mt', 'mw', 'mv', 'mq', 'ms', 'mr', 'im', 'ug', 'my', 'mx', 'il', 'pro', 'ac', 'sa', 'ae', 'ad', 'ag',
'af', 'ai', 'vi', 'is', 'ir', 'am', 'al', 'ao', 'an', 'aq', 'as', 'ar', 'au', 'at', 'aw', 'in', 'ax', 'az',
'ie', 'id', 'sr', 'nl', 'mil', 'no', 'na', 'travel', 'nc', 'ne', 'nf', 'ng', 'nz', 'dm', 'np',
- 'so', 'nr', 'nu', 'fr', 'io', 'ni', 'ye', 'sv', 'jsp', 'kz', 'fi', 'fj', 'php', 'fm', 'fo', 'tj', 'sz', 'sy',
+ 'so', 'nr', 'nu', 'fr', 'io', 'ni', 'ye', 'sv', 'kz', 'fi', 'fj', 'fm', 'fo', 'tj', 'sz', 'sy',
'mobi', 'kg', 'ke', 'doc', 'ki', 'kh', 'kn', 'km', 'st', 'sk', 'kr', 'si', 'kp', 'kw', 'sn', 'sm', 'sl', 'sc',
'biz', 'ky', 'sg', 'se', 'sd')
AUTO_LINK_RE = re.compile(r"""
(?P<ws>.?\s*)
(?P<url>
- (?P<format1>
+ (?:(?P<format1>
((?P<protocol1>[a-z][a-z]+)://)?
(?P<domain1>\w(?:[\w-]*\w)?\.\w(?:[\w-]*\w)?(?:\.\w(?:[\w-]*\w)?)*)
) | (?P<format2>
((?P<protocol2>[a-z][a-z]+)://)
(?P<domain2>\w(?:[\w-]*\w)?(?:\.\w(?:[\w-]*\w)?)*)
- )
+ ))
(?P<port>:\d+)?
(?P<uri>/[^\s<]*)?
)
""", re.X | re.I)
+EMAIL_LINK_REPLACE_RE = re.compile("(?<= href=\")[_a-z0-9-]+(\.[_a-z0-9-]+)*@[a-z0-9-]+(\.[a-z0-9-]+)*(\.[a-z]{2,4})(?=\")")
+
def is_ip(addr):
try:
socket.inet_aton(addr)
ws = m.group('ws')
- if ws and ws[0] in ("'", '"'):
+ if ws and ws[0] in ("'", '"', "@"):
return m.group(0)
elif not ws:
if not protocol:
domain_chunks = domain.split('.')
- if not ((len(domain_chunks) == 1 and domain_chunks[0].lower() == 'localhost') or (domain_chunks[-1].lower() in TLDS)):
+ if not (len(domain_chunks) == 1 and domain_chunks[0].lower() == 'localhost') or (domain_chunks[-1].lower() in TLDS):
return m.group(0)
if (not protocol) and is_ip(domain):
class AutoLinker(markdown.postprocessors.Postprocessor):
def run(self, text):
- return AUTO_LINK_RE.sub(replacer, text)
+ text = AUTO_LINK_RE.sub(replacer, text)
+ text = EMAIL_LINK_REPLACE_RE.sub(lambda m: "mailto:%s" % m.group(0), text)
+
+ return text
class AutoLinkerExtension(markdown.Extension):