diff --git a/rhodecode/lib/markup_renderer.py b/rhodecode/lib/markup_renderer.py --- a/rhodecode/lib/markup_renderer.py +++ b/rhodecode/lib/markup_renderer.py @@ -40,7 +40,7 @@ class MarkupRenderer(object): RST_PAT = re.compile(r're?st', re.IGNORECASE) PLAIN_PAT = re.compile(r'readme', re.IGNORECASE) - def __detect_renderer(self, source, filename=None): + def _detect_renderer(self, source, filename=None): """ runs detection of what renderer should be used for generating html from a markup language @@ -62,6 +62,49 @@ class MarkupRenderer(object): return getattr(MarkupRenderer, detected_renderer) + @classmethod + def _flavored_markdown(cls, text): + """ + Github style flavored markdown + + :param text: + """ + from hashlib import md5 + + # Extract pre blocks. + extractions = {} + def pre_extraction_callback(matchobj): + digest = md5(matchobj.group(0)).hexdigest() + extractions[digest] = matchobj.group(0) + return "{gfm-extraction-%s}" % digest + pattern = re.compile(r'
.*?
', re.MULTILINE | re.DOTALL) + text = re.sub(pattern, pre_extraction_callback, text) + + # Prevent foo_bar_baz from ending up with an italic word in the middle. + def italic_callback(matchobj): + s = matchobj.group(0) + if list(s).count('_') >= 2: + return s.replace('_', '\_') + return s + text = re.sub(r'^(?! {4}|\t)\w+_\w+_\w[\w_]*', italic_callback, text) + + # In very clear cases, let newlines become
tags. + def newline_callback(matchobj): + if len(matchobj.group(1)) == 1: + return matchobj.group(0).rstrip() + ' \n' + else: + return matchobj.group(0) + pattern = re.compile(r'^[\w\<][^\n]*(\n+)', re.MULTILINE) + text = re.sub(pattern, newline_callback, text) + + # Insert pre block extractions. + def pre_insert_callback(matchobj): + return '\n\n' + extractions[matchobj.group(1)] + text = re.sub(r'{gfm-extraction-([0-9a-f]{32})\}', + pre_insert_callback, text) + + return text + def render(self, source, filename=None): """ Renders a given filename using detected renderer @@ -72,7 +115,7 @@ class MarkupRenderer(object): :param source: """ - renderer = self.__detect_renderer(source, filename) + renderer = self._detect_renderer(source, filename) readme_data = renderer(source) return readme_data @@ -94,10 +137,12 @@ class MarkupRenderer(object): return '
' + source.replace("\n", '
') @classmethod - def markdown(cls, source, safe=True): + def markdown(cls, source, safe=True, flavored=False): source = safe_unicode(source) try: import markdown as __markdown + if flavored: + source = cls._flavored_markdown(source) return __markdown.markdown(source, ['codehilite', 'extra']) except ImportError: log.warning('Install markdown to use this function')