-
-
Notifications
You must be signed in to change notification settings - Fork 2.4k
Description
I'd like to be able to define custom link targets for domains.
I'm doing literate programming in the spirit of Donald E. Knuth, e.g.
MyClass
=======
MyClass does foo and has an attribute ``bar``
.. code-block:: python
class MyClass:
bar = "foo"
[...] some text later [...]
The behaviour of :py:class:`MyClass` is defined by the value of :py:attr:`MyClass.bar`.Since bar is not defined via the directive .. py:method:: MyClass.bar, the above :py:attr: does not produce a link since the target cannot be found.
I could add the directive right before the code-block but that would produce a "MyClass.bar" string in the output which a oddly misplaced as the definition is right in the code-block.
Thus, I'd like to have a new directive or new option to existing directives, which produces a target (and an index entry) but not any output, e.g.
.. py:class:: MyClass
:tagetandindexonly:
MyClass
=======
MyClass does foo and has an attribute ``bar``
.. py:attr-target:: MyClass.foo
.. code-block:: python
class MyClass:
bar = "foo"
[...] some text later [...]
The behaviour of :py:class:`MyClass` is defined by the value of :py:attr:`MyClass.bar`.Here :py:class:... and :py:attr:... would find and link to the corresponding targets.
The requested behaviour is sort of the opposite of what :noindex: currently provides, instead of producing output without target, produce a target but no output.
Some thoughts
- This feature needs support per domain as the implementation of the reference/targets is completely handed to the derived domain (Python)class.
- Consequently, custom domains are likely to not support this feature out of the box but they might join once this hits a Sphinx release
Implementation idea 1
- The class
ObjectDescriptionalready has aadd_target_and_index()which is essentially all what we need. - Subclasses of ObjectDescription might have overridden
run(), these might need additional adjustments - Rewrite run() to support an option
:targetandindexonly:(a bad name but will do for this report) and only generate a "target" node.
Calladd_target_and_index()with that target node. - This would only need a change in the class
ObjectDescriptionand some minor changes in those classes overridingrun().
Open questions:
- Was
add_target_and_index()ever part of an public API? Cannot find anything in the Domain API [1]. More precisely, was there a guarantee that the node passed is adesc_signature? - Unclear whether the target is applied to a following heading (see Class example above)
Implementation idea 2
- Duplicate each
.. py:whatever::directive to a.. py:whatever-target:directive which takes a signature as argument and produces the corresponding target and index. - This directive should have the same semantics as
.. _reference-label: - More flexibility as we do not need to relay on
add_target_and_index(), e.g. works with headers as target. - Would need more implementation in the individual domains as they must implement those new directives
Implementation idea 3
- Maybe go a step further and provide a generic
.. domaintarget::directive with options which would produce for any domain and any signature a suitable target.
.. domaintarget::
:domain: py
:subdomain: attr
:signature: bar
:signature: bar2 (event multiple signature might be allowed)
whatever is hier is the target-
This directive should have the same semantics as a
.. _targetname:label. -
This needs the domains to expose references and targets such that a generic
.. domaintarget::directive can be implemented, e.g.domain.subdomains()list of subdomains ("attr", "class", "foo", ...)domain.get_target("attr", "class.attrname")where the first argument is the "subdomain" get target referencedomain.add_target("attr", "class.attrname")creates a target nodedomain.add_index("attr", "class.attrname")creates an index node
-
Avoids duplicating code as all the reference/target logic would be centralised in the domain and the domain classes can use this as well.
-
Needs refactoring of implementation of existing domain classes.
How to implement
I've never hacked on Sphinx or docutils but if someone is willing to mentor me, I would try to implement this feature.
[1] https://www.sphinx-doc.org/en/master/extdev/domainapi.html