Commit fb568273 authored by Nícolas F. R. A. Prado's avatar Nícolas F. R. A. Prado Committed by Jonathan Corbet

docs: automarkup.py: Allow automatic cross-reference inside C namespace

Sphinx 3.1 introduced namespaces for C cross-references. With this,
each C domain type/function declaration is put inside the namespace that
was active at the time of its declaration.

Add support for automatic cross-referencing inside C namespaces by
checking whether the corresponding source file had a C namespace Sphinx
directive, and if so, try cross-referencing inside of it before going to
the global scope.

This assumes there's only one namespace (if any) per rst file.
Signed-off-by: default avatarNícolas F. R. A. Prado <nfraprado@protonmail.com>
Link: https://lore.kernel.org/r/20201117021107.214704-1-nfraprado@protonmail.comSigned-off-by: default avatarJonathan Corbet <corbet@lwn.net>
parent f59c4966
...@@ -53,6 +53,8 @@ RE_typedef = re.compile(r'\b(typedef)\s+([a-zA-Z_]\w+)', flags=ascii_p3) ...@@ -53,6 +53,8 @@ RE_typedef = re.compile(r'\b(typedef)\s+([a-zA-Z_]\w+)', flags=ascii_p3)
# #
RE_doc = re.compile(r'\bDocumentation(/[\w\-_/]+)(\.\w+)*') RE_doc = re.compile(r'\bDocumentation(/[\w\-_/]+)(\.\w+)*')
RE_namespace = re.compile(r'^\s*..\s*c:namespace::\s*(\S+)\s*$')
# #
# Reserved C words that we should skip when cross-referencing # Reserved C words that we should skip when cross-referencing
# #
...@@ -70,6 +72,8 @@ Skipfuncs = [ 'open', 'close', 'read', 'write', 'fcntl', 'mmap', ...@@ -70,6 +72,8 @@ Skipfuncs = [ 'open', 'close', 'read', 'write', 'fcntl', 'mmap',
'select', 'poll', 'fork', 'execve', 'clone', 'ioctl', 'select', 'poll', 'fork', 'execve', 'clone', 'ioctl',
'socket' ] 'socket' ]
c_namespace = ''
def markup_refs(docname, app, node): def markup_refs(docname, app, node):
t = node.astext() t = node.astext()
done = 0 done = 0
...@@ -128,30 +132,38 @@ def markup_func_ref_sphinx3(docname, app, match): ...@@ -128,30 +132,38 @@ def markup_func_ref_sphinx3(docname, app, match):
# #
# Go through the dance of getting an xref out of the C domain # Go through the dance of getting an xref out of the C domain
# #
target = match.group(2) base_target = match.group(2)
target_text = nodes.Text(match.group(0)) target_text = nodes.Text(match.group(0))
xref = None xref = None
if not (target in Skipfuncs or target in Skipnames): possible_targets = [base_target]
for class_s, reftype_s in zip(class_str, reftype_str): # Check if this document has a namespace, and if so, try
lit_text = nodes.literal(classes=['xref', 'c', class_s]) # cross-referencing inside it first.
lit_text += target_text if c_namespace:
pxref = addnodes.pending_xref('', refdomain = 'c', possible_targets.insert(0, c_namespace + "." + base_target)
reftype = reftype_s,
reftarget = target, modname = None,
classname = None)
#
# XXX The Latex builder will throw NoUri exceptions here,
# work around that by ignoring them.
#
try:
xref = cdom.resolve_xref(app.env, docname, app.builder,
reftype_s, target, pxref,
lit_text)
except NoUri:
xref = None
if xref: if base_target not in Skipnames:
return xref for target in possible_targets:
if target not in Skipfuncs:
for class_s, reftype_s in zip(class_str, reftype_str):
lit_text = nodes.literal(classes=['xref', 'c', class_s])
lit_text += target_text
pxref = addnodes.pending_xref('', refdomain = 'c',
reftype = reftype_s,
reftarget = target, modname = None,
classname = None)
#
# XXX The Latex builder will throw NoUri exceptions here,
# work around that by ignoring them.
#
try:
xref = cdom.resolve_xref(app.env, docname, app.builder,
reftype_s, target, pxref,
lit_text)
except NoUri:
xref = None
if xref:
return xref
return target_text return target_text
...@@ -179,34 +191,39 @@ def markup_c_ref(docname, app, match): ...@@ -179,34 +191,39 @@ def markup_c_ref(docname, app, match):
# #
# Go through the dance of getting an xref out of the C domain # Go through the dance of getting an xref out of the C domain
# #
target = match.group(2) base_target = match.group(2)
target_text = nodes.Text(match.group(0)) target_text = nodes.Text(match.group(0))
xref = None xref = None
if not ((match.re == RE_function and target in Skipfuncs) possible_targets = [base_target]
or (target in Skipnames)): # Check if this document has a namespace, and if so, try
lit_text = nodes.literal(classes=['xref', 'c', class_str[match.re]]) # cross-referencing inside it first.
lit_text += target_text if c_namespace:
pxref = addnodes.pending_xref('', refdomain = 'c', possible_targets.insert(0, c_namespace + "." + base_target)
reftype = reftype_str[match.re],
reftarget = target, modname = None, if base_target not in Skipnames:
classname = None) for target in possible_targets:
# if not (match.re == RE_function and target in Skipfuncs):
# XXX The Latex builder will throw NoUri exceptions here, lit_text = nodes.literal(classes=['xref', 'c', class_str[match.re]])
# work around that by ignoring them. lit_text += target_text
# pxref = addnodes.pending_xref('', refdomain = 'c',
try: reftype = reftype_str[match.re],
xref = cdom.resolve_xref(app.env, docname, app.builder, reftarget = target, modname = None,
reftype_str[match.re], target, pxref, classname = None)
lit_text) #
except NoUri: # XXX The Latex builder will throw NoUri exceptions here,
xref = None # work around that by ignoring them.
# #
# Return the xref if we got it; otherwise just return the plain text. try:
# xref = cdom.resolve_xref(app.env, docname, app.builder,
if xref: reftype_str[match.re], target, pxref,
return xref lit_text)
else: except NoUri:
return target_text xref = None
if xref:
return xref
return target_text
# #
# Try to replace a documentation reference of the form Documentation/... with a # Try to replace a documentation reference of the form Documentation/... with a
...@@ -239,7 +256,18 @@ def markup_doc_ref(docname, app, match): ...@@ -239,7 +256,18 @@ def markup_doc_ref(docname, app, match):
else: else:
return nodes.Text(match.group(0)) return nodes.Text(match.group(0))
def get_c_namespace(app, docname):
source = app.env.doc2path(docname)
with open(source) as f:
for l in f:
match = RE_namespace.search(l)
if match:
return match.group(1)
return ''
def auto_markup(app, doctree, name): def auto_markup(app, doctree, name):
global c_namespace
c_namespace = get_c_namespace(app, name)
# #
# This loop could eventually be improved on. Someday maybe we # This loop could eventually be improved on. Someday maybe we
# want a proper tree traversal with a lot of awareness of which # want a proper tree traversal with a lot of awareness of which
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment