From 3f95de7e49b53af4d2da750f4629e990a2eb42a2 Mon Sep 17 00:00:00 2001 From: "Dustin C. Hatch" Date: Sat, 7 Mar 2015 17:12:34 -0600 Subject: [PATCH] Add new module for preview renderers --- src/rstpreview/controllers.py | 19 ++------- src/rstpreview/markup.py | 72 +++++++++++++++++++++++++++++++++++ 2 files changed, 76 insertions(+), 15 deletions(-) create mode 100644 src/rstpreview/markup.py diff --git a/src/rstpreview/controllers.py b/src/rstpreview/controllers.py index 8d79976..d385933 100644 --- a/src/rstpreview/controllers.py +++ b/src/rstpreview/controllers.py @@ -1,4 +1,4 @@ -import docutils.core +from . import markup import jinja2 import milla.controllers @@ -37,7 +37,7 @@ class IndexController(BaseController): response = request.ResponseClass() try: content = request.POST['content'] - preview = PreviewController.rst2html(content) + preview = markup.get_previewer(content).preview() except KeyError: content = preview = '' response.text = self.render('index.html.j2', **dict( @@ -49,24 +49,13 @@ class IndexController(BaseController): class PreviewController(BaseController): - DOCUTILS_SETTINGS = { - 'syntax_highlight': 'short', - } - allowed_methods = ('HEAD', 'POST') def __call__(self, request): return getattr(self, request.method)(request) - @classmethod - def rst2html(cls, source): - return docutils.core.publish_parts( - source=source, - writer_name='html4css1', - settings_overrides=cls.DOCUTILS_SETTINGS, - )['html_body'] - def POST(self, request): response = request.ResponseClass() - response.text = self.rst2html(request.text) + previewer = markup.get_previewer(request.text) + response.text = previewer.preview() return response diff --git a/src/rstpreview/markup.py b/src/rstpreview/markup.py new file mode 100644 index 0000000..348b91a --- /dev/null +++ b/src/rstpreview/markup.py @@ -0,0 +1,72 @@ +import markupsafe +try: + import docutils.core +except ImportError: + docutils = None + + +def get_previewer(source): + lines = source.splitlines() + for previewer in PreviewerMeta.previewers: + if previewer.detect(lines): + return previewer(source) + return DefaultPreviewer(source) + + +class PreviewerMeta(type): + + previewers = [] + + def __new__(mcs, name, bases, attrs): + cls = type.__new__(mcs, name, bases, attrs) + if hasattr(cls, 'detect'): + mcs.previewers.append(cls) + return cls + + +Previewer = PreviewerMeta('Previewer', (), {}) + + +class BasePreviewer(Previewer): + + def __init__(self, source): + self.source = source + + +class ReStructuredTextPreviewer(BasePreviewer): + DOCUTILS_SETTINGS = { + 'syntax_highlight': 'short', + } + + @classmethod + def detect(cls, lines): + if docutils is None: + return False + for idx, line in enumerate(lines): + if line.startswith('.. '): # directives, comments + return True + if line.endswith('::'): # directive, literal block + return True + if '``' in line: # default role + return True + if ':`' in line: # role + return True + + def preview(self): + return docutils.core.publish_parts( + source=self.source, + writer_name='html4css1', + settings_overrides=self.DOCUTILS_SETTINGS, + )['html_body'] + + +class PlainTextPreviewer(BasePreviewer): + + def preview(self): + return '
{0}
'.format(markupsafe.escape(self.source)) + + +if docutils is not None: + DefaultPreviewer = ReStructuredTextPreviewer +else: + DefaultPreviewer = PlainTextPreviewer