.. _extend_sphinx_create_custom_role: Create extension (custom role) :footcite:p:`sphinx_role_extension_doug` :footcite:p:`sphinx_role_extension_thai` ================================================================================================================ In some cases, there is no adequate role available for your purpose, for instance, when nesting two roles. In such cases, adding an extension to your Sphinx project can overcome this limitation. In this example case, the `guilabel`_ role will be extended to support displaying a single unicode character, like a symbol, to describe buttons or GUI items which show such symbols instead of regular text. Create a new Python module in a proper location (e.g. ``./source/_ext/``). First off, we need to register our role in our Sphinx application: .. code-block:: python def setup(app): app.add_role("unicode-guilabel", unicode_guilabel_role) Here, we are adding the role *unicode-guilabel* and assign it to the function *unicode_guilabel_role*. Next, we need to define this role processor function. The docutils parser used by Sphinx converts the input text into tree, made up of different types of nodes. That tree is then parsed by a *writer* which creates the desired output format, hence your role processor function must return such a node, taking arguments describing the marked-up text: .. code-block:: python from docutils import nodes def unicode_guilabel_role(name, rawtext, text, lineno, inliner, options={}, content=[]): """Returns a guilabel node including a single unicode html-code""" if not text.startswith("&#"): msg = inliner.reporter.error("Wrong Unicode! " "Must start with '&#'.", line=lineno) prb = inliner.problematic(rawtext, rawtext, msg) return [msg], [prb] if not text.endswith(";"): msg = inliner.reporter.error("Wrong Unicode! " "Must end with ';'.", line=lineno) prb = inliner.problematic(rawtext, rawtext, msg) return [msg], [prb] html = f"{text}" node = nodes.raw("\n".join(content), html, format="html", **options) return [node], [] The arguments are expected in a certain order (see more under `Creating reStructuredText Interpreted Text Roles`_). The return value is a tuple containing two lists. The first list contains any new nodes to be added to the parse tree, the second list contains error or warning messages to show the user (processors are defined to return errors instead of raising exceptions because the error messages can be inserted into the output instead of halting all processing. In this example, the node itself is a `raw data node`_, which passes the node data as is. The nodes text is an HTML expression, wrapping a passed in *text* within a *guilabel* span assigned to the guilabel class. Lastly, your extension must be added to ``conf.py``: .. code-block:: python import sys import os sys.path.insert(0, os.path.abspath(".") + "/_ext") extensions = [ # your other extensions "unicode_guilabel" ] You can now use the new role like this: .. code-block:: rst You can click the :unicode-guilabel:`ᐊ` and :unicode-guilabel:`ᐅ` buttons to navigate. translates into: You can click the :unicode-guilabel:`ᐊ` and :unicode-guilabel:`ᐅ` buttons to navigate. Full ``unicode_guilabel.py``: .. literalinclude:: _file/unicode_guilabel.py .. warning:: It depends on the font, the used Sphinx theme (for example `sphinx-rtd-theme`_) uses, whether a symbols can be displayed. If the font does not include the symbol for a certain unicode character, it will be displayed as :raw-html:`🛈`. To overcome this limitation, the theme must use a backup font, that features most or all defined Unicode symbols. A possible candidate is the `Symbola`_ font. An older version (v9.00) is provided by the `Font Library`_ as a web font. To add it follow these steps: .. hint:: These steps proved to work for the *sphinx-rtd-theme*. If using a different theme, the ``layout.html`` or used Jinja blocks may be named differently. #. Inside the sphinx sources directory (for example ``source``) create a new directory for HTML templates (here: ``_templates``) and an empty template file (here: ``layout.html``): .. code-block:: bash $ cd source $ mkdir _templates $ touch _templates/layout.html If the directory is new, also add the templates to your ``conf.py`` to be considered when building the HTML: .. code-block:: python # Add any paths that contain templates here, relative to this directory. templates_path = ['_templates'] #. Copy the include HTML code (from the website's *Use this font* section) into ``layout.html`` and mark it as the block extension (here: *extrabody*), so it looks like this: .. code-block:: html {% extends "!layout.html" %} {% block extrabody %} {% endblock %} #. Open the `custom.css`_ and add the following content: .. hint:: If using a different theme, check the originally used ``font-family`` setting for the *guilabel* role first and attach ``SymbolaRegular`` as the last option. .. code-block:: css .guilabel { font-family: Lato,proxima-nova,Helvetica Neue,Arial,sans-serif,SymbolaRegular } #. Rebuild the documentation to see the new font being applied. .. hint:: A download for Symbola (v7.21) is available at https://fonts2u.com/symbola.font. .. footbibliography:: .. _guilabel: https://www.sphinx-doc.org/en/master/usage/restructuredtext/roles.html#role-guilabel .. _Creating reStructuredText Interpreted Text Roles: https://docutils.sourceforge.io/docs/howto/rst-roles.html .. _raw data node: https://pydoc.dev/docutils/latest/docutils.nodes.raw.html .. _sphinx-rtd-theme: https://github.com/readthedocs/sphinx_rtd_theme .. _Symbola: https://dn-works.com/wp-content/uploads/2023/UFAS010223/Symbola.pdf .. _Font Library: https://fontlibrary.org/en/font/symbola .. _custom.css: https://docs.readthedocs.io/en/stable/guides/adding-custom-css.html#how-to-add-custom-css-or-javascript-to-sphinx-documentation