mirror of
https://github.com/sphinx-doc/sphinx.git
synced 2025-02-25 18:55:22 -06:00
Add `allow_section_headings
` to SphinxDirective parsing methods (#12503)
This commit is contained in:
parent
9276639fa6
commit
24a0385997
@ -278,7 +278,8 @@ class ObjectDescription(SphinxDirective, Generic[ObjDescT]):
|
|||||||
# needed for association of version{added,changed} directives
|
# needed for association of version{added,changed} directives
|
||||||
self.env.temp_data['object'] = self.names[0]
|
self.env.temp_data['object'] = self.names[0]
|
||||||
self.before_content()
|
self.before_content()
|
||||||
content_node = addnodes.desc_content('', *self.parse_content_to_nodes())
|
content_children = self.parse_content_to_nodes(allow_section_headings=True)
|
||||||
|
content_node = addnodes.desc_content('', *content_children)
|
||||||
node.append(content_node)
|
node.append(content_node)
|
||||||
self.transform_content(content_node)
|
self.transform_content(content_node)
|
||||||
self.env.app.emit('object-description-transform',
|
self.env.app.emit('object-description-transform',
|
||||||
|
@ -311,7 +311,7 @@ class JSModule(SphinxDirective):
|
|||||||
self.env.ref_context['js:module'] = mod_name
|
self.env.ref_context['js:module'] = mod_name
|
||||||
no_index = 'no-index' in self.options or 'noindex' in self.options
|
no_index = 'no-index' in self.options or 'noindex' in self.options
|
||||||
|
|
||||||
content_nodes = self.parse_content_to_nodes()
|
content_nodes = self.parse_content_to_nodes(allow_section_headings=True)
|
||||||
|
|
||||||
ret: list[Node] = []
|
ret: list[Node] = []
|
||||||
if not no_index:
|
if not no_index:
|
||||||
|
@ -416,7 +416,7 @@ class PyModule(SphinxDirective):
|
|||||||
no_index = 'no-index' in self.options or 'noindex' in self.options
|
no_index = 'no-index' in self.options or 'noindex' in self.options
|
||||||
self.env.ref_context['py:module'] = modname
|
self.env.ref_context['py:module'] = modname
|
||||||
|
|
||||||
content_nodes = self.parse_content_to_nodes()
|
content_nodes = self.parse_content_to_nodes(allow_section_headings=True)
|
||||||
|
|
||||||
ret: list[Node] = []
|
ret: list[Node] = []
|
||||||
if not no_index:
|
if not no_index:
|
||||||
|
@ -405,7 +405,9 @@ class Glossary(SphinxDirective):
|
|||||||
|
|
||||||
if definition:
|
if definition:
|
||||||
offset = definition.items[0][1]
|
offset = definition.items[0][1]
|
||||||
definition_nodes = nested_parse_to_nodes(self.state, definition, offset=offset)
|
definition_nodes = nested_parse_to_nodes(
|
||||||
|
self.state, definition, offset=offset, allow_section_headings=False,
|
||||||
|
)
|
||||||
else:
|
else:
|
||||||
definition_nodes = []
|
definition_nodes = []
|
||||||
termnodes.append(nodes.definition('', *definition_nodes))
|
termnodes.append(nodes.definition('', *definition_nodes))
|
||||||
|
@ -409,7 +409,8 @@ class Autosummary(SphinxDirective):
|
|||||||
for text in column_texts:
|
for text in column_texts:
|
||||||
vl = StringList([text], f'{source}:{line}:<autosummary>')
|
vl = StringList([text], f'{source}:{line}:<autosummary>')
|
||||||
with switch_source_input(self.state, vl):
|
with switch_source_input(self.state, vl):
|
||||||
col_nodes = nested_parse_to_nodes(self.state, vl)
|
col_nodes = nested_parse_to_nodes(self.state, vl,
|
||||||
|
allow_section_headings=False)
|
||||||
if col_nodes and isinstance(col_nodes[0], nodes.paragraph):
|
if col_nodes and isinstance(col_nodes[0], nodes.paragraph):
|
||||||
node = col_nodes[0]
|
node = col_nodes[0]
|
||||||
else:
|
else:
|
||||||
|
@ -47,7 +47,7 @@ class IfConfig(SphinxDirective):
|
|||||||
node.document = self.state.document
|
node.document = self.state.document
|
||||||
self.set_source_info(node)
|
self.set_source_info(node)
|
||||||
node['expr'] = self.arguments[0]
|
node['expr'] = self.arguments[0]
|
||||||
node += self.parse_content_to_nodes()
|
node += self.parse_content_to_nodes(allow_section_headings=True)
|
||||||
return [node]
|
return [node]
|
||||||
|
|
||||||
|
|
||||||
|
@ -434,21 +434,49 @@ class SphinxDirective(Directive):
|
|||||||
return f'<unknown>:{line}'
|
return f'<unknown>:{line}'
|
||||||
return ''
|
return ''
|
||||||
|
|
||||||
def parse_content_to_nodes(self) -> list[Node]:
|
def parse_content_to_nodes(self, allow_section_headings: bool = False) -> list[Node]:
|
||||||
"""Parse the directive's content into nodes."""
|
"""Parse the directive's content into nodes.
|
||||||
return nested_parse_to_nodes(self.state, self.content, offset=self.content_offset)
|
|
||||||
|
|
||||||
def parse_text_to_nodes(self, text: str = '', /, *, offset: int = -1) -> list[Node]:
|
:param allow_section_headings:
|
||||||
|
Are titles (sections) allowed in the directive's content?
|
||||||
|
Note that this option bypasses Docutils' usual checks on
|
||||||
|
doctree structure, and misuse of this option can lead to
|
||||||
|
an incoherent doctree. In Docutils, section nodes should
|
||||||
|
only be children of ``Structural`` nodes, which includes
|
||||||
|
``document``, ``section``, and ``sidebar`` nodes.
|
||||||
|
"""
|
||||||
|
return nested_parse_to_nodes(
|
||||||
|
self.state,
|
||||||
|
self.content,
|
||||||
|
offset=self.content_offset,
|
||||||
|
allow_section_headings=allow_section_headings,
|
||||||
|
)
|
||||||
|
|
||||||
|
def parse_text_to_nodes(
|
||||||
|
self, text: str = '', /, *, offset: int = -1, allow_section_headings: bool = False,
|
||||||
|
) -> list[Node]:
|
||||||
"""Parse *text* into nodes.
|
"""Parse *text* into nodes.
|
||||||
|
|
||||||
:param text:
|
:param text:
|
||||||
Text, in string form. ``StringList`` is also accepted.
|
Text, in string form. ``StringList`` is also accepted.
|
||||||
|
:param allow_section_headings:
|
||||||
|
Are titles (sections) allowed in *text*?
|
||||||
|
Note that this option bypasses Docutils' usual checks on
|
||||||
|
doctree structure, and misuse of this option can lead to
|
||||||
|
an incoherent doctree. In Docutils, section nodes should
|
||||||
|
only be children of ``Structural`` nodes, which includes
|
||||||
|
``document``, ``section``, and ``sidebar`` nodes.
|
||||||
:param offset:
|
:param offset:
|
||||||
The offset of the content.
|
The offset of the content.
|
||||||
"""
|
"""
|
||||||
if offset == -1:
|
if offset == -1:
|
||||||
offset = self.content_offset
|
offset = self.content_offset
|
||||||
return nested_parse_to_nodes(self.state, text, offset=offset)
|
return nested_parse_to_nodes(
|
||||||
|
self.state,
|
||||||
|
text,
|
||||||
|
offset=offset,
|
||||||
|
allow_section_headings=allow_section_headings,
|
||||||
|
)
|
||||||
|
|
||||||
def parse_inline(
|
def parse_inline(
|
||||||
self, text: str, *, lineno: int = -1,
|
self, text: str, *, lineno: int = -1,
|
||||||
|
@ -334,7 +334,7 @@ def nested_parse_with_titles(state: RSTState, content: StringList, node: Node,
|
|||||||
context, such as docstrings.
|
context, such as docstrings.
|
||||||
|
|
||||||
This function is retained for compatability and will be deprecated in
|
This function is retained for compatability and will be deprecated in
|
||||||
Sphinx 8. Prefer ``parse_block_text()``.
|
Sphinx 8. Prefer ``nested_parse_to_nodes()``.
|
||||||
"""
|
"""
|
||||||
with _fresh_title_style_context(state):
|
with _fresh_title_style_context(state):
|
||||||
ret = state.nested_parse(content, content_offset, node, match_titles=True)
|
ret = state.nested_parse(content, content_offset, node, match_titles=True)
|
||||||
|
@ -20,6 +20,7 @@ def nested_parse_to_nodes(
|
|||||||
*,
|
*,
|
||||||
source: str = '<generated text>',
|
source: str = '<generated text>',
|
||||||
offset: int = 0,
|
offset: int = 0,
|
||||||
|
allow_section_headings: bool = True,
|
||||||
keep_title_context: bool = False,
|
keep_title_context: bool = False,
|
||||||
) -> list[nodes.Node]: # Element | nodes.Text
|
) -> list[nodes.Node]: # Element | nodes.Text
|
||||||
"""Parse *text* into nodes.
|
"""Parse *text* into nodes.
|
||||||
@ -32,6 +33,13 @@ def nested_parse_to_nodes(
|
|||||||
The text's source, used when creating a new ``StringList``.
|
The text's source, used when creating a new ``StringList``.
|
||||||
:param offset:
|
:param offset:
|
||||||
The offset of the content.
|
The offset of the content.
|
||||||
|
:param allow_section_headings:
|
||||||
|
Are titles (sections) allowed in *text*?
|
||||||
|
Note that this option bypasses Docutils' usual checks on
|
||||||
|
doctree structure, and misuse of this option can lead to
|
||||||
|
an incoherent doctree. In Docutils, section nodes should
|
||||||
|
only be children of ``Structural`` nodes, which includes
|
||||||
|
``document``, ``section``, and ``sidebar`` nodes.
|
||||||
:param keep_title_context:
|
:param keep_title_context:
|
||||||
If this is False (the default), then *content* is parsed as if it were
|
If this is False (the default), then *content* is parsed as if it were
|
||||||
an independent document, meaning that title decorations (e.g. underlines)
|
an independent document, meaning that title decorations (e.g. underlines)
|
||||||
@ -49,10 +57,10 @@ def nested_parse_to_nodes(
|
|||||||
node.document = document
|
node.document = document
|
||||||
|
|
||||||
if keep_title_context:
|
if keep_title_context:
|
||||||
state.nested_parse(content, offset, node, match_titles=True)
|
state.nested_parse(content, offset, node, match_titles=allow_section_headings)
|
||||||
else:
|
else:
|
||||||
with _fresh_title_style_context(state):
|
with _fresh_title_style_context(state):
|
||||||
state.nested_parse(content, offset, node, match_titles=True)
|
state.nested_parse(content, offset, node, match_titles=allow_section_headings)
|
||||||
return node.children
|
return node.children
|
||||||
|
|
||||||
|
|
||||||
|
@ -100,7 +100,7 @@ def test_sphinx_directive_parse_content_to_nodes():
|
|||||||
content = 'spam\n====\n\nEggs! *Lobster thermidor.*'
|
content = 'spam\n====\n\nEggs! *Lobster thermidor.*'
|
||||||
directive.content = StringList(content.split('\n'), source='<source>')
|
directive.content = StringList(content.split('\n'), source='<source>')
|
||||||
|
|
||||||
parsed = directive.parse_content_to_nodes()
|
parsed = directive.parse_content_to_nodes(allow_section_headings=True)
|
||||||
assert len(parsed) == 1
|
assert len(parsed) == 1
|
||||||
node = parsed[0]
|
node = parsed[0]
|
||||||
assert isinstance(node, nodes.section)
|
assert isinstance(node, nodes.section)
|
||||||
@ -115,7 +115,7 @@ def test_sphinx_directive_parse_text_to_nodes():
|
|||||||
directive = make_directive(env=SimpleNamespace())
|
directive = make_directive(env=SimpleNamespace())
|
||||||
content = 'spam\n====\n\nEggs! *Lobster thermidor.*'
|
content = 'spam\n====\n\nEggs! *Lobster thermidor.*'
|
||||||
|
|
||||||
parsed = directive.parse_text_to_nodes(content)
|
parsed = directive.parse_text_to_nodes(content, allow_section_headings=True)
|
||||||
assert len(parsed) == 1
|
assert len(parsed) == 1
|
||||||
node = parsed[0]
|
node = parsed[0]
|
||||||
assert isinstance(node, nodes.section)
|
assert isinstance(node, nodes.section)
|
||||||
|
Loading…
Reference in New Issue
Block a user