You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
101 lines
3.4 KiB
101 lines
3.4 KiB
# -*- coding: utf-8 -*- |
|
# Erik Stein <code@classlibrary.net>, 09/2010 |
|
|
|
import docutils |
|
import docutils.parsers.rst |
|
from django.conf import settings |
|
from django.utils.translation import ugettext_lazy as _ |
|
|
|
from ..base import Markup |
|
from ...settings import (RST_INITIAL_HEADER_LEVEL, RST_WRITER_NAME, |
|
RST_DEFAULT_LANGUAGE_CODE, RST_DOCTITLE_XFORM, |
|
RST_INPUT_ENCODING, RST_DEBUG_LEVEL, RST_FILTER_SETTINGS) |
|
from ..pygments import PYGMENTS_INSTALLED |
|
|
|
|
|
# Let's you conveniently import the parser |
|
parser = docutils.parsers.rst |
|
|
|
try: |
|
if PYGMENTS_INSTALLED: |
|
# Register "code" directive for pygments formatting |
|
from pygments import highlight |
|
from pygments.lexers import get_lexer_by_name, TextLexer |
|
from pygments.formatters import HtmlFormatter |
|
|
|
DEFAULT = HtmlFormatter() |
|
VARIANTS = { |
|
'linenos': HtmlFormatter(linenos=True), |
|
} |
|
|
|
def pygments_directive(name, arguments, options, content, lineno, |
|
content_offset, block_text, state, state_machine): |
|
try: |
|
lexer = get_lexer_by_name(arguments[0]) |
|
except ValueError: |
|
# no lexer found - use the text one instead of an exception |
|
lexer = TextLexer() |
|
formatter = options and VARIANTS[options.keys()[0]] or DEFAULT |
|
parsed = highlight(u'\n'.join(content), lexer, formatter) |
|
return [docutils.nodes.raw('', parsed, format='html')] |
|
pygments_directive.arguments = (1, 0, 1) |
|
pygments_directive.content = 1 |
|
parser.directives.register_directive('code', pygments_directive) |
|
except ImportError: |
|
pass |
|
|
|
|
|
class RestructuredtextMarkup(Markup): |
|
docutils_settings = { |
|
'language_code': RST_DEFAULT_LANGUAGE_CODE, |
|
'doctitle_xform': RST_DOCTITLE_XFORM, |
|
'input_encoding': RST_INPUT_ENCODING, |
|
'initial_header_level': RST_INITIAL_HEADER_LEVEL, |
|
'report_level': RST_DEBUG_LEVEL, |
|
} |
|
docutils_settings.update(RST_FILTER_SETTINGS) |
|
|
|
def render(self, initial_header_level=RST_INITIAL_HEADER_LEVEL, **kwargs): |
|
""" |
|
Returns the rendered html fragment, i.e. without any html header part. |
|
""" |
|
settings = self.docutils_settings.copy() |
|
settings['initial_header_level'] = initial_header_level |
|
parts = docutils.core.publish_parts( |
|
source=self.raw, |
|
writer_name=WRITER_NAME, |
|
settings_overrides=settings |
|
) |
|
return parts['fragment'] |
|
render.is_safe = True |
|
|
|
def doctree(self, **kwargs): |
|
""" |
|
Returns the docutils doctree. |
|
""" |
|
return docutils.core.publish_doctree(self.raw, settings_overrides=self.docutils_settings) |
|
|
|
def title(self, **kwargs): |
|
""" |
|
Returns the first found title node of a docutils doctree. |
|
""" |
|
# TODO Why don't we use the 'title' part? |
|
document = self.doctree() |
|
matches = document.traverse(condition=lambda node: isinstance(node, docutils.nodes.title)) |
|
if len(matches): |
|
return matches[0].astext() |
|
else: |
|
return None |
|
|
|
def plaintext(self, **kwargs): |
|
return self.doctree().astext() |
|
|
|
|
|
# Convenience function |
|
def restructuredtext(text, **kwargs): |
|
rst = RestructuredtextMarkup() |
|
rst.raw = text |
|
return rst.render(**kwargs) |
|
|
|
|
|
MARKUP_DESCRIPTION = ('text/x-rst', RestructuredtextMarkup)
|
|
|