From 14f7d243bd9509d0dab9cace0d9a18fe34b58b92 Mon Sep 17 00:00:00 2001 From: Jakob Lykke Andersen Date: Tue, 16 Mar 2021 20:02:26 +0100 Subject: [PATCH 01/22] Decl styling, more nodes and C++ conversion --- sphinx/addnodes.py | 67 ++- sphinx/domains/cpp.py | 495 +++++++++++------- sphinx/themes/basic/static/basic.css_t | 42 +- sphinx/transforms/post_transforms/__init__.py | 6 +- tests/test_domain_cpp.py | 4 + tests/test_ext_intersphinx.py | 4 +- 6 files changed, 381 insertions(+), 237 deletions(-) diff --git a/sphinx/addnodes.py b/sphinx/addnodes.py index 5645ac91b..3200e5e47 100644 --- a/sphinx/addnodes.py +++ b/sphinx/addnodes.py @@ -154,6 +154,10 @@ class desc_signature_line(nodes.Part, nodes.Inline, nodes.FixedTextElement): # nodes to use within a desc_signature or desc_signature_line +class desc_name(nodes.Part, nodes.Inline, nodes.FixedTextElement): + """Node for the main object name.""" + + class desc_addname(nodes.Part, nodes.Inline, nodes.FixedTextElement): """Node for additional name parts (module name, class name).""" @@ -168,14 +172,11 @@ class desc_type(nodes.Part, nodes.Inline, nodes.FixedTextElement): class desc_returns(desc_type): """Node for a "returns" annotation (a la -> in Python).""" + def astext(self) -> str: return ' -> ' + super().astext() -class desc_name(nodes.Part, nodes.Inline, nodes.FixedTextElement): - """Node for the main object name.""" - - class desc_parameterlist(nodes.Part, nodes.Inline, nodes.FixedTextElement): """Node for a general parameter list.""" child_text_separator = ', ' @@ -207,6 +208,10 @@ class desc_content(nodes.General, nodes.Element): """ +# Signature text elements, generally translated to node.inline +# in SigElementFallbackTransform. +# When adding a new one, add it to SIG_ELEMENTS. + class desc_sig_element(nodes.inline): """Common parent class of nodes for inline text of a signature.""" classes: List[str] = [] @@ -217,8 +222,19 @@ class desc_sig_element(nodes.inline): self['classes'].extend(self.classes) +# to not reinvent the wheel, the classes in the following desc_sig classes +# are based on those used in Pygments + +class desc_sig_space(desc_sig_element): + """Node for a space in a signature.""" + classes = ["w"] + + def __init__(self) -> None: + super().__init__(' ', ' ') + + class desc_sig_name(desc_sig_element): - """Node for a name in a signature.""" + """Node for an identifier in a signature.""" classes = ["n"] @@ -228,10 +244,43 @@ class desc_sig_operator(desc_sig_element): class desc_sig_punctuation(desc_sig_element): - """Node for a punctuation in a signature.""" + """Node for punctuation in a signature.""" classes = ["p"] +class desc_sig_keyword(desc_sig_element): + """Node for a general keyword in a signature.""" + classes = ["k"] + + +class desc_sig_keyword_type(desc_sig_element): + """Node for a keyword which is a built-in type in a signature.""" + classes = ["kt"] + + +class desc_sig_literal_number(desc_sig_element): + """Node for a numeric literal in a signature.""" + classes = ["m"] + + +class desc_sig_literal_string(desc_sig_element): + """Node for a string literal in a signature.""" + classes = ["s"] + + +class desc_sig_literal_char(desc_sig_element): + """Node for a character literal in a signature.""" + classes = ["sc"] + + +SIG_ELEMENTS = [desc_sig_space, + desc_sig_name, + desc_sig_operator, + desc_sig_punctuation, + desc_sig_keyword, desc_sig_keyword_type, + desc_sig_literal_number, desc_sig_literal_string, desc_sig_literal_char] + + # new admonition-like constructs class versionmodified(nodes.Admonition, nodes.TextElement): @@ -336,6 +385,7 @@ class pending_xref(nodes.Inline, nodes.Element): These nodes are resolved before writing output, in BuildEnvironment.resolve_references. """ + child_text_separator = '' class pending_xref_condition(nodes.Inline, nodes.TextElement): @@ -424,9 +474,8 @@ def setup(app: "Sphinx") -> Dict[str, Any]: app.add_node(desc_optional) app.add_node(desc_annotation) app.add_node(desc_content) - app.add_node(desc_sig_name) - app.add_node(desc_sig_operator) - app.add_node(desc_sig_punctuation) + for n in SIG_ELEMENTS: + app.add_node(n) app.add_node(versionmodified) app.add_node(seealso) app.add_node(productionlist) diff --git a/sphinx/domains/cpp.py b/sphinx/domains/cpp.py index abe961791..bb11138d6 100644 --- a/sphinx/domains/cpp.py +++ b/sphinx/domains/cpp.py @@ -604,6 +604,10 @@ class ASTIdentifier(ASTBase): def describe_signature(self, signode: TextElement, mode: str, env: "BuildEnvironment", prefix: str, templateArgs: str, symbol: "Symbol") -> None: verify_description_mode(mode) + if self.is_anon(): + node = addnodes.desc_sig_name(text="[anonymous]") + else: + node = addnodes.desc_sig_name(self.identifier, self.identifier) if mode == 'markType': targetText = prefix + self.identifier + templateArgs pnode = addnodes.pending_xref('', refdomain='cpp', @@ -611,21 +615,17 @@ class ASTIdentifier(ASTBase): reftarget=targetText, modname=None, classname=None) pnode['cpp:parent_key'] = symbol.get_lookup_key() - if self.is_anon(): - pnode += nodes.strong(text="[anonymous]") - else: - pnode += nodes.Text(self.identifier) + pnode += node signode += pnode elif mode == 'lastIsName': - if self.is_anon(): - signode += nodes.strong(text="[anonymous]") - else: - signode += addnodes.desc_name(self.identifier, self.identifier) + nameNode = addnodes.desc_name() + nameNode += node + signode += nameNode elif mode == 'noneIsName': - if self.is_anon(): - signode += nodes.strong(text="[anonymous]") - else: - signode += nodes.Text(self.identifier) + signode += node + elif mode == 'param': + node['classes'].append('sig-param') + signode += node elif mode == 'udl': # the target is 'operator""id' instead of just 'id' assert len(prefix) == 0 @@ -637,7 +637,7 @@ class ASTIdentifier(ASTBase): reftarget=targetText, modname=None, classname=None) pnode['cpp:parent_key'] = symbol.get_lookup_key() - pnode += nodes.Text(self.identifier) + pnode += node signode += pnode else: raise Exception('Unknown description mode: %s' % mode) @@ -669,7 +669,7 @@ class ASTNestedNameElement(ASTBase): tArgs = str(self.templateArgs) if self.templateArgs is not None else '' self.identOrOp.describe_signature(signode, mode, env, prefix, tArgs, symbol) if self.templateArgs is not None: - self.templateArgs.describe_signature(signode, mode, env, symbol) + self.templateArgs.describe_signature(signode, 'markType', env, symbol) class ASTNestedName(ASTBase): @@ -730,12 +730,15 @@ class ASTNestedName(ASTBase): # just print the name part, with template args, not template params if mode == 'noneIsName': if self.rooted: + assert False, "Can this happen?" # TODO signode += nodes.Text('::') for i in range(len(self.names)): if i != 0: - signode += nodes.Text('::') + assert False, "Can this happen?" # TODO + signode += nodes.Text('::blah') n = self.names[i] if self.templates[i]: + assert False, "Can this happen?" # TODO signode += nodes.Text("template") signode += nodes.Text(" ") n.describe_signature(signode, mode, env, '', symbol) @@ -743,9 +746,7 @@ class ASTNestedName(ASTBase): assert not self.rooted, str(self) assert len(self.names) == 1 assert not self.templates[0] - node = nodes.emphasis() - self.names[0].describe_signature(node, 'noneIsName', env, '', symbol) - signode += node + self.names[0].describe_signature(signode, 'param', env, '', symbol) elif mode == 'markType' or mode == 'lastIsName' or mode == 'markName': # Each element should be a pending xref targeting the complete # prefix. however, only the identifier part should be a link, such @@ -771,17 +772,18 @@ class ASTNestedName(ASTBase): if self.rooted: prefix += '::' if mode == 'lastIsName' and len(names) == 0: - signode += nodes.Text('::') + signode += addnodes.desc_sig_punctuation('::', '::') else: - dest += nodes.Text('::') + dest += addnodes.desc_sig_punctuation('::', '::') for i in range(len(names)): nne = names[i] template = self.templates[i] if not first: - dest += nodes.Text('::') + dest += addnodes.desc_sig_punctuation('::', '::') prefix += '::' if template: - dest += nodes.Text("template ") + dest += addnodes.desc_sig_keyword('template', 'template') + dest += addnodes.desc_sig_space() first = False txt_nne = str(nne) if txt_nne != '': @@ -793,10 +795,11 @@ class ASTNestedName(ASTBase): prefix += txt_nne if mode == 'lastIsName': if len(self.names) > 1: - dest += addnodes.desc_addname('::', '::') + dest += addnodes.desc_sig_punctuation('::', '::') signode += dest if self.templates[-1]: - signode += nodes.Text("template ") + signode += addnodes.desc_sig_keyword('template', 'template') + signode += addnodes.desc_sig_space() self.names[-1].describe_signature(signode, mode, env, '', symbol) else: raise Exception('Unknown description mode: %s' % mode) @@ -831,7 +834,7 @@ class ASTPointerLiteral(ASTLiteral): def describe_signature(self, signode: TextElement, mode: str, env: "BuildEnvironment", symbol: "Symbol") -> None: - signode.append(nodes.Text('nullptr')) + signode += addnodes.desc_sig_keyword('nullptr', 'nullptr') class ASTBooleanLiteral(ASTLiteral): @@ -852,7 +855,7 @@ class ASTBooleanLiteral(ASTLiteral): def describe_signature(self, signode: TextElement, mode: str, env: "BuildEnvironment", symbol: "Symbol") -> None: - signode.append(nodes.Text(str(self))) + signode += addnodes.desc_sig_keyword(str(self), str(self)) class ASTNumberLiteral(ASTLiteral): @@ -868,8 +871,7 @@ class ASTNumberLiteral(ASTLiteral): def describe_signature(self, signode: TextElement, mode: str, env: "BuildEnvironment", symbol: "Symbol") -> None: - txt = str(self) - signode.append(nodes.Text(txt, txt)) + signode += addnodes.desc_sig_literal_number(self.data, self.data) class ASTStringLiteral(ASTLiteral): @@ -885,8 +887,7 @@ class ASTStringLiteral(ASTLiteral): def describe_signature(self, signode: TextElement, mode: str, env: "BuildEnvironment", symbol: "Symbol") -> None: - txt = str(self) - signode.append(nodes.Text(txt, txt)) + signode += addnodes.desc_sig_literal_string(self.data, self.data) class ASTCharLiteral(ASTLiteral): @@ -913,8 +914,10 @@ class ASTCharLiteral(ASTLiteral): def describe_signature(self, signode: TextElement, mode: str, env: "BuildEnvironment", symbol: "Symbol") -> None: - txt = str(self) - signode.append(nodes.Text(txt, txt)) + if self.prefix is not None: + signode += addnodes.desc_sig_keyword(self.prefix, self.prefix) + txt = "'" + self.data + "'" + signode += addnodes.desc_sig_literal_char(txt, txt) class ASTUserDefinedLiteral(ASTLiteral): @@ -946,7 +949,7 @@ class ASTThisLiteral(ASTExpression): def describe_signature(self, signode: TextElement, mode: str, env: "BuildEnvironment", symbol: "Symbol") -> None: - signode.append(nodes.Text("this")) + signode += addnodes.desc_sig_keyword('this', 'this') class ASTFoldExpr(ASTExpression): @@ -996,19 +999,19 @@ class ASTFoldExpr(ASTExpression): def describe_signature(self, signode: TextElement, mode: str, env: "BuildEnvironment", symbol: "Symbol") -> None: - signode.append(nodes.Text('(')) + signode += addnodes.desc_sig_punctuation('(', '(') if self.leftExpr: self.leftExpr.describe_signature(signode, mode, env, symbol) - signode.append(nodes.Text(' ')) - signode.append(nodes.Text(self.op)) - signode.append(nodes.Text(' ')) - signode.append(nodes.Text('...')) + signode += addnodes.desc_sig_space() + signode += addnodes.desc_sig_operator(self.op, self.op) + signode += addnodes.desc_sig_space() + signode += addnodes.desc_sig_punctuation('...', '...') if self.rightExpr: - signode.append(nodes.Text(' ')) - signode.append(nodes.Text(self.op)) - signode.append(nodes.Text(' ')) + signode += addnodes.desc_sig_space() + signode += addnodes.desc_sig_operator(self.op, self.op) + signode += addnodes.desc_sig_space() self.rightExpr.describe_signature(signode, mode, env, symbol) - signode.append(nodes.Text(')')) + signode += addnodes.desc_sig_punctuation(')', ')') class ASTParenExpr(ASTExpression): @@ -1023,9 +1026,9 @@ class ASTParenExpr(ASTExpression): def describe_signature(self, signode: TextElement, mode: str, env: "BuildEnvironment", symbol: "Symbol") -> None: - signode.append(nodes.Text('(', '(')) + signode += addnodes.desc_sig_punctuation('(', '(') self.expr.describe_signature(signode, mode, env, symbol) - signode.append(nodes.Text(')', ')')) + signode += addnodes.desc_sig_punctuation(')', ')') class ASTIdExpression(ASTExpression): @@ -1068,9 +1071,9 @@ class ASTPostfixArray(ASTPostfixOp): def describe_signature(self, signode: TextElement, mode: str, env: "BuildEnvironment", symbol: "Symbol") -> None: - signode.append(nodes.Text('[')) + signode += addnodes.desc_sig_punctuation('[', '[') self.expr.describe_signature(signode, mode, env, symbol) - signode.append(nodes.Text(']')) + signode += addnodes.desc_sig_punctuation(']', ']') class ASTPostfixMember(ASTPostfixOp): @@ -1085,7 +1088,7 @@ class ASTPostfixMember(ASTPostfixOp): def describe_signature(self, signode: TextElement, mode: str, env: "BuildEnvironment", symbol: "Symbol") -> None: - signode.append(nodes.Text('.')) + signode += addnodes.desc_sig_punctuation('.', '.') self.name.describe_signature(signode, 'noneIsName', env, symbol) @@ -1101,7 +1104,7 @@ class ASTPostfixMemberOfPointer(ASTPostfixOp): def describe_signature(self, signode: TextElement, mode: str, env: "BuildEnvironment", symbol: "Symbol") -> None: - signode.append(nodes.Text('->')) + signode += addnodes.desc_sig_operator('->', '->') self.name.describe_signature(signode, 'noneIsName', env, symbol) @@ -1114,7 +1117,7 @@ class ASTPostfixInc(ASTPostfixOp): def describe_signature(self, signode: TextElement, mode: str, env: "BuildEnvironment", symbol: "Symbol") -> None: - signode.append(nodes.Text('++')) + signode += addnodes.desc_sig_operator('++', '++') class ASTPostfixDec(ASTPostfixOp): @@ -1126,7 +1129,7 @@ class ASTPostfixDec(ASTPostfixOp): def describe_signature(self, signode: TextElement, mode: str, env: "BuildEnvironment", symbol: "Symbol") -> None: - signode.append(nodes.Text('--')) + signode += addnodes.desc_sig_operator('--', '--') class ASTPostfixCallExpr(ASTPostfixOp): @@ -1195,13 +1198,13 @@ class ASTExplicitCast(ASTExpression): def describe_signature(self, signode: TextElement, mode: str, env: "BuildEnvironment", symbol: "Symbol") -> None: - signode.append(nodes.Text(self.cast)) - signode.append(nodes.Text('<')) + signode += addnodes.desc_sig_keyword(self.cast, self.cast) + signode += addnodes.desc_sig_punctuation('<', '<') self.typ.describe_signature(signode, mode, env, symbol) - signode.append(nodes.Text('>')) - signode.append(nodes.Text('(')) + signode += addnodes.desc_sig_punctuation('>', '>') + signode += addnodes.desc_sig_punctuation('(', '(') self.expr.describe_signature(signode, mode, env, symbol) - signode.append(nodes.Text(')')) + signode += addnodes.desc_sig_punctuation(')', ')') class ASTTypeId(ASTExpression): @@ -1218,10 +1221,10 @@ class ASTTypeId(ASTExpression): def describe_signature(self, signode: TextElement, mode: str, env: "BuildEnvironment", symbol: "Symbol") -> None: - signode.append(nodes.Text('typeid')) - signode.append(nodes.Text('(')) + signode += addnodes.desc_sig_keyword('typeid', 'typeid') + signode += addnodes.desc_sig_punctuation('(', '(') self.typeOrExpr.describe_signature(signode, mode, env, symbol) - signode.append(nodes.Text(')')) + signode += addnodes.desc_sig_punctuation(')', ')') # Unary expressions @@ -1243,9 +1246,9 @@ class ASTUnaryOpExpr(ASTExpression): def describe_signature(self, signode: TextElement, mode: str, env: "BuildEnvironment", symbol: "Symbol") -> None: - signode.append(nodes.Text(self.op)) + signode += addnodes.desc_sig_operator(self.op, self.op) if self.op[0] in 'cn': - signode.append(nodes.Text(' ')) + signode += addnodes.desc_sig_space() self.expr.describe_signature(signode, mode, env, symbol) @@ -1261,10 +1264,12 @@ class ASTSizeofParamPack(ASTExpression): def describe_signature(self, signode: TextElement, mode: str, env: "BuildEnvironment", symbol: "Symbol") -> None: - signode.append(nodes.Text('sizeof...(')) + signode += addnodes.desc_sig_keyword('sizeof', 'sizeof') + signode += addnodes.desc_sig_punctuation('...', '...') + signode += addnodes.desc_sig_punctuation('(', '(') self.identifier.describe_signature(signode, 'markType', env, symbol=symbol, prefix="", templateArgs="") - signode.append(nodes.Text(')')) + signode += addnodes.desc_sig_punctuation(')', ')') class ASTSizeofType(ASTExpression): @@ -1279,9 +1284,10 @@ class ASTSizeofType(ASTExpression): def describe_signature(self, signode: TextElement, mode: str, env: "BuildEnvironment", symbol: "Symbol") -> None: - signode.append(nodes.Text('sizeof(')) + signode += addnodes.desc_sig_keyword('sizeof', 'sizeof') + signode += addnodes.desc_sig_punctuation('(', '(') self.typ.describe_signature(signode, mode, env, symbol) - signode.append(nodes.Text(')')) + signode += addnodes.desc_sig_punctuation(')', ')') class ASTSizeofExpr(ASTExpression): @@ -1296,7 +1302,8 @@ class ASTSizeofExpr(ASTExpression): def describe_signature(self, signode: TextElement, mode: str, env: "BuildEnvironment", symbol: "Symbol") -> None: - signode.append(nodes.Text('sizeof ')) + signode += addnodes.desc_sig_keyword('sizeof', 'sizeof') + signode += addnodes.desc_sig_space() self.expr.describe_signature(signode, mode, env, symbol) @@ -1312,9 +1319,10 @@ class ASTAlignofExpr(ASTExpression): def describe_signature(self, signode: TextElement, mode: str, env: "BuildEnvironment", symbol: "Symbol") -> None: - signode.append(nodes.Text('alignof(')) + signode += addnodes.desc_sig_keyword('alignof', 'alignof') + signode += addnodes.desc_sig_punctuation('(', '(') self.typ.describe_signature(signode, mode, env, symbol) - signode.append(nodes.Text(')')) + signode += addnodes.desc_sig_punctuation(')', ')') class ASTNoexceptExpr(ASTExpression): @@ -1329,9 +1337,10 @@ class ASTNoexceptExpr(ASTExpression): def describe_signature(self, signode: TextElement, mode: str, env: "BuildEnvironment", symbol: "Symbol") -> None: - signode.append(nodes.Text('noexcept(')) + signode += addnodes.desc_sig_keyword('noexcept', 'noexcept') + signode += addnodes.desc_sig_punctuation('(', '(') self.expr.describe_signature(signode, mode, env, symbol) - signode.append(nodes.Text(')')) + signode += addnodes.desc_sig_punctuation(')', ')') class ASTNewExpr(ASTExpression): @@ -1371,8 +1380,9 @@ class ASTNewExpr(ASTExpression): def describe_signature(self, signode: TextElement, mode: str, env: "BuildEnvironment", symbol: "Symbol") -> None: if self.rooted: - signode.append(nodes.Text('::')) - signode.append(nodes.Text('new ')) + signode += addnodes.desc_sig_punctuation('::', '::') + signode += addnodes.desc_sig_keyword('new', 'new') + signode += addnodes.desc_sig_space() # TODO: placement if self.isNewTypeId: self.typ.describe_signature(signode, mode, env, symbol) @@ -1408,10 +1418,12 @@ class ASTDeleteExpr(ASTExpression): def describe_signature(self, signode: TextElement, mode: str, env: "BuildEnvironment", symbol: "Symbol") -> None: if self.rooted: - signode.append(nodes.Text('::')) - signode.append(nodes.Text('delete ')) + signode += addnodes.desc_sig_punctuation('::', '::') + signode += addnodes.desc_sig_keyword('delete', 'delete') + signode += addnodes.desc_sig_space() if self.array: - signode.append(nodes.Text('[] ')) + signode += addnodes.desc_sig_punctuation('[]', '[]') + signode += addnodes.desc_sig_space() self.expr.describe_signature(signode, mode, env, symbol) @@ -1435,9 +1447,9 @@ class ASTCastExpr(ASTExpression): def describe_signature(self, signode: TextElement, mode: str, env: "BuildEnvironment", symbol: "Symbol") -> None: - signode.append(nodes.Text('(')) + signode += addnodes.desc_sig_punctuation('(', '(') self.typ.describe_signature(signode, mode, env, symbol) - signode.append(nodes.Text(')')) + signode += addnodes.desc_sig_punctuation(')', ')') self.expr.describe_signature(signode, mode, env, symbol) @@ -1471,9 +1483,9 @@ class ASTBinOpExpr(ASTExpression): env: "BuildEnvironment", symbol: "Symbol") -> None: self.exprs[0].describe_signature(signode, mode, env, symbol) for i in range(1, len(self.exprs)): - signode.append(nodes.Text(' ')) - signode.append(nodes.Text(self.ops[i - 1])) - signode.append(nodes.Text(' ')) + signode += addnodes.desc_sig_space() + signode += addnodes.desc_sig_operator(self.ops[i - 1], self.ops[i - 1]) + signode += addnodes.desc_sig_space() self.exprs[i].describe_signature(signode, mode, env, symbol) @@ -1494,17 +1506,18 @@ class ASTBracedInitList(ASTBase): def describe_signature(self, signode: TextElement, mode: str, env: "BuildEnvironment", symbol: "Symbol") -> None: verify_description_mode(mode) - signode.append(nodes.Text('{')) + signode += addnodes.desc_sig_punctuation('{', '{') first = True for e in self.exprs: if not first: - signode.append(nodes.Text(', ')) + signode += addnodes.desc_sig_punctuation(',', ',') + signode += addnodes.desc_sig_space() else: first = False e.describe_signature(signode, mode, env, symbol) if self.trailingComma: - signode.append(nodes.Text(',')) - signode.append(nodes.Text('}')) + signode += addnodes.desc_sig_punctuation(',', ',') + signode += addnodes.desc_sig_punctuation('}', '}') class ASTAssignmentExpr(ASTExpression): @@ -1536,9 +1549,9 @@ class ASTAssignmentExpr(ASTExpression): env: "BuildEnvironment", symbol: "Symbol") -> None: self.exprs[0].describe_signature(signode, mode, env, symbol) for i in range(1, len(self.exprs)): - signode.append(nodes.Text(' ')) - signode.append(nodes.Text(self.ops[i - 1])) - signode.append(nodes.Text(' ')) + signode += addnodes.desc_sig_space() + signode += addnodes.desc_sig_operator(self.ops[i - 1], self.ops[i - 1]) + signode += addnodes.desc_sig_space() self.exprs[i].describe_signature(signode, mode, env, symbol) @@ -1563,7 +1576,8 @@ class ASTCommaExpr(ASTExpression): env: "BuildEnvironment", symbol: "Symbol") -> None: self.exprs[0].describe_signature(signode, mode, env, symbol) for i in range(1, len(self.exprs)): - signode.append(nodes.Text(', ')) + signode += addnodes.desc_sig_punctuation(',', ',') + signode += addnodes.desc_sig_space() self.exprs[i].describe_signature(signode, mode, env, symbol) @@ -1579,7 +1593,7 @@ class ASTFallbackExpr(ASTExpression): def describe_signature(self, signode: TextElement, mode: str, env: "BuildEnvironment", symbol: "Symbol") -> None: - signode += nodes.Text(self.expr) + signode += nodes.literal(self.expr, self.expr) ################################################################################ @@ -1599,24 +1613,39 @@ class ASTOperator(ASTBase): def get_id(self, version: int) -> str: raise NotImplementedError() + def _describe_identifier(self, signode: TextElement, identnode: TextElement, + env: "BuildEnvironment", symbol: "Symbol") -> None: + """Render the prefix into signode, and the last part into identnode.""" + raise NotImplementedError() + def describe_signature(self, signode: TextElement, mode: str, env: "BuildEnvironment", prefix: str, templateArgs: str, symbol: "Symbol") -> None: verify_description_mode(mode) - identifier = str(self) if mode == 'lastIsName': - signode += addnodes.desc_name(identifier, identifier) + identnode = addnodes.desc_name() + self._describe_identifier(identnode, identnode, env, symbol) + signode += identnode elif mode == 'markType': - targetText = prefix + identifier + templateArgs + targetText = prefix + str(self) + templateArgs pnode = addnodes.pending_xref('', refdomain='cpp', reftype='identifier', reftarget=targetText, modname=None, classname=None) pnode['cpp:parent_key'] = symbol.get_lookup_key() - pnode += nodes.Text(identifier) + # Render the identifier part, but collapse it into a string + # and make that the a link to this operator. + # E.g., if it is 'operator SomeType', then 'SomeType' becomes + # a link to the operator, not to 'SomeType'. + identnode = nodes.literal() + self._describe_identifier(signode, identnode, env, symbol) + txt = identnode.astext() + pnode += addnodes.desc_name(txt, txt) signode += pnode else: - signode += addnodes.desc_addname(identifier, identifier) + identnode = addnodes.desc_addname() + self._describe_identifier(identnode, identnode, env, symbol) + signode += identnode class ASTOperatorBuildIn(ASTOperator): @@ -1641,6 +1670,13 @@ class ASTOperatorBuildIn(ASTOperator): else: return 'operator' + self.op + def _describe_identifier(self, signode: TextElement, identnode: TextElement, + env: "BuildEnvironment", symbol: "Symbol") -> None: + signode += addnodes.desc_sig_keyword('operator', 'operator') + if self.op in ('new', 'new[]', 'delete', 'delete[]') or self.op[0] in "abcnox": + signode += addnodes.desc_sig_space() + identnode += addnodes.desc_sig_operator(self.op, self.op) + class ASTOperatorLiteral(ASTOperator): def __init__(self, identifier: ASTIdentifier) -> None: @@ -1655,6 +1691,12 @@ class ASTOperatorLiteral(ASTOperator): def _stringify(self, transform: StringifyTransform) -> str: return 'operator""' + transform(self.identifier) + def _describe_identifier(self, signode: TextElement, identnode: TextElement, + env: "BuildEnvironment", symbol: "Symbol") -> None: + signode += addnodes.desc_sig_keyword('operator', 'operator') + signode += addnodes.desc_sig_literal_string('""', '""') + self.identifier.describe_signature(identnode, 'markType', env, '', '', symbol) + class ASTOperatorType(ASTOperator): def __init__(self, type: "ASTType") -> None: @@ -1672,6 +1714,12 @@ class ASTOperatorType(ASTOperator): def get_name_no_template(self) -> str: return str(self) + def _describe_identifier(self, signode: TextElement, identnode: TextElement, + env: "BuildEnvironment", symbol: "Symbol") -> None: + signode += addnodes.desc_sig_keyword('operator', 'operator') + signode += addnodes.desc_sig_space() + self.type.describe_signature(identnode, 'markType', env, symbol) + class ASTTemplateArgConstant(ASTBase): def __init__(self, value: ASTExpression) -> None: @@ -1730,16 +1778,17 @@ class ASTTemplateArgs(ASTBase): def describe_signature(self, signode: TextElement, mode: str, env: "BuildEnvironment", symbol: "Symbol") -> None: verify_description_mode(mode) - signode += nodes.Text('<') + signode += addnodes.desc_sig_punctuation('<', '<') first = True for a in self.args: if not first: - signode += nodes.Text(', ') + signode += addnodes.desc_sig_punctuation(',', ',') + signode += addnodes.desc_sig_space() first = False a.describe_signature(signode, 'markType', env, symbol=symbol) if self.packExpansion: - signode += nodes.Text('...') - signode += nodes.Text('>') + signode += addnodes.desc_sig_punctuation('...', '...') + signode += addnodes.desc_sig_punctuation('>', '>') # Main part of declarations @@ -1780,7 +1829,7 @@ class ASTTrailingTypeSpecFundamental(ASTTrailingTypeSpec): def describe_signature(self, signode: TextElement, mode: str, env: "BuildEnvironment", symbol: "Symbol") -> None: - signode += nodes.Text(str(self.name)) + signode += addnodes.desc_sig_keyword_type(self.name, self.name) class ASTTrailingTypeSpecDecltypeAuto(ASTTrailingTypeSpec): @@ -1794,7 +1843,10 @@ class ASTTrailingTypeSpecDecltypeAuto(ASTTrailingTypeSpec): def describe_signature(self, signode: TextElement, mode: str, env: "BuildEnvironment", symbol: "Symbol") -> None: - signode.append(nodes.Text(str(self))) + signode += addnodes.desc_sig_keyword('decltype', 'decltype') + signode += addnodes.desc_sig_punctuation('(', '(') + signode += addnodes.desc_sig_keyword('auto', 'auto') + signode += addnodes.desc_sig_punctuation(')', ')') class ASTTrailingTypeSpecDecltype(ASTTrailingTypeSpec): @@ -1811,9 +1863,10 @@ class ASTTrailingTypeSpecDecltype(ASTTrailingTypeSpec): def describe_signature(self, signode: TextElement, mode: str, env: "BuildEnvironment", symbol: "Symbol") -> None: - signode.append(nodes.Text('decltype(')) + signode += addnodes.desc_sig_keyword('decltype', 'decltype') + signode += addnodes.desc_sig_punctuation('(', '(') self.expr.describe_signature(signode, mode, env, symbol) - signode.append(nodes.Text(')')) + signode += addnodes.desc_sig_punctuation(')', ')') class ASTTrailingTypeSpecName(ASTTrailingTypeSpec): @@ -1839,8 +1892,8 @@ class ASTTrailingTypeSpecName(ASTTrailingTypeSpec): def describe_signature(self, signode: TextElement, mode: str, env: "BuildEnvironment", symbol: "Symbol") -> None: if self.prefix: - signode += addnodes.desc_annotation(self.prefix, self.prefix) - signode += nodes.Text(' ') + signode += addnodes.desc_sig_keyword(self.prefix, self.prefix) + signode += addnodes.desc_sig_space() self.nestedName.describe_signature(signode, mode, env, symbol=symbol) @@ -1872,7 +1925,7 @@ class ASTFunctionParameter(ASTBase): env: "BuildEnvironment", symbol: "Symbol") -> None: verify_description_mode(mode) if self.ellipsis: - signode += nodes.Text('...') + signode += addnodes.desc_sig_punctuation('...', '...') else: self.arg.describe_signature(signode, mode, env, symbol=symbol) @@ -1888,18 +1941,19 @@ class ASTNoexceptSpec(ASTBase): def describe_signature(self, signode: TextElement, mode: str, env: "BuildEnvironment", symbol: "Symbol") -> None: - signode += addnodes.desc_annotation('noexcept', 'noexcept') + signode += addnodes.desc_sig_keyword('noexcept', 'noexcept') if self.expr: - signode.append(nodes.Text('(')) - self.expr.describe_signature(signode, mode, env, symbol) - signode.append(nodes.Text(')')) + signode += addnodes.desc_sig_punctuation('(', '(') + self.expr.describe_signature(signode, 'markType', env, symbol) + signode += addnodes.desc_sig_punctuation(')', ')') class ASTParametersQualifiers(ASTBase): def __init__(self, args: List[ASTFunctionParameter], volatile: bool, const: bool, - refQual: str, exceptionSpec: ASTNoexceptSpec, trailingReturn: "ASTType", + refQual: Optional[str], exceptionSpec: ASTNoexceptSpec, + trailingReturn: "ASTType", override: bool, final: bool, attrs: List[ASTAttribute], - initializer: str) -> None: + initializer: Optional[str]) -> None: self.args = args self.volatile = volatile self.const = const @@ -1988,43 +2042,51 @@ class ASTParametersQualifiers(ASTBase): paramlist += param signode += paramlist else: - signode += nodes.Text('(', '(') + signode += addnodes.desc_sig_punctuation('(', '(') first = True for arg in self.args: if not first: - signode += nodes.Text(', ', ', ') + signode += addnodes.desc_sig_punctuation(',', ',') + signode += addnodes.desc_sig_space() first = False arg.describe_signature(signode, 'markType', env, symbol=symbol) - signode += nodes.Text(')', ')') + signode += addnodes.desc_sig_punctuation(')', ')') def _add_anno(signode: TextElement, text: str) -> None: - signode += nodes.Text(' ') - signode += addnodes.desc_annotation(text, text) - - def _add_text(signode: TextElement, text: str) -> None: - signode += nodes.Text(' ' + text) + signode += addnodes.desc_sig_space() + signode += addnodes.desc_sig_keyword(text, text) if self.volatile: _add_anno(signode, 'volatile') if self.const: _add_anno(signode, 'const') if self.refQual: - _add_text(signode, self.refQual) + signode += addnodes.desc_sig_space() + signode += addnodes.desc_sig_punctuation(self.refQual, self.refQual) if self.exceptionSpec: - signode += nodes.Text(' ') + signode += addnodes.desc_sig_space() self.exceptionSpec.describe_signature(signode, mode, env, symbol) if self.trailingReturn: - signode += nodes.Text(' -> ') + signode += addnodes.desc_sig_space() + signode += addnodes.desc_sig_operator('->', '->') + signode += addnodes.desc_sig_space() self.trailingReturn.describe_signature(signode, mode, env, symbol) if self.final: _add_anno(signode, 'final') if self.override: _add_anno(signode, 'override') for attr in self.attrs: - signode += nodes.Text(' ') + signode += addnodes.desc_sig_space() attr.describe_signature(signode) if self.initializer: - _add_text(signode, '= ' + str(self.initializer)) + signode += addnodes.desc_sig_space() + signode += addnodes.desc_sig_punctuation('=', '=') + signode += addnodes.desc_sig_space() + assert self.initializer in ('0', 'delete', 'default') + if self.initializer == '0': + signode += addnodes.desc_sig_literal_number('0', '0') + else: + signode += addnodes.desc_sig_keyword(self.initializer, self.initializer) class ASTDeclSpecsSimple(ASTBase): @@ -2083,14 +2145,14 @@ class ASTDeclSpecsSimple(ASTBase): addSpace = False for attr in self.attrs: if addSpace: - signode += nodes.Text(' ') + signode += addnodes.desc_sig_space() addSpace = True attr.describe_signature(signode) def _add(signode: TextElement, text: str) -> bool: if addSpace: - signode += nodes.Text(' ') - signode += addnodes.desc_annotation(text, text) + signode += addnodes.desc_sig_space() + signode += addnodes.desc_sig_keyword(text, text) return True if self.storage: @@ -2168,7 +2230,7 @@ class ASTDeclSpecs(ASTBase): if self.trailingTypeSpec: if addSpace: - signode += nodes.Text(' ') + signode += addnodes.desc_sig_space() numChildren = len(signode) self.trailingTypeSpec.describe_signature(signode, mode, env, symbol=symbol) @@ -2176,7 +2238,7 @@ class ASTDeclSpecs(ASTBase): if len(str(self.rightSpecs)) > 0: if addSpace: - signode += nodes.Text(' ') + signode += addnodes.desc_sig_space() self.rightSpecs.describe_signature(signode) @@ -2209,10 +2271,10 @@ class ASTArray(ASTBase): def describe_signature(self, signode: TextElement, mode: str, env: "BuildEnvironment", symbol: "Symbol") -> None: verify_description_mode(mode) - signode.append(nodes.Text("[")) + signode += addnodes.desc_sig_punctuation('[', '[') if self.size: self.size.describe_signature(signode, 'markType', env, symbol) - signode.append(nodes.Text("]")) + signode += addnodes.desc_sig_punctuation(']', ']') class ASTDeclarator(ASTBase): @@ -2375,7 +2437,9 @@ class ASTDeclaratorNameBitField(ASTDeclarator): verify_description_mode(mode) if self.declId: self.declId.describe_signature(signode, mode, env, symbol) - signode.append(nodes.Text(' : ', ' : ')) + signode += addnodes.desc_sig_space() + signode += addnodes.desc_sig_punctuation(':', ':') + signode += addnodes.desc_sig_space() self.size.describe_signature(signode, mode, env, symbol) @@ -2461,23 +2525,23 @@ class ASTDeclaratorPtr(ASTDeclarator): def describe_signature(self, signode: TextElement, mode: str, env: "BuildEnvironment", symbol: "Symbol") -> None: verify_description_mode(mode) - signode += nodes.Text("*") + signode += addnodes.desc_sig_punctuation('*', '*') for a in self.attrs: a.describe_signature(signode) if len(self.attrs) > 0 and (self.volatile or self.const): - signode += nodes.Text(' ') + signode += addnodes.desc_sig_space() def _add_anno(signode: TextElement, text: str) -> None: - signode += addnodes.desc_annotation(text, text) + signode += addnodes.desc_sig_keyword(text, text) if self.volatile: _add_anno(signode, 'volatile') if self.const: if self.volatile: - signode += nodes.Text(' ') + signode += addnodes.desc_sig_space() _add_anno(signode, 'const') if self.const or self.volatile or len(self.attrs) > 0: if self.next.require_space_after_declSpecs(): - signode += nodes.Text(' ') + signode += addnodes.desc_sig_space() self.next.describe_signature(signode, mode, env, symbol) @@ -2538,11 +2602,11 @@ class ASTDeclaratorRef(ASTDeclarator): def describe_signature(self, signode: TextElement, mode: str, env: "BuildEnvironment", symbol: "Symbol") -> None: verify_description_mode(mode) - signode += nodes.Text("&") + signode += addnodes.desc_sig_punctuation('&', '&') for a in self.attrs: a.describe_signature(signode) if len(self.attrs) > 0 and self.next.require_space_after_declSpecs(): - signode += nodes.Text(' ') + signode += addnodes.desc_sig_space() self.next.describe_signature(signode, mode, env, symbol) @@ -2595,9 +2659,9 @@ class ASTDeclaratorParamPack(ASTDeclarator): def describe_signature(self, signode: TextElement, mode: str, env: "BuildEnvironment", symbol: "Symbol") -> None: verify_description_mode(mode) - signode += nodes.Text("...") + signode += addnodes.desc_sig_punctuation('...', '...') if self.next.name: - signode += nodes.Text(' ') + signode += addnodes.desc_sig_space() self.next.describe_signature(signode, mode, env, symbol) @@ -2680,18 +2744,19 @@ class ASTDeclaratorMemPtr(ASTDeclarator): env: "BuildEnvironment", symbol: "Symbol") -> None: verify_description_mode(mode) self.className.describe_signature(signode, 'markType', env, symbol) - signode += nodes.Text('::*') + signode += addnodes.desc_sig_punctuation('::', '::') + signode += addnodes.desc_sig_punctuation('*', '*') def _add_anno(signode: TextElement, text: str) -> None: - signode += addnodes.desc_annotation(text, text) + signode += addnodes.desc_sig_keyword(text, text) if self.volatile: _add_anno(signode, 'volatile') if self.const: if self.volatile: - signode += nodes.Text(' ') + signode += addnodes.desc_sig_space() _add_anno(signode, 'const') if self.next.require_space_after_declSpecs(): - signode += nodes.Text(' ') + signode += addnodes.desc_sig_space() self.next.describe_signature(signode, mode, env, symbol) @@ -2752,9 +2817,9 @@ class ASTDeclaratorParen(ASTDeclarator): def describe_signature(self, signode: TextElement, mode: str, env: "BuildEnvironment", symbol: "Symbol") -> None: verify_description_mode(mode) - signode += nodes.Text('(') + signode += addnodes.desc_sig_punctuation('(', '(') self.inner.describe_signature(signode, mode, env, symbol) - signode += nodes.Text(')') + signode += addnodes.desc_sig_punctuation(')', ')') self.next.describe_signature(signode, "noneIsName", env, symbol) @@ -2775,7 +2840,7 @@ class ASTPackExpansionExpr(ASTExpression): def describe_signature(self, signode: TextElement, mode: str, env: "BuildEnvironment", symbol: "Symbol") -> None: self.expr.describe_signature(signode, mode, env, symbol) - signode += nodes.Text('...') + signode += addnodes.desc_sig_punctuation('...', '...') class ASTParenExprList(ASTBaseParenExprList): @@ -2792,15 +2857,16 @@ class ASTParenExprList(ASTBaseParenExprList): def describe_signature(self, signode: TextElement, mode: str, env: "BuildEnvironment", symbol: "Symbol") -> None: verify_description_mode(mode) - signode.append(nodes.Text('(')) + signode += addnodes.desc_sig_punctuation('(', '(') first = True for e in self.exprs: if not first: - signode.append(nodes.Text(', ')) + signode += addnodes.desc_sig_punctuation(',', ',') + signode += addnodes.desc_sig_space() else: first = False e.describe_signature(signode, mode, env, symbol) - signode.append(nodes.Text(')')) + signode += addnodes.desc_sig_punctuation(')', ')') class ASTInitializer(ASTBase): @@ -2820,7 +2886,9 @@ class ASTInitializer(ASTBase): env: "BuildEnvironment", symbol: "Symbol") -> None: verify_description_mode(mode) if self.hasAssign: - signode.append(nodes.Text(' = ')) + signode += addnodes.desc_sig_space() + signode += addnodes.desc_sig_punctuation('=', '=') + signode += addnodes.desc_sig_space() self.value.describe_signature(signode, 'markType', env, symbol) @@ -2924,7 +2992,7 @@ class ASTType(ASTBase): self.declSpecs.describe_signature(signode, 'markType', env, symbol) if (self.decl.require_space_after_declSpecs() and len(str(self.declSpecs)) > 0): - signode += nodes.Text(' ') + signode += addnodes.desc_sig_space() # for parameters that don't really declare new names we get 'markType', # this should not be propagated, but be 'noneIsName'. if mode == 'markType': @@ -2966,7 +3034,9 @@ class ASTTemplateParamConstrainedTypeWithInit(ASTBase): env: "BuildEnvironment", symbol: "Symbol") -> None: self.type.describe_signature(signode, mode, env, symbol) if self.init: - signode += nodes.Text(" = ") + signode += addnodes.desc_sig_space() + signode += addnodes.desc_sig_punctuation('=', '=') + signode += addnodes.desc_sig_space() self.init.describe_signature(signode, mode, env, symbol) @@ -3034,7 +3104,9 @@ class ASTTypeUsing(ASTBase): verify_description_mode(mode) self.name.describe_signature(signode, mode, env, symbol=symbol) if self.type: - signode += nodes.Text(' = ') + signode += addnodes.desc_sig_space() + signode += addnodes.desc_sig_punctuation('=', '=') + signode += addnodes.desc_sig_space() self.type.describe_signature(signode, 'markType', env, symbol=symbol) @@ -3079,7 +3151,6 @@ class ASTBaseClass(ASTBase): def _stringify(self, transform: StringifyTransform) -> str: res = [] - if self.visibility is not None: res.append(self.visibility) res.append(' ') @@ -3094,15 +3165,15 @@ class ASTBaseClass(ASTBase): env: "BuildEnvironment", symbol: "Symbol") -> None: verify_description_mode(mode) if self.visibility is not None: - signode += addnodes.desc_annotation(self.visibility, - self.visibility) - signode += nodes.Text(' ') + signode += addnodes.desc_sig_keyword(self.visibility, + self.visibility) + signode += addnodes.desc_sig_space() if self.virtual: - signode += addnodes.desc_annotation('virtual', 'virtual') - signode += nodes.Text(' ') + signode += addnodes.desc_sig_keyword('virtual', 'virtual') + signode += addnodes.desc_sig_space() self.name.describe_signature(signode, 'markType', env, symbol=symbol) if self.pack: - signode += nodes.Text('...') + signode += addnodes.desc_sig_punctuation('...', '...') class ASTClass(ASTBase): @@ -3134,13 +3205,17 @@ class ASTClass(ASTBase): verify_description_mode(mode) self.name.describe_signature(signode, mode, env, symbol=symbol) if self.final: - signode += nodes.Text(' ') - signode += addnodes.desc_annotation('final', 'final') + signode += addnodes.desc_sig_space() + signode += addnodes.desc_sig_keyword('final', 'final') if len(self.bases) > 0: - signode += nodes.Text(' : ') + signode += addnodes.desc_sig_space() + signode += addnodes.desc_sig_punctuation(':', ':') + signode += addnodes.desc_sig_space() for b in self.bases: b.describe_signature(signode, mode, env, symbol=symbol) - signode += nodes.Text(', ') + signode += addnodes.desc_sig_punctuation(',', ',') + signode += addnodes.desc_sig_space() + signode.pop() signode.pop() @@ -3191,7 +3266,9 @@ class ASTEnum(ASTBase): # self.scoped has been done by the CPPEnumObject self.name.describe_signature(signode, mode, env, symbol=symbol) if self.underlyingType: - signode += nodes.Text(' : ') + signode += addnodes.desc_sig_space() + signode += addnodes.desc_sig_punctuation(':', ':') + signode += addnodes.desc_sig_space() self.underlyingType.describe_signature(signode, 'noneIsName', env, symbol=symbol) @@ -3281,17 +3358,19 @@ class ASTTemplateKeyParamPackIdDefault(ASTTemplateParam): def describe_signature(self, signode: TextElement, mode: str, env: "BuildEnvironment", symbol: "Symbol") -> None: - signode += nodes.Text(self.key) + signode += addnodes.desc_sig_keyword(self.key, self.key) if self.parameterPack: if self.identifier: - signode += nodes.Text(' ') - signode += nodes.Text('...') + signode += addnodes.desc_sig_space() + signode += addnodes.desc_sig_punctuation('...', '...') if self.identifier: if not self.parameterPack: - signode += nodes.Text(' ') + signode += addnodes.desc_sig_space() self.identifier.describe_signature(signode, mode, env, '', '', symbol) if self.default: - signode += nodes.Text(' = ') + signode += addnodes.desc_sig_space() + signode += addnodes.desc_sig_punctuation('=', '=') + signode += addnodes.desc_sig_space() self.default.describe_signature(signode, 'markType', env, symbol) @@ -3364,7 +3443,7 @@ class ASTTemplateParamTemplateType(ASTTemplateParam): def describe_signature(self, signode: TextElement, mode: str, env: "BuildEnvironment", symbol: "Symbol") -> None: self.nestedParams.describe_signature(signode, 'noneIsName', env, symbol) - signode += nodes.Text(' ') + signode += addnodes.desc_sig_space() self.data.describe_signature(signode, mode, env, symbol) @@ -3436,14 +3515,16 @@ class ASTTemplateParams(ASTBase): def describe_signature(self, signode: TextElement, mode: str, env: "BuildEnvironment", symbol: "Symbol") -> None: - signode += nodes.Text("template<") + signode += addnodes.desc_sig_keyword('template', 'template') + signode += addnodes.desc_sig_punctuation('<', '<') first = True for param in self.params: if not first: - signode += nodes.Text(", ") + signode += addnodes.desc_sig_punctuation(',', ',') + signode += addnodes.desc_sig_space() first = False param.describe_signature(signode, mode, env, symbol) - signode += nodes.Text(">") + signode += addnodes.desc_sig_punctuation('>', '>') def describe_signature_as_introducer( self, parentNode: desc_signature, mode: str, env: "BuildEnvironment", @@ -3454,18 +3535,20 @@ class ASTTemplateParams(ASTBase): signode.sphinx_line_type = 'templateParams' return signode lineNode = makeLine(parentNode) - lineNode += nodes.Text("template<") + lineNode += addnodes.desc_sig_keyword('template', 'template') + lineNode += addnodes.desc_sig_punctuation('<', '<') first = True for param in self.params: if not first: - lineNode += nodes.Text(", ") + lineNode += addnodes.desc_sig_punctuation(',', ',') + lineNode += addnodes.desc_sig_space() first = False if lineSpec: lineNode = makeLine(parentNode) param.describe_signature(lineNode, mode, env, symbol) if lineSpec and not first: lineNode = makeLine(parentNode) - lineNode += nodes.Text(">") + lineNode += addnodes.desc_sig_punctuation('>', '>') # Template introducers @@ -3519,7 +3602,7 @@ class ASTTemplateIntroductionParameter(ASTBase): def describe_signature(self, signode: TextElement, mode: str, env: "BuildEnvironment", symbol: "Symbol") -> None: if self.parameterPack: - signode += nodes.Text('...') + signode += addnodes.desc_sig_punctuation('...', '...') self.identifier.describe_signature(signode, mode, env, '', '', symbol) @@ -3564,14 +3647,15 @@ class ASTTemplateIntroduction(ASTBase): parentNode += signode signode.sphinx_line_type = 'templateIntroduction' self.concept.describe_signature(signode, 'markType', env, symbol) - signode += nodes.Text('{') + signode += addnodes.desc_sig_punctuation('{', '{') first = True for param in self.params: if not first: - signode += nodes.Text(', ') + signode += addnodes.desc_sig_punctuation(',', ',') + signode += addnodes.desc_sig_space() first = False param.describe_signature(signode, mode, env, symbol) - signode += nodes.Text('}') + signode += addnodes.desc_sig_punctuation('}', '}') ################################################################################ @@ -3613,7 +3697,8 @@ class ASTRequiresClause(ASTBase): def describe_signature(self, signode: addnodes.desc_signature_line, mode: str, env: "BuildEnvironment", symbol: "Symbol") -> None: - signode += nodes.Text('requires ', 'requires ') + signode += addnodes.desc_sig_keyword('requires', 'requires') + signode += addnodes.desc_sig_space() self.expr.describe_signature(signode, mode, env, symbol) @@ -3733,39 +3818,42 @@ class ASTDeclaration(ASTBase): self.requiresClause.describe_signature(reqNode, 'markType', env, self.symbol) signode += mainDeclNode if self.visibility and self.visibility != "public": - mainDeclNode += addnodes.desc_annotation(self.visibility + " ", - self.visibility + " ") + mainDeclNode += addnodes.desc_sig_keyword(self.visibility, self.visibility) + mainDeclNode += addnodes.desc_sig_space() if self.objectType == 'type': prefix = self.declaration.get_type_declaration_prefix() - prefix += ' ' - mainDeclNode += addnodes.desc_annotation(prefix, prefix) + mainDeclNode += addnodes.desc_sig_keyword(prefix, prefix) + mainDeclNode += addnodes.desc_sig_space() elif self.objectType == 'concept': - mainDeclNode += addnodes.desc_annotation('concept ', 'concept ') + mainDeclNode += addnodes.desc_sig_keyword('concept', 'concept') + mainDeclNode += addnodes.desc_sig_space() elif self.objectType == 'member': pass elif self.objectType == 'function': pass elif self.objectType == 'class': assert self.directiveType in ('class', 'struct') - prefix = self.directiveType + ' ' - mainDeclNode += addnodes.desc_annotation(prefix, prefix) + mainDeclNode += addnodes.desc_sig_keyword(self.directiveType, self.directiveType) + mainDeclNode += addnodes.desc_sig_space() elif self.objectType == 'union': - mainDeclNode += addnodes.desc_annotation('union ', 'union ') + mainDeclNode += addnodes.desc_sig_keyword('union', 'union') + mainDeclNode += addnodes.desc_sig_space() elif self.objectType == 'enum': - if self.directiveType == 'enum': - prefix = 'enum ' - elif self.directiveType == 'enum-class': - prefix = 'enum class ' + mainDeclNode += addnodes.desc_sig_keyword('enum', 'enum') + mainDeclNode += addnodes.desc_sig_space() + if self.directiveType == 'enum-class': + mainDeclNode += addnodes.desc_sig_keyword('class', 'class') + mainDeclNode += addnodes.desc_sig_space() elif self.directiveType == 'enum-struct': - prefix = 'enum struct ' + mainDeclNode += addnodes.desc_sig_keyword('struct', 'struct') + mainDeclNode += addnodes.desc_sig_space() else: - assert False # wrong directiveType used - mainDeclNode += addnodes.desc_annotation(prefix, prefix) + assert self.directiveType == 'enum', self.directiveType elif self.objectType == 'enumerator': - mainDeclNode += addnodes.desc_annotation('enumerator ', 'enumerator ') + mainDeclNode += addnodes.desc_sig_keyword('enumerator', 'enumerator') + mainDeclNode += addnodes.desc_sig_space() else: - print(self.objectType) - assert False + assert False, self.objectType self.declaration.describe_signature(mainDeclNode, mode, env, self.symbol) lastDeclNode = mainDeclNode if self.trailingRequiresClause: @@ -3776,7 +3864,7 @@ class ASTDeclaration(ASTBase): self.trailingRequiresClause.describe_signature( trailingReqNode, 'markType', env, self.symbol) if self.semicolon: - lastDeclNode += nodes.Text(';') + lastDeclNode += addnodes.desc_sig_punctuation(';', ';') class ASTNamespace(ASTBase): @@ -7604,9 +7692,10 @@ class CPPDomain(Domain): title += '()' * addParen # and reconstruct the title again contnode += nodes.Text(title) - return make_refnode(builder, fromdocname, docname, + res = make_refnode(builder, fromdocname, docname, declaration.get_newest_id(), contnode, displayName ), declaration.objectType + return res def resolve_xref(self, env: BuildEnvironment, fromdocname: str, builder: Builder, typ: str, target: str, node: pending_xref, contnode: Element diff --git a/sphinx/themes/basic/static/basic.css_t b/sphinx/themes/basic/static/basic.css_t index 6264f20d2..4af85bea9 100644 --- a/sphinx/themes/basic/static/basic.css_t +++ b/sphinx/themes/basic/static/basic.css_t @@ -508,6 +508,30 @@ table.hlist td { vertical-align: top; } +/* -- object description styles --------------------------------------------- */ + +.sig-name, code.descname { + background-color: transparent; + font-weight: bold; + font-size: 1.2em; +} + +.sig-prename, code.descclassname { + background-color: transparent; +} + +.optional { + font-size: 1.3em; +} + +.sig-paren { + font-size: larger; +} + +.sig-param.n { + font-style: italic; +} + /* -- other body styles ----------------------------------------------------- */ @@ -634,14 +658,6 @@ dl.glossary dt { font-size: 1.1em; } -.optional { - font-size: 1.3em; -} - -.sig-paren { - font-size: larger; -} - .versionmodified { font-style: italic; } @@ -786,16 +802,6 @@ div.literal-block-wrapper { margin: 1em 0; } -code.descname { - background-color: transparent; - font-weight: bold; - font-size: 1.2em; -} - -code.descclassname { - background-color: transparent; -} - code.xref, a code { background-color: transparent; font-weight: bold; diff --git a/sphinx/transforms/post_transforms/__init__.py b/sphinx/transforms/post_transforms/__init__.py index 653097cd8..76a709f5f 100644 --- a/sphinx/transforms/post_transforms/__init__.py +++ b/sphinx/transforms/post_transforms/__init__.py @@ -209,10 +209,6 @@ class SigElementFallbackTransform(SphinxPostTransform): """Fallback desc_sig_element nodes to inline if translator does not supported them.""" default_priority = 200 - SIG_ELEMENTS = [addnodes.desc_sig_name, - addnodes.desc_sig_operator, - addnodes.desc_sig_punctuation] - def run(self, **kwargs: Any) -> None: def has_visitor(translator: Type[nodes.NodeVisitor], node: Type[Element]) -> bool: return hasattr(translator, "visit_%s" % node.__name__) @@ -222,7 +218,7 @@ class SigElementFallbackTransform(SphinxPostTransform): # subclass of SphinxTranslator supports desc_sig_element nodes automatically. return - if all(has_visitor(translator, node) for node in self.SIG_ELEMENTS): + if all(has_visitor(translator, node) for node in addnodes.SIG_ELEMENTS): # the translator supports all desc_sig_element nodes return else: diff --git a/tests/test_domain_cpp.py b/tests/test_domain_cpp.py index edd5ea5bc..7ecf89f54 100644 --- a/tests/test_domain_cpp.py +++ b/tests/test_domain_cpp.py @@ -73,6 +73,7 @@ def _check(name, input, idDict, output, key, asTextOutput): print("Input: ", input) print("astext(): ", resAsText) print("Expected: ", outputAsText) + print("Node:", parentNode) raise DefinitionError("") idExpected = [None] @@ -743,6 +744,9 @@ def test_anon_definitions(): check('class', '@1', {3: "Ut1_1"}, asTextOutput='class [anonymous]') check('class', '@a::A', {3: "NUt1_a1AE"}, asTextOutput='class [anonymous]::A') + check('function', 'int f(int @a)', {1: 'f__i', 2: '1fi'}, + asTextOutput='int f(int [anonymous])') + def test_templates(): check('class', "A", {2: "IE1AI1TE"}, output="template<> {key}A") diff --git a/tests/test_ext_intersphinx.py b/tests/test_ext_intersphinx.py index 523ed2acc..785faed62 100644 --- a/tests/test_ext_intersphinx.py +++ b/tests/test_ext_intersphinx.py @@ -258,10 +258,10 @@ def test_missing_reference_cppdomain(tempdir, app, status, warning): 'Bar' in html) assert ('foons' in html) + ' title="(in foo v2.0)">foons' in html) assert ('bartype' in html) + ' title="(in foo v2.0)">bartype' in html) def test_missing_reference_jsdomain(tempdir, app, status, warning): From 3c9a74cb0b9e5ca90adfb1ee55b2262717fae223 Mon Sep 17 00:00:00 2001 From: Jakob Lykke Andersen Date: Sat, 20 Mar 2021 16:16:14 +0100 Subject: [PATCH 02/22] Decl styling, docs and restructuring --- doc/extdev/nodes.rst | 17 +++++++++-- sphinx/addnodes.py | 63 ++++++++++++++++++++++++++++------------- sphinx/writers/html5.py | 22 ++++++++++---- 3 files changed, 74 insertions(+), 28 deletions(-) diff --git a/doc/extdev/nodes.rst b/doc/extdev/nodes.rst index 3976de4c7..d327e1cb0 100644 --- a/doc/extdev/nodes.rst +++ b/doc/extdev/nodes.rst @@ -8,18 +8,31 @@ Doctree node classes added by Sphinx Nodes for domain-specific object descriptions --------------------------------------------- +Top-level nodes +............... + +These nodes form the top-most levels of object descriptions. + .. autoclass:: desc .. autoclass:: desc_signature .. autoclass:: desc_signature_line +.. autoclass:: desc_content + +Nodes for high-level structure in signatures +............................................ + +These nodes occur in in non-multiline :py:class:`desc_signature` nodes +and in :py:class:`desc_signature_line` nodes. + +.. autoclass:: desc_name .. autoclass:: desc_addname + .. autoclass:: desc_type .. autoclass:: desc_returns -.. autoclass:: desc_name .. autoclass:: desc_parameterlist .. autoclass:: desc_parameter .. autoclass:: desc_optional .. autoclass:: desc_annotation -.. autoclass:: desc_content New admonition-like constructs ------------------------------ diff --git a/sphinx/addnodes.py b/sphinx/addnodes.py index 3200e5e47..f818e496d 100644 --- a/sphinx/addnodes.py +++ b/sphinx/addnodes.py @@ -115,24 +115,32 @@ class toctree(nodes.General, nodes.Element, translatable): return messages -# domain-specific object descriptions (class, function etc.) +############################################################# +# Domain-specific object descriptions (class, function etc.) +############################################################# + +# Top-level nodes +################# class desc(nodes.Admonition, nodes.Element): - """Node for object descriptions. + """Node for a list of object signatures and a common description of them. - This node is similar to a "definition list" with one definition. It - contains one or more ``desc_signature`` and a ``desc_content``. + Contains one or more :py:class:`desc_signature` nodes + and then a single :py:class:`desc_content` node. + + This node always has two classes: + + - The name of the domain it belongs to, e.g., ``py`` or ``cpp``. + - The name of the object type in the domain, e.g., ``function``. """ class desc_signature(nodes.Part, nodes.Inline, nodes.TextElement): - """Node for object signatures. + """Node for a single object signature. - The "term" part of the custom Sphinx definition list. - - As default the signature is a single line signature, - but set ``is_multiline = True`` to describe a multi-line signature. - In that case all child nodes must be ``desc_signature_line`` nodes. + As default the signature is a single-line signature. + Set ``is_multiline = True`` to describe a multi-line signature. + In that case all child nodes must be :py:class:`desc_signature_line` nodes. """ @property @@ -144,22 +152,40 @@ class desc_signature(nodes.Part, nodes.Inline, nodes.TextElement): class desc_signature_line(nodes.Part, nodes.Inline, nodes.FixedTextElement): - """Node for a line in a multi-line object signatures. + """Node for a line in a multi-line object signature. - It should only be used in a ``desc_signature`` with ``is_multiline`` set. + It should only be used as a child of a :py:class:`desc_signature` + with ``is_multiline`` set to ``True``. Set ``add_permalink = True`` for the line that should get the permalink. """ sphinx_line_type = '' +class desc_content(nodes.General, nodes.Element): + """Node for object description content. + + Must be the last child node in a :py:class:`desc` node. + """ + +# Nodes for high-level structure in signatures +############################################## + # nodes to use within a desc_signature or desc_signature_line class desc_name(nodes.Part, nodes.Inline, nodes.FixedTextElement): - """Node for the main object name.""" + """Node for the main object name. + + For example, in the declaration of a Python class ``MyModule.MyClass``, + the main name is ``MyClass``. + """ class desc_addname(nodes.Part, nodes.Inline, nodes.FixedTextElement): - """Node for additional name parts (module name, class name).""" + """Node for additional name parts for an object. + + For example, in the declaration of a Python class ``MyModule.MyClass``, + the additional name part is ``MyModule.``. + """ # compatibility alias @@ -201,12 +227,8 @@ class desc_annotation(nodes.Part, nodes.Inline, nodes.FixedTextElement): """Node for signature annotations (not Python 3-style annotations).""" -class desc_content(nodes.General, nodes.Element): - """Node for object description content. - - This is the "definition" part of the custom Sphinx definition list. - """ - +# Leaf nodes for markup of text fragments +######################################### # Signature text elements, generally translated to node.inline # in SigElementFallbackTransform. @@ -281,6 +303,7 @@ SIG_ELEMENTS = [desc_sig_space, desc_sig_literal_number, desc_sig_literal_string, desc_sig_literal_char] +############################################################### # new admonition-like constructs class versionmodified(nodes.Admonition, nodes.TextElement): diff --git a/sphinx/writers/html5.py b/sphinx/writers/html5.py index fa7360c4e..745e76b38 100644 --- a/sphinx/writers/html5.py +++ b/sphinx/writers/html5.py @@ -78,6 +78,13 @@ class HTML5Translator(SphinxTranslator, BaseTranslator): def depart_start_of_file(self, node: Element) -> None: self.docnames.pop() + ############################################################# + # Domain-specific object descriptions + ############################################################# + + # Top-level nodes for descriptions + ################################## + def visit_desc(self, node: Element) -> None: self.body.append(self.starttag(node, 'dl', CLASS=node['objtype'])) @@ -104,6 +111,15 @@ class HTML5Translator(SphinxTranslator, BaseTranslator): self.add_permalink_ref(node.parent, _('Permalink to this definition')) self.body.append('
') + # Nodes for high-level structure in signatures + ############################################## + + def visit_desc_name(self, node: Element) -> None: + self.body.append(self.starttag(node, 'code', '', CLASS='sig-name descname')) + + def depart_desc_name(self, node: Element) -> None: + self.body.append('') + def visit_desc_addname(self, node: Element) -> None: self.body.append(self.starttag(node, 'code', '', CLASS='sig-prename descclassname')) @@ -122,12 +138,6 @@ class HTML5Translator(SphinxTranslator, BaseTranslator): def depart_desc_returns(self, node: Element) -> None: pass - def visit_desc_name(self, node: Element) -> None: - self.body.append(self.starttag(node, 'code', '', CLASS='sig-name descname')) - - def depart_desc_name(self, node: Element) -> None: - self.body.append('') - def visit_desc_parameterlist(self, node: Element) -> None: self.body.append('(') self.first_param = 1 From d131ec7acbc2026c0cc05c58fa39f3d845f3e6ba Mon Sep 17 00:00:00 2001 From: Jakob Lykke Andersen Date: Sat, 20 Mar 2021 16:25:09 +0100 Subject: [PATCH 03/22] Decl styling, move desc dynamic classes to domain base class --- sphinx/addnodes.py | 3 +++ sphinx/directives/__init__.py | 1 + sphinx/writers/html.py | 24 ++++++++++++++++++------ sphinx/writers/html5.py | 14 ++++++++------ 4 files changed, 30 insertions(+), 12 deletions(-) diff --git a/sphinx/addnodes.py b/sphinx/addnodes.py index f818e496d..ac41dd951 100644 --- a/sphinx/addnodes.py +++ b/sphinx/addnodes.py @@ -134,6 +134,9 @@ class desc(nodes.Admonition, nodes.Element): - The name of the object type in the domain, e.g., ``function``. """ + # TODO: can we introduce a constructor + # that forces the specification of the domain and objtyp? + class desc_signature(nodes.Part, nodes.Inline, nodes.TextElement): """Node for a single object signature. diff --git a/sphinx/directives/__init__.py b/sphinx/directives/__init__.py index e1ccc8be7..8e8d65f03 100644 --- a/sphinx/directives/__init__.py +++ b/sphinx/directives/__init__.py @@ -172,6 +172,7 @@ class ObjectDescription(SphinxDirective, Generic[T]): node['noindex'] = noindex = ('noindex' in self.options) if self.domain: node['classes'].append(self.domain) + node['classes'].append(node['objtype']) self.names: List[T] = [] signatures = self.get_signatures() diff --git a/sphinx/writers/html.py b/sphinx/writers/html.py index a92927cab..73e762c42 100644 --- a/sphinx/writers/html.py +++ b/sphinx/writers/html.py @@ -107,8 +107,15 @@ class HTMLTranslator(SphinxTranslator, BaseTranslator): def depart_start_of_file(self, node: Element) -> None: self.docnames.pop() + ############################################################# + # Domain-specific object descriptions + ############################################################# + + # Top-level nodes for descriptions + ################################## + def visit_desc(self, node: Element) -> None: - self.body.append(self.starttag(node, 'dl', CLASS=node['objtype'])) + self.body.append(self.starttag(node, 'dl')) def depart_desc(self, node: Element) -> None: self.body.append('\n\n') @@ -133,6 +140,15 @@ class HTMLTranslator(SphinxTranslator, BaseTranslator): self.add_permalink_ref(node.parent, _('Permalink to this definition')) self.body.append('
') + def visit_desc_content(self, node: Element) -> None: + self.body.append(self.starttag(node, 'dd', '')) + + def depart_desc_content(self, node: Element) -> None: + self.body.append('') + + # Nodes for high-level structure in signatures + ############################################## + def visit_desc_addname(self, node: Element) -> None: self.body.append(self.starttag(node, 'code', '', CLASS='descclassname')) @@ -205,11 +221,7 @@ class HTMLTranslator(SphinxTranslator, BaseTranslator): def depart_desc_annotation(self, node: Element) -> None: self.body.append('') - def visit_desc_content(self, node: Element) -> None: - self.body.append(self.starttag(node, 'dd', '')) - - def depart_desc_content(self, node: Element) -> None: - self.body.append('') + ############################################## def visit_versionmodified(self, node: Element) -> None: self.body.append(self.starttag(node, 'div', CLASS=node['type'])) diff --git a/sphinx/writers/html5.py b/sphinx/writers/html5.py index 745e76b38..c3c082967 100644 --- a/sphinx/writers/html5.py +++ b/sphinx/writers/html5.py @@ -86,7 +86,7 @@ class HTML5Translator(SphinxTranslator, BaseTranslator): ################################## def visit_desc(self, node: Element) -> None: - self.body.append(self.starttag(node, 'dl', CLASS=node['objtype'])) + self.body.append(self.starttag(node, 'dl')) def depart_desc(self, node: Element) -> None: self.body.append('\n\n') @@ -111,6 +111,12 @@ class HTML5Translator(SphinxTranslator, BaseTranslator): self.add_permalink_ref(node.parent, _('Permalink to this definition')) self.body.append('
') + def visit_desc_content(self, node: Element) -> None: + self.body.append(self.starttag(node, 'dd', '')) + + def depart_desc_content(self, node: Element) -> None: + self.body.append('') + # Nodes for high-level structure in signatures ############################################## @@ -186,11 +192,7 @@ class HTML5Translator(SphinxTranslator, BaseTranslator): def depart_desc_annotation(self, node: Element) -> None: self.body.append('') - def visit_desc_content(self, node: Element) -> None: - self.body.append(self.starttag(node, 'dd', '')) - - def depart_desc_content(self, node: Element) -> None: - self.body.append('') + ############################################## def visit_versionmodified(self, node: Element) -> None: self.body.append(self.starttag(node, 'div', CLASS=node['type'])) From e012c93f1b69d943fe481982dce6d9dcf317ed51 Mon Sep 17 00:00:00 2001 From: Jakob Lykke Andersen Date: Sat, 20 Mar 2021 16:42:00 +0100 Subject: [PATCH 04/22] Decl styling, move static classes to addnodes from HTML5 writer --- sphinx/addnodes.py | 25 ++++++++++++++++++++++--- sphinx/writers/html.py | 14 +++++++------- sphinx/writers/html5.py | 4 ++-- 3 files changed, 31 insertions(+), 12 deletions(-) diff --git a/sphinx/addnodes.py b/sphinx/addnodes.py index ac41dd951..17f579c0e 100644 --- a/sphinx/addnodes.py +++ b/sphinx/addnodes.py @@ -119,6 +119,19 @@ class toctree(nodes.General, nodes.Element, translatable): # Domain-specific object descriptions (class, function etc.) ############################################################# +class _desc_classes_injector: + """Helper base class for injecting a fixes list of classes. + + Use as the first base class. + """ + + classes = [] # type: List[str] + + def __init__(self, *args, **kwargs) -> None: + super().__init__(*args, **kwargs) + self['classes'].extend(self.classes) + + # Top-level nodes ################# @@ -175,20 +188,26 @@ class desc_content(nodes.General, nodes.Element): # nodes to use within a desc_signature or desc_signature_line -class desc_name(nodes.Part, nodes.Inline, nodes.FixedTextElement): +class desc_name(_desc_classes_injector, nodes.Part, nodes.Inline, nodes.FixedTextElement): """Node for the main object name. For example, in the declaration of a Python class ``MyModule.MyClass``, the main name is ``MyClass``. + + This node always has the class ``sig-name``. """ + classes = ['sig-name', 'descname'] # 'descname' is for backwards compatibility -class desc_addname(nodes.Part, nodes.Inline, nodes.FixedTextElement): +class desc_addname(_desc_classes_injector, nodes.Part, nodes.Inline, nodes.FixedTextElement): """Node for additional name parts for an object. For example, in the declaration of a Python class ``MyModule.MyClass``, the additional name part is ``MyModule.``. + + This node always has the class ``sig-prename``. """ + classes = ['sig-prename', 'descclassname'] # 'descclassname' is for backwards compatibility # compatibility alias @@ -237,7 +256,7 @@ class desc_annotation(nodes.Part, nodes.Inline, nodes.FixedTextElement): # in SigElementFallbackTransform. # When adding a new one, add it to SIG_ELEMENTS. -class desc_sig_element(nodes.inline): +class desc_sig_element(nodes.inline, _desc_classes_injector): """Common parent class of nodes for inline text of a signature.""" classes: List[str] = [] diff --git a/sphinx/writers/html.py b/sphinx/writers/html.py index 73e762c42..54d7311ea 100644 --- a/sphinx/writers/html.py +++ b/sphinx/writers/html.py @@ -149,8 +149,14 @@ class HTMLTranslator(SphinxTranslator, BaseTranslator): # Nodes for high-level structure in signatures ############################################## + def visit_desc_name(self, node: Element) -> None: + self.body.append(self.starttag(node, 'code', '')) + + def depart_desc_name(self, node: Element) -> None: + self.body.append('') + def visit_desc_addname(self, node: Element) -> None: - self.body.append(self.starttag(node, 'code', '', CLASS='descclassname')) + self.body.append(self.starttag(node, 'code', '')) def depart_desc_addname(self, node: Element) -> None: self.body.append('') @@ -167,12 +173,6 @@ class HTMLTranslator(SphinxTranslator, BaseTranslator): def depart_desc_returns(self, node: Element) -> None: pass - def visit_desc_name(self, node: Element) -> None: - self.body.append(self.starttag(node, 'code', '', CLASS='descname')) - - def depart_desc_name(self, node: Element) -> None: - self.body.append('') - def visit_desc_parameterlist(self, node: Element) -> None: self.body.append('(') self.first_param = 1 diff --git a/sphinx/writers/html5.py b/sphinx/writers/html5.py index c3c082967..e3a28f85d 100644 --- a/sphinx/writers/html5.py +++ b/sphinx/writers/html5.py @@ -121,13 +121,13 @@ class HTML5Translator(SphinxTranslator, BaseTranslator): ############################################## def visit_desc_name(self, node: Element) -> None: - self.body.append(self.starttag(node, 'code', '', CLASS='sig-name descname')) + self.body.append(self.starttag(node, 'code', '')) def depart_desc_name(self, node: Element) -> None: self.body.append('') def visit_desc_addname(self, node: Element) -> None: - self.body.append(self.starttag(node, 'code', '', CLASS='sig-prename descclassname')) + self.body.append(self.starttag(node, 'code', '')) def depart_desc_addname(self, node: Element) -> None: self.body.append('') From 98800be904eeb4aca33acaac60a06e42b181d0f3 Mon Sep 17 00:00:00 2001 From: Jakob Lykke Andersen Date: Sat, 20 Mar 2021 17:19:34 +0100 Subject: [PATCH 05/22] Decl styling, make desc_inline node Use the new node for cpp:expr --- CHANGES | 3 +++ doc/extdev/nodes.rst | 1 + sphinx/addnodes.py | 30 +++++++++++++++++++++++--- sphinx/domains/cpp.py | 7 ++---- sphinx/themes/basic/static/basic.css_t | 6 ++++++ sphinx/writers/html5.py | 6 ++++++ 6 files changed, 45 insertions(+), 8 deletions(-) diff --git a/CHANGES b/CHANGES index 2743788ac..fe87bf9b9 100644 --- a/CHANGES +++ b/CHANGES @@ -7,6 +7,9 @@ Dependencies Incompatible changes -------------------- +* #9023: Change the CSS classes on :rst:role:`cpp:expr` and + :rst:role:`cpp:texpr`. + Deprecated ---------- diff --git a/doc/extdev/nodes.rst b/doc/extdev/nodes.rst index d327e1cb0..77872df40 100644 --- a/doc/extdev/nodes.rst +++ b/doc/extdev/nodes.rst @@ -17,6 +17,7 @@ These nodes form the top-most levels of object descriptions. .. autoclass:: desc_signature .. autoclass:: desc_signature_line .. autoclass:: desc_content +.. autoclass:: desc_inline Nodes for high-level structure in signatures ............................................ diff --git a/sphinx/addnodes.py b/sphinx/addnodes.py index 17f579c0e..2d117d7a9 100644 --- a/sphinx/addnodes.py +++ b/sphinx/addnodes.py @@ -151,13 +151,16 @@ class desc(nodes.Admonition, nodes.Element): # that forces the specification of the domain and objtyp? -class desc_signature(nodes.Part, nodes.Inline, nodes.TextElement): +class desc_signature(_desc_classes_injector, nodes.Part, nodes.Inline, nodes.TextElement): """Node for a single object signature. As default the signature is a single-line signature. Set ``is_multiline = True`` to describe a multi-line signature. In that case all child nodes must be :py:class:`desc_signature_line` nodes. + + This node always has the classes ``sig`` and ``sig-object``. """ + classes = ['sig', 'sig-object'] @property def child_text_separator(self): @@ -183,6 +186,22 @@ class desc_content(nodes.General, nodes.Element): Must be the last child node in a :py:class:`desc` node. """ + +class desc_inline(_desc_classes_injector, nodes.Inline, nodes.TextElement): + """Node for a signature fragment in inline text. + + This is for example used for roles like :rst:role:`cpp:expr`. + + This node always has the classes ``sig``, ``sig-inline``, + and the name of the domain it belongs to. + """ + classes = ['sig', 'sig-inline'] + + def __init__(self, domain: str, *args, **kwargs): + super().__init__(*args, **kwargs) + self['classes'].append(domain) + + # Nodes for high-level structure in signatures ############################################## @@ -507,20 +526,25 @@ class manpage(nodes.Inline, nodes.FixedTextElement): def setup(app: "Sphinx") -> Dict[str, Any]: app.add_node(toctree) + app.add_node(desc) app.add_node(desc_signature) app.add_node(desc_signature_line) + app.add_node(desc_content) + app.add_node(desc_inline) + + app.add_node(desc_name) app.add_node(desc_addname) app.add_node(desc_type) app.add_node(desc_returns) - app.add_node(desc_name) app.add_node(desc_parameterlist) app.add_node(desc_parameter) app.add_node(desc_optional) app.add_node(desc_annotation) - app.add_node(desc_content) + for n in SIG_ELEMENTS: app.add_node(n) + app.add_node(versionmodified) app.add_node(seealso) app.add_node(productionlist) diff --git a/sphinx/domains/cpp.py b/sphinx/domains/cpp.py index bb11138d6..51cdd3946 100644 --- a/sphinx/domains/cpp.py +++ b/sphinx/domains/cpp.py @@ -7395,11 +7395,9 @@ class CPPExprRole(SphinxRole): if asCode: # render the expression as inline code self.class_type = 'cpp-expr' - self.node_type: Type[TextElement] = nodes.literal else: # render the expression as inline text self.class_type = 'cpp-texpr' - self.node_type = nodes.inline def run(self) -> Tuple[List[Node], List[system_message]]: text = self.text.replace('\n', ' ') @@ -7407,20 +7405,19 @@ class CPPExprRole(SphinxRole): location=self.get_source_info(), config=self.config) # attempt to mimic XRefRole classes, except that... - classes = ['xref', 'cpp', self.class_type] try: ast = parser.parse_expression() except DefinitionError as ex: logger.warning('Unparseable C++ expression: %r\n%s', text, ex, location=self.get_source_info()) # see below - return [self.node_type(text, text, classes=classes)], [] + return [addnodes.desc_inline('cpp', text, text, classes=[self.class_type])], [] parentSymbol = self.env.temp_data.get('cpp:parent_symbol', None) if parentSymbol is None: parentSymbol = self.env.domaindata['cpp']['root_symbol'] # ...most if not all of these classes should really apply to the individual references, # not the container node - signode = self.node_type(classes=classes) + signode = addnodes.desc_inline('cpp', classes=[self.class_type]) ast.describe_signature(signode, 'markType', self.env, parentSymbol) return [signode], [] diff --git a/sphinx/themes/basic/static/basic.css_t b/sphinx/themes/basic/static/basic.css_t index 4af85bea9..f0ce51e4b 100644 --- a/sphinx/themes/basic/static/basic.css_t +++ b/sphinx/themes/basic/static/basic.css_t @@ -532,6 +532,12 @@ table.hlist td { font-style: italic; } +/* C++ specific styling */ + +.sig-inline.cpp-expr { + font-family: monospace; +} + /* -- other body styles ----------------------------------------------------- */ diff --git a/sphinx/writers/html5.py b/sphinx/writers/html5.py index e3a28f85d..1c81584e3 100644 --- a/sphinx/writers/html5.py +++ b/sphinx/writers/html5.py @@ -117,6 +117,12 @@ class HTML5Translator(SphinxTranslator, BaseTranslator): def depart_desc_content(self, node: Element) -> None: self.body.append('') + def visit_desc_inline(self, node: Element) -> None: + self.body.append(self.starttag(node, 'span', '')) + + def depart_desc_inline(self, node: Element) -> None: + self.body.append('') + # Nodes for high-level structure in signatures ############################################## From b0a2e5cf040ab3ddb64ebc0ee4f60b59fa30eef9 Mon Sep 17 00:00:00 2001 From: Jakob Lykke Andersen Date: Sat, 20 Mar 2021 17:42:26 +0100 Subject: [PATCH 06/22] Decl styling, consistent monospace --- CHANGES | 2 ++ sphinx/themes/basic/static/basic.css_t | 8 ++++++-- sphinx/writers/html5.py | 8 ++++---- 3 files changed, 12 insertions(+), 6 deletions(-) diff --git a/CHANGES b/CHANGES index fe87bf9b9..28e89863f 100644 --- a/CHANGES +++ b/CHANGES @@ -16,6 +16,8 @@ Deprecated Features added -------------- +* #9023: More CSS classes on domain descriptions, see :ref:`nodes` for details. + Bugs fixed ---------- diff --git a/sphinx/themes/basic/static/basic.css_t b/sphinx/themes/basic/static/basic.css_t index f0ce51e4b..de7651e17 100644 --- a/sphinx/themes/basic/static/basic.css_t +++ b/sphinx/themes/basic/static/basic.css_t @@ -510,6 +510,10 @@ table.hlist td { /* -- object description styles --------------------------------------------- */ +.sig { + font-family: monospace; +} + .sig-name, code.descname { background-color: transparent; font-weight: bold; @@ -534,8 +538,8 @@ table.hlist td { /* C++ specific styling */ -.sig-inline.cpp-expr { - font-family: monospace; +.sig-inline.cpp-texpr { + font-family: unset; } diff --git a/sphinx/writers/html5.py b/sphinx/writers/html5.py index 1c81584e3..469642591 100644 --- a/sphinx/writers/html5.py +++ b/sphinx/writers/html5.py @@ -127,16 +127,16 @@ class HTML5Translator(SphinxTranslator, BaseTranslator): ############################################## def visit_desc_name(self, node: Element) -> None: - self.body.append(self.starttag(node, 'code', '')) + self.body.append(self.starttag(node, 'span', '')) def depart_desc_name(self, node: Element) -> None: - self.body.append('') + self.body.append('') def visit_desc_addname(self, node: Element) -> None: - self.body.append(self.starttag(node, 'code', '')) + self.body.append(self.starttag(node, 'span', '')) def depart_desc_addname(self, node: Element) -> None: - self.body.append('') + self.body.append('') def visit_desc_type(self, node: Element) -> None: pass From 86eeee5031008bb0da73332cd8dd28bd3c9e5aed Mon Sep 17 00:00:00 2001 From: Jakob Lykke Andersen Date: Sat, 20 Mar 2021 17:53:11 +0100 Subject: [PATCH 07/22] Fix flake8 and mypy violations --- sphinx/addnodes.py | 9 +++++---- sphinx/domains/cpp.py | 24 ++++++++++++------------ 2 files changed, 17 insertions(+), 16 deletions(-) diff --git a/sphinx/addnodes.py b/sphinx/addnodes.py index 2d117d7a9..69d11eb53 100644 --- a/sphinx/addnodes.py +++ b/sphinx/addnodes.py @@ -119,7 +119,7 @@ class toctree(nodes.General, nodes.Element, translatable): # Domain-specific object descriptions (class, function etc.) ############################################################# -class _desc_classes_injector: +class _desc_classes_injector(nodes.TextElement): """Helper base class for injecting a fixes list of classes. Use as the first base class. @@ -127,7 +127,7 @@ class _desc_classes_injector: classes = [] # type: List[str] - def __init__(self, *args, **kwargs) -> None: + def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) self['classes'].extend(self.classes) @@ -197,7 +197,7 @@ class desc_inline(_desc_classes_injector, nodes.Inline, nodes.TextElement): """ classes = ['sig', 'sig-inline'] - def __init__(self, domain: str, *args, **kwargs): + def __init__(self, domain: str, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) self['classes'].append(domain) @@ -226,7 +226,8 @@ class desc_addname(_desc_classes_injector, nodes.Part, nodes.Inline, nodes.Fixed This node always has the class ``sig-prename``. """ - classes = ['sig-prename', 'descclassname'] # 'descclassname' is for backwards compatibility + # 'descclassname' is for backwards compatibility + classes = ['sig-prename', 'descclassname'] # compatibility alias diff --git a/sphinx/domains/cpp.py b/sphinx/domains/cpp.py index 51cdd3946..aa88838f4 100644 --- a/sphinx/domains/cpp.py +++ b/sphinx/domains/cpp.py @@ -9,7 +9,7 @@ """ import re -from typing import (Any, Callable, Dict, Generator, Iterator, List, Optional, Tuple, Type, +from typing import (Any, Callable, Dict, Generator, Iterator, List, Optional, Tuple, TypeVar, Union, cast) from docutils import nodes @@ -1623,9 +1623,9 @@ class ASTOperator(ASTBase): symbol: "Symbol") -> None: verify_description_mode(mode) if mode == 'lastIsName': - identnode = addnodes.desc_name() - self._describe_identifier(identnode, identnode, env, symbol) - signode += identnode + mainName = addnodes.desc_name() + self._describe_identifier(mainName, mainName, env, symbol) + signode += mainName elif mode == 'markType': targetText = prefix + str(self) + templateArgs pnode = addnodes.pending_xref('', refdomain='cpp', @@ -1637,15 +1637,15 @@ class ASTOperator(ASTBase): # and make that the a link to this operator. # E.g., if it is 'operator SomeType', then 'SomeType' becomes # a link to the operator, not to 'SomeType'. - identnode = nodes.literal() - self._describe_identifier(signode, identnode, env, symbol) - txt = identnode.astext() + container = nodes.literal() + self._describe_identifier(signode, container, env, symbol) + txt = container.astext() pnode += addnodes.desc_name(txt, txt) signode += pnode else: - identnode = addnodes.desc_addname() - self._describe_identifier(identnode, identnode, env, symbol) - signode += identnode + addName = addnodes.desc_addname() + self._describe_identifier(addName, addName, env, symbol) + signode += addName class ASTOperatorBuildIn(ASTOperator): @@ -7690,8 +7690,8 @@ class CPPDomain(Domain): # and reconstruct the title again contnode += nodes.Text(title) res = make_refnode(builder, fromdocname, docname, - declaration.get_newest_id(), contnode, displayName - ), declaration.objectType + declaration.get_newest_id(), contnode, displayName + ), declaration.objectType return res def resolve_xref(self, env: BuildEnvironment, fromdocname: str, builder: Builder, From c1da955df2f14ffc5a686b8724d46369abf847d4 Mon Sep 17 00:00:00 2001 From: Jakob Lykke Andersen Date: Sat, 20 Mar 2021 18:02:07 +0100 Subject: [PATCH 08/22] Decl styling, use a post-transform to get the domain name in the desc_signature nodes --- sphinx/addnodes.py | 3 ++- sphinx/transforms/post_transforms/__init__.py | 10 ++++++++++ 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/sphinx/addnodes.py b/sphinx/addnodes.py index 69d11eb53..23cf0acb8 100644 --- a/sphinx/addnodes.py +++ b/sphinx/addnodes.py @@ -158,8 +158,9 @@ class desc_signature(_desc_classes_injector, nodes.Part, nodes.Inline, nodes.Tex Set ``is_multiline = True`` to describe a multi-line signature. In that case all child nodes must be :py:class:`desc_signature_line` nodes. - This node always has the classes ``sig`` and ``sig-object``. + This node always has the classes ``sig``, ``sig-object``, and the domain it belongs to. """ + # Note: the domain name is being added through a post-transform DescSigAddDomainAsClass classes = ['sig', 'sig-object'] @property diff --git a/sphinx/transforms/post_transforms/__init__.py b/sphinx/transforms/post_transforms/__init__.py index 76a709f5f..b70677e4f 100644 --- a/sphinx/transforms/post_transforms/__init__.py +++ b/sphinx/transforms/post_transforms/__init__.py @@ -232,10 +232,20 @@ class SigElementFallbackTransform(SphinxPostTransform): node.replace_self(newnode) +class DescSigAddDomainAsClass(SphinxPostTransform): + """Add the domain name of the parent node as a class in each desc_signature node.""" + default_priority = 200 + + def run(self, **kwargs: Any) -> None: + for node in self.document.traverse(addnodes.desc_signature): + node['classes'].append(node.parent['domain']) + + def setup(app: Sphinx) -> Dict[str, Any]: app.add_post_transform(ReferencesResolver) app.add_post_transform(OnlyNodeTransform) app.add_post_transform(SigElementFallbackTransform) + app.add_post_transform(DescSigAddDomainAsClass) return { 'version': 'builtin', From 70708e4b24f70aa84b7c46c0b83175eaba32baf6 Mon Sep 17 00:00:00 2001 From: Jakob Lykke Andersen Date: Sat, 20 Mar 2021 18:07:11 +0100 Subject: [PATCH 09/22] Decl styling, add CSS for the C++ domain --- sphinx/themes/basic/static/basic.css_t | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/sphinx/themes/basic/static/basic.css_t b/sphinx/themes/basic/static/basic.css_t index de7651e17..7f505f6b1 100644 --- a/sphinx/themes/basic/static/basic.css_t +++ b/sphinx/themes/basic/static/basic.css_t @@ -542,6 +542,18 @@ table.hlist td { font-family: unset; } +.sig.cpp .k, .sig.cpp .kt { + color: #0033B3; +} + +.sig.cpp .m { + color: #1750EB; +} + +.sig.cpp .s { + color: #067D17; +} + /* -- other body styles ----------------------------------------------------- */ From 87414faa92fe987b70dc2d4cb61d08a609a5e56c Mon Sep 17 00:00:00 2001 From: Jakob Lykke Andersen Date: Sat, 20 Mar 2021 19:27:13 +0100 Subject: [PATCH 10/22] Decl styling, fix cpp tests --- tests/test_domain_cpp.py | 5 ++--- tests/test_ext_intersphinx.py | 4 ++-- 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/tests/test_domain_cpp.py b/tests/test_domain_cpp.py index 7ecf89f54..52aaad850 100644 --- a/tests/test_domain_cpp.py +++ b/tests/test_domain_cpp.py @@ -1210,7 +1210,7 @@ not found in `{test}` cpp_any_role = RoleClasses('cpp-any', 'a', ['code']) # NYI: consistent looks # texpr_role = RoleClasses('cpp-texpr', 'span', ['a', 'code']) - expr_role = RoleClasses('cpp-expr', 'code', ['a']) + expr_role = RoleClasses('cpp-expr', 'span', ['a']) texpr_role = RoleClasses('cpp-texpr', 'span', ['a', 'span']) # XRefRole-style classes @@ -1227,8 +1227,7 @@ not found in `{test}` for role in (expr_role, texpr_role): name = role.name expect = '`{name}` puts the domain and role classes at its root'.format(name=name) - # NYI: xref should go in the references - assert {'xref', 'cpp', name} <= role.classes, expect + assert {'sig', 'sig-inline', 'cpp', name} <= role.classes, expect # reference classes diff --git a/tests/test_ext_intersphinx.py b/tests/test_ext_intersphinx.py index 785faed62..62456a3f4 100644 --- a/tests/test_ext_intersphinx.py +++ b/tests/test_ext_intersphinx.py @@ -258,10 +258,10 @@ def test_missing_reference_cppdomain(tempdir, app, status, warning): 'Bar' in html) assert ('foons' in html) + ' title="(in foo v2.0)">foons' in html) assert ('bartype' in html) + ' title="(in foo v2.0)">bartype' in html) def test_missing_reference_jsdomain(tempdir, app, status, warning): From 3fdc9bcf9fca90e30246b972651cbb29756c56fd Mon Sep 17 00:00:00 2001 From: Jakob Lykke Andersen Date: Sat, 20 Mar 2021 19:43:41 +0100 Subject: [PATCH 11/22] Fix desc_sig_space --- sphinx/addnodes.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/sphinx/addnodes.py b/sphinx/addnodes.py index 23cf0acb8..5d26643ed 100644 --- a/sphinx/addnodes.py +++ b/sphinx/addnodes.py @@ -294,8 +294,9 @@ class desc_sig_space(desc_sig_element): """Node for a space in a signature.""" classes = ["w"] - def __init__(self) -> None: - super().__init__(' ', ' ') + def __init__(self, rawsource: str = '', text: str = ' ', + *children: Element, **attributes: Any) -> None: + super().__init__(rawsource, text, *children, **attributes) class desc_sig_name(desc_sig_element): From f769dde254e6f25f5b8e6e29718b90b425c3f235 Mon Sep 17 00:00:00 2001 From: Jakob Lykke Andersen Date: Sat, 20 Mar 2021 19:48:54 +0100 Subject: [PATCH 12/22] Decl styling, fix html test --- tests/test_build_html.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/tests/test_build_html.py b/tests/test_build_html.py index b01d6f4eb..c74552d9e 100644 --- a/tests/test_build_html.py +++ b/tests/test_build_html.py @@ -285,10 +285,10 @@ def test_html4_output(app, status, warning): 'objects.html': [ (".//dt[@id='mod.Cls.meth1']", ''), (".//dt[@id='errmod.Error']", ''), - (".//dt/code/span", r'long\(parameter,'), - (".//dt/code/span", r'list\)'), - (".//dt/code/span", 'another'), - (".//dt/code/span", 'one'), + (".//dt/span[@class='sig-name descname']/span[@class='pre']", r'long\(parameter,'), + (".//dt/span[@class='sig-name descname']/span[@class='pre']", r'list\)'), + (".//dt/span[@class='sig-name descname']/span[@class='pre']", 'another'), + (".//dt/span[@class='sig-name descname']/span[@class='pre']", 'one'), (".//a[@href='#mod.Cls'][@class='reference internal']", ''), (".//dl[@class='std userdesc']", ''), (".//dt[@id='userdesc-myobj']", ''), From c0ef6a92656cbada6702d0102b19d58c881763ed Mon Sep 17 00:00:00 2001 From: Jakob Lykke Andersen Date: Sat, 20 Mar 2021 20:08:26 +0100 Subject: [PATCH 13/22] Fix isort violation --- sphinx/domains/cpp.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sphinx/domains/cpp.py b/sphinx/domains/cpp.py index aa88838f4..057cc2037 100644 --- a/sphinx/domains/cpp.py +++ b/sphinx/domains/cpp.py @@ -9,8 +9,8 @@ """ import re -from typing import (Any, Callable, Dict, Generator, Iterator, List, Optional, Tuple, - TypeVar, Union, cast) +from typing import (Any, Callable, Dict, Generator, Iterator, List, Optional, Tuple, TypeVar, + Union, cast) from docutils import nodes from docutils.nodes import Element, Node, TextElement, system_message From 7126503eeb2b13bba35dc18c87631c6e728bf6f0 Mon Sep 17 00:00:00 2001 From: Jakob Lykke Andersen Date: Thu, 25 Mar 2021 19:42:50 +0100 Subject: [PATCH 14/22] Decl styling, update writers Add test objects so all builders gets exposed to the new nodes. Make the fallback node post-transform change desc_inline as well. Make the html4, latex, and text writers handle desc_inline. --- sphinx/transforms/post_transforms/__init__.py | 17 +++---- sphinx/writers/html.py | 6 +++ sphinx/writers/latex.py | 48 +++++++++++++------ sphinx/writers/manpage.py | 34 ++++++++----- sphinx/writers/text.py | 30 +++++++++--- tests/roots/test-root/objects.txt | 6 +++ 6 files changed, 101 insertions(+), 40 deletions(-) diff --git a/sphinx/transforms/post_transforms/__init__.py b/sphinx/transforms/post_transforms/__init__.py index b70677e4f..bcc9caf00 100644 --- a/sphinx/transforms/post_transforms/__init__.py +++ b/sphinx/transforms/post_transforms/__init__.py @@ -206,7 +206,7 @@ class OnlyNodeTransform(SphinxPostTransform): class SigElementFallbackTransform(SphinxPostTransform): - """Fallback desc_sig_element nodes to inline if translator does not supported them.""" + """Fallback various desc_* nodes to inline if translator does not supported them.""" default_priority = 200 def run(self, **kwargs: Any) -> None: @@ -218,14 +218,15 @@ class SigElementFallbackTransform(SphinxPostTransform): # subclass of SphinxTranslator supports desc_sig_element nodes automatically. return - if all(has_visitor(translator, node) for node in addnodes.SIG_ELEMENTS): - # the translator supports all desc_sig_element nodes - return - else: - self.fallback() + # for the leaf elements (desc_sig_element), the translator should support _all_ + if not all(has_visitor(translator, node) for node in addnodes.SIG_ELEMENTS): + self.fallback(addnodes.desc_sig_element) - def fallback(self) -> None: - for node in self.document.traverse(addnodes.desc_sig_element): + if not has_visitor(translator, addnodes.desc_inline): + self.fallback(addnodes.desc_inline) + + def fallback(self, nodeType: Any) -> None: + for node in self.document.traverse(nodeType): newnode = nodes.inline() newnode.update_all_atts(node) newnode.extend(node) diff --git a/sphinx/writers/html.py b/sphinx/writers/html.py index 54d7311ea..d633f07e8 100644 --- a/sphinx/writers/html.py +++ b/sphinx/writers/html.py @@ -146,6 +146,12 @@ class HTMLTranslator(SphinxTranslator, BaseTranslator): def depart_desc_content(self, node: Element) -> None: self.body.append('') + def visit_desc_inline(self, node: Element) -> None: + self.body.append(self.starttag(node, 'span', '')) + + def depart_desc_inline(self, node: Element) -> None: + self.body.append('') + # Nodes for high-level structure in signatures ############################################## diff --git a/sphinx/writers/latex.py b/sphinx/writers/latex.py index edef5417f..546db9e31 100644 --- a/sphinx/writers/latex.py +++ b/sphinx/writers/latex.py @@ -698,6 +698,13 @@ class LaTeXTranslator(SphinxTranslator): def depart_subtitle(self, node: Element) -> None: self.body.append(self.context.pop()) + ############################################################# + # Domain-specific object descriptions + ############################################################# + + # Top-level nodes for descriptions + ################################## + def visit_desc(self, node: Element) -> None: if self.config.latex_show_urls == 'footnote': self.body.append(BLANKLINE) @@ -750,6 +757,31 @@ class LaTeXTranslator(SphinxTranslator): def depart_desc_signature_line(self, node: Element) -> None: self._depart_signature_line(node) + def visit_desc_content(self, node: Element) -> None: + if node.children and not isinstance(node.children[0], nodes.paragraph): + # avoid empty desc environment which causes a formatting bug + self.body.append('~') + + def depart_desc_content(self, node: Element) -> None: + pass + + def visit_desc_inline(self, node: Element) -> None: + self.body.append(r'\sphinxcode{\sphinxupquote{') + + def depart_desc_inline(self, node: Element) -> None: + self.body.append('}}') + + # Nodes for high-level structure in signatures + ############################################## + + def visit_desc_name(self, node: Element) -> None: + self.body.append(r'\sphinxbfcode{\sphinxupquote{') + self.literal_whitespace += 1 + + def depart_desc_name(self, node: Element) -> None: + self.body.append('}}') + self.literal_whitespace -= 1 + def visit_desc_addname(self, node: Element) -> None: self.body.append(r'\sphinxcode{\sphinxupquote{') self.literal_whitespace += 1 @@ -770,14 +802,6 @@ class LaTeXTranslator(SphinxTranslator): def depart_desc_returns(self, node: Element) -> None: self.body.append(r'}') - def visit_desc_name(self, node: Element) -> None: - self.body.append(r'\sphinxbfcode{\sphinxupquote{') - self.literal_whitespace += 1 - - def depart_desc_name(self, node: Element) -> None: - self.body.append('}}') - self.literal_whitespace -= 1 - def visit_desc_parameterlist(self, node: Element) -> None: # close name, open parameterlist self.body.append('}{') @@ -811,13 +835,7 @@ class LaTeXTranslator(SphinxTranslator): def depart_desc_annotation(self, node: Element) -> None: self.body.append('}}') - def visit_desc_content(self, node: Element) -> None: - if node.children and not isinstance(node.children[0], nodes.paragraph): - # avoid empty desc environment which causes a formatting bug - self.body.append('~') - - def depart_desc_content(self, node: Element) -> None: - pass + ############################################## def visit_seealso(self, node: Element) -> None: self.body.append(BLANKLINE) diff --git a/sphinx/writers/manpage.py b/sphinx/writers/manpage.py index c11c49892..a43f117ae 100644 --- a/sphinx/writers/manpage.py +++ b/sphinx/writers/manpage.py @@ -120,6 +120,13 @@ class ManualPageTranslator(SphinxTranslator, BaseTranslator): def depart_start_of_file(self, node: Element) -> None: pass + ############################################################# + # Domain-specific object descriptions + ############################################################# + + # Top-level nodes for descriptions + ################################## + def visit_desc(self, node: Element) -> None: self.visit_definition_list(node) @@ -139,6 +146,21 @@ class ManualPageTranslator(SphinxTranslator, BaseTranslator): def depart_desc_signature_line(self, node: Element) -> None: self.body.append(' ') + def visit_desc_content(self, node: Element) -> None: + self.visit_definition(node) + + def depart_desc_content(self, node: Element) -> None: + self.depart_definition(node) + + # Nodes for high-level structure in signatures + ############################################## + + def visit_desc_name(self, node: Element) -> None: + pass + + def depart_desc_name(self, node: Element) -> None: + pass + def visit_desc_addname(self, node: Element) -> None: pass @@ -157,12 +179,6 @@ class ManualPageTranslator(SphinxTranslator, BaseTranslator): def depart_desc_returns(self, node: Element) -> None: pass - def visit_desc_name(self, node: Element) -> None: - pass - - def depart_desc_name(self, node: Element) -> None: - pass - def visit_desc_parameterlist(self, node: Element) -> None: self.body.append('(') self.first_param = 1 @@ -191,11 +207,7 @@ class ManualPageTranslator(SphinxTranslator, BaseTranslator): def depart_desc_annotation(self, node: Element) -> None: pass - def visit_desc_content(self, node: Element) -> None: - self.visit_definition(node) - - def depart_desc_content(self, node: Element) -> None: - self.depart_definition(node) + ############################################## def visit_versionmodified(self, node: Element) -> None: self.visit_paragraph(node) diff --git a/sphinx/writers/text.py b/sphinx/writers/text.py index 5bd96de76..d8dab9181 100644 --- a/sphinx/writers/text.py +++ b/sphinx/writers/text.py @@ -536,6 +536,13 @@ class TextTranslator(SphinxTranslator): def depart_attribution(self, node: Element) -> None: pass + ############################################################# + # Domain-specific object descriptions + ############################################################# + + # Top-level nodes + ################# + def visit_desc(self, node: Element) -> None: pass @@ -555,6 +562,22 @@ class TextTranslator(SphinxTranslator): def depart_desc_signature_line(self, node: Element) -> None: self.add_text('\n') + def visit_desc_content(self, node: Element) -> None: + self.new_state() + self.add_text(self.nl) + + def depart_desc_content(self, node: Element) -> None: + self.end_state() + + def visit_desc_inline(self, node: Element) -> None: + pass + + def depart_desc_inline(self, node: Element) -> None: + pass + + # Nodes for high-level structure in signatures + ############################################## + def visit_desc_name(self, node: Element) -> None: pass @@ -606,12 +629,7 @@ class TextTranslator(SphinxTranslator): def depart_desc_annotation(self, node: Element) -> None: pass - def visit_desc_content(self, node: Element) -> None: - self.new_state() - self.add_text(self.nl) - - def depart_desc_content(self, node: Element) -> None: - self.end_state() + ############################################## def visit_figure(self, node: Element) -> None: self.new_state() diff --git a/tests/roots/test-root/objects.txt b/tests/roots/test-root/objects.txt index adb090a44..d5ec2a486 100644 --- a/tests/roots/test-root/objects.txt +++ b/tests/roots/test-root/objects.txt @@ -213,3 +213,9 @@ CPP domain .. cpp:function:: T& operator[]( unsigned j ) const T& operator[]( unsigned j ) const + +.. cpp:function:: template \ + requires A \ + void f() + +- :cpp:expr:`a + b` From a1ac0fd1ec97edf783a93cfc9fdd5c65621e4ff5 Mon Sep 17 00:00:00 2001 From: Jakob Lykke Andersen Date: Tue, 30 Mar 2021 11:50:36 +0200 Subject: [PATCH 15/22] Decl styling, C++, fix alternate spellings of operators --- sphinx/domains/cpp.py | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) diff --git a/sphinx/domains/cpp.py b/sphinx/domains/cpp.py index 057cc2037..1c876081b 100644 --- a/sphinx/domains/cpp.py +++ b/sphinx/domains/cpp.py @@ -1246,10 +1246,12 @@ class ASTUnaryOpExpr(ASTExpression): def describe_signature(self, signode: TextElement, mode: str, env: "BuildEnvironment", symbol: "Symbol") -> None: - signode += addnodes.desc_sig_operator(self.op, self.op) if self.op[0] in 'cn': + signode += addnodes.desc_sig_keyword(self.op, self.op) signode += addnodes.desc_sig_space() - self.expr.describe_signature(signode, mode, env, symbol) + else: + signode += addnodes.desc_sig_operator(self.op, self.op) + self.expr.describe_signature(signode, mode, env, symbol) class ASTSizeofParamPack(ASTExpression): @@ -1484,7 +1486,11 @@ class ASTBinOpExpr(ASTExpression): self.exprs[0].describe_signature(signode, mode, env, symbol) for i in range(1, len(self.exprs)): signode += addnodes.desc_sig_space() - signode += addnodes.desc_sig_operator(self.ops[i - 1], self.ops[i - 1]) + op = self.ops[i - 1] + if ord(op[0]) >= ord('a') and ord(op[0]) <= ord('z'): + signode += addnodes.desc_sig_keyword(op, op) + else: + signode += addnodes.desc_sig_operator(op, op) signode += addnodes.desc_sig_space() self.exprs[i].describe_signature(signode, mode, env, symbol) @@ -1550,7 +1556,11 @@ class ASTAssignmentExpr(ASTExpression): self.exprs[0].describe_signature(signode, mode, env, symbol) for i in range(1, len(self.exprs)): signode += addnodes.desc_sig_space() - signode += addnodes.desc_sig_operator(self.ops[i - 1], self.ops[i - 1]) + op = self.ops[i - 1] + if ord(op[0]) >= ord('a') and ord(op[0]) <= ord('z'): + signode += addnodes.desc_sig_keyword(op, op) + else: + signode += addnodes.desc_sig_operator(op, op) signode += addnodes.desc_sig_space() self.exprs[i].describe_signature(signode, mode, env, symbol) From 9cd9e124ff45553bf5a4385d37eeca6be47f9a80 Mon Sep 17 00:00:00 2001 From: Jakob Lykke Andersen Date: Tue, 30 Mar 2021 14:12:56 +0200 Subject: [PATCH 16/22] Decl styling, convert C --- sphinx/domains/c.py | 223 +++++++++++++++++++++++--------------------- 1 file changed, 118 insertions(+), 105 deletions(-) diff --git a/sphinx/domains/c.py b/sphinx/domains/c.py index 72b9746ac..d3aad012b 100644 --- a/sphinx/domains/c.py +++ b/sphinx/domains/c.py @@ -9,8 +9,7 @@ """ import re -from typing import (Any, Callable, Dict, Generator, Iterator, List, Tuple, Type, TypeVar, - Union, cast) +from typing import Any, Callable, Dict, Generator, Iterator, List, Tuple, TypeVar, Union, cast from docutils import nodes from docutils.nodes import Element, Node, TextElement, system_message @@ -132,6 +131,10 @@ class ASTIdentifier(ASTBaseBase): prefix: str, symbol: "Symbol") -> None: # note: slightly different signature of describe_signature due to the prefix verify_description_mode(mode) + if self.is_anon(): + node = addnodes.desc_sig_name(text="[anonymous]") + else: + node = addnodes.desc_sig_name(self.identifier, self.identifier) if mode == 'markType': targetText = prefix + self.identifier pnode = addnodes.pending_xref('', refdomain='c', @@ -139,21 +142,14 @@ class ASTIdentifier(ASTBaseBase): reftarget=targetText, modname=None, classname=None) pnode['c:parent_key'] = symbol.get_lookup_key() - if self.is_anon(): - pnode += nodes.strong(text="[anonymous]") - else: - pnode += nodes.Text(self.identifier) + pnode += node signode += pnode elif mode == 'lastIsName': - if self.is_anon(): - signode += nodes.strong(text="[anonymous]") - else: - signode += addnodes.desc_name(self.identifier, self.identifier) + nameNode = addnodes.desc_name() + nameNode += node + signode += nameNode elif mode == 'noneIsName': - if self.is_anon(): - signode += nodes.strong(text="[anonymous]") - else: - signode += nodes.Text(self.identifier) + signode += node else: raise Exception('Unknown description mode: %s' % mode) @@ -184,18 +180,18 @@ class ASTNestedName(ASTBase): # just print the name part, with template args, not template params if mode == 'noneIsName': if self.rooted: + assert False, "Can this happen?" # TODO signode += nodes.Text('.') for i in range(len(self.names)): if i != 0: + assert False, "Can this happen?" # TODO signode += nodes.Text('.') n = self.names[i] n.describe_signature(signode, mode, env, '', symbol) elif mode == 'param': assert not self.rooted, str(self) assert len(self.names) == 1 - node = nodes.emphasis() - self.names[0].describe_signature(node, 'noneIsName', env, '', symbol) - signode += node + self.names[0].describe_signature(signode, 'noneIsName', env, '', symbol) elif mode == 'markType' or mode == 'lastIsName' or mode == 'markName': # Each element should be a pending xref targeting the complete # prefix. @@ -213,13 +209,13 @@ class ASTNestedName(ASTBase): if self.rooted: prefix += '.' if mode == 'lastIsName' and len(names) == 0: - signode += nodes.Text('.') + signode += addnodes.desc_sig_punctuation('.', '.') else: - dest += nodes.Text('.') + dest += addnodes.desc_sig_punctuation('.', '.') for i in range(len(names)): ident = names[i] if not first: - dest += nodes.Text('.') + dest += addnodes.desc_sig_punctuation('.', '.') prefix += '.' first = False txt_ident = str(ident) @@ -228,7 +224,7 @@ class ASTNestedName(ASTBase): prefix += txt_ident if mode == 'lastIsName': if len(self.names) > 1: - dest += addnodes.desc_addname('.', '.') + dest += addnodes.desc_sig_punctuation('.', '.') signode += dest self.names[-1].describe_signature(signode, mode, env, '', symbol) else: @@ -262,7 +258,8 @@ class ASTBooleanLiteral(ASTLiteral): def describe_signature(self, signode: TextElement, mode: str, env: "BuildEnvironment", symbol: "Symbol") -> None: - signode.append(nodes.Text(str(self))) + txt = str(self) + signode += addnodes.desc_sig_keyword(txt, txt) class ASTNumberLiteral(ASTLiteral): @@ -275,7 +272,7 @@ class ASTNumberLiteral(ASTLiteral): def describe_signature(self, signode: TextElement, mode: str, env: "BuildEnvironment", symbol: "Symbol") -> None: txt = str(self) - signode.append(nodes.Text(txt, txt)) + signode += addnodes.desc_sig_literal_number(txt, txt) class ASTCharLiteral(ASTLiteral): @@ -297,7 +294,7 @@ class ASTCharLiteral(ASTLiteral): def describe_signature(self, signode: TextElement, mode: str, env: "BuildEnvironment", symbol: "Symbol") -> None: txt = str(self) - signode.append(nodes.Text(txt, txt)) + signode += addnodes.desc_sig_literal_char(txt, txt) class ASTStringLiteral(ASTLiteral): @@ -310,7 +307,7 @@ class ASTStringLiteral(ASTLiteral): def describe_signature(self, signode: TextElement, mode: str, env: "BuildEnvironment", symbol: "Symbol") -> None: txt = str(self) - signode.append(nodes.Text(txt, txt)) + signode += addnodes.desc_sig_literal_string(txt, txt) class ASTIdExpression(ASTExpression): @@ -341,9 +338,9 @@ class ASTParenExpr(ASTExpression): def describe_signature(self, signode: TextElement, mode: str, env: "BuildEnvironment", symbol: "Symbol") -> None: - signode.append(nodes.Text('(', '(')) + signode += addnodes.desc_sig_punctuation('(', '(') self.expr.describe_signature(signode, mode, env, symbol) - signode.append(nodes.Text(')', ')')) + signode += addnodes.desc_sig_punctuation(')', ')') # Postfix expressions @@ -374,9 +371,9 @@ class ASTPostfixArray(ASTPostfixOp): def describe_signature(self, signode: TextElement, mode: str, env: "BuildEnvironment", symbol: "Symbol") -> None: - signode.append(nodes.Text('[')) + signode += addnodes.desc_sig_punctuation('[', '[') self.expr.describe_signature(signode, mode, env, symbol) - signode.append(nodes.Text(']')) + signode += addnodes.desc_sig_punctuation(']', ']') class ASTPostfixInc(ASTPostfixOp): @@ -385,7 +382,7 @@ class ASTPostfixInc(ASTPostfixOp): def describe_signature(self, signode: TextElement, mode: str, env: "BuildEnvironment", symbol: "Symbol") -> None: - signode.append(nodes.Text('++')) + signode += addnodes.desc_sig_operator('++', '++') class ASTPostfixDec(ASTPostfixOp): @@ -394,7 +391,7 @@ class ASTPostfixDec(ASTPostfixOp): def describe_signature(self, signode: TextElement, mode: str, env: "BuildEnvironment", symbol: "Symbol") -> None: - signode.append(nodes.Text('--')) + signode += addnodes.desc_sig_operator('--', '--') class ASTPostfixMemberOfPointer(ASTPostfixOp): @@ -406,7 +403,7 @@ class ASTPostfixMemberOfPointer(ASTPostfixOp): def describe_signature(self, signode: TextElement, mode: str, env: "BuildEnvironment", symbol: "Symbol") -> None: - signode.append(nodes.Text('->')) + signode += addnodes.desc_sig_operator('->', '->') self.name.describe_signature(signode, 'noneIsName', env, symbol) @@ -444,10 +441,12 @@ class ASTUnaryOpExpr(ASTExpression): def describe_signature(self, signode: TextElement, mode: str, env: "BuildEnvironment", symbol: "Symbol") -> None: - signode.append(nodes.Text(self.op)) if self.op[0] in 'cn': - signode.append(nodes.Text(" ")) - self.expr.describe_signature(signode, mode, env, symbol) + signode += addnodes.desc_sig_keyword(self.op, self.op) + signode += addnodes.desc_sig_space() + else: + signode += addnodes.desc_sig_operator(self.op, self.op) + self.expr.describe_signature(signode, mode, env, symbol) class ASTSizeofType(ASTExpression): @@ -459,9 +458,10 @@ class ASTSizeofType(ASTExpression): def describe_signature(self, signode: TextElement, mode: str, env: "BuildEnvironment", symbol: "Symbol") -> None: - signode.append(nodes.Text('sizeof(')) + signode += addnodes.desc_sig_keyword('sizeof', 'sizeof') + signode += addnodes.desc_sig_punctuation('(', '(') self.typ.describe_signature(signode, mode, env, symbol) - signode.append(nodes.Text(')')) + signode += addnodes.desc_sig_punctuation(')', ')') class ASTSizeofExpr(ASTExpression): @@ -473,7 +473,8 @@ class ASTSizeofExpr(ASTExpression): def describe_signature(self, signode: TextElement, mode: str, env: "BuildEnvironment", symbol: "Symbol") -> None: - signode.append(nodes.Text('sizeof ')) + signode += addnodes.desc_sig_keyword('sizeof', 'sizeof') + signode += addnodes.desc_sig_space() self.expr.describe_signature(signode, mode, env, symbol) @@ -486,9 +487,10 @@ class ASTAlignofExpr(ASTExpression): def describe_signature(self, signode: TextElement, mode: str, env: "BuildEnvironment", symbol: "Symbol") -> None: - signode.append(nodes.Text('alignof(')) + signode += addnodes.desc_sig_keyword('alignof', 'alignof') + signode += addnodes.desc_sig_punctuation('(', '(') self.typ.describe_signature(signode, mode, env, symbol) - signode.append(nodes.Text(')')) + signode += addnodes.desc_sig_punctuation(')', ')') # Other expressions @@ -508,9 +510,9 @@ class ASTCastExpr(ASTExpression): def describe_signature(self, signode: TextElement, mode: str, env: "BuildEnvironment", symbol: "Symbol") -> None: - signode.append(nodes.Text('(')) + signode += addnodes.desc_sig_punctuation('(', '(') self.typ.describe_signature(signode, mode, env, symbol) - signode.append(nodes.Text(')')) + signode += addnodes.desc_sig_punctuation(')', ')') self.expr.describe_signature(signode, mode, env, symbol) @@ -535,9 +537,13 @@ class ASTBinOpExpr(ASTBase): env: "BuildEnvironment", symbol: "Symbol") -> None: self.exprs[0].describe_signature(signode, mode, env, symbol) for i in range(1, len(self.exprs)): - signode.append(nodes.Text(' ')) - signode.append(nodes.Text(self.ops[i - 1])) - signode.append(nodes.Text(' ')) + signode += addnodes.desc_sig_space() + op = self.ops[i - 1] + if ord(op[0]) >= ord('a') and ord(op[0]) <= ord('z'): + signode += addnodes.desc_sig_keyword(op, op) + else: + signode += addnodes.desc_sig_operator(op, op) + signode += addnodes.desc_sig_space() self.exprs[i].describe_signature(signode, mode, env, symbol) @@ -562,9 +568,13 @@ class ASTAssignmentExpr(ASTExpression): env: "BuildEnvironment", symbol: "Symbol") -> None: self.exprs[0].describe_signature(signode, mode, env, symbol) for i in range(1, len(self.exprs)): - signode.append(nodes.Text(' ')) - signode.append(nodes.Text(self.ops[i - 1])) - signode.append(nodes.Text(' ')) + signode += addnodes.desc_sig_space() + op = self.ops[i - 1] + if ord(op[0]) >= ord('a') and ord(op[0]) <= ord('z'): + signode += addnodes.desc_sig_keyword(op, op) + else: + signode += addnodes.desc_sig_operator(op, op) + signode += addnodes.desc_sig_space() self.exprs[i].describe_signature(signode, mode, env, symbol) @@ -580,7 +590,7 @@ class ASTFallbackExpr(ASTExpression): def describe_signature(self, signode: TextElement, mode: str, env: "BuildEnvironment", symbol: "Symbol") -> None: - signode += nodes.Text(self.expr) + signode += nodes.literal(self.expr, self.expr) ################################################################################ @@ -600,7 +610,7 @@ class ASTTrailingTypeSpecFundamental(ASTTrailingTypeSpec): def describe_signature(self, signode: TextElement, mode: str, env: "BuildEnvironment", symbol: "Symbol") -> None: - signode += nodes.Text(str(self.name)) + signode += addnodes.desc_sig_keyword_type(self.name, self.name) class ASTTrailingTypeSpecName(ASTTrailingTypeSpec): @@ -623,8 +633,8 @@ class ASTTrailingTypeSpecName(ASTTrailingTypeSpec): def describe_signature(self, signode: TextElement, mode: str, env: "BuildEnvironment", symbol: "Symbol") -> None: if self.prefix: - signode += addnodes.desc_annotation(self.prefix, self.prefix) - signode += nodes.Text(' ') + signode += addnodes.desc_sig_keyword(self.prefix, self.prefix) + signode += addnodes.desc_sig_space() self.nestedName.describe_signature(signode, mode, env, symbol=symbol) @@ -647,7 +657,7 @@ class ASTFunctionParameter(ASTBase): env: "BuildEnvironment", symbol: "Symbol") -> None: verify_description_mode(mode) if self.ellipsis: - signode += nodes.Text('...') + signode += addnodes.desc_sig_punctuation('...', '...') else: self.arg.describe_signature(signode, mode, env, symbol=symbol) @@ -688,17 +698,18 @@ class ASTParameters(ASTBase): paramlist += param signode += paramlist else: - signode += nodes.Text('(', '(') + signode += addnodes.desc_sig_punctuation('(', '(') first = True for arg in self.args: if not first: - signode += nodes.Text(', ', ', ') + signode += addnodes.desc_sig_punctuation(',', ',') + signode += addnodes.desc_sig_space() first = False arg.describe_signature(signode, 'markType', env, symbol=symbol) - signode += nodes.Text(')', ')') + signode += addnodes.desc_sig_punctuation(')', ')') for attr in self.attrs: - signode += nodes.Text(' ') + signode += addnodes.desc_sig_space() attr.describe_signature(signode) @@ -744,12 +755,12 @@ class ASTDeclSpecsSimple(ASTBaseBase): def describe_signature(self, modifiers: List[Node]) -> None: def _add(modifiers: List[Node], text: str) -> None: if len(modifiers) > 0: - modifiers.append(nodes.Text(' ')) - modifiers.append(addnodes.desc_annotation(text, text)) + modifiers.append(addnodes.desc_sig_space()) + modifiers.append(addnodes.desc_sig_keyword(text, text)) for attr in self.attrs: if len(modifiers) > 0: - modifiers.append(nodes.Text(' ')) + modifiers.append(addnodes.desc_sig_space()) modifiers.append(attr.describe_signature(modifiers)) if self.storage: _add(modifiers, self.storage) @@ -799,24 +810,19 @@ class ASTDeclSpecs(ASTBase): verify_description_mode(mode) modifiers: List[Node] = [] - def _add(modifiers: List[Node], text: str) -> None: - if len(modifiers) > 0: - modifiers.append(nodes.Text(' ')) - modifiers.append(addnodes.desc_annotation(text, text)) - self.leftSpecs.describe_signature(modifiers) for m in modifiers: signode += m if self.trailingTypeSpec: if len(modifiers) > 0: - signode += nodes.Text(' ') + signode += addnodes.desc_sig_space() self.trailingTypeSpec.describe_signature(signode, mode, env, symbol=symbol) modifiers = [] self.rightSpecs.describe_signature(modifiers) if len(modifiers) > 0: - signode += nodes.Text(' ') + signode += addnodes.desc_sig_space() for m in modifiers: signode += m @@ -857,13 +863,13 @@ class ASTArray(ASTBase): def describe_signature(self, signode: TextElement, mode: str, env: "BuildEnvironment", symbol: "Symbol") -> None: verify_description_mode(mode) - signode.append(nodes.Text("[")) + signode += addnodes.desc_sig_punctuation('[', '[') addSpace = False def _add(signode: TextElement, text: str) -> bool: if addSpace: - signode += nodes.Text(' ') - signode += addnodes.desc_annotation(text, text) + signode += addnodes.desc_sig_space() + signode += addnodes.desc_sig_keyword(text, text) return True if self.static: @@ -875,12 +881,12 @@ class ASTArray(ASTBase): if self.const: addSpace = _add(signode, 'const') if self.vla: - signode.append(nodes.Text('*')) + signode += addnodes.desc_sig_punctuation('*', '*') elif self.size: if addSpace: - signode += nodes.Text(' ') + signode += addnodes.desc_sig_space() self.size.describe_signature(signode, 'markType', env, symbol) - signode.append(nodes.Text("]")) + signode += addnodes.desc_sig_punctuation(']', ']') class ASTDeclarator(ASTBase): @@ -964,7 +970,9 @@ class ASTDeclaratorNameBitField(ASTDeclarator): verify_description_mode(mode) if self.declId: self.declId.describe_signature(signode, mode, env, symbol) - signode += nodes.Text(' : ', ' : ') + signode += addnodes.desc_sig_space() + signode += addnodes.desc_sig_punctuation(':', ':') + signode += addnodes.desc_sig_space() self.size.describe_signature(signode, mode, env, symbol) @@ -1016,28 +1024,28 @@ class ASTDeclaratorPtr(ASTDeclarator): def describe_signature(self, signode: TextElement, mode: str, env: "BuildEnvironment", symbol: "Symbol") -> None: verify_description_mode(mode) - signode += nodes.Text("*") + signode += addnodes.desc_sig_punctuation('*', '*') for a in self.attrs: a.describe_signature(signode) if len(self.attrs) > 0 and (self.restrict or self.volatile or self.const): - signode += nodes.Text(' ') + signode += addnodes.desc_sig_space() def _add_anno(signode: TextElement, text: str) -> None: - signode += addnodes.desc_annotation(text, text) + signode += addnodes.desc_sig_keyword(text, text) if self.restrict: _add_anno(signode, 'restrict') if self.volatile: if self.restrict: - signode += nodes.Text(' ') + signode += addnodes.desc_sig_space() _add_anno(signode, 'volatile') if self.const: if self.restrict or self.volatile: - signode += nodes.Text(' ') + signode += addnodes.desc_sig_space() _add_anno(signode, 'const') if self.const or self.volatile or self.restrict or len(self.attrs) > 0: if self.next.require_space_after_declSpecs(): - signode += nodes.Text(' ') + signode += addnodes.desc_sig_space() self.next.describe_signature(signode, mode, env, symbol) @@ -1070,9 +1078,9 @@ class ASTDeclaratorParen(ASTDeclarator): def describe_signature(self, signode: TextElement, mode: str, env: "BuildEnvironment", symbol: "Symbol") -> None: verify_description_mode(mode) - signode += nodes.Text('(') + signode += addnodes.desc_sig_punctuation('(', '(') self.inner.describe_signature(signode, mode, env, symbol) - signode += nodes.Text(')') + signode += addnodes.desc_sig_punctuation(')', ')') self.next.describe_signature(signode, "noneIsName", env, symbol) @@ -1090,15 +1098,16 @@ class ASTParenExprList(ASTBaseParenExprList): def describe_signature(self, signode: TextElement, mode: str, env: "BuildEnvironment", symbol: "Symbol") -> None: verify_description_mode(mode) - signode.append(nodes.Text('(')) + signode += addnodes.desc_sig_punctuation('(', '(') first = True for e in self.exprs: if not first: - signode.append(nodes.Text(', ')) + signode += addnodes.desc_sig_punctuation(',', ',') + signode += addnodes.desc_sig_space() else: first = False e.describe_signature(signode, mode, env, symbol) - signode.append(nodes.Text(')')) + signode += addnodes.desc_sig_punctuation(')', ')') class ASTBracedInitList(ASTBase): @@ -1114,17 +1123,18 @@ class ASTBracedInitList(ASTBase): def describe_signature(self, signode: TextElement, mode: str, env: "BuildEnvironment", symbol: "Symbol") -> None: verify_description_mode(mode) - signode.append(nodes.Text('{')) + signode += addnodes.desc_sig_punctuation('{', '{') first = True for e in self.exprs: if not first: - signode.append(nodes.Text(', ')) + signode += addnodes.desc_sig_punctuation(',', ',') + signode += addnodes.desc_sig_space() else: first = False e.describe_signature(signode, mode, env, symbol) if self.trailingComma: - signode.append(nodes.Text(',')) - signode.append(nodes.Text('}')) + signode += addnodes.desc_sig_punctuation(',', ',') + signode += addnodes.desc_sig_punctuation('}', '}') class ASTInitializer(ASTBase): @@ -1144,7 +1154,9 @@ class ASTInitializer(ASTBase): env: "BuildEnvironment", symbol: "Symbol") -> None: verify_description_mode(mode) if self.hasAssign: - signode.append(nodes.Text(' = ')) + signode += addnodes.desc_sig_space() + signode += addnodes.desc_sig_punctuation('=', '=') + signode += addnodes.desc_sig_space() self.value.describe_signature(signode, 'markType', env, symbol) @@ -1187,7 +1199,7 @@ class ASTType(ASTBase): self.declSpecs.describe_signature(signode, 'markType', env, symbol) if (self.decl.require_space_after_declSpecs() and len(str(self.declSpecs)) > 0): - signode += nodes.Text(' ') + signode += addnodes.desc_sig_space() # for parameters that don't really declare new names we get 'markType', # this should not be propagated, but be 'noneIsName'. if mode == 'markType': @@ -1241,10 +1253,10 @@ class ASTMacroParameter(ASTBase): env: "BuildEnvironment", symbol: "Symbol") -> None: verify_description_mode(mode) if self.ellipsis: - signode += nodes.Text('...') + signode += addnodes.desc_sig_punctuation('...', '...') elif self.variadic: name = str(self) - signode += nodes.emphasis(name, name) + signode += addnodes.desc_sig_name(name, name) else: self.arg.describe_signature(signode, mode, env, symbol=symbol) @@ -1427,23 +1439,27 @@ class ASTDeclaration(ASTBaseBase): elif self.objectType == 'macro': pass elif self.objectType == 'struct': - mainDeclNode += addnodes.desc_annotation('struct ', 'struct ') + mainDeclNode += addnodes.desc_sig_keyword('struct', 'struct') + mainDeclNode += addnodes.desc_sig_space() elif self.objectType == 'union': - mainDeclNode += addnodes.desc_annotation('union ', 'union ') + mainDeclNode += addnodes.desc_sig_keyword('union', 'union') + mainDeclNode += addnodes.desc_sig_space() elif self.objectType == 'enum': - mainDeclNode += addnodes.desc_annotation('enum ', 'enum ') + mainDeclNode += addnodes.desc_sig_keyword('enum', 'enum') + mainDeclNode += addnodes.desc_sig_space() elif self.objectType == 'enumerator': - mainDeclNode += addnodes.desc_annotation('enumerator ', 'enumerator ') + mainDeclNode += addnodes.desc_sig_keyword('enumerator', 'enumerator') + mainDeclNode += addnodes.desc_sig_space() elif self.objectType == 'type': decl = cast(ASTType, self.declaration) prefix = decl.get_type_declaration_prefix() - prefix += ' ' - mainDeclNode += addnodes.desc_annotation(prefix, prefix) + mainDeclNode += addnodes.desc_sig_keyword(prefix, prefix) + mainDeclNode += addnodes.desc_sig_space() else: assert False self.declaration.describe_signature(mainDeclNode, mode, env, self.symbol) if self.semicolon: - mainDeclNode += nodes.Text(';') + mainDeclNode += addnodes.desc_sig_punctuation(';', ';') class SymbolLookupResult: @@ -3661,31 +3677,28 @@ class CExprRole(SphinxRole): if asCode: # render the expression as inline code self.class_type = 'c-expr' - self.node_type: Type[TextElement] = nodes.literal else: # render the expression as inline text self.class_type = 'c-texpr' - self.node_type = nodes.inline def run(self) -> Tuple[List[Node], List[system_message]]: text = self.text.replace('\n', ' ') parser = DefinitionParser(text, location=self.get_source_info(), config=self.env.config) # attempt to mimic XRefRole classes, except that... - classes = ['xref', 'c', self.class_type] try: ast = parser.parse_expression() except DefinitionError as ex: logger.warning('Unparseable C expression: %r\n%s', text, ex, location=self.get_source_info()) # see below - return [self.node_type(text, text, classes=classes)], [] + return [addnodes.desc_inline('c', text, text, classes=[self.class_type])], [] parentSymbol = self.env.temp_data.get('c:parent_symbol', None) if parentSymbol is None: parentSymbol = self.env.domaindata['c']['root_symbol'] # ...most if not all of these classes should really apply to the individual references, # not the container node - signode = self.node_type(classes=classes) + signode = addnodes.desc_inline('c', classes=[self.class_type]) ast.describe_signature(signode, 'markType', self.env, parentSymbol) return [signode], [] From f1d9d0aac61ad40fba8bfd82b97352782aa11a45 Mon Sep 17 00:00:00 2001 From: Jakob Lykke Andersen Date: Tue, 30 Mar 2021 14:13:17 +0200 Subject: [PATCH 17/22] Decl styling, C styling and C++ char literal styling --- sphinx/themes/basic/static/basic.css_t | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/sphinx/themes/basic/static/basic.css_t b/sphinx/themes/basic/static/basic.css_t index 7f505f6b1..450b92ead 100644 --- a/sphinx/themes/basic/static/basic.css_t +++ b/sphinx/themes/basic/static/basic.css_t @@ -538,19 +538,23 @@ table.hlist td { /* C++ specific styling */ +.sig-inline.c-texpr, .sig-inline.cpp-texpr { font-family: unset; } +.sig.c .k, .sig.c .kt, .sig.cpp .k, .sig.cpp .kt { color: #0033B3; } +.sig.c .m, .sig.cpp .m { color: #1750EB; } -.sig.cpp .s { +.sig.c .s, .sig.c .sc, +.sig.cpp .s, .sig.cpp .sc { color: #067D17; } From a840b9e4d6fcf4c9144ac7ca7e15ac66cf5545df Mon Sep 17 00:00:00 2001 From: Jakob Lykke Andersen Date: Tue, 30 Mar 2021 16:18:00 +0200 Subject: [PATCH 18/22] C, C++, fix unary op --- sphinx/domains/c.py | 2 +- sphinx/domains/cpp.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/sphinx/domains/c.py b/sphinx/domains/c.py index d3aad012b..1eeaf65cf 100644 --- a/sphinx/domains/c.py +++ b/sphinx/domains/c.py @@ -446,7 +446,7 @@ class ASTUnaryOpExpr(ASTExpression): signode += addnodes.desc_sig_space() else: signode += addnodes.desc_sig_operator(self.op, self.op) - self.expr.describe_signature(signode, mode, env, symbol) + self.expr.describe_signature(signode, mode, env, symbol) class ASTSizeofType(ASTExpression): diff --git a/sphinx/domains/cpp.py b/sphinx/domains/cpp.py index 1c876081b..4a36f6131 100644 --- a/sphinx/domains/cpp.py +++ b/sphinx/domains/cpp.py @@ -1251,7 +1251,7 @@ class ASTUnaryOpExpr(ASTExpression): signode += addnodes.desc_sig_space() else: signode += addnodes.desc_sig_operator(self.op, self.op) - self.expr.describe_signature(signode, mode, env, symbol) + self.expr.describe_signature(signode, mode, env, symbol) class ASTSizeofParamPack(ASTExpression): From da5b8e41e337064028fb5b321155a8933c91f819 Mon Sep 17 00:00:00 2001 From: Jakob Lykke Andersen Date: Wed, 7 Apr 2021 20:37:44 +0200 Subject: [PATCH 19/22] Decl styling, fixes from review --- sphinx/addnodes.py | 4 ++-- sphinx/transforms/post_transforms/__init__.py | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/sphinx/addnodes.py b/sphinx/addnodes.py index 5d26643ed..a2fb776e4 100644 --- a/sphinx/addnodes.py +++ b/sphinx/addnodes.py @@ -119,13 +119,13 @@ class toctree(nodes.General, nodes.Element, translatable): # Domain-specific object descriptions (class, function etc.) ############################################################# -class _desc_classes_injector(nodes.TextElement): +class _desc_classes_injector(nodes.Element): """Helper base class for injecting a fixes list of classes. Use as the first base class. """ - classes = [] # type: List[str] + classes: List[str] = [] def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) diff --git a/sphinx/transforms/post_transforms/__init__.py b/sphinx/transforms/post_transforms/__init__.py index bcc9caf00..e2899d994 100644 --- a/sphinx/transforms/post_transforms/__init__.py +++ b/sphinx/transforms/post_transforms/__init__.py @@ -233,7 +233,7 @@ class SigElementFallbackTransform(SphinxPostTransform): node.replace_self(newnode) -class DescSigAddDomainAsClass(SphinxPostTransform): +class PropagateDescDomain(SphinxPostTransform): """Add the domain name of the parent node as a class in each desc_signature node.""" default_priority = 200 @@ -246,7 +246,7 @@ def setup(app: Sphinx) -> Dict[str, Any]: app.add_post_transform(ReferencesResolver) app.add_post_transform(OnlyNodeTransform) app.add_post_transform(SigElementFallbackTransform) - app.add_post_transform(DescSigAddDomainAsClass) + app.add_post_transform(PropagateDescDomain) return { 'version': 'builtin', From cb21eb2283b0489adf10cc6799de3be088eb3fe1 Mon Sep 17 00:00:00 2001 From: Jakob Lykke Andersen Date: Sun, 11 Apr 2021 19:55:03 +0200 Subject: [PATCH 20/22] Decl styling, handle desc_inline in manpage and texinfo --- sphinx/writers/manpage.py | 6 ++++++ sphinx/writers/texinfo.py | 28 ++++++++++++++++++++++------ 2 files changed, 28 insertions(+), 6 deletions(-) diff --git a/sphinx/writers/manpage.py b/sphinx/writers/manpage.py index a43f117ae..3f0eea5eb 100644 --- a/sphinx/writers/manpage.py +++ b/sphinx/writers/manpage.py @@ -152,6 +152,12 @@ class ManualPageTranslator(SphinxTranslator, BaseTranslator): def depart_desc_content(self, node: Element) -> None: self.depart_definition(node) + def visit_desc_inline(self, node: Element) -> None: + pass + + def depart_desc_inline(self, node: Element) -> None: + pass + # Nodes for high-level structure in signatures ############################################## diff --git a/sphinx/writers/texinfo.py b/sphinx/writers/texinfo.py index cad6f3685..6df558323 100644 --- a/sphinx/writers/texinfo.py +++ b/sphinx/writers/texinfo.py @@ -1367,7 +1367,12 @@ class TexinfoTranslator(SphinxTranslator): self.body.append('\n\n') raise nodes.SkipNode - # -- Desc + ############################################################# + # Domain-specific object descriptions + ############################################################# + + # Top-level nodes for descriptions + ################################## def visit_desc(self, node: addnodes.desc) -> None: self.descs.append(node) @@ -1408,6 +1413,21 @@ class TexinfoTranslator(SphinxTranslator): def depart_desc_signature_line(self, node: Element) -> None: pass + def visit_desc_content(self, node: Element) -> None: + pass + + def depart_desc_content(self, node: Element) -> None: + pass + + def visit_desc_inline(self, node: Element) -> None: + pass + + def depart_desc_inline(self, node: Element) -> None: + pass + + # Nodes for high-level structure in signatures + ############################################## + def visit_desc_name(self, node: Element) -> None: pass @@ -1470,11 +1490,7 @@ class TexinfoTranslator(SphinxTranslator): def depart_desc_annotation(self, node: Element) -> None: pass - def visit_desc_content(self, node: Element) -> None: - pass - - def depart_desc_content(self, node: Element) -> None: - pass + ############################################## def visit_inline(self, node: Element) -> None: pass From 9b3b8a49fb0c2c0059577ccd8993fb6ae64deb97 Mon Sep 17 00:00:00 2001 From: Jakob Lykke Andersen Date: Mon, 12 Apr 2021 20:24:11 +0200 Subject: [PATCH 21/22] Decl styling, fix font size in basic --- sphinx/themes/basic/static/basic.css_t | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/sphinx/themes/basic/static/basic.css_t b/sphinx/themes/basic/static/basic.css_t index 450b92ead..25ab688e4 100644 --- a/sphinx/themes/basic/static/basic.css_t +++ b/sphinx/themes/basic/static/basic.css_t @@ -511,12 +511,19 @@ table.hlist td { /* -- object description styles --------------------------------------------- */ .sig { - font-family: monospace; + font-family: 'Consolas', 'Menlo', 'DejaVu Sans Mono', 'Bitstream Vera Sans Mono', monospace; } .sig-name, code.descname { background-color: transparent; font-weight: bold; +} + +.sig-name { + font-size: 1.1em; +} + +code.descname { font-size: 1.2em; } From 709339ec53430691593b3a6059bf4ffc040dfe73 Mon Sep 17 00:00:00 2001 From: Jakob Lykke Andersen Date: Mon, 12 Apr 2021 20:40:08 +0200 Subject: [PATCH 22/22] Decl styling, disable smart quoting in sigs --- sphinx/addnodes.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sphinx/addnodes.py b/sphinx/addnodes.py index a2fb776e4..8a020b02e 100644 --- a/sphinx/addnodes.py +++ b/sphinx/addnodes.py @@ -119,7 +119,7 @@ class toctree(nodes.General, nodes.Element, translatable): # Domain-specific object descriptions (class, function etc.) ############################################################# -class _desc_classes_injector(nodes.Element): +class _desc_classes_injector(nodes.Element, not_smartquotable): """Helper base class for injecting a fixes list of classes. Use as the first base class.