Skip to content

Commit

Permalink
Move to sphinx.ext.collapse
Browse files Browse the repository at this point in the history
  • Loading branch information
AA-Turner committed Apr 27, 2024
1 parent 68c5006 commit 3828fe1
Show file tree
Hide file tree
Showing 14 changed files with 287 additions and 210 deletions.
1 change: 1 addition & 0 deletions .ruff.toml
Original file line number Diff line number Diff line change
Expand Up @@ -650,6 +650,7 @@ exclude = [
"tests/test_extensions/test_ext_githubpages.py",
"tests/test_extensions/test_ext_intersphinx.py",
"tests/test_extensions/test_ext_napoleon.py",
"tests/test_extensions/test_ext_collapse.py",
"tests/test_extensions/test_ext_coverage.py",
"tests/test_extensions/ext_napoleon_pep526_data_numpy.py",
"tests/test_extensions/test_ext_autodoc_configs.py",
Expand Down
5 changes: 3 additions & 2 deletions CHANGES.rst
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,9 @@ Features added
* Flatten ``Union[Literal[T], Literal[U], ...]`` to ``Literal[T, U, ...]``
when turning annotations into strings.
Patch by Adam Turner.
* #10532: Added the :rst:dir:`collapsible` directive and support for collapsible
content in HTML. Patch by Adam Turner.
* #10532: Add a new extension to support collapsible content in HTML,
``sphinx.ext.collapse``, which enables the :rst:dir:`collapsible` directive.
Patch by Adam Turner.

Bugs fixed
----------
Expand Down
2 changes: 0 additions & 2 deletions doc/extdev/nodes.rst
Original file line number Diff line number Diff line change
Expand Up @@ -93,8 +93,6 @@ Special nodes

.. autoclass:: only
.. autoclass:: highlightlang
.. autoclass:: collapsible
.. autoclass:: collapsible_summary

You should not need to generate the nodes below in extensions.

Expand Down
60 changes: 60 additions & 0 deletions doc/usage/extensions/collapse.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
.. _collapsible:

:mod:`sphinx.ext.collapse` -- HTML collapsible content
======================================================

.. module:: sphinx.ext.collapse
:synopsis: Support for collapsible content in HTML output.

.. versionadded:: 7.4

.. index:: single: collapse
single: collapsible
single: details
single: summary
pair: collapse; directive
pair: details; directive
pair: summary; directive

This extension provides a :rst:dir:`collapse` directive to provide support for
`collapsible content`_ in HTML output.

.. _collapsible content: https://developer.mozilla.org/en-US/docs/Web/HTML/Element/details

This extension is quite simple, and features only one directive:

.. rst:directive:: .. collapse:: <summary description>
For HTML builders, this directive places the content of the directive
into an HTML `details disclosure`_ element,
with the *summary description* text included as the summary for the element.
The *summary description* text is parsed as reStructuredText,
and can be broken over multiple lines if required.

Only the HTML 5 output format supports collapsible content.
For other builders, the *summary description* text
and the body of the directive are rendered in the document.

.. _details disclosure: https://developer.mozilla.org/en-US/docs/Web/HTML/Element/details

An example and the equivalent output are shown below:

.. code-block:: reStructuredText
.. collapse:: ``literal`` and **bold** content.
This is the body of the directive.
.. collapse:: ``literal`` and **bold** content.

This is the body of the directive.

.. versionadded:: 7.4

Internal node classes
---------------------

.. note:: These classes are only relevant to extension and theme developers.

.. autoclass:: collapsible
.. autoclass:: summary
31 changes: 0 additions & 31 deletions doc/usage/restructuredtext/directives.rst
Original file line number Diff line number Diff line change
Expand Up @@ -1083,37 +1083,6 @@ Including content based on tags
This directive is designed to control only content of document. It could
not control sections, labels and so on.

.. _collapsible:

Using collapsible content
-------------------------

.. rst:directive:: .. collapsible:: <summary description>
For HTML builders, place the content of the directive into a HTML `details
disclosure`_ element, with the *summary description* text included as the
summary for the element. The *summary description* text is parsed as
reStructuredText, and can be broken over multiple lines if required. An
example and the equivalent output are shown below:

.. code-block:: reStructuredText
.. collapsible:: ``literal`` and **bold** content.
This is the body of the directive.
.. collapsible:: ``literal`` and **bold** content.

This is the body of the directive.

Only the HTML 5 output format supports collapsible content. For other builders,
the *summary description* text and the body of the directive are rendered in
the document.

.. versionadded:: 5.1

.. _details disclosure: https://developer.mozilla.org/en-US/docs/Web/HTML/Element/details

.. _table-directives:

Tables
Expand Down
14 changes: 0 additions & 14 deletions sphinx/addnodes.py
Original file line number Diff line number Diff line change
Expand Up @@ -102,20 +102,6 @@ def extract_original_messages(self) -> list[str]:
return messages


class collapsible(nodes.General, nodes.Element):
"""Node for collapsible content.
This is used by the :rst:dir:`collapsible` directive.
"""


class collapsible_summary(nodes.General, nodes.TextElement):
"""Node for the description for collapsible content.
This is used by the :rst:dir:`collapsible` directive.
"""


#############################################################
# Domain-specific object descriptions (class, function etc.)
#############################################################
Expand Down
94 changes: 0 additions & 94 deletions sphinx/directives/other.py
Original file line number Diff line number Diff line change
Expand Up @@ -427,99 +427,6 @@ def _insert_input(include_lines: list[str], source: str) -> None:
return super().run()


class Collapsible(SphinxDirective):
"""
Directive to mark collapsible content, with an optional summary line.
"""
has_content = True
optional_arguments = 1
final_argument_whitespace = True
option_spec: OptionSpec = {
'class': directives.class_option,
'open': directives.flag,
}

@staticmethod
def _prepare_argument_string(s: str) -> str:
"""Prepare a directive argument string.
Remove common leading indentation, where the indentation of the first
line is ignored.
Return a list of lines usable for inserting into a docutils StringList.
"""
lines = s.expandtabs().splitlines()

# Find minimum indentation of any non-blank lines after the first.
# if your indent is larger than a million yotta-spaces, there's a problem...
margin = 10**30
for line in lines[1:]:
content = len(line.lstrip())
if content:
indent = len(line) - content
margin = min(margin, indent)

if margin == 10**30:
return s

return "\n".join((lines[0], *(line[margin:] for line in lines[1:])))

def run(self) -> List[Node]:
node = addnodes.collapsible(collapsible_open="open" in self.options)
node.document = self.state.document
self.set_source_info(node)
if len(self.arguments) > 0:
summary = self.arguments[0].strip()
else:
summary = "Collapsed Content:"

# parse the argument as reST
summary_trimmed = self._prepare_argument_string(summary)
textnodes, _messages = self.state.inline_text(summary_trimmed, self.lineno)
node.append(addnodes.collapsible_summary(summary, "", *textnodes))

# Same as util.nested_parse_with_titles but try to handle nested
# sections which should be raised higher up the doctree.
memo: Any = self.state.memo
surrounding_title_styles = memo.title_styles
surrounding_section_level = memo.section_level
memo.title_styles = []
memo.section_level = 0
try:
self.state.nested_parse(self.content, self.content_offset,
node, match_titles=True)
title_styles = memo.title_styles
if (not surrounding_title_styles or
not title_styles or
title_styles[0] not in surrounding_title_styles or
not self.state.parent):
# No nested sections so no special handling needed.
return [node]
# Calculate the depths of the current and nested sections.
current_depth = 0
parent = self.state.parent
while parent:
current_depth += 1
parent = parent.parent
current_depth -= 2
title_style = title_styles[0]
nested_depth = len(surrounding_title_styles)
if title_style in surrounding_title_styles:
nested_depth = surrounding_title_styles.index(title_style)
# Use these depths to determine where the nested sections should
# be placed in the doctree.
n_sects_to_raise = current_depth - nested_depth + 1
parent = cast(nodes.Element, self.state.parent)
for _i in range(n_sects_to_raise):
if parent.parent:
parent = parent.parent
parent.append(node)
return []
finally:
memo.title_styles = surrounding_title_styles
memo.section_level = surrounding_section_level


def setup(app: Sphinx) -> ExtensionMetadata:
directives.register_directive('toctree', TocTree)
directives.register_directive('sectionauthor', Author)
Expand All @@ -532,7 +439,6 @@ def setup(app: Sphinx) -> ExtensionMetadata:
directives.register_directive('hlist', HList)
directives.register_directive('only', Only)
directives.register_directive('include', Include)
directives.register_directive('collapsible', Collapsible)

# register the standard rst class directive under a different name
# only for backwards compatibility now
Expand Down
Loading

0 comments on commit 3828fe1

Please sign in to comment.