Skip to content

Commit

Permalink
Merge branch '3.x'
Browse files Browse the repository at this point in the history
  • Loading branch information
jfbu committed Feb 12, 2021
2 parents def6f13 + a148909 commit 62401ef
Show file tree
Hide file tree
Showing 6 changed files with 190 additions and 40 deletions.
9 changes: 9 additions & 0 deletions CHANGES
Original file line number Diff line number Diff line change
Expand Up @@ -157,6 +157,12 @@ Features added
* C++, also hyperlink operator overloads in expressions and alias declarations.
* #8247: Allow production lists to refer to tokens from other production groups
* #8813: Show what extension (or module) caused it on errors on event handler
* #8213: C++: add ``maxdepth`` option to :rst:dir:`cpp:alias` to insert nested
declarations.
* C, add ``noroot`` option to :rst:dir:`c:alias` to render only nested
declarations.
* C++, add ``noroot`` option to :rst:dir:`cpp:alias` to render only nested
declarations.

Bugs fixed
----------
Expand Down Expand Up @@ -229,6 +235,9 @@ Bugs fixed
builds
* #8865: LaTeX: Restructure the index nodes inside title nodes only on LaTeX
builds
* C, :rst:dir:`c:alias` skip symbols without explicit declarations
instead of crashing.
* C, :rst:dir:`c:alias` give a warning when the root symbol is not declared.

Testing
--------
Expand Down
6 changes: 3 additions & 3 deletions doc/development/tutorials/recipe.rst
Original file line number Diff line number Diff line change
Expand Up @@ -207,10 +207,10 @@ You can now use the extension throughout your project. For example:
The recipe contains `tomato` and `cilantro`.
.. recipe:recipe:: TomatoSoup
:contains: tomato cilantro salt pepper
:contains: tomato, cilantro, salt, pepper
This recipe is a tasty tomato soup, combine all ingredients
and cook.
This recipe is a tasty tomato soup, combine all ingredients
and cook.
The important things to note are the use of the ``:recipe:ref:`` role to
cross-reference the recipe actually defined elsewhere (using the
Expand Down
25 changes: 25 additions & 0 deletions doc/usage/restructuredtext/domains.rst
Original file line number Diff line number Diff line change
Expand Up @@ -795,6 +795,13 @@ The following directive can be used for this purpose.
.. versionadded:: 3.3
.. rst:directive:option:: noroot
Skip the mentioned declarations and only render nested declarations.
Requires ``maxdepth`` either 0 or at least 2.
.. versionadded:: 3.5
.. c:namespace-pop::
Expand Down Expand Up @@ -1219,6 +1226,24 @@ The following directive can be used for this purpose.
.. versionadded:: 2.0
.. rubric:: Options
.. rst:directive:option:: maxdepth: int
Insert nested declarations as well, up to the total depth given.
Use 0 for infinite depth and 1 for just the mentioned declaration.
Defaults to 1.
.. versionadded:: 3.5
.. rst:directive:option:: noroot
Skip the mentioned declarations and only render nested declarations.
Requires ``maxdepth`` either 0 or at least 2.
.. versionadded:: 3.5
Constrained Templates
~~~~~~~~~~~~~~~~~~~~~
Expand Down
96 changes: 71 additions & 25 deletions sphinx/domains/c.py
Original file line number Diff line number Diff line change
Expand Up @@ -3435,12 +3435,12 @@ def run(self) -> List[Node]:


class AliasNode(nodes.Element):
def __init__(self, sig: str, maxdepth: int, document: Any, env: "BuildEnvironment" = None,
def __init__(self, sig: str, aliasOptions: dict,
document: Any, env: "BuildEnvironment" = None,
parentKey: LookupKey = None) -> None:
super().__init__()
self.sig = sig
self.maxdepth = maxdepth
assert maxdepth >= 0
self.aliasOptions = aliasOptions
self.document = document
if env is not None:
if 'c:parent_symbol' not in env.temp_data:
Expand All @@ -3452,46 +3452,60 @@ def __init__(self, sig: str, maxdepth: int, document: Any, env: "BuildEnvironmen
self.parentKey = parentKey

def copy(self) -> 'AliasNode':
return self.__class__(self.sig, self.maxdepth, self.document,
return self.__class__(self.sig, self.aliasOptions, self.document,
env=None, parentKey=self.parentKey)


class AliasTransform(SphinxTransform):
default_priority = ReferencesResolver.default_priority - 1

def _render_symbol(self, s: Symbol, maxdepth: int, document: Any) -> List[Node]:
nodes = [] # type: List[Node]
options = dict() # type: ignore
signode = addnodes.desc_signature('', '')
nodes.append(signode)
s.declaration.describe_signature(signode, 'markName', self.env, options)
def _render_symbol(self, s: Symbol, maxdepth: int, skipThis: bool,
aliasOptions: dict, renderOptions: dict,
document: Any) -> List[Node]:
if maxdepth == 0:
recurse = True
elif maxdepth == 1:
recurse = False
else:
maxdepth -= 1
recurse = True

nodes = [] # type: List[Node]
if not skipThis:
signode = addnodes.desc_signature('', '')
nodes.append(signode)
s.declaration.describe_signature(signode, 'markName', self.env, renderOptions)

if recurse:
content = addnodes.desc_content()
desc = addnodes.desc()
content.append(desc)
desc.document = document
desc['domain'] = 'c'
# 'desctype' is a backwards compatible attribute
desc['objtype'] = desc['desctype'] = 'alias'
desc['noindex'] = True
if skipThis:
childContainer = nodes # type: Union[List[Node], addnodes.desc]
else:
content = addnodes.desc_content()
desc = addnodes.desc()
content.append(desc)
desc.document = document
desc['domain'] = 'c'
# 'desctype' is a backwards compatible attribute
desc['objtype'] = desc['desctype'] = 'alias'
desc['noindex'] = True
childContainer = desc

for sChild in s.children:
childNodes = self._render_symbol(sChild, maxdepth, document)
desc.extend(childNodes)
if sChild.declaration is None:
continue
childNodes = self._render_symbol(
sChild, maxdepth=maxdepth, skipThis=False,
aliasOptions=aliasOptions, renderOptions=renderOptions,
document=document)
childContainer.extend(childNodes)

if len(desc.children) != 0:
if not skipThis and len(desc.children) != 0:
nodes.append(content)
return nodes

def apply(self, **kwargs: Any) -> None:
for node in self.document.traverse(AliasNode):
node = cast(AliasNode, node)
sig = node.sig
parentKey = node.parentKey
try:
Expand Down Expand Up @@ -3531,17 +3545,40 @@ def apply(self, **kwargs: Any) -> None:
location=node)
node.replace_self(signode)
continue
# Declarations like .. var:: int Missing::var
# may introduce symbols without declarations.
# But if we skip the root then it is ok to start recursion from it.
if not node.aliasOptions['noroot'] and s.declaration is None:
signode = addnodes.desc_signature(sig, '')
node.append(signode)
signode.clear()
signode += addnodes.desc_name(sig, sig)

logger.warning(
"Can not render C declaration for alias '%s'. No such declaration." % name,
location=node)
node.replace_self(signode)
continue

nodes = self._render_symbol(s, maxdepth=node.maxdepth, document=node.document)
nodes = self._render_symbol(s, maxdepth=node.aliasOptions['maxdepth'],
skipThis=node.aliasOptions['noroot'],
aliasOptions=node.aliasOptions,
renderOptions=dict(), document=node.document)
node.replace_self(nodes)


class CAliasObject(ObjectDescription):
option_spec = {
'maxdepth': directives.nonnegative_int
'maxdepth': directives.nonnegative_int,
'noroot': directives.flag,
} # type: Dict

def run(self) -> List[Node]:
"""
On purpose this doesn't call the ObjectDescription version, but is based on it.
Each alias signature may expand into multiple real signatures if 'noroot'.
The code is therefore based on the ObjectDescription version.
"""
if ':' in self.name:
self.domain, self.objtype = self.name.split(':', 1)
else:
Expand All @@ -3555,10 +3592,19 @@ def run(self) -> List[Node]:
node['noindex'] = True

self.names = [] # type: List[str]
maxdepth = self.options.get('maxdepth', 1)
aliasOptions = {
'maxdepth': self.options.get('maxdepth', 1),
'noroot': 'noroot' in self.options,
}
if aliasOptions['noroot'] and aliasOptions['maxdepth'] == 1:
logger.warning("Error in C alias declaration."
" Requested 'noroot' but 'maxdepth' 1."
" When skipping the root declaration,"
" need 'maxdepth' 0 for infinite or at least 2.",
location=self.get_source_info())
signatures = self.get_signatures()
for i, sig in enumerate(signatures):
node.append(AliasNode(sig, maxdepth, self.state.document, env=self.env))
node.append(AliasNode(sig, aliasOptions, self.state.document, env=self.env))
return [node]


Expand Down
92 changes: 81 additions & 11 deletions sphinx/domains/cpp.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@

import re
from typing import (Any, Callable, Dict, Generator, Iterator, List, Optional, Tuple, Type,
TypeVar, Union)
TypeVar, Union, cast)

from docutils import nodes
from docutils.nodes import Element, Node, TextElement, system_message
Expand Down Expand Up @@ -3742,6 +3742,7 @@ def describe_signature(self, signode: desc_signature, mode: str,
elif self.objectType == 'enumerator':
mainDeclNode += addnodes.desc_annotation('enumerator ', 'enumerator ')
else:
print(self.objectType)
assert False
self.declaration.describe_signature(mainDeclNode, mode, env, self.symbol)
lastDeclNode = mainDeclNode
Expand Down Expand Up @@ -7046,10 +7047,12 @@ def run(self) -> List[Node]:


class AliasNode(nodes.Element):
def __init__(self, sig: str, env: "BuildEnvironment" = None,
def __init__(self, sig: str, aliasOptions: dict,
env: "BuildEnvironment" = None,
parentKey: LookupKey = None) -> None:
super().__init__()
self.sig = sig
self.aliasOptions = aliasOptions
if env is not None:
if 'cpp:parent_symbol' not in env.temp_data:
root = env.domaindata['cpp']['root_symbol']
Expand All @@ -7060,14 +7063,62 @@ def __init__(self, sig: str, env: "BuildEnvironment" = None,
self.parentKey = parentKey

def copy(self) -> 'AliasNode':
return self.__class__(self.sig, env=None, parentKey=self.parentKey)
return self.__class__(self.sig, self.aliasOptions,
env=None, parentKey=self.parentKey)


class AliasTransform(SphinxTransform):
default_priority = ReferencesResolver.default_priority - 1

def _render_symbol(self, s: Symbol, maxdepth: int, skipThis: bool,
aliasOptions: dict, renderOptions: dict,
document: Any) -> List[Node]:
if maxdepth == 0:
recurse = True
elif maxdepth == 1:
recurse = False
else:
maxdepth -= 1
recurse = True

nodes = [] # type: List[Node]
if not skipThis:
signode = addnodes.desc_signature('', '')
nodes.append(signode)
s.declaration.describe_signature(signode, 'markName', self.env, renderOptions)

if recurse:
if skipThis:
childContainer = nodes # type: Union[List[Node], addnodes.desc]
else:
content = addnodes.desc_content()
desc = addnodes.desc()
content.append(desc)
desc.document = document
desc['domain'] = 'cpp'
# 'desctype' is a backwards compatible attribute
desc['objtype'] = desc['desctype'] = 'alias'
desc['noindex'] = True
childContainer = desc

for sChild in s._children:
if sChild.declaration is None:
continue
if sChild.declaration.objectType in ("templateParam", "functionParam"):
continue
childNodes = self._render_symbol(
sChild, maxdepth=maxdepth, skipThis=False,
aliasOptions=aliasOptions, renderOptions=renderOptions,
document=document)
childContainer.extend(childNodes)

if not skipThis and len(desc.children) != 0:
nodes.append(content)
return nodes

def apply(self, **kwargs: Any) -> None:
for node in self.document.traverse(AliasNode):
node = cast(AliasNode, node)
sig = node.sig
parentKey = node.parentKey
try:
Expand Down Expand Up @@ -7131,22 +7182,31 @@ def apply(self, **kwargs: Any) -> None:
signode.clear()
signode += addnodes.desc_name(sig, sig)

logger.warning("Could not find C++ declaration for alias '%s'." % ast,
logger.warning("Can not find C++ declaration for alias '%s'." % ast,
location=node)
node.replace_self(signode)
else:
nodes = []
options = dict()
options['tparam-line-spec'] = False
renderOptions = {
'tparam-line-spec': False,
}
for s in symbols:
signode = addnodes.desc_signature(sig, '')
nodes.append(signode)
s.declaration.describe_signature(signode, 'markName', self.env, options)
assert s.declaration is not None
res = self._render_symbol(
s, maxdepth=node.aliasOptions['maxdepth'],
skipThis=node.aliasOptions['noroot'],
aliasOptions=node.aliasOptions,
renderOptions=renderOptions,
document=node.document)
nodes.extend(res)
node.replace_self(nodes)


class CPPAliasObject(ObjectDescription):
option_spec = {} # type: Dict
option_spec = {
'maxdepth': directives.nonnegative_int,
'noroot': directives.flag,
} # type: Dict

def run(self) -> List[Node]:
"""
Expand All @@ -7166,9 +7226,19 @@ def run(self) -> List[Node]:
node['objtype'] = node['desctype'] = self.objtype

self.names = [] # type: List[str]
aliasOptions = {
'maxdepth': self.options.get('maxdepth', 1),
'noroot': 'noroot' in self.options,
}
if aliasOptions['noroot'] and aliasOptions['maxdepth'] == 1:
logger.warning("Error in C++ alias declaration."
" Requested 'noroot' but 'maxdepth' 1."
" When skipping the root declaration,"
" need 'maxdepth' 0 for infinite or at least 2.",
location=self.get_source_info())
signatures = self.get_signatures()
for i, sig in enumerate(signatures):
node.append(AliasNode(sig, env=self.env))
node.append(AliasNode(sig, aliasOptions, env=self.env))

contentnode = addnodes.desc_content()
node.append(contentnode)
Expand Down
2 changes: 1 addition & 1 deletion sphinx/texinputs/sphinx.sty
Original file line number Diff line number Diff line change
Expand Up @@ -176,7 +176,7 @@
% FIXME: this is unrelated to an option, move this elsewhere
% To allow hyphenation of first word in narrow contexts; no option,
% customization to be done via 'preamble' key
\newcommand*\sphinxAtStartPar{\hskip\z@skip}
\newcommand*\sphinxAtStartPar{\leavevmode\nobreak\hskip\z@skip}
% No need for the \hspace{0pt} trick (\hskip\z@skip) with luatex
\ifdefined\directlua\let\sphinxAtStartPar\@empty\fi
% user interface: options can be changed midway in a document!
Expand Down

0 comments on commit 62401ef

Please sign in to comment.