mirror of
https://github.com/sphinx-doc/sphinx.git
synced 2025-02-25 18:55:22 -06:00
Add cpp:texpr role (style alternative to cpp:expr)
Simplified version of sphinx-doc/sphinx#4836, thanks to mickk-on-cpp.
This commit is contained in:
parent
46797104fa
commit
f592483156
1
CHANGES
1
CHANGES
@ -116,6 +116,7 @@ Features added
|
||||
* #4785: napoleon: Add strings to translation file for localisation
|
||||
* #4927: Display a warning when invalid values are passed to linenothreshold
|
||||
option of highlight directive
|
||||
* C++, add a ``cpp:texpr`` role as a sibling to ``cpp:expr``.
|
||||
|
||||
Bugs fixed
|
||||
----------
|
||||
|
@ -569,10 +569,10 @@ visibility statement (``public``, ``private`` or ``protected``).
|
||||
Full and partial template specialisations can be declared::
|
||||
|
||||
.. cpp:class:: template<> \
|
||||
std::array<bool, 256>
|
||||
std::array<bool, 256>
|
||||
|
||||
.. cpp:class:: template<typename T> \
|
||||
std::array<T, 42>
|
||||
std::array<T, 42>
|
||||
|
||||
.. rst:directive:: .. cpp:function:: (member) function prototype
|
||||
|
||||
@ -815,24 +815,31 @@ Inline Expressions and Tpes
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
.. rst:role:: cpp:expr
|
||||
cpp:texpr
|
||||
|
||||
A role for inserting a C++ expression or type as inline text. For example::
|
||||
Insert a C++ expression or type either as inline code (``cpp:expr``)
|
||||
or inline text (``cpp:texpr``). For example::
|
||||
|
||||
.. cpp:var:: int a = 42
|
||||
|
||||
.. cpp:function:: int f(int i)
|
||||
|
||||
An expression: :cpp:expr:`a * f(a)`.
|
||||
A type: :cpp:expr:`const MySortedContainer<int>&`.
|
||||
An expression: :cpp:expr:`a * f(a)` (or as text: :cpp:texpr:`a * f(a)`).
|
||||
|
||||
A type: :cpp:expr:`const MySortedContainer<int>&`
|
||||
(or as text :cpp:texpr:`const MySortedContainer<int>&`).
|
||||
|
||||
will be rendered as follows:
|
||||
|
||||
.. cpp:var:: int a = 42
|
||||
.. cpp:var:: int a = 42
|
||||
|
||||
.. cpp:function:: int f(int i)
|
||||
.. cpp:function:: int f(int i)
|
||||
|
||||
An expression: :cpp:expr:`a * f(a)` (or as text: :cpp:texpr:`a * f(a)`).
|
||||
|
||||
A type: :cpp:expr:`const MySortedContainer<int>&`
|
||||
(or as text :cpp:texpr:`const MySortedContainer<int>&`).
|
||||
|
||||
An expression: :cpp:expr:`a * f(a)`. A type: :cpp:expr:`const
|
||||
MySortedContainer<int>&`.
|
||||
|
||||
Namespacing
|
||||
~~~~~~~~~~~
|
||||
@ -880,7 +887,7 @@ The ``cpp:namespace-pop`` directive undoes the most recent
|
||||
|
||||
.. cpp:function:: std::size_t size() const
|
||||
|
||||
or:::
|
||||
or::
|
||||
|
||||
.. cpp:class:: template<typename T> \
|
||||
std::vector
|
||||
@ -949,20 +956,23 @@ These roles link to the given declaration types:
|
||||
|
||||
.. admonition:: Note on References with Templates Parameters/Arguments
|
||||
|
||||
Sphinx's syntax to give references a custom title can interfere with linking
|
||||
to class templates, if nothing follows the closing angle bracket, i.e. if
|
||||
the link looks like this: ``:cpp:class:`MyClass<int>```. This is
|
||||
interpreted as a link to ``int`` with a title of ``MyClass``. In this case,
|
||||
please escape the opening angle bracket with a backslash, like this:
|
||||
``:cpp:class:`MyClass\<int>```.
|
||||
These roles follow the Sphinx :ref:`xref-syntax` rules. This means care must be
|
||||
taken when referencing a (partial) template specialization, e.g. if the link looks like
|
||||
this: ``:cpp:class:`MyClass<int>```.
|
||||
This is interpreted as a link to ``int`` with a title of ``MyClass``.
|
||||
In this case, escape the opening angle bracket with a backslash,
|
||||
like this: ``:cpp:class:`MyClass\<int>```.
|
||||
|
||||
When a custom title is not needed it may be useful to use the roles for inline expressions,
|
||||
:rst:role:`cpp:expr` and :rst:role:`cpp:texpr`, where angle brackets do not need escaping.
|
||||
|
||||
.. admonition:: Note on References to Overloaded Functions
|
||||
|
||||
It is currently impossible to link to a specific version of an overloaded
|
||||
method. Currently the C++ domain is the first domain that has basic support
|
||||
for overloaded methods and until there is more data for comparison we don't
|
||||
want to select a bad syntax to reference a specific overload. Currently
|
||||
Sphinx will link to the first overloaded version of the method / function.
|
||||
function. Currently the C++ domain is the first domain that has basic
|
||||
support for overloaded functions and until there is more data for comparison
|
||||
we don't want to select a bad syntax to reference a specific overload.
|
||||
Currently Sphinx will link to the first overloaded version of the function.
|
||||
|
||||
Declarations without template parameters and template arguments
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
@ -983,13 +993,13 @@ Assume the following declarations.
|
||||
.. cpp:class:: template<typename TInner> \
|
||||
Inner
|
||||
|
||||
In general the reference must include the template paraemter declarations,
|
||||
In general the reference must include the template parameter declarations,
|
||||
e.g., ``template\<typename TOuter> Wrapper::Outer``
|
||||
(:cpp:class:`template\<typename TOuter> Wrapper::Outer`). Currently the lookup
|
||||
only succeed if the template parameter identifiers are equal strings. That is,
|
||||
``template\<typename UOuter> Wrapper::Outer`` will not work.
|
||||
|
||||
The inner class template can not be directly referenced, unless the current
|
||||
The inner class template cannot be directly referenced, unless the current
|
||||
namespace is changed or the following shorthand is used. If a template
|
||||
parameter list is omitted, then the lookup will assume either a template or a
|
||||
non-template, but not a partial template specialisation. This means the
|
||||
|
@ -5965,6 +5965,16 @@ class CPPXRefRole(XRefRole):
|
||||
|
||||
|
||||
class CPPExprRole(object):
|
||||
def __init__(self, asCode):
|
||||
if asCode:
|
||||
# render the expression as inline code
|
||||
self.class_type = 'cpp-expr'
|
||||
self.node_type = nodes.literal
|
||||
else:
|
||||
# render the expression as inline text
|
||||
self.class_type = 'cpp-texpr'
|
||||
self.node_type = nodes.inline
|
||||
|
||||
def __call__(self, typ, rawtext, text, lineno, inliner, options={}, content=[]):
|
||||
class Warner(object):
|
||||
def warn(self, msg):
|
||||
@ -5972,18 +5982,23 @@ class CPPExprRole(object):
|
||||
text = utils.unescape(text).replace('\n', ' ')
|
||||
env = inliner.document.settings.env
|
||||
parser = DefinitionParser(text, Warner(), env.config)
|
||||
# attempt to mimic XRefRole classes, except that...
|
||||
classes = ['xref', 'cpp', self.class_type]
|
||||
try:
|
||||
ast = parser.parse_expression()
|
||||
except DefinitionError as ex:
|
||||
Warner().warn('Unparseable C++ expression: %r\n%s'
|
||||
% (text, text_type(ex.description)))
|
||||
return [nodes.literal(text)], []
|
||||
# see below
|
||||
return [self.node_type(text, text, classes=classes)], []
|
||||
parentSymbol = env.temp_data.get('cpp:parent_symbol', None)
|
||||
if parentSymbol is None:
|
||||
parentSymbol = env.domaindata['cpp']['root_symbol']
|
||||
p = nodes.literal()
|
||||
ast.describe_signature(p, 'markType', env, parentSymbol)
|
||||
return [p], []
|
||||
# ...most if not all of these classes should really apply to the individual references,
|
||||
# not the container node
|
||||
signode = self.node_type(classes=classes)
|
||||
ast.describe_signature(signode, 'markType', env, parentSymbol)
|
||||
return [signode], []
|
||||
|
||||
|
||||
class CPPDomain(Domain):
|
||||
@ -6025,7 +6040,8 @@ class CPPDomain(Domain):
|
||||
'concept': CPPXRefRole(),
|
||||
'enum': CPPXRefRole(),
|
||||
'enumerator': CPPXRefRole(),
|
||||
'expr': CPPExprRole()
|
||||
'expr': CPPExprRole(asCode=True),
|
||||
'texpr': CPPExprRole(asCode=False)
|
||||
}
|
||||
initial_data = {
|
||||
'root_symbol': Symbol(None, None, None, None, None, None),
|
||||
|
12
tests/roots/test-domain-cpp/xref_consistency.rst
Normal file
12
tests/roots/test-domain-cpp/xref_consistency.rst
Normal file
@ -0,0 +1,12 @@
|
||||
xref consistency
|
||||
----------------
|
||||
|
||||
.. cpp:namespace:: xref_consistency
|
||||
|
||||
.. cpp:class:: item
|
||||
|
||||
code-role: :code:`item`
|
||||
any-role: :any:`item`
|
||||
cpp-any-role: :cpp:any:`item`
|
||||
cpp-expr-role: :cpp:expr:`item`
|
||||
cpp-texpr-role: :cpp:texpr:`item`
|
@ -735,3 +735,68 @@ def test_build_domain_cpp_with_add_function_parentheses_is_False(app, status, wa
|
||||
t = (app.outdir / f).text()
|
||||
for s in parenPatterns:
|
||||
check(s, t, f)
|
||||
|
||||
|
||||
@pytest.mark.sphinx(testroot='domain-cpp')
|
||||
def test_xref_consistency(app, status, warning):
|
||||
app.builder.build_all()
|
||||
|
||||
test = 'xref_consistency.html'
|
||||
output = (app.outdir / test).text()
|
||||
|
||||
def classes(role, tag):
|
||||
pattern = (r'{role}-role:.*?'
|
||||
'<(?P<tag>{tag}) .*?class=["\'](?P<classes>.*?)["\'].*?>'
|
||||
'.*'
|
||||
'</(?P=tag)>').format(role=role, tag=tag)
|
||||
result = re.search(pattern, output)
|
||||
expect = '''\
|
||||
Pattern for role `{role}` with tag `{tag}`
|
||||
\t{pattern}
|
||||
not found in `{test}`
|
||||
'''.format(role=role, tag=tag, pattern=pattern, test=test)
|
||||
assert result, expect
|
||||
return set(result.group('classes').split())
|
||||
|
||||
class RoleClasses(object):
|
||||
"""Collect the classes from the layout that was generated for a given role."""
|
||||
|
||||
def __init__(self, role, root, contents):
|
||||
self.name = role
|
||||
self.classes = classes(role, root)
|
||||
self.content_classes = dict()
|
||||
for tag in contents:
|
||||
self.content_classes[tag] = classes(role, tag)
|
||||
|
||||
# not actually used as a reference point
|
||||
#code_role = RoleClasses('code', 'code', [])
|
||||
any_role = RoleClasses('any', 'a', ['code'])
|
||||
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'])
|
||||
texpr_role = RoleClasses('cpp-texpr', 'span', ['a', 'span'])
|
||||
|
||||
# XRefRole-style classes
|
||||
|
||||
## any and cpp:any do not put these classes at the root
|
||||
|
||||
# n.b. the generic any machinery finds the specific 'cpp-class' object type
|
||||
expect = 'any uses XRefRole classes'
|
||||
assert {'xref', 'any', 'cpp', 'cpp-class'} <= any_role.content_classes['code'], expect
|
||||
|
||||
expect = 'cpp:any uses XRefRole classes'
|
||||
assert {'xref', 'cpp-any', 'cpp'} <= cpp_any_role.content_classes['code'], expect
|
||||
|
||||
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
|
||||
|
||||
# reference classes
|
||||
|
||||
expect = 'the xref roles use the same reference classes'
|
||||
assert any_role.classes == cpp_any_role.classes, expect
|
||||
assert any_role.classes == expr_role.content_classes['a'], expect
|
||||
assert any_role.classes == texpr_role.content_classes['a'], expect
|
||||
|
Loading…
Reference in New Issue
Block a user