Skip to content

Commit

Permalink
Add support for manual indexing (#177)
Browse files Browse the repository at this point in the history
- Allow the root api file generation to be skipped.
- Allow ``.rst.include`` behavior to be modified.
- Release 0.3.6.
  • Loading branch information
svenevs committed Oct 2, 2022
1 parent 0cbf655 commit 9a6138e
Show file tree
Hide file tree
Showing 7 changed files with 297 additions and 39 deletions.
2 changes: 1 addition & 1 deletion README.rst
Expand Up @@ -133,7 +133,7 @@ Exhale Version Compatibility with Python, Sphinx, and Breathe
+----------------+----------------+----------------+-----------------+
| Exhale Version | Python Version | Sphinx Version | Breathe Version |
+================+================+================+=================+
| 0.3.2 -- 0.3.4 | >=3.7 | >=3.0,<5 | >=4.32.0 |
| 0.3.2 -- 0.3.6 | >=3.7 | >=3.0,<5 | >=4.32.0 |
+----------------+----------------+----------------+-----------------+
| 0.3.0 | >=3.6 | >=3.0,<5 | >=4.32.0 |
+----------------+----------------+----------------+-----------------+
Expand Down
6 changes: 6 additions & 0 deletions docs/changelog.rst
Expand Up @@ -5,6 +5,12 @@ Changelog
:local:
:backlinks: none

v0.3.6
----------------------------------------------------------------------------------------

- Enable the root document to be excluded, and additional manual indexing control
(:issue:`176`, :pr:`177`).

v0.3.5
----------------------------------------------------------------------------------------

Expand Down
49 changes: 49 additions & 0 deletions docs/reference/configs.rst
Expand Up @@ -242,6 +242,55 @@ that you will link to from your documentation is laid out as follows:

.. autodata:: exhale.configs.unabridgedOrphanKinds

.. _manual_indexing:

Manual Indexing
****************************************************************************************

To compose the different sections of the root document, exhale generates some additional
files to ``.. include::`` them. Depending on the compounds documented in doxygen as
well as other settings different entries in the example below may or may not be
generated.

.. code-block:: rst
=======================
Some Title You Provided
=======================
.. include:: page_index.rst.include
.. include:: page_view_hierarchy.rst.include
.. include:: class_view_hierarchy.rst.include
.. include:: file_view_hierarchy.rst.include
.. include:: unabridged_api.rst.include
These should **not** use a file extension found in :confval:`sphinx:source_suffix`,
since the file ``class_view_hierarchy.rst`` for example will also be processed into
html. This results in warnings between duplicate labels being found in both the root
document and the document being included (`more information here`__).

__ https://github.com/sphinx-doc/sphinx/issues/1668

To manually index through the generated exhale documents, you can set
:data:`~exhale.configs.rootFileName` to ``"EXCLUDE"``. With the root file out of the
picture, you may seek to ``.. include::`` (or add to a ``.. toctree::``) one of the
documents above. In the ``.. toctree::`` scenario, you will want the file extension to
be ``.rst`` so that sphinx will process it.

.. autodata:: exhale.configs.classHierarchyFilename

.. autodata:: exhale.configs.fileHierarchyFilename

.. autodata:: exhale.configs.pageHierarchyFilename

.. autodata:: exhale.configs.unabridgedApiFilename

.. autodata:: exhale.configs.unabridgedOrphanFilename

Clickable Hierarchies
****************************************************************************************

Expand Down
2 changes: 1 addition & 1 deletion exhale/__init__.py
Expand Up @@ -8,7 +8,7 @@

from __future__ import unicode_literals

__version__ = "0.3.6.dev"
__version__ = "0.3.6"


def environment_ready(app):
Expand Down
53 changes: 49 additions & 4 deletions exhale/configs.py
Expand Up @@ -104,6 +104,11 @@
documents. Do **not** include the ``containmentFolder`` path in this file name,
Exhale will create the file ``"{contaimentFolder}/{rootFileName}"`` for you.
.. note::
If the value provided is exactly ``"EXCLUDE"`` then the root file will not be
generated. See :ref:`manual_indexing` for more information.
**Value in** ``exhale_args`` (str)
The value of key ``"rootFileName"`` should be a string representing the name of
the file you will be including in your top-level ``toctree`` directive. In order
Expand Down Expand Up @@ -490,6 +495,40 @@ class and file hierarchies.
will present classes and structs together.
"""

########################################################################################
# Manual Indexing #
########################################################################################
classHierarchyFilename = "class_view_hierarchy.rst.include"
'''
The name of the file the class hierarchy is generated in saved to
``{containmentFolder}/{classHierarchyFilename}``.
'''

fileHierarchyFilename = "file_view_hierarchy.rst.include"
'''
The name of the file the class hierarchy is generated in saved to
``{containmentFolder}/{fileHierarchyFilename}``.
'''

pageHierarchyFilename = "page_view_hierarchy.rst.include"
'''
The name of the file the class hierarchy is generated in saved to
``{containmentFolder}/{pageHierarchyFilename}``.
'''

unabridgedApiFilename = "unabridged_api.rst.include"
'''
The name of the file the class hierarchy is generated in saved to
``{containmentFolder}/{unabridgedApiFilename}``.
'''

unabridgedOrphanFilename = "unabridged_orphan.rst"
'''
The name of the file the class hierarchy is generated in saved to
``{containmentFolder}/{unabridgedOrphanFilename}``. See also:
:data:`~exhale.configs.unabridgedOrphanKinds`.
'''

########################################################################################
# Clickable Hierarchies <3 #
########################################################################################
Expand Down Expand Up @@ -1412,11 +1451,11 @@ def apply_sphinx_configurations(app):
# We *ONLY* generate reStructuredText, make sure Sphinx is expecting this as well as
# the to-be-generated library root file is correctly suffixed.
if not rootFileName.endswith(".rst"):
raise ConfigError(
"The given `rootFileName` ({0}) did not end with '.rst'; Exhale is reStructuredText only.".format(
rootFileName
if rootFileName != "EXCLUDE":
raise ConfigError(
f"The given `rootFileName` ({rootFileName}) did not end with '.rst'; "
"Exhale is reStructuredText only."
)
)
if ".rst" not in app.config.source_suffix:
raise ConfigError(
"Exhale is reStructuredText only, but '.rst' was not found in `source_suffix` list of `conf.py`."
Expand Down Expand Up @@ -1447,6 +1486,12 @@ def apply_sphinx_configurations(app):
("fullToctreeMaxDepth", int),
("listingExclude", list),
("unabridgedOrphanKinds", (list, set)),
# Manual Indexing
("classHierarchyFilename", six.string_types),
("fileHierarchyFilename", six.string_types),
("pageHierarchyFilename", six.string_types),
("unabridgedApiFilename", six.string_types),
("unabridgedOrphanFilename", six.string_types),
# Clickable Hierarchies <3
("createTreeView", bool),
("minifyTreeView", bool),
Expand Down
60 changes: 27 additions & 33 deletions exhale/graph.py
Expand Up @@ -1061,24 +1061,12 @@ def __init__(self):
self.root_directory = configs.containmentFolder
self.root_file_name = configs.rootFileName
self.full_root_file_path = os.path.join(self.root_directory, self.root_file_name)
# The {page,class,file}_view_hierarchy files are all `.. include::`ed in the
# root library document. Though we are generating rst, we will want to use a
# file extension `.rst.include` to bypass the fact that the sphinx builder will
# process them separately if we leave them as .rst (via the source_suffix
# configuration of the sphinx app). If users are getting warnings about it
# then we can actually check for `.include` in app.config.source_suffix, but
# it is very unlikely this is going to be a problem.
# See https://github.com/sphinx-doc/sphinx/issues/1668
self.page_hierarchy_file = os.path.join(self.root_directory, "page_view_hierarchy.rst.include")
self.class_hierarchy_file = os.path.join(self.root_directory, "class_view_hierarchy.rst.include")
self.file_hierarchy_file = os.path.join(self.root_directory, "file_view_hierarchy.rst.include")
self.unabridged_api_file = os.path.join(self.root_directory, "unabridged_api.rst.include")
# NOTE: do *NOT* do .rst.include for the unabridged orphan kinds, the purpose of
# that document is to have it be processed by sphinx with its corresponding
# .. toctree:: calls to kinds that the user has asked to be excluded. Sphinx
# processing this document directly is desired (it is also marked :orphan: to
# avoid a warning on the fact that it is *NOT* included in any exhale toctree).
self.unabridged_orphan_file = os.path.join(self.root_directory, "unabridged_orphan.rst")
# These documents are all included in the root file document.
self.page_hierarchy_file = os.path.join(self.root_directory, configs.pageHierarchyFilename)
self.class_hierarchy_file = os.path.join(self.root_directory, configs.classHierarchyFilename)
self.file_hierarchy_file = os.path.join(self.root_directory, configs.fileHierarchyFilename)
self.unabridged_api_file = os.path.join(self.root_directory, configs.unabridgedApiFilename)
self.unabridged_orphan_file = os.path.join(self.root_directory, configs.unabridgedOrphanFilename)

# whether or not we should generate the raw html tree view
self.use_tree_view = configs.createTreeView
Expand Down Expand Up @@ -2287,18 +2275,6 @@ def generateFullAPI(self):
2. :func:`~exhale.graph.ExhaleRoot.generateNodeDocuments`
3. :func:`~exhale.graph.ExhaleRoot.generateAPIRootBody`
'''
self.generateAPIRootHeader()
self.generateNodeDocuments()
self.generateAPIRootBody()

def generateAPIRootHeader(self):
'''
This method creates the root library api file that will include all of the
different hierarchy views and full api listing. If ``self.root_directory`` is
not a current directory, it is created first. Afterward, the root API file is
created and its title is written, as well as the value of
``configs.afterTitleDescription``.
'''
try:
# TODO: update to pathlib everywhere...
root_directory_path = Path(self.root_directory)
Expand All @@ -2307,6 +2283,26 @@ def generateAPIRootHeader(self):
utils.fancyError(
"Cannot create the directory {0} {1}".format(self.root_directory, e)
)
# TODO: API root body does not need to be separate, but it does need to happen
# after node documents are generated due to bad design (link names and other
# items get initialized). Or at least that's what I remember.
skip_root = self.root_file_name == "EXCLUDE"
if not skip_root:
self.generateAPIRootHeader()
self.generateNodeDocuments()
self.gerrymanderNodeFilenames()
self.generateViewHierarchies()
self.generateUnabridgedAPI()
if not skip_root:
self.generateAPIRootBody()

def generateAPIRootHeader(self):
'''
This method creates the root library api file that will include all of the
different hierarchy views and full api listing. The root API file is created
and its title is written, as well as the value of
``configs.afterTitleDescription``.
'''
try:
with codecs.open(self.full_root_file_path, "w", "utf-8") as generated_index:
# Add the metadata if they requested it
Expand Down Expand Up @@ -3613,9 +3609,7 @@ def generateAPIRootBody(self):
conditionally use a ``toctree`` if you really need it.
'''
try:
self.gerrymanderNodeFilenames()
self.generateViewHierarchies()
self.generateUnabridgedAPI()

with codecs.open(self.full_root_file_path, "a", "utf-8") as generated_index:
# Include index page, if present
for page in self.pages:
Expand Down

0 comments on commit 9a6138e

Please sign in to comment.