Feature/ntyukaev/add doxygen snippet sphinx (#10277)

* add doxygensnippet directive

* update MANIFEST.in
This commit is contained in:
Nikolay Tyukaev
2022-02-11 09:19:46 +03:00
committed by GitHub
parent dedcbeafa8
commit 437bc3280d
5 changed files with 99 additions and 7 deletions

View File

@@ -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 = {

View File

@@ -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

View File

@@ -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}

View File

@@ -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)]