Create extension (custom role) [1] [2]
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:
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:
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"<span class=\"guilabel\">{text}</span>"
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:
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:
You can click the :unicode-guilabel:`ᐊ` and :unicode-guilabel:`ᐅ`
buttons to navigate.
translates into:
You can click the ᐊ and ᐅ buttons to navigate.
Full unicode_guilabel.py:
from docutils import nodes
def setup(app):
app.add_role('unicode-guilabel', unicode_guilabel_role)
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"<span class=\"guilabel\">{text}</span>"
node = nodes.raw("\n".join(content), html, format="html", **options)
return [node], []
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 🛈.
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):$ cd source $ mkdir _templates $ touch _templates/layout.html
If the directory is new, also add the templates to your
conf.pyto be considered when building the HTML:# 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.htmland mark it as the block extension (here: extrabody), so it looks like this:{% extends "!layout.html" %} {% block extrabody %} <link rel="stylesheet" media="screen" href="https://fontlibrary.org//face/symbola" type="text/css"/> {% endblock %}Open the custom.css and add the following content:
Hint
If using a different theme, check the originally used
font-familysetting for the guilabel role first and attachSymbolaRegularas the last option..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.