|
# extension testbed |
|
|
|
import re |
|
|
|
from docutils import nodes |
|
from docutils.nodes import Element, Node |
|
from sphinx.util.docutils import SphinxDirective |
|
from sphinx.writers.html5 import HTML5Translator |
|
|
|
|
|
class CodeBlockCalloutsDirective(SphinxDirective): |
|
has_content = True |
|
|
|
def run(self) -> list[Node]: |
|
node = nodes.container() |
|
node.document = self.state.document |
|
self.state.nested_parse(self.content, self.content_offset, node) |
|
if len(node.children) != 1 or not isinstance(node.children[0], nodes.enumerated_list): |
|
logger.warning(__('The content of code-block-callouts should be an enumerated list'), |
|
location=(self.env.docname, self.lineno)) |
|
return [] |
|
|
|
node.children[0]['classes'].append('code-block-callouts') |
|
|
|
return node.children |
|
|
|
|
|
class CodeBlockCalloutsHTMLTranslator(HTML5Translator): |
|
def visit_literal_block(self, node: Element) -> None: |
|
if node.rawsource != node.astext(): |
|
# most probably a parsed-literal block -- don't highlight |
|
return super().visit_literal_block(node) |
|
|
|
lang = node.get('language', 'default') |
|
linenos = node.get('linenos', False) |
|
highlight_args = node.get('highlight_args', {}) |
|
highlight_args['force'] = node.get('force', False) |
|
opts = self.config.highlight_options.get(lang, {}) |
|
|
|
if linenos and self.config.html_codeblock_linenos_style: |
|
linenos = self.config.html_codeblock_linenos_style |
|
|
|
highlighted = self.highlighter.highlight_block( |
|
node.rawsource, lang, opts=opts, linenos=linenos, |
|
location=node, **highlight_args |
|
) |
|
|
|
# additional line |
|
highlighted = re.sub(r'<span class="c1"># (\d+)</span>', r'<span class="code-block-callouts"><span>\1</span></span>', highlighted) |
|
|
|
starttag = self.starttag(node, 'div', suffix='', |
|
CLASS='highlight-%s notranslate' % lang) |
|
self.body.append(starttag + highlighted + '</div>\n') |
|
raise nodes.SkipNode |
|
|
|
|
|
def setup(app): |
|
app.add_directive('code-block-callouts', CodeBlockCalloutsDirective) |
|
app.set_translator('html', CodeBlockCalloutsHTMLTranslator) |
|
|
|
return { |
|
'version': 'builtin', |
|
'parallel_read_safe': True, |
|
'parallel_write_safe': True, |
|
} |
Result: