# -*- coding: utf-8 -*-
"""
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) 2011-2012 Marcin Kuzminski <marcin@python-works.com>
:license: GPLv3, see COPYING for more details.
# 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/>.
import re
import logging
import traceback
from rhodecode.lib.utils2 import safe_unicode, MENTIONS_REGEX
log = logging.getLogger(__name__)
class MarkupRenderer(object):
RESTRUCTUREDTEXT_DISALLOWED_DIRECTIVES = ['include', 'meta', 'raw']
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)
def __detect_renderer(self, source, filename=None):
runs detection of what renderer should be used for generating html
from a markup language
filename can be also explicitly a renderer name
: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):
else:
detected_renderer = 'plain'
return getattr(MarkupRenderer, detected_renderer)
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/>
:param file_name:
renderer = self.__detect_renderer(source, filename)
readme_data = renderer(source)
return readme_data
@classmethod
def plain(cls, source):
source = safe_unicode(source)
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]
return '<a href="%(url)s">%(url)s</a>' % ({'url': url_full})
return url_pat.sub(url_func, text)
source = urlify_text(source)
return '<br />' + source.replace("\n", '<br />')
def markdown(cls, source, safe=True):
try:
import markdown as __markdown
return __markdown.markdown(source, ['codehilite'])
return __markdown.markdown(source, ['codehilite', 'tables'])
except ImportError:
log.warning('Install markdown to use this function')
return cls.plain(source)
except Exception:
log.error(traceback.format_exc())
if safe:
return source
raise
def rst(cls, source, safe=True):
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',
'report_level': 4})
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"]
log.warning('Install docutils to use this function')
def rst_with_mentions(cls, source):
mention_pat = re.compile(MENTIONS_REGEX)
def wrapp(match_obj):
uname = match_obj.groups()[0]
return ' **@%(uname)s** ' % {'uname': uname}
mention_hl = mention_pat.sub(wrapp, source).strip()
return cls.rst(mention_hl)
@@ -3903,384 +3903,392 @@ div.form div.fields div.field div.highli
#login div.form div.fields div.field div.input,#register div.form div.fields div.field div.input
{
float: left;
margin: 0;
padding: 0;
}
#login div.form div.fields div.field div.checkbox,#register div.form div.fields div.field div.checkbox
margin: 0 0 0 184px;
#login div.form div.fields div.field div.checkbox label,#register div.form div.fields div.field div.checkbox label
color: #565656;
font-weight: 700;
#login div.form div.fields div.buttons input,#register div.form div.fields div.buttons input
color: #000;
font-size: 1em;
#changeset_content .container .wrapper,#graph_content .container .wrapper
width: 600px;
#changeset_content .container .left {
width: 75%;
padding-left: 5px;
#changeset_content .container .left .date,.ac .match {
padding-top: 5px;
padding-bottom: 5px;
div#legend_container table td,div#legend_choices table td {
border: none !important;
height: 20px !important;
padding: 0 !important;
.q_filter_box {
-webkit-box-shadow: rgba(0,0,0,0.07) 0 1px 2px inset;
-webkit-border-radius: 4px;
-moz-border-radius: 4px;
border-radius: 4px;
border: 0 none;
color: #AAAAAA;
margin-bottom: -4px;
margin-top: -4px;
padding-left: 3px;
#node_filter {
border: 0px solid #545454;
.group_members_wrap{
min-height: 85px;
padding-left: 20px;
.group_members .group_member{
height: 30px;
padding:0px 0px 0px 0px;
.reviewers_member{
height: 15px;
padding:0px 0px 0px 10px;
.emails_wrap{
padding: 0px 20px;
.emails_wrap .email_entry{
.emails_wrap .email_entry .email{
float: left
.emails_wrap .email_entry .email_action{
/*README STYLE*/
div.readme {
padding:0px;
div.readme h2 {
font-weight: normal;
div.readme .readme_box {
background-color: #fafafa;
clear:both;
overflow:hidden;
margin:0;
padding:0 20px 10px;
div.readme .readme_box h1, div.readme .readme_box h2, div.readme .readme_box h3, div.readme .readme_box h4, div.readme .readme_box h5, div.readme .readme_box h6 {
border-bottom: 0 !important;
margin: 0 !important;
line-height: 1.5em !important;
div.readme .readme_box h1:first-child {
padding-top: .25em !important;
div.readme .readme_box h2, div.readme .readme_box h3 {
margin: 1em 0 !important;
div.readme .readme_box h2 {
margin-top: 1.5em !important;
border-top: 4px solid #e0e0e0 !important;
padding-top: .5em !important;
div.readme .readme_box p {
color: black !important;
div.readme .readme_box ul {
list-style: disc !important;
margin: 1em 0 1em 2em !important;
div.readme .readme_box ol {
list-style: decimal;
div.readme .readme_box pre, code {
font: 12px "Bitstream Vera Sans Mono","Courier",monospace;
div.readme .readme_box code {
font-size: 12px !important;
background-color: ghostWhite !important;
color: #444 !important;
padding: 0 .2em !important;
border: 1px solid #dedede !important;
div.readme .readme_box pre code {
background-color: #eee !important;
div.readme .readme_box pre {
margin: 1em 0;
font-size: 12px;
background-color: #eee;
border: 1px solid #ddd;
padding: 5px;
color: #444;
overflow: auto;
-webkit-border-radius: 3px;
-moz-border-radius: 3px;
border-radius: 3px;
div.readme .readme_box table {
display: table;
border-collapse: separate;
border-spacing: 2px;
border-color: gray;
width: auto !important;
/** RST STYLE **/
div.rst-block {
div.rst-block h2 {
div.rst-block h1, div.rst-block h2, div.rst-block h3, div.rst-block h4, div.rst-block h5, div.rst-block h6 {
div.rst-block h1:first-child {
div.rst-block h2, div.rst-block h3 {
div.rst-block p {
div.rst-block ul {
div.rst-block ol {
div.rst-block pre, code {
div.rst-block code {
div.rst-block pre code {
div.rst-block pre {
/** comment main **/
.comments {
padding:10px 20px;
.comments .comment {
margin-top: 10px;
.comments .comment .meta {
background: #f8f8f8;
padding: 4px;
border-bottom: 1px solid #ddd;
height: 18px;
.comments .comment .meta img {
vertical-align: middle;
.comments .comment .meta .user {
font-weight: bold;
padding: 4px 2px 2px 2px;
.comments .comment .meta .date {
padding:4px 4px 0px 4px;
.comments .comment .text {
background-color: #FAFAFA;
.comment .text div.rst-block p {
margin: 0.5em 0px !important;
.comments .comments-number{
padding:0px 0px 10px 0px;
color: #666;
font-size: 16px;
/** comment form **/
.status-block{
height:80px;
clear:both
.comment-form .clearfix{
background: #EEE;
padding: 10px;
div.comment-form {
margin-top: 20px;
.comment-form strong {
display: block;
margin-bottom: 15px;
.comment-form textarea {
width: 100%;
height: 100px;
font-family: 'Monaco', 'Courier', 'Courier New', monospace;
form.comment-form {
margin-left: 10px;
.comment-form-submit {
margin-top: 5px;
margin-left: 525px;
.file-comments {
display: none;
.comment-form .comment {
Status change: