| 1 | # SPDX-License-Identifier: MIT |
| 2 | # |
| 3 | # Copyright (c) 2020 Philippe Proulx <pproulx@efficios.com> |
| 4 | # |
| 5 | # This file is a Sphinx extension which adds the following roles: |
| 6 | # |
| 7 | # `bt2man`: |
| 8 | # A typical manual page reference, like `grep(1)`. |
| 9 | # |
| 10 | # Example: |
| 11 | # |
| 12 | # :bt2man:`grep(1)` |
| 13 | # |
| 14 | # This role creates a simple inline literal node with the role's |
| 15 | # text if it's not a Babeltrace 2 manual page reference, or an |
| 16 | # external link to the corresponding online manual page (on |
| 17 | # `babeltrace.org`) with the appropriate project's version |
| 18 | # (`version` configuration entry) otherwise. |
| 19 | # |
| 20 | # `bt2link`: |
| 21 | # An external link with an URL in which a specific placeholder is |
| 22 | # replaced with the project's version. |
| 23 | # |
| 24 | # The role's text follows the typical external link format, for |
| 25 | # example: |
| 26 | # |
| 27 | # Link text <https://example.com/> |
| 28 | # |
| 29 | # Any `@ver@` in the URL is replaced with the project's version |
| 30 | # (`version` configuration entry). |
| 31 | # |
| 32 | # Example: |
| 33 | # |
| 34 | # :bt2link:`libbabeltrace2 <https://babeltrace.org/docs/v@ver@/libbabeltrace2/>` |
| 35 | |
| 36 | import docutils |
| 37 | import docutils.utils |
| 38 | import docutils.nodes |
| 39 | import re |
| 40 | import functools |
| 41 | |
| 42 | |
| 43 | def _bt2man_role( |
| 44 | bt2_version, name, rawtext, text, lineno, inliner, options=None, content=None |
| 45 | ): |
| 46 | # match a manual page reference |
| 47 | m = re.match(r'^([a-zA-Z0-9_.:-]+)\(([a-zA-Z0-9]+)\)$', text) |
| 48 | |
| 49 | if not m: |
| 50 | msg = 'Cannot parse manual page reference `{}`'.format(text) |
| 51 | inliner.reporter.severe(msg, line=lineno) |
| 52 | return [inliner.problematic(rawtext, rawtext, msg)], [msg] |
| 53 | |
| 54 | # matched manual page and volume |
| 55 | page = m.group(1) |
| 56 | vol = m.group(2) |
| 57 | |
| 58 | # create nodes: `ret_node` is the node to return |
| 59 | page_node = docutils.nodes.strong(rawtext, page) |
| 60 | vol_node = docutils.nodes.inline(rawtext, '({})'.format(vol)) |
| 61 | man_node = docutils.nodes.inline(rawtext, '', page_node, vol_node) |
| 62 | ret_node = docutils.nodes.literal(rawtext, '', man_node) |
| 63 | |
| 64 | if page.startswith('babeltrace2'): |
| 65 | # Babeltrace 2 manual page: wrap `ret_node` with an external |
| 66 | # link node |
| 67 | url_tmpl = 'https://babeltrace.org/docs/v{ver}/man{vol}/{page}.{vol}/' |
| 68 | url = url_tmpl.format(ver=bt2_version, vol=vol, page=page) |
| 69 | ret_node = docutils.nodes.reference( |
| 70 | rawtext, '', ret_node, internal=False, refuri=url |
| 71 | ) |
| 72 | |
| 73 | return [ret_node], [] |
| 74 | |
| 75 | |
| 76 | def _bt2link_role( |
| 77 | bt2_version, name, rawtext, text, lineno, inliner, options=None, content=None |
| 78 | ): |
| 79 | # match link text and URL |
| 80 | m = re.match(r'^([^<]+) <([^>]+)>$', text) |
| 81 | |
| 82 | if not m: |
| 83 | msg = 'Cannot parse link template `{}`'.format(text) |
| 84 | inliner.reporter.severe(msg, line=lineno) |
| 85 | return [inliner.problematic(rawtext, rawtext, msg)], [msg] |
| 86 | |
| 87 | link_text = m.group(1) |
| 88 | |
| 89 | # replace `@ver@` with the project's version |
| 90 | url = m.group(2).replace('@ver@', bt2_version) |
| 91 | |
| 92 | # create and return an external link node |
| 93 | node = docutils.nodes.reference(rawtext, link_text, internal=False, refuri=url) |
| 94 | return [node], [] |
| 95 | |
| 96 | |
| 97 | def _add_roles(app): |
| 98 | # add the extension's roles; the role functions above expect the |
| 99 | # project's version as their first parameter |
| 100 | app.add_role('bt2man', functools.partial(_bt2man_role, app.config.version)) |
| 101 | app.add_role('bt2link', functools.partial(_bt2link_role, app.config.version)) |
| 102 | |
| 103 | |
| 104 | def setup(app): |
| 105 | app.connect('builder-inited', _add_roles) |
| 106 | return { |
| 107 | 'version': app.config.version, |
| 108 | 'parallel_read_safe': True, |
| 109 | } |