Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Composing roles in reStructuredText

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``
like image 321
brannerchinese Avatar asked Jan 22 '26 12:01

brannerchinese


2 Answers

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().
like image 145
marbu Avatar answered Jan 25 '26 09:01

marbu


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

like image 37
Matthew Avatar answered Jan 25 '26 10:01

Matthew



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!