Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Allow emphasising placeholders in option directives #10366

Merged
merged 3 commits into from Jun 16, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
3 changes: 3 additions & 0 deletions CHANGES
Expand Up @@ -16,6 +16,9 @@ Deprecated
Features added
--------------

* #10366: std domain: Add support for emphasising placeholders in :rst:dir`option`
directives through a new ``option_emphasise_placeholders`` configuration option.

Bugs fixed
----------

Expand Down
9 changes: 9 additions & 0 deletions doc/usage/configuration.rst
Expand Up @@ -706,6 +706,15 @@ General configuration

.. versionadded:: 3.0

.. confval:: option_emphasise_placeholders

Default is ``False``.
When enabled, emphasise placeholders in ``.. option:`` directives.
To display literal braces, escape with a backslash (``\{``). For example,
``option_emphasise_placeholders=True`` and ``.. option:: -foption={TYPE}`` would
render with ``TYPE`` emphasised.

.. versionadded:: 5.1

.. _intl-options:

Expand Down
3 changes: 3 additions & 0 deletions doc/usage/restructuredtext/domains.rst
Expand Up @@ -1750,6 +1750,9 @@ There is a set of directives allowing documenting command-line programs:
referenceable by :rst:role:`option` (in the example case, you'd use something
like ``:option:`dest_dir```, ``:option:`-m```, or ``:option:`--module```).

Use :confval:`option_emphasise_placeholders` for parsing of
"variable part" of a literal text (similarly to the ``samp`` role).

``cmdoption`` directive is a deprecated alias for the ``option`` directive.

.. rst:directive:: .. envvar:: name
Expand Down
1 change: 1 addition & 0 deletions sphinx/config.py
Expand Up @@ -140,6 +140,7 @@ class Config:
'smartquotes_excludes': ({'languages': ['ja'],
'builders': ['man', 'text']},
'env', []),
'option_emphasise_placeholders': (False, 'env', []),
}

def __init__(self, config: Dict[str, Any] = {}, overrides: Dict[str, Any] = {}) -> None:
Expand Down
36 changes: 32 additions & 4 deletions sphinx/domains/std.py
Expand Up @@ -15,7 +15,7 @@
from sphinx.directives import ObjectDescription
from sphinx.domains import Domain, ObjType
from sphinx.locale import _, __
from sphinx.roles import XRefRole
from sphinx.roles import EmphasizedLiteral, XRefRole
from sphinx.util import docname_join, logging, ws_re
from sphinx.util.docutils import SphinxDirective
from sphinx.util.nodes import clean_astext, make_id, make_refnode
Expand All @@ -34,6 +34,8 @@
# RE for grammar tokens
token_re = re.compile(r'`((~?\w*:)?\w+)`', re.U)

samp_role = EmphasizedLiteral()


class GenericObject(ObjectDescription[str]):
"""
Expand Down Expand Up @@ -170,15 +172,41 @@ def handle_signature(self, sig: str, signode: desc_signature) -> str:
location=signode)
continue
optname, args = m.groups()
if optname.endswith('[') and args.endswith(']'):
if optname[-1] == '[' and args[-1] == ']':
# optional value surrounded by brackets (ex. foo[=bar])
optname = optname[:-1]
args = '[' + args

if count:
signode += addnodes.desc_addname(', ', ', ')
if self.env.config.option_emphasise_placeholders:
signode += addnodes.desc_sig_punctuation(',', ',')
signode += addnodes.desc_sig_space()
else:
signode += addnodes.desc_addname(', ', ', ')
signode += addnodes.desc_name(optname, optname)
signode += addnodes.desc_addname(args, args)
if self.env.config.option_emphasise_placeholders:
add_end_bracket = False
if not args:
continue
if args[0] == '[' and args[-1] == ']':
add_end_bracket = True
signode += addnodes.desc_sig_punctuation('[', '[')
args = args[1:-1]
if args[0] == ' ':
signode += addnodes.desc_sig_space()
args = args.strip()
if args[0] == '=':
signode += addnodes.desc_sig_punctuation('=', '=')
args = args[1:]
for part in samp_role.parse(args):
if isinstance(part, nodes.Text):
signode += nodes.Text(part.astext())
else:
signode += part
if add_end_bracket:
signode += addnodes.desc_sig_punctuation(']', ']')
else:
signode += addnodes.desc_addname(args, args)
if not count:
firstname = optname
signode['allnames'] = [optname]
Expand Down
9 changes: 9 additions & 0 deletions tests/roots/test-root/objects.txt
Expand Up @@ -194,6 +194,15 @@ Link to :option:`perl +p`, :option:`--ObjC++`, :option:`--plugin.option`, :optio

Link to :option:`hg commit` and :option:`git commit -p`.

.. option:: --abi={TYPE}

.. option:: --test={WHERE}-{COUNT}

.. option:: --wrap=\{\{value\}\}

.. option:: -allowable_client {client_name}

Foo bar.

User markup
===========
Expand Down
22 changes: 22 additions & 0 deletions tests/test_build_html.py
Expand Up @@ -1735,3 +1735,25 @@ def test_html_code_role(app):
assert ('<div class="highlight-python notranslate">' +
'<div class="highlight"><pre><span></span>' +
common_content) in content


@pytest.mark.sphinx('html', testroot='root',
confoverrides={'option_emphasise_placeholders': True})
def test_option_emphasise_placeholders(app, status, warning):
app.build()
content = (app.outdir / 'objects.html').read_text()
assert '<em><span class="pre">TYPE</span></em>' in content
assert '{TYPE}' not in content
assert ('<em><span class="pre">WHERE</span></em>'
'<span class="pre">-</span>'
'<em><span class="pre">COUNT</span></em>' in content)
assert '<span class="pre">{{value}}</span>' in content


@pytest.mark.sphinx('html', testroot='root')
def test_option_emphasise_placeholders_default(app, status, warning):
app.build()
content = (app.outdir / 'objects.html').read_text()
assert '<span class="pre">={TYPE}</span>' in content
assert '<span class="pre">={WHERE}-{COUNT}</span></span>' in content
assert '<span class="pre">{client_name}</span>' in content