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

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.com


Signed-off-by: default avatarJonathan Corbet <corbet@lwn.net>
parent f59c4966
Loading
Loading
Loading
Loading
+75 −47
Original line number Diff line number Diff line
@@ -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_namespace = re.compile(r'^\s*..\s*c:namespace::\s*(\S+)\s*$')

#
# Reserved C words that we should skip when cross-referencing
#
@@ -70,6 +72,8 @@ Skipfuncs = [ 'open', 'close', 'read', 'write', 'fcntl', 'mmap',
              'select', 'poll', 'fork', 'execve', 'clone', 'ioctl',
              'socket' ]

c_namespace = ''

def markup_refs(docname, app, node):
    t = node.astext()
    done = 0
@@ -128,10 +132,18 @@ def markup_func_ref_sphinx3(docname, app, match):
    #
    # 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))
    xref = None
    if not (target in Skipfuncs or target in Skipnames):
    possible_targets = [base_target]
    # Check if this document has a namespace, and if so, try
    # cross-referencing inside it first.
    if c_namespace:
        possible_targets.insert(0, c_namespace + "." + base_target)

    if base_target not in Skipnames:
        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
@@ -179,11 +191,18 @@ def markup_c_ref(docname, app, match):
    #
    # 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))
    xref = None
    if not ((match.re == RE_function and target in Skipfuncs)
            or (target in Skipnames)):
    possible_targets = [base_target]
    # Check if this document has a namespace, and if so, try
    # cross-referencing inside it first.
    if c_namespace:
        possible_targets.insert(0, c_namespace + "." + base_target)

    if base_target not in Skipnames:
        for target in possible_targets:
            if not (match.re == RE_function and target in Skipfuncs):
                lit_text = nodes.literal(classes=['xref', 'c', class_str[match.re]])
                lit_text += target_text
                pxref = addnodes.pending_xref('', refdomain = 'c',
@@ -200,12 +219,10 @@ def markup_c_ref(docname, app, match):
                                             lit_text)
                except NoUri:
                    xref = None
    #
    # Return the xref if we got it; otherwise just return the plain text.
    #

                if xref:
                    return xref
    else:

    return target_text

#
@@ -239,7 +256,18 @@ def markup_doc_ref(docname, app, match):
    else:
        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):
    global c_namespace
    c_namespace = get_c_namespace(app, name)
    #
    # This loop could eventually be improved on.  Someday maybe we
    # want a proper tree traversal with a lot of awareness of which