1# vim: ts=8:sts=8:sw=8:noexpandtab 2 3# This file is part of python-markups module 4# License: 3-clause BSD, see LICENSE file 5# Copyright: (C) Dmitry Shachnev, 2012-2021 6 7import importlib 8import markups.common as common 9from markups.abstract import AbstractMarkup, ConvertedMarkup 10 11try: 12 from docutils.writers.html5_polyglot import HTMLTranslator 13except ImportError: 14 CustomHTMLTranslator = None 15else: 16 class CustomHTMLTranslator(HTMLTranslator): 17 def starttag(self, node, tagname, suffix='\n', empty=False, **attributes): 18 if getattr(node, 'line', None) is not None: 19 attributes['data-posmap'] = node.line 20 return super().starttag(node, tagname, suffix, empty, **attributes) 21 22 23class ReStructuredTextMarkup(AbstractMarkup): 24 """Markup class for reStructuredText language. 25 Inherits :class:`~markups.abstract.AbstractMarkup`. 26 27 :param settings_overrides: optional dictionary of overrides for the 28 `Docutils settings`_ 29 :type settings_overrides: dict 30 31 .. _`Docutils settings`: https://docutils.sourceforge.io/docs/user/config.html 32 """ 33 name = 'reStructuredText' 34 attributes = { 35 common.LANGUAGE_HOME_PAGE: 'https://docutils.sourceforge.io/rst.html', 36 common.MODULE_HOME_PAGE: 'https://docutils.sourceforge.io/', 37 common.SYNTAX_DOCUMENTATION: 'https://docutils.sourceforge.io/docs/ref/rst/restructuredtext.html' 38 } 39 40 file_extensions = ('.rst', '.rest') 41 default_extension = '.rst' 42 43 @staticmethod 44 def available(): 45 try: 46 importlib.import_module('docutils.core') 47 except ImportError: 48 return False 49 return True 50 51 def __init__(self, filename=None, settings_overrides=None): 52 self.overrides = settings_overrides or {} 53 self.overrides.update({ 54 'math_output': 'MathJax ' + common.MATHJAX_WEB_URL, 55 'syntax_highlight': 'short', 56 'halt_level': 5, # Never convert system messages to exceptions 57 'stylesheet_path': 'minimal.css', # Do not include plain.css 58 }) 59 AbstractMarkup.__init__(self, filename) 60 from docutils.core import publish_parts 61 from docutils.writers.html5_polyglot import Writer 62 self._publish_parts = publish_parts 63 self.writer = Writer() 64 self.writer.translator_class = CustomHTMLTranslator 65 66 def convert(self, text): 67 parts = self._publish_parts(text, source_path=self.filename, 68 writer=self.writer, settings_overrides=self.overrides) 69 70 # Determine head 71 head = parts['head'] 72 73 # Determine body 74 body = parts['html_body'] 75 76 # Determine title 77 title = parts['title'] 78 79 # Determine stylesheet 80 origstyle = parts['stylesheet'] 81 # Cut off <style> and </style> tags 82 stylestart = '<style type="text/css">' 83 stylesheet = '' 84 if stylestart in origstyle: 85 stylesheet = origstyle[origstyle.find(stylestart)+25:origstyle.rfind('</style>')] 86 stylesheet += common.get_pygments_stylesheet('.code') 87 88 return ConvertedReStructuredText(head, body, title, stylesheet) 89 90 91class ConvertedReStructuredText(ConvertedMarkup): 92 93 def __init__(self, head, body, title, stylesheet): 94 ConvertedMarkup.__init__(self, body, title, stylesheet) 95 self.head = head 96 97 def get_javascript(self, webenv=False): 98 if common.MATHJAX_WEB_URL not in self.head: 99 return '' 100 mathjax_url, mathjax_version = common.get_mathjax_url_and_version(webenv) 101 if mathjax_version == 2: 102 mathjax_url += '?config=TeX-AMS_CHTML' 103 async_attr = ' async' if mathjax_version == 3 else '' 104 script_tag = '<script type="text/javascript" src="%s"%s></script>\n' 105 return script_tag % (mathjax_url, async_attr) 106