.. | .. |
---|
40 | 40 | from sphinx.domains.c import c_funcptr_sig_re, c_sig_re |
---|
41 | 41 | from sphinx.domains.c import CObject as Base_CObject |
---|
42 | 42 | from sphinx.domains.c import CDomain as Base_CDomain |
---|
| 43 | +from itertools import chain |
---|
| 44 | +import re |
---|
43 | 45 | |
---|
44 | | -__version__ = '1.0' |
---|
| 46 | +__version__ = '1.1' |
---|
45 | 47 | |
---|
46 | 48 | # Get Sphinx version |
---|
47 | 49 | major, minor, patch = sphinx.version_info[:3] |
---|
48 | 50 | |
---|
| 51 | +# Namespace to be prepended to the full name |
---|
| 52 | +namespace = None |
---|
| 53 | + |
---|
| 54 | +# |
---|
| 55 | +# Handle trivial newer c domain tags that are part of Sphinx 3.1 c domain tags |
---|
| 56 | +# - Store the namespace if ".. c:namespace::" tag is found |
---|
| 57 | +# |
---|
| 58 | +RE_namespace = re.compile(r'^\s*..\s*c:namespace::\s*(\S+)\s*$') |
---|
| 59 | + |
---|
| 60 | +def markup_namespace(match): |
---|
| 61 | + global namespace |
---|
| 62 | + |
---|
| 63 | + namespace = match.group(1) |
---|
| 64 | + |
---|
| 65 | + return "" |
---|
| 66 | + |
---|
| 67 | +# |
---|
| 68 | +# Handle c:macro for function-style declaration |
---|
| 69 | +# |
---|
| 70 | +RE_macro = re.compile(r'^\s*..\s*c:macro::\s*(\S+)\s+(\S.*)\s*$') |
---|
| 71 | +def markup_macro(match): |
---|
| 72 | + return ".. c:function:: " + match.group(1) + ' ' + match.group(2) |
---|
| 73 | + |
---|
| 74 | +# |
---|
| 75 | +# Handle newer c domain tags that are evaluated as .. c:type: for |
---|
| 76 | +# backward-compatibility with Sphinx < 3.0 |
---|
| 77 | +# |
---|
| 78 | +RE_ctype = re.compile(r'^\s*..\s*c:(struct|union|enum|enumerator|alias)::\s*(.*)$') |
---|
| 79 | + |
---|
| 80 | +def markup_ctype(match): |
---|
| 81 | + return ".. c:type:: " + match.group(2) |
---|
| 82 | + |
---|
| 83 | +# |
---|
| 84 | +# Handle newer c domain tags that are evaluated as :c:type: for |
---|
| 85 | +# backward-compatibility with Sphinx < 3.0 |
---|
| 86 | +# |
---|
| 87 | +RE_ctype_refs = re.compile(r':c:(var|struct|union|enum|enumerator)::`([^\`]+)`') |
---|
| 88 | +def markup_ctype_refs(match): |
---|
| 89 | + return ":c:type:`" + match.group(2) + '`' |
---|
| 90 | + |
---|
| 91 | +# |
---|
| 92 | +# Simply convert :c:expr: and :c:texpr: into a literal block. |
---|
| 93 | +# |
---|
| 94 | +RE_expr = re.compile(r':c:(expr|texpr):`([^\`]+)`') |
---|
| 95 | +def markup_c_expr(match): |
---|
| 96 | + return '\ ``' + match.group(2) + '``\ ' |
---|
| 97 | + |
---|
| 98 | +# |
---|
| 99 | +# Parse Sphinx 3.x C markups, replacing them by backward-compatible ones |
---|
| 100 | +# |
---|
| 101 | +def c_markups(app, docname, source): |
---|
| 102 | + result = "" |
---|
| 103 | + markup_func = { |
---|
| 104 | + RE_namespace: markup_namespace, |
---|
| 105 | + RE_expr: markup_c_expr, |
---|
| 106 | + RE_macro: markup_macro, |
---|
| 107 | + RE_ctype: markup_ctype, |
---|
| 108 | + RE_ctype_refs: markup_ctype_refs, |
---|
| 109 | + } |
---|
| 110 | + |
---|
| 111 | + lines = iter(source[0].splitlines(True)) |
---|
| 112 | + for n in lines: |
---|
| 113 | + match_iterators = [regex.finditer(n) for regex in markup_func] |
---|
| 114 | + matches = sorted(chain(*match_iterators), key=lambda m: m.start()) |
---|
| 115 | + for m in matches: |
---|
| 116 | + n = n[:m.start()] + markup_func[m.re](m) + n[m.end():] |
---|
| 117 | + |
---|
| 118 | + result = result + n |
---|
| 119 | + |
---|
| 120 | + source[0] = result |
---|
| 121 | + |
---|
| 122 | +# |
---|
| 123 | +# Now implements support for the cdomain namespacing logic |
---|
| 124 | +# |
---|
| 125 | + |
---|
49 | 126 | def setup(app): |
---|
50 | 127 | |
---|
51 | | - app.override_domain(CDomain) |
---|
| 128 | + # Handle easy Sphinx 3.1+ simple new tags: :c:expr and .. c:namespace:: |
---|
| 129 | + app.connect('source-read', c_markups) |
---|
| 130 | + |
---|
| 131 | + if (major == 1 and minor < 8): |
---|
| 132 | + app.override_domain(CDomain) |
---|
| 133 | + else: |
---|
| 134 | + app.add_domain(CDomain, override=True) |
---|
52 | 135 | |
---|
53 | 136 | return dict( |
---|
54 | 137 | version = __version__, |
---|
.. | .. |
---|
71 | 154 | If the objtype is 'function' and the the signature ``sig`` is a |
---|
72 | 155 | function-like macro, the name of the macro is returned. Otherwise |
---|
73 | 156 | ``False`` is returned. """ |
---|
| 157 | + |
---|
| 158 | + global namespace |
---|
74 | 159 | |
---|
75 | 160 | if not self.objtype == 'function': |
---|
76 | 161 | return False |
---|
.. | .. |
---|
104 | 189 | param += nodes.emphasis(argname, argname) |
---|
105 | 190 | paramlist += param |
---|
106 | 191 | |
---|
| 192 | + if namespace: |
---|
| 193 | + fullname = namespace + "." + fullname |
---|
| 194 | + |
---|
107 | 195 | return fullname |
---|
108 | 196 | |
---|
109 | 197 | def handle_signature(self, sig, signode): |
---|
110 | 198 | """Transform a C signature into RST nodes.""" |
---|
| 199 | + |
---|
| 200 | + global namespace |
---|
111 | 201 | |
---|
112 | 202 | fullname = self.handle_func_like_macro(sig, signode) |
---|
113 | 203 | if not fullname: |
---|
.. | .. |
---|
119 | 209 | else: |
---|
120 | 210 | # FIXME: handle :name: value of other declaration types? |
---|
121 | 211 | pass |
---|
| 212 | + else: |
---|
| 213 | + if namespace: |
---|
| 214 | + fullname = namespace + "." + fullname |
---|
| 215 | + |
---|
122 | 216 | return fullname |
---|
123 | 217 | |
---|
124 | 218 | def add_target_and_index(self, name, sig, signode): |
---|