|
1 | 1 | Docutils markup API
|
2 | 2 | ===================
|
3 | 3 |
|
4 |
| -This section describes the API for adding ReST markup elements (roles and |
5 |
| -directives). |
| 4 | +This section describes the API for adding reStructuredText markup elements |
| 5 | +(roles and directives). |
| 6 | + |
6 | 7 |
|
7 | 8 | Roles
|
8 | 9 | -----
|
9 | 10 |
|
| 11 | +Roles follow the interface described below. |
| 12 | +They have to be registered by an extension using |
| 13 | +:meth:`.Sphinx.add_role` or :meth:`.Sphinx.add_role_to_domain`. |
| 14 | + |
| 15 | + |
| 16 | +.. code-block:: python |
| 17 | +
|
| 18 | + def role_function( |
| 19 | + role_name: str, raw_source: str, text: str, |
| 20 | + lineno: int, inliner: Inliner, |
| 21 | + options: dict = {}, content: list = [], |
| 22 | + ) -> tuple[list[Node], list[system_message]]: |
| 23 | + elements = [] |
| 24 | + messages = [] |
| 25 | + return elements, messages |
| 26 | +
|
| 27 | +The *options* and *content* parameters are only used for custom roles |
| 28 | +created via the :dudir:`role` directive. |
| 29 | +The return value is a tuple of two lists, |
| 30 | +the first containing the text nodes and elements from the role, |
| 31 | +and the second containing any system messages generated. |
| 32 | +For more information, see the `custom role overview`_ from Docutils. |
| 33 | + |
| 34 | +.. _custom role overview: https://docutils.sourceforge.io/docs/howto/rst-roles.html |
| 35 | + |
| 36 | + |
| 37 | +Creating custom roles |
| 38 | +^^^^^^^^^^^^^^^^^^^^^ |
| 39 | + |
| 40 | +Sphinx provides two base classes for creating custom roles, |
| 41 | +:class:`~sphinx.util.docutils.SphinxRole` and :class:`~sphinx.util.docutils.ReferenceRole`. |
| 42 | + |
| 43 | +These provide a class-based interface for creating roles, |
| 44 | +where the main logic must be implemented in your ``run()`` method. |
| 45 | +The classes provide a number of useful methods and attributes, |
| 46 | +such as ``self.text``, ``self.config``, and ``self.env``. |
| 47 | +The ``ReferenceRole`` class implements Sphinx's ``title <target>`` logic, |
| 48 | +exposing ``self.target`` and ``self.title`` attributes. |
| 49 | +This is useful for creating cross-reference roles. |
| 50 | + |
10 | 51 |
|
11 | 52 | Directives
|
12 | 53 | ----------
|
@@ -85,68 +126,106 @@ using :meth:`.Sphinx.add_directive` or :meth:`.Sphinx.add_directive_to_domain`.
|
85 | 126 | The state and state machine which controls the parsing. Used for
|
86 | 127 | ``nested_parse``.
|
87 | 128 |
|
| 129 | +.. seealso:: |
| 130 | + |
| 131 | + `Creating directives`_ HOWTO of the Docutils documentation |
| 132 | + |
| 133 | + .. _Creating directives: https://docutils.sourceforge.io/docs/howto/rst-directives.html |
| 134 | + |
| 135 | + |
| 136 | +.. _parsing-directive-content-as-rest: |
| 137 | + |
| 138 | +Parsing directive content as reStructuredText |
| 139 | +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ |
88 | 140 |
|
89 |
| -ViewLists |
90 |
| -^^^^^^^^^ |
| 141 | +Many directives will contain more markup that must be parsed. |
| 142 | +To do this, use one of the following APIs from the :meth:`~Directive.run` method: |
91 | 143 |
|
92 |
| -Docutils represents document source lines in a class |
93 |
| -``docutils.statemachine.ViewList``. This is a list with extended functionality |
94 |
| --- for one, slicing creates views of the original list, and also the list |
95 |
| -contains information about the source line numbers. |
| 144 | +* :py:meth:`.SphinxDirective.parse_content_to_nodes()` |
| 145 | +* :py:meth:`.SphinxDirective.parse_text_to_nodes()` |
96 | 146 |
|
97 |
| -The :attr:`Directive.content` attribute is a ViewList. If you generate content |
98 |
| -to be parsed as ReST, you have to create a ViewList yourself. Important for |
99 |
| -content generation are the following points: |
| 147 | +The first method parses all the directive's content as markup, |
| 148 | +whilst the second only parses the given *text* string. |
| 149 | +Both methods return the parsed Docutils nodes in a list. |
100 | 150 |
|
101 |
| -* The constructor takes a list of strings (lines) and a source (document) name. |
| 151 | +The methods are used as follows: |
102 | 152 |
|
103 |
| -* The ``.append()`` method takes a line and a source name as well. |
| 153 | +.. code-block:: python |
104 | 154 |
|
| 155 | + def run(self) -> list[Node]: |
| 156 | + # either |
| 157 | + parsed = self.parse_content_to_nodes() |
| 158 | + # or |
| 159 | + parsed = self.parse_text_to_nodes('spam spam spam') |
| 160 | + return parsed |
105 | 161 |
|
106 |
| -Parsing directive content as ReST |
107 |
| -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ |
| 162 | +.. note:: |
| 163 | + |
| 164 | + The above utility methods were added in Sphinx 7.4. |
| 165 | + Prior to Sphinx 7.4, the following methods should be used to parse content: |
108 | 166 |
|
109 |
| -Many directives will contain more markup that must be parsed. To do this, use |
110 |
| -one of the following APIs from the :meth:`Directive.run` method: |
| 167 | + * ``self.state.nested_parse`` |
| 168 | + * :func:`sphinx.util.nodes.nested_parse_with_titles` -- this allows titles in |
| 169 | + the parsed content. |
111 | 170 |
|
112 |
| -* ``self.state.nested_parse`` |
113 |
| -* :func:`sphinx.util.nodes.nested_parse_with_titles` -- this allows titles in |
114 |
| - the parsed content. |
| 171 | + .. code-block:: python |
115 | 172 |
|
116 |
| -Both APIs parse the content into a given node. They are used like this:: |
| 173 | + def run(self) -> list[Node]: |
| 174 | + container = docutils.nodes.Element() |
| 175 | + # either |
| 176 | + nested_parse_with_titles(self.state, self.result, container) |
| 177 | + # or |
| 178 | + self.state.nested_parse(self.result, 0, container) |
| 179 | + parsed = container.children |
| 180 | + return parsed |
117 | 181 |
|
118 |
| - node = docutils.nodes.paragraph() |
119 |
| - # either |
120 |
| - nested_parse_with_titles(self.state, self.result, node) |
121 |
| - # or |
122 |
| - self.state.nested_parse(self.result, 0, node) |
| 182 | +To parse inline markup, |
| 183 | +use :py:meth:`~sphinx.util.docutils.SphinxDirective.parse_inline()`. |
| 184 | +This must only be used for text which is a single line or paragraph, |
| 185 | +and does not contain any structural elements |
| 186 | +(headings, transitions, directives, etc). |
123 | 187 |
|
124 | 188 | .. note::
|
125 | 189 |
|
126 |
| - ``sphinx.util.docutils.switch_source_input()`` allows to change a target file |
127 |
| - during nested_parse. It is useful to mixed contents. |
128 |
| - For example, ``sphinx.ext.autodoc`` uses it to parse docstrings:: |
| 190 | + ``sphinx.util.docutils.switch_source_input()`` allows changing |
| 191 | + the source (input) file during parsing content in a directive. |
| 192 | + It is useful to parse mixed content, such as in ``sphinx.ext.autodoc``, |
| 193 | + where it is used to parse docstrings. |
| 194 | + |
| 195 | + .. code-block:: python |
129 | 196 |
|
130 |
| - from sphinx.util.docutils import switch_source_input |
| 197 | + from sphinx.util.docutils import switch_source_input |
| 198 | + from sphinx.util.parsing import nested_parse_to_nodes |
131 | 199 |
|
132 |
| - # Switch source_input between parsing content. |
133 |
| - # Inside this context, all parsing errors and warnings are reported as |
134 |
| - # happened in new source_input (in this case, ``self.result``). |
135 |
| - with switch_source_input(self.state, self.result): |
136 |
| - node = docutils.nodes.paragraph() |
137 |
| - self.state.nested_parse(self.result, 0, node) |
| 200 | + # Switch source_input between parsing content. |
| 201 | + # Inside this context, all parsing errors and warnings are reported as |
| 202 | + # happened in new source_input (in this case, ``self.result``). |
| 203 | + with switch_source_input(self.state, self.result): |
| 204 | + parsed = nested_parse_to_nodes(self.state, self.result) |
138 | 205 |
|
139 | 206 | .. deprecated:: 1.7
|
140 | 207 |
|
141 | 208 | Until Sphinx 1.6, ``sphinx.ext.autodoc.AutodocReporter`` was used for this
|
142 | 209 | purpose. It is replaced by ``switch_source_input()``.
|
143 | 210 |
|
144 |
| -If you don't need the wrapping node, you can use any concrete node type and |
145 |
| -return ``node.children`` from the Directive. |
146 | 211 |
|
| 212 | +.. _ViewLists: |
147 | 213 |
|
148 |
| -.. seealso:: |
| 214 | +ViewLists and StringLists |
| 215 | +^^^^^^^^^^^^^^^^^^^^^^^^^ |
149 | 216 |
|
150 |
| - `Creating directives`_ HOWTO of the Docutils documentation |
| 217 | +Docutils represents document source lines in a ``StringList`` class, |
| 218 | +which inherits from ``ViewList``, both in the ``docutils.statemachine`` module. |
| 219 | +This is a list with extended functionality, |
| 220 | +including that slicing creates views of the original list and |
| 221 | +that the list contains information about source line numbers. |
| 222 | + |
| 223 | +The :attr:`Directive.content` attribute is a ``StringList``. |
| 224 | +If you generate content to be parsed as reStructuredText, |
| 225 | +you have to create a ``StringList`` for the Docutils APIs. |
| 226 | +The utility functions provided by Sphinx handle this automatically. |
| 227 | +Important for content generation are the following points: |
151 | 228 |
|
152 |
| -.. _Creating directives: https://docutils.sourceforge.io/docs/howto/rst-directives.html |
| 229 | +* The ``ViewList`` constructor takes a list of strings (lines) |
| 230 | + and a source (document) name. |
| 231 | +* The ``ViewList.append()`` method takes a line and a source name as well. |
0 commit comments