Is there a way to compose standard text roles in reStructuredText? For instance, to format a string as both literal and strong?
The following do not do what I had hoped:
**``text``**
``**text**``
:strong:`:literal:`text``
:literal:`:strong:`text``
Is there a way to compose standard text roles in reStructuredText? For instance, to format a string as both literal and strong?
The following do not do what I had hoped:
**``text``**
``**text**``
:strong:`:literal:`text``
:literal:`:strong:`text``
No, this is not directly possible. Content passed into the function which implements the role (argument text
) is not further parsed.
See Creating reStructuredText Interpreted Text Roles.
That said, you could implement your own rst role which would parse the text further via nested_parse()
if you like - but that's not what are you asking about here.
Comment from docutils/docutils/parsers/rst/roles.py
suggests that the nested
parse feature you are asking about was/is planned/suggested, but hasn't been
implemented so far.
# Once nested inline markup is implemented, this and other methods should
# recursively call inliner.nested_parse().
(The following is hereby released under CC0.)
If you have the ability to extend the parser (e.g. if you are using Sphinx), you can add a custom role that parses its contents. (Note that this will work for simple things like bold/italic and substitutions, but will most likely fall on its face if you try to nest roles or such craziness.
I use this:
from docutils import nodes
from docutils.parsers.rst.states import Struct
def make_parsed_text_role(class_names=[], node_class=nodes.inline):
def parsed_text_role(name, rawtext, text, lineno, inliner,
options={}, content=[]):
# Prepare context for nested parsing
memo = Struct(document=inliner.document,
reporter=inliner.reporter,
language=inliner.language)
# Create parent node
options['classes'] = class_names
parent = node_class(rawtext, '', **options)
# Parse role text for markup and add to parent
processed, messages = inliner.parse(text, lineno, memo, parent)
parent += processed
# Return parent node, and any messages from nested parsing
return [parent], messages
return parsed_text_role
You can use this via a Sphinx conf.py
like so:
# Configuration file for the Sphinx documentation builder (conf.py).
project = 'My Documentation'
# ...
# ...paste the above code here...
def setup(app):
app.add_role('foo', make_parsed_text_role(class_names=['foo']))
In your documentation, this will let you write:
This is :foo:`some **bold** text`!
In HTML, this will produce a <span class="foo">
, at least for the default nodes.inline
node class. Use of the generator pattern is optional, but it's super-convenient if you want to make a whole bunch of these custom roles.
In 2023, this is "possible" in a way.
Inspired by @Matthew's answer, I wrote a Sphinx extension for this, which can:
First, download the extension from PyPI:
pip install sphinxnotes-comboroles
Then, add the extension name to the extensions configuration item in your conf.py:
extensions = [
# …
'sphinxnotes.comboroles',
# …
]
To create a “bold code” role, continue to add the following configuration, which tells the extension to composite roles strong
and literal
into a new role strong_literal
:
comboroles_roles = {
'strong_literal': ['strong', 'literal'],
}
Finally, you can see the rendered result here:
You can check https://sphinx.silverrainz.me/comboroles/index.html for more details.
An rST/CSS workaround using the "role" directive:
.. role:: strong-literal(literal)
:class: strong
This is :strong-literal:`literally strong`.
It requires custom CSS for correct rendering.
The following works in most browsers but does not validate
(<style>
is only allowed in the document head)
.. raw:: html
<style type="text/css"><!--
.strong {font-weight: bold;}
--></style>
© 2022 - 2025 — McMap. All rights reserved.