^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1) # SPDX-License-Identifier: GPL-2.0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2) # Copyright 2019 Jonathan Corbet <corbet@lwn.net>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3) #
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 4) # Apply kernel-specific tweaks after the initial document processing
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 5) # has been done.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 6) #
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 7) from docutils import nodes
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 8) import sphinx
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 9) from sphinx import addnodes
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 10) if sphinx.version_info[0] < 2 or \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 11) sphinx.version_info[0] == 2 and sphinx.version_info[1] < 1:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 12) from sphinx.environment import NoUri
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 13) else:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 14) from sphinx.errors import NoUri
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 15) import re
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 16) from itertools import chain
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 17)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 18) #
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 19) # Python 2 lacks re.ASCII...
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 20) #
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 21) try:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 22) ascii_p3 = re.ASCII
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 23) except AttributeError:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 24) ascii_p3 = 0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 25)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 26) #
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 27) # Regex nastiness. Of course.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 28) # Try to identify "function()" that's not already marked up some
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 29) # other way. Sphinx doesn't like a lot of stuff right after a
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 30) # :c:func: block (i.e. ":c:func:`mmap()`s" flakes out), so the last
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 31) # bit tries to restrict matches to things that won't create trouble.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 32) #
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 33) RE_function = re.compile(r'\b(([a-zA-Z_]\w+)\(\))', flags=ascii_p3)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 34)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 35) #
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 36) # Sphinx 2 uses the same :c:type role for struct, union, enum and typedef
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 37) #
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 38) RE_generic_type = re.compile(r'\b(struct|union|enum|typedef)\s+([a-zA-Z_]\w+)',
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 39) flags=ascii_p3)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 40)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 41) #
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 42) # Sphinx 3 uses a different C role for each one of struct, union, enum and
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 43) # typedef
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 44) #
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 45) RE_struct = re.compile(r'\b(struct)\s+([a-zA-Z_]\w+)', flags=ascii_p3)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 46) RE_union = re.compile(r'\b(union)\s+([a-zA-Z_]\w+)', flags=ascii_p3)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 47) RE_enum = re.compile(r'\b(enum)\s+([a-zA-Z_]\w+)', flags=ascii_p3)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 48) RE_typedef = re.compile(r'\b(typedef)\s+([a-zA-Z_]\w+)', flags=ascii_p3)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 49)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 50) #
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 51) # Detects a reference to a documentation page of the form Documentation/... with
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 52) # an optional extension
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 53) #
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 54) RE_doc = re.compile(r'\bDocumentation(/[\w\-_/]+)(\.\w+)*')
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 55)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 56) #
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 57) # Reserved C words that we should skip when cross-referencing
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 58) #
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 59) Skipnames = [ 'for', 'if', 'register', 'sizeof', 'struct', 'unsigned' ]
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 60)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 61)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 62) #
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 63) # Many places in the docs refer to common system calls. It is
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 64) # pointless to try to cross-reference them and, as has been known
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 65) # to happen, somebody defining a function by these names can lead
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 66) # to the creation of incorrect and confusing cross references. So
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 67) # just don't even try with these names.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 68) #
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 69) Skipfuncs = [ 'open', 'close', 'read', 'write', 'fcntl', 'mmap',
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 70) 'select', 'poll', 'fork', 'execve', 'clone', 'ioctl',
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 71) 'socket' ]
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 72)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 73) def markup_refs(docname, app, node):
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 74) t = node.astext()
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 75) done = 0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 76) repl = [ ]
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 77) #
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 78) # Associate each regex with the function that will markup its matches
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 79) #
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 80) markup_func_sphinx2 = {RE_doc: markup_doc_ref,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 81) RE_function: markup_c_ref,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 82) RE_generic_type: markup_c_ref}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 83)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 84) markup_func_sphinx3 = {RE_doc: markup_doc_ref,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 85) RE_function: markup_func_ref_sphinx3,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 86) RE_struct: markup_c_ref,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 87) RE_union: markup_c_ref,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 88) RE_enum: markup_c_ref,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 89) RE_typedef: markup_c_ref}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 90)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 91) if sphinx.version_info[0] >= 3:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 92) markup_func = markup_func_sphinx3
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 93) else:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 94) markup_func = markup_func_sphinx2
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 95)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 96) match_iterators = [regex.finditer(t) for regex in markup_func]
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 97) #
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 98) # Sort all references by the starting position in text
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 99) #
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 100) sorted_matches = sorted(chain(*match_iterators), key=lambda m: m.start())
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 101) for m in sorted_matches:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 102) #
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 103) # Include any text prior to match as a normal text node.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 104) #
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 105) if m.start() > done:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 106) repl.append(nodes.Text(t[done:m.start()]))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 107)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 108) #
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 109) # Call the function associated with the regex that matched this text and
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 110) # append its return to the text
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 111) #
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 112) repl.append(markup_func[m.re](docname, app, m))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 113)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 114) done = m.end()
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 115) if done < len(t):
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 116) repl.append(nodes.Text(t[done:]))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 117) return repl
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 118)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 119) #
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 120) # In sphinx3 we can cross-reference to C macro and function, each one with its
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 121) # own C role, but both match the same regex, so we try both.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 122) #
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 123) def markup_func_ref_sphinx3(docname, app, match):
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 124) class_str = ['c-func', 'c-macro']
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 125) reftype_str = ['function', 'macro']
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 126)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 127) cdom = app.env.domains['c']
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 128) #
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 129) # Go through the dance of getting an xref out of the C domain
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 130) #
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 131) target = match.group(2)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 132) target_text = nodes.Text(match.group(0))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 133) xref = None
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 134) if not (target in Skipfuncs or target in Skipnames):
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 135) for class_s, reftype_s in zip(class_str, reftype_str):
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 136) lit_text = nodes.literal(classes=['xref', 'c', class_s])
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 137) lit_text += target_text
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 138) pxref = addnodes.pending_xref('', refdomain = 'c',
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 139) reftype = reftype_s,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 140) reftarget = target, modname = None,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 141) classname = None)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 142) #
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 143) # XXX The Latex builder will throw NoUri exceptions here,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 144) # work around that by ignoring them.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 145) #
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 146) try:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 147) xref = cdom.resolve_xref(app.env, docname, app.builder,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 148) reftype_s, target, pxref,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 149) lit_text)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 150) except NoUri:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 151) xref = None
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 152)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 153) if xref:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 154) return xref
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 155)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 156) return target_text
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 157)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 158) def markup_c_ref(docname, app, match):
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 159) class_str = {# Sphinx 2 only
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 160) RE_function: 'c-func',
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 161) RE_generic_type: 'c-type',
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 162) # Sphinx 3+ only
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 163) RE_struct: 'c-struct',
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 164) RE_union: 'c-union',
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 165) RE_enum: 'c-enum',
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 166) RE_typedef: 'c-type',
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 167) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 168) reftype_str = {# Sphinx 2 only
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 169) RE_function: 'function',
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 170) RE_generic_type: 'type',
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 171) # Sphinx 3+ only
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 172) RE_struct: 'struct',
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 173) RE_union: 'union',
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 174) RE_enum: 'enum',
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 175) RE_typedef: 'type',
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 176) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 177)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 178) cdom = app.env.domains['c']
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 179) #
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 180) # Go through the dance of getting an xref out of the C domain
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 181) #
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 182) target = match.group(2)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 183) target_text = nodes.Text(match.group(0))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 184) xref = None
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 185) if not ((match.re == RE_function and target in Skipfuncs)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 186) or (target in Skipnames)):
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 187) lit_text = nodes.literal(classes=['xref', 'c', class_str[match.re]])
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 188) lit_text += target_text
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 189) pxref = addnodes.pending_xref('', refdomain = 'c',
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 190) reftype = reftype_str[match.re],
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 191) reftarget = target, modname = None,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 192) classname = None)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 193) #
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 194) # XXX The Latex builder will throw NoUri exceptions here,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 195) # work around that by ignoring them.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 196) #
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 197) try:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 198) xref = cdom.resolve_xref(app.env, docname, app.builder,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 199) reftype_str[match.re], target, pxref,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 200) lit_text)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 201) except NoUri:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 202) xref = None
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 203) #
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 204) # Return the xref if we got it; otherwise just return the plain text.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 205) #
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 206) if xref:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 207) return xref
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 208) else:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 209) return target_text
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 210)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 211) #
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 212) # Try to replace a documentation reference of the form Documentation/... with a
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 213) # cross reference to that page
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 214) #
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 215) def markup_doc_ref(docname, app, match):
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 216) stddom = app.env.domains['std']
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 217) #
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 218) # Go through the dance of getting an xref out of the std domain
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 219) #
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 220) target = match.group(1)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 221) xref = None
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 222) pxref = addnodes.pending_xref('', refdomain = 'std', reftype = 'doc',
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 223) reftarget = target, modname = None,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 224) classname = None, refexplicit = False)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 225) #
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 226) # XXX The Latex builder will throw NoUri exceptions here,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 227) # work around that by ignoring them.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 228) #
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 229) try:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 230) xref = stddom.resolve_xref(app.env, docname, app.builder, 'doc',
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 231) target, pxref, None)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 232) except NoUri:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 233) xref = None
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 234) #
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 235) # Return the xref if we got it; otherwise just return the plain text.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 236) #
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 237) if xref:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 238) return xref
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 239) else:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 240) return nodes.Text(match.group(0))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 241)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 242) def auto_markup(app, doctree, name):
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 243) #
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 244) # This loop could eventually be improved on. Someday maybe we
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 245) # want a proper tree traversal with a lot of awareness of which
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 246) # kinds of nodes to prune. But this works well for now.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 247) #
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 248) # The nodes.literal test catches ``literal text``, its purpose is to
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 249) # avoid adding cross-references to functions that have been explicitly
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 250) # marked with cc:func:.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 251) #
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 252) for para in doctree.traverse(nodes.paragraph):
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 253) for node in para.traverse(nodes.Text):
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 254) if not isinstance(node.parent, nodes.literal):
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 255) node.parent.replace(node, markup_refs(name, app, node))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 256)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 257) def setup(app):
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 258) app.connect('doctree-resolved', auto_markup)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 259) return {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 260) 'parallel_read_safe': True,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 261) 'parallel_write_safe': True,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 262) }