Composing roles in reStructuredText
Asked Answered
H

4

3

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``
Harlen answered 29/6, 2017 at 15:39 Comment(0)
N
4

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.

Additional details

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().
Nomography answered 29/6, 2017 at 17:41 Comment(1)
See also docutils.sourceforge.net/…Conjugated
E
3

(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.

Emsmus answered 20/8, 2021 at 17:0 Comment(0)
O
3

In 2023, this is "possible" in a way.

Inspired by @Matthew's answer, I wrote a Sphinx extension for this, which can:

  • Dynamic creating roles that composited by multiple roles
  • Make interpreted text of role can be parsed (a.k.a. "nested parse")

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.

Oina answered 1/1, 2024 at 9:57 Comment(0)
F
0

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>
Felisafelise answered 10/1, 2024 at 21:3 Comment(0)

© 2022 - 2025 — McMap. All rights reserved.