summaryrefslogtreecommitdiffstats
path: root/sphinx/parsers.py
diff options
context:
space:
mode:
Diffstat (limited to 'sphinx/parsers.py')
-rw-r--r--sphinx/parsers.py97
1 files changed, 97 insertions, 0 deletions
diff --git a/sphinx/parsers.py b/sphinx/parsers.py
new file mode 100644
index 0000000..1269884
--- /dev/null
+++ b/sphinx/parsers.py
@@ -0,0 +1,97 @@
+"""A Base class for additional parsers."""
+
+from __future__ import annotations
+
+from typing import TYPE_CHECKING, Any
+
+import docutils.parsers
+import docutils.parsers.rst
+from docutils import nodes
+from docutils.parsers.rst import states
+from docutils.statemachine import StringList
+from docutils.transforms.universal import SmartQuotes
+
+from sphinx.util.rst import append_epilog, prepend_prolog
+
+if TYPE_CHECKING:
+ from docutils.transforms import Transform
+
+ from sphinx.application import Sphinx
+ from sphinx.config import Config
+ from sphinx.environment import BuildEnvironment
+
+
+class Parser(docutils.parsers.Parser):
+ """
+ A base class of source parsers. The additional parsers should inherit this class instead
+ of ``docutils.parsers.Parser``. Compared with ``docutils.parsers.Parser``, this class
+ improves accessibility to Sphinx APIs.
+
+ The subclasses can access sphinx core runtime objects (app, config and env).
+ """
+
+ #: The config object
+ config: Config
+
+ #: The environment object
+ env: BuildEnvironment
+
+ def set_application(self, app: Sphinx) -> None:
+ """set_application will be called from Sphinx to set app and other instance variables
+
+ :param sphinx.application.Sphinx app: Sphinx application object
+ """
+ self._app = app
+ self.config = app.config
+ self.env = app.env
+
+
+class RSTParser(docutils.parsers.rst.Parser, Parser):
+ """A reST parser for Sphinx."""
+
+ def get_transforms(self) -> list[type[Transform]]:
+ """
+ Sphinx's reST parser replaces a transform class for smart-quotes by its own
+
+ refs: sphinx.io.SphinxStandaloneReader
+ """
+ transforms = super().get_transforms()
+ transforms.remove(SmartQuotes)
+ return transforms
+
+ def parse(self, inputstring: str | StringList, document: nodes.document) -> None:
+ """Parse text and generate a document tree."""
+ self.setup_parse(inputstring, document) # type: ignore[arg-type]
+ self.statemachine = states.RSTStateMachine(
+ state_classes=self.state_classes,
+ initial_state=self.initial_state,
+ debug=document.reporter.debug_flag)
+
+ # preprocess inputstring
+ if isinstance(inputstring, str):
+ lines = docutils.statemachine.string2lines(
+ inputstring, tab_width=document.settings.tab_width,
+ convert_whitespace=True)
+
+ inputlines = StringList(lines, document.current_source)
+ else:
+ inputlines = inputstring
+
+ self.decorate(inputlines)
+ self.statemachine.run(inputlines, document, inliner=self.inliner)
+ self.finish_parse()
+
+ def decorate(self, content: StringList) -> None:
+ """Preprocess reST content before parsing."""
+ prepend_prolog(content, self.config.rst_prolog)
+ append_epilog(content, self.config.rst_epilog)
+
+
+def setup(app: Sphinx) -> dict[str, Any]:
+ app.add_source_parser(RSTParser)
+
+ return {
+ 'version': 'builtin',
+ 'parallel_read_safe': True,
+ 'parallel_write_safe': True,
+ }