From fbffd22d7e918013ad108949a49048e4e652afe9 Mon Sep 17 00:00:00 2001 From: Felix Fontein Date: Wed, 23 Jun 2021 22:36:54 +0200 Subject: [PATCH] Use RST roles for formatting. --- antsibull/jinja2/filters.py | 27 +++++------- antsibull/lint_extra_docs.py | 11 +++++ sphinx_antsibull_ext/__init__.py | 4 ++ sphinx_antsibull_ext/roles.py | 71 ++++++++++++++++++++++++++++++++ 4 files changed, 97 insertions(+), 16 deletions(-) create mode 100644 sphinx_antsibull_ext/roles.py diff --git a/antsibull/jinja2/filters.py b/antsibull/jinja2/filters.py index 4fe83b486..aa7f29f8f 100644 --- a/antsibull/jinja2/filters.py +++ b/antsibull/jinja2/filters.py @@ -31,10 +31,10 @@ def _option_name_html(matcher): - parts = matcher.group(1).split('=', 1) - if len(parts) == 1: - return f'{parts[0]}' - return f'{parts[0]}={parts[1]}' + text = matcher.group(1) + if '=' not in text and ':' not in text: + return f'{text}' + return f'{text}' def html_ify(text): @@ -56,8 +56,10 @@ def html_ify(text): text, _counts['link'] = _LINK.subn(r"\1", text) text, _counts['const'] = _CONST.subn(r"\1", text) text, _counts['option-name'] = _SEM_OPTION_NAME.subn(_option_name_html, text) - text, _counts['option-value'] = _SEM_OPTION_VALUE.subn(r"\1", text) - text, _counts['environment-var'] = _SEM_ENV_VARIABLE.subn(r"\1", text) + text, _counts['option-value'] = _SEM_OPTION_VALUE.subn( + r"""\1""", text) + text, _counts['environment-var'] = _SEM_ENV_VARIABLE.subn( + r"""\1""", text) text, _counts['ruler'] = _RULER.subn(r"
", text) text = text.strip() @@ -87,13 +89,6 @@ def do_max(seq): return max(seq) -def _option_name_rst(matcher): - parts = matcher.group(1).split('=', 1) - if len(parts) == 1: - return f'*{parts[0]}*' - return f'*{parts[0]}* |equalsign| ``{parts[1]}``' - - def rst_ify(text): ''' convert symbols like I(this is in italics) to valid restructured text ''' @@ -111,9 +106,9 @@ def rst_ify(text): text, _counts['ref'] = _URL.subn(r"\1", text) text, _counts['link'] = _REF.subn(r":ref:`\1 <\2>`", text) text, _counts['const'] = _CONST.subn(r"``\1``", text) - text, _counts['option-name'] = _SEM_OPTION_NAME.subn(_option_name_rst, text) - text, _counts['option-value'] = _SEM_OPTION_VALUE.subn(r"``\1``", text) - text, _counts['environment-var'] = _SEM_ENV_VARIABLE.subn(r"``\1``", text) + text, _counts['option-name'] = _SEM_OPTION_NAME.subn(r":ansopt:`\1`", text) + text, _counts['option-value'] = _SEM_OPTION_VALUE.subn(r":ansval:`\1`", text) + text, _counts['environment-var'] = _SEM_ENV_VARIABLE.subn(r":envvar:`\1`", text) text, _counts['ruler'] = _RULER.subn(f"\n\n{'-' * 13}\n\n", text) flog.fields(counts=_counts).info('Number of macros converted to rst equivalents') diff --git a/antsibull/lint_extra_docs.py b/antsibull/lint_extra_docs.py index 337277ec7..ec5d21391 100644 --- a/antsibull/lint_extra_docs.py +++ b/antsibull/lint_extra_docs.py @@ -11,6 +11,10 @@ import docutils.utils import rstcheck +from docutils.parsers.rst import roles as docutils_roles + +from sphinx_antsibull_ext import roles as antsibull_roles + from .extra_docs import ( find_extra_docs, lint_required_conditions, @@ -46,6 +50,12 @@ def lint_optional_conditions(content: str, path: str, collection_name: str return [(result[0], 0, result[1]) for result in results] +def _setup_rstcheck(): + '''Make sure that rstcheck knows about our roles.''' + for name, role in antsibull_roles.ROLES.items(): + docutils_roles.register_local_role(name, role) + + def lint_collection_extra_docs_files(path_to_collection: str ) -> t.List[t.Tuple[str, int, int, str]]: try: @@ -56,6 +66,7 @@ def lint_collection_extra_docs_files(path_to_collection: str result = [] all_labels = set() docs = find_extra_docs(path_to_collection) + _setup_rstcheck() for doc in docs: try: # Load content diff --git a/sphinx_antsibull_ext/__init__.py b/sphinx_antsibull_ext/__init__.py index a7cf7ca1c..c6e3cce70 100644 --- a/sphinx_antsibull_ext/__init__.py +++ b/sphinx_antsibull_ext/__init__.py @@ -15,6 +15,7 @@ from .assets import setup_assets +from .roles import setup_roles def setup(app): @@ -26,6 +27,9 @@ def setup(app): # Add assets setup_assets(app) + # Add roles + setup_roles(app) + return dict( parallel_read_safe=True, parallel_write_safe=True, diff --git a/sphinx_antsibull_ext/roles.py b/sphinx_antsibull_ext/roles.py new file mode 100644 index 000000000..a7b3a47f3 --- /dev/null +++ b/sphinx_antsibull_ext/roles.py @@ -0,0 +1,71 @@ +# coding: utf-8 +# Author: Felix Fontein +# License: GPLv3+ +# Copyright: Ansible Project, 2021 +''' +Add roles for semantic markup. +''' + +from __future__ import (absolute_import, division, print_function) + + +from docutils import nodes + + +def option_role(name, rawtext, text, lineno, inliner, options={}, content=[]): + """Format Ansible option key, or option key-value. + + Returns 2 part tuple containing list of nodes to insert into the + document and a list of system messages. Both are allowed to be + empty. + + :param name: The role name used in the document. + :param rawtext: The entire markup snippet, with role. + :param text: The text marked with the role. + :param lineno: The line number where rawtext appears in the input. + :param inliner: The inliner instance that called us. + :param options: Directive options for customization. + :param content: The directive content for customization. + """ + children = [] + classes = [] + if '=' not in text and ':' not in text: + children.append(nodes.strong(rawtext, text)) + rawtext = '' + text = '' + classes.append('ansible-option') + else: + classes.append('ansible-option-value') + return [nodes.literal(rawtext, text, *children, classes=classes)], [] + + +def value_role(name, rawtext, text, lineno, inliner, options={}, content=[]): + """Format Ansible option value. + + Returns 2 part tuple containing list of nodes to insert into the + document and a list of system messages. Both are allowed to be + empty. + + :param name: The role name used in the document. + :param rawtext: The entire markup snippet, with role. + :param text: The text marked with the role. + :param lineno: The line number where rawtext appears in the input. + :param inliner: The inliner instance that called us. + :param options: Directive options for customization. + :param content: The directive content for customization. + """ + return [nodes.literal(rawtext, text, classes=['ansible-value'])], [] + + +ROLES = { + 'ansopt': option_role, + 'ansval': value_role, +} + + +def setup_roles(app): + ''' + Setup roles for a Sphinx app object. + ''' + for name, role in ROLES.items(): + app.add_role(name, role)