如何制作也是外部 link 的自定义 sphinx 角色?
how to make a custom sphinx role that is also an external link?
我正在尝试扩展 Sphinx 以拥有一个名为 newcontrib
的新内联角色。它应该做的是获取其内容并 (1) 添加一些额外的文本,(2) 在呈现的输出中将文本设为粗体,以及 (3) 将文本设为 link,其目标是原始文本角色的内容。示例:
:newcontrib:`Jane Doe`
最终应该像
一样被解析
`**new contributor Jane Doe** <Jane Doe_>`_
目标在另一个文件 (names.inc
) 中定义,看起来像:
.. _Jane Doe: https://jane-does-website.com
我目前的尝试(大致基于 this example)是这样的:
from docutils.nodes import reference, strong, target
from sphinx.addnodes import pending_xref
def newcontrib_role(name, rawtext, text, lineno, inliner, options={},
content=[]):
"""Create a role to highlight new contributors in changelog entries."""
newcontrib = f'new contributor {text}'
targ = f' <{text}_>'
rawtext = f'`{newcontrib}{targ}`_'
options.update(name=newcontrib, refname=text.lower())
strong_node = strong(rawtext, newcontrib)
node = reference('', '', strong_node, **options)
return [node], []
def setup(app):
app.add_role('newcontrib', newcontrib_role)
return
我也尝试过使用 pending_xref()
而不是 reference()
,并尝试明确创建一个 target
节点并将其添加为兄弟节点。结果因我的尝试而异;有时我在构建过程中遇到错误(缺少属性 refname、refdomain、reftype...),其他时候我构建成功但 link 变为 url-of-current-page#jane-doe
。我还简要地尝试了子类化 XRefRole
而不是定义角色函数...对任何方法都开放。
最终起作用的是:
def newcontrib_role(name, rawtext, text, lineno, inliner, options={},
content=[]):
"""Create a role to highlight new contributors in changelog entries."""
newcontrib = f'new contributor {text}'
alias_text = f' <{text}_>'
rawtext = f'`{newcontrib}{alias_text}`_'
refname = text.lower()
strong_node = strong(rawtext, newcontrib)
target_node = target(alias_text, refname=refname, names=[newcontrib])
target_node.indirect_reference_name = text
options.update(name=newcontrib, refname=refname)
ref_node = reference('', '', strong_node, **options)
ref_node[0].rawsource = rawtext
inliner.document.note_indirect_target(target_node)
inliner.document.note_refname(ref_node)
return [ref_node, target_node], []
(加上问题中的setup(app)
函数)
特别是,我以前没有尝试过的关键步骤是 inliner.document.note_indirect_target
和 inliner.document.note_refname
。我从 how docutils parses links.
得到了灵感
我正在尝试扩展 Sphinx 以拥有一个名为 newcontrib
的新内联角色。它应该做的是获取其内容并 (1) 添加一些额外的文本,(2) 在呈现的输出中将文本设为粗体,以及 (3) 将文本设为 link,其目标是原始文本角色的内容。示例:
:newcontrib:`Jane Doe`
最终应该像
一样被解析`**new contributor Jane Doe** <Jane Doe_>`_
目标在另一个文件 (names.inc
) 中定义,看起来像:
.. _Jane Doe: https://jane-does-website.com
我目前的尝试(大致基于 this example)是这样的:
from docutils.nodes import reference, strong, target
from sphinx.addnodes import pending_xref
def newcontrib_role(name, rawtext, text, lineno, inliner, options={},
content=[]):
"""Create a role to highlight new contributors in changelog entries."""
newcontrib = f'new contributor {text}'
targ = f' <{text}_>'
rawtext = f'`{newcontrib}{targ}`_'
options.update(name=newcontrib, refname=text.lower())
strong_node = strong(rawtext, newcontrib)
node = reference('', '', strong_node, **options)
return [node], []
def setup(app):
app.add_role('newcontrib', newcontrib_role)
return
我也尝试过使用 pending_xref()
而不是 reference()
,并尝试明确创建一个 target
节点并将其添加为兄弟节点。结果因我的尝试而异;有时我在构建过程中遇到错误(缺少属性 refname、refdomain、reftype...),其他时候我构建成功但 link 变为 url-of-current-page#jane-doe
。我还简要地尝试了子类化 XRefRole
而不是定义角色函数...对任何方法都开放。
最终起作用的是:
def newcontrib_role(name, rawtext, text, lineno, inliner, options={},
content=[]):
"""Create a role to highlight new contributors in changelog entries."""
newcontrib = f'new contributor {text}'
alias_text = f' <{text}_>'
rawtext = f'`{newcontrib}{alias_text}`_'
refname = text.lower()
strong_node = strong(rawtext, newcontrib)
target_node = target(alias_text, refname=refname, names=[newcontrib])
target_node.indirect_reference_name = text
options.update(name=newcontrib, refname=refname)
ref_node = reference('', '', strong_node, **options)
ref_node[0].rawsource = rawtext
inliner.document.note_indirect_target(target_node)
inliner.document.note_refname(ref_node)
return [ref_node, target_node], []
(加上问题中的setup(app)
函数)
特别是,我以前没有尝试过的关键步骤是 inliner.document.note_indirect_target
和 inliner.document.note_refname
。我从 how docutils parses links.