I created a super small extention to add the role "icon" in my doc. The idea is to write down the following :
I'm a folder :icon:`fa fa-folder`
I adapted some code find online and came up with the following:
from docutils import nodes
def icon_role(name, rawtext, text, lineno, inliner, options={}, content=[]):
"""add inline icons
Returns 2 part tuple containing list of nodes to insert into the
document and a list of system messages. Both are allowed to be
empty.
:param name: The role name used in the document.
:param rawtext: The entire markup snippet, with role.
:param text: The text marked with the role.
:param lineno: The line number where rawtext appears in the input.
:param inliner: The inliner instance that called us.
:param options: Directive options for customization.
:param content: The directive content for customization.
"""
node =nodes.reference()
html = f"<i class=\"{text}\"></i>"
node = nodes.raw('', html, format='html')
return [node], []
def setup(app):
"""Install the plugin.
:param app: Sphinx application context.
"""
app.add_role('icon', icon_role)
return
The problem is that the role is not taken into account in my pdf output, it remains blank. Is there extra code I should add to make it work in latex as well ?
Based on what I found in the sphinx-contrib organization and in particular in the clever youtube sphinx extension, I coded a custom node
that will create the <i>
tag for the HTML output and a bold output for the latex one. It will of course need more work to display the icon in latex but that's not relevant here.
I leave the code here for anyone interested.
# -*- coding: utf-8 -*-
from docutils import nodes
class icon(nodes.General, nodes.Element):
"""A general node class that will be used in setup"""
pass
def depart_icon_node(self, node):
"""Empty depart function, everything is handled in visit functions"""
pass
def visit_icon_node_html(self, node):
"""entry point of the html node. we simply create a <i> tag"""
icon = node["icon"]
self.body.append(f"<i class=\"{icon}\"></i>")
return
def visit_icon_node_latex(self, node):
"""
entry point of the html node. we simply write down the text in bold.
See the linked repository for more complex macros and how to set them up in 'preamble'
"""
icon = node["icon"]
self.body.append("\\textbf{%s}" %(icon))
return
def visit_icon_node_unsuported(self, node):
"""raise error when the requested output is not supported"""
self.builder.warn(f'unsupported output format (node skipped)')
raise nodes.SkipNode
_NODE_VISITORS = {
'html': (visit_icon_node_html, depart_icon_node),
'latex': (visit_icon_node_latex, depart_icon_node),
'man': (visit_icon_node_unsuported, None), # don't need depart function because I raise an error
'texinfo': (visit_icon_node_unsuported, None), # same
'text': (visit_icon_node_unsuported, None) #same
}
def icon_role(name, rawtext, text, lineno, inliner, options={}, content=[]):
"""add inline icons"""
node = icon(icon=text)
return [node], []
def setup(app):
"""Install the plugin.
:param app: Sphinx application context.
"""
app.add_node(icon, **_NODE_VISITORS)
app.add_role('icon', icon_role)
return