Skip to content

Commit

Permalink
Use RST roles for formatting.
Browse files Browse the repository at this point in the history
  • Loading branch information
felixfontein committed Dec 16, 2021
1 parent 7b3cb4c commit a08259d
Show file tree
Hide file tree
Showing 4 changed files with 111 additions and 18 deletions.
43 changes: 25 additions & 18 deletions src/antsibull/jinja2/filters.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,10 +32,10 @@


def _option_name_html(matcher):
parts = matcher.group(1).split('=', 1)
if len(parts) == 1:
return f'<em>{parts[0]}</em>'
return f"<em>{parts[0]}</em>=<code class='docutils literal notranslate'>{parts[1]}</code>"
text = matcher.group(1)
if '=' not in text and ':' not in text:
return f'<code class="ansible-option literal notranslate"><strong>{text}</strong></code>'
return f'<code class="ansible-option-value literal notranslate">{text}</code>'


def html_ify(text):
Expand All @@ -59,9 +59,9 @@ def html_ify(text):
r"<code class='docutils literal notranslate'>\1</code>", text)
text, _counts['option-name'] = _SEM_OPTION_NAME.subn(_option_name_html, text)
text, _counts['option-value'] = _SEM_OPTION_VALUE.subn(
r"<code class='docutils literal notranslate'>\1</code>", text)
r"<code class='ansible-value literal notranslate'>\1</code>", text)
text, _counts['environment-var'] = _SEM_ENV_VARIABLE.subn(
r"<code class='docutils literal notranslate'>\1</code>", text)
r"<code class='xref std std-envvar literal notranslate'>\1</code>", text)
text, _counts['ruler'] = _RULER.subn(r"<hr/>", text)

text = text.strip()
Expand Down Expand Up @@ -96,15 +96,6 @@ def do_max(seq):
# https://docutils.sourceforge.io/docs/ref/rst/restructuredtext.html#character-level-inline-markup-1
# for further information.

def _option_name_rst(matcher):
parts = matcher.group(1).split('=', 1)
start = f"\\ :strong:`{rst_escape(parts[0], escape_ending_whitespace=True)}`\\ "
if len(parts) == 1:
return start
end = f"\\ :literal:`{rst_escape(parts[1], escape_ending_whitespace=True)}`\\ "
return f'{start}={end}'


def _rst_ify_italic(m):
return f"\\ :emphasis:`{rst_escape(m.group(1), escape_ending_whitespace=True)}`\\ "

Expand Down Expand Up @@ -141,6 +132,22 @@ def _rst_ify_const(m):
return f"\\ :literal:`{rst_escape(m.group(1), escape_ending_whitespace=True)}`\\ "


def _rst_ify_option_name(matcher):
return f"\\ :ansopt:`{rst_escape(m.group(1), escape_ending_whitespace=True)}`\\ "


def _rst_ify_value(matcher):
return f"\\ :ansval:`{rst_escape(m.group(1), escape_ending_whitespace=True)}`\\ "


def _rst_ify_option_name(matcher):
return f"\\ :ansopt:`{rst_escape(m.group(1), escape_ending_whitespace=True)}`\\ "


def _rst_ify_envvar(matcher):
return f"\\ :envvar:`{rst_escape(m.group(1), escape_ending_whitespace=True)}`\\ "


def rst_ify(text):
''' convert symbols like I(this is in italics) to valid restructured text '''

Expand All @@ -155,9 +162,9 @@ def rst_ify(text):
text, _counts['url'] = _URL.subn(_rst_ify_url, text)
text, _counts['ref'] = _REF.subn(_rst_ify_ref, text)
text, _counts['const'] = _CONST.subn(_rst_ify_const, text)
text, _counts['option-name'] = _SEM_OPTION_NAME.subn(_option_name_rst, text)
text, _counts['option-value'] = _SEM_OPTION_VALUE.subn(_rst_ify_const, text)
text, _counts['environment-var'] = _SEM_ENV_VARIABLE.subn(_rst_ify_const, text)
text, _counts['option-name'] = _SEM_OPTION_NAME.subn(_rst_ify_option_name, text)
text, _counts['option-value'] = _SEM_OPTION_VALUE.subn(_rst_ify_value, text)
text, _counts['environment-var'] = _SEM_ENV_VARIABLE.subn(_rst_ify_envvar, text)
text, _counts['ruler'] = _RULER.subn('\n\n.. raw:: html\n\n <hr>\n\n', text)

flog.fields(counts=_counts).info('Number of macros converted to rst equivalents')
Expand Down
11 changes: 11 additions & 0 deletions src/antsibull/lint_extra_docs.py
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down Expand Up @@ -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:
Expand All @@ -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
Expand Down
4 changes: 4 additions & 0 deletions src/sphinx_antsibull_ext/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@


from .assets import setup_assets
from .roles import setup_roles


def setup(app):
Expand All @@ -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,
Expand Down
71 changes: 71 additions & 0 deletions src/sphinx_antsibull_ext/roles.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
# coding: utf-8
# Author: Felix Fontein <[email protected]>
# 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)

0 comments on commit a08259d

Please sign in to comment.