diff --git a/docs/conf.py b/docs/conf.py index 17c8970ab08..56cfae3624c 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -85,7 +85,9 @@ html_theme_options = { html_context = { 'current_language': 'English', - 'languages': (('English', '/latest'), ('Chinese', '/cn/latest')) + 'languages': (('English', '/latest'), ('Chinese', '/cn/latest')), + 'doxygen_mapping_file': '@DOXYGEN_MAPPING_FILE@', + 'doxygen_snippet_root': '@OpenVINO_SOURCE_DIR@' } repositories = { diff --git a/docs/openvino_sphinx_theme/MANIFEST.in b/docs/openvino_sphinx_theme/MANIFEST.in index bfbf945b216..52f927ccc27 100644 --- a/docs/openvino_sphinx_theme/MANIFEST.in +++ b/docs/openvino_sphinx_theme/MANIFEST.in @@ -1,3 +1,5 @@ include openvino_sphinx_theme/theme.conf recursive-include openvino_sphinx_theme *.html *.rst +recursive-include openvino_sphinx_theme/templates *.html *.rst recursive-include openvino_sphinx_theme/static *.js *.png *.css *.svg +recursive-include openvino_sphinx_theme/directives *.py diff --git a/docs/openvino_sphinx_theme/openvino_sphinx_theme/__init__.py b/docs/openvino_sphinx_theme/openvino_sphinx_theme/__init__.py index ddc231ddf49..208ac69066e 100644 --- a/docs/openvino_sphinx_theme/openvino_sphinx_theme/__init__.py +++ b/docs/openvino_sphinx_theme/openvino_sphinx_theme/__init__.py @@ -1,12 +1,15 @@ import os import sys +import json +from json import JSONDecodeError from sphinx.errors import ExtensionError import jinja2 +from docutils.parsers import rst from pathlib import Path from bs4 import BeautifulSoup as bs from sphinx.util import logging from pydata_sphinx_theme import index_toctree - +from .directives.code import DoxygenSnippet SPHINX_LOGGER = logging.getLogger(__name__) @@ -15,7 +18,7 @@ def setup_edit_url(app, pagename, templatename, context, doctree): """Add a function that jinja can access for returning the edit URL of a page.""" def has_github_page(): - doxygen_mapping_file = app.config['doxygen_mapping_file'] + doxygen_mapping_file = app.config.html_context.get('doxygen_mapping_file') name = pagename.rsplit('-')[0] if name in doxygen_mapping_file: return True @@ -46,7 +49,7 @@ def setup_edit_url(app, pagename, templatename, context, doctree): url_template = '{{ github_url }}/{{ github_user }}/{{ github_repo }}' \ '/edit/{{ github_version }}/{{ doc_path }}{{ file_name }}' - doxygen_mapping_file = app.config['doxygen_mapping_file'] + doxygen_mapping_file = app.config.html_context.get('doxygen_mapping_file') rst_name = pagename.rsplit('-')[0] file_name = doxygen_mapping_file[rst_name] parent_folder = Path(os.path.dirname(file_name)).parts[0] @@ -126,10 +129,9 @@ def _add_collapse_checkboxes(soup, open_first=False): # (by checking the checkbox) if "current" in classes or (open_first and toctree_checkbox_count == 1): checkbox.attrs["checked"] = "" - - element.insert(1, checkbox) + def add_toctree_functions(app, pagename, templatename, context, doctree): # override pydata_sphinx_theme @@ -208,10 +210,18 @@ def add_toctree_functions(app, pagename, templatename, context, doctree): return out - context["generate_sidebar_nav"] = generate_sidebar_nav +def read_doxygen_configs(app, env, docnames): + if app.config.html_context.get('doxygen_mapping_file'): + try: + with open(app.config.html_context.get('doxygen_mapping_file'), 'r', encoding='utf-8') as f: + app.config.html_context['doxygen_mapping_file'] = json.load(f) + except (JSONDecodeError, FileNotFoundError): + app.config.html_context['doxygen_mapping_file'] = dict() + + def setup(app): theme_path = get_theme_path() templates_path = os.path.join(theme_path, 'templates') @@ -220,5 +230,7 @@ def setup(app): app.config.html_static_path.append(static_path) app.connect("html-page-context", setup_edit_url, priority=sys.maxsize) app.connect("html-page-context", add_toctree_functions) + app.connect('env-before-read-docs', read_doxygen_configs) app.add_html_theme('openvino_sphinx_theme', theme_path) + rst.directives.register_directive('doxygensnippet', DoxygenSnippet) return {'parallel_read_safe': True, 'parallel_write_safe': True} diff --git a/docs/openvino_sphinx_theme/openvino_sphinx_theme/directives/__init__.py b/docs/openvino_sphinx_theme/openvino_sphinx_theme/directives/__init__.py new file mode 100644 index 00000000000..e69de29bb2d diff --git a/docs/openvino_sphinx_theme/openvino_sphinx_theme/directives/code.py b/docs/openvino_sphinx_theme/openvino_sphinx_theme/directives/code.py new file mode 100644 index 00000000000..ba4412d92ab --- /dev/null +++ b/docs/openvino_sphinx_theme/openvino_sphinx_theme/directives/code.py @@ -0,0 +1,76 @@ +import os.path + +from sphinx.directives.code import LiteralInclude, LiteralIncludeReader, container_wrapper +from sphinx.util import logging +from docutils.parsers.rst import directives +from typing import List, Tuple +from docutils.nodes import Node +from docutils import nodes +from sphinx.util import parselinenos + +logger = logging.getLogger(__name__) + + +class DoxygenSnippet(LiteralInclude): + + option_spec = dict({'fragment': directives.unchanged_required}, **LiteralInclude.option_spec) + + def run(self) -> List[Node]: + if 'fragment' in self.options: + self.options['start-after'] = self.options['fragment'] + self.options['end-before'] = self.options['fragment'] + document = self.state.document + if not document.settings.file_insertion_enabled: + return [document.reporter.warning('File insertion disabled', + line=self.lineno)] + # convert options['diff'] to absolute path + if 'diff' in self.options: + _, path = self.env.relfn2path(self.options['diff']) + self.options['diff'] = path + + try: + location = self.state_machine.get_source_and_line(self.lineno) + doxygen_snippet_root = self.config.html_context.get('doxygen_snippet_root') + + if doxygen_snippet_root and os.path.exists(doxygen_snippet_root): + rel_filename = self.arguments[0] + filename = os.path.join(doxygen_snippet_root, rel_filename) + else: + rel_filename, filename = self.env.relfn2path(self.arguments[0]) + self.env.note_dependency(rel_filename) + + reader = LiteralIncludeReader(filename, self.options, self.config) + text, lines = reader.read(location=location) + + retnode = nodes.literal_block(text, text, source=filename) # type: Element + retnode['force'] = 'force' in self.options + self.set_source_info(retnode) + if self.options.get('diff'): # if diff is set, set udiff + retnode['language'] = 'udiff' + elif 'language' in self.options: + retnode['language'] = self.options['language'] + if ('linenos' in self.options or 'lineno-start' in self.options or + 'lineno-match' in self.options): + retnode['linenos'] = True + retnode['classes'] += self.options.get('class', []) + extra_args = retnode['highlight_args'] = {} + if 'emphasize-lines' in self.options: + hl_lines = parselinenos(self.options['emphasize-lines'], lines) + if any(i >= lines for i in hl_lines): + logger.warning(__('line number spec is out of range(1-%d): %r') % + (lines, self.options['emphasize-lines']), + location=location) + extra_args['hl_lines'] = [x + 1 for x in hl_lines if x < lines] + extra_args['linenostart'] = reader.lineno_start + + if 'caption' in self.options: + caption = self.options['caption'] or self.arguments[0] + retnode = container_wrapper(self, retnode, caption) + + # retnode will be note_implicit_target that is linked from caption and numref. + # when options['name'] is provided, it should be primary ID. + self.add_name(retnode) + + return [retnode] + except Exception as exc: + return [document.reporter.warning(exc, line=self.lineno)]