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