diff --git a/CHANGES b/CHANGES index cdd8475b49..2e6a9a6237 100644 --- a/CHANGES +++ b/CHANGES @@ -17,6 +17,9 @@ Features added * #7888: napoleon: Add aliases Warn and Raise. * C, added :rst:dir:`c:alias` directive for inserting copies of existing declarations. +* #7052: add ``:noindexentry:`` to the Python, C, C++, and Javascript domains. + Update the documentation to better reflect the relationship between this option + and the ``:noindex:`` option. Bugs fixed ---------- diff --git a/doc/usage/restructuredtext/domains.rst b/doc/usage/restructuredtext/domains.rst index 285e5b826f..311b03d666 100644 --- a/doc/usage/restructuredtext/domains.rst +++ b/doc/usage/restructuredtext/domains.rst @@ -42,9 +42,22 @@ Basic Markup Most domains provide a number of :dfn:`object description directives`, used to describe specific objects provided by modules. Each directive requires one or more signatures to provide basic information about what is being described, and -the content should be the description. The basic version makes entries in the -general index; if no index entry is desired, you can give the directive option -flag ``:noindex:``. An example using a Python domain directive:: +the content should be the description. A domain will typically keep an +internal index of all entites to aid cross-referencing. Typically it will +also add entries in the shown general index. +If you want to suppress the addition of an entry in the shown index, you can +give the directive option flag ``:noindexentry:``. +If you want to typeset an object description, without even making it available +for cross-referencing, you can give the directive option flag ``:noindex:`` +(which implies ``:noindexentry:``). +Though, note that not every directive en every domain may support these +options. + +.. versionadded:: 3.2 + The directive option ``noindexentry`` in the Python, C, C++, and Javascript + domains. + +An example using a Python domain directive:: .. py:function:: spam(eggs) ham(eggs) @@ -1073,6 +1086,7 @@ Options Some directives support options: +- ``:noindexentry:``, see :ref:`basic-domain-markup`. - ``:tparam-line-spec:``, for templated declarations. If specified, each template parameter will be rendered on a separate line. diff --git a/sphinx/domains/c.py b/sphinx/domains/c.py index 8a0b8a1054..10ced026d3 100644 --- a/sphinx/domains/c.py +++ b/sphinx/domains/c.py @@ -16,6 +16,7 @@ from typing import cast from docutils import nodes from docutils.nodes import Element, Node, TextElement, system_message +from docutils.parsers.rst import directives from sphinx import addnodes from sphinx.addnodes import pending_xref @@ -3023,10 +3024,7 @@ class CObject(ObjectDescription): ] option_spec = { - # have a dummy option to ensure proper errors on options, - # otherwise the option is taken as a continuation of the - # argument - 'dummy': None + 'noindexentry': directives.flag, } def _add_enumerator_to_parent(self, ast: ASTDeclaration) -> None: @@ -3098,8 +3096,9 @@ class CObject(ObjectDescription): if name not in domain.objects: domain.objects[name] = (domain.env.docname, newestId, self.objtype) - indexText = self.get_index_text(name) - self.indexnode['entries'].append(('single', indexText, newestId, '', None)) + if 'noindexentry' not in self.options: + indexText = self.get_index_text(name) + self.indexnode['entries'].append(('single', indexText, newestId, '', None)) @property def object_type(self) -> str: diff --git a/sphinx/domains/cpp.py b/sphinx/domains/cpp.py index 310691d495..c840423aad 100644 --- a/sphinx/domains/cpp.py +++ b/sphinx/domains/cpp.py @@ -6625,6 +6625,7 @@ class CPPObject(ObjectDescription): ] option_spec = { + 'noindexentry': directives.flag, 'tparam-line-spec': directives.flag, } @@ -6701,7 +6702,7 @@ class CPPObject(ObjectDescription): if decl.objectType == 'concept': isInConcept = True break - if not isInConcept: + if not isInConcept and 'noindexentry' not in self.options: strippedName = name for prefix in self.env.config.cpp_index_common_prefix: if name.startswith(prefix): diff --git a/sphinx/domains/javascript.py b/sphinx/domains/javascript.py index d510d79034..6c75f8dd79 100644 --- a/sphinx/domains/javascript.py +++ b/sphinx/domains/javascript.py @@ -49,6 +49,11 @@ class JSObject(ObjectDescription): #: based on directive nesting allow_nesting = False + option_spec = { + 'noindex': directives.flag, + 'noindexentry': directives.flag, + } + def handle_signature(self, sig: str, signode: desc_signature) -> Tuple[str, str]: """Breaks down construct signatures @@ -120,9 +125,10 @@ class JSObject(ObjectDescription): domain = cast(JavaScriptDomain, self.env.get_domain('js')) domain.note_object(fullname, self.objtype, node_id, location=signode) - indextext = self.get_index_text(mod_name, name_obj) - if indextext: - self.indexnode['entries'].append(('single', indextext, node_id, '', None)) + if 'noindexentry' not in self.options: + indextext = self.get_index_text(mod_name, name_obj) + if indextext: + self.indexnode['entries'].append(('single', indextext, node_id, '', None)) def get_index_text(self, objectname: str, name_obj: Tuple[str, str]) -> str: name, obj = name_obj diff --git a/sphinx/domains/python.py b/sphinx/domains/python.py index 5ea8d5d3da..4ca6062484 100644 --- a/sphinx/domains/python.py +++ b/sphinx/domains/python.py @@ -317,6 +317,7 @@ class PyObject(ObjectDescription): """ option_spec = { 'noindex': directives.flag, + 'noindexentry': directives.flag, 'module': directives.unchanged, 'annotation': directives.unchanged, } @@ -459,9 +460,10 @@ class PyObject(ObjectDescription): domain = cast(PythonDomain, self.env.get_domain('py')) domain.note_object(fullname, self.objtype, node_id, location=signode) - indextext = self.get_index_text(modname, name_cls) - if indextext: - self.indexnode['entries'].append(('single', indextext, node_id, '', None)) + if 'noindexentry' not in self.options: + indextext = self.get_index_text(modname, name_cls) + if indextext: + self.indexnode['entries'].append(('single', indextext, node_id, '', None)) def before_content(self) -> None: """Handle object nesting before content @@ -576,16 +578,17 @@ class PyFunction(PyObject): def add_target_and_index(self, name_cls: Tuple[str, str], sig: str, signode: desc_signature) -> None: super().add_target_and_index(name_cls, sig, signode) - modname = self.options.get('module', self.env.ref_context.get('py:module')) - node_id = signode['ids'][0] + if 'noindexentry' not in self.options: + modname = self.options.get('module', self.env.ref_context.get('py:module')) + node_id = signode['ids'][0] - name, cls = name_cls - if modname: - text = _('%s() (in module %s)') % (name, modname) - self.indexnode['entries'].append(('single', text, node_id, '', None)) - else: - text = '%s; %s()' % (pairindextypes['builtin'], name) - self.indexnode['entries'].append(('pair', text, node_id, '', None)) + name, cls = name_cls + if modname: + text = _('%s() (in module %s)') % (name, modname) + self.indexnode['entries'].append(('single', text, node_id, '', None)) + else: + text = '%s; %s()' % (pairindextypes['builtin'], name) + self.indexnode['entries'].append(('pair', text, node_id, '', None)) def get_index_text(self, modname: str, name_cls: Tuple[str, str]) -> str: # add index in own add_target_and_index() instead. diff --git a/tests/test_domain_c.py b/tests/test_domain_c.py index 347f8c7d6a..efef104f95 100644 --- a/tests/test_domain_c.py +++ b/tests/test_domain_c.py @@ -10,6 +10,7 @@ import pytest from sphinx import addnodes +from sphinx.addnodes import desc from sphinx.domains.c import DefinitionParser, DefinitionError from sphinx.domains.c import _max_id, _id_prefix, Symbol from sphinx.testing import restructuredtext @@ -590,3 +591,13 @@ def test_cvar(app): domain = app.env.get_domain('c') entry = domain.objects.get('PyClass_Type') assert entry == ('index', 'c.PyClass_Type', 'var') + + +def test_noindexentry(app): + text = (".. c:function:: void f()\n" + ".. c:function:: void g()\n" + " :noindexentry:\n") + doctree = restructuredtext.parse(app, text) + assert_node(doctree, (addnodes.index, desc, addnodes.index, desc)) + assert_node(doctree[0], addnodes.index, entries=[('single', 'f (C function)', 'c.f', '', None)]) + assert_node(doctree[2], addnodes.index, entries=[]) diff --git a/tests/test_domain_cpp.py b/tests/test_domain_cpp.py index a6c9eee9d1..28e437219a 100644 --- a/tests/test_domain_cpp.py +++ b/tests/test_domain_cpp.py @@ -14,8 +14,11 @@ import pytest import sphinx.domains.cpp as cppDomain from sphinx import addnodes +from sphinx.addnodes import desc from sphinx.domains.cpp import DefinitionParser, DefinitionError, NoOldIdError from sphinx.domains.cpp import Symbol, _max_id, _id_prefix +from sphinx.testing import restructuredtext +from sphinx.testing.util import assert_node from sphinx.util import docutils @@ -1211,3 +1214,13 @@ not found in `{test}` 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 + + +def test_noindexentry(app): + text = (".. cpp:function:: void f()\n" + ".. cpp:function:: void g()\n" + " :noindexentry:\n") + doctree = restructuredtext.parse(app, text) + assert_node(doctree, (addnodes.index, desc, addnodes.index, desc)) + assert_node(doctree[0], addnodes.index, entries=[('single', 'f (C++ function)', '_CPPv41fv', '', None)]) + assert_node(doctree[2], addnodes.index, entries=[]) diff --git a/tests/test_domain_js.py b/tests/test_domain_js.py index 189f22e5b4..9d0b59b919 100644 --- a/tests/test_domain_js.py +++ b/tests/test_domain_js.py @@ -218,3 +218,13 @@ def test_js_data(app): assert_node(doctree[0], addnodes.index, entries=[("single", "name (global variable or constant)", "name", "", None)]) assert_node(doctree[1], addnodes.desc, domain="js", objtype="data", noindex=False) + + +def test_noindexentry(app): + text = (".. js:function:: f()\n" + ".. js:function:: g()\n" + " :noindexentry:\n") + doctree = restructuredtext.parse(app, text) + assert_node(doctree, (addnodes.index, desc, addnodes.index, desc)) + assert_node(doctree[0], addnodes.index, entries=[('single', 'f() (built-in function)', 'f', '', None)]) + assert_node(doctree[2], addnodes.index, entries=[]) diff --git a/tests/test_domain_py.py b/tests/test_domain_py.py index 25d9ae7dff..61cc5145b6 100644 --- a/tests/test_domain_py.py +++ b/tests/test_domain_py.py @@ -799,3 +799,19 @@ def test_modindex_common_prefix(app): ) +def test_noindexentry(app): + text = (".. py:function:: f()\n" + ".. py:function:: g()\n" + " :noindexentry:\n") + doctree = restructuredtext.parse(app, text) + assert_node(doctree, (addnodes.index, desc, addnodes.index, desc)) + assert_node(doctree[0], addnodes.index, entries=[('pair', 'built-in function; f()', 'f', '', None)]) + assert_node(doctree[2], addnodes.index, entries=[]) + + text = (".. py:class:: f\n" + ".. py:class:: g\n" + " :noindexentry:\n") + doctree = restructuredtext.parse(app, text) + assert_node(doctree, (addnodes.index, desc, addnodes.index, desc)) + assert_node(doctree[0], addnodes.index, entries=[('single', 'f (built-in class)', 'f', '', None)]) + assert_node(doctree[2], addnodes.index, entries=[])