diff --git a/discord/utils.py b/discord/utils.py index 0882250c7..6bdca37d9 100644 --- a/discord/utils.py +++ b/discord/utils.py @@ -369,15 +369,26 @@ def resolve_invite(invite): _MARKDOWN_ESCAPE_SUBREGEX = '|'.join(r'\{0}(?=([\s\S]*((?%s)' % _MARKDOWN_ESCAPE_SUBREGEX) -def escape_markdown(text): - """A helper function that escapes Discord's markdown. +def escape_markdown(text, *, as_needed=False, ignore_links=True): + r"""A helper function that escapes Discord's markdown. Parameters ----------- text: :class:`str` The text to escape markdown from. + as_needed: :class:`bool` + Whether to escape the markdown characters as needed. This + means that it does not escape extraneous characters if it's + not necessary, e.g. ``**hello**`` is escaped into ``\*\*hello**`` + instead of ``\*\*hello\*\*``. Note however that this can open + you up to some clever syntax abuse. Defaults to ``False``. + ignore_links: :class:`bool` + Whether to leave links alone when escaping markdown. For example, + if a URL in the text contains characters such as ``_`` then it will + be left alone. This option is not supported with ``as_needed``. + Defaults to ``True``. Returns -------- @@ -385,8 +396,22 @@ def escape_markdown(text): The text with the markdown special characters escaped with a slash. """ - text = re.sub(r'\\', r'\\\\', text) - return _MARKDOWN_ESCAPE_REGEX.sub(r'\\\1', text) + if not as_needed: + url_regex = r'(?P(?:https?|steam)://(?:-\.)?(?:[^\s/?\.#-]+\.?)+(?:/[^\s]*)?)' + def replacement(match): + groupdict = match.groupdict() + is_url = groupdict.get('url') + if is_url: + return is_url + return '\\' + groupdict['markdown'] + + regex = r'(?P[_\\~|\*])' + if ignore_links: + regex = '(?:%s|%s)' % (url_regex, regex) + return re.sub(regex, replacement, text) + else: + text = re.sub(r'\\', r'\\\\', text) + return _MARKDOWN_ESCAPE_REGEX.sub(r'\\\1', text) def escape_mentions(text): """A helper function that escapes everyone, here, role, and user mentions.