##// END OF EJS Templates
Close rhodecode-2.2.5-gpl
Close rhodecode-2.2.5-gpl

File last commit:

r4116:ffd45b18 rhodecode-2.2.5-gpl
r4174:5692f460 rhodecode-2.2.5-gpl
Show More
markup_renderer.py
199 lines | 6.8 KiB | text/x-python | PythonLexer
initial version of markup renderer
r1604 # -*- coding: utf-8 -*-
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
Bradley M. Kuhn
Imported some of the GPLv3'd changes from RhodeCode v2.2.5....
r4116 """
rhodecode.lib.markup_renderer
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Renderer for markup languages with ability to parse using rst or markdown
:created_on: Oct 27, 2011
:author: marcink
:copyright: (c) 2013 RhodeCode GmbH.
:license: GPLv3, see LICENSE for more details.
"""
initial version of markup renderer
r1604
import re
import logging
catch errors on renderers, and display plain if critical rendering error is present
r2747 import traceback
initial version of markup renderer
r1604
#426 fixed mention extracting regex
r2201 from rhodecode.lib.utils2 import safe_unicode, MENTIONS_REGEX
initial version of markup renderer
r1604
log = logging.getLogger(__name__)
activate codehilite extension on markdown renderer, inspired by bitbucket blog ;)
r1996
initial version of markup renderer
r1604 class MarkupRenderer(object):
RESTRUCTUREDTEXT_DISALLOWED_DIRECTIVES = ['include', 'meta', 'raw']
auto white-space removal
r1818
activate codehilite extension on markdown renderer, inspired by bitbucket blog ;)
r1996 MARKDOWN_PAT = re.compile(r'md|mkdn?|mdown|markdown', re.IGNORECASE)
RST_PAT = re.compile(r're?st', re.IGNORECASE)
PLAIN_PAT = re.compile(r'readme', re.IGNORECASE)
auto white-space removal
r1818
Added github flavored markdown style rendering into markdown...
r4009 def _detect_renderer(self, source, filename=None):
initial version of markup renderer
r1604 """
runs detection of what renderer should be used for generating html
from a markup language
auto white-space removal
r1818
initial version of markup renderer
r1604 filename can be also explicitly a renderer name
auto white-space removal
r1818
initial version of markup renderer
r1604 :param source:
:param filename:
"""
if MarkupRenderer.MARKDOWN_PAT.findall(filename):
detected_renderer = 'markdown'
elif MarkupRenderer.RST_PAT.findall(filename):
detected_renderer = 'rst'
elif MarkupRenderer.PLAIN_PAT.findall(filename):
detected_renderer = 'rst'
else:
detected_renderer = 'plain'
return getattr(MarkupRenderer, detected_renderer)
Added github flavored markdown style rendering into markdown...
r4009 @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'<pre>.*?</pre>', 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 <br /> 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
initial version of markup renderer
r1604 def render(self, source, filename=None):
"""
Renders a given filename using detected renderer
it detects renderers based on file extension or mimetype.
At last it will just do a simple html replacing new lines with <br/>
auto white-space removal
r1818
initial version of markup renderer
r1604 :param file_name:
:param source:
"""
Added github flavored markdown style rendering into markdown...
r4009 renderer = self._detect_renderer(source, filename)
initial version of markup renderer
r1604 readme_data = renderer(source)
return readme_data
@classmethod
Bradley M. Kuhn
Imported some of the GPLv3'd changes from RhodeCode v2.2.5....
r4116 def plain(cls, source, universal_newline=True):
initial version of markup renderer
r1604 source = safe_unicode(source)
Bradley M. Kuhn
Imported some of the GPLv3'd changes from RhodeCode v2.2.5....
r4116 if universal_newline:
newline = '\n'
source = newline.join(source.splitlines())
initial version of markup renderer
r1604 def urlify_text(text):
url_pat = re.compile(r'(http[s]?://(?:[a-zA-Z]|[0-9]|[$-_@.&+]'
'|[!*\(\),]|(?:%[0-9a-fA-F][0-9a-fA-F]))+)')
def url_func(match_obj):
url_full = match_obj.groups()[0]
activate codehilite extension on markdown renderer, inspired by bitbucket blog ;)
r1996 return '<a href="%(url)s">%(url)s</a>' % ({'url': url_full})
initial version of markup renderer
r1604
return url_pat.sub(url_func, text)
source = urlify_text(source)
return '<br />' + source.replace("\n", '<br />')
@classmethod
Added github flavored markdown style rendering into markdown...
r4009 def markdown(cls, source, safe=True, flavored=False):
initial version of markup renderer
r1604 source = safe_unicode(source)
try:
import markdown as __markdown
Added github flavored markdown style rendering into markdown...
r4009 if flavored:
source = cls._flavored_markdown(source)
xpol
Enable all Markdown Extra in Python markdown library.
r3164 return __markdown.markdown(source, ['codehilite', 'extra'])
initial version of markup renderer
r1604 except ImportError:
log.warning('Install markdown to use this function')
return cls.plain(source)
catch errors on renderers, and display plain if critical rendering error is present
r2747 except Exception:
log.error(traceback.format_exc())
if safe:
Bradley M. Kuhn
Imported some of the GPLv3'd changes from RhodeCode v2.2.5....
r4116 log.debug('Fallbacking to render in plain mode')
return cls.plain(source)
catch errors on renderers, and display plain if critical rendering error is present
r2747 else:
raise
initial version of markup renderer
r1604
@classmethod
catch errors on renderers, and display plain if critical rendering error is present
r2747 def rst(cls, source, safe=True):
initial version of markup renderer
r1604 source = safe_unicode(source)
try:
from docutils.core import publish_parts
from docutils.parsers.rst import directives
docutils_settings = dict([(alias, None) for alias in
cls.RESTRUCTUREDTEXT_DISALLOWED_DIRECTIVES])
docutils_settings.update({'input_encoding': 'unicode',
activate codehilite extension on markdown renderer, inspired by bitbucket blog ;)
r1996 'report_level': 4})
initial version of markup renderer
r1604
for k, v in docutils_settings.iteritems():
directives.register_directive(k, v)
parts = publish_parts(source=source,
writer_name="html4css1",
settings_overrides=docutils_settings)
return parts['html_title'] + parts["fragment"]
except ImportError:
log.warning('Install docutils to use this function')
return cls.plain(source)
catch errors on renderers, and display plain if critical rendering error is present
r2747 except Exception:
log.error(traceback.format_exc())
if safe:
Bradley M. Kuhn
Imported some of the GPLv3'd changes from RhodeCode v2.2.5....
r4116 log.debug('Fallbacking to render in plain mode')
return cls.plain(source)
catch errors on renderers, and display plain if critical rendering error is present
r2747 else:
raise
initial version of markup renderer
r1604
@mention highlighting
r1769 @classmethod
def rst_with_mentions(cls, source):
#426 fixed mention extracting regex
r2201 mention_pat = re.compile(MENTIONS_REGEX)
auto white-space removal
r1818
@mention highlighting
r1769 def wrapp(match_obj):
uname = match_obj.groups()[0]
#426 fixed mention extracting regex
r2201 return ' **@%(uname)s** ' % {'uname': uname}
@mention highlighting
r1769 mention_hl = mention_pat.sub(wrapp, source).strip()
return cls.rst(mention_hl)