Вопрос
Я хочу создать role
, coderef
, который будет ссылаться на помеченный код модуля, сгенерированный sphinx.ext.viewcode
.Для этого у меня сложилось впечатление, что мне нужно правильно заполнить env._viewcode_modules
, и я не уверен, как это сделать.
Фон
Глядя на viewcode
, кажется, что viewcode.doctree_read
сканируетдерево документа для addnode.desc_signature
узлов (если оно вложено в узлы addnode.desc
), заполняющее env._viewcode_modules
, dict, с модулями, которые будут помечены, как это происходит.Значения, вставленные в dict, изначально None
и заменяются либо False
, если модуль не может быть окрашен, либо узлом документа (здесь не уверен), когда это может бытьlinted.Кажется, что sphinx.ext.viewcode.collect_pages
выполняет итерацию по этим страницам, генерируя соответствующие страницы.
Текущая реализация
Я надеялся подключиться к этому механизму, и когда я сталкиваюсь с coderef
вхождениями, просто добавляю некоторые дополнительные записи вenv._viewcode_modules
.Я не уверен, однако, что я делаю это правильно.Код, который у меня есть, выглядит следующим образом:
from docutils import nodes, utils
from sphinx import addnodes
from sphinx.util.nodes import split_explicit_title
def coderef(role, rawtext, text, line, inliner, options={}, content=[]):
try :
env = inliner.document.settings.env
if not hasattr(env, '_viewcode_modules'): env._viewcode_modules = {} # View Code retains a list of modules, we sneak the cross linked modules into the list.
test, name, link = split_explicit_title(text)
refid = link.replace('.','-')
refuri = env.app.builder.get_relative_uri("/", "/".join(["_modules", *link.split('.')])) # Originally : "_modules/" + link.replace('.','/')
refname = utils.unescape(name) # Future : inliner.nested_parse() ?
reflink = utils.unescape("_modules/" + link.replace(".","/")) # str(Path("_modules").join(target.split('.')))
refnode = nodes.inline('', refname, classes=['viewcode-link']) # viewcode-link is a CSS class
coderef = addnodes.only(expr='html')
coderef+= addnodes.pending_xref('', refname,
refid = refid,
reftype = 'viewcode' or role, # The reference type, see viewcode extention
refdomain = 'std', #
refexplicit = False, #
refdoc = env.docname, # Originally : env.docname; This represents the name of the document with all extentions stripped, I think this doubles as a back reference.
reftarget = reflink)
return [coderef], []
except Exception as error : # This is bad form, specify explicit errors you know how to deal with
msg = inliner.reporter.error(
'An error occured while determining the code reference for'
' "%s" ' % text,
line = line)
prb = inliner.problematic(rawtext, text, msg)
return [prb], [msg]
Неудачная реализация
Раньше мне удавалось частично заставить это работать, используя nodes.reference
, но затем помеченные модули не всегда генерировались какони не добавляются к env._viewcode_modules
и не обрабатываются sphinx.ext.viewcode.collect_pages
.
Наблюдения
Некоторые странности, за которыми я пока не следую, заключаются в том, как разрешаются addnodes.pending_xref
.Кажется необходимым иметь как обратную, так и прямую ссылку, и я не думаю, что создаю соответствующую обратную ссылку в данный момент.addnodes.pending_xref
также, кажется, принимает узел nodes.inline
, предположительно, это узел для текста в последней ссылке;Это также не удалось должным образом на данный момент.