1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137
|
###############################################################################
# Top contributors (to current version):
# Gereon Kremer
#
# This file is part of the cvc5 project.
#
# Copyright (c) 2009-2025 by the authors listed in the file AUTHORS
# in the top-level source directory and their institutional affiliations.
# All rights reserved. See the file COPYING in the top-level source
# directory for licensing information.
# #############################################################################
#
# Sphinx extension, implements directive 'api-examples'.
##
import os
import re
from docutils import nodes
from docutils.statemachine import StringList
from sphinx.util import logging
from sphinx.util.docutils import SphinxDirective
class APIExamples(SphinxDirective):
"""Add directive `api-examples` to be used as follows:
.. api-examples::
file1
file2
The arguments should be proper filenames to source files.
This directives tries to detect the language from the file extension
and supports the file extensions specified in `examples_types`.
Additionally, `examples_file_patterns` allows to specify file name
patterns that allow using files from fixed directories more easily, and
to add proper download links.
examples_types:
'<regex>': {
'title': '<tab title>',
'lang': '<language identifier for syntax highlighting>',
'group': '<group identifier to detect missing examples>',
}
examples_file_patterns:
'<regex>': { # match groups are used to format the strings below
'local': '<pseudo-absolute path to local file>',
'url': '<url to download this file>', # optional
'urlname': '<text for the download link>',
}
"""
# The "arguments" are actually the content of the directive
has_content = True
option_spec = {
'skip': lambda x: [s.strip() for s in x.split(',')],
}
logger = logging.getLogger(__name__)
srcdir = None
def run(self):
self.state.document.settings.env.note_dependency(__file__)
# collect everything in a list of strings
content = ['.. tabs::', '']
remaining = set([t['group'] for t in self.env.config.examples_types.values()])
location = '{}:{}'.format(*self.get_source_info())
# remove skipped groups
skipped = set(self.options.get('skip', []))
remaining.difference_update(skipped)
for file in self.content:
# detect file extension
lang = None
title = None
for pattern,data in self.env.config.examples_types.items():
if re.search(pattern, file) != None:
lang = data['lang']
title = data['title']
remaining.discard(data['group'])
break
if lang == None:
self.logger.warning(
f'file type of {location} could not be detected')
title = os.path.splitext(file)[1]
lang = title
url = None
urlname = None
for k, v in self.env.config.examples_file_patterns.items():
m = re.match(k, file)
if m is not None:
file = v['local'].format(*m.groups())
if 'url' in v:
url = v['url'].format(*m.groups())
urlname = v['urlname'].format(*m.groups())
break
# generate tabs
content.append(f' .. tab:: {title}')
content.append(f'')
if url is not None:
# we can provide a download link
content.append(f' .. rst-class:: fa fa-download icon-margin')
content.append(f' ')
content.append(f' `{urlname} <{url}>`_')
content.append(f'')
content.append(f' .. literalinclude:: {file}')
content.append(f' :language: {lang}')
content.append(f' :linenos:')
for r in remaining:
self.logger.warning(f'{location} has no {r} example!')
# parse the string list
node = nodes.Element()
self.state.nested_parse(StringList(content), 0, node)
return node.children
def setup(app):
APIExamples.srcdir = app.srcdir
app.setup_extension('sphinx_tabs.tabs')
app.add_config_value('examples_types', {}, 'env')
app.add_config_value('examples_file_patterns', {}, 'env')
app.add_directive("api-examples", APIExamples)
return {
'version': '0.1',
'parallel_read_safe': True,
'parallel_write_safe': True,
}
|