mirror of
https://github.com/sphinx-doc/sphinx.git
synced 2025-02-25 18:55:22 -06:00
[rst] Add level option to rubric directive (#12506)
This commit adds a `level` option to the `rubric` directive, which propagates a `level` attribute to the `rubric` node, and allows renderers to select a specific heading level. Logic for this attribute has been added to the HTML5 and LaTeX builder.
This commit is contained in:
@@ -28,6 +28,8 @@ Features added
|
|||||||
|
|
||||||
.. rst-class:: compact
|
.. rst-class:: compact
|
||||||
|
|
||||||
|
* Add ``level`` option to :rst:dir:`rubric` directive.
|
||||||
|
Patch by Chris Sewell.
|
||||||
* Add optional ``description`` argument to
|
* Add optional ``description`` argument to
|
||||||
:meth:`~sphinx.application.Sphinx.add_config_value`.
|
:meth:`~sphinx.application.Sphinx.add_config_value`.
|
||||||
Patch by Chris Sewell.
|
Patch by Chris Sewell.
|
||||||
|
|||||||
@@ -373,8 +373,18 @@ units as well as normal text.
|
|||||||
|
|
||||||
.. rst:directive:: .. rubric:: title
|
.. rst:directive:: .. rubric:: title
|
||||||
|
|
||||||
This directive creates a paragraph heading that is not used to create a
|
A rubric is like an informal heading that doesn't correspond to the document's structure,
|
||||||
table of contents node.
|
i.e. it does not create a table of contents node.
|
||||||
|
|
||||||
|
.. rst:directive:option:: level: n
|
||||||
|
:type: number from 1 to 6
|
||||||
|
|
||||||
|
.. versionadded:: 7.4
|
||||||
|
|
||||||
|
Use this option to specify the heading level of the rubric.
|
||||||
|
In this case the rubric will be rendered as ``<h1>`` to ``<h6>`` for HTML output,
|
||||||
|
or as the corresponding non-numbered sectioning command for LaTeX
|
||||||
|
(see :confval:`latex_toplevel_sectioning`).
|
||||||
|
|
||||||
.. note::
|
.. note::
|
||||||
|
|
||||||
|
|||||||
@@ -176,12 +176,38 @@ class MathDirective(SphinxDirective):
|
|||||||
ret.insert(0, target)
|
ret.insert(0, target)
|
||||||
|
|
||||||
|
|
||||||
|
class Rubric(SphinxDirective):
|
||||||
|
"""A patch of the docutils' :rst:dir:`rubric` directive,
|
||||||
|
which adds a level option to specify the heading level of the rubric.
|
||||||
|
"""
|
||||||
|
|
||||||
|
required_arguments = 1
|
||||||
|
optional_arguments = 0
|
||||||
|
final_argument_whitespace = True
|
||||||
|
option_spec = {
|
||||||
|
'class': directives.class_option,
|
||||||
|
'name': directives.unchanged,
|
||||||
|
'level': lambda c: directives.choice(c, ('1', '2', '3', '4', '5', '6')),
|
||||||
|
}
|
||||||
|
|
||||||
|
def run(self) -> list[Node]:
|
||||||
|
set_classes(self.options)
|
||||||
|
rubric_text = self.arguments[0]
|
||||||
|
textnodes, messages = self.parse_inline(rubric_text, lineno=self.lineno)
|
||||||
|
rubric = nodes.rubric(rubric_text, '', *textnodes, **self.options)
|
||||||
|
self.add_name(rubric)
|
||||||
|
if 'level' in self.options:
|
||||||
|
rubric['level'] = int(self.options['level'])
|
||||||
|
return [rubric, *messages]
|
||||||
|
|
||||||
|
|
||||||
def setup(app: Sphinx) -> ExtensionMetadata:
|
def setup(app: Sphinx) -> ExtensionMetadata:
|
||||||
directives.register_directive('figure', Figure)
|
directives.register_directive('figure', Figure)
|
||||||
directives.register_directive('meta', Meta)
|
directives.register_directive('meta', Meta)
|
||||||
directives.register_directive('csv-table', CSVTable)
|
directives.register_directive('csv-table', CSVTable)
|
||||||
directives.register_directive('code', Code)
|
directives.register_directive('code', Code)
|
||||||
directives.register_directive('math', MathDirective)
|
directives.register_directive('math', MathDirective)
|
||||||
|
directives.register_directive('rubric', Rubric)
|
||||||
|
|
||||||
return {
|
return {
|
||||||
'version': 'builtin',
|
'version': 'builtin',
|
||||||
|
|||||||
@@ -509,6 +509,30 @@ class HTML5Translator(SphinxTranslator, BaseTranslator):
|
|||||||
|
|
||||||
super().depart_title(node)
|
super().depart_title(node)
|
||||||
|
|
||||||
|
# overwritten
|
||||||
|
def visit_rubric(self, node: Element) -> None:
|
||||||
|
if "level" in node:
|
||||||
|
level = node["level"]
|
||||||
|
if level in (1, 2, 3, 4, 5, 6):
|
||||||
|
self.body.append(self.starttag(node, f'h{level}', '', CLASS='rubric'))
|
||||||
|
else:
|
||||||
|
logger.warning(
|
||||||
|
__('unsupported rubric heading level: %s'),
|
||||||
|
level,
|
||||||
|
type='html',
|
||||||
|
location=node
|
||||||
|
)
|
||||||
|
super().visit_rubric(node)
|
||||||
|
else:
|
||||||
|
super().visit_rubric(node)
|
||||||
|
|
||||||
|
# overwritten
|
||||||
|
def depart_rubric(self, node: Element) -> None:
|
||||||
|
if level := node.get("level"):
|
||||||
|
self.body.append(f'</h{level}>\n')
|
||||||
|
else:
|
||||||
|
super().depart_rubric(node)
|
||||||
|
|
||||||
# overwritten
|
# overwritten
|
||||||
def visit_literal_block(self, node: Element) -> None:
|
def visit_literal_block(self, node: Element) -> None:
|
||||||
if node.rawsource != node.astext():
|
if node.rawsource != node.astext():
|
||||||
|
|||||||
@@ -967,7 +967,20 @@ class LaTeXTranslator(SphinxTranslator):
|
|||||||
def visit_rubric(self, node: Element) -> None:
|
def visit_rubric(self, node: Element) -> None:
|
||||||
if len(node) == 1 and node.astext() in ('Footnotes', _('Footnotes')):
|
if len(node) == 1 and node.astext() in ('Footnotes', _('Footnotes')):
|
||||||
raise nodes.SkipNode
|
raise nodes.SkipNode
|
||||||
self.body.append(r'\subsubsection*{')
|
tag = 'subsubsection'
|
||||||
|
if "level" in node:
|
||||||
|
level = node["level"]
|
||||||
|
try:
|
||||||
|
tag = self.sectionnames[self.top_sectionlevel - 1 + level]
|
||||||
|
except Exception:
|
||||||
|
logger.warning(
|
||||||
|
__('unsupported rubric heading level: %s'),
|
||||||
|
level,
|
||||||
|
type='latex',
|
||||||
|
location=node
|
||||||
|
)
|
||||||
|
|
||||||
|
self.body.append(rf'\{tag}*{{')
|
||||||
self.context.append('}' + CR)
|
self.context.append('}' + CR)
|
||||||
self.in_title = 1
|
self.in_title = 1
|
||||||
|
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
latex_documents = [
|
latex_documents = [
|
||||||
('index', 'test.tex', 'The basic Sphinx documentation for testing', 'Sphinx', 'report')
|
('index', 'test.tex', 'The basic Sphinx documentation for testing', 'Sphinx', 'report')
|
||||||
]
|
]
|
||||||
|
latex_toplevel_sectioning = 'section'
|
||||||
|
|||||||
@@ -5,3 +5,35 @@ test-markup-rubric
|
|||||||
|
|
||||||
.. rubric:: This is
|
.. rubric:: This is
|
||||||
a multiline rubric
|
a multiline rubric
|
||||||
|
|
||||||
|
.. rubric:: A rubric with a class
|
||||||
|
:class: myclass
|
||||||
|
|
||||||
|
.. rubric:: A rubric with a heading level 1
|
||||||
|
:level: 1
|
||||||
|
:class: myclass
|
||||||
|
|
||||||
|
.. rubric:: A rubric with a heading level 2
|
||||||
|
:level: 2
|
||||||
|
:class: myclass
|
||||||
|
|
||||||
|
.. rubric:: A rubric with a heading level 3
|
||||||
|
:level: 3
|
||||||
|
:class: myclass
|
||||||
|
|
||||||
|
.. rubric:: A rubric with a heading level 4
|
||||||
|
:level: 4
|
||||||
|
:class: myclass
|
||||||
|
|
||||||
|
.. rubric:: A rubric with a heading level 5
|
||||||
|
:level: 5
|
||||||
|
:class: myclass
|
||||||
|
|
||||||
|
.. rubric:: A rubric with a heading level 6
|
||||||
|
:level: 6
|
||||||
|
:class: myclass
|
||||||
|
|
||||||
|
.. rubric:: A rubric with a heading level 7
|
||||||
|
:level: 7
|
||||||
|
:class: myclass
|
||||||
|
|
||||||
|
|||||||
@@ -278,3 +278,12 @@ def tail_check(check):
|
|||||||
def test_html5_output(app, cached_etree_parse, fname, path, check):
|
def test_html5_output(app, cached_etree_parse, fname, path, check):
|
||||||
app.build()
|
app.build()
|
||||||
check_xpath(cached_etree_parse(app.outdir / fname), fname, path, check)
|
check_xpath(cached_etree_parse(app.outdir / fname), fname, path, check)
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.sphinx('html', testroot='markup-rubric')
|
||||||
|
def test_html5_rubric(app):
|
||||||
|
app.build()
|
||||||
|
assert '"7" unknown' in app.warning.getvalue()
|
||||||
|
content = (app.outdir / 'index.html').read_text(encoding='utf8')
|
||||||
|
assert '<p class="rubric">This is a rubric</p>' in content
|
||||||
|
assert '<h2 class="myclass rubric">A rubric with a heading level 2</h2>' in content
|
||||||
|
|||||||
@@ -1759,3 +1759,11 @@ def test_one_parameter_per_line(app, status, warning):
|
|||||||
assert ('\\pysiglinewithargsret{\\sphinxbfcode{\\sphinxupquote{hello}}}' in result)
|
assert ('\\pysiglinewithargsret{\\sphinxbfcode{\\sphinxupquote{hello}}}' in result)
|
||||||
|
|
||||||
assert ('\\pysigwithonelineperarg{\\sphinxbfcode{\\sphinxupquote{foo}}}' in result)
|
assert ('\\pysigwithonelineperarg{\\sphinxbfcode{\\sphinxupquote{foo}}}' in result)
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.sphinx('latex', testroot='markup-rubric')
|
||||||
|
def test_latex_rubric(app):
|
||||||
|
app.build()
|
||||||
|
content = (app.outdir / 'test.tex').read_text(encoding='utf8')
|
||||||
|
assert r'\subsubsection*{This is a rubric}' in content
|
||||||
|
assert r'\subsection*{A rubric with a heading level 2}' in content
|
||||||
|
|||||||
@@ -43,6 +43,7 @@ def test_texinfo_rubric(app, status, warning):
|
|||||||
output = (app.outdir / 'projectnamenotset.texi').read_text(encoding='utf8')
|
output = (app.outdir / 'projectnamenotset.texi').read_text(encoding='utf8')
|
||||||
assert '@heading This is a rubric' in output
|
assert '@heading This is a rubric' in output
|
||||||
assert '@heading This is a multiline rubric' in output
|
assert '@heading This is a multiline rubric' in output
|
||||||
|
assert '@heading A rubric with a heading level' in output
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.sphinx('texinfo', testroot='markup-citation')
|
@pytest.mark.sphinx('texinfo', testroot='markup-citation')
|
||||||
|
|||||||
Reference in New Issue
Block a user