""" Original Cond logic derived from https://github.com/mongodb/docs-tools/blob/master/sphinxext/fixed_only.py Original Only logic derived from https://github.com/sphinx-doc/sphinx/blob/5.x/sphinx/directives/other.py#L289, under the BSD license """ from docutils import nodes from docutils.nodes import Element, Node from docutils.parsers.rst import Directive, directives from sphinx.util.docutils import SphinxDirective from sphinx.util.nodes import nested_parse_with_titles, set_source_info, Node from typing import TYPE_CHECKING, Any, Dict, List, cast # Keeping this in case we need it later, but assuming everything works as expected, we can probably drop this entirely class Cond(Directive): """ Directive to only include text if the given tag(s) are enabled. """ has_content = True required_arguments = 1 optional_arguments = 0 final_argument_whitespace = True option_spec = {} def run(self): config = self.state.document.settings.env.config try: result = config._raw_config['tags'].eval_condition(self.arguments[0]) except ValueError as err: raise self.severe(u'Error parsing conditional parsing expression: {}'.format(str(err))) if result: node = nodes.Element() set_source_info(self, node) nested_parse_with_titles(self.state, self.content, node) return node.children return [] class CondPlus(SphinxDirective): """ Directive to only include text if the given tag(s) are enabled. """ has_content = True required_arguments = 1 optional_arguments = 0 final_argument_whitespace = True option_spec = {} def run(self): config = self.state.document.settings.env.config try: result = config._raw_config['tags'].eval_condition(self.arguments[0]) except ValueError as err: raise self.severe(u'Error parsing conditional parsing expression: {}'.format(str(err))) if not result: # early exit if we know there's no match return [] # 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 node = Element() node.document = self.state.document set_source_info(self, node) 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.children current_depth = 0 parent = self.state.parent while parent: current_depth +=1 parent = parent.parent # This should stop at the "Title" element # Accounts for the "Title" element? # Adding a debug just in case this runs negative - unsure when or why or how that would happen current_depth -= 2 if (current_depth < 0): print("Negative Depth" + str(current_depth)) # Grabbing the decorator for the title 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) # This should give us the number of heading levels to pop up, effectively n_sects_to_raise = current_depth - nested_depth + 1 # Resetting parent parent = cast(Element, self.state.parent) for i in range (n_sects_to_raise): if parent.parent: parent = parent.parent parent.extend(node) # for i in node: # parent.append(i) finally: memo.title_styles = surrounding_title_styles memo.section_level = surrounding_section_level # Actual work is done by extending the correct parent node, so we can return an empty list. return [] def setup(app): #directives.register_directive('cond', Cond) # If everything works as expected, we can rename CondPlus to Cond or "Conditional" or something like that. directives.register_directive('cond', CondPlus) return { 'parallel_read_safe': True, 'parallel_write_safe': True, }