# SPDX-License-Identifier: MIT # # Copyright (c) 2020 Philippe Proulx # # This file is a Sphinx extension which adds the following roles: # # `bt2man`: # A typical manual page reference, like `grep(1)`. # # Example: # # :bt2man:`grep(1)` # # This role creates a simple inline literal node with the role's # text if it's not a Babeltrace 2 manual page reference, or an # external link to the corresponding online manual page (on # `babeltrace.org`) with the appropriate project's version # (`version` configuration entry) otherwise. # # `bt2link`: # An external link with an URL in which a specific placeholder is # replaced with the project's version. # # The role's text follows the typical external link format, for # example: # # Link text # # Any `@ver@` in the URL is replaced with the project's version # (`version` configuration entry). # # Example: # # :bt2link:`libbabeltrace2 ` import docutils import docutils.utils import docutils.nodes import re import functools def _bt2man_role( bt2_version, name, rawtext, text, lineno, inliner, options=None, content=None ): # match a manual page reference m = re.match(r'^([a-zA-Z0-9_.:-]+)\(([a-zA-Z0-9]+)\)$', text) if not m: msg = 'Cannot parse manual page reference `{}`'.format(text) inliner.reporter.severe(msg, line=lineno) return [inliner.problematic(rawtext, rawtext, msg)], [msg] # matched manual page and volume page = m.group(1) vol = m.group(2) # create nodes: `ret_node` is the node to return page_node = docutils.nodes.strong(rawtext, page) vol_node = docutils.nodes.inline(rawtext, '({})'.format(vol)) man_node = docutils.nodes.inline(rawtext, '', page_node, vol_node) ret_node = docutils.nodes.literal(rawtext, '', man_node) if page.startswith('babeltrace2'): # Babeltrace 2 manual page: wrap `ret_node` with an external # link node url_tmpl = 'https://babeltrace.org/docs/v{ver}/man{vol}/{page}.{vol}/' url = url_tmpl.format(ver=bt2_version, vol=vol, page=page) ret_node = docutils.nodes.reference( rawtext, '', ret_node, internal=False, refuri=url ) return [ret_node], [] def _bt2link_role( bt2_version, name, rawtext, text, lineno, inliner, options=None, content=None ): # match link text and URL m = re.match(r'^([^<]+) <([^>]+)>$', text) if not m: msg = 'Cannot parse link template `{}`'.format(text) inliner.reporter.severe(msg, line=lineno) return [inliner.problematic(rawtext, rawtext, msg)], [msg] link_text = m.group(1) # replace `@ver@` with the project's version url = m.group(2).replace('@ver@', bt2_version) # create and return an external link node node = docutils.nodes.reference(rawtext, link_text, internal=False, refuri=url) return [node], [] def _add_roles(app): # add the extension's roles; the role functions above expect the # project's version as their first parameter app.add_role('bt2man', functools.partial(_bt2man_role, app.config.version)) app.add_role('bt2link', functools.partial(_bt2link_role, app.config.version)) def setup(app): app.connect('builder-inited', _add_roles) return { 'version': app.config.version, 'parallel_read_safe': True, }